@wix/headless-forms 0.0.10 → 0.0.12

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
  /**
@@ -303,6 +304,9 @@ export declare const Submitted: React.ForwardRefExoticComponent<SubmittedProps &
303
304
  /**
304
305
  * Mapping of form field types to their corresponding React components.
305
306
  *
307
+ * ALL field components in this map MUST use Form.Field for proper
308
+ * grid layout positioning.
309
+ *
306
310
  * Each key represents a field type identifier that matches the field types defined
307
311
  * in the form configuration, and each value is a React component that will receive
308
312
  * the field's props and render the appropriate UI element.
@@ -401,6 +405,8 @@ export interface FieldMap {
401
405
  *
402
406
  * @interface FieldsProps
403
407
  * @property {FieldMap} fieldMap - A mapping of field types to their corresponding React components
408
+ * @property {string} rowGapClassname - CSS class name for gap between rows
409
+ * @property {string} columnGapClassname - CSS class name for gap between columns
404
410
  * @example
405
411
  * ```tsx
406
412
  * const FIELD_MAP = {
@@ -414,11 +420,13 @@ export interface FieldMap {
414
420
  * // ... remaining field components
415
421
  * };
416
422
  *
417
- * <Form.Fields fieldMap={FIELD_MAP} />
423
+ * <Form.Fields fieldMap={FIELD_MAP} rowGapClassname="gap-y-4" columnGapClassname="gap-x-2" />
418
424
  * ```
419
425
  */
420
426
  interface FieldsProps {
421
427
  fieldMap: FieldMap;
428
+ rowGapClassname: string;
429
+ columnGapClassname: string;
422
430
  }
