@ai-matrx/records-ui 0.115.33 → 0.115.35

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
@@ -24,7 +24,7 @@ __reExport(askOnce_exports, versions_star);
24
24
  import * as versions_star from "@ai-matrx/records/versions";
25
25
 
26
26
  // src/AddChoicesInline.tsx
27
- import { useState as useState2 } from "react";
27
+ import { useState as useState3 } from "react";
28
28
  import { useOptionalRecordsClient } from "@ai-matrx/records/react";
29
29
  import { Button as Button2, Popover as Popover2, PopoverContent as PopoverContent2, PopoverTrigger as PopoverTrigger2 } from "@ai-matrx/design-system";
30
30
 
@@ -565,14 +565,285 @@ function ChoiceSwatch({ words, color, onColor }) {
565
565
  ] });
566
566
  }
567
567
 
568
+ // src/Refusal.tsx
569
+ import { archivedOrganizationId } from "@ai-matrx/records/core";
570
+ import { Alert as Alert2, AlertDescription as AlertDescription2, AlertTitle as AlertTitle2, ErrorBox, cn as cn3 } from "@ai-matrx/design-system";
571
+
572
+ // src/ArchivedOrganizationNotice.tsx
573
+ import { useEffect as useEffect2, useState as useState2 } from "react";
574
+ import { Alert, AlertDescription, AlertTitle, cn as cn2 } from "@ai-matrx/design-system";
575
+
576
+ // src/host.tsx
577
+ import { createContext, useContext, useMemo } from "react";
578
+ import { useMyLevel, useMyLevels } from "@ai-matrx/records/react";
579
+
580
+ // src/rights.ts
581
+ import { atLeast } from "@ai-matrx/records";
582
+ var LEVEL_WORD = {
583
+ viewer: "Viewer",
584
+ commenter: "Commenter",
585
+ edit_content: "Content editor",
586
+ editor: "Editor",
587
+ admin: "Admin"
588
+ };
589
+ var NEEDS = {
590
+ read: "viewer",
591
+ // custom.io_comment_write
592
+ comment: "commenter",
593
+ // custom.record_update / custom.record_write — `edit_content` changes rows and page content;
594
+ // columns, views and settings (structure) stay with admin below, and sharing with admin.
595
+ write: "edit_content",
596
+ // custom.view_designate / view_declare / migrate_merge / record_restore — all ask `editor`: more than
597
+ // changing content (`edit_content`), less than changing columns (`admin`).
598
+ organise: "editor",
599
+ // custom.record_delete
600
+ remove: "editor",
601
+ // custom.share_grant — passing your access on is an administrator's right
602
+ share: "admin",
603
+ // custom.field_declare / field_update / field_retire / table settings
604
+ structure: "admin"
605
+ };
606
+ var NOT_YET = "Still asking the store what you may do here. Nothing is offered until it has answered.";
607
+ var NOTHING_AT_ALL = "You have not been given this. Ask somebody who administers it to share it with you.";
608
+ function sentenceFor(what, level) {
609
+ if (level === null) return NOTHING_AT_ALL;
610
+ const need = LEVEL_WORD[NEEDS[what]];
611
+ const have = LEVEL_WORD[level];
612
+ const doing = {
613
+ read: "open this",
614
+ comment: "leave a comment",
615
+ write: "change anything here",
616
+ organise: "organise this",
617
+ remove: "delete this",
618
+ share: "pass this on to somebody else",
619
+ structure: "change the columns of this table"
620
+ };
621
+ return `You are ${have} here, and it takes ${need} to ${doing[what]}. Ask somebody who is Admin on it to move you up.`;
622
+ }
623
+ function whatYouMayDo(level, known = true) {
624
+ const may = (what) => known && atLeast(level, NEEDS[what]);
625
+ return {
626
+ level: known ? level : null,
627
+ known,
628
+ read: may("read"),
629
+ comment: may("comment"),
630
+ write: may("write"),
631
+ organise: may("organise"),
632
+ remove: may("remove"),
633
+ share: may("share"),
634
+ structure: may("structure"),
635
+ why: (what) => known ? sentenceFor(what, level) : NOT_YET
636
+ };
637
+ }
638
+ var NOT_ANSWERED_YET = whatYouMayDo(null, false);
639
+ var KERNEL_REASON = "This is one of the tables the platform ships, so its columns are not changed from a screen. Make your own table to change columns.";
640
+ function whatYouMayDoWithTable(table, level, known) {
641
+ const base = whatYouMayDo(level, known);
642
+ if (!table?.is_kernel) return table && tableIsLocked(table) ? lockedStructure(base) : base;
643
+ return {
644
+ ...base,
645
+ structure: false,
646
+ why: (what) => what === "structure" ? KERNEL_REASON : base.why(what)
647
+ };
648
+ }
649
+ function tableIsLocked(table) {
650
+ return table?.metadata?.["locked"] === true;
651
+ }
652
+ var DATABASE_LOCKED_REASON = "This database is locked, so its columns and settings are read-only. Unlock it to change them.";
653
+ function lockedStructure(base) {
654
+ return { ...base, structure: false, why: (what) => what === "structure" ? DATABASE_LOCKED_REASON : base.why(what) };
655
+ }
656
+
657
+ // src/host.tsx
658
+ import { jsx as jsx2 } from "react/jsx-runtime";
659
+ function tableRights(may, overallReason) {
660
+ return {
661
+ ...may,
662
+ admin: may.structure,
663
+ reason: overallReason ?? (may.structure ? "" : may.why("structure"))
664
+ };
665
+ }
666
+ var NO_RIGHTS = tableRights(NOT_ANSWERED_YET);
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.";
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.";
669
+ var HostContext = createContext(null);
670
+ function useRecordsUi() {
671
+ return useContext(HostContext) ?? {};
672
+ }
673
+ function quiet(may, say) {
674
+ if (say !== false) return may;
675
+ return { ...may, why: () => "", ..."reason" in may ? { reason: "" } : {} };
676
+ }
677
+ function useTableRights(table) {
678
+ const host = useRecordsUi();
679
+ const asked2 = useTableRightsAsked(table, host);
680
+ return useMemo(() => quiet(asked2, host.sayLevelNeeded), [asked2, host.sayLevelNeeded]);
681
+ }
682
+ function useTableRightsAsked(table, host) {
683
+ const bound = Boolean(host.rights);
684
+ const asked2 = useMyLevel(bound || !table ? null : table.id);
685
+ return useMemo(() => {
686
+ if (!table) return NO_RIGHTS;
687
+ if (host.rights) return host.rights(table);
688
+ if (asked2.loading) return tableRights(NOT_ANSWERED_YET);
689
+ const level = asked2.error ? null : asked2.data;
690
+ return tableRights(whatYouMayDoWithTable(table, level, true));
691
+ }, [host, table, bound, asked2.loading, asked2.error, asked2.data]);
692
+ }
693
+
694
+ // src/ArchivedOrganizationNotice.tsx
695
+ import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
696
+ function ArchivedOrganizationNotice({
697
+ organizationId,
698
+ error,
699
+ className
700
+ }) {
701
+ const port = useRecordsUi().archivedOrganization;
702
+ const [mayRestore, setMayRestore] = useState2(null);
703
+ const [busy, setBusy] = useState2(false);
704
+ const [failed, setFailed] = useState2(null);
705
+ useEffect2(() => {
706
+ let live = true;
707
+ if (!port) {
708
+ setMayRestore(false);
709
+ return;
710
+ }
711
+ setMayRestore(null);
712
+ port.state(organizationId).then((answer) => {
713
+ if (live) setMayRestore(answer?.mayRestore === true);
714
+ }).catch(() => {
715
+ if (live) setMayRestore(false);
716
+ });
717
+ return () => {
718
+ live = false;
719
+ };
720
+ }, [organizationId, port?.state]);
721
+ const restore = async () => {
722
+ if (!port || busy) return;
723
+ setBusy(true);
724
+ setFailed(null);
725
+ try {
726
+ await port.restore(organizationId);
727
+ if (port.afterRestore) port.afterRestore();
728
+ else if (typeof window !== "undefined") window.location.reload();
729
+ } catch (thrown) {
730
+ setFailed(thrown instanceof Error && thrown.message ? thrown.message : "The organization could not be restored.");
731
+ setBusy(false);
732
+ }
733
+ };
734
+ return /* @__PURE__ */ jsxs2(
735
+ Alert,
736
+ {
737
+ variant: "destructive",
738
+ role: "alert",
739
+ "data-refusal-notice": "",
740
+ "data-archived-organization": organizationId,
741
+ className: cn2("text-xs", className),
742
+ errorFacts: { message: "This organization is archived", title: "This organization is archived", error, origin: "records-ui/ArchivedOrganizationNotice" },
743
+ children: [
744
+ /* @__PURE__ */ jsx3(AlertTitle, { className: "text-xs font-medium", children: "This organization is archived" }),
745
+ /* @__PURE__ */ jsxs2(AlertDescription, { className: "space-y-1 text-xs", children: [
746
+ /* @__PURE__ */ jsx3("p", { className: "opacity-80", children: "Nothing was deleted. Everything here comes back the moment an owner of the organization, or a super admin, restores it." }),
747
+ mayRestore === true ? /* @__PURE__ */ jsx3(
748
+ "button",
749
+ {
750
+ type: "button",
751
+ "data-restore-organization": "",
752
+ disabled: busy,
753
+ className: "rounded border px-2 py-0.5 text-xs hover:bg-muted disabled:opacity-60",
754
+ onClick: () => void restore(),
755
+ children: busy ? "Restoring..." : "Restore organization"
756
+ }
757
+ ) : null,
758
+ mayRestore === false ? /* @__PURE__ */ jsx3("p", { "data-restore-who": "", className: "opacity-80", children: "Ask an owner of this organization to restore it." }) : null,
759
+ failed ? /* @__PURE__ */ jsx3("p", { "data-restore-refused": "", children: failed }) : null
760
+ ] })
761
+ ]
762
+ }
763
+ );
764
+ }
765
+
766
+ // src/Refusal.tsx
767
+ import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
768
+ function RefusalNotice({
769
+ error,
770
+ className,
771
+ actions,
772
+ onKeepEditing,
773
+ onDiscard
774
+ }) {
775
+ const archivedOrg = archivedOrganizationId(error);
776
+ if (archivedOrg) {
777
+ return /* @__PURE__ */ jsx4(ArchivedOrganizationNotice, { organizationId: archivedOrg, error, className });
778
+ }
779
+ const plain = refusalForAPerson(error);
780
+ const doors = onKeepEditing || onDiscard ? /* @__PURE__ */ jsxs3("div", { className: "flex flex-wrap items-center gap-1 pt-0.5", "data-refusal-doors": "", children: [
781
+ onKeepEditing ? /* @__PURE__ */ jsx4(
782
+ "button",
783
+ {
784
+ type: "button",
785
+ "data-refusal-keep-editing": "",
786
+ className: "rounded border px-2 py-0.5 text-xs hover:bg-muted",
787
+ onClick: onKeepEditing,
788
+ children: "Keep editing"
789
+ }
790
+ ) : null,
791
+ onDiscard ? /* @__PURE__ */ jsx4(
792
+ "button",
793
+ {
794
+ type: "button",
795
+ "data-refusal-discard": "",
796
+ className: "rounded border px-2 py-0.5 text-xs hover:bg-muted",
797
+ onClick: onDiscard,
798
+ children: "Discard"
799
+ }
800
+ ) : null
801
+ ] }) : null;
802
+ return /* @__PURE__ */ jsxs3(
803
+ Alert2,
804
+ {
805
+ variant: "destructive",
806
+ role: "alert",
807
+ "data-refusal-notice": "",
808
+ className: cn3("text-xs", className),
809
+ errorFacts: { message: plain.sentence, title: plain.title, error, origin: "records-ui/RefusalNotice" },
810
+ ...plain.forEngineers ? { "data-for-engineers": plain.forEngineers } : {},
811
+ ...error.sqlstate ? { "data-sqlstate": error.sqlstate } : {},
812
+ children: [
813
+ /* @__PURE__ */ jsx4(AlertTitle2, { className: "text-xs font-medium", children: plain.storeSaid ? plain.sentence : plain.title }),
814
+ /* @__PURE__ */ jsxs3(AlertDescription2, { className: "space-y-1 text-xs", children: [
815
+ plain.storeSaid || plain.sentence.replace(/\.$/, "") === plain.title ? null : /* @__PURE__ */ jsx4("p", { children: plain.sentence }),
816
+ /* @__PURE__ */ jsx4("p", { className: "opacity-80", children: plain.remedy }),
817
+ actions,
818
+ doors
819
+ ] })
820
+ ]
821
+ }
822
+ );
823
+ }
824
+ function RefusalLine({ error, className }) {
825
+ const plain = refusalForAPerson(error);
826
+ return /* @__PURE__ */ jsx4(
827
+ ErrorBox,
828
+ {
829
+ "data-refusal-line": "",
830
+ className: cn3("text-xs text-destructive", className),
831
+ message: archivedOrganizationId(error) ? "This organization is archived. An owner can restore it." : refusalLineForAPerson(error),
832
+ error,
833
+ origin: "records-ui/RefusalLine",
834
+ ...plain.forEngineers ? { "data-for-engineers": plain.forEngineers } : {}
835
+ }
836
+ );
837
+ }
838
+
568
839
  // src/AddChoicesInline.tsx
