@wix/headless-forms 0.0.11 → 0.0.13

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.
@@ -1,4 +1,5 @@
1
1
  import React from 'react';
2
+ import { type FormError } from '@wix/form-public';
2
3
  import { type CheckboxGroupProps, type CheckboxProps, type PhoneInputProps, type DateInputProps, type DatePickerProps, type DateTimeInputProps, type DropdownProps, type FileUploadProps, type MultilineAddressProps, type NumberInputProps, type RadioGroupProps, type RatingInputProps, type RichTextProps, type SignatureProps, type SubmitButtonProps, type TagsProps, type TextAreaProps, type TextInputProps, type TimeInputProps, type ProductListProps, type FixedPaymentProps, type PaymentInputProps, type DonationProps, type AppointmentProps, type ImageChoiceProps } from './types.js';
3
4
  import { type FormServiceConfig } from '../services/form-service.js';
4
5
  /**
@@ -621,7 +622,9 @@ export interface FieldProps {
621
622
  */
622
623
  interface FieldComponent extends React.ForwardRefExoticComponent<FieldProps & React.RefAttributes<HTMLDivElement>> {
623
624
  Label: typeof FieldLabel;
625
+ InputWrapper: typeof FieldInputWrapper;
624
626
  Input: typeof FieldInput;
627
+ Error: typeof FieldError;
625
628
  }
626
629
  /**
627
630
  * Props for Field.Label component
@@ -634,6 +637,14 @@ export interface FieldLabelProps {
634
637
  /** CSS classes to apply to the label element */
635
638
  className?: string;
636
639
  }
640
+ export interface FieldInputWrapperProps {
641
+ /** Child components (typically Field.Input and Field.Error) */
642
+ children: React.ReactNode;
643
+ /** Whether to render as a child component */
644
+ asChild?: boolean;
645
+ /** CSS classes to apply to the wrapper element */
646
+ className?: string;
647
+ }
637
648
  /**
638
649
  * Props for Field.Input component
639
650
  */
@@ -648,9 +659,74 @@ export interface FieldInputProps {
648
659
  description?: React.ReactNode;
649
660
  }
650
661
  /**
651
- * Label component for a form field with automatic grid positioning.
662
+ * Render props for Field.Error component
663
+ */
664
+ export interface FieldErrorRenderProps {
665
+ /** The error type */
666
+ type: FormError['errorType'];
667
+ /** The error message */
668
+ message: string;
669
+ }
670
+ /**
671
+ * Props for Field.Error component
672
+ */
673
+ export interface FieldErrorProps {
674
+ /** Whether to render as a child component */
675
+ asChild?: boolean;
676
+ /** CSS classes to apply to the error element */
677
+ className?: string;
678
+ /** The error message */
679
+ errorMessage?: string;
680
+ /** Child components to render */
681
+ children?: React.ReactNode;
682
+ }
683
+ /**
684
+ * Props for Field.Label.Required component
685
+ */
686
+ export interface FieldLabelRequiredProps {
687
+ /** Whether to show the required indicator */
688
+ required?: boolean;
689
+ /** Custom content to display (defaults to red asterisk) */
690
+ children?: React.ReactNode;
691
+ /** Whether to render as a child component */
692
+ asChild?: boolean;
693
+ /** CSS classes to apply to the required indicator */
694
+ className?: string;
695
+ }
696
+ /**
697
+ * Required indicator component for form field labels.
698
+ * Must be used within a Form.Field.Label component.
699
+ *
700
+ * @component
701
+ * @example
702
+ * ```tsx
703
+ * import { Form } from '@wix/headless-forms/react';
704
+ *
705
+ * // Basic usage with required prop
706
+ * <Form.Field.Label>
707
+ * <label className="text-foreground font-paragraph">
708
+ * Email Address
709
+ * <Form.Field.Label.Required />
710
+ * </label>
711
+ * </Form.Field.Label>
712
+ *
713
+ * // Custom styling
714
+ * <Form.Field.Label>
715
+ * <label className="text-foreground font-paragraph">
716
+ * Username
717
+ * <Form.Field.Label.Required required={true} className="text-destructive ml-2" />
718
+ * </label>
719
+ * </Form.Field.Label>
720
+ */
721
+ export declare const FieldLabelRequired: React.ForwardRefExoticComponent<FieldLabelRequiredProps & React.RefAttributes<HTMLSpanElement>>;
722
+ interface FieldLabelComponent extends React.ForwardRefExoticComponent<FieldLabelProps & React.RefAttributes<HTMLDivElement>> {
723
+ Required: typeof FieldLabelRequired;
724
+ }
725
+ export declare const FieldLabel: FieldLabelComponent;
726
+ /**
727
+ * InputWrapper component that wraps input and error elements with grid positioning.
652
728
  * Must be used within a Form.Field component.
653
- * Renders in the label row of the field's grid layout.
729
+ * This wrapper applies the grid positioning styles to contain both the input and error.
654
730
  *
655
731
  * @component
656
732
  * @example
@@ -661,17 +737,22 @@ export interface FieldInputProps {
661
737
  * <Form.Field.Label>
662
738
  * <label className="text-foreground font-paragraph">Email Address</label>
663
739
  * </Form.Field.Label>
664
- * <Form.Field.Input>
665
- * <input type="email" className="bg-background border-foreground" />
666
- * </Form.Field.Input>
740
+ * <Form.Field.InputWrapper>
741
+ * <Form.Field.Input>
742
+ * <input type="email" className="bg-background border-foreground text-foreground" />
743
+ * </Form.Field.Input>
744
+ * <Form.Field.Error>
745
+ * <span className="text-destructive text-sm font-paragraph">Please enter a valid email</span>
746
+ * </Form.Field.Error>
747
+ * </Form.Field.InputWrapper>
667
748
  * </Form.Field>
668
749
  * ```
669
750
  */
