@svgrid/grid 2.2.27 → 2.2.29

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 (248) hide show
  1. package/README.md +199 -199
  2. package/dist/FlexRender.svelte +96 -96
  3. package/dist/GridFooter.svelte +179 -179
  4. package/dist/GridMenus.svelte +782 -734
  5. package/dist/SvAutoComplete.svelte +165 -165
  6. package/dist/SvCalendar.svelte +503 -503
  7. package/dist/SvCarousel.svelte +141 -141
  8. package/dist/SvCheckBox.svelte +101 -101
  9. package/dist/SvColorInput.svelte +181 -181
  10. package/dist/SvComboBox.svelte +275 -275
  11. package/dist/SvContextMenu.svelte +116 -116
  12. package/dist/SvCountryInput.svelte +160 -160
  13. package/dist/SvDrawer.svelte +254 -250
  14. package/dist/SvDropDownList.svelte +374 -374
  15. package/dist/SvDurationInput.svelte +126 -126
  16. package/dist/SvField.svelte +293 -293
  17. package/dist/SvForm.svelte +437 -437
  18. package/dist/SvGrid.controller.svelte.d.ts +14 -1
  19. package/dist/SvGrid.controller.svelte.js +112 -28
  20. package/dist/SvGrid.css +2704 -2723
  21. package/dist/SvGrid.svelte +3361 -3333
  22. package/dist/SvGrid.types.d.ts +20 -5
  23. package/dist/SvGridChart.svelte +1724 -1724
  24. package/dist/SvGridChartPanel.svelte +485 -485
  25. package/dist/SvGridChartView.svelte +70 -70
  26. package/dist/SvGridDropdown.svelte +696 -696
  27. package/dist/SvGridSelect.svelte +259 -259
  28. package/dist/SvGroupCell.svelte +109 -109
  29. package/dist/SvListBox.svelte +326 -287
  30. package/dist/SvListBox.svelte.d.ts +10 -1
  31. package/dist/SvMaskedInput.svelte +122 -122
  32. package/dist/SvMenu.svelte +124 -124
  33. package/dist/SvMenuList.svelte +146 -146
  34. package/dist/SvMultiSelect.svelte +281 -281
  35. package/dist/SvNumberInput.svelte +168 -168
  36. package/dist/SvOtpInput.svelte +158 -158
  37. package/dist/SvPasswordInput.svelte +151 -151
  38. package/dist/SvPhoneInput.svelte +133 -131
  39. package/dist/SvPopover.svelte +197 -197
  40. package/dist/SvRadioGroup.svelte +107 -107
  41. package/dist/SvRowGroupPanel.svelte +170 -170
  42. package/dist/SvScrollArea.svelte +61 -61
  43. package/dist/SvSlider.svelte +200 -200
  44. package/dist/SvSwitchButton.svelte +107 -107
  45. package/dist/SvTagsInput.svelte +112 -112
  46. package/dist/SvTextInput.svelte +147 -147
  47. package/dist/SvTimePicker.svelte +245 -245
  48. package/dist/SvToaster.svelte +159 -159
  49. package/dist/SvToggleButton.svelte +85 -85
  50. package/dist/SvTooltip.svelte +161 -161
  51. package/dist/SvTour.svelte +204 -204
  52. package/dist/SvTree.svelte +437 -437
  53. package/dist/SvTreeSelect.svelte +233 -233
  54. package/dist/cdn/GridMenus-Da_p7SKS.js +486 -0
  55. package/dist/cdn/GridMenus-Ds3OpzZT.js +490 -0
  56. package/dist/cdn/{SvDateTimePicker-B1sDc9Pz.js → SvDateTimePicker-B8GopjhC.js} +2 -2
  57. package/dist/cdn/{SvDateTimePicker-Bh0FTs1E.js → SvDateTimePicker-DB0aIEk8.js} +2 -2
  58. package/dist/cdn/{SvGridChart-Bgk4hDs8.js → SvGridChart-BcLCYvw9.js} +1 -1
  59. package/dist/cdn/{SvGridChart-BKQsO5fZ.js → SvGridChart-BhnFdLd0.js} +1 -1
  60. package/dist/cdn/{SvGridChartPanel-DkCc2Z7b.js → SvGridChartPanel-Cmx9DHAS.js} +1 -1
  61. package/dist/cdn/{SvGridChartPanel-DSkHIQDd.js → SvGridChartPanel-DvjwxLvK.js} +1 -1
  62. package/dist/cdn/{SvGridChartView-BrbVaELm.js → SvGridChartView-B40DTJSX.js} +1 -1
  63. package/dist/cdn/{SvGridChartView-i9rWvSKg.js → SvGridChartView-PwqI4s02.js} +1 -1
  64. package/dist/cdn/{SvGridDropdown-D08sVmAy.js → SvGridDropdown-DjALc_4f.js} +1 -1
  65. package/dist/cdn/{SvGridDropdown-CGxxopQ4.js → SvGridDropdown-hpnHvOGt.js} +1 -1
  66. package/dist/cdn/{src-cgs1wcUS.js → src-BLJfdyL0.js} +4034 -3889
  67. package/dist/cdn/{src-Cw8d9U8j.js → src-DYDCiC0D.js} +7053 -6908
  68. package/dist/cdn/svgrid.js +9 -9
  69. package/dist/cdn/svgrid.svelte-external.js +9 -9
  70. package/dist/chart-export.js +8 -8
  71. package/dist/column-groups.js +8 -10
  72. package/dist/column-id.d.ts +9 -0
  73. package/dist/column-id.js +25 -0
  74. package/dist/core.js +2 -1
  75. package/dist/createListbox.svelte.d.ts +15 -2
  76. package/dist/createListbox.svelte.js +27 -6
  77. package/dist/editing.d.ts +1 -0
  78. package/dist/editing.js +45 -10
  79. package/dist/filtering/excel-filters.d.ts +30 -10
  80. package/dist/filtering/excel-filters.js +96 -15
  81. package/dist/index.d.ts +2 -2
  82. package/dist/index.js +2 -2
  83. package/dist/menus.d.ts +2 -0
  84. package/dist/menus.js +25 -0
  85. package/dist/row-resize.js +40 -0
  86. package/dist/selection.js +1 -1
  87. package/package.json +10 -10
  88. package/src/FlexRender.svelte +96 -96
  89. package/src/GridFooter.svelte +179 -179
  90. package/src/GridMenus.svelte +782 -734
  91. package/src/SvAutoComplete.svelte +165 -165
  92. package/src/SvCalendar.svelte +503 -503
  93. package/src/SvCalendar.test.ts +226 -226
  94. package/src/SvCarousel.svelte +141 -141
  95. package/src/SvCheckBox.svelte +101 -101
  96. package/src/SvColorInput.svelte +181 -181
  97. package/src/SvComboBox.svelte +275 -275
  98. package/src/SvContextMenu.svelte +116 -116
  99. package/src/SvCountryInput.svelte +160 -160
  100. package/src/SvDrawer.svelte +254 -250
  101. package/src/SvDrawer.test.ts +18 -1
  102. package/src/SvDropDownList.svelte +374 -374
  103. package/src/SvDurationInput.svelte +126 -126
  104. package/src/SvField.svelte +293 -293
  105. package/src/SvForm.svelte +437 -437
  106. package/src/SvForm.test.ts +411 -411
  107. package/src/SvGrid.controller.svelte.ts +3335 -3239
  108. package/src/SvGrid.css +2704 -2723
  109. package/src/SvGrid.svelte +3361 -3333
  110. package/src/SvGrid.types.ts +1628 -1613
  111. package/src/SvGridChart.svelte +1724 -1724
  112. package/src/SvGridChartPanel.svelte +485 -485
  113. package/src/SvGridChartView.svelte +70 -70
  114. package/src/SvGridDropdown.svelte +696 -696
  115. package/src/SvGridSelect.svelte +259 -259
  116. package/src/SvGroupCell.svelte +109 -109
  117. package/src/SvListBox.svelte +326 -287
  118. package/src/SvMaskedInput.svelte +122 -122
  119. package/src/SvMenu.svelte +124 -124
  120. package/src/SvMenu.test.ts +97 -97
  121. package/src/SvMenuList.svelte +146 -146
  122. package/src/SvMultiSelect.svelte +281 -281
  123. package/src/SvNavPane.test.ts +15 -4
  124. package/src/SvNumberInput.svelte +168 -168
  125. package/src/SvOtpInput.svelte +158 -158
  126. package/src/SvPasswordInput.svelte +151 -151
  127. package/src/SvPhoneInput.svelte +133 -131
  128. package/src/SvPopover.svelte +197 -197
  129. package/src/SvRadioGroup.svelte +107 -107
  130. package/src/SvRowGroupPanel.svelte +170 -170
  131. package/src/SvScrollArea.svelte +61 -61
  132. package/src/SvSlider.svelte +200 -200
  133. package/src/SvSwitchButton.svelte +107 -107
  134. package/src/SvTagsInput.svelte +112 -112
  135. package/src/SvTextInput.svelte +147 -147
  136. package/src/SvTimePicker.svelte +245 -245
  137. package/src/SvToaster.svelte +159 -159
  138. package/src/SvToaster.test.ts +95 -95
  139. package/src/SvToggleButton.svelte +85 -85
  140. package/src/SvTooltip.svelte +161 -161
  141. package/src/SvTour.svelte +204 -204
  142. package/src/SvTree.svelte +437 -437
  143. package/src/SvTreeSelect.svelte +233 -233
  144. package/src/a11y/dismissable.test.ts +119 -119
  145. package/src/a11y/dismissable.ts +114 -114
  146. package/src/a11y.contract.test.ts +49 -49
  147. package/src/a11y.test.ts +59 -59
  148. package/src/a11y.ts +61 -61
  149. package/src/ai.test.ts +502 -502
  150. package/src/ai.ts +1391 -1391
  151. package/src/build-api.coverage.test.ts +633 -633
  152. package/src/build-api.ts +895 -895
  153. package/src/builtin-editors.grid.test.ts +85 -85
  154. package/src/cell-formatting.ts +169 -169
  155. package/src/cell-render.ts +469 -469
  156. package/src/chart-export.ts +201 -201
  157. package/src/chart-view.svelte.ts +36 -36
  158. package/src/chart.ts +2296 -2296
  159. package/src/collaboration.test.ts +104 -104
  160. package/src/collaboration.ts +167 -167
  161. package/src/column-groups.test.ts +48 -0
  162. package/src/column-groups.ts +8 -10
  163. package/src/column-id.ts +30 -0
  164. package/src/core.performance.test.ts +30 -30
  165. package/src/core.ts +1112 -1111
  166. package/src/createAutocomplete.svelte.ts +132 -132
  167. package/src/createCombobox.svelte.ts +191 -191
  168. package/src/createCountryInput.svelte.ts +157 -157
  169. package/src/createDropdownList.svelte.ts +168 -168
  170. package/src/createForm.svelte.ts +386 -386
  171. package/src/createGrid.svelte.ts +42 -42
  172. package/src/createGrid.test.ts +10 -10
  173. package/src/createGridState.svelte.ts +17 -17
  174. package/src/createListbox.svelte.ts +39 -7
  175. package/src/createMenu.svelte.ts +225 -225
  176. package/src/createPopoverSelect.svelte.ts +213 -213
  177. package/src/createSlider.svelte.ts +191 -191
  178. package/src/createTooltip.svelte.ts +144 -144
  179. package/src/createTree.svelte.ts +319 -319
  180. package/src/editing.test.ts +949 -859
  181. package/src/editing.ts +709 -675
  182. package/src/editor-contract.ts +157 -157
  183. package/src/export-data-api.test.ts +126 -126
  184. package/src/export-format.test.ts +107 -107
  185. package/src/export-format.ts +598 -598
  186. package/src/filter-operators.ts +157 -157
  187. package/src/filtering/excel-filters.test.ts +44 -1
  188. package/src/filtering/excel-filters.ts +91 -14
  189. package/src/flex-render.ts +3 -3
  190. package/src/form-field.ts +127 -127
  191. package/src/index.ts +715 -713
  192. package/src/js-scroller.svelte.ts +173 -173
  193. package/src/keyboard.test.ts +59 -59
  194. package/src/keyboard.ts +97 -97
  195. package/src/list-nav.test.ts +49 -49
  196. package/src/list-nav.ts +29 -29
  197. package/src/list-option.test.ts +56 -56
  198. package/src/list-option.ts +172 -172
  199. package/src/menus.test.ts +736 -700
  200. package/src/menus.ts +679 -652
  201. package/src/merge-objects.ts +48 -48
  202. package/src/overlays.test.ts +90 -90
  203. package/src/render-component.ts +28 -28
  204. package/src/row-resize.test.ts +100 -0
  205. package/src/row-resize.ts +36 -0
  206. package/src/scheduler-model.test.ts +562 -562
  207. package/src/scheduler-model.ts +872 -872
  208. package/src/selection.test.ts +754 -754
  209. package/src/selection.ts +600 -600
  210. package/src/server-data-source.test.ts +289 -289
  211. package/src/server-data-source.ts +413 -413
  212. package/src/sparkline.test.ts +68 -68
  213. package/src/sparkline.ts +169 -169
  214. package/src/spreadsheet.test.ts +489 -489
  215. package/src/spreadsheet.ts +312 -312
  216. package/src/static-functions.ts +11 -11
  217. package/src/subscribe.ts +38 -38
  218. package/src/svgrid-wrapper.types.ts +524 -524
  219. package/src/svgrid.api-extensions.test.ts +8 -3
  220. package/src/svgrid.behavior.test.ts +706 -706
  221. package/src/svgrid.cell-dom-ids.test.ts +96 -0
  222. package/src/svgrid.charting.test.ts +534 -534
  223. package/src/svgrid.conditional-stat-scope.test.ts +111 -0
  224. package/src/svgrid.features.test.ts +157 -157
  225. package/src/svgrid.filter-menu-listbox.svelte.test.ts +308 -0
  226. package/src/svgrid.filter-menu-scroll.test.ts +3 -1
  227. package/src/svgrid.group-header-ids.test.ts +121 -0
  228. package/src/svgrid.new-features.wrapper.test.ts +251 -251
  229. package/src/svgrid.wrapper.test.ts +40 -40
  230. package/src/test-setup.ts +62 -62
  231. package/src/themes/index.ts +215 -215
  232. package/src/toast-store.svelte.ts +246 -246
  233. package/src/toast-store.test.ts +147 -147
  234. package/src/ui-buttons.test.ts +144 -144
  235. package/src/ui-inputs.test.ts +118 -118
  236. package/src/ui-range.test.ts +70 -70
  237. package/src/ui-selection.test.ts +155 -155
  238. package/src/ui-tier1.test.ts +142 -142
  239. package/src/virtual.test.ts +88 -88
  240. package/src/virtualization/column-virtualizer.test.ts +27 -27
  241. package/src/virtualization/column-virtualizer.ts +30 -30
  242. package/src/virtualization/svelte-virtualizer.svelte.ts +26 -26
  243. package/src/virtualization/types.ts +30 -30
  244. package/src/virtualization/virtualizer.test.ts +47 -47
  245. package/src/virtualization/virtualizer.ts +296 -296
  246. package/themes/ember.css +71 -71
  247. package/dist/cdn/GridMenus-BzxEYNtW.js +0 -421
  248. package/dist/cdn/GridMenus-Dr-nGEXn.js +0 -417
