@spaethtech/svelte-ui 0.1.10 → 0.3.1-dev.3.e16df24
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 +180 -42
- package/dist/components/Alert.svelte +119 -0
- package/dist/components/Alert.svelte.d.ts +29 -0
- package/dist/components/Badge/Badge.svelte +142 -69
- package/dist/components/Badge/Badge.svelte.d.ts +26 -6
- package/dist/components/Badge/index.d.ts +1 -1
- package/dist/components/Badge/index.js +1 -1
- package/dist/components/Banner.svelte +133 -0
- package/dist/components/Banner.svelte.d.ts +31 -0
- package/dist/components/Button.svelte +240 -0
- package/dist/components/Button.svelte.d.ts +33 -0
- package/dist/components/ButtonDropdown.svelte +145 -0
- package/dist/components/ButtonDropdown.svelte.d.ts +31 -0
- package/dist/components/Calendar.svelte +259 -0
- package/dist/components/Calendar.svelte.d.ts +27 -0
- package/dist/components/Card.svelte +78 -0
- package/dist/components/Card.svelte.d.ts +17 -0
- package/dist/components/CardBody.svelte +41 -0
- package/dist/components/CardBody.svelte.d.ts +17 -0
- package/dist/components/CardFooter.svelte +49 -0
- package/dist/components/CardFooter.svelte.d.ts +16 -0
- package/dist/components/CardHeader.svelte +49 -0
- package/dist/components/CardHeader.svelte.d.ts +16 -0
- package/dist/components/Checkbox.svelte +131 -0
- package/dist/components/Checkbox.svelte.d.ts +16 -0
- package/dist/components/DataTable.svelte +518 -0
- package/dist/components/DataTable.svelte.d.ts +74 -0
- package/dist/components/DatePicker.svelte +312 -0
- package/dist/components/DatePicker.svelte.d.ts +32 -0
- package/dist/components/DateTimeInput.svelte +93 -0
- package/dist/components/DateTimeInput.svelte.d.ts +20 -0
- package/dist/components/Dialog.svelte +132 -0
- package/dist/components/Dialog.svelte.d.ts +24 -0
- package/dist/components/{EmailInput/EmailInput.svelte → EmailInput.svelte} +17 -8
- package/dist/components/EmailInput.svelte.d.ts +21 -0
- package/dist/components/Input.svelte +369 -0
- package/dist/components/Input.svelte.d.ts +35 -0
- package/dist/components/{List/List.svelte → List.svelte} +194 -133
- package/dist/components/{List/List.svelte.d.ts → List.svelte.d.ts} +9 -1
- package/dist/components/Menu.svelte +117 -0
- package/dist/components/Menu.svelte.d.ts +20 -0
- package/dist/components/NotesEditor.svelte +127 -0
- package/dist/components/NotesEditor.svelte.d.ts +17 -0
- package/dist/components/{NumberInput/NumberInput.svelte → NumberInput.svelte} +146 -105
- package/dist/components/{NumberInput/NumberInput.svelte.d.ts → NumberInput.svelte.d.ts} +11 -4
- package/dist/components/PasswordInput.svelte +52 -0
- package/dist/components/PasswordInput.svelte.d.ts +20 -0
- package/dist/components/Popup.svelte +140 -0
- package/dist/components/Popup.svelte.d.ts +31 -0
- package/dist/components/Query.svelte +284 -0
- package/dist/components/Query.svelte.d.ts +15 -0
- package/dist/components/{Rating/Rating.svelte → Rating.svelte} +19 -10
- package/dist/components/Rating.svelte.d.ts +13 -0
- package/dist/components/{SearchInput/SearchInput.svelte → SearchInput.svelte} +19 -8
- package/dist/components/{SearchInput/SearchInput.svelte.d.ts → SearchInput.svelte.d.ts} +9 -2
- package/dist/components/{Select/Select.svelte → Select.svelte} +48 -76
- package/dist/components/{Select/Select.svelte.d.ts → Select.svelte.d.ts} +11 -1
- package/dist/components/SideBarMenu/SideBarMenu.svelte +724 -0
- package/dist/components/SideBarMenu/SideBarMenu.svelte.d.ts +109 -0
- package/dist/components/SideBarMenu/index.d.ts +2 -0
- package/dist/components/SideBarMenu/index.js +1 -0
- package/dist/components/TabStrip/TabStrip.svelte +384 -0
- package/dist/components/TabStrip/TabStrip.svelte.d.ts +50 -0
- package/dist/components/TabStrip/index.d.ts +3 -0
- package/dist/components/TabStrip/index.js +2 -0
- package/dist/components/{TextArea/TextArea.svelte → TextArea.svelte} +143 -112
- package/dist/components/TextArea.svelte.d.ts +38 -0
- package/dist/components/ThemeSelector.svelte +81 -0
- package/dist/components/ThemeSelector.svelte.d.ts +10 -0
- package/dist/components/TimePicker.svelte +148 -0
- package/dist/components/TimePicker.svelte.d.ts +28 -0
- package/dist/components/TimeRangeInput.svelte +203 -0
- package/dist/components/TimeRangeInput.svelte.d.ts +29 -0
- package/dist/components/TimeSpinner.svelte +202 -0
- package/dist/components/TimeSpinner.svelte.d.ts +26 -0
- package/dist/components/Toast/Toaster.svelte +51 -0
- package/dist/components/Toast/Toaster.svelte.d.ts +12 -0
- package/dist/components/Toast/toast.svelte.d.ts +29 -0
- package/dist/components/Toast/toast.svelte.js +27 -0
- package/dist/components/Toggle.svelte +93 -0
- package/dist/components/Toggle.svelte.d.ts +15 -0
- package/dist/data/dataset.d.ts +42 -0
- package/dist/data/dataset.js +3 -0
- package/dist/data/index.d.ts +3 -0
- package/dist/data/index.js +3 -0
- package/dist/data/query/ast.d.ts +62 -0
- package/dist/data/query/ast.js +12 -0
- package/dist/data/query/index.d.ts +3 -0
- package/dist/data/query/index.js +3 -0
- package/dist/data/query/lexer.d.ts +33 -0
- package/dist/data/query/lexer.js +225 -0
- package/dist/data/query/parser.d.ts +11 -0
- package/dist/data/query/parser.js +252 -0
- package/dist/data/table/grid.svelte.d.ts +57 -0
- package/dist/data/table/grid.svelte.js +139 -0
- package/dist/data/table/index.d.ts +2 -0
- package/dist/data/table/index.js +2 -0
- package/dist/data/table/types.d.ts +79 -0
- package/dist/index.d.ts +48 -22
- package/dist/index.js +45 -21
- package/dist/positioning/anchored.d.ts +61 -0
- package/dist/positioning/anchored.js +122 -0
- package/dist/positioning/tooltip.d.ts +41 -0
- package/dist/positioning/tooltip.js +147 -0
- package/dist/theme.css +205 -0
- package/dist/types/breakpoints.d.ts +24 -0
- package/dist/types/breakpoints.js +13 -0
- package/dist/types/responsive.d.ts +32 -0
- package/dist/types/responsive.js +54 -0
- package/dist/types/sizes.d.ts +10 -3
- package/dist/types/time.d.ts +19 -0
- package/dist/types/time.js +10 -0
- package/dist/types/variants.d.ts +8 -1
- package/dist/types/variants.js +16 -1
- package/package.json +93 -63
- package/dist/components/Button/Button.svelte +0 -172
- package/dist/components/Button/Button.svelte.d.ts +0 -32
- package/dist/components/Button/index.d.ts +0 -1
- package/dist/components/Button/index.js +0 -1
- package/dist/components/Dialog/Dialog.svelte +0 -101
- package/dist/components/Dialog/Dialog.svelte.d.ts +0 -18
- package/dist/components/Dialog/index.d.ts +0 -1
- package/dist/components/Dialog/index.js +0 -1
- package/dist/components/ElementManager/ElementManager.svelte +0 -397
- package/dist/components/ElementManager/ElementManager.svelte.d.ts +0 -43
- package/dist/components/ElementManager/index.d.ts +0 -1
- package/dist/components/ElementManager/index.js +0 -1
- package/dist/components/EmailInput/EmailInput.svelte.d.ts +0 -14
- package/dist/components/EmailInput/index.d.ts +0 -1
- package/dist/components/EmailInput/index.js +0 -1
- package/dist/components/Icon/Icon.svelte +0 -74
- package/dist/components/Icon/Icon.svelte.d.ts +0 -13
- package/dist/components/Icon/index.d.ts +0 -1
- package/dist/components/Icon/index.js +0 -1
- package/dist/components/Input/Input.svelte +0 -268
- package/dist/components/Input/Input.svelte.d.ts +0 -18
- package/dist/components/Input/index.d.ts +0 -1
- package/dist/components/Input/index.js +0 -1
- package/dist/components/List/index.d.ts +0 -1
- package/dist/components/List/index.js +0 -1
- package/dist/components/ListItem/ListItem.svelte +0 -175
- package/dist/components/ListItem/ListItem.svelte.d.ts +0 -24
- package/dist/components/ListItem/index.d.ts +0 -2
- package/dist/components/ListItem/index.js +0 -2
- package/dist/components/ListView/ListView.svelte +0 -463
- package/dist/components/ListView/ListView.svelte.d.ts +0 -37
- package/dist/components/ListView/index.d.ts +0 -2
- package/dist/components/ListView/index.js +0 -2
- package/dist/components/NodeGraph/BaseNode.d.ts +0 -57
- package/dist/components/NodeGraph/BaseNode.js +0 -30
- package/dist/components/NodeGraph/Edge.svelte +0 -60
- package/dist/components/NodeGraph/Edge.svelte.d.ts +0 -16
- package/dist/components/NodeGraph/ExpressionEvaluator.d.ts +0 -82
- package/dist/components/NodeGraph/ExpressionEvaluator.js +0 -152
- package/dist/components/NodeGraph/Node.svelte +0 -100
- package/dist/components/NodeGraph/Node.svelte.d.ts +0 -10
- package/dist/components/NodeGraph/NodeGraph.svelte +0 -52
- package/dist/components/NodeGraph/NodeGraph.svelte.d.ts +0 -14
- package/dist/components/NodeGraph/NodeInstance.svelte.d.ts +0 -80
- package/dist/components/NodeGraph/NodeInstance.svelte.js +0 -241
- package/dist/components/NodeGraph/NodePort.svelte +0 -75
- package/dist/components/NodeGraph/NodePort.svelte.d.ts +0 -11
- package/dist/components/NodeGraph/decorators.d.ts +0 -81
- package/dist/components/NodeGraph/decorators.js +0 -148
- package/dist/components/NodeGraph/index.d.ts +0 -9
- package/dist/components/NodeGraph/index.js +0 -9
- package/dist/components/NodeGraph/types.d.ts +0 -94
- package/dist/components/NodeGraph/types.js +0 -33
- package/dist/components/NotesEditor/NotesEditor.svelte +0 -203
- package/dist/components/NotesEditor/NotesEditor.svelte.d.ts +0 -9
- package/dist/components/NotesEditor/index.d.ts +0 -1
- package/dist/components/NotesEditor/index.js +0 -1
- package/dist/components/NumberInput/index.d.ts +0 -1
- package/dist/components/NumberInput/index.js +0 -1
- package/dist/components/PasswordInput/PasswordInput.svelte +0 -41
- package/dist/components/PasswordInput/PasswordInput.svelte.d.ts +0 -13
- package/dist/components/PasswordInput/index.d.ts +0 -1
- package/dist/components/PasswordInput/index.js +0 -1
- package/dist/components/Popup/index.d.ts +0 -1
- package/dist/components/Popup/index.js +0 -1
- package/dist/components/Rating/Rating.svelte.d.ts +0 -7
- package/dist/components/Rating/index.d.ts +0 -1
- package/dist/components/Rating/index.js +0 -1
- package/dist/components/ScrollView/ScrollView.svelte +0 -285
- package/dist/components/ScrollView/ScrollView.svelte.d.ts +0 -19
- package/dist/components/ScrollView/index.d.ts +0 -1
- package/dist/components/ScrollView/index.js +0 -1
- package/dist/components/SearchInput/index.d.ts +0 -1
- package/dist/components/SearchInput/index.js +0 -1
- package/dist/components/Select/index.d.ts +0 -1
- package/dist/components/Select/index.js +0 -1
- package/dist/components/TextArea/TextArea.svelte.d.ts +0 -19
- package/dist/components/TextArea/index.d.ts +0 -1
- package/dist/components/TextArea/index.js +0 -1
- package/dist/components/ThemeSelector/ThemeSelector.svelte +0 -64
- package/dist/components/ThemeSelector/ThemeSelector.svelte.d.ts +0 -3
- package/dist/components/ThemeSelector/index.d.ts +0 -1
- package/dist/components/ThemeSelector/index.js +0 -1
- package/dist/components/TooltipHandler/TooltipHandler.svelte +0 -593
- package/dist/components/TooltipHandler/TooltipHandler.svelte.d.ts +0 -10
- package/dist/components/TooltipHandler/index.d.ts +0 -1
- package/dist/components/TooltipHandler/index.js +0 -1
- package/dist/styles/sizes.d.ts +0 -78
- package/dist/styles/sizes.js +0 -120
- package/dist/styles/variants.d.ts +0 -106
- package/dist/styles/variants.js +0 -194
- package/dist/types/ManagerTypes.d.ts +0 -42
- /package/dist/{types/ManagerTypes.js → data/table/types.js} +0 -0
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
/**
|
|
3
|
+
* Calendar — the themed month-grid primitive behind DatePicker. A pure inline calendar (no popup/
|
|
4
|
+
* trigger) so it can live in a Popup, a Dialog, or on a page. Values are ISO `YYYY-MM-DD` (local, not
|
|
5
|
+
* UTC-shifted).
|
|
6
|
+
*
|
|
7
|
+
* `mode="single"` binds `value`; `mode="range"` binds `start`/`end` and paints the band between them
|
|
8
|
+
* (with a live hover preview while picking the end). Keyboard: arrows move the day cursor (crossing
|
|
9
|
+
* months), Home/End jump to row ends, PageUp/PageDown change month, Enter/Space select.
|
|
10
|
+
*/
|
|
11
|
+
-->
|
|
12
|
+
<script lang="ts">
|
|
13
|
+
import type { Size } from "../types/sizes.js";
|
|
14
|
+
import { responsiveClasses, type Responsive } from "../types/responsive.js";
|
|
15
|
+
import { variantToken, type Variant } from "../types/variants.js";
|
|
16
|
+
import IconLeft from "~icons/mdi/chevron-left";
|
|
17
|
+
import IconRight from "~icons/mdi/chevron-right";
|
|
18
|
+
|
|
19
|
+
interface Props {
|
|
20
|
+
mode?: "single" | "range";
|
|
21
|
+
/** Single mode: selected date, ISO `YYYY-MM-DD`. Bindable. */
|
|
22
|
+
value?: string;
|
|
23
|
+
/** Range mode: endpoints, ISO `YYYY-MM-DD`. Bindable. */
|
|
24
|
+
start?: string;
|
|
25
|
+
end?: string;
|
|
26
|
+
min?: string;
|
|
27
|
+
max?: string;
|
|
28
|
+
weekStart?: 0 | 1;
|
|
29
|
+
locale?: string;
|
|
30
|
+
size?: Responsive<Size>;
|
|
31
|
+
/** Accent for the selected day + range band. Default primary. */
|
|
32
|
+
variant?: Variant;
|
|
33
|
+
class?: string;
|
|
34
|
+
onselect?: (iso: string) => void;
|
|
35
|
+
onrange?: (r: { start: string; end: string }) => void;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
let {
|
|
39
|
+
mode = "single",
|
|
40
|
+
value = $bindable(""),
|
|
41
|
+
start = $bindable(""),
|
|
42
|
+
end = $bindable(""),
|
|
43
|
+
min,
|
|
44
|
+
max,
|
|
45
|
+
weekStart,
|
|
46
|
+
locale = typeof navigator !== "undefined" ? navigator.language : "en-US",
|
|
47
|
+
size = "md",
|
|
48
|
+
variant = "primary",
|
|
49
|
+
class: cls = "",
|
|
50
|
+
onselect,
|
|
51
|
+
onrange,
|
|
52
|
+
}: Props = $props();
|
|
53
|
+
|
|
54
|
+
const accent = $derived(`var(${variantToken[variant]})`);
|
|
55
|
+
|
|
56
|
+
const iso = (dt: Date) =>
|
|
57
|
+
`${dt.getFullYear()}-${String(dt.getMonth() + 1).padStart(2, "0")}-${String(dt.getDate()).padStart(2, "0")}`;
|
|
58
|
+
const parse = (s: string) => {
|
|
59
|
+
const [y, m, d] = s.split("-").map(Number);
|
|
60
|
+
return new Date(y, m - 1, d);
|
|
61
|
+
};
|
|
62
|
+
const todayIso = iso(new Date());
|
|
63
|
+
|
|
64
|
+
const resolvedWeekStart = $derived.by<0 | 1>(() => {
|
|
65
|
+
if (weekStart === 0 || weekStart === 1) return weekStart;
|
|
66
|
+
try {
|
|
67
|
+
const loc = new Intl.Locale(locale) as Intl.Locale & {
|
|
68
|
+
weekInfo?: { firstDay: number };
|
|
69
|
+
getWeekInfo?: () => { firstDay: number };
|
|
70
|
+
};
|
|
71
|
+
const first = loc.weekInfo?.firstDay ?? loc.getWeekInfo?.().firstDay;
|
|
72
|
+
return first === 1 ? 1 : 0;
|
|
73
|
+
} catch {
|
|
74
|
+
return 0;
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
const seed = $derived(parse(value || start || todayIso));
|
|
79
|
+
let view = $state({ y: seed.getFullYear(), m: seed.getMonth() });
|
|
80
|
+
let cursor = $state(iso(seed));
|
|
81
|
+
let hover = $state(""); // range: previewed end while picking
|
|
82
|
+
|
|
83
|
+
$effect(() => {
|
|
84
|
+
const anchor = value || start;
|
|
85
|
+
if (!anchor) return;
|
|
86
|
+
const d = parse(anchor);
|
|
87
|
+
if (d.getFullYear() !== view.y || d.getMonth() !== view.m)
|
|
88
|
+
view = { y: d.getFullYear(), m: d.getMonth() };
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
const monthLabel = $derived(
|
|
92
|
+
new Intl.DateTimeFormat(locale, { month: "long", year: "numeric" }).format(
|
|
93
|
+
new Date(view.y, view.m, 1),
|
|
94
|
+
),
|
|
95
|
+
);
|
|
96
|
+
const weekdays = $derived.by(() => {
|
|
97
|
+
const fmt = new Intl.DateTimeFormat(locale, { weekday: "short" });
|
|
98
|
+
return Array.from({ length: 7 }, (_, i) =>
|
|
99
|
+
fmt.format(new Date(2024, 0, 7 + ((i + resolvedWeekStart) % 7))),
|
|
100
|
+
);
|
|
101
|
+
});
|
|
102
|
+
const cells = $derived.by(() => {
|
|
103
|
+
const first = new Date(view.y, view.m, 1);
|
|
104
|
+
const lead = (first.getDay() - resolvedWeekStart + 7) % 7;
|
|
105
|
+
return Array.from({ length: 42 }, (_, i) => new Date(view.y, view.m, 1 - lead + i));
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
const outOfBounds = (i: string) => !!((min && i < min) || (max && i > max));
|
|
109
|
+
|
|
110
|
+
// range: the low/high of the currently-painted span (committed end, else hover preview).
|
|
111
|
+
const selecting = $derived(mode === "range" && !!start && !end);
|
|
112
|
+
const previewEnd = $derived(end || (selecting ? hover : ""));
|
|
113
|
+
const lo = $derived(start && previewEnd ? (start < previewEnd ? start : previewEnd) : start);
|
|
114
|
+
const hi = $derived(start && previewEnd ? (start < previewEnd ? previewEnd : start) : "");
|
|
115
|
+
|
|
116
|
+
// Each field is a per-Size class map → responsiveClasses() so `size` may be scalar OR responsive.
|
|
117
|
+
const cellMap: Record<Size, string> = {
|
|
118
|
+
sm: "size-7 text-xs",
|
|
119
|
+
md: "size-8 text-sm",
|
|
120
|
+
lg: "size-10 text-base",
|
|
121
|
+
};
|
|
122
|
+
const headMap: Record<Size, string> = { sm: "h-9", md: "h-10", lg: "h-11" };
|
|
123
|
+
const labelMap: Record<Size, string> = { sm: "text-xs", md: "text-sm", lg: "text-base" };
|
|
124
|
+
const navMap: Record<Size, string> = { sm: "size-7", md: "size-8", lg: "size-9" };
|
|
125
|
+
const sizing = $derived({
|
|
126
|
+
cell: responsiveClasses(size, cellMap),
|
|
127
|
+
head: responsiveClasses(size, headMap),
|
|
128
|
+
label: responsiveClasses(size, labelMap),
|
|
129
|
+
nav: responsiveClasses(size, navMap),
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
function go(deltaMonths: number) {
|
|
133
|
+
const d = new Date(view.y, view.m + deltaMonths, 1);
|
|
134
|
+
view = { y: d.getFullYear(), m: d.getMonth() };
|
|
135
|
+
}
|
|
136
|
+
function pick(i: string) {
|
|
137
|
+
if (outOfBounds(i)) return;
|
|
138
|
+
cursor = i;
|
|
139
|
+
if (mode === "single") {
|
|
140
|
+
value = i;
|
|
141
|
+
onselect?.(i);
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
if (!start || (start && end)) {
|
|
145
|
+
start = i;
|
|
146
|
+
end = "";
|
|
147
|
+
onrange?.({ start: i, end: "" });
|
|
148
|
+
} else if (i < start) {
|
|
149
|
+
start = i;
|
|
150
|
+
onrange?.({ start: i, end: "" });
|
|
151
|
+
} else {
|
|
152
|
+
end = i;
|
|
153
|
+
onrange?.({ start, end: i });
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
function moveCursor(days: number) {
|
|
157
|
+
const d = parse(cursor);
|
|
158
|
+
d.setDate(d.getDate() + days);
|
|
159
|
+
cursor = iso(d);
|
|
160
|
+
if (d.getFullYear() !== view.y || d.getMonth() !== view.m)
|
|
161
|
+
view = { y: d.getFullYear(), m: d.getMonth() };
|
|
162
|
+
}
|
|
163
|
+
function onKey(e: KeyboardEvent) {
|
|
164
|
+
const k = e.key;
|
|
165
|
+
if (k === "ArrowLeft") moveCursor(-1);
|
|
166
|
+
else if (k === "ArrowRight") moveCursor(1);
|
|
167
|
+
else if (k === "ArrowUp") moveCursor(-7);
|
|
168
|
+
else if (k === "ArrowDown") moveCursor(7);
|
|
169
|
+
else if (k === "Home") moveCursor(-((parse(cursor).getDay() - resolvedWeekStart + 7) % 7));
|
|
170
|
+
else if (k === "End") moveCursor(6 - ((parse(cursor).getDay() - resolvedWeekStart + 7) % 7));
|
|
171
|
+
else if (k === "PageUp") go(-1);
|
|
172
|
+
else if (k === "PageDown") go(1);
|
|
173
|
+
else if (k === "Enter" || k === " ") pick(cursor);
|
|
174
|
+
else return;
|
|
175
|
+
e.preventDefault();
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
let gridEl = $state<HTMLDivElement>();
|
|
179
|
+
$effect(() => {
|
|
180
|
+
const btn = gridEl?.querySelector<HTMLButtonElement>(`[data-iso="${cursor}"]`);
|
|
181
|
+
if (btn && gridEl?.contains(document.activeElement)) btn.focus();
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
const subtle = "[color:color-mix(in_srgb,var(--ui-color-text)_55%,transparent)]";
|
|
185
|
+
</script>
|
|
186
|
+
|
|
187
|
+
<div
|
|
188
|
+
class="inline-block select-none rounded-[var(--ui-border-radius)] [color:var(--ui-color-text)] {cls}"
|
|
189
|
+
style="--accent: {accent}"
|
|
190
|
+
>
|
|
191
|
+
<div class="mb-1 flex items-center justify-between {sizing.head}">
|
|
192
|
+
<button
|
|
193
|
+
type="button"
|
|
194
|
+
aria-label="Previous month"
|
|
195
|
+
class="grid {sizing.nav} place-items-center rounded-[var(--ui-border-radius)] hover:[background-color:var(--ui-color-hover)] active:[background-color:var(--ui-color-active)]"
|
|
196
|
+
onclick={() => go(-1)}><IconLeft class="size-5" /></button
|
|
197
|
+
>
|
|
198
|
+
<span class="{sizing.label} font-medium">{monthLabel}</span>
|
|
199
|
+
<button
|
|
200
|
+
type="button"
|
|
201
|
+
aria-label="Next month"
|
|
202
|
+
class="grid {sizing.nav} place-items-center rounded-[var(--ui-border-radius)] hover:[background-color:var(--ui-color-hover)] active:[background-color:var(--ui-color-active)]"
|
|
203
|
+
onclick={() => go(1)}><IconRight class="size-5" /></button
|
|
204
|
+
>
|
|
205
|
+
</div>
|
|
206
|
+
|
|
207
|
+
<div class="grid grid-cols-7 {subtle}">
|
|
208
|
+
{#each weekdays as w (w)}<div class="grid {sizing.cell} place-items-center font-medium">
|
|
209
|
+
{w}
|
|
210
|
+
</div>{/each}
|
|
211
|
+
</div>
|
|
212
|
+
|
|
213
|
+
<!-- svelte-ignore a11y_no_noninteractive_tabindex -->
|
|
214
|
+
<div
|
|
215
|
+
bind:this={gridEl}
|
|
216
|
+
role="grid"
|
|
217
|
+
tabindex="-1"
|
|
218
|
+
class="grid grid-cols-7"
|
|
219
|
+
onkeydown={onKey}
|
|
220
|
+
onmouseleave={() => (hover = "")}
|
|
221
|
+
>
|
|
222
|
+
{#each cells as dt (iso(dt))}
|
|
223
|
+
{@const i = iso(dt)}
|
|
224
|
+
{@const inMonth = dt.getMonth() === view.m}
|
|
225
|
+
{@const edge =
|
|
226
|
+
mode === "single" ? i === value : i === start || i === end || (selecting && i === hover)}
|
|
227
|
+
{@const band = mode === "range" && !!lo && !!hi && i > lo && i < hi}
|
|
228
|
+
{@const isToday = i === todayIso}
|
|
229
|
+
{@const disabled = outOfBounds(i)}
|
|
230
|
+
<div
|
|
231
|
+
class="flex justify-center"
|
|
232
|
+
style={band ? "background-color: color-mix(in srgb, var(--accent) 14%, transparent)" : ""}
|
|
233
|
+
>
|
|
234
|
+
<button
|
|
235
|
+
type="button"
|
|
236
|
+
role="gridcell"
|
|
237
|
+
data-iso={i}
|
|
238
|
+
aria-selected={edge}
|
|
239
|
+
aria-current={isToday ? "date" : undefined}
|
|
240
|
+
tabindex={i === cursor ? 0 : -1}
|
|
241
|
+
{disabled}
|
|
242
|
+
class="grid {sizing.cell} place-items-center rounded-[var(--ui-border-radius)] transition-colors
|
|
243
|
+
{disabled ? 'cursor-not-allowed opacity-30' : 'cursor-pointer'}
|
|
244
|
+
{edge
|
|
245
|
+
? '[background-color:var(--accent)] font-semibold text-white'
|
|
246
|
+
: !disabled && !band
|
|
247
|
+
? 'hover:[background-color:var(--ui-color-hover)] active:[background-color:var(--ui-color-active)]'
|
|
248
|
+
: ''}
|
|
249
|
+
{!edge && !inMonth ? subtle : ''}
|
|
250
|
+
{!edge && isToday ? '[box-shadow:inset_0_0_0_1px_var(--ui-color-secondary)]' : ''}"
|
|
251
|
+
onclick={() => pick(i)}
|
|
252
|
+
onmouseenter={() => {
|
|
253
|
+
if (selecting) hover = i;
|
|
254
|
+
}}>{dt.getDate()}</button
|
|
255
|
+
>
|
|
256
|
+
</div>
|
|
257
|
+
{/each}
|
|
258
|
+
</div>
|
|
259
|
+
</div>
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { Size } from "../types/sizes.js";
|
|
2
|
+
import { type Responsive } from "../types/responsive.js";
|
|
3
|
+
import { type Variant } from "../types/variants.js";
|
|
4
|
+
interface Props {
|
|
5
|
+
mode?: "single" | "range";
|
|
6
|
+
/** Single mode: selected date, ISO `YYYY-MM-DD`. Bindable. */
|
|
7
|
+
value?: string;
|
|
8
|
+
/** Range mode: endpoints, ISO `YYYY-MM-DD`. Bindable. */
|
|
9
|
+
start?: string;
|
|
10
|
+
end?: string;
|
|
11
|
+
min?: string;
|
|
12
|
+
max?: string;
|
|
13
|
+
weekStart?: 0 | 1;
|
|
14
|
+
locale?: string;
|
|
15
|
+
size?: Responsive<Size>;
|
|
16
|
+
/** Accent for the selected day + range band. Default primary. */
|
|
17
|
+
variant?: Variant;
|
|
18
|
+
class?: string;
|
|
19
|
+
onselect?: (iso: string) => void;
|
|
20
|
+
onrange?: (r: {
|
|
21
|
+
start: string;
|
|
22
|
+
end: string;
|
|
23
|
+
}) => void;
|
|
24
|
+
}
|
|
25
|
+
declare const Calendar: import("svelte").Component<Props, {}, "start" | "end" | "value">;
|
|
26
|
+
type Calendar = ReturnType<typeof Calendar>;
|
|
27
|
+
export default Calendar;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
/**
|
|
3
|
+
* Card — a bordered surface with rounded corners. The CARD owns the padding, so a `CardHeader` /
|
|
4
|
+
* `CardFooter` separator sits INSIDE that padding (inset, not edge-to-edge). Compose with the
|
|
5
|
+
* sub-components for structure, or pass plain children for a simple panel.
|
|
6
|
+
*
|
|
7
|
+
* Border + radius come from the shared tint tokens (the same scheme Input/DataTable use, so surfaces
|
|
8
|
+
* match): the OUTER frame is the variant token at `--ui-tint-border` (rest) / `--ui-tint-border-hover`
|
|
9
|
+
* (hover) — one calc for every variant, no `secondary` special case — while inset Header/Footer
|
|
10
|
+
* separators stay soft (`--ui-border-color`). `variant` sets the border colour; `size` the padding.
|
|
11
|
+
*
|
|
12
|
+
* Background comes from `--ui-color-background` so the card reads as a raised panel over the page
|
|
13
|
+
* body (matches Input, Dialog, tooltip surface tokens). Themes remap this token to their own
|
|
14
|
+
* surface color; svelte-ui's default is `#ffffff` for a light-UI baseline.
|
|
15
|
+
*/
|
|
16
|
+
-->
|
|
17
|
+
<script lang="ts">
|
|
18
|
+
import type { Snippet } from "svelte";
|
|
19
|
+
import type { HTMLAttributes } from "svelte/elements";
|
|
20
|
+
import type { Size } from "../types/sizes.js";
|
|
21
|
+
import { responsiveClasses, type Responsive } from "../types/responsive.js";
|
|
22
|
+
import { variantToken, type Variant } from "../types/variants.js";
|
|
23
|
+
|
|
24
|
+
let {
|
|
25
|
+
variant = "secondary",
|
|
26
|
+
size = "md",
|
|
27
|
+
borderless = false,
|
|
28
|
+
class: cls = "",
|
|
29
|
+
children,
|
|
30
|
+
...rest
|
|
31
|
+
}: {
|
|
32
|
+
variant?: Variant;
|
|
33
|
+
size?: Responsive<Size>;
|
|
34
|
+
/** Drop the visible frame while keeping the 1px box: border colour = the card's own background.
|
|
35
|
+
* Defaults `false` — a Card reads as a framed surface. */
|
|
36
|
+
borderless?: boolean;
|
|
37
|
+
class?: string;
|
|
38
|
+
children?: Snippet;
|
|
39
|
+
} & Omit<HTMLAttributes<HTMLDivElement>, "class"> = $props();
|
|
40
|
+
|
|
41
|
+
const padFor: Record<Size, string> = { sm: "p-3", md: "p-4", lg: "p-6" };
|
|
42
|
+
// Border: ONE calc for EVERY variant (no `secondary`/`--ui-border-color-strong` special case) — the
|
|
43
|
+
// variant token at `--ui-tint-border` (rest) and `--ui-tint-border-hover` (hover), mixed toward
|
|
44
|
+
// transparent, same as Input/TextArea. `borderless` paints it the card's own background (frame gone,
|
|
45
|
+
// box unchanged). Rest goes in inline style (dynamic token); hover needs a class (inline can't do
|
|
46
|
+
// :hover), enumerated per-variant so Tailwind emits it.
|
|
47
|
+
const borderColor = $derived(
|
|
48
|
+
borderless
|
|
49
|
+
? "var(--ui-color-background)"
|
|
50
|
+
: `color-mix(in srgb, var(${variantToken[variant]}) var(--ui-tint-border), transparent)`,
|
|
51
|
+
);
|
|
52
|
+
const hoverBorderClass: Record<Variant, string> = {
|
|
53
|
+
secondary:
|
|
54
|
+
"hover:[border-color:color-mix(in_srgb,var(--ui-color-secondary)_var(--ui-tint-border-hover),transparent)]",
|
|
55
|
+
primary:
|
|
56
|
+
"hover:[border-color:color-mix(in_srgb,var(--ui-color-primary)_var(--ui-tint-border-hover),transparent)]",
|
|
57
|
+
danger:
|
|
58
|
+
"hover:[border-color:color-mix(in_srgb,var(--ui-color-error)_var(--ui-tint-border-hover),transparent)]",
|
|
59
|
+
info: "hover:[border-color:color-mix(in_srgb,var(--ui-color-info)_var(--ui-tint-border-hover),transparent)]",
|
|
60
|
+
success:
|
|
61
|
+
"hover:[border-color:color-mix(in_srgb,var(--ui-color-success)_var(--ui-tint-border-hover),transparent)]",
|
|
62
|
+
warning:
|
|
63
|
+
"hover:[border-color:color-mix(in_srgb,var(--ui-color-warning)_var(--ui-tint-border-hover),transparent)]",
|
|
64
|
+
neutral:
|
|
65
|
+
"hover:[border-color:color-mix(in_srgb,var(--ui-color-text)_var(--ui-tint-border-hover),transparent)]",
|
|
66
|
+
ghost:
|
|
67
|
+
"hover:[border-color:color-mix(in_srgb,var(--ui-color-text)_var(--ui-tint-border-hover),transparent)]",
|
|
68
|
+
};
|
|
69
|
+
const hoverClass = $derived(borderless ? "" : `transition-colors ${hoverBorderClass[variant]}`);
|
|
70
|
+
</script>
|
|
71
|
+
|
|
72
|
+
<div
|
|
73
|
+
class="border {responsiveClasses(size, padFor)} {hoverClass} {cls}"
|
|
74
|
+
style="border-radius: var(--ui-border-radius); border-color: {borderColor}; background: var(--ui-color-background)"
|
|
75
|
+
{...rest}
|
|
76
|
+
>
|
|
77
|
+
{@render children?.()}
|
|
78
|
+
</div>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Snippet } from "svelte";
|
|
2
|
+
import type { HTMLAttributes } from "svelte/elements";
|
|
3
|
+
import type { Size } from "../types/sizes.js";
|
|
4
|
+
import { type Responsive } from "../types/responsive.js";
|
|
5
|
+
import { type Variant } from "../types/variants.js";
|
|
6
|
+
type $$ComponentProps = {
|
|
7
|
+
variant?: Variant;
|
|
8
|
+
size?: Responsive<Size>;
|
|
9
|
+
/** Drop the visible frame while keeping the 1px box: border colour = the card's own background.
|
|
10
|
+
* Defaults `false` — a Card reads as a framed surface. */
|
|
11
|
+
borderless?: boolean;
|
|
12
|
+
class?: string;
|
|
13
|
+
children?: Snippet;
|
|
14
|
+
} & Omit<HTMLAttributes<HTMLDivElement>, "class">;
|
|
15
|
+
declare const Card: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
16
|
+
type Card = ReturnType<typeof Card>;
|
|
17
|
+
export default Card;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
/**
|
|
3
|
+
* CardBody — the main content region of a Card. A semantic wrapper; the Card already provides the
|
|
4
|
+
* padding, so this just groups the body content between an optional CardHeader and CardFooter. Pass a
|
|
5
|
+
* `class` for body-specific layout (e.g. `space-y-3`).
|
|
6
|
+
*/
|
|
7
|
+
-->
|
|
8
|
+
<script lang="ts">
|
|
9
|
+
import type { Snippet } from "svelte";
|
|
10
|
+
import type { HTMLAttributes } from "svelte/elements";
|
|
11
|
+
import type { Size } from "../types/sizes.js";
|
|
12
|
+
import { responsiveClasses, type Responsive } from "../types/responsive.js";
|
|
13
|
+
import { variantToken, type Variant } from "../types/variants.js";
|
|
14
|
+
|
|
15
|
+
let {
|
|
16
|
+
variant,
|
|
17
|
+
size = "md",
|
|
18
|
+
class: cls = "",
|
|
19
|
+
children,
|
|
20
|
+
...rest
|
|
21
|
+
}: {
|
|
22
|
+
/** Scopes the accent to the body subtree — points `--ui-accent` at the variant token (via
|
|
23
|
+
* `.ui-accent`), so interactive children (hover tints, etc.) pick up that colour. */
|
|
24
|
+
variant?: Variant;
|
|
25
|
+
/** Body text tier (sm/md/lg). */
|
|
26
|
+
size?: Responsive<Size>;
|
|
27
|
+
class?: string;
|
|
28
|
+
children?: Snippet;
|
|
29
|
+
} & Omit<HTMLAttributes<HTMLDivElement>, "class"> = $props();
|
|
30
|
+
|
|
31
|
+
const textMap: Record<Size, string> = { sm: "text-sm", md: "", lg: "text-lg" };
|
|
32
|
+
const accentVar = $derived(variant ? `--ui-accent: var(${variantToken[variant]});` : "");
|
|
33
|
+
</script>
|
|
34
|
+
|
|
35
|
+
<div
|
|
36
|
+
class="{variant ? 'ui-accent ' : ''}{responsiveClasses(size, textMap)} {cls}"
|
|
37
|
+
style={accentVar}
|
|
38
|
+
{...rest}
|
|
39
|
+
>
|
|
40
|
+
{@render children?.()}
|
|
41
|
+
</div>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Snippet } from "svelte";
|
|
2
|
+
import type { HTMLAttributes } from "svelte/elements";
|
|
3
|
+
import type { Size } from "../types/sizes.js";
|
|
4
|
+
import { type Responsive } from "../types/responsive.js";
|
|
5
|
+
import { type Variant } from "../types/variants.js";
|
|
6
|
+
type $$ComponentProps = {
|
|
7
|
+
/** Scopes the accent to the body subtree — points `--ui-accent` at the variant token (via
|
|
8
|
+
* `.ui-accent`), so interactive children (hover tints, etc.) pick up that colour. */
|
|
9
|
+
variant?: Variant;
|
|
10
|
+
/** Body text tier (sm/md/lg). */
|
|
11
|
+
size?: Responsive<Size>;
|
|
12
|
+
class?: string;
|
|
13
|
+
children?: Snippet;
|
|
14
|
+
} & Omit<HTMLAttributes<HTMLDivElement>, "class">;
|
|
15
|
+
declare const CardBody: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
16
|
+
type CardBody = ReturnType<typeof CardBody>;
|
|
17
|
+
export default CardBody;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
/**
|
|
3
|
+
* CardFooter — the bottom section of a Card, with a top separator (inset by the Card's padding). The
|
|
4
|
+
* separator is configurable HERE: `variant` sets its colour, `separator={false}` removes it, `size`
|
|
5
|
+
* sets the spacing. Lays out as a flex row with the content end-aligned (action buttons) by default;
|
|
6
|
+
* override via `class`.
|
|
7
|
+
*/
|
|
8
|
+
-->
|
|
9
|
+
<script lang="ts">
|
|
10
|
+
import type { Snippet } from "svelte";
|
|
11
|
+
import type { HTMLAttributes } from "svelte/elements";
|
|
12
|
+
import type { Size } from "../types/sizes.js";
|
|
13
|
+
import { responsiveClasses, type Responsive } from "../types/responsive.js";
|
|
14
|
+
import { variantToken, type Variant } from "../types/variants.js";
|
|
15
|
+
|
|
16
|
+
let {
|
|
17
|
+
variant = "secondary",
|
|
18
|
+
size = "md",
|
|
19
|
+
separator = true,
|
|
20
|
+
class: cls = "",
|
|
21
|
+
children,
|
|
22
|
+
...rest
|
|
23
|
+
}: {
|
|
24
|
+
variant?: Variant;
|
|
25
|
+
size?: Responsive<Size>;
|
|
26
|
+
/** Show the top separator (default true). */
|
|
27
|
+
separator?: boolean;
|
|
28
|
+
class?: string;
|
|
29
|
+
children?: Snippet;
|
|
30
|
+
} & Omit<HTMLAttributes<HTMLDivElement>, "class"> = $props();
|
|
31
|
+
|
|
32
|
+
const space: Record<Size, string> = { sm: "pt-2 mt-2", md: "pt-3 mt-3", lg: "pt-4 mt-4" };
|
|
33
|
+
// Neutral default (secondary) → the shared surface border; any other variant → that accent.
|
|
34
|
+
const sepColor = $derived(
|
|
35
|
+
variant === "secondary"
|
|
36
|
+
? "var(--ui-border-color)"
|
|
37
|
+
: `color-mix(in srgb, var(${variantToken[variant]}) var(--ui-tint-border), transparent)`,
|
|
38
|
+
);
|
|
39
|
+
</script>
|
|
40
|
+
|
|
41
|
+
<div
|
|
42
|
+
class="flex items-center justify-end gap-3 {separator
|
|
43
|
+
? 'border-t ' + responsiveClasses(size, space)
|
|
44
|
+
: ''} {cls}"
|
|
45
|
+
style={separator ? `border-color: ${sepColor}` : ""}
|
|
46
|
+
{...rest}
|
|
47
|
+
>
|
|
48
|
+
{@render children?.()}
|
|
49
|
+
</div>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Snippet } from "svelte";
|
|
2
|
+
import type { HTMLAttributes } from "svelte/elements";
|
|
3
|
+
import type { Size } from "../types/sizes.js";
|
|
4
|
+
import { type Responsive } from "../types/responsive.js";
|
|
5
|
+
import { type Variant } from "../types/variants.js";
|
|
6
|
+
type $$ComponentProps = {
|
|
7
|
+
variant?: Variant;
|
|
8
|
+
size?: Responsive<Size>;
|
|
9
|
+
/** Show the top separator (default true). */
|
|
10
|
+
separator?: boolean;
|
|
11
|
+
class?: string;
|
|
12
|
+
children?: Snippet;
|
|
13
|
+
} & Omit<HTMLAttributes<HTMLDivElement>, "class">;
|
|
14
|
+
declare const CardFooter: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
15
|
+
type CardFooter = ReturnType<typeof CardFooter>;
|
|
16
|
+
export default CardFooter;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
/**
|
|
3
|
+
* CardHeader — the top section of a Card, with a bottom separator. It lives inside the Card's padding,
|
|
4
|
+
* so the separator is naturally inset. The separator is configurable HERE: `variant` sets its colour,
|
|
5
|
+
* `separator={false}` removes it, `size` sets the spacing around it. Lays out as a flex row
|
|
6
|
+
* (title left, actions right) by default; override via `class`.
|
|
7
|
+
*/
|
|
8
|
+
-->
|
|
9
|
+
<script lang="ts">
|
|
10
|
+
import type { Snippet } from "svelte";
|
|
11
|
+
import type { HTMLAttributes } from "svelte/elements";
|
|
12
|
+
import type { Size } from "../types/sizes.js";
|
|
13
|
+
import { responsiveClasses, type Responsive } from "../types/responsive.js";
|
|
14
|
+
import { variantToken, type Variant } from "../types/variants.js";
|
|
15
|
+
|
|
16
|
+
let {
|
|
17
|
+
variant = "secondary",
|
|
18
|
+
size = "md",
|
|
19
|
+
separator = true,
|
|
20
|
+
class: cls = "",
|
|
21
|
+
children,
|
|
22
|
+
...rest
|
|
23
|
+
}: {
|
|
24
|
+
variant?: Variant;
|
|
25
|
+
size?: Responsive<Size>;
|
|
26
|
+
/** Show the bottom separator (default true). */
|
|
27
|
+
separator?: boolean;
|
|
28
|
+
class?: string;
|
|
29
|
+
children?: Snippet;
|
|
30
|
+
} & Omit<HTMLAttributes<HTMLDivElement>, "class"> = $props();
|
|
31
|
+
|
|
32
|
+
const space: Record<Size, string> = { sm: "pb-2 mb-2", md: "pb-3 mb-3", lg: "pb-4 mb-4" };
|
|
33
|
+
// Neutral default (secondary) → the shared surface border; any other variant → that accent.
|
|
34
|
+
const sepColor = $derived(
|
|
35
|
+
variant === "secondary"
|
|
36
|
+
? "var(--ui-border-color)"
|
|
37
|
+
: `color-mix(in srgb, var(${variantToken[variant]}) var(--ui-tint-border), transparent)`,
|
|
38
|
+
);
|
|
39
|
+
</script>
|
|
40
|
+
|
|
41
|
+
<div
|
|
42
|
+
class="flex items-center justify-between gap-3 {separator
|
|
43
|
+
? 'border-b ' + responsiveClasses(size, space)
|
|
44
|
+
: ''} {cls}"
|
|
45
|
+
style={separator ? `border-color: ${sepColor}` : ""}
|
|
46
|
+
{...rest}
|
|
47
|
+
>
|
|
48
|
+
{@render children?.()}
|
|
49
|
+
</div>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Snippet } from "svelte";
|
|
2
|
+
import type { HTMLAttributes } from "svelte/elements";
|
|
3
|
+
import type { Size } from "../types/sizes.js";
|
|
4
|
+
import { type Responsive } from "../types/responsive.js";
|
|
5
|
+
import { type Variant } from "../types/variants.js";
|
|
6
|
+
type $$ComponentProps = {
|
|
7
|
+
variant?: Variant;
|
|
8
|
+
size?: Responsive<Size>;
|
|
9
|
+
/** Show the bottom separator (default true). */
|
|
10
|
+
separator?: boolean;
|
|
11
|
+
class?: string;
|
|
12
|
+
children?: Snippet;
|
|
13
|
+
} & Omit<HTMLAttributes<HTMLDivElement>, "class">;
|
|
14
|
+
declare const CardHeader: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
15
|
+
type CardHeader = ReturnType<typeof CardHeader>;
|
|
16
|
+
export default CardHeader;
|