@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
@@ -0,0 +1,152 @@
1
+ <script>
2
+ // MaskedInput — format-as-you-type using a simple mask pattern.
3
+ //
4
+ // Mask tokens:
5
+ // 9 → digit (0-9)
6
+ // A → letter (a-z, A-Z)
7
+ // * → alphanumeric
8
+ // Any other character in the mask is a literal (shown as-is, auto-inserted).
9
+ //
10
+ // Two display modes:
11
+ // showMask = false (default) — the value grows as you type: "(555) 123-"
12
+ // showMask = true — the full template is always shown with
13
+ // unfilled slots as `maskChar`: "(555) 12_-____"
14
+ //
15
+ // `value` is always the RAW (unmasked) characters, regardless of mode.
16
+
17
+ let {
18
+ value = $bindable(''),
19
+ mask = '',
20
+ showMask = false,
21
+ maskChar = '_',
22
+ placeholder = undefined,
23
+ disabled = false,
24
+ error = false,
25
+ success = false,
26
+ ...restProps
27
+ } = $props();
28
+
29
+ const tokens = { '9': /[0-9]/, 'A': /[a-zA-Z]/, '*': /[a-zA-Z0-9]/ };
30
+ const isToken = (ch) => Object.prototype.hasOwnProperty.call(tokens, ch);
31
+
32
+ let inputEl = $state();
33
+
34
+ // ─── Growing mode: format only as far as the user has typed ───
35
+ function applyMask(raw, mask) {
36
+ let out = '', ri = 0, mi = 0;
37
+ for (; mi < mask.length && ri < raw.length; mi++) {
38
+ const mch = mask[mi];
39
+ if (isToken(mch)) {
40
+ while (ri < raw.length) {
41
+ const rch = raw[ri++];
42
+ if (tokens[mch].test(rch)) { out += rch; break; }
43
+ }
44
+ } else {
45
+ out += mch;
46
+ if (raw[ri] === mch) ri++;
47
+ }
48
+ }
49
+ // auto-advance trailing literals so the next slot is exposed
50
+ if (raw.length > 0) {
51
+ while (mi < mask.length && !isToken(mask[mi])) { out += mask[mi]; mi++; }
52
+ }
53
+ return out;
54
+ }
55
+
56
+ // ─── Template mode: always render the full skeleton ───
57
+ function renderTemplate(raw, mask) {
58
+ let out = '', ri = 0;
59
+ for (let mi = 0; mi < mask.length; mi++) {
60
+ const mch = mask[mi];
61
+ out += isToken(mch) ? (ri < raw.length ? raw[ri++] : maskChar) : mch;
62
+ }
63
+ return out;
64
+ }
65
+
66
+ // Where the caret belongs given N filled raw chars: the first unfilled token
67
+ // slot, or end of string when full.
68
+ function caretForRaw(n, mask) {
69
+ let filled = 0;
70
+ for (let mi = 0; mi < mask.length; mi++) {
71
+ if (isToken(mask[mi])) {
72
+ if (filled === n) return mi;
73
+ filled++;
74
+ }
75
+ }
76
+ return mask.length;
77
+ }
78
+
79
+ // Validate raw chars against their token slots, walking slots and input
80
+ // chars in lockstep: each slot takes the next char that fits; chars that
81
+ // don't fit the current slot are dropped (they can't jump ahead). Caps at
82
+ // the number of token slots. (Verified against phone and plate masks.)
83
+ function sanitizeRaw(input, mask) {
84
+ const chars = [...input].filter((c) => /[a-zA-Z0-9]/.test(c));
85
+ const slots = [...mask].filter(isToken).map((ch) => tokens[ch]);
86
+ let raw = '', ci = 0, si = 0;
87
+ while (si < slots.length && ci < chars.length) {
88
+ const ch = chars[ci];
89
+ if (slots[si].test(ch)) { raw += ch; si++; ci++; }
90
+ else { ci++; }
91
+ }
92
+ return raw;
93
+ }
94
+
95
+ let display = $derived(
96
+ showMask ? renderTemplate(value ?? '', mask) : applyMask(value ?? '', mask)
97
+ );
98
+
99
+ function onInput(e) {
100
+ const isDelete = e.inputType && e.inputType.startsWith('delete');
101
+ const prevRaw = value ?? '';
102
+ let raw = sanitizeRaw(e.target.value, mask);
103
+
104
+ // Deletion that only removed literals leaves raw unchanged — drop one real
105
+ // char so backspace makes progress instead of sticking on a literal.
106
+ if (isDelete && raw.length === prevRaw.length && raw.length > 0) {
107
+ raw = raw.slice(0, -1);
108
+ }
109
+
110
+ value = raw;
111
+
112
+ if (showMask) {
113
+ const text = renderTemplate(raw, mask);
114
+ e.target.value = text;
115
+ const pos = caretForRaw(raw.length, mask);
116
+ // restore caret after the value write
117
+ requestAnimationFrame(() => {
118
+ try { e.target.setSelectionRange(pos, pos); } catch {}
119
+ });
120
+ } else {
121
+ e.target.value = applyMask(raw, mask);
122
+ }
123
+ }
124
+
125
+ // In template mode, clicking into the field should drop the caret at the next
126
+ // empty slot rather than wherever the click landed in the skeleton.
127
+ function onFocus(e) {
128
+ if (!showMask) return;
129
+ const pos = caretForRaw((value ?? '').length, mask);
130
+ requestAnimationFrame(() => {
131
+ try { e.target.setSelectionRange(pos, pos); } catch {}
132
+ });
133
+ }
134
+
135
+ let classes = $derived([
136
+ 'input', 'masked-input',
137
+ error ? 'input-error' : '',
138
+ success ? 'input-success' : '',
139
+ ].filter(Boolean).join(' '));
140
+ </script>
141
+
142
+ <input
143
+ bind:this={inputEl}
144
+ class={classes}
145
+ type="text"
146
+ value={display}
147
+ placeholder={showMask ? undefined : (placeholder ?? mask)}
148
+ {disabled}
149
+ oninput={onInput}
150
+ onfocus={onFocus}
151
+ {...restProps}
152
+ />
@@ -0,0 +1,25 @@
1
+ export default MaskedInput;
2
+ type MaskedInput = {
3
+ $on?(type: string, callback: (e: any) => void): () => void;
4
+ $set?(props: Partial<$$ComponentProps>): void;
5
+ };
6
+ declare const MaskedInput: import("svelte").Component<{
7
+ value?: string;
8
+ mask?: string;
9
+ showMask?: boolean;
10
+ maskChar?: string;
11
+ placeholder?: any;
12
+ disabled?: boolean;
13
+ error?: boolean;
14
+ success?: boolean;
15
+ } & Record<string, any>, {}, "value">;
16
+ type $$ComponentProps = {
17
+ value?: string;
18
+ mask?: string;
19
+ showMask?: boolean;
20
+ maskChar?: string;
21
+ placeholder?: any;
22
+ disabled?: boolean;
23
+ error?: boolean;
24
+ success?: boolean;
25
+ } & Record<string, any>;
@@ -0,0 +1,28 @@
1
+ <script>
2
+ let {
3
+ group = $bindable(undefined),
4
+ value,
5
+ label = undefined,
6
+ disabled = false,
7
+ children,
8
+ ...restProps
9
+ } = $props();
10
+ </script>
11
+
12
+ <label class="radio" class:radio-disabled={disabled}>
13
+ <input
14
+ type="radio"
15
+ bind:group
16
+ {value}
17
+ {disabled}
18
+ {...restProps}
19
+ />
20
+ <span class="radio-circle">
21
+ <span class="radio-dot"></span>
22
+ </span>
23
+ {#if label}
24
+ <span class="radio-label">{label}</span>
25
+ {:else if children}
26
+ <span class="radio-label">{@render children()}</span>
27
+ {/if}
28
+ </label>
@@ -0,0 +1,19 @@
1
+ export default Radio;
2
+ type Radio = {
3
+ $on?(type: string, callback: (e: any) => void): () => void;
4
+ $set?(props: Partial<$$ComponentProps>): void;
5
+ };
6
+ declare const Radio: import("svelte").Component<{
7
+ group?: any;
8
+ value: any;
9
+ label?: any;
10
+ disabled?: boolean;
11
+ children: any;
12
+ } & Record<string, any>, {}, "group">;
13
+ type $$ComponentProps = {
14
+ group?: any;
15
+ value: any;
16
+ label?: any;
17
+ disabled?: boolean;
18
+ children: any;
19
+ } & Record<string, any>;
@@ -0,0 +1,28 @@
1
+ <script>
2
+ import Radio from './Radio.svelte';
3
+
4
+ let {
5
+ value = $bindable(undefined),
6
+ options = [], // [{ value, label, disabled? }] or string[]
7
+ name = undefined,
8
+ disabled = false,
9
+ inline = false, // lay out horizontally
10
+ } = $props();
11
+
12
+ // Normalize string options to { value, label }
13
+ let normalized = $derived(
14
+ options.map((o) => (typeof o === 'string' ? { value: o, label: o } : o))
15
+ );
16
+ </script>
17
+
18
+ <div class="radio-group" class:radio-group-inline={inline} role="radiogroup">
19
+ {#each normalized as opt}
20
+ <Radio
21
+ bind:group={value}
22
+ value={opt.value}
23
+ label={opt.label}
24
+ disabled={disabled || opt.disabled}
25
+ {name}
26
+ />
27
+ {/each}
28
+ </div>
@@ -0,0 +1,19 @@
1
+ export default RadioGroup;
2
+ type RadioGroup = {
3
+ $on?(type: string, callback: (e: any) => void): () => void;
4
+ $set?(props: Partial<$$ComponentProps>): void;
5
+ };
6
+ declare const RadioGroup: import("svelte").Component<{
7
+ value?: any;
8
+ options?: any[];
9
+ name?: any;
10
+ disabled?: boolean;
11
+ inline?: boolean;
12
+ }, {}, "value">;
13
+ type $$ComponentProps = {
14
+ value?: any;
15
+ options?: any[];
16
+ name?: any;
17
+ disabled?: boolean;
18
+ inline?: boolean;
19
+ };
@@ -0,0 +1,20 @@
1
+ <script>
2
+ let {
3
+ value = $bindable(''),
4
+ disabled = false,
5
+ error = false,
6
+ size = 'md',
7
+ children,
8
+ ...restProps
9
+ } = $props();
10
+
11
+ const sizeClass = { sm: 'select-sm', md: '', lg: 'select-lg' };
12
+
13
+ let classes = $derived(
14
+ ['select', sizeClass[size], error ? 'select-error' : ''].filter(Boolean).join(' ')
15
+ );
16
+ </script>
17
+
18
+ <select class={classes} {disabled} bind:value {...restProps}>
19
+ {@render children?.()}
20
+ </select>
@@ -0,0 +1,19 @@
1
+ export default Select;
2
+ type Select = {
3
+ $on?(type: string, callback: (e: any) => void): () => void;
4
+ $set?(props: Partial<$$ComponentProps>): void;
5
+ };
6
+ declare const Select: import("svelte").Component<{
7
+ value?: string;
8
+ disabled?: boolean;
9
+ error?: boolean;
10
+ size?: string;
11
+ children: any;
12
+ } & Record<string, any>, {}, "value">;
13
+ type $$ComponentProps = {
14
+ value?: string;
15
+ disabled?: boolean;
16
+ error?: boolean;
17
+ size?: string;
18
+ children: any;
19
+ } & Record<string, any>;
@@ -0,0 +1,30 @@
1
+ <script>
2
+ let {
3
+ value = $bindable(''),
4
+ placeholder = undefined,
5
+ rows = 4,
6
+ disabled = false,
7
+ readonly = false,
8
+ error = false,
9
+ success = false,
10
+ resize = 'vertical', // 'none' | 'vertical' | 'horizontal' | 'both'
11
+ ...restProps
12
+ } = $props();
13
+
14
+ let classes = $derived([
15
+ 'textarea',
16
+ error ? 'textarea-error' : '',
17
+ success ? 'textarea-success' : '',
18
+ ].filter(Boolean).join(' '));
19
+ </script>
20
+
21
+ <textarea
22
+ class={classes}
23
+ bind:value
24
+ {placeholder}
25
+ {rows}
26
+ {disabled}
27
+ {readonly}
28
+ style:resize
29
+ {...restProps}
30
+ ></textarea>
@@ -0,0 +1,25 @@
1
+ export default Textarea;
2
+ type Textarea = {
3
+ $on?(type: string, callback: (e: any) => void): () => void;
4
+ $set?(props: Partial<$$ComponentProps>): void;
5
+ };
6
+ declare const Textarea: import("svelte").Component<{
7
+ value?: string;
8
+ placeholder?: any;
9
+ rows?: number;
10
+ disabled?: boolean;
11
+ readonly?: boolean;
12
+ error?: boolean;
13
+ success?: boolean;
14
+ resize?: string;
15
+ } & Record<string, any>, {}, "value">;
16
+ type $$ComponentProps = {
17
+ value?: string;
18
+ placeholder?: any;
19
+ rows?: number;
20
+ disabled?: boolean;
21
+ readonly?: boolean;
22
+ error?: boolean;
23
+ success?: boolean;
24
+ resize?: string;
25
+ } & Record<string, any>;
@@ -0,0 +1,21 @@
1
+ <script>
2
+ let {
3
+ checked = $bindable(false),
4
+ label = undefined,
5
+ disabled = false,
6
+ children,
7
+ ...restProps
8
+ } = $props();
9
+ </script>
10
+
11
+ <label class="toggle" class:toggle-disabled={disabled}>
12
+ <input type="checkbox" bind:checked {disabled} {...restProps} />
13
+ <div class="toggle-track">
14
+ <div class="toggle-thumb"></div>
15
+ </div>
16
+ {#if label}
17
+ <span class="toggle-label">{label}</span>
18
+ {:else if children}
19
+ <span class="toggle-label">{@render children()}</span>
20
+ {/if}
21
+ </label>
@@ -0,0 +1,17 @@
1
+ export default Toggle;
2
+ type Toggle = {
3
+ $on?(type: string, callback: (e: any) => void): () => void;
4
+ $set?(props: Partial<$$ComponentProps>): void;
5
+ };
6
+ declare const Toggle: import("svelte").Component<{
7
+ checked?: boolean;
8
+ label?: any;
9
+ disabled?: boolean;
10
+ children: any;
11
+ } & Record<string, any>, {}, "checked">;
12
+ type $$ComponentProps = {
13
+ checked?: boolean;
14
+ label?: any;
15
+ disabled?: boolean;
16
+ children: any;
17
+ } & Record<string, any>;
@@ -0,0 +1,77 @@
1
+ <script>
2
+ let {
3
+ open = $bindable(false),
4
+ size = 'md',
5
+ drawer = false,
6
+ closeOnBackdrop = true,
7
+ title = undefined,
8
+ subtitle = undefined,
9
+ header,
10
+ footer,
11
+ children,
12
+ } = $props();
13
+
14
+ const sizeClass = {
15
+ sm: 'modal-sm', md: '', lg: 'modal-lg', xl: 'modal-xl', full: 'modal-full'
16
+ };
17
+
18
+ let closing = $state(false);
19
+
20
+ function close() {
21
+ closing = true;
22
+ setTimeout(() => { closing = false; open = false; }, 200);
23
+ }
24
+
25
+ function onbackdrop() {
26
+ if (closeOnBackdrop) close();
27
+ }
28
+
29
+ function onkeydown(e) {
30
+ if (open && e.key === 'Escape') close();
31
+ }
32
+
33
+ let modalClass = $derived(
34
+ ['modal', sizeClass[size], drawer ? 'modal-drawer' : ''].filter(Boolean).join(' ')
35
+ );
36
+
37
+ let backdropClass = $derived(
38
+ ['modal-backdrop', closing ? 'closing' : '', drawer ? 'modal-backdrop-drawer' : '']
39
+ .filter(Boolean).join(' ')
40
+ );
41
+ </script>
42
+
43
+ <svelte:window onkeydown={onkeydown} />
44
+
45
+ {#if open || closing}
46
+ <!-- svelte-ignore a11y_click_events_have_key_events a11y_no_static_element_interactions -->
47
+ <div class={backdropClass} onclick={onbackdrop} role="dialog" aria-modal="true">
48
+ <!-- svelte-ignore a11y_click_events_have_key_events a11y_no_static_element_interactions -->
49
+ <div class={modalClass} onclick={(e) => e.stopPropagation()}>
50
+
51
+ <div class="modal-header">
52
+ {#if header}
53
+ {@render header()}
54
+ {:else if title}
55
+ <div>
56
+ <h2 class="modal-title">{title}</h2>
57
+ {#if subtitle}<p class="modal-subtitle">{subtitle}</p>{/if}
58
+ </div>
59
+ {/if}
60
+ <button class="btn btn-ghost btn-icon modal-close" onclick={close} aria-label="Close">
61
+ <span class="material-symbols-outlined">close</span>
62
+ </button>
63
+ </div>
64
+
65
+ <div class="modal-body">
66
+ {@render children?.()}
67
+ </div>
68
+
69
+ {#if footer}
70
+ <div class="modal-footer">
71
+ {@render footer()}
72
+ </div>
73
+ {/if}
74
+
75
+ </div>
76
+ </div>
77
+ {/if}
@@ -0,0 +1,27 @@
1
+ export default Modal;
2
+ type Modal = {
3
+ $on?(type: string, callback: (e: any) => void): () => void;
4
+ $set?(props: Partial<$$ComponentProps>): void;
5
+ };
6
+ declare const Modal: import("svelte").Component<{
7
+ open?: boolean;
8
+ size?: string;
9
+ drawer?: boolean;
10
+ closeOnBackdrop?: boolean;
11
+ title?: any;
12
+ subtitle?: any;
13
+ header: any;
14
+ footer: any;
15
+ children: any;
16
+ }, {}, "open">;
17
+ type $$ComponentProps = {
18
+ open?: boolean;
19
+ size?: string;
20
+ drawer?: boolean;
21
+ closeOnBackdrop?: boolean;
22
+ title?: any;
23
+ subtitle?: any;
24
+ header: any;
25
+ footer: any;
26
+ children: any;
27
+ };
@@ -0,0 +1,77 @@
1
+ <script>
2
+ // Pagination — page navigation with ellipsis truncation.
3
+ // `page` is 1-based and bindable. Emits onchange(page) too.
4
+ let {
5
+ page = $bindable(1),
6
+ total = 1, // total number of pages
7
+ siblings = 1, // pages shown on each side of current
8
+ onchange,
9
+ ...restProps
10
+ } = $props();
11
+
12
+ // Build the list of page items, inserting '…' where truncated.
13
+ function range(start, end) {
14
+ const out = [];
15
+ for (let i = start; i <= end; i++) out.push(i);
16
+ return out;
17
+ }
18
+
19
+ let items = $derived.by(() => {
20
+ const totalNumbers = siblings * 2 + 5; // first, last, current, 2 ellipsis slots
21
+ if (total <= totalNumbers) return range(1, total);
22
+
23
+ const left = Math.max(page - siblings, 1);
24
+ const right = Math.min(page + siblings, total);
25
+ const showLeftDots = left > 2;
26
+ const showRightDots = right < total - 1;
27
+
28
+ if (!showLeftDots && showRightDots) {
29
+ return [...range(1, siblings * 2 + 3), '…', total];
30
+ }
31
+ if (showLeftDots && !showRightDots) {
32
+ return [1, '…', ...range(total - (siblings * 2 + 2), total)];
33
+ }
34
+ return [1, '…', ...range(left, right), '…', total];
35
+ });
36
+
37
+ function go(p) {
38
+ if (p < 1 || p > total || p === page) return;
39
+ page = p;
40
+ onchange?.(p);
41
+ }
42
+ </script>
43
+
44
+ <nav class="pagination" aria-label="Pagination" {...restProps}>
45
+ <button
46
+ class="pagination-btn pagination-arrow"
47
+ disabled={page <= 1}
48
+ onclick={() => go(page - 1)}
49
+ aria-label="Previous page"
50
+ >
51
+ <span class="material-symbols-outlined">chevron_left</span>
52
+ </button>
53
+
54
+ {#each items as item}
55
+ {#if item === '…'}
56
+ <span class="pagination-ellipsis">…</span>
57
+ {:else}
58
+ <button
59
+ class="pagination-btn"
60
+ class:active={item === page}
61
+ aria-current={item === page ? 'page' : undefined}
62
+ onclick={() => go(item)}
63
+ >
64
+ {item}
65
+ </button>
66
+ {/if}
67
+ {/each}
68
+
69
+ <button
70
+ class="pagination-btn pagination-arrow"
71
+ disabled={page >= total}
72
+ onclick={() => go(page + 1)}
73
+ aria-label="Next page"
74
+ >
75
+ <span class="material-symbols-outlined">chevron_right</span>
76
+ </button>
77
+ </nav>
@@ -0,0 +1,17 @@
1
+ export default Pagination;
2
+ type Pagination = {
3
+ $on?(type: string, callback: (e: any) => void): () => void;
4
+ $set?(props: Partial<$$ComponentProps>): void;
5
+ };
6
+ declare const Pagination: import("svelte").Component<{
7
+ page?: number;
8
+ total?: number;
9
+ siblings?: number;
10
+ onchange: any;
11
+ } & Record<string, any>, {}, "page">;
12
+ type $$ComponentProps = {
13
+ page?: number;
14
+ total?: number;
15
+ siblings?: number;
16
+ onchange: any;
17
+ } & Record<string, any>;
@@ -0,0 +1,34 @@
1
+ <script>
2
+ // Progress — a linear progress bar. Determinate when `value` is set
3
+ // (0–max); indeterminate when `indeterminate` is true.
4
+ let {
5
+ value = 0,
6
+ max = 100,
7
+ indeterminate = false,
8
+ variant = 'primary', // 'primary' | 'success' | 'warning' | 'error'
9
+ size = 'md', // 'sm' | 'md' | 'lg'
10
+ showLabel = false,
11
+ ...restProps
12
+ } = $props();
13
+
14
+ let pct = $derived(Math.max(0, Math.min(100, (value / max) * 100)));
15
+ </script>
16
+
17
+ <div class="progress-container" {...restProps}>
18
+ <div
19
+ class="progress progress-{size}"
20
+ role="progressbar"
21
+ aria-valuenow={indeterminate ? undefined : value}
22
+ aria-valuemin="0"
23
+ aria-valuemax={max}
24
+ >
25
+ <div
26
+ class="progress-bar progress-{variant}"
27
+ class:progress-indeterminate={indeterminate}
28
+ style:width={indeterminate ? undefined : `${pct}%`}
29
+ ></div>
30
+ </div>
31
+ {#if showLabel && !indeterminate}
32
+ <span class="progress-label">{Math.round(pct)}%</span>
33
+ {/if}
34
+ </div>
@@ -0,0 +1,21 @@
1
+ export default Progress;
2
+ type Progress = {
3
+ $on?(type: string, callback: (e: any) => void): () => void;
4
+ $set?(props: Partial<$$ComponentProps>): void;
5
+ };
6
+ declare const Progress: import("svelte").Component<{
7
+ value?: number;
8
+ max?: number;
9
+ indeterminate?: boolean;
10
+ variant?: string;
11
+ size?: string;
12
+ showLabel?: boolean;
13
+ } & Record<string, any>, {}, "">;
14
+ type $$ComponentProps = {
15
+ value?: number;
16
+ max?: number;
17
+ indeterminate?: boolean;
18
+ variant?: string;
19
+ size?: string;
20
+ showLabel?: boolean;
21
+ } & Record<string, any>;