@toclocoinc/lattice-grid 1.37.0 → 1.39.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 (69) hide show
  1. package/README.md +1 -1
  2. package/docs/API.html +411 -13
  3. package/docs/api-detail.html +72 -1
  4. package/lattice-grid.d.ts +587 -17
  5. package/lattice-grid.esm.min.js +1203 -58
  6. package/lattice-grid.min.cjs +1200 -58
  7. package/lattice-grid.min.css +1 -1
  8. package/lattice-grid.min.js +1200 -58
  9. package/modules/angular.esm.min.js +4 -2
  10. package/modules/angular.min.cjs +4 -2
  11. package/modules/angular.min.js +4 -2
  12. package/modules/chart-alluvial.esm.min.js +1 -1
  13. package/modules/chart-arc.esm.min.js +1 -1
  14. package/modules/chart-bubblemap.esm.min.js +1 -1
  15. package/modules/chart-bump.esm.min.js +1 -1
  16. package/modules/chart-calendar.esm.min.js +1 -1
  17. package/modules/chart-decomposition.esm.min.js +1 -1
  18. package/modules/chart-diverging.esm.min.js +1 -1
  19. package/modules/chart-dumbbell.esm.min.js +1 -1
  20. package/modules/chart-fan.esm.min.js +1 -1
  21. package/modules/chart-hexbin.esm.min.js +1 -1
  22. package/modules/chart-hexmap.esm.min.js +1 -1
  23. package/modules/chart-icicle.esm.min.js +1 -1
  24. package/modules/chart-parallel.esm.min.js +1 -1
  25. package/modules/chart-ridgeline.esm.min.js +1 -1
  26. package/modules/chart-roc.esm.min.js +1 -1
  27. package/modules/chart-slope.esm.min.js +1 -1
  28. package/modules/chart-splom.esm.min.js +1 -1
  29. package/modules/chart-waffle.esm.min.js +1 -1
  30. package/modules/charts.esm.min.js +467 -10
  31. package/modules/charts.min.cjs +467 -10
  32. package/modules/charts.min.js +467 -10
  33. package/modules/data-router.esm.min.js +184 -7
  34. package/modules/data-router.min.cjs +184 -7
  35. package/modules/data-router.min.js +184 -7
  36. package/modules/devtools.esm.min.js +2 -2
  37. package/modules/devtools.min.cjs +2 -2
  38. package/modules/devtools.min.js +2 -2
  39. package/modules/dhtmlx-compat.esm.min.js +4 -4
  40. package/modules/dhtmlx-compat.min.cjs +4 -4
  41. package/modules/dhtmlx-compat.min.js +4 -4
  42. package/modules/gantt.esm.min.js +845 -16
  43. package/modules/gantt.min.cjs +842 -16
  44. package/modules/gantt.min.js +842 -16
  45. package/modules/htmx.esm.min.js +1197 -58
  46. package/modules/htmx.min.cjs +1197 -58
  47. package/modules/htmx.min.js +1197 -58
  48. package/modules/kanban.esm.min.js +379 -5
  49. package/modules/kanban.min.cjs +379 -5
  50. package/modules/kanban.min.js +379 -5
  51. package/modules/kpi.esm.min.js +4 -4
  52. package/modules/kpi.min.cjs +4 -4
  53. package/modules/kpi.min.js +4 -4
  54. package/modules/mock-socket.esm.min.js +2 -2
  55. package/modules/mock-socket.min.cjs +2 -2
  56. package/modules/mock-socket.min.js +2 -2
  57. package/modules/react.esm.min.js +4 -2
  58. package/modules/react.min.cjs +4 -2
  59. package/modules/react.min.js +4 -2
  60. package/modules/svelte.esm.min.js +4 -2
  61. package/modules/svelte.min.cjs +4 -2
  62. package/modules/svelte.min.js +4 -2
  63. package/modules/vue.esm.min.js +4 -2
  64. package/modules/vue.min.cjs +4 -2
  65. package/modules/vue.min.js +4 -2
  66. package/modules/webcomponent.esm.min.js +1200 -58
  67. package/modules/webcomponent.min.cjs +1200 -58
  68. package/modules/webcomponent.min.js +1200 -58
  69. package/package.json +1 -1
package/lattice-grid.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Lattice Grid 1.37.0, type declarations
2
+ * Lattice Grid 1.39.0, type declarations
3
3
  * Copyright (c) 2026 TOCLOCO Inc. All rights reserved.
4
4
  * https://latticegrid.dev
5
5
  */
@@ -522,6 +522,43 @@ export interface ColumnEditSpec {
522
522
  validate?: (p: ValidateParams) => true | string;
523
523
  }
524
524
 
