@svgrid/grid 2.2.16 → 2.2.17

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,111 @@
1
+ /**
2
+ * positioning - a small, dependency-free anchor-positioning engine for the
3
+ * overlay layer (popover, tooltip, menu, dropdowns). It replaces the vertical-
4
+ * flip-only `anchoredRect` for components that need the full placement matrix.
5
+ *
6
+ * Two halves:
7
+ *
8
+ * 1. `computePosition(reference, floating, options)` - PURE geometry. Given the
9
+ * reference rect and the floating size (plus a viewport), it returns the
10
+ * floating `x`/`y`, the resolved `placement` (after flip), the arrow offset,
11
+ * and the available `maxWidth`/`maxHeight` on the chosen side. No DOM, so it
12
+ * is fully unit-tested by feeding rects and asserting placement.
13
+ *
14
+ * 2. `autoUpdate(referenceEl, floatingEl, update)` - the browser half. Re-runs
15
+ * `update` whenever the reference/floating resize, an ancestor scrolls, or the
16
+ * window resizes (via `ResizeObserver` + scroll/resize listeners). SSR-safe
17
+ * (a no-op without `window`).
18
+ *
19
+ * The middleware (flip / shift / size / arrow) is implemented inline - no
20
+ * Floating-UI dependency - matching the kit's zero-runtime-dep posture.
21
+ */
22
+ /** A physical side the floating element is placed on, relative to the reference. */
23
+ export type Side = 'top' | 'bottom' | 'left' | 'right';
24
+ /** Cross-axis alignment. `center` is the bare side (e.g. `'bottom'`). */
25
+ export type Align = 'start' | 'center' | 'end';
26
+ /** `'bottom'` = bottom-center; `'bottom-start'` / `'bottom-end'` align the edges. */
27
+ export type Placement = Side | `${Side}-start` | `${Side}-end`;
28
+ /** A viewport-relative rectangle (CSS `getBoundingClientRect` shape suffices). */
29
+ export type Rect = {
30
+ x: number;
31
+ y: number;
32
+ width: number;
33
+ height: number;
34
+ };
35
+ /** The available viewport (defaults to `window` in the browser). */
36
+ export type Viewport = {
37
+ width: number;
38
+ height: number;
39
+ };
40
+ export type ComputePositionOptions = {
41
+ /** Preferred placement. Default `'bottom-start'`. */
42
+ placement?: Placement;
43
+ /** Main-axis gap between reference and floating. Default 6. */
44
+ offset?: number;
45
+ /** Viewport edge kept clear on every side. Default 8. */
46
+ padding?: number;
47
+ /** Flip to the opposite side when the preferred side overflows. Default true. */
48
+ flip?: boolean;
49
+ /** Shift along the cross axis to stay in view (without flipping). Default true. */
50
+ shift?: boolean;
51
+ /** Compute `maxWidth`/`maxHeight` for the chosen side. Default true. */
52
+ size?: boolean;
53
+ /** When set, compute the arrow offset for an arrow element of this size (px). */
54
+ arrow?: {
55
+ size: number;
56
+ };
57
+ /** Extra placements to try (after the automatic opposite) before giving up. */
58
+ fallbackPlacements?: Placement[];
59
+ /** Viewport to fit within. Defaults to the window; pure callers pass it. */
60
+ viewport?: Viewport;
61
+ /** Floor for the available main-axis size returned by `size`. Default 0. */
62
+ minMainAxis?: number;
63
+ };
64
+ export type ComputePositionResult = {
65
+ /** Floating left, in viewport (fixed-position) coordinates. */
66
+ x: number;
67
+ /** Floating top, in viewport (fixed-position) coordinates. */
68
+ y: number;
69
+ /** The resolved placement after flip. */
70
+ placement: Placement;
71
+ /** The resolved side after flip. */
72
+ side: Side;
73
+ /** The resolved cross-axis alignment. */
74
+ align: Align;
75
+ /** Space available for the floating on the chosen side's main axis (+cross). */
76
+ maxWidth: number;
77
+ maxHeight: number;
78
+ /**
79
+ * Arrow offset within the floating box: `x` for top/bottom placements, `y` for
80
+ * left/right. Only present when `options.arrow` is set. Clamped so the arrow
81
+ * stays inside the floating (minus padding).
82
+ */
83
+ arrow?: {
84
+ x?: number;
85
+ y?: number;
86
+ };
87
+ };
88
+ /** Split a placement into its side + alignment (`center` when no suffix). */
89
+ export declare function parsePlacement(p: Placement): {
90
+ side: Side;
91
+ align: Align;
92
+ };
93
+ /**
94
+ * Compute the floating position anchored to `reference`, applying flip (opposite
95
+ * side when the preferred side overflows), shift (cross-axis clamp to stay in
96
+ * view), size (available max width/height on the chosen side) and an optional
97
+ * arrow offset. Pure - pass an explicit `viewport` in tests.
98
+ */
99
+ export declare function computePosition(reference: Rect, floating: Viewport, options?: ComputePositionOptions): ComputePositionResult;
100
+ /**
101
+ * Re-run `update` whenever the anchored position could change: the reference or
102
+ * floating element resizes, an ancestor scrolls, or the window scrolls/resizes.
103
+ * Returns a cleanup function. SSR-safe (a no-op without `window`).
104
+ *
105
+ * ```ts
106
+ * const stop = autoUpdate(triggerEl, panelEl, () => reposition())
107
+ * // ...later
108
+ * stop()
109
+ * ```
110
+ */
111
+ export declare function autoUpdate(reference: Element, floating: HTMLElement, update: () => void): () => void;
@@ -0,0 +1,191 @@
1
+ /**
2
+ * positioning - a small, dependency-free anchor-positioning engine for the
3
+ * overlay layer (popover, tooltip, menu, dropdowns). It replaces the vertical-
4
+ * flip-only `anchoredRect` for components that need the full placement matrix.
5
+ *
6
+ * Two halves:
7
+ *
8
+ * 1. `computePosition(reference, floating, options)` - PURE geometry. Given the
9
+ * reference rect and the floating size (plus a viewport), it returns the
10
+ * floating `x`/`y`, the resolved `placement` (after flip), the arrow offset,
11
+ * and the available `maxWidth`/`maxHeight` on the chosen side. No DOM, so it
12
+ * is fully unit-tested by feeding rects and asserting placement.
13
+ *
14
+ * 2. `autoUpdate(referenceEl, floatingEl, update)` - the browser half. Re-runs
15
+ * `update` whenever the reference/floating resize, an ancestor scrolls, or the
16
+ * window resizes (via `ResizeObserver` + scroll/resize listeners). SSR-safe
17
+ * (a no-op without `window`).
18
+ *
19
+ * The middleware (flip / shift / size / arrow) is implemented inline - no
20
+ * Floating-UI dependency - matching the kit's zero-runtime-dep posture.
21
+ */
22
+ const SIDES = { top: 'bottom', bottom: 'top', left: 'right', right: 'left' };
23
+ /** Split a placement into its side + alignment (`center` when no suffix). */
24
+ export function parsePlacement(p) {
25
+ const [side, align] = p.split('-');
26
+ return { side, align: align ?? 'center' };
27
+ }
28
+ function opposite(p) {
29
+ const { side, align } = parsePlacement(p);
30
+ return (align === 'center' ? SIDES[side] : `${SIDES[side]}-${align}`);
31
+ }
32
+ function clamp(v, min, max) {
33
+ if (max < min)
34
+ return min;
35
+ return v < min ? min : v > max ? max : v;
36
+ }
37
+ /** Floating x/y for a given side+align (before flip/shift). */
38
+ function coordsFor(side, align, r, f, offset) {
39
+ if (side === 'top' || side === 'bottom') {
40
+ const y = side === 'top' ? r.y - f.height - offset : r.y + r.height + offset;
41
+ const x = align === 'start' ? r.x : align === 'end' ? r.x + r.width - f.width : r.x + r.width / 2 - f.width / 2;
42
+ return { x, y };
43
+ }
44
+ const x = side === 'left' ? r.x - f.width - offset : r.x + r.width + offset;
45
+ const y = align === 'start' ? r.y : align === 'end' ? r.y + r.height - f.height : r.y + r.height / 2 - f.height / 2;
46
+ return { x, y };
47
+ }
48
+ /** How far the floating exceeds the viewport on the placement's MAIN axis. >0 = overflow. */
49
+ function mainAxisOverflow(side, x, y, f, v, pad) {
50
+ switch (side) {
51
+ case 'top':
52
+ return pad - y;
53
+ case 'bottom':
54
+ return y + f.height - (v.height - pad);
55
+ case 'left':
56
+ return pad - x;
57
+ default:
58
+ return x + f.width - (v.width - pad);
59
+ }
60
+ }
61
+ function resolveViewport(v) {
62
+ if (v)
63
+ return v;
64
+ if (typeof window !== 'undefined')
65
+ return { width: window.innerWidth, height: window.innerHeight };
66
+ return { width: 0, height: 0 };
67
+ }
68
+ /**
69
+ * Compute the floating position anchored to `reference`, applying flip (opposite
70
+ * side when the preferred side overflows), shift (cross-axis clamp to stay in
71
+ * view), size (available max width/height on the chosen side) and an optional
72
+ * arrow offset. Pure - pass an explicit `viewport` in tests.
73
+ */
74
+ export function computePosition(reference, floating, options = {}) {
75
+ const offset = options.offset ?? 6;
76
+ const pad = options.padding ?? 8;
77
+ const doFlip = options.flip !== false;
78
+ const doShift = options.shift !== false;
79
+ const v = resolveViewport(options.viewport);
80
+ const preferred = options.placement ?? 'bottom-start';
81
+ // ---- flip: pick the placement whose main-axis overflow is smallest ----
82
+ const candidates = [preferred];
83
+ if (doFlip) {
84
+ candidates.push(opposite(preferred));
85
+ for (const fb of options.fallbackPlacements ?? [])
86
+ candidates.push(fb);
87
+ }
88
+ let chosen = preferred;
89
+ let best = Infinity;
90
+ for (const cand of candidates) {
91
+ const { side, align } = parsePlacement(cand);
92
+ const { x, y } = coordsFor(side, align, reference, floating, offset);
93
+ const overflow = mainAxisOverflow(side, x, y, floating, v, pad);
94
+ if (overflow <= 0) {
95
+ chosen = cand;
96
+ best = overflow;
97
+ break;
98
+ }
99
+ if (overflow < best) {
100
+ best = overflow;
101
+ chosen = cand;
102
+ }
103
+ }
104
+ const { side, align } = parsePlacement(chosen);
105
+ let { x, y } = coordsFor(side, align, reference, floating, offset);
106
+ // ---- shift: clamp along the CROSS axis so the floating stays in view ----
107
+ if (doShift) {
108
+ if (side === 'top' || side === 'bottom') {
109
+ x = clamp(x, pad, v.width - pad - floating.width);
110
+ }
111
+ else {
112
+ y = clamp(y, pad, v.height - pad - floating.height);
113
+ }
114
+ }
115
+ // ---- size: available room on the chosen side ----
116
+ const minMain = options.minMainAxis ?? 0;
117
+ let maxWidth;
118
+ let maxHeight;
119
+ if (side === 'top' || side === 'bottom') {
120
+ const avail = side === 'top' ? reference.y - offset - pad : v.height - pad - (reference.y + reference.height + offset);
121
+ maxHeight = Math.max(minMain, Math.floor(avail));
122
+ maxWidth = Math.max(0, v.width - 2 * pad);
123
+ }
124
+ else {
125
+ const avail = side === 'left' ? reference.x - offset - pad : v.width - pad - (reference.x + reference.width + offset);
126
+ maxWidth = Math.max(minMain, Math.floor(avail));
127
+ maxHeight = Math.max(0, v.height - 2 * pad);
128
+ }
129
+ const result = { x, y, placement: chosen, side, align, maxWidth, maxHeight };
130
+ // ---- arrow: point at the reference center, clamped inside the floating ----
131
+ if (options.arrow) {
132
+ const a = options.arrow.size;
133
+ if (side === 'top' || side === 'bottom') {
134
+ const center = reference.x + reference.width / 2;
135
+ const ax = clamp(center - x - a / 2, pad, floating.width - a - pad);
136
+ result.arrow = { x: ax };
137
+ }
138
+ else {
139
+ const center = reference.y + reference.height / 2;
140
+ const ay = clamp(center - y - a / 2, pad, floating.height - a - pad);
141
+ result.arrow = { y: ay };
142
+ }
143
+ }
144
+ return result;
145
+ }
146
+ /** Collect scrollable ancestors so `autoUpdate` can listen to their scroll. */
147
+ function scrollParents(node) {
148
+ const out = [];
149
+ let el = node.parentElement;
150
+ while (el) {
151
+ const style = getComputedStyle(el);
152
+ if (/(auto|scroll|overlay|hidden)/.test(style.overflow + style.overflowY + style.overflowX))
153
+ out.push(el);
154
+ el = el.parentElement;
155
+ }
156
+ return out;
157
+ }
158
+ /**
159
+ * Re-run `update` whenever the anchored position could change: the reference or
160
+ * floating element resizes, an ancestor scrolls, or the window scrolls/resizes.
161
+ * Returns a cleanup function. SSR-safe (a no-op without `window`).
162
+ *
163
+ * ```ts
164
+ * const stop = autoUpdate(triggerEl, panelEl, () => reposition())
165
+ * // ...later
166
+ * stop()
167
+ * ```
168
+ */
169
+ export function autoUpdate(reference, floating, update) {
170
+ if (typeof window === 'undefined')
171
+ return () => { };
172
+ const ancestors = scrollParents(reference);
173
+ for (const a of ancestors)
174
+ a.addEventListener('scroll', update, { passive: true });
175
+ window.addEventListener('scroll', update, { passive: true });
176
+ window.addEventListener('resize', update);
177
+ let ro;
178
+ if (typeof ResizeObserver === 'function') {
179
+ ro = new ResizeObserver(update);
180
+ ro.observe(reference);
181
+ ro.observe(floating);
182
+ }
183
+ update();
184
+ return () => {
185
+ for (const a of ancestors)
186
+ a.removeEventListener('scroll', update);
187
+ window.removeEventListener('scroll', update);
188
+ window.removeEventListener('resize', update);
189
+ ro?.disconnect();
190
+ };
191
+ }
@@ -52,6 +52,9 @@ export type RecurrenceException = {
52
52
  end?: DateLike | null;
53
53
  title?: string;
54
54
  allDay?: boolean;
55
+ /** Per-occurrence overrides for any other field, merged over the row for just
56
+ * this occurrence (attendees, calendar, color, resource, ...). */
57
+ fields?: Record<string, unknown>;
55
58
  };
