@rilaykit/forms 5.2.0 → 6.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.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { ril, FieldValidationConfig, FormFieldConfig, FormFieldRow, FormValidationConfig, FormValidator, FormConfiguration, ComponentRendererBaseProps, FormBodyRendererProps, ValidationError, ValidationResult, FormRowRendererProps, FormSubmitButtonRendererProps } from '@rilaykit/core';
2
+ import { ril, FieldValidationConfig, ConditionalBehavior, FormFieldConfig, FormFieldRow, FormValidationConfig, FormValidator, FormConfiguration, ComponentRendererBaseProps, FormBodyRendererProps, ValidationError, ValidationResult, FormRowRendererProps, FormSubmitButtonRendererProps } from '@rilaykit/core';
3
3
  export * from '@rilaykit/core';
4
4
  import React$1 from 'react';
5
5
 
@@ -31,6 +31,8 @@ type FieldConfig<C extends Record<string, any>, T extends keyof C> = {
31
31
  props?: Partial<C[T]>;
32
32
  /** Validation configuration for this field */
33
33
  validation?: FieldValidationConfig;
34
+ /** Conditional behavior configuration for this field */
35
+ conditions?: ConditionalBehavior;
34
36
  };
35
37
  /**
36
38
  * Form builder class for creating type-safe form configurations
@@ -122,7 +124,6 @@ declare class form<C extends Record<string, any> = Record<string, never>> {
122
124
  *
123
125
  * @template T - The component type
124
126
  * @param fieldConfigs - Array of field configurations for the row
125
- * @param rowOptions - Optional row layout configuration
126
127
  * @returns A complete FormFieldRow configuration
127
128
  * @throws Error if no fields provided or more than 3 fields specified
128
129
  *
@@ -174,7 +175,6 @@ declare class form<C extends Record<string, any> = Record<string, never>> {
174
175
  *
175
176
  * @template T - The component type
176
177
  * @param fieldConfigs - Array of field configurations
177
- * @param rowOptions - Optional row layout configuration applied to all rows
178
178
  * @returns The form builder instance for method chaining
179
179
  *
180
180
  * @example
@@ -369,6 +369,26 @@ declare class form<C extends Record<string, any> = Record<string, never>> {
369
369
  * ```
370
370
  */
371
371
  addFieldValidation(fieldId: string, validationConfig: FieldValidationConfig): this;
372
+ /**
373
+ * Adds conditions to a specific field by ID
374
+ *
375
+ * This method allows adding conditional behavior to a field after it has been created,
376
+ * useful for dynamic conditional requirements.
377
+ *
378
+ * @param fieldId - The ID of the field to add conditions to
379
+ * @param conditions - Conditional behavior configuration
380
+ * @returns The form builder instance for method chaining
381
+ * @throws Error if the field with the specified ID is not found
382
+ *
383
+ * @example
384
+ * ```typescript
385
+ * builder.addFieldConditions('phone', {
386
+ * visible: when('contactMethod').equals('phone').build(),
387
+ * required: when('contactMethod').equals('phone').build()
388
+ * });
389
+ * ```
390
+ */
391
+ addFieldConditions(fieldId: string, conditions: ConditionalBehavior): this;
372
392
  /**
373
393
  * Creates a deep copy of the current form builder
374
394
  *
@@ -551,8 +571,75 @@ interface FormFieldProps {
551
571
  disabled?: boolean;
552
572
  customProps?: Record<string, any>;
553
573
  className?: string;
574
+ /** Force field to be visible even if conditions say otherwise (for debugging) */
575
+ forceVisible?: boolean;
576
+ }
577
+ declare function FormField({ fieldId, disabled, customProps, className, forceVisible, }: FormFieldProps): react_jsx_runtime.JSX.Element | null;
578
+
579
+ interface ConditionEvaluationResult {
580
+ visible: boolean;
581
+ disabled: boolean;
582
+ required: boolean;
583
+ readonly: boolean;
554
584
  }
555
- declare function FormField({ fieldId, disabled, customProps, className, }: FormFieldProps): react_jsx_runtime.JSX.Element;
585
+ /**
586
+ * Hook to evaluate conditional behaviors based on form data
587
+ *
588
+ * @param conditions - The conditional behavior configuration
589
+ * @param formData - Current form data to evaluate against
590
+ * @param defaultState - Default state when no conditions are provided
591
+ * @returns Evaluated condition results
592
+ */
593
+ declare function useConditionEvaluation(conditions?: ConditionalBehavior, formData?: Record<string, any>, defaultState?: Partial<ConditionEvaluationResult>): ConditionEvaluationResult;
594
+ /**
595
+ * Hook to evaluate conditions for multiple fields at once
596
+ *
597
+ * @param fieldsWithConditions - Map of field IDs to their conditional behaviors
598
+ * @param formData - Current form data
599
+ * @returns Map of field IDs to their evaluated conditions
600
+ */
601
+ declare function useMultipleConditionEvaluation(fieldsWithConditions: Record<string, ConditionalBehavior | undefined>, formData?: Record<string, any>): Record<string, ConditionEvaluationResult>;
602
+
603
+ interface UseFormConditionsProps {
604
+ formConfig: FormConfiguration;
605
+ formValues: Record<string, any>;
606
+ }
607
+ interface UseFormConditionsReturn {
608
+ fieldConditions: Record<string, ConditionEvaluationResult>;
609
+ hasConditionalFields: boolean;
610
+ getFieldCondition: (fieldId: string) => ConditionEvaluationResult | undefined;
611
+ isFieldVisible: (fieldId: string) => boolean;
612
+ isFieldDisabled: (fieldId: string) => boolean;
613
+ isFieldRequired: (fieldId: string) => boolean;
614
+ isFieldReadonly: (fieldId: string) => boolean;
615
+ }
616
+ /**
617
+ * Hook to manage conditional behaviors for form fields
618
+ *
619
+ * This hook evaluates conditions for all form fields and provides
620
+ * convenient methods to check field states.
621
+ *
622
+ * @param props - Configuration for form conditions
623
+ * @returns Object containing field conditions and helper methods
624
+ *
625
+ * @example
626
+ * ```tsx
627
+ * const {
628
+ * fieldConditions,
629
+ * isFieldVisible,
630
+ * isFieldDisabled
631
+ * } = useFormConditions({
632
+ * formConfig,
633
+ * formValues
634
+ * });
635
+ *
636
+ * // Check if a field should be visible
637
+ * if (!isFieldVisible('phoneField')) {
638
+ * return null;
639
+ * }
640
+ * ```
641
+ */
642
+ declare function useFormConditions({ formConfig, formValues, }: UseFormConditionsProps): UseFormConditionsReturn;
556
643
 
