@ai-matrx/records-ui 0.93.153 → 0.95.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.
@@ -37,10 +37,13 @@ interface TableScopeProps {
37
37
  children: ReactNode;
38
38
  /** Shown while the Table's organization is unknown, or when no Table is chosen. */
39
39
  fallback?: ReactNode;
40
+ /** Shown when the list of Tables could not be read, or the Table is not one this person can
41
+ * open — a scope that never resolves must say so, never wait forever. Defaults to `fallback`. */
42
+ unavailable?: ReactNode;
40
43
  tables?: TablesAnywhere;
41
44
  }
42
45
  /** The record store, bound to the organization the chosen Table lives in. */
43
- declare function TableScope({ dataSource, userId, tableId, children, fallback, tables }: TableScopeProps): react.JSX.Element;
46
+ declare function TableScope({ dataSource, userId, tableId, children, fallback, unavailable, tables }: TableScopeProps): react.JSX.Element;
44
47
  interface ColumnValuesEditorProps {
45
48
  tableId: string;
46
49
  /** `{field key: stored value}` — what the step matches on or writes. */
package/dist/pickers.d.ts CHANGED
@@ -37,10 +37,13 @@ interface TableScopeProps {
37
37
  children: ReactNode;
38
38
  /** Shown while the Table's organization is unknown, or when no Table is chosen. */
39
39
  fallback?: ReactNode;
40
+ /** Shown when the list of Tables could not be read, or the Table is not one this person can
41
+ * open — a scope that never resolves must say so, never wait forever. Defaults to `fallback`. */
42
+ unavailable?: ReactNode;
40
43
  tables?: TablesAnywhere;
41
44
  }
42
45
  /** The record store, bound to the organization the chosen Table lives in. */
43
- declare function TableScope({ dataSource, userId, tableId, children, fallback, tables }: TableScopeProps): react.JSX.Element;
46
+ declare function TableScope({ dataSource, userId, tableId, children, fallback, unavailable, tables }: TableScopeProps): react.JSX.Element;
44
47
  interface ColumnValuesEditorProps {
45
48
  tableId: string;
46
49
  /** `{field key: stored value}` — what the step matches on or writes. */
package/dist/pickers.js CHANGED
@@ -398,6 +398,63 @@ function BarcodeControl({ value, onChange, disabled, id }) {
398
398
  ] });
399
399
  }
400
400
 
401
+ // src/choiceLooks.ts
402
+ import {
403
+ CHOICE_CHIP_CLASS,
404
+ NEUTRAL_CHIP_CLASS,
405
+ STYLE_COLORS
406
+ } from "@ai-matrx/design-system/data-table";
407
+ function displayFormatOf(field) {
408
+ const raw = field.display_format;
409
+ if (!raw || typeof raw !== "object") return null;
410
+ const id = raw.id;
411
+ if (typeof id !== "string" || id === "") return null;
412
+ const options = raw.options;
413
+ return { id, options: options && typeof options === "object" ? options : {} };
414
+ }
415
+ function isStyleColor(v) {
416
+ return typeof v === "string" && STYLE_COLORS.includes(v);
417
+ }
418
+ function choiceLooksOf(field) {
419
+ const display = displayFormatOf(field);
420
+ const choices = display?.options["choices"];
421
+ if (!Array.isArray(choices)) return [];
422
+ const out = [];
423
+ for (const c of choices) {
424
+ if (!c || typeof c !== "object") continue;
425
+ const value = c.value;
426
+ if (typeof value !== "string" || value.trim() === "") continue;
427
+ const color = c.color;
428
+ const label = c.label;
429
+ out.push({
430
+ value: value.trim(),
431
+ ...typeof label === "string" && label.trim() !== "" ? { label: label.trim() } : {},
432
+ ...isStyleColor(color) ? { color } : {}
433
+ });
434
+ }
435
+ return out;
436
+ }
437
+ function choiceWord(value) {
438
+ return String(value ?? "").trim().toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
439
+ }
440
+ function storedChoiceColor(field, value) {
441
+ if (value === null || value === void 0 || value === "") return void 0;
442
+ const word = choiceWord(value);
443
+ if (word === "") return void 0;
444
+ for (const look of choiceLooksOf(field)) {
445
+ if (!look.color) continue;
446
+ if (choiceWord(look.value) === word || look.label && choiceWord(look.label) === word) return look.color;
447
+ }
448
+ return void 0;
449
+ }
450
+ function choiceChipLookOf(field, ...words) {
451
+ for (const word of words) {
452
+ const color = storedChoiceColor(field, word);
453
+ if (color) return { className: CHOICE_CHIP_CLASS[color], color };
454
+ }
455
+ return { className: NEUTRAL_CHIP_CLASS, color: null };
456
+ }
457
+
401
458
  // src/parity.ts
