@wix/headless-bookings 0.0.55 → 0.0.57

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.
@@ -4,17 +4,20 @@
4
4
  */
5
5
  import React from 'react';
6
6
  import { Form } from '@wix/headless-forms/react';
7
+ import * as CoreBookingForm from '../core/booking-form/BookingForm.js';
7
8
  type FieldMap = Parameters<typeof Form.Fields>[0]['fieldMap'];
8
9
  /**
9
10
  * Props for BookingForm.Root component
10
11
  */
11
12
  export interface RootProps {
12
13
  /** The form ID to load (required - standalone mode) */
13
- formId: string;
14
+ formId?: string;
15
+ /** Optional service IDs to pass to FormService (will be merged into additionalMetadata) */
16
+ serviceIds?: string[];
14
17
  /** Optional additional metadata to pass to FormService */
15
18
  additionalMetadata?: Record<string, string | string[]>;
16
- /** Optional partial field map to override default booking field components */
17
- fieldMap?: Partial<FieldMap>;
19
+ /** Field map to override default booking field components */
20
+ fieldMap: FieldMap;
18
21
  /** Child components - if not provided, Form.Fields is rendered with default field map */
19
22
  children?: React.ReactNode;
20
23
  /** Whether to render as a child component */
@@ -25,6 +28,8 @@ export interface RootProps {
25
28
  rowGapClassname?: string;
26
29
  /** Column gap class name for Form.Fields when using default rendering */
27
30
  columnGapClassname?: string;
31
+ /** Custom fallback UI for load errors. Can be a ReactNode or a function that receives the error. */
32
+ loadErrorFallback?: React.ReactNode | ((error: Error) => React.ReactNode);
28
33
  }
29
34
  /**
30
35
  * Root component for booking form that wraps CoreBookingForm.Root.
@@ -40,6 +45,12 @@ export interface RootProps {
40
45
  * // Minimal usage - uses default field components
41
46
  * <BookingForm.Root formId="your-form-id" />
42
47
  *
48
+ * // With serviceIds
49
+ * <BookingForm.Root
50
+ * formId="your-form-id"
51
+ * serviceIds={['service-1', 'service-2']}
52
+ * />
53
+ *
43
54
  * // With custom styling
44
55
  * <BookingForm.Root
45
56
  * formId="your-form-id"
@@ -91,6 +102,74 @@ export interface FieldsProps {
91
102
  * ```
92
103
  */
93
104
  export declare const Fields: React.ForwardRefExoticComponent<FieldsProps & React.RefAttributes<HTMLDivElement>>;
105
+ /**
106
+ * Props for BookingForm.Actions.ValidateFormSubmission component
107
+ */
108
+ export interface ValidateFormSubmissionProps {
109
+ asChild?: boolean;
110
+ children?: React.ReactNode | ((props: {
111
+ onClick: () => Promise<void>;
112
+ valid: boolean | null;
113
+ validationFailures: string[];
114
+ }) => React.ReactNode);
115
+ className?: string;
116
+ label?: string;
117
+ /** Callback when validation completes */
118
+ onValidationComplete?: (result: {
119
+ valid: boolean;
120
+ validationFailures: string[];
121
+ }) => void;
122
+ }
123
+ /**
124
+ * Button to validate the booking form submission.
125
+ * Must be used within BookingForm.Root or BookingForm.Data context.
126
+ * Default label is "Validate".
127
+ *
128
+ * @component
129
+ * @example
130
+ * ```tsx
131
+ * // Within BookingForm.Root
132
+ * <BookingForm.Root formId="your-form-id" fieldMap={...}>
133
+ * <BookingForm.Fields />
134
+ * <BookingForm.Actions.ValidateFormSubmission />
135
+ * </BookingForm.Root>
136
+ *
137
+ * // With custom label
138
+ * <BookingForm.Actions.ValidateFormSubmission label="Check Form" />
139
+ *
140
+ * // With asChild
141
+ * <BookingForm.Actions.ValidateFormSubmission asChild>
142
+ * <button className="btn-primary">Validate Booking</button>
143
+ * </BookingForm.Actions.ValidateFormSubmission>
144
+ *
145
+ * // Using render prop pattern with validation callback
146
+ * <BookingForm.Actions.ValidateFormSubmission
147
+ * onValidationComplete={(result) => {
148
+ * if (result.valid) {
149
+ * console.log('Form is valid!');
150
+ * } else {
151
+ * console.log('Validation errors:', result.validationFailures);
152
+ * }
153
+ * }}
154
+ * >
155
+ * {({ onClick, valid, validationFailures }) => (
156
+ * <button onClick={onClick}>
157
+ * {valid === null ? 'Validate' : valid ? 'Valid ✓' : 'Invalid ✗'}
158
+ * {validationFailures.length > 0 && (
159
+ * <span> ({validationFailures.length} errors)</span>
160
+ * )}
161
+ * </button>
162
+ * )}
163
+ * </BookingForm.Actions.ValidateFormSubmission>
164
+ * ```
165
+ */
166
+ export declare const ValidateFormSubmission: React.ForwardRefExoticComponent<ValidateFormSubmissionProps & React.RefAttributes<HTMLButtonElement>>;
167
+ /**
168
+ * Actions namespace for BookingForm
169
+ */
170
+ export declare const Actions: {
171
+ ValidateFormSubmission: React.ForwardRefExoticComponent<ValidateFormSubmissionProps & React.RefAttributes<HTMLButtonElement>>;
172
+ };
94
173
  /**
95
174
  * Render props for BookingForm.Data component
96
175
  */
@@ -105,24 +184,27 @@ export interface DataRenderProps {
105
184
  formSubmission: Record<string, unknown> | null;
106
185
  /** Action to store form submission data */
107
186
  setFormSubmission: (formValues: Record<string, unknown>) => void;
108
- /** Action to validate the form */
109
- validateFormSubmission: () => Promise<{
110
- valid: boolean;
111
- validationFailures: string[];
112
- }>;
187
+ /** Ref to access form methods imperatively (pass to Form.Fields) */
188
+ formRef: React.RefObject<CoreBookingForm.FormHandle | null>;
189
+ /** Action to validate the form fields. Returns true if valid, false if there are errors. */
190
+ validate: () => Promise<boolean>;
113
191
  }
114
192
  /**
115
193
  * Props for BookingForm.Data component
116
194
  */
117
195
  export interface DataProps {
118
- /** The form ID to load (required - standalone mode) */
119
- formId: string;
196
+ /** The form ID to load (if not provided, the formId will be extracted from the selected service if available) */
197
+ formId?: string;
198
+ /** Optional service IDs to pass to FormService (will be merged into additionalMetadata) */
199
+ serviceIds?: string[];
120
200
  /** Optional additional metadata to pass to FormService */
121
201
  additionalMetadata?: Record<string, string | string[]>;
122
- /** Optional partial field map to override default booking field components */
123
- fieldMap?: Partial<FieldMap>;
202
+ /** Field map to override default booking field components */
203
+ fieldMap: FieldMap;
124
204
  /** Render prop function that receives form data and actions */
125
205
  children: (data: DataRenderProps) => React.ReactNode;
206
+ /** Custom fallback UI for load errors. Can be a ReactNode or a function that receives the error. */
207
+ loadErrorFallback?: React.ReactNode | ((error: Error) => React.ReactNode);
126
208
  }
127
209
  /**
128
210
  * Data component that provides booking form data via render props.
@@ -132,12 +214,17 @@ export interface DataProps {
132
214
  * @example
133
215
  * ```tsx
134
216
  * <BookingForm.Data formId="your-form-id">
135
- * {({ formId, fields, formValues, setFormSubmission, validateFormSubmission }) => (
217
+ * {({ formId, fields, formValues, formRef, validate, setFormSubmission }) => (
136
218
  * <div>
137
- * <Form.Fields fieldMap={fields} rowGapClassname="gap-y-4" columnGapClassname="gap-x-2" />
219
+ * <Form.Fields
220
+ * fieldMap={fields}
221
+ * rowGapClassname="gap-y-4"
222
+ * columnGapClassname="gap-x-2"
223
+ * formRef={formRef}
224
+ * />
138
225
  * <button onClick={async () => {
139
- * const result = await validateFormSubmission();
140
- * if (result.valid) {
226
+ * const isValid = await validate();
227
+ * if (isValid) {
141
228
  * // Store current form values before submission
142
229
  * setFormSubmission(formValues);
143
230
  * }
@@ -147,10 +234,23 @@ export interface DataProps {
147
234
  * </div>
148
235
  * )}
149
236
  * </BookingForm.Data>
237
+ *
238
+ * // With serviceIds
239
+ * <BookingForm.Data
240
+ * formId="your-form-id"
241
+ * serviceIds={['service-1', 'service-2']}
242
+ * >
243
+ * {({ fields, formRef }) => (
244
+ * <Form.Fields fieldMap={fields} formRef={formRef} />
245
+ * )}
246
+ * </BookingForm.Data>
150
247
  * ```
151
248
  */
152
249
  export declare function Data(props: DataProps): React.ReactNode;
153
250
  export declare namespace Data {
154
251
  var displayName: string;
155
252
  }
156
- export {};
253
+ /**
254
+ * Re-export LoadError component and utilities for error handling
255
+ */
256
+ export { LoadError, isBookingFormConfigurationError, BookingFormConfigurationError, } from '../core/booking-form/BookingForm.js';
@@ -7,10 +7,44 @@ import React from 'react';
7
7
  import { AsChildSlot } from '@wix/headless-utils/react';
8
8
  import { Form } from '@wix/headless-forms/react';
9
9
  import * as CoreBookingForm from '../core/booking-form/BookingForm.js';
10
+ import { BookingFormConfigurationError } from '../../services/booking-form/booking-form.js';
11
+ /**
12
+ * Internal ErrorBoundary for catching BookingFormConfigurationError
13
+ */
14
+ class BookingFormErrorBoundary extends React.Component {
15
+ constructor(props) {
16
+ super(props);
17
+ this.state = { error: null };
18
+ }
19
+ static getDerivedStateFromError(error) {
20
+ return { error };
21
+ }
22
+ render() {
23
+ const { error } = this.state;
24
+ const { children, fallback } = this.props;
25
+ if (error) {
26
+ // If it's a configuration error, render the fallback
27
+ if (error instanceof BookingFormConfigurationError) {
28
+ if (typeof fallback === 'function') {
29
+ return fallback(error);
30
+ }
31
+ if (fallback) {
32
+ return fallback;
33
+ }
34
+ // Default fallback UI
35
+ return _jsx("div", { "data-testid": "booking-form-load-error", children: error.message });
36
+ }
37
+ // Re-throw non-configuration errors
38
+ throw error;
39
+ }
40
+ return children;
41
+ }
42
+ }
10
43
  var TestIds;
11
44
  (function (TestIds) {
12
45
  TestIds["bookingFormRoot"] = "booking-form-root";
13
46
  TestIds["bookingFormFields"] = "booking-form-fields";
47
+ TestIds["bookingFormActionValidateFormSubmission"] = "booking-form-action-validate-form-submission";
14
48
  })(TestIds || (TestIds = {}));
15
49
  /**
16
50
  * Root component for booking form that wraps CoreBookingForm.Root.
@@ -26,6 +60,12 @@ var TestIds;
26
60
  * // Minimal usage - uses default field components
27
61
  * <BookingForm.Root formId="your-form-id" />
28
62
  *
63
+ * // With serviceIds
64
+ * <BookingForm.Root
65
+ * formId="your-form-id"
66
+ * serviceIds={['service-1', 'service-2']}
67
+ * />
68
+ *
29
69
  * // With custom styling
30
70
  * <BookingForm.Root
31
71
  * formId="your-form-id"
@@ -51,8 +91,8 @@ var TestIds;
51
91
  * ```
52
92
  */
53
93
  export const Root = React.forwardRef((props, ref) => {
54
- const { children, asChild, className, formId, additionalMetadata, fieldMap, rowGapClassname = 'gap-y-4', columnGapClassname = 'gap-x-2', ...otherProps } = props;
55
- return (_jsx(CoreBookingForm.Root, { formId: formId, additionalMetadata: additionalMetadata, fieldMap: fieldMap, children: ({ fields }) => (_jsx(BookingFormContext.Provider, { value: { fields, rowGapClassname, columnGapClassname }, children: _jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.bookingFormRoot, ...otherProps, children: _jsx("div", { children: children ?? (_jsxs(_Fragment, { children: [_jsx(Form.Loading, { className: "flex justify-center p-4 text-foreground" }), _jsx(Form.LoadingError, { className: "bg-destructive/10 border border-destructive/20 text-destructive px-4 py-3 rounded-lg mb-4" }), _jsx(Form.Fields, { fieldMap: fields, rowGapClassname: rowGapClassname, columnGapClassname: columnGapClassname }), _jsx(Form.Error, { className: "mt-4 bg-destructive/10 border border-destructive/20 text-destructive px-4 py-3 rounded-lg" }), _jsx(Form.Submitted, { className: "mt-4 bg-green-500/10 border border-green-500/20 text-green-500 px-4 py-3 rounded-lg" })] })) }) }) })) }));
94
+ const { children, asChild, className, formId, serviceIds, additionalMetadata, fieldMap, rowGapClassname = 'gap-y-4', columnGapClassname = 'gap-x-2', loadErrorFallback, ...otherProps } = props;
95
+ return (_jsx(BookingFormErrorBoundary, { fallback: loadErrorFallback, children: _jsx(CoreBookingForm.Root, { formId: formId, serviceIds: serviceIds, additionalMetadata: additionalMetadata, fieldMap: fieldMap, children: ({ fields }) => (_jsx(BookingFormContext.Provider, { value: { fields, rowGapClassname, columnGapClassname }, children: _jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.bookingFormRoot, ...otherProps, children: _jsx("div", { children: children ?? (_jsxs(_Fragment, { children: [_jsx(Form.Loading, { className: "flex justify-center p-4 text-foreground" }), _jsx(Form.LoadingError, { className: "bg-destructive/10 border border-destructive/20 text-destructive px-4 py-3 rounded-lg mb-4" }), _jsx(Form.Fields, { fieldMap: fields, rowGapClassname: rowGapClassname, columnGapClassname: columnGapClassname }), _jsx(Form.Error, { className: "mt-4 bg-destructive/10 border border-destructive/20 text-destructive px-4 py-3 rounded-lg" }), _jsx(Form.Submitted, { className: "mt-4 bg-green-500/10 border border-green-500/20 text-green-500 px-4 py-3 rounded-lg" })] })) }) }) })) }) }));
56
96
  });
