@ai-matrx/records-ui 0.115.69 → 0.115.71

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/pickers.js CHANGED
@@ -50,11 +50,7 @@ import { STYLE_COLORS as STYLE_COLORS2, STYLE_COLOR_LABELS, SWATCH_CLASS } from
50
50
 
51
51
  // src/choiceLooks.ts
52
52
  import { newerKindOf } from "@ai-matrx/records";
53
- import {
54
- CHOICE_CHIP_CLASS,
55
- NEUTRAL_CHIP_CLASS,
56
- STYLE_COLORS
57
- } from "@ai-matrx/design-system/data-table";
53
+ import { CHOICE_CHIP_CLASS, NEUTRAL_CHIP_CLASS, STYLE_COLORS } from "@ai-matrx/design-system/data-table/table-style";
58
54
  function displayFormatOf(field) {
59
55
  const raw = field.display_format;
60
56
  if (!raw || typeof raw !== "object") return null;
@@ -656,8 +652,7 @@ function lockedStructure(base) {
656
652
  return { ...base, structure: false, why: (what) => what === "structure" ? DATABASE_LOCKED_REASON : base.why(what) };
657
653
  }
658
654
 
659
- // src/host.tsx
660
- import { jsx as jsx2 } from "react/jsx-runtime";
655
+ // src/tableRights.ts
661
656
  function tableRights(may, overallReason) {
662
657
  return {
663
658
  ...may,
@@ -666,6 +661,9 @@ function tableRights(may, overallReason) {
666
661
  };
667
662
  }
668
663
  var NO_RIGHTS = tableRights(NOT_ANSWERED_YET);
664
+
665
+ // src/host.tsx
666
+ import { jsx as jsx2 } from "react/jsx-runtime";
669
667
  var NO_MEMBERS_REASON = "This app cannot offer the people in your organization on this screen yet, so there is nobody to pick. Type the person's name into a text field for now, and tell us \u2014 it is on our list, not yours.";
670
668
  var NO_UPLOAD_REASON = "This screen cannot take a file yet, so there is no chooser here rather than one that loses what you pick. Put a link to the file in a text field for now. It is on our list, not yours.";
671
669
  var HostContext = createContext(null);
@@ -956,6 +954,7 @@ import {
956
954
  statusGroupOf
957
955
  } from "@ai-matrx/records";
958
956
  import { BasicInput as BasicInput2, cn as cn4 } from "@ai-matrx/design-system";
957
+ import { OutboundLink } from "@ai-matrx/kit/outbound-react";
959
958
  import { Fragment as Fragment2, jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
960
959
  var own = (event) => event.stopPropagation();
961
960
  function newerKindValue(field, value, opts = {}) {
@@ -1004,11 +1003,9 @@ function AddressLink({ value }) {
1004
1003
  const href = addressMapUrl(value);
1005
1004
  if (!words || !href) return /* @__PURE__ */ jsx6("span", { className: "text-muted-foreground", children: "\u2014" });
1006
1005
  return /* @__PURE__ */ jsxs5(
1007
- "a",
1006
+ OutboundLink,
1008
1007
  {
1009
1008
  href,
1010
- target: "_blank",
1011
- rel: "noopener noreferrer",
1012
1009
  className: "inline-flex min-w-0 items-center gap-1 text-primary hover:underline",
1013
1010
  title: "Open in maps",
1014
1011
  "data-records-address": "",
@@ -1056,7 +1053,7 @@ function marks(text, key) {
1056
1053
  const link = /^\[([^\]]+)\]\(([^)\s]+)\)$/.exec(tok);
1057
1054
  const href = safeLinkHref(link?.[2] ?? "");
1058
1055
  out.push(
1059
- href ? /* @__PURE__ */ jsx6("a", { href, target: "_blank", rel: "noopener noreferrer", className: "text-primary underline-offset-2 hover:underline", onClick: own, children: link?.[1] }, k) : link?.[1] ?? tok
1056
+ href ? /* @__PURE__ */ jsx6(OutboundLink, { href, className: "text-primary underline-offset-2 hover:underline", onClick: own, children: link?.[1] }, k) : link?.[1] ?? tok
1060
1057
  );
1061
1058
  } else out.push(/* @__PURE__ */ jsx6("em", { children: tok.slice(1, -1) }, k));
1062
1059
  last = at + tok.length;
@@ -2140,7 +2137,8 @@ import { useCallback as useCallback2, useEffect as useEffect6, useMemo as useMem
2140
2137
  import { withTablePlacement } from "@ai-matrx/records";
2141
2138
  import { useRecordsClient as useRecordsClient2, useTables } from "@ai-matrx/records/react";
2142
2139
  import { Checkbox, cn as cn8 } from "@ai-matrx/design-system";
2143
- import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
2140
+
2141
+ // src/tablePickerEntries.ts
2144
2142
  var PLATFORM_TABLE_PREFIX = "records_ui_";
2145
2143
  function keptByPlatform(table) {
2146
2144
  return table.platform_owned === true || table.kept_by_the_app === true;
@@ -2184,6 +2182,9 @@ function madeOn(stamp) {
2184
2182
  if (Number.isNaN(at.getTime())) return null;
2185
2183
  return new Intl.DateTimeFormat(void 0, { month: "short", day: "numeric", year: "numeric" }).format(at);
2186
2184
  }
2185
+
2186
+ // src/tablePicking.tsx
2187
+ import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
2187
2188
  function usePickerTables() {
2188
2189
  const client = useRecordsClient2();
2189
2190
  const tables = useTables();
@@ -2848,10 +2849,7 @@ import { Badge as Badge5, cn as cn18 } from "@ai-matrx/design-system";
2848
2849
  import { createContext as createContext2, useContext as useContext2 } from "react";
2849
2850
 
2850
2851
  // src/presentation.ts
2851
- import { parseTableStyle, tableStyleIsEmpty } from "@ai-matrx/design-system/data-table/table-style";
2852
- import {
2853
- COLOR_ROTATION
2854
- } from "@ai-matrx/design-system/data-table";
2852
+ import { COLOR_ROTATION, parseTableStyle, tableStyleIsEmpty } from "@ai-matrx/design-system/data-table/table-style";
2855
2853
  import { getFieldFormat } from "@ai-matrx/design-system/field-formats";
2856
2854
  import { newerKindOf as newerKindOf4, ratingMaxOf } from "@ai-matrx/records";
2857
2855
  var DRAWN_KINDS = /* @__PURE__ */ new Set(["select", "multi_select", "relation", "member", "person", "attachment", "file", "entity_reference", "checkbox", "boolean", "signature", "json"]);
@@ -3741,6 +3739,7 @@ import { wholeValueOf } from "@ai-matrx/records/core";
3741
3739
  import { useEffect as useEffect10, useState as useState15 } from "react";
3742
3740
  import { wholeValueSize } from "@ai-matrx/records/core";
3743
3741
  import { BasicTextarea as BasicTextarea2 } from "@ai-matrx/design-system";
3742
+ import { OutboundLink as OutboundLink2 } from "@ai-matrx/kit/outbound-react";
3744
3743
  import { jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
3745
3744
  var WHOLE_VALUE_UNBOUND = "The whole text is kept as a file, and this screen has no way to open files yet.";
3746
3745
  function wholeValueLine(pointer) {
@@ -3755,7 +3754,7 @@ function WholeValueCell({ words, pointer }) {
3755
3754
  words,
3756
3755
  "\u2026"
3757
3756
  ] }),
3758
- href ? host.Link ? host.Link({ href, children: line, className: "shrink-0 text-xs text-primary underline-offset-2 hover:underline" }) : /* @__PURE__ */ jsx18("a", { className: "shrink-0 text-xs text-primary underline-offset-2 hover:underline", href, target: "_blank", rel: "noreferrer", children: line }) : /* @__PURE__ */ jsx18("span", { className: "shrink-0 text-xs italic text-muted-foreground", title: WHOLE_VALUE_UNBOUND, children: `${wholeValueSize(pointer)} in a file` })
3757
+ href ? host.Link ? host.Link({ href, children: line, className: "shrink-0 text-xs text-primary underline-offset-2 hover:underline" }) : /* @__PURE__ */ jsx18(OutboundLink2, { className: "shrink-0 text-xs text-primary underline-offset-2 hover:underline", href, children: line }) : /* @__PURE__ */ jsx18("span", { className: "shrink-0 text-xs italic text-muted-foreground", title: WHOLE_VALUE_UNBOUND, children: `${wholeValueSize(pointer)} in a file` })
3759
3758
  ] });
3760
3759
  }
3761
3760
 
@@ -3767,6 +3766,7 @@ import { useRef as useRef8 } from "react";
3767
3766
  import { FormattedCell } from "@ai-matrx/design-system/data-table";
3768
3767
  import { formatFieldValue as formatFieldValue2, formatPhone, getFieldFormat as getFieldFormat2 } from "@ai-matrx/design-system/field-formats";
3769
3768
  import { cn as cn15 } from "@ai-matrx/design-system";
3769
+ import { OutboundLink as OutboundLink3 } from "@ai-matrx/kit/outbound-react";
3770
3770
  import { jsx as jsx19, jsxs as jsxs17 } from "react/jsx-runtime";
3771
3771
  var LINK = "inline-flex min-w-0 items-center gap-1 text-primary hover:underline";
3772
3772
  var own2 = (event) => event.stopPropagation();
@@ -3837,16 +3837,14 @@ function rich(id, text, raw, format) {
3837
3837
  case "email":
3838
3838
  return /* @__PURE__ */ jsx19("a", { href: `mailto:${text}`, className: LINK, onClick: own2, children: /* @__PURE__ */ jsx19("span", { className: "truncate", children: text }) });
3839
3839
  case "url":
3840
- return /* @__PURE__ */ jsx19("a", { href: text.includes("://") ? text : `https://${text}`, target: "_blank", rel: "noopener noreferrer", className: LINK, onClick: own2, children: /* @__PURE__ */ jsx19("span", { className: "truncate", children: text }) });
3840
+ return /* @__PURE__ */ jsx19(OutboundLink3, { href: text.includes("://") ? text : `https://${text}`, className: LINK, onClick: own2, children: /* @__PURE__ */ jsx19("span", { className: "truncate", children: text }) });
3841
3841
  case "phone":
3842
3842
  return /* @__PURE__ */ jsx19("a", { href: `tel:${text.replace(/[^\d+]/g, "")}`, className: LINK, onClick: own2, title: text, children: /* @__PURE__ */ jsx19("span", { className: "truncate tabular-nums", children: formatPhone(text) }) });
3843
3843
  case "address":
3844
3844
  return /* @__PURE__ */ jsx19(
3845
- "a",
3845
+ OutboundLink3,
3846
3846
  {
3847
3847
  href: `https://www.google.com/maps/search/?api=1&query=${encodeURIComponent(text)}`,
3848
- target: "_blank",
3849
- rel: "noopener noreferrer",
3850
3848
  className: LINK,
3851
3849
  title: "Open in maps",
3852
3850
  onClick: own2,
@@ -4016,6 +4014,7 @@ function FilePicker({
4016
4014
  }
4017
4015
 
4018
4016
  // src/gridAttachments.tsx
4017
+ import { OutboundLink as OutboundLink4 } from "@ai-matrx/kit/outbound-react";
4019
4018
  import { jsx as jsx21, jsxs as jsxs19 } from "react/jsx-runtime";
4020
4019
  function attachmentIdsOf(value) {
4021
4020
  return idsOf(value);
@@ -4072,11 +4071,9 @@ function AttachmentChip({ id, onRemove }) {
4072
4071
  const title = href ? `Open ${words}` : read?.why ?? FILE_CHIP_NO_PAGE;
4073
4072
  return /* @__PURE__ */ jsxs19(Badge3, { variant: "secondary", className: "max-w-[14rem] gap-1 text-[11px]", "data-records-file-chip": id, title, children: [
4074
4073
  href ? /* @__PURE__ */ jsx21(
4075
- "a",
4074
+ OutboundLink4,
4076
4075
  {
4077
4076
  href,
4078
- target: "_blank",
4079
- rel: "noreferrer",
4080
4077
  className: "truncate underline-offset-2 hover:underline",
4081
4078
  "data-records-file-link": read?.fileId ?? "",
4082
4079
  onClick: (event) => event.stopPropagation(),
@@ -4392,14 +4389,15 @@ function formulaSourceArchived(field, document2) {
4392
4389
  const keys = (field.config ?? {})[FORMULA_INPUT_KEYS];
4393
4390
  if (!Array.isArray(keys) || !document2) return null;
4394
4391
  for (const key of keys) {
4395
- const state = sourceArchivedOf(document2[String(key)]);
4396
- if (state) return state;
4392
+ const state2 = sourceArchivedOf(document2[String(key)]);
4393
+ if (state2) return state2;
4397
4394
  }
4398
4395
  return null;
4399
4396
  }
4400
4397
 
4401
4398
  // src/values.tsx
4402
4399
  import { autonumberPrefixOf as autonumberPrefixOf2, autonumberWords as autonumberWords2, isButtonField as isButtonField2, newerKindWords, sourceArchivedOf as sourceArchivedOf2 } from "@ai-matrx/records";
4400
+ import { OutboundLink as OutboundLink5 } from "@ai-matrx/kit/outbound-react";
4403
4401
  import { Fragment as Fragment7, jsx as jsx23, jsxs as jsxs21 } from "react/jsx-runtime";
4404
4402
  function statusMark(field, item, document2) {
4405
4403
  const mark = statusMarkOf(field, item, document2);
@@ -4444,12 +4442,12 @@ function computedEmptyOf(field, document2) {
4444
4442
  return { kind: "formula" };
4445
4443
  }
4446
4444
  var SOURCE_ARCHIVED_WORDS = "Source archived";
4447
- function sourceArchivedSentence(state) {
4448
- if (!state.label) return "A column it reads is archived";
4449
- return state.table ? `${state.label} on ${state.table} is archived` : `${state.label} is archived`;
4445
+ function sourceArchivedSentence(state2) {
4446
+ if (!state2.label) return "A column it reads is archived";
4447
+ return state2.table ? `${state2.label} on ${state2.table} is archived` : `${state2.label} is archived`;
4450
4448
  }
4451
- function SourceArchivedValue({ state }) {
4452
- return /* @__PURE__ */ jsx23("span", { className: "text-xs italic text-muted-foreground", title: sourceArchivedSentence(state), "data-records-source-archived": state.field_id ?? "", children: SOURCE_ARCHIVED_WORDS });
4449
+ function SourceArchivedValue({ state: state2 }) {
4450
+ return /* @__PURE__ */ jsx23("span", { className: "text-xs italic text-muted-foreground", title: sourceArchivedSentence(state2), "data-records-source-archived": state2.field_id ?? "", children: SOURCE_ARCHIVED_WORDS });
4453
4451
  }
4454
4452
  var ABSENCE_WORDS = ABSENCE_WORD_LABEL;
4455
4453
  function renderValue(field, value, document2, labels, stillWaitingFor, look) {
@@ -4524,12 +4522,10 @@ function renderValue(field, value, document2, labels, stillWaitingFor, look) {
4524
4522
  if (kind === "url" && typeof value === "string") {
4525
4523
  const href = value.includes("://") ? value : `https://${value}`;
4526
4524
  return /* @__PURE__ */ jsxs21(
4527
- "a",
4525
+ OutboundLink5,
4528
4526
  {
4529
4527
  className: "inline-flex min-w-0 max-w-full items-center gap-1 rounded-md border border-border bg-muted/60 px-1.5 py-0.5 text-[11px] text-foreground hover:bg-accent",
4530
4528
  href,
4531
- target: "_blank",
4532
- rel: "noreferrer",
4533
4529
  title: value,
4534
4530
  "data-records-link-chip": "",
4535
4531
  onClick: (event) => event.stopPropagation(),
@@ -4603,12 +4599,12 @@ function scalarText(field, value, labels, stillWaitingFor) {
4603
4599
 
4604
4600
  // src/SourceArchivedNotice.tsx
4605
4601
  import { jsx as jsx24, jsxs as jsxs22 } from "react/jsx-runtime";
4606
- function bringBackLabel(state) {
4607
- return state.label ? `Bring back ${state.label}` : "Bring it back";
4602
+ function bringBackLabel(state2) {
4603
+ return state2.label ? `Bring back ${state2.label}` : "Bring it back";
4608
4604
  }
4609
4605
  function SourceArchivedNotice({ fieldId, tableId }) {
4610
4606
  const client = useRecordsClient6();
4611
- const [state, setState] = useState18(null);
4607
+ const [state2, setState] = useState18(null);
4612
4608
  const [busy, setBusy] = useState18(false);
4613
4609
  const [refused, setRefused] = useState18(null);
4614
4610
  const read = useCallback5(async () => {
@@ -4619,19 +4615,19 @@ function SourceArchivedNotice({ fieldId, tableId }) {
4619
4615
  useEffect12(() => {
4620
4616
  void read();
4621
4617
  }, [read]);
4622
- if (refused && !state) return /* @__PURE__ */ jsx24(RefusalNotice, { error: refused });
4623
- if (!state) return null;
4618
+ if (refused && !state2) return /* @__PURE__ */ jsx24(RefusalNotice, { error: refused });
4619
+ if (!state2) return null;
4624
4620
  const restore = async () => {
4625
- if (!state.field_id) return;
4621
+ if (!state2.field_id) return;
4626
4622
  setBusy(true);
4627
4623
  setRefused(null);
4628
- const done = await client.fieldRestore({ field_id: state.field_id });
4624
+ const done = await client.fieldRestore({ field_id: state2.field_id });
4629
4625
  setBusy(false);
4630
4626
  if (!done.ok) {
4631
4627
  setRefused(done.error);
4632
4628
  return;
4633
4629
  }
4634
- if (state.table_id) tableShapeChanged(state.table_id);
4630
+ if (state2.table_id) tableShapeChanged(state2.table_id);
4635
4631
  tableShapeChanged(tableId);
4636
4632
  await read();
4637
4633
  };
@@ -4640,13 +4636,13 @@ function SourceArchivedNotice({ fieldId, tableId }) {
4640
4636
  {
4641
4637
  className: "flex flex-wrap items-center gap-2 rounded-md border border-border px-3 py-2",
4642
4638
  "data-testid": "source-archived-notice",
4643
- "data-field-id": state.field_id ?? "",
4639
+ "data-field-id": state2.field_id ?? "",
4644
4640
  children: [
4645
4641
  /* @__PURE__ */ jsxs22("div", { className: "flex min-w-0 flex-1 flex-col", children: [
4646
4642
  /* @__PURE__ */ jsx24("span", { className: "text-sm", children: SOURCE_ARCHIVED_WORDS }),
4647
- /* @__PURE__ */ jsx24("span", { className: "truncate text-xs text-muted-foreground", children: sourceArchivedSentence(state) })
4643
+ /* @__PURE__ */ jsx24("span", { className: "truncate text-xs text-muted-foreground", children: sourceArchivedSentence(state2) })
4648
4644
  ] }),
4649
- state.field_id ? /* @__PURE__ */ jsx24(Button11, { type: "button", size: "sm", variant: "secondary", disabled: busy, onClick: () => void restore(), children: bringBackLabel(state) }) : null,
4645
+ state2.field_id ? /* @__PURE__ */ jsx24(Button11, { type: "button", size: "sm", variant: "secondary", disabled: busy, onClick: () => void restore(), children: bringBackLabel(state2) }) : null,
4650
4646
  refused ? /* @__PURE__ */ jsx24(RefusalNotice, { error: refused, className: "basis-full" }) : null
4651
4647
  ]
4652
4648
  }
@@ -4661,23 +4657,25 @@ import { useOptionalRecordsClient as useOptionalRecordsClient6 } from "@ai-matrx
4661
4657
 
4662
4658
  // src/personTime.ts
4663
4659
  import { useSyncExternalStore } from "react";
4660
+
4661
+ // src/personZone.ts
4664
4662
  import { setColorRuleTimeZone } from "@ai-matrx/design-system/data-table/table-style";
4665
- var zone = null;
4666
- var listeners = /* @__PURE__ */ new Set();
4663
+ import { globalSlot } from "@ai-matrx/kit/global-slot";
4664
+ var state = globalSlot("ai-matrx.records-ui.person-time-zone", () => ({
4665
+ zone: null,
4666
+ listeners: /* @__PURE__ */ new Set()
4667
+ }));
4667
4668
  function getPersonTimeZone() {
4668
- return zone;
4669
+ return state.zone;
4669
4670
  }
4670
- function usePersonTimeZone() {
4671
- return useSyncExternalStore(
4672
- (cb) => {
4673
- listeners.add(cb);
4674
- return () => listeners.delete(cb);
4675
- },
4676
- () => zone,
4677
- () => null
4678
- );
4671
+ function subscribePersonTimeZone(listener) {
4672
+ state.listeners.add(listener);
4673
+ return () => {
4674
+ state.listeners.delete(listener);
4675
+ };
4679
4676
  }
4680
4677
  function personWallNow(at = /* @__PURE__ */ new Date()) {
4678
+ const zone = state.zone;
4681
4679
  if (!zone) return at;
4682
4680
  const parts = new Intl.DateTimeFormat("en-US", {
4683
4681
  timeZone: zone,
@@ -4693,6 +4691,15 @@ function personWallNow(at = /* @__PURE__ */ new Date()) {
4693
4691
  return new Date(n("year"), n("month") - 1, n("day"), n("hour"), n("minute"), n("second"));
4694
4692
  }
4695
4693
 
4694
+ // src/personTime.ts
4695
+ function usePersonTimeZone() {
4696
+ return useSyncExternalStore(
4697
+ subscribePersonTimeZone,
4698
+ getPersonTimeZone,
4699
+ () => null
4700
+ );
4701
+ }
4702
+
4696
4703
  // src/Condition.tsx
4697
4704
  import { Fragment as Fragment8, jsx as jsx25, jsxs as jsxs23 } from "react/jsx-runtime";
4698
4705
  var CONDITION_OPS = [
@@ -4720,10 +4727,10 @@ var RELATIVE_DAY_TERMS = [
4720
4727
  { kind: "past_days", label: "is in the past \u2026 days", takesDays: true }
4721
4728
  ];
4722
4729
  function relativeDayNode(fieldId, kind, days) {
4723
- const zone2 = getPersonTimeZone();
4730
+ const zone = getPersonTimeZone();
4724
4731
  const window2 = { relative: kind };
4725
4732
  if (RELATIVE_DAY_TERMS.find((t) => t.kind === kind)?.takesDays) window2["n"] = days ?? 7;
4726
- if (zone2) window2["tz"] = zone2;
4733
+ if (zone) window2["tz"] = zone;
4727
4734
  return { op: "within", args: [{ field: fieldId }, { const: window2 }] };
4728
4735
  }
4729
4736
  function relativeDayOf(expr) {
@@ -7090,12 +7097,12 @@ function sourceKindOf(field) {
7090
7097
  if (kind === "attachment") return "file";
7091
7098
  return null;
7092
7099
  }
7093
- function whatIsMissing(state) {
7094
- const noun = state.noun ?? "column";
7095
- const { type, label, via, pick, agg, of, relations, formulaFields } = state;
7096
- const relationTarget = state.relationTarget ?? "";
7100
+ function whatIsMissing(state2) {
7101
+ const noun = state2.noun ?? "column";
7102
+ const { type, label, via, pick, agg, of, relations, formulaFields } = state2;
7103
+ const relationTarget = state2.relationTarget ?? "";
7097
7104
  if (label.trim() === "") return `Give the ${noun} a name.`;
7098
- if (type === "entity_reference") return whatIsMissingForEntityReference(state.allowedTypes ?? []);
7105
+ if (type === "entity_reference") return whatIsMissingForEntityReference(state2.allowedTypes ?? []);
7099
7106
  if (type === "relation") {
7100
7107
  if (relationTarget.trim() === "") return `Choose the table this ${noun} points at.`;
7101
7108
  return null;
@@ -7450,6 +7457,8 @@ function NewColumnDefault({
7450
7457
  }
7451
7458
 
7452
7459
  // src/buttonCell.tsx
7460
+ import { OutboundLink as OutboundLink6 } from "@ai-matrx/kit/outbound-react";
7461
+ import { openOutbound } from "@ai-matrx/kit/outbound";
7453
7462
  import { Fragment as Fragment10, jsx as jsx33, jsxs as jsxs31 } from "react/jsx-runtime";
7454
7463
  function buttonPressWords(label, pressed) {
7455
7464
  if (pressed.do === "open_url") return `${label} opened ${pressed.url}`;
@@ -7480,7 +7489,7 @@ function ButtonValue({ field, recordId, inCell }) {
7480
7489
  if (!answered.ok) return setSaid({ kind: "refused", error: answered.error });
7481
7490
  const pressed = answered.data;
7482
7491
  if (pressed.do === "open_url") {
7483
- const opened = typeof window !== "undefined" ? window.open(pressed.url, "_blank", "noopener,noreferrer") : null;
7492
+ const opened = typeof window !== "undefined" ? openOutbound(pressed.url, "_blank", "noopener") : null;
7484
7493
  return setSaid({ kind: "ran", says: opened ? `${b.label} opened.` : `${b.label} is ready:`, link: pressed.url });
7485
7494
  }
7486
7495
  setSaid({ kind: "ran", says: buttonPressWords(b.label, pressed) });
@@ -7514,7 +7523,7 @@ function ButtonValue({ field, recordId, inCell }) {
7514
7523
  said2?.kind === "ran" ? /* @__PURE__ */ jsxs31("p", { className: "break-words", children: [
7515
7524
  said2.says,
7516
7525
  " ",
7517
- said2.link ? /* @__PURE__ */ jsx33("a", { href: said2.link, target: "_blank", rel: "noopener noreferrer", className: "text-primary underline", children: said2.link }) : null
7526
+ said2.link ? /* @__PURE__ */ jsx33(OutboundLink6, { href: said2.link, className: "text-primary underline", children: said2.link }) : null
7518
7527
  ] }) : null,
7519
7528
  said2?.kind === "needs" ? /* @__PURE__ */ jsxs31(Fragment10, { children: [
7520
7529
  /* @__PURE__ */ jsx33("p", { children: said2.says }),
@@ -9031,11 +9040,17 @@ function ChoiceAnswer({
9031
9040
 
9032
9041
  // src/RecordsMount.tsx
9033
9042
  import { useRef as useRef17 } from "react";
9034
- import { RecordsProvider } from "@ai-matrx/records/react";
9035
- import { jsx as jsx39 } from "react/jsx-runtime";
9043
+
9044
+ // src/dataSource.ts
9045
+ import { globalSlot as globalSlot2 } from "@ai-matrx/kit/global-slot";
9036
9046
  function personActor(userId) {
9037
9047
  return userId ? { actor: "user", user_id: userId } : { actor: "user" };
9038
9048
  }
9049
+ var dataSources = globalSlot2("ai-matrx.records-ui.data-sources", () => /* @__PURE__ */ new WeakMap());
9050
+
9051
+ // src/RecordsMount.tsx
9052
+ import { RecordsProvider } from "@ai-matrx/records/react";
9053
+ import { jsx as jsx39 } from "react/jsx-runtime";
9039
9054
 
9040
9055
  // src/TablePickers.tsx
9041
9056
  import { Fragment as Fragment14, jsx as jsx40, jsxs as jsxs37 } from "react/jsx-runtime";
@@ -9070,7 +9085,7 @@ function readTablesAnywhere(dataSource) {
9070
9085
  return read;
9071
9086
  }
9072
9087
  function useTablesAnywhere(dataSource) {
9073
- const [state, setState] = useState31({ loading: true, error: null, rows: [] });
9088
+ const [state2, setState] = useState31({ loading: true, error: null, rows: [] });
9074
9089
  useEffect22(() => {
9075
9090
  let live = true;
9076
9091
  void readTablesAnywhere(dataSource).then((result) => {
@@ -9080,7 +9095,7 @@ function useTablesAnywhere(dataSource) {
9080
9095
  live = false;
9081
9096
  };
9082
9097
  }, [dataSource]);
9083
- return state;
9098
+ return state2;
9084
9099
  }
9085
9100
  function TablePicker({ dataSource, value, onChange, disabled, tables }) {
9086
9101
  const own3 = useTablesAnywhere(dataSource);