chore(field): custom fields tutorial
This commit is contained in:
parent
d5e2dfe38e
commit
6a0579cd91
3 changed files with 114 additions and 29 deletions
|
|
@ -1,53 +1,64 @@
|
||||||
|
|
||||||
# Form Fundaments
|
# Form Fundaments
|
||||||
|
|
||||||
[//]: # (AUTO INSERT HEADER PREPUBLISH)
|
[//]: # (AUTO INSERT HEADER PREPUBLISH)
|
||||||
|
|
||||||
Fields are the most fundamental building block of the Form System. They are the basis of
|
`Form control`s are the most fundamental building block of the Forms. They are the basis of
|
||||||
both `field`s and `fieldset`s.
|
both `field`s and `fieldset`s, and the `form` itself.
|
||||||
|
|
||||||
|
## Fields
|
||||||
|
|
||||||
## What are fields?
|
|
||||||
Fields are the actual form controls the end user interacts with.
|
Fields are the actual form controls the end user interacts with.
|
||||||
They extend the `LionField` class, which on its turn uses the `FormControlMixin`.
|
They extend the `Field` class, which on its turn uses the `FormControlMixin`.
|
||||||
Fields provide a normalized, predictable API for platform components and customly made form controls.
|
Fields provide a normalized, predictable API for platform components and custom made form controls.
|
||||||
On top of this, they feature:
|
On top of this, they feature:
|
||||||
|
|
||||||
- data synchronization with models
|
- data synchronization with models
|
||||||
- formatting of view values
|
- formatting of view values
|
||||||
- advanced validation possibilities
|
- advanced validation possibilities
|
||||||
- creation of advanced user interaction scenarios via `interaction states`
|
- creation of advanced user interaction scenarios via `interaction states`
|
||||||
- provision of labels, help texts in an easy, declaritive manner
|
- provision of labels and help texts in an easy, declarative manner
|
||||||
- better focus management
|
- better focus management
|
||||||
- accessibility out of the box
|
- accessibility out of the box
|
||||||
- advanced styling possibilities: map your own Design System to the internal HTML structure
|
- advanced styling possibilities: map your own Design System to the internal HTML structure
|
||||||
|
|
||||||
### Platform wrappers
|
### Platform fields (wrappers)
|
||||||
- `LionInput`, a wrapper for `<input>`
|
|
||||||
- `LionTextarea`, a wrapper for `<textarea>`
|
- [`LionInput`](../input/), a wrapper for `<input>`
|
||||||
- `LionSelect`, a wrapper for `<select>`
|
- [`LionTextarea`](../textarea/), a wrapper for `<textarea>`
|
||||||
|
- [`LionSelect`](../select/), a wrapper for `<select>`
|
||||||
|
- [`LionRadio`](../radio/), a wrapper for `<input type="radio">`
|
||||||
|
- [`LionCheckbox`](../checkbox/), a wrapper for `<input type="checkbox">`
|
||||||
|
|
||||||
|
### Custom fields (wrappers)
|
||||||
|
|
||||||
|
Whenever a native form control doesn't exist or is not sufficient, a
|
||||||
|
[custom form field](./docs/CustomFieldsTutorial.md) should be created. One could think of components
|
||||||
|
like:
|
||||||
|
|
||||||
### Custom wrappers
|
|
||||||
Whenever a native form control doesn't exist or is not sufficient, a custom form control should
|
|
||||||
be created. One could think of components like:
|
|
||||||
- slider
|
- slider
|
||||||
- combobox
|
- combobox
|
||||||
- autocomplete
|
- autocomplete
|
||||||
- etc...
|
- etc...
|
||||||
|
|
||||||
## What are fieldsets?
|
## Fieldsets
|
||||||
|
|
||||||
Fieldsets are groups of fields. They can be considered fields on their own as well, since they
|
Fieldsets are groups of fields. They can be considered fields on their own as well, since they
|
||||||
partly share the normalized api via `FormControlMixin`.
|
partly share the normalized api via `FormControlMixin`.
|
||||||
Fieldsets are the basis for:
|
Fieldsets are the basis for:
|
||||||
- `LionFieldset`
|
|
||||||
- `LionForm`
|
|
||||||
- `LionRadioGroup`
|
|
||||||
- `LionCheckboxGroup`
|
|
||||||
|
|
||||||
|
- [`LionFieldset`](../fieldset/)
|
||||||
|
- [`LionForm`](../form/)
|
||||||
|
- [`LionRadioGroup`](../radio-group/)
|
||||||
|
- [`LionCheckboxGroup`](../checkbox-group/)
|
||||||
|
|
||||||
# Other Resources
|
## Other Resources
|
||||||
- `FormControlMixin` (TODO: document)
|
|
||||||
- `LionField` (TODO: document)
|
<!-- TODO: - [`FormControlMixin`] () -->
|
||||||
- [`Model values`](./docs/modelValue.md)
|
<!-- TODO: - [`LionField`] () -->
|
||||||
- [`FormatMixin`](./docs/FormatMixin.md)
|
- [Model Value](./docs/ModelValue.md)
|
||||||
- `InteractionStateMixin` (TODO: document)
|
- [Formatting and parsing](./docs/FormattingAndParsing.md)
|
||||||
- `ValidateMixin` (TODO: document)
|
- [Interaction states](./docs/InteractionStates.md)
|
||||||
- `FocusMixin` (TODO: document)
|
- [Validation System](../validate/docs/ValidationSystem.md)
|
||||||
- `FieldCustomMixin` (TODO: document)
|
- [Custom Fields](./docs/CustomFieldsTutorial.md)
|
||||||
|
<!-- TODO: - [`FocusMixin`] (/FocusMixin.md) -->
|
||||||
|
|
|
||||||
76
packages/field/docs/CustomFieldsTutorial.md
Normal file
76
packages/field/docs/CustomFieldsTutorial.md
Normal file
|
|
@ -0,0 +1,76 @@
|
||||||
|
# Creating a custom field
|
||||||
|
Custom fields can be created in just a few steps. All you need is an interaction element
|
||||||
|
(like for instance a slider, a listbox or a combobox) and connect it to the [Field](../README.md)
|
||||||
|
functionality.
|
||||||
|
|
||||||
|
## Prerequisite: an interaction element
|
||||||
|
An interaction element provides the means for the end user to enter a certain value, just like
|
||||||
|
native elements provide in this (think of `<input>`, `<textarea>` and `<select>`).
|
||||||
|
An example of a non native element is the
|
||||||
|
[slider design pattern](https://www.w3.org/TR/2017/NOTE-wai-aria-practices-1.1-20171214/#slider)
|
||||||
|
described here.
|
||||||
|
|
||||||
|
For this tutorial, we assume we have a component `<my-slider>` that exposes its value via property
|
||||||
|
`mySliderValue` and sends an event `my-slider-changed` on every value change. To make it focusable,
|
||||||
|
it has a tabindex=“0” applied.
|
||||||
|
|
||||||
|
## Connecting the interaction element to the field
|
||||||
|
Now we want to integrate the slider in our form framework to enrich the user interface, get
|
||||||
|
validation support and get all the other [benefits of LionField](../README.md).
|
||||||
|
We start of by creating a component `<lion-slider>` that extends from `LionField`.
|
||||||
|
Then we follow the steps below:
|
||||||
|
|
||||||
|
- ### 1. Add your interaction element as ‘input slot'
|
||||||
|
Here you return the element the user interacts with. By configuring it as a slot, it will end up
|
||||||
|
in light DOM, ensuring the best accessibility for the end user.
|
||||||
|
|
||||||
|
- ### 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.
|
||||||
|
|
||||||
|
- ### 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.
|
||||||
|
|
||||||
|
|
||||||
|
Steps as described can be implemented with the following javascript:
|
||||||
|
|
||||||
|
```js
|
||||||
|
import { LionField } from '@lion/field';
|
||||||
|
import './my-slider.js';
|
||||||
|
|
||||||
|
export class LionSlider extends LionField {
|
||||||
|
// 1. Add your interaction element as ‘input slot'
|
||||||
|
get slots() {
|
||||||
|
return {
|
||||||
|
...super.slots,
|
||||||
|
input: () => document.createElement(‘my-slider’),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Proxy event `my-slider-changed` to `user-input-changed` event
|
||||||
|
connectedCallback() {
|
||||||
|
super.connectedCallback();
|
||||||
|
this.addEventListener('my-slider-changed', this._proxyChangeEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
_proxyChangeEvent() {
|
||||||
|
this.inputElement.dispatchEvent(
|
||||||
|
new CustomEvent('user-input-changed', { bubbles: true, composed: true }),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Proxy property `<my-slider>.mySliderValue` to `<lion-slider>.value`
|
||||||
|
get value() {
|
||||||
|
return this.$$slot('input').mySliderValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
set value(newV) {
|
||||||
|
this.$$slot('input').mySliderValue = newV;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
That was all. Now you can enhance your slider by writing custom validators for it
|
||||||
|
or by writing a parser to get a custom modelValue type.
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
# FieldCustomMixin
|
|
||||||
TODO: document
|
|
||||||
Loading…
Reference in a new issue