@ai-matrx/records-ui 0.101.30 → 0.101.33

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,23 @@
1
1
  # Changelog — @ai-matrx/records-ui
2
2
 
3
+ ## 0.101.33
4
+
5
+ Automatic changed-only republish (docs/metadata drift since the last tag — see
6
+ `git diff npm/records-ui/v0.101.31..npm/records-ui/v0.101.33 -- apps/shared/records-ui`).
7
+ No source changes intended and no consumer action required.
8
+
9
+ ## 0.101.32
10
+
11
+ Automatic changed-only republish (docs/metadata drift since the last tag — see
12
+ `git diff npm/records-ui/v0.101.31..npm/records-ui/v0.101.32 -- apps/shared/records-ui`).
13
+ No source changes intended and no consumer action required.
14
+
15
+ ## 0.101.31
16
+
17
+ Automatic changed-only republish (docs/metadata drift since the last tag — see
18
+ `git diff npm/records-ui/v0.101.30..npm/records-ui/v0.101.31 -- apps/shared/records-ui`).
19
+ No source changes intended and no consumer action required.
20
+
3
21
  ## 0.101.30
4
22
 
5
23
  Automatic changed-only republish (docs/metadata drift since the last tag — see
package/dist/index.cjs CHANGED
@@ -2368,10 +2368,10 @@ function shown(value) {
2368
2368
  if (typeof value === "number" || typeof value === "boolean") return String(value);
2369
2369
  return null;
2370
2370
  }
2371
- function tellApart(rows, nameOf) {
2371
+ function tellApart(rows, nameOf2) {
2372
2372
  const byName = /* @__PURE__ */ new Map();
2373
2373
  for (const row of rows) {
2374
- const name = nameOf(row.id).trim().toLowerCase();
2374
+ const name = nameOf2(row.id).trim().toLowerCase();
2375
2375
  byName.set(name, [...byName.get(name) ?? [], row]);
2376
2376
  }
2377
2377
  const out = /* @__PURE__ */ new Map();
@@ -2979,6 +2979,7 @@ function RecordLabelProvider({ children }) {
2979
2979
  const client = (0, import_react14.useRecordsClient)();
2980
2980
  const [names, setNames] = (0, import_react13.useState)({});
2981
2981
  const [archivedRefs, setArchivedRefs] = (0, import_react13.useState)({});
2982
+ const [iconsOf, setIconsOf] = (0, import_react13.useState)({});
2982
2983
  const [settled, setSettled] = (0, import_react13.useState)({});
2983
2984
  const [waitingLines, setWaitingLines] = (0, import_react13.useState)({});
2984
2985
  const asked3 = (0, import_react13.useRef)(/* @__PURE__ */ new Set());
@@ -3061,6 +3062,7 @@ function RecordLabelProvider({ children }) {
3061
3062
  void (async () => {
3062
3063
  const learned = {};
3063
3064
  const archivedNow = {};
3065
+ const iconsNow = {};
3064
3066
  await Promise.all(
3065
3067
  batch.map(async ({ field: field2, ids }) => {
3066
3068
  const wanted = [...ids];
@@ -3073,10 +3075,12 @@ function RecordLabelProvider({ children }) {
3073
3075
  learned[id] = !result.ok ? UNREAD_RECORD_LABEL : typeof words2 === "string" && words2 !== "" ? words2 : WITHHELD_RECORD_LABEL;
3074
3076
  }
3075
3077
  if (result.ok) for (const id of result.archived ?? []) archivedNow[`${field2.id}:${id}`] = true;
3078
+ if (result.ok) for (const [id, pair] of Object.entries(result.icons ?? {})) iconsNow[id] = pair;
3076
3079
  })
3077
3080
  );
3078
3081
  setNames((current) => ({ ...current, ...learned }));
3079
3082
  if (Object.keys(archivedNow).length > 0) setArchivedRefs((current) => ({ ...current, ...archivedNow }));
3083
+ if (Object.keys(iconsNow).length > 0) setIconsOf((current) => ({ ...current, ...iconsNow }));
3080
3084
  for (const { field: field2 } of batch) stopWaitClock(field2.id);
3081
3085
  })();
3082
3086
  }, [client, stopWaitClock]);
@@ -3124,9 +3128,10 @@ function RecordLabelProvider({ children }) {
3124
3128
  () => {
3125
3129
  const answer = ((field2, id) => lookupWords(field2, id));
3126
3130
  answer.archived = (field2, id) => archivedRefs[`${field2.id}:${id}`] === true;
3131
+ answer.icons = (_field, id) => iconsOf[id];
3127
3132
  return answer;
3128
3133
  },
3129
- [lookupWords, archivedRefs]
3134
+ [lookupWords, archivedRefs, iconsOf]
3130
3135
  );
3131
3136
  const waiting = (0, import_react13.useCallback)((field2) => waitingLines[field2.id] ?? null, [waitingLines]);
3132
3137
  const value = (0, import_react13.useMemo)(() => ({ lookup, want, waiting }), [lookup, want, waiting]);
@@ -5677,7 +5682,7 @@ var import_design_system21 = require("@ai-matrx/design-system");
5677
5682
 
5678
5683
  // src/embeddedLook.tsx
5679
5684
  var import_react32 = require("react");
5680
- var EMBEDDED_LOOK = { blankEmpty: true, choiceDot: true };
5685
+ var EMBEDDED_LOOK = { blankEmpty: true, choiceDot: true, plainRelation: true };
5681
5686
  var EmbeddedLookContext = (0, import_react32.createContext)(null);
5682
5687
  var EmbeddedLookProvider = EmbeddedLookContext.Provider;
5683
5688
  function useEmbeddedLook() {
@@ -5693,6 +5698,7 @@ var EMBEDDED_TABLE_CLASS = [
5693
5698
  "[&_thead_th]:border-border",
5694
5699
  "[&_thead_th:last-child]:border-r-0"
5695
5700
  ].join(" ");
5701
+ var EMBEDDED_PLAIN_FOOTER_CLASS = "[&_tfoot]:bg-transparent [&_tfoot]:border-t-0";
5696
5702
 
5697
5703
  // src/enumLabels.ts
5698
5704
  function exhaustiveValuesOf() {
@@ -5985,6 +5991,20 @@ function kindLabel(kind) {
5985
5991
 
5986
5992
  // src/ReferenceChips.tsx
5987
5993
  var import_jsx_runtime22 = require("react/jsx-runtime");
5994
+ function glyphOf(icon) {
5995
+ const text = (icon ?? "").trim();
5996
+ return text !== "" && text.length <= 8 && /[^\u0000-\u007f]/.test(text) ? text : null;
5997
+ }
5998
+ function nameOf(icon) {
5999
+ const text = (icon ?? "").trim();
6000
+ return /^[A-Za-z][A-Za-z0-9_-]{1,40}$/.test(text) ? text : null;
6001
+ }
6002
+ function iconOf(pair) {
6003
+ const own3 = glyphOf(pair?.icon) ?? nameOf(pair?.icon);
6004
+ const table = glyphOf(pair?.tableIcon) ?? nameOf(pair?.tableIcon);
6005
+ const chosen = own3 ?? table;
6006
+ return chosen ? { icon: chosen } : {};
6007
+ }
5988
6008
  function referencesOf(field2, value, kind, labels) {
5989
6009
  if (kind === "entity_reference") {
5990
6010
  return (0, import_records13.entityRefsOf)(value).map((r) => ({ token: r.token, id: r.id, label: r.label }));
@@ -5996,15 +6016,45 @@ function referencesOf(field2, value, kind, labels) {
5996
6016
  id,
5997
6017
  label: labels?.(field2, id) ?? null,
5998
6018
  tableId,
6019
+ ...iconOf(labels?.icons?.(field2, id)),
5999
6020
  ...labels?.archived?.(field2, id) ? { archived: true } : {}
6000
6021
  }));
6001
6022
  }
6002
6023
  var ARCHIVED_REFERENCE_WORD = "Archived";
6003
6024
  var ARCHIVED_REFERENCE_TIP = "In the Archived view; restore it to use it again";
6025
+ function PageGlyph() {
6026
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", width: 14, height: 14, fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", "data-records-page-glyph": "", children: [
6027
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("path", { d: "M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z" }),
6028
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("path", { d: "M14 2v4a2 2 0 0 0 2 2h4" }),
6029
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("path", { d: "M10 13H8" }),
6030
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("path", { d: "M16 17H8" })
6031
+ ] });
6032
+ }
6004
6033
  function ReferenceChip({ reference, waiting }) {
6005
6034
  const host = useRecordsUi();
6006
6035
  const words2 = reference.label ?? (reference.token === "record" ? waiting ?? "Loading\u2026" : WITHHELD_ENTITY_LABEL);
6007
6036
  const drawn = host.renderReference ? host.renderReference({ ...reference, label: reference.label ?? words2 }) : null;
6037
+ const look = useEmbeddedLook();
6038
+ if (look?.plainRelation) {
6039
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
6040
+ "span",
6041
+ {
6042
+ className: (0, import_design_system18.cn)(
6043
+ "inline-flex max-w-full min-w-0 items-center gap-1.5 text-sm text-foreground hover:underline [&_a]:text-inherit [&_a]:no-underline [&_a:hover]:underline",
6044
+ reference.archived && "opacity-70"
6045
+ ),
6046
+ "data-records-reference-chip": reference.token,
6047
+ "data-records-reference-plain": "",
6048
+ "data-records-reference-archived": reference.archived ? "" : void 0,
6049
+ title: reference.archived ? ARCHIVED_REFERENCE_TIP : words2,
6050
+ children: [
6051
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { "aria-hidden": "true", "data-records-reference-icon": "", className: "inline-flex size-4 shrink-0 items-center justify-center text-muted-foreground", children: glyphOf(reference.icon) ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "text-sm leading-none", children: reference.icon }) : reference.icon && host.renderIcon?.(reference.icon) || /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(PageGlyph, {}) }),
6052
+ drawn ?? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "truncate", children: words2 }),
6053
+ reference.archived ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "shrink-0 text-muted-foreground", children: ARCHIVED_REFERENCE_WORD }) : null
6054
+ ]
6055
+ }
6056
+ );
6057
+ }
6008
6058
  return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