@@ -12,7 +12,7 @@ import { getColumnBaseValue, isGroupRow, toolPanelHeaderLabel, formatSummaryNume
12
12
  * the component lifecycle) and consumed through the returned getters.
13
13
  */
14
14
  export type SvGridController<TFeatures extends TableFeatures = TableFeatures, TData extends RowData = RowData> = ReturnType<typeof createSvGridController<TFeatures, TData>>;
15
- export declare function createSvGridController<TFeatures extends TableFeatures = TableFeatures, TData extends RowData = RowData>(rawProps: Props<TFeatures, TData>): {
15
+ export declare function createSvGridController<TFeatures extends TableFeatures = TableFeatures, TData extends RowData = RowData>(rawProps: Props<TFeatures, TData>, domIdBase?: string): {
16
16
  readonly props: Props<TFeatures, TData>;
17
17
  optionOverrides: Record<string, unknown>;
18
18
  readonly editingEnabled: boolean;
@@ -126,6 +126,10 @@ export declare function createSvGridController<TFeatures extends TableFeatures =
126
126
  inSuggestPos: MenuPosition;
127
127
  inSuggestQuery: string;
128
128
  readonly inSuggestValues: string[];
129
+ readonly inSuggestOptions: {
130
+ value: string;
131
+ label: string;
132
+ }[];
129
133
  readonly facetValuesForColumn: (columnId: string) => Array<string>;
130
134
  chooseColumnsPos: MenuPosition | null;
131
135
  contextMenuFor: ContextMenuTarget<TData> | null;
@@ -446,6 +450,7 @@ export declare function createSvGridController<TFeatures extends TableFeatures =
446
450
  readonly columnWindowRightSpacer: number;
447
451
  readonly activeCell: any;
448
452
  readonly activeDescendantId: string | null;
453
+ readonly gridDomId: string;
449
454
  readonly formatSummaryNumeric: typeof formatSummaryNumeric;
450
455
  readonly computeSummaries: (rows: readonly Row<TData>[], columns: readonly Column<TData>[]) => Record<string, string>;
451
456
  readonly SUMMARY_DEFER_CELL_LIMIT: number;
@@ -549,6 +554,7 @@ export declare function createSvGridController<TFeatures extends TableFeatures =
549
554
  }, direction: "undo" | "redo") => void;
