@formancy/react 0.11.0 → 0.13.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.
package/dist/index.d.mts CHANGED
@@ -27,8 +27,8 @@ export declare function useFormText(): FormText$1;
27
27
  //#endregion
28
28
  //#region src/use-field.d.ts
29
29
  interface FieldBinding extends FieldSnapshot {
30
- setValue(value: unknown): void;
31
- touch(): void;
30
+ setValue(this: void, value: unknown): void;
31
+ touch(this: void): void;
32
32
  /** Spread onto the input/select/textarea element. */
33
33
  controlProps: ControlProps;
34
34
  /** Spread onto the label element. */
@@ -170,6 +170,13 @@ interface FormancyFormProps {
170
170
  * step offers "Check your answers" in place of sending (0204). Off unless asked for.
171
171
  */
172
172
  review?: boolean;
173
+ /**
174
+ * The host's own content under a field, by the field's path (a row's field by its own, as its
175
+ * wrapper's `data-formancy-field-path` says), or nothing: in the field's wrapper, after its
176
+ * label, description, control and error, as `data-formancy-part="field-addition"` (0233). A
177
+ * constant: a new function on every render redraws every field's addition.
178
+ */
179
+ fieldAddition?: (path: string) => ReactNode;
173
180
  onSubmit?: (outcome: SubmitOutcome) => void;
174
181
  }
175
182
  //#endregion
@@ -395,7 +402,7 @@ interface UploadOptions {
395
402
  /** Aborted when the person cancels this file. Hand it to `fetch` and the transfer stops. */
396
403
  signal: AbortSignal;
397
404
  /** Bytes sent so far, of how many. `fetch` cannot report an upload's progress; XHR can. */
398
- onProgress(sent: number, total: number): void;
405
+ onProgress(this: void, sent: number, total: number): void;
399
406
  }
400
407
  /**
401
408
  * Uploads one file and reports what was stored.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/context.tsx","../src/use-field.ts","../src/use-repeater.ts","../src/use-wizard.ts","../src/use-submit.ts","../src/go-to-field.ts","../src/fields/internals.tsx","../src/form.tsx","../src/error-summary.tsx","../src/rich-text.tsx","../src/options-source.ts","../src/scanning.ts","../src/uploads.ts","../src/rich-text-editor.ts","../src/resume-notice.tsx"],"mappings":";;;;;wBAsBgB,mBACd,QACA,OACA;EAEA,QAAQ;;;;;;;EAOR,QAAQ;EACR,WAAW;oBACZ,IAAA;wBAsBe,iBAAiB;;;;;;;;;wBAkBjB,eAAe;;;UCvEd,qBAAqB;EACpC,SAAS;EACT;;EAEA,cAAc;;EAEd;IAAc;IAAY;;;EAE1B;IAAc;;;;;;;;;;;;;wBAaA,SAAS,eAAe,OAAO;;;UCrB9B;EACf;;EAEA;;EAEA;;EAEA;EACA;EACA,UAAU;;EAEV,QAAQ,cAAc;;;;;;;wBAQR,YAAY,eAAe,OAAO;;;UCrBjC;EACf;EACA;;;EAGA;EACA;;EAEA,QAAQ;EACR;;EAEA,KAAK;;;;;;;wBAQS,aAAa;;;;;;;;;;;wBCTb;EAAqB;EAAa,QAAQ;;;;;;;;;;;wBCD1C,iBAAiB;;;;;;;;;;;;;;;;UCYhB;EACf;EACA;;KAGU,iBAAiB,cAAc;UAE1B;EACf,SAAS,QAAQ,OAAO,WAAW;EACnC,SAAS,eAAe;;UAGT;EACf;EACA,QAAQ;;EAER;;UAGe;;;;;;;EAOf,SAAS;EACT,WAAW;;;;;;;EAOX;EACA;;;;;EAKA;EACA,YAAY,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;wBCdP,aAAa,OAAO,oCAAiB,IAAA;;;UC7CpC;EACf,SAAS;;;;;;;;;;;wBAYK,eAAe,UAAU,oCAAiB,IAAA;;;;;;;;;;;;;;;;;;;;wBCG1C,WAAW;EAAY;IAAmB;;;;;;;;;;UCZzC;;;;;EAKf;;EAEA;;EAEA;;EAEA;;EAEA;;;;;;;;;EASA;;;;;;;;EAQA;;EAEA,QAAQ;;;;;;;;;;;UAYO;;;;;;;;;;;;;EAaf,QAAQ,SAAS,iBAAiB,QAAQ;;EAE1C;;;;;;EAMA;;EAEA;;;;;;;;;;;;;KAcU,iBAAiB,SAAS,eAAe;qBAIxC,wCAAsB,SAAA,SAAA,eAAA;;;;;;;;;wBAUnB,qBAAqB;;;;;;;;;;;;UC9FpB;;EAEf;;EAEA;;;;;;;;;;;;;;;;;;;KAoBU,WAAW,SAAS,gBAAgB;qBAInC,iCAAe,SAAA;;;;;;;;wBASZ,cAAc;;;;;;;;;;;UC/Bb;;;;;EAKf;;EAEA,QAAQ;;EAER,WAAW,cAAc;;;;;;;;;;;;KAaf,YAAY,MAAM,MAAM,SAAS,kBAAkB,QAAQ;qBAI1D,kCAAgB,SAAA;;;;;;;;;wBAUb,eAAe;;;;;;;;;;;;;;;;;;;;;UChCd;;EAEf;;EAEA,WAAW;;;;;;;;;;;;;EAaX,MAAM,SAAS,aAAa;;EAE5B,WAAW,SAAS;EACpB;;UAGe;;WAEN,SAAS;;WAET;;WAEA,WAAW;WACX;;;;;;;;;;WAUA,YAAY,SAAS;;KAGpB,yBAAyB,OAAO,wBAAwB;qBAIvD,wCAAsB,SAAA;;;;;;;;;wBAUnB,4BAA4B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UC9C3B;WACN;WACA,SAAS;aAAyB;aAAuB;;;UAGnD;;WAEN,YAAY;;WAEZ,SAAS,SAAS;;wBAGb,eAAe,WAAW,UAAU,oBAAoB"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/context.tsx","../src/use-field.ts","../src/use-repeater.ts","../src/use-wizard.ts","../src/use-submit.ts","../src/go-to-field.ts","../src/fields/internals.tsx","../src/form.tsx","../src/error-summary.tsx","../src/rich-text.tsx","../src/options-source.ts","../src/scanning.ts","../src/uploads.ts","../src/rich-text-editor.ts","../src/resume-notice.tsx"],"mappings":";;;;;wBAsBgB,mBACd,QACA,OACA;EAEA,QAAQ;;;;;;;EAOR,QAAQ;EACR,WAAW;oBACZ,IAAA;wBAsBe,iBAAiB;;;;;;;;;wBAkBjB,eAAe;;;UCvEd,qBAAqB;EACpC,SAAS,YAAY;EACrB,MAAM;;EAEN,cAAc;;EAEd;IAAc;IAAY;;;EAE1B;IAAc;;;;;;;;;;;;;wBAaA,SAAS,eAAe,OAAO;;;UCrB9B;EACf;;EAEA;;EAEA;;EAEA;EACA;EACA,UAAU;;EAEV,QAAQ,cAAc;;;;;;;wBAQR,YAAY,eAAe,OAAO;;;UCrBjC;EACf;EACA;;;EAGA;EACA;;EAEA,QAAQ;EACR;;EAEA,KAAK;;;;;;;wBAQS,aAAa;;;;;;;;;;;wBCTb;EAAqB;EAAa,QAAQ;;;;;;;;;;;wBCD1C,iBAAiB;;;;;;;;;;;;;;;;UCYhB;EACf;EACA;;KAGU,iBAAiB,cAAc;UAE1B;EACf,SAAS,QAAQ,OAAO,WAAW;EACnC,SAAS,eAAe;;UAGT;EACf;EACA,QAAQ;;EAER;;UAGe;;;;;;;EAOf,SAAS;EACT,WAAW;;;;;;;EAOX;EACA;;;;;EAKA;;;;;;;EAOA,iBAAiB,iBAAiB;EAClC,YAAY,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;wBC/BP,aAAa,OAAO,oCAAiB,IAAA;;;UCnCpC;EACf,SAAS;;;;;;;;;;;wBAYK,eAAe,UAAU,oCAAiB,IAAA;;;;;;;;;;;;;;;;;;;;wBCG1C,WAAW;EAAY;IAAmB;;;;;;;;;;UCZzC;;;;;EAKf;;EAEA;;EAEA;;EAEA;;EAEA;;;;;;;;;EASA;;;;;;;;EAQA;;EAEA,QAAQ;;;;;;;;;;;UAYO;;;;;;;;;;;;;EAaf,QAAQ,SAAS,iBAAiB,QAAQ;;EAE1C;;;;;;EAMA;;EAEA;;;;;;;;;;;;;KAcU,iBAAiB,SAAS,eAAe;qBAIxC,wCAAsB,SAAA,SAAA,eAAA;;;;;;;;;wBAUnB,qBAAqB;;;;;;;;;;;;UC9FpB;;EAEf;;EAEA;;;;;;;;;;;;;;;;;;;KAoBU,WAAW,SAAS,gBAAgB;qBAInC,iCAAe,SAAA;;;;;;;;wBASZ,cAAc;;;;;;;;;;;UC/Bb;;;;;EAKf;;EAEA,QAAQ;;EAER,WAAW,YAAY,cAAc;;;;;;;;;;;;KAa3B,YAAY,MAAM,MAAM,SAAS,kBAAkB,QAAQ;qBAI1D,kCAAgB,SAAA;;;;;;;;;wBAUb,eAAe;;;;;;;;;;;;;;;;;;;;;UChCd;;EAEf;;EAEA,WAAW;;;;;;;;;;;;;EAaX,MAAM,SAAS,aAAa;;EAE5B,WAAW,SAAS;EACpB;;UAGe;;WAEN,SAAS;;WAET;;WAEA,WAAW;WACX;;;;;;;;;;WAUA,YAAY,SAAS;;KAGpB,yBAAyB,OAAO,wBAAwB;qBAIvD,wCAAsB,SAAA;;;;;;;;;wBAUnB,4BAA4B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UC9C3B;WACN;WACA,SAAS;aAAyB;aAAuB;;;UAGnD;;WAEN,YAAY;;WAEZ,SAAS,SAAS;;wBAGb,eAAe,WAAW,UAAU,oBAAoB"}
package/dist/index.mjs CHANGED
@@ -337,7 +337,7 @@ function CodeNode({ schema, node, locale }) {
337
337
  const label = resolveText(schema, node.label, locale);
338
338
  const labelId = useId();
339
339
  const value = useField(node.path).value;
340
- const text = typeof value === "string" ? value : value === null || value === void 0 ? "" : String(value);
340
+ const text = typeof value === "string" ? value : typeof value === "number" || typeof value === "boolean" ? String(value) : "";
341
341
  return /* @__PURE__ */ jsxs("div", {
342
342
  "data-formancy-part": "code",
343
343
  "data-state": text === "" ? "empty" : "ready",
@@ -378,11 +378,6 @@ function CodeDrawing({ value }) {
378
378
  children: modules
379
379
  });
380
380
  }
381
- function placedPaths(nodes, into = []) {
382
- for (const node of nodes) if (node.kind === "field") into.push(node.path);
383
- else placedPaths(layoutChildren(node), into);
384
- return into;
385
- }
386
381
  //#endregion
387
382
  //#region src/focus-row.ts
388
383
  function focusRow(repeater, target, add) {
@@ -427,12 +422,12 @@ function useReview(goTo) {
427
422
  const goToField = useGoToField();
428
423
  return {
429
424
  reviewing,
430
- check() {
425
+ check: () => {
431
426
  if (submit().ok) return setReviewing(true);
432
427
  const firstInvalid = engine.firstInvalid();
433
428
  if (firstInvalid !== null) goTo?.(engine.pageOf(parsePath(firstInvalid)));
434
429
  },
435
- change(answer) {
430
+ change: (answer) => {
436
431
  setReviewing(false);
437
432
  goToField(answer.field);
438
433
  }
@@ -498,48 +493,115 @@ function Review({ onChange, children }) {
498
493
  });
499
494
  }
500
495
  //#endregion
501
- //#region src/rich-text.tsx
502
- function RichText({ source }) {
503
- const blocks = parseRichText(source);
504
- if (blocks.length === 0) return null;
496
+ //#region src/field-addition.tsx
497
+ const FieldAdditionContext = createContext(void 0);
498
+ function FieldAdditionSlot({ path }) {
499
+ const content = useContext(FieldAdditionContext)?.(path);
500
+ if (content === void 0 || content === null || typeof content === "boolean") return null;
505
501
  return /* @__PURE__ */ jsx("div", {
506
- "data-formancy-part": "richtext",
507
- children: blocks.map((block, index) => /* @__PURE__ */ jsx(Block, { block }, index))
502
+ "data-formancy-part": "field-addition",
503
+ children: content
508
504
  });
509
505
  }
510
- function Block({ block }) {
511
- if (block.kind === "paragraph") return /* @__PURE__ */ jsx("p", { children: /* @__PURE__ */ jsx(Inlines, { nodes: block.children }) });
512
- const items = block.items.map((item, index) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(Inlines, { nodes: item }) }, index));
513
- return block.ordered ? /* @__PURE__ */ jsx("ol", { children: items }) : /* @__PURE__ */ jsx("ul", { children: items });
506
+ //#endregion
507
+ //#region src/fields/internals.tsx
508
+ function ErrorText({ field }) {
509
+ const text = useFormText();
510
+ return /* @__PURE__ */ jsx("p", {
511
+ "data-formancy-part": "error",
512
+ ...field.errorProps,
513
+ children: field.errors.map((code, index) => /* @__PURE__ */ jsxs(Fragment, { children: [index > 0 ? " " : null, /* @__PURE__ */ jsx("span", {
514
+ "data-formancy-code": code,
515
+ children: errorSentence(text, field.def, code, field.messages)
516
+ })] }, code))
517
+ });
514
518
  }
515
- function Inlines({ nodes }) {
516
- return /* @__PURE__ */ jsx(Fragment$1, { children: nodes.map((node, index) => /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(Inline, { node }) }, index)) });
519
+ function FieldShell({ path, field, label, children }) {
520
+ return /* @__PURE__ */ jsxs("div", {
521
+ "data-formancy-part": "field",
522
+ "data-formancy-field-path": path,
523
+ "data-state": field.touched && field.errors.length > 0 ? "invalid" : "valid",
524
+ children: [
525
+ /* @__PURE__ */ jsx("label", {
526
+ "data-formancy-part": "label",
527
+ ...field.labelProps,
528
+ children: label
529
+ }),
530
+ /* @__PURE__ */ jsx(Description, { field }),
531
+ children,
532
+ field.touched && field.errors.length > 0 ? /* @__PURE__ */ jsx(ErrorText, { field }) : null,
533
+ /* @__PURE__ */ jsx(FieldAdditionSlot, { path })
534
+ ]
535
+ });
517
536
  }
518
- function Inline({ node }) {
519
- switch (node.kind) {
520
- case "text": return /* @__PURE__ */ jsx(Fragment$1, { children: node.text });
521
- case "strong": return /* @__PURE__ */ jsx("strong", { children: /* @__PURE__ */ jsx(Inlines, { nodes: node.children }) });
522
- case "emphasis": return /* @__PURE__ */ jsx("em", { children: /* @__PURE__ */ jsx(Inlines, { nodes: node.children }) });
523
- case "link": return /* @__PURE__ */ jsx("a", {
524
- href: node.href,
525
- rel: "noreferrer noopener nofollow ugc",
526
- children: /* @__PURE__ */ jsx(Inlines, { nodes: node.children })
527
- });
528
- }
537
+ function statusState({ sourced, said, open, matches }) {
538
+ if (sourced.remote === null) return open && matches === 0 ? "empty" : void 0;
539
+ if (sourced.remote.busy) return "busy";
540
+ if (sourced.remote.failed) return "failed";
541
+ if (said !== "") return "hint";
542
+ return open && matches === 0 ? "empty" : void 0;
529
543
  }
530
- //#endregion
531
- //#region src/rich-text-editor.ts
532
- const RichTextEditorContext = createContext(void 0);
533
- const RichTextEditorProvider = RichTextEditorContext.Provider;
534
- function useRichTextEditorFactory() {
535
- return useContext(RichTextEditorContext);
544
+ function RequiredHint({ field }) {
545
+ const text = useFormText();
546
+ if (!field.required) return null;
547
+ return /* @__PURE__ */ jsx("span", {
548
+ "data-formancy-part": "required-hint",
549
+ id: field.props.hint.id,
550
+ children: text("form.required")
551
+ });
552
+ }
553
+ function Description({ field }) {
554
+ if (field.description === void 0) return null;
555
+ return /* @__PURE__ */ jsx("p", {
556
+ "data-formancy-part": "description",
557
+ id: field.props.description.id,
558
+ children: field.description
559
+ });
560
+ }
561
+ function usePlaceholder(field) {
562
+ return useFormEngine().text(field.def.placeholder);
563
+ }
564
+ function optionDomId(field, value) {
565
+ return `${field.ids.control}:option:${value}`;
566
+ }
567
+ function useResolvedOptions(field) {
568
+ const engine = useFormEngine();
569
+ return inOptionOrder((field.def.options ?? []).map((option) => ({
570
+ value: option.value,
571
+ label: engine.text(option.label) ?? option.value,
572
+ ...option.image !== void 0 && isImageSource(option.image.src) ? { image: {
573
+ src: option.image.src,
574
+ alt: engine.text(option.image.alt) ?? ""
575
+ } } : {}
576
+ })), field.optionOrder);
577
+ }
578
+ function OptionPicture({ option }) {
579
+ if (option.image === void 0) return null;
580
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("img", {
581
+ "data-formancy-part": "option-image",
582
+ src: option.image.src,
583
+ alt: option.image.alt,
584
+ loading: "lazy",
585
+ decoding: "async"
586
+ }), " "] });
536
587
  }
537
588
  //#endregion
538
- //#region src/scanning.ts
539
- const ScannerContext = createContext(void 0);
540
- const ScannerProvider = ScannerContext.Provider;
541
- function useScanner() {
542
- return useContext(ScannerContext);
589
+ //#region src/fields/computed-answer.tsx
590
+ function ComputedAnswerField({ path, label }) {
591
+ const field = useField(path);
592
+ const engine = useFormEngine();
593
+ const text = useFormText();
594
+ return /* @__PURE__ */ jsx(FieldShell, {
595
+ path,
596
+ field,
597
+ label,
598
+ children: /* @__PURE__ */ jsx("input", {
599
+ type: "text",
600
+ readOnly: true,
601
+ ...field.controlProps,
602
+ value: answerInWords(engine.schema(), field.def, field.value, text, engine.locale())
603
+ })
604
+ });
543
605
  }
544
606
  //#endregion
545
607
  //#region src/options-source.ts
@@ -703,112 +765,6 @@ function storedValues(value) {
703
765
  return value.filter((item) => typeof item === "string" && item !== "");
704
766
  }
705
767
  //#endregion
706
- //#region src/uploads.ts
707
- const UploaderContext = createContext(void 0);
708
- const UploaderProvider = UploaderContext.Provider;
709
- function useUploader() {
710
- return useContext(UploaderContext);
711
- }
712
- //#endregion
713
- //#region src/fields/internals.tsx
714
- function ErrorText({ field }) {
715
- const text = useFormText();
716
- return /* @__PURE__ */ jsx("p", {
717
- "data-formancy-part": "error",
718
- ...field.errorProps,
719
- children: field.errors.map((code, index) => /* @__PURE__ */ jsxs(Fragment, { children: [index > 0 ? " " : null, /* @__PURE__ */ jsx("span", {
720
- "data-formancy-code": code,
721
- children: errorSentence(text, field.def, code, field.messages)
722
- })] }, code))
723
- });
724
- }
725
- function FieldShell({ path, field, label, children }) {
726
- return /* @__PURE__ */ jsxs("div", {
727
- "data-formancy-part": "field",
728
- "data-formancy-field-path": path,
729
- "data-state": field.touched && field.errors.length > 0 ? "invalid" : "valid",
730
- children: [
731
- /* @__PURE__ */ jsx("label", {
732
- "data-formancy-part": "label",
733
- ...field.labelProps,
734
- children: label
735
- }),
736
- /* @__PURE__ */ jsx(Description, { field }),
737
- children,
738
- field.touched && field.errors.length > 0 ? /* @__PURE__ */ jsx(ErrorText, { field }) : null
739
- ]
740
- });
741
- }
742
- function statusState({ sourced, said, open, matches }) {
743
- if (sourced.remote === null) return open && matches === 0 ? "empty" : void 0;
744
- if (sourced.remote.busy) return "busy";
745
- if (sourced.remote.failed) return "failed";
746
- if (said !== "") return "hint";
747
- return open && matches === 0 ? "empty" : void 0;
748
- }
749
- function RequiredHint({ field }) {
750
- const text = useFormText();
751
- if (!field.required) return null;
752
- return /* @__PURE__ */ jsx("span", {
753
- "data-formancy-part": "required-hint",
754
- id: field.props.hint.id,
755
- children: text("form.required")
756
- });
757
- }
758
- function Description({ field }) {
759
- if (field.description === void 0) return null;
760
- return /* @__PURE__ */ jsx("p", {
761
- "data-formancy-part": "description",
762
- id: field.props.description.id,
763
- children: field.description
764
- });
765
- }
766
- function usePlaceholder(field) {
767
- return useFormEngine().text(field.def.placeholder);
768
- }
769
- function optionDomId(field, value) {
770
- return `${field.ids.control}:option:${value}`;
771
- }
772
- function useResolvedOptions(field) {
773
- const engine = useFormEngine();
774
- return inOptionOrder((field.def.options ?? []).map((option) => ({
775
- value: option.value,
776
- label: engine.text(option.label) ?? option.value,
777
- ...option.image !== void 0 && isImageSource(option.image.src) ? { image: {
778
- src: option.image.src,
779
- alt: engine.text(option.image.alt) ?? ""
780
- } } : {}
781
- })), field.optionOrder);
782
- }
783
- function OptionPicture({ option }) {
784
- if (option.image === void 0) return null;
785
- return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("img", {
786
- "data-formancy-part": "option-image",
787
- src: option.image.src,
788
- alt: option.image.alt,
789
- loading: "lazy",
790
- decoding: "async"
791
- }), " "] });
792
- }
793
- //#endregion
794
- //#region src/fields/computed-answer.tsx
795
- function ComputedAnswerField({ path, label }) {
796
- const field = useField(path);
797
- const engine = useFormEngine();
798
- const text = useFormText();
799
- return /* @__PURE__ */ jsx(FieldShell, {
800
- path,
801
- field,
802
- label,
803
- children: /* @__PURE__ */ jsx("input", {
804
- type: "text",
805
- readOnly: true,
806
- ...field.controlProps,
807
- value: answerInWords(engine.schema(), field.def, field.value, text, engine.locale())
808
- })
809
- });
810
- }
811
- //#endregion
812
768
  //#region src/fields/typeahead-field.tsx
