@page-speed/forms 0.6.1 → 0.6.2

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,4 @@
1
- import { b as FormValues, U as UseFormOptions, m as UseFormReturn, p as UseFieldOptions, q as UseFieldReturn, r as FormProps, s as FieldProps } from './types-RnnhRtD2.cjs';
1
+ import { b as FormValues, U as UseFormOptions, m as UseFormReturn, p as UseFieldOptions, q as UseFieldReturn, r as FormProps, s as FieldProps } from './types-Fbt73kW_.cjs';
2
2
  import * as React from 'react';
3
3
 
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { b as FormValues, U as UseFormOptions, m as UseFormReturn, p as UseFieldOptions, q as UseFieldReturn, r as FormProps, s as FieldProps } from './types-RnnhRtD2.js';
1
+ import { b as FormValues, U as UseFormOptions, m as UseFormReturn, p as UseFieldOptions, q as UseFieldReturn, r as FormProps, s as FieldProps } from './types-Fbt73kW_.js';
2
2
  import * as React from 'react';
3
3
 
4
4
  /**
@@ -124,6 +124,7 @@ function ButtonGroupForm({
124
124
  size = "default",
125
125
  isSubmitting = false,
126
126
  submitIconName,
127
+ submitIconComponent,
127
128
  className,
128
129
  labelClassName
129
130
  }) {
@@ -131,11 +132,22 @@ function ButtonGroupForm({
131
132
  const hasValue = String(inputProps.value ?? "").trim().length > 0;
132
133
  const hasError = !!inputProps.error;
133
134
  const buttonSize = React4__namespace.useMemo(() => {
134
- if (submitIconName) {
135
+ if (submitIconName || submitIconComponent) {
135
136
  return size === "default" ? "icon" : `icon-${size}`;
136
137
  }
137
138
  return size;
138
- }, [submitIconName, size]);
139
+ }, [submitIconName, size, submitIconComponent]);
140
+ const labelElement = React4__namespace.useMemo(() => {
141
+ if (submitIconName) {
142
+ return /* @__PURE__ */ React4__namespace.createElement(icon.Icon, { name: submitIconName, apiKey: DEFAULT_ICON_API_KEY });
143
+ } else if (submitIconComponent) {
144
+ return submitIconComponent;
145
+ } else if (submitLabel) {
146
+ return submitLabel;
147
+ } else {
148
+ return "Submit";
149
+ }
150
+ }, [submitIconComponent, submitIconName, submitLabel]);
139
151
  const inputSizeClasses = {
140
152
  xs: "text-xs px-3",
141
153
  sm: "text-sm px-3",
@@ -165,7 +177,7 @@ function ButtonGroupForm({
165
177
  !hasError && hasValue && "ring-2 ring-ring"
166
178
  )
167
179
  },
168
- submitIconName ? /* @__PURE__ */ React4__namespace.createElement(icon.Icon, { name: submitIconName, apiKey: DEFAULT_ICON_API_KEY }) : submitLabel
180
+ labelElement
169
181
  )));
170
182
  }
171
183
  ButtonGroupForm.displayName = "ButtonGroupForm";
