@page-speed/forms 0.6.1 → 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.
- package/dist/{FormContext-DaRyEYnF.d.ts → FormContext-Db0L3Kwv.d.ts} +1 -1
- package/dist/{FormContext-KsjKSot3.d.cts → FormContext-kKZxeb7G.d.cts} +1 -1
- package/dist/{chunk-F5ZJCJOD.cjs → chunk-3ED2FKXF.cjs} +112 -58
- package/dist/chunk-3ED2FKXF.cjs.map +1 -0
- package/dist/{chunk-7ZX2EUOG.js → chunk-H3YJRLVO.js} +105 -51
- package/dist/chunk-H3YJRLVO.js.map +1 -0
- package/dist/{chunk-455PI4LV.js → chunk-J37BGNM6.js} +5 -4
- package/dist/chunk-J37BGNM6.js.map +1 -0
- package/dist/{chunk-4ROWNTY6.js → chunk-ML6FGUYS.js} +3 -3
- package/dist/{chunk-4ROWNTY6.js.map → chunk-ML6FGUYS.js.map} +1 -1
- package/dist/{chunk-QRI5TMES.cjs → chunk-QMWZLGON.cjs} +5 -4
- package/dist/chunk-QMWZLGON.cjs.map +1 -0
- package/dist/{chunk-MJYEXJ3U.js → chunk-SNSK3TMG.js} +3 -3
- package/dist/{chunk-MJYEXJ3U.js.map → chunk-SNSK3TMG.js.map} +1 -1
- package/dist/{chunk-ED4UK63G.cjs → chunk-UQ6JPOBF.cjs} +114 -114
- package/dist/{chunk-ED4UK63G.cjs.map → chunk-UQ6JPOBF.cjs.map} +1 -1
- package/dist/{chunk-MUBEMXI7.cjs → chunk-V545YJFP.cjs} +6 -6
- package/dist/{chunk-MUBEMXI7.cjs.map → chunk-V545YJFP.cjs.map} +1 -1
- package/dist/core.cjs +10 -10
- package/dist/core.d.cts +17 -9
- package/dist/core.d.ts +17 -9
- package/dist/core.js +3 -3
- package/dist/index.cjs +14 -14
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +3 -3
- package/dist/inputs.cjs +14 -14
- package/dist/inputs.d.cts +8 -2
- package/dist/inputs.d.ts +8 -2
- package/dist/inputs.js +2 -2
- package/dist/integration.cjs +17 -17
- package/dist/integration.cjs.map +1 -1
- package/dist/integration.d.cts +3 -112
- package/dist/integration.d.ts +3 -112
- package/dist/integration.js +3 -3
- package/dist/integration.js.map +1 -1
- package/dist/{types-RnnhRtD2.d.ts → types-BPxsUGm_.d.cts} +124 -2
- package/dist/{types-RnnhRtD2.d.cts → types-BPxsUGm_.d.ts} +124 -2
- package/dist/validation-rules.d.cts +1 -1
- package/dist/validation-rules.d.ts +1 -1
- package/dist/validation-utils.d.cts +1 -1
- package/dist/validation-utils.d.ts +1 -1
- package/dist/validation-valibot.d.cts +1 -1
- package/dist/validation-valibot.d.ts +1 -1
- package/dist/validation.d.cts +1 -1
- package/dist/validation.d.ts +1 -1
- package/package.json +1 -1
- package/dist/chunk-455PI4LV.js.map +0 -1
- package/dist/chunk-7ZX2EUOG.js.map +0 -1
- package/dist/chunk-F5ZJCJOD.cjs.map +0 -1
- package/dist/chunk-QRI5TMES.cjs.map +0 -1
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { FormContext } from './chunk-
|
|
2
|
-
import { cn, FieldLabel, TextInput, Button } from './chunk-
|
|
3
|
-
import * as
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
84
|
+
return /* @__PURE__ */ React3.createElement(
|
|
85
85
|
"div",
|
|
86
86
|
{
|
|
87
87
|
role: "group",
|
|
@@ -93,58 +93,110 @@ 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",
|
|
102
113
|
size = "default",
|
|
103
114
|
isSubmitting = false,
|
|
104
115
|
submitIconName,
|
|
116
|
+
submitIconComponent,
|
|
105
117
|
className,
|
|
106
118
|
labelClassName
|
|
107
119
|
}) {
|
|
108
|
-
const inputId =
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
const
|
|
112
|
-
|
|
113
|
-
|
|
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(() => {
|
|
130
|
+
if (submitIconName || submitIconComponent) {
|
|
131
|
+
return size === "default" || size === "sm" ? "icon" : `icon-${size}`;
|
|
114
132
|
}
|
|
115
133
|
return size;
|
|
116
|
-
}, [submitIconName, size]);
|
|
117
|
-
const
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
...inputProps,
|
|
127
|
-
id: inputId,
|
|
128
|
-
className: cn(
|
|
129
|
-
inputSizeClasses[size],
|
|
130
|
-
"border-r-0 rounded-r-none focus-visible:z-10",
|
|
131
|
-
inputProps.className
|
|
132
|
-
)
|
|
134
|
+
}, [submitIconName, size, submitIconComponent]);
|
|
135
|
+
const labelElement = React3.useMemo(() => {
|
|
136
|
+
if (submitIconName) {
|
|
137
|
+
return /* @__PURE__ */ React3.createElement(Icon, { name: submitIconName, apiKey: DEFAULT_ICON_API_KEY });
|
|
138
|
+
} else if (submitIconComponent) {
|
|
139
|
+
return submitIconComponent;
|
|
140
|
+
} else if (submitLabel) {
|
|
141
|
+
return submitLabel;
|
|
142
|
+
} else {
|
|
143
|
+
return "Submit";
|
|
133
144
|
}
|
|
134
|
-
|
|
135
|
-
|
|
145
|
+
}, [submitIconComponent, submitIconName, submitLabel]);
|
|
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,
|
|
136
148
|
{
|
|
137
|
-
size: buttonSize,
|
|
138
|
-
type: "submit",
|
|
139
|
-
variant: submitVariant,
|
|
140
|
-
disabled: isSubmitting,
|
|
141
149
|
className: cn(
|
|
142
|
-
"rounded-
|
|
143
|
-
!hasError && hasValue && "ring-2 ring-ring"
|
|
150
|
+
"rounded-md",
|
|
151
|
+
!hasError && hasValue && "ring-2 ring-ring",
|
|
152
|
+
hasError && "ring-1 ring-destructive"
|
|
144
153
|
)
|
|
145
154
|
},
|
|
146
|
-
|
|
147
|
-
|
|
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));
|
|
148
200
|
}
|
|
149
201
|
ButtonGroupForm.displayName = "ButtonGroupForm";
|
|
150
202
|
|
|
@@ -168,7 +220,7 @@ function Form({
|
|
|
168
220
|
formConfig,
|
|
169
221
|
...props
|
|
170
222
|
}) {
|
|
171
|
-
const handleFormSubmit =
|
|
223
|
+
const handleFormSubmit = React3.useCallback(
|
|
172
224
|
async (e) => {
|
|
173
225
|
try {
|
|
174
226
|
await form.handleSubmit(e);
|
|
@@ -195,7 +247,7 @@ function Form({
|
|
|
195
247
|
const newSubmissionAction = resolvedSubmissionConfig?.newFormSubmissionAction;
|
|
196
248
|
const showNewSubmissionAction = isSubmissionSuccessful && (typeof newSubmissionAction?.enable === "boolean" ? newSubmissionAction.enable : Boolean(newSubmissionAction?.label));
|
|
197
249
|
const newSubmissionLabel = newSubmissionAction?.label ?? "Submit another response";
|
|
198
|
-
const handleNewSubmission =
|
|
250
|
+
const handleNewSubmission = React3.useCallback(() => {
|
|
199
251
|
form.resetForm();
|
|
200
252
|
onNewSubmission?.();
|
|
201
253
|
}, [form, onNewSubmission]);
|
|
@@ -205,15 +257,16 @@ function Form({
|
|
|
205
257
|
fields[0].type
|
|
206
258
|
);
|
|
207
259
|
const shouldUseButtonGroup = isButtonGroupLayout && hasTextField;
|
|
208
|
-
const buttonGroupContent =
|
|
260
|
+
const buttonGroupContent = React3.useMemo(() => {
|
|
209
261
|
if (!shouldUseButtonGroup || !fields || fields.length === 0) return null;
|
|
210
262
|
const field = fields[0];
|
|
211
263
|
const fieldProps = form.getFieldProps(field.name);
|
|
212
|
-
return /* @__PURE__ */
|
|
264
|
+
return /* @__PURE__ */ React3.createElement(
|
|
213
265
|
ButtonGroupForm,
|
|
214
266
|
{
|
|
215
267
|
name: field.name,
|
|
216
268
|
label: field.label,
|
|
269
|
+
className: field.className,
|
|
217
270
|
inputProps: {
|
|
218
271
|
name: fieldProps.name,
|
|
219
272
|
value: fieldProps.value,
|
|
@@ -227,12 +280,13 @@ function Form({
|
|
|
227
280
|
submitLabel: formConfig?.submitLabel,
|
|
228
281
|
submitVariant: formConfig?.submitVariant,
|
|
229
282
|
submitIconName: formConfig?.submitIconName,
|
|
283
|
+
submitIconComponent: formConfig?.submitIconComponent,
|
|
230
284
|
size: formConfig?.buttonGroupSize,
|
|
231
285
|
isSubmitting: form.isSubmitting
|
|
232
286
|
}
|
|
233
287
|
);
|
|
234
288
|
}, [shouldUseButtonGroup, fields, form, formConfig]);
|
|
235
|
-
return /* @__PURE__ */
|
|
289
|
+
return /* @__PURE__ */ React3.createElement(FormContext.Provider, { value: form }, /* @__PURE__ */ React3.createElement(
|
|
236
290
|
"form",
|
|
237
291
|
{
|
|
238
292
|
onSubmit: handleFormSubmit,
|
|
@@ -242,13 +296,13 @@ function Form({
|
|
|
242
296
|
className: resolvedClassName,
|
|
243
297
|
...props
|
|
244
298
|
},
|
|
245
|
-
isSubmissionSuccessful ? /* @__PURE__ */
|
|
299
|
+
isSubmissionSuccessful ? /* @__PURE__ */ React3.createElement("div", { className: "space-y-4" }, shouldRenderCustomComponent ? resolvedSubmissionConfig?.customComponent : /* @__PURE__ */ React3.createElement(
|
|
246
300
|
FormFeedback,
|
|
247
301
|
{
|
|
248
302
|
successMessage: finalSuccessMessage,
|
|
249
303
|
successMessageClassName: resolvedSuccessMessageClassName
|
|
250
304
|
}
|
|
251
|
-
), showNewSubmissionAction ? /* @__PURE__ */
|
|
305
|
+
), showNewSubmissionAction ? /* @__PURE__ */ React3.createElement(
|
|
252
306
|
Button,
|
|
253
307
|
{
|
|
254
308
|
type: "button",
|
|
@@ -256,7 +310,7 @@ function Form({
|
|
|
256
310
|
onClick: handleNewSubmission
|
|
257
311
|
},
|
|
258
312
|
newSubmissionLabel
|
|
259
|
-
) : null) : /* @__PURE__ */
|
|
313
|
+
) : null) : /* @__PURE__ */ React3.createElement(React3.Fragment, null, shouldUseButtonGroup ? buttonGroupContent : children, resolvedSubmissionError ? /* @__PURE__ */ React3.createElement("div", { className: "mt-4" }, /* @__PURE__ */ React3.createElement(
|
|
260
314
|
FormFeedback,
|
|
261
315
|
{
|
|
262
316
|
submissionError: resolvedSubmissionError,
|
|
@@ -268,5 +322,5 @@ function Form({
|
|
|
268
322
|
Form.displayName = "Form";
|
|
269
323
|
|
|
270
324
|
export { ButtonGroupForm, Form, FormFeedback };
|
|
271
|
-
//# sourceMappingURL=chunk-
|
|
272
|
-
//# sourceMappingURL=chunk-
|
|
325
|
+
//# sourceMappingURL=chunk-H3YJRLVO.js.map
|
|
326
|
+
//# sourceMappingURL=chunk-H3YJRLVO.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/form-feedback.tsx","../src/components/ui/button-group.tsx","../src/core/button-group-form.tsx","../src/core/Form.tsx"],"names":["React","React2","React4"],"mappings":"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","file":"chunk-H3YJRLVO.js","sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../lib/utils\";\n\nexport interface FormFeedbackProps {\n successMessage?: React.ReactNode;\n submissionError?: React.ReactNode;\n successMessageClassName?: string;\n errorMessageClassName?: string;\n}\n\nfunction renderMessage(\n message: React.ReactNode,\n fallbackClassName: string,\n className?: string,\n) {\n if (typeof message === \"string\") {\n return (\n <p\n className={cn(\n \"text-sm font-medium text-center text-balance\",\n className,\n )}\n >\n {message}\n </p>\n );\n }\n\n return <div className={cn(fallbackClassName, className)}>{message}</div>;\n}\n\nexport function FormFeedback({\n successMessage,\n submissionError,\n successMessageClassName,\n errorMessageClassName,\n}: FormFeedbackProps) {\n if (!successMessage && !submissionError) {\n return null;\n }\n\n return (\n <>\n {successMessage ? (\n <div\n className={cn(\n \"rounded-md border border-primary bg-primary px-4 py-3 shadow-sm\",\n successMessageClassName,\n )}\n role=\"status\"\n aria-live=\"polite\"\n >\n {renderMessage(\n successMessage,\n \"text-primary-foreground\",\n \"text-primary-foreground\",\n )}\n </div>\n ) : null}\n\n {submissionError ? (\n <div\n className={cn(\n \"rounded-md border border-destructive bg-destructive px-4 py-3 shadow-sm\",\n errorMessageClassName,\n )}\n role=\"alert\"\n aria-live=\"assertive\"\n >\n {renderMessage(\n submissionError,\n \"text-destructive-foreground\",\n \"text-destructive-foreground\",\n )}\n </div>\n ) : null}\n </>\n );\n}\n\nFormFeedback.displayName = \"FormFeedback\";\n","import * as React from \"react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\nimport { Slot } from \"radix-ui\"\n\nimport { cn } from \"../../lib/utils\"\nimport { Separator } from \"./separator\"\n\nconst buttonGroupVariants = cva(\n \"flex w-fit items-stretch [&>*]:focus-visible:z-10 [&>*]:focus-visible:relative [&>[data-slot=select-trigger]:not([class*='w-'])]:w-fit [&>input]:flex-1 has-[select[aria-hidden=true]:last-child]:[&>[data-slot=select-trigger]:last-of-type]:rounded-r-md has-[>[data-slot=button-group]]:gap-2\",\n {\n variants: {\n orientation: {\n horizontal:\n \"[&>*:not(:first-child)]:rounded-l-none [&>*:not(:first-child)]:border-l-0 [&>*:not(:last-child)]:rounded-r-none\",\n vertical:\n \"flex-col [&>*:not(:first-child)]:rounded-t-none [&>*:not(:first-child)]:border-t-0 [&>*:not(:last-child)]:rounded-b-none\",\n },\n },\n defaultVariants: {\n orientation: \"horizontal\",\n },\n }\n)\n\nfunction ButtonGroup({\n className,\n orientation,\n ...props\n}: React.ComponentProps<\"div\"> & VariantProps<typeof buttonGroupVariants>) {\n return (\n <div\n role=\"group\"\n data-slot=\"button-group\"\n data-orientation={orientation}\n className={cn(buttonGroupVariants({ orientation }), className)}\n {...props}\n />\n )\n}\n\nfunction ButtonGroupText({\n className,\n asChild = false,\n ...props\n}: React.ComponentProps<\"div\"> & {\n asChild?: boolean\n}) {\n const Comp = asChild ? Slot.Root : \"div\"\n\n return (\n <Comp\n className={cn(\n \"bg-muted flex items-center gap-2 rounded-md border px-4 text-sm font-medium shadow-xs [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction ButtonGroupSeparator({\n className,\n orientation = \"vertical\",\n ...props\n}: React.ComponentProps<typeof Separator>) {\n return (\n <Separator\n data-slot=\"button-group-separator\"\n orientation={orientation}\n className={cn(\n \"bg-input relative !m-0 self-stretch data-[orientation=vertical]:h-auto\",\n className\n )}\n {...props}\n />\n )\n}\n\nexport {\n ButtonGroup,\n ButtonGroupSeparator,\n ButtonGroupText,\n buttonGroupVariants,\n}\n","\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { Button } from \"../components/ui/button\";\nimport { ButtonGroup } from \"../components/ui/button-group\";\nimport { FieldLabel, 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"]}
|
|
@@ -151,6 +151,7 @@ function TextInput({
|
|
|
151
151
|
className = "",
|
|
152
152
|
type = "text",
|
|
153
153
|
id = "text",
|
|
154
|
+
suppressValueRing = false,
|
|
154
155
|
...props
|
|
155
156
|
}) {
|
|
156
157
|
const handleChange = (e) => {
|
|
@@ -173,8 +174,8 @@ function TextInput({
|
|
|
173
174
|
disabled,
|
|
174
175
|
required,
|
|
175
176
|
className: cn(
|
|
176
|
-
// Valid value indicator - ring-2 when has value and
|
|
177
|
-
!error && hasValue && "ring-2 ring-ring",
|
|
177
|
+
// Valid value indicator - ring-2 when has value, no error, and not suppressed
|
|
178
|
+
!suppressValueRing && !error && hasValue && "ring-2 ring-ring",
|
|
178
179
|
// Error state - handled by Input component via aria-invalid
|
|
179
180
|
className
|
|
180
181
|
),
|
|
@@ -284,5 +285,5 @@ var LabelGroup = ({
|
|
|
284
285
|
};
|
|
285
286
|
|
|
286
287
|
export { Button, Field, FieldDescription, FieldError, FieldGroup, FieldLabel, INPUT_AUTOFILL_RESET_CLASSES, Input, LabelGroup, TextInput, buttonVariants, cn };
|
|
287
|
-
//# sourceMappingURL=chunk-
|
|
288
|
-
//# sourceMappingURL=chunk-
|
|
288
|
+
//# sourceMappingURL=chunk-J37BGNM6.js.map
|
|
289
|
+
//# sourceMappingURL=chunk-J37BGNM6.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/utils.ts","../src/components/ui/label.tsx","../src/components/ui/field.tsx","../src/components/ui/input.tsx","../src/inputs/TextInput.tsx","../src/components/ui/button.tsx","../src/core/label-group.tsx"],"names":["React","LabelPrimitive","React3","React4","React5","React6"],"mappings":"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","file":"chunk-J37BGNM6.js","sourcesContent":["import { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n\n/**\n * Normalizes browser autofill colors so inputs keep theme colors.\n */\nexport const INPUT_AUTOFILL_RESET_CLASSES =\n \"autofill:bg-transparent autofill:text-foreground \" +\n \"[&:-webkit-autofill]:[-webkit-text-fill-color:hsl(var(--foreground))] \" +\n \"[&:-webkit-autofill]:[caret-color:hsl(var(--foreground))] \" +\n \"[&:-webkit-autofill]:[box-shadow:0_0_0px_1000px_hsl(var(--background))_inset] \" +\n \"[&:-webkit-autofill:hover]:[box-shadow:0_0_0px_1000px_hsl(var(--background))_inset] \" +\n \"[&:-webkit-autofill:focus]:[box-shadow:0_0_0px_1000px_hsl(var(--background))_inset] \" +\n \"[&:-webkit-autofill]:[transition:background-color_9999s_ease-out,color_9999s_ease-out]\";\n","import * as React from \"react\"\nimport { Label as LabelPrimitive } from \"radix-ui\"\n\nimport { cn } from \"../../lib/utils\"\n\nfunction Label({\n className,\n ...props\n}: React.ComponentProps<typeof LabelPrimitive.Root>) {\n return (\n <LabelPrimitive.Root\n data-slot=\"label\"\n className={cn(\n \"flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50\",\n className\n )}\n {...props}\n />\n )\n}\n\nexport { Label }\n","import * as React from \"react\";\nimport { Label } from \"./label\";\nimport { cn } from \"../../lib/utils\";\n\ntype FieldOrientation = \"vertical\" | \"horizontal\";\n\ninterface FieldProps extends React.HTMLAttributes<HTMLDivElement> {\n orientation?: FieldOrientation;\n invalid?: boolean;\n}\n\n/**\n * Field - Container component for form inputs with validation display\n *\n * Provides consistent layout and spacing for form fields with labels,\n * inputs, descriptions, and error messages.\n */\nconst Field = React.forwardRef<HTMLDivElement, FieldProps>(\n({ className, orientation = \"vertical\", invalid = false, ...props }, ref) => {\n return (\n <div\n ref={ref}\n data-slot=\"field\"\n data-orientation={orientation}\n data-invalid={invalid || undefined}\n className={cn(\n // Use space-y instead of flex to avoid interfering with parent grid layouts\n orientation === \"horizontal\"\n ? \"flex items-center gap-2\"\n : \"space-y-1.5\",\n className,\n )}\n {...props}\n />\n );\n});\nField.displayName = \"Field\";\n\n/**\n * FieldGroup - Container for multiple related fields\n *\n * Used to group fields together (e.g., first name + last name in a row)\n */\nconst FieldGroup = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => {\n return (\n <div\n ref={ref}\n data-slot=\"field-group\"\n className={cn(\"flex flex-col gap-4\", className)}\n {...props}\n />\n );\n});\nFieldGroup.displayName = \"FieldGroup\";\n\n/**\n * FieldLabel - Label component for form fields\n *\n * Wrapper around ShadCN Label with consistent styling\n */\nconst FieldLabel = React.forwardRef<\n HTMLLabelElement,\n React.LabelHTMLAttributes<HTMLLabelElement> & {\n required?: boolean;\n }\n>(({ className, required, children, ...props }, ref) => {\n return (\n <Label\n ref={ref}\n data-slot=\"field-label\"\n className={cn(\n \"text-sm font-medium leading-none select-none\",\n \"peer-disabled:cursor-not-allowed peer-disabled:opacity-50\",\n className,\n )}\n {...props}\n >\n {children}\n {required && <span className=\"text-destructive ml-1\">*</span>}\n </Label>\n );\n});\nFieldLabel.displayName = \"FieldLabel\";\n\n/**\n * FieldDescription - Helper text for form fields\n *\n * Displays additional information or instructions for the field\n */\nconst FieldDescription = React.forwardRef<\n HTMLParagraphElement,\n React.HTMLAttributes<HTMLParagraphElement>\n>(({ className, ...props }, ref) => {\n return (\n <p\n ref={ref}\n data-slot=\"field-description\"\n className={cn(\"text-sm opacity-70\", className)}\n {...props}\n />\n );\n});\nFieldDescription.displayName = \"FieldDescription\";\n\n/**\n * FieldError - Error message display for form fields\n *\n * Shows validation errors with proper styling and accessibility\n */\nconst FieldError = React.forwardRef<\n HTMLParagraphElement,\n React.HTMLAttributes<HTMLParagraphElement>\n>(({ className, ...props }, ref) => {\n return (\n <p\n ref={ref}\n data-slot=\"field-error\"\n role=\"alert\"\n aria-live=\"polite\"\n className={cn(\"text-sm text-destructive\", className)}\n {...props}\n />\n );\n});\nFieldError.displayName = \"FieldError\";\n\nexport { Field, FieldGroup, FieldLabel, FieldDescription, FieldError };\n","import * as React from \"react\";\nimport { cn } from \"../../lib/utils\";\nimport { INPUT_AUTOFILL_RESET_CLASSES } from \"../../lib/utils\";\n\n/**\n * Input component - Optimized for dynamic theming across thousands of client brands\n *\n * CRITICAL: This component must work with dynamic Section backgrounds (light/dark/primary/etc)\n * Only uses CSS variables that adapt automatically - NO hardcoded semantic colors\n *\n * See: SHADCN_INTEGRATION_GUIDE.md for full documentation\n */\nconst Input = React.forwardRef<HTMLInputElement, React.ComponentProps<\"input\">>(\n ({ className, type, ...props }, ref) => {\n return (\n <input\n ref={ref}\n type={type}\n data-slot=\"input\"\n className={cn(\n // Core structure - no hardcoded colors, uses CSS variables\n \"flex h-9 w-full min-w-0 rounded-md border border-input\",\n \"bg-transparent px-3 py-1 text-base shadow-sm\",\n \"transition-colors outline-none md:text-sm\",\n\n // Focus state - uses ring-ring CSS variable (adapts to theme)\n \"focus-visible:ring-1 focus-visible:ring-ring\",\n\n // Error state - uses destructive CSS variables (adapts to theme)\n \"aria-invalid:border-destructive aria-invalid:ring-1 aria-invalid:ring-destructive\",\n\n // Disabled state - no color hardcoding\n \"disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50\",\n\n // File input specific - inherits text color from parent\n \"file:inline-flex file:h-7 file:border-0 file:bg-transparent\",\n \"file:text-sm file:font-medium\",\n\n // Autofill reset - prevents browser from overriding our dynamic colors\n INPUT_AUTOFILL_RESET_CLASSES,\n\n className,\n )}\n {...props}\n />\n );\n },\n);\nInput.displayName = \"Input\";\n\nexport { Input };\n","\"use client\";\n\nimport * as React from \"react\";\nimport type { InputProps } from \"../core/types\";\nimport { Input } from \"../components/ui/input\";\nimport { cn } from \"../lib/utils\";\n\n/**\n * TextInput - High-performance text input component (ShadCN-based)\n *\n * Built on ShadCN Input component with form-specific behavior:\n * - Error state handling\n * - Valid value indicator (ring-2)\n * - Form integration (onChange, onBlur)\n * - Full accessibility support\n *\n * @example\n * ```tsx\n * const form = useForm({ initialValues: { email: '' } });\n *\n * <TextInput\n * {...form.getFieldProps('email')}\n * type=\"email\"\n * placeholder=\"Enter your email\"\n * error={!!form.errors.email}\n * aria-invalid={!!form.errors.email}\n * aria-describedby={form.errors.email ? 'email-error' : undefined}\n * />\n * ```\n *\n * @see https://opensite.ai/developers/page-speed/forms/text-input\n */\nexport function TextInput({\n name,\n value,\n onChange,\n onBlur,\n placeholder,\n disabled = false,\n required = false,\n error = false,\n className = \"\",\n type = \"text\",\n id = \"text\",\n suppressValueRing = false,\n ...props\n}: InputProps<string> & {\n type?: \"text\" | \"email\" | \"password\" | \"url\" | \"tel\" | \"search\";\n /**\n * When true, suppresses the `ring-2 ring-ring` applied when a value is\n * present. Use this when the component is embedded inside a wrapper (e.g.\n * ButtonGroupForm) that renders its own unified ring.\n */\n suppressValueRing?: boolean;\n}) {\n const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n onChange(e.target.value);\n };\n\n const handleBlur = () => {\n onBlur?.();\n };\n\n const hasValue = String(value ?? \"\").trim().length > 0;\n\n return (\n <Input\n type={type}\n id={id}\n name={name}\n value={value ?? \"\"}\n onChange={handleChange}\n onBlur={handleBlur}\n placeholder={placeholder}\n disabled={disabled}\n required={required}\n className={cn(\n // Valid value indicator - ring-2 when has value, no error, and not suppressed\n !suppressValueRing && !error && hasValue && \"ring-2 ring-ring\",\n // Error state - handled by Input component via aria-invalid\n className,\n )}\n aria-invalid={error || props[\"aria-invalid\"]}\n aria-describedby={props[\"aria-describedby\"]}\n aria-required={required || props[\"aria-required\"]}\n {...props}\n />\n );\n}\n\nTextInput.displayName = \"TextInput\";\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\"\n\nconst buttonVariants = cva(\n \"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 aria-invalid:border-destructive\",\n {\n variants: {\n variant: {\n default: \"bg-primary text-primary-foreground hover:bg-primary/90\",\n destructive:\n \"bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20\",\n outline:\n \"border border-input bg-transparent shadow-xs hover:bg-accent hover:text-accent-foreground\",\n secondary:\n \"bg-secondary text-secondary-foreground hover:bg-secondary/80\",\n ghost:\n \"hover:bg-accent hover:text-accent-foreground\",\n link: \"text-primary underline-offset-4 hover:underline\",\n },\n size: {\n default: \"h-9 px-4 py-2 has-[>svg]:px-3\",\n xs: \"h-6 gap-1 rounded-md px-2 text-xs has-[>svg]:px-1.5 [&_svg:not([class*='size-'])]:size-3\",\n sm: \"h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5\",\n lg: \"h-10 rounded-md px-6 has-[>svg]:px-4\",\n icon: \"size-9\",\n \"icon-xs\": \"size-6 rounded-md [&_svg:not([class*='size-'])]:size-3\",\n \"icon-sm\": \"size-8\",\n \"icon-lg\": \"size-10\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n }\n)\n\nfunction Button({\n className,\n variant = \"default\",\n size = \"default\",\n asChild = false,\n ...props\n}: React.ComponentProps<\"button\"> &\n VariantProps<typeof buttonVariants> & {\n asChild?: boolean\n }) {\n const Comp = asChild ? Slot.Root : \"button\"\n\n return (\n <Comp\n data-slot=\"button\"\n data-variant={variant}\n data-size={size}\n className={cn(buttonVariants({ variant, size, className }))}\n {...props}\n />\n )\n}\n\nexport { Button, buttonVariants }\n","\"use client\";\n\nimport * as React from \"react\";\nimport type { ReactNode } from \"react\";\nimport { FieldDescription, FieldLabel } from \"../components/ui/field\";\nimport { cn } from \"../lib/utils\";\n\nexport type LabelGroupProps = {\n variant?: \"legend\" | \"label\" | \"text\";\n secondary?: ReactNode;\n secondaryId?: string;\n primary?: ReactNode;\n labelHtmlFor?: string;\n required?: boolean;\n primaryClassName?: string;\n secondaryClassName?: string;\n};\n\nconst LabelGroup = ({\n labelHtmlFor,\n required = false,\n variant = \"label\",\n secondaryId,\n secondary,\n primary,\n primaryClassName,\n secondaryClassName,\n}: LabelGroupProps) => {\n const primaryClasses = cn(\n \"text-sm font-medium leading-snug\",\n variant === \"legend\" ? \"mb-1.5\" : \"mb-1 block\",\n primaryClassName,\n );\n\n const requiredIndicator =\n required && variant !== \"label\" ? (\n <span className=\"text-destructive pl-0.5\" aria-label=\"required\">\n *\n </span>\n ) : null;\n\n let primaryElement: ReactNode = null;\n if (primary) {\n if (variant === \"label\") {\n primaryElement = (\n <FieldLabel\n htmlFor={labelHtmlFor}\n required={required}\n className={primaryClasses}\n >\n {primary}\n </FieldLabel>\n );\n } else if (variant === \"legend\") {\n primaryElement = (\n <legend data-slot=\"field-legend\" className={primaryClasses}>\n {primary}\n {requiredIndicator}\n </legend>\n );\n } else {\n primaryElement = (\n <div data-slot=\"field-label\" className={primaryClasses}>\n {primary}\n {requiredIndicator}\n </div>\n );\n }\n }\n\n const secondaryElement = secondary ? (\n <FieldDescription\n id={secondaryId}\n className={cn(\"leading-normal font-normal\", secondaryClassName)}\n >\n {secondary}\n </FieldDescription>\n ) : null;\n\n if (!primaryElement && !secondaryElement) return null;\n\n // Legend should remain a direct child of fieldset for proper semantics.\n if (variant === \"legend\") {\n return (\n <>\n {primaryElement}\n {secondaryElement}\n </>\n );\n }\n\n return (\n <div className=\"flex flex-1 flex-col gap-0.5\">\n {primaryElement}\n {secondaryElement}\n </div>\n );\n};\n\nexport { LabelGroup };\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { cn, FieldLabel, FieldDescription, LabelGroup, Field, INPUT_AUTOFILL_RESET_CLASSES, Button, Input, buttonVariants } from './chunk-
|
|
1
|
+
import { cn, FieldLabel, FieldDescription, LabelGroup, Field, INPUT_AUTOFILL_RESET_CLASSES, Button, Input, buttonVariants } from './chunk-J37BGNM6.js';
|
|
2
2
|
import * as React19 from 'react';
|
|
3
3
|
import { Dialog as Dialog$1, Checkbox as Checkbox$1, RadioGroup as RadioGroup$1, Switch as Switch$1, Select as Select$1, Popover as Popover$1 } from 'radix-ui';
|
|
4
4
|
import { Command as Command$1 } from 'cmdk';
|
|
@@ -4050,5 +4050,5 @@ function DateRangePicker({
|
|
|
4050
4050
|
DateRangePicker.displayName = "DateRangePicker";
|
|
4051
4051
|
|
|
4052
4052
|
export { Checkbox2 as Checkbox, CheckboxGroup, DatePicker, DateRangePicker, FileInput, MultiSelect, Radio, Select2 as Select, Switch2 as Switch, TextArea, TimePicker };
|
|
4053
|
-
//# sourceMappingURL=chunk-
|
|
4054
|
-
//# sourceMappingURL=chunk-
|
|
4053
|
+
//# sourceMappingURL=chunk-ML6FGUYS.js.map
|
|
4054
|
+
//# sourceMappingURL=chunk-ML6FGUYS.js.map
|