formlift 0.1.0 → 0.2.0

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.
@@ -23,8 +23,7 @@
23
23
 
24
24
 
25
25
 
26
-
27
- var _chunk5VHPTLLVcjs = require('../chunk-5VHPTLLV.cjs');
26
+ var _chunk33XWO4KBcjs = require('../chunk-33XWO4KB.cjs');
28
27
 
29
28
 
30
29
 
@@ -56,15 +55,11 @@ var _chunk7NZPYWL3cjs = require('../chunk-7NZPYWL3.cjs');
56
55
 
57
56
 
58
57
  var _lucidereact = require('lucide-react');
58
+ var _react = require('react');
59
59
 
60
+ // src/react/ui/slots.tsx
60
61
 
61
62
 
62
-
63
-
64
-
65
-
66
- var _react = require('react');
67
-
68
63
  // src/react/ui/Button.tsx
69
64
  var _jsxruntime = require('react/jsx-runtime');
70
65
  var variants = {
@@ -103,6 +98,143 @@ function Button({
103
98
  );
104
99
  }
105
100
 
101
+ // src/react/ui/Checkbox.tsx
102
+
103
+ function Checkbox({
104
+ label,
105
+ className = "",
106
+ ...rest
107
+ }) {
108
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
109
+ "input",
110
+ {
111
+ type: "checkbox",
112
+ "aria-label": label,
113
+ className: `h-[18px] w-[18px] flex-none cursor-pointer accent-primary ${className}`,
114
+ ...rest
115
+ }
116
+ );
117
+ }
118
+
119
+ // src/react/ui/Chip.tsx
120
+
121
+
122
+ function Chip({
123
+ label,
124
+ count,
125
+ active,
126
+ onClick
127
+ }) {
128
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
129
+ "button",
130
+ {
131
+ type: "button",
132
+ "aria-pressed": !!active,
133
+ onClick,
134
+ className: `inline-flex cursor-pointer items-center gap-1.5 rounded-full border px-3 py-1 text-[12.5px] whitespace-nowrap transition-colors ${active ? "border-primary bg-primary-tint font-semibold text-primary" : "border-line-strong bg-white text-ink-2 hover:border-faint hover:bg-surface"}`,
135
+ children: [
136
+ label,
137
+ count != null && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
138
+ "span",
139
+ {
140
+ className: `rounded-full px-1.5 text-[11px] font-semibold ${active ? "bg-primary text-white" : "bg-hover text-muted"}`,
141
+ children: count
142
+ }
143
+ )
144
+ ]
145
+ }
146
+ );
147
+ }
148
+ function ChipGroup({
149
+ title,
150
+ options,
151
+ value,
152
+ onChange
153
+ }) {
154
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { role: "group", "aria-label": title, className: "flex flex-wrap items-center gap-1.5", children: [
155
+ title && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "mr-1 min-w-28 text-[11.5px] max-sm:basis-full font-semibold tracking-wide text-muted uppercase", children: title }),
156
+ options.map((o) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
157
+ Chip,
158
+ {
159
+ label: o.label,
160
+ count: o.count,
161
+ active: value === o.value,
162
+ onClick: () => onChange(value === o.value ? null : o.value)
163
+ },
164
+ o.value
165
+ ))
166
+ ] });
167
+ }
168
+ function RemovableChip({ label, onRemove }) {
169
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { className: "inline-flex items-center gap-1 rounded-full bg-primary-tint py-0.5 pr-1 pl-2.5 text-[12px] font-medium text-primary", children: [
170
+ label,
171
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
172
+ "button",
173
+ {
174
+ type: "button",
175
+ "aria-label": `Remove ${label}`,
176
+ onClick: onRemove,
177
+ className: "inline-flex h-4.5 w-4.5 cursor-pointer items-center justify-center rounded-full hover:bg-primary hover:text-white",
178
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.X, { size: 12 })
179
+ }
180
+ )
181
+ ] });
182
+ }
183
+
184
+ // src/react/ui/FormField.tsx
185
+
186
+ var inputClass = "w-full rounded-md border border-line-strong bg-white px-3 py-2 text-[13.5px] outline-none focus:border-primary";
187
+ function FormField({
188
+ label,
189
+ required,
190
+ error,
191
+ children
192
+ }) {
193
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "label", { className: "block text-[13.5px]", children: [
194
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { className: "mb-1 block font-semibold", children: [
195
+ label,
196
+ " ",
197
+ required && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-danger", children: "*" })
198
+ ] }),
199
+ children,
200
+ error && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "small", { className: "text-danger", children: error })
201
+ ] });
202
+ }
203
+ var TextInput = ({ className = "", ...rest }) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "input", { className: `${inputClass} ${className}`, ...rest });
204
+ var Select = ({ className = "", ...rest }) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
205
+ "select",
206
+ {
207
+ className: `rounded-md border border-line-strong bg-white px-2.5 py-1.5 text-[13px] outline-none ${className}`,
208
+ ...rest
209
+ }
210
+ );
211
+ var TextArea = ({ className = "", ...rest }) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "textarea", { className: `${inputClass} resize-none ${className}`, ...rest });
212
+
213
+ // src/react/ui/IconButton.tsx
214
+
215
+ function IconButton({
216
+ title,
217
+ icon: Icon,
218
+ danger,
219
+ iconSize = 18,
220
+ light,
221
+ className = "",
222
+ ...rest
223
+ }) {
224
+ const tone = light ? "text-white opacity-90 hover:bg-white/15 hover:opacity-100" : `text-muted hover:bg-line-soft ${danger ? "hover:text-danger" : "hover:text-primary"}`;
225
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
226
+ "button",
227
+ {
228
+ type: "button",
229
+ title,
230
+ "aria-label": title,
231
+ className: `inline-flex cursor-pointer items-center justify-center rounded p-1.5 transition disabled:cursor-not-allowed disabled:opacity-40 ${tone} ${className}`,
232
+ ...rest,
233
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Icon, { size: iconSize })
234
+ }
235
+ );
236
+ }
237
+
106
238
  // src/react/ui/Modal.tsx
107
239
 
108
240
  function Modal({ children, onClose, width }) {
@@ -154,31 +286,6 @@ function ConfirmModal({
154
286
  ] });
155
287
  }
156
288
 
157
- // src/react/ui/IconButton.tsx
158
-
159
- function IconButton({
160
- title,
161
- icon: Icon,
162
- danger,
163
- iconSize = 18,
164
- light,
165
- className = "",
166
- ...rest
167
- }) {
168
- const tone = light ? "text-white opacity-90 hover:bg-white/15 hover:opacity-100" : `text-muted hover:bg-line-soft ${danger ? "hover:text-danger" : "hover:text-primary"}`;
169
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
170
- "button",
171
- {
172
- type: "button",
173
- title,
174
- "aria-label": title,
175
- className: `inline-flex cursor-pointer items-center justify-center rounded p-1.5 transition disabled:cursor-not-allowed disabled:opacity-40 ${tone} ${className}`,
176
- ...rest,
177
- children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Icon, { size: iconSize })
178
- }
179
- );
180
- }
181
-
182
289
  // src/react/ui/Panel.tsx
183
290
 
184
291
  var PanelHeading = ({ children, actions }) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex items-center justify-between bg-heading px-3.5 py-[11px] text-[13px] font-bold tracking-[0.02em] text-white", children: [
@@ -187,6 +294,65 @@ var PanelHeading = ({ children, actions }) => /* @__PURE__ */ _jsxruntime.jsxs.c
187
294
  ] });
188
295
  var EmptyText = ({ children, className = "" }) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: `m-0 px-3.5 py-3 text-[13px] text-muted ${className}`, children });
189
296
 
297
+ // src/react/ui/Popover.tsx
298
+
299
+
300
+ // src/react/ui/useOutsideClose.ts
301
+
302
+ function useOutsideClose(ref, open, onClose) {
303
+ _react.useEffect.call(void 0, () => {
304
+ if (!open) return;
305
+ const onClick = (e) => ref.current && e.composedPath().includes(ref.current) || onClose();
306
+ const onKey = (e) => e.key === "Escape" && onClose();
307
+ document.addEventListener("mousedown", onClick);
308
+ document.addEventListener("keydown", onKey);
309
+ return () => {
310
+ document.removeEventListener("mousedown", onClick);
311
+ document.removeEventListener("keydown", onKey);
312
+ };
313
+ }, [ref, open, onClose]);
314
+ }
315
+
316
+ // src/react/ui/Popover.tsx
317
+
318
+ function Popover({
319
+ label,
320
+ icon: Icon,
321
+ badge,
322
+ align = "left",
323
+ children
324
+ }) {
325
+ const [open, setOpen] = _react.useState.call(void 0, false);
326
+ const box2 = _react.useRef.call(void 0, null);
327
+ useOutsideClose(box2, open, () => setOpen(false));
328
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { ref: box2, className: "relative", children: [
329
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
330
+ "button",
331
+ {
332
+ type: "button",
333
+ "aria-expanded": open,
334
+ "aria-haspopup": "dialog",
335
+ onClick: () => setOpen((o) => !o),
336
+ className: `inline-flex cursor-pointer items-center gap-1.5 rounded-md border px-3 py-1.5 text-[13px] font-medium ${open || badge ? "border-primary bg-primary-soft text-primary" : "border-line-strong bg-white text-ink-2 hover:border-faint"}`,
337
+ children: [
338
+ Icon && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Icon, { size: 15 }),
339
+ label,
340
+ !!badge && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "inline-flex h-[18px] min-w-[18px] items-center justify-center rounded-full bg-primary px-1 text-[11px] font-bold text-white", children: badge })
341
+ ]
342
+ }
343
+ ),
344
+ open && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
345
+ "div",
346
+ {
347
+ role: "dialog",
348
+ "aria-label": label,
349
+ className: `absolute z-30 mt-1.5 w-[min(560px,calc(100vw-24px))] max-sm:fixed max-sm:inset-x-3 max-sm:max-h-[70dvh] max-sm:w-auto max-sm:overflow-y-auto rounded-lg border border-line bg-white p-4 shadow-xl ${align === "right" ? "right-0" : "left-0"}`,
350
+ children
351
+ }
352
+ )
353
+ ] });
354
+ }
355
+
190
356
  // src/react/ui/SegmentedTabs.tsx
191
357
 
192
358
  function SegmentedTabs({
@@ -209,52 +375,156 @@ function SegmentedTabs({
209
375
  )) });
210
376
  }
211
377
 
212
- // src/react/ui/Checkbox.tsx
213
-
214
- function Checkbox({
215
- label,
216
- className = "",
217
- ...rest
218
- }) {
219
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
220
- "input",
221
- {
222
- type: "checkbox",
223
- "aria-label": label,
224
- className: `h-[18px] w-[18px] flex-none cursor-pointer accent-primary ${className}`,
225
- ...rest
226
- }
227
- );
228
- }
378
+ // src/react/ui/SignaturePad.tsx
379
+
380
+
381
+ function SignaturePad({
382
+ onSave,
383
+ onCancel,
384
+ maxWidth = 600
385
+ }) {
386
+ const canvas = _react.useRef.call(void 0, null);
387
+ const last = _react.useRef.call(void 0, null);
388
+ const [empty, setEmpty] = _react.useState.call(void 0, true);
389
+ const point = (e) => {
390
+ const r = e.currentTarget.getBoundingClientRect();
391
+ return {
392
+ x: (e.clientX - r.left) / r.width * e.currentTarget.width,
393
+ y: (e.clientY - r.top) / r.height * e.currentTarget.height
394
+ };
395
+ };
396
+ const draw = (e) => {
397
+ const ctx = _optionalChain([canvas, 'access', _2 => _2.current, 'optionalAccess', _3 => _3.getContext, 'call', _4 => _4("2d")]);
398
+ if (!ctx || !last.current) return;
399
+ const p = point(e);
400
+ ctx.lineWidth = 3;
401
+ ctx.lineCap = "round";
402
+ ctx.strokeStyle = "#111827";
403
+ ctx.beginPath();
404
+ ctx.moveTo(last.current.x, last.current.y);
405
+ ctx.lineTo(p.x, p.y);
406
+ ctx.stroke();
407
+ last.current = p;
408
+ setEmpty(false);
409
+ };
410
+ const clear = () => {
411
+ const c = canvas.current;
412
+ _optionalChain([c, 'optionalAccess', _5 => _5.getContext, 'call', _6 => _6("2d"), 'optionalAccess', _7 => _7.clearRect, 'call', _8 => _8(0, 0, c.width, c.height)]);
413
+ setEmpty(true);
414
+ };
415
+ const save = () => {
416
+ const c = canvas.current;
417
+ if (!c) return;
418
+ const scale = Math.min(1, maxWidth / c.width);
419
+ const out = document.createElement("canvas");
420
+ out.width = Math.round(c.width * scale);
421
+ out.height = Math.round(c.height * scale);
422
+ _optionalChain([out, 'access', _9 => _9.getContext, 'call', _10 => _10("2d"), 'optionalAccess', _11 => _11.drawImage, 'call', _12 => _12(c, 0, 0, out.width, out.height)]);
423
+ onSave(out.toDataURL("image/png"));
424
+ };
425
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "space-y-3", children: [
426
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
427
+ "canvas",
428
+ {
429
+ ref: canvas,
430
+ width: 800,
431
+ height: 260,
432
+ "aria-label": "Signature drawing area",
433
+ className: "h-[200px] w-full touch-none rounded-md border border-dashed border-line-strong bg-surface",
434
+ onPointerDown: (e) => {
435
+ e.currentTarget.setPointerCapture(e.pointerId);
436
+ last.current = point(e);
437
+ },
438
+ onPointerMove: draw,
439
+ onPointerUp: () => last.current = null
440
+ }
441
+ ),
442
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex justify-end gap-2", children: [
443
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Button, { variant: "secondary", onClick: clear, children: "Clear" }),
444
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Button, { variant: "secondary", onClick: onCancel, children: "Cancel" }),
445
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Button, { disabled: empty, onClick: save, children: "Use signature" })
446
+ ] })
447
+ ] });
448
+ }
449
+
450
+ // src/react/ui/Tag.tsx
229
451
 
230
- // src/react/ui/FormField.tsx
452
+ var tones = {
453
+ success: "bg-success/15 text-success",
454
+ info: "bg-heading/20 text-primary",
455
+ muted: "bg-hover text-muted"
456
+ };
457
+ var Tag = ({ tone = "info", children }) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
458
+ "span",
459
+ {
460
+ className: `inline-block rounded-full px-2.5 py-0.5 text-[11px] font-semibold whitespace-nowrap ${tones[tone]}`,
461
+ children
462
+ }
463
+ );
231
464
 
232
- var inputClass = "w-full rounded-md border border-line-strong bg-white px-3 py-2 text-[13.5px] outline-none focus:border-primary";
233
- function FormField({
234
- label,
235
- required,
236
- error,
465
+ // src/react/ui/slots.tsx
466
+
467
+ var base = {
468
+ Button,
469
+ IconButton,
470
+ Checkbox,
471
+ FormField,
472
+ TextInput,
473
+ Select,
474
+ TextArea,
475
+ Modal,
476
+ ModalHeader,
477
+ ModalBody,
478
+ ModalFooter,
479
+ ConfirmModal,
480
+ PanelHeading,
481
+ EmptyText,
482
+ SegmentedTabs,
483
+ Chip,
484
+ ChipGroup,
485
+ RemovableChip,
486
+ Popover,
487
+ Tag,
488
+ SignaturePad
489
+ };
490
+ var defaultComponents = base;
491
+ var UIContext = _react.createContext.call(void 0, {});
492
+ function FormliftProvider({
493
+ components,
237
494
  children
238
495
  }) {
239
- return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "label", { className: "block text-[13.5px]", children: [
240
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { className: "mb-1 block font-semibold", children: [
241
- label,
242
- " ",
243
- required && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-danger", children: "*" })
244
- ] }),
245
- children,
246
- error && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "small", { className: "text-danger", children: error })
247
- ] });
496
+ const outer = _react.useContext.call(void 0, UIContext);
497
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, UIContext.Provider, { value: components ? { ...outer, ...components } : outer, children });
248
498
  }
249
- var TextInput = ({ className = "", ...rest }) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "input", { className: `${inputClass} ${className}`, ...rest });
250
- var Select = ({ className = "", ...rest }) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
251
- "select",
252
- {
253
- className: `rounded-md border border-line-strong bg-white px-2.5 py-1.5 text-[13px] outline-none ${className}`,
254
- ...rest
255
- }
256
- );
257
- var TextArea = ({ className = "", ...rest }) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "textarea", { className: `${inputClass} resize-none ${className}`, ...rest });
499
+ function slot(name) {
500
+ const Slot = (props) => {
501
+ const C = _nullishCoalesce(_react.useContext.call(void 0, UIContext)[name], () => ( base[name]));
502
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, C, { ...props });
503
+ };
504
+ Slot.displayName = `formlift.${name}`;
505
+ return Slot;
506
+ }
507
+ var Button2 = slot("Button");
508
+ var IconButton2 = slot("IconButton");
509
+ var Checkbox2 = slot("Checkbox");
510
+ var FormField2 = slot("FormField");
511
+ var TextInput2 = slot("TextInput");
512
+ var Select2 = slot("Select");
513
+ var TextArea2 = slot("TextArea");
514
+ var Modal2 = slot("Modal");
515
+ var ModalHeader2 = slot("ModalHeader");
516
+ var ModalBody2 = slot("ModalBody");
517
+ var ModalFooter2 = slot("ModalFooter");
518
+ var ConfirmModal2 = slot("ConfirmModal");
519
+ var PanelHeading2 = slot("PanelHeading");
520
+ var EmptyText2 = slot("EmptyText");
521
+ var SegmentedTabs2 = slot("SegmentedTabs");
522
+ var Chip2 = slot("Chip");
523
+ var ChipGroup2 = slot("ChipGroup");
524
+ var RemovableChip2 = slot("RemovableChip");
525
+ var Popover2 = slot("Popover");
526
+ var Tag2 = slot("Tag");
527
+ var SignaturePad2 = slot("SignaturePad");
258
528
 
259
529
  // src/react/components/ElementProperties.tsx
260
530
 
