@page-speed/forms 0.5.7 → 0.5.9

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 (53) hide show
  1. package/dist/FormContext-089h0j0Q.d.ts +153 -0
  2. package/dist/FormContext-iHzBALZa.d.cts +153 -0
  3. package/dist/{chunk-A7R6GEMA.js → chunk-455PI4LV.js} +84 -3
  4. package/dist/chunk-455PI4LV.js.map +1 -0
  5. package/dist/{chunk-5WWMVS2I.js → chunk-4ROWNTY6.js} +334 -415
  6. package/dist/chunk-4ROWNTY6.js.map +1 -0
  7. package/dist/{chunk-FIDKDYT7.cjs → chunk-ED4UK63G.cjs} +439 -521
  8. package/dist/chunk-ED4UK63G.cjs.map +1 -0
  9. package/dist/{chunk-Q7VR374Y.js → chunk-MJYEXJ3U.js} +3 -3
  10. package/dist/{chunk-Q7VR374Y.js.map → chunk-MJYEXJ3U.js.map} +1 -1
  11. package/dist/{chunk-KPHMVGTU.cjs → chunk-MUBEMXI7.cjs} +6 -6
  12. package/dist/{chunk-KPHMVGTU.cjs.map → chunk-MUBEMXI7.cjs.map} +1 -1
  13. package/dist/chunk-OF6ZYT7A.cjs +287 -0
  14. package/dist/chunk-OF6ZYT7A.cjs.map +1 -0
  15. package/dist/{chunk-QQSBW6N3.cjs → chunk-QRI5TMES.cjs} +85 -2
  16. package/dist/chunk-QRI5TMES.cjs.map +1 -0
  17. package/dist/chunk-TOPOO33Z.js +263 -0
  18. package/dist/chunk-TOPOO33Z.js.map +1 -0
  19. package/dist/core.cjs +13 -9
  20. package/dist/core.d.cts +66 -141
  21. package/dist/core.d.ts +66 -141
  22. package/dist/core.js +3 -3
  23. package/dist/index.cjs +14 -14
  24. package/dist/index.d.cts +2 -2
  25. package/dist/index.d.ts +2 -2
  26. package/dist/index.js +3 -3
  27. package/dist/inputs.cjs +16 -16
  28. package/dist/inputs.d.cts +1 -1
  29. package/dist/inputs.d.ts +1 -1
  30. package/dist/inputs.js +2 -2
  31. package/dist/integration.cjs +17 -17
  32. package/dist/integration.d.cts +1 -1
  33. package/dist/integration.d.ts +1 -1
  34. package/dist/integration.js +3 -3
  35. package/dist/{types-CnOCn7b3.d.ts → types-BemGfSPA.d.cts} +27 -1
  36. package/dist/{types-CnOCn7b3.d.cts → types-BemGfSPA.d.ts} +27 -1
  37. package/dist/validation-rules.d.cts +1 -1
  38. package/dist/validation-rules.d.ts +1 -1
  39. package/dist/validation-utils.d.cts +1 -1
  40. package/dist/validation-utils.d.ts +1 -1
  41. package/dist/validation-valibot.d.cts +1 -1
  42. package/dist/validation-valibot.d.ts +1 -1
  43. package/dist/validation.d.cts +1 -1
  44. package/dist/validation.d.ts +1 -1
  45. package/package.json +1 -1
  46. package/dist/chunk-5WWMVS2I.js.map +0 -1
  47. package/dist/chunk-A7R6GEMA.js.map +0 -1
  48. package/dist/chunk-FIDKDYT7.cjs.map +0 -1
  49. package/dist/chunk-N2HOVRRN.js +0 -150
  50. package/dist/chunk-N2HOVRRN.js.map +0 -1
  51. package/dist/chunk-O4ZLR7AN.cjs +0 -173
  52. package/dist/chunk-O4ZLR7AN.cjs.map +0 -1
  53. package/dist/chunk-QQSBW6N3.cjs.map +0 -1
