@nivaro/react 0.3.33 → 0.3.34

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.
Files changed (29) hide show
  1. package/dist/full.css +1 -1
  2. package/dist/hooks/useSessionRecorder.js +1 -1
  3. package/dist/index.d.ts +79 -5
  4. package/dist/index.js +338 -329
  5. package/dist/shared/components/ItemEditForm.js +5494 -5302
  6. package/dist/shared/components/ProfileView.js +46 -44
  7. package/dist/shared/components/ReportView.js +208 -205
  8. package/dist/shared/components/SearchHighlight.js +30 -0
  9. package/dist/shared/components/TipLayer.js +39 -37
  10. package/dist/shared/components/item-edit/CatalogPickerField.js +1484 -1232
  11. package/dist/shared/components/item-edit/FieldAffordances.js +370 -203
  12. package/dist/shared/components/item-edit/FieldRow.js +396 -354
  13. package/dist/shared/components/item-edit/PersonalDefaultPill.js +50 -0
  14. package/dist/shared/components/item-edit/RelationCombobox.js +42 -41
  15. package/dist/shared/components/item-edit/catalog-search.js +34 -0
  16. package/dist/shared/components/item-edit/entry/useEntryKeyboard.js +34 -34
  17. package/dist/shared/components/item-edit/personal-default-checks.js +134 -0
  18. package/dist/shared/components/item-edit/usePersonalDefaults.js +358 -0
  19. package/dist/shared/components/layout-editor/inspector/BehaviourSettings.js +130 -111
  20. package/dist/shared/components/layout-editor/inspector/RulesTab.js +76 -75
  21. package/dist/shared/components/layout-editor/parity-keys.json.js +1 -1
  22. package/dist/shared/components/profile/MyDefaultsCard.js +667 -0
  23. package/dist/shared/components/profile/PersonProfile.js +42 -40
  24. package/dist/shared/components/profile/my-defaults-labels.js +76 -0
  25. package/dist/shared/components/profile/primitives.js +72 -67
  26. package/dist/shared/lib/personal-defaults.js +76 -0
  27. package/dist/shared/lib/request-gate.js +78 -76
  28. package/dist/shared/lib/search-text.js +111 -0
  29. package/package.json +1 -1
