@ai-matrx/records-ui 0.93.2 → 0.93.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -4349,7 +4349,20 @@ function useGridEditing({ tableId, fields, rows, reload, canWrite, mayWriteRow,
4349
4349
  }
4350
4350
  return null;
4351
4351
  }, [client, tableId, reload, order]);
4352
+ const rowSignature = (0, import_react22.useCallback)(
4353
+ (rowId) => {
4354
+ const out = [];
4355
+ if (editing?.rowId === rowId) out.push("open", editing.key, draft);
4356
+ const prefix = `${rowId}::`;
4357
+ for (const id in optimistic) if (id.startsWith(prefix)) out.push("held", id, optimistic[id]);
4358
+ for (const id in saving) if (id.startsWith(prefix)) out.push("saving", id);
4359
+ for (const id in refusals) if (id.startsWith(prefix)) out.push("refused", id, refusals[id]);
4360
+ return out;
4361
+ },
4362
+ [editing, draft, optimistic, saving, refusals]
4363
+ );
4352
4364
  return {
4365
+ rowSignature,
4353
4366
  valueFor,
4354
4367
  editing,
4355
4368
  draft,
@@ -8202,11 +8215,12 @@ function placePinnedRows(pageRows, pinned, anchors) {
8202
8215
  }
8203
8216
  function withAddRowCells(columns, line) {
8204
8217
  if (line === null) return columns;
8218
+ const draw = () => typeof line === "function" ? line() : line;
8205
8219
  return columns.map((column, index) => {
8206
8220
  const own2 = column.cell;
8207
8221
  return {
8208
8222
  ...column,
8209
- cell: (row, rowIndex) => row.id === ADD_ROW_ID ? index === 0 ? line : null : own2 ? own2(row, rowIndex) : null
8223
+ cell: (row, rowIndex) => row.id === ADD_ROW_ID ? index === 0 ? draw() : null : own2 ? own2(row, rowIndex) : null
8210
8224
  };
8211
8225
  });
8212
8226
  }
@@ -8229,6 +8243,7 @@ function AddRowLine({ onAdd, busy }) {
8229
8243
  }
8230
8244
  );
8231
8245
  }
