@nivaro/react 0.3.33 → 0.3.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.
Files changed (32) 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 +5274 -5069
  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 +424 -213
  12. package/dist/shared/components/item-edit/FieldRow.js +475 -427
  13. package/dist/shared/components/item-edit/PersonalDefaultControl.js +211 -0
  14. package/dist/shared/components/item-edit/PersonalDefaultPill.js +20 -0
  15. package/dist/shared/components/item-edit/RecordLiveSync.js +115 -110
  16. package/dist/shared/components/item-edit/RelationCombobox.js +42 -41
  17. package/dist/shared/components/item-edit/catalog-search.js +34 -0
  18. package/dist/shared/components/item-edit/entry/useEntryKeyboard.js +43 -43
  19. package/dist/shared/components/item-edit/live-record-marks.js +13 -0
  20. package/dist/shared/components/item-edit/personal-default-checks.js +134 -0
  21. package/dist/shared/components/item-edit/usePersonalDefaults.js +442 -0
  22. package/dist/shared/components/layout-editor/inspector/BehaviourSettings.js +130 -111
  23. package/dist/shared/components/layout-editor/inspector/RulesTab.js +76 -75
  24. package/dist/shared/components/layout-editor/parity-keys.json.js +1 -1
  25. package/dist/shared/components/profile/MyDefaultsCard.js +667 -0
  26. package/dist/shared/components/profile/PersonProfile.js +42 -40
  27. package/dist/shared/components/profile/my-defaults-labels.js +76 -0
  28. package/dist/shared/components/profile/primitives.js +72 -67
  29. package/dist/shared/lib/personal-defaults.js +76 -0
  30. package/dist/shared/lib/request-gate.js +78 -76
  31. package/dist/shared/lib/search-text.js +111 -0
  32. package/package.json +1 -1