670
- export declare const FieldLabel: React.ForwardRefExoticComponent<FieldLabelProps & React.RefAttributes<HTMLDivElement>>;
751
+ export declare const FieldInputWrapper: React.ForwardRefExoticComponent<FieldInputWrapperProps & React.RefAttributes<HTMLDivElement>>;
671
752
  /**
672
- * Input component for a form field with automatic grid positioning.
673
- * Must be used within a Form.Field component.
674
- * Renders in the input row of the field's grid layout with optional description.
753
+ * Input component for a form field.
754
+ * Must be used within a Form.Field.InputWrapper component.
755
+ * Renders the actual input element without grid positioning.
675
756
  *
676
757
  * @component
677
758
  * @example
@@ -682,12 +763,40 @@ export declare const FieldLabel: React.ForwardRefExoticComponent<FieldLabelProps
682
763
  * <Form.Field.Label>
683
764
  * <label className="text-foreground font-paragraph">Password</label>
684
765
  * </Form.Field.Label>
685
- * <Form.Field.Input description={<span className="text-secondary-foreground">Min 8 characters</span>}>
686
- * <input type="password" className="bg-background border-foreground text-foreground" />
687
- * </Form.Field.Input>
766
+ * <Form.Field.InputWrapper>
767
+ * <Form.Field.Input description={<span className="text-secondary-foreground">Min 8 characters</span>}>
768
+ * <input type="password" className="bg-background border-foreground text-foreground" />
769
+ * </Form.Field.Input>
770
+ * </Form.Field.InputWrapper>
688
771
  * </Form.Field>
689
772
  * ```
690
773
  */
691
774
  export declare const FieldInput: React.ForwardRefExoticComponent<FieldInputProps & React.RefAttributes<HTMLDivElement>>;
775
+ /**
776
+ * Error component for displaying field-level validation errors.
777
+ * Must be used within a Form.Field.InputWrapper component.
778
+ * Only renders when there is an error for the current field.
779
+ *
780
+ * @component
781
+ * @example
782
+ * ```tsx
783
+ * import { Form } from '@wix/headless-forms/react';
784
+ *
785
+ * <Form.Field id="email">
786
+ * <Form.Field.Label>
787
+ * <label className="text-foreground font-paragraph">Email Address</label>
788
+ * </Form.Field.Label>
789
+ * <Form.Field.InputWrapper>
790
+ * <Form.Field.Input>
791
+ * <input type="email" className="bg-background border-foreground text-foreground" />
792
+ * </Form.Field.Input>
793
+ * <Form.Field.Error path="email">
794
+ * <span className="text-destructive text-sm font-paragraph">Please enter a valid email address</span>
795
+ * </Form.Field.Error>
796
+ * </Form.Field.InputWrapper>
797
+ * </Form.Field>
798
+ * ```
799
+ */
800
+ export declare const FieldError: React.ForwardRefExoticComponent<FieldErrorProps & React.RefAttributes<HTMLDivElement>>;
692
801
  export declare const Field: FieldComponent;
693
802
  export {};
@@ -33,12 +33,14 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.Field = exports.FieldInput = exports.FieldLabel = exports.Fields = exports.Submitted = exports.Error = exports.LoadingError = exports.Loading = exports.Root = void 0;
36
+ exports.Field = exports.FieldError = exports.FieldInput = exports.FieldInputWrapper = exports.FieldLabel = exports.FieldLabelRequired = exports.Fields = exports.Submitted = exports.Error = exports.LoadingError = exports.Loading = exports.Root = void 0;
37
37
  const jsx_runtime_1 = require("react/jsx-runtime");