569
- import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
840
+ import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
570
841
  function AddChoicesInline({ field, onAdded, disabled = false }) {
571
842
  const client = useOptionalRecordsClient();
572
- const [open, setOpen] = useState2(false);
573
- const [rows, setRows] = useState2(() => [newChoiceRow([])]);
574
- const [saving, setSaving] = useState2(false);
575
- const [refused, setRefused] = useState2(null);
843
+ const [open, setOpen] = useState3(false);
844
+ const [rows, setRows] = useState3(() => [newChoiceRow([])]);
845
+ const [saving, setSaving] = useState3(false);
846
+ const [refused, setRefused] = useState3(null);
576
847
  if (!client) return null;
577
848
  const words = rows.map((r) => r.words.trim()).filter((w) => w !== "");
578
849
  const missing = whatTheChoiceListIsMissing(rows);
@@ -582,19 +853,20 @@ function AddChoicesInline({ field, onAdded, disabled = false }) {
582
853
  const done = await client.fieldUpdate({ field_id: field.id, patch: { options_add: words } });
583
854
  setSaving(false);
584
855
  if (!done.ok) {
585
- setRefused(refusalSentence(done.error));
856
+ setRefused(done.error);
586
857
  return;
587
858
  }
588
859
  setOpen(false);
589
860
  setRows([newChoiceRow([])]);
590
861
  onAdded();
591
862
  };
592
- return /* @__PURE__ */ jsxs2(Popover2, { open, onOpenChange: setOpen, children: [
593
- /* @__PURE__ */ jsx2(PopoverTrigger2, { asChild: true, children: /* @__PURE__ */ jsx2(Button2, { type: "button", size: "sm", variant: "outline", className: "h-7 self-start text-xs", disabled, "data-records-add-choices": "", children: "Add choices" }) }),
594
- /* @__PURE__ */ jsxs2(PopoverContent2, { className: "w-72 space-y-2 p-3", align: "start", children: [
595
- /* @__PURE__ */ jsx2(ChoiceListEditor, { isNew: true, rows, onRows: setRows }),
596
- missing || refused ? /* @__PURE__ */ jsx2("p", { className: "text-[11px] text-destructive", children: missing ?? refused }) : null,
597
- /* @__PURE__ */ jsx2(Button2, { type: "button", size: "sm", className: "h-7 text-xs", disabled: saving || words.length === 0 || missing !== null, onClick: () => void save(), children: "Save choices" })
863
+ return /* @__PURE__ */ jsxs4(Popover2, { open, onOpenChange: setOpen, children: [
864
+ /* @__PURE__ */ jsx5(PopoverTrigger2, { asChild: true, children: /* @__PURE__ */ jsx5(Button2, { type: "button", size: "sm", variant: "outline", className: "h-7 self-start text-xs", disabled, "data-records-add-choices": "", children: "Add choices" }) }),
865
+ /* @__PURE__ */ jsxs4(PopoverContent2, { className: "w-72 space-y-2 p-3", align: "start", children: [
866
+ /* @__PURE__ */ jsx5(ChoiceListEditor, { isNew: true, rows, onRows: setRows }),
867
+ missing ? /* @__PURE__ */ jsx5("p", { className: "text-[11px] text-muted-foreground", children: missing }) : null,
868
+ refused ? /* @__PURE__ */ jsx5(RefusalLine, { error: refused }) : null,
869
+ /* @__PURE__ */ jsx5(Button2, { type: "button", size: "sm", className: "h-7 text-xs", disabled: saving || words.length === 0 || missing !== null, onClick: () => void save(), children: "Save choices" })
598
870
  ] })
599
871
  ] });
600
872
  }
@@ -664,7 +936,7 @@ function isDateLike(value) {
664
936
  }
665
937
 
666
938
  // src/newerKindValues.tsx
667
- import { useEffect as useEffect2, useRef as useRef2, useState as useState3 } from "react";
939
+ import { useEffect as useEffect3, useRef as useRef2, useState as useState4 } from "react";
668
940
  import { codeSpanText, findInlineCodeSpans } from "@ai-matrx/content-ir/source";
669
941
  import {
670
942
  ADDRESS_PARTS,
@@ -681,29 +953,29 @@ import {
681
953
  safeLinkHref,
682
954
  statusGroupOf
683
955
  } from "@ai-matrx/records";
684
- import { BasicInput as BasicInput2, cn as cn2 } from "@ai-matrx/design-system";
685
- import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
956
+ import { BasicInput as BasicInput2, cn as cn4 } from "@ai-matrx/design-system";
957
+ import { Fragment as Fragment2, jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
686
958
  var own = (event) => event.stopPropagation();
687
959
  function newerKindValue(field, value, opts = {}) {
688
960
  switch (newerKindOf2(field)) {
689
961
  case "duration": {
690
962
  const words = durationText(value);
691
- return words === null ? void 0 : /* @__PURE__ */ jsx3("span", { className: "tabular-nums", "data-records-duration": "", children: words });
963
+ return words === null ? void 0 : /* @__PURE__ */ jsx6("span", { className: "tabular-nums", "data-records-duration": "", children: words });
692
964
  }
693
965
  case "created_by":
694
966
  case "modified_by":
695
- return isPersonStamp(value) ? /* @__PURE__ */ jsx3(PersonStampChip, { stamp: value }) : void 0;
967
+ return isPersonStamp(value) ? /* @__PURE__ */ jsx6(PersonStampChip, { stamp: value }) : void 0;
696
968
  case "address":
697
- return isAddressValue(value) || typeof value === "string" ? /* @__PURE__ */ jsx3(AddressLink, { value }) : void 0;
969
+ return isAddressValue(value) || typeof value === "string" ? /* @__PURE__ */ jsx6(AddressLink, { value }) : void 0;
698
970
  case "barcode":
699
- return typeof value === "string" ? /* @__PURE__ */ jsxs3("span", { className: "inline-flex min-w-0 items-center gap-1 font-mono text-xs", "data-records-barcode": "", title: value, children: [
700
- /* @__PURE__ */ jsx3("span", { "aria-hidden": "true", className: "text-muted-foreground", children: "\u25AE\u25AF\u25AE" }),
701
- /* @__PURE__ */ jsx3("span", { className: "truncate", children: value })
971
+ return typeof value === "string" ? /* @__PURE__ */ jsxs5("span", { className: "inline-flex min-w-0 items-center gap-1 font-mono text-xs", "data-records-barcode": "", title: value, children: [
972
+ /* @__PURE__ */ jsx6("span", { "aria-hidden": "true", className: "text-muted-foreground", children: "\u25AE\u25AF\u25AE" }),
973
+ /* @__PURE__ */ jsx6("span", { className: "truncate", children: value })
702
974
  ] }) : void 0;
703
975
  case "rich_text":
704
- return typeof value === "string" ? /* @__PURE__ */ jsx3(SafeMarkdown, { text: value, clipped: opts.inCell === true }) : void 0;
976
+ return typeof value === "string" ? /* @__PURE__ */ jsx6(SafeMarkdown, { text: value, clipped: opts.inCell === true }) : void 0;
705
977
  case "count":
706
- return typeof value === "number" ? /* @__PURE__ */ jsx3("span", { className: "tabular-nums", children: value.toLocaleString() }) : void 0;
978
+ return typeof value === "number" ? /* @__PURE__ */ jsx6("span", { className: "tabular-nums", children: value.toLocaleString() }) : void 0;
707
979
  default:
708
980
  return void 0;
709
981
  }
@@ -713,8 +985,8 @@ function PersonStampChip({ stamp }) {
713
985
  const tier = stamp.actor ?? "user";
714
986
  const name = tier === "user" ? stamp.name : null;
715
987
  const initial = tier === "system" ? "\u2699" : tier === "agent" ? "\u2726" : name && name.trim() !== "" ? name.trim()[0].toUpperCase() : "?";
716
- return /* @__PURE__ */ jsxs3("span", { className: "inline-flex min-w-0 items-center gap-1.5", "data-records-person-stamp": tier, children: [
717
- /* @__PURE__ */ jsx3(
988
+ return /* @__PURE__ */ jsxs5("span", { className: "inline-flex min-w-0 items-center gap-1.5", "data-records-person-stamp": tier, children: [
989
+ /* @__PURE__ */ jsx6(
718
990
  "span",
719
991
  {
720
992
  "aria-hidden": "true",
@@ -722,14 +994,14 @@ function PersonStampChip({ stamp }) {
722
994
  children: initial
723
995
  }
724
996
  ),
725
- /* @__PURE__ */ jsx3("span", { className: cn2("truncate", tier === "user" && !name ? "italic text-muted-foreground" : ""), children: words })
997
+ /* @__PURE__ */ jsx6("span", { className: cn4("truncate", tier === "user" && !name ? "italic text-muted-foreground" : ""), children: words })
726
998
  ] });
727
999
  }
728
1000
  function AddressLink({ value }) {
729
1001
  const words = addressText(value);
730
1002
  const href = addressMapUrl(value);
731
- if (!words || !href) return /* @__PURE__ */ jsx3("span", { className: "text-muted-foreground", children: "\u2014" });
732
- return /* @__PURE__ */ jsxs3(
1003
+ if (!words || !href) return /* @__PURE__ */ jsx6("span", { className: "text-muted-foreground", children: "\u2014" });
1004
+ return /* @__PURE__ */ jsxs5(
733
1005
  "a",
734
1006
  {
735
1007
  href,
@@ -740,8 +1012,8 @@ function AddressLink({ value }) {
740
1012
  "data-records-address": "",
741
1013
  onClick: own,
742
1014
  children: [
743
- /* @__PURE__ */ jsx3("span", { "aria-hidden": "true", children: "\u2316" }),
744
- /* @__PURE__ */ jsx3("span", { className: "truncate", children: words })
1015
+ /* @__PURE__ */ jsx6("span", { "aria-hidden": "true", children: "\u2316" }),
1016
+ /* @__PURE__ */ jsx6("span", { className: "truncate", children: words })
745
1017
  ]
746
1018
  }
747
1019
  );
@@ -761,7 +1033,7 @@ function inline(text, key) {
761
1033
  for (const r of findInlineCodeSpans(text)) {
762
1034
  if (r.start < at) continue;
763
1035
  if (r.start > at) out.push(...marks(text.slice(at, r.start), `${key}-m${n++}`));
764
- out.push(/* @__PURE__ */ jsx3("code", { className: "rounded bg-muted px-1 font-mono text-[0.9em]", children: codeSpanText(text.slice(r.start, r.end)) }, `${key}-c${n++}`));
1036
+ out.push(/* @__PURE__ */ jsx6("code", { className: "rounded bg-muted px-1 font-mono text-[0.9em]", children: codeSpanText(text.slice(r.start, r.end)) }, `${key}-c${n++}`));
765
1037
  at = r.end;
766
1038
  }
767
1039
  if (at < text.length) out.push(...marks(text.slice(at), `${key}-m${n++}`));
@@ -777,14 +1049,14 @@ function marks(text, key) {
777
1049
  if (at > last) out.push(text.slice(last, at));
778
1050
  const tok = m[0];
779
1051
  const k = `${key}-${i++}`;
780
- if (tok.startsWith("**") || tok.startsWith("__")) out.push(/* @__PURE__ */ jsx3("strong", { children: tok.slice(2, -2) }, k));
1052
+ if (tok.startsWith("**") || tok.startsWith("__")) out.push(/* @__PURE__ */ jsx6("strong", { children: tok.slice(2, -2) }, k));
781
1053
  else if (tok.startsWith("[")) {
782
1054
  const link = /^\[([^\]]+)\]\(([^)\s]+)\)$/.exec(tok);
783
1055
  const href = safeLinkHref(link?.[2] ?? "");
784
1056
  out.push(
785
- href ? /* @__PURE__ */ jsx3("a", { href, target: "_blank", rel: "noopener noreferrer", className: "text-primary underline-offset-2 hover:underline", onClick: own, children: link?.[1] }, k) : link?.[1] ?? tok
1057
+ 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
786
1058
  );
787
- } else out.push(/* @__PURE__ */ jsx3("em", { children: tok.slice(1, -1) }, k));
1059
+ } else out.push(/* @__PURE__ */ jsx6("em", { children: tok.slice(1, -1) }, k));
788
1060
  last = at + tok.length;
789
1061
  }
790
1062
  if (last < text.length) out.push(text.slice(last));
@@ -797,15 +1069,15 @@ function SafeMarkdown({ text, clipped }) {
797
1069
  let para = [];
798
1070
  const flushPara = () => {
799
1071
  if (para.length > 0) {
800
- blocks.push(/* @__PURE__ */ jsx3("p", { children: inline(para.join(" "), `p${blocks.length}`) }, `p${blocks.length}`));
1072
+ blocks.push(/* @__PURE__ */ jsx6("p", { children: inline(para.join(" "), `p${blocks.length}`) }, `p${blocks.length}`));
801
1073
  para = [];
802
1074
  }
803
1075
  };
804
1076
  const flushList = () => {
805
1077
  if (list) {
806
- const items = list.items.map((item, i) => /* @__PURE__ */ jsx3("li", { children: inline(item, `l${blocks.length}-${i}`) }, i));
1078
+ const items = list.items.map((item, i) => /* @__PURE__ */ jsx6("li", { children: inline(item, `l${blocks.length}-${i}`) }, i));
807
1079
  blocks.push(
808
- list.ordered ? /* @__PURE__ */ jsx3("ol", { className: "ml-4 list-decimal", children: items }, `o${blocks.length}`) : /* @__PURE__ */ jsx3("ul", { className: "ml-4 list-disc", children: items }, `u${blocks.length}`)
1080
+ list.ordered ? /* @__PURE__ */ jsx6("ol", { className: "ml-4 list-decimal", children: items }, `o${blocks.length}`) : /* @__PURE__ */ jsx6("ul", { className: "ml-4 list-disc", children: items }, `u${blocks.length}`)
809
1081
  );
810
1082
  list = null;
811
1083
  }
@@ -824,7 +1096,7 @@ function SafeMarkdown({ text, clipped }) {
824
1096
  } else if (heading) {
825
1097
  flushPara();
826
1098
  flushList();
827
- blocks.push(/* @__PURE__ */ jsx3("p", { className: "font-semibold", children: inline(heading[2], `h${blocks.length}`) }, `h${blocks.length}`));
1099
+ blocks.push(/* @__PURE__ */ jsx6("p", { className: "font-semibold", children: inline(heading[2], `h${blocks.length}`) }, `h${blocks.length}`));
828
1100
  } else if (line.trim() === "") {
829
1101
  flushPara();
830
1102
  flushList();
@@ -835,10 +1107,10 @@ function SafeMarkdown({ text, clipped }) {
835
1107
  }
836
1108
  flushPara();
837
1109
  flushList();
838
- return /* @__PURE__ */ jsx3(
1110
+ return /* @__PURE__ */ jsx6(
839
1111
  "span",
840
1112
  {
841
- className: cn2("block min-w-0 space-y-1 whitespace-normal text-sm", clipped ? "max-h-[4.5em] overflow-hidden" : ""),
1113
+ className: cn4("block min-w-0 space-y-1 whitespace-normal text-sm", clipped ? "max-h-[4.5em] overflow-hidden" : ""),
842
1114
  "data-records-rich-text": "",
843
1115
  children: blocks
844
1116
  }
@@ -847,27 +1119,27 @@ function SafeMarkdown({ text, clipped }) {
847
1119
  function newerKindControl(props) {
848
1120
  switch (newerKindOf2(props.field)) {
849
1121
  case "duration":
850
- return /* @__PURE__ */ jsx3(DurationControl, { ...props });
1122
+ return /* @__PURE__ */ jsx6(DurationControl, { ...props });
851
1123
  case "address":
852
- return /* @__PURE__ */ jsx3(AddressControl, { ...props });
1124
+ return /* @__PURE__ */ jsx6(AddressControl, { ...props });
853
1125
  case "barcode":
854
- return /* @__PURE__ */ jsx3(BarcodeControl, { ...props });
1126
+ return /* @__PURE__ */ jsx6(BarcodeControl, { ...props });
855
1127
  case "created_by":
856
1128
  case "modified_by":
857
1129
  case "count":
858
- return /* @__PURE__ */ jsx3("div", { id: props.id, className: "rounded border border-dashed px-2 py-1.5 text-xs text-muted-foreground", children: props.value === null || props.value === void 0 ? "\u2014" : newerKindValue(props.field, props.value) });
1130
+ return /* @__PURE__ */ jsx6("div", { id: props.id, className: "rounded border border-dashed px-2 py-1.5 text-xs text-muted-foreground", children: props.value === null || props.value === void 0 ? "\u2014" : newerKindValue(props.field, props.value) });
859
1131
  default:
860
1132
  return void 0;
861
1133
  }
862
1134
  }
863
1135
  function DurationControl({ value, onChange, disabled, id }) {
864
- const [text, setText] = useState3(() => durationText(value) ?? "");
865
- const [wrong, setWrong] = useState3(false);
866
- useEffect2(() => {
1136
+ const [text, setText] = useState4(() => durationText(value) ?? "");
1137
+ const [wrong, setWrong] = useState4(false);
1138
+ useEffect3(() => {
867
1139
  setText(durationText(value) ?? "");
868
1140
  }, [value]);
869
- return /* @__PURE__ */ jsxs3("span", { className: "flex flex-col gap-1", children: [
870
- /* @__PURE__ */ jsx3(
1141
+ return /* @__PURE__ */ jsxs5("span", { className: "flex flex-col gap-1", children: [
1142
+ /* @__PURE__ */ jsx6(
871
1143
  BasicInput2,
872
1144
  {
873
1145
  id,
@@ -893,7 +1165,7 @@ function DurationControl({ value, onChange, disabled, id }) {
893
1165
  }
894
1166
  }
895
1167
  ),
896
- wrong ? /* @__PURE__ */ jsx3("span", { className: "text-[11px] text-destructive", children: "Write it like 45 min, 1:30 or 1h 30m." }) : null
1168
+ wrong ? /* @__PURE__ */ jsx6("span", { className: "text-[11px] text-destructive", children: "Write it like 45 min, 1:30 or 1h 30m." }) : null
897
1169
  ] });
898
1170
  }
899
1171
  var ADDRESS_LABELS = {
@@ -917,7 +1189,7 @@ function AddressControl({ value, onChange, disabled, id }) {
917
1189
  const kept = Object.fromEntries(Object.entries(next).filter(([, v]) => typeof v === "string" && v.trim() !== ""));
918
1190
  onChange(Object.keys(kept).length === 0 ? null : kept);
919
1191
  };
920
- return /* @__PURE__ */ jsx3("span", { id, className: "grid grid-cols-2 gap-1.5", "data-records-address-control": "", children: ADDRESS_PARTS.map((part) => /* @__PURE__ */ jsx3(
1192
+ return /* @__PURE__ */ jsx6("span", { id, className: "grid grid-cols-2 gap-1.5", "data-records-address-control": "", children: ADDRESS_PARTS.map((part) => /* @__PURE__ */ jsx6(
921
1193
  BasicInput2,
922
1194
  {
923
1195
  "aria-label": ADDRESS_LABELS[part],
@@ -937,11 +1209,11 @@ function barcodeDetector() {
937
1209
  }
938
1210
  function BarcodeControl({ value, onChange, disabled, id }) {
939
1211
  const file = useRef2(null);
940
- const [said2, setSaid] = useState3(null);
1212
+ const [said2, setSaid] = useState4(null);
941
1213
  const Detect = barcodeDetector();
942
- return /* @__PURE__ */ jsxs3("span", { className: "flex flex-col gap-1", children: [
943
- /* @__PURE__ */ jsxs3("span", { className: "flex items-center gap-1.5", children: [
944
- /* @__PURE__ */ jsx3(
1214
+ return /* @__PURE__ */ jsxs5("span", { className: "flex flex-col gap-1", children: [
1215
+ /* @__PURE__ */ jsxs5("span", { className: "flex items-center gap-1.5", children: [
1216
+ /* @__PURE__ */ jsx6(
945
1217
  BasicInput2,
946
1218
  {
947
1219
  id,
@@ -952,8 +1224,8 @@ function BarcodeControl({ value, onChange, disabled, id }) {
952
1224
  onChange: (e) => onChange(e.target.value === "" ? null : e.target.value)
953
1225
  }
954
1226
  ),
955
- Detect && !disabled ? /* @__PURE__ */ jsxs3(Fragment2, { children: [
956
- /* @__PURE__ */ jsx3(
1227
+ Detect && !disabled ? /* @__PURE__ */ jsxs5(Fragment2, { children: [
1228
+ /* @__PURE__ */ jsx6(
957
1229
  "button",
958
1230
  {
959
1231
  type: "button",
@@ -962,7 +1234,7 @@ function BarcodeControl({ value, onChange, disabled, id }) {
962
1234
  children: "Scan"
963
1235
  }
964
1236
  ),
965
- /* @__PURE__ */ jsx3(
1237
+ /* @__PURE__ */ jsx6(
966
1238
  "input",
967
1239
  {
968
1240
  ref: file,
@@ -988,7 +1260,7 @@ function BarcodeControl({ value, onChange, disabled, id }) {
988
1260
  )
989
1261
  ] }) : null
990
1262
  ] }),
991
- said2 ? /* @__PURE__ */ jsx3("span", { className: "text-[11px] text-muted-foreground", children: said2 }) : null
1263
+ said2 ? /* @__PURE__ */ jsx6("span", { className: "text-[11px] text-muted-foreground", children: said2 }) : null
992
1264
  ] });
993
1265
  }
994
1266
 
@@ -1166,23 +1438,23 @@ import { useOptionalRecordsClient as useOptionalRecordsClient2 } from "@ai-matrx
1166
1438
  import { BasicInput as BasicInput4, Button as Button4, cn as cn7 } from "@ai-matrx/design-system";
1167
1439
 
1168
1440
  // src/PickOrAdd.tsx
1169
- import { useEffect as useEffect3, useRef as useRef3, useState as useState4 } from "react";
1441
+ import { useEffect as useEffect4, useRef as useRef3, useState as useState5 } from "react";
1170
1442
 
1171
1443
  // src/personChip.tsx
1172
- import { cn as cn3 } from "@ai-matrx/design-system";
1173
- import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
1444
+ import { cn as cn5 } from "@ai-matrx/design-system";
1445
+ import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
1174
1446
  function initialsOf(name) {
1175
1447
  const words = name.replace(/@.*$/, "").split(/[\s._-]+/).filter((w) => /\p{L}|\d/u.test(w));
1176
1448
  const letters = words.filter((w) => !/^(dr|mr|mrs|ms|prof)\.?$/i.test(w)).slice(0, 2).map((w) => (w.match(/[\p{L}\d]/u)?.[0] ?? "").toUpperCase());
1177
1449
  return letters.join("") || "?";
1178
1450
  }
1179
1451
  function PersonAvatar({ name, size = "sm" }) {
1180
- return /* @__PURE__ */ jsx4(
1452
+ return /* @__PURE__ */ jsx7(
1181
1453
  "span",
1182
1454
  {
1183
1455
  "aria-hidden": "true",
1184
1456
  "data-records-person-avatar": "",
1185
- className: cn3(
1457
+ className: cn5(
1186
1458
  "inline-flex shrink-0 items-center justify-center rounded-full bg-foreground/10 font-medium text-foreground/80",
1187
1459
  size === "md" ? "size-5 text-[10px]" : "size-4 text-[9px]"
1188
1460
  ),
@@ -1191,35 +1463,35 @@ function PersonAvatar({ name, size = "sm" }) {
1191
1463
  );
1192
1464
  }
1193
1465
  function PersonChip({ name, onRemove, className }) {
1194
- return /* @__PURE__ */ jsxs4(
1466
+ return /* @__PURE__ */ jsxs6(
1195
1467
  "span",
1196
1468
  {
1197
1469
  "data-records-person-chip": "",
1198
1470
  title: name,
1199
- className: cn3("inline-flex min-w-0 max-w-full items-center gap-1 rounded-full bg-muted px-1.5 py-0.5 text-[11px] text-foreground", className),
1471
+ className: cn5("inline-flex min-w-0 max-w-full items-center gap-1 rounded-full bg-muted px-1.5 py-0.5 text-[11px] text-foreground", className),
1200
1472
  children: [
1201
- /* @__PURE__ */ jsx4(PersonAvatar, { name }),
1202
- /* @__PURE__ */ jsx4("span", { className: "min-w-0 truncate", children: name }),
1203
- onRemove ? /* @__PURE__ */ jsx4("button", { type: "button", onClick: onRemove, "aria-label": `Remove ${name}`, className: "shrink-0 opacity-60 hover:opacity-100", children: "\xD7" }) : null
1473
+ /* @__PURE__ */ jsx7(PersonAvatar, { name }),
1474
+ /* @__PURE__ */ jsx7("span", { className: "min-w-0 truncate", children: name }),
1475
+ onRemove ? /* @__PURE__ */ jsx7("button", { type: "button", onClick: onRemove, "aria-label": `Remove ${name}`, className: "shrink-0 opacity-60 hover:opacity-100", children: "\xD7" }) : null
1204
1476
  ]
1205
1477
  }
1206
1478
  );
1207
1479
  }
1208
1480
 
1209
1481
  // src/PickOrAdd.tsx
1210
- import { BasicInput as BasicInput3, Button as Button3, Popover as Popover3, PopoverAnchor, PopoverContent as PopoverContent3, PopoverTrigger as PopoverTrigger3, ScrollArea, cn as cn4 } from "@ai-matrx/design-system";
1211
- import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
1482
+ import { BasicInput as BasicInput3, Button as Button3, Popover as Popover3, PopoverAnchor, PopoverContent as PopoverContent3, PopoverTrigger as PopoverTrigger3, ScrollArea, cn as cn6 } from "@ai-matrx/design-system";
1483
+ import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
1212
1484
  function Glyph({ d, className }) {
1213
- return /* @__PURE__ */ jsx5("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2.5, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, className, children: /* @__PURE__ */ jsx5("path", { d }) });
1485
+ return /* @__PURE__ */ jsx8("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2.5, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, className, children: /* @__PURE__ */ jsx8("path", { d }) });
1214
1486
  }
1215
1487
  var TICK = "m5 12 4 4L19 6";
1216
1488
  var CROSS = "M18 6 6 18M6 6l12 12";
1217
1489
  var PLUS = "M12 5v14M5 12h14";
1218
1490
  function useListKeys(args) {
1219
1491
  const { count, resetOn, onPick, onNothing, onClose, onFinish, onBackspaceEmpty, searchEmpty } = args;
1220
- const [highlight, setHighlight] = useState4(0);
1221
- const [moved, setMoved] = useState4(false);
1222
- useEffect3(() => {
1492
+ const [highlight, setHighlight] = useState5(0);
1493
+ const [moved, setMoved] = useState5(false);
1494
+ useEffect4(() => {
1223
1495
  setHighlight(0);
1224
1496
  setMoved(false);
1225
1497
  }, [resetOn]);
@@ -1265,10 +1537,10 @@ function PickRow({
1265
1537
  onPoint
1266
1538
  }) {
1267
1539
  const ref = useRef3(null);
1268
- useEffect3(() => {
1540
+ useEffect4(() => {
1269
1541
  if (highlighted) ref.current?.scrollIntoView?.({ block: "nearest" });
1270
1542
  }, [highlighted]);
1271
- return /* @__PURE__ */ jsxs5(
1543
+ return /* @__PURE__ */ jsxs7(
1272
1544
  "button",
1273
1545
  {
1274
1546
  ref,
@@ -1281,19 +1553,19 @@ function PickRow({
1281
1553
  title: title ?? label,
1282
1554
  ...attrs ?? {},
1283
1555
  "data-pick-highlighted": highlighted ? "" : void 0,
1284
- className: cn4(
1556
+ className: cn6(
1285
1557
  "flex w-full min-w-0 items-center gap-2 rounded-sm px-2 py-1.5 text-left text-sm outline-none disabled:opacity-50",
1286
1558
  highlighted ? "bg-accent text-accent-foreground" : ""
1287
1559
  ),
1288
1560
  children: [
1289
- /* @__PURE__ */ jsxs5("span", { className: "flex size-3.5 shrink-0 items-center justify-center", children: [
1290
- picked ? /* @__PURE__ */ jsx5("span", { "data-pick-tick": "", className: "contents", children: /* @__PURE__ */ jsx5(Glyph, { d: TICK, className: "size-3.5" }) }) : null,
1291
- icon === "plus" ? /* @__PURE__ */ jsx5(Glyph, { d: PLUS, className: "size-3.5 text-muted-foreground" }) : null
1561
+ /* @__PURE__ */ jsxs7("span", { className: "flex size-3.5 shrink-0 items-center justify-center", children: [
1562
+ picked ? /* @__PURE__ */ jsx8("span", { "data-pick-tick": "", className: "contents", children: /* @__PURE__ */ jsx8(Glyph, { d: TICK, className: "size-3.5" }) }) : null,
1563
+ icon === "plus" ? /* @__PURE__ */ jsx8(Glyph, { d: PLUS, className: "size-3.5 text-muted-foreground" }) : null
1292
1564
  ] }),
1293
- person ? /* @__PURE__ */ jsx5(PersonAvatar, { name: label, size: "md" }) : null,
1294
- /* @__PURE__ */ jsxs5("span", { className: "min-w-0 flex-1", children: [
1295
- chip ? /* @__PURE__ */ jsx5("span", { className: cn4("inline-flex max-w-full truncate rounded-md border px-1.5 py-0.5 text-xs font-medium", chip), "data-records-choice-chip": "", children: label }) : /* @__PURE__ */ jsx5("span", { className: "block truncate", children: label }),
1296
- detail ? /* @__PURE__ */ jsx5("span", { className: "block truncate text-xs text-muted-foreground", "data-tell-apart": "", children: detail }) : null
1565
+ person ? /* @__PURE__ */ jsx8(PersonAvatar, { name: label, size: "md" }) : null,
1566
+ /* @__PURE__ */ jsxs7("span", { className: "min-w-0 flex-1", children: [
1567
+ chip ? /* @__PURE__ */ jsx8("span", { className: cn6("inline-flex max-w-full truncate rounded-md border px-1.5 py-0.5 text-xs font-medium", chip), "data-records-choice-chip": "", children: label }) : /* @__PURE__ */ jsx8("span", { className: "block truncate", children: label }),
1568
+ detail ? /* @__PURE__ */ jsx8("span", { className: "block truncate text-xs text-muted-foreground", "data-tell-apart": "", children: detail }) : null
1297
1569
  ] })
1298
1570
  ]
1299
1571
  }
@@ -1301,26 +1573,26 @@ function PickRow({
1301
1573
  }
1302
1574
  function PickChips({ chips }) {
1303
1575
  if (chips.length === 0) return null;
1304
- return /* @__PURE__ */ jsx5("div", { className: "flex flex-wrap gap-1 px-1 pb-1", "data-pick-chips": "", children: chips.map(
1305
- (c) => c.person ? /* @__PURE__ */ jsx5(PersonChip, { name: c.label, onRemove: c.onRemove }, c.id) : /* @__PURE__ */ jsxs5(
1576
+ return /* @__PURE__ */ jsx8("div", { className: "flex flex-wrap gap-1 px-1 pb-1", "data-pick-chips": "", children: chips.map(
1577
+ (c) => c.person ? /* @__PURE__ */ jsx8(PersonChip, { name: c.label, onRemove: c.onRemove }, c.id) : /* @__PURE__ */ jsxs7(
1306
1578
  "span",
1307
1579
  {
1308
1580
  "data-pick-chip": "",
1309
1581
  title: c.label,
1310
- className: cn4(
1582
+ className: cn6(
1311
1583
  "inline-flex max-w-full items-center gap-1 rounded-md border px-1.5 py-0.5 text-xs font-medium",
1312
1584
  c.chip ?? "bg-secondary text-secondary-foreground"
1313
1585
  ),
1314
1586
  children: [
1315
- /* @__PURE__ */ jsx5("span", { className: "min-w-0 truncate", children: c.label }),
1316
- c.onRemove ? /* @__PURE__ */ jsx5(
1587
+ /* @__PURE__ */ jsx8("span", { className: "min-w-0 truncate", children: c.label }),
1588
+ c.onRemove ? /* @__PURE__ */ jsx8(
1317
1589
  "button",
1318
1590
  {
1319
1591
  type: "button",
1320
1592
  "aria-label": `Remove ${c.label}`,
1321
1593
  onClick: c.onRemove,
1322
1594
  className: "shrink-0 rounded-sm opacity-60 hover:opacity-100",
1323
- children: /* @__PURE__ */ jsx5(Glyph, { d: CROSS, className: "size-3" })
1595
+ children: /* @__PURE__ */ jsx8(Glyph, { d: CROSS, className: "size-3" })
1324
1596
  }
1325
1597
  ) : null
1326
1598
  ]
@@ -1375,7 +1647,7 @@ function PickOrAdd({
1375
1647
  searchEmpty: search === ""
1376
1648
  });
1377
1649
  const hasFoot = Boolean(foot) || Boolean(footNote);
1378
- const addRowNode = addRow ? /* @__PURE__ */ jsx5(
1650
+ const addRowNode = addRow ? /* @__PURE__ */ jsx8(
1379
1651
  PickRow,
1380
1652
  {
1381
1653
  label: addRow.label,
@@ -1388,9 +1660,9 @@ function PickOrAdd({
1388
1660
  onPoint: () => keys.setHighlight(addAt)
1389
1661
  }
1390
1662
  ) : null;
1391
- return /* @__PURE__ */ jsxs5(Popover3, { open, onOpenChange, children: [
1392
- anchored ? /* @__PURE__ */ jsx5(PopoverAnchor, { asChild: true, children: /* @__PURE__ */ jsx5("div", { "data-pick-anchor": "", className: "flex min-h-6 w-full min-w-0 flex-wrap items-center gap-1", "aria-label": triggerLabel, children }) }) : /* @__PURE__ */ jsx5(PopoverTrigger3, { asChild: true, children: /* @__PURE__ */ jsx5(Button3, { id: triggerId, type: "button", size: "sm", variant: "outline", className: triggerSize === "field" ? "h-9" : void 0, "aria-label": triggerLabel, children: triggerText }) }),
1393
- /* @__PURE__ */ jsxs5(
1663
+ return /* @__PURE__ */ jsxs7(Popover3, { open, onOpenChange, children: [
1664
+ anchored ? /* @__PURE__ */ jsx8(PopoverAnchor, { asChild: true, children: /* @__PURE__ */ jsx8("div", { "data-pick-anchor": "", className: "flex min-h-6 w-full min-w-0 flex-wrap items-center gap-1", "aria-label": triggerLabel, children }) }) : /* @__PURE__ */ jsx8(PopoverTrigger3, { asChild: true, children: /* @__PURE__ */ jsx8(Button3, { id: triggerId, type: "button", size: "sm", variant: "outline", className: triggerSize === "field" ? "h-9" : void 0, "aria-label": triggerLabel, children: triggerText }) }),
1665
+ /* @__PURE__ */ jsxs7(
1394
1666
  PopoverContent3,
1395
1667
  {
1396
1668
  sizing: "content",
@@ -1412,8 +1684,8 @@ function PickOrAdd({
1412
1684
  if (anchored) event.preventDefault();
1413
1685
  },
1414
1686
  children: [
1415
- chips ? /* @__PURE__ */ jsx5(PickChips, { chips }) : null,
1416
- /* @__PURE__ */ jsx5(
1687
+ chips ? /* @__PURE__ */ jsx8(PickChips, { chips }) : null,
1688
+ /* @__PURE__ */ jsx8(
1417
1689
  BasicInput3,
1418
1690
  {
1419
1691
  value: search,
@@ -1427,9 +1699,9 @@ function PickOrAdd({
1427
1699
  }
1428
1700
  ),
1429
1701
  notice,
1430
- /* @__PURE__ */ jsxs5(ScrollArea, { className: "max-h-64", children: [
1431
- /* @__PURE__ */ jsxs5("div", { role: "listbox", "aria-label": triggerLabel, "aria-multiselectable": multi ? true : void 0, children: [
1432
- items.map((item, index) => /* @__PURE__ */ jsx5(
1702
+ /* @__PURE__ */ jsxs7(ScrollArea, { className: "max-h-64", children: [
1703
+ /* @__PURE__ */ jsxs7("div", { role: "listbox", "aria-label": triggerLabel, "aria-multiselectable": multi ? true : void 0, children: [
1704
+ items.map((item, index) => /* @__PURE__ */ jsx8(
1433
1705
  PickRow,
1434
1706
  {
1435
1707
  label: item.label,
@@ -1450,7 +1722,7 @@ function PickOrAdd({
1450
1722
  ] }),
1451
1723
  items.length === 0 && empty ? empty : null
1452
1724
  ] }),
1453
- hasFoot ? /* @__PURE__ */ jsxs5("div", { className: "mt-1 border-t pt-1", children: [
1725
+ hasFoot ? /* @__PURE__ */ jsxs7("div", { className: "mt-1 border-t pt-1", children: [
1454
1726
  foot,
1455
1727
  footNote
1456
1728
  ] }) : null
@@ -1460,277 +1732,6 @@ function PickOrAdd({
1460
1732
  ] });
1461
1733
  }
1462
1734
 
1463
- // src/Refusal.tsx
1464
- import { archivedOrganizationId } from "@ai-matrx/records/core";
1465
- import { Alert as Alert2, AlertDescription as AlertDescription2, AlertTitle as AlertTitle2, ErrorBox, cn as cn6 } from "@ai-matrx/design-system";
1466
-
1467
- // src/ArchivedOrganizationNotice.tsx
1468
- import { useEffect as useEffect4, useState as useState5 } from "react";
1469
- import { Alert, AlertDescription, AlertTitle, cn as cn5 } from "@ai-matrx/design-system";
1470
-
1471
- // src/host.tsx
1472
- import { createContext, useContext, useMemo } from "react";
1473
- import { useMyLevel, useMyLevels } from "@ai-matrx/records/react";
1474
-
1475
- // src/rights.ts
1476
- import { atLeast } from "@ai-matrx/records";
1477
- var LEVEL_WORD = {
1478
- viewer: "Viewer",
1479
- commenter: "Commenter",
1480
- edit_content: "Content editor",
1481
- editor: "Editor",
1482
- admin: "Admin"
1483
- };
1484
- var NEEDS = {
1485
- read: "viewer",
1486
- // custom.io_comment_write
1487
- comment: "commenter",
1488
- // custom.record_update / custom.record_write — `edit_content` changes rows and page content;
1489
- // columns, views and settings (structure) stay with admin below, and sharing with admin.
1490
- write: "edit_content",
1491
- // custom.view_designate / view_declare / migrate_merge / record_restore — all ask `editor`: more than
1492
- // changing content (`edit_content`), less than changing columns (`admin`).
1493
- organise: "editor",
1494
- // custom.record_delete
1495
- remove: "editor",
1496
- // custom.share_grant — passing your access on is an administrator's right
1497
- share: "admin",
1498
- // custom.field_declare / field_update / field_retire / table settings
1499
- structure: "admin"
1500
- };
1501
- var NOT_YET = "Still asking the store what you may do here. Nothing is offered until it has answered.";
1502
- var NOTHING_AT_ALL = "You have not been given this. Ask somebody who administers it to share it with you.";
1503
- function sentenceFor(what, level) {
1504
- if (level === null) return NOTHING_AT_ALL;
1505
- const need = LEVEL_WORD[NEEDS[what]];
1506
- const have = LEVEL_WORD[level];
1507
- const doing = {
1508
- read: "open this",
1509
- comment: "leave a comment",
1510
- write: "change anything here",
1511
- organise: "organise this",
1512
- remove: "delete this",
1513
- share: "pass this on to somebody else",
1514
- structure: "change the columns of this table"
1515
- };
1516
- return `You are ${have} here, and it takes ${need} to ${doing[what]}. Ask somebody who is Admin on it to move you up.`;
1517
- }
1518
- function whatYouMayDo(level, known = true) {
1519
- const may = (what) => known && atLeast(level, NEEDS[what]);
1520
- return {
1521
- level: known ? level : null,
1522
- known,
1523
- read: may("read"),
1524
- comment: may("comment"),
1525
- write: may("write"),
1526
- organise: may("organise"),
1527
- remove: may("remove"),
1528
- share: may("share"),
1529
- structure: may("structure"),
1530
- why: (what) => known ? sentenceFor(what, level) : NOT_YET
1531
- };
1532
- }
1533
- var NOT_ANSWERED_YET = whatYouMayDo(null, false);
1534
- var KERNEL_REASON = "This is one of the tables the platform ships, so its columns are not changed from a screen. Make your own table to change columns.";
1535
- function whatYouMayDoWithTable(table, level, known) {
1536
- const base = whatYouMayDo(level, known);
1537
- if (!table?.is_kernel) return table && tableIsLocked(table) ? lockedStructure(base) : base;
1538
- return {
1539
- ...base,
1540
- structure: false,
1541
- why: (what) => what === "structure" ? KERNEL_REASON : base.why(what)
1542
- };
1543
- }
1544
- function tableIsLocked(table) {
1545
- return table?.metadata?.["locked"] === true;
1546
- }
1547
- var DATABASE_LOCKED_REASON = "This database is locked, so its columns and settings are read-only. Unlock it to change them.";
1548
- function lockedStructure(base) {
1549
- return { ...base, structure: false, why: (what) => what === "structure" ? DATABASE_LOCKED_REASON : base.why(what) };
1550
- }
1551
-
1552
- // src/host.tsx
1553
- import { jsx as jsx6 } from "react/jsx-runtime";
1554
- function tableRights(may, overallReason) {
1555
- return {
1556
- ...may,
1557
- admin: may.structure,
1558
- reason: overallReason ?? (may.structure ? "" : may.why("structure"))
1559
- };
1560
- }
1561
- var NO_RIGHTS = tableRights(NOT_ANSWERED_YET);
1562
- 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.";
1563
- 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.";
1564
- var HostContext = createContext(null);
1565
- function useRecordsUi() {
1566
- return useContext(HostContext) ?? {};
1567
- }
1568
- function quiet(may, say) {
1569
- if (say !== false) return may;
1570
- return { ...may, why: () => "", ..."reason" in may ? { reason: "" } : {} };
1571
- }
1572
- function useTableRights(table) {
1573
- const host = useRecordsUi();
1574
- const asked2 = useTableRightsAsked(table, host);
1575
- return useMemo(() => quiet(asked2, host.sayLevelNeeded), [asked2, host.sayLevelNeeded]);
1576
- }
1577
- function useTableRightsAsked(table, host) {
1578
- const bound = Boolean(host.rights);
1579
- const asked2 = useMyLevel(bound || !table ? null : table.id);
1580
- return useMemo(() => {
1581
- if (!table) return NO_RIGHTS;
1582
- if (host.rights) return host.rights(table);
1583
- if (asked2.loading) return tableRights(NOT_ANSWERED_YET);
1584
- const level = asked2.error ? null : asked2.data;
1585
- return tableRights(whatYouMayDoWithTable(table, level, true));
1586
- }, [host, table, bound, asked2.loading, asked2.error, asked2.data]);
1587
- }
1588
-
1589
- // src/ArchivedOrganizationNotice.tsx
1590
- import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
1591
- function ArchivedOrganizationNotice({
1592
- organizationId,
1593
- error,
1594
- className
1595
- }) {
1596
- const port = useRecordsUi().archivedOrganization;
1597
- const [mayRestore, setMayRestore] = useState5(null);
1598
- const [busy, setBusy] = useState5(false);
1599
- const [failed, setFailed] = useState5(null);
1600
- useEffect4(() => {
1601
- let live = true;
1602
- if (!port) {
1603
- setMayRestore(false);
1604
- return;
1605
- }
1606
- setMayRestore(null);
1607
- port.state(organizationId).then((answer) => {
1608
- if (live) setMayRestore(answer?.mayRestore === true);
1609
- }).catch(() => {
1610
- if (live) setMayRestore(false);
1611
- });
1612
- return () => {
1613
- live = false;
1614
- };
1615
- }, [organizationId, port?.state]);
1616
- const restore = async () => {
1617
- if (!port || busy) return;
1618
- setBusy(true);
1619
- setFailed(null);
1620
- try {
1621
- await port.restore(organizationId);
1622
- if (port.afterRestore) port.afterRestore();
1623
- else if (typeof window !== "undefined") window.location.reload();
1624
- } catch (thrown) {
1625
- setFailed(thrown instanceof Error && thrown.message ? thrown.message : "The organization could not be restored.");
1626
- setBusy(false);
1627
- }
1628
- };
1629
- return /* @__PURE__ */ jsxs6(
1630
- Alert,
1631
- {
1632
- variant: "destructive",
1633
- role: "alert",
1634
- "data-refusal-notice": "",
1635
- "data-archived-organization": organizationId,
1636
- className: cn5("text-xs", className),
1637
- errorFacts: { message: "This organization is archived", title: "This organization is archived", error, origin: "records-ui/ArchivedOrganizationNotice" },
1638
- children: [
1639
- /* @__PURE__ */ jsx7(AlertTitle, { className: "text-xs font-medium", children: "This organization is archived" }),
1640
- /* @__PURE__ */ jsxs6(AlertDescription, { className: "space-y-1 text-xs", children: [
1641
- /* @__PURE__ */ jsx7("p", { className: "opacity-80", children: "Nothing was deleted. Everything here comes back the moment an owner of the organization, or a super admin, restores it." }),
1642
- mayRestore === true ? /* @__PURE__ */ jsx7(
1643
- "button",
1644
- {
1645
- type: "button",
1646
- "data-restore-organization": "",
1647
- disabled: busy,
1648
- className: "rounded border px-2 py-0.5 text-xs hover:bg-muted disabled:opacity-60",
1649
- onClick: () => void restore(),
1650
- children: busy ? "Restoring..." : "Restore organization"
1651
- }
1652
- ) : null,
1653
- mayRestore === false ? /* @__PURE__ */ jsx7("p", { "data-restore-who": "", className: "opacity-80", children: "Ask an owner of this organization to restore it." }) : null,
1654
- failed ? /* @__PURE__ */ jsx7("p", { "data-restore-refused": "", children: failed }) : null
1655
- ] })
1656
- ]
1657
- }
1658
- );
1659
- }
1660
-
1661
- // src/Refusal.tsx
1662
- import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
1663
- function RefusalNotice({
1664
- error,
1665
- className,
1666
- actions,
1667
- onKeepEditing,
1668
- onDiscard
1669
- }) {
1670
- const archivedOrg = archivedOrganizationId(error);
1671
- if (archivedOrg) {
1672
- return /* @__PURE__ */ jsx8(ArchivedOrganizationNotice, { organizationId: archivedOrg, error, className });
1673
- }
1674
- const plain = refusalForAPerson(error);
1675
- const doors = onKeepEditing || onDiscard ? /* @__PURE__ */ jsxs7("div", { className: "flex flex-wrap items-center gap-1 pt-0.5", "data-refusal-doors": "", children: [
1676
- onKeepEditing ? /* @__PURE__ */ jsx8(
1677
- "button",
1678
- {
1679
- type: "button",
1680
- "data-refusal-keep-editing": "",
1681
- className: "rounded border px-2 py-0.5 text-xs hover:bg-muted",
1682
- onClick: onKeepEditing,
1683
- children: "Keep editing"
1684
- }
1685
- ) : null,
1686
- onDiscard ? /* @__PURE__ */ jsx8(
1687
- "button",
1688
- {
1689
- type: "button",
1690
- "data-refusal-discard": "",
1691
- className: "rounded border px-2 py-0.5 text-xs hover:bg-muted",
1692
- onClick: onDiscard,
1693
- children: "Discard"
1694
- }
1695
- ) : null
1696
- ] }) : null;
1697
- return /* @__PURE__ */ jsxs7(
1698
- Alert2,
1699
- {
1700
- variant: "destructive",
1701
- role: "alert",
1702
- "data-refusal-notice": "",
1703
- className: cn6("text-xs", className),
1704
- errorFacts: { message: plain.sentence, title: plain.title, error, origin: "records-ui/RefusalNotice" },
1705
- ...plain.forEngineers ? { "data-for-engineers": plain.forEngineers } : {},
1706
- ...error.sqlstate ? { "data-sqlstate": error.sqlstate } : {},
1707
- children: [
1708
- /* @__PURE__ */ jsx8(AlertTitle2, { className: "text-xs font-medium", children: plain.storeSaid ? plain.sentence : plain.title }),
1709
- /* @__PURE__ */ jsxs7(AlertDescription2, { className: "space-y-1 text-xs", children: [
1710
- plain.storeSaid || plain.sentence.replace(/\.$/, "") === plain.title ? null : /* @__PURE__ */ jsx8("p", { children: plain.sentence }),
1711
- /* @__PURE__ */ jsx8("p", { className: "opacity-80", children: plain.remedy }),
1712
- actions,
1713
- doors
1714
- ] })
1715
- ]
1716
- }
1717
- );
1718
- }
1719
- function RefusalLine({ error, className }) {
1720
- const plain = refusalForAPerson(error);
1721
- return /* @__PURE__ */ jsx8(
1722
- ErrorBox,
1723
- {
1724
- "data-refusal-line": "",
1725
- className: cn6("text-xs text-destructive", className),
1726
- message: archivedOrganizationId(error) ? "This organization is archived. An owner can restore it." : refusalLineForAPerson(error),
1727
- error,
1728
- origin: "records-ui/RefusalLine",
1729
- ...plain.forEngineers ? { "data-for-engineers": plain.forEngineers } : {}
1730
- }
1731
- );
1732
- }
1733
-
1734
1735
  // src/refusals.ts
1735
1736
  var refusals_exports = {};
1736
1737
  __reExport(refusals_exports, versions_star2);