@svgrid/grid 1.1.0 → 1.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/FlexRender.svelte +96 -96
- package/dist/GridMenus.svelte +205 -127
- package/dist/SvGrid.controller.svelte.d.ts +44 -1
- package/dist/SvGrid.controller.svelte.js +240 -44
- package/dist/SvGrid.css +325 -22
- package/dist/SvGrid.helpers.test.d.ts +1 -0
- package/dist/SvGrid.helpers.test.js +298 -0
- package/dist/SvGrid.svelte +729 -203
- package/dist/SvGrid.types.d.ts +91 -4
- package/dist/aligned-grids.d.ts +6 -0
- package/dist/aligned-grids.js +84 -0
- package/dist/aligned-grids.test.d.ts +1 -0
- package/dist/aligned-grids.test.js +75 -0
- package/dist/build-api.coverage.test.d.ts +20 -0
- package/dist/build-api.coverage.test.js +505 -0
- package/dist/build-api.js +61 -31
- package/dist/cell-render.test.d.ts +1 -0
- package/dist/cell-render.test.js +338 -0
- package/dist/cell-values.d.ts +1 -1
- package/dist/cell-values.js +7 -7
- package/dist/chart-export.test.d.ts +1 -0
- package/dist/chart-export.test.js +302 -0
- package/dist/chart.coverage.test.d.ts +1 -0
- package/dist/chart.coverage.test.js +748 -0
- package/dist/clipboard.js +88 -24
- package/dist/clipboard.test.d.ts +1 -0
- package/dist/clipboard.test.js +700 -0
- package/dist/collaboration.coverage.test.d.ts +1 -0
- package/dist/collaboration.coverage.test.js +200 -0
- package/dist/column-groups.d.ts +19 -0
- package/dist/column-groups.js +62 -0
- package/dist/column-groups.test.d.ts +1 -0
- package/dist/column-groups.test.js +56 -0
- package/dist/column-types.d.ts +10 -0
- package/dist/column-types.js +63 -0
- package/dist/column-types.test.d.ts +1 -0
- package/dist/column-types.test.js +62 -0
- package/dist/columns.test.d.ts +1 -0
- package/dist/columns.test.js +625 -0
- package/dist/core.d.ts +86 -1
- package/dist/core.js +2 -2
- package/dist/editing.d.ts +7 -0
- package/dist/editing.js +191 -5
- package/dist/editing.test.d.ts +1 -0
- package/dist/editing.test.js +732 -0
- package/dist/editors/cell-editors.coverage.test.d.ts +1 -0
- package/dist/editors/cell-editors.coverage.test.js +139 -0
- package/dist/facet-buckets.test.d.ts +1 -0
- package/dist/facet-buckets.test.js +296 -0
- package/dist/filter-operators.test.d.ts +1 -0
- package/dist/filter-operators.test.js +135 -0
- package/dist/hyperformula-adapter.test.d.ts +1 -0
- package/dist/hyperformula-adapter.test.js +205 -0
- package/dist/index.d.ts +5 -2
- package/dist/index.js +4 -1
- package/dist/keyboard-handlers.coverage.test.d.ts +1 -0
- package/dist/keyboard-handlers.coverage.test.js +495 -0
- package/dist/keyboard-handlers.js +7 -2
- package/dist/menus.js +1 -0
- package/dist/menus.test.d.ts +1 -0
- package/dist/menus.test.js +560 -0
- package/dist/named-views.coverage.test.d.ts +1 -0
- package/dist/named-views.coverage.test.js +180 -0
- package/dist/row-drag.d.ts +49 -0
- package/dist/row-drag.js +221 -0
- package/dist/row-drag.test.d.ts +1 -0
- package/dist/row-drag.test.js +142 -0
- package/dist/row-resize.test.d.ts +1 -0
- package/dist/row-resize.test.js +329 -0
- package/dist/scroll-sync.js +3 -0
- package/dist/scroll-sync.test.d.ts +1 -0
- package/dist/scroll-sync.test.js +290 -0
- package/dist/selection.d.ts +7 -1
- package/dist/selection.js +76 -36
- package/dist/selection.multi-range.test.d.ts +1 -0
- package/dist/selection.multi-range.test.js +55 -0
- package/dist/selection.test.d.ts +1 -0
- package/dist/selection.test.js +647 -0
- package/dist/server-data-source.coverage.test.d.ts +1 -0
- package/dist/server-data-source.coverage.test.js +154 -0
- package/dist/spreadsheet.d.ts +30 -0
- package/dist/spreadsheet.js +48 -0
- package/dist/spreadsheet.test.d.ts +1 -0
- package/dist/spreadsheet.test.js +446 -0
- package/dist/summaries.js +4 -4
- package/dist/sv-grid-scrollbar.js +13 -1
- package/dist/svgrid-wrapper.types.d.ts +19 -0
- package/dist/svgrid.behavior.test.js +20 -0
- package/dist/svgrid.interaction.test.js +31 -0
- package/dist/svgrid.new-features.wrapper.test.js +34 -2
- package/dist/test-setup.js +9 -3
- package/dist/virtualization/scroll-scaling.d.ts +17 -0
- package/dist/virtualization/scroll-scaling.js +35 -0
- package/dist/virtualization/scroll-scaling.test.js +42 -1
- package/package.json +2 -1
- package/src/FlexRender.svelte +96 -96
- package/src/GridMenus.svelte +205 -127
- package/src/SvGrid.controller.svelte.ts +204 -36
- package/src/SvGrid.css +277 -12
- package/src/SvGrid.svelte +727 -205
- package/src/SvGrid.types.ts +85 -4
- package/src/a11y.contract.test.ts +49 -49
- package/src/a11y.test.ts +59 -59
- package/src/a11y.ts +59 -59
- package/src/aligned-grids.test.ts +80 -0
- package/src/aligned-grids.ts +87 -0
- package/src/build-api.ts +43 -23
- package/src/cell-formatting.ts +169 -169
- package/src/cell-values.ts +4 -4
- package/src/clipboard.test.ts +49 -0
- package/src/clipboard.ts +51 -23
- package/src/column-groups.test.ts +59 -0
- package/src/column-groups.ts +80 -0
- package/src/column-types.test.ts +68 -0
- package/src/column-types.ts +82 -0
- package/src/core.performance.test.ts +30 -30
- package/src/core.ts +1077 -999
- package/src/createGrid.svelte.ts +42 -42
- package/src/createGrid.test.ts +10 -10
- package/src/createGridState.svelte.ts +17 -17
- package/src/editing.ts +161 -5
- package/src/flex-render.ts +3 -3
- package/src/index.ts +208 -196
- package/src/keyboard.test.ts +59 -59
- package/src/keyboard.ts +97 -97
- package/src/menus.ts +1 -0
- package/src/merge-objects.ts +48 -48
- package/src/render-component.ts +28 -28
- package/src/row-drag.test.ts +168 -0
- package/src/row-drag.ts +255 -0
- package/src/scroll-sync.ts +2 -0
- package/src/selection.multi-range.test.ts +61 -0
- package/src/selection.ts +71 -37
- package/src/spreadsheet.test.ts +46 -2
- package/src/spreadsheet.ts +58 -0
- package/src/static-functions.ts +11 -11
- package/src/subscribe.ts +38 -38
- package/src/summaries.ts +4 -4
- package/src/svgrid-wrapper.types.ts +412 -393
- package/src/svgrid.features.test.ts +157 -157
- package/src/svgrid.new-features.wrapper.test.ts +2 -2
- package/src/svgrid.wrapper.test.ts +40 -40
- package/src/virtualization/column-virtualizer.test.ts +27 -27
- package/src/virtualization/column-virtualizer.ts +30 -30
- package/src/virtualization/svelte-virtualizer.svelte.ts +26 -26
- package/src/virtualization/types.ts +30 -30
- package/src/virtualization/virtualizer.test.ts +47 -47
- package/src/virtualization/virtualizer.ts +296 -296
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
import { computeColumnGroupMeta, hiddenLeavesForCollapse } from './column-groups'
|
|
3
|
+
|
|
4
|
+
// A group "Q1" with an always-on Total plus Jan/Feb that only show when open.
|
|
5
|
+
const columns = [
|
|
6
|
+
{ field: 'name' },
|
|
7
|
+
{
|
|
8
|
+
id: 'q1',
|
|
9
|
+
header: 'Q1',
|
|
10
|
+
columns: [
|
|
11
|
+
{ field: 'q1Total' },
|
|
12
|
+
{ field: 'jan', columnGroupShow: 'open' },
|
|
13
|
+
{ field: 'feb', columnGroupShow: 'open' },
|
|
14
|
+
],
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
id: 'q2',
|
|
18
|
+
header: 'Q2',
|
|
19
|
+
openByDefault: true,
|
|
20
|
+
columns: [
|
|
21
|
+
{ field: 'q2Total', columnGroupShow: 'closed' },
|
|
22
|
+
{ field: 'apr', columnGroupShow: 'open' },
|
|
23
|
+
],
|
|
24
|
+
},
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
describe('computeColumnGroupMeta', () => {
|
|
28
|
+
it('marks groups with columnGroupShow children as collapsible', () => {
|
|
29
|
+
const meta = computeColumnGroupMeta(columns)
|
|
30
|
+
expect([...meta.collapsibleGroupIds].sort()).toEqual(['q1', 'q2'])
|
|
31
|
+
expect(meta.defaultOpen.get('q1')).toBe(false)
|
|
32
|
+
expect(meta.defaultOpen.get('q2')).toBe(true)
|
|
33
|
+
})
|
|
34
|
+
it('maps controlled leaves to their group + show mode', () => {
|
|
35
|
+
const meta = computeColumnGroupMeta(columns)
|
|
36
|
+
expect(meta.leafControl.get('jan')).toEqual({ groupId: 'q1', show: 'open' })
|
|
37
|
+
expect(meta.leafControl.get('q2Total')).toEqual({ groupId: 'q2', show: 'closed' })
|
|
38
|
+
// untagged always-on column is not controlled
|
|
39
|
+
expect(meta.leafControl.has('q1Total')).toBe(false)
|
|
40
|
+
expect(meta.leafControl.has('name')).toBe(false)
|
|
41
|
+
})
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
describe('hiddenLeavesForCollapse', () => {
|
|
45
|
+
const meta = computeColumnGroupMeta(columns)
|
|
46
|
+
it('hides open-columns while collapsed, shows them while expanded', () => {
|
|
47
|
+
const collapsed = new Set(['q1'])
|
|
48
|
+
const hidden = hiddenLeavesForCollapse(meta, collapsed)
|
|
49
|
+
expect(hidden.jan).toBe(true)
|
|
50
|
+
expect(hidden.feb).toBe(true)
|
|
51
|
+
expect(hidden.q1Total).toBeUndefined() // always on
|
|
52
|
+
})
|
|
53
|
+
it('hides closed-columns while expanded', () => {
|
|
54
|
+
const collapsed = new Set<string>() // q2 expanded
|
|
55
|
+
const hidden = hiddenLeavesForCollapse(meta, collapsed)
|
|
56
|
+
expect(hidden.q2Total).toBe(true) // 'closed' hides when expanded
|
|
57
|
+
expect(hidden.apr).toBeUndefined() // 'open' shows when expanded
|
|
58
|
+
})
|
|
59
|
+
})
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// Collapsible column groups (AG-Grid `columnGroupShow`). A column group can
|
|
2
|
+
// carry a collapse toggle: its child columns tagged `columnGroupShow: 'open'`
|
|
3
|
+
// show only when the group is expanded, `'closed'` show only when collapsed,
|
|
4
|
+
// and untagged children always show.
|
|
5
|
+
//
|
|
6
|
+
// This module derives, from the user's column tree, the pure metadata the
|
|
7
|
+
// controller needs: which groups are collapsible, their default state, and each
|
|
8
|
+
// controlled leaf's group + show-mode. The controller turns that into a hidden
|
|
9
|
+
// map (merged into column visibility) AND feeds the same hidden set into the
|
|
10
|
+
// group-header colspan/width math, so headers stay aligned with the leaves.
|
|
11
|
+
|
|
12
|
+
export type ColumnGroupShow = "open" | "closed";
|
|
13
|
+
|
|
14
|
+
export type ColumnGroupMeta = {
|
|
15
|
+
/** Group ids that render a collapse toggle. */
|
|
16
|
+
collapsibleGroupIds: Set<string>;
|
|
17
|
+
/** Group id -> whether it starts expanded (openByDefault). */
|
|
18
|
+
defaultOpen: Map<string, boolean>;
|
|
19
|
+
/** Leaf column id -> the group controlling it + its show mode. */
|
|
20
|
+
leafControl: Map<string, { groupId: string; show: ColumnGroupShow }>;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
// Mirror the id resolution used by the group-header derivation so group ids and
|
|
24
|
+
// leaf ids line up across both.
|
|
25
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
26
|
+
function idOf(def: any, parentId: string | undefined, ix: number): string {
|
|
27
|
+
return def.id ?? def.field ?? `${parentId ?? "col"}_d_${ix}`;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
31
|
+
export function computeColumnGroupMeta(columns: ReadonlyArray<any>): ColumnGroupMeta {
|
|
32
|
+
const collapsibleGroupIds = new Set<string>();
|
|
33
|
+
const defaultOpen = new Map<string, boolean>();
|
|
34
|
+
const leafControl = new Map<string, { groupId: string; show: ColumnGroupShow }>();
|
|
35
|
+
|
|
36
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
37
|
+
function walk(defs: ReadonlyArray<any>, parentId: string | undefined, controllingGroup: string | undefined) {
|
|
38
|
+
defs.forEach((def, ix) => {
|
|
39
|
+
const id = idOf(def, parentId, ix);
|
|
40
|
+
if (def.columns?.length) {
|
|
41
|
+
// A group is collapsible when any DIRECT child declares columnGroupShow.
|
|
42
|
+
const collapsible = def.columns.some(
|
|
43
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
44
|
+
(c: any) => c.columnGroupShow === "open" || c.columnGroupShow === "closed",
|
|
45
|
+
);
|
|
46
|
+
if (collapsible) {
|
|
47
|
+
collapsibleGroupIds.add(id);
|
|
48
|
+
defaultOpen.set(id, def.openByDefault === true);
|
|
49
|
+
}
|
|
50
|
+
walk(def.columns, id, collapsible ? id : controllingGroup);
|
|
51
|
+
} else {
|
|
52
|
+
const show = def.columnGroupShow;
|
|
53
|
+
if ((show === "open" || show === "closed") && controllingGroup) {
|
|
54
|
+
leafControl.set(id, { groupId: controllingGroup, show });
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
walk(columns, undefined, undefined);
|
|
61
|
+
return { collapsibleGroupIds, defaultOpen, leafControl };
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Which leaf ids are hidden right now, given the set of collapsed group ids.
|
|
66
|
+
* `'open'` leaves hide while their group is collapsed; `'closed'` leaves hide
|
|
67
|
+
* while it is expanded.
|
|
68
|
+
*/
|
|
69
|
+
export function hiddenLeavesForCollapse(
|
|
70
|
+
meta: ColumnGroupMeta,
|
|
71
|
+
collapsed: ReadonlySet<string>,
|
|
72
|
+
): Record<string, boolean> {
|
|
73
|
+
const hidden: Record<string, boolean> = {};
|
|
74
|
+
for (const [leafId, ctrl] of meta.leafControl) {
|
|
75
|
+
const isCollapsed = collapsed.has(ctrl.groupId);
|
|
76
|
+
const hide = ctrl.show === "open" ? isCollapsed : !isCollapsed;
|
|
77
|
+
if (hide) hidden[leafId] = true;
|
|
78
|
+
}
|
|
79
|
+
return hidden;
|
|
80
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
import { inferCellDataType, resolveColumnTypes } from './column-types'
|
|
3
|
+
|
|
4
|
+
describe('inferCellDataType', () => {
|
|
5
|
+
it('classifies primitives', () => {
|
|
6
|
+
expect(inferCellDataType(42)).toBe('number')
|
|
7
|
+
expect(inferCellDataType(true)).toBe('boolean')
|
|
8
|
+
expect(inferCellDataType(new Date())).toBe('date')
|
|
9
|
+
expect(inferCellDataType('2026-06-27')).toBe('dateString')
|
|
10
|
+
expect(inferCellDataType('2026-06-27T10:00:00Z')).toBe('dateString')
|
|
11
|
+
expect(inferCellDataType('hello')).toBe('text')
|
|
12
|
+
})
|
|
13
|
+
it('returns undefined for null/undefined so nothing is forced', () => {
|
|
14
|
+
expect(inferCellDataType(null)).toBeUndefined()
|
|
15
|
+
expect(inferCellDataType(undefined)).toBeUndefined()
|
|
16
|
+
})
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
describe('resolveColumnTypes', () => {
|
|
20
|
+
it('maps explicit cellDataType to editorType + format', () => {
|
|
21
|
+
const cols = [
|
|
22
|
+
{ field: 'name', cellDataType: 'text' },
|
|
23
|
+
{ field: 'age', cellDataType: 'number' },
|
|
24
|
+
{ field: 'active', cellDataType: 'boolean' },
|
|
25
|
+
{ field: 'joined', cellDataType: 'date' },
|
|
26
|
+
{ field: 'iso', cellDataType: 'dateString' },
|
|
27
|
+
]
|
|
28
|
+
const out = resolveColumnTypes(cols, undefined, false)
|
|
29
|
+
expect(out[0].editorType).toBe('text')
|
|
30
|
+
expect(out[1].editorType).toBe('number')
|
|
31
|
+
expect(out[2].editorType).toBe('checkbox')
|
|
32
|
+
expect(out[3].editorType).toBe('date')
|
|
33
|
+
expect(out[3].format).toEqual({ type: 'date' })
|
|
34
|
+
expect(out[4].editorType).toBe('date')
|
|
35
|
+
expect(out[4].format).toBeUndefined()
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
it('never overrides an explicit editorType or format', () => {
|
|
39
|
+
const cols = [{ field: 'age', cellDataType: 'number', editorType: 'text', format: { type: 'currency' } }]
|
|
40
|
+
const out = resolveColumnTypes(cols, undefined, false)
|
|
41
|
+
expect(out[0].editorType).toBe('text')
|
|
42
|
+
expect(out[0].format).toEqual({ type: 'currency' })
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
it('infers from a sample row only when infer=true and nothing is declared', () => {
|
|
46
|
+
const cols = [
|
|
47
|
+
{ field: 'age' },
|
|
48
|
+
{ field: 'name' },
|
|
49
|
+
{ field: 'when' },
|
|
50
|
+
{ field: 'flag' },
|
|
51
|
+
]
|
|
52
|
+
const sample = { age: 30, name: 'Ada', when: '2026-01-02', flag: false }
|
|
53
|
+
const off = resolveColumnTypes(cols, sample, false)
|
|
54
|
+
expect(off[0].editorType).toBeUndefined() // inference off
|
|
55
|
+
|
|
56
|
+
const on = resolveColumnTypes(cols, sample, true)
|
|
57
|
+
expect(on[0].editorType).toBe('number')
|
|
58
|
+
expect(on[1].editorType).toBe('text')
|
|
59
|
+
expect(on[2].editorType).toBe('date')
|
|
60
|
+
expect(on[3].editorType).toBe('checkbox')
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
it('recurses into header groups', () => {
|
|
64
|
+
const cols = [{ header: 'Group', columns: [{ field: 'age', cellDataType: 'number' }] }]
|
|
65
|
+
const out = resolveColumnTypes(cols, undefined, false)
|
|
66
|
+
expect(out[0].columns[0].editorType).toBe('number')
|
|
67
|
+
})
|
|
68
|
+
})
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
// cellDataType resolution. A column's `cellDataType` (or grid-level
|
|
2
|
+
// `inferColumnTypes`) is a high-level shorthand that fills in `editorType`,
|
|
3
|
+
// `format`, and - transitively, via `getColumnAlign` and the filter-operator
|
|
4
|
+
// tables, which both key off `editorType` - alignment and filter operators.
|
|
5
|
+
//
|
|
6
|
+
// Anything set explicitly on the ColumnDef always wins; this only fills gaps.
|
|
7
|
+
// Resolution happens once when columns are ingested, producing plain ColumnDef
|
|
8
|
+
// objects, so every downstream reader (editing, filtering, formatting,
|
|
9
|
+
// alignment) sees a normal column with no new code paths.
|
|
10
|
+
export type CellDataType = "text" | "number" | "boolean" | "date" | "dateString";
|
|
11
|
+
|
|
12
|
+
type TypeDefaults = {
|
|
13
|
+
editorType: string;
|
|
14
|
+
format?: { type: string };
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
function defaultsFor(dt: CellDataType): TypeDefaults {
|
|
18
|
+
switch (dt) {
|
|
19
|
+
case "number":
|
|
20
|
+
return { editorType: "number" };
|
|
21
|
+
case "boolean":
|
|
22
|
+
return { editorType: "checkbox" };
|
|
23
|
+
case "date":
|
|
24
|
+
return { editorType: "date", format: { type: "date" } };
|
|
25
|
+
case "dateString":
|
|
26
|
+
// ISO date strings ('2026-06-27') - date editor, but no Date coercion.
|
|
27
|
+
return { editorType: "date" };
|
|
28
|
+
case "text":
|
|
29
|
+
default:
|
|
30
|
+
return { editorType: "text" };
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Best-effort inference of a column's data type from a sample value. */
|
|
35
|
+
export function inferCellDataType(value: unknown): CellDataType | undefined {
|
|
36
|
+
if (value == null) return undefined;
|
|
37
|
+
if (typeof value === "number" && Number.isFinite(value)) return "number";
|
|
38
|
+
if (typeof value === "boolean") return "boolean";
|
|
39
|
+
if (value instanceof Date) return "date";
|
|
40
|
+
if (typeof value === "string" && /^\d{4}-\d{2}-\d{2}([T\s]|$)/.test(value)) {
|
|
41
|
+
return "dateString";
|
|
42
|
+
}
|
|
43
|
+
return "text";
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Resolve `cellDataType` (explicit or, when `infer` is on, inferred from
|
|
48
|
+
* `sampleRow`) into concrete `editorType` / `format` defaults. Explicit fields
|
|
49
|
+
* on the ColumnDef are preserved. Columns that resolve to no type are returned
|
|
50
|
+
* untouched. Nested column groups are resolved recursively.
|
|
51
|
+
*/
|
|
52
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
53
|
+
export function resolveColumnTypes(
|
|
54
|
+
columns: ReadonlyArray<any>,
|
|
55
|
+
sampleRow: unknown,
|
|
56
|
+
infer: boolean,
|
|
57
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
58
|
+
): any[] {
|
|
59
|
+
return columns.map((col) => {
|
|
60
|
+
// Recurse into header groups first.
|
|
61
|
+
if (col.columns && col.columns.length) {
|
|
62
|
+
return { ...col, columns: resolveColumnTypes(col.columns, sampleRow, infer) };
|
|
63
|
+
}
|
|
64
|
+
// An explicit editorType means the author already chose - don't override.
|
|
65
|
+
const hasExplicitEditor = col.editorType != null;
|
|
66
|
+
let dt: CellDataType | undefined = col.cellDataType;
|
|
67
|
+
if (!dt && infer && !hasExplicitEditor && sampleRow != null) {
|
|
68
|
+
const field = col.field;
|
|
69
|
+
const raw =
|
|
70
|
+
col.fieldFn?.(sampleRow) ??
|
|
71
|
+
(typeof field === "string" ? (sampleRow as Record<string, unknown>)[field] : undefined);
|
|
72
|
+
dt = inferCellDataType(raw);
|
|
73
|
+
}
|
|
74
|
+
if (!dt) return col;
|
|
75
|
+
const d = defaultsFor(dt);
|
|
76
|
+
return {
|
|
77
|
+
...col,
|
|
78
|
+
editorType: col.editorType ?? d.editorType,
|
|
79
|
+
format: col.format ?? d.format,
|
|
80
|
+
};
|
|
81
|
+
});
|
|
82
|
+
}
|
|
@@ -1,30 +1,30 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest'
|
|
2
|
-
import { createCoreRowModel, createSortedRowModel, createSvGrid, sortFns, tableFeatures } from './index'
|
|
3
|
-
|
|
4
|
-
describe('core performance smoke', () => {
|
|
5
|
-
it('handles large synthetic shape with bounded row model call', () => {
|
|
6
|
-
const columns = Array.from({ length: 50 }, (_, index) => ({
|
|
7
|
-
field: `c${index}`,
|
|
8
|
-
editorType: 'number' as const,
|
|
9
|
-
}))
|
|
10
|
-
const data = Array.from({ length: 5000 }, (_, rowIndex) => {
|
|
11
|
-
const row: Record<string, number> = {}
|
|
12
|
-
for (let col = 0; col < 50; col += 1) row[`c${col}`] = rowIndex + col
|
|
13
|
-
return row
|
|
14
|
-
})
|
|
15
|
-
const grid = createSvGrid({
|
|
16
|
-
_features: tableFeatures({}),
|
|
17
|
-
_rowModels: {
|
|
18
|
-
coreRowModel: createCoreRowModel(),
|
|
19
|
-
sortedRowModel: createSortedRowModel(sortFns),
|
|
20
|
-
},
|
|
21
|
-
columns,
|
|
22
|
-
data,
|
|
23
|
-
state: { sorting: [{ id: 'c0', desc: true }, { id: 'c1', desc: false }] },
|
|
24
|
-
})
|
|
25
|
-
|
|
26
|
-
const rows = grid.getRowModel().rows
|
|
27
|
-
expect(rows.length).toBe(5000)
|
|
28
|
-
expect(rows[0]?.getCellValueByColumnId('c0')).toBe(4999)
|
|
29
|
-
})
|
|
30
|
-
})
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
import { createCoreRowModel, createSortedRowModel, createSvGrid, sortFns, tableFeatures } from './index'
|
|
3
|
+
|
|
4
|
+
describe('core performance smoke', () => {
|
|
5
|
+
it('handles large synthetic shape with bounded row model call', () => {
|
|
6
|
+
const columns = Array.from({ length: 50 }, (_, index) => ({
|
|
7
|
+
field: `c${index}`,
|
|
8
|
+
editorType: 'number' as const,
|
|
9
|
+
}))
|
|
10
|
+
const data = Array.from({ length: 5000 }, (_, rowIndex) => {
|
|
11
|
+
const row: Record<string, number> = {}
|
|
12
|
+
for (let col = 0; col < 50; col += 1) row[`c${col}`] = rowIndex + col
|
|
13
|
+
return row
|
|
14
|
+
})
|
|
15
|
+
const grid = createSvGrid({
|
|
16
|
+
_features: tableFeatures({}),
|
|
17
|
+
_rowModels: {
|
|
18
|
+
coreRowModel: createCoreRowModel(),
|
|
19
|
+
sortedRowModel: createSortedRowModel(sortFns),
|
|
20
|
+
},
|
|
21
|
+
columns,
|
|
22
|
+
data,
|
|
23
|
+
state: { sorting: [{ id: 'c0', desc: true }, { id: 'c1', desc: false }] },
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
const rows = grid.getRowModel().rows
|
|
27
|
+
expect(rows.length).toBe(5000)
|
|
28
|
+
expect(rows[0]?.getCellValueByColumnId('c0')).toBe(4999)
|
|
29
|
+
})
|
|
30
|
+
})
|