@toclocoinc/lattice-grid 1.1.1 → 1.4.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/LICENSE +2 -0
- package/README.md +1 -1
- package/lattice-grid.d.ts +847 -21
- package/lattice-grid.esm.min.js +11103 -777
- package/lattice-grid.min.css +1 -1
- package/lattice-grid.min.js +11097 -777
- package/modules/devtools.esm.js +1611 -0
- package/modules/devtools.esm.min.js +985 -0
- package/modules/react.esm.js +430 -0
- package/modules/react.esm.min.js +201 -0
- package/modules/svelte.esm.js +412 -0
- package/modules/svelte.esm.min.js +179 -0
- package/modules/vue.esm.js +432 -0
- package/modules/vue.esm.min.js +199 -0
- package/{lattice-grid.esm.js → modules/webcomponent.esm.js} +58405 -35926
- package/modules/webcomponent.esm.min.js +47024 -0
- package/package.json +2 -3
- package/lattice-core.esm.js +0 -38814
- package/lattice-grid.css +0 -4393
- package/lattice-grid.umd.js +0 -71701
package/lattice-grid.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* Lattice Grid 1.
|
|
2
|
+
* Lattice Grid 1.4.0 — type declarations
|
|
3
3
|
* Copyright (c) 2026 TOCLOCO Inc. All rights reserved.
|
|
4
4
|
* https://latticegrid.dev
|
|
5
5
|
*/
|
|
@@ -18,11 +18,29 @@
|
|
|
18
18
|
|
|
19
19
|
export type TypeName =
|
|
20
20
|
| 'text' | 'number' | 'boolean' | 'date' | 'dateString' | 'object' | 'lookup'
|
|
21
|
+
| 'image'
|
|
21
22
|
| (string & {});
|
|
22
23
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
/**
|
|
25
|
+
* Cell and header alignment.
|
|
26
|
+
*
|
|
27
|
+
* `left` and `right` are accepted and normalised to `start` and `end`. The grid
|
|
28
|
+
* has no RTL handling today, so the two pairs are exact synonyms; if direction
|
|
29
|
+
* support lands, `start`/`end` will follow the text direction while
|
|
30
|
+
* `left`/`right` stay physical. `centre` is accepted alongside `center`.
|
|
31
|
+
*/
|
|
32
|
+
export type Align = 'start' | 'center' | 'end' | 'left' | 'right' | 'centre';
|
|
33
|
+
/**
|
|
34
|
+
* A named preset, or a raw scale where 1 is `standard`. Row heights are
|
|
35
|
+
* 23.8 / 28 / 42 / 56px for the four presets; a number scales 28px.
|
|
36
|
+
*/
|
|
37
|
+
export type Density = 'compact' | 'standard' | 'comfortable' | 'spacious' | number;
|
|
38
|
+
/**
|
|
39
|
+
* A shipped theme, or your own name — the value is written to `data-theme` on
|
|
40
|
+
* the grid's root, so `.lattice[data-theme="mine"]` is all a custom one needs.
|
|
41
|
+
* Unset follows the viewer's `prefers-color-scheme`.
|
|
42
|
+
*/
|
|
43
|
+
export type Theme = 'light' | 'dark' | 'high-contrast' | 'terminal' | (string & {});
|
|
26
44
|
export type ColumnRef = string;
|
|
27
45
|
export type Comparator = (
|
|
28
46
|
a: unknown, b: unknown, rowA?: Row, rowB?: Row, descending?: boolean,
|
|
@@ -68,10 +86,27 @@ export interface RowChange {
|
|
|
68
86
|
remove?: unknown[] | string[];
|
|
69
87
|
}
|
|
70
88
|
|
|
89
|
+
/** A row a change could not apply, and why. Reported, never thrown. */
|
|
90
|
+
export interface RejectedRow {
|
|
91
|
+
operation: 'add' | 'update' | 'remove';
|
|
92
|
+
id: string;
|
|
93
|
+
/**
|
|
94
|
+
* `unknown-id` — no row with that key. `duplicate-id` — a row with that key
|
|
95
|
+
* already exists; admitting a second would corrupt every structure that
|
|
96
|
+
* resolves one key to one row.
|
|
97
|
+
*/
|
|
98
|
+
reason: 'unknown-id' | 'duplicate-id';
|
|
99
|
+
}
|
|
100
|
+
|
|
71
101
|
export interface ChangeResult {
|
|
72
102
|
added: Row[];
|
|
73
103
|
updated: Row[];
|
|
74
104
|
removed: string[];
|
|
105
|
+
/**
|
|
106
|
+
* Rows that could not be applied. A batch of a thousand containing three bad
|
|
107
|
+
* ones applies the other 997 and lists the three here.
|
|
108
|
+
*/
|
|
109
|
+
rejected?: RejectedRow[];
|
|
75
110
|
}
|
|
76
111
|
|
|
77
112
|
// ---------------------------------------------------------------------------
|
|
@@ -175,6 +210,8 @@ export interface DataType {
|
|
|
175
210
|
editor?: EditorName;
|
|
176
211
|
total?: TotalName;
|
|
177
212
|
align?: Align;
|
|
213
|
+
/** The cell renderer this type's values are drawn with by default. */
|
|
214
|
+
render?: RendererName;
|
|
178
215
|
};
|
|
179
216
|
storage?: 'float64' | 'int32' | 'bitset' | 'dictionary' | 'object';
|
|
180
217
|
excel?: string;
|
|
@@ -270,7 +307,24 @@ export interface Editor {
|
|
|
270
307
|
destroy?(): void;
|
|
271
308
|
}
|
|
272
309
|
export type EditorCtor = new () => Editor;
|
|
273
|
-
|
|
310
|
+
/** The built-in tool panels, addressable by name from configuration. */
|
|
311
|
+
export type ToolPanelName = 'columns' | 'filters' | 'views' | 'quick' | 'formatting' | (string & {});
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* The built-in cell renderers, addressable by name through `cell.render`.
|
|
315
|
+
* Anything registered through `components` is also valid here.
|
|
316
|
+
*/
|
|
317
|
+
export type RendererName =
|
|
318
|
+
| 'area' | 'bullet' | 'checkbox' | 'colour' | 'column' | 'delta' | 'detailExpander'
|
|
319
|
+
| 'donut' | 'gauge' | 'group' | 'icon' | 'image' | 'line' | 'link' | 'pie' | 'pill'
|
|
320
|
+
| 'progress' | 'qrcode' | 'range' | 'rating' | 'skeleton' | 'stacked' | 'twoline'
|
|
321
|
+
| 'winloss' | (string & {});
|
|
322
|
+
|
|
323
|
+
export type EditorName =
|
|
324
|
+
| 'checkbox' | 'code' | 'colour' | 'date' | 'datetime' | 'duration' | 'iconPicker'
|
|
325
|
+
| 'ipaddress' | 'multiSelect' | 'number' | 'objectPicker' | 'password' | 'radix'
|
|
326
|
+
| 'rating' | 'segmented' | 'select' | 'slider' | 'text' | 'textarea' | 'time'
|
|
327
|
+
| 'treeSelect' | 'unit' | (string & {});
|
|
274
328
|
|
|
275
329
|
export interface EditorParams extends CellParams {
|
|
276
330
|
stop(cancel?: boolean): void;
|
|
@@ -424,6 +478,8 @@ export interface ColumnGroup {
|
|
|
424
478
|
showWhen?: 'open' | 'closed' | 'always';
|
|
425
479
|
marryChildren?: boolean;
|
|
426
480
|
header?: { render?: string | RendererCtor; props?: Record<string, unknown>; class?: string | string[] };
|
|
481
|
+
/** This column's histogram. `true` turns it on with the grid's settings. */
|
|
482
|
+
facet?: ColumnFacetConfig | boolean;
|
|
427
483
|
}
|
|
428
484
|
|
|
429
485
|
/** A column after presets, type defaults and grid defaults are folded in. */
|
|
@@ -570,6 +626,15 @@ export interface StreamSourceConfig {
|
|
|
570
626
|
context: unknown;
|
|
571
627
|
signal: AbortSignal;
|
|
572
628
|
}): AsyncIterable<Chunk>;
|
|
629
|
+
/**
|
|
630
|
+
* The most rows to keep. A stream has no end, so an unbounded grid dies
|
|
631
|
+
* overnight; this makes it a sliding window and the oldest rows are dropped.
|
|
632
|
+
* Omit for no limit.
|
|
633
|
+
*
|
|
634
|
+
* Set on the source, not passed to `open` — it bounds what the grid retains
|
|
635
|
+
* rather than what the producer sends.
|
|
636
|
+
*/
|
|
637
|
+
maxRows?: number;
|
|
573
638
|
promoteToMemoryBelow?: number;
|
|
574
639
|
coalesceMs?: number;
|
|
575
640
|
}
|
|
@@ -587,6 +652,10 @@ export interface TreeConfig {
|
|
|
587
652
|
orphans?: 'root' | string;
|
|
588
653
|
hasChildren?: (row: unknown) => boolean;
|
|
589
654
|
loadChildren?: (row: Row, signal: AbortSignal) => Promise<unknown[]>;
|
|
655
|
+
/** Where the generated tree column takes its text from: a field or a function. */
|
|
656
|
+
label?: string | ((data: unknown, row: Row) => unknown);
|
|
657
|
+
/** The tree column's heading. Defaults to the label column's own title. */
|
|
658
|
+
title?: string;
|
|
590
659
|
}
|
|
591
660
|
|
|
592
661
|
export interface DetailConfig {
|
|
@@ -596,7 +665,22 @@ export interface DetailConfig {
|
|
|
596
665
|
rows?: (row: Row) => unknown[] | Promise<unknown[]>;
|
|
597
666
|
height?: number | 'auto' | ((row: Row) => number);
|
|
598
667
|
cacheLimit?: number;
|
|
599
|
-
isMaster?: (row:
|
|
668
|
+
isMaster?: (data: unknown, row: Row) => boolean;
|
|
669
|
+
/**
|
|
670
|
+
* Render the detail into this element instead of into a row beneath its
|
|
671
|
+
* master. A selector or an element. Exactly one detail is open at a time in
|
|
672
|
+
* this placement (§13).
|
|
673
|
+
*/
|
|
674
|
+
target?: string | HTMLElement;
|
|
675
|
+
/** Handed the nested grid as it is created, for whatever the forwarded events do not cover. */
|
|
676
|
+
onCreate?: (grid: Grid, masterRow: Row) => void;
|
|
677
|
+
/**
|
|
678
|
+
* The property of the master's record the detail rows live on, so an edit in
|
|
679
|
+
* the detail is reported as a path on the master — `ports.1.vlan`. Inferred
|
|
680
|
+
* by identity when `rows(row)` returns an array already on the record, which
|
|
681
|
+
* is the usual shape; set this when it does not (§13).
|
|
682
|
+
*/
|
|
683
|
+
path?: string;
|
|
600
684
|
}
|
|
601
685
|
|
|
602
686
|
export interface SelectionConfig {
|
|
@@ -616,6 +700,28 @@ export interface EditConfig {
|
|
|
616
700
|
start?: 'single' | 'double' | 'key';
|
|
617
701
|
enterMovesDown?: boolean;
|
|
618
702
|
undoDepth?: number;
|
|
703
|
+
commit?: (write: PendingWrite) => unknown;
|
|
704
|
+
confirm?: 'auto' | 'manual';
|
|
705
|
+
pendingTimeout?: number;
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
export interface PendingWrite {
|
|
709
|
+
id: string;
|
|
710
|
+
key: string;
|
|
711
|
+
colId: string;
|
|
712
|
+
value: unknown;
|
|
713
|
+
before: unknown;
|
|
714
|
+
row?: Row;
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
export interface OpenWrite {
|
|
718
|
+
id: string;
|
|
719
|
+
key: string;
|
|
720
|
+
colId: string;
|
|
721
|
+
value: unknown;
|
|
722
|
+
before: unknown;
|
|
723
|
+
state: 'pending' | 'superseded';
|
|
724
|
+
age: number;
|
|
619
725
|
}
|
|
620
726
|
|
|
621
727
|
export interface PaginationConfig {
|
|
@@ -633,6 +739,8 @@ export interface GridConfig {
|
|
|
633
739
|
columnDefaults?: Column;
|
|
634
740
|
columnPresets?: Record<string, Column>;
|
|
635
741
|
dataTypes?: Record<string, DataType>;
|
|
742
|
+
/** Values sampled per undeclared column when inferring its type. Default 100. */
|
|
743
|
+
sampleSize?: number;
|
|
636
744
|
components?: Record<string, RendererCtor | EditorCtor | FilterCtor>;
|
|
637
745
|
pipes?: Record<string, (value: unknown, ...args: string[]) => string>;
|
|
638
746
|
totalFns?: Record<string, TotalFn>;
|
|
@@ -653,24 +761,95 @@ export interface GridConfig {
|
|
|
653
761
|
rowHeight?: number | ((row: Row) => number);
|
|
654
762
|
headerHeight?: number;
|
|
655
763
|
overscan?: number;
|
|
764
|
+
/**
|
|
765
|
+
* Size rows to their content rather than to the density token.
|
|
766
|
+
*
|
|
767
|
+
* Only rows that are actually rendered are ever measured, in both settings —
|
|
768
|
+
* the grid does not lay out rows you cannot see. The difference is what
|
|
769
|
+
* happens on a large grid: `true` gives up above ten thousand rows and falls
|
|
770
|
+
* back to fixed heights, because a cumulative offset array being patched as
|
|
771
|
+
* you scroll a million rows is not worth the result. `'visible'` keeps
|
|
772
|
+
* measuring at any size, accepting that the scrollbar shifts as rows are
|
|
773
|
+
* measured on the way past.
|
|
774
|
+
*
|
|
775
|
+
* The name is historical and reads as though it were about which rows are
|
|
776
|
+
* measured; it is about whether the ceiling applies.
|
|
777
|
+
*/
|
|
656
778
|
autoHeight?: boolean | 'visible';
|
|
657
779
|
state?: GridState;
|
|
658
780
|
licence?: string;
|
|
659
781
|
maximise?: boolean;
|
|
782
|
+
/** Extra functions a formula may call, on top of the built-in library. */
|
|
783
|
+
formulaFunctions?: Record<string, (args: unknown[]) => unknown>;
|
|
660
784
|
allowUnsafeTemplates?: boolean;
|
|
785
|
+
/**
|
|
786
|
+
* Caps on the change log behind `grid.updates` and `grid.timeline`.
|
|
787
|
+
*
|
|
788
|
+
* Two caps, because an entry is not a fixed size: `logLimit` bounds how many
|
|
789
|
+
* changes are kept (default 2000) and `logRows` bounds the rows they account
|
|
790
|
+
* for between them (default 100,000). A feed delivering large batches reaches
|
|
791
|
+
* the second long before the first, and without it the log is unbounded in
|
|
792
|
+
* bytes while looking bounded in entries.
|
|
793
|
+
*/
|
|
794
|
+
updates?: {
|
|
795
|
+
logLimit?: number;
|
|
796
|
+
logRows?: number;
|
|
797
|
+
/**
|
|
798
|
+
* When a queued batch applies. `frame` (default) lands on a paint
|
|
799
|
+
* boundary, which is what makes one repaint per batch reliable;
|
|
800
|
+
* `microtask` at the end of the current task; `interval` on the coalescing
|
|
801
|
+
* window; `manual` only when you call `grid.updates.flush()`.
|
|
802
|
+
*/
|
|
803
|
+
flush?: 'frame' | 'microtask' | 'interval' | 'manual';
|
|
804
|
+
/** Queued rows that force an early flush regardless of strategy. */
|
|
805
|
+
maxQueued?: number;
|
|
806
|
+
/** Milliseconds one flush may spend before deferring the rest. */
|
|
807
|
+
budgetMs?: number;
|
|
808
|
+
};
|
|
809
|
+
/**
|
|
810
|
+
* Threaded comments on individual cells (§16). Requires a stable
|
|
811
|
+
* `rowKey`: comments outlive the values they annotate, and index
|
|
812
|
+
* identity would reattach every thread on the next sort.
|
|
813
|
+
*/
|
|
814
|
+
comments?: CommentConfig;
|
|
815
|
+
/**
|
|
816
|
+
* Collaborative presence (§18). A display feature over a transport the
|
|
817
|
+
* grid does not own; without a provider it is inert.
|
|
818
|
+
*/
|
|
819
|
+
presence?: PresenceConfig;
|
|
820
|
+
/**
|
|
821
|
+
* Host environment for a support bundle. Supplied by the DOM layer;
|
|
822
|
+
* core cannot read `navigator` or `window` itself (§3.1).
|
|
823
|
+
*/
|
|
824
|
+
environment?: () => Record<string, unknown>;
|
|
825
|
+
/**
|
|
826
|
+
* Column header histograms and the filters clicking them creates (§9.6).
|
|
827
|
+
*
|
|
828
|
+
* Off by default: the band roughly doubles header height, which is a cost
|
|
829
|
+
* no grid should pay without asking. Per-column settings layer over these.
|
|
830
|
+
*/
|
|
831
|
+
facets?: FacetConfig | boolean;
|
|
661
832
|
hostFilter?: { active(): boolean; passes(row: Row): boolean };
|
|
662
833
|
context?: unknown;
|
|
834
|
+
/** Row count above which a column distribution is computed in a Worker. */
|
|
663
835
|
workerThreshold?: number;
|
|
836
|
+
/**
|
|
837
|
+
* Compute column distributions off the main thread. Sorting, filtering and
|
|
838
|
+
* grouping run on the main thread; see §5.13 for why.
|
|
839
|
+
*/
|
|
664
840
|
useWorker?: boolean;
|
|
665
841
|
workerUrl?: string;
|
|
666
842
|
sharedMemory?: boolean;
|
|
667
843
|
groupFooter?: boolean;
|
|
668
844
|
/**
|
|
669
|
-
* Where the grand total goes.
|
|
670
|
-
*
|
|
671
|
-
*
|
|
845
|
+
* Where the grand total goes.
|
|
846
|
+
*
|
|
847
|
+
* `true` adds it as the last display row, counted by `rows.count()` like any
|
|
848
|
+
* other. `'bottom'` pins it beneath the viewport instead, so it stays in
|
|
849
|
+
* view while the rows scroll and is *not* part of `rows.count()`. Omitted or
|
|
850
|
+
* `false` means no grand total row.
|
|
672
851
|
*/
|
|
673
|
-
grandTotalRow?: 'bottom';
|
|
852
|
+
grandTotalRow?: boolean | 'bottom';
|
|
674
853
|
totalFilteredOnly?: boolean;
|
|
675
854
|
totalOnlyChangedColumns?: boolean;
|
|
676
855
|
showTotalInHeader?: boolean;
|
|
@@ -681,7 +860,7 @@ export interface GridConfig {
|
|
|
681
860
|
* suppresses it entirely, which is what a read-only grid wants — the default
|
|
682
861
|
* menu offers Paste, Clear and Fill down.
|
|
683
862
|
*/
|
|
684
|
-
contextMenu?: boolean | ((p:
|
|
863
|
+
contextMenu?: boolean | ((p: CellMenuParams, defaults: MenuItem[]) => MenuItem[] | void);
|
|
685
864
|
/** The header's 3-dot menu. `false` suppresses it. Default true. */
|
|
686
865
|
columnMenu?: boolean;
|
|
687
866
|
/**
|
|
@@ -695,13 +874,20 @@ export interface GridConfig {
|
|
|
695
874
|
duration?: number;
|
|
696
875
|
enabled?: boolean;
|
|
697
876
|
};
|
|
877
|
+
/**
|
|
878
|
+
* Conditional formatting rules the grid holds as runtime state, keyed by
|
|
879
|
+
* column id or `'*'` for every column (spec 8.12). Seeds `grid.formatting`,
|
|
880
|
+
* which an end user can then change; the rules travel in saved views and
|
|
881
|
+
* undo like any other change. Config-time `cell.style` is unaffected.
|
|
882
|
+
*/
|
|
883
|
+
formatting?: Record<string, FormattingRule[]>;
|
|
698
884
|
/** A class, or classes, for every row. Re-evaluated on each repaint. */
|
|
699
885
|
rowClass?: string | string[] | ((p: RowStyleParams) => string | string[]);
|
|
700
886
|
/** Inline styles for every row. Camel-case or hyphenated property names. */
|
|
701
887
|
rowStyle?: CellStyle | ((p: RowStyleParams) => CellStyle);
|
|
702
888
|
toolPanel?: boolean | {
|
|
703
|
-
/** Built-in names: `columns`, `filters`, `views`, `quick`. */
|
|
704
|
-
panels?:
|
|
889
|
+
/** Built-in names: `columns`, `filters`, `views`, `quick`, `formatting`. */
|
|
890
|
+
panels?: ToolPanelName[];
|
|
705
891
|
openPanel?: string;
|
|
706
892
|
/** Which edge to dock against. `left` is the icon rail; default `right`. */
|
|
707
893
|
side?: 'left' | 'right';
|
|
@@ -711,7 +897,14 @@ export interface GridConfig {
|
|
|
711
897
|
* Rail action buttons: `undo`, `redo`, `export`, `restore`. Defaults to all
|
|
712
898
|
* four on the left rail and none on the right; `false` drops them.
|
|
713
899
|
*/
|
|
714
|
-
|
|
900
|
+
/**
|
|
901
|
+
* Which action buttons the rail offers, in order. `false` drops them.
|
|
902
|
+
*
|
|
903
|
+
* The built-in names are `undo`, `redo`, `pause`, `restore`, `maximise`,
|
|
904
|
+
* `export`, `excel`, `clipboard` and `print`, plus `'-'` for a divider.
|
|
905
|
+
* A {@link RailAction} object places one of your own among them.
|
|
906
|
+
*/
|
|
907
|
+
actions?: false | (RailActionName | '-' | RailAction)[];
|
|
715
908
|
/** File name for the export action, without the extension. */
|
|
716
909
|
exportName?: string;
|
|
717
910
|
};
|
|
@@ -723,7 +916,27 @@ export interface GridConfig {
|
|
|
723
916
|
*/
|
|
724
917
|
permissions?: PermissionPolicy;
|
|
725
918
|
/** Prior state for diff and audit mode (§12). */
|
|
726
|
-
diff?: {
|
|
919
|
+
diff?: {
|
|
920
|
+
snapshot?: unknown[] | Map<string, unknown>;
|
|
921
|
+
strictNull?: boolean;
|
|
922
|
+
addedColumns?: 'unchanged' | 'changed';
|
|
923
|
+
/**
|
|
924
|
+
* Whether a row present in the snapshot but gone from the data is shown,
|
|
925
|
+
* and whether it counts as data when it is.
|
|
926
|
+
*
|
|
927
|
+
* `false` — the default — leaves it out entirely. `'pinned'` shows it
|
|
928
|
+
* beneath the rows, struck through: visible history that is not part of the
|
|
929
|
+
* row set, so it is excluded from `rows.count()`, from exports and from
|
|
930
|
+
* selection. `'data'` appends it to the row set instead, so it *is*
|
|
931
|
+
* counted and exported.
|
|
932
|
+
*
|
|
933
|
+
* Neither is sorted or filtered among the live rows: a removed row's values
|
|
934
|
+
* are the snapshot's, and ordering yesterday's numbers among today's would
|
|
935
|
+
* present two data sets as one. Neither can be edited — there is nothing
|
|
936
|
+
* left to write to.
|
|
937
|
+
*/
|
|
938
|
+
removedRows?: false | 'pinned' | 'data';
|
|
939
|
+
};
|
|
727
940
|
/** Saved views (§15): a storage adapter and any pre-loaded views. */
|
|
728
941
|
views?: { storage?: { read(): unknown[]; write(views: unknown[]): void }; saved?: unknown[] };
|
|
729
942
|
/** The undo toolbar. `element` mounts it into the host's own chrome. */
|
|
@@ -733,13 +946,35 @@ export interface GridConfig {
|
|
|
733
946
|
* host's, and owns the model, the key and the privacy decision.
|
|
734
947
|
*/
|
|
735
948
|
ai?: {
|
|
736
|
-
ask(p: {
|
|
949
|
+
ask(p: {
|
|
950
|
+
/** The full text to send: the schema description and the question together. */
|
|
951
|
+
prompt: string;
|
|
952
|
+
/** The grid's schema as data — columns, types and operators. No row values. */
|
|
953
|
+
schema: unknown;
|
|
954
|
+
/** The same schema rendered as text, which is what `prompt` embeds. */
|
|
955
|
+
schemaText: string;
|
|
956
|
+
/** What the user typed. */
|
|
957
|
+
message: string;
|
|
958
|
+
context?: unknown;
|
|
959
|
+
}): Promise<unknown>;
|
|
737
960
|
schemaOptions?: object;
|
|
738
961
|
context?: unknown;
|
|
739
962
|
element?: HTMLElement;
|
|
740
963
|
placeholder?: string;
|
|
741
964
|
};
|
|
742
|
-
pivot?: {
|
|
965
|
+
pivot?: {
|
|
966
|
+
enabled?: boolean;
|
|
967
|
+
/**
|
|
968
|
+
* Add a column group totalling every value column across all pivot values —
|
|
969
|
+
* the grand total beside the pivoted ones. `'before'` places it at the near
|
|
970
|
+
* edge, `'after'` at the far edge. Omitted or `false` adds none.
|
|
971
|
+
*/
|
|
972
|
+
groupTotals?: 'before' | 'after' | false;
|
|
973
|
+
/** Heading for that group. Defaults to `Total`. */
|
|
974
|
+
totalsLabel?: string;
|
|
975
|
+
maxColumns?: number;
|
|
976
|
+
separator?: string;
|
|
977
|
+
};
|
|
743
978
|
}
|
|
744
979
|
|
|
745
980
|
/**
|
|
@@ -795,6 +1030,7 @@ export interface GridState {
|
|
|
795
1030
|
sort?: SortEntry[];
|
|
796
1031
|
group?: string[];
|
|
797
1032
|
pivot?: { enabled: boolean; columns: string[] };
|
|
1033
|
+
formatting?: Record<string, FormattingRule[]>;
|
|
798
1034
|
expanded?: string[];
|
|
799
1035
|
selection?: string[];
|
|
800
1036
|
scroll?: { top: number; left: number };
|
|
@@ -806,13 +1042,65 @@ export interface StateApplyReport {
|
|
|
806
1042
|
skipped: { key: string; reason: string }[];
|
|
807
1043
|
}
|
|
808
1044
|
|
|
1045
|
+
// ---------------------------------------------------------------------------
|
|
1046
|
+
// Conditional formatting (spec 8.12)
|
|
1047
|
+
// ---------------------------------------------------------------------------
|
|
1048
|
+
|
|
1049
|
+
export interface FormattingCondition {
|
|
1050
|
+
op: Operator;
|
|
1051
|
+
value?: unknown;
|
|
1052
|
+
value2?: unknown;
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
export interface FormattingScale {
|
|
1056
|
+
min: number;
|
|
1057
|
+
max: number;
|
|
1058
|
+
mid?: number;
|
|
1059
|
+
colours?: string[];
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
/**
|
|
1063
|
+
* One rule. Either a condition and the styling it produces, or a colour scale.
|
|
1064
|
+
* A rule held as runtime state must be JSON, so `style` may not be a function
|
|
1065
|
+
* there — config-time `cell.style` still accepts one.
|
|
1066
|
+
*/
|
|
1067
|
+
export interface FormattingRule {
|
|
1068
|
+
id?: string;
|
|
1069
|
+
when?: FormattingCondition;
|
|
1070
|
+
style?: CellStyle | ((p: CellParams) => CellStyle | null);
|
|
1071
|
+
scale?: FormattingScale;
|
|
1072
|
+
stopIfTrue?: boolean;
|
|
1073
|
+
enabled?: boolean;
|
|
1074
|
+
icon?: string;
|
|
1075
|
+
bar?: boolean;
|
|
1076
|
+
label?: string;
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
/** A column id, or `'*'` for every column. */
|
|
1080
|
+
export type FormattingScope = string;
|
|
1081
|
+
|
|
1082
|
+
export interface FormattingApi {
|
|
1083
|
+
list(scope?: FormattingScope): FormattingRule[];
|
|
1084
|
+
all(): Record<FormattingScope, FormattingRule[]>;
|
|
1085
|
+
scopes(): FormattingScope[];
|
|
1086
|
+
add(scope: FormattingScope, rule: FormattingRule, opts?: { at?: number }): FormattingRule | null;
|
|
1087
|
+
remove(scope: FormattingScope, which: string | number): boolean;
|
|
1088
|
+
update(scope: FormattingScope, which: string | number, patch: FormattingRule): FormattingRule | null;
|
|
1089
|
+
move(scope: FormattingScope, which: string | number, to: number): boolean;
|
|
1090
|
+
set(scope: FormattingScope, rules: FormattingRule[]): FormattingRule[];
|
|
1091
|
+
replaceAll(rules: Record<FormattingScope, FormattingRule[]>): void;
|
|
1092
|
+
clear(scope?: FormattingScope): void;
|
|
1093
|
+
styleFor(colId: string, value: unknown): CellStyle | null;
|
|
1094
|
+
}
|
|
1095
|
+
|
|
809
1096
|
// ---------------------------------------------------------------------------
|
|
810
1097
|
// Events (spec 18.4)
|
|
811
1098
|
// ---------------------------------------------------------------------------
|
|
812
1099
|
|
|
813
1100
|
export type EventName =
|
|
814
1101
|
| 'ready' | 'destroy' | 'render:first' | 'model:changed' | 'rows:changed' | 'rows:queued'
|
|
815
|
-
| 'cell:changed' | 'cell:
|
|
1102
|
+
| 'cell:changed' | 'cell:pending' | 'cell:confirmed' | 'cell:reverted'
|
|
1103
|
+
| 'cell:clicked' | 'cell:dblclicked' | 'cell:contextmenu'
|
|
816
1104
|
| 'cell:edit:start' | 'cell:edit:end' | 'row:edit:start' | 'row:edit:end'
|
|
817
1105
|
| 'row:clicked' | 'row:dblclicked' | 'group:toggled'
|
|
818
1106
|
| 'sort:changed' | 'filter:changed'
|
|
@@ -911,6 +1199,8 @@ export interface RowsApi {
|
|
|
911
1199
|
count(): number;
|
|
912
1200
|
/** Rows in the source before filtering; under pagination, across every page. */
|
|
913
1201
|
totalCount(): number;
|
|
1202
|
+
/** Data rows matching the filters, excluding group, footer and total rows. */
|
|
1203
|
+
matchCount(): number;
|
|
914
1204
|
data(): unknown[];
|
|
915
1205
|
forEach(fn: (row: Row, index: number) => void): void;
|
|
916
1206
|
value(key: string, colId: string): unknown;
|
|
@@ -941,15 +1231,35 @@ export interface ColumnsApi {
|
|
|
941
1231
|
totals(ids: string | string[]): void;
|
|
942
1232
|
}
|
|
943
1233
|
|
|
1234
|
+
export interface DetailApi {
|
|
1235
|
+
enabled(): boolean;
|
|
1236
|
+
isMaster(target: string | Row): boolean;
|
|
1237
|
+
isOpen(key: string): boolean;
|
|
1238
|
+
open(key: string): void;
|
|
1239
|
+
close(key: string): void;
|
|
1240
|
+
toggle(key: string): boolean;
|
|
1241
|
+
closeAll(): void;
|
|
1242
|
+
keys(): string[];
|
|
1243
|
+
active(): string | null;
|
|
1244
|
+
placement(): 'inline' | 'target' | null;
|
|
1245
|
+
config(): DetailConfig | null;
|
|
1246
|
+
}
|
|
1247
|
+
|
|
944
1248
|
export interface SelectionApi {
|
|
945
1249
|
rows(): Row[];
|
|
946
1250
|
keys(): string[];
|
|
947
1251
|
set(keys: string[]): void;
|
|
948
1252
|
all(): void;
|
|
949
1253
|
clear(): void;
|
|
1254
|
+
headerState(): boolean | 'partial';
|
|
950
1255
|
cells(): { key: string; colId: string }[];
|
|
951
1256
|
ranges(): CellRange[];
|
|
952
1257
|
setRange(range: CellRange): void;
|
|
1258
|
+
addRange(range: CellRange): void;
|
|
1259
|
+
startRange(rowIndex: number, colId: string, opts?: { additive?: boolean }): void;
|
|
1260
|
+
extendRange(rowIndex: number, colId: string): void;
|
|
1261
|
+
corner(): { row: number; colId: string } | null;
|
|
1262
|
+
inRange(rowIndex: number, colId: string): boolean;
|
|
953
1263
|
}
|
|
954
1264
|
|
|
955
1265
|
export interface CellRange {
|
|
@@ -972,10 +1282,15 @@ export interface SortApi {
|
|
|
972
1282
|
}
|
|
973
1283
|
|
|
974
1284
|
export interface EditApi {
|
|
975
|
-
start(key: string, colId: string):
|
|
1285
|
+
start(key: string, colId: string): boolean;
|
|
976
1286
|
stop(cancel?: boolean): void;
|
|
977
1287
|
undo(): void;
|
|
978
1288
|
redo(): void;
|
|
1289
|
+
setCells(writes: { key: string; colId: string; value: unknown }[], type?: 'cell' | 'fill' | 'paste'): number;
|
|
1290
|
+
pasteInto(anchor: { key: string; colId: string }, text: string, extent?: { rows?: number; columns?: number }): number;
|
|
1291
|
+
settle(id: string, ok: boolean, reason?: string): boolean;
|
|
1292
|
+
pending(): OpenWrite[];
|
|
1293
|
+
status(key: string, colId: string): 'pending' | null;
|
|
979
1294
|
}
|
|
980
1295
|
|
|
981
1296
|
export interface ScrollApi {
|
|
@@ -1032,6 +1347,436 @@ export interface RowStyleParams {
|
|
|
1032
1347
|
context: unknown;
|
|
1033
1348
|
}
|
|
1034
1349
|
|
|
1350
|
+
/**
|
|
1351
|
+
* Presentation mode renders the grid for a room: full-screen, application
|
|
1352
|
+
* chrome hidden, and everything enlarged by a scale that multiplies the
|
|
1353
|
+
* configured density rather than replacing it. The data stays live and
|
|
1354
|
+
* interactive throughout.
|
|
1355
|
+
*/
|
|
1356
|
+
/**
|
|
1357
|
+
* Rendering the grid to a still image. `scale` multiplies the pixel dimensions
|
|
1358
|
+
* — 2 for a retina still, 3 or 4 for a slide. `background` fills behind the
|
|
1359
|
+
* grid so a PNG dropped into a deck does not show it through.
|
|
1360
|
+
*/
|
|
1361
|
+
export interface CaptureOptions {
|
|
1362
|
+
scale?: number;
|
|
1363
|
+
background?: string;
|
|
1364
|
+
download?: boolean;
|
|
1365
|
+
fileName?: string;
|
|
1366
|
+
}
|
|
1367
|
+
|
|
1368
|
+
/**
|
|
1369
|
+
* The presenter's drawing layer. Pixels over the grid — it never reads or
|
|
1370
|
+
* writes data, and it is inert until a tool is chosen, so scrolling and
|
|
1371
|
+
* selection pass straight through. Marks are held in content coordinates, so
|
|
1372
|
+
* they stay with the cells they annotate when the grid scrolls, and are
|
|
1373
|
+
* cleared when a presentation ends.
|
|
1374
|
+
*/
|
|
1375
|
+
export interface AnnotationApi {
|
|
1376
|
+
readonly tool: 'pen' | 'arrow' | 'rect' | 'highlight' | null;
|
|
1377
|
+
readonly count: number;
|
|
1378
|
+
use(tool: 'pen' | 'arrow' | 'rect' | 'highlight' | null, opts?: { colour?: string }): string | null;
|
|
1379
|
+
undo(): number;
|
|
1380
|
+
clear(): void;
|
|
1381
|
+
redraw(): void;
|
|
1382
|
+
}
|
|
1383
|
+
|
|
1384
|
+
/**
|
|
1385
|
+
* Holding incoming updates, and the counters describing what they cost.
|
|
1386
|
+
* Pausing is explicit — a button, not a guess at whether the user is busy.
|
|
1387
|
+
*/
|
|
1388
|
+
/** One thing the grid has flagged as probably a mistake. */
|
|
1389
|
+
export interface DiagnosticWarning {
|
|
1390
|
+
/** Stable identifier, nameable in a support conversation. */
|
|
1391
|
+
id: string;
|
|
1392
|
+
message: string;
|
|
1393
|
+
/** The specific values involved, so the warning is actionable. */
|
|
1394
|
+
values: Record<string, unknown>;
|
|
1395
|
+
count: number;
|
|
1396
|
+
first: number;
|
|
1397
|
+
last: number;
|
|
1398
|
+
/** `'check'` raised by a diagnostic check, `'reported'` from `warnOnce`. */
|
|
1399
|
+
source: 'check' | 'reported' | 'info';
|
|
1400
|
+
}
|
|
1401
|
+
|
|
1402
|
+
export interface DiagnosticsApi {
|
|
1403
|
+
snapshot(): Record<string, unknown>;
|
|
1404
|
+
/** `dom.cellWrites` is the figure a DOM-write assertion reads. */
|
|
1405
|
+
renders(): Record<string, unknown>;
|
|
1406
|
+
store(): Record<string, unknown>;
|
|
1407
|
+
operations(): Record<string, unknown>;
|
|
1408
|
+
providers(): Record<string, unknown>;
|
|
1409
|
+
events(): Record<string, number>;
|
|
1410
|
+
config(): { effective: Record<string, unknown>; supplied: string[]; defaulted: string[] };
|
|
1411
|
+
warnings(): DiagnosticWarning[];
|
|
1412
|
+
dismiss(id: string): void;
|
|
1413
|
+
/** Contains no row data, cell values or column values. */
|
|
1414
|
+
bundle(): Record<string, unknown>;
|
|
1415
|
+
checkOptions(options: unknown): boolean;
|
|
1416
|
+
record(kind: string, detail: { rows?: number; ms?: number; worker?: boolean }): void;
|
|
1417
|
+
render(cause: string, phases?: Record<string, number>): void;
|
|
1418
|
+
/** Off by default; recording times every emit. */
|
|
1419
|
+
recordEvents(on: boolean, limit?: number): void;
|
|
1420
|
+
eventLog(): Array<{ type: string; origin: string; listeners: number;
|
|
1421
|
+
payload: Record<string, string>; at: number; ms: number }>;
|
|
1422
|
+
clearEventLog(): void;
|
|
1423
|
+
/** Keep current store statistics so growth can be measured against them. */
|
|
1424
|
+
mark(): Record<string, unknown>;
|
|
1425
|
+
since(): Record<string, unknown> | null;
|
|
1426
|
+
reset(): void;
|
|
1427
|
+
}
|
|
1428
|
+
|
|
1429
|
+
/** One peer, as the grid holds them. */
|
|
1430
|
+
export interface Peer {
|
|
1431
|
+
id: string;
|
|
1432
|
+
name: string;
|
|
1433
|
+
/** Assigned deterministically from the id when the provider supplies none. */
|
|
1434
|
+
colour: string;
|
|
1435
|
+
avatarUrl?: string | null;
|
|
1436
|
+
initials?: string | null;
|
|
1437
|
+
/** Row key and column, never an index. */
|
|
1438
|
+
cursor: { rowId: string; colId: string } | null;
|
|
1439
|
+
ranges: Array<{ rowIds: string[]; columns: string[] }>;
|
|
1440
|
+
editing: { rowId: string; colId: string } | null;
|
|
1441
|
+
/** Local receipt time, not the sender's clock. */
|
|
1442
|
+
at: number;
|
|
1443
|
+
/** The sender's own timestamp, for inspection only. Nothing decides on it. */
|
|
1444
|
+
sentAt?: number | null;
|
|
1445
|
+
idle?: boolean;
|
|
1446
|
+
silentMs?: number;
|
|
1447
|
+
/** True when the peer's cursor is on a row this view is not showing. */
|
|
1448
|
+
hidden?: boolean;
|
|
1449
|
+
}
|
|
1450
|
+
|
|
1451
|
+
/**
|
|
1452
|
+
* Transport for presence. The grid never opens a connection: it subscribes to
|
|
1453
|
+
* what the provider delivers and hands it what changed locally.
|
|
1454
|
+
*/
|
|
1455
|
+
export interface PresenceProvider {
|
|
1456
|
+
/** Returns an unsubscribe function, if it has one. */
|
|
1457
|
+
subscribe(onMessage: (message: Peer | Peer[]) => void): (() => void) | void;
|
|
1458
|
+
publish(state: Record<string, unknown>): void;
|
|
1459
|
+
}
|
|
1460
|
+
|
|
1461
|
+
export interface PresenceConfig {
|
|
1462
|
+
/** Without one the feature is inert and raises nothing. */
|
|
1463
|
+
provider?: PresenceProvider;
|
|
1464
|
+
/** The local identity, echoed in everything published. */
|
|
1465
|
+
me?: { id: string; name?: string; colour?: string; avatarUrl?: string; initials?: string };
|
|
1466
|
+
/** Milliseconds between published updates. Throttled, not debounced. */
|
|
1467
|
+
throttleMs?: number;
|
|
1468
|
+
/** Silence after which a peer is shown idle. */
|
|
1469
|
+
idleMs?: number;
|
|
1470
|
+
/** Silence after which a peer is dropped. */
|
|
1471
|
+
removeMs?: number;
|
|
1472
|
+
/** Silence after which a peer's edit claim is disregarded. */
|
|
1473
|
+
lockMs?: number;
|
|
1474
|
+
/**
|
|
1475
|
+
* Refuse local editing of a cell a peer is editing. Advisory only: the
|
|
1476
|
+
* authoritative resolution is the conditional write in `edit.commit`.
|
|
1477
|
+
*/
|
|
1478
|
+
lock?: boolean;
|
|
1479
|
+
/** Override the peer colour palette. */
|
|
1480
|
+
palette?: string[];
|
|
1481
|
+
/** Suppress the roster, or place it. */
|
|
1482
|
+
roster?: boolean | { side?: 'start' | 'end' };
|
|
1483
|
+
/** Suppress join and leave announcements to assistive technology. */
|
|
1484
|
+
announce?: boolean;
|
|
1485
|
+
}
|
|
1486
|
+
|
|
1487
|
+
export interface PresenceApi {
|
|
1488
|
+
readonly enabled: boolean;
|
|
1489
|
+
readonly me: Record<string, unknown> | null;
|
|
1490
|
+
readonly publishing: boolean;
|
|
1491
|
+
peers(): Peer[];
|
|
1492
|
+
hiddenCount(): number;
|
|
1493
|
+
editorOf(rowId: string, colId: string): Peer | null;
|
|
1494
|
+
/** Advisory. Reduces collisions; does not eliminate them. */
|
|
1495
|
+
lockedBy(rowId: string, colId: string): Peer | null;
|
|
1496
|
+
jumpTo(peerId: string): boolean;
|
|
1497
|
+
publish(): void;
|
|
1498
|
+
setPublishing(on: boolean): void;
|
|
1499
|
+
setPaused(paused: boolean): void;
|
|
1500
|
+
connect(provider: PresenceProvider | null): void;
|
|
1501
|
+
stats(): Record<string, number>;
|
|
1502
|
+
}
|
|
1503
|
+
|
|
1504
|
+
/** One comment in a thread, as the provider returns it. */
|
|
1505
|
+
export interface Comment {
|
|
1506
|
+
id: string;
|
|
1507
|
+
body: string;
|
|
1508
|
+
/** Rendered as supplied. The grid does not know who the user is. */
|
|
1509
|
+
author?: { name?: string; avatarUrl?: string; initials?: string };
|
|
1510
|
+
at?: number;
|
|
1511
|
+
edited?: boolean;
|
|
1512
|
+
resolved?: boolean;
|
|
1513
|
+
parentId?: string | null;
|
|
1514
|
+
/** The cell's value when this was written, so a later reader is told it moved. */
|
|
1515
|
+
value?: unknown;
|
|
1516
|
+
/**
|
|
1517
|
+
* What the current user may do. Absent means the grid shows every affordance
|
|
1518
|
+
* and relies on the provider to refuse. Hiding a button is a convenience,
|
|
1519
|
+
* never a security control.
|
|
1520
|
+
*/
|
|
1521
|
+
can?: { edit?: boolean; delete?: boolean; resolve?: boolean };
|
|
1522
|
+
}
|
|
1523
|
+
|
|
1524
|
+
/** Counts for one cell. Never bodies — this is consulted on every repaint. */
|
|
1525
|
+
export interface CommentDescriptor {
|
|
1526
|
+
count: number;
|
|
1527
|
+
unresolved: number;
|
|
1528
|
+
updated: number;
|
|
1529
|
+
}
|
|
1530
|
+
|
|
1531
|
+
/** What `loadIndex` returns per commented cell. */
|
|
1532
|
+
export interface CommentIndexEntry extends CommentDescriptor {
|
|
1533
|
+
cellKey?: string;
|
|
1534
|
+
rowId?: string;
|
|
1535
|
+
field?: string;
|
|
1536
|
+
}
|
|
1537
|
+
|
|
1538
|
+
/**
|
|
1539
|
+
* Storage for comments. Every method returns a promise; a rejection surfaces in
|
|
1540
|
+
* the panel without disturbing grid state.
|
|
1541
|
+
*/
|
|
1542
|
+
export interface CommentProvider {
|
|
1543
|
+
loadIndex(rowIds: string[], fields: string[]): Promise<CommentIndexEntry[]>;
|
|
1544
|
+
loadThread(cellKey: string): Promise<Comment[]>;
|
|
1545
|
+
addComment(cellKey: string, body: string, parentId: string | null,
|
|
1546
|
+
context?: { value?: unknown }): Promise<Comment>;
|
|
1547
|
+
editComment(commentId: string, body: string): Promise<Comment>;
|
|
1548
|
+
deleteComment(commentId: string): Promise<void>;
|
|
1549
|
+
resolveThread(cellKey: string): Promise<void>;
|
|
1550
|
+
unresolveThread(cellKey: string): Promise<void>;
|
|
1551
|
+
}
|
|
1552
|
+
|
|
1553
|
+
export interface CommentConfig {
|
|
1554
|
+
/** Without one the feature is inert and no error is raised. */
|
|
1555
|
+
provider?: CommentProvider;
|
|
1556
|
+
/** Milliseconds a viewport change waits before the index is fetched. */
|
|
1557
|
+
debounce?: number;
|
|
1558
|
+
/** Cell descriptors held before the oldest are dropped. */
|
|
1559
|
+
indexLimit?: number;
|
|
1560
|
+
/** `'anchored'` floats beside the cell; `'docked'` uses a side panel. */
|
|
1561
|
+
mode?: 'anchored' | 'docked';
|
|
1562
|
+
/** Restricted markdown in bodies: emphasis, code and links only. */
|
|
1563
|
+
markdown?: boolean;
|
|
1564
|
+
/** Label for the row, so the panel says what is being commented on. */
|
|
1565
|
+
rowLabel?: (row: Row) => string;
|
|
1566
|
+
}
|
|
1567
|
+
|
|
1568
|
+
export interface CommentsApi {
|
|
1569
|
+
readonly enabled: boolean;
|
|
1570
|
+
readonly openKey: string | null;
|
|
1571
|
+
readonly thread: Comment[] | null;
|
|
1572
|
+
readonly loading: boolean;
|
|
1573
|
+
readonly complete: boolean;
|
|
1574
|
+
/** `'no-provider'`, `'no-row-identity'`, or null when available. */
|
|
1575
|
+
unavailable(): string | null;
|
|
1576
|
+
at(rowId: string, colId: string): CommentDescriptor | null;
|
|
1577
|
+
request(rowIds: string[], fields?: string[]): void;
|
|
1578
|
+
open(rowId: string, colId: string): Promise<Comment[] | null>;
|
|
1579
|
+
close(opts?: { reason?: string }): void;
|
|
1580
|
+
add(body: string, opts?: { parentId?: string; author?: object }): Promise<Comment | null>;
|
|
1581
|
+
edit(commentId: string, body: string): Promise<Comment | null>;
|
|
1582
|
+
remove(commentId: string): Promise<boolean>;
|
|
1583
|
+
resolve(): Promise<boolean>;
|
|
1584
|
+
unresolve(): Promise<boolean>;
|
|
1585
|
+
refresh(): void;
|
|
1586
|
+
loadAll(): Promise<boolean>;
|
|
1587
|
+
hiddenUnresolved(): number;
|
|
1588
|
+
filterToCommented(opts?: { unresolvedOnly?: boolean }): boolean;
|
|
1589
|
+
}
|
|
1590
|
+
|
|
1591
|
+
/** One bucket of a column's distribution. */
|
|
1592
|
+
export interface FacetBucket {
|
|
1593
|
+
/** Lower edge, for ordered columns. Half-open `[from, to)` except the last. */
|
|
1594
|
+
from?: number;
|
|
1595
|
+
/** Upper edge, for ordered columns. Inclusive on the last bucket only. */
|
|
1596
|
+
to?: number;
|
|
1597
|
+
/** The value, for categorical and boolean columns. */
|
|
1598
|
+
value?: unknown;
|
|
1599
|
+
/** True on the terminal bucket holding nulls, NaN and empty values. */
|
|
1600
|
+
null?: boolean;
|
|
1601
|
+
/** True on the aggregated tail bucket under `aboveLimit: 'topN'`. */
|
|
1602
|
+
remainder?: boolean;
|
|
1603
|
+
/** A ready-made label, where one is more useful than the raw value. */
|
|
1604
|
+
label?: string;
|
|
1605
|
+
}
|
|
1606
|
+
|
|
1607
|
+
/** Where a column's buckets are, and how they were chosen. */
|
|
1608
|
+
export interface FacetBounds {
|
|
1609
|
+
kind: 'numeric' | 'date' | 'category' | 'boolean' | 'none';
|
|
1610
|
+
buckets: FacetBucket[];
|
|
1611
|
+
/** Set when no histogram was drawn, naming why. */
|
|
1612
|
+
suppressed?: 'type' | 'cardinality' | 'rows' | 'streaming' | 'no-provider' | 'disabled';
|
|
1613
|
+
/** Distinct values, on categorical columns. */
|
|
1614
|
+
cardinality?: number;
|
|
1615
|
+
/** The time unit chosen, on date columns. */
|
|
1616
|
+
granularity?: 'hour' | 'day' | 'week' | 'month' | 'quarter' | 'year';
|
|
1617
|
+
/** The numeric strategy actually applied, which may differ from the request. */
|
|
1618
|
+
strategy?: 'equal' | 'quantile' | 'log';
|
|
1619
|
+
min?: number;
|
|
1620
|
+
max?: number;
|
|
1621
|
+
}
|
|
1622
|
+
|
|
1623
|
+
/** A column's computed distribution. */
|
|
1624
|
+
export interface FacetState {
|
|
1625
|
+
bounds: FacetBounds | null;
|
|
1626
|
+
/** Counts under every filter except this column's own. Aligned to `buckets`. */
|
|
1627
|
+
counts: Uint32Array | null;
|
|
1628
|
+
/** Counts with no filter applied, for the "40 of 200" reading. */
|
|
1629
|
+
unfiltered: Uint32Array | null;
|
|
1630
|
+
/** True while a recount is outstanding; draw the previous counts faded. */
|
|
1631
|
+
stale: boolean;
|
|
1632
|
+
suppressed: string | null;
|
|
1633
|
+
}
|
|
1634
|
+
|
|
1635
|
+
/** Per-column histogram settings, layered over the grid's. */
|
|
1636
|
+
export interface ColumnFacetConfig {
|
|
1637
|
+
enabled?: boolean;
|
|
1638
|
+
buckets?: number;
|
|
1639
|
+
strategy?: 'equal' | 'quantile' | 'log';
|
|
1640
|
+
granularity?: 'hour' | 'day' | 'week' | 'month' | 'quarter' | 'year';
|
|
1641
|
+
order?: 'count' | 'alpha';
|
|
1642
|
+
cardinalityLimit?: number;
|
|
1643
|
+
aboveLimit?: 'suppress' | 'topN';
|
|
1644
|
+
/** Replace the built-in bucketing entirely. */
|
|
1645
|
+
bucketFn?: (handle: unknown, indices: Uint32Array | null, count: number) => FacetBounds;
|
|
1646
|
+
/** Label a bucket for its tooltip and accessible name. */
|
|
1647
|
+
format?: (bucket: FacetBucket, count: number, unfiltered: number) => string;
|
|
1648
|
+
}
|
|
1649
|
+
|
|
1650
|
+
/** Grid-level histogram settings. */
|
|
1651
|
+
export interface FacetConfig extends ColumnFacetConfig {
|
|
1652
|
+
/** Off unless asked for: header space is tight and this doubles its height. */
|
|
1653
|
+
enabled?: boolean;
|
|
1654
|
+
/** Start as a one-line density strip that opens on hover or click. */
|
|
1655
|
+
collapsed?: boolean;
|
|
1656
|
+
/** Band height in pixels. */
|
|
1657
|
+
height?: number;
|
|
1658
|
+
/** Rows above which histograms are suppressed. */
|
|
1659
|
+
rowCeiling?: number;
|
|
1660
|
+
/** Milliseconds a filter change waits before charts recount. */
|
|
1661
|
+
debounce?: number;
|
|
1662
|
+
/** Whether a paused stream re-enables histograms. Defaults to true. */
|
|
1663
|
+
whilePaused?: boolean;
|
|
1664
|
+
/** Bucket counts for a source the client cannot compute over. */
|
|
1665
|
+
provider?: (request: {
|
|
1666
|
+
colId: string;
|
|
1667
|
+
column: unknown;
|
|
1668
|
+
filters: unknown;
|
|
1669
|
+
quick: string;
|
|
1670
|
+
bounds: FacetBounds | null;
|
|
1671
|
+
buckets: number;
|
|
1672
|
+
strategy: string;
|
|
1673
|
+
granularity?: string;
|
|
1674
|
+
}) => Promise<{ bounds?: FacetBounds; buckets?: FacetBucket[]; counts: ArrayLike<number>;
|
|
1675
|
+
unfiltered?: ArrayLike<number>; kind?: string }>;
|
|
1676
|
+
}
|
|
1677
|
+
|
|
1678
|
+
export interface FacetsApi {
|
|
1679
|
+
get(colId: string): FacetState | null;
|
|
1680
|
+
suppression(colId: string): string | null;
|
|
1681
|
+
config(colId?: string): FacetConfig;
|
|
1682
|
+
refresh(opts?: { immediate?: boolean }): void;
|
|
1683
|
+
isExpanded(colId: string): boolean;
|
|
1684
|
+
toggle(colId: string, open?: boolean): boolean;
|
|
1685
|
+
select(colId: string, from: number, to?: number,
|
|
1686
|
+
opts?: { additive?: boolean; gesture?: string }): boolean;
|
|
1687
|
+
clear(colId: string): boolean;
|
|
1688
|
+
selected(colId: string): number[];
|
|
1689
|
+
expanded(): string[];
|
|
1690
|
+
}
|
|
1691
|
+
|
|
1692
|
+
export interface UpdatesApi {
|
|
1693
|
+
readonly paused: boolean;
|
|
1694
|
+
pause(): boolean;
|
|
1695
|
+
resume(): ChangeResult;
|
|
1696
|
+
flush(): ChangeResult;
|
|
1697
|
+
stats(): {
|
|
1698
|
+
paused: boolean;
|
|
1699
|
+
pending: number;
|
|
1700
|
+
queued: number;
|
|
1701
|
+
coalesced: number;
|
|
1702
|
+
coalescedTotal: number;
|
|
1703
|
+
rows: number;
|
|
1704
|
+
dropped: number;
|
|
1705
|
+
held: number;
|
|
1706
|
+
heldLimit: number;
|
|
1707
|
+
flushes: number;
|
|
1708
|
+
strategy: string;
|
|
1709
|
+
deferrals: number;
|
|
1710
|
+
maxQueued: number;
|
|
1711
|
+
budgetMs: number;
|
|
1712
|
+
span: { from: number; to: number } | null;
|
|
1713
|
+
};
|
|
1714
|
+
log(opts?: { since?: number }): { at: number; change: RowChange; rows: number }[];
|
|
1715
|
+
}
|
|
1716
|
+
|
|
1717
|
+
/**
|
|
1718
|
+
* Moving the grid through recent data changes. Reads the change log rather
|
|
1719
|
+
* than the undo history: history records what the *user* did, and the question
|
|
1720
|
+
* on a live grid is what the *data* did. Nothing is scrubbable until
|
|
1721
|
+
* `attach()` — what a value used to be is not recoverable after the fact.
|
|
1722
|
+
*/
|
|
1723
|
+
export interface TimelineApi {
|
|
1724
|
+
readonly attached: boolean;
|
|
1725
|
+
readonly live: boolean;
|
|
1726
|
+
readonly position: number;
|
|
1727
|
+
readonly depth: number;
|
|
1728
|
+
attach(): void;
|
|
1729
|
+
detach(): void;
|
|
1730
|
+
seek(steps: number): number;
|
|
1731
|
+
step(by: number): number;
|
|
1732
|
+
toLive(): number;
|
|
1733
|
+
at(): number | null;
|
|
1734
|
+
span(): { from: number; to: number } | null;
|
|
1735
|
+
}
|
|
1736
|
+
|
|
1737
|
+
export interface PresentationApi {
|
|
1738
|
+
readonly active: boolean;
|
|
1739
|
+
readonly scale: number;
|
|
1740
|
+
readonly options: { scale?: number; chrome?: string[]; views?: string[]; from?: number; autoAdvance?: number };
|
|
1741
|
+
readonly views: string[];
|
|
1742
|
+
readonly index: number;
|
|
1743
|
+
readonly viewId: string | null;
|
|
1744
|
+
start(options?: {
|
|
1745
|
+
scale?: number;
|
|
1746
|
+
chrome?: string[];
|
|
1747
|
+
/** Saved view ids to step through. Views are the slides. */
|
|
1748
|
+
views?: string[];
|
|
1749
|
+
/** Where in that sequence to begin. */
|
|
1750
|
+
from?: number;
|
|
1751
|
+
/** Milliseconds between automatic advances, for an unattended display. */
|
|
1752
|
+
autoAdvance?: number;
|
|
1753
|
+
}): boolean;
|
|
1754
|
+
stop(): boolean;
|
|
1755
|
+
setScale(value: number): number;
|
|
1756
|
+
nudge(steps?: number): number;
|
|
1757
|
+
step(by?: number): number;
|
|
1758
|
+
goTo(index: number): number;
|
|
1759
|
+
reset(): boolean;
|
|
1760
|
+
readonly spotlight: { keys: string[]; colIds: string[] } | null;
|
|
1761
|
+
setSpotlight(target?: { keys?: string[]; colIds?: string[] } | null): boolean;
|
|
1762
|
+
}
|
|
1763
|
+
|
|
1764
|
+
/**
|
|
1765
|
+
* Redaction obscures a column's values on screen. It is presentational: the
|
|
1766
|
+
* values stay in the model, the DOM, the clipboard and every export. Use
|
|
1767
|
+
* `permissions` with `writeOnly` for a value that must not be readable.
|
|
1768
|
+
*/
|
|
1769
|
+
export interface RedactionApi {
|
|
1770
|
+
has(colId: string): boolean;
|
|
1771
|
+
list(): string[];
|
|
1772
|
+
toggle(colId: string): boolean;
|
|
1773
|
+
add(colId: string): void;
|
|
1774
|
+
remove(colId: string): void;
|
|
1775
|
+
set(ids: string[]): void;
|
|
1776
|
+
clear(): void;
|
|
1777
|
+
readonly active: boolean;
|
|
1778
|
+
}
|
|
1779
|
+
|
|
1035
1780
|
export interface HighlightApi {
|
|
1036
1781
|
/** Highlight a cell (`{key, colId}`), a row (`{key}`) or a column (`{colId}`). */
|
|
1037
1782
|
(target: { key?: string; colId?: string } | string,
|
|
@@ -1059,8 +1804,20 @@ export interface OverlayApi {
|
|
|
1059
1804
|
}
|
|
1060
1805
|
|
|
1061
1806
|
export interface HistoryEntry {
|
|
1807
|
+
/** Monotonic sequence number, in the order actions were recorded. */
|
|
1808
|
+
seq: number;
|
|
1809
|
+
/** What kind of action it was, e.g. `'sort'`, `'column:pin'`, `'edit'`. */
|
|
1810
|
+
type: string;
|
|
1811
|
+
/** Human text for a button, e.g. `'sort by Region'`. */
|
|
1062
1812
|
label: string;
|
|
1063
|
-
|
|
1813
|
+
/** The column or row the action was aimed at, where there was one. */
|
|
1814
|
+
target: string | null;
|
|
1815
|
+
/** When it was recorded, on the high-resolution clock. */
|
|
1816
|
+
at: number;
|
|
1817
|
+
/** True when the edit model owns the undo rather than the history stack. */
|
|
1818
|
+
delegated: boolean;
|
|
1819
|
+
/** Set once the entry has been undone. */
|
|
1820
|
+
undone?: boolean;
|
|
1064
1821
|
[key: string]: unknown;
|
|
1065
1822
|
}
|
|
1066
1823
|
|
|
@@ -1136,7 +1893,14 @@ export interface AiApi {
|
|
|
1136
1893
|
schema(opts?: { maxColumns?: number; maxRows?: number }): Record<string, unknown>;
|
|
1137
1894
|
/** The same schema as a tool definition. */
|
|
1138
1895
|
tool(opts?: { maxColumns?: number; maxRows?: number }): Record<string, unknown>;
|
|
1139
|
-
|
|
1896
|
+
/**
|
|
1897
|
+
* The prompt describing this grid — its columns, types and operators — for
|
|
1898
|
+
* sending to a model. It carries no row values.
|
|
1899
|
+
*
|
|
1900
|
+
* It does not take the user's question: compose that yourself alongside the
|
|
1901
|
+
* text this returns, which is what `ask` receives as `schemaText`.
|
|
1902
|
+
*/
|
|
1903
|
+
prompt(opts?: Record<string, unknown>): string;
|
|
1140
1904
|
buildPrompt(text: string, opts?: Record<string, unknown>): string;
|
|
1141
1905
|
/** Parse what the model returned into a plan. */
|
|
1142
1906
|
plan(reply: string | Record<string, unknown>, opts?: Record<string, unknown>): Record<string, unknown>;
|
|
@@ -1164,6 +1928,48 @@ export interface PaginationApi {
|
|
|
1164
1928
|
* created with `createGrid` unless `maximise: false`; never on a headless grid,
|
|
1165
1929
|
* which has no window to fill.
|
|
1166
1930
|
*/
|
|
1931
|
+
/** What a cell-menu builder and a host item's `action` are handed. */
|
|
1932
|
+
export interface CellMenuParams {
|
|
1933
|
+
key: string;
|
|
1934
|
+
colId: string;
|
|
1935
|
+
value: unknown;
|
|
1936
|
+
/** The row wrapper. */
|
|
1937
|
+
row: Row;
|
|
1938
|
+
/** Your original row object. */
|
|
1939
|
+
data: unknown;
|
|
1940
|
+
column: ResolvedColumn;
|
|
1941
|
+
index: number;
|
|
1942
|
+
grid: Grid;
|
|
1943
|
+
}
|
|
1944
|
+
|
|
1945
|
+
/** What a host rail action's `run` is handed. */
|
|
1946
|
+
/** The rail's built-in action names, plus `'-'` for a divider. */
|
|
1947
|
+
export type RailActionName =
|
|
1948
|
+
| 'undo' | 'redo' | 'pause' | 'restore' | 'maximise'
|
|
1949
|
+
| 'export' | 'excel' | 'clipboard' | 'print';
|
|
1950
|
+
|
|
1951
|
+
export interface RailActionParams {
|
|
1952
|
+
grid: Grid;
|
|
1953
|
+
keys: string[];
|
|
1954
|
+
cells: { key: string; colId: string }[];
|
|
1955
|
+
}
|
|
1956
|
+
|
|
1957
|
+
export interface RailAction {
|
|
1958
|
+
name: string;
|
|
1959
|
+
title: string | (() => string);
|
|
1960
|
+
icon?: string | (() => string);
|
|
1961
|
+
run(params: RailActionParams): void;
|
|
1962
|
+
enabled?(): boolean;
|
|
1963
|
+
}
|
|
1964
|
+
|
|
1965
|
+
/** The result of evaluating a formula a user typed into a cell (spec 8.11). */
|
|
1966
|
+
export type FormulaResult =
|
|
1967
|
+
| { ok: true; value: unknown; references: string[] }
|
|
1968
|
+
| { ok: false; error: string; at?: number };
|
|
1969
|
+
|
|
1970
|
+
export function evaluateFormula(text: string, params?: ParseParams): FormulaResult;
|
|
1971
|
+
export function looksLikeFormula(text: unknown): boolean;
|
|
1972
|
+
|
|
1167
1973
|
export interface MaximiseApi {
|
|
1168
1974
|
enter(): boolean;
|
|
1169
1975
|
exit(): boolean;
|
|
@@ -1190,7 +1996,27 @@ export interface Grid {
|
|
|
1190
1996
|
readonly licence: LicenceApi;
|
|
1191
1997
|
readonly pagination: PaginationApi;
|
|
1192
1998
|
readonly highlight: HighlightApi;
|
|
1999
|
+
readonly redaction: RedactionApi;
|
|
2000
|
+
capture?(opts?: CaptureOptions): Promise<Blob>;
|
|
2001
|
+
annotate?: AnnotationApi;
|
|
2002
|
+
readonly presentation: PresentationApi;
|
|
2003
|
+
readonly updates: UpdatesApi;
|
|
2004
|
+
readonly timeline: TimelineApi;
|
|
2005
|
+
readonly facets: FacetsApi;
|
|
2006
|
+
readonly detail: DetailApi;
|
|
2007
|
+
readonly comments: CommentsApi;
|
|
2008
|
+
readonly presence: PresenceApi;
|
|
2009
|
+
readonly diagnostics: DiagnosticsApi;
|
|
2010
|
+
readonly formatting: FormattingApi;
|
|
1193
2011
|
readonly maximise?: MaximiseApi;
|
|
2012
|
+
/**
|
|
2013
|
+
* The element you passed to `createGrid`, not the grid's own root.
|
|
2014
|
+
*
|
|
2015
|
+
* The grid builds its `.lattice` root *inside* that element, so
|
|
2016
|
+
* `el.closest('.lattice')` never matches this, and a theme attribute set on
|
|
2017
|
+
* it has no effect — the theme is read from the root within. Use
|
|
2018
|
+
* `element.querySelector('.lattice')` for the grid's own root.
|
|
2019
|
+
*/
|
|
1194
2020
|
readonly element: HTMLElement | null;
|
|
1195
2021
|
readonly destroyed: boolean;
|
|
1196
2022
|
/** False until the first render has been laid out. */
|