@toclocoinc/lattice-grid 1.5.5 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lattice-grid.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Lattice Grid 1.5.4 — type declarations
2
+ * Lattice Grid 1.6.0 — type declarations
3
3
  * Copyright (c) 2026 TOCLOCO Inc. All rights reserved.
4
4
  * https://latticegrid.dev
5
5
  */
@@ -19,15 +19,39 @@
19
19
  export type TypeName =
20
20
  | 'text' | 'number' | 'boolean' | 'date' | 'dateString' | 'object' | 'lookup'
21
21
  | 'image'
22
+ // Extended catalogue. Never inferred — a column asks for these by name.
23
+ | 'time' | 'datetime' | 'duration'
24
+ | 'ipv4' | 'ipv6' | 'cidr'
25
+ | 'json' | 'secret'
26
+ | 'hex' | 'hex8' | 'hex16' | 'hex32' | 'binary' | 'binary8' | 'octal'
27
+ | 'decibel' | 'decibelAmplitude' | 'ratio' | 'percentRate'
28
+ // Units — computing
29
+ | 'bytes' | 'megabytes' | 'gigabytes' | 'bitrate' | 'gigabits'
30
+ // Units — physical
31
+ | 'metres' | 'millimetres' | 'kilometres'
32
+ | 'grams' | 'kilograms' | 'tonnes'
33
+ | 'seconds' | 'milliseconds' | 'hours'
34
+ // Units — engineering
35
+ | 'speed' | 'kph' | 'mph' | 'knots' | 'acceleration'
36
+ | 'area' | 'hectares' | 'volume' | 'cubicMetres'
37
+ | 'energy' | 'kilowattHours' | 'power' | 'kilowatts' | 'force'
38
+ | 'pressure' | 'bar' | 'psi' | 'torque' | 'density'
39
+ | 'flow' | 'litresPerMinute' | 'radians' | 'degrees'
40
+ // Units — electrical and scientific
41
+ | 'voltage' | 'current' | 'resistance' | 'capacitance' | 'inductance'
42
+ | 'charge' | 'conductance' | 'fluxDensity' | 'luminousFlux' | 'illuminance'
43
+ | 'substance' | 'absorbedDose' | 'equivalentDose' | 'radioactivity' | 'frequency'
44
+ // Temperature, which is affine rather than multiplicative
45
+ | 'celsius' | 'fahrenheit' | 'kelvin'
22
46
  | (string & {});
23
47
 
24
48
  /**
25
49
  * Cell and header alignment.
26
50
  *
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`.
51
+ * `left` and `right` are accepted and normalised to `start` and `end`.
52
+ * `start`/`end` follow the writing direction, so they mirror in a right-to-left
53
+ * grid while `left`/`right` stay physical. `centre` is accepted alongside
54
+ * `center`.
31
55
  */
32
56
  export type Align = 'start' | 'center' | 'end' | 'left' | 'right' | 'centre';
33
57
  /**
@@ -77,6 +101,11 @@ export interface Row {
77
101
  /** Stable path of group keys from root to this row. */
78
102
  groupPath?: string[];
79
103
  hasChildren?: boolean;
104
+ /**
105
+ * Which sticky strip this row is pinned in, when it is one the host pinned
106
+ * through `setPinnedRows`. Absent on every row that is part of the data.
107
+ */
108
+ pinned?: 'top' | 'bottom';
80
109
  }
81
110
 
