@noxlovette/material 0.2.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/claude-skill/material-design/SKILL.md +3 -1
  2. package/claude-skill/material-design/references/component-patterns.md +15 -0
  3. package/dist/components/badge/Badge.stories.svelte +58 -0
  4. package/dist/components/badge/Badge.stories.svelte.d.ts +19 -0
  5. package/dist/components/buttons/Button.stories.svelte +50 -0
  6. package/dist/components/buttons/Button.stories.svelte.d.ts +19 -0
  7. package/dist/components/buttons/ButtonIcon.stories.svelte +74 -0
  8. package/dist/components/buttons/ButtonIcon.stories.svelte.d.ts +19 -0
  9. package/dist/components/buttons/FAB.stories.svelte +59 -0
  10. package/dist/components/buttons/FAB.stories.svelte.d.ts +19 -0
  11. package/dist/components/buttons/Toggle.stories.svelte +46 -0
  12. package/dist/components/buttons/Toggle.stories.svelte.d.ts +19 -0
  13. package/dist/components/cards/Card.stories.svelte +72 -0
  14. package/dist/components/cards/Card.stories.svelte.d.ts +19 -0
  15. package/dist/components/containers/bottom-sheet/BottomSheet.stories.svelte +35 -0
  16. package/dist/components/containers/bottom-sheet/BottomSheet.stories.svelte.d.ts +4 -0
  17. package/dist/components/containers/dialogue/Dialogue.stories.svelte +86 -0
  18. package/dist/components/containers/dialogue/Dialogue.stories.svelte.d.ts +4 -0
  19. package/dist/components/containers/menu/Menu.stories.svelte +62 -0
  20. package/dist/components/containers/menu/Menu.stories.svelte.d.ts +19 -0
  21. package/dist/components/containers/panes/SinglePane.stories.svelte +67 -0
  22. package/dist/components/containers/panes/SinglePane.stories.svelte.d.ts +19 -0
  23. package/dist/components/containers/panes/SplitPane.stories.svelte +124 -0
  24. package/dist/components/containers/panes/SplitPane.stories.svelte.d.ts +19 -0
  25. package/dist/components/containers/panes/SplitPane.svelte +25 -21
  26. package/dist/components/containers/panes/SplitPane.svelte.d.ts +4 -1
  27. package/dist/components/containers/panes/SupportingPane.stories.svelte +113 -0
  28. package/dist/components/containers/panes/SupportingPane.stories.svelte.d.ts +19 -0
  29. package/dist/components/containers/panes/theme.d.ts +18 -0
  30. package/dist/components/containers/panes/theme.js +11 -0
  31. package/dist/components/containers/panes/types.d.ts +17 -1
  32. package/dist/components/containers/popover/Popover.stories.svelte +65 -0
  33. package/dist/components/containers/popover/Popover.stories.svelte.d.ts +19 -0
  34. package/dist/components/containers/side-sheet/SideSheet.stories.svelte +54 -0
  35. package/dist/components/containers/side-sheet/SideSheet.stories.svelte.d.ts +4 -0
  36. package/dist/components/forms/checkbox/Checkbox.stories.svelte +42 -0
  37. package/dist/components/forms/checkbox/Checkbox.stories.svelte.d.ts +19 -0
  38. package/dist/components/forms/search/Search.stories.svelte +41 -0
  39. package/dist/components/forms/search/Search.stories.svelte.d.ts +19 -0
  40. package/dist/components/forms/select/Select.stories.svelte +89 -0
  41. package/dist/components/forms/select/Select.stories.svelte.d.ts +19 -0
  42. package/dist/components/forms/select/Select.svelte +1 -1
  43. package/dist/components/forms/slider/Slider.stories.svelte +76 -0
  44. package/dist/components/forms/slider/Slider.stories.svelte.d.ts +19 -0
  45. package/dist/components/forms/switch/Switch.stories.svelte +47 -0
  46. package/dist/components/forms/switch/Switch.stories.svelte.d.ts +19 -0
  47. package/dist/components/forms/textfield/Textfield.stories.svelte +74 -0
  48. package/dist/components/forms/textfield/Textfield.stories.svelte.d.ts +19 -0
  49. package/dist/components/misc/Avatar.svelte +2 -2
  50. package/dist/components/misc/types.d.ts +4 -0
  51. package/dist/components/nav/appbar/AppBar.stories.svelte +49 -0
  52. package/dist/components/nav/appbar/AppBar.stories.svelte.d.ts +19 -0
  53. package/dist/components/nav/navbar/Navbar.stories.svelte +33 -0
  54. package/dist/components/nav/navbar/Navbar.stories.svelte.d.ts +19 -0
  55. package/dist/components/nav/rail/Rail.stories.svelte +73 -0
  56. package/dist/components/nav/rail/Rail.stories.svelte.d.ts +19 -0
  57. package/dist/components/nav/tabs/Tabs.stories.svelte +55 -0
  58. package/dist/components/nav/tabs/Tabs.stories.svelte.d.ts +18 -0
  59. package/dist/components/pill/Pill.stories.svelte +48 -0
  60. package/dist/components/pill/Pill.stories.svelte.d.ts +19 -0
  61. package/dist/components/progress/Progress.stories.svelte +64 -0
  62. package/dist/components/progress/Progress.stories.svelte.d.ts +18 -0
  63. package/dist/components/snackbar/Snackbar.stories.svelte +76 -0
  64. package/dist/components/snackbar/Snackbar.stories.svelte.d.ts +4 -0
  65. package/dist/components/typography/body/Body.stories.svelte +30 -0
  66. package/dist/components/typography/body/Body.stories.svelte.d.ts +19 -0
  67. package/dist/components/typography/display/Display.stories.svelte +30 -0
  68. package/dist/components/typography/display/Display.stories.svelte.d.ts +19 -0
  69. package/dist/components/typography/headline/Headline.stories.svelte +30 -0
  70. package/dist/components/typography/headline/Headline.stories.svelte.d.ts +19 -0
  71. package/dist/components/typography/label/Label.stories.svelte +30 -0
  72. package/dist/components/typography/label/Label.stories.svelte.d.ts +19 -0
  73. package/dist/components/typography/title/Title.stories.svelte +30 -0
  74. package/dist/components/typography/title/Title.stories.svelte.d.ts +19 -0
  75. package/package.json +12 -4
