@petrarca/sonnet-forms 0.8.0 → 0.9.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/README.md +2 -2
- package/dist/index.d.ts +229 -19
- package/dist/index.js +2468 -451
- package/dist/index.js.map +1 -1
- package/dist/widget-options.d.ts +2 -1
- package/dist/widget-options.js +74 -1
- package/dist/widget-options.js.map +1 -1
- package/package.json +8 -8
package/dist/index.js
CHANGED
|
@@ -446,6 +446,13 @@ import {
|
|
|
446
446
|
import { Popover, PopoverContent, PopoverTrigger } from "@petrarca/sonnet-ui";
|
|
447
447
|
|
|
448
448
|
// src/formSelectUtils.ts
|
|
449
|
+
import { extractEnumValues } from "@petrarca/sonnet-core/schema";
|
|
450
|
+
function buildSelectOptions(propertySchema, enumNames) {
|
|
451
|
+
return extractEnumValues(propertySchema).map((val) => {
|
|
452
|
+
const key = String(val);
|
|
453
|
+
return { value: key, label: enumNames[key] || key };
|
|
454
|
+
});
|
|
455
|
+
}
|
|
449
456
|
function canCreateFromSearch(allowCreate, searchQuery, options) {
|
|
450
457
|
const trimmed = searchQuery.trim();
|
|
451
458
|
if (!allowCreate || trimmed.length === 0) return false;
|
|
@@ -503,7 +510,7 @@ function SelectDropdown({
|
|
|
503
510
|
searchQuery,
|
|
504
511
|
onSearchChange,
|
|
505
512
|
loading,
|
|
506
|
-
emptyMessage,
|
|
513
|
+
emptyMessage: emptyMessage2,
|
|
507
514
|
options,
|
|
508
515
|
value,
|
|
509
516
|
onSelect,
|
|
@@ -521,7 +528,7 @@ function SelectDropdown({
|
|
|
521
528
|
}
|
|
522
529
|
),
|
|
523
530
|
/* @__PURE__ */ jsxs5(CommandList, { children: [
|
|
524
|
-
!showCreate && /* @__PURE__ */ jsx6(CommandEmpty, { children: loading ? "Loading..." :
|
|
531
|
+
!showCreate && /* @__PURE__ */ jsx6(CommandEmpty, { children: loading ? "Loading..." : emptyMessage2 }),
|
|
525
532
|
/* @__PURE__ */ jsxs5(CommandGroup, { children: [
|
|
526
533
|
options.filter(
|
|
527
534
|
(option) => option.label.toLowerCase().includes(searchQuery.toLowerCase())
|
|
@@ -596,7 +603,7 @@ function FormSelect(props) {
|
|
|
596
603
|
const {
|
|
597
604
|
placeholder,
|
|
598
605
|
searchPlaceholder,
|
|
599
|
-
emptyMessage,
|
|
606
|
+
emptyMessage: emptyMessage2,
|
|
600
607
|
clearable,
|
|
601
608
|
disabled,
|
|
602
609
|
readOnly,
|
|
@@ -675,7 +682,7 @@ function FormSelect(props) {
|
|
|
675
682
|
searchQuery,
|
|
676
683
|
onSearchChange: setSearchQuery,
|
|
677
684
|
loading,
|
|
678
|
-
emptyMessage,
|
|
685
|
+
emptyMessage: emptyMessage2,
|
|
679
686
|
options,
|
|
680
687
|
value,
|
|
681
688
|
onSelect: handleSelect,
|
|
@@ -801,7 +808,7 @@ function MultiSelectDropdown({
|
|
|
801
808
|
searchQuery,
|
|
802
809
|
onSearchChange,
|
|
803
810
|
loading,
|
|
804
|
-
emptyMessage,
|
|
811
|
+
emptyMessage: emptyMessage2,
|
|
805
812
|
options,
|
|
806
813
|
value,
|
|
807
814
|
onSelect
|
|
@@ -816,7 +823,7 @@ function MultiSelectDropdown({
|
|
|
816
823
|
}
|
|
817
824
|
),
|
|
818
825
|
/* @__PURE__ */ jsxs6(CommandList2, { children: [
|
|
819
|
-
/* @__PURE__ */ jsx7(CommandEmpty2, { children: loading ? "Loading..." :
|
|
826
|
+
/* @__PURE__ */ jsx7(CommandEmpty2, { children: loading ? "Loading..." : emptyMessage2 }),
|
|
820
827
|
/* @__PURE__ */ jsx7(CommandGroup2, { children: options.filter(
|
|
821
828
|
(option) => option.label.toLowerCase().includes(searchQuery.toLowerCase())
|
|
822
829
|
).map((option) => /* @__PURE__ */ jsxs6(
|
|
@@ -930,7 +937,7 @@ function FormMultiSelect(props) {
|
|
|
930
937
|
const {
|
|
931
938
|
placeholder,
|
|
932
939
|
searchPlaceholder,
|
|
933
|
-
emptyMessage,
|
|
940
|
+
emptyMessage: emptyMessage2,
|
|
934
941
|
clearable,
|
|
935
942
|
disabled,
|
|
936
943
|
readOnly,
|
|
@@ -1016,7 +1023,7 @@ function FormMultiSelect(props) {
|
|
|
1016
1023
|
searchQuery,
|
|
1017
1024
|
onSearchChange: setSearchQuery,
|
|
1018
1025
|
loading,
|
|
1019
|
-
emptyMessage,
|
|
1026
|
+
emptyMessage: emptyMessage2,
|
|
1020
1027
|
options,
|
|
1021
1028
|
value,
|
|
1022
1029
|
onSelect: handleSelect
|
|
@@ -1033,18 +1040,38 @@ function FormMultiSelect(props) {
|
|
|
1033
1040
|
|
|
1034
1041
|
// src/FormTagsInput.tsx
|
|
1035
1042
|
import * as React7 from "react";
|
|
1036
|
-
import { X as X3 } from "lucide-react";
|
|
1037
1043
|
import { cn as cn8 } from "@petrarca/sonnet-core";
|
|
1038
1044
|
import { Input as Input3 } from "@petrarca/sonnet-ui";
|
|
1045
|
+
|
|
1046
|
+
// src/TagBadge.tsx
|
|
1047
|
+
import { X as X3 } from "lucide-react";
|
|
1039
1048
|
import { Badge as Badge2 } from "@petrarca/sonnet-ui";
|
|
1040
1049
|
import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
1041
|
-
function TagBadge({
|
|
1050
|
+
function TagBadge({
|
|
1051
|
+
tag,
|
|
1052
|
+
index,
|
|
1053
|
+
isDisabled,
|
|
1054
|
+
onRemove,
|
|
1055
|
+
onSelect
|
|
1056
|
+
}) {
|
|
1042
1057
|
return /* @__PURE__ */ jsxs7(Badge2, { variant: "secondary", className: "gap-1", children: [
|
|
1043
|
-
|
|
1058
|
+
onSelect && !isDisabled ? /* @__PURE__ */ jsx8(
|
|
1059
|
+
"button",
|
|
1060
|
+
{
|
|
1061
|
+
type: "button",
|
|
1062
|
+
className: "outline-none hover:underline focus:underline",
|
|
1063
|
+
onClick: (e) => {
|
|
1064
|
+
e.stopPropagation();
|
|
1065
|
+
onSelect(index);
|
|
1066
|
+
},
|
|
1067
|
+
children: tag
|
|
1068
|
+
}
|
|
1069
|
+
) : tag,
|
|
1044
1070
|
!isDisabled && /* @__PURE__ */ jsx8(
|
|
1045
1071
|
"button",
|
|
1046
1072
|
{
|
|
1047
1073
|
type: "button",
|
|
1074
|
+
"aria-label": `Remove ${tag}`,
|
|
1048
1075
|
className: "ml-1 ring-offset-background rounded-full outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
|
|
1049
1076
|
onKeyDown: (e) => {
|
|
1050
1077
|
if (e.key === "Enter") {
|
|
@@ -1065,6 +1092,9 @@ function TagBadge({ tag, index, isDisabled, onRemove }) {
|
|
|
1065
1092
|
)
|
|
1066
1093
|
] });
|
|
1067
1094
|
}
|
|
1095
|
+
|
|
1096
|
+
// src/FormTagsInput.tsx
|
|
1097
|
+
import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1068
1098
|
function useTagManagement(value, onChange, allowDuplicates, maxTags, splitKeys) {
|
|
1069
1099
|
const [inputValue, setInputValue] = React7.useState("");
|
|
1070
1100
|
const addTag = React7.useCallback(
|
|
@@ -1146,7 +1176,7 @@ var FormTagsInput = React7.forwardRef((props, ref) => {
|
|
|
1146
1176
|
const handleContainerClick = () => {
|
|
1147
1177
|
inputRef.current?.focus();
|
|
1148
1178
|
};
|
|
1149
|
-
return /* @__PURE__ */
|
|
1179
|
+
return /* @__PURE__ */ jsx9(
|
|
1150
1180
|
FormFieldWrapper,
|
|
1151
1181
|
{
|
|
1152
1182
|
inputId: fieldId,
|
|
@@ -1156,7 +1186,7 @@ var FormTagsInput = React7.forwardRef((props, ref) => {
|
|
|
1156
1186
|
required,
|
|
1157
1187
|
labelPlacement,
|
|
1158
1188
|
className: wrapperClassName,
|
|
1159
|
-
children: /* @__PURE__ */
|
|
1189
|
+
children: /* @__PURE__ */ jsxs8(
|
|
1160
1190
|
"div",
|
|
1161
1191
|
{
|
|
1162
1192
|
className: cn8(
|
|
@@ -1166,7 +1196,7 @@ var FormTagsInput = React7.forwardRef((props, ref) => {
|
|
|
1166
1196
|
),
|
|
1167
1197
|
onClick: handleContainerClick,
|
|
1168
1198
|
children: [
|
|
1169
|
-
value.map((tag, index) => /* @__PURE__ */
|
|
1199
|
+
value.map((tag, index) => /* @__PURE__ */ jsx9(
|
|
1170
1200
|
TagBadge,
|
|
1171
1201
|
{
|
|
1172
1202
|
tag,
|
|
@@ -1176,7 +1206,7 @@ var FormTagsInput = React7.forwardRef((props, ref) => {
|
|
|
1176
1206
|
},
|
|
1177
1207
|
index
|
|
1178
1208
|
)),
|
|
1179
|
-
/* @__PURE__ */
|
|
1209
|
+
/* @__PURE__ */ jsx9(
|
|
1180
1210
|
Input3,
|
|
1181
1211
|
{
|
|
1182
1212
|
ref: inputRef,
|
|
@@ -1198,16 +1228,415 @@ var FormTagsInput = React7.forwardRef((props, ref) => {
|
|
|
1198
1228
|
});
|
|
1199
1229
|
FormTagsInput.displayName = "FormTagsInput";
|
|
1200
1230
|
|
|
1231
|
+
// src/FormKeyValueInput.tsx
|
|
1232
|
+
import * as React8 from "react";
|
|
1233
|
+
import { Plus as Plus2, X as X4 } from "lucide-react";
|
|
1234
|
+
import { cn as cn9 } from "@petrarca/sonnet-core";
|
|
1235
|
+
import { Badge as Badge3, Button as Button3, IconButton, Input as Input4 } from "@petrarca/sonnet-ui";
|
|
1236
|
+
import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1237
|
+
function usePairEditor(value, onChange) {
|
|
1238
|
+
const [key, setKey] = React8.useState("");
|
|
1239
|
+
const [val, setVal] = React8.useState("");
|
|
1240
|
+
const [problem, setProblem] = React8.useState(null);
|
|
1241
|
+
const add = () => {
|
|
1242
|
+
const k = key.trim();
|
|
1243
|
+
const v = val.trim();
|
|
1244
|
+
if (!k || !v) {
|
|
1245
|
+
setProblem(!k ? "Enter a key." : "Enter a value.");
|
|
1246
|
+
return;
|
|
1247
|
+
}
|
|
1248
|
+
onChange?.({ ...value, [k]: v });
|
|
1249
|
+
setKey("");
|
|
1250
|
+
setVal("");
|
|
1251
|
+
setProblem(null);
|
|
1252
|
+
};
|
|
1253
|
+
const remove = (k) => {
|
|
1254
|
+
const { [k]: _removed, ...rest } = value;
|
|
1255
|
+
onChange?.(rest);
|
|
1256
|
+
};
|
|
1257
|
+
const replace = (from, k, v) => {
|
|
1258
|
+
const nextKey = k.trim();
|
|
1259
|
+
if (!nextKey) {
|
|
1260
|
+
setProblem("Enter a key.");
|
|
1261
|
+
return false;
|
|
1262
|
+
}
|
|
1263
|
+
if (nextKey !== from && nextKey in value) {
|
|
1264
|
+
setProblem(`The key '${nextKey}' is taken.`);
|
|
1265
|
+
return false;
|
|
1266
|
+
}
|
|
1267
|
+
setProblem(null);
|
|
1268
|
+
if (nextKey === from && value[from] === v) return true;
|
|
1269
|
+
onChange?.(
|
|
1270
|
+
Object.fromEntries(
|
|
1271
|
+
Object.entries(value).map(
|
|
1272
|
+
([key0, v0]) => key0 === from ? [nextKey, v] : [key0, v0]
|
|
1273
|
+
)
|
|
1274
|
+
)
|
|
1275
|
+
);
|
|
1276
|
+
return true;
|
|
1277
|
+
};
|
|
1278
|
+
const edit = (k) => {
|
|
1279
|
+
setKey(k);
|
|
1280
|
+
setVal(value[k] ?? "");
|
|
1281
|
+
setProblem(null);
|
|
1282
|
+
};
|
|
1283
|
+
const onKeyDown = (e) => {
|
|
1284
|
+
if (e.key !== "Enter") return;
|
|
1285
|
+
e.preventDefault();
|
|
1286
|
+
add();
|
|
1287
|
+
};
|
|
1288
|
+
const typeKey = (k) => {
|
|
1289
|
+
setKey(k);
|
|
1290
|
+
setProblem(null);
|
|
1291
|
+
};
|
|
1292
|
+
const typeValue = (v) => {
|
|
1293
|
+
setVal(v);
|
|
1294
|
+
setProblem(null);
|
|
1295
|
+
};
|
|
1296
|
+
return {
|
|
1297
|
+
key,
|
|
1298
|
+
typeKey,
|
|
1299
|
+
val,
|
|
1300
|
+
typeValue,
|
|
1301
|
+
problem,
|
|
1302
|
+
add,
|
|
1303
|
+
remove,
|
|
1304
|
+
replace,
|
|
1305
|
+
edit,
|
|
1306
|
+
onKeyDown
|
|
1307
|
+
};
|
|
1308
|
+
}
|
|
1309
|
+
function PairTags({
|
|
1310
|
+
value,
|
|
1311
|
+
separator,
|
|
1312
|
+
isDisabled,
|
|
1313
|
+
editor
|
|
1314
|
+
}) {
|
|
1315
|
+
const keys = Object.keys(value);
|
|
1316
|
+
if (keys.length === 0) return null;
|
|
1317
|
+
return /* @__PURE__ */ jsx10("div", { className: "flex flex-wrap gap-1.5", children: keys.map((k, index) => /* @__PURE__ */ jsx10(
|
|
1318
|
+
TagBadge,
|
|
1319
|
+
{
|
|
1320
|
+
tag: `${k}${separator}${value[k]}`,
|
|
1321
|
+
index,
|
|
1322
|
+
isDisabled,
|
|
1323
|
+
onRemove: (i) => editor.remove(keys[i]),
|
|
1324
|
+
onSelect: (i) => editor.edit(keys[i])
|
|
1325
|
+
},
|
|
1326
|
+
k
|
|
1327
|
+
)) });
|
|
1328
|
+
}
|
|
1329
|
+
function ValueInput({
|
|
1330
|
+
ariaLabel,
|
|
1331
|
+
value,
|
|
1332
|
+
onType,
|
|
1333
|
+
onPick,
|
|
1334
|
+
onBlur,
|
|
1335
|
+
onKeyDown,
|
|
1336
|
+
placeholder,
|
|
1337
|
+
readOnly,
|
|
1338
|
+
suggestions,
|
|
1339
|
+
className
|
|
1340
|
+
}) {
|
|
1341
|
+
if (!suggestions?.length)
|
|
1342
|
+
return /* @__PURE__ */ jsx10(
|
|
1343
|
+
Input4,
|
|
1344
|
+
{
|
|
1345
|
+
"aria-label": ariaLabel,
|
|
1346
|
+
value,
|
|
1347
|
+
onChange: (e) => onType(e.target.value),
|
|
1348
|
+
onBlur,
|
|
1349
|
+
onKeyDown,
|
|
1350
|
+
placeholder,
|
|
1351
|
+
readOnly,
|
|
1352
|
+
className
|
|
1353
|
+
}
|
|
1354
|
+
);
|
|
1355
|
+
const options = suggestions.map((s) => ({
|
|
1356
|
+
value: s.value,
|
|
1357
|
+
label: s.label ?? s.value
|
|
1358
|
+
}));
|
|
1359
|
+
if (value && !options.some((o) => o.value === value))
|
|
1360
|
+
options.unshift({ value, label: value });
|
|
1361
|
+
return /* @__PURE__ */ jsx10(
|
|
1362
|
+
FormSelect,
|
|
1363
|
+
{
|
|
1364
|
+
label: ariaLabel,
|
|
1365
|
+
compact: true,
|
|
1366
|
+
options,
|
|
1367
|
+
value: value || null,
|
|
1368
|
+
onChange: (picked) => onPick(picked ?? ""),
|
|
1369
|
+
allowCreate: true,
|
|
1370
|
+
onCreate: onPick,
|
|
1371
|
+
placeholder,
|
|
1372
|
+
searchPlaceholder: "Search, or type a value",
|
|
1373
|
+
readOnly,
|
|
1374
|
+
wrapperClassName: className
|
|
1375
|
+
}
|
|
1376
|
+
);
|
|
1377
|
+
}
|
|
1378
|
+
function PairRow({
|
|
1379
|
+
pairKey,
|
|
1380
|
+
pairValue,
|
|
1381
|
+
isDisabled,
|
|
1382
|
+
editor,
|
|
1383
|
+
suggestions
|
|
1384
|
+
}) {
|
|
1385
|
+
const [key, setKey] = React8.useState(pairKey);
|
|
1386
|
+
const [val, setVal] = React8.useState(pairValue);
|
|
1387
|
+
React8.useEffect(() => setKey(pairKey), [pairKey]);
|
|
1388
|
+
React8.useEffect(() => setVal(pairValue), [pairValue]);
|
|
1389
|
+
const commit = () => {
|
|
1390
|
+
if (!editor.replace(pairKey, key, val)) setKey(pairKey);
|
|
1391
|
+
};
|
|
1392
|
+
const onKeyDown = (e) => {
|
|
1393
|
+
if (e.key !== "Enter") return;
|
|
1394
|
+
e.preventDefault();
|
|
1395
|
+
commit();
|
|
1396
|
+
};
|
|
1397
|
+
return /* @__PURE__ */ jsxs9("li", { className: "flex items-center gap-2", children: [
|
|
1398
|
+
/* @__PURE__ */ jsx10(
|
|
1399
|
+
Input4,
|
|
1400
|
+
{
|
|
1401
|
+
"aria-label": `Key of ${pairKey}`,
|
|
1402
|
+
value: key,
|
|
1403
|
+
onChange: (e) => setKey(e.target.value),
|
|
1404
|
+
onBlur: commit,
|
|
1405
|
+
onKeyDown,
|
|
1406
|
+
readOnly: isDisabled,
|
|
1407
|
+
className: "h-8 w-1/3 shrink-0 font-mono text-xs"
|
|
1408
|
+
}
|
|
1409
|
+
),
|
|
1410
|
+
/* @__PURE__ */ jsx10(
|
|
1411
|
+
ValueInput,
|
|
1412
|
+
{
|
|
1413
|
+
ariaLabel: `Value of ${pairKey}`,
|
|
1414
|
+
value: val,
|
|
1415
|
+
onType: setVal,
|
|
1416
|
+
onPick: (picked) => {
|
|
1417
|
+
setVal(picked);
|
|
1418
|
+
if (!editor.replace(pairKey, key, picked)) setVal(pairValue);
|
|
1419
|
+
},
|
|
1420
|
+
onBlur: commit,
|
|
1421
|
+
onKeyDown,
|
|
1422
|
+
readOnly: isDisabled,
|
|
1423
|
+
suggestions,
|
|
1424
|
+
className: "h-8 min-w-0 flex-1 font-mono text-xs"
|
|
1425
|
+
}
|
|
1426
|
+
),
|
|
1427
|
+
!isDisabled && /* @__PURE__ */ jsx10(
|
|
1428
|
+
IconButton,
|
|
1429
|
+
{
|
|
1430
|
+
label: `Remove ${pairKey}`,
|
|
1431
|
+
tone: "destructive",
|
|
1432
|
+
onClick: () => editor.remove(pairKey),
|
|
1433
|
+
children: /* @__PURE__ */ jsx10(X4, {})
|
|
1434
|
+
}
|
|
1435
|
+
)
|
|
1436
|
+
] });
|
|
1437
|
+
}
|
|
1438
|
+
function PairRows({
|
|
1439
|
+
value,
|
|
1440
|
+
isDisabled,
|
|
1441
|
+
editor,
|
|
1442
|
+
suggestions
|
|
1443
|
+
}) {
|
|
1444
|
+
const keys = Object.keys(value);
|
|
1445
|
+
if (keys.length === 0) return null;
|
|
1446
|
+
return /* @__PURE__ */ jsx10("ul", { className: "space-y-1.5", children: keys.map((k, index) => /* @__PURE__ */ jsx10(
|
|
1447
|
+
PairRow,
|
|
1448
|
+
{
|
|
1449
|
+
pairKey: k,
|
|
1450
|
+
pairValue: value[k],
|
|
1451
|
+
isDisabled,
|
|
1452
|
+
editor,
|
|
1453
|
+
suggestions
|
|
1454
|
+
},
|
|
1455
|
+
index
|
|
1456
|
+
)) });
|
|
1457
|
+
}
|
|
1458
|
+
function PairKeys({
|
|
1459
|
+
value
|
|
1460
|
+
}) {
|
|
1461
|
+
const keys = Object.keys(value);
|
|
1462
|
+
return /* @__PURE__ */ jsx10("div", { className: "flex flex-wrap gap-1.5", children: keys.map((k) => /* @__PURE__ */ jsx10(
|
|
1463
|
+
Badge3,
|
|
1464
|
+
{
|
|
1465
|
+
variant: "outline",
|
|
1466
|
+
className: "font-mono text-[11px] font-normal",
|
|
1467
|
+
title: value[k],
|
|
1468
|
+
children: k
|
|
1469
|
+
},
|
|
1470
|
+
k
|
|
1471
|
+
)) });
|
|
1472
|
+
}
|
|
1473
|
+
function PairList({
|
|
1474
|
+
display,
|
|
1475
|
+
suggestions,
|
|
1476
|
+
...props
|
|
1477
|
+
}) {
|
|
1478
|
+
return display === "rows" ? /* @__PURE__ */ jsx10(PairRows, { ...props, suggestions }) : /* @__PURE__ */ jsx10(PairTags, { ...props });
|
|
1479
|
+
}
|
|
1480
|
+
var PairFields = React8.forwardRef(
|
|
1481
|
+
({
|
|
1482
|
+
id,
|
|
1483
|
+
name,
|
|
1484
|
+
keyPlaceholder = "Key",
|
|
1485
|
+
valuePlaceholder = "Value",
|
|
1486
|
+
asRow = false,
|
|
1487
|
+
editor,
|
|
1488
|
+
suggestions
|
|
1489
|
+
}, ref) => /* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-2", children: [
|
|
1490
|
+
/* @__PURE__ */ jsx10(
|
|
1491
|
+
Input4,
|
|
1492
|
+
{
|
|
1493
|
+
ref,
|
|
1494
|
+
id,
|
|
1495
|
+
name,
|
|
1496
|
+
value: editor.key,
|
|
1497
|
+
onChange: (e) => editor.typeKey(e.target.value),
|
|
1498
|
+
onKeyDown: editor.onKeyDown,
|
|
1499
|
+
placeholder: keyPlaceholder,
|
|
1500
|
+
className: cn9("h-8", asRow && "w-1/3 shrink-0 font-mono text-xs")
|
|
1501
|
+
}
|
|
1502
|
+
),
|
|
1503
|
+
/* @__PURE__ */ jsx10(
|
|
1504
|
+
ValueInput,
|
|
1505
|
+
{
|
|
1506
|
+
ariaLabel: valuePlaceholder,
|
|
1507
|
+
value: editor.val,
|
|
1508
|
+
onType: editor.typeValue,
|
|
1509
|
+
onPick: editor.typeValue,
|
|
1510
|
+
onKeyDown: editor.onKeyDown,
|
|
1511
|
+
placeholder: valuePlaceholder,
|
|
1512
|
+
suggestions,
|
|
1513
|
+
className: cn9("h-8", asRow && "min-w-0 flex-1 font-mono text-xs")
|
|
1514
|
+
}
|
|
1515
|
+
),
|
|
1516
|
+
/* @__PURE__ */ jsx10(
|
|
1517
|
+
Button3,
|
|
1518
|
+
{
|
|
1519
|
+
type: "button",
|
|
1520
|
+
variant: "outline",
|
|
1521
|
+
size: "compact",
|
|
1522
|
+
"aria-label": "Add",
|
|
1523
|
+
onClick: editor.add,
|
|
1524
|
+
children: /* @__PURE__ */ jsx10(Plus2, { className: "h-4 w-4" })
|
|
1525
|
+
}
|
|
1526
|
+
)
|
|
1527
|
+
] })
|
|
1528
|
+
);
|
|
1529
|
+
PairFields.displayName = "PairFields";
|
|
1530
|
+
function PairBox({
|
|
1531
|
+
isDisabled,
|
|
1532
|
+
hasError,
|
|
1533
|
+
children
|
|
1534
|
+
}) {
|
|
1535
|
+
return /* @__PURE__ */ jsx10(
|
|
1536
|
+
"div",
|
|
1537
|
+
{
|
|
1538
|
+
className: cn9(
|
|
1539
|
+
"w-full space-y-2 rounded-md border border-input bg-background px-3 py-2 text-sm",
|
|
1540
|
+
isDisabled && "cursor-not-allowed opacity-50",
|
|
1541
|
+
hasError && "border-destructive"
|
|
1542
|
+
),
|
|
1543
|
+
children
|
|
1544
|
+
}
|
|
1545
|
+
);
|
|
1546
|
+
}
|
|
1547
|
+
var PairEditorBox = React8.forwardRef(
|
|
1548
|
+
({
|
|
1549
|
+
display,
|
|
1550
|
+
value,
|
|
1551
|
+
separator,
|
|
1552
|
+
isDisabled,
|
|
1553
|
+
hasError,
|
|
1554
|
+
editor,
|
|
1555
|
+
suggestions,
|
|
1556
|
+
...fields
|
|
1557
|
+
}, ref) => /* @__PURE__ */ jsxs9(PairBox, { isDisabled, hasError, children: [
|
|
1558
|
+
/* @__PURE__ */ jsx10(
|
|
1559
|
+
PairList,
|
|
1560
|
+
{
|
|
1561
|
+
display,
|
|
1562
|
+
value,
|
|
1563
|
+
separator,
|
|
1564
|
+
isDisabled,
|
|
1565
|
+
editor,
|
|
1566
|
+
suggestions
|
|
1567
|
+
}
|
|
1568
|
+
),
|
|
1569
|
+
!isDisabled && /* @__PURE__ */ jsx10(
|
|
1570
|
+
PairFields,
|
|
1571
|
+
{
|
|
1572
|
+
ref,
|
|
1573
|
+
...fields,
|
|
1574
|
+
asRow: display === "rows",
|
|
1575
|
+
editor,
|
|
1576
|
+
suggestions
|
|
1577
|
+
}
|
|
1578
|
+
)
|
|
1579
|
+
] })
|
|
1580
|
+
);
|
|
1581
|
+
PairEditorBox.displayName = "PairEditorBox";
|
|
1582
|
+
var FormKeyValueInput = React8.forwardRef((props, ref) => {
|
|
1583
|
+
const {
|
|
1584
|
+
label,
|
|
1585
|
+
description,
|
|
1586
|
+
error,
|
|
1587
|
+
wrapperClassName,
|
|
1588
|
+
labelPlacement,
|
|
1589
|
+
id,
|
|
1590
|
+
value = {},
|
|
1591
|
+
onChange,
|
|
1592
|
+
separator = ":",
|
|
1593
|
+
display = "tags"
|
|
1594
|
+
} = props;
|
|
1595
|
+
const generatedId = React8.useId();
|
|
1596
|
+
const fieldId = id ?? generatedId;
|
|
1597
|
+
const editor = usePairEditor(value, onChange);
|
|
1598
|
+
return /* @__PURE__ */ jsx10(
|
|
1599
|
+
FormFieldWrapper,
|
|
1600
|
+
{
|
|
1601
|
+
inputId: fieldId,
|
|
1602
|
+
label: resolveFieldLabel(label),
|
|
1603
|
+
description,
|
|
1604
|
+
error: error ?? editor.problem ?? void 0,
|
|
1605
|
+
required: props.required ?? false,
|
|
1606
|
+
labelPlacement,
|
|
1607
|
+
className: wrapperClassName,
|
|
1608
|
+
children: display === "keys" ? /* @__PURE__ */ jsx10(PairKeys, { value }) : /* @__PURE__ */ jsx10(
|
|
1609
|
+
PairEditorBox,
|
|
1610
|
+
{
|
|
1611
|
+
ref,
|
|
1612
|
+
display,
|
|
1613
|
+
value,
|
|
1614
|
+
separator,
|
|
1615
|
+
isDisabled: Boolean(props.disabled || props.readOnly),
|
|
1616
|
+
hasError: Boolean(error),
|
|
1617
|
+
id: fieldId,
|
|
1618
|
+
name: props.name,
|
|
1619
|
+
keyPlaceholder: props.keyPlaceholder,
|
|
1620
|
+
valuePlaceholder: props.valuePlaceholder,
|
|
1621
|
+
editor,
|
|
1622
|
+
suggestions: props.valueSuggestions
|
|
1623
|
+
}
|
|
1624
|
+
)
|
|
1625
|
+
}
|
|
1626
|
+
);
|
|
1627
|
+
});
|
|
1628
|
+
FormKeyValueInput.displayName = "FormKeyValueInput";
|
|
1629
|
+
|
|
1201
1630
|
// src/FormQuantityInput.tsx
|
|
1202
|
-
import
|
|
1631
|
+
import React9, { useCallback as useCallback2, useEffect as useEffect3, useId as useId9, useMemo, useState as useState5 } from "react";
|
|
1203
1632
|
import { ChevronsUpDown as ChevronsUpDown3 } from "lucide-react";
|
|
1204
|
-
import { cn as
|
|
1633
|
+
import { cn as cn10 } from "@petrarca/sonnet-core";
|
|
1205
1634
|
import {
|
|
1206
1635
|
InputGroup,
|
|
1207
1636
|
InputGroupAddon,
|
|
1208
1637
|
InputGroupInput
|
|
1209
1638
|
} from "@petrarca/sonnet-ui";
|
|
1210
|
-
import { jsx as
|
|
1639
|
+
import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1211
1640
|
var VALID_NUMERIC_INPUT = /^-?\d*[.,]?\d*$/;
|
|
1212
1641
|
var INCOMPLETE_SENTINELS = /* @__PURE__ */ new Set(["", ".", "-", "-."]);
|
|
1213
1642
|
function roundToPrecision(n, p) {
|
|
@@ -1228,7 +1657,31 @@ function roundAndFormat(numValue, precision) {
|
|
|
1228
1657
|
const formatted = precision !== void 0 ? rounded.toFixed(precision) : String(rounded);
|
|
1229
1658
|
return { rounded, formatted };
|
|
1230
1659
|
}
|
|
1231
|
-
function
|
|
1660
|
+
function FreeUnitAddon({
|
|
1661
|
+
currentUnit,
|
|
1662
|
+
addonAlign,
|
|
1663
|
+
disabled,
|
|
1664
|
+
readOnly,
|
|
1665
|
+
onChange
|
|
1666
|
+
}) {
|
|
1667
|
+
return /* @__PURE__ */ jsx11(InputGroupAddon, { align: addonAlign, children: /* @__PURE__ */ jsx11(
|
|
1668
|
+
"input",
|
|
1669
|
+
{
|
|
1670
|
+
value: currentUnit,
|
|
1671
|
+
onChange,
|
|
1672
|
+
disabled,
|
|
1673
|
+
readOnly,
|
|
1674
|
+
placeholder: "unit",
|
|
1675
|
+
"aria-label": "Unit",
|
|
1676
|
+
className: "w-16 border-0 bg-transparent px-1 text-right text-sm text-muted-foreground outline-none placeholder:text-muted-foreground/60 focus:text-foreground"
|
|
1677
|
+
}
|
|
1678
|
+
) });
|
|
1679
|
+
}
|
|
1680
|
+
function UnitAddon({ units, freeUnit, ...rest }) {
|
|
1681
|
+
if (units.length === 0) return freeUnit ? /* @__PURE__ */ jsx11(FreeUnitAddon, { ...rest }) : null;
|
|
1682
|
+
return /* @__PURE__ */ jsx11(UnitPicker, { units, ...rest });
|
|
1683
|
+
}
|
|
1684
|
+
function UnitPicker({
|
|
1232
1685
|
units,
|
|
1233
1686
|
currentUnit,
|
|
1234
1687
|
addonAlign,
|
|
@@ -1236,12 +1689,11 @@ function UnitAddon({
|
|
|
1236
1689
|
readOnly,
|
|
1237
1690
|
onChange
|
|
1238
1691
|
}) {
|
|
1239
|
-
if (units.length === 0) return null;
|
|
1240
1692
|
if (units.length === 1) {
|
|
1241
|
-
return /* @__PURE__ */
|
|
1693
|
+
return /* @__PURE__ */ jsx11(InputGroupAddon, { align: addonAlign, children: /* @__PURE__ */ jsx11("span", { className: "text-sm text-muted-foreground", children: units[0].label }) });
|
|
1242
1694
|
}
|
|
1243
|
-
return /* @__PURE__ */
|
|
1244
|
-
/* @__PURE__ */
|
|
1695
|
+
return /* @__PURE__ */ jsx11(InputGroupAddon, { align: addonAlign, children: /* @__PURE__ */ jsxs10("div", { className: "relative flex items-center", children: [
|
|
1696
|
+
/* @__PURE__ */ jsx11(
|
|
1245
1697
|
"select",
|
|
1246
1698
|
{
|
|
1247
1699
|
value: currentUnit,
|
|
@@ -1249,15 +1701,16 @@ function UnitAddon({
|
|
|
1249
1701
|
disabled: disabled || readOnly,
|
|
1250
1702
|
className: "cursor-pointer appearance-none border-0 bg-transparent py-0 pr-5 pl-1 text-sm text-muted-foreground outline-none hover:text-foreground focus:text-foreground",
|
|
1251
1703
|
"aria-label": "Unit",
|
|
1252
|
-
children: units.map((u) => /* @__PURE__ */
|
|
1704
|
+
children: units.map((u) => /* @__PURE__ */ jsx11("option", { value: u.value, children: u.label }, u.value))
|
|
1253
1705
|
}
|
|
1254
1706
|
),
|
|
1255
|
-
/* @__PURE__ */
|
|
1707
|
+
/* @__PURE__ */ jsx11(ChevronsUpDown3, { className: "pointer-events-none absolute right-0 h-3.5 w-3.5 text-muted-foreground/60" })
|
|
1256
1708
|
] }) });
|
|
1257
1709
|
}
|
|
1258
1710
|
function useUnitState(value, units, unitPosition, min, max) {
|
|
1259
1711
|
const currentUnit = useMemo(() => {
|
|
1260
1712
|
const preferred = value?.unit;
|
|
1713
|
+
if (units.length === 0) return preferred ?? "";
|
|
1261
1714
|
if (preferred && units.some((u) => u.value === preferred)) return preferred;
|
|
1262
1715
|
return units[0]?.value ?? "";
|
|
1263
1716
|
}, [value?.unit, units]);
|
|
@@ -1272,11 +1725,11 @@ function useUnitState(value, units, unitPosition, min, max) {
|
|
|
1272
1725
|
return { currentUnit, effectiveMin, effectiveMax, addonAlign };
|
|
1273
1726
|
}
|
|
1274
1727
|
function useQuantityInput(value, onChange, onBlur, currentUnit, precision, effectiveMin, effectiveMax, externalError) {
|
|
1275
|
-
const [rawInput, setRawInput] =
|
|
1728
|
+
const [rawInput, setRawInput] = useState5(
|
|
1276
1729
|
value?.value !== void 0 ? String(value.value) : ""
|
|
1277
1730
|
);
|
|
1278
|
-
const [validationError, setValidationError] =
|
|
1279
|
-
|
|
1731
|
+
const [validationError, setValidationError] = useState5("");
|
|
1732
|
+
useEffect3(() => {
|
|
1280
1733
|
const external = value?.value !== void 0 ? String(value.value) : "";
|
|
1281
1734
|
setRawInput((prev) => {
|
|
1282
1735
|
const parsed = parseFloat(prev.replace(",", "."));
|
|
@@ -1341,7 +1794,7 @@ function useQuantityInput(value, onChange, onBlur, currentUnit, precision, effec
|
|
|
1341
1794
|
setValidationError
|
|
1342
1795
|
};
|
|
1343
1796
|
}
|
|
1344
|
-
var FormQuantityInput =
|
|
1797
|
+
var FormQuantityInput = React9.forwardRef((allProps, ref) => {
|
|
1345
1798
|
const {
|
|
1346
1799
|
value,
|
|
1347
1800
|
onChange,
|
|
@@ -1360,12 +1813,13 @@ var FormQuantityInput = React8.forwardRef((allProps, ref) => {
|
|
|
1360
1813
|
wrapperClassName,
|
|
1361
1814
|
labelPlacement,
|
|
1362
1815
|
className,
|
|
1363
|
-
name
|
|
1816
|
+
name,
|
|
1817
|
+
freeUnit
|
|
1364
1818
|
} = allProps;
|
|
1365
1819
|
const units = useMemo(() => allProps.units ?? [], [allProps.units]);
|
|
1366
1820
|
const unitPosition = allProps.unitPosition ?? "suffix";
|
|
1367
1821
|
const error = allProps.error;
|
|
1368
|
-
const generatedId =
|
|
1822
|
+
const generatedId = useId9();
|
|
1369
1823
|
const inputId = allProps.id ?? generatedId;
|
|
1370
1824
|
const { currentUnit, effectiveMin, effectiveMax, addonAlign } = useUnitState(
|
|
1371
1825
|
value,
|
|
@@ -1397,7 +1851,7 @@ var FormQuantityInput = React8.forwardRef((allProps, ref) => {
|
|
|
1397
1851
|
setValidationError("");
|
|
1398
1852
|
const normalized = rawInput.replace(",", ".");
|
|
1399
1853
|
const numValue = parseFloat(normalized);
|
|
1400
|
-
if (isNaN(numValue)) return;
|
|
1854
|
+
if (isNaN(numValue)) return emit(void 0, unitValue);
|
|
1401
1855
|
const um = units.find((u) => u.value === unitValue);
|
|
1402
1856
|
const lo = um?.min ?? min;
|
|
1403
1857
|
const hi = um?.max ?? max;
|
|
@@ -1407,10 +1861,11 @@ var FormQuantityInput = React8.forwardRef((allProps, ref) => {
|
|
|
1407
1861
|
[rawInput, units, min, max, emit, setValidationError]
|
|
1408
1862
|
);
|
|
1409
1863
|
const unitAddon = useMemo(
|
|
1410
|
-
() => /* @__PURE__ */
|
|
1864
|
+
() => /* @__PURE__ */ jsx11(
|
|
1411
1865
|
UnitAddon,
|
|
1412
1866
|
{
|
|
1413
1867
|
units,
|
|
1868
|
+
freeUnit,
|
|
1414
1869
|
currentUnit,
|
|
1415
1870
|
addonAlign,
|
|
1416
1871
|
disabled,
|
|
@@ -1418,9 +1873,17 @@ var FormQuantityInput = React8.forwardRef((allProps, ref) => {
|
|
|
1418
1873
|
onChange: handleUnitChange
|
|
1419
1874
|
}
|
|
1420
1875
|
),
|
|
1421
|
-
[
|
|
1876
|
+
[
|
|
1877
|
+
units,
|
|
1878
|
+
freeUnit,
|
|
1879
|
+
currentUnit,
|
|
1880
|
+
addonAlign,
|
|
1881
|
+
disabled,
|
|
1882
|
+
readOnly,
|
|
1883
|
+
handleUnitChange
|
|
1884
|
+
]
|
|
1422
1885
|
);
|
|
1423
|
-
return /* @__PURE__ */
|
|
1886
|
+
return /* @__PURE__ */ jsx11(
|
|
1424
1887
|
FormFieldWrapper,
|
|
1425
1888
|
{
|
|
1426
1889
|
inputId,
|
|
@@ -1430,13 +1893,13 @@ var FormQuantityInput = React8.forwardRef((allProps, ref) => {
|
|
|
1430
1893
|
required,
|
|
1431
1894
|
labelPlacement,
|
|
1432
1895
|
className: wrapperClassName,
|
|
1433
|
-
children: /* @__PURE__ */
|
|
1896
|
+
children: /* @__PURE__ */ jsxs10(
|
|
1434
1897
|
InputGroup,
|
|
1435
1898
|
{
|
|
1436
1899
|
"data-disabled": disabled || void 0,
|
|
1437
|
-
className:
|
|
1900
|
+
className: cn10(resolvedError && "border-destructive"),
|
|
1438
1901
|
children: [
|
|
1439
|
-
/* @__PURE__ */
|
|
1902
|
+
/* @__PURE__ */ jsx11(
|
|
1440
1903
|
InputGroupInput,
|
|
1441
1904
|
{
|
|
1442
1905
|
id: inputId,
|
|
@@ -1474,9 +1937,9 @@ var FormQuantityInput = React8.forwardRef((allProps, ref) => {
|
|
|
1474
1937
|
FormQuantityInput.displayName = "FormQuantityInput";
|
|
1475
1938
|
|
|
1476
1939
|
// src/FormActions.tsx
|
|
1477
|
-
import { Button as
|
|
1940
|
+
import { Button as Button4 } from "@petrarca/sonnet-ui";
|
|
1478
1941
|
import { SimpleGroup } from "@petrarca/sonnet-ui";
|
|
1479
|
-
import { jsx as
|
|
1942
|
+
import { jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
1480
1943
|
function isSaveDisabled(args) {
|
|
1481
1944
|
if (args.disabled || !args.hasChanges || args.isValidating) return true;
|
|
1482
1945
|
return args.saveWhenInvalid === "disable" && !args.isValid;
|
|
@@ -1502,11 +1965,11 @@ function FormActions({
|
|
|
1502
1965
|
saveWhenInvalid
|
|
1503
1966
|
});
|
|
1504
1967
|
const keepFocus = (e) => e.preventDefault();
|
|
1505
|
-
return /* @__PURE__ */
|
|
1506
|
-
/* @__PURE__ */
|
|
1507
|
-
/* @__PURE__ */
|
|
1508
|
-
showCancel && /* @__PURE__ */
|
|
1509
|
-
|
|
1968
|
+
return /* @__PURE__ */ jsxs11("div", { className: "flex items-center justify-between mt-4", children: [
|
|
1969
|
+
/* @__PURE__ */ jsx12("div", { className: "flex items-center gap-2", children: leadingActions }),
|
|
1970
|
+
/* @__PURE__ */ jsxs11(SimpleGroup, { justify: "flex-end", children: [
|
|
1971
|
+
showCancel && /* @__PURE__ */ jsx12(
|
|
1972
|
+
Button4,
|
|
1510
1973
|
{
|
|
1511
1974
|
variant: "outline",
|
|
1512
1975
|
onClick: onCancel,
|
|
@@ -1515,8 +1978,8 @@ function FormActions({
|
|
|
1515
1978
|
children: cancelLabel
|
|
1516
1979
|
}
|
|
1517
1980
|
),
|
|
1518
|
-
/* @__PURE__ */
|
|
1519
|
-
|
|
1981
|
+
/* @__PURE__ */ jsx12(
|
|
1982
|
+
Button4,
|
|
1520
1983
|
{
|
|
1521
1984
|
onClick: onSave,
|
|
1522
1985
|
onMouseDown: keepFocus,
|
|
@@ -1534,7 +1997,7 @@ import { ChevronDown, ChevronRight } from "lucide-react";
|
|
|
1534
1997
|
import { Card } from "@petrarca/sonnet-ui";
|
|
1535
1998
|
import { useDisclosure } from "@petrarca/sonnet-core/hooks";
|
|
1536
1999
|
import { Collapsible, CollapsibleContent } from "@petrarca/sonnet-ui";
|
|
1537
|
-
import { jsx as
|
|
2000
|
+
import { jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1538
2001
|
function ExtraPropertiesCard({ properties, schema }) {
|
|
1539
2002
|
const [opened, { toggle }] = useDisclosure(false);
|
|
1540
2003
|
const extraProperties = useMemo2(() => {
|
|
@@ -1546,32 +2009,35 @@ function ExtraPropertiesCard({ properties, schema }) {
|
|
|
1546
2009
|
return Object.keys(extra).length > 0 ? extra : null;
|
|
1547
2010
|
}, [properties, schema]);
|
|
1548
2011
|
if (!extraProperties) return null;
|
|
1549
|
-
return /* @__PURE__ */
|
|
1550
|
-
/* @__PURE__ */
|
|
2012
|
+
return /* @__PURE__ */ jsxs12(Card, { className: "border p-3", children: [
|
|
2013
|
+
/* @__PURE__ */ jsxs12(
|
|
1551
2014
|
"p",
|
|
1552
2015
|
{
|
|
1553
2016
|
className: `flex items-center gap-1 text-sm font-medium cursor-pointer select-none ${opened ? "mb-1" : ""}`,
|
|
1554
2017
|
onClick: toggle,
|
|
1555
2018
|
children: [
|
|
1556
|
-
opened ? /* @__PURE__ */
|
|
2019
|
+
opened ? /* @__PURE__ */ jsx13(ChevronDown, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsx13(ChevronRight, { className: "h-3.5 w-3.5" }),
|
|
1557
2020
|
"Extra Properties (not in schema)"
|
|
1558
2021
|
]
|
|
1559
2022
|
}
|
|
1560
2023
|
),
|
|
1561
|
-
/* @__PURE__ */
|
|
2024
|
+
/* @__PURE__ */ jsx13(Collapsible, { open: opened, children: /* @__PURE__ */ jsx13(CollapsibleContent, { children: /* @__PURE__ */ jsx13("pre", { className: "text-xs bg-muted p-2 rounded overflow-x-auto", children: /* @__PURE__ */ jsx13("code", { children: JSON.stringify(extraProperties, null, 2) }) }) }) })
|
|
1562
2025
|
] });
|
|
1563
2026
|
}
|
|
1564
2027
|
var ExtraPropertiesCard_default = ExtraPropertiesCard;
|
|
1565
2028
|
|
|
1566
2029
|
// src/JsonSchemaFormRenderer.tsx
|
|
1567
|
-
import
|
|
2030
|
+
import React18, { useCallback as useCallback9, useContext as useContext2, useMemo as useMemo12 } from "react";
|
|
1568
2031
|
import { SimpleStack } from "@petrarca/sonnet-ui";
|
|
1569
2032
|
import { AlertCircle as AlertCircle2 } from "lucide-react";
|
|
1570
2033
|
import {
|
|
1571
2034
|
WIDTH_TOKEN_REMS
|
|
1572
2035
|
} from "@petrarca/sonnet-core/schema";
|
|
1573
|
-
import {
|
|
1574
|
-
|
|
2036
|
+
import {
|
|
2037
|
+
isFieldRequired,
|
|
2038
|
+
evaluateUiRule,
|
|
2039
|
+
stripFormItemIds as stripFormItemIds2
|
|
2040
|
+
} from "@petrarca/sonnet-core/schema";
|
|
1575
2041
|
|
|
1576
2042
|
// src/widgets/types.ts
|
|
1577
2043
|
function firstError(rawErrors) {
|
|
@@ -1579,7 +2045,7 @@ function firstError(rawErrors) {
|
|
|
1579
2045
|
}
|
|
1580
2046
|
|
|
1581
2047
|
// src/widgets/TextInputWidget.tsx
|
|
1582
|
-
import { jsx as
|
|
2048
|
+
import { jsx as jsx14 } from "react/jsx-runtime";
|
|
1583
2049
|
function inputTypeFromFormat(format) {
|
|
1584
2050
|
if (format === "email") return "email";
|
|
1585
2051
|
if (format === "uri" || format === "url") return "url";
|
|
@@ -1604,7 +2070,7 @@ function TextInputWidget({
|
|
|
1604
2070
|
}) {
|
|
1605
2071
|
const error = firstError(rawErrors);
|
|
1606
2072
|
const compact = options?.compact;
|
|
1607
|
-
return /* @__PURE__ */
|
|
2073
|
+
return /* @__PURE__ */ jsx14(
|
|
1608
2074
|
FormInput,
|
|
1609
2075
|
{
|
|
1610
2076
|
id,
|
|
@@ -1631,7 +2097,7 @@ function TextInputWidget({
|
|
|
1631
2097
|
}
|
|
1632
2098
|
|
|
1633
2099
|
// src/widgets/TextareaWidget.tsx
|
|
1634
|
-
import { jsx as
|
|
2100
|
+
import { jsx as jsx15 } from "react/jsx-runtime";
|
|
1635
2101
|
function TextareaWidget({
|
|
1636
2102
|
id,
|
|
1637
2103
|
name,
|
|
@@ -1652,7 +2118,7 @@ function TextareaWidget({
|
|
|
1652
2118
|
const minRows = options.rows || options.minRows || 3;
|
|
1653
2119
|
const autosize = options.autosize !== false;
|
|
1654
2120
|
const error = firstError(rawErrors);
|
|
1655
|
-
return /* @__PURE__ */
|
|
2121
|
+
return /* @__PURE__ */ jsx15(
|
|
1656
2122
|
FormTextarea,
|
|
1657
2123
|
{
|
|
1658
2124
|
id,
|
|
@@ -1678,7 +2144,7 @@ function TextareaWidget({
|
|
|
1678
2144
|
}
|
|
1679
2145
|
|
|
1680
2146
|
// src/widgets/NumberWidget.tsx
|
|
1681
|
-
import { jsx as
|
|
2147
|
+
import { jsx as jsx16 } from "react/jsx-runtime";
|
|
1682
2148
|
function NumberWidget({
|
|
1683
2149
|
id,
|
|
1684
2150
|
name,
|
|
@@ -1700,7 +2166,7 @@ function NumberWidget({
|
|
|
1700
2166
|
const step = options.step ?? (isInteger ? 1 : void 0);
|
|
1701
2167
|
const allowDecimal = options.allowDecimal ?? !isInteger;
|
|
1702
2168
|
const error = firstError(rawErrors);
|
|
1703
|
-
return /* @__PURE__ */
|
|
2169
|
+
return /* @__PURE__ */ jsx16(
|
|
1704
2170
|
FormNumberInput,
|
|
1705
2171
|
{
|
|
1706
2172
|
id,
|
|
@@ -1728,7 +2194,7 @@ function NumberWidget({
|
|
|
1728
2194
|
// src/widgets/CheckboxWidget.tsx
|
|
1729
2195
|
import { useCallback as useCallback3 } from "react";
|
|
1730
2196
|
import { isNullableBoolean } from "@petrarca/sonnet-core/schema";
|
|
1731
|
-
import { jsx as
|
|
2197
|
+
import { jsx as jsx17 } from "react/jsx-runtime";
|
|
1732
2198
|
function CheckboxWidget({
|
|
1733
2199
|
id,
|
|
1734
2200
|
value,
|
|
@@ -1747,12 +2213,12 @@ function CheckboxWidget({
|
|
|
1747
2213
|
const compact = options?.compact;
|
|
1748
2214
|
const isTriState = isNullableBoolean(propertySchema);
|
|
1749
2215
|
const isChecked = value === true;
|
|
1750
|
-
const isIndeterminate = isTriState && value
|
|
2216
|
+
const isIndeterminate = isTriState && value == null;
|
|
1751
2217
|
const checkedState = isIndeterminate ? "indeterminate" : isChecked;
|
|
1752
2218
|
const handleChange = useCallback3(
|
|
1753
2219
|
(_newChecked) => {
|
|
1754
2220
|
if (isTriState) {
|
|
1755
|
-
if (value
|
|
2221
|
+
if (value == null) {
|
|
1756
2222
|
onChange(true);
|
|
1757
2223
|
} else if (value === true) {
|
|
1758
2224
|
onChange(false);
|
|
@@ -1765,7 +2231,7 @@ function CheckboxWidget({
|
|
|
1765
2231
|
},
|
|
1766
2232
|
[isTriState, value, onChange]
|
|
1767
2233
|
);
|
|
1768
|
-
return /* @__PURE__ */
|
|
2234
|
+
return /* @__PURE__ */ jsx17(
|
|
1769
2235
|
FormCheckbox,
|
|
1770
2236
|
{
|
|
1771
2237
|
id,
|
|
@@ -1785,15 +2251,7 @@ function CheckboxWidget({
|
|
|
1785
2251
|
|
|
1786
2252
|
// src/widgets/SelectWidget.tsx
|
|
1787
2253
|
import { useRef as useRef3 } from "react";
|
|
1788
|
-
import {
|
|
1789
|
-
import { jsx as jsx16 } from "react/jsx-runtime";
|
|
1790
|
-
function buildSelectOptions(propertySchema, enumNames) {
|
|
1791
|
-
const enumValues = extractEnumValues(propertySchema);
|
|
1792
|
-
return enumValues.map((val) => {
|
|
1793
|
-
const key = String(val);
|
|
1794
|
-
return { value: key, label: enumNames[key] || key };
|
|
1795
|
-
});
|
|
1796
|
-
}
|
|
2254
|
+
import { jsx as jsx18 } from "react/jsx-runtime";
|
|
1797
2255
|
function normalizeMultiValue(value) {
|
|
1798
2256
|
if (Array.isArray(value)) return value.map(String);
|
|
1799
2257
|
if (value) return [String(value)];
|
|
@@ -1833,7 +2291,7 @@ function SelectWidget(props) {
|
|
|
1833
2291
|
const triggerClassName = compact ? "h-8 text-xs" : void 0;
|
|
1834
2292
|
const handleBlur = () => onBlur?.(id, valueRef.current);
|
|
1835
2293
|
if (isMultiple) {
|
|
1836
|
-
return /* @__PURE__ */
|
|
2294
|
+
return /* @__PURE__ */ jsx18(
|
|
1837
2295
|
FormMultiSelect,
|
|
1838
2296
|
{
|
|
1839
2297
|
id,
|
|
@@ -1857,7 +2315,7 @@ function SelectWidget(props) {
|
|
|
1857
2315
|
}
|
|
1858
2316
|
);
|
|
1859
2317
|
}
|
|
1860
|
-
return /* @__PURE__ */
|
|
2318
|
+
return /* @__PURE__ */ jsx18(
|
|
1861
2319
|
FormSelect,
|
|
1862
2320
|
{
|
|
1863
2321
|
id,
|
|
@@ -1885,7 +2343,7 @@ function SelectWidget(props) {
|
|
|
1885
2343
|
}
|
|
1886
2344
|
|
|
1887
2345
|
// src/widgets/TagsInputWidget.tsx
|
|
1888
|
-
import { jsx as
|
|
2346
|
+
import { jsx as jsx19 } from "react/jsx-runtime";
|
|
1889
2347
|
function TagsInputWidget({
|
|
1890
2348
|
id,
|
|
1891
2349
|
name,
|
|
@@ -1902,7 +2360,7 @@ function TagsInputWidget({
|
|
|
1902
2360
|
}) {
|
|
1903
2361
|
const error = firstError(rawErrors);
|
|
1904
2362
|
const tags = Array.isArray(value) ? value.map(String) : [];
|
|
1905
|
-
return /* @__PURE__ */
|
|
2363
|
+
return /* @__PURE__ */ jsx19(
|
|
1906
2364
|
FormTagsInput,
|
|
1907
2365
|
{
|
|
1908
2366
|
id,
|
|
@@ -1925,9 +2383,13 @@ function TagsInputWidget({
|
|
|
1925
2383
|
}
|
|
1926
2384
|
|
|
1927
2385
|
// src/widgets/JsonEditorWidget.tsx
|
|
1928
|
-
import { useCallback as useCallback4, useState as
|
|
1929
|
-
import {
|
|
1930
|
-
|
|
2386
|
+
import { Suspense, lazy, useCallback as useCallback4, useState as useState6 } from "react";
|
|
2387
|
+
import { jsx as jsx20, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
2388
|
+
var JsonEditor = lazy(
|
|
2389
|
+
() => import("@petrarca/sonnet-ui/json-editor").then((m) => ({
|
|
2390
|
+
default: m.JsonEditor
|
|
2391
|
+
}))
|
|
2392
|
+
);
|
|
1931
2393
|
var FULL_DOCUMENT = ["/"];
|
|
1932
2394
|
function JsonEditorWidget({
|
|
1933
2395
|
id,
|
|
@@ -1938,7 +2400,7 @@ function JsonEditorWidget({
|
|
|
1938
2400
|
required,
|
|
1939
2401
|
options
|
|
1940
2402
|
}) {
|
|
1941
|
-
const [raw, setRaw] =
|
|
2403
|
+
const [raw, setRaw] = useState6(
|
|
1942
2404
|
value != null ? JSON.stringify(value, null, 2) : ""
|
|
1943
2405
|
);
|
|
1944
2406
|
const height = options?.height ?? "240px";
|
|
@@ -1953,54 +2415,116 @@ function JsonEditorWidget({
|
|
|
1953
2415
|
},
|
|
1954
2416
|
[onChange]
|
|
1955
2417
|
);
|
|
1956
|
-
return /* @__PURE__ */
|
|
1957
|
-
label && /* @__PURE__ */
|
|
2418
|
+
return /* @__PURE__ */ jsxs13("div", { className: "space-y-2", children: [
|
|
2419
|
+
label && /* @__PURE__ */ jsxs13("label", { htmlFor: id, className: "text-sm font-medium leading-none", children: [
|
|
1958
2420
|
label,
|
|
1959
|
-
required && /* @__PURE__ */
|
|
2421
|
+
required && /* @__PURE__ */ jsx20("span", { className: "text-destructive ml-1", children: "*" })
|
|
1960
2422
|
] }),
|
|
1961
|
-
description && /* @__PURE__ */
|
|
1962
|
-
/* @__PURE__ */
|
|
1963
|
-
|
|
2423
|
+
description && /* @__PURE__ */ jsx20("p", { className: "text-sm text-muted-foreground", children: description }),
|
|
2424
|
+
/* @__PURE__ */ jsx20(
|
|
2425
|
+
Suspense,
|
|
1964
2426
|
{
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
2427
|
+
fallback: /* @__PURE__ */ jsx20(
|
|
2428
|
+
"div",
|
|
2429
|
+
{
|
|
2430
|
+
className: "rounded-md border bg-muted/30",
|
|
2431
|
+
style: { height },
|
|
2432
|
+
"aria-busy": true
|
|
2433
|
+
}
|
|
2434
|
+
),
|
|
2435
|
+
children: /* @__PURE__ */ jsx20(
|
|
2436
|
+
JsonEditor,
|
|
2437
|
+
{
|
|
2438
|
+
value: raw,
|
|
2439
|
+
editablePaths: FULL_DOCUMENT,
|
|
2440
|
+
onChange: handleChange,
|
|
2441
|
+
height,
|
|
2442
|
+
className: "rounded-md border overflow-hidden"
|
|
2443
|
+
}
|
|
2444
|
+
)
|
|
1970
2445
|
}
|
|
1971
2446
|
)
|
|
1972
2447
|
] });
|
|
1973
2448
|
}
|
|
1974
2449
|
|
|
1975
|
-
// src/widgets/
|
|
1976
|
-
import {
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
import { jsx as jsx19, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1980
|
-
var VALID_MODES = ["eager", "typeahead", "explicit"];
|
|
1981
|
-
function resolveSelectMode(options) {
|
|
1982
|
-
const rawMode = options?.mode;
|
|
1983
|
-
if (typeof rawMode === "string" && VALID_MODES.includes(rawMode)) {
|
|
1984
|
-
return rawMode;
|
|
1985
|
-
}
|
|
1986
|
-
return "eager";
|
|
1987
|
-
}
|
|
1988
|
-
function resolveMinChars(options) {
|
|
1989
|
-
const rawMinChars = options?.minChars;
|
|
1990
|
-
if (typeof rawMinChars === "number" && rawMinChars >= 1) return rawMinChars;
|
|
1991
|
-
return 1;
|
|
2450
|
+
// src/widgets/KeyValueWidget.tsx
|
|
2451
|
+
import { jsx as jsx21 } from "react/jsx-runtime";
|
|
2452
|
+
function displayOf(display) {
|
|
2453
|
+
return display === "rows" || display === "keys" ? display : "tags";
|
|
1992
2454
|
}
|
|
1993
|
-
function
|
|
1994
|
-
if (!
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2455
|
+
function asStringMap(value) {
|
|
2456
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return {};
|
|
2457
|
+
return Object.fromEntries(
|
|
2458
|
+
Object.entries(value).map(([k, v]) => [
|
|
2459
|
+
k,
|
|
2460
|
+
String(v)
|
|
2461
|
+
])
|
|
2462
|
+
);
|
|
2463
|
+
}
|
|
2464
|
+
function KeyValueWidget({
|
|
2465
|
+
id,
|
|
2466
|
+
name,
|
|
2467
|
+
value,
|
|
2468
|
+
onChange,
|
|
2469
|
+
required,
|
|
2470
|
+
disabled,
|
|
2471
|
+
readonly,
|
|
2472
|
+
rawErrors,
|
|
2473
|
+
label,
|
|
2474
|
+
description,
|
|
2475
|
+
options
|
|
2476
|
+
}) {
|
|
2477
|
+
return /* @__PURE__ */ jsx21(
|
|
2478
|
+
FormKeyValueInput,
|
|
2479
|
+
{
|
|
2480
|
+
id,
|
|
2481
|
+
name,
|
|
2482
|
+
value: asStringMap(value),
|
|
2483
|
+
onChange: (next) => onChange(next),
|
|
2484
|
+
label,
|
|
2485
|
+
labelPlacement: options?.labelPlacement,
|
|
2486
|
+
description,
|
|
2487
|
+
required,
|
|
2488
|
+
disabled,
|
|
2489
|
+
readOnly: readonly,
|
|
2490
|
+
error: firstError(rawErrors),
|
|
2491
|
+
keyPlaceholder: options?.keyPlaceholder,
|
|
2492
|
+
valuePlaceholder: options?.valuePlaceholder,
|
|
2493
|
+
separator: options?.separator,
|
|
2494
|
+
display: displayOf(options?.display)
|
|
2495
|
+
}
|
|
2496
|
+
);
|
|
2497
|
+
}
|
|
2498
|
+
|
|
2499
|
+
// src/widgets/EntitySelectWidget.tsx
|
|
2500
|
+
import { useMemo as useMemo3 } from "react";
|
|
2501
|
+
import { EntitySelect } from "@petrarca/sonnet-ui";
|
|
2502
|
+
import { useFetcherFactory } from "@petrarca/sonnet-core/entityOptions";
|
|
2503
|
+
import { jsx as jsx22, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
2504
|
+
var VALID_MODES = ["eager", "typeahead", "explicit"];
|
|
2505
|
+
function resolveSelectMode(options) {
|
|
2506
|
+
const rawMode = options?.mode;
|
|
2507
|
+
if (typeof rawMode === "string" && VALID_MODES.includes(rawMode)) {
|
|
2508
|
+
return rawMode;
|
|
2509
|
+
}
|
|
2510
|
+
return "eager";
|
|
2511
|
+
}
|
|
2512
|
+
function resolveMinChars(options) {
|
|
2513
|
+
const rawMinChars = options?.minChars;
|
|
2514
|
+
if (typeof rawMinChars === "number" && rawMinChars >= 1) return rawMinChars;
|
|
2515
|
+
return 1;
|
|
2516
|
+
}
|
|
2517
|
+
function buildRestConfig(options) {
|
|
2518
|
+
if (!("endpoint" in options) || !options.endpoint) return null;
|
|
2519
|
+
const rawExtra = options.extraParams;
|
|
2520
|
+
const extraParams = rawExtra && typeof rawExtra === "object" ? rawExtra : void 0;
|
|
2521
|
+
return {
|
|
2522
|
+
endpoint: String(options.endpoint),
|
|
2523
|
+
valueKey: String(options.valueKey ?? "id"),
|
|
2524
|
+
labelKey: String(options.labelKey ?? "name"),
|
|
2525
|
+
searchKey: options.searchKey ? String(options.searchKey) : void 0,
|
|
2526
|
+
extraParams
|
|
2527
|
+
};
|
|
2004
2528
|
}
|
|
2005
2529
|
function buildGraphqlConfig(options) {
|
|
2006
2530
|
if (!("query" in options) || !options.query) return null;
|
|
@@ -2048,13 +2572,13 @@ function EntitySelectWidget({
|
|
|
2048
2572
|
[fetcherConfig, name]
|
|
2049
2573
|
);
|
|
2050
2574
|
if (!fetcher) {
|
|
2051
|
-
return /* @__PURE__ */
|
|
2575
|
+
return /* @__PURE__ */ jsxs14("div", { className: "text-sm text-destructive", children: [
|
|
2052
2576
|
'EntitySelectWidget: missing endpoint or query in x-ui-options for field "',
|
|
2053
2577
|
name,
|
|
2054
2578
|
'"'
|
|
2055
2579
|
] });
|
|
2056
2580
|
}
|
|
2057
|
-
return /* @__PURE__ */
|
|
2581
|
+
return /* @__PURE__ */ jsx22(
|
|
2058
2582
|
EntitySelect,
|
|
2059
2583
|
{
|
|
2060
2584
|
id,
|
|
@@ -2100,7 +2624,7 @@ function useNestedFormContext() {
|
|
|
2100
2624
|
}
|
|
2101
2625
|
|
|
2102
2626
|
// src/templates/DefaultObjectContainerTemplate.tsx
|
|
2103
|
-
import { useState as
|
|
2627
|
+
import { useState as useState7 } from "react";
|
|
2104
2628
|
import { ChevronDown as ChevronDown2, ChevronRight as ChevronRight2 } from "lucide-react";
|
|
2105
2629
|
import { Card as Card2, CardContent, CardHeader, CardTitle } from "@petrarca/sonnet-ui";
|
|
2106
2630
|
import {
|
|
@@ -2108,18 +2632,18 @@ import {
|
|
|
2108
2632
|
CollapsibleContent as CollapsibleContent2,
|
|
2109
2633
|
CollapsibleTrigger
|
|
2110
2634
|
} from "@petrarca/sonnet-ui";
|
|
2111
|
-
import { jsx as
|
|
2635
|
+
import { jsx as jsx23, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
2112
2636
|
function CardVariant({
|
|
2113
2637
|
children,
|
|
2114
2638
|
label,
|
|
2115
2639
|
description
|
|
2116
2640
|
}) {
|
|
2117
|
-
return /* @__PURE__ */
|
|
2118
|
-
label && /* @__PURE__ */
|
|
2119
|
-
/* @__PURE__ */
|
|
2120
|
-
description && /* @__PURE__ */
|
|
2641
|
+
return /* @__PURE__ */ jsxs15(Card2, { children: [
|
|
2642
|
+
label && /* @__PURE__ */ jsxs15(CardHeader, { className: "pb-3", children: [
|
|
2643
|
+
/* @__PURE__ */ jsx23(CardTitle, { className: "text-base", children: label }),
|
|
2644
|
+
description && /* @__PURE__ */ jsx23("p", { className: "text-sm text-muted-foreground", children: description })
|
|
2121
2645
|
] }),
|
|
2122
|
-
/* @__PURE__ */
|
|
2646
|
+
/* @__PURE__ */ jsx23(CardContent, { children })
|
|
2123
2647
|
] });
|
|
2124
2648
|
}
|
|
2125
2649
|
function SectionVariant({
|
|
@@ -2127,12 +2651,12 @@ function SectionVariant({
|
|
|
2127
2651
|
label,
|
|
2128
2652
|
description
|
|
2129
2653
|
}) {
|
|
2130
|
-
return /* @__PURE__ */
|
|
2131
|
-
label && /* @__PURE__ */
|
|
2132
|
-
/* @__PURE__ */
|
|
2133
|
-
description && /* @__PURE__ */
|
|
2654
|
+
return /* @__PURE__ */ jsxs15("div", { className: "space-y-3", children: [
|
|
2655
|
+
label && /* @__PURE__ */ jsxs15("div", { children: [
|
|
2656
|
+
/* @__PURE__ */ jsx23("h4", { className: "text-sm font-medium", children: label }),
|
|
2657
|
+
description && /* @__PURE__ */ jsx23("p", { className: "text-xs text-muted-foreground", children: description })
|
|
2134
2658
|
] }),
|
|
2135
|
-
/* @__PURE__ */
|
|
2659
|
+
/* @__PURE__ */ jsx23("div", { className: "pl-3 border-l-2 border-muted", children })
|
|
2136
2660
|
] });
|
|
2137
2661
|
}
|
|
2138
2662
|
function DefaultObjectContainerTemplate({
|
|
@@ -2144,10 +2668,10 @@ function DefaultObjectContainerTemplate({
|
|
|
2144
2668
|
}) {
|
|
2145
2669
|
switch (variant) {
|
|
2146
2670
|
case "card":
|
|
2147
|
-
return /* @__PURE__ */
|
|
2671
|
+
return /* @__PURE__ */ jsx23(CardVariant, { label, description, children });
|
|
2148
2672
|
case "collapsible":
|
|
2149
|
-
if (!label) return /* @__PURE__ */
|
|
2150
|
-
return /* @__PURE__ */
|
|
2673
|
+
if (!label) return /* @__PURE__ */ jsx23(SectionVariant, { children });
|
|
2674
|
+
return /* @__PURE__ */ jsx23(
|
|
2151
2675
|
CollapsibleVariant,
|
|
2152
2676
|
{
|
|
2153
2677
|
label,
|
|
@@ -2157,12 +2681,12 @@ function DefaultObjectContainerTemplate({
|
|
|
2157
2681
|
}
|
|
2158
2682
|
);
|
|
2159
2683
|
case "inline":
|
|
2160
|
-
return /* @__PURE__ */
|
|
2684
|
+
return /* @__PURE__ */ jsx23("div", { children });
|
|
2161
2685
|
case "borderless":
|
|
2162
|
-
return /* @__PURE__ */
|
|
2686
|
+
return /* @__PURE__ */ jsx23("div", { className: "space-y-4", children });
|
|
2163
2687
|
case "section":
|
|
2164
2688
|
default:
|
|
2165
|
-
return /* @__PURE__ */
|
|
2689
|
+
return /* @__PURE__ */ jsx23(SectionVariant, { label, description, children });
|
|
2166
2690
|
}
|
|
2167
2691
|
}
|
|
2168
2692
|
function CollapsibleVariant({
|
|
@@ -2171,26 +2695,26 @@ function CollapsibleVariant({
|
|
|
2171
2695
|
defaultOpen,
|
|
2172
2696
|
children
|
|
2173
2697
|
}) {
|
|
2174
|
-
const [open, setOpen] =
|
|
2175
|
-
return /* @__PURE__ */
|
|
2176
|
-
/* @__PURE__ */
|
|
2698
|
+
const [open, setOpen] = useState7(defaultOpen);
|
|
2699
|
+
return /* @__PURE__ */ jsxs15(Collapsible2, { open, onOpenChange: setOpen, children: [
|
|
2700
|
+
/* @__PURE__ */ jsx23(CollapsibleTrigger, { asChild: true, children: /* @__PURE__ */ jsxs15(
|
|
2177
2701
|
"button",
|
|
2178
2702
|
{
|
|
2179
2703
|
type: "button",
|
|
2180
2704
|
className: "flex w-full items-center gap-2 text-sm font-medium hover:text-foreground/80",
|
|
2181
2705
|
children: [
|
|
2182
|
-
open ? /* @__PURE__ */
|
|
2706
|
+
open ? /* @__PURE__ */ jsx23(ChevronDown2, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx23(ChevronRight2, { className: "h-4 w-4" }),
|
|
2183
2707
|
label
|
|
2184
2708
|
]
|
|
2185
2709
|
}
|
|
2186
2710
|
) }),
|
|
2187
|
-
description && /* @__PURE__ */
|
|
2188
|
-
/* @__PURE__ */
|
|
2711
|
+
description && /* @__PURE__ */ jsx23("p", { className: "text-xs text-muted-foreground ml-6", children: description }),
|
|
2712
|
+
/* @__PURE__ */ jsx23(CollapsibleContent2, { className: "mt-2 pl-3 border-l-2 border-muted", children })
|
|
2189
2713
|
] });
|
|
2190
2714
|
}
|
|
2191
2715
|
|
|
2192
2716
|
// src/widgets/ObjectWidget.tsx
|
|
2193
|
-
import { Fragment as Fragment3, jsx as
|
|
2717
|
+
import { Fragment as Fragment3, jsx as jsx24 } from "react/jsx-runtime";
|
|
2194
2718
|
function buildSubSchema(prop) {
|
|
2195
2719
|
const properties = prop.properties;
|
|
2196
2720
|
if (!properties) return null;
|
|
@@ -2256,7 +2780,7 @@ function ObjectWidget({
|
|
|
2256
2780
|
globalOptions,
|
|
2257
2781
|
layout
|
|
2258
2782
|
);
|
|
2259
|
-
const content = /* @__PURE__ */
|
|
2783
|
+
const content = /* @__PURE__ */ jsx24(
|
|
2260
2784
|
Renderer,
|
|
2261
2785
|
{
|
|
2262
2786
|
schema: subSchema,
|
|
@@ -2271,8 +2795,8 @@ function ObjectWidget({
|
|
|
2271
2795
|
onBlur: onBlur ? () => onBlur(id, value) : void 0
|
|
2272
2796
|
}
|
|
2273
2797
|
);
|
|
2274
|
-
if (displayContents) return /* @__PURE__ */
|
|
2275
|
-
return /* @__PURE__ */
|
|
2798
|
+
if (displayContents) return /* @__PURE__ */ jsx24(Fragment3, { children: content });
|
|
2799
|
+
return /* @__PURE__ */ jsx24(
|
|
2276
2800
|
ContainerTemplate,
|
|
2277
2801
|
{
|
|
2278
2802
|
label,
|
|
@@ -2286,15 +2810,15 @@ function ObjectWidget({
|
|
|
2286
2810
|
|
|
2287
2811
|
// src/widgets/ArrayWidget.tsx
|
|
2288
2812
|
import { useCallback as useCallback5, useMemo as useMemo5 } from "react";
|
|
2289
|
-
import { Plus as
|
|
2290
|
-
import { Button as
|
|
2813
|
+
import { Plus as Plus3 } from "lucide-react";
|
|
2814
|
+
import { Button as Button6 } from "@petrarca/sonnet-ui";
|
|
2291
2815
|
import { applySchemaDefaults } from "@petrarca/sonnet-core/schema";
|
|
2292
2816
|
import { FORM_ITEM_ID_FIELD, generateId } from "@petrarca/sonnet-core";
|
|
2293
2817
|
|
|
2294
2818
|
// src/templates/DefaultArrayItemTemplate.tsx
|
|
2295
2819
|
import { Trash2, ChevronUp, ChevronDown as ChevronDown3 } from "lucide-react";
|
|
2296
|
-
import { Button as
|
|
2297
|
-
import { jsx as
|
|
2820
|
+
import { Button as Button5 } from "@petrarca/sonnet-ui";
|
|
2821
|
+
import { jsx as jsx25, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
2298
2822
|
function DefaultArrayItemTemplate({
|
|
2299
2823
|
children,
|
|
2300
2824
|
index,
|
|
@@ -2308,16 +2832,16 @@ function DefaultArrayItemTemplate({
|
|
|
2308
2832
|
onMoveDown
|
|
2309
2833
|
}) {
|
|
2310
2834
|
const showControls = canRemove || orderable;
|
|
2311
|
-
return /* @__PURE__ */
|
|
2835
|
+
return /* @__PURE__ */ jsxs16(
|
|
2312
2836
|
"div",
|
|
2313
2837
|
{
|
|
2314
2838
|
"data-fid": fid,
|
|
2315
2839
|
className: "relative flex gap-2 rounded-md border border-border/50 bg-muted/20 p-3",
|
|
2316
2840
|
children: [
|
|
2317
|
-
/* @__PURE__ */
|
|
2318
|
-
showControls && /* @__PURE__ */
|
|
2319
|
-
orderable && index > 0 && /* @__PURE__ */
|
|
2320
|
-
|
|
2841
|
+
/* @__PURE__ */ jsx25("div", { className: "flex-1 min-w-0", children }),
|
|
2842
|
+
showControls && /* @__PURE__ */ jsxs16("div", { className: "flex flex-col gap-1 pt-0.5", children: [
|
|
2843
|
+
orderable && index > 0 && /* @__PURE__ */ jsx25(
|
|
2844
|
+
Button5,
|
|
2321
2845
|
{
|
|
2322
2846
|
type: "button",
|
|
2323
2847
|
variant: "ghost",
|
|
@@ -2325,11 +2849,11 @@ function DefaultArrayItemTemplate({
|
|
|
2325
2849
|
disabled,
|
|
2326
2850
|
onClick: onMoveUp,
|
|
2327
2851
|
title: "Move up",
|
|
2328
|
-
children: /* @__PURE__ */
|
|
2852
|
+
children: /* @__PURE__ */ jsx25(ChevronUp, { className: "h-3.5 w-3.5" })
|
|
2329
2853
|
}
|
|
2330
2854
|
),
|
|
2331
|
-
orderable && index < total - 1 && /* @__PURE__ */
|
|
2332
|
-
|
|
2855
|
+
orderable && index < total - 1 && /* @__PURE__ */ jsx25(
|
|
2856
|
+
Button5,
|
|
2333
2857
|
{
|
|
2334
2858
|
type: "button",
|
|
2335
2859
|
variant: "ghost",
|
|
@@ -2337,11 +2861,11 @@ function DefaultArrayItemTemplate({
|
|
|
2337
2861
|
disabled,
|
|
2338
2862
|
onClick: onMoveDown,
|
|
2339
2863
|
title: "Move down",
|
|
2340
|
-
children: /* @__PURE__ */
|
|
2864
|
+
children: /* @__PURE__ */ jsx25(ChevronDown3, { className: "h-3.5 w-3.5" })
|
|
2341
2865
|
}
|
|
2342
2866
|
),
|
|
2343
|
-
canRemove && /* @__PURE__ */
|
|
2344
|
-
|
|
2867
|
+
canRemove && /* @__PURE__ */ jsx25(
|
|
2868
|
+
Button5,
|
|
2345
2869
|
{
|
|
2346
2870
|
type: "button",
|
|
2347
2871
|
variant: "ghost",
|
|
@@ -2350,7 +2874,7 @@ function DefaultArrayItemTemplate({
|
|
|
2350
2874
|
onClick: onRemove,
|
|
2351
2875
|
title: "Remove item",
|
|
2352
2876
|
className: "text-muted-foreground hover:text-destructive",
|
|
2353
|
-
children: /* @__PURE__ */
|
|
2877
|
+
children: /* @__PURE__ */ jsx25(Trash2, { className: "h-3.5 w-3.5" })
|
|
2354
2878
|
}
|
|
2355
2879
|
)
|
|
2356
2880
|
] })
|
|
@@ -2367,7 +2891,7 @@ function buildGridTemplate(layout, canRemove, fieldCount, orderable = false) {
|
|
|
2367
2891
|
}
|
|
2368
2892
|
|
|
2369
2893
|
// src/templates/DefaultArrayHeaderTemplate.tsx
|
|
2370
|
-
import { jsx as
|
|
2894
|
+
import { jsx as jsx26, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
2371
2895
|
function DefaultArrayHeaderTemplate({
|
|
2372
2896
|
itemSchema,
|
|
2373
2897
|
layout,
|
|
@@ -2381,7 +2905,7 @@ function DefaultArrayHeaderTemplate({
|
|
|
2381
2905
|
const properties = itemSchema.properties ?? {};
|
|
2382
2906
|
const order = itemSchema["x-ui-order"];
|
|
2383
2907
|
const fieldNames = order ? order.filter((k) => k in properties) : Object.keys(properties);
|
|
2384
|
-
return /* @__PURE__ */
|
|
2908
|
+
return /* @__PURE__ */ jsxs17(
|
|
2385
2909
|
"div",
|
|
2386
2910
|
{
|
|
2387
2911
|
style: {
|
|
@@ -2390,16 +2914,16 @@ function DefaultArrayHeaderTemplate({
|
|
|
2390
2914
|
gap: `${gap}px`
|
|
2391
2915
|
},
|
|
2392
2916
|
children: [
|
|
2393
|
-
fieldNames.map((name) => /* @__PURE__ */
|
|
2394
|
-
orderable && /* @__PURE__ */
|
|
2395
|
-
canRemove && /* @__PURE__ */
|
|
2917
|
+
fieldNames.map((name) => /* @__PURE__ */ jsx26("span", { className: "text-xs font-medium text-muted-foreground", children: properties[name]?.title ?? name }, name)),
|
|
2918
|
+
orderable && /* @__PURE__ */ jsx26("span", {}),
|
|
2919
|
+
canRemove && /* @__PURE__ */ jsx26("span", {})
|
|
2396
2920
|
]
|
|
2397
2921
|
}
|
|
2398
2922
|
);
|
|
2399
2923
|
}
|
|
2400
2924
|
|
|
2401
2925
|
// src/widgets/ArrayWidget.tsx
|
|
2402
|
-
import { jsx as
|
|
2926
|
+
import { jsx as jsx27, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
2403
2927
|
function countFields(itemSchema) {
|
|
2404
2928
|
return Object.keys(itemSchema.properties ?? {}).length;
|
|
2405
2929
|
}
|
|
@@ -2438,9 +2962,9 @@ function buildSubGlobalOptions(layout, isHorizontal) {
|
|
|
2438
2962
|
}
|
|
2439
2963
|
function ArrayHeader({ label, description }) {
|
|
2440
2964
|
if (!label) return null;
|
|
2441
|
-
return /* @__PURE__ */
|
|
2442
|
-
/* @__PURE__ */
|
|
2443
|
-
description && /* @__PURE__ */
|
|
2965
|
+
return /* @__PURE__ */ jsxs18("div", { children: [
|
|
2966
|
+
/* @__PURE__ */ jsx27("h4", { className: "text-sm font-medium", children: label }),
|
|
2967
|
+
description && /* @__PURE__ */ jsx27("p", { className: "text-xs text-muted-foreground", children: description })
|
|
2444
2968
|
] });
|
|
2445
2969
|
}
|
|
2446
2970
|
function useArrayHandlers(items, onChange, propertySchema) {
|
|
@@ -2488,19 +3012,20 @@ function ArrayWidget({
|
|
|
2488
3012
|
description,
|
|
2489
3013
|
options,
|
|
2490
3014
|
schema,
|
|
2491
|
-
name
|
|
3015
|
+
name,
|
|
3016
|
+
onBlur
|
|
2492
3017
|
}) {
|
|
2493
3018
|
const { templates } = useNestedFormContext();
|
|
2494
3019
|
const items = useMemo5(() => ensureItemIds(value), [value]);
|
|
2495
3020
|
const { handleItemChange, handleAdd, handleRemove, handleMove } = useArrayHandlers(items, onChange, propertySchema);
|
|
2496
3021
|
const itemSchema = propertySchema.items;
|
|
2497
3022
|
if (!itemSchema?.properties) {
|
|
2498
|
-
return /* @__PURE__ */
|
|
3023
|
+
return /* @__PURE__ */ jsx27("p", { className: "text-sm text-destructive", children: 'ArrayWidget requires items with type "object" and properties.' });
|
|
2499
3024
|
}
|
|
2500
3025
|
const layout = resolveLayout2(uiSchema, propertySchema);
|
|
2501
3026
|
const isHorizontal = layout.direction === "horizontal";
|
|
2502
3027
|
const subGlobalOptions = buildSubGlobalOptions(layout, isHorizontal);
|
|
2503
|
-
return /* @__PURE__ */
|
|
3028
|
+
return /* @__PURE__ */ jsx27(
|
|
2504
3029
|
ArrayWidgetInner,
|
|
2505
3030
|
{
|
|
2506
3031
|
items,
|
|
@@ -2522,7 +3047,8 @@ function ArrayWidget({
|
|
|
2522
3047
|
onItemChange: handleItemChange,
|
|
2523
3048
|
onAdd: handleAdd,
|
|
2524
3049
|
onRemove: handleRemove,
|
|
2525
|
-
onMove: handleMove
|
|
3050
|
+
onMove: handleMove,
|
|
3051
|
+
onBlur
|
|
2526
3052
|
}
|
|
2527
3053
|
);
|
|
2528
3054
|
}
|
|
@@ -2582,7 +3108,8 @@ function ArrayWidgetInner({
|
|
|
2582
3108
|
onItemChange,
|
|
2583
3109
|
onAdd,
|
|
2584
3110
|
onRemove,
|
|
2585
|
-
onMove
|
|
3111
|
+
onMove,
|
|
3112
|
+
onBlur
|
|
2586
3113
|
}) {
|
|
2587
3114
|
const constraints = resolveConstraints(
|
|
2588
3115
|
propertySchema,
|
|
@@ -2599,10 +3126,10 @@ function ArrayWidgetInner({
|
|
|
2599
3126
|
);
|
|
2600
3127
|
const fieldCount = countFields(itemSchema);
|
|
2601
3128
|
const itemOptions = buildItemOptions(isHorizontal, subGlobalOptions);
|
|
2602
|
-
return /* @__PURE__ */
|
|
2603
|
-
/* @__PURE__ */
|
|
2604
|
-
items.length === 0 && display.emptyMessage && /* @__PURE__ */
|
|
2605
|
-
items.length > 0 && /* @__PURE__ */
|
|
3129
|
+
return /* @__PURE__ */ jsxs18("div", { className: isHorizontal ? "space-y-1" : "space-y-3", children: [
|
|
3130
|
+
/* @__PURE__ */ jsx27(ArrayHeader, { label, description }),
|
|
3131
|
+
items.length === 0 && display.emptyMessage && /* @__PURE__ */ jsx27("p", { className: "text-sm text-muted-foreground italic", children: display.emptyMessage }),
|
|
3132
|
+
items.length > 0 && /* @__PURE__ */ jsx27(
|
|
2606
3133
|
HeaderTemplate,
|
|
2607
3134
|
{
|
|
2608
3135
|
itemSchema,
|
|
@@ -2612,7 +3139,7 @@ function ArrayWidgetInner({
|
|
|
2612
3139
|
fieldCount
|
|
2613
3140
|
}
|
|
2614
3141
|
),
|
|
2615
|
-
items.map((item, index) => /* @__PURE__ */
|
|
3142
|
+
items.map((item, index) => /* @__PURE__ */ jsx27(
|
|
2616
3143
|
ActiveItemTemplate,
|
|
2617
3144
|
{
|
|
2618
3145
|
index,
|
|
@@ -2626,7 +3153,7 @@ function ArrayWidgetInner({
|
|
|
2626
3153
|
onRemove: () => onRemove(index),
|
|
2627
3154
|
onMoveUp: index > 0 ? () => onMove(index, index - 1) : void 0,
|
|
2628
3155
|
onMoveDown: index < items.length - 1 ? () => onMove(index, index + 1) : void 0,
|
|
2629
|
-
children: /* @__PURE__ */
|
|
3156
|
+
children: /* @__PURE__ */ jsx27(
|
|
2630
3157
|
ObjectWidget,
|
|
2631
3158
|
{
|
|
2632
3159
|
id: `field-${name}-${index}`,
|
|
@@ -2641,14 +3168,15 @@ function ArrayWidgetInner({
|
|
|
2641
3168
|
description: void 0,
|
|
2642
3169
|
disabled,
|
|
2643
3170
|
readonly,
|
|
2644
|
-
options: itemOptions
|
|
3171
|
+
options: itemOptions,
|
|
3172
|
+
onBlur
|
|
2645
3173
|
}
|
|
2646
3174
|
)
|
|
2647
3175
|
},
|
|
2648
3176
|
item[FORM_ITEM_ID_FIELD]
|
|
2649
3177
|
)),
|
|
2650
|
-
canAdd && /* @__PURE__ */
|
|
2651
|
-
|
|
3178
|
+
canAdd && /* @__PURE__ */ jsxs18(
|
|
3179
|
+
Button6,
|
|
2652
3180
|
{
|
|
2653
3181
|
type: "button",
|
|
2654
3182
|
variant: "outline",
|
|
@@ -2657,87 +3185,1221 @@ function ArrayWidgetInner({
|
|
|
2657
3185
|
disabled,
|
|
2658
3186
|
className: "gap-1.5",
|
|
2659
3187
|
children: [
|
|
2660
|
-
/* @__PURE__ */
|
|
3188
|
+
/* @__PURE__ */ jsx27(Plus3, { className: "h-3.5 w-3.5" }),
|
|
2661
3189
|
display.addLabel
|
|
2662
3190
|
]
|
|
2663
3191
|
}
|
|
2664
3192
|
)
|
|
2665
3193
|
] });
|
|
2666
3194
|
}
|
|
2667
|
-
|
|
2668
|
-
// src/widgets/QuantityWidget.tsx
|
|
2669
|
-
import { useCallback as useCallback6, useRef as useRef4 } from "react";
|
|
2670
|
-
import {
|
|
2671
|
-
|
|
2672
|
-
|
|
3195
|
+
|
|
3196
|
+
// src/widgets/QuantityWidget.tsx
|
|
3197
|
+
import { useCallback as useCallback6, useRef as useRef4, useState as useState8 } from "react";
|
|
3198
|
+
import { unitRangesOf } from "@petrarca/sonnet-core/schema";
|
|
3199
|
+
import { jsx as jsx28 } from "react/jsx-runtime";
|
|
3200
|
+
function isUnitOption(u) {
|
|
3201
|
+
return typeof u === "object" && u !== null && typeof u.value === "string" && typeof u.label === "string";
|
|
3202
|
+
}
|
|
3203
|
+
function schemaUnits(propertySchema) {
|
|
3204
|
+
const codes = propertySchema.properties?.unit?.enum;
|
|
3205
|
+
return Array.isArray(codes) ? codes.map((c) => ({ value: String(c), label: String(c) })) : [];
|
|
3206
|
+
}
|
|
3207
|
+
function withSchemaRanges(units, propertySchema) {
|
|
3208
|
+
const ranges = unitRangesOf(propertySchema) ?? {};
|
|
3209
|
+
return units.map((u) => {
|
|
3210
|
+
const range = ranges[u.value];
|
|
3211
|
+
return range ? { ...u, min: range.min, max: range.max } : u;
|
|
3212
|
+
});
|
|
3213
|
+
}
|
|
3214
|
+
function parseQuantityOptions(options, fallbackUnits) {
|
|
3215
|
+
const units = Array.isArray(options.units) ? options.units.filter(isUnitOption) : fallbackUnits;
|
|
3216
|
+
const precision = typeof options.precision === "number" ? options.precision : void 0;
|
|
3217
|
+
const step = typeof options.step === "number" ? options.step : void 0;
|
|
3218
|
+
const unitPosition = options.unitPosition === "prefix" || options.unitPosition === "suffix" ? options.unitPosition : void 0;
|
|
3219
|
+
return { units, precision, step, unitPosition };
|
|
3220
|
+
}
|
|
3221
|
+
function QuantityWidget({
|
|
3222
|
+
id,
|
|
3223
|
+
name,
|
|
3224
|
+
value,
|
|
3225
|
+
onChange,
|
|
3226
|
+
onBlur,
|
|
3227
|
+
propertySchema,
|
|
3228
|
+
required,
|
|
3229
|
+
disabled,
|
|
3230
|
+
readonly,
|
|
3231
|
+
rawErrors,
|
|
3232
|
+
label,
|
|
3233
|
+
description,
|
|
3234
|
+
placeholder,
|
|
3235
|
+
autofocus,
|
|
3236
|
+
options = {}
|
|
3237
|
+
}) {
|
|
3238
|
+
const error = firstError(rawErrors);
|
|
3239
|
+
const {
|
|
3240
|
+
units: optionUnits,
|
|
3241
|
+
precision,
|
|
3242
|
+
step,
|
|
3243
|
+
unitPosition: unitPositionOpt
|
|
3244
|
+
} = parseQuantityOptions(options, schemaUnits(propertySchema));
|
|
3245
|
+
const units = withSchemaRanges(optionUnits, propertySchema);
|
|
3246
|
+
const [pendingUnit, setPendingUnit] = useState8();
|
|
3247
|
+
const stored = value != null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
3248
|
+
const quantityValue = stored ?? (pendingUnit ? { value: void 0, unit: pendingUnit } : void 0);
|
|
3249
|
+
const handleChange = useCallback6(
|
|
3250
|
+
(next) => {
|
|
3251
|
+
if (next.value !== void 0) return onChange(next);
|
|
3252
|
+
setPendingUnit(next.unit);
|
|
3253
|
+
onChange(void 0);
|
|
3254
|
+
},
|
|
3255
|
+
[onChange]
|
|
3256
|
+
);
|
|
3257
|
+
const valueRef = useRef4(value);
|
|
3258
|
+
valueRef.current = value;
|
|
3259
|
+
const handleBlur = useCallback6(() => {
|
|
3260
|
+
onBlur?.(id, valueRef.current);
|
|
3261
|
+
}, [id, onBlur]);
|
|
3262
|
+
return /* @__PURE__ */ jsx28(
|
|
3263
|
+
FormQuantityInput,
|
|
3264
|
+
{
|
|
3265
|
+
id,
|
|
3266
|
+
name,
|
|
3267
|
+
value: quantityValue,
|
|
3268
|
+
onChange: handleChange,
|
|
3269
|
+
onBlur: handleBlur,
|
|
3270
|
+
units,
|
|
3271
|
+
freeUnit: propertySchema.properties?.unit !== void 0,
|
|
3272
|
+
unitPosition: unitPositionOpt,
|
|
3273
|
+
precision,
|
|
3274
|
+
step,
|
|
3275
|
+
min: propertySchema.minimum,
|
|
3276
|
+
max: propertySchema.maximum,
|
|
3277
|
+
label,
|
|
3278
|
+
labelPlacement: options?.labelPlacement,
|
|
3279
|
+
description,
|
|
3280
|
+
error,
|
|
3281
|
+
placeholder,
|
|
3282
|
+
required,
|
|
3283
|
+
disabled,
|
|
3284
|
+
readOnly: readonly,
|
|
3285
|
+
autoFocus: autofocus
|
|
3286
|
+
}
|
|
3287
|
+
);
|
|
3288
|
+
}
|
|
3289
|
+
|
|
3290
|
+
// src/widgets/CodedValueWidget.tsx
|
|
3291
|
+
import * as React13 from "react";
|
|
3292
|
+
import { ChevronsUpDown as ChevronsUpDown4, Loader2, TriangleAlert, X as X5 } from "lucide-react";
|
|
3293
|
+
import { cn as cn12, EMPTY_VALUE } from "@petrarca/sonnet-core";
|
|
3294
|
+
import {
|
|
3295
|
+
bindingOf,
|
|
3296
|
+
codingKey as codingKey5
|
|
3297
|
+
} from "@petrarca/sonnet-core/schema";
|
|
3298
|
+
import {
|
|
3299
|
+
useTerminology
|
|
3300
|
+
} from "@petrarca/sonnet-core/terminology";
|
|
3301
|
+
import {
|
|
3302
|
+
Badge as Badge4,
|
|
3303
|
+
Button as Button7,
|
|
3304
|
+
CodedValueDisplay as CodedValueDisplay2,
|
|
3305
|
+
Popover as Popover3,
|
|
3306
|
+
PopoverContent as PopoverContent3,
|
|
3307
|
+
PopoverTrigger as PopoverTrigger3
|
|
3308
|
+
} from "@petrarca/sonnet-ui";
|
|
3309
|
+
|
|
3310
|
+
// src/widgets/codedValue/codedValueModel.ts
|
|
3311
|
+
import {
|
|
3312
|
+
codingKey
|
|
3313
|
+
} from "@petrarca/sonnet-core/schema";
|
|
3314
|
+
var CODING_KEYS = ["system", "code", "version", "display"];
|
|
3315
|
+
function shapeOf(prop) {
|
|
3316
|
+
if (prop?.type === "string") return "code";
|
|
3317
|
+
return prop?.anyOf?.some((m) => m.type === "string") ? "codingOrText" : "coding";
|
|
3318
|
+
}
|
|
3319
|
+
function fieldModelOf(prop, options) {
|
|
3320
|
+
const multiple = prop.type === "array";
|
|
3321
|
+
const keep = Array.isArray(options?.keep) ? options.keep.filter(
|
|
3322
|
+
(k) => typeof k === "string"
|
|
3323
|
+
) : [];
|
|
3324
|
+
return {
|
|
3325
|
+
multiple,
|
|
3326
|
+
shape: shapeOf(multiple ? prop.items : prop),
|
|
3327
|
+
store: typeof options?.store === "string" ? options.store : "code",
|
|
3328
|
+
keep: keep.filter((k) => !CODING_KEYS.includes(k))
|
|
3329
|
+
};
|
|
3330
|
+
}
|
|
3331
|
+
function takesText(field, binding) {
|
|
3332
|
+
if (field.shape === "codingOrText") return true;
|
|
3333
|
+
return field.shape === "code" && binding?.strength === "extensible";
|
|
3334
|
+
}
|
|
3335
|
+
function asCoding(value) {
|
|
3336
|
+
if (typeof value !== "object" || value === null) return void 0;
|
|
3337
|
+
const c = value;
|
|
3338
|
+
return typeof c.code === "string" && c.code ? { ...c, system: c.system ?? "", code: c.code } : void 0;
|
|
3339
|
+
}
|
|
3340
|
+
function entryOf(value, field, binding) {
|
|
3341
|
+
if (typeof value !== "string") {
|
|
3342
|
+
const coding = asCoding(value);
|
|
3343
|
+
return coding && { coding };
|
|
3344
|
+
}
|
|
3345
|
+
if (!value) return void 0;
|
|
3346
|
+
if (field.shape === "codingOrText") return { text: value };
|
|
3347
|
+
return {
|
|
3348
|
+
coding: {
|
|
3349
|
+
system: binding?.system ?? "",
|
|
3350
|
+
code: value,
|
|
3351
|
+
...binding?.version && { version: binding.version }
|
|
3352
|
+
}
|
|
3353
|
+
};
|
|
3354
|
+
}
|
|
3355
|
+
function entriesOf(value, field, binding) {
|
|
3356
|
+
const values = field.multiple ? Array.isArray(value) ? value : [] : [value];
|
|
3357
|
+
return values.map((v) => entryOf(v, field, binding)).filter((e) => e !== void 0);
|
|
3358
|
+
}
|
|
3359
|
+
function entryKey(e) {
|
|
3360
|
+
return e.coding ? codingKey(e.coding) : `text:${e.text ?? ""}`;
|
|
3361
|
+
}
|
|
3362
|
+
function toStored(hit, field, binding) {
|
|
3363
|
+
if (field.shape === "code") return String(hit[field.store] ?? hit.code);
|
|
3364
|
+
const version = hit.version ?? binding?.version;
|
|
3365
|
+
const kept = field.keep.filter((k) => hit[k] != null);
|
|
3366
|
+
return {
|
|
3367
|
+
system: hit.system,
|
|
3368
|
+
code: hit.code,
|
|
3369
|
+
...version && { version },
|
|
3370
|
+
...hit.display && { display: hit.display },
|
|
3371
|
+
...Object.fromEntries(kept.map((k) => [k, hit[k]]))
|
|
3372
|
+
};
|
|
3373
|
+
}
|
|
3374
|
+
function storedKey(v, field, binding) {
|
|
3375
|
+
const entry = entryOf(v, field, binding);
|
|
3376
|
+
return entry ? entryKey(entry) : void 0;
|
|
3377
|
+
}
|
|
3378
|
+
function withAnswer(value, answer, field, binding) {
|
|
3379
|
+
if (!field.multiple) return answer;
|
|
3380
|
+
const current = Array.isArray(value) ? value : [];
|
|
3381
|
+
const key = storedKey(answer, field, binding);
|
|
3382
|
+
const others = current.filter((v) => storedKey(v, field, binding) !== key);
|
|
3383
|
+
if (others.length < current.length) return others.length ? others : void 0;
|
|
3384
|
+
return [...current, answer];
|
|
3385
|
+
}
|
|
3386
|
+
function withoutAnswer(value, key, field, binding) {
|
|
3387
|
+
if (!field.multiple) return void 0;
|
|
3388
|
+
const current = Array.isArray(value) ? value : [];
|
|
3389
|
+
const others = current.filter((v) => storedKey(v, field, binding) !== key);
|
|
3390
|
+
return others.length ? others : void 0;
|
|
3391
|
+
}
|
|
3392
|
+
|
|
3393
|
+
// src/widgets/codedValue/useCodedValueOptions.ts
|
|
3394
|
+
import { useCallback as useCallback7, useEffect as useEffect4, useRef as useRef5, useState as useState9 } from "react";
|
|
3395
|
+
var PAGE_SIZE = 50;
|
|
3396
|
+
var DEBOUNCE_MS = 250;
|
|
3397
|
+
function useDebounced(text) {
|
|
3398
|
+
const [settled, setSettled] = useState9(text);
|
|
3399
|
+
useEffect4(() => {
|
|
3400
|
+
const t = setTimeout(() => setSettled(text), DEBOUNCE_MS);
|
|
3401
|
+
return () => clearTimeout(t);
|
|
3402
|
+
}, [text]);
|
|
3403
|
+
return settled;
|
|
3404
|
+
}
|
|
3405
|
+
function fitsOnePage(result) {
|
|
3406
|
+
return result.total !== void 0 ? result.total <= PAGE_SIZE : result.codings.length < PAGE_SIZE;
|
|
3407
|
+
}
|
|
3408
|
+
function moreAfter(result) {
|
|
3409
|
+
return result.total !== void 0 ? result.codings.length < result.total : false;
|
|
3410
|
+
}
|
|
3411
|
+
function usePagedSearch(service, list) {
|
|
3412
|
+
const [page, setPage] = useState9();
|
|
3413
|
+
const [loading, setLoading] = useState9(false);
|
|
3414
|
+
const [error, setError] = useState9();
|
|
3415
|
+
const request = useRef5(0);
|
|
3416
|
+
const shown = useRef5(null);
|
|
3417
|
+
const run = useCallback7(
|
|
3418
|
+
(text, offset, before) => {
|
|
3419
|
+
if (!service || !list) return Promise.resolve(void 0);
|
|
3420
|
+
const id = ++request.current;
|
|
3421
|
+
setLoading(true);
|
|
3422
|
+
return service.search({ ...list, text, limit: PAGE_SIZE, offset }).then((r) => {
|
|
3423
|
+
if (id !== request.current) return void 0;
|
|
3424
|
+
shown.current = text ?? "";
|
|
3425
|
+
const result = { ...r, codings: [...before, ...r.codings] };
|
|
3426
|
+
setPage({ result, hasMore: moreAfter(result) });
|
|
3427
|
+
setError(void 0);
|
|
3428
|
+
return r;
|
|
3429
|
+
}).catch((e) => {
|
|
3430
|
+
if (id === request.current) setError(String(e));
|
|
3431
|
+
return void 0;
|
|
3432
|
+
}).finally(() => {
|
|
3433
|
+
if (id === request.current) setLoading(false);
|
|
3434
|
+
});
|
|
3435
|
+
},
|
|
3436
|
+
[service, list]
|
|
3437
|
+
);
|
|
3438
|
+
const clear = useCallback7(() => {
|
|
3439
|
+
request.current++;
|
|
3440
|
+
shown.current = null;
|
|
3441
|
+
setPage(void 0);
|
|
3442
|
+
setLoading(false);
|
|
3443
|
+
}, []);
|
|
3444
|
+
const isShown = useCallback7((text) => shown.current === text, []);
|
|
3445
|
+
return { page, loading, error, run, clear, isShown };
|
|
3446
|
+
}
|
|
3447
|
+
function useCodedValueOptions(service, list, forced, minChars = 1) {
|
|
3448
|
+
const [search, setSearch] = useState9("");
|
|
3449
|
+
const [decided, setDecided] = useState9(forced);
|
|
3450
|
+
const text = useDebounced(search.trim());
|
|
3451
|
+
const { page, loading, error, run, clear, isShown } = usePagedSearch(
|
|
3452
|
+
service,
|
|
3453
|
+
list
|
|
3454
|
+
);
|
|
3455
|
+
const mode = forced ?? decided;
|
|
3456
|
+
useEffect4(() => {
|
|
3457
|
+
if (forced) return;
|
|
3458
|
+
void run(void 0, 0, []).then(
|
|
3459
|
+
(r) => r && setDecided(fitsOnePage(r) ? "list" : "search")
|
|
3460
|
+
);
|
|
3461
|
+
}, [forced, run]);
|
|
3462
|
+
useEffect4(() => {
|
|
3463
|
+
if (!mode) return;
|
|
3464
|
+
if (mode === "search" && text.length < Math.max(minChars, 1)) clear();
|
|
3465
|
+
else if (!isShown(text)) void run(text || void 0, 0, []);
|
|
3466
|
+
}, [mode, text, minChars, run, clear, isShown]);
|
|
3467
|
+
const loadMore = useCallback7(() => {
|
|
3468
|
+
const loaded = page?.result.codings ?? [];
|
|
3469
|
+
void run(text || void 0, loaded.length, loaded);
|
|
3470
|
+
}, [page, run, text]);
|
|
3471
|
+
return {
|
|
3472
|
+
hits: page?.result.codings ?? [],
|
|
3473
|
+
total: page?.result.total,
|
|
3474
|
+
hasMore: page?.hasMore ?? false,
|
|
3475
|
+
loading,
|
|
3476
|
+
error,
|
|
3477
|
+
mode,
|
|
3478
|
+
search,
|
|
3479
|
+
setSearch,
|
|
3480
|
+
minChars,
|
|
3481
|
+
loadMore
|
|
3482
|
+
};
|
|
3483
|
+
}
|
|
3484
|
+
|
|
3485
|
+
// src/widgets/codedValue/useStoredLabel.ts
|
|
3486
|
+
import { useEffect as useEffect5, useState as useState10 } from "react";
|
|
3487
|
+
import {
|
|
3488
|
+
codingKey as codingKey2
|
|
3489
|
+
} from "@petrarca/sonnet-core/schema";
|
|
3490
|
+
async function fetchLabel(service, coding, valueSet, version) {
|
|
3491
|
+
if (coding.system) return (await service.lookup(coding))?.display;
|
|
3492
|
+
if (!valueSet) return void 0;
|
|
3493
|
+
const { codings } = await service.search({
|
|
3494
|
+
valueSet,
|
|
3495
|
+
version,
|
|
3496
|
+
text: coding.code
|
|
3497
|
+
});
|
|
3498
|
+
return codings.find((c) => c.code === coding.code)?.display;
|
|
3499
|
+
}
|
|
3500
|
+
function labelQuery(coding, binding) {
|
|
3501
|
+
const system = coding?.system ?? "";
|
|
3502
|
+
const code = coding?.code ?? "";
|
|
3503
|
+
return {
|
|
3504
|
+
own: coding?.display,
|
|
3505
|
+
system,
|
|
3506
|
+
code,
|
|
3507
|
+
version: coding?.version ?? binding?.version,
|
|
3508
|
+
valueSet: binding?.valueSet,
|
|
3509
|
+
key: codingKey2({ system, code })
|
|
3510
|
+
};
|
|
3511
|
+
}
|
|
3512
|
+
function useStoredLabel(service, coding, binding) {
|
|
3513
|
+
const [fetched, setFetched] = useState10();
|
|
3514
|
+
const { own, system, code, version, valueSet, key } = labelQuery(
|
|
3515
|
+
coding,
|
|
3516
|
+
binding
|
|
3517
|
+
);
|
|
3518
|
+
useEffect5(() => {
|
|
3519
|
+
if (!service || !code || own) return;
|
|
3520
|
+
let live = true;
|
|
3521
|
+
fetchLabel(service, { system, code, version }, valueSet, version).then((label) => live && setFetched({ key, label })).catch(() => live && setFetched({ key }));
|
|
3522
|
+
return () => {
|
|
3523
|
+
live = false;
|
|
3524
|
+
};
|
|
3525
|
+
}, [service, system, code, version, valueSet, own, key]);
|
|
3526
|
+
return own ?? (fetched?.key === key ? fetched.label : void 0);
|
|
3527
|
+
}
|
|
3528
|
+
|
|
3529
|
+
// src/widgets/codedValue/useListCheck.ts
|
|
3530
|
+
import { useEffect as useEffect6, useMemo as useMemo6, useState as useState11 } from "react";
|
|
3531
|
+
import {
|
|
3532
|
+
codingKey as codingKey3
|
|
3533
|
+
} from "@petrarca/sonnet-core/schema";
|
|
3534
|
+
var NONE = /* @__PURE__ */ new Map();
|
|
3535
|
+
function checks(binding, storesCodes) {
|
|
3536
|
+
return binding?.strength === "required" && !!(binding.valueSet || binding.system) && storesCodes;
|
|
3537
|
+
}
|
|
3538
|
+
async function warningOf(validate, binding, coding) {
|
|
3539
|
+
try {
|
|
3540
|
+
const result = await validate({
|
|
3541
|
+
valueSet: binding.valueSet,
|
|
3542
|
+
system: binding.system,
|
|
3543
|
+
version: binding.version,
|
|
3544
|
+
code: coding.code
|
|
3545
|
+
});
|
|
3546
|
+
if (result.inList) return void 0;
|
|
3547
|
+
return [
|
|
3548
|
+
codingKey3(coding),
|
|
3549
|
+
result.message ?? `${coding.code} is not in the list.`
|
|
3550
|
+
];
|
|
3551
|
+
} catch {
|
|
3552
|
+
return void 0;
|
|
3553
|
+
}
|
|
3554
|
+
}
|
|
3555
|
+
function useListCheck(service, binding, codings, storesCodes) {
|
|
3556
|
+
const [warnings, setWarnings] = useState11(NONE);
|
|
3557
|
+
const validate = useMemo6(() => service?.validate?.bind(service), [service]);
|
|
3558
|
+
const active = !!validate && checks(binding, storesCodes);
|
|
3559
|
+
const codes = active ? JSON.stringify(codings.map((c) => [c.system, c.code])) : "[]";
|
|
3560
|
+
const valueSet = binding?.valueSet;
|
|
3561
|
+
const system = binding?.system;
|
|
3562
|
+
const version = binding?.version;
|
|
3563
|
+
useEffect6(() => {
|
|
3564
|
+
const stored = JSON.parse(codes).map(
|
|
3565
|
+
([s, code]) => ({ system: s, code })
|
|
3566
|
+
);
|
|
3567
|
+
if (!validate || !active || stored.length === 0) {
|
|
3568
|
+
setWarnings(NONE);
|
|
3569
|
+
return;
|
|
3570
|
+
}
|
|
3571
|
+
const list = { valueSet, system, version, strength: "required" };
|
|
3572
|
+
let live = true;
|
|
3573
|
+
void Promise.all(stored.map((c) => warningOf(validate, list, c))).then(
|
|
3574
|
+
(found) => {
|
|
3575
|
+
if (!live) return;
|
|
3576
|
+
const entries = found.filter((w) => w !== void 0);
|
|
3577
|
+
setWarnings(entries.length ? new Map(entries) : NONE);
|
|
3578
|
+
}
|
|
3579
|
+
);
|
|
3580
|
+
return () => {
|
|
3581
|
+
live = false;
|
|
3582
|
+
};
|
|
3583
|
+
}, [active, validate, codes, valueSet, system, version]);
|
|
3584
|
+
return warnings;
|
|
3585
|
+
}
|
|
3586
|
+
|
|
3587
|
+
// src/widgets/codedValue/HitList.tsx
|
|
3588
|
+
import { Check as Check3 } from "lucide-react";
|
|
3589
|
+
import { cn as cn11 } from "@petrarca/sonnet-core";
|
|
3590
|
+
import { codingKey as codingKey4 } from "@petrarca/sonnet-core/schema";
|
|
3591
|
+
import {
|
|
3592
|
+
CodedValueDisplay,
|
|
3593
|
+
Command as Command3,
|
|
3594
|
+
CommandEmpty as CommandEmpty3,
|
|
3595
|
+
CommandGroup as CommandGroup3,
|
|
3596
|
+
CommandInput as CommandInput3,
|
|
3597
|
+
CommandItem as CommandItem3,
|
|
3598
|
+
CommandList as CommandList3
|
|
3599
|
+
} from "@petrarca/sonnet-ui";
|
|
3600
|
+
import { jsx as jsx29, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
3601
|
+
function emptyMessage(o) {
|
|
3602
|
+
if (o.loading) return "Loading...";
|
|
3603
|
+
if (o.error) return "The list could not be loaded.";
|
|
3604
|
+
const typed = o.search.trim().length;
|
|
3605
|
+
if (o.mode === "search" && typed < o.minChars)
|
|
3606
|
+
return o.minChars > 1 && typed > 0 ? `Type at least ${o.minChars} characters...` : "Type to search...";
|
|
3607
|
+
return "No matches.";
|
|
3608
|
+
}
|
|
3609
|
+
function HitItem({
|
|
3610
|
+
hit,
|
|
3611
|
+
selected,
|
|
3612
|
+
onPick
|
|
3613
|
+
}) {
|
|
3614
|
+
return /* @__PURE__ */ jsxs19(CommandItem3, { value: codingKey4(hit), onSelect: () => onPick(hit), children: [
|
|
3615
|
+
/* @__PURE__ */ jsx29(
|
|
3616
|
+
Check3,
|
|
3617
|
+
{
|
|
3618
|
+
className: cn11(
|
|
3619
|
+
"mr-2 h-4 w-4 shrink-0",
|
|
3620
|
+
selected ? "opacity-100" : "opacity-0"
|
|
3621
|
+
)
|
|
3622
|
+
}
|
|
3623
|
+
),
|
|
3624
|
+
/* @__PURE__ */ jsxs19("div", { className: "min-w-0", children: [
|
|
3625
|
+
/* @__PURE__ */ jsx29(CodedValueDisplay, { code: hit.code, display: hit.display }),
|
|
3626
|
+
hit.path && hit.path.length > 0 && /* @__PURE__ */ jsx29("div", { className: "truncate text-xs text-muted-foreground", children: hit.path.join(" \u203A ") })
|
|
3627
|
+
] })
|
|
3628
|
+
] });
|
|
3629
|
+
}
|
|
3630
|
+
function HitList({
|
|
3631
|
+
options,
|
|
3632
|
+
selected,
|
|
3633
|
+
freeText,
|
|
3634
|
+
onPick,
|
|
3635
|
+
onFreeText
|
|
3636
|
+
}) {
|
|
3637
|
+
return /* @__PURE__ */ jsxs19(Command3, { shouldFilter: false, children: [
|
|
3638
|
+
/* @__PURE__ */ jsx29(
|
|
3639
|
+
CommandInput3,
|
|
3640
|
+
{
|
|
3641
|
+
placeholder: "Search...",
|
|
3642
|
+
value: options.search,
|
|
3643
|
+
onValueChange: options.setSearch
|
|
3644
|
+
}
|
|
3645
|
+
),
|
|
3646
|
+
/* @__PURE__ */ jsxs19(CommandList3, { children: [
|
|
3647
|
+
/* @__PURE__ */ jsx29(CommandEmpty3, { children: emptyMessage(options) }),
|
|
3648
|
+
/* @__PURE__ */ jsxs19(CommandGroup3, { children: [
|
|
3649
|
+
options.hits.map((hit) => /* @__PURE__ */ jsx29(
|
|
3650
|
+
HitItem,
|
|
3651
|
+
{
|
|
3652
|
+
hit,
|
|
3653
|
+
selected: selected.has(codingKey4(hit)),
|
|
3654
|
+
onPick
|
|
3655
|
+
},
|
|
3656
|
+
codingKey4(hit)
|
|
3657
|
+
)),
|
|
3658
|
+
options.hasMore && /* @__PURE__ */ jsx29(CommandItem3, { value: "__more", onSelect: options.loadMore, children: /* @__PURE__ */ jsxs19("span", { className: "text-sm text-muted-foreground", children: [
|
|
3659
|
+
"Show more",
|
|
3660
|
+
options.total !== void 0 && ` (${options.hits.length} of ${options.total})`
|
|
3661
|
+
] }) }),
|
|
3662
|
+
freeText && /* @__PURE__ */ jsx29(CommandItem3, { value: "__text", onSelect: () => onFreeText(freeText), children: /* @__PURE__ */ jsxs19("span", { className: "text-sm", children: [
|
|
3663
|
+
"Use \u201C",
|
|
3664
|
+
freeText,
|
|
3665
|
+
"\u201D"
|
|
3666
|
+
] }) })
|
|
3667
|
+
] })
|
|
3668
|
+
] })
|
|
3669
|
+
] });
|
|
3670
|
+
}
|
|
3671
|
+
|
|
3672
|
+
// src/widgets/codedValue/InlineIconButton.tsx
|
|
3673
|
+
import { jsx as jsx30 } from "react/jsx-runtime";
|
|
3674
|
+
function InlineIconButton({
|
|
3675
|
+
label,
|
|
3676
|
+
onAct,
|
|
3677
|
+
children
|
|
3678
|
+
}) {
|
|
3679
|
+
const act = (e) => {
|
|
3680
|
+
e.preventDefault();
|
|
3681
|
+
e.stopPropagation();
|
|
3682
|
+
onAct();
|
|
3683
|
+
};
|
|
3684
|
+
return /* @__PURE__ */ jsx30(
|
|
3685
|
+
"span",
|
|
3686
|
+
{
|
|
3687
|
+
role: "button",
|
|
3688
|
+
"aria-label": label,
|
|
3689
|
+
tabIndex: -1,
|
|
3690
|
+
className: "rounded-sm opacity-50 hover:opacity-100",
|
|
3691
|
+
onPointerDown: act,
|
|
3692
|
+
children
|
|
3693
|
+
}
|
|
3694
|
+
);
|
|
3695
|
+
}
|
|
3696
|
+
|
|
3697
|
+
// src/widgets/codedValue/listOptions.ts
|
|
3698
|
+
import * as React12 from "react";
|
|
3699
|
+
function modeOption(options) {
|
|
3700
|
+
const mode = options?.mode;
|
|
3701
|
+
return mode === "list" || mode === "search" ? mode : void 0;
|
|
3702
|
+
}
|
|
3703
|
+
function minCharsOption(options) {
|
|
3704
|
+
const n = options?.minChars;
|
|
3705
|
+
return typeof n === "number" && n >= 1 ? n : 1;
|
|
3706
|
+
}
|
|
3707
|
+
function useListRef(binding) {
|
|
3708
|
+
const { valueSet, system, version } = binding ?? {};
|
|
3709
|
+
return React12.useMemo(
|
|
3710
|
+
() => valueSet || system ? { valueSet, system, version } : void 0,
|
|
3711
|
+
[valueSet, system, version]
|
|
3712
|
+
);
|
|
3713
|
+
}
|
|
3714
|
+
|
|
3715
|
+
// src/widgets/CodedValueWidget.tsx
|
|
3716
|
+
import { jsx as jsx31, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
3717
|
+
function freeTextOf(o, open) {
|
|
3718
|
+
const text = o.search.trim();
|
|
3719
|
+
if (!open || !text) return void 0;
|
|
3720
|
+
return o.hits.some((h) => h.code === text) ? void 0 : text;
|
|
3721
|
+
}
|
|
3722
|
+
function EntryText({
|
|
3723
|
+
entry,
|
|
3724
|
+
shown
|
|
3725
|
+
}) {
|
|
3726
|
+
const key = entryKey(entry);
|
|
3727
|
+
const known = shown.picked.has(key);
|
|
3728
|
+
const looked = useStoredLabel(
|
|
3729
|
+
known || !shown.lookup ? null : shown.service,
|
|
3730
|
+
entry.coding,
|
|
3731
|
+
shown.binding
|
|
3732
|
+
);
|
|
3733
|
+
if (!entry.coding)
|
|
3734
|
+
return /* @__PURE__ */ jsx31("span", { className: "truncate text-sm", children: entry.text });
|
|
3735
|
+
return /* @__PURE__ */ jsx31(
|
|
3736
|
+
CodedValueDisplay2,
|
|
3737
|
+
{
|
|
3738
|
+
code: entry.coding.code,
|
|
3739
|
+
display: known ? shown.picked.get(key) : looked,
|
|
3740
|
+
system: entry.coding.system || void 0
|
|
3741
|
+
}
|
|
3742
|
+
);
|
|
3743
|
+
}
|
|
3744
|
+
function Chip({
|
|
3745
|
+
entry,
|
|
3746
|
+
shown,
|
|
3747
|
+
onRemove
|
|
3748
|
+
}) {
|
|
3749
|
+
return /* @__PURE__ */ jsxs20(Badge4, { variant: "secondary", className: "max-w-full gap-1 font-normal", children: [
|
|
3750
|
+
/* @__PURE__ */ jsx31(EntryText, { entry, shown }),
|
|
3751
|
+
onRemove && /* @__PURE__ */ jsx31(
|
|
3752
|
+
InlineIconButton,
|
|
3753
|
+
{
|
|
3754
|
+
label: "Remove",
|
|
3755
|
+
onAct: () => onRemove(entryKey(entry)),
|
|
3756
|
+
children: /* @__PURE__ */ jsx31(X5, { className: "h-3 w-3" })
|
|
3757
|
+
}
|
|
3758
|
+
)
|
|
3759
|
+
] });
|
|
3760
|
+
}
|
|
3761
|
+
function Entries({
|
|
3762
|
+
entries,
|
|
3763
|
+
field,
|
|
3764
|
+
shown,
|
|
3765
|
+
onRemove
|
|
3766
|
+
}) {
|
|
3767
|
+
if (!field.multiple) return /* @__PURE__ */ jsx31(EntryText, { entry: entries[0], shown });
|
|
3768
|
+
return /* @__PURE__ */ jsx31("span", { className: "flex min-w-0 flex-wrap gap-1", children: entries.map((e) => /* @__PURE__ */ jsx31(Chip, { entry: e, shown, onRemove }, entryKey(e))) });
|
|
3769
|
+
}
|
|
3770
|
+
function TriggerIcons3({
|
|
3771
|
+
loading,
|
|
3772
|
+
onClear
|
|
3773
|
+
}) {
|
|
3774
|
+
return /* @__PURE__ */ jsxs20("span", { className: "ml-2 flex shrink-0 items-center gap-1", children: [
|
|
3775
|
+
loading && /* @__PURE__ */ jsx31(Loader2, { className: "h-4 w-4 animate-spin opacity-50" }),
|
|
3776
|
+
onClear && /* @__PURE__ */ jsx31(InlineIconButton, { label: "Clear selection", onAct: onClear, children: /* @__PURE__ */ jsx31(X5, { className: "h-4 w-4" }) }),
|
|
3777
|
+
/* @__PURE__ */ jsx31(ChevronsUpDown4, { className: "h-4 w-4 opacity-50" })
|
|
3778
|
+
] });
|
|
3779
|
+
}
|
|
3780
|
+
function fieldStateOf(props) {
|
|
3781
|
+
const binding = bindingOf(props.propertySchema);
|
|
3782
|
+
const field = fieldModelOf(props.propertySchema, props.options);
|
|
3783
|
+
return {
|
|
3784
|
+
binding,
|
|
3785
|
+
field,
|
|
3786
|
+
entries: entriesOf(props.value, field, binding),
|
|
3787
|
+
storesCodes: field.store === "code"
|
|
3788
|
+
};
|
|
3789
|
+
}
|
|
3790
|
+
function useAnswers(props, state) {
|
|
3791
|
+
const { value, onChange } = props;
|
|
3792
|
+
const { binding, field } = state;
|
|
3793
|
+
const [picked, setPicked] = React13.useState(
|
|
3794
|
+
() => /* @__PURE__ */ new Map()
|
|
3795
|
+
);
|
|
3796
|
+
const pick = (hit) => {
|
|
3797
|
+
setPicked((m) => new Map(m).set(codingKey5(hit), hit.display));
|
|
3798
|
+
onChange(withAnswer(value, toStored(hit, field, binding), field, binding));
|
|
3799
|
+
};
|
|
3800
|
+
const takeText = (typed) => onChange(withAnswer(value, typed, field, binding));
|
|
3801
|
+
const remove = (key) => onChange(withoutAnswer(value, key, field, binding));
|
|
3802
|
+
return { picked, pick, takeText, remove };
|
|
3803
|
+
}
|
|
3804
|
+
function EditableCodedValue({
|
|
3805
|
+
props,
|
|
3806
|
+
state,
|
|
3807
|
+
service
|
|
3808
|
+
}) {
|
|
3809
|
+
const { id, value, onChange, onBlur, required, rawErrors, placeholder } = props;
|
|
3810
|
+
const { binding, field, entries } = state;
|
|
3811
|
+
const [open, setOpen] = React13.useState(false);
|
|
3812
|
+
const list = useListRef(binding);
|
|
3813
|
+
const options = useCodedValueOptions(
|
|
3814
|
+
service,
|
|
3815
|
+
list,
|
|
3816
|
+
modeOption(props.options),
|
|
3817
|
+
minCharsOption(props.options)
|
|
3818
|
+
);
|
|
3819
|
+
const answers = useAnswers(props, state);
|
|
3820
|
+
const shown = {
|
|
3821
|
+
binding,
|
|
3822
|
+
service,
|
|
3823
|
+
picked: answers.picked,
|
|
3824
|
+
lookup: state.storesCodes
|
|
3825
|
+
};
|
|
3826
|
+
const empty = entries.length === 0;
|
|
3827
|
+
const close = (next) => {
|
|
3828
|
+
setOpen(next);
|
|
3829
|
+
if (!next) {
|
|
3830
|
+
options.setSearch("");
|
|
3831
|
+
onBlur?.(id, value);
|
|
3832
|
+
}
|
|
3833
|
+
};
|
|
3834
|
+
const done = () => {
|
|
3835
|
+
if (!field.multiple) close(false);
|
|
3836
|
+
};
|
|
3837
|
+
const clear = () => onChange(void 0);
|
|
3838
|
+
return /* @__PURE__ */ jsxs20(Popover3, { open, onOpenChange: close, children: [
|
|
3839
|
+
/* @__PURE__ */ jsx31(PopoverTrigger3, { asChild: true, children: /* @__PURE__ */ jsxs20(
|
|
3840
|
+
Button7,
|
|
3841
|
+
{
|
|
3842
|
+
id,
|
|
3843
|
+
variant: "outline",
|
|
3844
|
+
role: "combobox",
|
|
3845
|
+
"aria-expanded": open,
|
|
3846
|
+
className: cn12(
|
|
3847
|
+
"h-auto min-h-9 w-full justify-between font-normal",
|
|
3848
|
+
empty && "text-muted-foreground",
|
|
3849
|
+
firstError(rawErrors) && "border-destructive"
|
|
3850
|
+
),
|
|
3851
|
+
children: [
|
|
3852
|
+
empty ? /* @__PURE__ */ jsx31("span", { className: "truncate", children: placeholder || "Select..." }) : /* @__PURE__ */ jsx31(
|
|
3853
|
+
Entries,
|
|
3854
|
+
{
|
|
3855
|
+
entries,
|
|
3856
|
+
field,
|
|
3857
|
+
shown,
|
|
3858
|
+
onRemove: answers.remove
|
|
3859
|
+
}
|
|
3860
|
+
),
|
|
3861
|
+
/* @__PURE__ */ jsx31(
|
|
3862
|
+
TriggerIcons3,
|
|
3863
|
+
{
|
|
3864
|
+
loading: options.loading,
|
|
3865
|
+
onClear: !empty && !required ? clear : void 0
|
|
3866
|
+
}
|
|
3867
|
+
)
|
|
3868
|
+
]
|
|
3869
|
+
}
|
|
3870
|
+
) }),
|
|
3871
|
+
/* @__PURE__ */ jsx31(
|
|
3872
|
+
PopoverContent3,
|
|
3873
|
+
{
|
|
3874
|
+
className: "w-[--radix-popover-trigger-width] p-0",
|
|
3875
|
+
align: "start",
|
|
3876
|
+
children: /* @__PURE__ */ jsx31(
|
|
3877
|
+
HitList,
|
|
3878
|
+
{
|
|
3879
|
+
options,
|
|
3880
|
+
selected: new Set(entries.map(entryKey)),
|
|
3881
|
+
freeText: freeTextOf(options, takesText(field, binding)),
|
|
3882
|
+
onPick: (hit) => {
|
|
3883
|
+
answers.pick(hit);
|
|
3884
|
+
done();
|
|
3885
|
+
},
|
|
3886
|
+
onFreeText: (typed) => {
|
|
3887
|
+
answers.takeText(typed);
|
|
3888
|
+
done();
|
|
3889
|
+
}
|
|
3890
|
+
}
|
|
3891
|
+
)
|
|
3892
|
+
}
|
|
3893
|
+
)
|
|
3894
|
+
] });
|
|
3895
|
+
}
|
|
3896
|
+
function ReadonlyCodedValue({
|
|
3897
|
+
state,
|
|
3898
|
+
service,
|
|
3899
|
+
note
|
|
3900
|
+
}) {
|
|
3901
|
+
const shown = {
|
|
3902
|
+
binding: state.binding,
|
|
3903
|
+
service,
|
|
3904
|
+
picked: /* @__PURE__ */ new Map(),
|
|
3905
|
+
lookup: state.storesCodes
|
|
3906
|
+
};
|
|
3907
|
+
return /* @__PURE__ */ jsxs20("div", { className: "space-y-1", children: [
|
|
3908
|
+
state.entries.length ? /* @__PURE__ */ jsx31(Entries, { entries: state.entries, field: state.field, shown }) : /* @__PURE__ */ jsx31("span", { className: "text-sm text-muted-foreground", children: EMPTY_VALUE }),
|
|
3909
|
+
note && /* @__PURE__ */ jsx31("p", { className: "text-xs text-muted-foreground", children: note })
|
|
3910
|
+
] });
|
|
3911
|
+
}
|
|
3912
|
+
function readonlyNote(state, service) {
|
|
3913
|
+
if (!state.binding) return "No list is bound to this field.";
|
|
3914
|
+
if (!service) return "No terminology service is available.";
|
|
3915
|
+
return void 0;
|
|
3916
|
+
}
|
|
3917
|
+
function ListWarningsText({
|
|
3918
|
+
warnings
|
|
3919
|
+
}) {
|
|
3920
|
+
if (warnings.size === 0) return null;
|
|
3921
|
+
return /* @__PURE__ */ jsx31("div", { className: "space-y-0.5", children: [...warnings].map(([key, message]) => /* @__PURE__ */ jsxs20(
|
|
3922
|
+
"p",
|
|
3923
|
+
{
|
|
3924
|
+
className: "flex items-center gap-1 text-xs text-amber-600 dark:text-amber-400",
|
|
3925
|
+
children: [
|
|
3926
|
+
/* @__PURE__ */ jsx31(TriangleAlert, { className: "h-3 w-3 shrink-0" }),
|
|
3927
|
+
message
|
|
3928
|
+
]
|
|
3929
|
+
},
|
|
3930
|
+
key
|
|
3931
|
+
)) });
|
|
3932
|
+
}
|
|
3933
|
+
function CodedValueBody({
|
|
3934
|
+
props,
|
|
3935
|
+
state,
|
|
3936
|
+
service
|
|
3937
|
+
}) {
|
|
3938
|
+
const note = readonlyNote(state, service);
|
|
3939
|
+
if (props.disabled || props.readonly || note || !service)
|
|
3940
|
+
return /* @__PURE__ */ jsx31(
|
|
3941
|
+
ReadonlyCodedValue,
|
|
3942
|
+
{
|
|
3943
|
+
state,
|
|
3944
|
+
service,
|
|
3945
|
+
note: props.disabled || props.readonly ? void 0 : note
|
|
3946
|
+
}
|
|
3947
|
+
);
|
|
3948
|
+
return /* @__PURE__ */ jsx31(EditableCodedValue, { props, state, service });
|
|
3949
|
+
}
|
|
3950
|
+
function CodedValueField({
|
|
3951
|
+
props
|
|
3952
|
+
}) {
|
|
3953
|
+
const service = useTerminology();
|
|
3954
|
+
const state = fieldStateOf(props);
|
|
3955
|
+
const warnings = useListCheck(
|
|
3956
|
+
service,
|
|
3957
|
+
state.binding,
|
|
3958
|
+
state.entries.flatMap((e) => e.coding ? [e.coding] : []),
|
|
3959
|
+
state.storesCodes
|
|
3960
|
+
);
|
|
3961
|
+
return /* @__PURE__ */ jsxs20("div", { className: "space-y-1", children: [
|
|
3962
|
+
/* @__PURE__ */ jsx31(CodedValueBody, { props, state, service }),
|
|
3963
|
+
/* @__PURE__ */ jsx31(ListWarningsText, { warnings })
|
|
3964
|
+
] });
|
|
3965
|
+
}
|
|
3966
|
+
function CodedValueWidget(props) {
|
|
3967
|
+
return /* @__PURE__ */ jsx31(
|
|
3968
|
+
FormFieldWrapper,
|
|
3969
|
+
{
|
|
3970
|
+
inputId: props.id,
|
|
3971
|
+
label: props.label,
|
|
3972
|
+
description: props.description,
|
|
3973
|
+
required: props.required,
|
|
3974
|
+
error: firstError(props.rawErrors),
|
|
3975
|
+
children: /* @__PURE__ */ jsx31(CodedValueField, { props })
|
|
3976
|
+
}
|
|
3977
|
+
);
|
|
3978
|
+
}
|
|
3979
|
+
|
|
3980
|
+
// src/widgets/CodeableConceptWidget.tsx
|
|
3981
|
+
import * as React14 from "react";
|
|
3982
|
+
import { Plus as Plus4, X as X6 } from "lucide-react";
|
|
3983
|
+
import { cn as cn13 } from "@petrarca/sonnet-core";
|
|
3984
|
+
import {
|
|
3985
|
+
bindingLists,
|
|
3986
|
+
bindingOf as bindingOf2,
|
|
3987
|
+
CODING_TYPE,
|
|
3988
|
+
codingKey as codingKey6,
|
|
3989
|
+
codingsByList as codingsByList2,
|
|
3990
|
+
conceptOf as conceptOf2,
|
|
3991
|
+
listTitle
|
|
3992
|
+
} from "@petrarca/sonnet-core/schema";
|
|
3993
|
+
import {
|
|
3994
|
+
useTerminology as useTerminology2
|
|
3995
|
+
} from "@petrarca/sonnet-core/terminology";
|
|
3996
|
+
import {
|
|
3997
|
+
Badge as Badge5,
|
|
3998
|
+
Button as Button8,
|
|
3999
|
+
DropdownMenu,
|
|
4000
|
+
DropdownMenuContent,
|
|
4001
|
+
DropdownMenuItem,
|
|
4002
|
+
DropdownMenuTrigger,
|
|
4003
|
+
Popover as Popover4,
|
|
4004
|
+
PopoverAnchor,
|
|
4005
|
+
PopoverContent as PopoverContent4
|
|
4006
|
+
} from "@petrarca/sonnet-ui";
|
|
4007
|
+
|
|
4008
|
+
// src/widgets/codeableConcept/conceptModel.ts
|
|
4009
|
+
import {
|
|
4010
|
+
codingsByList,
|
|
4011
|
+
conceptOf
|
|
4012
|
+
} from "@petrarca/sonnet-core/schema";
|
|
4013
|
+
function valueOf(codings, text) {
|
|
4014
|
+
const t = text?.trim() ? text : void 0;
|
|
4015
|
+
if (codings.length === 0 && !t) return void 0;
|
|
4016
|
+
return {
|
|
4017
|
+
...codings.length ? { codings } : {},
|
|
4018
|
+
...t ? { text: t } : {}
|
|
4019
|
+
};
|
|
4020
|
+
}
|
|
4021
|
+
function withRow(value, lists, row, coding) {
|
|
4022
|
+
return withCoding(
|
|
4023
|
+
value,
|
|
4024
|
+
lists,
|
|
4025
|
+
row,
|
|
4026
|
+
coding && { ...coding, userSelected: true }
|
|
4027
|
+
);
|
|
4028
|
+
}
|
|
4029
|
+
function withSuggested(value, lists, row, suggestion) {
|
|
4030
|
+
if (codingsByList(value, lists).byList[row]) return conceptOf(value);
|
|
4031
|
+
const { coding, match } = suggestion;
|
|
4032
|
+
return withCoding(value, lists, row, {
|
|
4033
|
+
...coding,
|
|
4034
|
+
...match ? { match } : {}
|
|
4035
|
+
});
|
|
4036
|
+
}
|
|
4037
|
+
function withCoding(value, lists, row, coding) {
|
|
4038
|
+
const { byList: rows, others } = codingsByList(value, lists);
|
|
4039
|
+
const purpose = lists[row]?.purpose;
|
|
4040
|
+
const next = rows.map(
|
|
4041
|
+
(c, i) => i !== row ? c : coding && { ...coding, ...purpose ? { purpose } : {} }
|
|
4042
|
+
);
|
|
4043
|
+
return valueOf(
|
|
4044
|
+
[...next.filter((c) => !!c), ...others],
|
|
4045
|
+
conceptOf(value).text
|
|
4046
|
+
);
|
|
4047
|
+
}
|
|
4048
|
+
function withText(value, text) {
|
|
4049
|
+
return valueOf(conceptOf(value).codings ?? [], text);
|
|
4050
|
+
}
|
|
4051
|
+
|
|
4052
|
+
// src/widgets/CodeableConceptWidget.tsx
|
|
4053
|
+
import { jsx as jsx32, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
4054
|
+
function listSchema(list) {
|
|
4055
|
+
const { valueSet, system, version } = list;
|
|
4056
|
+
return {
|
|
4057
|
+
...CODING_TYPE.definition,
|
|
4058
|
+
"x-binding": {
|
|
4059
|
+
...valueSet ? { valueSet } : {},
|
|
4060
|
+
...system ? { system } : {},
|
|
4061
|
+
...version ? { version } : {},
|
|
4062
|
+
strength: "required"
|
|
4063
|
+
}
|
|
4064
|
+
};
|
|
4065
|
+
}
|
|
4066
|
+
var AS_CODING = {
|
|
4067
|
+
multiple: false,
|
|
4068
|
+
shape: "coding",
|
|
4069
|
+
store: "code",
|
|
4070
|
+
keep: []
|
|
4071
|
+
};
|
|
4072
|
+
function offersText(props, extensible) {
|
|
4073
|
+
const text = props.options?.text;
|
|
4074
|
+
return typeof text === "boolean" ? text : extensible;
|
|
4075
|
+
}
|
|
4076
|
+
function CodingChip({
|
|
4077
|
+
label,
|
|
4078
|
+
coding,
|
|
4079
|
+
onOpen,
|
|
4080
|
+
onRemove
|
|
4081
|
+
}) {
|
|
4082
|
+
const mapped = coding.match !== void 0 && !coding.userSelected;
|
|
4083
|
+
return /* @__PURE__ */ jsxs21(
|
|
4084
|
+
Badge5,
|
|
4085
|
+
{
|
|
4086
|
+
variant: "secondary",
|
|
4087
|
+
className: cn13("gap-1 font-normal", onOpen && "cursor-pointer"),
|
|
4088
|
+
title: coding.display ?? coding.code,
|
|
4089
|
+
onClick: onOpen,
|
|
4090
|
+
children: [
|
|
4091
|
+
/* @__PURE__ */ jsx32("span", { className: "text-muted-foreground", children: label }),
|
|
4092
|
+
/* @__PURE__ */ jsx32("span", { className: "font-mono text-xs", children: coding.code }),
|
|
4093
|
+
mapped && /* @__PURE__ */ jsx32("span", { className: "text-muted-foreground", children: "\xB7 mapped" }),
|
|
4094
|
+
onRemove && /* @__PURE__ */ jsx32(InlineIconButton, { label: `Remove ${label}`, onAct: onRemove, children: /* @__PURE__ */ jsx32(X6, { className: "h-3 w-3" }) })
|
|
4095
|
+
]
|
|
4096
|
+
}
|
|
4097
|
+
);
|
|
4098
|
+
}
|
|
4099
|
+
function MissingChip({
|
|
4100
|
+
label,
|
|
4101
|
+
onOpen
|
|
4102
|
+
}) {
|
|
4103
|
+
return /* @__PURE__ */ jsxs21(
|
|
4104
|
+
Badge5,
|
|
4105
|
+
{
|
|
4106
|
+
variant: "outline",
|
|
4107
|
+
className: cn13(
|
|
4108
|
+
"gap-1 border-dashed font-normal text-muted-foreground",
|
|
4109
|
+
onOpen && "cursor-pointer"
|
|
4110
|
+
),
|
|
4111
|
+
onClick: onOpen,
|
|
4112
|
+
children: [
|
|
4113
|
+
label,
|
|
4114
|
+
/* @__PURE__ */ jsx32("span", { className: "text-destructive", children: "*" })
|
|
4115
|
+
]
|
|
4116
|
+
}
|
|
4117
|
+
);
|
|
4118
|
+
}
|
|
4119
|
+
function ListSearch({
|
|
4120
|
+
list,
|
|
4121
|
+
props,
|
|
4122
|
+
selected,
|
|
4123
|
+
onPick
|
|
4124
|
+
}) {
|
|
4125
|
+
const service = useTerminology2();
|
|
4126
|
+
const ref = useListRef({ ...list, strength: "required" });
|
|
4127
|
+
const options = useCodedValueOptions(
|
|
4128
|
+
service,
|
|
4129
|
+
ref,
|
|
4130
|
+
modeOption(props.options),
|
|
4131
|
+
minCharsOption(props.options)
|
|
4132
|
+
);
|
|
4133
|
+
return /* @__PURE__ */ jsxs21("div", { className: "space-y-1", children: [
|
|
4134
|
+
/* @__PURE__ */ jsx32("p", { className: "px-2 pt-2 text-xs font-medium text-muted-foreground", children: listTitle(list) }),
|
|
4135
|
+
/* @__PURE__ */ jsx32(
|
|
4136
|
+
HitList,
|
|
4137
|
+
{
|
|
4138
|
+
options,
|
|
4139
|
+
selected: new Set(selected ? [codingKey6(selected)] : []),
|
|
4140
|
+
onPick,
|
|
4141
|
+
onFreeText: () => void 0
|
|
4142
|
+
}
|
|
4143
|
+
)
|
|
4144
|
+
] });
|
|
4145
|
+
}
|
|
4146
|
+
function AddCoding({
|
|
4147
|
+
lists,
|
|
4148
|
+
onOpen
|
|
4149
|
+
}) {
|
|
4150
|
+
const chosen = React14.useRef(null);
|
|
4151
|
+
if (lists.length === 0) return null;
|
|
4152
|
+
return /* @__PURE__ */ jsxs21(DropdownMenu, { children: [
|
|
4153
|
+
/* @__PURE__ */ jsx32(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs21(
|
|
4154
|
+
Button8,
|
|
4155
|
+
{
|
|
4156
|
+
type: "button",
|
|
4157
|
+
variant: "ghost",
|
|
4158
|
+
size: "sm",
|
|
4159
|
+
className: "h-6 gap-1 px-2 text-xs",
|
|
4160
|
+
children: [
|
|
4161
|
+
/* @__PURE__ */ jsx32(Plus4, { className: "h-3 w-3" }),
|
|
4162
|
+
"Coding"
|
|
4163
|
+
]
|
|
4164
|
+
}
|
|
4165
|
+
) }),
|
|
4166
|
+
/* @__PURE__ */ jsx32(
|
|
4167
|
+
DropdownMenuContent,
|
|
4168
|
+
{
|
|
4169
|
+
align: "start",
|
|
4170
|
+
onCloseAutoFocus: (e) => {
|
|
4171
|
+
if (chosen.current === null) return;
|
|
4172
|
+
e.preventDefault();
|
|
4173
|
+
onOpen(chosen.current);
|
|
4174
|
+
chosen.current = null;
|
|
4175
|
+
},
|
|
4176
|
+
children: lists.map(([list, row]) => /* @__PURE__ */ jsx32(DropdownMenuItem, { onSelect: () => chosen.current = row, children: listTitle(list) }, row))
|
|
4177
|
+
}
|
|
4178
|
+
)
|
|
4179
|
+
] });
|
|
4180
|
+
}
|
|
4181
|
+
function ListChip({
|
|
4182
|
+
list,
|
|
4183
|
+
row,
|
|
4184
|
+
coding,
|
|
4185
|
+
open,
|
|
4186
|
+
set
|
|
4187
|
+
}) {
|
|
4188
|
+
const onOpen = open && (() => open(row));
|
|
4189
|
+
if (coding)
|
|
4190
|
+
return /* @__PURE__ */ jsx32(
|
|
4191
|
+
CodingChip,
|
|
4192
|
+
{
|
|
4193
|
+
label: listTitle(list),
|
|
4194
|
+
coding,
|
|
4195
|
+
onOpen,
|
|
4196
|
+
onRemove: set && (() => set(row, void 0))
|
|
4197
|
+
}
|
|
4198
|
+
);
|
|
4199
|
+
return list.required ? /* @__PURE__ */ jsx32(MissingChip, { label: listTitle(list), onOpen }) : null;
|
|
4200
|
+
}
|
|
4201
|
+
function ChipLine({ lists, rows, others, open, set, addText }) {
|
|
4202
|
+
const addable = lists.map((l, i) => [l, i]).filter(([l, i]) => i > 0 && !rows[i] && !l.required);
|
|
4203
|
+
return /* @__PURE__ */ jsxs21("div", { className: "flex flex-wrap items-center gap-1", children: [
|
|
4204
|
+
lists.slice(1).map((list, k) => /* @__PURE__ */ jsx32(
|
|
4205
|
+
ListChip,
|
|
4206
|
+
{
|
|
4207
|
+
list,
|
|
4208
|
+
row: k + 1,
|
|
4209
|
+
coding: rows[k + 1],
|
|
4210
|
+
open,
|
|
4211
|
+
set
|
|
4212
|
+
},
|
|
4213
|
+
k + 1
|
|
4214
|
+
)),
|
|
4215
|
+
others.map((c) => /* @__PURE__ */ jsx32(CodingChip, { label: listTitle(c), coding: c }, codingKey6(c))),
|
|
4216
|
+
open && /* @__PURE__ */ jsx32(AddCoding, { lists: addable, onOpen: open }),
|
|
4217
|
+
addText && /* @__PURE__ */ jsxs21(
|
|
4218
|
+
Button8,
|
|
4219
|
+
{
|
|
4220
|
+
type: "button",
|
|
4221
|
+
variant: "ghost",
|
|
4222
|
+
size: "sm",
|
|
4223
|
+
className: "h-6 gap-1 px-2 text-xs",
|
|
4224
|
+
onClick: addText,
|
|
4225
|
+
children: [
|
|
4226
|
+
/* @__PURE__ */ jsx32(Plus4, { className: "h-3 w-3" }),
|
|
4227
|
+
"Text"
|
|
4228
|
+
]
|
|
4229
|
+
}
|
|
4230
|
+
)
|
|
4231
|
+
] });
|
|
4232
|
+
}
|
|
4233
|
+
function useConcept(props) {
|
|
4234
|
+
const binding = bindingOf2(props.propertySchema);
|
|
4235
|
+
const lists = binding ? bindingLists(binding) : [];
|
|
4236
|
+
const text = conceptOf2(props.value).text ?? "";
|
|
4237
|
+
const [editing, setEditing] = React14.useState(null);
|
|
4238
|
+
const [showText, setShowText] = React14.useState(false);
|
|
4239
|
+
const offered = offersText(props, binding?.strength === "extensible");
|
|
4240
|
+
const { byList: rows, others } = codingsByList2(props.value, lists);
|
|
4241
|
+
return {
|
|
4242
|
+
lists,
|
|
4243
|
+
rows,
|
|
4244
|
+
others,
|
|
4245
|
+
text,
|
|
4246
|
+
editing,
|
|
4247
|
+
setEditing,
|
|
4248
|
+
textShown: offered && (showText || text !== ""),
|
|
4249
|
+
textAsked: showText,
|
|
4250
|
+
addText: offered && !showText && text === "" ? () => setShowText(true) : void 0
|
|
4251
|
+
};
|
|
4252
|
+
}
|
|
4253
|
+
function useLatestValue(props) {
|
|
4254
|
+
const latest = React14.useRef(props.value);
|
|
4255
|
+
latest.current = props.value;
|
|
4256
|
+
return {
|
|
4257
|
+
get: () => latest.current,
|
|
4258
|
+
change: (next) => {
|
|
4259
|
+
latest.current = next;
|
|
4260
|
+
props.onChange(next);
|
|
4261
|
+
}
|
|
4262
|
+
};
|
|
4263
|
+
}
|
|
4264
|
+
function useSuggestions(lists, { get, change }) {
|
|
4265
|
+
const service = useTerminology2();
|
|
4266
|
+
return (coding) => {
|
|
4267
|
+
if (!coding || !service?.translate) return;
|
|
4268
|
+
const { system, code, version } = coding;
|
|
4269
|
+
const empty = codingsByList2(get(), lists).byList.flatMap(
|
|
4270
|
+
(c, row) => row > 0 && !c ? [row] : []
|
|
4271
|
+
);
|
|
4272
|
+
for (const row of empty)
|
|
4273
|
+
service.translate({
|
|
4274
|
+
coding: { system, code, ...version ? { version } : {} },
|
|
4275
|
+
targets: [lists[row]]
|
|
4276
|
+
}).then(([first]) => {
|
|
4277
|
+
if (first) change(withSuggested(get(), lists, row, first));
|
|
4278
|
+
}).catch(() => void 0);
|
|
4279
|
+
};
|
|
2673
4280
|
}
|
|
2674
|
-
function
|
|
2675
|
-
const
|
|
2676
|
-
const
|
|
2677
|
-
const
|
|
2678
|
-
const
|
|
2679
|
-
|
|
4281
|
+
function CodeableConceptWidget(props) {
|
|
4282
|
+
const { id, value, onBlur } = props;
|
|
4283
|
+
const c = useConcept(props);
|
|
4284
|
+
const editable = !props.disabled && !props.readonly;
|
|
4285
|
+
const blur = () => onBlur?.(id, value);
|
|
4286
|
+
const latest = useLatestValue(props);
|
|
4287
|
+
const suggest = useSuggestions(c.lists, latest);
|
|
4288
|
+
const set = (row, coding) => {
|
|
4289
|
+
latest.change(withRow(latest.get(), c.lists, row, coding));
|
|
4290
|
+
if (row === 0) suggest(coding);
|
|
4291
|
+
};
|
|
4292
|
+
const editingList = c.editing !== null ? c.lists[c.editing] : void 0;
|
|
4293
|
+
return /* @__PURE__ */ jsx32(
|
|
4294
|
+
FormFieldWrapper,
|
|
4295
|
+
{
|
|
4296
|
+
inputId: id,
|
|
4297
|
+
label: props.label,
|
|
4298
|
+
description: props.description,
|
|
4299
|
+
required: props.required,
|
|
4300
|
+
error: firstError(props.rawErrors),
|
|
4301
|
+
children: /* @__PURE__ */ jsxs21("div", { className: "space-y-1.5", children: [
|
|
4302
|
+
/* @__PURE__ */ jsx32(
|
|
4303
|
+
FirstList,
|
|
4304
|
+
{
|
|
4305
|
+
props,
|
|
4306
|
+
lists: c.lists,
|
|
4307
|
+
coding: c.rows[0],
|
|
4308
|
+
set,
|
|
4309
|
+
blur
|
|
4310
|
+
}
|
|
4311
|
+
),
|
|
4312
|
+
/* @__PURE__ */ jsxs21(
|
|
4313
|
+
Popover4,
|
|
4314
|
+
{
|
|
4315
|
+
open: editingList !== void 0,
|
|
4316
|
+
onOpenChange: (o) => {
|
|
4317
|
+
if (o) return;
|
|
4318
|
+
c.setEditing(null);
|
|
4319
|
+
blur();
|
|
4320
|
+
},
|
|
4321
|
+
children: [
|
|
4322
|
+
/* @__PURE__ */ jsx32(PopoverAnchor, { asChild: true, children: /* @__PURE__ */ jsx32("div", { children: /* @__PURE__ */ jsx32(
|
|
4323
|
+
ChipLine,
|
|
4324
|
+
{
|
|
4325
|
+
lists: c.lists,
|
|
4326
|
+
rows: c.rows,
|
|
4327
|
+
others: c.others,
|
|
4328
|
+
open: editable ? c.setEditing : void 0,
|
|
4329
|
+
set: editable ? set : void 0,
|
|
4330
|
+
addText: editable ? c.addText : void 0
|
|
4331
|
+
}
|
|
4332
|
+
) }) }),
|
|
4333
|
+
/* @__PURE__ */ jsx32(
|
|
4334
|
+
PopoverContent4,
|
|
4335
|
+
{
|
|
4336
|
+
className: "w-[--radix-popover-trigger-width] min-w-72 p-0",
|
|
4337
|
+
align: "start",
|
|
4338
|
+
children: editingList && c.editing !== null && /* @__PURE__ */ jsx32(
|
|
4339
|
+
ListSearch,
|
|
4340
|
+
{
|
|
4341
|
+
list: editingList,
|
|
4342
|
+
props,
|
|
4343
|
+
selected: c.rows[c.editing],
|
|
4344
|
+
onPick: (hit) => {
|
|
4345
|
+
set(
|
|
4346
|
+
c.editing,
|
|
4347
|
+
toStored(hit, AS_CODING, void 0)
|
|
4348
|
+
);
|
|
4349
|
+
c.setEditing(null);
|
|
4350
|
+
}
|
|
4351
|
+
}
|
|
4352
|
+
)
|
|
4353
|
+
}
|
|
4354
|
+
)
|
|
4355
|
+
]
|
|
4356
|
+
}
|
|
4357
|
+
),
|
|
4358
|
+
c.textShown && /* @__PURE__ */ jsx32(
|
|
4359
|
+
FormInput,
|
|
4360
|
+
{
|
|
4361
|
+
id: `${id}-text`,
|
|
4362
|
+
label: "Text",
|
|
4363
|
+
value: c.text,
|
|
4364
|
+
placeholder: "In words, as the person said it",
|
|
4365
|
+
disabled: props.disabled,
|
|
4366
|
+
readOnly: props.readonly,
|
|
4367
|
+
onChange: (e) => latest.change(withText(latest.get(), e.target.value)),
|
|
4368
|
+
onBlur: blur,
|
|
4369
|
+
autoFocus: c.textAsked
|
|
4370
|
+
}
|
|
4371
|
+
)
|
|
4372
|
+
] })
|
|
4373
|
+
}
|
|
4374
|
+
);
|
|
2680
4375
|
}
|
|
2681
|
-
function
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
|
|
2687
|
-
propertySchema,
|
|
2688
|
-
required,
|
|
2689
|
-
disabled,
|
|
2690
|
-
readonly,
|
|
2691
|
-
rawErrors,
|
|
2692
|
-
label,
|
|
2693
|
-
description,
|
|
2694
|
-
placeholder,
|
|
2695
|
-
autofocus,
|
|
2696
|
-
options = {}
|
|
4376
|
+
function FirstList({
|
|
4377
|
+
props,
|
|
4378
|
+
lists,
|
|
4379
|
+
coding,
|
|
4380
|
+
set,
|
|
4381
|
+
blur
|
|
2697
4382
|
}) {
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
step,
|
|
2703
|
-
unitPosition: unitPositionOpt
|
|
2704
|
-
} = parseQuantityOptions(options);
|
|
2705
|
-
const quantityValue = value != null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
2706
|
-
const valueRef = useRef4(value);
|
|
2707
|
-
valueRef.current = value;
|
|
2708
|
-
const handleBlur = useCallback6(() => {
|
|
2709
|
-
onBlur?.(id, valueRef.current);
|
|
2710
|
-
}, [id, onBlur]);
|
|
2711
|
-
return /* @__PURE__ */ jsx25(
|
|
2712
|
-
FormQuantityInput,
|
|
4383
|
+
if (!lists[0])
|
|
4384
|
+
return /* @__PURE__ */ jsx32("p", { className: "text-sm text-muted-foreground", children: "No list is bound to this field." });
|
|
4385
|
+
return /* @__PURE__ */ jsx32(
|
|
4386
|
+
CodedValueWidget,
|
|
2713
4387
|
{
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
step,
|
|
2723
|
-
min: propertySchema.minimum,
|
|
2724
|
-
max: propertySchema.maximum,
|
|
2725
|
-
label,
|
|
2726
|
-
labelPlacement: options?.labelPlacement,
|
|
2727
|
-
description,
|
|
2728
|
-
error,
|
|
2729
|
-
placeholder,
|
|
2730
|
-
required,
|
|
2731
|
-
disabled,
|
|
2732
|
-
readOnly: readonly,
|
|
2733
|
-
autoFocus: autofocus
|
|
4388
|
+
...props,
|
|
4389
|
+
label: "",
|
|
4390
|
+
description: void 0,
|
|
4391
|
+
rawErrors: void 0,
|
|
4392
|
+
propertySchema: listSchema(lists[0]),
|
|
4393
|
+
value: coding,
|
|
4394
|
+
onChange: (next) => set(0, next),
|
|
4395
|
+
onBlur: blur
|
|
2734
4396
|
}
|
|
2735
4397
|
);
|
|
2736
4398
|
}
|
|
2737
4399
|
|
|
2738
4400
|
// src/widgets/DateWidget.tsx
|
|
2739
4401
|
import { DateInput } from "@petrarca/sonnet-ui";
|
|
2740
|
-
import { jsx as
|
|
4402
|
+
import { jsx as jsx33 } from "react/jsx-runtime";
|
|
2741
4403
|
function resolvePrecision(value) {
|
|
2742
4404
|
return value === "year" || value === "month" ? value : "day";
|
|
2743
4405
|
}
|
|
@@ -2752,12 +4414,13 @@ function DateWidget({
|
|
|
2752
4414
|
label,
|
|
2753
4415
|
description,
|
|
2754
4416
|
placeholder,
|
|
2755
|
-
options
|
|
4417
|
+
options,
|
|
4418
|
+
propertySchema
|
|
2756
4419
|
}) {
|
|
2757
4420
|
const error = firstError(rawErrors);
|
|
2758
4421
|
const precision = resolvePrecision(options?.precision);
|
|
2759
4422
|
const locale = typeof options?.locale === "string" ? options.locale : void 0;
|
|
2760
|
-
return /* @__PURE__ */
|
|
4423
|
+
return /* @__PURE__ */ jsx33(
|
|
2761
4424
|
FormFieldWrapper,
|
|
2762
4425
|
{
|
|
2763
4426
|
inputId: id,
|
|
@@ -2765,7 +4428,7 @@ function DateWidget({
|
|
|
2765
4428
|
description,
|
|
2766
4429
|
required,
|
|
2767
4430
|
labelPlacement: options?.labelPlacement,
|
|
2768
|
-
children: /* @__PURE__ */
|
|
4431
|
+
children: /* @__PURE__ */ jsx33(
|
|
2769
4432
|
DateInput,
|
|
2770
4433
|
{
|
|
2771
4434
|
id,
|
|
@@ -2777,7 +4440,9 @@ function DateWidget({
|
|
|
2777
4440
|
placeholder,
|
|
2778
4441
|
required,
|
|
2779
4442
|
disabled,
|
|
2780
|
-
error
|
|
4443
|
+
error,
|
|
4444
|
+
min: propertySchema.formatMinimum,
|
|
4445
|
+
max: propertySchema.formatMaximum
|
|
2781
4446
|
}
|
|
2782
4447
|
)
|
|
2783
4448
|
}
|
|
@@ -2786,7 +4451,7 @@ function DateWidget({
|
|
|
2786
4451
|
|
|
2787
4452
|
// src/widgets/TimeWidget.tsx
|
|
2788
4453
|
import { TimeInput } from "@petrarca/sonnet-ui";
|
|
2789
|
-
import { jsx as
|
|
4454
|
+
import { jsx as jsx34 } from "react/jsx-runtime";
|
|
2790
4455
|
function resolveGranularity(value) {
|
|
2791
4456
|
return value === "second" ? "second" : "minute";
|
|
2792
4457
|
}
|
|
@@ -2805,7 +4470,7 @@ function TimeWidget({
|
|
|
2805
4470
|
}) {
|
|
2806
4471
|
const error = firstError(rawErrors);
|
|
2807
4472
|
const granularity = resolveGranularity(options?.granularity);
|
|
2808
|
-
return /* @__PURE__ */
|
|
4473
|
+
return /* @__PURE__ */ jsx34(
|
|
2809
4474
|
FormFieldWrapper,
|
|
2810
4475
|
{
|
|
2811
4476
|
inputId: id,
|
|
@@ -2813,7 +4478,7 @@ function TimeWidget({
|
|
|
2813
4478
|
description,
|
|
2814
4479
|
required,
|
|
2815
4480
|
labelPlacement: options?.labelPlacement,
|
|
2816
|
-
children: /* @__PURE__ */
|
|
4481
|
+
children: /* @__PURE__ */ jsx34(
|
|
2817
4482
|
TimeInput,
|
|
2818
4483
|
{
|
|
2819
4484
|
id,
|
|
@@ -2833,7 +4498,7 @@ function TimeWidget({
|
|
|
2833
4498
|
|
|
2834
4499
|
// src/widgets/DateTimeWidget.tsx
|
|
2835
4500
|
import { DateTimeInput } from "@petrarca/sonnet-ui";
|
|
2836
|
-
import { jsx as
|
|
4501
|
+
import { jsx as jsx35 } from "react/jsx-runtime";
|
|
2837
4502
|
function resolveGranularity2(value) {
|
|
2838
4503
|
return value === "second" ? "second" : "minute";
|
|
2839
4504
|
}
|
|
@@ -2847,13 +4512,14 @@ function DateTimeWidget({
|
|
|
2847
4512
|
rawErrors,
|
|
2848
4513
|
label,
|
|
2849
4514
|
description,
|
|
2850
|
-
options
|
|
4515
|
+
options,
|
|
4516
|
+
propertySchema
|
|
2851
4517
|
}) {
|
|
2852
4518
|
const error = firstError(rawErrors);
|
|
2853
4519
|
const granularity = resolveGranularity2(options?.granularity);
|
|
2854
4520
|
const timeZone = typeof options?.timeZone === "string" ? options.timeZone : void 0;
|
|
2855
4521
|
const locale = typeof options?.locale === "string" ? options.locale : void 0;
|
|
2856
|
-
return /* @__PURE__ */
|
|
4522
|
+
return /* @__PURE__ */ jsx35(
|
|
2857
4523
|
FormFieldWrapper,
|
|
2858
4524
|
{
|
|
2859
4525
|
inputId: id,
|
|
@@ -2861,7 +4527,7 @@ function DateTimeWidget({
|
|
|
2861
4527
|
description,
|
|
2862
4528
|
required,
|
|
2863
4529
|
labelPlacement: options?.labelPlacement,
|
|
2864
|
-
children: /* @__PURE__ */
|
|
4530
|
+
children: /* @__PURE__ */ jsx35(
|
|
2865
4531
|
DateTimeInput,
|
|
2866
4532
|
{
|
|
2867
4533
|
idPrefix: id,
|
|
@@ -2873,7 +4539,9 @@ function DateTimeWidget({
|
|
|
2873
4539
|
locale,
|
|
2874
4540
|
required,
|
|
2875
4541
|
disabled,
|
|
2876
|
-
error
|
|
4542
|
+
error,
|
|
4543
|
+
min: propertySchema.formatMinimum,
|
|
4544
|
+
max: propertySchema.formatMaximum
|
|
2877
4545
|
}
|
|
2878
4546
|
)
|
|
2879
4547
|
}
|
|
@@ -2881,20 +4549,20 @@ function DateTimeWidget({
|
|
|
2881
4549
|
}
|
|
2882
4550
|
|
|
2883
4551
|
// src/widgets/DisplayWidget.tsx
|
|
2884
|
-
import { jsx as
|
|
4552
|
+
import { jsx as jsx36, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
2885
4553
|
function DisplayWidget({
|
|
2886
4554
|
label,
|
|
2887
4555
|
description
|
|
2888
4556
|
}) {
|
|
2889
4557
|
if (!label && !description) return null;
|
|
2890
|
-
return /* @__PURE__ */
|
|
2891
|
-
label && /* @__PURE__ */
|
|
2892
|
-
description && /* @__PURE__ */
|
|
4558
|
+
return /* @__PURE__ */ jsxs22("div", { className: "space-y-1", children: [
|
|
4559
|
+
label && /* @__PURE__ */ jsx36("p", { className: "text-sm text-foreground", children: label }),
|
|
4560
|
+
description && /* @__PURE__ */ jsx36("p", { className: "text-sm text-muted-foreground", children: description })
|
|
2893
4561
|
] });
|
|
2894
4562
|
}
|
|
2895
4563
|
|
|
2896
4564
|
// src/widgets/OneOfWidget.tsx
|
|
2897
|
-
import { useMemo as
|
|
4565
|
+
import { useMemo as useMemo8 } from "react";
|
|
2898
4566
|
import {
|
|
2899
4567
|
getDiscriminator,
|
|
2900
4568
|
getBranchValue,
|
|
@@ -2909,7 +4577,7 @@ import {
|
|
|
2909
4577
|
SelectContent,
|
|
2910
4578
|
SelectItem
|
|
2911
4579
|
} from "@petrarca/sonnet-ui";
|
|
2912
|
-
import { jsx as
|
|
4580
|
+
import { jsx as jsx37, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
2913
4581
|
function buildChoices(branches, discriminator) {
|
|
2914
4582
|
return branches.map((branch, index) => {
|
|
2915
4583
|
const raw = discriminator ? getBranchValue(branch, discriminator) : void 0;
|
|
@@ -2945,15 +4613,20 @@ function BranchSelector({
|
|
|
2945
4613
|
disabled,
|
|
2946
4614
|
onSelect
|
|
2947
4615
|
}) {
|
|
2948
|
-
return /* @__PURE__ */
|
|
2949
|
-
label && /* @__PURE__ */
|
|
2950
|
-
/* @__PURE__ */
|
|
2951
|
-
/* @__PURE__ */
|
|
2952
|
-
/* @__PURE__ */
|
|
4616
|
+
return /* @__PURE__ */ jsxs23("div", { className: "space-y-1", children: [
|
|
4617
|
+
label && /* @__PURE__ */ jsx37(Label, { htmlFor: id, children: label }),
|
|
4618
|
+
/* @__PURE__ */ jsxs23(Select, { value: activeValue, onValueChange: onSelect, disabled, children: [
|
|
4619
|
+
/* @__PURE__ */ jsx37(SelectTrigger, { id, children: /* @__PURE__ */ jsx37(SelectValue, { placeholder: "Select an option" }) }),
|
|
4620
|
+
/* @__PURE__ */ jsx37(SelectContent, { children: choices.map((c) => /* @__PURE__ */ jsx37(SelectItem, { value: c.value, children: c.label }, c.value)) })
|
|
2953
4621
|
] }),
|
|
2954
|
-
description && /* @__PURE__ */
|
|
4622
|
+
description && /* @__PURE__ */ jsx37("p", { className: "text-sm text-muted-foreground", children: description })
|
|
2955
4623
|
] });
|
|
2956
4624
|
}
|
|
4625
|
+
function branchUiSchema(uiSchema, discriminator) {
|
|
4626
|
+
const fields = uiSchema?.["x-ui-fields"] ?? {};
|
|
4627
|
+
if (!discriminator) return fields;
|
|
4628
|
+
return { [discriminator]: { "x-ui-options": { hidden: true } }, ...fields };
|
|
4629
|
+
}
|
|
2957
4630
|
function resolveActive(propertySchema, branches, choices, discriminator, data) {
|
|
2958
4631
|
const index = findActiveBranch(propertySchema, data, discriminator);
|
|
2959
4632
|
if (index < 0) return { value: "", label: "", subSchema: null };
|
|
@@ -2978,12 +4651,12 @@ function OneOfWidget({
|
|
|
2978
4651
|
}) {
|
|
2979
4652
|
const { renderer: Renderer, templates } = useNestedFormContext();
|
|
2980
4653
|
const ContainerTemplate = templates.ObjectContainerTemplate ?? DefaultObjectContainerTemplate;
|
|
2981
|
-
const branches =
|
|
2982
|
-
const discriminator =
|
|
4654
|
+
const branches = useMemo8(() => propertySchema.oneOf ?? [], [propertySchema]);
|
|
4655
|
+
const discriminator = useMemo8(
|
|
2983
4656
|
() => getDiscriminator(propertySchema),
|
|
2984
4657
|
[propertySchema]
|
|
2985
4658
|
);
|
|
2986
|
-
const choices =
|
|
4659
|
+
const choices = useMemo8(
|
|
2987
4660
|
() => buildChoices(branches, discriminator),
|
|
2988
4661
|
[branches, discriminator]
|
|
2989
4662
|
);
|
|
@@ -2996,9 +4669,9 @@ function OneOfWidget({
|
|
|
2996
4669
|
data
|
|
2997
4670
|
);
|
|
2998
4671
|
if (branches.length === 0) return null;
|
|
2999
|
-
const subUiSchema = uiSchema
|
|
3000
|
-
return /* @__PURE__ */
|
|
3001
|
-
/* @__PURE__ */
|
|
4672
|
+
const subUiSchema = branchUiSchema(uiSchema, discriminator);
|
|
4673
|
+
return /* @__PURE__ */ jsxs23("div", { className: "space-y-4", children: [
|
|
4674
|
+
/* @__PURE__ */ jsx37(
|
|
3002
4675
|
BranchSelector,
|
|
3003
4676
|
{
|
|
3004
4677
|
id,
|
|
@@ -3010,14 +4683,14 @@ function OneOfWidget({
|
|
|
3010
4683
|
onSelect: (selected) => onChange(branchChangeData(choices, branches, discriminator, selected))
|
|
3011
4684
|
}
|
|
3012
4685
|
),
|
|
3013
|
-
active.subSchema && /* @__PURE__ */
|
|
4686
|
+
active.subSchema && /* @__PURE__ */ jsx37(
|
|
3014
4687
|
ContainerTemplate,
|
|
3015
4688
|
{
|
|
3016
4689
|
label: active.label,
|
|
3017
4690
|
description: void 0,
|
|
3018
4691
|
variant: options?.variant || "section",
|
|
3019
4692
|
defaultOpen: true,
|
|
3020
|
-
children: /* @__PURE__ */
|
|
4693
|
+
children: /* @__PURE__ */ jsx37(
|
|
3021
4694
|
Renderer,
|
|
3022
4695
|
{
|
|
3023
4696
|
schema: active.subSchema,
|
|
@@ -3035,8 +4708,304 @@ function OneOfWidget({
|
|
|
3035
4708
|
] });
|
|
3036
4709
|
}
|
|
3037
4710
|
|
|
4711
|
+
// src/widgets/RadioWidget.tsx
|
|
4712
|
+
import { RadioGroup, RadioGroupItem } from "@petrarca/sonnet-ui";
|
|
4713
|
+
import { cn as cn14 } from "@petrarca/sonnet-core";
|
|
4714
|
+
import { jsx as jsx38, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
4715
|
+
function RadioWidget({
|
|
4716
|
+
id,
|
|
4717
|
+
name,
|
|
4718
|
+
value,
|
|
4719
|
+
onChange,
|
|
4720
|
+
onBlur,
|
|
4721
|
+
propertySchema,
|
|
4722
|
+
required,
|
|
4723
|
+
disabled,
|
|
4724
|
+
readonly,
|
|
4725
|
+
rawErrors,
|
|
4726
|
+
label,
|
|
4727
|
+
description,
|
|
4728
|
+
options
|
|
4729
|
+
}) {
|
|
4730
|
+
const choices = buildSelectOptions(propertySchema, options?.enumNames ?? {});
|
|
4731
|
+
const horizontal = options?.orientation === "horizontal";
|
|
4732
|
+
return /* @__PURE__ */ jsx38(
|
|
4733
|
+
FormFieldWrapper,
|
|
4734
|
+
{
|
|
4735
|
+
inputId: id,
|
|
4736
|
+
label,
|
|
4737
|
+
description,
|
|
4738
|
+
error: firstError(rawErrors),
|
|
4739
|
+
required,
|
|
4740
|
+
compact: options?.compact,
|
|
4741
|
+
children: /* @__PURE__ */ jsx38(
|
|
4742
|
+
RadioGroup,
|
|
4743
|
+
{
|
|
4744
|
+
id,
|
|
4745
|
+
name,
|
|
4746
|
+
value: value === void 0 || value === null ? "" : String(value),
|
|
4747
|
+
onValueChange: (v) => onChange(v),
|
|
4748
|
+
onBlur: () => onBlur?.(id, value),
|
|
4749
|
+
disabled: disabled || readonly,
|
|
4750
|
+
required,
|
|
4751
|
+
className: cn14(horizontal && "flex flex-wrap gap-4"),
|
|
4752
|
+
children: choices.map((c) => /* @__PURE__ */ jsxs24("label", { className: "flex items-center gap-2 text-sm", children: [
|
|
4753
|
+
/* @__PURE__ */ jsx38(RadioGroupItem, { value: c.value, id: `${id}-${c.value}` }),
|
|
4754
|
+
c.label
|
|
4755
|
+
] }, c.value))
|
|
4756
|
+
}
|
|
4757
|
+
)
|
|
4758
|
+
}
|
|
4759
|
+
);
|
|
4760
|
+
}
|
|
4761
|
+
|
|
4762
|
+
// src/widgets/CheckboxGroupWidget.tsx
|
|
4763
|
+
import { Checkbox as Checkbox2 } from "@petrarca/sonnet-ui";
|
|
4764
|
+
import { cn as cn15 } from "@petrarca/sonnet-core";
|
|
4765
|
+
import { jsx as jsx39, jsxs as jsxs25 } from "react/jsx-runtime";
|
|
4766
|
+
function CheckboxGroupWidget({
|
|
4767
|
+
id,
|
|
4768
|
+
value,
|
|
4769
|
+
onChange,
|
|
4770
|
+
onBlur,
|
|
4771
|
+
propertySchema,
|
|
4772
|
+
required,
|
|
4773
|
+
disabled,
|
|
4774
|
+
readonly,
|
|
4775
|
+
rawErrors,
|
|
4776
|
+
label,
|
|
4777
|
+
description,
|
|
4778
|
+
options
|
|
4779
|
+
}) {
|
|
4780
|
+
const choices = buildSelectOptions(propertySchema, options?.enumNames ?? {});
|
|
4781
|
+
const chosen = new Set(Array.isArray(value) ? value.map(String) : []);
|
|
4782
|
+
const toggle = (v, on) => {
|
|
4783
|
+
const next = choices.map((c) => c.value).filter((c) => c === v ? on : chosen.has(c));
|
|
4784
|
+
onChange(next);
|
|
4785
|
+
};
|
|
4786
|
+
return /* @__PURE__ */ jsx39(
|
|
4787
|
+
FormFieldWrapper,
|
|
4788
|
+
{
|
|
4789
|
+
inputId: id,
|
|
4790
|
+
label,
|
|
4791
|
+
description,
|
|
4792
|
+
error: firstError(rawErrors),
|
|
4793
|
+
required,
|
|
4794
|
+
compact: options?.compact,
|
|
4795
|
+
children: /* @__PURE__ */ jsx39(
|
|
4796
|
+
"div",
|
|
4797
|
+
{
|
|
4798
|
+
id,
|
|
4799
|
+
role: "group",
|
|
4800
|
+
className: cn15(
|
|
4801
|
+
"grid gap-2",
|
|
4802
|
+
options?.orientation === "horizontal" && "flex flex-wrap gap-4"
|
|
4803
|
+
),
|
|
4804
|
+
onBlur: () => onBlur?.(id, value),
|
|
4805
|
+
children: choices.map((c) => /* @__PURE__ */ jsxs25("label", { className: "flex items-center gap-2 text-sm", children: [
|
|
4806
|
+
/* @__PURE__ */ jsx39(
|
|
4807
|
+
Checkbox2,
|
|
4808
|
+
{
|
|
4809
|
+
id: `${id}-${c.value}`,
|
|
4810
|
+
checked: chosen.has(c.value),
|
|
4811
|
+
onCheckedChange: (on) => toggle(c.value, on === true),
|
|
4812
|
+
disabled: disabled || readonly
|
|
4813
|
+
}
|
|
4814
|
+
),
|
|
4815
|
+
c.label
|
|
4816
|
+
] }, c.value))
|
|
4817
|
+
}
|
|
4818
|
+
)
|
|
4819
|
+
}
|
|
4820
|
+
);
|
|
4821
|
+
}
|
|
4822
|
+
|
|
4823
|
+
// src/widgets/ChoiceWithTextWidget.tsx
|
|
4824
|
+
import { jsx as jsx40 } from "react/jsx-runtime";
|
|
4825
|
+
var ROW_LAYOUT = {
|
|
4826
|
+
rows: [{ fields: ["choice", "text"], widths: ["md", "full"] }]
|
|
4827
|
+
};
|
|
4828
|
+
function textTitleOf(prop) {
|
|
4829
|
+
const text = prop.properties?.text ?? prop.allOf?.[0]?.then?.properties?.text;
|
|
4830
|
+
return text?.title;
|
|
4831
|
+
}
|
|
4832
|
+
function containerUiSchema(props) {
|
|
4833
|
+
const fields = props.uiSchema?.["x-ui-fields"] ?? {};
|
|
4834
|
+
const textTitle = textTitleOf(props.propertySchema);
|
|
4835
|
+
const layout = props.uiSchema?.["x-ui-layout"];
|
|
4836
|
+
return {
|
|
4837
|
+
...props.uiSchema,
|
|
4838
|
+
"x-ui-layout": layout ?? ROW_LAYOUT,
|
|
4839
|
+
"x-ui-fields": {
|
|
4840
|
+
...fields,
|
|
4841
|
+
choice: { "x-ui-title": false, ...fields.choice },
|
|
4842
|
+
text: {
|
|
4843
|
+
"x-ui-title": false,
|
|
4844
|
+
...textTitle ? { "x-ui-placeholder": textTitle } : {},
|
|
4845
|
+
...fields.text
|
|
4846
|
+
}
|
|
4847
|
+
}
|
|
4848
|
+
};
|
|
4849
|
+
}
|
|
4850
|
+
function ChoiceWithTextWidget(props) {
|
|
4851
|
+
return /* @__PURE__ */ jsx40(
|
|
4852
|
+
FormFieldWrapper,
|
|
4853
|
+
{
|
|
4854
|
+
inputId: props.id,
|
|
4855
|
+
label: props.label,
|
|
4856
|
+
description: props.description,
|
|
4857
|
+
required: props.required,
|
|
4858
|
+
compact: props.options?.compact,
|
|
4859
|
+
children: /* @__PURE__ */ jsx40(
|
|
4860
|
+
ObjectWidget,
|
|
4861
|
+
{
|
|
4862
|
+
...props,
|
|
4863
|
+
uiSchema: containerUiSchema(props),
|
|
4864
|
+
options: { ...props.options, variant: "inline" }
|
|
4865
|
+
}
|
|
4866
|
+
)
|
|
4867
|
+
}
|
|
4868
|
+
);
|
|
4869
|
+
}
|
|
4870
|
+
|
|
4871
|
+
// src/widgets/AbsentReasonsWidget.tsx
|
|
4872
|
+
import {
|
|
4873
|
+
Button as Button9,
|
|
4874
|
+
IconButton as IconButton2,
|
|
4875
|
+
Select as Select2,
|
|
4876
|
+
SelectContent as SelectContent2,
|
|
4877
|
+
SelectItem as SelectItem2,
|
|
4878
|
+
SelectTrigger as SelectTrigger2,
|
|
4879
|
+
SelectValue as SelectValue2
|
|
4880
|
+
} from "@petrarca/sonnet-ui";
|
|
4881
|
+
import { Plus as Plus5, X as X7 } from "lucide-react";
|
|
4882
|
+
import { jsx as jsx41, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
4883
|
+
function Pick({
|
|
4884
|
+
label,
|
|
4885
|
+
value,
|
|
4886
|
+
items,
|
|
4887
|
+
onChange,
|
|
4888
|
+
className
|
|
4889
|
+
}) {
|
|
4890
|
+
return /* @__PURE__ */ jsxs26(Select2, { value: value || void 0, onValueChange: onChange, children: [
|
|
4891
|
+
/* @__PURE__ */ jsx41(SelectTrigger2, { "aria-label": label, className, children: /* @__PURE__ */ jsx41(SelectValue2, { placeholder: label.toLowerCase() }) }),
|
|
4892
|
+
/* @__PURE__ */ jsx41(SelectContent2, { children: items.map((i) => /* @__PURE__ */ jsx41(SelectItem2, { value: i.value, children: i.label }, i.value)) })
|
|
4893
|
+
] });
|
|
4894
|
+
}
|
|
4895
|
+
function questionsOf(props) {
|
|
4896
|
+
return Object.entries(props.schema.properties ?? {}).filter(([key, p]) => key !== props.name && p.type !== "null").map(([key, p]) => ({ value: key, label: p.title ?? key }));
|
|
4897
|
+
}
|
|
4898
|
+
function ReasonRow({
|
|
4899
|
+
questionKey,
|
|
4900
|
+
reason,
|
|
4901
|
+
given,
|
|
4902
|
+
questions,
|
|
4903
|
+
reasons,
|
|
4904
|
+
locked,
|
|
4905
|
+
set
|
|
4906
|
+
}) {
|
|
4907
|
+
const { [questionKey]: _, ...rest } = given;
|
|
4908
|
+
return /* @__PURE__ */ jsxs26("div", { className: "group/row flex items-center gap-1.5 px-1.5 py-1", children: [
|
|
4909
|
+
/* @__PURE__ */ jsx41(
|
|
4910
|
+
Pick,
|
|
4911
|
+
{
|
|
4912
|
+
label: "Question",
|
|
4913
|
+
value: questionKey,
|
|
4914
|
+
items: questions.filter(
|
|
4915
|
+
(q) => q.value === questionKey || !(q.value in given)
|
|
4916
|
+
),
|
|
4917
|
+
onChange: (next) => set({ ...rest, [next]: reason }),
|
|
4918
|
+
className: "h-7 min-w-0 flex-1 text-xs"
|
|
4919
|
+
}
|
|
4920
|
+
),
|
|
4921
|
+
/* @__PURE__ */ jsx41(
|
|
4922
|
+
Pick,
|
|
4923
|
+
{
|
|
4924
|
+
label: "Reason",
|
|
4925
|
+
value: reason,
|
|
4926
|
+
items: reasons,
|
|
4927
|
+
onChange: (r) => set({ ...given, [questionKey]: r }),
|
|
4928
|
+
className: "h-7 w-40 shrink-0 text-xs"
|
|
4929
|
+
}
|
|
4930
|
+
),
|
|
4931
|
+
!locked && /* @__PURE__ */ jsx41(
|
|
4932
|
+
IconButton2,
|
|
4933
|
+
{
|
|
4934
|
+
label: "Answer it after all",
|
|
4935
|
+
revealOnHover: true,
|
|
4936
|
+
onClick: () => set(rest),
|
|
4937
|
+
children: /* @__PURE__ */ jsx41(X7, {})
|
|
4938
|
+
}
|
|
4939
|
+
)
|
|
4940
|
+
] });
|
|
4941
|
+
}
|
|
4942
|
+
function reasonsState(props) {
|
|
4943
|
+
const { value, readonly, disabled, options } = props;
|
|
4944
|
+
const additional = props.propertySchema.additionalProperties;
|
|
4945
|
+
const reasons = buildSelectOptions(
|
|
4946
|
+
additional ?? {},
|
|
4947
|
+
options?.enumNames ?? {}
|
|
4948
|
+
);
|
|
4949
|
+
const given = value && typeof value === "object" ? value : {};
|
|
4950
|
+
const questions = questionsOf(props);
|
|
4951
|
+
const free = questions.filter((q) => !(q.value in given));
|
|
4952
|
+
const locked = readonly || disabled;
|
|
4953
|
+
return {
|
|
4954
|
+
reasons,
|
|
4955
|
+
given,
|
|
4956
|
+
questions,
|
|
4957
|
+
free,
|
|
4958
|
+
locked,
|
|
4959
|
+
canAdd: !locked && free.length > 0 && reasons.length > 0
|
|
4960
|
+
};
|
|
4961
|
+
}
|
|
4962
|
+
function AbsentReasonsWidget(props) {
|
|
4963
|
+
const { id, onChange, label, rawErrors, options } = props;
|
|
4964
|
+
const { reasons, given, questions, free, locked, canAdd } = reasonsState(props);
|
|
4965
|
+
const set = (next) => onChange(Object.keys(next).length ? next : void 0);
|
|
4966
|
+
return /* @__PURE__ */ jsx41(
|
|
4967
|
+
FormFieldWrapper,
|
|
4968
|
+
{
|
|
4969
|
+
inputId: id,
|
|
4970
|
+
label,
|
|
4971
|
+
error: firstError(rawErrors),
|
|
4972
|
+
compact: options?.compact,
|
|
4973
|
+
children: /* @__PURE__ */ jsxs26("div", { className: "space-y-1.5", children: [
|
|
4974
|
+
Object.keys(given).length > 0 && /* @__PURE__ */ jsx41("div", { className: "rounded-md border divide-y", children: Object.entries(given).map(([key, reason]) => /* @__PURE__ */ jsx41(
|
|
4975
|
+
ReasonRow,
|
|
4976
|
+
{
|
|
4977
|
+
questionKey: key,
|
|
4978
|
+
reason,
|
|
4979
|
+
given,
|
|
4980
|
+
questions,
|
|
4981
|
+
reasons,
|
|
4982
|
+
locked,
|
|
4983
|
+
set
|
|
4984
|
+
},
|
|
4985
|
+
key
|
|
4986
|
+
)) }),
|
|
4987
|
+
canAdd && /* @__PURE__ */ jsxs26(
|
|
4988
|
+
Button9,
|
|
4989
|
+
{
|
|
4990
|
+
type: "button",
|
|
4991
|
+
variant: "ghost",
|
|
4992
|
+
size: "sm",
|
|
4993
|
+
className: "h-7 gap-1 px-2 text-xs",
|
|
4994
|
+
onClick: () => set({ ...given, [free[0].value]: reasons[0].value }),
|
|
4995
|
+
children: [
|
|
4996
|
+
/* @__PURE__ */ jsx41(Plus5, { className: "h-3.5 w-3.5" }),
|
|
4997
|
+
"Leave a question unanswered"
|
|
4998
|
+
]
|
|
4999
|
+
}
|
|
5000
|
+
)
|
|
5001
|
+
] })
|
|
5002
|
+
}
|
|
5003
|
+
);
|
|
5004
|
+
}
|
|
5005
|
+
|
|
3038
5006
|
// src/widgets/widgetResolver.ts
|
|
3039
5007
|
import {
|
|
5008
|
+
bindingOf as bindingOf3,
|
|
3040
5009
|
isNullableBoolean as isNullableBoolean2,
|
|
3041
5010
|
isOneOf,
|
|
3042
5011
|
extractEnumValues as extractEnumValues2,
|
|
@@ -3113,20 +5082,45 @@ function resolveFromUiWidget(uiWidget, propertySchema, registry) {
|
|
|
3113
5082
|
function isObjectArraySchema(schema) {
|
|
3114
5083
|
return schema.type === "array" && schema.items?.type === "object" && !!schema.items?.properties;
|
|
3115
5084
|
}
|
|
5085
|
+
function isStringArraySchema(schema) {
|
|
5086
|
+
return schema.type === "array" && schema.items?.type === "string" && !Array.isArray(schema.items?.enum);
|
|
5087
|
+
}
|
|
5088
|
+
function isStringMapSchema(schema) {
|
|
5089
|
+
const extra = schema.additionalProperties;
|
|
5090
|
+
return schema.type === "object" && !schema.properties && typeof extra === "object" && extra !== null && extra.type === "string";
|
|
5091
|
+
}
|
|
5092
|
+
function isEnumArraySchema(schema) {
|
|
5093
|
+
return schema.type === "array" && Array.isArray(schema.items?.enum);
|
|
5094
|
+
}
|
|
5095
|
+
function isCodedShape(schema) {
|
|
5096
|
+
return schema.type === "string" || schema.type === "array" || !!schema.anyOf;
|
|
5097
|
+
}
|
|
3116
5098
|
function registryLookup(registry, widgetName) {
|
|
3117
5099
|
return registry[widgetName] || registry["TextInputWidget"];
|
|
3118
5100
|
}
|
|
5101
|
+
function objectWidgetName(schema) {
|
|
5102
|
+
if (schema.properties) return "ObjectWidget";
|
|
5103
|
+
if (isStringMapSchema(schema)) return "KeyValueWidget";
|
|
5104
|
+
return "JsonEditorWidget";
|
|
5105
|
+
}
|
|
5106
|
+
function arrayWidgetName(schema) {
|
|
5107
|
+
if (isObjectArraySchema(schema)) return "ArrayWidget";
|
|
5108
|
+
if (isEnumArraySchema(schema)) return "SelectWidget";
|
|
5109
|
+
if (isStringArraySchema(schema)) return "TagsInputWidget";
|
|
5110
|
+
return null;
|
|
5111
|
+
}
|
|
3119
5112
|
function resolveFromSchemaStructure(schema, registry) {
|
|
3120
5113
|
if (isOneOf(schema)) return registryLookup(registry, "OneOfWidget");
|
|
3121
5114
|
if (isNullableBoolean2(schema))
|
|
3122
5115
|
return registryLookup(registry, "CheckboxWidget");
|
|
3123
5116
|
if (extractEnumValues2(schema).length > 0)
|
|
3124
5117
|
return registryLookup(registry, "SelectWidget");
|
|
3125
|
-
if (schema
|
|
3126
|
-
return registryLookup(registry, "
|
|
3127
|
-
if (
|
|
3128
|
-
return registryLookup(registry,
|
|
3129
|
-
|
|
5118
|
+
if (bindingOf3(schema) && isCodedShape(schema))
|
|
5119
|
+
return registryLookup(registry, "CodedValueWidget");
|
|
5120
|
+
if (schema.type === "object")
|
|
5121
|
+
return registryLookup(registry, objectWidgetName(schema));
|
|
5122
|
+
const arrayWidget = arrayWidgetName(schema);
|
|
5123
|
+
return arrayWidget ? registryLookup(registry, arrayWidget) : null;
|
|
3130
5124
|
}
|
|
3131
5125
|
function resolveFromTypeFormat(schema, registry) {
|
|
3132
5126
|
const type = getFieldType(schema);
|
|
@@ -3157,15 +5151,22 @@ var DEFAULT_WIDGETS = {
|
|
|
3157
5151
|
SelectWidget,
|
|
3158
5152
|
TagsInputWidget,
|
|
3159
5153
|
JsonEditorWidget,
|
|
5154
|
+
KeyValueWidget,
|
|
3160
5155
|
EntitySelectWidget,
|
|
3161
5156
|
ObjectWidget,
|
|
3162
5157
|
ArrayWidget,
|
|
3163
5158
|
QuantityWidget,
|
|
5159
|
+
CodedValueWidget,
|
|
5160
|
+
CodeableConceptWidget,
|
|
3164
5161
|
DateWidget,
|
|
3165
5162
|
TimeWidget,
|
|
3166
5163
|
DateTimeWidget,
|
|
3167
5164
|
DisplayWidget,
|
|
3168
5165
|
OneOfWidget,
|
|
5166
|
+
RadioWidget,
|
|
5167
|
+
CheckboxGroupWidget,
|
|
5168
|
+
ChoiceWithTextWidget,
|
|
5169
|
+
AbsentReasonsWidget,
|
|
3169
5170
|
// Lowercase aliases for x-ui-widget convenience
|
|
3170
5171
|
text: TextInputWidget,
|
|
3171
5172
|
textarea: TextareaWidget,
|
|
@@ -3174,21 +5175,28 @@ var DEFAULT_WIDGETS = {
|
|
|
3174
5175
|
select: SelectWidget,
|
|
3175
5176
|
tags: TagsInputWidget,
|
|
3176
5177
|
"json-editor": JsonEditorWidget,
|
|
5178
|
+
"key-value": KeyValueWidget,
|
|
3177
5179
|
"entity-select": EntitySelectWidget,
|
|
3178
5180
|
object: ObjectWidget,
|
|
3179
5181
|
array: ArrayWidget,
|
|
3180
5182
|
quantity: QuantityWidget,
|
|
5183
|
+
"coded-value": CodedValueWidget,
|
|
5184
|
+
"codeable-concept": CodeableConceptWidget,
|
|
3181
5185
|
date: DateWidget,
|
|
3182
5186
|
time: TimeWidget,
|
|
3183
5187
|
"date-time": DateTimeWidget,
|
|
3184
5188
|
display: DisplayWidget,
|
|
3185
|
-
"one-of": OneOfWidget
|
|
5189
|
+
"one-of": OneOfWidget,
|
|
5190
|
+
radio: RadioWidget,
|
|
5191
|
+
"checkbox-group": CheckboxGroupWidget,
|
|
5192
|
+
"choice-with-text": ChoiceWithTextWidget,
|
|
5193
|
+
"absent-reasons": AbsentReasonsWidget
|
|
3186
5194
|
};
|
|
3187
5195
|
|
|
3188
5196
|
// src/templates/HorizontalArrayItemTemplate.tsx
|
|
3189
5197
|
import { Trash2 as Trash22, ChevronUp as ChevronUp2, ChevronDown as ChevronDown4 } from "lucide-react";
|
|
3190
|
-
import { Button as
|
|
3191
|
-
import { jsx as
|
|
5198
|
+
import { Button as Button10 } from "@petrarca/sonnet-ui";
|
|
5199
|
+
import { jsx as jsx42, jsxs as jsxs27 } from "react/jsx-runtime";
|
|
3192
5200
|
function HorizontalArrayItemTemplate({
|
|
3193
5201
|
children,
|
|
3194
5202
|
index,
|
|
@@ -3212,7 +5220,7 @@ function HorizontalArrayItemTemplate({
|
|
|
3212
5220
|
);
|
|
3213
5221
|
const gap = resolvedLayout.gap ?? 8;
|
|
3214
5222
|
const alignItems = resolvedLayout.compact ? "center" : "start";
|
|
3215
|
-
return /* @__PURE__ */
|
|
5223
|
+
return /* @__PURE__ */ jsxs27(
|
|
3216
5224
|
"div",
|
|
3217
5225
|
{
|
|
3218
5226
|
"data-fid": fid,
|
|
@@ -3224,9 +5232,9 @@ function HorizontalArrayItemTemplate({
|
|
|
3224
5232
|
},
|
|
3225
5233
|
children: [
|
|
3226
5234
|
children,
|
|
3227
|
-
orderable && /* @__PURE__ */
|
|
3228
|
-
/* @__PURE__ */
|
|
3229
|
-
|
|
5235
|
+
orderable && /* @__PURE__ */ jsxs27("div", { className: "flex flex-col items-center justify-center", children: [
|
|
5236
|
+
/* @__PURE__ */ jsx42(
|
|
5237
|
+
Button10,
|
|
3230
5238
|
{
|
|
3231
5239
|
type: "button",
|
|
3232
5240
|
variant: "ghost",
|
|
@@ -3235,11 +5243,11 @@ function HorizontalArrayItemTemplate({
|
|
|
3235
5243
|
onClick: onMoveUp,
|
|
3236
5244
|
title: "Move up",
|
|
3237
5245
|
className: "h-4 w-8 p-0",
|
|
3238
|
-
children: /* @__PURE__ */
|
|
5246
|
+
children: /* @__PURE__ */ jsx42(ChevronUp2, { className: "h-3 w-3" })
|
|
3239
5247
|
}
|
|
3240
5248
|
),
|
|
3241
|
-
/* @__PURE__ */
|
|
3242
|
-
|
|
5249
|
+
/* @__PURE__ */ jsx42(
|
|
5250
|
+
Button10,
|
|
3243
5251
|
{
|
|
3244
5252
|
type: "button",
|
|
3245
5253
|
variant: "ghost",
|
|
@@ -3248,12 +5256,12 @@ function HorizontalArrayItemTemplate({
|
|
|
3248
5256
|
onClick: onMoveDown,
|
|
3249
5257
|
title: "Move down",
|
|
3250
5258
|
className: "h-4 w-8 p-0",
|
|
3251
|
-
children: /* @__PURE__ */
|
|
5259
|
+
children: /* @__PURE__ */ jsx42(ChevronDown4, { className: "h-3 w-3" })
|
|
3252
5260
|
}
|
|
3253
5261
|
)
|
|
3254
5262
|
] }),
|
|
3255
|
-
canRemove && /* @__PURE__ */
|
|
3256
|
-
|
|
5263
|
+
canRemove && /* @__PURE__ */ jsx42(
|
|
5264
|
+
Button10,
|
|
3257
5265
|
{
|
|
3258
5266
|
type: "button",
|
|
3259
5267
|
variant: "ghost",
|
|
@@ -3262,7 +5270,7 @@ function HorizontalArrayItemTemplate({
|
|
|
3262
5270
|
onClick: onRemove,
|
|
3263
5271
|
title: "Remove item",
|
|
3264
5272
|
className: "text-muted-foreground hover:text-destructive h-8 w-8 p-0",
|
|
3265
|
-
children: /* @__PURE__ */
|
|
5273
|
+
children: /* @__PURE__ */ jsx42(Trash22, { className: "h-3.5 w-3.5" })
|
|
3266
5274
|
}
|
|
3267
5275
|
)
|
|
3268
5276
|
]
|
|
@@ -3271,49 +5279,49 @@ function HorizontalArrayItemTemplate({
|
|
|
3271
5279
|
}
|
|
3272
5280
|
|
|
3273
5281
|
// src/templates/TabsGroupTemplate.tsx
|
|
3274
|
-
import { useState as
|
|
5282
|
+
import { useState as useState14 } from "react";
|
|
3275
5283
|
import { Tabs, TabsList, TabsTrigger, TabsContent } from "@petrarca/sonnet-ui";
|
|
3276
5284
|
|
|
3277
5285
|
// src/templates/GroupErrorBadge.tsx
|
|
3278
5286
|
import { AlertCircle } from "lucide-react";
|
|
3279
|
-
import { jsx as
|
|
5287
|
+
import { jsx as jsx43 } from "react/jsx-runtime";
|
|
3280
5288
|
function GroupErrorBadge({
|
|
3281
5289
|
count
|
|
3282
5290
|
}) {
|
|
3283
5291
|
if (count === 0) return null;
|
|
3284
5292
|
const label = count === 1 ? "1 field needs attention" : `${count} fields need attention`;
|
|
3285
|
-
return /* @__PURE__ */
|
|
5293
|
+
return /* @__PURE__ */ jsx43(
|
|
3286
5294
|
"span",
|
|
3287
5295
|
{
|
|
3288
5296
|
role: "img",
|
|
3289
5297
|
"aria-label": label,
|
|
3290
5298
|
title: label,
|
|
3291
5299
|
className: "inline-flex shrink-0 text-destructive",
|
|
3292
|
-
children: /* @__PURE__ */
|
|
5300
|
+
children: /* @__PURE__ */ jsx43(AlertCircle, { className: "h-3.5 w-3.5" })
|
|
3293
5301
|
}
|
|
3294
5302
|
);
|
|
3295
5303
|
}
|
|
3296
5304
|
|
|
3297
5305
|
// src/templates/TabsGroupTemplate.tsx
|
|
3298
|
-
import { jsx as
|
|
5306
|
+
import { jsx as jsx44, jsxs as jsxs28 } from "react/jsx-runtime";
|
|
3299
5307
|
function TabsGroupTemplate({
|
|
3300
5308
|
groups
|
|
3301
5309
|
}) {
|
|
3302
|
-
const [active, setActive] =
|
|
5310
|
+
const [active, setActive] = useState14(groups[0].key);
|
|
3303
5311
|
const value = groups.some((g) => g.key === active) ? active : groups[0].key;
|
|
3304
|
-
return /* @__PURE__ */
|
|
3305
|
-
/* @__PURE__ */
|
|
5312
|
+
return /* @__PURE__ */ jsxs28(Tabs, { value, onValueChange: setActive, children: [
|
|
5313
|
+
/* @__PURE__ */ jsx44(TabsList, { className: "mb-4", children: groups.map((g) => /* @__PURE__ */ jsxs28(TabsTrigger, { value: g.key, className: "gap-1.5", children: [
|
|
3306
5314
|
g.label,
|
|
3307
|
-
/* @__PURE__ */
|
|
5315
|
+
/* @__PURE__ */ jsx44(GroupErrorBadge, { count: g.errorCount })
|
|
3308
5316
|
] }, g.key)) }),
|
|
3309
|
-
groups.map((g) => /* @__PURE__ */
|
|
5317
|
+
groups.map((g) => /* @__PURE__ */ jsx44(TabsContent, { value: g.key, className: "space-y-4", children: g.content }, g.key))
|
|
3310
5318
|
] });
|
|
3311
5319
|
}
|
|
3312
5320
|
|
|
3313
5321
|
// src/templates/StepperGroupTemplate.tsx
|
|
3314
|
-
import { useState as
|
|
5322
|
+
import { useState as useState15 } from "react";
|
|
3315
5323
|
import {
|
|
3316
|
-
Button as
|
|
5324
|
+
Button as Button11,
|
|
3317
5325
|
Stepper,
|
|
3318
5326
|
StepperList,
|
|
3319
5327
|
StepperItem,
|
|
@@ -3325,47 +5333,47 @@ import {
|
|
|
3325
5333
|
StepperPrev,
|
|
3326
5334
|
StepperNext
|
|
3327
5335
|
} from "@petrarca/sonnet-ui";
|
|
3328
|
-
import { jsx as
|
|
5336
|
+
import { jsx as jsx45, jsxs as jsxs29 } from "react/jsx-runtime";
|
|
3329
5337
|
function StepperGroupTemplate({
|
|
3330
5338
|
groups
|
|
3331
5339
|
}) {
|
|
3332
|
-
const [active, setActive] =
|
|
5340
|
+
const [active, setActive] = useState15(groups[0].key);
|
|
3333
5341
|
const value = groups.some((g) => g.key === active) ? active : groups[0].key;
|
|
3334
5342
|
const isLast = value === groups[groups.length - 1].key;
|
|
3335
|
-
return /* @__PURE__ */
|
|
3336
|
-
/* @__PURE__ */
|
|
3337
|
-
/* @__PURE__ */
|
|
3338
|
-
/* @__PURE__ */
|
|
3339
|
-
/* @__PURE__ */
|
|
5343
|
+
return /* @__PURE__ */ jsxs29(Stepper, { value, onValueChange: setActive, children: [
|
|
5344
|
+
/* @__PURE__ */ jsx45(StepperList, { className: "mb-4 gap-2", children: groups.map((g) => /* @__PURE__ */ jsxs29(StepperItem, { value: g.key, children: [
|
|
5345
|
+
/* @__PURE__ */ jsxs29(StepperTrigger, { children: [
|
|
5346
|
+
/* @__PURE__ */ jsx45(StepperIndicator, {}),
|
|
5347
|
+
/* @__PURE__ */ jsxs29(StepperTitle, { className: "inline-flex items-center gap-1.5", children: [
|
|
3340
5348
|
g.label,
|
|
3341
|
-
/* @__PURE__ */
|
|
5349
|
+
/* @__PURE__ */ jsx45(GroupErrorBadge, { count: g.errorCount })
|
|
3342
5350
|
] })
|
|
3343
5351
|
] }),
|
|
3344
|
-
/* @__PURE__ */
|
|
5352
|
+
/* @__PURE__ */ jsx45(StepperSeparator, {})
|
|
3345
5353
|
] }, g.key)) }),
|
|
3346
|
-
groups.map((g) => /* @__PURE__ */
|
|
3347
|
-
/* @__PURE__ */
|
|
3348
|
-
/* @__PURE__ */
|
|
3349
|
-
!isLast && /* @__PURE__ */
|
|
5354
|
+
groups.map((g) => /* @__PURE__ */ jsx45(StepperContent, { value: g.key, className: "space-y-4", children: g.content }, g.key)),
|
|
5355
|
+
/* @__PURE__ */ jsxs29("div", { className: "mt-4 flex justify-between", children: [
|
|
5356
|
+
/* @__PURE__ */ jsx45(StepperPrev, { asChild: true, children: /* @__PURE__ */ jsx45(Button11, { variant: "outline", size: "sm", children: "Back" }) }),
|
|
5357
|
+
!isLast && /* @__PURE__ */ jsx45(StepperNext, { asChild: true, children: /* @__PURE__ */ jsx45(Button11, { size: "sm", children: "Next" }) })
|
|
3350
5358
|
] })
|
|
3351
5359
|
] });
|
|
3352
5360
|
}
|
|
3353
5361
|
|
|
3354
5362
|
// src/templates/SectionsGroupTemplate.tsx
|
|
3355
|
-
import { jsx as
|
|
5363
|
+
import { jsx as jsx46, jsxs as jsxs30 } from "react/jsx-runtime";
|
|
3356
5364
|
function SectionsGroupTemplate({
|
|
3357
5365
|
groups
|
|
3358
5366
|
}) {
|
|
3359
|
-
return /* @__PURE__ */
|
|
5367
|
+
return /* @__PURE__ */ jsx46("div", { className: "space-y-6", children: groups.map((g) => /* @__PURE__ */ jsxs30(
|
|
3360
5368
|
"fieldset",
|
|
3361
5369
|
{
|
|
3362
5370
|
className: "rounded-md border border-border/60 px-3 pb-3 pt-1",
|
|
3363
5371
|
children: [
|
|
3364
|
-
/* @__PURE__ */
|
|
5372
|
+
/* @__PURE__ */ jsxs30("legend", { className: "inline-flex items-center gap-1.5 px-1 text-sm font-medium text-muted-foreground", children: [
|
|
3365
5373
|
g.label,
|
|
3366
|
-
/* @__PURE__ */
|
|
5374
|
+
/* @__PURE__ */ jsx46(GroupErrorBadge, { count: g.errorCount })
|
|
3367
5375
|
] }),
|
|
3368
|
-
/* @__PURE__ */
|
|
5376
|
+
/* @__PURE__ */ jsx46("div", { className: "space-y-4", children: g.content })
|
|
3369
5377
|
]
|
|
3370
5378
|
},
|
|
3371
5379
|
g.key
|
|
@@ -3389,13 +5397,15 @@ function groupTemplateKey(variant) {
|
|
|
3389
5397
|
}
|
|
3390
5398
|
|
|
3391
5399
|
// src/FormFieldRenderer.tsx
|
|
5400
|
+
import { useMemo as useMemo9 } from "react";
|
|
3392
5401
|
import { warnLog } from "@petrarca/sonnet-core";
|
|
3393
5402
|
import {
|
|
3394
5403
|
getFieldTitle,
|
|
3395
5404
|
getFieldHelpText,
|
|
3396
|
-
getFieldPlaceholder
|
|
5405
|
+
getFieldPlaceholder,
|
|
5406
|
+
liftNullableMember
|
|
3397
5407
|
} from "@petrarca/sonnet-core/schema";
|
|
3398
|
-
import { jsx as
|
|
5408
|
+
import { jsx as jsx47 } from "react/jsx-runtime";
|
|
3399
5409
|
function mergeFieldOptions(globalOptions, property, uiSchema) {
|
|
3400
5410
|
const xWidgetOptions = property["x-ui-options"] || {};
|
|
3401
5411
|
const fieldOptions = uiSchema?.["x-ui-options"] || {};
|
|
@@ -3422,7 +5432,7 @@ function applyFieldWidth(widget, uiSchema, mergedOptions) {
|
|
|
3422
5432
|
}
|
|
3423
5433
|
const width = candidate && candidate in FIELD_WIDTH_CLASS ? candidate : "full";
|
|
3424
5434
|
if (width === "full") return widget;
|
|
3425
|
-
return /* @__PURE__ */
|
|
5435
|
+
return /* @__PURE__ */ jsx47("div", { className: FIELD_WIDTH_CLASS[width], children: widget });
|
|
3426
5436
|
}
|
|
3427
5437
|
function resolvePresentationText(property, uiSchema) {
|
|
3428
5438
|
return {
|
|
@@ -3438,7 +5448,7 @@ function resolveFieldFlags(fieldOptions, globalOptions, disabled, readOnly) {
|
|
|
3438
5448
|
}
|
|
3439
5449
|
function FormFieldRenderer({
|
|
3440
5450
|
fieldName,
|
|
3441
|
-
property,
|
|
5451
|
+
property: declared,
|
|
3442
5452
|
value,
|
|
3443
5453
|
onChange,
|
|
3444
5454
|
onBlur,
|
|
@@ -3453,6 +5463,7 @@ function FormFieldRenderer({
|
|
|
3453
5463
|
idPrefix = "field",
|
|
3454
5464
|
rawErrors
|
|
3455
5465
|
}) {
|
|
5466
|
+
const property = useMemo9(() => liftNullableMember(declared), [declared]);
|
|
3456
5467
|
const label = getFieldTitle(fieldName, property);
|
|
3457
5468
|
const { description, placeholder } = resolvePresentationText(
|
|
3458
5469
|
property,
|
|
@@ -3473,7 +5484,7 @@ function FormFieldRenderer({
|
|
|
3473
5484
|
uiSchema?.["x-ui-title"],
|
|
3474
5485
|
globalOptions.label
|
|
3475
5486
|
);
|
|
3476
|
-
const widget = /* @__PURE__ */
|
|
5487
|
+
const widget = /* @__PURE__ */ jsx47(
|
|
3477
5488
|
Widget,
|
|
3478
5489
|
{
|
|
3479
5490
|
id: `${idPrefix}-${fieldName}`,
|
|
@@ -3500,15 +5511,17 @@ function FormFieldRenderer({
|
|
|
3500
5511
|
}
|
|
3501
5512
|
|
|
3502
5513
|
// src/hooks/useFormEngine.ts
|
|
3503
|
-
import { useState as
|
|
5514
|
+
import { useState as useState17, useEffect as useEffect8, useMemo as useMemo11, useCallback as useCallback8, useRef as useRef8 } from "react";
|
|
3504
5515
|
import { isEqual } from "@petrarca/sonnet-core";
|
|
3505
5516
|
import {
|
|
5517
|
+
isNullableBoolean as isNullableBoolean3,
|
|
3506
5518
|
getSchemaProperties as getSchemaProperties4,
|
|
3507
5519
|
getFieldDefault,
|
|
3508
5520
|
applySchemaDefaults as applySchemaDefaults2,
|
|
3509
5521
|
resolveSchema,
|
|
3510
5522
|
resolveRefs,
|
|
3511
5523
|
validateFormData,
|
|
5524
|
+
stripFormItemIds,
|
|
3512
5525
|
mergeFieldErrors,
|
|
3513
5526
|
diffFormData,
|
|
3514
5527
|
ensureFormItemIds
|
|
@@ -3601,7 +5614,7 @@ function runValidators(schema, data, registry, uiSchema, includeFormValidators)
|
|
|
3601
5614
|
}
|
|
3602
5615
|
|
|
3603
5616
|
// src/validators/useAsyncValidators.ts
|
|
3604
|
-
import { useEffect as
|
|
5617
|
+
import { useEffect as useEffect7, useMemo as useMemo10, useRef as useRef7, useState as useState16 } from "react";
|
|
3605
5618
|
import { getSchemaProperties as getSchemaProperties3 } from "@petrarca/sonnet-core/schema";
|
|
3606
5619
|
function keyOf(value) {
|
|
3607
5620
|
try {
|
|
@@ -3657,12 +5670,12 @@ function collectCandidates(schema, data, registry, uiSchema, isRoot) {
|
|
|
3657
5670
|
return out;
|
|
3658
5671
|
}
|
|
3659
5672
|
function useAsyncValidators(schema, data, registry, uiSchema, isRoot) {
|
|
3660
|
-
const [entries, setEntries] =
|
|
3661
|
-
const handledKey =
|
|
5673
|
+
const [entries, setEntries] = useState16({});
|
|
5674
|
+
const handledKey = useRef7({});
|
|
3662
5675
|
const candidates = registry && (registry.asyncField || registry.asyncForm) ? collectCandidates(schema, data, registry, uiSchema, isRoot) : [];
|
|
3663
5676
|
const liveIds = new Set(candidates.map((c) => c.id));
|
|
3664
5677
|
const signature = candidates.map((c) => `${c.id}=${c.key}`).join(";");
|
|
3665
|
-
|
|
5678
|
+
useEffect7(() => {
|
|
3666
5679
|
for (const c of candidates) {
|
|
3667
5680
|
if (handledKey.current[c.id] === c.key) continue;
|
|
3668
5681
|
handledKey.current[c.id] = c.key;
|
|
@@ -3681,7 +5694,7 @@ function useAsyncValidators(schema, data, registry, uiSchema, isRoot) {
|
|
|
3681
5694
|
}
|
|
3682
5695
|
}, [signature]);
|
|
3683
5696
|
const liveKey = [...liveIds].sort().join(",");
|
|
3684
|
-
|
|
5697
|
+
useEffect7(() => {
|
|
3685
5698
|
setEntries((e) => {
|
|
3686
5699
|
const kept = Object.entries(e).filter(([id]) => liveIds.has(id));
|
|
3687
5700
|
return kept.length === Object.keys(e).length ? e : Object.fromEntries(kept);
|
|
@@ -3701,7 +5714,7 @@ function useAsyncValidators(schema, data, registry, uiSchema, isRoot) {
|
|
|
3701
5714
|
errorList.push(...entry.errors);
|
|
3702
5715
|
}
|
|
3703
5716
|
const errorSig = errorList.map((e) => `${e.pointer}\0${e.message}`).join("|");
|
|
3704
|
-
const asyncErrors =
|
|
5717
|
+
const asyncErrors = useMemo10(() => errorList, [errorSig]);
|
|
3705
5718
|
return { asyncErrors, isValidating };
|
|
3706
5719
|
}
|
|
3707
5720
|
|
|
@@ -3721,9 +5734,14 @@ function orderProperties(properties, orderArray) {
|
|
|
3721
5734
|
}
|
|
3722
5735
|
|
|
3723
5736
|
// src/hooks/useFormEngine.ts
|
|
5737
|
+
var COMMITTED_FORMATS = /* @__PURE__ */ new Set(["date", "time", "date-time"]);
|
|
5738
|
+
function isCommittedFormat(property) {
|
|
5739
|
+
return property.format !== void 0 && COMMITTED_FORMATS.has(property.format);
|
|
5740
|
+
}
|
|
3724
5741
|
function isImmediateField(fieldName, properties) {
|
|
3725
5742
|
const property = properties[fieldName];
|
|
3726
|
-
|
|
5743
|
+
if (!property) return false;
|
|
5744
|
+
return property.type === "boolean" || isNullableBoolean3(property) || isCommittedFormat(property) || property.enum !== void 0 || property.items?.enum !== void 0 || property["x-ui-options"]?.immediate === true;
|
|
3727
5745
|
}
|
|
3728
5746
|
function computeBaselineUpdate(newData, originalData, initialized, schemaPropertyNames) {
|
|
3729
5747
|
const newCount = Object.keys(newData).length;
|
|
@@ -3750,7 +5768,7 @@ function computeBaselineUpdate(newData, originalData, initialized, schemaPropert
|
|
|
3750
5768
|
}
|
|
3751
5769
|
function computeAllErrors(args) {
|
|
3752
5770
|
const { schema, data, customSync, asyncErrors, extraErrors } = args;
|
|
3753
|
-
const base = validateFormData(schema, data).fieldErrors;
|
|
5771
|
+
const base = validateFormData(schema, stripFormItemIds(data)).fieldErrors;
|
|
3754
5772
|
return mergeFieldErrors(base, customSync, asyncErrors, extraErrors ?? []);
|
|
3755
5773
|
}
|
|
3756
5774
|
function useFormEngine({
|
|
@@ -3772,21 +5790,21 @@ function useFormEngine({
|
|
|
3772
5790
|
validators,
|
|
3773
5791
|
isRoot = true
|
|
3774
5792
|
}) {
|
|
3775
|
-
const refResolvedSchema =
|
|
5793
|
+
const refResolvedSchema = useMemo11(
|
|
3776
5794
|
() => resolveRefs(schema, refResolver),
|
|
3777
5795
|
[schema, refResolver]
|
|
3778
5796
|
);
|
|
3779
|
-
const seed =
|
|
5797
|
+
const seed = useState17(
|
|
3780
5798
|
() => ensureFormItemIds(
|
|
3781
5799
|
applySchemaDefaults2(data, refResolvedSchema),
|
|
3782
5800
|
refResolvedSchema
|
|
3783
5801
|
)
|
|
3784
5802
|
)[0];
|
|
3785
|
-
const [originalData, setOriginalData] =
|
|
5803
|
+
const [originalData, setOriginalData] = useState17(
|
|
3786
5804
|
() => seed
|
|
3787
5805
|
);
|
|
3788
|
-
const [originalDataInitialized, setOriginalDataInitialized] =
|
|
3789
|
-
const [nonSchemaData, setNonSchemaData] =
|
|
5806
|
+
const [originalDataInitialized, setOriginalDataInitialized] = useState17(false);
|
|
5807
|
+
const [nonSchemaData, setNonSchemaData] = useState17(
|
|
3790
5808
|
() => {
|
|
3791
5809
|
const props = getSchemaProperties4(refResolvedSchema);
|
|
3792
5810
|
const names = Object.keys(props);
|
|
@@ -3795,26 +5813,26 @@ function useFormEngine({
|
|
|
3795
5813
|
);
|
|
3796
5814
|
}
|
|
3797
5815
|
);
|
|
3798
|
-
const [formData, setFormData] =
|
|
3799
|
-
const formDataRef =
|
|
5816
|
+
const [formData, setFormData] = useState17(() => seed);
|
|
5817
|
+
const formDataRef = useRef8(formData);
|
|
3800
5818
|
formDataRef.current = formData;
|
|
3801
|
-
const [pendingChanges, setPendingChanges] =
|
|
3802
|
-
const resolvedSchema =
|
|
5819
|
+
const [pendingChanges, setPendingChanges] = useState17({});
|
|
5820
|
+
const resolvedSchema = useMemo11(
|
|
3803
5821
|
() => resolveSchema(refResolvedSchema, formData),
|
|
3804
5822
|
[refResolvedSchema, formData]
|
|
3805
5823
|
);
|
|
3806
|
-
const orderedProperties =
|
|
5824
|
+
const orderedProperties = useMemo11(() => {
|
|
3807
5825
|
const properties2 = getSchemaProperties4(resolvedSchema);
|
|
3808
5826
|
const rawOrder = uiSchema["x-ui-order"] ?? resolvedSchema["x-ui-order"];
|
|
3809
5827
|
const orderArray = Array.isArray(rawOrder) ? rawOrder : void 0;
|
|
3810
5828
|
return orderProperties(properties2, orderArray);
|
|
3811
5829
|
}, [resolvedSchema, uiSchema]);
|
|
3812
|
-
const [initialDefaultsSent, setInitialDefaultsSent] =
|
|
3813
|
-
const
|
|
3814
|
-
const [touched, setTouched] =
|
|
3815
|
-
const [submitAttempted, setSubmitAttempted] =
|
|
5830
|
+
const [initialDefaultsSent, setInitialDefaultsSent] = useState17(false);
|
|
5831
|
+
const edited = useRef8(/* @__PURE__ */ new Set());
|
|
5832
|
+
const [touched, setTouched] = useState17({});
|
|
5833
|
+
const [submitAttempted, setSubmitAttempted] = useState17(false);
|
|
3816
5834
|
const properties = getSchemaProperties4(resolvedSchema);
|
|
3817
|
-
|
|
5835
|
+
useEffect8(() => {
|
|
3818
5836
|
if (!initialDefaultsSent) {
|
|
3819
5837
|
const hasDefaults = Object.entries(properties).some(
|
|
3820
5838
|
([fieldName, property]) => data[fieldName] === void 0 && getFieldDefault(property) !== void 0
|
|
@@ -3825,7 +5843,7 @@ function useFormEngine({
|
|
|
3825
5843
|
setInitialDefaultsSent(true);
|
|
3826
5844
|
}
|
|
3827
5845
|
}, [initialDefaultsSent, properties, data, formData, onChange]);
|
|
3828
|
-
|
|
5846
|
+
useEffect8(() => {
|
|
3829
5847
|
const currentPropertyNames = Object.keys(properties);
|
|
3830
5848
|
const keysToRemove = Object.keys(formData).filter(
|
|
3831
5849
|
(k) => !currentPropertyNames.includes(k)
|
|
@@ -3839,8 +5857,23 @@ function useFormEngine({
|
|
|
3839
5857
|
if (onChange) onChange(cleanedData);
|
|
3840
5858
|
}
|
|
3841
5859
|
}, [properties, formData, onChange]);
|
|
3842
|
-
const
|
|
3843
|
-
|
|
5860
|
+
const shownFields = useRef8(
|
|
5861
|
+
new Set(Object.keys(getSchemaProperties4(refResolvedSchema)))
|
|
5862
|
+
);
|
|
5863
|
+
useEffect8(() => {
|
|
5864
|
+
const names = Object.keys(properties);
|
|
5865
|
+
const appeared = names.filter((n) => !shownFields.current.has(n));
|
|
5866
|
+
shownFields.current = new Set(names);
|
|
5867
|
+
if (appeared.length === 0) return;
|
|
5868
|
+
const filled = applySchemaDefaults2(formData, {
|
|
5869
|
+
properties: Object.fromEntries(appeared.map((n) => [n, properties[n]]))
|
|
5870
|
+
});
|
|
5871
|
+
if (isEqual(filled, formData)) return;
|
|
5872
|
+
setFormData(filled);
|
|
5873
|
+
if (onChange) onChange(filled);
|
|
5874
|
+
}, [properties, formData, onChange]);
|
|
5875
|
+
const prevDataRef = useRef8(data);
|
|
5876
|
+
useEffect8(() => {
|
|
3844
5877
|
if (isEqual(prevDataRef.current, data)) return;
|
|
3845
5878
|
prevDataRef.current = data;
|
|
3846
5879
|
const newData = ensureFormItemIds(
|
|
@@ -3870,17 +5903,17 @@ function useFormEngine({
|
|
|
3870
5903
|
originalData,
|
|
3871
5904
|
originalDataInitialized
|
|
3872
5905
|
]);
|
|
3873
|
-
const hasChanges =
|
|
5906
|
+
const hasChanges = useMemo11(
|
|
3874
5907
|
() => !isEqual(formData, originalData),
|
|
3875
5908
|
[formData, originalData]
|
|
3876
5909
|
);
|
|
3877
|
-
const displayData =
|
|
5910
|
+
const displayData = useMemo11(() => {
|
|
3878
5911
|
if (deferStateUpdates && Object.keys(pendingChanges).length > 0) {
|
|
3879
5912
|
return { ...formData, ...pendingChanges };
|
|
3880
5913
|
}
|
|
3881
5914
|
return formData;
|
|
3882
5915
|
}, [formData, pendingChanges, deferStateUpdates]);
|
|
3883
|
-
const customSync =
|
|
5916
|
+
const customSync = useMemo11(
|
|
3884
5917
|
() => runValidators(resolvedSchema, displayData, validators, uiSchema, isRoot),
|
|
3885
5918
|
[resolvedSchema, displayData, validators, uiSchema, isRoot]
|
|
3886
5919
|
);
|
|
@@ -3891,7 +5924,7 @@ function useFormEngine({
|
|
|
3891
5924
|
uiSchema,
|
|
3892
5925
|
isRoot
|
|
3893
5926
|
);
|
|
3894
|
-
const validation =
|
|
5927
|
+
const validation = useMemo11(() => {
|
|
3895
5928
|
const merged = computeAllErrors({
|
|
3896
5929
|
schema: resolvedSchema,
|
|
3897
5930
|
data: displayData,
|
|
@@ -3906,17 +5939,15 @@ function useFormEngine({
|
|
|
3906
5939
|
};
|
|
3907
5940
|
}, [resolvedSchema, displayData, customSync, asyncErrors, extraErrors]);
|
|
3908
5941
|
const { isValid, fieldErrors } = validation;
|
|
3909
|
-
const onValidationChangeRef =
|
|
5942
|
+
const onValidationChangeRef = useRef8(onValidationChange);
|
|
3910
5943
|
onValidationChangeRef.current = onValidationChange;
|
|
3911
|
-
|
|
5944
|
+
useEffect8(() => {
|
|
3912
5945
|
onValidationChangeRef.current?.(validation.errors, validation.isValid);
|
|
3913
5946
|
}, [validation]);
|
|
3914
|
-
const handleFieldChange =
|
|
5947
|
+
const handleFieldChange = useCallback8(
|
|
3915
5948
|
(fieldName, value) => {
|
|
3916
5949
|
if (readOnly) return;
|
|
3917
|
-
|
|
3918
|
-
(prev) => prev[fieldName] ? prev : { ...prev, [fieldName]: true }
|
|
3919
|
-
);
|
|
5950
|
+
edited.current.add(fieldName);
|
|
3920
5951
|
const immediate = isImmediateField(fieldName, properties);
|
|
3921
5952
|
if (deferStateUpdates && !immediate) {
|
|
3922
5953
|
setPendingChanges((prev) => ({ ...prev, [fieldName]: value }));
|
|
@@ -3939,7 +5970,7 @@ function useFormEngine({
|
|
|
3939
5970
|
properties
|
|
3940
5971
|
]
|
|
3941
5972
|
);
|
|
3942
|
-
const flushPendingField =
|
|
5973
|
+
const flushPendingField = useCallback8(
|
|
3943
5974
|
(fieldName) => {
|
|
3944
5975
|
if (!deferStateUpdates) return;
|
|
3945
5976
|
if (pendingChanges[fieldName] === void 0) return;
|
|
@@ -3954,10 +5985,10 @@ function useFormEngine({
|
|
|
3954
5985
|
},
|
|
3955
5986
|
[showActions, deferStateUpdates, pendingChanges, formData, onChange]
|
|
3956
5987
|
);
|
|
3957
|
-
const handleFieldBlur =
|
|
5988
|
+
const handleFieldBlur = useCallback8(
|
|
3958
5989
|
(fieldName) => {
|
|
3959
5990
|
if (readOnly) return;
|
|
3960
|
-
if (edited
|
|
5991
|
+
if (edited.current.has(fieldName)) {
|
|
3961
5992
|
setTouched(
|
|
3962
5993
|
(prev) => prev[fieldName] ? prev : { ...prev, [fieldName]: true }
|
|
3963
5994
|
);
|
|
@@ -3975,7 +6006,6 @@ function useFormEngine({
|
|
|
3975
6006
|
},
|
|
3976
6007
|
[
|
|
3977
6008
|
readOnly,
|
|
3978
|
-
edited,
|
|
3979
6009
|
pendingChanges,
|
|
3980
6010
|
deferChanges,
|
|
3981
6011
|
deferStateUpdates,
|
|
@@ -3985,7 +6015,7 @@ function useFormEngine({
|
|
|
3985
6015
|
flushPendingField
|
|
3986
6016
|
]
|
|
3987
6017
|
);
|
|
3988
|
-
const handleSave =
|
|
6018
|
+
const handleSave = useCallback8(() => {
|
|
3989
6019
|
setSubmitAttempted(true);
|
|
3990
6020
|
if (!hasChanges && !allowPristineSave) return;
|
|
3991
6021
|
if (isValidating) return;
|
|
@@ -4032,10 +6062,10 @@ function useFormEngine({
|
|
|
4032
6062
|
validators,
|
|
4033
6063
|
isRoot
|
|
4034
6064
|
]);
|
|
4035
|
-
const handleCancel =
|
|
6065
|
+
const handleCancel = useCallback8(() => {
|
|
4036
6066
|
setFormData({ ...originalData });
|
|
4037
6067
|
setPendingChanges({});
|
|
4038
|
-
|
|
6068
|
+
edited.current = /* @__PURE__ */ new Set();
|
|
4039
6069
|
setTouched({});
|
|
4040
6070
|
setSubmitAttempted(false);
|
|
4041
6071
|
onCancel?.();
|
|
@@ -4063,30 +6093,7 @@ import {
|
|
|
4063
6093
|
useValidationDisplay,
|
|
4064
6094
|
useSaveWhenInvalid
|
|
4065
6095
|
} from "@petrarca/sonnet-core/config";
|
|
4066
|
-
import { jsx as
|
|
4067
|
-
function stripFids(data) {
|
|
4068
|
-
const result = {};
|
|
4069
|
-
for (const [key, value] of Object.entries(data)) {
|
|
4070
|
-
if (Array.isArray(value)) {
|
|
4071
|
-
result[key] = value.map((item) => {
|
|
4072
|
-
if (item !== null && typeof item === "object" && !Array.isArray(item)) {
|
|
4073
|
-
const rest = Object.fromEntries(
|
|
4074
|
-
Object.entries(item).filter(
|
|
4075
|
-
([k]) => k !== FORM_ITEM_ID_FIELD2
|
|
4076
|
-
)
|
|
4077
|
-
);
|
|
4078
|
-
return stripFids(rest);
|
|
4079
|
-
}
|
|
4080
|
-
return item;
|
|
4081
|
-
});
|
|
4082
|
-
} else if (value !== null && typeof value === "object") {
|
|
4083
|
-
result[key] = stripFids(value);
|
|
4084
|
-
} else {
|
|
4085
|
-
result[key] = value;
|
|
4086
|
-
}
|
|
4087
|
-
}
|
|
4088
|
-
return result;
|
|
4089
|
-
}
|
|
6096
|
+
import { jsx as jsx48, jsxs as jsxs31 } from "react/jsx-runtime";
|
|
4090
6097
|
function resolveFlagDefaults(props) {
|
|
4091
6098
|
return {
|
|
4092
6099
|
disabled: props.disabled ?? false,
|
|
@@ -4108,18 +6115,20 @@ function resolveValueDefaults(props) {
|
|
|
4108
6115
|
uiSchema: props.uiSchema ?? {}
|
|
4109
6116
|
};
|
|
4110
6117
|
}
|
|
4111
|
-
|
|
4112
|
-
|
|
4113
|
-
|
|
4114
|
-
|
|
6118
|
+
var keepFids = (data) => data;
|
|
6119
|
+
function useWrappedCallbacks(onChange, onBlur, onUpdate, isRootForm) {
|
|
6120
|
+
const strip = isRootForm ? stripFormItemIds2 : keepFids;
|
|
6121
|
+
const wrappedOnChange = useCallback9(
|
|
6122
|
+
(d) => onChange?.(strip(d)),
|
|
6123
|
+
[onChange, strip]
|
|
4115
6124
|
);
|
|
4116
|
-
const wrappedOnBlur =
|
|
4117
|
-
(fieldName, d) => onBlur?.(fieldName,
|
|
4118
|
-
[onBlur]
|
|
6125
|
+
const wrappedOnBlur = useCallback9(
|
|
6126
|
+
(fieldName, d) => onBlur?.(fieldName, strip(d)),
|
|
6127
|
+
[onBlur, strip]
|
|
4119
6128
|
);
|
|
4120
|
-
const wrappedOnUpdate =
|
|
4121
|
-
(d, changed, diff) => onUpdate?.(
|
|
4122
|
-
[onUpdate]
|
|
6129
|
+
const wrappedOnUpdate = useCallback9(
|
|
6130
|
+
(d, changed, diff) => onUpdate?.(strip(d), strip(changed), diff),
|
|
6131
|
+
[onUpdate, strip]
|
|
4123
6132
|
);
|
|
4124
6133
|
return {
|
|
4125
6134
|
wrappedOnChange: onChange ? wrappedOnChange : void 0,
|
|
@@ -4130,7 +6139,7 @@ function useWrappedCallbacks(onChange, onBlur, onUpdate) {
|
|
|
4130
6139
|
function buildFieldMap(fields) {
|
|
4131
6140
|
const map = /* @__PURE__ */ new Map();
|
|
4132
6141
|
for (const field of fields) {
|
|
4133
|
-
if (
|
|
6142
|
+
if (React18.isValidElement(field) && field.key != null) {
|
|
4134
6143
|
map.set(String(field.key), field);
|
|
4135
6144
|
}
|
|
4136
6145
|
}
|
|
@@ -4149,12 +6158,12 @@ function resolveGridColumns(row, fieldCount) {
|
|
|
4149
6158
|
}
|
|
4150
6159
|
function wrapInGroup(group, key, content) {
|
|
4151
6160
|
if (!group) return content;
|
|
4152
|
-
return /* @__PURE__ */
|
|
6161
|
+
return /* @__PURE__ */ jsxs31(
|
|
4153
6162
|
"fieldset",
|
|
4154
6163
|
{
|
|
4155
6164
|
className: "rounded-md border border-border/60 px-3 pb-3 pt-1",
|
|
4156
6165
|
children: [
|
|
4157
|
-
/* @__PURE__ */
|
|
6166
|
+
/* @__PURE__ */ jsx48("legend", { className: "px-1 text-sm font-medium text-muted-foreground", children: group }),
|
|
4158
6167
|
content
|
|
4159
6168
|
]
|
|
4160
6169
|
},
|
|
@@ -4176,7 +6185,7 @@ function buildRowElement(row, fieldMap, defaultRowGap) {
|
|
|
4176
6185
|
gridTemplateColumns: resolveGridColumns(row, rowFields.length),
|
|
4177
6186
|
gap: `${rowGap}px`
|
|
4178
6187
|
};
|
|
4179
|
-
const inner = /* @__PURE__ */
|
|
6188
|
+
const inner = /* @__PURE__ */ jsx48("div", { style, children: rowFields }, `row:${rowKey}`);
|
|
4180
6189
|
return {
|
|
4181
6190
|
element: wrapInGroup(row.group, rowKey, inner),
|
|
4182
6191
|
placed: row.fields
|
|
@@ -4185,7 +6194,7 @@ function buildRowElement(row, fieldMap, defaultRowGap) {
|
|
|
4185
6194
|
function collectUnplacedFields(fields, placed) {
|
|
4186
6195
|
const result = [];
|
|
4187
6196
|
for (const field of fields) {
|
|
4188
|
-
if (
|
|
6197
|
+
if (React18.isValidElement(field) && field.key != null && !placed.has(String(field.key))) {
|
|
4189
6198
|
result.push(field);
|
|
4190
6199
|
}
|
|
4191
6200
|
}
|
|
@@ -4278,8 +6287,8 @@ function HiddenErrorNotice({
|
|
|
4278
6287
|
count
|
|
4279
6288
|
}) {
|
|
4280
6289
|
if (count === 0) return null;
|
|
4281
|
-
return /* @__PURE__ */
|
|
4282
|
-
/* @__PURE__ */
|
|
6290
|
+
return /* @__PURE__ */ jsxs31("p", { className: "flex items-center gap-1.5 text-sm text-destructive", children: [
|
|
6291
|
+
/* @__PURE__ */ jsx48(AlertCircle2, { className: "h-4 w-4 shrink-0" }),
|
|
4283
6292
|
count === 1 ? "1 required field is in a section that is not currently shown." : `${count} required fields are in sections that are not currently shown.`
|
|
4284
6293
|
] });
|
|
4285
6294
|
}
|
|
@@ -4287,13 +6296,13 @@ function FormLevelErrors({
|
|
|
4287
6296
|
messages
|
|
4288
6297
|
}) {
|
|
4289
6298
|
if (messages.length === 0) return null;
|
|
4290
|
-
return /* @__PURE__ */
|
|
6299
|
+
return /* @__PURE__ */ jsx48("div", { className: "space-y-1", children: messages.map((msg, i) => /* @__PURE__ */ jsxs31(
|
|
4291
6300
|
"p",
|
|
4292
6301
|
{
|
|
4293
6302
|
role: "alert",
|
|
4294
6303
|
className: "flex items-center gap-1.5 text-sm text-destructive",
|
|
4295
6304
|
children: [
|
|
4296
|
-
/* @__PURE__ */
|
|
6305
|
+
/* @__PURE__ */ jsx48(AlertCircle2, { className: "h-4 w-4 shrink-0" }),
|
|
4297
6306
|
msg
|
|
4298
6307
|
]
|
|
4299
6308
|
},
|
|
@@ -4318,7 +6327,7 @@ function layoutFieldsInGroups(fields, groupDefs, defaultRowGap, fieldErrors, for
|
|
|
4318
6327
|
content: b.rows,
|
|
4319
6328
|
errorCount: groupErrorCount(groupDefs[b.index], fieldErrors)
|
|
4320
6329
|
}));
|
|
4321
|
-
return [/* @__PURE__ */
|
|
6330
|
+
return [/* @__PURE__ */ jsx48(GroupTemplate, { groups }, "form:groups"), ...unplaced];
|
|
4322
6331
|
}
|
|
4323
6332
|
function FormContainer({
|
|
4324
6333
|
displayContents,
|
|
@@ -4342,14 +6351,14 @@ function FormContainer({
|
|
|
4342
6351
|
children
|
|
4343
6352
|
}) {
|
|
4344
6353
|
if (displayContents) {
|
|
4345
|
-
return /* @__PURE__ */
|
|
6354
|
+
return /* @__PURE__ */ jsx48("div", { style: { display: "contents" }, children });
|
|
4346
6355
|
}
|
|
4347
|
-
return /* @__PURE__ */
|
|
6356
|
+
return /* @__PURE__ */ jsxs31(SimpleStack, { gap: "md", children: [
|
|
4348
6357
|
children,
|
|
4349
|
-
showExtraProperties && /* @__PURE__ */
|
|
4350
|
-
/* @__PURE__ */
|
|
4351
|
-
/* @__PURE__ */
|
|
4352
|
-
showActions && /* @__PURE__ */
|
|
6358
|
+
showExtraProperties && /* @__PURE__ */ jsx48(ExtraPropertiesCard_default, { properties: formData, schema: resolvedSchema }),
|
|
6359
|
+
/* @__PURE__ */ jsx48(HiddenErrorNotice, { count: hiddenErrorCount }),
|
|
6360
|
+
/* @__PURE__ */ jsx48(FormLevelErrors, { messages: formLevelErrors }),
|
|
6361
|
+
showActions && /* @__PURE__ */ jsx48(
|
|
4353
6362
|
FormActions,
|
|
4354
6363
|
{
|
|
4355
6364
|
onSave: handleSave,
|
|
@@ -4395,7 +6404,7 @@ function JsonSchemaFormRenderer(props) {
|
|
|
4395
6404
|
allowPristineSave
|
|
4396
6405
|
} = resolveFlagDefaults(props);
|
|
4397
6406
|
const { saveLabel, cancelLabel, widgets, uiSchema } = resolveValueDefaults(props);
|
|
4398
|
-
const { wrappedOnChange, wrappedOnBlur, wrappedOnUpdate } = useWrappedCallbacks(onChange, onBlur, onUpdate);
|
|
6407
|
+
const { wrappedOnChange, wrappedOnBlur, wrappedOnUpdate } = useWrappedCallbacks(onChange, onBlur, onUpdate, isRootForm);
|
|
4399
6408
|
const {
|
|
4400
6409
|
formData,
|
|
4401
6410
|
displayData,
|
|
@@ -4431,19 +6440,19 @@ function JsonSchemaFormRenderer(props) {
|
|
|
4431
6440
|
isRoot: isRootForm
|
|
4432
6441
|
});
|
|
4433
6442
|
const layoutLabelPlacement = uiSchema["x-ui-layout"]?.labelPlacement;
|
|
4434
|
-
const globalOptions =
|
|
6443
|
+
const globalOptions = useMemo12(
|
|
4435
6444
|
() => ({
|
|
4436
6445
|
...layoutLabelPlacement ? { labelPlacement: layoutLabelPlacement } : {},
|
|
4437
6446
|
...uiSchema["x-ui-globalOptions"] || {}
|
|
4438
6447
|
}),
|
|
4439
6448
|
[layoutLabelPlacement, uiSchema]
|
|
4440
6449
|
);
|
|
4441
|
-
const resolvedTemplates =
|
|
6450
|
+
const resolvedTemplates = useMemo12(
|
|
4442
6451
|
() => ({ ...DEFAULT_TEMPLATES, ...templates }),
|
|
4443
6452
|
[templates]
|
|
4444
6453
|
);
|
|
4445
|
-
const nestedRenderer =
|
|
4446
|
-
(props2) => /* @__PURE__ */
|
|
6454
|
+
const nestedRenderer = useCallback9(
|
|
6455
|
+
(props2) => /* @__PURE__ */ jsx48(
|
|
4447
6456
|
JsonSchemaFormRenderer,
|
|
4448
6457
|
{
|
|
4449
6458
|
...props2,
|
|
@@ -4460,7 +6469,7 @@ function JsonSchemaFormRenderer(props) {
|
|
|
4460
6469
|
nestedFormContext,
|
|
4461
6470
|
submitAttempted
|
|
4462
6471
|
);
|
|
4463
|
-
const contextValue =
|
|
6472
|
+
const contextValue = useMemo12(
|
|
4464
6473
|
() => ({
|
|
4465
6474
|
renderer: nestedRenderer,
|
|
4466
6475
|
templates: resolvedTemplates,
|
|
@@ -4477,7 +6486,7 @@ function JsonSchemaFormRenderer(props) {
|
|
|
4477
6486
|
hasOnBlur: !!onBlur,
|
|
4478
6487
|
validationDisplay
|
|
4479
6488
|
});
|
|
4480
|
-
const showFieldErrors =
|
|
6489
|
+
const showFieldErrors = useCallback9(
|
|
4481
6490
|
(fieldName) => fieldErrorsVisible(
|
|
4482
6491
|
validationDisplay,
|
|
4483
6492
|
effectiveSubmitAttempted,
|
|
@@ -4485,13 +6494,13 @@ function JsonSchemaFormRenderer(props) {
|
|
|
4485
6494
|
),
|
|
4486
6495
|
[validationDisplay, effectiveSubmitAttempted, touched]
|
|
4487
6496
|
);
|
|
4488
|
-
const fields =
|
|
6497
|
+
const fields = useMemo12(
|
|
4489
6498
|
() => orderedProperties.flatMap(([fieldName, property]) => {
|
|
4490
6499
|
const rule = uiSchema[fieldName]?.["x-ui-rule"] ?? property["x-ui-rule"];
|
|
4491
6500
|
const { visible, enabled } = evaluateUiRule(rule, rootData);
|
|
4492
6501
|
if (!visible) return [];
|
|
4493
6502
|
return [
|
|
4494
|
-
/* @__PURE__ */
|
|
6503
|
+
/* @__PURE__ */ jsx48(
|
|
4495
6504
|
FormFieldRenderer,
|
|
4496
6505
|
{
|
|
4497
6506
|
fieldName,
|
|
@@ -4547,7 +6556,7 @@ function JsonSchemaFormRenderer(props) {
|
|
|
4547
6556
|
resolvedTemplates,
|
|
4548
6557
|
layoutConfig?.variant
|
|
4549
6558
|
);
|
|
4550
|
-
const layoutFields =
|
|
6559
|
+
const layoutFields = useMemo12(() => {
|
|
4551
6560
|
if (groupDefs && groupDefs.length > 0) {
|
|
4552
6561
|
return layoutFieldsInGroups(
|
|
4553
6562
|
fields,
|
|
@@ -4572,17 +6581,17 @@ function JsonSchemaFormRenderer(props) {
|
|
|
4572
6581
|
rootData,
|
|
4573
6582
|
groupTemplate
|
|
4574
6583
|
]);
|
|
4575
|
-
const hiddenErrorCount =
|
|
6584
|
+
const hiddenErrorCount = useMemo12(() => {
|
|
4576
6585
|
if (!groupDefs?.length || fieldErrors.length === 0) return 0;
|
|
4577
6586
|
const hidden = hiddenGroupFieldNames(groupDefs, rootData);
|
|
4578
6587
|
if (hidden.size === 0) return 0;
|
|
4579
6588
|
return fieldErrors.filter((e) => hidden.has(pointerRoot(e.pointer))).length;
|
|
4580
6589
|
}, [groupDefs, fieldErrors, rootData]);
|
|
4581
|
-
const formLevelErrors =
|
|
6590
|
+
const formLevelErrors = useMemo12(() => {
|
|
4582
6591
|
if (validationDisplay !== "always" && !submitAttempted) return [];
|
|
4583
6592
|
return fieldErrors.filter((e) => e.pointer === "").map((e) => e.message);
|
|
4584
6593
|
}, [fieldErrors, validationDisplay, submitAttempted]);
|
|
4585
|
-
return /* @__PURE__ */
|
|
6594
|
+
return /* @__PURE__ */ jsx48(NestedFormContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx48(
|
|
4586
6595
|
FormContainer,
|
|
4587
6596
|
{
|
|
4588
6597
|
displayContents,
|
|
@@ -4609,7 +6618,7 @@ function JsonSchemaFormRenderer(props) {
|
|
|
4609
6618
|
}
|
|
4610
6619
|
|
|
4611
6620
|
// src/hooks/useResolvedSchema.ts
|
|
4612
|
-
import { useMemo as
|
|
6621
|
+
import { useMemo as useMemo13 } from "react";
|
|
4613
6622
|
import {
|
|
4614
6623
|
getSchemaProperties as getSchemaProperties5,
|
|
4615
6624
|
resolveSchema as resolveSchema2
|
|
@@ -4619,11 +6628,11 @@ function useResolvedSchema({
|
|
|
4619
6628
|
formData,
|
|
4620
6629
|
uiSchema
|
|
4621
6630
|
}) {
|
|
4622
|
-
const resolvedSchema =
|
|
6631
|
+
const resolvedSchema = useMemo13(
|
|
4623
6632
|
() => resolveSchema2(schema, formData),
|
|
4624
6633
|
[schema, formData]
|
|
4625
6634
|
);
|
|
4626
|
-
const orderedProperties =
|
|
6635
|
+
const orderedProperties = useMemo13(() => {
|
|
4627
6636
|
const properties = getSchemaProperties5(resolvedSchema);
|
|
4628
6637
|
const rawOrder = uiSchema["x-ui-order"] ?? resolvedSchema["x-ui-order"];
|
|
4629
6638
|
const orderArray = Array.isArray(rawOrder) ? rawOrder : void 0;
|
|
@@ -4632,8 +6641,13 @@ function useResolvedSchema({
|
|
|
4632
6641
|
return { resolvedSchema, orderedProperties };
|
|
4633
6642
|
}
|
|
4634
6643
|
export {
|
|
6644
|
+
AbsentReasonsWidget,
|
|
4635
6645
|
ArrayWidget,
|
|
6646
|
+
CheckboxGroupWidget,
|
|
4636
6647
|
CheckboxWidget,
|
|
6648
|
+
ChoiceWithTextWidget,
|
|
6649
|
+
CodeableConceptWidget,
|
|
6650
|
+
CodedValueWidget,
|
|
4637
6651
|
DEFAULT_TEMPLATES,
|
|
4638
6652
|
DEFAULT_WIDGETS,
|
|
4639
6653
|
DEFAULT_WIDGET_MAP,
|
|
@@ -4647,6 +6661,7 @@ export {
|
|
|
4647
6661
|
FormFieldRenderer,
|
|
4648
6662
|
FormFieldWrapper,
|
|
4649
6663
|
FormInput,
|
|
6664
|
+
FormKeyValueInput,
|
|
4650
6665
|
FormMultiSelect,
|
|
4651
6666
|
FormNumberInput,
|
|
4652
6667
|
FormQuantityInput,
|
|
@@ -4656,10 +6671,12 @@ export {
|
|
|
4656
6671
|
GroupErrorBadge,
|
|
4657
6672
|
JsonEditorWidget,
|
|
4658
6673
|
JsonSchemaFormRenderer,
|
|
6674
|
+
KeyValueWidget,
|
|
4659
6675
|
NumberWidget,
|
|
4660
6676
|
ObjectWidget,
|
|
4661
6677
|
OneOfWidget,
|
|
4662
6678
|
QuantityWidget,
|
|
6679
|
+
RadioWidget,
|
|
4663
6680
|
SectionsGroupTemplate,
|
|
4664
6681
|
SelectWidget,
|
|
4665
6682
|
StepperGroupTemplate,
|