@@ -249,6 +261,7 @@ function Form({
249
261
  submitLabel: formConfig?.submitLabel,
250
262
  submitVariant: formConfig?.submitVariant,
251
263
  submitIconName: formConfig?.submitIconName,
264
+ submitIconComponent: formConfig?.submitIconComponent,
252
265
  size: formConfig?.buttonGroupSize,
253
266
  isSubmitting: form.isSubmitting
254
267
  }
@@ -292,5 +305,5 @@ Form.displayName = "Form";
292
305
  exports.ButtonGroupForm = ButtonGroupForm;
293
306
  exports.Form = Form;
294
307
  exports.FormFeedback = FormFeedback;
295
- //# sourceMappingURL=chunk-F5ZJCJOD.cjs.map
296
- //# sourceMappingURL=chunk-F5ZJCJOD.cjs.map
308
+ //# sourceMappingURL=chunk-RS6AXV5S.cjs.map
309
+ //# sourceMappingURL=chunk-RS6AXV5S.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/form-feedback.tsx","../src/components/ui/button-group.tsx","../src/core/button-group-form.tsx","../src/core/Form.tsx"],"names":["React","cn","cva","React2","React3","Icon","FieldLabel","TextInput","Button","React4","FormContext"],"mappings":"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","file":"chunk-RS6AXV5S.cjs","sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../lib/utils\";\n\nexport interface FormFeedbackProps {\n successMessage?: React.ReactNode;\n submissionError?: React.ReactNode;\n successMessageClassName?: string;\n errorMessageClassName?: string;\n}\n\nfunction renderMessage(\n message: React.ReactNode,\n fallbackClassName: string,\n className?: string,\n) {\n if (typeof message === \"string\") {\n return (\n <p\n className={cn(\n \"text-sm font-medium text-center text-balance\",\n className,\n )}\n >\n {message}\n </p>\n );\n }\n\n return <div className={cn(fallbackClassName, className)}>{message}</div>;\n}\n\nexport function FormFeedback({\n successMessage,\n submissionError,\n successMessageClassName,\n errorMessageClassName,\n}: FormFeedbackProps) {\n if (!successMessage && !submissionError) {\n return null;\n }\n\n return (\n <>\n {successMessage ? (\n <div\n className={cn(\n \"rounded-md border border-primary bg-primary px-4 py-3 shadow-sm\",\n successMessageClassName,\n )}\n role=\"status\"\n aria-live=\"polite\"\n >\n {renderMessage(\n successMessage,\n \"text-primary-foreground\",\n \"text-primary-foreground\",\n )}\n </div>\n ) : null}\n\n {submissionError ? (\n <div\n className={cn(\n \"rounded-md border border-destructive bg-destructive px-4 py-3 shadow-sm\",\n errorMessageClassName,\n )}\n role=\"alert\"\n aria-live=\"assertive\"\n >\n {renderMessage(\n submissionError,\n \"text-destructive-foreground\",\n \"text-destructive-foreground\",\n )}\n </div>\n ) : null}\n </>\n );\n}\n\nFormFeedback.displayName = \"FormFeedback\";\n","import * as React from \"react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\nimport { Slot } from \"radix-ui\"\n\nimport { cn } from \"../../lib/utils\"\nimport { Separator } from \"./separator\"\n\nconst buttonGroupVariants = cva(\n \"flex w-fit items-stretch [&>*]:focus-visible:z-10 [&>*]:focus-visible:relative [&>[data-slot=select-trigger]:not([class*='w-'])]:w-fit [&>input]:flex-1 has-[select[aria-hidden=true]:last-child]:[&>[data-slot=select-trigger]:last-of-type]:rounded-r-md has-[>[data-slot=button-group]]:gap-2\",\n {\n variants: {\n orientation: {\n horizontal:\n \"[&>*:not(:first-child)]:rounded-l-none [&>*:not(:first-child)]:border-l-0 [&>*:not(:last-child)]:rounded-r-none\",\n vertical:\n \"flex-col [&>*:not(:first-child)]:rounded-t-none [&>*:not(:first-child)]:border-t-0 [&>*:not(:last-child)]:rounded-b-none\",\n },\n },\n defaultVariants: {\n orientation: \"horizontal\",\n },\n }\n)\n\nfunction ButtonGroup({\n className,\n orientation,\n ...props\n}: React.ComponentProps<\"div\"> & VariantProps<typeof buttonGroupVariants>) {\n return (\n <div\n role=\"group\"\n data-slot=\"button-group\"\n data-orientation={orientation}\n className={cn(buttonGroupVariants({ orientation }), className)}\n {...props}\n />\n )\n}\n\nfunction ButtonGroupText({\n className,\n asChild = false,\n ...props\n}: React.ComponentProps<\"div\"> & {\n asChild?: boolean\n}) {\n const Comp = asChild ? Slot.Root : \"div\"\n\n return (\n <Comp\n className={cn(\n \"bg-muted flex items-center gap-2 rounded-md border px-4 text-sm font-medium shadow-xs [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction ButtonGroupSeparator({\n className,\n orientation = \"vertical\",\n ...props\n}: React.ComponentProps<typeof Separator>) {\n return (\n <Separator\n data-slot=\"button-group-separator\"\n orientation={orientation}\n className={cn(\n \"bg-input relative !m-0 self-stretch data-[orientation=vertical]:h-auto\",\n className\n )}\n {...props}\n />\n )\n}\n\nexport {\n ButtonGroup,\n ButtonGroupSeparator,\n ButtonGroupText,\n buttonGroupVariants,\n}\n","\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { Button } from \"../components/ui/button\";\nimport { ButtonGroup } from \"../components/ui/button-group\";\nimport { FieldLabel } from \"../components/ui/field\";\nimport { TextInput } from \"../inputs/TextInput\";\nimport type { InputProps } from \"./types\";\nimport { Icon } from \"@page-speed/icon\";\n\nconst DEFAULT_ICON_API_KEY = \"au382bi7fsh96w9h9xlrnat2jglx\";\n\nexport type ButtonGroupFormSize = \"xs\" | \"sm\" | \"default\" | \"lg\";\n\nexport type ButtonGroupFormProps = {\n /**\n * Field name\n */\n name: string;\n /**\n * Optional label above the input\n */\n label?: React.ReactNode;\n /**\n * Placeholder text for the input\n */\n placeholder?: string;\n /**\n * Input props from form field\n */\n inputProps: InputProps<string> & {\n type?: \"text\" | \"email\" | \"password\" | \"url\" | \"tel\" | \"search\";\n };\n /**\n * Submit button label\n */\n submitLabel?: React.ReactNode;\n /**\n * Submit button size\n */\n size?: ButtonGroupFormSize;\n /**\n * Submit button variant\n */\n submitVariant?:\n | \"link\"\n | \"default\"\n | \"destructive\"\n | \"outline\"\n | \"secondary\"\n | \"ghost\"\n | null\n | undefined;\n /**\n * Whether form is submitting\n */\n isSubmitting?: boolean;\n /**\n * Additional className for the container\n */\n className?: string;\n /**\n * Icon name for icon based submit buttons\n */\n submitIconName?: string;\n /**\n * Icon component for icon based submit buttons\n */\n submitIconComponent?: React.ReactNode;\n /**\n * Additional className for the label\n */\n labelClassName?: string;\n};\n\n/**\n * ButtonGroupForm - Inline form layout with input and submit button grouped together\n *\n * Commonly used for newsletter signups and other simple single-field forms.\n * The input and button automatically adjust sizing together.\n *\n * Size mappings:\n * - xs: h-8 text-xs\n * - sm: h-9 text-sm\n * - default: h-10 text-sm\n * - lg: h-12 text-base\n *\n * @example\n * ```tsx\n * <ButtonGroupForm\n * name=\"email\"\n * placeholder=\"Enter your email\"\n * inputProps={form.getFieldProps('email')}\n * submitLabel=\"Subscribe\"\n * size=\"default\"\n * />\n * ```\n */\nexport function ButtonGroupForm({\n name,\n label,\n inputProps,\n submitLabel = \"Submit\",\n submitVariant = \"default\",\n size = \"default\",\n isSubmitting = false,\n submitIconName,\n submitIconComponent,\n className,\n labelClassName,\n}: ButtonGroupFormProps) {\n const inputId = `button-group-input-${name}`;\n\n const hasValue = String(inputProps.value ?? \"\").trim().length > 0;\n const hasError = !!inputProps.error;\n\n const buttonSize:\n | \"xs\"\n | \"sm\"\n | \"default\"\n | \"lg\"\n | \"icon\"\n | \"icon-xs\"\n | \"icon-sm\"\n | \"icon-lg\" = React.useMemo(() => {\n if (submitIconName || submitIconComponent) {\n return size === \"default\" ? \"icon\" : (`icon-${size}` as const);\n }\n return size;\n }, [submitIconName, size, submitIconComponent]);\n\n const labelElement = React.useMemo(() => {\n if (submitIconName) {\n return <Icon name={submitIconName} apiKey={DEFAULT_ICON_API_KEY} />;\n } else if (submitIconComponent) {\n return submitIconComponent;\n } else if (submitLabel) {\n return submitLabel;\n } else {\n return \"Submit\";\n }\n }, [submitIconComponent, submitIconName, submitLabel]);\n\n // Size-specific classes for input to match button heights\n const inputSizeClasses = {\n xs: \"text-xs px-3\",\n sm: \"text-sm px-3\",\n default: \"text-base px-4\",\n lg: \"text-md px-6\",\n };\n\n return (\n <div className={cn(\"space-y-2\", className)}>\n {label && (\n <FieldLabel htmlFor={inputId} className={labelClassName}>\n {label}\n </FieldLabel>\n )}\n <ButtonGroup>\n <TextInput\n {...inputProps}\n id={inputId}\n className={cn(\n inputSizeClasses[size],\n \"border-r-0 rounded-r-none focus-visible:z-10\",\n inputProps.className,\n )}\n />\n <Button\n size={buttonSize}\n type=\"submit\"\n variant={submitVariant}\n disabled={isSubmitting}\n className={cn(\n \"rounded-l-none\",\n !hasError && hasValue && \"ring-2 ring-ring\",\n )}\n >\n {labelElement}\n </Button>\n </ButtonGroup>\n </div>\n );\n}\n\nButtonGroupForm.displayName = \"ButtonGroupForm\";\n","\"use client\";\n\nimport * as React from \"react\";\nimport { FormContext } from \"./FormContext\";\nimport type { FormProps, FormValues } from \"./types\";\nimport { FormFeedback } from \"./form-feedback\";\nimport { Button } from \"../components/ui/button\";\nimport { ButtonGroupForm } from \"./button-group-form\";\nimport type { FormFieldConfig } from \"../integration/form-field-types\";\n\n/**\n * Form - Progressive enhancement form component\n *\n * Provides form context to child components and handles form submission.\n * Supports progressive enhancement with server-side fallback.\n *\n * Features:\n * - Provides FormContext for useField hook\n * - Handles form submission with validation\n * - Progressive enhancement support (works without JavaScript)\n * - Accessible form semantics\n *\n * @example\n * ```tsx\n * const form = useForm({\n * initialValues: { email: '' },\n * onSubmit: async (values) => {\n * await submitForm(values);\n * },\n * });\n *\n * return (\n * <Form form={form} action=\"/api/submit\" method=\"post\">\n * <input {...form.getFieldProps('email')} />\n * <button type=\"submit\">Submit</button>\n * </Form>\n * );\n * ```\n *\n * @see https://opensite.ai/developers/page-speed/forms/form\n */\nexport function Form<T extends FormValues = FormValues>({\n form,\n children,\n fields,\n className,\n action,\n method,\n noValidate = true,\n submissionConfig,\n successMessage,\n submissionError,\n successMessageClassName,\n errorMessageClassName,\n onNewSubmission,\n notificationConfig,\n styleConfig,\n formConfig,\n ...props\n}: FormProps<T> & React.FormHTMLAttributes<HTMLFormElement>) {\n // Wrap handleSubmit to catch any unhandled rejections\n const handleFormSubmit = React.useCallback(\n async (e: React.FormEvent) => {\n try {\n await form.handleSubmit(e);\n } catch {\n // Error is already handled by useForm, just prevent unhandled rejection\n // The form status and errors are already set by useForm's error handling\n }\n },\n [form],\n );\n\n const resolvedClassName = className ?? styleConfig?.formClassName;\n const resolvedAction = action ?? formConfig?.endpoint;\n const resolvedMethod = method ?? formConfig?.method ?? \"post\";\n const resolvedSubmissionConfig =\n submissionConfig ?? formConfig?.submissionConfig;\n const resolvedSuccessMessage =\n successMessage ?? notificationConfig?.successMessage;\n const resolvedSubmissionError =\n submissionError ?? notificationConfig?.submissionError;\n const resolvedSuccessMessageClassName =\n successMessageClassName ?? styleConfig?.successMessageClassName;\n const resolvedErrorMessageClassName =\n errorMessageClassName ?? styleConfig?.errorMessageClassName;\n\n const behavior = resolvedSubmissionConfig?.behavior || \"showConfirmation\";\n\n const shouldManageSubmissionUi =\n resolvedSubmissionConfig !== undefined ||\n resolvedSuccessMessage !== undefined ||\n resolvedSuccessMessageClassName !== undefined ||\n resolvedErrorMessageClassName !== undefined ||\n resolvedSubmissionError != null ||\n onNewSubmission !== undefined;\n\n const hasSubmissionError = Boolean(resolvedSubmissionError);\n\n const isSubmissionSuccessful =\n shouldManageSubmissionUi &&\n form.status === \"success\" &&\n !hasSubmissionError;\n\n const defaultSuccessMessage =\n behavior === \"redirect\"\n ? \"Form submitted successfully. Redirecting...\"\n : \"Thank you. Your form has been submitted successfully.\";\n\n const finalSuccessMessage = resolvedSuccessMessage ?? defaultSuccessMessage;\n\n const shouldRenderCustomComponent =\n isSubmissionSuccessful &&\n behavior === \"renderCustomComponent\" &&\n Boolean(resolvedSubmissionConfig?.customComponent);\n\n const newSubmissionAction = resolvedSubmissionConfig?.newFormSubmissionAction;\n\n const showNewSubmissionAction =\n isSubmissionSuccessful &&\n (typeof newSubmissionAction?.enable === \"boolean\"\n ? newSubmissionAction.enable\n : Boolean(newSubmissionAction?.label));\n\n const newSubmissionLabel =\n newSubmissionAction?.label ?? \"Submit another response\";\n\n const handleNewSubmission = React.useCallback(() => {\n form.resetForm();\n onNewSubmission?.();\n }, [form, onNewSubmission]);\n\n // Check if we should use button-group layout\n const formLayout = formConfig?.formLayout ?? \"standard\";\n const isButtonGroupLayout = formLayout === \"button-group\";\n const hasTextField =\n fields &&\n fields.length === 1 &&\n fields[0] &&\n [\"text\", \"email\", \"password\", \"url\", \"tel\", \"search\"].includes(\n fields[0].type,\n );\n const shouldUseButtonGroup = isButtonGroupLayout && hasTextField;\n\n // Render button-group layout if conditions are met\n const buttonGroupContent = React.useMemo(() => {\n if (!shouldUseButtonGroup || !fields || fields.length === 0) return null;\n\n const field = fields[0] as FormFieldConfig;\n const fieldProps = form.getFieldProps(field.name);\n\n return (\n <ButtonGroupForm\n name={field.name}\n label={field.label}\n inputProps={{\n name: fieldProps.name,\n value: fieldProps.value as string,\n onChange: fieldProps.onChange as (value: string) => void,\n onBlur: fieldProps.onBlur,\n type: field.type as\n | \"text\"\n | \"email\"\n | \"password\"\n | \"url\"\n | \"tel\"\n | \"search\",\n placeholder: field.placeholder,\n required: field.required,\n disabled: field.disabled,\n }}\n submitLabel={formConfig?.submitLabel}\n submitVariant={formConfig?.submitVariant}\n submitIconName={formConfig?.submitIconName}\n submitIconComponent={formConfig?.submitIconComponent}\n size={formConfig?.buttonGroupSize}\n isSubmitting={form.isSubmitting}\n />\n );\n }, [shouldUseButtonGroup, fields, form, formConfig]);\n\n return (\n <FormContext.Provider value={form}>\n <form\n onSubmit={handleFormSubmit}\n action={resolvedAction}\n method={resolvedMethod}\n noValidate={noValidate}\n className={resolvedClassName}\n {...props}\n >\n {isSubmissionSuccessful ? (\n <div className=\"space-y-4\">\n {shouldRenderCustomComponent ? (\n resolvedSubmissionConfig?.customComponent\n ) : (\n <FormFeedback\n successMessage={finalSuccessMessage}\n successMessageClassName={resolvedSuccessMessageClassName}\n />\n )}\n\n {showNewSubmissionAction ? (\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={handleNewSubmission}\n >\n {newSubmissionLabel}\n </Button>\n ) : null}\n </div>\n ) : (\n <>\n {shouldUseButtonGroup ? buttonGroupContent : children}\n {resolvedSubmissionError ? (\n <div className=\"mt-4\">\n <FormFeedback\n submissionError={resolvedSubmissionError}\n errorMessageClassName={resolvedErrorMessageClassName}\n />\n </div>\n ) : null}\n </>\n )}\n </form>\n </FormContext.Provider>\n );\n}\n\nForm.displayName = \"Form\";\n"]}
@@ -102,6 +102,7 @@ function ButtonGroupForm({
102
102
  size = "default",
103
103
  isSubmitting = false,
104
104
  submitIconName,
105
+ submitIconComponent,
105
106
  className,
106
107
  labelClassName
107
108
  }) {
@@ -109,11 +110,22 @@ function ButtonGroupForm({
109
110
  const hasValue = String(inputProps.value ?? "").trim().length > 0;
110
111
  const hasError = !!inputProps.error;
111
112
  const buttonSize = React4.useMemo(() => {
112
- if (submitIconName) {
113
+ if (submitIconName || submitIconComponent) {
113
114
  return size === "default" ? "icon" : `icon-${size}`;
114
115
  }
115
116
  return size;
116
- }, [submitIconName, size]);
117
+ }, [submitIconName, size, submitIconComponent]);
118
+ const labelElement = React4.useMemo(() => {
119
+ if (submitIconName) {
120
+ return /* @__PURE__ */ React4.createElement(Icon, { name: submitIconName, apiKey: DEFAULT_ICON_API_KEY });
121
+ } else if (submitIconComponent) {
122
+ return submitIconComponent;
123
+ } else if (submitLabel) {
124
+ return submitLabel;
125
+ } else {
126
+ return "Submit";
127
+ }
128
+ }, [submitIconComponent, submitIconName, submitLabel]);
117
129
  const inputSizeClasses = {
118
130
  xs: "text-xs px-3",
119
131
  sm: "text-sm px-3",
@@ -143,7 +155,7 @@ function ButtonGroupForm({
143
155
  !hasError && hasValue && "ring-2 ring-ring"
144
156
  )
145
157
  },
146
- submitIconName ? /* @__PURE__ */ React4.createElement(Icon, { name: submitIconName, apiKey: DEFAULT_ICON_API_KEY }) : submitLabel
158
+ labelElement
147
159
  )));
148
160
  }
149
161
  ButtonGroupForm.displayName = "ButtonGroupForm";
