Skip to content

Commit

Permalink
feat(content-switcher): add fds-content-switcher component (#186)
Browse files Browse the repository at this point in the history
  • Loading branch information
onursabanoglu authored Nov 19, 2024
1 parent 50cf7c8 commit 367575c
Show file tree
Hide file tree
Showing 6 changed files with 275 additions and 0 deletions.
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;
}
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>
`;
}
}
72 changes: 72 additions & 0 deletions src/components/content-switcher/fds-content-switcher.scss
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 src/components/content-switcher/fds-content-switcher.stories.ts
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>
`,
};
53 changes: 53 additions & 0 deletions src/components/content-switcher/fds-content-switcher.ts
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>
`;
}
}
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ export { FdsButton } from './components/button/fds-button';
export { FdsCard } from './components/card/fds-card';
export { FdsCheckbox } from './components/checkbox/fds-checkbox';
export { FdsCheckboxGroup } from './components/checkbox-group/fds-checkbox-group';
export { FdsContentSwitcher } from './components/content-switcher/fds-content-switcher';
export { FdsContentSwitcherButton } from './components/content-switcher/content-switcher-button/fds-content-switcher-button';
export { FdsHelperText } from './components/helper-text/fds-helper-text';
export { FdsIcon } from './components/icon/fds-icon';
export { FdsLink } from './components/link/fds-link';
Expand Down

0 comments on commit 367575c

Please sign in to comment.