82
111
  export interface RowChange {
@@ -130,7 +159,7 @@ export interface CellParams extends ValueParams {
130
159
  }
131
160
 
132
161
  export interface FormatParams extends ValueParams { locale: string }
133
- export interface ParseParams { text: string; value: unknown; data: unknown; row: Row; column: Column; grid: Grid; context: unknown }
162
+ export interface ParseParams { text: string; value: unknown; data: unknown; row: Row; column: Column; grid: Grid; context: unknown; locale?: string }
134
163
  export interface ApplyParams { value: unknown; oldValue: unknown; data: unknown; row: Row; column: Column; grid: Grid; context: unknown }
135
164
  export interface KeyParams extends ValueParams {}
136
165
  export interface ValidateParams extends ApplyParams {}
@@ -160,6 +189,20 @@ export interface NumberFormat {
160
189
  zeroDisplay?: string;
161
190
  nullDisplay?: string;
162
191
  locale?: string;
192
+ /**
193
+ * A partial message catalogue laid over the built-in British English one.
194
+ *
195
+ * Every valid key is listed in `MESSAGE_KEYS`; a key that is not is ignored
196
+ * with a warning. Import a bundled locale (`FR_FR`, `AR`, …) or supply your
197
+ * own object. Merged rather than replacing, so an incomplete translation
198
+ * leaves the remainder in English rather than showing raw keys.
199
+ */
200
+ messages?: Record<string, string | Record<string, string>>;
201
+ /**
202
+ * Writing direction. Omit to settle it from the element's own `dir` and then
203
+ * from `locale` — `ar`, `he`, `fa` and the rest resolve to `rtl`.
204
+ */
205
+ direction?: 'ltr' | 'rtl';
163
206
  scale?: number;
164
207
  }
165
208
 
@@ -214,6 +257,28 @@ export interface DataType {
214
257
  render?: RendererName;
215
258
  };
216
259
  storage?: 'float64' | 'int32' | 'bitset' | 'dictionary' | 'object';
260
+
261
+ /**
262
+ * Which aggregates are meaningful for this type, and how.
263
+ *
264
+ * Omit it and every aggregate is allowed, which is what every type that
265
+ * shipped before this does.
266
+ */
267
+ totals?: {
268
+ /**
269
+ * The aggregates that mean something. A column of this type configured
270
+ * with any other fails at construction rather than rendering a confident
271
+ * wrong number.
272
+ */
273
+ supported?: TotalName[];
274
+ /**
275
+ * The type's own reduction for an aggregate, replacing the built-in
276
+ * arithmetic. Receives the values index-aligned with their rows, and a
277
+ * context carrying `column` and `valueAt(colId, i)` for reading another
278
+ * column of the same row.
279
+ */
280
+ implement?: Record<string, TotalFn>;
281
+ };
217
282
  excel?: string;
218
283
  toClipboard?: (v: unknown) => string;
219
284
  fromClipboard?: (s: string) => unknown;
@@ -417,7 +482,16 @@ export interface ColumnFilterSpec {
417
482
  }
418
483
 
419
484
  export interface ColumnLayoutSpec {
420
- width?: number;
485
+ /**
486
+ * A pixel width, or a percentage of the grid's inner width as a string —
487
+ * `'25%'`.
488
+ *
489
+ * A percentage is a share of the *whole* grid. `flex` divides only the space
490
+ * left over after fixed columns, so the two are not interchangeable: `flex:
491
+ * 25` on four columns is a quarter of the remainder, which is a quarter of
492
+ * the grid only when nothing else is fixed.
493
+ */
494
+ width?: number | string;
421
495
  min?: number;
422
496
  max?: number;
423
497
  flex?: number;
@@ -445,6 +519,14 @@ export interface ColumnExportSpec {
445
519
  }
446
520
 
447
521
  export interface Column {
522
+ /**
523
+ * Free-form labels for grouping columns together. A bare string is
524
+ * accepted for a single tag.
525
+ *
526
+ * Used by the column tag bar to show and hide sets of columns — tag sixty
527
+ * monthly columns with their year, and a user can switch to one year.
528
+ */
529
+ tags?: string | string[];
448
530
  id?: string;
449
531
  field?: string;
450
532
  title?: string;
@@ -669,7 +751,7 @@ export interface DetailConfig {
669
751
  /**
670
752
  * Render the detail into this element instead of into a row beneath its
671
753
  * master. A selector or an element. Exactly one detail is open at a time in
672
- * this placement (§13).
754
+ * this placement.
673
755
  */
674
756
  target?: string | HTMLElement;
675
757
  /** Handed the nested grid as it is created, for whatever the forwarded events do not cover. */
@@ -678,7 +760,7 @@ export interface DetailConfig {
678
760
  * The property of the master's record the detail rows live on, so an edit in
679
761
  * the detail is reported as a path on the master — `ports.1.vlan`. Inferred
680
762
  * 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).
763
+ * is the usual shape; set this when it does not.
682
764
  */
683
765
  path?: string;
684
766
  }
@@ -764,6 +846,156 @@ export interface GridConfig {
764
846
  timeZone?: string;
765
847
  theme?: Theme;
766
848
  density?: Density;
849
+
850
+ /**
851
+ * Which rules are drawn between cells.
852
+ *
853
+ * `'both'` by default. The two axes are separate decisions: horizontal rules
854
+ * help the eye track along a row, vertical ones stop adjacent values running
855
+ * together. `false` or `'none'` draws neither.
856
+ *
857
+ * Only the rules *between data* are affected — the header's underline, the
858
+ * pinned seams and the totals separator are structure, not grid lines.
859
+ */
860
+ gridLines?: boolean | 'both' | 'horizontal' | 'vertical' | 'none' | 'rows' | 'columns';
861
+
862
+ /**
863
+ * Round the grid's outer corners.
864
+ *
865
+ * Square by default. `true` adopts the theme's own radius; a number is
866
+ * pixels; a string is used as written, so a host can pass its own token or a
867
+ * relative unit.
868
+ */
869
+ cornerRadius?: boolean | number | string;
870
+
871
+ /**
872
+ * Show a bar above the column headings for filtering columns by tag.
873
+ *
874
+ * Off by default, and it draws nothing unless some column carries a `tags`
875
+ * entry. `multiple: true` lets more than one tag be chosen at once.
876
+ *
877
+ * Only tagged columns are ever hidden, so an untagged account or total column
878
+ * stays visible whatever is selected.
879
+ */
880
+ columnTagFilter?: boolean | { multiple?: boolean; label?: string };
881
+
882
+ /**
883
+ * Open a row on a form when it is double-clicked.
884
+ *
885
+ * `mode` is a right-hand `'drawer'` (the default) or a centred `'dialog'`.
886
+ *
887
+ * Without `load` the form shows the grid's own columns, edited with the same
888
+ * editors the cells use. With `load` it shows whatever that returns — the
889
+ * grid rarely displays everything a record has — and then `fields` is
890
+ * required, because nothing here knows the shape of a record it has not seen.
891
+ *
892
+ * The panel opens immediately and fills in when the record arrives; a failure
893
+ * offers a retry inside the panel. Save collects the changed fields, writes
894
+ * the ones that map to columns, and emits `form:saved` with the lot —
895
+ * persisting is yours.
896
+ *
897
+ * `trigger: false` leaves opening to `grid.form.open(key)`.
898
+ */
899
+ /**
900
+ * Draw each row with a template instead of dividing it into columns.
901
+ *
902
+ * A card list, a feed, a search-result list. The template is the same
903
+ * declarative string a cell template is, and compiles once at configuration
904
+ * time — there is deliberately no per-row callback, because one would be used
905
+ * to allocate DOM per row and the virtualisation would stop paying for
906
+ * itself. Bind with `{{data.field}}`.
907
+ *
908
+ * Everything underneath is unchanged: sorting, filtering, grouping,
909
+ * selection, permissions, redaction, saved views, undo and the remote source
910
+ * all apply, and a card emits the same `row:clicked` and `row:dblclicked`
911
+ * events a table row does.
912
+ */
913
+ /**
914
+ * Per-column options a data type reads.
915
+ *
916
+ * `ratio` and `percentRate` use `{ weight }` to name the column their average
917
+ * is weighted by. A unit type reads `{ significantFigures }` to render to a
918
+ * fixed precision rather than a fixed number of decimals.
919
+ */
920
+ typeOptions?: Record<string, {
921
+ weight?: string;
922
+ significantFigures?: number;
923
+ [option: string]: unknown;
924
+ }>;
925
+
926
+ rowTemplate?: string | {
927
+ template: string;
928
+ /** A class of your own on every card, alongside the grid's. */
929
+ className?: string;
930
+ /** The layer's role. `list` by default; `listbox` for a selectable set. */
931
+ role?: string;
932
+ /** Each card's role. `listitem` by default. */
933
+ itemRole?: string;
934
+ /** A fixed number of cards on a line. Does not reflow. */
935
+ cardsPerRow?: number;
936
+ /** A ceiling on card width; the number on a line follows the container. */
937
+ maxCardWidth?: number;
938
+ /** Space between tiles, in pixels. 8 by default. */
939
+ gap?: number;
940
+ };
941
+
942
+ /**
943
+ * Present rows as cards when the grid's container is too narrow to be a
944
+ * table honestly — a phone, or a narrow panel on a wide screen.
945
+ *
946
+ * Measured on the container, not the viewport, so a grid in a sidebar
947
+ * collapses and a grid filling a small tablet does not. Sorting, filtering
948
+ * and export continue to work; the tool panel is where they live when there
949
+ * are no column headings to click. Emits `presentation:changed`.
950
+ */
951
+ responsive?: {
952
+ /** Collapse at or below this container width. 640 by default. */
953
+ maxWidth?: number;
954
+ /** The card layout, as `rowTemplate` takes it. */
955
+ template: string | object;
956
+ /** How tall a collapsed card is. 64 by default — a table row is too short. */
957
+ rowHeight?: number;
958
+ };
959
+
960
+ rowForm?: boolean | {
961
+ mode?: 'drawer' | 'dialog';
962
+ load?: (p: { row: Row; data: unknown; key: string; grid: Grid }) => unknown | Promise<unknown>;
963
+ fields?: (string | {
964
+ field: string;
965
+ label?: string;
966
+ /** Which editor to build, by registry name or constructor. Defaults to the column's, then the type's. */
967
+ editor?: string | (new () => object);
968
+ type?: TypeName;
969
+ props?: object;
970
+ lookup?: LookupSpec;
971
+ })[];
972
+ title?: string | ((p: { row: Row; data: unknown }) => string);
973
+ width?: string;
974
+ trigger?: false;
975
+ /** How long to wait for `load`, in milliseconds. 2000 by default; `false` waits indefinitely. */
976
+ timeout?: number | false;
977
+ /**
978
+ * An element of your own to build the form in, instead of over the grid.
979
+ * An element, a CSS selector or a function returning either; a selector is
980
+ * resolved when the form opens, not when the grid is configured. A form in
981
+ * your own container fills it, is a region rather than a modal dialog, and
982
+ * does not trap Tab.
983
+ */
984
+ container?: HTMLElement | string | (() => HTMLElement | string | null);
985
+ };
986
+
987
+ /**
988
+ * Draw the sort, filter and menu controls in the column headings.
989
+ *
990
+ * `true` by default. `false` leaves each heading as its label alone, which is
991
+ * what a dense grid wants: three affordances take roughly fifty pixels, and
992
+ * on an eighty-pixel column that leaves the heading nothing and the label
993
+ * disappears entirely.
994
+ *
995
+ * Only the furniture goes. Sorting, filtering and the column menu are still
996
+ * reachable through the API, the keyboard and the tool panel.
997
+ */
998
+ showColumnFunctions?: boolean;
767
999
  rowHeight?: number | ((row: Row) => number);
768
1000
  headerHeight?: number;
769
1001
  overscan?: number;
@@ -813,23 +1045,23 @@ export interface GridConfig {
813
1045
  budgetMs?: number;
814
1046
  };
815
1047
  /**
816
- * Threaded comments on individual cells (§16). Requires a stable
1048
+ * Threaded comments on individual cells. Requires a stable
817
1049
  * `rowKey`: comments outlive the values they annotate, and index
818
1050
  * identity would reattach every thread on the next sort.
819
1051
  */
820
1052
  comments?: CommentConfig;
821
1053
  /**
822
- * Collaborative presence (§18). A display feature over a transport the
1054
+ * Collaborative presence. A display feature over a transport the
823
1055
  * grid does not own; without a provider it is inert.
824
1056
  */
825
1057
  presence?: PresenceConfig;
826
1058
  /**
827
1059
  * Host environment for a support bundle. Supplied by the DOM layer;
828
- * core cannot read `navigator` or `window` itself (§3.1).
1060
+ * core cannot read `navigator` or `window` itself.
829
1061
  */
830
1062
  environment?: () => Record<string, unknown>;
831
1063
  /**
832
- * Column header histograms and the filters clicking them creates (§9.6).
1064
+ * Column header histograms and the filters clicking them creates.
833
1065
  *
834
1066
  * Off by default: the band roughly doubles header height, which is a cost
835
1067
  * no grid should pay without asking. Per-column settings layer over these.
@@ -841,7 +1073,7 @@ export interface GridConfig {
841
1073
  workerThreshold?: number;
842
1074
  /**
843
1075
  * Compute column distributions off the main thread. Sorting, filtering and
844
- * grouping run on the main thread; see §5.13 for why.
1076
+ * grouping run on the main thread; see the reference for why.
845
1077
  */
846
1078
  useWorker?: boolean;
847
1079
  workerUrl?: string;
@@ -856,6 +1088,38 @@ export interface GridConfig {
856
1088
  * `false` means no grand total row.
857
1089
  */
858
1090
  grandTotalRow?: boolean | 'bottom';
1091
+
1092
+ /**
1093
+ * Rows pinned above the scrolling body.
1094
+ *
1095
+ * The objects are rendered through the ordinary column pipeline but are not
1096
+ * part of the data: not counted by `rows.count()`, not sorted, filtered,
1097
+ * grouped, selectable or exported. Use it for a totals line or a units row
1098
+ * that must stay against the header.
1099
+ */
1100
+ pinnedTopRows?: unknown[];
1101
+
1102
+ /** Rows pinned below the scrolling body. As `pinnedTopRows`, at the other edge. */
1103
+ pinnedBottomRows?: unknown[];
1104
+
1105
+ /**
1106
+ * Rows drawn as a single band across every column instead of being divided
1107
+ * into them — a section banner, a note, a "load more" affordance.
1108
+ *
1109
+ * `when` picks the rows; `render` fills them. A full-width row is still one
1110
+ * of your data rows: counted by `rows.count()`, sorted, filtered and
1111
+ * exported like any other. Only its presentation changes. For a row that
1112
+ * should *not* be part of the data, use `pinnedTopRows`.
1113
+ */
1114
+ fullWidth?: {
1115
+ when(row: Row): boolean;
1116
+ /**
1117
+ * Return a string for text, or a node for content. Return nothing and
1118
+ * write into `params.element` yourself. An HTML string is deliberately not
1119
+ * accepted — see `allowUnsafeTemplates` for that decision elsewhere.
1120
+ */
1121
+ render(params: FullWidthParams): string | Node | void;
1122
+ };
859
1123
  totalFilteredOnly?: boolean;
860
1124
  totalOnlyChangedColumns?: boolean;
861
1125
  showTotalInHeader?: boolean;
@@ -867,8 +1131,80 @@ export interface GridConfig {
867
1131
  * menu offers Paste, Clear and Fill down.
868
1132
  */
869
1133
  contextMenu?: boolean | ((p: CellMenuParams, defaults: MenuItem[]) => MenuItem[] | void);
870
- /** The header's 3-dot menu. `false` suppresses it. Default true. */
871
- columnMenu?: boolean;
1134
+ /**
1135
+ * The header's 3-dot menu, and the right-click menu on a column heading.
1136
+ * `false` suppresses both. A function supplies custom items, receiving the
1137
+ * grid's own so it can add to them rather than reproduce them. Default true.
1138
+ */
1139
+ columnMenu?: boolean | ((p: ColumnMenuParams, defaults: MenuItem[]) => MenuItem[] | void);
1140
+
1141
+ /**
1142
+ * The `?` keyboard shortcut overlay. `false` suppresses it, for a host
1143
+ * that wants `?` for itself. Default true.
1144
+ */
1145
+ shortcuts?: boolean;
1146
+
1147
+ /**
1148
+ * Let a user reorder rows by dragging a handle, or with
1149
+ * Alt+Shift+Up/Down.
1150
+ *
1151
+ * `true` puts the handle in the first visible column; `{ column }` names a
1152
+ * different one. The move reorders your data and emits `row:moved`;
1153
+ * persisting it is yours, and `rows.data()` afterwards is the new order.
1154
+ *
1155
+ * Refused, with a reason announced, while a sort, filter or grouping is
1156
+ * active — the position a row is dropped at has no single meaning in the
1157
+ * underlying order then.
1158
+ */
1159
+ rowReorder?: boolean | { column?: string };
1160
+
1161
+ /**
1162
+ * Let rows be dragged out of this grid, into it, or both.
1163
+ *
1164
+ * Off by default: rows leaving a grid is a data change a host has to want,
1165
+ * and a mis-drag that silently removed one has no gesture a user would think
1166
+ * to undo.
1167
+ *
1168
+ * `send` and `receive` are both on when the option is present, so one-way is
1169
+ * expressed by turning off the direction you do not want — a source grid is
1170
+ * `{ receive: false }` and a target is `{ send: false }`.
1171
+ *
1172
+ * `mode: 'copy'` leaves the row where it was. `group` restricts exchange to
1173
+ * grids sharing the same name, so two unrelated grids on a page do not accept
1174
+ * each other's rows.
1175
+ *
1176
+ * The source needs `rowReorder` as well, since that is what draws the handle
1177
+ * a drag starts from.
1178
+ */
1179
+ rowTransfer?: boolean | {
1180
+ send?: boolean;
1181
+ receive?: boolean;
1182
+ mode?: 'move' | 'copy';
1183
+ group?: string;
1184
+ };
1185
+
1186
+ /**
1187
+ * Other grids to stay column-aligned with.
1188
+ *
1189
+ * Column widths, order, visibility and pinning are shared, and horizontal
1190
+ * scrolling moves them together. Sort, filters, selection, grouping and the
1191
+ * rows themselves stay independent — sharing those would make one grid with
1192
+ * extra steps rather than two aligned ones.
1193
+ *
1194
+ * Declared on the grid created last, since it is the only one that can name
1195
+ * the others; the link is peer-based once made.
1196
+ */
1197
+ alignedGrids?: unknown[];
1198
+
1199
+ /**
1200
+ * Keep the enclosing group headings pinned above the viewport while
1201
+ * scrolling inside a group.
1202
+ *
1203
+ * On by default, stacking at most two. `false` turns it off; a number, or
1204
+ * `{ depth }`, sets how many may stack — each costs a row of viewport, so a
1205
+ * deep grouping would otherwise spend the screen describing itself.
1206
+ */
1207
+ stickyGroupHeaders?: boolean | number | { depth?: number };
872
1208
  /**
873
1209
  * Flash a cell when its value changes. `true` takes the defaults; an object
874
1210
  * names a colour, a duration in milliseconds, or both.
@@ -916,12 +1252,12 @@ export interface GridConfig {
916
1252
  };
917
1253
  quickFilterText?: string;
918
1254
  /**
919
- * Per-column read/write/hidden policy (§8.1). A usability control, not a
1255
+ * Per-column read/write/hidden policy. A usability control, not a
920
1256
  * security boundary — hidden data is still resident in the store. Enforce the
921
1257
  * same policy server-side with `permittedColumns` / `permittedExport`.
922
1258
  */
923
1259
  permissions?: PermissionPolicy;
924
- /** Prior state for diff and audit mode (§12). */
1260
+ /** Prior state for diff and audit mode. */
925
1261
  diff?: {
926
1262
  snapshot?: unknown[] | Map<string, unknown>;
927
1263
  strictNull?: boolean;
@@ -943,7 +1279,7 @@ export interface GridConfig {
943
1279
  */
944
1280
  removedRows?: false | 'pinned' | 'data';
945
1281
  };
946
- /** Saved views (§15): a storage adapter and any pre-loaded views. */
1282
+ /** Saved views: a storage adapter and any pre-loaded views. */
947
1283
  views?: { storage?: { read(): unknown[]; write(views: unknown[]): void }; saved?: unknown[] };
948
1284
  /** The undo toolbar. `element` mounts it into the host's own chrome. */
949
1285
  historyBar?: boolean | { element?: HTMLElement; timeline?: boolean };
@@ -1215,6 +1551,16 @@ export interface RowsApi {
1215
1551
  text(key: string, colId: string): string;
1216
1552
  values(key: string): Record<string, unknown>;
1217
1553
  refresh(opts?: { rows?: string[]; columns?: string[]; force?: boolean }): void;
1554
+ /**
1555
+ * Move a row to another position in the data. Refuses, with a
1556
+ * reason, while a sort, filter or grouping is active.
1557
+ */
1558
+ move(key: string, to: number): { moved: boolean; from: number; to: number; reason?: string };
1559
+ /**
1560
+ * The group headings enclosing a display row, outermost first. Empty when the
1561
+ * grid is not grouped.
1562
+ */
1563
+ groupHeadings(index: number): Row[];
1218
1564
  expand(key: string, deep?: boolean): void;
1219
1565
  collapse(key: string): void;
1220
1566
  expandAll(): void;
@@ -1227,6 +1573,16 @@ export interface ColumnsApi {
1227
1573
  visible(): ResolvedColumn[];
1228
1574
  state(): ColumnState[];
1229
1575
  apply(state: ColumnState[]): void;
1576
+ /** Every distinct column tag, in the order first declared. */
1577
+ tags(): string[];
1578
+ /**
1579
+ * Show only the columns carrying one of these tags. **Columns with no tags
1580
+ * are never hidden.** Pass nothing to show every tagged column again.
1581
+ * Returns the ids that were hidden.
1582
+ */
1583
+ showTagged(tags?: string | string[] | null): string[];
1584
+ /** The tags currently being shown, empty when all are. */
1585
+ activeTags(): string[];
1230
1586
  show(ids: string | string[]): void;
1231
1587
  hide(ids: string | string[]): void;
1232
1588
  move(id: string, to: number): void;
@@ -1239,6 +1595,14 @@ export interface ColumnsApi {
1239
1595
  totals(ids: string | string[]): void;
1240
1596
  }
1241
1597
 
1598
+ export interface RowFormApi {
1599
+ /** Open the form for a row. False when the form is not configured. */
1600
+ open(key: string): boolean;
1601
+ close(): void;
1602
+ save(): boolean;
1603
+ isOpen(): boolean;
1604
+ }
1605
+
1242
1606
  export interface DetailApi {
1243
1607
  enabled(): boolean;
1244
1608
  isMaster(target: string | Row): boolean;
@@ -1302,9 +1666,18 @@ export interface EditApi {
1302
1666
  }
1303
1667
 
1304
1668
  export interface ScrollApi {
1305
- toRow(index: number, align?: 'start' | 'center' | 'end' | 'auto'): void;
1669
+ /**
1670
+ * A row key, or a display index. A key survives a sort and is usually what a
1671
+ * caller holds; resolving one scans the display order, so prefer an index
1672
+ * when scrolling a very large grid repeatedly.
1673
+ */
1674
+ toRow(row: string | number, align?: 'start' | 'center' | 'end' | 'auto'): void;
1306
1675
  toColumn(id: string): void;
1676
+ /** Scroll a cell into view, both axes in one call. */
1677
+ toCell(row: string | number, colId: string, align?: 'start' | 'center' | 'end' | 'auto'): void;
1307
1678
  position(): { top: number; left: number };
1679
+ /** `left` is the logical offset, zero at the content's start in either direction. */
1680
+ to(at: { top?: number; left?: number }): void;
1308
1681
  }
1309
1682
 
1310
1683
  export interface ExportApi {
@@ -1916,6 +2289,27 @@ export interface AiApi {
1916
2289
  apply(plan: Record<string, unknown>): Record<string, unknown>;
1917
2290
  }
1918
2291
 
2292
+ /**
2293
+ * The resolved message set for a grid: every user-visible string, in the
2294
+ * grid's locale.
2295
+ */
2296
+ export interface MessagesApi {
2297
+ /**
2298
+ * Format a message.
2299
+ * @param key a key from `keys`
2300
+ * @param params interpolation parameters; `count` selects the plural form
2301
+ */
2302
+ t(key: string, params?: Record<string, unknown>): string;
2303
+ /** Join parts the way this locale joins lists. */
2304
+ list(items: string[], type?: 'conjunction' | 'disjunction'): string;
2305
+ /** Format a number for this locale. */
2306
+ number(value: number, opts?: Intl.NumberFormatOptions): string;
2307
+ /** The resolved BCP 47 tag. */
2308
+ readonly locale: string;
2309
+ /** Every key the catalogue defines. */
2310
+ readonly keys: ReadonlyArray<string>;
2311
+ }
2312
+
1919
2313
  export interface LicenceApi {
1920
2314
  set(key: string): LicenceInfo;
1921
2315
  info(): LicenceInfo;
@@ -1950,12 +2344,32 @@ export interface CellMenuParams {
1950
2344
  grid: Grid;
1951
2345
  }
1952
2346
 
1953
- /** What a host rail action's `run` is handed. */
2347
+ /** What `fullWidth.render` is handed. */
2348
+ export interface FullWidthParams {
2349
+ row: Row;
2350
+ /** Your original row object. */
2351
+ data: unknown;
2352
+ /** Display index of the row. */
2353
+ index: number;
2354
+ grid: Grid;
2355
+ /** The element to fill. Write into it directly, or return content instead. */
2356
+ element: HTMLElement;
2357
+ }
2358
+
2359
+ /** What a column menu's item builder and its actions are handed. */
2360
+ export interface ColumnMenuParams {
2361
+ colId: string;
2362
+ /** The resolved column, including any properties you defined on it. */
2363
+ column: ResolvedColumn;
2364
+ grid: Grid;
2365
+ }
2366
+
1954
2367
  /** The rail's built-in action names, plus `'-'` for a divider. */
1955
2368
  export type RailActionName =
1956
2369
  | 'undo' | 'redo' | 'pause' | 'restore' | 'maximise'
1957
2370
  | 'export' | 'excel' | 'clipboard' | 'print';
1958
2371
 
2372
+ /** What a host rail action's `run` is handed. */
1959
2373
  export interface RailActionParams {
1960
2374
  grid: Grid;
1961
2375
  keys: string[];
@@ -2001,6 +2415,7 @@ export interface Grid {
2001
2415
  readonly diff: DiffApi;
2002
2416
  readonly permissions: PermissionsApi;
2003
2417
  readonly ai: AiApi;
2418
+ readonly messages: MessagesApi;
2004
2419
  readonly licence: LicenceApi;
2005
2420
  readonly pagination: PaginationApi;
2006
2421
  readonly highlight: HighlightApi;
@@ -2041,6 +2456,23 @@ export interface Grid {
2041
2456
  off(event: EventName, handler: EventHandler): void;
2042
2457
  emit(event: string, payload?: Record<string, unknown>): void;
2043
2458
 
2459
+ /**
2460
+ * Pin rows above or below the scrolling body.
2461
+ *
2462
+ * The rows render through the ordinary column pipeline but are not part of
2463
+ * the data: not counted, sorted, filtered, grouped, selectable or exported.
2464
+ *
2465
+ * Pass a new array rather than mutating the one you passed before — array
2466
+ * identity is how the grid knows the pinned rows have changed.
2467
+ */
2468
+ setPinnedRows(rows: unknown[], opts?: { edge?: 'top' | 'bottom' }): void;
2469
+
2470
+ /** The objects currently pinned at one edge, as a copy. */
2471
+ getPinnedRows(opts?: { edge?: 'top' | 'bottom' }): unknown[];
2472
+
2473
+ /** The row form. Declines when `rowForm` is not configured. */
2474
+ readonly form: RowFormApi;
2475
+
2044
2476
  getVersion(): string;
2045
2477
  destroy(): void;
2046
2478
  }
@@ -2064,3 +2496,60 @@ export const LatticeGrid: {
2064
2496
  };
2065
2497
 
2066
2498
  export default LatticeGrid;
2499
+
2500
+ /** The default British English catalogue. */
2501
+ export const EN_GB: Record<string, string | Record<string, string>>;
2502
+ /** Every key the default catalogue defines. */
2503
+ export const MESSAGE_KEYS: ReadonlyArray<string>;
2504
+ /** The locale the default catalogue is written in: 'en-GB'. */
2505
+ export const DEFAULT_LOCALE: string;
2506
+ /** Bundled catalogues, keyed by lower-cased BCP 47 tag. */
2507
+ export const LOCALES: Record<string, Record<string, string | Record<string, string>>>;
2508
+ export const EN_US: Record<string, string | Record<string, string>>;
2509
+ export const FR_FR: Record<string, string | Record<string, string>>;
2510
+ export const FR_CA: Record<string, string | Record<string, string>>;
2511
+ export const IT_IT: Record<string, string | Record<string, string>>;
2512
+ export const ES_ES: Record<string, string | Record<string, string>>;
2513
+ export const PT_BR: Record<string, string | Record<string, string>>;
2514
+ export const DE_DE: Record<string, string | Record<string, string>>;
2515
+ export const NL_NL: Record<string, string | Record<string, string>>;
2516
+ export const SV_SE: Record<string, string | Record<string, string>>;
2517
+ export const DA_DK: Record<string, string | Record<string, string>>;
2518
+ export const NB_NO: Record<string, string | Record<string, string>>;
2519
+ export const FI_FI: Record<string, string | Record<string, string>>;
2520
+ export const PL_PL: Record<string, string | Record<string, string>>;
2521
+ export const CS_CZ: Record<string, string | Record<string, string>>;
2522
+ export const HU_HU: Record<string, string | Record<string, string>>;
2523
+ export const RO_RO: Record<string, string | Record<string, string>>;
2524
+ export const UK_UA: Record<string, string | Record<string, string>>;
2525
+ export const EL_GR: Record<string, string | Record<string, string>>;
2526
+ export const JA_JP: Record<string, string | Record<string, string>>;
2527
+ export const AR: Record<string, string | Record<string, string>>;
2528
+ /**
2529
+ * Alias for {@link AR}. The Arabic catalogue is pan-Arabic rather than
2530
+ * Saudi-specific; the alias exists because the region-qualified name is the
2531
+ * common first guess, every other catalogue carrying one.
2532
+ */
2533
+ export const AR_SA: Record<string, string | Record<string, string>>;
2534
+
2535
+ /** A resolved message set. */
2536
+ export class Messages implements MessagesApi {
2537
+ constructor(opts?: { locale?: string; messages?: Record<string, unknown>; declared?: string });
2538
+ configure(opts?: { locale?: string; messages?: Record<string, unknown>; declared?: string }): void;
2539
+ t(key: string, params?: Record<string, unknown>): string;
2540
+ list(items: string[], type?: 'conjunction' | 'disjunction'): string;
2541
+ number(value: number, opts?: Intl.NumberFormatOptions): string;
2542
+ readonly locale: string;
2543
+ readonly keys: ReadonlyArray<string>;
2544
+ }
2545
+
2546
+ /** Build a message set, passing an existing instance straight through. */
2547
+ export function createMessages(opts?: object | Messages): Messages;
2548
+ /** Report which keys a catalogue is missing and which it invents. */
2549
+ export function auditCatalogue(catalogue: Record<string, unknown>): { missing: string[]; unknown: string[] };
2550
+ /** Join parts the way a locale joins lists. */
2551
+ export function formatList(items: string[], locale?: string, type?: 'conjunction' | 'disjunction'): string;
2552
+ /** Resolve the locale: what was configured, then the document's `lang`, then the default. */
2553
+ export function resolveLocale(configured: string | undefined, declared?: string, fallback?: string): string;
2554
+ /** Find the catalogue for a tag, falling back to the base language. */
2555
+ export function resolveCatalogue(tag?: string): Record<string, unknown> | null;