@toclocoinc/lattice-grid 1.49.0 → 1.51.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.
Files changed (74) hide show
  1. package/README.md +2 -1
  2. package/docs/API.html +363 -8
  3. package/docs/api-detail.html +235 -2
  4. package/lattice-grid.d.ts +270 -6
  5. package/lattice-grid.esm.min.js +549 -75
  6. package/lattice-grid.min.cjs +549 -75
  7. package/lattice-grid.min.js +549 -75
  8. package/modules/ai.esm.min.js +6 -4
  9. package/modules/ai.min.cjs +6 -4
  10. package/modules/ai.min.js +6 -4
  11. package/modules/angular.esm.min.js +2 -2
  12. package/modules/angular.min.cjs +2 -2
  13. package/modules/angular.min.js +2 -2
  14. package/modules/chart-alluvial.esm.min.js +1 -1
  15. package/modules/chart-arc.esm.min.js +1 -1
  16. package/modules/chart-bubblemap.esm.min.js +1 -1
  17. package/modules/chart-bump.esm.min.js +1 -1
  18. package/modules/chart-calendar.esm.min.js +1 -1
  19. package/modules/chart-decomposition.esm.min.js +1 -1
  20. package/modules/chart-diverging.esm.min.js +1 -1
  21. package/modules/chart-dumbbell.esm.min.js +1 -1
  22. package/modules/chart-fan.esm.min.js +1 -1
  23. package/modules/chart-hexbin.esm.min.js +1 -1
  24. package/modules/chart-hexmap.esm.min.js +1 -1
  25. package/modules/chart-icicle.esm.min.js +1 -1
  26. package/modules/chart-parallel.esm.min.js +1 -1
  27. package/modules/chart-ridgeline.esm.min.js +1 -1
  28. package/modules/chart-roc.esm.min.js +1 -1
  29. package/modules/chart-slope.esm.min.js +1 -1
  30. package/modules/chart-splom.esm.min.js +1 -1
  31. package/modules/chart-waffle.esm.min.js +1 -1
  32. package/modules/charts.esm.min.js +4 -4
  33. package/modules/charts.min.cjs +4 -4
  34. package/modules/charts.min.js +4 -4
  35. package/modules/data-router.esm.min.js +7 -5
  36. package/modules/data-router.min.cjs +7 -5
  37. package/modules/data-router.min.js +7 -5
  38. package/modules/devtools.esm.min.js +2 -2
  39. package/modules/devtools.min.cjs +2 -2
  40. package/modules/devtools.min.js +2 -2
  41. package/modules/dhtmlx-compat.esm.min.js +4 -4
  42. package/modules/dhtmlx-compat.min.cjs +4 -4
  43. package/modules/dhtmlx-compat.min.js +4 -4
  44. package/modules/gantt.esm.min.js +78 -4
  45. package/modules/gantt.min.cjs +77 -4
  46. package/modules/gantt.min.js +77 -4
  47. package/modules/htmx.esm.min.js +549 -75
  48. package/modules/htmx.min.cjs +549 -75
  49. package/modules/htmx.min.js +549 -75
  50. package/modules/kanban.esm.min.js +4 -4
  51. package/modules/kanban.min.cjs +4 -4
  52. package/modules/kanban.min.js +4 -4
  53. package/modules/kpi.esm.min.js +30 -7
  54. package/modules/kpi.min.cjs +30 -7
  55. package/modules/kpi.min.js +30 -7
  56. package/modules/mock-socket.esm.min.js +2 -2
  57. package/modules/mock-socket.min.cjs +2 -2
  58. package/modules/mock-socket.min.js +2 -2
  59. package/modules/react.esm.min.js +2 -2
  60. package/modules/react.min.cjs +2 -2
  61. package/modules/react.min.js +2 -2
  62. package/modules/svelte.esm.min.js +2 -2
  63. package/modules/svelte.min.cjs +2 -2
  64. package/modules/svelte.min.js +2 -2
  65. package/modules/tabs.esm.min.js +878 -0
  66. package/modules/tabs.min.cjs +881 -0
  67. package/modules/tabs.min.js +881 -0
  68. package/modules/vue.esm.min.js +2 -2
  69. package/modules/vue.min.cjs +2 -2
  70. package/modules/vue.min.js +2 -2
  71. package/modules/webcomponent.esm.min.js +549 -75
  72. package/modules/webcomponent.min.cjs +549 -75
  73. package/modules/webcomponent.min.js +549 -75
  74. package/package.json +1 -1
