diff --git a/eslint.config.js b/eslint.config.js index 049e8ec0eed..08674551d4c 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -171,8 +171,6 @@ export default [ }, }, ], - // TODO: Activate with standard decorators - 'lyne/property-decorator-accessor-rule': 'off', }, }, { diff --git a/package.json b/package.json index 870694d733d..d7280dee786 100644 --- a/package.json +++ b/package.json @@ -161,7 +161,7 @@ }, "lint-staged": { "*.{js,ts,yaml,yml}": [ - "eslint --fix" + "eslint --fix --no-ignore" ], "*.scss": [ "stylelint --fix" diff --git a/src/elements-experimental/journey-summary/journey-summary.ts b/src/elements-experimental/journey-summary/journey-summary.ts index 6bcf6c054a3..eba15163275 100644 --- a/src/elements-experimental/journey-summary/journey-summary.ts +++ b/src/elements-experimental/journey-summary/journey-summary.ts @@ -1,5 +1,6 @@ import { SbbLanguageController } from '@sbb-esta/lyne-elements/core/controllers.js'; import { defaultDateAdapter } from '@sbb-esta/lyne-elements/core/datetime.js'; +import { forceType } from '@sbb-esta/lyne-elements/core/decorators.js'; import { i18nTripDuration } from '@sbb-esta/lyne-elements/core/i18n.js'; import type { SbbDateLike } from '@sbb-esta/lyne-elements/core/interfaces/types'; import type { SbbTitleLevel } from '@sbb-esta/lyne-elements/title.js'; @@ -35,30 +36,35 @@ export interface InterfaceSbbJourneySummaryAttributes { * * @slot content - Use this slot to add `sbb-button`s or other interactive elements. */ +export @customElement('sbb-journey-summary') -export class SbbJourneySummaryElement extends LitElement { +class SbbJourneySummaryElement extends LitElement { public static override styles: CSSResultGroup = style; /** The trip prop */ - @property({ type: Object }) public trip!: InterfaceSbbJourneySummaryAttributes; + @property({ type: Object }) public accessor trip: InterfaceSbbJourneySummaryAttributes = null!; /** The tripBack prop */ @property({ attribute: 'trip-back', type: Object }) - public tripBack?: InterfaceSbbJourneySummaryAttributes; + public accessor tripBack: InterfaceSbbJourneySummaryAttributes = null!; /** * The RoundTrip prop. This prop controls if one or two arrows are displayed in the header. */ - @property({ attribute: 'round-trip', type: Boolean }) public roundTrip?: boolean; + @property({ attribute: 'round-trip', type: Boolean }) + @forceType(Boolean) + public accessor roundTrip: boolean = false; /** Heading level of the journey header element (e.g. h1-h6). */ - @property({ attribute: 'header-level' }) public headerLevel: SbbTitleLevel = '3'; + @property({ attribute: 'header-level' }) public accessor headerLevel: SbbTitleLevel = '3'; /** * Per default, the current location has a pulsating animation. You can * disable the animation with this property. */ - @property({ attribute: 'disable-animation', type: Boolean }) public disableAnimation?: boolean; + @property({ attribute: 'disable-animation', type: Boolean }) + @forceType(Boolean) + public accessor disableAnimation: boolean = false; /** * The Footpath attribute for rendering different icons @@ -66,7 +72,9 @@ export class SbbJourneySummaryElement extends LitElement { * false: render walk-icon * default: render walk-icon */ - @property({ attribute: 'a11y-footpath', type: Boolean }) public a11yFootpath?: boolean; + @property({ attribute: 'a11y-footpath', type: Boolean }) + @forceType(Boolean) + public accessor a11yFootpath: boolean = false; /** A configured date which acts as the current date instead of the real current date. Recommended for testing purposes. */ @property() diff --git a/src/elements-experimental/journey-summary/readme.md b/src/elements-experimental/journey-summary/readme.md index bce0f640f54..11c6625ef90 100644 --- a/src/elements-experimental/journey-summary/readme.md +++ b/src/elements-experimental/journey-summary/readme.md @@ -24,15 +24,15 @@ This is helpful if you need a specific state of the component. ## Properties -| Name | Attribute | Privacy | Type | Default | Description | -| ------------------ | ------------------- | ------- | --------------------------------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------- | -| `a11yFootpath` | `a11y-footpath` | public | `boolean \| undefined` | | The Footpath attribute for rendering different icons true: render a11y-icon false: render walk-icon default: render walk-icon | -| `disableAnimation` | `disable-animation` | public | `boolean \| undefined` | | Per default, the current location has a pulsating animation. You can disable the animation with this property. | -| `headerLevel` | `header-level` | public | `SbbTitleLevel` | `'3'` | Heading level of the journey header element (e.g. h1-h6). | -| `now` | `now` | public | `Date` | `null` | A configured date which acts as the current date instead of the real current date. Recommended for testing purposes. | -| `roundTrip` | `round-trip` | public | `boolean \| undefined` | | The RoundTrip prop. This prop controls if one or two arrows are displayed in the header. | -| `trip` | `trip` | public | `InterfaceSbbJourneySummaryAttributes` | | The trip prop | -| `tripBack` | `trip-back` | public | `InterfaceSbbJourneySummaryAttributes \| undefined` | | The tripBack prop | +| Name | Attribute | Privacy | Type | Default | Description | +| ------------------ | ------------------- | ------- | -------------------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------- | +| `a11yFootpath` | `a11y-footpath` | public | `boolean` | `false` | The Footpath attribute for rendering different icons true: render a11y-icon false: render walk-icon default: render walk-icon | +| `disableAnimation` | `disable-animation` | public | `boolean` | `false` | Per default, the current location has a pulsating animation. You can disable the animation with this property. | +| `headerLevel` | `header-level` | public | `SbbTitleLevel` | `'3'` | Heading level of the journey header element (e.g. h1-h6). | +| `now` | `now` | public | `Date` | `null` | A configured date which acts as the current date instead of the real current date. Recommended for testing purposes. | +| `roundTrip` | `round-trip` | public | `boolean` | `false` | The RoundTrip prop. This prop controls if one or two arrows are displayed in the header. | +| `trip` | `trip` | public | `InterfaceSbbJourneySummaryAttributes` | `null!` | The trip prop | +| `tripBack` | `trip-back` | public | `InterfaceSbbJourneySummaryAttributes` | `null!` | The tripBack prop | ## Slots diff --git a/src/elements-experimental/package.json b/src/elements-experimental/package.json index d7bee1133db..618c58db09f 100644 --- a/src/elements-experimental/package.json +++ b/src/elements-experimental/package.json @@ -14,7 +14,8 @@ "@sbb-esta/lyne-elements": "0.0.0-PLACEHOLDER" }, "dependencies": { - "lit": "0.0.0-LIT" + "lit": "0.0.0-LIT", + "tslib": "^2.7.0" }, "publishConfig": { "access": "public" diff --git a/src/elements-experimental/pearl-chain-time/pearl-chain-time.ts b/src/elements-experimental/pearl-chain-time/pearl-chain-time.ts index 78cef0ed89e..8b34cd2fab4 100644 --- a/src/elements-experimental/pearl-chain-time/pearl-chain-time.ts +++ b/src/elements-experimental/pearl-chain-time/pearl-chain-time.ts @@ -1,5 +1,6 @@ import { SbbLanguageController } from '@sbb-esta/lyne-elements/core/controllers.js'; import { defaultDateAdapter } from '@sbb-esta/lyne-elements/core/datetime.js'; +import { forceType } from '@sbb-esta/lyne-elements/core/decorators.js'; import { i18nArrival, i18nDeparture, @@ -22,8 +23,9 @@ import '../pearl-chain.js'; /** * Combined with `sbb-pearl-chain`, it displays walk time information. */ +export @customElement('sbb-pearl-chain-time') -export class SbbPearlChainTimeElement extends LitElement { +class SbbPearlChainTimeElement extends LitElement { public static override styles: CSSResultGroup = style; /** @@ -34,28 +36,33 @@ export class SbbPearlChainTimeElement extends LitElement { * to the total travel time. Example: departure 16:30, change at 16:40, * arrival at 17:00. So the change should have a duration of 33.33%. */ - @property({ type: Array }) public legs!: (Leg | PtRideLeg)[]; + @property({ type: Array }) public accessor legs: (Leg | PtRideLeg)[] = []; /** Prop to render the departure time - will be formatted as "H:mm" */ - @property({ attribute: 'departure-time' }) public departureTime?: string; + @property({ attribute: 'departure-time' }) public accessor departureTime: string = ''; /** Prop to render the arrival time - will be formatted as "H:mm" */ - @property({ attribute: 'arrival-time' }) public arrivalTime?: string; + @property({ attribute: 'arrival-time' }) public accessor arrivalTime: string = ''; /** Optional prop to render the walk time (in minutes) before departure */ - @property({ attribute: 'departure-walk', type: Number }) public departureWalk?: number; + @property({ attribute: 'departure-walk', type: Number }) public accessor departureWalk: number = + NaN; /** Optional prop to render the walk time (in minutes) after arrival */ - @property({ attribute: 'arrival-walk', type: Number }) public arrivalWalk?: number; + @property({ attribute: 'arrival-walk', type: Number }) public accessor arrivalWalk: number = NaN; /** * Per default, the current location has a pulsating animation. You can * disable the animation with this property. */ - @property({ attribute: 'disable-animation', type: Boolean }) public disableAnimation?: boolean; + @property({ attribute: 'disable-animation', type: Boolean }) + @forceType(Boolean) + public accessor disableAnimation: boolean = false; /** Optional prop to render wheelchair-small instead of walk-small */ - @property({ attribute: 'a11y-footpath', type: Boolean }) public a11yFootpath?: boolean; + @property({ attribute: 'a11y-footpath', type: Boolean }) + @forceType(Boolean) + public accessor a11yFootpath: boolean = false; /** A configured date which acts as the current date instead of the real current date. Recommended for testing purposes. */ @property() diff --git a/src/elements-experimental/pearl-chain-time/readme.md b/src/elements-experimental/pearl-chain-time/readme.md index 27ee28dad84..fb688e25bd2 100644 --- a/src/elements-experimental/pearl-chain-time/readme.md +++ b/src/elements-experimental/pearl-chain-time/readme.md @@ -55,11 +55,11 @@ This is helpful if you need a specific state of the component. | Name | Attribute | Privacy | Type | Default | Description | | ------------------ | ------------------- | ------- | ---------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `a11yFootpath` | `a11y-footpath` | public | `boolean \| undefined` | | Optional prop to render wheelchair-small instead of walk-small | -| `arrivalTime` | `arrival-time` | public | `string \| undefined` | | Prop to render the arrival time - will be formatted as "H:mm" | -| `arrivalWalk` | `arrival-walk` | public | `number \| undefined` | | Optional prop to render the walk time (in minutes) after arrival | -| `departureTime` | `departure-time` | public | `string \| undefined` | | Prop to render the departure time - will be formatted as "H:mm" | -| `departureWalk` | `departure-walk` | public | `number \| undefined` | | Optional prop to render the walk time (in minutes) before departure | -| `disableAnimation` | `disable-animation` | public | `boolean \| undefined` | | Per default, the current location has a pulsating animation. You can disable the animation with this property. | -| `legs` | `legs` | public | `(Leg \| PtRideLeg)[]` | | define the legs of the pearl-chain. Format: `{"legs": \[{"duration": 25}, ...]}` `duration` in minutes. Duration of the leg is relative to the total travel time. Example: departure 16:30, change at 16:40, arrival at 17:00. So the change should have a duration of 33.33%. | +| `a11yFootpath` | `a11y-footpath` | public | `boolean` | `false` | Optional prop to render wheelchair-small instead of walk-small | +| `arrivalTime` | `arrival-time` | public | `string` | `''` | Prop to render the arrival time - will be formatted as "H:mm" | +| `arrivalWalk` | `arrival-walk` | public | `number` | `NaN` | Optional prop to render the walk time (in minutes) after arrival | +| `departureTime` | `departure-time` | public | `string` | `''` | Prop to render the departure time - will be formatted as "H:mm" | +| `departureWalk` | `departure-walk` | public | `number` | `NaN` | Optional prop to render the walk time (in minutes) before departure | +| `disableAnimation` | `disable-animation` | public | `boolean` | `false` | Per default, the current location has a pulsating animation. You can disable the animation with this property. | +| `legs` | `legs` | public | `(Leg \| PtRideLeg)[]` | `[]` | define the legs of the pearl-chain. Format: `{"legs": \[{"duration": 25}, ...]}` `duration` in minutes. Duration of the leg is relative to the total travel time. Example: departure 16:30, change at 16:40, arrival at 17:00. So the change should have a duration of 33.33%. | | `now` | `now` | public | `Date` | `null` | A configured date which acts as the current date instead of the real current date. Recommended for testing purposes. | diff --git a/src/elements-experimental/pearl-chain-vertical-item/pearl-chain-vertical-item.ts b/src/elements-experimental/pearl-chain-vertical-item/pearl-chain-vertical-item.ts index f497e68687d..5432878c61c 100644 --- a/src/elements-experimental/pearl-chain-vertical-item/pearl-chain-vertical-item.ts +++ b/src/elements-experimental/pearl-chain-vertical-item/pearl-chain-vertical-item.ts @@ -1,3 +1,4 @@ +import { forceType } from '@sbb-esta/lyne-elements/core/decorators.js'; import type { CSSResultGroup, TemplateResult } from 'lit'; import { html, LitElement, nothing } from 'lit'; import { customElement, property } from 'lit/decorators.js'; @@ -28,17 +29,19 @@ export interface PearlChainVerticalItemAttributes { * @slot left - Content of the left side of the item * @slot right - Content of the right side of the item */ +export @customElement('sbb-pearl-chain-vertical-item') -export class SbbPearlChainVerticalItemElement extends LitElement { +class SbbPearlChainVerticalItemElement extends LitElement { public static override styles: CSSResultGroup = style; /** The pearlChainVerticalItemAttributes Prop for styling the bullets and line.*/ @property({ attribute: 'pearl-chain-vertical-item-attributes', type: Object }) - public pearlChainVerticalItemAttributes!: PearlChainVerticalItemAttributes; + public accessor pearlChainVerticalItemAttributes: PearlChainVerticalItemAttributes = null!; /** If true, the position won't be animated. */ @property({ attribute: 'disable-animation', reflect: true, type: Boolean }) - public disableAnimation?: boolean; + @forceType(Boolean) + public accessor disableAnimation: boolean = false; protected override render(): TemplateResult { const { bulletType, lineType, lineColor, hideLine, minHeight, bulletSize, position } = diff --git a/src/elements-experimental/pearl-chain-vertical-item/readme.md b/src/elements-experimental/pearl-chain-vertical-item/readme.md index 3943bc94ba0..3225581a549 100644 --- a/src/elements-experimental/pearl-chain-vertical-item/readme.md +++ b/src/elements-experimental/pearl-chain-vertical-item/readme.md @@ -38,8 +38,8 @@ The slots themselves are unstyled, so that they can be used in various ways. | Name | Attribute | Privacy | Type | Default | Description | | ---------------------------------- | -------------------------------------- | ------- | ---------------------------------- | ------- | --------------------------------------------------------------------------- | -| `disableAnimation` | `disable-animation` | public | `boolean \| undefined` | | If true, the position won't be animated. | -| `pearlChainVerticalItemAttributes` | `pearl-chain-vertical-item-attributes` | public | `PearlChainVerticalItemAttributes` | | The pearlChainVerticalItemAttributes Prop for styling the bullets and line. | +| `disableAnimation` | `disable-animation` | public | `boolean` | `false` | If true, the position won't be animated. | +| `pearlChainVerticalItemAttributes` | `pearl-chain-vertical-item-attributes` | public | `PearlChainVerticalItemAttributes` | `null!` | The pearlChainVerticalItemAttributes Prop for styling the bullets and line. | ## Slots diff --git a/src/elements-experimental/pearl-chain-vertical/pearl-chain-vertical.ts b/src/elements-experimental/pearl-chain-vertical/pearl-chain-vertical.ts index ddc422741fc..63d1a48fa94 100644 --- a/src/elements-experimental/pearl-chain-vertical/pearl-chain-vertical.ts +++ b/src/elements-experimental/pearl-chain-vertical/pearl-chain-vertical.ts @@ -9,8 +9,9 @@ import style from './pearl-chain-vertical.scss?lit&inline'; * * @slot - The unnamed slot is used for the `sbb-pearl-chain-vertical-item` component. */ +export @customElement('sbb-pearl-chain-vertical') -export class SbbPearlChainVerticalElement extends LitElement { +class SbbPearlChainVerticalElement extends LitElement { public static override styles: CSSResultGroup = style; protected override render(): TemplateResult { diff --git a/src/elements-experimental/pearl-chain/pearl-chain.ts b/src/elements-experimental/pearl-chain/pearl-chain.ts index f9a459adbed..047289a0905 100644 --- a/src/elements-experimental/pearl-chain/pearl-chain.ts +++ b/src/elements-experimental/pearl-chain/pearl-chain.ts @@ -1,4 +1,5 @@ import { defaultDateAdapter } from '@sbb-esta/lyne-elements/core/datetime.js'; +import { forceType } from '@sbb-esta/lyne-elements/core/decorators.js'; import type { SbbDateLike } from '@sbb-esta/lyne-elements/core/interfaces/types'; import { addMinutes, differenceInMinutes, isAfter, isBefore } from 'date-fns'; import type { CSSResultGroup, TemplateResult } from 'lit'; @@ -21,8 +22,9 @@ type Time = { /** * It visually displays journey information. */ +export @customElement('sbb-pearl-chain') -export class SbbPearlChainElement extends LitElement { +class SbbPearlChainElement extends LitElement { public static override styles: CSSResultGroup = style; /** @@ -33,13 +35,15 @@ export class SbbPearlChainElement extends LitElement { * to the total travel time. Example: departure 16:30, change at 16:40, * arrival at 17:00. So the change should have a duration of 33.33%. */ - @property({ type: Array }) public legs?: (Leg | PtRideLeg)[]; + @property({ type: Array }) public accessor legs: (Leg | PtRideLeg)[] = []; /** * Per default, the current location has a pulsating animation. You can * disable the animation with this property. */ - @property({ attribute: 'disable-animation', type: Boolean }) public disableAnimation?: boolean; + @property({ attribute: 'disable-animation', type: Boolean }) + @forceType(Boolean) + public accessor disableAnimation: boolean = false; /** A configured date which acts as the current date instead of the real current date. Recommended for testing purposes. */ @property() diff --git a/src/elements-experimental/pearl-chain/readme.md b/src/elements-experimental/pearl-chain/readme.md index 5b0cd0cce2c..49acceddd91 100644 --- a/src/elements-experimental/pearl-chain/readme.md +++ b/src/elements-experimental/pearl-chain/readme.md @@ -54,8 +54,8 @@ This is helpful if you need a specific state of the component. ## Properties -| Name | Attribute | Privacy | Type | Default | Description | -| ------------------ | ------------------- | ------- | ----------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `disableAnimation` | `disable-animation` | public | `boolean \| undefined` | | Per default, the current location has a pulsating animation. You can disable the animation with this property. | -| `legs` | `legs` | public | `(Leg \| PtRideLeg)[] \| undefined` | | Define the legs of the pearl-chain. Format: `{"legs": \[{"duration": 25}, ...]}` `duration` in minutes. Duration of the leg is relative to the total travel time. Example: departure 16:30, change at 16:40, arrival at 17:00. So the change should have a duration of 33.33%. | -| `now` | `now` | public | `Date \| null` | `null` | A configured date which acts as the current date instead of the real current date. Recommended for testing purposes. | +| Name | Attribute | Privacy | Type | Default | Description | +| ------------------ | ------------------- | ------- | ---------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `disableAnimation` | `disable-animation` | public | `boolean` | `false` | Per default, the current location has a pulsating animation. You can disable the animation with this property. | +| `legs` | `legs` | public | `(Leg \| PtRideLeg)[]` | `[]` | Define the legs of the pearl-chain. Format: `{"legs": \[{"duration": 25}, ...]}` `duration` in minutes. Duration of the leg is relative to the total travel time. Example: departure 16:30, change at 16:40, arrival at 17:00. So the change should have a duration of 33.33%. | +| `now` | `now` | public | `Date \| null` | `null` | A configured date which acts as the current date instead of the real current date. Recommended for testing purposes. | diff --git a/src/elements-experimental/timetable-duration/readme.md b/src/elements-experimental/timetable-duration/readme.md index 6d94da52588..3111e3570c1 100644 --- a/src/elements-experimental/timetable-duration/readme.md +++ b/src/elements-experimental/timetable-duration/readme.md @@ -7,4 +7,4 @@ here to show the various configuration options to component developers. !! | Name | Attribute | Privacy | Type | Default | Description | | -------- | --------- | ------- | -------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------- | -| `config` | `config` | public | `string` | | Stringified JSON which defines most of the content of the component. Please check the individual stories to get an idea of the structure. | +| `config` | `config` | public | `string` | `''` | Stringified JSON which defines most of the content of the component. Please check the individual stories to get an idea of the structure. | diff --git a/src/elements-experimental/timetable-duration/timetable-duration.ts b/src/elements-experimental/timetable-duration/timetable-duration.ts index 998ca5a149f..ad32d307296 100644 --- a/src/elements-experimental/timetable-duration/timetable-duration.ts +++ b/src/elements-experimental/timetable-duration/timetable-duration.ts @@ -9,8 +9,9 @@ import style from './timetable-duration.scss?lit&inline'; /** * Used in `sbb-timetable-row`, it displays information about the trip duration. */ +export @customElement('sbb-timetable-duration') -export class SbbTimetableDurationElement extends LitElement { +class SbbTimetableDurationElement extends LitElement { public static override styles: CSSResultGroup = style; /** @@ -19,7 +20,7 @@ export class SbbTimetableDurationElement extends LitElement { * individual stories to get an idea of the * structure. */ - @property() public config!: string; + @property() public accessor config: string = ''; private _language = new SbbLanguageController(this); diff --git a/src/elements-experimental/timetable-row/readme.md b/src/elements-experimental/timetable-row/readme.md index 1a776bc3f53..faaf62fa5ae 100644 --- a/src/elements-experimental/timetable-row/readme.md +++ b/src/elements-experimental/timetable-row/readme.md @@ -47,16 +47,16 @@ This is helpful if you need a specific state of the component. ## Properties -| Name | Attribute | Privacy | Type | Default | Description | -| ----------------------- | ------------------------ | ------- | ----------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `a11yFootpath` | `a11y-footpath` | public | `boolean \| undefined` | | The Footpath attribute for rendering different icons true: render a11y-icon false: render walk-icon default: render walk-icon | -| `accessibilityExpanded` | `accessibility-expanded` | public | `boolean \| undefined` | | This will be forwarded to the sbb-card component as aria-expanded. | -| `active` | `active` | public | `boolean \| undefined` | | When this prop is true the sbb-card will be in the active state. | -| `boarding` | `boarding` | public | `Boarding \| undefined` | | This will be forwarded to the notices section | -| `cardActionLabel` | `card-action-label` | public | `string \| undefined` | | Hidden label for the card action. It overrides the automatically generated accessibility text for the component. Use this prop to provide custom accessibility information for the component. | -| `disableAnimation` | `disable-animation` | public | `boolean \| undefined` | | This will be forwarded to the sbb-pearl-chain component - if true the position won't be animated. | -| `loadingPrice` | `loading-price` | public | `boolean` | `false` | The loading state - when this is true it will be render skeleton with an idling animation | -| `loadingTrip` | `loading-trip` | public | `boolean` | `false` | The loading state - when this is true it will be render skeleton with an idling animation | -| `now` | `now` | public | `Date` | `null` | A configured date which acts as the current date instead of the real current date. Recommended for testing purposes. | -| `price` | `price` | public | `Price \| undefined` | | The price Prop, which consists of the data for the badge. | -| `trip` | `trip` | public | `ITripItem` | | The trip Prop. | +| Name | Attribute | Privacy | Type | Default | Description | +| ----------------------- | ------------------------ | ------- | ----------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `a11yFootpath` | `a11y-footpath` | public | `boolean` | `false` | The Footpath attribute for rendering different icons true: render a11y-icon false: render walk-icon default: render walk-icon | +| `accessibilityExpanded` | `accessibility-expanded` | public | `boolean` | `false` | This will be forwarded to the sbb-card component as aria-expanded. | +| `active` | `active` | public | `boolean` | `false` | When this prop is true the sbb-card will be in the active state. | +| `boarding` | `boarding` | public | `Boarding` | `null!` | This will be forwarded to the notices section | +| `cardActionLabel` | `card-action-label` | public | `string` | `''` | Hidden label for the card action. It overrides the automatically generated accessibility text for the component. Use this prop to provide custom accessibility information for the component. | +| `disableAnimation` | `disable-animation` | public | `boolean` | `false` | This will be forwarded to the sbb-pearl-chain component - if true the position won't be animated. | +| `loadingPrice` | `loading-price` | public | `boolean` | `false` | The loading state - when this is true it will be render skeleton with an idling animation | +| `loadingTrip` | `loading-trip` | public | `boolean` | `false` | The loading state - when this is true it will be render skeleton with an idling animation | +| `now` | `now` | public | `Date` | `null` | A configured date which acts as the current date instead of the real current date. Recommended for testing purposes. | +| `price` | `price` | public | `Price` | `null!` | The price Prop, which consists of the data for the badge. | +| `trip` | `trip` | public | `ITripItem` | `null!` | The trip Prop. | diff --git a/src/elements-experimental/timetable-row/timetable-row.ts b/src/elements-experimental/timetable-row/timetable-row.ts index cd0ca8ecd04..ca50d9fee6e 100644 --- a/src/elements-experimental/timetable-row/timetable-row.ts +++ b/src/elements-experimental/timetable-row/timetable-row.ts @@ -1,5 +1,6 @@ import { SbbLanguageController } from '@sbb-esta/lyne-elements/core/controllers.js'; import { defaultDateAdapter } from '@sbb-esta/lyne-elements/core/datetime.js'; +import { forceType } from '@sbb-esta/lyne-elements/core/decorators.js'; import { setOrRemoveAttribute } from '@sbb-esta/lyne-elements/core/dom.js'; import { i18nArrival, @@ -203,28 +204,32 @@ export const handleNotices = (notices: Notice[]): Notice[] => { /** * It displays information about the trip, acting as a container for all the `sbb-timetable-*` components. * */ +export @customElement('sbb-timetable-row') -export class SbbTimetableRowElement extends LitElement { +class SbbTimetableRowElement extends LitElement { public static override styles: CSSResultGroup = style; /** The trip Prop. */ - @property({ type: Object }) public trip!: ITripItem; + @property({ type: Object }) public accessor trip: ITripItem = null!; /** The price Prop, which consists of the data for the badge. */ - @property({ type: Object }) public price?: Price; + @property({ type: Object }) public accessor price: Price = null!; /** This will be forwarded to the sbb-pearl-chain component - if true the position won't be animated. */ @property({ attribute: 'disable-animation', reflect: true, type: Boolean }) - public disableAnimation?: boolean; + @forceType(Boolean) + public accessor disableAnimation: boolean = false; /** This will be forwarded to the notices section */ - @property({ type: Object }) public boarding?: Boarding; + @property({ type: Object }) public accessor boarding: Boarding = null!; /** * The loading state - * when this is true it will be render skeleton with an idling animation */ - @property({ attribute: 'loading-trip', type: Boolean }) public loadingTrip = false; + @property({ attribute: 'loading-trip', type: Boolean }) + @forceType(Boolean) + public accessor loadingTrip: boolean = false; /** * The Footpath attribute for rendering different icons @@ -232,25 +237,30 @@ export class SbbTimetableRowElement extends LitElement { * false: render walk-icon * default: render walk-icon */ - @property({ attribute: 'a11y-footpath', type: Boolean }) public a11yFootpath?: boolean; + @property({ attribute: 'a11y-footpath', type: Boolean }) + @forceType(Boolean) + public accessor a11yFootpath: boolean = false; /** * The loading state - * when this is true it will be render skeleton with an idling animation */ - @property({ attribute: 'loading-price', type: Boolean }) public loadingPrice = false; + @property({ attribute: 'loading-price', type: Boolean }) + @forceType(Boolean) + public accessor loadingPrice: boolean = false; /** * Hidden label for the card action. It overrides the automatically generated accessibility text for the component. Use this prop to provide custom accessibility information for the component. */ - @property({ attribute: 'card-action-label' }) public cardActionLabel?: string; + @property({ attribute: 'card-action-label' }) public accessor cardActionLabel: string = ''; /** This will be forwarded to the sbb-card component as aria-expanded. */ @property({ attribute: 'accessibility-expanded', type: Boolean }) - public accessibilityExpanded?: boolean; + @forceType(Boolean) + public accessor accessibilityExpanded: boolean = false; /** When this prop is true the sbb-card will be in the active state. */ - @property({ type: Boolean }) public active?: boolean; + @property({ type: Boolean }) @forceType(Boolean) public accessor active: boolean = false; /** A configured date which acts as the current date instead of the real current date. Recommended for testing purposes. */ @property() @@ -493,7 +503,7 @@ export class SbbTimetableRowElement extends LitElement { ${this.cardActionLabel ? this.cardActionLabel : this._getAccessibilityText(this.trip)} diff --git a/src/elements-experimental/vite.config.ts b/src/elements-experimental/vite.config.ts index eb387561ca4..d304b2e59ec 100644 --- a/src/elements-experimental/vite.config.ts +++ b/src/elements-experimental/vite.config.ts @@ -62,7 +62,7 @@ export default defineConfig((config) => rollupOptions: { external: (source: string, importer: string | undefined) => { if ( - source.match(/(^lit$|^lit\/|^@lit\/|^@lit-labs\/)/) || + source.match(/(^lit$|^lit\/|^@lit\/|^@lit-labs\/|^tslib$)/) || source.match(/^@sbb-esta\/lyne-elements\/?/) || (!!importer && source.startsWith('../') && !importer.includes('/node_modules/')) || (!!importer && barrelExports.includes(importer) && source.match(/\.\/[a-z-]+/)) diff --git a/src/elements/accordion/accordion.ts b/src/elements/accordion/accordion.ts index edda6ee93e1..f6d31ba495c 100644 --- a/src/elements/accordion/accordion.ts +++ b/src/elements/accordion/accordion.ts @@ -3,6 +3,7 @@ import { html, LitElement } from 'lit'; import { customElement, property } from 'lit/decorators.js'; import { SbbConnectedAbortController } from '../core/controllers.js'; +import { forceType, handleDistinctChange } from '../core/decorators.js'; import { SbbHydrationMixin } from '../core/mixins.js'; import { SbbExpansionPanelElement } from '../expansion-panel.js'; import type { SbbTitleLevel } from '../title.js'; @@ -14,42 +15,28 @@ import style from './accordion.scss?lit&inline'; * * @slot - Use the unnamed slot to add `sbb-expansion-panel` elements. */ +export @customElement('sbb-accordion') -export class SbbAccordionElement extends SbbHydrationMixin(LitElement) { +class SbbAccordionElement extends SbbHydrationMixin(LitElement) { public static override styles: CSSResultGroup = style; /** Size variant, either l or s; overrides the size on any projected `sbb-expansion-panel`. */ - @property({ reflect: true }) public size: 's' | 'l' = 'l'; + @property({ reflect: true }) + public accessor size: 's' | 'l' = 'l'; /** * The heading level for the sbb-expansion-panel-headers within the component. * @controls SbbExpansionPanelElement.titleLevel */ @property({ attribute: 'title-level' }) - public set titleLevel(value: SbbTitleLevel | null) { - this._titleLevel = value; - this._setTitleLevelOnChildren(); - } - public get titleLevel(): SbbTitleLevel | null { - return this._titleLevel; - } - private _titleLevel: SbbTitleLevel | null = null; + @handleDistinctChange((e) => e._setTitleLevelOnChildren()) + public accessor titleLevel: SbbTitleLevel | null = null; /** Whether more than one sbb-expansion-panel can be open at the same time. */ @property({ type: Boolean }) - public set multi(value: boolean) { - const oldValue = this._multi; - this._multi = value; - this._resetExpansionPanels(this._multi, oldValue); - } - public get multi(): boolean { - return this._multi; - } - private _multi: boolean = false; - - private get _expansionPanels(): SbbExpansionPanelElement[] { - return Array.from(this.querySelectorAll?.('sbb-expansion-panel') ?? []); - } + @forceType(Boolean) + @handleDistinctChange((e, newValue, oldValue) => e._resetExpansionPanels(newValue, !!oldValue)) + public accessor multi: boolean = false; private _abort = new SbbConnectedAbortController(this); @@ -63,12 +50,16 @@ export class SbbAccordionElement extends SbbHydrationMixin(LitElement) { ); } + private _expansionPanels(): SbbExpansionPanelElement[] { + return Array.from(this.querySelectorAll?.('sbb-expansion-panel') ?? []); + } + private _closePanels(e: CustomEvent): void { if ((e.target as HTMLElement)?.localName !== 'sbb-expansion-panel' || this.multi) { return; } - this._expansionPanels + this._expansionPanels() .filter((panel) => panel !== e.target) .forEach((panel) => (panel.expanded = false)); } @@ -77,13 +68,15 @@ export class SbbAccordionElement extends SbbHydrationMixin(LitElement) { super.willUpdate(changedProperties); if (changedProperties.has('size')) { - this._expansionPanels.forEach((panel: SbbExpansionPanelElement) => (panel.size = this.size)); + this._expansionPanels().forEach( + (panel: SbbExpansionPanelElement) => (panel.size = this.size), + ); } } private _resetExpansionPanels(newValue: boolean, oldValue: boolean): void { // If it's changing from "multi = true" to "multi = false", open the first panel and close all the others. - const expansionPanels = this._expansionPanels; + const expansionPanels = this._expansionPanels(); if (expansionPanels.length > 1 && oldValue && !newValue) { expansionPanels[0].expanded = true; expansionPanels @@ -93,13 +86,13 @@ export class SbbAccordionElement extends SbbHydrationMixin(LitElement) { } private _setTitleLevelOnChildren(): void { - this._expansionPanels.forEach( + this._expansionPanels().forEach( (panel: SbbExpansionPanelElement) => (panel.titleLevel = this.titleLevel), ); } private _handleSlotchange(): void { - this._expansionPanels.forEach( + this._expansionPanels().forEach( (panel: SbbExpansionPanelElement, index: number, array: SbbExpansionPanelElement[]) => { panel.titleLevel = this.titleLevel; panel.size = this.size; diff --git a/src/elements/action-group/action-group.ts b/src/elements/action-group/action-group.ts index 5f770c85e44..49b7f0332c2 100644 --- a/src/elements/action-group/action-group.ts +++ b/src/elements/action-group/action-group.ts @@ -18,41 +18,42 @@ import style from './action-group.scss?lit&inline'; * * @slot - Use the unnamed slot to add `sbb-block-link` or `sbb-button` elements to the `sbb-action-group`. */ +export @customElement('sbb-action-group') -export class SbbActionGroupElement extends LitElement { +class SbbActionGroupElement extends LitElement { public static override styles: CSSResultGroup = style; /** * Set the slotted `` children's alignment. */ @property({ attribute: 'align-group', reflect: true }) - public alignGroup: 'start' | 'center' | 'stretch' | 'end' = 'start'; + public accessor alignGroup: 'start' | 'center' | 'stretch' | 'end' = 'start'; /** * Overrides the behaviour of `orientation` property. */ @property({ attribute: 'horizontal-from', reflect: true }) - public horizontalFrom: SbbHorizontalFrom = 'medium'; + public accessor horizontalFrom: SbbHorizontalFrom = 'medium'; /** * Indicates the orientation of the components inside the ``. */ @property({ reflect: true }) - public orientation: SbbOrientation = 'horizontal'; + public accessor orientation: SbbOrientation = 'horizontal'; /** * Size of the nested sbb-button instances. This will overwrite the size attribute of nested * sbb-button instances. */ @property({ attribute: 'button-size', reflect: true }) - public buttonSize: SbbButtonSize = 'l'; + public accessor buttonSize: SbbButtonSize = 'l'; /** * Size of the nested sbb-block-link instances. This will overwrite the size attribute of nested * sbb-block-link instances. */ @property({ attribute: 'link-size', reflect: true }) - public linkSize: SbbLinkSize = 'm'; + public accessor linkSize: SbbLinkSize = 'm'; protected override willUpdate(changedProperties: PropertyValues): void { super.willUpdate(changedProperties); diff --git a/src/elements/alert/alert-group/alert-group.ts b/src/elements/alert/alert-group/alert-group.ts index cd48a7b0268..dfda574db52 100644 --- a/src/elements/alert/alert-group/alert-group.ts +++ b/src/elements/alert/alert-group/alert-group.ts @@ -19,8 +19,9 @@ import style from './alert-group.scss?lit&inline'; * @event {CustomEvent} didDismissAlert - Emits when an alert was removed from DOM. * @event {CustomEvent} empty - Emits when `sbb-alert-group` becomes empty. */ +export @customElement('sbb-alert-group') -export class SbbAlertGroupElement extends SbbHydrationMixin(LitElement) { +class SbbAlertGroupElement extends SbbHydrationMixin(LitElement) { public static override styles: CSSResultGroup = style; public static readonly events = { didDismissAlert: 'didDismissAlert', @@ -34,17 +35,17 @@ export class SbbAlertGroupElement extends SbbHydrationMixin(LitElement) { * 'alert': sets aria-live to assertive and aria-atomic to true. */ @property({ reflect: true }) - public override role: 'alert' | 'status' | string = 'status'; + public override accessor role: 'alert' | 'status' | string = 'status'; /** Title for this alert group which is only visible for screen reader users. */ - @property({ attribute: 'accessibility-title' }) public accessibilityTitle?: string; + @property({ attribute: 'accessibility-title' }) public accessor accessibilityTitle: string = ''; /** Level of the accessibility title, will be rendered as heading tag (e.g. h2). Defaults to level 2. */ @property({ attribute: 'accessibility-title-level' }) - public accessibilityTitleLevel: SbbTitleLevel = '2'; + public accessor accessibilityTitleLevel: SbbTitleLevel = '2'; /** Whether the group currently has any alerts. */ - @state() private _hasAlerts?: boolean; + @state() private accessor _hasAlerts: boolean = false; /** Emits when an alert was removed from DOM. */ private _didDismissAlert: EventEmitter = new EventEmitter( diff --git a/src/elements/alert/alert-group/readme.md b/src/elements/alert/alert-group/readme.md index 8bd609bf867..ab440beee0b 100644 --- a/src/elements/alert/alert-group/readme.md +++ b/src/elements/alert/alert-group/readme.md @@ -45,7 +45,7 @@ and therefore interrupts screen reader flow, to immediately read out the alert c | Name | Attribute | Privacy | Type | Default | Description | | ------------------------- | --------------------------- | ------- | ------------------------------- | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `accessibilityTitle` | `accessibility-title` | public | `string \| undefined` | | Title for this alert group which is only visible for screen reader users. | +| `accessibilityTitle` | `accessibility-title` | public | `string` | `''` | Title for this alert group which is only visible for screen reader users. | | `accessibilityTitleLevel` | `accessibility-title-level` | public | `SbbTitleLevel` | `'2'` | Level of the accessibility title, will be rendered as heading tag (e.g. h2). Defaults to level 2. | | `role` | `role` | public | `'alert' \| 'status' \| string` | `'status'` | The role attribute defines how to announce alerts to the user. 'status': sets aria-live to polite and aria-atomic to true. 'alert': sets aria-live to assertive and aria-atomic to true. | diff --git a/src/elements/alert/alert/alert.ts b/src/elements/alert/alert/alert.ts index 5f5349fa2b1..595307b909c 100644 --- a/src/elements/alert/alert/alert.ts +++ b/src/elements/alert/alert/alert.ts @@ -3,6 +3,7 @@ import { customElement, property } from 'lit/decorators.js'; import { type LinkTargetType, SbbOpenCloseBaseElement } from '../../core/base-elements.js'; import { SbbLanguageController } from '../../core/controllers.js'; +import { forceType } from '../../core/decorators.js'; import { EventEmitter } from '../../core/eventing.js'; import { i18nCloseAlert, i18nFindOutMore } from '../../core/i18n.js'; import { SbbIconNameMixin } from '../../icon.js'; @@ -27,8 +28,9 @@ import '../../title.js'; * @event {CustomEvent} didClose - Emits when the closing animation ends. * @event {CustomEvent} dismissalRequested - Emits when dismissal of an alert was requested. */ +export @customElement('sbb-alert') -export class SbbAlertElement extends SbbIconNameMixin(SbbOpenCloseBaseElement) { +class SbbAlertElement extends SbbIconNameMixin(SbbOpenCloseBaseElement) { public static override styles: CSSResultGroup = style; public static override readonly events = { willOpen: 'willOpen', @@ -42,41 +44,49 @@ export class SbbAlertElement extends SbbIconNameMixin(SbbOpenCloseBaseElement) { * Whether the alert is readonly. * In readonly mode, there is no dismiss button offered to the user. */ - @property({ reflect: true, type: Boolean }) public readonly = false; + @property({ reflect: true, type: Boolean }) + @forceType(Boolean) + public accessor readonly: boolean = false; /** You can choose between `s`, `m` or `l` size. */ - @property({ reflect: true }) public size: 's' | 'm' | 'l' = 'm'; + @property({ reflect: true }) public accessor size: 's' | 'm' | 'l' = 'm'; /** * Name of the icon which will be forward to the nested `sbb-icon`. * Choose the icons from https://icons.app.sbb.ch. * Styling is optimized for icons of type HIM-CUS. */ - @property({ attribute: 'icon-name' }) public override iconName: string = 'info'; + @property({ attribute: 'icon-name' }) public override accessor iconName: string = 'info'; /** Content of title. */ - @property({ attribute: 'title-content' }) public titleContent?: string; + @property({ attribute: 'title-content' }) public accessor titleContent: string = ''; /** Level of title, will be rendered as heading tag (e.g. h3). Defaults to level 3. */ - @property({ attribute: 'title-level' }) public titleLevel: SbbTitleLevel = '3'; + @property({ attribute: 'title-level' }) public accessor titleLevel: SbbTitleLevel = '3'; /** Content of the link. */ - @property({ attribute: 'link-content' }) public linkContent?: string; + @property({ attribute: 'link-content' }) public accessor linkContent: string = ''; /** The href value you want to link to. */ - @property() public href: string | undefined; + @property() + @forceType(String) + public accessor href: string = ''; /** Where to display the linked URL. */ - @property() public target: LinkTargetType | string | undefined; + @property() + @forceType(String) + public accessor target: LinkTargetType | string = ''; /** The relationship of the linked URL as space-separated link types. */ - @property() public rel: string | undefined; + @property() + @forceType(String) + public accessor rel: string = ''; /** This will be forwarded as aria-label to the relevant nested element. */ - @property({ attribute: 'accessibility-label' }) public accessibilityLabel: string | undefined; + @property({ attribute: 'accessibility-label' }) public accessor accessibilityLabel: string = ''; /** The enabled animations. */ - @property({ reflect: true }) public animation: 'open' | 'close' | 'all' | 'none' = 'all'; + @property({ reflect: true }) public accessor animation: 'open' | 'close' | 'all' | 'none' = 'all'; /** * Emits when dismissal of an alert was requested. diff --git a/src/elements/alert/alert/readme.md b/src/elements/alert/alert/readme.md index 467620b726a..8bb3c7de4a7 100644 --- a/src/elements/alert/alert/readme.md +++ b/src/elements/alert/alert/readme.md @@ -82,20 +82,20 @@ As a base rule, opening animations should be active if an alert arrives after th ## Properties -| Name | Attribute | Privacy | Type | Default | Description | -| -------------------- | --------------------- | ------- | --------------------------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `accessibilityLabel` | `accessibility-label` | public | `string \| undefined` | | This will be forwarded as aria-label to the relevant nested element. | -| `animation` | `animation` | public | `'open' \| 'close' \| 'all' \| 'none'` | `'all'` | The enabled animations. | -| `href` | `href` | public | `string \| undefined` | | The href value you want to link to. | -| `iconName` | `icon-name` | public | `string \| undefined` | `'info'` | Name of the icon which will be forward to the nested `sbb-icon`. Choose the icons from https://icons.app.sbb.ch. Styling is optimized for icons of type HIM-CUS. | -| `isOpen` | - | public | `boolean` | | Whether the element is open. | -| `linkContent` | `link-content` | public | `string \| undefined` | | Content of the link. | -| `readonly` | `readonly` | public | `boolean` | `false` | Whether the alert is readonly. In readonly mode, there is no dismiss button offered to the user. | -| `rel` | `rel` | public | `string \| undefined` | | The relationship of the linked URL as space-separated link types. | -| `size` | `size` | public | `'s' \| 'm' \| 'l'` | `'m'` | You can choose between `s`, `m` or `l` size. | -| `target` | `target` | public | `LinkTargetType \| string \| undefined` | | Where to display the linked URL. | -| `titleContent` | `title-content` | public | `string \| undefined` | | Content of title. | -| `titleLevel` | `title-level` | public | `SbbTitleLevel` | `'3'` | Level of title, will be rendered as heading tag (e.g. h3). Defaults to level 3. | +| Name | Attribute | Privacy | Type | Default | Description | +| -------------------- | --------------------- | ------- | -------------------------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `accessibilityLabel` | `accessibility-label` | public | `string` | `''` | This will be forwarded as aria-label to the relevant nested element. | +| `animation` | `animation` | public | `'open' \| 'close' \| 'all' \| 'none'` | `'all'` | The enabled animations. | +| `href` | `href` | public | `string` | `''` | The href value you want to link to. | +| `iconName` | `icon-name` | public | `string \| null` | `'info'` | Name of the icon which will be forward to the nested `sbb-icon`. Choose the icons from https://icons.app.sbb.ch. Styling is optimized for icons of type HIM-CUS. | +| `isOpen` | - | public | `boolean` | | Whether the element is open. | +| `linkContent` | `link-content` | public | `string` | `''` | Content of the link. | +| `readonly` | `readonly` | public | `boolean` | `false` | Whether the alert is readonly. In readonly mode, there is no dismiss button offered to the user. | +| `rel` | `rel` | public | `string` | `''` | The relationship of the linked URL as space-separated link types. | +| `size` | `size` | public | `'s' \| 'm' \| 'l'` | `'m'` | You can choose between `s`, `m` or `l` size. | +| `target` | `target` | public | `LinkTargetType \| string` | `''` | Where to display the linked URL. | +| `titleContent` | `title-content` | public | `string` | `''` | Content of title. | +| `titleLevel` | `title-level` | public | `SbbTitleLevel` | `'3'` | Level of title, will be rendered as heading tag (e.g. h3). Defaults to level 3. | ## Methods diff --git a/src/elements/autocomplete-grid/autocomplete-grid-button/__snapshots__/autocomplete-grid-button.snapshot.spec.snap.js b/src/elements/autocomplete-grid/autocomplete-grid-button/__snapshots__/autocomplete-grid-button.snapshot.spec.snap.js index 8dd5e818ab7..2a5ca2c0017 100644 --- a/src/elements/autocomplete-grid/autocomplete-grid-button/__snapshots__/autocomplete-grid-button.snapshot.spec.snap.js +++ b/src/elements/autocomplete-grid/autocomplete-grid-button/__snapshots__/autocomplete-grid-button.snapshot.spec.snap.js @@ -3,7 +3,6 @@ export const snapshots = {}; snapshots["sbb-autocomplete-grid-button renders DOM"] = `): void { super.willUpdate(changedProperties); if (changedProperties.has('disabled')) { - setOrRemoveAttribute(this, 'aria-disabled', `${this.disabled || this._disabledFromGroup}`); + this._updateAriaDisabled(); + } + } + + private _updateAriaDisabled(): void { + if (this.disabled || this._disabledFromGroup) { + this.setAttribute('aria-disabled', 'true'); + } else { + this.removeAttribute('aria-disabled'); } } diff --git a/src/elements/autocomplete-grid/autocomplete-grid-button/readme.md b/src/elements/autocomplete-grid/autocomplete-grid-button/readme.md index efead5ba74a..c045f1e43b9 100644 --- a/src/elements/autocomplete-grid/autocomplete-grid-button/readme.md +++ b/src/elements/autocomplete-grid/autocomplete-grid-button/readme.md @@ -98,7 +98,7 @@ since the focus must always stay on the connected ``. | Name | Attribute | Privacy | Type | Default | Description | | ---------- | ----------- | ------- | ------------------------------------------ | ------- | -------------------------------------------------------------------------------------------------------------------------------- | | `disabled` | `disabled` | public | `boolean` | `false` | Whether the component is disabled. | -| `iconName` | `icon-name` | public | `string \| undefined` | | The icon name we want to use, choose from the small icon variants from the ui-icons category from here https://icons.app.sbb.ch. | +| `iconName` | `icon-name` | public | `string \| null` | `null` | The icon name we want to use, choose from the small icon variants from the ui-icons category from here https://icons.app.sbb.ch. | | `negative` | `negative` | public | `boolean` | `false` | Negative coloring variant flag. | | `option` | - | public | `SbbAutocompleteGridOptionElement \| null` | | Gets the SbbAutocompleteGridOptionElement on the same row of the button. | diff --git a/src/elements/autocomplete-grid/autocomplete-grid-cell/__snapshots__/autocomplete-grid-cell.snapshot.spec.snap.js b/src/elements/autocomplete-grid/autocomplete-grid-cell/__snapshots__/autocomplete-grid-cell.snapshot.spec.snap.js index 1f3d3f632b4..a5e3e5d3e16 100644 --- a/src/elements/autocomplete-grid/autocomplete-grid-cell/__snapshots__/autocomplete-grid-cell.snapshot.spec.snap.js +++ b/src/elements/autocomplete-grid/autocomplete-grid-cell/__snapshots__/autocomplete-grid-cell.snapshot.spec.snap.js @@ -4,7 +4,6 @@ export const snapshots = {}; snapshots["sbb-autocomplete-grid-cell renders DOM"] = ` ): void { super.willUpdate(changedProperties); - if (changedProperties.has('origin')) { - this._resetOriginClickListener(this.origin, changedProperties.get('origin')); - } - if (changedProperties.has('trigger')) { - this._resetTriggerClickListener(this.trigger, changedProperties.get('trigger')); + if ( + (changedProperties.has('origin') && this.origin !== changedProperties.get('origin')) || + (changedProperties.has('trigger') && this.trigger !== changedProperties.get('trigger')) + ) { + this._componentSetup(); } if (changedProperties.has('negative')) { this.syncNegative(); @@ -196,26 +198,6 @@ export abstract class SbbAutocompleteBaseElement extends SbbNegativeMixin( return this.triggerElement?.hasAttribute('readonly') ?? false; } - /** Removes trigger click listener on trigger change. */ - private _resetOriginClickListener( - newValue?: string | HTMLElement, - oldValue?: string | HTMLElement, - ): void { - if (newValue !== oldValue) { - this._componentSetup(); - } - } - - /** Removes trigger click listener on trigger change. */ - private _resetTriggerClickListener( - newValue?: string | HTMLElement, - oldValue?: string | HTMLElement, - ): void { - if (newValue !== oldValue) { - this._componentSetup(); - } - } - private _componentSetup(): void { if (isServer) { return; diff --git a/src/elements/autocomplete/autocomplete.ts b/src/elements/autocomplete/autocomplete.ts index 1150d1c7953..8dc515d30ed 100644 --- a/src/elements/autocomplete/autocomplete.ts +++ b/src/elements/autocomplete/autocomplete.ts @@ -28,11 +28,12 @@ const ariaRoleOnHost = isSafari; * the `z-index` can be overridden by defining this CSS variable. The default `z-index` of the * component is set to `var(--sbb-overlay-default-z-index)` with a value of `1000`. */ +export @customElement('sbb-autocomplete') @hostAttributes({ role: ariaRoleOnHost ? 'listbox' : null, }) -export class SbbAutocompleteElement extends SbbAutocompleteBaseElement { +class SbbAutocompleteElement extends SbbAutocompleteBaseElement { protected overlayId = `sbb-autocomplete-${++nextId}`; protected panelRole = 'listbox'; private _activeItemIndex = -1; diff --git a/src/elements/autocomplete/readme.md b/src/elements/autocomplete/readme.md index 4b1a1efa4cb..aed6f6ef8b6 100644 --- a/src/elements/autocomplete/readme.md +++ b/src/elements/autocomplete/readme.md @@ -111,15 +111,15 @@ using `aria-activedescendant` to support navigation though the autocomplete opti ## Properties -| Name | Attribute | Privacy | Type | Default | Description | -| ------------------- | --------------------- | ------- | ----------------------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `isOpen` | - | public | `boolean` | | Whether the element is open. | -| `negative` | `negative` | public | `boolean` | `false` | Negative coloring variant flag. | -| `origin` | `origin` | public | `string \| HTMLElement \| undefined` | | The element where the autocomplete will attach; accepts both an element's id or an HTMLElement. If not set, it will search for the first 'sbb-form-field' ancestor. | -| `originElement` | - | public | `HTMLElement` | | Returns the element where autocomplete overlay is attached to. | -| `preserveIconSpace` | `preserve-icon-space` | public | `boolean \| undefined` | | Whether the icon space is preserved when no icon is set. | -| `trigger` | `trigger` | public | `string \| HTMLInputElement \| undefined` | | The input element that will trigger the autocomplete opening; accepts both an element's id or an HTMLElement. By default, the autocomplete will open on focus, click, input or `ArrowDown` keypress of the 'trigger' element. If not set, will search for the first 'input' child of a 'sbb-form-field' ancestor. | -| `triggerElement` | - | public | `HTMLInputElement \| undefined` | | Returns the trigger element. | +| Name | Attribute | Privacy | Type | Default | Description | +| ------------------- | --------------------- | ------- | ------------------------------------ | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `isOpen` | - | public | `boolean` | | Whether the element is open. | +| `negative` | `negative` | public | `boolean` | `false` | Negative coloring variant flag. | +| `origin` | `origin` | public | `string \| HTMLElement \| null` | `null` | The element where the autocomplete will attach; accepts both an element's id or an HTMLElement. If not set, it will search for the first 'sbb-form-field' ancestor. | +| `originElement` | - | public | `HTMLElement` | | Returns the element where autocomplete overlay is attached to. | +| `preserveIconSpace` | `preserve-icon-space` | public | `boolean` | `false` | Whether the icon space is preserved when no icon is set. | +| `trigger` | `trigger` | public | `string \| HTMLInputElement \| null` | `null` | The input element that will trigger the autocomplete opening; accepts both an element's id or an HTMLElement. By default, the autocomplete will open on focus, click, input or `ArrowDown` keypress of the 'trigger' element. If not set, will search for the first 'input' child of a 'sbb-form-field' ancestor. | +| `triggerElement` | - | public | `HTMLInputElement \| undefined` | | Returns the trigger element. | ## Methods diff --git a/src/elements/breadcrumb/breadcrumb-group/breadcrumb-group.ts b/src/elements/breadcrumb/breadcrumb-group/breadcrumb-group.ts index b2126a8f764..3e36321920e 100644 --- a/src/elements/breadcrumb/breadcrumb-group/breadcrumb-group.ts +++ b/src/elements/breadcrumb/breadcrumb-group/breadcrumb-group.ts @@ -32,11 +32,12 @@ const MIN_BREADCRUMBS_TO_COLLAPSE = 3; * * @slot - Use the unnamed slot to add `sbb-breadcrumb` elements. */ +export @customElement('sbb-breadcrumb-group') @hostAttributes({ role: 'navigation', }) -export class SbbBreadcrumbGroupElement extends SbbNamedSlotListMixin< +class SbbBreadcrumbGroupElement extends SbbNamedSlotListMixin< SbbBreadcrumbElement, typeof LitElement >(LitElement) { diff --git a/src/elements/breadcrumb/breadcrumb-group/breadcrumb-group.visual.spec.ts b/src/elements/breadcrumb/breadcrumb-group/breadcrumb-group.visual.spec.ts index a5ad0e50978..d8cdcad7d4d 100644 --- a/src/elements/breadcrumb/breadcrumb-group/breadcrumb-group.visual.spec.ts +++ b/src/elements/breadcrumb/breadcrumb-group/breadcrumb-group.visual.spec.ts @@ -29,10 +29,7 @@ describe('sbb-breadcrumb-group', () => { .fill(undefined) .map( (_, i) => - html` Breadcrumb ${i + 1} `, )} diff --git a/src/elements/breadcrumb/breadcrumb/breadcrumb.ts b/src/elements/breadcrumb/breadcrumb/breadcrumb.ts index cdb74b1ccf7..50ba17f4939 100644 --- a/src/elements/breadcrumb/breadcrumb/breadcrumb.ts +++ b/src/elements/breadcrumb/breadcrumb/breadcrumb.ts @@ -14,11 +14,12 @@ import style from './breadcrumb.scss?lit&inline'; * @slot - Use the unnamed slot to add content to the breadcrumb. * @slot icon - Use this to display an icon as breadcrumb. */ +export @customElement('sbb-breadcrumb') -export class SbbBreadcrumbElement extends SbbIconNameMixin(SbbHydrationMixin(SbbLinkBaseElement)) { +class SbbBreadcrumbElement extends SbbIconNameMixin(SbbHydrationMixin(SbbLinkBaseElement)) { public static override styles: CSSResultGroup = style; - @state() private _hasText = false; + @state() private accessor _hasText = false; private _handleSlotchange(): void { this._hasText = Array.from(this.childNodes ?? []).some( diff --git a/src/elements/breadcrumb/breadcrumb/breadcrumb.visual.spec.ts b/src/elements/breadcrumb/breadcrumb/breadcrumb.visual.spec.ts index bda102fd03f..5c1733cdb33 100644 --- a/src/elements/breadcrumb/breadcrumb/breadcrumb.visual.spec.ts +++ b/src/elements/breadcrumb/breadcrumb/breadcrumb.visual.spec.ts @@ -25,8 +25,7 @@ describe('sbb-breadcrumb', () => { ${singleCase.text || nothing} `); @@ -46,7 +45,7 @@ describe('sbb-breadcrumb', () => { describe('slotted icon', () => { beforeEach(async function () { root = await visualRegressionFixture(html` - + Slotted icon @@ -67,12 +66,7 @@ describe('sbb-breadcrumb', () => { beforeEach(async function () { root = await visualRegressionFixture(html`
- + This label name is so long that it needs ellipsis to fit
diff --git a/src/elements/breadcrumb/breadcrumb/readme.md b/src/elements/breadcrumb/breadcrumb/readme.md index 72968e9ffcc..4570d364357 100644 --- a/src/elements/breadcrumb/breadcrumb/readme.md +++ b/src/elements/breadcrumb/breadcrumb/readme.md @@ -39,14 +39,14 @@ By default, the `sbb-breadcrumb-group` component sets `aria-current="page"` on t ## Properties -| Name | Attribute | Privacy | Type | Default | Description | -| -------------------- | --------------------- | ------- | --------------------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------- | -| `accessibilityLabel` | `accessibility-label` | public | `string \| undefined` | | This will be forwarded as aria-label to the inner anchor element. | -| `download` | `download` | public | `boolean \| undefined` | | Whether the browser will show the download dialog on click. | -| `href` | `href` | public | `string \| undefined` | | The href value you want to link to. | -| `iconName` | `icon-name` | public | `string \| undefined` | | The icon name we want to use, choose from the small icon variants from the ui-icons category from here https://icons.app.sbb.ch. | -| `rel` | `rel` | public | `string \| undefined` | | The relationship of the linked URL as space-separated link types. | -| `target` | `target` | public | `LinkTargetType \| string \| undefined` | | Where to display the linked URL. | +| Name | Attribute | Privacy | Type | Default | Description | +| -------------------- | --------------------- | ------- | -------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------- | +| `accessibilityLabel` | `accessibility-label` | public | `string` | `''` | This will be forwarded as aria-label to the inner anchor element. | +| `download` | `download` | public | `boolean` | `false` | Whether the browser will show the download dialog on click. | +| `href` | `href` | public | `string` | `''` | The href value you want to link to. | +| `iconName` | `icon-name` | public | `string \| null` | `null` | The icon name we want to use, choose from the small icon variants from the ui-icons category from here https://icons.app.sbb.ch. | +| `rel` | `rel` | public | `string` | `''` | The relationship of the linked URL as space-separated link types. | +| `target` | `target` | public | `LinkTargetType \| string` | `''` | Where to display the linked URL. | ## Slots diff --git a/src/elements/button/button-link/button-link.ts b/src/elements/button/button-link/button-link.ts index 714f34ee342..6b0a43165c5 100644 --- a/src/elements/button/button-link/button-link.ts +++ b/src/elements/button/button-link/button-link.ts @@ -11,8 +11,9 @@ import { buttonCommonStyle, buttonPrimaryStyle, SbbButtonCommonElementMixin } fr * @slot - Use the unnamed slot to add content to the button-link. * @slot icon - Slot used to display the icon, if one is set */ +export @customElement('sbb-button-link') -export class SbbButtonLinkElement extends SbbButtonCommonElementMixin( +class SbbButtonLinkElement extends SbbButtonCommonElementMixin( SbbDisabledInteractiveMixin(SbbDisabledMixin(SbbLinkBaseElement)), ) { public static override styles: CSSResultGroup = [buttonCommonStyle, buttonPrimaryStyle]; diff --git a/src/elements/button/button-link/readme.md b/src/elements/button/button-link/readme.md index ab5728e234e..75f68438798 100644 --- a/src/elements/button/button-link/readme.md +++ b/src/elements/button/button-link/readme.md @@ -72,18 +72,18 @@ Use the accessibility properties in case of an icon-only button to describe the ## Properties -| Name | Attribute | Privacy | Type | Default | Description | -| --------------------- | ---------------------- | ------- | --------------------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------- | -| `accessibilityLabel` | `accessibility-label` | public | `string \| undefined` | | This will be forwarded as aria-label to the inner anchor element. | -| `disabled` | `disabled` | public | `boolean` | `false` | Whether the component is disabled. | -| `disabledInteractive` | `disabled-interactive` | public | `boolean` | `false` | Whether disabled buttons should be interactive. | -| `download` | `download` | public | `boolean \| undefined` | | Whether the browser will show the download dialog on click. | -| `href` | `href` | public | `string \| undefined` | | The href value you want to link to. | -| `iconName` | `icon-name` | public | `string \| undefined` | | The icon name we want to use, choose from the small icon variants from the ui-icons category from here https://icons.app.sbb.ch. | -| `negative` | `negative` | public | `boolean` | `false` | Negative coloring variant flag. | -| `rel` | `rel` | public | `string \| undefined` | | The relationship of the linked URL as space-separated link types. | -| `size` | `size` | public | `SbbButtonSize \| undefined` | `'l'` | Size variant, either l or m. | -| `target` | `target` | public | `LinkTargetType \| string \| undefined` | | Where to display the linked URL. | +| Name | Attribute | Privacy | Type | Default | Description | +| --------------------- | ---------------------- | ------- | -------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------- | +| `accessibilityLabel` | `accessibility-label` | public | `string` | `''` | This will be forwarded as aria-label to the inner anchor element. | +| `disabled` | `disabled` | public | `boolean` | `false` | Whether the component is disabled. | +| `disabledInteractive` | `disabled-interactive` | public | `boolean` | `false` | Whether disabled buttons should be interactive. | +| `download` | `download` | public | `boolean` | `false` | Whether the browser will show the download dialog on click. | +| `href` | `href` | public | `string` | `''` | The href value you want to link to. | +| `iconName` | `icon-name` | public | `string \| null` | `null` | The icon name we want to use, choose from the small icon variants from the ui-icons category from here https://icons.app.sbb.ch. | +| `negative` | `negative` | public | `boolean` | `false` | Negative coloring variant flag. | +| `rel` | `rel` | public | `string` | `''` | The relationship of the linked URL as space-separated link types. | +| `size` | `size` | public | `SbbButtonSize` | `'l'` | Size variant, either l or m. | +| `target` | `target` | public | `LinkTargetType \| string` | `''` | Where to display the linked URL. | ## Slots diff --git a/src/elements/button/button-static/button-static.ts b/src/elements/button/button-static/button-static.ts index aa31b7180e9..7f37ef8b82d 100644 --- a/src/elements/button/button-static/button-static.ts +++ b/src/elements/button/button-static/button-static.ts @@ -11,8 +11,9 @@ import { buttonCommonStyle, buttonPrimaryStyle, SbbButtonCommonElementMixin } fr * @slot - Use the unnamed slot to add content to the button-static. * @slot icon - Slot used to display the icon, if one is set */ +export @customElement('sbb-button-static') -export class SbbButtonStaticElement extends SbbButtonCommonElementMixin( +class SbbButtonStaticElement extends SbbButtonCommonElementMixin( SbbDisabledMixin(SbbActionBaseElement), ) { public static override styles: CSSResultGroup = [buttonCommonStyle, buttonPrimaryStyle]; diff --git a/src/elements/button/button-static/readme.md b/src/elements/button/button-static/readme.md index ae08037ffe4..24afe6c7af7 100644 --- a/src/elements/button/button-static/readme.md +++ b/src/elements/button/button-static/readme.md @@ -57,12 +57,12 @@ Use the accessibility properties in case of an icon-only button to describe the ## Properties -| Name | Attribute | Privacy | Type | Default | Description | -| ---------- | ----------- | ------- | ---------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------- | -| `disabled` | `disabled` | public | `boolean` | `false` | Whether the component is disabled. | -| `iconName` | `icon-name` | public | `string \| undefined` | | The icon name we want to use, choose from the small icon variants from the ui-icons category from here https://icons.app.sbb.ch. | -| `negative` | `negative` | public | `boolean` | `false` | Negative coloring variant flag. | -| `size` | `size` | public | `SbbButtonSize \| undefined` | `'l'` | Size variant, either l or m. | +| Name | Attribute | Privacy | Type | Default | Description | +| ---------- | ----------- | ------- | ---------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------- | +| `disabled` | `disabled` | public | `boolean` | `false` | Whether the component is disabled. | +| `iconName` | `icon-name` | public | `string \| null` | `null` | The icon name we want to use, choose from the small icon variants from the ui-icons category from here https://icons.app.sbb.ch. | +| `negative` | `negative` | public | `boolean` | `false` | Negative coloring variant flag. | +| `size` | `size` | public | `SbbButtonSize` | `'l'` | Size variant, either l or m. | ## Slots diff --git a/src/elements/button/button/button.ts b/src/elements/button/button/button.ts index f956f868288..4eb978e88db 100644 --- a/src/elements/button/button/button.ts +++ b/src/elements/button/button/button.ts @@ -11,8 +11,9 @@ import { buttonCommonStyle, buttonPrimaryStyle, SbbButtonCommonElementMixin } fr * @slot - Use the unnamed slot to add content to the button. * @slot icon - Slot used to display the icon, if one is set */ +export @customElement('sbb-button') -export class SbbButtonElement extends SbbButtonCommonElementMixin( +class SbbButtonElement extends SbbButtonCommonElementMixin( SbbDisabledTabIndexActionMixin(SbbButtonBaseElement), ) { public static override styles: CSSResultGroup = [buttonCommonStyle, buttonPrimaryStyle]; diff --git a/src/elements/button/button/readme.md b/src/elements/button/button/readme.md index f1894686c5c..cadf2af40b3 100644 --- a/src/elements/button/button/readme.md +++ b/src/elements/button/button/readme.md @@ -79,17 +79,17 @@ guard against such cases in your component. ## Properties -| Name | Attribute | Privacy | Type | Default | Description | -| --------------------- | ---------------------- | ------- | ---------------------------- | ---------- | -------------------------------------------------------------------------------------------------------------------------------- | -| `disabled` | `disabled` | public | `boolean` | `false` | Whether the component is disabled. | -| `disabledInteractive` | `disabled-interactive` | public | `boolean` | `false` | Whether disabled buttons should be interactive. | -| `form` | `form` | public | `string \| undefined` | | The
element to associate the button with. | -| `iconName` | `icon-name` | public | `string \| undefined` | | The icon name we want to use, choose from the small icon variants from the ui-icons category from here https://icons.app.sbb.ch. | -| `name` | `name` | public | `string` | | The name of the button element. | -| `negative` | `negative` | public | `boolean` | `false` | Negative coloring variant flag. | -| `size` | `size` | public | `SbbButtonSize \| undefined` | `'l'` | Size variant, either l or m. | -| `type` | `type` | public | `SbbButtonType` | `'button'` | The type attribute to use for the button. | -| `value` | `value` | public | `string` | | The value of the button element. | +| Name | Attribute | Privacy | Type | Default | Description | +| --------------------- | ---------------------- | ------- | ---------------- | ---------- | -------------------------------------------------------------------------------------------------------------------------------- | +| `disabled` | `disabled` | public | `boolean` | `false` | Whether the component is disabled. | +| `disabledInteractive` | `disabled-interactive` | public | `boolean` | `false` | Whether disabled buttons should be interactive. | +| `form` | `form` | public | `string` | `''` | The element to associate the button with. | +| `iconName` | `icon-name` | public | `string \| null` | `null` | The icon name we want to use, choose from the small icon variants from the ui-icons category from here https://icons.app.sbb.ch. | +| `name` | `name` | public | `string` | | The name of the button element. | +| `negative` | `negative` | public | `boolean` | `false` | Negative coloring variant flag. | +| `size` | `size` | public | `SbbButtonSize` | `'l'` | Size variant, either l or m. | +| `type` | `type` | public | `SbbButtonType` | `'button'` | The type attribute to use for the button. | +| `value` | `value` | public | `string` | | The value of the button element. | ## Slots diff --git a/src/elements/button/common/button-common.ts b/src/elements/button/common/button-common.ts index 31e8317447b..fa6b208b0d9 100644 --- a/src/elements/button/common/button-common.ts +++ b/src/elements/button/common/button-common.ts @@ -19,10 +19,10 @@ export type SbbButtonSize = 'l' | 'm' | 's'; export declare class SbbButtonCommonElementMixinType implements SbbNegativeMixinType, Partial, Partial { - public size?: SbbButtonSize; - public disabled: boolean; - public iconName?: string; - public negative: boolean; + public accessor size: SbbButtonSize; + public accessor disabled: boolean; + public accessor iconName: string | null; + public accessor negative: boolean; } // eslint-disable-next-line @typescript-eslint/naming-convention @@ -38,7 +38,7 @@ export const SbbButtonCommonElementMixin = { /** Size variant, either l or m. */ - @property({ reflect: true }) public size?: SbbButtonSize = 'l'; + @property({ reflect: true }) public accessor size: SbbButtonSize = 'l'; protected override renderTemplate(): TemplateResult { return html` diff --git a/src/elements/button/mini-button-group/mini-button-group.ts b/src/elements/button/mini-button-group/mini-button-group.ts index ddcf9a30b68..8ae0c39becd 100644 --- a/src/elements/button/mini-button-group/mini-button-group.ts +++ b/src/elements/button/mini-button-group/mini-button-group.ts @@ -16,18 +16,19 @@ export type SbbMiniButtonGroupSize = 's' | 'm' | 'l' | 'xl'; * * @slot - Use the unnamed slot to add `sbb-mini-button` and `sbb-divider` elements. */ +export @customElement('sbb-mini-button-group') -export class SbbMiniButtonGroupElement extends SbbNegativeMixin( +class SbbMiniButtonGroupElement extends SbbNegativeMixin( SbbNamedSlotListMixin(LitElement), ) { public static override styles: CSSResultGroup = style; protected override readonly listChildLocalNames = ['sbb-mini-button', 'sbb-divider']; /** This will be forwarded as aria-label to the list that contains the buttons. */ - @property({ attribute: 'accessibility-label' }) public accessibilityLabel?: string; + @property({ attribute: 'accessibility-label' }) public accessor accessibilityLabel: string = ''; /** Size variant, either s, m, l or xl. */ - @property({ reflect: true }) public size: SbbMiniButtonGroupSize = 'm'; + @property({ reflect: true }) public accessor size: SbbMiniButtonGroupSize = 'm'; protected override willUpdate(changedProperties: PropertyValues): void { super.willUpdate(changedProperties); diff --git a/src/elements/button/mini-button-group/readme.md b/src/elements/button/mini-button-group/readme.md index 40cf0f3eea0..cdc7b7368dd 100644 --- a/src/elements/button/mini-button-group/readme.md +++ b/src/elements/button/mini-button-group/readme.md @@ -33,7 +33,7 @@ to ensure that the button list is read by screen readers with the correct size. | Name | Attribute | Privacy | Type | Default | Description | | -------------------- | --------------------- | ------- | ------------------------ | ------- | --------------------------------------------------------------------------- | -| `accessibilityLabel` | `accessibility-label` | public | `string \| undefined` | | This will be forwarded as aria-label to the list that contains the buttons. | +| `accessibilityLabel` | `accessibility-label` | public | `string` | `''` | This will be forwarded as aria-label to the list that contains the buttons. | | `negative` | `negative` | public | `boolean` | `false` | Negative coloring variant flag. | | `size` | `size` | public | `SbbMiniButtonGroupSize` | `'m'` | Size variant, either s, m, l or xl. | diff --git a/src/elements/button/mini-button/mini-button-base-element.ts b/src/elements/button/mini-button/mini-button-base-element.ts index 7d498911ca7..31a57fda417 100644 --- a/src/elements/button/mini-button/mini-button-base-element.ts +++ b/src/elements/button/mini-button/mini-button-base-element.ts @@ -5,8 +5,9 @@ import { slotState } from '../../core/decorators.js'; import { SbbNegativeMixin } from '../../core/mixins.js'; import { SbbIconNameMixin } from '../../icon.js'; +export @slotState() -export abstract class SbbMiniButtonBaseElement extends SbbNegativeMixin( +abstract class SbbMiniButtonBaseElement extends SbbNegativeMixin( SbbIconNameMixin(SbbButtonBaseElement), ) { protected override renderTemplate(): TemplateResult { diff --git a/src/elements/button/mini-button/mini-button.ts b/src/elements/button/mini-button/mini-button.ts index a7fd7bb56f0..c4ce6c4f715 100644 --- a/src/elements/button/mini-button/mini-button.ts +++ b/src/elements/button/mini-button/mini-button.ts @@ -12,8 +12,9 @@ import style from './mini-button.scss?lit&inline'; * * @slot icon - Slot used to display the icon, if one is set */ +export @customElement('sbb-mini-button') -export class SbbMiniButtonElement extends SbbDisabledTabIndexActionMixin(SbbMiniButtonBaseElement) { +class SbbMiniButtonElement extends SbbDisabledTabIndexActionMixin(SbbMiniButtonBaseElement) { public static override styles: CSSResultGroup = style; } diff --git a/src/elements/button/mini-button/readme.md b/src/elements/button/mini-button/readme.md index 8029cbd66d5..54e2ac403c7 100644 --- a/src/elements/button/mini-button/readme.md +++ b/src/elements/button/mini-button/readme.md @@ -87,16 +87,16 @@ guard against such cases in your component. ## Properties -| Name | Attribute | Privacy | Type | Default | Description | -| --------------------- | ---------------------- | ------- | --------------------- | ---------- | -------------------------------------------------------------------------------------------------------------------------------- | -| `disabled` | `disabled` | public | `boolean` | `false` | Whether the component is disabled. | -| `disabledInteractive` | `disabled-interactive` | public | `boolean` | `false` | Whether disabled buttons should be interactive. | -| `form` | `form` | public | `string \| undefined` | | The element to associate the button with. | -| `iconName` | `icon-name` | public | `string \| undefined` | | The icon name we want to use, choose from the small icon variants from the ui-icons category from here https://icons.app.sbb.ch. | -| `name` | `name` | public | `string` | | The name of the button element. | -| `negative` | `negative` | public | `boolean` | `false` | Negative coloring variant flag. | -| `type` | `type` | public | `SbbButtonType` | `'button'` | The type attribute to use for the button. | -| `value` | `value` | public | `string` | | The value of the button element. | +| Name | Attribute | Privacy | Type | Default | Description | +| --------------------- | ---------------------- | ------- | ---------------- | ---------- | -------------------------------------------------------------------------------------------------------------------------------- | +| `disabled` | `disabled` | public | `boolean` | `false` | Whether the component is disabled. | +| `disabledInteractive` | `disabled-interactive` | public | `boolean` | `false` | Whether disabled buttons should be interactive. | +| `form` | `form` | public | `string` | `''` | The element to associate the button with. | +| `iconName` | `icon-name` | public | `string \| null` | `null` | The icon name we want to use, choose from the small icon variants from the ui-icons category from here https://icons.app.sbb.ch. | +| `name` | `name` | public | `string` | | The name of the button element. | +| `negative` | `negative` | public | `boolean` | `false` | Negative coloring variant flag. | +| `type` | `type` | public | `SbbButtonType` | `'button'` | The type attribute to use for the button. | +| `value` | `value` | public | `string` | | The value of the button element. | ## Slots diff --git a/src/elements/button/secondary-button-link/readme.md b/src/elements/button/secondary-button-link/readme.md index 3fa66b7b584..39337876092 100644 --- a/src/elements/button/secondary-button-link/readme.md +++ b/src/elements/button/secondary-button-link/readme.md @@ -77,18 +77,18 @@ Use the accessibility properties in case of an icon-only button to describe the ## Properties -| Name | Attribute | Privacy | Type | Default | Description | -| --------------------- | ---------------------- | ------- | --------------------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------- | -| `accessibilityLabel` | `accessibility-label` | public | `string \| undefined` | | This will be forwarded as aria-label to the inner anchor element. | -| `disabled` | `disabled` | public | `boolean` | `false` | Whether the component is disabled. | -| `disabledInteractive` | `disabled-interactive` | public | `boolean` | `false` | Whether disabled buttons should be interactive. | -| `download` | `download` | public | `boolean \| undefined` | | Whether the browser will show the download dialog on click. | -| `href` | `href` | public | `string \| undefined` | | The href value you want to link to. | -| `iconName` | `icon-name` | public | `string \| undefined` | | The icon name we want to use, choose from the small icon variants from the ui-icons category from here https://icons.app.sbb.ch. | -| `negative` | `negative` | public | `boolean` | `false` | Negative coloring variant flag. | -| `rel` | `rel` | public | `string \| undefined` | | The relationship of the linked URL as space-separated link types. | -| `size` | `size` | public | `SbbButtonSize \| undefined` | `'l'` | Size variant, either l or m. | -| `target` | `target` | public | `LinkTargetType \| string \| undefined` | | Where to display the linked URL. | +| Name | Attribute | Privacy | Type | Default | Description | +| --------------------- | ---------------------- | ------- | -------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------- | +| `accessibilityLabel` | `accessibility-label` | public | `string` | `''` | This will be forwarded as aria-label to the inner anchor element. | +| `disabled` | `disabled` | public | `boolean` | `false` | Whether the component is disabled. | +| `disabledInteractive` | `disabled-interactive` | public | `boolean` | `false` | Whether disabled buttons should be interactive. | +| `download` | `download` | public | `boolean` | `false` | Whether the browser will show the download dialog on click. | +| `href` | `href` | public | `string` | `''` | The href value you want to link to. | +| `iconName` | `icon-name` | public | `string \| null` | `null` | The icon name we want to use, choose from the small icon variants from the ui-icons category from here https://icons.app.sbb.ch. | +| `negative` | `negative` | public | `boolean` | `false` | Negative coloring variant flag. | +| `rel` | `rel` | public | `string` | `''` | The relationship of the linked URL as space-separated link types. | +| `size` | `size` | public | `SbbButtonSize` | `'l'` | Size variant, either l or m. | +| `target` | `target` | public | `LinkTargetType \| string` | `''` | Where to display the linked URL. | ## Slots diff --git a/src/elements/button/secondary-button-link/secondary-button-link.ts b/src/elements/button/secondary-button-link/secondary-button-link.ts index b3893acfad0..499cf3357a7 100644 --- a/src/elements/button/secondary-button-link/secondary-button-link.ts +++ b/src/elements/button/secondary-button-link/secondary-button-link.ts @@ -11,8 +11,9 @@ import { buttonCommonStyle, buttonSecondaryStyle, SbbButtonCommonElementMixin } * @slot - Use the unnamed slot to add content to the secondary-button-link. * @slot icon - Slot used to display the icon, if one is set */ +export @customElement('sbb-secondary-button-link') -export class SbbSecondaryButtonLinkElement extends SbbButtonCommonElementMixin( +class SbbSecondaryButtonLinkElement extends SbbButtonCommonElementMixin( SbbDisabledInteractiveMixin(SbbDisabledMixin(SbbLinkBaseElement)), ) { public static override styles: CSSResultGroup = [buttonCommonStyle, buttonSecondaryStyle]; diff --git a/src/elements/button/secondary-button-static/readme.md b/src/elements/button/secondary-button-static/readme.md index 17d1919cf99..6f983e56af7 100644 --- a/src/elements/button/secondary-button-static/readme.md +++ b/src/elements/button/secondary-button-static/readme.md @@ -60,12 +60,12 @@ Use the accessibility properties in case of an icon-only button to describe the ## Properties -| Name | Attribute | Privacy | Type | Default | Description | -| ---------- | ----------- | ------- | ---------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------- | -| `disabled` | `disabled` | public | `boolean` | `false` | Whether the component is disabled. | -| `iconName` | `icon-name` | public | `string \| undefined` | | The icon name we want to use, choose from the small icon variants from the ui-icons category from here https://icons.app.sbb.ch. | -| `negative` | `negative` | public | `boolean` | `false` | Negative coloring variant flag. | -| `size` | `size` | public | `SbbButtonSize \| undefined` | `'l'` | Size variant, either l or m. | +| Name | Attribute | Privacy | Type | Default | Description | +| ---------- | ----------- | ------- | ---------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------- | +| `disabled` | `disabled` | public | `boolean` | `false` | Whether the component is disabled. | +| `iconName` | `icon-name` | public | `string \| null` | `null` | The icon name we want to use, choose from the small icon variants from the ui-icons category from here https://icons.app.sbb.ch. | +| `negative` | `negative` | public | `boolean` | `false` | Negative coloring variant flag. | +| `size` | `size` | public | `SbbButtonSize` | `'l'` | Size variant, either l or m. | ## Slots diff --git a/src/elements/button/secondary-button-static/secondary-button-static.ts b/src/elements/button/secondary-button-static/secondary-button-static.ts index d64ec051044..c908687cc0a 100644 --- a/src/elements/button/secondary-button-static/secondary-button-static.ts +++ b/src/elements/button/secondary-button-static/secondary-button-static.ts @@ -11,8 +11,9 @@ import { buttonCommonStyle, buttonSecondaryStyle, SbbButtonCommonElementMixin } * @slot - Use the unnamed slot to add content to the secondary-button-static. * @slot icon - Slot used to display the icon, if one is set */ +export @customElement('sbb-secondary-button-static') -export class SbbSecondaryButtonStaticElement extends SbbButtonCommonElementMixin( +class SbbSecondaryButtonStaticElement extends SbbButtonCommonElementMixin( SbbDisabledMixin(SbbActionBaseElement), ) { public static override styles: CSSResultGroup = [buttonCommonStyle, buttonSecondaryStyle]; diff --git a/src/elements/button/secondary-button/readme.md b/src/elements/button/secondary-button/readme.md index 1797f3daa04..90e95d15db7 100644 --- a/src/elements/button/secondary-button/readme.md +++ b/src/elements/button/secondary-button/readme.md @@ -84,17 +84,17 @@ guard against such cases in your component. ## Properties -| Name | Attribute | Privacy | Type | Default | Description | -| --------------------- | ---------------------- | ------- | ---------------------------- | ---------- | -------------------------------------------------------------------------------------------------------------------------------- | -| `disabled` | `disabled` | public | `boolean` | `false` | Whether the component is disabled. | -| `disabledInteractive` | `disabled-interactive` | public | `boolean` | `false` | Whether disabled buttons should be interactive. | -| `form` | `form` | public | `string \| undefined` | | The element to associate the button with. | -| `iconName` | `icon-name` | public | `string \| undefined` | | The icon name we want to use, choose from the small icon variants from the ui-icons category from here https://icons.app.sbb.ch. | -| `name` | `name` | public | `string` | | The name of the button element. | -| `negative` | `negative` | public | `boolean` | `false` | Negative coloring variant flag. | -| `size` | `size` | public | `SbbButtonSize \| undefined` | `'l'` | Size variant, either l or m. | -| `type` | `type` | public | `SbbButtonType` | `'button'` | The type attribute to use for the button. | -| `value` | `value` | public | `string` | | The value of the button element. | +| Name | Attribute | Privacy | Type | Default | Description | +| --------------------- | ---------------------- | ------- | ---------------- | ---------- | -------------------------------------------------------------------------------------------------------------------------------- | +| `disabled` | `disabled` | public | `boolean` | `false` | Whether the component is disabled. | +| `disabledInteractive` | `disabled-interactive` | public | `boolean` | `false` | Whether disabled buttons should be interactive. | +| `form` | `form` | public | `string` | `''` | The element to associate the button with. | +| `iconName` | `icon-name` | public | `string \| null` | `null` | The icon name we want to use, choose from the small icon variants from the ui-icons category from here https://icons.app.sbb.ch. | +| `name` | `name` | public | `string` | | The name of the button element. | +| `negative` | `negative` | public | `boolean` | `false` | Negative coloring variant flag. | +| `size` | `size` | public | `SbbButtonSize` | `'l'` | Size variant, either l or m. | +| `type` | `type` | public | `SbbButtonType` | `'button'` | The type attribute to use for the button. | +| `value` | `value` | public | `string` | | The value of the button element. | ## Slots diff --git a/src/elements/button/secondary-button/secondary-button.ts b/src/elements/button/secondary-button/secondary-button.ts index 415f2d3cdba..67b09e06faa 100644 --- a/src/elements/button/secondary-button/secondary-button.ts +++ b/src/elements/button/secondary-button/secondary-button.ts @@ -11,8 +11,9 @@ import { buttonCommonStyle, buttonSecondaryStyle, SbbButtonCommonElementMixin } * @slot - Use the unnamed slot to add content to the secondary-button. * @slot icon - Slot used to display the icon, if one is set */ +export @customElement('sbb-secondary-button') -export class SbbSecondaryButtonElement extends SbbButtonCommonElementMixin( +class SbbSecondaryButtonElement extends SbbButtonCommonElementMixin( SbbDisabledTabIndexActionMixin(SbbButtonBaseElement), ) { public static override styles: CSSResultGroup = [buttonCommonStyle, buttonSecondaryStyle]; diff --git a/src/elements/button/tertiary-button-link/readme.md b/src/elements/button/tertiary-button-link/readme.md index f0305783e11..86ca96e48c0 100644 --- a/src/elements/button/tertiary-button-link/readme.md +++ b/src/elements/button/tertiary-button-link/readme.md @@ -77,18 +77,18 @@ Use the accessibility properties in case of an icon-only button to describe the ## Properties -| Name | Attribute | Privacy | Type | Default | Description | -| --------------------- | ---------------------- | ------- | --------------------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------- | -| `accessibilityLabel` | `accessibility-label` | public | `string \| undefined` | | This will be forwarded as aria-label to the inner anchor element. | -| `disabled` | `disabled` | public | `boolean` | `false` | Whether the component is disabled. | -| `disabledInteractive` | `disabled-interactive` | public | `boolean` | `false` | Whether disabled buttons should be interactive. | -| `download` | `download` | public | `boolean \| undefined` | | Whether the browser will show the download dialog on click. | -| `href` | `href` | public | `string \| undefined` | | The href value you want to link to. | -| `iconName` | `icon-name` | public | `string \| undefined` | | The icon name we want to use, choose from the small icon variants from the ui-icons category from here https://icons.app.sbb.ch. | -| `negative` | `negative` | public | `boolean` | `false` | Negative coloring variant flag. | -| `rel` | `rel` | public | `string \| undefined` | | The relationship of the linked URL as space-separated link types. | -| `size` | `size` | public | `SbbButtonSize \| undefined` | `'l'` | Size variant, either l or m. | -| `target` | `target` | public | `LinkTargetType \| string \| undefined` | | Where to display the linked URL. | +| Name | Attribute | Privacy | Type | Default | Description | +| --------------------- | ---------------------- | ------- | -------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------- | +| `accessibilityLabel` | `accessibility-label` | public | `string` | `''` | This will be forwarded as aria-label to the inner anchor element. | +| `disabled` | `disabled` | public | `boolean` | `false` | Whether the component is disabled. | +| `disabledInteractive` | `disabled-interactive` | public | `boolean` | `false` | Whether disabled buttons should be interactive. | +| `download` | `download` | public | `boolean` | `false` | Whether the browser will show the download dialog on click. | +| `href` | `href` | public | `string` | `''` | The href value you want to link to. | +| `iconName` | `icon-name` | public | `string \| null` | `null` | The icon name we want to use, choose from the small icon variants from the ui-icons category from here https://icons.app.sbb.ch. | +| `negative` | `negative` | public | `boolean` | `false` | Negative coloring variant flag. | +| `rel` | `rel` | public | `string` | `''` | The relationship of the linked URL as space-separated link types. | +| `size` | `size` | public | `SbbButtonSize` | `'l'` | Size variant, either l or m. | +| `target` | `target` | public | `LinkTargetType \| string` | `''` | Where to display the linked URL. | ## Slots diff --git a/src/elements/button/tertiary-button-link/tertiary-button-link.ts b/src/elements/button/tertiary-button-link/tertiary-button-link.ts index 72cfba79d2c..fe9d4b58105 100644 --- a/src/elements/button/tertiary-button-link/tertiary-button-link.ts +++ b/src/elements/button/tertiary-button-link/tertiary-button-link.ts @@ -11,8 +11,9 @@ import { buttonCommonStyle, buttonTertiaryStyle, SbbButtonCommonElementMixin } f * @slot - Use the unnamed slot to add content to the tertiary-button-link. * @slot icon - Slot used to display the icon, if one is set */ +export @customElement('sbb-tertiary-button-link') -export class SbbTertiaryButtonLinkElement extends SbbButtonCommonElementMixin( +class SbbTertiaryButtonLinkElement extends SbbButtonCommonElementMixin( SbbDisabledInteractiveMixin(SbbDisabledMixin(SbbLinkBaseElement)), ) { public static override styles: CSSResultGroup = [buttonCommonStyle, buttonTertiaryStyle]; diff --git a/src/elements/button/tertiary-button-static/readme.md b/src/elements/button/tertiary-button-static/readme.md index 3154833eeaa..f45323cc156 100644 --- a/src/elements/button/tertiary-button-static/readme.md +++ b/src/elements/button/tertiary-button-static/readme.md @@ -60,12 +60,12 @@ Use the accessibility properties in case of an icon-only button to describe the ## Properties -| Name | Attribute | Privacy | Type | Default | Description | -| ---------- | ----------- | ------- | ---------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------- | -| `disabled` | `disabled` | public | `boolean` | `false` | Whether the component is disabled. | -| `iconName` | `icon-name` | public | `string \| undefined` | | The icon name we want to use, choose from the small icon variants from the ui-icons category from here https://icons.app.sbb.ch. | -| `negative` | `negative` | public | `boolean` | `false` | Negative coloring variant flag. | -| `size` | `size` | public | `SbbButtonSize \| undefined` | `'l'` | Size variant, either l or m. | +| Name | Attribute | Privacy | Type | Default | Description | +| ---------- | ----------- | ------- | ---------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------- | +| `disabled` | `disabled` | public | `boolean` | `false` | Whether the component is disabled. | +| `iconName` | `icon-name` | public | `string \| null` | `null` | The icon name we want to use, choose from the small icon variants from the ui-icons category from here https://icons.app.sbb.ch. | +| `negative` | `negative` | public | `boolean` | `false` | Negative coloring variant flag. | +| `size` | `size` | public | `SbbButtonSize` | `'l'` | Size variant, either l or m. | ## Slots diff --git a/src/elements/button/tertiary-button-static/tertiary-button-static.ts b/src/elements/button/tertiary-button-static/tertiary-button-static.ts index 8b2559a8734..2350e6f57b8 100644 --- a/src/elements/button/tertiary-button-static/tertiary-button-static.ts +++ b/src/elements/button/tertiary-button-static/tertiary-button-static.ts @@ -11,8 +11,9 @@ import { buttonCommonStyle, buttonTertiaryStyle, SbbButtonCommonElementMixin } f * @slot - Use the unnamed slot to add content to the tertiary-button-static. * @slot icon - Slot used to display the icon, if one is set */ +export @customElement('sbb-tertiary-button-static') -export class SbbTertiaryButtonStaticElement extends SbbButtonCommonElementMixin( +class SbbTertiaryButtonStaticElement extends SbbButtonCommonElementMixin( SbbDisabledMixin(SbbActionBaseElement), ) { public static override styles: CSSResultGroup = [buttonCommonStyle, buttonTertiaryStyle]; diff --git a/src/elements/button/tertiary-button/readme.md b/src/elements/button/tertiary-button/readme.md index 6c5150dbd8e..3d362c2b41e 100644 --- a/src/elements/button/tertiary-button/readme.md +++ b/src/elements/button/tertiary-button/readme.md @@ -84,17 +84,17 @@ guard against such cases in your component. ## Properties -| Name | Attribute | Privacy | Type | Default | Description | -| --------------------- | ---------------------- | ------- | ---------------------------- | ---------- | -------------------------------------------------------------------------------------------------------------------------------- | -| `disabled` | `disabled` | public | `boolean` | `false` | Whether the component is disabled. | -| `disabledInteractive` | `disabled-interactive` | public | `boolean` | `false` | Whether disabled buttons should be interactive. | -| `form` | `form` | public | `string \| undefined` | | The element to associate the button with. | -| `iconName` | `icon-name` | public | `string \| undefined` | | The icon name we want to use, choose from the small icon variants from the ui-icons category from here https://icons.app.sbb.ch. | -| `name` | `name` | public | `string` | | The name of the button element. | -| `negative` | `negative` | public | `boolean` | `false` | Negative coloring variant flag. | -| `size` | `size` | public | `SbbButtonSize \| undefined` | `'l'` | Size variant, either l or m. | -| `type` | `type` | public | `SbbButtonType` | `'button'` | The type attribute to use for the button. | -| `value` | `value` | public | `string` | | The value of the button element. | +| Name | Attribute | Privacy | Type | Default | Description | +| --------------------- | ---------------------- | ------- | ---------------- | ---------- | -------------------------------------------------------------------------------------------------------------------------------- | +| `disabled` | `disabled` | public | `boolean` | `false` | Whether the component is disabled. | +| `disabledInteractive` | `disabled-interactive` | public | `boolean` | `false` | Whether disabled buttons should be interactive. | +| `form` | `form` | public | `string` | `''` | The element to associate the button with. | +| `iconName` | `icon-name` | public | `string \| null` | `null` | The icon name we want to use, choose from the small icon variants from the ui-icons category from here https://icons.app.sbb.ch. | +| `name` | `name` | public | `string` | | The name of the button element. | +| `negative` | `negative` | public | `boolean` | `false` | Negative coloring variant flag. | +| `size` | `size` | public | `SbbButtonSize` | `'l'` | Size variant, either l or m. | +| `type` | `type` | public | `SbbButtonType` | `'button'` | The type attribute to use for the button. | +| `value` | `value` | public | `string` | | The value of the button element. | ## Slots diff --git a/src/elements/button/tertiary-button/tertiary-button.ts b/src/elements/button/tertiary-button/tertiary-button.ts index 02c656130b5..e2bb6e329bb 100644 --- a/src/elements/button/tertiary-button/tertiary-button.ts +++ b/src/elements/button/tertiary-button/tertiary-button.ts @@ -11,8 +11,9 @@ import { buttonCommonStyle, buttonTertiaryStyle, SbbButtonCommonElementMixin } f * @slot - Use the unnamed slot to add content to the tertiary-button. * @slot icon - Slot used to display the icon, if one is set */ +export @customElement('sbb-tertiary-button') -export class SbbTertiaryButtonElement extends SbbButtonCommonElementMixin( +class SbbTertiaryButtonElement extends SbbButtonCommonElementMixin( SbbDisabledTabIndexActionMixin(SbbButtonBaseElement), ) { public static override styles: CSSResultGroup = [buttonCommonStyle, buttonTertiaryStyle]; diff --git a/src/elements/button/transparent-button-link/readme.md b/src/elements/button/transparent-button-link/readme.md index 98c627da08c..62379e52d12 100644 --- a/src/elements/button/transparent-button-link/readme.md +++ b/src/elements/button/transparent-button-link/readme.md @@ -77,18 +77,18 @@ Use the accessibility properties in case of an icon-only button to describe the ## Properties -| Name | Attribute | Privacy | Type | Default | Description | -| --------------------- | ---------------------- | ------- | --------------------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------- | -| `accessibilityLabel` | `accessibility-label` | public | `string \| undefined` | | This will be forwarded as aria-label to the inner anchor element. | -| `disabled` | `disabled` | public | `boolean` | `false` | Whether the component is disabled. | -| `disabledInteractive` | `disabled-interactive` | public | `boolean` | `false` | Whether disabled buttons should be interactive. | -| `download` | `download` | public | `boolean \| undefined` | | Whether the browser will show the download dialog on click. | -| `href` | `href` | public | `string \| undefined` | | The href value you want to link to. | -| `iconName` | `icon-name` | public | `string \| undefined` | | The icon name we want to use, choose from the small icon variants from the ui-icons category from here https://icons.app.sbb.ch. | -| `negative` | `negative` | public | `boolean` | `false` | Negative coloring variant flag. | -| `rel` | `rel` | public | `string \| undefined` | | The relationship of the linked URL as space-separated link types. | -| `size` | `size` | public | `SbbButtonSize \| undefined` | `'l'` | Size variant, either l or m. | -| `target` | `target` | public | `LinkTargetType \| string \| undefined` | | Where to display the linked URL. | +| Name | Attribute | Privacy | Type | Default | Description | +| --------------------- | ---------------------- | ------- | -------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------- | +| `accessibilityLabel` | `accessibility-label` | public | `string` | `''` | This will be forwarded as aria-label to the inner anchor element. | +| `disabled` | `disabled` | public | `boolean` | `false` | Whether the component is disabled. | +| `disabledInteractive` | `disabled-interactive` | public | `boolean` | `false` | Whether disabled buttons should be interactive. | +| `download` | `download` | public | `boolean` | `false` | Whether the browser will show the download dialog on click. | +| `href` | `href` | public | `string` | `''` | The href value you want to link to. | +| `iconName` | `icon-name` | public | `string \| null` | `null` | The icon name we want to use, choose from the small icon variants from the ui-icons category from here https://icons.app.sbb.ch. | +| `negative` | `negative` | public | `boolean` | `false` | Negative coloring variant flag. | +| `rel` | `rel` | public | `string` | `''` | The relationship of the linked URL as space-separated link types. | +| `size` | `size` | public | `SbbButtonSize` | `'l'` | Size variant, either l or m. | +| `target` | `target` | public | `LinkTargetType \| string` | `''` | Where to display the linked URL. | ## Slots diff --git a/src/elements/button/transparent-button-link/transparent-button-link.ts b/src/elements/button/transparent-button-link/transparent-button-link.ts index 7618cf8deb8..104b7f1ed0f 100644 --- a/src/elements/button/transparent-button-link/transparent-button-link.ts +++ b/src/elements/button/transparent-button-link/transparent-button-link.ts @@ -15,8 +15,9 @@ import { * @slot - Use the unnamed slot to add content to the transparent-button-link. * @slot icon - Slot used to display the icon, if one is set */ +export @customElement('sbb-transparent-button-link') -export class SbbTransparentButtonLinkElement extends SbbButtonCommonElementMixin( +class SbbTransparentButtonLinkElement extends SbbButtonCommonElementMixin( SbbDisabledInteractiveMixin(SbbDisabledMixin(SbbLinkBaseElement)), ) { public static override styles: CSSResultGroup = [buttonCommonStyle, buttonTransparentStyle]; diff --git a/src/elements/button/transparent-button-static/readme.md b/src/elements/button/transparent-button-static/readme.md index c0f2964c1e0..850cd84aaa9 100644 --- a/src/elements/button/transparent-button-static/readme.md +++ b/src/elements/button/transparent-button-static/readme.md @@ -60,12 +60,12 @@ Use the accessibility properties in case of an icon-only button to describe the ## Properties -| Name | Attribute | Privacy | Type | Default | Description | -| ---------- | ----------- | ------- | ---------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------- | -| `disabled` | `disabled` | public | `boolean` | `false` | Whether the component is disabled. | -| `iconName` | `icon-name` | public | `string \| undefined` | | The icon name we want to use, choose from the small icon variants from the ui-icons category from here https://icons.app.sbb.ch. | -| `negative` | `negative` | public | `boolean` | `false` | Negative coloring variant flag. | -| `size` | `size` | public | `SbbButtonSize \| undefined` | `'l'` | Size variant, either l or m. | +| Name | Attribute | Privacy | Type | Default | Description | +| ---------- | ----------- | ------- | ---------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------- | +| `disabled` | `disabled` | public | `boolean` | `false` | Whether the component is disabled. | +| `iconName` | `icon-name` | public | `string \| null` | `null` | The icon name we want to use, choose from the small icon variants from the ui-icons category from here https://icons.app.sbb.ch. | +| `negative` | `negative` | public | `boolean` | `false` | Negative coloring variant flag. | +| `size` | `size` | public | `SbbButtonSize` | `'l'` | Size variant, either l or m. | ## Slots diff --git a/src/elements/button/transparent-button-static/transparent-button-static.ts b/src/elements/button/transparent-button-static/transparent-button-static.ts index 8c60ea781de..48f6b7359cd 100644 --- a/src/elements/button/transparent-button-static/transparent-button-static.ts +++ b/src/elements/button/transparent-button-static/transparent-button-static.ts @@ -15,8 +15,9 @@ import { * @slot - Use the unnamed slot to add content to the transparent-button-static. * @slot icon - Slot used to display the icon, if one is set */ +export @customElement('sbb-transparent-button-static') -export class SbbTransparentButtonStaticElement extends SbbButtonCommonElementMixin( +class SbbTransparentButtonStaticElement extends SbbButtonCommonElementMixin( SbbDisabledMixin(SbbActionBaseElement), ) { public static override styles: CSSResultGroup = [buttonCommonStyle, buttonTransparentStyle]; diff --git a/src/elements/button/transparent-button/readme.md b/src/elements/button/transparent-button/readme.md index a373b33ef9c..17925aafb0a 100644 --- a/src/elements/button/transparent-button/readme.md +++ b/src/elements/button/transparent-button/readme.md @@ -84,17 +84,17 @@ guard against such cases in your component. ## Properties -| Name | Attribute | Privacy | Type | Default | Description | -| --------------------- | ---------------------- | ------- | ---------------------------- | ---------- | -------------------------------------------------------------------------------------------------------------------------------- | -| `disabled` | `disabled` | public | `boolean` | `false` | Whether the component is disabled. | -| `disabledInteractive` | `disabled-interactive` | public | `boolean` | `false` | Whether disabled buttons should be interactive. | -| `form` | `form` | public | `string \| undefined` | | The element to associate the button with. | -| `iconName` | `icon-name` | public | `string \| undefined` | | The icon name we want to use, choose from the small icon variants from the ui-icons category from here https://icons.app.sbb.ch. | -| `name` | `name` | public | `string` | | The name of the button element. | -| `negative` | `negative` | public | `boolean` | `false` | Negative coloring variant flag. | -| `size` | `size` | public | `SbbButtonSize \| undefined` | `'l'` | Size variant, either l or m. | -| `type` | `type` | public | `SbbButtonType` | `'button'` | The type attribute to use for the button. | -| `value` | `value` | public | `string` | | The value of the button element. | +| Name | Attribute | Privacy | Type | Default | Description | +| --------------------- | ---------------------- | ------- | ---------------- | ---------- | -------------------------------------------------------------------------------------------------------------------------------- | +| `disabled` | `disabled` | public | `boolean` | `false` | Whether the component is disabled. | +| `disabledInteractive` | `disabled-interactive` | public | `boolean` | `false` | Whether disabled buttons should be interactive. | +| `form` | `form` | public | `string` | `''` | The element to associate the button with. | +| `iconName` | `icon-name` | public | `string \| null` | `null` | The icon name we want to use, choose from the small icon variants from the ui-icons category from here https://icons.app.sbb.ch. | +| `name` | `name` | public | `string` | | The name of the button element. | +| `negative` | `negative` | public | `boolean` | `false` | Negative coloring variant flag. | +| `size` | `size` | public | `SbbButtonSize` | `'l'` | Size variant, either l or m. | +| `type` | `type` | public | `SbbButtonType` | `'button'` | The type attribute to use for the button. | +| `value` | `value` | public | `string` | | The value of the button element. | ## Slots diff --git a/src/elements/button/transparent-button/transparent-button.ts b/src/elements/button/transparent-button/transparent-button.ts index b8fbb748626..515c676f247 100644 --- a/src/elements/button/transparent-button/transparent-button.ts +++ b/src/elements/button/transparent-button/transparent-button.ts @@ -15,8 +15,9 @@ import { * @slot - Use the unnamed slot to add content to the transparent-button. * @slot icon - Slot used to display the icon, if one is set */ +export @customElement('sbb-transparent-button') -export class SbbTransparentButtonElement extends SbbButtonCommonElementMixin( +class SbbTransparentButtonElement extends SbbButtonCommonElementMixin( SbbDisabledTabIndexActionMixin(SbbButtonBaseElement), ) { public static override styles: CSSResultGroup = [buttonCommonStyle, buttonTransparentStyle]; diff --git a/src/elements/calendar/calendar.ts b/src/elements/calendar/calendar.ts index 37884e24602..edf784a714a 100644 --- a/src/elements/calendar/calendar.ts +++ b/src/elements/calendar/calendar.ts @@ -21,6 +21,7 @@ import { YEARS_PER_PAGE, YEARS_PER_ROW, } from '../core/datetime.js'; +import { forceType } from '../core/decorators.js'; import { isBreakpoint } from '../core/dom.js'; import { EventEmitter } from '../core/eventing.js'; import { @@ -91,18 +92,19 @@ export type CalendarView = 'day' | 'month' | 'year'; * * @event {CustomEvent} dateSelected - Event emitted on date selection. */ +export @customElement('sbb-calendar') -export class SbbCalendarElement extends SbbHydrationMixin(LitElement) { +class SbbCalendarElement extends SbbHydrationMixin(LitElement) { public static override styles: CSSResultGroup = style; public static readonly events = { dateSelected: 'dateSelected', } as const; /** If set to true, two months are displayed */ - @property({ type: Boolean }) public wide = false; + @property({ type: Boolean }) @forceType(Boolean) public accessor wide: boolean = false; /** The initial view of the calendar which should be displayed on opening. */ - @property() public view: CalendarView = 'day'; + @property() public accessor view: CalendarView = 'day'; /** The minimum valid date. Takes T Object, ISOString, and Unix Timestamp (number of seconds since Jan 1, 1970). */ @property() @@ -154,7 +156,9 @@ export class SbbCalendarElement extends SbbHydrationMixin(LitElement) private _selectedDate?: T | null; /** A function used to filter out dates. */ - @property({ attribute: 'date-filter' }) public dateFilter?: (date: T | null) => boolean; + @property({ attribute: 'date-filter' }) public accessor dateFilter: + | ((date: T | null) => boolean) + | null = null; private _dateAdapter: DateAdapter = readConfig().datetime?.dateAdapter ?? defaultDateAdapter; @@ -165,10 +169,10 @@ export class SbbCalendarElement extends SbbHydrationMixin(LitElement) ); /** The currently active date. */ - @state() private _activeDate: T = this.now; + @state() private accessor _activeDate: T = this.now; /** The selected date as ISOString. */ - @state() private _selected?: string; + @state() private accessor _selected: string | undefined; /** The current wide property considering property value and breakpoints. From zero to small `wide` has always to be false. */ @state() @@ -179,7 +183,7 @@ export class SbbCalendarElement extends SbbHydrationMixin(LitElement) return this.hasAttribute('data-wide'); } - @state() private _calendarView: CalendarView = 'day'; + @state() private accessor _calendarView: CalendarView = 'day'; private _nextCalendarView: CalendarView = 'day'; @@ -221,7 +225,7 @@ export class SbbCalendarElement extends SbbHydrationMixin(LitElement) private _resetFocus = false; @state() - private _initialized = false; + private accessor _initialized = false; private _abort = new SbbConnectedAbortController(this); private _language = new SbbLanguageController(this).withHandler(() => { diff --git a/src/elements/calendar/readme.md b/src/elements/calendar/readme.md index 47829d412e0..1a0b12962fd 100644 --- a/src/elements/calendar/readme.md +++ b/src/elements/calendar/readme.md @@ -63,15 +63,15 @@ For accessibility purposes, the component is rendered as a native table element ## Properties -| Name | Attribute | Privacy | Type | Default | Description | -| ------------ | ------------- | ------- | ------------------------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------- | -| `dateFilter` | `date-filter` | public | `(date: T \| null) => boolean \| undefined` | | A function used to filter out dates. | -| `max` | `max` | public | `T \| null` | | The maximum valid date. Takes T Object, ISOString, and Unix Timestamp (number of seconds since Jan 1, 1970). | -| `min` | `min` | public | `T \| null` | | The minimum valid date. Takes T Object, ISOString, and Unix Timestamp (number of seconds since Jan 1, 1970). | -| `now` | `now` | public | `T` | `null` | A configured date which acts as the current date instead of the real current date. Recommended for testing purposes. | -| `selected` | `selected` | public | `T \| null` | | The selected date. Takes T Object, ISOString, and Unix Timestamp (number of seconds since Jan 1, 1970). | -| `view` | `view` | public | `CalendarView` | `'day'` | The initial view of the calendar which should be displayed on opening. | -| `wide` | `wide` | public | `boolean` | `false` | If set to true, two months are displayed | +| Name | Attribute | Privacy | Type | Default | Description | +| ------------ | ------------- | ------- | ----------------------------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------- | +| `dateFilter` | `date-filter` | public | `\| ((date: T \| null) => boolean) \| null` | `null` | A function used to filter out dates. | +| `max` | `max` | public | `T \| null` | | The maximum valid date. Takes T Object, ISOString, and Unix Timestamp (number of seconds since Jan 1, 1970). | +| `min` | `min` | public | `T \| null` | | The minimum valid date. Takes T Object, ISOString, and Unix Timestamp (number of seconds since Jan 1, 1970). | +| `now` | `now` | public | `T` | `null` | A configured date which acts as the current date instead of the real current date. Recommended for testing purposes. | +| `selected` | `selected` | public | `T \| null` | | The selected date. Takes T Object, ISOString, and Unix Timestamp (number of seconds since Jan 1, 1970). | +| `view` | `view` | public | `CalendarView` | `'day'` | The initial view of the calendar which should be displayed on opening. | +| `wide` | `wide` | public | `boolean` | `false` | If set to true, two months are displayed | ## Methods diff --git a/src/elements/card/card-badge/card-badge.ts b/src/elements/card/card-badge/card-badge.ts index 62a26261252..39076b9474d 100644 --- a/src/elements/card/card-badge/card-badge.ts +++ b/src/elements/card/card-badge/card-badge.ts @@ -12,16 +12,17 @@ import style from './card-badge.scss?lit&inline'; * @slot - Use the unnamed slot to add content to the badge. * Content parts should be wrapped in `` tags to achieve correct spacings. */ +export @customElement('sbb-card-badge') @hostAttributes({ slot: 'badge', role: 'text', }) -export class SbbCardBadgeElement extends LitElement { +class SbbCardBadgeElement extends LitElement { public static override styles: CSSResultGroup = style; /** Color of the card badge. */ - @property({ reflect: true }) public color: 'charcoal' | 'white' = 'charcoal'; + @property({ reflect: true }) public accessor color: 'charcoal' | 'white' = 'charcoal'; private _parentElement?: HTMLElement | null; diff --git a/src/elements/card/card-button/card-button.ts b/src/elements/card/card-button/card-button.ts index fdaab1a5a18..681abe201b2 100644 --- a/src/elements/card/card-button/card-button.ts +++ b/src/elements/card/card-button/card-button.ts @@ -9,8 +9,9 @@ import { SbbCardActionCommonElementMixin } from '../common.js'; * @slot - Use the unnamed slot to add a descriptive label / title of the button (important!). * This is relevant for SEO and screen readers. */ +export @customElement('sbb-card-button') -export class SbbCardButtonElement extends SbbCardActionCommonElementMixin(SbbButtonBaseElement) { +class SbbCardButtonElement extends SbbCardActionCommonElementMixin(SbbButtonBaseElement) { protected override actionRole: 'link' | 'button' = 'button'; } diff --git a/src/elements/card/card-button/readme.md b/src/elements/card/card-button/readme.md index dd6c18e3652..6cdd288b11a 100644 --- a/src/elements/card/card-button/readme.md +++ b/src/elements/card/card-button/readme.md @@ -22,13 +22,13 @@ as it is used for search engines and screen-reader users. ## Properties -| Name | Attribute | Privacy | Type | Default | Description | -| -------- | --------- | ------- | --------------------- | ---------- | ------------------------------------------------ | -| `active` | `active` | public | `boolean` | `false` | Whether the card is active. | -| `form` | `form` | public | `string \| undefined` | | The element to associate the button with. | -| `name` | `name` | public | `string` | | The name of the button element. | -| `type` | `type` | public | `SbbButtonType` | `'button'` | The type attribute to use for the button. | -| `value` | `value` | public | `string` | | The value of the button element. | +| Name | Attribute | Privacy | Type | Default | Description | +| -------- | --------- | ------- | --------------- | ---------- | ------------------------------------------------ | +| `active` | `active` | public | `boolean` | `false` | Whether the card is active. | +| `form` | `form` | public | `string` | `''` | The element to associate the button with. | +| `name` | `name` | public | `string` | | The name of the button element. | +| `type` | `type` | public | `SbbButtonType` | `'button'` | The type attribute to use for the button. | +| `value` | `value` | public | `string` | | The value of the button element. | ## Slots diff --git a/src/elements/card/card-link/card-link.ts b/src/elements/card/card-link/card-link.ts index b248c99d469..d99c5250cf6 100644 --- a/src/elements/card/card-link/card-link.ts +++ b/src/elements/card/card-link/card-link.ts @@ -9,8 +9,9 @@ import { SbbCardActionCommonElementMixin } from '../common.js'; * @slot - Use the unnamed slot to add a descriptive label / title of the link (important!). * This is relevant for SEO and screen readers. */ +export @customElement('sbb-card-link') -export class SbbCardLinkElement extends SbbCardActionCommonElementMixin(SbbLinkBaseElement) { +class SbbCardLinkElement extends SbbCardActionCommonElementMixin(SbbLinkBaseElement) { protected override actionRole: 'link' | 'button' = 'link'; } diff --git a/src/elements/card/card-link/readme.md b/src/elements/card/card-link/readme.md index 41657b5fe9e..bb545ba6f65 100644 --- a/src/elements/card/card-link/readme.md +++ b/src/elements/card/card-link/readme.md @@ -22,14 +22,14 @@ as it is used for search engines and screen-reader users. ## Properties -| Name | Attribute | Privacy | Type | Default | Description | -| -------------------- | --------------------- | ------- | --------------------------------------- | ------- | ----------------------------------------------------------------- | -| `accessibilityLabel` | `accessibility-label` | public | `string \| undefined` | | This will be forwarded as aria-label to the inner anchor element. | -| `active` | `active` | public | `boolean` | `false` | Whether the card is active. | -| `download` | `download` | public | `boolean \| undefined` | | Whether the browser will show the download dialog on click. | -| `href` | `href` | public | `string \| undefined` | | The href value you want to link to. | -| `rel` | `rel` | public | `string \| undefined` | | The relationship of the linked URL as space-separated link types. | -| `target` | `target` | public | `LinkTargetType \| string \| undefined` | | Where to display the linked URL. | +| Name | Attribute | Privacy | Type | Default | Description | +| -------------------- | --------------------- | ------- | -------------------------- | ------- | ----------------------------------------------------------------- | +| `accessibilityLabel` | `accessibility-label` | public | `string` | `''` | This will be forwarded as aria-label to the inner anchor element. | +| `active` | `active` | public | `boolean` | `false` | Whether the card is active. | +| `download` | `download` | public | `boolean` | `false` | Whether the browser will show the download dialog on click. | +| `href` | `href` | public | `string` | `''` | The href value you want to link to. | +| `rel` | `rel` | public | `string` | `''` | The relationship of the linked URL as space-separated link types. | +| `target` | `target` | public | `LinkTargetType \| string` | `''` | Where to display the linked URL. | ## Slots diff --git a/src/elements/card/card/card.ts b/src/elements/card/card/card.ts index 669553527da..bb67f1ebb08 100644 --- a/src/elements/card/card/card.ts +++ b/src/elements/card/card/card.ts @@ -11,15 +11,23 @@ import style from './card.scss?lit&inline'; * @slot badge - Use this slot to render a `sbb-card-badge` component. * @slot action - Use this slot to render a `sbb-card-button` or a `sbb-card-link` component. */ +export @customElement('sbb-card') -export class SbbCardElement extends LitElement { +class SbbCardElement extends LitElement { public static override styles: CSSResultGroup = style; /** Size variant, either xs, s, m, l, xl, xxl or xxxl. */ - @property({ reflect: true }) public size: 'xs' | 's' | 'm' | 'l' | 'xl' | 'xxl' | 'xxxl' = 'm'; + @property({ reflect: true }) public accessor size: + | 'xs' + | 's' + | 'm' + | 'l' + | 'xl' + | 'xxl' + | 'xxxl' = 'm'; /** Option to set the component's background color. */ - @property({ reflect: true }) public color: + @property({ reflect: true }) public accessor color: | 'white' | 'milk' | 'transparent-bordered' diff --git a/src/elements/card/card/readme.md b/src/elements/card/card/readme.md index 041a414d7ca..e6b8559490f 100644 --- a/src/elements/card/card/readme.md +++ b/src/elements/card/card/readme.md @@ -89,7 +89,7 @@ To improve coloring, it's needed to manually define styles for Window high contr | Name | Attribute | Privacy | Type | Default | Description | | ------- | --------- | ------- | --------------------------------------------------------------------------------------------- | --------- | -------------------------------------------------- | | `color` | `color` | public | `\| 'white' \| 'milk' \| 'transparent-bordered' \| 'transparent-bordered-dashed'` | `'white'` | Option to set the component's background color. | -| `size` | `size` | public | `'xs' \| 's' \| 'm' \| 'l' \| 'xl' \| 'xxl' \| 'xxxl'` | `'m'` | Size variant, either xs, s, m, l, xl, xxl or xxxl. | +| `size` | `size` | public | `\| 'xs' \| 's' \| 'm' \| 'l' \| 'xl' \| 'xxl' \| 'xxxl'` | `'m'` | Size variant, either xs, s, m, l, xl, xxl or xxxl. | ## Slots diff --git a/src/elements/card/common/card-action-common.ts b/src/elements/card/common/card-action-common.ts index 71d14eda967..43e22f4c871 100644 --- a/src/elements/card/common/card-action-common.ts +++ b/src/elements/card/common/card-action-common.ts @@ -14,7 +14,7 @@ import style from './card-action.scss?lit&inline'; import '../../screen-reader-only.js'; export declare class SbbCardActionCommonElementMixinType { - public active: boolean; + public accessor active: boolean; protected actionRole: 'link' | 'button'; } diff --git a/src/elements/checkbox/checkbox-group/checkbox-group.ts b/src/elements/checkbox/checkbox-group/checkbox-group.ts index b26a4150d48..d6ea8e6145e 100644 --- a/src/elements/checkbox/checkbox-group/checkbox-group.ts +++ b/src/elements/checkbox/checkbox-group/checkbox-group.ts @@ -4,7 +4,7 @@ import { customElement, property } from 'lit/decorators.js'; import { getNextElementIndex, interactivityChecker, isArrowKeyPressed } from '../../core/a11y.js'; import { SbbConnectedAbortController } from '../../core/controllers.js'; -import { slotState } from '../../core/decorators.js'; +import { forceType, slotState } from '../../core/decorators.js'; import type { SbbHorizontalFrom, SbbOrientation } from '../../core/interfaces.js'; import { SbbDisabledMixin } from '../../core/mixins.js'; import type { SbbCheckboxPanelElement } from '../checkbox-panel.js'; @@ -19,24 +19,27 @@ import style from './checkbox-group.scss?lit&inline'; * @slot - Use the unnamed slot to add `sbb-checkbox` elements to the `sbb-checkbox-group`. * @slot error - Slot used to render a `sbb-form-error` inside the `sbb-checkbox-group`. */ +export @customElement('sbb-checkbox-group') @slotState() -export class SbbCheckboxGroupElement extends SbbDisabledMixin(LitElement) { +class SbbCheckboxGroupElement extends SbbDisabledMixin(LitElement) { public static override styles: CSSResultGroup = style; /** Whether the checkbox group is required. */ - @property({ reflect: true, type: Boolean }) public required = false; + @property({ reflect: true, type: Boolean }) + @forceType(Boolean) + public accessor required: boolean = false; /** Size variant, either m or s. */ - @property() public size: SbbCheckboxSize = 'm'; + @property() public accessor size: SbbCheckboxSize = 'm'; /** Overrides the behaviour of `orientation` property. */ @property({ attribute: 'horizontal-from', reflect: true }) - public horizontalFrom?: SbbHorizontalFrom; + public accessor horizontalFrom: SbbHorizontalFrom | null = null; /** Indicates the orientation of the checkboxes inside the ``. */ @property({ reflect: true }) - public orientation: SbbOrientation = 'horizontal'; + public accessor orientation: SbbOrientation = 'horizontal'; /** List of contained checkbox elements. */ public get checkboxes(): (SbbCheckboxElement | SbbCheckboxPanelElement)[] { diff --git a/src/elements/checkbox/checkbox-group/readme.md b/src/elements/checkbox/checkbox-group/readme.md index 558bec1bd3f..176068080b1 100644 --- a/src/elements/checkbox/checkbox-group/readme.md +++ b/src/elements/checkbox/checkbox-group/readme.md @@ -77,7 +77,7 @@ Two values are available, `s` and `m`, which is the default | ---------------- | ----------------- | ------- | --------------------------------------------------- | -------------- | ------------------------------------------------------------------------------ | | `checkboxes` | - | public | `(SbbCheckboxElement \| SbbCheckboxPanelElement)[]` | | List of contained checkbox elements. | | `disabled` | `disabled` | public | `boolean` | `false` | Whether the component is disabled. | -| `horizontalFrom` | `horizontal-from` | public | `SbbHorizontalFrom \| undefined` | | Overrides the behaviour of `orientation` property. | +| `horizontalFrom` | `horizontal-from` | public | `SbbHorizontalFrom \| null` | `null` | Overrides the behaviour of `orientation` property. | | `orientation` | `orientation` | public | `SbbOrientation` | `'horizontal'` | Indicates the orientation of the checkboxes inside the ``. | | `required` | `required` | public | `boolean` | `false` | Whether the checkbox group is required. | | `size` | `size` | public | `SbbCheckboxSize` | `'m'` | Size variant, either m or s. | diff --git a/src/elements/checkbox/checkbox-panel/checkbox-panel.ts b/src/elements/checkbox/checkbox-panel/checkbox-panel.ts index 50fd83cb53e..43abf00d6d7 100644 --- a/src/elements/checkbox/checkbox-panel/checkbox-panel.ts +++ b/src/elements/checkbox/checkbox-panel/checkbox-panel.ts @@ -8,7 +8,7 @@ import { } from 'lit'; import { customElement, property } from 'lit/decorators.js'; -import { slotState } from '../../core/decorators.js'; +import { getOverride, slotState } from '../../core/decorators.js'; import { EventEmitter } from '../../core/eventing.js'; import type { SbbCheckedStateChange, @@ -42,9 +42,10 @@ export type SbbCheckboxPanelStateChange = Extract< * @event {Event} change - Event fired on change. * @event {InputEvent} input - Event fired on input. */ +export @customElement('sbb-checkbox-panel') @slotState() -export class SbbCheckboxPanelElement extends SbbPanelMixin( +class SbbCheckboxPanelElement extends SbbPanelMixin( SbbCheckboxCommonElementMixin(SbbUpdateSchedulerMixin(LitElement)), ) { public static override styles: CSSResultGroup = [checkboxCommonStyle, panelCommonStyle]; @@ -58,13 +59,8 @@ export class SbbCheckboxPanelElement extends SbbPanelMixin( /** Size variant. */ @property({ reflect: true }) - public set size(value: SbbPanelSize) { - this._size = value; - } - public get size(): SbbPanelSize { - return this.group?.size ? (this.group.size === 'xs' ? 's' : this.group.size) : this._size; - } - private _size: SbbPanelSize = 'm'; + @getOverride((i, v) => (i.group?.size ? (i.group.size === 'xs' ? 's' : i.group.size) : v)) + public accessor size: SbbPanelSize = 'm'; /** * @internal diff --git a/src/elements/checkbox/checkbox/checkbox.ts b/src/elements/checkbox/checkbox/checkbox.ts index fff6a5cbc12..01afd89802e 100644 --- a/src/elements/checkbox/checkbox/checkbox.ts +++ b/src/elements/checkbox/checkbox/checkbox.ts @@ -1,7 +1,7 @@ import { LitElement, html, type CSSResultGroup, type TemplateResult } from 'lit'; import { customElement, property } from 'lit/decorators.js'; -import { slotState } from '../../core/decorators.js'; +import { getOverride, slotState } from '../../core/decorators.js'; import type { SbbIconPlacement } from '../../core/interfaces.js'; import { SbbIconNameMixin } from '../../icon.js'; import { @@ -23,11 +23,10 @@ import '../../visual-checkbox.js'; * @event {Event} change - Event fired on change. * @event {InputEvent} input - Event fired on input. */ +export @customElement('sbb-checkbox') @slotState() -export class SbbCheckboxElement extends SbbCheckboxCommonElementMixin( - SbbIconNameMixin(LitElement), -) { +class SbbCheckboxElement extends SbbCheckboxCommonElementMixin(SbbIconNameMixin(LitElement)) { public static override styles: CSSResultGroup = [checkboxCommonStyle, checkboxStyle]; public static readonly events = { @@ -36,17 +35,12 @@ export class SbbCheckboxElement extends SbbCheckboxCommonElementMixin( /** Size variant. */ @property({ reflect: true }) - public set size(value: SbbCheckboxSize) { - this._size = value; - } - public get size(): SbbCheckboxSize { - return this.group?.size ?? this._size; - } - private _size: SbbCheckboxSize = 'm'; + @getOverride((i, v) => i.group?.size ?? v) + public accessor size: SbbCheckboxSize = 'm'; /** The label position relative to the labelIcon. Defaults to end */ @property({ attribute: 'icon-placement', reflect: true }) - public iconPlacement: SbbIconPlacement = 'end'; + public accessor iconPlacement: SbbIconPlacement = 'end'; protected override render(): TemplateResult { return html` diff --git a/src/elements/checkbox/checkbox/readme.md b/src/elements/checkbox/checkbox/readme.md index 389f60190c6..6371f39cdc7 100644 --- a/src/elements/checkbox/checkbox/readme.md +++ b/src/elements/checkbox/checkbox/readme.md @@ -87,7 +87,7 @@ If you don't want the label to appear next to the checkbox, you can use `aria-la | `disabled` | `disabled` | public | `boolean` | `false` | Whether the component is disabled. | | `form` | - | public | `HTMLFormElement \| null` | | Returns the form owner of internals target element. | | `group` | - | public | `SbbCheckboxGroupElement \| null` | `null` | Reference to the connected checkbox group. | -| `iconName` | `icon-name` | public | `string \| undefined` | | The icon name we want to use, choose from the small icon variants from the ui-icons category from here https://icons.app.sbb.ch. | +| `iconName` | `icon-name` | public | `string \| null` | `null` | The icon name we want to use, choose from the small icon variants from the ui-icons category from here https://icons.app.sbb.ch. | | `iconPlacement` | `icon-placement` | public | `SbbIconPlacement` | `'end'` | The label position relative to the labelIcon. Defaults to end | | `indeterminate` | `indeterminate` | public | `boolean` | `false` | Whether the checkbox is indeterminate. | | `name` | `name` | public | `string` | | Name of the form element. Will be read from name attribute. | diff --git a/src/elements/checkbox/common/checkbox-common.ts b/src/elements/checkbox/common/checkbox-common.ts index 09f0f6cc2c1..05f9561654c 100644 --- a/src/elements/checkbox/common/checkbox-common.ts +++ b/src/elements/checkbox/common/checkbox-common.ts @@ -1,6 +1,7 @@ import type { LitElement, PropertyValues } from 'lit'; import { property } from 'lit/decorators.js'; +import { forceType } from '../../core/decorators.js'; import { type Constructor, type SbbDisabledMixinType, @@ -16,7 +17,7 @@ export declare class SbbCheckboxCommonElementMixinType extends SbbFormAssociatedCheckboxMixinType implements Partial, Partial { - public indeterminate: boolean; + public accessor indeterminate: boolean; public get group(): SbbCheckboxGroupElement | null; } @@ -30,7 +31,7 @@ export const SbbCheckboxCommonElementMixin = > implements Partial { /** Whether the checkbox is indeterminate. */ - @property({ type: Boolean }) public indeterminate = false; + @property({ type: Boolean }) @forceType(Boolean) public accessor indeterminate: boolean = false; /** Reference to the connected checkbox group. */ public get group(): SbbCheckboxGroupElement | null { diff --git a/src/elements/chip/chip.ts b/src/elements/chip/chip.ts index c6b48403b77..e6725c5e160 100644 --- a/src/elements/chip/chip.ts +++ b/src/elements/chip/chip.ts @@ -9,17 +9,18 @@ import style from './chip.scss?lit&inline'; * * @slot - Use the unnamed slot to add content to the `sbb-chip`. */ +export @customElement('sbb-chip') -export class SbbChipElement extends LitElement { +class SbbChipElement extends LitElement { public static override styles: CSSResultGroup = style; /** Size of the chip. */ @property({ reflect: true }) - public size: 'xxs' | 'xs' | 's' = 'xxs'; + public accessor size: 'xxs' | 'xs' | 's' = 'xxs'; /** Color of the chip. */ @property({ reflect: true }) - public color: 'milk' | 'charcoal' | 'white' | 'granite' = 'milk'; + public accessor color: 'milk' | 'charcoal' | 'white' | 'granite' = 'milk'; protected override render(): TemplateResult { return html` diff --git a/src/elements/clock/clock.ts b/src/elements/clock/clock.ts index c33e9a3b160..004e40cc829 100644 --- a/src/elements/clock/clock.ts +++ b/src/elements/clock/clock.ts @@ -49,15 +49,16 @@ const ADD_EVENT_LISTENER_OPTIONS: AddEventListenerOptions = { /** * It displays an analog clock with the classic SBB face. */ +export @customElement('sbb-clock') -export class SbbClockElement extends LitElement { +class SbbClockElement extends LitElement { public static override styles: CSSResultGroup = style; /** * Define a specific time which the clock should show statically. * @param value HH:MM:ss */ - @property() public now: SbbTime | null = null; + @property() public accessor now: SbbTime | null = null; /** Reference to the hour hand. */ private _clockHandHours!: HTMLElement; diff --git a/src/elements/container/container/container.ts b/src/elements/container/container/container.ts index 6ffdb3e1770..e3608779897 100644 --- a/src/elements/container/container/container.ts +++ b/src/elements/container/container/container.ts @@ -7,7 +7,7 @@ import { } from 'lit'; import { customElement, property } from 'lit/decorators.js'; -import { slotState } from '../../core/decorators.js'; +import { forceType, slotState } from '../../core/decorators.js'; import style from './container.scss?lit&inline'; @@ -18,20 +18,24 @@ import style from './container.scss?lit&inline'; * @slot sticky-bar - The slot used by the sbb-sticky-bar component. * @slot image - The slot used to slot an `sbb-image` to use as background. */ +export @customElement('sbb-container') @slotState() -export class SbbContainerElement extends LitElement { +class SbbContainerElement extends LitElement { public static override styles: CSSResultGroup = style; /** Whether the container is expanded. */ - @property({ type: Boolean, reflect: true }) public expanded = false; + @property({ type: Boolean, reflect: true }) + @forceType(Boolean) + public accessor expanded: boolean = false; /** Whether the background color is shown on full container width on large screens. */ @property({ type: Boolean, reflect: true, attribute: 'background-expanded' }) - public backgroundExpanded = false; + @forceType(Boolean) + public accessor backgroundExpanded: boolean = false; /** Color of the container, like transparent, white etc. */ - @property({ reflect: true }) public color: 'transparent' | 'white' | 'milk' = 'white'; + @property({ reflect: true }) public accessor color: 'transparent' | 'white' | 'milk' = 'white'; protected override willUpdate(changedProperties: PropertyValues): void { super.willUpdate(changedProperties); diff --git a/src/elements/container/sticky-bar/readme.md b/src/elements/container/sticky-bar/readme.md index 9423b17241f..c96b9cb93f7 100644 --- a/src/elements/container/sticky-bar/readme.md +++ b/src/elements/container/sticky-bar/readme.md @@ -22,9 +22,9 @@ Optionally the user can set the `color` property on the `sbb-sticky-bar` in orde ## Properties -| Name | Attribute | Privacy | Type | Default | Description | -| ------- | --------- | ------- | -------------------------------- | ------- | ---------------------------------------------------- | -| `color` | `color` | public | `'white' \| 'milk' \| undefined` | | Color of the container, like transparent, white etc. | +| Name | Attribute | Privacy | Type | Default | Description | +| ------- | --------- | ------- | --------------------------- | ------- | ---------------------------------------------------- | +| `color` | `color` | public | `'white' \| 'milk' \| null` | `null` | Color of the container, like transparent, white etc. | ## CSS Properties diff --git a/src/elements/container/sticky-bar/sticky-bar.ts b/src/elements/container/sticky-bar/sticky-bar.ts index af2ec527978..e0652eba936 100644 --- a/src/elements/container/sticky-bar/sticky-bar.ts +++ b/src/elements/container/sticky-bar/sticky-bar.ts @@ -23,15 +23,16 @@ import style from './sticky-bar.scss?lit&inline'; * @cssprop [--sbb-sticky-bar-z-index] - To specify a custom stack order, * the `z-index` can be overridden by defining this CSS variable. */ +export @customElement('sbb-sticky-bar') @hostAttributes({ slot: 'sticky-bar', }) -export class SbbStickyBarElement extends LitElement { +class SbbStickyBarElement extends LitElement { public static override styles: CSSResultGroup = style; /** Color of the container, like transparent, white etc. */ - @property({ reflect: true }) public color?: 'white' | 'milk'; + @property({ reflect: true }) public accessor color: 'white' | 'milk' | null = null; private _intersector?: HTMLSpanElement; private _observer = new IntersectionController(this, { diff --git a/src/elements/core/base-elements/action-base-element.ts b/src/elements/core/base-elements/action-base-element.ts index 35798c68fa9..2136910fb3b 100644 --- a/src/elements/core/base-elements/action-base-element.ts +++ b/src/elements/core/base-elements/action-base-element.ts @@ -13,10 +13,11 @@ type MaybeDisabled = { disabledInteractive?: boolean; }; +export @hostAttributes({ 'data-action': '', }) -export abstract class SbbActionBaseElement extends LitElement { +abstract class SbbActionBaseElement extends LitElement { protected get maybeDisabled(): boolean | undefined { const maybeDisabled = this as MaybeDisabled; return maybeDisabled.disabled || maybeDisabled.formDisabled; diff --git a/src/elements/core/base-elements/button-base-element.spec.ts b/src/elements/core/base-elements/button-base-element.spec.ts index 67006811f14..0f2cb116aba 100644 --- a/src/elements/core/base-elements/button-base-element.spec.ts +++ b/src/elements/core/base-elements/button-base-element.spec.ts @@ -3,14 +3,15 @@ import { sendKeys } from '@web/test-runner-commands'; import { html, type TemplateResult } from 'lit'; import { property } from 'lit/decorators.js'; +import { forceType } from '../decorators.js'; import { fixture } from '../testing/private.js'; import { EventSpy, waitForLitRender } from '../testing.js'; import { SbbButtonBaseElement } from './button-base-element.js'; class GenericButton extends SbbButtonBaseElement { - @property() public disabled = false; - @property() public disabledInteractive = false; + @property() @forceType(Boolean) public accessor disabled: boolean = false; + @property() @forceType(Boolean) public accessor disabledInteractive: boolean = false; protected override renderTemplate(): TemplateResult { return html`Button`; diff --git a/src/elements/core/base-elements/button-base-element.ts b/src/elements/core/base-elements/button-base-element.ts index 485bbb07000..3e03e5cd43c 100644 --- a/src/elements/core/base-elements/button-base-element.ts +++ b/src/elements/core/base-elements/button-base-element.ts @@ -10,14 +10,15 @@ import { SbbActionBaseElement } from './action-base-element.js'; export type SbbButtonType = 'button' | 'reset' | 'submit'; /** Button base class. */ +export @hostAttributes({ role: 'button', tabindex: '0', 'data-button': '', }) -export abstract class SbbButtonBaseElement extends SbbActionBaseElement { +abstract class SbbButtonBaseElement extends SbbActionBaseElement { /** The type attribute to use for the button. */ - @property() public type: SbbButtonType = 'button'; + @property() public accessor type: SbbButtonType = 'button'; /** * The name of the button element. @@ -48,7 +49,7 @@ export abstract class SbbButtonBaseElement extends SbbActionBaseElement { } /** The element to associate the button with. */ - @property() public form?: string; + @property() public accessor form: string = ''; public constructor() { super(); diff --git a/src/elements/core/base-elements/link-base-element.spec.ts b/src/elements/core/base-elements/link-base-element.spec.ts index 385a9921766..2afc6b164bb 100644 --- a/src/elements/core/base-elements/link-base-element.spec.ts +++ b/src/elements/core/base-elements/link-base-element.spec.ts @@ -3,14 +3,15 @@ import { sendKeys } from '@web/test-runner-commands'; import { html, type TemplateResult } from 'lit'; import { property } from 'lit/decorators.js'; +import { forceType } from '../decorators.js'; import { fixture } from '../testing/private.js'; import { EventSpy, waitForLitRender } from '../testing.js'; import { SbbLinkBaseElement } from './link-base-element.js'; class GenericLink extends SbbLinkBaseElement { - @property() public disabled = false; - @property() public disabledInteractive = false; + @property() @forceType(Boolean) public accessor disabled: boolean = false; + @property() @forceType(Boolean) public accessor disabledInteractive: boolean = false; protected override renderTemplate(): TemplateResult { return html`Link`; diff --git a/src/elements/core/base-elements/link-base-element.ts b/src/elements/core/base-elements/link-base-element.ts index 1ba733007d2..c15a77c5da1 100644 --- a/src/elements/core/base-elements/link-base-element.ts +++ b/src/elements/core/base-elements/link-base-element.ts @@ -2,7 +2,7 @@ import { html, isServer, nothing, type TemplateResult } from 'lit'; import { property } from 'lit/decorators.js'; import { SbbLanguageController } from '../controllers.js'; -import { hostAttributes } from '../decorators.js'; +import { forceType, hostAttributes } from '../decorators.js'; import { i18nTargetOpensInNewWindow } from '../i18n.js'; import { SbbActionBaseElement } from './action-base-element.js'; @@ -13,24 +13,33 @@ import '../../screen-reader-only.js'; export type LinkTargetType = '_blank' | '_self' | '_parent' | '_top'; /** Link base class. */ +export @hostAttributes({ 'data-link': '', }) -export abstract class SbbLinkBaseElement extends SbbActionBaseElement { +abstract class SbbLinkBaseElement extends SbbActionBaseElement { /** The href value you want to link to. */ - @property() public href?: string; + @property() + @forceType(String) + public accessor href: string = ''; /** Where to display the linked URL. */ - @property() public target?: LinkTargetType | string; + @property() + @forceType(String) + public accessor target: LinkTargetType | string = ''; /** The relationship of the linked URL as space-separated link types. */ - @property() public rel?: string; + @property() + @forceType(String) + public accessor rel: string = ''; /** Whether the browser will show the download dialog on click. */ - @property({ type: Boolean }) public download?: boolean; + @property({ type: Boolean }) + @forceType(Boolean) + public accessor download: boolean = false; /** This will be forwarded as aria-label to the inner anchor element. */ - @property({ attribute: 'accessibility-label' }) public accessibilityLabel: string | undefined; + @property({ attribute: 'accessibility-label' }) public accessor accessibilityLabel: string = ''; protected language = new SbbLanguageController(this); @@ -65,7 +74,7 @@ export abstract class SbbLinkBaseElement extends SbbActionBaseElement { return html` = { + [K in keyof T]: T[K]; +}; + +// Overloads for property decorator so that TypeScript can infer the correct +// return type when a decorator is used as an accessor decorator or a setter +// decorator. +export type PropertyDecorator = { + // accessor decorator signature + , V>( + target: ClassAccessorDecoratorTarget, + context: ClassAccessorDecoratorContext, + ): ClassAccessorDecoratorResult; + + // setter decorator signature + , V>( + target: (value: V) => void, + context: ClassSetterDecoratorContext, + ): (this: C, value: V) => void; +}; diff --git a/src/elements/core/decorators/force-type.ts b/src/elements/core/decorators/force-type.ts new file mode 100644 index 00000000000..efafc77e4a4 --- /dev/null +++ b/src/elements/core/decorators/force-type.ts @@ -0,0 +1,42 @@ +import type { ReactiveElement } from 'lit'; + +import type { Interface, PropertyDecorator } from './base.js'; + +/** + * This is a decorator that forces the value of a property or getter/setter + * to the defined type. + */ +export const forceType = , V>( + type?: (v: unknown) => V, +): PropertyDecorator => { + return ( + target: ClassAccessorDecoratorTarget | ((value: V) => void), + context: ClassAccessorDecoratorContext | ClassSetterDecoratorContext, + ): any => { + const { kind, metadata } = context; + + type ??= globalThis.litPropertyMetadata.get(metadata)?.get(context.name)?.type as ( + v: unknown, + ) => V; + if (import.meta.env.DEV && typeof type !== 'function') { + throw new Error(`Type not defined and not available from '@property' decorator!`); + } + + if (kind === 'accessor') { + return { + set(this: C, value) { + (target as ClassAccessorDecoratorTarget).set.call( + this as unknown as C, + type!(value) as V, + ); + }, + } satisfies ClassAccessorDecoratorResult; + } else if (kind === 'setter') { + return function (value: unknown) { + (target as (value: unknown) => void)(type!(value)); + } satisfies (this: C, value: V) => void; + } + + throw new Error(`Unsupported decorator location: ${kind}`); + }; +}; diff --git a/src/elements/core/decorators/get-override.ts b/src/elements/core/decorators/get-override.ts new file mode 100644 index 00000000000..59cfc80c709 --- /dev/null +++ b/src/elements/core/decorators/get-override.ts @@ -0,0 +1,29 @@ +import type { ReactiveElement } from 'lit'; + +import type { Interface } from './base.js'; + +/** + * This is a decorator that overrides the underlying getter of the accessor. + */ +export const getOverride = , V>( + callback: (instance: C, innerValue: V) => V, +) => { + return ( + target: ClassAccessorDecoratorTarget, + context: ClassAccessorDecoratorContext, + ): any => { + const { kind } = context; + if (kind === 'accessor') { + return { + get(this: C) { + const innerValue = (target as ClassAccessorDecoratorTarget).get.call( + this as unknown as C, + ); + return callback(this, innerValue); + }, + } satisfies ClassAccessorDecoratorResult; + } + + throw new Error(`Unsupported decorator location: ${kind}`); + }; +}; diff --git a/src/elements/core/decorators/handle-distinct-change.ts b/src/elements/core/decorators/handle-distinct-change.ts new file mode 100644 index 00000000000..89cbed6747c --- /dev/null +++ b/src/elements/core/decorators/handle-distinct-change.ts @@ -0,0 +1,32 @@ +import type { ReactiveElement } from 'lit'; + +import type { Interface } from './base.js'; + +/** + * This is a decorator that calls the given callback when the value + * of the associated property is changed. + */ +export const handleDistinctChange = , V>( + callback: (instance: C, newValue: V, oldValue: V | undefined) => void, +) => { + return ( + target: ClassAccessorDecoratorTarget, + context: ClassAccessorDecoratorContext, + ): any => { + const { kind } = context; + if (kind === 'accessor') { + return { + set(this: C, value) { + const oldValue = context.access.get(this); + (target as ClassAccessorDecoratorTarget).set.call(this as unknown as C, value); + const newValue = context.access.get(this); + if (newValue !== oldValue) { + callback(this, newValue, oldValue); + } + }, + } satisfies ClassAccessorDecoratorResult; + } + + throw new Error(`Unsupported decorator location: ${kind}`); + }; +}; diff --git a/src/elements/core/mixins/disabled-mixin.ts b/src/elements/core/mixins/disabled-mixin.ts index bd4cf3da306..67a6f2ea66e 100644 --- a/src/elements/core/mixins/disabled-mixin.ts +++ b/src/elements/core/mixins/disabled-mixin.ts @@ -1,16 +1,17 @@ import type { LitElement, PropertyValues } from 'lit'; import { property } from 'lit/decorators.js'; +import { forceType } from '../decorators.js'; + import type { AbstractConstructor } from './constructor.js'; export declare class SbbDisabledMixinType { - public set disabled(value: boolean); - public get disabled(): boolean; + public accessor disabled: boolean; protected isDisabledExternally(): boolean; } export declare class SbbDisabledInteractiveMixinType { - public disabledInteractive: boolean; + public accessor disabledInteractive: boolean; } /** @@ -59,8 +60,9 @@ export const SbbDisabledInteractiveMixin = < implements Partial { /** Whether disabled buttons should be interactive. */ - @property({ attribute: 'disabled-interactive', type: Boolean }) public disabledInteractive = - false; + @property({ attribute: 'disabled-interactive', type: Boolean }) + @forceType(Boolean) + public accessor disabledInteractive: boolean = false; } return SbbDisabledInteractiveElement as unknown as AbstractConstructor & diff --git a/src/elements/core/mixins/form-associated-mixin.ts b/src/elements/core/mixins/form-associated-mixin.ts index 7ede1464f7f..70c497455e6 100644 --- a/src/elements/core/mixins/form-associated-mixin.ts +++ b/src/elements/core/mixins/form-associated-mixin.ts @@ -115,7 +115,7 @@ export const SbbFormAssociatedMixin = >( protected readonly internals: ElementInternals = this.attachInternals(); /** Whenever a surrounding form or fieldset is changing its disabled state. */ - @state() protected formDisabled: boolean = false; + @state() protected accessor formDisabled: boolean = false; public override attributeChangedCallback( name: string, diff --git a/src/elements/core/mixins/named-slot-list-mixin.ts b/src/elements/core/mixins/named-slot-list-mixin.ts index 45e24435e6b..530a94630ba 100644 --- a/src/elements/core/mixins/named-slot-list-mixin.ts +++ b/src/elements/core/mixins/named-slot-list-mixin.ts @@ -34,7 +34,7 @@ export declare abstract class SbbNamedSlotListMixinType< C extends HTMLElement, > extends SbbHydrationMixinType { protected abstract readonly listChildLocalNames: string[]; - @state() protected listChildren: C[]; + protected accessor listChildren: C[]; protected renderList( attributes?: { class?: string; @@ -73,7 +73,7 @@ export const SbbNamedSlotListMixin = < * This array is only updated if there is an actual change * to the child elements. */ - @state() protected listChildren: C[] = []; + @state() protected accessor listChildren: C[] = []; public override connectedCallback(): void { super.connectedCallback(); diff --git a/src/elements/core/mixins/negative-mixin.ts b/src/elements/core/mixins/negative-mixin.ts index ae053c4a113..1c4008f4925 100644 --- a/src/elements/core/mixins/negative-mixin.ts +++ b/src/elements/core/mixins/negative-mixin.ts @@ -1,10 +1,12 @@ import type { LitElement } from 'lit'; import { property } from 'lit/decorators.js'; +import { forceType } from '../decorators.js'; + import type { AbstractConstructor } from './constructor.js'; export declare class SbbNegativeMixinType { - public negative: boolean; + public accessor negative: boolean; } /** @@ -16,7 +18,9 @@ export const SbbNegativeMixin = >( ): AbstractConstructor & T => { abstract class SbbNegativeElement extends superClass implements SbbNegativeMixinType { /** Negative coloring variant flag. */ - @property({ reflect: true, type: Boolean }) public negative: boolean = false; + @property({ reflect: true, type: Boolean }) + @forceType(Boolean) + public accessor negative: boolean = false; } return SbbNegativeElement as AbstractConstructor & T; diff --git a/src/elements/core/mixins/panel-mixin.ts b/src/elements/core/mixins/panel-mixin.ts index 447fc9bb96f..9b932a29722 100644 --- a/src/elements/core/mixins/panel-mixin.ts +++ b/src/elements/core/mixins/panel-mixin.ts @@ -1,14 +1,15 @@ import type { LitElement } from 'lit'; import { property } from 'lit/decorators.js'; +import { forceType } from '../decorators.js'; import { EventEmitter } from '../eventing.js'; import type { AbstractConstructor } from './constructor.js'; export declare class SbbPanelMixinType { - public color: 'white' | 'milk'; - public borderless: boolean; - public expansionState?: string; + public accessor color: 'white' | 'milk'; + public accessor borderless: boolean; + public accessor expansionState: string; } export type SbbPanelSize = 's' | 'm'; @@ -26,13 +27,15 @@ export const SbbPanelMixin = >( } as const; /** The background color of the panel. */ - @property() public color: 'white' | 'milk' = 'white'; + @property() public accessor color: 'white' | 'milk' = 'white'; /** Whether the unselected panel has a border. */ - @property({ reflect: true, type: Boolean }) public borderless = false; + @property({ reflect: true, type: Boolean }) + @forceType(Boolean) + public accessor borderless: boolean = false; /** @internal used for accessibility label when in expansion panel */ - @property() public expansionState?: string; + @property() public accessor expansionState: string = ''; /** * @internal diff --git a/src/elements/core/mixins/required-mixin.ts b/src/elements/core/mixins/required-mixin.ts index 476df7f145d..e22e0d37d7d 100644 --- a/src/elements/core/mixins/required-mixin.ts +++ b/src/elements/core/mixins/required-mixin.ts @@ -5,8 +5,7 @@ import type { AbstractConstructor } from './constructor.js'; import type { SbbFormAssociatedMixinType } from './form-associated-mixin.js'; export declare class SbbRequiredMixinType { - public set required(value: boolean); - public get required(): boolean; + public accessor required: boolean; protected isRequiredExternally(): boolean; } diff --git a/src/elements/datepicker/common/datepicker-button.ts b/src/elements/datepicker/common/datepicker-button.ts index 0775daffbf7..e77f23784d4 100644 --- a/src/elements/datepicker/common/datepicker-button.ts +++ b/src/elements/datepicker/common/datepicker-button.ts @@ -18,10 +18,13 @@ import '../../icon.js'; export abstract class SbbDatepickerButton extends SbbNegativeMixin(SbbButtonBaseElement) { /** Datepicker reference. */ - @property({ attribute: 'date-picker' }) public datePicker?: string | SbbDatepickerElement; + @property({ attribute: 'date-picker' }) public accessor datePicker: + | string + | SbbDatepickerElement + | null = null; /** The boundary date (min/max) as set in the date-picker's input. */ - @state() protected boundary: string | number | null = null; + @state() protected accessor boundary: string | number | null = null; /** Whether the component is disabled due date equals to boundary date. */ private _disabled = false; @@ -59,7 +62,7 @@ export abstract class SbbDatepickerButton extends SbbNegativeMixin(Sbb super.willUpdate(changedProperties); if (changedProperties.has('datePicker')) { - this._init(this.datePicker); + this._init(this.datePicker!); } } diff --git a/src/elements/datepicker/datepicker-next-day/datepicker-next-day.ts b/src/elements/datepicker/datepicker-next-day/datepicker-next-day.ts index cfd6f4af12c..54f66430451 100644 --- a/src/elements/datepicker/datepicker-next-day/datepicker-next-day.ts +++ b/src/elements/datepicker/datepicker-next-day/datepicker-next-day.ts @@ -12,11 +12,12 @@ import style from './datepicker-next-day.scss?lit&inline'; /** * Combined with a `sbb-datepicker`, it can be used to move the date ahead. */ +export @customElement('sbb-datepicker-next-day') @hostAttributes({ slot: 'suffix', }) -export class SbbDatepickerNextDayElement extends SbbDatepickerButton { +class SbbDatepickerNextDayElement extends SbbDatepickerButton { public static override styles: CSSResultGroup = style; protected iconName: string = 'chevron-small-right-small'; diff --git a/src/elements/datepicker/datepicker-next-day/readme.md b/src/elements/datepicker/datepicker-next-day/readme.md index fda35f7b1fe..33e9234cb98 100644 --- a/src/elements/datepicker/datepicker-next-day/readme.md +++ b/src/elements/datepicker/datepicker-next-day/readme.md @@ -35,11 +35,11 @@ both standalone or within the `sbb-form-field`, they must have the same parent e ## Properties -| Name | Attribute | Privacy | Type | Default | Description | -| ------------ | ------------- | ------- | ------------------------------------------------ | ---------- | ------------------------------------------------ | -| `datePicker` | `date-picker` | public | `string \| SbbDatepickerElement \| undefined` | | Datepicker reference. | -| `form` | `form` | public | `string \| undefined` | | The element to associate the button with. | -| `name` | `name` | public | `string` | | The name of the button element. | -| `negative` | `negative` | public | `boolean` | `false` | Negative coloring variant flag. | -| `type` | `type` | public | `SbbButtonType` | `'button'` | The type attribute to use for the button. | -| `value` | `value` | public | `string` | | The value of the button element. | +| Name | Attribute | Privacy | Type | Default | Description | +| ------------ | ------------- | ------- | ------------------------------------------------------ | ---------- | ------------------------------------------------ | +| `datePicker` | `date-picker` | public | `\| string \| SbbDatepickerElement \| null` | `null` | Datepicker reference. | +| `form` | `form` | public | `string` | `''` | The element to associate the button with. | +| `name` | `name` | public | `string` | | The name of the button element. | +| `negative` | `negative` | public | `boolean` | `false` | Negative coloring variant flag. | +| `type` | `type` | public | `SbbButtonType` | `'button'` | The type attribute to use for the button. | +| `value` | `value` | public | `string` | | The value of the button element. | diff --git a/src/elements/datepicker/datepicker-previous-day/datepicker-previous-day.ts b/src/elements/datepicker/datepicker-previous-day/datepicker-previous-day.ts index 30cba55bec3..65c7e04fc1b 100644 --- a/src/elements/datepicker/datepicker-previous-day/datepicker-previous-day.ts +++ b/src/elements/datepicker/datepicker-previous-day/datepicker-previous-day.ts @@ -12,11 +12,12 @@ import style from './datepicker-previous-day.scss?lit&inline'; /** * Combined with a `sbb-datepicker`, it can be used to move the date back. */ +export @customElement('sbb-datepicker-previous-day') @hostAttributes({ slot: 'prefix', }) -export class SbbDatepickerPreviousDayElement extends SbbDatepickerButton { +class SbbDatepickerPreviousDayElement extends SbbDatepickerButton { public static override styles: CSSResultGroup = style; protected iconName: string = 'chevron-small-left-small'; diff --git a/src/elements/datepicker/datepicker-previous-day/readme.md b/src/elements/datepicker/datepicker-previous-day/readme.md index 8653a10686d..209b86c69c3 100644 --- a/src/elements/datepicker/datepicker-previous-day/readme.md +++ b/src/elements/datepicker/datepicker-previous-day/readme.md @@ -35,11 +35,11 @@ both standalone or within the `sbb-form-field`, they must have the same parent e ## Properties -| Name | Attribute | Privacy | Type | Default | Description | -| ------------ | ------------- | ------- | ------------------------------------------------ | ---------- | ------------------------------------------------ | -| `datePicker` | `date-picker` | public | `string \| SbbDatepickerElement \| undefined` | | Datepicker reference. | -| `form` | `form` | public | `string \| undefined` | | The element to associate the button with. | -| `name` | `name` | public | `string` | | The name of the button element. | -| `negative` | `negative` | public | `boolean` | `false` | Negative coloring variant flag. | -| `type` | `type` | public | `SbbButtonType` | `'button'` | The type attribute to use for the button. | -| `value` | `value` | public | `string` | | The value of the button element. | +| Name | Attribute | Privacy | Type | Default | Description | +| ------------ | ------------- | ------- | ------------------------------------------------------ | ---------- | ------------------------------------------------ | +| `datePicker` | `date-picker` | public | `\| string \| SbbDatepickerElement \| null` | `null` | Datepicker reference. | +| `form` | `form` | public | `string` | `''` | The element to associate the button with. | +| `name` | `name` | public | `string` | | The name of the button element. | +| `negative` | `negative` | public | `boolean` | `false` | Negative coloring variant flag. | +| `type` | `type` | public | `SbbButtonType` | `'button'` | The type attribute to use for the button. | +| `value` | `value` | public | `string` | | The value of the button element. | diff --git a/src/elements/datepicker/datepicker-toggle/datepicker-toggle.ts b/src/elements/datepicker/datepicker-toggle/datepicker-toggle.ts index 084c1ccec77..71197d28a1e 100644 --- a/src/elements/datepicker/datepicker-toggle/datepicker-toggle.ts +++ b/src/elements/datepicker/datepicker-toggle/datepicker-toggle.ts @@ -23,28 +23,30 @@ import '../../button/mini-button.js'; /** * Combined with a `sbb-datepicker`, it can be used to select a date from a `sbb-calendar`. */ +export @customElement('sbb-datepicker-toggle') @hostAttributes({ slot: 'prefix', }) -export class SbbDatepickerToggleElement extends SbbNegativeMixin( - SbbHydrationMixin(LitElement), -) { +class SbbDatepickerToggleElement extends SbbNegativeMixin(SbbHydrationMixin(LitElement)) { public static override styles: CSSResultGroup = style; /** Datepicker reference. */ - @property({ attribute: 'date-picker' }) public datePicker?: string | SbbDatepickerElement; + @property({ attribute: 'date-picker' }) public accessor datePicker: + | string + | SbbDatepickerElement + | null = null; /** The initial view of calendar which should be displayed on opening. */ - @property() public view: CalendarView = 'day'; + @property() public accessor view: CalendarView = 'day'; - @state() private _disabled = false; + @state() private accessor _disabled = false; - @state() private _min: string | number | null | undefined = null; + @state() private accessor _min: string | number | null | undefined = null; - @state() private _max: string | number | null | undefined = null; + @state() private accessor _max: string | number | null | undefined = null; - @state() private _renderCalendar = false; + @state() private accessor _renderCalendar = false; private _datePickerElement: SbbDatepickerElement | null | undefined; private _calendarElement!: SbbCalendarElement; @@ -97,7 +99,7 @@ export class SbbDatepickerToggleElement extends SbbNegativeMixin( super.willUpdate(changedProperties); if (changedProperties.has('datePicker')) { - this._init(this.datePicker); + this._init(this.datePicker!); } } diff --git a/src/elements/datepicker/datepicker-toggle/readme.md b/src/elements/datepicker/datepicker-toggle/readme.md index cfbfd229f22..2dcdff6fc53 100644 --- a/src/elements/datepicker/datepicker-toggle/readme.md +++ b/src/elements/datepicker/datepicker-toggle/readme.md @@ -36,11 +36,11 @@ both standalone or within the `sbb-form-field`, they must have the same parent e ## Properties -| Name | Attribute | Privacy | Type | Default | Description | -| ------------ | ------------- | ------- | --------------------------------------------- | ------- | ------------------------------------------------------------------ | -| `datePicker` | `date-picker` | public | `string \| SbbDatepickerElement \| undefined` | | Datepicker reference. | -| `negative` | `negative` | public | `boolean` | `false` | Negative coloring variant flag. | -| `view` | `view` | public | `CalendarView` | `'day'` | The initial view of calendar which should be displayed on opening. | +| Name | Attribute | Privacy | Type | Default | Description | +| ------------ | ------------- | ------- | --------------------------------------------------- | ------- | ------------------------------------------------------------------ | +| `datePicker` | `date-picker` | public | `\| string \| SbbDatepickerElement \| null` | `null` | Datepicker reference. | +| `negative` | `negative` | public | `boolean` | `false` | Negative coloring variant flag. | +| `view` | `view` | public | `CalendarView` | `'day'` | The initial view of calendar which should be displayed on opening. | ## Methods diff --git a/src/elements/datepicker/datepicker/datepicker.ts b/src/elements/datepicker/datepicker/datepicker.ts index 8a8c735c880..20f4f20365f 100644 --- a/src/elements/datepicker/datepicker/datepicker.ts +++ b/src/elements/datepicker/datepicker/datepicker.ts @@ -11,6 +11,7 @@ import { customElement, property, state } from 'lit/decorators.js'; import { readConfig } from '../../core/config.js'; import { SbbConnectedAbortController, SbbLanguageController } from '../../core/controllers.js'; import { type DateAdapter, defaultDateAdapter } from '../../core/datetime.js'; +import { forceType } from '../../core/decorators.js'; import { findInput, findReferencedElement } from '../../core/dom.js'; import { EventEmitter } from '../../core/eventing.js'; import { i18nDateChangedTo, i18nDatePickerPlaceholder } from '../../core/i18n.js'; @@ -177,12 +178,9 @@ export const datepickerControlRegisteredEventFactory = (): CustomEvent => * @event {CustomEvent} datePickerUpdated - Notifies that the attributes of the datepicker have changes. * @event {CustomEvent} validationChange - Emits whenever the internal validation state changes. */ +export @customElement('sbb-datepicker') -export class SbbDatepickerElement extends LitElement { - /* eslint-disable @typescript-eslint/member-ordering -- - * We deactivate member-ordering because of the @property decorated methods dateFilter, dateParser and format. - */ - +class SbbDatepickerElement extends LitElement { public static override styles: CSSResultGroup = style; public static readonly events = { didChange: 'didChange', @@ -193,25 +191,26 @@ export class SbbDatepickerElement extends LitElement { } as const; /** If set to true, two months are displayed. */ - @property({ type: Boolean }) public wide = false; + @property({ type: Boolean }) @forceType(Boolean) public accessor wide: boolean = false; /** A function used to filter out dates. */ - @property({ attribute: false }) public dateFilter: (date: T | null) => boolean = () => true; + @property({ attribute: false }) public accessor dateFilter: (date: T | null) => boolean = () => + true; /** * A function used to parse string value into dates. * @deprecated No longer required. */ - @property({ attribute: false }) public dateParser?: (value: string) => T | undefined; + @property({ attribute: false }) public accessor dateParser: ((value: string) => T) | null = null; /** * A function used to format dates into the preferred string format. * @deprecated No longer required. */ - @property({ attribute: false }) public format?: (date: T) => string; + @property({ attribute: false }) public accessor format: ((date: T) => string) | null = null; /** Reference of the native input connected to the datepicker. */ - @property() public input?: string | HTMLElement; + @property() public accessor input: string | HTMLElement | null = null; // TODO: Change undefined to null as a breaking change. /** A configured date which acts as the current date instead of the real current date. Recommended for testing purposes. */ @@ -276,7 +275,7 @@ export class SbbDatepickerElement extends LitElement { ); @state() - private _inputElement: HTMLInputElement | null = null; + private accessor _inputElement: HTMLInputElement | null = null; private _inputElementPlaceholderMutable = false; private _datePickerController!: AbortController; @@ -487,7 +486,6 @@ export class SbbDatepickerElement extends LitElement { protected override render(): TemplateResult { return html`

