@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.
Files changed (208) hide show
  1. package/README.md +180 -42
  2. package/dist/components/Alert.svelte +119 -0
  3. package/dist/components/Alert.svelte.d.ts +29 -0
  4. package/dist/components/Badge/Badge.svelte +142 -69
  5. package/dist/components/Badge/Badge.svelte.d.ts +26 -6
  6. package/dist/components/Badge/index.d.ts +1 -1
  7. package/dist/components/Badge/index.js +1 -1
  8. package/dist/components/Banner.svelte +133 -0
  9. package/dist/components/Banner.svelte.d.ts +31 -0
  10. package/dist/components/Button.svelte +240 -0
  11. package/dist/components/Button.svelte.d.ts +33 -0
  12. package/dist/components/ButtonDropdown.svelte +145 -0
  13. package/dist/components/ButtonDropdown.svelte.d.ts +31 -0
  14. package/dist/components/Calendar.svelte +259 -0
  15. package/dist/components/Calendar.svelte.d.ts +27 -0
  16. package/dist/components/Card.svelte +78 -0
  17. package/dist/components/Card.svelte.d.ts +17 -0
  18. package/dist/components/CardBody.svelte +41 -0
  19. package/dist/components/CardBody.svelte.d.ts +17 -0
  20. package/dist/components/CardFooter.svelte +49 -0
  21. package/dist/components/CardFooter.svelte.d.ts +16 -0
  22. package/dist/components/CardHeader.svelte +49 -0
  23. package/dist/components/CardHeader.svelte.d.ts +16 -0
  24. package/dist/components/Checkbox.svelte +131 -0
  25. package/dist/components/Checkbox.svelte.d.ts +16 -0
  26. package/dist/components/DataTable.svelte +518 -0
  27. package/dist/components/DataTable.svelte.d.ts +74 -0
  28. package/dist/components/DatePicker.svelte +312 -0
  29. package/dist/components/DatePicker.svelte.d.ts +32 -0
  30. package/dist/components/DateTimeInput.svelte +93 -0
  31. package/dist/components/DateTimeInput.svelte.d.ts +20 -0
  32. package/dist/components/Dialog.svelte +132 -0
  33. package/dist/components/Dialog.svelte.d.ts +24 -0
  34. package/dist/components/{EmailInput/EmailInput.svelte → EmailInput.svelte} +17 -8
  35. package/dist/components/EmailInput.svelte.d.ts +21 -0
  36. package/dist/components/Input.svelte +369 -0
  37. package/dist/components/Input.svelte.d.ts +35 -0
  38. package/dist/components/{List/List.svelte → List.svelte} +194 -133
  39. package/dist/components/{List/List.svelte.d.ts → List.svelte.d.ts} +9 -1
  40. package/dist/components/Menu.svelte +117 -0
  41. package/dist/components/Menu.svelte.d.ts +20 -0
  42. package/dist/components/NotesEditor.svelte +127 -0
  43. package/dist/components/NotesEditor.svelte.d.ts +17 -0
  44. package/dist/components/{NumberInput/NumberInput.svelte → NumberInput.svelte} +146 -105
  45. package/dist/components/{NumberInput/NumberInput.svelte.d.ts → NumberInput.svelte.d.ts} +11 -4
  46. package/dist/components/PasswordInput.svelte +52 -0
  47. package/dist/components/PasswordInput.svelte.d.ts +20 -0
  48. package/dist/components/Popup.svelte +140 -0
  49. package/dist/components/Popup.svelte.d.ts +31 -0
  50. package/dist/components/Query.svelte +284 -0
  51. package/dist/components/Query.svelte.d.ts +15 -0
  52. package/dist/components/{Rating/Rating.svelte → Rating.svelte} +19 -10
  53. package/dist/components/Rating.svelte.d.ts +13 -0
  54. package/dist/components/{SearchInput/SearchInput.svelte → SearchInput.svelte} +19 -8
  55. package/dist/components/{SearchInput/SearchInput.svelte.d.ts → SearchInput.svelte.d.ts} +9 -2
  56. package/dist/components/{Select/Select.svelte → Select.svelte} +48 -76
  57. package/dist/components/{Select/Select.svelte.d.ts → Select.svelte.d.ts} +11 -1
  58. package/dist/components/SideBarMenu/SideBarMenu.svelte +724 -0
  59. package/dist/components/SideBarMenu/SideBarMenu.svelte.d.ts +109 -0
  60. package/dist/components/SideBarMenu/index.d.ts +2 -0
  61. package/dist/components/SideBarMenu/index.js +1 -0
  62. package/dist/components/TabStrip/TabStrip.svelte +384 -0
  63. package/dist/components/TabStrip/TabStrip.svelte.d.ts +50 -0
  64. package/dist/components/TabStrip/index.d.ts +3 -0
  65. package/dist/components/TabStrip/index.js +2 -0
  66. package/dist/components/{TextArea/TextArea.svelte → TextArea.svelte} +143 -112
  67. package/dist/components/TextArea.svelte.d.ts +38 -0
  68. package/dist/components/ThemeSelector.svelte +81 -0
  69. package/dist/components/ThemeSelector.svelte.d.ts +10 -0
  70. package/dist/components/TimePicker.svelte +148 -0
  71. package/dist/components/TimePicker.svelte.d.ts +28 -0
  72. package/dist/components/TimeRangeInput.svelte +203 -0
  73. package/dist/components/TimeRangeInput.svelte.d.ts +29 -0
  74. package/dist/components/TimeSpinner.svelte +202 -0
  75. package/dist/components/TimeSpinner.svelte.d.ts +26 -0
  76. package/dist/components/Toast/Toaster.svelte +51 -0
  77. package/dist/components/Toast/Toaster.svelte.d.ts +12 -0
  78. package/dist/components/Toast/toast.svelte.d.ts +29 -0
  79. package/dist/components/Toast/toast.svelte.js +27 -0
  80. package/dist/components/Toggle.svelte +93 -0
  81. package/dist/components/Toggle.svelte.d.ts +15 -0
  82. package/dist/data/dataset.d.ts +42 -0
  83. package/dist/data/dataset.js +3 -0
  84. package/dist/data/index.d.ts +3 -0
  85. package/dist/data/index.js +3 -0
  86. package/dist/data/query/ast.d.ts +62 -0
  87. package/dist/data/query/ast.js +12 -0
  88. package/dist/data/query/index.d.ts +3 -0
  89. package/dist/data/query/index.js +3 -0
  90. package/dist/data/query/lexer.d.ts +33 -0
  91. package/dist/data/query/lexer.js +225 -0
  92. package/dist/data/query/parser.d.ts +11 -0
  93. package/dist/data/query/parser.js +252 -0
  94. package/dist/data/table/grid.svelte.d.ts +57 -0
  95. package/dist/data/table/grid.svelte.js +139 -0
  96. package/dist/data/table/index.d.ts +2 -0
  97. package/dist/data/table/index.js +2 -0
  98. package/dist/data/table/types.d.ts +79 -0
  99. package/dist/index.d.ts +48 -22
  100. package/dist/index.js +45 -21
  101. package/dist/positioning/anchored.d.ts +61 -0
  102. package/dist/positioning/anchored.js +122 -0
  103. package/dist/positioning/tooltip.d.ts +41 -0
  104. package/dist/positioning/tooltip.js +147 -0
  105. package/dist/theme.css +205 -0
  106. package/dist/types/breakpoints.d.ts +24 -0
  107. package/dist/types/breakpoints.js +13 -0
  108. package/dist/types/responsive.d.ts +32 -0
  109. package/dist/types/responsive.js +54 -0
  110. package/dist/types/sizes.d.ts +10 -3
  111. package/dist/types/time.d.ts +19 -0
  112. package/dist/types/time.js +10 -0
  113. package/dist/types/variants.d.ts +8 -1
  114. package/dist/types/variants.js +16 -1
  115. package/package.json +93 -63
  116. package/dist/components/Button/Button.svelte +0 -172
  117. package/dist/components/Button/Button.svelte.d.ts +0 -32
  118. package/dist/components/Button/index.d.ts +0 -1
  119. package/dist/components/Button/index.js +0 -1
  120. package/dist/components/Dialog/Dialog.svelte +0 -101
  121. package/dist/components/Dialog/Dialog.svelte.d.ts +0 -18
  122. package/dist/components/Dialog/index.d.ts +0 -1
  123. package/dist/components/Dialog/index.js +0 -1
  124. package/dist/components/ElementManager/ElementManager.svelte +0 -397
  125. package/dist/components/ElementManager/ElementManager.svelte.d.ts +0 -43
  126. package/dist/components/ElementManager/index.d.ts +0 -1
  127. package/dist/components/ElementManager/index.js +0 -1
  128. package/dist/components/EmailInput/EmailInput.svelte.d.ts +0 -14
  129. package/dist/components/EmailInput/index.d.ts +0 -1
  130. package/dist/components/EmailInput/index.js +0 -1
  131. package/dist/components/Icon/Icon.svelte +0 -74
  132. package/dist/components/Icon/Icon.svelte.d.ts +0 -13
  133. package/dist/components/Icon/index.d.ts +0 -1
  134. package/dist/components/Icon/index.js +0 -1
  135. package/dist/components/Input/Input.svelte +0 -268
  136. package/dist/components/Input/Input.svelte.d.ts +0 -18
  137. package/dist/components/Input/index.d.ts +0 -1
  138. package/dist/components/Input/index.js +0 -1
  139. package/dist/components/List/index.d.ts +0 -1
  140. package/dist/components/List/index.js +0 -1
  141. package/dist/components/ListItem/ListItem.svelte +0 -175
  142. package/dist/components/ListItem/ListItem.svelte.d.ts +0 -24
  143. package/dist/components/ListItem/index.d.ts +0 -2
  144. package/dist/components/ListItem/index.js +0 -2
  145. package/dist/components/ListView/ListView.svelte +0 -463
  146. package/dist/components/ListView/ListView.svelte.d.ts +0 -37
  147. package/dist/components/ListView/index.d.ts +0 -2
  148. package/dist/components/ListView/index.js +0 -2
  149. package/dist/components/NodeGraph/BaseNode.d.ts +0 -57
  150. package/dist/components/NodeGraph/BaseNode.js +0 -30
  151. package/dist/components/NodeGraph/Edge.svelte +0 -60
  152. package/dist/components/NodeGraph/Edge.svelte.d.ts +0 -16
  153. package/dist/components/NodeGraph/ExpressionEvaluator.d.ts +0 -82
  154. package/dist/components/NodeGraph/ExpressionEvaluator.js +0 -152
  155. package/dist/components/NodeGraph/Node.svelte +0 -100
  156. package/dist/components/NodeGraph/Node.svelte.d.ts +0 -10
  157. package/dist/components/NodeGraph/NodeGraph.svelte +0 -52
  158. package/dist/components/NodeGraph/NodeGraph.svelte.d.ts +0 -14
  159. package/dist/components/NodeGraph/NodeInstance.svelte.d.ts +0 -80
  160. package/dist/components/NodeGraph/NodeInstance.svelte.js +0 -241
  161. package/dist/components/NodeGraph/NodePort.svelte +0 -75
  162. package/dist/components/NodeGraph/NodePort.svelte.d.ts +0 -11
  163. package/dist/components/NodeGraph/decorators.d.ts +0 -81
  164. package/dist/components/NodeGraph/decorators.js +0 -148
  165. package/dist/components/NodeGraph/index.d.ts +0 -9
  166. package/dist/components/NodeGraph/index.js +0 -9
  167. package/dist/components/NodeGraph/types.d.ts +0 -94
  168. package/dist/components/NodeGraph/types.js +0 -33
  169. package/dist/components/NotesEditor/NotesEditor.svelte +0 -203
  170. package/dist/components/NotesEditor/NotesEditor.svelte.d.ts +0 -9
  171. package/dist/components/NotesEditor/index.d.ts +0 -1
  172. package/dist/components/NotesEditor/index.js +0 -1
  173. package/dist/components/NumberInput/index.d.ts +0 -1
  174. package/dist/components/NumberInput/index.js +0 -1
  175. package/dist/components/PasswordInput/PasswordInput.svelte +0 -41
  176. package/dist/components/PasswordInput/PasswordInput.svelte.d.ts +0 -13
  177. package/dist/components/PasswordInput/index.d.ts +0 -1
  178. package/dist/components/PasswordInput/index.js +0 -1
  179. package/dist/components/Popup/index.d.ts +0 -1
  180. package/dist/components/Popup/index.js +0 -1
  181. package/dist/components/Rating/Rating.svelte.d.ts +0 -7
  182. package/dist/components/Rating/index.d.ts +0 -1
  183. package/dist/components/Rating/index.js +0 -1
  184. package/dist/components/ScrollView/ScrollView.svelte +0 -285
  185. package/dist/components/ScrollView/ScrollView.svelte.d.ts +0 -19
  186. package/dist/components/ScrollView/index.d.ts +0 -1
  187. package/dist/components/ScrollView/index.js +0 -1
  188. package/dist/components/SearchInput/index.d.ts +0 -1
  189. package/dist/components/SearchInput/index.js +0 -1
  190. package/dist/components/Select/index.d.ts +0 -1
  191. package/dist/components/Select/index.js +0 -1
  192. package/dist/components/TextArea/TextArea.svelte.d.ts +0 -19
  193. package/dist/components/TextArea/index.d.ts +0 -1
  194. package/dist/components/TextArea/index.js +0 -1
  195. package/dist/components/ThemeSelector/ThemeSelector.svelte +0 -64
  196. package/dist/components/ThemeSelector/ThemeSelector.svelte.d.ts +0 -3
  197. package/dist/components/ThemeSelector/index.d.ts +0 -1
  198. package/dist/components/ThemeSelector/index.js +0 -1
  199. package/dist/components/TooltipHandler/TooltipHandler.svelte +0 -593
  200. package/dist/components/TooltipHandler/TooltipHandler.svelte.d.ts +0 -10
  201. package/dist/components/TooltipHandler/index.d.ts +0 -1
  202. package/dist/components/TooltipHandler/index.js +0 -1
  203. package/dist/styles/sizes.d.ts +0 -78
  204. package/dist/styles/sizes.js +0 -120
  205. package/dist/styles/variants.d.ts +0 -106
  206. package/dist/styles/variants.js +0 -194
  207. package/dist/types/ManagerTypes.d.ts +0 -42
  208. /package/dist/{types/ManagerTypes.js → data/table/types.js} +0 -0