6009
6059
  import_design_system18.Badge,
6010
6060
  {
@@ -6735,7 +6785,7 @@ function renderValue(field2, value, document2, labels, stillWaitingFor, look) {
6735
6785
  "data-records-choice-chip": "",
6736
6786
  ...chip.tinted ? { "data-records-choice-tint": "" } : {},
6737
6787
  children: [
6738
- look?.choiceDot ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { "aria-hidden": "true", "data-records-choice-dot": "", className: (0, import_design_system21.cn)("mr-1.5 inline-block size-1.5 shrink-0 rounded-full", chip.dot) }) : null,
6788
+ look?.choiceDot ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { "aria-hidden": "true", "data-matrx-pill-ink": "", "data-records-choice-dot": "", className: (0, import_design_system21.cn)("mr-1.5 inline-block size-1.5 shrink-0 rounded-full", chip.dot) }) : null,
6739
6789
  statusMark(field2, item, Array.isArray(value) ? void 0 : document2),
6740
6790
  scalarText(field2, item, labels, Array.isArray(value) ? void 0 : stillWaitingFor)
6741
6791
  ]
@@ -6890,7 +6940,7 @@ function RecordValue({
6890
6940
  const shape = shown4 && (shown4.id === "date" || shown4.id === "datetime") && isDateField(field2) ? dateFormatFor(field2, value) : void 0;
6891
6941
  const dated = shape ? { ...shape, ...shown4?.options ? { options: shown4.options } : {} } : void 0;
6892
6942
  const formatted = shown4 ? (0, import_data_table4.formatColumnValue)({ format: dated ?? shown4 }, value) : null;
6893
- if (formatted) return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(FormattedValue, { value, format: dated ?? shown4 });
6943
+ if (formatted && !(embeddedLook?.blankEmpty && formatted.empty)) return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(FormattedValue, { value, format: dated ?? shown4 });
6894
6944
  return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_jsx_runtime26.Fragment, { children: renderValue(field2, value, document2, labels, stillWaitingFor, embeddedLook) });
6895
6945
  }