@@ -0,0 +1,263 @@
1
+ import { FormContext } from './chunk-MJYEXJ3U.js';
2
+ import { cn, FieldLabel, TextInput, Button } from './chunk-455PI4LV.js';
3
+ import * as React4 from 'react';
4
+ import { cva } from 'class-variance-authority';
5
+ import 'radix-ui';
6
+
7
+ function renderMessage(message, fallbackClassName, className) {
8
+ if (typeof message === "string") {
9
+ return /* @__PURE__ */ React4.createElement(
10
+ "p",
11
+ {
12
+ className: cn(
13
+ "text-sm font-medium text-center text-balance",
14
+ className
15
+ )
16
+ },
17
+ message
18
+ );
19
+ }
20
+ return /* @__PURE__ */ React4.createElement("div", { className: cn(fallbackClassName, className) }, message);
21
+ }
22
+ function FormFeedback({
23
+ successMessage,
24
+ submissionError,
25
+ successMessageClassName,
26
+ errorMessageClassName
27
+ }) {
28
+ if (!successMessage && !submissionError) {
29
+ return null;
30
+ }
31
+ return /* @__PURE__ */ React4.createElement(React4.Fragment, null, successMessage ? /* @__PURE__ */ React4.createElement(
32
+ "div",
33
+ {
34
+ className: cn(
35
+ "rounded-md border border-primary bg-primary px-4 py-3 shadow-sm",
36
+ successMessageClassName
37
+ ),
38
+ role: "status",
39
+ "aria-live": "polite"
40
+ },
41
+ renderMessage(
42
+ successMessage,
43
+ "text-primary-foreground",
44
+ "text-primary-foreground"
45
+ )
46
+ ) : null, submissionError ? /* @__PURE__ */ React4.createElement(
47
+ "div",
48
+ {
49
+ className: cn(
50
+ "rounded-md border border-destructive bg-destructive px-4 py-3 shadow-sm",
51
+ errorMessageClassName
52
+ ),
53
+ role: "alert",
54
+ "aria-live": "assertive"
55
+ },
56
+ renderMessage(
57
+ submissionError,
58
+ "text-destructive-foreground",
59
+ "text-destructive-foreground"
60
+ )
61
+ ) : null);
62
+ }
63
+ FormFeedback.displayName = "FormFeedback";
64
+ var buttonGroupVariants = cva(
65
+ "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",
66
+ {
67
+ variants: {
68
+ orientation: {
69
+ horizontal: "[&>*:not(:first-child)]:rounded-l-none [&>*:not(:first-child)]:border-l-0 [&>*:not(:last-child)]:rounded-r-none",
70
+ vertical: "flex-col [&>*:not(:first-child)]:rounded-t-none [&>*:not(:first-child)]:border-t-0 [&>*:not(:last-child)]:rounded-b-none"
71
+ }
72
+ },
73
+ defaultVariants: {
74
+ orientation: "horizontal"
75
+ }
76
+ }
77
+ );
78
+ function ButtonGroup({
79
+ className,
80
+ orientation,
81
+ ...props
82
+ }) {
83
+ return /* @__PURE__ */ React4.createElement(
84
+ "div",
85
+ {
86
+ role: "group",
87
+ "data-slot": "button-group",
88
+ "data-orientation": orientation,
89
+ className: cn(buttonGroupVariants({ orientation }), className),
90
+ ...props
91
+ }
92
+ );
93
+ }
94
+
95
+ // src/core/button-group-form.tsx
96
+ function ButtonGroupForm({
97
+ name,
98
+ label,
99
+ inputProps,
100
+ submitLabel = "Submit",
101
+ submitVariant = "default",
102
+ size = "default",
103
+ isSubmitting = false,
104
+ className,
105
+ labelClassName
106
+ }) {
107
+ const inputId = `button-group-input-${name}`;
108
+ const inputSizeClasses = {
109
+ xs: "h-8 text-xs px-3",
110
+ sm: "h-9 text-sm px-3",
111
+ default: "h-10 text-sm px-4",
112
+ lg: "h-12 text-base px-6"
113
+ };
114
+ const buttonSizes = {
115
+ xs: "xs",
116
+ sm: "sm",
117
+ default: "default",
118
+ lg: "lg"
119
+ };
120
+ return /* @__PURE__ */ React4.createElement("div", { className: cn("space-y-2", className) }, label && /* @__PURE__ */ React4.createElement(FieldLabel, { htmlFor: inputId, className: labelClassName }, label), /* @__PURE__ */ React4.createElement(ButtonGroup, null, /* @__PURE__ */ React4.createElement(
121
+ TextInput,
122
+ {
123
+ ...inputProps,
124
+ id: inputId,
125
+ className: cn(
126
+ inputSizeClasses[size],
127
+ "border-r-0 rounded-r-none focus-visible:z-10",
128
+ inputProps.className
129
+ )
130
+ }
131
+ ), /* @__PURE__ */ React4.createElement(
132
+ Button,
133
+ {
134
+ size: buttonSizes[size],
135
+ type: "submit",
136
+ variant: submitVariant,
137
+ disabled: isSubmitting,
138
+ className: "rounded-l-none"
139
+ },
140
+ submitLabel
141
+ )));
142
+ }
143
+ ButtonGroupForm.displayName = "ButtonGroupForm";
144
+
145
+ // src/core/Form.tsx
146
+ function Form({
147
+ form,
148
+ children,
149
+ fields,
150
+ className,
151
+ action,
152
+ method,
153
+ noValidate = true,
154
+ submissionConfig,
155
+ successMessage,
156
+ submissionError,
157
+ successMessageClassName,
158
+ errorMessageClassName,
159
+ onNewSubmission,
160
+ notificationConfig,
161
+ styleConfig,
162
+ formConfig,
163
+ ...props
164
+ }) {
165
+ const handleFormSubmit = React4.useCallback(
166
+ async (e) => {
167
+ try {
168
+ await form.handleSubmit(e);
169
+ } catch {
170
+ }
171
+ },
172
+ [form]
173
+ );
174
+ const resolvedClassName = className ?? styleConfig?.formClassName;
175
+ const resolvedAction = action ?? formConfig?.endpoint;
176
+ const resolvedMethod = method ?? formConfig?.method ?? "post";
177
+ const resolvedSubmissionConfig = submissionConfig ?? formConfig?.submissionConfig;
178
+ const resolvedSuccessMessage = successMessage ?? notificationConfig?.successMessage;
179
+ const resolvedSubmissionError = submissionError ?? notificationConfig?.submissionError;
180
+ const resolvedSuccessMessageClassName = successMessageClassName ?? styleConfig?.successMessageClassName;
181
+ const resolvedErrorMessageClassName = errorMessageClassName ?? styleConfig?.errorMessageClassName;
182
+ const behavior = resolvedSubmissionConfig?.behavior || "showConfirmation";
183
+ const shouldManageSubmissionUi = resolvedSubmissionConfig !== void 0 || resolvedSuccessMessage !== void 0 || resolvedSuccessMessageClassName !== void 0 || resolvedErrorMessageClassName !== void 0 || resolvedSubmissionError != null || onNewSubmission !== void 0;
184
+ const hasSubmissionError = Boolean(resolvedSubmissionError);
185
+ const isSubmissionSuccessful = shouldManageSubmissionUi && form.status === "success" && !hasSubmissionError;
186
+ const defaultSuccessMessage = behavior === "redirect" ? "Form submitted successfully. Redirecting..." : "Thank you. Your form has been submitted successfully.";
187
+ const finalSuccessMessage = resolvedSuccessMessage ?? defaultSuccessMessage;
188
+ const shouldRenderCustomComponent = isSubmissionSuccessful && behavior === "renderCustomComponent" && Boolean(resolvedSubmissionConfig?.customComponent);
189
+ const newSubmissionAction = resolvedSubmissionConfig?.newFormSubmissionAction;
190
+ const showNewSubmissionAction = isSubmissionSuccessful && (typeof newSubmissionAction?.enable === "boolean" ? newSubmissionAction.enable : Boolean(newSubmissionAction?.label));
191
+ const newSubmissionLabel = newSubmissionAction?.label ?? "Submit another response";
192
+ const handleNewSubmission = React4.useCallback(() => {
193
+ form.resetForm();
194
+ onNewSubmission?.();
195
+ }, [form, onNewSubmission]);
196
+ const formLayout = formConfig?.formLayout ?? "standard";
197
+ const isButtonGroupLayout = formLayout === "button-group";
198
+ const hasTextField = fields && fields.length === 1 && fields[0] && ["text", "email", "password", "url", "tel", "search"].includes(fields[0].type);
199
+ const shouldUseButtonGroup = isButtonGroupLayout && hasTextField;
200
+ const buttonGroupContent = React4.useMemo(() => {
201
+ if (!shouldUseButtonGroup || !fields || fields.length === 0) return null;
202
+ const field = fields[0];
203
+ const fieldProps = form.getFieldProps(field.name);
204
+ return /* @__PURE__ */ React4.createElement(
205
+ ButtonGroupForm,
206
+ {
207
+ name: field.name,
208
+ label: field.label,
209
+ inputProps: {
210
+ name: fieldProps.name,
211
+ value: fieldProps.value,
212
+ onChange: fieldProps.onChange,
213
+ onBlur: fieldProps.onBlur,
214
+ type: field.type,
215
+ placeholder: field.placeholder,
216
+ required: field.required,
217
+ disabled: field.disabled
218
+ },
219
+ submitLabel: formConfig?.submitLabel,
220
+ submitVariant: formConfig?.submitVariant,
221
+ size: formConfig?.buttonGroupSize,
222
+ isSubmitting: form.isSubmitting
223
+ }
224
+ );
225
+ }, [shouldUseButtonGroup, fields, form, formConfig]);
226
+ return /* @__PURE__ */ React4.createElement(FormContext.Provider, { value: form }, /* @__PURE__ */ React4.createElement(
227
+ "form",
228
+ {
229
+ onSubmit: handleFormSubmit,
230
+ action: resolvedAction,
231
+ method: resolvedMethod,
232
+ noValidate,
233
+ className: resolvedClassName,
234
+ ...props
235
+ },
236
+ isSubmissionSuccessful ? /* @__PURE__ */ React4.createElement("div", { className: "space-y-4" }, shouldRenderCustomComponent ? resolvedSubmissionConfig?.customComponent : /* @__PURE__ */ React4.createElement(
237
+ FormFeedback,
238
+ {
239
+ successMessage: finalSuccessMessage,
240
+ successMessageClassName: resolvedSuccessMessageClassName
241
+ }
242
+ ), showNewSubmissionAction ? /* @__PURE__ */ React4.createElement(
243
+ Button,
244
+ {
245
+ type: "button",
246
+ variant: "outline",
247
+ onClick: handleNewSubmission
248
+ },
249
+ newSubmissionLabel
250
+ ) : null) : /* @__PURE__ */ React4.createElement(React4.Fragment, null, shouldUseButtonGroup ? buttonGroupContent : children, resolvedSubmissionError ? /* @__PURE__ */ React4.createElement("div", { className: "mt-4" }, /* @__PURE__ */ React4.createElement(
251
+ FormFeedback,
252
+ {
253
+ submissionError: resolvedSubmissionError,
254
+ errorMessageClassName: resolvedErrorMessageClassName
255
+ }
256
+ )) : null)
257
+ ));
258
+ }
259
+ Form.displayName = "Form";
260
+
261
+ export { ButtonGroupForm, Form, FormFeedback };
262
+ //# sourceMappingURL=chunk-TOPOO33Z.js.map
263
+ //# sourceMappingURL=chunk-TOPOO33Z.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-TOPOO33Z.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\";\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 * 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 className,\n labelClassName,\n}: ButtonGroupFormProps) {\n const inputId = `button-group-input-${name}`;\n\n // Size-specific classes for input to match button heights\n const inputSizeClasses = {\n xs: \"h-8 text-xs px-3\",\n sm: \"h-9 text-sm px-3\",\n default: \"h-10 text-sm px-4\",\n lg: \"h-12 text-base px-6\",\n };\n\n // Map button group sizes to button sizes\n const buttonSizes: Record<ButtonGroupFormSize, \"xs\" | \"sm\" | \"default\" | \"lg\"> = {\n xs: \"xs\",\n sm: \"sm\",\n default: \"default\",\n lg: \"lg\",\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={buttonSizes[size]}\n type=\"submit\"\n variant={submitVariant}\n disabled={isSubmitting}\n className=\"rounded-l-none\"\n >\n {submitLabel}\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 = 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 = fields && fields.length === 1 && fields[0] &&\n [\"text\", \"email\", \"password\", \"url\", \"tel\", \"search\"].includes(fields[0].type);\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 \"text\" | \"email\" | \"password\" | \"url\" | \"tel\" | \"search\",\n placeholder: field.placeholder,\n required: field.required,\n disabled: field.disabled,\n }}\n submitLabel={formConfig?.submitLabel}\n submitVariant={formConfig?.submitVariant}\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,34 +1,38 @@
1
1
  'use strict';