38
38
  const react_1 = __importStar(require("react"));
39
39
  const react_2 = require("@wix/headless-utils/react");
40
40
  const form_public_1 = require("@wix/form-public");
41
41
  const Form_js_1 = require("./core/Form.js");
42
+ const FieldContext_js_1 = require("./context/FieldContext.js");
43
+ const FieldLayoutContext_js_1 = require("./context/FieldLayoutContext.js");
42
44
  var TestIds;
43
45
  (function (TestIds) {
44
46
  TestIds["formRoot"] = "form-root";
@@ -49,7 +51,9 @@ var TestIds;
49
51
  TestIds["formSubmitted"] = "form-submitted";
50
52
  TestIds["fieldRoot"] = "field-root";
51
53
  TestIds["fieldLabel"] = "field-label";
54
+ TestIds["fieldInputWrapper"] = "field-input-wrapper";
52
55
  TestIds["fieldInput"] = "field-input";
56
+ TestIds["fieldError"] = "field-error";
53
57
  })(TestIds || (TestIds = {}));
54
58
  /**
55
59
  * Root component that provides all necessary service contexts for a complete form experience.
@@ -530,28 +534,27 @@ exports.Fields = react_1.default.forwardRef((props, ref) => {
530
534
  return ((0, jsx_runtime_1.jsx)(Form_js_1.Fields, { children: ({ form, submitForm }) => {
531
535
  if (!form)
532
536
  return null;
533
- return ((0, jsx_runtime_1.jsx)("div", { ref: ref, children: (0, jsx_runtime_1.jsx)(form_public_1.FormProvider, { children: (0, jsx_runtime_1.jsx)(FieldsWithForm, { form: form, values: formValues, onChange: handleFormChange, errors: formErrors, onValidate: handleFormValidate, fields: props.fieldMap, submitForm: () => submitForm(formValues), rowGapClassname: props.rowGapClassname, columnGapClassname: props.columnGapClassname }) }) }));
537
+ return ((0, jsx_runtime_1.jsx)("div", { ref: ref, children: (0, jsx_runtime_1.jsx)(form_public_1.FormProvider, { currency: 'USD', locale: 'en', children: (0, jsx_runtime_1.jsx)(FieldsWithForm, { form: form, values: formValues, onChange: handleFormChange, errors: formErrors, onValidate: handleFormValidate, fields: props.fieldMap, submitForm: () => submitForm(formValues), rowGapClassname: props.rowGapClassname, columnGapClassname: props.columnGapClassname }) }) }));
534
538
  } }));
535
539
  });
536
540
  const FieldsWithForm = ({ form, submitForm, values, onChange, errors, onValidate, fields: fieldMap, rowGapClassname, columnGapClassname, }) => {
537
541
  const formData = (0, form_public_1.useForm)({
538
542
  form,
539
543
  values,
540
- onChange,
541
544
  errors,
545
+ onChange,
542
546
  onValidate,
543
547
  submitForm,
544
548
  fieldMap,
545
549
  });
546
550
  if (!formData)
547
551
  return null;
548
- console.log('formData', formData);
549
552
  const { columnCount, fieldElements, fieldsLayout } = formData;
550
553
  return (
551
554
  // TODO: use readOnly, isDisabled
552
555
  // TODO: step title a11y support
553
556
  // TODO: mobile support?
554
- (0, jsx_runtime_1.jsx)(FieldLayoutProvider, { value: fieldsLayout, children: (0, jsx_runtime_1.jsx)("form", { onSubmit: (e) => e.preventDefault(), children: (0, jsx_runtime_1.jsx)("fieldset", { style: { display: 'flex', flexDirection: 'column' }, className: rowGapClassname, children: fieldElements.map((rowElements, index) => {
557
+ (0, jsx_runtime_1.jsx)(FieldLayoutContext_js_1.FieldLayoutProvider, { value: fieldsLayout, children: (0, jsx_runtime_1.jsx)("form", { onSubmit: (e) => e.preventDefault(), children: (0, jsx_runtime_1.jsx)("fieldset", { style: { display: 'flex', flexDirection: 'column' }, className: rowGapClassname, children: fieldElements.map((rowElements, index) => {
555
558
  return ((0, jsx_runtime_1.jsx)("div", { style: {
556
559
  display: 'grid',
557
560
  width: '100%',
@@ -560,45 +563,9 @@ const FieldsWithForm = ({ form, submitForm, values, onChange, errors, onValidate
560
563
  }, className: columnGapClassname, children: rowElements }, index));
561
564
  }) }) }) }));
562
565
  };
563
- /**
564
- * Context for sharing field layout data across the form
565
- * @internal
566
- */
567
- const FieldLayoutContext = react_1.default.createContext(null);
568
- /**
569
- * Provider component that makes field layout data available to child components
570
- * @internal
571
- */
572
- const FieldLayoutProvider = ({ value, children, }) => {
573
- return ((0, jsx_runtime_1.jsx)(FieldLayoutContext.Provider, { value: value, children: children }));
574
- };
575
- /**
576
- * Hook to access layout configuration for a specific field
577
- * @internal
578
- * @param {string} fieldId - The unique identifier of the field
579
- * @returns {Layout | null} The layout configuration for the field, or null if not found
580
- */
581
- function useFieldLayout(fieldId) {
582
- const layoutMap = react_1.default.useContext(FieldLayoutContext);
583
- if (!layoutMap) {
584
- return null;
585
- }
586
- return layoutMap[fieldId] || null;
587
- }
588
- const FieldContext = react_1.default.createContext(null);
589
- /**
590
- * Hook to access field context
591
- */
592
- function useFieldContext() {
593
- const context = react_1.default.useContext(FieldContext);
594
- if (!context) {
595
- throw new globalThis.Error('Field components must be used within a Form.Field component');
596
- }
597
- return context;
598
- }
599
566
  /**
600
567
  * Container component for a form field with grid layout support.
601
- * Provides context to Field.Label and Field.Input child components.
568
+ * Provides context to Field.Label, Field.InputWrapper, Field.Input, and Field.Error child components.
602
569
  * Based on the default-field-layout functionality.
603
570
  *
604
571
  * @component
@@ -612,9 +579,14 @@ function useFieldContext() {
612
579
  * <Form.Field.Label>
613
580
  * <label className="text-foreground font-paragraph">Username</label>
614
581
  * </Form.Field.Label>
615
- * <Form.Field.Input description={<span className="text-secondary-foreground">Required</span>}>
616
- * <input className="bg-background border-foreground text-foreground" />
617
- * </Form.Field.Input>
582
+ * <Form.Field.InputWrapper>
583
+ * <Form.Field.Input description={<span className="text-secondary-foreground">Required</span>}>
584
+ * <input className="bg-background border-foreground text-foreground" />
585
+ * </Form.Field.Input>
586
+ * <Form.Field.Error>
587
+ * <span className="text-destructive text-sm font-paragraph">Username is required</span>
588
+ * </Form.Field.Error>
589
+ * </Form.Field.InputWrapper>
618
590
  * </Form.Field>
619
591
  * );
620
592
  * }
@@ -622,7 +594,7 @@ function useFieldContext() {
622
594
  */
