@svgrid/grid 2.2.31 → 2.2.32
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 +1 -1
- package/dist/SvAvatar.svelte +1 -1
- package/dist/SvCheckBox.svelte +2 -1
- package/dist/SvCircularProgress.svelte +1 -1
- package/dist/SvGrid.controller.svelte.d.ts +20 -0
- package/dist/SvGrid.controller.svelte.js +358 -18
- package/dist/SvGrid.css +103 -3
- package/dist/SvGrid.svelte +162 -10
- package/dist/SvGrid.types.d.ts +81 -0
- package/dist/SvGridDropdown.svelte +38 -6
- package/dist/SvGridDropdown.svelte.d.ts +4 -0
- package/dist/SvGridSelect.svelte +12 -3
- package/dist/SvGridSelect.svelte.d.ts +6 -0
- package/dist/SvGroupCell.svelte +9 -2
- package/dist/SvMultiSelect.svelte +12 -3
- package/dist/SvMultiSelect.svelte.d.ts +6 -0
- package/dist/SvPasswordInput.svelte +1 -1
- package/dist/SvProgress.svelte +1 -1
- package/dist/SvRating.svelte +1 -1
- package/dist/SvResult.svelte +1 -1
- package/dist/SvRichText.svelte +31 -16
- package/dist/SvRichText.svelte.d.ts +9 -0
- package/dist/SvSwitchButton.svelte +2 -1
- package/dist/SvToaster.svelte +1 -1
- package/dist/SvTree.svelte +9 -2
- package/dist/SvTree.svelte.d.ts +5 -0
- package/dist/SvTreeSelect.svelte +6 -2
- package/dist/build-api.js +16 -0
- package/dist/cdn/{GridMenus-Ds3OpzZT.js → GridMenus-C6ixSGWW.js} +33 -33
- package/dist/cdn/{GridMenus-Da_p7SKS.js → GridMenus-Cyk3qpJ7.js} +33 -33
- package/dist/cdn/{SvDateTimePicker-B8GopjhC.js → SvDateTimePicker-CdqaP61H.js} +2 -1
- package/dist/cdn/{SvDateTimePicker-DB0aIEk8.js → SvDateTimePicker-ClqtVIj3.js} +2 -1
- package/dist/cdn/{SvGridDropdown-DjALc_4f.js → SvGridDropdown-D0VdjeR8.js} +129 -123
- package/dist/cdn/{SvGridDropdown-hpnHvOGt.js → SvGridDropdown-Dh-2ej8j.js} +92 -87
- package/dist/cdn/{src-BLJfdyL0.js → src-BgHjWF0Q.js} +4193 -3837
- package/dist/cdn/{src-DYDCiC0D.js → src-CgD-wiuS.js} +5956 -5602
- package/dist/cdn/svgrid.js +8 -8
- package/dist/cdn/svgrid.svelte-external.js +8 -8
- package/dist/cell-render.d.ts +1 -0
- package/dist/cell-render.js +115 -1
- package/dist/cell-values.js +5 -0
- package/dist/core.d.ts +80 -9
- package/dist/core.js +89 -0
- package/dist/editor-contract.d.ts +12 -5
- package/dist/editor-registry.d.ts +18 -7
- package/dist/editor-registry.js +10 -1
- package/dist/group-display.d.ts +39 -0
- package/dist/group-display.js +52 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/keyboard-handlers.js +16 -0
- package/dist/recurrence.js +3 -2
- package/dist/svgrid-wrapper.types.d.ts +8 -2
- package/dist/themes/index.d.ts +10 -0
- package/dist/themes/index.js +26 -0
- package/package.json +1 -1
- package/src/SvAccordion.test.ts +5 -5
- package/src/SvAvatar.svelte +1 -1
- package/src/SvButtonGroup.test.ts +6 -6
- package/src/SvCheckBox.svelte +2 -1
- package/src/SvCircularProgress.svelte +1 -1
- package/src/SvFileUpload.test.ts +1 -1
- package/src/SvGrid.controller.svelte.ts +367 -17
- package/src/SvGrid.css +103 -3
- package/src/SvGrid.svelte +162 -10
- package/src/SvGrid.types.ts +81 -0
- package/src/SvGridDropdown.svelte +38 -6
- package/src/SvGridSelect.svelte +12 -3
- package/src/SvGroupCell.svelte +9 -2
- package/src/SvMultiSelect.svelte +12 -3
- package/src/SvPasswordInput.svelte +1 -1
- package/src/SvProgress.svelte +1 -1
- package/src/SvRating.svelte +1 -1
- package/src/SvResult.svelte +1 -1
- package/src/SvRichText.svelte +31 -16
- package/src/SvSwitchButton.svelte +2 -1
- package/src/SvToaster.svelte +1 -1
- package/src/SvTree.svelte +9 -2
- package/src/SvTreeSelect.svelte +6 -2
- package/src/build-api.ts +15 -0
- package/src/builtin-editors.test.ts +3 -1
- package/src/cell-render.test.ts +27 -3
- package/src/cell-render.ts +122 -1
- package/src/cell-values.ts +4 -0
- package/src/chart-export.test.ts +2 -2
- package/src/clipboard.test.ts +0 -2
- package/src/core.ts +157 -8
- package/src/editing.test.ts +1 -1
- package/src/editor-contract.ts +12 -5
- package/src/editor-registry.grid.test.ts +48 -0
- package/src/editor-registry.test.ts +3 -1
- package/src/editor-registry.ts +23 -7
- package/src/facet-buckets.test.ts +33 -33
- package/src/group-display.test.ts +91 -1
- package/src/group-display.ts +83 -0
- package/src/index.ts +9 -0
- package/src/keyboard-handlers.ts +17 -0
- package/src/list-power.test.ts +2 -2
- package/src/menus.test.ts +4 -4
- package/src/named-views.coverage.test.ts +3 -3
- package/src/recurrence.ts +3 -2
- package/src/row-resize.test.ts +40 -40
- package/src/scheduler-model.ts +1 -1
- package/src/server-data-source.coverage.test.ts +1 -1
- package/src/server-group-model.test.ts +6 -6
- package/src/spreadsheet.test.ts +0 -1
- package/src/svgrid-wrapper.types.ts +11 -9
- package/src/svgrid.async-editor-options.test.ts +271 -0
- package/src/svgrid.auto-row-height.test.ts +204 -0
- package/src/svgrid.charting.test.ts +4 -4
- package/src/svgrid.comments-autocomplete.test.ts +8 -2
- package/src/svgrid.context-menu.test.ts +25 -9
- package/src/svgrid.filter-depth.test.ts +163 -0
- package/src/svgrid.filter-menu-listbox.svelte.test.ts +16 -2
- package/src/svgrid.filter-menu-scroll.test.ts +10 -2
- package/src/svgrid.grand-total.test.ts +188 -0
- package/src/svgrid.group-display-mode.test.ts +171 -0
- package/src/svgrid.group-footers.test.ts +121 -0
- package/src/svgrid.group-pagination.test.ts +153 -0
- package/src/svgrid.tree-data.test.ts +186 -0
- package/src/svgriddropdown.async-panel.svelte.test.ts +195 -0
- package/src/themes/index.ts +42 -0
- package/src/tree-edit.test.ts +4 -4
- package/src/tree-row-model.test.ts +169 -0
- package/src/ui-localization.test.ts +113 -0
- package/themes/ag-alpine.css +22 -0
- package/themes/antd.css +22 -0
- package/themes/atlassian.css +22 -0
- package/themes/bootstrap.css +22 -0
- package/themes/carbon.css +22 -0
- package/themes/catppuccin.css +22 -0
- package/themes/dracula.css +22 -0
- package/themes/ember.css +22 -0
- package/themes/excel.css +22 -0
- package/themes/fluent.css +22 -0
- package/themes/github.css +22 -0
- package/themes/linear.css +22 -0
- package/themes/material.css +22 -0
- package/themes/nord.css +22 -0
- package/themes/notion.css +22 -0
- package/themes/salesforce.css +22 -0
- package/themes/sap.css +22 -0
- package/themes/shadcn.css +22 -0
- package/themes/tailwind.css +22 -0
- package/themes/vercel.css +22 -0
package/README.md
CHANGED
|
@@ -88,7 +88,7 @@ all wire up the moment you turn on the matching prop.
|
|
|
88
88
|
|
|
89
89
|
- **Virtual scrolling** - row + column windowing; 100k x 100 stays smooth, with a 1M-row demo.
|
|
90
90
|
- **Filtering** - Excel-style filter menu, inline filter row, set / value-list filter, locale-aware matching, between operators.
|
|
91
|
-
- **Editing** -
|
|
91
|
+
- **Editing** - 15 built-in `editorType`s (text, number, date, datetime, time, select, rich-select with typeahead, autocomplete, textarea, color, checkbox, list, chips, rating, password), plus `date-native` / `datetime-native` / `time-native` to opt out of the rich pickers, and a `cellEditor` snippet slot for anything custom.
|
|
92
92
|
- **Selection** - cell-range click+drag and Shift+arrows, copy/paste as TSV, Excel-style fill handle, row selection.
|
|
93
93
|
- **Views** - row grouping with aggregation, tree data, master/detail, full-width detail rows, spreadsheet mode with formulas.
|
|
94
94
|
- **Layout** - row + column pinning, sticky header + first column, header drag-to-reorder, autosize, keyboard-accessible column sizing, zebra rows, responsive mode.
|
package/dist/SvAvatar.svelte
CHANGED
|
@@ -71,5 +71,5 @@
|
|
|
71
71
|
.sv-avatar__status.is-online { background: var(--sg-success, #16a34a); }
|
|
72
72
|
.sv-avatar__status.is-offline { background: var(--sg-muted, #94a3b8); }
|
|
73
73
|
.sv-avatar__status.is-busy { background: var(--sg-danger, #dc2626); }
|
|
74
|
-
.sv-avatar__status.is-away { background: var(--sg-warning, #
|
|
74
|
+
.sv-avatar__status.is-away { background: var(--sg-warning, #d97706); }
|
|
75
75
|
</style>
|
package/dist/SvCheckBox.svelte
CHANGED
|
@@ -56,8 +56,9 @@
|
|
|
56
56
|
|
|
57
57
|
<SvField id={uid} {hint} {error} {required} {dir}>
|
|
58
58
|
<label class="sv-check sv-check--{size}" class:is-disabled={disabled} class:is-readonly={readonly} class:is-invalid={invalid}>
|
|
59
|
+
<!-- role="checkbox" arrives via boxProps(), which the a11y pass cannot see through -->
|
|
60
|
+
<!-- svelte-ignore a11y_role_supports_aria_props_implicit -->
|
|
59
61
|
<button
|
|
60
|
-
role="checkbox"
|
|
61
62
|
class="sv-check__box"
|
|
62
63
|
class:is-checked={checked && !indeterminate}
|
|
63
64
|
class:is-indeterminate={indeterminate}
|
|
@@ -89,7 +89,7 @@
|
|
|
89
89
|
position: relative; display: inline-flex; flex: none;
|
|
90
90
|
}
|
|
91
91
|
.sv-circ--success { --_c: var(--sg-success, #16a34a); }
|
|
92
|
-
.sv-circ--warning { --_c: var(--sg-warning, #
|
|
92
|
+
.sv-circ--warning { --_c: var(--sg-warning, #d97706); }
|
|
93
93
|
.sv-circ--danger { --_c: var(--sg-danger, #dc2626); }
|
|
94
94
|
.sv-circ__svg { display: block; transform: rotate(-90deg); }
|
|
95
95
|
.sv-circ__track { stroke: var(--sg-border, #e2e8f0); }
|
|
@@ -260,6 +260,13 @@ export declare function createSvGridController<TFeatures extends TableFeatures =
|
|
|
260
260
|
readonly isCellEditableAt: (rowIndex: number, colIndex: number) => boolean;
|
|
261
261
|
readonly sortDirectionByColumn: Record<string, false | "asc" | "desc">;
|
|
262
262
|
readonly groupingColumns: any;
|
|
263
|
+
readonly groupDisplayMode: import("./group-display").GroupDisplayType;
|
|
264
|
+
readonly groupColumnMode: boolean;
|
|
265
|
+
readonly autoGroupCell: (row: Row<TData>, columnId: string) => {
|
|
266
|
+
label: string;
|
|
267
|
+
count: number;
|
|
268
|
+
depth: number;
|
|
269
|
+
} | null;
|
|
263
270
|
readonly paginationState: any;
|
|
264
271
|
readonly externalPaginationEnabled: boolean;
|
|
265
272
|
readonly paginationTotalRows: number;
|
|
@@ -413,6 +420,15 @@ export declare function createSvGridController<TFeatures extends TableFeatures =
|
|
|
413
420
|
readonly rowVirtualizationEnabled: boolean;
|
|
414
421
|
readonly columnVirtualizationEnabled: boolean;
|
|
415
422
|
readonly virtualRows: import("./index").VirtualItem[];
|
|
423
|
+
readonly autoRowHeightOn: boolean;
|
|
424
|
+
/** Svelte action: measure this row and report its natural height. */
|
|
425
|
+
readonly measureRowHeight: (node: HTMLElement, index: number) => {
|
|
426
|
+
update(next: number): void;
|
|
427
|
+
destroy(): void;
|
|
428
|
+
};
|
|
429
|
+
/** A row's measured height, or undefined before it has been measured.
|
|
430
|
+
* The non-virtualized body reads this directly (it has no virtual item). */
|
|
431
|
+
readonly measuredRowHeightPx: (index: number) => number | undefined;
|
|
416
432
|
readonly virtualRowTotalSize: number;
|
|
417
433
|
readonly virtualRowStart: number;
|
|
418
434
|
readonly virtualRowEnd: number;
|
|
@@ -469,7 +485,11 @@ export declare function createSvGridController<TFeatures extends TableFeatures =
|
|
|
469
485
|
readonly getCellDisplayValue: (rowId: string, columnId: string, baseValue: unknown) => any;
|
|
470
486
|
readonly getColumnAlign: typeof getColumnAlign;
|
|
471
487
|
readonly editorOptionsCache: Record<string, CellEditorOption[]>;
|
|
488
|
+
asyncEditorOptions: Record<string, CellEditorOption[]>;
|
|
489
|
+
readonly asyncEditorOptionsPending: Set<string>;
|
|
490
|
+
readonly asyncEditorColumns: Set<string>;
|
|
472
491
|
readonly getColumnEditorOptions: (column: Column<TData>, row?: Row<TData> | null | undefined) => CellEditorOption[];
|
|
492
|
+
readonly areEditorOptionsLoading: (column: Column<TData>, row?: Row<TData> | null | undefined) => boolean;
|
|
473
493
|
readonly formatListCellValue: (column: Column<TData>, value: unknown, row?: Row<TData> | null | undefined) => string;
|
|
474
494
|
readonly formatCellValue: (column: Column<TData>, value: unknown, row: Row<TData>) => string;
|
|
475
495
|
readonly getPinnedCellValue: typeof getPinnedCellValue;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { applyExcelFilter, normalizeForFilter, createColumnVirtualizer, createCoreRowModel, createExpandedRowModel, createFilteredRowModel, createGroupedRowModel, createSvelteVirtualizer, createSortedRowModel, createSvGrid, getGridCellDomId, sortFns, } from "./index";
|
|
1
|
+
import { applyExcelFilter, applyGroupAggregate, normalizeForFilter, createColumnVirtualizer, createCoreRowModel, createExpandedRowModel, createFilteredRowModel, createGroupedRowModel, createTreeRowModel, createSvelteVirtualizer, createSortedRowModel, createSvGrid, getGridCellDomId, sortFns, } from "./index";
|
|
2
2
|
import { createRowScrollScaling, resolveMaxDomHeight, } from "./virtualization/scroll-scaling";
|
|
3
3
|
import "./sv-grid-scrollbar";
|
|
4
4
|
import { computeColumnStat, formatsNeedingStats, formatNeedsStats, } from "./conditional-formatting";
|
|
@@ -17,6 +17,7 @@ import { createAlignedGrids, } from "./aligned-grids";
|
|
|
17
17
|
import { resolveColumnTypes, } from "./column-types";
|
|
18
18
|
import { computeColumnGroupMeta, hiddenLeavesForCollapse, } from "./column-groups";
|
|
19
19
|
import { resolveColumnId } from "./column-id";
|
|
20
|
+
import { buildAutoGroupColumns, insertGroupFooters, paginateGroupedRows } from "./group-display";
|
|
20
21
|
import { createGridApi, } from "./build-api";
|
|
21
22
|
import { createClipboard, } from "./clipboard";
|
|
22
23
|
import { resolveGridMessages } from "./grid-messages";
|
|
@@ -463,6 +464,10 @@ export function createSvGridController(rawProps, domIdBase) {
|
|
|
463
464
|
// consumer. Reactive (unlike sort/filter) so pageIndex/rowCount can change.
|
|
464
465
|
const externalPaginationEnabled = $derived(props.externalPagination === true);
|
|
465
466
|
const passthroughSortedRowModel = ({ rows }) => rows;
|
|
467
|
+
// Client tree data. Structural like external sort, so captured once at mount -
|
|
468
|
+
// the row-model pipeline is read before any later prop change could apply.
|
|
469
|
+
// svelte-ignore state_referenced_locally
|
|
470
|
+
const treeDataConfig = props.treeData;
|
|
466
471
|
const grid = createSvGrid({
|
|
467
472
|
get _features() {
|
|
468
473
|
return resolveEffectiveFeatures();
|
|
@@ -481,7 +486,14 @@ export function createSvGridController(rawProps, domIdBase) {
|
|
|
481
486
|
sortedRowModel: externalSortEnabled
|
|
482
487
|
? passthroughSortedRowModel
|
|
483
488
|
: createSortedRowModel(sortFns),
|
|
484
|
-
|
|
489
|
+
// Tree nesting replaces grouping when `treeData` is set - a row cannot
|
|
490
|
+
// be both a hierarchy node and bucketed under a group banner.
|
|
491
|
+
groupedRowModel: treeDataConfig
|
|
492
|
+
? createTreeRowModel({
|
|
493
|
+
parentField: treeDataConfig.parentField,
|
|
494
|
+
idField: treeDataConfig.idField,
|
|
495
|
+
})
|
|
496
|
+
: createGroupedRowModel(),
|
|
485
497
|
expandedRowModel: createExpandedRowModel(),
|
|
486
498
|
};
|
|
487
499
|
},
|
|
@@ -559,12 +571,108 @@ export function createSvGridController(rawProps, domIdBase) {
|
|
|
559
571
|
lastSeededOrder = incoming;
|
|
560
572
|
userColumnOrder = props.columnOrder ? [...props.columnOrder] : [];
|
|
561
573
|
});
|
|
574
|
+
// Declared here rather than beside the other pagination/state derivations:
|
|
575
|
+
// the auto-group column pipeline below reads it, and a `const` used above its
|
|
576
|
+
// declaration is a type error even though `$derived` is lazy enough at runtime.
|
|
577
|
+
const groupingColumns = $derived.by(() => {
|
|
578
|
+
gridStateVersion;
|
|
579
|
+
return grid.getState().grouping ?? [];
|
|
580
|
+
});
|
|
581
|
+
/**
|
|
582
|
+
* Row-grouping display mode. `groupRows` (the default) renders a full-width
|
|
583
|
+
* banner per group - the historical behaviour. `singleColumn` folds every
|
|
584
|
+
* grouping level into one synthetic column; `multipleColumns` gives each
|
|
585
|
+
* grouped field its own. Both hide the grouped SOURCE columns, since their
|
|
586
|
+
* values now live in the auto column.
|
|
587
|
+
*/
|
|
588
|
+
const groupDisplayMode = $derived(props.groupDisplayMode ?? "groupRows");
|
|
589
|
+
const autoGroupSpec = $derived(buildAutoGroupColumns(groupingColumns, groupDisplayMode));
|
|
590
|
+
/** True when group state is shown in columns rather than banner rows. */
|
|
591
|
+
const groupColumnMode = $derived(autoGroupSpec.autoColumns.length > 0);
|
|
592
|
+
/**
|
|
593
|
+
* The synthetic auto-group columns as real `Column` objects, so the rest of
|
|
594
|
+
* the pipeline (widths, pinning, virtualization, headers) treats them like
|
|
595
|
+
* any other column. They carry no `field` - their cell content is resolved
|
|
596
|
+
* from the row's group state at render time.
|
|
597
|
+
*/
|
|
598
|
+
const autoGroupColumns = $derived.by(() => {
|
|
599
|
+
if (!groupColumnMode)
|
|
600
|
+
return [];
|
|
601
|
+
const sourceById = new Map(grid.getAllColumns().map((c) => [c.id, c]));
|
|
602
|
+
return autoGroupSpec.autoColumns.map((spec) => {
|
|
603
|
+
const source = spec.field ? sourceById.get(spec.field) : undefined;
|
|
604
|
+
const sourceHeader = source?.columnDef.header;
|
|
605
|
+
const header = spec.field == null
|
|
606
|
+
? (props.autoGroupColumnHeader ?? "Group")
|
|
607
|
+
: typeof sourceHeader === "string"
|
|
608
|
+
? sourceHeader
|
|
609
|
+
: spec.field;
|
|
610
|
+
const column = {
|
|
611
|
+
id: spec.id,
|
|
612
|
+
depth: 0,
|
|
613
|
+
columnDef: {
|
|
614
|
+
header,
|
|
615
|
+
width: props.autoGroupColumnWidth ?? 220,
|
|
616
|
+
sortable: false,
|
|
617
|
+
filterable: false,
|
|
618
|
+
},
|
|
619
|
+
getCanSort: () => false,
|
|
620
|
+
getCanFilter: () => false,
|
|
621
|
+
getIsSorted: () => false,
|
|
622
|
+
getToggleSortingHandler: () => () => { },
|
|
623
|
+
};
|
|
624
|
+
return column;
|
|
625
|
+
});
|
|
626
|
+
});
|
|
627
|
+
/**
|
|
628
|
+
* What an auto-group column shows for a given row.
|
|
629
|
+
*
|
|
630
|
+
* `singleColumn` puts every level in one column, so a group row renders its
|
|
631
|
+
* own level (indented by depth) and leaf rows stay blank - the ancestry is
|
|
632
|
+
* already visible in the banner rows above.
|
|
633
|
+
*
|
|
634
|
+
* `multipleColumns` gives each grouped field a column, so a group row only
|
|
635
|
+
* writes into the column matching ITS level and leaves the others blank.
|
|
636
|
+
*
|
|
637
|
+
* Returns null when the cell should render nothing.
|
|
638
|
+
*/
|
|
639
|
+
function autoGroupCell(row, columnId) {
|
|
640
|
+
if (!isGroupRow(row))
|
|
641
|
+
return null;
|
|
642
|
+
const depth = row.depth ?? 0;
|
|
643
|
+
if (columnId !== "__autoGroup") {
|
|
644
|
+
// multipleColumns: only the column for this row's own level renders.
|
|
645
|
+
const field = groupingColumns[depth];
|
|
646
|
+
if (!field || `__group_${field}` !== columnId)
|
|
647
|
+
return null;
|
|
648
|
+
}
|
|
649
|
+
const groupingColumnId = groupingColumns[depth] ?? "";
|
|
650
|
+
const sourceColumn = grid
|
|
651
|
+
.getAllColumns()
|
|
652
|
+
.find((c) => c.id === groupingColumnId);
|
|
653
|
+
const raw = row.getCellValueByColumnId(groupingColumnId);
|
|
654
|
+
const label = sourceColumn
|
|
655
|
+
? formatCellValue(sourceColumn, raw, row)
|
|
656
|
+
: String(raw ?? "");
|
|
657
|
+
return {
|
|
658
|
+
label,
|
|
659
|
+
count: row.leafCount ?? row.subRows?.length ?? 0,
|
|
660
|
+
// singleColumn indents by level; multipleColumns already separates them.
|
|
661
|
+
depth: columnId === "__autoGroup" ? depth : 0,
|
|
662
|
+
};
|
|
663
|
+
}
|
|
562
664
|
const allColumns = $derived.by(() => {
|
|
563
665
|
let raw = grid
|
|
564
666
|
.getAllColumns()
|
|
565
667
|
.filter((column) => !hiddenColumns[column.id] &&
|
|
566
668
|
!hiddenByGroupCollapse[column.id] &&
|
|
567
|
-
!isHiddenByResponsive(column)
|
|
669
|
+
!isHiddenByResponsive(column) &&
|
|
670
|
+
// In a column display mode the grouped columns are folded into the
|
|
671
|
+
// auto column(s), so showing them too would just duplicate the value.
|
|
672
|
+
!autoGroupSpec.hiddenSourceIds.has(column.id));
|
|
673
|
+
// Auto-group columns lead, like a row header.
|
|
674
|
+
if (autoGroupColumns.length)
|
|
675
|
+
raw = [...autoGroupColumns, ...raw];
|
|
568
676
|
// Apply user reorder (if any). Unknown ids in userColumnOrder are
|
|
569
677
|
// skipped; columns not in userColumnOrder keep their original
|
|
570
678
|
// relative order after the user-ordered ones.
|
|
@@ -609,8 +717,21 @@ export function createSvGridController(rawProps, domIdBase) {
|
|
|
609
717
|
const headers = [];
|
|
610
718
|
for (const column of allColumns) {
|
|
611
719
|
const header = byId.get(column.id);
|
|
612
|
-
if (header)
|
|
720
|
+
if (header) {
|
|
613
721
|
headers.push(header);
|
|
722
|
+
continue;
|
|
723
|
+
}
|
|
724
|
+
// Auto-group columns have no engine header. Synthesize one rather than
|
|
725
|
+
// skipping: the header row indexes `headers` BY POSITION against the
|
|
726
|
+
// rendered columns, so a gap would shift every later header by one.
|
|
727
|
+
const synthetic = {
|
|
728
|
+
id: column.id,
|
|
729
|
+
isPlaceholder: false,
|
|
730
|
+
colSpan: 1,
|
|
731
|
+
column,
|
|
732
|
+
getContext: () => ({ header: synthetic, column, table: grid }),
|
|
733
|
+
};
|
|
734
|
+
headers.push(synthetic);
|
|
614
735
|
}
|
|
615
736
|
return [{ id: base[0].id, headers }];
|
|
616
737
|
});
|
|
@@ -814,10 +935,6 @@ export function createSvGridController(rawProps, domIdBase) {
|
|
|
814
935
|
directions[column.id] = column.getIsSorted();
|
|
815
936
|
return directions;
|
|
816
937
|
});
|
|
817
|
-
const groupingColumns = $derived.by(() => {
|
|
818
|
-
gridStateVersion;
|
|
819
|
-
return grid.getState().grouping ?? [];
|
|
820
|
-
});
|
|
821
938
|
const paginationState = $derived.by(() => {
|
|
822
939
|
gridStateVersion;
|
|
823
940
|
return grid.getState().pagination ?? { pageIndex: 0, pageSize: 10 };
|
|
@@ -917,15 +1034,132 @@ export function createSvGridController(rawProps, domIdBase) {
|
|
|
917
1034
|
* the full dataset rather than the current page (see the comment above
|
|
918
1035
|
* `_rowModels`).
|
|
919
1036
|
*/
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
1037
|
+
/**
|
|
1038
|
+
* Grouped pagination. `allRowsBeforePagination` interleaves group banners with
|
|
1039
|
+
* data rows, so a plain slice spends the page budget on banners - ten groups of
|
|
1040
|
+
* two at `pageSize: 10` used to show about three data rows (#73). When grouping
|
|
1041
|
+
* is active we page by DATA rows and reprint each page's ancestor banners.
|
|
1042
|
+
* Null when grouping is off, so the flat path stays a cheap slice.
|
|
1043
|
+
*/
|
|
1044
|
+
const groupedPage = $derived.by(() => {
|
|
923
1045
|
if (!paginationEnabled || externalPaginationEnabled)
|
|
924
|
-
return
|
|
1046
|
+
return null;
|
|
1047
|
+
if (!groupingColumns.length)
|
|
1048
|
+
return null;
|
|
925
1049
|
const { pageIndex, pageSize } = paginationState;
|
|
926
|
-
|
|
927
|
-
|
|
1050
|
+
return paginateGroupedRows(allRowsBeforePagination, {
|
|
1051
|
+
getDepth: (row) => row.depth ?? 0,
|
|
1052
|
+
isGroup: (row) => isGroupRow(row),
|
|
1053
|
+
// A collapsed group is the visible unit and takes a page slot; an expanded
|
|
1054
|
+
// one is a banner reprinted above its children.
|
|
1055
|
+
isExpanded: (row) => row.getIsExpanded?.() === true,
|
|
1056
|
+
pageIndex,
|
|
1057
|
+
pageSize,
|
|
1058
|
+
});
|
|
928
1059
|
});
|
|
1060
|
+
/**
|
|
1061
|
+
* The grand-total row: one synthetic row carrying each column's `aggregate`
|
|
1062
|
+
* over the whole filtered set. Shaped like a group footer so it renders
|
|
1063
|
+
* through the normal cell path - totals land under the columns they belong
|
|
1064
|
+
* to, and `getCanExpand`/`getIsExpanded` are off so nothing treats it as a
|
|
1065
|
+
* banner. Returns null when no column aggregates (nothing to total).
|
|
1066
|
+
*
|
|
1067
|
+
* Aggregates the LEAF rows: `allRowsBeforePagination` interleaves group
|
|
1068
|
+
* banners once grouping is on, and those carry per-group subtotals that
|
|
1069
|
+
* would otherwise be summed a second time.
|
|
1070
|
+
*/
|
|
1071
|
+
const buildGrandTotalRow = () => {
|
|
1072
|
+
const leaves = allRowsBeforePagination.filter((row) => !isGroupRow(row));
|
|
1073
|
+
const columns = grid.getAllColumns();
|
|
1074
|
+
const original = {};
|
|
1075
|
+
let hasAggregate = false;
|
|
1076
|
+
for (const column of columns) {
|
|
1077
|
+
const field = column.columnDef.field;
|
|
1078
|
+
const agg = column.columnDef.aggregate;
|
|
1079
|
+
if (!field || !agg)
|
|
1080
|
+
continue;
|
|
1081
|
+
hasAggregate = true;
|
|
1082
|
+
original[field] = applyGroupAggregate(agg, column.id, leaves);
|
|
1083
|
+
}
|
|
1084
|
+
if (!hasAggregate)
|
|
1085
|
+
return null;
|
|
1086
|
+
return {
|
|
1087
|
+
id: "__grand_total__",
|
|
1088
|
+
index: -1,
|
|
1089
|
+
original,
|
|
1090
|
+
depth: 0,
|
|
1091
|
+
subRows: [],
|
|
1092
|
+
leafCount: leaves.length,
|
|
1093
|
+
__groupFooter: true,
|
|
1094
|
+
__grandTotal: true,
|
|
1095
|
+
getCanExpand: () => false,
|
|
1096
|
+
getIsExpanded: () => false,
|
|
1097
|
+
toggleExpanded: () => { },
|
|
1098
|
+
getIsSelected: () => false,
|
|
1099
|
+
toggleSelected: () => { },
|
|
1100
|
+
getAllCells: () => [],
|
|
1101
|
+
getCellValueByColumnId: (columnId) => {
|
|
1102
|
+
const col = columns.find((c) => c.id === columnId);
|
|
1103
|
+
const field = col?.columnDef.field;
|
|
1104
|
+
return field && field in original ? original[field] : undefined;
|
|
1105
|
+
},
|
|
1106
|
+
};
|
|
1107
|
+
};
|
|
1108
|
+
/**
|
|
1109
|
+
* Visible rows for the current page. Applied last so filters operate on
|
|
1110
|
+
* the full dataset rather than the current page (see the comment above
|
|
1111
|
+
* `_rowModels`).
|
|
1112
|
+
*/
|
|
1113
|
+
const allRows = $derived.by(() => {
|
|
1114
|
+
const paged = (() => {
|
|
1115
|
+
const rows = allRowsBeforePagination;
|
|
1116
|
+
// External pagination: `data` already IS the current page - never slice.
|
|
1117
|
+
if (!paginationEnabled || externalPaginationEnabled)
|
|
1118
|
+
return rows;
|
|
1119
|
+
if (groupedPage)
|
|
1120
|
+
return groupedPage.rows;
|
|
1121
|
+
const { pageIndex, pageSize } = paginationState;
|
|
1122
|
+
const start = pageIndex * pageSize;
|
|
1123
|
+
return rows.slice(start, start + pageSize);
|
|
1124
|
+
})();
|
|
1125
|
+
const wantGroupFooters = Boolean(props.groupFooters) && groupingColumns.length > 0;
|
|
1126
|
+
// The grand total belongs at the END of the dataset, so it is appended only
|
|
1127
|
+
// on the last page - otherwise every page would end in a "total" that isn't
|
|
1128
|
+
// one. With pagination off (or external, where the consumer owns paging and
|
|
1129
|
+
// `data` is already the page) there is only one page to be last.
|
|
1130
|
+
const isLastPage = (() => {
|
|
1131
|
+
if (!paginationEnabled || externalPaginationEnabled)
|
|
1132
|
+
return true;
|
|
1133
|
+
const { pageIndex, pageSize } = paginationState;
|
|
1134
|
+
const total = groupedPage ? groupedPage.dataRowCount : allRowsBeforePagination.length;
|
|
1135
|
+
return pageIndex >= Math.ceil(total / pageSize) - 1;
|
|
1136
|
+
})();
|
|
1137
|
+
const wantGrandTotal = Boolean(props.grandTotalRow) && isLastPage;
|
|
1138
|
+
if (!wantGroupFooters && !wantGrandTotal)
|
|
1139
|
+
return paged;
|
|
1140
|
+
// Footers are inserted AFTER paging so they never eat page budget. A footer
|
|
1141
|
+
// is a clone of its group row, which already carries the group's aggregate
|
|
1142
|
+
// values - so it renders through the normal cell path and the totals land
|
|
1143
|
+
// under the columns they belong to, with `getCanExpand` off so nothing
|
|
1144
|
+
// treats it as a banner.
|
|
1145
|
+
return insertGroupFooters(paged, {
|
|
1146
|
+
getDepth: (row) => row.depth ?? 0,
|
|
1147
|
+
isGroup: (row) => isGroupRow(row),
|
|
1148
|
+
includeGroupFooter: wantGroupFooters,
|
|
1149
|
+
includeGrandTotalFooter: wantGrandTotal,
|
|
1150
|
+
makeGrandTotal: buildGrandTotalRow,
|
|
1151
|
+
makeFooter: (group) => ({
|
|
1152
|
+
...group,
|
|
1153
|
+
id: `${group.id}__footer`,
|
|
1154
|
+
subRows: [],
|
|
1155
|
+
__groupFooter: true,
|
|
1156
|
+
getCanExpand: () => false,
|
|
1157
|
+
getIsExpanded: () => false,
|
|
1158
|
+
}),
|
|
1159
|
+
});
|
|
1160
|
+
});
|
|
1161
|
+
/** Rows the pager divides into pages: data rows only once grouping is on. */
|
|
1162
|
+
const paginatedRowTotal = $derived(groupedPage ? groupedPage.dataRowCount : allRowsBeforePagination.length);
|
|
929
1163
|
// When a filter reduces the dataset, the stored pageIndex can point beyond
|
|
930
1164
|
// the last valid page. Reset to page 0 so the grid never shows a blank body.
|
|
931
1165
|
// Skipped for external pagination, where the consumer owns pageIndex.
|
|
@@ -933,14 +1167,14 @@ export function createSvGridController(rawProps, domIdBase) {
|
|
|
933
1167
|
if (!paginationEnabled || externalPaginationEnabled)
|
|
934
1168
|
return;
|
|
935
1169
|
const { pageIndex, pageSize } = paginationState;
|
|
936
|
-
const pageCount = Math.ceil(
|
|
1170
|
+
const pageCount = Math.ceil(paginatedRowTotal / pageSize);
|
|
937
1171
|
if (pageCount > 0 && pageIndex >= pageCount) {
|
|
938
1172
|
grid.setPagination({ pageIndex: 0, pageSize });
|
|
939
1173
|
}
|
|
940
1174
|
});
|
|
941
1175
|
// Footer-facing pagination values. In external mode they come from the
|
|
942
1176
|
// consumer-controlled props; otherwise from the local row model + state.
|
|
943
|
-
const paginationTotalRows = $derived(externalPaginationEnabled ? (props.rowCount ?? 0) :
|
|
1177
|
+
const paginationTotalRows = $derived(externalPaginationEnabled ? (props.rowCount ?? 0) : paginatedRowTotal);
|
|
944
1178
|
const paginationPageIndex = $derived(externalPaginationEnabled ? (props.pageIndex ?? 0) : paginationState.pageIndex);
|
|
945
1179
|
const paginationPageSize = $derived(externalPaginationEnabled ? (props.pageSize ?? 10) : paginationState.pageSize);
|
|
946
1180
|
const rowSelectionState = $derived.by(() => {
|
|
@@ -1893,6 +2127,72 @@ export function createSvGridController(rawProps, domIdBase) {
|
|
|
1893
2127
|
el.addEventListener("scroll-change", onHorizontal);
|
|
1894
2128
|
return () => el.removeEventListener("scroll-change", onHorizontal);
|
|
1895
2129
|
});
|
|
2130
|
+
// --- Auto row height -------------------------------------------------
|
|
2131
|
+
// Measured natural heights, keyed by row index. A plain Map (not $state):
|
|
2132
|
+
// it is written from a ResizeObserver during layout, and making it reactive
|
|
2133
|
+
// would re-run the render that is doing the measuring. `autoRowHeightVersion`
|
|
2134
|
+
// is the reactive signal instead, bumped only when a height actually changes.
|
|
2135
|
+
const measuredRowHeights = new Map();
|
|
2136
|
+
let autoRowHeightVersion = $state(0);
|
|
2137
|
+
// A per-row `rowHeight` function already supplies heights, so auto-measuring
|
|
2138
|
+
// would fight it. Fixed numbers are fine - they become the pre-measure estimate.
|
|
2139
|
+
const autoRowHeightOn = $derived(props.autoRowHeight === true && typeof props.rowHeight !== "function");
|
|
2140
|
+
const autoRowHeightFallback = $derived(typeof props.rowHeight === "number" ? props.rowHeight : 30);
|
|
2141
|
+
/** Report a row's measured height. Called by the view's measuring action.
|
|
2142
|
+
* Sub-pixel churn is ignored so a fractional layout can't loop. */
|
|
2143
|
+
function reportRowHeight(index, height) {
|
|
2144
|
+
if (!autoRowHeightOn || height <= 0)
|
|
2145
|
+
return;
|
|
2146
|
+
const prev = measuredRowHeights.get(index);
|
|
2147
|
+
if (prev !== undefined && Math.abs(prev - height) < 1)
|
|
2148
|
+
return;
|
|
2149
|
+
measuredRowHeights.set(index, height);
|
|
2150
|
+
autoRowHeightVersion += 1;
|
|
2151
|
+
}
|
|
2152
|
+
/**
|
|
2153
|
+
* Svelte action for a `<tr>` under `autoRowHeight`. Measures the row once on
|
|
2154
|
+
* mount and again whenever its content reflows (a resized column rewraps
|
|
2155
|
+
* text), reporting the natural height back to the virtualizer.
|
|
2156
|
+
*
|
|
2157
|
+
* Uses the shared rAF-deferred observer: the callback bumps state that
|
|
2158
|
+
* re-lays-out the observed element, which is exactly the pattern that trips
|
|
2159
|
+
* "ResizeObserver loop completed with undelivered notifications" when handled
|
|
2160
|
+
* synchronously.
|
|
2161
|
+
*/
|
|
2162
|
+
function measureRowHeight(node, index) {
|
|
2163
|
+
let current = index;
|
|
2164
|
+
let stop = null;
|
|
2165
|
+
const measure = () => reportRowHeight(current, node.getBoundingClientRect().height);
|
|
2166
|
+
const attach = () => {
|
|
2167
|
+
stop?.();
|
|
2168
|
+
stop = autoRowHeightOn ? observeSizeRaf(node, measure) : null;
|
|
2169
|
+
if (autoRowHeightOn)
|
|
2170
|
+
measure();
|
|
2171
|
+
};
|
|
2172
|
+
attach();
|
|
2173
|
+
return {
|
|
2174
|
+
update(next) {
|
|
2175
|
+
if (next === current)
|
|
2176
|
+
return;
|
|
2177
|
+
current = next;
|
|
2178
|
+
// A recycled row now shows different data - re-measure under its new index.
|
|
2179
|
+
measure();
|
|
2180
|
+
},
|
|
2181
|
+
destroy() {
|
|
2182
|
+
stop?.();
|
|
2183
|
+
},
|
|
2184
|
+
};
|
|
2185
|
+
}
|
|
2186
|
+
// Row index -> row identity changes when the data does, so stale measurements
|
|
2187
|
+
// would size new rows by the old ones. Drop them when the row set changes.
|
|
2188
|
+
$effect(() => {
|
|
2189
|
+
void allRows.length;
|
|
2190
|
+
void internalData;
|
|
2191
|
+
if (!autoRowHeightOn || measuredRowHeights.size === 0)
|
|
2192
|
+
return;
|
|
2193
|
+
measuredRowHeights.clear();
|
|
2194
|
+
autoRowHeightVersion += 1;
|
|
2195
|
+
});
|
|
1896
2196
|
$effect(() => {
|
|
1897
2197
|
// When containerHeight is a string (e.g. "100%") the actual pixel height
|
|
1898
2198
|
// depends on the parent layout - read it from the live scroll container.
|
|
@@ -1905,9 +2205,18 @@ export function createSvGridController(rawProps, domIdBase) {
|
|
|
1905
2205
|
? (scrollContainer?.clientHeight ?? 520)
|
|
1906
2206
|
: (props.containerHeight ?? 520);
|
|
1907
2207
|
const rh = props.rowHeight;
|
|
2208
|
+
// Auto height: read measured sizes, falling back to the fixed rowHeight as
|
|
2209
|
+
// the estimate for rows that have not rendered yet. Touch the version so a
|
|
2210
|
+
// new measurement re-runs this effect (the Map itself is not reactive).
|
|
2211
|
+
autoRowHeightVersion;
|
|
2212
|
+
const estimateSize = autoRowHeightOn
|
|
2213
|
+
? (index) => measuredRowHeights.get(index) ?? autoRowHeightFallback
|
|
2214
|
+
: typeof rh === "function"
|
|
2215
|
+
? rh
|
|
2216
|
+
: (rh ?? 30);
|
|
1908
2217
|
virtualizer.setOptions({
|
|
1909
2218
|
count: allRows.length,
|
|
1910
|
-
estimateSize
|
|
2219
|
+
estimateSize,
|
|
1911
2220
|
overscan: props.overscan ?? 8,
|
|
1912
2221
|
viewportHeight,
|
|
1913
2222
|
});
|
|
@@ -1967,6 +2276,20 @@ export function createSvGridController(rawProps, domIdBase) {
|
|
|
1967
2276
|
* are resolved on every call because they can change as other cells in
|
|
1968
2277
|
* the same row change (the whole point of cascading editors). */
|
|
1969
2278
|
const editorOptionsCache = {};
|
|
2279
|
+
// Resolved async `editorOptions`, keyed by column id (static source) or
|
|
2280
|
+
// `columnId::rowId` (per-row cascade). Reactive so a fetch landing re-renders
|
|
2281
|
+
// the open editor; `...Pending` both drives the loading state and dedupes the
|
|
2282
|
+
// request across the many synchronous render calls.
|
|
2283
|
+
let asyncEditorOptions = $state({});
|
|
2284
|
+
// Deliberately NOT reactive: this is written during render (the resolver runs
|
|
2285
|
+
// inside the template), and mutating $state there is a Svelte 5 error that
|
|
2286
|
+
// takes the whole editor down with it. Only the resolved result needs to be
|
|
2287
|
+
// reactive; the loading flag is derived from "thenable source, no result yet".
|
|
2288
|
+
const asyncEditorOptionsPending = new Set();
|
|
2289
|
+
// Columns whose per-row `editorOptions` has been observed returning a Promise.
|
|
2290
|
+
// Lets the resolver answer from cache without re-invoking the source, so an
|
|
2291
|
+
// async source fires one request per row instead of one per render.
|
|
2292
|
+
const asyncEditorColumns = new Set();
|
|
1970
2293
|
const headerSelectionState = $derived.by(() => {
|
|
1971
2294
|
gridStateVersion;
|
|
1972
2295
|
const selectable = allRows.filter((row) => !isGroupRow(row));
|
|
@@ -2503,6 +2826,9 @@ export function createSvGridController(rawProps, domIdBase) {
|
|
|
2503
2826
|
get isCellEditableAt() { return isCellEditableAt; },
|
|
2504
2827
|
get sortDirectionByColumn() { return sortDirectionByColumn; },
|
|
2505
2828
|
get groupingColumns() { return groupingColumns; },
|
|
2829
|
+
get groupDisplayMode() { return groupDisplayMode; },
|
|
2830
|
+
get groupColumnMode() { return groupColumnMode; },
|
|
2831
|
+
get autoGroupCell() { return autoGroupCell; },
|
|
2506
2832
|
get paginationState() { return paginationState; },
|
|
2507
2833
|
get externalPaginationEnabled() { return externalPaginationEnabled; },
|
|
2508
2834
|
get paginationTotalRows() { return paginationTotalRows; },
|
|
@@ -2677,6 +3003,15 @@ export function createSvGridController(rawProps, domIdBase) {
|
|
|
2677
3003
|
get rowVirtualizationEnabled() { return rowVirtualizationEnabled; },
|
|
2678
3004
|
get columnVirtualizationEnabled() { return columnVirtualizationEnabled; },
|
|
2679
3005
|
get virtualRows() { return virtualRows; },
|
|
3006
|
+
get autoRowHeightOn() { return autoRowHeightOn; },
|
|
3007
|
+
/** Svelte action: measure this row and report its natural height. */
|
|
3008
|
+
get measureRowHeight() { return measureRowHeight; },
|
|
3009
|
+
/** A row's measured height, or undefined before it has been measured.
|
|
3010
|
+
* The non-virtualized body reads this directly (it has no virtual item). */
|
|
3011
|
+
get measuredRowHeightPx() {
|
|
3012
|
+
autoRowHeightVersion;
|
|
3013
|
+
return (index) => measuredRowHeights.get(index);
|
|
3014
|
+
},
|
|
2680
3015
|
get virtualRowTotalSize() { return virtualRowTotalSize; },
|
|
2681
3016
|
get virtualRowStart() { return virtualRowStart; },
|
|
2682
3017
|
get virtualRowEnd() { return virtualRowEnd; },
|
|
@@ -2718,7 +3053,12 @@ export function createSvGridController(rawProps, domIdBase) {
|
|
|
2718
3053
|
get getCellDisplayValue() { return getCellDisplayValue; },
|
|
2719
3054
|
get getColumnAlign() { return getColumnAlign; },
|
|
2720
3055
|
get editorOptionsCache() { return editorOptionsCache; },
|
|
3056
|
+
get asyncEditorOptions() { return asyncEditorOptions; },
|
|
3057
|
+
set asyncEditorOptions(v) { asyncEditorOptions = v; },
|
|
3058
|
+
get asyncEditorOptionsPending() { return asyncEditorOptionsPending; },
|
|
3059
|
+
get asyncEditorColumns() { return asyncEditorColumns; },
|
|
2721
3060
|
get getColumnEditorOptions() { return getColumnEditorOptions; },
|
|
3061
|
+
get areEditorOptionsLoading() { return areEditorOptionsLoading; },
|
|
2722
3062
|
get formatListCellValue() { return formatListCellValue; },
|
|
2723
3063
|
get formatCellValue() { return formatCellValue; },
|
|
2724
3064
|
get getPinnedCellValue() { return getPinnedCellValue; },
|
|
@@ -2854,7 +3194,7 @@ export function createSvGridController(rawProps, domIdBase) {
|
|
|
2854
3194
|
const { onGridKeyDown, onWindowKeydown, onHeaderSortClick } = createKeyboard(ctx);
|
|
2855
3195
|
const { computeSummaries, hasRenderedColumn } = createSummaries(ctx);
|
|
2856
3196
|
const { updateFilterRow, updateFilterOperator, updateFilterMenuValue, updateFilterMenuValueTo, addFilterToken, removeFilterToken, toggleFilterToken, toggleCheckboxWithKeyboard, isColumnFiltered, closeMenus, openInSuggest, closeInSuggest, openChooseColumns, openColumnMenu, openFilterMenu, openOperatorMenu, sortColumnFromMenu, clearColumnSort, groupByColumnFromMenu, clearGroupingFromMenu, isFacetChecked, toggleFacetValue, setFacetSelection, setFilterTokens, isAllFacetsChecked, toggleAllFacets, clearColumnFilter, changePage, goToPage, setPageSize, openContextMenu, closeContextMenu, contextMenuItems, saveComment, removeComment, closeCommentEditor } = createMenus(ctx);
|
|
2857
|
-
const { cellConditionalFormat, computeRowClass, computeCellClass, computeCellTooltip, computeCellValidity, computeCellNote, getColumnEditorOptions, formatListCellValue, formatCellValue, formatPinnedValue, computePinnedCellClass } = createCellRender(ctx);
|
|
3197
|
+
const { cellConditionalFormat, computeRowClass, computeCellClass, computeCellTooltip, computeCellValidity, computeCellNote, getColumnEditorOptions, areEditorOptionsLoading, formatListCellValue, formatCellValue, formatPinnedValue, computePinnedCellClass } = createCellRender(ctx);
|
|
2858
3198
|
const { isCellEditable, isCellEditableAt, getRowColumnValue, getCellDisplayValue, startEditingWithChar, startEditing, stopEditing, startFullRowEdit, setFullRowDraft, commitFullRowEdit, cancelFullRowEdit, saveEditingCell, applyHistoryStep, updateEditingCellValue, onEditorKeyDown, commitAndMoveByTab, focusOnMount, onCellDoubleClick, pasteFromClipboard, onGridPaste } = createEditing(ctx);
|
|
2859
3199
|
const { isRowSelected, toggleRowSelectionById, toggleSelectAllRows, setActiveCell, scrollActiveCellIntoView, setSelection, extendSelection, isCellInSelectedRange, getCellRangeEdges, getSelectionRects, isInFillPreview, fillMarqueeEdges, findColumnById, onCellPointerDown, onCellPointerEnter, endDragSelection, onWindowPointerMove, onCellClick, emitCellDoubleClick } = createSelection(ctx);
|
|
2860
3200
|
const { cellPinStyle, isColumnPinned, getCurrentColumnOrder, emitColumnOrder, setColumnOrderInternal, applyColumnDrop, onColumnHeaderDragStart, onColumnHeaderDragOver, onColumnHeaderDragLeave, onColumnHeaderDrop, onColumnHeaderDragEnd, pinColumnLeft, pinColumnRight, unpinColumn, toggleColumnVisibleInPanel, moveColumnInPanel, toggleGroupInPanel, getColumnBaseWidth, getColumnWidth, startColumnResize, onColumnResizeMove, endColumnResize, measureText, autosizeColumn, autosizeAllColumns, resetColumns } = createColumns(ctx);
|