@svgrid/grid 2.2.16 → 2.2.18

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 (290) hide show
  1. package/README.md +1 -1
  2. package/dist/GridFooter.svelte +12 -11
  3. package/dist/SvAnchor.svelte +65 -0
  4. package/dist/SvAnchor.svelte.d.ts +24 -0
  5. package/dist/SvAspectRatio.svelte +38 -0
  6. package/dist/SvAspectRatio.svelte.d.ts +16 -0
  7. package/dist/SvAutoComplete.svelte +52 -7
  8. package/dist/SvAutoComplete.svelte.d.ts +4 -1
  9. package/dist/SvBlockquote.svelte +43 -0
  10. package/dist/SvBlockquote.svelte.d.ts +16 -0
  11. package/dist/SvCalendar.svelte +33 -2
  12. package/dist/SvCalendar.svelte.d.ts +8 -1
  13. package/dist/SvCheckBox.svelte +6 -2
  14. package/dist/SvCode.svelte +52 -0
  15. package/dist/SvCode.svelte.d.ts +19 -0
  16. package/dist/SvCollapsible.svelte +75 -0
  17. package/dist/SvCollapsible.svelte.d.ts +27 -0
  18. package/dist/SvColorInput.svelte +11 -17
  19. package/dist/SvColorInput.svelte.d.ts +2 -0
  20. package/dist/SvComboBox.svelte +85 -8
  21. package/dist/SvComboBox.svelte.d.ts +14 -0
  22. package/dist/SvCountryInput.svelte +2 -2
  23. package/dist/SvCountryInput.svelte.d.ts +1 -1
  24. package/dist/SvDropDownList.svelte +154 -51
  25. package/dist/SvDropDownList.svelte.d.ts +17 -3
  26. package/dist/SvDurationInput.svelte +59 -41
  27. package/dist/SvDurationInput.svelte.d.ts +18 -0
  28. package/dist/SvField.svelte +203 -12
  29. package/dist/SvField.svelte.d.ts +45 -8
  30. package/dist/SvForm.svelte +195 -21
  31. package/dist/SvForm.svelte.d.ts +23 -0
  32. package/dist/SvGrid.controller.svelte.d.ts +12 -1
  33. package/dist/SvGrid.controller.svelte.js +87 -7
  34. package/dist/SvGrid.svelte +383 -181
  35. package/dist/SvGrid.types.d.ts +123 -2
  36. package/dist/SvGridChartView.svelte +70 -0
  37. package/dist/SvGridChartView.svelte.d.ts +11 -0
  38. package/dist/SvGridDropdown.svelte +9 -2
  39. package/dist/SvGridSelect.svelte +5 -2
  40. package/dist/SvGridSelect.svelte.d.ts +1 -1
  41. package/dist/SvGroup.svelte +41 -0
  42. package/dist/SvGroup.svelte.d.ts +27 -0
  43. package/dist/SvHoverCard.svelte +70 -0
  44. package/dist/SvHoverCard.svelte.d.ts +41 -0
  45. package/dist/SvKbd.svelte +51 -0
  46. package/dist/SvKbd.svelte.d.ts +18 -0
  47. package/dist/SvList.svelte +55 -0
  48. package/dist/SvList.svelte.d.ts +23 -0
  49. package/dist/SvListBox.svelte +166 -77
  50. package/dist/SvListBox.svelte.d.ts +17 -4
  51. package/dist/SvLoadingOverlay.svelte +53 -0
  52. package/dist/SvLoadingOverlay.svelte.d.ts +28 -0
  53. package/dist/SvMark.svelte +36 -0
  54. package/dist/SvMark.svelte.d.ts +14 -0
  55. package/dist/SvMaskedInput.svelte +50 -35
  56. package/dist/SvMaskedInput.svelte.d.ts +17 -2
  57. package/dist/SvMenuList.svelte +32 -3
  58. package/dist/SvMenubar.svelte +200 -0
  59. package/dist/SvMenubar.svelte.d.ts +18 -0
  60. package/dist/SvMultiSelect.svelte +7 -4
  61. package/dist/SvMultiSelect.svelte.d.ts +1 -1
  62. package/dist/SvNumberInput.svelte +79 -42
  63. package/dist/SvNumberInput.svelte.d.ts +25 -0
  64. package/dist/SvOtpInput.svelte +2 -2
  65. package/dist/SvPasswordInput.svelte +51 -31
  66. package/dist/SvPasswordInput.svelte.d.ts +17 -0
  67. package/dist/SvPhoneInput.svelte +39 -28
  68. package/dist/SvPhoneInput.svelte.d.ts +4 -0
  69. package/dist/SvPopconfirm.svelte +79 -0
  70. package/dist/SvPopconfirm.svelte.d.ts +42 -0
  71. package/dist/SvPopover.svelte +87 -29
  72. package/dist/SvPopover.svelte.d.ts +18 -4
  73. package/dist/SvRadioGroup.svelte +5 -1
  74. package/dist/SvResult.svelte +73 -0
  75. package/dist/SvResult.svelte.d.ts +28 -0
  76. package/dist/SvSegmented.svelte +114 -0
  77. package/dist/SvSegmented.svelte.d.ts +29 -0
  78. package/dist/SvSimpleGrid.svelte +41 -0
  79. package/dist/SvSimpleGrid.svelte.d.ts +25 -0
  80. package/dist/SvSlider.svelte +23 -10
  81. package/dist/SvSpinner.svelte +43 -0
  82. package/dist/SvSpinner.svelte.d.ts +20 -0
  83. package/dist/SvStack.svelte +37 -0
  84. package/dist/SvStack.svelte.d.ts +24 -0
  85. package/dist/SvSwitchButton.svelte +6 -1
  86. package/dist/SvTagsInput.svelte +9 -5
  87. package/dist/SvText.svelte +76 -0
  88. package/dist/SvText.svelte.d.ts +31 -0
  89. package/dist/SvTextInput.svelte +75 -43
  90. package/dist/SvTextInput.svelte.d.ts +28 -1
  91. package/dist/SvTimePicker.svelte +32 -2
  92. package/dist/SvTimePicker.svelte.d.ts +8 -9
  93. package/dist/SvTitle.svelte +57 -0
  94. package/dist/SvTitle.svelte.d.ts +24 -0
  95. package/dist/SvToaster.svelte +41 -6
  96. package/dist/SvToggleButton.svelte +4 -1
  97. package/dist/SvTooltip.svelte +68 -34
  98. package/dist/SvTooltip.svelte.d.ts +14 -2
  99. package/dist/SvTree.svelte +81 -21
  100. package/dist/SvTree.svelte.d.ts +3 -2
  101. package/dist/SvTreeSelect.svelte +5 -2
  102. package/dist/SvTreeSelect.svelte.d.ts +1 -1
  103. package/dist/SvVisuallyHidden.svelte +49 -0
  104. package/dist/SvVisuallyHidden.svelte.d.ts +19 -0
  105. package/dist/ai.d.ts +289 -0
  106. package/dist/ai.js +1013 -0
  107. package/dist/board-view.svelte.d.ts +22 -0
  108. package/dist/board-view.svelte.js +13 -0
  109. package/dist/build-api.js +36 -6
  110. package/dist/cdn/GridMenus-0AK9O7qG.js +420 -0
  111. package/dist/cdn/GridMenus-BjUoCXoD.js +416 -0
  112. package/dist/cdn/SvDateTimePicker-CYC7gRER.js +2176 -0
  113. package/dist/cdn/SvDateTimePicker-DtQKd4Ns.js +2198 -0
  114. package/dist/cdn/SvGridChart-BcLCYvw9.js +1195 -0
  115. package/dist/cdn/SvGridChart-BhnFdLd0.js +1203 -0
  116. package/dist/cdn/SvGridChartPanel-Cmx9DHAS.js +561 -0
  117. package/dist/cdn/SvGridChartPanel-DvjwxLvK.js +577 -0
  118. package/dist/cdn/SvGridChartView-B40DTJSX.js +54 -0
  119. package/dist/cdn/SvGridChartView-PwqI4s02.js +53 -0
  120. package/dist/cdn/SvGridDropdown-DjALc_4f.js +255 -0
  121. package/dist/cdn/SvGridDropdown-hpnHvOGt.js +254 -0
  122. package/dist/cdn/chart-T1usDN0o.js +1212 -0
  123. package/dist/cdn/disclose-version-DoD9AFD_.js +2958 -0
  124. package/dist/cdn/export-format-JT5pWVT8.js +561 -0
  125. package/dist/cdn/popover-P-9P2YYn.js +69 -0
  126. package/dist/cdn/rolldown-runtime-Dy4uBu1J.js +11 -0
  127. package/dist/cdn/src-BLhdLmoN.js +25707 -0
  128. package/dist/cdn/src-BwnUVj3T.js +25623 -0
  129. package/dist/cdn/svgrid.js +9 -32897
  130. package/dist/cdn/svgrid.svelte-external.js +9 -30052
  131. package/dist/cell-formatting.d.ts +2 -2
  132. package/dist/cell-render.js +4 -4
  133. package/dist/chart-view.svelte.d.ts +25 -0
  134. package/dist/chart-view.svelte.js +14 -0
  135. package/dist/createCombobox.svelte.d.ts +5 -0
  136. package/dist/createCombobox.svelte.js +21 -5
  137. package/dist/createDropdownList.svelte.d.ts +3 -0
  138. package/dist/createDropdownList.svelte.js +8 -2
  139. package/dist/createForm.svelte.d.ts +18 -0
  140. package/dist/createForm.svelte.js +51 -6
  141. package/dist/createMenu.svelte.js +27 -0
  142. package/dist/createPopoverSelect.svelte.d.ts +3 -0
  143. package/dist/createPopoverSelect.svelte.js +9 -1
  144. package/dist/createSlider.svelte.d.ts +8 -21
  145. package/dist/createSlider.svelte.js +34 -0
  146. package/dist/createTooltip.svelte.d.ts +12 -0
  147. package/dist/createTooltip.svelte.js +72 -9
  148. package/dist/editor-contract.d.ts +15 -0
  149. package/dist/export-provider.d.ts +27 -0
  150. package/dist/export-provider.js +9 -0
  151. package/dist/filter-operators.d.ts +6 -0
  152. package/dist/filter-operators.js +33 -0
  153. package/dist/form-field.d.ts +45 -2
  154. package/dist/grid-messages.d.ts +61 -0
  155. package/dist/grid-messages.js +72 -0
  156. package/dist/group-display.d.ts +62 -0
  157. package/dist/group-display.js +78 -0
  158. package/dist/index.d.ts +36 -4
  159. package/dist/index.js +43 -2
  160. package/dist/js-scroller.svelte.d.ts +35 -0
  161. package/dist/js-scroller.svelte.js +154 -0
  162. package/dist/list-option.d.ts +46 -0
  163. package/dist/list-option.js +53 -0
  164. package/dist/menus.js +25 -11
  165. package/dist/pivot-view.svelte.d.ts +72 -0
  166. package/dist/pivot-view.svelte.js +13 -0
  167. package/dist/positioning.d.ts +111 -0
  168. package/dist/positioning.js +191 -0
  169. package/dist/scheduler-model.d.ts +3 -0
  170. package/dist/scheduler-model.js +22 -5
  171. package/dist/svgrid-wrapper.types.d.ts +18 -0
  172. package/dist/toast-store.svelte.d.ts +54 -0
  173. package/dist/toast-store.svelte.js +65 -15
  174. package/package.json +9 -1
  175. package/src/GridFooter.svelte +12 -11
  176. package/src/SvAnchor.svelte +65 -0
  177. package/src/SvAspectRatio.svelte +38 -0
  178. package/src/SvAutoComplete.svelte +52 -7
  179. package/src/SvBlockquote.svelte +43 -0
  180. package/src/SvCalendar.svelte +33 -2
  181. package/src/SvCalendar.test.ts +15 -0
  182. package/src/SvCheckBox.svelte +6 -2
  183. package/src/SvCode.svelte +52 -0
  184. package/src/SvCollapsible.svelte +75 -0
  185. package/src/SvColorInput.svelte +11 -17
  186. package/src/SvComboBox.svelte +85 -8
  187. package/src/SvCountryInput.svelte +2 -2
  188. package/src/SvDropDownList.svelte +154 -51
  189. package/src/SvDurationInput.svelte +59 -41
  190. package/src/SvField.svelte +203 -12
  191. package/src/SvForm.svelte +195 -21
  192. package/src/SvForm.test.ts +112 -0
  193. package/src/SvGrid.controller.svelte.ts +88 -7
  194. package/src/SvGrid.svelte +383 -181
  195. package/src/SvGrid.types.ts +125 -1
  196. package/src/SvGridChartView.svelte +70 -0
  197. package/src/SvGridDropdown.svelte +9 -2
  198. package/src/SvGridSelect.svelte +5 -2
  199. package/src/SvGroup.svelte +41 -0
  200. package/src/SvHoverCard.svelte +70 -0
  201. package/src/SvKbd.svelte +51 -0
  202. package/src/SvList.svelte +55 -0
  203. package/src/SvListBox.svelte +166 -77
  204. package/src/SvLoadingOverlay.svelte +53 -0
  205. package/src/SvMark.svelte +36 -0
  206. package/src/SvMaskedInput.svelte +50 -35
  207. package/src/SvMenuList.svelte +32 -3
  208. package/src/SvMenubar.svelte +200 -0
  209. package/src/SvMultiSelect.svelte +7 -4
  210. package/src/SvNumberInput.svelte +79 -42
  211. package/src/SvOtpInput.svelte +2 -2
  212. package/src/SvPasswordInput.svelte +51 -31
  213. package/src/SvPhoneInput.svelte +39 -28
  214. package/src/SvPopconfirm.svelte +79 -0
  215. package/src/SvPopover.svelte +87 -29
  216. package/src/SvRadioGroup.svelte +5 -1
  217. package/src/SvResult.svelte +73 -0
  218. package/src/SvSegmented.svelte +114 -0
  219. package/src/SvSimpleGrid.svelte +41 -0
  220. package/src/SvSlider.svelte +23 -10
  221. package/src/SvSpinner.svelte +43 -0
  222. package/src/SvStack.svelte +37 -0
  223. package/src/SvSwitchButton.svelte +6 -1
  224. package/src/SvTagsInput.svelte +9 -5
  225. package/src/SvText.svelte +76 -0
  226. package/src/SvTextInput.svelte +75 -43
  227. package/src/SvTimePicker.svelte +32 -2
  228. package/src/SvTitle.svelte +57 -0
  229. package/src/SvToaster.svelte +41 -6
  230. package/src/SvToaster.test.ts +32 -0
  231. package/src/SvToggleButton.svelte +4 -1
  232. package/src/SvTooltip.svelte +68 -34
  233. package/src/SvTree.svelte +81 -21
  234. package/src/SvTreeSelect.svelte +5 -2
  235. package/src/SvVisuallyHidden.svelte +49 -0
  236. package/src/ai.test.ts +502 -0
  237. package/src/ai.ts +1391 -0
  238. package/src/board-view.svelte.ts +33 -0
  239. package/src/build-api.coverage.test.ts +101 -0
  240. package/src/build-api.ts +43 -18
  241. package/src/builtin-editors.grid.test.ts +1 -1
  242. package/src/cell-formatting.ts +5 -5
  243. package/src/cell-render.ts +4 -4
  244. package/src/chart-view.svelte.ts +36 -0
  245. package/src/createCombobox.svelte.ts +17 -5
  246. package/src/createDropdownList.svelte.ts +8 -2
  247. package/src/createForm.svelte.ts +59 -6
  248. package/src/createMenu.svelte.ts +23 -0
  249. package/src/createPopoverSelect.svelte.ts +8 -1
  250. package/src/createSlider.svelte.ts +20 -0
  251. package/src/createTooltip.svelte.ts +67 -9
  252. package/src/editor-contract.ts +16 -0
  253. package/src/export-provider.ts +40 -0
  254. package/src/filter-operators.ts +37 -0
  255. package/src/form-field.ts +42 -2
  256. package/src/grid-messages.test.ts +24 -0
  257. package/src/grid-messages.ts +137 -0
  258. package/src/group-display.test.ts +77 -0
  259. package/src/group-display.ts +117 -0
  260. package/src/i18n.grid.test.ts +73 -0
  261. package/src/index.ts +91 -2
  262. package/src/js-scroller.svelte.ts +173 -0
  263. package/src/list-option.test.ts +56 -0
  264. package/src/list-option.ts +81 -0
  265. package/src/menus.test.ts +32 -0
  266. package/src/menus.ts +25 -12
  267. package/src/pivot-view.svelte.ts +90 -0
  268. package/src/pivot-view.test.ts +38 -0
  269. package/src/pivot.grid.test.ts +102 -0
  270. package/src/positioning.test.ts +141 -0
  271. package/src/positioning.ts +266 -0
  272. package/src/scheduler-model.test.ts +16 -0
  273. package/src/scheduler-model.ts +24 -5
  274. package/src/svgrid-wrapper.types.ts +23 -0
  275. package/src/svgrid.charting.test.ts +8 -1
  276. package/src/svgrid.comments-autocomplete.test.ts +7 -2
  277. package/src/svgrid.context-menu.test.ts +8 -3
  278. package/src/toast-store.svelte.ts +98 -0
  279. package/src/toast-store.test.ts +62 -1
  280. package/src/ui-breadth.test.ts +138 -0
  281. package/src/ui-buttons.test.ts +39 -0
  282. package/src/ui-inputs.test.ts +2 -2
  283. package/src/ui-range.test.ts +9 -0
  284. package/src/ui-selection.test.ts +36 -0
  285. package/src/ui-tier1.test.ts +1 -1
  286. package/src/virtual.test.ts +20 -6
  287. package/dist/SvGridBoard.svelte +0 -2339
  288. package/dist/SvGridBoard.svelte.d.ts +0 -31
  289. package/src/SvGridBoard.svelte +0 -2339
  290. package/src/board.test.ts +0 -927