550
555
  readonly updateEditingCellValue: (value: unknown) => void;
551
556
  readonly onEditorKeyDown: (event: KeyboardEvent) => void;
557
+ readonly commitAndMoveByTab: (shiftKey: boolean) => void;
552
558
  readonly focusOnMount: (node: HTMLInputElement | HTMLTextAreaElement) => void;
553
559
  readonly onHeaderSortClick: (event: MouseEvent, columnId: string) => void;
554
560
  readonly onGridKeyDown: (event: KeyboardEvent) => void;
@@ -594,6 +600,7 @@ export declare function createSvGridController<TFeatures extends TableFeatures =
594
600
  readonly addFilterToken: (columnId: string, token: string) => void;
595
601
  readonly removeFilterToken: (columnId: string, token: string) => void;
596
602
  readonly toggleFilterToken: (columnId: string, token: string) => void;
603
+ readonly setFilterTokens: (columnId: string, tokens: Iterable<string>) => void;
597
604
  readonly sortColumnFromMenu: (columnId: string, desc: boolean) => void;
598
605
  readonly clearColumnSort: (columnId: string) => void;
599
606
  readonly groupByColumnFromMenu: (columnId: string) => void;
@@ -605,8 +612,14 @@ export declare function createSvGridController<TFeatures extends TableFeatures =
605
612
  readonly serverFacetLoading: string | null;
