From b912dac06e4041c5df3628a162ce240d28f78d59 Mon Sep 17 00:00:00 2001 From: Marco D'Auria <101181211+dauriamarco@users.noreply.github.com> Date: Wed, 7 Aug 2024 14:02:28 +0200 Subject: [PATCH] feat(sbb-flip-card): add flip event and isFlipped getter (#2988) Closes #2961 --------- Co-authored-by: Jeremias Peier --- .../flip-card/flip-card/flip-card.spec.ts | 14 +++++++++++++- .../flip-card/flip-card/flip-card.stories.ts | 13 ++++++++++--- src/elements/flip-card/flip-card/flip-card.ts | 14 ++++++++++++++ src/elements/flip-card/flip-card/readme.md | 15 +++++++++++---- 4 files changed, 48 insertions(+), 8 deletions(-) diff --git a/src/elements/flip-card/flip-card/flip-card.spec.ts b/src/elements/flip-card/flip-card/flip-card.spec.ts index 909c7bd091..b95dec7faf 100644 --- a/src/elements/flip-card/flip-card/flip-card.spec.ts +++ b/src/elements/flip-card/flip-card/flip-card.spec.ts @@ -2,7 +2,7 @@ import { assert, expect } from '@open-wc/testing'; import { html } from 'lit/static-html.js'; import { fixture } from '../../core/testing/private.js'; -import { waitForLitRender } from '../../core/testing.js'; +import { EventSpy, waitForCondition, waitForLitRender } from '../../core/testing.js'; import type { SbbFlipCardDetailsElement } from '../flip-card-details.js'; import type { SbbFlipCardSummaryElement } from '../flip-card-summary.js'; @@ -31,32 +31,44 @@ describe('sbb-flip-card', () => { }); it('it toggles on click', async () => { + const flipSpy = new EventSpy(SbbFlipCardElement.events.flip); const summary: SbbFlipCardSummaryElement = element.summary; const details: SbbFlipCardDetailsElement = element.details; expect(summary.inert).to.be.equal(false); expect(details.inert).to.be.equal(true); + expect(element.isFlipped).to.be.false; element.shadowRoot?.querySelector('button')!.click(); await waitForLitRender(element); + await waitForCondition(() => flipSpy.events.length === 1); + expect(flipSpy.count).to.be.equal(1); + expect(element).to.have.attribute('data-flipped'); + expect(element.isFlipped).to.be.true; expect(summary.inert).to.be.equal(true); expect(details.inert).to.be.equal(false); }); it('it toggles programmatically', async () => { + const flipSpy = new EventSpy(SbbFlipCardElement.events.flip); const summary: SbbFlipCardSummaryElement = element.summary; const details: SbbFlipCardDetailsElement = element.details; expect(summary.inert).to.be.equal(false); expect(details.inert).to.be.equal(true); + expect(element.isFlipped).to.be.false; element.toggle(); await waitForLitRender(element); + await waitForCondition(() => flipSpy.events.length === 1); + expect(flipSpy.count).to.be.equal(1); + expect(element).to.have.attribute('data-flipped'); + expect(element.isFlipped).to.be.true; expect(summary.inert).to.be.equal(true); expect(details.inert).to.be.equal(false); diff --git a/src/elements/flip-card/flip-card/flip-card.stories.ts b/src/elements/flip-card/flip-card/flip-card.stories.ts index f89e01b22e..dc2b1ec1d5 100644 --- a/src/elements/flip-card/flip-card/flip-card.stories.ts +++ b/src/elements/flip-card/flip-card/flip-card.stories.ts @@ -1,10 +1,12 @@ +import { withActions } from '@storybook/addon-actions/decorator'; import type { InputType } from '@storybook/types'; -import type { Args, ArgTypes, Meta, StoryObj } from '@storybook/web-components'; +import type { Args, ArgTypes, Meta, StoryObj, Decorator } from '@storybook/web-components'; import type { TemplateResult } from 'lit'; import { html, nothing } from 'lit'; import sampleImages from '../../core/images.js'; +import { SbbFlipCardElement } from './flip-card.js'; import readme from './readme.md?raw'; import '../../image/image.js'; @@ -12,7 +14,6 @@ import '../../link/link/link.js'; import '../../title/title.js'; import '../flip-card-details.js'; import '../flip-card-summary.js'; -import './flip-card.js'; const imageAlignment: InputType = { control: { @@ -129,8 +130,14 @@ export const LongTitle: StoryObj = { }; const meta: Meta = { - decorators: [(story) => html`
${story()}
`], + decorators: [ + (story) => html`
${story()}
`, + withActions as Decorator, + ], parameters: { + actions: { + handles: [SbbFlipCardElement.events.flip], + }, docs: { extractComponentDescription: () => readme, }, diff --git a/src/elements/flip-card/flip-card/flip-card.ts b/src/elements/flip-card/flip-card/flip-card.ts index 042890ab68..b301768cd9 100644 --- a/src/elements/flip-card/flip-card/flip-card.ts +++ b/src/elements/flip-card/flip-card/flip-card.ts @@ -3,6 +3,7 @@ import { html, LitElement } from 'lit'; import { customElement, state } from 'lit/decorators.js'; import { SbbLanguageController } from '../../core/controllers.js'; +import { EventEmitter } from '../../core/eventing.js'; import { i18nFlipCard, i18nReverseCard } from '../../core/i18n.js'; import { SbbHydrationMixin } from '../../core/mixins.js'; import type { SbbFlipCardDetailsElement } from '../flip-card-details.js'; @@ -17,11 +18,18 @@ import '../../button/secondary-button.js'; * * @slot summary - Use this slot to provide a sbb-flip-card-summary component. * @slot details - Use this slot to provide a sbb-flip-card-details component. + * @event {CustomEvent} flip - Emits when the flip card flips. * */ @customElement('sbb-flip-card') export class SbbFlipCardElement extends SbbHydrationMixin(LitElement) { public static override styles: CSSResultGroup = style; + public static readonly events = { + flip: 'flip', + } as const; + + /** Emits whenever the component is flipped. */ + protected flip: EventEmitter = new EventEmitter(this, SbbFlipCardElement.events.flip); /** Returns the slotted sbb-flip-card-summary. */ public get summary(): SbbFlipCardSummaryElement { @@ -33,6 +41,11 @@ export class SbbFlipCardElement extends SbbHydrationMixin(LitElement) { return this.querySelector('sbb-flip-card-details')!; } + /** Whether the flip card is flipped. */ + public get isFlipped(): boolean { + return this._flipped; + } + /** Whether the card is flipped or not. */ @state() private _flipped = false; @@ -44,6 +57,7 @@ export class SbbFlipCardElement extends SbbHydrationMixin(LitElement) { this.toggleAttribute('data-flipped', this._flipped); this.summary.inert = this._flipped; this.details.inert = !this._flipped; + this.flip.emit(); } protected override render(): TemplateResult { diff --git a/src/elements/flip-card/flip-card/readme.md b/src/elements/flip-card/flip-card/readme.md index 4512dad1c8..2da83a0ba4 100644 --- a/src/elements/flip-card/flip-card/readme.md +++ b/src/elements/flip-card/flip-card/readme.md @@ -23,10 +23,11 @@ The `sbb-flip-card` will switch to the flipped state after the user clicks on it ## Properties -| Name | Attribute | Privacy | Type | Default | Description | -| --------- | --------- | ------- | --------------------------- | ------- | ------------------------------------------ | -| `details` | - | public | `SbbFlipCardDetailsElement` | | Returns the slotted sbb-flip-card-details. | -| `summary` | - | public | `SbbFlipCardSummaryElement` | | Returns the slotted sbb-flip-card-summary. | +| Name | Attribute | Privacy | Type | Default | Description | +| ----------- | --------- | ------- | --------------------------- | ------- | ------------------------------------------ | +| `details` | - | public | `SbbFlipCardDetailsElement` | | Returns the slotted sbb-flip-card-details. | +| `isFlipped` | - | public | `boolean` | | Whether the flip card is flipped. | +| `summary` | - | public | `SbbFlipCardSummaryElement` | | Returns the slotted sbb-flip-card-summary. | ## Methods @@ -34,6 +35,12 @@ The `sbb-flip-card` will switch to the flipped state after the user clicks on it | -------- | ------- | --------------------------------------- | ---------- | ------ | -------------- | | `toggle` | public | Toggles the state of the sbb-flip-card. | | `void` | | +## Events + +| Name | Type | Description | Inherited From | +| ------ | ------------------- | ------------------------------- | -------------- | +| `flip` | `CustomEvent` | Emits when the flip card flips. | | + ## Slots | Name | Description |