@svgrid/grid 3.0.5 → 3.0.7

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 (166) hide show
  1. package/README.md +28 -7
  2. package/dist/GridMenus.svelte +34 -4
  3. package/dist/SvGrid.controller.svelte.d.ts +23 -3
  4. package/dist/SvGrid.controller.svelte.js +235 -54
  5. package/dist/SvGrid.css +143 -7
  6. package/dist/SvGrid.helpers.js +2 -4
  7. package/dist/SvGrid.svelte +223 -38
  8. package/dist/SvGrid.types.d.ts +77 -4
  9. package/dist/SvGridDropdown.svelte +20 -0
  10. package/dist/SvGridDropdown.svelte.d.ts +12 -0
  11. package/dist/SvModal.svelte +22 -0
  12. package/dist/SvModal.svelte.d.ts +7 -0
  13. package/dist/a11y/dismissable.d.ts +10 -0
  14. package/dist/a11y/dismissable.js +24 -2
  15. package/dist/build-api.js +81 -31
  16. package/dist/cdn/{GridMenus-CID62rlI.js → GridMenus-BgUS-W3o.js} +151 -142
  17. package/dist/cdn/GridMenus-CcwU8I4t.js +644 -0
  18. package/dist/cdn/{SvChartMenu-FBSMINA6.js → SvChartMenu-BFSTpvB-.js} +1 -1
  19. package/dist/cdn/{SvChartMenu-Bl6PBbkT.js → SvChartMenu-BZ1Iwv0y.js} +1 -1
  20. package/dist/cdn/{SvDateTimePicker-DQwt4UAs.js → SvDateTimePicker-D9u_cOf8.js} +1 -1
  21. package/dist/cdn/{SvDateTimePicker-vNU6bZ-q.js → SvDateTimePicker-s_6IUpI7.js} +1 -1
  22. package/dist/cdn/{SvGridCellEditor-B1p-vCK5.js → SvGridCellEditor-9yz-SbdZ.js} +2 -2
  23. package/dist/cdn/{SvGridCellEditor-D_0q4xAu.js → SvGridCellEditor-D7-ql1Hd.js} +2 -2
  24. package/dist/cdn/{SvGridChart-C3EWAZaM.js → SvGridChart-DMUOFxOe.js} +4 -4
  25. package/dist/cdn/{SvGridChart-DzLkSwCH.js → SvGridChart-N7ik0oWy.js} +4 -4
  26. package/dist/cdn/{SvGridChartBuilder-CfII62sZ.js → SvGridChartBuilder-CB_Jnm2k.js} +4 -4
  27. package/dist/cdn/{SvGridChartBuilder-BE2T1ykB.js → SvGridChartBuilder-Ca7gF8ZK.js} +4 -4
  28. package/dist/cdn/{SvGridChartPanel-xf4sWVTo.js → SvGridChartPanel-9GOJRHP7.js} +5 -5
  29. package/dist/cdn/{SvGridChartPanel-CCX5_Wgd.js → SvGridChartPanel-Dl-FujN8.js} +5 -5
  30. package/dist/cdn/{SvGridChartView-CfuXmY5I.js → SvGridChartView-B1LFgoPP.js} +2 -2
  31. package/dist/cdn/{SvGridChartView-DYwabQWj.js → SvGridChartView-By3n7DGZ.js} +2 -2
  32. package/dist/cdn/{SvGridDropdown-D0VdjeR8.js → SvGridDropdown-BWeM3lMe.js} +46 -46
  33. package/dist/cdn/{SvGridDropdown-D13MtJ2j.js → SvGridDropdown-CJ6QqTxu.js} +67 -67
  34. package/dist/cdn/{SvModal-CIZWCcad.js → SvModal-ClxGmpAc.js} +187 -186
  35. package/dist/cdn/{SvModal-BAE-pjZX.js → SvModal-DhB_VMFR.js} +148 -147
  36. package/dist/cdn/{cell-formatting-C2Hf5gqd.js → cell-formatting-Mnv84zoE.js} +28 -6
  37. package/dist/cdn/{chart-Dz7SqMXH.js → chart-By7h2Guv.js} +1 -1
  38. package/dist/cdn/{chart-panel-messages-CUbf2R4i.js → chart-panel-messages-BC-tOgFY.js} +1 -1
  39. package/dist/cdn/{chart-panel-messages-CmNrMdsr.js → chart-panel-messages-DUaXr-sb.js} +1 -1
  40. package/dist/cdn/{chart-summary-BJW_tg_X.js → chart-summary-BDtrNEiA.js} +1 -1
  41. package/dist/cdn/{chart-trend-CaN9mDEV.js → chart-trend-C1aOAPBZ.js} +1 -1
  42. package/dist/cdn/{dismissable-DAHetSNk.js → dismissable-Brc4EZU1.js} +5 -1
  43. package/dist/cdn/{editor-registry-BhgE3S84.js → editor-registry-BVeHvlZR.js} +49 -50
  44. package/dist/cdn/{export-format-CUDLy2yn.js → export-format-y1wdyCcv.js} +93 -97
  45. package/dist/cdn/{row-resize-niQCp040.js → row-resize-DtOS1KG6.js} +41 -32
  46. package/dist/cdn/{server-block-cache-CGoWz-87.js → server-block-cache-DIqb3VZn.js} +4 -0
  47. package/dist/cdn/{src-jcFMkBnN.js → src-25JmJ_7g.js} +4768 -4149
  48. package/dist/cdn/{src-Bklofsad.js → src-kE9B98r6.js} +4796 -4177
  49. package/dist/cdn/svgrid.js +18 -18
  50. package/dist/cdn/svgrid.svelte-external.js +18 -18
  51. package/dist/cdn/{validate-C7Rn_Bns.js → validate-AZoD8BoR.js} +6 -2
  52. package/dist/cell-formatting.d.ts +9 -0
  53. package/dist/cell-formatting.js +52 -1
  54. package/dist/cell-render.js +25 -6
  55. package/dist/clipboard.d.ts +2 -2
  56. package/dist/clipboard.js +72 -23
  57. package/dist/columns.js +7 -2
  58. package/dist/conditional-formatting.d.ts +2 -0
  59. package/dist/conditional-formatting.js +2 -0
  60. package/dist/core.d.ts +22 -6
  61. package/dist/core.js +478 -40
  62. package/dist/editing.js +24 -0
  63. package/dist/export-format.d.ts +8 -0
  64. package/dist/export-format.js +23 -16
  65. package/dist/grid-messages.d.ts +4 -0
  66. package/dist/grid-messages.js +4 -0
  67. package/dist/headless.d.ts +5 -0
  68. package/dist/headless.js +12 -0
  69. package/dist/history.d.ts +21 -0
  70. package/dist/history.js +34 -4
  71. package/dist/index.d.ts +1 -1
  72. package/dist/keyboard-handlers.js +24 -1
  73. package/dist/keyboard.js +4 -0
  74. package/dist/row-drag-touch.d.ts +1 -1
  75. package/dist/row-drag.js +35 -1
  76. package/dist/row-model.d.ts +6 -0
  77. package/dist/row-resize.js +22 -1
  78. package/dist/selection.js +1 -1
  79. package/dist/server-block-cache.d.ts +5 -0
  80. package/dist/server-block-cache.js +8 -0
  81. package/dist/server-data-source.d.ts +35 -3
  82. package/dist/server-data-source.js +11 -2
  83. package/dist/server.d.ts +1 -1
  84. package/dist/sparkline.js +7 -5
  85. package/dist/svgrid-wrapper.types.d.ts +33 -0
  86. package/dist/validate.js +9 -1
  87. package/dist/virtualization/column-virtualizer.d.ts +1 -0
  88. package/dist/virtualization/svelte-virtualizer.svelte.d.ts +1 -0
  89. package/dist/virtualization/svelte-virtualizer.svelte.js +1 -0
  90. package/dist/virtualization/virtualizer.d.ts +3 -0
  91. package/dist/virtualization/virtualizer.js +14 -1
  92. package/package.json +6 -1
  93. package/src/GridMenus.svelte +34 -4
  94. package/src/SvGrid.controller.svelte.ts +236 -57
  95. package/src/SvGrid.css +143 -7
  96. package/src/SvGrid.helpers.ts +2 -4
  97. package/src/SvGrid.svelte +223 -38
  98. package/src/SvGrid.types.ts +77 -4
  99. package/src/SvGridDropdown.svelte +20 -0
  100. package/src/SvModal.svelte +22 -0
  101. package/src/SvModal.test.ts +30 -1
  102. package/src/a11y/dismissable.test.ts +10 -1
  103. package/src/a11y/dismissable.ts +22 -2
  104. package/src/build-api.ts +85 -27
  105. package/src/cell-formatting.test.ts +17 -0
  106. package/src/cell-formatting.ts +49 -1
  107. package/src/cell-render.test.ts +24 -2
  108. package/src/cell-render.ts +24 -8
  109. package/src/clipboard.test.ts +107 -0
  110. package/src/clipboard.ts +62 -23
  111. package/src/columns.test.ts +4 -4
  112. package/src/columns.ts +7 -2
  113. package/src/conditional-formatting.test.ts +8 -0
  114. package/src/conditional-formatting.ts +3 -0
  115. package/src/core.sort.test.ts +86 -0
  116. package/src/core.tick-repair.test.ts +287 -0
  117. package/src/core.ts +478 -40
  118. package/src/editing.test.ts +52 -0
  119. package/src/editing.ts +25 -0
  120. package/src/export-dates.test.ts +114 -0
  121. package/src/export-format.ts +26 -14
  122. package/src/grid-messages.test.ts +7 -0
  123. package/src/grid-messages.ts +10 -0
  124. package/src/headless.ts +24 -0
  125. package/src/history.test.ts +49 -1
  126. package/src/history.ts +48 -2
  127. package/src/index.ts +2 -0
  128. package/src/keyboard-handlers.coverage.test.ts +65 -0
  129. package/src/keyboard-handlers.ts +26 -1
  130. package/src/keyboard.ts +3 -0
  131. package/src/row-drag-touch.ts +2 -2
  132. package/src/row-drag.test.ts +51 -0
  133. package/src/row-drag.ts +35 -2
  134. package/src/row-model.ts +6 -0
  135. package/src/row-resize.ts +24 -1
  136. package/src/selection.ts +1 -1
  137. package/src/server-block-cache.test.ts +27 -0
  138. package/src/server-block-cache.ts +13 -0
  139. package/src/server-data-source.infinite.test.ts +62 -0
  140. package/src/server-data-source.test.ts +19 -0
  141. package/src/server-data-source.ts +48 -4
  142. package/src/server.ts +2 -0
  143. package/src/sparkline.test.ts +7 -0
  144. package/src/sparkline.ts +6 -4
  145. package/src/svgrid-wrapper.types.ts +32 -0
  146. package/src/svgrid.api.test.ts +21 -0
  147. package/src/svgrid.charting.test.ts +12 -4
  148. package/src/svgrid.context-menu.test.ts +12 -0
  149. package/src/svgrid.data-push.svelte.test.ts +94 -0
  150. package/src/svgrid.detail-rows.svelte.test.ts +187 -0
  151. package/src/svgrid.filter-menu-scroll.test.ts +9 -0
  152. package/src/svgrid.gantt-seam.test.ts +1 -1
  153. package/src/svgrid.live-update-paths.svelte.test.ts +186 -0
  154. package/src/svgrid.menu-scroll-close.test.ts +10 -0
  155. package/src/svgrid.row-model-seam.svelte.test.ts +16 -0
  156. package/src/svgrid.row-pinning.test.ts +15 -1
  157. package/src/svgrid.selection-bar-seam.test.ts +1 -1
  158. package/src/svgrid.sticky-groups.svelte.test.ts +145 -0
  159. package/src/svgrid.upsell-license.test.ts +1 -1
  160. package/src/test-setup.ts +12 -0
  161. package/src/transaction.test.ts +58 -0
  162. package/src/validate.ts +7 -1
  163. package/src/virtualization/svelte-virtualizer.svelte.ts +1 -0
  164. package/src/virtualization/virtualizer.test.ts +44 -0
  165. package/src/virtualization/virtualizer.ts +13 -1
  166. package/dist/cdn/GridMenus-DLL-qZeu.js +0 -635