@@ -1,63 +1,67 @@
1
- import { jsx as o, jsxs as x, Fragment as $ } from "react/jsx-runtime";
2
- import { Copy as F, History as O, Eye as K, Sigma as P, ExternalLink as B, Lock as H, X as I } from "lucide-react";
3
- import { useContext as U, createContext as q, useState as C, useCallback as g, useRef as v, useEffect as E } from "react";
4
- import { createPortal as J } from "react-dom";
5
- import { toast as k } from "sonner";
6
- import { htmlToText as R } from "../../lib/sanitize-html.js";
7
- import { cn as A, formatRelative as T } from "../../lib/utils.js";
8
- const V = q(null), re = () => U(V), j = (e) => {
9
- if (e == null || e === "") return "empty";
10
- if (typeof e == "boolean") return e ? "Yes" : "No";
11
- if (typeof e == "object")
1
+ import { jsx as s, jsxs as h, Fragment as fe } from "react/jsx-runtime";
2
+ import { Copy as Q, History as me, Eye as be, Sigma as pe, ExternalLink as xe, UserRound as ye, UserRoundPen as he, UserRoundX as ge, Lock as ke, X as ne } from "lucide-react";
3
+ import { useContext as we, createContext as ve, useState as C, useCallback as N, useRef as M, useEffect as B, useLayoutEffect as Ne } from "react";
4
+ import { createPortal as Ce } from "react-dom";
5
+ import { toast as v } from "sonner";
6
+ import { htmlToText as Se } from "../../lib/sanitize-html.js";
7
+ import { cn as re, formatRelative as Z } from "../../lib/utils.js";
8
+ import { useOverflowTip as Ee } from "../TipLayer.js";
9
+ import { clearPersonalDefault as Te, usePersonalDefaultCss as Ue, refusalText as ee } from "./PersonalDefaultControl.js";
10
+ import { PERSONAL_DEFAULT_GHOST_BUTTON as Le } from "./PersonalDefaultPill.js";
11
+ import { usePersonalDefaultsApi as Fe } from "./usePersonalDefaults.js";
12
+ const Me = ve(null), Ve = () => we(Me), te = (n) => {
13
+ if (n == null || n === "") return "empty";
14
+ if (typeof n == "boolean") return n ? "Yes" : "No";
15
+ if (typeof n == "object")
12
16
  try {
13
- const s = JSON.stringify(e);
14
- return s.length > 80 ? `${s.slice(0, 80)}…` : s;
17
+ const l = JSON.stringify(n);
18
+ return l.length > 80 ? `${l.slice(0, 80)}…` : l;
15
19
  } catch {
16
- return String(e);
20
+ return String(n);
17
21
  }
18
- const n = String(e), t = /[<&]/.test(n) ? R(n).trim() : n;
19
- return t.length > 80 ? `${t.slice(0, 80)}…` : t;
22
+ const t = String(n), o = /[<&]/.test(t) ? Se(t).trim() : t;
23
+ return o.length > 80 ? `${o.slice(0, 80)}…` : o;
20
24
  };
21
- function oe({
22
- change: e,
23
- onDismiss: n,
24
- onTakeTheirs: t
25
+ function Xe({
26
+ change: n,
27
+ onDismiss: t,
28
+ onTakeTheirs: o
25
29
  }) {
26
- return e.conflict && t ? /* @__PURE__ */ x(
30
+ return n.conflict && o ? /* @__PURE__ */ h(
27
31
  "div",
28
32
  {
29
33
  "data-remote-change-ghost": !0,
30
34
  "data-remote-conflict": !0,
31
35
  className: "nvr-expand-in flex flex-wrap items-center gap-1.5 rounded-md border border-amber-300 bg-amber-50 px-2 py-1 text-[11.5px] text-amber-900 dark:border-amber-500/40 dark:bg-amber-500/10 dark:text-amber-100",
32
36
  children: [
33
- /* @__PURE__ */ o("span", { className: "h-1.5 w-1.5 shrink-0 animate-pulse rounded-full bg-amber-500" }),
34
- /* @__PURE__ */ x("span", { className: "min-w-0 flex-1", children: [
35
- e.by ?? "Someone",
37
+ /* @__PURE__ */ s("span", { className: "h-1.5 w-1.5 shrink-0 animate-pulse rounded-full bg-amber-500" }),
38
+ /* @__PURE__ */ h("span", { className: "min-w-0 flex-1", children: [
39
+ n.by ?? "Someone",
36
40
  " changed this to",
37
41
  " ",
38
- /* @__PURE__ */ o("span", { className: "font-medium", children: j(e.theirs) }),
42
+ /* @__PURE__ */ s("span", { className: "font-medium", children: te(n.theirs) }),
39
43
  " while you were editing",
40
- /* @__PURE__ */ x("span", { className: "text-amber-700/80 dark:text-amber-200/70", children: [
44
+ /* @__PURE__ */ h("span", { className: "text-amber-700/80 dark:text-amber-200/70", children: [
41
45
  " ",
42
46
  "· ",
43
- T(e.at)
47
+ Z(n.at)
44
48
  ] })
45
49
  ] }),
46
- /* @__PURE__ */ o(
50
+ /* @__PURE__ */ s(
47
51
  "button",
48
52
  {
49
53
  type: "button",
50
- onClick: t,
54
+ onClick: o,
51
55
  "data-remote-take-theirs": !0,
52
56
  className: "shrink-0 rounded border border-amber-400 bg-white px-1.5 py-0.5 text-[10.5px] font-medium text-amber-900 hover:bg-amber-100 dark:bg-transparent dark:text-amber-100 dark:hover:bg-amber-500/20",
53
57
  children: "Take theirs"
54
58
  }
55
59
  ),
56
- /* @__PURE__ */ o(
60
+ /* @__PURE__ */ s(
57
61
  "button",
58
62
  {
59
63
  type: "button",
60
- onClick: n,
64
+ onClick: t,
61
65
  "data-remote-keep-mine": !0,
62
66
  className: "shrink-0 rounded px-1.5 py-0.5 text-[10.5px] font-medium text-amber-800 hover:bg-amber-100 dark:text-amber-200 dark:hover:bg-amber-500/20",
63
67
  children: "Keep mine"
@@ -65,300 +69,507 @@ function oe({
65
69
  )
66
70
  ]
67
71
  }
68
- ) : /* @__PURE__ */ x(
72
+ ) : /* @__PURE__ */ h(
69
73
  "div",
70
74
  {
71
75
  "data-remote-change-ghost": !0,
72
76
  className: "nvr-expand-in flex items-start gap-1.5 rounded-md border border-sky-200 bg-sky-50 px-2 py-1 text-[11.5px] text-sky-900 dark:border-sky-500/30 dark:bg-sky-500/10 dark:text-sky-200",
73
77
  children: [
74
- /* @__PURE__ */ o("span", { className: "mt-0.5 h-1.5 w-1.5 shrink-0 animate-pulse rounded-full bg-sky-500" }),
75
- /* @__PURE__ */ x("span", { className: "min-w-0 flex-1", children: [
78
+ /* @__PURE__ */ s("span", { className: "mt-0.5 h-1.5 w-1.5 shrink-0 animate-pulse rounded-full bg-sky-500" }),
79
+ /* @__PURE__ */ h("span", { className: "min-w-0 flex-1", children: [
76
80
  "was",
77
81
  " ",
78
- /* @__PURE__ */ o("span", { className: "font-medium line-through decoration-sky-400/70", children: j(e.was) }),
79
- /* @__PURE__ */ x("span", { className: "text-sky-700/80 dark:text-sky-300/80", children: [
82
+ /* @__PURE__ */ s("span", { className: "font-medium line-through decoration-sky-400/70", children: te(n.was) }),
83
+ /* @__PURE__ */ h("span", { className: "text-sky-700/80 dark:text-sky-300/80", children: [
80
84
  " ",
81
85
  "· ",
82
- e.by ?? "someone",
86
+ n.by ?? "someone",
83
87
  ", ",
84
- T(e.at)
88
+ Z(n.at)
85
89
  ] })
86
90
  ] }),
87
- /* @__PURE__ */ o(
91
+ /* @__PURE__ */ s(
88
92
  "button",
89
93
  {
90
94
  type: "button",
91
- onClick: n,
95
+ onClick: t,
92
96
  "aria-label": "Dismiss",
93
97
  className: "shrink-0 rounded p-0.5 text-sky-500 hover:bg-sky-100 hover:text-sky-800 dark:hover:bg-sky-500/20",
94
- children: /* @__PURE__ */ o(I, { className: "h-3 w-3" })
98
+ children: /* @__PURE__ */ s(ne, { className: "h-3 w-3" })
95
99
  }
96
100
  )
97
101
  ]
98
102
  }
99
103
  );
100
104
  }
101
- function ae({ reason: e, onHover: n }) {
102
- return /* @__PURE__ */ o(
105
+ function Ye({ reason: n, onHover: t }) {
106
+ return /* @__PURE__ */ s(
103
107
  "span",
104
108
  {
105
- onPointerEnter: n,
109
+ onPointerEnter: t,
106
110
  className: "inline-flex cursor-help items-center gap-1 text-amber-500 dark:text-amber-400",
107
- "data-tip": e,
111
+ "data-tip": n,
108
112
  "data-lock-reason": !0,
109
- "aria-label": e,
113
+ "aria-label": n,
110
114
  role: "img",
111
- children: /* @__PURE__ */ o(H, { className: "h-3 w-3" })
115
+ children: /* @__PURE__ */ s(ke, { className: "h-3 w-3" })
112
116
  }
113
117
  );
114
118
  }
115
- function W(e, n) {
116
- if (!e || !(n != null && n.contains(e))) return null;
117
- const t = e.closest(
119
+ function Re(n, t) {
120
+ if (!n || !(t != null && t.contains(n))) return null;
121
+ const o = n.closest(
118
122
  "input, textarea, select"
119
123
  );
120
- if (t && n.contains(t) && !(t instanceof HTMLInputElement && t.type === "checkbox"))
121
- return t.value;
122
- const s = e.closest("td, th");
123
- return s && n.contains(s) ? s.innerText.replace(/\s+/g, " ").trim() : null;
124
+ if (o && t.contains(o) && !(o instanceof HTMLInputElement && o.type === "checkbox"))
125
+ return o.value;
126
+ const l = n.closest("td, th");
127
+ return l && t.contains(l) ? l.innerText.replace(/\s+/g, " ").trim() : null;
124
128
  }
125
- function se({
126
- wrapperRef: e,
127
- field: n,
128
- value: t,
129
- relations: s,
129
+ function qe({
130
+ wrapperRef: n,
131
+ field: t,
132
+ value: o,
133
+ relations: l,
130
134
  collection: m,
131
- itemId: c,
132
- openRelated: l
135
+ itemId: x,
136
+ openRelated: w,
137
+ editable: R = !1
133
138
  }) {
134
- var M, D;
135
- const [y, w] = C(null), h = g((a, u) => w({ x: a, y: u }), []), b = g(() => w(null), []), r = v(null), f = g(
136
- (a) => {
137
- var L;
138
- const u = a.target;
139
- (L = window.getSelection()) != null && L.toString() && u.closest("input, textarea, [contenteditable]") || (a.preventDefault(), r.current = u, h(a.clientX, a.clientY));
140
- },
141
- [h]
142
- ), N = g(
143
- (a) => {
139
+ var J, z;
140
+ const [g, T] = C(null), r = Fe(), [k, S] = C(!1), [y, O] = C(null), [U, A] = C(null), [$, j] = C(!1), b = N((e, c) => T({ x: e, y: c }), []), [D, a] = C(null), f = M(null), L = M(null), i = N(() => {
141
+ T(null), a(null), S(!1), O(null), A(null), j(!1);
142
+ const e = f.current, c = L.current;
143
+ f.current = null, L.current = null, (e || c) && window.setTimeout(() => {
144
144
  var u;
145
- if (a.key === "ContextMenu" || a.shiftKey && a.key === "F10") {
146
- a.preventDefault();
147
- const p = (u = e.current) == null ? void 0 : u.getBoundingClientRect();
148
- r.current = document.activeElement, h(p ? p.left + 16 : 16, p ? p.top + 28 : 16);
145
+ document.activeElement && document.activeElement !== document.body || (e != null && e.isConnected ? e.focus() : (u = c == null ? void 0 : c()) == null || u.focus());
146
+ }, 0);
147
+ }, []), p = g !== null, d = N(
148
+ (e) => {
149
+ if (p) {
150
+ i();
151
+ return;
152
+ }
153
+ const c = e.getBoundingClientRect();
154
+ _.current = null, f.current = e, a("menu"), b(c.left, c.bottom + 4);
155
+ },
156
+ [p, i, b]
157
+ ), E = N(() => {
158
+ r && (O(null), S("save"), r.describeSave(t.field).then(
159
+ (e) => O(e),
160
+ () => O([])
161
+ ));
162
+ }, [r, t.field]), P = N(() => {
163
+ r && (A(null), S("update"), r.describeUpdate(t.field).then(
164
+ (e) => A(e),
165
+ () => A({ value: "", context: [] })
166
+ ));
167
+ }, [r, t.field]), H = N(
168
+ (e, c, u = "make") => {
169
+ if (p && D === u) {
170
+ i();
171
+ return;
172
+ }
173
+ const F = e.getBoundingClientRect();
174
+ _.current = null, f.current = e, L.current = c ?? null, a(u), u === "update" ? P() : E(), b(F.right - ae, F.bottom + 4);
175
+ },
176
+ [p, D, i, b, E, P]
177
+ ), _ = M(null), oe = N(
178
+ (e) => {
179
+ var F;
180
+ const c = e.target;
181
+ (F = window.getSelection()) != null && F.toString() && c.closest("input, textarea, [contenteditable]") || (e.preventDefault(), _.current = c, a("menu"), b(e.clientX, e.clientY));
182
+ },
183
+ [b]
184
+ ), le = N(
185
+ (e) => {
186
+ var c;
187
+ if (e.key === "ContextMenu" || e.shiftKey && e.key === "F10") {
188
+ e.preventDefault();
189
+ const u = (c = n.current) == null ? void 0 : c.getBoundingClientRect();
190
+ _.current = document.activeElement, a("menu"), b(u ? u.left + 16 : 16, u ? u.top + 28 : 16);
149
191
  }
150
192
  },
151
- [h, e]
152
- ), i = s.find(
153
- (a) => a.many_collection === m && a.many_field === n.field && a.one_collection
154
- ), d = c && c !== "new", S = (a) => {
155
- var p;
156
- const u = (p = e.current) == null ? void 0 : p.querySelector(a);
157
- return u ? (u.click(), !0) : !1;
158
- }, _ = [
193
+ [b, n]
194
+ ), I = l.find(
195
+ (e) => e.many_collection === m && e.many_field === t.field && e.one_collection
196
+ ), K = x && x !== "new", W = (e) => {
197
+ var u;
198
+ const c = (u = n.current) == null ? void 0 : u.querySelector(e);
199
+ return c ? (c.click(), !0) : !1;
200
+ }, V = !!(r != null && r.allowed(t.field)), X = V && R && !!(r != null && r.hasValue(t.field)), G = V ? (r == null ? void 0 : r.defaultFor(t.field)) ?? null : null, se = X && !G, ie = X && !!G && !(r != null && r.isDefault(t.field)), Y = [
159
201
  {
160
202
  key: "copy",
161
203
  label: "Copy value",
162
- icon: /* @__PURE__ */ o(F, { className: "h-3.5 w-3.5" }),
204
+ icon: /* @__PURE__ */ s(Q, { className: "h-3.5 w-3.5" }),
163
205
  run: () => {
164
- const u = W(r.current, e.current) ?? (t == null ? "" : typeof t == "object" ? JSON.stringify(t) : String(t));
165
- if (!u) {
166
- k.info("Nothing to copy");
206
+ const c = Re(_.current, n.current) ?? (o == null ? "" : typeof o == "object" ? JSON.stringify(o) : String(o));
207
+ if (!c) {
208
+ v.info("Nothing to copy");
167
209
  return;
168
210
  }
169
- navigator.clipboard.writeText(u).then(
170
- () => k.success("Value copied"),
171
- () => k.error("Could not copy")
211
+ navigator.clipboard.writeText(c).then(
212
+ () => v.success("Value copied"),
213
+ () => v.error("Could not copy")
172
214
  );
173
215
  }
174
216
  },
175
217
  {
176
218
  key: "copy-key",
177
219
  label: "Copy field key",
178
- icon: /* @__PURE__ */ o(F, { className: "h-3.5 w-3.5" }),
179
- hint: n.field,
220
+ icon: /* @__PURE__ */ s(Q, { className: "h-3.5 w-3.5" }),
221
+ hint: t.field,
180
222
  run: () => {
181
- navigator.clipboard.writeText(n.field).then(
182
- () => k.success(`Copied “${n.field}”`),
183
- () => k.error("Could not copy")
223
+ navigator.clipboard.writeText(t.field).then(
224
+ () => v.success(`Copied “${t.field}”`),
225
+ () => v.error("Could not copy")
184
226
  );
185
227
  }
186
228
  },
187
229
  {
188
230
  key: "history",
189
231
  label: "Value history",
190
- icon: /* @__PURE__ */ o(O, { className: "h-3.5 w-3.5" }),
191
- disabled: !d,
232
+ icon: /* @__PURE__ */ s(me, { className: "h-3.5 w-3.5" }),
233
+ disabled: !K,
192
234
  run: () => {
193
- S("[data-field-history]") || k.info("No history for this field yet");
235
+ W("[data-field-history]") || v.info("No history for this field yet");
194
236
  }
195
237
  },
196
238
  {
197
239
  key: "watch",
198
240
  label: "Watch this field",
199
- icon: /* @__PURE__ */ o(K, { className: "h-3.5 w-3.5" }),
200
- disabled: !d,
241
+ icon: /* @__PURE__ */ s(be, { className: "h-3.5 w-3.5" }),
242
+ disabled: !K,
201
243
  run: () => {
202
- S("[data-field-watch]") || k.info("Field watching is off — an admin can enable it in Settings → Content");
244
+ W("[data-field-watch]") || v.info("Field watching is off — an admin can enable it in Settings → Content");
203
245
  }
204
246
  },
205
247
  {
206
248
  key: "explain",
207
249
  label: "Explain value",
208
- icon: /* @__PURE__ */ o(P, { className: "h-3.5 w-3.5" }),
209
- disabled: !d || !((M = e.current) != null && M.querySelector("[data-field-lineage]")),
250
+ icon: /* @__PURE__ */ s(pe, { className: "h-3.5 w-3.5" }),
251
+ disabled: !K || !((J = n.current) != null && J.querySelector("[data-field-lineage]")),
210
252
  run: () => {
211
- S("[data-field-lineage]");
253
+ W("[data-field-lineage]");
212
254
  }
213
255
  },
214
- ...i && l ? [
256
+ ...I && w ? [
215
257
  {
216
258
  key: "open",
217
- label: `Open related ${(D = i.one_collection) == null ? void 0 : D.replace(/_/g, " ")}`,
218
- icon: /* @__PURE__ */ o(B, { className: "h-3.5 w-3.5" }),
219
- disabled: t == null || t === "",
259
+ label: `Open related ${(z = I.one_collection) == null ? void 0 : z.replace(/_/g, " ")}`,
260
+ icon: /* @__PURE__ */ s(xe, { className: "h-3.5 w-3.5" }),
261
+ disabled: o == null || o === "",
262
+ run: () => {
263
+ const e = typeof o == "object" && o && "id" in o ? String(o.id) : String(o);
264
+ w(String(I.one_collection), e);
265
+ }
266
+ }
267
+ ] : [],
268
+ // Same states as the visible control: no default here → Save; a default holding another
269
+ // value → Update (that default, in place); the value IS the default → only Clear.
270
+ ...se ? [
271
+ {
272
+ key: "save-default",
273
+ label: "Save as my default",
274
+ icon: /* @__PURE__ */ s(ye, { className: "h-3.5 w-3.5" }),
275
+ stay: !0,
276
+ run: E
277
+ }
278
+ ] : [],
279
+ ...ie ? [
280
+ {
281
+ key: "update-default",
282
+ label: "Update my default",
283
+ icon: /* @__PURE__ */ s(he, { className: "h-3.5 w-3.5" }),
284
+ stay: !0,
285
+ run: P
286
+ }
287
+ ] : [],
288
+ ...G && r ? [
289
+ {
290
+ key: "clear-default",
291
+ label: "Clear my default",
292
+ icon: /* @__PURE__ */ s(ge, { className: "h-3.5 w-3.5" }),
293
+ // Runs at once (a menu pick is deliberate); the toast's Undo saves it back.
220
294
  run: () => {
221
- const a = typeof t == "object" && t && "id" in t ? String(t.id) : String(t);
222
- l(String(i.one_collection), a);
295
+ Te(r, t.field);
223
296
  }
224
297
  }
225
298
  ] : []
226
- ];
227
- return { onContextMenu: f, onKeyDown: N, menu: y ? /* @__PURE__ */ o(X, { at: y, items: _, onClose: b }) : null };
299
+ ], q = (e, c) => {
300
+ const u = e.value ? ` to ${e.value}` : "", F = e.context.length ? ` for ${e.context.join(" · ")}` : "";
301
+ return c ? `Updated your default${F}${u}` : `Update your default${F}${u}?`;
302
+ }, ce = k === "update" && r ? {
303
+ label: "Update my default",
304
+ action: "Update",
305
+ text: U ? q(U, !1) : "Update your default?",
306
+ ready: U !== null && !$,
307
+ saving: $,
308
+ onCancel: i,
309
+ onSave: () => {
310
+ j(!0), r.update(t.field).then(
311
+ () => {
312
+ v.success(U ? q(U, !0) : "Updated your default"), i();
313
+ },
314
+ (e) => {
315
+ v.error(ee(e, "Could not update your default")), i();
316
+ }
317
+ );
318
+ }
319
+ } : k && r ? {
320
+ label: "Save as my default",
321
+ action: "Save",
322
+ text: y != null && y.length ? `Save ${y.join(" · ")} as your ${y.length > 1 ? "defaults" : "default"}?` : "Save as your default?",
323
+ ready: y !== null && !$,
324
+ saving: $,
325
+ onCancel: i,
326
+ onSave: () => {
327
+ j(!0), r.save(t.field).then(
328
+ () => {
329
+ v.success(
330
+ y != null && y.length ? `Saved ${y.join(" · ")} as your default${y.length > 1 ? "s" : ""}` : "Your default was saved"
331
+ ), i();
332
+ },
333
+ (e) => {
334
+ v.error(ee(e, "Could not save your default")), i();
335
+ }
336
+ );
337
+ }
338
+ } : null, de = g ? /* @__PURE__ */ s(
339
+ Oe,
340
+ {
341
+ at: g,
342
+ items: Y,
343
+ onClose: i,
344
+ confirm: ce,
345
+ anchor: n.current
346
+ }
347
+ ) : null, ue = Y.some(
348
+ (e) => e.key === "save-default" || e.key === "update-default" || e.key === "clear-default"
349
+ );
350
+ return {
351
+ onContextMenu: oe,
352
+ onKeyDown: le,
353
+ menu: de,
354
+ openFrom: d,
355
+ isOpen: p,
356
+ hasFieldItems: ue,
357
+ confirmSaveFrom: H,
358
+ openedBy: D
359
+ };
228
360
  }
229
- function X({
230
- at: e,
231
- items: n,
232
- onClose: t
361
+ const ae = 240, $e = "[data-field-menu-trigger], [data-personal-default-make], [data-personal-default-update]";
362
+ function Oe({
363
+ at: n,
364
+ items: t,
365
+ onClose: o,
366
+ confirm: l,
367
+ anchor: m
233
368
  }) {
234
- const s = v(null), [m, c] = C(0), l = n.filter((r) => !r.disabled);
235
- E(() => {
236
- var N;
237
- const r = (i) => {
238
- var d;
239
- (d = s.current) != null && d.contains(i.target) || t();
369
+ Ue();
370
+ const x = M(null), [w, R] = C(0), g = t.filter((a) => !a.disabled);
371
+ B(() => {
372
+ var L;
373
+ const a = (i) => {
374
+ var d, E;
375
+ const p = i.target;
376
+ (d = x.current) != null && d.contains(p) || (E = p == null ? void 0 : p.closest) != null && E.call(p, $e) && (m != null && m.contains(p)) || o();
240
377
  }, f = (i) => {
378
+ var p;
241
379
  if (i.key === "Escape")
242
- i.preventDefault(), t();
243
- else if (i.key === "ArrowDown")
244
- i.preventDefault(), c((d) => (d + 1) % Math.max(1, l.length));
380
+ i.preventDefault(), o();
381
+ else if (l) {
382
+ if (i.key === "Tab") {
383
+ i.preventDefault();
384
+ const d = [r.current, T.current].filter(
385
+ (H) => !!H && !H.disabled
386
+ );
387
+ if (d.length === 0) return;
388
+ const E = d.indexOf(document.activeElement), P = i.shiftKey ? E - 1 : E + 1;
389
+ (p = d[(P % d.length + d.length) % d.length]) == null || p.focus();
390
+ }
391
+ return;
392
+ } else if (i.key === "ArrowDown")
393
+ i.preventDefault(), R((d) => (d + 1) % Math.max(1, g.length));
245
394
  else if (i.key === "ArrowUp")
246
- i.preventDefault(), c((d) => (d - 1 + Math.max(1, l.length)) % Math.max(1, l.length));
395
+ i.preventDefault(), R((d) => (d - 1 + Math.max(1, g.length)) % Math.max(1, g.length));
247
396
  else if (i.key === "Enter" || i.key === " ") {
248
397
  i.preventDefault();
249
- const d = l[m];
250
- d && (d.run(), t());
398
+ const d = g[w];
399
+ d && (d.run(), d.stay || o());
251
400
  }
252
401
  };
253
- return window.addEventListener("mousedown", r, !0), window.addEventListener("keydown", f, !0), (N = s.current) == null || N.focus(), () => {
254
- window.removeEventListener("mousedown", r, !0), window.removeEventListener("keydown", f, !0);
402
+ return window.addEventListener("mousedown", a, !0), window.addEventListener("keydown", f, !0), (L = x.current) == null || L.focus(), () => {
403
+ window.removeEventListener("mousedown", a, !0), window.removeEventListener("keydown", f, !0);
404
+ };
405
+ }, [o, g, w, l, m]);
406
+ const T = M(null), r = M(null), k = !!l, S = !!(l != null && l.ready);
407
+ B(() => {
408
+ var a;
409
+ k && ((a = r.current) == null || a.focus());
410
+ }, [k]), B(() => {
411
+ var f;
412
+ if (!S) return;
413
+ const a = document.activeElement;
414
+ (a === r.current || a === x.current || a === document.body) && ((f = T.current) == null || f.focus());
415
+ }, [S]);
416
+ const y = Math.min(ae, window.innerWidth - 16), O = Ee(l == null ? void 0 : l.text), [U, A] = C(() => l ? 96 : t.length * 30 + 12);
417
+ Ne(() => {
418
+ var f;
419
+ const a = (f = x.current) == null ? void 0 : f.offsetHeight;
420
+ a && a !== U && A(a);
421
+ });
422
+ const $ = Math.max(8, Math.min(n.x, window.innerWidth - y - 8)), j = Math.max(8, Math.min(n.y, window.innerHeight - U - 8)), b = (m == null ? void 0 : m.closest('[role="dialog"]')) ?? document.body, D = b === document.body ? { position: "fixed", left: $, top: j } : (() => {
423
+ const a = b.getBoundingClientRect();
424
+ return {
425
+ position: "absolute",
426
+ left: $ - a.left + b.scrollLeft - b.clientLeft,
427
+ top: j - a.top + b.scrollTop - b.clientTop
255
428
  };
256
- }, [t, l, m]);
257
- const y = 240, w = n.length * 30 + 12, h = Math.min(e.x, window.innerWidth - y - 8), b = Math.min(e.y, window.innerHeight - w - 8);
258
- return J(
259
- /* @__PURE__ */ o(
429
+ })();
430
+ return Ce(
431
+ /* @__PURE__ */ h(
260
432
  "div",
261
433
  {
262
- ref: s,
263
- role: "menu",
434
+ ref: x,
435
+ ...l ? { role: "dialog", "aria-modal": !1, "aria-label": l.label } : { role: "menu", "aria-label": "Field options" },
264
436
  tabIndex: -1,
265
437
  "data-field-context-menu": !0,
266
- style: { position: "fixed", left: h, top: b, width: y, zIndex: 110 },
438
+ style: { ...D, width: y, maxWidth: "calc(100vw - 16px)", zIndex: 110 },
267
439
  className: "rounded-lg border border-slate-200 bg-white p-1 shadow-xl outline-none dark:border-border dark:bg-card",
268
- children: n.map((r) => {
269
- const f = l.indexOf(r), N = f === m && !r.disabled;
270
- return /* @__PURE__ */ x(
271
- "button",
272
- {
273
- type: "button",
274
- role: "menuitem",
275
- disabled: r.disabled,
276
- onMouseEnter: () => f >= 0 && c(f),
277
- onClick: () => {
278
- r.run(), t();
279
- },
280
- className: A(
281
- "flex h-[30px] w-full items-center gap-2 rounded-sm px-2 text-left text-[12.5px] font-medium text-slate-700 dark:text-slate-200",
282
- N && "bg-accent text-accent-foreground",
283
- r.disabled && "cursor-not-allowed opacity-40"
440
+ children: [
441
+ l ? /* @__PURE__ */ h("div", { "data-personal-default-confirm": !0, className: "space-y-2 px-2 py-1.5", children: [
442
+ /* @__PURE__ */ s(
443
+ "p",
444
+ {
445
+ ref: O,
446
+ "aria-live": "polite",
447
+ className: "line-clamp-4 text-[12.5px] leading-snug text-slate-700 [overflow-wrap:anywhere] dark:text-slate-200",
448
+ children: l.text
449
+ }
450
+ ),
451
+ /* @__PURE__ */ h("div", { className: "flex justify-end gap-1.5", children: [
452
+ /* @__PURE__ */ h(
453
+ "button",
454
+ {
455
+ ref: r,
456
+ type: "button",
457
+ onClick: l.onCancel,
458
+ className: Le,
459
+ children: [
460
+ /* @__PURE__ */ s(ne, { className: "h-3 w-3", "aria-hidden": !0 }),
461
+ " Cancel"
462
+ ]
463
+ }
284
464
  ),
285
- children: [
286
- /* @__PURE__ */ o("span", { className: "shrink-0 text-slate-500", children: r.icon }),
287
- /* @__PURE__ */ o("span", { className: "min-w-0 flex-1 truncate", children: r.label }),
288
- r.hint && /* @__PURE__ */ o("span", { className: "max-w-[90px] truncate font-mono text-[10.5px] text-slate-400", children: r.hint })
289
- ]
290
- },
291
- r.key
292
- );
293
- })
465
+ /* @__PURE__ */ s(
466
+ "button",
467
+ {
468
+ ref: T,
469
+ type: "button",
470
+ disabled: !l.ready,
471
+ onClick: l.onSave,
472
+ className: "h-7 rounded-md bg-nvr-cyan px-2.5 text-[11.5px] font-semibold text-white hover:bg-nvr-cyan/90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-nvr-cyan/40 focus-visible:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-50",
473
+ children: l.saving ? "Saving…" : l.action
474
+ }
475
+ )
476
+ ] })
477
+ ] }) : null,
478
+ l ? null : t.map((a) => {
479
+ const f = g.indexOf(a), L = f === w && !a.disabled;
480
+ return /* @__PURE__ */ h(
481
+ "button",
482
+ {
483
+ type: "button",
484
+ role: "menuitem",
485
+ disabled: a.disabled,
486
+ onMouseEnter: () => f >= 0 && R(f),
487
+ onClick: () => {
488
+ a.run(), a.stay || o();
489
+ },
490
+ className: re(
491
+ "flex h-[30px] w-full items-center gap-2 rounded-sm px-2 text-left text-[12.5px] font-medium text-slate-700 dark:text-slate-200",
492
+ L && "bg-accent text-accent-foreground",
493
+ a.disabled && "cursor-not-allowed opacity-40"
494
+ ),
495
+ children: [
496
+ /* @__PURE__ */ s("span", { className: "shrink-0 text-slate-500", children: a.icon }),
497
+ /* @__PURE__ */ s("span", { className: "min-w-0 flex-1 truncate", children: a.label }),
498
+ a.hint && /* @__PURE__ */ s("span", { className: "max-w-[90px] truncate font-mono text-[10.5px] text-slate-400", children: a.hint })
499
+ ]
500
+ },
501
+ a.key
502
+ );
503
+ })
504
+ ]
294
505
  }
295
506
  ),
296
- document.body
507
+ b
297
508
  );
298
509
  }
299
- function ie(e) {
300
- const [n, t] = C(null), [s, m] = C(!1), c = v(!1), l = v(null);
301
- E(() => {
302
- const b = e.current;
303
- if (!b) return;
304
- const r = () => t(b.getAttribute("data-remote-editor"));
305
- r();
306
- const f = new MutationObserver(r);
307
- return f.observe(b, { attributes: !0, attributeFilter: ["data-remote-editor"] }), () => f.disconnect();
308
- }, [e]), E(() => {
309
- n || (m(!1), c.current = !1);
310
- }, [n]);
311
- const y = g(
312
- (b) => {
313
- if (!n || c.current) return;
314
- const r = b.target;
315
- r.matches('input, textarea, select, [contenteditable="true"], [role="combobox"]') && (l.current = r, setTimeout(() => {
316
- c.current || r.blur();
510
+ function Je(n) {
511
+ const [t, o] = C(null), [l, m] = C(!1), x = M(!1), w = M(null);
512
+ B(() => {
513
+ const r = n.current;
514
+ if (!r) return;
515
+ const k = () => o(r.getAttribute("data-remote-editor"));
516
+ k();
517
+ const S = new MutationObserver(k);
518
+ return S.observe(r, { attributes: !0, attributeFilter: ["data-remote-editor"] }), () => S.disconnect();
519
+ }, [n]), B(() => {
520
+ t || (m(!1), x.current = !1);
521
+ }, [t]);
522
+ const R = N(
523
+ (r) => {
524
+ if (!t || x.current) return;
525
+ const k = r.target;
526
+ k.matches('input, textarea, select, [contenteditable="true"], [role="combobox"]') && (w.current = k, setTimeout(() => {
527
+ x.current || k.blur();
317
528
  }, 0), m(!0));
318
529
  },
319
- [n]
320
- ), w = g(() => {
321
- c.current = !0, m(!1);
322
- const b = l.current;
323
- l.current = null, b && setTimeout(() => b.focus(), 0);
324
- }, []), h = g(() => {
325
- m(!1), l.current = null;
530
+ [t]
531
+ ), g = N(() => {
532
+ x.current = !0, m(!1);
533
+ const r = w.current;
534
+ w.current = null, r && setTimeout(() => r.focus(), 0);
535
+ }, []), T = N(() => {
536
+ m(!1), w.current = null;
326
537
  }, []);
327
- return { editor: n, confirming: s, onFocusCapture: y, confirm: w, cancel: h };
538
+ return { editor: t, confirming: l, onFocusCapture: R, confirm: g, cancel: T };
328
539
  }
329
- function le({
330
- editor: e,
331
- confirming: n,
332
- onConfirm: t,
333
- onCancel: s
540
+ function ze({
541
+ editor: n,
542
+ confirming: t,
543
+ onConfirm: o,
544
+ onCancel: l
334
545
  }) {
335
- const m = e.split(/\s+/).map((c) => c[0]).filter(Boolean).slice(0, 2).join("").toUpperCase();
336
- return /* @__PURE__ */ x(
546
+ const m = n.split(/\s+/).map((x) => x[0]).filter(Boolean).slice(0, 2).join("").toUpperCase();
547
+ return /* @__PURE__ */ h(
337
548
  "div",
338
549
  {
339
550
  "data-presence-soft-lock": !0,
340
- className: A(
551
+ className: re(
341
552
  "flex flex-wrap items-center gap-2 rounded-md px-2 py-1 text-[11.5px]",
342
- n ? "border border-amber-300 bg-amber-50 text-amber-900 dark:border-amber-500/40 dark:bg-amber-500/10 dark:text-amber-100" : "text-amber-700 dark:text-amber-300"
553
+ t ? "border border-amber-300 bg-amber-50 text-amber-900 dark:border-amber-500/40 dark:bg-amber-500/10 dark:text-amber-100" : "text-amber-700 dark:text-amber-300"
343
554
  ),
344
555
  children: [
345
- /* @__PURE__ */ o("span", { className: "inline-flex h-4 w-4 shrink-0 items-center justify-center rounded-full bg-amber-200 text-[9px] font-semibold text-amber-900 dark:bg-amber-500/40 dark:text-amber-50", children: m || "?" }),
346
- /* @__PURE__ */ o("span", { className: "min-w-0 flex-1", children: n ? `${e} is typing here — edit anyway?` : `${e} is editing this field` }),
347
- n && /* @__PURE__ */ x($, { children: [
348
- /* @__PURE__ */ o(
556
+ /* @__PURE__ */ s("span", { className: "inline-flex h-4 w-4 shrink-0 items-center justify-center rounded-full bg-amber-200 text-[9px] font-semibold text-amber-900 dark:bg-amber-500/40 dark:text-amber-50", children: m || "?" }),
557
+ /* @__PURE__ */ s("span", { className: "min-w-0 flex-1", children: t ? `${n} is typing here — edit anyway?` : `${n} is editing this field` }),
558
+ t && /* @__PURE__ */ h(fe, { children: [
559
+ /* @__PURE__ */ s(
349
560
  "button",
350
561
  {
351
562
  type: "button",
352
- onClick: t,
563
+ onClick: o,
353
564
  className: "rounded-md bg-amber-600 px-2 py-0.5 text-[11px] font-semibold text-white hover:bg-amber-700",
354
565
  children: "Edit anyway"
355
566
  }
356
567
  ),
357
- /* @__PURE__ */ o(
568
+ /* @__PURE__ */ s(
358
569
  "button",
359
570
  {
360
571
  type: "button",
361
- onClick: s,
572
+ onClick: l,
362
573
  className: "rounded-md border border-amber-300 px-2 py-0.5 text-[11px] font-medium hover:bg-amber-100 dark:border-amber-500/40 dark:hover:bg-amber-500/15",
363
574
  children: "Leave it"
364
575
  }
@@ -369,12 +580,12 @@ function le({
369
580
  );
370
581
  }
371
582
  export {
372
- V as FieldAffordancesContext,
373
- ae as LockReasonBadge,
374
- le as PresenceSoftLockStrip,
375
- oe as RemoteChangeGhost,
376
- j as ghostText,
377
- re as useFieldAffordances,
378
- se as useFieldContextMenu,
379
- ie as usePresenceSoftLock
583
+ Me as FieldAffordancesContext,
584
+ Ye as LockReasonBadge,
585
+ ze as PresenceSoftLockStrip,
586
+ Xe as RemoteChangeGhost,
587
+ te as ghostText,
588
+ Ve as useFieldAffordances,
589
+ qe as useFieldContextMenu,
590
+ Je as usePresenceSoftLock
380
591
  };