@sveltekitchen/sveltekitchen 0.0.0-stage → 1.0.1

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 (142) hide show
  1. package/README.md +137 -2
  2. package/dist/components/Accordion.svelte +36 -0
  3. package/dist/components/Accordion.svelte.d.ts +15 -0
  4. package/dist/components/AccordionItem.svelte +73 -0
  5. package/dist/components/AccordionItem.svelte.d.ts +21 -0
  6. package/dist/components/Alert.svelte +23 -0
  7. package/dist/components/Alert.svelte.d.ts +15 -0
  8. package/dist/components/Badge.svelte +16 -0
  9. package/dist/components/Badge.svelte.d.ts +15 -0
  10. package/dist/components/Button.svelte +43 -0
  11. package/dist/components/Button.svelte.d.ts +25 -0
  12. package/dist/components/Calendar.svelte +88 -0
  13. package/dist/components/Calendar.svelte.d.ts +13 -0
  14. package/dist/components/Card.svelte +68 -0
  15. package/dist/components/Card.svelte.d.ts +25 -0
  16. package/dist/components/Chevron.svelte +36 -0
  17. package/dist/components/Chevron.svelte.d.ts +19 -0
  18. package/dist/components/Collapsible.svelte +46 -0
  19. package/dist/components/Collapsible.svelte.d.ts +19 -0
  20. package/dist/components/ConfirmDialog.svelte +70 -0
  21. package/dist/components/ConfirmDialog.svelte.d.ts +27 -0
  22. package/dist/components/DatePicker.svelte +60 -0
  23. package/dist/components/DatePicker.svelte.d.ts +17 -0
  24. package/dist/components/Divider.svelte +25 -0
  25. package/dist/components/Divider.svelte.d.ts +17 -0
  26. package/dist/components/Dropdown.svelte +100 -0
  27. package/dist/components/Dropdown.svelte.d.ts +21 -0
  28. package/dist/components/Form/Checkbox.svelte +37 -0
  29. package/dist/components/Form/Checkbox.svelte.d.ts +19 -0
  30. package/dist/components/Form/Field.svelte +28 -0
  31. package/dist/components/Form/Field.svelte.d.ts +21 -0
  32. package/dist/components/Form/Input.svelte +56 -0
  33. package/dist/components/Form/Input.svelte.d.ts +29 -0
  34. package/dist/components/Form/MaskedInput.svelte +152 -0
  35. package/dist/components/Form/MaskedInput.svelte.d.ts +25 -0
  36. package/dist/components/Form/Radio.svelte +28 -0
  37. package/dist/components/Form/Radio.svelte.d.ts +19 -0
  38. package/dist/components/Form/RadioGroup.svelte +28 -0
  39. package/dist/components/Form/RadioGroup.svelte.d.ts +19 -0
  40. package/dist/components/Form/Select.svelte +20 -0
  41. package/dist/components/Form/Select.svelte.d.ts +19 -0
  42. package/dist/components/Form/Textarea.svelte +30 -0
  43. package/dist/components/Form/Textarea.svelte.d.ts +25 -0
  44. package/dist/components/Form/Toggle.svelte +21 -0
  45. package/dist/components/Form/Toggle.svelte.d.ts +17 -0
  46. package/dist/components/Modal.svelte +77 -0
  47. package/dist/components/Modal.svelte.d.ts +27 -0
  48. package/dist/components/Pagination.svelte +77 -0
  49. package/dist/components/Pagination.svelte.d.ts +17 -0
  50. package/dist/components/Progress.svelte +34 -0
  51. package/dist/components/Progress.svelte.d.ts +21 -0
  52. package/dist/components/Spinner.svelte +24 -0
  53. package/dist/components/Spinner.svelte.d.ts +13 -0
  54. package/dist/components/Table.svelte +100 -0
  55. package/dist/components/Table.svelte.d.ts +21 -0
  56. package/dist/components/ThemeToggle.svelte +22 -0
  57. package/dist/components/ThemeToggle.svelte.d.ts +11 -0
  58. package/dist/components/Tooltip.svelte +45 -0
  59. package/dist/components/Tooltip.svelte.d.ts +15 -0
  60. package/dist/css/base/root.css +103 -0
  61. package/dist/css/base.css +47 -0
  62. package/dist/css/components/accordion.css +151 -0
  63. package/dist/css/components/alert.css +56 -0
  64. package/dist/css/components/badge.css +56 -0
  65. package/dist/css/components/button.css +171 -0
  66. package/dist/css/components/calendar.css +105 -0
  67. package/dist/css/components/card.css +128 -0
  68. package/dist/css/components/checkbox-radio.css +105 -0
  69. package/dist/css/components/collapsible.css +61 -0
  70. package/dist/css/components/divider.css +42 -0
  71. package/dist/css/components/dock-layout.css +111 -0
  72. package/dist/css/components/dropdown.css +68 -0
  73. package/dist/css/components/floating-shell.css +93 -0
  74. package/dist/css/components/form.css +286 -0
  75. package/dist/css/components/login.css +145 -0
  76. package/dist/css/components/modal.css +179 -0
  77. package/dist/css/components/nav.css +190 -0
  78. package/dist/css/components/nestable.css +187 -0
  79. package/dist/css/components/pagination.css +50 -0
  80. package/dist/css/components/progress.css +50 -0
  81. package/dist/css/components/sidebar.css +78 -0
  82. package/dist/css/components/spinner.css +36 -0
  83. package/dist/css/components/table.css +98 -0
  84. package/dist/css/components/tooltip.css +77 -0
  85. package/dist/css/components/topbar-layout.css +108 -0
  86. package/dist/css/icons/icons.css +52 -0
  87. package/dist/css/index.css +20 -0
  88. package/dist/css/layout/container.css +12 -0
  89. package/dist/css/layout/grid.css +40 -0
  90. package/dist/css/layout/shell.css +185 -0
  91. package/dist/css/overlay/default.css +27 -0
  92. package/dist/css/tokens/colors.css +81 -0
  93. package/dist/css/tokens/radius.css +8 -0
  94. package/dist/css/tokens/shadows.css +23 -0
  95. package/dist/css/tokens/spacing.css +30 -0
  96. package/dist/css/tokens/transitions.css +10 -0
  97. package/dist/css/tokens/typography.css +44 -0
  98. package/dist/index.d.ts +43 -0
  99. package/dist/index.js +52 -0
  100. package/dist/layout/NavItem.svelte +84 -0
  101. package/dist/layout/NavItem.svelte.d.ts +25 -0
  102. package/dist/layout/Shell.svelte +7 -0
  103. package/dist/layout/Shell.svelte.d.ts +13 -0
  104. package/dist/layout/SidebarProfile.svelte +31 -0
  105. package/dist/layout/SidebarProfile.svelte.d.ts +19 -0
  106. package/dist/layouts/AppShell.svelte +60 -0
  107. package/dist/layouts/AppShell.svelte.d.ts +21 -0
  108. package/dist/layouts/BarLayout.svelte +60 -0
  109. package/dist/layouts/BarLayout.svelte.d.ts +21 -0
  110. package/dist/layouts/BottomBarLayout.svelte +23 -0
  111. package/dist/layouts/BottomBarLayout.svelte.d.ts +15 -0
  112. package/dist/layouts/DockLayout.svelte +81 -0
  113. package/dist/layouts/DockLayout.svelte.d.ts +15 -0
  114. package/dist/layouts/FloatingDockLayout.svelte +56 -0
  115. package/dist/layouts/FloatingDockLayout.svelte.d.ts +13 -0
  116. package/dist/layouts/FloatingLayout.svelte +80 -0
  117. package/dist/layouts/FloatingLayout.svelte.d.ts +19 -0
  118. package/dist/layouts/FloatingLeftLayout.svelte +59 -0
  119. package/dist/layouts/FloatingLeftLayout.svelte.d.ts +15 -0
  120. package/dist/layouts/FloatingShell.svelte +80 -0
  121. package/dist/layouts/FloatingShell.svelte.d.ts +19 -0
  122. package/dist/layouts/FloatingTopLayout.svelte +68 -0
  123. package/dist/layouts/FloatingTopLayout.svelte.d.ts +15 -0
  124. package/dist/layouts/HybridLayout.svelte +20 -0
  125. package/dist/layouts/HybridLayout.svelte.d.ts +17 -0
  126. package/dist/layouts/IconRailLayout.svelte +75 -0
  127. package/dist/layouts/IconRailLayout.svelte.d.ts +15 -0
  128. package/dist/layouts/LeftBarLayout.svelte +19 -0
  129. package/dist/layouts/LeftBarLayout.svelte.d.ts +15 -0
  130. package/dist/layouts/RightBarLayout.svelte +21 -0
  131. package/dist/layouts/RightBarLayout.svelte.d.ts +15 -0
  132. package/dist/layouts/SideBar.svelte +86 -0
  133. package/dist/layouts/SideBar.svelte.d.ts +17 -0
  134. package/dist/layouts/SidebarLayout.svelte +11 -0
  135. package/dist/layouts/SidebarLayout.svelte.d.ts +15 -0
  136. package/dist/layouts/TopBar.svelte +90 -0
  137. package/dist/layouts/TopBar.svelte.d.ts +21 -0
  138. package/dist/layouts/TopBarLayout.svelte +26 -0
  139. package/dist/layouts/TopBarLayout.svelte.d.ts +15 -0
  140. package/dist/theme/theme.svelte.d.ts +11 -0
  141. package/dist/theme/theme.svelte.js +48 -0
  142. package/package.json +56 -4