package/dist/server.d.ts CHANGED
@@ -8,6 +8,6 @@
8
8
  * a worker feeding a block cache, or `@svgrid/enterprise`'s own row model,
9
9
  * whose unit tests run without the Svelte compiler.
10
10
  */
11
- export { createServerDataSource, type ServerDataSource, type ServerSelectionRule, type ServerRequest, type ServerResult, type ServerController, type ServerControllerOptions, type ServerState, type ServerSortModel, type ServerFilterModel, type ServerAggregation, type ServerGroupRow, type ServerLeafRow, type ServerMoreRow, type ServerFooterRow, type ServerSkeletonRow, type ServerGrandTotalRow, type ServerPlaceholderRow, type ServerDisplayRow, } from './server-data-source.js';
11
+ export { createServerDataSource, type ServerDataSource, type ServerSelectionRule, type ServerRequest, type ServerResult, type ServerController, type ServerControllerOptions, type ServerState, type ServerSortModel, type ServerFilterModel, type ServerAggFn, type ServerAggregation, type ServerGroupRow, type ServerLeafRow, type ServerMoreRow, type ServerFooterRow, type ServerSkeletonRow, type ServerGrandTotalRow, type ServerPlaceholderRow, type ServerDisplayRow, type ServerDetailRow, } from './server-data-source.js';
12
12
  export { createBlockCache, createRowPlaceholder, rowPlaceholderState, type BlockCache, type BlockCacheOptions, type BlockCacheState, type BlockFetchResult, type BlockState, } from './server-block-cache.js';
