@ai-matrx/design-system 0.40.0 → 0.41.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 (44) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/dist/data-table/copy-helpers.d.cts +2 -2
  3. package/dist/data-table/copy-helpers.d.ts +2 -2
  4. package/dist/data-table/filter-engine.d.cts +2 -2
  5. package/dist/data-table/filter-engine.d.ts +2 -2
  6. package/dist/data-table/host.d.cts +2 -2
  7. package/dist/data-table/host.d.ts +2 -2
  8. package/dist/data-table/index.cjs +269 -5
  9. package/dist/data-table/index.cjs.map +1 -1
  10. package/dist/data-table/index.d.cts +3 -3
  11. package/dist/data-table/index.d.ts +3 -3
  12. package/dist/data-table/index.js +269 -5
  13. package/dist/data-table/index.js.map +1 -1
  14. package/dist/data-table/infer-filter.d.cts +2 -2
  15. package/dist/data-table/infer-filter.d.ts +2 -2
  16. package/dist/data-table/layered-filters.d.cts +2 -2
  17. package/dist/data-table/layered-filters.d.ts +2 -2
  18. package/dist/data-table/query-control.d.cts +2 -2
  19. package/dist/data-table/query-control.d.ts +2 -2
  20. package/dist/data-table/types.d.cts +2 -2
  21. package/dist/data-table/types.d.ts +2 -2
  22. package/dist/data-table/url-state.d.cts +2 -2
  23. package/dist/data-table/url-state.d.ts +2 -2
  24. package/dist/data-table/validation.d.cts +1 -1
  25. package/dist/data-table/validation.d.ts +1 -1
  26. package/dist/data-table/xlsx.d.cts +2 -2
  27. package/dist/data-table/xlsx.d.ts +2 -2
  28. package/dist/field-formats/index.cjs +269 -5
  29. package/dist/field-formats/index.cjs.map +1 -1
  30. package/dist/field-formats/index.d.cts +2 -2
  31. package/dist/field-formats/index.d.ts +2 -2
  32. package/dist/field-formats/index.js +269 -5
  33. package/dist/field-formats/index.js.map +1 -1
  34. package/dist/formulas/index.cjs +38 -5
  35. package/dist/formulas/index.cjs.map +1 -1
  36. package/dist/formulas/index.d.cts +39 -2
  37. package/dist/formulas/index.d.ts +39 -2
  38. package/dist/formulas/index.js +38 -5
  39. package/dist/formulas/index.js.map +1 -1
  40. package/dist/{types-oVyZbfwn.d.cts → types-DNkbHRVK.d.cts} +1 -1
  41. package/dist/{types-Z32pxexx.d.ts → types-Dx5hJgCi.d.ts} +1 -1
  42. package/dist/{types-CJWU1Gae.d.cts → types-JnZD8wM0.d.cts} +27 -2
  43. package/dist/{types-CJWU1Gae.d.ts → types-JnZD8wM0.d.ts} +27 -2
  44. package/package.json +1 -1
@@ -1,11 +1,11 @@
1
- import { M as MatrxColumnDef, f as ColumnFilterKind } from '../types-oVyZbfwn.cjs';
1
+ import { M as MatrxColumnDef, f as ColumnFilterKind } from '../types-DNkbHRVK.cjs';
2
2
  import '../content-transfer.cjs';
3
3
  import 'react';
4
4
  import '@ai-matrx/kit/content-transfer';
5
5
  import '../content-transfer/icon.cjs';
6
6
  import './copy-types.cjs';
7
7
  import './table-style.cjs';
8
- import '../types-CJWU1Gae.cjs';
8
+ import '../types-JnZD8wM0.cjs';
9
9
  import './grouping.cjs';
10
10
  import './fill.cjs';
11
11
  import './facets.cjs';
@@ -1,11 +1,11 @@
1
- import { M as MatrxColumnDef, f as ColumnFilterKind } from '../types-Z32pxexx.js';
1
+ import { M as MatrxColumnDef, f as ColumnFilterKind } from '../types-Dx5hJgCi.js';
2
2
  import '../content-transfer.js';
3
3
  import 'react';
4
4
  import '@ai-matrx/kit/content-transfer';
5
5
  import '../content-transfer/icon.js';
6
6
  import './copy-types.js';
7
7
  import './table-style.js';
8
- import '../types-CJWU1Gae.js';
8
+ import '../types-JnZD8wM0.js';
9
9
  import './grouping.js';
10
10
  import './fill.js';
11
11
  import './facets.js';