813
769
  function TypeaheadSelectField({ path, label, field }) {
814
770
  const text = useFormText();
@@ -837,6 +793,10 @@ function TypeaheadSelectField({ path, label, field }) {
837
793
  const activeIndex = matches.findIndex((option) => option.value === activeValue);
838
794
  const activeId = expanded && activeIndex !== -1 ? optionDomId(field, matches[activeIndex].value) : void 0;
839
795
  const listboxId = `${field.ids.control}:listbox`;
796
+ const listbox = useRef(null);
797
+ useEffect(() => {
798
+ if (expanded && activeIndex !== -1) listbox.current?.children[activeIndex]?.scrollIntoView?.({ block: "nearest" });
799
+ }, [expanded, activeIndex]);
840
800
  const choose = (value) => {
841
801
  field.setValue(value);
842
802
  setQuery(null);
@@ -920,6 +880,7 @@ function TypeaheadSelectField({ path, label, field }) {
920
880
  onKeyDown,
921
881
  onBlur
922
882
  }), /* @__PURE__ */ jsx("ul", {
883
+ ref: listbox,
923
884
  id: listboxId,
924
885
  role: "listbox",
925
886
  "aria-label": text("options.suggestions", { label }),
@@ -1067,11 +1028,19 @@ function RadioGroupField({ path, label }) {
1067
1028
  })]
1068
1029
  }, option.value);