423
431
  /**
424
432
  * Fields component for rendering a form with custom field renderers.
@@ -428,6 +436,8 @@ interface FieldsProps {
428
436
  * @component
429
437
  * @param {FieldsProps} props - Component props
430
438
  * @param {FieldMap} props.fieldMap - A mapping of field types to their corresponding React components
439
+ * @param {string} props.rowGapClassname - CSS class name for gap between rows
440
+ * @param {string} props.columnGapClassname - CSS class name for gap between columns
431
441
  * @example
432
442
  * ```tsx
433
443
  * import { Form } from '@wix/headless-forms/react';
@@ -446,7 +456,11 @@ interface FieldsProps {
446
456
  * <Form.Root formServiceConfig={formServiceConfig}>
447
457
  * <Form.Loading className="flex justify-center p-4" />
448
458
  * <Form.LoadingError className="text-destructive px-4 py-3 rounded mb-4" />
449
- * <Form.Fields fieldMap={FIELD_MAP} />
459
+ * <Form.Fields
460
+ * fieldMap={FIELD_MAP}
461
+ * rowGapClassname="gap-y-4"
462
+ * columnGapClassname="gap-x-2"
463
+ * />
450
464
  * </Form.Root>
451
465
  * );
452
466
  * }
@@ -461,12 +475,15 @@ interface FieldsProps {
461
475
  * - Field validation and error display
462
476
  * - Form state management
463
477
  * - Field value updates
478
+ * - Grid layout with configurable row and column gaps
464
479
  *
465
480
  * Must be used within Form.Root to access form context.
466
481
  *
467
482
  * @component
468
483
  * @param {FieldsProps} props - The component props
469
484
  * @param {FieldMap} props.fieldMap - A mapping of field types to their corresponding React components. Each key represents a field type (e.g., 'TEXT_INPUT', 'CHECKBOX') and the value is the React component that should render that field type.
485
+ * @param {string} props.rowGapClassname - CSS class name for gap between form rows
486
+ * @param {string} props.columnGapClassname - CSS class name for gap between form columns
470
487
  *
471
488
  * @example
472
489
  * ```tsx
@@ -534,7 +551,11 @@ interface FieldsProps {
534
551
  * <Form.Root formServiceConfig={formServiceConfig}>
535
552
  * <Form.Loading className="flex justify-center p-4" />
536
553
  * <Form.LoadingError className="text-destructive px-4 py-3 rounded mb-4" />
537
- * <Form.Fields fieldMap={FIELD_MAP} />
554
+ * <Form.Fields
555
+ * fieldMap={FIELD_MAP}
556
+ * rowGapClassname="gap-y-4"
557
+ * columnGapClassname="gap-x-2"
558
+ * />
538
559
  * <Form.Error className="text-destructive p-4 rounded-lg mb-4" />
539
560
  * <Form.Submitted className="text-green-500 p-4 rounded-lg mb-4" />
540
561
  * </Form.Root>
@@ -544,25 +565,221 @@ interface FieldsProps {
544
565
  *
545
566
  * @example
546
567
  * ```tsx
547
- * // Advanced usage with custom field components
548
- * const CustomTextField = ({ value, onChange, label, error, ...props }) => (
549
- * <div className="form-field">
550
- * <label className="text-foreground font-paragraph">{label}</label>
551
- * <input
552
- * value={value || ''}
553
- * onChange={(e) => onChange(e.target.value)}
554
- * className="bg-background border-foreground text-foreground"
555
- * {...props}
556
- * />
557
- * {error && <span className="text-destructive">{error}</span>}
558
- * </div>
559
- * );
568
+ * // Creating custom field components - ALL field components MUST use Form.Field
569
+ * // This example shows the REQUIRED structure for a TEXT_INPUT component
570
+ * import { Form, type TextInputProps } from '@wix/headless-forms/react';
571
+ *
572
+ * const TextInput = (props: TextInputProps) => {
573
+ * const { id, value, onChange, label, error, required, ...inputProps } = props;
574
+ *
575
+ * // Form.Field provides automatic grid layout positioning
576
+ * return (
577
+ * <Form.Field id={id}>
578
+ * <Form.Field.Label>
579
+ * <label className="text-foreground font-paragraph">
580
+ * {label}
581
+ * {required && <span className="text-destructive ml-1">*</span>}
582
+ * </label>
583
+ * </Form.Field.Label>
584
+ * <Form.Field.Input
585
+ * description={error && <span className="text-destructive text-sm">{error}</span>}
586
+ * >
587
+ * <input
588
+ * type="text"
589
+ * value={value || ''}
590
+ * onChange={(e) => onChange(e.target.value)}
591
+ * className="bg-background border-foreground text-foreground"
592
+ * aria-invalid={!!error}
593
+ * {...inputProps}
594
+ * />
595
+ * </Form.Field.Input>
596
+ * </Form.Field>
597
+ * );
598
+ * };
560
599
  *
561
600
  * const FIELD_MAP = {
562
- * TEXT_INPUT: CustomTextField,
563
- * // ... other field components
601
+ * TEXT_INPUT: TextInput,
602
+ * // ... all other field components must also use Form.Field
564
603
  * };
565
604
  * ```
566
605
  */
567
606
  export declare const Fields: React.ForwardRefExoticComponent<FieldsProps & React.RefAttributes<HTMLDivElement>>;