6896
6946
  var ONE_FIELD_ARRAYS = /* @__PURE__ */ new WeakMap();
@@ -16466,7 +16516,7 @@ function opensOnKey(event) {
16466
16516
  }
16467
16517
  return true;
16468
16518
  }
16469
- function withOpenRecord(columns, onOpen, nameOf, place = "end", hrefOf) {
16519
+ function withOpenRecord(columns, onOpen, nameOf2, place = "end", hrefOf) {
16470
16520
  if (!onOpen) return columns;
16471
16521
  return columns.map((column, index) => {
16472
16522
  const original = column.cell;
@@ -16476,8 +16526,8 @@ function withOpenRecord(columns, onOpen, nameOf, place = "end", hrefOf) {
16476
16526
  {
16477
16527
  type: "button",
16478
16528
  "data-records-open-record": row.id,
16479
- "aria-label": openRecordLabel(nameOf(row)),
16480
- title: `${openRecordLabel(nameOf(row))} (Space)`,
16529
+ "aria-label": openRecordLabel(nameOf2(row)),
16530
+ title: `${openRecordLabel(nameOf2(row))} (Space)`,
16481
16531
  className: "shrink-0 rounded px-1 text-xs leading-5 text-muted-foreground opacity-40 hover:bg-muted hover:text-foreground focus-visible:opacity-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring group-hover/matrx-row:opacity-100",
16482
16532
  onClick: (event) => {
16483
16533
  event.stopPropagation();
@@ -22570,7 +22620,7 @@ function GridBody({
22570
22620
  [storePaged, query, queryTotal, classicInCard, records.data?.total]
22571
22621
  );
22572
22622
  const showAddLine = mayAddRow && rows.length > 0;
22573
- const showSummaryLine = rows.length > 0 && (!merged || Object.keys(chosenSummaries).length > 0);
22623
+ const showSummaryLine = rows.length > 0 && (embedded ? Object.keys(chosenSummaries).length > 0 : !merged || Object.keys(chosenSummaries).length > 0);
22574
22624
  const footerFace = JSON.stringify([
22575
22625
  showAddLine ? added.busy : null,
22576
22626
  showSummaryLine ? [chosenSummaries, summaries.values, summaries.rowCount, summaries.loading] : null
@@ -22753,7 +22803,7 @@ function GridBody({
22753
22803
  mode: phone ? "sheet" : toolbarFold2 >= 3 ? "menu" : "inline",
22754
22804
  pinned: /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)(import_jsx_runtime68.Fragment, { children: [
22755
22805
  /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(UndoRedoLive, { source: undoSource }),
22756
- !readOnly && rights.write ? /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
22806
+ !embedded && !readOnly && rights.write ? /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
22757
22807
  NewFromTemplateMenu,
22758
22808
  {
22759
22809
  tableId,
@@ -22765,7 +22815,8 @@ function GridBody({
22765
22815
  // NEW RECORD NEVER LEAVES THE ROW (live walk 2026-10-05: at 1440 px with the
22766
22816
  // side chat open it and "From template" both vanished behind the "…"). When the
22767
22817
  // row is short, "From template", undo and the rest ride the "…"; this stays.
22768
- ...!readOnly && rights.write ? {
22818
+ // EMBEDDED: the "+ New page" line under the table is the create action.
22819
+ ...!embedded && !readOnly && rights.write ? {
22769
22820
  primary: /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
22770
22821
  NewRecordControl,
22771
22822
  {
@@ -22830,7 +22881,7 @@ function GridBody({
22830
22881
  // 2026-09-28: with the Forms rail open "New record" read "New reco", faded
22831
22882
  // under the slot's edge). Pinned, it sticks to the row's right edge and what
22832
22883
  // scrolls passes under it — the merged grid's rule, not a second one.
22833
- ...!readOnly && rights.write ? {
22884
+ ...!embedded && !readOnly && rights.write ? {
22834
22885
  overflow: {
22835
22886
  mode: "inline",
22836
22887
  pinned: /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(import_design_system58.Button, { size: "sm", className: "shrink-0", disabled: editingBusy, onClick: () => void addRecord(), children: editingBusy ? "Adding\u2026" : "New record" })
@@ -23081,7 +23132,8 @@ function GridBody({
23081
23132
  tableClassName: (0, import_design_system58.cn)(
23082
23133
  !look.wrap && "[&_tbody_td]:max-w-[28rem] [&_tbody_td]:overflow-hidden [&_tbody_td]:text-ellipsis [&_tbody_td]:whitespace-nowrap! [&_tbody_td_*]:whitespace-nowrap!",
23083
23134
  look.fit === "scroll" && "sm:[&>table]:w-max! sm:[&>table]:max-w-none! sm:[&>table]:min-w-full!",
23084
- embedded && EMBEDDED_TABLE_CLASS
23135
+ embedded && EMBEDDED_TABLE_CLASS,
23136
+ embedded && !showSummaryLine && EMBEDDED_PLAIN_FOOTER_CLASS
23085
23137
  ),
23086
23138
  footerRows,
23087
23139
  ...embedded ? { copy: false } : copyConfig ? { copy: copyConfig } : {},
@@ -31587,7 +31639,11 @@ function ViewSwitcher({
31587
31639
  onUseSort: (sort) => change({ sorts: [sort], order: "sorted" })
31588
31640
  } : {}
31589
31641
  }
31590
- } : {}
31642
+ } : (view.sorts?.length ?? 0) > 0 || local.sorts ? (
31643
+ /* A VIEW THE HOST HOLDS INLINE (Spaces) has no saved id but still has its sort: the
31644
+ grid opens in it, never in the table's own order. */
31645
+ { viewOrder: { viewId: null, order: null, sorts: local.sorts ?? view.sorts ?? [] } }
31646
+ ) : {}
31591
31647
  }
31592
31648
  ) : /* @__PURE__ */ (0, import_jsx_runtime105.jsx)(
31593
31649
  Board,
@@ -45863,22 +45919,22 @@ function RailFrame({
45863
45919
  return /* @__PURE__ */ (0, import_jsx_runtime152.jsx)("aside", { "data-rail-column": "", className: "w-[26rem] shrink-0 overflow-y-auto rounded-md border p-3", children });
45864
45920
  }
45865
45921
  function filterInWords(filter, fields) {
45866
- const nameOf = (key) => {
45922
+ const nameOf2 = (key) => {
45867
45923
  const field2 = fields.find((f) => f.key === key);
45868
45924
  return field2 ? fieldName(field2) : (0, import_text_case17.humanizeIdentifier)(key);
45869
45925
  };
45870
45926
  const parts = Object.keys(filter).map((key) => {
45871
45927
  const value = filter[key];
45872
- if (value === null || value === void 0) return `${nameOf(key)} is not filled in`;
45928
+ if (value === null || value === void 0) return `${nameOf2(key)} is not filled in`;
45873
45929
  if (typeof value === "object") {
45874
45930
  const from = (value.from ?? "").toString().trim();
45875
45931
  const to = (value.to ?? "").toString().trim();
45876
- if (from !== "" && to !== "") return `${nameOf(key)} from ${from} up to ${to}`;
45877
- if (from !== "") return `${nameOf(key)} from ${from} onwards`;
45878
- if (to !== "") return `${nameOf(key)} up to ${to}`;
45879
- return `${nameOf(key)} in a period nobody named`;
45932
+ if (from !== "" && to !== "") return `${nameOf2(key)} from ${from} up to ${to}`;
45933
+ if (from !== "") return `${nameOf2(key)} from ${from} onwards`;
45934
+ if (to !== "") return `${nameOf2(key)} up to ${to}`;
45935
+ return `${nameOf2(key)} in a period nobody named`;
45880
45936
  }
45881
- return `${nameOf(key)} is ${String(value)}`;
45937
+ return `${nameOf2(key)} is ${String(value)}`;
45882
45938
  });
45883
45939
  if (parts.length === 0) return "";
45884
45940
  if (parts.length === 1) return parts[0];