lion/packages/fieldset/stories/index.stories.mdx
Thomas Allmer 89b835a799 feat: improved storybook demos
Co-authored-by: Joren Broekema <Joren.Broekema@ing.com>
Co-authored-by: Alex Ghiu <Alex.Ghiu@ing.com>
Co-authored-by: Thijs Louisse <Thijs.Louisse@ing.com>
2020-01-13 13:58:03 +01:00

417 lines
12 KiB
Text

import { Story, Meta, html } from '@open-wc/demoing-storybook';
import '@lion/input/lion-input.js';
import { localize } from '@lion/localize';
import { loadDefaultFeedbackMessages, MinLength, Validator, Required } from '@lion/validate';
import '../lion-fieldset.js';
import './helpers/demo-fieldset-child.js';
<Meta title="Forms/Fieldset" parameters={{ component: 'lion-fieldset' }} />
# Fieldset
`lion-fieldset` groups multiple input fields or other fieldsets together.
We have three specific fieldset implementations:
- [lion-form](?path=/docs/forms-form)
- [lion-checkbox-group](?path=/docs/forms-checkbox-group)
- [lion-radio-group](?path=/docs/forms-radio-group)
<Story name="Default">
{html`
<style>
lion-fieldset {
margin-top: 20px;
}
</style>
<lion-fieldset name="nameGroup" label="Name">
<demo-fieldset-child name="FirstName" label="First Name"></demo-fieldset-child>
<demo-fieldset-child name="LastName" label="Last Name"></demo-fieldset-child>
</lion-fieldset>
`}
</Story>
```html
<lion-fieldset name="nameGroup" label="Name">
<demo-fieldset-child name="FirstName" label="First Name"></demo-fieldset-child>
<demo-fieldset-child name="LastName" label="Last Name"></demo-fieldset-child>
</lion-fieldset>
```
A native fieldset element should always have a legend-element for a11y purposes.
However, our fieldset element is not native and should not have a legend-element.
Our fieldset instead has a label attribute or you can add a label with a div- or heading-element using `slot="label"`.
## Features
- Easy retrieval of form data based on field names
- Advanced user interaction scenarios via [interaction states](?path=/docs/forms-system-interaction-states)
- Can have [validate](?path=/docs/forms-system-validate-system) on fieldset level and shows the validation feedback below the fieldset
- Can disable input fields on fieldset level
- Accessible out of the box
## Examples
### With Data
The fieldset's modelValue is an `Object` containing properties where the key is the `name` attribute of the field,
and the value is the `modelValue` of the field.
<Story name="Data">
{html`
<lion-fieldset name="nameGroup" label="Name">
<demo-fieldset-child name="firstName" label="First Name" .modelValue=${'Foo'}></demo-fieldset-child>
<demo-fieldset-child name="lastName" label="Last Name" .modelValue=${'Bar'}></demo-fieldset-child>
<button @click=${ev => console.log(ev.target.parentElement.modelValue)}>
Log to Action Logger
</button>
</lion-fieldset>
`}
</Story>
```html
<lion-fieldset name="nameGroup" label="Name">
<demo-fieldset-child name="firstName" label="First Name" .modelValue=${'Foo'}></demo-fieldset-child>
<demo-fieldset-child name="lastName" label="Last Name" .modelValue=${'Bar'}></demo-fieldset-child>
<button @click=${ev => console.log(ev.target.parentElement.modelValue)}>
Log to Action Logger
</button>
</lion-fieldset>
```
### Disabled
Disabling a fieldset disables all its child fields.
When enabling a fieldset, fields that have disabled explicitly set will stay disabled.
<Story name="Disabled">
{() => {
function toggleDisabled() {
const fieldset = document.querySelector('#fieldset');
fieldset.disabled = !fieldset.disabled;
}
return html`
<lion-fieldset name="nameGroup" label="Name" id="fieldset" disabled>
<demo-fieldset-child name="FirstName" label="First Name" .modelValue=${'Foo'}></demo-fieldset-child>
<demo-fieldset-child name="LastName" label="Last Name" .modelValue=${'Bar'}></demo-fieldset-child>
<lion-fieldset name="nameGroup2" label="Name">
<demo-fieldset-child
name="FirstName2"
label="First Name"
.modelValue=${'Foo'}
disabled
></demo-fieldset-child>
<demo-fieldset-child name="LastName2" label="Last Name" .modelValue=${'Bar'}></demo-fieldset-child>
</lion-fieldset>
</lion-fieldset>
<button @click=${toggleDisabled}>
Toggle disabled
</button>
`;
}}
</Story>
```js
function toggleDisabled() {
const fieldset = document.querySelector('#fieldset');
fieldset.disabled = !fieldset.disabled;
}
```
```html
<lion-fieldset name="nameGroup" label="Name" id="fieldset" disabled>
<demo-fieldset-child name="FirstName" label="First Name" .modelValue=${'Foo'}></demo-fieldset-child>
<demo-fieldset-child name="LastName" label="Last Name" .modelValue=${'Bar'}></demo-fieldset-child>
<lion-fieldset name="nameGroup2" label="Name">
<demo-fieldset-child
name="FirstName2"
label="First Name"
.modelValue=${'Foo'}
disabled
></demo-fieldset-child>
<demo-fieldset-child name="LastName2" label="Last Name" .modelValue=${'Bar'}></demo-fieldset-child>
</lion-fieldset>
</lion-fieldset>
<button @click=${toggleDisabled}>
Toggle disabled
</button>
```
### Nesting fieldsets
Fieldsets can also be nested. The level of nesting will correspond one to one with the `modelValue` object.
<Story name="Nesting fieldsets">
{html`
<lion-fieldset>
<div slot="label">Personal data</div>
<lion-fieldset name="nameGroup" label="Name">
<demo-fieldset-child name="FirstName" label="First Name" .modelValue=${'Foo'}></demo-fieldset-child>
<demo-fieldset-child name="LastName" label="Last Name" .modelValue=${'Bar'}></demo-fieldset-child>
</lion-fieldset>
<lion-fieldset name="location" label="Location">
<demo-fieldset-child name="country" label="Country" .modelValue=${'Netherlands'}></demo-fieldset-child>
</lion-fieldset>
<demo-fieldset-child name="age" label="Age" .modelValue=${21}></demo-fieldset-child>
<button @click=${ev => console.log(ev.target.parentElement.modelValue)}>
Log everything to Action Logger
</button>
<br />
<button
@click=${ev => console.log(ev.target.parentElement.formElements.nameGroup.modelValue)}
>
Log only Name fieldset to Action Logger
</button>
</lion-fieldset>
`}
</Story>
```html
<lion-fieldset>
<div slot="label">Personal data</div>
<lion-fieldset name="nameGroup" label="Name">
<demo-fieldset-child name="FirstName" label="First Name" .modelValue=${'Foo'}></demo-fieldset-child>
<demo-fieldset-child name="LastName" label="Last Name" .modelValue=${'Bar'}></demo-fieldset-child>
</lion-fieldset>
<lion-fieldset name="location" label="Location">
<demo-fieldset-child name="country" label="Country" .modelValue=${'Netherlands'}></demo-fieldset-child>
</lion-fieldset>
<demo-fieldset-child name="age" label="Age" .modelValue=${21}></demo-fieldset-child>
<button @click=${ev => console.log(ev.target.parentElement.modelValue)}>
Log everything to Action Logger
</button>
<br />
<button
@click=${ev => console.log(ev.target.parentElement.formElements.nameGroup.modelValue)}
>
Log only Name fieldset to Action Logger
</button>
</lion-fieldset>
```
## Validation
You can create validators that work on a fieldset level.
Below, we mimic a `required` validator, but on the fieldset.
Try it by typing something in the input, then removing it.
<Story name="Validation">
{() => {
const DemoValidator = class extends Validator {
constructor() {
super();
this.name = 'DemoValidator';
}
execute(value) {
if (value && value.input1) {
return false; // el.hasError = true
}
return true;
}
static async getMessage() {
return '[Fieldset Error] Demo error message';
}
};
return html`
<lion-fieldset id="someId" .validators="${[new DemoValidator()]}">
<demo-fieldset-child name="input1" label="Label"></demo-fieldset-child>
</lion-fieldset>
`;
}}
</Story>
```js
const DemoValidator = class extends Validator {
constructor() {
super();
this.name = 'DemoValidator';
}
execute(value) {
if (value && value.input1) {
return false;
}
return true;
}
static async getMessage() {
return '[Fieldset Error] Demo error message';
}
};
```
```html
<lion-fieldset id="someId" .validators="${[new DemoValidator()]}">
<demo-fieldset-child name="input1" label="Label"></demo-fieldset-child>
</lion-fieldset>
```
### Validating multiple inputs in a fieldset
You can have your fieldset validator take into consideration multiple fields.
<Story name="Validating 2 fields">
{() => {
const IsCatsAndDogs = class extends Validator {
constructor() {
super();
this.name = 'IsCatsAndDogs';
}
execute(value) {
return !(value.input1 === 'cats' && value.input2 === 'dogs');
}
static async getMessage() {
return '[Fieldset Error] Input 1 needs to be "cats" and Input 2 needs to be "dogs"';
}
};
return html`
<lion-fieldset .validators="${[new IsCatsAndDogs()]}">
<demo-fieldset-child
label="An all time YouTube favorite"
name="input1"
help-text="cats"
>
</demo-fieldset-child>
<demo-fieldset-child
label="Another all time YouTube favorite"
name="input2"
help-text="dogs"
>
</demo-fieldset-child>
</lion-fieldset>
`;
}}
</Story>
```js
const IsCatsAndDogs = class extends Validator {
constructor() {
super();
this.name = 'IsCatsAndDogs';
}
execute(value) {
return !(value.input1 === 'cats' && value.input2 === 'dogs');
}
static async getMessage() {
return '[Fieldset Error] Input 1 needs to be "cats" and Input 2 needs to be "dogs"';
}
};
```
```html
<lion-fieldset .validators="${[new IsCatsAndDogs()]}">
<demo-fieldset-child
label="An all time YouTube favorite"
name="input1"
help-text="cats"
>
</demo-fieldset-child>
<demo-fieldset-child
label="Another all time YouTube favorite"
name="input2"
help-text="dogs"
>
</demo-fieldset-child>
</lion-fieldset>
```
Alternatively you can also let the fieldset validator be dependent on the error states of its child fields.
Simply loop over the formElements inside your Validator's `execute` method:
```js
this.formElementsArray.some(el => el.hasFeedbackFor.includes('error'));
```
### Validating multiple fieldsets
You can have your fieldset validator take into accounts multiple nested fieldsets.
<Story name="Validating 2 fieldsets">
{() => {
const IsCatsDogs = class extends Validator {
constructor() {
super();
this.name = 'IsCatsDogs';
}
execute(value) {
if ((value.inner1 && value.inner1.input1 === 'cats') &&
(value.inner2 && value.inner2.input1 === 'dogs')
) {
return false;
}
return true;
}
static async getMessage() {
return 'There is a problem with one of your fieldsets';
}
};
return html`
<lion-fieldset name="outer" .validators=${[new IsCatsDogs()]}>
<lion-fieldset name="inner1">
<label slot="label">Fieldset no. 1</label>
<demo-fieldset-child
label="Write 'cats' here"
name="input1"
>
</demo-fieldset-child>
</lion-fieldset>
<hr />
<lion-fieldset name="inner2">
<label slot="label">Fieldset no. 2</label>
<demo-fieldset-child
label="Write 'dogs' here"
name="input1"
>
</demo-fieldset-child>
</lion-fieldset>
</lion-fieldset>
`;
}}
</Story>
```js
const IsCatsDogs = class extends Validator {
constructor() {
super();
this.name = 'IsCatsDogs';
}
execute(value) {
if ((value.inner1 && value.inner1.input1 === 'cats') &&
(value.inner2 && value.inner2.input1 === 'dogs')
) {
return false;
}
return true;
}
static async getMessage() {
return 'There is a problem with one of your fieldsets';
}
};
```
```html
<lion-fieldset name="outer" .validators="${[new IsCatsDogs()]}">
<lion-fieldset name="inner1">
<label slot="label">Fieldset no. 1</label>
<demo-fieldset-child
label="Write 'cats' here"
name="input1"
>
</demo-fieldset-child>
</lion-fieldset>
<hr />
<lion-fieldset name="inner2">
<label slot="label">Fieldset no. 2</label>
<demo-fieldset-child
label="Write 'dogs' here"
name="input1"
>
</demo-fieldset-child>
</lion-fieldset>
</lion-fieldset>
```