607
+ /**
608
+ * Props for Field container component
609
+ */
610
+ export interface FieldProps {
611
+ /** The unique identifier for this field */
612
+ id: string;
613
+ /** Child components (Field.Label, Field.Input, etc.) */
614
+ children: React.ReactNode;
615
+ /** Whether to render as a child component */
616
+ asChild?: boolean;
617
+ /** CSS classes to apply to the root element */
618
+ className?: string;
619
+ }
620
+ /**
621
+ * Field component with sub-components
622
+ */
623
+ interface FieldComponent extends React.ForwardRefExoticComponent<FieldProps & React.RefAttributes<HTMLDivElement>> {
624
+ Label: typeof FieldLabel;
625
+ InputWrapper: typeof FieldInputWrapper;
626
+ Input: typeof FieldInput;
627
+ Error: typeof FieldError;
628
+ }
629
+ /**
630
+ * Props for Field.Label component
631
+ */
632
+ export interface FieldLabelProps {
633
+ /** Label content to display */
634
+ children: React.ReactNode;
635
+ /** Whether to render as a child component */
636
+ asChild?: boolean;
637
+ /** CSS classes to apply to the label element */
638
+ className?: string;
639
+ }
640
+ /**
641
+ * Props for Field.InputWrapper component
642
+ */
643
+ export interface FieldInputWrapperProps {
644
+ /** Child components (typically Field.Input and Field.Error) */
645
+ children: React.ReactNode;
646
+ /** Whether to render as a child component */
647
+ asChild?: boolean;
648
+ /** CSS classes to apply to the wrapper element */
649
+ className?: string;
650
+ }
651
+ /**
652
+ * Props for Field.Input component
653
+ */
654
+ export interface FieldInputProps {
655
+ /** Input element to render */
656
+ children: React.ReactNode;
657
+ /** Whether to render as a child component */
658
+ asChild?: boolean;
659
+ /** CSS classes to apply to the input element */
660
+ className?: string;
661
+ /** Description text to display below the input */
662
+ description?: React.ReactNode;
663
+ }
664
+ /**
665
+ * Render props for Field.Error component
666
+ */
667
+ export interface FieldErrorRenderProps {
668
+ /** The error type */
669
+ type: FormError['errorType'];
670
+ /** The error message */
671
+ message: string;
672
+ }
673
+ /**
674
+ * Props for Field.Error component
675
+ */
676
+ export interface FieldErrorProps {
677
+ /** Whether to render as a child component */
678
+ asChild?: boolean;
679
+ /** CSS classes to apply to the error element */
680
+ className?: string;
681
+ /** The error message */
682
+ errorMessage?: string;
683
+ /** Child components to render */
684
+ children?: React.ReactNode;
685
+ }
686
+ /**
687
+ * Label component for a form field with automatic grid positioning.
688
+ * Must be used within a Form.Field component.
689
+ * Renders in the label row of the field's grid layout.
690
+ *
691
+ * @component
692
+ * @example
693
+ * ```tsx
694
+ * import { Form } from '@wix/headless-forms/react';
695
+ *
696
+ * <Form.Field id="email">
697
+ * <Form.Field.Label>
698
+ * <label className="text-foreground font-paragraph">Email Address</label>
699
+ * </Form.Field.Label>
700
+ * <Form.Field.InputWrapper>
701
+ * <Form.Field.Input>
702
+ * <input type="email" className="bg-background border-foreground text-foreground" />
703
+ * </Form.Field.Input>
704
+ * </Form.Field.InputWrapper>
705
+ * </Form.Field>
706
+ * ```
707
+ */
708
+ export declare const FieldLabel: React.ForwardRefExoticComponent<FieldLabelProps & React.RefAttributes<HTMLDivElement>>;
709
+ /**
710
+ * InputWrapper component that wraps input and error elements with grid positioning.
711
+ * Must be used within a Form.Field component.
712
+ * This wrapper applies the grid positioning styles to contain both the input and error.
713
+ *
714
+ * @component
715
+ * @example
716
+ * ```tsx
717
+ * import { Form } from '@wix/headless-forms/react';
718
+ *
719
+ * <Form.Field id="email">
720
+ * <Form.Field.Label>
721
+ * <label className="text-foreground font-paragraph">Email Address</label>
722
+ * </Form.Field.Label>
723
+ * <Form.Field.InputWrapper>
724
+ * <Form.Field.Input>
725
+ * <input type="email" className="bg-background border-foreground text-foreground" />
726
+ * </Form.Field.Input>
727
+ * <Form.Field.Error>
728
+ * <span className="text-destructive text-sm font-paragraph">Please enter a valid email</span>
729
+ * </Form.Field.Error>
730
+ * </Form.Field.InputWrapper>
731
+ * </Form.Field>
732
+ * ```
733
+ */
734
+ export declare const FieldInputWrapper: React.ForwardRefExoticComponent<FieldInputWrapperProps & React.RefAttributes<HTMLDivElement>>;
735
+ /**
736
+ * Input component for a form field.
737
+ * Must be used within a Form.Field.InputWrapper component.
738
+ * Renders the actual input element without grid positioning.
739
+ *
740
+ * @component
741
+ * @example
742
+ * ```tsx
743
+ * import { Form } from '@wix/headless-forms/react';
744
+ *
745
+ * <Form.Field id="password">
746
+ * <Form.Field.Label>
747
+ * <label className="text-foreground font-paragraph">Password</label>
748
+ * </Form.Field.Label>
749
+ * <Form.Field.InputWrapper>
750
+ * <Form.Field.Input description={<span className="text-secondary-foreground">Min 8 characters</span>}>
751
+ * <input type="password" className="bg-background border-foreground text-foreground" />
752
+ * </Form.Field.Input>
753
+ * </Form.Field.InputWrapper>
754
+ * </Form.Field>
755
+ * ```
756
+ */
757
+ export declare const FieldInput: React.ForwardRefExoticComponent<FieldInputProps & React.RefAttributes<HTMLDivElement>>;
758
+ /**
759
+ * Error component for displaying field-level validation errors.
760
+ * Must be used within a Form.Field.InputWrapper component.
761
+ * Only renders when there is an error for the current field.
762
+ *
763
+ * @component
764
+ * @example
765
+ * ```tsx
766
+ * import { Form } from '@wix/headless-forms/react';
767
+ *
768
+ * <Form.Field id="email">
769
+ * <Form.Field.Label>
770
+ * <label className="text-foreground font-paragraph">Email Address</label>
771
+ * </Form.Field.Label>
772
+ * <Form.Field.InputWrapper>
773
+ * <Form.Field.Input>
774
+ * <input type="email" className="bg-background border-foreground text-foreground" />
775
+ * </Form.Field.Input>
776
+ * <Form.Field.Error path="email">
777
+ * <span className="text-destructive text-sm font-paragraph">Please enter a valid email address</span>
778
+ * </Form.Field.Error>
779
+ * </Form.Field.InputWrapper>
780
+ * </Form.Field>
781
+ * ```
782
+ */
783
+ export declare const FieldError: React.ForwardRefExoticComponent<FieldErrorProps & React.RefAttributes<HTMLDivElement>>;
784
+ export declare const Field: FieldComponent;
568
785
  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.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.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";
