@page-speed/forms 0.6.2 → 0.6.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/dist/{FormContext-D_K7lO2V.d.ts → FormContext-C6kWSQuv.d.ts} +1 -1
  2. package/dist/{FormContext-BHKCZ_du.d.cts → FormContext-DLG3GzgL.d.cts} +1 -1
  3. package/dist/chunk-A7MVZ757.js +701 -0
  4. package/dist/chunk-A7MVZ757.js.map +1 -0
  5. package/dist/chunk-DCGSRMZT.cjs +728 -0
  6. package/dist/chunk-DCGSRMZT.cjs.map +1 -0
  7. package/dist/{chunk-455PI4LV.js → chunk-J37BGNM6.js} +5 -4
  8. package/dist/chunk-J37BGNM6.js.map +1 -0
  9. package/dist/{chunk-4ROWNTY6.js → chunk-ML6FGUYS.js} +3 -3
  10. package/dist/{chunk-4ROWNTY6.js.map → chunk-ML6FGUYS.js.map} +1 -1
  11. package/dist/{chunk-QRI5TMES.cjs → chunk-QMWZLGON.cjs} +5 -4
  12. package/dist/chunk-QMWZLGON.cjs.map +1 -0
  13. package/dist/chunk-UBDA7CS5.js +3 -0
  14. package/dist/chunk-UBDA7CS5.js.map +1 -0
  15. package/dist/{chunk-ED4UK63G.cjs → chunk-UQ6JPOBF.cjs} +114 -114
  16. package/dist/{chunk-ED4UK63G.cjs.map → chunk-UQ6JPOBF.cjs.map} +1 -1
  17. package/dist/chunk-V7JSGFCI.cjs +4 -0
  18. package/dist/chunk-V7JSGFCI.cjs.map +1 -0
  19. package/dist/core.cjs +14 -14
  20. package/dist/core.d.cts +17 -11
  21. package/dist/core.d.ts +17 -11
  22. package/dist/core.js +3 -3
  23. package/dist/index.cjs +18 -18
  24. package/dist/index.d.cts +2 -2
  25. package/dist/index.d.ts +2 -2
  26. package/dist/index.js +3 -3
  27. package/dist/inputs.cjs +14 -14
  28. package/dist/inputs.d.cts +8 -2
  29. package/dist/inputs.d.ts +8 -2
  30. package/dist/inputs.js +2 -2
  31. package/dist/integration.cjs +115 -17
  32. package/dist/integration.cjs.map +1 -1
  33. package/dist/integration.d.cts +103 -127
  34. package/dist/integration.d.ts +103 -127
  35. package/dist/integration.js +101 -4
  36. package/dist/integration.js.map +1 -1
  37. package/dist/{types-Fbt73kW_.d.ts → types-BhcLAcZe.d.cts} +149 -22
  38. package/dist/{types-Fbt73kW_.d.cts → types-BhcLAcZe.d.ts} +149 -22
  39. package/dist/validation-rules.d.cts +1 -1
  40. package/dist/validation-rules.d.ts +1 -1
  41. package/dist/validation-utils.d.cts +1 -1
  42. package/dist/validation-utils.d.ts +1 -1
  43. package/dist/validation-valibot.d.cts +1 -1
  44. package/dist/validation-valibot.d.ts +1 -1
  45. package/dist/validation.d.cts +1 -1
  46. package/dist/validation.d.ts +1 -1
  47. package/package.json +1 -1
  48. package/dist/chunk-455PI4LV.js.map +0 -1
  49. package/dist/chunk-MJYEXJ3U.js +0 -373
  50. package/dist/chunk-MJYEXJ3U.js.map +0 -1
  51. package/dist/chunk-MUBEMXI7.cjs +0 -397
  52. package/dist/chunk-MUBEMXI7.cjs.map +0 -1
  53. package/dist/chunk-QRI5TMES.cjs.map +0 -1
  54. package/dist/chunk-RS6AXV5S.cjs +0 -309
  55. package/dist/chunk-RS6AXV5S.cjs.map +0 -1
  56. package/dist/chunk-ZEAH6AKP.js +0 -285
  57. package/dist/chunk-ZEAH6AKP.js.map +0 -1