623
595
  const FieldRoot = react_1.default.forwardRef((props, ref) => {
624
596
  const { id, children, asChild, className, ...otherProps } = props;
625
- const layout = useFieldLayout(id);
597
+ const layout = (0, FieldLayoutContext_js_1.useFieldLayout)(id);
626
598
  if (!layout) {
627
599
  return null;
628
600
  }
@@ -632,7 +604,7 @@ const FieldRoot = react_1.default.forwardRef((props, ref) => {
632
604
  layout: fieldData.layout,
633
605
  gridStyles: fieldData.gridStyles,
634
606
  };
635
- return ((0, jsx_runtime_1.jsx)(FieldContext.Provider, { value: contextValue, children: (0, jsx_runtime_1.jsx)(react_2.AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.fieldRoot, customElement: children, customElementProps: {}, ...otherProps, children: children }) }));
607
+ return ((0, jsx_runtime_1.jsx)(FieldContext_js_1.FieldContext.Provider, { value: contextValue, children: (0, jsx_runtime_1.jsx)(react_2.AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.fieldRoot, customElement: children, customElementProps: {}, ...otherProps, children: children }) }));
636
608
  } }));
637
609
  });
638
610
  FieldRoot.displayName = 'Form.Field';
@@ -648,24 +620,100 @@ FieldRoot.displayName = 'Form.Field';
648
620
  *
649
621
  * <Form.Field id="email">
650
622
  * <Form.Field.Label>
651
- * <label className="text-foreground font-paragraph">Email Address</label>
623
+ * <label className="text-foreground font-paragraph">
624
+ * Email Address
625
+ * <Form.Field.Label.Required required={true} />
626
+ * </label>
652
627
  * </Form.Field.Label>