@@ -0,0 +1,667 @@
1
+ import { jsxs as p, jsx as n, Fragment as ge } from "react/jsx-runtime";
2
+ import { useQueryClient as xe, useQuery as U, useMutation as ae, useQueries as Q } from "@tanstack/react-query";
3
+ import { Plus as be, BookmarkCheck as ve, Pencil as ye, UserRoundX as ke, ChevronsUpDown as Ne, Check as ne, X as Ce } from "lucide-react";
4
+ import { useState as w, useMemo as S, useRef as V, useEffect as le } from "react";
5
+ import { toast as B } from "sonner";
6
+ import { useNivaroClient as X, useItemEditAuth as Se, ParentDraftContext as we } from "../../context.js";
7
+ import { get as T, del as qe, put as Pe } from "../../lib/commands.js";
8
+ import { isEmptyValue as M, cascadeParents as Te } from "../../lib/personal-defaults.js";
9
+ import { userErrorMessage as Ee } from "../../lib/safe-error.js";
10
+ import { titleCase as _, cn as R, formatDate as Fe } from "../../lib/utils.js";
11
+ import { FieldRenderer as $e } from "../item-edit/FieldRenderer.js";
12
+ import { getCascadeFilters as re, buildCascadeFilter as Me } from "../item-edit/helpers.js";
13
+ import { M2MStagingContext as _e } from "../item-edit/M2MStagingContext.js";
14
+ import { PERSONAL_DEFAULT_GHOST_BUTTON as De } from "../item-edit/PersonalDefaultPill.js";
15
+ import { pickedCollection as Ae } from "../item-edit/personal-default-checks.js";
16
+ import { personalDefaultsKey as Ke } from "../item-edit/usePersonalDefaults.js";
17
+ import { Command as Le, CommandInput as Ue, CommandList as Re, CommandEmpty as je, CommandGroup as Ie, CommandItem as Oe } from "../ui/command.js";
18
+ import { Popover as Qe, PopoverTrigger as Ve, PopoverContent as Be } from "../ui/popover.js";
19
+ import { Skeleton as D } from "../ui/skeleton.js";
20
+ import { describeValue as J, loadDefaultLabels as Xe, labelKey as ze } from "./my-defaults-labels.js";
21
+ import { SectionCard as Ge, EmptyLine as He, Pill as Ye, ConfirmButton as Je } from "./primitives.js";
22
+ const W = { fields: [], relations: [], label: "", ready: !1 };
23
+ function We(a) {
24
+ const e = X(), t = Q({
25
+ queries: a.map((s) => ({
26
+ queryKey: ["field-config", s, null],
27
+ queryFn: () => e.request(T(`/field-config/${s}`)).then((d) => d.data ?? []),
28
+ staleTime: 6e4
29
+ }))
30
+ }), o = Q({
31
+ queries: a.map((s) => ({
32
+ queryKey: ["relations", s],
33
+ queryFn: () => e.request(T(`/data-model/relations/for/${s}`)).then((d) => d.data ?? []),
34
+ staleTime: 6e4
35
+ }))
36
+ }), u = Q({
37
+ queries: a.map((s) => ({
38
+ queryKey: ["col-meta", s],
39
+ queryFn: () => e.request(T(`/collections/${s}`)).then((d) => d.data ?? null),
40
+ staleTime: 6e4
41
+ }))
42
+ }), i = /* @__PURE__ */ new Map();
43
+ return a.forEach((s, d) => {
44
+ var x, c, b, y, f, v;
45
+ const m = (c = (x = u[d]) == null ? void 0 : x.data) == null ? void 0 : c.display_name;
46
+ i.set(s, {
47
+ fields: ((b = t[d]) == null ? void 0 : b.data) ?? [],
48
+ relations: ((y = o[d]) == null ? void 0 : y.data) ?? [],
49
+ label: m != null && m.trim() ? m : _(s),
50
+ ready: !((f = t[d]) != null && f.isPending) && !((v = o[d]) != null && v.isPending)
51
+ });
52
+ }), i;
53
+ }
54
+ function P(a, e) {
55
+ var o;
56
+ const t = a.fields.find((u) => u.field === e);
57
+ return (o = t == null ? void 0 : t.label) != null && o.trim() ? t.label : _(e);
58
+ }
59
+ function Ze(a, e) {
60
+ const t = Object.keys(e.context ?? {}).filter((s) => !M(e.context[s])), o = new Map(a.fields.map((s) => [s.field, s])), i = Te(
61
+ e.field,
62
+ (s) => {
63
+ var d;
64
+ return re(((d = o.get(s)) == null ? void 0 : d.dependency_config) ?? null);
65
+ }
66
+ ).reverse().filter((s) => t.includes(s));
67
+ return [...i, ...t.filter((s) => !i.includes(s))];
68
+ }
69
+ function Z(a, e) {
70
+ if (a.kind === "text") return { text: a.text, state: "ok" };
71
+ if (a.kind === "unknown") return { text: "Saved value", state: "ok" };
72
+ if (e.loading) return { text: "", state: "loading" };
73
+ if (e.failed) return { text: "Could not load this value", state: "failed" };
74
+ const t = [];
75
+ let o = 0;
76
+ for (const u of a.ids) {
77
+ const i = ze(a.target, u);
78
+ e.map.has(i) ? t.push(e.map.get(i) ?? "Untitled record") : o++;
79
+ }
80
+ return t.length === 0 ? { text: "No longer available", state: "gone" } : (o && t.push(`${o} no longer available`), { text: t.join(", "), state: "ok" });
81
+ }
82
+ function se(a) {
83
+ var o, u;
84
+ const e = a, t = ((u = (o = e == null ? void 0 : e.response) == null ? void 0 : o.data) == null ? void 0 : u.error) ?? (e == null ? void 0 : e.error);
85
+ return typeof t == "string" && t.trim() ? t : Ee(a, "Could not save");
86
+ }
87
+ function wt({ userId: a, name: e }) {
88
+ const t = X(), o = xe(), u = Se(), i = !!a && String(a).toUpperCase() !== String(u.userId).toUpperCase(), s = !i || u.isAdmin, d = i ? `/field-defaults/users/${encodeURIComponent(String(a))}` : "/field-defaults/mine", m = i ? String(a) : "me", x = ["field-defaults-card", m], {
89
+ data: c,
90
+ isPending: b,
91
+ isError: y,
92
+ refetch: f,
93
+ isRefetching: v
94
+ } = U({
95
+ queryKey: x,
96
+ queryFn: () => t.request(T(d, { on_layout: 1 })).then((l) => l.data ?? []),
97
+ enabled: s,
98
+ staleTime: 3e4
99
+ }), { data: h } = U({
100
+ queryKey: ["field-defaults-allowed", m],
101
+ queryFn: () => t.request(T(`${d}/allowed`)).then((l) => l.data ?? []),
102
+ enabled: s && i,
103
+ staleTime: 6e4
104
+ }), { data: g, isPending: q } = U({
105
+ queryKey: ["field-defaults-allowed-any", m],
106
+ queryFn: () => t.request(T(`${d}/allowed`, { any: 1 })).then((l) => {
107
+ var r;
108
+ return ((r = l.data) == null ? void 0 : r.any) === !0;
109
+ }),
110
+ enabled: s && !i,
111
+ staleTime: 6e4
112
+ }), [k, F] = w(!1), [C, z] = w(""), G = S(() => {
113
+ const l = new Set((c ?? []).map((r) => r.collection));
114
+ return C && l.add(C), [...l];
115
+ }, [c, C]), E = We(G), A = G.every((l) => {
116
+ var r;
117
+ return (r = E.get(l)) == null ? void 0 : r.ready;
118
+ }), j = S(() => {
119
+ const l = /* @__PURE__ */ new Map();
120
+ if (!A) return l;
121
+ for (const r of c ?? []) {
122
+ const N = E.get(r.collection) ?? W, L = ($) => N.fields.find((he) => he.field === $);
123
+ l.set(String(r.id), {
124
+ value: J(L(r.field), N.relations, r.collection, r.value),
125
+ context: Ze(N, r).map(($) => [
126
+ $,
127
+ J(L($), N.relations, r.collection, r.context[$])
128
+ ])
129
+ });
130
+ }
131
+ return l;
132
+ }, [c, E, A]), K = S(() => {
133
+ const l = /* @__PURE__ */ new Map();
134
+ for (const r of j.values())
135
+ for (const N of [r.value, ...r.context.map(([, L]) => L)])
136
+ N.kind === "records" && l.set(N.target, [.../* @__PURE__ */ new Set([...l.get(N.target) ?? [], ...N.ids])].sort());
137
+ return l;
138
+ }, [j]), ce = [...K].map(([l, r]) => `${l}:${r.join(",")}`).sort().join("|"), {
139
+ data: ue,
140
+ isPending: fe,
141
+ isError: H
142
+ } = U({
143
+ queryKey: ["field-defaults-card-labels", ce],
144
+ queryFn: () => Xe(
145
+ t,
146
+ K,
147
+ (l) => o.fetchQuery({
148
+ queryKey: ["col-meta", l],
149
+ queryFn: () => t.request(
150
+ T(`/collections/${l}`)
151
+ ).then((r) => r.data ?? null),
152
+ staleTime: 6e4
153
+ }).then((r) => (r == null ? void 0 : r.display_template) ?? null)
154
+ ),
155
+ enabled: A && K.size > 0,
156
+ staleTime: 6e4
157
+ }), me = {
158
+ map: ue ?? /* @__PURE__ */ new Map(),
159
+ loading: K.size > 0 && !H && (!A || fe),
160
+ failed: H
161
+ }, I = (l) => {
162
+ o.invalidateQueries({ queryKey: x }), !i && l && o.invalidateQueries({ queryKey: Ke(l) });
163
+ }, O = ae({
164
+ mutationFn: (l) => t.request(qe(`${d}/${l.id}`)),
165
+ onSuccess: (l, r) => {
166
+ I(r.collection), B.success("Default cleared");
167
+ },
168
+ onError: (l) => B.error(se(l))
169
+ });
170
+ if (!s || !i && (b || q && !y || !y && (c ?? []).length === 0 && g !== !0))
171
+ return null;
172
+ const pe = [...new Set((c ?? []).map((l) => l.collection))].map((l) => {
173
+ var r;
174
+ return { collection: l, label: ((r = E.get(l)) == null ? void 0 : r.label) || _(l) };
175
+ }).sort((l, r) => l.label.localeCompare(r.label)), Y = (e == null ? void 0 : e.trim()) || "This person";
176
+ return /* @__PURE__ */ p(
177
+ Ge,
178
+ {
179
+ icon: /* @__PURE__ */ n(ve, { className: "h-4 w-4" }),
180
+ title: i ? "Personal defaults" : "My defaults",
181
+ hint: i ? "Starting values their new records are filled in with" : "Starting values your new records are filled in with",
182
+ testId: "my-defaults",
183
+ actions: i && !k && ((h == null ? void 0 : h.length) ?? 0) > 0 ? /* @__PURE__ */ p(
184
+ "button",
185
+ {
186
+ type: "button",
187
+ "data-default-add": !0,
188
+ onClick: () => F(!0),
189
+ className: "inline-flex h-7 items-center gap-1 rounded-md px-2 text-[11.5px] font-medium text-slate-600 transition-colors hover:bg-muted hover:text-slate-900 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-nvr-cyan/40 dark:text-slate-300 dark:hover:text-white",
190
+ children: [
191
+ /* @__PURE__ */ n(be, { className: "h-3.5 w-3.5" }),
192
+ " Add default"
193
+ ]
194
+ }
195
+ ) : null,
196
+ children: [
197
+ b ? /* @__PURE__ */ n("div", { className: "space-y-3", "aria-busy": "true", children: [0, 1, 2].map((l) => /* @__PURE__ */ p("div", { className: "flex items-center gap-3", children: [
198
+ /* @__PURE__ */ n(D, { className: "h-3.5 w-24" }),
199
+ /* @__PURE__ */ n(D, { className: "h-3.5 w-40" })
200
+ ] }, l)) }) : y ? /* @__PURE__ */ p("div", { className: "flex flex-wrap items-center gap-2", children: [
201
+ /* @__PURE__ */ n(He, { children: "Could not load the saved defaults." }),
202
+ /* @__PURE__ */ n(
203
+ "button",
204
+ {
205
+ type: "button",
206
+ "data-default-retry": !0,
207
+ disabled: v,
208
+ onClick: () => void f(),
209
+ className: "inline-flex h-7 items-center rounded-md border border-slate-200 px-2.5 text-[11.5px] font-medium text-slate-700 transition-colors hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-nvr-cyan/40 disabled:opacity-50 dark:border-border dark:text-slate-200",
210
+ children: v ? "Trying…" : "Retry"
211
+ }
212
+ )
213
+ ] }) : (c ?? []).length === 0 ? /* @__PURE__ */ p("p", { "data-default-empty": !0, className: "text-[12px] text-slate-500 dark:text-slate-400", children: [
214
+ i ? `${Y} hasn’t saved any defaults yet.` : "No defaults yet.",
215
+ " On a record form, open a field’s ⋯ menu and choose",
216
+ " ",
217
+ /* @__PURE__ */ n("span", { className: "font-medium text-slate-700 dark:text-slate-200", children: "Save as my default" }),
218
+ i ? ((h == null ? void 0 : h.length) ?? 0) > 0 ? " — or add one here." : "." : " — new records then start with that value."
219
+ ] }) : /* @__PURE__ */ n("div", { className: "space-y-4", children: pe.map((l) => /* @__PURE__ */ p("section", { "data-default-group": l.collection, children: [
220
+ /* @__PURE__ */ n("h4", { className: "mb-1 text-[12px] font-semibold text-slate-700 dark:text-slate-200", children: l.label }),
221
+ /* @__PURE__ */ n("ul", { className: "divide-y divide-slate-100 dark:divide-border/60", children: (c ?? []).filter((r) => r.collection === l.collection).map((r) => {
222
+ var N;
223
+ return /* @__PURE__ */ n(
224
+ tt,
225
+ {
226
+ row: r,
227
+ meta: E.get(r.collection) ?? W,
228
+ parts: j.get(String(r.id)),
229
+ labels: me,
230
+ base: d,
231
+ onSaved: () => I(r.collection),
232
+ onClear: () => O.mutate(r),
233
+ clearing: O.isPending && ((N = O.variables) == null ? void 0 : N.id) === r.id
234
+ },
235
+ r.id
236
+ );
237
+ }) })
238
+ ] }, l.collection)) }),
239
+ i && (h == null ? void 0 : h.length) === 0 && /* @__PURE__ */ p("p", { className: "mt-3 text-[11.5px] text-slate-500 dark:text-slate-400", children: [
240
+ "No form gives ",
241
+ e != null && e.trim() ? Y : "this person",
242
+ " a personal default yet. Turn on Personal default for a field in the layout editor."
243
+ ] }),
244
+ i && k && /* @__PURE__ */ n(
245
+ nt,
246
+ {
247
+ allowed: h ?? [],
248
+ metas: E,
249
+ collection: C,
250
+ onCollection: z,
251
+ base: d,
252
+ onDone: () => {
253
+ F(!1), z("");
254
+ },
255
+ onSaved: (l) => I(l)
256
+ }
257
+ )
258
+ ]
259
+ }
260
+ );
261
+ }
262
+ const et = 'input:not([type=hidden]), textarea, [role=combobox], button, [tabindex]:not([tabindex="-1"])', ee = "No form you can be given offers a personal default for this field now, so it is not used. Clear it, or ask an admin to turn it back on.";
263
+ function tt({
264
+ row: a,
265
+ meta: e,
266
+ parts: t,
267
+ labels: o,
268
+ base: u,
269
+ onSaved: i,
270
+ onClear: s,
271
+ clearing: d
272
+ }) {
273
+ const [m, x] = w(!1), c = V(null), b = V(!1);
274
+ le(() => {
275
+ var k;
276
+ m || !b.current || (b.current = !1, (k = c.current) == null || k.focus());
277
+ }, [m]);
278
+ const y = () => {
279
+ b.current = !0, x(!1);
280
+ }, f = a.on_layout === !1, v = e.fields.find((k) => k.field === a.field), h = t ? Z(t.value, o) : { text: "", state: "loading" }, g = ((t == null ? void 0 : t.context) ?? []).map(([k, F]) => {
281
+ if (F.kind === "unknown") return P(e, k);
282
+ const C = Z(F, o);
283
+ return C.state === "loading" ? null : C.state === "gone" || C.state === "failed" ? `${P(e, k)} (unavailable)` : C.text;
284
+ }), q = ((t == null ? void 0 : t.context) ?? []).length > 0 && g.some((k) => k === null);
285
+ return /* @__PURE__ */ p("li", { "data-default-row": a.id, className: "group flex items-start gap-3 py-2", children: [
286
+ /* @__PURE__ */ p("div", { className: "min-w-0 flex-1 gap-3 sm:grid sm:grid-cols-[minmax(0,9rem)_minmax(0,1fr)]", children: [
287
+ /* @__PURE__ */ n(
288
+ "p",
289
+ {
290
+ "data-default-field": !0,
291
+ className: "truncate pt-px text-[12px] text-slate-500 dark:text-slate-400",
292
+ children: P(e, a.field)
293
+ }
294
+ ),
295
+ /* @__PURE__ */ p("div", { className: "min-w-0", children: [
296
+ m && v ? /* @__PURE__ */ n(
297
+ at,
298
+ {
299
+ row: a,
300
+ field: v,
301
+ relations: e.relations,
302
+ base: u,
303
+ onCancel: y,
304
+ onSaved: () => {
305
+ y(), i();
306
+ }
307
+ }
308
+ ) : h.state === "loading" ? /* @__PURE__ */ n(D, { className: "mt-0.5 h-3.5 w-32" }) : /* @__PURE__ */ n(
309
+ "p",
310
+ {
311
+ "data-default-value": !0,
312
+ "data-tip": h.state === "gone" ? "The saved record was removed, or is no longer visible to you" : void 0,
313
+ className: R(
314
+ "truncate text-[12.5px]",
315
+ h.state === "gone" || h.state === "failed" ? "italic text-slate-500 dark:text-slate-400" : f ? "text-slate-500 dark:text-slate-400" : "font-medium text-slate-800 dark:text-slate-100"
316
+ ),
317
+ children: h.text
318
+ }
319
+ ),
320
+ /* @__PURE__ */ p("p", { className: "mt-0.5 flex flex-wrap items-center gap-x-1.5 gap-y-1 text-[11.5px] text-slate-500 dark:text-slate-400", children: [
321
+ q ? /* @__PURE__ */ n(D, { className: "h-3 w-28" }) : g.length > 0 ? /* @__PURE__ */ p("span", { "data-default-context": !0, children: [
322
+ "for ",
323
+ g.join(" · ")
324
+ ] }) : null,
325
+ (q || g.length > 0) && /* @__PURE__ */ n("span", { "aria-hidden": !0, children: "·" }),
326
+ /* @__PURE__ */ p("span", { children: [
327
+ "Saved ",
328
+ Fe(a.updated_at),
329
+ a.updated_by ? " by an admin" : ""
330
+ ] }),
331
+ f && /* @__PURE__ */ p("span", { "data-tip": ee, children: [
332
+ /* @__PURE__ */ n(Ye, { tone: "amber", testId: "stale", children: /* @__PURE__ */ n("span", { "data-default-stale": !0, children: "No longer on any form" }) }),
333
+ /* @__PURE__ */ p("span", { className: "sr-only", children: [
334
+ ". ",
335
+ ee
336
+ ] })
337
+ ] })
338
+ ] })
339
+ ] })
340
+ ] }),
341
+ !m && /* @__PURE__ */ p(
342
+ "div",
343
+ {
344
+ className: R(
345
+ "flex shrink-0 items-center gap-0.5 transition-opacity duration-150",
346
+ // Reserve the slot; show on hover / keyboard focus, always on touch and when stale.
347
+ // …and while Clear is armed (the pointer may have left before the second press).
348
+ !f && "opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [&:has([data-armed])]:opacity-100"
349
+ ),
350
+ children: [
351
+ !f && v && /* @__PURE__ */ n(
352
+ "button",
353
+ {
354
+ ref: c,
355
+ type: "button",
356
+ "data-default-change": !0,
357
+ "aria-label": `Change the default for ${P(e, a.field)}`,
358
+ "data-tip": "Change",
359
+ onClick: () => x(!0),
360
+ className: "rounded p-1.5 text-slate-500 transition-colors hover:bg-muted hover:text-slate-800 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-nvr-cyan/40 dark:text-slate-400 dark:hover:text-slate-100",
361
+ children: /* @__PURE__ */ n(ye, { className: "h-3.5 w-3.5" })
362
+ }
363
+ ),
364
+ /* @__PURE__ */ n(
365
+ Je,
366
+ {
367
+ onConfirm: s,
368
+ disabled: d,
369
+ title: `Clear the default for ${P(e, a.field)}`,
370
+ confirmTitle: `Clear the default for ${P(e, a.field)}?`,
371
+ confirmLabel: /* @__PURE__ */ n("span", { "data-default-clear": !0, className: "px-1 text-[11.5px] font-semibold", children: "Clear?" }),
372
+ className: "inline-flex h-7 items-center rounded px-1.5 text-slate-500 transition-colors hover:bg-muted hover:text-red-700 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-nvr-cyan/40 disabled:opacity-50 dark:text-slate-400 dark:hover:text-red-400",
373
+ armedClassName: "bg-red-50 text-red-700 hover:bg-red-100 dark:bg-red-500/10 dark:text-red-400 dark:hover:bg-red-500/15",
374
+ children: /* @__PURE__ */ n("span", { "data-default-clear": !0, className: "inline-flex items-center", children: /* @__PURE__ */ n(ke, { className: "h-3.5 w-3.5" }) })
375
+ }
376
+ )
377
+ ]
378
+ }
379
+ )
380
+ ] });
381
+ }
382
+ function ie({
383
+ collection: a,
384
+ field: e,
385
+ relations: t,
386
+ context: o,
387
+ value: u,
388
+ onChange: i
389
+ }) {
390
+ var f;
391
+ const s = S(() => ({ ...e, readonly: !1, hidden: !1 }), [e]), d = ((f = Ae(t, a, e.field)) == null ? void 0 : f.kind) === "m2m", m = S(
392
+ () => Array.isArray(u) ? u : M(u) ? [] : [u],
393
+ [u]
394
+ ), x = S(
395
+ () => d ? {
396
+ getStagedLinks: () => m,
397
+ getStagedUnlinks: () => /* @__PURE__ */ new Set(),
398
+ stageLink: (v, h) => i(m.some((g) => String(g) === String(h)) ? m : [...m, h]),
399
+ unstageLink: (v, h) => i(m.filter((g) => String(g) !== String(h))),
400
+ stageUnlink: () => {
401
+ },
402
+ unstageUnlink: () => {
403
+ }
404
+ } : null,
405
+ [d, m, i]
406
+ ), c = S(
407
+ () => Me({
408
+ rules: re(e.dependency_config),
409
+ parentValue: (v) => M(o[v]) ? null : o[v]
410
+ }).filter,
411
+ [e.dependency_config, o]
412
+ ), b = S(() => ({ collection: a, draft: { ...o } }), [a, o]), y = /* @__PURE__ */ n(
413
+ $e,
414
+ {
415
+ field: s,
416
+ value: d ? void 0 : u,
417
+ onChange: i,
418
+ relations: t,
419
+ collection: a,
420
+ itemId: "new",
421
+ cascadeFilter: c
422
+ }
423
+ );
424
+ return /* @__PURE__ */ n(we.Provider, { value: b, children: x ? /* @__PURE__ */ n(_e.Provider, { value: x, children: y }) : y });
425
+ }
426
+ function oe({
427
+ canSave: a,
428
+ pending: e,
429
+ onSave: t,
430
+ onCancel: o
431
+ }) {
432
+ return /* @__PURE__ */ p("span", { className: "flex items-center gap-1.5", children: [
433
+ /* @__PURE__ */ p("button", { type: "button", onClick: o, className: De, children: [
434
+ /* @__PURE__ */ n(Ce, { className: "h-3 w-3" }),
435
+ " Cancel"
436
+ ] }),
437
+ /* @__PURE__ */ n(
438
+ "button",
439
+ {
440
+ type: "button",
441
+ "data-default-save": !0,
442
+ disabled: !a || e,
443
+ onClick: t,
444
+ className: "inline-flex h-7 items-center gap-1 rounded-md bg-nvr-cyan px-2.5 text-[11.5px] font-semibold text-white transition-opacity focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-nvr-cyan/40 focus-visible:ring-offset-1 disabled:opacity-50",
445
+ children: e ? "Saving…" : /* @__PURE__ */ p(ge, { children: [
446
+ /* @__PURE__ */ n(ne, { className: "h-3 w-3" }),
447
+ " Save"
448
+ ] })
449
+ }
450
+ )
451
+ ] });
452
+ }
453
+ function de(a, e) {
454
+ const t = X(), [o, u] = w(null);
455
+ return { save: ae({
456
+ mutationFn: (s) => t.request(Pe(a, s)),
457
+ onSuccess: () => {
458
+ u(null), B.success("Default saved"), e();
459
+ },
460
+ onError: (s) => u(se(s))
461
+ }), error: o };
462
+ }
463
+ function at({
464
+ row: a,
465
+ field: e,
466
+ relations: t,
467
+ base: o,
468
+ onCancel: u,
469
+ onSaved: i
470
+ }) {
471
+ const [s, d] = w(a.value), { save: m, error: x } = de(o, i), c = V(null);
472
+ return le(() => {
473
+ const b = () => {
474
+ var v, h;
475
+ const f = (h = (v = c.current) == null ? void 0 : v.querySelector("[data-default-control]")) == null ? void 0 : h.querySelector(et);
476
+ return f == null || f.focus(), !!f;
477
+ };
478
+ if (b()) return;
479
+ const y = window.setTimeout(b, 50);
480
+ return () => window.clearTimeout(y);
481
+ }, []), /* @__PURE__ */ p(
482
+ "fieldset",
483
+ {
484
+ ref: c,
485
+ className: "m-0 min-w-0 space-y-1.5 border-0 p-0",
486
+ "data-default-editor": !0,
487
+ onKeyDown: (b) => {
488
+ var y;
489
+ b.key !== "Escape" || b.defaultPrevented || (y = c.current) != null && y.contains(b.target) && (b.stopPropagation(), u());
490
+ },
491
+ children: [
492
+ /* @__PURE__ */ p("legend", { className: "sr-only", children: [
493
+ "Change the default for ",
494
+ e.label || e.field
495
+ ] }),
496
+ /* @__PURE__ */ n("div", { "data-default-control": !0, children: /* @__PURE__ */ n(
497
+ ie,
498
+ {
499
+ collection: a.collection,
500
+ field: e,
501
+ relations: t,
502
+ context: a.context ?? {},
503
+ value: s,
504
+ onChange: d
505
+ }
506
+ ) }),
507
+ x && /* @__PURE__ */ n("p", { role: "alert", className: "text-[11.5px] text-red-600 dark:text-red-400", children: x }),
508
+ /* @__PURE__ */ n(
509
+ oe,
510
+ {
511
+ canSave: !M(s),
512
+ pending: m.isPending,
513
+ onCancel: u,
514
+ onSave: () => m.mutate({
515
+ collection: a.collection,
516
+ field: a.field,
517
+ value: s,
518
+ context: a.context ?? {}
519
+ })
520
+ }
521
+ )
522
+ ]
523
+ }
524
+ );
525
+ }
526
+ function te({
527
+ value: a,
528
+ options: e,
529
+ placeholder: t,
530
+ label: o,
531
+ onChange: u,
532
+ testId: i,
533
+ disabled: s
534
+ }) {
535
+ const [d, m] = w(!1), x = e.find((c) => c.value === a);
536
+ return /* @__PURE__ */ p(Qe, { open: d, onOpenChange: m, children: [
537
+ /* @__PURE__ */ n(Ve, { asChild: !0, children: /* @__PURE__ */ p(
538
+ "button",
539
+ {
540
+ type: "button",
541
+ role: "combobox",
542
+ "aria-expanded": d,
543
+ "aria-label": o,
544
+ "data-default-pick": i,
545
+ disabled: s,
546
+ className: "flex h-8 w-full items-center justify-between gap-2 rounded-md border border-slate-200 bg-white px-2.5 text-left text-[12.5px] text-slate-700 transition-colors hover:border-slate-300 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-nvr-cyan/40 disabled:cursor-not-allowed disabled:bg-slate-50 disabled:hover:border-slate-200 dark:border-border dark:bg-background dark:text-slate-200 dark:hover:border-slate-600 dark:disabled:bg-muted/40 dark:disabled:hover:border-border",
547
+ children: [
548
+ /* @__PURE__ */ n("span", { className: R("truncate", !x && "text-slate-500 dark:text-slate-400"), children: (x == null ? void 0 : x.label) ?? t }),
549
+ /* @__PURE__ */ n(Ne, { className: "h-3.5 w-3.5 shrink-0 text-slate-400" })
550
+ ]
551
+ }
552
+ ) }),
553
+ /* @__PURE__ */ n(Be, { className: "w-[260px] p-0", align: "start", children: /* @__PURE__ */ p(Le, { children: [
554
+ /* @__PURE__ */ n(Ue, { placeholder: "Search…", className: "h-8 text-[12px]" }),
555
+ /* @__PURE__ */ p(Re, { children: [
556
+ /* @__PURE__ */ n(je, { className: "py-3 text-center text-[12px] text-slate-500 dark:text-slate-400", children: "No matches" }),
557
+ /* @__PURE__ */ n(Ie, { children: e.map((c) => /* @__PURE__ */ p(
558
+ Oe,
559
+ {
560
+ value: `${c.label} ${c.value}`,
561
+ onSelect: () => {
562
+ u(c.value), m(!1);
563
+ },
564
+ className: "text-[12px]",
565
+ children: [
566
+ /* @__PURE__ */ n(
567
+ ne,
568
+ {
569
+ className: R("mr-2 h-3 w-3", c.value === a ? "opacity-100" : "opacity-0")
570
+ }
571
+ ),
572
+ c.label
573
+ ]
574
+ },
575
+ c.value
576
+ )) })
577
+ ] })
578
+ ] }) })
579
+ ] });
580
+ }
581
+ function nt({
582
+ allowed: a,
583
+ metas: e,
584
+ collection: t,
585
+ onCollection: o,
586
+ base: u,
587
+ onDone: i,
588
+ onSaved: s
589
+ }) {
590
+ const [d, m] = w(""), [x, c] = w(null), { save: b, error: y } = de(u, () => {
591
+ s(t), i();
592
+ }), f = t ? e.get(t) : void 0, v = a.find((g) => g.collection === t), h = f == null ? void 0 : f.fields.find((g) => g.field === d);
593
+ return /* @__PURE__ */ p(
594
+ "div",
595
+ {
596
+ "data-default-add-form": !0,
597
+ className: "mt-3 space-y-2 border-t border-slate-100 pt-3 dark:border-border/60",
598
+ children: [
599
+ /* @__PURE__ */ p("div", { className: "grid gap-2 sm:grid-cols-2", children: [
600
+ /* @__PURE__ */ n(
601
+ te,
602
+ {
603
+ testId: "collection",
604
+ label: "Collection",
605
+ placeholder: "Choose a collection",
606
+ value: t,
607
+ options: a.map((g) => {
608
+ var q;
609
+ return {
610
+ value: g.collection,
611
+ label: g.label ?? ((q = e.get(g.collection)) == null ? void 0 : q.label) ?? _(g.collection)
612
+ };
613
+ }),
614
+ onChange: (g) => {
615
+ o(g), m(""), c(null);
616
+ }
617
+ }
618
+ ),
619
+ /* @__PURE__ */ n(
620
+ te,
621
+ {
622
+ testId: "field",
623
+ label: "Field",
624
+ disabled: !t,
625
+ placeholder: t ? "Choose a field" : "Choose a collection first",
626
+ value: d,
627
+ options: ((v == null ? void 0 : v.fields) ?? []).map((g) => ({
628
+ value: g,
629
+ label: f ? P(f, g) : _(g)
630
+ })),
631
+ onChange: (g) => {
632
+ m(g), c(null);
633
+ }
634
+ }
635
+ )
636
+ ] }),
637
+ h && (f != null && f.ready) ? /* @__PURE__ */ n(
638
+ ie,
639
+ {
640
+ collection: t,
641
+ field: h,
642
+ relations: f.relations,
643
+ context: {},
644
+ value: x,
645
+ onChange: c
646
+ }
647
+ ) : d && !(f != null && f.ready) ? /* @__PURE__ */ n(D, { className: "h-8 w-full" }) : null,
648
+ y && /* @__PURE__ */ n("p", { role: "alert", className: "text-[11.5px] text-red-600 dark:text-red-400", children: y }),
649
+ /* @__PURE__ */ p("div", { className: "flex items-center justify-between gap-2", children: [
650
+ /* @__PURE__ */ n("p", { className: "text-[11px] text-slate-500 dark:text-slate-400", children: "Checked as them: they must be able to set the field and pick the value." }),
651
+ /* @__PURE__ */ n(
652
+ oe,
653
+ {
654
+ canSave: !!h && !M(x),
655
+ pending: b.isPending,
656
+ onCancel: i,
657
+ onSave: () => b.mutate({ collection: t, field: d, value: x, context: {} })
658
+ }
659
+ )
660
+ ] })
661
+ ]
662
+ }
663
+ );
664
+ }
665
+ export {
666
+ wt as MyDefaultsCard
667
+ };