@@ -1,11 +1,11 @@
1
- export { _ as LAYERED_FILTER_OPERATORS, $ as LAYERED_FILTER_OPERATOR_LABELS, a0 as LayeredFilterField, a1 as LayeredFilterOperator, L as LayeredFilterRule, a2 as columnFiltersToLayeredRules, a3 as completeLayeredFilterRules, a4 as decodeLayeredFilterRules, a5 as encodeLayeredFilterRules, a6 as isCompleteLayeredFilterRule, a7 as isLayeredFilterOperator, a8 as layeredFilterMatchesValue, a9 as layeredFilterNeedsValue, aa as layeredFilterRuleSummary, ab as operatorsForLayeredField } from '../types-oVyZbfwn.cjs';
1
+ export { _ as LAYERED_FILTER_OPERATORS, $ as LAYERED_FILTER_OPERATOR_LABELS, a0 as LayeredFilterField, a1 as LayeredFilterOperator, L as LayeredFilterRule, a2 as columnFiltersToLayeredRules, a3 as completeLayeredFilterRules, a4 as decodeLayeredFilterRules, a5 as encodeLayeredFilterRules, a6 as isCompleteLayeredFilterRule, a7 as isLayeredFilterOperator, a8 as layeredFilterMatchesValue, a9 as layeredFilterNeedsValue, aa as layeredFilterRuleSummary, ab as operatorsForLayeredField } from '../types-DNkbHRVK.cjs';
2
2
  import '../content-transfer.cjs';
3
3
  import 'react';
4
4
  import '@ai-matrx/kit/content-transfer';
5
5
  import '../content-transfer/icon.cjs';
6
6
  import './copy-types.cjs';
7
7
  import './table-style.cjs';
8
- import '../types-CJWU1Gae.cjs';
8
+ import '../types-JnZD8wM0.cjs';
9
9
  import './grouping.cjs';
10
10
  import './fill.cjs';
11
11
  import './facets.cjs';
@@ -1,11 +1,11 @@
1
- export { _ as LAYERED_FILTER_OPERATORS, $ as LAYERED_FILTER_OPERATOR_LABELS, a0 as LayeredFilterField, a1 as LayeredFilterOperator, L as LayeredFilterRule, a2 as columnFiltersToLayeredRules, a3 as completeLayeredFilterRules, a4 as decodeLayeredFilterRules, a5 as encodeLayeredFilterRules, a6 as isCompleteLayeredFilterRule, a7 as isLayeredFilterOperator, a8 as layeredFilterMatchesValue, a9 as layeredFilterNeedsValue, aa as layeredFilterRuleSummary, ab as operatorsForLayeredField } from '../types-Z32pxexx.js';
1
+ export { _ as LAYERED_FILTER_OPERATORS, $ as LAYERED_FILTER_OPERATOR_LABELS, a0 as LayeredFilterField, a1 as LayeredFilterOperator, L as LayeredFilterRule, a2 as columnFiltersToLayeredRules, a3 as completeLayeredFilterRules, a4 as decodeLayeredFilterRules, a5 as encodeLayeredFilterRules, a6 as isCompleteLayeredFilterRule, a7 as isLayeredFilterOperator, a8 as layeredFilterMatchesValue, a9 as layeredFilterNeedsValue, aa as layeredFilterRuleSummary, ab as operatorsForLayeredField } from '../types-Dx5hJgCi.js';
2
2
  import '../content-transfer.js';
3
3
  import 'react';
4
4
  import '@ai-matrx/kit/content-transfer';
5
5
  import '../content-transfer/icon.js';
6
6
  import './copy-types.js';
7
7
  import './table-style.js';
8
- import '../types-CJWU1Gae.js';
8
+ import '../types-JnZD8wM0.js';
9
9
  import './grouping.js';
10
10
  import './fill.js';
11
11
  import './facets.js';
@@ -1,12 +1,12 @@
1
1
  import { ResolvedFilterKind } from './infer-filter.cjs';
2
- import { e as MatrxDataTableQueryState, M as MatrxColumnDef } from '../types-oVyZbfwn.cjs';
2
+ import { e as MatrxDataTableQueryState, M as MatrxColumnDef } from '../types-DNkbHRVK.cjs';
3
3
  import '../content-transfer.cjs';
4
4
  import 'react';
5
5
  import '@ai-matrx/kit/content-transfer';
6
6
  import '../content-transfer/icon.cjs';
7
7
  import './copy-types.cjs';
8
8
  import './table-style.cjs';
9
- import '../types-CJWU1Gae.cjs';
9
+ import '../types-JnZD8wM0.cjs';
10
10
  import './grouping.cjs';
11
11
  import './fill.cjs';
12
12
  import './facets.cjs';
@@ -1,12 +1,12 @@
1
1
  import { ResolvedFilterKind } from './infer-filter.js';
