diff --git a/.changeset/shy-walls-exercise.md b/.changeset/shy-walls-exercise.md new file mode 100644 index 0000000000..ba712642c4 --- /dev/null +++ b/.changeset/shy-walls-exercise.md @@ -0,0 +1,7 @@ +--- +'@swisspost/design-system-documentation': minor +'@swisspost/design-system-components': minor +'@swisspost/design-system-styles': minor +--- + +Added close button web component. diff --git a/packages/components/cypress/e2e/closebutton.cy.ts b/packages/components/cypress/e2e/closebutton.cy.ts new file mode 100644 index 0000000000..275adfb50a --- /dev/null +++ b/packages/components/cypress/e2e/closebutton.cy.ts @@ -0,0 +1,22 @@ +const CLOSE_BTN_ID = 'de313349-0c0b-4baf-adc6-cb8c2e36fc1a'; + +describe('Close button', () => { + describe('default', () => { + beforeEach(() => { + cy.getComponent('post-closebutton', CLOSE_BTN_ID); + }); + + it('should render with a close button and a11y label', () => { + cy.get('@closebutton').should('exist'); + cy.get('@closebutton').find('.btn-icon-close').should('exist'); + cy.get('@closebutton').find('span.visually-hidden').should('exist'); + }); + }); +}); + +describe('Accessibility', () => { + it('Has no detectable a11y violations on load for all variants', () => { + cy.getSnapshots('post-closebutton'); + cy.checkA11y('#root-inner'); + }); +}); diff --git a/packages/components/src/components.d.ts b/packages/components/src/components.d.ts index 5fb886f66a..3056034100 100644 --- a/packages/components/src/components.d.ts +++ b/packages/components/src/components.d.ts @@ -148,6 +148,8 @@ export namespace Components { */ "value": string; } + interface PostClosebutton { + } interface PostCollapsible { /** * If `true`, the element is collapsed otherwise it is displayed. @@ -475,6 +477,12 @@ declare global { prototype: HTMLPostCardControlElement; new (): HTMLPostCardControlElement; }; + interface HTMLPostClosebuttonElement extends Components.PostClosebutton, HTMLStencilElement { + } + var HTMLPostClosebuttonElement: { + prototype: HTMLPostClosebuttonElement; + new (): HTMLPostClosebuttonElement; + }; interface HTMLPostCollapsibleElementEventMap { "postToggle": boolean; } @@ -631,6 +639,7 @@ declare global { "post-avatar": HTMLPostAvatarElement; "post-breadcrumb-item": HTMLPostBreadcrumbItemElement; "post-card-control": HTMLPostCardControlElement; + "post-closebutton": HTMLPostClosebuttonElement; "post-collapsible": HTMLPostCollapsibleElement; "post-collapsible-trigger": HTMLPostCollapsibleTriggerElement; "post-icon": HTMLPostIconElement; @@ -769,6 +778,8 @@ declare namespace LocalJSX { */ "value"?: string; } + interface PostClosebutton { + } interface PostCollapsible { /** * If `true`, the element is collapsed otherwise it is displayed. @@ -973,6 +984,7 @@ declare namespace LocalJSX { "post-avatar": PostAvatar; "post-breadcrumb-item": PostBreadcrumbItem; "post-card-control": PostCardControl; + "post-closebutton": PostClosebutton; "post-collapsible": PostCollapsible; "post-collapsible-trigger": PostCollapsibleTrigger; "post-icon": PostIcon; @@ -1003,6 +1015,7 @@ declare module "@stencil/core" { * @class PostCardControl - representing a stencil component */ "post-card-control": LocalJSX.PostCardControl & JSXBase.HTMLAttributes; + "post-closebutton": LocalJSX.PostClosebutton & JSXBase.HTMLAttributes; "post-collapsible": LocalJSX.PostCollapsible & JSXBase.HTMLAttributes; "post-collapsible-trigger": LocalJSX.PostCollapsibleTrigger & JSXBase.HTMLAttributes; /** diff --git a/packages/components/src/components/post-closebutton/post-closebutton.tsx b/packages/components/src/components/post-closebutton/post-closebutton.tsx new file mode 100644 index 0000000000..68d13ef51a --- /dev/null +++ b/packages/components/src/components/post-closebutton/post-closebutton.tsx @@ -0,0 +1,26 @@ +import { Component, Element, h, Host } from '@stencil/core'; +import { version } from '@root/package.json'; + +/** + * @slot default - Slot for placing visually hidden label in the close button. + */ +@Component({ + tag: 'post-closebutton', + shadow: false, +}) +export class PostClosebutton { + @Element() host: HTMLPostClosebuttonElement; + + render() { + return ( + + + + ); + } +} diff --git a/packages/components/src/components/post-closebutton/readme.md b/packages/components/src/components/post-closebutton/readme.md new file mode 100644 index 0000000000..ca0053c6df --- /dev/null +++ b/packages/components/src/components/post-closebutton/readme.md @@ -0,0 +1,30 @@ +# post-closebutton + + + + + + +## Slots + +| Slot | Description | +| ----------- | ----------------------------------------------------------- | +| `"default"` | Slot for placing visually hidden label in the close button. | + + +## Dependencies + +### Depends on + +- [post-icon](../post-icon) + +### Graph +```mermaid +graph TD; + post-closebutton --> post-icon + style post-closebutton fill:#f9f,stroke:#333,stroke-width:4px +``` + +---------------------------------------------- + +*Built with [StencilJS](https://stenciljs.com/)* diff --git a/packages/components/src/components/post-icon/readme.md b/packages/components/src/components/post-icon/readme.md index 92d1a4bacb..afb94ab2e7 100644 --- a/packages/components/src/components/post-icon/readme.md +++ b/packages/components/src/components/post-icon/readme.md @@ -25,6 +25,7 @@ some content - [post-alert](../post-alert) - [post-breadcrumb-item](../post-breadcrumb-item) - [post-card-control](../post-card-control) + - [post-closebutton](../post-closebutton) - [post-rating](../post-rating) - [post-tag](../post-tag) @@ -34,6 +35,7 @@ graph TD; post-alert --> post-icon post-breadcrumb-item --> post-icon post-card-control --> post-icon + post-closebutton --> post-icon post-rating --> post-icon post-tag --> post-icon style post-icon fill:#f9f,stroke:#333,stroke-width:4px diff --git a/packages/components/src/index.ts b/packages/components/src/index.ts index 2644481576..a2734c8e80 100644 --- a/packages/components/src/index.ts +++ b/packages/components/src/index.ts @@ -7,6 +7,7 @@ export { PostAlert } from './components/post-alert/post-alert'; export { PostBreadcrumbItem } from './components/post-breadcrumb-item/post-breadcrumb-item'; export { PostAvatar } from './components/post-avatar/post-avatar'; export { PostCardControl } from './components/post-card-control/post-card-control'; +export { PostClosebutton } from './components/post-closebutton/post-closebutton'; export { PostCollapsible } from './components/post-collapsible/post-collapsible'; export { PostCollapsibleTrigger } from './components/post-collapsible-trigger/post-collapsible-trigger'; export { PostIcon } from './components/post-icon/post-icon'; diff --git a/packages/documentation/cypress/snapshots/components/close-button.snapshot.ts b/packages/documentation/cypress/snapshots/components/close-button.snapshot.ts new file mode 100644 index 0000000000..82da359c4c --- /dev/null +++ b/packages/documentation/cypress/snapshots/components/close-button.snapshot.ts @@ -0,0 +1,7 @@ +describe('Close button', () => { + it('post-closebutton', () => { + cy.visit('/iframe.html?id=snapshots--post-closebutton'); + cy.get('post-closebutton[data-hydrated]', { timeout: 30000 }).should('be.visible'); + cy.percySnapshot('Close button (Web Component)', { widths: [1440] }); + }); +}); diff --git a/packages/documentation/src/stories/components/button/button.docs.mdx b/packages/documentation/src/stories/components/buttons/button/button.docs.mdx similarity index 100% rename from packages/documentation/src/stories/components/button/button.docs.mdx rename to packages/documentation/src/stories/components/buttons/button/button.docs.mdx diff --git a/packages/documentation/src/stories/components/button/button.snapshot.stories.ts b/packages/documentation/src/stories/components/buttons/button/button.snapshot.stories.ts similarity index 100% rename from packages/documentation/src/stories/components/button/button.snapshot.stories.ts rename to packages/documentation/src/stories/components/buttons/button/button.snapshot.stories.ts diff --git a/packages/documentation/src/stories/components/button/button.stories.ts b/packages/documentation/src/stories/components/buttons/button/button.stories.ts similarity index 99% rename from packages/documentation/src/stories/components/button/button.stories.ts rename to packages/documentation/src/stories/components/buttons/button/button.stories.ts index 1b707a53a3..5e8ba415d2 100644 --- a/packages/documentation/src/stories/components/button/button.stories.ts +++ b/packages/documentation/src/stories/components/buttons/button/button.stories.ts @@ -6,7 +6,7 @@ import { MetaComponent } from '@root/types'; const meta: MetaComponent = { id: 'eb78afcb-ce92-4990-94b6-6536d5ec6af4', - title: 'Components/Button', + title: 'Components/Buttons/Button', tags: ['package:HTML'], parameters: { badges: [], diff --git a/packages/documentation/src/stories/components/buttons/close-button/close-button.docs.mdx b/packages/documentation/src/stories/components/buttons/close-button/close-button.docs.mdx new file mode 100644 index 0000000000..6e3948c7de --- /dev/null +++ b/packages/documentation/src/stories/components/buttons/close-button/close-button.docs.mdx @@ -0,0 +1,24 @@ +import { Canvas, Controls, Meta, Source } from '@storybook/blocks'; +import * as CloseButtonStories from './close-button.stories'; + + + +
+ # Close button + + +
+ +
+ The close button is a web component. It is a slightly adapted version of the icon button, intended + for a specific use case. +
+ +The value inside the `` element will be rendered inside the button as a visually hidden text so make sure to only insert inline content there. + + +
+ +
diff --git a/packages/documentation/src/stories/components/buttons/close-button/close-button.snapshot.stories.ts b/packages/documentation/src/stories/components/buttons/close-button/close-button.snapshot.stories.ts new file mode 100644 index 0000000000..d6b21d0b46 --- /dev/null +++ b/packages/documentation/src/stories/components/buttons/close-button/close-button.snapshot.stories.ts @@ -0,0 +1,26 @@ +import type { Args, StoryContext, StoryObj } from '@storybook/web-components'; +import meta, { Default } from './close-button.stories'; +import { html } from 'lit'; + +const { id, ...metaWithoutId } = meta; + +export default { + ...metaWithoutId, + title: 'Snapshots', +}; + +type Story = StoryObj; + +export const PostClosebutton: Story = { + render: (_args: Args, context: StoryContext) => { + return html` + ${['bg-white', 'bg-dark'].map( + bg => html` +
+ ${Default.render?.({ ...context.args }, context)} +
+ `, + )} + `; + }, +}; diff --git a/packages/documentation/src/stories/components/buttons/close-button/close-button.stories.ts b/packages/documentation/src/stories/components/buttons/close-button/close-button.stories.ts new file mode 100644 index 0000000000..7b947e99a0 --- /dev/null +++ b/packages/documentation/src/stories/components/buttons/close-button/close-button.stories.ts @@ -0,0 +1,39 @@ +import type { Args, StoryObj } from '@storybook/web-components'; +import { html } from 'lit/static-html.js'; +import { MetaComponent } from '@root/types'; +import { unsafeHTML } from 'lit/directives/unsafe-html.js'; + +const meta: MetaComponent = { + id: 'de313349-0c0b-4baf-adc6-cb8c2e36fc1a', + title: 'Components/Buttons/Close button', + component: 'post-closebutton', + tags: ['package:WebComponents'], + parameters: { + badges: [], + design: { + type: 'figma', + url: 'https://www.figma.com/design/JIT5AdGYqv6bDRpfBPV8XR/Foundations-%26-Components-Next-Level?node-id=2514-18516&t=gCGlckfBEobCTna3-4', + }, + }, + args: { + 'slots-default': 'Close button', + }, + argTypes: { + 'slots-default': { + name: 'Label', + control: { + type: 'text', + }, + }, + }, +}; + +export default meta; + +type Story = StoryObj; + +export const Default: Story = { + render: (args: Args) => { + return html`${unsafeHTML(args['slots-default'])} `; + }, +}; diff --git a/packages/styles/src/components/_index.scss b/packages/styles/src/components/_index.scss index b75e0b8370..41d7eacdf6 100644 --- a/packages/styles/src/components/_index.scss +++ b/packages/styles/src/components/_index.scss @@ -25,6 +25,7 @@ @use 'forms'; @use 'grid'; @use 'icon-button'; +@use 'icon-close-button'; @use 'icons'; @use 'lead'; @use 'list-group'; diff --git a/packages/styles/src/components/icon-close-button.scss b/packages/styles/src/components/icon-close-button.scss new file mode 100644 index 0000000000..c8eb34d175 --- /dev/null +++ b/packages/styles/src/components/icon-close-button.scss @@ -0,0 +1,28 @@ +@use '../functions/tokens'; +@use '../tokens/components'; +@use './../mixins/utilities'; + +tokens.$default-map: components.$post-close; + +.btn-icon-close { + padding: 0; + border: unset; + min-height: unset; + min-width: unset; + width: tokens.get('close-size'); + height: tokens.get('close-size'); + border-radius: tokens.get('close-border-radius'); + background-color: tokens.get('close-enabled-bg'); + color: tokens.get('close-enabled-fg'); + + > post-icon { + width: tokens.get('close-icon-size'); + height: tokens.get('close-icon-size'); + } + + @include utilities.not-disabled-hover() { + cursor: pointer; + background-color: tokens.get('close-hover-bg'); + color: tokens.get('close-hover-fg'); + } +}