@@ -270,7 +540,7 @@ function ColorField({
270
540
  onChange,
271
541
  allowNone
272
542
  }) {
273
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, FormField, { label, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { className: "flex items-center gap-2", children: [
543
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, FormField2, { label, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { className: "flex items-center gap-2", children: [
274
544
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
275
545
  "input",
276
546
  {
@@ -283,7 +553,7 @@ function ColorField({
283
553
  ),
284
554
  allowNone && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "label", { className: "inline-flex items-center gap-1.5 text-[12.5px]", children: [
285
555
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
286
- Checkbox,
556
+ Checkbox2,
287
557
  {
288
558
  label: `No ${label.toLowerCase()}`,
289
559
  checked: !value,
@@ -307,7 +577,7 @@ function ElementProperties({
307
577
  if (e.type === "line")
308
578
  set({ position: { ...p, width: Math.min(p.width, 1 - p.x), height: Math.min(p.height, 1 - p.y) } });
309
579
  else {
310
- const { page: _page, ...fitted } = _chunk5VHPTLLVcjs.fitInPage.call(void 0, { page: e.page, ...p });
580
+ const { page: _page, ...fitted } = _chunk33XWO4KBcjs.fitInPage.call(void 0, { page: e.page, ...p });
311
581
  void _page;
312
582
  set({ position: fitted });
313
583
  }
@@ -320,7 +590,7 @@ function ElementProperties({
320
590
  "\u201D"
321
591
  ] }),
322
592
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
323
- TextArea,
593
+ TextArea2,
324
594
  {
325
595
  rows: 4,
326
596
  "aria-label": "Text",
@@ -331,8 +601,8 @@ function ElementProperties({
331
601
  }
332
602
  ),
333
603
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "grid grid-cols-2 gap-2", children: [
334
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, FormField, { label: "Font", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
335
- Select,
604
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, FormField2, { label: "Font", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
605
+ Select2,
336
606
  {
337
607
  className: "w-full",
338
608
  value: _nullishCoalesce(e.font, () => ( "sans")),
@@ -340,8 +610,8 @@ function ElementProperties({
340
610
  children: _chunk7NZPYWL3cjs.FONTS.map((f) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "option", { value: f, children: { sans: "Sans (Helvetica)", serif: "Serif (Times)", mono: "Mono (Courier)" }[f] }, f))
341
611
  }
342
612
  ) }),
343
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, FormField, { label: "Size (pt)", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
344
- TextInput,
613
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, FormField2, { label: "Size (pt)", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
614
+ TextInput2,
345
615
  {
346
616
  type: "number",
347
617
  min: 3,
@@ -357,11 +627,11 @@ function ElementProperties({
357
627
  ] }),
358
628
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-wrap items-center gap-4", children: [
359
629
  ["bold", "italic"].map((k) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "label", { className: "inline-flex items-center gap-1.5", children: [
360
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Checkbox, { label: k, checked: !!e[k], onChange: (ev) => set({ [k]: ev.target.checked || void 0 }) }),
630
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Checkbox2, { label: k, checked: !!e[k], onChange: (ev) => set({ [k]: ev.target.checked || void 0 }) }),
361
631
  k === "bold" ? "Bold" : "Italic"
362
632
  ] }, k)),
363
633
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
364
- Select,
634
+ Select2,
365
635
  {
366
636
  "aria-label": "Alignment",
367
637
  value: _nullishCoalesce(e.align, () => ( "left")),
@@ -388,8 +658,8 @@ function ElementProperties({
388
658
  onChange: (v) => set({ stroke: v })
389
659
  }
390
660
  ),
391
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, FormField, { label: "Line width (pt)", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
392
- TextInput,
661
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, FormField2, { label: "Line width (pt)", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
662
+ TextInput2,
393
663
  {
394
664
  type: "number",
395
665
  min: 0,
@@ -406,8 +676,8 @@ function ElementProperties({
406
676
  e.fill === "#ffffff" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "m-0 text-[12px] text-muted", children: "A white background hides the original under it." })
407
677
  ] }),
408
678
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Section, { title: "Position (% of page)", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "grid grid-cols-2 gap-2", children: [
409
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, FormField, { label: "Page", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
410
- TextInput,
679
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, FormField2, { label: "Page", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
680
+ TextInput2,
411
681
  {
412
682
  type: "number",
413
683
  min: 1,
@@ -420,8 +690,8 @@ function ElementProperties({
420
690
  }
421
691
  ) }),
422
692
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", {}),
423
- ["x", "y", "width", "height"].map((k) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, FormField, { label: { x: "Left", y: "Top", width: "Width", height: "Height" }[k], children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
424
- TextInput,
693
+ ["x", "y", "width", "height"].map((k) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, FormField2, { label: { x: "Left", y: "Top", width: "Width", height: "Height" }[k], children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
694
+ TextInput2,
425
695
  {
426
696
  type: "number",
427
697
  step: 0.1,
@@ -437,80 +707,6 @@ function ElementProperties({
437
707
 
438
708
 
439
709
 
440
- // src/react/ui/SignaturePad.tsx
441
-
442
-
443
- function SignaturePad({
444
- onSave,
445
- onCancel,
446
- maxWidth = 600
447
- }) {
448
- const canvas = _react.useRef.call(void 0, null);
449
- const last = _react.useRef.call(void 0, null);
450
- const [empty, setEmpty] = _react.useState.call(void 0, true);
451
- const point = (e) => {
452
- const r = e.currentTarget.getBoundingClientRect();
453
- return {
454
- x: (e.clientX - r.left) / r.width * e.currentTarget.width,
455
- y: (e.clientY - r.top) / r.height * e.currentTarget.height
456
- };
457
- };
458
- const draw = (e) => {
459
- const ctx = _optionalChain([canvas, 'access', _2 => _2.current, 'optionalAccess', _3 => _3.getContext, 'call', _4 => _4("2d")]);
460
- if (!ctx || !last.current) return;
461
- const p = point(e);
462
- ctx.lineWidth = 3;
463
- ctx.lineCap = "round";
464
- ctx.strokeStyle = "#111827";
465
- ctx.beginPath();
466
- ctx.moveTo(last.current.x, last.current.y);
467
- ctx.lineTo(p.x, p.y);
468
- ctx.stroke();
469
- last.current = p;
470
- setEmpty(false);
471
- };
472
- const clear = () => {
473
- const c = canvas.current;
474
- _optionalChain([c, 'optionalAccess', _5 => _5.getContext, 'call', _6 => _6("2d"), 'optionalAccess', _7 => _7.clearRect, 'call', _8 => _8(0, 0, c.width, c.height)]);
475
- setEmpty(true);
476
- };
477
- const save = () => {
478
- const c = canvas.current;
479
- if (!c) return;
480
- const scale = Math.min(1, maxWidth / c.width);
481
- const out = document.createElement("canvas");
482
- out.width = Math.round(c.width * scale);
483
- out.height = Math.round(c.height * scale);
484
- _optionalChain([out, 'access', _9 => _9.getContext, 'call', _10 => _10("2d"), 'optionalAccess', _11 => _11.drawImage, 'call', _12 => _12(c, 0, 0, out.width, out.height)]);
485
- onSave(out.toDataURL("image/png"));
486
- };
487
- return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "space-y-3", children: [
488
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
489
- "canvas",
490
- {
491
- ref: canvas,
492
- width: 800,
493
- height: 260,
494
- "aria-label": "Signature drawing area",
495
- className: "h-[200px] w-full touch-none rounded-md border border-dashed border-line-strong bg-surface",
496
- onPointerDown: (e) => {
497
- e.currentTarget.setPointerCapture(e.pointerId);
498
- last.current = point(e);
499
- },
500
- onPointerMove: draw,
501
- onPointerUp: () => last.current = null
502
- }
503
- ),
504
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex justify-end gap-2", children: [
505
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Button, { variant: "secondary", onClick: clear, children: "Clear" }),
506
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Button, { variant: "secondary", onClick: onCancel, children: "Cancel" }),
507
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Button, { disabled: empty, onClick: save, children: "Use signature" })
508
- ] })
509
- ] });
510
- }
511
-
512
- // src/react/components/FieldControl.tsx
513
-
514
710
  var box = "h-full w-full rounded-sm border bg-primary-soft/70 px-1 text-[clamp(8px,62cqh,15px)] text-navy outline-none focus:border-primary focus:bg-white disabled:cursor-not-allowed";
515
711
  function pngFile(dataUrl, name) {
516
712
  const bin = atob(dataUrl.slice(dataUrl.indexOf(",") + 1));
@@ -616,14 +812,14 @@ function FieldControl({
616
812
  children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: `min-w-0 ${field.type === "textarea" ? "line-clamp-[8] whitespace-pre-wrap" : "truncate"}`, children: text || /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-faint", children: field.placeholder || "" }) })
617
813
  }
618
814
  ),
619
- editing && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, Modal, { onClose: () => setEditing(false), width: "w-[480px]", children: [
620
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ModalHeader, { title: name, onClose: () => setEditing(false) }),
621
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, ModalBody, { children: [
815
+ editing && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, Modal2, { onClose: () => setEditing(false), width: "w-[480px]", children: [
816
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ModalHeader2, { title: name, onClose: () => setEditing(false) }),
817
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, ModalBody2, { children: [
622
818
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, SheetInput, { field, text, onChange, onDone: () => setEditing(false) }),
623
819
  field.helpText && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "mt-2 mb-0 text-[13px] text-muted", children: field.helpText }),
624
820
  error && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "mt-2 mb-0 text-[13px] text-danger", children: error })
625
821
  ] }),
626
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ModalFooter, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Button, { onClick: () => setEditing(false), children: "Done" }) })
822
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ModalFooter2, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Button2, { onClick: () => setEditing(false), children: "Done" }) })
627
823
  ] })
628
824
  ] });
629
825
  }
@@ -707,10 +903,10 @@ function FieldControl({
707
903
  ] })
708
904
  }
709
905
  ),
710
- signing && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, Modal, { onClose: () => setSigning(false), width: "w-[640px]", children: [
711
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ModalHeader, { title: `Sign: ${field.label || field.key}`, onClose: () => setSigning(false) }),
712
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ModalBody, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
713
- SignaturePad,
906
+ signing && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, Modal2, { onClose: () => setSigning(false), width: "w-[640px]", children: [
907
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ModalHeader2, { title: `Sign: ${field.label || field.key}`, onClose: () => setSigning(false) }),
908
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ModalBody2, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
909
+ SignaturePad2,
714
910
  {
715
911
  onCancel: () => setSigning(false),
716
912
  onSave: (url) => {
@@ -780,6 +976,10 @@ function FieldControl({
780
976
  }
781
977
  }
782
978
  }
979
+ function AnswerControl({ components, ...props }) {
980
+ const C = _nullishCoalesce(_nullishCoalesce(_optionalChain([components, 'optionalAccess', _20 => _20.fields, 'optionalAccess', _21 => _21[props.field.type]]), () => ( _optionalChain([components, 'optionalAccess', _22 => _22.FieldControl]))), () => ( FieldControl));
981
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, C, { ...props });
982
+ }
783
983
 
784
984
  // src/react/components/FieldProperties.tsx
785
985
 
@@ -825,12 +1025,12 @@ function ConditionBuilder({
825
1025
  }) {
826
1026
  const setRule = (i, r) => onChange({ ...value, rules: value.rules.map((x, j) => j === i ? r : x) });
827
1027
  const remove = (i) => onChange({ ...value, rules: value.rules.filter((_, j) => j !== i) });
828
- const newRule = () => ({ fieldKey: _nullishCoalesce(_optionalChain([fields, 'access', _20 => _20[0], 'optionalAccess', _21 => _21.key]), () => ( "")), op: "equals", value: "" });
1028
+ const newRule = () => ({ fieldKey: _nullishCoalesce(_optionalChain([fields, 'access', _23 => _23[0], 'optionalAccess', _24 => _24.key]), () => ( "")), op: "equals", value: "" });
829
1029
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: `space-y-2 ${depth ? "rounded-md border border-line bg-surface p-2" : ""}`, children: [
830
1030
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex items-center gap-2 text-[12px]", children: [
831
1031
  "Match",
832
1032
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
833
- Select,
1033
+ Select2,
834
1034
  {
835
1035
  "aria-label": "Match all or any",
836
1036
  value: value.logic,
@@ -845,10 +1045,10 @@ function ConditionBuilder({
845
1045
  value.rules.map(
846
1046
  (r, i) => isGroup(r) ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex items-start gap-1", children: [
847
1047
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex-1", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ConditionBuilder, { value: r, onChange: (c) => setRule(i, c), fields, depth: depth + 1 }) }),
848
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, IconButton, { icon: _lucidereact.X, title: "Remove group", danger: true, iconSize: 14, onClick: () => remove(i) })
1048
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, IconButton2, { icon: _lucidereact.X, title: "Remove group", danger: true, iconSize: 14, onClick: () => remove(i) })
849
1049
  ] }, i) : /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-wrap items-center gap-1", children: [
850
1050
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
851
- Select,
1051
+ Select2,
852
1052
  {
853
1053
  "aria-label": "Field",
854
1054
  value: r.fieldKey,
@@ -860,7 +1060,7 @@ function ConditionBuilder({
860
1060
  }
861
1061
  ),
862
1062
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
863
- Select,
1063
+ Select2,
864
1064
  {
865
1065
  "aria-label": "Operator",
866
1066
  value: r.op,
@@ -869,7 +1069,7 @@ function ConditionBuilder({
869
1069
  }
870
1070
  ),
871
1071
  r.op !== "isEmpty" && r.op !== "isNotEmpty" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
872
- TextInput,
1072
+ TextInput2,
873
1073
  {
874
1074
  "aria-label": "Value",
875
1075
  className: "!w-24 !py-1",
@@ -878,7 +1078,7 @@ function ConditionBuilder({
878
1078
  }
879
1079
  ),
880
1080
  r.op === "between" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
881
- TextInput,
1081
+ TextInput2,
882
1082
  {
883
1083
  "aria-label": "Upper value",
884
1084
  className: "!w-24 !py-1",
@@ -886,12 +1086,12 @@ function ConditionBuilder({
886
1086
  onChange: (e) => setRule(i, { ...r, value2: e.target.value })
887
1087
  }
888
1088
  ),
889
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, IconButton, { icon: _lucidereact.X, title: "Remove rule", danger: true, iconSize: 14, onClick: () => remove(i) })
1089
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, IconButton2, { icon: _lucidereact.X, title: "Remove rule", danger: true, iconSize: 14, onClick: () => remove(i) })
890
1090
  ] }, i)
891
1091
  ),
892
1092
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex gap-2", children: [
893
1093
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
894
- Button,
1094
+ Button2,
895
1095
  {
896
1096
  size: "sm",
897
1097
  variant: "secondary",
@@ -902,7 +1102,7 @@ function ConditionBuilder({
902
1102
  }
903
1103
  ),
904
1104
  depth < 2 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
905
- Button,
1105
+ Button2,
906
1106
  {
907
1107
  size: "sm",
908
1108
  variant: "secondary",
@@ -942,7 +1142,7 @@ function FieldProperties({
942
1142
  const textual = !["checkbox", "file", "signature", "dropdown", "radio"].includes(field.type);
943
1143
  const setPos = (k, v) => {
944
1144
  const n = num2(v);
945
- if (n != null) set({ position: _chunk5VHPTLLVcjs.fitInPage.call(void 0, { ...field.position, [k]: n / 100 }) });
1145
+ if (n != null) set({ position: _chunk33XWO4KBcjs.fitInPage.call(void 0, { ...field.position, [k]: n / 100 }) });
946
1146
  };
947
1147
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "text-[13px]", children: [
948
1148
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, Section2, { title: "Field", children: [
@@ -955,38 +1155,38 @@ function FieldProperties({
955
1155
  "ID ",
956
1156
  field.id
957
1157
  ] }),
958
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, FormField, { label: "Label", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TextInput, { value: field.label, onChange: (e) => set({ label: e.target.value }) }) }),
959
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, FormField, { label: "Key (automatic, from the label)", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TextInput, { value: field.key, readOnly: true, className: "text-faint" }) }),
960
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, FormField, { label: "Type", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Select, { className: "w-full", value: field.type, onChange: (e) => set({ type: e.target.value }), children: _chunk7NZPYWL3cjs.FIELD_TYPES.map((t) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "option", { value: t, children: TYPE_LABEL[t] }, t)) }) }),
961
- textual && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, FormField, { label: "Placeholder", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
962
- TextInput,
1158
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, FormField2, { label: "Label", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TextInput2, { value: field.label, onChange: (e) => set({ label: e.target.value }) }) }),
1159
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, FormField2, { label: "Key (automatic, from the label)", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TextInput2, { value: field.key, readOnly: true, className: "text-faint" }) }),
1160
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, FormField2, { label: "Type", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Select2, { className: "w-full", value: field.type, onChange: (e) => set({ type: e.target.value }), children: _chunk7NZPYWL3cjs.FIELD_TYPES.map((t) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "option", { value: t, children: TYPE_LABEL[t] }, t)) }) }),
1161
+ textual && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, FormField2, { label: "Placeholder", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1162
+ TextInput2,
963
1163
  {
964
1164
  value: _nullishCoalesce(field.placeholder, () => ( "")),
965
1165
  onChange: (e) => set({ placeholder: e.target.value || void 0 })
966
1166
  }
967
1167
  ) }),
968
- field.type !== "file" && field.type !== "signature" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, FormField, { label: field.type === "checkbox" ? "Checked by default" : "Default value", children: field.type === "checkbox" ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
969
- Checkbox,
1168
+ field.type !== "file" && field.type !== "signature" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, FormField2, { label: field.type === "checkbox" ? "Checked by default" : "Default value", children: field.type === "checkbox" ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1169
+ Checkbox2,
970
1170
  {
971
1171
  label: "Checked by default",
972
1172
  checked: field.defaultValue === "true",
973
1173
  onChange: (e) => set({ defaultValue: e.target.checked ? "true" : void 0 })
974
1174
  }
975
1175
  ) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
976
- TextInput,
1176
+ TextInput2,
977
1177
  {
978
1178
  value: _nullishCoalesce(field.defaultValue, () => ( "")),
979
1179
  onChange: (e) => set({ defaultValue: e.target.value || void 0 })
980
1180
  }
981
1181
  ) }),
982
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, FormField, { label: "Help text (shown as tooltip)", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TextInput, { value: _nullishCoalesce(field.helpText, () => ( "")), onChange: (e) => set({ helpText: e.target.value || void 0 }) }) }),
1182
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, FormField2, { label: "Help text (shown as tooltip)", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TextInput2, { value: _nullishCoalesce(field.helpText, () => ( "")), onChange: (e) => set({ helpText: e.target.value || void 0 }) }) }),
983
1183
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex flex-wrap gap-4", children: ["required", "readOnly", "hidden"].map((k) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "label", { className: "inline-flex items-center gap-1.5", children: [
984
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Checkbox, { label: k, checked: !!field[k], onChange: (e) => set({ [k]: e.target.checked || void 0 }) }),
1184
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Checkbox2, { label: k, checked: !!field[k], onChange: (e) => set({ [k]: e.target.checked || void 0 }) }),
985
1185
  { required: "Required", readOnly: "Read-only", hidden: "Hidden" }[k]
986
1186
  ] }, k)) })
987
1187
  ] }),
