@usefillo/react 0.11.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +85 -13
- package/dist/index.js +424 -246
- package/dist/styles.css +53 -17
- package/dist/styles.unlayered.css +53 -17
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -483,6 +483,7 @@ import {
|
|
|
483
483
|
formatGroupedNumber,
|
|
484
484
|
isField,
|
|
485
485
|
isValidPartialNumberText,
|
|
486
|
+
localeForNotation,
|
|
486
487
|
parseGroupedNumber,
|
|
487
488
|
pipeBlock,
|
|
488
489
|
radioGroupStep,
|
|
@@ -1007,7 +1008,14 @@ function uploadFailureMessage(error, strings) {
|
|
|
1007
1008
|
}
|
|
1008
1009
|
return strings.uploadFailed;
|
|
1009
1010
|
}
|
|
1010
|
-
function FileUploadField({
|
|
1011
|
+
function FileUploadField({
|
|
1012
|
+
field,
|
|
1013
|
+
value,
|
|
1014
|
+
error,
|
|
1015
|
+
setValue,
|
|
1016
|
+
api,
|
|
1017
|
+
ids: providedIds
|
|
1018
|
+
}) {
|
|
1011
1019
|
const ids = useFilloFieldIds(field.id, providedIds);
|
|
1012
1020
|
const slots = useFieldSlots(field, error);
|
|
1013
1021
|
const strings = useStrings();
|
|
@@ -1036,9 +1044,10 @@ function FileUploadField({ field, value, error, setValue, api, ids: providedIds
|
|
|
1036
1044
|
const configuredMaxMb = schema.maxFileSizeMb ?? 500;
|
|
1037
1045
|
const maxMb = chrome?.uploadFileSizeLimitMb ? Math.min(configuredMaxMb, chrome.uploadFileSizeLimitMb) : configuredMaxMb;
|
|
1038
1046
|
const maxBytes = maxMb * 1024 * 1024;
|
|
1047
|
+
const renderOnly = chrome?.renderOnly === true;
|
|
1039
1048
|
const storageBlocked = chrome?.uploadsAvailable === false;
|
|
1040
1049
|
const storageUrl = storageBlocked && chrome?.devChrome ? safeHttpUrl(chrome.warningUrl) : null;
|
|
1041
|
-
const canUpload = Boolean(api.client && api.formId) && !storageBlocked;
|
|
1050
|
+
const canUpload = !renderOnly && Boolean(api.client && api.formId) && !storageBlocked;
|
|
1042
1051
|
const activeInFlight = inFlight.filter((f) => !f.error).length;
|
|
1043
1052
|
const remaining = maxFiles - files.length - activeInFlight;
|
|
1044
1053
|
async function startUpload(file) {
|
|
@@ -1047,7 +1056,15 @@ function FileUploadField({ field, value, error, setValue, api, ids: providedIds
|
|
|
1047
1056
|
if (file.size > maxBytes) {
|
|
1048
1057
|
setInFlight((prev) => [
|
|
1049
1058
|
...prev,
|
|
1050
|
-
{
|
|
1059
|
+
{
|
|
1060
|
+
key,
|
|
1061
|
+
name: file.name,
|
|
1062
|
+
size: file.size,
|
|
1063
|
+
fraction: 0,
|
|
1064
|
+
file,
|
|
1065
|
+
tooLarge: true,
|
|
1066
|
+
error: strings.fileTooLarge(maxMb)
|
|
1067
|
+
}
|
|
1051
1068
|
]);
|
|
1052
1069
|
return;
|
|
1053
1070
|
}
|
|
@@ -1074,9 +1091,7 @@ function FileUploadField({ field, value, error, setValue, api, ids: providedIds
|
|
|
1074
1091
|
} catch (err) {
|
|
1075
1092
|
if (mountedRef.current) {
|
|
1076
1093
|
const message = uploadFailureMessage(err, strings);
|
|
1077
|
-
setInFlight(
|
|
1078
|
-
(prev) => prev.map((f) => f.key === key ? { ...f, error: message } : f)
|
|
1079
|
-
);
|
|
1094
|
+
setInFlight((prev) => prev.map((f) => f.key === key ? { ...f, error: message } : f));
|
|
1080
1095
|
}
|
|
1081
1096
|
} finally {
|
|
1082
1097
|
controllers.current.delete(key);
|
|
@@ -1100,174 +1115,190 @@ function FileUploadField({ field, value, error, setValue, api, ids: providedIds
|
|
|
1100
1115
|
setValue(next);
|
|
1101
1116
|
}
|
|
1102
1117
|
const describedBy = [field.description ? ids.descriptionId : null, error ? ids.errorId : null].filter(Boolean).join(" ") || void 0;
|
|
1103
|
-
return /* @__PURE__ */ jsxs4(
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
className: slots.
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1118
|
+
return /* @__PURE__ */ jsxs4(
|
|
1119
|
+
"div",
|
|
1120
|
+
{
|
|
1121
|
+
...slots.wrapperProps(
|
|
1122
|
+
`fillo-field fillo-field--file_upload${error ? " fillo-field--error" : ""}`
|
|
1123
|
+
),
|
|
1124
|
+
children: [
|
|
1125
|
+
/* @__PURE__ */ jsxs4("label", { className: slots.label, "data-fillo": "label", id: ids.labelId, htmlFor: ids.inputId, children: [
|
|
1126
|
+
field.label,
|
|
1127
|
+
!field.required && /* @__PURE__ */ jsx4("span", { className: "fillo-optional", children: strings.optional })
|
|
1128
|
+
] }),
|
|
1129
|
+
field.description && /* @__PURE__ */ jsx4("p", { className: slots.description, "data-fillo": "fieldDescription", id: ids.descriptionId, children: field.description }),
|
|
1130
|
+
remaining > 0 && /* @__PURE__ */ jsxs4(
|
|
1131
|
+
"div",
|
|
1132
|
+
{
|
|
1133
|
+
"data-fillo": "control",
|
|
1134
|
+
"data-drag-over": dragOver ? "" : void 0,
|
|
1135
|
+
className: slots.control(
|
|
1136
|
+
`fillo-dropzone${dragOver ? " fillo-dropzone--over" : ""}${canUpload ? "" : " fillo-dropzone--disabled"}`
|
|
1137
|
+
),
|
|
1138
|
+
onDragOver: (e) => {
|
|
1139
|
+
e.preventDefault();
|
|
1140
|
+
setDragOver(true);
|
|
1141
|
+
},
|
|
1142
|
+
onDragLeave: () => setDragOver(false),
|
|
1143
|
+
onDrop: (e) => {
|
|
1144
|
+
e.preventDefault();
|
|
1145
|
+
setDragOver(false);
|
|
1146
|
+
if (canUpload) handleFiles(e.dataTransfer.files);
|
|
1147
|
+
},
|
|
1148
|
+
onClick: () => canUpload && inputRef.current?.click(),
|
|
1149
|
+
role: "button",
|
|
1150
|
+
tabIndex: 0,
|
|
1151
|
+
"aria-disabled": !canUpload || void 0,
|
|
1152
|
+
"aria-labelledby": ids.labelId,
|
|
1153
|
+
"aria-invalid": error ? true : void 0,
|
|
1154
|
+
"aria-describedby": describedBy,
|
|
1155
|
+
onKeyDown: (e) => {
|
|
1156
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
1157
|
+
e.preventDefault();
|
|
1158
|
+
if (canUpload) inputRef.current?.click();
|
|
1159
|
+
}
|
|
1160
|
+
},
|
|
1161
|
+
children: [
|
|
1162
|
+
/* @__PURE__ */ jsx4(
|
|
1163
|
+
"input",
|
|
1164
|
+
{
|
|
1165
|
+
ref: inputRef,
|
|
1166
|
+
id: ids.inputId,
|
|
1167
|
+
type: "file",
|
|
1168
|
+
hidden: true,
|
|
1169
|
+
disabled: !canUpload,
|
|
1170
|
+
multiple: maxFiles > 1,
|
|
1171
|
+
accept: schema.accept?.join(","),
|
|
1172
|
+
onChange: (e) => canUpload && handleFiles(e.target.files)
|
|
1173
|
+
}
|
|
1174
|
+
),
|
|
1175
|
+
canUpload ? /* @__PURE__ */ jsxs4(Fragment2, { children: [
|
|
1176
|
+
/* @__PURE__ */ jsx4("span", { className: "fillo-dropzone-title", children: strings.dropzoneTitle(maxFiles > 1) }),
|
|
1177
|
+
/* @__PURE__ */ jsx4("span", { className: "fillo-dropzone-hint", children: strings.dropzoneHint(maxMb) })
|
|
1178
|
+
] }) : storageBlocked && chrome?.devChrome ? /* @__PURE__ */ jsxs4("span", { className: "fillo-dropzone-hint", children: [
|
|
1179
|
+
"Connect file storage to enable uploads",
|
|
1180
|
+
storageUrl && /* @__PURE__ */ jsxs4(Fragment2, { children: [
|
|
1181
|
+
" \u2014 ",
|
|
1182
|
+
/* @__PURE__ */ jsx4("a", { href: storageUrl, target: "_blank", rel: "noopener noreferrer", children: storageUrl })
|
|
1183
|
+
] })
|
|
1184
|
+
] }) : /* @__PURE__ */ jsx4("span", { className: "fillo-dropzone-hint", children: renderOnly ? strings.uploadsRenderOnly : storageBlocked ? strings.uploadsUnavailable : strings.uploadsDisabled })
|
|
1185
|
+
]
|
|
1137
1186
|
}
|
|
1138
|
-
|
|
1139
|
-
children: [
|
|
1140
|
-
/* @__PURE__ */ jsx4(
|
|
1141
|
-
"input",
|
|
1142
|
-
{
|
|
1143
|
-
ref: inputRef,
|
|
1144
|
-
id: ids.inputId,
|
|
1145
|
-
type: "file",
|
|
1146
|
-
hidden: true,
|
|
1147
|
-
disabled: !canUpload,
|
|
1148
|
-
multiple: maxFiles > 1,
|
|
1149
|
-
accept: schema.accept?.join(","),
|
|
1150
|
-
onChange: (e) => canUpload && handleFiles(e.target.files)
|
|
1151
|
-
}
|
|
1152
|
-
),
|
|
1153
|
-
canUpload ? /* @__PURE__ */ jsxs4(Fragment2, { children: [
|
|
1154
|
-
/* @__PURE__ */ jsx4("span", { className: "fillo-dropzone-title", children: strings.dropzoneTitle(maxFiles > 1) }),
|
|
1155
|
-
/* @__PURE__ */ jsx4("span", { className: "fillo-dropzone-hint", children: strings.dropzoneHint(maxMb) })
|
|
1156
|
-
] }) : storageBlocked && chrome?.devChrome ? /* @__PURE__ */ jsxs4("span", { className: "fillo-dropzone-hint", children: [
|
|
1157
|
-
"Connect file storage to enable uploads",
|
|
1158
|
-
storageUrl && /* @__PURE__ */ jsxs4(Fragment2, { children: [
|
|
1159
|
-
" \u2014 ",
|
|
1160
|
-
/* @__PURE__ */ jsx4("a", { href: storageUrl, target: "_blank", rel: "noopener noreferrer", children: storageUrl })
|
|
1161
|
-
] })
|
|
1162
|
-
] }) : /* @__PURE__ */ jsx4("span", { className: "fillo-dropzone-hint", children: storageBlocked ? strings.uploadsUnavailable : strings.uploadsDisabled })
|
|
1163
|
-
]
|
|
1164
|
-
}
|
|
1165
|
-
),
|
|
1166
|
-
/* @__PURE__ */ jsx4(
|
|
1167
|
-
"div",
|
|
1168
|
-
{
|
|
1169
|
-
role: "status",
|
|
1170
|
-
"aria-live": "polite",
|
|
1171
|
-
className: "fillo-sr-only",
|
|
1172
|
-
style: { position: "absolute", left: "-9999px", width: 1, height: 1, overflow: "hidden" },
|
|
1173
|
-
children: uploadStatus(inFlight, files.length, strings)
|
|
1174
|
-
}
|
|
1175
|
-
),
|
|
1176
|
-
(inFlight.length > 0 || files.length > 0) && /* @__PURE__ */ jsxs4("ul", { className: "fillo-files", children: [
|
|
1177
|
-
files.map((f) => /* @__PURE__ */ jsxs4("li", { className: "fillo-file fillo-file--done", children: [
|
|
1178
|
-
/* @__PURE__ */ jsx4("span", { className: "fillo-file-name", children: f.name }),
|
|
1179
|
-
/* @__PURE__ */ jsx4("span", { className: "fillo-file-meta", children: formatBytes(f.size) }),
|
|
1180
|
-
/* @__PURE__ */ jsx4("span", { className: "fillo-sr-only", children: "Uploaded" }),
|
|
1187
|
+
),
|
|
1181
1188
|
/* @__PURE__ */ jsx4(
|
|
1182
|
-
"
|
|
1189
|
+
"div",
|
|
1183
1190
|
{
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
"
|
|
1187
|
-
|
|
1188
|
-
children:
|
|
1191
|
+
role: "status",
|
|
1192
|
+
"aria-live": "polite",
|
|
1193
|
+
className: "fillo-sr-only",
|
|
1194
|
+
style: { position: "absolute", left: "-9999px", width: 1, height: 1, overflow: "hidden" },
|
|
1195
|
+
children: uploadStatus(inFlight, files.length, strings)
|
|
1189
1196
|
}
|
|
1190
|
-
)
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
"li",
|
|
1194
|
-
{
|
|
1195
|
-
className: `fillo-file${f.error ? " fillo-file--failed" : ""}`,
|
|
1196
|
-
...f.error ? {} : {
|
|
1197
|
-
role: "progressbar",
|
|
1198
|
-
"aria-label": `Uploading ${f.name}`,
|
|
1199
|
-
"aria-valuemin": 0,
|
|
1200
|
-
"aria-valuemax": 100,
|
|
1201
|
-
"aria-valuenow": Math.round(f.fraction * 100)
|
|
1202
|
-
},
|
|
1203
|
-
children: [
|
|
1197
|
+
),
|
|
1198
|
+
(inFlight.length > 0 || files.length > 0) && /* @__PURE__ */ jsxs4("ul", { className: "fillo-files", children: [
|
|
1199
|
+
files.map((f) => /* @__PURE__ */ jsxs4("li", { className: "fillo-file fillo-file--done", children: [
|
|
1204
1200
|
/* @__PURE__ */ jsx4("span", { className: "fillo-file-name", children: f.name }),
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1201
|
+
/* @__PURE__ */ jsx4("span", { className: "fillo-file-meta", children: formatBytes(f.size) }),
|
|
1202
|
+
/* @__PURE__ */ jsx4("span", { className: "fillo-sr-only", children: "Uploaded" }),
|
|
1203
|
+
/* @__PURE__ */ jsx4(
|
|
1204
|
+
"button",
|
|
1205
|
+
{
|
|
1206
|
+
type: "button",
|
|
1207
|
+
className: "fillo-file-remove",
|
|
1208
|
+
"aria-label": `Remove ${f.name}`,
|
|
1209
|
+
onClick: () => removeFile(f.fileId),
|
|
1210
|
+
children: "\xD7"
|
|
1211
|
+
}
|
|
1212
|
+
)
|
|
1213
|
+
] }, f.fileId)),
|
|
1214
|
+
inFlight.map((f) => /* @__PURE__ */ jsxs4(
|
|
1215
|
+
"li",
|
|
1216
|
+
{
|
|
1217
|
+
className: `fillo-file${f.error ? " fillo-file--failed" : ""}`,
|
|
1218
|
+
...f.error ? {} : {
|
|
1219
|
+
role: "progressbar",
|
|
1220
|
+
"aria-label": `Uploading ${f.name}`,
|
|
1221
|
+
"aria-valuemin": 0,
|
|
1222
|
+
"aria-valuemax": 100,
|
|
1223
|
+
"aria-valuenow": Math.round(f.fraction * 100)
|
|
1224
|
+
},
|
|
1225
|
+
children: [
|
|
1226
|
+
/* @__PURE__ */ jsx4("span", { className: "fillo-file-name", children: f.name }),
|
|
1227
|
+
f.error ? /* @__PURE__ */ jsxs4(Fragment2, { children: [
|
|
1228
|
+
/* @__PURE__ */ jsxs4("span", { className: "fillo-file-actions", children: [
|
|
1229
|
+
f.file && !f.tooLarge && remaining > 0 && /* @__PURE__ */ jsx4(
|
|
1230
|
+
"button",
|
|
1231
|
+
{
|
|
1232
|
+
type: "button",
|
|
1233
|
+
className: "fillo-file-retry",
|
|
1234
|
+
"aria-label": `${strings.uploadRetry} ${f.name}`,
|
|
1235
|
+
onClick: () => {
|
|
1236
|
+
const retryFile = f.file;
|
|
1237
|
+
if (!retryFile) return;
|
|
1238
|
+
setInFlight((prev) => prev.filter((x) => x.key !== f.key));
|
|
1239
|
+
void startUpload(retryFile);
|
|
1240
|
+
},
|
|
1241
|
+
children: strings.uploadRetry
|
|
1242
|
+
}
|
|
1243
|
+
),
|
|
1244
|
+
/* @__PURE__ */ jsx4(
|
|
1245
|
+
"button",
|
|
1246
|
+
{
|
|
1247
|
+
type: "button",
|
|
1248
|
+
className: "fillo-file-remove",
|
|
1249
|
+
"aria-label": "Dismiss",
|
|
1250
|
+
onClick: () => setInFlight((prev) => prev.filter((x) => x.key !== f.key)),
|
|
1251
|
+
children: "\xD7"
|
|
1252
|
+
}
|
|
1253
|
+
)
|
|
1254
|
+
] }),
|
|
1255
|
+
/* @__PURE__ */ jsx4("span", { className: "fillo-file-error", role: "alert", children: f.error })
|
|
1256
|
+
] }) : /* @__PURE__ */ jsxs4(Fragment2, { children: [
|
|
1257
|
+
/* @__PURE__ */ jsxs4("span", { className: "fillo-file-meta", children: [
|
|
1258
|
+
Math.round(f.fraction * 100),
|
|
1259
|
+
"% of ",
|
|
1260
|
+
formatBytes(f.size)
|
|
1261
|
+
] }),
|
|
1262
|
+
/* @__PURE__ */ jsx4(
|
|
1263
|
+
"button",
|
|
1264
|
+
{
|
|
1265
|
+
type: "button",
|
|
1266
|
+
className: "fillo-file-remove",
|
|
1267
|
+
"aria-label": `Cancel ${f.name}`,
|
|
1268
|
+
onClick: () => cancelUpload(f.key),
|
|
1269
|
+
children: "\xD7"
|
|
1270
|
+
}
|
|
1271
|
+
),
|
|
1272
|
+
/* @__PURE__ */ jsx4("span", { className: "fillo-progress", "aria-hidden": "true", children: /* @__PURE__ */ jsx4(
|
|
1273
|
+
"span",
|
|
1274
|
+
{
|
|
1275
|
+
className: "fillo-progress-bar",
|
|
1276
|
+
style: { width: `${f.fraction * 100}%` }
|
|
1277
|
+
}
|
|
1278
|
+
) })
|
|
1279
|
+
] })
|
|
1280
|
+
]
|
|
1281
|
+
},
|
|
1282
|
+
f.key
|
|
1283
|
+
))
|
|
1284
|
+
] }),
|
|
1285
|
+
error && /* @__PURE__ */ jsx4("p", { className: slots.error, "data-fillo": "error", id: ids.errorId, children: error })
|
|
1286
|
+
]
|
|
1287
|
+
}
|
|
1288
|
+
);
|
|
1259
1289
|
}
|
|
1260
1290
|
|
|
1261
1291
|
// src/fields.tsx
|
|
1262
1292
|
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1263
|
-
function fieldAria(field, error, ids) {
|
|
1293
|
+
function fieldAria(field, error, ids, opts = {}) {
|
|
1264
1294
|
const describedBy = [
|
|
1265
1295
|
field.description ? ids.descriptionId : null,
|
|
1266
1296
|
error ? ids.errorId : null
|
|
1267
1297
|
].filter(Boolean);
|
|
1298
|
+
const requiredSupported = opts.required ?? true;
|
|
1268
1299
|
return {
|
|
1269
1300
|
"aria-invalid": error ? true : void 0,
|
|
1270
|
-
"aria-required": field.required ? true : void 0,
|
|
1301
|
+
"aria-required": requiredSupported && field.required ? true : void 0,
|
|
1271
1302
|
"aria-describedby": describedBy.length ? describedBy.join(" ") : void 0
|
|
1272
1303
|
};
|
|
1273
1304
|
}
|
|
@@ -1360,7 +1391,8 @@ function NumberInput({ field, value, error, setValue, api, ids: providedIds }) {
|
|
|
1360
1391
|
inputRef.current?.setSelectionRange(pos, pos);
|
|
1361
1392
|
});
|
|
1362
1393
|
const num = field;
|
|
1363
|
-
const grouped = num.notation
|
|
1394
|
+
const grouped = num.notation !== void 0;
|
|
1395
|
+
const locale = localeForNotation(num.notation);
|
|
1364
1396
|
const hasAffix = Boolean(num.prefix) || Boolean(num.suffix);
|
|
1365
1397
|
if (!grouped && !hasAffix) {
|
|
1366
1398
|
return /* @__PURE__ */ jsx5(
|
|
@@ -1377,7 +1409,7 @@ function NumberInput({ field, value, error, setValue, api, ids: providedIds }) {
|
|
|
1377
1409
|
}
|
|
1378
1410
|
const stored = typeof value === "string" || typeof value === "number" ? String(value) : "";
|
|
1379
1411
|
const n = Number(stored);
|
|
1380
|
-
const display = draft !== null ? draft : grouped && stored !== "" && Number.isFinite(n) ? formatGroupedNumber(n, { decimals: num.decimals }) : stored;
|
|
1412
|
+
const display = draft !== null ? draft : grouped && stored !== "" && Number.isFinite(n) ? formatGroupedNumber(n, { locale, decimals: num.decimals }) : stored;
|
|
1381
1413
|
const input = /* @__PURE__ */ jsx5(
|
|
1382
1414
|
"input",
|
|
1383
1415
|
{
|
|
@@ -1390,14 +1422,14 @@ function NumberInput({ field, value, error, setValue, api, ids: providedIds }) {
|
|
|
1390
1422
|
placeholder: field.placeholder,
|
|
1391
1423
|
onBlur: grouped ? () => setDraft(null) : void 0,
|
|
1392
1424
|
onChange: (e) => {
|
|
1393
|
-
if (!isValidPartialNumberText(e.target.value)) {
|
|
1425
|
+
if (!isValidPartialNumberText(e.target.value, locale)) {
|
|
1394
1426
|
pendingCaret.current = e.target.selectionStart ?? e.target.value.length;
|
|
1395
1427
|
setRevertTick((t) => t + 1);
|
|
1396
1428
|
return;
|
|
1397
1429
|
}
|
|
1398
1430
|
if (grouped) {
|
|
1399
1431
|
setDraft(e.target.value);
|
|
1400
|
-
setValue(parseGroupedNumber(e.target.value));
|
|
1432
|
+
setValue(parseGroupedNumber(e.target.value, locale));
|
|
1401
1433
|
} else {
|
|
1402
1434
|
setValue(e.target.value);
|
|
1403
1435
|
}
|
|
@@ -1590,7 +1622,7 @@ function MultiChoice({ field, value, error, setValue, ids: providedIds }) {
|
|
|
1590
1622
|
"data-fillo": "options",
|
|
1591
1623
|
role: "group",
|
|
1592
1624
|
"aria-labelledby": ids.labelId,
|
|
1593
|
-
...fieldAria(field, error, ids),
|
|
1625
|
+
...fieldAria(field, error, ids, { required: false }),
|
|
1594
1626
|
children: [
|
|
1595
1627
|
options.map((opt) => /* @__PURE__ */ jsxs5(
|
|
1596
1628
|
"label",
|
|
@@ -1967,7 +1999,7 @@ function Ranking({ field, value, error, setValue, ids: providedIds }) {
|
|
|
1967
1999
|
id: ids.inputId,
|
|
1968
2000
|
role: "group",
|
|
1969
2001
|
"aria-labelledby": ids.labelId,
|
|
1970
|
-
...fieldAria(field, error, ids),
|
|
2002
|
+
...fieldAria(field, error, ids, { required: false }),
|
|
1971
2003
|
children: /* @__PURE__ */ jsx5("ol", { className: "fillo-ranking", children: order.map((id, index) => {
|
|
1972
2004
|
const option = ranking.options.find((o) => o.id === id);
|
|
1973
2005
|
if (!option) return null;
|
|
@@ -2014,10 +2046,10 @@ function Matrix({ field, value, error, setValue, ids: providedIds }) {
|
|
|
2014
2046
|
className: "fillo-matrix-wrap",
|
|
2015
2047
|
role: "group",
|
|
2016
2048
|
"aria-labelledby": ids.labelId,
|
|
2017
|
-
...fieldAria(field, error, ids),
|
|
2049
|
+
...fieldAria(field, error, ids, { required: false }),
|
|
2018
2050
|
children: /* @__PURE__ */ jsxs5("table", { className: "fillo-matrix", children: [
|
|
2019
2051
|
/* @__PURE__ */ jsx5("thead", { children: /* @__PURE__ */ jsxs5("tr", { children: [
|
|
2020
|
-
/* @__PURE__ */ jsx5("
|
|
2052
|
+
/* @__PURE__ */ jsx5("td", {}),
|
|
2021
2053
|
matrix.columns.map((col) => /* @__PURE__ */ jsx5("th", { scope: "col", children: col.label }, col.id))
|
|
2022
2054
|
] }) }),
|
|
2023
2055
|
/* @__PURE__ */ jsx5("tbody", { children: matrix.rows.map((row) => {
|
|
@@ -2410,12 +2442,15 @@ function assertHpHidden(el) {
|
|
|
2410
2442
|
}
|
|
2411
2443
|
function FilloForm(props) {
|
|
2412
2444
|
const { form, formId } = props;
|
|
2445
|
+
const renderOnly = props.renderOnly === true || props.skipValidation === true;
|
|
2413
2446
|
const client = useMemo5(
|
|
2414
|
-
() => props.client ?? (formId ? createClient() : void 0),
|
|
2415
|
-
[props.client, formId]
|
|
2447
|
+
() => renderOnly ? void 0 : props.client ?? (formId ? createClient() : void 0),
|
|
2448
|
+
[renderOnly, props.client, formId]
|
|
2416
2449
|
);
|
|
2417
2450
|
const [loaded, setLoaded] = useState6(null);
|
|
2418
|
-
const [loadFailure, setLoadFailure] = useState6(
|
|
2451
|
+
const [loadFailure, setLoadFailure] = useState6(
|
|
2452
|
+
null
|
|
2453
|
+
);
|
|
2419
2454
|
const devEnv = useIsDevEnv();
|
|
2420
2455
|
const devChrome = props.preview === true || devEnv;
|
|
2421
2456
|
if (props.preview === true) warnPreviewInProduction();
|
|
@@ -2449,6 +2484,18 @@ function FilloForm(props) {
|
|
|
2449
2484
|
useEffect8(() => {
|
|
2450
2485
|
onErrorRef.current = onError;
|
|
2451
2486
|
});
|
|
2487
|
+
const targetError = useMemo5(
|
|
2488
|
+
() => form && !formId && !renderOnly && (!isCodeForm2(form) || !props.client) ? new FilloError2(
|
|
2489
|
+
"This form has no Fillo target. Pass formId with the schema, use a defineForm() value with client, or set renderOnly for a non-submitting preview.",
|
|
2490
|
+
422,
|
|
2491
|
+
void 0,
|
|
2492
|
+
"form_target_required"
|
|
2493
|
+
) : null,
|
|
2494
|
+
[form, formId, props.client, renderOnly]
|
|
2495
|
+
);
|
|
2496
|
+
useEffect8(() => {
|
|
2497
|
+
if (targetError) onErrorRef.current?.(targetError);
|
|
2498
|
+
}, [targetError]);
|
|
2452
2499
|
const needsFetch = !inlineSchema && Boolean(client && formId);
|
|
2453
2500
|
useEffect8(() => {
|
|
2454
2501
|
if (!needsFetch || !client || !formId) {
|
|
@@ -2487,10 +2534,28 @@ function FilloForm(props) {
|
|
|
2487
2534
|
const currentLoaded = needsFetch && loaded?.formId === formId ? loaded : null;
|
|
2488
2535
|
const loadError = needsFetch && loadFailure && loadFailure.formId === formId ? loadFailure.error : null;
|
|
2489
2536
|
const rawSchema = inlineSchema ?? currentLoaded?.schema ?? null;
|
|
2490
|
-
const normalized = useMemo5(
|
|
2537
|
+
const normalized = useMemo5(
|
|
2538
|
+
() => rawSchema ? normalizeFormSchema(rawSchema) : null,
|
|
2539
|
+
[rawSchema]
|
|
2540
|
+
);
|
|
2491
2541
|
const schema = normalized?.ok ? normalized.schema : null;
|
|
2492
2542
|
const resolvedCodeTheme = renderResolvedSnapshot ? resolvedTheme ?? void 0 : codeForm?.theme;
|
|
2493
2543
|
const theme = props.appearance?.theme ?? props.theme ?? resolvedCodeTheme ?? currentLoaded?.theme ?? void 0;
|
|
2544
|
+
if (targetError) {
|
|
2545
|
+
if (props.renderError) return /* @__PURE__ */ jsx7(Fragment3, { children: props.renderError(targetError) });
|
|
2546
|
+
return /* @__PURE__ */ jsx7(
|
|
2547
|
+
"div",
|
|
2548
|
+
{
|
|
2549
|
+
className: `fillo-form fillo-form--error ${props.className ?? ""}`,
|
|
2550
|
+
role: "alert",
|
|
2551
|
+
"data-fillo": "root",
|
|
2552
|
+
"data-state": "error",
|
|
2553
|
+
"data-error-code": "form_target_required",
|
|
2554
|
+
...themeProps(theme),
|
|
2555
|
+
children: devChrome ? `${targetError.message} (${targetError.code})` : strings.loadFailed
|
|
2556
|
+
}
|
|
2557
|
+
);
|
|
2558
|
+
}
|
|
2494
2559
|
if (normalized && !normalized.ok) {
|
|
2495
2560
|
const error = new FilloError2(`This form could not be rendered: ${normalized.error}`, 422);
|
|
2496
2561
|
if (props.renderError) return /* @__PURE__ */ jsx7(Fragment3, { children: props.renderError(error) });
|
|
@@ -2531,7 +2596,14 @@ function FilloForm(props) {
|
|
|
2531
2596
|
);
|
|
2532
2597
|
}
|
|
2533
2598
|
if (currentLoaded?.closed) {
|
|
2534
|
-
return /* @__PURE__ */ jsx7(
|
|
2599
|
+
return /* @__PURE__ */ jsx7(
|
|
2600
|
+
"div",
|
|
2601
|
+
{
|
|
2602
|
+
className: `fillo-form fillo-form--closed ${props.className ?? ""}`,
|
|
2603
|
+
...themeProps(theme),
|
|
2604
|
+
children: /* @__PURE__ */ jsx7("p", { className: "fillo-closed", children: strings.closed })
|
|
2605
|
+
}
|
|
2606
|
+
);
|
|
2535
2607
|
}
|
|
2536
2608
|
const canonicalSyncError = codeForm && syncError && !props.skipValidation ? syncError : null;
|
|
2537
2609
|
if (canonicalSyncError && props.renderError) {
|
|
@@ -2573,7 +2645,14 @@ function FilloForm(props) {
|
|
|
2573
2645
|
}
|
|
2574
2646
|
);
|
|
2575
2647
|
}
|
|
2576
|
-
return /* @__PURE__ */ jsx7(
|
|
2648
|
+
return /* @__PURE__ */ jsx7(
|
|
2649
|
+
"div",
|
|
2650
|
+
{
|
|
2651
|
+
className: `fillo-form fillo-form--closed ${props.className ?? ""}`,
|
|
2652
|
+
...themeProps(theme),
|
|
2653
|
+
children: /* @__PURE__ */ jsx7("p", { className: "fillo-closed", children: variant === "closed" ? strings.closed : strings.notLive })
|
|
2654
|
+
}
|
|
2655
|
+
);
|
|
2577
2656
|
}
|
|
2578
2657
|
const awaitingCanonical = Boolean(codeForm && codeFormSyncing && !props.skipValidation);
|
|
2579
2658
|
if (!devChrome && awaitingCanonical || !schema) {
|
|
@@ -2598,10 +2677,12 @@ function FilloForm(props) {
|
|
|
2598
2677
|
ResolvedForm,
|
|
2599
2678
|
{
|
|
2600
2679
|
...props,
|
|
2601
|
-
client,
|
|
2680
|
+
client: renderOnly ? void 0 : client,
|
|
2602
2681
|
schema,
|
|
2603
2682
|
theme,
|
|
2604
|
-
formId: syncedFormId ?? formId,
|
|
2683
|
+
formId: renderOnly ? void 0 : syncedFormId ?? formId,
|
|
2684
|
+
renderOnly,
|
|
2685
|
+
skipValidation: renderOnly ? true : props.skipValidation,
|
|
2605
2686
|
poweredBy,
|
|
2606
2687
|
brandLabel: branding?.label,
|
|
2607
2688
|
brandHref: branding?.href,
|
|
@@ -2672,13 +2753,14 @@ function useIsDevEnv() {
|
|
|
2672
2753
|
function ResolvedForm(props) {
|
|
2673
2754
|
const { schema, theme } = props;
|
|
2674
2755
|
const displayOnly = props.displayOnly === true;
|
|
2756
|
+
const renderOnly = props.renderOnly === true;
|
|
2675
2757
|
const instanceId = useId2().replace(/:/g, "");
|
|
2676
2758
|
const devEnv = useIsDevEnv();
|
|
2677
2759
|
const devChrome = !displayOnly && (props.preview === true || devEnv);
|
|
2678
2760
|
const hpRef = useRef8(null);
|
|
2679
2761
|
const codeForm = isCodeForm2(props.form) ? props.form : null;
|
|
2680
2762
|
const client = props.client;
|
|
2681
|
-
const challenge = props.challenge;
|
|
2763
|
+
const challenge = renderOnly ? void 0 : props.challenge;
|
|
2682
2764
|
const challengeRequired = Boolean(challenge);
|
|
2683
2765
|
const challengeTokenRef = useRef8(void 0);
|
|
2684
2766
|
const [resyncWarning, setResyncWarning] = useState6(null);
|
|
@@ -2790,7 +2872,7 @@ function ResolvedForm(props) {
|
|
|
2790
2872
|
resetChallengeRef.current?.();
|
|
2791
2873
|
}
|
|
2792
2874
|
});
|
|
2793
|
-
useDraftFlush(api, !displayOnly);
|
|
2875
|
+
useDraftFlush(api, !displayOnly && !renderOnly);
|
|
2794
2876
|
const strings = resolveStrings(props.strings);
|
|
2795
2877
|
const announceRef = useRef8(null);
|
|
2796
2878
|
const announce = useCallback((text) => {
|
|
@@ -2821,12 +2903,13 @@ function ResolvedForm(props) {
|
|
|
2821
2903
|
const chromeValue = useMemo5(
|
|
2822
2904
|
() => ({
|
|
2823
2905
|
devChrome,
|
|
2906
|
+
renderOnly,
|
|
2824
2907
|
uploadsAvailable,
|
|
2825
2908
|
uploadFileSizeLimitMb,
|
|
2826
2909
|
warningCode,
|
|
2827
2910
|
warningUrl
|
|
2828
2911
|
}),
|
|
2829
|
-
[devChrome, uploadsAvailable, uploadFileSizeLimitMb, warningCode, warningUrl]
|
|
2912
|
+
[devChrome, renderOnly, uploadsAvailable, uploadFileSizeLimitMb, warningCode, warningUrl]
|
|
2830
2913
|
);
|
|
2831
2914
|
const settings = schema.settings;
|
|
2832
2915
|
const submitted = api.status === "submitted";
|
|
@@ -2867,13 +2950,17 @@ function ResolvedForm(props) {
|
|
|
2867
2950
|
{ slot: "root", status: "submitted" }
|
|
2868
2951
|
),
|
|
2869
2952
|
"data-fillo": "root",
|
|
2953
|
+
"data-fillo-form-id": props.formId,
|
|
2870
2954
|
"data-state": "submitted",
|
|
2871
2955
|
...themed,
|
|
2872
2956
|
children: [
|
|
2873
2957
|
props.renderSuccess ? props.renderSuccess() : /* @__PURE__ */ jsxs6(
|
|
2874
2958
|
"div",
|
|
2875
2959
|
{
|
|
2876
|
-
className: slotClass3("fillo-success", appearance, {
|
|
2960
|
+
className: slotClass3("fillo-success", appearance, {
|
|
2961
|
+
slot: "success",
|
|
2962
|
+
status: "submitted"
|
|
2963
|
+
}),
|
|
2877
2964
|
"data-fillo": "success",
|
|
2878
2965
|
children: [
|
|
2879
2966
|
/* @__PURE__ */ jsx7("div", { className: "fillo-success-mark", "aria-hidden": "true" }),
|
|
@@ -2934,7 +3021,7 @@ function ResolvedForm(props) {
|
|
|
2934
3021
|
staged: props.stagedNotice,
|
|
2935
3022
|
draft: props.draftNotice,
|
|
2936
3023
|
warningUrl: props.syncWarningUrl,
|
|
2937
|
-
noClient: !props.client && !props.skipValidation
|
|
3024
|
+
noClient: !props.client && !props.skipValidation && !renderOnly
|
|
2938
3025
|
}
|
|
2939
3026
|
),
|
|
2940
3027
|
resuming && /* @__PURE__ */ jsxs6(
|
|
@@ -2951,7 +3038,9 @@ function ResolvedForm(props) {
|
|
|
2951
3038
|
api.resumeLinkFailed && !api.resumedDraft && !api.editingPrevious && /* @__PURE__ */ jsx7(
|
|
2952
3039
|
"div",
|
|
2953
3040
|
{
|
|
2954
|
-
className: slotClass3("fillo-resume fillo-resume--expired", appearance, {
|
|
3041
|
+
className: slotClass3("fillo-resume fillo-resume--expired", appearance, {
|
|
3042
|
+
slot: "resume"
|
|
3043
|
+
}),
|
|
2955
3044
|
"data-fillo": "resume",
|
|
2956
3045
|
role: "status",
|
|
2957
3046
|
children: /* @__PURE__ */ jsx7("span", { className: "fillo-resume-text", children: strings.resumeLinkExpired })
|
|
@@ -2972,23 +3061,46 @@ function ResolvedForm(props) {
|
|
|
2972
3061
|
{
|
|
2973
3062
|
className: slotClass3("fillo-progress-fill", appearance, { slot: "progressFill" }),
|
|
2974
3063
|
"data-fillo": "progressFill",
|
|
2975
|
-
style: {
|
|
3064
|
+
style: {
|
|
3065
|
+
"--fillo-progress-value": `${progressStep / progressTotal * 100}%`
|
|
3066
|
+
}
|
|
2976
3067
|
}
|
|
2977
3068
|
)
|
|
2978
3069
|
}
|
|
2979
3070
|
),
|
|
2980
|
-
api.pageIndex === 0 && props.showTitle !== false && /* @__PURE__ */ jsxs6(
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
"
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
3071
|
+
api.pageIndex === 0 && props.showTitle !== false && /* @__PURE__ */ jsxs6(
|
|
3072
|
+
"header",
|
|
3073
|
+
{
|
|
3074
|
+
className: slotClass3("fillo-header", appearance, { slot: "header" }),
|
|
3075
|
+
"data-fillo": "header",
|
|
3076
|
+
children: [
|
|
3077
|
+
schema.title && /* @__PURE__ */ jsx7(
|
|
3078
|
+
"h1",
|
|
3079
|
+
{
|
|
3080
|
+
className: slotClass3("fillo-title", appearance, { slot: "title" }),
|
|
3081
|
+
"data-fillo": "title",
|
|
3082
|
+
children: schema.title
|
|
3083
|
+
}
|
|
3084
|
+
),
|
|
3085
|
+
schema.description && /* @__PURE__ */ jsx7(
|
|
3086
|
+
"p",
|
|
3087
|
+
{
|
|
3088
|
+
className: slotClass3("fillo-form-description", appearance, { slot: "description" }),
|
|
3089
|
+
"data-fillo": "description",
|
|
3090
|
+
children: schema.description
|
|
3091
|
+
}
|
|
3092
|
+
)
|
|
3093
|
+
]
|
|
3094
|
+
}
|
|
3095
|
+
),
|
|
3096
|
+
multiPage && api.page.title && api.pageIndex > 0 && /* @__PURE__ */ jsx7(
|
|
3097
|
+
"h2",
|
|
3098
|
+
{
|
|
3099
|
+
className: slotClass3("fillo-page-title", appearance, { slot: "pageTitle" }),
|
|
3100
|
+
"data-fillo": "pageTitle",
|
|
3101
|
+
children: api.page.title
|
|
3102
|
+
}
|
|
3103
|
+
),
|
|
2992
3104
|
invalidFields.length > 0 && /* @__PURE__ */ jsxs6("div", { className: "fillo-error-summary", role: "alert", tabIndex: -1, "data-fillo": "error-summary", children: [
|
|
2993
3105
|
/* @__PURE__ */ jsx7("p", { className: "fillo-error-summary-title", children: strings.errorSummaryTitle }),
|
|
2994
3106
|
/* @__PURE__ */ jsx7("ul", { children: invalidFields.map(({ field, error, inputId }) => /* @__PURE__ */ jsx7("li", { children: /* @__PURE__ */ jsxs6(
|
|
@@ -3007,16 +3119,25 @@ function ResolvedForm(props) {
|
|
|
3007
3119
|
}
|
|
3008
3120
|
) }, field.id)) })
|
|
3009
3121
|
] }),
|
|
3010
|
-
/* @__PURE__ */ jsx7(
|
|
3011
|
-
|
|
3122
|
+
/* @__PURE__ */ jsx7(
|
|
3123
|
+
"div",
|
|
3012
3124
|
{
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3125
|
+
className: slotClass3("fillo-blocks", appearance, { slot: "blocks" }),
|
|
3126
|
+
"data-fillo": "blocks",
|
|
3127
|
+
ref: blocksRef,
|
|
3128
|
+
tabIndex: -1,
|
|
3129
|
+
children: api.blocks.map((block) => /* @__PURE__ */ jsx7(
|
|
3130
|
+
BlockRenderer,
|
|
3131
|
+
{
|
|
3132
|
+
block,
|
|
3133
|
+
api,
|
|
3134
|
+
components: props.components,
|
|
3135
|
+
customComponents: props.customComponents
|
|
3136
|
+
},
|
|
3137
|
+
block.id
|
|
3138
|
+
))
|
|
3139
|
+
}
|
|
3140
|
+
),
|
|
3020
3141
|
!displayOnly && /* @__PURE__ */ jsx7(
|
|
3021
3142
|
"input",
|
|
3022
3143
|
{
|
|
@@ -3056,43 +3177,66 @@ function ResolvedForm(props) {
|
|
|
3056
3177
|
/* @__PURE__ */ jsx7("a", { href: submitFixUrl, target: "_blank", rel: "noopener noreferrer", children: submitFixUrl })
|
|
3057
3178
|
] })
|
|
3058
3179
|
] }),
|
|
3059
|
-
showFooter && /* @__PURE__ */ jsxs6(
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
{
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
|
|
3069
|
-
|
|
3070
|
-
|
|
3071
|
-
|
|
3072
|
-
|
|
3073
|
-
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
|
|
3083
|
-
|
|
3180
|
+
showFooter && /* @__PURE__ */ jsxs6(
|
|
3181
|
+
"footer",
|
|
3182
|
+
{
|
|
3183
|
+
className: slotClass3("fillo-footer", appearance, { slot: "footer" }),
|
|
3184
|
+
"data-fillo": "footer",
|
|
3185
|
+
children: [
|
|
3186
|
+
multiPage && !api.isFirstPage && /* @__PURE__ */ jsx7(
|
|
3187
|
+
"button",
|
|
3188
|
+
{
|
|
3189
|
+
type: "button",
|
|
3190
|
+
className: slotClass3("fillo-button fillo-button--ghost", appearance, {
|
|
3191
|
+
slot: "button",
|
|
3192
|
+
variant: "ghost"
|
|
3193
|
+
}),
|
|
3194
|
+
"data-fillo": "button",
|
|
3195
|
+
onClick: api.back,
|
|
3196
|
+
children: strings.back
|
|
3197
|
+
}
|
|
3198
|
+
),
|
|
3199
|
+
showPrimaryButton && /* @__PURE__ */ jsx7(
|
|
3200
|
+
"button",
|
|
3201
|
+
{
|
|
3202
|
+
type: "submit",
|
|
3203
|
+
className: slotClass3("fillo-button fillo-button--primary", appearance, {
|
|
3204
|
+
slot: "button",
|
|
3205
|
+
variant: "primary"
|
|
3206
|
+
}),
|
|
3207
|
+
"data-fillo": "button",
|
|
3208
|
+
disabled: api.status === "submitting" || api.uploading || // Wait for the human check before enabling submit (never
|
|
3209
|
+
// "Next"). The server rejects a tokenless submit regardless —
|
|
3210
|
+
// this is UX only.
|
|
3211
|
+
showChallenge && !challengeToken,
|
|
3212
|
+
children: api.uploading ? strings.uploading : api.status === "submitting" ? strings.submitting : api.isLastPage ? settings.submitLabel ?? strings.submit : strings.next
|
|
3213
|
+
}
|
|
3214
|
+
)
|
|
3215
|
+
]
|
|
3216
|
+
}
|
|
3217
|
+
),
|
|
3084
3218
|
props.poweredBy && /* @__PURE__ */ jsx7(PoweredBy, { label: props.brandLabel, href: props.brandHref })
|
|
3085
3219
|
] });
|
|
3086
3220
|
return /* @__PURE__ */ jsx7(FilloContext.Provider, { value: api, children: /* @__PURE__ */ jsx7(FilloChromeContext.Provider, { value: chromeValue, children: /* @__PURE__ */ jsx7(FilloAnnounceContext.Provider, { value: announce, children: /* @__PURE__ */ jsx7(FilloStringsContext.Provider, { value: strings, children: /* @__PURE__ */ jsx7(FilloAppearanceContext.Provider, { value: appearance, children: /* @__PURE__ */ jsx7(FilloInstanceIdContext.Provider, { value: instanceId, children: displayOnly ? (
|
|
3087
3221
|
// Display-only preview: a plain div (no form element to submit) with
|
|
3088
3222
|
// every control inside a natively disabled fieldset — unfocusable
|
|
3089
3223
|
// and unfillable even without the stylesheet or inert support.
|
|
3090
|
-
/* @__PURE__ */ jsx7(
|
|
3224
|
+
/* @__PURE__ */ jsx7(
|
|
3225
|
+
"div",
|
|
3226
|
+
{
|
|
3227
|
+
className: rootClass,
|
|
3228
|
+
"data-fillo": "preview-form",
|
|
3229
|
+
"data-state": "preview",
|
|
3230
|
+
...themed,
|
|
3231
|
+
children: /* @__PURE__ */ jsx7("fieldset", { disabled: true, className: "fillo-not-open-fields", children: formBody })
|
|
3232
|
+
}
|
|
3233
|
+
)
|
|
3091
3234
|
) : /* @__PURE__ */ jsx7(
|
|
3092
3235
|
"form",
|
|
3093
3236
|
{
|
|
3094
3237
|
className: rootClass,
|
|
3095
3238
|
"data-fillo": "root",
|
|
3239
|
+
"data-fillo-form-id": props.formId,
|
|
3096
3240
|
"data-state": api.status,
|
|
3097
3241
|
"data-page": api.pageIndex + 1,
|
|
3098
3242
|
"data-last-page": api.isLastPage ? "" : void 0,
|
|
@@ -3138,7 +3282,7 @@ function JsxForm(props) {
|
|
|
3138
3282
|
if (!memo2.current || memo2.current.json !== json) {
|
|
3139
3283
|
memo2.current = { json, form: compiled };
|
|
3140
3284
|
}
|
|
3141
|
-
return /* @__PURE__ */ jsx8(FilloForm, { form: memo2.current.form, client, ...rest });
|
|
3285
|
+
return /* @__PURE__ */ jsx8(FilloForm, { ...{ form: memo2.current.form, client, ...rest } });
|
|
3142
3286
|
}
|
|
3143
3287
|
function defineFormFromJsx(element) {
|
|
3144
3288
|
if (!element || element.type !== JsxForm) {
|
|
@@ -3183,9 +3327,10 @@ var Fillo = {
|
|
|
3183
3327
|
};
|
|
3184
3328
|
|
|
3185
3329
|
// src/provider.tsx
|
|
3186
|
-
import { useId as useId3, useMemo as useMemo6, useState as useState7 } from "react";
|
|
3330
|
+
import { useEffect as useEffect9, useId as useId3, useMemo as useMemo6, useState as useState7 } from "react";
|
|
3187
3331
|
import {
|
|
3188
3332
|
FilloError as FilloError3,
|
|
3333
|
+
createClient as createClient2,
|
|
3189
3334
|
formSchemasEqual as formSchemasEqual2,
|
|
3190
3335
|
isFilloError as isFilloError3,
|
|
3191
3336
|
normalizeFormSchema as normalizeFormSchema2,
|
|
@@ -3203,13 +3348,33 @@ function FilloProvider({
|
|
|
3203
3348
|
onError,
|
|
3204
3349
|
renderError,
|
|
3205
3350
|
preview,
|
|
3351
|
+
renderOnly,
|
|
3352
|
+
skipValidation,
|
|
3206
3353
|
...options
|
|
3207
3354
|
}) {
|
|
3355
|
+
const localPreview = renderOnly === true || skipValidation === true;
|
|
3356
|
+
const activeClient = useMemo6(
|
|
3357
|
+
() => localPreview ? void 0 : client ?? (formId ? createClient2() : void 0),
|
|
3358
|
+
[client, formId, localPreview]
|
|
3359
|
+
);
|
|
3360
|
+
const activeFormId = localPreview ? void 0 : formId;
|
|
3208
3361
|
const instanceId = useId3().replace(/:/g, "");
|
|
3209
3362
|
const devEnv = useIsDevEnv();
|
|
3210
3363
|
const devChrome = preview === true || devEnv;
|
|
3211
3364
|
if (preview === true) warnPreviewInProduction();
|
|
3212
3365
|
const codeForm = isCodeForm2(form) ? form : null;
|
|
3366
|
+
const targetError = useMemo6(
|
|
3367
|
+
() => !formId && !localPreview && (!codeForm || !client) ? new FilloError3(
|
|
3368
|
+
"This form has no Fillo target. Pass formId with the schema, use a defineForm() value with client, or set renderOnly for a non-submitting preview.",
|
|
3369
|
+
422,
|
|
3370
|
+
void 0,
|
|
3371
|
+
"form_target_required"
|
|
3372
|
+
) : null,
|
|
3373
|
+
[client, codeForm, formId, localPreview]
|
|
3374
|
+
);
|
|
3375
|
+
useEffect9(() => {
|
|
3376
|
+
if (targetError) onError?.(targetError);
|
|
3377
|
+
}, [onError, targetError]);
|
|
3213
3378
|
const {
|
|
3214
3379
|
formId: syncedFormId,
|
|
3215
3380
|
status: syncedStatus,
|
|
@@ -3222,8 +3387,8 @@ function FilloProvider({
|
|
|
3222
3387
|
uploadFileSizeLimitMb,
|
|
3223
3388
|
warningCode,
|
|
3224
3389
|
warningUrl
|
|
3225
|
-
} = useCodeFormSync(form,
|
|
3226
|
-
allowUnsynced: Boolean(!
|
|
3390
|
+
} = useCodeFormSync(form, activeClient, onError, {
|
|
3391
|
+
allowUnsynced: Boolean(!activeClient || activeFormId || localPreview)
|
|
3227
3392
|
});
|
|
3228
3393
|
const [resyncWarning, setResyncWarning] = useState7(null);
|
|
3229
3394
|
const rawSchema = codeForm ? resolvedSchema && !devChrome ? resolvedSchema : codeForm.schema : form;
|
|
@@ -3233,9 +3398,9 @@ function FilloProvider({
|
|
|
3233
3398
|
}
|
|
3234
3399
|
const schema = normalized.schema;
|
|
3235
3400
|
const resolveFormId = useMemo6(
|
|
3236
|
-
() => codeForm &&
|
|
3401
|
+
() => codeForm && activeClient?.key ? async () => {
|
|
3237
3402
|
try {
|
|
3238
|
-
const result = await syncCodeForm3(
|
|
3403
|
+
const result = await syncCodeForm3(activeClient, codeForm, { bypassCache: true });
|
|
3239
3404
|
setResyncWarning({
|
|
3240
3405
|
code: result.warningCode,
|
|
3241
3406
|
url: result.warningUrl,
|
|
@@ -3297,13 +3462,14 @@ function FilloProvider({
|
|
|
3297
3462
|
throw failure;
|
|
3298
3463
|
}
|
|
3299
3464
|
} : void 0,
|
|
3300
|
-
[
|
|
3465
|
+
[activeClient, codeForm, onError, schema]
|
|
3301
3466
|
);
|
|
3302
3467
|
const api = useFilloController({
|
|
3303
3468
|
...options,
|
|
3304
|
-
client,
|
|
3469
|
+
client: activeClient,
|
|
3305
3470
|
form: schema,
|
|
3306
|
-
formId: syncedFormId ??
|
|
3471
|
+
formId: syncedFormId ?? activeFormId ?? void 0,
|
|
3472
|
+
skipValidation: localPreview,
|
|
3307
3473
|
resolveFormId,
|
|
3308
3474
|
// Dev chrome (preview or dev env) surfaces the developer-grade resolution
|
|
3309
3475
|
// failure (message + code); an explicit option wins.
|
|
@@ -3312,7 +3478,7 @@ function FilloProvider({
|
|
|
3312
3478
|
// method; recorded per response so usage stays measurable.
|
|
3313
3479
|
surface: "headless"
|
|
3314
3480
|
});
|
|
3315
|
-
useDraftFlush(api);
|
|
3481
|
+
useDraftFlush(api, !localPreview);
|
|
3316
3482
|
const freshWarningCode = resyncWarning ? resyncWarning.code : warningCode;
|
|
3317
3483
|
const freshWarningUrl = resyncWarning ? resyncWarning.url : warningUrl;
|
|
3318
3484
|
const freshUploadsAvailable = resyncWarning ? resyncWarning.uploadsAvailable : uploadsAvailable;
|
|
@@ -3320,20 +3486,32 @@ function FilloProvider({
|
|
|
3320
3486
|
const chromeValue = useMemo6(
|
|
3321
3487
|
() => ({
|
|
3322
3488
|
devChrome,
|
|
3489
|
+
renderOnly: localPreview,
|
|
3323
3490
|
uploadsAvailable: freshUploadsAvailable,
|
|
3324
3491
|
uploadFileSizeLimitMb: freshUploadFileSizeLimitMb,
|
|
3325
3492
|
warningCode: freshWarningCode,
|
|
3326
3493
|
warningUrl: freshWarningUrl
|
|
3327
3494
|
}),
|
|
3328
|
-
[
|
|
3495
|
+
[
|
|
3496
|
+
devChrome,
|
|
3497
|
+
localPreview,
|
|
3498
|
+
freshUploadsAvailable,
|
|
3499
|
+
freshUploadFileSizeLimitMb,
|
|
3500
|
+
freshWarningCode,
|
|
3501
|
+
freshWarningUrl
|
|
3502
|
+
]
|
|
3329
3503
|
);
|
|
3330
3504
|
const resolvedStrings = resolveStrings2(strings);
|
|
3331
|
-
|
|
3505
|
+
if (targetError) {
|
|
3506
|
+
if (renderError) return /* @__PURE__ */ jsx9(Fragment4, { children: renderError(targetError) });
|
|
3507
|
+
throw targetError;
|
|
3508
|
+
}
|
|
3509
|
+
const canonicalSyncError = syncError && !localPreview ? syncError : null;
|
|
3332
3510
|
if (canonicalSyncError && renderError) return /* @__PURE__ */ jsx9(Fragment4, { children: renderError(canonicalSyncError) });
|
|
3333
3511
|
if (canonicalSyncError && !devChrome) return null;
|
|
3334
|
-
if (codeFormSyncing && !
|
|
3335
|
-
const notPublished = Boolean(codeForm) && syncedStatus === "draft" && !
|
|
3336
|
-
const notAccepting = Boolean(codeForm) && syncedStatus === "published" && syncedAccepting === false && !
|
|
3512
|
+
if (codeFormSyncing && !localPreview && !devChrome) return null;
|
|
3513
|
+
const notPublished = Boolean(codeForm) && syncedStatus === "draft" && !localPreview;
|
|
3514
|
+
const notAccepting = Boolean(codeForm) && syncedStatus === "published" && syncedAccepting === false && !localPreview;
|
|
3337
3515
|
if ((notPublished || notAccepting) && !devChrome) {
|
|
3338
3516
|
const error = notPublished ? new FilloError3("This form isn't published yet.", 403, void 0, "form_not_published") : new FilloError3(
|
|
3339
3517
|
"This form is no longer accepting responses.",
|
|
@@ -3348,7 +3526,7 @@ function FilloProvider({
|
|
|
3348
3526
|
|
|
3349
3527
|
// src/index.ts
|
|
3350
3528
|
import {
|
|
3351
|
-
createClient as
|
|
3529
|
+
createClient as createClient3,
|
|
3352
3530
|
provisionWorkspace,
|
|
3353
3531
|
when,
|
|
3354
3532
|
FilloJsxError as FilloJsxError2,
|
|
@@ -3375,7 +3553,7 @@ export {
|
|
|
3375
3553
|
FilloJsxError2 as FilloJsxError,
|
|
3376
3554
|
FilloProvider,
|
|
3377
3555
|
FormField,
|
|
3378
|
-
|
|
3556
|
+
createClient3 as createClient,
|
|
3379
3557
|
defineForm,
|
|
3380
3558
|
provisionWorkspace,
|
|
3381
3559
|
useField,
|