@nivaro/react 0.3.35 → 0.3.37

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 (106) hide show
  1. package/dist/components/slots/CommentsSlot.js +44 -36
  2. package/dist/full.css +1 -1
  3. package/dist/hooks/useSessionRecorder.js +1 -1
  4. package/dist/index.d.ts +13 -4
  5. package/dist/shared/components/AgentBadge.js +26 -0
  6. package/dist/shared/components/AgentQuestionsCard.js +198 -0
  7. package/dist/shared/components/ItemEditForm.js +3329 -3263
  8. package/dist/shared/components/McpConnectionScope.js +480 -0
  9. package/dist/shared/components/MyWorkView.js +223 -208
  10. package/dist/shared/components/RecordReadView.js +620 -572
  11. package/dist/shared/components/chat/ChatPanel.js +683 -671
  12. package/dist/shared/components/imports/DownloadSampleButton.js +69 -0
  13. package/dist/shared/components/imports/ImportConsole.js +106 -104
  14. package/dist/shared/components/imports/RunDetailSheet.js +11 -10
  15. package/dist/shared/components/item-edit/FieldAffordances.js +32 -32
  16. package/dist/shared/components/item-edit/FormTour.js +279 -0
  17. package/dist/shared/components/item-edit/GroupSection.js +377 -360
  18. package/dist/shared/components/item-edit/PersonalDefaultControl.js +80 -63
  19. package/dist/shared/components/item-edit/entry/EntryStrip.js +30 -26
  20. package/dist/shared/components/item-edit/form-density.js +36 -0
  21. package/dist/shared/components/item-edit/useFormUsageBeacon.js +59 -46
  22. package/dist/shared/components/item-edit/usePersonalDefaults.js +312 -296
  23. package/dist/shared/components/layout-editor/AddPanel.js +349 -192
  24. package/dist/shared/components/layout-editor/DesignNode.js +146 -131
  25. package/dist/shared/components/layout-editor/EditorCanvas.js +25 -17
  26. package/dist/shared/components/layout-editor/EditorTopBar.js +268 -206
  27. package/dist/shared/components/layout-editor/LayoutEditor.js +810 -731
  28. package/dist/shared/components/layout-editor/PlaceTools.js +334 -0
  29. package/dist/shared/components/layout-editor/SlashInsert.js +252 -0
  30. package/dist/shared/components/layout-editor/StructureMenu.js +285 -242
  31. package/dist/shared/components/layout-editor/add-target.js +54 -43
  32. package/dist/shared/components/layout-editor/ai-forms/AiComposer.js +238 -155
  33. package/dist/shared/components/layout-editor/ai-forms/AiFormsButton.js +1 -1
  34. package/dist/shared/components/layout-editor/ai-forms/ai-forms-api.js +15 -12
  35. package/dist/shared/components/layout-editor/dnd/LayoutDndProvider.js +379 -185
  36. package/dist/shared/components/layout-editor/dnd/TrashZone.js +96 -0
  37. package/dist/shared/components/layout-editor/dnd/UndoChip.js +76 -0
  38. package/dist/shared/components/layout-editor/dnd/merge-drop.js +33 -0
  39. package/dist/shared/components/layout-editor/dnd/multi-drop.js +87 -0
  40. package/dist/shared/components/layout-editor/dnd/node.js +115 -105
  41. package/dist/shared/components/layout-editor/dnd/rail-drop.js +4 -4
  42. package/dist/shared/components/layout-editor/dnd/sensors.js +23 -0
  43. package/dist/shared/components/layout-editor/dnd/trash-drop.js +58 -0
  44. package/dist/shared/components/layout-editor/dnd/trash-links.js +97 -0
  45. package/dist/shared/components/layout-editor/even-row.js +86 -0
  46. package/dist/shared/components/layout-editor/field-list.js +99 -0
  47. package/dist/shared/components/layout-editor/format-painter.js +102 -0
  48. package/dist/shared/components/layout-editor/grid-guides.js +15 -13
  49. package/dist/shared/components/layout-editor/inspector/BehaviourSettings.js +150 -132
  50. package/dist/shared/components/layout-editor/inspector/BulkInspector.js +57 -53
  51. package/dist/shared/components/layout-editor/inspector/EvenRowAction.js +31 -0
  52. package/dist/shared/components/layout-editor/inspector/GroupInspector.js +154 -141
  53. package/dist/shared/components/layout-editor/inspector/Inspector.js +209 -178
  54. package/dist/shared/components/layout-editor/inspector/LookTab.js +106 -98
  55. package/dist/shared/components/layout-editor/inspector/RulesTab.js +38 -37
  56. package/dist/shared/components/layout-editor/inspector/kit.js +280 -223
  57. package/dist/shared/components/layout-editor/keyboard-move.js +15 -15
  58. package/dist/shared/components/layout-editor/lint/LabelStyle.js +201 -0
  59. package/dist/shared/components/layout-editor/lint/LintPanel.js +132 -84
  60. package/dist/shared/components/layout-editor/lint/lint-api.js +65 -28
  61. package/dist/shared/components/layout-editor/nav/NavTools.js +14 -12
  62. package/dist/shared/components/layout-editor/nav/ZoomControls.js +145 -0
  63. package/dist/shared/components/layout-editor/nav/useEditorNav.js +34 -32
  64. package/dist/shared/components/layout-editor/nav/view-prefs.js +100 -15
  65. package/dist/shared/components/layout-editor/outputs/LayoutFile.js +89 -0
  66. package/dist/shared/components/layout-editor/outputs/OutputsButton.js +272 -195
  67. package/dist/shared/components/layout-editor/outputs/layout-file-plan.js +176 -0
  68. package/dist/shared/components/layout-editor/outputs/output-api.js +71 -37
  69. package/dist/shared/components/layout-editor/overview/describe-conditions.js +16 -11
  70. package/dist/shared/components/layout-editor/overview/purpose.js +5 -5
  71. package/dist/shared/components/layout-editor/panel-frame.js +1 -1
  72. package/dist/shared/components/layout-editor/parity-keys.json.js +1 -1
  73. package/dist/shared/components/layout-editor/personal-default-marks.js +40 -0
  74. package/dist/shared/components/layout-editor/pin.js +37 -19
  75. package/dist/shared/components/layout-editor/place-clip.js +257 -0
  76. package/dist/shared/components/layout-editor/preview/PreviewModes.js +27 -26
  77. package/dist/shared/components/layout-editor/preview/PreviewPanes.js +149 -118
  78. package/dist/shared/components/layout-editor/preview/SampleRecord.js +113 -0
  79. package/dist/shared/components/layout-editor/preview/preview-model.js +79 -60
  80. package/dist/shared/components/layout-editor/preview/sample-record.js +105 -0
  81. package/dist/shared/components/layout-editor/removed-log.js +151 -0
  82. package/dist/shared/components/layout-editor/reuse/LibraryRows.js +109 -78
  83. package/dist/shared/components/layout-editor/reuse/linked-sections.js +373 -0
  84. package/dist/shared/components/layout-editor/revert-element.js +140 -0
  85. package/dist/shared/components/layout-editor/section-structure.js +193 -170
  86. package/dist/shared/components/layout-editor/settings/EntrySection.js +63 -45
  87. package/dist/shared/components/layout-editor/settings/LayoutSection.js +63 -32
  88. package/dist/shared/components/layout-editor/settings/ResolveSettings.js +179 -137
  89. package/dist/shared/components/layout-editor/settings/WhoSection.js +18 -17
  90. package/dist/shared/components/layout-editor/settings/settings-registry.js +24 -0
  91. package/dist/shared/components/layout-editor/shortcuts.js +21 -16
  92. package/dist/shared/components/layout-editor/structure-ops.js +221 -195
  93. package/dist/shared/components/layout-editor/usage/UsagePanel.js +133 -85
  94. package/dist/shared/components/layout-editor/usage/refusal-lens.js +130 -0
  95. package/dist/shared/components/layout-editor/usage/usage-api.js +12 -11
  96. package/dist/shared/components/panels/CommentPanel.js +47 -45
  97. package/dist/shared/components/panels/RevisionsPanel.js +66 -64
  98. package/dist/shared/components/panels/TaskPanel.js +395 -332
  99. package/dist/shared/components/profile/AgentsPanel.js +196 -147
  100. package/dist/shared/components/profile/ConnectionRollback.js +329 -0
  101. package/dist/shared/components/profile/MyDefaultsCard.js +526 -520
  102. package/dist/shared/lib/entry-config.js +22 -22
  103. package/dist/shared/lib/form-usage-beacon.js +91 -55
  104. package/dist/shared/lib/layout-lint.js +530 -284
  105. package/dist/shared/lib/layout-resolve.js +58 -44
  106. package/package.json +1 -1