988
1188
  hasOptions && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Section2, { title: "Options (one per line)", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
989
- TextArea,
1189
+ TextArea2,
990
1190
  {
991
1191
  rows: 4,
992
1192
  value: optionsText,
@@ -1004,8 +1204,8 @@ function FieldProperties({
1004
1204
  ) }),
1005
1205
  textual && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, Section2, { title: "Validation", children: [
1006
1206
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "grid grid-cols-2 gap-2", children: [
1007
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, FormField, { label: "Min length", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1008
- TextInput,
1207
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, FormField2, { label: "Min length", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1208
+ TextInput2,
1009
1209
  {
1010
1210
  type: "number",
1011
1211
  min: 0,
@@ -1013,8 +1213,8 @@ function FieldProperties({
1013
1213
  onChange: (e) => set({ minLength: num2(e.target.value) })
1014
1214
  }
1015
1215
  ) }),
1016
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, FormField, { label: "Max length", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1017
- TextInput,
1216
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, FormField2, { label: "Max length", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1217
+ TextInput2,
1018
1218
  {
1019
1219
  type: "number",
1020
1220
  min: 0,
@@ -1023,16 +1223,16 @@ function FieldProperties({
1023
1223
  }
1024
1224
  ) }),
1025
1225
  field.type === "number" && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
1026
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, FormField, { label: "Min value", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1027
- TextInput,
1226
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, FormField2, { label: "Min value", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1227
+ TextInput2,
1028
1228
  {
1029
1229
  type: "number",
1030
1230
  value: _nullishCoalesce(field.min, () => ( "")),
1031
1231
  onChange: (e) => set({ min: num2(e.target.value) })
1032
1232
  }
1033
1233
  ) }),
1034
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, FormField, { label: "Max value", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1035
- TextInput,
1234
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, FormField2, { label: "Max value", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1235
+ TextInput2,
1036
1236
  {
1037
1237
  type: "number",
1038
1238
  value: _nullishCoalesce(field.max, () => ( "")),
@@ -1041,8 +1241,8 @@ function FieldProperties({
1041
1241
  ) })
1042
1242
  ] })
1043
1243
  ] }),
1044
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, FormField, { label: "Regex (whole value must match)", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1045
- TextInput,
1244
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, FormField2, { label: "Regex (whole value must match)", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1245
+ TextInput2,
1046
1246
  {
1047
1247
  className: "font-mono",
1048
1248
  value: _nullishCoalesce(field.pattern, () => ( "")),
@@ -1071,8 +1271,8 @@ function FieldProperties({
1071
1271
  ) }, key);
1072
1272
  }),
1073
1273
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Section2, { title: "Position (% of page)", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "grid grid-cols-2 gap-2", children: [
1074
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, FormField, { label: "Page", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1075
- TextInput,
1274
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, FormField2, { label: "Page", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1275
+ TextInput2,
1076
1276
  {
1077
1277
  type: "number",
1078
1278
  min: 1,
@@ -1086,8 +1286,8 @@ function FieldProperties({
1086
1286
  }
1087
1287
  ) }),
1088
1288
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", {}),
1089
- ["x", "y", "width", "height"].map((k) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, FormField, { label: { x: "Left", y: "Top", width: "Width", height: "Height" }[k], children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1090
- TextInput,
1289
+ ["x", "y", "width", "height"].map((k) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, FormField2, { label: { x: "Left", y: "Top", width: "Width", height: "Height" }[k], children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1290
+ TextInput2,
1091
1291
  {
1092
1292
  type: "number",
1093
1293
  step: 0.1,
@@ -1114,9 +1314,9 @@ function LayoutElementView({
1114
1314
  style
1115
1315
  }) {
1116
1316
  const stroke = ptToCqh(_nullishCoalesce(e.strokeWidth, () => ( 1)), pageHeight);
1117
- const base = { ..._chunk5VHPTLLVcjs.boxStyle.call(void 0, { page: e.page, ...e.position }), ...style };
1317
+ const base2 = { ..._chunk33XWO4KBcjs.boxStyle.call(void 0, { page: e.page, ...e.position }), ...style };
1118
1318
  if (e.type === "line")
1119
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { className: `absolute overflow-visible ${className}`, style: base, "aria-hidden": true, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1319
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { className: `absolute overflow-visible ${className}`, style: base2, "aria-hidden": true, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1120
1320
  "line",
1121
1321
  {
1122
1322
  x1: "0",
@@ -1132,7 +1332,7 @@ function LayoutElementView({
1132
1332
  {
1133
1333
  className: `absolute overflow-hidden whitespace-pre-wrap ${className}`,
1134
1334
  style: {
1135
- ...base,
1335
+ ...base2,
1136
1336
  background: e.fill,
1137
1337
  border: e.type === "box" && e.stroke ? `${stroke} solid ${e.stroke}` : void 0,
1138
1338
  color: _nullishCoalesce(e.color, () => ( "#000000")),
@@ -1198,7 +1398,7 @@ function PagesPanel({
1198
1398
  }
1199
1399
  ),
1200
1400
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1201
- IconButton,
1401
+ IconButton2,
1202
1402
  {
1203
1403
  icon: _lucidereact.ArrowUp,
1204
1404
  title: "Move page up",
@@ -1208,7 +1408,7 @@ function PagesPanel({
1208
1408
  }
1209
1409
  ),
1210
1410
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1211
- IconButton,
1411
+ IconButton2,
1212
1412
  {
1213
1413
  icon: _lucidereact.ArrowDown,
1214
1414
  title: "Move page down",
@@ -1218,7 +1418,7 @@ function PagesPanel({
1218
1418
  }
1219
1419
  ),
1220
1420
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1221
- IconButton,
1421
+ IconButton2,
1222
1422
  {
1223
1423
  icon: _lucidereact.FilePlus2,
1224
1424
  title: "Add blank page after",
@@ -1227,7 +1427,7 @@ function PagesPanel({
1227
1427
  }
1228
1428
  ),
1229
1429
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1230
- IconButton,
1430
+ IconButton2,
1231
1431
  {
1232
1432
  icon: _lucidereact.Trash2,
1233
1433
  title: "Delete page",
@@ -1302,11 +1502,11 @@ function PdfPages({
1302
1502
  if (!live) return;
1303
1503
  setSizes(list);
1304
1504
  setDoc(pdf);
1305
- _optionalChain([callbacks, 'access', _22 => _22.current, 'access', _23 => _23.onLoaded, 'optionalCall', _24 => _24(list, pdf)]);
1306
- }).catch((err) => live && _optionalChain([callbacks, 'access', _25 => _25.current, 'access', _26 => _26.onError, 'optionalCall', _27 => _27(err)]));
1505
+ _optionalChain([callbacks, 'access', _25 => _25.current, 'access', _26 => _26.onLoaded, 'optionalCall', _27 => _27(list, pdf)]);
1506
+ }).catch((err) => live && _optionalChain([callbacks, 'access', _28 => _28.current, 'access', _29 => _29.onError, 'optionalCall', _30 => _30(err)]));
1307
1507
  return () => {
1308
1508
  live = false;
1309
- void _optionalChain([opened, 'optionalAccess', _28 => _28.destroy, 'call', _29 => _29()]);
1509
+ void _optionalChain([opened, 'optionalAccess', _31 => _31.destroy, 'call', _32 => _32()]);
1310
1510
  };
1311
1511
  }, []);
1312
1512
  if (!doc) return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "p-6 text-center text-[13px] text-muted", children: "Loading document\u2026" });
@@ -1367,22 +1567,22 @@ function PdfPage({
1367
1567
  });
1368
1568
  return () => {
1369
1569
  live = false;
1370
- _optionalChain([task, 'optionalAccess', _30 => _30.cancel, 'call', _31 => _31()]);
1570
+ _optionalChain([task, 'optionalAccess', _33 => _33.cancel, 'call', _34 => _34()]);
1371
1571
  };
1372
1572
  }, [doc, source, visible, zoom]);
1373
1573
  _react.useEffect.call(void 0, () => {
1374
- if (!withText || !visible || !source || _optionalChain([lines, 'optionalAccess', _32 => _32.source]) === source) return;
1574
+ if (!withText || !visible || !source || _optionalChain([lines, 'optionalAccess', _35 => _35.source]) === source) return;
1375
1575
  let live = true;
1376
1576
  void doc.getPage(source).then(async (page) => {
1377
1577
  const content = await page.getTextContent();
1378
1578
  const fontOf = (id) => {
1379
1579
  try {
1380
- return page.commonObjs.has(id) ? _optionalChain([page, 'access', _33 => _33.commonObjs, 'access', _34 => _34.get, 'call', _35 => _35(id), 'optionalAccess', _36 => _36.name]) : void 0;
1580
+ return page.commonObjs.has(id) ? _optionalChain([page, 'access', _36 => _36.commonObjs, 'access', _37 => _37.get, 'call', _38 => _38(id), 'optionalAccess', _39 => _39.name]) : void 0;
1381
1581
  } catch (e2) {
1382
1582
  return void 0;
1383
1583
  }
1384
1584
  };
1385
- if (live) setLines({ source, lines: _chunk5VHPTLLVcjs.toLines.call(void 0, content.items, page.view, fontOf) });
1585
+ if (live) setLines({ source, lines: _chunk33XWO4KBcjs.toLines.call(void 0, content.items, page.view, fontOf) });
1386
1586
  }).catch(() => live && setLines({ source, lines: [] }));
1387
1587
  return () => {
1388
1588
  live = false;
@@ -1397,7 +1597,7 @@ function PdfPage({
1397
1597
  style: { width, height },
1398
1598
  children: [
1399
1599
  source && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "canvas", { ref: canvas, className: "absolute inset-0 h-full w-full", "aria-label": `Page ${pageNo}` }),
1400
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "absolute inset-0 [container-type:size]", children: _optionalChain([overlay, 'optionalCall', _37 => _37(pageNo, withText && _optionalChain([lines, 'optionalAccess', _38 => _38.source]) === source ? lines.lines : void 0)]) })
1600
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "absolute inset-0 [container-type:size]", children: _optionalChain([overlay, 'optionalCall', _40 => _40(pageNo, withText && _optionalChain([lines, 'optionalAccess', _41 => _41.source]) === source ? lines.lines : void 0)]) })
1401
1601
  ]
1402
1602
  }
1403
1603
  );
@@ -1410,12 +1610,12 @@ function ZoomControls({ zoom, onChange }) {
1410
1610
  const lower = [...ZOOMS].reverse().find((z) => z < zoom - 0.01);
1411
1611
  const higher = ZOOMS.find((z) => z > zoom + 0.01);
1412
1612
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "inline-flex items-center gap-1 text-[13px]", children: [
1413
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, IconButton, { icon: _lucidereact.Minus, title: "Zoom out", disabled: lower == null, onClick: () => onChange(lower) }),
1613
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, IconButton2, { icon: _lucidereact.Minus, title: "Zoom out", disabled: lower == null, onClick: () => onChange(lower) }),
1414
1614
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { className: "w-12 text-center tabular-nums", children: [
1415
1615
  Math.round(zoom * 100),
1416
1616
  "%"
1417
1617
  ] }),
1418
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, IconButton, { icon: _lucidereact.Plus, title: "Zoom in", disabled: higher == null, onClick: () => onChange(higher) })
1618
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, IconButton2, { icon: _lucidereact.Plus, title: "Zoom in", disabled: higher == null, onClick: () => onChange(higher) })
1419
1619
  ] });
1420
1620
  }
1421
1621
 
@@ -1442,10 +1642,10 @@ function useFitZoom(pageWidthPt) {
1442
1642
  }
1443
1643
  function useCompact() {
1444
1644
  const query = "(max-width: 767px), (pointer: coarse)";
1445
- const get = () => typeof window !== "undefined" && !!_optionalChain([window, 'access', _39 => _39.matchMedia, 'optionalCall', _40 => _40(query), 'access', _41 => _41.matches]);
1645
+ const get = () => typeof window !== "undefined" && !!_optionalChain([window, 'access', _42 => _42.matchMedia, 'optionalCall', _43 => _43(query), 'access', _44 => _44.matches]);
1446
1646
  const [compact, setCompact] = _react.useState.call(void 0, get);
1447
1647
  _react.useEffect.call(void 0, () => {
1448
- const m = _optionalChain([window, 'access', _42 => _42.matchMedia, 'optionalCall', _43 => _43(query)]);
1648
+ const m = _optionalChain([window, 'access', _45 => _45.matchMedia, 'optionalCall', _46 => _46(query)]);
1449
1649
  if (!m) return;
1450
1650
  const on = () => setCompact(m.matches);
1451
1651
  m.addEventListener("change", on);
@@ -1454,6 +1654,9 @@ function useCompact() {
1454
1654
  return compact;
1455
1655
  }
1456
1656
 
1657
+ // src/react/hooks/useFormEditor.ts
1658
+
1659
+
1457
1660
  // src/react/hooks/useUndo.ts
1458
1661
 
1459
1662
  var LIMIT = 100;
@@ -1495,57 +1698,45 @@ function useUndo(initial) {
1495
1698
  };
1496
1699
  }
1497
1700
 
1498
- // src/react/FormEditor.tsx
1499
-
1701
+ // src/react/hooks/useFormEditor.ts
1500
1702
  var GRID = 5e-3;
1501
- var DRAG_TYPE = "application/x-doc-item";
1502
1703
  var EMPTY = { fields: [], layout: null };
1503
1704
  var isDefault = (l, sizes2) => !l.elements.length && l.pages.length === sizes2.length && l.pages.every((p, i) => p.source === i + 1);
1504
- function FormEditor({
1505
- pdf: pdfSource,
1705
+ function useFormEditor({
1506
1706
  initialValue = EMPTY,
1507
1707
  onSave,
1508
1708
  onChange,
1509
- title,
1510
- onBack,
1511
- toolbar,
1512
- banner,
1513
- tabs = [],
1514
1709
  autoDetect,
1710
+ onDetected,
1711
+ keyboard = true,
1712
+ warnUnsaved = true,
1713
+ fieldTypes = _chunk7NZPYWL3cjs.FIELD_TYPES,
1714
+ elementTools = Object.keys(_chunk33XWO4KBcjs.ELEMENT_TOOLS),
1515
1715
  notify = () => {
1516
1716
  },
1517
- onError: notifyError = (e) => console.error(e),
1518
- className = "h-full",
1519
- ref
1717
+ onError: notifyError = (e) => console.error(e)
1520
1718
  }) {
1521
1719
  const [sizes2, setSizes] = _react.useState.call(void 0, null);
1522
1720
  const history = useUndo(initialValue);
1523
1721
  const { value: doc, set } = history;
1524
1722
  const [saved, setSaved] = _react.useState.call(void 0, initialValue);
1525
1723
  const [selection, setSelection] = _react.useState.call(void 0, null);
1526
- const [tab, setTab] = _react.useState.call(void 0, "props");
1527
- const [drawer, setDrawer] = _react.useState.call(void 0, null);
1528
1724
  const [armed, setArmed] = _react.useState.call(void 0, null);
1529
- const compact = useCompact();
1530
1725
  const [snapOn, setSnapOn] = _react.useState.call(void 0, true);
1531
1726
  const [editText, setEditText] = _react.useState.call(void 0, false);
1532
- const [preview, setPreview] = _react.useState.call(void 0, false);
1727
+ const [preview, setPreviewState] = _react.useState.call(void 0, false);
1533
1728
  const [previewAnswers, setPreviewAnswers] = _react.useState.call(void 0, {});
1534
1729
  const [busy, setBusy] = _react.useState.call(void 0, false);
1535
- const [confirmDeletePage, setConfirmDeletePage] = _react.useState.call(void 0, null);
1536
- const [loadError, setLoadError] = _react.useState.call(void 0, "");
1537
1730
  const [pdf, setPdf] = _react.useState.call(void 0, null);
1538
1731
  const [detecting, setDetecting] = _react.useState.call(void 0, null);
1539
1732
  const autoDetected = _react.useRef.call(void 0, false);
1540
1733
  const drag = _react.useRef.call(void 0, null);
1541
- const scroller = _react.useRef.call(void 0, null);
1542
- const { zoom, setZoom, ref: fitRef } = useFitZoom(Math.max(...(_nullishCoalesce(sizes2, () => ( [{ width: 595 }]))).map((p) => p.width)));
1543
1734
  const { fields } = doc;
1544
1735
  const layout = _nullishCoalesce(doc.layout, () => ( (sizes2 ? _chunk7NZPYWL3cjs.defaultLayout.call(void 0, sizes2) : null)));
1545
- const pageCount = _nullishCoalesce(_optionalChain([layout, 'optionalAccess', _44 => _44.pages, 'access', _45 => _45.length]), () => ( 1));
1736
+ const pageCount = _nullishCoalesce(_optionalChain([layout, 'optionalAccess', _47 => _47.pages, 'access', _48 => _48.length]), () => ( 1));
1546
1737
  const grid = snapOn ? GRID : 0;
1547
- const selectedField = _optionalChain([selection, 'optionalAccess', _46 => _46.kind]) === "field" ? _nullishCoalesce(fields.find((f) => f.id === selection.id), () => ( null)) : null;
1548
- const selectedElement = _optionalChain([selection, 'optionalAccess', _47 => _47.kind]) === "element" ? _nullishCoalesce(_optionalChain([layout, 'optionalAccess', _48 => _48.elements, 'access', _49 => _49.find, 'call', _50 => _50((e) => e.id === selection.id)]), () => ( null)) : null;
1738
+ const selectedField = _optionalChain([selection, 'optionalAccess', _49 => _49.kind]) === "field" ? _nullishCoalesce(fields.find((f) => f.id === selection.id), () => ( null)) : null;
1739
+ const selectedElement = _optionalChain([selection, 'optionalAccess', _50 => _50.kind]) === "element" ? _nullishCoalesce(_optionalChain([layout, 'optionalAccess', _51 => _51.elements, 'access', _52 => _52.find, 'call', _53 => _53((e) => e.id === selection.id)]), () => ( null)) : null;
1549
1740
  const dirty = JSON.stringify(doc) !== JSON.stringify(saved);
1550
1741
  const problems = _react.useMemo.call(void 0,
1551
1742
  () => sizes2 ? [...doc.layout ? _chunk7NZPYWL3cjs.validateLayout.call(void 0, doc.layout, sizes2.length) : [], ..._chunk7NZPYWL3cjs.validateFields.call(void 0, fields, pageCount)] : [],
@@ -1558,13 +1749,13 @@ function FormEditor({
1558
1749
  const first = _react.useRef.call(void 0, true);
1559
1750
  _react.useEffect.call(void 0, () => {
1560
1751
  if (first.current) first.current = false;
1561
- else _optionalChain([onChangeRef, 'access', _51 => _51.current, 'optionalCall', _52 => _52(doc)]);
1752
+ else _optionalChain([onChangeRef, 'access', _54 => _54.current, 'optionalCall', _55 => _55(doc)]);
1562
1753
  }, [doc]);
1563
1754
  const withDoc = _react.useCallback.call(void 0,
1564
1755
  (fn, record = true) => set((cur) => {
1565
- const base = _nullishCoalesce(cur.layout, () => ( (sizes2 ? _chunk7NZPYWL3cjs.defaultLayout.call(void 0, sizes2) : null)));
1566
- if (!base) return cur;
1567
- return fn({ fields: cur.fields, layout: base });
1756
+ const base2 = _nullishCoalesce(cur.layout, () => ( (sizes2 ? _chunk7NZPYWL3cjs.defaultLayout.call(void 0, sizes2) : null)));
1757
+ if (!base2) return cur;
1758
+ return fn({ fields: cur.fields, layout: base2 });
1568
1759
  }, record),
1569
1760
  [set, sizes2]
1570
1761
  );
@@ -1576,15 +1767,11 @@ function FormEditor({
1576
1767
  (fn, record = true) => withDoc((d) => ({ ...d, layout: { ...d.layout, elements: fn(d.layout.elements) } }), record),
1577
1768
  [withDoc]
1578
1769
  );
1579
- const select = (s) => {
1580
- setSelection(s);
1581
- if (s) setTab("props");
1582
- };
1583
- const updateField = _react.useCallback.call(void 0, (f) => setFields((l) => _chunk5VHPTLLVcjs.withField.call(void 0, l, f)), [setFields]);
1770
+ const updateField = _react.useCallback.call(void 0, (f) => setFields((l) => _chunk33XWO4KBcjs.withField.call(void 0, l, f)), [setFields]);
1584
1771
  const updateElement = _react.useCallback.call(void 0,
1585
1772
  (e) => {
1586
- const pageWidth = _nullishCoalesce(_optionalChain([layout, 'optionalAccess', _53 => _53.pages, 'access', _54 => _54[e.page - 1], 'optionalAccess', _55 => _55.width]), () => ( 595));
1587
- setElements((l) => l.map((x) => x.id === e.id ? _chunk5VHPTLLVcjs.fitTextWidth.call(void 0, e, pageWidth) : x));
1773
+ const pageWidth = _nullishCoalesce(_optionalChain([layout, 'optionalAccess', _56 => _56.pages, 'access', _57 => _57[e.page - 1], 'optionalAccess', _58 => _58.width]), () => ( 595));
1774
+ setElements((l) => l.map((x) => x.id === e.id ? _chunk33XWO4KBcjs.fitTextWidth.call(void 0, e, pageWidth) : x));
1588
1775
  },
1589
1776
  [setElements, layout]
1590
1777
  );
@@ -1596,16 +1783,28 @@ function FormEditor({
1596
1783
  }, [selection, setFields, setElements]);
1597
1784
  const duplicateSelected = _react.useCallback.call(void 0, () => {
1598
1785
  if (selectedField) {
1599
- const copy = _chunk5VHPTLLVcjs.duplicate.call(void 0, selectedField, fields);
1786
+ const copy = _chunk33XWO4KBcjs.duplicate.call(void 0, selectedField, fields);
1600
1787
  setFields((l) => [...l, copy]);
1601
1788
  setSelection({ kind: "field", id: copy.id });
1602
1789
  } else if (selectedElement) {
1603
- const copy = _chunk5VHPTLLVcjs.duplicateElement.call(void 0, selectedElement);
1790
+ const copy = _chunk33XWO4KBcjs.duplicateElement.call(void 0, selectedElement);
1604
1791
  setElements((l) => [...l, copy]);
1605
1792
  setSelection({ kind: "element", id: copy.id });
1606
1793
  }
1607
1794
  }, [selectedField, selectedElement, fields, setFields, setElements]);
1795
+ const nudge = _react.useCallback.call(void 0,
1796
+ (dx, dy) => {
1797
+ if (selectedField) updateField({ ...selectedField, position: _chunk33XWO4KBcjs.moveBy.call(void 0, selectedField.position, dx, dy) });
1798
+ if (selectedElement) {
1799
+ const { page: _p, ...position } = _chunk33XWO4KBcjs.moveBy.call(void 0, { page: selectedElement.page, ...selectedElement.position }, dx, dy);
1800
+ void _p;
1801
+ updateElement({ ...selectedElement, position });
1802
+ }
1803
+ },
1804
+ [selectedField, selectedElement, updateField, updateElement]
1805
+ );
1608
1806
  _react.useEffect.call(void 0, () => {
1807
+ if (!keyboard) return;
1609
1808
  const onKey = (e) => {
1610
1809
  const t = e.target;
1611
1810
  if (preview || t.closest("input, textarea, select, [contenteditable]")) return;
@@ -1627,42 +1826,27 @@ function FormEditor({
1627
1826
  else if (e.key.startsWith("Arrow")) {
1628
1827
  e.preventDefault();
1629
1828
  const step = e.shiftKey ? 0.01 : 2e-3;
1630
- const dx = e.key === "ArrowLeft" ? -step : e.key === "ArrowRight" ? step : 0;
1631
- const dy = e.key === "ArrowUp" ? -step : e.key === "ArrowDown" ? step : 0;
1632
- if (selectedField) updateField({ ...selectedField, position: _chunk5VHPTLLVcjs.moveBy.call(void 0, selectedField.position, dx, dy) });
1633
- if (selectedElement) {
1634
- const { page: _p, ...position } = _chunk5VHPTLLVcjs.moveBy.call(void 0, { page: selectedElement.page, ...selectedElement.position }, dx, dy);
1635
- void _p;
1636
- updateElement({ ...selectedElement, position });
1637
- }
1829
+ nudge(
1830
+ e.key === "ArrowLeft" ? -step : e.key === "ArrowRight" ? step : 0,
1831
+ e.key === "ArrowUp" ? -step : e.key === "ArrowDown" ? step : 0
1832
+ );
1638
1833
  }
1639
1834
  };
1640
1835
  window.addEventListener("keydown", onKey);
1641
1836
  return () => window.removeEventListener("keydown", onKey);
1642
- }, [
1643
- preview,
1644
- armed,
1645
- selection,
1646
- selectedField,
1647
- selectedElement,
1648
- history,
1649
- removeSelected,
1650
- duplicateSelected,
1651
- updateField,
1652
- updateElement
1653
- ]);
1837
+ }, [keyboard, preview, armed, selection, history, removeSelected, duplicateSelected, nudge]);
1654
1838
  _react.useEffect.call(void 0, () => {
1655
- if (!dirty) return;
1839
+ if (!dirty || !warnUnsaved) return;
1656
1840
  const warn = (e) => e.preventDefault();
1657
1841
  window.addEventListener("beforeunload", warn);
1658
1842
  return () => window.removeEventListener("beforeunload", warn);
1659
- }, [dirty]);
1843
+ }, [dirty, warnUnsaved]);
1660
1844
  function startDrag(e, sel, start, mode) {
1661
1845
  if (e.button !== 0) return;
1662
1846
  e.stopPropagation();
1663
1847
  const pageEl = e.currentTarget.closest("[data-page]");
1664
1848
  if (!pageEl) return;
1665
- select(sel);
1849
+ setSelection(sel);
1666
1850
  history.checkpoint();
1667
1851
  drag.current = { sel, mode, x: e.clientX, y: e.clientY, start, rect: pageEl.getBoundingClientRect() };
1668
1852
  e.currentTarget.setPointerCapture(e.pointerId);
@@ -1673,7 +1857,7 @@ function FormEditor({
1673
1857
  const dx = (e.clientX - d.x) / d.rect.width;
1674
1858
  const dy = (e.clientY - d.y) / d.rect.height;
1675
1859
  if (d.sel.kind === "field") {
1676
- const position = d.mode === "move" ? _chunk5VHPTLLVcjs.moveBy.call(void 0, d.start, dx, dy, grid) : _chunk5VHPTLLVcjs.resizeBy.call(void 0, d.start, dx, dy, grid);
1860
+ const position = d.mode === "move" ? _chunk33XWO4KBcjs.moveBy.call(void 0, d.start, dx, dy, grid) : _chunk33XWO4KBcjs.resizeBy.call(void 0, d.start, dx, dy, grid);
1677
1861
  setFields((l) => l.map((x) => x.id === d.sel.id ? { ...x, position } : x), false);
1678
1862
  return;
1679
1863
  }
@@ -1681,48 +1865,52 @@ function FormEditor({
1681
1865
  (l) => l.map((x) => {
1682
1866
  if (x.id !== d.sel.id) return x;
1683
1867
  if (d.mode === "move") {
1684
- const { page: _p2, ...position2 } = _chunk5VHPTLLVcjs.moveBy.call(void 0, d.start, dx, dy, grid);
1868
+ const { page: _p2, ...position2 } = _chunk33XWO4KBcjs.moveBy.call(void 0, d.start, dx, dy, grid);
1685
1869
  void _p2;
1686
1870
  return { ...x, position: position2 };
1687
1871
  }
1688
1872
  if (x.type === "line") {
1689
1873
  const flat = (n) => n < 4e-3 ? 0 : n;
1690
- const width = flat(Math.min(1 - d.start.x, Math.max(0, _chunk5VHPTLLVcjs.snap.call(void 0, d.start.width + dx, grid))));
1691
- const height = flat(Math.min(1 - d.start.y, Math.max(0, _chunk5VHPTLLVcjs.snap.call(void 0, d.start.height + dy, grid))));
1874
+ const width = flat(Math.min(1 - d.start.x, Math.max(0, _chunk33XWO4KBcjs.snap.call(void 0, d.start.width + dx, grid))));
1875
+ const height = flat(Math.min(1 - d.start.y, Math.max(0, _chunk33XWO4KBcjs.snap.call(void 0, d.start.height + dy, grid))));
1692
1876
  return { ...x, position: { ...x.position, width, height } };
1693
1877
  }
1694
- const { page: _p, ...position } = _chunk5VHPTLLVcjs.resizeBy.call(void 0, d.start, dx, dy, grid);
1878
+ const { page: _p, ...position } = _chunk33XWO4KBcjs.resizeBy.call(void 0, d.start, dx, dy, grid);
1695
1879
  void _p;
1696
1880
  return { ...x, position };
1697
1881
  }),
1698
1882
  false
1699
1883
  );
1700
1884
  }
1701
- const endDrag = () => drag.current = null;
1885
+ const endDrag = () => {
1886
+ drag.current = null;
1887
+ };
1702
1888
  function placeNew(key, page, clientX, clientY, rect) {
1703
1889
  const [kind, what] = key.split(":");
1704
- const { x, y } = _chunk5VHPTLLVcjs.toPage.call(void 0, clientX, clientY, rect);
1705
- if (kind === "field" && _chunk7NZPYWL3cjs.FIELD_TYPES.includes(what)) {
1706
- const f = _chunk5VHPTLLVcjs.newField.call(void 0, what, page, x, y, fields);
1890
+ const { x, y } = _chunk33XWO4KBcjs.toPage.call(void 0, clientX, clientY, rect);
1891
+ if (kind === "field" && fieldTypes.includes(what)) {
1892
+ const f = _chunk33XWO4KBcjs.newField.call(void 0, what, page, x, y, fields);
1707
1893
  setFields((l) => [...l, f]);
1708
- select({ kind: "field", id: f.id });
1894
+ setSelection({ kind: "field", id: f.id });
1709
1895
  return true;
1710
1896
  }
1711
- if (kind === "element" && what in _chunk5VHPTLLVcjs.ELEMENT_TOOLS) {
1712
- const el = _chunk5VHPTLLVcjs.newElement.call(void 0, what, page, x, y);
1897
+ if (kind === "element" && elementTools.includes(what)) {
1898
+ const el = _chunk33XWO4KBcjs.newElement.call(void 0, what, page, x, y);
1713
1899
  setElements((l) => [...l, el]);
1714
- select({ kind: "element", id: el.id });
1900
+ setSelection({ kind: "element", id: el.id });
1715
1901
  return true;
1716
1902
  }
1717
1903
  return false;
1718
1904
  }
1719
- function dropNew(e, page) {
1720
- const key = e.dataTransfer.getData(DRAG_TYPE);
1721
- if (placeNew(key, page, e.clientX, e.clientY, e.currentTarget.getBoundingClientRect())) e.preventDefault();
1722
- }
1723
- function goToPage(n) {
1724
- _optionalChain([scroller, 'access', _56 => _56.current, 'optionalAccess', _57 => _57.querySelector, 'call', _58 => _58(`[data-page="${n}"]`), 'optionalAccess', _59 => _59.scrollIntoView, 'call', _60 => _60({ block: "start" })]);
1905
+ function editLine(line, page) {
1906
+ const el = _chunk33XWO4KBcjs.replaceLine.call(void 0, line, page);
1907
+ setElements((l) => [...l, el]);
1908
+ setSelection({ kind: "element", id: el.id });
1725
1909
  }
1910
+ const onDetectedRef = _react.useRef.call(void 0, onDetected);
1911
+ _react.useEffect.call(void 0, () => {
1912
+ onDetectedRef.current = onDetected;
1913
+ });
1726
1914
  const detect = _react.useCallback.call(void 0,
1727
1915
  async (auto = false) => {
1728
1916
  if (!pdf || !layout || detecting) return;
@@ -1730,7 +1918,7 @@ function FormEditor({
1730
1918
  setDetecting({ done: 0, total: layout.pages.length, stop });
1731
1919
  try {
1732
1920
  const lib = await loadPdfJs();
1733
- const found = await _chunk5VHPTLLVcjs.detectDocument.call(void 0,
1921
+ const found = await _chunk33XWO4KBcjs.detectDocument.call(void 0,
1734
1922
  pdf,
1735
1923
  lib.OPS,
1736
1924
  layout.pages,
@@ -1740,7 +1928,7 @@ function FormEditor({
1740
1928
  );
1741
1929
  if (found.length) {
1742
1930
  setFields((l) => [...l, ...found]);
1743
- setTab("fields");
1931
+ _optionalChain([onDetectedRef, 'access', _59 => _59.current, 'optionalCall', _60 => _60(found)]);
1744
1932
  }
1745
1933
  notify(
1746
1934
  found.length ? `${found.length} fields suggested${stop.signal.aborted ? " (stopped early)" : ""}. Check the dashed ones, then Save.` : auto ? "No fields found automatically. Drag them in from the left." : "No new fields found"
@@ -1786,25 +1974,144 @@ function FormEditor({
1786
1974
  setBusy(false);
1787
1975
  }
1788
1976
  }
1789
- const saveRef = _react.useRef.call(void 0, save);
1977
+ const counts = {};
1978
+ for (const f of fields) counts[f.position.page] = (_nullishCoalesce(counts[f.position.page], () => ( 0))) + 1;
1979
+ for (const el of _nullishCoalesce(_optionalChain([layout, 'optionalAccess', _61 => _61.elements]), () => ( []))) counts[el.page] = (_nullishCoalesce(counts[el.page], () => ( 0))) + 1;
1980
+ return {
1981
+ doc,
1982
+ fields,
1983
+ /** The layout as shown (the original pages until changed); null until the PDF has loaded. */
1984
+ layout,
1985
+ pageCount,
1986
+ /** Page size in PDF points, for drawing layout text at the right size. */
1987
+ pageHeight: (page) => _nullishCoalesce(_optionalChain([layout, 'optionalAccess', _62 => _62.pages, 'access', _63 => _63[page - 1], 'optionalAccess', _64 => _64.height]), () => ( 842)),
1988
+ /** Fields + layout items per page. */
1989
+ counts,
1990
+ dirty,
1991
+ /** Validation messages; save() refuses while there are any. */
1992
+ problems,
1993
+ busy,
1994
+ save,
1995
+ undo: history.undo,
1996
+ redo: history.redo,
1997
+ canUndo: history.canUndo,
1998
+ canRedo: history.canRedo,
1999
+ /** Changes the document; `record: false` = no undo step (live drags). */
2000
+ setFields,
2001
+ setElements,
2002
+ updateField,
2003
+ updateElement,
2004
+ reorderField: (id, step) => setFields((l) => _chunk33XWO4KBcjs.reorder.call(void 0, l, id, step)),
2005
+ movePage: (n, step) => withDoc((d) => _chunk33XWO4KBcjs.movePage.call(void 0, d, n, step)),
2006
+ insertBlankPage: (n) => withDoc((d) => _chunk33XWO4KBcjs.insertBlankPage.call(void 0, d, n)),
2007
+ deletePage: (n) => {
2008
+ setSelection(null);
2009
+ withDoc((d) => _chunk33XWO4KBcjs.deletePage.call(void 0, d, n));
2010
+ },
2011
+ selection,
2012
+ setSelection,
2013
+ selectedField,
2014
+ selectedElement,
2015
+ removeSelected,
2016
+ duplicateSelected,
2017
+ nudge,
2018
+ startDrag,
2019
+ onDrag,
2020
+ endDrag,
2021
+ /** Tools for a palette: drag with `dataTransfer` / tap to arm, then placeNew. */
2022
+ fieldTools: fieldTypes.map((t) => `field:${t}`),
2023
+ elementTools: elementTools.map((t) => `element:${t}`),
2024
+ armed,
2025
+ setArmed,
2026
+ placeNew,
2027
+ editText,
2028
+ setEditText,
2029
+ editLine,
2030
+ snapOn,
2031
+ setSnapOn,
2032
+ preview,
2033
+ /** Preview starts with empty answers; leaving it ends Edit text. */
2034
+ setPreview: (on) => {
2035
+ setPreviewState(on);
2036
+ setPreviewAnswers({});
2037
+ setEditText(false);
2038
+ },
2039
+ previewAnswers,
2040
+ setPreviewAnswers,
2041
+ previewStates: _chunk7NZPYWL3cjs.fieldStates.call(void 0, fields, previewAnswers),
2042
+ pdf,
2043
+ /** Pass to PdfPages' onLoaded. */
2044
+ onPdfLoaded: (s, d) => {
2045
+ setSizes(s);
2046
+ setPdf(d);
2047
+ },
2048
+ pageSizes: sizes2,
2049
+ detect,
2050
+ /** Progress while detecting; `stop.abort()` keeps what was found so far. */
2051
+ detecting
2052
+ };
2053
+ }
2054
+
2055
+ // src/react/FormEditor.tsx
2056
+
2057
+ var DRAG_TYPE = "application/x-doc-item";
2058
+ function FormEditor({
2059
+ pdf: pdfSource,
2060
+ title,
2061
+ onBack,
2062
+ toolbar,
2063
+ banner,
2064
+ tabs = [],
2065
+ components,
2066
+ hide = [],
2067
+ className = "h-full",
2068
+ ref,
2069
+ ...options
2070
+ }) {
2071
+ const shows = (p) => !hide.includes(p);
2072
+ const panelTabs = [
2073
+ ...shows("propertiesTab") ? ["props"] : [],
2074
+ ...shows("fieldsTab") ? ["fields"] : [],
2075
+ ...shows("pagesTab") ? ["pages"] : [],
2076
+ ...tabs.map((t) => t.id)
2077
+ ];
2078
+ const [tab, setTabState] = _react.useState.call(void 0, _nullishCoalesce(panelTabs[0], () => ( "props")));
2079
+ const setTab = (t) => panelTabs.includes(t) && setTabState(t);
2080
+ const ed = useFormEditor({
2081
+ ...options,
2082
+ onDetected: (found) => {
2083
+ setTab("fields");
2084
+ _optionalChain([options, 'access', _65 => _65.onDetected, 'optionalCall', _66 => _66(found)]);
2085
+ }
2086
+ });
2087
+ const { fields, layout, pageCount, selection, selectedField, selectedElement, preview, armed, snapOn, editText } = ed;
2088
+ const [drawer, setDrawer] = _react.useState.call(void 0, null);
2089
+ const compact = useCompact();
2090
+ const [confirmDeletePage, setConfirmDeletePage] = _react.useState.call(void 0, null);
2091
+ const [loadError, setLoadError] = _react.useState.call(void 0, "");
2092
+ const scroller = _react.useRef.call(void 0, null);
2093
+ const { zoom, setZoom, ref: fitRef } = useFitZoom(Math.max(...(_nullishCoalesce(ed.pageSizes, () => ( [{ width: 595 }]))).map((p) => p.width)));
2094
+ _react.useEffect.call(void 0, () => {
2095
+ if (selection) setTab("props");
2096
+ }, [selection]);
2097
+ function goToPage(n) {
2098
+ _optionalChain([scroller, 'access', _67 => _67.current, 'optionalAccess', _68 => _68.querySelector, 'call', _69 => _69(`[data-page="${n}"]`), 'optionalAccess', _70 => _70.scrollIntoView, 'call', _71 => _71({ block: "start" })]);
2099
+ }
2100
+ const saveRef = _react.useRef.call(void 0, ed.save);
1790
2101
  _react.useEffect.call(void 0, () => {
1791
- saveRef.current = save;
2102
+ saveRef.current = ed.save;
1792
2103
  });
1793
2104
  _react.useImperativeHandle.call(void 0,
1794
2105
  ref,
1795
2106
  () => ({
1796
- save: () => dirty ? saveRef.current() : Promise.resolve(problems.length === 0),
1797
- dirty,
1798
- value: doc
2107
+ save: () => ed.dirty ? saveRef.current() : Promise.resolve(ed.problems.length === 0),
2108
+ dirty: ed.dirty,
2109
+ value: ed.doc
1799
2110
  }),
1800
- [dirty, doc, problems]
2111
+ [ed.dirty, ed.doc, ed.problems]
1801
2112
  );
1802
2113
  if (loadError) return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "fl-root p-6 text-center text-sm text-danger", children: loadError });
1803
- const previewStates = _chunk7NZPYWL3cjs.fieldStates.call(void 0, fields, previewAnswers);
1804
- const counts = {};
1805
- for (const f of fields) counts[f.position.page] = (_nullishCoalesce(counts[f.position.page], () => ( 0))) + 1;
1806
- for (const el of _nullishCoalesce(_optionalChain([layout, 'optionalAccess', _61 => _61.elements]), () => ( []))) counts[el.page] = (_nullishCoalesce(counts[el.page], () => ( 0))) + 1;
1807
- const pageHeight = (page) => _nullishCoalesce(_optionalChain([layout, 'optionalAccess', _62 => _62.pages, 'access', _63 => _63[page - 1], 'optionalAccess', _64 => _64.height]), () => ( 842));
2114
+ const { previewStates, previewAnswers, counts, pageHeight } = ed;
1808
2115
  const toolItem = (key, label) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1809
2116
  "button",
1810
2117
  {
@@ -1812,7 +2119,7 @@ function FormEditor({
1812
2119
  draggable: true,
1813
2120
  onDragStart: (e) => e.dataTransfer.setData(DRAG_TYPE, key),
1814
2121
  onClick: () => {
1815
- setArmed((a) => a === key ? null : key);
2122
+ ed.setArmed(armed === key ? null : key);
1816
2123
  setDrawer(null);
1817
2124
  },
1818
2125
  "aria-pressed": armed === key,
@@ -1821,12 +2128,12 @@ function FormEditor({
1821
2128
  },
1822
2129
  key
1823
2130
  );
1824
- const armedLabel = armed ? armed.startsWith("field:") ? TYPE_LABEL[armed.slice(6)] : _optionalChain([_chunk5VHPTLLVcjs.ELEMENT_TOOLS, 'access', _65 => _65[armed.slice(8)], 'optionalAccess', _66 => _66.label]) : "";
1825
- return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: `fl-root flex min-h-[640px] flex-col bg-white text-ink ${className}`, children: [
2131
+ const armedLabel = armed ? armed.startsWith("field:") ? TYPE_LABEL[armed.slice(6)] : _optionalChain([_chunk33XWO4KBcjs.ELEMENT_TOOLS, 'access', _72 => _72[armed.slice(8)], 'optionalAccess', _73 => _73.label]) : "";
2132
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, FormliftProvider, { components, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: `fl-root flex min-h-[640px] flex-col bg-white text-ink ${className}`, children: [
1826
2133
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-wrap items-center gap-2 border-b border-line bg-white px-4 py-2.5", children: [
1827
- onBack && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Button, { variant: "secondary", size: "sm", icon: _lucidereact.ArrowLeft, onClick: onBack, children: "Back" }),
1828
- !preview && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1829
- Button,
2134
+ onBack && shows("back") && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Button2, { variant: "secondary", size: "sm", icon: _lucidereact.ArrowLeft, onClick: onBack, children: "Back" }),
2135
+ !preview && shows("tools") && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2136
+ Button2,
1830
2137
  {
1831
2138
  variant: drawer === "tools" ? "primary" : "secondary",
1832
2139
  size: "sm",
@@ -1836,8 +2143,8 @@ function FormEditor({
1836
2143
  children: "Add"
1837
2144
  }
1838
2145
  ),
1839
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1840
- Button,
2146
+ shows("panel") && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2147
+ Button2,
1841
2148
  {
1842
2149
  variant: drawer === "panel" ? "primary" : "secondary",
1843
2150
  size: "sm",
@@ -1847,91 +2154,73 @@ function FormEditor({
1847
2154
  children: selection ? "Properties" : "Panel"
1848
2155
  }
1849
2156
  ),
1850
- title != null && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h2", { className: "m-0 min-w-0 truncate text-[17px] font-semibold", children: title }),
1851
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-[12px] text-muted", children: dirty ? "Unsaved changes" : "All changes saved" }),
2157
+ title != null && shows("title") && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h2", { className: "m-0 min-w-0 truncate text-[17px] font-semibold", children: title }),
2158
+ shows("status") && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-[12px] text-muted", children: ed.dirty ? "Unsaved changes" : "All changes saved" }),
1852
2159
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "ml-auto flex flex-wrap items-center gap-1.5", children: [
1853
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1854
- IconButton,
1855
- {
1856
- icon: _lucidereact.Undo2,
1857
- title: "Undo (Ctrl+Z)",
1858
- disabled: !history.canUndo || preview,
1859
- onClick: history.undo
1860
- }
1861
- ),
1862
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1863
- IconButton,
1864
- {
1865
- icon: _lucidereact.Redo2,
1866
- title: "Redo (Ctrl+Y)",
1867
- disabled: !history.canRedo || preview,
1868
- onClick: history.redo
1869
- }
1870
- ),
1871
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1872
- IconButton,
2160
+ shows("undo") && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
2161
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, IconButton2, { icon: _lucidereact.Undo2, title: "Undo (Ctrl+Z)", disabled: !ed.canUndo || preview, onClick: ed.undo }),
2162
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, IconButton2, { icon: _lucidereact.Redo2, title: "Redo (Ctrl+Y)", disabled: !ed.canRedo || preview, onClick: ed.redo })
2163
+ ] }),
2164
+ shows("snap") && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2165
+ IconButton2,
1873
2166
  {
1874
2167
  icon: _lucidereact.Grid3x3,
1875
2168
  title: snapOn ? "Snap to grid: on" : "Snap to grid: off",
1876
2169
  className: snapOn ? "!text-primary" : "",
1877
- onClick: () => setSnapOn((s) => !s)
2170
+ onClick: () => ed.setSnapOn(!snapOn)
1878
2171
  }
1879
2172
  ),
1880
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ZoomControls, { zoom, onChange: setZoom }),
1881
- !preview && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1882
- Button,
2173
+ shows("zoom") && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ZoomControls, { zoom, onChange: setZoom }),
2174
+ !preview && shows("editText") && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2175
+ Button2,
1883
2176
  {
1884
2177
  variant: editText ? "primary" : "secondary",
1885
2178
  size: "sm",
1886
2179
  icon: _lucidereact.Type,
1887
2180
  disabled: !layout,
1888
2181
  title: "Click any line of the document to change its text",
1889
- onClick: () => setEditText((v) => !v),
2182
+ onClick: () => ed.setEditText(!editText),
1890
2183
  children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "max-sm:hidden", children: "Edit text" })
1891
2184
  }
1892
2185
  ),
1893
- !preview && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1894
- Button,
2186
+ !preview && shows("autoDetect") && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2187
+ Button2,
1895
2188
  {
1896
2189
  variant: "secondary",
1897
2190
  size: "sm",
1898
2191
  icon: _lucidereact.Wand2,
1899
- disabled: !pdf || !layout || !!detecting,
2192
+ disabled: !ed.pdf || !layout || !!ed.detecting,
1900
2193
  title: "Find answer lines, checkboxes and table cells and suggest fields for them",
1901
- onClick: () => void detect(),
2194
+ onClick: () => void ed.detect(),
1902
2195
  children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "max-sm:hidden", children: "Auto-detect" })
1903
2196
  }
1904
2197
  ),
1905
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1906
- Button,
2198
+ shows("preview") && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2199
+ Button2,
1907
2200
  {
1908
2201
  variant: "secondary",
1909
2202
  size: "sm",
1910
2203
  icon: preview ? _lucidereact.Pencil : _lucidereact.Eye,
1911
2204
  title: preview ? "Back to editing" : "Preview",
1912
- onClick: () => {
1913
- setPreview((p) => !p);
1914
- setPreviewAnswers({});
1915
- setEditText(false);
1916
- },
2205
+ onClick: () => ed.setPreview(!preview),
1917
2206
  children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "max-sm:hidden", children: preview ? "Edit" : "Preview" })
1918
2207
  }
1919
2208
  ),
1920
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Button, { size: "sm", icon: _lucidereact.Save, title: "Save", disabled: !dirty || busy, onClick: () => void save(), children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "max-sm:hidden", children: "Save" }) }),
2209
+ shows("save") && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Button2, { size: "sm", icon: _lucidereact.Save, title: "Save", disabled: !ed.dirty || ed.busy, onClick: () => void ed.save(), children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "max-sm:hidden", children: "Save" }) }),
1921
2210
  toolbar
1922
2211
  ] })
1923
2212
  ] }),
