@form-engine-ts/react 2.9.5 → 3.0.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.js CHANGED
@@ -1214,6 +1214,11 @@ var BUILDER_DEFAULTS = {
1214
1214
  "builder.translating": "Translating\u2026",
1215
1215
  "builder.translationLocale": "Translation locale",
1216
1216
  "builder.selectLocale": "Select a locale to edit translations.",
1217
+ "builder.localization.selectLocaleToAdd": "Select a locale to add",
1218
+ "builder.localization.noLocalesConfigured": "Translations not configured",
1219
+ "builder.localization.localesConfiguredSummary": "{{count}} locales configured",
1220
+ "builder.localization.allLocalesAdded": "\u3059\u3079\u3066\u306E\u5019\u88DC\u8A00\u8A9E\u304C\u8FFD\u52A0\u6E08\u307F\u3067\u3059",
1221
+ "builder.localization.maxLocalesReached": "\u767B\u9332\u53EF\u80FD\u306A\u6700\u5927\u8A00\u8A9E\u6570\uFF08{{max}}\uFF09\u306B\u9054\u3057\u307E\u3057\u305F",
1217
1222
  "builder.translation": "{{locale}} translation",
1218
1223
  "builder.translatedFormTitle": "Translated form title",
1219
1224
  "builder.translatedFormDescription": "Translated form description",
@@ -2585,6 +2590,18 @@ import {
2585
2590
  validatePageAnswers
2586
2591
  } from "@form-engine-ts/core";
2587
2592
  import { createContext as createContext2, useCallback as useCallback2, useContext as useContext2, useEffect, useMemo as useMemo2, useRef, useState as useState2 } from "react";
2593
+
2594
+ // src/types.ts
2595
+ var FormSubmissionError = class extends Error {
2596
+ payload;
2597
+ constructor(message, payload) {
2598
+ super(message);
2599
+ this.name = "FormSubmissionError";
2600
+ this.payload = payload ?? { formError: message };
2601
+ }
2602
+ };
2603
+
2604
+ // src/context.tsx
2588
2605
  import { jsx as jsx2 } from "react/jsx-runtime";
2589
2606
  var FormContext = createContext2(null);
2590
2607
  function issuesByField(issues) {
@@ -2592,6 +2609,18 @@ function issuesByField(issues) {
2592
2609
  for (const issue of issues) result[issue.fieldId] ??= issue;
2593
2610
  return result;
2594
2611
  }
2612
+ function defaultAttemptId2() {
2613
+ const randomUuid = globalThis.crypto?.randomUUID;
2614
+ if (typeof randomUuid === "function") return randomUuid.call(globalThis.crypto);
2615
+ return `attempt-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;
2616
+ }
2617
+ function isServerErrorPayload(value) {
2618
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
2619
+ const record = value;
2620
+ const fieldErrors = record.fieldErrors;
2621
+ const formError = record.formError;
2622
+ return (Object.hasOwn(record, "fieldErrors") || Object.hasOwn(record, "formError")) && (fieldErrors === void 0 || typeof fieldErrors === "object" && fieldErrors !== null && !Array.isArray(fieldErrors) && Object.values(fieldErrors).every((message) => typeof message === "string")) && (formError === void 0 || typeof formError === "string");
2623
+ }
2595
2624
  function FormProvider({
2596
2625
  schema,
2597
2626
  locale,
@@ -2635,6 +2664,17 @@ function FormProvider({
2635
2664
  },
2636
2665
  [validSchema, validationPageIndex]
2637
2666
  );
2667
+ const setServerErrors = useCallback2((fieldErrors) => {
2668
+ setErrors(
2669
+ Object.fromEntries(
2670
+ Object.entries(fieldErrors).map(([fieldId, message]) => [
2671
+ fieldId,
2672
+ { fieldId, code: "invalid_type", messageKey: message, params: {} }
2673
+ ])
2674
+ )
2675
+ );
2676
+ setValidationPageIndex(null);
2677
+ }, []);
2638
2678
  const restoreValues = useCallback2(
2639
2679
  (restoredValues) => {
2640
2680
  const fieldIds = new Set(validSchema.fields.map((field) => field.id));
@@ -2665,7 +2705,7 @@ function FormProvider({
2665
2705
  setSubmitError(null);
2666
2706
  }, [initialValues]);
2667
2707
  const submit = useCallback2(
2668
- async (beforeSubmit, prepareSubmission) => {
2708
+ async (beforeSubmit, submitContext) => {
2669
2709
  if (submissionInFlight.current) return { status: "cancelled" };
2670
2710
  const validation = validateAnswers(validSchema, values);
2671
2711
  if (!validation.valid) {
@@ -2686,13 +2726,22 @@ function FormProvider({
2686
2726
  setSubmitStatus("idle");
2687
2727
  return { status: "cancelled" };
2688
2728
  }
2689
- const submissionValues = prepareSubmission === void 0 ? visibleValues : await prepareSubmission(visibleValues);
2690
- const response = await onSubmit(submissionValues);
2729
+ const context = submitContext ?? {
2730
+ attemptId: defaultAttemptId2(),
2731
+ formId: validSchema.id,
2732
+ formVersion: validSchema.version,
2733
+ locale,
2734
+ submittedAt: (/* @__PURE__ */ new Date()).toISOString()
2735
+ };
2736
+ const response = await onSubmit({ ...visibleValues }, context);
2691
2737
  if (resetOnSuccess) setValues({ ...initialValues });
2692
2738
  setSubmitStatus("success");
2693
2739
  return response === void 0 ? { status: "success" } : { status: "success", response };
2694
2740
  } catch (cause) {
2695
- const error = cause instanceof Error ? cause : new Error(String(cause));
2741
+ const error = isServerErrorPayload(cause) ? new FormSubmissionError(
2742
+ cause.formError ?? (cause instanceof Error ? cause.message : "Form submission failed."),
2743
+ cause
2744
+ ) : cause instanceof Error ? cause : new Error(String(cause));
2696
2745
  setSubmitError(error);
2697
2746
  setSubmitStatus("error");
2698
2747
  return { status: "error", error };
@@ -2700,7 +2749,7 @@ function FormProvider({
2700
2749
  submissionInFlight.current = false;
2701
2750
  }
2702
2751
  },
2703
- [initialValues, onSubmit, resetOnSuccess, validSchema, values]
2752
+ [initialValues, locale, onSubmit, resetOnSuccess, validSchema, values]
2704
2753
  );
2705
2754
  const translate = useCallback2(
2706
2755
  (key, params) => translator.translate(key, locale, params),
@@ -2719,6 +2768,7 @@ function FormProvider({
2719
2768
  submitError,
2720
2769
  isSubmitting: submitStatus === "submitting",
2721
2770
  setValue,
2771
+ setServerErrors,
2722
2772
  restoreValues,
2723
2773
  validatePage,
2724
2774
  reset,
@@ -2732,6 +2782,7 @@ function FormProvider({
2732
2782
  reset,
2733
2783
  restoreValues,
2734
2784
  setValue,
2785
+ setServerErrors,
2735
2786
  submit,
2736
2787
  submitError,
2737
2788
  submitStatus,
@@ -2882,6 +2933,7 @@ import {
2882
2933
  } from "@form-engine-ts/core";
2883
2934
  import {
2884
2935
  Fragment as Fragment2,
2936
+ useCallback as useCallback3,
2885
2937
  useEffect as useEffect3,
2886
2938
  useId,
2887
2939
  useMemo as useMemo4,
@@ -3074,7 +3126,11 @@ function DefaultField(props) {
3074
3126
  fieldId: field.id,
3075
3127
  current: typeof value === "string" ? value.length : 0,
3076
3128
  max: field.maxLength
3077
- }) : null,
3129
+ }) ?? /* @__PURE__ */ jsxs2("div", { className: "fe-character-count", "aria-live": "polite", children: [
3130
+ typeof value === "string" ? value.length : 0,
3131
+ " / ",
3132
+ field.maxLength
3133
+ ] }) : null,
3078
3134
  /* @__PURE__ */ jsx3(FieldMessage, { props })
3079
3135
  ] });
3080
3136
  }
@@ -3084,6 +3140,30 @@ function isRecord(value) {
3084
3140
  function isFormValue(value) {
3085
3141
  return value === void 0 || typeof value === "string" || typeof value === "boolean" || typeof value === "number" && Number.isFinite(value) || Array.isArray(value) && value.every((item) => typeof item === "string");
3086
3142
  }
3143
+ function displaySubmittedValue(field, value, translate) {
3144
+ if (value === void 0 || value === null) return "";
3145
+ if (field.type === "checkbox") return value === true ? translate("form.yes") : translate("form.no");
3146
+ if (field.type === "multi-select" && Array.isArray(value)) {
3147
+ const labels = new Map(field.options.map((option) => [option.id, option.label]));
3148
+ return value.map((item) => labels.get(item) ?? item).join(", ");
3149
+ }
3150
+ if ((field.type === "radio" || field.type === "select") && typeof value === "string") {
3151
+ return field.options.find((option) => option.id === value)?.label ?? value;
3152
+ }
3153
+ if (Array.isArray(value)) return value.join(", ");
3154
+ return String(value);
3155
+ }
3156
+ function buildSubmittedItems(schema, answers, visibility, translate, showHiddenFields) {
3157
+ return schema.fields.filter((field) => showHiddenFields || visibility[field.id] === true).map((field) => ({
3158
+ fieldId: field.id,
3159
+ title: field.title,
3160
+ type: field.type,
3161
+ rawValue: answers[field.id],
3162
+ displayValue: displaySubmittedValue(field, answers[field.id], translate),
3163
+ visible: visibility[field.id] === true,
3164
+ ...field.metadata === void 0 ? {} : { metadata: field.metadata }
3165
+ }));
3166
+ }
3087
3167
  function parseDraft(serialized) {
3088
3168
  try {
3089
3169
  const value = JSON.parse(serialized);
@@ -3102,15 +3182,65 @@ function parseDraft(serialized) {
3102
3182
  return null;
3103
3183
  }
3104
3184
  }
3185
+ var DEFAULT_RENDERER_MESSAGES = {
3186
+ en: {
3187
+ submitButton: "Submit",
3188
+ submittingButton: "Submitting...",
3189
+ retryButton: "Retry",
3190
+ requiredField: "This field is required.",
3191
+ alreadySubmittedTitle: "Already Submitted",
3192
+ alreadySubmittedMessage: "Already submitted.",
3193
+ serverErrorSummary: "Submission failed. Please check your answers and try again.",
3194
+ confirmSensitiveDataTitle: "Sensitive data may be included",
3195
+ confirmSensitiveDataMessage: "The following answers may contain personal information. Continue submitting?",
3196
+ confirmButton: "Proceed",
3197
+ cancelButton: "Cancel"
3198
+ },
3199
+ ja: {
3200
+ submitButton: "\u9001\u4FE1\u3059\u308B",
3201
+ submittingButton: "\u9001\u4FE1\u4E2D...",
3202
+ retryButton: "\u518D\u9001\u4FE1\u3059\u308B",
3203
+ requiredField: "\u3053\u306E\u9805\u76EE\u306F\u5FC5\u9808\u3067\u3059",
3204
+ alreadySubmittedTitle: "\u56DE\u7B54\u6E08\u307F\u3067\u3059",
3205
+ alreadySubmittedMessage: "\u3053\u306E\u30A2\u30F3\u30B1\u30FC\u30C8\u306B\u306F\u3059\u3067\u306B\u56DE\u7B54\u3057\u3066\u3044\u307E\u3059\u3002",
3206
+ serverErrorSummary: "\u9001\u4FE1\u306B\u5931\u6557\u3057\u307E\u3057\u305F\u3002\u5185\u5BB9\u3092\u3054\u78BA\u8A8D\u306E\u4E0A\u3001\u518D\u5EA6\u304A\u8A66\u3057\u304F\u3060\u3055\u3044\u3002",
3207
+ confirmSensitiveDataTitle: "\u500B\u4EBA\u60C5\u5831\u304C\u542B\u307E\u308C\u3066\u3044\u308B\u53EF\u80FD\u6027\u304C\u3042\u308A\u307E\u3059",
3208
+ confirmSensitiveDataMessage: "\u4EE5\u4E0B\u306E\u9805\u76EE\u306B\u500B\u4EBA\u60C5\u5831\u3068\u307F\u3089\u308C\u308B\u8A18\u8FF0\u304C\u3042\u308A\u307E\u3059\u3002\u3053\u306E\u307E\u307E\u9001\u4FE1\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B\uFF1F",
3209
+ confirmButton: "\u3053\u306E\u307E\u307E\u9001\u4FE1",
3210
+ cancelButton: "\u4FEE\u6B63\u3059\u308B"
3211
+ }
3212
+ };
3213
+ function createRendererAttemptId() {
3214
+ const randomUuid = globalThis.crypto?.randomUUID;
3215
+ if (typeof randomUuid === "function") return randomUuid.call(globalThis.crypto);
3216
+ return `attempt-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;
3217
+ }
3218
+ function maskSensitiveValue(finding) {
3219
+ if (finding.maskedText !== void 0) return finding.maskedText;
3220
+ const value = finding.matchedText;
3221
+ if (value === void 0) return void 0;
3222
+ if (finding.type === "email") {
3223
+ const separator = value.indexOf("@");
3224
+ if (separator > 0) return `${value.slice(0, Math.min(2, separator))}***${value.slice(separator)}`;
3225
+ }
3226
+ if (finding.type === "phone" || finding.type === "postal_code") return "***";
3227
+ return value.length <= 2 ? "***" : `${value.slice(0, 2)}***`;
3228
+ }
3105
3229
  function ContextFormRenderer({
3106
3230
  components = {},
3107
3231
  className = "",
3108
3232
  successMessageKey,
3109
3233
  errorMessageKey,
3234
+ attemptIdFactory,
3235
+ messages = {},
3236
+ messageResolver,
3110
3237
  autoSaveKey,
3111
3238
  beforeSubmit,
3112
3239
  onDraftSave,
3113
3240
  successRenderMode = "append",
3241
+ submissionConfirmationRenderMode = "inline",
3242
+ showHiddenFieldsInSummary = false,
3243
+ fieldsClassName,
3114
3244
  hideFormOnSuccess = false,
3115
3245
  submissionGuards = [],
3116
3246
  receiptStore,
@@ -3129,9 +3259,12 @@ function ContextFormRenderer({
3129
3259
  const [guardMessage, setGuardMessage] = useState4(null);
3130
3260
  const [guardsPending, setGuardsPending] = useState4(false);
3131
3261
  const [receipt, setReceipt] = useState4(null);
3262
+ const [completionData, setCompletionData] = useState4(null);
3132
3263
  const [receiptLoaded, setReceiptLoaded] = useState4(receiptStore === void 0);
3133
3264
  const rendererSubmissionInFlight = useRef2(false);
3265
+ const fallbackAttemptId = useRef2(null);
3134
3266
  const completionRef = useRef2(null);
3267
+ const confirmationRef = useRef2(null);
3135
3268
  const pages = form.schema.pages;
3136
3269
  const visiblePageIndexes = useMemo4(
3137
3270
  () => pages === void 0 ? [] : pages.flatMap((page, index) => form.pageVisibility[page.id] === true ? [index] : []),
@@ -3144,6 +3277,22 @@ function ContextFormRenderer({
3144
3277
  const submitState = confirmation === null && !guardsPending ? form.submitStatus : "confirming";
3145
3278
  const interactionLocked = submitState === "confirming" || submitState === "submitting";
3146
3279
  const isReplaceMode = successRenderMode === "replace" || hideFormOnSuccess;
3280
+ const resolveMessage = useCallback3(
3281
+ (key, fallback) => {
3282
+ const defaultText = fallback ?? DEFAULT_RENDERER_MESSAGES[form.locale.toLowerCase().startsWith("ja") ? "ja" : "en"][key] ?? key;
3283
+ const configured = messages[key];
3284
+ return messageResolver?.(key, configured ?? defaultText) ?? configured ?? defaultText;
3285
+ },
3286
+ [form.locale, messageResolver, messages]
3287
+ );
3288
+ const fieldTranslate = useCallback3(
3289
+ (key, params) => key === "validation.required" && (messages.requiredField !== void 0 || messageResolver !== void 0) ? resolveMessage("requiredField") : form.translate(key, params),
3290
+ [form.translate, messageResolver, messages.requiredField, resolveMessage]
3291
+ );
3292
+ const focusSubmitButton = useCallback3(() => {
3293
+ const button = formRef.current?.querySelector(".fe-submit, button[type='submit'], button");
3294
+ button?.focus();
3295
+ }, []);
3147
3296
  useEffect3(() => {
3148
3297
  let active = true;
3149
3298
  if (receiptStore === void 0) {
@@ -3179,6 +3328,7 @@ function ContextFormRenderer({
3179
3328
  );
3180
3329
  const control = fieldContainer?.querySelector("input, select, textarea");
3181
3330
  if (control !== void 0 && control !== null) {
3331
+ control.scrollIntoView?.({ behavior: "smooth", block: "center" });
3182
3332
  control.focus();
3183
3333
  setFocusFieldId(null);
3184
3334
  }
@@ -3187,6 +3337,38 @@ function ContextFormRenderer({
3187
3337
  if (!isReplaceMode || form.submitStatus !== "success") return;
3188
3338
  completionRef.current?.focus();
3189
3339
  }, [form.submitStatus, isReplaceMode]);
3340
+ useEffect3(() => {
3341
+ if (confirmation === null) return;
3342
+ const confirmButton = confirmationRef.current?.querySelector("[data-fe-confirm], button");
3343
+ confirmButton?.focus();
3344
+ if (submissionConfirmationRenderMode !== "dialog") return;
3345
+ const onKeyDown = (event) => {
3346
+ if (event.key === "Escape") {
3347
+ event.preventDefault();
3348
+ setConfirmation(null);
3349
+ globalThis.setTimeout(focusSubmitButton, 0);
3350
+ return;
3351
+ }
3352
+ if (event.key !== "Tab") return;
3353
+ const focusable = [
3354
+ ...confirmationRef.current?.querySelectorAll(
3355
+ "button, [href], input, select, textarea, [tabindex]:not([tabindex='-1'])"
3356
+ ) ?? []
3357
+ ].filter((element) => !element.hasAttribute("disabled"));
3358
+ if (focusable.length === 0) return;
3359
+ const first = focusable[0];
3360
+ const last = focusable[focusable.length - 1];
3361
+ if (event.shiftKey && document.activeElement === first) {
3362
+ event.preventDefault();
3363
+ last?.focus();
3364
+ } else if (!event.shiftKey && document.activeElement === last) {
3365
+ event.preventDefault();
3366
+ first?.focus();
3367
+ }
3368
+ };
3369
+ globalThis.addEventListener("keydown", onKeyDown);
3370
+ return () => globalThis.removeEventListener("keydown", onKeyDown);
3371
+ }, [confirmation, focusSubmitButton, submissionConfirmationRenderMode]);
3190
3372
  useEffect3(() => {
3191
3373
  if (autoSaveKey === void 0 || typeof globalThis.localStorage === "undefined") return;
3192
3374
  const loadIdentity = `${autoSaveKey}:${form.schema.id}:${form.schema.version}`;
@@ -3283,17 +3465,24 @@ function ContextFormRenderer({
3283
3465
  rendererSubmissionInFlight.current = true;
3284
3466
  try {
3285
3467
  let submissionAttempt;
3286
- const result = await form.submit(
3287
- beforeSubmit,
3288
- attemptStore === void 0 ? void 0 : async (values) => {
3289
- submissionAttempt = await attemptStore.getOrCreate(form.schema.id, form.schema.version);
3290
- return {
3291
- ...values,
3292
- attemptId: submissionAttempt.attemptId,
3293
- submissionId: submissionAttempt.attemptId
3294
- };
3295
- }
3296
- );
3468
+ let attemptId = fallbackAttemptId.current;
3469
+ if (attemptStore !== void 0) {
3470
+ submissionAttempt = await attemptStore.getOrCreate(form.schema.id, form.schema.version, attemptIdFactory);
3471
+ attemptId = submissionAttempt.attemptId;
3472
+ } else if (attemptId === null) {
3473
+ attemptId = attemptIdFactory?.() ?? createRendererAttemptId();
3474
+ fallbackAttemptId.current = attemptId;
3475
+ }
3476
+ if (attemptId === null) throw new Error("Unable to create a submission attempt id.");
3477
+ const submittedAt = (/* @__PURE__ */ new Date()).toISOString();
3478
+ const submitContext = {
3479
+ attemptId,
3480
+ formId: form.schema.id,
3481
+ formVersion: form.schema.version,
3482
+ locale: form.locale,
3483
+ submittedAt
3484
+ };
3485
+ const result = await form.submit(beforeSubmit, submitContext);
3297
3486
  if (result.status === "invalid") {
3298
3487
  const invalidPageIndex = pages?.findIndex(
3299
3488
  (page) => firstInvalidFieldId === void 0 ? false : page.questionIds.includes(firstInvalidFieldId)
@@ -3302,14 +3491,40 @@ function ContextFormRenderer({
3302
3491
  focusFirstIssue(firstInvalidFieldId);
3303
3492
  return result;
3304
3493
  }
3494
+ if (result.status === "error") {
3495
+ if (result.error instanceof FormSubmissionError) {
3496
+ const fieldErrors = result.error.payload.fieldErrors ?? {};
3497
+ form.setServerErrors?.(fieldErrors);
3498
+ const firstServerFieldId = form.schema.fields.find((field) => Object.hasOwn(fieldErrors, field.id))?.id ?? Object.keys(fieldErrors)[0];
3499
+ if (firstServerFieldId !== void 0) {
3500
+ const invalidPageIndex = pages?.findIndex((page) => page.questionIds.includes(firstServerFieldId));
3501
+ if (invalidPageIndex !== void 0 && invalidPageIndex >= 0) setCurrentPageIndex(invalidPageIndex);
3502
+ focusFirstIssue(firstServerFieldId);
3503
+ }
3504
+ }
3505
+ return result;
3506
+ }
3305
3507
  if (result.status !== "success") return result;
3508
+ const submittedAnswers = { ...form.values };
3509
+ const submittedItems = buildSubmittedItems(
3510
+ form.schema,
3511
+ submittedAnswers,
3512
+ form.visibility,
3513
+ (key) => form.translate(key),
3514
+ showHiddenFieldsInSummary
3515
+ );
3516
+ setCompletionData({
3517
+ answers: submittedAnswers,
3518
+ submittedItems,
3519
+ ...result.response === void 0 ? {} : { response: result.response }
3520
+ });
3306
3521
  if (receiptStore !== void 0) {
3307
3522
  const response = result.response;
3308
- const submissionId = response?.submissionId ?? submissionAttempt?.attemptId;
3523
+ const submissionId = response?.submissionId ?? submissionAttempt?.attemptId ?? attemptId;
3309
3524
  const storedReceipt = {
3310
3525
  formId: form.schema.id,
3311
3526
  formVersion: form.schema.version,
3312
- submittedAt: response?.submittedAt ?? (/* @__PURE__ */ new Date()).toISOString(),
3527
+ submittedAt: response?.submittedAt ?? submittedAt,
3313
3528
  ...submissionId === void 0 ? {} : { submissionId }
3314
3529
  };
3315
3530
  try {
@@ -3328,6 +3543,7 @@ function ContextFormRenderer({
3328
3543
  } catch {
3329
3544
  }
3330
3545
  }
3546
+ if (attemptStore === void 0) fallbackAttemptId.current = null;
3331
3547
  if (autoSaveKey !== void 0 && typeof globalThis.localStorage !== "undefined") {
3332
3548
  globalThis.localStorage.removeItem(autoSaveKey);
3333
3549
  setDraftRestored(false);
@@ -3349,6 +3565,7 @@ function ContextFormRenderer({
3349
3565
  };
3350
3566
  const cancelSubmission = () => {
3351
3567
  setConfirmation(null);
3568
+ globalThis.setTimeout(focusSubmitButton, 0);
3352
3569
  };
3353
3570
  const resetReceipt = async () => {
3354
3571
  if (receiptStore === void 0) return;
@@ -3366,144 +3583,220 @@ function ContextFormRenderer({
3366
3583
  disabled: interactionLocked || submitState === "success",
3367
3584
  onSubmit: () => void submitValues()
3368
3585
  };
3369
- return slots.renderSubmitButton?.(submitButtonProps) ?? /* @__PURE__ */ jsx3("button", { className: "fe-submit", type: "submit", disabled: submitButtonProps.disabled, children: form.translate(form.schema.submitLabelKey ?? "form.submit") });
3586
+ return slots.renderSubmitButton?.(submitButtonProps) ?? /* @__PURE__ */ jsxs2("button", { className: "fe-submit", type: "submit", disabled: submitButtonProps.disabled, children: [
3587
+ submitState === "submitting" ? /* @__PURE__ */ jsx3("span", { className: "fe-spinner", "aria-hidden": "true" }) : null,
3588
+ submitState === "submitting" ? resolveMessage("submittingButton") : resolveMessage("submitButton", form.translate(form.schema.submitLabelKey ?? "form.submit"))
3589
+ ] });
3370
3590
  };
3371
3591
  const completionMessage = form.schema.completionMessage ?? (successMessageKey === void 0 ? "Submitted." : form.translate(successMessageKey));
3372
- const completionRegion = /* @__PURE__ */ jsx3("div", { ref: completionRef, className: "fe-completion", role: "status", "aria-live": "polite", tabIndex: -1, children: slots.renderCompletion?.({ message: completionMessage }) ?? /* @__PURE__ */ jsx3("div", { children: completionMessage }) });
3592
+ const activeCompletionData = completionData ?? {
3593
+ answers: { ...form.values },
3594
+ submittedItems: buildSubmittedItems(
3595
+ form.schema,
3596
+ form.values,
3597
+ form.visibility,
3598
+ (key) => form.translate(key),
3599
+ showHiddenFieldsInSummary
3600
+ )
3601
+ };
3602
+ const completionProps = {
3603
+ message: completionMessage,
3604
+ schema: form.schema,
3605
+ answers: activeCompletionData.answers,
3606
+ submittedItems: activeCompletionData.submittedItems,
3607
+ ...activeCompletionData.response === void 0 ? {} : { response: activeCompletionData.response },
3608
+ onReset: form.reset
3609
+ };
3610
+ const completionRegion = /* @__PURE__ */ jsxs2("div", { ref: completionRef, className: "fe-completion", role: "status", "aria-live": "polite", tabIndex: -1, children: [
3611
+ slots.renderCompletion?.(completionProps) ?? /* @__PURE__ */ jsx3("div", { children: completionMessage }),
3612
+ slots.renderSubmittedValues?.({ items: activeCompletionData.submittedItems, schema: form.schema })
3613
+ ] });
3614
+ const confirmationContent = /* @__PURE__ */ jsx3(
3615
+ "div",
3616
+ {
3617
+ ref: confirmationRef,
3618
+ className: "fe-submission-confirmation",
3619
+ role: submissionConfirmationRenderMode === "dialog" ? void 0 : "dialog",
3620
+ children: slots.renderSubmissionConfirmation?.({
3621
+ findings: confirmation?.findings ?? [],
3622
+ message: confirmation?.message ?? resolveMessage("confirmSensitiveDataMessage", form.translate("form.confirmSensitiveData")),
3623
+ schema: form.schema,
3624
+ visibleValues,
3625
+ onConfirm: confirmSubmission,
3626
+ onCancel: cancelSubmission
3627
+ }) ?? /* @__PURE__ */ jsxs2(Fragment3, { children: [
3628
+ /* @__PURE__ */ jsx3("h2", { children: resolveMessage("confirmSensitiveDataTitle") }),
3629
+ /* @__PURE__ */ jsx3("p", { children: confirmation?.message ?? resolveMessage("confirmSensitiveDataMessage", form.translate("form.confirmSensitiveData")) }),
3630
+ (confirmation?.findings ?? []).length === 0 ? null : /* @__PURE__ */ jsx3("ul", { children: (confirmation?.findings ?? []).map((finding, index) => {
3631
+ const field = form.schema.fields.find((candidate) => candidate.id === finding.fieldId);
3632
+ const typeLabels = form.locale.toLowerCase().startsWith("ja") ? { email: "\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9", phone: "\u96FB\u8A71\u756A\u53F7", url: "URL", postal_code: "\u90F5\u4FBF\u756A\u53F7" } : { email: "Email address", phone: "Phone number", url: "URL", postal_code: "Postal code" };
3633
+ const typeLabel = finding.typeLabel ?? typeLabels[finding.type] ?? finding.type;
3634
+ const value = maskSensitiveValue(finding);
3635
+ return /* @__PURE__ */ jsxs2("li", { children: [
3636
+ /* @__PURE__ */ jsx3("span", { children: finding.fieldTitle ?? field?.title ?? finding.fieldId }),
3637
+ " ",
3638
+ /* @__PURE__ */ jsx3("span", { className: "fe-sensitive-type", children: typeLabel }),
3639
+ value === void 0 ? null : /* @__PURE__ */ jsxs2("span", { className: "fe-sensitive-value", children: [
3640
+ " ",
3641
+ value
3642
+ ] })
3643
+ ] }, `${finding.fieldId}-${finding.type}-${finding.start ?? index}`);
3644
+ }) }),
3645
+ /* @__PURE__ */ jsx3("button", { type: "button", "data-fe-confirm": "true", onClick: confirmSubmission, children: resolveMessage("confirmButton", form.translate("form.confirmSubmission")) }),
3646
+ /* @__PURE__ */ jsx3("button", { type: "button", onClick: cancelSubmission, children: resolveMessage("cancelButton", form.translate("form.cancelSubmission")) })
3647
+ ] })
3648
+ }
3649
+ );
3373
3650
  if (!receiptLoaded) return null;
3374
3651
  if (receipt !== null) {
3375
3652
  return /* @__PURE__ */ jsx3("div", { className: `fe-form fe-already-submitted ${className}`.trim(), children: slots.renderAlreadySubmitted?.({
3376
3653
  receipt,
3377
3654
  ...receiptStore === void 0 ? {} : { onReset: () => void resetReceipt() }
3378
3655
  }) ?? /* @__PURE__ */ jsxs2("div", { role: "status", children: [
3379
- form.translate("form.alreadySubmitted"),
3380
- receiptStore === void 0 ? null : /* @__PURE__ */ jsx3("button", { type: "button", onClick: () => void resetReceipt(), children: form.translate("form.submitAnother") })
3656
+ /* @__PURE__ */ jsx3("h2", { children: resolveMessage("alreadySubmittedTitle") }),
3657
+ /* @__PURE__ */ jsx3("p", { children: resolveMessage("alreadySubmittedMessage", form.translate("form.alreadySubmitted")) }),
3658
+ receiptStore === void 0 ? null : /* @__PURE__ */ jsx3("button", { type: "button", onClick: () => void resetReceipt(), children: resolveMessage("submitButton", form.translate("form.submitAnother")) })
3381
3659
  ] }) });
3382
3660
  }
3383
3661
  if (form.submitStatus === "success" && isReplaceMode) {
3384
3662
  return /* @__PURE__ */ jsx3("div", { className: `fe-form ${className}`.trim(), children: completionRegion });
3385
3663
  }
3386
- return /* @__PURE__ */ jsxs2("form", { ref: formRef, className: `fe-form ${className}`.trim(), noValidate: true, onSubmit: handleSubmit, children: [
3387
- slots.renderHeader?.({
3388
- title: form.schema.title,
3389
- ...form.schema.description === void 0 ? {} : { description: form.schema.description }
3390
- }) ?? /* @__PURE__ */ jsxs2("header", { className: "fe-header", children: [
3391
- /* @__PURE__ */ jsx3("h1", { children: form.schema.title }),
3392
- form.schema.description === void 0 ? null : /* @__PURE__ */ jsx3("p", { children: form.schema.description }),
3393
- pages === void 0 ? null : /* @__PURE__ */ jsxs2("div", { className: "fe-progress", children: [
3394
- /* @__PURE__ */ jsx3(
3395
- "div",
3396
- {
3397
- className: "form-progress-bar",
3398
- role: "progressbar",
3399
- "aria-valuemin": 1,
3400
- "aria-valuemax": visiblePageIndexes.length,
3401
- "aria-valuenow": activeVisibleIndex + 1,
3402
- children: /* @__PURE__ */ jsx3(
3403
- "div",
3404
- {
3405
- className: "form-progress-fill",
3406
- style: { width: `${(activeVisibleIndex + 1) / visiblePageIndexes.length * 100}%` }
3664
+ if (confirmation !== null && submissionConfirmationRenderMode === "replace") {
3665
+ return /* @__PURE__ */ jsx3("div", { className: `fe-form ${className}`.trim(), children: confirmationContent });
3666
+ }
3667
+ return /* @__PURE__ */ jsxs2(Fragment3, { children: [
3668
+ /* @__PURE__ */ jsxs2(
3669
+ "form",
3670
+ {
3671
+ ref: formRef,
3672
+ className: `fe-form ${className}`.trim(),
3673
+ noValidate: true,
3674
+ onSubmit: handleSubmit,
3675
+ "aria-hidden": confirmation !== null && submissionConfirmationRenderMode === "dialog" ? true : void 0,
3676
+ children: [
3677
+ slots.renderHeader?.({
3678
+ title: form.schema.title,
3679
+ ...form.schema.description === void 0 ? {} : { description: form.schema.description }
3680
+ }) ?? /* @__PURE__ */ jsxs2("header", { className: "fe-header", children: [
3681
+ /* @__PURE__ */ jsx3("h1", { children: form.schema.title }),
3682
+ form.schema.description === void 0 ? null : /* @__PURE__ */ jsx3("p", { children: form.schema.description }),
3683
+ pages === void 0 ? null : /* @__PURE__ */ jsxs2("div", { className: "fe-progress", children: [
3684
+ /* @__PURE__ */ jsx3(
3685
+ "div",
3686
+ {
3687
+ className: "form-progress-bar",
3688
+ role: "progressbar",
3689
+ "aria-valuemin": 1,
3690
+ "aria-valuemax": visiblePageIndexes.length,
3691
+ "aria-valuenow": activeVisibleIndex + 1,
3692
+ children: /* @__PURE__ */ jsx3(
3693
+ "div",
3694
+ {
3695
+ className: "form-progress-fill",
3696
+ style: { width: `${(activeVisibleIndex + 1) / visiblePageIndexes.length * 100}%` }
3697
+ }
3698
+ )
3699
+ }
3700
+ ),
3701
+ /* @__PURE__ */ jsx3("span", { children: form.translate("form.step", { current: activeVisibleIndex + 1, total: visiblePageIndexes.length }) })
3702
+ ] }),
3703
+ draftRestored ? /* @__PURE__ */ jsx3("span", { className: "form-draft-badge", children: form.translate("form.draftRestored") }) : null
3704
+ ] }),
3705
+ activePage === void 0 ? null : slots.renderPageHeader?.({
3706
+ page: activePage,
3707
+ pageIndex: activeVisibleIndex,
3708
+ totalPages: visiblePageIndexes.length
3709
+ }) ?? /* @__PURE__ */ jsxs2("div", { className: "fe-page-header", children: [
3710
+ activePage.title === void 0 ? null : /* @__PURE__ */ jsx3("h2", { className: "fe-page-title", children: activePage.title }),
3711
+ activePage.description === void 0 ? null : /* @__PURE__ */ jsx3("p", { className: "fe-page-description", children: activePage.description })
3712
+ ] }),
3713
+ (() => {
3714
+ const fieldChildren = form.schema.fields.filter((field) => form.visibility[field.id] === true && (fieldIds === void 0 || fieldIds.has(field.id))).map((field) => {
3715
+ const error = form.errors[field.id];
3716
+ const props = {
3717
+ field,
3718
+ value: form.values[field.id],
3719
+ error,
3720
+ setValue: (value) => form.setValue(field.id, value),
3721
+ translate: fieldTranslate,
3722
+ inputId: `${prefix}-${field.id}`,
3723
+ errorId: `${prefix}-${field.id}-error`,
3724
+ helpId: `${prefix}-${field.id}-help`,
3725
+ ...slots.renderCharacterCount === void 0 ? {} : { renderCharacterCount: slots.renderCharacterCount }
3726
+ };
3727
+ if (slots.renderField !== void 0) {
3728
+ return /* @__PURE__ */ jsx3(Fragment2, { children: slots.renderField({
3729
+ question: field,
3730
+ value: form.values[field.id],
3731
+ onChange: (value) => {
3732
+ if (isFormValue(value)) form.setValue(field.id, value);
3733
+ },
3734
+ ...error === void 0 ? {} : { error }
3735
+ }) }, field.id);
3407
3736
  }
3408
- )
3409
- }
3410
- ),
3411
- /* @__PURE__ */ jsx3("span", { children: form.translate("form.step", { current: activeVisibleIndex + 1, total: visiblePageIndexes.length }) })
3412
- ] }),
3413
- draftRestored ? /* @__PURE__ */ jsx3("span", { className: "form-draft-badge", children: form.translate("form.draftRestored") }) : null
3414
- ] }),
3415
- activePage === void 0 ? null : slots.renderPageHeader?.({
3416
- page: activePage,
3417
- pageIndex: activeVisibleIndex,
3418
- totalPages: visiblePageIndexes.length
3419
- }) ?? /* @__PURE__ */ jsxs2("div", { className: "fe-page-header", children: [
3420
- activePage.title === void 0 ? null : /* @__PURE__ */ jsx3("h2", { className: "fe-page-title", children: activePage.title }),
3421
- activePage.description === void 0 ? null : /* @__PURE__ */ jsx3("p", { className: "fe-page-description", children: activePage.description })
3422
- ] }),
3423
- /* @__PURE__ */ jsx3("div", { className: "fe-fields", children: form.schema.fields.filter((field) => form.visibility[field.id] === true && (fieldIds === void 0 || fieldIds.has(field.id))).map((field) => {
3424
- const error = form.errors[field.id];
3425
- const props = {
3426
- field,
3427
- value: form.values[field.id],
3428
- error,
3429
- setValue: (value) => form.setValue(field.id, value),
3430
- translate: form.translate,
3431
- inputId: `${prefix}-${field.id}`,
3432
- errorId: `${prefix}-${field.id}-error`,
3433
- helpId: `${prefix}-${field.id}-help`,
3434
- ...slots.renderCharacterCount === void 0 ? {} : { renderCharacterCount: slots.renderCharacterCount }
3435
- };
3436
- if (slots.renderField !== void 0) {
3437
- return /* @__PURE__ */ jsx3(Fragment2, { children: slots.renderField({
3438
- question: field,
3439
- value: form.values[field.id],
3440
- onChange: (value) => {
3441
- if (isFormValue(value)) form.setValue(field.id, value);
3442
- },
3443
- ...error === void 0 ? {} : { error }
3444
- }) }, field.id);
3737
+ const Component = components[field.type];
3738
+ return Component === void 0 ? /* @__PURE__ */ jsx3(DefaultField, { ...props }, field.id) : /* @__PURE__ */ jsx3(Component, { ...props }, field.id);
3739
+ });
3740
+ const fieldClassName = `fe-fields${fieldsClassName === void 0 ? "" : ` ${fieldsClassName}`}`;
3741
+ return slots.renderFields?.({ children: fieldChildren, className: fieldClassName }) ?? /* @__PURE__ */ jsx3("div", { className: fieldClassName, children: fieldChildren });
3742
+ })(),
3743
+ guardMessage === null ? null : /* @__PURE__ */ jsx3("div", { role: "alert", children: guardMessage }),
3744
+ confirmation !== null && submissionConfirmationRenderMode === "inline" ? confirmationContent : null,
3745
+ validationIssues.length === 0 ? null : slots.renderValidationSummary?.({ issues: validationIssues }) ?? /* @__PURE__ */ jsxs2("div", { className: "fe-validation-summary", role: "alert", children: [
3746
+ validationIssues.length,
3747
+ " validation error",
3748
+ validationIssues.length === 1 ? "" : "s",
3749
+ "."
3750
+ ] }),
3751
+ pages === void 0 ? /* @__PURE__ */ jsxs2(Fragment3, { children: [
3752
+ slots.renderNavigation?.({
3753
+ currentPage: 0,
3754
+ totalPages: 1,
3755
+ canPrev: false,
3756
+ canNext: false,
3757
+ onPrev: () => void 0,
3758
+ onNext: () => void 0
3759
+ }),
3760
+ renderSubmitButton()
3761
+ ] }) : /* @__PURE__ */ jsxs2("div", { className: "form-step-navigation", children: [
3762
+ slots.renderNavigation?.({
3763
+ currentPage: activeVisibleIndex,
3764
+ totalPages: visiblePageIndexes.length,
3765
+ canPrev,
3766
+ canNext,
3767
+ onPrev: () => {
3768
+ if (!interactionLocked) setCurrentPageIndex(visiblePageIndexes[activeVisibleIndex - 1] ?? 0);
3769
+ },
3770
+ onNext: handleNext
3771
+ }) ?? /* @__PURE__ */ jsxs2(Fragment3, { children: [
3772
+ canPrev ? /* @__PURE__ */ jsx3(
3773
+ "button",
3774
+ {
3775
+ className: "btn-prev",
3776
+ type: "button",
3777
+ disabled: interactionLocked,
3778
+ onClick: () => setCurrentPageIndex(visiblePageIndexes[activeVisibleIndex - 1] ?? 0),
3779
+ children: form.translate("form.back")
3780
+ }
3781
+ ) : null,
3782
+ canNext ? /* @__PURE__ */ jsx3("button", { className: "btn-next", type: "button", disabled: interactionLocked, onClick: handleNext, children: form.translate("form.next") }) : null
3783
+ ] }),
3784
+ canNext ? null : renderSubmitButton()
3785
+ ] }),
3786
+ /* @__PURE__ */ jsxs2("div", { className: "fe-status", "aria-live": "polite", children: [
3787
+ form.submitStatus === "success" ? completionRegion : null,
3788
+ form.submitStatus === "error" && form.submitError !== null ? slots.renderSubmitError?.({ error: form.submitError, onRetry: () => void submitValues() }) ?? (form.submitError instanceof FormSubmissionError && form.submitError.payload.formError !== void 0 ? /* @__PURE__ */ jsxs2("div", { role: "alert", children: [
3789
+ form.submitError.payload.formError,
3790
+ /* @__PURE__ */ jsx3("button", { type: "button", onClick: () => void submitValues(), children: resolveMessage("retryButton") })
3791
+ ] }) : /* @__PURE__ */ jsxs2("div", { role: "alert", children: [
3792
+ errorMessageKey === void 0 ? resolveMessage("serverErrorSummary") : form.translate(errorMessageKey),
3793
+ /* @__PURE__ */ jsx3("button", { type: "button", onClick: () => void submitValues(), children: resolveMessage("retryButton") })
3794
+ ] })) : null
3795
+ ] })
3796
+ ]
3445
3797
  }
3446
- const Component = components[field.type];
3447
- return Component === void 0 ? /* @__PURE__ */ jsx3(DefaultField, { ...props }, field.id) : /* @__PURE__ */ jsx3(Component, { ...props }, field.id);
3448
- }) }),
3449
- guardMessage === null ? null : /* @__PURE__ */ jsx3("div", { role: "alert", children: guardMessage }),
3450
- confirmation === null ? null : slots.renderSubmissionConfirmation?.({
3451
- findings: confirmation.findings,
3452
- message: confirmation.message ?? form.translate("form.confirmSensitiveData"),
3453
- schema: form.schema,
3454
- visibleValues,
3455
- onConfirm: confirmSubmission,
3456
- onCancel: cancelSubmission
3457
- }) ?? /* @__PURE__ */ jsxs2("div", { className: "fe-submission-confirmation", role: "dialog", "aria-modal": "true", children: [
3458
- /* @__PURE__ */ jsx3("p", { children: confirmation.message ?? form.translate("form.confirmSensitiveData") }),
3459
- /* @__PURE__ */ jsx3("button", { type: "button", onClick: confirmSubmission, children: form.translate("form.confirmSubmission") }),
3460
- /* @__PURE__ */ jsx3("button", { type: "button", onClick: cancelSubmission, children: form.translate("form.cancelSubmission") })
3461
- ] }),
3462
- validationIssues.length === 0 ? null : slots.renderValidationSummary?.({ issues: validationIssues }) ?? /* @__PURE__ */ jsxs2("div", { className: "fe-validation-summary", role: "alert", children: [
3463
- validationIssues.length,
3464
- " validation error",
3465
- validationIssues.length === 1 ? "" : "s",
3466
- "."
3467
- ] }),
3468
- pages === void 0 ? /* @__PURE__ */ jsxs2(Fragment3, { children: [
3469
- slots.renderNavigation?.({
3470
- currentPage: 0,
3471
- totalPages: 1,
3472
- canPrev: false,
3473
- canNext: false,
3474
- onPrev: () => void 0,
3475
- onNext: () => void 0
3476
- }),
3477
- renderSubmitButton()
3478
- ] }) : /* @__PURE__ */ jsxs2("div", { className: "form-step-navigation", children: [
3479
- slots.renderNavigation?.({
3480
- currentPage: activeVisibleIndex,
3481
- totalPages: visiblePageIndexes.length,
3482
- canPrev,
3483
- canNext,
3484
- onPrev: () => {
3485
- if (!interactionLocked) setCurrentPageIndex(visiblePageIndexes[activeVisibleIndex - 1] ?? 0);
3486
- },
3487
- onNext: handleNext
3488
- }) ?? /* @__PURE__ */ jsxs2(Fragment3, { children: [
3489
- canPrev ? /* @__PURE__ */ jsx3(
3490
- "button",
3491
- {
3492
- className: "btn-prev",
3493
- type: "button",
3494
- disabled: interactionLocked,
3495
- onClick: () => setCurrentPageIndex(visiblePageIndexes[activeVisibleIndex - 1] ?? 0),
3496
- children: form.translate("form.back")
3497
- }
3498
- ) : null,
3499
- canNext ? /* @__PURE__ */ jsx3("button", { className: "btn-next", type: "button", disabled: interactionLocked, onClick: handleNext, children: form.translate("form.next") }) : null
3500
- ] }),
3501
- canNext ? null : renderSubmitButton()
3502
- ] }),
3503
- /* @__PURE__ */ jsxs2("div", { className: "fe-status", "aria-live": "polite", children: [
3504
- form.submitStatus === "success" ? completionRegion : null,
3505
- form.submitStatus === "error" && form.submitError !== null ? slots.renderSubmitError?.({ error: form.submitError, onRetry: () => void submitValues() }) ?? (errorMessageKey === void 0 ? null : /* @__PURE__ */ jsx3("div", { role: "alert", children: form.translate(errorMessageKey) })) : null
3506
- ] })
3798
+ ),
3799
+ confirmation !== null && submissionConfirmationRenderMode === "dialog" ? /* @__PURE__ */ jsx3("div", { className: "fe-confirmation-dialog-backdrop", role: "dialog", "aria-modal": "true", children: confirmationContent }) : null
3507
3800
  ] });
3508
3801
  }
3509
3802
  var RENDERER_MESSAGES = {
@@ -3514,15 +3807,34 @@ var RENDERER_MESSAGES = {
3514
3807
  "form.draftRestored": "Draft restored",
3515
3808
  "form.submissionBlocked": "Submission blocked because sensitive data was detected.",
3516
3809
  "form.confirmSensitiveData": "Sensitive data may be included. Confirm before submitting.",
3517
- "form.confirmSubmission": "Confirm submission",
3810
+ "form.confirmSubmission": "Proceed",
3518
3811
  "form.cancelSubmission": "Cancel",
3812
+ "form.yes": "Yes",
3813
+ "form.no": "No",
3519
3814
  "form.alreadySubmitted": "Already submitted.",
3520
3815
  "form.submitAnother": "Submit another response",
3521
3816
  "validation.required": "This field is required."
3522
3817
  };
3818
+ var RENDERER_MESSAGES_JA = {
3819
+ "form.submit": "\u9001\u4FE1\u3059\u308B",
3820
+ "form.back": "\u623B\u308B",
3821
+ "form.next": "\u6B21\u3078",
3822
+ "form.step": "{{current}} / {{total}}",
3823
+ "form.draftRestored": "\u4E0B\u66F8\u304D\u3092\u5FA9\u5143\u3057\u307E\u3057\u305F",
3824
+ "form.submissionBlocked": "\u500B\u4EBA\u60C5\u5831\u304C\u691C\u51FA\u3055\u308C\u305F\u305F\u3081\u9001\u4FE1\u3067\u304D\u307E\u305B\u3093\u3002",
3825
+ "form.confirmSensitiveData": "\u500B\u4EBA\u60C5\u5831\u304C\u542B\u307E\u308C\u3066\u3044\u308B\u53EF\u80FD\u6027\u304C\u3042\u308A\u307E\u3059\u3002\u9001\u4FE1\u524D\u306B\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
3826
+ "form.confirmSubmission": "\u3053\u306E\u307E\u307E\u9001\u4FE1",
3827
+ "form.cancelSubmission": "\u4FEE\u6B63\u3059\u308B",
3828
+ "form.yes": "\u306F\u3044",
3829
+ "form.no": "\u3044\u3044\u3048",
3830
+ "form.alreadySubmitted": "\u56DE\u7B54\u6E08\u307F\u3067\u3059",
3831
+ "form.submitAnother": "\u5225\u306E\u56DE\u7B54\u3092\u9001\u4FE1",
3832
+ "validation.required": "\u3053\u306E\u9805\u76EE\u306F\u5FC5\u9808\u3067\u3059"
3833
+ };
3523
3834
  var defaultRendererTranslator = {
3524
- translate(key, _locale, params = {}) {
3525
- return (RENDERER_MESSAGES[key] ?? key).replace(
3835
+ translate(key, locale, params = {}) {
3836
+ const localizedMessages = locale.toLowerCase().startsWith("ja") ? RENDERER_MESSAGES_JA : RENDERER_MESSAGES;
3837
+ return (localizedMessages[key] ?? key).replace(
3526
3838
  /\{\{(\w+)\}\}/g,
3527
3839
  (token, name) => Object.hasOwn(params, name) ? String(params[name]) : token
3528
3840
  );
@@ -3556,6 +3868,7 @@ export {
3556
3868
  FormBuilder,
3557
3869
  FormProvider,
3558
3870
  FormRenderer,
3871
+ FormSubmissionError,
3559
3872
  createLocalStorageSubmissionAttemptStore,
3560
3873
  createLocalStorageSubmissionReceiptStore,
3561
3874
  resolveInitialFieldType,