@@ -16,7 +16,9 @@ This repo is a single, already-opinionated M3 component library, not a blank can
16
16
  - Creating or editing a component under `src/lib/components/`
17
17
  - Deciding which variant (filled/tonal/outlined/text/elevated) or color role (primary/secondary/tertiary/error) fits a given action or emphasis level
18
18
  - Adding a transition, page transition, or list/expand animation
19
- - Building a showcase route or docs page for a component
19
+ - Building a showcase route or docs page for a component — these MUST be built from
20
+ `@noxlovette/material` components (`SinglePane`/`SplitPane`/`SupportingPane` for layout), never
21
+ hand-rolled flex/aside divs; see `references/component-patterns.md` for the pane decision table
20
22
  - Reviewing UI for M3 correctness (contrast, touch targets, focus, motion)
21
23
 
22
24
  **Skip this skill** for changes with no visual surface (pure logic, data layer, config), and for Cypress test work (use the `cypress-*` skills instead).
@@ -32,6 +32,21 @@ Only fall back to `bare` (no color/background at all) when the component supplie
32
32
  - **Focus ring** — the `md-sys-state-focus-indicator` utility, not a custom `:focus` style.
33
33
  - **Disabled state** — `.md-component-button-base`'s disabled handling (via `disabled:`/`aria-disabled`/`data-disabled` selectors in `component.css`), not a manually-toggled opacity class.
34
34
 
