@form-engine-ts/react 2.3.0 → 2.5.1

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 CHANGED
@@ -78,6 +78,11 @@ surfaces: `toolbar`, `fieldEditor`, `optionEditor`, `pages`, `localization`, or
78
78
  policy-aware `actions`; a custom `translationActions` slot can therefore call an application-specific AI mutation while
79
79
  the standard manual localization editors remain unchanged.
80
80
 
81
+ Input primitives receive design-system-friendly `name`, `label`, `required`, `error`, and `helperText` props in addition
82
+ to their normalized string-value callbacks. The `translationActions` slot also receives `translationError`, the latest
83
+ `translationReport`, and `onClearTranslationError`, allowing a custom MUI action surface to represent the complete
84
+ translation lifecycle.
85
+
81
86
  ```tsx
82
87
  <FormBuilder
83
88
  schema={schema}
package/dist/index.cjs CHANGED
@@ -718,6 +718,11 @@ function DefaultTextInput({
718
718
  disabled,
719
719
  readOnly,
720
720
  "aria-label": ariaLabel,
721
+ name,
722
+ label,
723
+ required,
724
+ error,
725
+ helperText,
721
726
  value,
722
727
  onChange,
723
728
  placeholder,
@@ -728,25 +733,31 @@ function DefaultTextInput({
728
733
  max,
729
734
  step
730
735
  }) {
731
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
732
- "input",
733
- {
734
- id,
735
- className,
736
- disabled,
737
- readOnly,
738
- "aria-label": ariaLabel,
739
- type: type === "text" ? void 0 : type,
740
- inputMode,
741
- min,
742
- max,
743
- step,
744
- value,
745
- placeholder,
746
- maxLength,
747
- onChange: (event) => onChange(event.currentTarget.value)
748
- }
749
- );
736
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
737
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
738
+ "input",
739
+ {
740
+ id,
741
+ name,
742
+ className,
743
+ disabled,
744
+ readOnly,
745
+ required,
746
+ "aria-label": ariaLabel ?? label,
747
+ "aria-invalid": error === true ? true : void 0,
748
+ type: type === "text" ? void 0 : type,
749
+ inputMode,
750
+ min,
751
+ max,
752
+ step,
753
+ value,
754
+ placeholder,
755
+ maxLength,
756
+ onChange: (event) => onChange(event.currentTarget.value)
757
+ }
758
+ ),
759
+ helperText === void 0 || helperText.length === 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("small", { children: helperText })
760
+ ] });
750
761
  }
751
762
  function DefaultTextArea({
752
763
  id,
@@ -754,49 +765,71 @@ function DefaultTextArea({
754
765
  disabled,
755
766
  readOnly,
756
767
  "aria-label": ariaLabel,
768
+ name,
769
+ label,
770
+ required,
771
+ error,
772
+ helperText,
757
773
  value,
758
774
  onChange,
759
775
  rows,
760
776
  placeholder,
761
777
  maxLength
762
778
  }) {
763
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
764
- "textarea",
765
- {
766
- id,
767
- className,
768
- disabled,
769
- readOnly,
770
- "aria-label": ariaLabel,
771
- value,
772
- rows,
773
- placeholder,
774
- maxLength,
775
- onChange: (event) => onChange(event.currentTarget.value)
776
- }
777
- );
779
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
780
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
781
+ "textarea",
782
+ {
783
+ id,
784
+ name,
785
+ className,
786
+ disabled,
787
+ readOnly,
788
+ required,
789
+ "aria-label": ariaLabel ?? label,
790
+ "aria-invalid": error === true ? true : void 0,
791
+ value,
792
+ rows,
793
+ placeholder,
794
+ maxLength,
795
+ onChange: (event) => onChange(event.currentTarget.value)
796
+ }
797
+ ),
798
+ helperText === void 0 || helperText.length === 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("small", { children: helperText })
799
+ ] });
778
800
  }
779
801
  function DefaultSelect({
780
802
  id,
781
803
  className,
782
804
  disabled,
783
805
  "aria-label": ariaLabel,
806
+ name,
807
+ label,
808
+ required,
809
+ error,
810
+ helperText,
784
811
  value,
785
812
  onChange,
786
813
  options
787
814
  }) {
788
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
789
- "select",
790
- {
791
- id,
792
- className,
793
- disabled,
794
- "aria-label": ariaLabel,
795
- value,
796
- onChange: (event) => onChange(event.currentTarget.value),
797
- children: options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: option.value, disabled: option.disabled, children: option.label }, option.value))
798
- }
799
- );
815
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
816
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
817
+ "select",
818
+ {
819
+ id,
820
+ name,
821
+ className,
822
+ disabled,
823
+ required,
824
+ "aria-label": ariaLabel ?? label,
825
+ "aria-invalid": error === true ? true : void 0,
826
+ value,
827
+ onChange: (event) => onChange(event.currentTarget.value),
828
+ children: options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: option.value, disabled: option.disabled, children: option.label }, option.value))
829
+ }
830
+ ),
831
+ helperText === void 0 || helperText.length === 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("small", { children: helperText })
832
+ ] });
800
833
  }
801
834
  function DefaultCheckbox({
802
835
  id,
@@ -1122,6 +1155,7 @@ function FormBuilder({
1122
1155
  const [editingLocale, setEditingLocale] = (0, import_react2.useState)("");
1123
1156
  const [isTranslating, setIsTranslating] = (0, import_react2.useState)(false);
1124
1157
  const [translationError, setTranslationError] = (0, import_react2.useState)(null);
1158
+ const [translationReport, setTranslationReport] = (0, import_react2.useState)();
1125
1159
  const translate = (key, params = {}) => {
1126
1160
  const translated = translator?.translate(key, locale, params);
1127
1161
  return translated === void 0 ? interpolate(BUILDER_DEFAULTS[key] ?? key, params) : translated;
@@ -1239,8 +1273,10 @@ function FormBuilder({
1239
1273
  ...translationPolicy === void 0 ? {} : { policy: translationPolicy }
1240
1274
  });
1241
1275
  onChange(populated.schema);
1276
+ setTranslationReport(populated.report);
1242
1277
  onTranslationReport?.(populated.report);
1243
1278
  } catch (cause) {
1279
+ setTranslationReport(void 0);
1244
1280
  setTranslationError(cause instanceof Error ? cause.message : String(cause));
1245
1281
  } finally {
1246
1282
  setIsTranslating(false);
@@ -1713,6 +1749,9 @@ function FormBuilder({
1713
1749
  currentLocale: editingLocale,
1714
1750
  onAutoTranslate: () => void translateAll(),
1715
1751
  isTranslating,
1752
+ ...translationError === null ? {} : { translationError },
1753
+ ...translationReport === void 0 ? {} : { translationReport },
1754
+ onClearTranslationError: () => setTranslationError(null),
1716
1755
  readOnly,
1717
1756
  actions,
1718
1757
  components
@@ -1842,6 +1881,11 @@ function FormBuilder({
1842
1881
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1843
1882
  TextInput,
1844
1883
  {
1884
+ name: `fields.${field.id}.title`,
1885
+ label: translate("builder.questionTitle"),
1886
+ required: true,
1887
+ error: field.title.trim().length === 0,
1888
+ helperText: field.title.trim().length === 0 ? translate("builder.required") : "",
1845
1889
  value: field.title,
1846
1890
  placeholder: translate("builder.questionTitlePlaceholder"),
1847
1891
  onChange: (value) => updateField(field.id, (current) => ({
package/dist/index.d.cts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as react from 'react';
2
2
  import { ReactNode, ComponentType, MouseEvent } from 'react';
3
- import { QuestionType, FormField, ChoiceOption, FormPage, FormSchema, DisplayCondition, JsonValue, SchemaIssue, FormPolicy, FieldOption, ValidationError, TranslationAdapter, AsyncTranslationAdapter, PopulateTranslationOptions, TranslationReport, FormValue, ValidationIssue, FormValues, AnswerValidationResult, FieldType } from '@form-engine-ts/core';
3
+ import { QuestionType, FormField, ChoiceOption, FormPage, FormSchema, DisplayCondition, JsonValue, SchemaIssue, FormPolicy, FieldOption, TranslationReport, ValidationError, TranslationAdapter, AsyncTranslationAdapter, PopulateTranslationOptions, FormValue, ValidationIssue, FormValues, AnswerValidationResult, FieldType } from '@form-engine-ts/core';
4
4
 
5
5
  /** @deprecated Import FormPolicy from @form-engine-ts/core instead. */
6
6
  type BuilderPolicy = FormPolicy;
@@ -104,32 +104,33 @@ interface BuilderIconButtonProps extends ComponentBaseProps {
104
104
  readonly icon: string;
105
105
  readonly title: string;
106
106
  }
107
- interface BuilderTextInputProps extends ComponentBaseProps {
107
+ interface InputComponentProps extends ComponentBaseProps {
108
+ readonly name?: string;
109
+ readonly label?: string;
110
+ readonly required?: boolean;
111
+ readonly error?: boolean;
112
+ readonly helperText?: string;
108
113
  readonly value: string;
109
114
  readonly onChange: (value: string) => void;
110
115
  readonly placeholder?: string;
111
116
  readonly maxLength?: number;
117
+ }
118
+ interface BuilderTextInputProps extends InputComponentProps {
112
119
  readonly inputMode?: "text" | "numeric";
113
120
  readonly type?: "text" | "number";
114
121
  readonly min?: number;
115
122
  readonly max?: number;
116
123
  readonly step?: number;
117
124
  }
118
- interface BuilderTextAreaProps extends ComponentBaseProps {
119
- readonly value: string;
120
- readonly onChange: (value: string) => void;
125
+ interface BuilderTextAreaProps extends InputComponentProps {
121
126
  readonly rows?: number;
122
- readonly placeholder?: string;
123
- readonly maxLength?: number;
124
127
  }
125
128
  interface BuilderSelectOption {
126
129
  readonly label: string;
127
130
  readonly value: string;
128
131
  readonly disabled?: boolean;
129
132
  }
130
- interface BuilderSelectProps extends ComponentBaseProps {
131
- readonly value: string;
132
- readonly onChange: (value: string) => void;
133
+ interface BuilderSelectProps extends InputComponentProps {
133
134
  readonly options: readonly BuilderSelectOption[];
134
135
  }
135
136
  interface BuilderCheckboxProps extends ComponentBaseProps {
@@ -211,6 +212,9 @@ interface BuilderTranslationActionsSlotProps extends BuilderSlotBaseProps {
211
212
  readonly currentLocale: string;
212
213
  readonly onAutoTranslate: () => void;
213
214
  readonly isTranslating: boolean;
215
+ readonly translationError?: string;
216
+ readonly translationReport?: TranslationReport;
217
+ readonly onClearTranslationError?: () => void;
214
218
  }
215
219
  interface FormBuilderSlots {
216
220
  readonly toolbar?: ComponentType<BuilderToolbarSlotProps>;
@@ -384,4 +388,4 @@ interface StandaloneFormRendererProps extends FormRendererPresentationProps {
384
388
  type FormRendererProps = FormRendererPresentationProps | StandaloneFormRendererProps;
385
389
  declare function FormRenderer(props: FormRendererProps): react.JSX.Element;
386
390
 
387
- export { type BeforeSubmit, type BuilderActionContext, type BuilderActionError, type BuilderActionResult, type BuilderButtonProps, type BuilderCheckboxProps, type BuilderFactories, type BuilderFieldEditorSlotProps, type BuilderFieldsetProps, type BuilderIconButtonProps, type BuilderIdKind, type BuilderLocalizationSlotProps, type BuilderOptionEditorSlotProps, type BuilderPagesSlotProps, type BuilderPolicy, type BuilderSectionProps, type BuilderSelectOption, type BuilderSelectProps, type BuilderTextAreaProps, type BuilderTextInputProps, type BuilderTextTarget, type BuilderToolbarSlotProps, type BuilderTranslationActionsSlotProps, type ComponentBaseProps, type FieldComponentProps, type FieldComponents, type FieldState, FormBuilder, type FormBuilderActions, type FormBuilderComponents, type FormBuilderFeatures, type FormBuilderOptions, type FormBuilderProps, type FormBuilderResult, type FormBuilderSlots, type FormContextValue, FormProvider, type FormProviderProps, FormRenderer, type FormRendererPresentationProps, type FormRendererProps, type FormRendererSlots, type ManualTranslationContext, type StandaloneFormRendererProps, type SubmitResult, type SubmitStatus, resolveInitialFieldType, useField, useForm, useFormBuilder };
391
+ export { type BeforeSubmit, type BuilderActionContext, type BuilderActionError, type BuilderActionResult, type BuilderButtonProps, type BuilderCheckboxProps, type BuilderFactories, type BuilderFieldEditorSlotProps, type BuilderFieldsetProps, type BuilderIconButtonProps, type BuilderIdKind, type BuilderLocalizationSlotProps, type BuilderOptionEditorSlotProps, type BuilderPagesSlotProps, type BuilderPolicy, type BuilderSectionProps, type BuilderSelectOption, type BuilderSelectProps, type BuilderTextAreaProps, type BuilderTextInputProps, type BuilderTextTarget, type BuilderToolbarSlotProps, type BuilderTranslationActionsSlotProps, type ComponentBaseProps, type FieldComponentProps, type FieldComponents, type FieldState, FormBuilder, type FormBuilderActions, type FormBuilderComponents, type FormBuilderFeatures, type FormBuilderOptions, type FormBuilderProps, type FormBuilderResult, type FormBuilderSlots, type FormContextValue, FormProvider, type FormProviderProps, FormRenderer, type FormRendererPresentationProps, type FormRendererProps, type FormRendererSlots, type InputComponentProps, type ManualTranslationContext, type StandaloneFormRendererProps, type SubmitResult, type SubmitStatus, resolveInitialFieldType, useField, useForm, useFormBuilder };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as react from 'react';
2
2
  import { ReactNode, ComponentType, MouseEvent } from 'react';
3
- import { QuestionType, FormField, ChoiceOption, FormPage, FormSchema, DisplayCondition, JsonValue, SchemaIssue, FormPolicy, FieldOption, ValidationError, TranslationAdapter, AsyncTranslationAdapter, PopulateTranslationOptions, TranslationReport, FormValue, ValidationIssue, FormValues, AnswerValidationResult, FieldType } from '@form-engine-ts/core';
3
+ import { QuestionType, FormField, ChoiceOption, FormPage, FormSchema, DisplayCondition, JsonValue, SchemaIssue, FormPolicy, FieldOption, TranslationReport, ValidationError, TranslationAdapter, AsyncTranslationAdapter, PopulateTranslationOptions, FormValue, ValidationIssue, FormValues, AnswerValidationResult, FieldType } from '@form-engine-ts/core';
4
4
 
5
5
  /** @deprecated Import FormPolicy from @form-engine-ts/core instead. */
6
6
  type BuilderPolicy = FormPolicy;
@@ -104,32 +104,33 @@ interface BuilderIconButtonProps extends ComponentBaseProps {
104
104
  readonly icon: string;
105
105
  readonly title: string;
106
106
  }
107
- interface BuilderTextInputProps extends ComponentBaseProps {
107
+ interface InputComponentProps extends ComponentBaseProps {
108
+ readonly name?: string;
109
+ readonly label?: string;
110
+ readonly required?: boolean;
111
+ readonly error?: boolean;
112
+ readonly helperText?: string;
108
113
  readonly value: string;
109
114
  readonly onChange: (value: string) => void;
110
115
  readonly placeholder?: string;
111
116
  readonly maxLength?: number;
117
+ }
118
+ interface BuilderTextInputProps extends InputComponentProps {
112
119
  readonly inputMode?: "text" | "numeric";
113
120
  readonly type?: "text" | "number";
114
121
  readonly min?: number;
115
122
  readonly max?: number;
116
123
  readonly step?: number;
117
124
  }
118
- interface BuilderTextAreaProps extends ComponentBaseProps {
119
- readonly value: string;
120
- readonly onChange: (value: string) => void;
125
+ interface BuilderTextAreaProps extends InputComponentProps {
121
126
  readonly rows?: number;
122
- readonly placeholder?: string;
123
- readonly maxLength?: number;
124
127
  }
125
128
  interface BuilderSelectOption {
126
129
  readonly label: string;
127
130
  readonly value: string;
128
131
  readonly disabled?: boolean;
129
132
  }
130
- interface BuilderSelectProps extends ComponentBaseProps {
131
- readonly value: string;
132
- readonly onChange: (value: string) => void;
133
+ interface BuilderSelectProps extends InputComponentProps {
133
134
  readonly options: readonly BuilderSelectOption[];
134
135
  }
135
136
  interface BuilderCheckboxProps extends ComponentBaseProps {
@@ -211,6 +212,9 @@ interface BuilderTranslationActionsSlotProps extends BuilderSlotBaseProps {
211
212
  readonly currentLocale: string;
212
213
  readonly onAutoTranslate: () => void;
213
214
  readonly isTranslating: boolean;
215
+ readonly translationError?: string;
216
+ readonly translationReport?: TranslationReport;
217
+ readonly onClearTranslationError?: () => void;
214
218
  }
215
219
  interface FormBuilderSlots {
216
220
  readonly toolbar?: ComponentType<BuilderToolbarSlotProps>;
@@ -384,4 +388,4 @@ interface StandaloneFormRendererProps extends FormRendererPresentationProps {
384
388
  type FormRendererProps = FormRendererPresentationProps | StandaloneFormRendererProps;
385
389
  declare function FormRenderer(props: FormRendererProps): react.JSX.Element;
386
390
 
387
- export { type BeforeSubmit, type BuilderActionContext, type BuilderActionError, type BuilderActionResult, type BuilderButtonProps, type BuilderCheckboxProps, type BuilderFactories, type BuilderFieldEditorSlotProps, type BuilderFieldsetProps, type BuilderIconButtonProps, type BuilderIdKind, type BuilderLocalizationSlotProps, type BuilderOptionEditorSlotProps, type BuilderPagesSlotProps, type BuilderPolicy, type BuilderSectionProps, type BuilderSelectOption, type BuilderSelectProps, type BuilderTextAreaProps, type BuilderTextInputProps, type BuilderTextTarget, type BuilderToolbarSlotProps, type BuilderTranslationActionsSlotProps, type ComponentBaseProps, type FieldComponentProps, type FieldComponents, type FieldState, FormBuilder, type FormBuilderActions, type FormBuilderComponents, type FormBuilderFeatures, type FormBuilderOptions, type FormBuilderProps, type FormBuilderResult, type FormBuilderSlots, type FormContextValue, FormProvider, type FormProviderProps, FormRenderer, type FormRendererPresentationProps, type FormRendererProps, type FormRendererSlots, type ManualTranslationContext, type StandaloneFormRendererProps, type SubmitResult, type SubmitStatus, resolveInitialFieldType, useField, useForm, useFormBuilder };
391
+ export { type BeforeSubmit, type BuilderActionContext, type BuilderActionError, type BuilderActionResult, type BuilderButtonProps, type BuilderCheckboxProps, type BuilderFactories, type BuilderFieldEditorSlotProps, type BuilderFieldsetProps, type BuilderIconButtonProps, type BuilderIdKind, type BuilderLocalizationSlotProps, type BuilderOptionEditorSlotProps, type BuilderPagesSlotProps, type BuilderPolicy, type BuilderSectionProps, type BuilderSelectOption, type BuilderSelectProps, type BuilderTextAreaProps, type BuilderTextInputProps, type BuilderTextTarget, type BuilderToolbarSlotProps, type BuilderTranslationActionsSlotProps, type ComponentBaseProps, type FieldComponentProps, type FieldComponents, type FieldState, FormBuilder, type FormBuilderActions, type FormBuilderComponents, type FormBuilderFeatures, type FormBuilderOptions, type FormBuilderProps, type FormBuilderResult, type FormBuilderSlots, type FormContextValue, FormProvider, type FormProviderProps, FormRenderer, type FormRendererPresentationProps, type FormRendererProps, type FormRendererSlots, type InputComponentProps, type ManualTranslationContext, type StandaloneFormRendererProps, type SubmitResult, type SubmitStatus, resolveInitialFieldType, useField, useForm, useFormBuilder };
package/dist/index.js CHANGED
@@ -692,6 +692,11 @@ function DefaultTextInput({
692
692
  disabled,
693
693
  readOnly,
694
694
  "aria-label": ariaLabel,
695
+ name,
696
+ label,
697
+ required,
698
+ error,
699
+ helperText,
695
700
  value,
696
701
  onChange,
697
702
  placeholder,
@@ -702,25 +707,31 @@ function DefaultTextInput({
702
707
  max,
703
708
  step
704
709
  }) {
705
- return /* @__PURE__ */ jsx(
706
- "input",
707
- {
708
- id,
709
- className,
710
- disabled,
711
- readOnly,
712
- "aria-label": ariaLabel,
713
- type: type === "text" ? void 0 : type,
714
- inputMode,
715
- min,
716
- max,
717
- step,
718
- value,
719
- placeholder,
720
- maxLength,
721
- onChange: (event) => onChange(event.currentTarget.value)
722
- }
723
- );
710
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
711
+ /* @__PURE__ */ jsx(
712
+ "input",
713
+ {
714
+ id,
715
+ name,
716
+ className,
717
+ disabled,
718
+ readOnly,
719
+ required,
720
+ "aria-label": ariaLabel ?? label,
721
+ "aria-invalid": error === true ? true : void 0,
722
+ type: type === "text" ? void 0 : type,
723
+ inputMode,
724
+ min,
725
+ max,
726
+ step,
727
+ value,
728
+ placeholder,
729
+ maxLength,
730
+ onChange: (event) => onChange(event.currentTarget.value)
731
+ }
732
+ ),
733
+ helperText === void 0 || helperText.length === 0 ? null : /* @__PURE__ */ jsx("small", { children: helperText })
734
+ ] });
724
735
  }
725
736
  function DefaultTextArea({
726
737
  id,
@@ -728,49 +739,71 @@ function DefaultTextArea({
728
739
  disabled,
729
740
  readOnly,
730
741
  "aria-label": ariaLabel,
742
+ name,
743
+ label,
744
+ required,
745
+ error,
746
+ helperText,
731
747
  value,
732
748
  onChange,
733
749
  rows,
734
750
  placeholder,
735
751
  maxLength
736
752
  }) {
737
- return /* @__PURE__ */ jsx(
738
- "textarea",
739
- {
740
- id,
741
- className,
742
- disabled,
743
- readOnly,
744
- "aria-label": ariaLabel,
745
- value,
746
- rows,
747
- placeholder,
748
- maxLength,
749
- onChange: (event) => onChange(event.currentTarget.value)
750
- }
751
- );
753
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
754
+ /* @__PURE__ */ jsx(
755
+ "textarea",
756
+ {
757
+ id,
758
+ name,
759
+ className,
760
+ disabled,
761
+ readOnly,
762
+ required,
763
+ "aria-label": ariaLabel ?? label,
764
+ "aria-invalid": error === true ? true : void 0,
765
+ value,
766
+ rows,
767
+ placeholder,
768
+ maxLength,
769
+ onChange: (event) => onChange(event.currentTarget.value)
770
+ }
771
+ ),
772
+ helperText === void 0 || helperText.length === 0 ? null : /* @__PURE__ */ jsx("small", { children: helperText })
773
+ ] });
752
774
  }
753
775
  function DefaultSelect({
754
776
  id,
755
777
  className,
756
778
  disabled,
757
779
  "aria-label": ariaLabel,
780
+ name,
781
+ label,
782
+ required,
783
+ error,
784
+ helperText,
758
785
  value,
759
786
  onChange,
760
787
  options
761
788
  }) {
762
- return /* @__PURE__ */ jsx(
763
- "select",
764
- {
765
- id,
766
- className,
767
- disabled,
768
- "aria-label": ariaLabel,
769
- value,
770
- onChange: (event) => onChange(event.currentTarget.value),
771
- children: options.map((option) => /* @__PURE__ */ jsx("option", { value: option.value, disabled: option.disabled, children: option.label }, option.value))
772
- }
773
- );
789
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
790
+ /* @__PURE__ */ jsx(
791
+ "select",
792
+ {
793
+ id,
794
+ name,
795
+ className,
796
+ disabled,
797
+ required,
798
+ "aria-label": ariaLabel ?? label,
799
+ "aria-invalid": error === true ? true : void 0,
800
+ value,
801
+ onChange: (event) => onChange(event.currentTarget.value),
802
+ children: options.map((option) => /* @__PURE__ */ jsx("option", { value: option.value, disabled: option.disabled, children: option.label }, option.value))
803
+ }
804
+ ),
805
+ helperText === void 0 || helperText.length === 0 ? null : /* @__PURE__ */ jsx("small", { children: helperText })
806
+ ] });
774
807
  }
775
808
  function DefaultCheckbox({
776
809
  id,
@@ -1096,6 +1129,7 @@ function FormBuilder({
1096
1129
  const [editingLocale, setEditingLocale] = useState("");
1097
1130
  const [isTranslating, setIsTranslating] = useState(false);
1098
1131
  const [translationError, setTranslationError] = useState(null);
1132
+ const [translationReport, setTranslationReport] = useState();
1099
1133
  const translate = (key, params = {}) => {
1100
1134
  const translated = translator?.translate(key, locale, params);
1101
1135
  return translated === void 0 ? interpolate(BUILDER_DEFAULTS[key] ?? key, params) : translated;
@@ -1213,8 +1247,10 @@ function FormBuilder({
1213
1247
  ...translationPolicy === void 0 ? {} : { policy: translationPolicy }
1214
1248
  });
1215
1249
  onChange(populated.schema);
1250
+ setTranslationReport(populated.report);
1216
1251
  onTranslationReport?.(populated.report);
1217
1252
  } catch (cause) {
1253
+ setTranslationReport(void 0);
1218
1254
  setTranslationError(cause instanceof Error ? cause.message : String(cause));
1219
1255
  } finally {
1220
1256
  setIsTranslating(false);
@@ -1687,6 +1723,9 @@ function FormBuilder({
1687
1723
  currentLocale: editingLocale,
1688
1724
  onAutoTranslate: () => void translateAll(),
1689
1725
  isTranslating,
1726
+ ...translationError === null ? {} : { translationError },
1727
+ ...translationReport === void 0 ? {} : { translationReport },
1728
+ onClearTranslationError: () => setTranslationError(null),
1690
1729
  readOnly,
1691
1730
  actions,
1692
1731
  components
@@ -1816,6 +1855,11 @@ function FormBuilder({
1816
1855
  /* @__PURE__ */ jsx(
1817
1856
  TextInput,
1818
1857
  {
1858
+ name: `fields.${field.id}.title`,
1859
+ label: translate("builder.questionTitle"),
1860
+ required: true,
1861
+ error: field.title.trim().length === 0,
1862
+ helperText: field.title.trim().length === 0 ? translate("builder.required") : "",
1819
1863
  value: field.title,
1820
1864
  placeholder: translate("builder.questionTitlePlaceholder"),
1821
1865
  onChange: (value) => updateField(field.id, (current) => ({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@form-engine-ts/react",
3
- "version": "2.3.0",
3
+ "version": "2.5.1",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -42,7 +42,7 @@
42
42
  "typescript"
43
43
  ],
44
44
  "dependencies": {
45
- "@form-engine-ts/core": "2.3.0"
45
+ "@form-engine-ts/core": "2.5.1"
46
46
  },
47
47
  "peerDependencies": {
48
48
  "react": ">=18.2 <20",