653
- * <Form.Field.Input>
654
- * <input type="email" className="bg-background border-foreground" />
655
- * </Form.Field.Input>
628
+ * <Form.Field.InputWrapper>
629
+ * <Form.Field.Input>
630
+ * <input type="email" className="bg-background border-foreground text-foreground" />
631
+ * </Form.Field.Input>
632
+ * </Form.Field.InputWrapper>
656
633
  * </Form.Field>
657
634
  * ```
658
635
  */
659
- exports.FieldLabel = react_1.default.forwardRef((props, ref) => {
636
+ const FieldLabelRoot = react_1.default.forwardRef((props, ref) => {
660
637
  const { children, asChild, className, ...otherProps } = props;
661
- const { gridStyles } = useFieldContext();
638
+ const { gridStyles } = (0, FieldContext_js_1.useFieldContext)();
662
639
  return ((0, jsx_runtime_1.jsx)(react_2.AsChildSlot, { ref: ref, asChild: asChild, className: className, style: gridStyles.label, "data-testid": TestIds.fieldLabel, customElement: children, customElementProps: {}, ...otherProps, children: (0, jsx_runtime_1.jsx)("div", { children: children }) }));
663
640
  });
664
- exports.FieldLabel.displayName = 'Form.Field.Label';
641
+ FieldLabelRoot.displayName = 'Form.Field.Label';
665
642
  /**
666
- * Input component for a form field with automatic grid positioning.
643
+ * Required indicator component for form field labels.
644
+ * Must be used within a Form.Field.Label component.
645
+ *
646
+ * @component
647
+ * @example
648
+ * ```tsx
649
+ * import { Form } from '@wix/headless-forms/react';
650
+ *
651
+ * // Basic usage with required prop
652
+ * <Form.Field.Label>
653
+ * <label className="text-foreground font-paragraph">
654
+ * Email Address
655
+ * <Form.Field.Label.Required />
656
+ * </label>
657
+ * </Form.Field.Label>
658
+ *
659
+ * // Custom styling
660
+ * <Form.Field.Label>
661
+ * <label className="text-foreground font-paragraph">
662
+ * Username
663
+ * <Form.Field.Label.Required required={true} className="text-destructive ml-2" />
664
+ * </label>
665
+ * </Form.Field.Label>
666
+ */
667
+ exports.FieldLabelRequired = react_1.default.forwardRef((props, ref) => {
668
+ const { required = false, children, asChild, className, ...otherProps } = props;
669
+ const requiredIndicator = 'asterisk';
670
+ // @ts-expect-error
671
+ if (!required || requiredIndicator === 'none')
672
+ return null;
673
+ return ((0, jsx_runtime_1.jsx)(react_2.AsChildSlot, { ref: ref, asChild: asChild, className: className, customElement: children, ...otherProps, children: (0, jsx_runtime_1.jsx)("span", { children: requiredIndicator === 'asterisk'
674
+ ? '*'
675
+ : requiredIndicator === 'text'
676
+ ? '(Required)'
677
+ : null }) }));
678
+ });
679
+ exports.FieldLabelRequired.displayName = 'Form.Field.Label.Required';
680
+ exports.FieldLabel = FieldLabelRoot;
681
+ exports.FieldLabel.Required = exports.FieldLabelRequired;
682
+ /**
683
+ * InputWrapper component that wraps input and error elements with grid positioning.
667
684
  * Must be used within a Form.Field component.
668
- * Renders in the input row of the field's grid layout with optional description.
685
+ * This wrapper applies the grid positioning styles to contain both the input and error.
686
+ *
687
+ * @component
688
+ * @example
689
+ * ```tsx
690
+ * import { Form } from '@wix/headless-forms/react';
691
+ *
692
+ * <Form.Field id="email">
693
+ * <Form.Field.Label>
694
+ * <label className="text-foreground font-paragraph">Email Address</label>
695
+ * </Form.Field.Label>
696
+ * <Form.Field.InputWrapper>
697
+ * <Form.Field.Input>
698
+ * <input type="email" className="bg-background border-foreground text-foreground" />
699
+ * </Form.Field.Input>
700
+ * <Form.Field.Error>
701
+ * <span className="text-destructive text-sm font-paragraph">Please enter a valid email</span>
702
+ * </Form.Field.Error>
703
+ * </Form.Field.InputWrapper>
704
+ * </Form.Field>
705
+ * ```
706
+ */
707
+ exports.FieldInputWrapper = react_1.default.forwardRef((props, ref) => {
708
+ const { children, asChild, className, ...otherProps } = props;
709
+ const { gridStyles } = (0, FieldContext_js_1.useFieldContext)();
710
+ return ((0, jsx_runtime_1.jsx)(react_2.AsChildSlot, { ref: ref, asChild: asChild, className: className, style: gridStyles.input, "data-testid": TestIds.fieldInputWrapper, customElement: children, customElementProps: {}, ...otherProps, children: (0, jsx_runtime_1.jsx)("div", { children: children }) }));
711
+ });
712
+ exports.FieldInputWrapper.displayName = 'Form.Field.InputWrapper';
713
+ /**
714
+ * Input component for a form field.
715
+ * Must be used within a Form.Field.InputWrapper component.
716
+ * Renders the actual input element without grid positioning.
669
717
  *
670
718
  * @component
671
719
  * @example
@@ -676,18 +724,53 @@ exports.FieldLabel.displayName = 'Form.Field.Label';
676
724
  * <Form.Field.Label>
677
725
  * <label className="text-foreground font-paragraph">Password</label>
678
726
  * </Form.Field.Label>
679
- * <Form.Field.Input description={<span className="text-secondary-foreground">Min 8 characters</span>}>
680
- * <input type="password" className="bg-background border-foreground text-foreground" />
681
- * </Form.Field.Input>
727
+ * <Form.Field.InputWrapper>
728
+ * <Form.Field.Input description={<span className="text-secondary-foreground">Min 8 characters</span>}>
729
+ * <input type="password" className="bg-background border-foreground text-foreground" />
730
+ * </Form.Field.Input>
731
+ * </Form.Field.InputWrapper>
682
732
  * </Form.Field>
683
733
  * ```
684
734
  */
