diff --git a/src/components/accordion/accordion.stories.ts b/src/components/accordion/accordion.stories.ts index f43274ef236..b5e2e82eb78 100644 --- a/src/components/accordion/accordion.stories.ts +++ b/src/components/accordion/accordion.stories.ts @@ -53,6 +53,16 @@ const titleLevel: InputType = { }, }; +const size: InputType = { + control: { + type: 'inline-radio', + }, + options: ['l', 's'], + table: { + category: 'Accordion', + }, +}; + const color: InputType = { control: { type: 'inline-radio', @@ -122,6 +132,7 @@ const defaultArgTypes: ArgTypes = { multi, 'disable-animation': disableAnimation, 'title-level': titleLevel, + size, color, expanded, borderless, @@ -136,6 +147,7 @@ const defaultArgs: Args = { multi: false, 'disable-animation': false, 'title-level': titleLevel.options[2], + size: size.options[0], color: color.options[0], expanded: false, borderless: false, @@ -233,6 +245,18 @@ export const NoAnimation: StoryObj = { args: { ...defaultArgs, 'disable-animation': true }, }; +export const SizeS: StoryObj = { + render: Template, + argTypes: defaultArgTypes, + args: { ...defaultArgs, size: size.options[1] }, +}; + +export const SizeSWithIcon: StoryObj = { + render: Template, + argTypes: defaultArgTypes, + args: { ...defaultArgs, size: size.options[1], iconName: 'swisspass-medium' }, +}; + const wrapperStyle = (context: StoryContext): Record => ({ 'background-color': context.args.borderless ? '#bdbdbd' : 'var(--sbb-color-white)', }); diff --git a/src/components/accordion/accordion.ts b/src/components/accordion/accordion.ts index 3235a8109a9..76af4dcd480 100644 --- a/src/components/accordion/accordion.ts +++ b/src/components/accordion/accordion.ts @@ -1,4 +1,4 @@ -import type { CSSResultGroup, TemplateResult } from 'lit'; +import type { CSSResultGroup, PropertyValues, TemplateResult } from 'lit'; import { html, LitElement } from 'lit'; import { customElement, property } from 'lit/decorators.js'; @@ -51,6 +51,9 @@ export class SbbAccordionElement extends SbbHydrationMixin(LitElement) { } private _multi: boolean = false; + /** Size variant, either l or s; overrides the size on any projected `sbb-expansion-panel`. `*/ + @property({ reflect: true }) public size: 's' | 'l' = 'l'; + private _abort = new SbbConnectedAbortController(this); private _closePanels(e: CustomEvent): void { @@ -94,11 +97,18 @@ export class SbbAccordionElement extends SbbHydrationMixin(LitElement) { ); } + protected override willUpdate(changedProperties: PropertyValues): void { + if (changedProperties.has('size')) { + this._expansionPanels.forEach((panel: SbbExpansionPanelElement) => (panel.size = this.size)); + } + } + private _handleSlotchange(): void { this._expansionPanels.forEach( (panel: SbbExpansionPanelElement, index: number, array: SbbExpansionPanelElement[]) => { panel.titleLevel = this.titleLevel; panel.disableAnimation = this.disableAnimation; + panel.size = this.size; panel.toggleAttribute('data-accordion-first', index === 0); panel.toggleAttribute('data-accordion-last', index === array.length - 1); }, diff --git a/src/components/accordion/readme.md b/src/components/accordion/readme.md index c9e0e9558ce..7424aab71ff 100644 --- a/src/components/accordion/readme.md +++ b/src/components/accordion/readme.md @@ -24,6 +24,13 @@ The `multi` property, if set, allows having more than one `sbb-expansion-panel` ## Style +The component has two different sizes, `l` (default) and `s`, which can be changed using the `size` property. +The property overrides the `size` value of any inner `sbb-expansion-panel`. + +```html + ... +``` + The component has a `titleLevel` property, which is proxied to each inner `sbb-expansion-panel-header`, and can be used to wrap the header of each `sbb-expansion-panel` in a heading tag; if the property is unset, a `div` is used. @@ -43,11 +50,12 @@ In the following example, all the `sbb-expansion-panel-header` would be wrapped ## Properties -| Name | Attribute | Privacy | Type | Default | Description | -| ------------------ | ------------------- | ------- | ----------------------- | ------- | --------------------------------------------------------------------------- | -| `titleLevel` | `title-level` | public | `SbbTitleLevel \| null` | `null` | The heading level for the sbb-expansion-panel-headers within the component. | -| `disableAnimation` | `disable-animation` | public | `boolean` | `false` | Whether the animation should be disabled. | -| `multi` | `multi` | public | `boolean` | `false` | Whether more than one sbb-expansion-panel can be open at the same time. | +| Name | Attribute | Privacy | Type | Default | Description | +| ------------------ | ------------------- | ------- | ----------------------- | ------- | ----------------------------------------------------------------------------------------- | +| `titleLevel` | `title-level` | public | `SbbTitleLevel \| null` | `null` | The heading level for the sbb-expansion-panel-headers within the component. | +| `disableAnimation` | `disable-animation` | public | `boolean` | `false` | Whether the animation should be disabled. | +| `multi` | `multi` | public | `boolean` | `false` | Whether more than one sbb-expansion-panel can be open at the same time. | +| `size` | `size` | public | `'s' \| 'l'` | `'l'` | Size variant, either l or s; overrides the size on any projected `sbb-expansion-panel`. ` | ## Slots diff --git a/src/components/expansion-panel/expansion-panel-content/expansion-panel-content.scss b/src/components/expansion-panel/expansion-panel-content/expansion-panel-content.scss index 0aa89537f26..5b1dab7573f 100644 --- a/src/components/expansion-panel/expansion-panel-content/expansion-panel-content.scss +++ b/src/components/expansion-panel/expansion-panel-content/expansion-panel-content.scss @@ -12,6 +12,10 @@ display: block; } +:host([data-size='s']) { + --sbb-expansion-panel-content-padding-inline: var(--sbb-spacing-fixed-5x); +} + :host([data-icon-space]) { @include sbb.mq($from: micro) { // The space taken by the icon in the sbb-expansion-panel-header must be considered here to correctly calculate the padding value; diff --git a/src/components/expansion-panel/expansion-panel-header/expansion-panel-header.scss b/src/components/expansion-panel/expansion-panel-header/expansion-panel-header.scss index 1a99abdbf37..79cbcfdd075 100644 --- a/src/components/expansion-panel/expansion-panel-header/expansion-panel-header.scss +++ b/src/components/expansion-panel/expansion-panel-header/expansion-panel-header.scss @@ -17,6 +17,12 @@ display: block; } +:host([data-size='s']) { + --sbb-expansion-panel-header-gap: var(--sbb-spacing-fixed-2x); + --sbb-expansion-panel-header-padding-block: var(--sbb-spacing-fixed-3x); + --sbb-expansion-panel-header-padding-inline: var(--sbb-spacing-fixed-5x); +} + :host([disabled]) { --sbb-expansion-panel-header-cursor: default; --sbb-expansion-panel-header-text-color: var(--sbb-color-granite); diff --git a/src/components/expansion-panel/expansion-panel/expansion-panel.stories.ts b/src/components/expansion-panel/expansion-panel/expansion-panel.stories.ts index ecf59585531..7b8dfff1a61 100644 --- a/src/components/expansion-panel/expansion-panel/expansion-panel.stories.ts +++ b/src/components/expansion-panel/expansion-panel/expansion-panel.stories.ts @@ -92,6 +92,13 @@ const disableAnimation: InputType = { }, }; +const size: InputType = { + control: { + type: 'inline-radio', + }, + options: ['l', 's'], +}; + const defaultArgTypes: ArgTypes = { headerText, iconName, @@ -102,6 +109,7 @@ const defaultArgTypes: ArgTypes = { borderless, disabled, 'disable-animation': disableAnimation, + size, }; const defaultArgs: Args = { @@ -114,6 +122,7 @@ const defaultArgs: Args = { borderless: false, disabled: false, 'disable-animation': false, + size: size.options[0], }; const Template = ({ headerText, iconName, contentText, ...args }: Args): TemplateResult => html` @@ -206,6 +215,18 @@ export const NoAnimation: StoryObj = { args: { ...defaultArgs, 'disable-animation': true }, }; +export const SizeS: StoryObj = { + render: Template, + argTypes: defaultArgTypes, + args: { ...defaultArgs, size: size.options[1] }, +}; + +export const SizeSWithIcon: StoryObj = { + render: Template, + argTypes: defaultArgTypes, + args: { ...defaultArgs, size: size.options[1], iconName: 'swisspass-medium' }, +}; + const wrapperStyle = (context: StoryContext): Record => ({ 'background-color': context.args.color === 'white' && context.args.borderless diff --git a/src/components/expansion-panel/expansion-panel/expansion-panel.ts b/src/components/expansion-panel/expansion-panel/expansion-panel.ts index 3a5ccaaf68d..dcb62614d3a 100644 --- a/src/components/expansion-panel/expansion-panel/expansion-panel.ts +++ b/src/components/expansion-panel/expansion-panel/expansion-panel.ts @@ -1,4 +1,4 @@ -import type { CSSResultGroup, TemplateResult } from 'lit'; +import type { CSSResultGroup, PropertyValues, TemplateResult } from 'lit'; import { LitElement } from 'lit'; import { customElement, property } from 'lit/decorators.js'; import { html, unsafeStatic } from 'lit/static-html.js'; @@ -69,6 +69,9 @@ export class SbbExpansionPanelElement extends SbbHydrationMixin(LitElement) { @property({ attribute: 'disable-animation', reflect: true, type: Boolean }) public disableAnimation = false; + /** Size variant, either l or s. */ + @property({ reflect: true }) public size: 's' | 'l' = 'l'; + /** Emits whenever the `sbb-expansion-panel` starts the opening transition. */ private _willOpen: EventEmitter = new EventEmitter( this, @@ -136,8 +139,14 @@ export class SbbExpansionPanelElement extends SbbHydrationMixin(LitElement) { super.connectedCallback(); const signal = this._abort.signal; this.addEventListener('toggleExpanded', () => this._toggleExpanded(), { signal }); - const accordion = this.closest?.('sbb-accordion'); - this.toggleAttribute('data-accordion', !!accordion); + this.toggleAttribute('data-accordion', !!this.closest?.('sbb-accordion')); + } + + protected override willUpdate(changedProperties: PropertyValues): void { + if (changedProperties.has('size')) { + this._headerRef?.setAttribute('data-size', String(this.size)); + this._contentRef?.setAttribute('data-size', String(this.size)); + } } public override disconnectedCallback(): void { @@ -161,10 +170,12 @@ export class SbbExpansionPanelElement extends SbbHydrationMixin(LitElement) { header.id ||= `sbb-expansion-panel-header${this._progressiveId}`; header.setAttribute('aria-expanded', String(this.expanded)); header.toggleAttribute('disabled', this.disabled); + header.setAttribute('data-size', String(this.size)); } if (content && this._contentRef !== content) { content.id ||= `sbb-expansion-panel-content${this._progressiveId}`; content.setAttribute('aria-hidden', String(!this.expanded)); + content.setAttribute('data-size', String(this.size)); } this._headerRef = header; @@ -218,6 +229,7 @@ export class SbbExpansionPanelElement extends SbbHydrationMixin(LitElement) { `; + /* eslint-enable lit/binding-positions */ } } diff --git a/src/components/expansion-panel/expansion-panel/readme.md b/src/components/expansion-panel/expansion-panel/readme.md index c86ff96c741..336b8fb5002 100644 --- a/src/components/expansion-panel/expansion-panel/readme.md +++ b/src/components/expansion-panel/expansion-panel/readme.md @@ -40,6 +40,13 @@ The component has two background options (`milk` and `white`, which is the defau ... ``` +The component has two different sizes, `l` (default) and `s`, which can be changed using the `size` property. +The property is overridden when the component is used within a `sbb-accordion`. + +```html + ... +``` + It's also possible to display the `sbb-expansion-panel` without border by setting the `borderless` variable. ```html @@ -79,6 +86,7 @@ and the `aria-hidden` attribute on the content. | `disabled` | `disabled` | public | `boolean` | `false` | Whether the panel is disabled, so its expanded state can't be changed. | | `borderless` | `borderless` | public | `boolean` | `false` | Whether the panel has no border. | | `disableAnimation` | `disable-animation` | public | `boolean` | `false` | Whether the animations should be disabled. | +| `size` | `size` | public | `'s' \| 'l'` | `'l'` | Size variant, either l or s. | ## Events