`; } - /* eslint-enable @typescript-eslint/member-ordering */ } declare global { diff --git a/src/elements/datepicker/datepicker/readme.md b/src/elements/datepicker/datepicker/readme.md index dd38f2f2908..a8ca76d0c00 100644 --- a/src/elements/datepicker/datepicker/readme.md +++ b/src/elements/datepicker/datepicker/readme.md @@ -104,15 +104,15 @@ Whenever the validation state changes (e.g., a valid value becomes invalid or vi ## Properties -| Name | Attribute | Privacy | Type | Default | Description | -| ------------- | --------- | ------- | ------------------------------------------------ | ------- | -------------------------------------------------------------------------------------------------------------------- | -| `dateFilter` | - | public | `(date: T \| null) => boolean` | | A function used to filter out dates. | -| `dateParser` | - | public | `(value: string) => T \| undefined \| undefined` | | A function used to parse string value into dates. | -| `format` | - | public | `(date: T) => string \| undefined` | | A function used to format dates into the preferred string format. | -| `input` | `input` | public | `string \| HTMLElement \| undefined` | | Reference of the native input connected to the datepicker. | -| `now` | `now` | public | `T` | | A configured date which acts as the current date instead of the real current date. Recommended for testing purposes. | -| `valueAsDate` | - | public | `T \| null` | | The currently selected date as a Date or custom date provider instance. | -| `wide` | `wide` | public | `boolean` | `false` | If set to true, two months are displayed. | +| Name | Attribute | Privacy | Type | Default | Description | +| ------------- | --------- | ------- | -------------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------- | +| `dateFilter` | - | public | `(date: T \| null) => boolean` | | A function used to filter out dates. | +| `dateParser` | - | public | `((value: string) => T) \| null` | `null` | A function used to parse string value into dates. | +| `format` | - | public | `((date: T) => string) \| null` | `null` | A function used to format dates into the preferred string format. | +| `input` | `input` | public | `string \| HTMLElement \| null` | `null` | Reference of the native input connected to the datepicker. | +| `now` | `now` | public | `T` | | A configured date which acts as the current date instead of the real current date. Recommended for testing purposes. | +| `valueAsDate` | - | public | `T \| null` | | The currently selected date as a Date or custom date provider instance. | +| `wide` | `wide` | public | `boolean` | `false` | If set to true, two months are displayed. | ## Methods diff --git a/src/elements/dialog/dialog-actions/dialog-actions.ts b/src/elements/dialog/dialog-actions/dialog-actions.ts index 60b4a8ad61f..b6c048b7c35 100644 --- a/src/elements/dialog/dialog-actions/dialog-actions.ts +++ b/src/elements/dialog/dialog-actions/dialog-actions.ts @@ -11,8 +11,9 @@ import style from './dialog-actions.scss?lit&inline'; * * @slot - Use the unnamed slot to add `sbb-block-link` or `sbb-button` elements to the `sbb-dialog-actions`. */ +export @customElement('sbb-dialog-actions') -export class SbbDialogActionsElement extends SbbActionGroupElement { +class SbbDialogActionsElement extends SbbActionGroupElement { public static override styles: CSSResultGroup = [SbbActionGroupElement.styles, style]; protected override render(): TemplateResult { diff --git a/src/elements/dialog/dialog-content/dialog-content.ts b/src/elements/dialog/dialog-content/dialog-content.ts index b1143f6308c..ddb67269cbe 100644 --- a/src/elements/dialog/dialog-content/dialog-content.ts +++ b/src/elements/dialog/dialog-content/dialog-content.ts @@ -9,8 +9,9 @@ import style from './dialog-content.scss?lit&inline'; * * @slot - Use the unnamed slot to provide a dialog content. */ +export @customElement('sbb-dialog-content') -export class SbbDialogContentElement extends LitElement { +class SbbDialogContentElement extends LitElement { public static override styles: CSSResultGroup = style; protected override render(): TemplateResult { diff --git a/src/elements/dialog/dialog-title/dialog-title.ts b/src/elements/dialog/dialog-title/dialog-title.ts index 8740aa302d8..0bc5e3f7ae9 100644 --- a/src/elements/dialog/dialog-title/dialog-title.ts +++ b/src/elements/dialog/dialog-title/dialog-title.ts @@ -5,6 +5,7 @@ import { html, unsafeStatic } from 'lit/static-html.js'; import { SbbFocusVisibleWithinController } from '../../core/a11y.js'; import { SbbLanguageController } from '../../core/controllers.js'; +import { forceType } from '../../core/decorators.js'; import type { Breakpoint } from '../../core/dom.js'; import { EventEmitter } from '../../core/eventing.js'; import { i18nCloseDialog, i18nGoBack } from '../../core/i18n.js'; @@ -20,8 +21,9 @@ import '../../button/transparent-button.js'; * * @event {CustomEvent} requestBackAction - Emits whenever the back button is clicked. */ +export @customElement('sbb-dialog-title') -export class SbbDialogTitleElement extends SbbTitleBase { +class SbbDialogTitleElement extends SbbTitleBase { public static override styles: CSSResultGroup = [SbbTitleBase.styles, style]; public static readonly events: Record = { backClick: 'requestBackAction', @@ -30,21 +32,21 @@ export class SbbDialogTitleElement extends SbbTitleBase { /** * Whether a back button is displayed next to the title. */ - @property({ attribute: 'back-button', type: Boolean }) public backButton = false; + @property({ attribute: 'back-button', type: Boolean }) + @forceType(Boolean) + public accessor backButton: boolean = false; /** * This will be forwarded as aria-label to the close button element. */ - @property({ attribute: 'accessibility-close-label' }) public accessibilityCloseLabel: - | string - | undefined; + @property({ attribute: 'accessibility-close-label' }) + public accessor accessibilityCloseLabel: string = ''; /** * This will be forwarded as aria-label to the back button element. */ - @property({ attribute: 'accessibility-back-label' }) public accessibilityBackLabel: - | string - | undefined; + @property({ attribute: 'accessibility-back-label' }) + public accessor accessibilityBackLabel: string = ''; /** * Whether to hide the title up to a certain breakpoint. diff --git a/src/elements/dialog/dialog-title/readme.md b/src/elements/dialog/dialog-title/readme.md index b0a7ddf552d..d3738bcb98c 100644 --- a/src/elements/dialog/dialog-title/readme.md +++ b/src/elements/dialog/dialog-title/readme.md @@ -42,16 +42,16 @@ If a back button is displayed it emits a `requestBackAction` event on click. ## Properties -| Name | Attribute | Privacy | Type | Default | Description | -| ------------------------- | --------------------------- | ------- | ---------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `accessibilityBackLabel` | `accessibility-back-label` | public | `\| string \| undefined` | | This will be forwarded as aria-label to the back button element. | -| `accessibilityCloseLabel` | `accessibility-close-label` | public | `\| string \| undefined` | | This will be forwarded as aria-label to the close button element. | -| `backButton` | `back-button` | public | `boolean` | `false` | Whether a back button is displayed next to the title. | -| `hideOnScroll` | `hide-on-scroll` | public | `Breakpoint \| boolean` | `false` | Whether to hide the title up to a certain breakpoint. | -| `level` | `level` | public | `SbbTitleLevel` | `'2'` | Title level | -| `negative` | `negative` | public | `boolean` | `false` | Negative coloring variant flag. | -| `visualLevel` | `visual-level` | public | `SbbTitleLevel \| undefined` | `'3'` | Visual level for the title. Optional, if not set, the value of level will be used. | -| `visuallyHidden` | `visually-hidden` | public | `boolean \| undefined` | | Sometimes we need a title in the markup to present a proper hierarchy to the screen readers while we do not want to let that title appear visually. In this case we set visuallyHidden to true. | +| Name | Attribute | Privacy | Type | Default | Description | +| ------------------------- | --------------------------- | ------- | ----------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `accessibilityBackLabel` | `accessibility-back-label` | public | `string` | `''` | This will be forwarded as aria-label to the back button element. | +| `accessibilityCloseLabel` | `accessibility-close-label` | public | `string` | `''` | This will be forwarded as aria-label to the close button element. | +| `backButton` | `back-button` | public | `boolean` | `false` | Whether a back button is displayed next to the title. | +| `hideOnScroll` | `hide-on-scroll` | public | `Breakpoint \| boolean` | `false` | Whether to hide the title up to a certain breakpoint. | +| `level` | `level` | public | `SbbTitleLevel` | `'2'` | Title level | +| `negative` | `negative` | public | `boolean` | `false` | Negative coloring variant flag. | +| `visualLevel` | `visual-level` | public | `SbbTitleLevel \| null` | `'3'` | Visual level for the title. Optional, if not set, the value of level will be used. | +| `visuallyHidden` | `visually-hidden` | public | `boolean` | `false` | Sometimes we need a title in the markup to present a proper hierarchy to the screen readers while we do not want to let that title appear visually. In this case we set visuallyHidden to true. | ## Events diff --git a/src/elements/dialog/dialog/dialog.ts b/src/elements/dialog/dialog/dialog.ts index 562e0961ce7..2bb07a6cb8f 100644 --- a/src/elements/dialog/dialog/dialog.ts +++ b/src/elements/dialog/dialog/dialog.ts @@ -27,12 +27,14 @@ let nextId = 0; * the `z-index` can be overridden by defining this CSS variable. The default `z-index` of the * component is set to `var(--sbb-overlay-default-z-index)` with a value of `1000`. */ +export @customElement('sbb-dialog') -export class SbbDialogElement extends SbbOverlayBaseElement { +class SbbDialogElement extends SbbOverlayBaseElement { public static override styles: CSSResultGroup = style; /** Backdrop click action. */ - @property({ attribute: 'backdrop-action' }) public backdropAction: 'close' | 'none' = 'close'; + @property({ attribute: 'backdrop-action' }) public accessor backdropAction: 'close' | 'none' = + 'close'; // We use a timeout as a workaround to the "ResizeObserver loop completed with undelivered notifications" error. // For more details: diff --git a/src/elements/dialog/dialog/readme.md b/src/elements/dialog/dialog/readme.md index 20712652e3f..26162e7ce30 100644 --- a/src/elements/dialog/dialog/readme.md +++ b/src/elements/dialog/dialog/readme.md @@ -90,12 +90,12 @@ The `sbb-dialog` component may visually hide the title thanks to the `hideOnScro ## Properties -| Name | Attribute | Privacy | Type | Default | Description | -| -------------------- | --------------------- | ------- | --------------------- | --------- | ----------------------------------------------------------------------------------------------------------- | -| `accessibilityLabel` | `accessibility-label` | public | `string \| undefined` | | This will be forwarded as aria-label to the relevant nested element to describe the purpose of the overlay. | -| `backdropAction` | `backdrop-action` | public | `'close' \| 'none'` | `'close'` | Backdrop click action. | -| `isOpen` | - | public | `boolean` | | Whether the element is open. | -| `negative` | `negative` | public | `boolean` | `false` | Negative coloring variant flag. | +| Name | Attribute | Privacy | Type | Default | Description | +| -------------------- | --------------------- | ------- | ------------------- | --------- | ----------------------------------------------------------------------------------------------------------- | +| `accessibilityLabel` | `accessibility-label` | public | `string` | `''` | This will be forwarded as aria-label to the relevant nested element to describe the purpose of the overlay. | +| `backdropAction` | `backdrop-action` | public | `'close' \| 'none'` | `'close'` | Backdrop click action. | +| `isOpen` | - | public | `boolean` | | Whether the element is open. | +| `negative` | `negative` | public | `boolean` | `false` | Negative coloring variant flag. | ## Methods diff --git a/src/elements/divider/divider.ts b/src/elements/divider/divider.ts index 1200986fb02..970542ce5b9 100644 --- a/src/elements/divider/divider.ts +++ b/src/elements/divider/divider.ts @@ -11,15 +11,16 @@ import style from './divider.scss?lit&inline'; /** * It displays a divider between sections. */ +export @customElement('sbb-divider') @hostAttributes({ role: 'separator', }) -export class SbbDividerElement extends SbbNegativeMixin(LitElement) { +class SbbDividerElement extends SbbNegativeMixin(LitElement) { public static override styles: CSSResultGroup = style; /** Orientation property with possible values 'horizontal' | 'vertical'. Defaults to horizontal. */ - @property({ reflect: true }) public orientation: SbbOrientation = 'horizontal'; + @property({ reflect: true }) public accessor orientation: SbbOrientation = 'horizontal'; protected override willUpdate(changedProperties: PropertyValues): void { super.willUpdate(changedProperties); diff --git a/src/elements/expansion-panel/expansion-panel-content/expansion-panel-content.ts b/src/elements/expansion-panel/expansion-panel-content/expansion-panel-content.ts index f75db2825d9..2026f69cd62 100644 --- a/src/elements/expansion-panel/expansion-panel-content/expansion-panel-content.ts +++ b/src/elements/expansion-panel/expansion-panel-content/expansion-panel-content.ts @@ -11,12 +11,13 @@ import style from './expansion-panel-content.scss?lit&inline'; * * @slot - Use the unnamed slot to add content to the `sbb-expansion-panel`. */ +export @customElement('sbb-expansion-panel-content') @hostAttributes({ role: 'region', slot: 'content', }) -export class SbbExpansionPanelContentElement extends LitElement { +class SbbExpansionPanelContentElement extends LitElement { public static override styles: CSSResultGroup = style; protected override render(): TemplateResult { diff --git a/src/elements/expansion-panel/expansion-panel-header/expansion-panel-header.ts b/src/elements/expansion-panel/expansion-panel-header/expansion-panel-header.ts index 59ddc3bddb2..939653a380e 100644 --- a/src/elements/expansion-panel/expansion-panel-header/expansion-panel-header.ts +++ b/src/elements/expansion-panel/expansion-panel-header/expansion-panel-header.ts @@ -18,11 +18,12 @@ import style from './expansion-panel-header.scss?lit&inline'; * @slot icon - Slot used to render the `sbb-expansion-panel-header` icon. * @event {CustomEvent} toggleExpanded - Notifies that the `sbb-expansion-panel` has to expand. */ +export @customElement('sbb-expansion-panel-header') @hostAttributes({ slot: 'header', }) -export class SbbExpansionPanelHeaderElement extends SbbDisabledTabIndexActionMixin( +class SbbExpansionPanelHeaderElement extends SbbDisabledTabIndexActionMixin( SbbIconNameMixin(SbbButtonBaseElement), ) { public static override styles: CSSResultGroup = style; diff --git a/src/elements/expansion-panel/expansion-panel-header/readme.md b/src/elements/expansion-panel/expansion-panel-header/readme.md index 1535bc06b1f..2b097b30323 100644 --- a/src/elements/expansion-panel/expansion-panel-header/readme.md +++ b/src/elements/expansion-panel/expansion-panel-header/readme.md @@ -35,15 +35,15 @@ When the element is clicked, the `toggleExpanded` event is emitted. ## Properties -| Name | Attribute | Privacy | Type | Default | Description | -| --------------------- | ---------------------- | ------- | --------------------- | ---------- | -------------------------------------------------------------------------------------------------------------------------------- | -| `disabled` | `disabled` | public | `boolean` | `false` | Whether the component is disabled. | -| `disabledInteractive` | `disabled-interactive` | public | `boolean` | `false` | Whether disabled buttons should be interactive. | -| `form` | `form` | public | `string \| undefined` | | The element to associate the button with. | -| `iconName` | `icon-name` | public | `string \| undefined` | | The icon name we want to use, choose from the small icon variants from the ui-icons category from here https://icons.app.sbb.ch. | -| `name` | `name` | public | `string` | | The name of the button element. | -| `type` | `type` | public | `SbbButtonType` | `'button'` | The type attribute to use for the button. | -| `value` | `value` | public | `string` | | The value of the button element. | +| Name | Attribute | Privacy | Type | Default | Description | +| --------------------- | ---------------------- | ------- | ---------------- | ---------- | -------------------------------------------------------------------------------------------------------------------------------- | +| `disabled` | `disabled` | public | `boolean` | `false` | Whether the component is disabled. | +| `disabledInteractive` | `disabled-interactive` | public | `boolean` | `false` | Whether disabled buttons should be interactive. | +| `form` | `form` | public | `string` | `''` | The element to associate the button with. | +| `iconName` | `icon-name` | public | `string \| null` | `null` | The icon name we want to use, choose from the small icon variants from the ui-icons category from here https://icons.app.sbb.ch. | +| `name` | `name` | public | `string` | | The name of the button element. | +| `type` | `type` | public | `SbbButtonType` | `'button'` | The type attribute to use for the button. | +| `value` | `value` | public | `string` | | The value of the button element. | ## Events diff --git a/src/elements/expansion-panel/expansion-panel/expansion-panel.ts b/src/elements/expansion-panel/expansion-panel/expansion-panel.ts index e9e9d6d5790..4b1194a7b0d 100644 --- a/src/elements/expansion-panel/expansion-panel/expansion-panel.ts +++ b/src/elements/expansion-panel/expansion-panel/expansion-panel.ts @@ -4,6 +4,7 @@ import { customElement, property } from 'lit/decorators.js'; import { html, unsafeStatic } from 'lit/static-html.js'; import { SbbConnectedAbortController } from '../../core/controllers.js'; +import { forceType } from '../../core/decorators.js'; import { EventEmitter } from '../../core/eventing.js'; import type { SbbOpenedClosedState } from '../../core/interfaces.js'; import { SbbHydrationMixin } from '../../core/mixins.js'; @@ -24,8 +25,9 @@ let nextId = 0; * @event {CustomEvent} willClose - Emits whenever the `sbb-expansion-panel` begins the closing transition. * @event {CustomEvent} didClose - Emits whenever the `sbb-expansion-panel` is closed. */ +export @customElement('sbb-expansion-panel') -export class SbbExpansionPanelElement extends SbbHydrationMixin(LitElement) { +class SbbExpansionPanelElement extends SbbHydrationMixin(LitElement) { public static override styles: CSSResultGroup = style; public static readonly events = { willOpen: 'willOpen', @@ -35,10 +37,10 @@ export class SbbExpansionPanelElement extends SbbHydrationMixin(LitElement) { } as const; /** Heading level; if unset, a `div` will be rendered. */ - @property({ attribute: 'title-level' }) public titleLevel?: SbbTitleLevel | null; + @property({ attribute: 'title-level' }) public accessor titleLevel: SbbTitleLevel | null = null; /** The background color of the panel. */ - @property() public color: 'white' | 'milk' = 'white'; + @property() public accessor color: 'white' | 'milk' = 'white'; /** Whether the panel is expanded. */ @property({ reflect: true, type: Boolean }) @@ -63,10 +65,12 @@ export class SbbExpansionPanelElement extends SbbHydrationMixin(LitElement) { private _disabled: boolean = false; /** Whether the panel has no border. */ - @property({ reflect: true, type: Boolean }) public borderless = false; + @property({ reflect: true, type: Boolean }) + @forceType(Boolean) + public accessor borderless: boolean = false; /** Size variant, either l or s. */ - @property({ reflect: true }) public size: 's' | 'l' = 'l'; + @property({ reflect: true }) public accessor size: 's' | 'l' = 'l'; /** * The state of the notification. diff --git a/src/elements/expansion-panel/expansion-panel/readme.md b/src/elements/expansion-panel/expansion-panel/readme.md index 9a0d16f5d45..0b694e49f5d 100644 --- a/src/elements/expansion-panel/expansion-panel/readme.md +++ b/src/elements/expansion-panel/expansion-panel/readme.md @@ -86,14 +86,14 @@ This can be achieved by adding an `aria-label`, `aria-labelledby` or `aria-descr ## Properties -| Name | Attribute | Privacy | Type | Default | Description | -| ------------ | ------------- | ------- | ------------------------------------ | --------- | ---------------------------------------------------------------------- | -| `borderless` | `borderless` | public | `boolean` | `false` | Whether the panel has no border. | -| `color` | `color` | public | `'white' \| 'milk'` | `'white'` | The background color of the panel. | -| `disabled` | `disabled` | public | `boolean` | `false` | Whether the panel is disabled, so its expanded state can't be changed. | -| `expanded` | `expanded` | public | `boolean` | `false` | Whether the panel is expanded. | -| `size` | `size` | public | `'s' \| 'l'` | `'l'` | Size variant, either l or s. | -| `titleLevel` | `title-level` | public | `SbbTitleLevel \| null \| undefined` | | Heading level; if unset, a `div` will be rendered. | +| Name | Attribute | Privacy | Type | Default | Description | +| ------------ | ------------- | ------- | ----------------------- | --------- | ---------------------------------------------------------------------- | +| `borderless` | `borderless` | public | `boolean` | `false` | Whether the panel has no border. | +| `color` | `color` | public | `'white' \| 'milk'` | `'white'` | The background color of the panel. | +| `disabled` | `disabled` | public | `boolean` | `false` | Whether the panel is disabled, so its expanded state can't be changed. | +| `expanded` | `expanded` | public | `boolean` | `false` | Whether the panel is expanded. | +| `size` | `size` | public | `'s' \| 'l'` | `'l'` | Size variant, either l or s. | +| `titleLevel` | `title-level` | public | `SbbTitleLevel \| null` | `null` | Heading level; if unset, a `div` will be rendered. | ## Events diff --git a/src/elements/file-selector/file-selector.ts b/src/elements/file-selector/file-selector.ts index 64b3c47a034..26417a6da41 100644 --- a/src/elements/file-selector/file-selector.ts +++ b/src/elements/file-selector/file-selector.ts @@ -7,7 +7,7 @@ import { html, unsafeStatic } from 'lit/static-html.js'; import type { SbbSecondaryButtonStaticElement } from '../button.js'; import { sbbInputModalityDetector } from '../core/a11y.js'; import { SbbLanguageController } from '../core/controllers.js'; -import { slotState } from '../core/decorators.js'; +import { forceType, slotState } from '../core/decorators.js'; import { EventEmitter } from '../core/eventing.js'; import { i18nFileSelectorButtonLabel, @@ -31,38 +31,39 @@ export type DOMEvent = globalThis.Event; * @slot error - Use this to provide a `sbb-form-error` to show an error message. * @event {CustomEvent} fileChanged - An event which is emitted each time the file list changes. */ +export @customElement('sbb-file-selector') @slotState() -export class SbbFileSelectorElement extends SbbDisabledMixin(LitElement) { +class SbbFileSelectorElement extends SbbDisabledMixin(LitElement) { public static override styles: CSSResultGroup = style; public static readonly events = { fileChangedEvent: 'fileChanged', } as const; /** Whether the component has a dropzone area or not. */ - @property() public variant: 'default' | 'dropzone' = 'default'; + @property() public accessor variant: 'default' | 'dropzone' = 'default'; /** Size variant, either s or m. */ - @property({ reflect: true }) public size: 's' | 'm' = 'm'; + @property({ reflect: true }) public accessor size: 's' | 'm' = 'm'; /** Whether more than one file can be selected. */ - @property({ type: Boolean }) public multiple: boolean = false; + @property({ type: Boolean }) @forceType(Boolean) public accessor multiple: boolean = false; /** Whether the newly added files should override the previously added ones. */ @property({ attribute: 'multiple-mode' }) - public multipleMode: 'default' | 'persistent' = 'default'; + public accessor multipleMode: 'default' | 'persistent' = 'default'; /** A comma-separated list of allowed unique file type specifiers. */ - @property() public accept?: string; + @property() public accessor accept: string = ''; /** The title displayed in `dropzone` variant. */ - @property({ attribute: 'title-content' }) public titleContent?: string; + @property({ attribute: 'title-content' }) public accessor titleContent: string = ''; /** This will be forwarded as aria-label to the native input element. */ - @property({ attribute: 'accessibility-label' }) public accessibilityLabel: string | undefined; + @property({ attribute: 'accessibility-label' }) public accessor accessibilityLabel: string = ''; /** The list of selected files. */ - @state() private _files?: File[]; + @state() private accessor _files!: File[]; /** An event which is emitted each time the file list changes. */ private _fileChangedEvent: EventEmitter = new EventEmitter( diff --git a/src/elements/file-selector/readme.md b/src/elements/file-selector/readme.md index 7be0291c444..8de8a065564 100644 --- a/src/elements/file-selector/readme.md +++ b/src/elements/file-selector/readme.md @@ -90,14 +90,14 @@ It's suggested to have a different value for each variant, e.g.: | Name | Attribute | Privacy | Type | Default | Description | | -------------------- | --------------------- | ------- | --------------------------- | ----------- | ------------------------------------------------------------------------ | -| `accept` | `accept` | public | `string \| undefined` | | A comma-separated list of allowed unique file type specifiers. | -| `accessibilityLabel` | `accessibility-label` | public | `string \| undefined` | | This will be forwarded as aria-label to the native input element. | +| `accept` | `accept` | public | `string` | `''` | A comma-separated list of allowed unique file type specifiers. | +| `accessibilityLabel` | `accessibility-label` | public | `string` | `''` | This will be forwarded as aria-label to the native input element. | | `disabled` | `disabled` | public | `boolean` | `false` | Whether the component is disabled. | | `files` | - | public | `File[]` | | Gets the currently selected files. | | `multiple` | `multiple` | public | `boolean` | `false` | Whether more than one file can be selected. | | `multipleMode` | `multiple-mode` | public | `'default' \| 'persistent'` | `'default'` | Whether the newly added files should override the previously added ones. | | `size` | `size` | public | `'s' \| 'm'` | `'m'` | Size variant, either s or m. | -| `titleContent` | `title-content` | public | `string \| undefined` | | The title displayed in `dropzone` variant. | +| `titleContent` | `title-content` | public | `string` | `''` | The title displayed in `dropzone` variant. | | `variant` | `variant` | public | `'default' \| 'dropzone'` | `'default'` | Whether the component has a dropzone area or not. | ## Methods diff --git a/src/elements/flip-card/flip-card-details/flip-card-details.ts b/src/elements/flip-card/flip-card-details/flip-card-details.ts index 49584d3f47c..46556e0d338 100644 --- a/src/elements/flip-card/flip-card-details/flip-card-details.ts +++ b/src/elements/flip-card/flip-card-details/flip-card-details.ts @@ -13,11 +13,12 @@ import style from './flip-card-details.scss?lit&inline'; * * @slot - Use the unnamed slot to provide any kind of content. */ +export @customElement('sbb-flip-card-details') @hostAttributes({ slot: 'details', }) -export class SbbFlipCardDetailsElement extends LitElement { +class SbbFlipCardDetailsElement extends LitElement { public static override styles: CSSResultGroup = style; public constructor() { diff --git a/src/elements/flip-card/flip-card-summary/flip-card-summary.ts b/src/elements/flip-card/flip-card-summary/flip-card-summary.ts index 56b02539310..25539dcb2b3 100644 --- a/src/elements/flip-card/flip-card-summary/flip-card-summary.ts +++ b/src/elements/flip-card/flip-card-summary/flip-card-summary.ts @@ -14,16 +14,17 @@ export type SbbFlipCardImageAlignment = 'after' | 'below'; * @slot - Use the unnamed slot to provide a title for the `sbb-flip-card-summary`. * @slot image - Use this slot to provide an image for the `sbb-flip-card-summary`. */ +export @customElement('sbb-flip-card-summary') @hostAttributes({ slot: 'summary', }) -export class SbbFlipCardSummaryElement extends LitElement { +class SbbFlipCardSummaryElement extends LitElement { public static override styles: CSSResultGroup = style; /** The position where to render the image. */ @property({ attribute: 'image-alignment', reflect: true }) - public imageAlignment: SbbFlipCardImageAlignment = 'after'; + public accessor imageAlignment: SbbFlipCardImageAlignment = 'after'; protected override willUpdate(_changedProperties: PropertyValues): void { super.willUpdate(_changedProperties); diff --git a/src/elements/flip-card/flip-card/flip-card.ts b/src/elements/flip-card/flip-card/flip-card.ts index 0d697b08874..e8e8ee1c896 100644 --- a/src/elements/flip-card/flip-card/flip-card.ts +++ b/src/elements/flip-card/flip-card/flip-card.ts @@ -22,8 +22,9 @@ import '../../screen-reader-only.js'; * @event {CustomEvent} flip - Emits when the flip card flips. * */ +export @customElement('sbb-flip-card') -export class SbbFlipCardElement extends SbbHydrationMixin(LitElement) { +class SbbFlipCardElement extends SbbHydrationMixin(LitElement) { public static override styles: CSSResultGroup = style; public static readonly events = { flip: 'flip', @@ -33,7 +34,7 @@ export class SbbFlipCardElement extends SbbHydrationMixin(LitElement) { * This will be forwarded as aria-label to the action in the non flipped state. * If not set, the textContent of the `sbb-flip-card-summary` is taken. */ - @property({ attribute: 'accessibility-label' }) public accessibilityLabel: string | undefined; + @property({ attribute: 'accessibility-label' }) public accessor accessibilityLabel: string = ''; /** Emits whenever the component is flipped. */ protected flip: EventEmitter = new EventEmitter(this, SbbFlipCardElement.events.flip); @@ -54,7 +55,7 @@ export class SbbFlipCardElement extends SbbHydrationMixin(LitElement) { } /** Whether the card is flipped or not. */ - @state() private _flipped = false; + @state() private accessor _flipped = false; private _abort = new SbbConnectedAbortController(this); private _language = new SbbLanguageController(this); diff --git a/src/elements/flip-card/flip-card/readme.md b/src/elements/flip-card/flip-card/readme.md index 41e986a2a77..44483bc260d 100644 --- a/src/elements/flip-card/flip-card/readme.md +++ b/src/elements/flip-card/flip-card/readme.md @@ -25,7 +25,7 @@ The `sbb-flip-card` will switch to the flipped state after the user clicks on it | Name | Attribute | Privacy | Type | Default | Description | | -------------------- | --------------------- | ------- | ----------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | -| `accessibilityLabel` | `accessibility-label` | public | `string \| undefined` | | This will be forwarded as aria-label to the action in the non flipped state. If not set, the textContent of the `sbb-flip-card-summary` is taken. | +| `accessibilityLabel` | `accessibility-label` | public | `string` | `''` | This will be forwarded as aria-label to the action in the non flipped state. If not set, the textContent of the `sbb-flip-card-summary` is taken. | | `details` | - | public | `SbbFlipCardDetailsElement \| null` | | Returns the slotted sbb-flip-card-details. | | `isFlipped` | - | public | `boolean` | | Whether the flip card is flipped. | | `summary` | - | public | `SbbFlipCardSummaryElement \| null` | | Returns the slotted sbb-flip-card-summary. | diff --git a/src/elements/footer/footer.ts b/src/elements/footer/footer.ts index 8cfc9d690b8..e2358d51087 100644 --- a/src/elements/footer/footer.ts +++ b/src/elements/footer/footer.ts @@ -3,6 +3,7 @@ import { LitElement, nothing } from 'lit'; import { customElement, property } from 'lit/decorators.js'; import { html, unsafeStatic } from 'lit/static-html.js'; +import { forceType } from '../core/decorators.js'; import { SbbNegativeMixin } from '../core/mixins.js'; import type { SbbTitleLevel } from '../title.js'; @@ -13,8 +14,9 @@ import style from './footer.scss?lit&inline'; * * @slot - Use the unnamed slot to add elements like `sbb-block-link`, `sbb-link-list`, `sbb-divider` and so on. */ +export @customElement('sbb-footer') -export class SbbFooterElement extends SbbNegativeMixin(LitElement) { +class SbbFooterElement extends SbbNegativeMixin(LitElement) { public static override styles: CSSResultGroup = style; /** @@ -22,20 +24,22 @@ export class SbbFooterElement extends SbbNegativeMixin(LitElement) { * approach. The clock-columns, used a css-grid for displaying the content over different * breakpoints. */ - @property({ reflect: true }) public variant: 'default' | 'clock-columns' = 'default'; + @property({ reflect: true }) public accessor variant: 'default' | 'clock-columns' = 'default'; /** * Whether to allow the footer content to stretch to full width. * By default, the content has the appropriate page size. */ - @property({ reflect: true, type: Boolean }) public expanded = false; + @property({ reflect: true, type: Boolean }) + @forceType(Boolean) + public accessor expanded: boolean = false; /** Footer title text, visually hidden, necessary for screen readers. */ - @property({ attribute: 'accessibility-title' }) public accessibilityTitle?: string; + @property({ attribute: 'accessibility-title' }) public accessor accessibilityTitle: string = ''; /** Level of the accessibility title, will be rendered as heading tag (e.g. h1). Defaults to level 1. */ @property({ attribute: 'accessibility-title-level' }) - public accessibilityTitleLevel: SbbTitleLevel = '1'; + public accessor accessibilityTitleLevel: SbbTitleLevel = '1'; protected override render(): TemplateResult { const TITLE_TAG_NAME = `h${this.accessibilityTitleLevel}`; diff --git a/src/elements/footer/readme.md b/src/elements/footer/readme.md index 7c1c5281c95..fe0c2621479 100644 --- a/src/elements/footer/readme.md +++ b/src/elements/footer/readme.md @@ -77,7 +77,7 @@ to the content where needed (e.g. `sbb-link-list`, `sbb-link` and `sbb-divider`) | Name | Attribute | Privacy | Type | Default | Description | | ------------------------- | --------------------------- | ------- | ------------------------------ | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `accessibilityTitle` | `accessibility-title` | public | `string \| undefined` | | Footer title text, visually hidden, necessary for screen readers. | +| `accessibilityTitle` | `accessibility-title` | public | `string` | `''` | Footer title text, visually hidden, necessary for screen readers. | | `accessibilityTitleLevel` | `accessibility-title-level` | public | `SbbTitleLevel` | `'1'` | Level of the accessibility title, will be rendered as heading tag (e.g. h1). Defaults to level 1. | | `expanded` | `expanded` | public | `boolean` | `false` | Whether to allow the footer content to stretch to full width. By default, the content has the appropriate page size. | | `negative` | `negative` | public | `boolean` | `false` | Negative coloring variant flag. | diff --git a/src/elements/form-error/form-error.ts b/src/elements/form-error/form-error.ts index 48a06ddeac1..f3e47452b6f 100644 --- a/src/elements/form-error/form-error.ts +++ b/src/elements/form-error/form-error.ts @@ -14,8 +14,9 @@ let nextId = 0; * @slot - Use this slot to display the error message. * @slot icon - Use this slot to override the default error icon. */ +export @customElement('sbb-form-error') -export class SbbFormErrorElement extends SbbNegativeMixin(LitElement) { +class SbbFormErrorElement extends SbbNegativeMixin(LitElement) { public static override styles: CSSResultGroup = style; public override connectedCallback(): void { diff --git a/src/elements/form-field/form-field-clear/form-field-clear.ts b/src/elements/form-field/form-field-clear/form-field-clear.ts index 8878e776926..5dda4be5d67 100644 --- a/src/elements/form-field/form-field-clear/form-field-clear.ts +++ b/src/elements/form-field/form-field-clear/form-field-clear.ts @@ -16,11 +16,12 @@ import '../../icon.js'; /** * Combined with `sbb-form-field`, it displays a button which clears the input value. */ +export @customElement('sbb-form-field-clear') @hostAttributes({ slot: 'suffix', }) -export class SbbFormFieldClearElement extends SbbNegativeMixin(SbbButtonBaseElement) { +class SbbFormFieldClearElement extends SbbNegativeMixin(SbbButtonBaseElement) { public static override styles: CSSResultGroup = style; private _formField?: SbbFormFieldElement | null; diff --git a/src/elements/form-field/form-field-clear/readme.md b/src/elements/form-field/form-field-clear/readme.md index 9ace16a4cb3..5f6395457b9 100644 --- a/src/elements/form-field/form-field-clear/readme.md +++ b/src/elements/form-field/form-field-clear/readme.md @@ -15,10 +15,10 @@ to provide the possibility to display a clear button which can clear the input v ## Properties -| Name | Attribute | Privacy | Type | Default | Description | -| ---------- | ---------- | ------- | --------------------- | ---------- | ------------------------------------------------ | -| `form` | `form` | public | `string \| undefined` | | The element to associate the button with. | -| `name` | `name` | public | `string` | | The name of the button element. | -| `negative` | `negative` | public | `boolean` | `false` | Negative coloring variant flag. | -| `type` | `type` | public | `SbbButtonType` | `'button'` | The type attribute to use for the button. | -| `value` | `value` | public | `string` | | The value of the button element. | +| Name | Attribute | Privacy | Type | Default | Description | +| ---------- | ---------- | ------- | --------------- | ---------- | ------------------------------------------------ | +| `form` | `form` | public | `string` | `''` | The element to associate the button with. | +| `name` | `name` | public | `string` | | The name of the button element. | +| `negative` | `negative` | public | `boolean` | `false` | Negative coloring variant flag. | +| `type` | `type` | public | `SbbButtonType` | `'button'` | The type attribute to use for the button. | +| `value` | `value` | public | `string` | | The value of the button element. | diff --git a/src/elements/form-field/form-field/form-field.ts b/src/elements/form-field/form-field/form-field.ts index 31906d50924..00ab11ccd91 100644 --- a/src/elements/form-field/form-field/form-field.ts +++ b/src/elements/form-field/form-field/form-field.ts @@ -5,7 +5,7 @@ import { customElement, property, state } from 'lit/decorators.js'; import type { SbbInputModality } from '../../core/a11y.js'; import { sbbInputModalityDetector } from '../../core/a11y.js'; import { SbbConnectedAbortController, SbbLanguageController } from '../../core/controllers.js'; -import { slotState } from '../../core/decorators.js'; +import { forceType, slotState } from '../../core/decorators.js'; import { isFirefox, setOrRemoveAttribute } from '../../core/dom.js'; import { i18nOptional } from '../../core/i18n.js'; import { SbbHydrationMixin, SbbNegativeMixin } from '../../core/mixins.js'; @@ -29,9 +29,10 @@ const supportedPopupTagNames = ['sbb-autocomplete', 'sbb-autocomplete-grid', 'sb * @slot suffix - Use this slot to render an icon on the right side of the input. * @slot error - Use this slot to render an error. */ +export @customElement('sbb-form-field') @slotState() -export class SbbFormFieldElement extends SbbNegativeMixin(SbbHydrationMixin(LitElement)) { +class SbbFormFieldElement extends SbbNegativeMixin(SbbHydrationMixin(LitElement)) { public static override styles: CSSResultGroup = style; private readonly _supportedNativeInputElements = ['input', 'select', 'textarea']; @@ -67,40 +68,45 @@ export class SbbFormFieldElement extends SbbNegativeMixin(SbbHydrationMixin(LitE * `reserve` does reserve one row for an error message. */ @property({ attribute: 'error-space', reflect: true }) - public errorSpace?: 'none' | 'reserve' = 'none'; + public accessor errorSpace: 'none' | 'reserve' = 'none'; /** Indicates whether the input is optional. */ - @property({ type: Boolean }) public optional?: boolean; + @property({ type: Boolean }) @forceType(Boolean) public accessor optional: boolean = false; /** Size variant, either l or m. */ - @property({ reflect: true }) public size?: 'l' | 'm' | 's' = 'm'; + @property({ reflect: true }) public accessor size: 'l' | 'm' | 's' = 'm'; /** Whether to display the form field without a border. */ - @property({ reflect: true, type: Boolean }) public borderless = false; + @property({ reflect: true, type: Boolean }) + @forceType(Boolean) + public accessor borderless: boolean = false; /** Defines the width of the component: * - `default`: the component has defined width and min-width; * - `collapse`: the component adapts itself to its inner input content. */ - @property({ reflect: true }) public width: 'default' | 'collapse' = 'default'; + @property({ reflect: true }) public accessor width: 'default' | 'collapse' = 'default'; /** Whether to visually hide the label. If hidden, screen readers will still read it. */ - @property({ attribute: 'hidden-label', reflect: true, type: Boolean }) public hiddenLabel = false; + @property({ attribute: 'hidden-label', reflect: true, type: Boolean }) + @forceType(Boolean) + public accessor hiddenLabel: boolean = false; /** Whether the label should float. If activated, the placeholder of the input is hidden. */ - @property({ attribute: 'floating-label', reflect: true, type: Boolean }) public floatingLabel = - false; + @property({ attribute: 'floating-label', reflect: true, type: Boolean }) + @forceType(Boolean) + public accessor floatingLabel: boolean = false; /** It is used internally to get the `error` slot. */ - @state() private _errorElements: Element[] = []; + @state() private accessor _errorElements: Element[] = []; /** Original aria-describedby value of the slotted input element. */ private _originalInputAriaDescribedby?: string | null; /** Reference to the slotted input element. */ - @state() private _input?: HTMLInputElement | HTMLSelectElement | HTMLElement; + @state() private accessor _input!: HTMLInputElement | HTMLSelectElement | HTMLElement | undefined; /** Reference to the slotted label elements. */ - @state() private _label?: HTMLLabelElement; + @state() private accessor _label!: HTMLLabelElement; /** Returns the input element. */ public get inputElement(): HTMLInputElement | HTMLSelectElement | HTMLElement | undefined { diff --git a/src/elements/form-field/form-field/readme.md b/src/elements/form-field/form-field/readme.md index 262c9832709..43d172a7ccb 100644 --- a/src/elements/form-field/form-field/readme.md +++ b/src/elements/form-field/form-field/readme.md @@ -151,13 +151,13 @@ technology will announce errors when they appear. | Name | Attribute | Privacy | Type | Default | Description | | --------------- | ---------------- | ------- | ------------------------------------------------------------------- | ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `borderless` | `borderless` | public | `boolean` | `false` | Whether to display the form field without a border. | -| `errorSpace` | `error-space` | public | `'none' \| 'reserve' \| undefined` | `'none'` | Whether to reserve space for an error message. `none` does not reserve any space. `reserve` does reserve one row for an error message. | +| `errorSpace` | `error-space` | public | `'none' \| 'reserve'` | `'none'` | Whether to reserve space for an error message. `none` does not reserve any space. `reserve` does reserve one row for an error message. | | `floatingLabel` | `floating-label` | public | `boolean` | `false` | Whether the label should float. If activated, the placeholder of the input is hidden. | | `hiddenLabel` | `hidden-label` | public | `boolean` | `false` | Whether to visually hide the label. If hidden, screen readers will still read it. | | `inputElement` | - | public | `HTMLInputElement \| HTMLSelectElement \| HTMLElement \| undefined` | | Returns the input element. | | `negative` | `negative` | public | `boolean` | `false` | Negative coloring variant flag. | -| `optional` | `optional` | public | `boolean \| undefined` | | Indicates whether the input is optional. | -| `size` | `size` | public | `'l' \| 'm' \| 's' \| undefined` | `'m'` | Size variant, either l or m. | +| `optional` | `optional` | public | `boolean` | `false` | Indicates whether the input is optional. | +| `size` | `size` | public | `'l' \| 'm' \| 's'` | `'m'` | Size variant, either l or m. | | `width` | `width` | public | `'default' \| 'collapse'` | `'default'` | Defines the width of the component: - `default`: the component has defined width and min-width; - `collapse`: the component adapts itself to its inner input content. | ## Methods diff --git a/src/elements/header/common/header-action-common.ts b/src/elements/header/common/header-action-common.ts index b24a2918ecf..cf11aee3ed2 100644 --- a/src/elements/header/common/header-action-common.ts +++ b/src/elements/header/common/header-action-common.ts @@ -12,8 +12,8 @@ import style from './header-action.scss?lit&inline'; export declare class SbbHeaderActionCommonElementMixinType implements Partial { - public expandFrom: SbbHorizontalFrom; - public iconName?: string; + public accessor expandFrom: SbbHorizontalFrom; + public accessor iconName: string | null; } // eslint-disable-next-line @typescript-eslint/naming-convention @@ -34,7 +34,7 @@ export const SbbHeaderActionCommonElementMixin = < * and hidden for all the others. */ @property({ attribute: 'expand-from', reflect: true }) - public expandFrom: SbbHorizontalFrom = 'medium'; + public accessor expandFrom: SbbHorizontalFrom = 'medium'; protected override renderTemplate(): TemplateResult { return html` diff --git a/src/elements/header/header-button/header-button.ts b/src/elements/header/header-button/header-button.ts index 4d182d15cc0..8026958f51c 100644 --- a/src/elements/header/header-button/header-button.ts +++ b/src/elements/header/header-button/header-button.ts @@ -9,10 +9,9 @@ import { SbbHeaderActionCommonElementMixin } from '../common.js'; * @slot icon - Slot used to render the button icon. * @slot - Use the unnamed slot to add content to the `sbb-header-button`. */ +export @customElement('sbb-header-button') -export class SbbHeaderButtonElement extends SbbHeaderActionCommonElementMixin( - SbbButtonBaseElement, -) {} +class SbbHeaderButtonElement extends SbbHeaderActionCommonElementMixin(SbbButtonBaseElement) {} declare global { interface HTMLElementTagNameMap { diff --git a/src/elements/header/header-button/readme.md b/src/elements/header/header-button/readme.md index bea1ea2dad7..425b6f79334 100644 --- a/src/elements/header/header-button/readme.md +++ b/src/elements/header/header-button/readme.md @@ -31,14 +31,14 @@ accepting its associated properties (`type`, `name`, `value` and `form`). ## Properties -| Name | Attribute | Privacy | Type | Default | Description | -| ------------ | ------------- | ------- | --------------------- | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `expandFrom` | `expand-from` | public | `SbbHorizontalFrom` | `'medium'` | Used to set the minimum breakpoint from which the text is displayed. E.g. if set to 'large', the text will be visible for breakpoints large, wide, ultra, and hidden for all the others. | -| `form` | `form` | public | `string \| undefined` | | The element to associate the button with. | -| `iconName` | `icon-name` | public | `string \| undefined` | | The icon name we want to use, choose from the small icon variants from the ui-icons category from here https://icons.app.sbb.ch. | -| `name` | `name` | public | `string` | | The name of the button element. | -| `type` | `type` | public | `SbbButtonType` | `'button'` | The type attribute to use for the button. | -| `value` | `value` | public | `string` | | The value of the button element. | +| Name | Attribute | Privacy | Type | Default | Description | +| ------------ | ------------- | ------- | ------------------- | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `expandFrom` | `expand-from` | public | `SbbHorizontalFrom` | `'medium'` | Used to set the minimum breakpoint from which the text is displayed. E.g. if set to 'large', the text will be visible for breakpoints large, wide, ultra, and hidden for all the others. | +| `form` | `form` | public | `string` | `''` | The element to associate the button with. | +| `iconName` | `icon-name` | public | `string \| null` | `null` | The icon name we want to use, choose from the small icon variants from the ui-icons category from here https://icons.app.sbb.ch. | +| `name` | `name` | public | `string` | | The name of the button element. | +| `type` | `type` | public | `SbbButtonType` | `'button'` | The type attribute to use for the button. | +| `value` | `value` | public | `string` | | The value of the button element. | ## Slots diff --git a/src/elements/header/header-link/header-link.ts b/src/elements/header/header-link/header-link.ts index d2099c49aa6..a180a03190e 100644 --- a/src/elements/header/header-link/header-link.ts +++ b/src/elements/header/header-link/header-link.ts @@ -9,8 +9,9 @@ import { SbbHeaderActionCommonElementMixin } from '../common.js'; * @slot icon - Slot used to render the link icon. * @slot - Use the unnamed slot to add content to the `sbb-header-link`. */ +export @customElement('sbb-header-link') -export class SbbHeaderLinkElement extends SbbHeaderActionCommonElementMixin(SbbLinkBaseElement) {} +class SbbHeaderLinkElement extends SbbHeaderActionCommonElementMixin(SbbLinkBaseElement) {} declare global { interface HTMLElementTagNameMap { diff --git a/src/elements/header/header-link/readme.md b/src/elements/header/header-link/readme.md index a27e128c3af..7ff4f5fcc24 100644 --- a/src/elements/header/header-link/readme.md +++ b/src/elements/header/header-link/readme.md @@ -31,15 +31,15 @@ accepting its associated properties (`href`, `target`, `rel` and `download`). ## Properties -| Name | Attribute | Privacy | Type | Default | Description | -| -------------------- | --------------------- | ------- | --------------------------------------- | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `accessibilityLabel` | `accessibility-label` | public | `string \| undefined` | | This will be forwarded as aria-label to the inner anchor element. | -| `download` | `download` | public | `boolean \| undefined` | | Whether the browser will show the download dialog on click. | -| `expandFrom` | `expand-from` | public | `SbbHorizontalFrom` | `'medium'` | Used to set the minimum breakpoint from which the text is displayed. E.g. if set to 'large', the text will be visible for breakpoints large, wide, ultra, and hidden for all the others. | -| `href` | `href` | public | `string \| undefined` | | The href value you want to link to. | -| `iconName` | `icon-name` | public | `string \| undefined` | | The icon name we want to use, choose from the small icon variants from the ui-icons category from here https://icons.app.sbb.ch. | -| `rel` | `rel` | public | `string \| undefined` | | The relationship of the linked URL as space-separated link types. | -| `target` | `target` | public | `LinkTargetType \| string \| undefined` | | Where to display the linked URL. | +| Name | Attribute | Privacy | Type | Default | Description | +| -------------------- | --------------------- | ------- | -------------------------- | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `accessibilityLabel` | `accessibility-label` | public | `string` | `''` | This will be forwarded as aria-label to the inner anchor element. | +| `download` | `download` | public | `boolean` | `false` | Whether the browser will show the download dialog on click. | +| `expandFrom` | `expand-from` | public | `SbbHorizontalFrom` | `'medium'` | Used to set the minimum breakpoint from which the text is displayed. E.g. if set to 'large', the text will be visible for breakpoints large, wide, ultra, and hidden for all the others. | +| `href` | `href` | public | `string` | `''` | The href value you want to link to. | +| `iconName` | `icon-name` | public | `string \| null` | `null` | The icon name we want to use, choose from the small icon variants from the ui-icons category from here https://icons.app.sbb.ch. | +| `rel` | `rel` | public | `string` | `''` | The relationship of the linked URL as space-separated link types. | +| `target` | `target` | public | `LinkTargetType \| string` | `''` | Where to display the linked URL. | ## Slots diff --git a/src/elements/header/header/header.ts b/src/elements/header/header/header.ts index 16dd91f2889..de4adf8ef5c 100644 --- a/src/elements/header/header/header.ts +++ b/src/elements/header/header/header.ts @@ -2,6 +2,7 @@ import { type CSSResultGroup, html, isServer, LitElement, type TemplateResult } import { customElement, property, state } from 'lit/decorators.js'; import { SbbFocusVisibleWithinController } from '../../core/a11y.js'; +import { forceType } from '../../core/decorators.js'; import { findReferencedElement } from '../../core/dom.js'; import { SbbHydrationMixin } from '../../core/mixins.js'; @@ -19,15 +20,18 @@ const IS_MENU_OPENED_QUERY = "[aria-controls][aria-expanded='true']"; * @cssprop [--sbb-header-z-index=10] - Can be used to modify the z-index of the header. * @cssprop [--sbb-header-height=zero-small:var(--sbb-spacing-fixed-14x);medium-ultra:var(--sbb-spacing-fixed-24x)] - Can be used to modify height of the header. */ +export @customElement('sbb-header') -export class SbbHeaderElement extends SbbHydrationMixin(LitElement) { +class SbbHeaderElement extends SbbHydrationMixin(LitElement) { public static override styles: CSSResultGroup = style; /** * Whether to allow the header content to stretch to full width. * By default, the content has the appropriate page size. */ - @property({ reflect: true, type: Boolean }) public expanded = false; + @property({ reflect: true, type: Boolean }) + @forceType(Boolean) + public accessor expanded: boolean = false; /** The element's id or the element on which the scroll listener is attached. */ @property({ attribute: 'scroll-origin' }) @@ -42,13 +46,14 @@ export class SbbHeaderElement extends SbbHydrationMixin(LitElement) { private _scrollOrigin: string | HTMLElement | Document = !isServer ? document : null!; /** Whether the header should hide and show on scroll. */ - @property({ attribute: 'hide-on-scroll', reflect: true, type: Boolean }) public hideOnScroll = - false; + @property({ attribute: 'hide-on-scroll', reflect: true, type: Boolean }) + @forceType(Boolean) + public accessor hideOnScroll: boolean = false; /** Size of the header. */ - @property({ reflect: true }) public size: 'm' | 's' = 'm'; + @property({ reflect: true }) public accessor size: 'm' | 's' = 'm'; - @state() private _headerOnTop = true; + @state() private accessor _headerOnTop = true; private _scrollElement: HTMLElement | Document | null | undefined; private _scrollEventsController!: AbortController; diff --git a/src/elements/icon/icon-base.ts b/src/elements/icon/icon-base.ts index f856d7906c7..225876bd544 100644 --- a/src/elements/icon/icon-base.ts +++ b/src/elements/icon/icon-base.ts @@ -6,29 +6,31 @@ import type { UnsafeHTMLDirective } from 'lit/directives/unsafe-html.js'; import { unsafeHTML } from 'lit/directives/unsafe-html.js'; import { until } from 'lit/directives/until.js'; -import { hostAttributes } from '../core/decorators.js'; +import { forceType, hostAttributes } from '../core/decorators.js'; import { getSvgContent } from './icon-request.js'; import style from './icon.scss?lit&inline'; +const defaultNamespace = 'default'; + /** * @cssprop [--sbb-icon-svg-width=auto] - Can be used to set a custom width. * @cssprop [--sbb-icon-svg-height=auto] - Can be used to set a custom height. */ +export @hostAttributes({ - 'data-namespace': SbbIconBase._defaultNamespace, + 'data-namespace': defaultNamespace, 'data-empty': '', }) -export abstract class SbbIconBase extends LitElement { +abstract class SbbIconBase extends LitElement { public static override styles: CSSResultGroup = style; - private static readonly _defaultNamespace = 'default'; - @state() private _svgNamespace = SbbIconBase._defaultNamespace; + @state() private accessor _svgNamespace = defaultNamespace; /** * The icon svg content rendered on the page: .... */ - @state() private _svgIcon?: Promise>; + @state() private accessor _svgIcon!: Promise>; /** * When set to `true`, SVG content that is HTTP fetched will not be checked @@ -36,7 +38,9 @@ export abstract class SbbIconBase extends LitElement { * that start with `on`, such as `onclick`. * @default false */ - @property({ attribute: 'no-sanitize', type: Boolean }) public noSanitize = false; + @property({ attribute: 'no-sanitize', type: Boolean }) + @forceType(Boolean) + public accessor noSanitize: boolean = false; protected async loadSvgIcon(iconName: string): Promise { if (!iconName) { @@ -68,7 +72,7 @@ export abstract class SbbIconBase extends LitElement { switch (parts.length) { case 1: // Use default namespace if empty. - return [SbbIconBase._defaultNamespace, parts[0]]; + return [defaultNamespace, parts[0]]; case 2: return parts as [string, string]; default: diff --git a/src/elements/icon/icon-name-mixin.ts b/src/elements/icon/icon-name-mixin.ts index 0a960c0b9d7..5f58fd84040 100644 --- a/src/elements/icon/icon-name-mixin.ts +++ b/src/elements/icon/icon-name-mixin.ts @@ -6,7 +6,7 @@ import type { AbstractConstructor } from '../core/mixins.js'; import './icon.js'; export declare class SbbIconNameMixinType { - public iconName?: string; + public accessor iconName: string | null; protected renderIconSlot(classname?: string): TemplateResult; } @@ -23,7 +23,8 @@ export const SbbIconNameMixin = >( * from the ui-icons category from here * https://icons.app.sbb.ch. */ - @property({ attribute: 'icon-name', reflect: true }) public iconName?: string; + @property({ attribute: 'icon-name', reflect: true }) + public accessor iconName: string | null = null; protected renderIconSlot(classname?: string): TemplateResult { return html` diff --git a/src/elements/icon/icon.ts b/src/elements/icon/icon.ts index 3fac5b85159..fa475cd0a5c 100644 --- a/src/elements/icon/icon.ts +++ b/src/elements/icon/icon.ts @@ -6,8 +6,9 @@ import { SbbIconBase } from './icon-base.js'; /** * It displays an icon loaded from a registered namespace. */ +export @customElement('sbb-icon') -export class SbbIconElement extends SbbIconBase { +class SbbIconElement extends SbbIconBase { /** * We need to additionally observe the svgicon attribute * for sbb-angular compatibility. @@ -22,7 +23,7 @@ export class SbbIconElement extends SbbIconBase { * If the namespace is missing, the default namespace "sbb" will be used. * E.g. `name` (will use "sbb" as namespace) or `namespace:name`. */ - @property({ reflect: true }) public name!: string; + @property({ reflect: true }) public accessor name: string | null = null; private _defaultAriaLabel = ''; @@ -31,7 +32,7 @@ export class SbbIconElement extends SbbIconBase { * compatibility with it (as some icons are used internally inside the other sbb-angular * components) we need to check whether the attribute svgicon is used. */ - @state() private _sbbAngularCompatibility = false; + @state() private accessor _sbbAngularCompatibility = false; protected override async fetchSvgIcon(namespace: string, name: string): Promise { // If the icon is changing, and we were using the defaultAriaLabel, reset it @@ -53,7 +54,7 @@ export class SbbIconElement extends SbbIconBase { protected override willUpdate(changedProperties: PropertyValues): void { super.willUpdate(changedProperties); - if (changedProperties.has('name')) { + if (changedProperties.has('name') && this.name) { this.loadSvgIcon(this.name); } } diff --git a/src/elements/icon/readme.md b/src/elements/icon/readme.md index 4b288c74d60..a36b8fc549f 100644 --- a/src/elements/icon/readme.md +++ b/src/elements/icon/readme.md @@ -34,10 +34,10 @@ In thinking about accessibility, it is useful to place icon use into one of thre ## Properties -| Name | Attribute | Privacy | Type | Default | Description | -| ------------ | ------------- | ------- | --------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `name` | `name` | public | `string` | | The provided name consisting of the namespace and the name of the icon. If the namespace is missing, the default namespace "sbb" will be used. E.g. `name` (will use "sbb" as namespace) or `namespace:name`. | -| `noSanitize` | `no-sanitize` | public | `boolean` | `false` | When set to `true`, SVG content that is HTTP fetched will not be checked if the response SVG content has any `