@@ -0,0 +1,117 @@
1
+ <!--
2
+ /**
3
+ * Menu — a keyboard-navigable action menu rendered inside a Popup (top layer, flips vs boundary).
4
+ *
5
+ * Convention (from the data-table): render ALL items always and `disabled` the invalid ones.
6
+ * If ANY item has an icon, icon-less items reserve the icon column so labels align. Selecting an
7
+ * enabled item runs its onclick / follows its href and closes; disabled items don't close.
8
+ */
9
+ -->
10
+ <script lang="ts">
11
+ import Popup from "./Popup.svelte";
12
+ import type { Side, Align, Boundary } from "../positioning/anchored.js";
13
+ import type { MenuItem } from "../data/table/types.js";
14
+ import type { Size } from "../types/sizes.js";
15
+ import { responsiveClasses, type Responsive } from "../types/responsive.js";
16
+ import { variantToken, type Variant } from "../types/variants.js";
17
+
18
+ let {
19
+ anchor,
20
+ open = $bindable(false),
21
+ items,
22
+ side = "bottom",
23
+ align = "end",
24
+ boundary = "viewport",
25
+ size = "md",
26
+ variant,
27
+ }: {
28
+ anchor: HTMLElement | undefined;
29
+ open?: boolean;
30
+ items: MenuItem[];
31
+ side?: Side;
32
+ align?: Align;
33
+ boundary?: Boundary;
34
+ size?: Responsive<Size>;
35
+ /** Tints the highlighted item with a semantic colour (via `.ui-accent` / `--ui-accent`) instead
36
+ * of neutral grey. Omit for the default. */
37
+ variant?: Variant;
38
+ } = $props();
39
+
40
+ let active = $state(-1);
41
+ const hasIcons = $derived(items.some((i) => i.icon));
42
+ const enabledIdx = $derived(items.map((i, idx) => (i.disabled ? -1 : idx)).filter((i) => i >= 0));
43
+
44
+ // Size axis → item padding / text / icon box. Variant → --ui-accent (re-mixes the item's hover tint).
45
+ const padMap: Record<Size, string> = { sm: "px-1.5 py-1", md: "px-2 py-1.5", lg: "px-2.5 py-2" };
46
+ const textMap: Record<Size, string> = { sm: "text-xs", md: "text-sm", lg: "text-base" };
47
+ const iconMap: Record<Size, string> = { sm: "w-3.5 h-3.5", md: "w-4 h-4", lg: "w-5 h-5" };
48
+ const padClass = $derived(responsiveClasses(size, padMap));
49
+ const textClass = $derived(responsiveClasses(size, textMap));
50
+ const iconClass = $derived(responsiveClasses(size, iconMap));
51
+ const accentVar = $derived(variant ? `--ui-accent: var(${variantToken[variant]});` : "");
52
+
53
+ function choose(item: MenuItem) {
54
+ if (item.disabled) return;
55
+ item.onclick?.();
56
+ if (item.href) window.location.href = item.href;
57
+ open = false;
58
+ }
59
+
60
+ function onkeydown(e: KeyboardEvent) {
61
+ if (!enabledIdx.length) return;
62
+ const pos = enabledIdx.indexOf(active);
63
+ if (e.key === "ArrowDown") {
64
+ e.preventDefault();
65
+ active = enabledIdx[(pos + 1 + enabledIdx.length) % enabledIdx.length] ?? enabledIdx[0];
66
+ } else if (e.key === "ArrowUp") {
67
+ e.preventDefault();
68
+ active =
69
+ enabledIdx[(pos - 1 + enabledIdx.length) % enabledIdx.length] ??
70
+ enabledIdx[enabledIdx.length - 1];
71
+ } else if (e.key === "Enter" && active >= 0) {
72
+ e.preventDefault();
73
+ choose(items[active]);
74
+ }
75
+ }
76
+
77
+ $effect(() => {
78
+ if (!open) active = -1;
79
+ });
80
+ </script>
81
+
82
+ <Popup {anchor} bind:open {side} {align} {boundary}>
83
+ <!-- svelte-ignore a11y_no_noninteractive_tabindex -->
84
+ <ul
85
+ role="menu"
86
+ tabindex="0"
87
+ {onkeydown}
88
+ class="ui-accent min-w-48 rounded-md border p-1 shadow-lg outline-none [background-color:var(--ui-color-background)] [border-color:color-mix(in_srgb,var(--ui-color-secondary)_var(--ui-tint-border),transparent)]"
89
+ style={accentVar}
90
+ >
91
+ {#each items as item, i (item.label)}
92
+ {@const danger = item.danger}
93
+ <li role="none">
94
+ <button
95
+ type="button"
96
+ role="menuitem"
97
+ disabled={item.disabled}
98
+ onmouseenter={() => (active = item.disabled ? active : i)}
99
+ onclick={() => choose(item)}
100
+ class="flex w-full items-center gap-2 rounded {padClass} {textClass} text-left transition-colors
101
+ {item.disabled ? 'cursor-not-allowed opacity-40' : 'cursor-pointer'}
102
+ {i === active && !item.disabled ? '[background-color:var(--ui-color-surface)]' : ''}
103
+ {danger ? '[color:var(--ui-color-error)]' : '[color:var(--ui-color-text)]'}"
104
+ >
105
+ {#if hasIcons}
106
+ <span
107
+ class="inline-flex {iconClass} shrink-0 items-center justify-center [&_svg]:w-full [&_svg]:h-full"
108
+ >
109
+ {#if item.icon}{@const Icon = item.icon}<Icon />{/if}
110
+ </span>
111
+ {/if}
112
+ <span class="truncate">{item.label}</span>
113
+ </button>
114
+ </li>
115
+ {/each}
116
+ </ul>
117
+ </Popup>
@@ -0,0 +1,20 @@
1
+ import type { Side, Align, Boundary } from "../positioning/anchored.js";
2
+ import type { MenuItem } from "../data/table/types.js";
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
+ anchor: HTMLElement | undefined;
8
+ open?: boolean;
9
+ items: MenuItem[];
10
+ side?: Side;
11
+ align?: Align;
12
+ boundary?: Boundary;
13
+ size?: Responsive<Size>;
14
+ /** Tints the highlighted item with a semantic colour (via `.ui-accent` / `--ui-accent`) instead
15
+ * of neutral grey. Omit for the default. */
16
+ variant?: Variant;
17
+ };
18
+ declare const Menu: import("svelte").Component<$$ComponentProps, {}, "open">;
19
+ type Menu = ReturnType<typeof Menu>;
20
+ export default Menu;
@@ -0,0 +1,127 @@
1
+ <!--
2
+ /**
3
+ * NotesEditor — an auto-saving notes field. Built on the core <TextArea> (so it inherits the shared
4
+ * frame, autosize, and the `size` + `variant` axes) plus a debounced auto-save + a status indicator.
5
+ * Saves 1s after typing stops, or immediately on Ctrl/Cmd+S while focused.
6
+ */
7
+ -->
8
+ <script lang="ts">
9
+ import TextArea from "./TextArea.svelte";
10
+ import type { Size } from "../types/sizes.js";
11
+ import type { Responsive } from "../types/responsive.js";
12
+ import type { Variant } from "../types/variants.js";
13
+
14
+ let {
15
+ notes = $bindable(""),
16
+ placeholder = "Add your notes...",
17
+ onSave,
18
+ size = "md",
19
+ variant = "secondary",
20
+ copy,
21
+ className = "",
22
+ }: {
23
+ notes?: string;
24
+ placeholder?: string;
25
+ onSave?: (notes: string) => Promise<void>;
26
+ /** Shared axes — forwarded to the underlying TextArea. */
27
+ size?: Responsive<Size>;
28
+ variant?: Variant;
29
+ /** Copy affordance — forwarded to the underlying TextArea (defaults to its `'selection'`). */
30
+ copy?: "none" | "selection" | "button";
31
+ className?: string;
32
+ } = $props();
33
+
34
+ let saveState = $state<"idle" | "typing" | "saving" | "saved" | "error">("idle");
35
+ let saveTimeout: ReturnType<typeof setTimeout>;
36
+ let lastSavedNotes = $state(notes || "");
37
+ let textareaElement = $state<HTMLTextAreaElement>();
38
+
39
+ // Auto-save: 1s debounce after typing stops.
40
+ $effect(() => {
41
+ const currentNotes = notes || "";
42
+ if (currentNotes !== lastSavedNotes && saveState !== "saving") {
43
+ saveState = "typing";
44
+ clearTimeout(saveTimeout);
45
+ saveTimeout = setTimeout(() => {
46
+ handleSave();
47
+ }, 1000);
48
+ }
49
+ });
50
+
51
+ // Ctrl/Cmd+S saves immediately while the editor is focused.
52
+ $effect(() => {
53
+ async function handleKeyDown(event: KeyboardEvent) {
54
+ if (
55
+ (event.ctrlKey || event.metaKey) &&
56
+ event.key === "s" &&
57
+ textareaElement &&
58
+ document.activeElement === textareaElement
59
+ ) {
60
+ event.preventDefault();
61
+ event.stopPropagation();
62
+ clearTimeout(saveTimeout);
63
+ await handleSave();
64
+ }
65
+ }
66
+ document.addEventListener("keydown", handleKeyDown);
67
+ return () => document.removeEventListener("keydown", handleKeyDown);
68
+ });
69
+
70
+ async function handleSave() {
71
+ const currentNotes = notes || "";
72
+
73
+ if (currentNotes === lastSavedNotes) {
74
+ // Brief "Saved" feedback for a manual save with no changes.
75
+ saveState = "saved";
76
+ setTimeout(() => {
77
+ if (saveState === "saved") saveState = "idle";
78
+ }, 1000);
79
+ return;
80
+ }
81
+
82
+ saveState = "saving";
83
+ try {
84
+ await onSave?.(currentNotes);
85
+ lastSavedNotes = currentNotes;
86
+ saveState = "saved";
87
+ setTimeout(() => {
88
+ if (saveState === "saved") saveState = "idle";
89
+ }, 2000);
90
+ } catch (error) {
91
+ console.error("Failed to save notes:", error);
92
+ saveState = "error";
93
+ setTimeout(() => {
94
+ if (saveState === "error") saveState = "idle";
95
+ }, 3000);
96
+ }
97
+ }
98
+
99
+ // Status text + colour (theme tokens, not hard-coded Tailwind colours).
100
+ const STATUS = {
101
+ idle: { text: "", color: "" },
102
+ typing: { text: "Typing…", color: "color-mix(in srgb, var(--ui-color-text) 55%, transparent)" },
103
+ saving: { text: "Saving…", color: "var(--ui-color-info)" },
104
+ saved: { text: "Saved", color: "var(--ui-color-success)" },
105
+ error: { text: "Save failed", color: "var(--ui-color-error)" },
106
+ } as const;
107
+ const status = $derived(STATUS[saveState]);
108
+ </script>
109
+
110
+ <div class={className}>
111
+ <!-- Header: label + save status -->
112
+ <div class="flex items-center justify-between mb-2">
113
+ <span class="block text-sm font-medium [color:var(--ui-color-text)]">Notes</span>
114
+ <span class="text-xs min-h-[16px]" style="color: {status.color}">{status.text}</span>
115
+ </div>
116
+
117
+ <TextArea
118
+ bind:value={notes}
119
+ bind:element={textareaElement}
120
+ {placeholder}
121
+ {size}
122
+ {variant}
123
+ {copy}
124
+ minRows={3}
125
+ maxRows={15}
126
+ />
127
+ </div>
@@ -0,0 +1,17 @@
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
+ type $$ComponentProps = {
5
+ notes?: string;
6
+ placeholder?: string;
7
+ onSave?: (notes: string) => Promise<void>;
8
+ /** Shared axes — forwarded to the underlying TextArea. */
9
+ size?: Responsive<Size>;
10
+ variant?: Variant;
11
+ /** Copy affordance — forwarded to the underlying TextArea (defaults to its `'selection'`). */
12
+ copy?: "none" | "selection" | "button";
13
+ className?: string;
14
+ };
15
+ declare const NotesEditor: import("svelte").Component<$$ComponentProps, {}, "notes">;
16
+ type NotesEditor = ReturnType<typeof NotesEditor>;
17
+ export default NotesEditor;