@@ -47,6 +49,11 @@ var TestIds;
47
49
  TestIds["formLoadingError"] = "form-loading-error";
48
50
  TestIds["formError"] = "form-error";
49
51
  TestIds["formSubmitted"] = "form-submitted";
52
+ TestIds["fieldRoot"] = "field-root";
53
+ TestIds["fieldLabel"] = "field-label";
54
+ TestIds["fieldInputWrapper"] = "field-input-wrapper";
55
+ TestIds["fieldInput"] = "field-input";
56
+ TestIds["fieldError"] = "field-error";
50
57
  })(TestIds || (TestIds = {}));
51
58
  /**
52
59
  * Root component that provides all necessary service contexts for a complete form experience.
@@ -348,6 +355,8 @@ exports.Submitted = react_1.default.forwardRef((props, ref) => {
348
355
  * @component
349
356
  * @param {FieldsProps} props - Component props
350
357
  * @param {FieldMap} props.fieldMap - A mapping of field types to their corresponding React components
358
+ * @param {string} props.rowGapClassname - CSS class name for gap between rows
359
+ * @param {string} props.columnGapClassname - CSS class name for gap between columns
351
360
  * @example
352
361
  * ```tsx
353
362
  * import { Form } from '@wix/headless-forms/react';
@@ -366,7 +375,11 @@ exports.Submitted = react_1.default.forwardRef((props, ref) => {
366
375
  * <Form.Root formServiceConfig={formServiceConfig}>
367
376
  * <Form.Loading className="flex justify-center p-4" />
368
377
  * <Form.LoadingError className="text-destructive px-4 py-3 rounded mb-4" />
369
- * <Form.Fields fieldMap={FIELD_MAP} />
378
+ * <Form.Fields
379
+ * fieldMap={FIELD_MAP}
380
+ * rowGapClassname="gap-y-4"
381
+ * columnGapClassname="gap-x-2"
382
+ * />
370
383
  * </Form.Root>
371
384
  * );
372
385
  * }
@@ -381,12 +394,15 @@ exports.Submitted = react_1.default.forwardRef((props, ref) => {
381
394
  * - Field validation and error display
382
395
  * - Form state management
383
396
  * - Field value updates
397
+ * - Grid layout with configurable row and column gaps
384
398
  *
385
399
  * Must be used within Form.Root to access form context.
386
400
  *
387
401
  * @component
388
402
  * @param {FieldsProps} props - The component props
389
403
  * @param {FieldMap} props.fieldMap - A mapping of field types to their corresponding React components. Each key represents a field type (e.g., 'TEXT_INPUT', 'CHECKBOX') and the value is the React component that should render that field type.
404
+ * @param {string} props.rowGapClassname - CSS class name for gap between form rows
405
+ * @param {string} props.columnGapClassname - CSS class name for gap between form columns
390
406
  *
391
407
  * @example
392
408
  * ```tsx
@@ -454,7 +470,11 @@ exports.Submitted = react_1.default.forwardRef((props, ref) => {
454
470
  * <Form.Root formServiceConfig={formServiceConfig}>
455
471
  * <Form.Loading className="flex justify-center p-4" />
456
472
  * <Form.LoadingError className="text-destructive px-4 py-3 rounded mb-4" />
457
- * <Form.Fields fieldMap={FIELD_MAP} />
473
+ * <Form.Fields
474
+ * fieldMap={FIELD_MAP}
475
+ * rowGapClassname="gap-y-4"
476
+ * columnGapClassname="gap-x-2"
477
+ * />
458
478
  * <Form.Error className="text-destructive p-4 rounded-lg mb-4" />
459
479
  * <Form.Submitted className="text-green-500 p-4 rounded-lg mb-4" />
460
480
  * </Form.Root>
@@ -464,23 +484,41 @@ exports.Submitted = react_1.default.forwardRef((props, ref) => {
464
484
  *
465
485
  * @example
466
486
  * ```tsx
467
- * // Advanced usage with custom field components
468
- * const CustomTextField = ({ value, onChange, label, error, ...props }) => (
469
- * <div className="form-field">
470
- * <label className="text-foreground font-paragraph">{label}</label>
471
- * <input
472
- * value={value || ''}
473
- * onChange={(e) => onChange(e.target.value)}
474
- * className="bg-background border-foreground text-foreground"
475
- * {...props}
476
- * />
477
- * {error && <span className="text-destructive">{error}</span>}
478
- * </div>
479
- * );
487
+ * // Creating custom field components - ALL field components MUST use Form.Field
488
+ * // This example shows the REQUIRED structure for a TEXT_INPUT component
489
+ * import { Form, type TextInputProps } from '@wix/headless-forms/react';
490
+ *
491
+ * const TextInput = (props: TextInputProps) => {
492
+ * const { id, value, onChange, label, error, required, ...inputProps } = props;
493
+ *
494
+ * // Form.Field provides automatic grid layout positioning
495
+ * return (
496
+ * <Form.Field id={id}>
497
+ * <Form.Field.Label>
498
+ * <label className="text-foreground font-paragraph">
499
+ * {label}
500
+ * {required && <span className="text-destructive ml-1">*</span>}
501
+ * </label>
502
+ * </Form.Field.Label>
503
+ * <Form.Field.Input
504
+ * description={error && <span className="text-destructive text-sm">{error}</span>}
505
+ * >
506
+ * <input
507
+ * type="text"
508
+ * value={value || ''}
509
+ * onChange={(e) => onChange(e.target.value)}
510
+ * className="bg-background border-foreground text-foreground"
511
+ * aria-invalid={!!error}
512
+ * {...inputProps}
513
+ * />
514
+ * </Form.Field.Input>
515
+ * </Form.Field>
516
+ * );
517
+ * };
480
518
  *
481
519
  * const FIELD_MAP = {
482
- * TEXT_INPUT: CustomTextField,
483
- * // ... other field components
520
+ * TEXT_INPUT: TextInput,
521
+ * // ... all other field components must also use Form.Field
484
522
  * };
485
523
  * ```
486
524
  */
