diff --git a/.storybook/preview-head.html b/.storybook/preview-head.html index 347ec33232..4d6747b90f 100644 --- a/.storybook/preview-head.html +++ b/.storybook/preview-head.html @@ -27,7 +27,8 @@ @@ -43,9 +43,14 @@ describe(`sbb-header`, () => { Christina Müller English + ${size === 's' - ? html`` - : html``} + ? html`` + : html``}
${loremIpsumTemplate} @@ -76,7 +81,7 @@ describe(`sbb-header`, () => { padding: '0', }); setup.withStateElement( - setup.snapshotElement.querySelector(`a[slot='logo']`)!, + setup.snapshotElement.querySelector('.sbb-header-logo')!, ); }), ); diff --git a/src/elements/header/header/readme.md b/src/elements/header/header/readme.md index 650ed05872..7b7ec42a71 100644 --- a/src/elements/header/header/readme.md +++ b/src/elements/header/header/readme.md @@ -2,12 +2,13 @@ The `sbb-header` component is a container for actions and a logo, and it is disp ## Slots -It has two slots: -the first one can contain one or more action ([sbb-header-button](/docs/elements-sbb-header-sbb-header-button--docs) or -[sbb-header-link](/docs/elements-sbb-header-sbb-header-link--docs)) -or other action items like [sbb-button](/docs/elements-sbb-button--docs) or [sbb-link](/docs/elements-sbb-link--docs), -and it is displayed at the left end of the component; the second slot is displayed at the right end, -and it can contain a logo or a signet, which by default is the [sbb-logo](/docs/elements-sbb-logo--docs). +The slot can contain: + +- one or more actions ([sbb-header-button](/docs/elements-sbb-header-sbb-header-button--docs) or [sbb-header-link](/docs/elements-sbb-header-sbb-header-link--docs)) +- other action items like [sbb-button](/docs/elements-sbb-button--docs) or [sbb-link](/docs/elements-sbb-link--docs) +- a logo or a signet with the `.sbb-header-logo` class (see [sbb-logo](/docs/elements-sbb-logo--docs)) + +Slotted elements are aligned to the left. Use `
` to align elements after it to the right. ```html @@ -15,7 +16,8 @@ and it can contain a logo or a signet, which by default is the [sbb-logo](/docs/ Menu Search - +
+
@@ -38,8 +40,9 @@ For the latter, the usage of the `sbb-signet` with `protective-room='panel'` is Menu Search - - +
+
``` @@ -61,8 +64,9 @@ From accessibility perspective `aria-current="page"` should be set whenever the > Overview - - +
+
``` @@ -79,7 +83,8 @@ using the `scrollOrigin` property, which accepts an `HTMLElement` or the id of t ```html Search - +
+
@@ -92,18 +97,26 @@ by adding classes to `sbb-header-button`/`sbb-header-link` elements and then def [All the examples in Storybook](/story/elements-sbb-header-sbb-header--basic) have the following requirements: -- four action items (with custom icons); -- the first item is always left aligned and has `expand-from` set to `small`; -- the other three items are left aligned in breakpoints zero to medium, and right aligned from large to ultra; -- the last item is not visible in breakpoints zero to small. +1. four action items (with custom icons); +2. the first item is always left aligned and has `expand-from` set to `small`; +3. the other three items are left aligned in breakpoints zero to medium, and right aligned from large to ultra; +4. the last item is not visible in breakpoints zero to small; +5. the logo is always aligned to the right. + +To achieve the alignment requirements, two `div` tags with a CSS class named `sbb-header-spacer` were added: + +- one after the first `sbb-header-button` item (that will be hidden on smaller screen sizes); +- the second, before the logo. Since this spacer will only be shown on small screen sizes, we need a new class to target it (in this example `sbb-header-spacer-logo`); + +We also need a class (in this example `last-element`) on the last `sbb-header-button` to achieve requirement n° 4. -To achieve this result, a `div` tag with a CSS class named `sbb-header-spacer` was added between the first -and the second `sbb-header-button` item, then a class named `last-element` was added to the last one. Finally, the following custom CSS has been added(\*). -The result can be seen in the [home](/story/pages-home--home) and [home-logged-in](/story/pages-home--home-logged-in) stories. + +The result can also be seen in the [home](/story/pages-home--home) and [home-logged-in](/story/pages-home--home-logged-in) stories. ```css -.last-element { +.last-element, +.sbb-header-spacer-logo { display: none; } @@ -117,9 +130,33 @@ The result can be seen in the [home](/story/pages-home--home) and [home-logged-i .sbb-header-spacer { display: none; } + + .sbb-header-spacer-logo { + display: block; + } } ``` +```html + + ... + + +
+ + ... + ... + ... + + + + + +
+``` + The `sbb-header` can be also customized by adding the application's name and version: a helper class named `sbb-header-info` is provided to achieve the correct visual result. @@ -134,8 +171,10 @@ a helper class named `sbb-header-info` is provided to achieve the correct visual V. 1.1 - - +
+ +
``` @@ -153,7 +192,8 @@ set the CSS class `sbb-header-shrinkable` on the desired `sbb-header-button`/`sb Christina Müller has a long name - +
+
@@ -183,7 +223,6 @@ so they were wrapped into a `style` tag and added to the Storybook's configurati ## Slots -| Name | Description | -| ------ | --------------------------------------------------------------------- | -| | Use the unnamed slot to add actions or content to the header. | -| `logo` | Slot used to render the logo on the right side (sbb-logo as default). | +| Name | Description | +| ---- | -------------------------------------------------------------------- | +| | Use the unnamed slot to add actions, content and logo to the header. | diff --git a/src/elements/map-container/map-container.stories.ts b/src/elements/map-container/map-container.stories.ts index 5342657986..f987015355 100644 --- a/src/elements/map-container/map-container.stories.ts +++ b/src/elements/map-container/map-container.stories.ts @@ -12,6 +12,7 @@ import '../form-field.js'; import '../icon.js'; import '../title.js'; import '../header.js'; +import '../logo.js'; const hideScrollUpButton: InputType = { control: { @@ -86,6 +87,8 @@ const meta: Meta = { Menu +
+ ${story()} `, diff --git a/src/elements/map-container/map-container.visual.spec.ts b/src/elements/map-container/map-container.visual.spec.ts index 970e48e8f5..a31975606d 100644 --- a/src/elements/map-container/map-container.visual.spec.ts +++ b/src/elements/map-container/map-container.visual.spec.ts @@ -6,6 +6,7 @@ import { describeViewports, visualDiffDefault } from '../core/testing/private.js import './map-container.js'; import '../header.js'; import '../title.js'; +import '../logo.js'; describe(`sbb-map-container`, () => { const template = (stickyOffset = false): TemplateResult => html` @@ -13,6 +14,8 @@ describe(`sbb-map-container`, () => { Menu +
+ ` | Notifies that the component's value has changed. | | -| `didChange` | `CustomEvent` | Deprecated. used for React. Will probably be removed once React 19 is available. | | -| `didClose` | `CustomEvent` | Emits whenever the `sbb-select` is closed. | SbbOpenCloseBaseElement | -| `didOpen` | `CustomEvent` | Emits whenever the `sbb-select` is opened. | SbbOpenCloseBaseElement | -| `input` | `CustomEvent` | Notifies that an option value has been selected. | | -| `willClose` | `CustomEvent` | Emits whenever the `sbb-select` begins the closing transition. Can be canceled. | SbbOpenCloseBaseElement | -| `willOpen` | `CustomEvent` | Emits whenever the `sbb-select` starts the opening transition. Can be canceled. | SbbOpenCloseBaseElement | +| Name | Type | Description | Inherited From | +| ----------- | ------------------- | ------------------------------------------------------------------------------- | ----------------------- | +| `change` | `CustomEvent` | Notifies that the component's value has changed. | | +| `didClose` | `CustomEvent` | Emits whenever the `sbb-select` is closed. | SbbOpenCloseBaseElement | +| `didOpen` | `CustomEvent` | Emits whenever the `sbb-select` is opened. | SbbOpenCloseBaseElement | +| `input` | `CustomEvent` | Notifies that an option value has been selected. | | +| `willClose` | `CustomEvent` | Emits whenever the `sbb-select` begins the closing transition. Can be canceled. | SbbOpenCloseBaseElement | +| `willOpen` | `CustomEvent` | Emits whenever the `sbb-select` starts the opening transition. Can be canceled. | SbbOpenCloseBaseElement | ## CSS Properties diff --git a/src/elements/select/select.ts b/src/elements/select/select.ts index 3ce7b3932e..a2e5eade15 100644 --- a/src/elements/select/select.ts +++ b/src/elements/select/select.ts @@ -43,7 +43,6 @@ export interface SelectChange { * It displays a panel with selectable options. * * @slot - Use the unnamed slot to add options. - * @event {CustomEvent} didChange - Deprecated. used for React. Will probably be removed once React 19 is available. * @event {CustomEvent} change - Notifies that the component's value has changed. * @event {CustomEvent} input - Notifies that an option value has been selected. * @event {CustomEvent} willOpen - Emits whenever the `sbb-select` starts the opening transition. Can be canceled. @@ -77,7 +76,6 @@ class SbbSelectElement extends SbbUpdateSchedulerMixin( // FIXME using ...super.events requires: https://github.com/sbb-design-systems/lyne-components/issues/2600 public static override readonly events = { - didChange: 'didChange', change: 'change', input: 'input', stateChange: 'stateChange', @@ -113,11 +111,6 @@ class SbbSelectElement extends SbbUpdateSchedulerMixin( /** The value displayed by the component. */ @state() private accessor _displayValue: string | null = null; - /** - * @deprecated only used for React. Will probably be removed once React 19 is available. - */ - private _didChange: EventEmitter = new EventEmitter(this, SbbSelectElement.events.didChange); - /** Notifies that the component's value has changed. */ private _change: EventEmitter = new EventEmitter(this, SbbSelectElement.events.change); @@ -519,7 +512,6 @@ class SbbSelectElement extends SbbUpdateSchedulerMixin( this._input.emit(); this._change.emit(); - this._didChange.emit(); } /** When an option is unselected in `multiple`, removes it from value and updates displayValue. */ @@ -531,7 +523,6 @@ class SbbSelectElement extends SbbUpdateSchedulerMixin( this._input.emit(); this._change.emit(); - this._didChange.emit(); } } diff --git a/src/elements/time-input/time-input.spec.ts b/src/elements/time-input/time-input.spec.ts index 601c22321a..de59150ff5 100644 --- a/src/elements/time-input/time-input.spec.ts +++ b/src/elements/time-input/time-input.spec.ts @@ -39,13 +39,25 @@ describe(`sbb-time-input`, () => { it('should emit form events', async () => { const changeSpy = new EventSpy('change', element); const inputSpy = new EventSpy('input', element); + const nativeInputSpy = new EventSpy('input', input); + const nativeChangeSpy = new EventSpy('change', input); - typeInElement(input, '1'); + input.focus(); + await sendKeys({ press: '1' }); input.blur(); await waitForLitRender(element); - expect(changeSpy.count).to.be.greaterThan(0); - expect(inputSpy.count).to.be.greaterThan(0); + await nativeChangeSpy.calledOnce().then(() => { + expect(input.value).to.be.equal('01:00'); + }); + await changeSpy.calledOnce().then(() => { + expect(input.value).to.be.equal('01:00'); + }); + + expect(inputSpy.count, 'sbb-time-input input event').to.be.equal(2); + expect(changeSpy.count, 'sbb-time-input change event').to.be.equal(1); + expect(nativeInputSpy.count, 'input input event').to.be.equal(2); + expect(nativeChangeSpy.count, 'input change event').to.be.equal(1); }); it('should emit validation change event', async () => { diff --git a/src/elements/time-input/time-input.ts b/src/elements/time-input/time-input.ts index 3759b087c1..4ec0a839e0 100644 --- a/src/elements/time-input/time-input.ts +++ b/src/elements/time-input/time-input.ts @@ -144,18 +144,22 @@ class SbbTimeInputElement extends LitElement { ); this._inputElement.addEventListener( 'change', - (event: Event) => this._updateValueAndEmitChange(event), + (event: Event) => this._updateValue((event.target as HTMLInputElement).value), + { + signal: this._abortController.signal, + capture: true, + }, + ); + this._inputElement.addEventListener( + 'change', + (event: Event) => { + this._emitChange(event); + this._updateAccessibilityMessage(); + }, { signal: this._abortController.signal, }, ); - } - - /** Applies the correct format to values and triggers event dispatch. */ - private _updateValueAndEmitChange(event: Event): void { - this._updateValue((event.target as HTMLInputElement).value); - this._emitChange(event); - this._updateAccessibilityMessage(); } /** @@ -175,7 +179,12 @@ class SbbTimeInputElement extends LitElement { const isTimeValid = !!time && this._isTimeValid(time); const isEmptyOrValid = !value || value.trim() === '' || isTimeValid; if (isEmptyOrValid && time) { - this._inputElement.value = this._formatValue(time); + // In order to support React onChange event, we have to get the setter and call it. + // https://github.com/facebook/react/issues/11600#issuecomment-345813130 + const setValue = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value')!.set!; + setValue.call(this._inputElement, this._formatValue(time)); + + this._inputElement.dispatchEvent(new InputEvent('input', { bubbles: true, composed: true })); } const wasValid = !this._inputElement.hasAttribute('data-sbb-invalid'); diff --git a/src/elements/toggle-check/readme.md b/src/elements/toggle-check/readme.md index 734c4f79b1..60b307c4c2 100644 --- a/src/elements/toggle-check/readme.md +++ b/src/elements/toggle-check/readme.md @@ -79,11 +79,10 @@ you can not provide it and then use `aria-label` to specify an appropriate label ## Events -| Name | Type | Description | Inherited From | -| ----------- | ------------------- | -------------------------------------------------------------------------------- | -------------- | -| `change` | `Event` | Event fired on change. | | -| `didChange` | `CustomEvent` | Deprecated. used for React. Will probably be removed once React 19 is available. | | -| `input` | `InputEvent` | Event fired on input. | | +| Name | Type | Description | Inherited From | +| -------- | ------------ | ---------------------- | -------------- | +| `change` | `Event` | Event fired on change. | | +| `input` | `InputEvent` | Event fired on input. | | ## Slots diff --git a/src/elements/toggle-check/toggle-check.ts b/src/elements/toggle-check/toggle-check.ts index 85b0e81c12..67744a5208 100644 --- a/src/elements/toggle-check/toggle-check.ts +++ b/src/elements/toggle-check/toggle-check.ts @@ -13,7 +13,6 @@ import style from './toggle-check.scss?lit&inline'; * * @slot - Use the unnamed slot to add content to the toggle label. * @slot icon - Use this slot to provide an icon. If `icon-name` is set, a sbb-icon will be used. - * @event {CustomEvent} didChange - Deprecated. used for React. Will probably be removed once React 19 is available. * @event {Event} change - Event fired on change. * @event {InputEvent} input - Event fired on input. */ @@ -22,9 +21,6 @@ export @slotState() class SbbToggleCheckElement extends SbbFormAssociatedCheckboxMixin(SbbIconNameMixin(LitElement)) { public static override styles: CSSResultGroup = style; - public static readonly events = { - didChange: 'didChange', - } as const; /** Size variant, either m, s or xs. */ @property({ reflect: true }) public accessor size: 'xs' | 's' | 'm' = 's'; diff --git a/src/elements/toggle/toggle/readme.md b/src/elements/toggle/toggle/readme.md index 4b2b55e154..b2d57bf8ec 100644 --- a/src/elements/toggle/toggle/readme.md +++ b/src/elements/toggle/toggle/readme.md @@ -44,10 +44,9 @@ The component has two different sizes, `s` and `m` (default), which can be set u ## Events -| Name | Type | Description | Inherited From | -| ----------- | ------------------- | -------------------------------------------------------------------------------- | -------------- | -| `change` | `CustomEvent` | Emits whenever the toggle value changes. | | -| `didChange` | `CustomEvent` | Deprecated. used for React. Will probably be removed once React 19 is available. | | +| Name | Type | Description | Inherited From | +| -------- | ------------------- | ---------------------------------------- | -------------- | +| `change` | `CustomEvent` | Emits whenever the toggle value changes. | | ## Slots diff --git a/src/elements/toggle/toggle/toggle.ts b/src/elements/toggle/toggle/toggle.ts index a228c57640..61fd82a8d3 100644 --- a/src/elements/toggle/toggle/toggle.ts +++ b/src/elements/toggle/toggle/toggle.ts @@ -21,7 +21,6 @@ import style from './toggle.scss?lit&inline'; * It can be used as a container for two `sbb-toggle-option`, acting as a toggle button. * * @slot - Use the unnamed slot to add `` elements to the toggle. - * @event {CustomEvent} didChange - Deprecated. used for React. Will probably be removed once React 19 is available. * @event {CustomEvent} change - Emits whenever the toggle value changes. */ export @@ -32,7 +31,6 @@ export class SbbToggleElement extends LitElement { public static override styles: CSSResultGroup = style; public static readonly events = { - didChange: 'didChange', change: 'change', } as const; @@ -84,15 +82,6 @@ class SbbToggleElement extends LitElement { callback: () => this.updatePillPosition(true), }); - /** - * @deprecated only used for React. Will probably be removed once React 19 is available. - * Emits whenever the toggle value changes. - */ - private _didChange: EventEmitter = new EventEmitter(this, SbbToggleElement.events.didChange, { - bubbles: true, - composed: true, - }); - /** Emits whenever the toggle value changes. */ private _change: EventEmitter = new EventEmitter(this, SbbToggleElement.events.change, { bubbles: true, @@ -185,7 +174,6 @@ class SbbToggleElement extends LitElement { private _handleInput(): void { this.updatePillPosition(false); this._change.emit(); - this._didChange.emit(); } private _handleKeyDown(evt: KeyboardEvent): void { diff --git a/src/storybook/pages/home/home--logged-in.stories.ts b/src/storybook/pages/home/home--logged-in.stories.ts index 50f6de3620..df6e88783e 100644 --- a/src/storybook/pages/home/home--logged-in.stories.ts +++ b/src/storybook/pages/home/home--logged-in.stories.ts @@ -75,7 +75,8 @@ const Template = (args: Args): TemplateResult => html` Italiano English - + + diff --git a/src/storybook/pages/home/home.stories.ts b/src/storybook/pages/home/home.stories.ts index 0ff03467ad..99304aba45 100644 --- a/src/storybook/pages/home/home.stories.ts +++ b/src/storybook/pages/home/home.stories.ts @@ -55,7 +55,8 @@ const Template = (args: Args): TemplateResult => html` Italiano English - + + diff --git a/src/visual-regression-app/src/components/test-case/test-case.ts b/src/visual-regression-app/src/components/test-case/test-case.ts index c8d45f37d6..1cbf27f59c 100644 --- a/src/visual-regression-app/src/components/test-case/test-case.ts +++ b/src/visual-regression-app/src/components/test-case/test-case.ts @@ -110,7 +110,7 @@ class TestCase extends LitElement {
-
+