1924
2213
  banner,
1925
- detecting && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex items-center gap-3 bg-folder/15 px-4 py-1.5 text-[12.5px] text-ink-2", role: "status", children: [
2214
+ ed.detecting && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex items-center gap-3 bg-folder/15 px-4 py-1.5 text-[12.5px] text-ink-2", role: "status", children: [
1926
2215
  "Detecting fields\u2026 page ",
1927
- detecting.done,
2216
+ ed.detecting.done,
1928
2217
  " of ",
1929
- detecting.total,
2218
+ ed.detecting.total,
1930
2219
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "h-1.5 w-40 overflow-hidden rounded bg-white", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1931
2220
  "div",
1932
2221
  {
1933
2222
  className: "h-full bg-folder",
1934
- style: { width: `${100 * detecting.done / Math.max(1, detecting.total)}%` }
2223
+ style: { width: `${100 * ed.detecting.done / Math.max(1, ed.detecting.total)}%` }
1935
2224
  }
1936
2225
  ) }),
1937
2226
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
@@ -1939,7 +2228,7 @@ function FormEditor({
1939
2228
  {
1940
2229
  type: "button",
1941
2230
  className: "cursor-pointer text-primary hover:underline",
1942
- onClick: () => detecting.stop.abort(),
2231
+ onClick: () => _optionalChain([ed, 'access', _74 => _74.detecting, 'optionalAccess', _75 => _75.stop, 'access', _76 => _76.abort, 'call', _77 => _77()]),
1943
2232
  children: "Stop"
1944
2233
  }
1945
2234
  )
@@ -1948,22 +2237,32 @@ function FormEditor({
1948
2237
  "Tap the page where the ",
1949
2238
  armedLabel,
1950
2239
  " should go.",
1951
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { type: "button", className: "cursor-pointer text-primary hover:underline", onClick: () => setArmed(null), children: "Cancel" })
2240
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2241
+ "button",
2242
+ {
2243
+ type: "button",
2244
+ className: "cursor-pointer text-primary hover:underline",
2245
+ onClick: () => ed.setArmed(null),
2246
+ children: "Cancel"
2247
+ }
2248
+ )
1952
2249
  ] }),