56
59
  /** Field accessors the model uses to read an event off a row. The component
57
60
  * builds this from `SchedulerConfig`, applying its move/edit overlay first so
@@ -140,6 +140,14 @@ export function resolveEvents(rows, spec, rangeStart, rangeEnd) {
140
140
  let iEnd = new Date(occStart.getTime() + durationMs);
141
141
  let iTitle = title;
142
142
  let iAllDay = allDay;
143
+ // Per-occurrence overrides of ANY other field: merge onto a copy of the
144
+ // row for this instance, then re-derive the surfaced props from it so a
145
+ // "This event" change to attendees / calendar / color / resource shows.
146
+ let iRow = row;
147
+ let iColor = color;
148
+ let iColor2 = color2;
149
+ let iStatus = status;
150
+ let iResource = resourceId;
143
151
  if (ex) {
144
152
  const exS = toDate(ex.start);
145
153
  const exE = toDate(ex.end);
@@ -154,6 +162,15 @@ export function resolveEvents(rows, spec, rangeStart, rangeEnd) {
154
162
  iTitle = ex.title;
155
163
  if (ex.allDay != null)
156
164
  iAllDay = ex.allDay;
165
+ if (ex.fields) {
166
+ iRow = { ...row, ...ex.fields };
167
+ iColor = spec.getColor?.(iRow) ?? color;
168
+ iColor2 = spec.getSecondaryColor?.(iRow) ?? color2;
169
+ iStatus = spec.getStatus?.(iRow) ?? status;
170
+ iResource = spec.getResource?.(iRow) ?? resourceId;
171
+ if (ex.title == null)
172
+ iTitle = spec.getTitle?.(iRow) ?? iTitle;
173
+ }
157
174
  }
158
175
  if (!rangesOverlap(iStart, iEnd, rangeStart, rangeEnd))
159
176
  continue;
@@ -161,15 +178,15 @@ export function resolveEvents(rows, spec, rangeStart, rangeEnd) {
161
178
  // Key on the CANONICAL occurrence start so a moved occurrence keeps its identity.
162
179
  key: `${rowKey}#${occStart.getFullYear()}-${occStart.getMonth() + 1}-${occStart.getDate()}T${occStart.getHours()}:${occStart.getMinutes()}`,
163
180
  rowKey,
164
- row,
181
+ row: iRow,
165
182
  title: iTitle,
166
183
  start: iStart,
167
184
  end: iEnd,
168
185
  allDay: iAllDay,
169
- color,
170
- color2,
171
- status,
172
- resourceId,
186
+ color: iColor,
187
+ color2: iColor2,
188
+ status: iStatus,
189
+ resourceId: iResource,
173
190
  recurring: true,
174
191
  occurrenceStart: occStart,
175
192
  isException: !!ex,
@@ -1,4 +1,5 @@
1
1
  import type { CellFormatConfig, ColumnDef, RowData, SvGridOptions, TableFeatures } from './core';
2
+ import type { Props } from './SvGrid.types';
2
3
  import type { GridExportOptions, GridClipboardOptions } from './export-format';
3
4
  import type { ChartSpec, ChartType } from './chart';
4
5
  export type SvGridFilterOperator = 'contains' | 'equals' | 'startsWith' | 'greaterThan' | 'lessThan' | 'between' | 'isBlank';
@@ -168,6 +169,23 @@ export type SvGridApi<TFeatures extends TableFeatures, TData extends RowData> =
168
169
  setSort(columnId: string, direction: 'asc' | 'desc' | null): void;
169
170
  clearSort(): void;
170
171
  setGroupBy(columnIds: ReadonlyArray<string>): void;
172
+ /**
173
+ * Change a grid prop at runtime, e.g. `api.setOption('sortable', true)`. The
174
+ * override is merged over the incoming prop and the grid re-renders reactively -
175
+ * identical to the parent passing a new prop value. Pass `undefined` to clear the
176
+ * override and fall back to the prop.
177
+ *
178
+ * Note: seed-once props are NOT retroactive - `initialSorting`,
179
+ * `initialColumnPinning`, `initialHiddenColumns`, `columnOrder`, the initial
180
+ * `pageSize`, and the one-shot `externalSort` / `externalFilter` are read at mount,
181
+ * so overriding them later has no effect. Prefer the dedicated data path for
182
+ * `data` / `columns` (this works, but the sync effects are the idiomatic route).
183
+ */
184
+ setOption<K extends keyof Props<TFeatures, TData>>(key: K, value: Props<TFeatures, TData>[K] | undefined): void;
185
+ /** Read a prop's effective value: the runtime override if set, else the incoming prop. */
186
+ getOption<K extends keyof Props<TFeatures, TData>>(key: K): Props<TFeatures, TData>[K];
187
+ /** Clear every runtime override set via `setOption`, reverting to the incoming props. */
188
+ resetOptions(): void;
171
189
  /** Set the operator filter for a column. Pass `null` to clear. */
