@page-speed/forms 0.6.2 → 0.6.3

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 (51) hide show
  1. package/dist/{FormContext-D_K7lO2V.d.ts → FormContext-Db0L3Kwv.d.ts} +1 -1
  2. package/dist/{FormContext-BHKCZ_du.d.cts → FormContext-kKZxeb7G.d.cts} +1 -1
  3. package/dist/{chunk-RS6AXV5S.cjs → chunk-3ED2FKXF.cjs} +100 -59
  4. package/dist/chunk-3ED2FKXF.cjs.map +1 -0
  5. package/dist/{chunk-ZEAH6AKP.js → chunk-H3YJRLVO.js} +93 -52
  6. package/dist/chunk-H3YJRLVO.js.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-MJYEXJ3U.js → chunk-SNSK3TMG.js} +3 -3
  14. package/dist/{chunk-MJYEXJ3U.js.map → chunk-SNSK3TMG.js.map} +1 -1
  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-MUBEMXI7.cjs → chunk-V545YJFP.cjs} +6 -6
  18. package/dist/{chunk-MUBEMXI7.cjs.map → chunk-V545YJFP.cjs.map} +1 -1
  19. package/dist/core.cjs +10 -10
  20. package/dist/core.d.cts +13 -9
  21. package/dist/core.d.ts +13 -9
  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 +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 +17 -17
  32. package/dist/integration.cjs.map +1 -1
  33. package/dist/integration.d.cts +3 -112
  34. package/dist/integration.d.ts +3 -112
  35. package/dist/integration.js +3 -3
  36. package/dist/integration.js.map +1 -1
  37. package/dist/{types-Fbt73kW_.d.ts → types-BPxsUGm_.d.cts} +120 -2
  38. package/dist/{types-Fbt73kW_.d.cts → types-BPxsUGm_.d.ts} +120 -2
  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-QRI5TMES.cjs.map +0 -1
  50. package/dist/chunk-RS6AXV5S.cjs.map +0 -1
  51. package/dist/chunk-ZEAH6AKP.js.map +0 -1
@@ -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-Fbt73kW_.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-BPxsUGm_.js';
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-Fbt73kW_.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-BPxsUGm_.cjs';
2
2
  import * as React from 'react';
3
3
 
4
4
  /**
@@ -1,8 +1,8 @@
1
1
  'use strict';
2
2
 
3
- var chunkMUBEMXI7_cjs = require('./chunk-MUBEMXI7.cjs');
4
- var chunkQRI5TMES_cjs = require('./chunk-QRI5TMES.cjs');
5
- var React4 = require('react');
3
+ var chunkV545YJFP_cjs = require('./chunk-V545YJFP.cjs');
4
+ var chunkQMWZLGON_cjs = require('./chunk-QMWZLGON.cjs');
5
+ var React3 = require('react');
6
6
  var classVarianceAuthority = require('class-variance-authority');
7
7
  require('radix-ui');
8
8
  var icon = require('@page-speed/icon');
@@ -25,14 +25,14 @@ function _interopNamespace(e) {
25
25
  return Object.freeze(n);
26
26
  }
27
27
 
28
- var React4__namespace = /*#__PURE__*/_interopNamespace(React4);
28
+ var React3__namespace = /*#__PURE__*/_interopNamespace(React3);
29
29
 