2
2
 
3
- var chunkO4ZLR7AN_cjs = require('./chunk-O4ZLR7AN.cjs');
4
- var chunkKPHMVGTU_cjs = require('./chunk-KPHMVGTU.cjs');
5
- require('./chunk-QQSBW6N3.cjs');
3
+ var chunkOF6ZYT7A_cjs = require('./chunk-OF6ZYT7A.cjs');
4
+ var chunkMUBEMXI7_cjs = require('./chunk-MUBEMXI7.cjs');
5
+ require('./chunk-QRI5TMES.cjs');
6
6
 
7
7
 
8
8
 
9
+ Object.defineProperty(exports, "ButtonGroupForm", {
10
+ enumerable: true,
11
+ get: function () { return chunkOF6ZYT7A_cjs.ButtonGroupForm; }
12
+ });
9
13
  Object.defineProperty(exports, "Form", {
10
14
  enumerable: true,
11
- get: function () { return chunkO4ZLR7AN_cjs.Form; }
15
+ get: function () { return chunkOF6ZYT7A_cjs.Form; }
12
16
  });
13
17
  Object.defineProperty(exports, "FormFeedback", {
14
18
  enumerable: true,
15
- get: function () { return chunkO4ZLR7AN_cjs.FormFeedback; }
19
+ get: function () { return chunkOF6ZYT7A_cjs.FormFeedback; }
16
20
  });