1953
2250
  editText && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "m-0 bg-folder/15 px-4 py-1.5 text-[12.5px] text-ink-2", children: "Edit text: click a line of the document to replace it with an editable copy (same place and size). The uploaded file itself never changes." }),
1954
2251
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "relative flex min-h-0 flex-1", children: [
1955
- !preview && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
2252
+ !preview && shows("tools") && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
1956
2253
  "aside",
1957
2254
  {
1958
2255
  className: `w-[170px] flex-none overflow-y-auto border-r border-line bg-white max-lg:absolute max-lg:inset-y-0 max-lg:left-0 max-lg:z-30 max-lg:w-[220px] max-lg:shadow-xl ${drawer === "tools" ? "" : "max-lg:hidden"}`,
1959
2256
  children: [
1960
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, PanelHeading, { children: "FIELDS" }),
1961
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "m-0 px-3 pt-2 text-[11.5px] text-muted", children: "Drag onto the document, or tap one, then the page" }),
1962
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "space-y-1 p-2", children: _chunk7NZPYWL3cjs.FIELD_TYPES.map((t) => toolItem(`field:${t}`, TYPE_LABEL[t])) }),
1963
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, PanelHeading, { children: "LAYOUT" }),
1964
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "space-y-1 p-2", children: Object.keys(_chunk5VHPTLLVcjs.ELEMENT_TOOLS).map(
1965
- (t) => toolItem(`element:${t}`, _chunk5VHPTLLVcjs.ELEMENT_TOOLS[t].label)
1966
- ) })
2257
+ shows("fieldTools") && ed.fieldTools.length > 0 && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
2258
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, PanelHeading2, { children: "FIELDS" }),
2259
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "m-0 px-3 pt-2 text-[11.5px] text-muted", children: "Drag onto the document, or tap one, then the page" }),
2260
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "space-y-1 p-2", children: ed.fieldTools.map((k) => toolItem(k, TYPE_LABEL[k.slice(6)])) })
2261
+ ] }),
2262
+ shows("layoutTools") && ed.elementTools.length > 0 && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
2263
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, PanelHeading2, { children: "LAYOUT" }),
2264
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "space-y-1 p-2", children: ed.elementTools.map((k) => toolItem(k, _chunk33XWO4KBcjs.ELEMENT_TOOLS[k.slice(8)].label)) })
2265
+ ] })
1967
2266
  ]
1968
2267
  }
1969
2268
  ),
@@ -1976,7 +2275,7 @@ function FormEditor({
1976
2275
  },
1977
2276
  className: "min-w-0 flex-1 overflow-auto bg-hover",
1978
2277
  onPointerDown: () => {
1979
- if (!preview) setSelection(null);
2278
+ if (!preview) ed.setSelection(null);
1980
2279
  setDrawer(null);
1981
2280
  },
1982
2281
  children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
@@ -1984,12 +2283,9 @@ function FormEditor({
1984
2283
  {
1985
2284
  load: pdfSource,
1986
2285
  zoom,
1987
- pages: _optionalChain([layout, 'optionalAccess', _67 => _67.pages]),
2286
+ pages: _optionalChain([layout, 'optionalAccess', _78 => _78.pages]),
1988
2287
  withText: editText && !preview,
1989
- onLoaded: (s, doc2) => {
1990
- setSizes(s);
1991
- setPdf(doc2);
1992
- },
2288
+ onLoaded: ed.onPdfLoaded,
1993
2289
  onError: () => setLoadError("The document could not be shown"),
1994
2290
  overlay: (page, lines) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
1995
2291
  "div",
@@ -2000,41 +2296,41 @@ function FormEditor({
2000
2296
  backgroundSize: "2% 2%"
2001
2297
  } : void 0,
2002
2298
  onDragOver: (e) => !preview && e.preventDefault(),
2003
- onDrop: (e) => dropNew(e, page),
2299
+ onDrop: (e) => {
2300
+ const key = e.dataTransfer.getData(DRAG_TYPE);
2301
+ if (ed.placeNew(key, page, e.clientX, e.clientY, e.currentTarget.getBoundingClientRect()))
2302
+ e.preventDefault();
2303
+ },
2004
2304
  onClick: (e) => {
2005
2305
  if (!armed || preview) return;
2006
- placeNew(armed, page, e.clientX, e.clientY, e.currentTarget.getBoundingClientRect());
2007
- setArmed(null);
2306
+ ed.placeNew(armed, page, e.clientX, e.clientY, e.currentTarget.getBoundingClientRect());
2307
+ ed.setArmed(null);
2008
2308
  },
2009
2309
  children: [
2010
- _optionalChain([lines, 'optionalAccess', _68 => _68.map, 'call', _69 => _69((line, i) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2310
+ _optionalChain([lines, 'optionalAccess', _79 => _79.map, 'call', _80 => _80((line, i) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2011
2311
  "button",
2012
2312
  {
2013
2313
  type: "button",
2014
2314
  title: `Edit: ${line.text}`,
2015
2315
  className: "absolute cursor-text rounded-[1px] outline-1 outline-folder/60 hover:bg-folder/25 hover:outline-folder",
2016
- style: _chunk5VHPTLLVcjs.boxStyle.call(void 0, { page, ...line }),
2316
+ style: _chunk33XWO4KBcjs.boxStyle.call(void 0, { page, ...line }),
2017
2317
  onPointerDown: (e) => e.stopPropagation(),
2018
- onClick: () => {
2019
- const el = _chunk5VHPTLLVcjs.replaceLine.call(void 0, line, page);
2020
- setElements((l) => [...l, el]);
2021
- select({ kind: "element", id: el.id });
2022
- }
2318
+ onClick: () => ed.editLine(line, page)
2023
2319
  },
2024
2320
  i
2025
2321
  ))]),
2026
- _optionalChain([layout, 'optionalAccess', _70 => _70.elements, 'access', _71 => _71.filter, 'call', _72 => _72((el) => el.page === page), 'access', _73 => _73.map, 'call', _74 => _74(
2322
+ _optionalChain([layout, 'optionalAccess', _81 => _81.elements, 'access', _82 => _82.filter, 'call', _83 => _83((el) => el.page === page), 'access', _84 => _84.map, 'call', _85 => _85(
2027
2323
  (el) => preview ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, LayoutElementView, { element: el, pageHeight: pageHeight(page) }, el.id) : /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
2028
2324
  "div",
2029
2325
  {
2030
2326
  role: "button",
2031
2327
  tabIndex: 0,
2032
2328
  "aria-label": `${el.type} ${_nullishCoalesce(el.text, () => ( ""))}`,
2033
- className: `absolute cursor-move touch-none select-none ${_optionalChain([selection, 'optionalAccess', _75 => _75.id]) === el.id ? "z-10 outline-2 outline-primary" : "hover:outline-1 hover:outline-primary/50"}`,
2034
- style: _chunk5VHPTLLVcjs.boxStyle.call(void 0, { page, ...el.position, height: Math.max(el.position.height, 4e-3) }),
2035
- onPointerDown: (e) => startDrag(e, { kind: "element", id: el.id }, { page, ...el.position }, "move"),
2036
- onPointerMove: onDrag,
2037
- onPointerUp: endDrag,
2329
+ className: `absolute cursor-move touch-none select-none ${_optionalChain([selection, 'optionalAccess', _86 => _86.id]) === el.id ? "z-10 outline-2 outline-primary" : "hover:outline-1 hover:outline-primary/50"}`,
2330
+ style: _chunk33XWO4KBcjs.boxStyle.call(void 0, { page, ...el.position, height: Math.max(el.position.height, 4e-3) }),
2331
+ onPointerDown: (e) => ed.startDrag(e, { kind: "element", id: el.id }, { page, ...el.position }, "move"),
2332
+ onPointerMove: ed.onDrag,
2333
+ onPointerUp: ed.endDrag,
2038
2334
  onClick: (e) => e.stopPropagation(),
2039
2335
  children: [
2040
2336
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
@@ -2045,14 +2341,14 @@ function FormEditor({
2045
2341
  style: { left: 0, top: 0, width: "100%", height: "100%" }
2046
2342
  }
2047
2343
  ),
2048
- _optionalChain([selection, 'optionalAccess', _76 => _76.id]) === el.id && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2344
+ _optionalChain([selection, 'optionalAccess', _87 => _87.id]) === el.id && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2049
2345
  "span",
2050
2346
  {
2051
2347
  "aria-label": "Resize",
2052
2348
  className: "absolute -right-1 -bottom-1 h-2.5 w-2.5 cursor-se-resize rounded-sm border border-white bg-primary",
2053
- onPointerDown: (e) => startDrag(e, { kind: "element", id: el.id }, { page, ...el.position }, "resize"),
2054
- onPointerMove: onDrag,
2055
- onPointerUp: endDrag
2349
+ onPointerDown: (e) => ed.startDrag(e, { kind: "element", id: el.id }, { page, ...el.position }, "resize"),
2350
+ onPointerMove: ed.onDrag,
2351
+ onPointerUp: ed.endDrag
2056
2352
  }
2057
2353
  )
2058
2354
  ]
@@ -2061,14 +2357,15 @@ function FormEditor({
2061
2357
  )
2062
2358
  )]),
2063
2359
  fields.filter((f) => f.position.page === page).map(
2064
- (f) => preview ? _optionalChain([previewStates, 'access', _77 => _77[f.key], 'optionalAccess', _78 => _78.visible]) && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "absolute [container-type:size]", style: _chunk5VHPTLLVcjs.boxStyle.call(void 0, f.position), children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2065
- FieldControl,
2360
+ (f) => preview ? _optionalChain([previewStates, 'access', _88 => _88[f.key], 'optionalAccess', _89 => _89.visible]) && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "absolute [container-type:size]", style: _chunk33XWO4KBcjs.boxStyle.call(void 0, f.position), children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2361
+ AnswerControl,
2066
2362
  {
2363
+ components,
2067
2364
  field: f,
2068
2365
  value: previewAnswers[f.key],
2069
2366
  readOnly: previewStates[f.key].readOnly,
2070
2367
  compact,
2071
- onChange: (v) => setPreviewAnswers((a) => ({ ...a, [f.key]: v }))
2368
+ onChange: (v) => ed.setPreviewAnswers((a) => ({ ...a, [f.key]: v }))
2072
2369
  }
2073
2370
  ) }, f.id) : /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
2074
2371
  "div",
@@ -2077,25 +2374,25 @@ function FormEditor({
2077
2374
  tabIndex: 0,
2078
2375
  "aria-label": `${TYPE_LABEL[f.type]} field ${f.label || f.key}`,
2079
2376
  title: `${f.label || f.key} (${TYPE_LABEL[f.type]})`,
2080
- className: `absolute cursor-move touch-none rounded-sm border text-[10px] select-none [container-type:size] ${_optionalChain([selection, 'optionalAccess', _79 => _79.id]) === f.id ? "z-10 border-primary bg-primary/20 ring-2 ring-primary/40" : f.source === "ai" ? "border-dashed border-folder bg-folder/15" : "border-primary/60 bg-primary/10 hover:bg-primary/15"}`,
2081
- style: _chunk5VHPTLLVcjs.boxStyle.call(void 0, f.position),
2082
- onPointerDown: (e) => startDrag(e, { kind: "field", id: f.id }, f.position, "move"),
2083
- onPointerMove: onDrag,
2084
- onPointerUp: endDrag,
2377
+ className: `absolute cursor-move touch-none rounded-sm border text-[10px] select-none [container-type:size] ${_optionalChain([selection, 'optionalAccess', _90 => _90.id]) === f.id ? "z-10 border-primary bg-primary/20 ring-2 ring-primary/40" : f.source === "ai" ? "border-dashed border-folder bg-folder/15" : "border-primary/60 bg-primary/10 hover:bg-primary/15"}`,
2378
+ style: _chunk33XWO4KBcjs.boxStyle.call(void 0, f.position),
2379
+ onPointerDown: (e) => ed.startDrag(e, { kind: "field", id: f.id }, f.position, "move"),
2380
+ onPointerMove: ed.onDrag,
2381
+ onPointerUp: ed.endDrag,
2085
2382
  onClick: (e) => e.stopPropagation(),
2086
2383
  children: [
2087
2384
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { className: "pointer-events-none block truncate px-0.5 text-[clamp(7px,55cqh,12px)] leading-tight text-primary", children: [
2088
2385
  f.label || f.key,
2089
2386
  f.required && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "b", { className: "text-danger", children: " *" })
2090
2387
  ] }),
2091
- _optionalChain([selection, 'optionalAccess', _80 => _80.id]) === f.id && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2388
+ _optionalChain([selection, 'optionalAccess', _91 => _91.id]) === f.id && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2092
2389
  "span",
2093
2390
  {
2094
2391
  "aria-label": "Resize",
2095
2392
  className: "absolute -right-1 -bottom-1 h-2.5 w-2.5 cursor-se-resize rounded-sm border border-white bg-primary",
2096
- onPointerDown: (e) => startDrag(e, { kind: "field", id: f.id }, f.position, "resize"),
2097
- onPointerMove: onDrag,
2098
- onPointerUp: endDrag
2393
+ onPointerDown: (e) => ed.startDrag(e, { kind: "field", id: f.id }, f.position, "resize"),
2394
+ onPointerMove: ed.onDrag,
2395
+ onPointerUp: ed.endDrag
2099
2396
  }
2100
2397
  )
2101
2398
  ]
@@ -2110,42 +2407,51 @@ function FormEditor({
2110
2407
  )
2111
2408
  }
2112
2409
  ),
2113
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
2410
+ shows("panel") && panelTabs.length > 0 && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
2114
2411
  "aside",
2115
2412
  {
2116
2413
  className: `flex w-[350px] flex-none flex-col border-l border-line bg-white max-lg:absolute max-lg:inset-y-0 max-lg:right-0 max-lg:z-30 max-lg:w-[min(350px,92vw)] max-lg:shadow-xl ${drawer === "panel" ? "" : "max-lg:hidden"}`,
2117
2414
  children: [
2118
2415
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "overflow-x-auto border-b border-line p-2 [&_button]:px-2.5", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2119
- SegmentedTabs,
2416
+ SegmentedTabs2,
2120
2417
  {
2121
2418
  options: [
2122
2419
  { value: "props", label: "Properties" },
2123
2420
  { value: "fields", label: `Fields (${fields.length})` },
2124
2421
  { value: "pages", label: `Pages (${pageCount})` },
2125
2422
  ...tabs.map((t) => ({ value: t.id, label: t.label }))
2126
- ],
2423
+ ].filter((o) => panelTabs.includes(o.value)),
2127
2424
  value: tab,
2128
2425
  onChange: setTab
2129
2426
  }
2130
2427
  ) }),
2131
- problems.length > 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "ul", { className: "m-0 border-b border-danger/30 bg-danger/5 py-2 pr-3 pl-7 text-[12px] text-danger", children: problems.slice(0, 6).map((p) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "li", { children: p }, p)) }),
2428
+ ed.problems.length > 0 && shows("problems") && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "ul", { className: "m-0 border-b border-danger/30 bg-danger/5 py-2 pr-3 pl-7 text-[12px] text-danger", children: ed.problems.slice(0, 6).map((p) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "li", { children: p }, p)) }),
2132
2429
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "min-h-0 flex-1 overflow-y-auto", children: [
2133
2430
  tab === "props" && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
2134
2431
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2135
- PanelHeading,
2432
+ PanelHeading2,
2136
2433
  {
2137
2434
  actions: selection && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
2138
2435
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2139
- IconButton,
2436
+ IconButton2,
2140
2437
  {
2141
2438
  icon: _lucidereact.Copy,
2142
2439
  title: "Duplicate (Ctrl+D)",
2143
2440
  light: true,
2144
2441
  iconSize: 16,
2145
- onClick: duplicateSelected
2442
+ onClick: ed.duplicateSelected
2146
2443
  }
2147
2444
  ),
2148
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, IconButton, { icon: _lucidereact.Trash2, title: "Delete (Del)", light: true, iconSize: 16, onClick: removeSelected })
2445
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2446
+ IconButton2,
2447
+ {
2448
+ icon: _lucidereact.Trash2,
2449
+ title: "Delete (Del)",
2450
+ light: true,
2451
+ iconSize: 16,
2452
+ onClick: ed.removeSelected
2453
+ }
2454
+ )
2149
2455
  ] }),
