@ai-matrx/records-ui 0.93.33 → 0.93.37

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/CHANGELOG.md CHANGED
@@ -1,5 +1,29 @@
1
1
  # Changelog — @ai-matrx/records-ui
2
2
 
3
+ ## 0.93.37
4
+
5
+ Automatic changed-only republish (docs/metadata drift since the last tag — see
6
+ `git diff npm/records-ui/v0.93.33..npm/records-ui/v0.93.37 -- apps/shared/records-ui`).
7
+ No source changes intended and no consumer action required.
8
+
9
+ ## 0.93.36
10
+
11
+ Automatic changed-only republish (docs/metadata drift since the last tag — see
12
+ `git diff npm/records-ui/v0.93.33..npm/records-ui/v0.93.36 -- apps/shared/records-ui`).
13
+ No source changes intended and no consumer action required.
14
+
15
+ ## 0.93.35
16
+
17
+ Automatic changed-only republish (docs/metadata drift since the last tag — see
18
+ `git diff npm/records-ui/v0.93.33..npm/records-ui/v0.93.35 -- apps/shared/records-ui`).
19
+ No source changes intended and no consumer action required.
20
+
21
+ ## 0.93.34
22
+
23
+ Automatic changed-only republish (docs/metadata drift since the last tag — see
24
+ `git diff npm/records-ui/v0.93.33..npm/records-ui/v0.93.34 -- apps/shared/records-ui`).
25
+ No source changes intended and no consumer action required.
26
+
3
27
  ## 0.93.33
4
28
 