1069
1030
  }),
1070
- showError ? /* @__PURE__ */ jsx(ErrorText, { field }) : null
1031
+ showError ? /* @__PURE__ */ jsx(ErrorText, { field }) : null,
1032
+ /* @__PURE__ */ jsx(FieldAdditionSlot, { path })
1071
1033
  ]
1072
1034
  });
1073
1035
  }
1074
1036
  //#endregion
1037
+ //#region src/uploads.ts
1038
+ const UploaderContext = createContext(void 0);
1039
+ const UploaderProvider = UploaderContext.Provider;
1040
+ function useUploader() {
1041
+ return useContext(UploaderContext);
1042
+ }
1043
+ //#endregion
1075
1044
  //#region src/fields/file-field.tsx
1076
1045
  function FileField({ path, label }) {
1077
1046
  const field = useField(path);
@@ -1315,6 +1284,43 @@ function FileThumbnail({ source }) {
1315
1284
  });
1316
1285
  }
1317
1286
  //#endregion
1287
+ //#region src/rich-text.tsx
1288
+ function RichText({ source }) {
1289
+ const blocks = parseRichText(source);
1290
+ if (blocks.length === 0) return null;
1291
+ return /* @__PURE__ */ jsx("div", {
1292
+ "data-formancy-part": "richtext",
1293
+ children: blocks.map((block, index) => /* @__PURE__ */ jsx(Block, { block }, index))
1294
+ });
1295
+ }
1296
+ function Block({ block }) {
1297
+ if (block.kind === "paragraph") return /* @__PURE__ */ jsx("p", { children: /* @__PURE__ */ jsx(Inlines, { nodes: block.children }) });
1298
+ const items = block.items.map((item, index) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(Inlines, { nodes: item }) }, index));
1299
+ return block.ordered ? /* @__PURE__ */ jsx("ol", { children: items }) : /* @__PURE__ */ jsx("ul", { children: items });
1300
+ }
1301
+ function Inlines({ nodes }) {
1302
+ return /* @__PURE__ */ jsx(Fragment$1, { children: nodes.map((node, index) => /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(Inline, { node }) }, index)) });
1303
+ }
1304
+ function Inline({ node }) {
1305
+ switch (node.kind) {
1306
+ case "text": return /* @__PURE__ */ jsx(Fragment$1, { children: node.text });
1307
+ case "strong": return /* @__PURE__ */ jsx("strong", { children: /* @__PURE__ */ jsx(Inlines, { nodes: node.children }) });
1308
+ case "emphasis": return /* @__PURE__ */ jsx("em", { children: /* @__PURE__ */ jsx(Inlines, { nodes: node.children }) });
1309
+ case "link": return /* @__PURE__ */ jsx("a", {
1310
+ href: node.href,
1311
+ rel: "noreferrer noopener nofollow ugc",
1312
+ children: /* @__PURE__ */ jsx(Inlines, { nodes: node.children })
1313
+ });
1314
+ }
1315
+ }
1316
+ //#endregion
1317
+ //#region src/rich-text-editor.ts
1318
+ const RichTextEditorContext = createContext(void 0);
1319
+ const RichTextEditorProvider = RichTextEditorContext.Provider;
1320
+ function useRichTextEditorFactory() {
1321
+ return useContext(RichTextEditorContext);
1322
+ }
1323
+ //#endregion
1318
1324
  //#region src/fields/rich-text-field.tsx