2
- import { e as MatrxDataTableQueryState, M as MatrxColumnDef } from '../types-Z32pxexx.js';
2
+ import { e as MatrxDataTableQueryState, M as MatrxColumnDef } from '../types-Dx5hJgCi.js';
3
3
  import '../content-transfer.js';
4
4
  import 'react';
5
5
  import '@ai-matrx/kit/content-transfer';
6
6
  import '../content-transfer/icon.js';
7
7
  import './copy-types.js';
8
8
  import './table-style.js';
9
- import '../types-CJWU1Gae.js';
9
+ import '../types-JnZD8wM0.js';
10
10
  import './grouping.js';
11
11
  import './fill.js';
12
12
  import './facets.js';
@@ -1,9 +1,9 @@
1
1
  import '../content-transfer.cjs';
2
2
  import 'react';
3
- export { A as AnyOfColumnSearch, k as CellEditType, l as CellEditsMap, f as ColumnFilterKind, a as ColumnFilterValue, C as ColumnFiltersState, j as ColumnMarker, M as MatrxColumnDef, m as MatrxDataTableContextMenuConfig, g as MatrxDataTableCopyConfig, n as MatrxDataTableCoverageConfig, c as MatrxDataTableDensity, o as MatrxDataTableDetailConfig, p as MatrxDataTableEditConfig, q as MatrxDataTableEmptyState, r as MatrxDataTableExpandedDetailConfig, s as MatrxDataTableFacetsConfig, t as MatrxDataTableFilterUi, u as MatrxDataTableGroupingConfig, v as MatrxDataTableHierarchyConfig, w as MatrxDataTableHierarchyMove, x as MatrxDataTableMobileCardControls, y as MatrxDataTableMultiExpandedDetailConfig, h as MatrxDataTableProps, z as MatrxDataTableQueryControl, e as MatrxDataTableQueryState, d as MatrxDataTableRecordControls, B as MatrxDataTableSelectionConfig, D as MatrxDataTableSingleExpandedDetailConfig, E as MatrxDataTableSourceProcessing, F as MatrxDataTableSpreadsheetConfig, G as MatrxDataTableStyleConfig, H as MatrxDataTableToolbar, I as MatrxDataTableUrlStateConfig, J as MatrxDataTableVirtualizeConfig, K as MatrxDataTableWindowConfig, N as MatrxTablePagination, O as SortDirection, S as SortState, b as TableSavedViewsProps, T as TableSearchMatchMode, U as TableViewQuery, i as TableViewSnapshot, V as TextFilterMode, W as ToolbarFacet } from '../types-oVyZbfwn.cjs';
3
+ export { A as AnyOfColumnSearch, k as CellEditType, l as CellEditsMap, f as ColumnFilterKind, a as ColumnFilterValue, C as ColumnFiltersState, j as ColumnMarker, M as MatrxColumnDef, m as MatrxDataTableContextMenuConfig, g as MatrxDataTableCopyConfig, n as MatrxDataTableCoverageConfig, c as MatrxDataTableDensity, o as MatrxDataTableDetailConfig, p as MatrxDataTableEditConfig, q as MatrxDataTableEmptyState, r as MatrxDataTableExpandedDetailConfig, s as MatrxDataTableFacetsConfig, t as MatrxDataTableFilterUi, u as MatrxDataTableGroupingConfig, v as MatrxDataTableHierarchyConfig, w as MatrxDataTableHierarchyMove, x as MatrxDataTableMobileCardControls, y as MatrxDataTableMultiExpandedDetailConfig, h as MatrxDataTableProps, z as MatrxDataTableQueryControl, e as MatrxDataTableQueryState, d as MatrxDataTableRecordControls, B as MatrxDataTableSelectionConfig, D as MatrxDataTableSingleExpandedDetailConfig, E as MatrxDataTableSourceProcessing, F as MatrxDataTableSpreadsheetConfig, G as MatrxDataTableStyleConfig, H as MatrxDataTableToolbar, I as MatrxDataTableUrlStateConfig, J as MatrxDataTableVirtualizeConfig, K as MatrxDataTableWindowConfig, N as MatrxTablePagination, O as SortDirection, S as SortState, b as TableSavedViewsProps, T as TableSearchMatchMode, U as TableViewQuery, i as TableViewSnapshot, V as TextFilterMode, W as ToolbarFacet } from '../types-DNkbHRVK.cjs';
4
4
  export { AgentPayloadInput } from './copy-types.cjs';
5
5
  import './table-style.cjs';
6
- import '../types-CJWU1Gae.cjs';
6
+ import '../types-JnZD8wM0.cjs';
7
7
  import './grouping.cjs';
8
8
  import './fill.cjs';
9
9
  import './facets.cjs';
