@svgrid/grid 2.1.22 → 2.2.0

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 (295) hide show
  1. package/README.md +9 -2
  2. package/dist/DockNodeView.svelte +306 -0
  3. package/dist/DockNodeView.svelte.d.ts +7 -0
  4. package/dist/DockPopoutHost.svelte +17 -0
  5. package/dist/DockPopoutHost.svelte.d.ts +14 -0
  6. package/dist/FlexRender.svelte +96 -96
  7. package/dist/GridFooter.svelte +178 -178
  8. package/dist/GridMenus.svelte +83 -3
  9. package/dist/SvAutoComplete.svelte +5 -3
  10. package/dist/SvCarousel.svelte +141 -163
  11. package/dist/SvColorInput.svelte +187 -186
  12. package/dist/SvColorInput.svelte.d.ts +1 -1
  13. package/dist/SvComboBox.svelte +7 -3
  14. package/dist/SvCommand.svelte +28 -85
  15. package/dist/SvContextMenu.svelte +116 -116
  16. package/dist/SvCountryInput.svelte +1 -1
  17. package/dist/SvDateRangeInput.svelte +1 -1
  18. package/dist/SvDateTimePicker.svelte +9 -3
  19. package/dist/SvDateTimePicker.svelte.d.ts +3 -0
  20. package/dist/SvDockLayout.svelte +244 -0
  21. package/dist/SvDockLayout.svelte.d.ts +77 -0
  22. package/dist/SvDockManager.svelte +922 -0
  23. package/dist/SvDockManager.svelte.d.ts +106 -0
  24. package/dist/SvDrawer.svelte +250 -228
  25. package/dist/SvDrawer.svelte.d.ts +4 -0
  26. package/dist/SvDropDownList.svelte +85 -13
  27. package/dist/SvDropDownList.svelte.d.ts +3 -0
  28. package/dist/SvField.svelte +21 -4
  29. package/dist/SvField.svelte.d.ts +1 -0
  30. package/dist/SvForm.svelte +201 -91
  31. package/dist/SvForm.svelte.d.ts +15 -22
  32. package/dist/SvGrid.controller.svelte.d.ts +32 -1
  33. package/dist/SvGrid.controller.svelte.js +156 -27
  34. package/dist/SvGrid.css +193 -5
  35. package/dist/SvGrid.svelte +3131 -2786
  36. package/dist/SvGrid.types.d.ts +452 -1
  37. package/dist/SvGridBoard.svelte +2339 -2339
  38. package/dist/SvGridChart.svelte +1724 -1724
  39. package/dist/SvGridChartPanel.svelte +485 -485
  40. package/dist/SvGridDropdown.svelte +689 -682
  41. package/dist/SvGridSelect.svelte +1 -0
  42. package/dist/SvGroupCell.svelte +109 -109
  43. package/dist/SvListBox.svelte +36 -14
  44. package/dist/SvMaskedInput.svelte +4 -3
  45. package/dist/SvMaskedInput.svelte.d.ts +1 -1
  46. package/dist/SvMenu.svelte +124 -124
  47. package/dist/SvMenuList.svelte +117 -165
  48. package/dist/SvMenuList.svelte.d.ts +2 -13
  49. package/dist/SvModal.svelte +12 -29
  50. package/dist/SvMultiSelect.svelte +1 -0
  51. package/dist/SvNumberInput.svelte +131 -130
  52. package/dist/SvNumberInput.svelte.d.ts +1 -1
  53. package/dist/SvOtpInput.svelte +158 -158
  54. package/dist/SvPagination.svelte +18 -18
  55. package/dist/SvPasswordInput.svelte +3 -2
  56. package/dist/SvPasswordInput.svelte.d.ts +1 -1
  57. package/dist/SvPhoneInput.svelte +3 -2
  58. package/dist/SvPhoneInput.svelte.d.ts +1 -1
  59. package/dist/SvPopover.svelte +139 -139
  60. package/dist/SvRowGroupPanel.svelte +170 -170
  61. package/dist/SvScrollArea.svelte +61 -61
  62. package/dist/SvStepper.svelte +6 -9
  63. package/dist/SvTagsInput.svelte +3 -2
  64. package/dist/SvTagsInput.svelte.d.ts +1 -1
  65. package/dist/SvTooltip.svelte +127 -138
  66. package/dist/SvTour.svelte +204 -176
  67. package/dist/SvTree.svelte +377 -377
  68. package/dist/SvTreeSelect.svelte +230 -229
  69. package/dist/build-api.js +76 -54
  70. package/dist/cdn/svgrid.js +10913 -6450
  71. package/dist/cdn/svgrid.svelte-external.js +9628 -5481
  72. package/dist/chart-export.js +8 -8
  73. package/dist/columns.js +6 -0
  74. package/dist/conditional-formatting.d.ts +67 -3
  75. package/dist/conditional-formatting.js +124 -17
  76. package/dist/createCarousel.svelte.d.ts +72 -0
  77. package/dist/createCarousel.svelte.js +80 -0
  78. package/dist/createCommand.svelte.d.ts +62 -0
  79. package/dist/createCommand.svelte.js +109 -0
  80. package/dist/createForm.svelte.d.ts +62 -0
  81. package/dist/createForm.svelte.js +374 -0
  82. package/dist/createMenu.svelte.d.ts +88 -0
  83. package/dist/createMenu.svelte.js +153 -0
  84. package/dist/createOverlay.svelte.d.ts +38 -0
  85. package/dist/createOverlay.svelte.js +68 -0
  86. package/dist/createPagination.d.ts +74 -0
  87. package/dist/createPagination.js +71 -0
  88. package/dist/createPopoverSelect.svelte.js +6 -12
  89. package/dist/createStepper.d.ts +44 -0
  90. package/dist/createStepper.js +26 -0
  91. package/dist/createTooltip.svelte.d.ts +32 -0
  92. package/dist/createTooltip.svelte.js +61 -0
  93. package/dist/datetime/timezone.d.ts +36 -0
  94. package/dist/datetime/timezone.js +110 -0
  95. package/dist/dock-context.d.ts +52 -0
  96. package/dist/dock-context.js +1 -0
  97. package/dist/dock-manager-model.d.ts +136 -0
  98. package/dist/dock-manager-model.js +514 -0
  99. package/dist/dock-model.d.ts +105 -0
  100. package/dist/dock-model.js +288 -0
  101. package/dist/dock-popout.d.ts +30 -0
  102. package/dist/dock-popout.js +81 -0
  103. package/dist/editor-contract.d.ts +2 -0
  104. package/dist/filter-operators.d.ts +6 -0
  105. package/dist/filter-operators.js +35 -2
  106. package/dist/filtering/excel-filters.d.ts +18 -1
  107. package/dist/filtering/excel-filters.js +56 -0
  108. package/dist/form-field.d.ts +73 -0
  109. package/dist/form-field.js +15 -0
  110. package/dist/index.d.ts +25 -5
  111. package/dist/index.js +40 -4
  112. package/dist/list-nav.d.ts +18 -0
  113. package/dist/list-nav.js +30 -0
  114. package/dist/list-option.d.ts +2 -0
  115. package/dist/menu-item.d.ts +20 -0
  116. package/dist/menu-item.js +1 -0
  117. package/dist/menus.d.ts +5 -0
  118. package/dist/menus.js +68 -16
  119. package/dist/panel-resize.d.ts +25 -0
  120. package/dist/panel-resize.js +40 -0
  121. package/dist/popover.d.ts +29 -3
  122. package/dist/popover.js +22 -6
  123. package/dist/recurrence.d.ts +33 -7
  124. package/dist/recurrence.js +151 -13
  125. package/dist/row-drag.d.ts +8 -0
  126. package/dist/row-drag.js +11 -0
  127. package/dist/scheduler-ical.d.ts +30 -0
  128. package/dist/scheduler-ical.js +180 -0
  129. package/dist/scheduler-model.d.ts +269 -0
  130. package/dist/scheduler-model.js +602 -0
  131. package/dist/scheduler-view.svelte.d.ts +22 -0
  132. package/dist/scheduler-view.svelte.js +13 -0
  133. package/dist/spreadsheet.js +20 -12
  134. package/dist/ui-app.types.d.ts +3 -0
  135. package/package.json +14 -10
  136. package/src/DockNodeView.svelte +306 -0
  137. package/src/DockPopoutHost.svelte +17 -0
  138. package/src/FlexRender.svelte +96 -96
  139. package/src/GridFooter.svelte +178 -178
  140. package/src/GridMenus.svelte +83 -3
  141. package/src/SvAutoComplete.svelte +5 -3
  142. package/src/SvCarousel.svelte +141 -163
  143. package/src/SvCarousel.test.ts +68 -0
  144. package/src/SvColorInput.svelte +187 -186
  145. package/src/SvComboBox.svelte +7 -3
  146. package/src/SvCommand.svelte +28 -85
  147. package/src/SvCommand.test.ts +78 -0
  148. package/src/SvContextMenu.svelte +116 -116
  149. package/src/SvCountryInput.svelte +1 -1
  150. package/src/SvDateRangeInput.svelte +1 -1
  151. package/src/SvDateTimePicker.svelte +9 -3
  152. package/src/SvDockLayout.svelte +244 -0
  153. package/src/SvDockManager.svelte +922 -0
  154. package/src/SvDrawer.svelte +250 -228
  155. package/src/SvDropDownList.svelte +85 -13
  156. package/src/SvField.svelte +21 -4
  157. package/src/SvForm.svelte +201 -91
  158. package/src/SvForm.test.ts +299 -0
  159. package/src/SvGrid.controller.svelte.ts +3158 -3034
  160. package/src/SvGrid.css +193 -5
  161. package/src/SvGrid.svelte +3131 -2786
  162. package/src/SvGrid.types.ts +1489 -1027
  163. package/src/SvGridBoard.svelte +2339 -2339
  164. package/src/SvGridChart.svelte +1724 -1724
  165. package/src/SvGridChartPanel.svelte +485 -485
  166. package/src/SvGridDropdown.svelte +689 -682
  167. package/src/SvGridSelect.svelte +1 -0
  168. package/src/SvGroupCell.svelte +109 -109
  169. package/src/SvListBox.svelte +36 -14
  170. package/src/SvMaskedInput.svelte +4 -3
  171. package/src/SvMenu.svelte +124 -124
  172. package/src/SvMenu.test.ts +97 -73
  173. package/src/SvMenuList.svelte +117 -165
  174. package/src/SvModal.svelte +12 -29
  175. package/src/SvModal.test.ts +82 -0
  176. package/src/SvMultiSelect.svelte +1 -0
  177. package/src/SvNumberInput.svelte +131 -130
  178. package/src/SvOtpInput.svelte +158 -158
  179. package/src/SvPagination.svelte +18 -18
  180. package/src/SvPasswordInput.svelte +3 -2
  181. package/src/SvPhoneInput.svelte +3 -2
  182. package/src/SvPopover.svelte +139 -139
  183. package/src/SvRowGroupPanel.svelte +170 -170
  184. package/src/SvScrollArea.svelte +61 -61
  185. package/src/SvStepper.svelte +6 -9
  186. package/src/SvTagsInput.svelte +3 -2
  187. package/src/SvTooltip.svelte +127 -138
  188. package/src/SvTooltip.test.ts +73 -0
  189. package/src/SvTour.svelte +204 -176
  190. package/src/SvTree.svelte +377 -377
  191. package/src/SvTreeSelect.svelte +230 -229
  192. package/src/a11y.contract.test.ts +49 -49
  193. package/src/a11y.test.ts +59 -59
  194. package/src/a11y.ts +61 -61
  195. package/src/build-api.ts +870 -847
  196. package/src/cell-formatting.ts +169 -169
  197. package/src/cell-render.ts +469 -469
  198. package/src/chart-export.ts +201 -201
  199. package/src/chart.ts +2296 -2296
  200. package/src/collaboration.test.ts +104 -104
  201. package/src/collaboration.ts +167 -167
  202. package/src/columns.ts +5 -0
  203. package/src/conditional-formatting.test.ts +104 -0
  204. package/src/conditional-formatting.ts +176 -19
  205. package/src/core.performance.test.ts +30 -30
  206. package/src/core.ts +1111 -1111
  207. package/src/createAutocomplete.svelte.ts +132 -132
  208. package/src/createCarousel.svelte.ts +104 -0
  209. package/src/createCombobox.svelte.ts +179 -179
  210. package/src/createCommand.svelte.ts +125 -0
  211. package/src/createCountryInput.svelte.ts +157 -157
  212. package/src/createDropdownList.svelte.ts +162 -162
  213. package/src/createForm.svelte.ts +333 -0
  214. package/src/createGrid.svelte.ts +42 -42
  215. package/src/createGrid.test.ts +10 -10
  216. package/src/createGridState.svelte.ts +17 -17
  217. package/src/createMenu.svelte.ts +202 -0
  218. package/src/createOverlay.svelte.ts +101 -0
  219. package/src/createPagination.test.ts +65 -0
  220. package/src/createPagination.ts +84 -0
  221. package/src/createPopoverSelect.svelte.ts +206 -210
  222. package/src/createStepper.test.ts +62 -0
  223. package/src/createStepper.ts +61 -0
  224. package/src/createTooltip.svelte.ts +86 -0
  225. package/src/createTree.svelte.ts +319 -319
  226. package/src/datetime/timezone.test.ts +69 -0
  227. package/src/datetime/timezone.ts +134 -0
  228. package/src/dock-context.ts +47 -0
  229. package/src/dock-manager-model.test.ts +275 -0
  230. package/src/dock-manager-model.ts +593 -0
  231. package/src/dock-model.test.ts +163 -0
  232. package/src/dock-model.ts +368 -0
  233. package/src/dock-popout.ts +94 -0
  234. package/src/editing.test.ts +859 -859
  235. package/src/editing.ts +675 -675
  236. package/src/editor-contract.ts +2 -0
  237. package/src/export-data-api.test.ts +126 -126
  238. package/src/export-format.test.ts +107 -107
  239. package/src/export-format.ts +598 -598
  240. package/src/filter-operators.test.ts +59 -0
  241. package/src/filter-operators.ts +35 -2
  242. package/src/filtering/excel-filters.test.ts +86 -1
  243. package/src/filtering/excel-filters.ts +65 -0
  244. package/src/flex-render.ts +3 -3
  245. package/src/form-field.ts +87 -0
  246. package/src/index.ts +623 -469
  247. package/src/keyboard.test.ts +59 -59
  248. package/src/keyboard.ts +97 -97
  249. package/src/list-nav.test.ts +49 -0
  250. package/src/list-nav.ts +29 -0
  251. package/src/list-option.ts +2 -0
  252. package/src/menu-item.ts +21 -0
  253. package/src/menus.test.ts +48 -0
  254. package/src/menus.ts +639 -582
  255. package/src/merge-objects.ts +48 -48
  256. package/src/overlays.test.ts +90 -90
  257. package/src/panel-resize.ts +52 -0
  258. package/src/popover.bounds.test.ts +93 -0
  259. package/src/popover.ts +51 -7
  260. package/src/recurrence.test.ts +88 -1
  261. package/src/recurrence.ts +166 -15
  262. package/src/render-component.ts +28 -28
  263. package/src/row-drag.ts +10 -0
  264. package/src/scheduler-ical.test.ts +68 -0
  265. package/src/scheduler-ical.ts +180 -0
  266. package/src/scheduler-model.test.ts +546 -0
  267. package/src/scheduler-model.ts +853 -0
  268. package/src/scheduler-view.svelte.ts +33 -0
  269. package/src/selection.test.ts +754 -754
  270. package/src/selection.ts +600 -600
  271. package/src/server-data-source.test.ts +289 -289
  272. package/src/server-data-source.ts +413 -413
  273. package/src/sparkline.test.ts +68 -68
  274. package/src/sparkline.ts +169 -169
  275. package/src/spreadsheet.test.ts +489 -489
  276. package/src/spreadsheet.ts +312 -304
  277. package/src/static-functions.ts +11 -11
  278. package/src/subscribe.ts +38 -38
  279. package/src/svgrid-wrapper.types.ts +501 -501
  280. package/src/svgrid.behavior.test.ts +706 -706
  281. package/src/svgrid.charting.test.ts +527 -527
  282. package/src/svgrid.effect-driven-filter.svelte.test.ts +116 -0
  283. package/src/svgrid.features.test.ts +157 -157
  284. package/src/svgrid.new-features.wrapper.test.ts +251 -251
  285. package/src/svgrid.wrapper.test.ts +40 -40
  286. package/src/test-setup.ts +62 -62
  287. package/src/themes/index.ts +159 -159
  288. package/src/ui-app.types.ts +3 -0
  289. package/src/virtual.test.ts +6 -4
  290. package/src/virtualization/column-virtualizer.test.ts +27 -27
  291. package/src/virtualization/column-virtualizer.ts +30 -30
  292. package/src/virtualization/svelte-virtualizer.svelte.ts +26 -26
  293. package/src/virtualization/types.ts +30 -30
  294. package/src/virtualization/virtualizer.test.ts +47 -47
  295. package/src/virtualization/virtualizer.ts +296 -296