package/README.md CHANGED
@@ -1,3 +1,138 @@
1
- # Temporary Holding Version
1
+ # SvelteKitchen
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ A themeable **Svelte 5** component library with a bundled CSS design system, a
4
+ light/dark theme engine, and ready-made application layouts.
5
+
6
+ - **Docs & live examples:** https://sveltekitchen.net
7
+ - **Package:** [`@sveltekitchen/sveltekitchen`](https://www.npmjs.com/package/@sveltekitchen/sveltekitchen)
8
+
9
+ Everything is built on runes (`$props`, `$state`, `$derived`, `$bindable`) and
10
+ plain CSS custom properties — no Tailwind, no Sass, no CSS-in-JS.
11
+
12
+ > **Svelte 5 only.** This is a native Svelte component library — it is not a
13
+ > React, Vue, or web-components package, and there are no plans to port it.
14
+ > The one exception is the stylesheet: the bundled CSS design system is
15
+ > framework-agnostic and can be used on its own in any project.
16
+
17
+ ## Install
18
+
19
+ ```bash
20
+ npm install @sveltekitchen/sveltekitchen
21
+ ```
22
+
23
+ `svelte@^5` is a peer dependency.
24
+
25
+ ## Usage
26
+
27
+ Load the CSS **once**, globally (in your root layout or app entry):
28
+
29
+ ```js
30
+ import '@sveltekitchen/sveltekitchen/css';
31
+ ```
32
+
33
+ Then import components anywhere:
34
+
35
+ ```svelte
36
+ <script>
37
+ import { Button, Card, Field, Input } from '@sveltekitchen/sveltekitchen';
38
+
39
+ let email = $state('');
40
+ </script>
41
+
42
+ <Card title="Welcome" subtitle="Sign in to continue">
43
+ <Field label="Email" required>
44
+ <Input bind:value={email} type="email" iconLeft="mail" />
45
+ </Field>
46
+
47
+ {#snippet footer()}
48
+ <Button variant="primary" full>Continue</Button>
49
+ {/snippet}
50
+ </Card>
51
+ ```
52
+
53
+ ### Theming (light / dark)
54
+
55
+ The package ships a tiny reactive theme store. It respects the OS preference on
56
+ first visit and persists the choice to `localStorage`:
57
+
58
+ ```svelte
59
+ <script>
60
+ import { theme, ThemeToggle } from '@sveltekitchen/sveltekitchen';
61
+ import { onMount } from 'svelte';
62
+
63
+ onMount(() => theme.init());
64
+ </script>
65
+
66
+ <ThemeToggle />
67
+
68
+ <!-- or drive it yourself -->
69
+ <button onclick={() => theme.toggle()}>
70
+ {theme.isDark ? 'Light' : 'Dark'} mode
71
+ </button>
72
+ ```
73
+
74
+ Icons use [Material Symbols Outlined](https://fonts.google.com/icons); the docs
75
+ site loads them (and the Inter font) via a `<link>` in `app.html`.
76
+
77
+ ## What's inside
78
+
79
+ - **~30 UI components** — Button, Card, Modal, ConfirmDialog, Alert, Badge,
80
+ Accordion, Dropdown, Table, Pagination, Progress, Spinner, Tooltip, Divider,
81
+ Collapsible, Calendar, DatePicker, and more.
82
+ - **9 form controls** — Field, Input, Select, Toggle, Checkbox, Radio,
83
+ RadioGroup, Textarea, MaskedInput.
84
+ - **Layout primitives** — `Shell`, `NavItem`, `SidebarProfile` for building an
85
+ app chrome, plus **10 importable app-shell layouts** (top bar, sidebar, icon
86
+ rail, floating dock, and variants).
87
+ - **A bundled CSS design system** — resets, layout utilities, component styles,
88
+ and a full set of design tokens.
89
+
90
+ ## CSS architecture — base + overlay
91
+
92
+ The stylesheet is split into two layers:
93
+
94
+ ```
95
+ css/
96
+ overlay/default.css → CUSTOMIZABLE: every token *value* (colors, type,
97
+ spacing, radius, shadow) for light + dark mode.
98
+ base.css → STRUCTURAL: resets, layout, component styles.
99
+ Consumes tokens via var(); defines none.
100
+ ```
101
+
102
+ `css/index.css` imports the overlay first (so tokens exist), then the base. To
103
+ ship a custom theme you either replace `overlay/default.css`, or load
104
+ `index.css` and then your own `theme.css` after it:
105
+
106
+ ```js
107
+ import '@sveltekitchen/sveltekitchen/css'; // structure + default tokens
108
+ import './my-theme.css'; // overrides token values only
109
+ ```
110
+
111
+ Because structural CSS only ever reads tokens through `var()`, re-skinning the
112
+ whole system is a matter of overriding custom properties — no component changes.
113
+
114
+ ### Package exports
115
+
116
+ | Import | What it is |
117
+ |--------|-----------|
118
+ | `@sveltekitchen/sveltekitchen` | All components + the `theme` store (Svelte). |
119
+ | `@sveltekitchen/sveltekitchen/css` | The full stylesheet (base + default overlay). |
120
+ | `@sveltekitchen/sveltekitchen/css/*` | Individual CSS files, if you want to cherry-pick. |
121
+ | `@sveltekitchen/sveltekitchen/theme` | The theme store on its own. |
122
+
123
+ ## Develop
124
+
125
+ The library is consumed **from source** by the [docs site](https://github.com/sveltekitchen/designsystem),
126
+ which gives you instant hot-reload while iterating. Clone both repos side by
127
+ side and run the docs site — see its README for details.
128
+
129
+ Build the distributable package locally:
130
+
131
+ ```bash
132
+ npm install
133
+ npm run package # svelte-package: src/lib → dist/
134
+ ```
135
+
136
+ ## License
137
+
138
+ MIT
@@ -0,0 +1,36 @@
1
+ <script>
2
+ import { setContext } from 'svelte';
3
+
4
+ let {
5
+ variant = 'default',
6
+ multiple = false,
7
+ children,
8
+ } = $props();
9
+
10
+ const variantClass = {
11
+ default: '',
12
+ separated: 'accordion-separated',
13
+ minimal: 'accordion-minimal',
14
+ flush: 'accordion-flush',
15
+ };
16
+
17
+ let openItems = $state(new Set());
18
+
19
+ setContext('accordion', {
20
+ get openItems() { return openItems; },
21
+ toggle(id) {
22
+ const next = multiple ? new Set(openItems) : new Set();
23
+ if (openItems.has(id)) next.delete(id);
24
+ else next.add(id);
25
+ openItems = next;
26
+ }
27
+ });
28
+
29
+ let classes = $derived(
30
+ ['accordion', variantClass[variant]].filter(Boolean).join(' ')
31
+ );
32
+ </script>
33
+
34
+ <div class={classes}>
35
+ {@render children?.()}
36
+ </div>
@@ -0,0 +1,15 @@
1
+ export default Accordion;
2
+ type Accordion = {
3
+ $on?(type: string, callback: (e: any) => void): () => void;
4
+ $set?(props: Partial<$$ComponentProps>): void;
5
+ };
6
+ declare const Accordion: import("svelte").Component<{
7
+ variant?: string;
8
+ multiple?: boolean;
9
+ children: any;
10
+ }, {}, "">;
11
+ type $$ComponentProps = {
12
+ variant?: string;
13
+ multiple?: boolean;
14
+ children: any;
15
+ };
@@ -0,0 +1,73 @@
1
+ <script>
2
+ import { getContext, onMount } from 'svelte';
3
+
4
+ let {
5
+ title = '',
6
+ subtitle = undefined,
7
+ icon = undefined,
8
+ badge = undefined,
9
+ initialOpen = false,
10
+ children,
11
+ } = $props();
12
+
13
+ const id = Math.random().toString(36).slice(2);
14
+ const ctx = getContext('accordion');
15
+
16
+ // standalone (no accordion context) falls back to local state
17
+ let localOpen = $state(initialOpen);
18
+
19
+ let isOpen = $derived(ctx ? ctx.openItems.has(id) : localOpen);
20
+
21
+ function toggle() {
22
+ if (ctx) ctx.toggle(id);
23
+ else localOpen = !localOpen;
24
+ }
25
+
26
+ // height animation
27
+ let bodyEl = $state(null);
28
+ let bodyInnerEl = $state(null);
29
+
30
+ $effect(() => {
31
+ if (!bodyEl || !bodyInnerEl) return;
32
+ if (isOpen) {
33
+ bodyEl.style.height = bodyInnerEl.scrollHeight + 'px';
34
+ const onend = () => { if (isOpen) bodyEl.style.height = 'auto'; };
35
+ bodyEl.addEventListener('transitionend', onend, { once: true });
36
+ } else {
37
+ if (bodyEl.style.height === 'auto') {
38
+ bodyEl.style.height = bodyInnerEl.scrollHeight + 'px';
39
+ }
40
+ requestAnimationFrame(() => { bodyEl.style.height = '0'; });
41
+ }
42
+ });
43
+
44
+ onMount(() => {
45
+ if (initialOpen && ctx) ctx.toggle(id);
46
+ });
47
+ </script>
48
+
49
+ <div class="accordion-item" class:open={isOpen}>
50
+
51
+ <button class="accordion-trigger" onclick={toggle} aria-expanded={isOpen}>
52
+ <div class="accordion-trigger-content">
53
+ {#if icon}
54
+ <span class="material-symbols-outlined accordion-icon">{icon}</span>
55
+ {/if}
56
+ <div>
57
+ <div class="accordion-title">{title}</div>
58
+ {#if subtitle}<div class="accordion-subtitle">{subtitle}</div>{/if}
59
+ </div>
60
+ </div>
61
+ {#if badge !== undefined}
62
+ <span class="accordion-badge">{badge}</span>
63
+ {/if}
64
+ <span class="material-symbols-outlined accordion-chevron">expand_more</span>
65
+ </button>
66
+
67
+ <div class="accordion-body" style="height:{initialOpen ? 'auto' : '0'}" bind:this={bodyEl}>
68
+ <div class="accordion-body-inner" bind:this={bodyInnerEl}>
69
+ {@render children?.()}
70
+ </div>
71
+ </div>
72
+
73
+ </div>
@@ -0,0 +1,21 @@
1
+ export default AccordionItem;
2
+ type AccordionItem = {
3
+ $on?(type: string, callback: (e: any) => void): () => void;
4
+ $set?(props: Partial<$$ComponentProps>): void;
5
+ };
6
+ declare const AccordionItem: import("svelte").Component<{
7
+ title?: string;
8
+ subtitle?: any;
9
+ icon?: any;
10
+ badge?: any;
11
+ initialOpen?: boolean;
12
+ children: any;
13
+ }, {}, "">;
14
+ type $$ComponentProps = {
15
+ title?: string;
16
+ subtitle?: any;
17
+ icon?: any;
18
+ badge?: any;
19
+ initialOpen?: boolean;
20
+ children: any;
21
+ };
@@ -0,0 +1,23 @@
1
+ <script>
2
+ let {
3
+ variant = 'info',
4
+ title = undefined,
5
+ children,
6
+ ...restProps
7
+ } = $props();
8
+
9
+ const icons = {
10
+ info: 'info',
11
+ success: 'check_circle',
12
+ warning: 'warning',
13
+ error: 'error',
14
+ };
15
+ </script>
16
+
17
+ <div class="alert alert-{variant}" {...restProps}>
18
+ <span class="material-symbols-outlined alert-icon">{icons[variant]}</span>
19
+ <div class="alert-content">
20
+ {#if title}<div class="alert-title">{title}</div>{/if}
21
+ {@render children?.()}
22
+ </div>
23
+ </div>
@@ -0,0 +1,15 @@
1
+ export default Alert;
2
+ type Alert = {
3
+ $on?(type: string, callback: (e: any) => void): () => void;
4
+ $set?(props: Partial<$$ComponentProps>): void;
5
+ };
6
+ declare const Alert: import("svelte").Component<{
7
+ variant?: string;
8
+ title?: any;
9
+ children: any;
10
+ } & Record<string, any>, {}, "">;
11
+ type $$ComponentProps = {
12
+ variant?: string;
13
+ title?: any;
14
+ children: any;
15
+ } & Record<string, any>;
@@ -0,0 +1,16 @@
1
+ <script>
2
+ let {
3
+ variant = 'default',
4
+ dot = false,
5
+ children,
6
+ ...restProps
7
+ } = $props();
8
+
9
+ let classes = $derived(
10
+ ['badge', `badge-${variant}`, dot ? 'badge-dot' : ''].filter(Boolean).join(' ')
11
+ );
12
+ </script>
13
+
14
+ <span class={classes} {...restProps}>
15
+ {@render children?.()}
16
+ </span>
@@ -0,0 +1,15 @@
1
+ export default Badge;
2
+ type Badge = {
3
+ $on?(type: string, callback: (e: any) => void): () => void;
4
+ $set?(props: Partial<$$ComponentProps>): void;
5
+ };
6
+ declare const Badge: import("svelte").Component<{
7
+ variant?: string;
8
+ dot?: boolean;
9
+ children: any;
10
+ } & Record<string, any>, {}, "">;
11
+ type $$ComponentProps = {
12
+ variant?: string;
13
+ dot?: boolean;
14
+ children: any;
15
+ } & Record<string, any>;
@@ -0,0 +1,43 @@
1
+ <script>
2
+ import Spinner from './Spinner.svelte';
3
+
4
+ /**
5
+ * @typedef {'primary'|'secondary'|'ghost'|'danger'|'danger-outline'} Variant
6
+ * @typedef {'sm'|'md'|'lg'} Size
7
+ */
8
+
9
+ let {
10
+ variant = 'primary',
11
+ size = 'md',
12
+ full = false,
13
+ icon = false,
14
+ disabled = false,
15
+ loading = false,
16
+ href = undefined,
17
+ children,
18
+ ...restProps
19
+ } = $props();
20
+
21
+ const sizeClass = { sm: 'btn-sm', md: '', lg: 'btn-lg' };
22
+
23
+ let classes = $derived([
24
+ 'btn',
25
+ `btn-${variant}`,
26
+ sizeClass[size],
27
+ full ? 'btn-full' : '',
28
+ icon ? 'btn-icon' : '',
29
+ loading ? 'btn-loading' : '',
30
+ ].filter(Boolean).join(' '));
31
+ </script>
32
+
33
+ {#if href}
34
+ <a {href} class={classes} aria-busy={loading} {...restProps}>
35
+ {#if loading}<Spinner />{/if}
36
+ {@render children?.()}
37
+ </a>
38
+ {:else}
39
+ <button class={classes} disabled={disabled || loading} aria-busy={loading} {...restProps}>
40
+ {#if loading}<Spinner />{/if}
41
+ {@render children?.()}
42
+ </button>
43
+ {/if}
@@ -0,0 +1,25 @@
1
+ export default Button;
2
+ type Button = {
3
+ $on?(type: string, callback: (e: any) => void): () => void;
4
+ $set?(props: Partial<$$ComponentProps>): void;
5
+ };
6
+ declare const Button: import("svelte").Component<{
7
+ variant?: string;
8
+ size?: string;
9
+ full?: boolean;
10
+ icon?: boolean;
11
+ disabled?: boolean;
12
+ loading?: boolean;
13
+ href?: any;
14
+ children: any;
15
+ } & Record<string, any>, {}, "">;
16
+ type $$ComponentProps = {
17
+ variant?: string;
18
+ size?: string;
19
+ full?: boolean;
20
+ icon?: boolean;
21
+ disabled?: boolean;
22
+ loading?: boolean;
23
+ href?: any;
24
+ children: any;
25
+ } & Record<string, any>;
@@ -0,0 +1,88 @@
1
+ <script>
2
+ // Calendar — an inline month grid. Click a day to select it.
3
+ // Simple by design: no keyboard nav, no min/max, no time — just a date.
4
+ //
5
+ // `value` is a JS Date (or null), bindable.
6
+ let {
7
+ value = $bindable(null),
8
+ onselect,
9
+ ...restProps
10
+ } = $props();
11
+
12
+ const MONTHS = ['January','February','March','April','May','June',
13
+ 'July','August','September','October','November','December'];
14
+ const DOW = ['Su','Mo','Tu','We','Th','Fr','Sa'];
15
+
16
+ // The month currently being viewed (defaults to value's month, or today).
17
+ let view = $state(startOfMonth(value ?? new Date()));
18
+
19
+ function startOfMonth(d) { return new Date(d.getFullYear(), d.getMonth(), 1); }
20
+ function sameDay(a, b) {
21
+ return a && b &&
22
+ a.getFullYear() === b.getFullYear() &&
23
+ a.getMonth() === b.getMonth() &&
24
+ a.getDate() === b.getDate();
25
+ }
26
+
27
+ const today = new Date();
28
+
29
+ let cells = $derived.by(() => {
30
+ const year = view.getFullYear();
31
+ const month = view.getMonth();
32
+ const startDay = new Date(year, month, 1).getDay();
33
+ const daysInMonth = new Date(year, month + 1, 0).getDate();
34
+ const prevDays = new Date(year, month, 0).getDate();
35
+ const out = [];
36
+ for (let i = startDay - 1; i >= 0; i--) {
37
+ out.push({ date: new Date(year, month - 1, prevDays - i), outside: true });
38
+ }
39
+ for (let d = 1; d <= daysInMonth; d++) {
40
+ out.push({ date: new Date(year, month, d), outside: false });
41
+ }
42
+ let next = 1;
43
+ while (out.length < 42) {
44
+ out.push({ date: new Date(year, month + 1, next++), outside: true });
45
+ }
46
+ return out;
47
+ });
48
+
49
+ function prevMonth() { view = new Date(view.getFullYear(), view.getMonth() - 1, 1); }
50
+ function nextMonth() { view = new Date(view.getFullYear(), view.getMonth() + 1, 1); }
51
+
52
+ function pick(date) {
53
+ value = date;
54
+ // if they clicked an outside day, follow to that month
55
+ if (date.getMonth() !== view.getMonth()) view = startOfMonth(date);
56
+ onselect?.(date);
57
+ }
58
+ </script>
59
+
60
+ <div class="calendar" {...restProps}>
61
+ <div class="calendar-header">
62
+ <button type="button" class="calendar-nav" onclick={prevMonth} aria-label="Previous month">
63
+ <span class="material-symbols-outlined">chevron_left</span>
64
+ </button>
65
+ <div class="calendar-title">{MONTHS[view.getMonth()]} {view.getFullYear()}</div>
66
+ <button type="button" class="calendar-nav" onclick={nextMonth} aria-label="Next month">
67
+ <span class="material-symbols-outlined">chevron_right</span>
68
+ </button>
69
+ </div>
70
+
71
+ <div class="calendar-grid">
72
+ {#each DOW as d}
73
+ <div class="calendar-dow">{d}</div>
74
+ {/each}
75
+ {#each cells as cell}
76
+ <button
77
+ type="button"
78
+ class="calendar-day"
79
+ class:outside={cell.outside}
80
+ class:selected={sameDay(cell.date, value)}
81
+ class:today={sameDay(cell.date, today)}
82
+ onclick={() => pick(cell.date)}
83
+ >
84
+ {cell.date.getDate()}
85
+ </button>
86
+ {/each}
87
+ </div>
88
+ </div>
@@ -0,0 +1,13 @@
1
+ export default Calendar;
2
+ type Calendar = {
3
+ $on?(type: string, callback: (e: any) => void): () => void;
4
+ $set?(props: Partial<$$ComponentProps>): void;
5
+ };
6
+ declare const Calendar: import("svelte").Component<{
7
+ value?: any;
8
+ onselect: any;
9
+ } & Record<string, any>, {}, "value">;
10
+ type $$ComponentProps = {
11
+ value?: any;
12
+ onselect: any;
13
+ } & Record<string, any>;
@@ -0,0 +1,68 @@
1
+ <script>
2
+ let {
3
+ variant = 'default',
4
+ padding = 'md',
5
+ title = undefined,
6
+ subtitle = undefined,
7
+ header,
8
+ actions,
9
+ footer,
10
+ children,
11
+ ...restProps
12
+ } = $props();
13
+
14
+ const variantClass = {
15
+ default: '',
16
+ flat: 'card-flat',
17
+ raised: 'card-raised',
18
+ interactive: 'card-interactive',
19
+ selected: 'card-selected',
20
+ subtle: 'card-subtle',
21
+ info: 'card-info',
22
+ success: 'card-success',
23
+ warning: 'card-warning',
24
+ error: 'card-error',
25
+ };
26
+
27
+ const paddingClass = {
28
+ sm: 'card-body-sm',
29
+ md: '',
30
+ lg: 'card-body-lg',
31
+ none: 'card-body-none',
32
+ };
33
+
34
+ let cardClass = $derived(['card', variantClass[variant]].filter(Boolean).join(' '));
35
+ let bodyClass = $derived(['card-body', paddingClass[padding]].filter(Boolean).join(' '));
36
+ </script>
37
+
38
+ <div class={cardClass} {...restProps}>
39
+
40
+ {#if header || title}
41
+ <div class="card-header">
42
+ {#if header}
43
+ {@render header()}
44
+ {:else}
45
+ <div>
46
+ <h3 class="card-title">{title}</h3>
47
+ {#if subtitle}<p class="card-subtitle">{subtitle}</p>{/if}
48
+ </div>
49
+ {/if}
50
+ {#if actions}
51
+ <div class="card-header-actions">
52
+ {@render actions()}
53
+ </div>
54
+ {/if}
55
+ </div>
56
+ {/if}
57
+
58
+ <div class={bodyClass}>
59
+ {@render children?.()}
60
+ </div>
61
+
62
+ {#if footer}
63
+ <div class="card-footer">
64
+ {@render footer()}
65
+ </div>
66
+ {/if}
67
+
68
+ </div>
@@ -0,0 +1,25 @@
1
+ export default Card;
2
+ type Card = {
3
+ $on?(type: string, callback: (e: any) => void): () => void;
4
+ $set?(props: Partial<$$ComponentProps>): void;
5
+ };
6
+ declare const Card: import("svelte").Component<{
7
+ variant?: string;
8
+ padding?: string;
9
+ title?: any;
10
+ subtitle?: any;
11
+ header: any;
12
+ actions: any;
13
+ footer: any;
14
+ children: any;
15
+ } & Record<string, any>, {}, "">;
16
+ type $$ComponentProps = {
17
+ variant?: string;
18
+ padding?: string;
19
+ title?: any;
20
+ subtitle?: any;
21
+ header: any;
22
+ actions: any;
23
+ footer: any;
24
+ children: any;
25
+ } & Record<string, any>;
@@ -0,0 +1,36 @@
1
+ <script>
2
+ // Chevron — a small clickable chevron that toggles a bindable `expanded`
3
+ // state. Use it to drive show/hide of anything yourself:
4
+ //
5
+ // <script> let open = $state(false); <\/script>
6
+ // <Chevron bind:expanded={open} /> {#if open}…{/if}
7
+ //
8
+ // Purely presentational + the boolean; it doesn't hide anything itself.
9
+ let {
10
+ expanded = $bindable(false),
11
+ size = undefined, // e.g. '1.25rem'; defaults to 1.25em
12
+ direction = 'right', // collapsed-state direction: 'right' | 'down'
13
+ disabled = false,
14
+ onToggle,
15
+ ...restProps
16
+ } = $props();
17
+
18
+ function toggle() {
19
+ if (disabled) return;
20
+ expanded = !expanded;
21
+ onToggle?.(expanded);
22
+ }
23
+ </script>
24
+
25
+ <button
26
+ type="button"
27
+ class="chevron chevron-from-{direction}"
28
+ class:expanded
29
+ {disabled}
30
+ aria-expanded={expanded}
31
+ onclick={toggle}
32
+ style:font-size={size}
33
+ {...restProps}
34
+ >
35
+ <span class="material-symbols-outlined">chevron_right</span>
36
+ </button>
@@ -0,0 +1,19 @@
1
+ export default Chevron;
2
+ type Chevron = {
3
+ $on?(type: string, callback: (e: any) => void): () => void;
4
+ $set?(props: Partial<$$ComponentProps>): void;
5
+ };
6
+ declare const Chevron: import("svelte").Component<{
7
+ expanded?: boolean;
8
+ size?: any;
9
+ direction?: string;
10
+ disabled?: boolean;
11
+ onToggle: any;
12
+ } & Record<string, any>, {}, "expanded">;
13
+ type $$ComponentProps = {
14
+ expanded?: boolean;
15
+ size?: any;
16
+ direction?: string;
17
+ disabled?: boolean;
18
+ onToggle: any;
19
+ } & Record<string, any>;