-
Notifications
You must be signed in to change notification settings - Fork 71
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add reusable PillContainer component to Holocene * Add count to Pill * Add focus styles
- Loading branch information
1 parent
7d20a6a
commit 8edb57d
Showing
6 changed files
with
165 additions
and
46 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
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
This file was deleted.
Oops, something went wrong.
36 changes: 36 additions & 0 deletions
36
src/lib/holocene/pill-container/pill-container.stories.svelte
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,36 @@ | ||
<script lang="ts" context="module"> | ||
import type { Meta } from '@storybook/svelte'; | ||
import PillContainer from './pill-container.svelte'; | ||
import Pill from './pill.svelte'; | ||
export const meta = { | ||
title: 'Pill Container', | ||
component: PillContainer, | ||
subcomponents: { Pill }, | ||
argTypes: { | ||
PILLS: { | ||
name: 'Pill Container', | ||
table: { | ||
disable: true, | ||
}, | ||
}, | ||
}, | ||
} satisfies Meta<Omit<PillContainer, 'PILLS'>>; | ||
</script> | ||
|
||
<script lang="ts"> | ||
import { Story, Template } from '@storybook/addon-svelte-csf'; | ||
</script> | ||
|
||
<Template let:args> | ||
<PillContainer {...args}> | ||
<Pill id="A">Pill A</Pill> | ||
<Pill id="B">Pill B</Pill> | ||
<Pill id="C">Pill C</Pill> | ||
</PillContainer> | ||
</Template> | ||
|
||
<Story name="Light" /> | ||
|
||
<Story name="Dark" parameters={{ themes: { themeOverride: 'dark' } }} /> |
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 @@ | ||
<script lang="ts" context="module"> | ||
export type PillsContext = { | ||
activePill: Writable<string>; | ||
registerPill: (pill: string) => void; | ||
selectPill: (pill: string) => void; | ||
}; | ||
export const PILLS = {}; | ||
</script> | ||
|
||
<script lang="ts"> | ||
import type { HTMLAttributes } from 'svelte/elements'; | ||
import { type Writable, writable } from 'svelte/store'; | ||
import { onDestroy, setContext } from 'svelte'; | ||
import { twMerge as merge } from 'tailwind-merge'; | ||
type $$Props = HTMLAttributes<HTMLDivElement>; | ||
let className = ''; | ||
export { className as class }; | ||
const pills: string[] = []; | ||
const activePill = writable<string>(null); | ||
setContext<PillsContext>(PILLS, { | ||
registerPill: (pill: string) => { | ||
pills.push(pill); | ||
activePill.update((current) => current || pill); | ||
onDestroy(() => { | ||
const i = pills.indexOf(pill); | ||
pills.splice(i, 1); | ||
activePill.update((current) => | ||
current === pill ? pills[i] || pills[pills.length - 1] : current, | ||
); | ||
}); | ||
}, | ||
selectPill: (pill: string) => { | ||
activePill.set(pill); | ||
}, | ||
activePill, | ||
}); | ||
</script> | ||
|
||
<div | ||
class={merge( | ||
'surface-subtle inline-flex flex-col items-center justify-start gap-2 rounded-md px-2 py-2 md:flex-row md:rounded-full', | ||
className, | ||
)} | ||
> | ||
<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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
<script lang="ts"> | ||
import type { HTMLButtonAttributes } from 'svelte/elements'; | ||
import { noop } from 'svelte/internal'; | ||
import { getContext } from 'svelte'; | ||
import { twMerge as merge } from 'tailwind-merge'; | ||
import Badge from '$lib/holocene/badge.svelte'; | ||
import type { IconName } from '$lib/holocene/icon'; | ||
import Icon from '$lib/holocene/icon/icon.svelte'; | ||
import { isNull } from '$lib/utilities/is'; | ||
import { PILLS, type PillsContext } from './pill-container.svelte'; | ||
type $$Props = { | ||
id: string; | ||
onClick?: () => void; | ||
disabled?: boolean; | ||
loading?: boolean; | ||
active?: boolean; | ||
icon?: IconName; | ||
count?: number; | ||
class?: string; | ||
} & HTMLButtonAttributes; | ||
export let id: string; | ||
export let onClick: () => void = noop; | ||
export let disabled = false; | ||
export let loading = false; | ||
export let active: boolean = null; | ||
export let icon: IconName = null; | ||
export let count: number = null; | ||
let className = ''; | ||
export { className as class }; | ||
const { activePill, registerPill, selectPill } = | ||
getContext<PillsContext>(PILLS); | ||
registerPill(id); | ||
$: isActive = isNull(active) ? $activePill === id : active; | ||
const handleClick = () => { | ||
if (disabled) return; | ||
selectPill(id); | ||
onClick && onClick(); | ||
}; | ||
</script> | ||
|
||
<button | ||
on:click|stopPropagation={handleClick} | ||
class={merge( | ||
'surface-subtle flex items-center justify-center gap-2 rounded-full px-3 py-1 text-sm', | ||
'focus-visible:outline-none focus-visible:ring-4 focus-visible:ring-primary/70', | ||
isActive && 'bg-interactive text-white', | ||
className, | ||
)} | ||
{disabled} | ||
> | ||
{#if icon} | ||
<span class:animate-spin={loading}> | ||
<Icon name={loading ? 'spinner' : icon} /> | ||
</span> | ||
{/if} | ||
<slot /> | ||
{#if !isNull(count)} | ||
<Badge type="count">{count}</Badge> | ||
{/if} | ||
</button> |