57
97
  Root.displayName = 'BookingForm.Root';
58
98
  const BookingFormContext = React.createContext(null);
@@ -87,6 +127,77 @@ export const Fields = React.forwardRef((props, ref) => {
87
127
  return (_jsx("div", { ref: ref, className: className, "data-testid": TestIds.bookingFormFields, ...otherProps, children: _jsx(Form.Fields, { fieldMap: context.fields, rowGapClassname: rowGapClassname, columnGapClassname: columnGapClassname }) }));
88
128
  });
89
129
  Fields.displayName = 'BookingForm.Fields';
130
+ /**
131
+ * Button to validate the booking form submission.
132
+ * Must be used within BookingForm.Root or BookingForm.Data context.
133
+ * Default label is "Validate".
134
+ *
135
+ * @component
136
+ * @example
137
+ * ```tsx
138
+ * // Within BookingForm.Root
139
+ * <BookingForm.Root formId="your-form-id" fieldMap={...}>
140
+ * <BookingForm.Fields />
141
+ * <BookingForm.Actions.ValidateFormSubmission />
142
+ * </BookingForm.Root>
143
+ *
144
+ * // With custom label
145
+ * <BookingForm.Actions.ValidateFormSubmission label="Check Form" />
146
+ *
147
+ * // With asChild
148
+ * <BookingForm.Actions.ValidateFormSubmission asChild>
149
+ * <button className="btn-primary">Validate Booking</button>
150
+ * </BookingForm.Actions.ValidateFormSubmission>
151
+ *
152
+ * // Using render prop pattern with validation callback
153
+ * <BookingForm.Actions.ValidateFormSubmission
154
+ * onValidationComplete={(result) => {
155
+ * if (result.valid) {
156
+ * console.log('Form is valid!');
157
+ * } else {
158
+ * console.log('Validation errors:', result.validationFailures);
159
+ * }
160
+ * }}
161
+ * >
162
+ * {({ onClick, valid, validationFailures }) => (
163
+ * <button onClick={onClick}>
164
+ * {valid === null ? 'Validate' : valid ? 'Valid ✓' : 'Invalid ✗'}
165
+ * {validationFailures.length > 0 && (
166
+ * <span> ({validationFailures.length} errors)</span>
167
+ * )}
168
+ * </button>
169
+ * )}
170
+ * </BookingForm.Actions.ValidateFormSubmission>
171
+ * ```
172
+ */
173
+ export const ValidateFormSubmission = React.forwardRef((props, ref) => {
174
+ const { asChild, children, className, label = 'Validate', onValidationComplete, } = props;
175
+ const [valid, setValid] = React.useState(null);
176
+ const [validationFailures, setValidationFailures] = React.useState([]);
177
+ return (_jsx(CoreBookingForm.Actions, { children: ({ validateFormSubmission }) => {
178
+ const handleClick = async () => {
179
+ const result = await validateFormSubmission();
180
+ setValid(result.valid);
181
+ setValidationFailures(result.validationFailures);
182
+ if (onValidationComplete) {
183
+ onValidationComplete(result);
184
+ }
185
+ };
186
+ return (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.bookingFormActionValidateFormSubmission, "data-valid": valid, customElement: children, customElementProps: {
187
+ onClick: handleClick,
188
+ valid,
189
+ validationFailures,
190
+ }, children: _jsx("button", { onClick: handleClick, children: label }) }));
191
+ } }));
192
+ });
193
+ ValidateFormSubmission.displayName =
194
+ 'BookingForm.Actions.ValidateFormSubmission';
195
+ /**
196
+ * Actions namespace for BookingForm
197
+ */
198
+ export const Actions = {
199
+ ValidateFormSubmission,
200
+ };
90
201
  /**
91
202
  * Data component that provides booking form data via render props.
92
203
  * Use this when you need programmatic access to form state and actions.
@@ -95,12 +206,17 @@ Fields.displayName = 'BookingForm.Fields';
95
206
  * @example
96
207
  * ```tsx
97
208
  * <BookingForm.Data formId="your-form-id">
98
- * {({ formId, fields, formValues, setFormSubmission, validateFormSubmission }) => (
209
+ * {({ formId, fields, formValues, formRef, validate, setFormSubmission }) => (
99
210
  * <div>
100
- * <Form.Fields fieldMap={fields} rowGapClassname="gap-y-4" columnGapClassname="gap-x-2" />
211
+ * <Form.Fields
212
+ * fieldMap={fields}
213
+ * rowGapClassname="gap-y-4"
214
+ * columnGapClassname="gap-x-2"
215
+ * formRef={formRef}
216
+ * />
101
217
  * <button onClick={async () => {
102
- * const result = await validateFormSubmission();
103
- * if (result.valid) {
218
+ * const isValid = await validate();
219
+ * if (isValid) {
104
220
  * // Store current form values before submission
105
221
  * setFormSubmission(formValues);
106
222
  * }
@@ -110,17 +226,35 @@ Fields.displayName = 'BookingForm.Fields';
110
226
  * </div>
111
227
  * )}
112
228
  * </BookingForm.Data>
229
+ *
230
+ * // With serviceIds
231
+ * <BookingForm.Data
232
+ * formId="your-form-id"
233
+ * serviceIds={['service-1', 'service-2']}
234
+ * >
235
+ * {({ fields, formRef }) => (
236
+ * <Form.Fields fieldMap={fields} formRef={formRef} />
237
+ * )}
238
+ * </BookingForm.Data>
113
239
  * ```
114
240
  */
