@page-speed/forms 0.6.3 → 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 (45) hide show
  1. package/dist/{FormContext-Db0L3Kwv.d.ts → FormContext-C6kWSQuv.d.ts} +1 -1
  2. package/dist/{FormContext-kKZxeb7G.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-UBDA7CS5.js +3 -0
  8. package/dist/chunk-UBDA7CS5.js.map +1 -0
  9. package/dist/chunk-V7JSGFCI.cjs +4 -0
  10. package/dist/chunk-V7JSGFCI.cjs.map +1 -0
  11. package/dist/core.cjs +13 -13
  12. package/dist/core.d.cts +10 -8
  13. package/dist/core.d.ts +10 -8
  14. package/dist/core.js +2 -2
  15. package/dist/index.cjs +12 -12
  16. package/dist/index.d.cts +2 -2
  17. package/dist/index.d.ts +2 -2
  18. package/dist/index.js +2 -2
  19. package/dist/inputs.d.cts +1 -1
  20. package/dist/inputs.d.ts +1 -1
  21. package/dist/integration.cjs +101 -3
  22. package/dist/integration.cjs.map +1 -1
  23. package/dist/integration.d.cts +103 -18
  24. package/dist/integration.d.ts +103 -18
  25. package/dist/integration.js +100 -3
  26. package/dist/integration.js.map +1 -1
  27. package/dist/{types-BPxsUGm_.d.ts → types-BhcLAcZe.d.cts} +31 -22
  28. package/dist/{types-BPxsUGm_.d.cts → types-BhcLAcZe.d.ts} +31 -22
  29. package/dist/validation-rules.d.cts +1 -1
  30. package/dist/validation-rules.d.ts +1 -1
  31. package/dist/validation-utils.d.cts +1 -1
  32. package/dist/validation-utils.d.ts +1 -1
  33. package/dist/validation-valibot.d.cts +1 -1
  34. package/dist/validation-valibot.d.ts +1 -1
  35. package/dist/validation.d.cts +1 -1
  36. package/dist/validation.d.ts +1 -1
  37. package/package.json +1 -1
  38. package/dist/chunk-3ED2FKXF.cjs +0 -350
  39. package/dist/chunk-3ED2FKXF.cjs.map +0 -1
  40. package/dist/chunk-H3YJRLVO.js +0 -326
  41. package/dist/chunk-H3YJRLVO.js.map +0 -1
  42. package/dist/chunk-SNSK3TMG.js +0 -373
  43. package/dist/chunk-SNSK3TMG.js.map +0 -1
  44. package/dist/chunk-V545YJFP.cjs +0 -397
  45. package/dist/chunk-V545YJFP.cjs.map +0 -1
@@ -1,7 +1,6 @@
1
1
  import * as React from 'react';
2
- import { ReactNode } from 'react';
3
- import { d as FormSubmissionBehavior, N as NewFormSubmissionActionConfig, t as FormFieldConfig, m as UseFormReturn } from './types-BPxsUGm_.js';
4
- export { x as FormFieldType, y as SelectOption, u as generateInitialValues, v as generateValidationSchema, w as getColumnSpanClass } from './types-BPxsUGm_.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';
5
4
 
6
5
  /**
7
6
  * @page-speed/forms - Rails API Serializer
@@ -387,12 +386,12 @@ interface PageSpeedFormSubmissionResult {
387
386
  formData: Record<string, any>;
388
387
  responseData: unknown;
389
388
  }
390
- interface PageSpeedFormSubmissionConfig {
391
- /**
392
- * Post-submit behavior.
393
- * @default "showConfirmation"
394
- */
395
- 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 {
396
395
  /**
397
396
  * Optional callback triggered on successful submission.
398
397
  */
@@ -401,14 +400,6 @@ interface PageSpeedFormSubmissionConfig {
401
400
  * Redirect destination used when behavior is "redirect".
402
401
  */
403
402
  redirectUrl?: string;
404
- /**
405
- * Custom component rendered when behavior is "renderCustomComponent".
406
- */
407
- customComponent?: ReactNode;
408
- /**
409
- * Optional action to allow a fresh submission after success.
410
- */
411
- newFormSubmissionAction?: NewFormSubmissionActionConfig;
412
403
  }
413
404
  interface PageSpeedFormConfig {
414
405
  /**
@@ -466,6 +457,12 @@ interface PageSpeedFormConfig {
466
457
  * Optional post-submission behavior configuration.
467
458
  */
468
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;
469
466
  }
470
467
  declare class PageSpeedFormSubmissionError extends Error {
471
468
  formErrors?: FormErrors;
@@ -572,4 +569,92 @@ interface DynamicFormFieldProps {
572
569
  */
573
570
  declare function DynamicFormField({ field, className, uploadProgress, onFileUpload, onFileRemove, isUploading, renderLabel, }: DynamicFormFieldProps): React.JSX.Element;
574
571
 
575
- export { type AdaptedComponentProps, type Block, type BlockAdapterOptions, DynamicFormField, type DynamicFormFieldProps, type FileUploadProgress, type FormErrors, FormFieldConfig, 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 };
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-SNSK3TMG.js';
1
+ import { useForm, Field, Form } from './chunk-A7MVZ757.js';
2
2
  import { TextArea, Select, MultiSelect, Radio, Checkbox, CheckboxGroup, DatePicker, DateRangePicker, TimePicker, FileInput } from './chunk-ML6FGUYS.js';
3
- import { TextInput } from './chunk-J37BGNM6.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