685
735
  exports.FieldInput = react_1.default.forwardRef((props, ref) => {
686
736
  const { children, description, asChild, className, ...otherProps } = props;
687
- const { gridStyles } = useFieldContext();
688
- return ((0, jsx_runtime_1.jsx)(react_2.AsChildSlot, { ref: ref, asChild: asChild, className: className, style: gridStyles.input, "data-testid": TestIds.fieldInput, customElement: children, customElementProps: {}, ...otherProps, children: (0, jsx_runtime_1.jsx)("div", { children: children }) }));
737
+ return ((0, jsx_runtime_1.jsx)(react_2.AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.fieldInput, customElement: children, customElementProps: {}, ...otherProps, children: (0, jsx_runtime_1.jsx)("div", { children: children }) }));
689
738
  });
690
739
  exports.FieldInput.displayName = 'Form.Field.Input';
740
+ /**
741
+ * Error component for displaying field-level validation errors.
742
+ * Must be used within a Form.Field.InputWrapper component.
743
+ * Only renders when there is an error for the current field.
744
+ *
745
+ * @component
746
+ * @example
747
+ * ```tsx
748
+ * import { Form } from '@wix/headless-forms/react';
749
+ *
750
+ * <Form.Field id="email">
751
+ * <Form.Field.Label>
752
+ * <label className="text-foreground font-paragraph">Email Address</label>
753
+ * </Form.Field.Label>
754
+ * <Form.Field.InputWrapper>
755
+ * <Form.Field.Input>
756
+ * <input type="email" className="bg-background border-foreground text-foreground" />
757
+ * </Form.Field.Input>
758
+ * <Form.Field.Error path="email">
759
+ * <span className="text-destructive text-sm font-paragraph">Please enter a valid email address</span>
760
+ * </Form.Field.Error>
761
+ * </Form.Field.InputWrapper>
762
+ * </Form.Field>
763
+ * ```
764
+ */
765
+ exports.FieldError = react_1.default.forwardRef((props, ref) => {
766
+ const { errorMessage, asChild, className, children, ...otherProps } = props;
767
+ if (!errorMessage && !children)
768
+ return null;
769
+ return ((0, jsx_runtime_1.jsx)(react_2.AsChildSlot, { "data-testid": TestIds.fieldError, ref: ref, asChild: asChild, className: className, ...otherProps, children: children || errorMessage }));
770
+ });
771
+ exports.FieldError.displayName = 'Form.Field.Error';
691
772
  exports.Field = FieldRoot;
692
773
  exports.Field.Label = exports.FieldLabel;
774
+ exports.Field.InputWrapper = exports.FieldInputWrapper;
693
775
  exports.Field.Input = exports.FieldInput;