606
613
  readonly columnMenuFacetValues: string[];
607
614
  readonly columnMenuVisibleFacets: string[];
615
+ readonly columnMenuFacetOptions: {
616
+ value: string;
617
+ label: string;
618
+ }[];
619
+ readonly columnMenuSelectedFacets: ReadonlySet<string>;
608
620
  readonly isFacetChecked: (columnId: string, value: string) => any;
609
621
  readonly toggleFacetValue: (columnId: string, value: string) => void;
622
+ readonly setFacetSelection: (columnId: string, next: ReadonlySet<string>) => void;
610
623
  readonly isAllFacetsChecked: (columnId: string) => boolean;
611
624
  readonly toggleAllFacets: (columnId: string) => void;
612
625
  readonly clearColumnFilter: (columnId: string) => void;
@@ -16,6 +16,7 @@ import { createRowDrag, } from "./row-drag";
16
16
  import { createAlignedGrids, } from "./aligned-grids";
17
17
  import { resolveColumnTypes, } from "./column-types";
18
18
  import { computeColumnGroupMeta, hiddenLeavesForCollapse, } from "./column-groups";
19
+ import { resolveColumnId } from "./column-id";
19
20
  import { createGridApi, } from "./build-api";
20
21
  import { createClipboard, } from "./clipboard";
21
22
  import { resolveGridMessages } from "./grid-messages";
@@ -23,6 +24,7 @@ import { getPivotEngine, hasPivotEngine } from "./pivot-view.svelte";
23
24
  import { filterOperatorOptions, fallbackOperatorOption, TEXT_OPERATORS, NUMBER_OPERATORS, DATE_OPERATORS, CHECKBOX_OPERATORS, operatorOption, operatorsForColumn, defaultOperatorFor, operatorLabelFor, } from "./filter-operators";
24
25
  import { isBucketableColumn, buildBuckets, isInBucket, } from "./facet-buckets";