@@ -0,0 +1,76 @@
1
+ <script lang="ts">
2
+ /**
3
+ * SvText - the workhorse text primitive: a paragraph or inline span with
4
+ * consistent size / weight / colour tokens, optional truncation and line
5
+ * clamping. Themes from the shared `--sg-*` tokens.
6
+ *
7
+ * <SvText size="sm" tone="muted">Last synced 2 minutes ago</SvText>
8
+ * <SvText clamp={2}>A long description that wraps then ellipsises...</SvText>
9
+ */
10
+ import type { Snippet } from 'svelte'
11
+
12
+ type Props = {
13
+ /** Font size step. */
14
+ size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl'
15
+ /** Font weight. */
16
+ weight?: 'normal' | 'medium' | 'semibold' | 'bold'
17
+ /** Semantic colour. */
18
+ tone?: 'default' | 'muted' | 'accent' | 'success' | 'warning' | 'error'
19
+ /** Text alignment. */
20
+ align?: 'start' | 'center' | 'end'
21
+ /** Truncate to a single line with an ellipsis. */
22
+ truncate?: boolean
23
+ /** Clamp to N lines with an ellipsis (overrides truncate). */
24
+ clamp?: number
25
+ /** Render inline (`span`) instead of a block (`p`). */
26
+ inline?: boolean
27
+ /** Override the element/tag. */
28
+ as?: string
29
+ children?: Snippet
30
+ }
31
+
32
+ let {
33
+ size = 'md', weight = 'normal', tone = 'default', align,
34
+ truncate = false, clamp, inline = false, as, children,
35
+ }: Props = $props()
36
+
37
+ const sizeMap = { xs: '11px', sm: '13px', md: '14px', lg: '16px', xl: '20px' } as const
38
+ const weightMap = { normal: 400, medium: 500, semibold: 600, bold: 700 } as const
39
+ const toneMap = {
40
+ default: 'var(--sg-fg, #0f172a)',
41
+ muted: 'var(--sg-muted, #64748b)',
42
+ accent: 'var(--sg-accent, #2563eb)',
43
+ success: 'var(--sg-success, #16a34a)',
44
+ warning: 'var(--sg-warning, #d97706)',
45
+ error: 'var(--sg-danger, #dc2626)',
46
+ } as const
47
+ const alignMap = { start: 'left', center: 'center', end: 'right' } as const
48
+
49
+ const tag = $derived(as ?? (inline ? 'span' : 'p'))
50
+ </script>
51
+
52
+ <svelte:element
53
+ this={tag}
54
+ class="sv-text"
55
+ class:is-truncate={truncate && !clamp}
56
+ class:is-clamp={clamp != null}
57
+ style:font-size={sizeMap[size]}
58
+ style:font-weight={weightMap[weight]}
59
+ style:color={toneMap[tone]}
60
+ style:text-align={align ? alignMap[align] : undefined}
61
+ style:--sv-text-clamp={clamp}
62
+ >
63
+ {@render children?.()}
64
+ </svelte:element>
65
+
66
+ <style>
67
+ .sv-text { margin: 0; font-family: var(--sg-font, inherit); line-height: 1.5; }
68
+ .sv-text.is-truncate { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
69
+ .sv-text.is-clamp {
70
+ display: -webkit-box;
71
+ -webkit-box-orient: vertical;
72
+ -webkit-line-clamp: var(--sv-text-clamp, 2);
73
+ line-clamp: var(--sv-text-clamp, 2);
74
+ overflow: hidden;
75
+ }
76
+ </style>
@@ -0,0 +1,31 @@
1
+ /**
2
+ * SvText - the workhorse text primitive: a paragraph or inline span with
3
+ * consistent size / weight / colour tokens, optional truncation and line
4
+ * clamping. Themes from the shared `--sg-*` tokens.
5
+ *
6
+ * <SvText size="sm" tone="muted">Last synced 2 minutes ago</SvText>
7
+ * <SvText clamp={2}>A long description that wraps then ellipsises...</SvText>
8
+ */
9
+ import type { Snippet } from 'svelte';
10
+ type Props = {
11
+ /** Font size step. */
12
+ size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
13
+ /** Font weight. */
14
+ weight?: 'normal' | 'medium' | 'semibold' | 'bold';
15
+ /** Semantic colour. */
16
+ tone?: 'default' | 'muted' | 'accent' | 'success' | 'warning' | 'error';
17
+ /** Text alignment. */
18
+ align?: 'start' | 'center' | 'end';
19
+ /** Truncate to a single line with an ellipsis. */
20
+ truncate?: boolean;
21
+ /** Clamp to N lines with an ellipsis (overrides truncate). */
22
+ clamp?: number;
23
+ /** Render inline (`span`) instead of a block (`p`). */
24
+ inline?: boolean;
25
+ /** Override the element/tag. */
26
+ as?: string;
27
+ children?: Snippet;
28
+ };
29
+ declare const SvText: import("svelte").Component<Props, {}, "">;
30
+ type SvText = ReturnType<typeof SvText>;
31
+ export default SvText;
@@ -4,9 +4,14 @@
4
4
  * (label / hint / error / RTL / a11y via SvField). Handles `text`, `email`,
5
5
  * `url`, `tel` and `search`. As a grid cell editor it honours the interaction
6
6
  * contract: Enter commits, Escape cancels. Parity: Smart `smart-input`.
7
+ *
8
+ * The control box, size, invalid state, clear button and leading/trailing
9
+ * adornments are all owned by SvField's `frame` mode, so they behave identically
10
+ * across the text-input family.
7
11
  */
12
+ import type { Snippet } from 'svelte'
8
13
  import SvField from './SvField.svelte'
9
- import { editorAria, nextEditorId, type SvEditorProps } from './editor-contract'
14
+ import { editorAria, nextEditorId, type EditorAction, type SvEditorProps } from './editor-contract'
10
15
 
11
16
  type Props = SvEditorProps & {
12
17
  value?: string
@@ -23,6 +28,22 @@
23
28
  autocomplete?: AutoFill
24
29
  /** Autofocus + select on mount (used when mounted as a cell editor). */
25
30
  autofocus?: boolean
31
+ /** Select the whole value whenever the field is focused. */
32
+ selectOnFocus?: boolean
33
+ /** Leading adornment (icon/button) inside the field. */
34
+ leading?: Snippet
35
+ /** Trailing adornment (icon/button) inside the field. */
36
+ trailing?: Snippet
37
+ /** Plain-text affix at the start (e.g. a `$` or protocol). */
38
+ prefix?: string
39
+ /** Plain-text affix at the end (e.g. a unit). */
40
+ suffix?: string
41
+ /** `floating` animates the label up on focus/value. Default `static`. */
42
+ labelMode?: 'static' | 'floating'
43
+ /** Compact in-field action buttons (lookup/generate/copy...). */
44
+ actions?: EditorAction[]
45
+ /** Stretch to the container width. */
46
+ block?: boolean
26
47
  }
27
48
 
28
49
  let {
@@ -46,8 +67,17 @@
46
67
  hint,
47
68
  dir,
48
69
  id,
70
+ loading = false,
49
71
  autocomplete,
50
72
  autofocus = false,
73
+ selectOnFocus = false,
74
+ leading,
75
+ trailing,
76
+ prefix,
77
+ suffix,
78
+ labelMode = 'static',
79
+ actions,
80
+ block = false,
51
81
  }: Props = $props()
52
82
 
53
83
  const autoId = nextEditorId('sv-text')
@@ -68,48 +98,50 @@
68
98
  function mountFocus(node: HTMLInputElement) {
69
99
  if (autofocus) { node.focus(); node.select() }
70
100
  }
101
+ function onFocus(e: FocusEvent) {
102
+ if (selectOnFocus) (e.currentTarget as HTMLInputElement).select()
103
+ }
71
104
  </script>
72
105
 
73
- <SvField id={uid} {label} {hint} {error} {required} {dir}>
74
- <div class="sv-text sv-text--{size}" class:is-disabled={disabled}>
75
- <div class="sv-text__field" class:is-invalid={invalid}>
76
- <input
77
- use:mountFocus
78
- class="sv-text__input"
79
- {type}
80
- {value}
81
- {placeholder}
82
- {disabled}
83
- {readonly}
84
- {maxlength}
85
- {autocomplete}
86
- oninput={onInput}
87
- onkeydown={onKeydown}
88
- {...editorAria({ id: uid, invalid, required, error, hint, ariaLabel })}
89
- />
90
- {#if clearable && value && !disabled && !readonly}
91
- <button class="sv-text__clear" type="button" tabindex="-1" aria-label="Clear" onclick={() => set('')}>&times;</button>
92
- {/if}
93
- </div>
94
- {#if name}<input type="hidden" {name} value={value} />{/if}
95
- </div>
106
+ <SvField
107
+ frame
108
+ id={uid}
109
+ {label}
110
+ {hint}
111
+ {error}
112
+ {required}
113
+ {dir}
114
+ {size}
115
+ {invalid}
116
+ {disabled}
117
+ {readonly}
118
+ {loading}
119
+ {block}
120
+ {leading}
121
+ {trailing}
122
+ {prefix}
123
+ {suffix}
124
+ {labelMode}
125
+ filled={!!value}
126
+ {actions}
127
+ clearable={clearable}
128
+ showClear={!!value}
129
+ onclear={() => set('')}
130
+ >
131
+ <input
132
+ use:mountFocus
133
+ class="sv-text__input"
134
+ {type}
135
+ {value}
136
+ placeholder={labelMode === 'floating' ? undefined : placeholder}
137
+ {disabled}
138
+ {readonly}
139
+ {maxlength}
140
+ {autocomplete}
141
+ oninput={onInput}
142
+ onkeydown={onKeydown}
143
+ onfocus={onFocus}
144
+ {...editorAria({ id: uid, invalid, required, error, hint, ariaLabel })}
145
+ />
146
+ {#if name}<input type="hidden" {name} value={value} />{/if}
96
147
  </SvField>
97
-
98
- <style>
99
- .sv-text { --_accent: var(--sg-accent, #2563eb); display: inline-flex; flex-direction: column; width: 220px; }
100
- .sv-text.is-disabled { opacity: 0.6; }
101
- .sv-text__field {
102
- display: flex; align-items: center;
103
- background: var(--sg-input-bg, #fff); color: var(--sg-fg, #0f172a);
104
- border: 1px solid var(--sg-input-border, var(--sg-border, #cbd5e1)); border-radius: var(--sg-radius, 8px);
105
- }
106
- .sv-text__field:focus-within { border-color: var(--_accent); box-shadow: 0 0 0 2px color-mix(in srgb, var(--_accent) 22%, transparent); }
107
- .sv-text__field.is-invalid { border-color: var(--sg-danger, #dc2626); }
108
- .sv-text__field.is-invalid:focus-within { box-shadow: 0 0 0 2px color-mix(in srgb, var(--sg-danger, #dc2626) 22%, transparent); }
109
- .sv-text__input { flex: 1; min-width: 0; border: 0; background: none; outline: none; color: inherit; font: inherit; padding: 0 10px; }
110
- .sv-text--sm .sv-text__field { height: 28px; font-size: 12px; }
111
- .sv-text--md .sv-text__field { height: 34px; font-size: 13px; }
112
- .sv-text--lg .sv-text__field { height: 40px; font-size: 15px; }
113
- .sv-text__clear { display: grid; place-items: center; width: 28px; align-self: stretch; background: none; border: 0; color: var(--sg-muted, #64748b); cursor: pointer; font-size: 17px; line-height: 1; }
114
- .sv-text__clear:hover { color: var(--sg-fg, #0f172a); }
115
- </style>
@@ -1,4 +1,15 @@
1
- import { type SvEditorProps } from './editor-contract';
1
+ /**
2
+ * SvTextInput - the base single-line text editor on the shared editor contract
3
+ * (label / hint / error / RTL / a11y via SvField). Handles `text`, `email`,
4
+ * `url`, `tel` and `search`. As a grid cell editor it honours the interaction
5
+ * contract: Enter commits, Escape cancels. Parity: Smart `smart-input`.
6
+ *
7
+ * The control box, size, invalid state, clear button and leading/trailing
8
+ * adornments are all owned by SvField's `frame` mode, so they behave identically
9
+ * across the text-input family.
10
+ */
11
+ import type { Snippet } from 'svelte';
12
+ import { type EditorAction, type SvEditorProps } from './editor-contract';
2
13
  type Props = SvEditorProps & {
3
14
  value?: string;
4
15
  onChange?: (value: string) => void;
@@ -14,6 +25,22 @@ type Props = SvEditorProps & {
14
25
  autocomplete?: AutoFill;
15
26
  /** Autofocus + select on mount (used when mounted as a cell editor). */
16
27
  autofocus?: boolean;
28
+ /** Select the whole value whenever the field is focused. */
29
+ selectOnFocus?: boolean;
30
+ /** Leading adornment (icon/button) inside the field. */
31
+ leading?: Snippet;
32
+ /** Trailing adornment (icon/button) inside the field. */
33
+ trailing?: Snippet;
34
+ /** Plain-text affix at the start (e.g. a `$` or protocol). */
35
+ prefix?: string;
36
+ /** Plain-text affix at the end (e.g. a unit). */
37
+ suffix?: string;
38
+ /** `floating` animates the label up on focus/value. Default `static`. */
39
+ labelMode?: 'static' | 'floating';
40
+ /** Compact in-field action buttons (lookup/generate/copy...). */
41
+ actions?: EditorAction[];
42
+ /** Stretch to the container width. */
43
+ block?: boolean;
17
44
  };
18
45
  declare const SvTextInput: import("svelte").Component<Props, {}, "value">;
19
46
  type SvTextInput = ReturnType<typeof SvTextInput>;
@@ -11,7 +11,8 @@
11
11
  * and ARIA; this component keeps the DOM-bound pointer capture + hit-testing.
12
12
  * All visuals come from `--sg-*` tokens so every theme applies for free.
13
13
  */
14
- import { resolveMessages, type EditorDir } from './editor-contract'
14
+ import SvField from './SvField.svelte'
15
+ import { nextEditorId, resolveMessages, type EditorDir, type EditorSize } from './editor-contract'
15
16
  import { createTimePicker, type TimeValue, type TimeFormat, type TimeSelection } from './createTimePicker.svelte'
16
17
 
17
18
  /** User-facing strings (localizable via `messages`). */
@@ -38,6 +39,16 @@
38
39
  dir?: EditorDir
39
40
  /** Override the built-in strings (group label + AM/PM/Now). */
40
41
  messages?: Partial<TimeMessages>
42
+ // Optional field chrome: when any of label/hint/error is set, the dial is
43
+ // wrapped in <SvField> so it gains a label/hint/error line; otherwise it
44
+ // renders bare (as embedded inside SvDateTimePicker's popover).
45
+ label?: string
46
+ hint?: string
47
+ error?: string
48
+ required?: boolean
49
+ invalid?: boolean
50
+ size?: EditorSize
51
+ id?: string
41
52
  }
42
53
 
43
54
  let {
@@ -53,8 +64,18 @@
53
64
  selection = 'hour',
54
65
  dir,
55
66
  messages,
67
+ label,
68
+ hint,
69
+ error,
70
+ required = false,
71
+ invalid = false,
72
+ id,
56
73
  }: Props = $props()
57
74
 
75
+ const autoId = nextEditorId('sv-tp')
76
+ const uid = $derived(id ?? autoId)
77
+ const hasChrome = $derived(!!(label || hint || error))
78
+
58
79
  const M = $derived(resolveMessages(DEFAULT_MESSAGES, messages))
59
80
  const resolvedDir = $derived(dir === 'ltr' || dir === 'rtl' ? dir : undefined)
60
81
 
@@ -107,7 +128,8 @@
107
128
  }
108
129
  </script>
109
130
 
110
- <div class="sv-tp" class:sv-tp--disabled={disabled} role="group" aria-label={M.label} dir={resolvedDir}>
131
+ {#snippet dialBody()}
132
+ <div class="sv-tp" class:sv-tp--disabled={disabled} class:sv-tp--invalid={invalid} id={uid} role="group" aria-label={label ?? M.label} dir={resolvedDir}>
111
133
  <div class="sv-tp__head">
112
134
  <button class="sv-tp__seg" class:is-active={tp.selection === 'hour'} {...tp.segProps('hour')}>
113
135
  {String(tp.displayHour).padStart(2, '0')}
@@ -159,6 +181,13 @@
159
181
 
160
182
  {#if name}<input type="hidden" {name} value={`${String(tp.hours).padStart(2, '0')}:${tp.mm}`} />{/if}
161
183
  </div>
184
+ {/snippet}
185
+
186
+ {#if hasChrome}
187
+ <SvField id={uid} {label} {hint} {error} {required} {dir}>{@render dialBody()}</SvField>
188
+ {:else}
189
+ {@render dialBody()}
190
+ {/if}
162
191
 
163
192
  <style>
164
193
  .sv-tp {
@@ -175,6 +204,7 @@
175
204
  border: 1px solid var(--_border); border-radius: calc(var(--_radius) + 4px);
176
205
  user-select: none;
177
206
  }
207
+ .sv-tp--invalid { border-color: var(--sg-danger, #dc2626); }
178
208
  .sv-tp--disabled { opacity: 0.55; pointer-events: none; }
179
209
 
180
210
  .sv-tp__head { display: flex; align-items: center; gap: 2px; font-variant-numeric: tabular-nums; }
@@ -1,13 +1,5 @@
1
1
  export type { TimeValue } from './createTimePicker.svelte';
2
- /**
3
- * SvTimePicker - an analog clock-dial time picker (parity: Smart
4
- * `smart-time-picker`). 12/24-hour, minute snapping, hour->minute auto-switch,
5
- * pointer-drag + keyboard. It is a styled renderer over the headless
6
- * `createTimePicker` core: the core owns the value math, dial geometry, keyboard
7
- * and ARIA; this component keeps the DOM-bound pointer capture + hit-testing.
8
- * All visuals come from `--sg-*` tokens so every theme applies for free.
9
- */
10
- import { type EditorDir } from './editor-contract';
2
+ import { type EditorDir, type EditorSize } from './editor-contract';
11
3
  import { type TimeValue, type TimeFormat, type TimeSelection } from './createTimePicker.svelte';
12
4
  /** User-facing strings (localizable via `messages`). */
13
5
  type TimeMessages = {
@@ -36,6 +28,13 @@ type Props = {
36
28
  dir?: EditorDir;
37
29
  /** Override the built-in strings (group label + AM/PM/Now). */
38
30
  messages?: Partial<TimeMessages>;
31
+ label?: string;
32
+ hint?: string;
33
+ error?: string;
34
+ required?: boolean;
35
+ invalid?: boolean;
36
+ size?: EditorSize;
37
+ id?: string;
39
38
  };
40
39
  declare const SvTimePicker: import("svelte").Component<Props, {}, "">;
41
40
  type SvTimePicker = ReturnType<typeof SvTimePicker>;
@@ -0,0 +1,57 @@
1
+ <script lang="ts">
2
+ /**
3
+ * SvTitle - a heading primitive. `order` sets the semantic level (h1-h6) and,
4
+ * by default, the visual size; pass `size` to decouple the two (e.g. an h2 that
5
+ * looks like an h4). Themes from the shared `--sg-*` tokens.
6
+ *
7
+ * <SvTitle order={1}>Dashboard</SvTitle>
8
+ * <SvTitle order={3} size={5}>Small but semantic h3</SvTitle>
9
+ */
10
+ import type { Snippet } from 'svelte'
11
+
12
+ type Level = 1 | 2 | 3 | 4 | 5 | 6
13
+
14
+ type Props = {
15
+ /** Semantic heading level (h1-h6). */
16
+ order?: Level
17
+ /** Visual size step, defaults to `order`. */
18
+ size?: Level
19
+ /** Text alignment. */
20
+ align?: 'start' | 'center' | 'end'
21
+ /** Truncate to a single line with an ellipsis. */
22
+ truncate?: boolean
23
+ children?: Snippet
24
+ }
25
+
26
+ let { order = 2, size, align, truncate = false, children }: Props = $props()
27
+
28
+ // px + weight per visual step - a compact, balanced type scale.
29
+ const sizeMap = { 1: '30px', 2: '24px', 3: '20px', 4: '17px', 5: '15px', 6: '13px' } as const
30
+ const weightMap = { 1: 700, 2: 700, 3: 600, 4: 600, 5: 600, 6: 600 } as const
31
+ const alignMap = { start: 'left', center: 'center', end: 'right' } as const
32
+
33
+ const step = $derived(size ?? order)
34
+ const tag = $derived(`h${order}`)
35
+ </script>
36
+
37
+ <svelte:element
38
+ this={tag}
39
+ class="sv-title"
40
+ class:is-truncate={truncate}
41
+ style:font-size={sizeMap[step]}
42
+ style:font-weight={weightMap[step]}
43
+ style:text-align={align ? alignMap[align] : undefined}
44
+ >
45
+ {@render children?.()}
46
+ </svelte:element>
47
+
48
+ <style>
49
+ .sv-title {
50
+ margin: 0;
51
+ font-family: var(--sg-font, inherit);
52
+ color: var(--sg-fg, #0f172a);
53
+ line-height: 1.25;
54
+ letter-spacing: -0.01em;
55
+ }
56
+ .sv-title.is-truncate { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
57
+ </style>
@@ -0,0 +1,24 @@
1
+ /**
2
+ * SvTitle - a heading primitive. `order` sets the semantic level (h1-h6) and,
3
+ * by default, the visual size; pass `size` to decouple the two (e.g. an h2 that
4
+ * looks like an h4). Themes from the shared `--sg-*` tokens.
5
+ *
6
+ * <SvTitle order={1}>Dashboard</SvTitle>
7
+ * <SvTitle order={3} size={5}>Small but semantic h3</SvTitle>
8
+ */
9
+ import type { Snippet } from 'svelte';
10
+ type Level = 1 | 2 | 3 | 4 | 5 | 6;
11
+ type Props = {
12
+ /** Semantic heading level (h1-h6). */
13
+ order?: Level;
14
+ /** Visual size step, defaults to `order`. */
15
+ size?: Level;
16
+ /** Text alignment. */
17
+ align?: 'start' | 'center' | 'end';
18
+ /** Truncate to a single line with an ellipsis. */
19
+ truncate?: boolean;
20
+ children?: Snippet;
21
+ };
22
+ declare const SvTitle: import("svelte").Component<Props, {}, "">;
23
+ type SvTitle = ReturnType<typeof SvTitle>;
24
+ export default SvTitle;
@@ -10,7 +10,7 @@
10
10
  * ```
11
11
  */
12
12
  import { portalToBody } from './popover'
13
- import { toastStore, dismissToast, pauseToast, resumeToast, type Toast } from './toast-store.svelte'
13
+ import { toastStore, dismissToast, pauseToast, resumeToast, type Toast, type ToastAction } from './toast-store.svelte'
14
14
 
15
15
  type Position =
16
16
  | 'top-left' | 'top-center' | 'top-right'
@@ -32,6 +32,12 @@
32
32
  // Swipe-to-dismiss: drag a toast sideways past ~60px to dismiss it.
33
33
  let drag = $state<{ id: number; startX: number; dx: number } | null>(null)
34
34
  function onDown(e: PointerEvent, id: number) {
35
+ // Only the primary button starts a swipe.
36
+ if (e.button !== 0) return
37
+ // Don't hijack presses on the toast's own controls (dismiss X, action /
38
+ // cancel buttons). Capturing the pointer here would redirect the pointerup
39
+ // to the toast and swallow the button's click.
40
+ if (e.target instanceof Element && e.target.closest('button')) return
35
41
  drag = { id, startX: e.clientX, dx: 0 }
36
42
  ;(e.currentTarget as HTMLElement).setPointerCapture?.(e.pointerId)
37
43
  pauseToast(id)
@@ -47,6 +53,12 @@
47
53
  else resumeToast(id)
48
54
  }
49
55
  const dragDx = (id: number) => (drag?.id === id ? drag.dx : 0)
56
+
57
+ // Run a toast action, then dismiss the toast unless it opted to stay open.
58
+ function runAction(a: ToastAction, id: number) {
59
+ a.onClick?.(id)
60
+ if (!a.keepOpen) dismissToast(id)
61
+ }
50
62
  </script>
51
63
 
52
64
  <div class="sv-toaster sv-toaster--{position}" use:portalToBody role="region" aria-label="Notifications">
@@ -67,11 +79,25 @@
67
79
  onpointerup={() => onUp(t.id)}
68
80
  onpointercancel={() => onUp(t.id)}
69
81
  >
70
- <span class="sv-toast__icon" aria-hidden="true">{icon(t.variant)}</span>
71
- <div class="sv-toast__content">
72
- {#if t.title}<div class="sv-toast__title">{t.title}</div>{/if}
73
- <div class="sv-toast__msg">{t.message}</div>
74
- </div>
82
+ {#if t.render}
83
+ <div class="sv-toast__content">{@render t.render(t)}</div>
84
+ {:else}
85
+ <span class="sv-toast__icon" aria-hidden="true">{icon(t.variant)}</span>
86
+ <div class="sv-toast__content">
87
+ {#if t.title}<div class="sv-toast__title">{t.title}</div>{/if}
88
+ <div class="sv-toast__msg">{t.message}</div>
89
+ {#if t.action || t.cancel}
90
+ <div class="sv-toast__actions">
91
+ {#if t.cancel}
92
+ <button type="button" class="sv-toast__action sv-toast__action--cancel" onclick={() => runAction(t.cancel!, t.id)}>{t.cancel.label}</button>
93
+ {/if}
94
+ {#if t.action}
95
+ <button type="button" class="sv-toast__action" onclick={() => runAction(t.action!, t.id)}>{t.action.label}</button>
96
+ {/if}
97
+ </div>
98
+ {/if}
99
+ </div>
100
+ {/if}
75
101
  {#if t.dismissible}
76
102
  <button type="button" class="sv-toast__x" aria-label="Dismiss" onclick={() => dismissToast(t.id)}>&times;</button>
77
103
  {/if}
@@ -116,6 +142,15 @@
116
142
  :global(.sv-toast__content) { flex: 1; min-width: 0; }
117
143
  :global(.sv-toast__title) { font-weight: 650; margin-bottom: 1px; }
118
144
  :global(.sv-toast__msg) { color: var(--sg-fg, #0f172a); overflow-wrap: anywhere; }
145
+ :global(.sv-toast__actions) { display: flex; gap: 8px; margin-top: 9px; }
146
+ :global(.sv-toast__action) {
147
+ font: inherit; font-size: 12.5px; font-weight: 600; padding: 4px 11px; border-radius: 6px;
148
+ border: 1px solid var(--_accent, var(--sg-accent, #2563eb)); background: none; color: var(--_accent, var(--sg-accent, #2563eb));
149
+ cursor: pointer;
150
+ }
151
+ :global(.sv-toast__action:hover) { background: color-mix(in srgb, var(--_accent, #2563eb) 12%, transparent); }
152
+ :global(.sv-toast__action--cancel) { border-color: var(--sg-border, #e2e8f0); color: var(--sg-muted, #64748b); }
153
+ :global(.sv-toast__action--cancel:hover) { background: var(--sg-row-hover-bg, #f1f5f9); color: var(--sg-fg, #0f172a); }
119
154
  :global(.sv-toast__x) {
120
155
  flex: none; width: 22px; height: 22px; display: grid; place-items: center; margin: -2px -2px 0 0;
121
156
  background: none; border: 0; color: var(--sg-muted, #64748b); cursor: pointer; border-radius: 5px; font-size: 17px; line-height: 1;
@@ -18,6 +18,7 @@
18
18
  pressed = false,
19
19
  onChange,
20
20
  disabled = false,
21
+ readonly = false,
21
22
  size = 'md',
22
23
  ariaLabel,
23
24
  invalid = false,
@@ -36,7 +37,7 @@
36
37
  // The styled toggle is just a renderer over the headless core.
37
38
  const t = createToggle({
38
39
  pressed: () => pressed,
39
- onChange: (v) => onChange?.(v),
40
+ onChange: (v) => { if (readonly) return; onChange?.(v) },
40
41
  disabled: () => disabled,
41
42
  ariaLabel: () => ariaLabel,
42
43
  id: () => uid,
@@ -52,6 +53,7 @@
52
53
  class="sv-toggle sv-toggle--{size}"
53
54
  class:is-pressed={pressed}
54
55
  class:is-invalid={invalid}
56
+ class:is-readonly={readonly}
55
57
  {...t.buttonProps()}
56
58
  >
57
59
  {#if children}{@render children()}{/if}
@@ -77,6 +79,7 @@
77
79
  background: var(--_accent); color: var(--sg-on-accent, #fff); border-color: var(--_accent);
78
80
  }
79
81
  .sv-toggle[disabled] { opacity: 0.55; cursor: not-allowed; }
82
+ .sv-toggle.is-readonly { cursor: default; }
80
83
  .sv-toggle.is-invalid { border-color: var(--sg-danger, #dc2626); }
81
84
  .sv-toggle:focus-visible { outline: 2px solid var(--sg-focus-ring, var(--_accent)); outline-offset: 2px; }
82
85
  </style>