776
+ exports.Field.Error = exports.FieldError;
@@ -0,0 +1,47 @@
1
+ import React from 'react';
2
+ export interface PhoneFieldProps {
3
+ id: string;
4
+ children: React.ReactNode;
5
+ asChild?: boolean;
6
+ className?: string;
7
+ }
8
+ export interface PhoneLabelProps {
9
+ children: React.ReactNode;
10
+ asChild?: boolean;
11
+ className?: string;
12
+ }
13
+ export interface PhoneLabelRequiredProps {
14
+ required?: boolean;
15
+ children?: React.ReactNode;
16
+ asChild?: boolean;
17
+ className?: string;
18
+ }
19
+ export declare const Required: React.ForwardRefExoticComponent<PhoneLabelRequiredProps & React.RefAttributes<HTMLSpanElement>>;
20
+ interface PhoneLabelComponent extends React.ForwardRefExoticComponent<PhoneLabelProps & React.RefAttributes<HTMLDivElement>> {
21
+ Required: typeof Required;
22
+ }
23
+ export declare const Label: PhoneLabelComponent;
24
+ export interface PhoneErrorProps {
25
+ children?: React.ReactNode;
26
+ asChild?: boolean;
27
+ className?: string;
28
+ }
29
+ declare const Error: React.ForwardRefExoticComponent<PhoneErrorProps & React.RefAttributes<HTMLDivElement>>;
30
+ export interface CountryCodeProps {
31
+ asChild?: boolean;
32
+ className?: string;
33
+ }
34
+ declare const CountryCode: React.ForwardRefExoticComponent<CountryCodeProps & React.RefAttributes<HTMLDivElement>>;
35
+ export interface PhoneFieldInputProps {
36
+ asChild?: boolean;
37
+ className?: string;
38
+ }
39
+ declare const Input: React.ForwardRefExoticComponent<PhoneFieldInputProps & React.RefAttributes<HTMLDivElement>>;
40
+ interface PhoneFieldComponent extends React.ForwardRefExoticComponent<PhoneFieldProps & React.RefAttributes<HTMLDivElement>> {
41
+ Label: typeof Label;
42
+ Error: typeof Error;
43
+ Input: typeof Input;
44
+ CountryCode: typeof CountryCode;
45
+ }
46
+ export declare const PhoneField: PhoneFieldComponent;
47
+ export {};
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.PhoneField = exports.Label = exports.Required = void 0;
7
+ const jsx_runtime_1 = require("react/jsx-runtime");
8
+ const react_1 = __importDefault(require("react"));
9
+ const react_2 = require("@wix/headless-forms/react");
10
+ const form_public_1 = require("@wix/form-public");
11
+ const Root = react_1.default.forwardRef((props, ref) => {
12
+ const { id, children, asChild, className } = props;
13
+ const { description } = (0, form_public_1.useFieldProps)();
14
+ return ((0, jsx_runtime_1.jsx)(react_2.Form.Field, { ref: ref, id: id, asChild: asChild, className: className, children: (0, jsx_runtime_1.jsx)(react_2.Form.Field.InputWrapper, { children: (0, jsx_runtime_1.jsx)(react_2.Form.Field.Input, { description: description, children: children }) }) }));
15
+ });
16
+ Root.displayName = 'PhoneField';
17
+ const LabelRoot = react_1.default.forwardRef((props, ref) => {
18
+ const { asChild, className, children } = props;
19
+ const { id, label, showLabel } = (0, form_public_1.useFieldProps)();
20
+ if (!showLabel) {
21
+ return null;
22
+ }
23
+ return ((0, jsx_runtime_1.jsx)(react_2.Form.Field.Label, { ref: ref, asChild: asChild, className: className, children: (0, jsx_runtime_1.jsxs)("label", { htmlFor: id, children: [label, children] }) }));
24
+ });
25
+ LabelRoot.displayName = 'PhoneField.Label';
26
+ exports.Required = react_1.default.forwardRef((props, ref) => {
27
+ const { required } = (0, form_public_1.useFieldProps)();
28
+ return (0, jsx_runtime_1.jsx)(react_2.Form.Field.Label.Required, { ...props, ref: ref, required: required });
29
+ });
30
+ exports.Required.displayName = 'PhoneField.Label.Required';
31
+ exports.Label = LabelRoot;
32
+ exports.Label.Required = exports.Required;
33
+ const Error = react_1.default.forwardRef((props, ref) => {
34
+ const { children, ...rest } = props;
35
+ const { errorMessage } = (0, form_public_1.useFieldProps)();
36
+ return ((0, jsx_runtime_1.jsx)(react_2.Form.Field.Error, { ref: ref, ...rest, children: errorMessage }));
37
+ });
38
+ Error.displayName = 'PhoneField.Error';
39
+ const CountryCode = react_1.default.forwardRef((props, ref) => {
40
+ const { asChild, className, ...rest } = props;
41
+ const { id, countryCodes, defaultCountryCode, readOnly, onChange, onBlur, onFocus, } = (0, form_public_1.useFieldProps)();
42
+ return ((0, jsx_runtime_1.jsx)(react_2.Form.Field.Input, { ref: ref, asChild: asChild, className: className, ...rest, children: (0, jsx_runtime_1.jsx)("select", { id: `${id}-country`, defaultValue: defaultCountryCode || '', disabled: readOnly, onChange: (e) => onChange?.(e.target.value), onBlur: () => onBlur?.(), onFocus: () => onFocus?.(), children: countryCodes?.map((code) => ((0, jsx_runtime_1.jsx)("option", { value: code, children: code }, code))) }) }));
43
+ });
44
+ CountryCode.displayName = 'PhoneField.CountryCode';
45
+ const Input = react_1.default.forwardRef((props, ref) => {
46
+ const { asChild, className, ...rest } = props;
47
+ const { id, value, required, readOnly, placeholder, onChange, onBlur, onFocus, description, } = (0, form_public_1.useFieldProps)();
48
+ const descriptionId = description ? `${id}-description` : undefined;
49
+ return ((0, jsx_runtime_1.jsx)(react_2.Form.Field.Input, { ref: ref, asChild: asChild, className: className, ...rest, children: (0, jsx_runtime_1.jsx)("input", { id: id, type: "tel", value: value || '', required: required, readOnly: readOnly, placeholder: placeholder, "aria-describedby": descriptionId, "aria-invalid": !!(required && !value), "aria-required": required, onChange: (e) => onChange?.(e.target.value), onBlur: () => onBlur?.(), onFocus: () => onFocus?.() }) }));
50
+ });
51
+ Input.displayName = 'PhoneField.Input';
52
+ exports.PhoneField = Root;
53
+ exports.PhoneField.Label = exports.Label;
54
+ exports.PhoneField.Error = Error;
55
+ exports.PhoneField.Input = Input;
56
+ exports.PhoneField.CountryCode = CountryCode;
@@ -0,0 +1,12 @@
1
+ import React from 'react';
2
+ import { type Layout } from '../core/Form.js';
3
+ export interface FieldContextValue {
4
+ id: string;
5
+ layout: Layout;
6
+ gridStyles: {
7
+ label: React.CSSProperties;
8
+ input: React.CSSProperties;
9
+ };
10
+ }
11
+ export declare const FieldContext: React.Context<FieldContextValue | null>;
12
+ export declare function useFieldContext(): FieldContextValue;
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.FieldContext = void 0;
7
+ exports.useFieldContext = useFieldContext;
8
+ const react_1 = __importDefault(require("react"));
9
+ exports.FieldContext = react_1.default.createContext(null);
10
+ function useFieldContext() {
11
+ const context = react_1.default.useContext(exports.FieldContext);
12
+ if (!context) {
13
+ throw new Error('Field components must be used within a Form.Field component');
14
+ }
15
+ return context;
16
+ }
@@ -0,0 +1,12 @@
1
+ import React from 'react';
2
+ import { type Layout } from '../core/Form.js';
3
+ export interface FieldLayoutMap {
4
+ [fieldId: string]: Layout;
5
+ }
6
+ export declare const FieldLayoutContext: React.Context<FieldLayoutMap | null>;
7
+ export interface FieldLayoutProviderProps {
8
+ value: FieldLayoutMap;
9
+ children: React.ReactNode;
10
+ }
11
+ export declare const FieldLayoutProvider: React.FC<FieldLayoutProviderProps>;
12
+ export declare function useFieldLayout(fieldId: string): Layout | null;
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.FieldLayoutProvider = exports.FieldLayoutContext = void 0;
7
+ exports.useFieldLayout = useFieldLayout;
8
+ const jsx_runtime_1 = require("react/jsx-runtime");
9
+ const react_1 = __importDefault(require("react"));
10
+ exports.FieldLayoutContext = react_1.default.createContext(null);
11
+ const FieldLayoutProvider = ({ value, children, }) => {
12
+ return ((0, jsx_runtime_1.jsx)(exports.FieldLayoutContext.Provider, { value: value, children: children }));
13
+ };
14
+ exports.FieldLayoutProvider = FieldLayoutProvider;
15
+ function useFieldLayout(fieldId) {
16
+ const layoutMap = react_1.default.useContext(exports.FieldLayoutContext);
17
+ if (!layoutMap) {
18
+ return null;
19
+ }
20
+ return layoutMap[fieldId] || null;
21
+ }