17
21
  Object.defineProperty(exports, "Field", {
18
22
  enumerable: true,
19
- get: function () { return chunkKPHMVGTU_cjs.Field; }
23
+ get: function () { return chunkMUBEMXI7_cjs.Field; }
20
24
  });
21
25
  Object.defineProperty(exports, "FormContext", {
22
26
  enumerable: true,
23
- get: function () { return chunkKPHMVGTU_cjs.FormContext; }
27
+ get: function () { return chunkMUBEMXI7_cjs.FormContext; }
24
28
  });
25
29
  Object.defineProperty(exports, "useField", {
26
30
  enumerable: true,
27
- get: function () { return chunkKPHMVGTU_cjs.useField; }
31
+ get: function () { return chunkMUBEMXI7_cjs.useField; }
28
32
  });
29
33
  Object.defineProperty(exports, "useForm", {
30
34
  enumerable: true,
31
- get: function () { return chunkKPHMVGTU_cjs.useForm; }
35
+ get: function () { return chunkMUBEMXI7_cjs.useForm; }
32
36
  });
33
37
  //# sourceMappingURL=core.cjs.map
34
38
  //# sourceMappingURL=core.cjs.map
package/dist/core.d.cts CHANGED
@@ -1,154 +1,79 @@
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-CnOCn7b3.cjs';
2
- export { E as ErrorHandler, n as FieldInputProps, o as FieldMeta, F as FieldValidator, l as FormActions, c as FormErrors, i as FormHelpers, f as FormNotificationConfig, h as FormRenderConfig, k as FormState, g as FormStyleConfig, d as FormSubmissionBehavior, e as FormSubmissionConfig, I as InputProps, N as NewFormSubmissionActionConfig, S as SubmissionStatus, j as SubmitHandler, T as TouchedFields, a as ValidationMode, V as ValidationSchema } from './types-CnOCn7b3.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-iHzBALZa.cjs';
3
2
  import * as React from 'react';