402
459
  import {
403
460
  KERNEL_TABLES,
@@ -2440,7 +2497,7 @@ function PersonPicker({ field, value, onChange, disabled, id, className, autoOpe
2440
2497
 
2441
2498
  // src/presentation.ts
2442
2499
  import {
2443
- STYLE_COLORS,
2500
+ STYLE_COLORS as STYLE_COLORS2,
2444
2501
  parseTableStyle,
2445
2502
  tableStyleIsEmpty
2446
2503
  } from "@ai-matrx/design-system/data-table";
@@ -2512,7 +2569,7 @@ import { getFieldFormat as getFieldFormat3, parseFieldInput } from "@ai-matrx/de
2512
2569
  // src/formattedValue.tsx
2513
2570
  import { useRef as useRef7 } from "react";
2514
2571
  import { FormattedCell } from "@ai-matrx/design-system/data-table";
2515
- import { formatFieldValue as formatFieldValue2, getFieldFormat as getFieldFormat2 } from "@ai-matrx/design-system/field-formats";
2572
+ import { formatFieldValue as formatFieldValue2, formatPhone, getFieldFormat as getFieldFormat2 } from "@ai-matrx/design-system/field-formats";
2516
2573
  import { cn as cn10 } from "@ai-matrx/design-system";
2517
2574
  import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
2518
2575
  var LINK = "inline-flex min-w-0 items-center gap-1 text-primary hover:underline";
@@ -2652,16 +2709,6 @@ function FormattedValue({
2652
2709
  if (!result.ok || result.empty || !def?.rich) return /* @__PURE__ */ jsx13(FormattedCell, { result });
2653
2710
  return rich(def.id, result.text, value, format) ?? /* @__PURE__ */ jsx13(FormattedCell, { result });
2654
2711
  }
2655
- function formatPhone(raw) {
2656
- const text = raw.trim();
2657
- const digits = text.replace(/\D/g, "");
2658
- if (/[a-z]/i.test(text.replace(/ext\.?|x/gi, ""))) return text;
2659
- if (digits.length === 10 && !text.startsWith("+")) return `(${digits.slice(0, 3)}) ${digits.slice(3, 6)}-${digits.slice(6)}`;
2660
- if (digits.length === 11 && digits.startsWith("1") && (text.startsWith("+1") || text.startsWith("1") || !text.startsWith("+"))) {
2661
- return `+1 (${digits.slice(1, 4)}) ${digits.slice(4, 7)}-${digits.slice(7)}`;
2662
- }
2663
- return text;
2664
- }
2665
2712
  function linkChipText(raw) {
2666
2713
  try {
2667
2714
  const url = new URL(raw.includes("://") ? raw : `https://${raw}`);
@@ -2946,63 +2993,6 @@ function useChoiceNudge(enabled = true) {
2946
2993
  return nudge;
2947
2994
  }
2948
2995
 
2949
- // src/choiceLooks.ts
2950
- import {
2951
- CHOICE_CHIP_CLASS,
2952
- NEUTRAL_CHIP_CLASS,
2953
- STYLE_COLORS as STYLE_COLORS2
2954
- } from "@ai-matrx/design-system/data-table";
2955
- function displayFormatOf(field) {
2956
- const raw = field.display_format;
2957
- if (!raw || typeof raw !== "object") return null;
2958
- const id = raw.id;
2959
- if (typeof id !== "string" || id === "") return null;
2960
- const options = raw.options;
2961
- return { id, options: options && typeof options === "object" ? options : {} };
2962
- }
2963
- function isStyleColor(v) {
2964
- return typeof v === "string" && STYLE_COLORS2.includes(v);
2965
- }
2966
- function choiceLooksOf(field) {
2967
- const display = displayFormatOf(field);
2968
- const choices = display?.options["choices"];
2969
- if (!Array.isArray(choices)) return [];
2970
- const out = [];
2971
- for (const c of choices) {
2972
- if (!c || typeof c !== "object") continue;
2973
- const value = c.value;
2974
- if (typeof value !== "string" || value.trim() === "") continue;
2975
- const color = c.color;
2976
- const label = c.label;
2977
- out.push({
2978
- value: value.trim(),
2979
- ...typeof label === "string" && label.trim() !== "" ? { label: label.trim() } : {},
2980
- ...isStyleColor(color) ? { color } : {}
2981
- });
2982
- }
2983
- return out;
2984
- }
2985
- function choiceWord(value) {
2986
- return String(value ?? "").trim().toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
2987
- }
2988
- function storedChoiceColor(field, value) {
2989
- if (value === null || value === void 0 || value === "") return void 0;
2990
- const word = choiceWord(value);
2991
- if (word === "") return void 0;
2992
- for (const look of choiceLooksOf(field)) {
2993
- if (!look.color) continue;
2994
- if (choiceWord(look.value) === word || look.label && choiceWord(look.label) === word) return look.color;
2995
- }
2996
- return void 0;
2997
- }
2998
- function choiceChipLookOf(field, ...words) {
2999
- for (const word of words) {
3000
- const color = storedChoiceColor(field, word);
3001
- if (color) return { className: CHOICE_CHIP_CLASS[color], color };
3002
- }
3003
- return { className: NEUTRAL_CHIP_CLASS, color: null };
3004
- }
3005
-
3006
2996
  // src/editors.tsx
3007
2997
  import { Fragment as Fragment4, jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
3008
2998
  var CHOICE_EDITOR_ADDS_WHAT_IS_TYPED = true;
@@ -3904,25 +3894,43 @@ function madeOn(stamp) {
3904
3894
 
3905
3895
  // src/TablePickers.tsx
3906
3896
  import { Fragment as Fragment5, jsx as jsx19, jsxs as jsxs16 } from "react/jsx-runtime";
3897
+ var SHARED_FOR_MS = 5e3;
3898
+ var sharedReads = /* @__PURE__ */ new WeakMap();
3899
+ function readTablesAnywhere(dataSource) {
3900
+ const held = sharedReads.get(dataSource);
3901
+ if (held && Date.now() - held.at < SHARED_FOR_MS) return held.read;
3902
+ const read = Promise.resolve(dataSource.rpc("data_home_tables", {}, { schema: "custom" })).then(
3903
+ ({ data, error }) => {
3904
+ if (error) {
3905
+ return {
3906
+ loading: false,
3907
+ error: refusalSentence({ message: String(error["message"] ?? "") }) || "Tables could not be read.",
3908
+ rows: []
3909
+ };
3910
+ }
3911
+ const rows = (Array.isArray(data) ? data : []).slice();
3912
+ rows.sort((a, b) => a.table_name.localeCompare(b.table_name));
3913
+ return { loading: false, error: null, rows };
3914
+ },
3915
+ (thrown) => ({
3916
+ loading: false,
3917
+ error: String(thrown?.message ?? thrown) || "Tables could not be read.",
3918
+ rows: []
3919
+ })
3920
+ );
3921
+ sharedReads.set(dataSource, { at: Date.now(), read });
3922
+ void read.then((result) => {
3923
+ if (result.error && sharedReads.get(dataSource)?.read === read) sharedReads.delete(dataSource);
3924
+ });
3925
+ return read;
3926
+ }
3907
3927
  function useTablesAnywhere(dataSource) {
3908
3928
  const [state, setState] = useState16({ loading: true, error: null, rows: [] });
3909
3929
  useEffect12(() => {
3910
3930
  let live = true;
3911
- void Promise.resolve(dataSource.rpc("data_home_tables", {}, { schema: "custom" })).then(
3912
- ({ data, error }) => {
3913
- if (!live) return;
3914
- if (error) {
3915
- setState({ loading: false, error: refusalSentence({ message: String(error["message"] ?? "") }) || "Tables could not be read.", rows: [] });
3916
- return;
3917
- }
3918
- const rows = (Array.isArray(data) ? data : []).slice();
3919
- rows.sort((a, b) => a.table_name.localeCompare(b.table_name));
3920
- setState({ loading: false, error: null, rows });
3921
- },
3922
- (thrown) => {
3923
- if (live) setState({ loading: false, error: String(thrown?.message ?? thrown), rows: [] });
3924
- }
3925
- );
3931
+ void readTablesAnywhere(dataSource).then((result) => {
3932
+ if (live) setState(result);
3933
+ });
3926
3934
  return () => {
3927
3935
  live = false;
3928
3936
  };
@@ -3962,10 +3970,11 @@ function TablePicker({ dataSource, value, onChange, disabled, tables }) {
3962
3970
  missing && /* @__PURE__ */ jsx19("p", { className: "text-[11px] text-destructive", children: "This table is archived or not shared with you." })
3963
3971
  ] });
3964
3972
  }
3965
- function TableScope({ dataSource, userId, tableId, children, fallback = null, tables }) {
3973
+ function TableScope({ dataSource, userId, tableId, children, fallback = null, unavailable, tables }) {
3966
3974
  const own3 = useTablesAnywhere(dataSource);
3967
3975
  const list = tables ?? own3;
3968
3976
  const organizationId = list.rows.find((t) => t.table_id === tableId)?.organization_id ?? null;
3977
+ if (tableId && !organizationId && !list.loading) return /* @__PURE__ */ jsx19(Fragment5, { children: unavailable ?? fallback });
3969
3978
  if (!tableId || !organizationId) return /* @__PURE__ */ jsx19(Fragment5, { children: fallback });
3970
3979
  return /* @__PURE__ */ jsx19(RecordsProvider2, { config: { dataSource, actor: personActor(userId), organizationId }, children });
3971
3980
  }
@@ -4394,6 +4403,9 @@ function WholeValueCell({ words, pointer }) {
4394
4403
  ] });
4395
4404
  }
4396
4405
 
4406
+ // src/values.tsx
4407
+ import { formatPhone as formatPhone2 } from "@ai-matrx/design-system/field-formats";
4408
+
4397
4409
  // src/ReferenceChips.tsx
4398
4410
  import { entityRefsOf as entityRefsOf2 } from "@ai-matrx/records";
4399
4411
  import { Badge as Badge4, cn as cn15 } from "@ai-matrx/design-system";
@@ -4638,7 +4650,7 @@ function renderValue(field, value, document2, labels, stillWaitingFor) {
4638
4650
  title: value,
4639
4651
  "data-records-phone": "",
4640
4652
  onClick: (event) => event.stopPropagation(),
4641
- children: formatPhone(value)
4653
+ children: formatPhone2(value)
4642
4654
  }
4643
4655
  );
4644
4656
  }
@@ -4704,7 +4716,17 @@ function ColumnValuesText({
4704
4716
  value
4705
4717
  }) {
4706
4718
  if (!tableId) return /* @__PURE__ */ jsx24(Fragment7, { children: "\u2014" });
4707
- return /* @__PURE__ */ jsx24(TableScope, { dataSource, userId, tableId, fallback: /* @__PURE__ */ jsx24(Fragment7, { children: "\u2026" }), children: /* @__PURE__ */ jsx24(RecordLabelProvider, { children: /* @__PURE__ */ jsx24(ColumnValuesWords, { tableId, value }) }) });
4719
+ return /* @__PURE__ */ jsx24(
4720
+ TableScope,
4721
+ {
4722
+ dataSource,
4723
+ userId,
4724
+ tableId,
4725
+ fallback: /* @__PURE__ */ jsx24(Fragment7, { children: "\u2026" }),
4726
+ unavailable: /* @__PURE__ */ jsx24(Fragment7, { children: "Couldn't load this table's columns" }),
4727
+ children: /* @__PURE__ */ jsx24(RecordLabelProvider, { children: /* @__PURE__ */ jsx24(ColumnValuesWords, { tableId, value }) })
4728
+ }
4729
+ );
4708
4730
  }
4709
4731
  function ColumnValuesWords({ tableId, value }) {
4710
4732
  const fields = useFields3(tableId);
@@ -4733,7 +4755,17 @@ function RecordNameText({
4733
4755
  recordId
4734
4756
  }) {
4735
4757
  if (!tableId || !recordId) return /* @__PURE__ */ jsx24(Fragment7, { children: "\u2014" });
4736
- return /* @__PURE__ */ jsx24(TableScope, { dataSource, userId, tableId, fallback: /* @__PURE__ */ jsx24(Fragment7, { children: "\u2026" }), children: /* @__PURE__ */ jsx24(RecordNameWords, { tableId, recordId }) });
4758
+ return /* @__PURE__ */ jsx24(
4759
+ TableScope,
4760
+ {
4761
+ dataSource,
4762
+ userId,
4763
+ tableId,
4764
+ fallback: /* @__PURE__ */ jsx24(Fragment7, { children: "\u2026" }),
4765
+ unavailable: /* @__PURE__ */ jsx24(Fragment7, { children: "Couldn't load this record" }),
4766
+ children: /* @__PURE__ */ jsx24(RecordNameWords, { tableId, recordId })
4767
+ }
4768
+ );
4737
4769
  }
4738
4770
  function RecordNameWords({ tableId, recordId }) {
4739
4771
  const table = useTable3(tableId);