-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(content-switcher): add fds-content-switcher component (#186)
- Loading branch information
1 parent
50cf7c8
commit 367575c
Showing
6 changed files
with
275 additions
and
0 deletions.
There are no files selected for viewing
43 changes: 43 additions & 0 deletions
43
src/components/content-switcher/content-switcher-button/fds-content-switcher-button.scss
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,43 @@ | ||
@import '../../../styles/settings/prefix'; | ||
@import '../../../design-tokens/build/scss/tokens'; | ||
@import '../../../styles/tools/button'; | ||
@import '../../../styles/tools/text-truncate'; | ||
|
||
:host { | ||
display: inline-block; | ||
} | ||
|
||
:host(:first-of-type), | ||
:host(:first-of-type[selected]) .#{$prefix}-content-switcher-btn { | ||
border-radius: $button-border-radius 0 0 $button-border-radius; | ||
} | ||
|
||
:host(:last-of-type), | ||
:host(:last-of-type[selected]) .#{$prefix}-content-switcher-btn { | ||
border-radius: 0 $button-border-radius $button-border-radius 0; | ||
} | ||
|
||
.#{$prefix}-content-switcher-btn { | ||
@include button-base; | ||
|
||
height: 100%; | ||
color: inherit; | ||
border-radius: 0; | ||
} | ||
|
||
.#{$prefix}-content-switcher-btn__label { | ||
@include truncate; | ||
|
||
flex-grow: 1; | ||
} | ||
|
||
:host([selected]) .#{$prefix}-content-switcher-btn, | ||
:host([selected]) .#{$prefix}-content-switcher-btn:hover { | ||
background-color: $button-color-outline-active-background; | ||
box-shadow: inset 0 0 0 1px $button-color-outline-active-border; | ||
color: $button-color-outline-active-text; | ||
} | ||
|
||
:host([selected]) .#{$prefix}-content-switcher-btn { | ||
cursor: default; | ||
} |
24 changes: 24 additions & 0 deletions
24
src/components/content-switcher/content-switcher-button/fds-content-switcher-button.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,24 @@ | ||
import { html, LitElement, TemplateResult, unsafeCSS } from 'lit'; | ||
import { customElement, property } from 'lit/decorators.js'; | ||
|
||
import style from './fds-content-switcher-button.scss'; | ||
|
||
@customElement('fds-content-switcher-button') | ||
export class FdsContentSwitcherButton extends LitElement { | ||
static get styles() { | ||
return [unsafeCSS(style)]; | ||
} | ||
|
||
@property({ type: Boolean, reflect: true }) | ||
selected = false; | ||
|
||
render(): TemplateResult { | ||
return html` | ||
<button class="fds-content-switcher-btn" type="button" aria-pressed="${this.selected}"> | ||
<span class="fds-content-switcher-btn__label"> | ||
<slot></slot> | ||
</span> | ||
</button> | ||
`; | ||
} | ||
} |
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,72 @@ | ||
@import '../../styles/settings/prefix'; | ||
@import '../../design-tokens/build/scss/tokens'; | ||
|
||
|
||
:host { | ||
display: inline-flex; | ||
} | ||
|
||
.#{$prefix}-content-switcher { | ||
display: inline-flex; | ||
height: $content-switcher-size-height; | ||
flex-wrap: nowrap; | ||
gap: 1px; | ||
} | ||
|
||
:host([variant="solid"]) ::slotted(fds-content-switcher-button) { | ||
background-color: $button-color-secondary-background; | ||
box-shadow: inset 0 0 0 1px $button-color-secondary-border; | ||
color: $button-color-secondary-text; | ||
} | ||
|
||
:host([variant="solid"]) ::slotted(fds-content-switcher-button:hover) { | ||
background-color: $button-color-secondary-hover-background; | ||
box-shadow: inset 0 0 0 1px $button-color-secondary-hover-border; | ||
} | ||
|
||
:host([variant="solid"]) ::slotted(fds-content-switcher-button:active) { | ||
background-color: $button-color-secondary-active-background; | ||
box-shadow: inset 0 0 0 1px $button-color-secondary-active-border; | ||
} | ||
|
||
:host([variant="solid"]) ::slotted(fds-content-switcher-button:focus-visible) { | ||
box-shadow: inset 0 0 0 2px $button-color-focus-border, | ||
inset 0 0 0 3px $color-white; | ||
} | ||
|
||
:host([variant="outline"]) { | ||
.#{$prefix}-content-switcher { | ||
gap: 0; | ||
} | ||
} | ||
|
||
:host([variant="outline"]) ::slotted(fds-content-switcher-button) { | ||
background-color: transparent; | ||
box-shadow: inset 0 0 0 1px $button-color-outline-border; | ||
color: $button-color-outline-text; | ||
} | ||
|
||
:host([variant="outline"]) ::slotted(fds-content-switcher-button:not(:first-child)) { | ||
margin-left: -1px; | ||
} | ||
|
||
:host([variant="outline"]) ::slotted(fds-content-switcher-button:hover) { | ||
color: $button-color-outline-hover-text; | ||
background-color: $button-color-outline-hover-background; | ||
box-shadow: inset 0 0 0 1px $button-color-outline-hover-border; | ||
} | ||
|
||
:host([variant="outline"]) ::slotted(fds-content-switcher-button:active) { | ||
color: $button-color-outline-active-text; | ||
background-color: $button-color-outline-active-background; | ||
box-shadow: inset 0 0 0 1px $button-color-outline-active-border; | ||
} | ||
|
||
:host([variant="outline"]) ::slotted(fds-content-switcher-button:focus-visible) { | ||
box-shadow: inset 0 0 0 2px $button-color-focus-border, | ||
inset 0 0 0 3px $color-white; | ||
} | ||
|
||
:host([size="small"]) .#{$prefix}-content-switcher { | ||
height: $content-switcher-size-small-height; | ||
} |
81 changes: 81 additions & 0 deletions
81
src/components/content-switcher/fds-content-switcher.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 { html } from 'lit'; | ||
import { ifDefined } from 'lit/directives/if-defined.js'; | ||
|
||
import './fds-content-switcher'; | ||
import './content-switcher-button/fds-content-switcher-button'; | ||
|
||
export default { | ||
title: 'Components/Content Switcher', | ||
component: 'fds-content-switcher', | ||
parameters: { | ||
docs: { | ||
description: { | ||
component: | ||
'The content switcher is a layout-level component that helps differentiate and group similar or identical types of records and allows users to switch between them within itself.', | ||
}, | ||
}, | ||
}, | ||
argTypes: { | ||
variant: { | ||
options: ['solid', 'outline'], | ||
control: { | ||
type: 'inline-radio', | ||
}, | ||
}, | ||
size: { | ||
options: ['small', 'medium'], | ||
control: { | ||
type: 'inline-radio', | ||
}, | ||
}, | ||
}, | ||
args: { | ||
variant: 'solid', | ||
size: 'medium', | ||
}, | ||
}; | ||
|
||
/* eslint-disable @typescript-eslint/no-explicit-any */ | ||
export const Base = (args: any) => html` | ||
<fds-content-switcher variant=${ifDefined(args.variant)} size=${ifDefined(args.size)}> | ||
<fds-content-switcher-button selected>First item</fds-content-switcher-button> | ||
<fds-content-switcher-button>Second item</fds-content-switcher-button> | ||
<fds-content-switcher-button>Third item</fds-content-switcher-button> | ||
</fds-content-switcher> | ||
`; | ||
|
||
export const Variants = { | ||
render: () => html` | ||
<div style="display: flex; flex-direction: column; gap: 1rem"> | ||
<fds-content-switcher variant="solid" size="medium"> | ||
<fds-content-switcher-button selected>First item</fds-content-switcher-button> | ||
<fds-content-switcher-button>Second item</fds-content-switcher-button> | ||
<fds-content-switcher-button>Third item</fds-content-switcher-button> | ||
</fds-content-switcher> | ||
<fds-content-switcher variant="outline" size="medium"> | ||
<fds-content-switcher-button selected>First item</fds-content-switcher-button> | ||
<fds-content-switcher-button>Second item</fds-content-switcher-button> | ||
<fds-content-switcher-button>Third item</fds-content-switcher-button> | ||
</fds-content-switcher> | ||
</div> | ||
`, | ||
}; | ||
|
||
export const Sizes = { | ||
render: () => html` | ||
<div style="display: flex; flex-direction: column; gap: 1rem"> | ||
<fds-content-switcher variant="solid" size="small"> | ||
<fds-content-switcher-button selected>First item</fds-content-switcher-button> | ||
<fds-content-switcher-button>Second item</fds-content-switcher-button> | ||
<fds-content-switcher-button>Third item</fds-content-switcher-button> | ||
</fds-content-switcher> | ||
<fds-content-switcher variant="solid" size="medium"> | ||
<fds-content-switcher-button selected>First item</fds-content-switcher-button> | ||
<fds-content-switcher-button>Second item</fds-content-switcher-button> | ||
<fds-content-switcher-button>Third item</fds-content-switcher-button> | ||
</fds-content-switcher> | ||
</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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import { html, LitElement, TemplateResult, unsafeCSS } from 'lit'; | ||
import { customElement, property } from 'lit/decorators.js'; | ||
|
||
import style from './fds-content-switcher.scss'; | ||
|
||
@customElement('fds-content-switcher') | ||
export class FdsContentSwitcher extends LitElement { | ||
static get styles() { | ||
return [unsafeCSS(style)]; | ||
} | ||
|
||
@property({ type: String, reflect: true }) | ||
variant: 'solid' | 'outline' = 'solid'; | ||
|
||
@property({ type: String, reflect: true }) | ||
size: 'small' | 'medium' = 'medium'; | ||
|
||
private handleButtonClick = (event: MouseEvent) => { | ||
const target = event.target as HTMLElement; | ||
const clickedButton = target.closest('fds-content-switcher-button') as HTMLElement; | ||
|
||
if (!clickedButton) return; | ||
|
||
const buttons = this.querySelectorAll('fds-content-switcher-button'); | ||
buttons.forEach((button: Element) => { | ||
if (button === clickedButton) { | ||
button.setAttribute('selected', ''); | ||
} else { | ||
button.removeAttribute('selected'); | ||
} | ||
}); | ||
|
||
this.dispatchEvent( | ||
new CustomEvent('selection-change', { | ||
detail: { selectedButton: clickedButton }, | ||
bubbles: true, | ||
composed: true, | ||
}) | ||
); | ||
}; | ||
|
||
firstUpdated() { | ||
this.addEventListener('click', this.handleButtonClick); | ||
} | ||
|
||
render(): TemplateResult { | ||
return html` | ||
<div class="fds-content-switcher"> | ||
<slot></slot> | ||
</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