@formancy/react 0.8.0 → 0.10.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 +10 -0
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +221 -103
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -4
package/dist/index.d.mts
CHANGED
|
@@ -109,6 +109,16 @@ export declare function useSubmit(): () => {
|
|
|
109
109
|
errors: Record<string, string[]>;
|
|
110
110
|
};
|
|
111
111
|
//#endregion
|
|
112
|
+
//#region src/go-to-field.d.ts
|
|
113
|
+
/**
|
|
114
|
+
* Take the person to a question: to its page first, on a paged form, and to its control once
|
|
115
|
+
* that page is drawn — into a group's first option, since a fieldset takes no focus, and past a
|
|
116
|
+
* tab a layout hides it behind (0213). What the error summary's links and the review's Change do,
|
|
117
|
+
* one function for both and for a host's own list of questions; the Angular binding's
|
|
118
|
+
* `injectGoToField` is the same. A path no field has throws, as the engine does for one.
|
|
119
|
+
*/
|
|
120
|
+
export declare function useGoToField(): (path: string) => void;
|
|
121
|
+
//#endregion
|
|
112
122
|
//#region src/fields/internals.d.ts
|
|
113
123
|
/**
|
|
114
124
|
* The pieces every control shares: the shell it renders inside, the prop shapes, and the few helpers more than one of them needs.
|
package/dist/index.d.mts.map
CHANGED
|
@@ -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/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
|
|
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;;;;;;;;;;;;;;;;;;;;;;;;;wBCNP,aAAa,OAAO,oCAAiB,IAAA;;;UCrDpC;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"}
|
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Fragment, createContext, useCallback, useContext, useEffect, useId, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
|
|
2
|
-
import { cancelUploads, fieldUploads, formatPath, inOptionOrder, parsePath, placedGroup, placedPage, thumbnailSize, ticked } from "@formancy/core";
|
|
3
|
-
import { answersToReview, countSentence, createFormText, errorSentence, optionsStatus } from "@formancy/core/words";
|
|
2
|
+
import { cancelUploads, fieldUploads, formatPath, hasReadOnlyControl, inOptionOrder, parsePath, placedGroup, placedPage, thumbnailSize, ticked } from "@formancy/core";
|
|
3
|
+
import { answerInWords, answersToReview, countSentence, createFormText, errorSentence, optionsStatus } from "@formancy/core/words";
|
|
4
4
|
import { LAYOUT_LEAF_KINDS, acceptRemoteAnswer, answerFromText, applyRichCommand, capRemoteAnswer, datagridColumns, editMasked, formatMasked, isImageSource, layoutChildren, layoutNodeShows, maskIsNumeric, maskPlaceholder, narrowOptionsByLabel, parseRichText, resolveText, resolvedLocale } from "@formancy/spec";
|
|
5
5
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
6
6
|
import { flushSync } from "react-dom";
|
|
@@ -143,6 +143,24 @@ function useSubmit() {
|
|
|
143
143
|
}, [engine]);
|
|
144
144
|
}
|
|
145
145
|
//#endregion
|
|
146
|
+
//#region src/go-to-field.ts
|
|
147
|
+
function useGoToField() {
|
|
148
|
+
const engine = useFormEngine();
|
|
149
|
+
const [focusing, setFocusing] = useState(void 0);
|
|
150
|
+
useEffect(() => {
|
|
151
|
+
if (focusing === void 0) return;
|
|
152
|
+
focusControl(document.getElementById(focusing.id));
|
|
153
|
+
setFocusing(void 0);
|
|
154
|
+
}, [focusing]);
|
|
155
|
+
return useCallback((path) => {
|
|
156
|
+
const at = parsePath(path);
|
|
157
|
+
const wizard = engine.wizard();
|
|
158
|
+
const page = engine.pageOf(at);
|
|
159
|
+
if (wizard !== void 0 && wizard.page() !== page) wizard.goTo(page);
|
|
160
|
+
setFocusing({ id: engine.getFieldSnapshot(at).ids.control });
|
|
161
|
+
}, [engine]);
|
|
162
|
+
}
|
|
163
|
+
//#endregion
|
|
146
164
|
//#region src/layout.tsx
|
|
147
165
|
function LayoutTree({ schema, nodes, locale, renderField, at = [], shows }) {
|
|
148
166
|
return /* @__PURE__ */ jsx(Fragment$1, { children: nodes.map((node, index) => {
|
|
@@ -396,12 +414,7 @@ function useReview(goTo) {
|
|
|
396
414
|
const engine = useFormEngine();
|
|
397
415
|
const submit = useSubmit();
|
|
398
416
|
const [reviewing, setReviewing] = useState(false);
|
|
399
|
-
const
|
|
400
|
-
useEffect(() => {
|
|
401
|
-
if (focusing === void 0) return;
|
|
402
|
-
focusControl(document.getElementById(focusing));
|
|
403
|
-
setFocusing(void 0);
|
|
404
|
-
}, [focusing]);
|
|
417
|
+
const goToField = useGoToField();
|
|
405
418
|
return {
|
|
406
419
|
reviewing,
|
|
407
420
|
check() {
|
|
@@ -411,8 +424,7 @@ function useReview(goTo) {
|
|
|
411
424
|
},
|
|
412
425
|
change(answer) {
|
|
413
426
|
setReviewing(false);
|
|
414
|
-
|
|
415
|
-
setFocusing(answer.controlId);
|
|
427
|
+
goToField(answer.field);
|
|
416
428
|
}
|
|
417
429
|
};
|
|
418
430
|
}
|
|
@@ -452,7 +464,10 @@ function Review({ onChange, children }) {
|
|
|
452
464
|
"data-formancy-part": "review-answer",
|
|
453
465
|
children: [
|
|
454
466
|
/* @__PURE__ */ jsx("dt", { children: answer.label }),
|
|
455
|
-
/* @__PURE__ */ jsx("dd", {
|
|
467
|
+
/* @__PURE__ */ jsx("dd", {
|
|
468
|
+
...answer.answered ? {} : { "data-formancy-part": "review-unanswered" },
|
|
469
|
+
children: answer.said
|
|
470
|
+
}),
|
|
456
471
|
/* @__PURE__ */ jsx("dd", { children: /* @__PURE__ */ jsxs("button", {
|
|
457
472
|
type: "button",
|
|
458
473
|
onClick: () => onChange(answer),
|
|
@@ -544,7 +559,8 @@ function useSourcedOptions(field, query, enabled = true) {
|
|
|
544
559
|
const debounceMs = source?.debounceMs ?? DEBOUNCE_MS;
|
|
545
560
|
const minQueryLength = source?.minQueryLength ?? MIN_QUERY;
|
|
546
561
|
const maxRows = source?.maxRows ?? MAX_ROWS;
|
|
547
|
-
const stored =
|
|
562
|
+
const stored = storedValues(field.value);
|
|
563
|
+
const storedKey = stored.join("\0");
|
|
548
564
|
const path = field.path;
|
|
549
565
|
const disabled = field.disabled;
|
|
550
566
|
const asked = useRef(0);
|
|
@@ -616,18 +632,19 @@ function useSourcedOptions(field, query, enabled = true) {
|
|
|
616
632
|
]);
|
|
617
633
|
const askedFor = useRef(/* @__PURE__ */ new Set());
|
|
618
634
|
useEffect(() => {
|
|
619
|
-
if (!enabled || source === void 0 ||
|
|
620
|
-
|
|
621
|
-
|
|
635
|
+
if (!enabled || source === void 0 || storedKey === "") return;
|
|
636
|
+
const unnamed = storedKey.split("\0").filter((value) => !named.has(value) && !askedFor.current.has(value));
|
|
637
|
+
if (unnamed.length === 0) return;
|
|
638
|
+
for (const value of unnamed) askedFor.current.add(value);
|
|
622
639
|
const controller = new AbortController();
|
|
623
640
|
source.resolve({
|
|
624
641
|
kind: "labels",
|
|
625
642
|
source: name ?? "",
|
|
626
643
|
path,
|
|
627
644
|
query: "",
|
|
628
|
-
values:
|
|
645
|
+
values: unnamed,
|
|
629
646
|
locale: engine.locale(),
|
|
630
|
-
limit:
|
|
647
|
+
limit: unnamed.length,
|
|
631
648
|
signal: controller.signal
|
|
632
649
|
}).then((answer) => {
|
|
633
650
|
const accepted = acceptRemoteAnswer(answer);
|
|
@@ -644,7 +661,7 @@ function useSourcedOptions(field, query, enabled = true) {
|
|
|
644
661
|
source,
|
|
645
662
|
name,
|
|
646
663
|
path,
|
|
647
|
-
|
|
664
|
+
storedKey,
|
|
648
665
|
named,
|
|
649
666
|
engine
|
|
650
667
|
]);
|
|
@@ -655,13 +672,11 @@ function useSourcedOptions(field, query, enabled = true) {
|
|
|
655
672
|
})),
|
|
656
673
|
remote: null
|
|
657
674
|
};
|
|
658
|
-
const offered = [...rows];
|
|
659
|
-
if (stored !== void 0 && !offered.some((row) => row.value === stored)) offered.unshift({
|
|
660
|
-
value: stored,
|
|
661
|
-
label: named.get(stored) ?? stored
|
|
662
|
-
});
|
|
663
675
|
return {
|
|
664
|
-
options:
|
|
676
|
+
options: [...stored.filter((value) => !rows.some((row) => row.value === value)).map((value) => ({
|
|
677
|
+
value,
|
|
678
|
+
label: named.get(value) ?? value
|
|
679
|
+
})), ...rows],
|
|
665
680
|
remote: {
|
|
666
681
|
unavailable: source === void 0,
|
|
667
682
|
busy,
|
|
@@ -672,6 +687,11 @@ function useSourcedOptions(field, query, enabled = true) {
|
|
|
672
687
|
}
|
|
673
688
|
};
|
|
674
689
|
}
|
|
690
|
+
function storedValues(value) {
|
|
691
|
+
if (typeof value === "string") return value === "" ? [] : [value];
|
|
692
|
+
if (!Array.isArray(value)) return [];
|
|
693
|
+
return value.filter((item) => typeof item === "string" && item !== "");
|
|
694
|
+
}
|
|
675
695
|
//#endregion
|
|
676
696
|
//#region src/uploads.ts
|
|
677
697
|
const UploaderContext = createContext(void 0);
|
|
@@ -1008,6 +1028,7 @@ function RadioGroupField({ path, label }) {
|
|
|
1008
1028
|
name: field.controlProps.name,
|
|
1009
1029
|
value: option.value,
|
|
1010
1030
|
checked: field.value === option.value,
|
|
1031
|
+
disabled: field.disabled,
|
|
1011
1032
|
onChange: () => field.setValue(option.value),
|
|
1012
1033
|
onBlur: () => field.touch()
|
|
1013
1034
|
}), /* @__PURE__ */ jsxs("label", {
|
|
@@ -1021,6 +1042,24 @@ function RadioGroupField({ path, label }) {
|
|
|
1021
1042
|
});
|
|
1022
1043
|
}
|
|
1023
1044
|
//#endregion
|
|
1045
|
+
//#region src/fields/computed-answer.tsx
|
|
1046
|
+
function ComputedAnswerField({ path, label }) {
|
|
1047
|
+
const field = useField(path);
|
|
1048
|
+
const engine = useFormEngine();
|
|
1049
|
+
const text = useFormText();
|
|
1050
|
+
return /* @__PURE__ */ jsx(FieldShell, {
|
|
1051
|
+
path,
|
|
1052
|
+
field,
|
|
1053
|
+
label,
|
|
1054
|
+
children: /* @__PURE__ */ jsx("input", {
|
|
1055
|
+
type: "text",
|
|
1056
|
+
readOnly: true,
|
|
1057
|
+
...field.controlProps,
|
|
1058
|
+
value: answerInWords(engine.schema(), field.def, field.value, text, engine.locale())
|
|
1059
|
+
})
|
|
1060
|
+
});
|
|
1061
|
+
}
|
|
1062
|
+
//#endregion
|
|
1024
1063
|
//#region src/fields/file-field.tsx
|
|
1025
1064
|
function FileField({ path, label }) {
|
|
1026
1065
|
const field = useField(path);
|
|
@@ -1461,14 +1500,30 @@ function SelectBoxesSwitch(props) {
|
|
|
1461
1500
|
function TagPickerField({ path, label }) {
|
|
1462
1501
|
const field = useField(path);
|
|
1463
1502
|
const text = useFormText();
|
|
1464
|
-
const options = useResolvedOptions(field);
|
|
1465
1503
|
const chosen = Array.isArray(field.value) ? field.value.map(String) : [];
|
|
1466
1504
|
const [query, setQuery] = useState("");
|
|
1467
1505
|
const [open, setOpen] = useState(false);
|
|
1468
1506
|
const listboxId = `${field.ids.control}:listbox`;
|
|
1507
|
+
const written = useResolvedOptions(field);
|
|
1508
|
+
const sourced = useSourcedOptions({
|
|
1509
|
+
...field,
|
|
1510
|
+
path
|
|
1511
|
+
}, query);
|
|
1512
|
+
const remote = sourced.remote;
|
|
1513
|
+
const options = remote === null ? written : sourced.options;
|
|
1469
1514
|
const remaining = options.filter((option) => !chosen.includes(option.value));
|
|
1470
|
-
const matches = narrowOptionsByLabel(remaining, query);
|
|
1515
|
+
const matches = remote === null ? narrowOptionsByLabel(remaining, query) : remaining;
|
|
1471
1516
|
const expanded = open && !field.disabled && matches.length > 0;
|
|
1517
|
+
const said = remote === null ? "" : optionsStatus(text, {
|
|
1518
|
+
control: "typeahead",
|
|
1519
|
+
open: open && !field.disabled,
|
|
1520
|
+
disabled: field.disabled,
|
|
1521
|
+
failed: remote.failed,
|
|
1522
|
+
busy: remote.busy,
|
|
1523
|
+
needs: remote.needs,
|
|
1524
|
+
query,
|
|
1525
|
+
completeness: remote.completeness
|
|
1526
|
+
});
|
|
1472
1527
|
const add = (value) => {
|
|
1473
1528
|
field.setValue(ticked(field.def, chosen, value, true));
|
|
1474
1529
|
setQuery("");
|
|
@@ -1478,92 +1533,139 @@ function TagPickerField({ path, label }) {
|
|
|
1478
1533
|
field.setValue(chosen.filter((candidate) => candidate !== value));
|
|
1479
1534
|
};
|
|
1480
1535
|
const labelFor = (value) => options.find((option) => option.value === value)?.label ?? value;
|
|
1536
|
+
if (remote?.unavailable === true) return /* @__PURE__ */ jsx(FieldShell, {
|
|
1537
|
+
path,
|
|
1538
|
+
field,
|
|
1539
|
+
label,
|
|
1540
|
+
children: /* @__PURE__ */ jsx("p", {
|
|
1541
|
+
"data-formancy-part": "options-unavailable",
|
|
1542
|
+
children: text("options.unavailable", { source: field.def.optionsSource ?? "" })
|
|
1543
|
+
})
|
|
1544
|
+
});
|
|
1481
1545
|
return /* @__PURE__ */ jsx(FieldShell, {
|
|
1482
1546
|
path,
|
|
1483
1547
|
field,
|
|
1484
1548
|
label,
|
|
1485
1549
|
children: /* @__PURE__ */ jsxs("div", {
|
|
1486
1550
|
"data-formancy-part": "tagpicker",
|
|
1487
|
-
children: [
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1551
|
+
children: [
|
|
1552
|
+
chosen.length === 0 ? null : /* @__PURE__ */ jsx("ul", {
|
|
1553
|
+
"data-formancy-part": "tagpicker-chips",
|
|
1554
|
+
"aria-label": text("tagpicker.chosen", { label }),
|
|
1555
|
+
children: chosen.map((value) => /* @__PURE__ */ jsxs("li", {
|
|
1556
|
+
"data-formancy-part": "tagpicker-chip",
|
|
1557
|
+
children: [labelFor(value), /* @__PURE__ */ jsx("button", {
|
|
1558
|
+
type: "button",
|
|
1559
|
+
"data-formancy-part": "tagpicker-remove",
|
|
1560
|
+
"aria-label": text("tagpicker.remove", { option: labelFor(value) }),
|
|
1561
|
+
disabled: field.disabled,
|
|
1562
|
+
onClick: () => remove(value),
|
|
1563
|
+
children: "×"
|
|
1564
|
+
})]
|
|
1565
|
+
}, value))
|
|
1566
|
+
}),
|
|
1567
|
+
/* @__PURE__ */ jsxs("div", {
|
|
1568
|
+
"data-formancy-part": "tagpicker-anchor",
|
|
1569
|
+
children: [/* @__PURE__ */ jsx("input", {
|
|
1570
|
+
type: "text",
|
|
1571
|
+
role: "combobox",
|
|
1572
|
+
...field.controlProps,
|
|
1573
|
+
"data-formancy-part": "tagpicker-input",
|
|
1574
|
+
autoComplete: "off",
|
|
1575
|
+
"aria-expanded": expanded,
|
|
1576
|
+
"aria-controls": listboxId,
|
|
1577
|
+
"aria-autocomplete": "list",
|
|
1578
|
+
"aria-busy": remote?.busy === true ? true : void 0,
|
|
1579
|
+
value: query,
|
|
1580
|
+
onChange: (event) => {
|
|
1581
|
+
setQuery(event.target.value);
|
|
1582
|
+
setOpen(true);
|
|
1583
|
+
},
|
|
1584
|
+
onClick: () => setOpen(true),
|
|
1585
|
+
onKeyDown: (event) => {
|
|
1586
|
+
if (event.key === "Escape") {
|
|
1587
|
+
setOpen(false);
|
|
1588
|
+
return;
|
|
1589
|
+
}
|
|
1590
|
+
if (event.key === "Enter" && expanded && matches[0] !== void 0) {
|
|
1591
|
+
event.preventDefault();
|
|
1592
|
+
add(matches[0].value);
|
|
1593
|
+
return;
|
|
1594
|
+
}
|
|
1595
|
+
if (event.key === "Backspace" && query === "" && chosen.length > 0) remove(chosen[chosen.length - 1]);
|
|
1596
|
+
},
|
|
1597
|
+
onBlur: () => {
|
|
1520
1598
|
setOpen(false);
|
|
1521
|
-
|
|
1522
|
-
}
|
|
1523
|
-
if (event.key === "Enter" && expanded && matches[0] !== void 0) {
|
|
1524
|
-
event.preventDefault();
|
|
1525
|
-
add(matches[0].value);
|
|
1526
|
-
return;
|
|
1599
|
+
field.touch();
|
|
1527
1600
|
}
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1601
|
+
}), /* @__PURE__ */ jsx("ul", {
|
|
1602
|
+
id: listboxId,
|
|
1603
|
+
role: "listbox",
|
|
1604
|
+
"aria-label": text("options.suggestions", { label }),
|
|
1605
|
+
"data-formancy-part": "tagpicker-listbox",
|
|
1606
|
+
hidden: !expanded,
|
|
1607
|
+
children: matches.map((option) => /* @__PURE__ */ jsx("li", {
|
|
1608
|
+
role: "option",
|
|
1609
|
+
"data-formancy-part": "tagpicker-option",
|
|
1610
|
+
"aria-selected": false,
|
|
1611
|
+
onMouseDown: (event) => event.preventDefault(),
|
|
1612
|
+
onClick: () => add(option.value),
|
|
1613
|
+
children: option.label
|
|
1614
|
+
}, option.value))
|
|
1615
|
+
})]
|
|
1616
|
+
}),
|
|
1617
|
+
remote === null ? null : /* @__PURE__ */ jsx("p", {
|
|
1618
|
+
role: "status",
|
|
1619
|
+
"data-formancy-part": "tagpicker-status",
|
|
1620
|
+
"data-state": remote.failed ? "failed" : void 0,
|
|
1621
|
+
children: said
|
|
1622
|
+
})
|
|
1623
|
+
]
|
|
1550
1624
|
})
|
|
1551
1625
|
});
|
|
1552
1626
|
}
|
|
1553
1627
|
function SelectBoxesField({ path, label }) {
|
|
1554
1628
|
const field = useField(path);
|
|
1555
|
-
const
|
|
1629
|
+
const text = useFormText();
|
|
1630
|
+
const written = useResolvedOptions(field);
|
|
1631
|
+
const sourced = useSourcedOptions({
|
|
1632
|
+
...field,
|
|
1633
|
+
path
|
|
1634
|
+
}, "");
|
|
1635
|
+
const remote = sourced.remote;
|
|
1636
|
+
const options = remote === null ? written : sourced.options;
|
|
1556
1637
|
const showError = field.touched && field.errors.length > 0;
|
|
1557
1638
|
const chosen = Array.isArray(field.value) ? field.value : [];
|
|
1639
|
+
const group = useRef(null);
|
|
1640
|
+
const again = useRef(null);
|
|
1641
|
+
const [retrying, setRetrying] = useState(false);
|
|
1642
|
+
const settled = remote !== null && !remote.busy && !remote.failed;
|
|
1643
|
+
useEffect(() => {
|
|
1644
|
+
if (!retrying || !settled) return;
|
|
1645
|
+
setRetrying(false);
|
|
1646
|
+
if (document.activeElement === again.current) group.current?.querySelector("input[type=\"checkbox\"]")?.focus();
|
|
1647
|
+
}, [retrying, settled]);
|
|
1648
|
+
const said = remote === null ? "" : optionsStatus(text, {
|
|
1649
|
+
control: "ticks",
|
|
1650
|
+
open: true,
|
|
1651
|
+
disabled: field.disabled,
|
|
1652
|
+
failed: remote.failed,
|
|
1653
|
+
busy: remote.busy,
|
|
1654
|
+
needs: remote.needs,
|
|
1655
|
+
query: "",
|
|
1656
|
+
completeness: remote.completeness
|
|
1657
|
+
});
|
|
1558
1658
|
const toggle = (value, on) => {
|
|
1559
1659
|
field.setValue(ticked(field.def, chosen, value, on));
|
|
1560
1660
|
};
|
|
1561
1661
|
return /* @__PURE__ */ jsxs("fieldset", {
|
|
1662
|
+
ref: group,
|
|
1562
1663
|
id: field.ids.control,
|
|
1563
1664
|
"data-formancy-part": "field",
|
|
1564
1665
|
"data-formancy-field-path": path,
|
|
1565
1666
|
"data-state": showError ? "invalid" : "valid",
|
|
1566
1667
|
"aria-describedby": field.controlProps["aria-describedby"],
|
|
1668
|
+
"aria-busy": remote?.busy === true ? true : void 0,
|
|
1567
1669
|
children: [
|
|
1568
1670
|
/* @__PURE__ */ jsx("legend", {
|
|
1569
1671
|
"data-formancy-part": "label",
|
|
@@ -1571,6 +1673,10 @@ function SelectBoxesField({ path, label }) {
|
|
|
1571
1673
|
}),
|
|
1572
1674
|
/* @__PURE__ */ jsx(RequiredHint, { field }),
|
|
1573
1675
|
/* @__PURE__ */ jsx(Description, { field }),
|
|
1676
|
+
remote?.unavailable === true ? /* @__PURE__ */ jsx("p", {
|
|
1677
|
+
"data-formancy-part": "options-unavailable",
|
|
1678
|
+
children: text("options.unavailable", { source: field.def.optionsSource ?? "" })
|
|
1679
|
+
}) : null,
|
|
1574
1680
|
options.map((option) => {
|
|
1575
1681
|
const optionId = `${field.ids.control}:${option.value}`;
|
|
1576
1682
|
return /* @__PURE__ */ jsxs("span", {
|
|
@@ -1590,6 +1696,22 @@ function SelectBoxesField({ path, label }) {
|
|
|
1590
1696
|
})]
|
|
1591
1697
|
}, option.value);
|
|
1592
1698
|
}),
|
|
1699
|
+
remote === null || remote.unavailable ? null : /* @__PURE__ */ jsx("p", {
|
|
1700
|
+
role: "status",
|
|
1701
|
+
"data-formancy-part": "checkbox-status",
|
|
1702
|
+
"data-state": remote.failed ? "failed" : void 0,
|
|
1703
|
+
children: said
|
|
1704
|
+
}),
|
|
1705
|
+
remote !== null && (remote.failed || retrying) && !field.disabled ? /* @__PURE__ */ jsx("button", {
|
|
1706
|
+
ref: again,
|
|
1707
|
+
type: "button",
|
|
1708
|
+
"data-formancy-part": "checkbox-retry",
|
|
1709
|
+
onClick: () => {
|
|
1710
|
+
setRetrying(true);
|
|
1711
|
+
remote.retry();
|
|
1712
|
+
},
|
|
1713
|
+
children: text("options.retry")
|
|
1714
|
+
}) : null,
|
|
1593
1715
|
showError ? /* @__PURE__ */ jsx(ErrorText, { field }) : null
|
|
1594
1716
|
]
|
|
1595
1717
|
});
|
|
@@ -1817,6 +1939,7 @@ function RatingField({ path, label }) {
|
|
|
1817
1939
|
name: controlProps.id,
|
|
1818
1940
|
value,
|
|
1819
1941
|
checked: value === chosen,
|
|
1942
|
+
disabled: field.disabled,
|
|
1820
1943
|
onChange: () => field.setValue(value),
|
|
1821
1944
|
onBlur: () => field.touch()
|
|
1822
1945
|
}), /* @__PURE__ */ jsx("span", {
|
|
@@ -1915,12 +2038,13 @@ function SignatureField({ path, label }) {
|
|
|
1915
2038
|
};
|
|
1916
2039
|
}, []);
|
|
1917
2040
|
const onPointerDown = (event) => {
|
|
2041
|
+
if (field.disabled) return;
|
|
1918
2042
|
before.current = drawn;
|
|
1919
2043
|
stroke.current = [pointFrom(event)];
|
|
1920
2044
|
surface.current?.setPointerCapture?.(event.pointerId);
|
|
1921
2045
|
};
|
|
1922
2046
|
const onPointerMove = (event) => {
|
|
1923
|
-
if (stroke.current === null) return;
|
|
2047
|
+
if (stroke.current === null || field.disabled) return;
|
|
1924
2048
|
stroke.current = [...stroke.current, pointFrom(event)];
|
|
1925
2049
|
commit([...before.current, stroke.current]);
|
|
1926
2050
|
};
|
|
@@ -1944,6 +2068,7 @@ function SignatureField({ path, label }) {
|
|
|
1944
2068
|
viewBox: `0 0 ${String(width)} ${String(height)}`,
|
|
1945
2069
|
role: "img",
|
|
1946
2070
|
"aria-label": label,
|
|
2071
|
+
"aria-disabled": field.disabled ? true : void 0,
|
|
1947
2072
|
onPointerDown,
|
|
1948
2073
|
onPointerMove,
|
|
1949
2074
|
onPointerUp,
|
|
@@ -1955,11 +2080,11 @@ function SignatureField({ path, label }) {
|
|
|
1955
2080
|
}, at))
|
|
1956
2081
|
}),
|
|
1957
2082
|
/* @__PURE__ */ jsx("input", {
|
|
1958
|
-
|
|
2083
|
+
...field.controlProps,
|
|
1959
2084
|
"data-formancy-part": "signature-typed",
|
|
1960
2085
|
type: "text",
|
|
1961
2086
|
value: answer.typed ?? "",
|
|
1962
|
-
"aria-label": text("signature.typed"),
|
|
2087
|
+
"aria-label": text("signature.typed", { label }),
|
|
1963
2088
|
onChange: (event) => {
|
|
1964
2089
|
const typed = event.target.value;
|
|
1965
2090
|
field.setValue(typed === "" ? null : { typed });
|
|
@@ -1969,6 +2094,7 @@ function SignatureField({ path, label }) {
|
|
|
1969
2094
|
/* @__PURE__ */ jsx("button", {
|
|
1970
2095
|
"data-formancy-part": "signature-clear",
|
|
1971
2096
|
type: "button",
|
|
2097
|
+
disabled: field.disabled,
|
|
1972
2098
|
onClick: () => {
|
|
1973
2099
|
stroke.current = null;
|
|
1974
2100
|
before.current = [];
|
|
@@ -2307,7 +2433,7 @@ function FieldList({ labels, registry, page, layout }) {
|
|
|
2307
2433
|
function FieldSlot({ path, fallbackLabel, registry }) {
|
|
2308
2434
|
const field = useField(path);
|
|
2309
2435
|
if (!field.visible) return null;
|
|
2310
|
-
const Component = registry?.byPath?.[path] ?? registry?.byType?.[field.type] ?? DEFAULT_COMPONENTS[field.type];
|
|
2436
|
+
const Component = registry?.byPath?.[path] ?? (field.readOnly && !hasReadOnlyControl(field.def) ? ComputedAnswerField : void 0) ?? registry?.byType?.[field.type] ?? DEFAULT_COMPONENTS[field.type];
|
|
2311
2437
|
if (Component === null) return null;
|
|
2312
2438
|
const label = field.label ?? fallbackLabel ?? path;
|
|
2313
2439
|
return /* @__PURE__ */ jsx(Component, {
|
|
@@ -2508,12 +2634,7 @@ function ErrorSummary({ labels }) {
|
|
|
2508
2634
|
const errors = useSyncExternalStore(subscribe, getErrors, getErrors);
|
|
2509
2635
|
const region = useRef(null);
|
|
2510
2636
|
const previousCount = useRef(0);
|
|
2511
|
-
const
|
|
2512
|
-
useEffect(() => {
|
|
2513
|
-
if (focusing === void 0) return;
|
|
2514
|
-
focusControl(document.getElementById(focusing));
|
|
2515
|
-
setFocusing(void 0);
|
|
2516
|
-
}, [focusing]);
|
|
2637
|
+
const goToField = useGoToField();
|
|
2517
2638
|
useEffect(() => {
|
|
2518
2639
|
if (errors.length > 0 && previousCount.current === 0) region.current?.focus();
|
|
2519
2640
|
previousCount.current = errors.length;
|
|
@@ -2534,10 +2655,7 @@ function ErrorSummary({ labels }) {
|
|
|
2534
2655
|
href: `#${controlId}`,
|
|
2535
2656
|
onClick: (event) => {
|
|
2536
2657
|
event.preventDefault();
|
|
2537
|
-
|
|
2538
|
-
const page = engine.pageOf(parsePath(path));
|
|
2539
|
-
if (wizard !== void 0 && wizard.page() !== page) wizard.goTo(page);
|
|
2540
|
-
setFocusing(controlId);
|
|
2658
|
+
goToField(path);
|
|
2541
2659
|
},
|
|
2542
2660
|
children: text("errors.entry", {
|
|
2543
2661
|
label: labelFor(path),
|
|
@@ -2581,6 +2699,6 @@ function ResumeNotice({ migration, labels }) {
|
|
|
2581
2699
|
});
|
|
2582
2700
|
}
|
|
2583
2701
|
//#endregion
|
|
2584
|
-
export { ErrorSummary, FormancyForm, FormancyProvider, OptionsSourcesProvider, ResumeNotice, RichText, RichTextEditorProvider, ScannerProvider, UploaderProvider, useField, useFormEngine, useFormText, useOptionsSources, useRepeater, useRichTextEditorFactory, useScanner, useSubmit, useUploader, useWizard };
|
|
2702
|
+
export { ErrorSummary, FormancyForm, FormancyProvider, OptionsSourcesProvider, ResumeNotice, RichText, RichTextEditorProvider, ScannerProvider, UploaderProvider, useField, useFormEngine, useFormText, useGoToField, useOptionsSources, useRepeater, useRichTextEditorFactory, useScanner, useSubmit, useUploader, useWizard };
|
|
2585
2703
|
|
|
2586
2704
|
//# sourceMappingURL=index.mjs.map
|