35
+ ## Laying out a showcase or docs page (`src/routes/**`)
36
+
37
+ Routes are not a blank canvas either — every page-level layout shape already has a `containers/panes`
38
+ component. Reach for these instead of a hand-rolled `flex`/`aside`/`sticky` div, and if none fits,
39
+ that's a sign the pattern belongs in the library, not in a one-off route file:
40
+
41
+ | Shape you need | Component | Notes |
42
+ | --------------------------------------------------------------------------------------------------- | ------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
43
+ | Centered/full-width single column | `SinglePane` | `centered` variant for max-width, `padding`/`gap` for spacing |
44
+ | User-resizable two-column split | `SplitPane` (`resizable` default) | Drag handle + `localStorage` persistence |
45
+ | Static, non-draggable sidebar fixed to the true viewport edge | `SplitPane` `anchor="viewport" resizable={false}` | Only correct if this is the outermost positioned element (nothing else is already offsetting content) |
46
+ | Static sidebar absolutely positioned in a bounded/contained box | `SplitPane` `anchor="parent" resizable={false}` | Does not stay visible while the page scrolls — for embedded demos, not full-page nav |
47
+ | Static sidebar nested inside other already-offset content, that should stay visible while scrolling | `SplitPane` `anchor="sticky" resizable={false}` | e.g. the docs secondary component-list nav, nested inside the root layout's Rail-offset column |
48
+ | Main content + fixed-width side panel (TOC, filters, details) | `SupportingPane` `anchor="parent"` | The M3 [supporting-pane](https://m3.material.io/foundations/layout/canonical-layouts/supporting-pane) pattern |
49
+
35
50
  ## Before exporting a new component
36
51
 
37
52
  Follow CLAUDE.md's "Adding a New Component" steps as the mechanical checklist (create `.svelte` + `types.ts`, define `theme.ts` with `tv()`, export from the category `index.ts`, run `bun scripts/generate-components-index.ts`, add a showcase route and a docs page) — this skill governs the _design_ decisions (which variant/color/motion) that should be made before or while writing that `theme.ts`, not the export mechanics themselves.
@@ -0,0 +1,58 @@
1
+ <!--
2
+ Badge renders `absolute` (top/right offsets baked into its `size` variant), so it always needs a
3
+ `position: relative` ancestor to anchor against — it's an overlay primitive, not a
4
+ standalone/inline element. NavbarItem/RailItem already wire this up internally via their
5
+ `badge` prop; the stories below reproduce that same relative-wrapper pattern by hand so Badge
6
+ can be previewed in isolation.
7
+ -->
8
+ <script module lang="ts">
9
+ import { defineMeta } from '@storybook/addon-svelte-csf';
10
+ import Badge from './Badge.svelte';
11
+ import Icon from '../../utils/icon/Icon.svelte';
12
+
13
+ const { Story } = defineMeta({
14
+ title: 'Feedback/Badge',
15
+ component: Badge,
16
+ argTypes: {
17
+ size: {
18
+ control: 'select',
19
+ options: ['sm', 'lg']
20
+ },
21
+ number: { control: 'number' }
22
+ },
23
+ args: {
24
+ size: 'lg',
25
+ number: 5
26
+ }
27
+ });
28
+ </script>
29
+
30
+ <Story name="Playground">
31
+ {#snippet template(args)}
32
+ <div class="relative inline-flex size-10 items-center justify-center">
33
+ <Icon name="mail" />
34
+ <Badge size={args.size} number={args.number} />
35
+ </div>
36
+ {/snippet}
37
+ </Story>
38
+
39
+ <Story name="Dot (Small)" asChild>
40
+ <div class="relative inline-flex size-10 items-center justify-center">
41
+ <Icon name="notifications" />
42
+ <Badge size="sm" />
43
+ </div>
44
+ </Story>
45
+
46
+ <Story name="Numbered (Large)" asChild>
47
+ <div class="relative inline-flex size-10 items-center justify-center">
48
+ <Icon name="mail" />
49
+ <Badge size="lg" number={7} />
50
+ </div>
51
+ </Story>
52
+
53
+ <Story name="Overflow (99+)" asChild>
54
+ <div class="relative inline-flex size-10 items-center justify-center">
55
+ <Icon name="mail" />
56
+ <Badge size="lg" number={128} />
57
+ </div>
58
+ </Story>
@@ -0,0 +1,19 @@
1
+ import Badge from './Badge.svelte';
2
+ interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
3
+ new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
4
+ $$bindings?: Bindings;
5
+ } & Exports;
6
+ (internal: unknown, props: {
7
+ $$events?: Events;
8
+ $$slots?: Slots;
9
+ }): Exports & {
10
+ $set?: any;
11
+ $on?: any;
12
+ };
13
+ z_$$bindings?: Bindings;
14
+ }
15
+ declare const Badge: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
16
+ [evt: string]: CustomEvent<any>;
17
+ }, {}, {}, string>;
18
+ type Badge = InstanceType<typeof Badge>;
19
+ export default Badge;
@@ -0,0 +1,50 @@
1
+ <script module lang="ts">
2
+ import { defineMeta } from '@storybook/addon-svelte-csf';
3
+ import Button from './Button.svelte';
4
+
5
+ const { Story } = defineMeta({
6
+ title: 'Buttons/Button',
7
+ component: Button,
8
+ argTypes: {
9
+ variant: {
10
+ control: 'select',
11
+ options: ['elevated', 'filled', 'tonal', 'outlined', 'text', 'bare']
12
+ },
13
+ color: {
14
+ control: 'select',
15
+ options: ['default', 'primary', 'secondary', 'tertiary', 'error']
16
+ },
17
+ size: {
18
+ control: 'select',
19
+ options: ['xs', 'sm', 'md', 'lg', 'xl']
20
+ },
21
+ shape: {
22
+ control: 'select',
23
+ options: ['round', 'square']
24
+ },
25
+ disabled: { control: 'boolean' },
26
+ loading: { control: 'boolean' }
27
+ },
28
+ args: {
29
+ variant: 'filled',
30
+ color: 'primary',
31
+ size: 'md',
32
+ shape: 'round',
33
+ disabled: false,
34
+ loading: false
35
+ }
36
+ });
37
+ </script>
38
+
39
+ <Story name="Playground">Label</Story>
40
+
41
+ <Story name="Variants" asChild>
42
+ <div class="flex flex-wrap items-center gap-4 p-6">
43
+ <Button variant="elevated" color="primary">Elevated</Button>
44
+ <Button variant="filled" color="primary">Filled</Button>
45
+ <Button variant="tonal" color="primary">Tonal</Button>
46
+ <Button variant="outlined" color="primary">Outlined</Button>
47
+ <Button variant="text" color="primary">Text</Button>
48
+ <Button variant="bare" color="primary">Bare</Button>
49
+ </div>
50
+ </Story>
@@ -0,0 +1,19 @@
1
+ import Button from './Button.svelte';
2
+ interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
3
+ new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
4
+ $$bindings?: Bindings;
5
+ } & Exports;
6
+ (internal: unknown, props: {
7
+ $$events?: Events;
8
+ $$slots?: Slots;
9
+ }): Exports & {
10
+ $set?: any;
11
+ $on?: any;
12
+ };
13
+ z_$$bindings?: Bindings;
14
+ }
15
+ declare const Button: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
16
+ [evt: string]: CustomEvent<any>;
17
+ }, {}, {}, string>;
18
+ type Button = InstanceType<typeof Button>;
19
+ export default Button;
@@ -0,0 +1,74 @@
1
+ <script module lang="ts">
2
+ import { defineMeta } from '@storybook/addon-svelte-csf';
3
+ import ButtonIcon from './ButtonIcon.svelte';
4
+
5
+ const { Story } = defineMeta({
6
+ title: 'Buttons/Button Icon',
7
+ component: ButtonIcon,
8
+ argTypes: {
9
+ variant: {
10
+ control: 'select',
11
+ options: ['elevated', 'filled', 'tonal', 'outlined', 'text', 'bare']
12
+ },
13
+ color: {
14
+ control: 'select',
15
+ options: ['default', 'primary', 'secondary', 'tertiary', 'error']
16
+ },
17
+ size: {
18
+ control: 'select',
19
+ options: ['xs', 'sm', 'md', 'lg', 'xl']
20
+ },
21
+ width: {
22
+ control: 'select',
23
+ options: ['default', 'narrow', 'wide']
24
+ },
25
+ shape: {
26
+ control: 'select',
27
+ options: ['round', 'square']
28
+ },
29
+ variation: {
30
+ control: 'select',
31
+ options: ['default', 'toggle']
32
+ },
33
+ disabled: { control: 'boolean' },
34
+ loading: { control: 'boolean' },
35
+ tooltipContent: { control: 'text' }
36
+ },
37
+ args: {
38
+ variant: 'text',
39
+ color: 'primary',
40
+ size: 'md',
41
+ width: 'default',
42
+ shape: 'round',
43
+ variation: 'default',
44
+ disabled: false,
45
+ loading: false,
46
+ iconProps: { name: 'favorite' },
47
+ tooltipContent: 'Favorite'
48
+ }
49
+ });
50
+ </script>
51
+
52
+ <Story name="Playground" />
53
+
54
+ <Story name="Variants" asChild>
55
+ <div class="flex flex-wrap items-center gap-4 p-6">
56
+ <ButtonIcon variant="elevated" color="primary" iconProps={{ name: 'favorite' }} />
57
+ <ButtonIcon variant="filled" color="primary" iconProps={{ name: 'favorite' }} />
58
+ <ButtonIcon variant="tonal" color="primary" iconProps={{ name: 'favorite' }} />
59
+ <ButtonIcon variant="outlined" color="primary" iconProps={{ name: 'favorite' }} />
60
+ <ButtonIcon variant="text" color="primary" iconProps={{ name: 'favorite' }} />
61
+ <ButtonIcon variant="bare" color="primary" iconProps={{ name: 'favorite' }} />
62
+ </div>
63
+ </Story>
64
+
65
+ <Story name="Toggle" asChild>
66
+ <div class="flex flex-wrap items-center gap-4 p-6">
67
+ <ButtonIcon
68
+ variation="toggle"
69
+ variant="tonal"
70
+ iconProps={{ name: 'star' }}
71
+ tooltipContent="Star"
72
+ />
73
+ </div>
74
+ </Story>
@@ -0,0 +1,19 @@
1
+ import ButtonIcon from './ButtonIcon.svelte';
2
+ interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
3
+ new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
4
+ $$bindings?: Bindings;
5
+ } & Exports;
6
+ (internal: unknown, props: {
7
+ $$events?: Events;
8
+ $$slots?: Slots;
9
+ }): Exports & {
10
+ $set?: any;
11
+ $on?: any;
12
+ };
13
+ z_$$bindings?: Bindings;
14
+ }
15
+ declare const ButtonIcon: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
16
+ [evt: string]: CustomEvent<any>;
17
+ }, {}, {}, string>;
18
+ type ButtonIcon = InstanceType<typeof ButtonIcon>;
19
+ export default ButtonIcon;
@@ -0,0 +1,59 @@
1
+ <script module lang="ts">
2
+ import { defineMeta } from '@storybook/addon-svelte-csf';
3
+ import FAB from './FAB.svelte';
4
+ import FABMenuItem from './FABMenuItem.svelte';
5
+
6
+ const { Story } = defineMeta({
7
+ title: 'Buttons/FAB',
8
+ component: FAB,
9
+ argTypes: {
10
+ config: {
11
+ control: 'select',
12
+ options: ['primary', 'secondary', 'tertiary']
13
+ },
14
+ size: {
15
+ control: 'select',
16
+ options: ['small', 'regular', 'large']
17
+ },
18
+ expanded: { control: 'boolean' },
19
+ label: { control: 'text' },
20
+ disabled: { control: 'boolean' },
21
+ loading: { control: 'boolean' }
22
+ },
23
+ args: {
24
+ config: 'primary',
25
+ size: 'regular',
26
+ expanded: false,
27
+ label: 'Compose',
28
+ disabled: false,
29
+ loading: false,
30
+ iconProps: { name: 'edit' }
31
+ }
32
+ });
33
+ </script>
34
+
35
+ <Story name="Playground" />
36
+
37
+ <Story name="Sizes" asChild>
38
+ <div class="flex flex-wrap items-end gap-4 p-6">
39
+ <FAB size="small" config="primary" iconProps={{ name: 'edit' }} />
40
+ <FAB size="regular" config="primary" iconProps={{ name: 'edit' }} />
41
+ <FAB size="large" config="primary" iconProps={{ name: 'edit' }} />
42
+ </div>
43
+ </Story>
44
+
45
+ <Story name="Extended" asChild>
46
+ <div class="flex flex-wrap items-center gap-4 p-6">
47
+ <FAB config="primary" expanded label="Compose" iconProps={{ name: 'edit' }} />
48
+ </div>
49
+ </Story>
50
+
51
+ <Story name="With Menu" asChild>
52
+ <div class="relative flex h-40 items-end gap-4 p-6">
53
+ <FAB config="primary" withMenu iconProps={{ name: 'add' }}>
54
+ <FABMenuItem variant="primary" iconProps={{ name: 'draw' }}>Draw</FABMenuItem>
55
+ <FABMenuItem variant="secondary" iconProps={{ name: 'image' }}>Insert Image</FABMenuItem>
56
+ <FABMenuItem variant="tertiary" iconProps={{ name: 'mic' }}>Record</FABMenuItem>
57
+ </FAB>
58
+ </div>
59
+ </Story>
@@ -0,0 +1,19 @@
1
+ import FAB from './FAB.svelte';
2
+ interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
3
+ new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
4
+ $$bindings?: Bindings;
5
+ } & Exports;
6
+ (internal: unknown, props: {
7
+ $$events?: Events;
8
+ $$slots?: Slots;
9
+ }): Exports & {
10
+ $set?: any;
11
+ $on?: any;
12
+ };
13
+ z_$$bindings?: Bindings;
14
+ }
15
+ declare const FAB: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
16
+ [evt: string]: CustomEvent<any>;
17
+ }, {}, {}, string>;
18
+ type FAB = InstanceType<typeof FAB>;
19
+ export default FAB;
@@ -0,0 +1,46 @@
1
+ <script module lang="ts">
2
+ import { defineMeta } from '@storybook/addon-svelte-csf';
3
+ import Toggle from './Toggle.svelte';
4
+
5
+ const { Story } = defineMeta({
6
+ title: 'Buttons/Toggle',
7
+ component: Toggle,
8
+ argTypes: {
9
+ size: {
10
+ control: 'select',
11
+ options: ['xs', 'sm', 'md', 'lg', 'xl']
12
+ },
13
+ shape: {
14
+ control: 'select',
15
+ options: ['round', 'square']
16
+ },
17
+ pressed: { control: 'boolean' },
18
+ disabled: { control: 'boolean' },
19
+ loading: { control: 'boolean' }
20
+ },
21
+ args: {
22
+ size: 'md',
23
+ shape: 'round',
24
+ pressed: false,
25
+ disabled: false,
26
+ loading: false
27
+ }
28
+ });
29
+ </script>
30
+
31
+ <Story name="Playground">Toggle</Story>
32
+
33
+ <Story name="With Icon" asChild>
34
+ <div class="flex flex-wrap items-center gap-4 p-6">
35
+ <Toggle iconProps={{ name: 'format_bold' }}>Bold</Toggle>
36
+ <Toggle iconProps={{ name: 'format_italic' }} pressed>Italic</Toggle>
37
+ </div>
38
+ </Story>
39
+
40
+ <Story name="States" asChild>
41
+ <div class="flex flex-wrap items-center gap-4 p-6">
42
+ <Toggle>Unpressed</Toggle>
43
+ <Toggle pressed>Pressed</Toggle>
44
+ <Toggle disabled>Disabled</Toggle>
45
+ </div>
46
+ </Story>
@@ -0,0 +1,19 @@
1
+ import Toggle from './Toggle.svelte';
2
+ interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
3
+ new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
4
+ $$bindings?: Bindings;
5
+ } & Exports;
6
+ (internal: unknown, props: {
7
+ $$events?: Events;
8
+ $$slots?: Slots;
9
+ }): Exports & {
10
+ $set?: any;
11
+ $on?: any;
12
+ };
13
+ z_$$bindings?: Bindings;
14
+ }
15
+ declare const Toggle: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
16
+ [evt: string]: CustomEvent<any>;
17
+ }, {}, {}, string>;
18
+ type Toggle = InstanceType<typeof Toggle>;
19
+ export default Toggle;
@@ -0,0 +1,72 @@
1
+ <script module lang="ts">
2
+ import { defineMeta } from '@storybook/addon-svelte-csf';
3
+ import Card from './Card.svelte';
4
+
5
+ const { Story } = defineMeta({
6
+ title: 'Cards/Card',
7
+ component: Card,
8
+ argTypes: {
9
+ type: {
10
+ control: 'select',
11
+ options: ['elevated', 'filled', 'outlined']
12
+ },
13
+ padding: {
14
+ control: 'select',
15
+ options: ['none', 'sm', 'md', 'lg']
16
+ },
17
+ hoverable: { control: 'boolean' },
18
+ href: { control: 'text' }
19
+ },
20
+ args: {
21
+ type: 'filled',
22
+ padding: 'md',
23
+ hoverable: false,
24
+ href: undefined
25
+ }
26
+ });
27
+ </script>
28
+
29
+ <Story name="Playground">
30
+ {#snippet template(args)}
31
+ <Card
32
+ type={args.type}
33
+ padding={args.padding}
34
+ hoverable={args.hoverable}
35
+ href={args.href}
36
+ class="max-w-sm"
37
+ >
38
+ <p class="md-sys-typescale-title-medium mb-1">Card title</p>
39
+ <p class="text-md-sys-color-on-surface-variant text-sm">
40
+ Supporting text describing the card's content.
41
+ </p>
42
+ </Card>
43
+ {/snippet}
44
+ </Story>
45
+
46
+ <Story name="Types" asChild>
47
+ <div class="flex flex-wrap gap-4 p-6">
48
+ <Card type="elevated" class="w-56">
49
+ <p class="md-sys-typescale-title-medium mb-1">Elevated</p>
50
+ <p class="text-md-sys-color-on-surface-variant text-sm">Shadow separates from background.</p>
51
+ </Card>
52
+ <Card type="filled" class="w-56">
53
+ <p class="md-sys-typescale-title-medium mb-1">Filled</p>
54
+ <p class="text-md-sys-color-on-surface-variant text-sm">
55
+ Solid background, subtle separation.
56
+ </p>
57
+ </Card>
58
+ <Card type="outlined" class="w-56">
59
+ <p class="md-sys-typescale-title-medium mb-1">Outlined</p>
60
+ <p class="text-md-sys-color-on-surface-variant text-sm">Boundary line, least separation.</p>
61
+ </Card>
62
+ </div>
63
+ </Story>
64
+
65
+ <Story name="Hoverable Link" asChild>
66
+ <Card href="#" class="max-w-sm">
67
+ <p class="md-sys-typescale-title-medium mb-1">Clickable card</p>
68
+ <p class="text-md-sys-color-on-surface-variant text-sm">
69
+ Rendered as an anchor when <code>href</code> is provided; hoverable defaults to true.
70
+ </p>
71
+ </Card>
72
+ </Story>
@@ -0,0 +1,19 @@
1
+ import Card from './Card.svelte';
2
+ interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
3
+ new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
4
+ $$bindings?: Bindings;
5
+ } & Exports;
6
+ (internal: unknown, props: {
7
+ $$events?: Events;
8
+ $$slots?: Slots;
9
+ }): Exports & {
10
+ $set?: any;
11
+ $on?: any;
12
+ };
13
+ z_$$bindings?: Bindings;
14
+ }
15
+ declare const Card: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
16
+ [evt: string]: CustomEvent<any>;
17
+ }, {}, {}, string>;
18
+ type Card = InstanceType<typeof Card>;
19
+ export default Card;
@@ -0,0 +1,35 @@
1
+ <!--
2
+ BottomSheet has no `open` prop of its own — mounting it calls the native <dialog>'s
3
+ showModal() immediately, so visibility is controlled by conditionally rendering the component
4
+ ({#if open}<BottomSheet ...>{/if}). `close` is a required callback the sheet invokes on Esc,
5
+ backdrop click, or dragging the handle down below a minimum height ('esc' | 'click' | 'low') —
6
+ the consumer is expected to flip its own `open` flag to false in response.
7
+ -->
8
+ <script module lang="ts">
9
+ import { defineMeta } from '@storybook/addon-svelte-csf';
10
+ import BottomSheet from './BottomSheet.svelte';
11
+ import Button from '../../buttons/Button.svelte';
12
+ import MenuItem from '../menu-item/MenuItem.svelte';
13
+
14
+ const { Story } = defineMeta({
15
+ title: 'Containers/Bottom Sheet',
16
+ component: BottomSheet
17
+ });
18
+ </script>
19
+
20
+ <script lang="ts">
21
+ let playgroundOpen = $state(false);
22
+ </script>
23
+
24
+ <Story name="Playground" asChild>
25
+ <div class="p-6">
26
+ <Button onclick={() => (playgroundOpen = true)}>Open bottom sheet</Button>
27
+ {#if playgroundOpen}
28
+ <BottomSheet close={() => (playgroundOpen = false)}>
29
+ <MenuItem iconProps={{ name: 'share' }}>Share</MenuItem>
30
+ <MenuItem iconProps={{ name: 'link' }}>Copy link</MenuItem>
31
+ <MenuItem iconProps={{ name: 'download' }}>Download</MenuItem>
32
+ </BottomSheet>
33
+ {/if}
34
+ </div>
35
+ </Story>
@@ -0,0 +1,4 @@
1
+ import BottomSheet from './BottomSheet.svelte';
2
+ declare const BottomSheet: import("svelte").Component<Record<string, never>, {}, "">;
3
+ type BottomSheet = ReturnType<typeof BottomSheet>;
4
+ export default BottomSheet;
@@ -0,0 +1,86 @@
1
+ <!--
2
+ NOTE: The exported component is `Dialogue` (British spelling) even though the M3 concept and
3
+ this docs nav entry are both called "Dialog" — see docs/dialog for the full explanation.
4
+
5
+ Dialogue wraps its content in a <form> (bits-ui Dialog.Content) driven by a required `enhance`
6
+ action, mirroring SvelteKit/superforms usage. Since Storybook has no real form action to POST
7
+ to, the stories below pass a no-op `enhance` stub that just prevents the native submit —
8
+ consumers in a real SvelteKit app would pass superforms' `enhance` instead.
9
+
10
+ Dialogue's `open` is bindable but there is no args-driven "Controls" story for it — clicking a
11
+ trigger button is the natural way to open a modal, so each story wires up its own local state
12
+ in this file's instance script (shared across the module, one flag per story).
13
+ -->
14
+ <script module lang="ts">
15
+ import { defineMeta } from '@storybook/addon-svelte-csf';
16
+ import Dialogue from './Dialogue.svelte';
17
+
18
+ const { Story } = defineMeta({
19
+ title: 'Containers/Dialogue',
20
+ component: Dialogue
21
+ });
22
+
23
+ // Storybook has no SvelteKit form action to submit to — stub out `enhance` so submitting the
24
+ // confirm button doesn't attempt a real network POST.
25
+ function noopEnhance(formEl: HTMLFormElement) {
26
+ const onSubmit = (e: SubmitEvent) => e.preventDefault();
27
+ formEl.addEventListener('submit', onSubmit);
28
+ return { destroy: () => formEl.removeEventListener('submit', onSubmit) };
29
+ }
30
+ </script>
31
+
32
+ <script lang="ts">
33
+ import Button from '../../buttons/Button.svelte';
34
+
35
+ let playgroundOpen = $state(false);
36
+ let extraContentOpen = $state(false);
37
+ let loadingOpen = $state(false);
38
+ </script>
39
+
40
+ <Story name="Playground" asChild>
41
+ <div class="p-6">
42
+ <Button onclick={() => (playgroundOpen = true)}>Open dialog</Button>
43
+ <Dialogue
44
+ bind:open={playgroundOpen}
45
+ enhance={noopEnhance}
46
+ headline="Delete this file?"
47
+ supportingText="This action cannot be undone. The file will be permanently removed."
48
+ confirmText="Delete"
49
+ cancelText="Cancel"
50
+ />
51
+ </div>
52
+ </Story>
53
+
54
+ <Story name="With Extra Content" asChild>
55
+ <div class="p-6">
56
+ <Button onclick={() => (extraContentOpen = true)}>Open dialog with content</Button>
57
+ <Dialogue
58
+ bind:open={extraContentOpen}
59
+ enhance={noopEnhance}
60
+ headline="Rename project"
61
+ confirmText="Save"
62
+ cancelText="Cancel"
63
+ >
64
+ <input
65
+ type="text"
66
+ value="Untitled project"
67
+ class="border-md-sys-color-outline-variant bg-md-sys-color-surface w-full rounded-lg border px-3 py-2"
68
+ />
69
+ </Dialogue>
70
+ </div>
71
+ </Story>
72
+
73
+ <Story name="Loading Confirm" asChild>
74
+ <div class="p-6">
75
+ <Button onclick={() => (loadingOpen = true)}>Open dialog</Button>
76
+ <Dialogue
77
+ bind:open={loadingOpen}
78
+ enhance={noopEnhance}
79
+ headline="Processing"
80
+ supportingText="The confirm action is in a loading state."
81
+ confirmText="Confirm"
82
+ cancelText="Cancel"
83
+ loading
84
+ />
85
+ </div>
86
+ </Story>
@@ -0,0 +1,4 @@
1
+ import Dialogue from './Dialogue.svelte';
2
+ declare const Dialogue: import("svelte").Component<Record<string, never>, {}, "">;
3
+ type Dialogue = ReturnType<typeof Dialogue>;
4
+ export default Dialogue;