@@ -1,174 +1,210 @@
1
- import { jsx as t, jsxs as s } from "react/jsx-runtime";
2
- import { FileUp as _, Sparkles as P, Quote as q } from "lucide-react";
3
- import { useState as y, useRef as K, useMemo as v } from "react";
4
- import { useNivaroClient as L } from "../../../context.js";
5
- import { cn as g, formatFileSize as U } from "../../../lib/utils.js";
6
- import { Checkbox as Q } from "../../ui/checkbox.js";
7
- import { useOverviewFields as Y, apiFailure as W } from "../overview/overview-api.js";
8
- import { effectText as X, inputBase as R, tintCard as G } from "../panel-style.js";
9
- import { COMPOSE_ACCEPT as H, COMPOSE_MAX_BYTES as J, composeFromText as V, composeFromFile as Z } from "./ai-forms-api.js";
10
- import { extraChoices as E, planComposed as T } from "./plan.js";
11
- const ee = {
1
+ import { jsx as e, jsxs as r } from "react/jsx-runtime";
2
+ import { FileUp as U, X, Sparkles as j, Quote as q, Copy as Y } from "lucide-react";
3
+ import { useState as N, useRef as Q, useMemo as S } from "react";
4
+ import { useNivaroClient as W } from "../../../context.js";
5
+ import { cn as y, formatFileSize as G } from "../../../lib/utils.js";
6
+ import { Checkbox as H } from "../../ui/checkbox.js";
7
+ import { useOverviewFields as J, apiFailure as V } from "../overview/overview-api.js";
8
+ import { effectText as Z, inputBase as $, tintCard as ee } from "../panel-style.js";
9
+ import { COMPOSE_ACCEPT as te, COMPOSE_MAX_FILES as T, COMPOSE_MAX_BYTES as ae, COMPOSE_MAX_TOTAL_BYTES as re, composeFromText as se, composeFromFile as ne } from "./ai-forms-api.js";
10
+ import { extraChoices as z, planComposed as D } from "./plan.js";
11
+ const ie = {
12
12
  describe: {
13
13
  title: "Describe the form",
14
14
  hint: "Built from this collection’s fields. Anything the AI names that is not a field is left out and listed."
15
15
  },
16
16
  picture: {
17
- title: "From a picture or PDF",
18
- hint: "A screenshot, scan, PDF or spreadsheet of the old form. Its labels are matched to fields; labels with no field are listed, never created. Read once, never stored. Up to 10 MB."
17
+ title: "From a paper form, picture or PDF",
18
+ hint: "A photo, scan, PDF or spreadsheet of the old form (several photos for a form of several pages). Its labels are matched to fields; labels with no field are listed as fields you may want to create, never created. Read once, never stored. Up to 6 files, 10 MB each."
19
19
  },
20
20
  sop: {
21
21
  title: "From a process document",
22
22
  hint: "One step per stage of the process, with suggested read-only and required fields for the pipeline states. Read once, never stored. Up to 10 MB."
23
23
  }
24
- }, x = X, j = "inline-flex h-7 items-center gap-1 rounded-md px-2.5 text-[12px] font-medium text-slate-600 transition-colors hover:bg-muted hover:text-slate-900 disabled:opacity-50 dark:text-muted-foreground dark:hover:text-foreground", z = "inline-flex h-7 items-center gap-1.5 rounded-md bg-nvr-cyan px-3 text-[12px] font-medium text-white transition-opacity hover:opacity-90 disabled:pointer-events-none disabled:opacity-50", F = "text-[12px] font-semibold text-slate-700 dark:text-foreground", te = "rounded-md border border-amber-200 bg-amber-50 px-2.5 py-1.5 text-[12px] leading-snug text-amber-800 dark:border-amber-500/30 dark:bg-amber-500/10 dark:text-amber-200";
25
- function he({
24
+ }, k = Z, O = "inline-flex h-7 items-center gap-1 rounded-md px-2.5 text-[12px] font-medium text-slate-600 transition-colors hover:bg-muted hover:text-slate-900 disabled:opacity-50 dark:text-muted-foreground dark:hover:text-foreground", L = "inline-flex h-7 items-center gap-1.5 rounded-md bg-nvr-cyan px-3 text-[12px] font-medium text-white transition-opacity hover:opacity-90 disabled:pointer-events-none disabled:opacity-50", R = "text-[12px] font-semibold text-slate-700 dark:text-foreground", oe = "rounded-md border border-amber-200 bg-amber-50 px-2.5 py-1.5 text-[12px] leading-snug text-amber-800 dark:border-amber-500/30 dark:bg-amber-500/10 dark:text-amber-200";
25
+ function ye({
26
26
  collection: o,
27
27
  mode: n,
28
- bundle: m,
29
- applyLabel: h,
30
- onApply: w,
31
- onBack: b,
32
- busy: C = !1
28
+ bundle: h,
29
+ applyLabel: u,
30
+ onApply: d,
31
+ onBack: p,
32
+ busy: B = !1
33
33
  }) {
34
- const k = L(), { data: N = [] } = Y(o), [r, p] = y(""), [d, A] = y(null), [i, c] = y({ kind: "input" }), [e, u] = y(/* @__PURE__ */ new Set()), f = K(null), S = v(() => ({ fields: N }), [N]), D = ee[n], I = n === "describe" ? r.trim().length >= 6 : !!d, M = async () => {
35
- if (I) {
36
- c({ kind: "asking" });
34
+ const v = W(), { data: w = [] } = J(o), [i, g] = N(""), [c, C] = N([]), [l, m] = N({ kind: "input" }), [A, a] = N(/* @__PURE__ */ new Set()), x = Q(null), b = S(() => ({ fields: w }), [w]), E = ie[n], P = n === "describe" ? i.trim().length >= 6 : c.length > 0, K = (t) => {
35
+ const s = [...c];
36
+ for (const f of t) {
37
+ if (f.size > ae) {
38
+ m({ kind: "input", error: `${f.name} is larger than 10 MB` });
39
+ return;
40
+ }
41
+ s.some((F) => F.name === f.name && F.size === f.size) || s.push(f);
42
+ }
43
+ if (s.length > T) {
44
+ m({ kind: "input", error: `Up to ${T} files at once` });
45
+ return;
46
+ }
47
+ if (s.reduce((f, F) => f + F.size, 0) > re) {
48
+ m({ kind: "input", error: "The files are larger than 25 MB together" });
49
+ return;
50
+ }
51
+ C(s), m({ kind: "input" });
52
+ }, _ = async () => {
53
+ if (P) {
54
+ m({ kind: "asking" });
37
55
  try {
38
- const a = n === "describe" ? await V(k, o, r.trim()) : await Z(k, {
56
+ const t = n === "describe" ? await se(v, o, i.trim()) : await ne(v, {
39
57
  collection: o,
40
58
  mode: n,
41
- file: d,
42
- note: r
59
+ files: c,
60
+ note: i
43
61
  });
44
- u(
62
+ a(
45
63
  new Set(
46
- E(a.form, a.states ?? [], S).filter((l) => l.checked).map((l) => l.id)
64
+ z(t.form, t.states ?? [], b).filter((s) => s.checked).map((s) => s.id)
47
65
  )
48
- ), c({ kind: "review", result: a });
49
- } catch (a) {
50
- const l = W(a, "The AI could not build the form");
51
- c({
66
+ ), m({ kind: "review", result: t });
67
+ } catch (t) {
68
+ const s = V(t, "The AI could not build the form");
69
+ m({
52
70
  kind: "input",
53
- error: l.status === 503 ? "AI is not set up here. Turn it on under Settings → AI." : l.message
71
+ error: s.status === 503 ? "AI is not set up here. Turn it on under Settings → AI." : s.message
54
72
  });
55
73
  }
56
74
  }
57
75
  };
58
- return i.kind === "review" ? /* @__PURE__ */ t(
59
- ae,
76
+ return l.kind === "review" ? /* @__PURE__ */ e(
77
+ le,
60
78
  {
61
- result: i.result,
62
- bundle: m,
63
- env: S,
64
- chosen: e,
65
- onChosen: u,
66
- applyLabel: h,
67
- busy: C,
68
- onBack: () => c({ kind: "input" }),
69
- onApply: (a) => w(a, i.result)
79
+ result: l.result,
80
+ bundle: h,
81
+ env: b,
82
+ chosen: A,
83
+ onChosen: a,
84
+ applyLabel: u,
85
+ busy: B,
86
+ onBack: () => m({ kind: "input" }),
87
+ onApply: (t) => d(t, l.result)
70
88
  }
71
- ) : /* @__PURE__ */ s(
89
+ ) : /* @__PURE__ */ r(
72
90
  "form",
73
91
  {
74
92
  className: "space-y-2.5",
75
93
  "data-ai-compose": n,
76
- onSubmit: (a) => {
77
- a.preventDefault(), M();
94
+ onSubmit: (t) => {
95
+ t.preventDefault(), _();
78
96
  },
79
97
  children: [
80
- /* @__PURE__ */ t("p", { className: F, children: D.title }),
81
- /* @__PURE__ */ t("p", { className: x, children: D.hint }),
82
- n !== "describe" && /* @__PURE__ */ s("div", { className: "flex items-center gap-2", children: [
83
- /* @__PURE__ */ t(
98
+ /* @__PURE__ */ e("p", { className: R, children: E.title }),
99
+ /* @__PURE__ */ e("p", { className: k, children: E.hint }),
100
+ n !== "describe" && /* @__PURE__ */ r("div", { className: "space-y-1.5", children: [
101
+ /* @__PURE__ */ e(
84
102
  "input",
85
103
  {
86
- ref: f,
104
+ ref: x,
87
105
  type: "file",
88
- accept: H,
106
+ accept: te,
107
+ multiple: !0,
89
108
  className: "hidden",
90
109
  "data-ai-compose-file": "",
91
- onChange: (a) => {
92
- var O;
93
- const l = ((O = a.target.files) == null ? void 0 : O[0]) ?? null;
94
- if (a.target.value = "", l && l.size > J) {
95
- c({ kind: "input", error: `${l.name} is larger than 10 MB` });
96
- return;
97
- }
98
- A(l), c({ kind: "input" });
110
+ onChange: (t) => {
111
+ const s = Array.from(t.target.files ?? []);
112
+ t.target.value = "", s.length && K(s);
99
113
  }
100
114
  }
101
115
  ),
102
- /* @__PURE__ */ s(
116
+ /* @__PURE__ */ r(
103
117
  "button",
104
118
  {
105
119
  type: "button",
106
- className: g(
107
- "inline-flex h-8 items-center gap-1.5 rounded-md border border-slate-200 bg-white px-2.5 text-[12.5px] font-medium text-slate-700 transition-colors hover:bg-slate-50 dark:border-border dark:bg-card dark:text-foreground dark:hover:bg-muted"
120
+ className: y(
121
+ "inline-flex h-8 items-center gap-1.5 rounded-md border border-slate-200 bg-white px-2.5 text-[12.5px] font-medium text-slate-700 transition-colors hover:bg-slate-50 disabled:opacity-50 dark:border-border dark:bg-card dark:text-foreground dark:hover:bg-muted"
108
122
  ),
123
+ disabled: c.length >= T,
109
124
  onClick: () => {
110
- var a;
111
- return (a = f.current) == null ? void 0 : a.click();
125
+ var t;
126
+ return (t = x.current) == null ? void 0 : t.click();
112
127
  },
113
128
  children: [
114
- /* @__PURE__ */ t(_, { className: "h-3.5 w-3.5" }),
115
- d ? "Choose another file" : "Choose a file"
129
+ /* @__PURE__ */ e(U, { className: "h-3.5 w-3.5" }),
130
+ c.length ? "Add another page or file" : "Choose files"
116
131
  ]
117
132
  }
118
133
  ),
119
- d && /* @__PURE__ */ s("span", { className: "min-w-0 truncate text-[12px] text-slate-600 dark:text-muted-foreground", children: [
120
- d.name,
121
- " · ",
122
- U(d.size)
123
- ] })
134
+ c.length > 0 && /* @__PURE__ */ e("ul", { className: "space-y-0.5", "data-ai-compose-files": "", children: c.map((t, s) => /* @__PURE__ */ r(
135
+ "li",
136
+ {
137
+ className: "flex min-w-0 items-center gap-1.5 text-[12px] text-slate-600 dark:text-muted-foreground",
138
+ children: [
139
+ c.length > 1 && /* @__PURE__ */ e("span", { className: "w-4 shrink-0 text-right tabular-nums text-slate-400 dark:text-muted-foreground", children: s + 1 }),
140
+ /* @__PURE__ */ r("span", { className: "min-w-0 flex-1 truncate", children: [
141
+ t.name,
142
+ " · ",
143
+ G(t.size)
144
+ ] }),
145
+ /* @__PURE__ */ e(
146
+ "button",
147
+ {
148
+ type: "button",
149
+ "aria-label": `Remove ${t.name}`,
150
+ "data-tip": "Remove",
151
+ onClick: () => C(c.filter((f) => f !== t)),
152
+ className: "inline-flex h-6 w-6 shrink-0 items-center justify-center rounded text-slate-400 transition-colors hover:bg-muted hover:text-slate-700 dark:hover:text-foreground",
153
+ children: /* @__PURE__ */ e(X, { className: "h-3.5 w-3.5" })
154
+ }
155
+ )
156
+ ]
157
+ },
158
+ `${t.name}:${t.size}`
159
+ )) })
124
160
  ] }),
125
- n === "describe" ? /* @__PURE__ */ t(
161
+ n === "describe" ? /* @__PURE__ */ e(
126
162
  "textarea",
127
163
  {
128
- value: r,
129
- onChange: (a) => p(a.target.value),
164
+ value: i,
165
+ onChange: (t) => g(t.target.value),
130
166
  rows: 3,
131
167
  maxLength: 2e3,
132
168
  "aria-label": "Describe the form",
133
169
  placeholder: "A returns form with a manager approval step",
134
170
  "data-ai-compose-text": "",
135
- className: g(R, "h-auto resize-y py-1.5 leading-snug"),
136
- onKeyDown: (a) => {
137
- a.key === "Enter" && (a.metaKey || a.ctrlKey) && (a.preventDefault(), M());
171
+ className: y($, "h-auto resize-y py-1.5 leading-snug"),
172
+ onKeyDown: (t) => {
173
+ t.key === "Enter" && (t.metaKey || t.ctrlKey) && (t.preventDefault(), _());
138
174
  }
139
175
  }
140
- ) : /* @__PURE__ */ t(
176
+ ) : /* @__PURE__ */ e(
141
177
  "input",
142
178
  {
143
- value: r,
144
- onChange: (a) => p(a.target.value),
179
+ value: i,
180
+ onChange: (t) => g(t.target.value),
145
181
  maxLength: 500,
146
182
  "aria-label": "Note for the AI (optional)",
147
183
  placeholder: "Note for the AI (optional)",
148
- className: R
184
+ className: $
149
185
  }
150
186
  ),
151
- i.kind === "input" && i.error && /* @__PURE__ */ t(
187
+ l.kind === "input" && l.error && /* @__PURE__ */ e(
152
188
  "p",
153
189
  {
154
190
  role: "alert",
155
191
  "data-ai-compose-error": "",
156
192
  className: "text-[12.5px] leading-snug text-red-700 dark:text-red-300",
157
- children: i.error
193
+ children: l.error
158
194
  }
159
195
  ),
160
- /* @__PURE__ */ s("div", { className: "flex items-center justify-end gap-1.5 pt-0.5", children: [
161
- b && /* @__PURE__ */ t("button", { type: "button", className: j, onClick: b, children: "Back" }),
162
- /* @__PURE__ */ s(
196
+ /* @__PURE__ */ r("div", { className: "flex items-center justify-end gap-1.5 pt-0.5", children: [
197
+ p && /* @__PURE__ */ e("button", { type: "button", className: O, onClick: p, children: "Back" }),
198
+ /* @__PURE__ */ r(
163
199
  "button",
164
200
  {
165
201
  type: "submit",
166
- className: z,
167
- disabled: !I || i.kind === "asking",
202
+ className: L,
203
+ disabled: !P || l.kind === "asking",
168
204
  "data-ai-compose-run": "",
169
205
  children: [
170
- /* @__PURE__ */ t(P, { className: "h-3.5 w-3.5" }),
171
- i.kind === "asking" ? n === "describe" ? "Building…" : "Reading…" : n === "describe" ? "Build draft" : "Read it"
206
+ /* @__PURE__ */ e(j, { className: "h-3.5 w-3.5" }),
207
+ l.kind === "asking" ? n === "describe" ? "Building…" : "Reading…" : n === "describe" ? "Build draft" : "Read it"
172
208
  ]
173
209
  }
174
210
  )
@@ -177,95 +213,142 @@ function he({
177
213
  }
178
214
  );
179
215
  }
180
- function ae({
216
+ function le({
181
217
  result: o,
182
218
  bundle: n,
183
- env: m,
184
- chosen: h,
185
- onChosen: w,
186
- applyLabel: b,
187
- onApply: C,
188
- onBack: k,
189
- busy: N
219
+ env: h,
220
+ chosen: u,
221
+ onChosen: d,
222
+ applyLabel: p,
223
+ onApply: B,
224
+ onBack: v,
225
+ busy: w
190
226
  }) {
191
- const { form: r } = o, p = v(() => o.states ?? [], [o]), d = v(() => E(r, p, m), [r, p, m]), A = (e) => T(e, r, m, { chosen: h, states: p }), i = v(
192
- () => T(n, r, m, { chosen: h, states: p }),
193
- [n, r, m, h, p]
194
- ), c = r.groups.filter((e) => e.source);
195
- return /* @__PURE__ */ s("div", { className: "space-y-3", "data-ai-review": "", children: [
196
- /* @__PURE__ */ s("p", { className: g(F, "flex items-center gap-1.5"), children: [
197
- /* @__PURE__ */ t(P, { className: "h-3.5 w-3.5 text-nvr-cyan" }),
227
+ var A;
228
+ const { form: i } = o, g = S(() => o.states ?? [], [o]), c = S(() => z(i, g, h), [i, g, h]), C = (a) => D(a, i, h, { chosen: u, states: g }), l = S(
229
+ () => D(n, i, h, { chosen: u, states: g }),
230
+ [n, i, h, u, g]
231
+ ), m = i.groups.filter((a) => a.source);
232
+ return /* @__PURE__ */ r("div", { className: "space-y-3", "data-ai-review": "", children: [
233
+ /* @__PURE__ */ r("p", { className: y(R, "flex items-center gap-1.5"), children: [
234
+ /* @__PURE__ */ e(j, { className: "h-3.5 w-3.5 text-nvr-cyan" }),
198
235
  "The AI proposes"
199
236
  ] }),
200
- r.explanation && /* @__PURE__ */ t("p", { className: x, children: r.explanation }),
201
- i.steps.length > 0 ? /* @__PURE__ */ t("ol", { className: "list-decimal space-y-1 pl-5 text-[12.5px] leading-snug text-slate-700 dark:text-foreground", children: i.steps.map((e, u) => (
237
+ i.explanation && /* @__PURE__ */ e("p", { className: k, children: i.explanation }),
238
+ ((A = o.read_as) == null ? void 0 : A.includes("pdf-pages")) && /* @__PURE__ */ e("p", { className: k, "data-ai-read-as": "", children: "Read from pictures of the PDF’s pages." }),
239
+ l.steps.length > 0 ? /* @__PURE__ */ e("ol", { className: "list-decimal space-y-1 pl-5 text-[12.5px] leading-snug text-slate-700 dark:text-foreground", children: l.steps.map((a, x) => (
202
240
  // biome-ignore lint/suspicious/noArrayIndexKey: two steps may read the same; the list is rebuilt whole
203
- /* @__PURE__ */ t("li", { children: e }, `${u}:${e}`)
204
- )) }) : /* @__PURE__ */ t("p", { className: x, children: "Nothing to change: the form already looks like this." }),
205
- d.length > 0 && /* @__PURE__ */ t(B, { title: "Read-only and required, from the process", children: /* @__PURE__ */ t("ul", { className: "space-y-1.5", children: d.map((e) => /* @__PURE__ */ s("li", { className: "flex items-start gap-2", children: [
206
- /* @__PURE__ */ t(
207
- Q,
241
+ /* @__PURE__ */ e("li", { children: a }, `${x}:${a}`)
242
+ )) }) : /* @__PURE__ */ e("p", { className: k, children: "Nothing to change: the form already looks like this." }),
243
+ c.length > 0 && /* @__PURE__ */ e(M, { title: "Read-only and required, from the process", children: /* @__PURE__ */ e("ul", { className: "space-y-1.5", children: c.map((a) => /* @__PURE__ */ r("li", { className: "flex items-start gap-2", children: [
244
+ /* @__PURE__ */ e(
245
+ H,
208
246
  {
209
- id: `ai-extra-${e.id}`,
247
+ id: `ai-extra-${a.id}`,
210
248
  className: "mt-0.5 border-slate-300 data-[state=checked]:border-nvr-cyan data-[state=checked]:bg-nvr-cyan data-[state=checked]:text-white dark:border-border",
211
- checked: h.has(e.id),
212
- onCheckedChange: (u) => {
213
- const f = new Set(h);
214
- u === !0 ? f.add(e.id) : f.delete(e.id), w(f);
249
+ checked: u.has(a.id),
250
+ onCheckedChange: (x) => {
251
+ const b = new Set(u);
252
+ x === !0 ? b.add(a.id) : b.delete(a.id), d(b);
215
253
  },
216
- "data-ai-extra": e.id
254
+ "data-ai-extra": a.id
217
255
  }
218
256
  ),
219
- /* @__PURE__ */ s("label", { htmlFor: `ai-extra-${e.id}`, className: "min-w-0 flex-1 cursor-pointer", children: [
220
- /* @__PURE__ */ t("span", { className: "block text-[12.5px] leading-snug text-slate-800 dark:text-foreground", children: e.text }),
221
- e.note && /* @__PURE__ */ t("span", { className: g(x, "block"), children: e.note }),
222
- e.source && /* @__PURE__ */ t($, { text: e.source })
257
+ /* @__PURE__ */ r("label", { htmlFor: `ai-extra-${a.id}`, className: "min-w-0 flex-1 cursor-pointer", children: [
258
+ /* @__PURE__ */ e("span", { className: "block text-[12.5px] leading-snug text-slate-800 dark:text-foreground", children: a.text }),
259
+ a.note && /* @__PURE__ */ e("span", { className: y(k, "block"), children: a.note }),
260
+ a.source && /* @__PURE__ */ e(I, { text: a.source })
223
261
  ] })
224
- ] }, e.id)) }) }),
225
- c.length > 0 && /* @__PURE__ */ t(B, { title: "Where each step came from", children: /* @__PURE__ */ t("ul", { className: "space-y-1.5", "data-ai-sources": "", children: c.map((e) => /* @__PURE__ */ s("li", { children: [
226
- /* @__PURE__ */ t("span", { className: "text-[12px] font-medium text-slate-800 dark:text-foreground", children: e.label }),
227
- /* @__PURE__ */ t($, { text: e.source })
228
- ] }, e.label)) }) }),
229
- r.candidates.length > 0 && /* @__PURE__ */ s(B, { title: "Labels with no field", children: [
230
- /* @__PURE__ */ t("p", { className: x, children: "Not created. Add them as fields in the data model first if the form needs them." }),
231
- /* @__PURE__ */ t("ul", { className: "mt-1 space-y-0.5", "data-ai-candidates": "", children: r.candidates.map((e) => /* @__PURE__ */ s("li", { className: "text-[12.5px] text-slate-700 dark:text-foreground", children: [
232
- e.label,
233
- /* @__PURE__ */ t("span", { className: "text-slate-500 dark:text-muted-foreground", children: [e.type, e.group ? `in ${e.group}` : null].filter(Boolean).length ? ` · ${[e.type, e.group ? `in ${e.group}` : null].filter(Boolean).join(" · ")}` : "" })
234
- ] }, e.label)) })
235
- ] }),
236
- i.notes.map((e) => /* @__PURE__ */ t("p", { className: te, children: e }, e)),
237
- /* @__PURE__ */ s("div", { className: "flex items-center justify-end gap-1.5 pt-1", children: [
238
- /* @__PURE__ */ t("button", { type: "button", className: j, onClick: k, children: "Back" }),
239
- /* @__PURE__ */ t(
262
+ ] }, a.id)) }) }),
263
+ m.length > 0 && /* @__PURE__ */ e(M, { title: "Where each step came from", children: /* @__PURE__ */ e("ul", { className: "space-y-1.5", "data-ai-sources": "", children: m.map((a) => /* @__PURE__ */ r("li", { children: [
264
+ /* @__PURE__ */ e("span", { className: "text-[12px] font-medium text-slate-800 dark:text-foreground", children: a.label }),
265
+ /* @__PURE__ */ e(I, { text: a.source })
266
+ ] }, a.label)) }) }),
267
+ i.candidates.length > 0 && /* @__PURE__ */ e(de, { candidates: i.candidates }),
268
+ l.notes.map((a) => /* @__PURE__ */ e("p", { className: oe, children: a }, a)),
269
+ /* @__PURE__ */ r("div", { className: "flex items-center justify-end gap-1.5 pt-1", children: [
270
+ /* @__PURE__ */ e("button", { type: "button", className: O, onClick: v, children: "Back" }),
271
+ /* @__PURE__ */ e(
240
272
  "button",
241
273
  {
242
274
  type: "button",
243
- className: z,
244
- disabled: i.ops.length === 0 || N,
245
- onClick: () => C(A),
275
+ className: L,
276
+ disabled: l.ops.length === 0 || w,
277
+ onClick: () => B(C),
246
278
  "data-ai-apply": "",
247
- children: b(i)
279
+ children: p(l)
248
280
  }
249
281
  )
250
282
  ] })
251
283
  ] });
252
284
  }
253
- function B({ title: o, children: n }) {
254
- return /* @__PURE__ */ s("div", { className: g(G, "space-y-1.5 px-2.5 py-2"), children: [
255
- /* @__PURE__ */ t("p", { className: F, children: o }),
285
+ function de({ candidates: o }) {
286
+ const [n, h] = N(!1), u = async () => {
287
+ const d = o.map((p) => [p.label, p.key ?? "", p.type ?? ""].join(" "));
288
+ try {
289
+ await navigator.clipboard.writeText(["Label Key Type", ...d].join(`
290
+ `)), h(!0), setTimeout(() => h(!1), 2e3);
291
+ } catch {
292
+ }
293
+ };
294
+ return /* @__PURE__ */ r(M, { title: "Fields you may want to create", children: [
295
+ /* @__PURE__ */ e("p", { className: k, children: "Labels on the form no field matched. Nothing is created: add the ones you need in the data model, then build again to place them." }),
296
+ /* @__PURE__ */ e("ul", { className: "mt-1 space-y-1", "data-ai-candidates": "", children: o.map((d) => {
297
+ const p = [d.type, d.group ? `in ${d.group}` : null].filter(Boolean).join(" · ");
298
+ return /* @__PURE__ */ r(
299
+ "li",
300
+ {
301
+ className: "flex min-w-0 flex-wrap items-baseline gap-x-1.5 text-[12.5px] text-slate-700 dark:text-foreground",
302
+ children: [
303
+ /* @__PURE__ */ e("span", { className: "min-w-0 break-words", children: d.label }),
304
+ p && /* @__PURE__ */ r("span", { className: "text-slate-500 dark:text-muted-foreground", children: [
305
+ "· ",
306
+ p
307
+ ] }),
308
+ d.key && /* @__PURE__ */ e(
309
+ "span",
310
+ {
311
+ "data-tip": "Suggested field key",
312
+ className: "font-mono text-[11px] text-slate-500 dark:text-muted-foreground",
313
+ children: d.key
314
+ }
315
+ )
316
+ ]
317
+ },
318
+ d.label
319
+ );
320
+ }) }),
321
+ /* @__PURE__ */ r(
322
+ "button",
323
+ {
324
+ type: "button",
325
+ className: y(O, "-ml-2.5 mt-0.5"),
326
+ onClick: () => void u(),
327
+ "data-ai-candidates-copy": "",
328
+ children: [
329
+ /* @__PURE__ */ e(Y, { className: "h-3.5 w-3.5" }),
330
+ n ? "Copied" : "Copy the list"
331
+ ]
332
+ }
333
+ )
334
+ ] });
335
+ }
336
+ function M({ title: o, children: n }) {
337
+ return /* @__PURE__ */ r("div", { className: y(ee, "space-y-1.5 px-2.5 py-2"), children: [
338
+ /* @__PURE__ */ e("p", { className: R, children: o }),
256
339
  n
257
340
  ] });
258
341
  }
259
- function $({ text: o }) {
260
- return /* @__PURE__ */ s("span", { className: "mt-0.5 flex items-start gap-1 text-[11.5px] italic leading-snug text-slate-500 dark:text-muted-foreground", children: [
261
- /* @__PURE__ */ t(q, { className: "mt-0.5 h-3 w-3 shrink-0 not-italic" }),
342
+ function I({ text: o }) {
343
+ return /* @__PURE__ */ r("span", { className: "mt-0.5 flex items-start gap-1 text-[11.5px] italic leading-snug text-slate-500 dark:text-muted-foreground", children: [
344
+ /* @__PURE__ */ e(q, { className: "mt-0.5 h-3 w-3 shrink-0 not-italic" }),
262
345
  o
263
346
  ] });
264
347
  }
265
348
  export {
266
- he as AiComposer,
267
- ee as MODE_COPY,
268
- j as ghostBtn,
269
- z as primaryBtn,
270
- x as quiet
349
+ ye as AiComposer,
350
+ ie as MODE_COPY,
351
+ O as ghostBtn,
352
+ L as primaryBtn,
353
+ k as quiet
271
354
  };
@@ -64,7 +64,7 @@ function $({
64
64
  m,
65
65
  {
66
66
  icon: /* @__PURE__ */ e(v, { className: "h-3.5 w-3.5" }),
67
- title: "From a picture or PDF",
67
+ title: "From a paper form or PDF",
68
68
  sub: "An old paper, PDF or Excel form, matched to fields",
69
69
  onClick: () => t("picture")
70
70
  }
@@ -1,14 +1,15 @@
1
1
  import { post as r } from "../../../lib/commands.js";
2
- const d = ".png,.jpg,.jpeg,.gif,.webp,.pdf,.docx,.xlsx,.xls,.xlsm,.csv,.txt,.md,.eml,.html,.htm", l = 10 * 1024 * 1024;
3
- async function m(o, e, t) {
2
+ const m = ".png,.jpg,.jpeg,.gif,.webp,.pdf,.docx,.xlsx,.xls,.xlsm,.csv,.txt,.md,.eml,.html,.htm", l = 10 * 1024 * 1024, f = 6, u = 25 * 1024 * 1024;
3
+ async function p(o, e, t) {
4
4
  return (await o.request(
5
5
  r("/ai-design/layouts/compose", { collection: e, text: t })
6
6
  )).data;
7
7
  }
8
- async function f(o, e) {
9
- var i;
8
+ async function g(o, e) {
9
+ var c;
10
10
  const t = new FormData();
11
- t.append("collection", e.collection), t.append("mode", e.mode), (i = e.note) != null && i.trim() && t.append("note", e.note.trim()), t.append("file", e.file, e.file.name);
11
+ t.append("collection", e.collection), t.append("mode", e.mode), (c = e.note) != null && c.trim() && t.append("note", e.note.trim());
12
+ for (const i of e.files) t.append("file", i, i.name);
12
13
  const s = o.getToken(), a = await fetch(`${o.url}/api/ai-design/layouts/compose/file`, {
13
14
  method: "POST",
14
15
  headers: s ? { Authorization: `Bearer ${s}` } : {},
@@ -22,19 +23,21 @@ async function f(o, e) {
22
23
  });
23
24
  return n.data;
24
25
  }
25
- async function u(o, e, t) {
26
+ async function h(o, e, t) {
26
27
  return (await o.request(
27
28
  r(`/ai-design/layouts/${e}/slim`, { role_id: t })
28
29
  )).data;
29
30
  }
30
- async function p(o, e, t) {
31
+ async function O(o, e, t) {
31
32
  return (await o.request(r(`/ai-design/layouts/${e}/sections-by-meaning`, t))).data;
32
33
  }
33
34
  export {
34
- d as COMPOSE_ACCEPT,
35
+ m as COMPOSE_ACCEPT,
35
36
  l as COMPOSE_MAX_BYTES,
36
- f as composeFromFile,
37
- m as composeFromText,
38
- p as fetchMeaning,
39
- u as fetchSlim
37
+ f as COMPOSE_MAX_FILES,
38
+ u as COMPOSE_MAX_TOTAL_BYTES,
39
+ g as composeFromFile,
40
+ p as composeFromText,
41
+ O as fetchMeaning,
42
+ h as fetchSlim
40
43
  };