@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/index.js CHANGED
@@ -99,8 +99,7 @@ function lockedStructure(base2) {
99
99
  return { ...base2, structure: false, why: (what) => what === "structure" ? DATABASE_LOCKED_REASON : base2.why(what) };
100
100
  }
101
101
 
102
- // src/host.tsx
103
- import { jsx } from "react/jsx-runtime";
102
+ // src/tableRights.ts
104
103
  function tableRights(may, overallReason) {
105
104
  return {
106
105
  ...may,
@@ -112,6 +111,9 @@ var NO_RIGHTS = tableRights(NOT_ANSWERED_YET);
112
111
  function tableRightsAt(level) {
113
112
  return tableRights(whatYouMayDo(level, true));
114
113
  }
114
+
115
+ // src/host.tsx
116
+ import { jsx } from "react/jsx-runtime";
115
117
  var NO_SAVED_VIEWS_REASON = "There are no saved views here yet, so there is nothing to be told about. Save a view of this table first and it will be offered here.";
116
118
  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.";
117
119
  var NO_SHARE_REASON = "Sharing is not available on this screen, so there is no Share button here rather than one that opens nothing. Share this table from the tables list instead.";
@@ -646,9 +648,14 @@ import { dateFilterBounds, dateFilterDayBounds, dayInstantWindow } from "@ai-mat
646
648
 
647
649
  // src/personTime.ts
648
650
  import { useSyncExternalStore } from "react";
651
+
652
+ // src/personZone.ts
649
653
  import { setColorRuleTimeZone } from "@ai-matrx/design-system/data-table/table-style";
650
- var zone = null;
651
- var listeners = /* @__PURE__ */ new Set();
654
+ import { globalSlot } from "@ai-matrx/kit/global-slot";
655
+ var state = globalSlot("ai-matrx.records-ui.person-time-zone", () => ({
656
+ zone: null,
657
+ listeners: /* @__PURE__ */ new Set()
658
+ }));
652
659
  function valid(z) {
653
660
  if (typeof z !== "string" || !z.trim()) return false;
654
661
  try {
@@ -660,25 +667,22 @@ function valid(z) {
660
667
  }
661
668
  function setPersonTimeZone(next) {
662
669
  const clean = valid(next) ? next : null;
663
- if (clean === zone) return;
664
- zone = clean;
670
+ if (clean === state.zone) return;
671
+ state.zone = clean;
665
672
  setColorRuleTimeZone(clean);
666
- listeners.forEach((l) => l());
673
+ state.listeners.forEach((l) => l());
667
674
  }
668
675
  function getPersonTimeZone() {
669
- return zone;
676
+ return state.zone;
670
677
  }
671
- function usePersonTimeZone() {
672
- return useSyncExternalStore(
673
- (cb) => {
674
- listeners.add(cb);
675
- return () => listeners.delete(cb);
676
- },
677
- () => zone,
678
- () => null
679
- );
678
+ function subscribePersonTimeZone(listener) {
679
+ state.listeners.add(listener);
680
+ return () => {
681
+ state.listeners.delete(listener);
682
+ };
680
683
  }
681
684
  function personWallNow(at = /* @__PURE__ */ new Date()) {
685
+ const zone = state.zone;
682
686
  if (!zone) return at;
683
687
  const parts = new Intl.DateTimeFormat("en-US", {
684
688
  timeZone: zone,
@@ -694,13 +698,18 @@ function personWallNow(at = /* @__PURE__ */ new Date()) {
694
698
  return new Date(n("year"), n("month") - 1, n("day"), n("hour"), n("minute"), n("second"));
695
699
  }
696
700
 
701
+ // src/personTime.ts
702
+ function usePersonTimeZone() {
703
+ return useSyncExternalStore(
704
+ subscribePersonTimeZone,
705
+ getPersonTimeZone,
706
+ () => null
707
+ );
708
+ }
709
+
697
710
  // src/choiceLooks.ts
698
711
  import { newerKindOf } from "@ai-matrx/records";
699
- import {
700
- CHOICE_CHIP_CLASS,
701
- NEUTRAL_CHIP_CLASS,
702
- STYLE_COLORS
703
- } from "@ai-matrx/design-system/data-table";
712
+ import { CHOICE_CHIP_CLASS, NEUTRAL_CHIP_CLASS, STYLE_COLORS } from "@ai-matrx/design-system/data-table/table-style";
704
713
  function displayFormatOf(field2) {
705
714
  const raw = field2.display_format;
706
715
  if (!raw || typeof raw !== "object") return null;
@@ -1046,10 +1055,10 @@ function clauseFor(f, value, now = /* @__PURE__ */ new Date()) {
1046
1055
  return { rule: value.negated ? not(range) : range };
1047
1056
  }
1048
1057
  case "date": {
1049
- const zone2 = getPersonTimeZone() ?? void 0;
1050
- const moments = dateFilterBounds(value.preset ? { ...value, anchor: now.toISOString() } : value, now, zone2);
1058
+ const zone = getPersonTimeZone() ?? void 0;
1059
+ const moments = dateFilterBounds(value.preset ? { ...value, anchor: now.toISOString() } : value, now, zone);
1051
1060
  const holdsDays = String((f.config ?? {})["kind"] ?? "") === "date";
1052
- const bounds = holdsDays ? dateFilterDayBounds(moments, zone2) : moments;
1061
+ const bounds = holdsDays ? dateFilterDayBounds(moments, zone) : moments;
1053
1062
  if (bounds.since === void 0 && bounds.until === void 0) return null;
1054
1063
  return {
1055
1064
  flat: {
@@ -3127,7 +3136,8 @@ import { useCallback as useCallback2, useEffect as useEffect7, useMemo as useMem
3127
3136
  import { withTablePlacement } from "@ai-matrx/records";
3128
3137
  import { useRecordsClient as useRecordsClient4, useTables } from "@ai-matrx/records/react";
3129
3138
  import { Checkbox, cn as cn7 } from "@ai-matrx/design-system";
3130
- import { jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
3139
+
3140
+ // src/tablePickerEntries.ts
3131
3141
  var PLATFORM_TABLE_PREFIX = "records_ui_";
3132
3142
  function keptByPlatform(table) {
3133
3143
  return table.platform_owned === true || table.kept_by_the_app === true;
@@ -3171,6 +3181,9 @@ function madeOn(stamp) {
3171
3181
  if (Number.isNaN(at.getTime())) return null;
3172
3182
  return new Intl.DateTimeFormat(void 0, { month: "short", day: "numeric", year: "numeric" }).format(at);
3173
3183
  }
3184
+
3185
+ // src/tablePicking.tsx
3186
+ import { jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
3174
3187
  function usePickerTables() {
3175
3188
  const client = useRecordsClient4();
3176
3189
  const tables = useTables();
@@ -3745,10 +3758,7 @@ import { useRecordsClient as useRecordsClient13 } from "@ai-matrx/records/react"
3745
3758
  import { Button as Button20, Checkbox as Checkbox6, Popover as Popover8, PopoverContent as PopoverContent8, PopoverTrigger as PopoverTrigger8, cn as cn26 } from "@ai-matrx/design-system";
3746
3759
 
3747
3760
  // src/presentation.ts
3748
- import { parseTableStyle, tableStyleIsEmpty } from "@ai-matrx/design-system/data-table/table-style";
3749
- import {
3750
- COLOR_ROTATION
3751
- } from "@ai-matrx/design-system/data-table";
3761
+ import { COLOR_ROTATION, parseTableStyle, tableStyleIsEmpty } from "@ai-matrx/design-system/data-table/table-style";
3752
3762
  import { getFieldFormat } from "@ai-matrx/design-system/field-formats";
3753
3763
  import { newerKindOf as newerKindOf3, ratingMaxOf } from "@ai-matrx/records";
3754
3764
 
@@ -4533,6 +4543,7 @@ import {
4533
4543
  statusGroupOf
4534
4544
  } from "@ai-matrx/records";
4535
4545
  import { BasicInput as BasicInput4, cn as cn11 } from "@ai-matrx/design-system";
4546
+ import { OutboundLink } from "@ai-matrx/kit/outbound-react";
4536
4547
  import { Fragment as Fragment4, jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
4537
4548
  var own = (event) => event.stopPropagation();
4538
4549
  function newerKindValue(field2, value, opts = {}) {
@@ -4581,11 +4592,9 @@ function AddressLink({ value }) {
4581
4592
  const href = addressMapUrl(value);
4582
4593
  if (!words2 || !href) return /* @__PURE__ */ jsx16("span", { className: "text-muted-foreground", children: "\u2014" });
4583
4594
  return /* @__PURE__ */ jsxs14(
4584
- "a",
4595
+ OutboundLink,
4585
4596
  {
4586
4597
  href,
4587
- target: "_blank",
4588
- rel: "noopener noreferrer",
4589
4598
  className: "inline-flex min-w-0 items-center gap-1 text-primary hover:underline",
4590
4599
  title: "Open in maps",
4591
4600
  "data-records-address": "",
@@ -4633,7 +4642,7 @@ function marks(text, key) {
4633
4642
  const link = /^\[([^\]]+)\]\(([^)\s]+)\)$/.exec(tok);
4634
4643
  const href = safeLinkHref(link?.[2] ?? "");
4635
4644
  out.push(
4636
- href ? /* @__PURE__ */ jsx16("a", { href, target: "_blank", rel: "noopener noreferrer", className: "text-primary underline-offset-2 hover:underline", onClick: own, children: link?.[1] }, k) : link?.[1] ?? tok
4645
+ href ? /* @__PURE__ */ jsx16(OutboundLink, { href, className: "text-primary underline-offset-2 hover:underline", onClick: own, children: link?.[1] }, k) : link?.[1] ?? tok
4637
4646
  );
4638
4647
  } else out.push(/* @__PURE__ */ jsx16("em", { children: tok.slice(1, -1) }, k));
4639
4648
  last = at + tok.length;
@@ -5531,8 +5540,7 @@ import { tableShapeChanged as tableShapeChanged3, useRecordsClient as useRecords
5531
5540
  import { SWATCH_CLASS as SWATCH_CLASS2, formatColumnValue } from "@ai-matrx/design-system/data-table";
5532
5541
  import { formatFieldValue as formatFieldValue3 } from "@ai-matrx/design-system/field-formats";
5533
5542
 
5534
- // src/withheld.tsx
5535
- import { jsx as jsx20 } from "react/jsx-runtime";
5543
+ // src/withheldNotice.ts
5536
5544
  var WITHHELD_WORD = "Withheld";
5537
5545
  function withheldNoticeOf(hidden, key) {
5538
5546
  const notice = hidden?.[key];
@@ -5550,6 +5558,9 @@ function withheldSentence(field2, notice) {
5550
5558
  const or = notice.or ? `${needs || reason ? ", or" : " It needs"} ${notice.or}` : "";
5551
5559
  return `${name} is withheld from you.${reason}${needs}${or}${reason || needs || or ? "." : ""}`;
5552
5560
  }
5561
+
5562
+ // src/withheld.tsx
5563
+ import { jsx as jsx20 } from "react/jsx-runtime";
5553
5564
  function WithheldValue({ field: field2, notice }) {
5554
5565
  const sentence2 = withheldSentence(field2, notice);
5555
5566
  return /* @__PURE__ */ jsx20(
@@ -5928,6 +5939,7 @@ import { wholeValueOf } from "@ai-matrx/records/core";
5928
5939
  import { useEffect as useEffect13, useState as useState18 } from "react";
5929
5940
  import { wholeValueSize } from "@ai-matrx/records/core";
5930
5941
  import { BasicTextarea as BasicTextarea2 } from "@ai-matrx/design-system";
5942
+ import { OutboundLink as OutboundLink2 } from "@ai-matrx/kit/outbound-react";
5931
5943
  import { jsx as jsx22, jsxs as jsxs19 } from "react/jsx-runtime";
5932
5944
  var WHOLE_VALUE_UNBOUND = "The whole text is kept as a file, and this screen has no way to open files yet.";
5933
5945
  function wholeValueLine(pointer) {
@@ -5942,7 +5954,7 @@ function WholeValueCell({ words: words2, pointer }) {
5942
5954
  words2,
5943
5955
  "\u2026"
5944
5956
  ] }),
5945
- href ? host.Link ? host.Link({ href, children: line, className: "shrink-0 text-xs text-primary underline-offset-2 hover:underline" }) : /* @__PURE__ */ jsx22("a", { className: "shrink-0 text-xs text-primary underline-offset-2 hover:underline", href, target: "_blank", rel: "noreferrer", children: line }) : /* @__PURE__ */ jsx22("span", { className: "shrink-0 text-xs italic text-muted-foreground", title: WHOLE_VALUE_UNBOUND, children: `${wholeValueSize(pointer)} in a file` })
5957
+ href ? host.Link ? host.Link({ href, children: line, className: "shrink-0 text-xs text-primary underline-offset-2 hover:underline" }) : /* @__PURE__ */ jsx22(OutboundLink2, { className: "shrink-0 text-xs text-primary underline-offset-2 hover:underline", href, children: line }) : /* @__PURE__ */ jsx22("span", { className: "shrink-0 text-xs italic text-muted-foreground", title: WHOLE_VALUE_UNBOUND, children: `${wholeValueSize(pointer)} in a file` })
5946
5958
  ] });
5947
5959
  }
5948
5960
  var WHOLE_VALUE_NOT_EDITABLE_HERE = "The whole text is kept as a file. Open it to read it; this screen cannot load it to edit.";
@@ -6024,6 +6036,7 @@ import { useRef as useRef10 } from "react";
6024
6036
  import { FormattedCell } from "@ai-matrx/design-system/data-table";
6025
6037
  import { formatFieldValue as formatFieldValue2, formatPhone, getFieldFormat as getFieldFormat2 } from "@ai-matrx/design-system/field-formats";
6026
6038
  import { cn as cn16 } from "@ai-matrx/design-system";
6039
+ import { OutboundLink as OutboundLink3 } from "@ai-matrx/kit/outbound-react";
6027
6040
  import { jsx as jsx23, jsxs as jsxs20 } from "react/jsx-runtime";
6028
6041
  var LINK = "inline-flex min-w-0 items-center gap-1 text-primary hover:underline";
6029
6042
  var own2 = (event) => event.stopPropagation();
@@ -6094,16 +6107,14 @@ function rich(id, text, raw, format) {
6094
6107
  case "email":
6095
6108
  return /* @__PURE__ */ jsx23("a", { href: `mailto:${text}`, className: LINK, onClick: own2, children: /* @__PURE__ */ jsx23("span", { className: "truncate", children: text }) });
6096
6109
  case "url":
6097
- return /* @__PURE__ */ jsx23("a", { href: text.includes("://") ? text : `https://${text}`, target: "_blank", rel: "noopener noreferrer", className: LINK, onClick: own2, children: /* @__PURE__ */ jsx23("span", { className: "truncate", children: text }) });
6110
+ return /* @__PURE__ */ jsx23(OutboundLink3, { href: text.includes("://") ? text : `https://${text}`, className: LINK, onClick: own2, children: /* @__PURE__ */ jsx23("span", { className: "truncate", children: text }) });
6098
6111
  case "phone":
6099
6112
  return /* @__PURE__ */ jsx23("a", { href: `tel:${text.replace(/[^\d+]/g, "")}`, className: LINK, onClick: own2, title: text, children: /* @__PURE__ */ jsx23("span", { className: "truncate tabular-nums", children: formatPhone(text) }) });
6100
6113
  case "address":
6101
6114
  return /* @__PURE__ */ jsx23(
6102
- "a",
6115
+ OutboundLink3,
6103
6116
  {
6104
6117
  href: `https://www.google.com/maps/search/?api=1&query=${encodeURIComponent(text)}`,
6105
- target: "_blank",
6106
- rel: "noopener noreferrer",
6107
6118
  className: LINK,
6108
6119
  title: "Open in maps",
6109
6120
  onClick: own2,
@@ -6273,6 +6284,7 @@ function FilePicker({
6273
6284
  }
6274
6285
 
6275
6286
  // src/gridAttachments.tsx
6287
+ import { OutboundLink as OutboundLink4 } from "@ai-matrx/kit/outbound-react";
6276
6288
  import { jsx as jsx25, jsxs as jsxs22 } from "react/jsx-runtime";
6277
6289
  function attachmentIdsOf(value) {
6278
6290
  return idsOf(value);
@@ -6329,11 +6341,9 @@ function AttachmentChip({ id, onRemove }) {
6329
6341
  const title = href ? `Open ${words2}` : read?.why ?? FILE_CHIP_NO_PAGE;
6330
6342
  return /* @__PURE__ */ jsxs22(Badge3, { variant: "secondary", className: "max-w-[14rem] gap-1 text-[11px]", "data-records-file-chip": id, title, children: [
6331
6343
  href ? /* @__PURE__ */ jsx25(
6332
- "a",
6344
+ OutboundLink4,
6333
6345
  {
6334
6346
  href,
6335
- target: "_blank",
6336
- rel: "noreferrer",
6337
6347
  className: "truncate underline-offset-2 hover:underline",
6338
6348
  "data-records-file-link": read?.fileId ?? "",
6339
6349
  onClick: (event) => event.stopPropagation(),
@@ -6806,8 +6816,8 @@ function formulaSourceArchived(field2, document2) {
6806
6816
  const keys = (field2.config ?? {})[FORMULA_INPUT_KEYS];
6807
6817
  if (!Array.isArray(keys) || !document2) return null;
6808
6818
  for (const key of keys) {
6809
- const state = sourceArchivedOf(document2[String(key)]);
6810
- if (state) return state;
6819
+ const state2 = sourceArchivedOf(document2[String(key)]);
6820
+ if (state2) return state2;
6811
6821
  }
6812
6822
  return null;
6813
6823
  }
@@ -6992,6 +7002,7 @@ function WorkedOutError({ field: field2, sentence: sentence2, floated = false })
6992
7002
  }
6993
7003
 
6994
7004
  // src/values.tsx
7005
+ import { OutboundLink as OutboundLink5 } from "@ai-matrx/kit/outbound-react";
6995
7006
  import { Fragment as Fragment8, jsx as jsx30, jsxs as jsxs26 } from "react/jsx-runtime";
6996
7007
  function statusMark(field2, item, document2) {
6997
7008
  const mark = statusMarkOf(field2, item, document2);
@@ -7036,12 +7047,12 @@ function computedEmptyOf(field2, document2) {
7036
7047
  return { kind: "formula" };
7037
7048
  }
7038
7049
  var SOURCE_ARCHIVED_WORDS = "Source archived";
7039
- function sourceArchivedSentence(state) {
7040
- if (!state.label) return "A column it reads is archived";
7041
- return state.table ? `${state.label} on ${state.table} is archived` : `${state.label} is archived`;
7050
+ function sourceArchivedSentence(state2) {
7051
+ if (!state2.label) return "A column it reads is archived";
7052
+ return state2.table ? `${state2.label} on ${state2.table} is archived` : `${state2.label} is archived`;
7042
7053
  }
7043
- function SourceArchivedValue({ state }) {
7044
- return /* @__PURE__ */ jsx30("span", { className: "text-xs italic text-muted-foreground", title: sourceArchivedSentence(state), "data-records-source-archived": state.field_id ?? "", children: SOURCE_ARCHIVED_WORDS });
7054
+ function SourceArchivedValue({ state: state2 }) {
7055
+ return /* @__PURE__ */ jsx30("span", { className: "text-xs italic text-muted-foreground", title: sourceArchivedSentence(state2), "data-records-source-archived": state2.field_id ?? "", children: SOURCE_ARCHIVED_WORDS });
7045
7056
  }
7046
7057
  var ABSENCE_WORDS = ABSENCE_WORD_LABEL;
7047
7058
  function renderValue(field2, value, document2, labels, stillWaitingFor, look) {
@@ -7116,12 +7127,10 @@ function renderValue(field2, value, document2, labels, stillWaitingFor, look) {
7116
7127
  if (kind === "url" && typeof value === "string") {
7117
7128
  const href = value.includes("://") ? value : `https://${value}`;
7118
7129
  return /* @__PURE__ */ jsxs26(
7119
- "a",
7130
+ OutboundLink5,
7120
7131
  {
7121
7132
  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",
7122
7133
  href,
7123
- target: "_blank",
7124
- rel: "noreferrer",
7125
7134
  title: value,
7126
7135
  "data-records-link-chip": "",
7127
7136
  onClick: (event) => event.stopPropagation(),
@@ -7281,12 +7290,12 @@ function cardWords(record, field2, labels) {
7281
7290
 
7282
7291
  // src/SourceArchivedNotice.tsx
7283
7292
  import { jsx as jsx31, jsxs as jsxs27 } from "react/jsx-runtime";
7284
- function bringBackLabel(state) {
7285
- return state.label ? `Bring back ${state.label}` : "Bring it back";
7293
+ function bringBackLabel(state2) {
7294
+ return state2.label ? `Bring back ${state2.label}` : "Bring it back";
7286
7295
  }
7287
7296
  function SourceArchivedNotice({ fieldId, tableId }) {
7288
7297
  const client = useRecordsClient9();
7289
- const [state, setState] = useState23(null);
7298
+ const [state2, setState] = useState23(null);
7290
7299
  const [busy, setBusy] = useState23(false);
7291
7300
  const [refused, setRefused] = useState23(null);
7292
7301
  const read = useCallback7(async () => {
@@ -7297,19 +7306,19 @@ function SourceArchivedNotice({ fieldId, tableId }) {
7297
7306
  useEffect15(() => {
7298
7307
  void read();
7299
7308
  }, [read]);
7300
- if (refused && !state) return /* @__PURE__ */ jsx31(RefusalNotice, { error: refused });
7301
- if (!state) return null;
7309
+ if (refused && !state2) return /* @__PURE__ */ jsx31(RefusalNotice, { error: refused });
7310
+ if (!state2) return null;
7302
7311
  const restore = async () => {
7303
- if (!state.field_id) return;
7312
+ if (!state2.field_id) return;
7304
7313
  setBusy(true);
7305
7314
  setRefused(null);
7306
- const done = await client.fieldRestore({ field_id: state.field_id });
7315
+ const done = await client.fieldRestore({ field_id: state2.field_id });
7307
7316
  setBusy(false);
7308
7317
  if (!done.ok) {
7309
7318
  setRefused(done.error);
7310
7319
  return;
7311
7320
  }
7312
- if (state.table_id) tableShapeChanged3(state.table_id);
7321
+ if (state2.table_id) tableShapeChanged3(state2.table_id);
7313
7322
  tableShapeChanged3(tableId);
7314
7323
  await read();
7315
7324
  };
@@ -7318,13 +7327,13 @@ function SourceArchivedNotice({ fieldId, tableId }) {
7318
7327
  {
7319
7328
  className: "flex flex-wrap items-center gap-2 rounded-md border border-border px-3 py-2",
7320
7329
  "data-testid": "source-archived-notice",
7321
- "data-field-id": state.field_id ?? "",
7330
+ "data-field-id": state2.field_id ?? "",
7322
7331
  children: [
7323
7332
  /* @__PURE__ */ jsxs27("div", { className: "flex min-w-0 flex-1 flex-col", children: [
7324
7333
  /* @__PURE__ */ jsx31("span", { className: "text-sm", children: SOURCE_ARCHIVED_WORDS }),
7325
- /* @__PURE__ */ jsx31("span", { className: "truncate text-xs text-muted-foreground", children: sourceArchivedSentence(state) })
7334
+ /* @__PURE__ */ jsx31("span", { className: "truncate text-xs text-muted-foreground", children: sourceArchivedSentence(state2) })
7326
7335
  ] }),
7327
- state.field_id ? /* @__PURE__ */ jsx31(Button14, { type: "button", size: "sm", variant: "secondary", disabled: busy, onClick: () => void restore(), children: bringBackLabel(state) }) : null,
7336
+ state2.field_id ? /* @__PURE__ */ jsx31(Button14, { type: "button", size: "sm", variant: "secondary", disabled: busy, onClick: () => void restore(), children: bringBackLabel(state2) }) : null,
7328
7337
  refused ? /* @__PURE__ */ jsx31(RefusalNotice, { error: refused, className: "basis-full" }) : null
7329
7338
  ]
7330
7339
  }
@@ -7362,10 +7371,10 @@ var RELATIVE_DAY_TERMS = [
7362
7371
  { kind: "past_days", label: "is in the past \u2026 days", takesDays: true }
7363
7372
  ];
7364
7373
  function relativeDayNode(fieldId, kind, days) {
7365
- const zone2 = getPersonTimeZone();
7374
+ const zone = getPersonTimeZone();
7366
7375
  const window2 = { relative: kind };
7367
7376
  if (RELATIVE_DAY_TERMS.find((t) => t.kind === kind)?.takesDays) window2["n"] = days ?? 7;
7368
- if (zone2) window2["tz"] = zone2;
7377
+ if (zone) window2["tz"] = zone;
7369
7378
  return { op: "within", args: [{ field: fieldId }, { const: window2 }] };
7370
7379
  }
7371
7380
  function relativeDayOf(expr) {
@@ -9587,12 +9596,12 @@ function sourceKindOf(field2) {
9587
9596
  if (kind === "attachment") return "file";
9588
9597
  return null;
9589
9598
  }
9590
- function whatIsMissing(state) {
9591
- const noun = state.noun ?? "column";
9592
- const { type, label, via, pick, agg, of, relations, formulaFields } = state;
9593
- const relationTarget = state.relationTarget ?? "";
9599
+ function whatIsMissing(state2) {
9600
+ const noun = state2.noun ?? "column";
9601
+ const { type, label, via, pick, agg, of, relations, formulaFields } = state2;
9602
+ const relationTarget = state2.relationTarget ?? "";
9594
9603
  if (label.trim() === "") return `Give the ${noun} a name.`;
9595
- if (type === "entity_reference") return whatIsMissingForEntityReference(state.allowedTypes ?? []);
9604
+ if (type === "entity_reference") return whatIsMissingForEntityReference(state2.allowedTypes ?? []);
9596
9605
  if (type === "relation") {
9597
9606
  if (relationTarget.trim() === "") return `Choose the table this ${noun} points at.`;
9598
9607
  return null;
@@ -9947,6 +9956,8 @@ function NewColumnDefault({
9947
9956
  }
9948
9957
 
9949
9958
  // src/buttonCell.tsx
9959
+ import { OutboundLink as OutboundLink6 } from "@ai-matrx/kit/outbound-react";
9960
+ import { openOutbound } from "@ai-matrx/kit/outbound";
9950
9961
  import { Fragment as Fragment11, jsx as jsx39, jsxs as jsxs35 } from "react/jsx-runtime";
9951
9962
  function buttonPressWords(label, pressed) {
9952
9963
  if (pressed.do === "open_url") return `${label} opened ${pressed.url}`;
@@ -9977,7 +9988,7 @@ function ButtonValue({ field: field2, recordId, inCell }) {
9977
9988
  if (!answered.ok) return setSaid({ kind: "refused", error: answered.error });
9978
9989
  const pressed = answered.data;
9979
9990
  if (pressed.do === "open_url") {
9980
- const opened = typeof window !== "undefined" ? window.open(pressed.url, "_blank", "noopener,noreferrer") : null;
9991
+ const opened = typeof window !== "undefined" ? openOutbound(pressed.url, "_blank", "noopener") : null;
9981
9992
  return setSaid({ kind: "ran", says: opened ? `${b.label} opened.` : `${b.label} is ready:`, link: pressed.url });
9982
9993
  }
9983
9994
  setSaid({ kind: "ran", says: buttonPressWords(b.label, pressed) });
@@ -10011,7 +10022,7 @@ function ButtonValue({ field: field2, recordId, inCell }) {
10011
10022
  said2?.kind === "ran" ? /* @__PURE__ */ jsxs35("p", { className: "break-words", children: [
10012
10023
  said2.says,
10013
10024
  " ",
10014
- said2.link ? /* @__PURE__ */ jsx39("a", { href: said2.link, target: "_blank", rel: "noopener noreferrer", className: "text-primary underline", children: said2.link }) : null
10025
+ said2.link ? /* @__PURE__ */ jsx39(OutboundLink6, { href: said2.link, className: "text-primary underline", children: said2.link }) : null
10015
10026
  ] }) : null,
10016
10027
  said2?.kind === "needs" ? /* @__PURE__ */ jsxs35(Fragment11, { children: [
10017
10028
  /* @__PURE__ */ jsx39("p", { children: said2.says }),
@@ -12313,7 +12324,7 @@ function GridCell({
12313
12324
  else cancelSinglePress();
12314
12325
  };
12315
12326
  const value = editing ? editing.valueFor(row, field2) : row.document?.[field2.key];
12316
- const state = editing ? editing.stateOf(row.id, field2.key) : null;
12327
+ const state2 = editing ? editing.stateOf(row.id, field2.key) : null;
12317
12328
  const refusal3 = editing ? editing.refusalOf(row.id, field2.key) : null;
12318
12329
  const editable = Boolean(editing) && canWrite && fieldIsEditable(field2);
12319
12330
  if (open && editing) {
@@ -12374,7 +12385,7 @@ function GridCell({
12374
12385
  disabled: !editable,
12375
12386
  "aria-label": editable ? `${fieldName(field2)} \u2014 press Space to ${value === true ? "untick" : "tick"}` : fieldName(field2),
12376
12387
  title: editable ? answered ? `${fieldName(field2)} \u2014 press Space to change` : `${fieldName(field2)} \u2014 nobody has answered this yet` : whyNot ?? `${fieldName(field2)} \u2014 you cannot change this record`,
12377
- className: cn26(state === "saving" ? "opacity-60" : "", state === "refused" ? "ring-1 ring-destructive" : ""),
12388
+ className: cn26(state2 === "saving" ? "opacity-60" : "", state2 === "refused" ? "ring-1 ring-destructive" : ""),
12378
12389
  onCheckedChange: (next) => editing?.setCell(row.id, field2.key, next === true)
12379
12390
  }
12380
12391
  ),
@@ -12385,7 +12396,7 @@ function GridCell({
12385
12396
  if (editable && format?.id === "rating") {
12386
12397
  return /* @__PURE__ */ jsxs40("span", { "data-matrx-cell-control": "", className: "relative flex h-full w-full flex-wrap items-center gap-1.5", children: [
12387
12398
  /* @__PURE__ */ jsx45(FormattedValue, { value, format, onRate: (next) => editing?.setCell(row.id, field2.key, next), selectFirst: true }),
12388
- state === "saving" ? /* @__PURE__ */ jsx45("span", { "data-records-cell-saving": "", className: "pointer-events-none absolute right-1 top-1/2 z-10 -translate-y-1/2 rounded bg-card/90 px-1 text-[10px] text-muted-foreground", children: "Saving\u2026" }) : null,
12399
+ state2 === "saving" ? /* @__PURE__ */ jsx45("span", { "data-records-cell-saving": "", className: "pointer-events-none absolute right-1 top-1/2 z-10 -translate-y-1/2 rounded bg-card/90 px-1 text-[10px] text-muted-foreground", children: "Saving\u2026" }) : null,
12389
12400
  refusal3 ? /* @__PURE__ */ jsx45(CellRefusalNotice, { refusal: refusal3, field: field2, row, editing, typed: false }) : null
12390
12401
  ] });
12391
12402
  }
@@ -12447,8 +12458,8 @@ function GridCell({
12447
12458
  // table cell, and a click there is a row click.
12448
12459
  "block w-full min-w-0 flex-1 truncate rounded px-1 py-0.5",
12449
12460
  editable ? "cursor-text hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring" : "",
12450
- state === "saving" ? "opacity-60" : "",
12451
- state === "refused" ? "ring-1 ring-destructive" : ""
12461
+ state2 === "saving" ? "opacity-60" : "",
12462
+ state2 === "refused" ? "ring-1 ring-destructive" : ""
12452
12463
  ),
12453
12464
  onMouseDown: onPointerDown,
12454
12465
  onClickCapture: onLinkClickCapture,
@@ -12507,7 +12518,7 @@ function GridCell({
12507
12518
  }
12508
12519
  ) : null
12509
12520
  ] }),
12510
- state === "saving" ? /* @__PURE__ */ jsx45("span", { "data-records-cell-saving": "", className: "pointer-events-none absolute right-1 top-1/2 z-10 -translate-y-1/2 rounded bg-card/90 px-1 text-[10px] text-muted-foreground", children: "Saving\u2026" }) : null,
12521
+ state2 === "saving" ? /* @__PURE__ */ jsx45("span", { "data-records-cell-saving": "", className: "pointer-events-none absolute right-1 top-1/2 z-10 -translate-y-1/2 rounded bg-card/90 px-1 text-[10px] text-muted-foreground", children: "Saving\u2026" }) : null,
12511
12522
  refusal3 ? /* @__PURE__ */ jsx45(CellRefusalNotice, { refusal: refusal3, field: field2, row, editing, typed: true }) : null
12512
12523
  ]
12513
12524
  }
@@ -13083,7 +13094,7 @@ import { useCallback as useCallback11, useEffect as useEffect27, useRef as useRe
13083
13094
  import { useRecordsClient as useRecordsClient15 } from "@ai-matrx/records/react";
13084
13095
  function useTableDecorations(tableId, revision) {
13085
13096
  const client = useRecordsClient15();
13086
- const [state, setState] = useState37({ data: null, loading: Boolean(tableId) });
13097
+ const [state2, setState] = useState37({ data: null, loading: Boolean(tableId) });
13087
13098
  const seen = useRef22({ tableId: void 0, revision: void 0 });
13088
13099
  const ticket = useRef22(0);
13089
13100
  useEffect27(() => {
@@ -13109,7 +13120,7 @@ function useTableDecorations(tableId, revision) {
13109
13120
  ticket.current += 1;
13110
13121
  }, []);
13111
13122
  const apply = useCallback11((next) => setState({ data: next, loading: false }), []);
13112
- return { ...state, apply };
13123
+ return { ...state2, apply };
13113
13124
  }
13114
13125
 
13115
13126
  // src/emptyState.tsx
@@ -13802,42 +13813,13 @@ import { Button as Button24, CreatablePicker as CreatablePicker2 } from "@ai-mat
13802
13813
 
13803
13814
  // src/RecordsMount.tsx
13804
13815
  import { useRef as useRef23 } from "react";
13805
- import { RecordsProvider } from "@ai-matrx/records/react";
13806
- import { jsx as jsx50 } from "react/jsx-runtime";
13807
- 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.";
13808
- function storeDecidesRights(_table) {
13809
- return NO_RIGHTS;
13810
- }
13811
- function RecordsMount({
13812
- config,
13813
- host,
13814
- letTheStoreDecideRights,
13815
- children
13816
- }) {
13817
- const bound2 = useShallowStableHost(host);
13818
- void letTheStoreDecideRights;
13819
- return /* @__PURE__ */ jsx50(RecordsProvider, { config, children: /* @__PURE__ */ jsx50(RecordsUiProvider, { value: bound2, children: /* @__PURE__ */ jsx50(RecordLabelProvider, { children }) }) });
13820
- }
13821
- function useShallowStableHost(host) {
13822
- const held = useRef23(null);
13823
- const next = host ?? {};
13824
- const previous = held.current;
13825
- if (previous !== null && sameParts(previous, next)) return previous;
13826
- const bound2 = { ...next };
13827
- held.current = bound2;
13828
- return bound2;
13829
- }
13830
- function sameParts(a, b) {
13831
- const aKeys = Object.keys(a);
13832
- const bKeys = Object.keys(b);
13833
- if (aKeys.length !== bKeys.length) return false;
13834
- for (const key of aKeys) if (a[key] !== b[key]) return false;
13835
- return true;
13836
- }
13816
+
13817
+ // src/dataSource.ts
13818
+ import { globalSlot as globalSlot2 } from "@ai-matrx/kit/global-slot";
13837
13819
  function personActor(userId) {
13838
13820
  return userId ? { actor: "user", user_id: userId } : { actor: "user" };
13839
13821
  }
13840
- var dataSources = /* @__PURE__ */ new WeakMap();
13822
+ var dataSources = globalSlot2("ai-matrx.records-ui.data-sources", () => /* @__PURE__ */ new WeakMap());
13841
13823
  function recordsDataSource(client, fallbackSchema = "custom") {
13842
13824
  let bySchema = dataSources.get(client);
13843
13825
  if (!bySchema) {
@@ -13883,6 +13865,40 @@ async function hasSession(getSession) {
13883
13865
  }
13884
13866
  }
13885
13867
 
13868
+ // src/RecordsMount.tsx
13869
+ import { RecordsProvider } from "@ai-matrx/records/react";
13870
+ import { jsx as jsx50 } from "react/jsx-runtime";
13871
+ 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.";
13872
+ function storeDecidesRights(_table) {
13873
+ return NO_RIGHTS;
13874
+ }
13875
+ function RecordsMount({
13876
+ config,
13877
+ host,
13878
+ letTheStoreDecideRights,
13879
+ children
13880
+ }) {
13881
+ const bound2 = useShallowStableHost(host);
13882
+ void letTheStoreDecideRights;
13883
+ return /* @__PURE__ */ jsx50(RecordsProvider, { config, children: /* @__PURE__ */ jsx50(RecordsUiProvider, { value: bound2, children: /* @__PURE__ */ jsx50(RecordLabelProvider, { children }) }) });
13884
+ }
13885
+ function useShallowStableHost(host) {
13886
+ const held = useRef23(null);
13887
+ const next = host ?? {};
13888
+ const previous = held.current;
13889
+ if (previous !== null && sameParts(previous, next)) return previous;
13890
+ const bound2 = { ...next };
13891
+ held.current = bound2;
13892
+ return bound2;
13893
+ }
13894
+ function sameParts(a, b) {
13895
+ const aKeys = Object.keys(a);
13896
+ const bKeys = Object.keys(b);
13897
+ if (aKeys.length !== bKeys.length) return false;
13898
+ for (const key of aKeys) if (a[key] !== b[key]) return false;
13899
+ return true;
13900
+ }
13901
+
13886
13902
  // src/TablePickers.tsx
13887
13903
  import { Fragment as Fragment15, jsx as jsx51, jsxs as jsxs45 } from "react/jsx-runtime";
13888
13904
  var SHARED_FOR_MS = 5e3;
@@ -13916,7 +13932,7 @@ function readTablesAnywhere(dataSource) {
13916
13932
  return read;
13917
13933
  }
13918
13934
  function useTablesAnywhere(dataSource) {
13919
- const [state, setState] = useState40({ loading: true, error: null, rows: [] });
13935
+ const [state2, setState] = useState40({ loading: true, error: null, rows: [] });
13920
13936
  useEffect28(() => {
13921
13937
  let live = true;
13922
13938
  void readTablesAnywhere(dataSource).then((result) => {
@@ -13926,7 +13942,7 @@ function useTablesAnywhere(dataSource) {
13926
13942
  live = false;
13927
13943
  };
13928
13944
  }, [dataSource]);
13929
- return state;
13945
+ return state2;
13930
13946
  }
13931
13947
  function TablePicker({ dataSource, value, onChange, disabled, tables }) {
13932
13948
  const own3 = useTablesAnywhere(dataSource);
@@ -18033,7 +18049,7 @@ function CustomFieldsSection({
18033
18049
  });
18034
18050
  useEffect39(() => {
18035
18051
  if (!agentDoor) return;
18036
- const state = () => {
18052
+ const state2 = () => {
18037
18053
  const now = live.current;
18038
18054
  return {
18039
18055
  entityToken,
@@ -18050,7 +18066,7 @@ function CustomFieldsSection({
18050
18066
  };
18051
18067
  };
18052
18068
  const check = (requests) => {
18053
- const now = state();
18069
+ const now = state2();
18054
18070
  if (now.mayAdd === false) {
18055
18071
  return [now.refusal ?? "This person may not add a field here."];
18056
18072
  }
@@ -18115,7 +18131,7 @@ function CustomFieldsSection({
18115
18131
  live.current.reload();
18116
18132
  return { ok: true, written };
18117
18133
  };
18118
- return agentDoor({ entityToken, recordId, state, check, addField, checkValues, setValues });
18134
+ return agentDoor({ entityToken, recordId, state: state2, check, addField, checkValues, setValues });
18119
18135
  }, [agentDoor, client, entityToken, recordId]);
18120
18136
  if (!read.loading && !read.error && fields.length === 0 && !mayAdd && !rights.data) return null;
18121
18137
  const storeReason = rights.data?.reason ?? null;
@@ -19018,7 +19034,7 @@ function useDrillLevelReads(args) {
19018
19034
  const asks = drillLevelAsks({ question, dimensions, answers, where });
19019
19035
  const all = [...asks.attributes, ...asks.focus, ...asks.names];
19020
19036
  const key = JSON.stringify({ source, all, window: args.window ?? null, lane: args.lane ?? null });
19021
- const [state, setState] = useState56({ key: "", held: {}, failed: {} });
19037
+ const [state2, setState] = useState56({ key: "", held: {}, failed: {} });
19022
19038
  useEffect42(() => {
19023
19039
  if (!enabled || !source || all.length === 0) return;
19024
19040
  let cancelled = false;
@@ -19053,12 +19069,12 @@ function useDrillLevelReads(args) {
19053
19069
  cancelled = true;
19054
19070
  };
19055
19071
  }, [client, key, enabled]);
19056
- const ready = state.key === key;
19072
+ const ready = state2.key === key;
19057
19073
  const dim = (k) => dimensions.find((d) => d.key === k);
19058
19074
  const outer2 = question.by[0] ?? null;
19059
19075
  const attributes = asks.attributes.length === 0 || !outer2 ? void 0 : asks.attributes.map((ask2) => {
19060
19076
  const d = dim(ask2.fact);
19061
- const why = ready ? state.failed[askId(ask2)] : void 0;
19077
+ const why = ready ? state2.failed[askId(ask2)] : void 0;
19062
19078
  return {
19063
19079
  key: ask2.fact,
19064
19080
  label: d?.label ?? ask2.fact,
@@ -19067,17 +19083,17 @@ function useDrillLevelReads(args) {
19067
19083
  read: (groups) => {
19068
19084
  if (!ready) return void 0;
19069
19085
  const g = groups[outer2];
19070
- return g ? drillFactWords(state.held[askId(ask2)]?.[g], d) : null;
19086
+ return g ? drillFactWords(state2.held[askId(ask2)]?.[g], d) : null;
19071
19087
  }
19072
19088
  };
19073
19089
  });
19074
19090
  const focusAttributes = asks.focus.length === 0 ? void 0 : asks.focus.map((ask2) => {
19075
19091
  const d = dim(ask2.fact);
19076
- const why = ready ? state.failed[askId(ask2)] : void 0;
19092
+ const why = ready ? state2.failed[askId(ask2)] : void 0;
19077
19093
  return {
19078
19094
  key: ask2.fact,
19079
19095
  label: d?.label ?? ask2.fact,
19080
- value: ready ? drillFactWords(state.held[askId(ask2)]?.["\0"], d) : void 0,
19096
+ value: ready ? drillFactWords(state2.held[askId(ask2)]?.["\0"], d) : void 0,
19081
19097
  ...why ? { error: why } : {}
19082
19098
  };
19083
19099
  });
@@ -19086,7 +19102,7 @@ function useDrillLevelReads(args) {
19086
19102
  for (const ask2 of asks.names) {
19087
19103
  if (!ask2.outer) continue;
19088
19104
  const out = names.get(ask2.outer) ?? /* @__PURE__ */ new Map();
19089
- for (const [value, facts] of Object.entries(state.held[askId(ask2)] ?? {})) {
19105
+ for (const [value, facts] of Object.entries(state2.held[askId(ask2)] ?? {})) {
19090
19106
  const words2 = drillFactWords(facts, dim(ask2.fact));
19091
19107
  if (words2 && words2 !== "Several") out.set(value, words2);
19092
19108
  }
@@ -19140,7 +19156,7 @@ function definitionOf(raw) {
19140
19156
  function useDrillDefinition(source) {
19141
19157
  const client = useRecordsClient33();
19142
19158
  const key = source ? JSON.stringify(source) : null;
19143
- const [state, setState] = useState57({ key: null, def: null, error: null });
19159
+ const [state2, setState] = useState57({ key: null, def: null, error: null });
19144
19160
  useEffect43(() => {
19145
19161
  if (!key) return;
19146
19162
  let cancelled = false;
@@ -19160,7 +19176,7 @@ function useDrillDefinition(source) {
19160
19176
  cancelled = true;
19161
19177
  };
19162
19178
  }, [client, key]);
19163
- return state.key === key ? { def: state.def, error: state.error } : { def: null, error: null };
19179
+ return state2.key === key ? { def: state2.def, error: state2.error } : { def: null, error: null };
19164
19180
  }
19165
19181
  function drillWhere(base2, trail, booleans) {
19166
19182
  const where = { ...base2 ?? {} };
@@ -19530,8 +19546,8 @@ function useGridDrillQuestion(args) {
19530
19546
  return { enabled, source, def, question, setQuestion: url.setQuestion, filter, trailFilter };
19531
19547
  }
19532
19548
  function useGridDrillConfig(args) {
19533
- const { state, presentation, onPresentationChange, version } = args;
19534
- const { setQuestion } = state;
19549
+ const { state: state2, presentation, onPresentationChange, version } = args;
19550
+ const { setQuestion } = state2;
19535
19551
  const onQuestionChange = useMemo28(
19536
19552
  () => (next) => {
19537
19553
  setQuestion(next);
@@ -19543,21 +19559,21 @@ function useGridDrillConfig(args) {
19543
19559
  },
19544
19560
  [setQuestion, onPresentationChange, presentation]
19545
19561
  );
19546
- const flat = state.filter && !isRuleFilter2(state.filter) ? state.filter : void 0;
19547
- const rule = state.filter && isRuleFilter2(state.filter) ? filterWithTrailRuleOnly(state) : void 0;
19562
+ const flat = state2.filter && !isRuleFilter2(state2.filter) ? state2.filter : void 0;
19563
+ const rule = state2.filter && isRuleFilter2(state2.filter) ? filterWithTrailRuleOnly(state2) : void 0;
19548
19564
  const { config } = useDrill({
19549
- source: state.source,
19550
- question: state.question,
19565
+ source: state2.source,
19566
+ question: state2.question,
19551
19567
  onQuestionChange,
19552
19568
  filter: flat,
19553
19569
  rule,
19554
19570
  version,
19555
- enabled: state.enabled
19571
+ enabled: state2.enabled
19556
19572
  });
19557
19573
  return config;
19558
19574
  }
19559
- function filterWithTrailRuleOnly(state) {
19560
- return state.trailFilter;
19575
+ function filterWithTrailRuleOnly(state2) {
19576
+ return state2.trailFilter;
19561
19577
  }
19562
19578
 
19563
19579
  // src/pointsCost.ts
@@ -19601,18 +19617,18 @@ function ago(at) {
19601
19617
  return at ? formatRelativeTime2(at, { style: "intl", fallback: "" }) : "";
19602
19618
  }
19603
19619
  function EnrichBadge({ cell: cell2, onPin, className }) {
19604
- const state = cellState(cell2);
19605
- if (!cell2 || state === "none") return null;
19620
+ const state2 = cellState(cell2);
19621
+ if (!cell2 || state2 === "none") return null;
19606
19622
  const source = cell2.source ?? {};
19607
19623
  const read = Array.isArray(source.read) ? source.read : [];
19608
19624
  const alternates = cell2.alternates ?? [];
19609
- const word = state === "yours" ? "yours" : state === "unsure" ? "unsure" : "agent";
19625
+ const word = state2 === "yours" ? "yours" : state2 === "unsure" ? "unsure" : "agent";
19610
19626
  return /* @__PURE__ */ jsxs62(HoverCard, { openDelay: 120, children: [
19611
19627
  /* @__PURE__ */ jsx68(HoverCardTrigger, { asChild: true, children: /* @__PURE__ */ jsxs62("span", { className: cn35("inline-flex items-center gap-1 align-middle", className), children: [
19612
19628
  /* @__PURE__ */ jsx68(
19613
19629
  Badge8,
19614
19630
  {
19615
- variant: state === "yours" ? "secondary" : "outline",
19631
+ variant: state2 === "yours" ? "secondary" : "outline",
19616
19632
  className: "text-[10px] font-normal leading-none",
19617
19633
  children: word
19618
19634
  }
@@ -19620,8 +19636,8 @@ function EnrichBadge({ cell: cell2, onPin, className }) {
19620
19636
  cell2.stale ? /* @__PURE__ */ jsx68(Badge8, { variant: "outline", className: "text-[10px] font-normal leading-none opacity-70", children: "stale" }) : null
19621
19637
  ] }) }),
19622
19638
  /* @__PURE__ */ jsxs62(HoverCardContent, { className: "w-80 space-y-2 text-xs", children: [
19623
- /* @__PURE__ */ jsx68("p", { className: "font-medium", children: state === "yours" ? "You typed this one in" : state === "unsure" ? "A model had candidates and committed to none" : "Filled in by a model" }),
19624
- state !== "yours" && cell2.on_behalf_of ? /* @__PURE__ */ jsxs62("p", { className: "text-muted-foreground", children: [
19639
+ /* @__PURE__ */ jsx68("p", { className: "font-medium", children: state2 === "yours" ? "You typed this one in" : state2 === "unsure" ? "A model had candidates and committed to none" : "Filled in by a model" }),
19640
+ state2 !== "yours" && cell2.on_behalf_of ? /* @__PURE__ */ jsxs62("p", { className: "text-muted-foreground", children: [
19625
19641
  "Acting for ",
19626
19642
  cell2.on_behalf_of,
19627
19643
  cell2.written_at ? `, ${ago(cell2.written_at)}` : "",
@@ -19642,7 +19658,7 @@ function EnrichBadge({ cell: cell2, onPin, className }) {
19642
19658
  /* @__PURE__ */ jsx68("ul", { className: "list-inside list-disc", children: read.slice(0, 4).map((r, i) => /* @__PURE__ */ jsx68("li", { className: "truncate", children: String(r.title ?? r.url ?? "") }, i)) })
19643
19659
  ] }) : null,
19644
19660
  alternates.length > 0 ? /* @__PURE__ */ jsxs62("div", { children: [
19645
- /* @__PURE__ */ jsx68("p", { className: "text-muted-foreground", children: state === "unsure" ? "What it considered" : "What it nearly said instead" }),
19661
+ /* @__PURE__ */ jsx68("p", { className: "text-muted-foreground", children: state2 === "unsure" ? "What it considered" : "What it nearly said instead" }),
19646
19662
  /* @__PURE__ */ jsx68("ul", { className: "list-inside list-decimal", children: alternates.slice(0, 4).map((a, i) => /* @__PURE__ */ jsx68("li", { children: String(a.value ?? "") }, i)) })
19647
19663
  ] }) : null,
19648
19664
  cell2.stale && cell2.due_at ? /* @__PURE__ */ jsxs62("p", { className: "text-muted-foreground", children: [
@@ -21124,6 +21140,7 @@ function ObjectActionMenuItems({ actions }) {
21124
21140
  }
21125
21141
 
21126
21142
  // src/RecordActionMenu.tsx
21143
+ import { openOutbound as openOutbound2 } from "@ai-matrx/kit/outbound";
21127
21144
  import { Fragment as Fragment23, jsx as jsx75, jsxs as jsxs68 } from "react/jsx-runtime";
21128
21145
  function duplicateValues(fields, document2) {
21129
21146
  const data = {};
@@ -21156,7 +21173,7 @@ function useRecordActionHost({ tableId, row, onOpenRecord, onChanged, onMerge, o
21156
21173
  // The record's panel carries its history under it — on its page, or in the table's rail.
21157
21174
  ...href ? { history: () => window.location.assign(href) } : onOpenRecord ? { history: (r) => onOpenRecord(r.id) } : {},
21158
21175
  openInNewTab: (url) => {
21159
- window.open(url, "_blank", "noopener,noreferrer");
21176
+ openOutbound2(url, "_blank", "noopener");
21160
21177
  },
21161
21178
  copyText: async (url) => {
21162
21179
  if (await copyText(url)) {
@@ -21324,6 +21341,7 @@ function RecordActionMenu({ tableId, row, name, onOpenRecord, onChanged, childre
21324
21341
  }
21325
21342
 
21326
21343
  // src/gridOpen.tsx
21344
+ import { openOutbound as openOutbound3 } from "@ai-matrx/kit/outbound";
21327
21345
  import { jsx as jsx76, jsxs as jsxs69 } from "react/jsx-runtime";
21328
21346
  function openRecordLabel(name) {
21329
21347
  return `Open ${name}`;
@@ -21361,7 +21379,7 @@ function withOpenRecord(columns, onOpen, nameOf2, place = "end", hrefOf) {
21361
21379
  onOpen(row.id);
21362
21380
  return;
21363
21381
  }
21364
- if (event.metaKey || event.ctrlKey) window.open(href, "_blank", "noopener,noreferrer");
21382
+ if (event.metaKey || event.ctrlKey) openOutbound3(href, "_blank", "noopener");
21365
21383
  else window.location.assign(href);
21366
21384
  },
21367
21385
  children: "\u2922"
@@ -25351,19 +25369,19 @@ function StructureLocked({ className }) {
25351
25369
  // src/viewAddress.ts
25352
25370
  import { createContext as createContext8, useContext as useContext8 } from "react";
25353
25371
  var VIEW_ADDRESS_KEYS = ["sort", "cf", "q", "hide", "page"];
25354
- function isViewAddressEmpty(state) {
25355
- if (!state) return true;
25356
- return !state.sort && Object.keys(state.filters ?? {}).length === 0 && !(state.search ?? "").trim() && (state.hidden?.length ?? 0) === 0 && !(state.page && state.page > 1);
25372
+ function isViewAddressEmpty(state2) {
25373
+ if (!state2) return true;
25374
+ return !state2.sort && Object.keys(state2.filters ?? {}).length === 0 && !(state2.search ?? "").trim() && (state2.hidden?.length ?? 0) === 0 && !(state2.page && state2.page > 1);
25357
25375
  }
25358
- function viewAddressToParams(state) {
25376
+ function viewAddressToParams(state2) {
25359
25377
  const out = {};
25360
- if (!state) return out;
25361
- if (state.sort) out["sort"] = `${state.sort.field}:${state.sort.direction}`;
25362
- const filters = Object.fromEntries(Object.entries(state.filters ?? {}).filter(([, v]) => v !== void 0 && v !== null));
25378
+ if (!state2) return out;
25379
+ if (state2.sort) out["sort"] = `${state2.sort.field}:${state2.sort.direction}`;
25380
+ const filters = Object.fromEntries(Object.entries(state2.filters ?? {}).filter(([, v]) => v !== void 0 && v !== null));
25363
25381
  if (Object.keys(filters).length > 0) out["cf"] = JSON.stringify(filters);
25364
- if ((state.search ?? "").trim()) out["q"] = (state.search ?? "").trim();
25365
- if (state.hidden && state.hidden.length > 0) out["hide"] = JSON.stringify(state.hidden);
25366
- if (state.page && state.page > 1) out["page"] = String(Math.floor(state.page));
25382
+ if ((state2.search ?? "").trim()) out["q"] = (state2.search ?? "").trim();
25383
+ if (state2.hidden && state2.hidden.length > 0) out["hide"] = JSON.stringify(state2.hidden);
25384
+ if (state2.page && state2.page > 1) out["page"] = String(Math.floor(state2.page));
25367
25385
  return out;
25368
25386
  }
25369
25387
  function viewAddressFromParams(get) {
@@ -29230,7 +29248,7 @@ function TimeZoneInput({
29230
29248
  "aria-label": label
29231
29249
  }
29232
29250
  ),
29233
- /* @__PURE__ */ jsx93("datalist", { id: listId, children: TIME_ZONES.map((zone2) => /* @__PURE__ */ jsx93("option", { value: zone2 }, zone2)) })
29251
+ /* @__PURE__ */ jsx93("datalist", { id: listId, children: TIME_ZONES.map((zone) => /* @__PURE__ */ jsx93("option", { value: zone }, zone)) })
29234
29252
  ] });
29235
29253
  }
29236
29254
 
@@ -33152,7 +33170,7 @@ async function declare(client, spec) {
33152
33170
  }
33153
33171
  function usePlatformTable(spec) {
33154
33172
  const client = useRecordsClient66();
33155
- const [state, setState] = useState94({ tableId: null, loading: true, error: null });
33173
+ const [state2, setState] = useState94({ tableId: null, loading: true, error: null });
33156
33174
  const slug = spec.slug;
33157
33175
  const stable = useMemo52(() => spec, [slug]);
33158
33176
  useEffect75(() => {
@@ -33168,7 +33186,7 @@ function usePlatformTable(spec) {
33168
33186
  cancelled = true;
33169
33187
  };
33170
33188
  }, [client, stable]);
33171
- return state;
33189
+ return state2;
33172
33190
  }
33173
33191
 
33174
33192
  // src/viewLook.ts
@@ -37929,7 +37947,7 @@ function chartQuestion(view, fields) {
37929
37947
  function ChartLayout({ view, fields, filter, onChange, remembered }) {
37930
37948
  const client = useRecordsClient70();
37931
37949
  const q = useMemo61(() => chartQuestion(view, fields), [view, fields]);
37932
- const [state, setState] = useState105({ block: null, error: null });
37950
+ const [state2, setState] = useState105({ block: null, error: null });
37933
37951
  const filterKey = JSON.stringify(filter ?? {});
37934
37952
  const qKey = JSON.stringify(q);
37935
37953
  useEffect86(() => {
@@ -37997,7 +38015,7 @@ function ChartLayout({ view, fields, filter, onChange, remembered }) {
37997
38015
  MEASURE_LABEL2[isChartMeasure(view.chartMeasure) ? view.chartMeasure : "count"],
37998
38016
  " needs a number field \u2014 pick one above. Counting until then."
37999
38017
  ] }) : null,
38000
- state.error ? /* @__PURE__ */ jsx127(RefusalNotice, { error: state.error }) : state.block ? /* @__PURE__ */ jsx127(ChartBlock, { block: state.block, subject: view.subject, variant: "bare", centerValue: true }) : null
38018
+ state2.error ? /* @__PURE__ */ jsx127(RefusalNotice, { error: state2.error }) : state2.block ? /* @__PURE__ */ jsx127(ChartBlock, { block: state2.block, subject: view.subject, variant: "bare", centerValue: true }) : null
38001
38019
  ] });
38002
38020
  }
38003
38021
 
@@ -39642,7 +39660,7 @@ function SectionBox({ id, children, ...rest }) {
39642
39660
  return /* @__PURE__ */ jsx131("div", { ref: setNodeRef, className: cn65("rounded-sm", isOver && "bg-accent/40"), ...rest, children });
39643
39661
  }
39644
39662
  function SortableRow({ id, disabled, children }) {
39645
- const { attributes, listeners: listeners2, setNodeRef, transform, transition, isDragging } = useSortable({ id, disabled });
39663
+ const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({ id, disabled });
39646
39664
  return /* @__PURE__ */ jsx131(
39647
39665
  "div",
39648
39666
  {
@@ -39651,7 +39669,7 @@ function SortableRow({ id, disabled, children }) {
39651
39669
  className: cn65(isDragging && "relative z-10 opacity-80"),
39652
39670
  "data-view-row": id,
39653
39671
  ...disabled ? {} : attributes,
39654
- ...disabled ? {} : listeners2,
39672
+ ...disabled ? {} : listeners,
39655
39673
  children
39656
39674
  }
39657
39675
  );
@@ -41903,8 +41921,8 @@ function planUndo(changes, current, only) {
41903
41921
  const doc = current ?? {};
41904
41922
  return changes.filter((change) => !only || change.key === only).map((change) => {
41905
41923
  const now = doc[change.key];
41906
- const state = sameValue2(now, change.before) ? "already" : sameValue2(now, change.after) ? "clean" : "conflict";
41907
- return { key: change.key, label: change.label, current: now, after: change.after, before: change.before, state };
41924
+ const state2 = sameValue2(now, change.before) ? "already" : sameValue2(now, change.after) ? "clean" : "conflict";
41925
+ return { key: change.key, label: change.label, current: now, after: change.after, before: change.before, state: state2 };
41908
41926
  });
41909
41927
  }
41910
41928
  function undoPatch(lines, replaceLaterEdits) {
@@ -41936,11 +41954,11 @@ import { Button as Button84, Skeleton as Skeleton21, cn as cn69 } from "@ai-matr
41936
41954
  import { Button as ControlButton2, Field as ControlField } from "@ai-matrx/design-system/controls";
41937
41955
  import { humanizeIdentifier as humanizeIdentifier16 } from "@ai-matrx/kit/text-case";
41938
41956
  import { Fragment as Fragment52, jsx as jsx135, jsxs as jsxs123 } from "react/jsx-runtime";
41939
- function endOfDayIso(day2, zone2 = getPersonTimeZone()) {
41957
+ function endOfDayIso(day2, zone = getPersonTimeZone()) {
41940
41958
  const [y, m, d] = day2.split("-").map(Number);
41941
- if (!zone2) return new Date(y, m - 1, d, 23, 59, 59, 999).toISOString();
41959
+ if (!zone) return new Date(y, m - 1, d, 23, 59, 59, 999).toISOString();
41942
41960
  const wall = (at) => {
41943
- const parts = new Intl.DateTimeFormat("en-US", { timeZone: zone2, year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit", hourCycle: "h23" }).formatToParts(new Date(at));
41961
+ const parts = new Intl.DateTimeFormat("en-US", { timeZone: zone, year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit", hourCycle: "h23" }).formatToParts(new Date(at));
41944
41962
  const n = (t) => Number(parts.find((p) => p.type === t)?.value ?? 0);
41945
41963
  return Date.UTC(n("year"), n("month") - 1, n("day"), n("hour"), n("minute"), n("second"));
41946
41964
  };
@@ -41949,8 +41967,8 @@ function endOfDayIso(day2, zone2 = getPersonTimeZone()) {
41949
41967
  for (let i = 0; i < 2; i += 1) guess -= wall(guess) - target;
41950
41968
  return new Date(guess + 999).toISOString();
41951
41969
  }
41952
- function asOfArgs(record_id, asOf, zone2 = getPersonTimeZone()) {
41953
- return asOf.clock === "recorded" ? { record_id, recorded_at: endOfDayIso(asOf.day, zone2) } : { record_id, world_on: asOf.day };
41970
+ function asOfArgs(record_id, asOf, zone = getPersonTimeZone()) {
41971
+ return asOf.clock === "recorded" ? { record_id, recorded_at: endOfDayIso(asOf.day, zone) } : { record_id, world_on: asOf.day };
41954
41972
  }
41955
41973
  function AsOfControl({ value, onChange, className }) {
41956
41974
  const [text, setText] = useState113(value ? typedDateText3(value.day) : "");
@@ -42053,12 +42071,12 @@ function AsOfReading({
42053
42071
  className
42054
42072
  }) {
42055
42073
  const client = useRecordsClient78();
42056
- const zone2 = usePersonTimeZone();
42074
+ const zone = usePersonTimeZone();
42057
42075
  const [answer, setAnswer] = useState113(null);
42058
- const key = `${recordId}|${asOf.clock}|${asOf.day}|${zone2 ?? ""}`;
42076
+ const key = `${recordId}|${asOf.clock}|${asOf.day}|${zone ?? ""}`;
42059
42077
  useEffect94(() => {
42060
42078
  let live = true;
42061
- void client.recordAsOf(asOfArgs(recordId, asOf, zone2)).then((got) => {
42079
+ void client.recordAsOf(asOfArgs(recordId, asOf, zone)).then((got) => {
42062
42080
  if (!live) return;
42063
42081
  setAnswer(got.ok ? { key, doc: got.data } : { key, error: got.error });
42064
42082
  });
@@ -44355,7 +44373,7 @@ function People({
44355
44373
  said2 ? /* @__PURE__ */ jsx144("p", { className: "text-xs text-muted-foreground", children: said2 }) : null,
44356
44374
  card.principals.length === 0 ? /* @__PURE__ */ jsx144("p", { className: "text-xs text-muted-foreground", children: "Nobody yet. Inviting somebody below emails them a sign-in link; it gives them nothing until they follow it." }) : null,
44357
44375
  card.principals.map((person) => {
44358
- const state = stateWords(person);
44376
+ const state2 = stateWords(person);
44359
44377
  const asking = askingToRevoke?.principal_id === person.principal_id;
44360
44378
  const showing = previewing?.principal_id === person.principal_id;
44361
44379
  return /* @__PURE__ */ jsxs132(
@@ -44365,10 +44383,10 @@ function People({
44365
44383
  children: [
44366
44384
  /* @__PURE__ */ jsxs132("div", { className: "flex flex-wrap items-center gap-1.5", children: [
44367
44385
  /* @__PURE__ */ jsx144("span", { className: "min-w-0 flex-1 truncate font-medium", children: person.client || person.email }),
44368
- /* @__PURE__ */ jsx144(Badge22, { variant: state.tone, children: state.label })
44386
+ /* @__PURE__ */ jsx144(Badge22, { variant: state2.tone, children: state2.label })
44369
44387
  ] }),
44370
44388
  /* @__PURE__ */ jsx144("p", { className: "mt-0.5 break-all text-muted-foreground", children: person.email }),
44371
- /* @__PURE__ */ jsx144("p", { className: "mt-0.5 text-muted-foreground", children: state.why }),
44389
+ /* @__PURE__ */ jsx144("p", { className: "mt-0.5 text-muted-foreground", children: state2.why }),
44372
44390
  person.is_active ? /* @__PURE__ */ jsxs132("div", { className: "mt-1.5 flex flex-wrap gap-1.5", children: [
44373
44391
  person.accept_path ? /* @__PURE__ */ jsx144(CopyLink, { url: `${here}${person.accept_path}`, what: "their link" }) : null,
44374
44392
  /* @__PURE__ */ jsx144(
@@ -44697,8 +44715,8 @@ function scheduleWords(schedule, tz) {
44697
44715
  if (words2.length === 0) return null;
44698
44716
  const time = words2.find((w) => /^\d{1,2}:\d{2}$/.test(w)) ?? null;
44699
44717
  const day2 = words2.map((w) => DAYS3[w.slice(0, 3)]).find(Boolean) ?? null;
44700
- const zone2 = tz?.trim() ? `${tz.trim()} time` : "UTC";
44701
- const at = time ? `at ${time.padStart(5, "0")}, ${zone2}` : null;
44718
+ const zone = tz?.trim() ? `${tz.trim()} time` : "UTC";
44719
+ const at = time ? `at ${time.padStart(5, "0")}, ${zone}` : null;
44702
44720
  return [day2, at].filter(Boolean).join(" ") || null;
44703
44721
  }
44704
44722
 
@@ -46432,6 +46450,7 @@ import {
46432
46450
  formFromSummary,
46433
46451
  formLookDocument
46434
46452
  } from "@ai-matrx/records/forms";
46453
+ import { OutboundLink as OutboundLink7 } from "@ai-matrx/kit/outbound-react";
46435
46454
  import { Fragment as Fragment60, jsx as jsx151, jsxs as jsxs139 } from "react/jsx-runtime";
46436
46455
  function freshFormName(base2, taken) {
46437
46456
  const names = new Set(taken.map((n) => n.trim().toLowerCase()));
@@ -47061,7 +47080,7 @@ function FormBuilder({ tableId, seed, activeFormId, onActiveForm, startWithOne,
47061
47080
  }
47062
47081
  function PublishRow({
47063
47082
  url,
47064
- state,
47083
+ state: state2,
47065
47084
  mayPublish,
47066
47085
  why,
47067
47086
  busy,
@@ -47071,7 +47090,7 @@ function PublishRow({
47071
47090
  onCopy,
47072
47091
  unsaved = false
47073
47092
  }) {
47074
- const open = state === "open";
47093
+ const open = state2 === "open";
47075
47094
  return /* @__PURE__ */ jsxs139("div", { className: "flex flex-col gap-1.5 rounded border px-2.5 py-2", children: [
47076
47095
  /* @__PURE__ */ jsxs139("div", { className: "flex flex-wrap items-center gap-2", children: [
47077
47096
  mayPublish ? /* @__PURE__ */ jsx151(
@@ -47084,13 +47103,11 @@ function PublishRow({
47084
47103
  children: busy ? "\u2026" : open ? "Unpublish" : unsaved ? "Save and publish" : "Publish"
47085
47104
  }
47086
47105
  ) : null,
47087
- state !== "draft" ? /* @__PURE__ */ jsxs139(Fragment60, { children: [
47106
+ state2 !== "draft" ? /* @__PURE__ */ jsxs139(Fragment60, { children: [
47088
47107
  /* @__PURE__ */ jsx151(
47089
- "a",
47108
+ OutboundLink7,
47090
47109
  {
47091
47110
  href: url,
47092
- target: "_blank",
47093
- rel: "noreferrer",
47094
47111
  className: "min-w-0 flex-1 truncate text-xs underline underline-offset-2",
47095
47112
  children: url
47096
47113
  }
@@ -47098,7 +47115,7 @@ function PublishRow({
47098
47115
  /* @__PURE__ */ jsx151(Button98, { size: "sm", variant: "outline", onClick: () => onCopy(url), children: copied ? "Copied" : "Copy link" })
47099
47116
  ] }) : null
47100
47117
  ] }),
47101
- /* @__PURE__ */ jsx151("p", { className: "w-fit text-xs text-muted-foreground", title: FORM_STATE_WORDS[state], "data-records-form-state": state, children: FORM_STATE_LABELS[state] }),
47118
+ /* @__PURE__ */ jsx151("p", { className: "w-fit text-xs text-muted-foreground", title: FORM_STATE_WORDS[state2], "data-records-form-state": state2, children: FORM_STATE_LABELS[state2] }),
47102
47119
  open && unsaved ? /* @__PURE__ */ jsx151("p", { className: "text-xs text-muted-foreground", "data-records-form-unsaved": "", children: "Unsaved changes \u2014 the live form shows your last save" }) : null,
47103
47120
  !mayPublish ? /* @__PURE__ */ jsx151("p", { className: "w-fit text-xs text-muted-foreground", title: why, children: "Publishing needs table admin" }) : null,
47104
47121
  shownUrl ? /* @__PURE__ */ jsxs139("p", { className: "break-all rounded border border-dashed px-2 py-1 text-xs", title: "This browser would not copy for you.", children: [
@@ -52135,6 +52152,7 @@ function asRefusal3(e, fallback) {
52135
52152
 
52136
52153
  // src/CalendarSubscribe.tsx
52137
52154
  import { Button as Button113, Dialog as Dialog17, DialogContent as DialogContent17, DialogHeader as DialogHeader17, DialogTitle as DialogTitle17 } from "@ai-matrx/design-system";
52155
+ import { OutboundLink as OutboundLink8 } from "@ai-matrx/kit/outbound-react";
52138
52156
  import { jsx as jsx168, jsxs as jsxs156 } from "react/jsx-runtime";
52139
52157
  function CalendarLinkOnce({ url }) {
52140
52158
  const notify = useRecordsUi().notify;
@@ -52162,7 +52180,7 @@ function CalendarLinkOnce({ url }) {
52162
52180
  ] }),
52163
52181
  /* @__PURE__ */ jsxs156("div", { className: "flex flex-wrap gap-2", children: [
52164
52182
  /* @__PURE__ */ jsx168(Button113, { asChild: true, size: "sm", variant: "outline", children: /* @__PURE__ */ jsx168("a", { href: webcalUrl(url), "data-calendar-apple": "", children: "Open in Apple Calendar" }) }),
52165
- /* @__PURE__ */ jsx168(Button113, { asChild: true, size: "sm", variant: "outline", children: /* @__PURE__ */ jsx168("a", { href: googleCalendarUrl(url), target: "_blank", rel: "noopener noreferrer", "data-calendar-google": "", children: "Add to Google Calendar" }) })
52183
+ /* @__PURE__ */ jsx168(Button113, { asChild: true, size: "sm", variant: "outline", children: /* @__PURE__ */ jsx168(OutboundLink8, { href: googleCalendarUrl(url), "data-calendar-google": "", children: "Add to Google Calendar" }) })
52166
52184
  ] }),
52167
52185
  /* @__PURE__ */ jsx168("p", { className: "text-xs text-muted-foreground", children: "Shown once. Rotate it from Settings if you lose it." })
52168
52186
  ] });
@@ -53067,6 +53085,7 @@ function useSlotScroll(slot) {
53067
53085
 
53068
53086
  // src/TablePage.tsx
53069
53087
  import { isUuidShape as isUuidShape3 } from "@ai-matrx/kit/uuid";
53088
+ import { openOutbound as openOutbound4 } from "@ai-matrx/kit/outbound";
53070
53089
  import { Fragment as Fragment71, jsx as jsx175, jsxs as jsxs163 } from "react/jsx-runtime";
53071
53090
  var RAIL_TITLE = {
53072
53091
  settings: "Table settings",
@@ -53887,7 +53906,7 @@ function TablePage({
53887
53906
  ...actionHost?.extend ? actionHost.extend(subject, mayDo) : []
53888
53907
  ],
53889
53908
  openInNewTab: (url) => {
53890
- window.open(url, "_blank", "noopener,noreferrer");
53909
+ openOutbound4(url, "_blank", "noopener");
53891
53910
  },
53892
53911
  copyText: async (url) => {
53893
53912
  if (await copyText15(url)) {
@@ -55882,6 +55901,7 @@ export {
55882
55901
  styleFromDecorations,
55883
55902
  submissionStamp2 as submissionStamp,
55884
55903
  subscribeCalendarAction,
55904
+ subscribePersonTimeZone,
55885
55905
  surfaceChosen,
55886
55906
  tableActions,
55887
55907
  tableLink,