@spaethtech/svelte-ui 0.1.10 → 0.3.1-dev.10.ff03a8d

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 (218) hide show
  1. package/.claude/skills/svelte-ui/SKILL.md +118 -0
  2. package/.claude/skills/themes/SKILL.md +303 -0
  3. package/CLAUDE.md +248 -0
  4. package/README.md +180 -42
  5. package/dist/components/Alert.svelte +119 -0
  6. package/dist/components/Alert.svelte.d.ts +29 -0
  7. package/dist/components/Badge/Badge.svelte +142 -69
  8. package/dist/components/Badge/Badge.svelte.d.ts +26 -6
  9. package/dist/components/Badge/index.d.ts +1 -1
  10. package/dist/components/Badge/index.js +1 -1
  11. package/dist/components/Banner.svelte +133 -0
  12. package/dist/components/Banner.svelte.d.ts +31 -0
  13. package/dist/components/Button.svelte +240 -0
  14. package/dist/components/Button.svelte.d.ts +33 -0
  15. package/dist/components/ButtonDropdown.svelte +145 -0
  16. package/dist/components/ButtonDropdown.svelte.d.ts +31 -0
  17. package/dist/components/Calendar.svelte +259 -0
  18. package/dist/components/Calendar.svelte.d.ts +27 -0
  19. package/dist/components/Card.svelte +79 -0
  20. package/dist/components/Card.svelte.d.ts +17 -0
  21. package/dist/components/CardBody.svelte +41 -0
  22. package/dist/components/CardBody.svelte.d.ts +17 -0
  23. package/dist/components/CardFooter.svelte +51 -0
  24. package/dist/components/CardFooter.svelte.d.ts +16 -0
  25. package/dist/components/CardHeader.svelte +51 -0
  26. package/dist/components/CardHeader.svelte.d.ts +16 -0
  27. package/dist/components/Checkbox.svelte +131 -0
  28. package/dist/components/Checkbox.svelte.d.ts +16 -0
  29. package/dist/components/ConfirmDialog.svelte +103 -0
  30. package/dist/components/ConfirmDialog.svelte.d.ts +33 -0
  31. package/dist/components/DataTable.svelte +518 -0
  32. package/dist/components/DataTable.svelte.d.ts +74 -0
  33. package/dist/components/DatePicker.svelte +312 -0
  34. package/dist/components/DatePicker.svelte.d.ts +32 -0
  35. package/dist/components/DateTimeInput.svelte +93 -0
  36. package/dist/components/DateTimeInput.svelte.d.ts +20 -0
  37. package/dist/components/Dialog.svelte +151 -0
  38. package/dist/components/Dialog.svelte.d.ts +30 -0
  39. package/dist/components/{EmailInput/EmailInput.svelte → EmailInput.svelte} +17 -8
  40. package/dist/components/EmailInput.svelte.d.ts +21 -0
  41. package/dist/components/Input.svelte +369 -0
  42. package/dist/components/Input.svelte.d.ts +35 -0
  43. package/dist/components/{List/List.svelte → List.svelte} +194 -133
  44. package/dist/components/{List/List.svelte.d.ts → List.svelte.d.ts} +9 -1
  45. package/dist/components/Menu.svelte +117 -0
  46. package/dist/components/Menu.svelte.d.ts +20 -0
  47. package/dist/components/NotesEditor.svelte +127 -0
  48. package/dist/components/NotesEditor.svelte.d.ts +17 -0
  49. package/dist/components/{NumberInput/NumberInput.svelte → NumberInput.svelte} +146 -105
  50. package/dist/components/{NumberInput/NumberInput.svelte.d.ts → NumberInput.svelte.d.ts} +11 -4
  51. package/dist/components/PasswordInput.svelte +52 -0
  52. package/dist/components/PasswordInput.svelte.d.ts +20 -0
  53. package/dist/components/Popup.svelte +140 -0
  54. package/dist/components/Popup.svelte.d.ts +31 -0
  55. package/dist/components/Query.svelte +284 -0
  56. package/dist/components/Query.svelte.d.ts +15 -0
  57. package/dist/components/{Rating/Rating.svelte → Rating.svelte} +19 -10
  58. package/dist/components/Rating.svelte.d.ts +13 -0
  59. package/dist/components/{SearchInput/SearchInput.svelte → SearchInput.svelte} +19 -8
  60. package/dist/components/{SearchInput/SearchInput.svelte.d.ts → SearchInput.svelte.d.ts} +9 -2
  61. package/dist/components/{Select/Select.svelte → Select.svelte} +48 -76
  62. package/dist/components/{Select/Select.svelte.d.ts → Select.svelte.d.ts} +11 -1
  63. package/dist/components/SideBarMenu/SideBarMenu.svelte +724 -0
  64. package/dist/components/SideBarMenu/SideBarMenu.svelte.d.ts +109 -0
  65. package/dist/components/SideBarMenu/index.d.ts +2 -0
  66. package/dist/components/SideBarMenu/index.js +1 -0
  67. package/dist/components/TabStrip/TabStrip.svelte +384 -0
  68. package/dist/components/TabStrip/TabStrip.svelte.d.ts +50 -0
  69. package/dist/components/TabStrip/index.d.ts +3 -0
  70. package/dist/components/TabStrip/index.js +2 -0
  71. package/dist/components/{TextArea/TextArea.svelte → TextArea.svelte} +143 -112
  72. package/dist/components/TextArea.svelte.d.ts +38 -0
  73. package/dist/components/ThemeSelector.svelte +81 -0
  74. package/dist/components/ThemeSelector.svelte.d.ts +10 -0
  75. package/dist/components/TimePicker.svelte +148 -0
  76. package/dist/components/TimePicker.svelte.d.ts +28 -0
  77. package/dist/components/TimeRangeInput.svelte +203 -0
  78. package/dist/components/TimeRangeInput.svelte.d.ts +29 -0
  79. package/dist/components/TimeSpinner.svelte +202 -0
  80. package/dist/components/TimeSpinner.svelte.d.ts +26 -0
  81. package/dist/components/Toast/Toaster.svelte +51 -0
  82. package/dist/components/Toast/Toaster.svelte.d.ts +12 -0
  83. package/dist/components/Toast/toast.svelte.d.ts +29 -0
  84. package/dist/components/Toast/toast.svelte.js +27 -0
  85. package/dist/components/Toggle.svelte +93 -0
  86. package/dist/components/Toggle.svelte.d.ts +15 -0
  87. package/dist/data/dataset.d.ts +42 -0
  88. package/dist/data/dataset.js +3 -0
  89. package/dist/data/index.d.ts +3 -0
  90. package/dist/data/index.js +3 -0
  91. package/dist/data/query/ast.d.ts +62 -0
  92. package/dist/data/query/ast.js +12 -0
  93. package/dist/data/query/index.d.ts +3 -0
  94. package/dist/data/query/index.js +3 -0
  95. package/dist/data/query/lexer.d.ts +33 -0
  96. package/dist/data/query/lexer.js +225 -0
  97. package/dist/data/query/parser.d.ts +11 -0
  98. package/dist/data/query/parser.js +252 -0
  99. package/dist/data/table/grid.svelte.d.ts +57 -0
  100. package/dist/data/table/grid.svelte.js +139 -0
  101. package/dist/data/table/index.d.ts +2 -0
  102. package/dist/data/table/index.js +2 -0
  103. package/dist/data/table/types.d.ts +79 -0
  104. package/dist/index.d.ts +49 -22
  105. package/dist/index.js +46 -21
  106. package/dist/positioning/anchored.d.ts +61 -0
  107. package/dist/positioning/anchored.js +122 -0
  108. package/dist/positioning/tooltip.d.ts +41 -0
  109. package/dist/positioning/tooltip.js +147 -0
  110. package/dist/theme.css +205 -0
  111. package/dist/types/breakpoints.d.ts +24 -0
  112. package/dist/types/breakpoints.js +13 -0
  113. package/dist/types/responsive.d.ts +32 -0
  114. package/dist/types/responsive.js +54 -0
  115. package/dist/types/sizes.d.ts +10 -3
  116. package/dist/types/time.d.ts +19 -0
  117. package/dist/types/time.js +10 -0
  118. package/dist/types/variants.d.ts +8 -1
  119. package/dist/types/variants.js +16 -1
  120. package/docs/components.md +255 -0
  121. package/docs/examples.md +323 -0
  122. package/docs/paradigm.md +240 -0
  123. package/docs/themes.md +170 -0
  124. package/docs/usage.md +450 -0
  125. package/package.json +97 -63
  126. package/dist/components/Button/Button.svelte +0 -172
  127. package/dist/components/Button/Button.svelte.d.ts +0 -32
  128. package/dist/components/Button/index.d.ts +0 -1
  129. package/dist/components/Button/index.js +0 -1
  130. package/dist/components/Dialog/Dialog.svelte +0 -101
  131. package/dist/components/Dialog/Dialog.svelte.d.ts +0 -18
  132. package/dist/components/Dialog/index.d.ts +0 -1
  133. package/dist/components/Dialog/index.js +0 -1
  134. package/dist/components/ElementManager/ElementManager.svelte +0 -397
  135. package/dist/components/ElementManager/ElementManager.svelte.d.ts +0 -43
  136. package/dist/components/ElementManager/index.d.ts +0 -1
  137. package/dist/components/ElementManager/index.js +0 -1
  138. package/dist/components/EmailInput/EmailInput.svelte.d.ts +0 -14
  139. package/dist/components/EmailInput/index.d.ts +0 -1
  140. package/dist/components/EmailInput/index.js +0 -1
  141. package/dist/components/Icon/Icon.svelte +0 -74
  142. package/dist/components/Icon/Icon.svelte.d.ts +0 -13
  143. package/dist/components/Icon/index.d.ts +0 -1
  144. package/dist/components/Icon/index.js +0 -1
  145. package/dist/components/Input/Input.svelte +0 -268
  146. package/dist/components/Input/Input.svelte.d.ts +0 -18
  147. package/dist/components/Input/index.d.ts +0 -1
  148. package/dist/components/Input/index.js +0 -1
  149. package/dist/components/List/index.d.ts +0 -1
  150. package/dist/components/List/index.js +0 -1
  151. package/dist/components/ListItem/ListItem.svelte +0 -175
  152. package/dist/components/ListItem/ListItem.svelte.d.ts +0 -24
  153. package/dist/components/ListItem/index.d.ts +0 -2
  154. package/dist/components/ListItem/index.js +0 -2
  155. package/dist/components/ListView/ListView.svelte +0 -463
  156. package/dist/components/ListView/ListView.svelte.d.ts +0 -37
  157. package/dist/components/ListView/index.d.ts +0 -2
  158. package/dist/components/ListView/index.js +0 -2
  159. package/dist/components/NodeGraph/BaseNode.d.ts +0 -57
  160. package/dist/components/NodeGraph/BaseNode.js +0 -30
  161. package/dist/components/NodeGraph/Edge.svelte +0 -60
  162. package/dist/components/NodeGraph/Edge.svelte.d.ts +0 -16
  163. package/dist/components/NodeGraph/ExpressionEvaluator.d.ts +0 -82
  164. package/dist/components/NodeGraph/ExpressionEvaluator.js +0 -152
  165. package/dist/components/NodeGraph/Node.svelte +0 -100
  166. package/dist/components/NodeGraph/Node.svelte.d.ts +0 -10
  167. package/dist/components/NodeGraph/NodeGraph.svelte +0 -52
  168. package/dist/components/NodeGraph/NodeGraph.svelte.d.ts +0 -14
  169. package/dist/components/NodeGraph/NodeInstance.svelte.d.ts +0 -80
  170. package/dist/components/NodeGraph/NodeInstance.svelte.js +0 -241
  171. package/dist/components/NodeGraph/NodePort.svelte +0 -75
  172. package/dist/components/NodeGraph/NodePort.svelte.d.ts +0 -11
  173. package/dist/components/NodeGraph/decorators.d.ts +0 -81
  174. package/dist/components/NodeGraph/decorators.js +0 -148
  175. package/dist/components/NodeGraph/index.d.ts +0 -9
  176. package/dist/components/NodeGraph/index.js +0 -9
  177. package/dist/components/NodeGraph/types.d.ts +0 -94
  178. package/dist/components/NodeGraph/types.js +0 -33
  179. package/dist/components/NotesEditor/NotesEditor.svelte +0 -203
  180. package/dist/components/NotesEditor/NotesEditor.svelte.d.ts +0 -9
  181. package/dist/components/NotesEditor/index.d.ts +0 -1
  182. package/dist/components/NotesEditor/index.js +0 -1
  183. package/dist/components/NumberInput/index.d.ts +0 -1
  184. package/dist/components/NumberInput/index.js +0 -1
  185. package/dist/components/PasswordInput/PasswordInput.svelte +0 -41
  186. package/dist/components/PasswordInput/PasswordInput.svelte.d.ts +0 -13
  187. package/dist/components/PasswordInput/index.d.ts +0 -1
  188. package/dist/components/PasswordInput/index.js +0 -1
  189. package/dist/components/Popup/index.d.ts +0 -1
  190. package/dist/components/Popup/index.js +0 -1
  191. package/dist/components/Rating/Rating.svelte.d.ts +0 -7
  192. package/dist/components/Rating/index.d.ts +0 -1
  193. package/dist/components/Rating/index.js +0 -1
  194. package/dist/components/ScrollView/ScrollView.svelte +0 -285
  195. package/dist/components/ScrollView/ScrollView.svelte.d.ts +0 -19
  196. package/dist/components/ScrollView/index.d.ts +0 -1
  197. package/dist/components/ScrollView/index.js +0 -1
  198. package/dist/components/SearchInput/index.d.ts +0 -1
  199. package/dist/components/SearchInput/index.js +0 -1
  200. package/dist/components/Select/index.d.ts +0 -1
  201. package/dist/components/Select/index.js +0 -1
  202. package/dist/components/TextArea/TextArea.svelte.d.ts +0 -19
  203. package/dist/components/TextArea/index.d.ts +0 -1
  204. package/dist/components/TextArea/index.js +0 -1
  205. package/dist/components/ThemeSelector/ThemeSelector.svelte +0 -64
  206. package/dist/components/ThemeSelector/ThemeSelector.svelte.d.ts +0 -3
  207. package/dist/components/ThemeSelector/index.d.ts +0 -1
  208. package/dist/components/ThemeSelector/index.js +0 -1
  209. package/dist/components/TooltipHandler/TooltipHandler.svelte +0 -593
  210. package/dist/components/TooltipHandler/TooltipHandler.svelte.d.ts +0 -10
  211. package/dist/components/TooltipHandler/index.d.ts +0 -1
  212. package/dist/components/TooltipHandler/index.js +0 -1
  213. package/dist/styles/sizes.d.ts +0 -78
  214. package/dist/styles/sizes.js +0 -120
  215. package/dist/styles/variants.d.ts +0 -106
  216. package/dist/styles/variants.js +0 -194
  217. package/dist/types/ManagerTypes.d.ts +0 -42
  218. /package/dist/{types/ManagerTypes.js → data/table/types.js} +0 -0
