-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(components): segmented-button (#3879)
Co-authored-by: Zherdetska Alona, IT21.1 <[email protected]> Co-authored-by: Oliver Schürch <[email protected]> Co-authored-by: Philipp Gfeller <[email protected]> Co-authored-by: Philipp Gfeller <[email protected]>
- Loading branch information
1 parent
6ca7f64
commit 47570b0
Showing
8 changed files
with
408 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
--- | ||
'@swisspost/design-system-documentation': minor | ||
'@swisspost/design-system-styles': minor | ||
--- | ||
|
||
Added a new `segmented-button` component, which allows users to toggle between two or more content sections within the same area on the screen. |
45 changes: 45 additions & 0 deletions
45
packages/documentation/cypress/e2e/components/segmented-button.cy.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
describe('Segmented Button', () => { | ||
describe('Accessibility', () => { | ||
beforeEach(() => { | ||
cy.visit('/iframe.html?id=snapshots--segmented-button'); | ||
cy.get('.segmented-button', { timeout: 30000 }).should('be.visible'); | ||
cy.injectAxe(); | ||
}); | ||
|
||
it('Has no detectable a11y violations on load for all variants', () => { | ||
cy.checkA11y('#root-inner'); | ||
}); | ||
}); | ||
|
||
describe('Responsiveness', () => { | ||
beforeEach(() => { | ||
cy.visit('/iframe.html?id=snapshots--segmented-button'); | ||
cy.get('.segmented-button', { timeout: 30000 }).should('be.visible'); | ||
}); | ||
|
||
it('Displays vertical layout when viewport is narrower than 600px', () => { | ||
cy.viewport(500, 600); | ||
cy.get('.segmented-button') | ||
.should('have.css', 'flex-direction', 'column'); | ||
}); | ||
}); | ||
|
||
describe('Input Selection', () => { | ||
beforeEach(() => { | ||
cy.visit('/iframe.html?id=snapshots--segmented-button'); | ||
cy.get('.segmented-button', { timeout: 30000 }).should('be.visible'); | ||
}); | ||
|
||
it('Allows selecting an input and updates the state', () => { | ||
cy.get('.segmented-button label').first().click(); | ||
|
||
cy.get('.segmented-button label input').first().should('be.checked'); | ||
|
||
cy.get('.segmented-button label').eq(1).click(); | ||
|
||
cy.get('.segmented-button label input').eq(1).should('be.checked'); | ||
|
||
cy.get('.segmented-button label input').first().should('not.be.checked'); | ||
}); | ||
}); | ||
}); |
7 changes: 7 additions & 0 deletions
7
packages/documentation/cypress/snapshots/components/segmented-button.snapshot.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
describe('Segmented-button', () => { | ||
it('default', () => { | ||
cy.visit('/iframe.html?id=snapshots--segmented-button'); | ||
cy.get('.segmented-button', { timeout: 30000 }).should('be.visible'); | ||
cy.percySnapshot('Segmented-button', { widths: [1440] }); | ||
}); | ||
}); |
34 changes: 34 additions & 0 deletions
34
...documentation/src/stories/components/segmented-button/segmented-button.docs.mdx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import { Meta, Canvas, Controls } from '@storybook/blocks'; | ||
import * as SegmentedButtonStories from './segmented-button.stories'; | ||
import StylesPackageImport from '@/shared/styles-package-import.mdx'; | ||
|
||
<Meta of={SegmentedButtonStories} /> | ||
|
||
<div className="docs-title"> | ||
# Segmented Button | ||
|
||
<nav> | ||
<link-design of={JSON.stringify(SegmentedButtonStories)}></link-design> | ||
</nav> | ||
</div> | ||
|
||
The segmented button is a single-select component. | ||
It allows users to toggle between two or more content sections within the same area on the screen. | ||
|
||
<div role="alert" class="alert alert-info"> | ||
<p> | ||
If the labels are too long or the number of options is excessive for the available space, | ||
consider using a select component. Keep in mind that long labels may cause layout issues, | ||
such as text overflowing or word breaks. | ||
</p> | ||
</div> | ||
|
||
<Canvas of={SegmentedButtonStories.TextExample} sourceState="shown" /> | ||
<Controls of={SegmentedButtonStories.TextExample} /> | ||
|
||
## Segmented icon button | ||
|
||
<Canvas of={SegmentedButtonStories.IconExample} sourceState="shown" /> | ||
<Controls of={SegmentedButtonStories.IconExample} /> | ||
|
||
<StylesPackageImport components={['segmented-button']} /> |
48 changes: 48 additions & 0 deletions
48
...ocumentation/src/stories/components/segmented-button/segmented-button.snapshot.stories.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
import type { StoryObj } from '@storybook/web-components'; | ||
import meta from './segmented-button.stories'; | ||
import { html } from 'lit'; | ||
|
||
const { id, ...metaWithoutId } = meta; | ||
|
||
export default { | ||
...metaWithoutId, | ||
title: 'Snapshots', | ||
}; | ||
|
||
type Story = StoryObj; | ||
|
||
export const SegmentedButton: Story = { | ||
render: () => { | ||
const labelCounts = [2, 4, 6, 8]; | ||
const themes = ['bg-light', 'bg-dark']; | ||
|
||
return html` | ||
<div class="gap-4"> | ||
${themes.map( | ||
(theme) => html` | ||
<div class="${theme} d-flex flex-column w-75 gap-16 p-16"> | ||
${labelCounts.map((count) => { | ||
const labels = Array.from({ length: count }, (_, i) => `Label ${i + 1}`); | ||
return html` | ||
<div class="segmented-button-container"> | ||
<fieldset class="segmented-button"> | ||
${labels.map( | ||
(label) => html` | ||
<label class="segmented-button-label"> | ||
<input name="snapshot-${count}-${theme}" type="radio" /> | ||
${label} | ||
</label> | ||
` | ||
)} | ||
</fieldset> | ||
</div> | ||
`; | ||
})} | ||
</div> | ||
` | ||
)} | ||
</div> | ||
`; | ||
}, | ||
}; |
81 changes: 81 additions & 0 deletions
81
packages/documentation/src/stories/components/segmented-button/segmented-button.stories.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
import { Args, StoryObj } from '@storybook/web-components'; | ||
import { html, nothing } from 'lit'; | ||
import { MetaComponent } from '@root/types'; | ||
|
||
const MAX_LABELS = 8; | ||
|
||
const meta: MetaComponent = { | ||
id: '78509712-d45e-462c-bde3-405cfaff5421', | ||
title: 'Components/Segmented button', | ||
tags: ['package:HTML'], | ||
parameters: { | ||
badges: [], | ||
design: { | ||
type: 'figma', | ||
url: 'https://www.figma.com/design/JIT5AdGYqv6bDRpfBPV8XR/Foundations-%26-Components-Next-Level?node-id=2864-83396&node-type=instance&m=dev', | ||
}, | ||
}, | ||
args: { | ||
labelCount: 4, | ||
}, | ||
argTypes: { | ||
labelCount: { | ||
name: 'Number of segments', | ||
description: `Defines the number of segments for the segmented button. The maximum number of supported segments is 8. If you need more options, please refer to the select component.`, | ||
control: { type: 'number', min: 1, max: MAX_LABELS }, | ||
table: { category: 'Content' }, | ||
}, | ||
}, | ||
}; | ||
|
||
export default meta; | ||
|
||
type Story = StoryObj; | ||
|
||
export const TextExample: Story = { | ||
render: (args: Args) => { | ||
const labelCount = Math.min(args.labelCount || 0, MAX_LABELS); | ||
const labelsArray = Array.from({ length: labelCount }, (_, i) => `Label ${i + 1}`); | ||
const name = `segmented-button-${Math.random().toString(36).slice(-6)}`; | ||
|
||
return html` | ||
<div class="segmented-button-container"> | ||
<fieldset class="segmented-button"> | ||
<legend>Choose one of the options</legend> | ||
${labelsArray.map( | ||
(label, index) => html` | ||
<label class="segmented-button-label"> | ||
<input name="${name}" type="radio" checked="${index === 0 ? '' : nothing}" /> | ||
${label} | ||
</label> | ||
`, | ||
)} | ||
</fieldset> | ||
</div> | ||
`; | ||
}, | ||
}; | ||
|
||
export const IconExample: Story = { | ||
render: (args: Args) => { | ||
const labelCount = Math.min(args.labelCount || 0, MAX_LABELS); | ||
const name = `segmented-button-${Math.random().toString(36).slice(-6)}`; | ||
|
||
return html` | ||
<div class="segmented-button-container"> | ||
<fieldset class="segmented-button"> | ||
<legend>Choose one of the options</legend> | ||
${Array.from( | ||
{ length: labelCount }, | ||
(_undefined, index) => html` | ||
<label class="segmented-button-label"> | ||
<input type="radio" name="${name}" checked="${index === 0 ? '' : nothing}" /> | ||
<post-icon name="${1000 + index}" /> | ||
</label> | ||
`, | ||
)} | ||
</fieldset> | ||
</div> | ||
`; | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.