5
29
  Automatic changed-only republish (docs/metadata drift since the last tag — see
package/dist/index.cjs CHANGED
@@ -5777,16 +5777,26 @@ var import_react34 = require("@ai-matrx/records/react");
5777
5777
  var import_design_system18 = require("@ai-matrx/design-system");
5778
5778
  var import_jsx_runtime22 = require("react/jsx-runtime");
5779
5779
  var RETYPE_TARGETS = [
5780
- { behaviour: "text", label: "Text", holds: "words" },
5781
- { behaviour: "range", label: "Number", holds: "a number" },
5782
- { behaviour: "boolean", label: "Yes / no", holds: "a yes or a no" }
5780
+ { id: "text", behaviour: "text", kind: null, label: "Text", holds: "words" },
5781
+ { id: "number", behaviour: "range", kind: "number", label: "Number", holds: "a number" },
5782
+ // A DATE is a `range` of kind date: `migrate_retype` alone cannot say "date" (it keeps the old
5783
+ // kind, so every date would be kept aside), so this one goes through `custom.field_update`'s own
5784
+ // retype arm (`parity_type: datetime`), which converts on the SAME trigger and keeps what does not
5785
+ // fit in `_retired` with the reason — measured on the live store 2026-09-28.
5786
+ { id: "date", behaviour: "range", kind: "date", label: "Date", holds: "a date" },
5787
+ { id: "checkbox", behaviour: "boolean", kind: null, label: "Yes / no", holds: "a yes or a no" }
5783
5788
  ];
5784
5789
  var PREVIEW_GROUPS = 1e3;
5785
5790
  function retypeableFrom(field2) {
5786
5791
  const behaviour = String(field2.type);
5787
- if (behaviour !== "text" && behaviour !== "range" && behaviour !== "boolean") return false;
5792
+ return behaviour === "text" || behaviour === "range" || behaviour === "boolean";
5793
+ }
5794
+ function currentTarget(field2) {
5788
5795
  const kind = String(editorKindFor(field2));
5789
- return kind !== "datetime" && kind !== "date";
5796
+ if (String(field2.type) === "boolean") return "checkbox";
5797
+ if (kind === "datetime" || kind === "date") return "date";
5798
+ if (String(field2.type) === "range") return "number";
5799
+ return "text";
5790
5800
  }
5791
5801
  function FieldRetype({ field: field2, tableId, onRetyped }) {
5792
5802
  const client = (0, import_react34.useRecordsClient)();
@@ -5797,7 +5807,7 @@ function FieldRetype({ field: field2, tableId, onRetyped }) {
5797
5807
  const [busy, setBusy] = (0, import_react33.useState)(false);
5798
5808
  const [said, setSaid] = (0, import_react33.useState)(null);
5799
5809
  const name = fieldName(field2);
5800
- const targets = RETYPE_TARGETS.filter((t) => t.behaviour !== String(field2.type));
5810
+ const targets = RETYPE_TARGETS.filter((t) => t.id !== currentTarget(field2));
5801
5811
  (0, import_react33.useEffect)(() => {
5802
5812
  if (!to) return;
5803
5813
  let cancelled = false;
@@ -5812,7 +5822,7 @@ function FieldRetype({ field: field2, tableId, onRetyped }) {
5812
5822
  return;
5813
5823
  }
5814
5824
  const groups = answer.data.map((row) => ({ value: row.groups[field2.key] ?? null, count: row.row_count }));
5815
- setPreview((0, import_records10.previewRetype)({ type: to.behaviour }, groups, answer.data.length >= PREVIEW_GROUPS));
5825
+ setPreview((0, import_records10.previewRetype)({ type: to.behaviour, kind: to.kind }, groups, answer.data.length >= PREVIEW_GROUPS));
5816
5826
  });
5817
5827
  return () => {
5818
5828
  cancelled = true;
@@ -5822,22 +5832,35 @@ function FieldRetype({ field: field2, tableId, onRetyped }) {
5822
5832
  return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("p", { className: "text-[11px] text-muted-foreground", "data-records-retype": "not-here", children: [
5823
5833
  name,
5824
5834
  " holds ",
5825
- String(editorKindFor(field2)) === "datetime" ? "dates" : "records picked from a list or another table",
5826
- ", so what it holds is not changed here \u2014 add a new column and move the values across."
5835
+ String(field2.type) === "formula" ? "a value the table works out" : "records picked from a list or another table",
5836
+ ", and the store keeps those as record ids \u2014 turned into words or numbers they would read as ids, so it is not changed here."
5827
5837
  ] });
5828
5838
  }
5829
5839
  const change = async () => {
5830
5840
  if (!to) return;
5831
5841
  setBusy(true);
5832
5842
  setRefusal(null);
5833
- const done = await client.migrateRetype({ field_id: field2.id, to: to.behaviour });
5834
- setBusy(false);
5835
- if (!done.ok) {
5836
- setRefusal(done.error);
5837
- return;
5843
+ let holding;
5844
+ let aside;
5845
+ if (to.id === "date") {
5846
+ const done = await client.fieldUpdate({ field_id: field2.id, patch: { parity_type: "datetime" } });
5847
+ setBusy(false);
5848
+ if (!done.ok) {
5849
+ setRefusal(done.error);
5850
+ return;
5851
+ }
5852
+ holding = preview?.converts ?? 0;
5853
+ aside = preview?.keptAside ?? 0;
5854
+ } else {
5855
+ const done = await client.migrateRetype({ field_id: field2.id, to: to.behaviour });
5856
+ setBusy(false);
5857
+ if (!done.ok) {
5858
+ setRefusal(done.error);
5859
+ return;
5860
+ }
5861
+ holding = done.data.records_still_holding_a_value ?? 0;
5862
+ aside = done.data.values_in_retired_for_this_field ?? 0;
5838
5863
  }
5839
- const holding = done.data.records_still_holding_a_value ?? 0;
5840
- const aside = done.data.values_in_retired_for_this_field ?? 0;
5841
5864
  setSaid(
5842
5865
  `${name} now holds ${to.holds}. ${holding} ${holding === 1 ? "record holds" : "records hold"} a value` + (aside > 0 ? `; ${aside} ${aside === 1 ? "value that did not fit was" : "values that did not fit were"} kept with ${aside === 1 ? "its record" : "their records"}, with the reason.` : ".")
5843
5866
  );
@@ -5848,9 +5871,9 @@ function FieldRetype({ field: field2, tableId, onRetyped }) {
5848
5871
  };
5849
5872
  return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "flex flex-col gap-1.5", "data-records-retype": "", children: [
5850
5873
  /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "flex flex-wrap items-center gap-2", children: [
5851
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_design_system18.Select, { value: to?.behaviour ?? "", onValueChange: (next) => setTo(targets.find((t) => t.behaviour === next) ?? null), children: [
5874
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_design_system18.Select, { value: to?.id ?? "", onValueChange: (next) => setTo(targets.find((t) => t.id === next) ?? null), children: [
5852
5875
  /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_design_system18.SelectTrigger, { size: "sm", "aria-label": "Change what this column holds", className: "w-auto min-w-[12rem]", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_design_system18.SelectValue, { placeholder: "Change what this column holds" }) }),
5853
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_design_system18.SelectContent, { children: targets.map((t) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_design_system18.SelectItem, { value: t.behaviour, children: t.label }, t.behaviour)) })
5876
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_design_system18.SelectContent, { children: targets.map((t) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_design_system18.SelectItem, { value: t.id, children: t.label }, t.id)) })
5854
5877
  ] }),
5855
5878
  to ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_design_system18.Button, { size: "sm", disabled: busy || asking || preview === null, onClick: () => void change(), "data-records-retype-go": "", children: busy ? "Changing\u2026" : `Change to ${to.label}` }) : null,
5856
5879
  to ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_design_system18.Button, { size: "sm", variant: "ghost", onClick: () => setTo(null), disabled: busy, children: "Cancel" }) : null
@@ -9790,7 +9813,10 @@ function columnForField(field2, editing, mayWriteRow, whyNotRow, look, onAskWhoC
9790
9813
  // The type is in the header's tooltip rather than a second header row: one
9791
9814
  // row of headers, always — and it is the parity type's own WORD, not a
9792
9815
  // token (`Long text`, never `long_text`).
9793
- className: "align-top",
9816
+ // Top-aligned where a value may wrap to several lines; on a phone a cell never wraps (one line,
9817
+ // scrolled sideways) and the row is as tall as its 44 px tick box, so the value sits in the
9818
+ // middle beside the box — top-aligned it sat ~10 px above it (merged-grid review 2, 390 px).
9819
+ className: "sm:align-top max-sm:align-middle",
9794
9820
  ...{ title: fieldTypeLabel(field2) }
9795
9821
  };
9796
9822
  }
