diff --git a/.release-please-manifest.json b/.release-please-manifest.json index bac44b9758..93247c8524 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,4 +1,4 @@ { "last-release-sha": "fed492ab6cb4e807cffcb07e26bf25ab585f1c6b", - ".": "1.12.1" + ".": "1.13.0" } diff --git a/CHANGELOG.md b/CHANGELOG.md index 436356e721..1b0b1b17a6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,22 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [1.13.0](https://github.com/sbb-design-systems/lyne-components/compare/v1.12.1...v1.13.0) (2024-10-21) + + +### Features + +* **sbb-file-selector:** implement native form support ([#3085](https://github.com/sbb-design-systems/lyne-components/issues/3085)) ([449ee6d](https://github.com/sbb-design-systems/lyne-components/commit/449ee6d27667dcd944a4f17c6b91da0a1d250534)) +* **sbb-header:** introduce active state ([#3154](https://github.com/sbb-design-systems/lyne-components/issues/3154)) ([ffdeec4](https://github.com/sbb-design-systems/lyne-components/commit/ffdeec4e6d844b4af5b521c0af3742df207c0f1d)) +* **sbb-paginator:** add disabled property ([#3130](https://github.com/sbb-design-systems/lyne-components/issues/3130)) ([d43f64c](https://github.com/sbb-design-systems/lyne-components/commit/d43f64c3b306633fd1c663c81e7fc7336dbe1cf3)) +* **sbb-select:** implement native form support ([#3101](https://github.com/sbb-design-systems/lyne-components/issues/3101)) ([b9156ab](https://github.com/sbb-design-systems/lyne-components/commit/b9156ab70ffe14d543606194df305f9e7d4a1375)) + + +### Bug Fixes + +* **sbb-loading-indicator:** center component into his box ([#3144](https://github.com/sbb-design-systems/lyne-components/issues/3144)) ([22978f6](https://github.com/sbb-design-systems/lyne-components/commit/22978f6776598c7a457adcee4e9665229550caed)) +* **sbb-teaser:** css variable typo ([#3143](https://github.com/sbb-design-systems/lyne-components/issues/3143)) ([d3e4fb3](https://github.com/sbb-design-systems/lyne-components/commit/d3e4fb3c527059574195cf58686ca6bf3a599cdc)) + ## [1.12.1](https://github.com/sbb-design-systems/lyne-components/compare/v1.12.0...v1.12.1) (2024-10-03) diff --git a/eslint.config.js b/eslint.config.js index 049e8ec0ee..08674551d4 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 be55b56236..2954c196a2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@sbb-esta/lyne-elements", - "version": "1.12.1", + "version": "1.13.0", "description": "Lyne Design System", "keywords": [ "design system", @@ -76,30 +76,30 @@ "@custom-elements-manifest/analyzer": "0.10.3", "@custom-elements-manifest/to-markdown": "0.1.0", "@eslint/eslintrc": "3.1.0", - "@eslint/js": "9.12.0", + "@eslint/js": "9.13.0", "@lit-labs/observers": "2.0.4", "@lit-labs/router": "0.1.3", "@lit-labs/testing": "0.2.5", "@lit/react": "1.0.6", "@open-wc/lit-helpers": "0.7.0", "@open-wc/testing": "4.0.0", - "@sbb-esta/lyne-design-tokens": "1.2.1", - "@storybook/addon-a11y": "8.3.5", - "@storybook/addon-actions": "8.3.5", - "@storybook/addon-essentials": "8.3.5", - "@storybook/addon-interactions": "8.3.5", - "@storybook/addon-links": "8.3.5", - "@storybook/blocks": "8.3.5", - "@storybook/manager-api": "8.3.5", - "@storybook/preview-api": "8.3.5", - "@storybook/test": "8.3.5", - "@storybook/theming": "8.3.5", - "@storybook/types": "8.3.5", - "@storybook/web-components": "8.3.5", - "@storybook/web-components-vite": "8.3.5", + "@sbb-esta/lyne-design-tokens": "1.3.0", + "@storybook/addon-a11y": "8.3.6", + "@storybook/addon-actions": "8.3.6", + "@storybook/addon-essentials": "8.3.6", + "@storybook/addon-interactions": "8.3.6", + "@storybook/addon-links": "8.3.6", + "@storybook/blocks": "8.3.6", + "@storybook/manager-api": "8.3.6", + "@storybook/preview-api": "8.3.6", + "@storybook/test": "8.3.6", + "@storybook/theming": "8.3.6", + "@storybook/types": "8.3.6", + "@storybook/web-components": "8.3.6", + "@storybook/web-components-vite": "8.3.6", "@types/glob": "8.1.0", "@types/mocha": "10.0.9", - "@types/node": "20.16.12", + "@types/node": "20.16.13", "@types/react": "18.3.11", "@typescript-eslint/eslint-plugin": "8.10.0", "@typescript-eslint/parser": "8.10.0", @@ -111,7 +111,7 @@ "custom-elements-manifest": "2.1.0", "date-fns": "4.1.0", "esbuild": "0.24.0", - "eslint": "9.12.0", + "eslint": "9.13.0", "eslint-config-prettier": "9.1.0", "eslint-import-resolver-typescript": "3.6.3", "eslint-plugin-import-x": "4.3.1", @@ -131,14 +131,15 @@ "prettier": "3.3.3", "react": "18.3.1", "rollup-plugin-postcss-lit": "2.1.0", - "sass": "1.80.2", + "sass": "1.80.3", "sinon": "19.0.2", - "storybook": "8.3.5", + "storybook": "8.3.6", "stylelint": "16.10.0", "stylelint-config-prettier-scss": "1.0.0", "stylelint-config-standard-scss": "13.1.0", "stylelint-scss": "6.8.1", "ts-lit-plugin": "2.0.2", + "tslib": "2.8.0", "typescript": "5.6.3", "typescript-eslint": "8.10.0", "urlpattern-polyfill": "10.0.0", @@ -146,7 +147,7 @@ "vite-plugin-dts": "4.2.4" }, "resolutions": { - "@types/node": "20.16.12", + "@types/node": "20.16.13", "@webcomponents/template-shadowroot": "0.2.1", "@web/dev-server-core": "0.7.1", "jackspeak": "2.1.1", @@ -161,7 +162,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 6bcf6c054a..abd0593ea5 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; + @forceType() + @property({ attribute: 'round-trip', type: 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; + @forceType() + @property({ attribute: 'disable-animation', type: 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; + @forceType() + @property({ attribute: 'a11y-footpath', type: 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 bce0f640f5..11c6625ef9 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 d7bee1133d..d7ac52213e 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": "0.0.0-TSLIB" }, "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 78cef0ed89..d01b54b99d 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,40 @@ 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; + @forceType() + @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; + @forceType() + @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; + @forceType() + @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; + @forceType() + @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; + @forceType() + @property({ attribute: 'disable-animation', type: 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; + @forceType() + @property({ attribute: 'a11y-footpath', type: 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 27ee28dad8..fb688e25bd 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 f497e68687..c4936efd61 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. */ + @forceType() @property({ attribute: 'disable-animation', reflect: true, type: Boolean }) - public disableAnimation?: 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 3943bc94ba..3225581a54 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 ddc422741f..63d1a48fa9 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 f9a459adbe..dc9eae65bf 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; + @forceType() + @property({ attribute: 'disable-animation', type: 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 5b0cd0cce2..49acceddd9 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 6d94da5258..3111e3570c 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 998ca5a149..dca9e298e6 100644 --- a/src/elements-experimental/timetable-duration/timetable-duration.ts +++ b/src/elements-experimental/timetable-duration/timetable-duration.ts @@ -1,4 +1,5 @@ import { SbbLanguageController } from '@sbb-esta/lyne-elements/core/controllers.js'; +import { forceType } from '@sbb-esta/lyne-elements/core/decorators.js'; import { i18nDurationHour, i18nDurationMinute } from '@sbb-esta/lyne-elements/core/i18n.js'; import type { CSSResultGroup, TemplateResult } from 'lit'; import { html, LitElement } from 'lit'; @@ -9,8 +10,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 +21,9 @@ export class SbbTimetableDurationElement extends LitElement { * individual stories to get an idea of the * structure. */ - @property() public config!: string; + @forceType() + @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 1a776bc3f5..faaf62fa5a 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 cd0ca8ecd0..df3884459f 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. */ + @forceType() @property({ attribute: 'disable-animation', reflect: true, type: Boolean }) - public disableAnimation?: 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; + @forceType() + @property({ attribute: 'loading-trip', type: Boolean }) + public accessor loadingTrip: boolean = false; /** * The Footpath attribute for rendering different icons @@ -232,25 +237,34 @@ export class SbbTimetableRowElement extends LitElement { * false: render walk-icon * default: render walk-icon */ - @property({ attribute: 'a11y-footpath', type: Boolean }) public a11yFootpath?: boolean; + @forceType() + @property({ attribute: 'a11y-footpath', type: 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; + @forceType() + @property({ attribute: 'loading-price', type: 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; + @forceType() + @property({ attribute: 'card-action-label' }) + public accessor cardActionLabel: string = ''; /** This will be forwarded to the sbb-card component as aria-expanded. */ + @forceType() @property({ attribute: 'accessibility-expanded', type: Boolean }) - public accessibilityExpanded?: 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; + @forceType() + @property({ type: 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 +507,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 eb387561ca..d304b2e59e 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 edda6ee93e..7e6ab50c03 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 */ + @handleDistinctChange((e) => e._setTitleLevelOnChildren()) @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; + public accessor titleLevel: SbbTitleLevel | null = null; /** Whether more than one sbb-expansion-panel can be open at the same time. */ + @forceType() + @handleDistinctChange((e, newValue, oldValue) => e._resetExpansionPanels(newValue, !!oldValue)) @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') ?? []); - } + 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 5f770c85e4..49b7f0332c 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 cd48a7b026..e41de61d88 100644 --- a/src/elements/alert/alert-group/alert-group.ts +++ b/src/elements/alert/alert-group/alert-group.ts @@ -4,6 +4,7 @@ import { customElement, property, state } 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 { SbbHydrationMixin } from '../../core/mixins.js'; import type { SbbTitleLevel } from '../../title.js'; @@ -19,8 +20,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 +36,19 @@ 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; + @forceType() + @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 8bd609bf86..ab440beee0 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 5f5349fa2b..5c09c0757f 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,57 @@ 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; + @forceType() + @property({ reflect: true, type: 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'; + @forceType() + @property({ attribute: 'icon-name' }) + public override accessor iconName: string = 'info'; /** Content of title. */ - @property({ attribute: 'title-content' }) public titleContent?: string; + @forceType() + @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; + @forceType() + @property({ attribute: 'link-content' }) + public accessor linkContent: string = ''; /** The href value you want to link to. */ - @property() public href: string | undefined; + @forceType() + @property() + public accessor href: string = ''; /** Where to display the linked URL. */ - @property() public target: LinkTargetType | string | undefined; + @forceType() + @property() + public accessor target: LinkTargetType | string = ''; /** The relationship of the linked URL as space-separated link types. */ - @property() public rel: string | undefined; + @forceType() + @property() + public accessor rel: string = ''; /** This will be forwarded as aria-label to the relevant nested element. */ - @property({ attribute: 'accessibility-label' }) public accessibilityLabel: string | undefined; + @forceType() + @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 467620b726..cdd26b061f 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` | `'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 8dd5e818ab..2a5ca2c001 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 efead5ba74..e91815bc20 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` | `''` | 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 1f3d3f632b..a5e3e5d3e1 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"] = ` +snapshots["sbb-autocomplete-grid Chrome-Firefox DOM"] = +` `; -/* end snapshot sbb-autocomplete-grid Safari DOM */ +/* end snapshot sbb-autocomplete-grid Chrome-Firefox DOM */ -snapshots["sbb-autocomplete-grid Safari Shadow DOM"] = +snapshots["sbb-autocomplete-grid Chrome-Firefox Shadow DOM"] = `
@@ -81,7 +75,11 @@ snapshots["sbb-autocomplete-grid Safari Shadow DOM"] =
-
+
@@ -89,10 +87,14 @@ snapshots["sbb-autocomplete-grid Safari Shadow DOM"] =
`; -/* end snapshot sbb-autocomplete-grid Safari Shadow DOM */ +/* end snapshot sbb-autocomplete-grid Chrome-Firefox Shadow DOM */ -snapshots["sbb-autocomplete-grid Chrome-Firefox DOM"] = -` +snapshots["sbb-autocomplete-grid Safari DOM"] = +` `; -/* end snapshot sbb-autocomplete-grid Chrome-Firefox DOM */ +/* end snapshot sbb-autocomplete-grid Safari DOM */ -snapshots["sbb-autocomplete-grid Chrome-Firefox Shadow DOM"] = +snapshots["sbb-autocomplete-grid Safari Shadow DOM"] = `
@@ -167,11 +167,7 @@ snapshots["sbb-autocomplete-grid Chrome-Firefox Shadow DOM"] =
-
+
@@ -179,16 +175,16 @@ snapshots["sbb-autocomplete-grid Chrome-Firefox Shadow DOM"] =
`; -/* end snapshot sbb-autocomplete-grid Chrome-Firefox Shadow DOM */ +/* end snapshot sbb-autocomplete-grid Safari Shadow DOM */ -snapshots["sbb-autocomplete-grid Chrome-Firefox A11y tree Chrome"] = +snapshots["sbb-autocomplete-grid Chrome-Firefox A11y tree Firefox"] = `

{ - "role": "WebArea", + "role": "document", "name": "", "children": [ { - "role": "text", + "role": "statictext", "name": "​" }, { @@ -201,16 +197,16 @@ snapshots["sbb-autocomplete-grid Chrome-Firefox A11y tree Chrome"] = }

`; -/* end snapshot sbb-autocomplete-grid Chrome-Firefox A11y tree Chrome */ +/* end snapshot sbb-autocomplete-grid Chrome-Firefox A11y tree Firefox */ -snapshots["sbb-autocomplete-grid Chrome-Firefox A11y tree Firefox"] = +snapshots["sbb-autocomplete-grid Chrome-Firefox A11y tree Chrome"] = `

{ - "role": "document", + "role": "WebArea", "name": "", "children": [ { - "role": "statictext", + "role": "text", "name": "​" }, { @@ -223,5 +219,5 @@ snapshots["sbb-autocomplete-grid Chrome-Firefox A11y tree Firefox"] = }

`; -/* end snapshot sbb-autocomplete-grid Chrome-Firefox A11y tree Firefox */ +/* end snapshot sbb-autocomplete-grid Chrome-Firefox A11y tree Chrome */ diff --git a/src/elements/autocomplete-grid/autocomplete-grid/autocomplete-grid.ts b/src/elements/autocomplete-grid/autocomplete-grid/autocomplete-grid.ts index 01e1ec5e62..f29752cb01 100644 --- a/src/elements/autocomplete-grid/autocomplete-grid/autocomplete-grid.ts +++ b/src/elements/autocomplete-grid/autocomplete-grid/autocomplete-grid.ts @@ -31,11 +31,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-grid') @hostAttributes({ role: ariaRoleOnHost ? 'grid' : null, }) -export class SbbAutocompleteGridElement extends SbbAutocompleteBaseElement { +class SbbAutocompleteGridElement extends SbbAutocompleteBaseElement { protected overlayId = `sbb-autocomplete-grid-${++nextId}`; protected panelRole = 'grid'; private _activeItemIndex = -1; diff --git a/src/elements/autocomplete-grid/autocomplete-grid/readme.md b/src/elements/autocomplete-grid/autocomplete-grid/readme.md index 09af61a121..dd8bfbdb26 100644 --- a/src/elements/autocomplete-grid/autocomplete-grid/readme.md +++ b/src/elements/autocomplete-grid/autocomplete-grid/readme.md @@ -154,15 +154,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/autocomplete/autocomplete-base-element.ts b/src/elements/autocomplete/autocomplete-base-element.ts index 4c5df0c2e8..fa4b931dc2 100644 --- a/src/elements/autocomplete/autocomplete-base-element.ts +++ b/src/elements/autocomplete/autocomplete-base-element.ts @@ -11,6 +11,7 @@ import { ref } from 'lit/directives/ref.js'; import { SbbOpenCloseBaseElement } from '../core/base-elements.js'; import { SbbConnectedAbortController } from '../core/controllers.js'; +import { forceType } from '../core/decorators.js'; import { findReferencedElement, isSafari } from '../core/dom.js'; import { SbbNegativeMixin, SbbHydrationMixin } from '../core/mixins.js'; import { @@ -38,18 +39,19 @@ export abstract class SbbAutocompleteBaseElement extends SbbNegativeMixin( * 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. */ - @property() public origin?: string | HTMLElement; + @property() public accessor origin: string | HTMLElement | 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. */ - @property() public trigger?: string | HTMLInputElement; + @property() public accessor trigger: string | HTMLInputElement | null = null; /** Whether the icon space is preserved when no icon is set. */ + @forceType() @property({ attribute: 'preserve-icon-space', reflect: true, type: Boolean }) - public preserveIconSpace?: boolean; + public accessor preserveIconSpace: boolean = false; /** Returns the element where autocomplete overlay is attached to. */ public get originElement(): HTMLElement { @@ -139,11 +141,11 @@ export abstract class SbbAutocompleteBaseElement extends SbbNegativeMixin( protected override willUpdate(changedProperties: PropertyValues): 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 1150d1c795..8dc515d30e 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 4b1a1efa4c..aed6f6ef8b 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 b2126a8f76..3e36321920 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 a5ad0e5097..d8cdcad7d4 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 cdb74b1ccf..50ba17f493 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 bda102fd03..13b6ce5427 100644 --- a/src/elements/breadcrumb/breadcrumb/breadcrumb.visual.spec.ts +++ b/src/elements/breadcrumb/breadcrumb/breadcrumb.visual.spec.ts @@ -25,7 +25,6 @@ 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 72968e9ffc..fc296414ce 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` | `''` | 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 714f34ee34..6b0a43165c 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 ab5728e234..8a5aac2318 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` | `''` | 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 aa31b7180e..7f37ef8b82 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 ae08037ffe..e9741adf3f 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` | `''` | 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 f956f86828..4eb978e88d 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 f1894686c5..527c48d04e 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` | `''` | 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 31e8317447..b86ab883a6 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; + 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 ddcf9a30b6..4715e89960 100644 --- a/src/elements/button/mini-button-group/mini-button-group.ts +++ b/src/elements/button/mini-button-group/mini-button-group.ts @@ -2,6 +2,7 @@ import type { CSSResultGroup, PropertyValues, TemplateResult } from 'lit'; import { html, LitElement } from 'lit'; import { customElement, property } from 'lit/decorators.js'; +import { forceType } from '../../core/decorators.js'; import { SbbNamedSlotListMixin, SbbNegativeMixin } from '../../core/mixins.js'; import type { SbbDividerElement } from '../../divider/divider.js'; import type { SbbMiniButtonElement } from '../mini-button/mini-button.js'; @@ -16,18 +17,21 @@ 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; + @forceType() + @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 40cf0f3eea..cdc7b7368d 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 7d498911ca..31a57fda41 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 a7fd7bb56f..c4ce6c4f71 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 8029cbd66d..d9635b9463 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` | `''` | 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 3fa66b7b58..086b6ab7ae 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` | `''` | 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 b3893acfad..499cf3357a 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 17d1919cf9..ad9eb30407 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` | `''` | 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 d64ec05104..c908687cc0 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 1797f3daa0..57ca9fb6da 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` | `''` | 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 415f2d3cdb..67b09e06fa 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 f0305783e1..06162ad796 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` | `''` | 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 72cfba79d2..fe9d4b5810 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 3154833eea..9c3133deb3 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` | `''` | 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 8b2559a873..2350e6f57b 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 6c5150dbd8..736a65410d 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` | `''` | 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 02c656130b..e2bb6e329b 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 98c627da08..7a01c1e65f 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` | `''` | 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 7618cf8deb..104b7f1ed0 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 c0f2964c1e..8b750e41b7 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` | `''` | 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 8c60ea781d..48f6b7359c 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 a373b33ef9..581d050939 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` | `''` | 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 b8fbb74862..515c676f24 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 37884e2460..4f0e05243f 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,21 @@ 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; + @forceType() + @property({ type: 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 +158,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 +171,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 +185,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 +227,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 47829d412e..2a85d338af 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 62a2626125..39076b9474 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 fdaab1a5a1..681abe201b 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 dd6c18e365..6cdd288b11 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 b248c99d46..d99c5250cf 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 41657b5fe9..bb545ba6f6 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 669553527d..bb67f1ebb0 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/common/card-action-common.ts b/src/elements/card/common/card-action-common.ts index 71d14eda96..43e22f4c87 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 b26a4150d4..98dcb68c0c 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; + @forceType() + @property({ reflect: true, type: 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 558bec1bd3..176068080b 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 50fd83cb53..43abf00d6d 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 fff6a5cbc1..01afd89802 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 ce419ee5ea..9a3e08bbc9 100644 --- a/src/elements/checkbox/checkbox/readme.md +++ b/src/elements/checkbox/checkbox/readme.md @@ -90,7 +90,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 the internals of the 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` | `''` | 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 09f0f6cc2c..4cff2b464c 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,9 @@ export const SbbCheckboxCommonElementMixin = > implements Partial { /** Whether the checkbox is indeterminate. */ - @property({ type: Boolean }) public indeterminate = false; + @forceType() + @property({ type: 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 c6b48403b7..e6725c5e16 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 c33e9a3b16..004e40cc82 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 6ffdb3e177..1b59cfb468 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; + @forceType() + @property({ type: Boolean, reflect: true }) + public accessor expanded: boolean = false; /** Whether the background color is shown on full container width on large screens. */ + @forceType() @property({ type: Boolean, reflect: true, attribute: 'background-expanded' }) - public backgroundExpanded = false; + 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 9423b17241..c96b9cb93f 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 af2ec52797..e0652eba93 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 35798c68fa..2136910fb3 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 67006811f1..5f5954eeee 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,19 @@ 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; + @forceType() + @property({ type: Boolean }) + public accessor disabled: boolean = false; + @forceType() + @property({ type: 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 485bbb0700..a4e4386e6a 100644 --- a/src/elements/core/base-elements/button-base-element.ts +++ b/src/elements/core/base-elements/button-base-element.ts @@ -1,7 +1,7 @@ import { isServer } from 'lit'; import { property } from 'lit/decorators.js'; -import { hostAttributes } from '../decorators.js'; +import { forceType, hostAttributes } from '../decorators.js'; import { isEventPrevented } from '../eventing.js'; import { SbbActionBaseElement } from './action-base-element.js'; @@ -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,9 @@ export abstract class SbbButtonBaseElement extends SbbActionBaseElement { } /** The element to associate the button with. */ - @property() public form?: string; + @forceType() + @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 385a992176..43df8064b7 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,19 @@ 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; + @forceType() + @property({ type: Boolean }) + public accessor disabled: boolean = false; + @forceType() + @property({ type: 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 1ba733007d..2c87979d1c 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,35 @@ 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; + @forceType() + @property() + public accessor href: string = ''; /** Where to display the linked URL. */ - @property() public target?: LinkTargetType | string; + @forceType() + @property() + public accessor target: LinkTargetType | string = ''; /** The relationship of the linked URL as space-separated link types. */ - @property() public rel?: string; + @forceType() + @property() + public accessor rel: string = ''; /** Whether the browser will show the download dialog on click. */ - @property({ type: Boolean }) public download?: boolean; + @forceType() + @property({ type: 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; + @forceType() + @property({ attribute: 'accessibility-label' }) + public accessor accessibilityLabel: string = ''; protected language = new SbbLanguageController(this); diff --git a/src/elements/core/decorators.ts b/src/elements/core/decorators.ts index 1d6b1f57ad..44abf975fa 100644 --- a/src/elements/core/decorators.ts +++ b/src/elements/core/decorators.ts @@ -1,2 +1,6 @@ +export * from './decorators/force-type.js'; +export * from './decorators/get-override.js'; +export * from './decorators/handle-distinct-change.js'; export * from './decorators/host-attributes.js'; +export * from './decorators/omit-empty-converter.js'; export * from './decorators/slot-state.js'; diff --git a/src/elements/core/decorators/base.ts b/src/elements/core/decorators/base.ts new file mode 100644 index 0000000000..08a8c5066c --- /dev/null +++ b/src/elements/core/decorators/base.ts @@ -0,0 +1,29 @@ +import type { ReactiveElement } from 'lit'; + +// Types used from lit: https://github.com/lit/lit/blob/main/packages/reactive-element/src/decorators/property.ts + +/** + * Generates a public interface type that removes private and protected fields. + * This allows accepting otherwise incompatible versions of the type (e.g. from + * multiple copies of the same package in `node_modules`). + */ +export type Interface = { + [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 0000000000..9f3db259bb --- /dev/null +++ b/src/elements/core/decorators/force-type.ts @@ -0,0 +1,47 @@ +import type { ReactiveElement } from 'lit'; + +import type { Interface, PropertyDecorator } from './base.js'; + +/** + * Decorator that forces the value of a property or getter/setter + * to the defined type. + */ +export const forceType = , V>(): PropertyDecorator => { + return ( + target: ClassAccessorDecoratorTarget | ((value: V) => void), + context: ClassAccessorDecoratorContext | ClassSetterDecoratorContext, + ): any => { + const { kind, metadata, name } = context; + + const type = (globalThis.litPropertyMetadata.get(metadata)?.get(name)?.type ?? String) as ( + v: unknown, + ) => V; + let convert = type; + if ((type as unknown) === String) { + // In case of String, we want to handle null/undefined differently + // from the native behavior in that we want to treat these values + // as empty strings. + convert = (v) => (v == null ? '' : String(v)) as V; + } else if ((type as unknown) === Number) { + // In case of Number, we want to handle null differently + // from the native behavior in that we want to treat null as NaN. + convert = (v) => (v == null ? NaN : Number(v)) as V; + } + if (kind === 'accessor') { + return { + set(this: C, value) { + (target as ClassAccessorDecoratorTarget).set.call( + this as unknown as C, + convert(value) as V, + ); + }, + } satisfies ClassAccessorDecoratorResult; + } else if (kind === 'setter') { + return function (value: unknown) { + (target as (value: unknown) => void)(convert(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 0000000000..09c0d92c4b --- /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'; + +/** + * 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 0000000000..4177e4b48f --- /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'; + +/** + * 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/decorators/omit-empty-converter.ts b/src/elements/core/decorators/omit-empty-converter.ts new file mode 100644 index 0000000000..2a3c0f4ce8 --- /dev/null +++ b/src/elements/core/decorators/omit-empty-converter.ts @@ -0,0 +1,15 @@ +import { defaultConverter, type ComplexAttributeConverter } from 'lit'; + +/** + * Converts empty values to null, which will not be rendered as attributes. + * e.g. for string properties, an empty value '' will not be rendered as an + * empty attribute, as would be the default with lit. + */ +export const omitEmptyConverter: ComplexAttributeConverter = { + toAttribute(value, type) { + return ((type === String || type === undefined) && value === '') || + (type === Number && isNaN(value as number)) + ? null + : defaultConverter.toAttribute!(value, type); + }, +}; diff --git a/src/elements/core/mixins/disabled-mixin.ts b/src/elements/core/mixins/disabled-mixin.ts index bd4cf3da30..4e1bdd350e 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, getOverride } 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; } /** @@ -22,16 +23,10 @@ export const SbbDisabledMixin = >( ): AbstractConstructor & T => { abstract class SbbDisabledElement extends superClass implements Partial { /** Whether the component is disabled. */ + @forceType() @property({ reflect: true, type: Boolean }) - public set disabled(value: boolean) { - // To provide the same behavior as the native disabled state, - // any value is converted to a boolean. - this._disabled = Boolean(value); - } - public get disabled(): boolean { - return this._disabled || this.isDisabledExternally(); - } - private _disabled: boolean = false; + @getOverride((e, v) => v || e.isDisabledExternally()) + public accessor disabled: boolean = false; /** * Will be used as 'or' check to the current disabled state. @@ -59,8 +54,9 @@ export const SbbDisabledInteractiveMixin = < implements Partial { /** Whether disabled buttons should be interactive. */ - @property({ attribute: 'disabled-interactive', type: Boolean }) public disabledInteractive = - false; + @forceType() + @property({ attribute: 'disabled-interactive', type: Boolean }) + public accessor disabledInteractive: boolean = false; } return SbbDisabledInteractiveElement as unknown as AbstractConstructor & diff --git a/src/elements/core/mixins/form-associated-checkbox-mixin.ts b/src/elements/core/mixins/form-associated-checkbox-mixin.ts index d651ee40ed..0d2166cc97 100644 --- a/src/elements/core/mixins/form-associated-checkbox-mixin.ts +++ b/src/elements/core/mixins/form-associated-checkbox-mixin.ts @@ -86,7 +86,7 @@ export const SbbFormAssociatedCheckboxMixin = public get checked(): boolean { return this._checked; } - private _checked = false; + private _checked: boolean = false; protected constructor() { super(); diff --git a/src/elements/core/mixins/form-associated-mixin.ts b/src/elements/core/mixins/form-associated-mixin.ts index b3931d4fe6..24573f5e53 100644 --- a/src/elements/core/mixins/form-associated-mixin.ts +++ b/src/elements/core/mixins/form-associated-mixin.ts @@ -118,7 +118,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/form-associated-radio-button-mixin.ts b/src/elements/core/mixins/form-associated-radio-button-mixin.ts index 5be948c3af..d5b9588ff8 100644 --- a/src/elements/core/mixins/form-associated-radio-button-mixin.ts +++ b/src/elements/core/mixins/form-associated-radio-button-mixin.ts @@ -3,6 +3,7 @@ import { property } from 'lit/decorators.js'; import { getNextElementIndex, isArrowKeyPressed } from '../a11y.js'; import { SbbConnectedAbortController } from '../controllers.js'; +import { forceType } from '../decorators.js'; import type { Constructor } from './constructor.js'; import { SbbDisabledMixin, type SbbDisabledMixinType } from './disabled-mixin.js'; @@ -93,14 +94,9 @@ export const SbbFormAssociatedRadioButtonMixin = 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 ae053c4a11..ec659d17b6 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; + @forceType() + @property({ reflect: true, type: 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 447fc9bb96..597b30e00d 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,17 @@ 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; + @forceType() + @property({ reflect: true, type: Boolean }) + public accessor borderless: boolean = false; /** @internal used for accessibility label when in expansion panel */ - @property() public expansionState?: string; + @forceType() + @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 b9191a86a5..3d82b98f0c 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 0775daffbf..e77f23784d 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 cfd6f4af12..54f6643045 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 fda35f7b1f..bf3781daea 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 30cba55bec..65c7e04fc1 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 8653a10686..b3dbf709cd 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 084c1ccec7..71197d28a1 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 cfbfd229f2..289948c003 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 8a8c735c88..0a9ddf23eb 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,28 @@ export class SbbDatepickerElement extends LitElement { } as const; /** If set to true, two months are displayed. */ - @property({ type: Boolean }) public wide = false; + @forceType() + @property({ type: 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 +277,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 +488,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 dd38f2f290..a8ca76d0c0 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 60b4a8ad61..b6c048b7c3 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 b1143f6308..ddb67269cb 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 8740aa302d..41c09d88a6 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,23 @@ export class SbbDialogTitleElement extends SbbTitleBase { /** * Whether a back button is displayed next to the title. */ - @property({ attribute: 'back-button', type: Boolean }) public backButton = false; + @forceType() + @property({ attribute: 'back-button', type: 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; + @forceType() + @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; + @forceType() + @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 38190cbbb2..d3738bcb98 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 562e0961ce..2bb07a6cb8 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 20712652e3..26162e7ce3 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 1200986fb0..970542ce5b 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 f75db2825d..2026f69cd6 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 59ddc3bddb..939653a380 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 1535bc06b1..6f66c79c3e 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` | `''` | 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 e9e9d6d579..f06d268127 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; + @forceType() + @property({ reflect: true, type: 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 9a0d16f5d4..0b694e49f5 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 123be51c86..c6d5d6c30d 100644 --- a/src/elements/file-selector/file-selector.ts +++ b/src/elements/file-selector/file-selector.ts @@ -6,7 +6,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, forwardEventToHost } from '../core/eventing.js'; import { i18nFileSelectorButtonLabel, @@ -37,35 +37,44 @@ export type DOMEvent = globalThis.Event; * @event change - An event which is emitted each time the user modifies the value. Unlike the input event, the change event is not necessarily fired for each alteration to an element's value * @event input - An event which is emitted each time the value changes as a direct result of a user action. */ +export @customElement('sbb-file-selector') @slotState() -export class SbbFileSelectorElement extends SbbDisabledMixin(SbbFormAssociatedMixin(LitElement)) { +class SbbFileSelectorElement extends SbbDisabledMixin(SbbFormAssociatedMixin(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; + @forceType() + @property({ type: 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; + @forceType() + @property() + public accessor accept: string = ''; /** The title displayed in `dropzone` variant. */ - @property({ attribute: 'title-content' }) public titleContent?: string; + @forceType() + @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; + @forceType() + @property({ attribute: 'accessibility-label' }) + public accessor accessibilityLabel: string = ''; /** The path of the first selected file. Empty string ('') if no file is selected */ @property({ attribute: false }) diff --git a/src/elements/file-selector/readme.md b/src/elements/file-selector/readme.md index 38490b1353..e1cdbc1237 100644 --- a/src/elements/file-selector/readme.md +++ b/src/elements/file-selector/readme.md @@ -93,8 +93,8 @@ 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[]` | `[]` | The list of selected files. | | `form` | - | public | `HTMLFormElement \| null` | | Returns the form owner of the internals of the target element. | @@ -102,7 +102,7 @@ It's suggested to have a different value for each variant, e.g.: | `multipleMode` | `multiple-mode` | public | `'default' \| 'persistent'` | `'default'` | Whether the newly added files should override the previously added ones. | | `name` | `name` | public | `string` | | Name of the form element. Will be read from name attribute. | | `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. | | `value` | `value` | public | `string \| null` | `null` | The path of the first selected file. Empty string ('') if no file is selected | | `variant` | `variant` | public | `'default' \| 'dropzone'` | `'default'` | Whether the component has a dropzone area or not. | 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 49584d3f47..46556e0d33 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 56b0253931..25539dcb2b 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 0d697b0887..e7badb1317 100644 --- a/src/elements/flip-card/flip-card/flip-card.ts +++ b/src/elements/flip-card/flip-card/flip-card.ts @@ -4,6 +4,7 @@ import { until } from 'lit/directives/until.js'; import { IS_FOCUSABLE_QUERY } from '../../core/a11y.js'; import { SbbConnectedAbortController, SbbLanguageController } from '../../core/controllers.js'; +import { forceType } from '../../core/decorators.js'; import { EventEmitter } from '../../core/eventing.js'; import { i18nFlipCard, i18nReverseCard } from '../../core/i18n.js'; import { SbbHydrationMixin } from '../../core/mixins.js'; @@ -22,8 +23,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 +35,9 @@ 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; + @forceType() + @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 +58,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 41e986a2a7..44483bc260 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 8cfc9d690b..463734af84 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,24 @@ 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; + @forceType() + @property({ reflect: true, type: Boolean }) + public accessor expanded: boolean = false; /** Footer title text, visually hidden, necessary for screen readers. */ - @property({ attribute: 'accessibility-title' }) public accessibilityTitle?: string; + @forceType() + @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 7c1c5281c9..fe0c262147 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 48a06ddeac..f3e47452b6 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 8878e77692..5dda4be5d6 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 9ace16a4cb..5f6395457b 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 31906d5092..72f3f4aae0 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,47 @@ 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; + @forceType() + @property({ type: 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; + @forceType() + @property({ reflect: true, type: 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; + @forceType() + @property({ attribute: 'hidden-label', reflect: true, type: 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; + @forceType() + @property({ attribute: 'floating-label', reflect: true, type: 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 262c983270..43d172a7cc 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 b24a2918ec..0811d7979e 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; } // 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 4d182d15cc..8026958f51 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 fd22af1175..9140ecbb74 100644 --- a/src/elements/header/header-button/readme.md +++ b/src/elements/header/header-button/readme.md @@ -48,14 +48,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` | `''` | 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 d2099c49aa..a180a03190 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 b6efd2729f..a3d30fdc29 100644 --- a/src/elements/header/header-link/readme.md +++ b/src/elements/header/header-link/readme.md @@ -43,15 +43,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` | `''` | 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 16dd91f288..f3627beda6 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; + @forceType() + @property({ reflect: true, type: 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; + @forceType() + @property({ attribute: 'hide-on-scroll', reflect: true, type: 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 f856d7906c..4558de661a 100644 --- a/src/elements/icon/icon-base.ts +++ b/src/elements/icon/icon-base.ts @@ -6,29 +6,32 @@ 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> | null = + null; /** * When set to `true`, SVG content that is HTTP fetched will not be checked @@ -36,7 +39,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; + @forceType() + @property({ attribute: 'no-sanitize', type: Boolean }) + public accessor noSanitize: boolean = false; protected async loadSvgIcon(iconName: string): Promise { if (!iconName) { @@ -68,7 +73,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 0a960c0b9d..6ffdcb34b5 100644 --- a/src/elements/icon/icon-name-mixin.ts +++ b/src/elements/icon/icon-name-mixin.ts @@ -1,12 +1,13 @@ import { html, type LitElement, nothing, type TemplateResult } from 'lit'; import { property } from 'lit/decorators.js'; +import { forceType, omitEmptyConverter } from '../core/decorators.js'; import type { AbstractConstructor } from '../core/mixins.js'; import './icon.js'; export declare class SbbIconNameMixinType { - public iconName?: string; + public accessor iconName: string; protected renderIconSlot(classname?: string): TemplateResult; } @@ -23,7 +24,9 @@ export const SbbIconNameMixin = >( * from the ui-icons category from here * https://icons.app.sbb.ch. */ - @property({ attribute: 'icon-name', reflect: true }) public iconName?: string; + @forceType() + @property({ attribute: 'icon-name', reflect: true, converter: omitEmptyConverter }) + public accessor iconName: string = ''; protected renderIconSlot(classname?: string): TemplateResult { return html` diff --git a/src/elements/icon/icon.ts b/src/elements/icon/icon.ts index 3fac5b8515..4d048a78e1 100644 --- a/src/elements/icon/icon.ts +++ b/src/elements/icon/icon.ts @@ -1,13 +1,16 @@ import { html, type PropertyValues, type TemplateResult } from 'lit'; import { customElement, property, state } from 'lit/decorators.js'; +import { forceType, omitEmptyConverter } from '../core/decorators.js'; + 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 +25,9 @@ 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; + @forceType() + @property({ reflect: true, converter: omitEmptyConverter }) + public accessor name: string = ''; private _defaultAriaLabel = ''; @@ -31,7 +36,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 +58,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 4b288c74d6..5f5bb38354 100644 --- a/src/elements/icon/readme.md +++ b/src/elements/icon/readme.md @@ -36,7 +36,7 @@ In thinking about accessibility, it is useful to place icon use into one of thre | 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`. | +| `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 `