@@ -13,6 +13,30 @@ export function normalizeForFilter(s, locale) {
13
13
  ? stripped.toLocaleLowerCase(locale)
14
14
  : stripped.toLowerCase();
15
15
  }
16
+ /**
17
+ * Delimiter used to serialise the `in` / `notIn` value list into the single
18
+ * `value` string that the filter model carries. A newline is used because it
19
+ * (unlike a comma) practically never appears inside a typed token, so tokens
20
+ * survive the round-trip unescaped. The chip input in the filter row reads and
21
+ * writes with the same separator via {@link splitInTokens} / {@link joinInTokens}.
22
+ */
23
+ export const IN_TOKEN_SEP = '\n';
24
+ /**
25
+ * Split a serialised `in` / `notIn` value into its individual tokens. Accepts
26
+ * both the newline separator the chip input writes and a plain comma-separated
27
+ * string (what a raw text field, e.g. the tool-panel filter, produces), so the
28
+ * same value round-trips through either UI.
29
+ */
30
+ export function splitInTokens(value) {
31
+ return String(value ?? '')
32
+ .split(/[\n,]/)
33
+ .map((t) => t.trim())
34
+ .filter((t) => t.length > 0);
35
+ }
36
+ /** Serialise a list of tokens back into the single `in` / `notIn` value. */
37
+ export function joinInTokens(tokens) {
38
+ return tokens.map((t) => t.trim()).filter((t) => t.length > 0).join(IN_TOKEN_SEP);
39
+ }
16
40
  export function applyExcelFilter(cellValue, filter, options) {
17
41
  const text = String(cellValue ?? '');
18
42
  const normalizedText = normalizeForFilter(text, options?.locale);
@@ -20,10 +44,40 @@ export function applyExcelFilter(cellValue, filter, options) {
20
44
  switch (filter.operator) {
21
45
  case 'contains':
22
46
  return normalizedText.includes(normalizedValue);
47
+ case 'notContains':
48
+ // An empty needle is no constraint (mirrors `contains` returning true),
49
+ // so nothing is excluded until the user types something.
50
+ return normalizedValue === '' || !normalizedText.includes(normalizedValue);
23
51
  case 'equals':
24
52
  return normalizedText === normalizedValue;
53
+ case 'notEquals':
54
+ return normalizedValue === '' || normalizedText !== normalizedValue;
25
55
  case 'startsWith':
26
56
  return normalizedText.startsWith(normalizedValue);
57
+ case 'endsWith':
58
+ return normalizedText.endsWith(normalizedValue);
59
+ case 'regex': {
60
+ // Case-insensitive by default (matches the accent/case-folded feel of
61
+ // the other text operators). An invalid pattern matches nothing rather
62
+ // than throwing, so a half-typed regex never crashes the row model.
63
+ const pattern = String(filter.value ?? '');
64
+ if (!pattern)
65
+ return true;
66
+ try {
67
+ return new RegExp(pattern, 'i').test(text);
68
+ }
69
+ catch {
70
+ return false;
71
+ }
72
+ }
73
+ case 'in':
74
+ case 'notIn': {
75
+ const tokens = splitInTokens(filter.value);
76
+ if (tokens.length === 0)
77
+ return true;
78
+ const hit = tokens.some((t) => normalizeForFilter(t, options?.locale) === normalizedText);
79
+ return filter.operator === 'in' ? hit : !hit;
80
+ }
27
81
  case 'greaterThan': {
28
82
  const a = Number(cellValue);
29
83
  const b = Number(filter.value);
@@ -60,5 +114,7 @@ export function applyExcelFilter(cellValue, filter, options) {
60
114
  }
61
115
  case 'isBlank':
62
116
  return text.trim().length === 0;
117
+ case 'isNotBlank':
118
+ return text.trim().length > 0;
63
119
  }
64
120
  }
@@ -0,0 +1,73 @@
1
+ import type { Validator } from './validators';
2
+ /**
3
+ * Field descriptor for <SvForm> and the headless `createForm` core. Kept in a
4
+ * plain `.ts` module so the core can import the type without pulling in the
5
+ * `.svelte` component (which would create a `.svelte.ts` -> `.svelte` import
6
+ * cycle Vite's dev import-analysis fails to resolve).
7
+ */
8
+ export type FormFieldType = 'text' | 'email' | 'tel' | 'textarea' | 'number' | 'password' | 'select' | 'checkbox' | 'switch' | 'date' | 'color' | 'rating' | 'array';
9
+ export type FormField = {
10
+ name: string;
11
+ label: string;
12
+ type?: FormFieldType;
13
+ required?: boolean;
14
+ placeholder?: string;
15
+ options?: Array<{
16
+ value: string | number;
17
+ label: string;
18
+ color?: string;
19
+ }>;
20
+ /** Declarative validation rules (see `rules` - email/pattern/min/compare...). */
21
+ rules?: ReadonlyArray<Validator>;
22
+ /** Return an error message, or null/undefined when valid. */
23
+ validate?: (value: any, values: Record<string, any>) => string | null | undefined;
24
+ /**
25
+ * Async validator (e.g. "is this username taken?"). Runs after the sync checks
26
+ * pass, debounced (`asyncDebounce`, default 300ms) and stale-guarded so only the
27
+ * latest result wins. While it runs, `form.isValidating(name)` is true and the
28
+ * field shows a checking indicator. Submit waits for all async validators.
29
+ */
30
+ asyncValidate?: (value: any, values: Record<string, any>) => Promise<string | null | undefined>;
31
+ /** Debounce (ms) before `asyncValidate` runs on edit. Default 300. */
32
+ asyncDebounce?: number;
33
+ /** Span full width in the grid. */
34
+ full?: boolean;
35
+ /**
36
+ * Show the field only when this is `true` / returns `true` (default: always).
37
+ * A field derived from other values, e.g. `visible: (v) => v.hasAddress`.
38
+ * Hidden fields are skipped in validation and excluded from the submitted values.
39
+ */
40
+ visible?: boolean | ((values: Record<string, any>) => boolean);
41
+ /** Disable the field, statically or derived from other values. */
42
+ disabled?: boolean | ((values: Record<string, any>) => boolean);
43
+ /**
44
+ * For `type: 'array'` - the fields of each repeatable item. The value is an
45
+ * array of item objects; each item's fields validate against that item (so
46
+ * cross-field rules within a row work). `required`/`minItems`/`maxItems` gate
47
+ * the array length.
48
+ */
49
+ itemFields?: ReadonlyArray<FormField>;
50
+ /** Label for the "add item" button of an array field. Default "+ Add". */
51
+ addLabel?: string;
52
+ /** Min / max item count for an array field. */
53
+ minItems?: number;
54
+ maxItems?: number;
55
+ };
56
+ /**
57
+ * A group of fields rendered as a titled fieldset - and, when `<SvForm stepper>`
58
+ * is set, as one step of a wizard. Use in place of a plain `FormField` inside the
59
+ * `fields` array; the schema may freely mix flat fields and sections.
60
+ */
61
+ export type FormSection = {
62
+ section: string;
63
+ description?: string;
64
+ fields: ReadonlyArray<FormField>;
65
+ /** Column count for this section's grid (defaults to the form's `columns`). */
66
+ columns?: number;
67
+ };
68
+ /** An entry in a form schema: either a single field or a titled section/step. */
69
+ export type FormEntry = FormField | FormSection;
70
+ /** Narrow a schema entry to a section (has a `fields` array). */
71
+ export declare function isFormSection(e: FormEntry): e is FormSection;
72
+ /** Flatten a mixed schema (fields + sections) to the flat list of fields. */
73
+ export declare function flattenFields(entries: ReadonlyArray<FormEntry>): FormField[];
@@ -0,0 +1,15 @@
1
+ /** Narrow a schema entry to a section (has a `fields` array). */
2
+ export function isFormSection(e) {
3
+ return Array.isArray(e.fields);
4
+ }
5
+ /** Flatten a mixed schema (fields + sections) to the flat list of fields. */
6
+ export function flattenFields(entries) {
7
+ const out = [];
8
+ for (const e of entries) {
9
+ if (isFormSection(e))
10
+ out.push(...e.fields);
11
+ else
12
+ out.push(e);
13
+ }
14
+ return out;
15
+ }
package/dist/index.d.ts CHANGED
@@ -7,9 +7,12 @@ export { subscribeGrid, subscribeSvGrid } from './subscribe';
7
7
  export { default as SvGrid } from './SvGrid.svelte';
8
8
  export { default as SvGridBoard } from './SvGridBoard.svelte';
9
9
  export type { BoardConfig, BoardLane, BoardCardMoveEvent, BoardCardCommitEvent, BoardLayout, BoardSubtask, BoardComment, BoardMenuContext, BoardLaneMenuContext, BoardDrawerConfig } from './SvGrid.types';
10
+ export type { SchedulerConfig, SchedulerDrawerConfig, SchedulerEventMoveEvent, SchedulerEventResizeEvent, SchedulerEventCommitEvent, SchedulerRangeSelection, SchedulerView, SchedulerResource, SchedulerCollisionMode, SchedulerException, SchedulerEditScope, SchedulerOccurrenceChangeEvent, } from './SvGrid.types';
11
+ export { registerSchedulerView, getSchedulerView, hasSchedulerView } from './scheduler-view.svelte';
12
+ export { resolveEvents, hasConflict, overlapCount, overlapsBands, workingIntervals, withinWorking, type WorkingWindow, eventsOnDay, layoutDayEvents, monthWeekSegments, agendaGroups, rangeForView, daysForView, navigateAnchor, timelineAxis, timelineGeom, timelineRows, type ResolvedEvent, type EventSpec, type RecurrenceException, type PositionedEvent, type OverflowMarker, type DayLayout, type LayoutOptions, type MonthSegment, type AgendaGroup, type TimelineTick, type TimelineMajor, type TimelineAxis, type TimelineRow, } from './scheduler-model';
10
13
  export { default as SvGridDropdown } from './SvGridDropdown.svelte';
11
14
  export { default as SvCalendar, type CalendarValue, type CalendarPreset, type CalendarAnimation } from './SvCalendar.svelte';
12
- export { matchesRecurrence, expandRecurrence, type RecurrenceRule, type RecurrenceFreq } from './recurrence';
15
+ export { matchesRecurrence, expandRecurrence, describeRecurrence, type RecurrenceRule, type RecurrenceFreq, type RecurrenceLabels, } from './recurrence';
13
16
  export { default as SvTimePicker, type TimeValue } from './SvTimePicker.svelte';
14
17
  export { default as SvDateTimePicker, type DateTimeValue } from './SvDateTimePicker.svelte';
15
18
  export { default as SvDateRangeInput, type DateRangeValue } from './SvDateRangeInput.svelte';
@@ -20,12 +23,22 @@ export { FOCUSABLE_SELECTOR, getFocusable, createFocusTrap, type FocusTrap, type
20
23
  export { lockScroll, scrollLockDepth } from './a11y/scroll-lock';
21
24
  export { createDismissableLayer, dismissableDepth, type DismissableLayer, type DismissableOptions, } from './a11y/dismissable';
22
25
  export { announce, type AnnounceOptions } from './a11y/live-region';
26
+ export { createOverlay, type Overlay, type OverlayConfig, type DialogProps } from './createOverlay.svelte';
27
+ export { createTooltip, type Tooltip, type TooltipConfig, type TooltipAnchorProps, type TooltipProps } from './createTooltip.svelte';
28
+ export { createPagination, type Pagination, type PaginationConfig } from './createPagination';
29
+ export { createStepper, type Stepper, type StepperConfig, type StepStatus } from './createStepper';
30
+ export { createCarousel, type Carousel, type CarouselConfig } from './createCarousel.svelte';
31
+ export { createCommand, type Command, type CommandConfig } from './createCommand.svelte';
32
+ export { createForm, type Form, type FormConfig } from './createForm.svelte';
23
33
  export { registerCellEditor, getCellEditor, hasCellEditor, unregisterCellEditor, registeredCellEditorTypes, defaultEditorProps, resolveEditorProps, type CellEditorContext, type CellEditorRegistration, } from './editor-registry';
24
34
  export { registerBuiltinEditors } from './builtin-editors';
25
35
  export { default as SvField } from './SvField.svelte';
26
36
  export { createListbox, toSelectedArray, type Listbox, type ListboxConfig, type ListboxValue, type ListboxRootProps, type OptionProps, } from './createListbox.svelte';
27
37
  export { createCombobox, type Combobox, type ComboboxConfig, type ComboboxValue } from './createCombobox.svelte';
28
38
  export { createDropdownList, type DropdownList, type DropdownListConfig, type DropdownValue } from './createDropdownList.svelte';
39
+ export { createPopoverSelect, type PopoverSelect, type PopoverSelectConfig } from './createPopoverSelect.svelte';
40
+ export { createMenu, type Menu, type MenuConfig, type MenuItemProps } from './createMenu.svelte';
41
+ export { enabledIndices, wrapMove } from './list-nav';
29
42
  export { createAutocomplete, type Autocomplete, type AutocompleteConfig } from './createAutocomplete.svelte';
30
43
  export { createTagsInput, type TagsInput, type TagsInputConfig } from './createTagsInput.svelte';
31
44
  export { createCountryInput, type CountryInput, type CountryInputConfig } from './createCountryInput.svelte';
@@ -89,6 +102,10 @@ export { default as SvAccordion, type AccordionItem, type AccordionExpandMode }
89
102
  export { createAccordion, type Accordion, type AccordionConfig } from './createAccordion.svelte';
90
103
  export { default as SvSplitter, type SplitterOrientation } from './SvSplitter.svelte';
91
104
  export { createSplitter, type Splitter, type SplitterConfig, type SplitterPoint } from './createSplitter.svelte';
105
+ export { default as SvDockLayout } from './SvDockLayout.svelte';
106
+ export { default as SvDockManager, type DockManagerApi, type DockEvent } from './SvDockManager.svelte';
107
+ export { dockPane, dockTabs, dockGroup, removePane, movePane, dockInto, reorderPane, removeLeaf, dockLeafToEdge, setActive as dockSetActive, setSizes as dockSetSizes, normalize as dockNormalize, findTabsWithPane, allPaneIds, type DockNode, type DockGroup, type DockTabs, type DockPane, type DockZone, } from './dock-model';
108
+ export { floatPane, dockPaneOnto, dockWindowOnto, dockPaneToEmptyMain, reorderTab, autoHideLeaf, autoHidePaneToSide, pinAutoHidden, setAutoHideSize, closePane as dockManagerClosePane, moveWindow, resizeWindow, bringToFront, setWindowMinimized, toggleWindowMaximized, closeWindow, autoHideWindow, toggleMaximizeLeaf, findLeafById, addPaneToMain, resizeGroup as dockManagerResizeGroup, setManagerActive, locatePane, surfaceOfTabs, allManagerPaneIds, allManagerIds, dedupeManagerNodeIds, type DockManagerState, type FloatWindow, type AutoHideEntry, type DockSide, type PaneLocation, } from './dock-manager-model';
92
109
  export { default as SvFileUpload, type FileRejection, type FileRejectReason } from './SvFileUpload.svelte';
93
110
  export { createFileUpload, fileMatchesAccept, type FileUpload, type FileUploadConfig } from './createFileUpload.svelte';
94
111
  export { default as SvPopover } from './SvPopover.svelte';
@@ -123,15 +140,18 @@ export { avatarInitials, avatarColorHue } from './avatar';
123
140
  export { default as SvContextMenu } from './SvContextMenu.svelte';
124
141
  export { toast, dismissToast, clearToasts, pauseToast, resumeToast, toastStore, type Toast, type ToastVariant, type ToastOptions, type ToastFn, } from './toast-store.svelte';
125
142
  export { default as SvMenu, type MenuItem } from './SvMenu.svelte';
143
+ export { default as SvMenuList } from './SvMenuList.svelte';
126
144
  export { default as SvNavPane, type NavItem, type NavSection, type NavModule } from './SvNavPane.svelte';
127
145
  export { default as SvProgress } from './SvProgress.svelte';
128
146
  export { default as SvCircularProgress } from './SvCircularProgress.svelte';
129
147
  export { popIn } from './popover';
130
- export { default as SvForm, type FormField, type FormFieldType } from './SvForm.svelte';
148
+ export { default as SvForm, type FormField, type FormFieldType, type FormSection, type FormEntry } from './SvForm.svelte';
131
149
  export { rules, runRules, isEmptyValue, type Validator, type RuleOptions, type CompareOp } from './validators';
132
150
  export { anchoredRect, portalToBody, PANEL_THEME_VARS, type AnchoredRect } from './popover';
133
- export { toDate, startOfDay, addDays, addMonths, addYears, clampDate, isSameDay, monthMatrix, isoWeek, decadeRange, withTime, snapMinute, type DateLike, } from './datetime/date-core';
151
+ export { toDate, startOfDay, startOfWeek, startOfMonth, addDays, addMonths, addYears, clampDate, isSameDay, monthMatrix, weekdayOrder, isoWeek, decadeRange, withTime, snapMinute, type DateLike, } from './datetime/date-core';
134
152
  export { formatDate, parseDate, tokenizeMask } from './datetime/date-format';
153
+ export { toICS, fromICS, ruleToRRule, rruleToRule, type ICalEvent } from './scheduler-ical';
154
+ export { zoneParts, zoneOffsetMs, toZonedLocal, fromZonedLocal, instantFromWallClock, zoneAbbr, normalizeTimeZone, type ZoneParts, } from './datetime/timezone';
135
155
  export { selectDate, rangeDays, isSelected, isMultiSelectMode, emptySelection, type SelectionMode, type SelectionState, } from './datetime/date-selection';
136
156
  export { isDisabledDay, isOutOfRange, isRestricted, isImportant, type RestrictOptions, } from './datetime/date-restrict';
137
157
  export { default as FlexRender } from './FlexRender.svelte';
@@ -154,7 +174,7 @@ export { createServerGroupModel, serverGroupRows, serverGroupNav, type ServerGro
154
174
  export { default as SvGroupCell } from './SvGroupCell.svelte';
155
175
  export { default as SvRowGroupPanel } from './SvRowGroupPanel.svelte';
156
176
  export { createNamedViews, memoryViews, localStorageViews, attachAutoSavedView, type SavedView, type ViewStorage, type NamedViews, type AutoSavedViewOptions, } from './named-views';
157
- export { resolveCellFormat, computeColumnStat, lerpColor, contrastText, type ConditionalFormat, type ConditionalFormatSpec, type ColorScaleFormat, type DataBarFormat, type IconSetFormat, type RuleFormat, type ResolvedCellFormat, } from './conditional-formatting';
177
+ export { resolveCellFormat, computeColumnStat, lerpColor, rgba, contrastText, formatNeedsStats, formatsNeedingStats, type ConditionalFormat, type ConditionalFormatSpec, type ColorScaleFormat, type ColorScaleStop, type ScaleBounds, type DataBarFormat, type IconSetFormat, type RuleFormat, type ResolvedCellFormat, } from './conditional-formatting';
158
178
  export { getKeyboardIntent, getNextActiveCell, type GridKeyboardIntent } from './keyboard';
159
179
  export { createVirtualizer } from './virtualization/virtualizer';
160
180
  export { createSvelteVirtualizer } from './virtualization/svelte-virtualizer.svelte';
@@ -162,7 +182,7 @@ export { createColumnVirtualizer } from './virtualization/column-virtualizer';
162
182
  export type { VirtualItem, VirtualizerOptions, VirtualizerState } from './virtualization/types';
163
183
  export type { SvGridApi, SvGridFilterOperator, SvGridWrapperProps } from './svgrid-wrapper.types';
164
184
  export { parseEditorValue, normalizeEditorOptions, type CellEditorType, type CellEditorOption, } from './editors/cell-editors';
165
- export { applyExcelFilter, normalizeForFilter, type ExcelFilter, type ExcelFilterOperator, type ExcelFilterOptions, } from './filtering/excel-filters';
185
+ export { applyExcelFilter, normalizeForFilter, splitInTokens, joinInTokens, type ExcelFilter, type ExcelFilterOperator, type ExcelFilterOptions, } from './filtering/excel-filters';
166
186
  export { getGridCellDomId, getGridCellA11yProps, getGridHeaderA11yProps, getGridRootA11yProps, getGridRowA11yProps, type GridCellA11yInput, type GridColumnA11yInput, type GridSortDirection, } from './a11y';
167
187
  /**
168
188
  * Compatibility alias for teams migrating from `createTable`.
package/dist/index.js CHANGED
@@ -6,9 +6,13 @@ export { createGridState, createSvGridState } from './createGridState.svelte';
6
6
  export { subscribeGrid, subscribeSvGrid } from './subscribe';
7
7
  export { default as SvGrid } from './SvGrid.svelte';
8
8
  export { default as SvGridBoard } from './SvGridBoard.svelte';
9
+ export { registerSchedulerView, getSchedulerView, hasSchedulerView } from './scheduler-view.svelte';
10
+ // Pure scheduler layout/model helpers (framework-free, like recurrence/date-core).
11
+ // The calendar RENDERER that consumes these ships in @svgrid/enterprise.
12
+ export { resolveEvents, hasConflict, overlapCount, overlapsBands, workingIntervals, withinWorking, eventsOnDay, layoutDayEvents, monthWeekSegments, agendaGroups, rangeForView, daysForView, navigateAnchor, timelineAxis, timelineGeom, timelineRows, } from './scheduler-model';
9
13
  export { default as SvGridDropdown } from './SvGridDropdown.svelte';
10
14
  export { default as SvCalendar } from './SvCalendar.svelte';
11
- export { matchesRecurrence, expandRecurrence } from './recurrence';
15
+ export { matchesRecurrence, expandRecurrence, describeRecurrence, } from './recurrence';
12
16
  export { default as SvTimePicker } from './SvTimePicker.svelte';
13
17
  export { default as SvDateTimePicker } from './SvDateTimePicker.svelte';
14
18
  export { default as SvDateRangeInput } from './SvDateRangeInput.svelte';
@@ -20,6 +24,23 @@ export { FOCUSABLE_SELECTOR, getFocusable, createFocusTrap, } from './a11y/focus
20
24
  export { lockScroll, scrollLockDepth } from './a11y/scroll-lock';
21
25
  export { createDismissableLayer, dismissableDepth, } from './a11y/dismissable';
22
26
  export { announce } from './a11y/live-region';
27
+ // Dialog-overlay core (SvModal / SvDrawer): open -> focus-trap + scroll-lock +
28
+ // Escape/backdrop dismissal -> restore, on the primitives above.
29
+ export { createOverlay } from './createOverlay.svelte';
30
+ // Tooltip core (SvTooltip): hover/focus open with a show delay, Escape-to-hide,
31
+ // and aria-describedby / role=tooltip wiring. (Toasts are already headless: see
32
+ // the toastStore / toast() exports below.)
33
+ export { createTooltip } from './createTooltip.svelte';
34
+ // Navigation cores: pager (SvPagination), wizard steps (SvStepper), slideshow
35
+ // (SvCarousel). Pagination + stepper are pure/rune-free; carousel owns autoplay.
36
+ export { createPagination } from './createPagination';
37
+ export { createStepper } from './createStepper';
38
+ export { createCarousel } from './createCarousel.svelte';
39
+ // Command palette core (SvCommand): fuzzy filter + roving + hotkey. Pair with
40
+ // createOverlay for the focus-trap/scroll-lock/dismissal lifecycle.
41
+ export { createCommand } from './createCommand.svelte';
42
+ // Schema-driven form core (SvForm): values/errors/touched + validation + submit.
43
+ export { createForm } from './createForm.svelte';
23
44
  // UI kit - custom cell-editor registry (register any component as a grid editor)
24
45
  export { registerCellEditor, getCellEditor, hasCellEditor, unregisterCellEditor, registeredCellEditorTypes, defaultEditorProps, resolveEditorProps, } from './editor-registry';
25
46
  export { registerBuiltinEditors } from './builtin-editors';
@@ -30,6 +51,14 @@ export { createListbox, toSelectedArray, } from './createListbox.svelte';
30
51
  // Selection family cores
31
52
  export { createCombobox } from './createCombobox.svelte';
32
53
  export { createDropdownList } from './createDropdownList.svelte';
54
+ // Shared engine behind the anchored-panel selects (SvMultiSelect / SvTreeSelect /
55
+ // SvGridSelect): open/close, positioning, dismissal, roving active index, ARIA.
56
+ export { createPopoverSelect } from './createPopoverSelect.svelte';
57
+ // Menu family core (SvMenu / SvMenuList / SvContextMenu): roving focus, submenus,
58
+ // keyboard. `MenuItem` also re-exported from SvMenuList for back-compat.
59
+ export { createMenu } from './createMenu.svelte';
60
+ // Pure roving-focus navigation math shared by the cores above.
61
+ export { enabledIndices, wrapMove } from './list-nav';
33
62
  export { createAutocomplete } from './createAutocomplete.svelte';
34
63
  export { createTagsInput } from './createTagsInput.svelte';
35
64
  export { createCountryInput } from './createCountryInput.svelte';
@@ -102,6 +131,10 @@ export { default as SvAccordion } from './SvAccordion.svelte';
102
131
  export { createAccordion } from './createAccordion.svelte';
103
132
  export { default as SvSplitter } from './SvSplitter.svelte';
104
133
  export { createSplitter } from './createSplitter.svelte';
134
+ export { default as SvDockLayout } from './SvDockLayout.svelte';
135
+ export { default as SvDockManager } from './SvDockManager.svelte';
136
+ export { dockPane, dockTabs, dockGroup, removePane, movePane, dockInto, reorderPane, removeLeaf, dockLeafToEdge, setActive as dockSetActive, setSizes as dockSetSizes, normalize as dockNormalize, findTabsWithPane, allPaneIds, } from './dock-model';
137
+ export { floatPane, dockPaneOnto, dockWindowOnto, dockPaneToEmptyMain, reorderTab, autoHideLeaf, autoHidePaneToSide, pinAutoHidden, setAutoHideSize, closePane as dockManagerClosePane, moveWindow, resizeWindow, bringToFront, setWindowMinimized, toggleWindowMaximized, closeWindow, autoHideWindow, toggleMaximizeLeaf, findLeafById, addPaneToMain, resizeGroup as dockManagerResizeGroup, setManagerActive, locatePane, surfaceOfTabs, allManagerPaneIds, allManagerIds, dedupeManagerNodeIds, } from './dock-manager-model';
105
138
  export { default as SvFileUpload } from './SvFileUpload.svelte';
106
139
  export { createFileUpload, fileMatchesAccept } from './createFileUpload.svelte';
107
140
  // UI kit - overlays (popover / tooltip / modal), sharing the popover.ts positioning + animation
@@ -136,6 +169,7 @@ export { avatarInitials, avatarColorHue } from './avatar';
136
169
  export { default as SvContextMenu } from './SvContextMenu.svelte';
137
170
  export { toast, dismissToast, clearToasts, pauseToast, resumeToast, toastStore, } from './toast-store.svelte';
138
171
  export { default as SvMenu } from './SvMenu.svelte';
172
+ export { default as SvMenuList } from './SvMenuList.svelte';
139
173
  export { default as SvNavPane } from './SvNavPane.svelte';
140
174
  export { default as SvProgress } from './SvProgress.svelte';
141
175
  export { default as SvCircularProgress } from './SvCircularProgress.svelte';
@@ -143,8 +177,10 @@ export { popIn } from './popover';
143
177
  export { default as SvForm } from './SvForm.svelte';
144
178
  export { rules, runRules, isEmptyValue } from './validators';
145
179
  export { anchoredRect, portalToBody, PANEL_THEME_VARS } from './popover';
146
- export { toDate, startOfDay, addDays, addMonths, addYears, clampDate, isSameDay, monthMatrix, isoWeek, decadeRange, withTime, snapMinute, } from './datetime/date-core';
180
+ export { toDate, startOfDay, startOfWeek, startOfMonth, addDays, addMonths, addYears, clampDate, isSameDay, monthMatrix, weekdayOrder, isoWeek, decadeRange, withTime, snapMinute, } from './datetime/date-core';
147
181
  export { formatDate, parseDate, tokenizeMask } from './datetime/date-format';
182
+ export { toICS, fromICS, ruleToRRule, rruleToRule } from './scheduler-ical';
183
+ export { zoneParts, zoneOffsetMs, toZonedLocal, fromZonedLocal, instantFromWallClock, zoneAbbr, normalizeTimeZone, } from './datetime/timezone';
148
184
  export { selectDate, rangeDays, isSelected, isMultiSelectMode, emptySelection, } from './datetime/date-selection';
149
185
  export { isDisabledDay, isOutOfRange, isRestricted, isImportant, } from './datetime/date-restrict';
150
186
  export { default as FlexRender } from './FlexRender.svelte';
@@ -166,13 +202,13 @@ export { createServerGroupModel, serverGroupRows, serverGroupNav, } from './serv
166
202
  export { default as SvGroupCell } from './SvGroupCell.svelte';
167
203
  export { default as SvRowGroupPanel } from './SvRowGroupPanel.svelte';
168
204
  export { createNamedViews, memoryViews, localStorageViews, attachAutoSavedView, } from './named-views';
169
- export { resolveCellFormat, computeColumnStat, lerpColor, contrastText, } from './conditional-formatting';
205
+ export { resolveCellFormat, computeColumnStat, lerpColor, rgba, contrastText, formatNeedsStats, formatsNeedingStats, } from './conditional-formatting';
170
206
  export { getKeyboardIntent, getNextActiveCell } from './keyboard';
171
207
  export { createVirtualizer } from './virtualization/virtualizer';
172
208
  export { createSvelteVirtualizer } from './virtualization/svelte-virtualizer.svelte';
173
209
  export { createColumnVirtualizer } from './virtualization/column-virtualizer';
174
210
  export { parseEditorValue, normalizeEditorOptions, } from './editors/cell-editors';
175
- export { applyExcelFilter, normalizeForFilter, } from './filtering/excel-filters';
211
+ export { applyExcelFilter, normalizeForFilter, splitInTokens, joinInTokens, } from './filtering/excel-filters';
176
212
  export { getGridCellDomId, getGridCellA11yProps, getGridHeaderA11yProps, getGridRootA11yProps, getGridRowA11yProps, } from './a11y';
177
213
  /**
178
214
  * Compatibility alias for teams migrating from `createTable`.
@@ -0,0 +1,18 @@
1
+ /**
2
+ * list-nav - the pure, framework-free navigation math shared by the roving-focus
3
+ * cores (createListbox, createPopoverSelect, createMenu). No runes, no DOM - just
4
+ * index arithmetic, so it is unit-testable on its own and behaves identically
5
+ * everywhere. The cores wrap these in `$state`.
6
+ */
7
+ /** Indices of items that can take roving focus / selection - i.e. the ones the
8
+ * caller does not mark disabled. `count` is the total item count; `isDisabled`
9
+ * is consulted per index (a separator counts as disabled to the caller). */
10
+ export declare function enabledIndices(count: number, isDisabled?: (index: number) => boolean): number[];
11
+ /**
12
+ * The next index when moving `delta` steps through `list`, wrapping around the
13
+ * ends. `current` need not be in `list` (it may sit on a disabled item): when it
14
+ * is absent we start just before the head so `delta: 1` lands on the first entry
15
+ * and `delta: -1` on the last-but-one - the same behaviour every existing core
16
+ * already had. Returns `-1` for an empty list.
17
+ */
18
+ export declare function wrapMove(list: readonly number[], current: number, delta: number): number;
@@ -0,0 +1,30 @@
1
+ /**
2
+ * list-nav - the pure, framework-free navigation math shared by the roving-focus
3
+ * cores (createListbox, createPopoverSelect, createMenu). No runes, no DOM - just
4
+ * index arithmetic, so it is unit-testable on its own and behaves identically
5
+ * everywhere. The cores wrap these in `$state`.
6
+ */
7
+ /** Indices of items that can take roving focus / selection - i.e. the ones the
8
+ * caller does not mark disabled. `count` is the total item count; `isDisabled`
9
+ * is consulted per index (a separator counts as disabled to the caller). */
10
+ export function enabledIndices(count, isDisabled) {
11
+ const out = [];
12
+ for (let i = 0; i < count; i++)
13
+ if (!isDisabled?.(i))
14
+ out.push(i);
15
+ return out;
16
+ }
17
+ /**
18
+ * The next index when moving `delta` steps through `list`, wrapping around the
19
+ * ends. `current` need not be in `list` (it may sit on a disabled item): when it
20
+ * is absent we start just before the head so `delta: 1` lands on the first entry
21
+ * and `delta: -1` on the last-but-one - the same behaviour every existing core
22
+ * already had. Returns `-1` for an empty list.
23
+ */
24
+ export function wrapMove(list, current, delta) {
25
+ const len = list.length;
26
+ if (len === 0)
27
+ return -1;
28
+ const pos = list.indexOf(current);
29
+ return list[(pos + delta + len) % len];
30
+ }
@@ -5,6 +5,8 @@ export type ListOption = {
5
5
  disabled?: boolean;
6
6
  /** Optional group heading this option belongs under. */
7
7
  group?: string;
8
+ /** Optional color swatch (any CSS color) shown before the label. */
9
+ color?: string;
8
10
  };
9
11
  /** Case-insensitive substring filter over option labels. */
10
12
  export declare function filterOptions(options: ReadonlyArray<ListOption>, query: string): ListOption[];
@@ -0,0 +1,20 @@
1
+ import type { Snippet } from 'svelte';
2
+ /**
3
+ * A single item in a menu (SvMenu / SvMenuList / SvContextMenu) and the headless
4
+ * `createMenu` core. Kept in a plain `.ts` module so the core can import the type
5
+ * without pulling in the `.svelte` component - which would create a
6
+ * `.svelte.ts` -> `.svelte` -> `.svelte.ts` import cycle that Vite's dev-time
7
+ * import-analysis fails to resolve.
8
+ */
9
+ export type MenuItem = {
10
+ /** Item text. Omit + set `separator` for a divider. */
11
+ label?: string;
12
+ separator?: boolean;
13
+ icon?: Snippet;
14
+ /** Right-aligned hint, e.g. a keyboard shortcut. */
15
+ shortcut?: string;
16
+ disabled?: boolean;
17
+ /** Nested submenu items (renders a flyout). */
18
+ children?: MenuItem[];
19
+ onSelect?: () => void;
20
+ };
@@ -0,0 +1 @@
1
+ export {};
package/dist/menus.d.ts CHANGED
@@ -6,9 +6,14 @@ export declare function createMenus<TFeatures extends TableFeatures = TableFeatu
6
6
  updateFilterOperator: (columnId: string, operator: FilterOperator) => void;
7
7
  updateFilterMenuValue: (columnId: string, value: string) => void;
8
8
  updateFilterMenuValueTo: (columnId: string, valueTo: string) => void;
9
+ addFilterToken: (columnId: string, token: string) => void;
10
+ removeFilterToken: (columnId: string, token: string) => void;
11
+ toggleFilterToken: (columnId: string, token: string) => void;
9
12
  toggleCheckboxWithKeyboard: (event: KeyboardEvent, toggle: () => void) => void;
10
13
  isColumnFiltered: (columnId: string) => boolean;
11
14
  closeMenus: () => void;
15
+ openInSuggest: (anchor: HTMLElement, columnId: string) => void;
16
+ closeInSuggest: () => void;
12
17
  openChooseColumns: (event: MouseEvent) => void;
13
18
  openColumnMenu: (event: MouseEvent, columnId: string) => void;
14
19
  openFilterMenu: (event: MouseEvent, columnId: string) => void;
package/dist/menus.js CHANGED
@@ -1,5 +1,7 @@
1
1
  import "./sv-grid-scrollbar";
2
+ import { untrack } from "svelte";
2
3
  import { clampMenuX, cssEscape, } from "./SvGrid.helpers";
4
+ import { splitInTokens, joinInTokens } from "./filtering/excel-filters";
3
5
  export function createMenus(ctx) {
4
6
  function updateFilterRow(columnId, value) {
5
7
  ctx.filterRowValues = { ...ctx.filterRowValues, [columnId]: value };
@@ -46,6 +48,31 @@ export function createMenus(ctx) {
46
48
  [columnId]: { ...current, valueTo },
47
49
  };
48
50
  }
51
+ /** Current `in` / `notIn` token list for a column (from the filter-row value). */
52
+ function filterTokens(columnId) {
53
+ return splitInTokens(ctx.filterRowValues[columnId] ?? "");
54
+ }
55
+ /** Add a value to a column's `in` / `notIn` list (no-op if already present). */
56
+ function addFilterToken(columnId, token) {
57
+ const t = token.trim();
58
+ if (!t)
59
+ return;
60
+ const tokens = filterTokens(columnId);
61
+ if (!tokens.includes(t))
62
+ tokens.push(t);
63
+ updateFilterRow(columnId, joinInTokens(tokens));
64
+ }
65
+ /** Remove a value from a column's `in` / `notIn` list. */
66
+ function removeFilterToken(columnId, token) {
67
+ updateFilterRow(columnId, joinInTokens(filterTokens(columnId).filter((t) => t !== token)));
68
+ }
69
+ /** Toggle a value in a column's `in` / `notIn` list (checklist behaviour). */
70
+ function toggleFilterToken(columnId, token) {
71
+ if (filterTokens(columnId).includes(token))
72
+ removeFilterToken(columnId, token);
73
+ else
74
+ addFilterToken(columnId, token);
75
+ }
49
76
  function toggleCheckboxWithKeyboard(event, toggle) {
50
77
  if (event.key !== "Enter" && event.key !== " ")
51
78
  return;
@@ -57,14 +84,28 @@ export function createMenus(ctx) {
57
84
  return true;
58
85
  const menuFilter = ctx.filterMenuValues[columnId];
59
86
  return Boolean(menuFilter &&
60
- (menuFilter.operator === "isBlank" || menuFilter.value.trim()));
87
+ (menuFilter.operator === "isBlank" ||
88
+ menuFilter.operator === "isNotBlank" ||
89
+ menuFilter.value.trim()));
61
90
  }
62
91
  function closeMenus() {
63
92
  ctx.columnMenuFor = null;
64
93
  ctx.filterMenuFor = null;
65
94
  ctx.operatorMenuFor = null;
95
+ ctx.inSuggestFor = null;
66
96
  ctx.chooseColumnsPos = null;
67
97
  }
98
+ /** Open the `in` / `notIn` value-suggestions dropdown under a chip input. */
99
+ function openInSuggest(anchor, columnId) {
100
+ const rect = anchor.getBoundingClientRect();
101
+ ctx.inSuggestPos = { x: clampMenuX(rect.left, 220), y: rect.bottom + 4 };
102
+ ctx.inSuggestQuery = "";
103
+ ctx.inSuggestFor = columnId;
104
+ }
105
+ function closeInSuggest() {
106
+ ctx.inSuggestFor = null;
107
+ ctx.inSuggestQuery = "";
108
+ }
68
109
  function openChooseColumns(event) {
69
110
  event.stopPropagation();
70
111
  // Submenu behavior: keep the parent operations menu open and float the
@@ -200,21 +241,27 @@ export function createMenus(ctx) {
200
241
  }
201
242
  }
202
243
  function clearColumnFilter(columnId) {
203
- if (ctx.valueFilters[columnId]) {
204
- const next = { ...ctx.valueFilters };
205
- delete next[columnId];
206
- ctx.valueFilters = next;
207
- }
208
- if (ctx.filterMenuValues[columnId]) {
209
- const next = { ...ctx.filterMenuValues };
210
- delete next[columnId];
211
- ctx.filterMenuValues = next;
212
- }
213
- if (ctx.filterRowValues[columnId]) {
214
- const next = { ...ctx.filterRowValues };
215
- delete next[columnId];
216
- ctx.filterRowValues = next;
217
- }
244
+ // `untrack`: read-modify-write on the filter maps. Keeps the method safe to
245
+ // call from a consumer's reactive `$effect` (e.g. via `api.clearFilter`)
246
+ // without capturing these reads as a dependency and looping. See
247
+ // `build-api`'s `setFilter` for the full rationale.
248
+ untrack(() => {
249
+ if (ctx.valueFilters[columnId]) {
250
+ const next = { ...ctx.valueFilters };
251
+ delete next[columnId];
252
+ ctx.valueFilters = next;
253
+ }
254
+ if (ctx.filterMenuValues[columnId]) {
255
+ const next = { ...ctx.filterMenuValues };
256
+ delete next[columnId];
257
+ ctx.filterMenuValues = next;
258
+ }
259
+ if (ctx.filterRowValues[columnId]) {
260
+ const next = { ...ctx.filterRowValues };
261
+ delete next[columnId];
262
+ ctx.filterRowValues = next;
263
+ }
264
+ });
218
265
  }
219
266
  // External pagination is controlled: emit the requested page/size and let
220
267
  // the consumer fetch + update props. Never mutate local pagination state.
@@ -385,9 +432,14 @@ export function createMenus(ctx) {
385
432
  updateFilterOperator,
386
433
  updateFilterMenuValue,
387
434
  updateFilterMenuValueTo,
435
+ addFilterToken,
436
+ removeFilterToken,
437
+ toggleFilterToken,
388
438
  toggleCheckboxWithKeyboard,
389
439
  isColumnFiltered,
390
440
  closeMenus,
441
+ openInSuggest,
442
+ closeInSuggest,
391
443
  openChooseColumns,
392
444
  openColumnMenu,
393
445
  openFilterMenu,
@@ -0,0 +1,25 @@
1
+ /**
2
+ * panel-resize - the drag math behind a dropdown panel's bottom resize grip
3
+ * (the "····" handle). Rune-free and DOM-only so every popover select can reuse
4
+ * it: on the grip's `pointerdown` it tracks the pointer and reports a clamped
5
+ * height as it moves, releasing its listeners on `pointerup`.
6
+ *
7
+ * The grip is only meaningful when the panel opens DOWNWARD (it grows toward the
8
+ * bottom of the screen); components hide it on an upward flip, where there is no
9
+ * room below to grow into.
10
+ */
11
+ export type PanelResizeOptions = {
12
+ /** Panel height (px) at the moment the drag starts. */
13
+ startHeight: number;
14
+ /** Smallest height the panel may shrink to. Default 80. */
15
+ min?: number;
16
+ /** Largest height the panel may grow to - the live viewport ceiling. */
17
+ max: () => number;
18
+ /** Called with the new clamped height on each pointer move. */
19
+ onHeight: (height: number) => void;
20
+ };
21
+ /**
22
+ * Begin a vertical resize from a grip `pointerdown`. Returns nothing; the drag
23
+ * ends itself on `pointerup`. Safe to call from an `onpointerdown` handler.
24
+ */
25
+ export declare function startPanelResize(event: PointerEvent, opts: PanelResizeOptions): void;