30
30
  function renderMessage(message, fallbackClassName, className) {
31
31
  if (typeof message === "string") {
32
- return /* @__PURE__ */ React4__namespace.createElement(
32
+ return /* @__PURE__ */ React3__namespace.createElement(
33
33
  "p",
34
34
  {
35
- className: chunkQRI5TMES_cjs.cn(
35
+ className: chunkQMWZLGON_cjs.cn(
36
36
  "text-sm font-medium text-center text-balance",
37
37
  className
38
38
  )
@@ -40,7 +40,7 @@ function renderMessage(message, fallbackClassName, className) {
40
40
  message
41
41
  );
42
42
  }
43
- return /* @__PURE__ */ React4__namespace.createElement("div", { className: chunkQRI5TMES_cjs.cn(fallbackClassName, className) }, message);
43
+ return /* @__PURE__ */ React3__namespace.createElement("div", { className: chunkQMWZLGON_cjs.cn(fallbackClassName, className) }, message);
44
44
  }
45
45
  function FormFeedback({
46
46
  successMessage,
@@ -51,10 +51,10 @@ function FormFeedback({
51
51
  if (!successMessage && !submissionError) {
52
52
  return null;
53
53
  }
54
- return /* @__PURE__ */ React4__namespace.createElement(React4__namespace.Fragment, null, successMessage ? /* @__PURE__ */ React4__namespace.createElement(
54
+ return /* @__PURE__ */ React3__namespace.createElement(React3__namespace.Fragment, null, successMessage ? /* @__PURE__ */ React3__namespace.createElement(
55
55
  "div",
56
56
  {
57
- className: chunkQRI5TMES_cjs.cn(
57
+ className: chunkQMWZLGON_cjs.cn(
58
58
  "rounded-md border border-primary bg-primary px-4 py-3 shadow-sm",
59
59
  successMessageClassName
60
60
  ),
@@ -66,10 +66,10 @@ function FormFeedback({
66
66
  "text-primary-foreground",
67
67
  "text-primary-foreground"
68
68
  )
69
- ) : null, submissionError ? /* @__PURE__ */ React4__namespace.createElement(
69
+ ) : null, submissionError ? /* @__PURE__ */ React3__namespace.createElement(
70
70
  "div",
71
71
  {
72
- className: chunkQRI5TMES_cjs.cn(
72
+ className: chunkQMWZLGON_cjs.cn(
73
73
  "rounded-md border border-destructive bg-destructive px-4 py-3 shadow-sm",
74
74
  errorMessageClassName
75
75
  ),
@@ -103,21 +103,32 @@ function ButtonGroup({
103
103
  orientation,
104
104
  ...props
105
105
  }) {
106
- return /* @__PURE__ */ React4__namespace.createElement(
106
+ return /* @__PURE__ */ React3__namespace.createElement(
107
107
  "div",
108
108
  {
109
109
  role: "group",
110
110
  "data-slot": "button-group",
111
111
  "data-orientation": orientation,
112
- className: chunkQRI5TMES_cjs.cn(buttonGroupVariants({ orientation }), className),
112
+ className: chunkQMWZLGON_cjs.cn(buttonGroupVariants({ orientation }), className),
113
113
  ...props
114
114
  }
115
115
  );
116
116
  }
117
117
  var DEFAULT_ICON_API_KEY = "au382bi7fsh96w9h9xlrnat2jglx";
118
+ var INPUT_SIZE_CLASSES = {
119
+ xs: "h-6 text-xs px-3",
120
+ // button: h-6 → match
121
+ sm: "text-sm px-3",
122
+ // button: h-8 overridden to h-9 below → match
123
+ default: "text-base px-4",
124
+ // button: h-9 (no override needed)
125
+ lg: "h-10 text-md px-6"
126
+ // button: h-10 → match
127
+ };
118
128
  function ButtonGroupForm({
119
129
  name,
120
130
  label,
131
+ description,
121
132
  inputProps,
122
133
  submitLabel = "Submit",
123
134
  submitVariant = "default",
@@ -128,18 +139,24 @@ function ButtonGroupForm({
128
139
  className,
129
140
  labelClassName
130
141
  }) {
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(() => {
142
+ const inputId = React3__namespace.useMemo(() => {
143
+ return `button-group-input-${name}`;
144
+ }, [name]);
145
+ const hasValue = React3__namespace.useMemo(() => {
146
+ return String(inputProps.value ?? "").trim().length > 0;
147
+ }, [inputProps.value]);
148
+ const hasError = React3__namespace.useMemo(() => {
149
+ return !!inputProps.error;
150
+ }, [inputProps.error]);
151
+ const buttonSize = React3__namespace.useMemo(() => {
135
152
  if (submitIconName || submitIconComponent) {
136
- return size === "default" ? "icon" : `icon-${size}`;
153
+ return size === "default" || size === "sm" ? "icon" : `icon-${size}`;
137
154
  }
138
155
  return size;
139
156
  }, [submitIconName, size, submitIconComponent]);
140
- const labelElement = React4__namespace.useMemo(() => {
157
+ const labelElement = React3__namespace.useMemo(() => {
141
158
  if (submitIconName) {
142
- return /* @__PURE__ */ React4__namespace.createElement(icon.Icon, { name: submitIconName, apiKey: DEFAULT_ICON_API_KEY });
159
+ return /* @__PURE__ */ React3__namespace.createElement(icon.Icon, { name: submitIconName, apiKey: DEFAULT_ICON_API_KEY });
143
160
  } else if (submitIconComponent) {
144
161
  return submitIconComponent;
145
162
  } else if (submitLabel) {
@@ -148,37 +165,60 @@ function ButtonGroupForm({
148
165
  return "Submit";
149
166
  }
150
167
  }, [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,
168
+ return /* @__PURE__ */ React3__namespace.createElement("div", { className: chunkQMWZLGON_cjs.cn("space-y-2", className) }, label && /* @__PURE__ */ React3__namespace.createElement(chunkQMWZLGON_cjs.FieldLabel, { htmlFor: inputId, className: labelClassName }, label), /* @__PURE__ */ React3__namespace.createElement(
169
+ ButtonGroup,
159
170
  {
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"
171
+ className: chunkQMWZLGON_cjs.cn(
172
+ "rounded-md",
173
+ !hasError && hasValue && "ring-2 ring-ring",
174
+ hasError && "ring-1 ring-destructive"
178
175
  )
179
176
  },
180
- labelElement
181
- )));
177
+ /* @__PURE__ */ React3__namespace.createElement(
178
+ chunkQMWZLGON_cjs.TextInput,
179
+ {
180
+ ...inputProps,
181
+ id: inputId,
182
+ suppressValueRing: true,
183
+ className: chunkQMWZLGON_cjs.cn(
184
+ INPUT_SIZE_CLASSES[size],
185
+ "border-r-0 rounded-r-none focus-visible:z-10",
186
+ inputProps.className
187
+ )
188
+ }
189
+ ),
190
+ /* @__PURE__ */ React3__namespace.createElement(
191
+ chunkQMWZLGON_cjs.Button,
192
+ {
193
+ size: buttonSize,
194
+ type: "submit",
195
+ variant: submitVariant,
196
+ disabled: isSubmitting,
197
+ className: chunkQMWZLGON_cjs.cn(
198
+ "relative rounded-l-none ring-0",
199
+ // 'sm' button variant is h-8; override to h-9 to align with input
200
+ size === "sm" && "h-9"
201
+ )
202
+ },
203
+ isSubmitting ? /* @__PURE__ */ React3__namespace.createElement("span", { className: "absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2" }, /* @__PURE__ */ React3__namespace.createElement(
204
+ icon.Icon,
205
+ {
206
+ name: "line-md/loading-twotone-loop",
207
+ apiKey: DEFAULT_ICON_API_KEY
208
+ }
209
+ )) : null,
210
+ /* @__PURE__ */ React3__namespace.createElement(
211
+ "span",
212
+ {
213
+ className: chunkQMWZLGON_cjs.cn(
214
+ "transition-opacity duration-200",
215
+ isSubmitting ? "opacity-0" : "opacity-100"
216
+ )
217
+ },
218
+ labelElement
219
+ )
220
+ )
221
+ ), description && /* @__PURE__ */ React3__namespace.createElement(chunkQMWZLGON_cjs.FieldDescription, null, description));
182
222
  }
183
223
  ButtonGroupForm.displayName = "ButtonGroupForm";
184
224
 
@@ -202,7 +242,7 @@ function Form({
202
242
  formConfig,
203
243
  ...props
204
244
  }) {
205
- const handleFormSubmit = React4__namespace.useCallback(
245
+ const handleFormSubmit = React3__namespace.useCallback(
206
246
  async (e) => {
207
247
  try {
208
248
  await form.handleSubmit(e);
@@ -229,7 +269,7 @@ function Form({
229
269
  const newSubmissionAction = resolvedSubmissionConfig?.newFormSubmissionAction;
230
270
  const showNewSubmissionAction = isSubmissionSuccessful && (typeof newSubmissionAction?.enable === "boolean" ? newSubmissionAction.enable : Boolean(newSubmissionAction?.label));
231
271
  const newSubmissionLabel = newSubmissionAction?.label ?? "Submit another response";
232
- const handleNewSubmission = React4__namespace.useCallback(() => {
272
+ const handleNewSubmission = React3__namespace.useCallback(() => {
233
273
  form.resetForm();
234
274
  onNewSubmission?.();
235
275
  }, [form, onNewSubmission]);
@@ -239,15 +279,16 @@ function Form({
239
279
  fields[0].type
240
280
  );
241
281
  const shouldUseButtonGroup = isButtonGroupLayout && hasTextField;
242
- const buttonGroupContent = React4__namespace.useMemo(() => {
282
+ const buttonGroupContent = React3__namespace.useMemo(() => {
243
283
  if (!shouldUseButtonGroup || !fields || fields.length === 0) return null;
244
284
  const field = fields[0];
245
285
  const fieldProps = form.getFieldProps(field.name);
246
- return /* @__PURE__ */ React4__namespace.createElement(
286
+ return /* @__PURE__ */ React3__namespace.createElement(
247
287
  ButtonGroupForm,
248
288
  {
249
289
  name: field.name,
250
290
  label: field.label,
291
+ className: field.className,
251
292
  inputProps: {
252
293
  name: fieldProps.name,
253
294
  value: fieldProps.value,
@@ -267,7 +308,7 @@ function Form({
267
308
  }
268
309
  );
269
310
  }, [shouldUseButtonGroup, fields, form, formConfig]);
270
- return /* @__PURE__ */ React4__namespace.createElement(chunkMUBEMXI7_cjs.FormContext.Provider, { value: form }, /* @__PURE__ */ React4__namespace.createElement(
311
+ return /* @__PURE__ */ React3__namespace.createElement(chunkV545YJFP_cjs.FormContext.Provider, { value: form }, /* @__PURE__ */ React3__namespace.createElement(
271
312
  "form",
272
313
  {
273
314
  onSubmit: handleFormSubmit,
@@ -277,21 +318,21 @@ function Form({
277
318
  className: resolvedClassName,
278
319
  ...props
279
320
  },
280
- isSubmissionSuccessful ? /* @__PURE__ */ React4__namespace.createElement("div", { className: "space-y-4" }, shouldRenderCustomComponent ? resolvedSubmissionConfig?.customComponent : /* @__PURE__ */ React4__namespace.createElement(
321
+ isSubmissionSuccessful ? /* @__PURE__ */ React3__namespace.createElement("div", { className: "space-y-4" }, shouldRenderCustomComponent ? resolvedSubmissionConfig?.customComponent : /* @__PURE__ */ React3__namespace.createElement(
281
322
  FormFeedback,
282
323
  {
283
324
  successMessage: finalSuccessMessage,
284
325
  successMessageClassName: resolvedSuccessMessageClassName
285
326
  }
286
- ), showNewSubmissionAction ? /* @__PURE__ */ React4__namespace.createElement(
287
- chunkQRI5TMES_cjs.Button,
327
+ ), showNewSubmissionAction ? /* @__PURE__ */ React3__namespace.createElement(
328
+ chunkQMWZLGON_cjs.Button,
288
329
  {
289
330
  type: "button",
290
331
  variant: "outline",
291
332
  onClick: handleNewSubmission
292
333
  },
293
334
  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(
335
+ ) : null) : /* @__PURE__ */ React3__namespace.createElement(React3__namespace.Fragment, null, shouldUseButtonGroup ? buttonGroupContent : children, resolvedSubmissionError ? /* @__PURE__ */ React3__namespace.createElement("div", { className: "mt-4" }, /* @__PURE__ */ React3__namespace.createElement(
295
336
  FormFeedback,
296
337
  {
297
338
  submissionError: resolvedSubmissionError,
@@ -305,5 +346,5 @@ Form.displayName = "Form";
305
346
  exports.ButtonGroupForm = ButtonGroupForm;
306
347
  exports.Form = Form;
307
348
  exports.FormFeedback = FormFeedback;
308
- //# sourceMappingURL=chunk-RS6AXV5S.cjs.map
309
- //# sourceMappingURL=chunk-RS6AXV5S.cjs.map
349
+ //# sourceMappingURL=chunk-3ED2FKXF.cjs.map
350
+ //# sourceMappingURL=chunk-3ED2FKXF.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","FieldDescription","React4","FormContext"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAYA,SAAS,aAAA,CACP,OAAA,EACA,iBAAA,EACA,SAAA,EACA;AACA,EAAA,IAAI,OAAO,YAAY,QAAA,EAAU;AAC/B,IAAA,uBACEA,iBAAA,CAAA,aAAA;AAAA,MAAC,GAAA;AAAA,MAAA;AAAA,QACC,SAAA,EAAWC,oBAAA;AAAA,UACT,8CAAA;AAAA,UACA;AAAA;AACF,OAAA;AAAA,MAEC;AAAA,KACH;AAAA,EAEJ;AAEA,EAAA,uDAAQ,KAAA,EAAA,EAAI,SAAA,EAAWA,qBAAG,iBAAA,EAAmB,SAAS,KAAI,OAAQ,CAAA;AACpE;AAEO,SAAS,YAAA,CAAa;AAAA,EAC3B,cAAA;AAAA,EACA,eAAA;AAAA,EACA,uBAAA;AAAA,EACA;AACF,CAAA,EAAsB;AACpB,EAAA,IAAI,CAAC,cAAA,IAAkB,CAAC,eAAA,EAAiB;AACvC,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,yFAEK,cAAA,mBACCD,iBAAA,CAAA,aAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,SAAA,EAAWC,oBAAA;AAAA,QACT,iEAAA;AAAA,QACA;AAAA,OACF;AAAA,MACA,IAAA,EAAK,QAAA;AAAA,MACL,WAAA,EAAU;AAAA,KAAA;AAAA,IAET,aAAA;AAAA,MACC,cAAA;AAAA,MACA,yBAAA;AAAA,MACA;AAAA;AACF,GACF,GACE,MAEH,eAAA,mBACCD,iBAAA,CAAA,aAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,SAAA,EAAWC,oBAAA;AAAA,QACT,yEAAA;AAAA,QACA;AAAA,OACF;AAAA,MACA,IAAA,EAAK,OAAA;AAAA,MACL,WAAA,EAAU;AAAA,KAAA;AAAA,IAET,aAAA;AAAA,MACC,eAAA;AAAA,MACA,6BAAA;AAAA,MACA;AAAA;AACF,MAEA,IACN,CAAA;AAEJ;AAEA,YAAA,CAAa,WAAA,GAAc,cAAA;AC3E3B,IAAM,mBAAA,GAAsBC,0BAAA;AAAA,EAC1B,kSAAA;AAAA,EACA;AAAA,IACE,QAAA,EAAU;AAAA,MACR,WAAA,EAAa;AAAA,QACX,UAAA,EACE,iHAAA;AAAA,QACF,QAAA,EACE;AAAA;AACJ,KACF;AAAA,IACA,eAAA,EAAiB;AAAA,MACf,WAAA,EAAa;AAAA;AACf;AAEJ,CAAA;AAEA,SAAS,WAAA,CAAY;AAAA,EACnB,SAAA;AAAA,EACA,WAAA;AAAA,EACA,GAAG;AACL,CAAA,EAA2E;AACzE,EAAA,uBACEC,iBAAA,CAAA,aAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,IAAA,EAAK,OAAA;AAAA,MACL,WAAA,EAAU,cAAA;AAAA,MACV,kBAAA,EAAkB,WAAA;AAAA,MAClB,WAAWF,oBAAA,CAAG,mBAAA,CAAoB,EAAE,WAAA,EAAa,GAAG,SAAS,CAAA;AAAA,MAC5D,GAAG;AAAA;AAAA,GACN;AAEJ;AC3BA,IAAM,oBAAA,GAAuB,8BAAA;AAM7B,IAAM,kBAAA,GAA0D;AAAA,EAC9D,EAAA,EAAI,kBAAA;AAAA;AAAA,EACJ,EAAA,EAAI,cAAA;AAAA;AAAA,EACJ,OAAA,EAAS,gBAAA;AAAA;AAAA,EACT,EAAA,EAAI;AAAA;AACN,CAAA;AA0FO,SAAS,eAAA,CAAgB;AAAA,EAC9B,IAAA;AAAA,EACA,KAAA;AAAA,EACA,WAAA;AAAA,EACA,UAAA;AAAA,EACA,WAAA,GAAc,QAAA;AAAA,EACd,aAAA,GAAgB,SAAA;AAAA,EAChB,IAAA,GAAO,SAAA;AAAA,EACP,YAAA,GAAe,KAAA;AAAA,EACf,cAAA;AAAA,EACA,mBAAA;AAAA,EACA,SAAA;AAAA,EACA;AACF,CAAA,EAAyB;AACvB,EAAA,MAAM,OAAA,GAAgBG,0BAAQ,MAAM;AAClC,IAAA,OAAO,sBAAsB,IAAI,CAAA,CAAA;AAAA,EACnC,CAAA,EAAG,CAAC,IAAI,CAAC,CAAA;AAET,EAAA,MAAM,QAAA,GAAiBA,0BAAQ,MAAM;AACnC,IAAA,OAAO,OAAO,UAAA,CAAW,KAAA,IAAS,EAAE,CAAA,CAAE,IAAA,GAAO,MAAA,GAAS,CAAA;AAAA,EACxD,CAAA,EAAG,CAAC,UAAA,CAAW,KAAK,CAAC,CAAA;AAErB,EAAA,MAAM,QAAA,GAAiBA,0BAAQ,MAAM;AACnC,IAAA,OAAO,CAAC,CAAC,UAAA,CAAW,KAAA;AAAA,EACtB,CAAA,EAAG,CAAC,UAAA,CAAW,KAAK,CAAC,CAAA;AAErB,EAAA,MAAM,UAAA,GAQgBA,0BAAQ,MAAM;AAClC,IAAA,IAAI,kBAAkB,mBAAA,EAAqB;AAGzC,MAAA,OAAO,SAAS,SAAA,IAAa,IAAA,KAAS,IAAA,GAClC,MAAA,GACC,QAAQ,IAAI,CAAA,CAAA;AAAA,IACnB;AACA,IAAA,OAAO,IAAA;AAAA,EACT,CAAA,EAAG,CAAC,cAAA,EAAgB,IAAA,EAAM,mBAAmB,CAAC,CAAA;AAE9C,EAAA,MAAM,YAAA,GAAqBA,0BAAQ,MAAM;AACvC,IAAA,IAAI,cAAA,EAAgB;AAClB,MAAA,uBAAOA,iBAAA,CAAA,aAAA,CAACC,SAAA,EAAA,EAAK,IAAA,EAAM,cAAA,EAAgB,QAAQ,oBAAA,EAAsB,CAAA;AAAA,IACnE,WAAW,mBAAA,EAAqB;AAC9B,MAAA,OAAO,mBAAA;AAAA,IACT,WAAW,WAAA,EAAa;AACtB,MAAA,OAAO,WAAA;AAAA,IACT,CAAA,MAAO;AACL,MAAA,OAAO,QAAA;AAAA,IACT;AAAA,EACF,CAAA,EAAG,CAAC,mBAAA,EAAqB,cAAA,EAAgB,WAAW,CAAC,CAAA;AAErD,EAAA,uBACED,iBAAA,CAAA,aAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAWH,oBAAA,CAAG,aAAa,SAAS,CAAA,EAAA,EACtC,KAAA,oBACCG,iBAAA,CAAA,aAAA,CAACE,gCAAW,OAAA,EAAS,OAAA,EAAS,SAAA,EAAW,cAAA,EAAA,EACtC,KACH,CAAA,kBAEFF,iBAAA,CAAA,aAAA;AAAA,IAAC,WAAA;AAAA,IAAA;AAAA,MACC,SAAA,EAAWH,oBAAA;AAAA,QACT,YAAA;AAAA,QACA,CAAC,YAAY,QAAA,IAAY,kBAAA;AAAA,QACzB,QAAA,IAAY;AAAA;AACd,KAAA;AAAA,oBAEAG,iBAAA,CAAA,aAAA;AAAA,MAACG,2BAAA;AAAA,MAAA;AAAA,QACE,GAAG,UAAA;AAAA,QACJ,EAAA,EAAI,OAAA;AAAA,QACJ,iBAAA,EAAiB,IAAA;AAAA,QACjB,SAAA,EAAWN,oBAAA;AAAA,UACT,mBAAmB,IAAI,CAAA;AAAA,UACvB,8CAAA;AAAA,UACA,UAAA,CAAW;AAAA;AACb;AAAA,KACF;AAAA,oBACAG,iBAAA,CAAA,aAAA;AAAA,MAACI,wBAAA;AAAA,MAAA;AAAA,QACC,IAAA,EAAM,UAAA;AAAA,QACN,IAAA,EAAK,QAAA;AAAA,QACL,OAAA,EAAS,aAAA;AAAA,QACT,QAAA,EAAU,YAAA;AAAA,QACV,SAAA,EAAWP,oBAAA;AAAA,UACT,gCAAA;AAAA;AAAA,UAEA,SAAS,IAAA,IAAQ;AAAA;AACnB,OAAA;AAAA,MAEC,YAAA,mBACCG,iBAAA,CAAA,aAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,6DAAA,EAAA,kBACdA,iBAAA,CAAA,aAAA;AAAA,QAACC,SAAA;AAAA,QAAA;AAAA,UACC,IAAA,EAAK,8BAAA;AAAA,UACL,MAAA,EAAQ;AAAA;AAAA,OAEZ,CAAA,GACE,IAAA;AAAA,sBACJD,iBAAA,CAAA,aAAA;AAAA,QAAC,MAAA;AAAA,QAAA;AAAA,UACC,SAAA,EAAWH,oBAAA;AAAA,YACT,iCAAA;AAAA,YACA,eAAe,WAAA,GAAc;AAAA;AAC/B,SAAA;AAAA,QAEC;AAAA;AACH;AACF,GACF,EACC,WAAA,oBAAeG,iBAAA,CAAA,aAAA,CAACK,kCAAA,EAAA,IAAA,EAAkB,WAAY,CACjD,CAAA;AAEJ;AAEA,eAAA,CAAgB,WAAA,GAAc,iBAAA;;;AC1LvB,SAAS,IAAA,CAAwC;AAAA,EACtD,IAAA;AAAA,EACA,QAAA;AAAA,EACA,MAAA;AAAA,EACA,SAAA;AAAA,EACA,MAAA;AAAA,EACA,MAAA;AAAA,EACA,UAAA,GAAa,IAAA;AAAA,EACb,gBAAA;AAAA,EACA,cAAA;AAAA,EACA,eAAA;AAAA,EACA,uBAAA;AAAA,EACA,qBAAA;AAAA,EACA,eAAA;AAAA,EACA,kBAAA;AAAA,EACA,WAAA;AAAA,EACA,UAAA;AAAA,EACA,GAAG;AACL,CAAA,EAA6D;AAE3D,EAAA,MAAM,gBAAA,GAAyBC,iBAAA,CAAA,WAAA;AAAA,IAC7B,OAAO,CAAA,KAAuB;AAC5B,MAAA,IAAI;AACF,QAAA,MAAM,IAAA,CAAK,aAAa,CAAC,CAAA;AAAA,MAC3B,CAAA,CAAA,MAAQ;AAAA,MAGR;AAAA,IACF,CAAA;AAAA,IACA,CAAC,IAAI;AAAA,GACP;AAEA,EAAA,MAAM,iBAAA,GAAoB,aAAa,WAAA,EAAa,aAAA;AACpD,EAAA,MAAM,cAAA,GAAiB,UAAU,UAAA,EAAY,QAAA;AAC7C,EAAA,MAAM,cAAA,GAAiB,MAAA,IAAU,UAAA,EAAY,MAAA,IAAU,MAAA;AACvD,EAAA,MAAM,wBAAA,GACJ,oBAAoB,UAAA,EAAY,gBAAA;AAClC,EAAA,MAAM,sBAAA,GACJ,kBAAkB,kBAAA,EAAoB,cAAA;AACxC,EAAA,MAAM,uBAAA,GACJ,mBAAmB,kBAAA,EAAoB,eAAA;AACzC,EAAA,MAAM,+BAAA,GACJ,2BAA2B,WAAA,EAAa,uBAAA;AAC1C,EAAA,MAAM,6BAAA,GACJ,yBAAyB,WAAA,EAAa,qBAAA;AAExC,EAAA,MAAM,QAAA,GAAW,0BAA0B,QAAA,IAAY,kBAAA;AAEvD,EAAA,MAAM,wBAAA,GACJ,wBAAA,KAA6B,MAAA,IAC7B,sBAAA,KAA2B,MAAA,IAC3B,+BAAA,KAAoC,MAAA,IACpC,6BAAA,KAAkC,MAAA,IAClC,uBAAA,IAA2B,IAAA,IAC3B,eAAA,KAAoB,MAAA;AAEtB,EAAA,MAAM,kBAAA,GAAqB,QAAQ,uBAAuB,CAAA;AAE1D,EAAA,MAAM,sBAAA,GACJ,wBAAA,IACA,IAAA,CAAK,MAAA,KAAW,aAChB,CAAC,kBAAA;AAEH,EAAA,MAAM,qBAAA,GACJ,QAAA,KAAa,UAAA,GACT,6CAAA,GACA,uDAAA;AAEN,EAAA,MAAM,sBAAsB,sBAAA,IAA0B,qBAAA;AAEtD,EAAA,MAAM,8BACJ,sBAAA,IACA,QAAA,KAAa,uBAAA,IACb,OAAA,CAAQ,0BAA0B,eAAe,CAAA;AAEnD,EAAA,MAAM,sBAAsB,wBAAA,EAA0B,uBAAA;AAEtD,EAAA,MAAM,uBAAA,GACJ,sBAAA,KACC,OAAO,mBAAA,EAAqB,MAAA,KAAW,YACpC,mBAAA,CAAoB,MAAA,GACpB,OAAA,CAAQ,mBAAA,EAAqB,KAAK,CAAA,CAAA;AAExC,EAAA,MAAM,kBAAA,GACJ,qBAAqB,KAAA,IAAS,yBAAA;AAEhC,EAAA,MAAM,mBAAA,GAA4BA,8BAAY,MAAM;AAClD,IAAA,IAAA,CAAK,SAAA,EAAU;AACf,IAAA,eAAA,IAAkB;AAAA,EACpB,CAAA,EAAG,CAAC,IAAA,EAAM,eAAe,CAAC,CAAA;AAG1B,EAAA,MAAM,UAAA,GAAa,YAAY,UAAA,IAAc,UAAA;AAC7C,EAAA,MAAM,sBAAsB,UAAA,KAAe,cAAA;AAC3C,EAAA,MAAM,YAAA,GACJ,MAAA,IACA,MAAA,CAAO,MAAA,KAAW,KAClB,MAAA,CAAO,CAAC,CAAA,IACR,CAAC,QAAQ,OAAA,EAAS,UAAA,EAAY,KAAA,EAAO,KAAA,EAAO,QAAQ,CAAA,CAAE,QAAA;AAAA,IACpD,MAAA,CAAO,CAAC,CAAA,CAAE;AAAA,GACZ;AACF,EAAA,MAAM,uBAAuB,mBAAA,IAAuB,YAAA;AAGpD,EAAA,MAAM,kBAAA,GAA2BA,0BAAQ,MAAM;AAC7C,IAAA,IAAI,CAAC,oBAAA,IAAwB,CAAC,UAAU,MAAA,CAAO,MAAA,KAAW,GAAG,OAAO,IAAA;AAEpE,IAAA,MAAM,KAAA,GAAQ,OAAO,CAAC,CAAA;AACtB,IAAA,MAAM,UAAA,GAAa,IAAA,CAAK,aAAA,CAAc,KAAA,CAAM,IAAI,CAAA;AAEhD,IAAA,uBACEA,iBAAA,CAAA,aAAA;AAAA,MAAC,eAAA;AAAA,MAAA;AAAA,QACC,MAAM,KAAA,CAAM,IAAA;AAAA,QACZ,OAAO,KAAA,CAAM,KAAA;AAAA,QACb,WAAW,KAAA,CAAM,SAAA;AAAA,QACjB,UAAA,EAAY;AAAA,UACV,MAAM,UAAA,CAAW,IAAA;AAAA,UACjB,OAAO,UAAA,CAAW,KAAA;AAAA,UAClB,UAAU,UAAA,CAAW,QAAA;AAAA,UACrB,QAAQ,UAAA,CAAW,MAAA;AAAA,UACnB,MAAM,KAAA,CAAM,IAAA;AAAA,UAOZ,aAAa,KAAA,CAAM,WAAA;AAAA,UACnB,UAAU,KAAA,CAAM,QAAA;AAAA,UAChB,UAAU,KAAA,CAAM;AAAA,SAClB;AAAA,QACA,aAAa,UAAA,EAAY,WAAA;AAAA,QACzB,eAAe,UAAA,EAAY,aAAA;AAAA,QAC3B,gBAAgB,UAAA,EAAY,cAAA;AAAA,QAC5B,qBAAqB,UAAA,EAAY,mBAAA;AAAA,QACjC,MAAM,UAAA,EAAY,eAAA;AAAA,QAClB,cAAc,IAAA,CAAK;AAAA;AAAA,KACrB;AAAA,EAEJ,GAAG,CAAC,oBAAA,EAAsB,MAAA,EAAQ,IAAA,EAAM,UAAU,CAAC,CAAA;AAEnD,EAAA,uBACEA,iBAAA,CAAA,aAAA,CAACC,6BAAA,CAAY,QAAA,EAAZ,EAAqB,OAAO,IAAA,EAAA,kBAC3BD,iBAAA,CAAA,aAAA;AAAA,IAAC,MAAA;AAAA,IAAA;AAAA,MACC,QAAA,EAAU,gBAAA;AAAA,MACV,MAAA,EAAQ,cAAA;AAAA,MACR,MAAA,EAAQ,cAAA;AAAA,MACR,UAAA;AAAA,MACA,SAAA,EAAW,iBAAA;AAAA,MACV,GAAG;AAAA,KAAA;AAAA,IAEH,yCACCA,iBAAA,CAAA,aAAA,CAAC,KAAA,EAAA,EAAI,WAAU,WAAA,EAAA,EACZ,2BAAA,GACC,0BAA0B,eAAA,mBAE1BA,iBAAA,CAAA,aAAA;AAAA,MAAC,YAAA;AAAA,MAAA;AAAA,QACC,cAAA,EAAgB,mBAAA;AAAA,QAChB,uBAAA,EAAyB;AAAA;AAAA,OAI5B,uBAAA,mBACCA,iBAAA,CAAA,aAAA;AAAA,MAACF,wBAAA;AAAA,MAAA;AAAA,QACC,IAAA,EAAK,QAAA;AAAA,QACL,OAAA,EAAQ,SAAA;AAAA,QACR,OAAA,EAAS;AAAA,OAAA;AAAA,MAER;AAAA,KACH,GACE,IACN,CAAA,mBAEAE,iBAAA,CAAA,aAAA,CAAAA,iBAAA,CAAA,QAAA,EAAA,IAAA,EACG,oBAAA,GAAuB,kBAAA,GAAqB,QAAA,EAC5C,uBAAA,mBACCA,iBAAA,CAAA,aAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,MAAA,EAAA,kBACbA,iBAAA,CAAA,aAAA;AAAA,MAAC,YAAA;AAAA,MAAA;AAAA,QACC,eAAA,EAAiB,uBAAA;AAAA,QACjB,qBAAA,EAAuB;AAAA;AAAA,KAE3B,IACE,IACN;AAAA,GAGN,CAAA;AAEJ;AAEA,IAAA,CAAK,WAAA,GAAc,MAAA","file":"chunk-3ED2FKXF.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, FieldDescription } 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\n// Size-specific classes for input — height overrides ensure the input matches\n// the button height for every size variant.\nconst INPUT_SIZE_CLASSES: Record<ButtonGroupFormSize, string> = {\n xs: \"h-6 text-xs px-3\", // button: h-6 → match\n sm: \"text-sm px-3\", // button: h-8 overridden to h-9 below → match\n default: \"text-base px-4\", // button: h-9 (no override needed)\n lg: \"h-10 text-md px-6\", // button: h-10 → match\n};\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 * Optional description below the input\n */\n description?: 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 (input height / button height — always equal):\n * - xs: h-6 / h-6\n * - sm: h-9 / h-9\n * - default: h-9 / h-9\n * - lg: h-10 / h-10\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 description,\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 = React.useMemo(() => {\n return `button-group-input-${name}`;\n }, [name]);\n\n const hasValue = React.useMemo(() => {\n return String(inputProps.value ?? \"\").trim().length > 0;\n }, [inputProps.value]);\n\n const hasError = React.useMemo(() => {\n return !!inputProps.error;\n }, [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 // 'sm' maps to 'icon' (size-9) rather than 'icon-sm' (size-8) so the\n // icon button stays the same height as the h-9 input.\n return size === \"default\" || size === \"sm\"\n ? \"icon\"\n : (`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 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 className={cn(\n \"rounded-md\",\n !hasError && hasValue && \"ring-2 ring-ring\",\n hasError && \"ring-1 ring-destructive\",\n )}\n >\n <TextInput\n {...inputProps}\n id={inputId}\n suppressValueRing\n className={cn(\n INPUT_SIZE_CLASSES[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 \"relative rounded-l-none ring-0\",\n // 'sm' button variant is h-8; override to h-9 to align with input\n size === \"sm\" && \"h-9\",\n )}\n >\n {isSubmitting ? (\n <span className=\"absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2\">\n <Icon\n name=\"line-md/loading-twotone-loop\"\n apiKey={DEFAULT_ICON_API_KEY}\n />\n </span>\n ) : null}\n <span\n className={cn(\n \"transition-opacity duration-200\",\n isSubmitting ? \"opacity-0\" : \"opacity-100\",\n )}\n >\n {labelElement}\n </span>\n </Button>\n </ButtonGroup>\n {description && <FieldDescription>{description}</FieldDescription>}\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 { ButtonGroupFormFieldConfig } 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 ButtonGroupFormFieldConfig;\n const fieldProps = form.getFieldProps(field.name);\n\n return (\n <ButtonGroupForm\n name={field.name}\n label={field.label}\n className={field.className}\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,13 +1,13 @@
1
- import { FormContext } from './chunk-MJYEXJ3U.js';
2
- import { cn, FieldLabel, TextInput, Button } from './chunk-455PI4LV.js';
3
- import * as React4 from 'react';
1
+ import { FormContext } from './chunk-SNSK3TMG.js';
2
+ import { cn, FieldLabel, TextInput, Button, FieldDescription } from './chunk-J37BGNM6.js';
3
+ import * as React3 from 'react';
4
4
  import { cva } from 'class-variance-authority';
5
5
  import 'radix-ui';
6
6
  import { Icon } from '@page-speed/icon';
7
7
 
8
8
  function renderMessage(message, fallbackClassName, className) {
9
9
  if (typeof message === "string") {
10
- return /* @__PURE__ */ React4.createElement(
10
+ return /* @__PURE__ */ React3.createElement(
11
11
  "p",
12
12
  {
13
13
  className: cn(
@@ -18,7 +18,7 @@ function renderMessage(message, fallbackClassName, className) {
18
18
  message
19
19
  );
20
20
  }
21
- return /* @__PURE__ */ React4.createElement("div", { className: cn(fallbackClassName, className) }, message);
21
+ return /* @__PURE__ */ React3.createElement("div", { className: cn(fallbackClassName, className) }, message);
22
22
  }
23
23
  function FormFeedback({
24
24
  successMessage,
@@ -29,7 +29,7 @@ function FormFeedback({
29
29
  if (!successMessage && !submissionError) {
30
30
  return null;
31
31
  }
32
- return /* @__PURE__ */ React4.createElement(React4.Fragment, null, successMessage ? /* @__PURE__ */ React4.createElement(
32
+ return /* @__PURE__ */ React3.createElement(React3.Fragment, null, successMessage ? /* @__PURE__ */ React3.createElement(
33
33
  "div",
34
34
  {
35
35
  className: cn(
@@ -44,7 +44,7 @@ function FormFeedback({
44
44
  "text-primary-foreground",
45
45
  "text-primary-foreground"
46
46
  )
47
- ) : null, submissionError ? /* @__PURE__ */ React4.createElement(
47
+ ) : null, submissionError ? /* @__PURE__ */ React3.createElement(
48
48
  "div",
49
49
  {
50
50
  className: cn(
@@ -81,7 +81,7 @@ function ButtonGroup({
81
81
  orientation,
82
82
  ...props
83
83
  }) {
84
- return /* @__PURE__ */ React4.createElement(
84
+ return /* @__PURE__ */ React3.createElement(
85
85
  "div",
86
86
  {
87
87
  role: "group",
@@ -93,9 +93,20 @@ function ButtonGroup({
93
93
  );
94
94
  }
95
95
  var DEFAULT_ICON_API_KEY = "au382bi7fsh96w9h9xlrnat2jglx";
96
+ var INPUT_SIZE_CLASSES = {
97
+ xs: "h-6 text-xs px-3",
98
+ // button: h-6 → match
99
+ sm: "text-sm px-3",
100
+ // button: h-8 overridden to h-9 below → match
101
+ default: "text-base px-4",
102
+ // button: h-9 (no override needed)
103
+ lg: "h-10 text-md px-6"
104
+ // button: h-10 → match
105
+ };
96
106
  function ButtonGroupForm({
97
107
  name,
98
108
  label,
109
+ description,
99
110
  inputProps,
100
111
  submitLabel = "Submit",
101
112
  submitVariant = "default",
@@ -106,18 +117,24 @@ function ButtonGroupForm({
106
117
  className,
107
118
  labelClassName
108
119
  }) {
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(() => {
120
+ const inputId = React3.useMemo(() => {
121
+ return `button-group-input-${name}`;
122
+ }, [name]);
123
+ const hasValue = React3.useMemo(() => {
124
+ return String(inputProps.value ?? "").trim().length > 0;
125
+ }, [inputProps.value]);
126
+ const hasError = React3.useMemo(() => {
127
+ return !!inputProps.error;
128
+ }, [inputProps.error]);
129
+ const buttonSize = React3.useMemo(() => {
113
130
  if (submitIconName || submitIconComponent) {
114
- return size === "default" ? "icon" : `icon-${size}`;
131
+ return size === "default" || size === "sm" ? "icon" : `icon-${size}`;
115
132
  }
116
133
  return size;
117
134
  }, [submitIconName, size, submitIconComponent]);
118
- const labelElement = React4.useMemo(() => {
135
+ const labelElement = React3.useMemo(() => {
119
136
  if (submitIconName) {
120
- return /* @__PURE__ */ React4.createElement(Icon, { name: submitIconName, apiKey: DEFAULT_ICON_API_KEY });
137
+ return /* @__PURE__ */ React3.createElement(Icon, { name: submitIconName, apiKey: DEFAULT_ICON_API_KEY });
121
138
  } else if (submitIconComponent) {
122
139
  return submitIconComponent;
123
140
  } else if (submitLabel) {
@@ -126,37 +143,60 @@ function ButtonGroupForm({
126
143
  return "Submit";
127
144
  }
128
145
  }, [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,
146
+ return /* @__PURE__ */ React3.createElement("div", { className: cn("space-y-2", className) }, label && /* @__PURE__ */ React3.createElement(FieldLabel, { htmlFor: inputId, className: labelClassName }, label), /* @__PURE__ */ React3.createElement(
147
+ ButtonGroup,
137
148
  {
138
- ...inputProps,
139
- id: inputId,
140
149
  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"
150
+ "rounded-md",
151
+ !hasError && hasValue && "ring-2 ring-ring",
152
+ hasError && "ring-1 ring-destructive"
156
153
  )
157
154
  },
158
- labelElement
159
- )));
155
+ /* @__PURE__ */ React3.createElement(
156
+ TextInput,
157
+ {
158
+ ...inputProps,
159
+ id: inputId,
160
+ suppressValueRing: true,
161
+ className: cn(
162
+ INPUT_SIZE_CLASSES[size],
163
+ "border-r-0 rounded-r-none focus-visible:z-10",
164
+ inputProps.className
165
+ )
166
+ }
167
+ ),
168
+ /* @__PURE__ */ React3.createElement(
169
+ Button,
170
+ {
171
+ size: buttonSize,
172
+ type: "submit",
173
+ variant: submitVariant,
174
+ disabled: isSubmitting,
175
+ className: cn(
176
+ "relative rounded-l-none ring-0",
177
+ // 'sm' button variant is h-8; override to h-9 to align with input
178
+ size === "sm" && "h-9"
179
+ )
180
+ },
181
+ isSubmitting ? /* @__PURE__ */ React3.createElement("span", { className: "absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2" }, /* @__PURE__ */ React3.createElement(
182
+ Icon,
183
+ {
184
+ name: "line-md/loading-twotone-loop",
185
+ apiKey: DEFAULT_ICON_API_KEY
186
+ }
187
+ )) : null,
188
+ /* @__PURE__ */ React3.createElement(
189
+ "span",
190
+ {
191
+ className: cn(
192
+ "transition-opacity duration-200",
193
+ isSubmitting ? "opacity-0" : "opacity-100"
194
+ )
195
+ },
196
+ labelElement
197
+ )
198
+ )
199
+ ), description && /* @__PURE__ */ React3.createElement(FieldDescription, null, description));
160
200
  }
161
201
  ButtonGroupForm.displayName = "ButtonGroupForm";
162
202
 
@@ -180,7 +220,7 @@ function Form({
180
220
  formConfig,
181
221
  ...props
182
222
  }) {
183
- const handleFormSubmit = React4.useCallback(
223
+ const handleFormSubmit = React3.useCallback(
184
224
  async (e) => {
185
225
  try {
186
226
  await form.handleSubmit(e);
@@ -207,7 +247,7 @@ function Form({
207
247
  const newSubmissionAction = resolvedSubmissionConfig?.newFormSubmissionAction;
208
248
  const showNewSubmissionAction = isSubmissionSuccessful && (typeof newSubmissionAction?.enable === "boolean" ? newSubmissionAction.enable : Boolean(newSubmissionAction?.label));
209
249
  const newSubmissionLabel = newSubmissionAction?.label ?? "Submit another response";
210
- const handleNewSubmission = React4.useCallback(() => {
250
+ const handleNewSubmission = React3.useCallback(() => {
211
251
  form.resetForm();
212
252
  onNewSubmission?.();
213
253
  }, [form, onNewSubmission]);
@@ -217,15 +257,16 @@ function Form({
217
257
  fields[0].type
218
258
  );
219
259
  const shouldUseButtonGroup = isButtonGroupLayout && hasTextField;
220
- const buttonGroupContent = React4.useMemo(() => {
260
+ const buttonGroupContent = React3.useMemo(() => {
221
261
  if (!shouldUseButtonGroup || !fields || fields.length === 0) return null;
222
262
  const field = fields[0];
223
263
  const fieldProps = form.getFieldProps(field.name);
224
- return /* @__PURE__ */ React4.createElement(
264
+ return /* @__PURE__ */ React3.createElement(
225
265
  ButtonGroupForm,
226
266
  {
227
267
  name: field.name,
228
268
  label: field.label,
269
+ className: field.className,
229
270
  inputProps: {
230
271
  name: fieldProps.name,
231
272
  value: fieldProps.value,
@@ -245,7 +286,7 @@ function Form({
245
286
  }
246
287
  );
247
288
  }, [shouldUseButtonGroup, fields, form, formConfig]);
248
- return /* @__PURE__ */ React4.createElement(FormContext.Provider, { value: form }, /* @__PURE__ */ React4.createElement(
289
+ return /* @__PURE__ */ React3.createElement(FormContext.Provider, { value: form }, /* @__PURE__ */ React3.createElement(
249
290
  "form",
250
291
  {
251
292
  onSubmit: handleFormSubmit,
@@ -255,13 +296,13 @@ function Form({
255
296
  className: resolvedClassName,
256
297
  ...props
257
298
  },
258
- isSubmissionSuccessful ? /* @__PURE__ */ React4.createElement("div", { className: "space-y-4" }, shouldRenderCustomComponent ? resolvedSubmissionConfig?.customComponent : /* @__PURE__ */ React4.createElement(
299
+ isSubmissionSuccessful ? /* @__PURE__ */ React3.createElement("div", { className: "space-y-4" }, shouldRenderCustomComponent ? resolvedSubmissionConfig?.customComponent : /* @__PURE__ */ React3.createElement(
259
300
  FormFeedback,
260
301
  {
261
302
  successMessage: finalSuccessMessage,
262
303
  successMessageClassName: resolvedSuccessMessageClassName
263
304
  }
264
- ), showNewSubmissionAction ? /* @__PURE__ */ React4.createElement(
305
+ ), showNewSubmissionAction ? /* @__PURE__ */ React3.createElement(
265
306
  Button,
266
307
  {
267
308
  type: "button",
@@ -269,7 +310,7 @@ function Form({
269
310
  onClick: handleNewSubmission
270
311
  },
271
312
  newSubmissionLabel
272
- ) : null) : /* @__PURE__ */ React4.createElement(React4.Fragment, null, shouldUseButtonGroup ? buttonGroupContent : children, resolvedSubmissionError ? /* @__PURE__ */ React4.createElement("div", { className: "mt-4" }, /* @__PURE__ */ React4.createElement(
313
+ ) : null) : /* @__PURE__ */ React3.createElement(React3.Fragment, null, shouldUseButtonGroup ? buttonGroupContent : children, resolvedSubmissionError ? /* @__PURE__ */ React3.createElement("div", { className: "mt-4" }, /* @__PURE__ */ React3.createElement(
273
314
  FormFeedback,
274
315
  {
275
316
  submissionError: resolvedSubmissionError,
@@ -281,5 +322,5 @@ function Form({
281
322
  Form.displayName = "Form";
282
323
 
283
324
  export { ButtonGroupForm, Form, FormFeedback };
284
- //# sourceMappingURL=chunk-ZEAH6AKP.js.map
285
- //# sourceMappingURL=chunk-ZEAH6AKP.js.map
325
+ //# sourceMappingURL=chunk-H3YJRLVO.js.map
326
+ //# sourceMappingURL=chunk-H3YJRLVO.js.map