525
+ /**
526
+ * Declarative edit-validation rules for a column (BACKLOG-0000956).
527
+ *
528
+ * Rules are checked in a fixed order — `required` first, then the value-shape
529
+ * rules, then the functions — and the first failure wins. A blank but optional
530
+ * value passes everything after `required`: an empty cell is empty, not "below
531
+ * the minimum". A failure vetoes the commit through `beforeEdit` and marks the
532
+ * cell; the cancellation carries `reason: 'validation:<code>'`.
533
+ */
534
+ export interface ColumnValidation {
535
+ /** The value may not be blank. A string is used as the message. */
536
+ required?: boolean | string;
537
+ /** Minimum, for a number or a date. */
538
+ min?: number;
539
+ /** Maximum, for a number or a date. */
540
+ max?: number;
541
+ /** Minimum text length. */
542
+ minLength?: number;
543
+ /** Maximum text length. */
544
+ maxLength?: number;
545
+ /** A pattern the whole value must match. A string is a RegExp source. */
546
+ pattern?: string | RegExp;
547
+ /** The value must be one of these. */
548
+ oneOf?: unknown[];
549
+ /**
550
+ * A cross-field rule: return `true` to pass, or a message string to fail. The
551
+ * row is passed so a rule can compare against its siblings.
552
+ */
553
+ crossField?: (value: unknown, row: unknown, ctx: { key: string; colId: string; changes: unknown[] }) => true | string | void;
554
+ /** A free-form check, the same contract as `crossField`. */
555
+ validate?: (value: unknown, row: unknown, ctx: { key: string; colId: string; changes: unknown[] }) => true | string | void;
556
+ /** A default message for any rule without its own. */
557
+ message?: string;
558
+ /** Per-rule messages, keyed by rule name (`required`, `min`, `pattern`, …). */
559
+ messages?: Record<string, string>;
560
+ }
561
+
525
562
  export interface ColumnSortSpec {
526
563
  enabled?: boolean;
527
564
  direction?: 'asc' | 'desc' | null;
@@ -616,6 +653,13 @@ export interface Column {
616
653
  cell?: ColumnCellSpec | string;
617
654
  /** Whether and how the cell can be edited. A string names an editor. */
618
655
  edit?: ColumnEditSpec | boolean | string;
656
+ /**
657
+ * Declarative edit-validation rules (BACKLOG-0000956). Each is checked against
658
+ * a value before it is written, through the `beforeEdit` before-event: a
659
+ * failing value cancels the commit and marks the cell. Distinct from and
660
+ * complementary to `edit.validate`, which is an imperative function.
661
+ */
662
+ validation?: ColumnValidation;
619
663
  /** Whether the column sorts, and by what comparison. `false` refuses it. */
620
664
  sort?: ColumnSortSpec | boolean;
621
665
  /** Whether the column filters, and with which filter. A string names one. */
@@ -1890,6 +1934,24 @@ export interface GridConfig {
1890
1934
  * menu offers Paste, Clear and Fill down.
1891
1935
  */
1892
1936
  contextMenu?: boolean | ((p: CellMenuParams, defaults: MenuItem[]) => MenuItem[] | void);
1937
+ /**
1938
+ * Bringing rows in from a file, the clipboard or a drop (§14, the mirror of
1939
+ * export). `true` adds a "Import rows from CSV…" item to the cell menu, makes
1940
+ * the grid a drop target for `.csv`/`.tsv` files, and reads a pasted
1941
+ * spreadsheet block, each opening a preview the user confirms. An object tunes
1942
+ * the affordances. Off by default; the `grid.import` API is always present.
1943
+ * Import is a client-side data operation, so it applies to a memory grid.
1944
+ */
1945
+ import?: boolean | ImportSettings;
1946
+ /**
1947
+ * Enable the built-in row-delete gesture (§18.4, BACKLOG-0000968) — the
1948
+ * Delete/Backspace key on selected rows and a "Delete row" cell-menu item —
1949
+ * and the `grid.edit.deleteRows` API. Off by default, because deleting data
1950
+ * on a keystroke is destructive and opt-in. Every deletion flows through the
1951
+ * cancellable `beforeDelete` event, so a handler can confirm or veto it, on a
1952
+ * memory-source grid as well as a remote one.
1953
+ */
1954
+ rowDelete?: boolean;
1893
1955
  /**
1894
1956
  * The header's 3-dot menu, and the right-click menu on a column heading.
1895
1957
  * `false` suppresses both. A function supplies custom items, receiving the
@@ -2281,22 +2343,83 @@ export interface FormattingScale {
2281
2343
  }
2282
2344
 
2283
2345
  /**
2284
- * One rule. Either a condition and the styling it produces, or a colour scale.
2285
- * A rule held as runtime state must be JSON, so `style` may not be a function
2286
- * there: config-time `cell.style` still accepts one.
2346
+ * An in-cell proportional bar (BACKLOG-0000955). Drawn as a CSS gradient on the
2347
+ * cell background — no extra element, and it composes with the cell's text.
2348
+ *
2349
+ * The bar's length is the value's position between `min` and `max`. Give both to
2350
+ * pin the scale (0 to 100 for a percentage); otherwise `from` derives them from
2351
+ * the column — `'minmax'` (the default) spans the data, `'quantile'` the 5th–95th
2352
+ * percentile, `'stddev'` a number of deviations either side of the mean. When the
2353
+ * range straddles zero, bars grow from a shared axis: positive right, negative
2354
+ * left, each in its own colour.
2355
+ */
2356
+ export interface DataBarSpec {
2357
+ min?: number;
2358
+ max?: number;
2359
+ from?: 'minmax' | 'quantile' | 'stddev';
2360
+ low?: number;
2361
+ high?: number;
2362
+ deviations?: number;
2363
+ /** The fill for non-negative values. */
2364
+ colour?: string;
2365
+ /** American spelling of `colour`. */
2366
+ color?: string;
2367
+ /** The fill for negative values. */
2368
+ negativeColour?: string;
2369
+ /** American spelling of `negativeColour`. */
2370
+ negativeColor?: string;
2371
+ /** Which way the bar grows. `'ltr'` (the default) or `'rtl'`. */
2372
+ direction?: 'ltr' | 'rtl';
2373
+ }
2374
+
2375
+ /**
2376
+ * An icon set (BACKLOG-0000955): a glyph placed beside the value by the band it
2377
+ * falls in. Drawn as a `background-image` with padding, so it too needs no extra
2378
+ * element and stays a plain style value.
2379
+ *
2380
+ * `set` names a built-in — `'arrows'`, `'trafficLights'` or `'ratings'` (see
2381
+ * {@link ICON_SETS}) — or supply your own ordered `icons` (SVG documents, data
2382
+ * URIs or `url(...)` values). Bands are split at `thresholds` (ascending, one
2383
+ * fewer than the icons); without them the column's distribution is cut into
2384
+ * equal-count bands. `reverse` flips the order so a high value can read as red.
2385
+ */
2386
+ export interface IconSetSpec {
2387
+ set?: 'arrows' | 'trafficLights' | 'ratings' | string;
2388
+ /** Your own glyphs, low value first: SVG documents, data URIs or `url(...)`. */
2389
+ icons?: string[];
2390
+ /** How many bands, where the set's size is not fixed (e.g. `'ratings'`). */
2391
+ count?: number;
2392
+ /** Band edges, ascending; one fewer than the number of icons. */
2393
+ thresholds?: number[];
2394
+ /** Reverse the glyph order, so the highest band takes the first icon. */
2395
+ reverse?: boolean;
2396
+ /** Glyph height in pixels. Default 16. */
2397
+ size?: number;
2398
+ }
2399
+
2400
+ /**
2401
+ * One rule. A condition and the styling it produces, a colour scale, a data bar
2402
+ * or an icon set. A rule held as runtime state must be JSON, so `style` may not
2403
+ * be a function there (config-time `cell.style` still accepts one) and a data
2404
+ * bar / icon set / scale is the JSON way to say the same visual intent.
2287
2405
  */
2288
2406
  export interface FormattingRule {
2289
2407
  id?: string;
2290
2408
  when?: FormattingCondition;
2291
2409
  style?: CellStyle | ((p: CellParams) => CellStyle | null);
2292
2410
  scale?: FormattingScale;
2411
+ /** An in-cell proportional bar (BACKLOG-0000955). */
2412
+ dataBar?: DataBarSpec;
2413
+ /** A per-band glyph beside the value (BACKLOG-0000955). */
2414
+ iconSet?: IconSetSpec;
2293
2415
  stopIfTrue?: boolean;
2294
2416
  enabled?: boolean;
2295
- icon?: string;
2296
- bar?: boolean;
2297
2417
  label?: string;
2298
2418
  }
2299
2419
 
2420
+ /** The built-in icon set names, id to label, for a panel to offer. */
2421
+ export const ICON_SETS: Readonly<Record<string, string>>;
2422
+
2300
2423
  /** A column id, or `'*'` for every column. */
2301
2424
  export type FormattingScope = string;
2302
2425
 
@@ -2547,8 +2670,8 @@ export interface StatisticsApi {
2547
2670
  * verdict from nowhere. Non-numeric columns are returned under `skipped`.
2548
2671
  */
2549
2672
  anomalies(opts?: { columns?: string[];
2550
- method?: 'modifiedZScore' | 'iqr' | 'mahalanobis';
2551
- threshold?: number; k?: number; p?: number }): AnomalyReport;
2673
+ method?: 'modifiedZScore' | 'iqr' | 'mahalanobis' | 'rollingModifiedZScore' | 'rollingIqr';
2674
+ threshold?: number; k?: number; p?: number; windowLen?: number; minPeriods?: number }): AnomalyReport;
2552
2675
  /**
2553
2676
  * Which columns differ most between the filtered subset and the whole
2554
2677
  * population it was drawn from, ranked by effect size — never by a p-value.
@@ -2820,6 +2943,52 @@ export function mahalanobis(
2820
2943
  distances: (number | null)[]; squared: (number | null)[]; flags: boolean[];
2821
2944
  flagged: number } | null;
2822
2945
 
2946
+ /**
2947
+ * The rolling (windowed) anomaly methods (BACKLOG-0000954): the robust modified
2948
+ * z-score and Tukey's IQR fences, each computed over a trailing window rather
2949
+ * than the whole series, for live monitoring where a drift or a shifted regime
2950
+ * must not poison a global baseline.
2951
+ */
2952
+ export const ROLLING_ANOMALY_METHODS: readonly ('rollingModifiedZScore' | 'rollingIqr')[];
2953
+
2954
+ /**
2955
+ * Rolling (windowed) anomaly detection (BACKLOG-0000954): judge every reading
2956
+ * against a causal trailing window ending at it — the current point and the
2957
+ * `window − 1` before it — so a spike is caught against its recent neighbours and
2958
+ * a slow drift does not permanently poison the baseline. With a window at least
2959
+ * as long as the series (and `minPeriods` of 1) the last point's score equals the
2960
+ * static {@link modifiedZScores} score. A non-finite reading, a too-short window
2961
+ * (`minPeriods`) or a zero-MAD window yields a null score and no flag.
2962
+ */
2963
+ export function rollingAnomalies(
2964
+ values: ArrayLike<number>,
2965
+ opts?: {
2966
+ method?: 'rollingModifiedZScore' | 'rollingIqr';
2967
+ windowLen?: number; threshold?: number; k?: number; minPeriods?: number;
2968
+ },
2969
+ ): { method: string; windowLen: number; minPeriods: number; threshold: number; k: number;
2970
+ scores: (number | null)[]; flags: boolean[]; flagged: number };
2971
+
2972
+ /**
2973
+ * Build a Data Router alert condition from an anomaly detector (BACKLOG-0000954):
2974
+ * a `(rows) => signal` for the router's existing `router.alert(value, condition,
2975
+ * handler)` (BACKLOG-0000909), so live monitoring reuses the router's
2976
+ * partitioning, debounce and rising-edge re-arm rather than duplicating any of
2977
+ * it. Reads one numeric `field` off each row, runs the chosen detector, and
2978
+ * returns the flagged rows and scores when anything is anomalous or `false` when
2979
+ * nothing is. `orderBy` names the axis rolling methods window on; `latest` signals
2980
+ * only when the newest reading is the anomaly.
2981
+ */
2982
+ export function anomalyCondition(
2983
+ opts: {
2984
+ field: string;
2985
+ method?: 'modifiedZScore' | 'iqr' | 'rollingModifiedZScore' | 'rollingIqr';
2986
+ orderBy?: string; latest?: boolean;
2987
+ windowLen?: number; threshold?: number; k?: number; minPeriods?: number;
2988
+ },
2989
+ ): (rows: Iterable<Record<string, unknown>>) =>
2990
+ false | { method: string; field: string; flagged: { row: Record<string, unknown>; score: number | null }[] };
2991
+
2823
2992
  export type ShadowKind =
2824
2993
  | 'updates' | 'updatedAt' | 'sinceUpdate' | 'delta' | 'deltaPercent'
2825
2994
  | 'rate' | 'history' | 'firstValue' | 'streak'
@@ -3106,6 +3275,12 @@ export interface ColumnProfile {
3106
3275
  stddev: number | null;
3107
3276
  outliers: number;
3108
3277
  histogram: HistogramBin[];
3278
+ /**
3279
+ * For a categorical (non-numeric) column, the commonest values, largest
3280
+ * first (BACKLOG-0000959). Absent for a numeric column, whose shape the
3281
+ * numeric figures and the histogram already carry.
3282
+ */
3283
+ topValues?: TopValue[];
3109
3284
  }
3110
3285
 
3111
3286
  export interface HistogramBin {
@@ -3114,6 +3289,16 @@ export interface HistogramBin {
3114
3289
  count: number;
3115
3290
  }
3116
3291
 
3292
+ /** One row of a categorical column's top-values table (BACKLOG-0000959). */
3293
+ export interface TopValue {
3294
+ /** The value itself, as it is stored. */
3295
+ value: unknown;
3296
+ /** How many present rows carry it. */
3297
+ count: number;
3298
+ /** Its share of the present values, 0 to 1. */
3299
+ share: number;
3300
+ }
3301
+
3117
3302
  /** How one column differs between the filtered subset and its population. */
3118
3303
  export interface ColumnDifference {
3119
3304
  /** The column id. */
@@ -3365,6 +3550,30 @@ export interface FormattingApi {
3365
3550
  distribution(colId: string): ColumnDistribution | null;
3366
3551
  }
3367
3552
 
3553
+ /** One recorded validation error (BACKLOG-0000956). */
3554
+ export interface ValidationError {
3555
+ key: string;
3556
+ colId: string;
3557
+ code: string;
3558
+ message: string;
3559
+ }
3560
+
3561
+ /** The runtime face of declarative column validation (BACKLOG-0000956). */
3562
+ export interface ValidationApi {
3563
+ /** Run a column's rules against a value, returning the first failure or null. */
3564
+ check(colId: string, value: unknown, row?: unknown): { code: string; message: string } | null;
3565
+ /** The recorded error for one cell, or null when it is valid. */
3566
+ errorFor(key: string, colId: string): ValidationError | null;
3567
+ /** Every cell that currently holds a validation error. */
3568
+ errors(): ValidationError[];
3569
+ /** Clear errors: one cell, a whole row, or all of them. */
3570
+ clear(key?: string, colId?: string): boolean;
3571
+ /** Set or replace a column's rules at runtime; null removes them. */
3572
+ define(colId: string, spec: ColumnValidation | null): void;
3573
+ /** Whether at least one column declares a rule. */
3574
+ readonly active: boolean;
3575
+ }
3576
+
3368
3577
  /** Operators that resolve against the column's own distribution (spec 8.12). */
3369
3578
  export type DistributionOp =
3370
3579
  | 'topPercent' | 'bottomPercent' | 'topN' | 'bottomN'
@@ -3419,7 +3628,8 @@ export type EventName =
3419
3628
  | 'facet:computed' | 'facet:filtered' | 'facet:expanded' | 'facet:failed'
3420
3629
  /* Columns */
3421
3630
  | 'column:moved' | 'column:resized' | 'column:visible' | 'column:pinned'
3422
- | 'column:grouped' | 'column:pivoted' | 'column:filter:open' | 'column:menu:open'
3631
+ | 'column:grouped' | 'column:pivoted' | 'column:filter:open' | 'column:profile:open'
3632
+ | 'column:menu:open'
3423
3633
  | 'pivot:drill'
3424
3634
  | 'columns:changed' | 'columns:tagged' | 'columngroup:changed' | 'header:contextmenu'
3425
3635
  /* Selection and view */
@@ -3432,6 +3642,9 @@ export type EventName =
3432
3642
  | 'state:changed' | 'state:reset' | 'history:changed' | 'history:applied'
3433
3643
  | 'views:changed' | 'view:applied' | 'view:saved' | 'view:removed'
3434
3644
  | 'view:renamed' | 'view:default'
3645
+ /* Validation (BACKLOG-0000956): a declared column rule vetoed an edit, or a
3646
+ * recorded error was cleared. The veto itself rides the cancellable `beforeEdit`. */
3647
+ | 'validation:failed' | 'validation:cleared'
3435
3648
  /* Formatting and presentation */
3436
3649
  | 'formatting:changed' | 'redaction:changed' | 'permissions:changed'
3437
3650
  | 'presentation:changed' | 'presentation:started' | 'presentation:ended'
@@ -3865,6 +4078,19 @@ export interface EditApi {
3865
4078
  * @returns the id the op is tracked under, or null when delete is not available
3866
4079
  */
3867
4080
  deleteRow(key: string): string | null;
4081
+ /**
4082
+ * Delete rows on a user gesture, through the cancellable `beforeDelete` event
4083
+ * (§18.4, BACKLOG-0000968) — what the built-in Delete-key and "Delete row"
4084
+ * gestures call. Unlike {@link deleteRow}, `beforeDelete` fires on a
4085
+ * memory-source grid too, so the row can be confirmed or vetoed there. Off
4086
+ * until `config.rowDelete` opts in; the keys default to the row selection.
4087
+ * Returns the keys removed (empty on a veto or when disabled), or a Promise of
4088
+ * them when a `beforeDelete` handler deferred.
4089
+ * @param keys the row keys; defaults to the current selection
4090
+ * @param opts `origin` names the provenance carried onto the events
4091
+ * @returns the removed keys, or a Promise of them on the async path
4092
+ */
4093
+ deleteRows(keys?: string | string[], opts?: { origin?: string }): string[] | Promise<string[]>;
3868
4094
  /**
3869
4095
  * Report the outcome of an optimistic structural write (§5.3), the counterpart
3870
4096
  * to {@link settle} for `edit.confirm: 'manual'` over a backend that
@@ -3914,6 +4140,65 @@ export interface ExportApi {
3914
4140
  print(): void;
3915
4141
  }
3916
4142
 
4143
+ /** How `config.import` tunes the DOM import affordances (§14). */
4144
+ export interface ImportSettings {
4145
+ /** Add the cell-menu item and open a file picker for CSV/TSV. Default true. */
4146
+ file?: boolean;
4147
+ /** Make the grid a drop target for `.csv`/`.tsv` files. Default true. */
4148
+ drop?: boolean;
4149
+ /** Read a pasted spreadsheet block into a preview. Default true. */
4150
+ paste?: boolean;
4151
+ /** How a confirmed import lands: append (default) or replace the dataset. */
4152
+ mode?: 'append' | 'replace';
4153
+ }
4154
+
4155
+ /** One source column as understood by the importer, after type inference (§14). */
4156
+ export interface ImportColumn {
4157
+ /** The heading as written in the file. */
4158
+ source: string;
4159
+ /** The column's position in each row. */
4160
+ index: number;
4161
+ /** The grid field this column maps onto; empty to exclude it from the import. */
4162
+ field: string;
4163
+ /** The inferred (or grid-dictated) type used to coerce the column's values. */
4164
+ type: string;
4165
+ /** A few non-blank sample values, for the preview. */
4166
+ samples: string[];
4167
+ /** Whether the heading matched one of the grid's own columns. */
4168
+ matched: boolean;
4169
+ }
4170
+
4171
+ /** What a preview carries — everything a confirm dialog needs (§14). */
4172
+ export interface ImportPreview {
4173
+ /** The delimiter that was used, detected or supplied. */
4174
+ delimiter: string;
4175
+ /** The source column headings. */
4176
+ header: string[];
4177
+ /** The per-column mapping and inference the user may edit before confirming. */
4178
+ columns: ImportColumn[];
4179
+ /** Every mapped, coerced record the import would add. */
4180
+ records: Record<string, unknown>[];
4181
+ /** The leading records, for a preview table. */
4182
+ sample: Record<string, unknown>[];
4183
+ /** How many data rows the file holds. */
4184
+ rowCount: number;
4185
+ /** Anything worth flagging before confirming — a ragged file, a bad quote. */
4186
+ warnings: string[];
4187
+ }
4188
+
4189
+ /** Bringing rows in — the mirror of {@link ExportApi} (§14, BACKLOG-0000949). */
4190
+ export interface ImportApi {
4191
+ /** Parse delimited text into a preview, changing nothing. */
4192
+ preview(text: string, opts?: object): ImportPreview;
4193
+ /** Parse delimited text into coerced records — the inverse of `export.csv`. */
4194
+ csv(text: string, opts?: object): Record<string, unknown>[];
4195
+ /** Add or replace the grid's rows from text, a preview or records. */
4196
+ apply(
4197
+ input: string | ImportPreview | Record<string, unknown>[],
4198
+ opts?: { mode?: 'append' | 'replace' },
4199
+ ): ChangeResult | null;
4200
+ }
4201
+
3917
4202
  export interface SavedView {
3918
4203
  id: string;
3919
4204
  name: string;
@@ -4709,6 +4994,8 @@ export interface Grid {
4709
4994
  readonly scroll: ScrollApi;
4710
4995
  /** CSV, Excel and clipboard. */
4711
4996
  readonly export: ExportApi;
4997
+ /** Bringing rows in from CSV/TSV text, a file, the clipboard or a drop. */
4998
+ readonly import: ImportApi;
4712
4999
  /** Everything the user arranged, as a serialisable object. */
4713
5000
  readonly state: StateApi;
4714
5001
  /** The loading, empty and error surfaces drawn over the grid. */
@@ -4761,6 +5048,8 @@ export interface Grid {
4761
5048
  readonly statistics: StatisticsApi;
4762
5049
  /** Formatting a value as the grid would, outside a cell. */
4763
5050
  readonly formatting: FormattingApi;
5051
+ /** Declarative column validation: why a write was refused, and clearing marks. */
5052
+ readonly validation: ValidationApi;
4764
5053
  /** Full-screen control, where it is enabled. */
4765
5054
  readonly maximise?: MaximiseApi;
4766
5055
  /**
@@ -5621,22 +5910,82 @@ export interface ChartAxis {
5621
5910
  * placed against the wrong scale, and is written into the accessible table as a
5622
5911
  * sentence.
5623
5912
  */
5913
+ /**
5914
+ * A trend or forecast overlay method (BACKLOG-0000952). Each name has aliases:
5915
+ * `linear` (also `lr`, `ols`, `regression`); `movingAverage` (also `ma`, `sma`,
5916
+ * `rolling`); `exponential` (also `ewma`, `ses`, `holt`, `smoothing`).
5917
+ */
5918
+ export type ChartTrendMethod = 'linear' | 'movingAverage' | 'exponential'
5919
+ | 'lr' | 'ols' | 'regression' | 'ma' | 'sma' | 'rolling'
5920
+ | 'ewma' | 'ses' | 'holt' | 'smoothing';
5921
+
5922
+ /** One trend or forecast overlay (BACKLOG-0000952). */
5923
+ export interface ChartTrend {
5924
+ /** The overlay method; `linear` by default. */
5925
+ method?: ChartTrendMethod;
5926
+ /**
5927
+ * For the linear method, how many steps to project the line past the data as a
5928
+ * dashed forecast. Ignored by the moving-average and exponential methods,
5929
+ * which have no slope to extrapolate.
5930
+ */
5931
+ forecast?: number;
5932
+ /** For the moving-average method, the trailing window in points; 3 by default. */
5933
+ window?: number;
5934
+ /** An alias for `window`. */
5935
+ period?: number;
5936
+ /** For the exponential method, single smoothing (`ses`) or Holt's level+trend (`holt`). */
5937
+ kind?: 'ses' | 'holt';
5938
+ /** For the exponential method, the level factor in `[0, 1]`; omit to fit it. */
5939
+ alpha?: number;
5940
+ /** For Holt's exponential smoothing, the trend factor in `[0, 1]`; omit to fit it. */
5941
+ beta?: number;
5942
+ /** `false` suppresses the R² label on a linear trend. */
5943
+ label?: boolean;
5944
+ }
5945
+
5946
+ /**
5947
+ * One declarative annotation (BACKLOG-0000744, extended by BACKLOG-0000953). A
5948
+ * reference or target line, a shaded band, a callout, or an `event` marker. Its
5949
+ * value is a constant `value` (or `from`/`to` for a band), or a `compute`
5950
+ * reduction of the data it annotates — `mean`, `median`, `min`, `max`, or `p95`
5951
+ * for a percentile — so it follows the data as the grid is filtered. A band with
5952
+ * `orient: 'vertical'` shades an x-range instead — an event window, a
5953
+ * maintenance period — and an `event` marker is a labelled vertical rule with a
5954
+ * flag at a position on the x axis. Every annotation names the axis it reads,
5955
+ * which on a dual-axis chart is what stops it being placed against the wrong
5956
+ * scale, and is written into the accessible table as a sentence — a vertical
5957
+ * marker and an event stating the position they sit at, because a screen-reader
5958
+ * user needs where and when, not only that a marker exists.
5959
+ */
5624
5960
  export interface ChartAnnotation {
5625
- /** The default is a reference line. */
5626
- kind?: 'line' | 'target' | 'band' | 'callout';
5961
+ /**
5962
+ * The default is a reference line. `event` is a labelled vertical marker with
5963
+ * a flag at a position on the x axis, described into the accessible table with
5964
+ * that position stated (BACKLOG-0000953).
5965
+ */
5966
+ kind?: 'line' | 'target' | 'band' | 'callout' | 'event';
5627
5967
  /** A constant value, for a line, target or callout's measure position. */
5628
5968
  value?: number;
5629
5969
  /** A reduction of the annotated data instead of a constant. */
5630
5970
  compute?: 'mean' | 'avg' | 'median' | 'min' | 'max' | string;
5631
- /** A band's two edges, each a constant or (with `fromCompute`/`toCompute`) computed. */
5632
- from?: number;
5633
- to?: number;
5971
+ /**
5972
+ * A band's two edges. On a horizontal band each is a measure value, a constant
5973
+ * or (with `fromCompute`/`toCompute`) computed. On a vertical band (`orient:
5974
+ * 'vertical'`, BACKLOG-0000953) each is an x position — a category or a number
5975
+ * — and the band shades the x-range between them: an event window, a
5976
+ * maintenance period, a recession.
5977
+ */
5978
+ from?: number | string;
5979
+ to?: number | string;
5634
5980
  fromCompute?: string;
5635
5981
  toCompute?: string;
5636
- /** A vertical line's or callout's x position: a category or a number. */
5982
+ /** A vertical line's, event marker's or callout's x position: a category or a number. */
5637
5983
  x?: unknown;
5638
5984
  at?: unknown;
5639
- /** Force a line vertical rather than horizontal. */
5985
+ /**
5986
+ * Force a line vertical rather than horizontal, or shade a `band` across an
5987
+ * x-range rather than a measure range (BACKLOG-0000953).
5988
+ */
5640
5989
  orient?: 'horizontal' | 'vertical';
5641
5990
  /** Which measure axis the annotation reads. */
5642
5991
  axis?: 'left' | 'right' | 'y2';
@@ -5729,6 +6078,23 @@ export interface ChartSpec {
5729
6078
  * through the order they happened to be listed in.
5730
6079
  */
5731
6080
  fit?: boolean | 'line';
6081
+ /**
6082
+ * Trend and forecast overlays (BACKLOG-0000952): a least-squares line, a
6083
+ * trailing moving average, or exponential smoothing, drawn over a line, area
6084
+ * or scatter chart. `true` draws a single linear trend; a method name or a
6085
+ * {@link ChartTrend} object configures one; an array draws several.
6086
+ *
6087
+ * The maths matches the core stats engine to the last digit — the same
6088
+ * least-squares fit, rolling window and exponential recursions — but is
6089
+ * computed locally in the charts module rather than imported, because the
6090
+ * in-tree bundler does not tree-shake and the import would inline the whole
6091
+ * statistics closure; a test asserts the parity. A `forecast` count projects
6092
+ * the linear line that many steps past the data, drawn dashed so it never
6093
+ * reads as a reading; a moving average and a smoothed level have no slope to
6094
+ * project, so `forecast` is ignored for them and the fact is stated in the
6095
+ * accessible description rather than faked.
6096
+ */
6097
+ trend?: boolean | ChartTrendMethod | ChartTrend | Array<ChartTrendMethod | ChartTrend>;
5732
6098
  /**
5733
6099
  * A pointwise confidence band, drawn as a varying-width ribbon beneath the fit
5734
6100
  * line (BACKLOG-0000812). Fed by a fitted model's own interval — the `band`
@@ -6404,10 +6770,38 @@ declare module 'lattice-grid/modules/gantt' {
6404
6770
  assignee?: string | string[];
6405
6771
  assignees?: string[];
6406
6772
  owner?: string;
6773
+ /**
6774
+ * Explicit resource assignments with fractional units (BACKLOG-0000948):
6775
+ * `units` is a multiplier where 1 is a full-time booking. Use this when a
6776
+ * task books a resource at less (or more) than 100%; a bare `assignee` is
6777
+ * `units: 1`.
6778
+ */
6779
+ assignments?: Array<{ resource?: string; name?: string; id?: string; units?: number }>;
6780
+ /** Leveling priority: a higher value is delayed last (default 0). */
6781
+ priority?: number;
6407
6782
  /** An explicit row height (px) for the split view; applied to both panels. */
6408
6783
  height?: number;
6784
+ /**
6785
+ * The budgeted cost (BAC) for earned-value analysis (BACKLOG-0000958). When
6786
+ * omitted the task's duration is used as the budget, giving schedule-only EVM.
6787
+ */
6788
+ cost?: number;
6789
+ /**
6790
+ * The actual cost incurred (ACWP) for earned-value analysis
6791
+ * (BACKLOG-0000958). Left out, the task's cost variance/CPI are `null`.
6792
+ */
6793
+ actualCost?: number;
6409
6794
  }
6410
6795
 
6796
+ /**
6797
+ * Resource capacities for over-allocation detection and leveling
6798
+ * (BACKLOG-0000948): either a list of resources with a capacity (max
6799
+ * concurrent units, default 1) or a name→capacity map.
6800
+ */
6801
+ export type GanttResourceSpec =
6802
+ | Array<{ id?: string; name?: string; resource?: string; capacity?: number; maxUnits?: number; max?: number; units?: number }>
6803
+ | Record<string, number>;
6804
+
6411
6805
  /**
6412
6806
  * A typed dependency between two tasks (by id), with optional lag/lead. `type`
6413
6807
  * defaults to `'FS'`; either endpoint may be a leaf or a summary.
@@ -6467,6 +6861,47 @@ declare module 'lattice-grid/modules/gantt' {
6467
6861
  conflicts?: GanttConflict[];
6468
6862
  /** Whether a working-time calendar was applied. */
6469
6863
  calendar?: boolean;
6864
+ /** The resource over-allocations for this schedule (BACKLOG-0000948). */
6865
+ overAllocations?: GanttOverAllocation[];
6866
+ /** The full resource-load report for this schedule (BACKLOG-0000948). */
6867
+ resourceLoad?: GanttResourceLoad;
6868
+ }
6869
+
6870
+ /** One contiguous load segment for a resource: how many units are booked over a span. */
6871
+ interface GanttResourceSegment {
6872
+ start: number;
6873
+ end: number;
6874
+ load: number;
6875
+ taskIds: string[];
6876
+ }
6877
+
6878
+ /** A resource booked beyond its capacity across concurrent tasks (BACKLOG-0000948). */
6879
+ interface GanttOverAllocation {
6880
+ resource: string;
6881
+ capacity: number;
6882
+ start: number;
6883
+ end: number;
6884
+ load: number;
6885
+ taskIds: string[];
6886
+ }
6887
+
6888
+ /** The per-resource load and the over-allocations across a schedule (BACKLOG-0000948). */
6889
+ interface GanttResourceLoad {
6890
+ ok: boolean;
6891
+ resources: Array<{ resource: string; capacity: number; peak: number; segments: GanttResourceSegment[] }>;
6892
+ overAllocations: GanttOverAllocation[];
6893
+ byResource: Map<string, { capacity: number; peak: number; segments: GanttResourceSegment[] }>;
6894
+ }
6895
+
6896
+ /** The result of resource leveling: the shifted tasks and what moved (BACKLOG-0000948). */
6897
+ interface GanttLevelResult {
6898
+ ok: boolean;
6899
+ resolved?: boolean;
6900
+ tasks?: GanttTask[];
6901
+ schedule?: GanttSchedule;
6902
+ moves?: Array<{ id: string; from: number; to: number; delay: number }>;
6903
+ remaining?: GanttOverAllocation[];
6904
+ error?: { code: string; message: string };
6470
6905
  }
6471
6906
 
6472
6907
  /** A placement violation flagged by `findViolations`. */
@@ -6497,6 +6932,62 @@ declare module 'lattice-grid/modules/gantt' {
6497
6932
  /** Format an engine day-number as an ISO calendar date (`YYYY-MM-DD`, UTC). */
6498
6933
  export function toISODate(day: number): string | null;
6499
6934
 
6935
+ /** Earned-value metrics for one task or the whole project (BACKLOG-0000958). */
6936
+ interface GanttEarnedValueRow {
6937
+ id: string;
6938
+ name: string;
6939
+ isSummary: boolean;
6940
+ isMilestone: boolean;
6941
+ percentComplete: number | null;
6942
+ /** Whether a baseline (not the fallback scheduled window) drove PV. */
6943
+ hasBaseline: boolean;
6944
+ /** Whether any actual cost fed AC (else AC/CV/CPI are null). */
6945
+ hasActualCost: boolean;
6946
+ /** Budget at completion (the task's cost, or its duration when no cost). */
6947
+ bac: number;
6948
+ /** Planned Value (BCWS): budgeted cost of the work scheduled by the status date. */
6949
+ pv: number;
6950
+ /** Earned Value (BCWP): budgeted cost of the work performed (BAC × %complete). */
6951
+ ev: number;
6952
+ /** Actual Cost (ACWP): what the work performed actually cost, or null. */
6953
+ ac: number | null;
6954
+ /** Schedule Variance (EV − PV); positive is ahead of schedule. */
6955
+ sv: number;
6956
+ /** Cost Variance (EV − AC); positive is under budget; null without AC. */
6957
+ cv: number | null;
6958
+ /** Schedule Performance Index (EV / PV); null when PV is zero. */
6959
+ spi: number | null;
6960
+ /** Cost Performance Index (EV / AC); null without AC or when AC is zero. */
6961
+ cpi: number | null;
6962
+ }
6963
+
6964
+ /** The earned-value result at a status date (BACKLOG-0000958). */
6965
+ interface GanttEarnedValue {
6966
+ ok: boolean;
6967
+ error?: { code: string; message: string };
6968
+ /** The status date the metrics were evaluated at (day-number). */
6969
+ statusDate?: number;
6970
+ /** Every task keyed by id (leaf, summary and derived). */
6971
+ byTask?: Map<string, GanttEarnedValueRow>;
6972
+ /** The same rows in schedule order. */
6973
+ rows?: GanttEarnedValueRow[];
6974
+ /** The project total, rolled up as money sums of the leaves. */
6975
+ project?: GanttEarnedValueRow;
6976
+ }
6977
+
6978
+ /**
6979
+ * Compute earned-value management (EVM) metrics for a scheduled plan at a
6980
+ * status date (BACKLOG-0000958): PV/BCWS from the baseline, EV/BCWP from
6981
+ * %complete, AC/ACWP from the per-task `actualCost`, and the derived SV/CV and
6982
+ * SPI/CPI — per leaf, rolled up to summaries and the project. The math is
6983
+ * implemented locally in the module (no core-compute dependency).
6984
+ */
6985
+ export function computeEarnedValue(
6986
+ tasks: GanttTask[],
6987
+ schedule: GanttSchedule,
6988
+ options?: { statusDate?: number | string | Date; costField?: string; actualCostField?: string },
6989
+ ): GanttEarnedValue;
6990
+
6500
6991
  /** A headless Gantt controller: holds the model, recomputes on edits, emits changes. */
6501
6992
  interface Gantt {
6502
6993
  readonly tasks: GanttTask[];
@@ -6507,13 +6998,43 @@ declare module 'lattice-grid/modules/gantt' {
6507
6998
  readonly conflicts: GanttConflict[];
6508
6999
  readonly autoSchedule: boolean;
6509
7000
  readonly grid: unknown;
7001
+ /** The over-allocations from the latest schedule (BACKLOG-0000948). */
7002
+ readonly overAllocations: GanttOverAllocation[];
7003
+ /** The latest resource-load report, or null before a successful schedule (BACKLOG-0000948). */
7004
+ readonly resourceLoad: GanttResourceLoad | null;
6510
7005
  setTasks(tasks: GanttTask[]): GanttSchedule;
6511
7006
  setDependencies(deps: GanttDependency[]): GanttSchedule;
6512
7007
  applyEdit(patch: { id: string | number; start?: number; end?: number; duration?: number }, editOpts?: { writeBack?: boolean }): GanttSchedule;
6513
7008
  compute(): GanttSchedule;
6514
7009
  findViolations(): GanttViolation[];
7010
+ /**
7011
+ * Compute the resource load and over-allocations on demand (BACKLOG-0000948),
7012
+ * optionally overriding the capacities for this call.
7013
+ */
7014
+ resources(loadOpts?: { resources?: GanttResourceSpec; defaultCapacity?: number }): GanttResourceLoad;
7015
+ /**
7016
+ * Resolve resource over-allocation by shifting tasks later — resource
7017
+ * leveling (BACKLOG-0000948). Honours the CPM dependencies and the
7018
+ * working-time calendar. Mutates the model unless `{ dryRun: true }`; with
7019
+ * `{ writeBack: true }` and a bound grid the moved tasks are pushed through
7020
+ * the grid's edit surface.
7021
+ */
7022
+ level(levelOpts?: {
7023
+ dryRun?: boolean;
7024
+ writeBack?: boolean;
7025
+ priorityField?: string;
7026
+ maxIterations?: number;
7027
+ resources?: GanttResourceSpec;
7028
+ defaultCapacity?: number;
7029
+ }): GanttLevelResult;
6515
7030
  /** Export the scheduled tasks as CSV; `{ dates: true }` writes ISO dates. */
6516
7031
  toCSV(csvOpts?: { dates?: boolean }): string;
7032
+ /**
7033
+ * Export the current plan as Microsoft Project (MSPDI) XML (BACKLOG-0000950):
7034
+ * tasks, dependencies, constraints, baseline, resources and assignments, plus
7035
+ * the working-time calendar, serialised with the computed schedule.
7036
+ */
7037
+ toMSPDI(xmlOpts?: { hoursPerDay?: number; projectName?: string }): string;
6517
7038
  /**
6518
7039
  * The live consumer surface, mirroring `grid.rows.apply`, so a Data Router
6519
7040
  * can drive the Gantt like any other view. Keyed by the controller's rowKey.
@@ -6581,7 +7102,13 @@ declare module 'lattice-grid/modules/gantt' {
6581
7102
  showProgress?: boolean;
6582
7103
  showBaseline?: boolean;
6583
7104
  barLabel?: 'name' | 'percent' | 'dates' | 'none' | ((task: GanttScheduledTask) => string);
6584
- columns?: Array<{ key: string; title?: string; width?: number; kind?: 'name' | 'assignee' | 'progress'; render?: (task: GanttScheduledTask, ctx: { rawTask: GanttTask; depth: number }) => unknown }>;
7105
+ /**
7106
+ * Surface earned-value metrics in `kind: 'evm'` columns (BACKLOG-0000958).
7107
+ * `true` computes EVM at the today line (or the project finish); an object
7108
+ * overrides the status date and the cost field names.
7109
+ */
7110
+ evm?: boolean | { statusDate?: number | string | Date; costField?: string; actualCostField?: string };
7111
+ columns?: Array<{ key: string; title?: string; width?: number; kind?: 'name' | 'assignee' | 'progress' | 'evm'; metric?: 'bac' | 'pv' | 'ev' | 'ac' | 'sv' | 'cv' | 'spi' | 'cpi'; digits?: number; render?: (task: GanttScheduledTask, ctx: { rawTask: GanttTask; depth: number }) => unknown }>;
6585
7112
  }): unknown;
6586
7113
  /**
6587
7114
  * Capture a baseline (planned) snapshot of the current schedule as HOST data
@@ -6589,6 +7116,13 @@ declare module 'lattice-grid/modules/gantt' {
6589
7116
  * `baselineStart`/`baselineEnd` task fields to get variance and ghost bars.
6590
7117
  */
6591
7118
  captureBaseline(): Array<{ id: string; baselineStart: number; baselineEnd: number; baselineDuration: number }>;
7119
+ /**
7120
+ * Compute earned-value (EVM) metrics for the current plan at a status date
7121
+ * (BACKLOG-0000958): PV/EV/AC and the derived SV/CV/SPI/CPI per task, rolled
7122
+ * up to summaries and the project. Budget (BAC) is the task's `cost`, or its
7123
+ * duration when no cost is given; AC comes from `actualCost`.
7124
+ */
7125
+ earnedValue(evmOpts?: { statusDate?: number | string | Date; costField?: string; actualCostField?: string }): GanttEarnedValue;
6592
7126
  /** Detach the mounted view, if any. The host still owns the container. */
6593
7127
  unmount(): void;
6594
7128
  /** The mounted view, or null. */
@@ -6612,6 +7146,10 @@ declare module 'lattice-grid/modules/gantt' {
6612
7146
  deadline?: number | string | Date;
6613
7147
  /** A working-time calendar: skip weekends/holidays, durations in working days. */
6614
7148
  calendar?: GanttCalendar | null;
7149
+ /** Resource capacities for over-allocation detection and leveling (BACKLOG-0000948). */
7150
+ resources?: GanttResourceSpec;
7151
+ /** The capacity for a resource with none stated (default 1 = one full-time booking). */
7152
+ defaultCapacity?: number;
6615
7153
  autoSchedule?: boolean;
6616
7154
  grid?: unknown;
6617
7155
  /** Map task fields to grid column ids to enable drag write-back. */
@@ -6622,6 +7160,38 @@ declare module 'lattice-grid/modules/gantt' {
6622
7160
  element?: unknown;
6623
7161
  }): Gantt;
6624
7162
  export default createGantt;
7163
+
7164
+ /** The model {@link importMSPDI} returns and {@link exportMSPDI} takes. */
7165
+ interface GanttMSPDIModel {
7166
+ tasks: GanttTask[];
7167
+ dependencies?: GanttDependency[];
7168
+ resources?: GanttResourceSpec;
7169
+ projectStart?: number | string | Date;
7170
+ calendar?: GanttCalendar | null;
7171
+ schedule?: GanttSchedule;
7172
+ }
7173
+
7174
+ /**
7175
+ * Import a Microsoft Project (MSPDI) XML document (BACKLOG-0000950) into the
7176
+ * module's model: the task tree, typed dependencies with lag, constraints,
7177
+ * baseline, %complete, resources with capacity, the resource assignments, and
7178
+ * the working-time calendar. The result is ready to pass to {@link createGantt}.
7179
+ */
7180
+ export function importMSPDI(xml: string, opts?: { hoursPerDay?: number }): {
7181
+ ok: boolean;
7182
+ error?: string;
7183
+ tasks: GanttTask[];
7184
+ dependencies: GanttDependency[];
7185
+ resources: Array<{ id: string; name: string; capacity: number }>;
7186
+ projectStart?: number;
7187
+ calendar?: null | { workdays: number[]; holidays: number[] };
7188
+ };
7189
+
7190
+ /**
7191
+ * Export a Gantt model to Microsoft Project (MSPDI) XML (BACKLOG-0000950). A
7192
+ * scheduled model may be passed so start/finish dates are the computed ones.
7193
+ */
7194
+ export function exportMSPDI(model: GanttMSPDIModel, opts?: { hoursPerDay?: number; projectName?: string }): string;
6625
7195
  }
6626
7196
 
6627
7197
  declare module 'lattice-grid/modules/webcomponent' {