@@ -1,309 +0,0 @@
1
- 'use strict';
2
-
3
- var chunkMUBEMXI7_cjs = require('./chunk-MUBEMXI7.cjs');
4
- var chunkQRI5TMES_cjs = require('./chunk-QRI5TMES.cjs');
5
- var React4 = require('react');
6
- var classVarianceAuthority = require('class-variance-authority');
7
- require('radix-ui');
8
- var icon = require('@page-speed/icon');
9
-
10
- function _interopNamespace(e) {
11
- if (e && e.__esModule) return e;
12
- var n = Object.create(null);
13
- if (e) {
14
- Object.keys(e).forEach(function (k) {
15
- if (k !== 'default') {
16
- var d = Object.getOwnPropertyDescriptor(e, k);
17
- Object.defineProperty(n, k, d.get ? d : {
18
- enumerable: true,
19
- get: function () { return e[k]; }
20
- });
21
- }
22
- });
23
- }
24
- n.default = e;
25
- return Object.freeze(n);
26
- }
27
-
28
- var React4__namespace = /*#__PURE__*/_interopNamespace(React4);
29
-
30
- function renderMessage(message, fallbackClassName, className) {
31
- if (typeof message === "string") {
32
- return /* @__PURE__ */ React4__namespace.createElement(
33
- "p",
34
- {
35
- className: chunkQRI5TMES_cjs.cn(
36
- "text-sm font-medium text-center text-balance",
37
- className
38
- )
39
- },
40
- message
41
- );
42
- }
43
- return /* @__PURE__ */ React4__namespace.createElement("div", { className: chunkQRI5TMES_cjs.cn(fallbackClassName, className) }, message);
44
- }
45
- function FormFeedback({
46
- successMessage,
47
- submissionError,
48
- successMessageClassName,
49
- errorMessageClassName
50
- }) {
51
- if (!successMessage && !submissionError) {
52
- return null;
53
- }
54
- return /* @__PURE__ */ React4__namespace.createElement(React4__namespace.Fragment, null, successMessage ? /* @__PURE__ */ React4__namespace.createElement(
55
- "div",
56
- {
57
- className: chunkQRI5TMES_cjs.cn(
58
- "rounded-md border border-primary bg-primary px-4 py-3 shadow-sm",
59
- successMessageClassName
60
- ),
61
- role: "status",
62
- "aria-live": "polite"
63
- },
64
- renderMessage(
65
- successMessage,
66
- "text-primary-foreground",
67
- "text-primary-foreground"
68
- )
69
- ) : null, submissionError ? /* @__PURE__ */ React4__namespace.createElement(
70
- "div",
71
- {
72
- className: chunkQRI5TMES_cjs.cn(
73
- "rounded-md border border-destructive bg-destructive px-4 py-3 shadow-sm",
74
- errorMessageClassName
75
- ),
76
- role: "alert",
77
- "aria-live": "assertive"
78
- },
79
- renderMessage(
80
- submissionError,
81
- "text-destructive-foreground",
82
- "text-destructive-foreground"
83
- )
84
- ) : null);
85
- }
86
- FormFeedback.displayName = "FormFeedback";
87
- var buttonGroupVariants = classVarianceAuthority.cva(
88
- "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",
89
- {
90
- variants: {
91
- orientation: {
92
- horizontal: "[&>*:not(:first-child)]:rounded-l-none [&>*:not(:first-child)]:border-l-0 [&>*:not(:last-child)]:rounded-r-none",
93
- vertical: "flex-col [&>*:not(:first-child)]:rounded-t-none [&>*:not(:first-child)]:border-t-0 [&>*:not(:last-child)]:rounded-b-none"
94
- }
95
- },
96
- defaultVariants: {
97
- orientation: "horizontal"
98
- }
99
- }
100
- );
101
- function ButtonGroup({
102
- className,
103
- orientation,
104
- ...props
105
- }) {
106
- return /* @__PURE__ */ React4__namespace.createElement(
107
- "div",
108
- {
109
- role: "group",
110
- "data-slot": "button-group",
111
- "data-orientation": orientation,
112
- className: chunkQRI5TMES_cjs.cn(buttonGroupVariants({ orientation }), className),
113
- ...props
114
- }
115
- );
116
- }
117
- var DEFAULT_ICON_API_KEY = "au382bi7fsh96w9h9xlrnat2jglx";
118
- function ButtonGroupForm({
119
- name,
120
- label,
121
- inputProps,
122
- submitLabel = "Submit",
123
- submitVariant = "default",
124
- size = "default",
125
- isSubmitting = false,
126
- submitIconName,
127
- submitIconComponent,
128
- className,
129
- labelClassName
130
- }) {
131
- const inputId = `button-group-input-${name}`;
132
- const hasValue = String(inputProps.value ?? "").trim().length > 0;
133
- const hasError = !!inputProps.error;
134
- const buttonSize = React4__namespace.useMemo(() => {
135
- if (submitIconName || submitIconComponent) {
136
- return size === "default" ? "icon" : `icon-${size}`;
137
- }
138
- return 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]);
151
- const inputSizeClasses = {
152
- xs: "text-xs px-3",
153
- sm: "text-sm px-3",
154
- default: "text-base px-4",
155
- lg: "text-md px-6"
156
- };
157
- return /* @__PURE__ */ React4__namespace.createElement("div", { className: chunkQRI5TMES_cjs.cn("space-y-2", className) }, label && /* @__PURE__ */ React4__namespace.createElement(chunkQRI5TMES_cjs.FieldLabel, { htmlFor: inputId, className: labelClassName }, label), /* @__PURE__ */ React4__namespace.createElement(ButtonGroup, null, /* @__PURE__ */ React4__namespace.createElement(
158
- chunkQRI5TMES_cjs.TextInput,
159
- {
160
- ...inputProps,
161
- id: inputId,
162
- className: chunkQRI5TMES_cjs.cn(
163
- inputSizeClasses[size],
164
- "border-r-0 rounded-r-none focus-visible:z-10",
165
- inputProps.className
166
- )
167
- }
168
- ), /* @__PURE__ */ React4__namespace.createElement(
169
- chunkQRI5TMES_cjs.Button,
170
- {
171
- size: buttonSize,
172
- type: "submit",
173
- variant: submitVariant,
174
- disabled: isSubmitting,
175
- className: chunkQRI5TMES_cjs.cn(
176
- "rounded-l-none",
177
- !hasError && hasValue && "ring-2 ring-ring"
178
- )
179
- },
180
- labelElement
181
- )));
182
- }
183
- ButtonGroupForm.displayName = "ButtonGroupForm";
184
-
185
- // src/core/Form.tsx
186
- function Form({
187
- form,
188
- children,
189
- fields,
190
- className,
191
- action,
192
- method,
193
- noValidate = true,
194
- submissionConfig,
195
- successMessage,
196
- submissionError,
197
- successMessageClassName,
198
- errorMessageClassName,
199
- onNewSubmission,
200
- notificationConfig,
201
- styleConfig,
202
- formConfig,
203
- ...props
204
- }) {
205
- const handleFormSubmit = React4__namespace.useCallback(
206
- async (e) => {
207
- try {
208
- await form.handleSubmit(e);
209
- } catch {
210
- }
211
- },
212
- [form]
213
- );
214
- const resolvedClassName = className ?? styleConfig?.formClassName;
215
- const resolvedAction = action ?? formConfig?.endpoint;
216
- const resolvedMethod = method ?? formConfig?.method ?? "post";
217
- const resolvedSubmissionConfig = submissionConfig ?? formConfig?.submissionConfig;
218
- const resolvedSuccessMessage = successMessage ?? notificationConfig?.successMessage;
219
- const resolvedSubmissionError = submissionError ?? notificationConfig?.submissionError;
220
- const resolvedSuccessMessageClassName = successMessageClassName ?? styleConfig?.successMessageClassName;
221
- const resolvedErrorMessageClassName = errorMessageClassName ?? styleConfig?.errorMessageClassName;
222
- const behavior = resolvedSubmissionConfig?.behavior || "showConfirmation";
223
- const shouldManageSubmissionUi = resolvedSubmissionConfig !== void 0 || resolvedSuccessMessage !== void 0 || resolvedSuccessMessageClassName !== void 0 || resolvedErrorMessageClassName !== void 0 || resolvedSubmissionError != null || onNewSubmission !== void 0;
224
- const hasSubmissionError = Boolean(resolvedSubmissionError);
225
- const isSubmissionSuccessful = shouldManageSubmissionUi && form.status === "success" && !hasSubmissionError;
226
- const defaultSuccessMessage = behavior === "redirect" ? "Form submitted successfully. Redirecting..." : "Thank you. Your form has been submitted successfully.";
227
- const finalSuccessMessage = resolvedSuccessMessage ?? defaultSuccessMessage;
228
- const shouldRenderCustomComponent = isSubmissionSuccessful && behavior === "renderCustomComponent" && Boolean(resolvedSubmissionConfig?.customComponent);
229
- const newSubmissionAction = resolvedSubmissionConfig?.newFormSubmissionAction;
230
- const showNewSubmissionAction = isSubmissionSuccessful && (typeof newSubmissionAction?.enable === "boolean" ? newSubmissionAction.enable : Boolean(newSubmissionAction?.label));
231
- const newSubmissionLabel = newSubmissionAction?.label ?? "Submit another response";
232
- const handleNewSubmission = React4__namespace.useCallback(() => {
233
- form.resetForm();
234
- onNewSubmission?.();
235
- }, [form, onNewSubmission]);
236
- const formLayout = formConfig?.formLayout ?? "standard";
237
- const isButtonGroupLayout = formLayout === "button-group";
238
- const hasTextField = fields && fields.length === 1 && fields[0] && ["text", "email", "password", "url", "tel", "search"].includes(
239
- fields[0].type
240
- );
241
- const shouldUseButtonGroup = isButtonGroupLayout && hasTextField;
242
- const buttonGroupContent = React4__namespace.useMemo(() => {
243
- if (!shouldUseButtonGroup || !fields || fields.length === 0) return null;
244
- const field = fields[0];
245
- const fieldProps = form.getFieldProps(field.name);
246
- return /* @__PURE__ */ React4__namespace.createElement(
247
- ButtonGroupForm,
248
- {
249
- name: field.name,
250
- label: field.label,
251
- inputProps: {
252
- name: fieldProps.name,
253
- value: fieldProps.value,
254
- onChange: fieldProps.onChange,
255
- onBlur: fieldProps.onBlur,
256
- type: field.type,
257
- placeholder: field.placeholder,
258
- required: field.required,
259
- disabled: field.disabled
260
- },
261
- submitLabel: formConfig?.submitLabel,
262
- submitVariant: formConfig?.submitVariant,
263
- submitIconName: formConfig?.submitIconName,
264
- submitIconComponent: formConfig?.submitIconComponent,
265
- size: formConfig?.buttonGroupSize,
266
- isSubmitting: form.isSubmitting
267
- }
268
- );
269
- }, [shouldUseButtonGroup, fields, form, formConfig]);
270
- return /* @__PURE__ */ React4__namespace.createElement(chunkMUBEMXI7_cjs.FormContext.Provider, { value: form }, /* @__PURE__ */ React4__namespace.createElement(
271
- "form",
272
- {
273
- onSubmit: handleFormSubmit,
274
- action: resolvedAction,
275
- method: resolvedMethod,
276
- noValidate,
277
- className: resolvedClassName,
278
- ...props
279
- },
280
- isSubmissionSuccessful ? /* @__PURE__ */ React4__namespace.createElement("div", { className: "space-y-4" }, shouldRenderCustomComponent ? resolvedSubmissionConfig?.customComponent : /* @__PURE__ */ React4__namespace.createElement(
281
- FormFeedback,
282
- {
283
- successMessage: finalSuccessMessage,
284
- successMessageClassName: resolvedSuccessMessageClassName
285
- }
286
- ), showNewSubmissionAction ? /* @__PURE__ */ React4__namespace.createElement(
287
- chunkQRI5TMES_cjs.Button,
288
- {
289
- type: "button",
290
- variant: "outline",
291
- onClick: handleNewSubmission
292
- },
293
- newSubmissionLabel
294
- ) : null) : /* @__PURE__ */ React4__namespace.createElement(React4__namespace.Fragment, null, shouldUseButtonGroup ? buttonGroupContent : children, resolvedSubmissionError ? /* @__PURE__ */ React4__namespace.createElement("div", { className: "mt-4" }, /* @__PURE__ */ React4__namespace.createElement(
295
- FormFeedback,
296
- {
297
- submissionError: resolvedSubmissionError,
298
- errorMessageClassName: resolvedErrorMessageClassName
299
- }
300
- )) : null)
301
- ));
302
- }
303
- Form.displayName = "Form";
304
-
305
- exports.ButtonGroupForm = ButtonGroupForm;
306
- exports.Form = Form;
307
- exports.FormFeedback = FormFeedback;
308
- //# sourceMappingURL=chunk-RS6AXV5S.cjs.map
309
- //# sourceMappingURL=chunk-RS6AXV5S.cjs.map
@@ -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","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"]}
@@ -1,285 +0,0 @@
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
- import { Icon } from '@page-speed/icon';
7
-
8
- function renderMessage(message, fallbackClassName, className) {
9
- if (typeof message === "string") {
10
- return /* @__PURE__ */ React4.createElement(
11
- "p",
12
- {
13
- className: cn(
14
- "text-sm font-medium text-center text-balance",
15
- className
16
- )
17
- },
18
- message
19
- );
20
- }
21
- return /* @__PURE__ */ React4.createElement("div", { className: cn(fallbackClassName, className) }, message);
22
- }
23
- function FormFeedback({
24
- successMessage,
25
- submissionError,
26
- successMessageClassName,
27
- errorMessageClassName
28
- }) {
29
- if (!successMessage && !submissionError) {
30
- return null;
31
- }
32
- return /* @__PURE__ */ React4.createElement(React4.Fragment, null, successMessage ? /* @__PURE__ */ React4.createElement(
33
- "div",
34
- {
35
- className: cn(
36
- "rounded-md border border-primary bg-primary px-4 py-3 shadow-sm",
37
- successMessageClassName
38
- ),
39
- role: "status",
40
- "aria-live": "polite"
41
- },
42
- renderMessage(
43
- successMessage,
44
- "text-primary-foreground",
45
- "text-primary-foreground"
46
- )
47
- ) : null, submissionError ? /* @__PURE__ */ React4.createElement(
48
- "div",
49
- {
50
- className: cn(
51
- "rounded-md border border-destructive bg-destructive px-4 py-3 shadow-sm",
52
- errorMessageClassName
53
- ),
54
- role: "alert",
55
- "aria-live": "assertive"
56
- },
57
- renderMessage(
58
- submissionError,
59
- "text-destructive-foreground",
60
- "text-destructive-foreground"
61
- )
62
- ) : null);
63
- }
64
- FormFeedback.displayName = "FormFeedback";
65
- var buttonGroupVariants = cva(
66
- "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",
67
- {
68
- variants: {
69
- orientation: {
70
- horizontal: "[&>*:not(:first-child)]:rounded-l-none [&>*:not(:first-child)]:border-l-0 [&>*:not(:last-child)]:rounded-r-none",
71
- vertical: "flex-col [&>*:not(:first-child)]:rounded-t-none [&>*:not(:first-child)]:border-t-0 [&>*:not(:last-child)]:rounded-b-none"
72
- }
73
- },
74
- defaultVariants: {
75
- orientation: "horizontal"
76
- }
77
- }
78
- );
79
- function ButtonGroup({
80
- className,
81
- orientation,
82
- ...props
83
- }) {
84
- return /* @__PURE__ */ React4.createElement(
85
- "div",
86
- {
87
- role: "group",
88
- "data-slot": "button-group",
89
- "data-orientation": orientation,
90
- className: cn(buttonGroupVariants({ orientation }), className),
91
- ...props
92
- }
93
- );
94
- }
95
- var DEFAULT_ICON_API_KEY = "au382bi7fsh96w9h9xlrnat2jglx";
96
- function ButtonGroupForm({
97
- name,
98
- label,
99
- inputProps,
100
- submitLabel = "Submit",
101
- submitVariant = "default",
102
- size = "default",
103
- isSubmitting = false,
104
- submitIconName,
105
- submitIconComponent,
106
- className,
107
- labelClassName
108
- }) {
109
- const inputId = `button-group-input-${name}`;
110
- const hasValue = String(inputProps.value ?? "").trim().length > 0;
111
- const hasError = !!inputProps.error;
112
- const buttonSize = React4.useMemo(() => {
113
- if (submitIconName || submitIconComponent) {
114
- return size === "default" ? "icon" : `icon-${size}`;
115
- }
116
- return 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]);
129
- const inputSizeClasses = {
130
- xs: "text-xs px-3",
131
- sm: "text-sm px-3",
132
- default: "text-base px-4",
133
- lg: "text-md px-6"
134
- };
135
- 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(
136
- TextInput,
137
- {
138
- ...inputProps,
139
- id: inputId,
140
- className: cn(
141
- inputSizeClasses[size],
142
- "border-r-0 rounded-r-none focus-visible:z-10",
143
- inputProps.className
144
- )
145
- }
146
- ), /* @__PURE__ */ React4.createElement(
147
- Button,
148
- {
149
- size: buttonSize,
150
- type: "submit",
151
- variant: submitVariant,
152
- disabled: isSubmitting,
153
- className: cn(
154
- "rounded-l-none",
155
- !hasError && hasValue && "ring-2 ring-ring"
156
- )
157
- },
158
- labelElement
159
- )));
160
- }
161
- ButtonGroupForm.displayName = "ButtonGroupForm";
162
-
163
- // src/core/Form.tsx
164
- function Form({
165
- form,
166
- children,
167
- fields,
168
- className,
169
- action,
170
- method,
171
- noValidate = true,
172
- submissionConfig,
173
- successMessage,
174
- submissionError,
175
- successMessageClassName,
176
- errorMessageClassName,
177
- onNewSubmission,
178
- notificationConfig,
179
- styleConfig,
180
- formConfig,
181
- ...props
182
- }) {
183
- const handleFormSubmit = React4.useCallback(
184
- async (e) => {
185
- try {
186
- await form.handleSubmit(e);
187
- } catch {
188
- }
189
- },
190
- [form]
191
- );
192
- const resolvedClassName = className ?? styleConfig?.formClassName;
193
- const resolvedAction = action ?? formConfig?.endpoint;
194
- const resolvedMethod = method ?? formConfig?.method ?? "post";
195
- const resolvedSubmissionConfig = submissionConfig ?? formConfig?.submissionConfig;
196
- const resolvedSuccessMessage = successMessage ?? notificationConfig?.successMessage;
197
- const resolvedSubmissionError = submissionError ?? notificationConfig?.submissionError;
198
- const resolvedSuccessMessageClassName = successMessageClassName ?? styleConfig?.successMessageClassName;
199
- const resolvedErrorMessageClassName = errorMessageClassName ?? styleConfig?.errorMessageClassName;
200
- const behavior = resolvedSubmissionConfig?.behavior || "showConfirmation";
201
- const shouldManageSubmissionUi = resolvedSubmissionConfig !== void 0 || resolvedSuccessMessage !== void 0 || resolvedSuccessMessageClassName !== void 0 || resolvedErrorMessageClassName !== void 0 || resolvedSubmissionError != null || onNewSubmission !== void 0;
202
- const hasSubmissionError = Boolean(resolvedSubmissionError);
203
- const isSubmissionSuccessful = shouldManageSubmissionUi && form.status === "success" && !hasSubmissionError;
204
- const defaultSuccessMessage = behavior === "redirect" ? "Form submitted successfully. Redirecting..." : "Thank you. Your form has been submitted successfully.";
205
- const finalSuccessMessage = resolvedSuccessMessage ?? defaultSuccessMessage;
206
- const shouldRenderCustomComponent = isSubmissionSuccessful && behavior === "renderCustomComponent" && Boolean(resolvedSubmissionConfig?.customComponent);
207
- const newSubmissionAction = resolvedSubmissionConfig?.newFormSubmissionAction;
208
- const showNewSubmissionAction = isSubmissionSuccessful && (typeof newSubmissionAction?.enable === "boolean" ? newSubmissionAction.enable : Boolean(newSubmissionAction?.label));
209
- const newSubmissionLabel = newSubmissionAction?.label ?? "Submit another response";
210
- const handleNewSubmission = React4.useCallback(() => {
211
- form.resetForm();
212
- onNewSubmission?.();
213
- }, [form, onNewSubmission]);
214
- const formLayout = formConfig?.formLayout ?? "standard";
215
- const isButtonGroupLayout = formLayout === "button-group";
216
- const hasTextField = fields && fields.length === 1 && fields[0] && ["text", "email", "password", "url", "tel", "search"].includes(
217
- fields[0].type
218
- );
219
- const shouldUseButtonGroup = isButtonGroupLayout && hasTextField;
220
- const buttonGroupContent = React4.useMemo(() => {
221
- if (!shouldUseButtonGroup || !fields || fields.length === 0) return null;
222
- const field = fields[0];
223
- const fieldProps = form.getFieldProps(field.name);
224
- return /* @__PURE__ */ React4.createElement(
225
- ButtonGroupForm,
226
- {
227
- name: field.name,
228
- label: field.label,
229
- inputProps: {
230
- name: fieldProps.name,
231
- value: fieldProps.value,
232
- onChange: fieldProps.onChange,
233
- onBlur: fieldProps.onBlur,
234
- type: field.type,
235
- placeholder: field.placeholder,
236
- required: field.required,
237
- disabled: field.disabled
238
- },
239
- submitLabel: formConfig?.submitLabel,
240
- submitVariant: formConfig?.submitVariant,
241
- submitIconName: formConfig?.submitIconName,
242
- submitIconComponent: formConfig?.submitIconComponent,
243
- size: formConfig?.buttonGroupSize,
244
- isSubmitting: form.isSubmitting
245
- }
246
- );
247
- }, [shouldUseButtonGroup, fields, form, formConfig]);
248
- return /* @__PURE__ */ React4.createElement(FormContext.Provider, { value: form }, /* @__PURE__ */ React4.createElement(
249
- "form",
250
- {
251
- onSubmit: handleFormSubmit,
252
- action: resolvedAction,
253
- method: resolvedMethod,
254
- noValidate,
255
- className: resolvedClassName,
256
- ...props
257
- },
258
- isSubmissionSuccessful ? /* @__PURE__ */ React4.createElement("div", { className: "space-y-4" }, shouldRenderCustomComponent ? resolvedSubmissionConfig?.customComponent : /* @__PURE__ */ React4.createElement(
259
- FormFeedback,
260
- {
261
- successMessage: finalSuccessMessage,
262
- successMessageClassName: resolvedSuccessMessageClassName
263
- }
264
- ), showNewSubmissionAction ? /* @__PURE__ */ React4.createElement(
265
- Button,
266
- {
267
- type: "button",
268
- variant: "outline",
269
- onClick: handleNewSubmission
270
- },
271
- newSubmissionLabel
272
- ) : null) : /* @__PURE__ */ React4.createElement(React4.Fragment, null, shouldUseButtonGroup ? buttonGroupContent : children, resolvedSubmissionError ? /* @__PURE__ */ React4.createElement("div", { className: "mt-4" }, /* @__PURE__ */ React4.createElement(
273
- FormFeedback,
274
- {
275
- submissionError: resolvedSubmissionError,
276
- errorMessageClassName: resolvedErrorMessageClassName
277
- }
278
- )) : null)
279
- ));
280
- }
281
- Form.displayName = "Form";
282
-
283
- export { ButtonGroupForm, Form, FormFeedback };
284
- //# sourceMappingURL=chunk-ZEAH6AKP.js.map
285
- //# sourceMappingURL=chunk-ZEAH6AKP.js.map