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:
|
Check out ways to contribute to Lion Web Components:
|
||||||
|
|
||||||
## Existing components: we love pull requests ♥
|
## Existing components: we love pull requests ♥
|
||||||
|
|
||||||
Help out the whole lion community by sending your merge requests and issues.
|
Help out the whole lion community by sending your merge requests and issues.
|
||||||
Check out how to set it up:
|
Check out how to set it up:
|
||||||
|
|
||||||
Setup:
|
Setup:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Clone the repo:
|
# Clone the repo:
|
||||||
git clone https://github.com/ing-bank/lion.git
|
git clone https://github.com/ing-bank/lion.git
|
||||||
|
|
@ -20,6 +22,7 @@ git checkout -b fix/buttonSize
|
||||||
```
|
```
|
||||||
|
|
||||||
Make sure everything works as expected:
|
Make sure everything works as expected:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Linting
|
# Linting
|
||||||
npm run lint
|
npm run lint
|
||||||
|
|
@ -32,7 +35,9 @@ npm run storybook
|
||||||
```
|
```
|
||||||
|
|
||||||
Create a Pull Request:
|
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
|
```bash
|
||||||
# add fork to your remotes
|
# add fork to your remotes
|
||||||
git remote add fork git@github.com:<your-user>/lion.git
|
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
|
# push new branch to your fork
|
||||||
git push -u fork fix/buttonSize
|
git push -u fork fix/buttonSize
|
||||||
```
|
```
|
||||||
|
|
||||||
- Go to your fork and create a Pull Request :)
|
- Go to your fork and create a Pull Request :)
|
||||||
|
|
||||||
Some things that will increase the chance that your merge request is accepted:
|
Some things that will increase the chance that your merge request is accepted:
|
||||||
|
|
||||||
* Write tests.
|
- Write tests.
|
||||||
* Write a [good commit message](https://www.conventionalcommits.org/).
|
- Write a [good commit message](https://www.conventionalcommits.org/).
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
# Lion Web Components
|
||||||
|
|
||||||
> ## 🛠 Status: Pilot Phase
|
> ## 🛠 Status: Pilot Phase
|
||||||
>
|
>
|
||||||
> Lion Web Components are still in an early alpha stage; they should not be considered production ready yet.
|
> 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 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
|
> - 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)
|
> 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
|
|
||||||
|
|
||||||
Lion web components is a set of highly performant, accessible and flexible Web Components.
|
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.
|
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)
|
It is a promise based system for fetching data, based on [axios](https://github.com/axios/axios)
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- only JS functions, no (unnecessarily expensive) web components
|
- only JS functions, no (unnecessarily expensive) web components
|
||||||
- supports GET, POST, PUT, DELETE, REQUEST, PATCH and HEAD methods
|
- supports GET, POST, PUT, DELETE, REQUEST, PATCH and HEAD methods
|
||||||
- can be used with or without XSRF token
|
- can be used with or without XSRF token
|
||||||
|
|
||||||
|
|
||||||
## How to use
|
## How to use
|
||||||
|
|
||||||
### Installation
|
### Installation
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
npm i --save @lion/ajax
|
npm i --save @lion/ajax
|
||||||
```
|
```
|
||||||
|
|
||||||
### Example
|
### Example
|
||||||
|
|
||||||
```js
|
```js
|
||||||
import { ajax } from '@lion/ajax';
|
import { ajax } from '@lion/ajax';
|
||||||
|
|
||||||
ajax.get('data.json')
|
ajax
|
||||||
.then((response) => {
|
.get('data.json')
|
||||||
|
.then(response => {
|
||||||
console.log(response);
|
console.log(response);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch(error => {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
@ -34,15 +37,17 @@ ajax.get('data.json')
|
||||||
### Create own instances for custom options
|
### Create own instances for custom options
|
||||||
|
|
||||||
#### Cancel
|
#### Cancel
|
||||||
|
|
||||||
```js
|
```js
|
||||||
import { AjaxClass } from '@lion/ajax';
|
import { AjaxClass } from '@lion/ajax';
|
||||||
|
|
||||||
const myAjax = AjaxClass.getNewInstance({ cancelable: true });
|
const myAjax = AjaxClass.getNewInstance({ cancelable: true });
|
||||||
myAjax.get('data.json')
|
myAjax
|
||||||
.then((response) => {
|
.get('data.json')
|
||||||
|
.then(response => {
|
||||||
document.querySelector('#canceled').innerHTML = JSON.stringify(response.data);
|
document.querySelector('#canceled').innerHTML = JSON.stringify(response.data);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch(error => {
|
||||||
document.querySelector('#canceled').innerHTML = `I got cancelled: ${error.message}`;
|
document.querySelector('#canceled').innerHTML = `I got cancelled: ${error.message}`;
|
||||||
});
|
});
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
|
@ -51,22 +56,25 @@ setTimeout(() => {
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Cancel previous on new request
|
#### Cancel previous on new request
|
||||||
|
|
||||||
```js
|
```js
|
||||||
import { AjaxClass } from '@lion/ajax'
|
import { AjaxClass } from '@lion/ajax';
|
||||||
|
|
||||||
const myAjax = AjaxClass.getNewInstance({ cancelPreviousOnNewRequest: true });
|
const myAjax = AjaxClass.getNewInstance({ cancelPreviousOnNewRequest: true });
|
||||||
myAjax.get('data.json')
|
myAjax
|
||||||
.then((response) => {
|
.get('data.json')
|
||||||
|
.then(response => {
|
||||||
document.querySelector('#request1').innerHTML = 'Request 1: ' + JSON.stringify(response.data);
|
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}`;
|
document.querySelector('#request1').innerHTML = `Request 1: I got cancelled: ${error.message}`;
|
||||||
});
|
});
|
||||||
myAjax.get('data2.json')
|
myAjax
|
||||||
.then((response) => {
|
.get('data2.json')
|
||||||
|
.then(response => {
|
||||||
document.querySelector('#request2').innerHTML = 'Request 2: ' + JSON.stringify(response.data);
|
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}`;
|
document.querySelector('#request2').innerHTML = `Request 2: I got cancelled: ${error.message}`;
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -7,12 +7,14 @@
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
### Disabled
|
### Disabled
|
||||||
|
|
||||||
You can also set a button as disabled with the `disabled` property.
|
You can also set a button as disabled with the `disabled` property.
|
||||||
|
|
||||||
## How to use
|
## How to use
|
||||||
|
|
||||||
### Installation
|
### Installation
|
||||||
```
|
|
||||||
|
```sh
|
||||||
npm i --save @lion/button
|
npm i --save @lion/button
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,12 +7,14 @@
|
||||||
You should use [lion-checkbox](../checkbox/)'s inside this element.
|
You should use [lion-checkbox](../checkbox/)'s inside this element.
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
Since it extends from [lion-fieldset](../fieldset/), it has all the features a fieldset has.
|
Since it extends from [lion-fieldset](../fieldset/), it has all the features a fieldset has.
|
||||||
|
|
||||||
## How to use
|
## How to use
|
||||||
|
|
||||||
### Installation
|
### Installation
|
||||||
```
|
|
||||||
|
```sh
|
||||||
npm i --save @lion/checkbox @lion/checkbox-group
|
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.
|
`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
|
## Features
|
||||||
|
|
||||||
- Get or set the checked state (boolean) - `choiceChecked()`
|
- Get or set the checked state (boolean) - `choiceChecked()`
|
||||||
- Get or set the value of the choice - `choiceValue()`
|
- Get or set the value of the choice - `choiceValue()`
|
||||||
- Pre-select an option by setting the `checked` boolean attribute
|
- Pre-select an option by setting the `checked` boolean attribute
|
||||||
|
|
@ -12,8 +13,9 @@
|
||||||
## How to use
|
## How to use
|
||||||
|
|
||||||
### Installation
|
### Installation
|
||||||
```
|
|
||||||
npm i --save @lion/checkbox;
|
```sh
|
||||||
|
npm i --save @lion/checkbox
|
||||||
```
|
```
|
||||||
|
|
||||||
```js
|
```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.
|
This is an example of how to make a conventional ES mixin deduping.
|
||||||
|
|
||||||
```javascript
|
```js
|
||||||
const BaseMixin = dedupeMixin((superClass) => {
|
const BaseMixin = dedupeMixin((superClass) => {
|
||||||
return class extends superClass { ... };
|
return class extends superClass { ... };
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
# Form Fundaments
|
# Form Fundaments
|
||||||
|
|
||||||
[//]: # 'AUTO INSERT HEADER PREPUBLISH'
|
[//]: # '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
|
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
|
[custom form field](./docs/CustomFieldsTutorial.md) should be created. One could think of components
|
||||||
like:
|
like:
|
||||||
|
|
||||||
- slider
|
- slider
|
||||||
- combobox
|
- combobox
|
||||||
|
|
@ -56,9 +55,11 @@ Fieldsets are the basis for:
|
||||||
|
|
||||||
<!-- TODO: - [`FormControlMixin`] () -->
|
<!-- TODO: - [`FormControlMixin`] () -->
|
||||||
<!-- TODO: - [`LionField`] () -->
|
<!-- TODO: - [`LionField`] () -->
|
||||||
|
|
||||||
- [Model Value](./docs/ModelValue.md)
|
- [Model Value](./docs/ModelValue.md)
|
||||||
- [Formatting and parsing](./docs/FormattingAndParsing.md)
|
- [Formatting and parsing](./docs/FormattingAndParsing.md)
|
||||||
- [Interaction states](./docs/InteractionStates.md)
|
- [Interaction states](./docs/InteractionStates.md)
|
||||||
- [Validation System](../validate/docs/ValidationSystem.md)
|
- [Validation System](../validate/docs/ValidationSystem.md)
|
||||||
- [Custom Fields](./docs/CustomFieldsTutorial.md)
|
- [Custom Fields](./docs/CustomFieldsTutorial.md)
|
||||||
|
|
||||||
<!-- TODO: - [`FocusMixin`] (/FocusMixin.md) -->
|
<!-- TODO: - [`FocusMixin`] (/FocusMixin.md) -->
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,11 @@
|
||||||
# Creating a custom field
|
# Creating a custom field
|
||||||
|
|
||||||
Custom fields can be created in just a few steps. All you need is an interaction element
|
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)
|
(like for instance a slider, a listbox or a combobox) and connect it to the [Field](../README.md)
|
||||||
functionality.
|
functionality.
|
||||||
|
|
||||||
## Prerequisite: an interaction element
|
## Prerequisite: an interaction element
|
||||||
|
|
||||||
An interaction element provides the means for the end user to enter a certain value, just like
|
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>`).
|
native elements provide in this (think of `<input>`, `<textarea>` and `<select>`).
|
||||||
An example of a non native element is the
|
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.
|
it has a tabindex=“0” applied.
|
||||||
|
|
||||||
## Connecting the interaction element to the field
|
## Connecting the interaction element to the field
|
||||||
|
|
||||||
Now we want to integrate the slider in our form framework to enrich the user interface, get
|
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).
|
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`.
|
We start of by creating a component `<lion-slider>` that extends from `LionField`.
|
||||||
Then we follow the steps below:
|
Then we follow the steps below:
|
||||||
|
|
||||||
- ### 1. Add your interaction element as ‘input slot'
|
- ### 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
|
- ### 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`
|
- ### 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:
|
Steps as described can be implemented with the following javascript:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -52,9 +52,11 @@ Fieldsets are the basis for:
|
||||||
|
|
||||||
<!-- TODO: - [`FormControlMixin`] () -->
|
<!-- TODO: - [`FormControlMixin`] () -->
|
||||||
<!-- TODO: - [`LionField`] () -->
|
<!-- TODO: - [`LionField`] () -->
|
||||||
|
|
||||||
- [Model Value](./ModelValue.md)
|
- [Model Value](./ModelValue.md)
|
||||||
- [Formatting and parsing](./FormattingAndParsing.md)
|
- [Formatting and parsing](./FormattingAndParsing.md)
|
||||||
- [Interaction states](./InteractionStates.md)
|
- [Interaction states](./InteractionStates.md)
|
||||||
- [Validation System](../../validate/docs/ValidationSystem.md)
|
- [Validation System](../../validate/docs/ValidationSystem.md)
|
||||||
- [FieldCustomMixin](./FieldCustomMixin.md)
|
- [FieldCustomMixin](./FieldCustomMixin.md)
|
||||||
|
|
||||||
<!-- TODO: - [`FocusMixin`] (/FocusMixin.md) -->
|
<!-- TODO: - [`FocusMixin`] (/FocusMixin.md) -->
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,12 @@
|
||||||
# FormatMixin
|
# FormatMixin
|
||||||
|
|
||||||
The FormatMixin keeps track of the `modelValue`, `formattedValue` and `serializedValue`.
|
The FormatMixin keeps track of the `modelValue`, `formattedValue` and `serializedValue`.
|
||||||
It is designed to work in conjunction with `LionField`.
|
It is designed to work in conjunction with `LionField`.
|
||||||
|
|
||||||
## Concepts of different values
|
## Concepts of different values
|
||||||
|
|
||||||
### model value
|
### model value
|
||||||
|
|
||||||
The model value is the result of the parser function. It will be stored as `.modelValue`
|
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.
|
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
|
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`.
|
output value of the `LionField`.
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
|
|
||||||
- For a date input: a String '20/01/1999' will be converted to `new Date('1999/01/20')`
|
- 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`
|
- For a number input: a formatted String '1.234,56' will be converted to a Number: `1234.56`
|
||||||
|
|
||||||
### view value
|
### view value
|
||||||
|
|
||||||
The view value is the result of the formatter function.
|
The view value is the result of the formatter function.
|
||||||
It will be stored as `.formattedValue` and synchronized to `.value` (a viewValue setter that
|
It will be stored as `.formattedValue` and synchronized to `.value` (a viewValue setter that
|
||||||
allows to synchronize to `.inputElement`).
|
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.
|
(like error state/validity and whether the a model value was set programatically) also play a role.
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
|
|
||||||
- For a date input, this would be '20/01/1999' (dependent on locale).
|
- 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
|
- For a number input, this could be '1,234.56' (a String representation of modelValue
|
||||||
1234.56)
|
1234.56)
|
||||||
|
|
||||||
### serialized value
|
### serialized value
|
||||||
|
|
||||||
This is the serialized version of the model value.
|
This is the serialized version of the model value.
|
||||||
It exists for maximal compatibility with the platform API.
|
It exists for maximal compatibility with the platform API.
|
||||||
The serialized value can be an interface in context where data binding is not supported
|
The serialized value can be an interface in context where data binding is not supported
|
||||||
and a serialized string needs to be set.
|
and a serialized string needs to be set.
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
|
|
||||||
- For a date input, this would be the iso format of a date, e.g. '1999-01-20'.
|
- 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
|
- For a number input this would be the String representation of a float ('1234.56' instead
|
||||||
of 1234.56)
|
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
|
## Formatters, parsers and (de)serializers
|
||||||
|
|
||||||
In order to create advanced user experiences (automatically formatting a user input or an input
|
In order to create advanced user experiences (automatically formatting a user input or an input
|
||||||
set imperatively by an Application Developer).
|
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.
|
extrapolating the example of a date input.
|
||||||
|
|
||||||
### Formatters
|
### Formatters
|
||||||
|
|
||||||
A formatter should return a `formattedValue`:
|
A formatter should return a `formattedValue`:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
function formatDate(modelValue, options) {
|
function formatDate(modelValue, options) {
|
||||||
if (!(modelValue instanceof Date)) {
|
if (!(modelValue instanceof Date)) {
|
||||||
|
|
@ -58,27 +67,35 @@ function formatDate(modelValue, options) {
|
||||||
return formatDateLocalized(modelValue, options);
|
return formatDateLocalized(modelValue, options);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Notice the options object, which holds a fallback value that shows what should be presented on
|
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
|
screen when the user input resulted in an invalid modelValue
|
||||||
|
|
||||||
### Parsers
|
### Parsers
|
||||||
|
|
||||||
A parser should return a `modelValue`:
|
A parser should return a `modelValue`:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
function parseDate(formattedValue, options) {
|
function parseDate(formattedValue, options) {
|
||||||
return formattedValue === '' ? undefined : parseDateLocalized(formattedValue);
|
return formattedValue === '' ? undefined : parseDateLocalized(formattedValue);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Notice that when it's not possible to create a valid modelValue based on the formattedValue,
|
Notice that when it's not possible to create a valid modelValue based on the formattedValue,
|
||||||
one should return `undefined`.
|
one should return `undefined`.
|
||||||
|
|
||||||
### Serializers and deserializers
|
### Serializers and deserializers
|
||||||
|
|
||||||
A serializer should return a `serializedValue`:
|
A serializer should return a `serializedValue`:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
function serializeDate(modelValue, options) {
|
function serializeDate(modelValue, options) {
|
||||||
return modelValue.toISOString();
|
return modelValue.toISOString();
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
A deserializer should return a `modelValue`:
|
A deserializer should return a `modelValue`:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
function deserializeDate(serializeValue, options) {
|
function deserializeDate(serializeValue, options) {
|
||||||
return new Date(serializeValue);
|
return new Date(serializeValue);
|
||||||
|
|
@ -86,13 +103,15 @@ function deserializeDate(serializeValue, options) {
|
||||||
```
|
```
|
||||||
|
|
||||||
### FieldCustomMixin
|
### FieldCustomMixin
|
||||||
|
|
||||||
When creating your own custom input, please use `FieldCustomMixin` as a basis for this.
|
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
|
Concrete examples can be found at [`<lion-input-date>`](../../input-date) and
|
||||||
[`<lion-input-amount>`](../../input-amount).
|
[`<lion-input-amount>`](../../input-amount).
|
||||||
|
|
||||||
## Flow diagram
|
## Flow diagram
|
||||||
|
|
||||||
The following flow diagram is based on both end user input and interaction programmed by the
|
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.
|
is triggered.
|
||||||
|
|
||||||
[Flow diagram](./formatterParserFlow.svg)
|
[Flow diagram](./formatterParserFlow.svg)
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ Examples:
|
||||||
|
|
||||||
- For a date input, this would be '20/01/1999' (dependent on locale).
|
- 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
|
- For a number input, this could be '1,234.56' (a String representation of modelValue
|
||||||
1234.56)
|
1234.56)
|
||||||
|
|
||||||
### serializedValue
|
### 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 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
|
- For a number input this would be the String representation of a float ('1234.56' instead
|
||||||
of 1234.56)
|
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
|
## Formatters, parsers and (de)serializers
|
||||||
|
|
||||||
|
|
@ -108,7 +108,7 @@ Concrete examples can be found at [`<lion-input-date>`](../../input-date/) and
|
||||||
## Flow diagram
|
## Flow diagram
|
||||||
|
|
||||||
The following flow diagram is based on both end user input and interaction programmed by the
|
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.
|
is triggered.
|
||||||
|
|
||||||
[Flow diagram](./formatterParserFlow.svg)
|
[Flow diagram](./formatterParserFlow.svg)
|
||||||
|
|
|
||||||
|
|
@ -40,14 +40,14 @@ static _isPrefilled(modelValue) {
|
||||||
We show the validity feedback when one of the following conditions is met:
|
We show the validity feedback when one of the following conditions is met:
|
||||||
|
|
||||||
- prefilled:
|
- prefilled:
|
||||||
The user already filled in something, or the value is prefilled
|
The user already filled in something, or the value is prefilled
|
||||||
when the form is initially rendered.
|
when the form is initially rendered.
|
||||||
|
|
||||||
- touched && dirty && !prefilled:
|
- touched && dirty && !prefilled:
|
||||||
When a user starts typing for the first time in a field with for instance `required` validation,
|
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).
|
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`),
|
When a user enters a field without altering the value (making it `dirty` but not `touched`),
|
||||||
an error message shouldn't be shown either.
|
an error message shouldn't be shown either.
|
||||||
|
|
||||||
- submitted:
|
- 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.
|
computed from a modelValue change.
|
||||||
|
|
||||||
## Single source of truth
|
## Single source of truth
|
||||||
|
|
||||||
ModelValues are designed to provide the Application Developer a single way of programmatical
|
ModelValues are designed to provide the Application Developer a single way of programmatical
|
||||||
interaction with the form for an Application Developer.
|
interaction with the form for an Application Developer.
|
||||||
|
|
||||||
### One single concept for Application Developers
|
### One single concept for Application Developers
|
||||||
|
|
||||||
Application Developers need to only care about interacting with the modelValue on a form control
|
Application Developers need to only care about interacting with the modelValue on a form control
|
||||||
level, via:
|
level, via:
|
||||||
|
|
||||||
- `.modelValue`
|
- `.modelValue`
|
||||||
- `@model-value-changed`
|
- `@model-value-changed`
|
||||||
|
|
||||||
> Internal/private concepts like viewValue, formattedValue, serializedValue are therefore not
|
> 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
|
### One single concept for internals
|
||||||
|
|
||||||
Internally, all derived states are computed from model-value-changed events.
|
Internally, all derived states are computed from model-value-changed events.
|
||||||
Since the modelValue is computed 'realtime' and reflects all user interaction, visibility and
|
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
|
validation states, we can guarantee a system that enables the best User Experience
|
||||||
(see Interaction States).
|
(see Interaction States).
|
||||||
|
|
||||||
|
|
||||||
## Unparseable modelValues
|
## Unparseable modelValues
|
||||||
|
|
||||||
A modelValue can demand a certain type (Date, Number, Iban etc.). A correct type will always be
|
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`.
|
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
|
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
|
The Unparseable type is an addition on top of this that mainly is added for the following two
|
||||||
purposes:
|
purposes:
|
||||||
|
|
||||||
- restoring user sessions
|
- restoring user sessions
|
||||||
- realtime updated with all value changes
|
- realtime updated with all value changes
|
||||||
|
|
||||||
### Restoring user sessions
|
### Restoring user sessions
|
||||||
|
|
||||||
As a modelValue is always a single source of truth
|
As a modelValue is always a single source of truth
|
||||||
|
|
||||||
### Realtime updated with all value changes
|
### Realtime updated with all value changes
|
||||||
|
|
||||||
As an Application Developer, you will be notified when a user tries to write the correct type of
|
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.
|
a value. This might be handy for giving feedback to the user.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ Two specific types of fieldsets:
|
||||||
### Installation
|
### Installation
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
npm i --save @lion/fieldset;
|
npm i --save @lion/fieldset
|
||||||
```
|
```
|
||||||
|
|
||||||
```js
|
```js
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
The Form System allows you to create complex forms with various validation in an easy way.
|
The Form System allows you to create complex forms with various validation in an easy way.
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- built in [validate](../validate) for error/warning/info/success
|
- built in [validate](../validate) for error/warning/info/success
|
||||||
- formatting of values
|
- formatting of values
|
||||||
- accessible
|
- accessible
|
||||||
|
|
|
||||||
|
|
@ -28,13 +28,19 @@ import '@lion/form/lion-form.js';
|
||||||
### Example
|
### Example
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<lion-form><form>
|
<lion-form>
|
||||||
<lion-fieldset name="fullName">
|
<form>
|
||||||
<lion-input label="First Name" name="firstName" .modelValue=${model.firstName}></lion-input>
|
<lion-fieldset name="fullName">
|
||||||
<lion-input label="Last Name" name="lastName" .modelValue=${model.lastName}></lion-input>
|
<lion-input label="First Name" name="firstName" .modelValue="${model.firstName}"></lion-input>
|
||||||
</lion-fieldset>
|
<lion-input label="Last Name" name="lastName" .modelValue="${model.lastName}"></lion-input>
|
||||||
<lion-textarea label="Description" name="description" .modelValue=${model.description}></lion-textarea>
|
</lion-fieldset>
|
||||||
</form></lion-form>
|
<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)
|
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:
|
Use it in your lit-html template:
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<lion-icon .svg=${bugSvg}></lion-icon>
|
<lion-icon .svg="${bugSvg}"></lion-icon>
|
||||||
```
|
```
|
||||||
|
|
||||||
### Icon format
|
### 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:
|
You may add an `aria-label` to provide information to visually impaired users:
|
||||||
|
|
||||||
```html
|
```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.
|
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;
|
stroke: lightsteelblue;
|
||||||
}
|
}
|
||||||
</style>
|
</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.
|
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.
|
`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
|
## Features
|
||||||
|
|
||||||
- based on [lion-input](../input)
|
- based on [lion-input](../input)
|
||||||
- makes use of [formatNumber](../localize/docs/number.md) for formatting and parsing.
|
- makes use of [formatNumber](../localize/docs/number.md) for formatting and parsing.
|
||||||
- option to show currency as a suffix
|
- option to show currency as a suffix
|
||||||
|
|
@ -20,7 +21,8 @@
|
||||||
## How to use
|
## How to use
|
||||||
|
|
||||||
### Installation
|
### Installation
|
||||||
```
|
|
||||||
|
```sh
|
||||||
npm i --save @lion/input-amount
|
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.
|
`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
|
## Features
|
||||||
|
|
||||||
- based on [lion-input](../input)
|
- based on [lion-input](../input)
|
||||||
- makes use of [formatDate](../localize/docs/date.md) for formatting and parsing.
|
- makes use of [formatDate](../localize/docs/date.md) for formatting and parsing.
|
||||||
- option to overwrite locale to change the formatting and parsing
|
- option to overwrite locale to change the formatting and parsing
|
||||||
|
|
@ -19,7 +19,8 @@
|
||||||
## How to use
|
## How to use
|
||||||
|
|
||||||
### Installation
|
### Installation
|
||||||
```
|
|
||||||
|
```sh
|
||||||
npm i --save @lion/input-date
|
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).
|
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
|
## Features
|
||||||
|
|
||||||
- input field with a datepicker to help to choose a date
|
- input field with a datepicker to help to choose a date
|
||||||
- based on [lion-input-date](../input-date)
|
- based on [lion-input-date](../input-date)
|
||||||
- makes use of [lion-calendar](../calendar) inside the datepicker
|
- 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
|
## How to use
|
||||||
|
|
||||||
### Installation
|
### Installation
|
||||||
```
|
|
||||||
|
```sh
|
||||||
npm i --save @lion/input-datepicker
|
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.
|
`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
|
## Features
|
||||||
|
|
||||||
- based on [lion-input](../input)
|
- based on [lion-input](../input)
|
||||||
- default label in different languages
|
- default label in different languages
|
||||||
- makes use of email [validators](../validate/docs/DefaultValidators.md) with corresponding error messages 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
|
## How to use
|
||||||
|
|
||||||
### Installation
|
### Installation
|
||||||
```
|
|
||||||
|
```sh
|
||||||
npm i --save @lion/input-email
|
npm i --save @lion/input-email
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -25,8 +26,5 @@ import '@lion/input-email/lion-input-email.js';
|
||||||
### Example
|
### Example
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<lion-input-email
|
<lion-input-email name="email" .errorValidators="${[['required']]}"></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.
|
`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
|
## Features
|
||||||
|
|
||||||
- based on [lion-input](../input)
|
- based on [lion-input](../input)
|
||||||
- default label in different languages
|
- default label in different languages
|
||||||
- makes use of IBAN specific [validate](../validate) with corresponding error messages in different languages
|
- makes use of IBAN specific [validate](../validate) with corresponding error messages in different languages
|
||||||
|
|
@ -14,7 +15,8 @@
|
||||||
## How to use
|
## How to use
|
||||||
|
|
||||||
### Installation
|
### Installation
|
||||||
```
|
|
||||||
|
```sh
|
||||||
npm i --save @lion/input-amount
|
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.
|
`lion-input` component is a webcomponent that enhances the functionality of the native `<input>` element.
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- based on [field](../field/)
|
- based on [field](../field/)
|
||||||
- extra visual elements can be added via `slots`
|
- 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.
|
- **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
|
## How to use
|
||||||
|
|
||||||
### Installation
|
### Installation
|
||||||
```
|
|
||||||
npm i --save @lion/input;
|
```sh
|
||||||
|
npm i --save @lion/input
|
||||||
```
|
```
|
||||||
|
|
||||||
```js
|
```js
|
||||||
|
|
@ -44,6 +46,7 @@ import { maxLengthValidator } from '@lion/validate';
|
||||||
```
|
```
|
||||||
|
|
||||||
Making use of slots:
|
Making use of slots:
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<lion-input name="amount">
|
<lion-input name="amount">
|
||||||
<label slot="label">Amount</label>
|
<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.
|
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.
|
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';
|
import { localize } from '@lion/localize';
|
||||||
// localize is the instance of LocalizeManager
|
// 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
|
## Usage for component developers
|
||||||
|
|
||||||
As a component developer you get:
|
As a component developer you get:
|
||||||
|
|
||||||
- unified data structure for different locales;
|
- unified data structure for different locales;
|
||||||
- promisified helper to load data;
|
- promisified helper to load data;
|
||||||
- notification about page locale changes;
|
- 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`
|
- `/path/to/my-hello-component/translations/en-GB.js`
|
||||||
|
|
||||||
```js
|
```js
|
||||||
export default {
|
export default {
|
||||||
greeting: 'Hello {name}!',
|
greeting: 'Hello {name}!',
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
- `/path/to/my-hello-component/translations/nl-NL.js`
|
- `/path/to/my-hello-component/translations/nl-NL.js`
|
||||||
|
|
||||||
```js
|
```js
|
||||||
export default {
|
export default {
|
||||||
greeting: 'Hallo {name}!',
|
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.
|
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`
|
- `/path/to/my-family-component/translations/en.js`
|
||||||
|
|
||||||
```js
|
```js
|
||||||
export default {
|
export default {
|
||||||
havePartnerQuestion: 'Do you have a partner?',
|
havePartnerQuestion: 'Do you have a partner?',
|
||||||
haveChildrenQuestion: 'Do you have children?',
|
haveChildrenQuestion: 'Do you have children?',
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
- `/path/to/my-family-component/translations/en-GB.js`
|
- `/path/to/my-family-component/translations/en-GB.js`
|
||||||
|
|
||||||
```js
|
```js
|
||||||
import en from './en.js'
|
import en from './en.js';
|
||||||
export default en;
|
export default en;
|
||||||
```
|
```
|
||||||
|
|
||||||
- `/path/to/my-family-component/translations/en-US.js`
|
- `/path/to/my-family-component/translations/en-US.js`
|
||||||
|
|
||||||
```js
|
```js
|
||||||
import en from './en.js'
|
import en from './en.js';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
...en,
|
...en,
|
||||||
haveChildrenQuestion: 'Do you have kids?',
|
haveChildrenQuestion: 'Do you have kids?',
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
To load this data the method `loadNamespace()` which returns a promise can be used.
|
To load this data the method `loadNamespace()` which returns a promise can be used.
|
||||||
|
|
||||||
```javascript
|
```js
|
||||||
localize.loadNamespace(namespace).then(() => {
|
localize.loadNamespace(namespace).then(() => {
|
||||||
// do smth when data is loaded
|
// do smth when data is loaded
|
||||||
});
|
});
|
||||||
|
|
@ -92,58 +93,60 @@ Let's look at both cases in depth.
|
||||||
|
|
||||||
1. Using explicit loader functions:
|
1. Using explicit loader functions:
|
||||||
|
|
||||||
```javascript
|
```js
|
||||||
// use the dynamic import to load static assets
|
// use the dynamic import to load static assets
|
||||||
localize.loadNamespace({
|
localize.loadNamespace({
|
||||||
'my-hello-component': (locale) => {
|
'my-hello-component': locale => {
|
||||||
// resolves to a module with the module.default `{ greeting: 'Hallo {name}!' }`
|
// resolves to a module with the module.default `{ greeting: 'Hallo {name}!' }`
|
||||||
return import(`./translations/${locale}.js`);
|
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.
|
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.
|
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.
|
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.
|
If you want to fetch it from some API this is also possible.
|
||||||
|
|
||||||
```javascript
|
```js
|
||||||
// fetch from an API
|
// fetch from an API
|
||||||
localize.loadNamespace({
|
localize.loadNamespace({
|
||||||
'my-hello-component': async (locale) => {
|
'my-hello-component': async locale => {
|
||||||
const response = await fetch(`http://api.example.com/?namespace=my-hello-component&locale=${locale}`);
|
const response = await fetch(
|
||||||
return response.json(); // resolves to the JSON object `{ greeting: 'Hallo {name}!' }`
|
`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.
|
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.
|
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
|
```js
|
||||||
// using the regexp to match all component names staring with 'my-'
|
// using the regexp to match all component names staring with 'my-'
|
||||||
localize.setupNamespaceLoader(/my-.+/, async (locale, namespace) => {
|
localize.setupNamespaceLoader(/my-.+/, async (locale, namespace) => {
|
||||||
const response = await fetch(`http://api.example.com/?namespace=${namespace}&locale=${locale}`);
|
const response = await fetch(`http://api.example.com/?namespace=${namespace}&locale=${locale}`);
|
||||||
return response.json();
|
return response.json();
|
||||||
});
|
});
|
||||||
|
|
||||||
Promise.all([
|
Promise.all([
|
||||||
localize.loadNamespace('my-hello-component');
|
localize.loadNamespace('my-hello-component');
|
||||||
localize.loadNamespace('my-goodbuy-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 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">`.
|
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.
|
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', () => {
|
localize.addEventListener('localeChanged', () => {
|
||||||
// do smth when data is loaded for a new locale
|
// 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.
|
`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.
|
It expects a key in the format of `namespace:name` and can also receive variables as a second argument.
|
||||||
|
|
||||||
```javascript
|
```js
|
||||||
_onNameChanged() {
|
_onNameChanged() {
|
||||||
// inserts 'Hello John!' into the element with id="name"
|
// inserts 'Hello John!' into the element with id="name"
|
||||||
const name = localize.msg('my-hello-component:greeting', { name: 'John' });
|
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.
|
This mixin was created to significantly simplify integration with LionLitElement.
|
||||||
It provides several capabilities:
|
It provides several capabilities:
|
||||||
|
|
||||||
- automatic loading of specified namespaces;
|
- automatic loading of specified namespaces;
|
||||||
- life-cycle callbacks for localization events;
|
- life-cycle callbacks for localization events;
|
||||||
- alias `_m` for `localize.msg`;
|
- alias `_m` for `localize.msg`;
|
||||||
- promisified alias `_msgAsync` for `localize.msg` resolved when data is loaded.
|
- promisified alias `_msgAsync` for `localize.msg` resolved when data is loaded.
|
||||||
|
|
||||||
```javascript
|
```js
|
||||||
class MyHelloComponent extends LocalizeMixin(LionLitElement) {
|
class MyHelloComponent extends LocalizeMixin(LionLitElement) {
|
||||||
static get localizeNamespaces() {
|
static get localizeNamespaces() {
|
||||||
// using an explicit loader function
|
// 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.
|
This is an extension of LocalizeMixin for usage with LionLitElement and LitRenderMixin.
|
||||||
It provides extra capabilities on top of LocalizeMixin:
|
It provides extra capabilities on top of LocalizeMixin:
|
||||||
|
|
||||||
- smart wrapper `msg` for `localize.msg`;
|
- smart wrapper `msg` for `localize.msg`;
|
||||||
- automatic update of DOM after locale was changed.
|
- 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()`:
|
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() {
|
render() {
|
||||||
return html`
|
return html`
|
||||||
<div>${this.name ? this.msgLit('my-hello-component:greeting', { name: this.name }) : ''}</div>
|
<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
|
## Usage for application developers
|
||||||
|
|
||||||
As an application developer you get:
|
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;
|
- 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;
|
- smart defaults for data loading;
|
||||||
- simple customization of paths where the data is loaded from for common use cases;
|
- 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:
|
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
|
// my-inlined-data.js
|
||||||
import { localize } from 'lion-localize/localize.js';
|
import { localize } from 'lion-localize/localize.js';
|
||||||
localize.addData('en-GB', 'my-namespace', {/* data */});
|
localize.addData('en-GB', 'my-namespace', {
|
||||||
localize.addData('nl-NL', 'my-namespace', {/* data */});
|
/* data */
|
||||||
|
});
|
||||||
|
localize.addData('nl-NL', 'my-namespace', {
|
||||||
|
/* data */
|
||||||
|
});
|
||||||
|
|
||||||
// my-app.js
|
// my-app.js
|
||||||
import './my-inlined-data.js'; // must be on top to be executed before any other code using the data
|
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()`.
|
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.
|
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
|
// for one specific component
|
||||||
localize.setupNamespaceLoader('my-hello-component', async (locale) => {
|
localize.setupNamespaceLoader('my-hello-component', async locale => {
|
||||||
const response = await fetch(`http://api.example.com/?namespace=my-hello-component&locale=${locale}`);
|
const response = await fetch(
|
||||||
|
`http://api.example.com/?namespace=my-hello-component&locale=${locale}`,
|
||||||
|
);
|
||||||
return response.json();
|
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.
|
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
|
## Features
|
||||||
|
|
||||||
- **formatAmountHtml**: returns a formatted amount based on locale to be used in lit-html
|
- **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
|
- **formatAmountHtmlString**: returns a formatted amount based on locale as a string
|
||||||
|
|
||||||
## How to use
|
## How to use
|
||||||
|
|
||||||
### Installation
|
### Installation
|
||||||
```
|
|
||||||
npm i --save @lion/localize;
|
```sh
|
||||||
|
npm i --save @lion/localize
|
||||||
```
|
```
|
||||||
|
|
||||||
### Example
|
### 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.
|
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
|
## Features
|
||||||
|
|
||||||
- **formatDate**: returns a formatted date based on locale
|
- **formatDate**: returns a formatted date based on locale
|
||||||
- **parseDate**: returns a date Object
|
- **parseDate**: returns a date Object
|
||||||
- **getDateFormatBasedOnLocale**: returns the date format based on locale
|
- **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
|
## How to use
|
||||||
|
|
||||||
### Installation
|
### Installation
|
||||||
```
|
|
||||||
npm i --save @lion/localize;
|
```sh
|
||||||
|
npm i --save @lion/localize
|
||||||
```
|
```
|
||||||
|
|
||||||
### Example
|
### Example
|
||||||
|
|
@ -19,12 +21,15 @@ npm i --save @lion/localize;
|
||||||
```js
|
```js
|
||||||
import { parseDate, formatDate } from '@lion/localize';
|
import { parseDate, formatDate } from '@lion/localize';
|
||||||
|
|
||||||
function dateExampleFunction () {
|
function dateExampleFunction() {
|
||||||
const parsedDate = parseDate('21-05-2012');
|
const parsedDate = parseDate('21-05-2012');
|
||||||
const options = {
|
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.
|
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:
|
`LocalizeMixin` has the following features:
|
||||||
|
|
||||||
- Use translated text in your template (`msgLit()`)
|
- Use translated text in your template (`msgLit()`)
|
||||||
- Get the localize namespaces of the component (`localizeNamespaces`)
|
- Get the localize namespaces of the component (`localizeNamespaces`)
|
||||||
- Await loading of localize namespaces (`localizeNamespacesLoaded`)
|
- Await loading of localize namespaces (`localizeNamespacesLoaded`)
|
||||||
|
|
||||||
Advanced:
|
Advanced:
|
||||||
|
|
||||||
- Set whether your component should wait for localize namespaces before rendering your component's template (`waitForLocalizeNamespaces`)
|
- 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
|
- 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()`
|
- Lifecycle methods `onLocaleReady()`, `onLocaleChanged()`, `onLocaleUpdated()`
|
||||||
|
|
||||||
|
|
||||||
## How to use
|
## How to use
|
||||||
|
|
||||||
### In a webcomponent
|
### 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.
|
> 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:
|
An example of the a preconfigured loader:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
static get localizeNamespaces() {
|
static get localizeNamespaces() {
|
||||||
return ['my-hello-component', ...super.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:
|
It is also possible to pass data to your translation:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
render() {
|
render() {
|
||||||
return html`
|
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.
|
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
|
### 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`.
|
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
|
```js
|
||||||
|
|
@ -112,6 +116,7 @@ export function myTemplate(someData) {
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
This template is meant for importing in your webcomponent which uses this localize namespace.
|
This template is meant for importing in your webcomponent which uses this localize namespace.
|
||||||
|
|
||||||
### Translation files
|
### 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:
|
Localization data modules for `my-hello-component` might look like these:
|
||||||
|
|
||||||
|
|
||||||
- `/path/to/my-family-component/translations/en.js`
|
- `/path/to/my-family-component/translations/en.js`
|
||||||
|
|
||||||
```js
|
```js
|
||||||
export default {
|
export default {
|
||||||
havePartnerQuestion: 'Do you have a partner?',
|
havePartnerQuestion: 'Do you have a partner?',
|
||||||
haveChildrenQuestion: 'Do you have children?',
|
haveChildrenQuestion: 'Do you have children?',
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
- `/path/to/my-family-component/translations/en-GB.js`
|
- `/path/to/my-family-component/translations/en-GB.js`
|
||||||
|
|
||||||
```js
|
```js
|
||||||
import en from './en.js'
|
import en from './en.js';
|
||||||
export default en;
|
export default en;
|
||||||
```
|
```
|
||||||
|
|
||||||
- `/path/to/my-family-component/translations/en-US.js`
|
- `/path/to/my-family-component/translations/en-US.js`
|
||||||
|
|
||||||
```js
|
```js
|
||||||
import en from './en.js'
|
import en from './en.js';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
...en,
|
...en,
|
||||||
haveChildrenQuestion: 'Do you have kids?',
|
haveChildrenQuestion: 'Do you have kids?',
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
The module must have a `default` export as shown above to be handled properly.
|
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
|
```js
|
||||||
// fetch from an API
|
// fetch from an API
|
||||||
localize.loadNamespace({
|
localize.loadNamespace({
|
||||||
'my-hello-component': async (locale) => {
|
'my-hello-component': async locale => {
|
||||||
const response = await fetch(`http://api.example.com/?namespace=my-hello-component&locale=${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}!' }`
|
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.
|
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
|
## Features
|
||||||
|
|
||||||
- **formatNumber**: returns a formatted number based on locale
|
- **formatNumber**: returns a formatted number based on locale
|
||||||
- **formatNumberToParts**: returns a formatted number in parts based on locale
|
- **formatNumberToParts**: returns a formatted number in parts based on locale
|
||||||
- **getFractionDigits**: returns the fraction digit for a certain currency
|
- **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
|
## How to use
|
||||||
|
|
||||||
### Installation
|
### Installation
|
||||||
```
|
|
||||||
npm i --save @lion/localize;
|
```sh
|
||||||
|
npm i --save @lion/localize
|
||||||
```
|
```
|
||||||
|
|
||||||
### Example
|
### Example
|
||||||
|
|
@ -21,9 +23,9 @@ npm i --save @lion/localize;
|
||||||
```js
|
```js
|
||||||
import { formatNumber } from '@lion/localize';
|
import { formatNumber } from '@lion/localize';
|
||||||
|
|
||||||
function numberExampleFunction () {
|
function numberExampleFunction() {
|
||||||
const number = 2000;
|
const number = 2000;
|
||||||
const options = { style: 'currency', currency: 'EUR', currencyDisplay: 'code' };
|
const options = { style: 'currency', currency: 'EUR', currencyDisplay: 'code' };
|
||||||
return formatNumber(number, options) // 'EUR 2,000.00' for British locale
|
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.
|
Manages their position on the screen relative to other elements, including other overlays.
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- [**Overlays Manager**](./docs/OverlaysManager.md), a global repository keeping track of all different types of overlays.
|
- [**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:
|
- [**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.
|
- [**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
|
## How to use
|
||||||
|
|
||||||
### Installation
|
### Installation
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
npm i --save @lion/overlays
|
npm i --save @lion/overlays
|
||||||
```
|
```
|
||||||
|
|
||||||
### Example
|
### Example
|
||||||
|
|
||||||
```js
|
```js
|
||||||
import { overlays } from '@lion/overlays';
|
import { overlays } from '@lion/overlays';
|
||||||
|
|
||||||
const myCtrl = overlays.add(
|
const myCtrl = overlays.add(
|
||||||
new OverlayTypeController({
|
new OverlayTypeController({
|
||||||
/* options */
|
/* options */
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
// name OverlayTypeController is for illustration purpose only
|
// name OverlayTypeController is for illustration purpose only
|
||||||
// please read below about existing classes for different types of overlays
|
// 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
|
## How to use
|
||||||
|
|
||||||
### Installation
|
### Installation
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
npm i --save @lion/overlays
|
npm i --save @lion/overlays
|
||||||
```
|
```
|
||||||
|
|
||||||
### Example
|
### Example
|
||||||
|
|
||||||
```js
|
```js
|
||||||
import { overlays } from '@lion/overlays';
|
import { overlays } from '@lion/overlays';
|
||||||
|
|
||||||
const myCtrl = overlays.add(
|
const myCtrl = overlays.add(
|
||||||
new GlobalOverlayController({
|
new GlobalOverlayController({
|
||||||
/* options */
|
/* options */
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
### ModalDialogController
|
### ModalDialogController
|
||||||
|
|
||||||
A specific extension of GlobalOverlayController configured to create accessible modal dialogs.
|
A specific extension of GlobalOverlayController configured to create accessible modal dialogs.
|
||||||
|
|
||||||
```js
|
```js
|
||||||
|
|
|
||||||
|
|
@ -8,21 +8,22 @@ All supported types of local overlays are described below.
|
||||||
## How to use
|
## How to use
|
||||||
|
|
||||||
### Installation
|
### Installation
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
npm i --save @lion/overlays
|
npm i --save @lion/overlays
|
||||||
```
|
```
|
||||||
|
|
||||||
### Example
|
### Example
|
||||||
|
|
||||||
```js
|
```js
|
||||||
import { overlays } from '@lion/overlays';
|
import { overlays } from '@lion/overlays';
|
||||||
|
|
||||||
const myCtrl = overlays.add(
|
const myCtrl = overlays.add(
|
||||||
new LocalOverlayController({
|
new LocalOverlayController({
|
||||||
/* options */
|
/* options */
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
This is currently WIP.
|
This is currently WIP.
|
||||||
Stay tuned for updates on new types of overlays.
|
Stay tuned for updates on new types of overlays.
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,22 @@
|
||||||
# LocalOverlayPositioning
|
# LocalOverlayPositioning
|
||||||
|
|
||||||
## Featuring - [Popper.js](https://popper.js.org/)
|
## 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.
|
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
|
## Features
|
||||||
|
|
||||||
- Everything Popper.js!
|
- 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.
|
- 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.
|
> 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
|
## How to use
|
||||||
|
|
||||||
For installation, see [LocalOverlayController](./LocalOverlayController.md)'s `How to use` section.
|
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):
|
The API for LocalOverlay without Popper looks like this (`overlays` being the OverlayManager singleton):
|
||||||
|
|
||||||
```js
|
```js
|
||||||
const localOverlay = overlays.add(
|
const localOverlay = overlays.add(
|
||||||
new LocalOverlayController({
|
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:
|
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
|
```js
|
||||||
const localOverlay = overlays.add(
|
const localOverlay = overlays.add(
|
||||||
new LocalOverlayController({
|
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.
|
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
|
## 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.
|
- 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.
|
- Default overflow and/or max-width behavior when content is too wide or high for the viewport.
|
||||||
|
|
|
||||||
|
|
@ -1,29 +1,33 @@
|
||||||
# Overlay System: Implementation
|
# Overlay System: Implementation
|
||||||
|
|
||||||
This document provides an outline of all possible occurrences of overlays found in applications in
|
This document provides an outline of all possible occurrences of overlays found in applications in
|
||||||
general and thus provided by Lion.
|
general and thus provided by Lion.
|
||||||
For all concepts referred to in this document, please read [Overlay System Scope](./OverlaySystemScope.md).
|
For all concepts referred to in this document, please read [Overlay System Scope](./OverlaySystemScope.md).
|
||||||
|
|
||||||
## Local and global overlay controllers
|
## Local and global overlay controllers
|
||||||
|
|
||||||
Currently, we have a global and a local overlay controller, as two separate entities.
|
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.
|
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.
|
All of their configuration options will be described below as part of the _Responsive overlay_ section.
|
||||||
|
|
||||||
### Connection points and placement contexts
|
### Connection points and placement contexts
|
||||||
|
|
||||||
It's currently not clear where the border between global and local overlays lie. They seem to be
|
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)).
|
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
|
However, there is no required relationship here: we can create a modal dialog from
|
||||||
local context('page cursor') as well.
|
local context('page cursor') as well.
|
||||||
|
|
||||||
Only, we would have a few concerns when creating global overlays from a local connection point:
|
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
|
- 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
|
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
|
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
|
element with role="dialog". (we basically need to test our supported browsers and screen readers
|
||||||
for compatibility with aria-modal).
|
for compatibility with aria-modal).
|
||||||
- Stacking context need to be managed: the whole 'z-index chain' should win (it's a battle between
|
- 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
|
- 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
|
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.
|
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,
|
For maximum flexibility, it should be up to the developer to decide how overlays should be rendered,
|
||||||
per instance of an overlay.
|
per instance of an overlay.
|
||||||
|
|
||||||
## Responsive overlay
|
### Responsive overlay
|
||||||
|
|
||||||
Based on screen size, we might want to switch the appearance of an 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,
|
For instance: an application menu can be displayed as a dropdown on desktop,
|
||||||
but as a bottom sheet on mobile.
|
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.
|
mentioned.
|
||||||
Note: a more generic and precise term for all mentionings of `invoker` below would actually be
|
Note: a more generic and precise term for all mentionings of `invoker` below would actually be
|
||||||
`relative positioning element`.
|
`relative positioning element`.
|
||||||
```
|
|
||||||
|
```text
|
||||||
- {Element} elementToFocusAfterHide - the element that should be called `.focus()` on after dialog closes
|
- {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} hasBackdrop - whether it should have a backdrop (currently exclusive to globalOverlayController)
|
||||||
- {Boolean} isBlocking - hides other overlays when mutiple are opened (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:
|
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} 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} 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
|
- {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)
|
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)
|
// 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
|
// 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,
|
- {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
|
||||||
|
|
||||||
Controllers/behaviors provide preconfigured configuration objects for the global/local
|
Controllers/behaviors provide preconfigured configuration objects for the global/local
|
||||||
overlay controllers.
|
overlay controllers.
|
||||||
They provide an imperative and very flexible api for creating overlays and should be used by
|
They provide an imperative and very flexible api for creating overlays and should be used by
|
||||||
Subclassers, inside webcomponents.
|
Subclassers, inside webcomponents.
|
||||||
|
|
||||||
#### Dialog
|
### Dialog Controller
|
||||||
|
|
||||||
```js
|
```js
|
||||||
{
|
{
|
||||||
isGlobal: true,
|
isGlobal: true,
|
||||||
|
|
@ -130,7 +140,8 @@ Subclassers, inside webcomponents.
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Tooltip
|
### Tooltip Controller
|
||||||
|
|
||||||
```js
|
```js
|
||||||
{
|
{
|
||||||
isTooltip: true,
|
isTooltip: true,
|
||||||
|
|
@ -139,16 +150,20 @@ Subclassers, inside webcomponents.
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Popover
|
### Popover Controller
|
||||||
|
|
||||||
```js
|
```js
|
||||||
{
|
{
|
||||||
handlesUserInteraction: true,
|
handlesUserInteraction: true,
|
||||||
handlesAccessibility: true,
|
handlesAccessibility: true,
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
#### Dropdown
|
|
||||||
|
### Dropdown Controller
|
||||||
|
|
||||||
It will be quite common to override placement to 'bottom-fullwidth'.
|
It will be quite common to override placement to 'bottom-fullwidth'.
|
||||||
Also, it would be quite common to add a pointerNode.
|
Also, it would be quite common to add a pointerNode.
|
||||||
|
|
||||||
```js
|
```js
|
||||||
{
|
{
|
||||||
placement: 'bottom',
|
placement: 'bottom',
|
||||||
|
|
@ -156,63 +171,79 @@ Also, it would be quite common to add a pointerNode.
|
||||||
handlesAccessibility: true,
|
handlesAccessibility: true,
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
#### Toast
|
|
||||||
|
### Toast Controller
|
||||||
|
|
||||||
TODO:
|
TODO:
|
||||||
|
|
||||||
- add an option for role="alertdialog" ?
|
- add an option for role="alertdialog" ?
|
||||||
- add an option for a 'hide timer' and belonging a11y features for this
|
- add an option for a 'hide timer' and belonging a11y features for this
|
||||||
|
|
||||||
```js
|
```js
|
||||||
{
|
{
|
||||||
...Dialog,
|
...Dialog,
|
||||||
viewportPlacement: 'top-right', (?)
|
viewportPlacement: 'top-right', (?)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
#### Sheet (bottom, top, left, right)
|
|
||||||
|
### Sheet Controller (bottom, top, left, right)
|
||||||
|
|
||||||
```js
|
```js
|
||||||
{
|
{
|
||||||
...Dialog,
|
...Dialog,
|
||||||
viewportPlacement: '{top|bottom|left|right}-fullwidth', (?)
|
viewportPlacement: '{top|bottom|left|right}-fullwidth', (?)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
#### Select
|
|
||||||
|
### Select Controller
|
||||||
|
|
||||||
No need for a config, will probably invoke ResponsiveOverlayCtrl and switches
|
No need for a config, will probably invoke ResponsiveOverlayCtrl and switches
|
||||||
config based on media query from Dropdown to BottomSheet/CenteredDialog
|
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
|
No need for a config, will probably invoke ResponsiveOverlayCtrl and switches
|
||||||
config based on media query from Dropdown to BottomSheet/CenteredDialog
|
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
|
No need for cfg, will probably invoke ResponsiveOverlayCtrl and switches
|
||||||
config based on media query from Dropdown to BottomSheet/CenteredDialog
|
config based on media query from Dropdown to BottomSheet/CenteredDialog
|
||||||
|
|
||||||
|
|
||||||
## Web components
|
## Web components
|
||||||
|
|
||||||
Web components provide a declaritive, developer friendly interface with a prewconfigured styling
|
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
|
that fits the Design System and makes it really easy for Application Developers to build
|
||||||
user interfaces.
|
user interfaces.
|
||||||
Web components should use
|
Web components should use
|
||||||
The ground layers for the webcomponents in Lion are the following:
|
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.
|
Imperative might be better here? We can add a web component later if needed.
|
||||||
|
|
||||||
#### Tooltip
|
### Tooltip Component
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<lion-tooltip>
|
<lion-tooltip>
|
||||||
<button slot="invoker">hover/focus</button>
|
<button slot="invoker">hover/focus</button>
|
||||||
<div slot="content">This will be shown</div>
|
<div slot="content">This will be shown</div>
|
||||||
</lion-tooltip>
|
</lion-tooltip>
|
||||||
```
|
```
|
||||||
#### Popover
|
|
||||||
|
### Popover Component
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<lion-popover>
|
<lion-popover>
|
||||||
<button slot="invoker">click/space/enter</button>
|
<button slot="invoker">click/space/enter</button>
|
||||||
<div slot="content">This will be shown</div>
|
<div slot="content">This will be shown</div>
|
||||||
</lion-popover>
|
</lion-popover>
|
||||||
```
|
```
|
||||||
#### Dropdown
|
|
||||||
|
### Dropdown Component
|
||||||
|
|
||||||
Like the name suggests, the default placement will be button
|
Like the name suggests, the default placement will be button
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<lion-dropdown>
|
<lion-dropdown>
|
||||||
<button slot="invoker">click/space/enter</button>
|
<button slot="invoker">click/space/enter</button>
|
||||||
|
|
@ -223,17 +254,18 @@ Like the name suggests, the default placement will be button
|
||||||
</ul>
|
</ul>
|
||||||
</lion-dropdown>
|
</lion-dropdown>
|
||||||
```
|
```
|
||||||
#### Toast
|
|
||||||
|
|
||||||
Imperative might be better here?
|
### Toast Component
|
||||||
#### Sheet (bottom, top, left, right)
|
|
||||||
|
|
||||||
Imperative might be better here?
|
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
|
Those will be separate web components with a lot of form and a11y logic that will be described
|
||||||
in detail in different sections.
|
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.
|
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.
|
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:
|
As opposed to a single overlay, the overlay manager stores knowledge about:
|
||||||
|
|
||||||
- whether the scroll behaviour of the body element can be manipulated
|
- whether the scroll behaviour of the body element can be manipulated
|
||||||
- what space is available in the window for drawing new overlays
|
- 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
|
The manager is in charge of rendering an overlay to the DOM. Therefore, a developer should be able
|
||||||
to control:
|
to control:
|
||||||
|
|
||||||
- It’s ‘physical position’ (where the dialog is attached). This can either be:
|
- 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
|
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
|
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
|
all surroundings to have aria-hidden="true", will be easier when the overlay is attached on
|
||||||
body level.
|
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
|
(performant) rendering of an overlay next to its invoker on scroll and window resizes
|
||||||
- Toggling of the ‘shown’ state of the overlay
|
- Toggling of the ‘shown’ state of the overlay
|
||||||
- Positioning preferences(for instance ‘bottom-left’) and strategies (ordered fallback preferences)
|
- 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
|
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
|
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
|
## Defining different types of overlays
|
||||||
|
|
||||||
When browsing through the average ui library, one can encounter multiple names for occurrences of
|
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:
|
overlays. Here is a list of names encountered throughout the years:
|
||||||
|
|
||||||
- dialog
|
- dialog
|
||||||
- modal
|
- modal
|
||||||
- popover
|
- 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
|
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:
|
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
|
A great overview of all widget-, structure- and role relations can be found in the ontology diagram
|
||||||
below:
|
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
|
Out of all the overlay names mentioned above, we can only identify the dialog and the tooltip as
|
||||||
official roles.
|
official roles.
|
||||||
|
|
@ -80,57 +83,59 @@ Let’s take a closer look at their definitions...
|
||||||
### Dialog
|
### Dialog
|
||||||
|
|
||||||
The dialog is described as follows by the W3C:
|
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
|
> “A dialog is a window overlaid on either the primary window or another dialog window. Windows
|
||||||
- widget description: https://www.w3.org/TR/wai-aria-practices/#dialog_modal
|
> 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
|
### Tooltip
|
||||||
|
|
||||||
According to W3C, a tooltip is described by the following:
|
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
|
> “A tooltip is a popup that displays information related to an element when the element receives
|
||||||
- widget description: https://www.w3.org/TR/wai-aria-practices/#tooltip
|
> 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
|
What needs to be mentioned is that the W3C taskforce didn’t reach consensus yet about the above
|
||||||
tooltip description. A good alternative resource:
|
tooltip description. A good alternative resource:
|
||||||
https://inclusive-components.design/tooltips-toggletips/
|
<https://inclusive-components.design/tooltips-toggletips/>
|
||||||
|
|
||||||
### Dialog vs tooltip
|
### Dialog vs tooltip
|
||||||
|
|
||||||
Summarizing, the main differences between dialogs and tooltips are:
|
Summarizing, the main differences between dialogs and tooltips are:
|
||||||
|
|
||||||
- Dialogs have a modal option, tooltips don’t
|
- Dialogs have a modal option, tooltips don’t
|
||||||
- Dialogs have interactive content, tooltips don’t
|
- Dialogs have interactive content, tooltips don’t
|
||||||
- Dialogs are opened via regular buttons (click/space/enter), tooltips act on focus/mouseover
|
- Dialogs are opened via regular buttons (click/space/enter), tooltips act on focus/mouseover
|
||||||
|
|
||||||
|
|
||||||
### Other roles and concepts
|
### Other roles and concepts
|
||||||
|
|
||||||
Other roles worth mentioning are *alertdialog* (a specific instance of the dialog for system
|
Other roles worth mentioning are _alertdialog_ (a specific instance of the dialog for system
|
||||||
alerts), select (an abstract role), *combobox* and *menu*.
|
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*,
|
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
|
_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’.
|
’tree’ and ‘dialog’.
|
||||||
|
|
||||||
|
|
||||||
## Common Overlay Components
|
## Common Overlay Components
|
||||||
|
|
||||||
In our component library, we want to have the following overlay ‘child’ components:
|
In our component library, we want to have the following overlay ‘child’ components:
|
||||||
|
|
||||||
- Dialog
|
- Dialog
|
||||||
- Tooltip
|
- Tooltip
|
||||||
- Popover
|
- Popover
|
||||||
|
|
@ -141,77 +146,69 @@ In our component library, we want to have the following overlay ‘child’ comp
|
||||||
- Combobox/autocomplete
|
- Combobox/autocomplete
|
||||||
- Application menu
|
- Application menu
|
||||||
|
|
||||||
### Dialog
|
### Dialog Component
|
||||||
|
|
||||||
The dialog is pretty much the dialog as described in the W3C spec, having the modal option applied
|
The dialog is pretty much the dialog as described in the W3C spec, having the modal option applied
|
||||||
by default.
|
by default.
|
||||||
The flexibility in focus delegation (see https://www.w3.org/TR/wai-aria-practices/#dialog_modal
|
The flexibility in focus delegation (see <https://www.w3.org/TR/wai-aria-practices/#dialog_modal> notes) is not implemented, however.
|
||||||
notes) is not implemented, however.
|
|
||||||
Addressing these:
|
Addressing these:
|
||||||
|
|
||||||
- The first focusable element in the content: although delegate this focus management to the
|
- 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
|
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
|
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.
|
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
|
- 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 Component
|
||||||
### Tooltip
|
|
||||||
|
|
||||||
The tooltip is always invoked on hover and has no interactive content. See
|
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 Component
|
||||||
### Popover
|
|
||||||
|
|
||||||
The popover looks like a crossover between the dialog and the tooltip. Popovers are invoked on
|
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/
|
click. For non interactive content, the <https://inclusive-components.design/tooltips-toggletips/> toggletip could be applied.
|
||||||
toggletip could be applied.
|
|
||||||
Whenever there would be a close button present, the ‘non interactiveness’ wouldn’t apply.
|
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)
|
This looks more like a small dialog, except that the page flow is respected (no rotating tab)
|
||||||
|
|
||||||
|
### Dropdown Component
|
||||||
### Dropdown
|
|
||||||
|
|
||||||
The dropdown is not an official aria-widget and thus can’t be tied to a specific role. It exists
|
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:
|
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)
|
- Preferred position is ‘down’
|
||||||
- Unlike popovers and tooltips, it will never be positioned horizontally
|
- 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.
|
Aliases are ‘popdown’, ‘pulldown’ and many others.
|
||||||
|
|
||||||
|
### Select Component
|
||||||
### Select
|
|
||||||
|
|
||||||
Implemented as a dropdown listbox with invoker button. Depending on the content of the options,
|
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.
|
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 Component
|
||||||
### Combobox
|
|
||||||
|
|
||||||
Implemented as a dropdown combobox with invoker input. Input is used as search filter
|
Implemented as a dropdown combobox with invoker input. Input is used as search filter
|
||||||
and can contain autocomplete or autosuggest functionality:
|
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 Component
|
||||||
### (Application) menu
|
|
||||||
|
|
||||||
Or sometimes called context-menu. Uses a dropdown to position its content.
|
Or sometimes called context-menu. Uses a dropdown to position its content.
|
||||||
See: https://www.w3.org/WAI/tutorials/menus/flyout/
|
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/
|
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.
|
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.
|
global(modal) dialog.
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,9 @@
|
||||||
You should use [lion-radio](../radio/)'s inside this element.
|
You should use [lion-radio](../radio/)'s inside this element.
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
Since it extends from [lion-fieldset](../fieldset/), it has all the features a fieldset has.
|
Since it extends from [lion-fieldset](../fieldset/), it has all the features a fieldset has.
|
||||||
|
|
||||||
- Get or set the checked value of the group:
|
- Get or set the checked value of the group:
|
||||||
- modelValue (default) - `checkedValue()`
|
- modelValue (default) - `checkedValue()`
|
||||||
- formattedValue - `formattedValue()`
|
- formattedValue - `formattedValue()`
|
||||||
|
|
@ -16,7 +18,8 @@ Since it extends from [lion-fieldset](../fieldset/), it has all the features a f
|
||||||
## How to use
|
## How to use
|
||||||
|
|
||||||
### Installation
|
### Installation
|
||||||
```
|
|
||||||
|
```sh
|
||||||
npm i --save @lion/radio @lion/radio-group
|
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.
|
`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
|
## Features
|
||||||
|
|
||||||
- Get or set the checked state (boolean) - `choiceChecked()`
|
- Get or set the checked state (boolean) - `choiceChecked()`
|
||||||
- Get or set the value of the choice - `choiceValue()`
|
- Get or set the value of the choice - `choiceValue()`
|
||||||
- Pre-select an option by setting the `checked` boolean attribute
|
- Pre-select an option by setting the `checked` boolean attribute
|
||||||
|
|
@ -12,8 +13,9 @@
|
||||||
## How to use
|
## How to use
|
||||||
|
|
||||||
### Installation
|
### Installation
|
||||||
```
|
|
||||||
npm i --save @lion/radio;
|
```sh
|
||||||
|
npm i --save @lion/radio
|
||||||
```
|
```
|
||||||
|
|
||||||
```js
|
```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.
|
usability for keyboard and screen reader users.
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- catches and forwards the select events
|
- catches and forwards the select events
|
||||||
- can be set to required or disabled
|
- can be set to required or disabled
|
||||||
|
|
||||||
## How to use
|
## How to use
|
||||||
|
|
||||||
### Installation
|
### Installation
|
||||||
```
|
|
||||||
|
```sh
|
||||||
npm i --save @lion/select
|
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.
|
You can preselect an option by setting the property modelValue.
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<lion-select
|
<lion-select name="favoriteColor" .modelValue="${'<value of option 2>'}">
|
||||||
name="favoriteColor"
|
|
||||||
.modelValue="${'<value of option 2>'}"
|
|
||||||
>
|
|
||||||
...
|
...
|
||||||
</lion-select>
|
</lion-select>
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
`lion-steps` breaks a single goal down into dependable sub-tasks.
|
`lion-steps` breaks a single goal down into dependable sub-tasks.
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- navigate between different steps with 'previous' and 'next' functions.
|
- navigate between different steps with 'previous' and 'next' functions.
|
||||||
- keeps status of each step
|
- keeps status of each step
|
||||||
- untouched
|
- untouched
|
||||||
|
|
@ -21,7 +22,8 @@ In many application you build multi-step workflows like multi-step forms where y
|
||||||
## How to use
|
## How to use
|
||||||
|
|
||||||
### Installation
|
### Installation
|
||||||
```
|
|
||||||
|
```sh
|
||||||
npm i --save @lion/select
|
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`:
|
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() {
|
next() {
|
||||||
return this.$id('steps').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-steps>
|
||||||
<lion-step>preliminary step</lion-step>
|
<lion-step>preliminary step</lion-step>
|
||||||
<lion-step forward-only>data is loaded and next() is called automatically afterwards</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>
|
</lion-steps>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,8 +24,5 @@ import '@lion/textarea/lion-textarea.js';
|
||||||
### Example
|
### Example
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<lion-textarea
|
<lion-textarea label="Stops growing after 4 rows" max-rows="4"></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.
|
> 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
|
### Example
|
||||||
|
|
||||||
|
|
@ -42,7 +42,8 @@ import '@lion/input/lion-input.js';
|
||||||
import { isString, maxLengthValidator, defaultOkValidator } from '@lion/validate';
|
import { isString, maxLengthValidator, defaultOkValidator } from '@lion/validate';
|
||||||
|
|
||||||
const isInitialsRegex = /^([A-Z]\.)+$/;
|
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 = () => [
|
export const isExampleInitialsValidator = () => [
|
||||||
(...params) => ({ isExampleInitials: isExampleInitials(...params) }),
|
(...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.
|
optionally an additional configuration object.
|
||||||
|
|
||||||
```js
|
```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
|
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
|
```html
|
||||||
<validatable-el
|
<validatable-el
|
||||||
.errorValidators="${[[ myValidatorFunction, { myParam: 'foo' }, { extra: 'options' } ]]}">
|
.errorValidators="${[[ myValidatorFunction, { myParam: 'foo' }, { extra: 'options' } ]]}"
|
||||||
</validatable-el>
|
></validatable-el>
|
||||||
```
|
```
|
||||||
|
|
||||||
As you can see the 'errorValidators' property expects a map (an array of arrays).
|
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
|
```html
|
||||||
<validatable-el
|
<validatable-el
|
||||||
.errorValidators="${[minLengthValidator({ min: 3 }), isZipCodeValidator()]}">
|
.errorValidators="${[minLengthValidator({ min: 3 }), isZipCodeValidator()]}"
|
||||||
</validatable-el>
|
></validatable-el>
|
||||||
```
|
```
|
||||||
|
|
||||||
### Default Validators
|
### Default Validators
|
||||||
|
|
@ -112,8 +112,8 @@ The api for warning validators and info validators are as follows:
|
||||||
```html
|
```html
|
||||||
<validatable-field
|
<validatable-field
|
||||||
.warningValidators="${[myWarningValidator()]}"
|
.warningValidators="${[myWarningValidator()]}"
|
||||||
.infoValidators="${[myInfoValidator()]}">
|
.infoValidators="${[myInfoValidator()]}"
|
||||||
</validatable-field>
|
></validatable-field>
|
||||||
```
|
```
|
||||||
|
|
||||||
### Success validators
|
### Success validators
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue