Skip to content

Commit

Permalink
feat(sbb-slider): implement native form support (#3071)
Browse files Browse the repository at this point in the history
  • Loading branch information
TomMenga authored Sep 26, 2024
1 parent a886b4f commit ad35f2f
Show file tree
Hide file tree
Showing 9 changed files with 493 additions and 208 deletions.
12 changes: 6 additions & 6 deletions src/elements/checkbox/common/checkbox-common.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ describe(`checkbox common behaviors`, () => {
expect(snapshot.required).not.to.be.ok;
});

it('should should restore form state on formStateRestoreCallback()', async () => {
it('should restore form state on formStateRestoreCallback()', async () => {
// Mimic tab restoration. Does not test the full cycle as we can not set the browser in the required state.
element.formStateRestoreCallback('true', 'restore');
await waitForLitRender(element);
Expand Down Expand Up @@ -537,11 +537,11 @@ describe(`checkbox common behaviors`, () => {
expect(element).not.to.have.attribute('disabled');
}

const disabledElements = Array.from(form.querySelectorAll(':disabled'));

expect(disabledElements.includes(element), ':disabled selector').to.be.equal(
assertions.disabledSelector,
);
if (assertions.disabledSelector) {
expect(element).to.match(':disabled');
} else {
expect(element).not.to.match(':disabled');
}

const snapshot = (await a11ySnapshot({
selector: element.localName,
Expand Down
133 changes: 109 additions & 24 deletions src/elements/slider/__snapshots__/slider.snapshot.spec.snap.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,7 @@ export const snapshots = {};

snapshots["sbb-slider renders DOM"] =
`<sbb-slider
aria-valuemax="100"
aria-valuemin="0"
aria-valuenow="1"
name=""
role="slider"
id="slider-1"
tabindex="0"
value="1"
>
Expand Down Expand Up @@ -48,14 +44,9 @@ snapshots["sbb-slider renders Shadow DOM"] =

snapshots["sbb-slider renders with properties DOM"] =
`<sbb-slider
aria-valuemax="500"
aria-valuemin="0"
aria-valuenow="100"
end-icon="walk-fast-small"
max="500"
min="0"
name=""
role="slider"
start-icon="walk-slow-small"
tabindex="0"
value="100"
Expand Down Expand Up @@ -111,17 +102,12 @@ snapshots["sbb-slider renders with properties Shadow DOM"] =

snapshots["sbb-slider renders disabled DOM"] =
`<sbb-slider
aria-disabled="true"
aria-valuemax="500"
aria-valuemin="0"
aria-valuenow="100"
disabled=""
end-icon="walk-fast-small"
max="500"
min="0"
name=""
role="slider"
start-icon="walk-slow-small"
tabindex="0"
value="100"
>
</sbb-slider>
Expand Down Expand Up @@ -176,16 +162,10 @@ snapshots["sbb-slider renders disabled Shadow DOM"] =

snapshots["sbb-slider renders readonly DOM"] =
`<sbb-slider
aria-readonly="true"
aria-valuemax="500"
aria-valuemin="0"
aria-valuenow="100"
end-icon="walk-fast-small"
max="500"
min="0"
name=""
readonly=""
role="slider"
start-icon="walk-slow-small"
tabindex="0"
value="100"
Expand Down Expand Up @@ -246,9 +226,13 @@ snapshots["sbb-slider renders A11y tree Chrome"] =
"role": "WebArea",
"name": "",
"children": [
{
"role": "text",
"name": "Label"
},
{
"role": "slider",
"name": "",
"name": "Label",
"valuetext": "",
"valuemin": 0,
"valuemax": 100,
Expand Down Expand Up @@ -331,9 +315,13 @@ snapshots["sbb-slider renders A11y tree Firefox"] =
"role": "document",
"name": "",
"children": [
{
"role": "text leaf",
"name": "Label"
},
{
"role": "slider",
"name": "",
"name": "Label",
"valuetext": "1",
"value": "1"
}
Expand Down Expand Up @@ -398,3 +386,100 @@ snapshots["sbb-slider renders readonly A11y tree Firefox"] =
`;
/* end snapshot sbb-slider renders readonly A11y tree Firefox */

snapshots["sbb-slider renders in form DOM"] =
`<sbb-slider
max="10"
min="0"
name="sbb-slider"
tabindex="0"
value="1"
>
</sbb-slider>
`;
/* end snapshot sbb-slider renders in form DOM */

snapshots["sbb-slider renders in form Shadow DOM"] =
`<div class="sbb-slider__height-container">
<div class="sbb-slider__wrapper">
<slot name="prefix">
</slot>
<div
class="sbb-slider__container"
style="--sbb-slider-value-fraction:0.1;"
>
<input
class="sbb-slider__range-input"
max="10"
min="0"
tabindex="-1"
type="range"
value="1"
>
<div class="sbb-slider__line">
<div class="sbb-slider__selected-line">
</div>
</div>
<div class="sbb-slider__knob">
</div>
</div>
<slot name="suffix">
</slot>
</div>
</div>
`;
/* end snapshot sbb-slider renders in form Shadow DOM */

snapshots["sbb-slider renders in form A11y tree Chrome"] =
`<p>
{
"role": "WebArea",
"name": "",
"children": [
{
"role": "slider",
"name": "",
"valuetext": "",
"valuemin": 0,
"valuemax": 10,
"orientation": "horizontal",
"value": 1
},
{
"role": "slider",
"name": "",
"valuetext": "",
"valuemin": 0,
"valuemax": 10,
"orientation": "horizontal",
"value": 1
}
]
}
</p>
`;
/* end snapshot sbb-slider renders in form A11y tree Chrome */

snapshots["sbb-slider renders in form A11y tree Firefox"] =
`<p>
{
"role": "document",
"name": "",
"children": [
{
"role": "slider",
"name": "",
"valuetext": "1",
"value": "1"
},
{
"role": "slider",
"name": "",
"valuetext": "1",
"value": "1"
}
]
}
</p>
`;
/* end snapshot sbb-slider renders in form A11y tree Firefox */

25 changes: 12 additions & 13 deletions src/elements/slider/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,25 +70,24 @@ The `sbb-slider` has the following behaviour on keypress when focused:

## Properties

| Name | Attribute | Privacy | Type | Default | Description |
| --------------- | ----------------- | ------- | ---------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| `disabled` | `disabled` | public | `boolean` | `false` | Whether the component is disabled. |
| `endIcon` | `end-icon` | public | `string \| undefined` | | Name of the icon at component's end, which will be forward to the nested `sbb-icon`. |
| `form` | `form` | public | `string \| undefined` | | The <form> element to associate the inner HTMLInputElement with. |
| `max` | `max` | public | `string \| undefined` | `'100'` | Maximum acceptable value for the inner HTMLInputElement. |
| `min` | `min` | public | `string \| undefined` | `'0'` | Minimum acceptable value for the inner HTMLInputElement. |
| `name` | `name` | public | `string \| undefined` | `''` | Name of the inner HTMLInputElement. |
| `readonly` | `readonly` | public | `boolean \| undefined` | `false` | Readonly state for the inner HTMLInputElement. Since the input range does not allow this attribute, it will be merged with the `disabled` one. |
| `startIcon` | `start-icon` | public | `string \| undefined` | | Name of the icon at component's start, which will be forward to the nested `sbb-icon`. |
| `value` | `value` | public | `string \| undefined` | `''` | Value for the inner HTMLInputElement. |
| `valueAsNumber` | `value-as-number` | public | `number \| undefined` | | Numeric value for the inner HTMLInputElement. |
| Name | Attribute | Privacy | Type | Default | Description |
| --------------- | ----------------- | ------- | ------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| `disabled` | `disabled` | public | `boolean` | `false` | Whether the component is disabled. |
| `endIcon` | `end-icon` | public | `string \| undefined` | | Name of the icon at component's end, which will be forward to the nested `sbb-icon`. |
| `form` | - | public | `HTMLFormElement \| null` | | Returns the form owner of internals target element. |
| `max` | `max` | public | `string` | `'100'` | Maximum acceptable value for the inner HTMLInputElement. |
| `min` | `min` | public | `string` | `'0'` | Minimum acceptable value for the inner HTMLInputElement. |
| `name` | `name` | public | `string` | | Name of the form element. Will be read from name attribute. |
| `readonly` | `readonly` | public | `boolean \| undefined` | `false` | Readonly state for the inner HTMLInputElement. Since the input range does not allow this attribute, it will be merged with the `disabled` one. |
| `startIcon` | `start-icon` | public | `string \| undefined` | | Name of the icon at component's start, which will be forward to the nested `sbb-icon`. |
| `value` | `value` | public | `string \| null` | `null` | Value of the form element. If no value is provided, default is the middle point between min and max. |
| `valueAsNumber` | `value-as-number` | public | `number \| null` | | Numeric value for the inner HTMLInputElement. |

## Events

| Name | Type | Description | Inherited From |
| ----------- | ------------------- | -------------------------------------------------------------------------------- | -------------- |
| `didChange` | `CustomEvent<void>` | Deprecated. used for React. Will probably be removed once React 19 is available. | |
| `input` | `InputEvent` | | |

## Slots

Expand Down
6 changes: 3 additions & 3 deletions src/elements/slider/slider.scss
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
}
}

:host([disabled]) {
:host(:disabled) {
--sbb-slider-icon-color: var(--sbb-color-graphite);
--sbb-slider-knob-border-color: var(--sbb-color-smoke);
--sbb-slider-knob-border-size: var(--sbb-border-width-2x);
Expand All @@ -43,7 +43,7 @@
--sbb-slider-knob-border-color: var(--sbb-slider-selected-line-disabled-color);
}

:host([disabled]),
:host(:disabled),
:host([readonly]) {
--sbb-slider-line-color: var(--sbb-slider-line-disabled-color);
--sbb-slider-selected-line-color: var(--sbb-slider-selected-line-disabled-color);
Expand Down Expand Up @@ -128,7 +128,7 @@
}

// slider knob resize on click (active / focus)
:host(:not(:is([disabled], [readonly]))) .sbb-slider__range-input:active ~ & {
:host(:not(:is(:disabled, [readonly]))) .sbb-slider__range-input:active ~ & {
--sbb-slider-knob-size: var(--sbb-slider-knob-size-active);
}
}
31 changes: 30 additions & 1 deletion src/elements/slider/slider.snapshot.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,14 @@ describe(`sbb-slider`, () => {

describe('renders', async () => {
beforeEach(async () => {
element = await fixture(html`<sbb-slider value="1"></sbb-slider>`);
element = (
await fixture(html`
<div>
<label for="slider-1">Label</label>
<sbb-slider value="1" id="slider-1"></sbb-slider>
</div>
`)
).querySelector('sbb-slider')!;
});

it('DOM', async () => {
Expand Down Expand Up @@ -99,4 +106,26 @@ describe(`sbb-slider`, () => {

testA11yTreeSnapshot();
});

describe('renders in form', async () => {
beforeEach(async () => {
const form = await fixture(
html` <form>
<sbb-slider name="sbb-slider" min="0" max="10" value="1"></sbb-slider>
<input type="range" name="input-range" min="0" max="10" value="1" />
</form>`,
);
element = form.querySelector('sbb-slider')!;
});

it('DOM', async () => {
await expect(element).dom.to.be.equalSnapshot();
});

it('Shadow DOM', async () => {
await expect(element).shadowDom.to.be.equalSnapshot();
});

testA11yTreeSnapshot();
});
});
Loading

0 comments on commit ad35f2f

Please sign in to comment.