8246
+ var drawNothing = () => null;
8232
8247
  function addColumnColumn(onAdd) {
8233
8248
  return {
8234
8249
  id: ADD_COLUMN_ID,
@@ -8248,7 +8263,8 @@ function addColumnColumn(onAdd) {
8248
8263
  children: "+"
8249
8264
  }
8250
8265
  ),
8251
- cell: () => null,
8266
+ // ONE function for the life of the module: a body cell that draws nothing never changes.
8267
+ cell: drawNothing,
8252
8268
  sortable: false,
8253
8269
  filter: false,
8254
8270
  hideable: false,
@@ -10836,6 +10852,8 @@ function HandOrderDialog({
10836
10852
  var import_jsx_runtime42 = require("react/jsx-runtime");
10837
10853
  var NO_COLUMNS_YET = "This table has no columns yet";
10838
10854
  var NO_COLUMNS_WHY = "A column is what a record holds \u2014 a name, a date, an amount, a person. Add the first one and the grid appears with it; everything else on this page works the moment it exists.";
10855
+ var NO_SUMMARIES = Object.freeze({});
10856
+ var rowIdOf = (row) => row.id;
10839
10857
  function Grid({
10840
10858
  tableId,
10841
10859
  pageSize = 50,
@@ -10985,6 +11003,15 @@ function Grid({
10985
11003
  onEnded: (exit, from, how) => sheetController.current?.endEdit(exit, { rowId: from.rowId, columnId: from.key }, how)
10986
11004
  } : {}
10987
11005
  });
11006
+ const editingNow = (0, import_react60.useRef)(editing);
11007
+ editingNow.current = editing;
11008
+ const editingHandle = (0, import_react60.useMemo)(
11009
+ () => new Proxy({}, {
11010
+ get: (_target, key) => editingNow.current[key]
11011
+ }),
11012
+ []
11013
+ );
11014
+ const rowVersion = (0, import_react60.useCallback)((row) => editingNow.current.rowSignature(row.id), []);
10988
11015
  const undo = useGridUndo({ tableId, reload: records.reload, forget: editing.forget });
10989
11016
  pushWritten.current = (write) => {
10990
11017
  const field2 = (fields.data ?? []).find((f) => f.key === write.key);
@@ -11055,7 +11082,7 @@ function Grid({
11055
11082
  const [selectedIds, setSelectedIds] = (0, import_react60.useState)([]);
11056
11083
  const offerSelection = canWrite && (merged || tableActions.runnable.length > 0);
11057
11084
  const [reordering, setReordering] = (0, import_react60.useState)(false);
11058
- const chosenSummaries = localSummaries ?? presentation.summaries ?? {};
11085
+ const chosenSummaries = localSummaries ?? presentation.summaries ?? NO_SUMMARIES;
11059
11086
  const summaries = useColumnSummaries({ tableId, chosen: chosenSummaries, filter: question.filter, version: records.data });
11060
11087
  const [duplicated, setDuplicated] = (0, import_react60.useState)(null);
11061
11088
  const duplicate = (0, import_react60.useCallback)(
@@ -11504,7 +11531,7 @@ function Grid({
11504
11531
  () => ordered.map(
11505
11532
  (field2) => columnForField(
11506
11533
  field2,
11507
- canWrite ? editing : null,
11534
+ canWrite ? editingHandle : null,
11508
11535
  mayWriteRow,
11509
11536
  whyNotRow,
11510
11537
  {
@@ -11523,7 +11550,7 @@ function Grid({
11523
11550
  [
11524
11551
  ordered,
11525
11552
  canWrite,
11526
- editing,
11553
+ editingHandle,
11527
11554
  mayWriteRow,
11528
11555
  whyNotRow,
11529
11556
  presentation.formats,
@@ -11535,9 +11562,34 @@ function Grid({
11535
11562
  pinCell
11536
11563
  ]
11537
11564
  );
11538
- const columns = (0, import_react60.useMemo)(
11539
- () => {
11540
- const drawn = withHeaderMenus(withAddRowCells(withSummaryCells(
11565
+ const footerNow = (0, import_react60.useRef)({
11566
+ summaryCell: () => null,
11567
+ addLine: () => null
11568
+ });
11569
+ footerNow.current = {
11570
+ summaryCell: (columnId) => {
11571
+ const field2 = ordered.find((f) => f.key === columnId);
11572
+ if (!field2) return null;
11573
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
11574
+ SummaryCell,
11575
+ {
11576
+ field: field2,
11577
+ firstColumn: ordered[0]?.key === columnId,
11578
+ chosen: chosenSummaries[columnId],
11579
+ value: summaries.values[columnId],
11580
+ rowCount: summaries.rowCount,
11581
+ summaries,
11582
+ onChoose: (op2) => chooseSummary(columnId, op2)
11583
+ }
11584
+ );
11585
+ },
11586
+ addLine: () => /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(AddRowLine, { onAdd: () => void addRowHere(), busy: added.busy })
11587
+ };
11588
+ const addColumnNow = (0, import_react60.useRef)(controls.addColumn);
11589
+ addColumnNow.current = controls.addColumn;
11590
+ const bodyColumns = (0, import_react60.useMemo)(
11591
+ () => withAddRowCells(
11592
+ withSummaryCells(
11541
11593
  // THE ONE WAY A ROW OPENS ITS RECORD (VERIFIER-17): an Open control on the first cell,
11542
11594
  // and Space on any cell. Absent when the host cannot open a record.
11543
11595
  withOpenRecord(
@@ -11547,26 +11599,111 @@ function Grid({
11547
11599
  // The merged grid's handle sits at the START of the row, where Airtable's expand sits.
11548
11600
  merged ? "start" : "end"
11549
11601
  ),
11550
- (columnId) => {
11551
- const field2 = ordered.find((f) => f.key === columnId);
11552
- if (!field2) return null;
11553
- return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
11554
- SummaryCell,
11555
- {
11556
- field: field2,
11557
- firstColumn: ordered[0]?.key === columnId,
11558
- chosen: chosenSummaries[columnId],
11559
- value: summaries.values[columnId],
11560
- rowCount: summaries.rowCount,
11561
- summaries,
11562
- onChoose: (op2) => chooseSummary(columnId, op2)
11563
- }
11564
- );
11602
+ (columnId) => footerNow.current.summaryCell(columnId)
11603
+ ),
11604
+ mayAddRow ? () => footerNow.current.addLine() : null
11605
+ ),
11606
+ [fieldColumns, onOpenRecord, table.data, merged, mayAddRow]
11607
+ );
11608
+ const isRowSelectable = (0, import_react60.useCallback)((row) => row.id !== SUMMARY_ROW.id && mayWriteRow(row.id), [mayWriteRow]);
11609
+ const copyConfig = (0, import_react60.useMemo)(
11610
+ () => table.data ? gridCopyConfig({
11611
+ tableId,
11612
+ tableName: tableName(table.data),
11613
+ fields: ordered,
11614
+ rowLabel: (row) => recordNameIn(table.data, row.document ?? {})
11615
+ }) : null,
11616
+ [tableId, table.data, ordered]
11617
+ );
11618
+ const tableStyleProp = (0, import_react60.useMemo)(
11619
+ () => (0, import_data_table9.tableStyleIsEmpty)(paint.style) ? null : {
11620
+ style: paint.style,
11621
+ // A choice is read as its OPTION (`paintByOption`): the rule, the value and the
11622
+ // colour a column keeps for it all name the same option, however it is stored.
11623
+ documentOf: (row) => paint.documentOf(row.document ?? {}),
11624
+ // A value its column keeps a colour for wears THAT colour (`choiceLooks.ts`);
11625
+ // any other value still paints from its word.
11626
+ choiceColorFor: paint.choiceColorFor
11627
+ },
11628
+ [paint]
11629
+ );
11630
+ const rowActionsNow = (0, import_react60.useRef)({ runner, handToAgent, host, table: table.data, duplicate });
11631
+ rowActionsNow.current = { runner, handToAgent, host, table: table.data, duplicate };
11632
+ const offersRowActions = canWrite || Boolean(host.talkToRecord) || Boolean(host.runAgentAction && tableActions.agent.length > 0);
11633
+ const hasTalk = Boolean(host.talkToRecord);
11634
+ const hasAgent = Boolean(host.runAgentAction);
11635
+ const rowActions = (0, import_react60.useCallback)(
11636
+ (row) => /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(import_jsx_runtime42.Fragment, { children: [
11637
+ canWrite && mayWriteRow(row.id) ? tableActions.runnable.map((action) => /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
11638
+ ActionButton,
11639
+ {
11640
+ action,
11641
+ busy: runner.busy === action.id,
11642
+ onPress: () => rowActionsNow.current.runner.press(action, [row.id])
11643
+ },
11644
+ action.id
11645
+ )) : null,
11646
+ host.runAgentAction ? tableActions.agent.map((action) => /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
11647
+ ActionButton,
11648
+ {
11649
+ action,
11650
+ busy: false,
11651
+ onPress: () => rowActionsNow.current.handToAgent(action, row)
11652
+ },
11653
+ action.id
11654
+ )) : null,
11655
+ host.talkToRecord ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
11656
+ import_design_system35.Button,
11657
+ {
11658
+ size: "sm",
11659
+ variant: "ghost",
11660
+ onClick: () => rowActionsNow.current.host.talkToRecord?.({
11661
+ tableId,
11662
+ recordId: row.id,
11663
+ // ONE NAMING CALL (`names.ts`), not this file's own join
11664
+ // of a Table's title column to a document.
11665
+ title: recordNameIn(
11666
+ rowActionsNow.current.table,
11667
+ row.document ?? {}
11668
+ )
11669
+ }),
11670
+ children: "Talk"
11671
+ }
11672
+ ) : null,
11673
+ Boolean(editable) && rights.write ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
11674
+ import_design_system35.Button,
11675
+ {
11676
+ size: "sm",
11677
+ variant: "ghost",
11678
+ "data-records-duplicate": row.id,
11679
+ title: "Duplicate this record",
11680
+ onClick: (event) => {
11681
+ event.stopPropagation();
11682
+ void rowActionsNow.current.duplicate(row);
11683
+ },
11684
+ children: "Duplicate"
11685
+ }
11686
+ ) : null,
11687
+ canWrite && mayWriteRow(row.id) ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
11688
+ import_design_system35.Button,
11689
+ {
11690
+ size: "sm",
11691
+ variant: "ghost",
11692
+ title: "Delete this record",
11693
+ onClick: () => setDeleting(row),
11694
+ children: "Delete"
11565
11695
  }
11566
- ), mayAddRow ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(AddRowLine, { onAdd: () => void addRowHere(), busy: added.busy }) : null), controls.headerMenuFor, controls.filterFor);
11567
- return merged && rights.structure && editable ? [...drawn, addColumnColumn(controls.addColumn)] : drawn;
11696
+ ) : null
11697
+ ] }),
11698
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- `hasTalk`/`hasAgent` stand for the host ports the JSX reads; handlers run through `rowActionsNow`.
11699
+ [canWrite, mayWriteRow, tableActions.runnable, tableActions.agent, runner.busy, hasTalk, hasAgent, editable, rights.write]
11700
+ );
11701
+ const columns = (0, import_react60.useMemo)(
11702
+ () => {
11703
+ const drawn = withHeaderMenus(bodyColumns, controls.headerMenuFor, controls.filterFor);
11704
+ return merged && rights.structure && editable ? [...drawn, addColumnColumn(() => addColumnNow.current())] : drawn;
11568
11705
  },
11569
- [fieldColumns, onOpenRecord, table.data, ordered, chosenSummaries, summaries, chooseSummary, controls.headerMenuFor, controls.filterFor, mayAddRow, addRowHere, added.busy, merged, rights.structure, editable, controls.addColumn]
11706
+ [bodyColumns, controls.headerMenuFor, controls.filterFor, merged, rights.structure, editable]
11570
11707
  );
11571
11708
  const [localColumns, setLocalColumns] = (0, import_react60.useState)(
11572
11709
  null
@@ -11800,7 +11937,8 @@ function Grid({
11800
11937
  ...fills ? { className: "min-h-0 flex-1" } : {},
11801
11938
  data: rows,
11802
11939
  columns,
11803
- getRowId: (row) => row.id,
11940
+ getRowId: rowIdOf,
11941
+ rowVersion,
11804
11942
  isLoading: nothingToShowYet,
11805
11943
  isFetching: refreshing,
11806
11944
  density: host.density ?? "condensed",
@@ -11826,20 +11964,13 @@ function Grid({
11826
11964
  ];
11827
11965
  return footerRows.length > 0 ? { footerRows } : {};
11828
11966
  })(),
11829
- ...table.data ? {
11830
- copy: gridCopyConfig({
11831
- tableId,
11832
- tableName: tableName(table.data),
11833
- fields: ordered,
11834
- rowLabel: (row) => recordNameIn(table.data, row.document ?? {})
11835
- })
11836
- } : {},
11967
+ ...copyConfig ? { copy: copyConfig } : {},
11837
11968
  ...offerSelection ? {
11838
11969
  selection: {
11839
11970
  selectedIds,
11840
11971
  onSelectedIdsChange: setSelectedIds,
11841
11972
  noun,
11842
- isRowSelectable: (row) => row.id !== SUMMARY_ROW.id && mayWriteRow(row.id),
11973
+ isRowSelectable,
11843
11974
  actions: (_selected, ids) => /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(import_jsx_runtime42.Fragment, { children: [
11844
11975
  merged ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
11845
11976
  BulkActions,
@@ -11935,85 +12066,9 @@ function Grid({
11935
12066
  noun: "record",
11936
12067
  ...typeof records.data?.total === "number" ? { total: records.data.total } : {}
11937
12068
  },
11938
- ...!(0, import_data_table9.tableStyleIsEmpty)(paint.style) ? {
11939
- tableStyle: {
11940
- style: paint.style,
11941
- // A choice is read as its OPTION (`paintByOption`): the rule, the value and the
11942
- // colour a column keeps for it all name the same option, however it is stored.
11943
- documentOf: (row) => paint.documentOf(row.document ?? {}),
11944
- // A value its column keeps a colour for wears THAT colour (`choiceLooks.ts`);
11945
- // any other value still paints from its word.
11946
- choiceColorFor: paint.choiceColorFor
11947
- }
11948
- } : {},
12069
+ ...tableStyleProp ? { tableStyle: tableStyleProp } : {},
11949
12070
  ...onOpenRecord ? { onRowOpen: (row) => onOpenRecord(row.id) } : {},
11950
- ...canWrite || host.talkToRecord || host.runAgentAction && tableActions.agent.length > 0 ? {
11951
- // ABSENT, NEVER DEAD: a row this person may not delete carries no
11952
- // Delete at all, rather than one that refuses when pressed — and a
11953
- // deployment with no chat surface bound carries no Talk.
11954
- rowActions: (row) => /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(import_jsx_runtime42.Fragment, { children: [
11955
- canWrite && mayWriteRow(row.id) ? tableActions.runnable.map((action) => /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
11956
- ActionButton,
11957
- {
11958
- action,
11959
- busy: runner.busy === action.id,
11960
- onPress: () => runner.press(action, [row.id])
11961
- },
11962
- action.id
11963
- )) : null,
11964
- host.runAgentAction ? tableActions.agent.map((action) => /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
11965
- ActionButton,
11966
- {
11967
- action,
11968
- busy: false,
11969
- onPress: () => handToAgent(action, row)
11970
- },
11971
- action.id
11972
- )) : null,
11973
- host.talkToRecord ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
11974
- import_design_system35.Button,
11975
- {
11976
- size: "sm",
11977
- variant: "ghost",
11978
- onClick: () => host.talkToRecord?.({
11979
- tableId,
11980
- recordId: row.id,
11981
- // ONE NAMING CALL (`names.ts`), not this file's own join
11982
- // of a Table's title column to a document.
11983
- title: recordNameIn(
11984
- table.data,
11985
- row.document ?? {}
11986
- )
11987
- }),
11988
- children: "Talk"
11989
- }
11990
- ) : null,
11991
- Boolean(editable) && rights.write ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
11992
- import_design_system35.Button,
11993
- {
11994
- size: "sm",
11995
- variant: "ghost",
11996
- "data-records-duplicate": row.id,
11997
- title: "Duplicate this record",
11998
- onClick: (event) => {
11999
- event.stopPropagation();
12000
- void duplicate(row);
12001
- },
12002
- children: "Duplicate"
12003
- }
12004
- ) : null,
12005
- canWrite && mayWriteRow(row.id) ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
12006
- import_design_system35.Button,
12007
- {
12008
- size: "sm",
12009
- variant: "ghost",
12010
- title: "Delete this record",
12011
- onClick: () => setDeleting(row),
12012
- children: "Delete"
12013
- }
12014
- ) : null
12015
- ] })
12016
- } : {},
12071
+ ...offersRowActions ? { rowActions } : {},
12017
12072
  emptyState: emptyWords({
12018
12073
  error: records.error,
12019
12074
  asked: questionIsAsked({ search: query.search, columnFilters: query.columnFilters, filter }),
@@ -26512,7 +26567,8 @@ function useEmbedHandshake(args) {
26512
26567
  }
26513
26568
 
26514
26569
  // src/RecordsMount.tsx
26515
- var import_react160 = require("@ai-matrx/records/react");
26570
+ var import_react160 = require("react");
26571
+ var import_react161 = require("@ai-matrx/records/react");
26516
26572
  var import_jsx_runtime91 = require("react/jsx-runtime");
26517
26573
  var STORE_DECIDES_REASON = "This host offers exactly what the record store says this person may do: the level comes back with the table on the read door, so a control they cannot use is never drawn in the first place.";
26518
26574
  function storeDecidesRights(_table) {
@@ -26524,9 +26580,25 @@ function RecordsMount({
26524
26580
  letTheStoreDecideRights,
26525
26581
  children
26526
26582
  }) {
26527
- const bound = { ...host ?? {} };
26583
+ const bound = useShallowStableHost(host);
26528
26584
  void letTheStoreDecideRights;
26529
- return /* @__PURE__ */ (0, import_jsx_runtime91.jsx)(import_react160.RecordsProvider, { config, children: /* @__PURE__ */ (0, import_jsx_runtime91.jsx)(RecordsUiProvider, { value: bound, children: /* @__PURE__ */ (0, import_jsx_runtime91.jsx)(RecordLabelProvider, { children }) }) });
26585
+ return /* @__PURE__ */ (0, import_jsx_runtime91.jsx)(import_react161.RecordsProvider, { config, children: /* @__PURE__ */ (0, import_jsx_runtime91.jsx)(RecordsUiProvider, { value: bound, children: /* @__PURE__ */ (0, import_jsx_runtime91.jsx)(RecordLabelProvider, { children }) }) });
26586
+ }
26587
+ function useShallowStableHost(host) {
26588
+ const held = (0, import_react160.useRef)(null);
26589
+ const next = host ?? {};
26590
+ const previous = held.current;
26591
+ if (previous !== null && sameParts(previous, next)) return previous;
26592
+ const bound = { ...next };
26593
+ held.current = bound;
26594
+ return bound;
26595
+ }
26596
+ function sameParts(a, b) {
26597
+ const aKeys = Object.keys(a);
26598
+ const bKeys = Object.keys(b);
26599
+ if (aKeys.length !== bKeys.length) return false;
26600
+ for (const key of aKeys) if (a[key] !== b[key]) return false;
26601
+ return true;
26530
26602
  }
26531
26603
  function personActor(userId) {
26532
26604
  return userId ? { actor: "user", user_id: userId } : { actor: "user" };
@@ -26545,15 +26617,15 @@ function recordsDataSource(client, fallbackSchema = "custom") {
26545
26617
  }
26546
26618
 
26547
26619
  // src/TablesHome.tsx
26548
- var import_react165 = require("react");
26549
- var import_react166 = require("@ai-matrx/records/react");
26620
+ var import_react166 = require("react");
26621
+ var import_react167 = require("@ai-matrx/records/react");
26550
26622
  var import_core16 = require("@ai-matrx/records/core");
26551
26623
  var import_records29 = require("@ai-matrx/records");
26552
26624
  var import_design_system85 = require("@ai-matrx/design-system");
26553
26625
 
26554
26626
  // src/ExampleTables.tsx
26555
- var import_react161 = require("react");
26556
- var import_react162 = require("@ai-matrx/records/react");
26627
+ var import_react162 = require("react");
26628
+ var import_react163 = require("@ai-matrx/records/react");
26557
26629
  var import_use_cases = require("@ai-matrx/records/use-cases");
26558
26630
  var import_design_system83 = require("@ai-matrx/design-system");
26559
26631
  var import_jsx_runtime92 = require("react/jsx-runtime");
@@ -26562,12 +26634,12 @@ function ExampleTables({
26562
26634
  onClose,
26563
26635
  className
26564
26636
  }) {
26565
- const client = (0, import_react162.useRecordsClient)();
26566
- const [summaries, setSummaries] = (0, import_react161.useState)(null);
26567
- const [busy, setBusy] = (0, import_react161.useState)(null);
26568
- const [error, setError] = (0, import_react161.useState)(null);
26569
- const [built, setBuilt] = (0, import_react161.useState)(null);
26570
- (0, import_react161.useEffect)(() => {
26637
+ const client = (0, import_react163.useRecordsClient)();
26638
+ const [summaries, setSummaries] = (0, import_react162.useState)(null);
26639
+ const [busy, setBusy] = (0, import_react162.useState)(null);
26640
+ const [error, setError] = (0, import_react162.useState)(null);
26641
+ const [built, setBuilt] = (0, import_react162.useState)(null);
26642
+ (0, import_react162.useEffect)(() => {
26571
26643
  let alive = true;
26572
26644
  void Promise.all((0, import_use_cases.useCaseIds)().map(async (id) => (0, import_use_cases.summarize)(await (0, import_use_cases.loadUseCase)(id)))).then((rows) => {
26573
26645
  if (alive) setSummaries(rows);
@@ -26645,22 +26717,22 @@ function ExampleTables({
26645
26717
  var import_core15 = require("@ai-matrx/records/core");
26646
26718
 
26647
26719
  // src/WhereItLives.tsx
26648
- var import_react163 = require("react");
26720
+ var import_react164 = require("react");
26649
26721
  var import_records28 = require("@ai-matrx/records");
26650
- var import_react164 = require("@ai-matrx/records/react");
26722
+ var import_react165 = require("@ai-matrx/records/react");
26651
26723
  var import_design_system84 = require("@ai-matrx/design-system");
26652
26724
  var import_jsx_runtime93 = require("react/jsx-runtime");
26653
26725
  function WhereItLives({ tableId, knownOrganizationName, onMoved, variant = "header" }) {
26654
- const client = (0, import_react164.useRecordsClient)();
26726
+ const client = (0, import_react165.useRecordsClient)();
26655
26727
  const host = useRecordsUi();
26656
- const [answer, setAnswer] = (0, import_react163.useState)(null);
26657
- const [attempt, setAttempt] = (0, import_react163.useState)(0);
26658
- const [open, setOpen] = (0, import_react163.useState)(false);
26659
- const [armed, setArmed] = (0, import_react163.useState)(variant !== "row" || !knownOrganizationName);
26660
- const [choosing, setChoosing] = (0, import_react163.useState)(null);
26661
- const [moving, setMoving] = (0, import_react163.useState)(false);
26662
- const [said, setSaid] = (0, import_react163.useState)(null);
26663
- (0, import_react163.useEffect)(() => {
26728
+ const [answer, setAnswer] = (0, import_react164.useState)(null);
26729
+ const [attempt, setAttempt] = (0, import_react164.useState)(0);
26730
+ const [open, setOpen] = (0, import_react164.useState)(false);
26731
+ const [armed, setArmed] = (0, import_react164.useState)(variant !== "row" || !knownOrganizationName);
26732
+ const [choosing, setChoosing] = (0, import_react164.useState)(null);
26733
+ const [moving, setMoving] = (0, import_react164.useState)(false);
26734
+ const [said, setSaid] = (0, import_react164.useState)(null);
26735
+ (0, import_react164.useEffect)(() => {
26664
26736
  if (!armed) return;
26665
26737
  let alive = true;
26666
26738
  setAnswer(null);
@@ -26906,11 +26978,11 @@ function visibilityLaneFor(table) {
26906
26978
  return "organization";
26907
26979
  }
26908
26980
  function TablesHome({ onOpenTable, organizationName, makingOnly = false, className }) {
26909
- const client = (0, import_react166.useRecordsClient)();
26910
- const tables = (0, import_react166.useTables)();
26981
+ const client = (0, import_react167.useRecordsClient)();
26982
+ const tables = (0, import_react167.useTables)();
26911
26983
  const me = client.config.actor.user_id ?? null;
26912
- const [facts, setFacts] = (0, import_react165.useState)({ phase: "reading" });
26913
- (0, import_react165.useEffect)(() => {
26984
+ const [facts, setFacts] = (0, import_react166.useState)({ phase: "reading" });
26985
+ (0, import_react166.useEffect)(() => {
26914
26986
  let alive = true;
26915
26987
  void client.tableFacts().then((answered) => {
26916
26988
  if (!alive) return;
@@ -26924,11 +26996,11 @@ function TablesHome({ onOpenTable, organizationName, makingOnly = false, classNa
26924
26996
  (0, import_core16.withTableFacts)(tables.data ?? [], facts.rows, me),
26925
26997
  facts.rows
26926
26998
  ) : tables.data ?? [];
26927
- const [showEverything, setShowEverything] = (0, import_react165.useState)(false);
26999
+ const [showEverything, setShowEverything] = (0, import_react166.useState)(false);
26928
27000
  const keptCount = listed.filter((t) => laneFor(t) === "app").length;
26929
- const [askedName, setAskedName] = (0, import_react165.useState)(null);
27001
+ const [askedName, setAskedName] = (0, import_react166.useState)(null);
26930
27002
  const firstTableId = listed[0]?.id ?? null;
26931
- (0, import_react165.useEffect)(() => {
27003
+ (0, import_react166.useEffect)(() => {
26932
27004
  if (organizationName || !firstTableId) return;
26933
27005
  let alive = true;
26934
27006
  void client.tableHome({ table_id: firstTableId }).then((answered) => {
@@ -26941,14 +27013,14 @@ function TablesHome({ onOpenTable, organizationName, makingOnly = false, classNa
26941
27013
  const livesIn = organizationName || askedName;
26942
27014
  const isMine = (t) => Boolean(me) && laneFor(t) !== "system" && laneFor(t) !== "app" && t.created_by === me;
26943
27015
  const sectionsKnown = facts.phase !== "failed";
26944
- const [creating, setCreating] = (0, import_react165.useState)(false);
26945
- const [name, setName] = (0, import_react165.useState)("");
26946
- const [busy, setBusy] = (0, import_react165.useState)(false);
26947
- const [error, setError] = (0, import_react165.useState)(null);
26948
- const [importInto, setImportInto] = (0, import_react165.useState)(null);
26949
- const [examples, setExamples] = (0, import_react165.useState)(false);
26950
- const [boards, setBoards] = (0, import_react165.useState)(null);
26951
- (0, import_react165.useEffect)(() => {
27016
+ const [creating, setCreating] = (0, import_react166.useState)(false);
27017
+ const [name, setName] = (0, import_react166.useState)("");
27018
+ const [busy, setBusy] = (0, import_react166.useState)(false);
27019
+ const [error, setError] = (0, import_react166.useState)(null);
27020
+ const [importInto, setImportInto] = (0, import_react166.useState)(null);
27021
+ const [examples, setExamples] = (0, import_react166.useState)(false);
27022
+ const [boards, setBoards] = (0, import_react166.useState)(null);
27023
+ (0, import_react166.useEffect)(() => {
26952
27024
  if (makingOnly) return;
26953
27025
  let cancelled = false;
26954
27026
  void client.dashboards({}).then((result) => {
@@ -26959,7 +27031,7 @@ function TablesHome({ onOpenTable, organizationName, makingOnly = false, classNa
26959
27031
  cancelled = true;
26960
27032
  };
26961
27033
  }, [client, makingOnly]);
26962
- const create = (0, import_react165.useCallback)(
27034
+ const create = (0, import_react166.useCallback)(
26963
27035
  async (mode) => {
26964
27036
  const trimmed = name.trim();
26965
27037
  if (!trimmed) return;
@@ -27124,15 +27196,15 @@ function TablesHome({ onOpenTable, organizationName, makingOnly = false, classNa
27124
27196
  }
27125
27197
 
27126
27198
  // src/TablePage.tsx
27127
- var import_react170 = require("react");
27199
+ var import_react171 = require("react");
27128
27200
  var import_records30 = require("@ai-matrx/records");
27129
- var import_react171 = require("@ai-matrx/records/react");
27201
+ var import_react172 = require("@ai-matrx/records/react");
27130
27202
  var import_design_system87 = require("@ai-matrx/design-system");
27131
27203
 
27132
27204
  // src/ViewFilter.tsx
27133
- var import_react167 = require("react");
27205
+ var import_react168 = require("react");
27134
27206
  var import_design_system86 = require("@ai-matrx/design-system");
27135
- var import_react168 = require("@ai-matrx/records/react");
27207
+ var import_react169 = require("@ai-matrx/records/react");
27136
27208
  var import_jsx_runtime95 = require("react/jsx-runtime");
27137
27209
  function conditionCount(expr) {
27138
27210
  if (!expr || typeof expr !== "object" || Array.isArray(expr)) return 0;
@@ -27143,15 +27215,15 @@ function conditionCount(expr) {
27143
27215
  return 1;
27144
27216
  }
27145
27217
  function ViewFilter({ tableId, view, onApply, className }) {
27146
- const fields = (0, import_react168.useFields)(tableId);
27147
- const [open, setOpen] = (0, import_react167.useState)(false);
27218
+ const fields = (0, import_react169.useFields)(tableId);
27219
+ const [open, setOpen] = (0, import_react168.useState)(false);
27148
27220
  const saved = view?.where ?? null;
27149
- const [draft, setDraft] = (0, import_react167.useState)(saved);
27221
+ const [draft, setDraft] = (0, import_react168.useState)(saved);
27150
27222
  const savedKey = JSON.stringify(saved);
27151
- (0, import_react167.useEffect)(() => {
27223
+ (0, import_react168.useEffect)(() => {
27152
27224
  setDraft(saved);
27153
27225
  }, [view?.id, savedKey]);
27154
- const conditionFields = (0, import_react167.useMemo)(
27226
+ const conditionFields = (0, import_react168.useMemo)(
27155
27227
  () => (fields.data ?? []).map((f) => ({ id: f.id, key: f.key, label: f.label || f.key, field: f })),
27156
27228
  [fields.data]
27157
27229
  );
@@ -27231,7 +27303,7 @@ function ViewFilter({ tableId, view, onApply, className }) {
27231
27303
  }
27232
27304
 
27233
27305
  // src/toolbarFit.ts
27234
- var import_react169 = require("react");
27306
+ var import_react170 = require("react");
27235
27307
  var FOLDED_GUESS = { look: 104, chooser: 96, tools: 120 };
27236
27308
  function toolbarFold(input) {
27237
27309
  const { available, needsNow, gap, folded } = input;
@@ -27282,8 +27354,8 @@ function rowNeeds(row) {
27282
27354
  return { needs: needs + gap * Math.max(0, pieces.length - 1), gap };
27283
27355
  }
27284
27356
  function useToolbarFit(row) {
27285
- const [fold, setFold] = (0, import_react169.useState)(0);
27286
- (0, import_react169.useEffect)(() => {
27357
+ const [fold, setFold] = (0, import_react170.useState)(0);
27358
+ (0, import_react170.useEffect)(() => {
27287
27359
  if (!row) return;
27288
27360
  const widths = {
27289
27361
  look: { full: null, folded: null },
@@ -27363,8 +27435,8 @@ function clippedEnds(scrollLeft, clientWidth, scrollWidth) {
27363
27435
  return start && end ? "both" : start ? "start" : end ? "end" : "none";
27364
27436
  }
27365
27437
  function useSlotScroll(slot) {
27366
- const [ends, setEnds] = (0, import_react169.useState)("none");
27367
- (0, import_react169.useEffect)(() => {
27438
+ const [ends, setEnds] = (0, import_react170.useState)("none");
27439
+ (0, import_react170.useEffect)(() => {
27368
27440
  if (!slot) return;
27369
27441
  let pending = 0;
27370
27442
  const read = () => {
@@ -27480,11 +27552,11 @@ function TableNotHere({
27480
27552
  leaveLabel,
27481
27553
  className
27482
27554
  }) {
27483
- const client = (0, import_react171.useRecordsClient)();
27484
- const [archived, setArchived] = (0, import_react170.useState)({ phase: "asking" });
27485
- const [restoring, setRestoring] = (0, import_react170.useState)(false);
27486
- const [refusal2, setRefusal] = (0, import_react170.useState)(null);
27487
- (0, import_react170.useEffect)(() => {
27555
+ const client = (0, import_react172.useRecordsClient)();
27556
+ const [archived, setArchived] = (0, import_react171.useState)({ phase: "asking" });
27557
+ const [restoring, setRestoring] = (0, import_react171.useState)(false);
27558
+ const [refusal2, setRefusal] = (0, import_react171.useState)(null);
27559
+ (0, import_react171.useEffect)(() => {
27488
27560
  let alive = true;
27489
27561
  void client.tableArchived({ table_id: tableId }).then((answered) => {
27490
27562
  if (!alive) return;
@@ -27661,15 +27733,15 @@ function TablePage({
27661
27733
  onShownViewChange,
27662
27734
  className
27663
27735
  }) {
27664
- const client = (0, import_react171.useRecordsClient)();
27665
- const table = (0, import_react171.useTable)(tableId);
27736
+ const client = (0, import_react172.useRecordsClient)();
27737
+ const table = (0, import_react172.useTable)(tableId);
27666
27738
  const rights = useTableRights(table.data);
27667
- const pageFields = (0, import_react171.useFields)(filter ? tableId : null);
27739
+ const pageFields = (0, import_react172.useFields)(filter ? tableId : null);
27668
27740
  const askedInWords = filter ? filterInWords(filter, pageFields.data ?? []) : null;
27669
- const organizationId = (0, import_react171.useRecordsClient)().config.organizationId;
27670
- const [view, setView] = (0, import_react170.useState)(null);
27671
- const [looks, setLooks] = (0, import_react170.useState)(void 0);
27672
- (0, import_react170.useEffect)(() => {
27741
+ const organizationId = (0, import_react172.useRecordsClient)().config.organizationId;
27742
+ const [view, setView] = (0, import_react171.useState)(null);
27743
+ const [looks, setLooks] = (0, import_react171.useState)(void 0);
27744
+ (0, import_react171.useEffect)(() => {
27673
27745
  let live = true;
27674
27746
  setLooks(void 0);
27675
27747
  void readLooks(client, tableId).then((answered) => {
@@ -27682,35 +27754,35 @@ function TablePage({
27682
27754
  }, [client, tableId]);
27683
27755
  const look = view && looks ? looks[view.id] : void 0;
27684
27756
  const shown3 = view ? applyLook(view, look) : null;
27685
- const [viewsEpoch, setViewsEpoch] = (0, import_react170.useState)(0);
27757
+ const [viewsEpoch, setViewsEpoch] = (0, import_react171.useState)(0);
27686
27758
  const opening = openingRail(activeRecordId, activeRail);
27687
27759
  const hostLayouts = useRecordsUi().layouts ?? [];
27688
27760
  const hostLayoutFor = (asked) => openingHostLayout(asked, hostLayouts);
27689
27761
  const hostFromLink = hostLayoutFor(activeView);
27690
27762
  const openedByPackage = openingView(hostFromLink ? null : activeView, activeDashboardId);
27691
27763
  const opened = hostFromLink ? { ...openedByPackage, main: "records" } : openedByPackage;
27692
- const [hostLayout, setHostLayout] = (0, import_react170.useState)(hostFromLink);
27693
- const [views, setViews] = (0, import_react170.useState)(void 0);
27694
- const [pickedViewId, setPickedViewId] = (0, import_react170.useState)(null);
27695
- const [layoutChosen, setLayoutChosen] = (0, import_react170.useState)(false);
27764
+ const [hostLayout, setHostLayout] = (0, import_react171.useState)(hostFromLink);
27765
+ const [views, setViews] = (0, import_react171.useState)(void 0);
27766
+ const [pickedViewId, setPickedViewId] = (0, import_react171.useState)(null);
27767
+ const [layoutChosen, setLayoutChosen] = (0, import_react171.useState)(false);
27696
27768
  const railAsked = typeof activeRail === "string" ? activeRail.trim() : "";
27697
27769
  const railUnknown = railAsked !== "" && railFromParam(railAsked) === null ? railAsked : null;
27698
27770
  const shareFromLink = railFromParam(activeRail) === "share";
27699
27771
  const canShare = useCanShare();
27700
27772
  const itemFor = (which) => railFromParam(activeRail) === which ? activeItemId ?? null : null;
27701
- const [asking, setAsking] = (0, import_react170.useState)(null);
27702
- const [layoutFromLink, setLayoutFromLink] = (0, import_react170.useState)(opened.layout);
27703
- const [surface, setSurface] = (0, import_react170.useState)({
27773
+ const [asking, setAsking] = (0, import_react171.useState)(null);
27774
+ const [layoutFromLink, setLayoutFromLink] = (0, import_react171.useState)(opened.layout);
27775
+ const [surface, setSurface] = (0, import_react171.useState)({
27704
27776
  main: opened.main,
27705
27777
  rail: opening.rail
27706
27778
  });
27707
27779
  const { main, rail } = surface;
27708
27780
  const setRail = (next) => setSurface((now) => ({ ...now, rail: next }));
27709
- const [openRecord, setOpenRecord] = (0, import_react170.useState)(opening.record);
27781
+ const [openRecord, setOpenRecord] = (0, import_react171.useState)(opening.record);
27710
27782
  const phone = (0, import_design_system87.useIsMobile)();
27711
- const [shareAsked, setShareAsked] = (0, import_react170.useState)(0);
27712
- const [toolbarSlot, setToolbarSlot] = (0, import_react170.useState)(null);
27713
- const [toolbarRow, setToolbarRow] = (0, import_react170.useState)(null);
27783
+ const [shareAsked, setShareAsked] = (0, import_react171.useState)(0);
27784
+ const [toolbarSlot, setToolbarSlot] = (0, import_react171.useState)(null);
27785
+ const [toolbarRow, setToolbarRow] = (0, import_react171.useState)(null);
27714
27786
  const toolbarFold2 = useToolbarFit(toolbarRow);
27715
27787
  const slotClipped = useSlotScroll(toolbarSlot);
27716
27788
  const face = tableOpening(view, hostLayouts.map((h) => h.id));
@@ -27718,7 +27790,7 @@ function TablePage({
27718
27790
  const chooserInline = !designated && !phone && toolbarFold2 < 2;
27719
27791
  const chooserCompact = !designated && !phone && toolbarFold2 >= 2;
27720
27792
  const controlsInSheet = phone && !designated;
27721
- (0, import_react170.useEffect)(() => {
27793
+ (0, import_react171.useEffect)(() => {
27722
27794
  if (face.kind !== "designated") return;
27723
27795
  if (hostFromLink || opened.layout || layoutChosen) return;
27724
27796
  setHostLayout(face.hostLayout);
@@ -27749,9 +27821,9 @@ function TablePage({
27749
27821
  lookDiffers: view ? lookDiffers(view, look) : false
27750
27822
  };
27751
27823
  const shownSignature = JSON.stringify(shownReport);
27752
- const reportRef = (0, import_react170.useRef)(onShownViewChange);
27824
+ const reportRef = (0, import_react171.useRef)(onShownViewChange);
27753
27825
  reportRef.current = onShownViewChange;
27754
- (0, import_react170.useEffect)(() => {
27826
+ (0, import_react171.useEffect)(() => {
27755
27827
  reportRef.current?.(JSON.parse(shownSignature));
27756
27828
  }, [shownSignature]);
27757
27829
  const pickLayout = (next) => {
@@ -27769,18 +27841,18 @@ function TablePage({
27769
27841
  onViewChanged?.(id);
27770
27842
  };
27771
27843
  const openedFromMenu = MENU.find((entry) => entry.press.main !== void 0 && entry.press.main === main) ?? MENU.find((entry) => entry.press.rail !== void 0 && entry.press.rail === rail) ?? null;
27772
- (0, import_react170.useEffect)(() => {
27844
+ (0, import_react171.useEffect)(() => {
27773
27845
  if (!activeRecordId) return;
27774
27846
  setOpenRecord(activeRecordId);
27775
27847
  setSurface((now) => ({ ...now, rail: "record" }));
27776
27848
  }, [activeRecordId]);
27777
- (0, import_react170.useEffect)(() => {
27849
+ (0, import_react171.useEffect)(() => {
27778
27850
  if (activeRecordId) return;
27779
27851
  const named = railFromParam(activeRail);
27780
27852
  if (named === null || named === "share") return;
27781
27853
  setSurface((now) => ({ ...now, rail: named }));
27782
27854
  }, [activeRail, activeRecordId]);
27783
- (0, import_react170.useEffect)(() => {
27855
+ (0, import_react171.useEffect)(() => {
27784
27856
  const host = hostLayoutFor(activeView);
27785
27857
  if (host) {
27786
27858
  setHostLayout(host);
@@ -27794,8 +27866,8 @@ function TablePage({
27794
27866
  setLayoutFromLink(isLayout ? named : null);
27795
27867
  setSurface((now) => ({ ...now, main: isLayout ? "records" : named }));
27796
27868
  }, [activeView]);
27797
- const [viewSaveRefused, setViewSaveRefused] = (0, import_react170.useState)(null);
27798
- const patchView = (0, import_react170.useCallback)(
27869
+ const [viewSaveRefused, setViewSaveRefused] = (0, import_react171.useState)(null);
27870
+ const patchView = (0, import_react171.useCallback)(
27799
27871
  async (asked) => {
27800
27872
  const current = view;
27801
27873
  if (!current) return;
@@ -27812,9 +27884,9 @@ function TablePage({
27812
27884
  [client, tableId, view, looks]
27813
27885
  );
27814
27886
  const lookShowing = Boolean(view && looks && lookDiffers(view, looks[view.id]));
27815
- const [lookRefused, setLookRefused] = (0, import_react170.useState)(null);
27816
- const [namingLook, setNamingLook] = (0, import_react170.useState)(false);
27817
- const [lookName, setLookName] = (0, import_react170.useState)("");
27887
+ const [lookRefused, setLookRefused] = (0, import_react171.useState)(null);
27888
+ const [namingLook, setNamingLook] = (0, import_react171.useState)(false);
27889
+ const [lookName, setLookName] = (0, import_react171.useState)("");
27818
27890
  const resetLook = async () => {
27819
27891
  const current = view;
27820
27892
  if (!current) return;
@@ -27872,7 +27944,7 @@ function TablePage({
27872
27944
  setPickedViewId(written.data);
27873
27945
  setViewsEpoch((n) => n + 1);
27874
27946
  };
27875
- const [designateRefused, setDesignateRefused] = (0, import_react170.useState)(null);
27947
+ const [designateRefused, setDesignateRefused] = (0, import_react171.useState)(null);
27876
27948
  const opensAs = view?.isDefault ? openingLayoutOf(view) : null;
27877
27949
  const canDesignate = Boolean(rights.write && view && layoutShowing && layoutShowing !== opensAs);
27878
27950
  const layoutShowingLabel = layoutShowing ? hostLayouts.find((h) => h.id === layoutShowing)?.label ?? (VIEW_LAYOUTS.includes(layoutShowing) ? LAYOUT_LABEL[layoutShowing] : layoutShowing) : "";