@svgrid/grid 2.6.19 → 2.6.21
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/SvGrid.controller.svelte.d.ts +1 -0
- package/dist/SvGrid.controller.svelte.js +64 -2
- package/dist/SvGrid.svelte +2 -1
- package/dist/SvGrid.types.d.ts +150 -0
- package/dist/ai.d.ts +28 -0
- package/dist/ai.js +6 -0
- package/dist/cdn/{GridMenus-B0F9iBrG.js → GridMenus-BfTAKn84.js} +1 -1
- package/dist/cdn/{GridMenus-IHK_l7m6.js → GridMenus-C3bJd7w8.js} +1 -1
- package/dist/cdn/{src-Cd0tearp.js → src-BYq-qyrp.js} +1012 -999
- package/dist/cdn/{src-B1TdiyS8.js → src-DBel9wRZ.js} +1324 -1311
- package/dist/cdn/svgrid.js +1 -1
- package/dist/cdn/svgrid.svelte-external.js +1 -1
- package/dist/cdn/validate-_CDJzgIo.js +75 -0
- package/dist/cell-formatting.d.ts +2 -0
- package/dist/cell-formatting.js +2 -0
- package/dist/chart-export.d.ts +1 -0
- package/dist/chart.d.ts +31 -5
- package/dist/chart.js +9 -3
- package/dist/core.d.ts +197 -0
- package/dist/core.js +72 -0
- package/dist/createTree.svelte.d.ts +3 -0
- package/dist/createTree.svelte.js +1 -0
- package/dist/datetime/date-core.d.ts +2 -0
- package/dist/datetime/date-restrict.d.ts +1 -0
- package/dist/datetime/timezone.d.ts +1 -0
- package/dist/dock-manager-model.d.ts +3 -0
- package/dist/dock-manager-model.js +1 -0
- package/dist/dock-model.d.ts +6 -0
- package/dist/dock-model.js +3 -0
- package/dist/editor-contract.d.ts +1 -0
- package/dist/list-option.d.ts +1 -0
- package/dist/positioning.d.ts +2 -0
- package/dist/scheduler-ical.d.ts +1 -0
- package/dist/scheduler-model.d.ts +1 -0
- package/dist/summaries.js +22 -0
- package/dist/svgrid-wrapper.types.d.ts +5 -0
- package/dist/toast-store.svelte.d.ts +4 -0
- package/dist/validate.d.ts +50 -0
- package/dist/validate.js +187 -0
- package/package.json +4 -1
- package/src/SvGrid.controller.svelte.ts +68 -2
- package/src/SvGrid.svelte +2 -1
- package/src/SvGrid.types.ts +150 -0
- package/src/ai.ts +28 -0
- package/src/cell-formatting.ts +2 -0
- package/src/chart-export.ts +1 -0
- package/src/chart.ts +31 -5
- package/src/core.ts +207 -0
- package/src/createTree.svelte.ts +3 -0
- package/src/datetime/date-core.ts +2 -0
- package/src/datetime/date-restrict.ts +1 -0
- package/src/datetime/timezone.ts +1 -0
- package/src/dock-manager-model.ts +3 -0
- package/src/dock-model.ts +6 -0
- package/src/editor-contract.ts +1 -0
- package/src/list-option.ts +1 -0
- package/src/positioning.ts +2 -0
- package/src/scheduler-ical.ts +1 -0
- package/src/scheduler-model.ts +1 -0
- package/src/summaries.ts +21 -0
- package/src/svgrid-wrapper.types.ts +5 -0
- package/src/svgrid.summaries.test.ts +217 -0
- package/src/toast-store.svelte.ts +4 -0
- package/src/validate.test.ts +207 -0
- package/src/validate.ts +269 -0
package/src/core.ts
CHANGED
|
@@ -1,30 +1,79 @@
|
|
|
1
1
|
import type { SparklineConfig } from './sparkline'
|
|
2
2
|
import { resolveColumnId } from './column-id'
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* The constraint every row type satisfies: an object keyed by string. Your own
|
|
6
|
+
* row type (`type Person = { name: string }`) is what flows through the generics
|
|
7
|
+
* below; this is only the lower bound they are declared against.
|
|
8
|
+
*/
|
|
4
9
|
export type RowData = Record<string, unknown>
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* A new value, or a function that derives it from the previous one - the shape
|
|
13
|
+
* every `set*` on the grid accepts, so callers can update state without first
|
|
14
|
+
* reading it.
|
|
15
|
+
*
|
|
16
|
+
* api.setSorting([{ id: 'name', desc: false }])
|
|
17
|
+
* api.setSorting((prev) => [...prev, { id: 'age', desc: true }])
|
|
18
|
+
*/
|
|
5
19
|
export type Updater<T> = T | ((prev: T) => T)
|
|
20
|
+
|
|
21
|
+
/** Active sort clauses, outermost first. `desc: false` is ascending. */
|
|
6
22
|
export type SortingState = Array<{ id: string; desc: boolean }>
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* One column's filter: the column `id`, the `value` being matched, and
|
|
26
|
+
* optionally which comparison to use. `fn` defaults to the column's own type -
|
|
27
|
+
* see {@link filterFns} for the available names.
|
|
28
|
+
*/
|
|
7
29
|
export type ColumnFilter = { id: string; value: unknown; fn?: keyof typeof filterFns }
|
|
30
|
+
|
|
31
|
+
/** Every active column filter. A column with no entry here is unfiltered. */
|
|
8
32
|
export type ColumnFiltersState = Array<ColumnFilter>
|
|
33
|
+
|
|
34
|
+
/** Current page position. `pageIndex` is 0-based, so page 1 is index 0. */
|
|
9
35
|
export type PaginationState = { pageIndex: number; pageSize: number }
|
|
36
|
+
|
|
37
|
+
/** Column ids the rows are grouped by, outermost first. */
|
|
10
38
|
export type GroupingState = Array<string>
|
|
39
|
+
|
|
40
|
+
/** Which rows are expanded, keyed by row id. Absent means collapsed. */
|
|
11
41
|
export type ExpandedState = Record<string, boolean>
|
|
42
|
+
|
|
43
|
+
/** Which rows are selected, keyed by row id. Absent means unselected. */
|
|
12
44
|
export type RowSelectionState = Record<string, boolean>
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Where keyboard focus sits. The indices address the *displayed* grid (after
|
|
48
|
+
* sorting, filtering and paging), not the source data.
|
|
49
|
+
*/
|
|
13
50
|
export type ActiveCellState = {
|
|
14
51
|
rowIndex: number
|
|
15
52
|
colIndex: number
|
|
16
53
|
cellId: string | null
|
|
17
54
|
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* The set of features a grid has registered, as built by {@link tableFeatures}.
|
|
58
|
+
* Deliberately open: a feature is identified by its key, so the type carries
|
|
59
|
+
* which ones are on without enumerating them.
|
|
60
|
+
*/
|
|
18
61
|
export type TableFeatures = Record<string, unknown>
|
|
19
62
|
|
|
63
|
+
/** A cell's value. Unconstrained - a column can hold anything. */
|
|
20
64
|
export type CellData = unknown
|
|
21
65
|
|
|
66
|
+
/** What a column's `header` render function receives. */
|
|
22
67
|
export type HeaderContext<TData extends RowData> = {
|
|
23
68
|
header: Header<TData>
|
|
24
69
|
column: Column<TData>
|
|
25
70
|
table: SvGrid<TData>
|
|
26
71
|
}
|
|
27
72
|
|
|
73
|
+
/**
|
|
74
|
+
* What a column's `cell` render function receives. `getValue()` applies the
|
|
75
|
+
* column's accessor (`field` or `fieldFn`); `row.original` is the raw object.
|
|
76
|
+
*/
|
|
28
77
|
export type CellContext<TData extends RowData> = {
|
|
29
78
|
cell: Cell<TData>
|
|
30
79
|
row: Row<TData>
|
|
@@ -84,6 +133,11 @@ export type EditorContext<TData extends RowData> = CellContext<TData> & {
|
|
|
84
133
|
cancel: () => void
|
|
85
134
|
}
|
|
86
135
|
|
|
136
|
+
/**
|
|
137
|
+
* Declarative cell formatting, applied through `Intl` - number, currency,
|
|
138
|
+
* percent, date and datetime. Prefer this over a `formatter` function: it is
|
|
139
|
+
* locale-aware, and export and the clipboard reuse the same configuration.
|
|
140
|
+
*/
|
|
87
141
|
export type CellFormatConfig =
|
|
88
142
|
| {
|
|
89
143
|
type: 'number'
|
|
@@ -119,6 +173,10 @@ export type CellFormatConfig =
|
|
|
119
173
|
options?: Intl.DateTimeFormatOptions
|
|
120
174
|
}
|
|
121
175
|
|
|
176
|
+
/**
|
|
177
|
+
* A column's custom display function, for anything {@link CellFormatConfig}
|
|
178
|
+
* cannot express. Returns a string - to render markup, use `cell` instead.
|
|
179
|
+
*/
|
|
122
180
|
export type CellFormatter<TData extends RowData> = (context: {
|
|
123
181
|
value: unknown
|
|
124
182
|
row: Row<TData>
|
|
@@ -126,6 +184,7 @@ export type CellFormatter<TData extends RowData> = (context: {
|
|
|
126
184
|
table: SvGrid<TData>
|
|
127
185
|
}) => string
|
|
128
186
|
|
|
187
|
+
/** A header or cell slot: a literal string, or a function returning renderable content. */
|
|
129
188
|
export type ColumnDefTemplate<TContext> = string | ((context: TContext) => unknown)
|
|
130
189
|
|
|
131
190
|
/**
|
|
@@ -378,6 +437,20 @@ export type ColumnDef<TFeatures extends TableFeatures, TData extends RowData> =
|
|
|
378
437
|
* is formatted with this column's `format` and shown in the group header.
|
|
379
438
|
*/
|
|
380
439
|
aggregate?: GroupAggregator<TData>
|
|
440
|
+
/**
|
|
441
|
+
* What this column contributes to the grid's footer summary row (the one
|
|
442
|
+
* turned on with `summary` / `enableRowSummaries`). Takes the same
|
|
443
|
+
* aggregators as {@link aggregate}, and the result is formatted with this
|
|
444
|
+
* column's `format`.
|
|
445
|
+
*
|
|
446
|
+
* Without it the footer falls back to its default: the sum of a numeric
|
|
447
|
+
* column, `Count: N` otherwise. Set `false` to leave the cell blank, which is
|
|
448
|
+
* usually what an actions or checkbox column wants.
|
|
449
|
+
*
|
|
450
|
+
* { field: 'amount', summary: 'avg' }
|
|
451
|
+
* { id: 'actions', summary: false }
|
|
452
|
+
*/
|
|
453
|
+
summary?: GroupAggregator<TData> | false
|
|
381
454
|
/**
|
|
382
455
|
* Render the cell as an in-cell sparkline chart. The cell value should be
|
|
383
456
|
* an array of numbers (or a comma/space separated string). Mutually
|
|
@@ -445,6 +518,12 @@ export type GridColumnDef<TData extends RowData = RowData> = ColumnDef<TableFeat
|
|
|
445
518
|
/** An array of {@link GridColumnDef} - what you pass to `<SvGrid columns={...}>`. */
|
|
446
519
|
export type GridColumns<TData extends RowData = RowData> = Array<GridColumnDef<TData>>
|
|
447
520
|
|
|
521
|
+
/**
|
|
522
|
+
* A resolved column: your {@link ColumnDef} plus everything the grid computed
|
|
523
|
+
* from it - its id, its depth under any group header, and the sort handlers a
|
|
524
|
+
* header needs. This is what you receive in render contexts; the `ColumnDef`
|
|
525
|
+
* is what you wrote.
|
|
526
|
+
*/
|
|
448
527
|
export type Column<TData extends RowData> = {
|
|
449
528
|
id: string
|
|
450
529
|
columnDef: ColumnDef<any, TData>
|
|
@@ -456,6 +535,11 @@ export type Column<TData extends RowData> = {
|
|
|
456
535
|
getToggleSortingHandler: () => () => void
|
|
457
536
|
}
|
|
458
537
|
|
|
538
|
+
/**
|
|
539
|
+
* One header cell. `colSpan` is how many leaf columns it covers, and
|
|
540
|
+
* `isPlaceholder` marks the empty cells that pad a group-header row so the
|
|
541
|
+
* levels line up.
|
|
542
|
+
*/
|
|
459
543
|
export type Header<TData extends RowData> = {
|
|
460
544
|
id: string
|
|
461
545
|
isPlaceholder: boolean
|
|
@@ -464,11 +548,13 @@ export type Header<TData extends RowData> = {
|
|
|
464
548
|
getContext: () => HeaderContext<TData>
|
|
465
549
|
}
|
|
466
550
|
|
|
551
|
+
/** One row of header cells. A grid with grouped columns has several, outermost first. */
|
|
467
552
|
export type HeaderGroup<TData extends RowData> = {
|
|
468
553
|
id: string
|
|
469
554
|
headers: Array<Header<TData>>
|
|
470
555
|
}
|
|
471
556
|
|
|
557
|
+
/** One cell: the intersection of a {@link Row} and a {@link Column}. */
|
|
472
558
|
export type Cell<TData extends RowData> = {
|
|
473
559
|
id: string
|
|
474
560
|
row: Row<TData>
|
|
@@ -477,6 +563,13 @@ export type Cell<TData extends RowData> = {
|
|
|
477
563
|
getContext: () => CellContext<TData>
|
|
478
564
|
}
|
|
479
565
|
|
|
566
|
+
/**
|
|
567
|
+
* A row in the display model. `original` is your untouched data object;
|
|
568
|
+
* everything else is grid-computed. `index` is the position in the displayed
|
|
569
|
+
* set, so it shifts as sorting and filtering change - key on `id`, not index.
|
|
570
|
+
*
|
|
571
|
+
* Group rows and tree parents carry `subRows`; a plain data row does not.
|
|
572
|
+
*/
|
|
480
573
|
export type Row<TData extends RowData> = {
|
|
481
574
|
id: string
|
|
482
575
|
index: number
|
|
@@ -494,10 +587,19 @@ export type Row<TData extends RowData> = {
|
|
|
494
587
|
getCellValueByColumnId: (columnId: string) => unknown
|
|
495
588
|
}
|
|
496
589
|
|
|
590
|
+
/** The output of the row pipeline: the rows to display, in order. */
|
|
497
591
|
export type RowModel<TData extends RowData> = {
|
|
498
592
|
rows: Array<Row<TData>>
|
|
499
593
|
}
|
|
500
594
|
|
|
595
|
+
/**
|
|
596
|
+
* The minimal reactive store behind the headless core - read `state`, write
|
|
597
|
+
* through `setState`, and `subscribe` for changes. Deliberately framework
|
|
598
|
+
* free, which is what lets the core run under plain Node.
|
|
599
|
+
*
|
|
600
|
+
* In Svelte you rarely touch this: `subscribeGrid` wraps it with fine-grained
|
|
601
|
+
* selectors so a component only re-runs for the slice it read.
|
|
602
|
+
*/
|
|
501
603
|
export type Store<T> = {
|
|
502
604
|
readonly state: T
|
|
503
605
|
setState: (updater: (prev: T) => T) => void
|
|
@@ -522,17 +624,51 @@ function createStore<T>(initial: T): Store<T> {
|
|
|
522
624
|
}
|
|
523
625
|
}
|
|
524
626
|
|
|
627
|
+
/**
|
|
628
|
+
* Click-to-sort. Injected by the `sortable` shortcut.
|
|
629
|
+
*
|
|
630
|
+
* This and the five features below are opaque markers: pass the ones you want
|
|
631
|
+
* to {@link tableFeatures} and the grid wires up the matching row model. With
|
|
632
|
+
* `<SvGrid>` you rarely name them - the boolean shortcuts (`sortable`,
|
|
633
|
+
* `filterable`, `pageable`, `groupable`) inject them for you. Reach for them
|
|
634
|
+
* directly when driving the headless core, or when you want a feature on
|
|
635
|
+
* without its UI.
|
|
636
|
+
*
|
|
637
|
+
* The names match TanStack Table v9, so a features object written for it works
|
|
638
|
+
* here unchanged.
|
|
639
|
+
*/
|
|
525
640
|
export const rowSortingFeature = { key: 'rowSortingFeature' }
|
|
641
|
+
/** Per-column filtering. Injected by the `filterable` shortcut. */
|
|
526
642
|
export const columnFilteringFeature = { key: 'columnFilteringFeature' }
|
|
643
|
+
/** Paging of the row model. Injected by the `pageable` shortcut. */
|
|
527
644
|
export const rowPaginationFeature = { key: 'rowPaginationFeature' }
|
|
645
|
+
/** Row grouping with aggregation. Injected by the `groupable` shortcut. */
|
|
528
646
|
export const columnGroupingFeature = { key: 'columnGroupingFeature' }
|
|
647
|
+
/** Row selection state (the checkbox column reads it). */
|
|
529
648
|
export const rowSelectionFeature = { key: 'rowSelectionFeature' }
|
|
649
|
+
/** Expand / collapse, for tree rows and master-detail. */
|
|
530
650
|
export const rowExpandingFeature = { key: 'rowExpandingFeature' }
|
|
531
651
|
|
|
652
|
+
/**
|
|
653
|
+
* Declare which features a grid uses. Identity at runtime - its whole job is to
|
|
654
|
+
* capture the exact set in the type, so `ColumnDef<typeof features, Row>` knows
|
|
655
|
+
* what is registered and anything you did not register is tree-shaken out.
|
|
656
|
+
*
|
|
657
|
+
* ```ts
|
|
658
|
+
* const features = tableFeatures({ rowSortingFeature, columnFilteringFeature })
|
|
659
|
+
* ```
|
|
660
|
+
*
|
|
661
|
+
* Same call signature as TanStack Table v9, so a features object written for it
|
|
662
|
+
* transfers unchanged.
|
|
663
|
+
*/
|
|
532
664
|
export function tableFeatures<T extends TableFeatures>(features: T): T {
|
|
533
665
|
return features
|
|
534
666
|
}
|
|
535
667
|
|
|
668
|
+
/**
|
|
669
|
+
* Built-in comparators, chosen per column by its data type. `auto` compares as
|
|
670
|
+
* text; set a column's type or supply your own comparator to override.
|
|
671
|
+
*/
|
|
536
672
|
export const sortFns = {
|
|
537
673
|
auto: (a: unknown, b: unknown) => String(a).localeCompare(String(b)),
|
|
538
674
|
number: (a: unknown, b: unknown) => Number(a ?? 0) - Number(b ?? 0),
|
|
@@ -543,20 +679,37 @@ export const sortFns = {
|
|
|
543
679
|
},
|
|
544
680
|
}
|
|
545
681
|
|
|
682
|
+
/**
|
|
683
|
+
* Built-in match functions, named by {@link ColumnFilter}'s `fn`.
|
|
684
|
+
* `includesString` is case-insensitive substring; `equals` is strict identity.
|
|
685
|
+
*/
|
|
546
686
|
export const filterFns = {
|
|
547
687
|
includesString: (value: unknown, query: string) =>
|
|
548
688
|
String(value).toLowerCase().includes(query.toLowerCase()),
|
|
549
689
|
equals: (value: unknown, query: unknown) => value === query,
|
|
550
690
|
}
|
|
551
691
|
|
|
692
|
+
/**
|
|
693
|
+
* One stage of the row pipeline: takes the rows produced so far and returns the
|
|
694
|
+
* next set. Stages compose in the order given to `_rowModels`, so filtering
|
|
695
|
+
* before sorting sorts only what survived the filter.
|
|
696
|
+
*/
|
|
552
697
|
export type RowModelFactory<TData extends RowData> = (args: {
|
|
553
698
|
table: SvGrid<TData>
|
|
554
699
|
rows: Array<Row<TData>>
|
|
555
700
|
}) => Array<Row<TData>>
|
|
556
701
|
|
|
702
|
+
/**
|
|
703
|
+
* The identity stage that starts every pipeline. Always required, even when no
|
|
704
|
+
* other stage is: it is what turns your data into rows.
|
|
705
|
+
*/
|
|
557
706
|
export function createCoreRowModel<TData extends RowData>(): RowModelFactory<TData> {
|
|
558
707
|
return ({ rows }) => rows
|
|
559
708
|
}
|
|
709
|
+
/**
|
|
710
|
+
* Drops rows that fail the active {@link ColumnFiltersState}. Pairs with
|
|
711
|
+
* `columnFilteringFeature`; without it there are no filters to apply.
|
|
712
|
+
*/
|
|
560
713
|
export function createFilteredRowModel<TData extends RowData>(): RowModelFactory<TData> {
|
|
561
714
|
return ({ table, rows }) => {
|
|
562
715
|
const filters: ColumnFiltersState = table.getState().columnFilters ?? []
|
|
@@ -573,6 +726,10 @@ export function createFilteredRowModel<TData extends RowData>(): RowModelFactory
|
|
|
573
726
|
})
|
|
574
727
|
}
|
|
575
728
|
}
|
|
729
|
+
/**
|
|
730
|
+
* Narrows the rows to the current page. Put it LAST: anything after it would
|
|
731
|
+
* only ever see one page of data.
|
|
732
|
+
*/
|
|
576
733
|
export function createPaginatedRowModel<TData extends RowData>(): RowModelFactory<TData> {
|
|
577
734
|
return ({ table, rows }) => {
|
|
578
735
|
const pagination = table.getState().pagination ?? { pageIndex: 0, pageSize: rows.length || 10 }
|
|
@@ -580,6 +737,10 @@ export function createPaginatedRowModel<TData extends RowData>(): RowModelFactor
|
|
|
580
737
|
return rows.slice(start, start + pagination.pageSize)
|
|
581
738
|
}
|
|
582
739
|
}
|
|
740
|
+
/**
|
|
741
|
+
* Buckets rows by the active {@link GroupingState} and inserts a group row
|
|
742
|
+
* ahead of each bucket, carrying that bucket's aggregates.
|
|
743
|
+
*/
|
|
583
744
|
export function createGroupedRowModel<TData extends RowData>(): RowModelFactory<TData> {
|
|
584
745
|
return ({ table, rows }) => {
|
|
585
746
|
const grouping: GroupingState = table.getState().grouping ?? []
|
|
@@ -683,6 +844,14 @@ export function createGroupedRowModel<TData extends RowData>(): RowModelFactory<
|
|
|
683
844
|
return buildGroups(rows, 0, 0, 'group')
|
|
684
845
|
}
|
|
685
846
|
}
|
|
847
|
+
/**
|
|
848
|
+
* How to read a hierarchy out of FLAT rows: each row names its parent, and the
|
|
849
|
+
* grid reconstructs the tree. Rows whose parent id matches nothing become roots
|
|
850
|
+
* rather than disappearing.
|
|
851
|
+
*
|
|
852
|
+
* For nested source data (`children: [...]`), flatten it first with
|
|
853
|
+
* {@link flattenTreeData}.
|
|
854
|
+
*/
|
|
686
855
|
export type TreeRowModelOptions = {
|
|
687
856
|
/** Field holding each row's parent id. Rows with no parent are roots. */
|
|
688
857
|
parentField: string
|
|
@@ -761,6 +930,11 @@ export function createTreeRowModel<TData extends RowData>(
|
|
|
761
930
|
}
|
|
762
931
|
}
|
|
763
932
|
|
|
933
|
+
/**
|
|
934
|
+
* How to flatten NESTED source data into the parent-id shape tree rows need.
|
|
935
|
+
* `parentField` is written onto each row, so point `treeData.parentField` at
|
|
936
|
+
* the same name afterwards.
|
|
937
|
+
*/
|
|
764
938
|
export type FlattenTreeOptions = {
|
|
765
939
|
/** Field holding an array of child objects. */
|
|
766
940
|
childrenField: string
|
|
@@ -796,6 +970,10 @@ export function flattenTreeData<T extends RowData>(
|
|
|
796
970
|
return out
|
|
797
971
|
}
|
|
798
972
|
|
|
973
|
+
/**
|
|
974
|
+
* Hides the descendants of collapsed rows. Needed for grouping, tree data and
|
|
975
|
+
* master-detail alike - all three are the same expand/collapse mechanism.
|
|
976
|
+
*/
|
|
799
977
|
export function createExpandedRowModel<TData extends RowData>(): RowModelFactory<TData> {
|
|
800
978
|
return ({ table, rows }) => {
|
|
801
979
|
const expanded: ExpandedState = table.getState().expanded ?? {}
|
|
@@ -810,6 +988,11 @@ export function createExpandedRowModel<TData extends RowData>(): RowModelFactory
|
|
|
810
988
|
return flattened
|
|
811
989
|
}
|
|
812
990
|
}
|
|
991
|
+
/**
|
|
992
|
+
* Orders rows by the active {@link SortingState}. Pass your own comparators to
|
|
993
|
+
* override the built-in {@link sortFns} - useful for locale-aware or
|
|
994
|
+
* domain-specific ordering.
|
|
995
|
+
*/
|
|
813
996
|
export function createSortedRowModel<TData extends RowData>(
|
|
814
997
|
localSortFns: typeof sortFns = sortFns,
|
|
815
998
|
): RowModelFactory<TData> {
|
|
@@ -840,6 +1023,14 @@ export function createSortedRowModel<TData extends RowData>(
|
|
|
840
1023
|
}
|
|
841
1024
|
}
|
|
842
1025
|
|
|
1026
|
+
/**
|
|
1027
|
+
* Everything {@link createSvGridCore} accepts: the data and columns, the
|
|
1028
|
+
* features and row models that make up the pipeline, and an `on*Change`
|
|
1029
|
+
* callback per piece of state for controlled use.
|
|
1030
|
+
*
|
|
1031
|
+
* `<SvGrid>` builds this for you from its props - you only construct it
|
|
1032
|
+
* directly when driving the headless core.
|
|
1033
|
+
*/
|
|
843
1034
|
export type SvGridOptions<TFeatures extends TableFeatures, TData extends RowData> = {
|
|
844
1035
|
_features: TFeatures
|
|
845
1036
|
_rowModels?: {
|
|
@@ -869,6 +1060,13 @@ export type SvGridOptions<TFeatures extends TableFeatures, TData extends RowData
|
|
|
869
1060
|
onActiveCellChange?: (updater: Updater<ActiveCellState>) => void
|
|
870
1061
|
}
|
|
871
1062
|
|
|
1063
|
+
/**
|
|
1064
|
+
* The headless grid instance: the state stores plus the read methods a renderer
|
|
1065
|
+
* needs (`getHeaderGroups()`, `getRowModel()`, the `set*` writers).
|
|
1066
|
+
*
|
|
1067
|
+
* Framework free by design - `<SvGrid>` is one renderer over this, and you can
|
|
1068
|
+
* write another. See the "Why headless?" guide.
|
|
1069
|
+
*/
|
|
872
1070
|
export type SvGrid<TData extends RowData> = {
|
|
873
1071
|
store: Store<Record<string, any>>
|
|
874
1072
|
optionsStore: Store<Record<string, any>>
|
|
@@ -892,6 +1090,14 @@ type InternalGrid<TData extends RowData> = SvGrid<TData> & {
|
|
|
892
1090
|
getAllColumns: () => Array<Column<TData>>
|
|
893
1091
|
}
|
|
894
1092
|
|
|
1093
|
+
/**
|
|
1094
|
+
* Build a headless grid: state, the row pipeline, and the read methods, with no
|
|
1095
|
+
* DOM and no Svelte. This is the engine `<SvGrid>` renders.
|
|
1096
|
+
*
|
|
1097
|
+
* Most callers want `createSvGrid` (the runes-aware wrapper) or the component
|
|
1098
|
+
* itself; reach for this when you are writing your own renderer or running the
|
|
1099
|
+
* pipeline outside a browser.
|
|
1100
|
+
*/
|
|
895
1101
|
export function createSvGridCore<TFeatures extends TableFeatures, TData extends RowData>(
|
|
896
1102
|
options: SvGridOptions<TFeatures, TData>,
|
|
897
1103
|
): SvGrid<TData> {
|
|
@@ -1256,6 +1462,7 @@ export function createSvGridCore<TFeatures extends TableFeatures, TData extends
|
|
|
1256
1462
|
return grid
|
|
1257
1463
|
}
|
|
1258
1464
|
|
|
1465
|
+
/** Narrowing helper for the many options that accept a value or a function. */
|
|
1259
1466
|
export function isFunction(value: unknown): value is (...args: Array<any>) => any {
|
|
1260
1467
|
return typeof value === 'function'
|
|
1261
1468
|
}
|
package/src/createTree.svelte.ts
CHANGED
|
@@ -31,6 +31,7 @@ export type TreeNode = {
|
|
|
31
31
|
lazy?: boolean
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
+
/** A node's checkbox state. `'indeterminate'` means some but not all descendants are checked. */
|
|
34
35
|
export type CheckState = 'checked' | 'indeterminate' | 'unchecked'
|
|
35
36
|
|
|
36
37
|
/** A single visible (flattened) tree row. */
|
|
@@ -145,6 +146,7 @@ export type TreeConfig = {
|
|
|
145
146
|
filter?: () => string | undefined
|
|
146
147
|
}
|
|
147
148
|
|
|
149
|
+
/** Build the headless tree model: expansion, selection and checkbox cascading, with no markup. */
|
|
148
150
|
export function createTree(config: TreeConfig) {
|
|
149
151
|
const nodes = () => config.nodes()
|
|
150
152
|
const checkable = () => config.checkable?.() ?? false
|
|
@@ -316,4 +318,5 @@ export function createTree(config: TreeConfig) {
|
|
|
316
318
|
}
|
|
317
319
|
}
|
|
318
320
|
|
|
321
|
+
/** The headless tree instance returned by {@link createTree}. */
|
|
319
322
|
export type Tree = ReturnType<typeof createTree>
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
* `firstDayOfWeek`.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
+
/** Anything the date helpers accept: a `Date`, epoch milliseconds, or a parseable string. */
|
|
13
14
|
export type DateLike = Date | number | string
|
|
14
15
|
|
|
15
16
|
/** Coerce a Date | epoch-ms | parseable string to a Date, or null if invalid. */
|
|
@@ -137,6 +138,7 @@ export function centuryRange(year: number): { start: number; end: number } {
|
|
|
137
138
|
return { start, end: start + 99 }
|
|
138
139
|
}
|
|
139
140
|
|
|
141
|
+
/** One cell of a month grid, including the leading and trailing days from adjacent months. */
|
|
140
142
|
export type MonthMatrixCell = {
|
|
141
143
|
date: Date
|
|
142
144
|
/** In the displayed month (vs. leading/trailing days of adjacent months). */
|
package/src/datetime/timezone.ts
CHANGED
|
@@ -31,6 +31,7 @@ import {
|
|
|
31
31
|
type IdGen,
|
|
32
32
|
} from './dock-model'
|
|
33
33
|
|
|
34
|
+
/** Which edge a pane docks against when dropped. */
|
|
34
35
|
export type DockSide = Exclude<DockZone, 'center'>
|
|
35
36
|
|
|
36
37
|
/** A floating window: one tabs leaf shown in a movable/resizable frame. */
|
|
@@ -58,6 +59,7 @@ export type AutoHideEntry = {
|
|
|
58
59
|
size: number
|
|
59
60
|
}
|
|
60
61
|
|
|
62
|
+
/** The whole dock manager: its layout tree plus floating and pinned panes. */
|
|
61
63
|
export type DockManagerState = {
|
|
62
64
|
main: DockNode | null
|
|
63
65
|
floating: FloatWindow[]
|
|
@@ -74,6 +76,7 @@ export type PaneLocation =
|
|
|
74
76
|
| { kind: 'floating'; windowId: string }
|
|
75
77
|
| { kind: 'autoHide'; entryId: string }
|
|
76
78
|
|
|
79
|
+
/** Find a pane in the layout tree by id, returning it with its parent for mutation. */
|
|
77
80
|
export function locatePane(state: DockManagerState, paneId: string): PaneLocation | null {
|
|
78
81
|
if (state.main && findTabsWithPane(state.main, paneId)) return { kind: 'main' }
|
|
79
82
|
for (const w of state.floating) {
|
package/src/dock-model.ts
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
* without a browser. Modelled on Smart's `smart-layout` group/item structure.
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
+
/** One dockable pane: its id, title, and the state a tab needs to render. */
|
|
16
17
|
export type DockPane = {
|
|
17
18
|
id: string
|
|
18
19
|
title: string
|
|
@@ -40,15 +41,18 @@ export type DockGroup = {
|
|
|
40
41
|
sizes: number[]
|
|
41
42
|
}
|
|
42
43
|
|
|
44
|
+
/** A node in the layout tree - either a split group or a tabbed leaf. */
|
|
43
45
|
export type DockNode = DockGroup | DockTabs
|
|
44
46
|
|
|
45
47
|
/** Where a dragged pane lands relative to a target leaf. */
|
|
46
48
|
export type DockZone = 'left' | 'right' | 'top' | 'bottom' | 'center'
|
|
47
49
|
|
|
50
|
+
/** Supplies ids for newly created nodes, so layouts stay deterministic in tests. */
|
|
48
51
|
export type IdGen = () => string
|
|
49
52
|
|
|
50
53
|
// ---- construction helpers -------------------------------------------------
|
|
51
54
|
|
|
55
|
+
/** Build a {@link DockPane}. */
|
|
52
56
|
export function pane(id: string, title: string, closable = true): DockPane {
|
|
53
57
|
return { id, title, closable }
|
|
54
58
|
}
|
|
@@ -58,10 +62,12 @@ export function leafMinSize(node: DockTabs): number {
|
|
|
58
62
|
return node.panes.reduce((m, p) => Math.max(m, p.minSize ?? 0), 0)
|
|
59
63
|
}
|
|
60
64
|
|
|
65
|
+
/** Build a tabbed leaf holding the given panes. */
|
|
61
66
|
export function tabs(genId: IdGen, panes: DockPane[], active = 0): DockTabs {
|
|
62
67
|
return { type: 'tabs', id: genId(), panes, active: clampIndex(active, panes.length) }
|
|
63
68
|
}
|
|
64
69
|
|
|
70
|
+
/** Build a split group: panes or nested groups laid out in a row or column. */
|
|
65
71
|
export function group(
|
|
66
72
|
genId: IdGen,
|
|
67
73
|
direction: 'row' | 'column',
|
package/src/editor-contract.ts
CHANGED
package/src/list-option.ts
CHANGED
|
@@ -71,6 +71,7 @@ export type VirtualListRow =
|
|
|
71
71
|
| { type: 'group'; label: string; size: number }
|
|
72
72
|
| { type: 'option'; opt: IndexedOption; size: number }
|
|
73
73
|
|
|
74
|
+
/** A flattened option list plus its measurements, for virtualizing long dropdowns. */
|
|
74
75
|
export type FlatVirtualModel = {
|
|
75
76
|
/** Group headings + options in render order, each with its px height. */
|
|
76
77
|
entries: VirtualListRow[]
|
package/src/positioning.ts
CHANGED
|
@@ -35,6 +35,7 @@ export type Rect = { x: number; y: number; width: number; height: number }
|
|
|
35
35
|
/** The available viewport (defaults to `window` in the browser). */
|
|
36
36
|
export type Viewport = { width: number; height: number }
|
|
37
37
|
|
|
38
|
+
/** Where to put a floating element: its preferred side, offsets, and collision behaviour. */
|
|
38
39
|
export type ComputePositionOptions = {
|
|
39
40
|
/** Preferred placement. Default `'bottom-start'`. */
|
|
40
41
|
placement?: Placement
|
|
@@ -58,6 +59,7 @@ export type ComputePositionOptions = {
|
|
|
58
59
|
minMainAxis?: number
|
|
59
60
|
}
|
|
60
61
|
|
|
62
|
+
/** The resolved position, including the side actually used after collision handling. */
|
|
61
63
|
export type ComputePositionResult = {
|
|
62
64
|
/** Floating left, in viewport (fixed-position) coordinates. */
|
|
63
65
|
x: number
|
package/src/scheduler-ical.ts
CHANGED
package/src/scheduler-model.ts
CHANGED
|
@@ -444,6 +444,7 @@ export type DayLayout<TData = unknown> = {
|
|
|
444
444
|
overflows: OverflowMarker<TData>[]
|
|
445
445
|
}
|
|
446
446
|
|
|
447
|
+
/** Tuning for event layout: how overlapping events share horizontal space. */
|
|
447
448
|
export type LayoutOptions = {
|
|
448
449
|
dayStartHour?: number
|
|
449
450
|
dayEndHour?: number
|
package/src/summaries.ts
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
// reading/writing controller state via the `ctx` handle; the reactive core
|
|
3
3
|
// ($state/$derived/$effect) stays in the controller.
|
|
4
4
|
import {
|
|
5
|
+
applyGroupAggregate,
|
|
5
6
|
type Column,
|
|
6
7
|
type Row,
|
|
7
8
|
type RowData,
|
|
@@ -45,6 +46,26 @@ export function createSummaries<
|
|
|
45
46
|
const fieldFn = def.fieldFn;
|
|
46
47
|
const field = def.field;
|
|
47
48
|
const columnId = column.id;
|
|
49
|
+
|
|
50
|
+
// A column that declares its own `summary` opts out of the default
|
|
51
|
+
// sum/count below. Only that column pays for the aggregator dispatch, so
|
|
52
|
+
// a grid that declares none keeps the original hot loop exactly as it was.
|
|
53
|
+
const declared = def.summary;
|
|
54
|
+
if (declared !== undefined) {
|
|
55
|
+
if (declared === false) {
|
|
56
|
+
summary[columnId] = "";
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
const value = applyGroupAggregate(declared, columnId, rows);
|
|
60
|
+
summary[columnId] =
|
|
61
|
+
typeof value === "number" && Number.isFinite(value)
|
|
62
|
+
? formatSummaryNumeric(column, value)
|
|
63
|
+
: value == null
|
|
64
|
+
? ""
|
|
65
|
+
: String(value);
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
|
|
48
69
|
let numericSum = 0;
|
|
49
70
|
let numericCount = 0;
|
|
50
71
|
for (let i = 0; i < rowCount; i += 1) {
|
|
@@ -9,6 +9,7 @@ import type { GridPredicateExpr } from './filtering/predicate-expr'
|
|
|
9
9
|
// Aliased to the core union rather than restated: the API surfaces below hand
|
|
10
10
|
// back whatever the grid actually filtered with, so a hand-maintained subset
|
|
11
11
|
// here silently mistypes operators like 'endsWith' that reach callers at runtime.
|
|
12
|
+
/** The comparisons a column filter can use, as shown in the filter menu. */
|
|
12
13
|
export type SvGridFilterOperator = FilterOperator
|
|
13
14
|
|
|
14
15
|
/**
|
|
@@ -79,6 +80,7 @@ export type SvGridTransaction<TData> = {
|
|
|
79
80
|
remove?: ReadonlyArray<TData | string>
|
|
80
81
|
}
|
|
81
82
|
|
|
83
|
+
/** What a batched `applyTransaction` did: how many rows were added, updated and removed. */
|
|
82
84
|
export type SvGridTransactionResult = {
|
|
83
85
|
added: number
|
|
84
86
|
updated: number
|
|
@@ -503,6 +505,7 @@ export type SvGridApi<
|
|
|
503
505
|
refresh(): void
|
|
504
506
|
}
|
|
505
507
|
|
|
508
|
+
/** The props `<SvGrid>` accepts. See the SvGrid reference for the full list with defaults. */
|
|
506
509
|
export type SvGridWrapperProps<
|
|
507
510
|
TFeatures extends TableFeatures,
|
|
508
511
|
TData extends RowData,
|
|
@@ -553,6 +556,8 @@ export type SvGridWrapperProps<
|
|
|
553
556
|
enableCellSelection?: boolean
|
|
554
557
|
enableInlineEditing?: boolean
|
|
555
558
|
enableRowSummaries?: boolean
|
|
559
|
+
/** Shortcut alias for `enableRowSummaries`; wins when both are set. */
|
|
560
|
+
summary?: boolean
|
|
556
561
|
/** Receives the imperative grid API when the component is ready. */
|
|
557
562
|
onApiReady?: (api: SvGridApi<TFeatures, TData>) => void
|
|
558
563
|
}
|