25
26
  import { getColumnBaseValue, isGroupRow, toolPanelHeaderLabel, formatSummaryNumeric, getColumnAlign, getPinnedCellValue, getColumnAccessorValue, columnDefMatchesId, } from "./cell-values";
27
+ import { untrack } from "svelte";
26
28
  /**
27
29
  * Conservative fallback for the browser's max element height, used during SSR
28
30
  * or if runtime detection fails. 8M is below every known engine cap (Firefox
@@ -145,7 +147,15 @@ function observeSizeRaf(el, cb) {
145
147
  observer.disconnect();
146
148
  };
147
149
  }
148
- export function createSvGridController(rawProps) {
150
+ export function createSvGridController(rawProps, domIdBase) {
151
+ /**
152
+ * Base for every DOM id this grid mints (`<base>_cell_<row>_<col>`). The view
153
+ * passes Svelte's per-instance `$props.id()`, which is stable across SSR and
154
+ * hydration; two `<SvGrid>` instances on one page used to emit identical cell
155
+ * ids, so `aria-activedescendant` on the second pointed into the first (#77).
156
+ * Falls back to the historical literal for direct controller construction.
157
+ */
158
+ const gridDomId = domIdBase ?? "svgrid";
149
159
  // Runtime option overrides set via the imperative api (`api.setOption(key, value)`).
150
160
  // Every controller read of a prop goes through the `props` proxy below (and the view
151
161
  // reads controller-resolved gates like `_features` / `editingEnabled`, not the raw
