Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 46 additions & 3 deletions components/src/Switcher/Switcher.stories.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@
</script>

<Story name="Two Options" asChild>
<DesignTokens theme="light">
<DesignTokens theme="auto">
<Switcher options={['Option A', 'Option B']} value="Option A" size="default" label="Label" />
</DesignTokens>
</Story>

<Story name="Hidden Label" asChild>
<DesignTokens theme="light">
<DesignTokens theme="auto">
<Switcher
hideLabel
options={['Option A', 'Option B']}
Expand Down Expand Up @@ -47,7 +47,7 @@
});
}}
>
<DesignTokens theme="light">
<DesignTokens theme="auto">
<Switcher
options={['Apples', 'Oranges', 'Bananas', 'Peaches']}
value="Oranges"
Expand All @@ -57,6 +57,49 @@
</DesignTokens>
</Story>

<Story
name="Force row layout"
asChild
play={async ({ canvasElement, step }) => {
const canvas = within(canvasElement);
console.log(canvas);
await step('Options are displayed in a row', async () => {
const list = canvas.getByRole('list');
expect(list.classList).toContain('layout-row');
});
}}
>
<DesignTokens theme="auto">
<Switcher
options={['Do not wrap', 'on mobile']}
value="Do not wrap"
label="Label"
layout="row"
/>
</DesignTokens>
</Story>

<Story
name="Force column layout"
asChild
play={async ({ canvasElement, step }) => {
const canvas = within(canvasElement);
console.log(canvas);
await step('Options are displayed in a row', async () => {
const list = canvas.getByRole('list');
expect(list.classList).toContain('layout-column');
});
}}
>
<DesignTokens theme="auto">
<Switcher
options={['Always wrap', 'even on', 'large screens']}
value="Always wrap"
label="Label"
layout="column"
/>
</DesignTokens>
</Story>
<Story
name="onchange event"
asChild
Expand Down
65 changes: 47 additions & 18 deletions components/src/Switcher/Switcher.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,14 @@
* Display size
*/
size?: 'default' | 'small';
/**
* Hide the main label visually
*/
hideLabel?: boolean;
/**
* Force the options to be displayed in a row (even on small screens)
*/
layout?: 'row' | 'column' | 'auto';
/**
* The currently-selected option (bindable)
*/
Expand All @@ -30,6 +37,7 @@
options,
size = 'default',
hideLabel = false,
layout = 'auto',
value = $bindable(null),
onchange
}: SwitcherProps = $props();
Expand All @@ -46,7 +54,12 @@
<div class="legend" class:hidden={hideLabel}>
<FormLabel as="legend">{label}</FormLabel>
</div>
<ul>
<ul
class:layout-row={layout === 'row'}
class:layout-column={layout === 'column'}
class:layout-auto={layout === 'auto'}
role="list"
>
{#each options as o (o)}
<li class:is-selected={o === value}>
<label for={optionToID(o)}>
Expand Down Expand Up @@ -84,23 +97,32 @@
width: 100%;
display: flex;
flex-direction: column;
overflow: hidden;
overflow-x: auto;
padding: 0;
margin: 0;
border: 1px solid var(--color-textSecondary);
border-top: 1px solid var(--color-textSecondary);
border-left: 1px solid var(--color-textSecondary);
color: var(--color-textPrimary);
background: var(--color-surfaceFill);
border-radius: var(--br-small);

@media (min-width: base.$bp-s) {
flex-flow: row;
}
&.layout-row {
flex-flow: row;
}
&.layout-column {
flex-direction: column;
}
}
li {
display: contents;
&:last-child label {
border-right: 0;
border-bottom: 0;
border-bottom-right-radius: var(--br-small);
}
&:first-child label {
border-top-left-radius: var(--br-small);
}
}
input {
Expand All @@ -117,34 +139,41 @@
line-height: 1;
white-space: nowrap;
padding: 0 1em;
cursor: pointer;
margin: 0;
align-items: center;
cursor: pointer;
display: flex;
justify-content: center;
align-items: center;
color: currentColor;
position: relative;
transition: var(--fast);
text-underline-offset: 0.1em;
border-right: 1px solid var(--color-textSecondary);
height: 2.25em;
border-right: 1px solid var(--color-textSecondary);
border-bottom: 1px solid var(--color-textSecondary);
flex-grow: 1;

@media (min-width: base.$bp-s) {
justify-content: center;
padding: 0 1em;
flex-basis: 0;
flex-grow: 1;
border-bottom: 0;
}
@media (min-width: base.$bp-s) {
height: 2.5em;
.layout-row & {
flex-basis: 0;
}
&:hover,
&:focus-visible {
text-decoration: underline;
text-decoration-color: var(--color-textSecondary);
.layout-column & {
flex-basis: auto;
}
.is-selected & {
background: var(--color-surfaceHover);
font-weight: 700;

@media (prefers-color-scheme: dark) {
background: var(--gray-dark-2);
}
}
&:hover,
&:focus-visible {
text-decoration: underline;
text-decoration-color: var(--color-textSecondary);
}
}
</style>