1319
1325
  function RichTextToolbar({ disabled, label, onCommand }) {
1320
1326
  const buttons = useRef([]);
@@ -1729,7 +1735,8 @@ function SelectBoxesField({ path, label }) {
1729
1735
  },
1730
1736
  children: text("options.retry")
1731
1737
  }) : null,
1732
- showError ? /* @__PURE__ */ jsx(ErrorText, { field }) : null
1738
+ showError ? /* @__PURE__ */ jsx(ErrorText, { field }) : null,
1739
+ /* @__PURE__ */ jsx(FieldAdditionSlot, { path })
1733
1740
  ]
1734
1741
  });
1735
1742
  }
@@ -1841,7 +1848,8 @@ function RankingField({ path, label }) {
1841
1848
  })
1842
1849
  }, option.value))
1843
1850
  }),
1844
- showError ? /* @__PURE__ */ jsx(ErrorText, { field }) : null
1851
+ showError ? /* @__PURE__ */ jsx(ErrorText, { field }) : null,
1852
+ /* @__PURE__ */ jsx(FieldAdditionSlot, { path })
1845
1853
  ]
1846
1854
  });
1847
1855
  }
@@ -1905,7 +1913,8 @@ function MatrixField({ path, label }) {
1905
1913
  })]
1906
1914
  }, row.value))