@@ -620,16 +630,13 @@ export function createSvGridController(rawProps) {
620
630
  if (depth === 0)
621
631
  return [];
622
632
  const leafEntries = [];
623
- function buildId(def, parentId, fallbackIx) {
624
- return def.id ?? def.field ?? `${parentId ?? 'col'}_d_${fallbackIx}`;
625
- }
626
633
  // Leaves hidden by a collapsed/expanded group are skipped everywhere here,
627
634
  // so group colSpan + widthPx exclude them and stay aligned with the leaves
628
635
  // the body actually renders.
629
636
  const hiddenLeaf = hiddenByGroupCollapse;
630
637
  function collectLeaves(defs, parentId, depthHere) {
631
638
  defs.forEach((def, ix) => {
632
- const id = buildId(def, parentId, ix);
639
+ const id = resolveColumnId(def, parentId, depthHere, ix);
633
640
  if (def.columns?.length) {
634
641
  collectLeaves(def.columns, id, depthHere + 1);
635
642
  }
@@ -639,17 +646,22 @@ export function createSvGridController(rawProps) {
639
646
  });
640
647
  }
641
648
  collectLeaves(userCols, undefined, 0);
642
- function indexTree(defs, parentId, cursor) {
649
+ function indexTree(defs, parentId, cursor, depthHere) {
643
650
  const nodes = [];
644
- for (const def of defs) {
645
- const id = buildId(def, parentId, nodes.length);
651
+ // Walk by array index, not by a count of pushed nodes: the `continue`
652
+ // below skips hidden leaves without pushing, so a counter would drift and
653
+ // hand the next unnamed sibling a different id than `collectLeaves` and
654
+ // the engine give it (#63).
655
+ for (let ix = 0; ix < defs.length; ix += 1) {
656
+ const def = defs[ix];
657
+ const id = resolveColumnId(def, parentId, depthHere, ix);
646
658
  // Skip leaves the collapse state hides, so leaf indices/colSpans match
647
659
  // `leafEntries` (and the body's rendered columns) exactly.
648
660
  if (!def.columns?.length && hiddenLeaf[id])
649
661
  continue;
650
662
  const leafStart = cursor.leaf;
651
663
  if (def.columns?.length) {
652
- indexTree(def.columns, id, cursor);
664
+ indexTree(def.columns, id, cursor, depthHere + 1);
653
665
  }
654
666
  else {
655
667
  cursor.leaf += 1;
@@ -660,7 +672,7 @@ export function createSvGridController(rawProps) {
660
672
  return nodes;
661
673
  }
662
674
  const cursor = { leaf: 0 };
663
- const topNodes = indexTree(userCols, undefined, cursor);
675
+ const topNodes = indexTree(userCols, undefined, cursor, 0);
664
676
  function nodesAtDepth(nodes, currentDepth, targetDepth) {
665
677
  if (currentDepth === targetDepth)
666
678
  return nodes;
@@ -668,7 +680,7 @@ export function createSvGridController(rawProps) {
668
680
  for (const n of nodes) {
669
681
  if (n.def.columns?.length) {
670
682
  const childCursor = { leaf: n.leafStart };
671
- const children = indexTree(n.def.columns, n.id, childCursor);
683
+ const children = indexTree(n.def.columns, n.id, childCursor, currentDepth + 1);
672
684
  out.push(...nodesAtDepth(children, currentDepth + 1, targetDepth));
673
685
  }
674
686
  else {
@@ -760,10 +772,13 @@ export function createSvGridController(rawProps) {
760
772
  const formats = props.conditionalFormats;
761
773
  if (!formats?.length || !formatsNeedingStats(formats))
762
774
  return map;
763
- // `visible` (default): the currently displayed rows (filtered + paged),
764
- // so the heat map reflects what the user is looking at. `all`: the full
765
- // unfiltered dataset, for a stable scale independent of filter/paging.
766
- const scanAll = props.conditionalStatScope === "all";
775
+ // `filtered` (default): every row that survives the filters, ignoring the
776
+ // page slice - so a value keeps the same colour as you page through (#61).
777
+ // `visible`: only the rows on screen, rescaling per page. `all`: the full
778
+ // unfiltered dataset, for a scale that stays put as you filter.
779
+ const scope = props.conditionalStatScope ?? "filtered";
780
+ const scanAll = scope === "all";
781
+ const scanRows = scope === "visible" ? allRows : allRowsBeforePagination;
767
782
  for (const column of allColumns) {
768
783
  const needs = formats.some((f) => formatNeedsStats(f) && (!f.columns || f.columns.includes(column.id)));
769
784
  if (!needs)
@@ -779,7 +794,7 @@ export function createSvGridController(rawProps) {
779
794
  }
780
795
  })()
781
796
  : (function* () {
782
- for (const row of allRows) {
797
+ for (const row of scanRows) {
783
798
  yield fieldFn
784
799
  ? fieldFn(row.original)
785
800
  : field
@@ -1740,7 +1755,7 @@ export function createSvGridController(rawProps) {
1740
1755
  const inCols = active.colIndex >= 0 && active.colIndex < allColumns.length;
1741
1756
  if (!inRows || !inCols)
1742
1757
  return null;
1743
- return getGridCellDomId("svgrid", active.rowIndex, active.colIndex);
1758
+ return getGridCellDomId(gridDomId, active.rowIndex, active.colIndex);
1744
1759
  });
1745
1760
  // Above this many cells (rows x columns) the summary aggregation is
1746
1761
  // deferred one animation frame so it never blocks first paint - a
@@ -1808,7 +1823,7 @@ export function createSvGridController(rawProps) {
1808
1823
  grid.setActiveCell({
1809
1824
  rowIndex: 0,
1810
1825
  colIndex: 0,
1811
- cellId: getGridCellDomId("svgrid", 0, 0),
1826
+ cellId: getGridCellDomId(gridDomId, 0, 0),
1812
1827
  });
1813
1828
  });
1814
1829
  $effect(() => {
@@ -2166,13 +2181,55 @@ export function createSvGridController(rawProps) {
2166
2181
  }
2167
2182
  return Array.from(seen).sort((a, b) => a.localeCompare(b, undefined, { numeric: true }));
2168
2183
  }
2184
+ /**
2185
+ * Facet values for the open menu, SNAPSHOTTED when it opens.
2186
+ *
2187
+ * `facetValuesForColumn` walks every row and natural-sorts the distinct
2188
+ * values, so deriving it live re-ran that whole scan on every data change.
2189
+ * On a streaming grid (the trading-desk demo replaces its row array a couple
2190
+ * of times a second) that meant rebuilding a 10k-entry set + sort - and
2191
+ * re-keying the rendered value list - continuously for as long as the menu
2192
+ * sat open. The offered values are frozen for the life of the popover
2193
+ * instead, which is also what a spreadsheet's filter checklist does.
2194
+ * Filtering itself is unaffected: `valueFilters` matches live row values.
2195
+ *
2196
+ * The cache is a plain local, not `$state`, so writing it here can't feed
2197
+ * back into this derived.
2198
+ */
2199
+ // Stable identities for the closed-menu case, so the derives below don't hand
2200
+ // out a fresh empty array/set on every read.
2201
+ const EMPTY_FACETS = [];
2202
+ const EMPTY_FACET_SET = new Set();
2203
+ let facetCache = null;
2169
2204
  const columnMenuFacetValues = $derived.by(() => {
2170
2205
  // The funnel popover drives via `filterMenuFor`; the column menu's Filter
2171
2206
  // tab drives via `columnMenuFor`. Support whichever is open.
2172
2207
  const columnId = filterMenuFor ?? columnMenuFor;
2173
2208
  if (!columnId)
2174
- return [];
2175
- return facetValuesForColumn(columnId);
2209
+ return EMPTY_FACETS;
2210
+ // Server-provided values land asynchronously, so they stay TRACKED and
2211
+ // re-snapshot when they arrive. Locally derived values are read untracked
2212
+ // so a live data tick can't retrigger the scan.
2213
+ const source = props.serverFilterValues
2214
+ ? (serverFacetValues[columnId] ?? null)
2215
+ : null;
2216
+ if (facetCache?.columnId === columnId && facetCache.source === source) {
2217
+ return facetCache.values;
2218
+ }
2219
+ facetCache = {
2220
+ columnId,
2221
+ source,
2222
+ values: untrack(() => facetValuesForColumn(columnId)),
2223
+ };
2224
+ return facetCache.values;
2225
+ });
2226
+ // Drop the snapshot when the menu closes, so reopening the SAME column
2227
+ // re-scans and picks up whatever the data has become meanwhile. This has to
2228
+ // be an effect rather than a branch in the derived above: the derived is
2229
+ // lazy, and nothing reads it while the menu is shut.
2230
+ $effect(() => {
2231
+ if (!(filterMenuFor ?? columnMenuFor))
2232
+ facetCache = null;
2176
2233
  });
2177
2234
  const columnMenuVisibleFacets = $derived.by(() => {
2178
2235
  const query = columnMenuSearch.trim().toLowerCase();
@@ -2180,20 +2237,40 @@ export function createSvGridController(rawProps) {
2180
2237
  return columnMenuFacetValues;
2181
2238
  return columnMenuFacetValues.filter((value) => value.toLowerCase().includes(query));
2182
2239
  });
2240
+ /** Visible facets as listbox options ((Blanks) label for the empty value). */
2241
+ const columnMenuFacetOptions = $derived(columnMenuVisibleFacets.map((value) => ({
2242
+ value,
2243
+ label: value === "" ? "(Blanks)" : value,
2244
+ })));
2245
+ /**
2246
+ * Checked facets for the open menu. An ABSENT `valueFilters` entry means
2247
+ * "everything checked", so that case materializes the set once here rather
2248
+ * than every consumer re-deriving it.
2249
+ */
2250
+ const columnMenuSelectedFacets = $derived.by(() => {
2251
+ const columnId = filterMenuFor ?? columnMenuFor;
2252
+ if (!columnId)
2253
+ return EMPTY_FACET_SET;
2254
+ return valueFilters[columnId] ?? new Set(columnMenuFacetValues);
2255
+ });
2183
2256
  // Distinct values offered in the `in` / `notIn` suggestions dropdown for the
2184
- // active chip input, narrowed by whatever the user has typed. Capped so a
2185
- // high-cardinality column can't render thousands of rows into the popover.
2186
- const IN_SUGGEST_LIMIT = 200;
2257
+ // active chip input, narrowed by whatever the user has typed. Uncapped - the
2258
+ // dropdown windows its rows, so a high-cardinality column costs a list of
2259
+ // strings, not thousands of nodes.
2187
2260
  const inSuggestValues = $derived.by(() => {
2188
2261
  if (!inSuggestFor)
2189
- return [];
2262
+ return EMPTY_FACETS;
2190
2263
  const query = inSuggestQuery.trim().toLowerCase();
2191
2264
  const all = facetValuesForColumn(inSuggestFor);
2192
- const matched = query
2265
+ return query
2193
2266
  ? all.filter((value) => value.toLowerCase().includes(query))
2194
2267
  : all;
2195
- return matched.slice(0, IN_SUGGEST_LIMIT);
2196
2268
  });
2269
+ /** `in` / `notIn` suggestions as listbox options. */
2270
+ const inSuggestOptions = $derived(inSuggestValues.map((value) => ({
2271
+ value,
2272
+ label: value === "" ? "(Blanks)" : value,
2273
+ })));
2197
2274
  // Fire onApiReady exactly once when the grid is first ready. Wrapping in
2198
2275
  // an effect that tracks `props.onApiReady` was racy - every parent render
2199
2276
  // creates a new inline arrow, the effect re-fired, and any synchronous
@@ -2332,6 +2409,7 @@ export function createSvGridController(rawProps) {
2332
2409
  get inSuggestQuery() { return inSuggestQuery; },
2333
2410
  set inSuggestQuery(v) { inSuggestQuery = v; },
2334
2411
  get inSuggestValues() { return inSuggestValues; },
2412
+ get inSuggestOptions() { return inSuggestOptions; },
2335
2413
  get facetValuesForColumn() { return facetValuesForColumn; },
2336
2414
  get chooseColumnsPos() { return chooseColumnsPos; },
2337
2415
  set chooseColumnsPos(v) { chooseColumnsPos = v; },
@@ -2621,6 +2699,7 @@ export function createSvGridController(rawProps) {
2621
2699
  get columnWindowRightSpacer() { return columnWindowRightSpacer; },
2622
2700
  get activeCell() { return activeCell; },
2623
2701
  get activeDescendantId() { return activeDescendantId; },
2702
+ get gridDomId() { return gridDomId; },
2624
2703
  get formatSummaryNumeric() { return formatSummaryNumeric; },
2625
2704
  get computeSummaries() { return computeSummaries; },
2626
2705
  get SUMMARY_DEFER_CELL_LIMIT() { return SUMMARY_DEFER_CELL_LIMIT; },
@@ -2703,6 +2782,7 @@ export function createSvGridController(rawProps) {
2703
2782
  get applyHistoryStep() { return applyHistoryStep; },
2704
2783
  get updateEditingCellValue() { return updateEditingCellValue; },
2705
2784
  get onEditorKeyDown() { return onEditorKeyDown; },
2785
+ get commitAndMoveByTab() { return commitAndMoveByTab; },
2706
2786
  get focusOnMount() { return focusOnMount; },
2707
2787
  get onHeaderSortClick() { return onHeaderSortClick; },
2708
2788
  get onGridKeyDown() { return onGridKeyDown; },
@@ -2743,6 +2823,7 @@ export function createSvGridController(rawProps) {
2743
2823
  get addFilterToken() { return addFilterToken; },
2744
2824
  get removeFilterToken() { return removeFilterToken; },
2745
2825
  get toggleFilterToken() { return toggleFilterToken; },
2826
+ get setFilterTokens() { return setFilterTokens; },
2746
2827
  get sortColumnFromMenu() { return sortColumnFromMenu; },
2747
2828
  get clearColumnSort() { return clearColumnSort; },
2748
2829
  get groupByColumnFromMenu() { return groupByColumnFromMenu; },
@@ -2754,8 +2835,11 @@ export function createSvGridController(rawProps) {
2754
2835
  get serverFacetLoading() { return serverFacetLoading; },
2755
2836
  get columnMenuFacetValues() { return columnMenuFacetValues; },
2756
2837
  get columnMenuVisibleFacets() { return columnMenuVisibleFacets; },
2838
+ get columnMenuFacetOptions() { return columnMenuFacetOptions; },
2839
+ get columnMenuSelectedFacets() { return columnMenuSelectedFacets; },
2757
2840
  get isFacetChecked() { return isFacetChecked; },
2758
2841
  get toggleFacetValue() { return toggleFacetValue; },
2842
+ get setFacetSelection() { return setFacetSelection; },
2759
2843
  get isAllFacetsChecked() { return isAllFacetsChecked; },
2760
2844
  get toggleAllFacets() { return toggleAllFacets; },
2761
2845
  get clearColumnFilter() { return clearColumnFilter; },
@@ -2769,9 +2853,9 @@ export function createSvGridController(rawProps) {
2769
2853
  const { showTooltipFor, hideTooltip, flushScheduledScrollSync, scheduleScrollSync, onBodyScroll } = createScrollSync(ctx);
2770
2854
  const { onGridKeyDown, onWindowKeydown, onHeaderSortClick } = createKeyboard(ctx);
2771
2855
  const { computeSummaries, hasRenderedColumn } = createSummaries(ctx);
2772
- const { updateFilterRow, updateFilterOperator, updateFilterMenuValue, updateFilterMenuValueTo, addFilterToken, removeFilterToken, toggleFilterToken, toggleCheckboxWithKeyboard, isColumnFiltered, closeMenus, openInSuggest, closeInSuggest, openChooseColumns, openColumnMenu, openFilterMenu, openOperatorMenu, sortColumnFromMenu, clearColumnSort, groupByColumnFromMenu, clearGroupingFromMenu, isFacetChecked, toggleFacetValue, isAllFacetsChecked, toggleAllFacets, clearColumnFilter, changePage, goToPage, setPageSize, openContextMenu, closeContextMenu, contextMenuItems, saveComment, removeComment, closeCommentEditor } = createMenus(ctx);
2856
+ const { updateFilterRow, updateFilterOperator, updateFilterMenuValue, updateFilterMenuValueTo, addFilterToken, removeFilterToken, toggleFilterToken, toggleCheckboxWithKeyboard, isColumnFiltered, closeMenus, openInSuggest, closeInSuggest, openChooseColumns, openColumnMenu, openFilterMenu, openOperatorMenu, sortColumnFromMenu, clearColumnSort, groupByColumnFromMenu, clearGroupingFromMenu, isFacetChecked, toggleFacetValue, setFacetSelection, setFilterTokens, isAllFacetsChecked, toggleAllFacets, clearColumnFilter, changePage, goToPage, setPageSize, openContextMenu, closeContextMenu, contextMenuItems, saveComment, removeComment, closeCommentEditor } = createMenus(ctx);
2773
2857
  const { cellConditionalFormat, computeRowClass, computeCellClass, computeCellTooltip, computeCellValidity, computeCellNote, getColumnEditorOptions, formatListCellValue, formatCellValue, formatPinnedValue, computePinnedCellClass } = createCellRender(ctx);
2774
- const { isCellEditable, isCellEditableAt, getRowColumnValue, getCellDisplayValue, startEditingWithChar, startEditing, stopEditing, startFullRowEdit, setFullRowDraft, commitFullRowEdit, cancelFullRowEdit, saveEditingCell, applyHistoryStep, updateEditingCellValue, onEditorKeyDown, focusOnMount, onCellDoubleClick, pasteFromClipboard, onGridPaste } = createEditing(ctx);
2858
+ const { isCellEditable, isCellEditableAt, getRowColumnValue, getCellDisplayValue, startEditingWithChar, startEditing, stopEditing, startFullRowEdit, setFullRowDraft, commitFullRowEdit, cancelFullRowEdit, saveEditingCell, applyHistoryStep, updateEditingCellValue, onEditorKeyDown, commitAndMoveByTab, focusOnMount, onCellDoubleClick, pasteFromClipboard, onGridPaste } = createEditing(ctx);
2775
2859
  const { isRowSelected, toggleRowSelectionById, toggleSelectAllRows, setActiveCell, scrollActiveCellIntoView, setSelection, extendSelection, isCellInSelectedRange, getCellRangeEdges, getSelectionRects, isInFillPreview, fillMarqueeEdges, findColumnById, onCellPointerDown, onCellPointerEnter, endDragSelection, onWindowPointerMove, onCellClick, emitCellDoubleClick } = createSelection(ctx);
2776
2860
  const { cellPinStyle, isColumnPinned, getCurrentColumnOrder, emitColumnOrder, setColumnOrderInternal, applyColumnDrop, onColumnHeaderDragStart, onColumnHeaderDragOver, onColumnHeaderDragLeave, onColumnHeaderDrop, onColumnHeaderDragEnd, pinColumnLeft, pinColumnRight, unpinColumn, toggleColumnVisibleInPanel, moveColumnInPanel, toggleGroupInPanel, getColumnBaseWidth, getColumnWidth, startColumnResize, onColumnResizeMove, endColumnResize, measureText, autosizeColumn, autosizeAllColumns, resetColumns } = createColumns(ctx);
2777
2861
  const { onRowDragStart, onRowDragOver, onRowDragLeave, onRowDrop, onRowsContainerDragOver, onRowsContainerDrop, onRowDragEnd, destroyRowDrag } = createRowDrag(ctx);