@page-speed/forms 0.7.3 → 0.7.5
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/README.md +1 -1
- package/dist/{chunk-ZH6XDBWH.js → chunk-DSK3VLIV.js} +127 -71
- package/dist/chunk-DSK3VLIV.js.map +1 -0
- package/dist/{chunk-SUF7WJS6.js → chunk-EQKN2OPX.js} +65 -6
- package/dist/chunk-EQKN2OPX.js.map +1 -0
- package/dist/{chunk-WQ4HD5UD.cjs → chunk-IGI4JJKE.cjs} +65 -5
- package/dist/chunk-IGI4JJKE.cjs.map +1 -0
- package/dist/{chunk-4K6J2DOK.cjs → chunk-K7ZHLPLX.cjs} +237 -181
- package/dist/chunk-K7ZHLPLX.cjs.map +1 -0
- package/dist/{chunk-QXC7B4QC.js → chunk-MRGJTFGD.js} +18 -9
- package/dist/chunk-MRGJTFGD.js.map +1 -0
- package/dist/{chunk-7OZ5SKVC.cjs → chunk-T2SLAP65.cjs} +35 -26
- package/dist/chunk-T2SLAP65.cjs.map +1 -0
- package/dist/core.cjs +9 -9
- package/dist/core.js +2 -2
- package/dist/index.cjs +13 -13
- package/dist/index.js +2 -2
- package/dist/inputs.cjs +14 -14
- package/dist/inputs.d.cts +13 -2
- package/dist/inputs.d.ts +13 -2
- package/dist/inputs.js +2 -2
- package/dist/integration.cjs +59 -25
- package/dist/integration.cjs.map +1 -1
- package/dist/integration.js +40 -6
- package/dist/integration.js.map +1 -1
- package/package.json +2 -2
- package/dist/chunk-4K6J2DOK.cjs.map +0 -1
- package/dist/chunk-7OZ5SKVC.cjs.map +0 -1
- package/dist/chunk-QXC7B4QC.js.map +0 -1
- package/dist/chunk-SUF7WJS6.js.map +0 -1
- package/dist/chunk-WQ4HD5UD.cjs.map +0 -1
- package/dist/chunk-ZH6XDBWH.js.map +0 -1
|
@@ -14,6 +14,13 @@ function humanizeFieldName(name) {
|
|
|
14
14
|
return words.charAt(0).toUpperCase() + words.slice(1);
|
|
15
15
|
}
|
|
16
16
|
var INPUT_AUTOFILL_RESET_CLASSES = "autofill:bg-transparent autofill:text-foreground [&:-webkit-autofill]:[-webkit-text-fill-color:hsl(var(--foreground))] [&:-webkit-autofill]:[caret-color:hsl(var(--foreground))] [&:-webkit-autofill]:[box-shadow:0_0_0px_1000px_hsl(var(--background))_inset] [&:-webkit-autofill:hover]:[box-shadow:0_0_0px_1000px_hsl(var(--background))_inset] [&:-webkit-autofill:focus]:[box-shadow:0_0_0px_1000px_hsl(var(--background))_inset] [&:-webkit-autofill]:[transition:background-color_9999s_ease-out,color_9999s_ease-out]";
|
|
17
|
+
function fieldIsChoiceCard(field) {
|
|
18
|
+
if (["radio", "checkbox-group"].includes(field.type)) {
|
|
19
|
+
return field?.options ? field?.options?.some((opt) => opt.description) : false;
|
|
20
|
+
} else {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
17
24
|
|
|
18
25
|
// src/components/ui/label.tsx
|
|
19
26
|
function Label({
|
|
@@ -44,6 +51,7 @@ var Field = React2.forwardRef(
|
|
|
44
51
|
"data-orientation": orientation,
|
|
45
52
|
"data-invalid": invalid || void 0,
|
|
46
53
|
className: cn(
|
|
54
|
+
"relative",
|
|
47
55
|
// Use space-y instead of flex to avoid interfering with parent grid layouts
|
|
48
56
|
orientation === "horizontal" ? "flex items-center gap-2" : "space-y-1.5",
|
|
49
57
|
className
|
|
@@ -104,7 +112,10 @@ var FieldError = React2.forwardRef(({ className, ...props }, ref) => {
|
|
|
104
112
|
"data-slot": "field-error",
|
|
105
113
|
role: "alert",
|
|
106
114
|
"aria-live": "polite",
|
|
107
|
-
className: cn(
|
|
115
|
+
className: cn(
|
|
116
|
+
"text-xs text-destructive absolute -bottom-1/2 left-0",
|
|
117
|
+
className
|
|
118
|
+
),
|
|
108
119
|
...props
|
|
109
120
|
}
|
|
110
121
|
);
|
|
@@ -157,6 +168,8 @@ function TextInput({
|
|
|
157
168
|
type = "text",
|
|
158
169
|
id = "text",
|
|
159
170
|
suppressValueRing = false,
|
|
171
|
+
iconStart,
|
|
172
|
+
iconEnd,
|
|
160
173
|
...props
|
|
161
174
|
}) {
|
|
162
175
|
const handleChange = (e) => {
|
|
@@ -166,6 +179,52 @@ function TextInput({
|
|
|
166
179
|
onBlur?.();
|
|
167
180
|
};
|
|
168
181
|
const hasValue = String(value ?? "").trim().length > 0;
|
|
182
|
+
const hasIconStart = Boolean(iconStart);
|
|
183
|
+
const hasIconEnd = Boolean(iconEnd);
|
|
184
|
+
if (hasIconStart || hasIconEnd) {
|
|
185
|
+
return /* @__PURE__ */ React2.createElement("div", { className: "relative" }, hasIconStart && /* @__PURE__ */ React2.createElement(
|
|
186
|
+
"span",
|
|
187
|
+
{
|
|
188
|
+
className: cn(
|
|
189
|
+
"absolute left-3 top-1/2 -translate-y-1/2",
|
|
190
|
+
"pointer-events-none flex items-center justify-center",
|
|
191
|
+
"pointer-events-none"
|
|
192
|
+
),
|
|
193
|
+
"aria-hidden": "true"
|
|
194
|
+
},
|
|
195
|
+
iconStart
|
|
196
|
+
), /* @__PURE__ */ React2.createElement(
|
|
197
|
+
Input,
|
|
198
|
+
{
|
|
199
|
+
type,
|
|
200
|
+
id,
|
|
201
|
+
name,
|
|
202
|
+
value: value ?? "",
|
|
203
|
+
onChange: handleChange,
|
|
204
|
+
onBlur: handleBlur,
|
|
205
|
+
placeholder,
|
|
206
|
+
disabled,
|
|
207
|
+
required,
|
|
208
|
+
className: cn(
|
|
209
|
+
!suppressValueRing && !error && hasValue && "ring-2 ring-primary",
|
|
210
|
+
hasIconStart && "pl-10",
|
|
211
|
+
hasIconEnd && "pr-10",
|
|
212
|
+
className
|
|
213
|
+
),
|
|
214
|
+
"aria-invalid": error || props["aria-invalid"],
|
|
215
|
+
"aria-describedby": props["aria-describedby"],
|
|
216
|
+
"aria-required": required || props["aria-required"],
|
|
217
|
+
...props
|
|
218
|
+
}
|
|
219
|
+
), hasIconEnd && /* @__PURE__ */ React2.createElement(
|
|
220
|
+
"span",
|
|
221
|
+
{
|
|
222
|
+
className: "absolute right-3 top-1/2 -translate-y-1/2 pointer-events-none",
|
|
223
|
+
"aria-hidden": "true"
|
|
224
|
+
},
|
|
225
|
+
iconEnd
|
|
226
|
+
));
|
|
227
|
+
}
|
|
169
228
|
return /* @__PURE__ */ React2.createElement(
|
|
170
229
|
Input,
|
|
171
230
|
{
|
|
@@ -180,7 +239,7 @@ function TextInput({
|
|
|
180
239
|
required,
|
|
181
240
|
className: cn(
|
|
182
241
|
// Valid value indicator - ring-2 when has value, no error, and not suppressed
|
|
183
|
-
!suppressValueRing && !error && hasValue && "ring-2 ring-
|
|
242
|
+
!suppressValueRing && !error && hasValue && "ring-2 ring-primary",
|
|
184
243
|
// Error state - handled by Input component via aria-invalid
|
|
185
244
|
className
|
|
186
245
|
),
|
|
@@ -252,7 +311,7 @@ var LabelGroup = ({
|
|
|
252
311
|
}) => {
|
|
253
312
|
const primaryClasses = cn(
|
|
254
313
|
"text-sm font-medium leading-snug",
|
|
255
|
-
variant === "legend" ? "mb-
|
|
314
|
+
variant === "legend" ? "mb-2.5" : "mb-1 block",
|
|
256
315
|
primaryClassName
|
|
257
316
|
);
|
|
258
317
|
const requiredIndicator = required && variant !== "label" ? /* @__PURE__ */ React2.createElement("span", { className: "text-destructive pl-0.5", "aria-label": "required" }, "*") : null;
|
|
@@ -289,6 +348,6 @@ var LabelGroup = ({
|
|
|
289
348
|
return /* @__PURE__ */ React2.createElement("div", { className: "flex flex-1 flex-col gap-0.5" }, primaryElement, secondaryElement);
|
|
290
349
|
};
|
|
291
350
|
|
|
292
|
-
export { Button, Field, FieldDescription, FieldError, FieldGroup, FieldLabel, INPUT_AUTOFILL_RESET_CLASSES, Input, LabelGroup, TextInput, buttonVariants, cn, humanizeFieldName };
|
|
293
|
-
//# sourceMappingURL=chunk-
|
|
294
|
-
//# sourceMappingURL=chunk-
|
|
351
|
+
export { Button, Field, FieldDescription, FieldError, FieldGroup, FieldLabel, INPUT_AUTOFILL_RESET_CLASSES, Input, LabelGroup, TextInput, buttonVariants, cn, fieldIsChoiceCard, humanizeFieldName };
|
|
352
|
+
//# sourceMappingURL=chunk-EQKN2OPX.js.map
|
|
353
|
+
//# sourceMappingURL=chunk-EQKN2OPX.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-EQKN2OPX.js","sourcesContent":["import { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\nimport { FormFieldConfig } from \"../integration\";\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n\n/**\n * Converts a field name (snake_case or camelCase) to a human-readable label.\n *\n * @example\n * humanizeFieldName(\"first_name\") // \"First name\"\n * humanizeFieldName(\"email\") // \"Email\"\n * humanizeFieldName(\"accepts_sms_marketing\") // \"Accepts sms marketing\"\n */\nexport function humanizeFieldName(name: string): string {\n if (!name) return \"This field\";\n\n // Replace underscores with spaces and split camelCase\n const words = name\n .replace(/_/g, \" \")\n .replace(/([a-z])([A-Z])/g, \"$1 $2\")\n .toLowerCase()\n .trim();\n\n // Capitalize first letter only\n return words.charAt(0).toUpperCase() + words.slice(1);\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\n/**\n * Converts a field name (snake_case or camelCase) to a human-readable label.\n *\n * @example\n * fieldIsChoiceCard(field) // false\n */\nexport function fieldIsChoiceCard(field: FormFieldConfig) {\n if ([\"radio\", \"checkbox-group\"].includes(field.type)) {\n return field?.options\n ? field?.options?.some((opt) => opt.description)\n : false;\n } else {\n return false;\n }\n}\n\n/**\n * Converts file upload meta instructions to human-readable format.\n *\n * @example\n * humanizeFileMeta(\"image/jpeg\") // \"JPEG image\"\n * humanizeFileMeta(\"application/pdf\") // \"PDF document\"\n * humanizeFileMeta(\"text/plain\") // \"Plain text\"\n */\nexport function humanizeFileMeta(meta: string): string {\n const [type, subtype] = meta.split(\"/\");\n const typeLabel = type.charAt(0).toUpperCase() + type.slice(1);\n const subtypeLabel = subtype.charAt(0).toUpperCase() + subtype.slice(1);\n return `${subtypeLabel} ${typeLabel}`;\n}\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 \"relative\",\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 },\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(\n \"text-xs text-destructive absolute -bottom-1/2 left-0\",\n className,\n )}\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 * - Optional start/end icon support with automatic padding\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 iconStart,\n iconEnd,\n ...props\n}: InputProps<string> & {\n type?: \"text\" | \"email\" | \"password\" | \"url\" | \"tel\" | \"search\";\n /**\n * When true, suppresses the `ring-2 ring-primary` 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 * Optional icon rendered at the start (left) of the input.\n * Automatically adjusts input padding when provided.\n */\n iconStart?: React.ReactNode;\n /**\n * Optional icon rendered at the end (right) of the input.\n * Automatically adjusts input padding when provided.\n */\n iconEnd?: React.ReactNode;\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 const hasIconStart = Boolean(iconStart);\n const hasIconEnd = Boolean(iconEnd);\n\n if (hasIconStart || hasIconEnd) {\n return (\n <div className=\"relative\">\n {hasIconStart && (\n <span\n className={cn(\n \"absolute left-3 top-1/2 -translate-y-1/2\",\n \"pointer-events-none flex items-center justify-center\",\n \"pointer-events-none\",\n )}\n aria-hidden=\"true\"\n >\n {iconStart}\n </span>\n )}\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 !suppressValueRing && !error && hasValue && \"ring-2 ring-primary\",\n hasIconStart && \"pl-10\",\n hasIconEnd && \"pr-10\",\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 {hasIconEnd && (\n <span\n className=\"absolute right-3 top-1/2 -translate-y-1/2 pointer-events-none\"\n aria-hidden=\"true\"\n >\n {iconEnd}\n </span>\n )}\n </div>\n );\n }\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-primary\",\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-2.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"]}
|
|
@@ -36,6 +36,13 @@ function humanizeFieldName(name) {
|
|
|
36
36
|
return words.charAt(0).toUpperCase() + words.slice(1);
|
|
37
37
|
}
|
|
38
38
|
var INPUT_AUTOFILL_RESET_CLASSES = "autofill:bg-transparent autofill:text-foreground [&:-webkit-autofill]:[-webkit-text-fill-color:hsl(var(--foreground))] [&:-webkit-autofill]:[caret-color:hsl(var(--foreground))] [&:-webkit-autofill]:[box-shadow:0_0_0px_1000px_hsl(var(--background))_inset] [&:-webkit-autofill:hover]:[box-shadow:0_0_0px_1000px_hsl(var(--background))_inset] [&:-webkit-autofill:focus]:[box-shadow:0_0_0px_1000px_hsl(var(--background))_inset] [&:-webkit-autofill]:[transition:background-color_9999s_ease-out,color_9999s_ease-out]";
|
|
39
|
+
function fieldIsChoiceCard(field) {
|
|
40
|
+
if (["radio", "checkbox-group"].includes(field.type)) {
|
|
41
|
+
return field?.options ? field?.options?.some((opt) => opt.description) : false;
|
|
42
|
+
} else {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
39
46
|
|
|
40
47
|
// src/components/ui/label.tsx
|
|
41
48
|
function Label({
|
|
@@ -66,6 +73,7 @@ var Field = React2__namespace.forwardRef(
|
|
|
66
73
|
"data-orientation": orientation,
|
|
67
74
|
"data-invalid": invalid || void 0,
|
|
68
75
|
className: cn(
|
|
76
|
+
"relative",
|
|
69
77
|
// Use space-y instead of flex to avoid interfering with parent grid layouts
|
|
70
78
|
orientation === "horizontal" ? "flex items-center gap-2" : "space-y-1.5",
|
|
71
79
|
className
|
|
@@ -126,7 +134,10 @@ var FieldError = React2__namespace.forwardRef(({ className, ...props }, ref) =>
|
|
|
126
134
|
"data-slot": "field-error",
|
|
127
135
|
role: "alert",
|
|
128
136
|
"aria-live": "polite",
|
|
129
|
-
className: cn(
|
|
137
|
+
className: cn(
|
|
138
|
+
"text-xs text-destructive absolute -bottom-1/2 left-0",
|
|
139
|
+
className
|
|
140
|
+
),
|
|
130
141
|
...props
|
|
131
142
|
}
|
|
132
143
|
);
|
|
@@ -179,6 +190,8 @@ function TextInput({
|
|
|
179
190
|
type = "text",
|
|
180
191
|
id = "text",
|
|
181
192
|
suppressValueRing = false,
|
|
193
|
+
iconStart,
|
|
194
|
+
iconEnd,
|
|
182
195
|
...props
|
|
183
196
|
}) {
|
|
184
197
|
const handleChange = (e) => {
|
|
@@ -188,6 +201,52 @@ function TextInput({
|
|
|
188
201
|
onBlur?.();
|
|
189
202
|
};
|
|
190
203
|
const hasValue = String(value ?? "").trim().length > 0;
|
|
204
|
+
const hasIconStart = Boolean(iconStart);
|
|
205
|
+
const hasIconEnd = Boolean(iconEnd);
|
|
206
|
+
if (hasIconStart || hasIconEnd) {
|
|
207
|
+
return /* @__PURE__ */ React2__namespace.createElement("div", { className: "relative" }, hasIconStart && /* @__PURE__ */ React2__namespace.createElement(
|
|
208
|
+
"span",
|
|
209
|
+
{
|
|
210
|
+
className: cn(
|
|
211
|
+
"absolute left-3 top-1/2 -translate-y-1/2",
|
|
212
|
+
"pointer-events-none flex items-center justify-center",
|
|
213
|
+
"pointer-events-none"
|
|
214
|
+
),
|
|
215
|
+
"aria-hidden": "true"
|
|
216
|
+
},
|
|
217
|
+
iconStart
|
|
218
|
+
), /* @__PURE__ */ React2__namespace.createElement(
|
|
219
|
+
Input,
|
|
220
|
+
{
|
|
221
|
+
type,
|
|
222
|
+
id,
|
|
223
|
+
name,
|
|
224
|
+
value: value ?? "",
|
|
225
|
+
onChange: handleChange,
|
|
226
|
+
onBlur: handleBlur,
|
|
227
|
+
placeholder,
|
|
228
|
+
disabled,
|
|
229
|
+
required,
|
|
230
|
+
className: cn(
|
|
231
|
+
!suppressValueRing && !error && hasValue && "ring-2 ring-primary",
|
|
232
|
+
hasIconStart && "pl-10",
|
|
233
|
+
hasIconEnd && "pr-10",
|
|
234
|
+
className
|
|
235
|
+
),
|
|
236
|
+
"aria-invalid": error || props["aria-invalid"],
|
|
237
|
+
"aria-describedby": props["aria-describedby"],
|
|
238
|
+
"aria-required": required || props["aria-required"],
|
|
239
|
+
...props
|
|
240
|
+
}
|
|
241
|
+
), hasIconEnd && /* @__PURE__ */ React2__namespace.createElement(
|
|
242
|
+
"span",
|
|
243
|
+
{
|
|
244
|
+
className: "absolute right-3 top-1/2 -translate-y-1/2 pointer-events-none",
|
|
245
|
+
"aria-hidden": "true"
|
|
246
|
+
},
|
|
247
|
+
iconEnd
|
|
248
|
+
));
|
|
249
|
+
}
|
|
191
250
|
return /* @__PURE__ */ React2__namespace.createElement(
|
|
192
251
|
Input,
|
|
193
252
|
{
|
|
@@ -202,7 +261,7 @@ function TextInput({
|
|
|
202
261
|
required,
|
|
203
262
|
className: cn(
|
|
204
263
|
// Valid value indicator - ring-2 when has value, no error, and not suppressed
|
|
205
|
-
!suppressValueRing && !error && hasValue && "ring-2 ring-
|
|
264
|
+
!suppressValueRing && !error && hasValue && "ring-2 ring-primary",
|
|
206
265
|
// Error state - handled by Input component via aria-invalid
|
|
207
266
|
className
|
|
208
267
|
),
|
|
@@ -274,7 +333,7 @@ var LabelGroup = ({
|
|
|
274
333
|
}) => {
|
|
275
334
|
const primaryClasses = cn(
|
|
276
335
|
"text-sm font-medium leading-snug",
|
|
277
|
-
variant === "legend" ? "mb-
|
|
336
|
+
variant === "legend" ? "mb-2.5" : "mb-1 block",
|
|
278
337
|
primaryClassName
|
|
279
338
|
);
|
|
280
339
|
const requiredIndicator = required && variant !== "label" ? /* @__PURE__ */ React2__namespace.createElement("span", { className: "text-destructive pl-0.5", "aria-label": "required" }, "*") : null;
|
|
@@ -323,6 +382,7 @@ exports.LabelGroup = LabelGroup;
|
|
|
323
382
|
exports.TextInput = TextInput;
|
|
324
383
|
exports.buttonVariants = buttonVariants;
|
|
325
384
|
exports.cn = cn;
|
|
385
|
+
exports.fieldIsChoiceCard = fieldIsChoiceCard;
|
|
326
386
|
exports.humanizeFieldName = humanizeFieldName;
|
|
327
|
-
//# sourceMappingURL=chunk-
|
|
328
|
-
//# sourceMappingURL=chunk-
|
|
387
|
+
//# sourceMappingURL=chunk-IGI4JJKE.cjs.map
|
|
388
|
+
//# sourceMappingURL=chunk-IGI4JJKE.cjs.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":["twMerge","clsx","React","LabelPrimitive","React2","React3","React4","cva","Slot","React5","React6"],"mappings":"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","file":"chunk-IGI4JJKE.cjs","sourcesContent":["import { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\nimport { FormFieldConfig } from \"../integration\";\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n\n/**\n * Converts a field name (snake_case or camelCase) to a human-readable label.\n *\n * @example\n * humanizeFieldName(\"first_name\") // \"First name\"\n * humanizeFieldName(\"email\") // \"Email\"\n * humanizeFieldName(\"accepts_sms_marketing\") // \"Accepts sms marketing\"\n */\nexport function humanizeFieldName(name: string): string {\n if (!name) return \"This field\";\n\n // Replace underscores with spaces and split camelCase\n const words = name\n .replace(/_/g, \" \")\n .replace(/([a-z])([A-Z])/g, \"$1 $2\")\n .toLowerCase()\n .trim();\n\n // Capitalize first letter only\n return words.charAt(0).toUpperCase() + words.slice(1);\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\n/**\n * Converts a field name (snake_case or camelCase) to a human-readable label.\n *\n * @example\n * fieldIsChoiceCard(field) // false\n */\nexport function fieldIsChoiceCard(field: FormFieldConfig) {\n if ([\"radio\", \"checkbox-group\"].includes(field.type)) {\n return field?.options\n ? field?.options?.some((opt) => opt.description)\n : false;\n } else {\n return false;\n }\n}\n\n/**\n * Converts file upload meta instructions to human-readable format.\n *\n * @example\n * humanizeFileMeta(\"image/jpeg\") // \"JPEG image\"\n * humanizeFileMeta(\"application/pdf\") // \"PDF document\"\n * humanizeFileMeta(\"text/plain\") // \"Plain text\"\n */\nexport function humanizeFileMeta(meta: string): string {\n const [type, subtype] = meta.split(\"/\");\n const typeLabel = type.charAt(0).toUpperCase() + type.slice(1);\n const subtypeLabel = subtype.charAt(0).toUpperCase() + subtype.slice(1);\n return `${subtypeLabel} ${typeLabel}`;\n}\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 \"relative\",\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 },\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(\n \"text-xs text-destructive absolute -bottom-1/2 left-0\",\n className,\n )}\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 * - Optional start/end icon support with automatic padding\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 iconStart,\n iconEnd,\n ...props\n}: InputProps<string> & {\n type?: \"text\" | \"email\" | \"password\" | \"url\" | \"tel\" | \"search\";\n /**\n * When true, suppresses the `ring-2 ring-primary` 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 * Optional icon rendered at the start (left) of the input.\n * Automatically adjusts input padding when provided.\n */\n iconStart?: React.ReactNode;\n /**\n * Optional icon rendered at the end (right) of the input.\n * Automatically adjusts input padding when provided.\n */\n iconEnd?: React.ReactNode;\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 const hasIconStart = Boolean(iconStart);\n const hasIconEnd = Boolean(iconEnd);\n\n if (hasIconStart || hasIconEnd) {\n return (\n <div className=\"relative\">\n {hasIconStart && (\n <span\n className={cn(\n \"absolute left-3 top-1/2 -translate-y-1/2\",\n \"pointer-events-none flex items-center justify-center\",\n \"pointer-events-none\",\n )}\n aria-hidden=\"true\"\n >\n {iconStart}\n </span>\n )}\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 !suppressValueRing && !error && hasValue && \"ring-2 ring-primary\",\n hasIconStart && \"pl-10\",\n hasIconEnd && \"pr-10\",\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 {hasIconEnd && (\n <span\n className=\"absolute right-3 top-1/2 -translate-y-1/2 pointer-events-none\"\n aria-hidden=\"true\"\n >\n {iconEnd}\n </span>\n )}\n </div>\n );\n }\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-primary\",\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-2.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"]}
|