@@ -1,9 +1,9 @@
1
1
  import '../content-transfer.js';
2
2
  import 'react';
3
- export { A as AnyOfColumnSearch, k as CellEditType, l as CellEditsMap, f as ColumnFilterKind, a as ColumnFilterValue, C as ColumnFiltersState, j as ColumnMarker, M as MatrxColumnDef, m as MatrxDataTableContextMenuConfig, g as MatrxDataTableCopyConfig, n as MatrxDataTableCoverageConfig, c as MatrxDataTableDensity, o as MatrxDataTableDetailConfig, p as MatrxDataTableEditConfig, q as MatrxDataTableEmptyState, r as MatrxDataTableExpandedDetailConfig, s as MatrxDataTableFacetsConfig, t as MatrxDataTableFilterUi, u as MatrxDataTableGroupingConfig, v as MatrxDataTableHierarchyConfig, w as MatrxDataTableHierarchyMove, x as MatrxDataTableMobileCardControls, y as MatrxDataTableMultiExpandedDetailConfig, h as MatrxDataTableProps, z as MatrxDataTableQueryControl, e as MatrxDataTableQueryState, d as MatrxDataTableRecordControls, B as MatrxDataTableSelectionConfig, D as MatrxDataTableSingleExpandedDetailConfig, E as MatrxDataTableSourceProcessing, F as MatrxDataTableSpreadsheetConfig, G as MatrxDataTableStyleConfig, H as MatrxDataTableToolbar, I as MatrxDataTableUrlStateConfig, J as MatrxDataTableVirtualizeConfig, K as MatrxDataTableWindowConfig, N as MatrxTablePagination, O as SortDirection, S as SortState, b as TableSavedViewsProps, T as TableSearchMatchMode, U as TableViewQuery, i as TableViewSnapshot, V as TextFilterMode, W as ToolbarFacet } from '../types-Z32pxexx.js';
3
+ export { A as AnyOfColumnSearch, k as CellEditType, l as CellEditsMap, f as ColumnFilterKind, a as ColumnFilterValue, C as ColumnFiltersState, j as ColumnMarker, M as MatrxColumnDef, m as MatrxDataTableContextMenuConfig, g as MatrxDataTableCopyConfig, n as MatrxDataTableCoverageConfig, c as MatrxDataTableDensity, o as MatrxDataTableDetailConfig, p as MatrxDataTableEditConfig, q as MatrxDataTableEmptyState, r as MatrxDataTableExpandedDetailConfig, s as MatrxDataTableFacetsConfig, t as MatrxDataTableFilterUi, u as MatrxDataTableGroupingConfig, v as MatrxDataTableHierarchyConfig, w as MatrxDataTableHierarchyMove, x as MatrxDataTableMobileCardControls, y as MatrxDataTableMultiExpandedDetailConfig, h as MatrxDataTableProps, z as MatrxDataTableQueryControl, e as MatrxDataTableQueryState, d as MatrxDataTableRecordControls, B as MatrxDataTableSelectionConfig, D as MatrxDataTableSingleExpandedDetailConfig, E as MatrxDataTableSourceProcessing, F as MatrxDataTableSpreadsheetConfig, G as MatrxDataTableStyleConfig, H as MatrxDataTableToolbar, I as MatrxDataTableUrlStateConfig, J as MatrxDataTableVirtualizeConfig, K as MatrxDataTableWindowConfig, N as MatrxTablePagination, O as SortDirection, S as SortState, b as TableSavedViewsProps, T as TableSearchMatchMode, U as TableViewQuery, i as TableViewSnapshot, V as TextFilterMode, W as ToolbarFacet } from '../types-Dx5hJgCi.js';
4
4
  export { AgentPayloadInput } from './copy-types.js';
5
5
  import './table-style.js';
6
- import '../types-CJWU1Gae.js';
6
+ import '../types-JnZD8wM0.js';
7
7
  import './grouping.js';
8
8
  import './fill.js';
9
9
  import './facets.js';
@@ -1,4 +1,4 @@
1
- import { S as SortState, e as MatrxDataTableQueryState } from '../types-oVyZbfwn.cjs';
1
+ import { S as SortState, e as MatrxDataTableQueryState } from '../types-DNkbHRVK.cjs';
2
2
  import { UrlHistoryMode } from '@ai-matrx/kit/url-state';
3
3
  import '../content-transfer.cjs';
4
4
  import 'react';
@@ -6,7 +6,7 @@ import '@ai-matrx/kit/content-transfer';
6
6
  import '../content-transfer/icon.cjs';
7
7
  import './copy-types.cjs';
8
8
  import './table-style.cjs';
9
- import '../types-CJWU1Gae.cjs';
9
+ import '../types-JnZD8wM0.cjs';
10
10
  import './grouping.cjs';
