chore: fix style of markdown files
This commit is contained in:
parent
c23fc22061
commit
2de378391c
42 changed files with 454 additions and 308 deletions
|
|
@ -3,10 +3,12 @@
|
|||
Check out ways to contribute to Lion Web Components:
|
||||
|
||||
## Existing components: we love pull requests ♥
|
||||
|
||||
Help out the whole lion community by sending your merge requests and issues.
|
||||
Check out how to set it up:
|
||||
|
||||
Setup:
|
||||
|
||||
```bash
|
||||
# Clone the repo:
|
||||
git clone https://github.com/ing-bank/lion.git
|
||||
|
|
@ -20,6 +22,7 @@ git checkout -b fix/buttonSize
|
|||
```
|
||||
|
||||
Make sure everything works as expected:
|
||||
|
||||
```bash
|
||||
# Linting
|
||||
npm run lint
|
||||
|
|
@ -32,7 +35,9 @@ npm run storybook
|
|||
```
|
||||
|
||||
Create a Pull Request:
|
||||
- At https://github.com/ing-bank/lion click on fork (at the right top)
|
||||
|
||||
- At <https://github.com/ing-bank/lion> click on fork (at the right top)
|
||||
|
||||
```bash
|
||||
# add fork to your remotes
|
||||
git remote add fork git@github.com:<your-user>/lion.git
|
||||
|
|
@ -40,9 +45,10 @@ git remote add fork git@github.com:<your-user>/lion.git
|
|||
# push new branch to your fork
|
||||
git push -u fork fix/buttonSize
|
||||
```
|
||||
|
||||
- Go to your fork and create a Pull Request :)
|
||||
|
||||
Some things that will increase the chance that your merge request is accepted:
|
||||
|
||||
* Write tests.
|
||||
* Write a [good commit message](https://www.conventionalcommits.org/).
|
||||
- Write tests.
|
||||
- Write a [good commit message](https://www.conventionalcommits.org/).
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
# Lion Web Components
|
||||
|
||||
> ## 🛠 Status: Pilot Phase
|
||||
>
|
||||
> Lion Web Components are still in an early alpha stage; they should not be considered production ready yet.
|
||||
|
|
@ -8,9 +10,7 @@
|
|||
> - not publicly promote or link us yet: (no tweets, blog posts or other forms of communication about Lion Web Components)
|
||||
> - not publicly promote or link products derived from/based on Lion Web Components
|
||||
>
|
||||
> As soon as Pilot Phase ends we will let you know (feel free to subscribe to this issue https://github.com/ing-bank/lion/issues/1)
|
||||
|
||||
# Lion Web Components
|
||||
> As soon as Pilot Phase ends we will let you know (feel free to subscribe to this issue <https://github.com/ing-bank/lion/issues/1>)
|
||||
|
||||
Lion web components is a set of highly performant, accessible and flexible Web Components.
|
||||
They provide an unopinionated, white label layer that can be extended to your own layer of components.
|
||||
|
|
|
|||
|
|
@ -6,27 +6,30 @@
|
|||
It is a promise based system for fetching data, based on [axios](https://github.com/axios/axios)
|
||||
|
||||
## Features
|
||||
|
||||
- only JS functions, no (unnecessarily expensive) web components
|
||||
- supports GET, POST, PUT, DELETE, REQUEST, PATCH and HEAD methods
|
||||
- can be used with or without XSRF token
|
||||
|
||||
|
||||
## How to use
|
||||
|
||||
### Installation
|
||||
|
||||
```sh
|
||||
npm i --save @lion/ajax
|
||||
```
|
||||
|
||||
### Example
|
||||
|
||||
```js
|
||||
import { ajax } from '@lion/ajax';
|
||||
|
||||
ajax.get('data.json')
|
||||
.then((response) => {
|
||||
ajax
|
||||
.get('data.json')
|
||||
.then(response => {
|
||||
console.log(response);
|
||||
})
|
||||
.catch((error) => {
|
||||
.catch(error => {
|
||||
console.log(error);
|
||||
});
|
||||
```
|
||||
|
|
@ -34,15 +37,17 @@ ajax.get('data.json')
|
|||
### Create own instances for custom options
|
||||
|
||||
#### Cancel
|
||||
|
||||
```js
|
||||
import { AjaxClass } from '@lion/ajax';
|
||||
|
||||
const myAjax = AjaxClass.getNewInstance({ cancelable: true });
|
||||
myAjax.get('data.json')
|
||||
.then((response) => {
|
||||
myAjax
|
||||
.get('data.json')
|
||||
.then(response => {
|
||||
document.querySelector('#canceled').innerHTML = JSON.stringify(response.data);
|
||||
})
|
||||
.catch((error) => {
|
||||
.catch(error => {
|
||||
document.querySelector('#canceled').innerHTML = `I got cancelled: ${error.message}`;
|
||||
});
|
||||
setTimeout(() => {
|
||||
|
|
@ -51,22 +56,25 @@ setTimeout(() => {
|
|||
```
|
||||
|
||||
#### Cancel previous on new request
|
||||
|
||||
```js
|
||||
import { AjaxClass } from '@lion/ajax'
|
||||
import { AjaxClass } from '@lion/ajax';
|
||||
|
||||
const myAjax = AjaxClass.getNewInstance({ cancelPreviousOnNewRequest: true });
|
||||
myAjax.get('data.json')
|
||||
.then((response) => {
|
||||
myAjax
|
||||
.get('data.json')
|
||||
.then(response => {
|
||||
document.querySelector('#request1').innerHTML = 'Request 1: ' + JSON.stringify(response.data);
|
||||
})
|
||||
.catch((error) => {
|
||||
.catch(error => {
|
||||
document.querySelector('#request1').innerHTML = `Request 1: I got cancelled: ${error.message}`;
|
||||
});
|
||||
myAjax.get('data2.json')
|
||||
.then((response) => {
|
||||
myAjax
|
||||
.get('data2.json')
|
||||
.then(response => {
|
||||
document.querySelector('#request2').innerHTML = 'Request 2: ' + JSON.stringify(response.data);
|
||||
})
|
||||
.catch((error) => {
|
||||
.catch(error => {
|
||||
document.querySelector('#request2').innerHTML = `Request 2: I got cancelled: ${error.message}`;
|
||||
});
|
||||
```
|
||||
|
|
|
|||
|
|
@ -7,12 +7,14 @@
|
|||
## Features
|
||||
|
||||
### Disabled
|
||||
|
||||
You can also set a button as disabled with the `disabled` property.
|
||||
|
||||
## How to use
|
||||
|
||||
### Installation
|
||||
```
|
||||
|
||||
```sh
|
||||
npm i --save @lion/button
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -7,12 +7,14 @@
|
|||
You should use [lion-checkbox](../checkbox/)'s inside this element.
|
||||
|
||||
## Features
|
||||
|
||||
Since it extends from [lion-fieldset](../fieldset/), it has all the features a fieldset has.
|
||||
|
||||
## How to use
|
||||
|
||||
### Installation
|
||||
```
|
||||
|
||||
```sh
|
||||
npm i --save @lion/checkbox @lion/checkbox-group
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
`lion-checkbox` component is a sub-element to be used in [lion-checkbox-group](../checkbox-group/) elements. Its purpose is to provide a way for users to check **multiple** options amongst a set of choices, or to function as a single toggle.
|
||||
|
||||
## Features
|
||||
|
||||
- Get or set the checked state (boolean) - `choiceChecked()`
|
||||
- Get or set the value of the choice - `choiceValue()`
|
||||
- Pre-select an option by setting the `checked` boolean attribute
|
||||
|
|
@ -12,8 +13,9 @@
|
|||
## How to use
|
||||
|
||||
### Installation
|
||||
```
|
||||
npm i --save @lion/checkbox;
|
||||
|
||||
```sh
|
||||
npm i --save @lion/checkbox
|
||||
```
|
||||
|
||||
```js
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ The more generic the mixin is, the higher the chance of being appliend more than
|
|||
|
||||
This is an example of how to make a conventional ES mixin deduping.
|
||||
|
||||
```javascript
|
||||
```js
|
||||
const BaseMixin = dedupeMixin((superClass) => {
|
||||
return class extends superClass { ... };
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
# Form Fundaments
|
||||
|
||||
[//]: # 'AUTO INSERT HEADER PREPUBLISH'
|
||||
|
|
@ -34,7 +33,7 @@ On top of this, they feature:
|
|||
|
||||
Whenever a native form control doesn't exist or is not sufficient, a
|
||||
[custom form field](./docs/CustomFieldsTutorial.md) should be created. One could think of components
|
||||
like:
|
||||
like:
|
||||
|
||||
- slider
|
||||
- combobox
|
||||
|
|
@ -56,9 +55,11 @@ Fieldsets are the basis for:
|
|||
|
||||
<!-- TODO: - [`FormControlMixin`] () -->
|
||||
<!-- TODO: - [`LionField`] () -->
|
||||
|
||||
- [Model Value](./docs/ModelValue.md)
|
||||
- [Formatting and parsing](./docs/FormattingAndParsing.md)
|
||||
- [Interaction states](./docs/InteractionStates.md)
|
||||
- [Validation System](../validate/docs/ValidationSystem.md)
|
||||
- [Custom Fields](./docs/CustomFieldsTutorial.md)
|
||||
|
||||
<!-- TODO: - [`FocusMixin`] (/FocusMixin.md) -->
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
# Creating a custom field
|
||||
|
||||
Custom fields can be created in just a few steps. All you need is an interaction element
|
||||
(like for instance a slider, a listbox or a combobox) and connect it to the [Field](../README.md)
|
||||
functionality.
|
||||
|
||||
## Prerequisite: an interaction element
|
||||
|
||||
An interaction element provides the means for the end user to enter a certain value, just like
|
||||
native elements provide in this (think of `<input>`, `<textarea>` and `<select>`).
|
||||
An example of a non native element is the
|
||||
|
|
@ -15,24 +17,27 @@ For this tutorial, we assume we have a component `<my-slider>` that exposes its
|
|||
it has a tabindex=“0” applied.
|
||||
|
||||
## Connecting the interaction element to the field
|
||||
|
||||
Now we want to integrate the slider in our form framework to enrich the user interface, get
|
||||
validation support and get all the other [benefits of LionField](../README.md).
|
||||
We start of by creating a component `<lion-slider>` that extends from `LionField`.
|
||||
Then we follow the steps below:
|
||||
|
||||
- ### 1. Add your interaction element as ‘input slot'
|
||||
Here you return the element the user interacts with. By configuring it as a slot, it will end up
|
||||
in light DOM, ensuring the best accessibility for the end user.
|
||||
|
||||
Here you return the element the user interacts with. By configuring it as a slot, it will end up
|
||||
in light DOM, ensuring the best accessibility for the end user.
|
||||
|
||||
- ### 2. Proxy event `my-slider-changed` to `user-input-changed` event
|
||||
The `user-input-changed` event is listened to by the FormatMixin: it should be regarded as the
|
||||
equivalent of the `input` event of the platform, but for custom built interaction elements.
|
||||
|
||||
The `user-input-changed` event is listened to by the FormatMixin: it should be regarded as the
|
||||
equivalent of the `input` event of the platform, but for custom built interaction elements.
|
||||
|
||||
- ### 3. Proxy property `<my-slider>.mySliderValue` to `<lion-slider>.value`
|
||||
Every time the `user-input-changed` fires, the value of `<my-slider>` is synchronized with the
|
||||
[`modelValue`](./modelValue.md) of `<my-slider>`. Now the cycle is complete: the modelValue connects
|
||||
your interaction element to all logic inside the LionField.
|
||||
|
||||
Every time the `user-input-changed` fires, the value of `<my-slider>` is synchronized with the
|
||||
[`modelValue`](./modelValue.md) of `<my-slider>`. Now the cycle is complete: the modelValue connects
|
||||
your interaction element to all logic inside the LionField.
|
||||
|
||||
Steps as described can be implemented with the following javascript:
|
||||
|
||||
|
|
|
|||
|
|
@ -52,9 +52,11 @@ Fieldsets are the basis for:
|
|||
|
||||
<!-- TODO: - [`FormControlMixin`] () -->
|
||||
<!-- TODO: - [`LionField`] () -->
|
||||
|
||||
- [Model Value](./ModelValue.md)
|
||||
- [Formatting and parsing](./FormattingAndParsing.md)
|
||||
- [Interaction states](./InteractionStates.md)
|
||||
- [Validation System](../../validate/docs/ValidationSystem.md)
|
||||
- [FieldCustomMixin](./FieldCustomMixin.md)
|
||||
|
||||
<!-- TODO: - [`FocusMixin`] (/FocusMixin.md) -->
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
# FormatMixin
|
||||
|
||||
The FormatMixin keeps track of the `modelValue`, `formattedValue` and `serializedValue`.
|
||||
It is designed to work in conjunction with `LionField`.
|
||||
|
||||
## Concepts of different values
|
||||
|
||||
### model value
|
||||
|
||||
The model value is the result of the parser function. It will be stored as `.modelValue`
|
||||
and should be considered the internal value used for validation and reasoning/logic.
|
||||
The model value is 'ready for consumption' by the outside world (think of a Date object
|
||||
|
|
@ -12,10 +14,12 @@ or a float). It can(and is recommended to) be used as both input value and
|
|||
output value of the `LionField`.
|
||||
|
||||
Examples:
|
||||
|
||||
- For a date input: a String '20/01/1999' will be converted to `new Date('1999/01/20')`
|
||||
- For a number input: a formatted String '1.234,56' will be converted to a Number: `1234.56`
|
||||
|
||||
### view value
|
||||
|
||||
The view value is the result of the formatter function.
|
||||
It will be stored as `.formattedValue` and synchronized to `.value` (a viewValue setter that
|
||||
allows to synchronize to `.inputElement`).
|
||||
|
|
@ -23,25 +27,28 @@ Synchronization happens conditionally and is (by default) the result of a blur.
|
|||
(like error state/validity and whether the a model value was set programatically) also play a role.
|
||||
|
||||
Examples:
|
||||
|
||||
- For a date input, this would be '20/01/1999' (dependent on locale).
|
||||
- For a number input, this could be '1,234.56' (a String representation of modelValue
|
||||
1234.56)
|
||||
1234.56)
|
||||
|
||||
### serialized value
|
||||
|
||||
This is the serialized version of the model value.
|
||||
It exists for maximal compatibility with the platform API.
|
||||
The serialized value can be an interface in context where data binding is not supported
|
||||
and a serialized string needs to be set.
|
||||
|
||||
Examples:
|
||||
|
||||
- For a date input, this would be the iso format of a date, e.g. '1999-01-20'.
|
||||
- For a number input this would be the String representation of a float ('1234.56' instead
|
||||
of 1234.56)
|
||||
When no parser is available, the value is usually the same as the formattedValue
|
||||
(being inputElement.value)
|
||||
|
||||
When no parser is available, the value is usually the same as the formattedValue (being inputElement.value)
|
||||
|
||||
## Formatters, parsers and (de)serializers
|
||||
|
||||
In order to create advanced user experiences (automatically formatting a user input or an input
|
||||
set imperatively by an Application Developer).
|
||||
|
||||
|
|
@ -49,7 +56,9 @@ Below some concrete examples can be found of implementations of formatters and p
|
|||
extrapolating the example of a date input.
|
||||
|
||||
### Formatters
|
||||
|
||||
A formatter should return a `formattedValue`:
|
||||
|
||||
```js
|
||||
function formatDate(modelValue, options) {
|
||||
if (!(modelValue instanceof Date)) {
|
||||
|
|
@ -58,27 +67,35 @@ function formatDate(modelValue, options) {
|
|||
return formatDateLocalized(modelValue, options);
|
||||
}
|
||||
```
|
||||
|
||||
Notice the options object, which holds a fallback value that shows what should be presented on
|
||||
screen when the user input resulted in an invalid modelValue
|
||||
|
||||
### Parsers
|
||||
|
||||
A parser should return a `modelValue`:
|
||||
|
||||
```js
|
||||
function parseDate(formattedValue, options) {
|
||||
return formattedValue === '' ? undefined : parseDateLocalized(formattedValue);
|
||||
}
|
||||
```
|
||||
|
||||
Notice that when it's not possible to create a valid modelValue based on the formattedValue,
|
||||
one should return `undefined`.
|
||||
|
||||
### Serializers and deserializers
|
||||
|
||||
A serializer should return a `serializedValue`:
|
||||
|
||||
```js
|
||||
function serializeDate(modelValue, options) {
|
||||
return modelValue.toISOString();
|
||||
}
|
||||
```
|
||||
|
||||
A deserializer should return a `modelValue`:
|
||||
|
||||
```js
|
||||
function deserializeDate(serializeValue, options) {
|
||||
return new Date(serializeValue);
|
||||
|
|
@ -86,13 +103,15 @@ function deserializeDate(serializeValue, options) {
|
|||
```
|
||||
|
||||
### FieldCustomMixin
|
||||
|
||||
When creating your own custom input, please use `FieldCustomMixin` as a basis for this.
|
||||
Concrete examples can be found at [`<lion-input-date>`](../../input-date) and
|
||||
[`<lion-input-amount>`](../../input-amount).
|
||||
|
||||
## Flow diagram
|
||||
|
||||
The following flow diagram is based on both end user input and interaction programmed by the
|
||||
developer. It shows how the 'computation loop' for modelValue, formattedValue and serializedValue
|
||||
developer. It shows how the 'computation loop' for modelValue, formattedValue and serializedValue
|
||||
is triggered.
|
||||
|
||||
[Flow diagram](./formatterParserFlow.svg)
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ Examples:
|
|||
|
||||
- For a date input, this would be '20/01/1999' (dependent on locale).
|
||||
- For a number input, this could be '1,234.56' (a String representation of modelValue
|
||||
1234.56)
|
||||
1234.56)
|
||||
|
||||
### serializedValue
|
||||
|
||||
|
|
@ -41,8 +41,8 @@ Examples:
|
|||
- For a date input, this would be the iso format of a date, e.g. '1999-01-20'.
|
||||
- For a number input this would be the String representation of a float ('1234.56' instead
|
||||
of 1234.56)
|
||||
When no parser is available, the value is usually the same as the formattedValue
|
||||
(being inputElement.value)
|
||||
|
||||
When no parser is available, the value is usually the same as the formattedValue (being inputElement.value)
|
||||
|
||||
## Formatters, parsers and (de)serializers
|
||||
|
||||
|
|
@ -108,7 +108,7 @@ Concrete examples can be found at [`<lion-input-date>`](../../input-date/) and
|
|||
## Flow diagram
|
||||
|
||||
The following flow diagram is based on both end user input and interaction programmed by the
|
||||
developer. It shows how the 'computation loop' for modelValue, formattedValue and serializedValue
|
||||
developer. It shows how the 'computation loop' for modelValue, formattedValue and serializedValue
|
||||
is triggered.
|
||||
|
||||
[Flow diagram](./formatterParserFlow.svg)
|
||||
|
|
|
|||
|
|
@ -40,14 +40,14 @@ static _isPrefilled(modelValue) {
|
|||
We show the validity feedback when one of the following conditions is met:
|
||||
|
||||
- prefilled:
|
||||
The user already filled in something, or the value is prefilled
|
||||
when the form is initially rendered.
|
||||
The user already filled in something, or the value is prefilled
|
||||
when the form is initially rendered.
|
||||
|
||||
- touched && dirty && !prefilled:
|
||||
When a user starts typing for the first time in a field with for instance `required` validation,
|
||||
error message should not be shown until a field becomes `touched` (a user leaves(blurs) a field).
|
||||
When a user enters a field without altering the value (making it `dirty` but not `touched`),
|
||||
an error message shouldn't be shown either.
|
||||
When a user starts typing for the first time in a field with for instance `required` validation,
|
||||
error message should not be shown until a field becomes `touched` (a user leaves(blurs) a field).
|
||||
When a user enters a field without altering the value (making it `dirty` but not `touched`),
|
||||
an error message shouldn't be shown either.
|
||||
|
||||
- submitted:
|
||||
If the form is submitted, always show the error message.
|
||||
If the form is submitted, always show the error message.
|
||||
|
|
|
|||
|
|
@ -6,26 +6,30 @@ of the form, also for all derived states: interaction, validation, visibility an
|
|||
computed from a modelValue change.
|
||||
|
||||
## Single source of truth
|
||||
|
||||
ModelValues are designed to provide the Application Developer a single way of programmatical
|
||||
interaction with the form for an Application Developer.
|
||||
|
||||
### One single concept for Application Developers
|
||||
|
||||
Application Developers need to only care about interacting with the modelValue on a form control
|
||||
level, via:
|
||||
|
||||
- `.modelValue`
|
||||
- `@model-value-changed`
|
||||
|
||||
> Internal/private concepts like viewValue, formattedValue, serializedValue are therefore not
|
||||
recommended as a means of interaction.
|
||||
> recommended as a means of interaction.
|
||||
|
||||
### One single concept for internals
|
||||
|
||||
Internally, all derived states are computed from model-value-changed events.
|
||||
Since the modelValue is computed 'realtime' and reflects all user interaction, visibility and
|
||||
validation states, we can guarantee a system that enables the best User Experience
|
||||
(see Interaction States).
|
||||
|
||||
|
||||
## Unparseable modelValues
|
||||
|
||||
A modelValue can demand a certain type (Date, Number, Iban etc.). A correct type will always be
|
||||
translatable into a String representation (the value presented to the end user) via the `formatter`.
|
||||
When the type is not valid (usually as a consequence of a user typing in an invalid or incomplete
|
||||
|
|
@ -37,13 +41,16 @@ popular frameworks like Angular and Vue.
|
|||
|
||||
The Unparseable type is an addition on top of this that mainly is added for the following two
|
||||
purposes:
|
||||
|
||||
- restoring user sessions
|
||||
- realtime updated with all value changes
|
||||
|
||||
### Restoring user sessions
|
||||
|
||||
As a modelValue is always a single source of truth
|
||||
|
||||
### Realtime updated with all value changes
|
||||
|
||||
As an Application Developer, you will be notified when a user tries to write the correct type of
|
||||
a value. This might be handy for giving feedback to the user.
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ Two specific types of fieldsets:
|
|||
### Installation
|
||||
|
||||
```sh
|
||||
npm i --save @lion/fieldset;
|
||||
npm i --save @lion/fieldset
|
||||
```
|
||||
|
||||
```js
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
The Form System allows you to create complex forms with various validation in an easy way.
|
||||
|
||||
## Features
|
||||
|
||||
- built in [validate](../validate) for error/warning/info/success
|
||||
- formatting of values
|
||||
- accessible
|
||||
|
|
|
|||
|
|
@ -28,13 +28,19 @@ import '@lion/form/lion-form.js';
|
|||
### Example
|
||||
|
||||
```html
|
||||
<lion-form><form>
|
||||
<lion-fieldset name="fullName">
|
||||
<lion-input label="First Name" name="firstName" .modelValue=${model.firstName}></lion-input>
|
||||
<lion-input label="Last Name" name="lastName" .modelValue=${model.lastName}></lion-input>
|
||||
</lion-fieldset>
|
||||
<lion-textarea label="Description" name="description" .modelValue=${model.description}></lion-textarea>
|
||||
</form></lion-form>
|
||||
<lion-form>
|
||||
<form>
|
||||
<lion-fieldset name="fullName">
|
||||
<lion-input label="First Name" name="firstName" .modelValue="${model.firstName}"></lion-input>
|
||||
<lion-input label="Last Name" name="lastName" .modelValue="${model.lastName}"></lion-input>
|
||||
</lion-fieldset>
|
||||
<lion-textarea
|
||||
label="Description"
|
||||
name="description"
|
||||
.modelValue="${model.description}"
|
||||
></lion-textarea>
|
||||
</form>
|
||||
</lion-form>
|
||||
```
|
||||
|
||||
Note that the example above is rendered using [lit-html](https://github.com/Polymer/lit-html)
|
||||
|
|
|
|||
|
|
@ -28,8 +28,9 @@ Include the import for both the custom element the icons you want:
|
|||
```
|
||||
|
||||
Use it in your lit-html template:
|
||||
|
||||
```html
|
||||
<lion-icon .svg=${bugSvg}></lion-icon>
|
||||
<lion-icon .svg="${bugSvg}"></lion-icon>
|
||||
```
|
||||
|
||||
### Icon format
|
||||
|
|
@ -50,7 +51,7 @@ Make sure you have `focusable="false"` in the icon file to prevent bugs in IE/Ed
|
|||
You may add an `aria-label` to provide information to visually impaired users:
|
||||
|
||||
```html
|
||||
<lion-icon .svg=${arrowLeftSvg} aria-label="Pointing left"></lion-icon>
|
||||
<lion-icon .svg="${arrowLeftSvg}" aria-label="Pointing left"></lion-icon>
|
||||
```
|
||||
|
||||
A `lion-icon` without an `aria-label` attribute will be automatically be given an `aria-hidden` attribute.
|
||||
|
|
@ -83,7 +84,7 @@ A `lion-icon` may be styled like a regular HTML element:
|
|||
stroke: lightsteelblue;
|
||||
}
|
||||
</style>
|
||||
<lion-icon .icon=${arrowSvg} class="strong"></lion-icon>
|
||||
<lion-icon .icon="${arrowSvg}" class="strong"></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.
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
`lion-input-amount` component is based on the generic text input field. Its purpose is to provide a way for users to fill in an amount.
|
||||
|
||||
## Features
|
||||
|
||||
- based on [lion-input](../input)
|
||||
- makes use of [formatNumber](../localize/docs/number.md) for formatting and parsing.
|
||||
- option to show currency as a suffix
|
||||
|
|
@ -20,7 +21,8 @@
|
|||
## How to use
|
||||
|
||||
### Installation
|
||||
```
|
||||
|
||||
```sh
|
||||
npm i --save @lion/input-amount
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@
|
|||
|
||||
`lion-input-date` component is based on the generic text input field. Its purpose is to provide a way for users to fill in a date.
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
- based on [lion-input](../input)
|
||||
- makes use of [formatDate](../localize/docs/date.md) for formatting and parsing.
|
||||
- option to overwrite locale to change the formatting and parsing
|
||||
|
|
@ -19,7 +19,8 @@
|
|||
## How to use
|
||||
|
||||
### Installation
|
||||
```
|
||||
|
||||
```sh
|
||||
npm i --save @lion/input-date
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
For an input field with a big range, such as `birthday-input`, a datepicker is not the ultimate tool, so use the standard [lion-input-date](../input-date).
|
||||
|
||||
## Features
|
||||
|
||||
- input field with a datepicker to help to choose a date
|
||||
- based on [lion-input-date](../input-date)
|
||||
- makes use of [lion-calendar](../calendar) inside the datepicker
|
||||
|
|
@ -19,7 +20,8 @@ For an input field with a big range, such as `birthday-input`, a datepicker is n
|
|||
## How to use
|
||||
|
||||
### Installation
|
||||
```
|
||||
|
||||
```sh
|
||||
npm i --save @lion/input-datepicker
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@
|
|||
|
||||
`lion-input-email` component is based on the generic text input field. Its purpose is to provide a way for users to fill in an email.
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
- based on [lion-input](../input)
|
||||
- default label in different languages
|
||||
- makes use of email [validators](../validate/docs/DefaultValidators.md) with corresponding error messages in different languages
|
||||
|
|
@ -14,7 +14,8 @@
|
|||
## How to use
|
||||
|
||||
### Installation
|
||||
```
|
||||
|
||||
```sh
|
||||
npm i --save @lion/input-email
|
||||
```
|
||||
|
||||
|
|
@ -25,8 +26,5 @@ import '@lion/input-email/lion-input-email.js';
|
|||
### Example
|
||||
|
||||
```html
|
||||
<lion-input-email
|
||||
name="email"
|
||||
.errorValidators="${[['required']]}"
|
||||
></lion-input-email>
|
||||
<lion-input-email name="email" .errorValidators="${[['required']]}"></lion-input-email>
|
||||
```
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
`lion-input-iban` component is based on the generic text input field. Its purpose is to provide a way for users to fill in an iban.
|
||||
|
||||
## Features
|
||||
|
||||
- based on [lion-input](../input)
|
||||
- default label in different languages
|
||||
- makes use of IBAN specific [validate](../validate) with corresponding error messages in different languages
|
||||
|
|
@ -14,7 +15,8 @@
|
|||
## How to use
|
||||
|
||||
### Installation
|
||||
```
|
||||
|
||||
```sh
|
||||
npm i --save @lion/input-amount
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
`lion-input` component is a webcomponent that enhances the functionality of the native `<input>` element.
|
||||
|
||||
## Features
|
||||
|
||||
- based on [field](../field/)
|
||||
- extra visual elements can be added via `slots`
|
||||
- **label**: can also be provided via the `label` attribute, but the slot can be used to change the `html` and `CSS` of the label.
|
||||
|
|
@ -21,8 +22,9 @@
|
|||
## How to use
|
||||
|
||||
### Installation
|
||||
```
|
||||
npm i --save @lion/input;
|
||||
|
||||
```sh
|
||||
npm i --save @lion/input
|
||||
```
|
||||
|
||||
```js
|
||||
|
|
@ -44,6 +46,7 @@ import { maxLengthValidator } from '@lion/validate';
|
|||
```
|
||||
|
||||
Making use of slots:
|
||||
|
||||
```html
|
||||
<lion-input name="amount">
|
||||
<label slot="label">Amount</label>
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ The core of the system is a `LocalizeManager` instance which is responsible for
|
|||
It is exposed as a `localize` singleton instance.
|
||||
This ensures that the data can be cached in the single place and reused across different components and same component instances.
|
||||
|
||||
```javascript
|
||||
```js
|
||||
import { localize } from '@lion/localize';
|
||||
// localize is the instance of LocalizeManager
|
||||
```
|
||||
|
|
@ -23,6 +23,7 @@ Component developers will have a unified way to integrate with localization syst
|
|||
## Usage for component developers
|
||||
|
||||
As a component developer you get:
|
||||
|
||||
- unified data structure for different locales;
|
||||
- promisified helper to load data;
|
||||
- notification about page locale changes;
|
||||
|
|
@ -36,52 +37,52 @@ Localization data modules for `my-hello-component` might look like these:
|
|||
|
||||
- `/path/to/my-hello-component/translations/en-GB.js`
|
||||
|
||||
```js
|
||||
export default {
|
||||
greeting: 'Hello {name}!',
|
||||
};
|
||||
```
|
||||
```js
|
||||
export default {
|
||||
greeting: 'Hello {name}!',
|
||||
};
|
||||
```
|
||||
|
||||
- `/path/to/my-hello-component/translations/nl-NL.js`
|
||||
|
||||
```js
|
||||
export default {
|
||||
greeting: 'Hallo {name}!',
|
||||
};
|
||||
```
|
||||
```js
|
||||
export default {
|
||||
greeting: 'Hallo {name}!',
|
||||
};
|
||||
```
|
||||
|
||||
The approach with ES modules is great because it allows to simply reuse basic locale data and override only the needed parts for more specific locales.
|
||||
|
||||
- `/path/to/my-family-component/translations/en.js`
|
||||
|
||||
```js
|
||||
export default {
|
||||
havePartnerQuestion: 'Do you have a partner?',
|
||||
haveChildrenQuestion: 'Do you have children?',
|
||||
};
|
||||
```
|
||||
```js
|
||||
export default {
|
||||
havePartnerQuestion: 'Do you have a partner?',
|
||||
haveChildrenQuestion: 'Do you have children?',
|
||||
};
|
||||
```
|
||||
|
||||
- `/path/to/my-family-component/translations/en-GB.js`
|
||||
|
||||
```js
|
||||
import en from './en.js'
|
||||
export default en;
|
||||
```
|
||||
```js
|
||||
import en from './en.js';
|
||||
export default en;
|
||||
```
|
||||
|
||||
- `/path/to/my-family-component/translations/en-US.js`
|
||||
|
||||
```js
|
||||
import en from './en.js'
|
||||
```js
|
||||
import en from './en.js';
|
||||
|
||||
export default {
|
||||
...en,
|
||||
haveChildrenQuestion: 'Do you have kids?',
|
||||
};
|
||||
```
|
||||
export default {
|
||||
...en,
|
||||
haveChildrenQuestion: 'Do you have kids?',
|
||||
};
|
||||
```
|
||||
|
||||
To load this data the method `loadNamespace()` which returns a promise can be used.
|
||||
|
||||
```javascript
|
||||
```js
|
||||
localize.loadNamespace(namespace).then(() => {
|
||||
// do smth when data is loaded
|
||||
});
|
||||
|
|
@ -92,58 +93,60 @@ Let's look at both cases in depth.
|
|||
|
||||
1. Using explicit loader functions:
|
||||
|
||||
```javascript
|
||||
// use the dynamic import to load static assets
|
||||
localize.loadNamespace({
|
||||
'my-hello-component': (locale) => {
|
||||
// resolves to a module with the module.default `{ greeting: 'Hallo {name}!' }`
|
||||
return import(`./translations/${locale}.js`);
|
||||
},
|
||||
});
|
||||
```
|
||||
```js
|
||||
// use the dynamic import to load static assets
|
||||
localize.loadNamespace({
|
||||
'my-hello-component': locale => {
|
||||
// resolves to a module with the module.default `{ greeting: 'Hallo {name}!' }`
|
||||
return import(`./translations/${locale}.js`);
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
Usage of dynamic imports is recommended if you want to be able to create smart bundles later on for a certain locale.
|
||||
The module must have a `default` export as shown above to be handled properly.
|
||||
Usage of dynamic imports is recommended if you want to be able to create smart bundles later on for a certain locale.
|
||||
The module must have a `default` export as shown above to be handled properly.
|
||||
|
||||
But in fact you are not limited in the way how exactly the data is loaded.
|
||||
If you want to fetch it from some API this is also possible.
|
||||
But in fact you are not limited in the way how exactly the data is loaded.
|
||||
If you want to fetch it from some API this is also possible.
|
||||
|
||||
```javascript
|
||||
// fetch from an API
|
||||
localize.loadNamespace({
|
||||
'my-hello-component': async (locale) => {
|
||||
const response = await fetch(`http://api.example.com/?namespace=my-hello-component&locale=${locale}`);
|
||||
return response.json(); // resolves to the JSON object `{ greeting: 'Hallo {name}!' }`
|
||||
},
|
||||
});
|
||||
```
|
||||
```js
|
||||
// fetch from an API
|
||||
localize.loadNamespace({
|
||||
'my-hello-component': async locale => {
|
||||
const response = await fetch(
|
||||
`http://api.example.com/?namespace=my-hello-component&locale=${locale}`,
|
||||
);
|
||||
return response.json(); // resolves to the JSON object `{ greeting: 'Hallo {name}!' }`
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
But it does not make much sense to have such a loader function for each of your namespaces.
|
||||
And this is there the second option comes in handy.
|
||||
But it does not make much sense to have such a loader function for each of your namespaces.
|
||||
And this is there the second option comes in handy.
|
||||
|
||||
2. Using the loaders preconfigured via `setupNamespaceLoader()`:
|
||||
1. Using the loaders preconfigured via `setupNamespaceLoader()`:
|
||||
|
||||
```javascript
|
||||
// using the regexp to match all component names staring with 'my-'
|
||||
localize.setupNamespaceLoader(/my-.+/, async (locale, namespace) => {
|
||||
const response = await fetch(`http://api.example.com/?namespace=${namespace}&locale=${locale}`);
|
||||
return response.json();
|
||||
});
|
||||
```js
|
||||
// using the regexp to match all component names staring with 'my-'
|
||||
localize.setupNamespaceLoader(/my-.+/, async (locale, namespace) => {
|
||||
const response = await fetch(`http://api.example.com/?namespace=${namespace}&locale=${locale}`);
|
||||
return response.json();
|
||||
});
|
||||
|
||||
Promise.all([
|
||||
localize.loadNamespace('my-hello-component');
|
||||
localize.loadNamespace('my-goodbuy-component');
|
||||
])
|
||||
```
|
||||
Promise.all([
|
||||
localize.loadNamespace('my-hello-component');
|
||||
localize.loadNamespace('my-goodbuy-component');
|
||||
])
|
||||
```
|
||||
|
||||
Thus there is a loder function for all components having a certain prefix in a name.
|
||||
Thus there is a loder function for all components having a certain prefix in a name.
|
||||
|
||||
The locale which will be loaded by default is accesed via the `localize.locale`.
|
||||
|
||||
The single source of truth for page's locale is `<html lang="my-LOCALE">`.
|
||||
At the same time the interaction should happen via `localize.locale` getter/setter to be able to notify and react to the change.
|
||||
|
||||
```javascript
|
||||
```js
|
||||
localize.addEventListener('localeChanged', () => {
|
||||
// do smth when data is loaded for a new locale
|
||||
});
|
||||
|
|
@ -160,7 +163,7 @@ When all necessary data is loaded and you want to show localized content on the
|
|||
`localize.msg` comes into play here.
|
||||
It expects a key in the format of `namespace:name` and can also receive variables as a second argument.
|
||||
|
||||
```javascript
|
||||
```js
|
||||
_onNameChanged() {
|
||||
// inserts 'Hello John!' into the element with id="name"
|
||||
const name = localize.msg('my-hello-component:greeting', { name: 'John' });
|
||||
|
|
@ -174,12 +177,13 @@ _onNameChanged() {
|
|||
|
||||
This mixin was created to significantly simplify integration with LionLitElement.
|
||||
It provides several capabilities:
|
||||
|
||||
- automatic loading of specified namespaces;
|
||||
- life-cycle callbacks for localization events;
|
||||
- alias `_m` for `localize.msg`;
|
||||
- promisified alias `_msgAsync` for `localize.msg` resolved when data is loaded.
|
||||
|
||||
```javascript
|
||||
```js
|
||||
class MyHelloComponent extends LocalizeMixin(LionLitElement) {
|
||||
static get localizeNamespaces() {
|
||||
// using an explicit loader function
|
||||
|
|
@ -220,12 +224,13 @@ Refer to demos to see a full example.
|
|||
|
||||
This is an extension of LocalizeMixin for usage with LionLitElement and LitRenderMixin.
|
||||
It provides extra capabilities on top of LocalizeMixin:
|
||||
|
||||
- smart wrapper `msg` for `localize.msg`;
|
||||
- automatic update of DOM after locale was changed.
|
||||
|
||||
With the help of this mixin writing a component can be as easy as defining namespaces in `localizeNamespaces` and writing lit-html template using `this.msgLit()`:
|
||||
|
||||
```javascript
|
||||
```js
|
||||
render() {
|
||||
return html`
|
||||
<div>${this.name ? this.msgLit('my-hello-component:greeting', { name: this.name }) : ''}</div>
|
||||
|
|
@ -238,6 +243,7 @@ Refer to demos to see a full example.
|
|||
## Usage for application developers
|
||||
|
||||
As an application developer you get:
|
||||
|
||||
- ability to inline localization data for any locales and namespaces to prevent async loading and improve rendering speed in critical cases;
|
||||
- smart defaults for data loading;
|
||||
- simple customization of paths where the data is loaded from for common use cases;
|
||||
|
|
@ -247,11 +253,15 @@ As an application developer you get:
|
|||
|
||||
If you want to optimize the page rendering and you can inline some of your localization data upfront then there is a simple way to do it:
|
||||
|
||||
```javascript
|
||||
```js
|
||||
// my-inlined-data.js
|
||||
import { localize } from 'lion-localize/localize.js';
|
||||
localize.addData('en-GB', 'my-namespace', {/* data */});
|
||||
localize.addData('nl-NL', 'my-namespace', {/* data */});
|
||||
localize.addData('en-GB', 'my-namespace', {
|
||||
/* data */
|
||||
});
|
||||
localize.addData('nl-NL', 'my-namespace', {
|
||||
/* data */
|
||||
});
|
||||
|
||||
// my-app.js
|
||||
import './my-inlined-data.js'; // must be on top to be executed before any other code using the data
|
||||
|
|
@ -268,10 +278,12 @@ But as we have already covered in the documentation for component developers the
|
|||
The configuration is done via `setupNamespaceLoader()`.
|
||||
This is sort of a router for the data and is typically needed to fetch it from an API.
|
||||
|
||||
```javascript
|
||||
```js
|
||||
// for one specific component
|
||||
localize.setupNamespaceLoader('my-hello-component', async (locale) => {
|
||||
const response = await fetch(`http://api.example.com/?namespace=my-hello-component&locale=${locale}`);
|
||||
localize.setupNamespaceLoader('my-hello-component', async locale => {
|
||||
const response = await fetch(
|
||||
`http://api.example.com/?namespace=my-hello-component&locale=${locale}`,
|
||||
);
|
||||
return response.json();
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -3,14 +3,16 @@
|
|||
The amount formatter returns a number based on the locale by using [Intl NumberFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NumberFormat) specification.
|
||||
|
||||
## Features
|
||||
|
||||
- **formatAmountHtml**: returns a formatted amount based on locale to be used in lit-html
|
||||
- **formatAmountHtmlString**: returns a formatted amount based on locale as a string
|
||||
|
||||
## How to use
|
||||
|
||||
### Installation
|
||||
```
|
||||
npm i --save @lion/localize;
|
||||
|
||||
```sh
|
||||
npm i --save @lion/localize
|
||||
```
|
||||
|
||||
### Example
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
The date formatter returns a date based on the locale by using [Intl DateTimeFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat) specification.
|
||||
|
||||
## Features
|
||||
|
||||
- **formatDate**: returns a formatted date based on locale
|
||||
- **parseDate**: returns a date Object
|
||||
- **getDateFormatBasedOnLocale**: returns the date format based on locale
|
||||
|
|
@ -10,8 +11,9 @@ The date formatter returns a date based on the locale by using [Intl DateTimeFor
|
|||
## How to use
|
||||
|
||||
### Installation
|
||||
```
|
||||
npm i --save @lion/localize;
|
||||
|
||||
```sh
|
||||
npm i --save @lion/localize
|
||||
```
|
||||
|
||||
### Example
|
||||
|
|
@ -19,12 +21,15 @@ npm i --save @lion/localize;
|
|||
```js
|
||||
import { parseDate, formatDate } from '@lion/localize';
|
||||
|
||||
function dateExampleFunction () {
|
||||
function dateExampleFunction() {
|
||||
const parsedDate = parseDate('21-05-2012');
|
||||
const options = {
|
||||
weekday: 'long', year: 'numeric', month: 'long', day: '2-digit',
|
||||
weekday: 'long',
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: '2-digit',
|
||||
};
|
||||
|
||||
return formatDate(parsedDate, options) // 'Monday, 21 May 2012' for British locale
|
||||
return formatDate(parsedDate, options); // 'Monday, 21 May 2012' for British locale
|
||||
}
|
||||
```
|
||||
|
|
|
|||
|
|
@ -9,16 +9,17 @@ The localization system helps to manage localization data, split into locales an
|
|||
The LocalizeMixin is the one you want to use in your web components. By adding this mixing, you can internationalize your component.
|
||||
|
||||
`LocalizeMixin` has the following features:
|
||||
|
||||
- Use translated text in your template (`msgLit()`)
|
||||
- Get the localize namespaces of the component (`localizeNamespaces`)
|
||||
- Await loading of localize namespaces (`localizeNamespacesLoaded`)
|
||||
|
||||
Advanced:
|
||||
|
||||
- Set whether your component should wait for localize namespaces before rendering your component's template (`waitForLocalizeNamespaces`)
|
||||
- Lit-element's `performUpdate()` is overridden in this mixin to perform updates async or delayed sync based on the `waitForLocalizeNamespaces` getter
|
||||
- Lifecycle methods `onLocaleReady()`, `onLocaleChanged()`, `onLocaleUpdated()`
|
||||
|
||||
|
||||
## How to use
|
||||
|
||||
### In a webcomponent
|
||||
|
|
@ -52,6 +53,7 @@ The `namespace` can be one of two types: an object with an explicit loader funct
|
|||
> When calling `this.msgLit()`, what comes after `:` may contain dots only if they are intended as a separator for objects. For more details, please check [messageformat](https://messageformat.github.io/messageformat/), which is the underlying library that we use.
|
||||
|
||||
An example of the a preconfigured loader:
|
||||
|
||||
```js
|
||||
static get localizeNamespaces() {
|
||||
return ['my-hello-component', ...super.localizeNamespaces];
|
||||
|
|
@ -85,6 +87,7 @@ class MyHelloComponent extends LocalizeMixin(LionLitElement) {
|
|||
```
|
||||
|
||||
It is also possible to pass data to your translation:
|
||||
|
||||
```js
|
||||
render() {
|
||||
return html`
|
||||
|
|
@ -98,6 +101,7 @@ render() {
|
|||
Usage of dynamic imports is recommended if you want to be able to create smart bundles later on for a certain locale.
|
||||
|
||||
### Not using a webcomponent
|
||||
|
||||
For example, if you simply want to make a reusable template, you can also use localization using the singleton instance of LocalizeManager called `localize`.
|
||||
|
||||
```js
|
||||
|
|
@ -112,6 +116,7 @@ export function myTemplate(someData) {
|
|||
`;
|
||||
}
|
||||
```
|
||||
|
||||
This template is meant for importing in your webcomponent which uses this localize namespace.
|
||||
|
||||
### Translation files
|
||||
|
|
@ -121,33 +126,32 @@ Typically the locale is an ES module which is by convention put into the `/trans
|
|||
|
||||
Localization data modules for `my-hello-component` might look like these:
|
||||
|
||||
|
||||
- `/path/to/my-family-component/translations/en.js`
|
||||
|
||||
```js
|
||||
export default {
|
||||
havePartnerQuestion: 'Do you have a partner?',
|
||||
haveChildrenQuestion: 'Do you have children?',
|
||||
};
|
||||
```
|
||||
```js
|
||||
export default {
|
||||
havePartnerQuestion: 'Do you have a partner?',
|
||||
haveChildrenQuestion: 'Do you have children?',
|
||||
};
|
||||
```
|
||||
|
||||
- `/path/to/my-family-component/translations/en-GB.js`
|
||||
|
||||
```js
|
||||
import en from './en.js'
|
||||
export default en;
|
||||
```
|
||||
```js
|
||||
import en from './en.js';
|
||||
export default en;
|
||||
```
|
||||
|
||||
- `/path/to/my-family-component/translations/en-US.js`
|
||||
|
||||
```js
|
||||
import en from './en.js'
|
||||
```js
|
||||
import en from './en.js';
|
||||
|
||||
export default {
|
||||
...en,
|
||||
haveChildrenQuestion: 'Do you have kids?',
|
||||
};
|
||||
```
|
||||
export default {
|
||||
...en,
|
||||
haveChildrenQuestion: 'Do you have kids?',
|
||||
};
|
||||
```
|
||||
|
||||
The module must have a `default` export as shown above to be handled properly.
|
||||
|
||||
|
|
@ -158,8 +162,10 @@ If you want to fetch translation data from some API this is also possible.
|
|||
```js
|
||||
// fetch from an API
|
||||
localize.loadNamespace({
|
||||
'my-hello-component': async (locale) => {
|
||||
const response = await fetch(`http://api.example.com/?namespace=my-hello-component&locale=${locale}`);
|
||||
'my-hello-component': async locale => {
|
||||
const response = await fetch(
|
||||
`http://api.example.com/?namespace=my-hello-component&locale=${locale}`,
|
||||
);
|
||||
return response.json(); // resolves to the JSON object `{ greeting: 'Hallo {name}!' }`
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
The number formatter returns a number based on the locale by using [Intl NumberFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NumberFormat) specification.
|
||||
|
||||
## Features
|
||||
|
||||
- **formatNumber**: returns a formatted number based on locale
|
||||
- **formatNumberToParts**: returns a formatted number in parts based on locale
|
||||
- **getFractionDigits**: returns the fraction digit for a certain currency
|
||||
|
|
@ -12,8 +13,9 @@ The number formatter returns a number based on the locale by using [Intl NumberF
|
|||
## How to use
|
||||
|
||||
### Installation
|
||||
```
|
||||
npm i --save @lion/localize;
|
||||
|
||||
```sh
|
||||
npm i --save @lion/localize
|
||||
```
|
||||
|
||||
### Example
|
||||
|
|
@ -21,9 +23,9 @@ npm i --save @lion/localize;
|
|||
```js
|
||||
import { formatNumber } from '@lion/localize';
|
||||
|
||||
function numberExampleFunction () {
|
||||
function numberExampleFunction() {
|
||||
const number = 2000;
|
||||
const options = { style: 'currency', currency: 'EUR', currencyDisplay: 'code' };
|
||||
return formatNumber(number, options) // 'EUR 2,000.00' for British locale
|
||||
const options = { style: 'currency', currency: 'EUR', currencyDisplay: 'code' };
|
||||
return formatNumber(number, options); // 'EUR 2,000.00' for British locale
|
||||
}
|
||||
```
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ Supports different types of overlays like dialogs, toasts, tooltips, dropdown, e
|
|||
Manages their position on the screen relative to other elements, including other overlays.
|
||||
|
||||
## Features
|
||||
|
||||
- [**Overlays Manager**](./docs/OverlaysManager.md), a global repository keeping track of all different types of overlays.
|
||||
- [**Overlays Occurrences**](./docs/OverlayOccurrences.md), outline of all possible occurrences of overlays. Divided into two main types:
|
||||
- [**Global Overlay Controller**](./docs/GlobalOverlayController.md), controller for overlays relative to the viewport.
|
||||
|
|
@ -14,18 +15,20 @@ Manages their position on the screen relative to other elements, including other
|
|||
## How to use
|
||||
|
||||
### Installation
|
||||
|
||||
```sh
|
||||
npm i --save @lion/overlays
|
||||
```
|
||||
|
||||
### Example
|
||||
|
||||
```js
|
||||
import { overlays } from '@lion/overlays';
|
||||
|
||||
const myCtrl = overlays.add(
|
||||
new OverlayTypeController({
|
||||
/* options */
|
||||
})
|
||||
}),
|
||||
);
|
||||
// name OverlayTypeController is for illustration purpose only
|
||||
// please read below about existing classes for different types of overlays
|
||||
|
|
|
|||
|
|
@ -8,22 +8,25 @@ All supported types of global overlays are described below.
|
|||
## How to use
|
||||
|
||||
### Installation
|
||||
|
||||
```sh
|
||||
npm i --save @lion/overlays
|
||||
```
|
||||
|
||||
### Example
|
||||
|
||||
```js
|
||||
import { overlays } from '@lion/overlays';
|
||||
|
||||
const myCtrl = overlays.add(
|
||||
new GlobalOverlayController({
|
||||
/* options */
|
||||
})
|
||||
}),
|
||||
);
|
||||
```
|
||||
|
||||
### ModalDialogController
|
||||
|
||||
A specific extension of GlobalOverlayController configured to create accessible modal dialogs.
|
||||
|
||||
```js
|
||||
|
|
|
|||
|
|
@ -8,21 +8,22 @@ All supported types of local overlays are described below.
|
|||
## How to use
|
||||
|
||||
### Installation
|
||||
|
||||
```sh
|
||||
npm i --save @lion/overlays
|
||||
```
|
||||
|
||||
### Example
|
||||
|
||||
```js
|
||||
import { overlays } from '@lion/overlays';
|
||||
|
||||
const myCtrl = overlays.add(
|
||||
new LocalOverlayController({
|
||||
/* options */
|
||||
})
|
||||
}),
|
||||
);
|
||||
```
|
||||
|
||||
|
||||
This is currently WIP.
|
||||
Stay tuned for updates on new types of overlays.
|
||||
|
|
|
|||
|
|
@ -1,19 +1,22 @@
|
|||
# LocalOverlayPositioning
|
||||
|
||||
## Featuring - [Popper.js](https://popper.js.org/)
|
||||
|
||||
Our local overlays use the open-source Popper.js library for positioning the content relative to the reference element, which we usually refer to as the invoker, in the context of local overlays.
|
||||
|
||||
## Features
|
||||
|
||||
- Everything Popper.js!
|
||||
- Currently eagerly loads popper in the constructor of LocalOverlayController. Loading during idle time / using prefetch would be better, this is still WIP.
|
||||
|
||||
|
||||
> Popper strictly is scoped on positioning. **It does not change the dimensions of the popper element nor the reference element**. This also means that if you use the arrow feature, you are in charge of styling it properly, use the x-placement attribute for this.
|
||||
|
||||
## How to use
|
||||
|
||||
For installation, see [LocalOverlayController](./LocalOverlayController.md)'s `How to use` section.
|
||||
|
||||
The API for LocalOverlay without Popper looks like this (`overlays` being the OverlayManager singleton):
|
||||
|
||||
```js
|
||||
const localOverlay = overlays.add(
|
||||
new LocalOverlayController({
|
||||
|
|
@ -28,7 +31,9 @@ const localOverlay = overlays.add(
|
|||
});
|
||||
);
|
||||
```
|
||||
|
||||
This will use the defaults we set for Popper configuration. To override the default options, you add a `popperConfig` object to the properties of the object you pass to `the LocalOverlayController` like so:
|
||||
|
||||
```js
|
||||
const localOverlay = overlays.add(
|
||||
new LocalOverlayController({
|
||||
|
|
@ -73,8 +78,10 @@ const localOverlay = overlays.add(
|
|||
});
|
||||
);
|
||||
```
|
||||
|
||||
The popperConfig is 1 to 1 aligned with Popper.js' API. For more detailed information and more advanced options, visit the [Popper.js documentation](https://popper.js.org/popper-documentation.html) to learn about the usage.
|
||||
|
||||
## Future additions
|
||||
|
||||
- Coming soon: Webcomponent implementation of LocalOverlay with a default arrow, styled out of the box to at least have proper rotations and positions.
|
||||
- Default overflow and/or max-width behavior when content is too wide or high for the viewport.
|
||||
|
|
|
|||
|
|
@ -1,29 +1,33 @@
|
|||
# Overlay System: Implementation
|
||||
|
||||
This document provides an outline of all possible occurrences of overlays found in applications in
|
||||
general and thus provided by Lion.
|
||||
For all concepts referred to in this document, please read [Overlay System Scope](./OverlaySystemScope.md).
|
||||
|
||||
## Local and global overlay controllers
|
||||
|
||||
Currently, we have a global and a local overlay controller, as two separate entities.
|
||||
Based on provided config, they handle all positioning logic, accessibility and interaction patterns.
|
||||
All of their configuration options will be described below as part of the _Responsive overlay_ section.
|
||||
|
||||
### Connection points and placement contexts
|
||||
|
||||
It's currently not clear where the border between global and local overlays lie. They seem to be
|
||||
separated based on their 'dom connection point' (body vs 'page cursor'(usually invoker sibling)).
|
||||
However, there is no required relationship here: we can create a modal dialog from
|
||||
local context('page cursor') as well.
|
||||
|
||||
Only, we would have a few concerns when creating global overlays from a local connection point:
|
||||
|
||||
- Accessibility will be harder to implement. When wai-aria 1.0 needs to be supported, all siblings
|
||||
need to have aria-hidden="true" and all parents role="presentation". Not always straightforward
|
||||
in shadow dom. If we only need to support wai-aria 1.1, we could use aria-modal="true" on the
|
||||
element with role="dialog". (we basically need to test our supported browsers and screen readers
|
||||
for compatibility with aria-modal).
|
||||
need to have aria-hidden="true" and all parents role="presentation". Not always straightforward
|
||||
in shadow dom. If we only need to support wai-aria 1.1, we could use aria-modal="true" on the
|
||||
element with role="dialog". (we basically need to test our supported browsers and screen readers
|
||||
for compatibility with aria-modal).
|
||||
- Stacking context need to be managed: the whole 'z-index chain' should win (it's a battle between
|
||||
parents in the hierarchy). This would require some complex code to cover all edge cases.
|
||||
parents in the hierarchy). This would require some complex code to cover all edge cases.
|
||||
- Side effects of parents adding transforms or clipping become a risk. This is hard to detect and
|
||||
'counter'.
|
||||
'counter'.
|
||||
|
||||
When the dom connection point is 'body', content projection will not work, but a template that
|
||||
can be rendered without being dependent on its context will be required.
|
||||
|
|
@ -41,7 +45,8 @@ focused cell in table mode))
|
|||
For maximum flexibility, it should be up to the developer to decide how overlays should be rendered,
|
||||
per instance of an overlay.
|
||||
|
||||
## Responsive overlay
|
||||
### Responsive overlay
|
||||
|
||||
Based on screen size, we might want to switch the appearance of an overlay.
|
||||
For instance: an application menu can be displayed as a dropdown on desktop,
|
||||
but as a bottom sheet on mobile.
|
||||
|
|
@ -61,7 +66,8 @@ Some options are mutually exclusive, in which case their dependent options and r
|
|||
mentioned.
|
||||
Note: a more generic and precise term for all mentionings of `invoker` below would actually be
|
||||
`relative positioning element`.
|
||||
```
|
||||
|
||||
```text
|
||||
- {Element} elementToFocusAfterHide - the element that should be called `.focus()` on after dialog closes
|
||||
- {Boolean} hasBackdrop - whether it should have a backdrop (currently exclusive to globalOverlayController)
|
||||
- {Boolean} isBlocking - hides other overlays when mutiple are opened (currently exclusive to globalOverlayController)
|
||||
|
|
@ -77,7 +83,8 @@ Note: a more generic and precise term for all mentionings of `invoker` below wou
|
|||
```
|
||||
|
||||
These options are suggested to be added to the current ones:
|
||||
```
|
||||
|
||||
```text
|
||||
- {Boolean} isModal - sets aria-modal and/or aria-hidden="true" on siblings
|
||||
- {Boolean} isGlobal - determines the connection point in DOM (body vs handled by user) TODO: rename to renderToBody?
|
||||
- {Boolean} isTooltip - has a totally different interaction - and accessibility pattern from all
|
||||
|
|
@ -99,7 +106,8 @@ other overlays, so needed for internals.
|
|||
```
|
||||
|
||||
What we should think about more properly is a global placement option (positioned relative to window instead of invoker)
|
||||
```
|
||||
|
||||
```text
|
||||
// TODO: namings very much under construction (we should also reconsider 'placement' names, see: https://github.com/ing-bank/lion/pull/61)
|
||||
// Something like the drawing Joren made: https://github.com/ing-bank/lion/issues/36#issuecomment-491855381
|
||||
- {String} viewportPlacement - consists of a vertical alignment part and an horizontal alignment part,
|
||||
|
|
@ -110,12 +118,14 @@ What we should think about more properly is a global placement option (positione
|
|||
```
|
||||
|
||||
## Controllers/behaviors
|
||||
|
||||
Controllers/behaviors provide preconfigured configuration objects for the global/local
|
||||
overlay controllers.
|
||||
They provide an imperative and very flexible api for creating overlays and should be used by
|
||||
Subclassers, inside webcomponents.
|
||||
|
||||
#### Dialog
|
||||
### Dialog Controller
|
||||
|
||||
```js
|
||||
{
|
||||
isGlobal: true,
|
||||
|
|
@ -130,7 +140,8 @@ Subclassers, inside webcomponents.
|
|||
}
|
||||
```
|
||||
|
||||
#### Tooltip
|
||||
### Tooltip Controller
|
||||
|
||||
```js
|
||||
{
|
||||
isTooltip: true,
|
||||
|
|
@ -139,16 +150,20 @@ Subclassers, inside webcomponents.
|
|||
}
|
||||
```
|
||||
|
||||
#### Popover
|
||||
### Popover Controller
|
||||
|
||||
```js
|
||||
{
|
||||
handlesUserInteraction: true,
|
||||
handlesAccessibility: true,
|
||||
}
|
||||
```
|
||||
#### Dropdown
|
||||
|
||||
### Dropdown Controller
|
||||
|
||||
It will be quite common to override placement to 'bottom-fullwidth'.
|
||||
Also, it would be quite common to add a pointerNode.
|
||||
|
||||
```js
|
||||
{
|
||||
placement: 'bottom',
|
||||
|
|
@ -156,63 +171,79 @@ Also, it would be quite common to add a pointerNode.
|
|||
handlesAccessibility: true,
|
||||
}
|
||||
```
|
||||
#### Toast
|
||||
|
||||
### Toast Controller
|
||||
|
||||
TODO:
|
||||
|
||||
- add an option for role="alertdialog" ?
|
||||
- add an option for a 'hide timer' and belonging a11y features for this
|
||||
|
||||
```js
|
||||
{
|
||||
...Dialog,
|
||||
viewportPlacement: 'top-right', (?)
|
||||
}
|
||||
```
|
||||
#### Sheet (bottom, top, left, right)
|
||||
|
||||
### Sheet Controller (bottom, top, left, right)
|
||||
|
||||
```js
|
||||
{
|
||||
...Dialog,
|
||||
viewportPlacement: '{top|bottom|left|right}-fullwidth', (?)
|
||||
}
|
||||
```
|
||||
#### Select
|
||||
|
||||
### Select Controller
|
||||
|
||||
No need for a config, will probably invoke ResponsiveOverlayCtrl and switches
|
||||
config based on media query from Dropdown to BottomSheet/CenteredDialog
|
||||
|
||||
#### Combobox/autocomplete
|
||||
### Combobox/autocomplete Controller
|
||||
|
||||
No need for a config, will probably invoke ResponsiveOverlayCtrl and switches
|
||||
config based on media query from Dropdown to BottomSheet/CenteredDialog
|
||||
|
||||
#### Application menu
|
||||
### Application menu Controller
|
||||
|
||||
No need for cfg, will probably invoke ResponsiveOverlayCtrl and switches
|
||||
config based on media query from Dropdown to BottomSheet/CenteredDialog
|
||||
|
||||
|
||||
## Web components
|
||||
|
||||
Web components provide a declaritive, developer friendly interface with a prewconfigured styling
|
||||
that fits the Design System and makes it really easy for Application Developers to build
|
||||
user interfaces.
|
||||
Web components should use
|
||||
The ground layers for the webcomponents in Lion are the following:
|
||||
|
||||
#### Dialog
|
||||
### Dialog Component
|
||||
|
||||
Imperative might be better here? We can add a web component later if needed.
|
||||
|
||||
#### Tooltip
|
||||
### Tooltip Component
|
||||
|
||||
```html
|
||||
<lion-tooltip>
|
||||
<button slot="invoker">hover/focus</button>
|
||||
<div slot="content">This will be shown</div>
|
||||
</lion-tooltip>
|
||||
```
|
||||
#### Popover
|
||||
|
||||
### Popover Component
|
||||
|
||||
```html
|
||||
<lion-popover>
|
||||
<button slot="invoker">click/space/enter</button>
|
||||
<div slot="content">This will be shown</div>
|
||||
</lion-popover>
|
||||
```
|
||||
#### Dropdown
|
||||
|
||||
### Dropdown Component
|
||||
|
||||
Like the name suggests, the default placement will be button
|
||||
|
||||
```html
|
||||
<lion-dropdown>
|
||||
<button slot="invoker">click/space/enter</button>
|
||||
|
|
@ -223,17 +254,18 @@ Like the name suggests, the default placement will be button
|
|||
</ul>
|
||||
</lion-dropdown>
|
||||
```
|
||||
#### Toast
|
||||
|
||||
Imperative might be better here?
|
||||
#### Sheet (bottom, top, left, right)
|
||||
### Toast Component
|
||||
|
||||
Imperative might be better here?
|
||||
|
||||
### Sheet Component (bottom, top, left, right)
|
||||
|
||||
### Web components implementing generic overlays
|
||||
Imperative might be better here?
|
||||
|
||||
#### Select, Combobox/autocomplete, Application menu
|
||||
## Web components implementing generic overlays
|
||||
|
||||
### Select, Combobox/autocomplete, Application menu
|
||||
|
||||
Those will be separate web components with a lot of form and a11y logic that will be described
|
||||
in detail in different sections.
|
||||
|
|
|
|||
|
|
@ -10,18 +10,20 @@ document flow.
|
|||
An overlay manager is a global repository keeping track of all different types of overlays.
|
||||
The need for a global housekeeping mainly arises when multiple overlays are opened simultaneously.
|
||||
As opposed to a single overlay, the overlay manager stores knowledge about:
|
||||
|
||||
- whether the scroll behaviour of the body element can be manipulated
|
||||
- what space is available in the window for drawing new overlays
|
||||
|
||||
The manager is in charge of rendering an overlay to the DOM. Therefore, a developer should be able
|
||||
to control:
|
||||
|
||||
- It’s ‘physical position’ (where the dialog is attached). This can either be:
|
||||
- globally: at root level of the DOM. This guarantees a total control over its painting, since
|
||||
- globally: at root level of the DOM. This guarantees a total control over its painting, since
|
||||
the stacking context can be controlled from here and interfering parents (that set overflow
|
||||
values or transforms) can’t be apparent. Additionally, making a modal dialog requiring
|
||||
all surroundings to have aria-hidden="true", will be easier when the overlay is attached on
|
||||
body level.
|
||||
- locally: next to the invoking element. This gives advantages for accessibility and
|
||||
- locally: next to the invoking element. This gives advantages for accessibility and
|
||||
(performant) rendering of an overlay next to its invoker on scroll and window resizes
|
||||
- Toggling of the ‘shown’ state of the overlay
|
||||
- Positioning preferences(for instance ‘bottom-left’) and strategies (ordered fallback preferences)
|
||||
|
|
@ -35,12 +37,13 @@ browser/screen reader support (aria 1.0 vs 1.1). We strive for an optimum here b
|
|||
|
||||
For every overlay, the manager has access to the overlay element and the invoker (and possible
|
||||
other elements that are needed for focus delegation as described in
|
||||
https://www.w3.org/TR/wai-aria-practices/#dialog_modal (notes).
|
||||
<https://www.w3.org/TR/wai-aria-practices/#dialog_modal> (notes).
|
||||
|
||||
## Defining different types of overlays
|
||||
|
||||
When browsing through the average ui library, one can encounter multiple names for occurrences of
|
||||
overlays. Here is a list of names encountered throughout the years:
|
||||
|
||||
- dialog
|
||||
- modal
|
||||
- popover
|
||||
|
|
@ -67,11 +70,11 @@ in framework C, might actually be just a dialog. Etc etc…
|
|||
|
||||
In order to avoid confusion and be as specification compliant as possible, it’s always a good idea
|
||||
to consult the W3C. This website shows a full list with specifications of accessible web widgets:
|
||||
https://www.w3.org/TR/wai-aria-practices/.
|
||||
<https://www.w3.org/TR/wai-aria-practices/>.
|
||||
A great overview of all widget-, structure- and role relations can be found in the ontology diagram
|
||||
below:
|
||||

|
||||
https://www.w3.org/WAI/PF/aria-1.1/rdf_model.svg
|
||||
<https://www.w3.org/WAI/PF/aria-1.1/rdf_model.svg>
|
||||
|
||||
Out of all the overlay names mentioned above, we can only identify the dialog and the tooltip as
|
||||
official roles.
|
||||
|
|
@ -80,57 +83,59 @@ Let’s take a closer look at their definitions...
|
|||
### Dialog
|
||||
|
||||
The dialog is described as follows by the W3C:
|
||||
> “A dialog is a window overlaid on either the primary window or another dialog window. Windows
|
||||
under a modal dialog are inert. That is, users cannot interact with content outside an active
|
||||
dialog window. Inert content outside an active dialog is typically visually obscured or dimmed so
|
||||
it is difficult to discern, and in some implementations, attempts to interact with the inert
|
||||
content cause the dialog to close.
|
||||
Like non-modal dialogs, modal dialogs contain their tab sequence. That is, Tab and Shift + Tab do
|
||||
not move focus outside the dialog. However, unlike most non-modal dialogs, modal dialogs do not
|
||||
provide means for moving keyboard focus outside the dialog window without closing the dialog.”
|
||||
|
||||
- specification: https://www.w3.org/TR/wai-aria-1.1/#dialog
|
||||
- widget description: https://www.w3.org/TR/wai-aria-practices/#dialog_modal
|
||||
> “A dialog is a window overlaid on either the primary window or another dialog window. Windows
|
||||
> under a modal dialog are inert. That is, users cannot interact with content outside an active
|
||||
> dialog window. Inert content outside an active dialog is typically visually obscured or dimmed so
|
||||
> it is difficult to discern, and in some implementations, attempts to interact with the inert
|
||||
> content cause the dialog to close.
|
||||
> Like non-modal dialogs, modal dialogs contain their tab sequence. That is, Tab and Shift + Tab do
|
||||
> not move focus outside the dialog. However, unlike most non-modal dialogs, modal dialogs do not
|
||||
> provide means for moving keyboard focus outside the dialog window without closing the dialog.”
|
||||
|
||||
- specification: <https://www.w3.org/TR/wai-aria-1.1/#dialog>
|
||||
- widget description: <https://www.w3.org/TR/wai-aria-practices/#dialog_modal>
|
||||
|
||||
### Tooltip
|
||||
|
||||
According to W3C, a tooltip is described by the following:
|
||||
> “A tooltip is a popup that displays information related to an element when the element receives
|
||||
keyboard focus or the mouse hovers over it. It typically appears after a small delay and disappears
|
||||
when Escape is pressed or on mouse out.
|
||||
> Tooltip widgets do not receive focus. A hover that contains focusable elements can be made using
|
||||
a non-modal dialog.”
|
||||
|
||||
- specification: https://www.w3.org/TR/wai-aria-1.1/#tooltip
|
||||
- widget description: https://www.w3.org/TR/wai-aria-practices/#tooltip
|
||||
> “A tooltip is a popup that displays information related to an element when the element receives
|
||||
> keyboard focus or the mouse hovers over it. It typically appears after a small delay and disappears
|
||||
> when Escape is pressed or on mouse out.
|
||||
> Tooltip widgets do not receive focus. A hover that contains focusable elements can be made using
|
||||
> a non-modal dialog.”
|
||||
|
||||
- specification: <https://www.w3.org/TR/wai-aria-1.1/#tooltip>
|
||||
- widget description: <https://www.w3.org/TR/wai-aria-practices/#tooltip>
|
||||
|
||||
What needs to be mentioned is that the W3C taskforce didn’t reach consensus yet about the above
|
||||
tooltip description. A good alternative resource:
|
||||
https://inclusive-components.design/tooltips-toggletips/
|
||||
<https://inclusive-components.design/tooltips-toggletips/>
|
||||
|
||||
### Dialog vs tooltip
|
||||
|
||||
Summarizing, the main differences between dialogs and tooltips are:
|
||||
|
||||
- Dialogs have a modal option, tooltips don’t
|
||||
- Dialogs have interactive content, tooltips don’t
|
||||
- Dialogs are opened via regular buttons (click/space/enter), tooltips act on focus/mouseover
|
||||
|
||||
|
||||
### Other roles and concepts
|
||||
|
||||
Other roles worth mentioning are *alertdialog* (a specific instance of the dialog for system
|
||||
alerts), select (an abstract role), *combobox* and *menu*.
|
||||
Other roles worth mentioning are _alertdialog_ (a specific instance of the dialog for system
|
||||
alerts), select (an abstract role), _combobox_ and _menu_.
|
||||
|
||||
Also, the W3C document often refers to *popup*. This term is mentioned in the context of *combobox*,
|
||||
*listbox*, *grid*, *tree*, *dialog* and *tooltip*. Therefore, one could say it could be a term
|
||||
Also, the W3C document often refers to _popup_. This term is mentioned in the context of _combobox_,
|
||||
_listbox_, _grid_, _tree_, _dialog_ and _tooltip_. Therefore, one could say it could be a term
|
||||
|
||||
*aria-haspopup* attribute needs to be mentioned: it can have values ‘menu’, ‘listbox’, ‘grid’,
|
||||
_aria-haspopup_ attribute needs to be mentioned: it can have values ‘menu’, ‘listbox’, ‘grid’,
|
||||
’tree’ and ‘dialog’.
|
||||
|
||||
|
||||
## Common Overlay Components
|
||||
|
||||
In our component library, we want to have the following overlay ‘child’ components:
|
||||
|
||||
- Dialog
|
||||
- Tooltip
|
||||
- Popover
|
||||
|
|
@ -141,77 +146,69 @@ In our component library, we want to have the following overlay ‘child’ comp
|
|||
- Combobox/autocomplete
|
||||
- Application menu
|
||||
|
||||
### Dialog
|
||||
### Dialog Component
|
||||
|
||||
The dialog is pretty much the dialog as described in the W3C spec, having the modal option applied
|
||||
by default.
|
||||
The flexibility in focus delegation (see https://www.w3.org/TR/wai-aria-practices/#dialog_modal
|
||||
notes) is not implemented, however.
|
||||
The flexibility in focus delegation (see <https://www.w3.org/TR/wai-aria-practices/#dialog_modal> notes) is not implemented, however.
|
||||
Addressing these:
|
||||
|
||||
- The first focusable element in the content: although delegate this focus management to the
|
||||
implementing developer is highly preferred, since this is highly dependent on the moment the dialog
|
||||
content has finished rendering. This is something the overlay manager or dialog widget should not
|
||||
be aware of in order to provide.a clean and reliable component.
|
||||
implementing developer is highly preferred, since this is highly dependent on the moment the dialog
|
||||
content has finished rendering. This is something the overlay manager or dialog widget should not
|
||||
be aware of in order to provide.a clean and reliable component.
|
||||
- The focusable element after a close: by default, this is the invoker. For different behaviour, a
|
||||
reference should be supplied to a more logical element in the particular workflow.
|
||||
reference should be supplied to a more logical element in the particular workflow.
|
||||
|
||||
|
||||
### Tooltip
|
||||
### Tooltip Component
|
||||
|
||||
The tooltip is always invoked on hover and has no interactive content. See
|
||||
https://inclusive-components.design/tooltips-toggletips/ (the tooltip example, not the toggle tip).
|
||||
<https://inclusive-components.design/tooltips-toggletips/> (the tooltip example, not the toggle tip).
|
||||
|
||||
|
||||
### Popover
|
||||
### Popover Component
|
||||
|
||||
The popover looks like a crossover between the dialog and the tooltip. Popovers are invoked on
|
||||
click. For non interactive content, the https://inclusive-components.design/tooltips-toggletips/
|
||||
toggletip could be applied.
|
||||
click. For non interactive content, the <https://inclusive-components.design/tooltips-toggletips/> toggletip could be applied.
|
||||
Whenever there would be a close button present, the ‘non interactiveness’ wouldn’t apply.
|
||||
|
||||
An alternative implementation: https://whatsock.com/tsg/Coding%20Arena/Popups/Popup%20(Internal%20Content)/demo.htm
|
||||
An alternative implementation: <https://whatsock.com/tsg/Coding%20Arena/Popups/Popup%20(Internal%20Content)/demo.htm>
|
||||
This looks more like a small dialog, except that the page flow is respected (no rotating tab)
|
||||
|
||||
|
||||
### Dropdown
|
||||
### Dropdown Component
|
||||
|
||||
The dropdown is not an official aria-widget and thus can’t be tied to a specific role. It exists
|
||||
in a lot of UI libraries and most of them share these properties:
|
||||
- Preferred position is ‘down’
|
||||
- When no space at bottom, they show ‘up’ (in which. Case it behaves a as a dropup)
|
||||
- Unlike popovers and tooltips, it will never be positioned horizontally
|
||||
|
||||
- Preferred position is ‘down’
|
||||
- When no space at bottom, they show ‘up’ (in which. Case it behaves a as a dropup)
|
||||
- Unlike popovers and tooltips, it will never be positioned horizontally
|
||||
|
||||
Aliases are ‘popdown’, ‘pulldown’ and many others.
|
||||
|
||||
|
||||
### Select
|
||||
### Select Component
|
||||
|
||||
Implemented as a dropdown listbox with invoker button. Depending on the content of the options,
|
||||
the child list can either be of type listbox or grid.
|
||||
See: https://www.w3.org/TR/wai-aria-practices/examples/listbox/listbox-collapsible.html
|
||||
See: <https://www.w3.org/TR/wai-aria-practices/examples/listbox/listbox-collapsible.html>
|
||||
|
||||
|
||||
### Combobox
|
||||
### Combobox Component
|
||||
|
||||
Implemented as a dropdown combobox with invoker input. Input is used as search filter
|
||||
and can contain autocomplete or autosuggest functionality:
|
||||
See: https://www.w3.org/TR/wai-aria-practices/#combobox
|
||||
See: <https://www.w3.org/TR/wai-aria-practices/#combobox>
|
||||
|
||||
|
||||
### (Application) menu
|
||||
### (Application) menu Component
|
||||
|
||||
Or sometimes called context-menu. Uses a dropdown to position its content.
|
||||
See: https://www.w3.org/WAI/tutorials/menus/flyout/
|
||||
Be aware not to use role=“menu”: https://www.w3.org/WAI/tutorials/menus/application-menus/
|
||||
See: <https://www.w3.org/WAI/tutorials/menus/flyout/>
|
||||
Be aware not to use role=“menu”: <https://www.w3.org/WAI/tutorials/menus/application-menus/>
|
||||
|
||||
### Toast Component
|
||||
|
||||
### Toast
|
||||
|
||||
See: https://www.webcomponents.org/element/@polymer/paper-toast. Should probably be implemented as
|
||||
See: <https://www.webcomponents.org/element/@polymer/paper-toast>. Should probably be implemented as
|
||||
an alertdialog.
|
||||
|
||||
### Sheet Component
|
||||
|
||||
### Sheet
|
||||
|
||||
See: https://material.io/design/components/sheets-bottom.html. Should probably be a
|
||||
See: <https://material.io/design/components/sheets-bottom.html>. Should probably be a
|
||||
global(modal) dialog.
|
||||
|
|
|
|||
|
|
@ -7,7 +7,9 @@
|
|||
You should use [lion-radio](../radio/)'s inside this element.
|
||||
|
||||
## Features
|
||||
|
||||
Since it extends from [lion-fieldset](../fieldset/), it has all the features a fieldset has.
|
||||
|
||||
- Get or set the checked value of the group:
|
||||
- modelValue (default) - `checkedValue()`
|
||||
- formattedValue - `formattedValue()`
|
||||
|
|
@ -16,7 +18,8 @@ Since it extends from [lion-fieldset](../fieldset/), it has all the features a f
|
|||
## How to use
|
||||
|
||||
### Installation
|
||||
```
|
||||
|
||||
```sh
|
||||
npm i --save @lion/radio @lion/radio-group
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
`lion-radio` component is a sub-element to be used in [lion-radio-group](../radio-group/) elements. Its purpose is to provide a way for users to check a **single** option amongst a set of choices.
|
||||
|
||||
## Features
|
||||
|
||||
- Get or set the checked state (boolean) - `choiceChecked()`
|
||||
- Get or set the value of the choice - `choiceValue()`
|
||||
- Pre-select an option by setting the `checked` boolean attribute
|
||||
|
|
@ -12,8 +13,9 @@
|
|||
## How to use
|
||||
|
||||
### Installation
|
||||
```
|
||||
npm i --save @lion/radio;
|
||||
|
||||
```sh
|
||||
npm i --save @lion/radio
|
||||
```
|
||||
|
||||
```js
|
||||
|
|
|
|||
|
|
@ -10,13 +10,15 @@ where each option name starts with the same word or phrase can also significantl
|
|||
usability for keyboard and screen reader users.
|
||||
|
||||
## Features
|
||||
|
||||
- catches and forwards the select events
|
||||
- can be set to required or disabled
|
||||
|
||||
## How to use
|
||||
|
||||
### Installation
|
||||
```
|
||||
|
||||
```sh
|
||||
npm i --save @lion/select
|
||||
```
|
||||
|
||||
|
|
@ -42,11 +44,9 @@ import '@lion/select/lion-select.js';
|
|||
```
|
||||
|
||||
You can preselect an option by setting the property modelValue.
|
||||
|
||||
```html
|
||||
<lion-select
|
||||
name="favoriteColor"
|
||||
.modelValue="${'<value of option 2>'}"
|
||||
>
|
||||
<lion-select name="favoriteColor" .modelValue="${'<value of option 2>'}">
|
||||
...
|
||||
</lion-select>
|
||||
```
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
`lion-steps` breaks a single goal down into dependable sub-tasks.
|
||||
|
||||
## Features
|
||||
|
||||
- navigate between different steps with 'previous' and 'next' functions.
|
||||
- keeps status of each step
|
||||
- untouched
|
||||
|
|
@ -21,7 +22,8 @@ In many application you build multi-step workflows like multi-step forms where y
|
|||
## How to use
|
||||
|
||||
### Installation
|
||||
```
|
||||
|
||||
```sh
|
||||
npm i --save @lion/select
|
||||
```
|
||||
|
||||
|
|
@ -45,7 +47,7 @@ We provide two components: `lion-steps` and `lion-step`. Steps need to be direct
|
|||
|
||||
The first step needs to be explicitely set via `initial-step` so that it get status `entered`, while others are `untouched` by default. You can navigate between steps using `next()` and `previous()` methods, so that next step gets `entered` status, while previous one becomes `left`:
|
||||
|
||||
```javascript
|
||||
```js
|
||||
...
|
||||
next() {
|
||||
return this.$id('steps').next();
|
||||
|
|
@ -90,7 +92,8 @@ If you have an intermediate step loading data via AJAX request and then automati
|
|||
<lion-steps>
|
||||
<lion-step>preliminary step</lion-step>
|
||||
<lion-step forward-only>data is loaded and next() is called automatically afterwards</lion-step>
|
||||
<lion-step>do smth with data</lion-step><!-- user decides to go to previous step here -->
|
||||
<!-- user decides to go to previous step here -->
|
||||
<lion-step>do smth with data</lion-step>
|
||||
</lion-steps>
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -24,8 +24,5 @@ import '@lion/textarea/lion-textarea.js';
|
|||
### Example
|
||||
|
||||
```html
|
||||
<lion-textarea
|
||||
label="Stops growing after 4 rows"
|
||||
max-rows="4"
|
||||
></lion-textarea>
|
||||
<lion-textarea label="Stops growing after 4 rows" max-rows="4"></lion-textarea>
|
||||
```
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ import { %validatorName% } from '@lion/validate';
|
|||
```
|
||||
|
||||
> Note that we import an lion-input here as an example of a form control implementing ValidateMixin.
|
||||
We could equally well use lion-textarea, lion-select, lion-fieldset etc. to illustrate our example.
|
||||
> We could equally well use lion-textarea, lion-select, lion-fieldset etc. to illustrate our example.
|
||||
|
||||
### Example
|
||||
|
||||
|
|
@ -42,7 +42,8 @@ import '@lion/input/lion-input.js';
|
|||
import { isString, maxLengthValidator, defaultOkValidator } from '@lion/validate';
|
||||
|
||||
const isInitialsRegex = /^([A-Z]\.)+$/;
|
||||
export const isExampleInitials = value => isString(value) && isInitialsRegex.test(value.toUpperCase());
|
||||
export const isExampleInitials = value =>
|
||||
isString(value) && isInitialsRegex.test(value.toUpperCase());
|
||||
export const isExampleInitialsValidator = () => [
|
||||
(...params) => ({ isExampleInitials: isExampleInitials(...params) }),
|
||||
];
|
||||
|
|
@ -63,7 +64,7 @@ A validator applied to `.errorValidators` expects an array with a function, a pa
|
|||
optionally an additional configuration object.
|
||||
|
||||
```js
|
||||
minMaxLengthValidator({ min: 5, max: 10 })
|
||||
minMaxLengthValidator({ min: 5, max: 10 });
|
||||
```
|
||||
|
||||
The custom `isExampleInitialsValidator` checks if the value is fitting our regex, but does not
|
||||
|
|
|
|||
|
|
@ -25,8 +25,8 @@ All validators are provided via pure functions. They should be applied to the el
|
|||
|
||||
```html
|
||||
<validatable-el
|
||||
.errorValidators="${[[ myValidatorFunction, { myParam: 'foo' }, { extra: 'options' } ]]}">
|
||||
</validatable-el>
|
||||
.errorValidators="${[[ myValidatorFunction, { myParam: 'foo' }, { extra: 'options' } ]]}"
|
||||
></validatable-el>
|
||||
```
|
||||
|
||||
As you can see the 'errorValidators' property expects a map (an array of arrays).
|
||||
|
|
@ -46,8 +46,8 @@ Below example has two validators (as factory functions) applied:
|
|||
|
||||
```html
|
||||
<validatable-el
|
||||
.errorValidators="${[minLengthValidator({ min: 3 }), isZipCodeValidator()]}">
|
||||
</validatable-el>
|
||||
.errorValidators="${[minLengthValidator({ min: 3 }), isZipCodeValidator()]}"
|
||||
></validatable-el>
|
||||
```
|
||||
|
||||
### Default Validators
|
||||
|
|
@ -112,8 +112,8 @@ The api for warning validators and info validators are as follows:
|
|||
```html
|
||||
<validatable-field
|
||||
.warningValidators="${[myWarningValidator()]}"
|
||||
.infoValidators="${[myInfoValidator()]}">
|
||||
</validatable-field>
|
||||
.infoValidators="${[myInfoValidator()]}"
|
||||
></validatable-field>
|
||||
```
|
||||
|
||||
### Success validators
|
||||
|
|
|
|||
Loading…
Reference in a new issue