115
241
  export function Data(props) {
116
- const { formId, additionalMetadata, fieldMap, children } = props;
117
- return (_jsx(CoreBookingForm.Root, { formId: formId, additionalMetadata: additionalMetadata, fieldMap: fieldMap, children: ({ formId: id, fields, formValues, formSubmission, setFormSubmission, validateFormSubmission, }) => children({
118
- formId: id,
119
- fields,
120
- formValues,
121
- formSubmission,
122
- setFormSubmission,
123
- validateFormSubmission,
124
- }) }));
242
+ const { formId, serviceIds, additionalMetadata, fieldMap, children, loadErrorFallback, } = props;
243
+ return (_jsx(BookingFormErrorBoundary, { fallback: loadErrorFallback, children: _jsx(CoreBookingForm.Root, { formId: formId, serviceIds: serviceIds, additionalMetadata: additionalMetadata, fieldMap: fieldMap, children: ({ formId: id, fields, formValues, formSubmission, setFormSubmission, validateFormSubmission, formRef, }) => children({
244
+ formId: id,
245
+ fields,
246
+ formValues,
247
+ formSubmission,
248
+ setFormSubmission,
249
+ formRef,
250
+ validate: validateFormSubmission,
251
+ }) }) }));
125
252
  }
126
253
  Data.displayName = 'BookingForm.Data';