1907
1915
  }),
1908
- showError ? /* @__PURE__ */ jsx(ErrorText, { field }) : null
1916
+ showError ? /* @__PURE__ */ jsx(ErrorText, { field }) : null,
1917
+ /* @__PURE__ */ jsx(FieldAdditionSlot, { path })
1909
1918
  ]
1910
1919
  });
1911
1920
  }
@@ -2227,6 +2236,13 @@ function CharacterCount({ field }) {
2227
2236
  })] });
2228
2237
  }
2229
2238
  //#endregion
2239
+ //#region src/scanning.ts
2240
+ const ScannerContext = createContext(void 0);
2241
+ const ScannerProvider = ScannerContext.Provider;
2242
+ function useScanner() {
2243
+ return useContext(ScannerContext);
2244
+ }
2245
+ //#endregion
2230
2246
  //#region src/fields/text-fields.tsx
2231
2247
  function TextField({ path, label }) {
2232
2248
  const field = useField(path);
@@ -2361,7 +2377,11 @@ const DEFAULT_COMPONENTS = {
2361
2377
  //#endregion
2362
2378
  //#region src/form.tsx
2363
2379
  function FormancyForm(props) {
2364
- return useFormEngine().wizard() === void 0 ? /* @__PURE__ */ jsx(FlatForm, { ...props }) : /* @__PURE__ */ jsx(PagedForm, { ...props });
2380
+ const engine = useFormEngine();
2381
+ return /* @__PURE__ */ jsx(FieldAdditionContext.Provider, {
2382
+ value: props.fieldAddition,
2383
+ children: engine.wizard() === void 0 ? /* @__PURE__ */ jsx(FlatForm, { ...props }) : /* @__PURE__ */ jsx(PagedForm, { ...props })
2384
+ });
2365
2385
  }
2366
2386
  function FlatForm(props) {
2367
2387
  const review = useReview();
@@ -2431,34 +2451,31 @@ function FieldList({ labels, registry, page, layout }) {
2431
2451
  const repeaterWires = engine.repeaterPaths();
2432
2452
  const schema = engine.schema();
2433
2453
  const arrangement = schema.layouts?.find((candidate) => candidate.name === layout);
2434
- if (layout !== void 0 && arrangement !== void 0) {
2435
- new Set(placedPaths(arrangement.nodes));
2436
- return /* @__PURE__ */ jsx(LayoutTree, {
2437
- schema,
2438
- nodes: arrangement.nodes,
2439
- locale: engine.locale(),
2440
- shows: page === void 0 ? void 0 : (path) => placedPage(engine, path) === page,
2441
- renderField: (path) => {
2442
- if (repeaterWires.includes(path)) return /* @__PURE__ */ jsx(RepeaterSection, {
2443
- wire: path,
2444
- labels,
2445
- registry
2446
- }, path);
2447
- const group = placedGroup(engine, path);
2448
- if (group !== void 0) return /* @__PURE__ */ jsx(GroupSection, {
2449
- path,
2450
- group,
2451
- labels,
2452
- registry
2453
- }, path);
2454
- return /* @__PURE__ */ jsx(FieldSlot, {
2455
- path,
2456
- fallbackLabel: labels?.[path],
2457
- registry
2458
- }, path);
2459
- }
2460
- });
2461
- }
2454
+ if (layout !== void 0 && arrangement !== void 0) return /* @__PURE__ */ jsx(LayoutTree, {
2455
+ schema,
2456
+ nodes: arrangement.nodes,
2457
+ locale: engine.locale(),
2458
+ shows: page === void 0 ? void 0 : (path) => placedPage(engine, path) === page,
2459
+ renderField: (path) => {
2460
+ if (repeaterWires.includes(path)) return /* @__PURE__ */ jsx(RepeaterSection, {
2461
+ wire: path,
2462
+ labels,
2463
+ registry
2464
+ }, path);
2465
+ const group = placedGroup(engine, path);
2466
+ if (group !== void 0) return /* @__PURE__ */ jsx(GroupSection, {
2467
+ path,
2468
+ group,
2469
+ labels,
2470
+ registry
2471
+ }, path);
2472
+ return /* @__PURE__ */ jsx(FieldSlot, {
2473
+ path,
2474
+ fallbackLabel: labels?.[path],
2475
+ registry
2476
+ }, path);
2477
+ }
2478
+ });
2462
2479
  const inPage = (wire) => page === void 0 || engine.pageOf(parsePath(wire)) === page;
2463
2480
  const staticWires = engine.fieldPaths().filter((wire) => !repeaterWires.some((repeater) => wire.startsWith(`${repeater}[`)));
2464
2481
  return /* @__PURE__ */ jsxs(Fragment$1, { children: [staticWires.filter(inPage).map((wire) => /* @__PURE__ */ jsx(FieldSlot, {