feat: as BREAKING CHANGE add exports & convert to static docs page

This commit is contained in:
Thomas Allmer 2021-03-15 10:54:44 +01:00 committed by Thomas Allmer
parent f2c63e858e
commit 5db622e9da
670 changed files with 14455 additions and 12288 deletions

View file

@ -0,0 +1,5 @@
---
'babel-plugin-extend-docs': patch
---
Still replace tags if templates uses `.foo=${{ key: 'value' }}`

View file

@ -0,0 +1,23 @@
---
'remark-extend': minor
---
BREAKING CHANGE: Changing approach from overwriting extending files to using an import-based approach.
Removed features:
- `::replaceFrom`
- `::replaceBetween`
- `::addMdAfter`
- `::removeFrom`
- `::removeBetween`
Added Features:
- `::import`
- `::importBlock`
- `::importBlockContent`
- `::importSmallBlock`
- `::importSmallBlockContent`
See the updated documentation for how to use this new approach.

View file

@ -0,0 +1,5 @@
---
'providence-analytics': minor
---
BREAKING: Align exports fields. If you want to import from CLI instead of main entrypoint (`import { ... } from 'providence-analytics';`) using export maps, you can now do so with `import { ... } from 'providence-analytics/src/cli';` instead of `import { ... } from 'providence-analytics/src/cli/index.js';`.

View file

@ -0,0 +1,40 @@
---
'@lion/accordion': minor
'@lion/button': minor
'@lion/calendar': minor
'@lion/checkbox-group': minor
'@lion/collapsible': minor
'@lion/combobox': minor
'@lion/core': minor
'@lion/dialog': minor
'@lion/fieldset': minor
'@lion/form': minor
'@lion/form-core': minor
'@lion/form-integrations': minor
'@lion/helpers': minor
'@lion/icon': minor
'@lion/input': minor
'@lion/input-amount': minor
'@lion/input-date': minor
'@lion/input-datepicker': minor
'@lion/input-email': minor
'@lion/input-iban': minor
'@lion/input-range': minor
'@lion/input-stepper': minor
'@lion/listbox': minor
'@lion/localize': minor
'@lion/overlays': minor
'@lion/pagination': minor
'@lion/progress-indicator': minor
'@lion/radio-group': minor
'@lion/select': minor
'@lion/select-rich': minor
'@lion/steps': minor
'@lion/switch': minor
'@lion/tabs': minor
'@lion/textarea': minor
'@lion/tooltip': minor
'@lion/validate-messages': minor
---
BREAKING: Align exports fields. This means no more wildcards, meaning you always import with bare import specifiers, extensionless. Import components where customElements.define side effect is executed by importing from '@lion/package/define'. For multi-component packages this defines all components (e.g. radio-group + radio). If you want to only import a single one, do '@lion/package/define-radio' for example for just lion-radio.

4
.eleventyignore Normal file
View file

@ -0,0 +1,4 @@
node_modules/**
/docs/_assets
/docs/_includes
/docs/_data

View file

@ -3,3 +3,5 @@ coverage/
bundlesize/ bundlesize/
.history/ .history/
*.d.ts *.d.ts
_site-dev
_site

View file

@ -5,6 +5,8 @@ module.exports = {
files: ['**/*.js'], files: ['**/*.js'],
rules: { rules: {
'wc/guard-super-call': 'off', // types will prevent you from calling the super if it's not in the base class, making the guard unnecessary 'wc/guard-super-call': 'off', // types will prevent you from calling the super if it's not in the base class, making the guard unnecessary
'no-await-in-loop': 'off',
'import/no-unresolved': 'off', // eslint not smart enough atm to understand package exports maps
}, },
}, },
{ {

11
.gitignore vendored
View file

@ -42,6 +42,15 @@ local.log
## browserstack ## browserstack
browserstack.err browserstack.err
## Rocket ignore files (need to be the full relative path to the folders)
docs/_merged_data/
docs/_merged_assets/
docs/_merged_includes/
debug.log debug.log
!packages/singleton-manager/demo/**/node_modules _site
_site-dev
## generated test fiels
__output

View file

@ -2,6 +2,9 @@
"line-length": { "line-length": {
"line_length": -1 "line_length": -1
}, },
"fenced-code-language": false,
"no-inline-html": false,
"first-line-h1": false,
"no-trailing-punctuation": { "no-trailing-punctuation": {
"punctuation": ".,;。,;:!" "punctuation": ".,;。,;:!"
} }

View file

@ -1,3 +1,5 @@
coverage/ coverage/
CHANGELOG.md CHANGELOG.md
bundlesize/ bundlesize/
_site
_site-dev

View file

@ -1,81 +0,0 @@
const fs = require('fs');
const path = require('path');
module.exports = {
stories: [
'../{packages,packages-node}/*/README.md',
'../{packages,packages-node}/*/docs/*.md',
'../{packages,packages-node}/*/docs/!(assets)**/*.md',
'../packages/helpers/*/README.md',
'../docs/README.md',
'../docs/**/*.md',
'../README.md',
'../demo/README.md',
'../demo/docs/*.md',
],
addons: [
// order of tabs in addons panel
'storybook-prebuilt/addon-actions/register.js',
'storybook-prebuilt/addon-knobs/register.js',
'storybook-prebuilt/addon-a11y/register.js',
'storybook-prebuilt/addon-docs/register.js',
// no tab in addons panel (e.g. load order does not matter here)
'storybook-prebuilt/addon-backgrounds/register.js',
'storybook-prebuilt/addon-links/register.js',
'storybook-prebuilt/addon-viewport/register.js',
],
addons: [
'storybook-prebuilt/addon-docs/register.js',
'storybook-prebuilt/addon-actions/register.js',
'storybook-prebuilt/addon-knobs/register.js',
'storybook-prebuilt/addon-a11y/register.js',
'storybook-prebuilt/addon-backgrounds/register.js',
'storybook-prebuilt/addon-links/register.js',
'storybook-prebuilt/addon-viewport/register.js',
],
esDevServer: {
nodeResolve: true,
watch: true,
open: true,
},
rollup: config => {
// temporarily hard copy all needed global files as all tested rollup plugins flatten the
// directory structure
// `rollup-plugin-copy` might work if issue 37 is resolved
// https://github.com/vladshcherbin/rollup-plugin-copy/issues/37
config.plugins.push({
generateBundle() {
this.emitFile({
type: 'asset',
fileName: 'packages/form-integrations/dev-assets/FormatMixinDiagram-1.svg',
source: fs.readFileSync(
path.join(
__dirname,
'../packages/form-integrations/dev-assets/FormatMixinDiagram-1.svg',
),
),
});
this.emitFile({
type: 'asset',
fileName: 'packages/form-integrations/dev-assets/FormatMixinDiagram-2.svg',
source: fs.readFileSync(
path.join(
__dirname,
'../packages/form-integrations/dev-assets/FormatMixinDiagram-2.svg',
),
),
});
this.emitFile({
type: 'asset',
fileName: 'packages/form-integrations/dev-assets/FormatMixinDiagram-3.svg',
source: fs.readFileSync(
path.join(
__dirname,
'../packages/form-integrations/dev-assets/FormatMixinDiagram-3.svg',
),
),
});
},
});
},
};

View file

@ -1,27 +0,0 @@
<style>
/**
* Temp approach for showing local overlays that flow out of their container
* Ideally, this would be configurable in Preview:
* https://github.com/storybookjs/storybook/blob/next/lib/components/src/blocks/Preview.ts
*/
.sbdocs.sbdocs-preview {
overflow: initial;
position: relative;
z-index: unset;
}
.sbdocs.sbdocs-preview > div:first-child {
z-index: unset;
}
.sbdocs.sbdocs-preview > div > div {
overflow: initial;
z-index: unset;
}
.sbdocs.sbdocs-preview > div > div [scale='1'] {
z-index: unset;
transform: none;
}
</style>

View file

@ -1,49 +0,0 @@
import {
addDecorator,
addParameters,
setCustomElements,
withA11y,
} from '@open-wc/demoing-storybook';
import { sortEachDepth } from '../packages/helpers/index.js';
async function run() {
// const customElements = await (
// await fetch(new URL('../custom-elements.json', import.meta.url))
// ).json();
setCustomElements({});
addDecorator(withA11y);
addParameters({
a11y: {
config: {},
options: {
checks: { 'color-contrast': { options: { noScroll: true } } },
restoreScroll: true,
},
},
docs: {
iframeHeight: '200px',
},
options: {
showRoots: true,
storySort: sortEachDepth([
[
'Intro',
'Forms',
'Buttons',
'Overlays',
'Navigation',
'Localize',
'Icons',
'Others',
'...',
],
['Intro', 'Features Overview', '...', 'Validation', 'System'],
['Overview', '...', '_internals'],
]),
},
});
}
run();

View file