557
644
  interface FormState {
558
645
  values: Record<string, any>;
@@ -561,11 +648,72 @@ interface FormState {
561
648
  touched: Record<string, boolean>;
562
649
  isDirty: boolean;
563
650
  isSubmitting: boolean;
564
- isValid: boolean;
565
651
  }
652
+ type FormAction = {
653
+ type: 'SET_VALUE';
654
+ fieldId: string;
655
+ value: any;
656
+ } | {
657
+ type: 'SET_FIELD_ERRORS';
658
+ fieldId: string;
659
+ errors: ValidationError[];
660
+ } | {
661
+ type: 'SET_FIELD_VALIDATION_STATE';
662
+ fieldId: string;
663
+ state: 'idle' | 'validating' | 'valid' | 'invalid';
664
+ } | {
665
+ type: 'SET_FIELD_TOUCHED';
666
+ fieldId: string;
667
+ } | {
668
+ type: 'SET_SUBMITTING';
669
+ isSubmitting: boolean;
670
+ } | {
671
+ type: 'RESET';
672
+ values?: Record<string, any>;
673
+ };
674
+ interface UseFormStateProps {
675
+ defaultValues?: Record<string, any>;
676
+ onFieldChange?: (fieldId: string, value: any, formData: Record<string, any>) => void;
677
+ }
678
+ declare function useFormState({ defaultValues, onFieldChange }: UseFormStateProps): {
679
+ formState: FormState;
680
+ setValue: (fieldId: string, value: any) => void;
681
+ setFieldTouched: (fieldId: string) => void;
682
+ setError: (fieldId: string, errors: ValidationError[]) => void;
683
+ clearError: (fieldId: string) => void;
684
+ setFieldValidationState: (fieldId: string, state: "idle" | "validating" | "valid" | "invalid") => void;
685
+ setSubmitting: (isSubmitting: boolean) => void;
686
+ reset: (values?: Record<string, any>) => void;
687
+ isFormValid: () => boolean;
688
+ };
689
+
690
+ interface UseFormSubmissionProps {
691
+ formState: FormState;
692
+ onSubmit?: (data: Record<string, any>) => void | Promise<void>;
693
+ validateForm: () => Promise<ValidationResult>;
694
+ setSubmitting: (isSubmitting: boolean) => void;
695
+ }
696
+ declare function useFormSubmission({ formState, onSubmit, validateForm, setSubmitting, }: UseFormSubmissionProps): {
697
+ submit: (event?: React$1.FormEvent) => Promise<boolean>;
698
+ };
699
+
700
+ interface UseFormValidationProps {
701
+ formConfig: FormConfiguration;
702
+ formState: FormState;
703
+ conditionsHelpers: Omit<UseFormConditionsReturn, 'fieldConditions'>;
704
+ setFieldValidationState: (fieldId: string, state: 'idle' | 'validating' | 'valid' | 'invalid') => void;
705
+ setError: (fieldId: string, errors: any[]) => void;
706
+ }
707
+ declare function useFormValidation({ formConfig, formState, conditionsHelpers, setFieldValidationState, setError, }: UseFormValidationProps): {
708
+ validateField: (fieldId: string, value?: any) => Promise<ValidationResult>;
709
+ validateForm: () => Promise<ValidationResult>;
710
+ };
711
+
566
712
  interface FormContextValue {
567
713
  formState: FormState;
568
714
  formConfig: FormConfiguration;
715
+ fieldConditions: Record<string, ConditionEvaluationResult>;
716
+ conditionsHelpers: Omit<UseFormConditionsReturn, 'fieldConditions'>;
569
717
  setValue: (fieldId: string, value: any) => void;
570
718
  setFieldTouched: (fieldId: string, touched?: boolean) => void;
571
719
  validateField: (fieldId: string, value?: any) => Promise<ValidationResult>;
@@ -594,4 +742,4 @@ declare function FormRow({ row, className, ...props }: FormRowProps): react_jsx_
594
742
 
595
743
  declare function FormSubmitButton({ className, ...props }: ComponentRendererBaseProps<FormSubmitButtonRendererProps>): react_jsx_runtime.JSX.Element;
596
744
 
597
- export { type FieldConfig, Form, FormBody, form as FormBuilder, FormField, FormProvider, FormRow, FormSubmitButton, createForm, form, useFormContext };
745
+ export { type ConditionEvaluationResult, type FieldConfig, Form, type FormAction, FormBody, form as FormBuilder, FormField, FormProvider, FormRow, type FormState, FormSubmitButton, type UseFormConditionsProps, type UseFormConditionsReturn, type UseFormStateProps, type UseFormSubmissionProps, type UseFormValidationProps, createForm, form, useConditionEvaluation, useFormConditions, useFormContext, useFormState, useFormSubmission, useFormValidation, useMultipleConditionEvaluation };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { ril, FieldValidationConfig, FormFieldConfig, FormFieldRow, FormValidationConfig, FormValidator, FormConfiguration, ComponentRendererBaseProps, FormBodyRendererProps, ValidationError, ValidationResult, FormRowRendererProps, FormSubmitButtonRendererProps } from '@rilaykit/core';
2
+ import { ril, FieldValidationConfig, ConditionalBehavior, FormFieldConfig, FormFieldRow, FormValidationConfig, FormValidator, FormConfiguration, ComponentRendererBaseProps, FormBodyRendererProps, ValidationError, ValidationResult, FormRowRendererProps, FormSubmitButtonRendererProps } from '@rilaykit/core';
3
3
  export * from '@rilaykit/core';
4
4
  import React$1 from 'react';
5
5
 
@@ -31,6 +31,8 @@ type FieldConfig<C extends Record<string, any>, T extends keyof C> = {
31
31
  props?: Partial<C[T]>;
32
32
  /** Validation configuration for this field */
33
33
  validation?: FieldValidationConfig;
34
+ /** Conditional behavior configuration for this field */
35
+ conditions?: ConditionalBehavior;
34
36
  };
35
37
  /**
36
38
  * Form builder class for creating type-safe form configurations
@@ -122,7 +124,6 @@ declare class form<C extends Record<string, any> = Record<string, never>> {
122
124
  *
123
125
  * @template T - The component type
124
126
  * @param fieldConfigs - Array of field configurations for the row
125
- * @param rowOptions - Optional row layout configuration
126
127
  * @returns A complete FormFieldRow configuration
127
128
  * @throws Error if no fields provided or more than 3 fields specified
128
129
  *
@@ -174,7 +175,6 @@ declare class form<C extends Record<string, any> = Record<string, never>> {
174
175
  *
175
176
  * @template T - The component type
176
177
  * @param fieldConfigs - Array of field configurations
177
- * @param rowOptions - Optional row layout configuration applied to all rows
178
178
  * @returns The form builder instance for method chaining
179
179
  *
180
180
  * @example
@@ -369,6 +369,26 @@ declare class form<C extends Record<string, any> = Record<string, never>> {
369
369
  * ```
370
370
  */
371
371
  addFieldValidation(fieldId: string, validationConfig: FieldValidationConfig): this;
372
+ /**
373
+ * Adds conditions to a specific field by ID
374
+ *
375
+ * This method allows adding conditional behavior to a field after it has been created,
376
+ * useful for dynamic conditional requirements.
377
+ *
378
+ * @param fieldId - The ID of the field to add conditions to
379
+ * @param conditions - Conditional behavior configuration
380
+ * @returns The form builder instance for method chaining
381
+ * @throws Error if the field with the specified ID is not found
382
+ *
383
+ * @example
384
+ * ```typescript
385
+ * builder.addFieldConditions('phone', {
386
+ * visible: when('contactMethod').equals('phone').build(),
387
+ * required: when('contactMethod').equals('phone').build()
388
+ * });
389
+ * ```
390
+ */
391
+ addFieldConditions(fieldId: string, conditions: ConditionalBehavior): this;
372
392
  /**
373
393
  * Creates a deep copy of the current form builder
374
394
  *
@@ -551,8 +571,75 @@ interface FormFieldProps {
551
571
  disabled?: boolean;
552
572
  customProps?: Record<string, any>;
553
573
  className?: string;
574
+ /** Force field to be visible even if conditions say otherwise (for debugging) */
575
+ forceVisible?: boolean;
576
+ }
577
+ declare function FormField({ fieldId, disabled, customProps, className, forceVisible, }: FormFieldProps): react_jsx_runtime.JSX.Element | null;
578
+
579
+ interface ConditionEvaluationResult {
580
+ visible: boolean;
581
+ disabled: boolean;
582
+ required: boolean;
583
+ readonly: boolean;
554
584
  }
555
- declare function FormField({ fieldId, disabled, customProps, className, }: FormFieldProps): react_jsx_runtime.JSX.Element;
585
+ /**
586
+ * Hook to evaluate conditional behaviors based on form data
587
+ *
588
+ * @param conditions - The conditional behavior configuration
589
+ * @param formData - Current form data to evaluate against
590
+ * @param defaultState - Default state when no conditions are provided
591
+ * @returns Evaluated condition results
592
+ */
593
+ declare function useConditionEvaluation(conditions?: ConditionalBehavior, formData?: Record<string, any>, defaultState?: Partial<ConditionEvaluationResult>): ConditionEvaluationResult;
594
+ /**
595
+ * Hook to evaluate conditions for multiple fields at once
596
+ *
597
+ * @param fieldsWithConditions - Map of field IDs to their conditional behaviors
598
+ * @param formData - Current form data
599
+ * @returns Map of field IDs to their evaluated conditions
600
+ */
601
+ declare function useMultipleConditionEvaluation(fieldsWithConditions: Record<string, ConditionalBehavior | undefined>, formData?: Record<string, any>): Record<string, ConditionEvaluationResult>;
602
+
603
+ interface UseFormConditionsProps {
604
+ formConfig: FormConfiguration;
605
+ formValues: Record<string, any>;
606
+ }
607
+ interface UseFormConditionsReturn {
608
+ fieldConditions: Record<string, ConditionEvaluationResult>;
609
+ hasConditionalFields: boolean;
610
+ getFieldCondition: (fieldId: string) => ConditionEvaluationResult | undefined;
611
+ isFieldVisible: (fieldId: string) => boolean;
612
+ isFieldDisabled: (fieldId: string) => boolean;
613
+ isFieldRequired: (fieldId: string) => boolean;
614
+ isFieldReadonly: (fieldId: string) => boolean;
615
+ }
616
+ /**
617
+ * Hook to manage conditional behaviors for form fields
618
+ *
619
+ * This hook evaluates conditions for all form fields and provides
620
+ * convenient methods to check field states.
621
+ *
622
+ * @param props - Configuration for form conditions
623
+ * @returns Object containing field conditions and helper methods
624
+ *
625
+ * @example
626
+ * ```tsx
627
+ * const {
628
+ * fieldConditions,
629
+ * isFieldVisible,
630
+ * isFieldDisabled
631
+ * } = useFormConditions({
632
+ * formConfig,
633
+ * formValues
634
+ * });
635
+ *
636
+ * // Check if a field should be visible
637
+ * if (!isFieldVisible('phoneField')) {
638
+ * return null;
639
+ * }
640
+ * ```
641
+ */
642
+ declare function useFormConditions({ formConfig, formValues, }: UseFormConditionsProps): UseFormConditionsReturn;
556
643
 
557
644
  interface FormState {
558
645
  values: Record<string, any>;
@@ -561,11 +648,72 @@ interface FormState {
561
648
  touched: Record<string, boolean>;
562
649
  isDirty: boolean;
563
650
  isSubmitting: boolean;
564
- isValid: boolean;
565
651
  }
652
+ type FormAction = {
653
+ type: 'SET_VALUE';
654
+ fieldId: string;
655
+ value: any;
656
+ } | {
657
+ type: 'SET_FIELD_ERRORS';
658
+ fieldId: string;
659
+ errors: ValidationError[];
660
+ } | {
661
+ type: 'SET_FIELD_VALIDATION_STATE';
662
+ fieldId: string;
663
+ state: 'idle' | 'validating' | 'valid' | 'invalid';
664
+ } | {
665
+ type: 'SET_FIELD_TOUCHED';
666
+ fieldId: string;
667
+ } | {
668
+ type: 'SET_SUBMITTING';
669
+ isSubmitting: boolean;
670
+ } | {
671
+ type: 'RESET';
672
+ values?: Record<string, any>;
673
+ };
674
+ interface UseFormStateProps {
675
+ defaultValues?: Record<string, any>;
676
+ onFieldChange?: (fieldId: string, value: any, formData: Record<string, any>) => void;
677
+ }
678
+ declare function useFormState({ defaultValues, onFieldChange }: UseFormStateProps): {
679
+ formState: FormState;
680
+ setValue: (fieldId: string, value: any) => void;
681
+ setFieldTouched: (fieldId: string) => void;
682
+ setError: (fieldId: string, errors: ValidationError[]) => void;
683
+ clearError: (fieldId: string) => void;
684
+ setFieldValidationState: (fieldId: string, state: "idle" | "validating" | "valid" | "invalid") => void;
685
+ setSubmitting: (isSubmitting: boolean) => void;
686
+ reset: (values?: Record<string, any>) => void;
687
+ isFormValid: () => boolean;
688
+ };
689
+
690
+ interface UseFormSubmissionProps {
691
+ formState: FormState;
692
+ onSubmit?: (data: Record<string, any>) => void | Promise<void>;
693
+ validateForm: () => Promise<ValidationResult>;
694
+ setSubmitting: (isSubmitting: boolean) => void;
695
+ }
696
+ declare function useFormSubmission({ formState, onSubmit, validateForm, setSubmitting, }: UseFormSubmissionProps): {
697
+ submit: (event?: React$1.FormEvent) => Promise<boolean>;
698
+ };
699
+
700
+ interface UseFormValidationProps {
701
+ formConfig: FormConfiguration;
702
+ formState: FormState;
703
+ conditionsHelpers: Omit<UseFormConditionsReturn, 'fieldConditions'>;
704
+ setFieldValidationState: (fieldId: string, state: 'idle' | 'validating' | 'valid' | 'invalid') => void;
705
+ setError: (fieldId: string, errors: any[]) => void;
706
+ }
707
+ declare function useFormValidation({ formConfig, formState, conditionsHelpers, setFieldValidationState, setError, }: UseFormValidationProps): {
708
+ validateField: (fieldId: string, value?: any) => Promise<ValidationResult>;
709
+ validateForm: () => Promise<ValidationResult>;
710
+ };
711
+
566
712
  interface FormContextValue {
567
713
  formState: FormState;
568
714
  formConfig: FormConfiguration;
715
+ fieldConditions: Record<string, ConditionEvaluationResult>;
716
+ conditionsHelpers: Omit<UseFormConditionsReturn, 'fieldConditions'>;
569
717
  setValue: (fieldId: string, value: any) => void;
570
718
  setFieldTouched: (fieldId: string, touched?: boolean) => void;
571
719
  validateField: (fieldId: string, value?: any) => Promise<ValidationResult>;
@@ -594,4 +742,4 @@ declare function FormRow({ row, className, ...props }: FormRowProps): react_jsx_
594
742
 
595
743
  declare function FormSubmitButton({ className, ...props }: ComponentRendererBaseProps<FormSubmitButtonRendererProps>): react_jsx_runtime.JSX.Element;
596
744
 
597
- export { type FieldConfig, Form, FormBody, form as FormBuilder, FormField, FormProvider, FormRow, FormSubmitButton, createForm, form, useFormContext };
745
+ export { type ConditionEvaluationResult, type FieldConfig, Form, type FormAction, FormBody, form as FormBuilder, FormField, FormProvider, FormRow, type FormState, FormSubmitButton, type UseFormConditionsProps, type UseFormConditionsReturn, type UseFormStateProps, type UseFormSubmissionProps, type UseFormValidationProps, createForm, form, useConditionEvaluation, useFormConditions, useFormContext, useFormState, useFormSubmission, useFormValidation, useMultipleConditionEvaluation };
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- 'use strict';var se=require('react'),core=require('@rilaykit/core'),jsxRuntime=require('react/jsx-runtime');function _interopDefault(e){return e&&e.__esModule?e:{default:e}}var se__default=/*#__PURE__*/_interopDefault(se);var v=class t{constructor(e,r){this.rows=[];this.idGenerator=new core.IdGenerator;this.config=e,this.formId=r||`form-${Date.now()}`;}static create(e,r){return new t(e,r)}createFormField(e){let r=this.config.getComponent(e.type);if(!r)throw new Error(`No component found with type "${e.type}"`);let i;return (r.validation||e.validation)&&(i={validateOnChange:e.validation?.validateOnChange??r.validation?.validateOnChange,validateOnBlur:e.validation?.validateOnBlur??r.validation?.validateOnBlur,debounceMs:e.validation?.debounceMs??r.validation?.debounceMs,validators:[...r.validation?.validators||[],...e.validation?.validators||[]]}),{id:e.id||this.idGenerator.next("field"),componentId:r.id,props:{...r.defaultProps,...e.props},validation:i}}createRow(e){if(e.length===0)throw new Error("At least one field is required");if(e.length>3)throw new Error("Maximum 3 fields per row");let r=e.map(i=>this.createFormField(i));return {id:this.idGenerator.next("row"),fields:r,maxColumns:e.length}}add(...e){let r,i=false;if(e.length===1&&Array.isArray(e[0])?(r=e[0],i=true):r=e,r.length===0)throw new Error("At least one field is required");if(i&&r.length>3)throw new Error("Maximum 3 fields per row");if(r.length===1){let o=this.createRow(r);return this.rows.push(o),this}if(r.length<=3){let o=this.createRow(r);return this.rows.push(o),this}for(let o of r){let m=this.createRow([o]);this.rows.push(m);}return this}addSeparateRows(e){for(let r of e)this.add(r);return this}setId(e){return this.formId=e,this}updateField(e,r){let i=this.findField(e);if(!i)throw new Error(`Field with ID "${e}" not found`);return Object.assign(i,{...r,props:{...i.props,...r.props}}),this}findField(e){for(let r of this.rows){let i=r.fields.find(o=>o.id===e);if(i)return i}return null}removeField(e){return this.rows=this.rows.map(r=>({...r,fields:r.fields.filter(i=>i.id!==e)})).filter(r=>r.fields.length>0),this}getField(e){return this.findField(e)||void 0}getFields(){return this.rows.flatMap(e=>e.fields)}getRows(){return [...this.rows]}clear(){return this.rows=[],this.idGenerator.reset(),this}setValidation(e){return this.formValidation=e,this}addValidators(e){return this.formValidation||(this.formValidation={validators:[]}),this.formValidation={...this.formValidation,validators:[...this.formValidation.validators||[],...e]},this}addFieldValidation(e,r){let i=this.findField(e);if(!i)throw new Error(`Field with ID "${e}" not found`);let o={...i.validation,...r,validators:[...i.validation?.validators||[],...r.validators||[]]};return this.updateField(e,{validation:o})}clone(e){let r=new t(this.config,e||`${this.formId}-clone`);return r.rows=core.deepClone(this.rows),r}validate(){let e=[],r=this.getFields(),i=r.map(o=>o.id);try{core.ensureUnique(i,"field");}catch(o){e.push(o instanceof Error?o.message:String(o));}for(let o of r)this.config.hasComponent(o.componentId)||e.push(`Component "${o.componentId}" not found for field "${o.id}"`);for(let o of this.rows)o.fields.length>3&&e.push(`Row "${o.id}" has ${o.fields.length} fields, maximum is 3`),o.fields.length===0&&e.push(`Row "${o.id}" is empty`);return e}build(){let e=this.validate();if(e.length>0)throw new Error(`Form validation failed: ${e.join(", ")}`);return {id:this.formId,rows:[...this.rows],allFields:this.getFields(),config:this.config,renderConfig:this.config.getFormRenderConfig(),validation:this.formValidation}}toJSON(){return {id:this.formId,rows:this.rows}}fromJSON(e){return e.id&&(this.formId=e.id),e.rows&&(this.rows=e.rows),this}getStats(){let e=this.getFields(),r=this.rows.map(i=>i.fields.length);return {totalFields:e.length,totalRows:this.rows.length,averageFieldsPerRow:this.rows.length>0?e.length/this.rows.length:0,maxFieldsInRow:r.length>0?Math.max(...r):0,minFieldsInRow:r.length>0?Math.min(...r):0}}};function Z(t,e){return v.create(t,e)}core.ril.prototype.form=function(t){return v.create(this,t)};function k(){return {isValid:true,errors:[]}}function te(t,e){switch(e.type){case "SET_VALUE":{let r={...t.values,[e.fieldId]:e.value};return {...t,values:r,isDirty:true}}case "SET_FIELD_ERRORS":return {...t,errors:{...t.errors,[e.fieldId]:e.errors},touched:{...t.touched,[e.fieldId]:true}};case "SET_FIELD_VALIDATION_STATE":return {...t,validationState:{...t.validationState,[e.fieldId]:e.state}};case "SET_FIELD_TOUCHED":return {...t,touched:{...t.touched,[e.fieldId]:e.touched}};case "SET_SUBMITTING":return {...t,isSubmitting:e.isSubmitting};case "SET_FORM_VALIDITY":return {...t,isValid:e.isValid};case "RESET":return {values:e.values||{},errors:{},validationState:{},touched:{},isDirty:false,isSubmitting:false,isValid:true};default:return t}}var U=se.createContext(null);function B({children:t,formConfig:e,defaultValues:r={},onSubmit:i,onFieldChange:o,className:m}){let R={values:r,errors:{},validationState:{},touched:{},isDirty:false,isSubmitting:false,isValid:true},[s,d]=se.useReducer(te,R),a=se.useRef(i),c=se.useRef(o),u=se.useRef(r);a.current=i,c.current=o,se.useEffect(()=>{JSON.stringify(u.current)!==JSON.stringify(r)&&(u.current=r,d({type:"RESET",values:r}));},[r]);let E=se.useCallback((n,l)=>{d({type:"SET_VALUE",fieldId:n,value:l}),c.current?.(n,l,{...s.values,[n]:l});},[s.values]),S=se.useCallback((n,l=true)=>{d({type:"SET_FIELD_TOUCHED",fieldId:n,touched:l});},[]),g=se.useCallback(async(n,l)=>{let p=e.allFields.find(f=>f.id===n);if(!p||!p.validation?.validators)return k();let y=l!==void 0?l:s.values[n],_=core.createValidationContext({fieldId:n,formId:e.id,allFormData:{...s.values,[n]:y}});d({type:"SET_FIELD_VALIDATION_STATE",fieldId:n,state:"validating"});try{let f=await core.runValidatorsAsync(p.validation.validators,y,_);return d({type:"SET_FIELD_ERRORS",fieldId:n,errors:f.errors}),d({type:"SET_FIELD_VALIDATION_STATE",fieldId:n,state:f.isValid?"valid":"invalid"}),f}catch(f){let x={isValid:false,errors:[{message:f instanceof Error?f.message:"Validation failed",code:"VALIDATION_ERROR"}]};return d({type:"SET_FIELD_ERRORS",fieldId:n,errors:x.errors}),d({type:"SET_FIELD_VALIDATION_STATE",fieldId:n,state:"invalid"}),x}},[e,s.values]),w=se.useCallback(async()=>{let n=e.allFields.filter(f=>f.validation?.validators).map(f=>g(f.id)),l=await Promise.all(n),p=l.some(f=>!f.isValid),y=k();if(e.validation?.validators){let f=core.createValidationContext({formId:e.id,allFormData:s.values});try{y=await core.runValidatorsAsync(e.validation.validators,s.values,f);}catch(x){y={isValid:false,errors:[{message:x instanceof Error?x.message:"Form validation failed",code:"FORM_VALIDATION_ERROR"}]};}}let _={isValid:!p&&y.isValid,errors:[...l.flatMap(f=>f.errors),...y.errors]};return d({type:"SET_FORM_VALIDITY",isValid:_.isValid}),_},[e,s.values,g]),T=se.useCallback(()=>{let n=Object.values(s.errors).some(p=>p.length>0),l=Object.values(s.validationState).some(p=>p==="invalid");return s.isValid&&!n&&!l},[s.isValid,s.errors,s.validationState]),V=se.useMemo(()=>e,[e]),b=se.useCallback(n=>{d({type:"RESET",values:n});},[]),P=se.useCallback((n,l)=>{d({type:"SET_FIELD_ERRORS",fieldId:n,errors:l}),l.length>0&&d({type:"SET_FORM_VALIDITY",isValid:false});},[]),C=se.useCallback(n=>{d({type:"SET_FIELD_ERRORS",fieldId:n,errors:[]});},[]),D=se.useCallback(async n=>{n?.preventDefault();try{return d({type:"SET_SUBMITTING",isSubmitting:!0}),(await w()).isValid?(a.current&&await a.current(s.values),!0):!1}catch(l){return console.error("Error during form submission:",l),false}finally{d({type:"SET_SUBMITTING",isSubmitting:false});}},[s.values,w]),H=se.useMemo(()=>({formState:s,formConfig:V,setValue:E,setFieldTouched:S,validateField:g,validateForm:w,isFormValid:T,reset:b,submit:D,setError:P,clearError:C}),[s,V,E,S,g,w,T,b,D,P,C]);return jsxRuntime.jsx(U.Provider,{value:H,children:jsxRuntime.jsx("form",{onSubmit:D,className:m,noValidate:true,children:t})})}function h(){let t=se.useContext(U);if(!t)throw new Error("useFormContext must be used within a FormProvider");return t}function ne({formConfig:t,defaultValues:e,onSubmit:r,onFieldChange:i,children:o}){let m=se.useMemo(()=>t instanceof v?t.build():t,[t]);return jsxRuntime.jsx(B,{formConfig:m,defaultValues:e,onSubmit:r,onFieldChange:i,children:o})}function O({fieldId:t,disabled:e=false,customProps:r={},className:i}){let{formState:o,formConfig:m,setValue:R,setFieldTouched:s,validateField:d}=h(),a=se.useMemo(()=>m.allFields.find(C=>C.id===t),[m.allFields,t]);if(!a)throw new Error(`Field with ID "${t}" not found`);let c=se.useMemo(()=>m.config.getComponent(a.componentId),[m.config,a.componentId]);if(!c)throw new Error(`Component with ID "${a.componentId}" not found`);let u=se.useMemo(()=>({value:o.values[t],errors:o.errors[t]||[],validationState:o.validationState[t]||"idle",isValidating:o.validationState[t]==="validating",isTouched:o.touched[t]||false}),[o.values,o.errors,o.validationState,o.touched,t]),E=se.useCallback(async C=>{R(a.id,C),(a.validation?.validateOnChange||u.isTouched)&&await d(a.id,C);},[a.id,a.validation?.validateOnChange,u.isTouched,R,d]),S=se.useCallback(async()=>{u.isTouched||s(a.id,true),(a.validation?.validateOnBlur||!a.validation?.validateOnChange)&&await d(a.id);},[a.id,a.validation?.validateOnBlur,a.validation?.validateOnChange,u.isTouched,s,d]),g=se.useMemo(()=>({...c.defaultProps??{},...a.props,...r}),[c.defaultProps,a.props,r]),w=se.useMemo(()=>({id:a.id,props:g,value:u.value,onChange:E,onBlur:S,disabled:e,error:u.errors,isValidating:u.isValidating,touched:u.isTouched}),[a.id,g,u.value,u.errors,u.isValidating,u.isTouched,E,S,e]),T=m.renderConfig?.fieldRenderer,V=c.renderer(w),b=c.useFieldRenderer!==false,P=T&&b?T({children:V,id:a.id,disabled:e,...g,error:u.errors,isValidating:u.isValidating,touched:u.isTouched}):V;return jsxRuntime.jsx("div",{className:i,"data-field-id":a.id,"data-field-type":c.type,children:P})}se__default.default.memo(O);function J({row:t,className:e,...r}){let{formConfig:i}=h(),o=t.fields.map(R=>jsxRuntime.jsx(O,{fieldId:R.id},R.id)),m={row:t,children:o,className:e};return jsxRuntime.jsx(core.ComponentRendererWrapper,{name:"FormRow",renderer:i.renderConfig?.rowRenderer,props:m,...r,children:o})}var Y=J;function fe({className:t,...e}){let{formConfig:r}=h(),i=se.useMemo(()=>r.rows.map(m=>jsxRuntime.jsx(Y,{row:m},m.id)),[r.rows]),o={formConfig:r,children:i,className:t};return jsxRuntime.jsx(core.ComponentRendererWrapper,{name:"FormBody",renderer:r.renderConfig?.bodyRenderer,props:o,...e,children:i})}function pe({className:t,...e}){let{formState:r,submit:i,formConfig:o}=h(),m={isSubmitting:r.isSubmitting,onSubmit:i,className:t};return jsxRuntime.jsx(core.ComponentRendererWrapper,{name:"FormSubmitButton",renderer:o.renderConfig?.submitButtonRenderer,props:m,...e})}exports.Form=ne;exports.FormBody=fe;exports.FormBuilder=v;exports.FormField=O;exports.FormProvider=B;exports.FormRow=J;exports.FormSubmitButton=pe;exports.createForm=Z;exports.form=v;exports.useFormContext=h;Object.keys(core).forEach(function(k){if(k!=='default'&&!Object.prototype.hasOwnProperty.call(exports,k))Object.defineProperty(exports,k,{enumerable:true,get:function(){return core[k]}})});
1
+ 'use strict';var Re=require('react'),core=require('@rilaykit/core'),jsxRuntime=require('react/jsx-runtime');function _interopDefault(e){return e&&e.__esModule?e:{default:e}}var Re__default=/*#__PURE__*/_interopDefault(Re);var h=class i{constructor(e,r){this.rows=[];this.idGenerator=new core.IdGenerator;this.config=e,this.formId=r||`form-${Math.random().toString(36).substring(2,15)}`;}static create(e,r){return new i(e,r)}createFormField(e){let r=this.config.getComponent(e.type);if(!r)throw new Error(`No component found with type "${e.type}"`);let t;return (r.validation||e.validation)&&(t={validateOnChange:e.validation?.validateOnChange??r.validation?.validateOnChange,validateOnBlur:e.validation?.validateOnBlur??r.validation?.validateOnBlur,debounceMs:e.validation?.debounceMs??r.validation?.debounceMs,validators:[...r.validation?.validators||[],...e.validation?.validators||[]]}),{id:e.id||this.idGenerator.next("field"),componentId:r.id,props:{...r.defaultProps,...e.props},validation:t,conditions:e.conditions}}createRow(e){if(e.length===0)throw new Error("At least one field is required");if(e.length>3)throw new Error("Maximum 3 fields per row");let r=e.map(t=>this.createFormField(t));return {id:this.idGenerator.next("row"),fields:r,maxColumns:e.length}}add(...e){let r,t=false;if(e.length===1&&Array.isArray(e[0])?(r=e[0],t=true):r=e,r.length===0)throw new Error("At least one field is required");if(t&&r.length>3)throw new Error("Maximum 3 fields per row");if(r.length===1){let o=this.createRow(r);return this.rows.push(o),this}if(r.length<=3){let o=this.createRow(r);return this.rows.push(o),this}for(let o of r){let d=this.createRow([o]);this.rows.push(d);}return this}addSeparateRows(e){for(let r of e)this.add(r);return this}setId(e){return this.formId=e,this}updateField(e,r){let t=this.findField(e);if(!t)throw new Error(`Field with ID "${e}" not found`);return Object.assign(t,{...r,props:{...t.props,...r.props}}),this}findField(e){for(let r of this.rows){let t=r.fields.find(o=>o.id===e);if(t)return t}return null}removeField(e){return this.rows=this.rows.map(r=>({...r,fields:r.fields.filter(t=>t.id!==e)})).filter(r=>r.fields.length>0),this}getField(e){return this.findField(e)||void 0}getFields(){return this.rows.flatMap(e=>e.fields)}getRows(){return [...this.rows]}clear(){return this.rows=[],this.idGenerator.reset(),this}setValidation(e){return this.formValidation=e,this}addValidators(e){return this.formValidation||(this.formValidation={validators:[]}),this.formValidation={...this.formValidation,validators:[...this.formValidation.validators||[],...e]},this}addFieldValidation(e,r){let t=this.findField(e);if(!t)throw new Error(`Field with ID "${e}" not found`);let o={...t.validation,...r,validators:[...t.validation?.validators||[],...r.validators||[]]};return this.updateField(e,{validation:o})}addFieldConditions(e,r){let t=this.findField(e);if(!t)throw new Error(`Field with ID "${e}" not found`);let o={...t.conditions,...r};return this.updateField(e,{conditions:o})}clone(e){let r=new i(this.config,e||`${this.formId}-clone`);return r.rows=core.deepClone(this.rows),r}validate(){let e=[],r=this.getFields(),t=r.map(o=>o.id);try{core.ensureUnique(t,"field");}catch(o){e.push(o instanceof Error?o.message:String(o));}for(let o of r)this.config.hasComponent(o.componentId)||e.push(`Component "${o.componentId}" not found for field "${o.id}"`);for(let o of this.rows)o.fields.length>3&&e.push(`Row "${o.id}" has ${o.fields.length} fields, maximum is 3`),o.fields.length===0&&e.push(`Row "${o.id}" is empty`);return e}build(){let e=this.validate();if(e.length>0)throw new Error(`Form validation failed: ${e.join(", ")}`);return {id:this.formId,rows:[...this.rows],allFields:this.getFields(),config:this.config,renderConfig:this.config.getFormRenderConfig(),validation:this.formValidation}}toJSON(){return {id:this.formId,rows:this.rows}}fromJSON(e){return e.id&&(this.formId=e.id),e.rows&&(this.rows=e.rows),this}getStats(){let e=this.getFields(),r=this.rows.map(t=>t.fields.length);return {totalFields:e.length,totalRows:this.rows.length,averageFieldsPerRow:this.rows.length>0?e.length/this.rows.length:0,maxFieldsInRow:r.length>0?Math.max(...r):0,minFieldsInRow:r.length>0?Math.min(...r):0}}};function ae(i,e){return h.create(i,e)}core.ril.prototype.form=function(i){return h.create(this,i)};function De(i,e={},r={}){return Re.useMemo(()=>{if(!i)return {visible:r.visible??true,disabled:r.disabled??false,required:r.required??false,readonly:r.readonly??false};let t=o=>{try{return o&&typeof o=="object"&&"build"in o?core.evaluateCondition(o.build(),e):core.evaluateCondition(o,e)}catch(d){return console.warn("Error evaluating condition:",d),false}};return {visible:i.visible?t(i.visible):r.visible??true,disabled:i.disabled?t(i.disabled):r.disabled??false,required:i.required?t(i.required):r.required??false,readonly:i.readonly?t(i.readonly):r.readonly??false}},[i,e,r])}function L(i,e={}){return Re.useMemo(()=>{let r={};for(let[t,o]of Object.entries(i))if(r[t]={visible:true,disabled:false,required:false,readonly:false},o){let d=m=>{try{return m&&typeof m=="object"&&"build"in m?core.evaluateCondition(m.build(),e):core.evaluateCondition(m,e)}catch(s){return console.warn(`Error evaluating condition for field ${t}:`,s),false}};r[t]={visible:o.visible?d(o.visible):true,disabled:o.disabled?d(o.disabled):false,required:o.required?d(o.required):false,readonly:o.readonly?d(o.readonly):false};}return r},[i,e])}function $({formConfig:i,formValues:e}){let r=Re.useMemo(()=>{let l={};for(let a of i.allFields)a.conditions&&(l[a.id]=a.conditions);return l},[i.allFields]),t=Re.useMemo(()=>Object.keys(r).length>0,[r]),o=L(t?r:{},t?e:{}),d=Re.useCallback(l=>o[l],[o]),m=Re.useCallback(l=>{let a=o[l];return a?a.visible:true},[o]),s=Re.useCallback(l=>{let a=o[l];return a?a.disabled:false},[o]),F=Re.useCallback(l=>{let a=o[l];return a?a.required:false},[o]),f=Re.useCallback(l=>{let a=o[l];return a?a.readonly:false},[o]);return Re.useMemo(()=>({fieldConditions:o,hasConditionalFields:t,getFieldCondition:d,isFieldVisible:m,isFieldDisabled:s,isFieldRequired:F,isFieldReadonly:f}),[o,t,d,m,s,F,f])}function ue(i,e){switch(e.type){case "SET_VALUE":return {...i,values:{...i.values,[e.fieldId]:e.value},isDirty:true};case "SET_FIELD_ERRORS":return {...i,errors:{...i.errors,[e.fieldId]:e.errors}};case "SET_FIELD_VALIDATION_STATE":return {...i,validationState:{...i.validationState,[e.fieldId]:e.state}};case "SET_FIELD_TOUCHED":return {...i,touched:{...i.touched,[e.fieldId]:true}};case "SET_SUBMITTING":return {...i,isSubmitting:e.isSubmitting};case "RESET":return {values:e.values||{},errors:{},validationState:{},touched:{},isDirty:false,isSubmitting:false};default:return i}}function G({defaultValues:i={},onFieldChange:e}){let r={values:i,errors:{},validationState:{},touched:{},isDirty:false,isSubmitting:false},[t,o]=Re.useReducer(ue,r),d=Re.useRef(e);d.current=e;let m=Re.useCallback((u,c)=>{o({type:"SET_VALUE",fieldId:u,value:c}),d.current?.(u,c,{...t.values,[u]:c});},[t.values]),s=Re.useCallback(u=>{o({type:"SET_FIELD_TOUCHED",fieldId:u});},[]),F=Re.useCallback((u,c)=>{o({type:"SET_FIELD_ERRORS",fieldId:u,errors:c});},[]),f=Re.useCallback(u=>{o({type:"SET_FIELD_ERRORS",fieldId:u,errors:[]});},[]),l=Re.useCallback((u,c)=>{o({type:"SET_FIELD_VALIDATION_STATE",fieldId:u,state:c});},[]),a=Re.useCallback(u=>{o({type:"SET_SUBMITTING",isSubmitting:u});},[]),n=Re.useCallback(u=>{o({type:"RESET",values:u});},[]),v=Re.useCallback(()=>{let u=Object.values(t.errors).some(p=>p.length>0),c=Object.values(t.validationState).some(p=>p==="invalid");return !u&&!c},[t.errors,t.validationState]);return {formState:t,setValue:m,setFieldTouched:s,setError:F,clearError:f,setFieldValidationState:l,setSubmitting:a,reset:n,isFormValid:v}}function W({formState:i,onSubmit:e,validateForm:r,setSubmitting:t}){let o=Re.useRef(e);return o.current=e,{submit:Re.useCallback(async m=>{m?.preventDefault();try{return t(!0),(await r()).isValid?(o.current&&await o.current(i.values),!0):!1}catch(s){return console.error("Error during form submission:",s),false}finally{t(false);}},[i.values,r,t])}}function k(){return {isValid:true,errors:[]}}function H({formConfig:i,formState:e,conditionsHelpers:r,setFieldValidationState:t,setError:o}){let d=Re.useCallback(async(s,F)=>{let f=i.allFields.find(n=>n.id===s);if(!f)return k();if(!r.isFieldVisible(s))return o(s,[]),t(s,"valid"),k();if(!f.validation?.validators?.length)return o(s,[]),t(s,"valid"),k();let l=F!==void 0?F:e.values[s],a=core.createValidationContext({fieldId:s,formId:i.id,allFormData:{...e.values,[s]:l}});t(s,"validating");try{let n=await core.runValidatorsAsync(f.validation.validators,l,a),v=r.isFieldRequired(s),u=l==null||l==="";if(v&&u&&!n.errors.some(p=>p.code==="REQUIRED"||p.message.toLowerCase().includes("required"))){let p={isValid:!1,errors:[{message:"This field is required",code:"CONDITIONAL_REQUIRED"},...n.errors]};return o(s,p.errors),t(s,"invalid"),p}return o(s,n.errors),t(s,n.isValid?"valid":"invalid"),n}catch(n){let v={isValid:false,errors:[{message:n instanceof Error?n.message:"Validation failed",code:"VALIDATION_ERROR"}]};return o(s,v.errors),t(s,"invalid"),v}},[i,e.values,r,t,o]),m=Re.useCallback(async()=>{let s=i.allFields.filter(n=>{let v=r.isFieldVisible(n.id),u=n.validation?.validators&&n.validation.validators.length>0;return v&&u}),F=i.allFields.filter(n=>!r.isFieldVisible(n.id));for(let n of F)o(n.id,[]),t(n.id,"valid");let f=await Promise.all(s.map(n=>d(n.id))),l=f.some(n=>!n.isValid),a=k();if(i.validation?.validators?.length){let n=Object.keys(e.values).reduce((u,c)=>(r.isFieldVisible(c)&&(u[c]=e.values[c]),u),{}),v=core.createValidationContext({formId:i.id,allFormData:n});try{a=await core.runValidatorsAsync(i.validation.validators,n,v);}catch(u){a={isValid:false,errors:[{message:u instanceof Error?u.message:"Form validation failed",code:"FORM_VALIDATION_ERROR"}]};}}return {isValid:!l&&a.isValid,errors:[...f.flatMap(n=>n.errors),...a.errors]}},[i,e.values,r,d,o,t]);return {validateField:d,validateForm:m}}var K=Re.createContext(null);function M({children:i,formConfig:e,defaultValues:r={},onSubmit:t,onFieldChange:o,className:d}){let m=Re.useRef(e.id),{formState:s,setValue:F,setFieldTouched:f,reset:l,setError:a,clearError:n,setFieldValidationState:v,setSubmitting:u,isFormValid:c}=G({defaultValues:r,onFieldChange:o}),{fieldConditions:p,hasConditionalFields:b,getFieldCondition:w,isFieldVisible:R,isFieldDisabled:E,isFieldRequired:V,isFieldReadonly:I}=$({formConfig:e,formValues:s.values}),x=Re.useMemo(()=>({hasConditionalFields:b,getFieldCondition:w,isFieldVisible:R,isFieldDisabled:E,isFieldRequired:V,isFieldReadonly:I}),[b,w,R,E,V,I]),{validateField:S,validateForm:P}=H({formConfig:e,formState:s,conditionsHelpers:x,setFieldValidationState:v,setError:a}),{submit:y}=W({formState:s,onSubmit:t,validateForm:P,setSubmitting:u});Re.useEffect(()=>{(m.current===null||e.id!==m.current)&&(m.current=e.id,l(r));},[e.id,l]);let T=Re.useMemo(()=>e,[e]),q=Re.useMemo(()=>({formState:s,formConfig:T,fieldConditions:p,conditionsHelpers:x,setValue:F,setFieldTouched:f,validateField:S,validateForm:P,isFormValid:c,reset:l,submit:y,setError:a,clearError:n}),[s,T,p,x,F,f,S,P,c,l,y,a,n]);return jsxRuntime.jsx(K.Provider,{value:q,children:jsxRuntime.jsx("form",{onSubmit:y,className:d,noValidate:true,children:i})})}function g(){let i=Re.useContext(K);if(!i)throw new Error("useFormContext must be used within a FormProvider");return i}function he({formConfig:i,defaultValues:e,onSubmit:r,onFieldChange:t,children:o}){let d=Re.useMemo(()=>i instanceof h?i.build():i,[i]);return jsxRuntime.jsx(M,{formConfig:d,defaultValues:e,onSubmit:r,onFieldChange:t,children:o})}function _({fieldId:i,disabled:e=false,customProps:r={},className:t,forceVisible:o=false}){let{formState:d,formConfig:m,setValue:s,setFieldTouched:F,validateField:f,conditionsHelpers:l}=g(),a=m.allFields.find(O=>O.id===i);if(!a)throw new Error(`Field with ID "${i}" not found`);let n=m.config.getComponent(a.componentId);if(!n)throw new Error(`Component with ID "${a.componentId}" not found`);let v=d.values[i],u=d.errors[i]||[],c=d.validationState[i]||"idle",p=d.touched[i]||false,b=c==="validating",w=o||l.isFieldVisible(i),R=e||l.isFieldDisabled(i),E=l.isFieldRequired(i),V=l.isFieldReadonly(i);if(!w)return null;let I=Re.useCallback(async O=>{s(i,O),(a.validation?.validateOnChange||p)&&await f(i,O);},[i,s,f,a.validation?.validateOnChange,p]),x=Re.useCallback(async()=>{p||F(i),a.validation?.validateOnBlur!==false&&await f(i);},[i,p,F,f,a.validation?.validateOnBlur]),S={...n.defaultProps??{},...a.props,...r,disabled:R,required:E,readOnly:V},P={id:i,props:S,value:v,onChange:I,onBlur:x,disabled:R,error:u,isValidating:b,touched:p},y=m.renderConfig?.fieldRenderer,T=n.renderer(P),q=n.useFieldRenderer!==false,oe=y&&q?y({children:T,id:i,...S,error:u,isValidating:b,touched:p}):T;return jsxRuntime.jsx("div",{className:t,"data-field-id":i,"data-field-type":n.type,"data-field-visible":w,"data-field-disabled":R,"data-field-required":E,"data-field-readonly":V,children:oe})}Re__default.default.memo(_);function Z({row:i,className:e,...r}){let{formConfig:t}=g(),o=i.fields.map(m=>jsxRuntime.jsx(_,{fieldId:m.id},m.id)),d={row:i,children:o,className:e};return jsxRuntime.jsx(core.ComponentRendererWrapper,{name:"FormRow",renderer:t.renderConfig?.rowRenderer,props:d,...r,children:o})}var ee=Z;function Ve({className:i,...e}){let{formConfig:r}=g(),t=Re.useMemo(()=>r.rows.map(d=>jsxRuntime.jsx(ee,{row:d},d.id)),[r.rows]),o={formConfig:r,children:t,className:i};return jsxRuntime.jsx(core.ComponentRendererWrapper,{name:"FormBody",renderer:r.renderConfig?.bodyRenderer,props:o,...e,children:t})}function Se({className:i,...e}){let{formState:r,submit:t,formConfig:o}=g(),d={isSubmitting:r.isSubmitting,onSubmit:t,className:i};return jsxRuntime.jsx(core.ComponentRendererWrapper,{name:"FormSubmitButton",renderer:o.renderConfig?.submitButtonRenderer,props:d,...e})}exports.Form=he;exports.FormBody=Ve;exports.FormBuilder=h;exports.FormField=_;exports.FormProvider=M;exports.FormRow=Z;exports.FormSubmitButton=Se;exports.createForm=ae;exports.form=h;exports.useConditionEvaluation=De;exports.useFormConditions=$;exports.useFormContext=g;exports.useFormState=G;exports.useFormSubmission=W;exports.useFormValidation=H;exports.useMultipleConditionEvaluation=L;Object.keys(core).forEach(function(k){if(k!=='default'&&!Object.prototype.hasOwnProperty.call(exports,k))Object.defineProperty(exports,k,{enumerable:true,get:function(){return core[k]}})});
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- import se,{createContext,useMemo,useCallback,useContext,useReducer,useRef,useEffect}from'react';import {ril,IdGenerator,deepClone,ensureUnique,createValidationContext,runValidatorsAsync,ComponentRendererWrapper}from'@rilaykit/core';export*from'@rilaykit/core';import {jsx}from'react/jsx-runtime';var v=class t{constructor(e,r){this.rows=[];this.idGenerator=new IdGenerator;this.config=e,this.formId=r||`form-${Date.now()}`;}static create(e,r){return new t(e,r)}createFormField(e){let r=this.config.getComponent(e.type);if(!r)throw new Error(`No component found with type "${e.type}"`);let i;return (r.validation||e.validation)&&(i={validateOnChange:e.validation?.validateOnChange??r.validation?.validateOnChange,validateOnBlur:e.validation?.validateOnBlur??r.validation?.validateOnBlur,debounceMs:e.validation?.debounceMs??r.validation?.debounceMs,validators:[...r.validation?.validators||[],...e.validation?.validators||[]]}),{id:e.id||this.idGenerator.next("field"),componentId:r.id,props:{...r.defaultProps,...e.props},validation:i}}createRow(e){if(e.length===0)throw new Error("At least one field is required");if(e.length>3)throw new Error("Maximum 3 fields per row");let r=e.map(i=>this.createFormField(i));return {id:this.idGenerator.next("row"),fields:r,maxColumns:e.length}}add(...e){let r,i=false;if(e.length===1&&Array.isArray(e[0])?(r=e[0],i=true):r=e,r.length===0)throw new Error("At least one field is required");if(i&&r.length>3)throw new Error("Maximum 3 fields per row");if(r.length===1){let o=this.createRow(r);return this.rows.push(o),this}if(r.length<=3){let o=this.createRow(r);return this.rows.push(o),this}for(let o of r){let m=this.createRow([o]);this.rows.push(m);}return this}addSeparateRows(e){for(let r of e)this.add(r);return this}setId(e){return this.formId=e,this}updateField(e,r){let i=this.findField(e);if(!i)throw new Error(`Field with ID "${e}" not found`);return Object.assign(i,{...r,props:{...i.props,...r.props}}),this}findField(e){for(let r of this.rows){let i=r.fields.find(o=>o.id===e);if(i)return i}return null}removeField(e){return this.rows=this.rows.map(r=>({...r,fields:r.fields.filter(i=>i.id!==e)})).filter(r=>r.fields.length>0),this}getField(e){return this.findField(e)||void 0}getFields(){return this.rows.flatMap(e=>e.fields)}getRows(){return [...this.rows]}clear(){return this.rows=[],this.idGenerator.reset(),this}setValidation(e){return this.formValidation=e,this}addValidators(e){return this.formValidation||(this.formValidation={validators:[]}),this.formValidation={...this.formValidation,validators:[...this.formValidation.validators||[],...e]},this}addFieldValidation(e,r){let i=this.findField(e);if(!i)throw new Error(`Field with ID "${e}" not found`);let o={...i.validation,...r,validators:[...i.validation?.validators||[],...r.validators||[]]};return this.updateField(e,{validation:o})}clone(e){let r=new t(this.config,e||`${this.formId}-clone`);return r.rows=deepClone(this.rows),r}validate(){let e=[],r=this.getFields(),i=r.map(o=>o.id);try{ensureUnique(i,"field");}catch(o){e.push(o instanceof Error?o.message:String(o));}for(let o of r)this.config.hasComponent(o.componentId)||e.push(`Component "${o.componentId}" not found for field "${o.id}"`);for(let o of this.rows)o.fields.length>3&&e.push(`Row "${o.id}" has ${o.fields.length} fields, maximum is 3`),o.fields.length===0&&e.push(`Row "${o.id}" is empty`);return e}build(){let e=this.validate();if(e.length>0)throw new Error(`Form validation failed: ${e.join(", ")}`);return {id:this.formId,rows:[...this.rows],allFields:this.getFields(),config:this.config,renderConfig:this.config.getFormRenderConfig(),validation:this.formValidation}}toJSON(){return {id:this.formId,rows:this.rows}}fromJSON(e){return e.id&&(this.formId=e.id),e.rows&&(this.rows=e.rows),this}getStats(){let e=this.getFields(),r=this.rows.map(i=>i.fields.length);return {totalFields:e.length,totalRows:this.rows.length,averageFieldsPerRow:this.rows.length>0?e.length/this.rows.length:0,maxFieldsInRow:r.length>0?Math.max(...r):0,minFieldsInRow:r.length>0?Math.min(...r):0}}};function Z(t,e){return v.create(t,e)}ril.prototype.form=function(t){return v.create(this,t)};function k(){return {isValid:true,errors:[]}}function te(t,e){switch(e.type){case "SET_VALUE":{let r={...t.values,[e.fieldId]:e.value};return {...t,values:r,isDirty:true}}case "SET_FIELD_ERRORS":return {...t,errors:{...t.errors,[e.fieldId]:e.errors},touched:{...t.touched,[e.fieldId]:true}};case "SET_FIELD_VALIDATION_STATE":return {...t,validationState:{...t.validationState,[e.fieldId]:e.state}};case "SET_FIELD_TOUCHED":return {...t,touched:{...t.touched,[e.fieldId]:e.touched}};case "SET_SUBMITTING":return {...t,isSubmitting:e.isSubmitting};case "SET_FORM_VALIDITY":return {...t,isValid:e.isValid};case "RESET":return {values:e.values||{},errors:{},validationState:{},touched:{},isDirty:false,isSubmitting:false,isValid:true};default:return t}}var U=createContext(null);function B({children:t,formConfig:e,defaultValues:r={},onSubmit:i,onFieldChange:o,className:m}){let R={values:r,errors:{},validationState:{},touched:{},isDirty:false,isSubmitting:false,isValid:true},[s,d]=useReducer(te,R),a=useRef(i),c=useRef(o),u=useRef(r);a.current=i,c.current=o,useEffect(()=>{JSON.stringify(u.current)!==JSON.stringify(r)&&(u.current=r,d({type:"RESET",values:r}));},[r]);let E=useCallback((n,l)=>{d({type:"SET_VALUE",fieldId:n,value:l}),c.current?.(n,l,{...s.values,[n]:l});},[s.values]),S=useCallback((n,l=true)=>{d({type:"SET_FIELD_TOUCHED",fieldId:n,touched:l});},[]),g=useCallback(async(n,l)=>{let p=e.allFields.find(f=>f.id===n);if(!p||!p.validation?.validators)return k();let y=l!==void 0?l:s.values[n],_=createValidationContext({fieldId:n,formId:e.id,allFormData:{...s.values,[n]:y}});d({type:"SET_FIELD_VALIDATION_STATE",fieldId:n,state:"validating"});try{let f=await runValidatorsAsync(p.validation.validators,y,_);return d({type:"SET_FIELD_ERRORS",fieldId:n,errors:f.errors}),d({type:"SET_FIELD_VALIDATION_STATE",fieldId:n,state:f.isValid?"valid":"invalid"}),f}catch(f){let x={isValid:false,errors:[{message:f instanceof Error?f.message:"Validation failed",code:"VALIDATION_ERROR"}]};return d({type:"SET_FIELD_ERRORS",fieldId:n,errors:x.errors}),d({type:"SET_FIELD_VALIDATION_STATE",fieldId:n,state:"invalid"}),x}},[e,s.values]),w=useCallback(async()=>{let n=e.allFields.filter(f=>f.validation?.validators).map(f=>g(f.id)),l=await Promise.all(n),p=l.some(f=>!f.isValid),y=k();if(e.validation?.validators){let f=createValidationContext({formId:e.id,allFormData:s.values});try{y=await runValidatorsAsync(e.validation.validators,s.values,f);}catch(x){y={isValid:false,errors:[{message:x instanceof Error?x.message:"Form validation failed",code:"FORM_VALIDATION_ERROR"}]};}}let _={isValid:!p&&y.isValid,errors:[...l.flatMap(f=>f.errors),...y.errors]};return d({type:"SET_FORM_VALIDITY",isValid:_.isValid}),_},[e,s.values,g]),T=useCallback(()=>{let n=Object.values(s.errors).some(p=>p.length>0),l=Object.values(s.validationState).some(p=>p==="invalid");return s.isValid&&!n&&!l},[s.isValid,s.errors,s.validationState]),V=useMemo(()=>e,[e]),b=useCallback(n=>{d({type:"RESET",values:n});},[]),P=useCallback((n,l)=>{d({type:"SET_FIELD_ERRORS",fieldId:n,errors:l}),l.length>0&&d({type:"SET_FORM_VALIDITY",isValid:false});},[]),C=useCallback(n=>{d({type:"SET_FIELD_ERRORS",fieldId:n,errors:[]});},[]),D=useCallback(async n=>{n?.preventDefault();try{return d({type:"SET_SUBMITTING",isSubmitting:!0}),(await w()).isValid?(a.current&&await a.current(s.values),!0):!1}catch(l){return console.error("Error during form submission:",l),false}finally{d({type:"SET_SUBMITTING",isSubmitting:false});}},[s.values,w]),H=useMemo(()=>({formState:s,formConfig:V,setValue:E,setFieldTouched:S,validateField:g,validateForm:w,isFormValid:T,reset:b,submit:D,setError:P,clearError:C}),[s,V,E,S,g,w,T,b,D,P,C]);return jsx(U.Provider,{value:H,children:jsx("form",{onSubmit:D,className:m,noValidate:true,children:t})})}function h(){let t=useContext(U);if(!t)throw new Error("useFormContext must be used within a FormProvider");return t}function ne({formConfig:t,defaultValues:e,onSubmit:r,onFieldChange:i,children:o}){let m=useMemo(()=>t instanceof v?t.build():t,[t]);return jsx(B,{formConfig:m,defaultValues:e,onSubmit:r,onFieldChange:i,children:o})}function O({fieldId:t,disabled:e=false,customProps:r={},className:i}){let{formState:o,formConfig:m,setValue:R,setFieldTouched:s,validateField:d}=h(),a=useMemo(()=>m.allFields.find(C=>C.id===t),[m.allFields,t]);if(!a)throw new Error(`Field with ID "${t}" not found`);let c=useMemo(()=>m.config.getComponent(a.componentId),[m.config,a.componentId]);if(!c)throw new Error(`Component with ID "${a.componentId}" not found`);let u=useMemo(()=>({value:o.values[t],errors:o.errors[t]||[],validationState:o.validationState[t]||"idle",isValidating:o.validationState[t]==="validating",isTouched:o.touched[t]||false}),[o.values,o.errors,o.validationState,o.touched,t]),E=useCallback(async C=>{R(a.id,C),(a.validation?.validateOnChange||u.isTouched)&&await d(a.id,C);},[a.id,a.validation?.validateOnChange,u.isTouched,R,d]),S=useCallback(async()=>{u.isTouched||s(a.id,true),(a.validation?.validateOnBlur||!a.validation?.validateOnChange)&&await d(a.id);},[a.id,a.validation?.validateOnBlur,a.validation?.validateOnChange,u.isTouched,s,d]),g=useMemo(()=>({...c.defaultProps??{},...a.props,...r}),[c.defaultProps,a.props,r]),w=useMemo(()=>({id:a.id,props:g,value:u.value,onChange:E,onBlur:S,disabled:e,error:u.errors,isValidating:u.isValidating,touched:u.isTouched}),[a.id,g,u.value,u.errors,u.isValidating,u.isTouched,E,S,e]),T=m.renderConfig?.fieldRenderer,V=c.renderer(w),b=c.useFieldRenderer!==false,P=T&&b?T({children:V,id:a.id,disabled:e,...g,error:u.errors,isValidating:u.isValidating,touched:u.isTouched}):V;return jsx("div",{className:i,"data-field-id":a.id,"data-field-type":c.type,children:P})}se.memo(O);function J({row:t,className:e,...r}){let{formConfig:i}=h(),o=t.fields.map(R=>jsx(O,{fieldId:R.id},R.id)),m={row:t,children:o,className:e};return jsx(ComponentRendererWrapper,{name:"FormRow",renderer:i.renderConfig?.rowRenderer,props:m,...r,children:o})}var Y=J;function fe({className:t,...e}){let{formConfig:r}=h(),i=useMemo(()=>r.rows.map(m=>jsx(Y,{row:m},m.id)),[r.rows]),o={formConfig:r,children:i,className:t};return jsx(ComponentRendererWrapper,{name:"FormBody",renderer:r.renderConfig?.bodyRenderer,props:o,...e,children:i})}function pe({className:t,...e}){let{formState:r,submit:i,formConfig:o}=h(),m={isSubmitting:r.isSubmitting,onSubmit:i,className:t};return jsx(ComponentRendererWrapper,{name:"FormSubmitButton",renderer:o.renderConfig?.submitButtonRenderer,props:m,...e})}export{ne as Form,fe as FormBody,v as FormBuilder,O as FormField,B as FormProvider,J as FormRow,pe as FormSubmitButton,Z as createForm,v as form,h as useFormContext};
1
+ import Re,{createContext,useCallback,useContext,useMemo,useReducer,useRef,useEffect}from'react';import {ril,IdGenerator,deepClone,ensureUnique,createValidationContext,runValidatorsAsync,ComponentRendererWrapper,evaluateCondition}from'@rilaykit/core';export*from'@rilaykit/core';import {jsx}from'react/jsx-runtime';var h=class i{constructor(e,r){this.rows=[];this.idGenerator=new IdGenerator;this.config=e,this.formId=r||`form-${Math.random().toString(36).substring(2,15)}`;}static create(e,r){return new i(e,r)}createFormField(e){let r=this.config.getComponent(e.type);if(!r)throw new Error(`No component found with type "${e.type}"`);let t;return (r.validation||e.validation)&&(t={validateOnChange:e.validation?.validateOnChange??r.validation?.validateOnChange,validateOnBlur:e.validation?.validateOnBlur??r.validation?.validateOnBlur,debounceMs:e.validation?.debounceMs??r.validation?.debounceMs,validators:[...r.validation?.validators||[],...e.validation?.validators||[]]}),{id:e.id||this.idGenerator.next("field"),componentId:r.id,props:{...r.defaultProps,...e.props},validation:t,conditions:e.conditions}}createRow(e){if(e.length===0)throw new Error("At least one field is required");if(e.length>3)throw new Error("Maximum 3 fields per row");let r=e.map(t=>this.createFormField(t));return {id:this.idGenerator.next("row"),fields:r,maxColumns:e.length}}add(...e){let r,t=false;if(e.length===1&&Array.isArray(e[0])?(r=e[0],t=true):r=e,r.length===0)throw new Error("At least one field is required");if(t&&r.length>3)throw new Error("Maximum 3 fields per row");if(r.length===1){let o=this.createRow(r);return this.rows.push(o),this}if(r.length<=3){let o=this.createRow(r);return this.rows.push(o),this}for(let o of r){let d=this.createRow([o]);this.rows.push(d);}return this}addSeparateRows(e){for(let r of e)this.add(r);return this}setId(e){return this.formId=e,this}updateField(e,r){let t=this.findField(e);if(!t)throw new Error(`Field with ID "${e}" not found`);return Object.assign(t,{...r,props:{...t.props,...r.props}}),this}findField(e){for(let r of this.rows){let t=r.fields.find(o=>o.id===e);if(t)return t}return null}removeField(e){return this.rows=this.rows.map(r=>({...r,fields:r.fields.filter(t=>t.id!==e)})).filter(r=>r.fields.length>0),this}getField(e){return this.findField(e)||void 0}getFields(){return this.rows.flatMap(e=>e.fields)}getRows(){return [...this.rows]}clear(){return this.rows=[],this.idGenerator.reset(),this}setValidation(e){return this.formValidation=e,this}addValidators(e){return this.formValidation||(this.formValidation={validators:[]}),this.formValidation={...this.formValidation,validators:[...this.formValidation.validators||[],...e]},this}addFieldValidation(e,r){let t=this.findField(e);if(!t)throw new Error(`Field with ID "${e}" not found`);let o={...t.validation,...r,validators:[...t.validation?.validators||[],...r.validators||[]]};return this.updateField(e,{validation:o})}addFieldConditions(e,r){let t=this.findField(e);if(!t)throw new Error(`Field with ID "${e}" not found`);let o={...t.conditions,...r};return this.updateField(e,{conditions:o})}clone(e){let r=new i(this.config,e||`${this.formId}-clone`);return r.rows=deepClone(this.rows),r}validate(){let e=[],r=this.getFields(),t=r.map(o=>o.id);try{ensureUnique(t,"field");}catch(o){e.push(o instanceof Error?o.message:String(o));}for(let o of r)this.config.hasComponent(o.componentId)||e.push(`Component "${o.componentId}" not found for field "${o.id}"`);for(let o of this.rows)o.fields.length>3&&e.push(`Row "${o.id}" has ${o.fields.length} fields, maximum is 3`),o.fields.length===0&&e.push(`Row "${o.id}" is empty`);return e}build(){let e=this.validate();if(e.length>0)throw new Error(`Form validation failed: ${e.join(", ")}`);return {id:this.formId,rows:[...this.rows],allFields:this.getFields(),config:this.config,renderConfig:this.config.getFormRenderConfig(),validation:this.formValidation}}toJSON(){return {id:this.formId,rows:this.rows}}fromJSON(e){return e.id&&(this.formId=e.id),e.rows&&(this.rows=e.rows),this}getStats(){let e=this.getFields(),r=this.rows.map(t=>t.fields.length);return {totalFields:e.length,totalRows:this.rows.length,averageFieldsPerRow:this.rows.length>0?e.length/this.rows.length:0,maxFieldsInRow:r.length>0?Math.max(...r):0,minFieldsInRow:r.length>0?Math.min(...r):0}}};function ae(i,e){return h.create(i,e)}ril.prototype.form=function(i){return h.create(this,i)};function De(i,e={},r={}){return useMemo(()=>{if(!i)return {visible:r.visible??true,disabled:r.disabled??false,required:r.required??false,readonly:r.readonly??false};let t=o=>{try{return o&&typeof o=="object"&&"build"in o?evaluateCondition(o.build(),e):evaluateCondition(o,e)}catch(d){return console.warn("Error evaluating condition:",d),false}};return {visible:i.visible?t(i.visible):r.visible??true,disabled:i.disabled?t(i.disabled):r.disabled??false,required:i.required?t(i.required):r.required??false,readonly:i.readonly?t(i.readonly):r.readonly??false}},[i,e,r])}function L(i,e={}){return useMemo(()=>{let r={};for(let[t,o]of Object.entries(i))if(r[t]={visible:true,disabled:false,required:false,readonly:false},o){let d=m=>{try{return m&&typeof m=="object"&&"build"in m?evaluateCondition(m.build(),e):evaluateCondition(m,e)}catch(s){return console.warn(`Error evaluating condition for field ${t}:`,s),false}};r[t]={visible:o.visible?d(o.visible):true,disabled:o.disabled?d(o.disabled):false,required:o.required?d(o.required):false,readonly:o.readonly?d(o.readonly):false};}return r},[i,e])}function $({formConfig:i,formValues:e}){let r=useMemo(()=>{let l={};for(let a of i.allFields)a.conditions&&(l[a.id]=a.conditions);return l},[i.allFields]),t=useMemo(()=>Object.keys(r).length>0,[r]),o=L(t?r:{},t?e:{}),d=useCallback(l=>o[l],[o]),m=useCallback(l=>{let a=o[l];return a?a.visible:true},[o]),s=useCallback(l=>{let a=o[l];return a?a.disabled:false},[o]),F=useCallback(l=>{let a=o[l];return a?a.required:false},[o]),f=useCallback(l=>{let a=o[l];return a?a.readonly:false},[o]);return useMemo(()=>({fieldConditions:o,hasConditionalFields:t,getFieldCondition:d,isFieldVisible:m,isFieldDisabled:s,isFieldRequired:F,isFieldReadonly:f}),[o,t,d,m,s,F,f])}function ue(i,e){switch(e.type){case "SET_VALUE":return {...i,values:{...i.values,[e.fieldId]:e.value},isDirty:true};case "SET_FIELD_ERRORS":return {...i,errors:{...i.errors,[e.fieldId]:e.errors}};case "SET_FIELD_VALIDATION_STATE":return {...i,validationState:{...i.validationState,[e.fieldId]:e.state}};case "SET_FIELD_TOUCHED":return {...i,touched:{...i.touched,[e.fieldId]:true}};case "SET_SUBMITTING":return {...i,isSubmitting:e.isSubmitting};case "RESET":return {values:e.values||{},errors:{},validationState:{},touched:{},isDirty:false,isSubmitting:false};default:return i}}function G({defaultValues:i={},onFieldChange:e}){let r={values:i,errors:{},validationState:{},touched:{},isDirty:false,isSubmitting:false},[t,o]=useReducer(ue,r),d=useRef(e);d.current=e;let m=useCallback((u,c)=>{o({type:"SET_VALUE",fieldId:u,value:c}),d.current?.(u,c,{...t.values,[u]:c});},[t.values]),s=useCallback(u=>{o({type:"SET_FIELD_TOUCHED",fieldId:u});},[]),F=useCallback((u,c)=>{o({type:"SET_FIELD_ERRORS",fieldId:u,errors:c});},[]),f=useCallback(u=>{o({type:"SET_FIELD_ERRORS",fieldId:u,errors:[]});},[]),l=useCallback((u,c)=>{o({type:"SET_FIELD_VALIDATION_STATE",fieldId:u,state:c});},[]),a=useCallback(u=>{o({type:"SET_SUBMITTING",isSubmitting:u});},[]),n=useCallback(u=>{o({type:"RESET",values:u});},[]),v=useCallback(()=>{let u=Object.values(t.errors).some(p=>p.length>0),c=Object.values(t.validationState).some(p=>p==="invalid");return !u&&!c},[t.errors,t.validationState]);return {formState:t,setValue:m,setFieldTouched:s,setError:F,clearError:f,setFieldValidationState:l,setSubmitting:a,reset:n,isFormValid:v}}function W({formState:i,onSubmit:e,validateForm:r,setSubmitting:t}){let o=useRef(e);return o.current=e,{submit:useCallback(async m=>{m?.preventDefault();try{return t(!0),(await r()).isValid?(o.current&&await o.current(i.values),!0):!1}catch(s){return console.error("Error during form submission:",s),false}finally{t(false);}},[i.values,r,t])}}function k(){return {isValid:true,errors:[]}}function H({formConfig:i,formState:e,conditionsHelpers:r,setFieldValidationState:t,setError:o}){let d=useCallback(async(s,F)=>{let f=i.allFields.find(n=>n.id===s);if(!f)return k();if(!r.isFieldVisible(s))return o(s,[]),t(s,"valid"),k();if(!f.validation?.validators?.length)return o(s,[]),t(s,"valid"),k();let l=F!==void 0?F:e.values[s],a=createValidationContext({fieldId:s,formId:i.id,allFormData:{...e.values,[s]:l}});t(s,"validating");try{let n=await runValidatorsAsync(f.validation.validators,l,a),v=r.isFieldRequired(s),u=l==null||l==="";if(v&&u&&!n.errors.some(p=>p.code==="REQUIRED"||p.message.toLowerCase().includes("required"))){let p={isValid:!1,errors:[{message:"This field is required",code:"CONDITIONAL_REQUIRED"},...n.errors]};return o(s,p.errors),t(s,"invalid"),p}return o(s,n.errors),t(s,n.isValid?"valid":"invalid"),n}catch(n){let v={isValid:false,errors:[{message:n instanceof Error?n.message:"Validation failed",code:"VALIDATION_ERROR"}]};return o(s,v.errors),t(s,"invalid"),v}},[i,e.values,r,t,o]),m=useCallback(async()=>{let s=i.allFields.filter(n=>{let v=r.isFieldVisible(n.id),u=n.validation?.validators&&n.validation.validators.length>0;return v&&u}),F=i.allFields.filter(n=>!r.isFieldVisible(n.id));for(let n of F)o(n.id,[]),t(n.id,"valid");let f=await Promise.all(s.map(n=>d(n.id))),l=f.some(n=>!n.isValid),a=k();if(i.validation?.validators?.length){let n=Object.keys(e.values).reduce((u,c)=>(r.isFieldVisible(c)&&(u[c]=e.values[c]),u),{}),v=createValidationContext({formId:i.id,allFormData:n});try{a=await runValidatorsAsync(i.validation.validators,n,v);}catch(u){a={isValid:false,errors:[{message:u instanceof Error?u.message:"Form validation failed",code:"FORM_VALIDATION_ERROR"}]};}}return {isValid:!l&&a.isValid,errors:[...f.flatMap(n=>n.errors),...a.errors]}},[i,e.values,r,d,o,t]);return {validateField:d,validateForm:m}}var K=createContext(null);function M({children:i,formConfig:e,defaultValues:r={},onSubmit:t,onFieldChange:o,className:d}){let m=useRef(e.id),{formState:s,setValue:F,setFieldTouched:f,reset:l,setError:a,clearError:n,setFieldValidationState:v,setSubmitting:u,isFormValid:c}=G({defaultValues:r,onFieldChange:o}),{fieldConditions:p,hasConditionalFields:b,getFieldCondition:w,isFieldVisible:R,isFieldDisabled:E,isFieldRequired:V,isFieldReadonly:I}=$({formConfig:e,formValues:s.values}),x=useMemo(()=>({hasConditionalFields:b,getFieldCondition:w,isFieldVisible:R,isFieldDisabled:E,isFieldRequired:V,isFieldReadonly:I}),[b,w,R,E,V,I]),{validateField:S,validateForm:P}=H({formConfig:e,formState:s,conditionsHelpers:x,setFieldValidationState:v,setError:a}),{submit:y}=W({formState:s,onSubmit:t,validateForm:P,setSubmitting:u});useEffect(()=>{(m.current===null||e.id!==m.current)&&(m.current=e.id,l(r));},[e.id,l]);let T=useMemo(()=>e,[e]),q=useMemo(()=>({formState:s,formConfig:T,fieldConditions:p,conditionsHelpers:x,setValue:F,setFieldTouched:f,validateField:S,validateForm:P,isFormValid:c,reset:l,submit:y,setError:a,clearError:n}),[s,T,p,x,F,f,S,P,c,l,y,a,n]);return jsx(K.Provider,{value:q,children:jsx("form",{onSubmit:y,className:d,noValidate:true,children:i})})}function g(){let i=useContext(K);if(!i)throw new Error("useFormContext must be used within a FormProvider");return i}function he({formConfig:i,defaultValues:e,onSubmit:r,onFieldChange:t,children:o}){let d=useMemo(()=>i instanceof h?i.build():i,[i]);return jsx(M,{formConfig:d,defaultValues:e,onSubmit:r,onFieldChange:t,children:o})}function _({fieldId:i,disabled:e=false,customProps:r={},className:t,forceVisible:o=false}){let{formState:d,formConfig:m,setValue:s,setFieldTouched:F,validateField:f,conditionsHelpers:l}=g(),a=m.allFields.find(O=>O.id===i);if(!a)throw new Error(`Field with ID "${i}" not found`);let n=m.config.getComponent(a.componentId);if(!n)throw new Error(`Component with ID "${a.componentId}" not found`);let v=d.values[i],u=d.errors[i]||[],c=d.validationState[i]||"idle",p=d.touched[i]||false,b=c==="validating",w=o||l.isFieldVisible(i),R=e||l.isFieldDisabled(i),E=l.isFieldRequired(i),V=l.isFieldReadonly(i);if(!w)return null;let I=useCallback(async O=>{s(i,O),(a.validation?.validateOnChange||p)&&await f(i,O);},[i,s,f,a.validation?.validateOnChange,p]),x=useCallback(async()=>{p||F(i),a.validation?.validateOnBlur!==false&&await f(i);},[i,p,F,f,a.validation?.validateOnBlur]),S={...n.defaultProps??{},...a.props,...r,disabled:R,required:E,readOnly:V},P={id:i,props:S,value:v,onChange:I,onBlur:x,disabled:R,error:u,isValidating:b,touched:p},y=m.renderConfig?.fieldRenderer,T=n.renderer(P),q=n.useFieldRenderer!==false,oe=y&&q?y({children:T,id:i,...S,error:u,isValidating:b,touched:p}):T;return jsx("div",{className:t,"data-field-id":i,"data-field-type":n.type,"data-field-visible":w,"data-field-disabled":R,"data-field-required":E,"data-field-readonly":V,children:oe})}Re.memo(_);function Z({row:i,className:e,...r}){let{formConfig:t}=g(),o=i.fields.map(m=>jsx(_,{fieldId:m.id},m.id)),d={row:i,children:o,className:e};return jsx(ComponentRendererWrapper,{name:"FormRow",renderer:t.renderConfig?.rowRenderer,props:d,...r,children:o})}var ee=Z;function Ve({className:i,...e}){let{formConfig:r}=g(),t=useMemo(()=>r.rows.map(d=>jsx(ee,{row:d},d.id)),[r.rows]),o={formConfig:r,children:t,className:i};return jsx(ComponentRendererWrapper,{name:"FormBody",renderer:r.renderConfig?.bodyRenderer,props:o,...e,children:t})}function Se({className:i,...e}){let{formState:r,submit:t,formConfig:o}=g(),d={isSubmitting:r.isSubmitting,onSubmit:t,className:i};return jsx(ComponentRendererWrapper,{name:"FormSubmitButton",renderer:o.renderConfig?.submitButtonRenderer,props:d,...e})}export{he as Form,Ve as FormBody,h as FormBuilder,_ as FormField,M as FormProvider,Z as FormRow,Se as FormSubmitButton,ae as createForm,h as form,De as useConditionEvaluation,$ as useFormConditions,g as useFormContext,G as useFormState,W as useFormSubmission,H as useFormValidation,L as useMultipleConditionEvaluation};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rilaykit/forms",
3
- "version": "5.2.0",
3
+ "version": "6.0.0",
4
4
  "description": "Form building utilities and components for RilayKit",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -24,7 +24,7 @@
24
24
  "url": "https://github.com/andyoucreate/rilay/issues"
25
25
  },
26
26
  "dependencies": {
27
- "@rilaykit/core": "5.2.0"
27
+ "@rilaykit/core": "6.0.0"
28
28
  },
29
29
  "peerDependencies": {
30
30
  "react": ">=18.0.0",