172
190
  setFilter(columnId: string, filter: {
173
191
  operator: SvGridFilterOperator;
@@ -1,4 +1,28 @@
1
+ /**
2
+ * toast-store - the headless model behind <SvToaster>: a singleton reactive
3
+ * queue of transient notifications with auto-dismiss timers, plus the `toast()`
4
+ * API you call from anywhere. Every toast is also pushed to the shared ARIA
5
+ * live region via `announce()`, so screen-reader users hear it even though the
6
+ * visual toast is off to the side.
7
+ *
8
+ * ```ts
9
+ * import { toast } from '@svgrid/grid'
10
+ * toast.success('Saved')
11
+ * toast.error('Could not save', { duration: 0 }) // sticky
12
+ * ```
13
+ *
14
+ * Mount a single <SvToaster /> once near the app root to render the queue.
15
+ */
16
+ import type { Snippet } from 'svelte';
1
17
  export type ToastVariant = 'info' | 'success' | 'warning' | 'error';
18
+ /** A button rendered inside a toast (a primary `action` or a secondary `cancel`). */
19
+ export type ToastAction = {
20
+ label: string;
21
+ /** Invoked with the toast id when pressed. */
22
+ onClick?: (id: number) => void;
23
+ /** Keep the toast open after the click (default: dismiss it). */
24
+ keepOpen?: boolean;
25
+ };
2
26
  export type ToastOptions = {
3
27
  variant?: ToastVariant;
4
28
  /** Auto-dismiss after N ms. `0` = sticky (dismiss manually). Default 4000. */
@@ -7,6 +31,12 @@ export type ToastOptions = {
7
31
  dismissible?: boolean;
8
32
  /** Optional bold title above the message. */
9
33
  title?: string;
34
+ /** Primary action button. */
35
+ action?: ToastAction;
36
+ /** Secondary (cancel) action button. */
37
+ cancel?: ToastAction;
38
+ /** Render a fully custom toast body instead of the icon + title + message. */
39
+ render?: Snippet<[Toast]>;
10
40
  };
11
41
  export type Toast = {
12
42
  id: number;
@@ -15,6 +45,17 @@ export type Toast = {
15
45
  duration: number;
16
46
  dismissible: boolean;
17
47
  title?: string;
48
+ action?: ToastAction;
49
+ cancel?: ToastAction;
50
+ render?: Snippet<[Toast]>;
51
+ };
52
+ /** Patch applied by `toast.update(id, patch)`; every field is optional. */
53
+ export type UpdateToast = Partial<Omit<Toast, 'id'>>;
54
+ /** Messages for `toast.promise`; success/error may derive from the value/error. */
55
+ export type PromiseMessages<T> = {
56
+ loading: string;
57
+ success: string | ((value: T) => string);
58
+ error: string | ((error: unknown) => string);
18
59
  };
19
60
  type VariantOptions = Omit<ToastOptions, 'variant'>;
20
61
  export type ToastFn = {
@@ -23,6 +64,17 @@ export type ToastFn = {
23
64
  success: (message: string, options?: VariantOptions) => number;
24
65
  warning: (message: string, options?: VariantOptions) => number;
25
66
  error: (message: string, options?: VariantOptions) => number;
67
+ /**
68
+ * Show a sticky loading toast, then update it IN PLACE to success/error when
69
+ * the promise settles. Returns the original promise so callers can await it.
70
+ */
71
+ promise: <T>(promise: Promise<T>, messages: PromiseMessages<T>, options?: ToastOptions) => Promise<T>;
72
+ /** Patch an existing toast (message/variant/title/action/duration/render). */
73
+ update: (id: number, patch: UpdateToast) => void;
74
+ /** Push a toast with a fully custom body snippet. Returns its id. */
75
+ custom: (render: Snippet<[Toast]>, options?: ToastOptions) => number;
76
+ /** Dismiss a toast by id. */
77
+ dismiss: (id: number) => void;
26
78
  };
27
79
  /** Live reactive list of active toasts (read inside a component/effect). */
28
80
  export declare const toastStore: {
@@ -32,6 +84,8 @@ export declare const toastStore: {
32
84
  export declare const toast: ToastFn;
33
85
  /** Dismiss a toast by id. */
34
86
  export declare const dismissToast: (id: number) => void;
87
+ /** Patch an existing toast in place (message/variant/title/action/duration/render). */
88
+ export declare const updateToast: (id: number, patch: UpdateToast) => void;
35
89
  /** Remove every toast (and cancel their timers). */
36
90
  export declare const clearToasts: () => void;
37
91
  /** Pause a toast's auto-dismiss countdown (e.g. while hovered). */
@@ -1,18 +1,3 @@
1
- /**
2
- * toast-store - the headless model behind <SvToaster>: a singleton reactive
3
- * queue of transient notifications with auto-dismiss timers, plus the `toast()`
4
- * API you call from anywhere. Every toast is also pushed to the shared ARIA
5
- * live region via `announce()`, so screen-reader users hear it even though the
6
- * visual toast is off to the side.
7
- *
8
- * ```ts
9
- * import { toast } from '@svgrid/grid'
10
- * toast.success('Saved')
11
- * toast.error('Could not save', { duration: 0 }) // sticky
12
- * ```
13
- *
14
- * Mount a single <SvToaster /> once near the app root to render the queue.
15
- */
16
1
  import { announce } from './a11y/live-region';
17
2
  function createToastStore() {
18
3
  const toasts = $state([]);
@@ -72,6 +57,9 @@ function createToastStore() {
72
57
  duration,
73
58
  dismissible: options.dismissible ?? true,
74
59
  title: options.title,
60
+ action: options.action,
61
+ cancel: options.cancel,
62
+ render: options.render,
75
63
  };
76
64
  toasts.push(entry);
77
65
  // Errors/warnings interrupt (assertive); info/success are polite.
@@ -82,16 +70,76 @@ function createToastStore() {
82
70
  schedule(id, duration);
83
71
  return id;
84
72
  }
73
+ /** Patch an existing toast in place (used by `promise`, and callable directly). */
74
+ function update(id, patch) {
75
+ const t = toasts.find((x) => x.id === id);
76
+ if (!t)
77
+ return;
78
+ if (patch.message != null)
79
+ t.message = patch.message;
80
+ if (patch.title !== undefined)
81
+ t.title = patch.title;
82
+ if (patch.variant)
83
+ t.variant = patch.variant;
84
+ if (patch.dismissible !== undefined)
85
+ t.dismissible = patch.dismissible;
86
+ if (patch.action !== undefined)
87
+ t.action = patch.action;
88
+ if (patch.cancel !== undefined)
89
+ t.cancel = patch.cancel;
90
+ if (patch.render !== undefined)
91
+ t.render = patch.render;
92
+ // A new duration restarts the auto-dismiss timer (0 = make it sticky again).
93
+ if (patch.duration !== undefined) {
94
+ const timer = timers.get(id);
95
+ if (timer) {
96
+ clearTimeout(timer);
97
+ timers.delete(id);
98
+ }
99
+ meta.delete(id);
100
+ t.duration = patch.duration;
101
+ if (patch.duration > 0)
102
+ schedule(id, patch.duration);
103
+ }
104
+ announce(t.title ? `${t.title}: ${t.message}` : t.message, {
105
+ assertive: t.variant === 'error' || t.variant === 'warning',
106
+ });
107
+ }
108
+ function promise(p, messages, options = {}) {
109
+ const id = push(messages.loading, {
110
+ ...options,
111
+ variant: 'info',
112
+ duration: 0,
113
+ dismissible: options.dismissible ?? false,
114
+ });
115
+ p.then((value) => update(id, {
116
+ message: typeof messages.success === 'function' ? messages.success(value) : messages.success,
117
+ variant: 'success',
118
+ duration: options.duration ?? 4000,
119
+ dismissible: true,
120
+ }), (error) => update(id, {
121
+ message: typeof messages.error === 'function' ? messages.error(error) : messages.error,
122
+ variant: 'error',
123
+ duration: options.duration ?? 6000,
124
+ dismissible: true,
125
+ }));
126
+ return p;
127
+ }
85
128
  const toast = push;
86
129
  toast.info = (m, o = {}) => push(m, { ...o, variant: 'info' });
87
130
  toast.success = (m, o = {}) => push(m, { ...o, variant: 'success' });
88
131
  toast.warning = (m, o = {}) => push(m, { ...o, variant: 'warning' });
89
132
  toast.error = (m, o = {}) => push(m, { ...o, variant: 'error' });
133
+ toast.promise = promise;
134
+ toast.update = update;
135
+ toast.custom = (render, o = {}) => push('', { ...o, render });
136
+ toast.dismiss = dismiss;
90
137
  return {
91
138
  get toasts() {
92
139
  return toasts;
93
140
  },
94
141
  toast,
142
+ update,
95
143
  dismiss,
96
144
  clear,
97
145
  pause,
@@ -105,6 +153,8 @@ export const toastStore = { get toasts() { return store.toasts; } };
105
153
  export const toast = store.toast;
106
154
  /** Dismiss a toast by id. */
107
155
  export const dismissToast = (id) => store.dismiss(id);
156
+ /** Patch an existing toast in place (message/variant/title/action/duration/render). */
157
+ export const updateToast = (id, patch) => store.update(id, patch);
108
158
  /** Remove every toast (and cancel their timers). */
109
159
  export const clearToasts = () => store.clear();
110
160
  /** Pause a toast's auto-dismiss countdown (e.g. while hovered). */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@svgrid/grid",
3
- "version": "2.2.16",
3
+ "version": "2.2.17",
4
4
  "description": "SvGrid - a headless-first, Svelte 5-native data grid engine and render component.",
5
5
  "author": "jQWidgets <boikom@jqwidgets.com>",
6
6
  "license": "MIT",
@@ -22,6 +22,9 @@
22
22
  "datagrid"
23
23
  ],
24
24
  "type": "module",
25
+ "sideEffects": [
26
+ "**/*.css"
27
+ ],
25
28
  "types": "dist/index.d.ts",
26
29
  "module": "dist/index.js",
27
30
  "svelte": "./dist/index.js",
@@ -51,6 +54,11 @@
51
54
  "svelte": "./dist/export-format.js",
52
55
  "import": "./dist/export-format.js"
53
56
  },
57
+ "./filtering": {
58
+ "types": "./dist/filtering/excel-filters.d.ts",
59
+ "svelte": "./dist/filtering/excel-filters.js",
60
+ "import": "./dist/filtering/excel-filters.js"
61
+ },
54
62
  "./flex-render": {
55
63
  "types": "./dist/flex-render.d.ts",
56
64
  "svelte": "./dist/flex-render.js",