@page-speed/forms 0.6.2 → 0.6.4

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.
Files changed (57) hide show
  1. package/dist/{FormContext-D_K7lO2V.d.ts → FormContext-C6kWSQuv.d.ts} +1 -1
  2. package/dist/{FormContext-BHKCZ_du.d.cts → FormContext-DLG3GzgL.d.cts} +1 -1
  3. package/dist/chunk-A7MVZ757.js +701 -0
  4. package/dist/chunk-A7MVZ757.js.map +1 -0
  5. package/dist/chunk-DCGSRMZT.cjs +728 -0
  6. package/dist/chunk-DCGSRMZT.cjs.map +1 -0
  7. package/dist/{chunk-455PI4LV.js → chunk-J37BGNM6.js} +5 -4
  8. package/dist/chunk-J37BGNM6.js.map +1 -0
  9. package/dist/{chunk-4ROWNTY6.js → chunk-ML6FGUYS.js} +3 -3
  10. package/dist/{chunk-4ROWNTY6.js.map → chunk-ML6FGUYS.js.map} +1 -1
  11. package/dist/{chunk-QRI5TMES.cjs → chunk-QMWZLGON.cjs} +5 -4
  12. package/dist/chunk-QMWZLGON.cjs.map +1 -0
  13. package/dist/chunk-UBDA7CS5.js +3 -0
  14. package/dist/chunk-UBDA7CS5.js.map +1 -0
  15. package/dist/{chunk-ED4UK63G.cjs → chunk-UQ6JPOBF.cjs} +114 -114
  16. package/dist/{chunk-ED4UK63G.cjs.map → chunk-UQ6JPOBF.cjs.map} +1 -1
  17. package/dist/chunk-V7JSGFCI.cjs +4 -0
  18. package/dist/chunk-V7JSGFCI.cjs.map +1 -0
  19. package/dist/core.cjs +14 -14
  20. package/dist/core.d.cts +17 -11
  21. package/dist/core.d.ts +17 -11
  22. package/dist/core.js +3 -3
  23. package/dist/index.cjs +18 -18
  24. package/dist/index.d.cts +2 -2
  25. package/dist/index.d.ts +2 -2
  26. package/dist/index.js +3 -3
  27. package/dist/inputs.cjs +14 -14
  28. package/dist/inputs.d.cts +8 -2
  29. package/dist/inputs.d.ts +8 -2
  30. package/dist/inputs.js +2 -2
  31. package/dist/integration.cjs +115 -17
  32. package/dist/integration.cjs.map +1 -1
  33. package/dist/integration.d.cts +103 -127
  34. package/dist/integration.d.ts +103 -127
  35. package/dist/integration.js +101 -4
  36. package/dist/integration.js.map +1 -1
  37. package/dist/{types-Fbt73kW_.d.ts → types-BhcLAcZe.d.cts} +149 -22
  38. package/dist/{types-Fbt73kW_.d.cts → types-BhcLAcZe.d.ts} +149 -22
  39. package/dist/validation-rules.d.cts +1 -1
  40. package/dist/validation-rules.d.ts +1 -1
  41. package/dist/validation-utils.d.cts +1 -1
  42. package/dist/validation-utils.d.ts +1 -1
  43. package/dist/validation-valibot.d.cts +1 -1
  44. package/dist/validation-valibot.d.ts +1 -1
  45. package/dist/validation.d.cts +1 -1
  46. package/dist/validation.d.ts +1 -1
  47. package/package.json +1 -1
  48. package/dist/chunk-455PI4LV.js.map +0 -1
  49. package/dist/chunk-MJYEXJ3U.js +0 -373
  50. package/dist/chunk-MJYEXJ3U.js.map +0 -1
  51. package/dist/chunk-MUBEMXI7.cjs +0 -397
  52. package/dist/chunk-MUBEMXI7.cjs.map +0 -1
  53. package/dist/chunk-QRI5TMES.cjs.map +0 -1
  54. package/dist/chunk-RS6AXV5S.cjs +0 -309
  55. package/dist/chunk-RS6AXV5S.cjs.map +0 -1
  56. package/dist/chunk-ZEAH6AKP.js +0 -285
  57. package/dist/chunk-ZEAH6AKP.js.map +0 -1
@@ -1,6 +1,6 @@
1
1
  import * as React from 'react';
2
- import { ReactNode } from 'react';
3
- import { d as FormSubmissionBehavior, N as NewFormSubmissionActionConfig, m as UseFormReturn } from './types-Fbt73kW_.cjs';
2
+ import { e as FormSubmissionConfig, t as FormLayoutSettings, u as FormFieldConfig, m as UseFormReturn, B as ButtonGroupFormFieldConfig } from './types-BhcLAcZe.cjs';
3
+ export { y as FormFieldType, z as SelectOption, v as generateInitialValues, w as generateValidationSchema, x as getColumnSpanClass } from './types-BhcLAcZe.cjs';
4
4
 