3
+ import { I as InputProps } from './types-BemGfSPA.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-BemGfSPA.cjs';
4
5
 
6
+ type ButtonGroupFormSize = "xs" | "sm" | "default" | "lg";
7
+ type ButtonGroupFormProps = {
8
+ /**
9
+ * Field name
10
+ */
11
+ name: string;
12
+ /**
13
+ * Optional label above the input
14
+ */
15
+ label?: React.ReactNode;
16
+ /**
17
+ * Placeholder text for the input
18
+ */
19
+ placeholder?: string;
20
+ /**
21
+ * Input props from form field
22
+ */
23
+ inputProps: InputProps<string> & {
24
+ type?: "text" | "email" | "password" | "url" | "tel" | "search";
25
+ };
26
+ /**
27
+ * Submit button label
28
+ */
29
+ submitLabel?: React.ReactNode;
30
+ /**
31
+ * Submit button size
32
+ */
33
+ size?: ButtonGroupFormSize;
34
+ /**
35
+ * Submit button variant
36
+ */
37
+ submitVariant?: "link" | "default" | "destructive" | "outline" | "secondary" | "ghost" | null | undefined;
38
+ /**
39
+ * Whether form is submitting
40
+ */
41
+ isSubmitting?: boolean;
42
+ /**
43
+ * Additional className for the container
44
+ */
45
+ className?: string;
46
+ /**
47
+ * Additional className for the label
48
+ */
49
+ labelClassName?: string;
50
+ };
5
51
  /**
6
- * useForm - High-performance form state management with field-level reactivity
52
+ * ButtonGroupForm - Inline form layout with input and submit button grouped together
7
53
  *
8
- * Built on @legendapp/state for optimal performance:
9
- * - Field-level reactivity: Only re-render the specific field that changed
10
- * - Observable-based state: ~1 re-render per change vs ~10 for traditional hooks
11
- * - Tree-shakable: Only bundle what you use
54
+ * Commonly used for newsletter signups and other simple single-field forms.
55
+ * The input and button automatically adjust sizing together.
12
56
  *
13
- * @example
14
- * ```tsx
15
- * const form = useForm({
16
- * initialValues: { email: '', password: '' },
17
- * onSubmit: async (values) => {
18
- * await login(values);
19
- * },
20
- * validationSchema: {
21
- * email: (value) => !value ? 'Required' : undefined,
22
- * password: (value) => value.length < 8 ? 'Too short' : undefined,
23
- * },
24
- * });
25
- *
26
- * return (
27
- * <form onSubmit={form.handleSubmit}>
28
- * <input {...form.getFieldProps('email')} />
29
- * {form.errors.email && <span>{form.errors.email}</span>}
30
- * </form>
31
- * );
32
- * ```
33
- *
34
- * @see https://opensite.ai/developers/page-speed/forms/use-form
35
- */
36
- declare function useForm<T extends FormValues = FormValues>(options: UseFormOptions<T>): UseFormReturn<T>;
37
-
38
- /**
39
- * useField - Field-level reactive hook for form inputs
40
- *
41
- * Provides isolated reactivity for individual form fields.
42
- * Only re-renders when the specific field changes, not when other fields update.
43
- *
44
- * Must be used within a FormContext (inside <Form> component).
45
- *
46
- * @example
47
- * ```tsx
48
- * function EmailInput() {
49
- * const { field, meta, helpers } = useField({ name: 'email' });
50
- *
51
- * return (
52
- * <div>
53
- * <input {...field} type="email" />
54
- * {meta.touched && meta.error && <span>{meta.error}</span>}
55
- * </div>
56
- * );
57
- * }
58
- * ```
59
- *
60
- * @see https://opensite.ai/developers/page-speed/forms/use-field
61
- */
62
- declare function useField<T = any>(options: UseFieldOptions<T>): UseFieldReturn<T>;
63
-
64
- /**
65
- * Form - Progressive enhancement form component
66
- *
67
- * Provides form context to child components and handles form submission.
68
- * Supports progressive enhancement with server-side fallback.
69
- *
70
- * Features:
71
- * - Provides FormContext for useField hook
72
- * - Handles form submission with validation
73
- * - Progressive enhancement support (works without JavaScript)
74
- * - Accessible form semantics
75
- *
76
- * @example
77
- * ```tsx
78
- * const form = useForm({
79
- * initialValues: { email: '' },
80
- * onSubmit: async (values) => {
81
- * await submitForm(values);
82
- * },
83
- * });
84
- *
85
- * return (
86
- * <Form form={form} action="/api/submit" method="post">
87
- * <input {...form.getFieldProps('email')} />
88
- * <button type="submit">Submit</button>
89
- * </Form>
90
- * );
91
- * ```
92
- *
93
- * @see https://opensite.ai/developers/page-speed/forms/form
94
- */
95
- declare function Form<T extends FormValues = FormValues>({ form, children, className, action, method, noValidate, submissionConfig, successMessage, submissionError, successMessageClassName, errorMessageClassName, onNewSubmission, notificationConfig, styleConfig, formConfig, ...props }: FormProps<T> & React.FormHTMLAttributes<HTMLFormElement>): React.JSX.Element;
96
- declare namespace Form {
97
- var displayName: string;
98
- }
99
-
100
- /**
101
- * Field - Field wrapper component with label, description, and error display
102
- *
103
- * Provides a complete field UI with automatic error handling and accessibility.
104
- * Uses useField hook internally for field-level reactivity.
105
- *
106
- * Features:
107
- * - Automatic label association
108
- * - Error display with accessibility
109
- * - Optional description text
110
- * - Render prop pattern for flexibility
111
- * - Full accessibility support
57
+ * Size mappings:
58
+ * - xs: h-8 text-xs
59
+ * - sm: h-9 text-sm
60
+ * - default: h-10 text-sm
61
+ * - lg: h-12 text-base
112
62
  *
113
63
  * @example
114
64
  * ```tsx
115
- * <Field name="email" label="Email Address" description="We'll never share your email">
116
- * {({ field, meta }) => (
117
- * <input
118
- * {...field}
119
- * type="email"
120
- * className={meta.error && meta.touched ? 'error' : ''}
121
- * />
122
- * )}
123
- * </Field>
65
+ * <ButtonGroupForm
66
+ * name="email"
67
+ * placeholder="Enter your email"
68
+ * inputProps={form.getFieldProps('email')}
69
+ * submitLabel="Subscribe"
70
+ * size="default"
71
+ * />
124
72
  * ```
125
- *
126
- * @see https://opensite.ai/developers/page-speed/forms/field
127
73
  */
