@svgrid/grid 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (144) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +137 -39
  3. package/dist/GridFooter.svelte +164 -0
  4. package/dist/GridFooter.svelte.d.ts +29 -0
  5. package/dist/GridMenus.svelte +570 -0
  6. package/dist/GridMenus.svelte.d.ts +31 -0
  7. package/dist/SvGrid.controller.svelte.d.ts +429 -0
  8. package/dist/SvGrid.controller.svelte.js +1732 -0
  9. package/dist/SvGrid.css +1709 -0
  10. package/dist/SvGrid.helpers.d.ts +35 -0
  11. package/dist/SvGrid.helpers.js +160 -0
  12. package/dist/SvGrid.svelte +344 -7043
  13. package/dist/SvGrid.svelte.d.ts +4 -357
  14. package/dist/SvGrid.types.d.ts +436 -0
  15. package/dist/SvGrid.types.js +1 -0
  16. package/dist/SvGridChart.svelte +1060 -23
  17. package/dist/SvGridChart.svelte.d.ts +17 -0
  18. package/dist/build-api.d.ts +5 -0
  19. package/dist/build-api.js +527 -0
  20. package/dist/cell-render.d.ts +15 -0
  21. package/dist/cell-render.js +246 -0
  22. package/dist/cell-values.d.ts +28 -0
  23. package/dist/cell-values.js +89 -0
  24. package/dist/chart.d.ts +370 -3
  25. package/dist/chart.js +1135 -42
  26. package/dist/clipboard.d.ts +15 -0
  27. package/dist/clipboard.js +356 -0
  28. package/dist/columns.d.ts +30 -0
  29. package/dist/columns.js +277 -0
  30. package/dist/core.d.ts +1 -1
  31. package/dist/css.d.ts +3 -0
  32. package/dist/editing.d.ts +24 -0
  33. package/dist/editing.js +343 -0
  34. package/dist/editors/cell-editors.d.ts +1 -1
  35. package/dist/facet-buckets.d.ts +13 -0
  36. package/dist/facet-buckets.js +54 -0
  37. package/dist/features.d.ts +5 -0
  38. package/dist/features.js +30 -0
  39. package/dist/filter-operators.d.ts +16 -0
  40. package/dist/filter-operators.js +69 -0
  41. package/dist/hyperformula-adapter.d.ts +82 -0
  42. package/dist/hyperformula-adapter.js +73 -0
  43. package/dist/index.d.ts +5 -2
  44. package/dist/index.js +5 -2
  45. package/dist/keyboard-handlers.d.ts +7 -0
  46. package/dist/keyboard-handlers.js +197 -0
  47. package/dist/menus.d.ts +40 -0
  48. package/dist/menus.js +389 -0
  49. package/dist/named-views.d.ts +27 -0
  50. package/dist/named-views.js +39 -0
  51. package/dist/row-resize.d.ts +43 -0
  52. package/dist/row-resize.js +158 -0
  53. package/dist/scroll-sync.d.ts +9 -0
  54. package/dist/scroll-sync.js +86 -0
  55. package/dist/selection.d.ts +26 -0
  56. package/dist/selection.js +387 -0
  57. package/dist/spreadsheet.d.ts +80 -0
  58. package/dist/spreadsheet.js +194 -0
  59. package/dist/summaries.d.ts +12 -0
  60. package/dist/summaries.js +65 -0
  61. package/dist/sv-grid-scrollbar.js +7 -1
  62. package/dist/svgrid-wrapper.types.d.ts +12 -1
  63. package/dist/svgrid.comments-autocomplete.test.d.ts +1 -0
  64. package/dist/svgrid.comments-autocomplete.test.js +96 -0
  65. package/dist/svgrid.context-menu.test.d.ts +1 -0
  66. package/dist/svgrid.context-menu.test.js +102 -0
  67. package/dist/svgrid.new-features.wrapper.test.js +30 -4
  68. package/dist/svgrid.wrapper.test.js +27 -1
  69. package/dist/virtualization/column-virtualizer.d.ts +2 -0
  70. package/dist/virtualization/scroll-scaling.d.ts +28 -0
  71. package/dist/virtualization/scroll-scaling.js +64 -0
  72. package/dist/virtualization/scroll-scaling.test.d.ts +1 -0
  73. package/dist/virtualization/scroll-scaling.test.js +86 -0
  74. package/dist/virtualization/svelte-virtualizer.svelte.d.ts +2 -0
  75. package/dist/virtualization/svelte-virtualizer.svelte.js +2 -0
  76. package/dist/virtualization/virtualizer.d.ts +7 -0
  77. package/dist/virtualization/virtualizer.js +30 -0
  78. package/package.json +1 -1
  79. package/src/GridFooter.svelte +164 -0
  80. package/src/GridMenus.svelte +570 -0
  81. package/src/SvGrid.controller.svelte.ts +2195 -0
  82. package/src/SvGrid.css +1747 -0
  83. package/src/SvGrid.helpers.test.ts +415 -0
  84. package/src/SvGrid.helpers.ts +185 -0
  85. package/src/SvGrid.svelte +348 -7043
  86. package/src/SvGrid.types.ts +456 -0
  87. package/src/SvGridChart.svelte +1060 -23
  88. package/src/build-api.coverage.test.ts +532 -0
  89. package/src/build-api.ts +663 -0
  90. package/src/cell-render.test.ts +451 -0
  91. package/src/cell-render.ts +426 -0
  92. package/src/cell-values.ts +114 -0
  93. package/src/chart-export.test.ts +370 -0
  94. package/src/chart.coverage.test.ts +814 -0
  95. package/src/chart.ts +1352 -47
  96. package/src/clipboard.test.ts +731 -0
  97. package/src/clipboard.ts +524 -0
  98. package/src/collaboration.coverage.test.ts +220 -0
  99. package/src/columns.test.ts +702 -0
  100. package/src/columns.ts +419 -0
  101. package/src/core.ts +8 -0
  102. package/src/css.d.ts +3 -0
  103. package/src/editing.test.ts +837 -0
  104. package/src/editing.ts +513 -0
  105. package/src/editors/cell-editors.coverage.test.ts +156 -0
  106. package/src/editors/cell-editors.ts +1 -0
  107. package/src/facet-buckets.test.ts +353 -0
  108. package/src/facet-buckets.ts +67 -0
  109. package/src/features.ts +128 -0
  110. package/src/filter-operators.test.ts +174 -0
  111. package/src/filter-operators.ts +87 -0
  112. package/src/hyperformula-adapter.test.ts +256 -0
  113. package/src/hyperformula-adapter.ts +124 -0
  114. package/src/index.ts +37 -0
  115. package/src/keyboard-handlers.coverage.test.ts +560 -0
  116. package/src/keyboard-handlers.ts +353 -0
  117. package/src/keyboard.ts +97 -97
  118. package/src/menus.test.ts +620 -0
  119. package/src/menus.ts +554 -0
  120. package/src/named-views.coverage.test.ts +210 -0
  121. package/src/named-views.ts +48 -0
  122. package/src/row-resize.test.ts +369 -0
  123. package/src/row-resize.ts +171 -0
  124. package/src/scroll-sync.test.ts +330 -0
  125. package/src/scroll-sync.ts +216 -0
  126. package/src/selection.test.ts +722 -0
  127. package/src/selection.ts +545 -0
  128. package/src/server-data-source.coverage.test.ts +180 -0
  129. package/src/spreadsheet.test.ts +445 -0
  130. package/src/spreadsheet.ts +246 -0
  131. package/src/summaries.ts +204 -0
  132. package/src/sv-grid-scrollbar.ts +21 -2
  133. package/src/svgrid-wrapper.types.ts +12 -1
  134. package/src/svgrid.behavior.test.ts +22 -0
  135. package/src/svgrid.comments-autocomplete.test.ts +112 -0
  136. package/src/svgrid.context-menu.test.ts +126 -0
  137. package/src/svgrid.interaction.test.ts +30 -0
  138. package/src/svgrid.new-features.wrapper.test.ts +65 -4
  139. package/src/svgrid.wrapper.test.ts +27 -1
  140. package/src/test-setup.ts +9 -6
  141. package/src/virtualization/scroll-scaling.test.ts +148 -0
  142. package/src/virtualization/scroll-scaling.ts +121 -0
  143. package/src/virtualization/svelte-virtualizer.svelte.ts +2 -0
  144. package/src/virtualization/virtualizer.ts +26 -0