@ -1,38 +1,60 @@
# Lion Web Components <p align="center">
<img
width="60%"
src="./assets/logo.png"
alt="Lion"
/>
</p>
```js script <p align="center">
export default { <a href="https://github.com/modernweb-dev/rocket/actions"
title: 'Intro/Lion Web Components', ><img
}; src="https://img.shields.io/github/workflow/status/modernweb-dev/rocket/Release/main?label=workflow&style=flat-square"
``` alt="GitHub Actions workflow status"
/></a>
<a href="https://github.com/modernweb-dev/rocket/actions"
><img
src="https://img.shields.io/github/workflow/status/modernweb-dev/rocket/Release/main?label=workflow&style=flat-square"
alt="GitHub Actions workflow status"
/></a>
<a href="https://www.tickgit.com/browse?repo=github.com/ing-bank/lion"
><img
src="https://badgen.net/https/api.tickgit.com/badgen/github.comgithub.com/ing-bank/lion"
alt="Todos"
/></a>
</p>
Lion web components is a set of highly performant, accessible and flexible Web Components. <p align="center">
They provide an unopinionated, white label layer that can be extended to your own layer of components. <a href="https://lion-web.netlify.app">Website</a>
·
<a href="https://lion-web.netlify.app/guides/">Guides</a>
·
<a href="https://lion-web.netlify.app/components/">Components</a>
·
<a href="https://lion-web.netlify.app/docs/">Documentation</a>
·
<a href="https://lion-web.netlify.app/blog/">Blog</a>
</p>
For some more details see the [announcement blog post](https://medium.com/ing-blog/ing-open-sources-lion-a-library-for-performant-accessible-flexible-web-components-22ad165b1d3d). <h1></h1>
[![TODOs](https://badgen.net/https/api.tickgit.com/badgen/github.comgithub.com/ing-bank/lion)](https://www.tickgit.com/browse?repo=github.com/ing-bank/lion) **Lion is a set of highly performant, accessible and flexible Web Components.!**
## Demos They provide an unopinionated, white-label layer that can be extended to your own layer of components.
We do have a [live Storybook](http://lion-web-components.netlify.com) which shows all our components. - **High Performance:** Focused on great performance in all relevant browsers with a minimal number of dependencies.
- **Accessibility:** Aimed at compliance with the WCAG 2.1 AA standard to create components that are accessible for everybody.
- **Flexibility:** Provides solutions through Web Components and JavaScript classes which can be used, adopted and extended to fit all needs.
- **Modern Code:** Lion is distributes as pure es modules.
- **Exposes functions/classes and Web Components:** Ships a functionality in it's most appropriate form.
**Please note:** This project uses Yarn [Workspaces](https://classic.yarnpkg.com/en/docs/workspaces). If you want to run all demos locally you need to get [Yarn](https://classic.yarnpkg.com/en/docs/install) and install all dependencies by executing `yarn install`. > Note: Our demos may look a little bland but that is on purpose. They only come with functional stylings.
The code examples make use of [Javascript tagged template literals](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals) which are a key component of the [lit-html engine](https://lit-html.polymer-project.org/) used in Lion.
Additionally imports like `import '@lion/form/lion-form.js'` need to be transformed somehow, for example by [es-dev-server](https://open-wc.org/developing/es-dev-server.html#node-resolve).
## Features
- High Performance - Focused on great performance in all relevant browsers with a minimal number of dependencies
- Accessibility - Aimed at compliance with the WCAG 2.1 AA standard to create components that are accessible for everybody
- Flexibility - Provides solutions through Web Components and JavaScript classes which can be used, adopted and extended to fit all needs
- Pure ES Modules
- Exposes functions/classes and Web Components
> Note: These demos may look a little bland but that is on purpose. They only come with functional stylings.
> This makes sense as the main use case is to extend those components and if you do you do not want to override existing stylings. > This makes sense as the main use case is to extend those components and if you do you do not want to override existing stylings.
<p align="center">
<a href="https://lion-web.netlify.app/guides/"><strong>Explore the Lion Guides&nbsp;&nbsp;</strong></a>
</p>
## How to install ## How to install
```bash ```bash
@ -82,7 +104,7 @@ You can also use the lion elements directly, although this is likely not a commo
```html ```html
<script type="module"> <script type="module">
import '@lion/input/lion-input.js'; import '@lion/input/define';
</script> </script>
<lion-input name="firstName"></lion-input> <lion-input name="firstName"></lion-input>
@ -150,18 +172,17 @@ The accessibility column indicates whether the functionality is accessible in it
## Technologies ## Technologies
Lion Web Components aims to be future proof and use well-supported proven technology. The stack we have chosen should reflect this. Lion Web Components aims to be future-proof and use well-supported proven technology. The stack we have chosen should reflect this.
- [lit-html](https://lit-html.polymer-project.org) and [lit-element](https://lit-element.polymer-project.org) - [lit-html](https://lit-html.polymer-project.org) and [lit-element](https://lit-element.polymer-project.org)
- [npm](http://npmjs.com) - [npm](http://npmjs.com)
- [yarn](https://yarnpkg.com) - [yarn](https://yarnpkg.com)
- [open-wc](https://open-wc.org) - [Open Web Components](https://open-wc.org)
- [Karma](https://karma-runner.github.io) - [Modern Web](https://modern-web.dev)
- [Mocha](https://mochajs.org) - [Mocha](https://mochajs.org)
- [Chai](https://www.chaijs.com) - [Chai](https://www.chaijs.com)
- [ESLint](https://eslint.org) - [ESLint](https://eslint.org)
- [prettier](https://prettier.io) - [prettier](https://prettier.io)
- [Storybook](https://storybook.js.org)
- [ES modules](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import) - [ES modules](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import)
- Lots and lots of tests - Lots and lots of tests
@ -180,6 +201,8 @@ Check out our [coding guidelines](https://lion-web-components.netlify.app/?path=
## How to contribute ## How to contribute
**Please note:** This project uses Yarn [Workspaces](https://classic.yarnpkg.com/en/docs/workspaces). If you want to run all demos locally you need to get [Yarn](https://classic.yarnpkg.com/en/docs/install) and install all dependencies by executing `yarn install`.
Lion Web Components are only as good as its contributions. Lion Web Components are only as good as its contributions.
Read our [contribution guide](https://github.com/ing-bank/lion/blob/master/CONTRIBUTING.md) and feel free to enhance/improve Lion. We keep feature requests closed while we're not working on them. Read our [contribution guide](https://github.com/ing-bank/lion/blob/master/CONTRIBUTING.md) and feel free to enhance/improve Lion. We keep feature requests closed while we're not working on them.

BIN
assets/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View file

@ -1,231 +0,0 @@
# lea Tabs
> This is not a real implementation!
>
> It is an example of how you can reuse the functionality of Lion to create your own Style System
`lea-tabs` implements tabs view to allow users to quickly move between a small number of equally important views.
```js script
import { html } from '@lion/core';
import { LitElement } from '@lion/core';
import '../lea-tabs.js';
import '../lea-tab.js';
import '../lea-tab-panel.js';
export default {
title: 'Intro/Tabs Example',
};
```
```js preview-story
export const main = () => html`
<lea-tabs>
<lea-tab slot="tab">Info</lea-tab>
<lea-tab-panel slot="panel"> Info page with lots of information about us. </lea-tab-panel>
<lea-tab slot="tab">Work</lea-tab>
<lea-tab-panel slot="panel"> Work page that showcases our work. </lea-tab-panel>
</lea-tabs>
`;
```
## How to use
### Installation
```sh
npm i --save @lion/tabs;
```
### Usage
```js
import '@lion/tabs/lea-tabs.js';
```
```html
<lea-tabs>
<lea-tab slot="tab">Info</lea-tab>
<lea-tab-panel slot="panel"> Info page with lots of information about us. </lea-tab-panel>
<lea-tab slot="tab">Work</lea-tab>
<lea-tab-panel slot="panel"> Work page that showcases our work. </lea-tab-panel>
</lea-tabs>
```
## Examples
### Selected Index
You can set the `selectedIndex` to select a certain tab.
```js preview-story
export const selectedIndex = () => html`
<lea-tabs .selectedIndex=${1}>
<lea-tab slot="tab">Info</lea-tab>
<lea-tab-panel slot="panel"> Info page with lots of information about us. </lea-tab-panel>
<lea-tab slot="tab">Work</lea-tab>
<lea-tab-panel slot="panel"> Work page that showcases our work. </lea-tab-panel>
</lea-tabs>
`;
```
### Slots Order
The tab and panel slots are ordered by DOM order.
This means you can switch the grouping in your `lea-tabs` from tab + panel to all tabs first or all panels first.
```js preview-story
export const slotsOrder = () => html`
<lea-tabs>
<lea-tab slot="tab">Info</lea-tab>
<lea-tab slot="tab">Work</lea-tab>
<lea-tab-panel slot="panel"> Info page with lots of information about us. </lea-tab-panel>
<lea-tab-panel slot="panel"> Work page that showcases our work. </lea-tab-panel>
</lea-tabs>
`;
```
### Distribute New Elements
Below, we demonstrate on how you could dynamically add new tab + panels.
```js preview-story
export const distributeNewElements = () => {
const tagName = 'lea-tabs-experimental';
if (!customElements.get(tagName)) {
customElements.define(
tagName,
class extends LitElement {
static get properties() {
return {
__collection: { type: Array },
};
}
render() {
return html`
<h3>Append</h3>
<button @click="${this.__handleAppendClick}">Append</button>
<lea-tabs id="appendTabs">
<lea-tab slot="tab">tab 1</lea-tab>
<lea-tab-panel slot="panel">panel 1</lea-tab-panel>
<lea-tab slot="tab">tab 2</lea-tab>
<lea-tab-panel slot="panel">panel 2</lea-tab-panel>
</lea-tabs>
<hr />
<h3>Push</h3>
<button @click="${this.__handlePushClick}">Push</button>
<lea-tabs id="pushTabs">
<lea-tab slot="tab">tab 1</lea-tab>
<lea-tab-panel slot="panel">panel 1</lea-tab-panel>
<lea-tab slot="tab">tab 2</lea-tab>
<lea-tab-panel slot="panel">panel 2</lea-tab-panel>
${this.__collection.map(
item => html`
<lea-tab slot="tab">${item.button}</lea-tab>
<lea-tab-panel slot="panel">${item.panel}</lea-tab-panel>
`,
)}
</lea-tabs>
`;
}
constructor() {
super();
this.__collection = [];
}
__handleAppendClick() {
const tabsElement = this.shadowRoot.querySelector('#appendTabs');
const c = 2;
const n = Math.floor(tabsElement.children.length / 2);
for (let i = n + 1; i < n + c; i += 1) {
const tab = document.createElement('lea-tab');
tab.setAttribute('slot', 'tab');
tab.innerText = `tab ${i}`;
const panel = document.createElement('lea-tab-panel');
panel.setAttribute('slot', 'panel');
panel.innerText = `panel ${i}`;
tabsElement.append(tab);
tabsElement.append(panel);
}
}
__handlePushClick() {
const tabsElement = this.shadowRoot.querySelector('#pushTabs');
const i = Math.floor(tabsElement.children.length / 2) + 1;
this.__collection = [
...this.__collection,
{
button: `tab ${i}`,
panel: `panel ${i}`,
},
];
}
},
);
}
return html` <lea-tabs-experimental></lea-tabs-experimental> `;
};
```
One way is by creating the DOM elements and appending them as needed.
Inside your `lea-tabs` extension, an example for appending nodes on a certain button click:
```js
__handleAppendClick() {
const tabsAmount = this.children.length / 2;
const tab = document.createElement('lea-tab');
tab.setAttribute('slot', 'tab');
tab.innerText = `tab ${tabsAmount + 1}`;
const panel = document.createElement('lea-tab-panel');
panel.setAttribute('slot', 'panel');
panel.innerText = `panel ${tabsAmount + 1}`;
this.append(tab);
this.append(panel);
}
```
The other way is by adding data to a Lit property where you loop over this property in your template.
You then need to ensure this causes a re-render.
```js
__handlePushClick() {
const tabsAmount = this.children.length;
myCollection = [
...myCollection,
{
button: `tab ${tabsAmount + 1}`,
panel: `panel ${tabsAmount + 1}`,
},
];
renderMyCollection();
}
```
Make sure your template re-renders when myCollection is updated.
```html
<lea-tabs id="pushTabs">
${myCollection.map(item => html`
<lea-tab slot="tab">${item.button}</lea-tab>
<lea-tab-panel slot="panel">${item.panel}</lea-tab-panel>
`)}
</lea-tabs>
```
## Rationale
### No separate active/focus state when using keyboard
We will immediately switch content as all our content comes from light dom (e.g. no latency)
See Note at <https://www.w3.org/TR/wai-aria-practices/#keyboard-interaction-19>
> It is recommended that tabs activate automatically when they receive focus as long as their
> associated tab panels are displayed without noticeable latency. This typically requires tab
> panel content to be preloaded.
### Panels are not focusable
Focusable elements should have a means to interact with them. Tab panels themselves do not offer any interactiveness.
If there is a button or a form inside the tab panel then these elements get focused directly.

View file

@ -1,3 +0,0 @@
import { LeaTabPanel } from './src/LeaTabPanel.js';
customElements.define('lea-tab-panel', LeaTabPanel);

View file

@ -1,3 +0,0 @@
import { LeaTab } from './src/LeaTab.js';
customElements.define('lea-tab', LeaTab);

View file

@ -1,3 +0,0 @@
import { LeaTabs } from './src/LeaTabs.js';
customElements.define('lea-tabs', LeaTabs);

4
docs/404.md Normal file
View file

@ -0,0 +1,4 @@
---
permalink: 404.html
layout: layout-404
---

View file

@ -1,13 +0,0 @@
# Coding Guidelines
```js script
export default {
title: 'Guidelines/Intro',
};
```
First be sure to understand our [definitions](?path=/docs/guidelines-definitions--page).
- [Guidelines for Styling](?path=/docs/guidelines-styling--page)
- [Guidelines for Scoped Elements](?path=/docs/guidelines-scoped-elements--page)
- [Guidelines for SubClasser APIs](?path=/docs/guidelines-subclasser-apis--page)

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 837 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

View file

@ -0,0 +1,39 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="700.000000pt" height="700.000000pt" viewBox="0 0 700.000000 700.000000"
preserveAspectRatio="xMidYMid meet">
<metadata>
Created by potrace 1.11, written by Peter Selinger 2001-2013
</metadata>
<g transform="translate(0.000000,700.000000) scale(0.100000,-0.100000)"
fill="#000000" stroke="none">
<path d="M2732 6067 c-12 -7 -62 -43 -111 -82 l-90 -70 -1 -91 c0 -87 -1 -91
-30 -119 -17 -16 -28 -36 -26 -44 3 -9 8 -74 11 -146 4 -71 8 -141 10 -155 2
-14 7 -83 10 -155 4 -71 8 -141 10 -155 2 -14 7 -79 10 -145 4 -66 8 -136 10
-155 2 -19 6 -89 10 -155 4 -66 8 -136 10 -155 2 -19 7 -89 10 -155 4 -66 8
-131 10 -145 1 -14 -9 -43 -23 -65 -15 -23 -26 -55 -26 -75 0 -38 10 -234 29
-580 8 -139 11 -206 20 -370 4 -69 8 -150 10 -180 2 -30 7 -122 10 -205 4 -82
9 -167 10 -188 3 -31 0 -37 -13 -33 -10 3 -33 8 -52 11 -19 3 -66 12 -105 20
-38 8 -144 28 -235 45 -91 17 -208 40 -260 50 -52 11 -113 22 -135 26 -22 3
-43 8 -46 9 -3 2 -28 7 -55 11 -27 3 -52 8 -55 10 -3 2 -21 6 -40 9 -19 3 -90
16 -159 30 -69 13 -141 27 -160 30 -19 3 -78 14 -130 25 -52 10 -111 22 -130
25 -19 3 -66 12 -105 20 -38 8 -86 17 -105 20 -19 3 -80 15 -135 25 -177 34
-161 35 -263 -15 -72 -35 -92 -49 -92 -66 0 -33 58 -81 166 -137 250 -130 242
-125 248 -158 6 -27 13 -33 60 -48 46 -14 55 -21 58 -43 4 -33 -5 -28 241
-134 54 -23 95 -45 90 -48 -4 -4 -24 -19 -43 -33 -19 -14 -174 -127 -344 -252
l-309 -228 -76 7 c-41 3 -78 8 -82 10 -3 3 -57 -25 -120 -61 -63 -36 -138 -80
-167 -96 -29 -17 -52 -32 -50 -33 3 -4 628 -13 1123 -17 l260 -3 0 170 1 170
93 125 c52 69 95 126 96 128 1 1 67 -14 146 -33 79 -20 155 -38 169 -41 14 -2
32 -7 40 -10 8 -3 26 -8 40 -10 14 -3 36 -8 50 -13 14 -5 52 -15 85 -22 33 -7
63 -15 68 -19 4 -3 -64 -55 -150 -114 -87 -59 -219 -149 -294 -200 -74 -51
-144 -96 -154 -99 -10 -4 -15 -10 -12 -13 5 -5 5408 -6 5413 -1 2 1 -54 48
-124 104 -228 183 -377 323 -497 464 -57 69 -239 344 -299 454 -10 18 -143
241 -449 755 -64 107 -137 218 -163 245 -26 28 -86 92 -133 144 -47 52 -97
106 -111 121 -93 100 -219 236 -239 259 -195 214 -241 257 -351 331 -97 65
-146 109 -310 277 -171 177 -204 205 -267 237 -78 39 -62 21 -262 295 -146
199 -142 196 -204 211 -50 12 -57 16 -63 44 -22 104 -90 254 -160 352 -116
164 -306 278 -499 300 -27 3 -60 7 -71 9 -12 2 -31 -2 -42 -8z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

31
docs/_assets/logo.svg Normal file
View file

@ -0,0 +1,31 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 457 457">
<defs/>
<g transform="translate(-247.653 -647.52)">
<path fill="#65511b" d="M247.38 1008.44l91.25 1.03-.62-22.05 12.62-16.75 39.85 9.9-38.43 26.2-3.38 1.93 355.09-.12s-35.2-26.06-47.95-46.15c-12.91-20.32-49.38-82.24-49.38-82.24l-50-54.21-15.35-10.36-25.63-26.32-9.3-4.51-21.61-29.53-7.74-2.16s-6.81-44.22-50.2-45.2L413 718.61l-.27 12.01-3.4 2.93 6.63 102.33-3.47 5.94 5.5 103.31-136.33-26.07-12.37 5.75-.06 3.01 4.36 4.11 22.01 11.5 1.02 4.03 6.63 2.16 1.02 4.03 22.05 9.5-46.4 34.03-11.1-1.25-21.44 12.51z"/>
<linearGradient id="a" x1="201.739" x2="210.647" y1="1781.71" y2="1778.468" gradientTransform="matrix(12.274 0 0 -67.886 -2104.537 121677.61)" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#c19d3b"/>
<stop offset="1" stop-color="#65511b"/>
</linearGradient>
<path fill="url(#a)" d="M426.6 707.87l26.86 244.04-35.47-6.8-5.5-103.31 3.47-5.94-6.63-102.33 3.4-2.93.27-12.01 13.6-10.72z"/>
<linearGradient id="b" x1="219.109" x2="219.562" y1="1780.966" y2="1778.31" gradientTransform="matrix(25.036 0 0 -12.792 -5195.276 23762.836)" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#c19d3b"/>
<stop offset="1" stop-color="#65511b"/>
</linearGradient>
<path fill="url(#b)" d="M326.31 963.11l11.08 2.25-31.76 43.73-58.24-.65 21.43-12.55 11.1 1.25 46.39-34.03z"/>
<linearGradient id="c" x1="226.508" x2="228.072" y1="1784.668" y2="1781.059" gradientTransform="matrix(31.819 0 0 -41.355 -6759.904 74504.36)" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#c19d3b"/>
<stop offset="1" stop-color="#65511b"/>
</linearGradient>
<path fill="url(#c)" d="M476.8 753.07s-6.68 50.27-17.04 65.4c-7.3 9.04-13.26 19.08-17.71 29.82l5.88 53.44s9.29-18.86 56.63-45.86c14.68-8.37 35.85-10.22 51.87-29.91l-15.35-10.36-25.63-26.32-9.3-4.51-21.61-29.53-7.74-2.17z"/>
<linearGradient id="d" x1="230.192" x2="231.598" y1="1783.099" y2="1780.414" gradientTransform="matrix(44.091 0 0 -35.032 -9687.025 63279.066)" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#c19d3b"/>
<stop offset="1" stop-color="#65511b"/>
</linearGradient>
<path fill="url(#d)" d="M447.93 901.74s15.43-24.23 56.63-45.86c14.64-7.69 33.58-8.27 51.87-29.91l50 54.2a256.687 256.687 0 01-62.81 21.53c-27.95 5.39-41.53 15.55-50.61 23.37a276.64 276.64 0 01-39.54 26.84l-2.83-23.1-2.71-27.07z"/>
<linearGradient id="e" x1="231.595" x2="232.99" y1="1785.571" y2="1779.909" gradientTransform="matrix(49.718 0 0 -21.1301 -11028.4 38569.195)" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#c19d3b"/>
<stop offset="1" stop-color="#65511b"/>
</linearGradient>
<path fill="url(#e)" d="M453.45 951.91a245.398 245.398 0 0038.42-25.75c9.08-7.81 21.55-18 49.5-23.39a272.307 272.307 0 0065.07-22.6l25.75 43.65c-43.55 6.04-82.95 26.21-103.07 29.77-37.18 6.57-75.67-1.68-75.67-1.68z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

23
docs/_assets/style.css Normal file
View file

@ -0,0 +1,23 @@
body[layout='layout-home'] .markdown-body .call-to-action:nth-of-type(2) {
--primary-color: #222;
--primary-color-lighter: #333;
--primary-color-darker: #000;
}
.markdown-body img {
width: 100%;
}
mdjs-preview {
margin-bottom: 20px;
}
#main-header a[href="/blog/"] {
display: none;
}
@media screen and (min-width: 1024px) {
#main-header a[href="/blog/"] {
display: block;
}
}

View file

@ -0,0 +1,41 @@
html {
--primary-color: #a07f23;
--primary-color-lighter: #d1a62f;
--primary-color-darker: #705918;
--primary-color-accent: #cee5f6;
--primary-text-color: #2c3e50;
--primary-lines-color: #ccc;
/* Contrast colors */
--contrast-color-light: #fff;
--contrast-color-dark: #1d3557;
/* background-colors */
--page-background: white;
--footer-background: rgba(0, 0, 0, 0.1);
--text-color: black;
}
html.dark {
--primary-color: #e63946;
--primary-color-lighter: #e25761;
--primary-color-darker: #a22831;
--primary-color-accent: #cee5f6;
--primary-text-color: #eee;
/* Contrast colors */
--contrast-color-light: #fff;
--contrast-color-dark: #1d3557;
/* background-colors */
--page-background: #333;
--footer-background: #4f4f4f;
--text-color: white;
--markdown-octicon-link: white;
--markdown-syntax-background-color: #a0a0a0;
--markdown-link-color: #fb7881;
--markdown-blockquote-color: #c9e3ff;
}

41
docs/_data/footer.json Normal file
View file

@ -0,0 +1,41 @@
[
{
"name": "Discover",
"children": [
{
"text": "Blog",
"href": "/blog/"
},
{
"text": "Help and Feedback",
"href": "https://github.com/ing-bank/lion/issues"
}
]
},
{
"name": "Follow",
"children": [
{
"text": "Github",
"href": "https://github.com/ing-bank/lion"
},
{
"text": "Twitter",
"href": "https://twitter.com/daKmoR"
},
{
"text": "Slack",
"href": "/about/slack/"
}
]
},
{
"name": "Support",
"children": [
{
"text": "Contribute",
"href": "https://github.com/ing-bank/lion/blob/master/CONTRIBUTING.md"
}
]
}
]

22
docs/_data/site.cjs Normal file
View file

@ -0,0 +1,22 @@
module.exports = async function () {
return {
dir: 'ltr',
lang: 'en',
name: 'Lion',
description: 'Fundamental white label web components for building your design system',
socialLinks: [
{
name: 'GitHub',
url: 'https://github.com/ing-bank/lion',
},
],
gitSiteUrl: 'https://github.com/ing-bank/lion',
gitBranch: 'master',
helpUrl: 'https://github.com/ing-bank/lion/issues',
logoAlt: 'Lion Logo',
iconColorMaskIcon: '#3f93ce',
iconColorMsapplicationTileColor: '#1d3557',
iconColorThemeColor: '#1d3557',
analytics: 'G-151V7YV71K',
};
};

5
docs/about/slack.md Normal file
View file

@ -0,0 +1,5 @@
# Slack
You can also find us on the Polymer Slack in the [#lion](https://polymer.slack.com/archives/CJGFWJN9J) channel.
You can join the Polymer Slack by visiting [https://www.polymer-project.org/slack-invite](https://www.polymer-project.org/slack-invite).

View file

@ -0,0 +1,173 @@
---
title: Controlling exports
published: true
description: Maintainer can now define their public api of a package itself.
date: 2021-03-09
tags: [javascript, exports]
cover_image: /blog/images/controlling-exports-cover-image.jpg
---
When publishing npm packages it can often be hard to understand what users are actually using.
Basically, JavaScript allows you to write imports like this
```js
import { addLeadingZero } '@lion/localize/src/date/utils/addLeadingZero.js';
```
We as the maintainers of that package however consider this internal code, so any changes to it will not result in a new breaking change update.
So if you depend on this directly then your code may break with any minor or patch update.
So why would we even "allow" such imports? Because so far there was no way to actually define and enforce what a maintainer considers to be the public API of the package. Now, with the introduction of node's [Package Entry Points](https://nodejs.org/api/packages.html#packages_package_entry_points) and the adoption of it in [@rollup/plugin-node-resolve](https://github.com/rollup/plugins/tree/master/packages/node-resolve#package-entrypoints) it can now be used in node, [@web/dev-server](https://modern-web.dev/docs/dev-server/overview/) and [rollup](https://rollupjs.org/).
How can you use those `Package Entry Points`?
Let's assume you have these two files in your `src` directory.
```js
// src/index.js
export { foo } from './public.js';
// src/public.js
export const foo = 'public foo';
// src/internal.js
export const bar = 'internal bar';
```
If you publish the package "normally" then users will be able to write imports like this
```js
import { foo } from 'my-pkg';
import { foo } from 'my-pkg/src/public.js';
import { bar } from 'my-pkg/src/internal.js';
```
This has multiple issues, described in use cases:
1. Case 1: For maintenance purposes, we want to split `public.js` in `featureA.js` and `helpers.js`. Now all imports that use `import { foo } from 'my-pkg/src/public.js';` will break.
2. Case 2: We found a package that solved what we did in `internal.js` in a more generic way. We don't treat it as public API, so we actually go ahead and get rid of this file. Now all imports for `import { bar } from 'my-pkg/src/internal.js';` will break.
Instead, what we actually want is all our consumers using the intended public API, which is
```js
import { foo } from 'my-pkg';
```
This way, above cases 1 and 2 just don't have any effect and we can freely refactor our codebase without introducing breaking changes. This means we can keep improving our code without disturbing our users. It's a win-win situation 🎉
Now, if someone tries to use a not defined export, like
```js
import { bar } from 'my-pkg/src/internal.js';
```
Then an error will be thrown
```
Could not resolve import "my-pkg/src/internal.js"
```
If a users needs access to `bar` then a GitHub Issue/Discussion should be opened to request it.
Maintainers can then have a discussion if they want to make this part of the public API or not.
## Using consumer import in your own code
An additional benefit of using Package Entry Points is that you can write imports in the same way as your consumers.
So instead of writing demos or tests like
```js
import { LionInput } from '../src/LionInput.js';
```
we can now write
```js
import { LionInput } from '@lion/input';
```
This has the following benefits:
- We can make sure everything we are demoing/testing is actually part of the public API
- Users can read / copy our demo code and it just works
- We can move files around without needing to adjust our demos/docs/tests
## Exports for a single web component
Usage:
```js
// only the classes
import { MyElement } from 'my-element';
// OR
// execute customElements.define
import 'my-element/define';
```
Package Entry Points:
```json
"exports": {
".": "./src/index.js",
"define": "./src/my-element.js",
}
```
## Exports for multiple web components
Usage:
```js
// only the classes
import { MyElement, SubElement } from 'my-element';
// OR
// execute customElements.define for all elements
import 'my-element/define';
// execute customElements.define for a single element
import 'my-element/define-my-element';
import 'my-element/define-sub-element';
```
Package Entry Points:
```json
"exports": {
".": "./src/index.js",
"define": "./src/define.js",
"define-my-element": "./src/my-element.js",
"define-sub-element": "./src/sub-element.js",
}
```
in this case, the `src/define.js` should not contain any `customElements.define`, but instead it just imports the other define files
```js
import 'my-element/define-my-element';
import 'my-element/define-sub-element';
```
## What does it mean for Lion?
Imports that worked before will need be be adjusted as they will no longer work.
This is a breaking change.
```js
// no longer works
import '@lion/input/lion-input';
import '@lion/input/lion-input.js';
import { LionInput } from '@lion/input/src/LionInput.js';
// works
import '@lion/input/define';
import { LionInput } from '@lion/input';
```
---
Photo by <a href="https://unsplash.com/@curology?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Curology</a> on <a href="https://unsplash.com/">Unsplash</a>

View file

@ -1,12 +1,13 @@
# Extending Lion Documentation ---
title: Extending Lion Documentation
published: true
description: Extending a component library and its documentation for a speedy design system
date: 2020-12-01
tags: javascript, documentation, demos
cover_image: https://miro.medium.com/max/2000/1*NZ6tdtJHHJjxtPmIFxWpGw.jpeg
---
```js script If you extend [Lion](https://lion-web.netlify.app/) components, you don't only want to reuse the components, but you probably want to reuse the documentation (Storybook demos) as well. Wouldn't it be nice to just take it all from lion, but replace it with your own design system extension, so you don't have the extra maintenance of essentially copying the docs from `Lion` for your own design system implementation?
export default {
title: 'Guidelines/Extending documentation',
};
```
If you extend [Lion](https://lion-web-components.netlify.app/) components, you don't only want to reuse the components, but you probably want to reuse the documentation (Storybook demos) as well. Wouldn't it be nice to just take it all from lion, but replace it with your own design system extension, so you don't have the extra maintenance of essentially copying the docs from `Lion` for your own design system implementation?
In this blog we will explain how `Lion` supports this use case, and allows you to extend not just the components, but also the documentation. In this blog we will explain how `Lion` supports this use case, and allows you to extend not just the components, but also the documentation.
@ -29,13 +30,13 @@ For step 1, we can use `@open-wc/demoing-storybook` version 2 or higher, which u
Install it manually (and see the docs for configuring): Install it manually (and see the docs for configuring):
```sh ```bash
npm i @open-wc/demoing-storybook --save-dev npm i @open-wc/demoing-storybook --save-dev
``` ```
Or scaffold it with basic configuration by doing Or scaffold it with basic configuration by doing
```sh ```bash
npm init @open-wc npm init @open-wc
``` ```
@ -66,11 +67,11 @@ This step alone should already give you the `LionTabs` docs inside your own Stor
Potentially the hardest part is to analyse your extension `LeaTabs`, and to figure out how we should transform the import paths for `LionTabs` to new paths to your `LeaTabs`. Potentially the hardest part is to analyse your extension `LeaTabs`, and to figure out how we should transform the import paths for `LionTabs` to new paths to your `LeaTabs`.
To do this we make use of [Providence](https://lion-web-components.netlify.app/?path=/docs/tools-providence-main--run-providence). This tool has a command that creates a full map of all the import paths of a reference project (`Lion`) and can replace them with the correct paths of a target project (`Lea`). To do this we make use of [Providence](https://lion-web.netlify.app/?path=/docs/tools-providence-main--run-providence). This tool has a command that creates a full map of all the import paths of a reference project (`Lion`) and can replace them with the correct paths of a target project (`Lea`).
So lets install it: So lets install it:
```sh ```bash
npm i providence-analytics --save-dev npm i providence-analytics --save-dev
``` ```
@ -86,7 +87,7 @@ The `--prefix-from` and `--prefix-to` are the prefixes of the project you extend
If you know you only use a single component from lion, you can reduce the time the tool needs for analysis, by specifying this package `-r 'node_modules/@lion/tabs'`. If you know you only use a single component from lion, you can reduce the time the tool needs for analysis, by specifying this package `-r 'node_modules/@lion/tabs'`.
Running the script will create a `providence-extend-docs-data.json` file, with all from/to information. You can change the name / location of the output file, refer to [Providence Documentation](https://lion-web-components.netlify.app/?path=/docs/tools-providence-main--run-providence) for this. Running the script will create a `providence-extend-docs-data.json` file, with all from/to information. You can change the name / location of the output file, refer to [Providence Documentation](https://lion-web.netlify.app/?path=/docs/tools-providence-main--run-providence) for this.
#### Running it automatically when upgrading lion dependency #### Running it automatically when upgrading lion dependency
@ -103,13 +104,13 @@ Inside ING, our design system also makes use of this providence tool to create t
Now that we have a JSON file with all the information we need to know about to replace import paths and tagnames inside templates, we can start transforming the `LionTabs` documentation to `LeaTabs` documentation. Now that we have a JSON file with all the information we need to know about to replace import paths and tagnames inside templates, we can start transforming the `LionTabs` documentation to `LeaTabs` documentation.
For this, we created a `babel-plugin` called [babel-plugin-extend-docs](https://lion-web-components.netlify.app/?path=/docs/tools-babelpluginextenddocs--page). For this, we created a `babel-plugin` called [babel-plugin-extend-docs](https://lion-web.netlify.app/?path=/docs/tools-babelpluginextenddocs--page).
This will analyse the JavaScript script and story content inside the markdown files, which uses [MDJS](https://open-wc.org/mdjs/) syntax, and transform it on the fly in `es-dev-server`, as well as on rollup build for production. This will analyse the JavaScript script and story content inside the markdown files, which uses [MDJS](https://open-wc.org/mdjs/) syntax, and transform it on the fly in `es-dev-server`, as well as on rollup build for production.
So all you need to do is to install this plugin: So all you need to do is to install this plugin:
```sh ```bash
npm i babel-plugin-extend-docs --save-dev npm i babel-plugin-extend-docs --save-dev
``` ```
@ -164,7 +165,7 @@ In some cases you don't want to show all examples of how to use a component. Som
In our example, we will show you have to remove the `Rationale` section that you would normally inherit from the `Lion` documentation. In our example, we will show you have to remove the `Rationale` section that you would normally inherit from the `Lion` documentation.
For this step we make use of a remark plugin for the MD content, similar to how you would use a babel plugin for JS content. It is called [Remark extend](https://lion-web-components.netlify.app/?path=/docs/tools-remark-extend--page). For this step we make use of a remark plugin for the MD content, similar to how you would use a babel plugin for JS content. It is called [Remark extend](https://lion-web.netlify.app/?path=/docs/tools-remark-extend--page).
It will let you add, remove or replace sections or specific words. It will let you add, remove or replace sections or specific words.
First of all we need to add the plugin to the `.storybook/main.js`: First of all we need to add the plugin to the `.storybook/main.js`:
@ -256,7 +257,7 @@ Or you can add an extra paragraph below the content. Create a fenced codeblock:
::removeMdAfter(':scope:last-child') ::removeMdAfter(':scope:last-child')
``` ```
> See [Remark extend](https://lion-web-components.netlify.app/?path=/docs/tools-remark-extend--page) for more information > See [Remark extend](https://lion-web.netlify.app/?path=/docs/tools-remark-extend--page) for more information
### Lea Tabs Special Feature ### Lea Tabs Special Feature

View file

@ -0,0 +1,124 @@
---
title: Extending lions website
published: false
description: A static website with docs and demos for lion
date: 2021-03-10
tags: [javascript, rocket, documentation]
cover_image: /blog/images/introducing-lions-website-cover-image.jpg
---
After a month of preparations we can finally present to you our new website. With it we are enabled to give more context to each of our components.
Right now it's more or less a port for our existing demos from storybook. But we can organize it in a nicer way by splitting it into components, docs, guides and blog sections.
## Importing Content into Markdown files
We now use a system to import content from one markdown file into another.
So let's say you find the documentation of `input-amount` useful and you want to present it on your page as well.
Anywhere in your documentation you can now write.
👉 `docs/input-amount.md`
````md
# Input Amount
```js ::import('@lion/input-amount/docs/overview.md', 'heading[depth=1] ~ *')
```
````
So when you now go to `https://domain.com/input-amount/` you will actually see the content from `@lion/input-amount/docs/overview.md`.
Why is it a `js code block`?
- You can define a start and end for what should be imported (using [unist-util-select](https://github.com/syntax-tree/unist-util-select#support))
- You can add adjustments to the content as a function
- As links like `[go there](@lion/input-amount/docs/overview.md)` would not work anyways, having one syntax that allows for additional features is enough
### Importing Partial Content
Quite often you probably don't want to get the full file, so there is a special helper for that.
Let's assume you have the following source file
```md
# First Headline
Content of first headline
## Second Headline
Content of second headline
## Third Headline
Content of Third headline
```
and you only want to get the 2nd "block" e.g. 2nd headline + text.
With `importBlock` you can get exactly that.
A block starts with a headline and ends when the next headline of an equal level starts.
Note: importBlock is a faster way of writing imports for headlines
```md
::importBlock('./path/to/file.md', '## red')
// is the same as
::import('./path/to/file.md', 'heading[depth=2]:has([value=red])', 'heading[depth=2]:has([value=red]) ~heading[depth=2]')
```
If you want to know more please look at the documentation for [remark-extend](../docs/node-tools/remark-extend/overview.md).
## Upgrading Documentation
Unfortunately this is quite a different concept then what we used with storybook before. Luckily the content is very much the same.
Let's convert an example page
### FROM
````md
# Calendar
`lion-calendar` is a reusable and accessible calendar view. It depends on [calendar](?path=/docs/calendar--default-story).
```js script
import { html, css } from '@lion/core';
import './lion-calendar.js';
export default {
title: 'Others/Calendar',
};
```
...
````
### TO
````md
# Component >> Calendar ||20
`lion-calendar` is a reusable and accessible calendar view. It depends on [calendar](../../path/to/calendar.md).
```js script
import { html, css } from '@lion/core';
import '@lion/calendar/define';
```
...
````
So what you need to do:
1. Remove the js default export and put the title / navigation into the headline
2. Replace all imports with the Package Entry Points
3. Adjust all link to be relative links to actual files (instead of storybook specific urls)
## Upgrading Extending Documentation
If you are currently extending our storybook documentation then this will no longer work.
For now we will need to ask you to stay on the current version and NOT upgrade.
We will release the necessary tools to extend our Lion Website in the upcoming weeks 🤗

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

View file

Before

Width:  |  Height:  |  Size: 247 KiB

After

Width:  |  Height:  |  Size: 247 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

14
docs/blog/index.md Normal file
View file

@ -0,0 +1,14 @@
---
title: Lion Blog
layout: layout-blog-overview
eleventyNavigation:
key: Blog
order: 40
pagination:
data: collections.blog
size: 10
reverse: true
alias: posts
---
Discover articles from the core team and contributors about Lion, tips and tricks included!

View file

@ -1,10 +1,11 @@
# ING open sources Lion: A library of performant, accessible & flexible Web Components ---
title: ING open sources Lion
```js script published: true
export default { description: A library of performant, accessible & flexible Web Components
title: 'Intro/Announcement', date: 2020-08-10
}; tags: [javascript, tests, demos]
``` cover_image: https://miro.medium.com/max/1400/1*FT8CF6G-1IVa88G04nkf5w.png
---
**TL;DR:** Web development can be hard, whether you're making your own components, implementing Design Systems, support many different browsers, incorporating accessibility, or adding third party dependencies. Lion aims to make your life a little bit easier, by taking the groundwork of feature complete, accessible, performant, and framework agnostic components out of your hands! Check out the repo at [ing-bank/lion](https://github.com/ing-bank/lion). **TL;DR:** Web development can be hard, whether you're making your own components, implementing Design Systems, support many different browsers, incorporating accessibility, or adding third party dependencies. Lion aims to make your life a little bit easier, by taking the groundwork of feature complete, accessible, performant, and framework agnostic components out of your hands! Check out the repo at [ing-bank/lion](https://github.com/ing-bank/lion).
@ -79,9 +80,9 @@ Lion is a core package of white label Web Components. What this means is that th
And this is exactly what we at ING do as well. Our very own ing-web components extend the Lion components and apply our own ING visual identity which mostly is a thin layer on top of Lion. And this is exactly what we at ING do as well. Our very own ing-web components extend the Lion components and apply our own ING visual identity which mostly is a thin layer on top of Lion.
Check out the [Lion demo's](http://lion-web-components.netlify.com/). Looks plain, doesn't it? And now compare Lion to ing-web: Check out the [Lion demo's](http://lion-web.netlify.app/). Looks plain, doesn't it? And now compare Lion to ing-web:
![Lion - ing-web side by side](https://raw.githubusercontent.com/ing-bank/lion/master/demo/docs/assets/side-by-side.png) ![Lion - ing-web side by side](./images/ing-open-sources-lion-side-by-side.png)
### 🎯 Focus ### 🎯 Focus
@ -149,7 +150,7 @@ npm i lit-element @lion/tabs
Create a `lea-tabs` component by reusing the functionality of Lion. This gives Lea all the functionality and accessible core that she needs for his custom tabs component. Create a `lea-tabs` component by reusing the functionality of Lion. This gives Lea all the functionality and accessible core that she needs for his custom tabs component.
```js ```js
import { css } from '@lion/core'; import { css } from 'lit-element';
import { LionTabs } from '@lion/tabs'; import { LionTabs } from '@lion/tabs';
export class LeaTabs extends LionTabs { export class LeaTabs extends LionTabs {
@ -178,7 +179,7 @@ customElements.define('lea-tabs', LeaTabs);
Lea also wants to be able to style the tab and tab-panel according to Betatechs visual identity. In order to do so, she creates a `lea-tab-panel` component and a `lea-tab` component, which she can then fully style however she desires, and eventually place inside the `lea-tabs` component. You can see how Lea achieved this in the example down below. Lea also wants to be able to style the tab and tab-panel according to Betatechs visual identity. In order to do so, she creates a `lea-tab-panel` component and a `lea-tab` component, which she can then fully style however she desires, and eventually place inside the `lea-tabs` component. You can see how Lea achieved this in the example down below.
```js ```js
import { LitElement, html, css } from '@lion/core'; import { LitElement, html, css } from 'lit-element';
export class LeaTab extends LitElement { export class LeaTab extends LitElement {
static get styles() { static get styles() {
@ -209,7 +210,7 @@ Excellent! Lea can now use the tabs component like so:
</lea-tabs> </lea-tabs>
``` ```
There we go, Lea's component is already done, so let's write some documentation. See the [live Lea tabs documentation page](?path=/docs/intro-tabs-example--default-story). You can see the full code of `lea-tabs` [on github](https://github.com/ing-bank/lion/tree/master/demo/). There we go, Lea's component is already done, so let's write some documentation. See the [live Lea tabs documentation page](../components/content/tabs/examples.md). You can see the full code of `lea-tabs` [on github](https://github.com/ing-bank/lion/tree/master/demo/).
P.S.: Do note that Lea is now responsible for keeping the documentation of `lea-tabs` up to date herself, and improvements on Lion's documentation will not automatically be reflected on Lea's documentation. P.S.: Do note that Lea is now responsible for keeping the documentation of `lea-tabs` up to date herself, and improvements on Lion's documentation will not automatically be reflected on Lea's documentation.
@ -223,7 +224,7 @@ Component libraries are in huge demand. By open-sourcing our extendable componen
Building applications is hard, and sometimes, you need a little bit more than just the right component alone, but also things like: Validation, Forms, Overlays, Localization, etc. But fear not; Lion has got you covered! Building applications is hard, and sometimes, you need a little bit more than just the right component alone, but also things like: Validation, Forms, Overlays, Localization, etc. But fear not; Lion has got you covered!
You can check them out in our [documentation](http://lion-web-components.netlify.com/), and we'll go into more depth about Lion's additional systems in future blog posts. You can check them out in our [documentation](http://lion-web.netlify.app/), and we'll go into more depth about Lion's additional systems in future blog posts.
## Thanks ## Thanks

View file

@ -0,0 +1,110 @@
---
title: Introducing lions website
published: true
description: A static website with docs and demos for lion
date: 2021-03-10
tags: [javascript, rocket, documentation]
cover_image: /blog/images/introducing-lions-website-cover-image.jpg
---
After a month of preparations, we can finally present to you our new website. With it, we are enabled to give more context to each of our components.
Right now it's more or less a port for our existing demos from storybook. But we can organize it in a nicer way by splitting it into components, docs, guides and blog sections.
## Meet the new sections
1. [Guides](../guides/index.md) <br>
A dedicated section where we will teach you about how to get started with lion. This section is completely new and will grow over time.
2. [Components](../components/index.md) <br>
Here you will find our documentation for each of our components. Each is split into two pages namely Overview and Features. We also plan to add an API page soonish.
3. [Docs](../docs/index.md) <br>
This is the home for general documentation which includes the fundamental systems all our components are build upon and various tools we use in the frontend or backend.
4. [Blog](./index.md) <br>
We now have a dedicated section about all our blog posts. Take a peek and follow our story.
## Upgrading Our Documentation
As this page is now a static website and no longer storybook we needed to convert all our documentation.
Luckily the format is very similar.
Let's convert an example page
### FROM
````md
# Calendar
`lion-calendar` is a reusable and accessible calendar view. It depends on [calendar](?path=/docs/calendar--default-story).
```js script
import { html, css } from '@lion/core';
import './lion-calendar.js';
export default {
title: 'Others/Calendar',
};
```
...
````
### TO
````md
# Component >> Calendar ||20
`lion-calendar` is a reusable and accessible calendar view. It depends on [calendar](../../path/to/calendar.md).
```js script
import { html, css } from '@lion/core';
import '@lion/calendar/define';
```
...
````
So what we needed to do:
1. Remove the js default export and put the title / navigation into the headline
2. Replace all imports with the Package Entry Points
3. Adjust all link to be relative links to actual files (instead of storybook specific urls)
## Handling Mono Repo Documentation
All of our documentation now resides in the root `docs` folder. To publish them with our components we added a tool that can copy content and files into our published package.
Let's say you have this file in your documentation.
👉 `docs/components/accordion/overview.md`
```
# Accordion
Is a very useful...
```
Now you want to make sure it gets published with your accordion package so you replace you Readme file with this
👉 `packages/accordion/README.md`
```
# Accordion
[=> See Source <=](../../docs/components/content/accordion/overview.md)
```
Now by calling `publish-docs` within the `prepublishOnly` step your Readme file will contain the content of its source.
The benefits of this approach are
- Readme still makes sense on GitHub (e.g. you can navigate to the package and with one click you are at the docs)
- The published readme contains all the documentation you need
- All links are version safe (e.g. if you look at v0.5 it will link to the GitHub Pages at this time)
If you want to know more please look at the documentation for [publish-docs](../docs/node-tools/publish-docs/overview.md).
## Upgrading Extending Documentation
If you are currently extending our storybook documentation then this will no longer work.
For now, we will need to ask you to stay on the current version and NOT upgrade.
We will release the necessary tools to extend our Lion Website in the upcoming weeks 🤗

9
docs/browserconfig.xml Normal file
View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<browserconfig>
<msapplication>
<tile>
<square150x150logo src="/mstile-150x150.png"/>
<TileColor>#1d3557</TileColor>
</tile>
</msapplication>
</browserconfig>

View file

@ -0,0 +1,214 @@
# Content >> Accordion >> Features ||20
```js script
import { LitElement, html } from '@lion/core';
import '@lion/accordion/define';
```
## Expanded
You can set `expanded` to pre-expand a certain invoker.
```js preview-story
export const expanded = () => html`
<lion-accordion .expanded=${[1]}>
<h3 slot="invoker">
<button>Lorem</button>
</h3>
<p slot="content">Lorem ipsum dolor sit, amet consectetur adipisicing elit.</p>
<h3 slot="invoker">
<button>Laboriosam</button>
</h3>
<p slot="content">
Laboriosam sequi odit cumque, enim aut assumenda itaque quis voluptas est quos fugiat unde
labore reiciendis saepe, iure, optio officiis obcaecati quibusdam.
</p>
</lion-accordion>
`;
```
## Slots Order
The invoker and content slots are ordered by DOM order.
```js preview-story
export const slotsOrder = () => html`
<lion-accordion>
<h3 slot="invoker">
<button>Lorem</button>
</h3>
<p slot="content">Lorem ipsum dolor sit, amet consectetur adipisicing elit.</p>
<h3 slot="invoker">
<button>Laboriosam</button>
</h3>
<p slot="content">
Laboriosam sequi odit cumque, enim aut assumenda itaque quis voluptas est quos fugiat unde
labore reiciendis saepe, iure, optio officiis obcaecati quibusdam.
</p>
</lion-accordion>
`;
```
## Multiline header
A header can be multiline.
```js preview-story
export const multilineHeader = () => html`
<lion-accordion>
<h3 slot="invoker">
<button>
header 1 with
<br />
multiple lines
</button>
</h3>
<p slot="content">content 1</p>
<h3 slot="invoker">
<button>header 2</button>
</h3>
<p slot="content">content 2</p>
</lion-accordion>
`;
```
## Distribute New Elements
Below, we demonstrate how you could dynamically add a new invoker + content.
```js preview-story
export const distributeNewElement = () => {
const tagName = 'demo-accordion-add-dynamically';
if (!customElements.get(tagName)) {
customElements.define(
tagName,
class extends LitElement {
static get properties() {
return {
__collection: { type: Array },
};
}
render() {
return html`
<h3>Append</h3>
<lion-accordion id="appendAccordion">
<h4 slot="invoker">
<button>header 1</button>
</h4>
<p slot="content">content 1</p>
<h4 slot="invoker">
<button>header 2</button>
</h4>
<p slot="content">content 2</p>
</lion-accordion>
<button @click="${this.__handleAppendClick}">Append</button>
<hr />
<h3>Push</h3>
<lion-accordion id="pushTabs">
<h4 slot="invoker">
<button>header 1</button>
</h4>
<p slot="content">content 1</p>
<h4 slot="invoker">
<button>header 2</button>
</h4>
<p slot="content">content 2</p>
${this.__collection.map(
item => html`
<h4 slot="invoker"><button>${item.invoker}</button></h4>
<p slot="content">${item.content}</p>
`,
)}
</lion-accordion>
<button @click="${this.__handlePushClick}">Push</button>
`;
}
constructor() {
super();
this.__collection = [];
}
__handleAppendClick() {
const accordionElement = this.shadowRoot.querySelector('#appendAccordion');
const c = 2;
const n = Math.floor(accordionElement.children.length / 2);
for (let i = n + 1; i < n + c; i += 1) {
const invoker = document.createElement('h4');
const button = document.createElement('button');
button.innerText = `header ${i}`;
invoker.setAttribute('slot', 'invoker');
invoker.appendChild(button);
const content = document.createElement('p');
content.setAttribute('slot', 'content');
content.innerText = `content ${i}`;
accordionElement.append(invoker);
accordionElement.append(content);
}
}
__handlePushClick() {
const accordionElement = this.shadowRoot.querySelector('#pushTabs');
const i = Math.floor(accordionElement.children.length / 2) + 1;
this.__collection = [
...this.__collection,
{
invoker: `header ${i}`,
content: `content ${i}`,
},
];
}
},
);
}
return html` <demo-accordion-add-dynamically></demo-accordion-add-dynamically> `;
};
```
One way is by creating the DOM elements and appending them as needed.
Inside your `lion-accordion` extension, an example for appending nodes on a certain button click:
```js
__handleAppendClick() {
const accordionAmount = this.children.length / 2;
const invoker = document.createElement('h4');
const button = document.createElement('button');
button.innerText = `header ${accordionAmount + 1}`;
invoker.setAttribute('slot', 'invoker');
invoker.appendChild(button);
const content = document.createElement('p');
content.setAttribute('slot', 'content');
content.innerText = `content ${accordionAmount + 1}`;
this.append(invoker);
this.append(content);
}
```
The other way is by adding data to a Lit property where you loop over this property in your template.
You then need to ensure this causes a re-render.
```js
__handlePushClick() {
const accordionAmount = this.children.length;
myCollection = [
...myCollection,
{
invoker: `header ${accordionAmount + 1}`,
content: `content ${accordionAmount + 1}`,
},
];
renderMyCollection();
}
```
Make sure your template re-renders when myCollection is updated.
```html
<lion-accordion id="pushAccordion">
${myCollection.map(item => html`
<h4 slot="invoker">
<button>${item.invoker}</button>
</h4>
<p slot="content">${item.content}</p>
`)}
</lion-accordion>
```

View file

@ -0,0 +1,3 @@
# Content >> Accordion
-> go to Overview

View file

@ -0,0 +1,52 @@
# Content >> Accordion >> Overview ||10
`lion-accordion` is a component used to toggle the display of sections of content.
Its purpose is to reduce the need to scroll when presenting multiple sections of content on a single page. Accordions often allow users to get the big picture before focusing on details.
```js script
import { html } from '@lion/core';
import '@lion/accordion/define';
```
```js preview-story
export const main = () => html`
<lion-accordion>
<h3 slot="invoker">
<button>Lorem</button>
</h3>
<p slot="content">Lorem ipsum dolor sit, amet consectetur adipisicing elit.</p>
<h3 slot="invoker">
<button>Laboriosam</button>
</h3>
<p slot="content">
Laboriosam sequi odit cumque, enim aut assumenda itaque quis voluptas est quos fugiat unde
labore reiciendis saepe, iure, optio officiis obcaecati quibusdam.
</p>
</lion-accordion>
`;
```
## Features
- content gets provided by users (slotted in)
- handles accessibility
- support navigation via keyboard
## Installation
```bash
npm i --save @lion/accordion
```
```js
import { LionAccordion } from '@lion/accordion';
// or
import '@lion/accordion/define';
```
## Rationale
### Contents are not focusable
Focusable elements should be interactive. Contents themselves do not offer any interactivity.
If there is a button or a form inside the tab panel then these elements get focused directly.

View file

@ -1,4 +1,4 @@
import { LionCollapsible } from '../index.js'; import { LionCollapsible } from '@lion/collapsible';
const EVENT = { const EVENT = {
TRANSITION_END: 'transitionend', TRANSITION_END: 'transitionend',
@ -8,8 +8,8 @@ const EVENT = {
* `CustomCollapsible` is a class for custom collapsible element (`<custom-collapsible>` web component). * `CustomCollapsible` is a class for custom collapsible element (`<custom-collapsible>` web component).
* @customElement custom-collapsible * @customElement custom-collapsible
*/ */
// @ts-expect-error false positive for incompatible static get properties. Lit-element merges super properties already for you.
export class CustomCollapsible extends LionCollapsible { export class CustomCollapsible extends LionCollapsible {
/** @type {any} */
static get properties() { static get properties() {
return { return {
transitioning: { transitioning: {
@ -56,9 +56,7 @@ export class CustomCollapsible extends LionCollapsible {
contentNode.style.setProperty('opacity', '1'); contentNode.style.setProperty('opacity', '1');
contentNode.style.setProperty('padding', '12px 0'); contentNode.style.setProperty('padding', '12px 0');
contentNode.style.setProperty('max-height', '0px'); contentNode.style.setProperty('max-height', '0px');
await /** @type {Promise<void>} */ (new Promise(resolve => await new Promise(resolve => requestAnimationFrame(() => resolve()));
requestAnimationFrame(() => resolve()),
));
contentNode.style.setProperty('max-height', expectedHeight); contentNode.style.setProperty('max-height', expectedHeight);
await this._waitForTransition({ contentNode }); await this._waitForTransition({ contentNode });
} }
@ -107,9 +105,9 @@ export class CustomCollapsible extends LionCollapsible {
*/ */
async __calculateHeight(contentNode) { async __calculateHeight(contentNode) {
contentNode.style.setProperty('max-height', ''); contentNode.style.setProperty('max-height', '');
await /** @type {Promise<void>} */ (new Promise(resolve => await new Promise(resolve => requestAnimationFrame(() => resolve()));
requestAnimationFrame(() => resolve()),
));
return this._contentHeight; // Expected height i.e. actual size once collapsed after animation return this._contentHeight; // Expected height i.e. actual size once collapsed after animation
} }
} }
customElements.define('custom-collapsible', CustomCollapsible);

View file

@ -0,0 +1,83 @@
# Content >> Collapsible >> Examples ||30
```js script
import { html } from '@lion/core';
import '@lion/collapsible/define';
import '@lion/button/define';
import './assets/CustomCollapsible.js';
import './assets/applyDemoCollapsibleStyles.js';
```
## Custom Invoker Template
A custom template can be specified to the `invoker` slot. It can be any button or custom component which mimics the button behavior for better accessibility support. In the below example, `lion-button` and native `button` with styling is used as a collapsible invoker.
```js preview-story
export const customInvokerTemplate = () => html`
<lion-collapsible style="margin-top:16px;">
<lion-button slot="invoker">More about cars</lion-button>
<div slot="content">
Most definitions of cars say that they run primarily on roads, seat one to eight people, have
four tires, and mainly transport people rather than goods.
</div>
</lion-collapsible>
`;
```
## Extended collapsible with animation
`LionCollapsible` can easily be extended to add more features in the component, like animation for example.
```js preview-story
export const customAnimation = () => html`
<div class="demo-custom-collapsible-container">
<div class="demo-custom-collapsible-body">
A motorcycle, often called a motorbike, bike, or cycle, is a two- or three-wheeled motor
vehicle.
</div>
<custom-collapsible>
<button class="demo-custom-collapsible-invoker" slot="invoker">MORE ABOUT MOTORCYCLES</button>
<div slot="content">
Motorcycle design varies greatly to suit a range of different purposes: long distance
travel, commuting, cruising, sport including racing, and off-road riding. Motorcycling is
riding a motorcycle and related social activity such as joining a motorcycle club and
attending motorcycle rallies.
</div>
</custom-collapsible>
</div>
<div class="demo-custom-collapsible-container">
<div class="demo-custom-collapsible-body">
A car (or automobile) is a wheeled motor vehicle used for transportation.
</div>
<custom-collapsible opened>
<button class="demo-custom-collapsible-invoker" slot="invoker">MORE ABOUT CARS</button>
<div slot="content">
Most definitions of cars say that they run primarily on roads, seat one to eight people,
have four tires, and mainly transport people rather than goods.
</div>
</custom-collapsible>
</div>
`;
```
Use `_showAnimation()` and `_hideAnimation()` methods to customize open and close behavior. Check the code for a full example of a `custom-collapsible`.
```js
_showAnimation({ contentNode }) {
const expectedHeight = await this.__calculateHeight(contentNode);
contentNode.style.setProperty('opacity', '1');
contentNode.style.setProperty('padding', '12px 0');
contentNode.style.setProperty('max-height', '0px');
await new Promise(resolve => requestAnimationFrame(() => resolve()));
contentNode.style.setProperty('max-height', expectedHeight);
await this._waitForTransition({ contentNode });
}
_hideAnimation({ contentNode }) {
if (this._contentHeight === '0px') {
return;
}
['opacity', 'padding', 'max-height'].map(prop => contentNode.style.setProperty(prop, 0));
await this._waitForTransition({ contentNode });
}
```

View file

@ -0,0 +1,79 @@
# Content >> Collapsible >> Features ||20
```js script
import { html } from '@lion/core';
import '@lion/collapsible/define';
```
## Default open
Add the `opened` attribute to keep the component default open.
```js preview-story
export const defaultOpen = () => html`
<lion-collapsible opened>
<button slot="invoker">More about cars</button>
<div slot="content">
Most definitions of cars say that they run primarily on roads, seat one to eight people, have
four tires, and mainly transport people rather than goods.
</div>
</lion-collapsible>
`;
```
## Methods
There are the following methods available to control the extra content for the collapsible.
- `toggle()`: toggle the extra content
- `show()`: show the extra content
- `hide()`: hide the extra content
```js preview-story
export const methods = ({ shadowRoot }) => html`
<lion-collapsible id="car-collapsible">
<button slot="invoker">More about cars</button>
<div slot="content">
Most definitions of cars say that they run primarily on roads, seat one to eight people, have
four tires, and mainly transport people rather than goods.
</div>
</lion-collapsible>
<section style="margin-top:16px">
<button @click=${() => shadowRoot.querySelector('#car-collapsible').toggle()}>
Toggle content
</button>
<button @click=${() => shadowRoot.querySelector('#car-collapsible').show()}>
Show content
</button>
<button @click=${() => shadowRoot.querySelector('#car-collapsible').hide()}>
Hide content
</button>
</section>
`;
```
## Events
`lion-collapsible` fires an event on `invoker` click to notify the component's current state. It is useful for analytics purposes or to perform some actions while expanding and collapsing the component.
- `@opened-changed`: triggers when collapsible either gets opened or closed
```js preview-story
export const events = ({ shadowRoot }) => html`
<div class="demo-custom-collapsible-state-container">
<strong id="collapsible-state"></strong>
</div>
<lion-collapsible
@opened-changed=${ev => {
const collapsibleState = shadowRoot.getElementById('collapsible-state');
collapsibleState.innerText = `Opened: ${ev.target.opened}`;
}}
>
<button slot="invoker">More about cars</button>
<div slot="content">
Most definitions of cars say that they run primarily on roads, seat one to eight people, have
four tires, and mainly transport people rather than goods.
</div>
</lion-collapsible>
`;
```

View file

@ -0,0 +1,3 @@
# Content >> Collapsible
-> go to Overview

View file

@ -0,0 +1,39 @@
# Content >> Collapsible >> Overview ||10
`lion-collapsible` is a combination of a button (the invoker), a chunk of 'extra content', and can be extended with an animation to disclose the extra content. There are two slots available respectively; `invoker` to specify the collapsible's invoker and `content` for the extra content of the collapsible.
```js script
import { html } from '@lion/core';
import '@lion/collapsible/define';
```
```js preview-story
export const main = () => html`
<lion-collapsible>
<button slot="invoker">More about cars</button>
<div slot="content">
Most definitions of cars say that they run primarily on roads, seat one to eight people, have
four tires, and mainly transport people rather than goods.
</div>
</lion-collapsible>
`;
```
## Features
- Use `opened` attribute or `toggle()` method to render default open
- `invoker` slot can be custom template e.g. `lion-button` or native `button` with custom styling
- Observe the state with the help of `@opened-changed` event
- `show()` and `hide()` are helper methods to hide or show the content from outside
## Installation
```bash
npm i --save @lion/collapsible
```
```js
import { LionCollapsible } from '@lion/collapsible';
// or
import '@lion/collapsible/define';
```

View file

@ -0,0 +1 @@
# Content ||10

View file

@ -1,26 +1,26 @@
import { svg, css } from '@lion/core'; import { html, css } from '@lion/core';
import { LionProgressIndicator } from '../index.js'; import { LionProgressIndicator } from '@lion/progress-indicator';
export class CustomProgressIndicator extends LionProgressIndicator { export class CustomProgressIndicator extends LionProgressIndicator {
static get styles() { static get styles() {
return [ return [
css` css`
:host { :host {
display: inline-block; display: block;
} }
svg { .progress--icon {
animation: spinner-rotate 2s linear infinite;
display: inline-block; display: inline-block;
height: 48px;
width: 48px; width: 48px;
height: 48px;
animation: spinner-rotate 2s linear infinite;
} }
circle { .progress--icon--circle {
animation: spinner-dash 1.35s ease-in-out infinite; animation: spinner-dash 1.35s ease-in-out infinite;
fill: none; fill: none;
stroke-width: 3.6; stroke-width: 6px;
stroke: firebrick; stroke: var(--primary-color);
stroke-dasharray: 100, 28; /* This is a fallback for IE11 */ stroke-dasharray: 100, 28; /* This is a fallback for IE11 */
} }
@ -49,8 +49,12 @@ export class CustomProgressIndicator extends LionProgressIndicator {
} }
_graphicTemplate() { _graphicTemplate() {
return svg`<svg viewBox="22 22 44 44"> return html`
<circle cx="44" cy="44" r="20.2" /> <svg class="progress--icon" viewBox="20 20 47 47">
</svg>`; <circle class="progress--icon--circle" cx="44" cy="44" r="20.2" />
</svg>
`;
} }
} }
customElements.define('custom-progress-indicator', CustomProgressIndicator);

View file

@ -0,0 +1,76 @@
# Content >> Progress Indicator >> Examples ||30
```js script
import { html } from '@lion/core';
import './assets/custom-progress-indicator.js';
```
## Extended indicator with a custom visual
`LionProgressIndicator` is designed to be extended to add visuals. Implement the `_graphicTemplate()` method to set the rendered content and apply styles normally.
### Example extension
```js
class CustomProgressIndicator extends LionProgressIndicator {
static get styles() {
return [
css`
:host {
display: block;
}
.progress--icon {
display: inline-block;
width: 48px;
height: 48px;
animation: spinner-rotate 2s linear infinite;
}
.progress--icon--circle {
animation: spinner-dash 1.35s ease-in-out infinite;
fill: none;
stroke-width: 6px;
stroke: var(--primary-color);
stroke-dasharray: 100, 28; /* This is a fallback for IE11 */
}
@keyframes spinner-rotate {
to {
transform: rotate(360deg);
}
}
@keyframes spinner-dash {
0% {
stroke-dasharray: 6, 122;
stroke-dashoffset: 0;
}
50% {
stroke-dasharray: 100, 28;
stroke-dashoffset: -16;
}
100% {
stroke-dasharray: 6, 122;
stroke-dashoffset: -127;
}
}
`,
];
}
_graphicTemplate() {
return html`
<svg class="progress--icon" viewBox="20 20 47 47">
<circle class="progress--icon--circle" cx="44" cy="44" r="20.2" />
</svg>
`;
}
}
```
### Result
```js preview-story
export const main = () => html` <custom-progress-indicator></custom-progress-indicator> `;
```

View file

@ -0,0 +1,3 @@
# Content >> Progress Indicator
-> go to Overview

View file

@ -0,0 +1,29 @@
# Content >> Progress Indicator >> Overview ||10
`lion-progress-indicator` implements accessibility requirements for progress indicators.
```html
<lion-progress-indicator></lion-progress-indicator>
```
Note: You don't see a live demo here as it would be empty, since there is no styling. Check out the [examples](./examples.md) if you want to see a possible implementation.
## Features
`LionProgressIndicator` is designed to be extended to add visuals.
- Accessibility compliant
- Localized "Loading" label
- Implementation independent of visuals
## Installation
```bash
npm i --save @lion/progress-indicator
```
```js
import { LionProgressIndicator } from '@lion/progress-indicator';
// or
import '@lion/progress-indicator/define';
```

View file

@ -0,0 +1,23 @@
# Content >> Tabs >> Examples ||30
```js script
import { LitElement, html } from '@lion/core';
import './src/lea-tabs.js';
import './src/lea-tab.js';
import './src/lea-tab-panel.js';
```
## Lea Tabs
Learn how to create the `lea tabs` in our ["introducing lion" blogpost](../../../blog/ing-open-sources-lion.md).
```js preview-story
export const main = () => html`
<lea-tabs>
<lea-tab slot="tab">Info</lea-tab>
<lea-tab-panel slot="panel"> Info page with lots of information about us. </lea-tab-panel>
<lea-tab slot="tab">Work</lea-tab>
<lea-tab-panel slot="panel"> Work page that showcases our work. </lea-tab-panel>
</lea-tabs>
`;
```

View file

@ -0,0 +1,194 @@
# Content >> Tabs >> Features ||20
```js script
import { LitElement, html } from '@lion/core';
import '@lion/tabs/define';
```
## Selected Index
You can set the `selectedIndex` to select a certain tab.
```js preview-story
export const selectedIndex = () => html`
<lion-tabs .selectedIndex=${1}>
<button slot="tab">Info</button>
<p slot="panel">Info page with lots of information about us.</p>
<button slot="tab">Work</button>
<p slot="panel">Work page that showcases our work.</p>
</lion-tabs>
`;
```
## Slots Order
The tab and panel slots are ordered by DOM order.
This means you can switch the grouping in your `lion-tabs` from tab + panel to all tabs first or all panels first.
```js preview-story
export const slotsOrder = () => html`
<lion-tabs>
<button slot="tab">Info</button>
<button slot="tab">Work</button>
<p slot="panel">Info page with lots of information about us.</p>
<p slot="panel">Work page that showcases our work.</p>
</lion-tabs>
`;
```
## Nesting tabs
You can include tabs within tabs
```js preview-story
export const nestedTabs = () => html`
<lion-tabs>
<button slot="tab">Movies</button>
<button slot="tab">Work</button>
<div slot="panel">
<p>Find some more info about our favorite movies:</p>
<lion-tabs>
<button slot="tab">Info about Cars</button>
<button slot="tab">Info about Toy Story</button>
<p slot="panel">
Cars is a 2006 American computer-animated comedy film produced by Pixar Animation Studios
and released by Walt Disney Pictures.
</p>
<p slot="panel">
The feature film directorial debut of John Lasseter, it was the first entirely
computer-animated feature film, as well as the first feature film from Pixar.
</p>
</lion-tabs>
</div>
<p slot="panel">Work page that showcases our work.</p>
</lion-tabs>
`;
```
## Distribute New Elements
Below, we demonstrate on how you could dynamically add new tab + panels.
```js preview-story
export const distributeNewElement = () => {
const tagName = 'demo-tabs-add-dynamically';
if (!customElements.get(tagName)) {
customElements.define(
tagName,
class extends LitElement {
static get properties() {
return {
__collection: { type: Array },
};
}
render() {
return html`
<h3>Append</h3>
<lion-tabs id="appendTabs">
<button slot="tab">tab 1</button>
<p slot="panel">panel 1</p>
<button slot="tab">tab 2</button>
<p slot="panel">panel 2</p>
</lion-tabs>
<button @click="${this.__handleAppendClick}">Append</button>
<hr />
<h3>Push</h3>
<lion-tabs id="pushTabs">
<button slot="tab">tab 1</button>
<p slot="panel">panel 1</p>
<button slot="tab">tab 2</button>
<p slot="panel">panel 2</p>
${this.__collection.map(
item => html`
<button slot="tab">${item.button}</button>
<p slot="panel">${item.panel}</p>
`,
)}
</lion-tabs>
<button @click="${this.__handlePushClick}">Push</button>
`;
}
constructor() {
super();
this.__collection = [];
}
__handleAppendClick() {
const tabsElement = this.shadowRoot.querySelector('#appendTabs');
const c = 2;
const n = Math.floor(tabsElement.children.length / 2);
for (let i = n + 1; i < n + c; i += 1) {
const tab = document.createElement('button');
tab.setAttribute('slot', 'tab');
tab.innerText = `tab ${i}`;
const panel = document.createElement('p');
panel.setAttribute('slot', 'panel');
panel.innerText = `panel ${i}`;
tabsElement.append(tab);
tabsElement.append(panel);
}
}
__handlePushClick() {
const tabsElement = this.shadowRoot.querySelector('#pushTabs');
const i = Math.floor(tabsElement.children.length / 2) + 1;
this.__collection = [
...this.__collection,
{
button: `tab ${i}`,
panel: `panel ${i}`,
},
];
}
},
);
}
return html` <demo-tabs-add-dynamically></demo-tabs-add-dynamically> `;
};
```
One way is by creating the DOM elements and appending them as needed.
Inside your `lion-tabs` extension, an example for appending nodes on a certain button click:
```js
__handleAppendClick() {
const tabsAmount = this.children.length / 2;
const tab = document.createElement('button');
tab.setAttribute('slot', 'tab');
tab.innerText = `tab ${tabsAmount + 1}`;
const panel = document.createElement('p');
panel.setAttribute('slot', 'panel');
panel.innerText = `panel ${tabsAmount + 1}`;
this.append(tab);
this.append(panel);
}
```
The other way is by adding data to a Lit property where you loop over this property in your template.
You then need to ensure this causes a re-render.
```js
__handlePushClick() {
const tabsAmount = this.children.length;
myCollection = [
...myCollection,
{
button: `tab ${tabsAmount + 1}`,
panel: `panel ${tabsAmount + 1}`,
},
];
renderMyCollection();
}
```
Make sure your template re-renders when myCollection is updated.
```html
<lion-tabs id="pushTabs">
${myCollection.map(item => html`
<button slot="tab">${item.button}</button>
<p slot="panel">${item.panel}</p>
`)}
</lion-tabs>
```

View file

@ -0,0 +1,3 @@
# Content >> Tabs
-> go to Overview

View file

@ -0,0 +1,48 @@
# Content >> Tabs >> Overview ||10
A component to allow users to quickly move between a small number of equally important views.
```js script
import { LitElement, html } from '@lion/core';
import '@lion/tabs/define';
```
```js preview-story
export const main = () => html`
<lion-tabs>
<button slot="tab">Info</button>
<p slot="panel">Info page with lots of information about us.</p>
<button slot="tab">Work</button>
<p slot="panel">Work page that showcases our work.</p>
</lion-tabs>
`;
```
## Installation
```bash
npm i --save @lion/tabs;
```
```js
import { LionTabs } from '@lion/tabs';
// or
import '@lion/tabs/define';
```
## Rationale
### No separate active/focus state when using keyboard
We will immediately switch content as all our content comes from light dom (e.g. no latency)
See Note at <https://www.w3.org/TR/wai-aria-practices/#keyboard-interaction-19>
> It is recommended that tabs activate automatically when they receive focus as long as their
> associated tab panels are displayed without noticeable latency. This typically requires tab
> panel content to be preloaded.
### Panels are not focusable
Focusable elements should have a means to interact with them. Tab panels themselves do not offer any interactivity.
If there is a button or a form inside the tab panel then these elements get focused directly.

View file

@ -20,3 +20,5 @@ export class LeaTabPanel extends LitElement {
`; `;
} }
} }
customElements.define('lea-tab-panel', LeaTabPanel);

View file

@ -41,3 +41,5 @@ export class LeaTab extends LitElement {
return html`<slot></slot>`; return html`<slot></slot>`;
} }
} }
customElements.define('lea-tab', LeaTab);

View file

@ -24,3 +24,5 @@ export class LeaTabs extends LionTabs {
// being awesome // being awesome
} }
} }
customElements.define('lea-tabs', LeaTabs);

View file

@ -0,0 +1,93 @@
# Icons >> Icon >> Features ||20
```js script
import { html } from '@lion/core';
import { icons } from '@lion/icon';
import './assets/iconset-bugs.js';
import './assets/iconset-misc.js';
import * as spaceSet from './assets/iconset-space.js';
import '@lion/icon/define';
icons.addIconResolver('lion', (iconset, name) => {
switch (iconset) {
case 'bugs':
return import('./assets/iconset-bugs.js').then(module => module[name]);
case 'space':
return import('./assets/iconset-space.js').then(module => module[name]);
case 'misc':
return import('./assets/iconset-misc.js').then(module => module[name]);
default:
throw new Error(`Unknown iconset ${iconset}`);
}
});
```
## Icon sets
Icons are displayed using icon sets. These are collections of icons, lazily loaded on demand for performance.
See the [system documentation](../../../docs/systems/icon/overview.md) to learn more about icon sets.
```js preview-story
export const iconSets = () => html`
${Object.keys(spaceSet).map(
name => html`
<style>
.demo-icon__container {
display: inline-flex;
position: relative;
flex-grow: 1;
flex-direction: column;
align-items: center;
width: 80px;
height: 80px;
padding: 4px;
}
.demo-icon__name {
font-size: 10px;
}
</style>
<div class="demo-icon__container">
<lion-icon icon-id="lion:space:${name}" aria-label="${name}"></lion-icon>
<span class="demo-icon__name">${name}</span>
</div>
`,
)}
`;
```
If for some reason you don't want to lazy load icons, you can still import and use them
synchronously.
## Accessibility
It is recommended to add an `aria-label` to provide information to visually impaired users:
A `lion-icon` without an `aria-label` attribute will be automatically given an `aria-hidden` attribute.
```js preview-story
export const accessibleLabel = () => html`
<lion-icon icon-id="lion:misc:arrowLeft" aria-label="Pointing left"></lion-icon>
`;
```
## Styling
By default, a `lion-icon` will be `1em` × `1em` (the current line-height).
`lion-icon` uses SVGs and may be styled with CSS, including using CSS properties such as `fill`:
```js preview-story
export const Styling = () => html`
<style>
.demo-icon {
width: 160px;
height: 160px;
fill: blue;
}
</style>
<lion-icon icon-id="lion:bugs:bug02" aria-label="Bug" class="demo-icon"></lion-icon>
`;
```
See [SVG and CSS](https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial/SVG_and_CSS) on MDN web docs for more information.

View file

@ -0,0 +1,3 @@
# Icons >> Icon
-> go to Overview

View file

@ -0,0 +1,40 @@
# Icons >> Icon >> Overview ||10
A web component for displaying icons.
```js script
import { html } from '@lion/core';
import { icons } from '@lion/icon';
import '@lion/icon/define';
icons.addIconResolver('lion', (iconset, name) => {
switch (iconset) {
case 'bugs':
return import('./assets/iconset-bugs.js').then(module => module[name]);
case 'space':
return import('./assets/iconset-space.js').then(module => module[name]);
case 'misc':
return import('./assets/iconset-misc.js').then(module => module[name]);
default:
throw new Error(`Unknown iconset ${iconset}`);
}
});
```
```js preview-story
export const main = () => html`
<lion-icon icon-id="lion:space:alienSpaceship" style="width: 50px; height: 50px;"></lion-icon>
`;
```
## Installation
```bash
npm i --save @lion/icon
```
```js
import { LionIcon } from '@lion/icon';
// or
import '@lion/icon/define';
```

View file

@ -0,0 +1 @@
# Icons ||30

16
docs/components/index.md Normal file
View file

@ -0,0 +1,16 @@
# Components ||20
We offer many web components for your application needs. For each, you will find an overview page to highlight its capabilities and how to start using it. Additionally, there will be a features page that showcases multiple use cases in action. Some even have a dedicated examples page so you can see a possible styled implementation.
For organizational purposes, we split them into the following groups.
1. [Content](./content/accordion/overview.md) <br>
Everything to help you organize your content.
2. [Icons](./icons/icon/overview.md) <br>
Loading and displaying icons.
3. [Inputs](./inputs/overview.md) <br>
Input components that lets you make complex forms with ease, including validation.
4. [Interaction](./interaction/button/overview.md) <br>
A set of interactive components.
5. [Navigation](./navigation/pagination/overview.md) <br>
The reasoning behind some of our decisions.

View file

@ -0,0 +1,192 @@
# Inputs >> Calendar >> Features ||20
```js script
import { html, css } from '@lion/core';
import '@lion/calendar/define';
```
## Selected date
The `selectedDate` is the date which is currently marked as selected.
You usually select a date by clicking on it with the mouse or hitting Enter on the keyboard.
The `selectedDate` might not be within the dates in the current month view.
```js preview-story
export const selectedDate = () => html`
<style>
.demo-calendar {
border: 1px solid #adadad;
box-shadow: 0 0 16px #ccc;
max-width: 500px;
}
</style>
<lion-calendar class="demo-calendar" .selectedDate=${new Date(1988, 2, 5)}></lion-calendar>
`;
```
## Central Date
The `centralDate` defines which day will be focused when keyboard moves the focus to the current month grid.
By default it is set to today, or the enabled day of the current month view that is closest to today's date.
The next and previous months' buttons work by changing the `centralDate` with plus or minus one month.
Changing the `centralDate` may mean a different view will be displayed to your users if it is in a different month.
Usually if you change only the day, "nothing" happens as it's already currently in view.
The `centralDate` can be different from `selectedDate` as you can have today as actively selected but still look at date that is years ago.
When the `selectedDate` changes, it will sync its value to the `centralDate`.
```js preview-story
export const centralDate = () => {
const today = new Date();
const centralDate = new Date(today.getFullYear(), today.getMonth() + 1, today.getDate());
return html`
<style>
.demo-calendar {
border: 1px solid #adadad;
box-shadow: 0 0 16px #ccc;
max-width: 500px;
}
</style>
<lion-calendar class="demo-calendar" .centralDate="${centralDate}"></lion-calendar>
`;
};
```
## Controlling focus
You can control the focus by calling the following methods
- `focusCentralDate()`
- `focusSelectedDate()`
- `focusDate(dateInstanceToFocus)`
> Be aware that the central date changes when a new date is focused.
```js preview-story
export const controllingFocus = () => {
const today = new Date();
const selectedDate = new Date(today.getFullYear(), today.getMonth(), today.getDate() + 1);
const centralDate = new Date(today.getFullYear(), today.getMonth(), today.getDate() - 5);
return html`
<style>
.demo-calendar {
border: 1px solid #adadad;
box-shadow: 0 0 16px #ccc;
max-width: 500px;
}
</style>
<lion-calendar
id="js-demo-calendar"
class="demo-calendar"
.selectedDate="${selectedDate}"
.centralDate="${centralDate}"
></lion-calendar>
<button
@click="${e => e.target.parentElement.querySelector('#js-demo-calendar').focusCentralDate()}"
>
Set focus on: Central date
</button>
<button
@click="${e => e.target.parentElement.querySelector('#js-demo-calendar').focusSelectedDate()}"
>
Set focus on: Selected date
</button>
<button
@click="${e => e.target.parentElement.querySelector('#js-demo-calendar').focusDate(today)}"
>
Set focus on: Today
</button>
`;
};
```
## Limiting selectable values
### Providing a lower limit
To give a lower limit you can bind a date to the `minDate` property.
```js preview-story
export const providingLowerLimit = () => {
const minDate = new Date();
return html`
<style>
.demo-calendar {
border: 1px solid #adadad;
box-shadow: 0 0 16px #ccc;
max-width: 500px;
}
</style>
<lion-calendar class="demo-calendar" .minDate="${minDate}"></lion-calendar>
`;
};
```
### Provide a higher limit
To give a higher limit you can bind a date to the `maxDate` property. In this example, we show how to create an offset of + 2 days.
```js preview-story
export const providingHigherLimit = () => {
const today = new Date();
const maxDate = new Date(today.getFullYear(), today.getMonth(), today.getDate() + 2);
return html`
<style>
.demo-calendar {
border: 1px solid #adadad;
box-shadow: 0 0 16px #ccc;
max-width: 500px;
}
</style>
<lion-calendar class="demo-calendar" .maxDate="${maxDate}"></lion-calendar>
`;
};
```
### Provide a list of disabled dates
In some cases a specific date or day of the week needs to be disabled, supply those days to the `disableDates` property.
```js preview-story
export const disabledDates = () => html`
<style>
.demo-calendar {
border: 1px solid #adadad;
box-shadow: 0 0 16px #ccc;
max-width: 500px;
}
</style>
<lion-calendar
class="demo-calendar"
.disableDates=${day => day.getDay() === 6 || day.getDay() === 0}
></lion-calendar>
`;
```
### Combined disable dates
To limit the scope of possible dates further, combine the methods mentioned above.
```js preview-story
export const combinedDisabledDates = () => {
const today = new Date();
const maxDate = new Date(today.getFullYear(), today.getMonth() + 2, today.getDate());
return html`
<style>
.demo-calendar {
border: 1px solid #adadad;
box-shadow: 0 0 16px #ccc;
max-width: 500px;
}
</style>
<lion-calendar
class="demo-calendar"
.disableDates=${day => day.getDay() === 6 || day.getDay() === 0}
.minDate="${new Date()}"
.maxDate="${maxDate}"
></lion-calendar>
`;
};
```

View file

@ -0,0 +1,3 @@
# Inputs >> Calendar ||20
-> go to Overview

View file

@ -0,0 +1,49 @@
# Inputs >> Calendar >> Overview ||10
`lion-calendar` is a reusable and accessible calendar view.
```js script
import { html, css } from '@lion/core';
import '@lion/calendar/define';
```
```js story
export const main = () => {
return html`
<style>
.demo-calendar {
border: 1px solid #adadad;
box-shadow: 0 0 16px #ccc;
max-width: 500px;
}
</style>
<lion-calendar class="demo-calendar"></lion-calendar>
`;
};
```
## Features
- fully accessible keyboard navigation (Arrow Keys, PgUp, PgDn, ALT+PgUp, ALT+PgDn)
- **minDate**: disables all dates before a given date
- **maxDate**: disables all dates after a given date
- **disableDates**: disables some dates within an available range
- **selectedDate**: currently selected date
- **centralDate**: date that determines the currently visible month and that will be focused when keyboard moves the focus to the month grid
- **focusedDate**: (getter only) currently focused date (if there is any with real focus)
- **focusDate(date)**: focus on a certain date
- **focusSelectedDate()**: focus on the current selected date
- **focusCentralDate()**: focus on the current central date
- **firstDayOfWeek**: typically Sunday (default) or Monday
- **weekdayHeaderNotation**: long/short/narrow for the current locale (e.g. Thursday/Thu/T)
- **locale**: different locale for the current component only
## Installation
```bash
npm i --save @lion/calendar
```
```js
import '@lion/calendar/define';
```

Some files were not shown because too many files have changed in this diff Show more