@@ -9820,6 +9846,12 @@ function PastePreview({
9820
9846
  "aria-label": "What this paste will write",
9821
9847
  "data-matrx-paste-preview": true,
9822
9848
  className: "fixed inset-0 z-50 flex items-center justify-center bg-black/40 p-4",
9849
+ onKeyDown: (event) => {
9850
+ if (event.key !== "Escape") return;
9851
+ event.preventDefault();
9852
+ event.stopPropagation();
9853
+ if (!busy) onCancel();
9854
+ },
9823
9855
  children: /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "flex max-h-[80vh] w-full max-w-2xl flex-col gap-3 overflow-auto rounded-lg border bg-background p-4 shadow-lg", children: [
9824
9856
  /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "flex items-baseline justify-between gap-3", children: [
9825
9857
  /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("h2", { className: "text-sm font-medium", children: outcome ? "What was written" : "Before this is written" }),
@@ -9895,11 +9927,13 @@ function PastePreview({
9895
9927
  ". Add the columns first and paste again."
9896
9928
  ] }) : null,
9897
9929
  /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "flex items-center justify-end gap-2 pt-1", children: [
9898
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_design_system30.Button, { size: "sm", variant: "ghost", onClick: onCancel, disabled: busy, children: "Cancel" }),
9930
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_design_system30.Button, { size: "sm", variant: "ghost", onClick: onCancel, disabled: busy, autoFocus: nothingToDo, children: "Cancel" }),
9899
9931
  /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
9900
9932
  import_design_system30.Button,
9901
9933
  {
9902
9934
  size: "sm",
9935
+ autoFocus: !nothingToDo,
9936
+ "data-matrx-paste-confirm": "",
9903
9937
  disabled: busy || nothingToDo,
9904
9938
  onClick: () => {
9905
9939
  setBusy(true);
@@ -9919,7 +9953,7 @@ function Outcome({ outcome, onClose }) {
9919
9953
  return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(import_jsx_runtime34.Fragment, { children: [
9920
9954
  /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("p", { className: "text-sm", "data-matrx-paste-outcome": whole ? "whole" : "partial", children: whole ? `All ${outcome.readBack} ${outcome.readBack === 1 ? "value is" : "values are"} in the table \u2014 read back out of it, not just accepted.` : `${outcome.readBack} of ${outcome.readBack + outcome.missing} values are in the table. The rest are not, and nothing was lost from what you copied \u2014 it is still on your clipboard.` }),
9921
9955
  outcome.refusals.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("ul", { className: "flex flex-col gap-1", children: outcome.refusals.slice(0, 8).map((why, index) => /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("li", { className: "text-xs text-muted-foreground", children: why }, index)) }) : null,
9922
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: "flex justify-end pt-1", children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_design_system30.Button, { size: "sm", onClick: onClose, children: "Close" }) })
9956
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: "flex justify-end pt-1", children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_design_system30.Button, { size: "sm", onClick: onClose, autoFocus: true, children: "Close" }) })
9923
9957
  ] });
9924
9958
  }
9925
9959
  function PlanTable({ plan }) {