@@ -0,0 +1,570 @@
1
+ <script lang="ts" generics="TFeatures extends TableFeatures = TableFeatures, TData extends RowData = RowData">
2
+ import {
3
+ applyExcelFilter,
4
+ normalizeForFilter,
5
+ createColumnVirtualizer,
6
+ createCoreRowModel,
7
+ createExpandedRowModel,
8
+ createFilteredRowModel,
9
+ createGroupedRowModel,
10
+ createPaginatedRowModel,
11
+ createSvelteVirtualizer,
12
+ createSortedRowModel,
13
+ createSvGrid,
14
+ filterFns,
15
+ getGridCellA11yProps,
16
+ getGridCellDomId,
17
+ getGridHeaderA11yProps,
18
+ getGridRootA11yProps,
19
+ getGridRowA11yProps,
20
+ parseEditorValue,
21
+ normalizeEditorOptions,
22
+ sortFns,
23
+ tableFeatures,
24
+ rowSortingFeature,
25
+ columnFilteringFeature,
26
+ columnGroupingFeature,
27
+ type CellContext,
28
+ type EditorContext,
29
+ type CellEditorOption,
30
+ type CellEditorType,
31
+ type CellFormatter,
32
+ type CellFormatConfig,
33
+ type Column,
34
+ type ColumnDef,
35
+ type Row,
36
+ type RowData,
37
+ type SvGridApi,
38
+ type TableFeatures,
39
+ } from "./index";
40
+ import "./sv-grid-scrollbar";
41
+ import type { Snippet } from "svelte";
42
+ import { getKeyboardIntent, getNextActiveCell } from "./keyboard";
43
+ import {
44
+ formatNumericWithConfig,
45
+ getDateFormatter,
46
+ resolveDatePattern,
47
+ } from "./cell-formatting";
48
+ import {
49
+ RenderSnippetConfig,
50
+ RenderComponentConfig,
51
+ } from "./render-component";
52
+ import { buildFillPattern } from "./fill-patterns";
53
+ import { buildSparkline, toSparklineValues } from "./sparkline";
54
+ import {
55
+ resolveCellFormat,
56
+ computeColumnStat,
57
+ formatsNeedingStats,
58
+ type ColumnStat,
59
+ type ResolvedCellFormat,
60
+ } from "./conditional-formatting";
61
+ import SvGridDropdown from "./SvGridDropdown.svelte";
62
+ import type {
63
+ Props,
64
+ SelectionPoint,
65
+ SelectionRange,
66
+ CellEditState,
67
+ FilterOperator,
68
+ FilterOption,
69
+ MenuPosition,
70
+ } from "./SvGrid.types";
71
+ import {
72
+ cfTextStyle,
73
+ fmtStat,
74
+ getCellKey,
75
+ resolveClassList,
76
+ toDateInputValue,
77
+ toDateTimeLocalInputValue,
78
+ getEditableInputValue,
79
+ getEditorInputType,
80
+ toValueArray,
81
+ getOptionLabel,
82
+ getOptionColor,
83
+ colorfulChipStyle,
84
+ getEditorClass,
85
+ asDate,
86
+ clampMenuX,
87
+ cssEscape,
88
+ rawToNumber,
89
+ formatFacetNumber,
90
+ formatFacetDate,
91
+ } from "./SvGrid.helpers";
92
+
93
+ import type { SvGridController } from "./SvGrid.controller.svelte";
94
+
95
+ let { ctrl, icon }: { ctrl: SvGridController<TFeatures, TData>; icon: Snippet<[string]> } = $props();
96
+
97
+ // View facade: re-bind the controller's reactive members so the markup
98
+ // (moved verbatim from SvGrid.svelte) stays identical.
99
+ const groupingControlsEnabled = $derived(ctrl.groupingControlsEnabled);
100
+ const filterMenuValues = $derived(ctrl.filterMenuValues);
101
+ const tooltip = $derived(ctrl.tooltip);
102
+ const showTooltipFor = $derived(ctrl.showTooltipFor);
103
+ const columnMenuFor = $derived(ctrl.columnMenuFor);
104
+ const columnMenuPos = $derived(ctrl.columnMenuPos);
105
+ const filterMenuFor = $derived(ctrl.filterMenuFor);
106
+ const filterMenuPos = $derived(ctrl.filterMenuPos);
107
+ const operatorMenuFor = $derived(ctrl.operatorMenuFor);
108
+ const operatorMenuPos = $derived(ctrl.operatorMenuPos);
109
+ const chooseColumnsPos = $derived(ctrl.chooseColumnsPos);
110
+ const showColumnFiltersEffective = $derived(ctrl.showColumnFiltersEffective);
111
+ const grid = $derived(ctrl.grid);
112
+ const allColumns = $derived(ctrl.allColumns);
113
+ const isColumnPinned = $derived(ctrl.isColumnPinned);
114
+ const pinColumnLeft = $derived(ctrl.pinColumnLeft);
115
+ const pinColumnRight = $derived(ctrl.pinColumnRight);
116
+ const unpinColumn = $derived(ctrl.unpinColumn);
117
+ const sortDirectionByColumn = $derived(ctrl.sortDirectionByColumn);
118
+ const groupingColumns = $derived(ctrl.groupingColumns);
119
+ const columnVirtualizationEnabled = $derived(ctrl.columnVirtualizationEnabled);
120
+ const updateFilterOperator = $derived(ctrl.updateFilterOperator);
121
+ const updateFilterMenuValue = $derived(ctrl.updateFilterMenuValue);
122
+ const updateFilterMenuValueTo = $derived(ctrl.updateFilterMenuValueTo);
123
+ const operatorsForColumn = $derived(ctrl.operatorsForColumn);
124
+ const defaultOperatorFor = $derived(ctrl.defaultOperatorFor);
125
+ const operatorLabelFor = $derived(ctrl.operatorLabelFor);
126
+ const isColumnFiltered = $derived(ctrl.isColumnFiltered);
127
+ const closeMenus = $derived(ctrl.closeMenus);
128
+ const autosizeColumn = $derived(ctrl.autosizeColumn);
129
+ const autosizeAllColumns = $derived(ctrl.autosizeAllColumns);
130
+ const resetColumns = $derived(ctrl.resetColumns);
131
+ const openChooseColumns = $derived(ctrl.openChooseColumns);
132
+ const sortColumnFromMenu = $derived(ctrl.sortColumnFromMenu);
133
+ const clearColumnSort = $derived(ctrl.clearColumnSort);
134
+ const groupByColumnFromMenu = $derived(ctrl.groupByColumnFromMenu);
135
+ const clearGroupingFromMenu = $derived(ctrl.clearGroupingFromMenu);
136
+ const columnMenuFacetValues = $derived(ctrl.columnMenuFacetValues);
137
+ const columnMenuVisibleFacets = $derived(ctrl.columnMenuVisibleFacets);
138
+ const isFacetChecked = $derived(ctrl.isFacetChecked);
139
+ const toggleFacetValue = $derived(ctrl.toggleFacetValue);
140
+ const isAllFacetsChecked = $derived(ctrl.isAllFacetsChecked);
141
+ const toggleAllFacets = $derived(ctrl.toggleAllFacets);
142
+ const clearColumnFilter = $derived(ctrl.clearColumnFilter);
143
+ const contextMenuFor = $derived(ctrl.contextMenuFor);
144
+ const contextMenuPos = $derived(ctrl.contextMenuPos);
145
+ const contextMenuItems = $derived(ctrl.contextMenuItems);
146
+ const closeContextMenu = $derived(ctrl.closeContextMenu);
147
+ const commentEditFor = $derived(ctrl.commentEditFor);
148
+ const saveComment = $derived(ctrl.saveComment);
149
+ const removeComment = $derived(ctrl.removeComment);
150
+ const closeCommentEditor = $derived(ctrl.closeCommentEditor);
151
+ </script>
152
+
153
+ {#if tooltip}
154
+ <!-- Custom hover tooltip. Floats above the grid; positioned by
155
+ showTooltipFor(). Notes and column tooltips both surface here. -->
156
+ <div
157
+ class="sv-grid-tooltip"
158
+ class:sv-grid-tooltip-above={!tooltip.below}
159
+ style={`left: ${tooltip.x}px; top: ${tooltip.y}px; ${tooltip.below ? '' : 'transform: translateY(-100%);'}`}
160
+ role="tooltip"
161
+ >{tooltip.text}</div>
162
+ {/if}
163
+
164
+ {#if columnMenuFor || filterMenuFor || operatorMenuFor || chooseColumnsPos}
165
+ <div
166
+ class="sv-grid-menu-backdrop"
167
+ role="presentation"
168
+ onclick={closeMenus}
169
+ ></div>
170
+ {/if}
171
+
172
+ {#if columnMenuFor}
173
+ {@const menuColumnId = columnMenuFor}
174
+ {@const menuCol = allColumns.find((c) => c.id === menuColumnId)}
175
+ {@const menuCanSort = menuCol?.getCanSort?.() ?? false}
176
+ <div
177
+ class="sv-grid-menu sv-grid-column-menu"
178
+ role="menu"
179
+ style={`left: ${columnMenuPos.x}px; top: ${columnMenuPos.y}px;`}
180
+ >
181
+ {#if menuCanSort}
182
+ <button
183
+ type="button"
184
+ class="sv-grid-menu-item"
185
+ role="menuitem"
186
+ onclick={() => sortColumnFromMenu(menuColumnId, false)}
187
+ >
188
+ <span class="sv-grid-header-icon">{@render icon("sort-asc")}</span> Sort
189
+ ascending
190
+ </button>
191
+ <button
192
+ type="button"
193
+ class="sv-grid-menu-item"
194
+ role="menuitem"
195
+ onclick={() => sortColumnFromMenu(menuColumnId, true)}
196
+ >
197
+ <span class="sv-grid-header-icon">{@render icon("sort-desc")}</span> Sort
198
+ descending
199
+ </button>
200
+ <button
201
+ type="button"
202
+ class="sv-grid-menu-item"
203
+ role="menuitem"
204
+ disabled={!sortDirectionByColumn[menuColumnId]}
205
+ onclick={() => clearColumnSort(menuColumnId)}
206
+ >
207
+ <span class="sv-grid-header-icon">{@render icon("x")}</span> Remove sort
208
+ </button>
209
+ {/if}
210
+ {#if !columnVirtualizationEnabled}
211
+ {@const menuPinSide = isColumnPinned(menuColumnId)}
212
+ <div class="sv-grid-menu-sep"></div>
213
+ <button
214
+ type="button"
215
+ class="sv-grid-menu-item"
216
+ role="menuitem"
217
+ disabled={menuPinSide === "left"}
218
+ onclick={() => pinColumnLeft(menuColumnId)}
219
+ >
220
+ <span class="sv-grid-header-icon"
221
+ >{@render icon("op-startsWith")}</span
222
+ > Pin to left
223
+ </button>
224
+ <button
225
+ type="button"
226
+ class="sv-grid-menu-item"
227
+ role="menuitem"
228
+ disabled={menuPinSide === "right"}
229
+ onclick={() => pinColumnRight(menuColumnId)}
230
+ >
231
+ <span class="sv-grid-header-icon"
232
+ >{@render icon("op-greaterThan")}</span
233
+ > Pin to right
234
+ </button>
235
+ <button
236
+ type="button"
237
+ class="sv-grid-menu-item"
238
+ role="menuitem"
239
+ disabled={!menuPinSide}
240
+ onclick={() => unpinColumn(menuColumnId)}
241
+ >
242
+ <span class="sv-grid-header-icon">{@render icon("x")}</span> Unpin column
243
+ </button>
244
+ {/if}
245
+ <div class="sv-grid-menu-sep"></div>
246
+ <button
247
+ type="button"
248
+ class="sv-grid-menu-item"
249
+ role="menuitem"
250
+ onclick={() => {
251
+ autosizeColumn(menuColumnId);
252
+ closeMenus();
253
+ }}
254
+ >
255
+ <span class="sv-grid-header-icon">{@render icon("autosize")}</span> Autosize
256
+ this column
257
+ </button>
258
+ <button
259
+ type="button"
260
+ class="sv-grid-menu-item"
261
+ role="menuitem"
262
+ onclick={() => {
263
+ autosizeAllColumns();
264
+ closeMenus();
265
+ }}
266
+ >
267
+ <span class="sv-grid-header-icon">{@render icon("autosize")}</span> Autosize
268
+ all columns
269
+ </button>
270
+ {#if groupingControlsEnabled}
271
+ <div class="sv-grid-menu-sep"></div>
272
+ <button
273
+ type="button"
274
+ class="sv-grid-menu-item"
275
+ role="menuitem"
276
+ disabled={groupingColumns.includes(menuColumnId)}
277
+ onclick={() => groupByColumnFromMenu(menuColumnId)}
278
+ >
279
+ <span class="sv-grid-header-icon">{@render icon("group")}</span> Group
280
+ by this column
281
+ </button>
282
+ <button
283
+ type="button"
284
+ class="sv-grid-menu-item"
285
+ role="menuitem"
286
+ disabled={!groupingColumns.includes(menuColumnId)}
287
+ onclick={() => clearGroupingFromMenu(menuColumnId)}
288
+ >
289
+ <span class="sv-grid-header-icon">{@render icon("x")}</span> Remove grouping
290
+ </button>
291
+ {/if}
292
+ <div class="sv-grid-menu-sep"></div>
293
+ <button
294
+ type="button"
295
+ class="sv-grid-menu-item"
296
+ class:is-open={chooseColumnsPos !== null}
297
+ role="menuitem"
298
+ aria-haspopup="menu"
299
+ aria-expanded={chooseColumnsPos !== null}
300
+ onclick={(event) => openChooseColumns(event)}
301
+ >
302
+ <span class="sv-grid-header-icon">{@render icon("columns")}</span>
303
+ Choose columns
304
+ <span class="sv-grid-header-icon sv-grid-menu-item-chevron"
305
+ >{@render icon("chevron-down")}</span
306
+ >
307
+ </button>
308
+ <button
309
+ type="button"
310
+ class="sv-grid-menu-item"
311
+ role="menuitem"
312
+ onclick={() => {
313
+ resetColumns();
314
+ closeMenus();
315
+ }}
316
+ >
317
+ <span class="sv-grid-header-icon">{@render icon("reset")}</span> Reset columns
318
+ </button>
319
+ </div>
320
+ {/if}
321
+
322
+ {#if filterMenuFor && showColumnFiltersEffective}
323
+ {@const menuColumnId = filterMenuFor}
324
+ {@const menuColumn = allColumns.find((c) => c.id === menuColumnId)}
325
+ {@const menuOperatorOptions = operatorsForColumn(menuColumn)}
326
+ {@const menuActiveOperator =
327
+ filterMenuValues[menuColumnId]?.operator ??
328
+ defaultOperatorFor(menuColumn)}
329
+ {@const menuInputType = getEditorInputType(
330
+ (menuColumn?.columnDef.editorType ?? "text") as CellEditorType,
331
+ )}
332
+ <div
333
+ class="sv-grid-menu sv-grid-filter-menu"
334
+ role="menu"
335
+ style={`left: ${filterMenuPos.x}px; top: ${filterMenuPos.y}px;`}
336
+ >
337
+ <div class="sv-grid-menu-filter">
338
+ <div class="sv-grid-menu-filter-head">
339
+ <span class="sv-grid-header-icon">{@render icon("filter")}</span> Filter
340
+ condition
341
+ </div>
342
+ <select
343
+ class="sv-grid-menu-operator-select"
344
+ aria-label="Filter condition"
345
+ value={menuActiveOperator}
346
+ onchange={(event) =>
347
+ updateFilterOperator(
348
+ menuColumnId,
349
+ (event.currentTarget as HTMLSelectElement)
350
+ .value as FilterOperator,
351
+ )}
352
+ >
353
+ {#each menuOperatorOptions as option (option.value)}
354
+ <option value={option.value}
355
+ >{operatorLabelFor(option, menuColumn)}</option
356
+ >
357
+ {/each}
358
+ </select>
359
+ {#if menuActiveOperator !== "isBlank"}
360
+ <input
361
+ class="sv-grid-menu-condition-value"
362
+ type={menuInputType}
363
+ value={filterMenuValues[menuColumnId]?.value ?? ""}
364
+ placeholder={menuActiveOperator === "between" ? "From" : "Filter value..."}
365
+ oninput={(event) =>
366
+ updateFilterMenuValue(
367
+ menuColumnId,
368
+ (event.currentTarget as HTMLInputElement).value,
369
+ )}
370
+ />
371
+ {#if menuActiveOperator === "between"}
372
+ <input
373
+ class="sv-grid-menu-condition-value"
374
+ type={menuInputType}
375
+ value={filterMenuValues[menuColumnId]?.valueTo ?? ""}
376
+ placeholder="To"
377
+ oninput={(event) =>
378
+ updateFilterMenuValueTo(
379
+ menuColumnId,
380
+ (event.currentTarget as HTMLInputElement).value,
381
+ )}
382
+ />
383
+ {/if}
384
+ {/if}
385
+ <div class="sv-grid-menu-sep"></div>
386
+ <div class="sv-grid-menu-filter-head">Values</div>
387
+ <input
388
+ class="sv-grid-menu-search"
389
+ placeholder="Search values..."
390
+ bind:value={ctrl.columnMenuSearch}
391
+ />
392
+ <label class="sv-grid-facet sv-grid-facet-all">
393
+ <input
394
+ type="checkbox"
395
+ checked={isAllFacetsChecked(menuColumnId)}
396
+ onchange={() => toggleAllFacets(menuColumnId)}
397
+ />
398
+ <span class="sv-grid-facet-label">(Select all)</span>
399
+ </label>
400
+ <div class="sv-grid-facet-list">
401
+ {#each columnMenuVisibleFacets as value (value)}
402
+ <label class="sv-grid-facet">
403
+ <input
404
+ type="checkbox"
405
+ checked={isFacetChecked(menuColumnId, value)}
406
+ onchange={() => toggleFacetValue(menuColumnId, value)}
407
+ />
408
+ <span class="sv-grid-facet-label"
409
+ >{value === "" ? "(Blanks)" : value}</span
410
+ >
411
+ </label>
412
+ {:else}
413
+ <div class="sv-grid-facet-empty">No values</div>
414
+ {/each}
415
+ </div>
416
+ {#if columnMenuFacetValues.length > columnMenuVisibleFacets.length}
417
+ <div class="sv-grid-facet-note">
418
+ Showing {columnMenuVisibleFacets.length} of {columnMenuFacetValues.length}
419
+ </div>
420
+ {/if}
421
+ <div class="sv-grid-menu-actions">
422
+ <button
423
+ type="button"
424
+ class="sv-grid-menu-btn"
425
+ disabled={!isColumnFiltered(menuColumnId)}
426
+ onclick={() => clearColumnFilter(menuColumnId)}
427
+ >
428
+ Clear filter
429
+ </button>
430
+ <button
431
+ type="button"
432
+ class="sv-grid-menu-btn sv-grid-menu-btn-primary"
433
+ onclick={closeMenus}
434
+ >
435
+ Done
436
+ </button>
437
+ </div>
438
+ </div>
439
+ </div>
440
+ {/if}
441
+
442
+ {#if chooseColumnsPos}
443
+ {@const everyColumn = grid.getAllColumns()}
444
+ <div
445
+ class="sv-grid-menu sv-grid-choose-columns-menu"
446
+ role="menu"
447
+ style={`left: ${chooseColumnsPos.x}px; top: ${chooseColumnsPos.y}px;`}
448
+ >
449
+ <div class="sv-grid-menu-filter-head">Visible columns</div>
450
+ <div class="sv-grid-facet-list">
451
+ {#each everyColumn as column (column.id)}
452
+ <label class="sv-grid-facet">
453
+ <input
454
+ type="checkbox"
455
+ checked={!ctrl.hiddenColumns[column.id]}
456
+ onchange={(event) => {
457
+ const visible = (event.currentTarget as HTMLInputElement)
458
+ .checked;
459
+ if (visible) {
460
+ const next = { ...ctrl.hiddenColumns };
461
+ delete next[column.id];
462
+ ctrl.hiddenColumns = next;
463
+ } else {
464
+ ctrl.hiddenColumns = { ...ctrl.hiddenColumns, [column.id]: true };
465
+ }
466
+ }}
467
+ />
468
+ <span class="sv-grid-facet-label"
469
+ >{typeof column.columnDef.header === "string"
470
+ ? column.columnDef.header
471
+ : column.id}</span
472
+ >
473
+ </label>
474
+ {/each}
475
+ </div>
476
+ </div>
477
+ {/if}
478
+
479
+ {#if operatorMenuFor}
480
+ {@const opColumnId = operatorMenuFor}
481
+ {@const opColumn = allColumns.find((c) => c.id === opColumnId)}
482
+ {@const opOptions = operatorsForColumn(opColumn)}
483
+ {@const opActive =
484
+ filterMenuValues[opColumnId]?.operator ?? defaultOperatorFor(opColumn)}
485
+ <div
486
+ class="sv-grid-menu sv-grid-operator-menu"
487
+ role="menu"
488
+ style={`left: ${operatorMenuPos.x}px; top: ${operatorMenuPos.y}px;`}
489
+ >
490
+ {#each opOptions as option (option.value)}
491
+ <button
492
+ type="button"
493
+ class="sv-grid-menu-item"
494
+ role="menuitemradio"
495
+ aria-checked={opActive === option.value}
496
+ onclick={() => {
497
+ updateFilterOperator(opColumnId, option.value);
498
+ closeMenus();
499
+ }}
500
+ >
501
+ <span class="sv-grid-header-icon"
502
+ >{@render icon(option.iconName)}</span
503
+ >
504
+ {operatorLabelFor(option, opColumn)}
505
+ </button>
506
+ {/each}
507
+ </div>
508
+ {/if}
509
+
510
+ {#if contextMenuFor}
511
+ <div
512
+ class="sv-grid-menu-backdrop"
513
+ role="presentation"
514
+ oncontextmenu={(e) => { e.preventDefault(); closeContextMenu(); }}
515
+ onclick={closeContextMenu}
516
+ ></div>
517
+ <div
518
+ class="sv-grid-menu sv-grid-context-menu"
519
+ role="menu"
520
+ style={`left: ${contextMenuPos.x}px; top: ${contextMenuPos.y}px;`}
521
+ >
522
+ {#each contextMenuItems() as item (item.key)}
523
+ {#if item.separator}
524
+ <div class="sv-grid-menu-sep"></div>
525
+ {:else}
526
+ <button
527
+ type="button"
528
+ class="sv-grid-menu-item"
529
+ role="menuitem"
530
+ disabled={item.disabled}
531
+ onclick={() => { item.run?.(); closeContextMenu(); }}
532
+ >{item.label}</button>
533
+ {/if}
534
+ {/each}
535
+ </div>
536
+ {/if}
537
+
538
+ {#if commentEditFor}
539
+ <div
540
+ class="sv-grid-menu-backdrop"
541
+ role="presentation"
542
+ onclick={closeCommentEditor}
543
+ ></div>
544
+ <div
545
+ class="sv-grid-menu sv-grid-comment-editor"
546
+ role="dialog"
547
+ aria-label="Edit comment"
548
+ style={`left: ${commentEditFor.x}px; top: ${commentEditFor.y}px;`}
549
+ >
550
+ <!-- svelte-ignore a11y_autofocus -->
551
+ <textarea
552
+ class="sv-grid-comment-textarea"
553
+ rows="3"
554
+ placeholder="Add a comment…"
555
+ autofocus
556
+ bind:value={ctrl.commentDraft}
557
+ onkeydown={(e) => {
558
+ e.stopPropagation();
559
+ if (e.key === "Escape") { e.preventDefault(); closeCommentEditor(); }
560
+ if (e.key === "Enter" && (e.ctrlKey || e.metaKey)) { e.preventDefault(); saveComment(); }
561
+ }}
562
+ ></textarea>
563
+ <div class="sv-grid-comment-actions">
564
+ <button type="button" class="sv-grid-comment-remove" onclick={removeComment}>Remove</button>
565
+ <span class="sv-grid-comment-spacer"></span>
566
+ <button type="button" class="sv-grid-comment-cancel" onclick={closeCommentEditor}>Cancel</button>
567
+ <button type="button" class="sv-grid-comment-save" onclick={saveComment}>Save</button>
568
+ </div>
569
+ </div>
570
+ {/if}
@@ -0,0 +1,31 @@
1
+ import { type RowData, type TableFeatures } from "./index";
2
+ import "./sv-grid-scrollbar";
3
+ import type { Snippet } from "svelte";
4
+ import type { SvGridController } from "./SvGrid.controller.svelte";
5
+ declare function $$render<TFeatures extends TableFeatures = TableFeatures, TData extends RowData = RowData>(): {
6
+ props: {
7
+ ctrl: SvGridController<TFeatures, TData>;
8
+ icon: Snippet<[string]>;
9
+ };
10
+ exports: {};
11
+ bindings: "";
12
+ slots: {};
13
+ events: {};
14
+ };
15
+ declare class __sveltets_Render<TFeatures extends TableFeatures = TableFeatures, TData extends RowData = RowData> {
16
+ props(): ReturnType<typeof $$render<TFeatures, TData>>['props'];
17
+ events(): ReturnType<typeof $$render<TFeatures, TData>>['events'];
18
+ slots(): ReturnType<typeof $$render<TFeatures, TData>>['slots'];
19
+ bindings(): "";
20
+ exports(): {};
21
+ }
22
+ interface $$IsomorphicComponent {
23
+ new <TFeatures extends TableFeatures = TableFeatures, TData extends RowData = RowData>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<TFeatures, TData>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<TFeatures, TData>['props']>, ReturnType<__sveltets_Render<TFeatures, TData>['events']>, ReturnType<__sveltets_Render<TFeatures, TData>['slots']>> & {
24
+ $$bindings?: ReturnType<__sveltets_Render<TFeatures, TData>['bindings']>;
25
+ } & ReturnType<__sveltets_Render<TFeatures, TData>['exports']>;
26
+ <TFeatures extends TableFeatures = TableFeatures, TData extends RowData = RowData>(internal: unknown, props: ReturnType<__sveltets_Render<TFeatures, TData>['props']> & {}): ReturnType<__sveltets_Render<TFeatures, TData>['exports']>;
27
+ z_$$bindings?: ReturnType<__sveltets_Render<any, any>['bindings']>;
28
+ }
29
+ declare const GridMenus: $$IsomorphicComponent;
30
+ type GridMenus<TFeatures extends TableFeatures = TableFeatures, TData extends RowData = RowData> = InstanceType<typeof GridMenus<TFeatures, TData>>;
31
+ export default GridMenus;