@svgrid/grid 1.1.0 → 1.1.2
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.
- package/dist/FlexRender.svelte +96 -96
- package/dist/GridMenus.svelte +205 -127
- package/dist/SvGrid.controller.svelte.d.ts +44 -1
- package/dist/SvGrid.controller.svelte.js +240 -44
- package/dist/SvGrid.css +325 -22
- package/dist/SvGrid.helpers.test.d.ts +1 -0
- package/dist/SvGrid.helpers.test.js +298 -0
- package/dist/SvGrid.svelte +729 -203
- package/dist/SvGrid.types.d.ts +91 -4
- package/dist/aligned-grids.d.ts +6 -0
- package/dist/aligned-grids.js +84 -0
- package/dist/aligned-grids.test.d.ts +1 -0
- package/dist/aligned-grids.test.js +75 -0
- package/dist/build-api.coverage.test.d.ts +20 -0
- package/dist/build-api.coverage.test.js +505 -0
- package/dist/build-api.js +61 -31
- package/dist/cell-render.test.d.ts +1 -0
- package/dist/cell-render.test.js +338 -0
- package/dist/cell-values.d.ts +1 -1
- package/dist/cell-values.js +7 -7
- package/dist/chart-export.test.d.ts +1 -0
- package/dist/chart-export.test.js +302 -0
- package/dist/chart.coverage.test.d.ts +1 -0
- package/dist/chart.coverage.test.js +748 -0
- package/dist/clipboard.js +88 -24
- package/dist/clipboard.test.d.ts +1 -0
- package/dist/clipboard.test.js +700 -0
- package/dist/collaboration.coverage.test.d.ts +1 -0
- package/dist/collaboration.coverage.test.js +200 -0
- package/dist/column-groups.d.ts +19 -0
- package/dist/column-groups.js +62 -0
- package/dist/column-groups.test.d.ts +1 -0
- package/dist/column-groups.test.js +56 -0
- package/dist/column-types.d.ts +10 -0
- package/dist/column-types.js +63 -0
- package/dist/column-types.test.d.ts +1 -0
- package/dist/column-types.test.js +62 -0
- package/dist/columns.test.d.ts +1 -0
- package/dist/columns.test.js +625 -0
- package/dist/core.d.ts +86 -1
- package/dist/core.js +2 -2
- package/dist/editing.d.ts +7 -0
- package/dist/editing.js +191 -5
- package/dist/editing.test.d.ts +1 -0
- package/dist/editing.test.js +732 -0
- package/dist/editors/cell-editors.coverage.test.d.ts +1 -0
- package/dist/editors/cell-editors.coverage.test.js +139 -0
- package/dist/facet-buckets.test.d.ts +1 -0
- package/dist/facet-buckets.test.js +296 -0
- package/dist/filter-operators.test.d.ts +1 -0
- package/dist/filter-operators.test.js +135 -0
- package/dist/hyperformula-adapter.test.d.ts +1 -0
- package/dist/hyperformula-adapter.test.js +205 -0
- package/dist/index.d.ts +5 -2
- package/dist/index.js +4 -1
- package/dist/keyboard-handlers.coverage.test.d.ts +1 -0
- package/dist/keyboard-handlers.coverage.test.js +495 -0
- package/dist/keyboard-handlers.js +7 -2
- package/dist/menus.js +1 -0
- package/dist/menus.test.d.ts +1 -0
- package/dist/menus.test.js +560 -0
- package/dist/named-views.coverage.test.d.ts +1 -0
- package/dist/named-views.coverage.test.js +180 -0
- package/dist/row-drag.d.ts +49 -0
- package/dist/row-drag.js +221 -0
- package/dist/row-drag.test.d.ts +1 -0
- package/dist/row-drag.test.js +142 -0
- package/dist/row-resize.test.d.ts +1 -0
- package/dist/row-resize.test.js +329 -0
- package/dist/scroll-sync.js +3 -0
- package/dist/scroll-sync.test.d.ts +1 -0
- package/dist/scroll-sync.test.js +290 -0
- package/dist/selection.d.ts +7 -1
- package/dist/selection.js +76 -36
- package/dist/selection.multi-range.test.d.ts +1 -0
- package/dist/selection.multi-range.test.js +55 -0
- package/dist/selection.test.d.ts +1 -0
- package/dist/selection.test.js +647 -0
- package/dist/server-data-source.coverage.test.d.ts +1 -0
- package/dist/server-data-source.coverage.test.js +154 -0
- package/dist/spreadsheet.d.ts +30 -0
- package/dist/spreadsheet.js +48 -0
- package/dist/spreadsheet.test.d.ts +1 -0
- package/dist/spreadsheet.test.js +446 -0
- package/dist/summaries.js +4 -4
- package/dist/sv-grid-scrollbar.js +13 -1
- package/dist/svgrid-wrapper.types.d.ts +19 -0
- package/dist/svgrid.behavior.test.js +20 -0
- package/dist/svgrid.interaction.test.js +31 -0
- package/dist/svgrid.new-features.wrapper.test.js +34 -2
- package/dist/test-setup.js +9 -3
- package/dist/virtualization/scroll-scaling.d.ts +17 -0
- package/dist/virtualization/scroll-scaling.js +35 -0
- package/dist/virtualization/scroll-scaling.test.js +42 -1
- package/package.json +2 -1
- package/src/FlexRender.svelte +96 -96
- package/src/GridMenus.svelte +205 -127
- package/src/SvGrid.controller.svelte.ts +204 -36
- package/src/SvGrid.css +277 -12
- package/src/SvGrid.svelte +727 -205
- package/src/SvGrid.types.ts +85 -4
- package/src/a11y.contract.test.ts +49 -49
- package/src/a11y.test.ts +59 -59
- package/src/a11y.ts +59 -59
- package/src/aligned-grids.test.ts +80 -0
- package/src/aligned-grids.ts +87 -0
- package/src/build-api.ts +43 -23
- package/src/cell-formatting.ts +169 -169
- package/src/cell-values.ts +4 -4
- package/src/clipboard.test.ts +49 -0
- package/src/clipboard.ts +51 -23
- package/src/column-groups.test.ts +59 -0
- package/src/column-groups.ts +80 -0
- package/src/column-types.test.ts +68 -0
- package/src/column-types.ts +82 -0
- package/src/core.performance.test.ts +30 -30
- package/src/core.ts +1077 -999
- package/src/createGrid.svelte.ts +42 -42
- package/src/createGrid.test.ts +10 -10
- package/src/createGridState.svelte.ts +17 -17
- package/src/editing.ts +161 -5
- package/src/flex-render.ts +3 -3
- package/src/index.ts +208 -196
- package/src/keyboard.test.ts +59 -59
- package/src/keyboard.ts +97 -97
- package/src/menus.ts +1 -0
- package/src/merge-objects.ts +48 -48
- package/src/render-component.ts +28 -28
- package/src/row-drag.test.ts +168 -0
- package/src/row-drag.ts +255 -0
- package/src/scroll-sync.ts +2 -0
- package/src/selection.multi-range.test.ts +61 -0
- package/src/selection.ts +71 -37
- package/src/spreadsheet.test.ts +46 -2
- package/src/spreadsheet.ts +58 -0
- package/src/static-functions.ts +11 -11
- package/src/subscribe.ts +38 -38
- package/src/summaries.ts +4 -4
- package/src/svgrid-wrapper.types.ts +412 -393
- package/src/svgrid.features.test.ts +157 -157
- package/src/svgrid.new-features.wrapper.test.ts +2 -2
- package/src/svgrid.wrapper.test.ts +40 -40
- package/src/virtualization/column-virtualizer.test.ts +27 -27
- package/src/virtualization/column-virtualizer.ts +30 -30
- package/src/virtualization/svelte-virtualizer.svelte.ts +26 -26
- package/src/virtualization/types.ts +30 -30
- package/src/virtualization/virtualizer.test.ts +47 -47
- package/src/virtualization/virtualizer.ts +296 -296
package/src/GridMenus.svelte
CHANGED
|
@@ -108,6 +108,7 @@
|
|
|
108
108
|
const operatorMenuPos = $derived(ctrl.operatorMenuPos);
|
|
109
109
|
const chooseColumnsPos = $derived(ctrl.chooseColumnsPos);
|
|
110
110
|
const showColumnFiltersEffective = $derived(ctrl.showColumnFiltersEffective);
|
|
111
|
+
const columnMenuTabsEnabled = $derived(ctrl.props.columnMenuTabs === true);
|
|
111
112
|
const grid = $derived(ctrl.grid);
|
|
112
113
|
const allColumns = $derived(ctrl.allColumns);
|
|
113
114
|
const isColumnPinned = $derived(ctrl.isColumnPinned);
|
|
@@ -123,6 +124,15 @@
|
|
|
123
124
|
const operatorsForColumn = $derived(ctrl.operatorsForColumn);
|
|
124
125
|
const defaultOperatorFor = $derived(ctrl.defaultOperatorFor);
|
|
125
126
|
const operatorLabelFor = $derived(ctrl.operatorLabelFor);
|
|
127
|
+
|
|
128
|
+
// Patch a column's menu filter (used for the optional 2nd condition + join
|
|
129
|
+
// of multi-condition filtering). Merges into the existing entry, creating a
|
|
130
|
+
// base entry from the column's default operator when none exists yet.
|
|
131
|
+
function patchFilter(columnId: string, patch: Record<string, unknown>) {
|
|
132
|
+
const col = allColumns.find((c) => c.id === columnId);
|
|
133
|
+
const cur = ctrl.filterMenuValues[columnId] ?? { operator: defaultOperatorFor(col), value: "" };
|
|
134
|
+
ctrl.filterMenuValues = { ...ctrl.filterMenuValues, [columnId]: { ...cur, ...patch } };
|
|
135
|
+
}
|
|
126
136
|
const isColumnFiltered = $derived(ctrl.isColumnFiltered);
|
|
127
137
|
const closeMenus = $derived(ctrl.closeMenus);
|
|
128
138
|
const autosizeColumn = $derived(ctrl.autosizeColumn);
|
|
@@ -169,15 +179,190 @@
|
|
|
169
179
|
></div>
|
|
170
180
|
{/if}
|
|
171
181
|
|
|
182
|
+
<!-- Shared filter UI: rendered both in the funnel popover and in the column
|
|
183
|
+
menu's Filter tab, so the two never diverge. -->
|
|
184
|
+
{#snippet filterPanelBody(colId: string)}
|
|
185
|
+
{@const menuColumn = allColumns.find((c) => c.id === colId)}
|
|
186
|
+
{@const menuOperatorOptions = operatorsForColumn(menuColumn)}
|
|
187
|
+
{@const menuActiveOperator = filterMenuValues[colId]?.operator ?? defaultOperatorFor(menuColumn)}
|
|
188
|
+
{@const menuInputType = getEditorInputType((menuColumn?.columnDef.editorType ?? "text") as CellEditorType)}
|
|
189
|
+
<div class="sv-grid-menu-filter">
|
|
190
|
+
<div class="sv-grid-menu-filter-head">
|
|
191
|
+
<span class="sv-grid-header-icon">{@render icon("filter")}</span> Filter
|
|
192
|
+
condition
|
|
193
|
+
</div>
|
|
194
|
+
<select
|
|
195
|
+
class="sv-grid-menu-operator-select"
|
|
196
|
+
aria-label="Filter condition"
|
|
197
|
+
value={menuActiveOperator}
|
|
198
|
+
onchange={(event) =>
|
|
199
|
+
updateFilterOperator(colId, (event.currentTarget as HTMLSelectElement).value as FilterOperator)}
|
|
200
|
+
>
|
|
201
|
+
{#each menuOperatorOptions as option (option.value)}
|
|
202
|
+
<option value={option.value}>{operatorLabelFor(option, menuColumn)}</option>
|
|
203
|
+
{/each}
|
|
204
|
+
</select>
|
|
205
|
+
{#if menuActiveOperator !== "isBlank"}
|
|
206
|
+
<input
|
|
207
|
+
class="sv-grid-menu-condition-value"
|
|
208
|
+
type={menuInputType}
|
|
209
|
+
value={filterMenuValues[colId]?.value ?? ""}
|
|
210
|
+
placeholder={menuActiveOperator === "between" ? "From" : "Filter value..."}
|
|
211
|
+
oninput={(event) => updateFilterMenuValue(colId, (event.currentTarget as HTMLInputElement).value)}
|
|
212
|
+
/>
|
|
213
|
+
{#if menuActiveOperator === "between"}
|
|
214
|
+
<input
|
|
215
|
+
class="sv-grid-menu-condition-value"
|
|
216
|
+
type={menuInputType}
|
|
217
|
+
value={filterMenuValues[colId]?.valueTo ?? ""}
|
|
218
|
+
placeholder="To"
|
|
219
|
+
oninput={(event) => updateFilterMenuValueTo(colId, (event.currentTarget as HTMLInputElement).value)}
|
|
220
|
+
/>
|
|
221
|
+
{/if}
|
|
222
|
+
{@const mf = filterMenuValues[colId]}
|
|
223
|
+
{#if mf?.operator2}
|
|
224
|
+
{@const op2 = mf.operator2 ?? defaultOperatorFor(menuColumn)}
|
|
225
|
+
<div class="sv-grid-menu-join" role="radiogroup" aria-label="Combine conditions">
|
|
226
|
+
<button type="button" class:is-on={(mf.join ?? "AND") === "AND"}
|
|
227
|
+
onclick={() => patchFilter(colId, { join: "AND" })}>AND</button>
|
|
228
|
+
<button type="button" class:is-on={mf.join === "OR"}
|
|
229
|
+
onclick={() => patchFilter(colId, { join: "OR" })}>OR</button>
|
|
230
|
+
<button type="button" class="sv-grid-menu-join-x" title="Remove second condition"
|
|
231
|
+
aria-label="Remove second condition"
|
|
232
|
+
onclick={() => patchFilter(colId, { operator2: undefined, value2: undefined, valueTo2: undefined, join: undefined })}>×</button>
|
|
233
|
+
</div>
|
|
234
|
+
<select
|
|
235
|
+
class="sv-grid-menu-operator-select"
|
|
236
|
+
aria-label="Second filter condition"
|
|
237
|
+
value={op2}
|
|
238
|
+
onchange={(event) =>
|
|
239
|
+
patchFilter(colId, { operator2: (event.currentTarget as HTMLSelectElement).value as FilterOperator })}
|
|
240
|
+
>
|
|
241
|
+
{#each menuOperatorOptions as option (option.value)}
|
|
242
|
+
<option value={option.value}>{operatorLabelFor(option, menuColumn)}</option>
|
|
243
|
+
{/each}
|
|
244
|
+
</select>
|
|
245
|
+
{#if op2 !== "isBlank"}
|
|
246
|
+
<input
|
|
247
|
+
class="sv-grid-menu-condition-value"
|
|
248
|
+
type={menuInputType}
|
|
249
|
+
value={mf.value2 ?? ""}
|
|
250
|
+
placeholder={op2 === "between" ? "From" : "Filter value..."}
|
|
251
|
+
oninput={(event) => patchFilter(colId, { value2: (event.currentTarget as HTMLInputElement).value })}
|
|
252
|
+
/>
|
|
253
|
+
{#if op2 === "between"}
|
|
254
|
+
<input
|
|
255
|
+
class="sv-grid-menu-condition-value"
|
|
256
|
+
type={menuInputType}
|
|
257
|
+
value={mf.valueTo2 ?? ""}
|
|
258
|
+
placeholder="To"
|
|
259
|
+
oninput={(event) => patchFilter(colId, { valueTo2: (event.currentTarget as HTMLInputElement).value })}
|
|
260
|
+
/>
|
|
261
|
+
{/if}
|
|
262
|
+
{/if}
|
|
263
|
+
{:else}
|
|
264
|
+
<button type="button" class="sv-grid-menu-add-cond"
|
|
265
|
+
onclick={() => patchFilter(colId, { operator2: defaultOperatorFor(menuColumn), value2: "", join: "AND" })}>
|
|
266
|
+
+ Add condition
|
|
267
|
+
</button>
|
|
268
|
+
{/if}
|
|
269
|
+
{/if}
|
|
270
|
+
<div class="sv-grid-menu-sep"></div>
|
|
271
|
+
<div class="sv-grid-menu-filter-head">Values</div>
|
|
272
|
+
<input
|
|
273
|
+
class="sv-grid-menu-search"
|
|
274
|
+
placeholder="Search values..."
|
|
275
|
+
bind:value={ctrl.columnMenuSearch}
|
|
276
|
+
/>
|
|
277
|
+
<label class="sv-grid-facet sv-grid-facet-all">
|
|
278
|
+
<input type="checkbox" checked={isAllFacetsChecked(colId)} onchange={() => toggleAllFacets(colId)} />
|
|
279
|
+
<span class="sv-grid-facet-label">(Select all)</span>
|
|
280
|
+
</label>
|
|
281
|
+
<div class="sv-grid-facet-list">
|
|
282
|
+
{#each columnMenuVisibleFacets as value (value)}
|
|
283
|
+
<label class="sv-grid-facet">
|
|
284
|
+
<input type="checkbox" checked={isFacetChecked(colId, value)} onchange={() => toggleFacetValue(colId, value)} />
|
|
285
|
+
<span class="sv-grid-facet-label">{value === "" ? "(Blanks)" : value}</span>
|
|
286
|
+
</label>
|
|
287
|
+
{:else}
|
|
288
|
+
<div class="sv-grid-facet-empty">No values</div>
|
|
289
|
+
{/each}
|
|
290
|
+
</div>
|
|
291
|
+
{#if columnMenuFacetValues.length > columnMenuVisibleFacets.length}
|
|
292
|
+
<div class="sv-grid-facet-note">
|
|
293
|
+
Showing {columnMenuVisibleFacets.length} of {columnMenuFacetValues.length}
|
|
294
|
+
</div>
|
|
295
|
+
{/if}
|
|
296
|
+
<div class="sv-grid-menu-actions">
|
|
297
|
+
<button
|
|
298
|
+
type="button"
|
|
299
|
+
class="sv-grid-menu-btn"
|
|
300
|
+
disabled={!isColumnFiltered(colId)}
|
|
301
|
+
onclick={() => clearColumnFilter(colId)}
|
|
302
|
+
>
|
|
303
|
+
Clear filter
|
|
304
|
+
</button>
|
|
305
|
+
<button type="button" class="sv-grid-menu-btn sv-grid-menu-btn-primary" onclick={closeMenus}>
|
|
306
|
+
Done
|
|
307
|
+
</button>
|
|
308
|
+
</div>
|
|
309
|
+
</div>
|
|
310
|
+
{/snippet}
|
|
311
|
+
|
|
172
312
|
{#if columnMenuFor}
|
|
173
313
|
{@const menuColumnId = columnMenuFor}
|
|
174
314
|
{@const menuCol = allColumns.find((c) => c.id === menuColumnId)}
|
|
175
315
|
{@const menuCanSort = menuCol?.getCanSort?.() ?? false}
|
|
316
|
+
{@const menuCanFilter = (menuCol?.columnDef.field != null) && (menuCol?.columnDef.filterable !== false)}
|
|
317
|
+
{@const menuTab = ctrl.columnMenuTab}
|
|
176
318
|
<div
|
|
177
319
|
class="sv-grid-menu sv-grid-column-menu"
|
|
178
320
|
role="menu"
|
|
179
|
-
style={`left: ${columnMenuPos.x}px; top: ${columnMenuPos.y}px;`}
|
|
321
|
+
style={`left: ${columnMenuPos.x}px; top: ${columnMenuPos.y}px; max-height: calc(100vh - ${columnMenuPos.y}px - 12px);`}
|
|
180
322
|
>
|
|
323
|
+
{#if columnMenuTabsEnabled}
|
|
324
|
+
<div class="sv-grid-menu-tabs" role="tablist">
|
|
325
|
+
<button type="button" class="sv-grid-menu-tab" class:is-active={menuTab === "general"}
|
|
326
|
+
role="tab" aria-selected={menuTab === "general"}
|
|
327
|
+
onclick={() => (ctrl.columnMenuTab = "general")}>General</button>
|
|
328
|
+
{#if menuCanFilter && showColumnFiltersEffective}
|
|
329
|
+
<button type="button" class="sv-grid-menu-tab" class:is-active={menuTab === "filter"}
|
|
330
|
+
role="tab" aria-selected={menuTab === "filter"}
|
|
331
|
+
onclick={() => (ctrl.columnMenuTab = "filter")}>Filter</button>
|
|
332
|
+
{/if}
|
|
333
|
+
<button type="button" class="sv-grid-menu-tab" class:is-active={menuTab === "columns"}
|
|
334
|
+
role="tab" aria-selected={menuTab === "columns"}
|
|
335
|
+
onclick={() => (ctrl.columnMenuTab = "columns")}>Columns</button>
|
|
336
|
+
</div>
|
|
337
|
+
{/if}
|
|
338
|
+
{#if columnMenuTabsEnabled && menuTab === "filter" && menuCanFilter && showColumnFiltersEffective}
|
|
339
|
+
{@render filterPanelBody(menuColumnId)}
|
|
340
|
+
{:else if columnMenuTabsEnabled && menuTab === "columns"}
|
|
341
|
+
<div class="sv-grid-menu-filter-head">Visible columns</div>
|
|
342
|
+
<div class="sv-grid-facet-list">
|
|
343
|
+
{#each grid.getAllColumns() as column (column.id)}
|
|
344
|
+
<label class="sv-grid-facet">
|
|
345
|
+
<input
|
|
346
|
+
type="checkbox"
|
|
347
|
+
checked={!ctrl.hiddenColumns[column.id]}
|
|
348
|
+
onchange={(event) => {
|
|
349
|
+
const visible = (event.currentTarget as HTMLInputElement).checked;
|
|
350
|
+
if (visible) {
|
|
351
|
+
const next = { ...ctrl.hiddenColumns };
|
|
352
|
+
delete next[column.id];
|
|
353
|
+
ctrl.hiddenColumns = next;
|
|
354
|
+
} else {
|
|
355
|
+
ctrl.hiddenColumns = { ...ctrl.hiddenColumns, [column.id]: true };
|
|
356
|
+
}
|
|
357
|
+
}}
|
|
358
|
+
/>
|
|
359
|
+
<span class="sv-grid-facet-label"
|
|
360
|
+
>{typeof column.columnDef.header === "string" ? column.columnDef.header : column.id}</span
|
|
361
|
+
>
|
|
362
|
+
</label>
|
|
363
|
+
{/each}
|
|
364
|
+
</div>
|
|
365
|
+
{:else}
|
|
181
366
|
{#if menuCanSort}
|
|
182
367
|
<button
|
|
183
368
|
type="button"
|
|
@@ -290,21 +475,23 @@
|
|
|
290
475
|
</button>
|
|
291
476
|
{/if}
|
|
292
477
|
<div class="sv-grid-menu-sep"></div>
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
<span class="sv-grid-header-icon sv-grid-menu-item-chevron"
|
|
305
|
-
>{@render icon("chevron-down")}</span
|
|
478
|
+
{#if !columnMenuTabsEnabled}
|
|
479
|
+
<!-- Flat menu: reach the column chooser via a submenu (tabbed mode has
|
|
480
|
+
a Columns tab instead). -->
|
|
481
|
+
<button
|
|
482
|
+
type="button"
|
|
483
|
+
class="sv-grid-menu-item"
|
|
484
|
+
class:is-open={chooseColumnsPos !== null}
|
|
485
|
+
role="menuitem"
|
|
486
|
+
aria-haspopup="menu"
|
|
487
|
+
aria-expanded={chooseColumnsPos !== null}
|
|
488
|
+
onclick={(event) => openChooseColumns(event)}
|
|
306
489
|
>
|
|
307
|
-
|
|
490
|
+
<span class="sv-grid-header-icon">{@render icon("columns")}</span>
|
|
491
|
+
Choose columns
|
|
492
|
+
<span class="sv-grid-header-icon sv-grid-menu-item-chevron">{@render icon("chevron-down")}</span>
|
|
493
|
+
</button>
|
|
494
|
+
{/if}
|
|
308
495
|
<button
|
|
309
496
|
type="button"
|
|
310
497
|
class="sv-grid-menu-item"
|
|
@@ -316,126 +503,17 @@
|
|
|
316
503
|
>
|
|
317
504
|
<span class="sv-grid-header-icon">{@render icon("reset")}</span> Reset columns
|
|
318
505
|
</button>
|
|
506
|
+
{/if}
|
|
319
507
|
</div>
|
|
320
508
|
{/if}
|
|
321
509
|
|
|
322
510
|
{#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
511
|
<div
|
|
333
512
|
class="sv-grid-menu sv-grid-filter-menu"
|
|
334
513
|
role="menu"
|
|
335
|
-
style={`left: ${filterMenuPos.x}px; top: ${filterMenuPos.y}px;`}
|
|
514
|
+
style={`left: ${filterMenuPos.x}px; top: ${filterMenuPos.y}px; max-height: calc(100vh - ${filterMenuPos.y}px - 12px);`}
|
|
336
515
|
>
|
|
337
|
-
|
|
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>
|
|
516
|
+
{@render filterPanelBody(filterMenuFor)}
|
|
439
517
|
</div>
|
|
440
518
|
{/if}
|
|
441
519
|
|