254
+ // ============================================================================
255
+ // Error Handling
256
+ // ============================================================================
257
+ /**
258
+ * Re-export LoadError component and utilities for error handling
259
+ */
260
+ export { LoadError, isBookingFormConfigurationError, BookingFormConfigurationError, } from '../core/booking-form/BookingForm.js';
@@ -9,11 +9,18 @@
9
9
  * 2. SSR/SSG: Provide a pre-loaded form object for server-side rendering
10
10
  */
11
11
  import * as React from 'react';
12
- import type { FormValues } from '@wix/form-public';
13
- import { forms } from '@wix/forms';
14
- import { type ValidationResult } from '../../../services/booking-form/booking-form.js';
12
+ import { type FormValues } from '@wix/form-public';
13
+ import { forms, submissions } from '@wix/forms';
14
+ import { BookingFormConfigurationError, type ValidationResult } from '../../../services/booking-form/booking-form.js';
15
15
  import { Form } from '@wix/headless-forms/react';
16
16
  type FieldMap = Parameters<typeof Form.Fields>[0]['fieldMap'];
17
+ export type Submit = () => Promise<submissions.GetSubmissionResponse['submission'] | undefined>;
18
+ export type ValidateStep = (stepId: string) => Promise<boolean>;
19
+ export type FormHandle = {
20
+ submit: Submit;
21
+ validate: () => Promise<boolean>;
22
+ validateStep?: ValidateStep;
23
+ };
17
24
  /**
18
25
  * Render props data provided to BookingForm children
19
26
  */