2150
2456
  children: selectedField ? "FIELD" : selectedElement ? selectedElement.type.toUpperCase() : "PROPERTIES"
2151
2457
  }
@@ -2156,7 +2462,7 @@ function FormEditor({
2156
2462
  field: selectedField,
2157
2463
  fields,
2158
2464
  pageCount,
2159
- onChange: updateField
2465
+ onChange: ed.updateField
2160
2466
  },
2161
2467
  selectedField.id
2162
2468
  ) : selectedElement ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
@@ -2164,10 +2470,10 @@ function FormEditor({
2164
2470
  {
2165
2471
  element: selectedElement,
2166
2472
  pageCount,
2167
- onChange: updateElement
2473
+ onChange: ed.updateElement
2168
2474
  },
2169
2475
  selectedElement.id
2170
- ) : /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, EmptyText, { children: [
2476
+ ) : /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, EmptyText2, { children: [
2171
2477
  "Select something on the document, drag a field or layout item in from the left, or use",
2172
2478
  " ",
2173
2479
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "b", { children: "Edit text" }),
@@ -2175,12 +2481,12 @@ function FormEditor({
2175
2481
  ] })
2176
2482
  ] }),
2177
2483
  tab === "fields" && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
2178
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, PanelHeading, { children: "FILL ORDER" }),
2179
- !fields.length && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, EmptyText, { children: "No fields yet." }),
2484
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, PanelHeading2, { children: "FILL ORDER" }),
2485
+ !fields.length && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, EmptyText2, { children: "No fields yet." }),
2180
2486
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "ol", { className: "m-0 list-none p-0", children: fields.map((f, i) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
2181
2487
  "li",
2182
2488
  {
2183
- className: `flex items-center gap-1 border-b border-line-soft px-2 py-1 text-[12.5px] ${_optionalChain([selection, 'optionalAccess', _81 => _81.id]) === f.id ? "bg-primary-tint" : ""}`,
2489
+ className: `flex items-center gap-1 border-b border-line-soft px-2 py-1 text-[12.5px] ${_optionalChain([selection, 'optionalAccess', _92 => _92.id]) === f.id ? "bg-primary-tint" : ""}`,
2184
2490
  children: [
2185
2491
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
2186
2492
  "button",
@@ -2188,7 +2494,7 @@ function FormEditor({
2188
2494
  type: "button",
2189
2495
  className: "min-w-0 flex-1 cursor-pointer truncate text-left",
2190
2496
  onClick: () => {
2191
- select({ kind: "field", id: f.id });
2497
+ ed.setSelection({ kind: "field", id: f.id });
2192
2498
  goToPage(f.position.page);
2193
2499
  },
2194
2500
  children: [
@@ -2208,23 +2514,23 @@ function FormEditor({
2208
2514
  }
2209
2515
  ),
2210
2516
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2211
- IconButton,
2517
+ IconButton2,
2212
2518
  {
2213
2519
  icon: _lucidereact.ArrowUp,
2214
2520
  title: "Move up",
2215
2521
  iconSize: 13,
2216
2522
  disabled: i === 0,
2217
- onClick: () => setFields((l) => _chunk5VHPTLLVcjs.reorder.call(void 0, l, f.id, -1))
2523
+ onClick: () => ed.reorderField(f.id, -1)
2218
2524
  }
2219
2525
  ),
2220
2526
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2221
- IconButton,
2527
+ IconButton2,
2222
2528
  {
2223
2529
  icon: _lucidereact.ArrowDown,
2224
2530
  title: "Move down",
2225
2531
  iconSize: 13,
2226
2532
  disabled: i === fields.length - 1,
2227
- onClick: () => setFields((l) => _chunk5VHPTLLVcjs.reorder.call(void 0, l, f.id, 1))
2533
+ onClick: () => ed.reorderField(f.id, 1)
2228
2534
  }
2229
2535
  )
2230
2536
  ]
@@ -2238,19 +2544,19 @@ function FormEditor({
2238
2544
  pages: layout.pages,
2239
2545
  counts,
2240
2546
  onGoTo: goToPage,
2241
- onMove: (n, step) => withDoc((d) => _chunk5VHPTLLVcjs.movePage.call(void 0, d, n, step)),
2242
- onInsertBlank: (n) => withDoc((d) => _chunk5VHPTLLVcjs.insertBlankPage.call(void 0, d, n)),
2243
- onDelete: (n) => counts[n] ? setConfirmDeletePage(n) : withDoc((d) => _chunk5VHPTLLVcjs.deletePage.call(void 0, d, n))
2547
+ onMove: ed.movePage,
2548
+ onInsertBlank: ed.insertBlankPage,
2549
+ onDelete: (n) => counts[n] ? setConfirmDeletePage(n) : ed.deletePage(n)
2244
2550
  }
2245
- ) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, EmptyText, { children: "Loading pages\u2026" })),
2246
- _optionalChain([tabs, 'access', _82 => _82.find, 'call', _83 => _83((t) => t.id === tab), 'optionalAccess', _84 => _84.content])
2551
+ ) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, EmptyText2, { children: "Loading pages\u2026" })),
2552
+ _optionalChain([tabs, 'access', _93 => _93.find, 'call', _94 => _94((t) => t.id === tab), 'optionalAccess', _95 => _95.content])
2247
2553
  ] })
2248
2554
  ]
2249
2555
  }
2250
2556
  )
2251
2557
  ] }),
2252
2558
  confirmDeletePage != null && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
2253
- ConfirmModal,
2559
+ ConfirmModal2,
2254
2560
  {
2255
2561
  danger: true,
2256
2562
  confirmLabel: "Delete page",
@@ -2258,8 +2564,7 @@ function FormEditor({
2258
2564
  onConfirm: () => {
2259
2565
  const n = confirmDeletePage;
2260
2566
  setConfirmDeletePage(null);
2261
- setSelection(null);
2262
- withDoc((d) => _chunk5VHPTLLVcjs.deletePage.call(void 0, d, n));
2567
+ ed.deletePage(n);
2263
2568
  },
2264
2569
  children: [
2265
2570
  "Delete page ",
@@ -2270,7 +2575,7 @@ function FormEditor({
2270
2575
  ]
2271
2576
  }
2272
2577
  )
2273
- ] });
2578
+ ] }) });
2274
2579
  }
2275
2580
 
2276
2581
  // src/react/FormFiller.tsx
@@ -2281,145 +2586,75 @@ function FormEditor({
2281
2586
 
2282
2587
 
2283
2588
 
2284
- // src/react/ui/Chip.tsx
2285
-
2589
+ // src/react/hooks/useQuestionFilter.ts
2286
2590
 
2287
- function Chip({
2288
- label,
2289
- count,
2290
- active,
2291
- onClick
2292
- }) {
2293
- return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
2294
- "button",
2295
- {
2296
- type: "button",
2297
- "aria-pressed": !!active,
2298
- onClick,
2299
- className: `inline-flex cursor-pointer items-center gap-1.5 rounded-full border px-3 py-1 text-[12.5px] whitespace-nowrap transition-colors ${active ? "border-primary bg-primary-tint font-semibold text-primary" : "border-line-strong bg-white text-ink-2 hover:border-faint hover:bg-surface"}`,
2300
- children: [
2301
- label,
2302
- count != null && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2303
- "span",
2304
- {
2305
- className: `rounded-full px-1.5 text-[11px] font-semibold ${active ? "bg-primary text-white" : "bg-hover text-muted"}`,
2306
- children: count
2307
- }
2308
- )
2309
- ]
2310
- }
2591
+ var defaultFilters = _chunk33XWO4KBcjs.builtinFilters.call(void 0, { type: (t) => TYPE_LABEL[t] });
2592
+ var byId = (id) => {
2593
+ if (id === "tags") return defaultFilters.find((s) => typeof s === "function");
2594
+ return defaultFilters.find((s) => typeof s !== "function" && s.id === id);
2595
+ };
2596
+ function useQuestionFilter(questions, answers, { filters = defaultFilters, search: searchOn = true, initial, predicate, onChange } = {}) {
2597
+ const [values, setValues] = _react.useState.call(void 0, _nullishCoalesce(_optionalChain([initial, 'optionalAccess', _96 => _96.values]), () => ( {})));
2598
+ const [search, setSearchState] = _react.useState.call(void 0, _nullishCoalesce(_optionalChain([initial, 'optionalAccess', _97 => _97.search]), () => ( "")));
2599
+ const [seen, setSeen] = _react.useState.call(void 0, answers);
2600
+ const [version, setVersion] = _react.useState.call(void 0, 0);
2601
+ const update = (nextSearch, nextValues) => {
2602
+ setSearchState(nextSearch);
2603
+ setValues(nextValues);
2604
+ setSeen(answers);
2605
+ setVersion((v) => v + 1);
2606
+ _optionalChain([onChange, 'optionalCall', _98 => _98({ search: nextSearch, values: nextValues })]);
2607
+ };
2608
+ const key = filters.map((f) => typeof f === "string" ? f : typeof f === "function" ? "fn" : f.id).join();
2609
+ const defs = _react.useMemo.call(void 0,
2610
+ () => _chunk33XWO4KBcjs.resolveFilters.call(void 0,
2611
+ filters.map((f) => typeof f === "string" ? byId(f) : f).filter((f) => !!f),
2612
+ questions
2613
+ ),
2614
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- re-resolve when the list's ids change, not on every render
2615
+ [key, questions]
2311
2616
  );
2312
- }
2313
- function ChipGroup({
2314
- title,
2315
- options,
2316
- value,
2317
- onChange
2318
- }) {
2319
- return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { role: "group", "aria-label": title, className: "flex flex-wrap items-center gap-1.5", children: [
2320
- title && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "mr-1 min-w-28 text-[11.5px] max-sm:basis-full font-semibold tracking-wide text-muted uppercase", children: title }),
2321
- options.map((o) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2322
- Chip,
2323
- {
2324
- label: o.label,
2325
- count: o.count,
2326
- active: value === o.value,
2327
- onClick: () => onChange(value === o.value ? null : o.value)
2328
- },
2329
- o.value
2330
- ))
2331
- ] });
2332
- }
2333
- function RemovableChip({ label, onRemove }) {
2334
- return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { className: "inline-flex items-center gap-1 rounded-full bg-primary-tint py-0.5 pr-1 pl-2.5 text-[12px] font-medium text-primary", children: [
2335
- label,
2336
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2337
- "button",
2338
- {
2339
- type: "button",
2340
- "aria-label": `Remove ${label}`,
2341
- onClick: onRemove,
2342
- className: "inline-flex h-4.5 w-4.5 cursor-pointer items-center justify-center rounded-full hover:bg-primary hover:text-white",
2343
- children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.X, { size: 12 })
2344
- }
2345
- )
2346
- ] });
2347
- }
2348
-
2349
- // src/react/ui/Popover.tsx
2350
-
2351
-
2352
- // src/react/ui/useOutsideClose.ts
2353
-
2354
- function useOutsideClose(ref, open, onClose) {
2355
- _react.useEffect.call(void 0, () => {
2356
- if (!open) return;
2357
- const onClick = (e) => ref.current && e.composedPath().includes(ref.current) || onClose();
2358
- const onKey = (e) => e.key === "Escape" && onClose();
2359
- document.addEventListener("mousedown", onClick);
2360
- document.addEventListener("keydown", onKey);
2361
- return () => {
2362
- document.removeEventListener("mousedown", onClick);
2363
- document.removeEventListener("keydown", onKey);
2617
+ const list = _react.useMemo.call(void 0, () => {
2618
+ const shown = _chunk33XWO4KBcjs.filterQuestions.call(void 0, questions, seen, defs, values, searchOn ? search : "");
2619
+ return predicate ? shown.filter((q) => predicate(q, seen)) : shown;
2620
+ }, [questions, seen, defs, values, search, searchOn, predicate]);
2621
+ const groups = defs.map((d) => {
2622
+ const options = d.options(questions, answers);
2623
+ return {
2624
+ id: d.id,
2625
+ title: d.title,
2626
+ section: d.section,
2627
+ options,
2628
+ available: options.length > 0,
2629
+ value: _nullishCoalesce(values[d.id], () => ( null)),
2630
+ set: (v) => update(search, { ...values, [d.id]: v })
2364
2631
  };
2365
- }, [ref, open, onClose]);
2366
- }
2367
-
2368
- // src/react/ui/Popover.tsx
2369
-
2370
- function Popover({
2371
- label,
2372
- icon: Icon,
2373
- badge,
2374
- align = "left",
2375
- children
2376
- }) {
2377
- const [open, setOpen] = _react.useState.call(void 0, false);
2378
- const box2 = _react.useRef.call(void 0, null);
2379
- useOutsideClose(box2, open, () => setOpen(false));
2380
- return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { ref: box2, className: "relative", children: [
2381
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
2382
- "button",
2383
- {
2384
- type: "button",
2385
- "aria-expanded": open,
2386
- "aria-haspopup": "dialog",
2387
- onClick: () => setOpen((o) => !o),
2388
- className: `inline-flex cursor-pointer items-center gap-1.5 rounded-md border px-3 py-1.5 text-[13px] font-medium ${open || badge ? "border-primary bg-primary-soft text-primary" : "border-line-strong bg-white text-ink-2 hover:border-faint"}`,
2389
- children: [
2390
- Icon && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Icon, { size: 15 }),
2391
- label,
2392
- !!badge && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "inline-flex h-[18px] min-w-[18px] items-center justify-center rounded-full bg-primary px-1 text-[11px] font-bold text-white", children: badge })
2393
- ]
2394
- }
2395
- ),
2396
- open && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2397
- "div",
2398
- {
2399
- role: "dialog",
2400
- "aria-label": label,
2401
- className: `absolute z-30 mt-1.5 w-[min(560px,calc(100vw-24px))] max-sm:fixed max-sm:inset-x-3 max-sm:max-h-[70dvh] max-sm:w-auto max-sm:overflow-y-auto rounded-lg border border-line bg-white p-4 shadow-xl ${align === "right" ? "right-0" : "left-0"}`,
2402
- children
2403
- }
2404
- )
2405
- ] });
2632
+ });
2633
+ const picked = groups.filter((g) => g.value != null);
2634
+ return {
2635
+ groups,
2636
+ /** One group by id (undefined when not in `filters`). */
2637
+ group: (id) => groups.find((g) => g.id === id),
2638
+ /** The search text; null when search is off. */
2639
+ search: searchOn ? search : null,
2640
+ setSearch: (text) => update(text, values),
2641
+ values,
2642
+ /** Filters in use, as chips to take off one by one. */
2643
+ inUse: picked.map((g) => ({
2644
+ id: g.id,
2645
+ label: `${g.title}: ${_nullishCoalesce(_optionalChain([g, 'access', _99 => _99.options, 'access', _100 => _100.find, 'call', _101 => _101((o) => o.value === g.value), 'optionalAccess', _102 => _102.label]), () => ( g.value))}`,
2646
+ clear: () => g.set(null)
2647
+ })),
2648
+ active: !!search || picked.length > 0,
2649
+ clear: () => update("", {}),
2650
+ /** The questions that match, in form order. */
2651
+ list,
2652
+ total: questions.length,
2653
+ /** Bumps on every change (reset paging / scroll on it). */
2654
+ version
2655
+ };
2406
2656
  }
2407
2657
 
2408
- // src/react/ui/Tag.tsx
2409
-
2410
- var tones = {
2411
- success: "bg-success/15 text-success",
2412
- info: "bg-heading/20 text-primary",
2413
- muted: "bg-hover text-muted"
2414
- };
2415
- var Tag = ({ tone = "info", children }) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2416
- "span",
2417
- {
2418
- className: `inline-block rounded-full px-2.5 py-0.5 text-[11px] font-semibold whitespace-nowrap ${tones[tone]}`,
2419
- children
2420
- }
2421
- );
2422
-
2423
2658
  // src/react/components/QuestionList.tsx
2424
2659
 
2425
2660
  var PAGE = 100;
@@ -2430,75 +2665,32 @@ var SIZE = {
2430
2665
  file: "h-9 w-full sm:w-72",
2431
2666
  radio: "h-9 w-full"
2432
2667
  };
2433
- var gridSize = (q) => _nullishCoalesce(_optionalChain([q, 'access', _85 => _85.rows, 'optionalAccess', _86 => _86.reduce, 'call', _87 => _87((a, b) => a + b, 0)]), () => ( 0));
2668
+ var gridSize = (q) => _nullishCoalesce(_optionalChain([q, 'access', _103 => _103.rows, 'optionalAccess', _104 => _104.reduce, 'call', _105 => _105((a, b) => a + b, 0)]), () => ( 0));
2434
2669
  var wide = (t) => t === "textarea" || t === "radio" || t === "file";
