@svgrid/grid 3.0.3 → 4.0.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.
- package/README.md +5 -4
- package/dist/GridMenus.svelte +44 -2
- package/dist/SvChartMenu.svelte +69 -0
- package/dist/SvChartMenu.svelte.d.ts +11 -0
- package/dist/SvChartPanes.svelte +113 -0
- package/dist/SvChartPanes.svelte.d.ts +20 -0
- package/dist/SvGrid.controller.svelte.d.ts +122 -41
- package/dist/SvGrid.controller.svelte.js +845 -207
- package/dist/SvGrid.css +178 -2
- package/dist/SvGrid.svelte +467 -516
- package/dist/SvGrid.types.d.ts +315 -12
- package/dist/SvGridCellEditor.svelte +17 -0
- package/dist/SvGridChart.svelte +2257 -329
- package/dist/SvGridChart.svelte.d.ts +6 -106
- package/dist/SvGridChart.types.d.ts +338 -0
- package/dist/SvGridChart.types.js +1 -0
- package/dist/SvGridChartBuilder.svelte +323 -0
- package/dist/SvGridChartBuilder.svelte.d.ts +34 -0
- package/dist/SvGridChartPanel.svelte +221 -275
- package/dist/SvGridChartPickers.svelte +417 -0
- package/dist/SvGridChartPickers.svelte.d.ts +70 -0
- package/dist/SvGridChartView.svelte +13 -14
- package/dist/SvModal.svelte +7 -1
- package/dist/SvModal.svelte.d.ts +5 -0
- package/dist/ai.d.ts +40 -8
- package/dist/ai.js +135 -24
- package/dist/aria.d.ts +11 -0
- package/dist/build-api.js +119 -28
- package/dist/cdn/GridMenus-CLI93jke.js +635 -0
- package/dist/cdn/{GridMenus-DhdPF700.js → GridMenus-CwooL3QA.js} +240 -207
- package/dist/cdn/SvChartMenu-Bl6PBbkT.js +58 -0
- package/dist/cdn/SvChartMenu-FBSMINA6.js +59 -0
- package/dist/cdn/{SvDateRangeInput-DMLKmGEc.js → SvDateRangeInput-BeU_TkbQ.js} +15 -14
- package/dist/cdn/{SvDateRangeInput-CaOuMs8O.js → SvDateRangeInput-yX8vzleW.js} +38 -37
- package/dist/cdn/{SvDateTimePicker-sonaH0oh.js → SvDateTimePicker-DQwt4UAs.js} +139 -180
- package/dist/cdn/SvDateTimePicker-vNU6bZ-q.js +775 -0
- package/dist/cdn/{SvGridCellEditor-CjEJMJKc.js → SvGridCellEditor-B1p-vCK5.js} +188 -178
- package/dist/cdn/{SvGridCellEditor-BWnTi2N7.js → SvGridCellEditor-D_0q4xAu.js} +98 -88
- package/dist/cdn/SvGridChart-C3EWAZaM.js +3574 -0
- package/dist/cdn/SvGridChart-DzLkSwCH.js +3572 -0
- package/dist/cdn/SvGridChartBuilder-BE2T1ykB.js +783 -0
- package/dist/cdn/SvGridChartBuilder-CfII62sZ.js +784 -0
- package/dist/cdn/SvGridChartPanel-CCX5_Wgd.js +675 -0
- package/dist/cdn/SvGridChartPanel-xf4sWVTo.js +699 -0
- package/dist/cdn/SvGridChartView-CfuXmY5I.js +48 -0
- package/dist/cdn/SvGridChartView-DYwabQWj.js +47 -0
- package/dist/cdn/SvMenuList-CLN8OuIK.js +452 -0
- package/dist/cdn/SvMenuList-DkGhNKjf.js +451 -0
- package/dist/cdn/SvModal-BAE-pjZX.js +396 -0
- package/dist/cdn/SvModal-CIZWCcad.js +397 -0
- package/dist/cdn/chart-Dz7SqMXH.js +4341 -0
- package/dist/cdn/chart-export-BXqueeWJ.js +135 -0
- package/dist/cdn/chart-export-pdf-DONFUnNY.js +110 -0
- package/dist/cdn/chart-panel-messages-CUbf2R4i.js +1052 -0
- package/dist/cdn/chart-panel-messages-CmNrMdsr.js +1053 -0
- package/dist/cdn/chart-summary-BJW_tg_X.js +138 -0
- package/dist/cdn/chart-trend-CaN9mDEV.js +50 -0
- package/dist/cdn/chart-validate-HcOVFAfJ.js +188 -0
- package/dist/cdn/{column-resize-DsfNXMom.js → column-resize-DpmOLfRp.js} +3 -3
- package/dist/cdn/{date-format-BnnHlqGw.js → date-format-CtquV-p3.js} +583 -603
- package/dist/cdn/{date-format-BNii4zeD.js → date-format-D6KFzU_W.js} +347 -367
- package/dist/cdn/dismissable-DAHetSNk.js +44 -0
- package/dist/cdn/editor-contract-LXgQJAgd.js +22 -0
- package/dist/cdn/focus-trap-BBOQYBma.js +65 -0
- package/dist/cdn/{row-resize-BRcimkUT.js → row-resize-niQCp040.js} +44 -36
- package/dist/cdn/server-block-cache-CGoWz-87.js +237 -0
- package/dist/cdn/{src-D6XvA1Ij.js → src-B6HXdfHY.js} +10448 -10049
- package/dist/cdn/{src-Bugf5XlI.js → src-C6Iowdvs.js} +6908 -6509
- package/dist/cdn/svgrid.js +27 -15
- package/dist/cdn/svgrid.svelte-external.js +27 -15
- package/dist/cdn/validate-CchXzyrX.js +76 -0
- package/dist/chart-axes.d.ts +53 -0
- package/dist/chart-axes.js +351 -0
- package/dist/chart-cartesian.d.ts +88 -0
- package/dist/chart-cartesian.js +1862 -0
- package/dist/chart-decimate.d.ts +51 -0
- package/dist/chart-decimate.js +199 -0
- package/dist/chart-export-pdf.d.ts +47 -0
- package/dist/chart-export-pdf.js +187 -0
- package/dist/chart-export.d.ts +2 -1
- package/dist/chart-export.js +18 -3
- package/dist/chart-financial.d.ts +91 -0
- package/dist/chart-financial.js +175 -0
- package/dist/chart-flow.d.ts +10 -0
- package/dist/chart-flow.js +298 -0
- package/dist/chart-format.d.ts +18 -0
- package/dist/chart-format.js +65 -0
- package/dist/chart-grid.d.ts +8 -0
- package/dist/chart-grid.js +190 -0
- package/dist/chart-hierarchy.d.ts +17 -0
- package/dist/chart-hierarchy.js +146 -0
- package/dist/chart-indicators.d.ts +115 -0
- package/dist/chart-indicators.js +389 -0
- package/dist/chart-messages.d.ts +95 -0
- package/dist/chart-messages.js +92 -0
- package/dist/chart-motion.d.ts +16 -0
- package/dist/chart-motion.js +141 -0
- package/dist/chart-panel-messages.d.ts +265 -0
- package/dist/chart-panel-messages.js +285 -0
- package/dist/chart-pivot.d.ts +87 -0
- package/dist/chart-pivot.js +156 -0
- package/dist/chart-polar.d.ts +25 -0
- package/dist/chart-polar.js +700 -0
- package/dist/chart-samples.d.ts +16 -0
- package/dist/chart-samples.js +153 -0
- package/dist/chart-scale.d.ts +113 -0
- package/dist/chart-scale.js +405 -0
- package/dist/chart-stats.d.ts +111 -0
- package/dist/chart-stats.js +419 -0
- package/dist/chart-stream.d.ts +45 -0
- package/dist/chart-stream.js +91 -0
- package/dist/chart-summary.d.ts +27 -0
- package/dist/chart-summary.js +205 -0
- package/dist/chart-sync.svelte.d.ts +32 -0
- package/dist/chart-sync.svelte.js +23 -0
- package/dist/chart-table.d.ts +35 -0
- package/dist/chart-table.js +165 -0
- package/dist/chart-trend.d.ts +19 -0
- package/dist/chart-trend.js +61 -0
- package/dist/chart-types.d.ts +1456 -0
- package/dist/chart-types.js +6 -0
- package/dist/chart-validate.d.ts +43 -0
- package/dist/chart-validate.js +272 -0
- package/dist/chart-zoom.d.ts +40 -0
- package/dist/chart-zoom.js +145 -0
- package/dist/chart.d.ts +186 -865
- package/dist/chart.js +460 -2204
- package/dist/clipboard.d.ts +1 -0
- package/dist/clipboard.js +137 -18
- package/dist/column-resize.d.ts +3 -0
- package/dist/column-resize.js +4 -1
- package/dist/columns.js +3 -0
- package/dist/command-context.d.ts +19 -0
- package/dist/command-context.js +116 -0
- package/dist/core.d.ts +7 -0
- package/dist/core.js +36 -13
- package/dist/createPopoverSelect.svelte.d.ts +2 -2
- package/dist/editing.d.ts +2 -8
- package/dist/editing.js +272 -33
- package/dist/fill-patterns.d.ts +0 -5
- package/dist/fill-patterns.js +56 -2
- package/dist/grid-icons.d.ts +2 -2
- package/dist/grid-icons.js +2 -2
- package/dist/grid-messages.d.ts +12 -3
- package/dist/grid-messages.js +7 -0
- package/dist/history.d.ts +83 -0
- package/dist/history.js +133 -0
- package/dist/index.d.ts +27 -10
- package/dist/index.js +22 -5
- package/dist/keyboard-handlers.js +88 -31
- package/dist/keyboard.d.ts +55 -0
- package/dist/keyboard.js +132 -0
- package/dist/menus.d.ts +3 -1
- package/dist/menus.js +7 -2
- package/dist/merges.d.ts +97 -0
- package/dist/merges.js +147 -0
- package/dist/row-model.d.ts +133 -0
- package/dist/row-model.js +16 -0
- package/dist/row-resize.d.ts +3 -0
- package/dist/row-resize.js +14 -0
- package/dist/scroll-sync.d.ts +1 -0
- package/dist/scroll-sync.js +24 -0
- package/dist/selection.d.ts +18 -1
- package/dist/selection.js +138 -18
- package/dist/server-block-cache.d.ts +214 -0
- package/dist/server-block-cache.js +531 -0
- package/dist/server-data-source.d.ts +240 -6
- package/dist/server-data-source.js +220 -20
- package/dist/server.d.ts +13 -0
- package/dist/server.js +13 -0
- package/dist/shortcut-registry.d.ts +145 -0
- package/dist/shortcut-registry.js +44 -0
- package/dist/svgrid-wrapper.types.d.ts +213 -22
- package/dist/validate.d.ts +2 -0
- package/dist/validate.js +8 -3
- package/dist/virtualization/virtualizer.js +38 -17
- package/package.json +11 -1
- package/src/GridMenus.svelte +44 -2
- package/src/SvChartMenu.svelte +69 -0
- package/src/SvChartPanes.svelte +113 -0
- package/src/SvChartPanes.test.ts +66 -0
- package/src/SvGrid.controller.svelte.ts +818 -179
- package/src/SvGrid.css +178 -2
- package/src/SvGrid.svelte +467 -516
- package/src/SvGrid.types.ts +293 -11
- package/src/SvGridCellEditor.svelte +17 -0
- package/src/SvGridChart.svelte +2257 -329
- package/src/SvGridChart.test.ts +1419 -1
- package/src/SvGridChart.types.ts +336 -0
- package/src/SvGridChartBuilder.svelte +323 -0
- package/src/SvGridChartPanel.svelte +221 -275
- package/src/SvGridChartPickers.svelte +417 -0
- package/src/SvGridChartView.svelte +13 -14
- package/src/SvModal.svelte +7 -1
- package/src/SvModal.test.ts +9 -0
- package/src/ai.test.ts +57 -2
- package/src/ai.ts +166 -22
- package/src/aria.d.ts +11 -0
- package/src/build-api.coverage.test.ts +184 -0
- package/src/build-api.ts +118 -22
- package/src/chart-axes.test.ts +573 -0
- package/src/chart-axes.ts +342 -0
- package/src/chart-cartesian.ts +1863 -0
- package/src/chart-decimate.test.ts +249 -0
- package/src/chart-decimate.ts +186 -0
- package/src/chart-export-pdf.test.ts +91 -0
- package/src/chart-export-pdf.ts +207 -0
- package/src/chart-export.test.ts +14 -0
- package/src/chart-export.ts +13 -3
- package/src/chart-financial.ts +208 -0
- package/src/chart-flow.ts +286 -0
- package/src/chart-format.ts +67 -0
- package/src/chart-grid.ts +179 -0
- package/src/chart-hierarchy.ts +135 -0
- package/src/chart-indicators.test.ts +443 -0
- package/src/chart-indicators.ts +384 -0
- package/src/chart-messages.test.ts +21 -0
- package/src/chart-messages.ts +184 -0
- package/src/chart-motion.test.ts +71 -0
- package/src/chart-motion.ts +148 -0
- package/src/chart-panel-messages.test.ts +29 -0
- package/src/chart-panel-messages.ts +550 -0
- package/src/chart-pivot.test.ts +54 -0
- package/src/chart-pivot.ts +225 -0
- package/src/chart-polar.ts +674 -0
- package/src/chart-samples.ts +106 -0
- package/src/chart-scale.ts +394 -0
- package/src/chart-series-types.test.ts +714 -0
- package/src/chart-stats.ts +409 -0
- package/src/chart-stream.test.ts +75 -0
- package/src/chart-stream.ts +114 -0
- package/src/chart-summary.test.ts +90 -0
- package/src/chart-summary.ts +197 -0
- package/src/chart-sync.svelte.ts +41 -0
- package/src/chart-table.test.ts +76 -0
- package/src/chart-table.ts +178 -0
- package/src/chart-trend.ts +47 -0
- package/src/chart-types.ts +1309 -0
- package/src/chart-validate.test.ts +100 -0
- package/src/chart-validate.ts +247 -0
- package/src/chart-zoom.test.ts +137 -0
- package/src/chart-zoom.ts +124 -0
- package/src/chart.coverage.test.ts +81 -0
- package/src/chart.test.ts +56 -3
- package/src/chart.ts +557 -2784
- package/src/clipboard.test.ts +151 -0
- package/src/clipboard.ts +145 -16
- package/src/column-resize.ts +7 -1
- package/src/columns.ts +2 -0
- package/src/command-context.test.ts +200 -0
- package/src/command-context.ts +137 -0
- package/src/core.rowmodel-cache.test.ts +51 -0
- package/src/core.ts +40 -12
- package/src/editing.test.ts +281 -3
- package/src/editing.ts +264 -38
- package/src/fill-patterns.test.ts +35 -0
- package/src/fill-patterns.ts +56 -2
- package/src/grid-icons.ts +2 -2
- package/src/grid-messages.ts +21 -3
- package/src/history.test.ts +196 -0
- package/src/history.ts +162 -0
- package/src/icon-seam.test.ts +5 -6
- package/src/index.ts +169 -12
- package/src/keyboard-handlers.coverage.test.ts +126 -6
- package/src/keyboard-handlers.ts +91 -30
- package/src/keyboard-shortcuts.seam.test.ts +200 -0
- package/src/keyboard.test.ts +124 -1
- package/src/keyboard.ts +142 -0
- package/src/menus.test.ts +26 -0
- package/src/menus.ts +10 -3
- package/src/merges.test.ts +112 -0
- package/src/merges.ts +168 -0
- package/src/pivot.grid.test.ts +40 -5
- package/src/row-model.ts +146 -0
- package/src/row-resize.test.ts +44 -0
- package/src/row-resize.ts +17 -0
- package/src/scroll-sync.test.ts +42 -1
- package/src/scroll-sync.ts +25 -0
- package/src/selection.multi-range.test.ts +34 -0
- package/src/selection.test.ts +33 -2
- package/src/selection.ts +143 -21
- package/src/server-block-cache.test.ts +645 -0
- package/src/server-block-cache.ts +677 -0
- package/src/server-data-source.infinite.test.ts +343 -0
- package/src/server-data-source.ts +450 -27
- package/src/server.ts +47 -0
- package/src/shortcut-registry.test.ts +97 -0
- package/src/shortcut-registry.ts +181 -0
- package/src/svgrid-wrapper.types.ts +184 -13
- package/src/svgrid.behavior.test.ts +135 -0
- package/src/svgrid.charting.test.ts +513 -3
- package/src/svgrid.context-menu.test.ts +31 -0
- package/src/svgrid.new-features.wrapper.test.ts +10 -3
- package/src/svgrid.row-model-prop.svelte.test.ts +352 -0
- package/src/svgrid.row-model-seam.svelte.test.ts +289 -0
- package/src/validate.test.ts +10 -0
- package/src/validate.ts +10 -3
- package/src/virtualization/virtualizer.ts +39 -17
- package/dist/SvGroupCell.svelte +0 -141
- package/dist/SvGroupCell.svelte.d.ts +0 -49
- package/dist/SvRowGroupPanel.svelte +0 -186
- package/dist/SvRowGroupPanel.svelte.d.ts +0 -25
- package/dist/cdn/GridMenus-CHOMnW-c.js +0 -602
- package/dist/cdn/SvDateTimePicker-CCbDZNZB.js +0 -816
- package/dist/cdn/SvGridChart-1PMSp2LZ.js +0 -1481
- package/dist/cdn/SvGridChart-D02avhyr.js +0 -1480
- package/dist/cdn/SvGridChartPanel-DJnViOv4.js +0 -834
- package/dist/cdn/SvGridChartPanel-vPTNerFZ.js +0 -810
- package/dist/cdn/SvGridChartView-C--HhdUo.js +0 -56
- package/dist/cdn/SvGridChartView-KyyFG-wY.js +0 -55
- package/dist/cdn/chart-DLg3_zTQ.js +0 -1652
- package/dist/cdn/validate-_CDJzgIo.js +0 -75
- package/dist/server-group-model.d.ts +0 -98
- package/dist/server-group-model.js +0 -263
- package/src/SvGroupCell.svelte +0 -141
- package/src/SvRowGroupPanel.svelte +0 -186
- package/src/server-group-model.test.ts +0 -294
- package/src/server-group-model.ts +0 -370
package/dist/SvGrid.svelte
CHANGED
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
generics="TFeatures extends TableFeatures = TableFeatures, TData extends RowData = RowData"
|
|
4
4
|
>
|
|
5
5
|
import {
|
|
6
|
-
getGridCellA11yProps,
|
|
7
6
|
getGridCellDomId,
|
|
8
7
|
getGridHeaderA11yProps,
|
|
9
8
|
getGridRootA11yProps,
|
|
@@ -22,6 +21,7 @@
|
|
|
22
21
|
RenderComponentConfig,
|
|
23
22
|
} from "./render-component";
|
|
24
23
|
import { buildSparkline, toSparklineValues } from "./sparkline";
|
|
24
|
+
import { mergeDrawAt } from "./merges";
|
|
25
25
|
import { localizeOperatorLabel } from "./filter-operators";
|
|
26
26
|
import { GRID_ICON_GLYPHS, type GridIconName } from "./grid-icons";
|
|
27
27
|
// The whole editor UI - including the lazy SvGridDropdown / SvDateTimePicker
|
|
@@ -387,8 +387,9 @@
|
|
|
387
387
|
);
|
|
388
388
|
|
|
389
389
|
const rowSizePx = (i: number): number => {
|
|
390
|
-
// A height the user dragged
|
|
391
|
-
// where they put it across re-renders
|
|
390
|
+
// A height the user dragged, or set through the api, wins over the
|
|
391
|
+
// declared one, so the row stays where they put it across re-renders
|
|
392
|
+
// and virtualization recycling.
|
|
392
393
|
const dragged = ctrl.rowResizeHeightPx(i);
|
|
393
394
|
if (dragged != null) return dragged;
|
|
394
395
|
const rh = opt.rowHeight;
|
|
@@ -402,10 +403,52 @@
|
|
|
402
403
|
autoRowHeightOn
|
|
403
404
|
? `min-height: ${measuredRowHeightPx(i) ?? rowSizePx(i)}px;`
|
|
404
405
|
: `height: ${rowSizePx(i)}px;`;
|
|
406
|
+
const collapsedColumns = $derived(ctrl.collapsedColumns);
|
|
405
407
|
const columnVirtualizationEnabled = $derived(
|
|
406
408
|
ctrl.columnVirtualizationEnabled,
|
|
407
409
|
);
|
|
408
410
|
const virtualRows = $derived(ctrl.virtualRows);
|
|
411
|
+
// The first body row on screen: where a failed run that started above
|
|
412
|
+
// the window repeats its message.
|
|
413
|
+
const firstRenderedRowIndex = $derived(
|
|
414
|
+
rowVirtualizationEnabled ? (virtualRows[0]?.index ?? 0) : 0,
|
|
415
|
+
);
|
|
416
|
+
const frozenRowCount = $derived(ctrl.frozenRowCount);
|
|
417
|
+
const frozenRowList = $derived(ctrl.frozenRowList);
|
|
418
|
+
// Merged cells. A merge is drawn once per band (the frozen rows, the
|
|
419
|
+
// scrolling body), by the top-left cell of the part the band shows, with
|
|
420
|
+
// its spans clamped to the rendered window: a td never spans into rows
|
|
421
|
+
// the table has not drawn.
|
|
422
|
+
const mergeIndex = $derived(ctrl.mergeIndex);
|
|
423
|
+
const mergeColumnWindow = $derived.by(() => ({
|
|
424
|
+
firstCol: renderedColumns[0]?.item.index ?? 0,
|
|
425
|
+
lastCol: renderedColumns[renderedColumns.length - 1]?.item.index ?? -1,
|
|
426
|
+
}));
|
|
427
|
+
const mergeBodyWindow = $derived.by(() => {
|
|
428
|
+
const cols = mergeColumnWindow;
|
|
429
|
+
if (!rowVirtualizationEnabled) return { firstRow: frozenRowCount, lastRow: allRows.length - 1, ...cols };
|
|
430
|
+
let firstRow = Number.POSITIVE_INFINITY;
|
|
431
|
+
let lastRow = -1;
|
|
432
|
+
for (const item of virtualRows) {
|
|
433
|
+
if (item.index < frozenRowCount) continue;
|
|
434
|
+
if (item.index < firstRow) firstRow = item.index;
|
|
435
|
+
if (item.index > lastRow) lastRow = item.index;
|
|
436
|
+
}
|
|
437
|
+
return { firstRow: Number.isFinite(firstRow) ? firstRow : frozenRowCount, lastRow, ...cols };
|
|
438
|
+
});
|
|
439
|
+
const mergeFrozenWindow = $derived.by(() => ({ firstRow: 0, lastRow: frozenRowCount - 1, ...mergeColumnWindow }));
|
|
440
|
+
/** The width a td spanning `colSpan` rendered columns from `colIndex` takes. */
|
|
441
|
+
function mergedWidth(colIndex: number, colSpan: number, own: number): number {
|
|
442
|
+
if (colSpan <= 1) return own;
|
|
443
|
+
let total = 0;
|
|
444
|
+
for (const rendered of renderedColumns) {
|
|
445
|
+
const i = rendered.item.index;
|
|
446
|
+
if (i >= colIndex && i < colIndex + colSpan) total += rendered.item.size;
|
|
447
|
+
}
|
|
448
|
+
return total || own;
|
|
449
|
+
}
|
|
450
|
+
const frozenBandHeight = $derived(ctrl.frozenBandHeight);
|
|
451
|
+
const frozenRowTop = $derived(ctrl.frozenRowTop);
|
|
409
452
|
const autoRowHeightOn = $derived(ctrl.autoRowHeightOn);
|
|
410
453
|
const measureRowHeight = $derived(ctrl.measureRowHeight);
|
|
411
454
|
const measuredRowHeightPx = $derived(ctrl.measuredRowHeightPx);
|
|
@@ -522,9 +565,8 @@
|
|
|
522
565
|
const toggleSelectAllRows = $derived(ctrl.toggleSelectAllRows);
|
|
523
566
|
const setActiveCell = $derived(ctrl.setActiveCell);
|
|
524
567
|
const scrollActiveCellIntoView = $derived(ctrl.scrollActiveCellIntoView);
|
|
568
|
+
const cellSelectionState = $derived(ctrl.cellSelectionState);
|
|
525
569
|
const getColumnWidth = $derived(ctrl.getColumnWidth);
|
|
526
|
-
const getCellRangeEdges = $derived(ctrl.getCellRangeEdges);
|
|
527
|
-
const fillHandleCell = $derived(ctrl.fillHandleCell);
|
|
528
570
|
const isInFillPreview = $derived(ctrl.isInFillPreview);
|
|
529
571
|
const fillMarqueeEdges = $derived(ctrl.fillMarqueeEdges);
|
|
530
572
|
const startFillDrag = $derived(ctrl.startFillDrag);
|
|
@@ -755,6 +797,19 @@
|
|
|
755
797
|
rotate-on-open both hang off it (SvGrid.css), and an override that
|
|
756
798
|
dropped the class would lose both silently - which is the kind of bug
|
|
757
799
|
that only shows up in someone else's app. -->
|
|
800
|
+
{#snippet chartToggle()}
|
|
801
|
+
<button
|
|
802
|
+
type="button"
|
|
803
|
+
class="sv-grid-toolbar-btn sv-grid-chart-toggle"
|
|
804
|
+
class:is-active={ctrl.chartPanelOpen}
|
|
805
|
+
aria-label={ctrl.chartPanelOpen ? "Close chart" : "Open chart"}
|
|
806
|
+
aria-expanded={ctrl.chartPanelOpen}
|
|
807
|
+
onclick={() => (ctrl.chartPanelOpen = !ctrl.chartPanelOpen)}
|
|
808
|
+
>
|
|
809
|
+
{@render icon("chart")}
|
|
810
|
+
Chart
|
|
811
|
+
</button>
|
|
812
|
+
{/snippet}
|
|
758
813
|
{#snippet icon(name: GridIconName)}
|
|
759
814
|
{@const override = opt.icons?.[name]}
|
|
760
815
|
{#if override}
|
|
@@ -1046,6 +1101,9 @@
|
|
|
1046
1101
|
</div>
|
|
1047
1102
|
</div>
|
|
1048
1103
|
{:else if pivotViewOn}
|
|
1104
|
+
<!-- The Chart panel docks here the way it docks beside the flat grid,
|
|
1105
|
+
and charts the pivot on screen: the root reserves the panel's edge and
|
|
1106
|
+
the pivot bar carries the toggle the toolbar carries in flat mode. -->
|
|
1049
1107
|
<div
|
|
1050
1108
|
class="sv-grid-root sv-grid-pivot-root"
|
|
1051
1109
|
class:sv-grid-root-fill={opt.containerHeight === "100%"}
|
|
@@ -1053,7 +1111,7 @@
|
|
|
1053
1111
|
typeof opt.containerHeight === "string"
|
|
1054
1112
|
? opt.containerHeight
|
|
1055
1113
|
: `${opt.containerHeight ?? 520}px`
|
|
1056
|
-
}; display: flex; flex-direction: column
|
|
1114
|
+
}; display: flex; flex-direction: column; ${chartDockReserveStyle}`}
|
|
1057
1115
|
>
|
|
1058
1116
|
<div class="sv-grid-pivot-bar">
|
|
1059
1117
|
<span class="sv-grid-pivot-badge">{messages.group}</span>
|
|
@@ -1063,6 +1121,9 @@
|
|
|
1063
1121
|
aria-pressed="true"
|
|
1064
1122
|
onclick={() => ctrl.togglePivotMode()}
|
|
1065
1123
|
>{messages.pivotUpsellTitle}</button>
|
|
1124
|
+
{#if ctrl.chartingEnabled}
|
|
1125
|
+
{@render chartToggle()}
|
|
1126
|
+
{/if}
|
|
1066
1127
|
</div>
|
|
1067
1128
|
<div style="flex: 1 1 auto; min-height: 0;">
|
|
1068
1129
|
{#if pivotResult}
|
|
@@ -1081,6 +1142,9 @@
|
|
|
1081
1142
|
</div>
|
|
1082
1143
|
{/if}
|
|
1083
1144
|
</div>
|
|
1145
|
+
{#if ctrl.chartingEnabled && ctrl.chartPanelOpen && ChartPanelView}
|
|
1146
|
+
<ChartPanelView {ctrl} />
|
|
1147
|
+
{/if}
|
|
1084
1148
|
</div>
|
|
1085
1149
|
{:else}
|
|
1086
1150
|
|
|
@@ -1402,10 +1466,386 @@
|
|
|
1402
1466
|
</tr>
|
|
1403
1467
|
{/snippet}
|
|
1404
1468
|
|
|
1469
|
+
<!-- A row whose data has not arrived.
|
|
1470
|
+
|
|
1471
|
+
"loading" keeps the real columns and draws a shimmer bar in each,
|
|
1472
|
+
so the table keeps its shape while blocks stream in - a full-width
|
|
1473
|
+
bar would make the whole grid jump every time one landed. "failed"
|
|
1474
|
+
is the opposite case: there is nothing per-column to say, just one
|
|
1475
|
+
message and a way to try again, so it spans the row like a detail
|
|
1476
|
+
cell does. Neither is selectable or editable; there is nothing
|
|
1477
|
+
there to act on.
|
|
1478
|
+
|
|
1479
|
+
A failed block is a run of failed rows, one per row it claimed,
|
|
1480
|
+
and one message serves the run: the first failed row on screen
|
|
1481
|
+
carries it (the run's first row, or the top of the window when
|
|
1482
|
+
the run started above it) and the rows under it are a plain
|
|
1483
|
+
tinted band. A hundred "Could not load" lines for one block
|
|
1484
|
+
was a wall of red. -->
|
|
1485
|
+
{#snippet placeholderRowMarkup(
|
|
1486
|
+
phRow: Row<TData>,
|
|
1487
|
+
phRowIndex: number,
|
|
1488
|
+
phState: "loading" | "failed",
|
|
1489
|
+
phStyle: string,
|
|
1490
|
+
phContinues: boolean,
|
|
1491
|
+
)}
|
|
1492
|
+
<tr
|
|
1493
|
+
class="sv-grid-row sv-grid-placeholder-row"
|
|
1494
|
+
class:sv-grid-placeholder-failed={phState === "failed"}
|
|
1495
|
+
class:sv-grid-placeholder-failed-cont={phContinues}
|
|
1496
|
+
aria-busy={phState === "loading" ? "true" : undefined}
|
|
1497
|
+
{...getGridRowA11yProps(phRowIndex + 1)}
|
|
1498
|
+
style={phStyle}
|
|
1499
|
+
>
|
|
1500
|
+
{#if phState === "failed"}
|
|
1501
|
+
<td
|
|
1502
|
+
class="sv-grid-cell sv-grid-placeholder-cell"
|
|
1503
|
+
colspan={allColumns.length +
|
|
1504
|
+
(showRowNumbersEffective ? 1 : 0) +
|
|
1505
|
+
(showRowSelectionEffective ? 1 : 0)}
|
|
1506
|
+
>
|
|
1507
|
+
{#if !phContinues}
|
|
1508
|
+
<div class="sv-grid-placeholder-failed-body">
|
|
1509
|
+
<span class="sv-grid-placeholder-error">{messages.rowLoadFailed}</span>
|
|
1510
|
+
{#if opt.onRetryRow}
|
|
1511
|
+
<button
|
|
1512
|
+
type="button"
|
|
1513
|
+
class="sv-grid-placeholder-retry"
|
|
1514
|
+
onclick={() => ctrl.retryRow(phRow)}>{messages.rowLoadRetry}</button
|
|
1515
|
+
>
|
|
1516
|
+
{/if}
|
|
1517
|
+
</div>
|
|
1518
|
+
{/if}
|
|
1519
|
+
</td>
|
|
1520
|
+
{:else}
|
|
1521
|
+
{#if showRowNumbersEffective}
|
|
1522
|
+
<td class="sv-grid-cell sv-grid-rownum-cell"></td>
|
|
1523
|
+
{/if}
|
|
1524
|
+
{#if showRowSelectionEffective}
|
|
1525
|
+
<td class="sv-grid-cell sv-grid-select-cell"></td>
|
|
1526
|
+
{/if}
|
|
1527
|
+
{#each allColumns as col (col.id)}
|
|
1528
|
+
<td class="sv-grid-cell sv-grid-placeholder-cell">
|
|
1529
|
+
<span class="sv-grid-placeholder-skeleton" aria-hidden="true"></span>
|
|
1530
|
+
</td>
|
|
1531
|
+
{/each}
|
|
1532
|
+
{/if}
|
|
1533
|
+
</tr>
|
|
1534
|
+
{/snippet}
|
|
1535
|
+
|
|
1405
1536
|
<!-- A single pinned row (top or bottom). Read-only by design: no
|
|
1406
1537
|
inline editing, no row-selection checkbox, no fill handle.
|
|
1407
1538
|
Position-sticky CSS keeps it anchored to the top of the body or
|
|
1408
1539
|
the bottom of the viewport while the rest scrolls. -->
|
|
1540
|
+
<!--
|
|
1541
|
+
One body row, whatever path renders it: the virtualized window, the
|
|
1542
|
+
plain full-list body, or the frozen rows pinned above the window. The
|
|
1543
|
+
two loops used to carry a copy each and had drifted apart (cell
|
|
1544
|
+
tooltips on one, the fill handle on the other), so a feature landed in
|
|
1545
|
+
one mode and not the other. `rowStyle` is the height the caller knows:
|
|
1546
|
+
the virtualizer's measured size, or the declared one.
|
|
1547
|
+
-->
|
|
1548
|
+
{#snippet bodyRow(row: Row<TData>, rowIndex: number, rowStyle: string)}
|
|
1549
|
+
{@const phState = ctrl.placeholderStateOf(row)}
|
|
1550
|
+
{#if phState}
|
|
1551
|
+
{@const phContinues =
|
|
1552
|
+
phState === "failed" &&
|
|
1553
|
+
rowIndex > firstRenderedRowIndex &&
|
|
1554
|
+
ctrl.placeholderStateOf(allRows[rowIndex - 1]!) === "failed"}
|
|
1555
|
+
{@render placeholderRowMarkup(row, rowIndex, phState, rowStyle, phContinues)}
|
|
1556
|
+
{:else if opt.isDetailRow?.(row.original as TData, rowIndex)}
|
|
1557
|
+
{@render detailRowMarkup(row, rowIndex)}
|
|
1558
|
+
{:else if isGroupRow(row) && !groupColumnMode}
|
|
1559
|
+
<tr
|
|
1560
|
+
class="sv-grid-row sv-grid-group-row"
|
|
1561
|
+
class:sv-grid-row-selected={isRowSelected(row.id)}
|
|
1562
|
+
class:sv-grid-row-frozen={rowIndex < frozenRowCount}
|
|
1563
|
+
class:sv-grid-row-frozen-last={frozenRowCount > 0 && rowIndex === frozenRowCount - 1}
|
|
1564
|
+
style:top={rowIndex < frozenRowCount ? `${frozenRowTop(rowIndex)}px` : undefined}
|
|
1565
|
+
aria-level={row.depth + 1}
|
|
1566
|
+
aria-expanded={row.getIsExpanded?.() ? "true" : "false"}
|
|
1567
|
+
{...getGridRowA11yProps(rowIndex + 1)}
|
|
1568
|
+
class:sv-grid-row-collapsed={ctrl.isRowCollapsed(rowIndex)}
|
|
1569
|
+
style={rowStyle}
|
|
1570
|
+
>
|
|
1571
|
+
<td
|
|
1572
|
+
class="sv-grid-cell sv-grid-group-cell"
|
|
1573
|
+
class:sv-grid-cell-active={activeCell.rowIndex ===
|
|
1574
|
+
rowIndex}
|
|
1575
|
+
colspan={allColumns.length +
|
|
1576
|
+
(showRowNumbersEffective ? 1 : 0) +
|
|
1577
|
+
(showRowSelectionEffective ? 1 : 0)}
|
|
1578
|
+
onclick={() => row.toggleExpanded?.()}
|
|
1579
|
+
>
|
|
1580
|
+
{@render groupRowContent(row)}
|
|
1581
|
+
</td>
|
|
1582
|
+
</tr>
|
|
1583
|
+
{:else}
|
|
1584
|
+
{@const userRowClass = computeRowClass(row, rowIndex)}
|
|
1585
|
+
<tr
|
|
1586
|
+
class={`sv-grid-row ${userRowClass} ${rowDropClass(rowIndex)}`}
|
|
1587
|
+
class:sv-grid-row-selected={isRowSelected(row.id)}
|
|
1588
|
+
class:sv-grid-row-alt={opt.zebraRows &&
|
|
1589
|
+
rowIndex % 2 === 1}
|
|
1590
|
+
class:sv-grid-row-draggable={rowDragManagedEffective}
|
|
1591
|
+
class:sv-grid-group-footer-row={isGroupFooterRow(row)}
|
|
1592
|
+
class:sv-grid-grand-total-row={isGrandTotalRow(row)}
|
|
1593
|
+
class:sv-grid-row-auto-height={autoRowHeightOn}
|
|
1594
|
+
class:sv-grid-row-frozen={rowIndex < frozenRowCount}
|
|
1595
|
+
class:sv-grid-row-frozen-last={frozenRowCount > 0 && rowIndex === frozenRowCount - 1}
|
|
1596
|
+
style:top={rowIndex < frozenRowCount ? `${frozenRowTop(rowIndex)}px` : undefined}
|
|
1597
|
+
{...getGridRowA11yProps(rowIndex + 1)}
|
|
1598
|
+
aria-level={sgAriaLevel(row)}
|
|
1599
|
+
aria-expanded={sgAriaExpanded(row)}
|
|
1600
|
+
{...rowDragAttrs(rowIndex)}
|
|
1601
|
+
class:sv-grid-row-collapsed={ctrl.isRowCollapsed(rowIndex)}
|
|
1602
|
+
style={rowStyle}
|
|
1603
|
+
use:measureRowHeight={rowIndex}
|
|
1604
|
+
>
|
|
1605
|
+
{#if showRowNumbersEffective}
|
|
1606
|
+
<td
|
|
1607
|
+
class="sv-grid-cell sv-grid-row-number-cell"
|
|
1608
|
+
style={`width: ${rowNumberColumnWidth}px; min-width: ${rowNumberColumnWidth}px; max-width: ${rowNumberColumnWidth}px; left: 0;`}
|
|
1609
|
+
>{rowIndex + 1}</td
|
|
1610
|
+
>
|
|
1611
|
+
{/if}
|
|
1612
|
+
{#if showRowSelectionEffective}
|
|
1613
|
+
<td
|
|
1614
|
+
class="sv-grid-cell sv-grid-selection-cell"
|
|
1615
|
+
style={`width: ${selectionColumnWidth}px; min-width: ${selectionColumnWidth}px; max-width: ${selectionColumnWidth}px; left: ${showRowNumbersEffective ? rowNumberColumnWidth : 0}px;`}
|
|
1616
|
+
onclick={() => toggleRowSelectionById(row.id)}
|
|
1617
|
+
>
|
|
1618
|
+
<button
|
|
1619
|
+
type="button"
|
|
1620
|
+
class="sv-grid-checkbox"
|
|
1621
|
+
role="checkbox"
|
|
1622
|
+
aria-checked={isRowSelected(row.id)}
|
|
1623
|
+
aria-label="Select row"
|
|
1624
|
+
onclick={(event) => {
|
|
1625
|
+
event.stopPropagation();
|
|
1626
|
+
toggleRowSelectionById(row.id);
|
|
1627
|
+
}}
|
|
1628
|
+
onkeydown={(event) =>
|
|
1629
|
+
toggleCheckboxWithKeyboard(event, () => {
|
|
1630
|
+
event.stopPropagation();
|
|
1631
|
+
toggleRowSelectionById(row.id);
|
|
1632
|
+
})}
|
|
1633
|
+
></button>
|
|
1634
|
+
</td>
|
|
1635
|
+
{/if}
|
|
1636
|
+
{#if columnVirtualizationEnabled && columnWindowStart > 0}
|
|
1637
|
+
<td
|
|
1638
|
+
class="sv-grid-cell sv-grid-cell-spacer"
|
|
1639
|
+
aria-hidden="true"
|
|
1640
|
+
style={`width: ${columnWindowStart}px; min-width: ${columnWindowStart}px; max-width: ${columnWindowStart}px;`}
|
|
1641
|
+
></td>
|
|
1642
|
+
{/if}
|
|
1643
|
+
{#each renderedColumns as rendered (rendered.column.id)}
|
|
1644
|
+
{@const colIndex = rendered.item.index}
|
|
1645
|
+
{@const draw = mergeIndex
|
|
1646
|
+
? mergeDrawAt(mergeIndex, rowIndex, colIndex, rowIndex < frozenRowCount ? mergeFrozenWindow : mergeBodyWindow)
|
|
1647
|
+
: null}
|
|
1648
|
+
{#if draw?.kind !== "skip"}
|
|
1649
|
+
{@const cellRow = draw?.kind === "continuation" ? (allRows[draw.merge.rowIndex] ?? row) : row}
|
|
1650
|
+
{@const cellColumn = draw?.kind === "continuation" ? (allColumns[draw.merge.colIndex] ?? rendered.column) : rendered.column}
|
|
1651
|
+
{@const baseValue = getColumnBaseValue(
|
|
1652
|
+
cellRow,
|
|
1653
|
+
cellColumn,
|
|
1654
|
+
)}
|
|
1655
|
+
{@const cellValue = getCellDisplayValue(
|
|
1656
|
+
cellRow.id,
|
|
1657
|
+
cellColumn.id,
|
|
1658
|
+
baseValue,
|
|
1659
|
+
)}
|
|
1660
|
+
{@const isEditing =
|
|
1661
|
+
ctrl.editingCell?.rowId === cellRow.id &&
|
|
1662
|
+
ctrl.editingCell?.columnId === cellColumn.id}
|
|
1663
|
+
{@const inRowEdit =
|
|
1664
|
+
!!fullRowEdit &&
|
|
1665
|
+
fullRowEdit.rowId === cellRow.id &&
|
|
1666
|
+
cellColumn.id in fullRowEdit.draft}
|
|
1667
|
+
{@const cellSel = cellSelectionState(rowIndex, colIndex)}
|
|
1668
|
+
{@const fillEdges = fillMarqueeEdges(rowIndex, colIndex)}
|
|
1669
|
+
{@const userCellClass = computeCellClass(
|
|
1670
|
+
cellRow,
|
|
1671
|
+
cellColumn,
|
|
1672
|
+
)}
|
|
1673
|
+
{@const cellTooltip = computeCellTooltip(
|
|
1674
|
+
cellRow,
|
|
1675
|
+
cellColumn,
|
|
1676
|
+
)}
|
|
1677
|
+
{@const cellValidity = computeCellValidity(
|
|
1678
|
+
cellRow,
|
|
1679
|
+
cellColumn,
|
|
1680
|
+
)}
|
|
1681
|
+
{@const cellNote = computeCellNote(
|
|
1682
|
+
cellRow,
|
|
1683
|
+
cellColumn,
|
|
1684
|
+
)}
|
|
1685
|
+
{@const tdWidth = draw ? mergedWidth(colIndex, draw.colSpan, rendered.item.size) : rendered.item.size}
|
|
1686
|
+
<td
|
|
1687
|
+
rowspan={draw && draw.rowSpan > 1 ? draw.rowSpan : undefined}
|
|
1688
|
+
colspan={draw && draw.colSpan > 1 ? draw.colSpan : undefined}
|
|
1689
|
+
data-merge-origin={draw ? `${draw.merge.rowIndex}:${draw.merge.colIndex}` : undefined}
|
|
1690
|
+
class:sv-grid-cell-merged={!!draw}
|
|
1691
|
+
class={`sv-grid-cell ${userCellClass}`}
|
|
1692
|
+
class:sv-grid-cell-editing={isEditing || inRowEdit}
|
|
1693
|
+
class:sv-grid-cell-collapsed={!!collapsedColumns[rendered.column.id]}
|
|
1694
|
+
class:sv-grid-cell-active={!!cellSel?.active}
|
|
1695
|
+
class:sv-grid-cell-has-fill-handle={!!cellSel?.fillHandle}
|
|
1696
|
+
class:sv-grid-cell-cf={hasConditionalFormats}
|
|
1697
|
+
class:sv-grid-cell-invalid={cellValidity.invalid}
|
|
1698
|
+
class:sv-grid-cell-has-note={cellNote != null}
|
|
1699
|
+
aria-invalid={cellValidity.invalid ? "true" : undefined}
|
|
1700
|
+
data-svgrid-row={rowIndex}
|
|
1701
|
+
data-svgrid-col={colIndex}
|
|
1702
|
+
data-col-id={rendered.column.id}
|
|
1703
|
+
data-align={getColumnAlign(rendered.column)}
|
|
1704
|
+
data-pinned={isColumnPinned(rendered.column.id) ??
|
|
1705
|
+
undefined}
|
|
1706
|
+
data-selected-range={cellSel?.edges ? "true" : undefined}
|
|
1707
|
+
data-range-top={cellSel?.edges?.top ? "true" : undefined}
|
|
1708
|
+
data-range-bottom={cellSel?.edges?.bottom
|
|
1709
|
+
? "true"
|
|
1710
|
+
: undefined}
|
|
1711
|
+
data-range-left={cellSel?.edges?.left
|
|
1712
|
+
? "true"
|
|
1713
|
+
: undefined}
|
|
1714
|
+
data-range-right={cellSel?.edges?.right
|
|
1715
|
+
? "true"
|
|
1716
|
+
: undefined}
|
|
1717
|
+
data-fill-preview={isInFillPreview(rowIndex, colIndex)
|
|
1718
|
+
? "true"
|
|
1719
|
+
: undefined}
|
|
1720
|
+
data-fill-top={fillEdges?.top ? "true" : undefined}
|
|
1721
|
+
data-fill-bottom={fillEdges?.bottom ? "true" : undefined}
|
|
1722
|
+
data-fill-left={fillEdges?.left ? "true" : undefined}
|
|
1723
|
+
data-fill-right={fillEdges?.right ? "true" : undefined}
|
|
1724
|
+
style={`width: ${tdWidth}px; min-width: ${tdWidth}px; max-width: ${tdWidth}px; ${cellPinStyle(rendered.column.id)}`}
|
|
1725
|
+
onpointerdown={(event) =>
|
|
1726
|
+
onCellPointerDown(rowIndex, colIndex, event)}
|
|
1727
|
+
onpointerenter={(event) => {
|
|
1728
|
+
onCellPointerEnter(rowIndex, colIndex);
|
|
1729
|
+
// The column tooltip fires on whole-cell hover; a
|
|
1730
|
+
// per-cell note waits for its corner below. A
|
|
1731
|
+
// validation message wins over the column's tooltip.
|
|
1732
|
+
const tip =
|
|
1733
|
+
cellValidity.invalid && cellValidity.message
|
|
1734
|
+
? cellValidity.message
|
|
1735
|
+
: cellTooltip;
|
|
1736
|
+
if (tip)
|
|
1737
|
+
showTooltipFor(
|
|
1738
|
+
event.currentTarget as HTMLElement,
|
|
1739
|
+
tip,
|
|
1740
|
+
);
|
|
1741
|
+
}}
|
|
1742
|
+
onpointerleave={hideTooltip}
|
|
1743
|
+
ondblclick={() =>
|
|
1744
|
+
emitCellDoubleClick(rowIndex, colIndex)}
|
|
1745
|
+
onclick={() => onCellClick(rowIndex, colIndex)}
|
|
1746
|
+
oncontextmenu={(event) =>
|
|
1747
|
+
openContextMenu(
|
|
1748
|
+
event,
|
|
1749
|
+
rowIndex,
|
|
1750
|
+
colIndex,
|
|
1751
|
+
rendered.column.id,
|
|
1752
|
+
)}
|
|
1753
|
+
use:cellFlashAction={{
|
|
1754
|
+
rowId: cellRow.id,
|
|
1755
|
+
value: cellValue,
|
|
1756
|
+
active: !!cellColumn.columnDef.cellFlash,
|
|
1757
|
+
className: flashClassFor(
|
|
1758
|
+
cellColumn.columnDef.cellFlash,
|
|
1759
|
+
),
|
|
1760
|
+
}}
|
|
1761
|
+
role="gridcell"
|
|
1762
|
+
id={getGridCellDomId(ctrl.gridDomId, rowIndex, colIndex)}
|
|
1763
|
+
aria-colindex={colIndex + 1}
|
|
1764
|
+
aria-rowindex={rowIndex + 1}
|
|
1765
|
+
aria-selected={isRowSelected(row.id)}
|
|
1766
|
+
>
|
|
1767
|
+
{#if inRowEdit || isEditing}
|
|
1768
|
+
<!-- The editing cell stays empty until the lazy
|
|
1769
|
+
editor chunk lands, exactly as it already did
|
|
1770
|
+
for the dropdown / date editors. Falling back
|
|
1771
|
+
to the read-only value here would flash stale
|
|
1772
|
+
content into a cell the user is editing. -->
|
|
1773
|
+
{#if CellEditor}
|
|
1774
|
+
<CellEditor {ctrl} column={cellColumn} row={cellRow} fullRow={inRowEdit} />
|
|
1775
|
+
{/if}
|
|
1776
|
+
{:else}
|
|
1777
|
+
{#if plainCellBody}
|
|
1778
|
+
{@render cellBody(cellRow, cellColumn, cellValue)}
|
|
1779
|
+
{:else}
|
|
1780
|
+
{@render cellBodyWithFormat(
|
|
1781
|
+
cellRow,
|
|
1782
|
+
cellColumn,
|
|
1783
|
+
cellValue,
|
|
1784
|
+
)}
|
|
1785
|
+
{/if}
|
|
1786
|
+
{/if}
|
|
1787
|
+
{#if !isEditing && cellSel?.fillHandle}
|
|
1788
|
+
<!-- Excel-style fill handle: drag down/right to
|
|
1789
|
+
extend the selection and pattern-fill the new
|
|
1790
|
+
cells on release. Rendered inside the bottom-
|
|
1791
|
+
right cell of the selection range (or active
|
|
1792
|
+
cell if there's no range). -->
|
|
1793
|
+
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
1794
|
+
<div
|
|
1795
|
+
class="sv-grid-fill-handle"
|
|
1796
|
+
role="button"
|
|
1797
|
+
aria-label="Fill handle"
|
|
1798
|
+
tabindex={-1}
|
|
1799
|
+
onpointerdown={(event) =>
|
|
1800
|
+
startFillDrag(event, rowIndex, colIndex)}
|
|
1801
|
+
ondblclick={(event) => {
|
|
1802
|
+
// Not the cell's double-click: this fills
|
|
1803
|
+
// down as far as the neighbour column goes.
|
|
1804
|
+
event.stopPropagation();
|
|
1805
|
+
event.preventDefault();
|
|
1806
|
+
ctrl.fillDownToNeighbour();
|
|
1807
|
+
}}
|
|
1808
|
+
></div>
|
|
1809
|
+
{/if}
|
|
1810
|
+
{#if cellValidity.invalid && cellValidity.message}
|
|
1811
|
+
<!-- The validation message, for assistive tech: the
|
|
1812
|
+
tooltip above is mouse-only, and unlike a title
|
|
1813
|
+
a visually-hidden span adds no second native
|
|
1814
|
+
tooltip competing with the custom one. -->
|
|
1815
|
+
<span class="sv-grid-sr-only"
|
|
1816
|
+
>{cellValidity.message}</span
|
|
1817
|
+
>
|
|
1818
|
+
{/if}
|
|
1819
|
+
{#if cellNote != null && !isEditing}
|
|
1820
|
+
<span
|
|
1821
|
+
class="sv-grid-cell-note-corner"
|
|
1822
|
+
aria-label="Note"
|
|
1823
|
+
onpointerenter={(event) => {
|
|
1824
|
+
event.stopPropagation();
|
|
1825
|
+
showTooltipFor(
|
|
1826
|
+
event.currentTarget as HTMLElement,
|
|
1827
|
+
cellNote,
|
|
1828
|
+
);
|
|
1829
|
+
}}
|
|
1830
|
+
onpointerleave={(event) => {
|
|
1831
|
+
event.stopPropagation();
|
|
1832
|
+
hideTooltip();
|
|
1833
|
+
}}
|
|
1834
|
+
></span>
|
|
1835
|
+
{/if}
|
|
1836
|
+
</td>
|
|
1837
|
+
{/if}
|
|
1838
|
+
{/each}
|
|
1839
|
+
{#if columnVirtualizationEnabled && columnWindowRightSpacer > 0}
|
|
1840
|
+
<td
|
|
1841
|
+
class="sv-grid-cell sv-grid-cell-spacer"
|
|
1842
|
+
aria-hidden="true"
|
|
1843
|
+
style={`width: ${columnWindowRightSpacer}px; min-width: ${columnWindowRightSpacer}px; max-width: ${columnWindowRightSpacer}px;`}
|
|
1844
|
+
></td>
|
|
1845
|
+
{/if}
|
|
1846
|
+
</tr>
|
|
1847
|
+
{/if}
|
|
1848
|
+
{/snippet}
|
|
1409
1849
|
{#snippet pinnedRowBody(
|
|
1410
1850
|
rowData: TData,
|
|
1411
1851
|
where: "top" | "bottom",
|
|
@@ -1466,7 +1906,7 @@
|
|
|
1466
1906
|
style={chartDockReserveStyle}
|
|
1467
1907
|
data-move-grab={ctrl.moveGrabHover || ctrl.moveDrag ? "true" : undefined}
|
|
1468
1908
|
data-selbar={
|
|
1469
|
-
ctrl.
|
|
1909
|
+
ctrl.selectionBarVisible
|
|
1470
1910
|
? (getSelectionBarView() ? ctrl.selectionBarPosition : `upsell-${ctrl.selectionBarPosition}`)
|
|
1471
1911
|
: undefined
|
|
1472
1912
|
}
|
|
@@ -1475,7 +1915,8 @@
|
|
|
1475
1915
|
// No gutter column on most grids, so fall back to the first body cell -
|
|
1476
1916
|
// otherwise `rowResize` would be a prop that silently does nothing.
|
|
1477
1917
|
anchor: "row",
|
|
1478
|
-
onResize: (index, height) => ctrl.
|
|
1918
|
+
onResize: (index, height) => ctrl.resizeRowByUser(index, height),
|
|
1919
|
+
onAutosize: (index) => ctrl.resizeRowByUser(index, null),
|
|
1479
1920
|
}}
|
|
1480
1921
|
use:lazyColumnResize={{
|
|
1481
1922
|
disabled: !columnResizeEnabled,
|
|
@@ -1483,12 +1924,13 @@
|
|
|
1483
1924
|
onResize: (columnId, width) => {
|
|
1484
1925
|
ctrl.columnWidths = { ...ctrl.columnWidths, [columnId]: width };
|
|
1485
1926
|
},
|
|
1927
|
+
onResizeEnd: (columnId, width, startWidth) => ctrl.resizeColumnByUser(columnId, width, startWidth),
|
|
1486
1928
|
label: (columnId) => {
|
|
1487
1929
|
const col = ctrl.findColumnById(columnId);
|
|
1488
1930
|
return col ? toolPanelHeaderLabel(col) : columnId;
|
|
1489
1931
|
},
|
|
1490
1932
|
canResize: (columnId) => ctrl.columnResizable(columnId),
|
|
1491
|
-
onAutosize: (columnId) => ctrl.
|
|
1933
|
+
onAutosize: (columnId) => ctrl.autosizeColumnByUser(columnId),
|
|
1492
1934
|
}}
|
|
1493
1935
|
>
|
|
1494
1936
|
{#if showGlobalFilterEffective}
|
|
@@ -1535,17 +1977,7 @@
|
|
|
1535
1977
|
</button>
|
|
1536
1978
|
{/if}
|
|
1537
1979
|
{#if ctrl.chartingEnabled}
|
|
1538
|
-
|
|
1539
|
-
type="button"
|
|
1540
|
-
class="sv-grid-toolbar-btn sv-grid-chart-toggle"
|
|
1541
|
-
class:is-active={ctrl.chartPanelOpen}
|
|
1542
|
-
aria-label={ctrl.chartPanelOpen ? "Close chart" : "Open chart"}
|
|
1543
|
-
aria-expanded={ctrl.chartPanelOpen}
|
|
1544
|
-
onclick={() => (ctrl.chartPanelOpen = !ctrl.chartPanelOpen)}
|
|
1545
|
-
>
|
|
1546
|
-
{@render icon("chart")}
|
|
1547
|
-
Chart
|
|
1548
|
-
</button>
|
|
1980
|
+
{@render chartToggle()}
|
|
1549
1981
|
{/if}
|
|
1550
1982
|
</div>
|
|
1551
1983
|
{/if}
|
|
@@ -1560,7 +1992,7 @@
|
|
|
1560
1992
|
typeof opt.containerHeight === "string"
|
|
1561
1993
|
? opt.containerHeight
|
|
1562
1994
|
: `${opt.containerHeight ?? 520}px`
|
|
1563
|
-
}; --sg-thead-h: ${headerHeight}px; --sg-pinned-row-h: ${typeof opt.rowHeight === "number" ? opt.rowHeight : 30}px;`}
|
|
1995
|
+
}; --sg-thead-h: ${headerHeight}px; --sg-frozen-h: ${frozenBandHeight}px; --sg-pinned-row-h: ${typeof opt.rowHeight === "number" ? opt.rowHeight : 30}px;`}
|
|
1564
1996
|
>
|
|
1565
1997
|
<div
|
|
1566
1998
|
class="sv-grid-container sv-grid-container-custom-scrollbars"
|
|
@@ -1723,6 +2155,7 @@
|
|
|
1723
2155
|
)}
|
|
1724
2156
|
<th
|
|
1725
2157
|
class="sv-grid-column"
|
|
2158
|
+
class:sv-grid-column-collapsed={!!collapsedColumns[header.column.id]}
|
|
1726
2159
|
class:is-drag-target-before={colDropOnId ===
|
|
1727
2160
|
header.column.id && colDropSide === "before"}
|
|
1728
2161
|
class:is-drag-target-after={colDropOnId ===
|
|
@@ -2180,6 +2613,9 @@
|
|
|
2180
2613
|
</td>
|
|
2181
2614
|
</tr>
|
|
2182
2615
|
{:else if rowVirtualizationEnabled}
|
|
2616
|
+
{#each frozenRowList as row, rowIndex (row.id)}
|
|
2617
|
+
{@render bodyRow(row, rowIndex, rowStyleFor(rowIndex))}
|
|
2618
|
+
{/each}
|
|
2183
2619
|
{#if rowTopSpacer > 0}
|
|
2184
2620
|
<tr class="sv-grid-row sv-grid-row-spacer" aria-hidden="true">
|
|
2185
2621
|
<td
|
|
@@ -2191,256 +2627,17 @@
|
|
|
2191
2627
|
></td>
|
|
2192
2628
|
</tr>
|
|
2193
2629
|
{/if}
|
|
2630
|
+
<!-- The virtualizer counts every row, frozen ones included, so its
|
|
2631
|
+
offsets and sizes stay in row-index space; the frozen rows are
|
|
2632
|
+
rendered in the band above and SKIPPED here. Shifting the
|
|
2633
|
+
index instead (item i drawn as row i + N) sized every row with
|
|
2634
|
+
the height of the row N above it, so a row dragged taller under
|
|
2635
|
+
a freeze showed its neighbour's height. -->
|
|
2194
2636
|
{#each virtualRows as rowItem (rowItem.key)}
|
|
2195
2637
|
{@const rowIndex = rowItem.index}
|
|
2196
2638
|
{@const row = allRows[rowIndex]}
|
|
2197
|
-
{#if row}
|
|
2198
|
-
{
|
|
2199
|
-
{@render detailRowMarkup(row, rowIndex)}
|
|
2200
|
-
{:else if isGroupRow(row) && !groupColumnMode}
|
|
2201
|
-
<tr
|
|
2202
|
-
class="sv-grid-row sv-grid-group-row"
|
|
2203
|
-
class:sv-grid-row-selected={isRowSelected(row.id)}
|
|
2204
|
-
aria-level={row.depth + 1}
|
|
2205
|
-
aria-expanded={row.getIsExpanded?.() ? "true" : "false"}
|
|
2206
|
-
{...getGridRowA11yProps(rowIndex + 1)}
|
|
2207
|
-
style={rowHeightStyle(rowItem.size)}
|
|
2208
|
-
>
|
|
2209
|
-
<td
|
|
2210
|
-
class="sv-grid-cell sv-grid-group-cell"
|
|
2211
|
-
class:sv-grid-cell-active={activeCell.rowIndex ===
|
|
2212
|
-
rowIndex}
|
|
2213
|
-
colspan={allColumns.length +
|
|
2214
|
-
(showRowNumbersEffective ? 1 : 0) +
|
|
2215
|
-
(showRowSelectionEffective ? 1 : 0)}
|
|
2216
|
-
onclick={() => row.toggleExpanded?.()}
|
|
2217
|
-
>
|
|
2218
|
-
{@render groupRowContent(row)}
|
|
2219
|
-
</td>
|
|
2220
|
-
</tr>
|
|
2221
|
-
{:else}
|
|
2222
|
-
{@const userRowClass = computeRowClass(row, rowIndex)}
|
|
2223
|
-
<tr
|
|
2224
|
-
class={`sv-grid-row ${userRowClass} ${rowDropClass(rowIndex)}`}
|
|
2225
|
-
class:sv-grid-row-selected={isRowSelected(row.id)}
|
|
2226
|
-
class:sv-grid-row-alt={opt.zebraRows &&
|
|
2227
|
-
rowIndex % 2 === 1}
|
|
2228
|
-
class:sv-grid-row-draggable={rowDragManagedEffective}
|
|
2229
|
-
class:sv-grid-group-footer-row={isGroupFooterRow(row)}
|
|
2230
|
-
class:sv-grid-grand-total-row={isGrandTotalRow(row)}
|
|
2231
|
-
class:sv-grid-row-auto-height={autoRowHeightOn}
|
|
2232
|
-
{...getGridRowA11yProps(rowIndex + 1)}
|
|
2233
|
-
aria-level={sgAriaLevel(row)}
|
|
2234
|
-
aria-expanded={sgAriaExpanded(row)}
|
|
2235
|
-
{...rowDragAttrs(rowIndex)}
|
|
2236
|
-
style={rowHeightStyle(rowItem.size)}
|
|
2237
|
-
use:measureRowHeight={rowIndex}
|
|
2238
|
-
>
|
|
2239
|
-
{#if showRowNumbersEffective}
|
|
2240
|
-
<td
|
|
2241
|
-
class="sv-grid-cell sv-grid-row-number-cell"
|
|
2242
|
-
style={`width: ${rowNumberColumnWidth}px; min-width: ${rowNumberColumnWidth}px; max-width: ${rowNumberColumnWidth}px; left: 0;`}
|
|
2243
|
-
>{rowIndex + 1}</td
|
|
2244
|
-
>
|
|
2245
|
-
{/if}
|
|
2246
|
-
{#if showRowSelectionEffective}
|
|
2247
|
-
<td
|
|
2248
|
-
class="sv-grid-cell sv-grid-selection-cell"
|
|
2249
|
-
style={`width: ${selectionColumnWidth}px; min-width: ${selectionColumnWidth}px; max-width: ${selectionColumnWidth}px; left: ${showRowNumbersEffective ? rowNumberColumnWidth : 0}px;`}
|
|
2250
|
-
onclick={() => toggleRowSelectionById(row.id)}
|
|
2251
|
-
>
|
|
2252
|
-
<button
|
|
2253
|
-
type="button"
|
|
2254
|
-
class="sv-grid-checkbox"
|
|
2255
|
-
role="checkbox"
|
|
2256
|
-
aria-checked={isRowSelected(row.id)}
|
|
2257
|
-
aria-label="Select row"
|
|
2258
|
-
onclick={(event) => {
|
|
2259
|
-
event.stopPropagation();
|
|
2260
|
-
toggleRowSelectionById(row.id);
|
|
2261
|
-
}}
|
|
2262
|
-
onkeydown={(event) =>
|
|
2263
|
-
toggleCheckboxWithKeyboard(event, () => {
|
|
2264
|
-
event.stopPropagation();
|
|
2265
|
-
toggleRowSelectionById(row.id);
|
|
2266
|
-
})}
|
|
2267
|
-
></button>
|
|
2268
|
-
</td>
|
|
2269
|
-
{/if}
|
|
2270
|
-
{#if columnVirtualizationEnabled && columnWindowStart > 0}
|
|
2271
|
-
<td
|
|
2272
|
-
class="sv-grid-cell sv-grid-cell-spacer"
|
|
2273
|
-
aria-hidden="true"
|
|
2274
|
-
style={`width: ${columnWindowStart}px; min-width: ${columnWindowStart}px; max-width: ${columnWindowStart}px;`}
|
|
2275
|
-
></td>
|
|
2276
|
-
{/if}
|
|
2277
|
-
{#each renderedColumns as rendered (rendered.column.id)}
|
|
2278
|
-
{@const colIndex = rendered.item.index}
|
|
2279
|
-
{@const baseValue = getColumnBaseValue(
|
|
2280
|
-
row,
|
|
2281
|
-
rendered.column,
|
|
2282
|
-
)}
|
|
2283
|
-
{@const cellValue = getCellDisplayValue(
|
|
2284
|
-
row.id,
|
|
2285
|
-
rendered.column.id,
|
|
2286
|
-
baseValue,
|
|
2287
|
-
)}
|
|
2288
|
-
{@const isEditing =
|
|
2289
|
-
ctrl.editingCell?.rowId === row.id &&
|
|
2290
|
-
ctrl.editingCell?.columnId === rendered.column.id}
|
|
2291
|
-
{@const inRowEdit =
|
|
2292
|
-
!!fullRowEdit &&
|
|
2293
|
-
fullRowEdit.rowId === row.id &&
|
|
2294
|
-
rendered.column.id in fullRowEdit.draft}
|
|
2295
|
-
{@const rangeEdges = getCellRangeEdges(
|
|
2296
|
-
rowIndex,
|
|
2297
|
-
colIndex,
|
|
2298
|
-
)}
|
|
2299
|
-
{@const fillEdges = fillMarqueeEdges(rowIndex, colIndex)}
|
|
2300
|
-
{@const hasFillHandle =
|
|
2301
|
-
fillHandleCell &&
|
|
2302
|
-
fillHandleCell.rowIndex === rowIndex &&
|
|
2303
|
-
fillHandleCell.colIndex === colIndex}
|
|
2304
|
-
{@const userCellClass = computeCellClass(
|
|
2305
|
-
row,
|
|
2306
|
-
rendered.column,
|
|
2307
|
-
)}
|
|
2308
|
-
{@const cellValidity = computeCellValidity(
|
|
2309
|
-
row,
|
|
2310
|
-
rendered.column,
|
|
2311
|
-
)}
|
|
2312
|
-
{@const cellNote = computeCellNote(
|
|
2313
|
-
row,
|
|
2314
|
-
rendered.column,
|
|
2315
|
-
)}
|
|
2316
|
-
<td
|
|
2317
|
-
class={`sv-grid-cell ${userCellClass}`}
|
|
2318
|
-
class:sv-grid-cell-editing={isEditing || inRowEdit}
|
|
2319
|
-
class:sv-grid-cell-active={activeCell.rowIndex ===
|
|
2320
|
-
rowIndex && activeCell.colIndex === colIndex}
|
|
2321
|
-
class:sv-grid-cell-has-fill-handle={hasFillHandle}
|
|
2322
|
-
class:sv-grid-cell-cf={hasConditionalFormats}
|
|
2323
|
-
class:sv-grid-cell-invalid={cellValidity.invalid}
|
|
2324
|
-
class:sv-grid-cell-has-note={cellNote != null}
|
|
2325
|
-
aria-invalid={cellValidity.invalid ? "true" : undefined}
|
|
2326
|
-
title={cellValidity.message ?? undefined}
|
|
2327
|
-
data-svgrid-row={rowIndex}
|
|
2328
|
-
data-svgrid-col={colIndex}
|
|
2329
|
-
data-col-id={rendered.column.id}
|
|
2330
|
-
data-align={getColumnAlign(rendered.column)}
|
|
2331
|
-
data-pinned={isColumnPinned(rendered.column.id) ??
|
|
2332
|
-
undefined}
|
|
2333
|
-
data-selected-range={rangeEdges ? "true" : undefined}
|
|
2334
|
-
data-range-top={rangeEdges?.top ? "true" : undefined}
|
|
2335
|
-
data-range-bottom={rangeEdges?.bottom
|
|
2336
|
-
? "true"
|
|
2337
|
-
: undefined}
|
|
2338
|
-
data-range-left={rangeEdges?.left
|
|
2339
|
-
? "true"
|
|
2340
|
-
: undefined}
|
|
2341
|
-
data-range-right={rangeEdges?.right
|
|
2342
|
-
? "true"
|
|
2343
|
-
: undefined}
|
|
2344
|
-
data-fill-preview={isInFillPreview(rowIndex, colIndex)
|
|
2345
|
-
? "true"
|
|
2346
|
-
: undefined}
|
|
2347
|
-
data-fill-top={fillEdges?.top ? "true" : undefined}
|
|
2348
|
-
data-fill-bottom={fillEdges?.bottom ? "true" : undefined}
|
|
2349
|
-
data-fill-left={fillEdges?.left ? "true" : undefined}
|
|
2350
|
-
data-fill-right={fillEdges?.right ? "true" : undefined}
|
|
2351
|
-
style={`width: ${rendered.item.size}px; min-width: ${rendered.item.size}px; max-width: ${rendered.item.size}px; ${cellPinStyle(rendered.column.id)}`}
|
|
2352
|
-
onpointerdown={(event) =>
|
|
2353
|
-
onCellPointerDown(rowIndex, colIndex, event)}
|
|
2354
|
-
onpointerenter={() =>
|
|
2355
|
-
onCellPointerEnter(rowIndex, colIndex)}
|
|
2356
|
-
ondblclick={() =>
|
|
2357
|
-
emitCellDoubleClick(rowIndex, colIndex)}
|
|
2358
|
-
onclick={() => onCellClick(rowIndex, colIndex)}
|
|
2359
|
-
oncontextmenu={(event) =>
|
|
2360
|
-
openContextMenu(
|
|
2361
|
-
event,
|
|
2362
|
-
rowIndex,
|
|
2363
|
-
colIndex,
|
|
2364
|
-
rendered.column.id,
|
|
2365
|
-
)}
|
|
2366
|
-
use:cellFlashAction={{
|
|
2367
|
-
rowId: row.id,
|
|
2368
|
-
value: cellValue,
|
|
2369
|
-
active: !!rendered.column.columnDef.cellFlash,
|
|
2370
|
-
className: flashClassFor(
|
|
2371
|
-
rendered.column.columnDef.cellFlash,
|
|
2372
|
-
),
|
|
2373
|
-
}}
|
|
2374
|
-
role="gridcell"
|
|
2375
|
-
id={getGridCellDomId(ctrl.gridDomId, rowIndex, colIndex)}
|
|
2376
|
-
aria-colindex={colIndex + 1}
|
|
2377
|
-
aria-rowindex={rowIndex + 1}
|
|
2378
|
-
aria-selected={isRowSelected(row.id)}
|
|
2379
|
-
>
|
|
2380
|
-
{#if inRowEdit || isEditing}
|
|
2381
|
-
<!-- The editing cell stays empty until the lazy
|
|
2382
|
-
editor chunk lands, exactly as it already did
|
|
2383
|
-
for the dropdown / date editors. Falling back
|
|
2384
|
-
to the read-only value here would flash stale
|
|
2385
|
-
content into a cell the user is editing. -->
|
|
2386
|
-
{#if CellEditor}
|
|
2387
|
-
<CellEditor {ctrl} column={rendered.column} {row} fullRow={inRowEdit} />
|
|
2388
|
-
{/if}
|
|
2389
|
-
{:else}
|
|
2390
|
-
{#if plainCellBody}
|
|
2391
|
-
{@render cellBody(row, rendered.column, cellValue)}
|
|
2392
|
-
{:else}
|
|
2393
|
-
{@render cellBodyWithFormat(
|
|
2394
|
-
row,
|
|
2395
|
-
rendered.column,
|
|
2396
|
-
cellValue,
|
|
2397
|
-
)}
|
|
2398
|
-
{/if}
|
|
2399
|
-
{/if}
|
|
2400
|
-
{#if !isEditing && fillHandleCell && fillHandleCell.rowIndex === rowIndex && fillHandleCell.colIndex === colIndex}
|
|
2401
|
-
<!-- Excel-style fill handle: drag down/right to
|
|
2402
|
-
extend the selection and pattern-fill the new
|
|
2403
|
-
cells on release. Rendered inside the bottom-
|
|
2404
|
-
right cell of the selection range (or active
|
|
2405
|
-
cell if there's no range). -->
|
|
2406
|
-
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
2407
|
-
<div
|
|
2408
|
-
class="sv-grid-fill-handle"
|
|
2409
|
-
role="button"
|
|
2410
|
-
aria-label="Fill handle"
|
|
2411
|
-
tabindex={-1}
|
|
2412
|
-
onpointerdown={(event) =>
|
|
2413
|
-
startFillDrag(event, rowIndex, colIndex)}
|
|
2414
|
-
></div>
|
|
2415
|
-
{/if}
|
|
2416
|
-
{#if cellNote != null && !isEditing}
|
|
2417
|
-
<span
|
|
2418
|
-
class="sv-grid-cell-note-corner"
|
|
2419
|
-
aria-label="Note"
|
|
2420
|
-
onpointerenter={(event) => {
|
|
2421
|
-
event.stopPropagation();
|
|
2422
|
-
showTooltipFor(
|
|
2423
|
-
event.currentTarget as HTMLElement,
|
|
2424
|
-
cellNote,
|
|
2425
|
-
);
|
|
2426
|
-
}}
|
|
2427
|
-
onpointerleave={(event) => {
|
|
2428
|
-
event.stopPropagation();
|
|
2429
|
-
hideTooltip();
|
|
2430
|
-
}}
|
|
2431
|
-
></span>
|
|
2432
|
-
{/if}
|
|
2433
|
-
</td>
|
|
2434
|
-
{/each}
|
|
2435
|
-
{#if columnVirtualizationEnabled && columnWindowRightSpacer > 0}
|
|
2436
|
-
<td
|
|
2437
|
-
class="sv-grid-cell sv-grid-cell-spacer"
|
|
2438
|
-
aria-hidden="true"
|
|
2439
|
-
style={`width: ${columnWindowRightSpacer}px; min-width: ${columnWindowRightSpacer}px; max-width: ${columnWindowRightSpacer}px;`}
|
|
2440
|
-
></td>
|
|
2441
|
-
{/if}
|
|
2442
|
-
</tr>
|
|
2443
|
-
{/if}
|
|
2639
|
+
{#if row && rowIndex >= frozenRowCount}
|
|
2640
|
+
{@render bodyRow(row, rowIndex, rowHeightStyle(rowItem.size))}
|
|
2444
2641
|
{/if}
|
|
2445
2642
|
{/each}
|
|
2446
2643
|
{#if rowBottomSpacer > 0}
|
|
@@ -2456,253 +2653,7 @@
|
|
|
2456
2653
|
{/if}
|
|
2457
2654
|
{:else}
|
|
2458
2655
|
{#each allRows as row, rowIndex (row.id)}
|
|
2459
|
-
{
|
|
2460
|
-
{@render detailRowMarkup(row, rowIndex)}
|
|
2461
|
-
{:else if isGroupRow(row) && !groupColumnMode}
|
|
2462
|
-
<tr
|
|
2463
|
-
class="sv-grid-row sv-grid-group-row"
|
|
2464
|
-
class:sv-grid-row-selected={isRowSelected(row.id)}
|
|
2465
|
-
aria-level={row.depth + 1}
|
|
2466
|
-
aria-expanded={row.getIsExpanded?.() ? "true" : "false"}
|
|
2467
|
-
{...getGridRowA11yProps(rowIndex + 1)}
|
|
2468
|
-
style={rowStyleFor(rowIndex)}
|
|
2469
|
-
>
|
|
2470
|
-
<td
|
|
2471
|
-
class="sv-grid-cell sv-grid-group-cell"
|
|
2472
|
-
class:sv-grid-cell-active={activeCell.rowIndex ===
|
|
2473
|
-
rowIndex}
|
|
2474
|
-
colspan={allColumns.length +
|
|
2475
|
-
(showRowNumbersEffective ? 1 : 0) +
|
|
2476
|
-
(showRowSelectionEffective ? 1 : 0)}
|
|
2477
|
-
onclick={() => row.toggleExpanded?.()}
|
|
2478
|
-
>
|
|
2479
|
-
{@render groupRowContent(row)}
|
|
2480
|
-
</td>
|
|
2481
|
-
</tr>
|
|
2482
|
-
{:else}
|
|
2483
|
-
{@const userRowClass = computeRowClass(row, rowIndex)}
|
|
2484
|
-
<tr
|
|
2485
|
-
class={`sv-grid-row ${userRowClass} ${rowDropClass(rowIndex)}`}
|
|
2486
|
-
class:sv-grid-row-selected={isRowSelected(row.id)}
|
|
2487
|
-
class:sv-grid-row-alt={opt.zebraRows &&
|
|
2488
|
-
rowIndex % 2 === 1}
|
|
2489
|
-
class:sv-grid-row-draggable={rowDragManagedEffective}
|
|
2490
|
-
class:sv-grid-group-footer-row={isGroupFooterRow(row)}
|
|
2491
|
-
class:sv-grid-grand-total-row={isGrandTotalRow(row)}
|
|
2492
|
-
class:sv-grid-row-auto-height={autoRowHeightOn}
|
|
2493
|
-
{...getGridRowA11yProps(rowIndex + 1)}
|
|
2494
|
-
aria-level={sgAriaLevel(row)}
|
|
2495
|
-
aria-expanded={sgAriaExpanded(row)}
|
|
2496
|
-
{...rowDragAttrs(rowIndex)}
|
|
2497
|
-
style={rowStyleFor(rowIndex)}
|
|
2498
|
-
use:measureRowHeight={rowIndex}
|
|
2499
|
-
>
|
|
2500
|
-
{#if showRowNumbersEffective}
|
|
2501
|
-
<td
|
|
2502
|
-
class="sv-grid-cell sv-grid-row-number-cell"
|
|
2503
|
-
style={`width: ${rowNumberColumnWidth}px; min-width: ${rowNumberColumnWidth}px; max-width: ${rowNumberColumnWidth}px; left: 0;`}
|
|
2504
|
-
>{rowIndex + 1}</td
|
|
2505
|
-
>
|
|
2506
|
-
{/if}
|
|
2507
|
-
{#if showRowSelectionEffective}
|
|
2508
|
-
<td
|
|
2509
|
-
class="sv-grid-cell sv-grid-selection-cell"
|
|
2510
|
-
style={`width: ${selectionColumnWidth}px; min-width: ${selectionColumnWidth}px; max-width: ${selectionColumnWidth}px; left: ${showRowNumbersEffective ? rowNumberColumnWidth : 0}px;`}
|
|
2511
|
-
onclick={() => toggleRowSelectionById(row.id)}
|
|
2512
|
-
>
|
|
2513
|
-
<button
|
|
2514
|
-
type="button"
|
|
2515
|
-
class="sv-grid-checkbox"
|
|
2516
|
-
role="checkbox"
|
|
2517
|
-
aria-checked={isRowSelected(row.id)}
|
|
2518
|
-
aria-label="Select row"
|
|
2519
|
-
onclick={(event) => {
|
|
2520
|
-
event.stopPropagation();
|
|
2521
|
-
toggleRowSelectionById(row.id);
|
|
2522
|
-
}}
|
|
2523
|
-
onkeydown={(event) =>
|
|
2524
|
-
toggleCheckboxWithKeyboard(event, () => {
|
|
2525
|
-
event.stopPropagation();
|
|
2526
|
-
toggleRowSelectionById(row.id);
|
|
2527
|
-
})}
|
|
2528
|
-
></button>
|
|
2529
|
-
</td>
|
|
2530
|
-
{/if}
|
|
2531
|
-
{#if columnVirtualizationEnabled && columnWindowStart > 0}
|
|
2532
|
-
<td
|
|
2533
|
-
class="sv-grid-cell sv-grid-cell-spacer"
|
|
2534
|
-
aria-hidden="true"
|
|
2535
|
-
style={`width: ${columnWindowStart}px; min-width: ${columnWindowStart}px; max-width: ${columnWindowStart}px;`}
|
|
2536
|
-
></td>
|
|
2537
|
-
{/if}
|
|
2538
|
-
{#each renderedColumns as rendered (rendered.column.id)}
|
|
2539
|
-
{@const colIndex = rendered.item.index}
|
|
2540
|
-
{@const baseValue = getColumnBaseValue(
|
|
2541
|
-
row,
|
|
2542
|
-
rendered.column,
|
|
2543
|
-
)}
|
|
2544
|
-
{@const cellValue = getCellDisplayValue(
|
|
2545
|
-
row.id,
|
|
2546
|
-
rendered.column.id,
|
|
2547
|
-
baseValue,
|
|
2548
|
-
)}
|
|
2549
|
-
{@const isEditing =
|
|
2550
|
-
ctrl.editingCell?.rowId === row.id &&
|
|
2551
|
-
ctrl.editingCell?.columnId === rendered.column.id}
|
|
2552
|
-
{@const inRowEdit =
|
|
2553
|
-
!!fullRowEdit &&
|
|
2554
|
-
fullRowEdit.rowId === row.id &&
|
|
2555
|
-
rendered.column.id in fullRowEdit.draft}
|
|
2556
|
-
{@const rangeEdges = getCellRangeEdges(
|
|
2557
|
-
rowIndex,
|
|
2558
|
-
colIndex,
|
|
2559
|
-
)}
|
|
2560
|
-
{@const userCellClass = computeCellClass(
|
|
2561
|
-
row,
|
|
2562
|
-
rendered.column,
|
|
2563
|
-
)}
|
|
2564
|
-
{@const cellTooltip = computeCellTooltip(
|
|
2565
|
-
row,
|
|
2566
|
-
rendered.column,
|
|
2567
|
-
)}
|
|
2568
|
-
{@const cellValidity = computeCellValidity(
|
|
2569
|
-
row,
|
|
2570
|
-
rendered.column,
|
|
2571
|
-
)}
|
|
2572
|
-
{@const cellNote = computeCellNote(row, rendered.column)}
|
|
2573
|
-
<td
|
|
2574
|
-
class={`sv-grid-cell ${userCellClass}`}
|
|
2575
|
-
class:sv-grid-cell-editing={isEditing || inRowEdit}
|
|
2576
|
-
class:sv-grid-cell-active={activeCell.rowIndex ===
|
|
2577
|
-
rowIndex && activeCell.colIndex === colIndex}
|
|
2578
|
-
class:sv-grid-cell-cf={hasConditionalFormats}
|
|
2579
|
-
class:sv-grid-cell-invalid={cellValidity.invalid}
|
|
2580
|
-
class:sv-grid-cell-has-note={cellNote != null}
|
|
2581
|
-
aria-invalid={cellValidity.invalid ? "true" : undefined}
|
|
2582
|
-
data-svgrid-row={rowIndex}
|
|
2583
|
-
data-svgrid-col={colIndex}
|
|
2584
|
-
data-col-id={rendered.column.id}
|
|
2585
|
-
data-align={getColumnAlign(rendered.column)}
|
|
2586
|
-
data-pinned={isColumnPinned(rendered.column.id) ??
|
|
2587
|
-
undefined}
|
|
2588
|
-
data-selected-range={rangeEdges ? "true" : undefined}
|
|
2589
|
-
data-range-top={rangeEdges?.top ? "true" : undefined}
|
|
2590
|
-
data-range-bottom={rangeEdges?.bottom
|
|
2591
|
-
? "true"
|
|
2592
|
-
: undefined}
|
|
2593
|
-
data-range-left={rangeEdges?.left ? "true" : undefined}
|
|
2594
|
-
data-range-right={rangeEdges?.right
|
|
2595
|
-
? "true"
|
|
2596
|
-
: undefined}
|
|
2597
|
-
style={`width: ${rendered.item.size}px; min-width: ${rendered.item.size}px; max-width: ${rendered.item.size}px; ${cellPinStyle(rendered.column.id)}`}
|
|
2598
|
-
onpointerdown={(event) =>
|
|
2599
|
-
onCellPointerDown(rowIndex, colIndex, event)}
|
|
2600
|
-
onpointerenter={(event) => {
|
|
2601
|
-
onCellPointerEnter(rowIndex, colIndex);
|
|
2602
|
-
// Column tooltip fires on whole-cell hover.
|
|
2603
|
-
// Per-cell notes are gated on the corner hot-
|
|
2604
|
-
// zone below (Excel-style: hover the small
|
|
2605
|
-
// triangle to read the note). A validation
|
|
2606
|
-
// message (when the cell is invalid) wins over
|
|
2607
|
-
// the plain column tooltip.
|
|
2608
|
-
const tip =
|
|
2609
|
-
cellValidity.invalid && cellValidity.message
|
|
2610
|
-
? cellValidity.message
|
|
2611
|
-
: cellTooltip;
|
|
2612
|
-
if (tip)
|
|
2613
|
-
showTooltipFor(
|
|
2614
|
-
event.currentTarget as HTMLElement,
|
|
2615
|
-
tip,
|
|
2616
|
-
);
|
|
2617
|
-
}}
|
|
2618
|
-
onpointerleave={hideTooltip}
|
|
2619
|
-
ondblclick={() =>
|
|
2620
|
-
emitCellDoubleClick(rowIndex, colIndex)}
|
|
2621
|
-
onclick={() => onCellClick(rowIndex, colIndex)}
|
|
2622
|
-
oncontextmenu={(event) =>
|
|
2623
|
-
openContextMenu(
|
|
2624
|
-
event,
|
|
2625
|
-
rowIndex,
|
|
2626
|
-
colIndex,
|
|
2627
|
-
rendered.column.id,
|
|
2628
|
-
)}
|
|
2629
|
-
use:cellFlashAction={{
|
|
2630
|
-
rowId: row.id,
|
|
2631
|
-
value: cellValue,
|
|
2632
|
-
active: !!rendered.column.columnDef.cellFlash,
|
|
2633
|
-
className: flashClassFor(
|
|
2634
|
-
rendered.column.columnDef.cellFlash,
|
|
2635
|
-
),
|
|
2636
|
-
}}
|
|
2637
|
-
{...getGridCellA11yProps({
|
|
2638
|
-
id: getGridCellDomId(ctrl.gridDomId, rowIndex, colIndex),
|
|
2639
|
-
rowIndex: rowIndex + 1,
|
|
2640
|
-
colIndex: colIndex + 1,
|
|
2641
|
-
selected: isRowSelected(row.id),
|
|
2642
|
-
})}
|
|
2643
|
-
>
|
|
2644
|
-
{#if inRowEdit || isEditing}
|
|
2645
|
-
<!-- Empty until the lazy editor chunk lands - see the
|
|
2646
|
-
matching branch in the pinned-row body above. -->
|
|
2647
|
-
{#if CellEditor}
|
|
2648
|
-
<CellEditor {ctrl} column={rendered.column} {row} fullRow={inRowEdit} />
|
|
2649
|
-
{/if}
|
|
2650
|
-
{:else}
|
|
2651
|
-
{@render cellBodyWithFormat(
|
|
2652
|
-
row,
|
|
2653
|
-
rendered.column,
|
|
2654
|
-
cellValue,
|
|
2655
|
-
)}
|
|
2656
|
-
{/if}
|
|
2657
|
-
{#if cellValidity.invalid && cellValidity.message}
|
|
2658
|
-
<!-- The validation message, for assistive tech.
|
|
2659
|
-
On this path the message is shown visually by
|
|
2660
|
-
the pointerenter tooltip above, which is mouse-
|
|
2661
|
-
only - a keyboard or screen-reader user would
|
|
2662
|
-
get `aria-invalid` with no reason attached.
|
|
2663
|
-
A visually-hidden span inside the cell is read
|
|
2664
|
-
as part of the cell when focus lands on it, and
|
|
2665
|
-
unlike `title` it adds no second native tooltip
|
|
2666
|
-
competing with the custom one. -->
|
|
2667
|
-
<span class="sv-grid-sr-only"
|
|
2668
|
-
>{cellValidity.message}</span
|
|
2669
|
-
>
|
|
2670
|
-
{/if}
|
|
2671
|
-
{#if cellNote != null && !isEditing}
|
|
2672
|
-
<!-- Excel-style per-cell note indicator. The
|
|
2673
|
-
triangle itself is the hot-zone; hover
|
|
2674
|
-
just the corner to see the note (Excel
|
|
2675
|
-
red-dot behaviour). The cell-level
|
|
2676
|
-
tooltip handler only shows the column
|
|
2677
|
-
tooltip, so the two surfaces stay
|
|
2678
|
-
separate. -->
|
|
2679
|
-
<span
|
|
2680
|
-
class="sv-grid-cell-note-corner"
|
|
2681
|
-
aria-label="Note"
|
|
2682
|
-
onpointerenter={(event) => {
|
|
2683
|
-
event.stopPropagation();
|
|
2684
|
-
showTooltipFor(
|
|
2685
|
-
event.currentTarget as HTMLElement,
|
|
2686
|
-
cellNote,
|
|
2687
|
-
);
|
|
2688
|
-
}}
|
|
2689
|
-
onpointerleave={(event) => {
|
|
2690
|
-
event.stopPropagation();
|
|
2691
|
-
hideTooltip();
|
|
2692
|
-
}}
|
|
2693
|
-
></span>
|
|
2694
|
-
{/if}
|
|
2695
|
-
</td>
|
|
2696
|
-
{/each}
|
|
2697
|
-
{#if columnVirtualizationEnabled && columnWindowRightSpacer > 0}
|
|
2698
|
-
<td
|
|
2699
|
-
class="sv-grid-cell sv-grid-cell-spacer"
|
|
2700
|
-
aria-hidden="true"
|
|
2701
|
-
style={`width: ${columnWindowRightSpacer}px; min-width: ${columnWindowRightSpacer}px; max-width: ${columnWindowRightSpacer}px;`}
|
|
2702
|
-
></td>
|
|
2703
|
-
{/if}
|
|
2704
|
-
</tr>
|
|
2705
|
-
{/if}
|
|
2656
|
+
{@render bodyRow(row, rowIndex, rowStyleFor(rowIndex))}
|
|
2706
2657
|
{/each}
|
|
2707
2658
|
{/if}
|
|
2708
2659
|
</tbody>
|
|
@@ -3132,7 +3083,7 @@
|
|
|
3132
3083
|
`absolute` against it, so moving it outside would anchor it to the
|
|
3133
3084
|
page. The renderer is Enterprise and arrives through the
|
|
3134
3085
|
selection-bar-view seam; without it, a short note in its place. -->
|
|
3135
|
-
{#if ctrl.
|
|
3086
|
+
{#if ctrl.selectionBarVisible}
|
|
3136
3087
|
{#if getSelectionBarView()}
|
|
3137
3088
|
{@const SelectionBarView = getSelectionBarView()}
|
|
3138
3089
|
<SelectionBarView {ctrl} />
|