11
11
  import './fill.cjs';
12
12
  import './facets.cjs';
@@ -1,4 +1,4 @@
1
- import { S as SortState, e as MatrxDataTableQueryState } from '../types-Z32pxexx.js';
1
+ import { S as SortState, e as MatrxDataTableQueryState } from '../types-Dx5hJgCi.js';
2
2
  import { UrlHistoryMode } from '@ai-matrx/kit/url-state';
3
3
  import '../content-transfer.js';
4
4
  import 'react';
@@ -6,7 +6,7 @@ import '@ai-matrx/kit/content-transfer';
6
6
  import '../content-transfer/icon.js';
7
7
  import './copy-types.js';
8
8
  import './table-style.js';
9
- import '../types-CJWU1Gae.js';
9
+ import '../types-JnZD8wM0.js';
10
10
  import './grouping.js';
11
11
  import './fill.js';
12
12
  import './facets.js';
@@ -1,4 +1,4 @@
1
- import { F as FieldFormatConfig } from '../types-CJWU1Gae.cjs';
1
+ import { F as FieldFormatConfig } from '../types-JnZD8wM0.cjs';
2
2
 
3
3
  /**
4
4
  * Column validation rules for user data tables — THE one rule model.
@@ -1,4 +1,4 @@
1
- import { F as FieldFormatConfig } from '../types-CJWU1Gae.js';
1
+ import { F as FieldFormatConfig } from '../types-JnZD8wM0.js';
2
2
 
3
3
  /**
4
4
  * Column validation rules for user data tables — THE one rule model.
@@ -1,11 +1,11 @@
1
- import { M as MatrxColumnDef } from '../types-oVyZbfwn.cjs';
1
+ import { M as MatrxColumnDef } from '../types-DNkbHRVK.cjs';
2
2
  import '../content-transfer.cjs';
3
3
  import 'react';
4
4
  import '@ai-matrx/kit/content-transfer';
5
5
  import '../content-transfer/icon.cjs';
6
6
  import './copy-types.cjs';
7
7
  import './table-style.cjs';
8
- import '../types-CJWU1Gae.cjs';
8
+ import '../types-JnZD8wM0.cjs';
9
9
  import './grouping.cjs';
10
10
  import './fill.cjs';
11
11
  import './facets.cjs';
@@ -1,11 +1,11 @@
1
- import { M as MatrxColumnDef } from '../types-Z32pxexx.js';
1
+ import { M as MatrxColumnDef } from '../types-Dx5hJgCi.js';
2
2
  import '../content-transfer.js';
3
3
  import 'react';
4
4
  import '@ai-matrx/kit/content-transfer';
5
5
  import '../content-transfer/icon.js';
6
6
  import './copy-types.js';
7
7
  import './table-style.js';
8
- import '../types-CJWU1Gae.js';
8
+ import '../types-JnZD8wM0.js';
9
9
  import './grouping.js';
10
10
  import './fill.js';
11
11
  import './facets.js';
@@ -57,6 +57,35 @@ function toText(value) {
57
57
  return String(value);
58
58
  return null;
59
59
  }
60
+ function parseTimeOfDay(value) {
61
+ if (value instanceof Date) {
62
+ return { h: value.getHours(), m: value.getMinutes(), s: value.getSeconds() };
63
+ }
64
+ if (typeof value !== "string") return null;
65
+ const text = value.trim();
66
+ if (!text) return null;
67
+ const m = /^(\d{1,2})(?::(\d{2}))?(?::(\d{2}))?\s*([aApP]\.?[mM]\.?)?$/.exec(text);
68
+ if (m) {
69
+ let h = Number(m[1]);
70
+ const min = m[2] ? Number(m[2]) : 0;
71
+ const sec = m[3] ? Number(m[3]) : 0;
72
+ const ampm = m[4]?.toLowerCase().replace(/\./g, "");
73
+ if (ampm) {
74
+ if (h < 1 || h > 12) return null;
75
+ if (ampm === "pm" && h !== 12) h += 12;
76
+ if (ampm === "am" && h === 12) h = 0;
77
+ }
78
+ if (h > 23 || min > 59 || sec > 59) return null;
79
+ return { h, m: min, s: sec };
80
+ }
81
+ if (/\d{4}-\d{2}-\d{2}T/.test(text)) {
82
+ const d = new Date(text);
83
+ if (!Number.isNaN(d.getTime())) {
84
+ return { h: d.getHours(), m: d.getMinutes(), s: d.getSeconds() };
85
+ }
86
+ }
87
+ return null;
88
+ }
60
89
  var BARE_CALENDAR_DATE = /^(\d{4})-(\d{2})-(\d{2})(?:[T ]00:00(?::00(?:\.0+)?)?)?$/;
61
90
  function toDate(value) {
62
91
  if (value instanceof Date) return Number.isNaN(value.getTime()) ? null : value;
@@ -177,6 +206,23 @@ var DEFS = [
177
206
  },
178
207
  parse: (raw) => raw === "" || raw == null ? null : String(raw).trim()
179
208
  },
209
+ {
210
+ // A postal address. Free text by design (addresses have no one shape
211
+ // worldwide); the cell opens it in maps, which is the thing people do
212
+ // with an address in a table.
213
+ id: "address",
214
+ label: "Address",
215
+ description: "Street address \u2014 click to open in maps",
216
+ group: "Text",
217
+ base: "string",
218
+ editor: "text",
219
+ rich: true,
220
+ format: (v) => {
221
+ const t = toText(v)?.trim();
222
+ return t ? t : null;
223
+ },
224
+ parse: (raw) => raw === "" || raw == null ? null : String(raw)
225
+ },
180
226
  {
181
227
  id: "url",
182
228
  label: "Link",
@@ -310,6 +356,26 @@ var DEFS = [
310
356
  },
311
357
  parse: (raw) => toNumber(raw)
312
358
  },
359
+ {
360
+ // A percentage DRAWN as a bar — task completion, quota used, a score out of
361
+ // 100. Same storage and scale rule as `percent`; only the rendering differs.
362
+ id: "progress",
363
+ label: "Progress bar",
364
+ description: "A percentage shown as a bar",
365
+ group: "Numbers",
366
+ base: "number",
367
+ alsoAccepts: ["integer"],
368
+ editor: "number",
369
+ rich: true,
370
+ optionKeys: ["percentScale"],
371
+ format: (v, o) => {
372
+ const n = toNumber(v);
373
+ if (n === null) return null;
374
+ const shown = o.percentScale === "fraction" ? n * 100 : n;
375
+ return `${groupedNumber(shown, { precision: 0 })}%`;
376
+ },
377
+ parse: (raw) => toNumber(raw)
378
+ },
313
379
  {
314
380
  id: "duration",
315
381
  label: "Duration",
@@ -378,13 +444,16 @@ var DEFS = [
378
444
  alsoAccepts: ["number"],
379
445
  editor: "number",
380
446
  numericAlign: true,
447
+ // The name says BYTES on purpose: this cell holds a genuine byte length,
448
+ // never a character or item count, and `formatFileSize` is only honest
449
+ // about a quantity that is actually bytes.
381
450
  format: (v) => {
382
- const n = toNumber(v);
383
- return n === null ? null : (0, import_format.formatFileSize)(n);
451
+ const byteLength = toNumber(v);
452
+ return byteLength === null ? null : (0, import_format.formatFileSize)(byteLength);
384
453
  },
385
454
  parse: (raw) => {
386
- const n = toNumber(raw);
387
- return n === null ? null : Math.trunc(n);
455
+ const byteLength = toNumber(raw);
456
+ return byteLength === null ? null : Math.trunc(byteLength);
388
457
  }
389
458
  },
390
459
  // ── Choice ────────────────────────────────────────────────────────────────
@@ -445,6 +514,87 @@ var DEFS = [
445
514
  },
446
515
  parse: (raw) => raw === "" || raw == null ? null : String(raw)
447
516
  },
517
+ {
518
+ // A TIME OF DAY with no date: opening hours, a shift start, a meeting slot.
519
+ // Stored as the string the <input type="time"> gives ("HH:MM" or
520
+ // "HH:MM:SS"), shown in the viewer's locale ("2:30 PM" / "14:30"). The
521
+ // storage type stays `string`; sorting is lexical on the 24-hour form,
522
+ // which is chronological — the one reason the stored form is 24-hour.
523
+ id: "time",
524
+ label: "Time",
525
+ description: "Time of day, without a date",
526
+ group: "Dates",
527
+ base: "string",
528
+ editor: "time",
529
+ optionKeys: ["timeSeconds"],
530
+ format: (v, o) => {
531
+ const parts = parseTimeOfDay(v);
532
+ if (!parts) return null;
533
+ const d = new Date(2e3, 0, 1, parts.h, parts.m, parts.s);
534
+ return d.toLocaleTimeString(void 0, {
535
+ hour: "numeric",
536
+ minute: "2-digit",
537
+ ...o.timeSeconds ? { second: "2-digit" } : {}
538
+ });
539
+ },
540
+ // Normalise to the 24-hour "HH:MM[:SS]" form; a value that is not a time
541
+ // is handed back unchanged so the validation layer can refuse it by name.
542
+ parse: (raw) => {
543
+ if (raw == null || raw === "") return null;
544
+ const parts = parseTimeOfDay(raw);
545
+ if (!parts) return raw;
546
+ const two = (n) => String(n).padStart(2, "0");
547
+ const fields = parts.s > 0 ? [parts.h, parts.m, parts.s] : [parts.h, parts.m];
548
+ return fields.map(two).join(":");
549
+ }
550
+ },
551
+ {
552
+ // Assigned BY THE DATABASE when the row is inserted (trigger
553
+ // `_udt_autonumber`), so it is the same number whichever door made the row
554
+ // and never shifts when another row is deleted. Stored in the cell as an
555
+ // integer; every editor refuses it. `prefix` turns 42 into "INV-42".
556
+ id: "autonumber",
557
+ label: "Autonumber",
558
+ description: "A number the table assigns to each new row \u2014 never typed",
559
+ group: "Numbers",
560
+ base: "integer",
561
+ alsoAccepts: ["number"],
562
+ editor: "computed",
563
+ numericAlign: true,
564
+ optionKeys: ["prefix"],
565
+ format: (v, o) => {
566
+ const n = toNumber(v);
567
+ if (n === null) return null;
568
+ return `${o.prefix ?? ""}${Math.trunc(n)}`;
569
+ },
570
+ parse: () => null
571
+ },
572
+ // ── System columns ────────────────────────────────────────────────────────
573
+ // Filled from the ROW'S OWN RECORD on read (`withComputedColumns` in
574
+ // `@ai-matrx/design-system/formulas`), never typed and never stored in the
575
+ // cell. `editor: "computed"` makes every editor refuse them.
576
+ {
577
+ id: "created_time",
578
+ label: "Created time",
579
+ description: "When the row was added \u2014 filled in automatically",
580
+ group: "Dates",
581
+ base: "string",
582
+ editor: "computed",
583
+ optionKeys: ["dateStyle"],
584
+ format: (v, o) => FIELD_FORMATS.datetime.format(v, o),
585
+ parse: () => null
586
+ },
587
+ {
588
+ id: "modified_time",
589
+ label: "Last modified time",
590
+ description: "When the row last changed \u2014 filled in automatically",
591
+ group: "Dates",
592
+ base: "string",
593
+ editor: "computed",
594
+ optionKeys: ["dateStyle"],
595
+ format: (v, o) => FIELD_FORMATS.datetime.format(v, o),
596
+ parse: () => null
597
+ },
448
598
  {
449
599
  id: "relative_time",
450
600
  label: "Relative time",
@@ -501,6 +651,44 @@ var DEFS = [
501
651
  return toList(raw) ?? raw;
502
652
  }
503
653
  },
654
+ {
655
+ // FILES ATTACHED TO THE ROW. The cell stores the files feature's file ids
656
+ // (`files.files.id`), never a URL or a name: a rename or a move in Files
657
+ // changes nothing here, and access is the file's own (RLS) — a reader who
658
+ // may see the row but not the file gets the chip's honest "no access", not
659
+ // a broken link. Drawn by `AttachmentChips`, edited by `AttachmentInput`
660
+ // through the ONE file picker.
661
+ id: "attachment",
662
+ label: "Attachments",
663
+ description: "Files from your Files, shown as chips",
664
+ group: "Structured",
665
+ base: "array",
666
+ // Not `string`: on a text column it must appear under "Other kinds" so
667
+ // picking it retypes the column to a list, rather than storing a JSON
668
+ // string of ids in a text cell.
669
+ alsoAccepts: ["json"],
670
+ editor: "attachment",
671
+ rich: true,
672
+ format: (v) => {
673
+ const list = toList(v);
674
+ if (list === null) return null;
675
+ const n = list.filter((i) => String(i).trim()).length;
676
+ return n === 0 ? "" : n === 1 ? "1 file" : `${n} files`;
677
+ },
678
+ parse: (raw) => {
679
+ if (raw == null || raw === "") return null;
680
+ if (Array.isArray(raw)) return raw.map((i) => String(i).trim()).filter(Boolean);
681
+ const text = String(raw).trim();
682
+ if (text.startsWith("[")) {
683
+ try {
684
+ const parsed = JSON.parse(text);
685
+ if (Array.isArray(parsed)) return parsed.map((i) => String(i).trim()).filter(Boolean);
686
+ } catch {
687
+ }
688
+ }
689
+ return text.split(",").map((s) => s.trim()).filter(Boolean);
690
+ }
691
+ },
504
692
  {
505
693
  id: "tags",
506
694
  label: "Tags",
@@ -564,6 +752,82 @@ var DEFS = [
564
752
  return trimmed === "" ? null : trimmed;
565
753
  }
566
754
  },
755
+ {
756
+ // A PERSON: one member of the organization the table belongs to, stored as
757
+ // the user id. It is a choice column whose options are the members —
758
+ // supplied at runtime by whoever renders it (features/data-tables/
759
+ // person-choices.tsx), the same door a structured-list-bound column uses —
760
+ // so the cell picker, the chip, filters, color-by and the agent scope are
761
+ // all the choice system's, with no second implementation.
762
+ id: "person",
763
+ label: "Person",
764
+ description: "Someone in your organization \u2014 pick from its members",
765
+ group: "Choice",
766
+ base: "string",
767
+ editor: "select",
768
+ rich: true,
769
+ format: (v, o) => FIELD_FORMATS.choice.format(v, o),
770
+ parse: (raw) => FIELD_FORMATS.choice.parse(raw, {})
771
+ },
772
+ {
773
+ // A RECORD OF ANOTHER TABLE. The cell stores that record's ID; the screen
774
+ // shows its WORDS. `person` is the precedent and the template — it has
775
+ // stored a user id and displayed a name through `choiceMap` since
776
+ // 2026-09-21 — so `relation` is a member of CHOICE_FORMAT_IDS and every
777
+ // one of the ten readers that print a cell resolves it through the path
778
+ // they already use for `person`. There is no eleventh place to remember.
779
+ //
780
+ // THREE STATES, THREE RENDERINGS, NO FOURTH (OLD-TABLES-CUTOVER §3.3):
781
+ // resolved the target's words
782
+ // unresolvable the amber fallback WITH the id, as an identifier — never
783
+ // a blank, and never the bare uuid as if it were text, so a
784
+ // person can act on it and support can trace it
785
+ // withheld platform.relation_withheld_label(), with NO id — a cell
786
+ // the reader may not see never leaks the identifier through
787
+ // the gap between the two stores' refusals
788
+ //
789
+ // `format` therefore returns null (the fallback law's "cannot interpret")
790
+ // for anything the resolver did not turn into words, and the renderer is
791
+ // what distinguishes unresolvable from withheld. It never prints a bare id.
792
+ id: "relation",
793
+ label: "Relation",
794
+ description: "A record of another table \u2014 pick it, and its name is shown",
795
+ group: "Choice",
796
+ base: "string",
797
+ alsoAccepts: ["array", "json"],
798
+ editor: "select",
799
+ rich: true,
800
+ optionKeys: ["relation_target", "relation_max", "on_delete", "display"],
801
+ // IT DOES NOT DELEGATE TO `choice`, AND THAT IS THE WHOLE POINT.
802
+ // `choice.format` deliberately returns the RAW VALUE when no options have
803
+ // resolved yet — a structured list still loading should not make every cell
804
+ // look off-list. For a label column that is right: the raw value IS the
805
+ // label. For an identifier column it is the defect §3.3 names, and it is
806
+ // how the first cut of this wave put four raw uuids on a real grid: the
807
+ // fallback arm never ran, because returning the uuid counted as SUCCESS.
808
+ //
809
+ // Here, a value that did not resolve to words is a MISMATCH — `null` — so
810
+ // the renderer's three-state arm owns it and shows the amber fallback with
811
+ // the id marked as an identifier, or the withheld sentence. The id never
812
+ // reaches the eye as if it were the cell's contents.
813
+ format: (v, options) => {
814
+ const list = toList(v);
815
+ const values = list !== null ? list : v == null ? [] : [v];
816
+ if (values.length === 0) return "";
817
+ const words = [];
818
+ for (const entry of values) {
819
+ const text = toText(entry);
820
+ if (text === null) return null;
821
+ const trimmed = text.trim();
822
+ if (trimmed === "") continue;
823
+ const match = findChoice(options.choices, trimmed);
824
+ if (!match) return null;
825
+ words.push(match.label ?? match.value);
826
+ }
827
+ return words.length === 0 ? "" : words.join(", ");
828
+ },
829
+ parse: (raw) => FIELD_FORMATS.choice.parse(raw, {})
830
+ },
567
831
  {
568
832
  id: "multi_choice",
569
833
  label: "Multi-choice",
@@ -608,7 +872,7 @@ var DEFS = [
608
872
  // A formula column stores NOTHING. `metadata.format.options.formula` holds
609
873
  // the expression; the stored cell is always null; the value is computed on
610
874
  // read from the other columns of the same row
611
- // (`features/data-tables/formulas.ts`). Grouped under Structured on purpose
875
+ // (`@ai-matrx/design-system/formulas`). Grouped under Structured on purpose
612
876
  // — the picker's groups are a fixed vocabulary, and a formula is structure
613
877
  // over a plain string column, not a sixth family.
614
878
  //