5
5
  /**
6
6
  * @page-speed/forms - Rails API Serializer
@@ -386,12 +386,12 @@ interface PageSpeedFormSubmissionResult {
386
386
  formData: Record<string, any>;
387
387
  responseData: unknown;
388
388
  }
389
- interface PageSpeedFormSubmissionConfig {
390
- /**
391
- * Post-submit behavior.
392
- * @default "showConfirmation"
393
- */
394
- behavior?: FormSubmissionBehavior;
389
+ /**
390
+ * PageSpeed-specific extension of the core FormSubmissionConfig.
391
+ * Inherits behavior, customComponent, and newFormSubmissionAction from the
392
+ * base type and adds integration-layer callbacks and redirect support.
393
+ */
394
+ interface PageSpeedFormSubmissionConfig extends FormSubmissionConfig {
395
395
  /**
396
396
  * Optional callback triggered on successful submission.
397
397
  */
@@ -400,14 +400,6 @@ interface PageSpeedFormSubmissionConfig {
400
400
  * Redirect destination used when behavior is "redirect".
401
401
  */
402
402
  redirectUrl?: string;
403
- /**
404
- * Custom component rendered when behavior is "renderCustomComponent".
405
- */
406
- customComponent?: ReactNode;
407
- /**
408
- * Optional action to allow a fresh submission after success.
409
- */
410
- newFormSubmissionAction?: NewFormSubmissionActionConfig;
411
403
  }
412
404
  interface PageSpeedFormConfig {
413
405
  /**
@@ -465,6 +457,12 @@ interface PageSpeedFormConfig {
465
457
  * Optional post-submission behavior configuration.
466
458
  */
467
459
  submissionConfig?: PageSpeedFormSubmissionConfig;
460
+ /**
461
+ * Optional layout and presentation settings.
462
+ * Provides a typed home for layout props (formLayout, buttonGroupSize, etc.)
463
+ * so consumers don't need an `as any` cast when passing them alongside API config.
464
+ */
465
+ formLayoutSettings?: FormLayoutSettings;
468
466
  }
469
467
  declare class PageSpeedFormSubmissionError extends Error {
470
468
  formErrors?: FormErrors;
@@ -477,116 +475,6 @@ declare class PageSpeedFormSubmissionError extends Error {
477
475
  declare function isValidEmail(value: string): boolean;
478
476
  declare function submitPageSpeedForm(values: Record<string, any>, config?: PageSpeedFormConfig): Promise<unknown>;
479
477
 
480
- /**
481
- * Dynamic form field schema types and helpers.
482
- *
483
- * These utilities are intentionally exposed from the integration layer so
484
- * block/rendering libraries can share one field schema contract.
485
- */
486
- type FormFieldType = "text" | "email" | "search" | "password" | "tel" | "textarea" | "select" | "radio" | "checkbox" | "checkbox-group" | "number" | "url" | "date" | "date-picker" | "date-range" | "time" | "file" | "multi-select";
487
- interface SelectOption {
488
- value: string;
489
- label: string;
490
- disabled?: boolean;
491
- description?: string;
492
- }
493
- interface FormFieldConfig {
494
- /**
495
- * Unique field name (used as the key in form values)
496
- */
497
- name: string;
498
- /**
499
- * Field type
500
- */
501
- type: FormFieldType;
502
- /**
503
- * Display label for the field
504
- */
505
- label: string;
506
- /**
507
- * Placeholder text
508
- */
509
- placeholder?: string;
510
- /**
511
- * Whether the field is required
512
- * @default false
513
- */
514
- required?: boolean;
515
- /**
516
- * Column span in grid layout (1-12)
517
- * @default 12 (full width)
518
- */
519
- columnSpan?: number;
520
- /**
521
- * Options for select/radio/checkbox-group fields
522
- */
523
- options?: SelectOption[];
524
- /**
525
- * Number of rows for textarea
526
- * @default 4
527
- */
528
- rows?: number;
529
- /**
530
- * Custom validation function
531
- * Return undefined for valid, or an error message string for invalid
532
- */
533
- validator?: (value: any, allValues: Record<string, any>) => string | undefined;
534
- /**
535
- * Additional CSS classes for the field wrapper
536
- */
537
- className?: string;
538
- /**
539
- * Whether the field is disabled
540
- * @default false
541
- */
542
- disabled?: boolean;
543
- /**
544
- * Accepted file types for file inputs (MIME types or extensions)
545
- * @example ".pdf,.doc,.docx"
546
- * @example "image/*,application/pdf"
547
- */
548
- accept?: string;
549
- /**
550
- * Maximum file size in bytes for file inputs
551
- * @default 5MB (5 * 1024 * 1024)
552
- */
553
- maxSize?: number;
554
- /**
555
- * Maximum number of files for file inputs
556
- * @default 1
557
- */
558
- maxFiles?: number;
559
- /**
560
- * Allow multiple file selection
561
- * @default false
562
- */
563
- multiple?: boolean;
564
- /**
565
- * Description/help text displayed with the field
566
- */
567
- description?: string;
568
- /**
569
- * Layout for radio/checkbox groups
570
- * @default "stacked"
571
- */
572
- layout?: "grid" | "stacked";
573
- }
574
- /**
575
- * Generate initial values object from form field configs.
576
- */
577
- declare function generateInitialValues(fields: FormFieldConfig[]): Record<string, any>;
578
- /**
579
- * Generate validation schema from form field configs.
580
- */
581
- declare function generateValidationSchema(fields: FormFieldConfig[]): Record<string, (value: any, allValues: Record<string, any>) => string | undefined>;
582
- /**
583
- * Get grid column span class for Tailwind.
584
- *
585
- * On small screens the field is always full-width, then from `md` and up the
586
- * configured span is applied.
587
- */
588
- declare function getColumnSpanClass(span?: number): string;
589
-
590
478
  interface FileUploadProgress {
591
479
  [fileName: string]: number;
592
480
  }
@@ -681,4 +569,92 @@ interface DynamicFormFieldProps {
681
569
  */
682
570
  declare function DynamicFormField({ field, className, uploadProgress, onFileUpload, onFileRemove, isUploading, renderLabel, }: DynamicFormFieldProps): React.JSX.Element;
683
571
 
684
- export { type AdaptedComponentProps, type Block, type BlockAdapterOptions, DynamicFormField, type DynamicFormFieldProps, type FileUploadProgress, type FormErrors, type FormFieldConfig, type FormFieldType, type PageSpeedFormConfig, type PageSpeedFormMethod, type PageSpeedFormSubmissionConfig, PageSpeedFormSubmissionError, type PageSpeedFormSubmissionFormat, type PageSpeedFormSubmissionResult, type RailsApiConfig, type RailsErrorResponse, type SelectOption, type SerializedFormData, type UseContactFormOptions, type UseContactFormReturn, type UseFileUploadOptions, type UseFileUploadReturn, createBlockAdapter, createBlockAdapters, deserializeErrors, generateInitialValues, generateValidationSchema, getColumnSpanClass, isValidEmail, serializeForRails, standardInputTransformer, submitPageSpeedForm, useContactForm, useFileUpload };
572
+ interface ButtonGroupFormSetup {
573
+ size?: "xs" | "sm" | "default" | "lg";
574
+ submitLabel?: React.ReactNode;
575
+ submitVariant?: "link" | "default" | "destructive" | "outline" | "secondary" | "ghost";
576
+ submitIconName?: string;
577
+ submitIconComponent?: React.ReactNode;
578
+ }
579
+ interface FormEngineSubmitButtonSetup {
580
+ submitLabel?: React.ReactNode;
581
+ submitVariant?: "link" | "default" | "destructive" | "outline" | "secondary" | "ghost";
582
+ submitIconName?: string;
583
+ submitIconComponent?: React.ReactNode;
584
+ }
585
+ interface FormEngineStyleRules {
586
+ /** ClassName applied to the div wrapping the `<form>` element */
587
+ formContainer?: string;
588
+ /** ClassName applied to the grid div wrapping all field columns (standard layout) */
589
+ fieldsContainer?: string;
590
+ /** Fallback className applied to each field wrapper when the field has no own className */
591
+ fieldClassName?: string;
592
+ /** className forwarded to the `<form>` element itself via FormStyleConfig */
593
+ formClassName?: string;
594
+ /** className forwarded to the success message container via FormStyleConfig */
595
+ successMessageClassName?: string;
596
+ /** className forwarded to the error message container via FormStyleConfig */
597
+ errorMessageClassName?: string;
598
+ }
599
+ interface FormEngineLayoutSettings {
600
+ styleRules?: FormEngineStyleRules;
601
+ formLayout?: "standard" | "button-group";
602
+ /** Settings for button-group layout (only used when formLayout is "button-group") */
603
+ buttonGroupSetup?: ButtonGroupFormSetup;
604
+ /** Settings for the submit button in standard layout */
605
+ submitButtonSetup?: FormEngineSubmitButtonSetup;
606
+ }
607
+ interface FormEngineProps {
608
+ /** API / submission configuration */
609
+ api?: PageSpeedFormConfig;
610
+ /** Form field definitions */
611
+ fields: (FormFieldConfig | ButtonGroupFormFieldConfig)[];
612
+ /** Layout, style, and submit-button settings */
613
+ formLayoutSettings?: FormEngineLayoutSettings;
614
+ /** Success message shown after a successful submission */
615
+ successMessage?: React.ReactNode;
616
+ /** Custom submit handler (called in addition to any api endpoint) */
617
+ onSubmit?: (values: Record<string, any>) => void | Promise<void>;
618
+ /** Called after a successful submission with the server response */
619
+ onSuccess?: (data: unknown) => void;
620
+ /** Called when submission fails */
621
+ onError?: (error: Error) => void;
622
+ /** Navigation handler for internal redirects (return false to fall back to browser navigation) */
623
+ navigate?: (href: string) => boolean | void;
624
+ /** Reset form values after success @default true */
625
+ resetOnSuccess?: boolean;
626
+ /** File upload tokens to merge into the payload */
627
+ uploadTokens?: string[];
628
+ /** Called when files are selected for upload */
629
+ onFileUpload?: (files: File[]) => Promise<void>;
630
+ /** Called when a file is removed */
631
+ onFileRemove?: (file: File, index: number) => void;
632
+ /** Whether a file upload is in progress */
633
+ isUploading?: boolean;
634
+ /** Per-file upload progress map (fileName → 0-100) */
635
+ uploadProgress?: {
636
+ [fileName: string]: number;
637
+ };
638
+ }
639
+ /**
640
+ * FormEngine — declarative form component with built-in API integration.
641
+ *
642
+ * Handles `useContactForm` orchestration internally so callers only need to
643
+ * supply `api`, `fields`, and optional layout/style settings.
644
+ *
645
+ * @example Standard layout
646
+ * ```tsx
647
+ * <FormEngine api={api} fields={fields} formLayoutSettings={{ submitButtonSetup: { submitLabel: "Send" } }} />
648
+ * ```
649
+ *
650
+ * @example Button-group layout
651
+ * ```tsx
652
+ * <FormEngine api={api} fields={[emailField]} formLayoutSettings={{ formLayout: "button-group", buttonGroupSetup: { size: "lg", submitLabel: "Subscribe" } }} />
653
+ * ```
654
+ */
655
+ declare function FormEngine({ api, fields, formLayoutSettings, successMessage, onSubmit, onSuccess, onError, navigate, resetOnSuccess, uploadTokens, onFileUpload, onFileRemove, isUploading, uploadProgress, }: FormEngineProps): React.JSX.Element;
656
+ declare namespace FormEngine {
657
+ var displayName: string;
658
+ }
659
+
660
+ export { type AdaptedComponentProps, type Block, type BlockAdapterOptions, ButtonGroupFormFieldConfig, type ButtonGroupFormSetup, DynamicFormField, type DynamicFormFieldProps, type FileUploadProgress, FormEngine, type FormEngineLayoutSettings, type FormEngineProps, type FormEngineStyleRules, type FormEngineSubmitButtonSetup, type FormErrors, FormFieldConfig, FormLayoutSettings, type PageSpeedFormConfig, type PageSpeedFormMethod, type PageSpeedFormSubmissionConfig, PageSpeedFormSubmissionError, type PageSpeedFormSubmissionFormat, type PageSpeedFormSubmissionResult, type RailsApiConfig, type RailsErrorResponse, type SerializedFormData, type UseContactFormOptions, type UseContactFormReturn, type UseFileUploadOptions, type UseFileUploadReturn, createBlockAdapter, createBlockAdapters, deserializeErrors, isValidEmail, serializeForRails, standardInputTransformer, submitPageSpeedForm, useContactForm, useFileUpload };
@@ -1,6 +1,6 @@
1
1
  import * as React from 'react';
2
- import { ReactNode } from 'react';
3
- import { d as FormSubmissionBehavior, N as NewFormSubmissionActionConfig, m as UseFormReturn } from './types-Fbt73kW_.js';
2
+ import { e as FormSubmissionConfig, t as FormLayoutSettings, u as FormFieldConfig, m as UseFormReturn, B as ButtonGroupFormFieldConfig } from './types-BhcLAcZe.js';
3
+ export { y as FormFieldType, z as SelectOption, v as generateInitialValues, w as generateValidationSchema, x as getColumnSpanClass } from './types-BhcLAcZe.js';
4
4
 
5
5
  /**
6
6
  * @page-speed/forms - Rails API Serializer
@@ -386,12 +386,12 @@ interface PageSpeedFormSubmissionResult {
386
386
  formData: Record<string, any>;
387
387
  responseData: unknown;
388
388
  }
389
- interface PageSpeedFormSubmissionConfig {
390
- /**
391
- * Post-submit behavior.
392
- * @default "showConfirmation"
393
- */
394
- behavior?: FormSubmissionBehavior;
389
+ /**
390
+ * PageSpeed-specific extension of the core FormSubmissionConfig.
391
+ * Inherits behavior, customComponent, and newFormSubmissionAction from the
392
+ * base type and adds integration-layer callbacks and redirect support.
393
+ */
394
+ interface PageSpeedFormSubmissionConfig extends FormSubmissionConfig {
395
395
  /**
396
396
  * Optional callback triggered on successful submission.
397
397
  */
@@ -400,14 +400,6 @@ interface PageSpeedFormSubmissionConfig {
400
400
  * Redirect destination used when behavior is "redirect".
401
401
  */
402
402
  redirectUrl?: string;
403
- /**
404
- * Custom component rendered when behavior is "renderCustomComponent".
405
- */
406
- customComponent?: ReactNode;
407
- /**
408
- * Optional action to allow a fresh submission after success.
409
- */
410
- newFormSubmissionAction?: NewFormSubmissionActionConfig;
411
403
  }
412
404
  interface PageSpeedFormConfig {
413
405
  /**
@@ -465,6 +457,12 @@ interface PageSpeedFormConfig {
465
457
  * Optional post-submission behavior configuration.
466
458
  */
467
459
  submissionConfig?: PageSpeedFormSubmissionConfig;
460
+ /**
461
+ * Optional layout and presentation settings.
462
+ * Provides a typed home for layout props (formLayout, buttonGroupSize, etc.)
463
+ * so consumers don't need an `as any` cast when passing them alongside API config.
464
+ */
465
+ formLayoutSettings?: FormLayoutSettings;
468
466
  }
469
467
  declare class PageSpeedFormSubmissionError extends Error {
470
468
  formErrors?: FormErrors;
@@ -477,116 +475,6 @@ declare class PageSpeedFormSubmissionError extends Error {
477
475
  declare function isValidEmail(value: string): boolean;
478
476
  declare function submitPageSpeedForm(values: Record<string, any>, config?: PageSpeedFormConfig): Promise<unknown>;
479
477
 
480
- /**
481
- * Dynamic form field schema types and helpers.
482
- *
483
- * These utilities are intentionally exposed from the integration layer so
484
- * block/rendering libraries can share one field schema contract.
485
- */
486
- type FormFieldType = "text" | "email" | "search" | "password" | "tel" | "textarea" | "select" | "radio" | "checkbox" | "checkbox-group" | "number" | "url" | "date" | "date-picker" | "date-range" | "time" | "file" | "multi-select";
487
- interface SelectOption {
488
- value: string;
489
- label: string;
490
- disabled?: boolean;
491
- description?: string;
492
- }
493
- interface FormFieldConfig {
494
- /**
495
- * Unique field name (used as the key in form values)
496
- */
497
- name: string;
498
- /**
499
- * Field type
500
- */
501
- type: FormFieldType;
502
- /**
503
- * Display label for the field
504
- */
505
- label: string;
506
- /**
507
- * Placeholder text
508
- */
509
- placeholder?: string;
510
- /**
511
- * Whether the field is required
512
- * @default false
513
- */
514
- required?: boolean;
515
- /**
516
- * Column span in grid layout (1-12)
517
- * @default 12 (full width)
518
- */
519
- columnSpan?: number;
520
- /**
521
- * Options for select/radio/checkbox-group fields
522
- */
523
- options?: SelectOption[];
524
- /**
525
- * Number of rows for textarea
526
- * @default 4
527
- */
528
- rows?: number;
529
- /**
530
- * Custom validation function
531
- * Return undefined for valid, or an error message string for invalid
532
- */
533
- validator?: (value: any, allValues: Record<string, any>) => string | undefined;
534
- /**
535
- * Additional CSS classes for the field wrapper
536
- */
537
- className?: string;
538
- /**
539
- * Whether the field is disabled
540
- * @default false
541
- */
542
- disabled?: boolean;
543
- /**
544
- * Accepted file types for file inputs (MIME types or extensions)
545
- * @example ".pdf,.doc,.docx"
546
- * @example "image/*,application/pdf"
547
- */
548
- accept?: string;
549
- /**
550
- * Maximum file size in bytes for file inputs
551
- * @default 5MB (5 * 1024 * 1024)
552
- */
553
- maxSize?: number;
554
- /**
555
- * Maximum number of files for file inputs
556
- * @default 1
557
- */
558
- maxFiles?: number;
559
- /**
560
- * Allow multiple file selection
561
- * @default false
562
- */
563
- multiple?: boolean;
564
- /**
565
- * Description/help text displayed with the field
566
- */
567
- description?: string;
568
- /**
569
- * Layout for radio/checkbox groups
570
- * @default "stacked"
571
- */
572
- layout?: "grid" | "stacked";
573
- }
574
- /**
575
- * Generate initial values object from form field configs.
576
- */
577
- declare function generateInitialValues(fields: FormFieldConfig[]): Record<string, any>;
578
- /**
579
- * Generate validation schema from form field configs.
580
- */
581
- declare function generateValidationSchema(fields: FormFieldConfig[]): Record<string, (value: any, allValues: Record<string, any>) => string | undefined>;
582
- /**
583
- * Get grid column span class for Tailwind.
584
- *
585
- * On small screens the field is always full-width, then from `md` and up the
586
- * configured span is applied.
587
- */
588
- declare function getColumnSpanClass(span?: number): string;
589
-
590
478
  interface FileUploadProgress {
591
479
  [fileName: string]: number;
592
480
  }
@@ -681,4 +569,92 @@ interface DynamicFormFieldProps {
681
569
  */
682
570
  declare function DynamicFormField({ field, className, uploadProgress, onFileUpload, onFileRemove, isUploading, renderLabel, }: DynamicFormFieldProps): React.JSX.Element;
683
571
 
684
- export { type AdaptedComponentProps, type Block, type BlockAdapterOptions, DynamicFormField, type DynamicFormFieldProps, type FileUploadProgress, type FormErrors, type FormFieldConfig, type FormFieldType, type PageSpeedFormConfig, type PageSpeedFormMethod, type PageSpeedFormSubmissionConfig, PageSpeedFormSubmissionError, type PageSpeedFormSubmissionFormat, type PageSpeedFormSubmissionResult, type RailsApiConfig, type RailsErrorResponse, type SelectOption, type SerializedFormData, type UseContactFormOptions, type UseContactFormReturn, type UseFileUploadOptions, type UseFileUploadReturn, createBlockAdapter, createBlockAdapters, deserializeErrors, generateInitialValues, generateValidationSchema, getColumnSpanClass, isValidEmail, serializeForRails, standardInputTransformer, submitPageSpeedForm, useContactForm, useFileUpload };
572
+ interface ButtonGroupFormSetup {
573
+ size?: "xs" | "sm" | "default" | "lg";
574
+ submitLabel?: React.ReactNode;
575
+ submitVariant?: "link" | "default" | "destructive" | "outline" | "secondary" | "ghost";
576
+ submitIconName?: string;
577
+ submitIconComponent?: React.ReactNode;
578
+ }
579
+ interface FormEngineSubmitButtonSetup {
580
+ submitLabel?: React.ReactNode;
581
+ submitVariant?: "link" | "default" | "destructive" | "outline" | "secondary" | "ghost";
582
+ submitIconName?: string;
583
+ submitIconComponent?: React.ReactNode;
584
+ }
585
+ interface FormEngineStyleRules {
586
+ /** ClassName applied to the div wrapping the `<form>` element */
587
+ formContainer?: string;
588
+ /** ClassName applied to the grid div wrapping all field columns (standard layout) */
589
+ fieldsContainer?: string;
590
+ /** Fallback className applied to each field wrapper when the field has no own className */
591
+ fieldClassName?: string;
592
+ /** className forwarded to the `<form>` element itself via FormStyleConfig */
593
+ formClassName?: string;
594
+ /** className forwarded to the success message container via FormStyleConfig */
595
+ successMessageClassName?: string;
596
+ /** className forwarded to the error message container via FormStyleConfig */
597
+ errorMessageClassName?: string;
598
+ }
599
+ interface FormEngineLayoutSettings {
600
+ styleRules?: FormEngineStyleRules;
601
+ formLayout?: "standard" | "button-group";
602
+ /** Settings for button-group layout (only used when formLayout is "button-group") */
603
+ buttonGroupSetup?: ButtonGroupFormSetup;
604
+ /** Settings for the submit button in standard layout */
605
+ submitButtonSetup?: FormEngineSubmitButtonSetup;
606
+ }
607
+ interface FormEngineProps {
608
+ /** API / submission configuration */
609
+ api?: PageSpeedFormConfig;
610
+ /** Form field definitions */
611
+ fields: (FormFieldConfig | ButtonGroupFormFieldConfig)[];
612
+ /** Layout, style, and submit-button settings */
613
+ formLayoutSettings?: FormEngineLayoutSettings;
614
+ /** Success message shown after a successful submission */
615
+ successMessage?: React.ReactNode;
616
+ /** Custom submit handler (called in addition to any api endpoint) */
617
+ onSubmit?: (values: Record<string, any>) => void | Promise<void>;
618
+ /** Called after a successful submission with the server response */
619
+ onSuccess?: (data: unknown) => void;
620
+ /** Called when submission fails */
621
+ onError?: (error: Error) => void;
622
+ /** Navigation handler for internal redirects (return false to fall back to browser navigation) */
623
+ navigate?: (href: string) => boolean | void;
624
+ /** Reset form values after success @default true */
625
+ resetOnSuccess?: boolean;
626
+ /** File upload tokens to merge into the payload */
627
+ uploadTokens?: string[];
628
+ /** Called when files are selected for upload */
629
+ onFileUpload?: (files: File[]) => Promise<void>;
630
+ /** Called when a file is removed */
631
+ onFileRemove?: (file: File, index: number) => void;
632
+ /** Whether a file upload is in progress */
633
+ isUploading?: boolean;
634
+ /** Per-file upload progress map (fileName → 0-100) */
635
+ uploadProgress?: {
636
+ [fileName: string]: number;
637
+ };
638
+ }
639
+ /**
640
+ * FormEngine — declarative form component with built-in API integration.
641
+ *
642
+ * Handles `useContactForm` orchestration internally so callers only need to
643
+ * supply `api`, `fields`, and optional layout/style settings.
644
+ *
645
+ * @example Standard layout
646
+ * ```tsx
647
+ * <FormEngine api={api} fields={fields} formLayoutSettings={{ submitButtonSetup: { submitLabel: "Send" } }} />
648
+ * ```
649
+ *
650
+ * @example Button-group layout
651
+ * ```tsx
652
+ * <FormEngine api={api} fields={[emailField]} formLayoutSettings={{ formLayout: "button-group", buttonGroupSetup: { size: "lg", submitLabel: "Subscribe" } }} />
653
+ * ```
654
+ */
655
+ declare function FormEngine({ api, fields, formLayoutSettings, successMessage, onSubmit, onSuccess, onError, navigate, resetOnSuccess, uploadTokens, onFileUpload, onFileRemove, isUploading, uploadProgress, }: FormEngineProps): React.JSX.Element;
656
+ declare namespace FormEngine {
657
+ var displayName: string;
658
+ }
659
+
660
+ export { type AdaptedComponentProps, type Block, type BlockAdapterOptions, ButtonGroupFormFieldConfig, type ButtonGroupFormSetup, DynamicFormField, type DynamicFormFieldProps, type FileUploadProgress, FormEngine, type FormEngineLayoutSettings, type FormEngineProps, type FormEngineStyleRules, type FormEngineSubmitButtonSetup, type FormErrors, FormFieldConfig, FormLayoutSettings, type PageSpeedFormConfig, type PageSpeedFormMethod, type PageSpeedFormSubmissionConfig, PageSpeedFormSubmissionError, type PageSpeedFormSubmissionFormat, type PageSpeedFormSubmissionResult, type RailsApiConfig, type RailsErrorResponse, type SerializedFormData, type UseContactFormOptions, type UseContactFormReturn, type UseFileUploadOptions, type UseFileUploadReturn, createBlockAdapter, createBlockAdapters, deserializeErrors, isValidEmail, serializeForRails, standardInputTransformer, submitPageSpeedForm, useContactForm, useFileUpload };
@@ -1,6 +1,6 @@
1
- import { useForm, Field } from './chunk-MJYEXJ3U.js';
2
- import { TextArea, Select, MultiSelect, Radio, Checkbox, CheckboxGroup, DatePicker, DateRangePicker, TimePicker, FileInput } from './chunk-4ROWNTY6.js';
3
- import { TextInput } from './chunk-455PI4LV.js';
1
+ import { useForm, Field, Form } from './chunk-A7MVZ757.js';
2
+ import { TextArea, Select, MultiSelect, Radio, Checkbox, CheckboxGroup, DatePicker, DateRangePicker, TimePicker, FileInput } from './chunk-ML6FGUYS.js';
3
+ import { TextInput, cn, Button } from './chunk-J37BGNM6.js';
4
4
  import * as React2 from 'react';
5
5
  import { useState, useCallback, useMemo } from 'react';
6
6
 
@@ -783,7 +783,104 @@ function DynamicFormField({
783
783
  ))
784
784
  );
785
785
  }
786
+ function FormEngine({
787
+ api,
788
+ fields,
789
+ formLayoutSettings,
790
+ successMessage,
791
+ onSubmit,
792
+ onSuccess,
793
+ onError,
794
+ navigate,
795
+ resetOnSuccess,
796
+ uploadTokens,
797
+ onFileUpload,
798
+ onFileRemove,
799
+ isUploading,
800
+ uploadProgress
801
+ }) {
802
+ const {
803
+ styleRules,
804
+ formLayout = "standard",
805
+ buttonGroupSetup,
806
+ submitButtonSetup
807
+ } = formLayoutSettings ?? {};
808
+ const isButtonGroup = formLayout === "button-group";
809
+ const normalizedFields = React2.useMemo(
810
+ () => fields.map((f) => ({ ...f, label: f.label ?? f.name })),
811
+ [fields]
812
+ );
813
+ const { form, submissionError, formMethod, resetSubmissionState } = useContactForm({
814
+ formFields: normalizedFields,
815
+ formConfig: api,
816
+ onSubmit,
817
+ onSuccess,
818
+ onError,
819
+ navigate,
820
+ resetOnSuccess,
821
+ uploadTokens
822
+ });
823
+ const legacyFormConfig = React2.useMemo(() => {
824
+ if (isButtonGroup) {
825
+ return {
826
+ formLayout: "button-group",
827
+ buttonGroupSize: buttonGroupSetup?.size,
828
+ submitLabel: buttonGroupSetup?.submitLabel,
829
+ submitVariant: buttonGroupSetup?.submitVariant,
830
+ submitIconName: buttonGroupSetup?.submitIconName,
831
+ submitIconComponent: buttonGroupSetup?.submitIconComponent,
832
+ endpoint: api?.endpoint,
833
+ submissionConfig: api?.submissionConfig
834
+ };
835
+ }
836
+ return {
837
+ formLayout: "standard",
838
+ endpoint: api?.endpoint,
839
+ submissionConfig: api?.submissionConfig
840
+ };
841
+ }, [isButtonGroup, buttonGroupSetup, api]);
842
+ return /* @__PURE__ */ React2.createElement("div", { className: styleRules?.formContainer }, /* @__PURE__ */ React2.createElement(
843
+ Form,
844
+ {
845
+ form,
846
+ fields: isButtonGroup ? fields : void 0,
847
+ formConfig: legacyFormConfig,
848
+ method: formMethod,
849
+ notificationConfig: {
850
+ submissionError: submissionError ?? void 0,
851
+ successMessage
852
+ },
853
+ styleConfig: {
854
+ formClassName: styleRules?.formClassName,
855
+ successMessageClassName: styleRules?.successMessageClassName,
856
+ errorMessageClassName: styleRules?.errorMessageClassName
857
+ },
858
+ onNewSubmission: resetSubmissionState
859
+ },
860
+ !isButtonGroup && /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement("div", { className: cn("grid grid-cols-12 gap-6", styleRules?.fieldsContainer) }, normalizedFields.map((field) => /* @__PURE__ */ React2.createElement("div", { key: field.name, className: cn(getColumnSpanClass(field.columnSpan ?? 12), "min-w-0") }, /* @__PURE__ */ React2.createElement(
861
+ DynamicFormField,
862
+ {
863
+ field,
864
+ className: field.className ?? styleRules?.fieldClassName,
865
+ uploadProgress,
866
+ onFileUpload,
867
+ onFileRemove,
868
+ isUploading
869
+ }
870
+ )))), /* @__PURE__ */ React2.createElement(
871
+ Button,
872
+ {
873
+ type: "submit",
874
+ variant: submitButtonSetup?.submitVariant ?? "default",
875
+ disabled: form.isSubmitting,
876
+ className: "mt-6 w-full"
877
+ },
878
+ submitButtonSetup?.submitLabel ?? "Submit"
879
+ ))
880
+ ));
881
+ }
882
+ FormEngine.displayName = "FormEngine";
786
883
 
787
- export { DynamicFormField, PageSpeedFormSubmissionError, createBlockAdapter, createBlockAdapters, deserializeErrors, generateInitialValues, generateValidationSchema, getColumnSpanClass, isValidEmail, serializeForRails, standardInputTransformer, submitPageSpeedForm, useContactForm, useFileUpload };
884
+ export { DynamicFormField, FormEngine, PageSpeedFormSubmissionError, createBlockAdapter, createBlockAdapters, deserializeErrors, generateInitialValues, generateValidationSchema, getColumnSpanClass, isValidEmail, serializeForRails, standardInputTransformer, submitPageSpeedForm, useContactForm, useFileUpload };
788
885
  //# sourceMappingURL=integration.js.map
789
886
  //# sourceMappingURL=integration.js.map