@@ -496,6 +534,200 @@ exports.Fields = react_1.default.forwardRef((props, ref) => {
496
534
  return ((0, jsx_runtime_1.jsx)(Form_js_1.Fields, { children: ({ form, submitForm }) => {
497
535
  if (!form)
498
536
  return null;
499
- return ((0, jsx_runtime_1.jsx)("div", { ref: ref, children: (0, jsx_runtime_1.jsx)(form_public_1.Form, { form: form, values: formValues, onChange: handleFormChange, errors: formErrors, onValidate: handleFormValidate, fields: props.fieldMap, submitForm: () => submitForm(formValues) }) }));
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 }) }) }));
538
+ } }));
539
+ });
540
+ const FieldsWithForm = ({ form, submitForm, values, onChange, errors, onValidate, fields: fieldMap, rowGapClassname, columnGapClassname, }) => {
541
+ const formData = (0, form_public_1.useForm)({
542
+ form,
543
+ values,
544
+ errors,
545
+ onChange,
546
+ onValidate,
547
+ submitForm,
548
+ fieldMap,
549
+ });
550
+ if (!formData)
551
+ return null;
552
+ const { columnCount, fieldElements, fieldsLayout } = formData;
553
+ return (
554
+ // TODO: use readOnly, isDisabled
555
+ // TODO: step title a11y support
556
+ // TODO: mobile support?
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) => {
558
+ return ((0, jsx_runtime_1.jsx)("div", { style: {
559
+ display: 'grid',
560
+ width: '100%',
561
+ gridTemplateColumns: `repeat(${columnCount}, 1fr)`,
562
+ gridAutoRows: 'minmax(min-content, max-content)',
563
+ }, className: columnGapClassname, children: rowElements }, index));
564
+ }) }) }) }));
565
+ };
566
+ /**
567
+ * Container component for a form field with grid layout support.
568
+ * Provides context to Field.Label, Field.InputWrapper, Field.Input, and Field.Error child components.
569
+ * Based on the default-field-layout functionality.
570
+ *
571
+ * @component
572
+ * @example
573
+ * ```tsx
574
+ * import { Form } from '@wix/headless-forms/react';
575
+ *
576
+ * function FormFields() {
577
+ * return (
578
+ * <Form.Field id="username">
579
+ * <Form.Field.Label>
580
+ * <label className="text-foreground font-paragraph">Username</label>
581
+ * </Form.Field.Label>
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>
590
+ * </Form.Field>
591
+ * );
592
+ * }
593
+ * ```
594
+ */
595
+ const FieldRoot = react_1.default.forwardRef((props, ref) => {
596
+ const { id, children, asChild, className, ...otherProps } = props;
597
+ const layout = (0, FieldLayoutContext_js_1.useFieldLayout)(id);
598
+ if (!layout) {
599
+ return null;
600
+ }
601
+ return ((0, jsx_runtime_1.jsx)(Form_js_1.Field, { id: id, layout: layout, children: (fieldData) => {
602
+ const contextValue = {
603
+ id,
604
+ layout: fieldData.layout,
605
+ gridStyles: fieldData.gridStyles,
606
+ };
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 }) }));
500
608
  } }));
