@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.
- package/README.md +137 -2
- package/dist/components/Accordion.svelte +36 -0
- package/dist/components/Accordion.svelte.d.ts +15 -0
- package/dist/components/AccordionItem.svelte +73 -0
- package/dist/components/AccordionItem.svelte.d.ts +21 -0
- package/dist/components/Alert.svelte +23 -0
- package/dist/components/Alert.svelte.d.ts +15 -0
- package/dist/components/Badge.svelte +16 -0
- package/dist/components/Badge.svelte.d.ts +15 -0
- package/dist/components/Button.svelte +43 -0
- package/dist/components/Button.svelte.d.ts +25 -0
- package/dist/components/Calendar.svelte +88 -0
- package/dist/components/Calendar.svelte.d.ts +13 -0
- package/dist/components/Card.svelte +68 -0
- package/dist/components/Card.svelte.d.ts +25 -0
- package/dist/components/Chevron.svelte +36 -0
- package/dist/components/Chevron.svelte.d.ts +19 -0
- package/dist/components/Collapsible.svelte +46 -0
- package/dist/components/Collapsible.svelte.d.ts +19 -0
- package/dist/components/ConfirmDialog.svelte +70 -0
- package/dist/components/ConfirmDialog.svelte.d.ts +27 -0
- package/dist/components/DatePicker.svelte +60 -0
- package/dist/components/DatePicker.svelte.d.ts +17 -0
- package/dist/components/Divider.svelte +25 -0
- package/dist/components/Divider.svelte.d.ts +17 -0
- package/dist/components/Dropdown.svelte +100 -0
- package/dist/components/Dropdown.svelte.d.ts +21 -0
- package/dist/components/Form/Checkbox.svelte +37 -0
- package/dist/components/Form/Checkbox.svelte.d.ts +19 -0
- package/dist/components/Form/Field.svelte +28 -0
- package/dist/components/Form/Field.svelte.d.ts +21 -0
- package/dist/components/Form/Input.svelte +56 -0
- package/dist/components/Form/Input.svelte.d.ts +29 -0
- package/dist/components/Form/MaskedInput.svelte +152 -0
- package/dist/components/Form/MaskedInput.svelte.d.ts +25 -0
- package/dist/components/Form/Radio.svelte +28 -0
- package/dist/components/Form/Radio.svelte.d.ts +19 -0
- package/dist/components/Form/RadioGroup.svelte +28 -0
- package/dist/components/Form/RadioGroup.svelte.d.ts +19 -0
- package/dist/components/Form/Select.svelte +20 -0
- package/dist/components/Form/Select.svelte.d.ts +19 -0
- package/dist/components/Form/Textarea.svelte +30 -0
- package/dist/components/Form/Textarea.svelte.d.ts +25 -0
- package/dist/components/Form/Toggle.svelte +21 -0
- package/dist/components/Form/Toggle.svelte.d.ts +17 -0
- package/dist/components/Modal.svelte +77 -0
- package/dist/components/Modal.svelte.d.ts +27 -0
- package/dist/components/Pagination.svelte +77 -0
- package/dist/components/Pagination.svelte.d.ts +17 -0
- package/dist/components/Progress.svelte +34 -0
- package/dist/components/Progress.svelte.d.ts +21 -0
- package/dist/components/Spinner.svelte +24 -0
- package/dist/components/Spinner.svelte.d.ts +13 -0
- package/dist/components/Table.svelte +100 -0
- package/dist/components/Table.svelte.d.ts +21 -0
- package/dist/components/ThemeToggle.svelte +22 -0
- package/dist/components/ThemeToggle.svelte.d.ts +11 -0
- package/dist/components/Tooltip.svelte +45 -0
- package/dist/components/Tooltip.svelte.d.ts +15 -0
- package/dist/css/base/root.css +103 -0
- package/dist/css/base.css +47 -0
- package/dist/css/components/accordion.css +151 -0
- package/dist/css/components/alert.css +56 -0
- package/dist/css/components/badge.css +56 -0
- package/dist/css/components/button.css +171 -0
- package/dist/css/components/calendar.css +105 -0
- package/dist/css/components/card.css +128 -0
- package/dist/css/components/checkbox-radio.css +105 -0
- package/dist/css/components/collapsible.css +61 -0
- package/dist/css/components/divider.css +42 -0
- package/dist/css/components/dock-layout.css +111 -0
- package/dist/css/components/dropdown.css +68 -0
- package/dist/css/components/floating-shell.css +93 -0
- package/dist/css/components/form.css +286 -0
- package/dist/css/components/login.css +145 -0
- package/dist/css/components/modal.css +179 -0
- package/dist/css/components/nav.css +190 -0
- package/dist/css/components/nestable.css +187 -0
- package/dist/css/components/pagination.css +50 -0
- package/dist/css/components/progress.css +50 -0
- package/dist/css/components/sidebar.css +78 -0
- package/dist/css/components/spinner.css +36 -0
- package/dist/css/components/table.css +98 -0
- package/dist/css/components/tooltip.css +77 -0
- package/dist/css/components/topbar-layout.css +108 -0
- package/dist/css/icons/icons.css +52 -0
- package/dist/css/index.css +20 -0
- package/dist/css/layout/container.css +12 -0
- package/dist/css/layout/grid.css +40 -0
- package/dist/css/layout/shell.css +185 -0
- package/dist/css/overlay/default.css +27 -0
- package/dist/css/tokens/colors.css +81 -0
- package/dist/css/tokens/radius.css +8 -0
- package/dist/css/tokens/shadows.css +23 -0
- package/dist/css/tokens/spacing.css +30 -0
- package/dist/css/tokens/transitions.css +10 -0
- package/dist/css/tokens/typography.css +44 -0
- package/dist/index.d.ts +43 -0
- package/dist/index.js +52 -0
- package/dist/layout/NavItem.svelte +84 -0
- package/dist/layout/NavItem.svelte.d.ts +25 -0
- package/dist/layout/Shell.svelte +7 -0
- package/dist/layout/Shell.svelte.d.ts +13 -0
- package/dist/layout/SidebarProfile.svelte +31 -0
- package/dist/layout/SidebarProfile.svelte.d.ts +19 -0
- package/dist/layouts/AppShell.svelte +60 -0
- package/dist/layouts/AppShell.svelte.d.ts +21 -0
- package/dist/layouts/BarLayout.svelte +60 -0
- package/dist/layouts/BarLayout.svelte.d.ts +21 -0
- package/dist/layouts/BottomBarLayout.svelte +23 -0
- package/dist/layouts/BottomBarLayout.svelte.d.ts +15 -0
- package/dist/layouts/DockLayout.svelte +81 -0
- package/dist/layouts/DockLayout.svelte.d.ts +15 -0
- package/dist/layouts/FloatingDockLayout.svelte +56 -0
- package/dist/layouts/FloatingDockLayout.svelte.d.ts +13 -0
- package/dist/layouts/FloatingLayout.svelte +80 -0
- package/dist/layouts/FloatingLayout.svelte.d.ts +19 -0
- package/dist/layouts/FloatingLeftLayout.svelte +59 -0
- package/dist/layouts/FloatingLeftLayout.svelte.d.ts +15 -0
- package/dist/layouts/FloatingShell.svelte +80 -0
- package/dist/layouts/FloatingShell.svelte.d.ts +19 -0
- package/dist/layouts/FloatingTopLayout.svelte +68 -0
- package/dist/layouts/FloatingTopLayout.svelte.d.ts +15 -0
- package/dist/layouts/HybridLayout.svelte +20 -0
- package/dist/layouts/HybridLayout.svelte.d.ts +17 -0
- package/dist/layouts/IconRailLayout.svelte +75 -0
- package/dist/layouts/IconRailLayout.svelte.d.ts +15 -0
- package/dist/layouts/LeftBarLayout.svelte +19 -0
- package/dist/layouts/LeftBarLayout.svelte.d.ts +15 -0
- package/dist/layouts/RightBarLayout.svelte +21 -0
- package/dist/layouts/RightBarLayout.svelte.d.ts +15 -0
- package/dist/layouts/SideBar.svelte +86 -0
- package/dist/layouts/SideBar.svelte.d.ts +17 -0
- package/dist/layouts/SidebarLayout.svelte +11 -0
- package/dist/layouts/SidebarLayout.svelte.d.ts +15 -0
- package/dist/layouts/TopBar.svelte +90 -0
- package/dist/layouts/TopBar.svelte.d.ts +21 -0
- package/dist/layouts/TopBarLayout.svelte +26 -0
- package/dist/layouts/TopBarLayout.svelte.d.ts +15 -0
- package/dist/theme/theme.svelte.d.ts +11 -0
- package/dist/theme/theme.svelte.js +48 -0
- 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>;
|