package/lattice-grid.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Lattice Grid 1.49.0, type declarations
2
+ * Lattice Grid 1.51.0, type declarations
3
3
  * Copyright (c) 2026 TOCLOCO Inc. All rights reserved.
4
4
  * https://latticegrid.dev
5
5
  */
@@ -729,6 +729,12 @@ export interface Column {
729
729
  shadow?: ShadowKind | {
730
730
  of?: string;
731
731
  kind: ShadowKind;
732
+ /**
733
+ * For `kind: 'history'`, how many past readings to keep (20 by default). With
734
+ * a time `window` (BACKLOG-0001043) this is instead how many buckets the span
735
+ * divides into — `window: {kind: 'time', span: 60_000}, depth: 20` is sixty
736
+ * one-second buckets. Ignored by every other kind.
737
+ */
732
738
  depth?: number;
733
739
  /**
734
740
  * For a positional kind, what to rank against. `'all'` (the default) uses
@@ -768,6 +774,16 @@ export interface Column {
768
774
  * (`time`), or everything so far (`session`). The first rows of a series
769
775
  * carry a partial window, stamped by a `windowCoverage` companion rather than
770
776
  * dressed as full.
777
+ *
778
+ * For `kind: 'history'` (BACKLOG-0001043), only `{kind: 'time', span}` (or
779
+ * `minutes`) applies, and it changes what `history` means rather than what it
780
+ * aggregates: the `depth` buckets that span divides into are read once each,
781
+ * carrying the row's last known value forward into any bucket in which it did
782
+ * not change, so a static row still draws a flat, advancing line instead of
783
+ * freezing — the plain count-based history (no `window`) is a count of
784
+ * *changes* and stays exactly as it was. `count` and `session` are refused
785
+ * here: a plain count is already what `depth` means, and a session has no
786
+ * fixed span to divide into buckets.
771
787
  */
772
788
  window?: {
773
789
  kind: 'count' | 'time' | 'session';
@@ -847,6 +863,24 @@ export interface Column {
847
863
  layout?: ColumnLayoutSpec | number;
848
864
  /** The header cell: its text, tooltip, menu and any header chart. */
849
865
  header?: ColumnHeaderSpec | string;
866
+ /**
867
+ * The cell right-click menu for this column alone (BACKLOG-0001068), in the
868
+ * same shapes the grid-level `contextMenu` takes plus a bare array for the
869
+ * common "just these items here" case.
870
+ *
871
+ * Declared where the column is declared rather than as another branch inside
872
+ * one grid-level callback: the menu logic for a column belongs beside the
873
+ * column it belongs to. It does not replace the grid-level menu — the three
874
+ * levels compose as a chain, built-in defaults then grid-level then this one,
875
+ * each handed the previous result as its `defaults`, so a column adding one
876
+ * item does not have to restate Paste, Clear and Fill down.
877
+ *
878
+ * `false` suppresses the menu on this column and leaves every other column
879
+ * alone: what a sensitive or read-only column wants. The more specific level
880
+ * wins, so a column may also declare a menu on a grid whose `contextMenu` is
881
+ * `false`.
882
+ */
883
+ contextMenu?: boolean | MenuItem[] | ((p: CellMenuParams, defaults: MenuItem[]) => MenuItem[] | void);
850
884
  /**
851
885
  * When this column's header controls — its sort arrow, filter funnel and menu
852
886
  * button — are shown, overriding the grid-level `headerControls` default for
@@ -923,6 +957,12 @@ export interface ResolvedColumn {
923
957
  grandTotal: TotalName | TotalFn | null;
924
958
  layout: ColumnLayoutSpec;
925
959
  header: ColumnHeaderSpec;
960
+ /**
961
+ * This column's own cell-menu declaration (BACKLOG-0001068), or null when it
962
+ * makes none and the grid-level menu stands alone. Carried onto the resolved
963
+ * column so a column preset or `columnDefaults` can supply one.
964
+ */
965
+ contextMenu: boolean | MenuItem[] | ((p: CellMenuParams, defaults: MenuItem[]) => MenuItem[] | void) | null;
926
966
  export: ColumnExportSpec;
927
967
  lookup: LookupSpec | null;
928
968
  allowGroup: boolean;
@@ -1204,9 +1244,57 @@ export interface DerivedSourceConfig {
1204
1244
  * key when nothing is grouped. `config.rowKey` defaults to it, so it need not
1205
1245
  * be set; an explicit `rowKey` still wins.
1206
1246
  */
1207
- /** The grid to read. */
1208
- from: Grid;
1209
- /** Which of its rows to read. `filtered` by default. */
1247
+ /**
1248
+ * The grid to read, or several to combine into one row set before the rest
1249
+ * of the pipeline runs (BACKLOG-0001045). A bare `Grid` is shorthand for a
1250
+ * `UnionSourceOptions` with no `label`/`follow`/`map` override, so an
1251
+ * existing `from: <grid>` keeps meaning exactly what it always has.
1252
+ *
1253
+ * Given an array, every source is read (each narrowed by its own `follow`,
1254
+ * defaulting to `'filtered'` as a lone `from` does today), concatenated in
1255
+ * **declaration order** — deterministic, not interleaved — and only then
1256
+ * does `unnest`/`join`/`where`/`bucket`/`groupBy`/`select`/`sort`/`limit`/
1257
+ * `limitPer`/`cumulative` run, over the combined set, so "the worst
1258
+ * performers across both" is one derivation rather than a hand-merge.
1259
+ *
1260
+ * The output carries the **union of the sources' fields**: a field present
1261
+ * on only one source is `undefined` on rows from the others. Sources are
1262
+ * **not** type-reconciled — if two disagree on what a field means or holds,
1263
+ * that is not resolved for you; give each source a `map` to project it into
1264
+ * a common shape first. Every row also carries `__source` (the entry's
1265
+ * `label`, or its declaration index when unlabelled), which is required —
1266
+ * not optional — because without it a combined list cannot be read, filtered
1267
+ * or grouped by where it came from; it is an ordinary field to `where`,
1268
+ * `groupBy` and `select`. And because the derived key (`__key`) would
1269
+ * otherwise collide across sources sharing the same identifiers, it is
1270
+ * namespaced by the same source tag when nothing is grouped (a grouped
1271
+ * union's `__key` is the group value, exactly as today, and rows from
1272
+ * different sources correctly land in the *same* group when their group
1273
+ * values agree — that merging is the point of grouping a union, not a
1274
+ * collision to guard against).
1275
+ *
1276
+ * This is **not** a join: there is no dedup or merge-on-key, and it draws no
1277
+ * UNION/UNION ALL distinction — overlapping rows from two sources simply
1278
+ * both appear. Reach for `join` when two sides share a key and you want them
1279
+ * matched rather than stacked.
1280
+ *
1281
+ * An empty source contributes nothing and the rest still combine; a source
1282
+ * that fails to read is named in a `warnOnce` and skipped for that pass
1283
+ * rather than silently dropped, because a silently missing source would
1284
+ * make "worst across both" quietly wrong. A source list that includes the
1285
+ * grid being derived, directly or through a chain, is refused when the
1286
+ * source is built (naming the offender) rather than recursed into.
1287
+ *
1288
+ * `crossFilter` has no single target once there is more than one parent, so
1289
+ * it is not supported alongside a union `from` (ignored, with a `warnOnce`,
1290
+ * rather than guessing which parent to push onto).
1291
+ */
1292
+ from: Grid | UnionSourceOptions[];
1293
+ /**
1294
+ * Which of its rows to read. `filtered` by default. Ignored — with a
1295
+ * `warnOnce` — when `from` is a union array: each entry there carries its
1296
+ * own `follow` instead (BACKLOG-0001045).
1297
+ */
1210
1298
  follow?: 'filtered' | 'all' | 'selected' | 'grouped';
1211
1299
 
1212
1300
  /** An array property to expand, one row per element, before anything else. */
@@ -1249,6 +1337,38 @@ export interface DerivedSourceConfig {
1249
1337
  crossFilter?: boolean | string | { col?: string };
1250
1338
  }
1251
1339
 
1340
+ /**
1341
+ * One member of a union `from` (BACKLOG-0001045): a grid to combine with the
1342
+ * others, plus how to read it and reshape it before it joins the rest. A bare
1343
+ * `Grid` in the `from` array is shorthand for `{ grid }` with every other
1344
+ * field defaulted.
1345
+ */
1346
+ export interface UnionSourceOptions {
1347
+ /** The grid this source reads. */
1348
+ grid: Grid;
1349
+ /**
1350
+ * Identifies this source: it is what `__source` carries on every row this
1351
+ * source contributes, and what namespaces that row's `__key` so two sources
1352
+ * sharing the same identifiers do not collide. Defaults to the source's
1353
+ * position in the `from` array (`'0'`, `'1'`, …), as a string.
1354
+ */
1355
+ label?: string;
1356
+ /**
1357
+ * Which of this source's rows to read. `filtered` by default, exactly as a
1358
+ * lone `from` follows its grid today — set independently per source, so
1359
+ * filtering one narrows only its own contribution.
1360
+ */
1361
+ follow?: 'filtered' | 'all' | 'selected' | 'grouped';
1362
+ /**
1363
+ * Reshape this source's rows into the common shape before they join the
1364
+ * rest — typically a rename or a projection, for a field this source calls
1365
+ * something else. Not a type coercion: if a field means something different
1366
+ * on two sources, `map` is where you make them agree, because the union
1367
+ * itself does not guess.
1368
+ */
1369
+ map?: (row: unknown) => unknown;
1370
+ }
1371
+
1252
1372
  export interface DerivedJoin {
1253
1373
  /** The grid holding the other side. */
1254
1374
  with: Grid;
@@ -5936,6 +6056,18 @@ export function duckdbAdapter(options: {
5936
6056
  from: string;
5937
6057
  /** Columns to select. Everything by default. */
5938
6058
  fields?: string[];
6059
+ /**
6060
+ * Whether to count the matching set at all. `true` by default: the total is a
6061
+ * separate `count(*)` statement carrying the same `WHERE`, dispatched in the
6062
+ * same tick as the page query rather than serialised behind it
6063
+ * (BACKLOG-0001065). `false` issues no count statement, declares
6064
+ * `capabilities.total: false`, and leaves the result's `total` **absent** — so
6065
+ * the grid scrolls open-ended instead of being told the page length is the
6066
+ * whole set. Turn it off for a grid that never shows a count: an unfiltered
6067
+ * count is answered from Parquet metadata and a filtered one still has to
6068
+ * evaluate the predicate, so it is cheap rather than free.
6069
+ */
6070
+ count?: boolean;
5939
6071
  /**
5940
6072
  * The key column an update and a delete target in their `WHERE`, and that an
5941
6073
  * add-row is rekeyed by. Write-back is refused unless this names a real column,
@@ -5958,7 +6090,15 @@ export function duckdbAdapter(options: {
5958
6090
  * key to rekey the temp row.
5959
6091
  */
5960
6092
  returning?: 'row' | 'none';
5961
- }): PushdownAdapter & { sqlFor(query: RemoteRequest): { sql: string; params: unknown[] } };
6093
+ }): PushdownAdapter & {
6094
+ sqlFor(query: RemoteRequest): { sql: string; params: unknown[] };
6095
+ /**
6096
+ * The separate `count(*)` statement that reports the matching set's size, with
6097
+ * the same `WHERE` as {@link sqlFor} and no `ORDER BY` or `LIMIT`
6098
+ * (BACKLOG-0001065). `null` when the adapter was built with `count: false`.
6099
+ */
6100
+ countSqlFor(query: RemoteRequest): { sql: string; params: unknown[] } | null;
6101
+ };
5962
6102
 
5963
6103
  /**
5964
6104
  * An adapter for a DemandFlow entity, speaking `POST /v1/query`.
@@ -6038,6 +6178,15 @@ export function graphqlAdapter(options: {
6038
6178
  pagination?: 'offset' | 'cursor';
6039
6179
  /** The page size for the whole-result and forward-cursor walks. */
6040
6180
  pageSize?: number;
6181
+ /**
6182
+ * Whether the default query asks for `totalCount`. `true` by default.
6183
+ * `false` drops it from the selection set and declares
6184
+ * `capabilities.total: false`, so a grid that never shows a count does not
6185
+ * make the server compute one (BACKLOG-0001065). Unlike the DuckDB adapter the
6186
+ * count is not split into a second operation — that would cost an extra HTTP
6187
+ * round trip rather than saving one — so suppression is the only lever here.
6188
+ */
6189
+ count?: boolean;
6041
6190
  /** Rename the pagination variables the adapter drives per page. */
6042
6191
  vars?: Partial<Record<'offset' | 'limit' | 'first' | 'after', string>>;
6043
6192
  capabilities?: PushdownCapabilities; operators?: string[];
@@ -8340,7 +8489,17 @@ declare module 'lattice-grid/modules/kpi' {
8340
8489
  field?: string;
8341
8490
  value: unknown;
8342
8491
  formatted: string;
8343
- status: 'good' | 'warn' | 'critical' | null;
8492
+ /**
8493
+ * The tile's semantic band, or `unknown` when the panel holds no rows at
8494
+ * all. `unknown` is decided from data presence before any threshold is
8495
+ * consulted: an aggregation over nothing returns the identity of its
8496
+ * operation (`sum` and `count` return 0), and 0 is a number a threshold
8497
+ * grades, so without it an empty panel would report as a healthy one. A
8498
+ * tile whose `filter` matches none of the rows the panel *does* hold has
8499
+ * measured a real zero and is banded normally. `null` means the tile has no
8500
+ * thresholds or bands configured.
8501
+ */
8502
+ status: 'good' | 'warn' | 'critical' | 'unknown' | null;
8344
8503
  target?: number;
8345
8504
  baseline?: number;
8346
8505
  delta: number | null;
@@ -8808,3 +8967,108 @@ declare module 'lattice-grid/modules/ai' {
8808
8967
 
8809
8968
  export default createAI;
8810
8969
  }
8970
+
8971
+ declare module 'lattice-grid/modules/tabs' {
8972
+ /**
8973
+ * One tab: an id, a display label, a grid config, and — for a derived tab —
8974
+ * the parent tab id plus the narrowing forwarded onto the derived source
8975
+ * built for it (`source: { mode: 'derived', from: <parent's grid>, ... }`).
8976
+ * The derivation keys are the ones `packages/core/src/source/derive.js`
8977
+ * already understands; this module invents none of its own.
8978
+ */
8979
+ interface TabDescriptor {
8980
+ /** A stable, unique id. Required. */
8981
+ id: string;
8982
+ /** The tab button's text. Defaults to `id`. */
8983
+ label?: string;
8984
+ /** The grid config passed to `createGrid` for this tab (merged with the derived `source`, when `from` is set). */
8985
+ config?: object;
8986
+ /** The parent tab id to derive from. When set, `config.source` is built for you and any of your own is replaced (with a warning). */
8987
+ from?: string;
8988
+ /** Row predicate forwarded to the derived source. */
8989
+ where?: (row: unknown) => boolean;
8990
+ /** Group-by forwarded to the derived source. */
8991
+ group?: unknown;
8992
+ groupBy?: unknown;
8993
+ /** Time-bucketing forwarded to the derived source. */
8994
+ bucket?: unknown;
8995
+ /** Join spec forwarded to the derived source. */
8996
+ join?: unknown;
8997
+ /** Array-field unnesting forwarded to the derived source. */
8998
+ unnest?: unknown;
8999
+ /** `'live' | 'idle' | 'manual' | number` forwarded to the derived source. */
9000
+ refresh?: 'live' | 'idle' | 'manual' | number;
9001
+ /** Cross-filter wiring forwarded to the derived source. */
9002
+ crossFilter?: unknown;
9003
+ /** Which slice of the parent's rows to derive from: `'filtered' | 'all' | 'selected' | 'grouped'`. */
9004
+ follow?: 'filtered' | 'all' | 'selected' | 'grouped';
9005
+ /** Row limit forwarded to the derived source. */
9006
+ limit?: number;
9007
+ /** Sort forwarded to the derived source. */
9008
+ sort?: unknown;
9009
+ /** Statistical-profile derivation, forwarded to the derived source. */
9010
+ profile?: unknown;
9011
+ /** This tab's panel's own `aria-label`, when the label alone is not enough context. */
9012
+ ariaLabel?: string;
9013
+ }
9014
+
9015
+ /** The payload every tab-change event carries. */
9016
+ interface TabChangeEvent {
9017
+ id: string;
9018
+ previousId: string | null;
9019
+ origin?: 'api' | 'user' | 'init';
9020
+ reason?: string | null;
9021
+ /** Cancel the switch (only meaningful on `beforeTabChange`). */
9022
+ preventDefault?: (reason?: string) => void;
9023
+ defaultPrevented?: boolean;
9024
+ }
9025
+
9026
+ /** Tabbed-grid configuration. */
9027
+ interface TabsConfig {
9028
+ /** The grid factory to mount each tab with, e.g. `import { createGrid } from 'lattice-grid'`. Required. */
9029
+ createGrid: (el: HTMLElement, config: object) => unknown;
9030
+ /** The tabs, in display order. Required, at least one. */
9031
+ tabs: TabDescriptor[];
9032
+ /** The initially active tab id. Defaults to the first tab. */
9033
+ active?: string;
9034
+ /** The tablist landmark's accessible name. */
9035
+ ariaLabel?: string;
9036
+ /** An explicit message-catalogue override; otherwise a mounted tab's own `grid.messages` is used. */
9037
+ messages?: { t(key: string, params?: Record<string, unknown>): string };
9038
+ onTabChange?: (event: TabChangeEvent) => void;
9039
+ onBeforeTabChange?: (event: TabChangeEvent) => boolean | void | Promise<boolean>;
9040
+ onTabChangeCancelled?: (event: TabChangeEvent) => void;
9041
+ }
9042
+
9043
+ /**
9044
+ * A tabbed grid: a `role="tablist"` strip above a stack of `role="tabpanel"`
9045
+ * regions, each hosting its own, independently-configured grid instance
9046
+ * (BACKLOG-0001039). A tab's grid mounts on first activation and is kept
9047
+ * alive, hidden, until `destroy()`.
9048
+ */
9049
+ interface Tabs {
9050
+ readonly el: HTMLElement;
9051
+ /** The currently active tab id. */
9052
+ readonly activeId: string;
9053
+ /** The configured tab ids, in order. */
9054
+ tabs(): string[];
9055
+ /** The live grid instance for a tab, or `null` before it has been materialised. */
9056
+ tab(id: string): unknown | null;
9057
+ /** Whether a tab's grid has been created yet. */
9058
+ isMounted(id: string): boolean;
9059
+ /** Switch the active tab, gated by `beforeTabChange`. */
9060
+ activate(id: string, opts?: { origin?: 'api' | 'user' }): boolean | Promise<boolean>;
9061
+ on(name: 'beforeTabChange' | 'tab:changed' | 'tabChange:cancelled' | string, fn: (event: TabChangeEvent) => void): () => void;
9062
+ off(name: string, fn: (event: TabChangeEvent) => void): void;
9063
+ /** Tear the whole strip down; destroys every mounted tab's grid. */
9064
+ destroy(): void;
9065
+ }
9066
+
9067
+ /**
9068
+ * Create a tabbed grid over a host element. Each tab is a full,
9069
+ * independently-configured grid instance; a tab may derive from another via
9070
+ * `from`, reusing the shipped `source: { mode: 'derived' }` mechanism.
9071
+ */
9072
+ export function createTabs(el: HTMLElement, config: TabsConfig): Tabs;
9073
+ export default createTabs;
9074
+ }