2435
2670
  function QuestionList({
2436
2671
  questions,
2437
2672
  answers,
2438
- control
2673
+ control,
2674
+ filter: external,
2675
+ filters,
2676
+ search,
2677
+ hideUnavailable = true,
2678
+ toolbar = true,
2679
+ renderToolbar
2439
2680
  }) {
2440
- const [filter, setFilter] = _react.useState.call(void 0, _chunk5VHPTLLVcjs.NO_FILTER);
2681
+ const own = useQuestionFilter(questions, answers, { filters, search });
2682
+ const fs = _nullishCoalesce(external, () => ( own));
2683
+ const { list } = fs;
2441
2684
  const [shown, setShown] = _react.useState.call(void 0, PAGE);
2442
- const [seen, setSeen] = _react.useState.call(void 0, answers);
2443
- const set = (patch) => {
2444
- setFilter((f) => ({ ...f, ...patch }));
2445
- setSeen(answers);
2446
- setShown(PAGE);
2447
- };
2448
- const list = _react.useMemo.call(void 0, () => questions.filter((q) => _chunk5VHPTLLVcjs.matches.call(void 0, q, seen, filter)), [questions, seen, filter]);
2449
- const count = (f) => questions.filter(f).length;
2450
- const types = _react.useMemo.call(void 0, () => [...new Set(questions.flatMap((q) => q.parts.map((p) => p.field.type)))], [questions]);
2451
- const categories = _react.useMemo.call(void 0,
2452
- () => [...new Set(questions.map((q) => q.category).filter((c) => !!c))],
2453
- [questions]
2454
- );
2455
- const tagValues = _react.useMemo.call(void 0, () => {
2456
- const m = /* @__PURE__ */ new Map();
2457
- for (const q of questions)
2458
- for (const [k, v] of Object.entries(_nullishCoalesce(q.tags, () => ( {})))) m.set(k, (_nullishCoalesce(m.get(k), () => ( /* @__PURE__ */ new Set()))).add(v));
2459
- return [...m].map(
2460
- ([k, vs]) => [k, [...vs].sort((a, b) => a.localeCompare(b, void 0, { numeric: true }))]
2461
- );
2462
- }, [questions]);
2463
- const has = (re) => questions.some((q) => q.parts.some((p) => re.test(p.name) || re.test(p.field.label)));
2464
- const progress = [
2465
- ["answered", "Answered", "Answered", "Not answered"],
2466
- ["remarks", "Remarks", "Written", "Empty"],
2467
- ["comments", "Comments", "Written", "Empty"]
2468
- ].filter(([key]) => key === "answered" || has(key === "remarks" ? /remark/i : /comment/i));
2469
- const setTag = (key, value) => {
2470
- const tags = { ...filter.tags };
2471
- if (value == null) delete tags[key];
2472
- else tags[key] = value;
2473
- set({ tags });
2474
- };
2475
- const choiceCount = _react.useMemo.call(void 0, () => {
2476
- const m = /* @__PURE__ */ new Map();
2477
- for (const q of questions) for (const c of new Set(_chunk5VHPTLLVcjs.choicesOf.call(void 0, q))) m.set(c, (_nullishCoalesce(m.get(c), () => ( 0))) + 1);
2478
- return [...m].filter(([, n]) => n >= 2).slice(0, 40);
2479
- }, [questions]);
2480
- const [choiceMode, setChoiceMode] = _react.useState.call(void 0, "offered");
2481
- const choiceValue = choiceMode === "picked" ? filter.picked : filter.choices;
2482
- const pickedCount = _react.useMemo.call(void 0, () => {
2483
- const m = /* @__PURE__ */ new Map();
2484
- for (const q of questions) for (const c of new Set(_chunk5VHPTLLVcjs.pickedOf.call(void 0, q, answers))) m.set(c, (_nullishCoalesce(m.get(c), () => ( 0))) + 1);
2485
- return m;
2486
- }, [questions, answers]);
2487
- const inUse = [
2488
- ...progress.filter(([key]) => filter[key] !== "all").map(([key, title, yes, no]) => ({
2489
- label: `${title}: ${filter[key] === "filled" ? yes : no}`,
2490
- clear: () => set({ [key]: "all" })
2491
- })),
2492
- ...filter.type !== "all" ? [{ label: `Type: ${TYPE_LABEL[filter.type]}`, clear: () => set({ type: "all" }) }] : [],
2493
- ...Object.entries(filter.tags).map(([k, v]) => ({ label: `${k}: ${v}`, clear: () => setTag(k, null) })),
2494
- ...filter.choices !== "all" ? [{ label: `Has option: ${filter.choices}`, clear: () => set({ choices: "all" }) }] : [],
2495
- ...filter.picked !== "all" ? [{ label: `Answered: ${filter.picked}`, clear: () => set({ picked: "all" }) }] : []
2496
- ];
2497
- const active = JSON.stringify(filter) !== JSON.stringify(_chunk5VHPTLLVcjs.NO_FILTER);
2685
+ _react.useEffect.call(void 0, () => setShown(PAGE), [fs.version]);
2686
+ const groups = fs.groups.filter((g) => g.available || !hideUnavailable);
2687
+ const bar = groups.filter((g) => g.section === "bar");
2688
+ const menu = groups.filter((g) => g.section !== "bar");
2689
+ const sections = [...new Set(menu.map((g) => _nullishCoalesce(g.section, () => ( ""))))];
2498
2690
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "w-full p-3 sm:p-4 lg:px-6", children: [
2499
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "sticky top-0 z-10 -mx-3 mb-3 flex flex-col gap-2 border-b border-line bg-white/95 px-3 py-2.5 shadow-sm backdrop-blur sm:-mx-4 sm:px-4 lg:-mx-6 lg:px-6", children: [
2691
+ renderToolbar ? renderToolbar(fs) : toolbar && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "sticky top-0 z-10 -mx-3 mb-3 flex flex-col gap-2 border-b border-line bg-white/95 px-3 py-2.5 shadow-sm backdrop-blur sm:-mx-4 sm:px-4 lg:-mx-6 lg:px-6", children: [
2500
2692
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-wrap items-center gap-2", children: [
2501
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "label", { className: "relative min-w-0 flex-1 basis-full sm:basis-72", children: [
2693
+ fs.search != null && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "label", { className: "relative min-w-0 flex-1 basis-full sm:basis-72", children: [
2502
2694
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.Search, { size: 15, className: "absolute top-1/2 left-3 -translate-y-1/2 text-muted" }),
2503
2695
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2504
2696
  "input",
@@ -2506,132 +2698,62 @@ function QuestionList({
2506
2698
  type: "search",
2507
2699
  "aria-label": "Search questions",
2508
2700
  placeholder: "Search questions, sections, answers\u2026",
2509
- value: filter.search,
2510
- onChange: (e) => set({ search: e.target.value }),
2701
+ value: fs.search,
2702
+ onChange: (e) => fs.setSearch(e.target.value),
2511
2703
  className: "w-full rounded-full border border-line-strong bg-surface py-1.5 pr-3 pl-9 text-[13px] outline-none focus:border-primary focus:bg-white max-sm:text-base"
2512
2704
  }
2513
2705
  )
2514
2706
  ] }),
2515
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Popover, { label: "Filters", icon: _lucidereact.SlidersHorizontal, badge: inUse.length, align: "right", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col gap-4", children: [
2516
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, FilterSection, { title: "Progress", children: progress.map(([key, title, yes, no]) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2517
- ChipGroup,
2518
- {
2519
- title,
2520
- value: filter[key] === "all" ? null : filter[key],
2521
- onChange: (v) => set({ [key]: _nullishCoalesce(v, () => ( "all")) }),
2522
- options: [
2523
- { value: "filled", label: yes },
2524
- { value: "empty", label: no }
2525
- ]
2526
- },
2527
- key
2528
- )) }),
2529
- choiceCount.length > 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2530
- FilterSection,
2531
- {
2532
- title: "Answers",
2533
- action: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2534
- SegmentedTabs,
2535
- {
2536
- size: "sm",
2537
- value: choiceMode,
2538
- onChange: (m) => {
2539
- setChoiceMode(m);
2540
- const c = filter.choices !== "all" ? filter.choices : filter.picked;
2541
- if (c !== "all")
2542
- set(m === "picked" ? { picked: c, choices: "all" } : { choices: c, picked: "all" });
2543
- },
2544
- options: [
2545
- { value: "offered", label: "Has option" },
2546
- { value: "picked", label: "Answered" }
2547
- ]
2548
- }
2549
- ),
2550
- children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2551
- ChipGroup,
2552
- {
2553
- value: choiceValue === "all" ? null : choiceValue,
2554
- onChange: (v) => set(choiceMode === "picked" ? { picked: _nullishCoalesce(v, () => ( "all")) } : { choices: _nullishCoalesce(v, () => ( "all")) }),
2555
- options: choiceCount.map(([c, n]) => ({
2556
- value: c,
2557
- label: c,
2558
- count: choiceMode === "picked" ? _nullishCoalesce(pickedCount.get(c), () => ( 0)) : n
2559
- }))
2560
- }
2561
- )
2562
- }
2563
- ),
2564
- tagValues.length > 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, FilterSection, { title: "Question details", children: tagValues.map(([key, values]) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2565
- ChipGroup,
2566
- {
2567
- title: key,
2568
- value: _nullishCoalesce(filter.tags[key], () => ( null)),
2569
- onChange: (v) => setTag(key, v),
2570
- options: values.map((v) => ({ value: v, label: v, count: count((q) => _optionalChain([q, 'access', _88 => _88.tags, 'optionalAccess', _89 => _89[key]]) === v) }))
2571
- },
2572
- key
2573
- )) }),
2574
- types.length > 1 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, FilterSection, { title: "Answer type", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2575
- ChipGroup,
2576
- {
2577
- value: filter.type === "all" ? null : filter.type,
2578
- onChange: (v) => set({ type: _nullishCoalesce(v, () => ( "all")) }),
2579
- options: types.map((t) => ({
2580
- value: t,
2581
- label: TYPE_LABEL[t],
2582
- count: count((q) => q.parts.some((p) => p.field.type === t))
2583
- }))
2584
- }
2585
- ) })
2586
- ] }) }),
2707
+ menu.length > 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Popover2, { label: "Filters", icon: _lucidereact.SlidersHorizontal, badge: fs.inUse.length, align: "right", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex flex-col gap-4", children: sections.map((sec) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, FilterSection, { title: sec, children: menu.filter((g) => (_nullishCoalesce(g.section, () => ( ""))) === sec).map((g) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2708
+ ChipGroup2,
2709
+ {
2710
+ title: g.title,
2711
+ value: g.value,
2712
+ onChange: g.set,
2713
+ options: g.options
2714
+ },
2715
+ g.id
2716
+ )) }, sec)) }) }),
2587
2717
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { className: "text-[12.5px] text-muted sm:ml-auto", "aria-live": "polite", children: [
2588
2718
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "b", { className: "font-semibold text-ink-2", children: list.length }),
2589
2719
  " of ",
2590
- questions.length,
2720
+ fs.total,
2591
2721
  " questions"
2592
2722
  ] }),
2593
- active && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Button, { variant: "secondary", size: "sm", onClick: () => set(_chunk5VHPTLLVcjs.NO_FILTER), children: "Clear all" })
2723
+ fs.active && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Button2, { variant: "secondary", size: "sm", onClick: fs.clear, children: "Clear all" })
2594
2724
  ] }),
2595
- categories.length > 0 && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { role: "group", "aria-label": "Category", className: "flex flex-wrap items-center gap-1.5", children: [
2596
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "mr-1 text-[11.5px] font-semibold tracking-wide text-muted uppercase", children: "Category" }),
2597
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2598
- Chip,
2599
- {
2600
- label: "All",
2601
- count: questions.length,
2602
- active: filter.category === "all",
2603
- onClick: () => set({ category: "all" })
2604
- }
2605
- ),
2606
- categories.map((c) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2607
- Chip,
2725
+ bar.map((g) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { role: "group", "aria-label": g.title, className: "flex flex-wrap items-center gap-1.5", children: [
2726
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "mr-1 text-[11.5px] font-semibold tracking-wide text-muted uppercase", children: g.title }),
2727
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Chip2, { label: "All", count: fs.total, active: g.value == null, onClick: () => g.set(null) }),
2728
+ g.options.map((o) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2729
+ Chip2,
2608
2730
  {
2609
- label: c,
2610
- count: count((q) => q.category === c),
2611
- active: filter.category === c,
2612
- onClick: () => set({ category: filter.category === c ? "all" : c })
2731
+ label: o.label,
2732
+ count: o.count,
2733
+ active: g.value === o.value,
2734
+ onClick: () => g.set(g.value === o.value ? null : o.value)
2613
2735
  },
2614
- c
2736
+ o.value
2615
2737
  ))
2616
- ] }),
2617
- inUse.length > 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex flex-wrap items-center gap-1.5", children: inUse.map((f) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, RemovableChip, { label: f.label, onRemove: f.clear }, f.label)) })
2738
+ ] }, g.id)),
2739
+ fs.inUse.length > 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex flex-wrap items-center gap-1.5", children: fs.inUse.map((f) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, RemovableChip2, { label: f.label, onRemove: f.clear }, f.id)) })
2618
2740
  ] }),
2619
- list.length === 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, EmptyText, { children: "No question matches these filters." }),
2741
+ list.length === 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, EmptyText2, { children: "No question matches these filters." }),
2620
2742
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "ul", { className: "m-0 flex list-none flex-col gap-2 p-0", children: list.slice(0, shown).map((q, i, all) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _react.Fragment, { children: [
2621
- q.section && q.section !== _optionalChain([all, 'access', _90 => _90[i - 1], 'optionalAccess', _91 => _91.section]) && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "li", { className: "mt-2 flex flex-wrap items-center gap-x-2 gap-y-1 border-b border-line pb-1", children: [
2743
+ q.section && q.section !== _optionalChain([all, 'access', _106 => _106[i - 1], 'optionalAccess', _107 => _107.section]) && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "li", { className: "mt-2 flex flex-wrap items-center gap-x-2 gap-y-1 border-b border-line pb-1", children: [
2622
2744
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-[13.5px] font-semibold text-primary lg:text-[15px]", children: q.section }),
2623
- Object.entries(_nullishCoalesce(q.tags, () => ( {}))).map(([k, v]) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, Tag, { tone: "muted", children: [
2745
+ Object.entries(_nullishCoalesce(q.tags, () => ( {}))).map(([k, v]) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, Tag2, { tone: "muted", children: [
2624
2746
  k,
2625
2747
  ": ",
2626
2748
  v
2627
2749
  ] }, k))
2628
2750
  ] }),
2629
- q.intro && (q.intro !== _optionalChain([all, 'access', _92 => _92[i - 1], 'optionalAccess', _93 => _93.intro]) || q.section !== _optionalChain([all, 'access', _94 => _94[i - 1], 'optionalAccess', _95 => _95.section])) && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "li", { className: "rounded-md border-l-4 border-primary bg-primary-soft px-3 py-2 text-[13px] font-medium text-ink-2 lg:text-[14px]", children: q.intro }),
2751
+ q.intro && (q.intro !== _optionalChain([all, 'access', _108 => _108[i - 1], 'optionalAccess', _109 => _109.intro]) || q.section !== _optionalChain([all, 'access', _110 => _110[i - 1], 'optionalAccess', _111 => _111.section])) && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "li", { className: "rounded-md border-l-4 border-primary bg-primary-soft px-3 py-2 text-[13px] font-medium text-ink-2 lg:text-[14px]", children: q.intro }),
2630
2752
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "li", { className: "rounded-lg border border-line bg-white p-3", children: [
2631
2753
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "mb-2 flex items-start gap-2", children: [
2632
2754
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "m-0 min-w-0 flex-1 text-[13.5px] font-semibold whitespace-pre-line text-ink-2 lg:text-[15px]", children: q.title }),
2633
- q.category && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Tag, { tone: "muted", children: q.category }),
2634
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, Tag, { tone: "muted", children: [
2755
+ q.category && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Tag2, { tone: "muted", children: q.category }),
2756
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, Tag2, { tone: "muted", children: [
2635
2757
  "p.",
2636
2758
  q.page
2637
2759
  ] })
@@ -2658,7 +2780,7 @@ function QuestionList({
2658
2780
  ] })
2659
2781
  ] })
2660
2782
  ] }, q.id)) }),