@@ -26,19 +33,23 @@ export interface BookingFormRenderProps {
26
33
  formSubmission: FormValues | null;
27
34
  /** Action to store form submission data */
28
35
  setFormSubmission: (formValues: FormValues) => void;
29
- /** Action to validate the form */
30
- validateFormSubmission: () => Promise<ValidationResult>;
36
+ /** Action to validate the form fields. Returns true if valid, false if there are errors. */
37
+ validateFormSubmission: () => Promise<boolean>;
31
38
  /** Merged field map (DEFAULT_BOOKING_FIELD_MAP + user overrides) */
32
39
  fields: FieldMap;
40
+ /** Ref to access form methods imperatively (pass to Form.Fields) */
41
+ formRef: React.RefObject<FormHandle | null>;
33
42
  }
34
43
  /**
35
44
  * Base props shared by all BookingForm config patterns
36
45
  */
37
46
  interface BookingFormBaseProps {
47
+ /** Optional service IDs to pass to FormService (will be merged into additionalMetadata) */
48
+ serviceIds?: string[];
38
49
  /** Optional additional metadata to pass to FormService */
39
50
  additionalMetadata?: Record<string, string | string[]>;
40
- /** Optional partial field map to override default booking field components */
41
- fieldMap?: Partial<FieldMap>;
51
+ /** Field map to override default booking field components */
52
+ fieldMap: FieldMap;
42
53
  /** Render prop function that receives form data and actions */
43
54
  children: (data: BookingFormRenderProps) => React.ReactNode;
44
55
  }