128
- declare function Field({ name, label, description, children, showError, className, errorClassName, required, validate, }: FieldProps): React.JSX.Element;
129
- declare namespace Field {
130
- var displayName: string;
131
- }
132
-
133
- interface FormFeedbackProps {
134
- successMessage?: React.ReactNode;
135
- submissionError?: React.ReactNode;
136
- successMessageClassName?: string;
137
- errorMessageClassName?: string;
138
- }
139
- declare function FormFeedback({ successMessage, submissionError, successMessageClassName, errorMessageClassName, }: FormFeedbackProps): React.JSX.Element | null;
140
- declare namespace FormFeedback {
74
+ declare function ButtonGroupForm({ name, label, inputProps, submitLabel, submitVariant, size, isSubmitting, className, labelClassName, }: ButtonGroupFormProps): React.JSX.Element;
75
+ declare namespace ButtonGroupForm {
141
76
  var displayName: string;
142
77
  }
143
78
 
144
- /**
145
- * FormContext - React context for providing form state to child components
146
- *
147
- * Allows useField hook to access form state without prop drilling.
148
- * Automatically provided by the <Form> component.
149
- *
150
- * @internal
151
- */
152
- declare const FormContext: React.Context<UseFormReturn<any> | null>;
153
-
154
- export { Field, FieldProps, Form, FormContext, FormFeedback, type FormFeedbackProps, FormProps, FormValues, UseFieldOptions, UseFieldReturn, UseFormOptions, UseFormReturn, useField, useForm };
79
+ export { ButtonGroupForm, type ButtonGroupFormProps, type ButtonGroupFormSize, InputProps };