@@ -0,0 +1,131 @@
1
+ <!--
2
+ /**
3
+ * Checkbox — a themed multi-state box (unchecked / checked / indeterminate). Use this, NOT a Toggle,
4
+ * for selection semantics: a row is / isn't selected, a rule does / doesn't apply, a filter is / isn't
5
+ * active. A real `<input type=checkbox>` drives it — laid INVISIBLY over the whole control, so clicking
6
+ * anywhere toggles it (naturally clickable + testable + accessible + form-friendly; `bind:checked`
7
+ * works, and `onchange` fires a real event). Honours the shared {@link Variant} (the "checked" colour)
8
+ * + {@link Size} axes.
9
+ *
10
+ * ALIGNMENT: same story as Toggle — the visible box is deliberately smaller than a text control, but
11
+ * the Checkbox occupies a wrapper sized to the standard control HEIGHT for its `size` (sm 24 / md 32 /
12
+ * lg 40px — same as Input), with the box centred inside. Drop it next to a `size`-matched Input/Select
13
+ * and everything lines up on the same baseline; the full-height wrapper is the click target while the
14
+ * box itself stays box-sized.
15
+ */
16
+ -->
17
+ <script lang="ts">
18
+ import type { HTMLInputAttributes } from "svelte/elements";
19
+ import type { Size } from "../types/sizes.js";
20
+ import { responsiveClasses, type Responsive } from "../types/responsive.js";
21
+ import { variantToken, type Variant } from "../types/variants.js";
22
+
23
+ let {
24
+ checked = $bindable(false),
25
+ indeterminate = false,
26
+ disabled = false,
27
+ size = "md",
28
+ variant = "primary",
29
+ class: cls = "",
30
+ ...rest
31
+ }: {
32
+ checked?: boolean;
33
+ indeterminate?: boolean;
34
+ disabled?: boolean;
35
+ size?: Responsive<Size>;
36
+ /** The colour of the "checked" state (default primary). */
37
+ variant?: Variant;
38
+ class?: string;
39
+ } & Omit<HTMLInputAttributes, "size" | "type" | "class"> = $props();
40
+
41
+ // Per size: visible box dimension. Same scale as icons (14 / 16 / 20 px) so the box aligns with
42
+ // adjacent MDI icons at the matching size.
43
+ const dims: Record<Size, string> = {
44
+ sm: "size-3.5",
45
+ md: "size-4",
46
+ lg: "size-5",
47
+ };
48
+ const iconSize: Record<Size, string> = {
49
+ sm: "size-3",
50
+ md: "size-3.5",
51
+ lg: "size-4",
52
+ };
53
+ // Wrapper height matches Input's h-6/h-8/h-10 so the box centres on the same baseline as sibling
54
+ // controls at the same `size`.
55
+ const heightMap: Record<Size, string> = { sm: "h-6", md: "h-8", lg: "h-10" };
56
+ const heightClass = $derived(responsiveClasses(size, heightMap));
57
+ const boxSize = $derived(responsiveClasses(size, dims));
58
+ const iconSizeCls = $derived(responsiveClasses(size, iconSize));
59
+ const filled = $derived(checked || indeterminate);
60
+ const variantVar = $derived(`var(${variantToken[variant]})`);
61
+ const boxStyle = $derived(
62
+ filled
63
+ ? `background-color: ${variantVar}; border-color: ${variantVar};`
64
+ : `background-color: transparent; border-color: color-mix(in srgb, var(--ui-color-text) 40%, transparent);`,
65
+ );
66
+ // Mark colour = the INVERTED text colour (`--ui-color-background`) with a hint of the variant mixed
67
+ // in — ONE rule for every variant, both themes (matches the Toggle knob). Light: near-white on the
68
+ // fill; dark: flips dark, which reads on the dark theme's brighter accent fills. The 80% background
69
+ // keeps it contrasting even on a neutral (`--ui-color-text`) fill.
70
+ const markColor = $derived(
71
+ `color-mix(in srgb, var(--ui-color-background) 80%, var(${variantToken[variant]}))`,
72
+ );
73
+
74
+ let el = $state<HTMLInputElement>();
75
+ // `indeterminate` is a DOM property, not an attribute — sync it imperatively so the real
76
+ // checkbox reports the tri-state to a11y and form serialization.
77
+ $effect(() => {
78
+ if (el) el.indeterminate = indeterminate;
79
+ });
80
+ </script>
81
+
82
+ <label
83
+ class="relative inline-flex shrink-0 items-center justify-center {heightClass} {disabled
84
+ ? 'cursor-not-allowed opacity-50'
85
+ : 'cursor-pointer'} {cls}"
86
+ >
87
+ <!-- Real checkbox — invisible, covering the whole control so a click anywhere toggles it and
88
+ keyboard/focus/screen-reader behavior is native. -->
89
+ <input
90
+ bind:this={el}
91
+ type="checkbox"
92
+ bind:checked
93
+ {disabled}
94
+ class="peer absolute inset-0 z-10 m-0 cursor-pointer opacity-0 disabled:cursor-not-allowed"
95
+ {...rest}
96
+ />
97
+ <span
98
+ class="relative inline-flex items-center justify-center rounded-[3px] border transition-colors duration-150 peer-focus-visible:outline peer-focus-visible:outline-2 peer-focus-visible:outline-offset-2 peer-focus-visible:[outline-color:var(--ui-color-primary)] {boxSize}"
99
+ style={boxStyle}
100
+ >
101
+ {#if indeterminate}
102
+ <!-- Dash for indeterminate — mid-line, contrasting mark on the filled background. -->
103
+ <svg
104
+ viewBox="0 0 16 16"
105
+ class={iconSizeCls}
106
+ style="color: {markColor}"
107
+ fill="none"
108
+ stroke="currentColor"
109
+ stroke-width="2.5"
110
+ stroke-linecap="round"
111
+ >
112
+ <line x1="4" y1="8" x2="12" y2="8" />
113
+ </svg>
114
+ {:else if checked}
115
+ <!-- Checkmark — sits inside the filled box. Stroke uses currentColor; `markColor` picks white
116
+ on accent fills, the background colour on neutral/ghost (which are text-coloured). -->
117
+ <svg
118
+ viewBox="0 0 16 16"
119
+ class={iconSizeCls}
120
+ style="color: {markColor}"
121
+ fill="none"
122
+ stroke="currentColor"
123
+ stroke-width="2.5"
124
+ stroke-linecap="round"
125
+ stroke-linejoin="round"
126
+ >
127
+ <polyline points="3.5,8.5 6.5,11.5 12.5,5" />
128
+ </svg>
129
+ {/if}
130
+ </span>
131
+ </label>
@@ -0,0 +1,16 @@
1
+ import type { HTMLInputAttributes } from "svelte/elements";
2
+ import type { Size } from "../types/sizes.js";
3
+ import { type Responsive } from "../types/responsive.js";
4
+ import { type Variant } from "../types/variants.js";
5
+ type $$ComponentProps = {
6
+ checked?: boolean;
7
+ indeterminate?: boolean;
8
+ disabled?: boolean;
9
+ size?: Responsive<Size>;
10
+ /** The colour of the "checked" state (default primary). */
11
+ variant?: Variant;
12
+ class?: string;
13
+ } & Omit<HTMLInputAttributes, "size" | "type" | "class">;
14
+ declare const Checkbox: import("svelte").Component<$$ComponentProps, {}, "checked">;
15
+ type Checkbox = ReturnType<typeof Checkbox>;
16
+ export default Checkbox;
@@ -0,0 +1,103 @@
1
+ <script lang="ts">
2
+ import Dialog from "./Dialog.svelte";
3
+ import Card from "./Card.svelte";
4
+ import CardHeader from "./CardHeader.svelte";
5
+ import CardFooter from "./CardFooter.svelte";
6
+ import Button from "./Button.svelte";
7
+ import type { Snippet } from "svelte";
8
+ import type { Size } from "../types/sizes.js";
9
+ import type { Responsive } from "../types/responsive.js";
10
+
11
+ /**
12
+ * ConfirmDialog — the common title + message + Confirm/Cancel modal, built on the `Dialog` shell.
13
+ * It composes a `Card` (`CardHeader` title, body, `CardFooter` actions) inside `Dialog`, so it stays
14
+ * consistent with every other surface. Pass `children` to replace the message body with custom
15
+ * content (the header + footer stay). For a fully custom modal, use `Dialog` directly.
16
+ */
17
+ interface Props {
18
+ isOpen: boolean;
19
+ title?: string;
20
+ message?: string;
21
+ confirmText?: string;
22
+ cancelText?: string;
23
+ onConfirm?: () => void;
24
+ onCancel?: () => void;
25
+ variant?: "danger" | "normal";
26
+ /** Density tier — forwarded to the Card / CardHeader / CardFooter. */
27
+ size?: Responsive<Size>;
28
+ showConfirm?: boolean;
29
+ showCancel?: boolean;
30
+ /** Allow dismissing by backdrop / Escape (default true). */
31
+ dismissible?: boolean;
32
+ /** Forwarded to the Dialog shell — any CSS value (default: content-sized, capped at 32rem). */
33
+ width?: string;
34
+ height?: string;
35
+ /** Custom body between header and footer (replaces `message`). */
36
+ children?: Snippet;
37
+ }
38
+
39
+ let {
40
+ isOpen = $bindable(),
41
+ title = "Dialog",
42
+ message,
43
+ confirmText = "Confirm",
44
+ cancelText = "Cancel",
45
+ onConfirm,
46
+ onCancel,
47
+ variant = "normal",
48
+ size = "md",
49
+ showConfirm = true,
50
+ showCancel = true,
51
+ dismissible = true,
52
+ width,
53
+ height,
54
+ children,
55
+ }: Props = $props();
56
+
57
+ function handleConfirm() {
58
+ onConfirm?.();
59
+ isOpen = false;
60
+ }
61
+ function handleCancel() {
62
+ onCancel?.();
63
+ isOpen = false;
64
+ }
65
+ </script>
66
+
67
+ <Dialog
68
+ bind:isOpen
69
+ {dismissible}
70
+ {width}
71
+ {height}
72
+ onClose={onCancel}
73
+ aria-label={title}
74
+ >
75
+ <Card {size} class="w-full shadow-xl">
76
+ <CardHeader {size}>
77
+ <h3 class="text-lg font-medium [color:var(--ui-color-text)]">{title}</h3>
78
+ </CardHeader>
79
+
80
+ {#if children}
81
+ {@render children()}
82
+ {:else if message}
83
+ <p class="text-sm [color:color-mix(in_srgb,var(--ui-color-text)_70%,transparent)]">
84
+ {message}
85
+ </p>
86
+ {/if}
87
+
88
+ {#if showConfirm || showCancel}
89
+ <CardFooter {size}>
90
+ {#if showCancel}
91
+ <Button text={cancelText} onclick={handleCancel} variant="secondary" />
92
+ {/if}
93
+ {#if showConfirm}
94
+ <Button
95
+ text={confirmText}
96
+ onclick={handleConfirm}
97
+ variant={variant === "danger" ? "danger" : "primary"}
98
+ />
99
+ {/if}
100
+ </CardFooter>
101
+ {/if}
102
+ </Card>
103
+ </Dialog>
@@ -0,0 +1,33 @@
1
+ import type { Snippet } from "svelte";
2
+ import type { Size } from "../types/sizes.js";
3
+ import type { Responsive } from "../types/responsive.js";
4
+ /**
5
+ * ConfirmDialog — the common title + message + Confirm/Cancel modal, built on the `Dialog` shell.
6
+ * It composes a `Card` (`CardHeader` title, body, `CardFooter` actions) inside `Dialog`, so it stays
7
+ * consistent with every other surface. Pass `children` to replace the message body with custom
8
+ * content (the header + footer stay). For a fully custom modal, use `Dialog` directly.
9
+ */
10
+ interface Props {
11
+ isOpen: boolean;
12
+ title?: string;
13
+ message?: string;
14
+ confirmText?: string;
15
+ cancelText?: string;
16
+ onConfirm?: () => void;
17
+ onCancel?: () => void;
18
+ variant?: "danger" | "normal";
19
+ /** Density tier — forwarded to the Card / CardHeader / CardFooter. */
20
+ size?: Responsive<Size>;
21
+ showConfirm?: boolean;
22
+ showCancel?: boolean;
23
+ /** Allow dismissing by backdrop / Escape (default true). */
24
+ dismissible?: boolean;
25
+ /** Forwarded to the Dialog shell — any CSS value (default: content-sized, capped at 32rem). */
26
+ width?: string;
27
+ height?: string;
28
+ /** Custom body between header and footer (replaces `message`). */
29
+ children?: Snippet;
30
+ }
31
+ declare const ConfirmDialog: import("svelte").Component<Props, {}, "isOpen">;
32
+ type ConfirmDialog = ReturnType<typeof ConfirmDialog>;
33
+ export default ConfirmDialog;