@@ -46,13 +57,14 @@ interface BookingFormBaseProps {
46
57
  * Props for BookingForm with formId (client-side loading)
47
58
  */
48
59
  interface BookingFormWithFormIdProps extends BookingFormBaseProps {
49
- /** The form ID to load (client-side loading) */
50
- formId: string;
60
+ /** The form ID to load (client-side loading) if not provided, the formId will be extracted from the selected service if available */
61
+ formId?: string;
51
62
  /** Pre-loaded form - not used in this mode */
52
63
  form?: never;
53
64
  }
54
65
  /**
55
66
  * Props for BookingForm with pre-loaded form (SSR/SSG)
67
+ * Returns undefined if formId should be extracted from services by the service layer
56
68
  */
57
69
  interface BookingFormWithFormProps extends BookingFormBaseProps {
58
70
  /** Pre-loaded form object (SSR/SSG) - must be from bookings namespace */
@@ -136,4 +148,94 @@ export type BookingFormProps = BookingFormWithFormIdProps | BookingFormWithFormP
136
148
  * ```
137
149
  */
138
150
  export declare function Root(props: BookingFormProps): React.ReactNode;
139
- export {};
151
+ /**
152
+ * Render props for BookingForm.Actions component
153
+ */
154
+ export interface ActionsRenderProps {
155
+ /** Action to validate the form submission */
156
+ validateFormSubmission: () => Promise<ValidationResult>;
157
+ /** The form ID being used */
158
+ formId: string;
159
+ /** Current form values */
160
+ formValues: FormValues;
161
+ /** Current form submission data */
162
+ formSubmission: FormValues | null;
163
+ }
164
+ /**
165
+ * Props for BookingForm.Actions component
166
+ */
167
+ export interface ActionsProps {
168
+ children: (data: ActionsRenderProps) => React.ReactNode;
169
+ }
170
+ /**
171
+ * Core component that provides booking form actions via render props.
172
+ * Must be used within BookingForm.Root context.
173
+ *
174
+ * @component
175
+ * @example
176
+ * ```tsx
177
+ * <CoreBookingForm.Root formId="form-123">
178
+ * {({ fields }) => (
179
+ * <>
180
+ * <Form.Fields fieldMap={fields} />
181
+ * <CoreBookingForm.Actions>
182
+ * {({ validateFormSubmission, formId }) => (
183
+ * <button onClick={async () => {
184
+ * const result = await validateFormSubmission();
185
+ * console.log('Validation result:', result);
186
+ * }}>
187
+ * Validate Form
188
+ * </button>
189
+ * )}
190
+ * </CoreBookingForm.Actions>
191
+ * </>
192
+ * )}
193
+ * </CoreBookingForm.Root>
194
+ * ```
195
+ */
196
+ export declare function Actions(props: ActionsProps): React.ReactNode;
197
+ /**
198
+ * Props for BookingForm.LoadError component
199
+ */
200
+ export interface LoadErrorProps {
201
+ /** The error that was caught */
202
+ error: Error;
203
+ /** Whether to render as a child component */
204
+ asChild?: boolean;
205
+ /** Custom content to render. If not provided, displays the error message. */
206
+ children?: React.ReactNode;
207
+ /** Additional CSS class name */
208
+ className?: string;
209
+ }
210
+ /**
211
+ * Component to display when BookingForm fails to load due to configuration errors.
212
+ * This component should be used in an error boundary to catch BookingFormConfigurationError.
213
+ *
214
+ * @component
215
+ * @example
216
+ * ```tsx
217
+ * import * as CoreBookingForm from '@wix/headless-bookings/react/core/booking-form';
218
+ *
219
+ * // Default usage with className
220
+ * <CoreBookingForm.LoadError error={error} className="text-destructive p-4" />
221
+ *
222
+ * // Custom content
223
+ * <CoreBookingForm.LoadError error={error}>
224
+ * <div className="error-container">
225
+ * <h3>Error Loading Form</h3>
226
+ * <p>Please try again later.</p>
227
+ * </div>
228
+ * </CoreBookingForm.LoadError>
229
+ *
230
+ * // With asChild for custom components
231
+ * <CoreBookingForm.LoadError error={error} asChild>
232
+ * <CustomErrorComponent />
233
+ * </CoreBookingForm.LoadError>
234
+ * ```
235
+ */
236
+ export declare const LoadError: React.ForwardRefExoticComponent<LoadErrorProps & React.RefAttributes<HTMLElement>>;
237
+ /**
238
+ * Type guard to check if an error is a BookingFormConfigurationError
239
+ */
240
+ export declare function isBookingFormConfigurationError(error: unknown): error is BookingFormConfigurationError;
241
+ export { BookingFormConfigurationError };