501
609
  });
610
+ FieldRoot.displayName = 'Form.Field';
611
+ /**
612
+ * Label component for a form field with automatic grid positioning.
613
+ * Must be used within a Form.Field component.
614
+ * Renders in the label row of the field's grid layout.
615
+ *
616
+ * @component
617
+ * @example
618
+ * ```tsx
619
+ * import { Form } from '@wix/headless-forms/react';
620
+ *
621
+ * <Form.Field id="email">
622
+ * <Form.Field.Label>
623
+ * <label className="text-foreground font-paragraph">Email Address</label>
624
+ * </Form.Field.Label>
625
+ * <Form.Field.InputWrapper>
626
+ * <Form.Field.Input>
627
+ * <input type="email" className="bg-background border-foreground text-foreground" />
628
+ * </Form.Field.Input>
629
+ * </Form.Field.InputWrapper>
630
+ * </Form.Field>
631
+ * ```
632
+ */
633
+ exports.FieldLabel = react_1.default.forwardRef((props, ref) => {
634
+ const { children, asChild, className, ...otherProps } = props;
635
+ const { gridStyles } = (0, FieldContext_js_1.useFieldContext)();
636
+ 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 }) }));
637
+ });
638
+ exports.FieldLabel.displayName = 'Form.Field.Label';
639
+ /**
640
+ * InputWrapper component that wraps input and error elements with grid positioning.
641
+ * Must be used within a Form.Field component.
642
+ * This wrapper applies the grid positioning styles to contain both the input and error.
643
+ *
644
+ * @component
645
+ * @example
646
+ * ```tsx
647
+ * import { Form } from '@wix/headless-forms/react';
648
+ *
649
+ * <Form.Field id="email">
650
+ * <Form.Field.Label>
651
+ * <label className="text-foreground font-paragraph">Email Address</label>
652
+ * </Form.Field.Label>
653
+ * <Form.Field.InputWrapper>
654
+ * <Form.Field.Input>
655
+ * <input type="email" className="bg-background border-foreground text-foreground" />
656
+ * </Form.Field.Input>
657
+ * <Form.Field.Error>
658
+ * <span className="text-destructive text-sm font-paragraph">Please enter a valid email</span>
659
+ * </Form.Field.Error>
660
+ * </Form.Field.InputWrapper>
661
+ * </Form.Field>
662
+ * ```
663
+ */
664
+ exports.FieldInputWrapper = react_1.default.forwardRef((props, ref) => {
665
+ const { children, asChild, className, ...otherProps } = props;
666
+ const { gridStyles } = (0, FieldContext_js_1.useFieldContext)();
667
+ 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 }) }));
668
+ });
669
+ exports.FieldInputWrapper.displayName = 'Form.Field.InputWrapper';
670
+ /**
671
+ * Input component for a form field.
672
+ * Must be used within a Form.Field.InputWrapper component.
673
+ * Renders the actual input element without grid positioning.
674
+ *
675
+ * @component
676
+ * @example
677
+ * ```tsx
678
+ * import { Form } from '@wix/headless-forms/react';
679
+ *
680
+ * <Form.Field id="password">
681
+ * <Form.Field.Label>
682
+ * <label className="text-foreground font-paragraph">Password</label>
683
+ * </Form.Field.Label>
684
+ * <Form.Field.InputWrapper>
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>
688
+ * </Form.Field.InputWrapper>
689
+ * </Form.Field>
690
+ * ```
691
+ */
692
+ exports.FieldInput = react_1.default.forwardRef((props, ref) => {
693
+ const { children, description, asChild, className, ...otherProps } = props;
694
+ 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 }) }));
695
+ });
696
+ exports.FieldInput.displayName = 'Form.Field.Input';
697
+ /**
698
+ * Error component for displaying field-level validation errors.
699
+ * Must be used within a Form.Field.InputWrapper component.
700
+ * Only renders when there is an error for the current field.
701
+ *
702
+ * @component
703
+ * @example
704
+ * ```tsx
705
+ * import { Form } from '@wix/headless-forms/react';
706
+ *
707
+ * <Form.Field id="email">
708
+ * <Form.Field.Label>
709
+ * <label className="text-foreground font-paragraph">Email Address</label>
710
+ * </Form.Field.Label>
711
+ * <Form.Field.InputWrapper>
712
+ * <Form.Field.Input>
713
+ * <input type="email" className="bg-background border-foreground text-foreground" />
714
+ * </Form.Field.Input>
715
+ * <Form.Field.Error path="email">
716
+ * <span className="text-destructive text-sm font-paragraph">Please enter a valid email address</span>
717
+ * </Form.Field.Error>
718
+ * </Form.Field.InputWrapper>
719
+ * </Form.Field>
720
+ * ```
721
+ */
722
+ exports.FieldError = react_1.default.forwardRef((props, ref) => {
723
+ const { errorMessage, asChild, className, children, ...otherProps } = props;
724
+ if (!errorMessage && !children)
725
+ return null;
726
+ return ((0, jsx_runtime_1.jsx)(react_2.AsChildSlot, { "data-testid": TestIds.fieldError, ref: ref, asChild: asChild, className: className, ...otherProps, children: children || errorMessage }));
727
+ });
728
+ exports.FieldError.displayName = 'Form.Field.Error';
729
+ exports.Field = FieldRoot;
730
+ exports.Field.Label = exports.FieldLabel;
731
+ exports.Field.InputWrapper = exports.FieldInputWrapper;
732
+ exports.Field.Input = exports.FieldInput;
733
+ exports.Field.Error = exports.FieldError;
@@ -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;