13
13
  export { toServerFilterColumns, type GridRowModel, type GridFilterState, type GridRowModelSort, } from './row-model.js';
package/dist/sparkline.js CHANGED
@@ -38,13 +38,15 @@ export function buildSparkline(values, cfg = {}) {
38
38
  const barW = Math.max(1, slot - gap);
39
39
  const mid = height / 2;
40
40
  const h = innerH / 2;
41
- const bars = values.map((v, i) => {
41
+ const bars = [];
42
+ values.forEach((v, i) => {
42
43
  const x = pad + i * slot + (slot - barW) / 2;
44
+ // A win/loss sparkline marks a win up and a loss down; a zero is a
45
+ // blank gap, no mark at all, the way Excel draws one.
43
46
  if (v > 0)
44
- return { x, y: mid - h, w: barW, h, negative: false };
45
- if (v < 0)
46
- return { x, y: mid, w: barW, h, negative: true };
47
- return { x, y: mid - 1, w: barW, h: 2, negative: false };
47
+ bars.push({ x, y: mid - h, w: barW, h, negative: false });
48
+ else if (v < 0)
49
+ bars.push({ x, y: mid, w: barW, h, negative: true });
48
50
  });
49
51
  return { ...base, linePath: '', areaPath: '', bars, lastPoint: null };
50
52
  }
@@ -151,6 +151,12 @@ export type SvGridTransactionResult = {
151
151
  * the component.
152
152
  */
153
153
  export type SvGridApi<TFeatures extends TableFeatures, TData extends RowData> = {
154
+ /**
155
+ * The grid's root element (`.sv-grid-root`), or null before mount and
156
+ * after unmount. For measuring, focusing, or reading the theme the grid
157
+ * is drawn with - the PDF export takes its colours from here.
158
+ */
159
+ getElement(): HTMLElement | null;
154
160
  /** Read a cell value from the underlying data at `rowIndex`. */
155
161
  getCellValue(rowIndex: number, columnId: string): unknown;
156
162
  /** Write a cell value through the column's field. */
@@ -413,6 +419,15 @@ export type SvGridApi<TFeatures extends TableFeatures, TData extends RowData> =
413
419
  getDisplayedRows(): ReadonlyArray<TData>;
414
420
  /** Snapshot of the current data array (pre-pipeline). */
415
421
  getData(): ReadonlyArray<TData>;
422
+ /**
423
+ * The stable id the grid keys a row by: what the `getRowId` prop
424
+ * computed, or the row's position when no `getRowId` is set. Pass a
425
+ * display index (the space `getActiveCell`, `scrollToRow` and the cell
426
+ * methods use) or a row object; returns null for an unknown index or a
427
+ * row that is not in the data. Pair with `selectRows`, `toggleRowSelected`
428
+ * or an `applyTransaction` remove, all of which take these ids.
429
+ */
430
+ getRowId(row: number | TData): string | null;
416
431
  /**
417
432
  * Snapshot of every column the grid currently knows about, in visual
418
433
  * order, with the human-readable header label. Use this when exporting
@@ -560,6 +575,24 @@ export type SvGridApi<TFeatures extends TableFeatures, TData extends RowData> =
560
575
  canRedo(): boolean;
561
576
  /** Wipe both stacks (e.g. after a server save commits the buffer). */
562
577
  clearHistory(): void;
578
+ /**
579
+ * Mark every step recorded from now on with `tag`, until the next call;
580
+ * `undefined` stops the marking. The grid never reads the tag. It is for a
581
+ * consumer that shows one of several data sets through the grid (a
582
+ * workbook's sheets, say) and has to know which one the next Ctrl+Z would
583
+ * change before it lets the grid apply it: it tags the steps with the data
584
+ * set they were made on and asks `peekUndo` first.
585
+ */
586
+ setHistoryTag(tag: unknown): void;
587
+ /** The step the next `undo()` would apply, or null when there is none. A
588
+ * multi-cell action carries one tag, so it reports as one. */
589
+ peekUndo(): {
590
+ tag: unknown;
591
+ } | null;
592
+ /** The step the next `redo()` would apply, or null when there is none. */
593
+ peekRedo(): {
594
+ tag: unknown;
595
+ } | null;
563
596
  /**
564
597
  * The same `GridCommandContext` a registered shortcut handler receives.
565
598
  *
package/dist/validate.js CHANGED
@@ -21,7 +21,15 @@ export function validateGridConfig(input) {
21
21
  // (a key absent from row 0 but present later) does not trip it. A row
22
22
  // model shows placeholder rows before its first block lands; those carry
23
23
  // no data keys at all and say nothing about the columns.
24
- const sample = (input.data ?? []).filter((row) => !rowPlaceholderState(row)).slice(0, FIELD_SAMPLE_ROWS);
24
+ // Stops at the sample size: this runs on every data change, and a filter
25
+ // over all the rows first was O(n) per tick on a live feed.
26
+ const sample = [];
27
+ for (const row of input.data ?? []) {
28
+ if (sample.length >= FIELD_SAMPLE_ROWS)
29
+ break;
30
+ if (!rowPlaceholderState(row))
31
+ sample.push(row);
32
+ }
25
33
  // Under server-side grouping the first rows are group rows, which carry
26
34
  // a key and aggregates and none of the leaf fields; nothing to judge by.
27
35
  if (sample.length && !input.serverGroup) {
@@ -10,6 +10,7 @@ export declare function createColumnVirtualizer(input: {
10
10
  setViewportWidth(viewportWidth: number): void;
11
11
  setHorizontalOffset(scrollOffset: number): void;
12
12
  setOptions(next: Partial<import("./types.js").VirtualizerOptions>): void;
13
+ measure(): void;
13
14
  setScrollOffset(scrollOffset: number): void;
14
15
  setViewportHeight(viewportHeight: number): void;
15
16
  scrollToIndex(index: number): void;
@@ -2,6 +2,7 @@ import type { VirtualizerOptions } from './types.js';
2
2
  export declare function createSvelteVirtualizer(options: VirtualizerOptions): {
3
3
  readonly version: number;
4
4
  setOptions: (next: Partial<VirtualizerOptions>) => void;
5
+ measure: () => void;
5
6
  setScrollOffset: (scrollOffset: number) => void;
6
7
  setViewportHeight: (viewportHeight: number) => void;
7
8
  scrollToIndex: (index: number) => void;
@@ -10,6 +10,7 @@ export function createSvelteVirtualizer(options) {
10
10
  return version;
11
11
  },
12
12
  setOptions: virtualizer.setOptions,
13
+ measure: virtualizer.measure,
13
14
  setScrollOffset: virtualizer.setScrollOffset,
14
15
  setViewportHeight: virtualizer.setViewportHeight,
15
16
  scrollToIndex: virtualizer.scrollToIndex,
@@ -16,6 +16,9 @@ type VirtualizerListener = () => void;
16
16
  export declare function buildPreMeasureItems(count: number, estimateSize: number, viewportHeight: number, overscan: number): Array<VirtualItem>;
17
17
  export declare function createVirtualizer(initial: VirtualizerOptions): {
18
18
  setOptions(next: Partial<VirtualizerOptions>): void;
19
+ /** Drop the cached offsets and re-read every size from `estimateSize`.
20
+ * Call after the sizes a stable size function reports have changed. */
21
+ measure(): void;
19
22
  setScrollOffset(scrollOffset: number): void;
20
23
  setViewportHeight(viewportHeight: number): void;
21
24
  scrollToIndex(index: number): void;
@@ -210,9 +210,22 @@ export function createVirtualizer(initial) {
210
210
  return {
211
211
  setOptions(next) {
212
212
  const merged = { ...options, ...next };
213
- if (sameOptions(options, merged))
213
+ // Passing a size function means "sizes may have changed", even when it is
214
+ // the same reference: the documented variable-height pattern is a stable
215
+ // function reading a mutable map, and keying the cache on identity alone
216
+ // left the offsets and total stale after a row grew (#102).
217
+ const remeasure = typeof next.estimateSize === 'function';
218
+ if (!remeasure && sameOptions(options, merged))
214
219
  return;
215
220
  options = merged;
221
+ if (remeasure)
222
+ offsetCache = null;
223
+ recalc();
224
+ },
225
+ /** Drop the cached offsets and re-read every size from `estimateSize`.
226
+ * Call after the sizes a stable size function reports have changed. */
227
+ measure() {
228
+ offsetCache = null;
216
229
  recalc();
217
230
  },
218
231
  setScrollOffset(scrollOffset) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@svgrid/grid",
3
- "version": "3.0.5",
3
+ "version": "3.0.7",
4
4
  "description": "Svelte 5-native data grid and data table. Headless-first engine with virtual scrolling for 100k+ rows, Excel-style filtering, inline editing, grouping, tree data, pivot, and server-side data. Drop-in <SvGrid> component. TypeScript, SSR-ready.",
5
5
  "author": "jQWidgets <boikom@jqwidgets.com>",
6
6
  "license": "MIT",
@@ -94,6 +94,11 @@
94
94
  "svelte": "./dist/filtering/excel-filters.js",
95
95
  "import": "./dist/filtering/excel-filters.js"
96
96
  },
97
+ "./sparkline": {
98
+ "types": "./dist/sparkline.d.ts",
99
+ "svelte": "./dist/sparkline.js",
100
+ "import": "./dist/sparkline.js"
101
+ },
97
102
  "./shortcuts": {
98
103
  "types": "./dist/shortcut-registry.d.ts",
99
104
  "svelte": "./dist/shortcut-registry.js",
@@ -214,6 +214,19 @@
214
214
  });
215
215
  }
216
216
 
217
+ /**
218
+ * Whether a column's active filter operator is one of the set operators,
219
+ * read at event time from component state: the condition input's focus
220
+ * and blur handlers cannot depend on a template `@const`, because blur
221
+ * also fires while the popover is being torn down, after that const's
222
+ * effect is gone.
223
+ */
224
+ function isSetOperatorFor(colId: string): boolean {
225
+ const column = allColumns.find((c) => c.id === colId);
226
+ const op = filterMenuValues[colId]?.operator ?? defaultOperatorFor(column);
227
+ return op === "in" || op === "notIn";
228
+ }
229
+
217
230
  /** Enter anywhere in the panel means "done" - filtering is already live. */
218
231
  function onFilterPanelKeydown(event: KeyboardEvent) {
219
232
  if (event.key !== "Enter" || event.shiftKey) return;
@@ -286,8 +299,23 @@
286
299
  const saveComment = $derived(ctrl.saveComment);
287
300
  const removeComment = $derived(ctrl.removeComment);
288
301
  const closeCommentEditor = $derived(ctrl.closeCommentEditor);
302
+
303
+ function onContextMenuKeydown(event: KeyboardEvent) {
304
+ // Escape closes the context menu, the way every spreadsheet and desktop
305
+ // app does. The backdrop closes it on a click, but a keyboard user who
306
+ // opened it (Shift+F10, the Menu key) otherwise has no way out, and the
307
+ // menu sits over the sheet swallowing every other key. Handled at the
308
+ // window so it works whatever holds focus while the menu is open.
309
+ if (contextMenuFor && (event.key === "Escape" || event.key === "Esc")) {
310
+ event.preventDefault();
311
+ event.stopPropagation();
312
+ closeContextMenu();
313
+ }
314
+ }
289
315
  </script>
290
316
 
317
+ <svelte:window onkeydown={onContextMenuKeydown} />
318
+
291
319
  {#if tooltip}
292
320
  <!-- Custom hover tooltip. Floats above the grid; positioned by
293
321
  showTooltipFor(). Notes and column tooltips both surface here. -->
@@ -396,10 +424,12 @@
396
424
  : menuActiveOperator === "regex"
397
425
  ? "Pattern..."
398
426
  : "Filter value..."}
399
- onfocus={isSetOp
400
- ? (event) => onSetOpFilterFocus(event.currentTarget as HTMLInputElement, colId)
401
- : undefined}
402
- onblur={isSetOp ? () => closeInSuggest() : undefined}
427
+ onfocus={(event) => {
428
+ if (isSetOperatorFor(colId)) onSetOpFilterFocus(event.currentTarget as HTMLInputElement, colId);
429
+ }}
430
+ onblur={() => {
431
+ if (isSetOperatorFor(colId)) closeInSuggest();
432
+ }}
403
433
  oninput={(event) => {
404
434
  const input = event.currentTarget as HTMLInputElement;
405
435
  updateFilterMenuValue(colId, input.value);