@@ -227,6 +239,7 @@ function Form({
227
239
  submitLabel: formConfig?.submitLabel,
228
240
  submitVariant: formConfig?.submitVariant,
229
241
  submitIconName: formConfig?.submitIconName,
242
+ submitIconComponent: formConfig?.submitIconComponent,
230
243
  size: formConfig?.buttonGroupSize,
231
244
  isSubmitting: form.isSubmitting
232
245
  }
@@ -268,5 +281,5 @@ function Form({
268
281
  Form.displayName = "Form";
269
282
 
270
283
  export { ButtonGroupForm, Form, FormFeedback };
271
- //# sourceMappingURL=chunk-7ZX2EUOG.js.map
272
- //# sourceMappingURL=chunk-7ZX2EUOG.js.map
284
+ //# sourceMappingURL=chunk-ZEAH6AKP.js.map
285
+ //# sourceMappingURL=chunk-ZEAH6AKP.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/form-feedback.tsx","../src/components/ui/button-group.tsx","../src/core/button-group-form.tsx","../src/core/Form.tsx"],"names":["React","React2","React3"],"mappings":"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","file":"chunk-ZEAH6AKP.js","sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../lib/utils\";\n\nexport interface FormFeedbackProps {\n successMessage?: React.ReactNode;\n submissionError?: React.ReactNode;\n successMessageClassName?: string;\n errorMessageClassName?: string;\n}\n\nfunction renderMessage(\n message: React.ReactNode,\n fallbackClassName: string,\n className?: string,\n) {\n if (typeof message === \"string\") {\n return (\n <p\n className={cn(\n \"text-sm font-medium text-center text-balance\",\n className,\n )}\n >\n {message}\n </p>\n );\n }\n\n return <div className={cn(fallbackClassName, className)}>{message}</div>;\n}\n\nexport function FormFeedback({\n successMessage,\n submissionError,\n successMessageClassName,\n errorMessageClassName,\n}: FormFeedbackProps) {\n if (!successMessage && !submissionError) {\n return null;\n }\n\n return (\n <>\n {successMessage ? (\n <div\n className={cn(\n \"rounded-md border border-primary bg-primary px-4 py-3 shadow-sm\",\n successMessageClassName,\n )}\n role=\"status\"\n aria-live=\"polite\"\n >\n {renderMessage(\n successMessage,\n \"text-primary-foreground\",\n \"text-primary-foreground\",\n )}\n </div>\n ) : null}\n\n {submissionError ? (\n <div\n className={cn(\n \"rounded-md border border-destructive bg-destructive px-4 py-3 shadow-sm\",\n errorMessageClassName,\n )}\n role=\"alert\"\n aria-live=\"assertive\"\n >\n {renderMessage(\n submissionError,\n \"text-destructive-foreground\",\n \"text-destructive-foreground\",\n )}\n </div>\n ) : null}\n </>\n );\n}\n\nFormFeedback.displayName = \"FormFeedback\";\n","import * as React from \"react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\nimport { Slot } from \"radix-ui\"\n\nimport { cn } from \"../../lib/utils\"\nimport { Separator } from \"./separator\"\n\nconst buttonGroupVariants = cva(\n \"flex w-fit items-stretch [&>*]:focus-visible:z-10 [&>*]:focus-visible:relative [&>[data-slot=select-trigger]:not([class*='w-'])]:w-fit [&>input]:flex-1 has-[select[aria-hidden=true]:last-child]:[&>[data-slot=select-trigger]:last-of-type]:rounded-r-md has-[>[data-slot=button-group]]:gap-2\",\n {\n variants: {\n orientation: {\n horizontal:\n \"[&>*:not(:first-child)]:rounded-l-none [&>*:not(:first-child)]:border-l-0 [&>*:not(:last-child)]:rounded-r-none\",\n vertical:\n \"flex-col [&>*:not(:first-child)]:rounded-t-none [&>*:not(:first-child)]:border-t-0 [&>*:not(:last-child)]:rounded-b-none\",\n },\n },\n defaultVariants: {\n orientation: \"horizontal\",\n },\n }\n)\n\nfunction ButtonGroup({\n className,\n orientation,\n ...props\n}: React.ComponentProps<\"div\"> & VariantProps<typeof buttonGroupVariants>) {\n return (\n <div\n role=\"group\"\n data-slot=\"button-group\"\n data-orientation={orientation}\n className={cn(buttonGroupVariants({ orientation }), className)}\n {...props}\n />\n )\n}\n\nfunction ButtonGroupText({\n className,\n asChild = false,\n ...props\n}: React.ComponentProps<\"div\"> & {\n asChild?: boolean\n}) {\n const Comp = asChild ? Slot.Root : \"div\"\n\n return (\n <Comp\n className={cn(\n \"bg-muted flex items-center gap-2 rounded-md border px-4 text-sm font-medium shadow-xs [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction ButtonGroupSeparator({\n className,\n orientation = \"vertical\",\n ...props\n}: React.ComponentProps<typeof Separator>) {\n return (\n <Separator\n data-slot=\"button-group-separator\"\n orientation={orientation}\n className={cn(\n \"bg-input relative !m-0 self-stretch data-[orientation=vertical]:h-auto\",\n className\n )}\n {...props}\n />\n )\n}\n\nexport {\n ButtonGroup,\n ButtonGroupSeparator,\n ButtonGroupText,\n buttonGroupVariants,\n}\n","\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { Button } from \"../components/ui/button\";\nimport { ButtonGroup } from \"../components/ui/button-group\";\nimport { FieldLabel } from \"../components/ui/field\";\nimport { TextInput } from \"../inputs/TextInput\";\nimport type { InputProps } from \"./types\";\nimport { Icon } from \"@page-speed/icon\";\n\nconst DEFAULT_ICON_API_KEY = \"au382bi7fsh96w9h9xlrnat2jglx\";\n\nexport type ButtonGroupFormSize = \"xs\" | \"sm\" | \"default\" | \"lg\";\n\nexport type ButtonGroupFormProps = {\n /**\n * Field name\n */\n name: string;\n /**\n * Optional label above the input\n */\n label?: React.ReactNode;\n /**\n * Placeholder text for the input\n */\n placeholder?: string;\n /**\n * Input props from form field\n */\n inputProps: InputProps<string> & {\n type?: \"text\" | \"email\" | \"password\" | \"url\" | \"tel\" | \"search\";\n };\n /**\n * Submit button label\n */\n submitLabel?: React.ReactNode;\n /**\n * Submit button size\n */\n size?: ButtonGroupFormSize;\n /**\n * Submit button variant\n */\n submitVariant?:\n | \"link\"\n | \"default\"\n | \"destructive\"\n | \"outline\"\n | \"secondary\"\n | \"ghost\"\n | null\n | undefined;\n /**\n * Whether form is submitting\n */\n isSubmitting?: boolean;\n /**\n * Additional className for the container\n */\n className?: string;\n /**\n * Icon name for icon based submit buttons\n */\n submitIconName?: string;\n /**\n * Icon component for icon based submit buttons\n */\n submitIconComponent?: React.ReactNode;\n /**\n * Additional className for the label\n */\n labelClassName?: string;\n};\n\n/**\n * ButtonGroupForm - Inline form layout with input and submit button grouped together\n *\n * Commonly used for newsletter signups and other simple single-field forms.\n * The input and button automatically adjust sizing together.\n *\n * Size mappings:\n * - xs: h-8 text-xs\n * - sm: h-9 text-sm\n * - default: h-10 text-sm\n * - lg: h-12 text-base\n *\n * @example\n * ```tsx\n * <ButtonGroupForm\n * name=\"email\"\n * placeholder=\"Enter your email\"\n * inputProps={form.getFieldProps('email')}\n * submitLabel=\"Subscribe\"\n * size=\"default\"\n * />\n * ```\n */\nexport function ButtonGroupForm({\n name,\n label,\n inputProps,\n submitLabel = \"Submit\",\n submitVariant = \"default\",\n size = \"default\",\n isSubmitting = false,\n submitIconName,\n submitIconComponent,\n className,\n labelClassName,\n}: ButtonGroupFormProps) {\n const inputId = `button-group-input-${name}`;\n\n const hasValue = String(inputProps.value ?? \"\").trim().length > 0;\n const hasError = !!inputProps.error;\n\n const buttonSize:\n | \"xs\"\n | \"sm\"\n | \"default\"\n | \"lg\"\n | \"icon\"\n | \"icon-xs\"\n | \"icon-sm\"\n | \"icon-lg\" = React.useMemo(() => {\n if (submitIconName || submitIconComponent) {\n return size === \"default\" ? \"icon\" : (`icon-${size}` as const);\n }\n return size;\n }, [submitIconName, size, submitIconComponent]);\n\n const labelElement = React.useMemo(() => {\n if (submitIconName) {\n return <Icon name={submitIconName} apiKey={DEFAULT_ICON_API_KEY} />;\n } else if (submitIconComponent) {\n return submitIconComponent;\n } else if (submitLabel) {\n return submitLabel;\n } else {\n return \"Submit\";\n }\n }, [submitIconComponent, submitIconName, submitLabel]);\n\n // Size-specific classes for input to match button heights\n const inputSizeClasses = {\n xs: \"text-xs px-3\",\n sm: \"text-sm px-3\",\n default: \"text-base px-4\",\n lg: \"text-md px-6\",\n };\n\n return (\n <div className={cn(\"space-y-2\", className)}>\n {label && (\n <FieldLabel htmlFor={inputId} className={labelClassName}>\n {label}\n </FieldLabel>\n )}\n <ButtonGroup>\n <TextInput\n {...inputProps}\n id={inputId}\n className={cn(\n inputSizeClasses[size],\n \"border-r-0 rounded-r-none focus-visible:z-10\",\n inputProps.className,\n )}\n />\n <Button\n size={buttonSize}\n type=\"submit\"\n variant={submitVariant}\n disabled={isSubmitting}\n className={cn(\n \"rounded-l-none\",\n !hasError && hasValue && \"ring-2 ring-ring\",\n )}\n >\n {labelElement}\n </Button>\n </ButtonGroup>\n </div>\n );\n}\n\nButtonGroupForm.displayName = \"ButtonGroupForm\";\n","\"use client\";\n\nimport * as React from \"react\";\nimport { FormContext } from \"./FormContext\";\nimport type { FormProps, FormValues } from \"./types\";\nimport { FormFeedback } from \"./form-feedback\";\nimport { Button } from \"../components/ui/button\";\nimport { ButtonGroupForm } from \"./button-group-form\";\nimport type { FormFieldConfig } from \"../integration/form-field-types\";\n\n/**\n * Form - Progressive enhancement form component\n *\n * Provides form context to child components and handles form submission.\n * Supports progressive enhancement with server-side fallback.\n *\n * Features:\n * - Provides FormContext for useField hook\n * - Handles form submission with validation\n * - Progressive enhancement support (works without JavaScript)\n * - Accessible form semantics\n *\n * @example\n * ```tsx\n * const form = useForm({\n * initialValues: { email: '' },\n * onSubmit: async (values) => {\n * await submitForm(values);\n * },\n * });\n *\n * return (\n * <Form form={form} action=\"/api/submit\" method=\"post\">\n * <input {...form.getFieldProps('email')} />\n * <button type=\"submit\">Submit</button>\n * </Form>\n * );\n * ```\n *\n * @see https://opensite.ai/developers/page-speed/forms/form\n */\nexport function Form<T extends FormValues = FormValues>({\n form,\n children,\n fields,\n className,\n action,\n method,\n noValidate = true,\n submissionConfig,\n successMessage,\n submissionError,\n successMessageClassName,\n errorMessageClassName,\n onNewSubmission,\n notificationConfig,\n styleConfig,\n formConfig,\n ...props\n}: FormProps<T> & React.FormHTMLAttributes<HTMLFormElement>) {\n // Wrap handleSubmit to catch any unhandled rejections\n const handleFormSubmit = React.useCallback(\n async (e: React.FormEvent) => {\n try {\n await form.handleSubmit(e);\n } catch {\n // Error is already handled by useForm, just prevent unhandled rejection\n // The form status and errors are already set by useForm's error handling\n }\n },\n [form],\n );\n\n const resolvedClassName = className ?? styleConfig?.formClassName;\n const resolvedAction = action ?? formConfig?.endpoint;\n const resolvedMethod = method ?? formConfig?.method ?? \"post\";\n const resolvedSubmissionConfig =\n submissionConfig ?? formConfig?.submissionConfig;\n const resolvedSuccessMessage =\n successMessage ?? notificationConfig?.successMessage;\n const resolvedSubmissionError =\n submissionError ?? notificationConfig?.submissionError;\n const resolvedSuccessMessageClassName =\n successMessageClassName ?? styleConfig?.successMessageClassName;\n const resolvedErrorMessageClassName =\n errorMessageClassName ?? styleConfig?.errorMessageClassName;\n\n const behavior = resolvedSubmissionConfig?.behavior || \"showConfirmation\";\n\n const shouldManageSubmissionUi =\n resolvedSubmissionConfig !== undefined ||\n resolvedSuccessMessage !== undefined ||\n resolvedSuccessMessageClassName !== undefined ||\n resolvedErrorMessageClassName !== undefined ||\n resolvedSubmissionError != null ||\n onNewSubmission !== undefined;\n\n const hasSubmissionError = Boolean(resolvedSubmissionError);\n\n const isSubmissionSuccessful =\n shouldManageSubmissionUi &&\n form.status === \"success\" &&\n !hasSubmissionError;\n\n const defaultSuccessMessage =\n behavior === \"redirect\"\n ? \"Form submitted successfully. Redirecting...\"\n : \"Thank you. Your form has been submitted successfully.\";\n\n const finalSuccessMessage = resolvedSuccessMessage ?? defaultSuccessMessage;\n\n const shouldRenderCustomComponent =\n isSubmissionSuccessful &&\n behavior === \"renderCustomComponent\" &&\n Boolean(resolvedSubmissionConfig?.customComponent);\n\n const newSubmissionAction = resolvedSubmissionConfig?.newFormSubmissionAction;\n\n const showNewSubmissionAction =\n isSubmissionSuccessful &&\n (typeof newSubmissionAction?.enable === \"boolean\"\n ? newSubmissionAction.enable\n : Boolean(newSubmissionAction?.label));\n\n const newSubmissionLabel =\n newSubmissionAction?.label ?? \"Submit another response\";\n\n const handleNewSubmission = React.useCallback(() => {\n form.resetForm();\n onNewSubmission?.();\n }, [form, onNewSubmission]);\n\n // Check if we should use button-group layout\n const formLayout = formConfig?.formLayout ?? \"standard\";\n const isButtonGroupLayout = formLayout === \"button-group\";\n const hasTextField =\n fields &&\n fields.length === 1 &&\n fields[0] &&\n [\"text\", \"email\", \"password\", \"url\", \"tel\", \"search\"].includes(\n fields[0].type,\n );\n const shouldUseButtonGroup = isButtonGroupLayout && hasTextField;\n\n // Render button-group layout if conditions are met\n const buttonGroupContent = React.useMemo(() => {\n if (!shouldUseButtonGroup || !fields || fields.length === 0) return null;\n\n const field = fields[0] as FormFieldConfig;\n const fieldProps = form.getFieldProps(field.name);\n\n return (\n <ButtonGroupForm\n name={field.name}\n label={field.label}\n inputProps={{\n name: fieldProps.name,\n value: fieldProps.value as string,\n onChange: fieldProps.onChange as (value: string) => void,\n onBlur: fieldProps.onBlur,\n type: field.type as\n | \"text\"\n | \"email\"\n | \"password\"\n | \"url\"\n | \"tel\"\n | \"search\",\n placeholder: field.placeholder,\n required: field.required,\n disabled: field.disabled,\n }}\n submitLabel={formConfig?.submitLabel}\n submitVariant={formConfig?.submitVariant}\n submitIconName={formConfig?.submitIconName}\n submitIconComponent={formConfig?.submitIconComponent}\n size={formConfig?.buttonGroupSize}\n isSubmitting={form.isSubmitting}\n />\n );\n }, [shouldUseButtonGroup, fields, form, formConfig]);\n\n return (\n <FormContext.Provider value={form}>\n <form\n onSubmit={handleFormSubmit}\n action={resolvedAction}\n method={resolvedMethod}\n noValidate={noValidate}\n className={resolvedClassName}\n {...props}\n >\n {isSubmissionSuccessful ? (\n <div className=\"space-y-4\">\n {shouldRenderCustomComponent ? (\n resolvedSubmissionConfig?.customComponent\n ) : (\n <FormFeedback\n successMessage={finalSuccessMessage}\n successMessageClassName={resolvedSuccessMessageClassName}\n />\n )}\n\n {showNewSubmissionAction ? (\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={handleNewSubmission}\n >\n {newSubmissionLabel}\n </Button>\n ) : null}\n </div>\n ) : (\n <>\n {shouldUseButtonGroup ? buttonGroupContent : children}\n {resolvedSubmissionError ? (\n <div className=\"mt-4\">\n <FormFeedback\n submissionError={resolvedSubmissionError}\n errorMessageClassName={resolvedErrorMessageClassName}\n />\n </div>\n ) : null}\n </>\n )}\n </form>\n </FormContext.Provider>\n );\n}\n\nForm.displayName = \"Form\";\n"]}
package/dist/core.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkF5ZJCJOD_cjs = require('./chunk-F5ZJCJOD.cjs');
3
+ var chunkRS6AXV5S_cjs = require('./chunk-RS6AXV5S.cjs');
4
4
  var chunkMUBEMXI7_cjs = require('./chunk-MUBEMXI7.cjs');
5
5
  require('./chunk-QRI5TMES.cjs');
6
6
 
@@ -8,15 +8,15 @@ require('./chunk-QRI5TMES.cjs');
8
8
 
9
9
  Object.defineProperty(exports, "ButtonGroupForm", {
10
10
  enumerable: true,
11
- get: function () { return chunkF5ZJCJOD_cjs.ButtonGroupForm; }
11
+ get: function () { return chunkRS6AXV5S_cjs.ButtonGroupForm; }
12
12
  });
13
13
  Object.defineProperty(exports, "Form", {
14
14
  enumerable: true,
15
- get: function () { return chunkF5ZJCJOD_cjs.Form; }
15
+ get: function () { return chunkRS6AXV5S_cjs.Form; }
16
16
  });
17
17
  Object.defineProperty(exports, "FormFeedback", {
18
18
  enumerable: true,
19
- get: function () { return chunkF5ZJCJOD_cjs.FormFeedback; }
19
+ get: function () { return chunkRS6AXV5S_cjs.FormFeedback; }
20
20
  });
21
21
  Object.defineProperty(exports, "Field", {
22
22
  enumerable: true,
package/dist/core.d.cts CHANGED
@@ -1,7 +1,7 @@
1
- export { b as Field, F as Form, d as FormContext, c as FormFeedback, e as FormFeedbackProps, a as useField, u as useForm } from './FormContext-KsjKSot3.cjs';
1
+ export { b as Field, F as Form, d as FormContext, c as FormFeedback, e as FormFeedbackProps, a as useField, u as useForm } from './FormContext-BHKCZ_du.cjs';
2
2
  import * as React from 'react';
3
- import { I as InputProps } from './types-RnnhRtD2.cjs';
4
- export { E as ErrorHandler, n as FieldInputProps, o as FieldMeta, s as FieldProps, F as FieldValidator, l as FormActions, c as FormErrors, i as FormHelpers, f as FormNotificationConfig, r as FormProps, h as FormRenderConfig, k as FormState, g as FormStyleConfig, d as FormSubmissionBehavior, e as FormSubmissionConfig, b as FormValues, N as NewFormSubmissionActionConfig, S as SubmissionStatus, j as SubmitHandler, T as TouchedFields, p as UseFieldOptions, q as UseFieldReturn, U as UseFormOptions, m as UseFormReturn, a as ValidationMode, V as ValidationSchema } from './types-RnnhRtD2.cjs';
3
+ import { I as InputProps } from './types-Fbt73kW_.cjs';
4
+ export { E as ErrorHandler, n as FieldInputProps, o as FieldMeta, s as FieldProps, F as FieldValidator, l as FormActions, c as FormErrors, i as FormHelpers, f as FormNotificationConfig, r as FormProps, h as FormRenderConfig, k as FormState, g as FormStyleConfig, d as FormSubmissionBehavior, e as FormSubmissionConfig, b as FormValues, N as NewFormSubmissionActionConfig, S as SubmissionStatus, j as SubmitHandler, T as TouchedFields, p as UseFieldOptions, q as UseFieldReturn, U as UseFormOptions, m as UseFormReturn, a as ValidationMode, V as ValidationSchema } from './types-Fbt73kW_.cjs';
5
5
 
6
6
  type ButtonGroupFormSize = "xs" | "sm" | "default" | "lg";
7
7
  type ButtonGroupFormProps = {
@@ -47,6 +47,10 @@ type ButtonGroupFormProps = {
47
47
  * Icon name for icon based submit buttons
48
48
  */
49
49
  submitIconName?: string;
50
+ /**
51
+ * Icon component for icon based submit buttons
52
+ */
53
+ submitIconComponent?: React.ReactNode;
50
54
  /**
51
55
  * Additional className for the label
52
56
  */
@@ -75,7 +79,7 @@ type ButtonGroupFormProps = {
75
79
  * />
76
80
  * ```
77
81
  */
78
- declare function ButtonGroupForm({ name, label, inputProps, submitLabel, submitVariant, size, isSubmitting, submitIconName, className, labelClassName, }: ButtonGroupFormProps): React.JSX.Element;
82
+ declare function ButtonGroupForm({ name, label, inputProps, submitLabel, submitVariant, size, isSubmitting, submitIconName, submitIconComponent, className, labelClassName, }: ButtonGroupFormProps): React.JSX.Element;
79
83
  declare namespace ButtonGroupForm {
80
84
  var displayName: string;
81
85
  }
package/dist/core.d.ts CHANGED
@@ -1,7 +1,7 @@
1
- export { b as Field, F as Form, d as FormContext, c as FormFeedback, e as FormFeedbackProps, a as useField, u as useForm } from './FormContext-DaRyEYnF.js';
1
+ export { b as Field, F as Form, d as FormContext, c as FormFeedback, e as FormFeedbackProps, a as useField, u as useForm } from './FormContext-D_K7lO2V.js';
2
2
  import * as React from 'react';
3
- import { I as InputProps } from './types-RnnhRtD2.js';
4
- export { E as ErrorHandler, n as FieldInputProps, o as FieldMeta, s as FieldProps, F as FieldValidator, l as FormActions, c as FormErrors, i as FormHelpers, f as FormNotificationConfig, r as FormProps, h as FormRenderConfig, k as FormState, g as FormStyleConfig, d as FormSubmissionBehavior, e as FormSubmissionConfig, b as FormValues, N as NewFormSubmissionActionConfig, S as SubmissionStatus, j as SubmitHandler, T as TouchedFields, p as UseFieldOptions, q as UseFieldReturn, U as UseFormOptions, m as UseFormReturn, a as ValidationMode, V as ValidationSchema } from './types-RnnhRtD2.js';
3
+ import { I as InputProps } from './types-Fbt73kW_.js';
4
+ export { E as ErrorHandler, n as FieldInputProps, o as FieldMeta, s as FieldProps, F as FieldValidator, l as FormActions, c as FormErrors, i as FormHelpers, f as FormNotificationConfig, r as FormProps, h as FormRenderConfig, k as FormState, g as FormStyleConfig, d as FormSubmissionBehavior, e as FormSubmissionConfig, b as FormValues, N as NewFormSubmissionActionConfig, S as SubmissionStatus, j as SubmitHandler, T as TouchedFields, p as UseFieldOptions, q as UseFieldReturn, U as UseFormOptions, m as UseFormReturn, a as ValidationMode, V as ValidationSchema } from './types-Fbt73kW_.js';
5
5
 
6
6
  type ButtonGroupFormSize = "xs" | "sm" | "default" | "lg";
7
7
  type ButtonGroupFormProps = {
@@ -47,6 +47,10 @@ type ButtonGroupFormProps = {
47
47
  * Icon name for icon based submit buttons
48
48
  */
49
49
  submitIconName?: string;
50
+ /**
51
+ * Icon component for icon based submit buttons
52
+ */
53
+ submitIconComponent?: React.ReactNode;
50
54
  /**
51
55
  * Additional className for the label
52
56
  */
@@ -75,7 +79,7 @@ type ButtonGroupFormProps = {
75
79
  * />
76
80
  * ```
77
81
  */
78
- declare function ButtonGroupForm({ name, label, inputProps, submitLabel, submitVariant, size, isSubmitting, submitIconName, className, labelClassName, }: ButtonGroupFormProps): React.JSX.Element;
82
+ declare function ButtonGroupForm({ name, label, inputProps, submitLabel, submitVariant, size, isSubmitting, submitIconName, submitIconComponent, className, labelClassName, }: ButtonGroupFormProps): React.JSX.Element;
79
83
  declare namespace ButtonGroupForm {
80
84
  var displayName: string;
81
85
  }
package/dist/core.js CHANGED
@@ -1,4 +1,4 @@
1
- export { ButtonGroupForm, Form, FormFeedback } from './chunk-7ZX2EUOG.js';
1
+ export { ButtonGroupForm, Form, FormFeedback } from './chunk-ZEAH6AKP.js';
2
2
  export { Field, FormContext, useField, useForm } from './chunk-MJYEXJ3U.js';
3
3
  import './chunk-455PI4LV.js';
4
4
  //# sourceMappingURL=core.js.map
package/dist/index.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkF5ZJCJOD_cjs = require('./chunk-F5ZJCJOD.cjs');
3
+ var chunkRS6AXV5S_cjs = require('./chunk-RS6AXV5S.cjs');
4
4
  var chunkMUBEMXI7_cjs = require('./chunk-MUBEMXI7.cjs');
5
5
  var chunkQRI5TMES_cjs = require('./chunk-QRI5TMES.cjs');
6
6
 
@@ -8,11 +8,11 @@ var chunkQRI5TMES_cjs = require('./chunk-QRI5TMES.cjs');
8
8
 
9
9
  Object.defineProperty(exports, "Form", {
10
10
  enumerable: true,
11
- get: function () { return chunkF5ZJCJOD_cjs.Form; }
11
+ get: function () { return chunkRS6AXV5S_cjs.Form; }
12
12
  });
13
13
  Object.defineProperty(exports, "FormFeedback", {
14
14
  enumerable: true,
15
- get: function () { return chunkF5ZJCJOD_cjs.FormFeedback; }
15
+ get: function () { return chunkRS6AXV5S_cjs.FormFeedback; }
16
16
  });
17
17
  Object.defineProperty(exports, "Field", {
18
18
  enumerable: true,
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
- export { b as Field, F as Form, d as FormContext, c as FormFeedback, e as FormFeedbackProps, a as useField, u as useForm } from './FormContext-KsjKSot3.cjs';
2
- export { E as ErrorHandler, n as FieldInputProps, o as FieldMeta, s as FieldProps, F as FieldValidator, l as FormActions, c as FormErrors, i as FormHelpers, f as FormNotificationConfig, r as FormProps, h as FormRenderConfig, k as FormState, g as FormStyleConfig, d as FormSubmissionBehavior, e as FormSubmissionConfig, b as FormValues, I as InputProps, N as NewFormSubmissionActionConfig, S as SubmissionStatus, j as SubmitHandler, T as TouchedFields, p as UseFieldOptions, q as UseFieldReturn, U as UseFormOptions, m as UseFormReturn, a as ValidationMode, V as ValidationSchema } from './types-RnnhRtD2.cjs';
1
+ export { b as Field, F as Form, d as FormContext, c as FormFeedback, e as FormFeedbackProps, a as useField, u as useForm } from './FormContext-BHKCZ_du.cjs';
2
+ export { E as ErrorHandler, n as FieldInputProps, o as FieldMeta, s as FieldProps, F as FieldValidator, l as FormActions, c as FormErrors, i as FormHelpers, f as FormNotificationConfig, r as FormProps, h as FormRenderConfig, k as FormState, g as FormStyleConfig, d as FormSubmissionBehavior, e as FormSubmissionConfig, b as FormValues, I as InputProps, N as NewFormSubmissionActionConfig, S as SubmissionStatus, j as SubmitHandler, T as TouchedFields, p as UseFieldOptions, q as UseFieldReturn, U as UseFormOptions, m as UseFormReturn, a as ValidationMode, V as ValidationSchema } from './types-Fbt73kW_.cjs';
3
3
  import * as React from 'react';
4
4
 
5
5
  type FieldOrientation = "vertical" | "horizontal";
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- export { b as Field, F as Form, d as FormContext, c as FormFeedback, e as FormFeedbackProps, a as useField, u as useForm } from './FormContext-DaRyEYnF.js';
2
- export { E as ErrorHandler, n as FieldInputProps, o as FieldMeta, s as FieldProps, F as FieldValidator, l as FormActions, c as FormErrors, i as FormHelpers, f as FormNotificationConfig, r as FormProps, h as FormRenderConfig, k as FormState, g as FormStyleConfig, d as FormSubmissionBehavior, e as FormSubmissionConfig, b as FormValues, I as InputProps, N as NewFormSubmissionActionConfig, S as SubmissionStatus, j as SubmitHandler, T as TouchedFields, p as UseFieldOptions, q as UseFieldReturn, U as UseFormOptions, m as UseFormReturn, a as ValidationMode, V as ValidationSchema } from './types-RnnhRtD2.js';
1
+ export { b as Field, F as Form, d as FormContext, c as FormFeedback, e as FormFeedbackProps, a as useField, u as useForm } from './FormContext-D_K7lO2V.js';
2
+ export { E as ErrorHandler, n as FieldInputProps, o as FieldMeta, s as FieldProps, F as FieldValidator, l as FormActions, c as FormErrors, i as FormHelpers, f as FormNotificationConfig, r as FormProps, h as FormRenderConfig, k as FormState, g as FormStyleConfig, d as FormSubmissionBehavior, e as FormSubmissionConfig, b as FormValues, I as InputProps, N as NewFormSubmissionActionConfig, S as SubmissionStatus, j as SubmitHandler, T as TouchedFields, p as UseFieldOptions, q as UseFieldReturn, U as UseFormOptions, m as UseFormReturn, a as ValidationMode, V as ValidationSchema } from './types-Fbt73kW_.js';
3
3
  import * as React from 'react';
4
4
 
5
5
  type FieldOrientation = "vertical" | "horizontal";
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- export { Form, FormFeedback } from './chunk-7ZX2EUOG.js';
1
+ export { Form, FormFeedback } from './chunk-ZEAH6AKP.js';
2
2
  export { Field, FormContext, useField, useForm } from './chunk-MJYEXJ3U.js';
3
3
  export { FieldDescription, FieldError, FieldGroup, Field as FieldWrapper, FieldLabel as FormFieldLabel } from './chunk-455PI4LV.js';
4
4
  //# sourceMappingURL=index.js.map
package/dist/inputs.d.cts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as React from 'react';
2
- import { I as InputProps } from './types-RnnhRtD2.cjs';
2
+ import { I as InputProps } from './types-Fbt73kW_.cjs';
3
3
 
4
4
  /**
5
5
  * TextInput - High-performance text input component (ShadCN-based)
package/dist/inputs.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as React from 'react';
2
- import { I as InputProps } from './types-RnnhRtD2.js';
2
+ import { I as InputProps } from './types-Fbt73kW_.js';
3
3
 
4
4
  /**
5
5
  * TextInput - High-performance text input component (ShadCN-based)
@@ -1,6 +1,6 @@
1
1
  import * as React from 'react';
2
2
  import { ReactNode } from 'react';
3
- import { d as FormSubmissionBehavior, N as NewFormSubmissionActionConfig, m as UseFormReturn } from './types-RnnhRtD2.cjs';
3
+ import { d as FormSubmissionBehavior, N as NewFormSubmissionActionConfig, m as UseFormReturn } from './types-Fbt73kW_.cjs';
4
4
 
5
5
  /**
6
6
  * @page-speed/forms - Rails API Serializer
@@ -1,6 +1,6 @@
1
1
  import * as React from 'react';
2
2
  import { ReactNode } from 'react';
3
- import { d as FormSubmissionBehavior, N as NewFormSubmissionActionConfig, m as UseFormReturn } from './types-RnnhRtD2.js';
3
+ import { d as FormSubmissionBehavior, N as NewFormSubmissionActionConfig, m as UseFormReturn } from './types-Fbt73kW_.js';
4
4
 
5
5
  /**
6
6
  * @page-speed/forms - Rails API Serializer
@@ -365,6 +365,10 @@ interface FormRenderConfig {
365
365
  * Icon name for icon based submit buttons
366
366
  */
367
367
  submitIconName?: string;
368
+ /**
369
+ * Icon component for icon based submit buttons
370
+ */
371
+ submitIconComponent?: React.ReactNode;
368
372
  }
369
373
  /**
370
374
  * Form component props
@@ -365,6 +365,10 @@ interface FormRenderConfig {
365
365
  * Icon name for icon based submit buttons
366
366
  */
367
367
  submitIconName?: string;
368
+ /**
369
+ * Icon component for icon based submit buttons
370
+ */
371
+ submitIconComponent?: React.ReactNode;
368
372
  }
369
373
  /**
370
374
  * Form component props
@@ -1,4 +1,4 @@
1
- import { F as FieldValidator } from './types-RnnhRtD2.cjs';
1
+ import { F as FieldValidator } from './types-Fbt73kW_.cjs';
2
2
  import 'react';
3
3
 
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { F as FieldValidator } from './types-RnnhRtD2.js';
1
+ import { F as FieldValidator } from './types-Fbt73kW_.js';
2
2
  import 'react';
3
3
 
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { F as FieldValidator, b as FormValues } from './types-RnnhRtD2.cjs';
1
+ import { F as FieldValidator, b as FormValues } from './types-Fbt73kW_.cjs';
2
2
  import 'react';
3
3
 
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { F as FieldValidator, b as FormValues } from './types-RnnhRtD2.js';
1
+ import { F as FieldValidator, b as FormValues } from './types-Fbt73kW_.js';
2
2
  import 'react';
3
3
 
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { b as FormValues, V as ValidationSchema, F as FieldValidator } from './types-RnnhRtD2.cjs';
1
+ import { b as FormValues, V as ValidationSchema, F as FieldValidator } from './types-Fbt73kW_.cjs';
2
2
  import 'react';
3
3
 
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { b as FormValues, V as ValidationSchema, F as FieldValidator } from './types-RnnhRtD2.js';
1
+ import { b as FormValues, V as ValidationSchema, F as FieldValidator } from './types-Fbt73kW_.js';
2
2
  import 'react';
3
3
 
4
4
  /**
@@ -1,4 +1,4 @@
1
- export { F as FieldValidator, a as ValidationMode, V as ValidationSchema } from './types-RnnhRtD2.cjs';
1
+ export { F as FieldValidator, a as ValidationMode, V as ValidationSchema } from './types-Fbt73kW_.cjs';
2
2
  export { ErrorMessageFn, ValidationRuleOptions, alpha, alphanumeric, compose, creditCard, email, integer, matches, max, maxLength, min, minLength, numeric, oneOf, pattern, phone, postalCode, required, url } from './validation-rules.cjs';
3
3
  export { DebounceOptions, ErrorMessages, MessageTemplate, asyncValidator, crossFieldValidator, debounce, defaultMessages, getErrorMessage, messageRegistry, resetErrorMessages, setErrorMessages, when, withRaceConditionPrevention } from './validation-utils.cjs';
4
4
  import 'react';
@@ -1,4 +1,4 @@
1
- export { F as FieldValidator, a as ValidationMode, V as ValidationSchema } from './types-RnnhRtD2.js';
1
+ export { F as FieldValidator, a as ValidationMode, V as ValidationSchema } from './types-Fbt73kW_.js';
2
2
  export { ErrorMessageFn, ValidationRuleOptions, alpha, alphanumeric, compose, creditCard, email, integer, matches, max, maxLength, min, minLength, numeric, oneOf, pattern, phone, postalCode, required, url } from './validation-rules.js';
3
3
  export { DebounceOptions, ErrorMessages, MessageTemplate, asyncValidator, crossFieldValidator, debounce, defaultMessages, getErrorMessage, messageRegistry, resetErrorMessages, setErrorMessages, when, withRaceConditionPrevention } from './validation-utils.js';
4
4
  import 'react';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@page-speed/forms",
3
- "version": "0.6.1",
3
+ "version": "0.6.2",
4
4
  "description": "Ultra-high-performance React form library with field-level reactivity and tree-shakable architecture",
5
5
  "keywords": [
6
6
  "react",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/core/form-feedback.tsx","../src/components/ui/button-group.tsx","../src/core/button-group-form.tsx","../src/core/Form.tsx"],"names":["React","React2","React3"],"mappings":"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","file":"chunk-7ZX2EUOG.js","sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../lib/utils\";\n\nexport interface FormFeedbackProps {\n successMessage?: React.ReactNode;\n submissionError?: React.ReactNode;\n successMessageClassName?: string;\n errorMessageClassName?: string;\n}\n\nfunction renderMessage(\n message: React.ReactNode,\n fallbackClassName: string,\n className?: string,\n) {\n if (typeof message === \"string\") {\n return (\n <p\n className={cn(\n \"text-sm font-medium text-center text-balance\",\n className,\n )}\n >\n {message}\n </p>\n );\n }\n\n return <div className={cn(fallbackClassName, className)}>{message}</div>;\n}\n\nexport function FormFeedback({\n successMessage,\n submissionError,\n successMessageClassName,\n errorMessageClassName,\n}: FormFeedbackProps) {\n if (!successMessage && !submissionError) {\n return null;\n }\n\n return (\n <>\n {successMessage ? (\n <div\n className={cn(\n \"rounded-md border border-primary bg-primary px-4 py-3 shadow-sm\",\n successMessageClassName,\n )}\n role=\"status\"\n aria-live=\"polite\"\n >\n {renderMessage(\n successMessage,\n \"text-primary-foreground\",\n \"text-primary-foreground\",\n )}\n </div>\n ) : null}\n\n {submissionError ? (\n <div\n className={cn(\n \"rounded-md border border-destructive bg-destructive px-4 py-3 shadow-sm\",\n errorMessageClassName,\n )}\n role=\"alert\"\n aria-live=\"assertive\"\n >\n {renderMessage(\n submissionError,\n \"text-destructive-foreground\",\n \"text-destructive-foreground\",\n )}\n </div>\n ) : null}\n </>\n );\n}\n\nFormFeedback.displayName = \"FormFeedback\";\n","import * as React from \"react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\nimport { Slot } from \"radix-ui\"\n\nimport { cn } from \"../../lib/utils\"\nimport { Separator } from \"./separator\"\n\nconst buttonGroupVariants = cva(\n \"flex w-fit items-stretch [&>*]:focus-visible:z-10 [&>*]:focus-visible:relative [&>[data-slot=select-trigger]:not([class*='w-'])]:w-fit [&>input]:flex-1 has-[select[aria-hidden=true]:last-child]:[&>[data-slot=select-trigger]:last-of-type]:rounded-r-md has-[>[data-slot=button-group]]:gap-2\",\n {\n variants: {\n orientation: {\n horizontal:\n \"[&>*:not(:first-child)]:rounded-l-none [&>*:not(:first-child)]:border-l-0 [&>*:not(:last-child)]:rounded-r-none\",\n vertical:\n \"flex-col [&>*:not(:first-child)]:rounded-t-none [&>*:not(:first-child)]:border-t-0 [&>*:not(:last-child)]:rounded-b-none\",\n },\n },\n defaultVariants: {\n orientation: \"horizontal\",\n },\n }\n)\n\nfunction ButtonGroup({\n className,\n orientation,\n ...props\n}: React.ComponentProps<\"div\"> & VariantProps<typeof buttonGroupVariants>) {\n return (\n <div\n role=\"group\"\n data-slot=\"button-group\"\n data-orientation={orientation}\n className={cn(buttonGroupVariants({ orientation }), className)}\n {...props}\n />\n )\n}\n\nfunction ButtonGroupText({\n className,\n asChild = false,\n ...props\n}: React.ComponentProps<\"div\"> & {\n asChild?: boolean\n}) {\n const Comp = asChild ? Slot.Root : \"div\"\n\n return (\n <Comp\n className={cn(\n \"bg-muted flex items-center gap-2 rounded-md border px-4 text-sm font-medium shadow-xs [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction ButtonGroupSeparator({\n className,\n orientation = \"vertical\",\n ...props\n}: React.ComponentProps<typeof Separator>) {\n return (\n <Separator\n data-slot=\"button-group-separator\"\n orientation={orientation}\n className={cn(\n \"bg-input relative !m-0 self-stretch data-[orientation=vertical]:h-auto\",\n className\n )}\n {...props}\n />\n )\n}\n\nexport {\n ButtonGroup,\n ButtonGroupSeparator,\n ButtonGroupText,\n buttonGroupVariants,\n}\n","\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { Button } from \"../components/ui/button\";\nimport { ButtonGroup } from \"../components/ui/button-group\";\nimport { FieldLabel } from \"../components/ui/field\";\nimport { TextInput } from \"../inputs/TextInput\";\nimport type { InputProps } from \"./types\";\nimport { Icon } from \"@page-speed/icon\";\n\nconst DEFAULT_ICON_API_KEY = \"au382bi7fsh96w9h9xlrnat2jglx\";\n\nexport type ButtonGroupFormSize = \"xs\" | \"sm\" | \"default\" | \"lg\";\n\nexport type ButtonGroupFormProps = {\n /**\n * Field name\n */\n name: string;\n /**\n * Optional label above the input\n */\n label?: React.ReactNode;\n /**\n * Placeholder text for the input\n */\n placeholder?: string;\n /**\n * Input props from form field\n */\n inputProps: InputProps<string> & {\n type?: \"text\" | \"email\" | \"password\" | \"url\" | \"tel\" | \"search\";\n };\n /**\n * Submit button label\n */\n submitLabel?: React.ReactNode;\n /**\n * Submit button size\n */\n size?: ButtonGroupFormSize;\n /**\n * Submit button variant\n */\n submitVariant?:\n | \"link\"\n | \"default\"\n | \"destructive\"\n | \"outline\"\n | \"secondary\"\n | \"ghost\"\n | null\n | undefined;\n /**\n * Whether form is submitting\n */\n isSubmitting?: boolean;\n /**\n * Additional className for the container\n */\n className?: string;\n /**\n * Icon name for icon based submit buttons\n */\n submitIconName?: string;\n /**\n * Additional className for the label\n */\n labelClassName?: string;\n};\n\n/**\n * ButtonGroupForm - Inline form layout with input and submit button grouped together\n *\n * Commonly used for newsletter signups and other simple single-field forms.\n * The input and button automatically adjust sizing together.\n *\n * Size mappings:\n * - xs: h-8 text-xs\n * - sm: h-9 text-sm\n * - default: h-10 text-sm\n * - lg: h-12 text-base\n *\n * @example\n * ```tsx\n * <ButtonGroupForm\n * name=\"email\"\n * placeholder=\"Enter your email\"\n * inputProps={form.getFieldProps('email')}\n * submitLabel=\"Subscribe\"\n * size=\"default\"\n * />\n * ```\n */\nexport function ButtonGroupForm({\n name,\n label,\n inputProps,\n submitLabel = \"Submit\",\n submitVariant = \"default\",\n size = \"default\",\n isSubmitting = false,\n submitIconName,\n className,\n labelClassName,\n}: ButtonGroupFormProps) {\n const inputId = `button-group-input-${name}`;\n\n const hasValue = String(inputProps.value ?? \"\").trim().length > 0;\n const hasError = !!inputProps.error;\n\n const buttonSize:\n | \"xs\"\n | \"sm\"\n | \"default\"\n | \"lg\"\n | \"icon\"\n | \"icon-xs\"\n | \"icon-sm\"\n | \"icon-lg\" = React.useMemo(() => {\n if (submitIconName) {\n return size === \"default\" ? \"icon\" : (`icon-${size}` as const);\n }\n return size;\n }, [submitIconName, size]);\n\n // Size-specific classes for input to match button heights\n const inputSizeClasses = {\n xs: \"text-xs px-3\",\n sm: \"text-sm px-3\",\n default: \"text-base px-4\",\n lg: \"text-md px-6\",\n };\n\n return (\n <div className={cn(\"space-y-2\", className)}>\n {label && (\n <FieldLabel htmlFor={inputId} className={labelClassName}>\n {label}\n </FieldLabel>\n )}\n <ButtonGroup>\n <TextInput\n {...inputProps}\n id={inputId}\n className={cn(\n inputSizeClasses[size],\n \"border-r-0 rounded-r-none focus-visible:z-10\",\n inputProps.className,\n )}\n />\n <Button\n size={buttonSize}\n type=\"submit\"\n variant={submitVariant}\n disabled={isSubmitting}\n className={cn(\n \"rounded-l-none\",\n !hasError && hasValue && \"ring-2 ring-ring\",\n )}\n >\n {submitIconName ? (\n <Icon name={submitIconName} apiKey={DEFAULT_ICON_API_KEY} />\n ) : (\n submitLabel\n )}\n </Button>\n </ButtonGroup>\n </div>\n );\n}\n\nButtonGroupForm.displayName = \"ButtonGroupForm\";\n","\"use client\";\n\nimport * as React from \"react\";\nimport { FormContext } from \"./FormContext\";\nimport type { FormProps, FormValues } from \"./types\";\nimport { FormFeedback } from \"./form-feedback\";\nimport { Button } from \"../components/ui/button\";\nimport { ButtonGroupForm } from \"./button-group-form\";\nimport type { FormFieldConfig } from \"../integration/form-field-types\";\n\n/**\n * Form - Progressive enhancement form component\n *\n * Provides form context to child components and handles form submission.\n * Supports progressive enhancement with server-side fallback.\n *\n * Features:\n * - Provides FormContext for useField hook\n * - Handles form submission with validation\n * - Progressive enhancement support (works without JavaScript)\n * - Accessible form semantics\n *\n * @example\n * ```tsx\n * const form = useForm({\n * initialValues: { email: '' },\n * onSubmit: async (values) => {\n * await submitForm(values);\n * },\n * });\n *\n * return (\n * <Form form={form} action=\"/api/submit\" method=\"post\">\n * <input {...form.getFieldProps('email')} />\n * <button type=\"submit\">Submit</button>\n * </Form>\n * );\n * ```\n *\n * @see https://opensite.ai/developers/page-speed/forms/form\n */\nexport function Form<T extends FormValues = FormValues>({\n form,\n children,\n fields,\n className,\n action,\n method,\n noValidate = true,\n submissionConfig,\n successMessage,\n submissionError,\n successMessageClassName,\n errorMessageClassName,\n onNewSubmission,\n notificationConfig,\n styleConfig,\n formConfig,\n ...props\n}: FormProps<T> & React.FormHTMLAttributes<HTMLFormElement>) {\n // Wrap handleSubmit to catch any unhandled rejections\n const handleFormSubmit = React.useCallback(\n async (e: React.FormEvent) => {\n try {\n await form.handleSubmit(e);\n } catch {\n // Error is already handled by useForm, just prevent unhandled rejection\n // The form status and errors are already set by useForm's error handling\n }\n },\n [form],\n );\n\n const resolvedClassName = className ?? styleConfig?.formClassName;\n const resolvedAction = action ?? formConfig?.endpoint;\n const resolvedMethod = method ?? formConfig?.method ?? \"post\";\n const resolvedSubmissionConfig =\n submissionConfig ?? formConfig?.submissionConfig;\n const resolvedSuccessMessage =\n successMessage ?? notificationConfig?.successMessage;\n const resolvedSubmissionError =\n submissionError ?? notificationConfig?.submissionError;\n const resolvedSuccessMessageClassName =\n successMessageClassName ?? styleConfig?.successMessageClassName;\n const resolvedErrorMessageClassName =\n errorMessageClassName ?? styleConfig?.errorMessageClassName;\n\n const behavior = resolvedSubmissionConfig?.behavior || \"showConfirmation\";\n\n const shouldManageSubmissionUi =\n resolvedSubmissionConfig !== undefined ||\n resolvedSuccessMessage !== undefined ||\n resolvedSuccessMessageClassName !== undefined ||\n resolvedErrorMessageClassName !== undefined ||\n resolvedSubmissionError != null ||\n onNewSubmission !== undefined;\n\n const hasSubmissionError = Boolean(resolvedSubmissionError);\n\n const isSubmissionSuccessful =\n shouldManageSubmissionUi &&\n form.status === \"success\" &&\n !hasSubmissionError;\n\n const defaultSuccessMessage =\n behavior === \"redirect\"\n ? \"Form submitted successfully. Redirecting...\"\n : \"Thank you. Your form has been submitted successfully.\";\n\n const finalSuccessMessage = resolvedSuccessMessage ?? defaultSuccessMessage;\n\n const shouldRenderCustomComponent =\n isSubmissionSuccessful &&\n behavior === \"renderCustomComponent\" &&\n Boolean(resolvedSubmissionConfig?.customComponent);\n\n const newSubmissionAction = resolvedSubmissionConfig?.newFormSubmissionAction;\n\n const showNewSubmissionAction =\n isSubmissionSuccessful &&\n (typeof newSubmissionAction?.enable === \"boolean\"\n ? newSubmissionAction.enable\n : Boolean(newSubmissionAction?.label));\n\n const newSubmissionLabel =\n newSubmissionAction?.label ?? \"Submit another response\";\n\n const handleNewSubmission = React.useCallback(() => {\n form.resetForm();\n onNewSubmission?.();\n }, [form, onNewSubmission]);\n\n // Check if we should use button-group layout\n const formLayout = formConfig?.formLayout ?? \"standard\";\n const isButtonGroupLayout = formLayout === \"button-group\";\n const hasTextField =\n fields &&\n fields.length === 1 &&\n fields[0] &&\n [\"text\", \"email\", \"password\", \"url\", \"tel\", \"search\"].includes(\n fields[0].type,\n );\n const shouldUseButtonGroup = isButtonGroupLayout && hasTextField;\n\n // Render button-group layout if conditions are met\n const buttonGroupContent = React.useMemo(() => {\n if (!shouldUseButtonGroup || !fields || fields.length === 0) return null;\n\n const field = fields[0] as FormFieldConfig;\n const fieldProps = form.getFieldProps(field.name);\n\n return (\n <ButtonGroupForm\n name={field.name}\n label={field.label}\n inputProps={{\n name: fieldProps.name,\n value: fieldProps.value as string,\n onChange: fieldProps.onChange as (value: string) => void,\n onBlur: fieldProps.onBlur,\n type: field.type as\n | \"text\"\n | \"email\"\n | \"password\"\n | \"url\"\n | \"tel\"\n | \"search\",\n placeholder: field.placeholder,\n required: field.required,\n disabled: field.disabled,\n }}\n submitLabel={formConfig?.submitLabel}\n submitVariant={formConfig?.submitVariant}\n submitIconName={formConfig?.submitIconName}\n size={formConfig?.buttonGroupSize}\n isSubmitting={form.isSubmitting}\n />\n );\n }, [shouldUseButtonGroup, fields, form, formConfig]);\n\n return (\n <FormContext.Provider value={form}>\n <form\n onSubmit={handleFormSubmit}\n action={resolvedAction}\n method={resolvedMethod}\n noValidate={noValidate}\n className={resolvedClassName}\n {...props}\n >\n {isSubmissionSuccessful ? (\n <div className=\"space-y-4\">\n {shouldRenderCustomComponent ? (\n resolvedSubmissionConfig?.customComponent\n ) : (\n <FormFeedback\n successMessage={finalSuccessMessage}\n successMessageClassName={resolvedSuccessMessageClassName}\n />\n )}\n\n {showNewSubmissionAction ? (\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={handleNewSubmission}\n >\n {newSubmissionLabel}\n </Button>\n ) : null}\n </div>\n ) : (\n <>\n {shouldUseButtonGroup ? buttonGroupContent : children}\n {resolvedSubmissionError ? (\n <div className=\"mt-4\">\n <FormFeedback\n submissionError={resolvedSubmissionError}\n errorMessageClassName={resolvedErrorMessageClassName}\n />\n </div>\n ) : null}\n </>\n )}\n </form>\n </FormContext.Provider>\n );\n}\n\nForm.displayName = \"Form\";\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/core/form-feedback.tsx","../src/components/ui/button-group.tsx","../src/core/button-group-form.tsx","../src/core/Form.tsx"],"names":["React","cn","cva","React2","React3","FieldLabel","TextInput","Button","Icon","React4","FormContext"],"mappings":"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","file":"chunk-F5ZJCJOD.cjs","sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../lib/utils\";\n\nexport interface FormFeedbackProps {\n successMessage?: React.ReactNode;\n submissionError?: React.ReactNode;\n successMessageClassName?: string;\n errorMessageClassName?: string;\n}\n\nfunction renderMessage(\n message: React.ReactNode,\n fallbackClassName: string,\n className?: string,\n) {\n if (typeof message === \"string\") {\n return (\n <p\n className={cn(\n \"text-sm font-medium text-center text-balance\",\n className,\n )}\n >\n {message}\n </p>\n );\n }\n\n return <div className={cn(fallbackClassName, className)}>{message}</div>;\n}\n\nexport function FormFeedback({\n successMessage,\n submissionError,\n successMessageClassName,\n errorMessageClassName,\n}: FormFeedbackProps) {\n if (!successMessage && !submissionError) {\n return null;\n }\n\n return (\n <>\n {successMessage ? (\n <div\n className={cn(\n \"rounded-md border border-primary bg-primary px-4 py-3 shadow-sm\",\n successMessageClassName,\n )}\n role=\"status\"\n aria-live=\"polite\"\n >\n {renderMessage(\n successMessage,\n \"text-primary-foreground\",\n \"text-primary-foreground\",\n )}\n </div>\n ) : null}\n\n {submissionError ? (\n <div\n className={cn(\n \"rounded-md border border-destructive bg-destructive px-4 py-3 shadow-sm\",\n errorMessageClassName,\n )}\n role=\"alert\"\n aria-live=\"assertive\"\n >\n {renderMessage(\n submissionError,\n \"text-destructive-foreground\",\n \"text-destructive-foreground\",\n )}\n </div>\n ) : null}\n </>\n );\n}\n\nFormFeedback.displayName = \"FormFeedback\";\n","import * as React from \"react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\nimport { Slot } from \"radix-ui\"\n\nimport { cn } from \"../../lib/utils\"\nimport { Separator } from \"./separator\"\n\nconst buttonGroupVariants = cva(\n \"flex w-fit items-stretch [&>*]:focus-visible:z-10 [&>*]:focus-visible:relative [&>[data-slot=select-trigger]:not([class*='w-'])]:w-fit [&>input]:flex-1 has-[select[aria-hidden=true]:last-child]:[&>[data-slot=select-trigger]:last-of-type]:rounded-r-md has-[>[data-slot=button-group]]:gap-2\",\n {\n variants: {\n orientation: {\n horizontal:\n \"[&>*:not(:first-child)]:rounded-l-none [&>*:not(:first-child)]:border-l-0 [&>*:not(:last-child)]:rounded-r-none\",\n vertical:\n \"flex-col [&>*:not(:first-child)]:rounded-t-none [&>*:not(:first-child)]:border-t-0 [&>*:not(:last-child)]:rounded-b-none\",\n },\n },\n defaultVariants: {\n orientation: \"horizontal\",\n },\n }\n)\n\nfunction ButtonGroup({\n className,\n orientation,\n ...props\n}: React.ComponentProps<\"div\"> & VariantProps<typeof buttonGroupVariants>) {\n return (\n <div\n role=\"group\"\n data-slot=\"button-group\"\n data-orientation={orientation}\n className={cn(buttonGroupVariants({ orientation }), className)}\n {...props}\n />\n )\n}\n\nfunction ButtonGroupText({\n className,\n asChild = false,\n ...props\n}: React.ComponentProps<\"div\"> & {\n asChild?: boolean\n}) {\n const Comp = asChild ? Slot.Root : \"div\"\n\n return (\n <Comp\n className={cn(\n \"bg-muted flex items-center gap-2 rounded-md border px-4 text-sm font-medium shadow-xs [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction ButtonGroupSeparator({\n className,\n orientation = \"vertical\",\n ...props\n}: React.ComponentProps<typeof Separator>) {\n return (\n <Separator\n data-slot=\"button-group-separator\"\n orientation={orientation}\n className={cn(\n \"bg-input relative !m-0 self-stretch data-[orientation=vertical]:h-auto\",\n className\n )}\n {...props}\n />\n )\n}\n\nexport {\n ButtonGroup,\n ButtonGroupSeparator,\n ButtonGroupText,\n buttonGroupVariants,\n}\n","\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { Button } from \"../components/ui/button\";\nimport { ButtonGroup } from \"../components/ui/button-group\";\nimport { FieldLabel } from \"../components/ui/field\";\nimport { TextInput } from \"../inputs/TextInput\";\nimport type { InputProps } from \"./types\";\nimport { Icon } from \"@page-speed/icon\";\n\nconst DEFAULT_ICON_API_KEY = \"au382bi7fsh96w9h9xlrnat2jglx\";\n\nexport type ButtonGroupFormSize = \"xs\" | \"sm\" | \"default\" | \"lg\";\n\nexport type ButtonGroupFormProps = {\n /**\n * Field name\n */\n name: string;\n /**\n * Optional label above the input\n */\n label?: React.ReactNode;\n /**\n * Placeholder text for the input\n */\n placeholder?: string;\n /**\n * Input props from form field\n */\n inputProps: InputProps<string> & {\n type?: \"text\" | \"email\" | \"password\" | \"url\" | \"tel\" | \"search\";\n };\n /**\n * Submit button label\n */\n submitLabel?: React.ReactNode;\n /**\n * Submit button size\n */\n size?: ButtonGroupFormSize;\n /**\n * Submit button variant\n */\n submitVariant?:\n | \"link\"\n | \"default\"\n | \"destructive\"\n | \"outline\"\n | \"secondary\"\n | \"ghost\"\n | null\n | undefined;\n /**\n * Whether form is submitting\n */\n isSubmitting?: boolean;\n /**\n * Additional className for the container\n */\n className?: string;\n /**\n * Icon name for icon based submit buttons\n */\n submitIconName?: string;\n /**\n * Additional className for the label\n */\n labelClassName?: string;\n};\n\n/**\n * ButtonGroupForm - Inline form layout with input and submit button grouped together\n *\n * Commonly used for newsletter signups and other simple single-field forms.\n * The input and button automatically adjust sizing together.\n *\n * Size mappings:\n * - xs: h-8 text-xs\n * - sm: h-9 text-sm\n * - default: h-10 text-sm\n * - lg: h-12 text-base\n *\n * @example\n * ```tsx\n * <ButtonGroupForm\n * name=\"email\"\n * placeholder=\"Enter your email\"\n * inputProps={form.getFieldProps('email')}\n * submitLabel=\"Subscribe\"\n * size=\"default\"\n * />\n * ```\n */\nexport function ButtonGroupForm({\n name,\n label,\n inputProps,\n submitLabel = \"Submit\",\n submitVariant = \"default\",\n size = \"default\",\n isSubmitting = false,\n submitIconName,\n className,\n labelClassName,\n}: ButtonGroupFormProps) {\n const inputId = `button-group-input-${name}`;\n\n const hasValue = String(inputProps.value ?? \"\").trim().length > 0;\n const hasError = !!inputProps.error;\n\n const buttonSize:\n | \"xs\"\n | \"sm\"\n | \"default\"\n | \"lg\"\n | \"icon\"\n | \"icon-xs\"\n | \"icon-sm\"\n | \"icon-lg\" = React.useMemo(() => {\n if (submitIconName) {\n return size === \"default\" ? \"icon\" : (`icon-${size}` as const);\n }\n return size;\n }, [submitIconName, size]);\n\n // Size-specific classes for input to match button heights\n const inputSizeClasses = {\n xs: \"text-xs px-3\",\n sm: \"text-sm px-3\",\n default: \"text-base px-4\",\n lg: \"text-md px-6\",\n };\n\n return (\n <div className={cn(\"space-y-2\", className)}>\n {label && (\n <FieldLabel htmlFor={inputId} className={labelClassName}>\n {label}\n </FieldLabel>\n )}\n <ButtonGroup>\n <TextInput\n {...inputProps}\n id={inputId}\n className={cn(\n inputSizeClasses[size],\n \"border-r-0 rounded-r-none focus-visible:z-10\",\n inputProps.className,\n )}\n />\n <Button\n size={buttonSize}\n type=\"submit\"\n variant={submitVariant}\n disabled={isSubmitting}\n className={cn(\n \"rounded-l-none\",\n !hasError && hasValue && \"ring-2 ring-ring\",\n )}\n >\n {submitIconName ? (\n <Icon name={submitIconName} apiKey={DEFAULT_ICON_API_KEY} />\n ) : (\n submitLabel\n )}\n </Button>\n </ButtonGroup>\n </div>\n );\n}\n\nButtonGroupForm.displayName = \"ButtonGroupForm\";\n","\"use client\";\n\nimport * as React from \"react\";\nimport { FormContext } from \"./FormContext\";\nimport type { FormProps, FormValues } from \"./types\";\nimport { FormFeedback } from \"./form-feedback\";\nimport { Button } from \"../components/ui/button\";\nimport { ButtonGroupForm } from \"./button-group-form\";\nimport type { FormFieldConfig } from \"../integration/form-field-types\";\n\n/**\n * Form - Progressive enhancement form component\n *\n * Provides form context to child components and handles form submission.\n * Supports progressive enhancement with server-side fallback.\n *\n * Features:\n * - Provides FormContext for useField hook\n * - Handles form submission with validation\n * - Progressive enhancement support (works without JavaScript)\n * - Accessible form semantics\n *\n * @example\n * ```tsx\n * const form = useForm({\n * initialValues: { email: '' },\n * onSubmit: async (values) => {\n * await submitForm(values);\n * },\n * });\n *\n * return (\n * <Form form={form} action=\"/api/submit\" method=\"post\">\n * <input {...form.getFieldProps('email')} />\n * <button type=\"submit\">Submit</button>\n * </Form>\n * );\n * ```\n *\n * @see https://opensite.ai/developers/page-speed/forms/form\n */\nexport function Form<T extends FormValues = FormValues>({\n form,\n children,\n fields,\n className,\n action,\n method,\n noValidate = true,\n submissionConfig,\n successMessage,\n submissionError,\n successMessageClassName,\n errorMessageClassName,\n onNewSubmission,\n notificationConfig,\n styleConfig,\n formConfig,\n ...props\n}: FormProps<T> & React.FormHTMLAttributes<HTMLFormElement>) {\n // Wrap handleSubmit to catch any unhandled rejections\n const handleFormSubmit = React.useCallback(\n async (e: React.FormEvent) => {\n try {\n await form.handleSubmit(e);\n } catch {\n // Error is already handled by useForm, just prevent unhandled rejection\n // The form status and errors are already set by useForm's error handling\n }\n },\n [form],\n );\n\n const resolvedClassName = className ?? styleConfig?.formClassName;\n const resolvedAction = action ?? formConfig?.endpoint;\n const resolvedMethod = method ?? formConfig?.method ?? \"post\";\n const resolvedSubmissionConfig =\n submissionConfig ?? formConfig?.submissionConfig;\n const resolvedSuccessMessage =\n successMessage ?? notificationConfig?.successMessage;\n const resolvedSubmissionError =\n submissionError ?? notificationConfig?.submissionError;\n const resolvedSuccessMessageClassName =\n successMessageClassName ?? styleConfig?.successMessageClassName;\n const resolvedErrorMessageClassName =\n errorMessageClassName ?? styleConfig?.errorMessageClassName;\n\n const behavior = resolvedSubmissionConfig?.behavior || \"showConfirmation\";\n\n const shouldManageSubmissionUi =\n resolvedSubmissionConfig !== undefined ||\n resolvedSuccessMessage !== undefined ||\n resolvedSuccessMessageClassName !== undefined ||\n resolvedErrorMessageClassName !== undefined ||\n resolvedSubmissionError != null ||\n onNewSubmission !== undefined;\n\n const hasSubmissionError = Boolean(resolvedSubmissionError);\n\n const isSubmissionSuccessful =\n shouldManageSubmissionUi &&\n form.status === \"success\" &&\n !hasSubmissionError;\n\n const defaultSuccessMessage =\n behavior === \"redirect\"\n ? \"Form submitted successfully. Redirecting...\"\n : \"Thank you. Your form has been submitted successfully.\";\n\n const finalSuccessMessage = resolvedSuccessMessage ?? defaultSuccessMessage;\n\n const shouldRenderCustomComponent =\n isSubmissionSuccessful &&\n behavior === \"renderCustomComponent\" &&\n Boolean(resolvedSubmissionConfig?.customComponent);\n\n const newSubmissionAction = resolvedSubmissionConfig?.newFormSubmissionAction;\n\n const showNewSubmissionAction =\n isSubmissionSuccessful &&\n (typeof newSubmissionAction?.enable === \"boolean\"\n ? newSubmissionAction.enable\n : Boolean(newSubmissionAction?.label));\n\n const newSubmissionLabel =\n newSubmissionAction?.label ?? \"Submit another response\";\n\n const handleNewSubmission = React.useCallback(() => {\n form.resetForm();\n onNewSubmission?.();\n }, [form, onNewSubmission]);\n\n // Check if we should use button-group layout\n const formLayout = formConfig?.formLayout ?? \"standard\";\n const isButtonGroupLayout = formLayout === \"button-group\";\n const hasTextField =\n fields &&\n fields.length === 1 &&\n fields[0] &&\n [\"text\", \"email\", \"password\", \"url\", \"tel\", \"search\"].includes(\n fields[0].type,\n );\n const shouldUseButtonGroup = isButtonGroupLayout && hasTextField;\n\n // Render button-group layout if conditions are met\n const buttonGroupContent = React.useMemo(() => {\n if (!shouldUseButtonGroup || !fields || fields.length === 0) return null;\n\n const field = fields[0] as FormFieldConfig;\n const fieldProps = form.getFieldProps(field.name);\n\n return (\n <ButtonGroupForm\n name={field.name}\n label={field.label}\n inputProps={{\n name: fieldProps.name,\n value: fieldProps.value as string,\n onChange: fieldProps.onChange as (value: string) => void,\n onBlur: fieldProps.onBlur,\n type: field.type as\n | \"text\"\n | \"email\"\n | \"password\"\n | \"url\"\n | \"tel\"\n | \"search\",\n placeholder: field.placeholder,\n required: field.required,\n disabled: field.disabled,\n }}\n submitLabel={formConfig?.submitLabel}\n submitVariant={formConfig?.submitVariant}\n submitIconName={formConfig?.submitIconName}\n size={formConfig?.buttonGroupSize}\n isSubmitting={form.isSubmitting}\n />\n );\n }, [shouldUseButtonGroup, fields, form, formConfig]);\n\n return (\n <FormContext.Provider value={form}>\n <form\n onSubmit={handleFormSubmit}\n action={resolvedAction}\n method={resolvedMethod}\n noValidate={noValidate}\n className={resolvedClassName}\n {...props}\n >\n {isSubmissionSuccessful ? (\n <div className=\"space-y-4\">\n {shouldRenderCustomComponent ? (\n resolvedSubmissionConfig?.customComponent\n ) : (\n <FormFeedback\n successMessage={finalSuccessMessage}\n successMessageClassName={resolvedSuccessMessageClassName}\n />\n )}\n\n {showNewSubmissionAction ? (\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={handleNewSubmission}\n >\n {newSubmissionLabel}\n </Button>\n ) : null}\n </div>\n ) : (\n <>\n {shouldUseButtonGroup ? buttonGroupContent : children}\n {resolvedSubmissionError ? (\n <div className=\"mt-4\">\n <FormFeedback\n submissionError={resolvedSubmissionError}\n errorMessageClassName={resolvedErrorMessageClassName}\n />\n </div>\n ) : null}\n </>\n )}\n </form>\n </FormContext.Provider>\n );\n}\n\nForm.displayName = \"Form\";\n"]}