2661
- list.length > shown && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "mt-3 text-center", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, Button, { variant: "secondary", size: "sm", onClick: () => setShown((n) => n + PAGE), children: [
2783
+ list.length > shown && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "mt-3 text-center", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, Button2, { variant: "secondary", size: "sm", onClick: () => setShown((n) => n + PAGE), children: [
2662
2784
  "Show more (",
2663
2785
  list.length - shown,
2664
2786
  " left)"
@@ -2686,7 +2808,7 @@ function OptionGrid({
2686
2808
  "span",
2687
2809
  {
2688
2810
  className: "min-w-0 cursor-pointer break-words",
2689
- onClick: (e) => _optionalChain([e, 'access', _96 => _96.currentTarget, 'access', _97 => _97.parentElement, 'optionalAccess', _98 => _98.querySelector, 'call', _99 => _99("input"), 'optionalAccess', _100 => _100.click, 'call', _101 => _101()]),
2811
+ onClick: (e) => _optionalChain([e, 'access', _112 => _112.currentTarget, 'access', _113 => _113.parentElement, 'optionalAccess', _114 => _114.querySelector, 'call', _115 => _115("input"), 'optionalAccess', _116 => _116.click, 'call', _117 => _117()]),
2690
2812
  children: name
2691
2813
  }
2692
2814
  )
@@ -2733,18 +2855,8 @@ function FilterSection({ title, action, children }) {
2733
2855
  ] });
2734
2856
  }
2735
2857
 
2736
- // src/react/FormFiller.tsx
2858
+ // src/react/hooks/useFormFiller.ts
2737
2859
 
2738
- var humanSize = (n) => {
2739
- if (!n) return "";
2740
- const units = ["B", "KB", "MB", "GB"];
2741
- let i = 0;
2742
- while (n >= 1024 && i < units.length - 1) {
2743
- n /= 1024;
2744
- i++;
2745
- }
2746
- return `${n.toFixed(i ? 1 : 0)} ${units[i]}`;
2747
- };
2748
2860
  function download(blob, name) {
2749
2861
  const url = URL.createObjectURL(blob);
2750
2862
  const a = document.createElement("a");
@@ -2753,11 +2865,9 @@ function download(blob, name) {
2753
2865
  a.click();
2754
2866
  setTimeout(() => URL.revokeObjectURL(url), 1e3);
2755
2867
  }
2756
- function FormFiller({
2757
- pdf: pdfSource,
2868
+ function useFormFiller({
2758
2869
  fields,
2759
2870
  layout = null,
2760
- title,
2761
2871
  initialAnswers,
2762
2872
  files: initialFiles = [],
2763
2873
  readOnly = false,
@@ -2766,61 +2876,54 @@ function FormFiller({
2766
2876
  autosave = 2500,
2767
2877
  onUpload,
2768
2878
  loadFile,
2769
- onBack,
2770
- toolbar,
2879
+ toQuestions: toQuestions2 = _chunk33XWO4KBcjs.toQuestions,
2771
2880
  notify = () => {
2772
2881
  },
2773
- onError: notifyError = (e) => console.error(e),
2774
- className = "h-full"
2882
+ onError: notifyError = (e) => console.error(e)
2775
2883
  }) {
2776
2884
  const [answers, setAnswers] = _react.useState.call(void 0, () => _nullishCoalesce(initialAnswers, () => ( _chunk7NZPYWL3cjs.defaultAnswers.call(void 0, fields))));
2777
2885
  const [files, setFiles] = _react.useState.call(void 0, initialFiles);
2778
2886
  const [signatures, setSignatures] = _react.useState.call(void 0, {});
2779
2887
  const [errors, setErrors] = _react.useState.call(void 0, {});
2780
- const [pdfWidth, setPdfWidth] = _react.useState.call(void 0, 595);
2781
- const pageWidth = Math.max(..._nullishCoalesce(_optionalChain([layout, 'optionalAccess', _102 => _102.pages, 'access', _103 => _103.map, 'call', _104 => _104((p) => p.width)]), () => ( [pdfWidth])));
2782
- const { zoom, setZoom, ref: fitRef } = useFitZoom(pageWidth);
2783
- const compact = useCompact();
2784
2888
  const [saveState, setSaveState] = _react.useState.call(void 0, "saved");
2785
2889
  const [hasSaved, setHasSaved] = _react.useState.call(void 0, !!initialAnswers);
2786
- const [confirmSubmit, setConfirmSubmit] = _react.useState.call(void 0, false);
2787
- const [loadError, setLoadError] = _react.useState.call(void 0, "");
2890
+ const [pdf, setPdf] = _react.useState.call(void 0, null);
2891
+ const [pdfSizes, setPdfSizes] = _react.useState.call(void 0, []);
2788
2892
  const queue = _react.useRef.call(void 0, Promise.resolve());
2789
2893
  const latest = _react.useRef.call(void 0, answers);
2790
2894
  _react.useEffect.call(void 0, () => {
2791
2895
  latest.current = answers;
2792
2896
  }, [answers]);
2793
2897
  const states = _react.useMemo.call(void 0, () => _chunk7NZPYWL3cjs.fieldStates.call(void 0, fields, answers), [fields, answers]);
2794
- const [view, setView] = _react.useState.call(void 0, "document");
2795
- const [pdf, setPdf] = _react.useState.call(void 0, null);
2898
+ const [wantText, setWantText] = _react.useState.call(void 0, false);
2796
2899
  const [pageText, setPageText] = _react.useState.call(void 0, null);
2797
2900
  _react.useEffect.call(void 0, () => {
2798
- if (view !== "list" || !pdf || pageText) return;
2901
+ if (!wantText || !pdf || pageText) return;
2799
2902
  let live = true;
2800
2903
  (async () => {
2801
2904
  const out = {};
2802
2905
  for (let i = 1; i <= pdf.numPages; i++) {
2803
2906
  const page = await pdf.getPage(i);
2804
- out[i] = _chunk5VHPTLLVcjs.toLines.call(void 0, (await page.getTextContent()).items, page.view);
2907
+ out[i] = _chunk33XWO4KBcjs.toLines.call(void 0, (await page.getTextContent()).items, page.view);
2805
2908
  }
2806
2909
  if (live) setPageText(out);
2807
2910
  })().catch(() => live && setPageText({}));
2808
2911
  return () => {
2809
2912
  live = false;
2810
2913
  };
2811
- }, [view, pdf, pageText]);
2812
- const visibleKeys = fields.filter((f) => _optionalChain([states, 'access', _105 => _105[f.key], 'optionalAccess', _106 => _106.visible])).map((f) => f.key).join(",");
2914
+ }, [wantText, pdf, pageText]);
2915
+ const visibleKeys = fields.filter((f) => _optionalChain([states, 'access', _118 => _118[f.key], 'optionalAccess', _119 => _119.visible])).map((f) => f.key).join(",");
2813
2916
  const questions = _react.useMemo.call(void 0, () => {
2814
2917
  const keys = new Set(visibleKeys.split(","));
2815
2918
  const textOf = (page) => {
2816
- const source = layout ? _optionalChain([layout, 'access', _107 => _107.pages, 'access', _108 => _108[page - 1], 'optionalAccess', _109 => _109.source]) : page;
2817
- return source ? _optionalChain([pageText, 'optionalAccess', _110 => _110[source]]) : void 0;
2919
+ const source = layout ? _optionalChain([layout, 'access', _120 => _120.pages, 'access', _121 => _121[page - 1], 'optionalAccess', _122 => _122.source]) : page;
2920
+ return source ? _optionalChain([pageText, 'optionalAccess', _123 => _123[source]]) : void 0;
2818
2921
  };
2819
- return _chunk5VHPTLLVcjs.toQuestions.call(void 0,
2922
+ return toQuestions2(
2820
2923
  fields.filter((f) => keys.has(f.key)),
2821
2924
  textOf
2822
2925
  );
2823
- }, [fields, layout, visibleKeys, pageText]);
2926
+ }, [fields, layout, visibleKeys, pageText, toQuestions2]);
2824
2927
  const loading = _react.useRef.call(void 0, /* @__PURE__ */ new Set());
2825
2928
  _react.useEffect.call(void 0, () => {
2826
2929
  if (!loadFile) return;
@@ -2849,7 +2952,7 @@ function FormFiller({
2849
2952
  return true;
2850
2953
  } catch (err) {
2851
2954
  setSaveState("error");
2852
- const fieldErrors = _optionalChain([err, 'optionalAccess', _111 => _111.errors]);
2955
+ const fieldErrors = _optionalChain([err, 'optionalAccess', _124 => _124.errors]);
2853
2956
  if (fieldErrors && typeof fieldErrors === "object") setErrors(fieldErrors);
2854
2957
  notifyError(err);
2855
2958
  return false;
@@ -2869,7 +2972,7 @@ function FormFiller({
2869
2972
  setAnswers((a) => ({ ...a, [f.key]: v }));
2870
2973
  setSaveState("dirty");
2871
2974
  if (errors[f.key]) {
2872
- const err = _chunk7NZPYWL3cjs.checkAnswer.call(void 0, f, v, _optionalChain([states, 'access', _112 => _112[f.key], 'optionalAccess', _113 => _113.required]));
2975
+ const err = _chunk7NZPYWL3cjs.checkAnswer.call(void 0, f, v, _optionalChain([states, 'access', _125 => _125[f.key], 'optionalAccess', _126 => _126.required]));
2873
2976
  setErrors((all) => {
2874
2977
  const rest = { ...all };
2875
2978
  delete rest[f.key];
@@ -2888,88 +2991,171 @@ function FormFiller({
2888
2991
  notifyError(err);
2889
2992
  }
2890
2993
  }
2891
- const fetchFile = (id, then) => _optionalChain([loadFile, 'optionalCall', _114 => _114(id), 'access', _115 => _115.then, 'call', _116 => _116(then, () => notifyError("Unable to open the file"))]);
2994
+ const fetchFile = (id, then) => _optionalChain([loadFile, 'optionalCall', _127 => _127(id), 'access', _128 => _128.then, 'call', _129 => _129(then, () => notifyError("Unable to open the file"))]);
2995
+ const openFile = (id) => fetchFile(id, (blob) => {
2996
+ const url = URL.createObjectURL(blob);
2997
+ window.open(url, "_blank");
2998
+ setTimeout(() => URL.revokeObjectURL(url), 6e4);
2999
+ });
3000
+ const downloadFile = (id, name) => fetchFile(id, (blob) => download(blob, name));
2892
3001
  async function submit() {
2893
- setConfirmSubmit(false);
2894
3002
  const found = _chunk7NZPYWL3cjs.validateAnswers.call(void 0, fields, answers);
2895
3003
  setErrors(found);
2896
- if (Object.keys(found).length) return notifyError("Some answers need attention");
2897
- if (await save(true)) {
2898
- notify("Submitted");
2899
- _optionalChain([onSubmitted, 'optionalCall', _117 => _117(latest.current)]);
3004
+ if (Object.keys(found).length) {
3005
+ notifyError("Some answers need attention");
3006
+ return false;
2900
3007
  }
3008
+ if (!await save(true)) return false;
3009
+ notify("Submitted");
3010
+ _optionalChain([onSubmitted, 'optionalCall', _130 => _130(latest.current)]);
3011
+ return true;
2901
3012
  }
2902
- if (loadError) return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "fl-root p-6 text-center text-sm text-danger", children: loadError });
2903
3013
  const fileOf = (id) => files.find((x) => x.id === id);
2904
- const attachments = files.filter(
2905
- (x) => fields.some((f) => f.type === "file" && f.key === x.fieldKey && answers[f.key] === x.id)
2906
- );
2907
- const errorList = fields.filter((f) => errors[f.key]);
3014
+ return {
3015
+ answers,
3016
+ /** Visible / required / readOnly per field key, from the conditions and current answers. */
3017
+ states,
3018
+ /** Field key → message. */
3019
+ errors,
3020
+ setErrors,
3021
+ /** Fields with an error, in form order. */
3022
+ errorList: fields.filter((f) => errors[f.key]),
3023
+ change,
3024
+ save,
3025
+ submit,
3026
+ saveState,
3027
+ hasSaved,
3028
+ readOnly,
3029
+ files,
3030
+ fileOf,
3031
+ /** Files of upload fields that are answers now. */
3032
+ attachments: files.filter(
3033
+ (x) => fields.some((f) => f.type === "file" && f.key === x.fieldKey && answers[f.key] === x.id)
3034
+ ),
3035
+ attach,
3036
+ canUpload: !!onUpload,
3037
+ canLoadFiles: !!loadFile,
3038
+ openFile,
3039
+ downloadFile,
3040
+ /** Image src of a signature answer (stored file or data URL). */
3041
+ signatureSrc: (f) => signatures[String(answers[f.key])],
3042
+ /** Visible fields grouped as questions (tables, option groups), titled from the PDF text once loaded. */
3043
+ questions,
3044
+ /** Reads the PDF text so `questions` get real titles (call when you first show them). */
3045
+ loadPageText: () => setWantText(true),
3046
+ pdf,
3047
+ pdfSizes,
3048
+ /** Pass to PdfPages' onLoaded. */
3049
+ onPdfLoaded: (sizes2, doc) => {
3050
+ setPdf(doc);
3051
+ setPdfSizes(sizes2);
3052
+ }
3053
+ };
3054
+ }
3055
+
3056
+ // src/react/FormFiller.tsx
3057
+
3058
+ var humanSize = (n) => {
3059
+ if (!n) return "";
3060
+ const units = ["B", "KB", "MB", "GB"];
3061
+ let i = 0;
3062
+ while (n >= 1024 && i < units.length - 1) {
3063
+ n /= 1024;
3064
+ i++;
3065
+ }
3066
+ return `${n.toFixed(i ? 1 : 0)} ${units[i]}`;
3067
+ };
3068
+ function FormFiller({
3069
+ pdf: pdfSource,
3070
+ title,
3071
+ onBack,
3072
+ toolbar,
3073
+ components,
3074
+ hide = [],
3075
+ views = ["document", "list"],
3076
+ listFilters,
3077
+ listSearch,
3078
+ hideUnavailableFilters,
3079
+ renderFilters,
3080
+ confirmSubmit: askFirst = true,
3081
+ className = "h-full",
3082
+ ...options
3083
+ }) {
3084
+ const shows = (p) => !hide.includes(p);
3085
+ const ff = useFormFiller(options);
3086
+ const { fields, readOnly = false, onSave } = options;
3087
+ const layout = _nullishCoalesce(options.layout, () => ( null));
3088
+ const { answers, states, errors } = ff;
3089
+ const pdfWidth = ff.pdfSizes.length ? Math.max(...ff.pdfSizes.map((p) => p.width)) : 595;
3090
+ const { zoom, setZoom, ref: fitRef } = useFitZoom(Math.max(..._nullishCoalesce(_optionalChain([layout, 'optionalAccess', _131 => _131.pages, 'access', _132 => _132.map, 'call', _133 => _133((p) => p.width)]), () => ( [pdfWidth]))));
3091
+ const compact = useCompact();
3092
+ const [confirmSubmit, setConfirmSubmit] = _react.useState.call(void 0, false);
3093
+ const [loadError, setLoadError] = _react.useState.call(void 0, "");
3094
+ const [view, setView] = _react.useState.call(void 0, _nullishCoalesce(views[0], () => ( "document")));
3095
+ const { loadPageText } = ff;
3096
+ _react.useEffect.call(void 0, () => {
3097
+ if (view === "list") loadPageText();
3098
+ }, [view, loadPageText]);
3099
+ if (loadError) return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "fl-root p-6 text-center text-sm text-danger", children: loadError });
2908
3100
  const control = (f) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
2909
3101
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2910
- FieldControl,
3102
+ AnswerControl,
2911
3103
  {
3104
+ components,
2912
3105
  field: f,
2913
3106
  value: answers[f.key],
2914
- readOnly: readOnly || states[f.key].readOnly || f.type === "file" && !onUpload,
3107
+ readOnly: readOnly || states[f.key].readOnly || f.type === "file" && !ff.canUpload,
2915
3108
  compact,
2916
3109
  error: errors[f.key],
2917
- onChange: (v) => change(f, v),
2918
- fileName: _optionalChain([fileOf, 'call', _118 => _118(answers[f.key]), 'optionalAccess', _119 => _119.fileName]),
2919
- signatureSrc: signatures[String(answers[f.key])],
2920
- onFile: onUpload ? (file) => void attach(f, file) : void 0,
2921
- onOpenFile: () => fetchFile(String(answers[f.key]), (blob) => {
2922
- const url = URL.createObjectURL(blob);
2923
- window.open(url, "_blank");
2924
- setTimeout(() => URL.revokeObjectURL(url), 6e4);
2925
- })
3110
+ onChange: (v) => ff.change(f, v),
3111
+ fileName: _optionalChain([ff, 'access', _134 => _134.fileOf, 'call', _135 => _135(answers[f.key]), 'optionalAccess', _136 => _136.fileName]),
3112
+ signatureSrc: ff.signatureSrc(f),
3113
+ onFile: ff.canUpload ? (file) => void ff.attach(f, file) : void 0,
3114
+ onOpenFile: () => ff.openFile(String(answers[f.key]))
2926
3115
  }
2927
3116
  ),
2928
- states[f.key].required && !readOnly && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "pointer-events-none absolute -top-1.5 -right-1.5 text-[12px] font-bold text-danger", children: "*" })
3117
+ states[f.key].required && !readOnly && shows("requiredMark") && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "pointer-events-none absolute -top-1.5 -right-1.5 text-[12px] font-bold text-danger", children: "*" })
2929
3118
  ] });
2930
- return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: `fl-root flex min-h-[min(600px,100dvh)] flex-col bg-white text-ink ${className}`, children: [
3119
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, FormliftProvider, { components, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: `fl-root flex min-h-[min(600px,100dvh)] flex-col bg-white text-ink ${className}`, children: [
2931
3120
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-wrap items-center gap-3 border-b border-line bg-white px-4 py-2.5", children: [
2932
- onBack && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Button, { variant: "secondary", size: "sm", icon: _lucidereact.ArrowLeft, onClick: onBack, children: "Back" }),
2933
- title != null && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h2", { className: "m-0 min-w-0 flex-1 truncate text-[17px] font-semibold max-sm:text-[15px] sm:flex-none", children: title }),
2934
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2935
- SegmentedTabs,
3121
+ onBack && shows("back") && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Button2, { variant: "secondary", size: "sm", icon: _lucidereact.ArrowLeft, onClick: onBack, children: "Back" }),
3122
+ title != null && shows("title") && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h2", { className: "m-0 min-w-0 flex-1 truncate text-[17px] font-semibold max-sm:text-[15px] sm:flex-none", children: title }),
3123
+ views.length > 1 && shows("views") && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
3124
+ SegmentedTabs2,
2936
3125
  {
2937
- options: [
2938
- { value: "document", label: "Document" },
2939
- { value: "list", label: "List" }
2940
- ],
3126
+ options: views.map((v) => ({ value: v, label: v === "document" ? "Document" : "List" })),
2941
3127
  value: view,
2942
3128
  onChange: setView
2943
3129
  }
2944
3130
  ),
2945
3131
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "ml-auto flex flex-wrap items-center gap-2 max-sm:w-full max-sm:justify-end", children: [
2946
- view === "document" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ZoomControls, { zoom, onChange: setZoom }),
3132
+ view === "document" && shows("zoom") && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ZoomControls, { zoom, onChange: setZoom }),
2947
3133
  !readOnly && onSave && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
2948
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-right text-[12px] text-muted sm:w-24", "aria-live": "polite", children: {
2949
- saved: hasSaved ? "Draft saved" : "",
3134
+ shows("saveStatus") && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-right text-[12px] text-muted sm:w-24", "aria-live": "polite", children: {
3135
+ saved: ff.hasSaved ? "Draft saved" : "",
2950
3136
  dirty: "Unsaved",
2951
3137
  saving: "Saving\u2026",
2952
3138
  error: "Not saved"
2953
- }[saveState] }),
2954
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Button, { variant: "secondary", size: "sm", icon: _lucidereact.Save, title: "Save draft", onClick: () => void save(), children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "max-sm:hidden", children: "Save draft" }) }),
2955
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Button, { size: "sm", icon: _lucidereact.Send, onClick: () => setConfirmSubmit(true), children: "Submit" })
3139
+ }[ff.saveState] }),
3140
+ shows("saveDraft") && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Button2, { variant: "secondary", size: "sm", icon: _lucidereact.Save, title: "Save draft", onClick: () => void ff.save(), children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "max-sm:hidden", children: "Save draft" }) }),
3141
+ shows("submit") && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Button2, { size: "sm", icon: _lucidereact.Send, onClick: () => askFirst ? setConfirmSubmit(true) : void ff.submit(), children: "Submit" })
2956
3142
  ] }),
2957
3143
  toolbar
2958
3144
  ] })
2959
3145
  ] }),
2960
- attachments.length > 0 && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-wrap items-center gap-x-3 gap-y-1 border-b border-line bg-white px-4 py-1.5 text-[12.5px]", children: [
3146
+ ff.attachments.length > 0 && shows("attachments") && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-wrap items-center gap-x-3 gap-y-1 border-b border-line bg-white px-4 py-1.5 text-[12.5px]", children: [
2961
3147
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { className: "inline-flex items-center gap-1 font-semibold text-ink-2", children: [
2962
3148
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.Paperclip, { size: 13 }),
2963
3149
  " Attachments"
2964
3150
  ] }),
2965
- attachments.map((x) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
3151
+ ff.attachments.map((x) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
2966
3152
  "button",
2967
3153
  {
2968
3154
  type: "button",
2969
3155
  title: `Download ${x.fileName}`,
2970
- disabled: !loadFile,
3156
+ disabled: !ff.canLoadFiles,
2971
3157
  className: "inline-flex max-w-full cursor-pointer items-center gap-1 text-primary hover:underline disabled:cursor-default",
2972
- onClick: () => fetchFile(x.id, (blob) => download(blob, x.fileName)),
3158
+ onClick: () => ff.downloadFile(x.id, x.fileName),
2973
3159
  children: [
2974
3160
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "truncate", children: x.fileName }),
2975
3161
  x.fileSize ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { className: "text-muted", children: [
@@ -2977,39 +3163,58 @@ function FormFiller({
2977
3163
  humanSize(x.fileSize),
2978
3164
  ")"
2979
3165
  ] }) : null,
2980
- loadFile && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.Download, { size: 12 })
3166
+ ff.canLoadFiles && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.Download, { size: 12 })
2981
3167
  ]
2982
3168
  },
2983
3169
  x.id
2984
3170
  ))
2985
3171
  ] }),
2986
- errorList.length > 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "ul", { className: "m-0 border-b border-danger/30 bg-danger/5 px-6 py-2 text-[13px] text-danger", children: errorList.map((f) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "li", { children: [
3172
+ ff.errorList.length > 0 && shows("errors") && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "ul", { className: "m-0 border-b border-danger/30 bg-danger/5 px-6 py-2 text-[13px] text-danger", children: ff.errorList.map((f) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "li", { children: [
2987
3173
  "Page ",
2988
3174
  f.position.page,
2989
3175
  ": ",
2990
3176
  errors[f.key]
2991
3177
  ] }, f.key)) }),
2992
- view === "list" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex-1 overflow-auto bg-hover", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, QuestionList, { questions, answers, control }) }),
3178
+ view === "list" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex-1 overflow-auto bg-hover", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
3179
+ QuestionList,
3180
+ {
3181
+ questions: ff.questions,
3182
+ answers,
3183
+ control,
3184
+ filters: listFilters,
3185
+ search: listSearch,
3186
+ hideUnavailable: hideUnavailableFilters,
3187
+ renderToolbar: renderFilters
3188
+ }
3189
+ ) }),
2993
3190
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { ref: fitRef, className: `flex-1 overflow-auto bg-hover ${view === "list" ? "hidden" : ""}`, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2994
3191
  PdfPages,
2995
3192
  {
2996
3193
  load: pdfSource,
2997
3194
  zoom,
2998
- pages: _optionalChain([layout, 'optionalAccess', _120 => _120.pages]),
2999
- onLoaded: (sizes2, doc) => {
3000
- setPdf(doc);
3001
- if (sizes2.length) setPdfWidth(Math.max(...sizes2.map((p) => p.width)));
3002
- },
3195
+ pages: _optionalChain([layout, 'optionalAccess', _137 => _137.pages]),
3196
+ onLoaded: ff.onPdfLoaded,
3003
3197
  onError: () => setLoadError("The document could not be shown"),
3004
3198
  overlay: (page) => [
3005
3199
  // The admin's text / boxes / lines first, the answer controls on top.
3006
- ...(_nullishCoalesce(_optionalChain([layout, 'optionalAccess', _121 => _121.elements]), () => ( []))).filter((el) => el.page === page).map((el) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, LayoutElementView, { element: el, pageHeight: _nullishCoalesce(_optionalChain([layout, 'access', _122 => _122.pages, 'access', _123 => _123[page - 1], 'optionalAccess', _124 => _124.height]), () => ( 842)) }, el.id)),
3007
- ...fields.filter((f) => f.position.page === page && _optionalChain([states, 'access', _125 => _125[f.key], 'optionalAccess', _126 => _126.visible])).map((f) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "absolute [container-type:size]", style: _chunk5VHPTLLVcjs.boxStyle.call(void 0, f.position), children: control(f) }, f.id))
3200
+ ...(_nullishCoalesce(_optionalChain([layout, 'optionalAccess', _138 => _138.elements]), () => ( []))).filter((el) => el.page === page).map((el) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, LayoutElementView, { element: el, pageHeight: _nullishCoalesce(_optionalChain([layout, 'access', _139 => _139.pages, 'access', _140 => _140[page - 1], 'optionalAccess', _141 => _141.height]), () => ( 842)) }, el.id)),
3201
+ ...fields.filter((f) => f.position.page === page && _optionalChain([states, 'access', _142 => _142[f.key], 'optionalAccess', _143 => _143.visible])).map((f) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "absolute [container-type:size]", style: _chunk33XWO4KBcjs.boxStyle.call(void 0, f.position), children: control(f) }, f.id))
3008
3202
  ]
3009
3203
  }
3010
3204
  ) }),
3011
- confirmSubmit && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ConfirmModal, { confirmLabel: "Submit", onConfirm: () => void submit(), onCancel: () => setConfirmSubmit(false), children: "Submit this form? You cannot change the answers afterwards." })
3012
- ] });
3205
+ confirmSubmit && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
3206
+ ConfirmModal2,
3207
+ {
3208
+ confirmLabel: "Submit",
3209
+ onConfirm: () => {
3210
+ setConfirmSubmit(false);
3211
+ void ff.submit();
3212
+ },
3213
+ onCancel: () => setConfirmSubmit(false),
3214
+ children: "Submit this form? You cannot change the answers afterwards."
3215
+ }
3216
+ )
3217
+ ] }) });
3013
3218
  }
3014
3219
 
3015
3220
 
@@ -3019,5 +3224,16 @@ function FormFiller({
3019
3224
 
3020
3225
 
3021
3226
 
3022
- exports.FieldControl = FieldControl; exports.FormEditor = FormEditor; exports.FormFiller = FormFiller; exports.PdfPages = PdfPages; exports.TYPE_LABEL = TYPE_LABEL; exports.readPdf = readPdf; exports.setPdfWorker = setPdfWorker;
3227
+
3228
+
3229
+
3230
+
3231
+
3232
+
3233
+
3234
+
3235
+
3236
+
3237
+
3238
+ exports.AnswerControl = AnswerControl; exports.FieldControl = FieldControl; exports.FormEditor = FormEditor; exports.FormFiller = FormFiller; exports.FormliftProvider = FormliftProvider; exports.LayoutElementView = LayoutElementView; exports.PdfPages = PdfPages; exports.QuestionList = QuestionList; exports.TYPE_LABEL = TYPE_LABEL; exports.defaultComponents = defaultComponents; exports.defaultFilters = defaultFilters; exports.readPdf = readPdf; exports.setPdfWorker = setPdfWorker; exports.useFitZoom = useFitZoom; exports.useFormEditor = useFormEditor; exports.useFormFiller = useFormFiller; exports.useQuestionFilter = useQuestionFilter; exports.useUndo = useUndo;
3023
3239
  //# sourceMappingURL=index.cjs.map