@vritti/quantum-ui 0.3.19 → 0.3.21

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.
@@ -0,0 +1,47 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import { useState, useRef, useEffect, useCallback } from 'react';
3
+ import { c as cn } from './utils.js';
4
+ import { T as Tooltip } from './Tooltip.js';
5
+ import { C as Check } from './check.js';
6
+ import { C as Copy } from './copy.js';
7
+
8
+ const CopyButton = ({ value, label = "Copy", className }) => {
9
+ const [copied, setCopied] = useState(false);
10
+ const timeoutRef = useRef(null);
11
+ useEffect(
12
+ () => () => {
13
+ if (timeoutRef.current) {
14
+ clearTimeout(timeoutRef.current);
15
+ }
16
+ },
17
+ []
18
+ );
19
+ const handleCopy = useCallback(async () => {
20
+ try {
21
+ await navigator.clipboard.writeText(value);
22
+ setCopied(true);
23
+ if (timeoutRef.current) {
24
+ clearTimeout(timeoutRef.current);
25
+ }
26
+ timeoutRef.current = setTimeout(() => setCopied(false), 1500);
27
+ } catch {
28
+ }
29
+ }, [value]);
30
+ return /* @__PURE__ */ jsx(Tooltip, { content: copied ? "Copied" : label, children: /* @__PURE__ */ jsx(
31
+ "button",
32
+ {
33
+ type: "button",
34
+ onClick: handleCopy,
35
+ "aria-label": label,
36
+ className: cn(
37
+ "inline-flex size-6 shrink-0 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-muted hover:text-foreground",
38
+ className
39
+ ),
40
+ children: copied ? /* @__PURE__ */ jsx(Check, { className: "size-3.5 text-success" }) : /* @__PURE__ */ jsx(Copy, { className: "size-3.5" })
41
+ }
42
+ ) });
43
+ };
44
+ CopyButton.displayName = "CopyButton";
45
+
46
+ export { CopyButton as C };
47
+ //# sourceMappingURL=CopyButton.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CopyButton.js","sources":["../lib/components/CopyButton/CopyButton.tsx"],"sourcesContent":["import { Check, Copy } from 'lucide-react';\nimport type React from 'react';\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport { cn } from '../../../shadcn/utils';\nimport { Tooltip } from '../Tooltip';\n\n/**\n * Props for the CopyButton component\n */\nexport interface CopyButtonProps {\n /** The full string copied to the clipboard */\n value: string;\n /** Accessible label and tooltip text (default: 'Copy'); the tooltip shows 'Copied' after a copy */\n label?: string;\n /** Additional CSS classes applied to the button */\n className?: string;\n}\n\n/**\n * CopyButton is an icon-only copy-to-clipboard affordance that briefly flips a\n * Copy icon to a Check and surfaces a Tooltip confirming the copy.\n *\n * @example\n * ```tsx\n * <CopyButton value=\"sk_live_123\" label=\"Copy API key\" />\n * ```\n */\nexport const CopyButton: React.FC<CopyButtonProps> = ({ value, label = 'Copy', className }) => {\n const [copied, setCopied] = useState(false);\n const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n // Clear any pending revert timer on unmount to avoid setting state on an unmounted component\n useEffect(\n () => () => {\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n }\n },\n [],\n );\n\n // Write the value to the clipboard and briefly show the copied confirmation\n const handleCopy = useCallback(async () => {\n try {\n await navigator.clipboard.writeText(value);\n setCopied(true);\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n }\n timeoutRef.current = setTimeout(() => setCopied(false), 1500);\n } catch {\n // Clipboard access can be denied or unavailable; fail silently without breaking the UI\n }\n }, [value]);\n\n return (\n <Tooltip content={copied ? 'Copied' : label}>\n <button\n type=\"button\"\n onClick={handleCopy}\n aria-label={label}\n className={cn(\n 'inline-flex size-6 shrink-0 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-muted hover:text-foreground',\n className,\n )}\n >\n {copied ? <Check className=\"size-3.5 text-success\" /> : <Copy className=\"size-3.5\" />}\n </button>\n </Tooltip>\n );\n};\n\nCopyButton.displayName = 'CopyButton';\n"],"names":[],"mappings":";;;;;;;AA2BO,MAAM,aAAwC,CAAC,EAAE,OAAO,KAAA,GAAQ,MAAA,EAAQ,WAAU,KAAM;AAC7F,EAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,GAAI,SAAS,KAAK,CAAA;AAC1C,EAAA,MAAM,UAAA,GAAa,OAA6C,IAAI,CAAA;AAGpE,EAAA,SAAA;AAAA,IACE,MAAM,MAAM;AACV,MAAA,IAAI,WAAW,OAAA,EAAS;AACtB,QAAA,YAAA,CAAa,WAAW,OAAO,CAAA;AAAA,MACjC;AAAA,IACF,CAAA;AAAA,IACA;AAAC,GACH;AAGA,EAAA,MAAM,UAAA,GAAa,YAAY,YAAY;AACzC,IAAA,IAAI;AACF,MAAA,MAAM,SAAA,CAAU,SAAA,CAAU,SAAA,CAAU,KAAK,CAAA;AACzC,MAAA,SAAA,CAAU,IAAI,CAAA;AACd,MAAA,IAAI,WAAW,OAAA,EAAS;AACtB,QAAA,YAAA,CAAa,WAAW,OAAO,CAAA;AAAA,MACjC;AACA,MAAA,UAAA,CAAW,UAAU,UAAA,CAAW,MAAM,SAAA,CAAU,KAAK,GAAG,IAAI,CAAA;AAAA,IAC9D,CAAA,CAAA,MAAQ;AAAA,IAER;AAAA,EACF,CAAA,EAAG,CAAC,KAAK,CAAC,CAAA;AAEV,EAAA,uBACE,GAAA,CAAC,OAAA,EAAA,EAAQ,OAAA,EAAS,MAAA,GAAS,WAAW,KAAA,EACpC,QAAA,kBAAA,GAAA;AAAA,IAAC,QAAA;AAAA,IAAA;AAAA,MACC,IAAA,EAAK,QAAA;AAAA,MACL,OAAA,EAAS,UAAA;AAAA,MACT,YAAA,EAAY,KAAA;AAAA,MACZ,SAAA,EAAW,EAAA;AAAA,QACT,iJAAA;AAAA,QACA;AAAA,OACF;AAAA,MAEC,QAAA,EAAA,MAAA,uBAAU,KAAA,EAAA,EAAM,SAAA,EAAU,yBAAwB,CAAA,mBAAK,GAAA,CAAC,IAAA,EAAA,EAAK,SAAA,EAAU,UAAA,EAAW;AAAA;AAAA,GACrF,EACF,CAAA;AAEJ;AAEA,UAAA,CAAW,WAAA,GAAc,YAAA;;;;"}
package/dist/Form.js CHANGED
@@ -217,7 +217,7 @@ function Form({
217
217
  className: cn(hasActions ? "flex min-h-0 flex-1 flex-col" : "space-y-4", className),
218
218
  ...props,
219
219
  children: hasActions ? /* @__PURE__ */ jsxs(Fragment, { children: [
220
- /* @__PURE__ */ jsxs("div", { className: "min-h-0 flex-1 space-y-4 overflow-y-auto overscroll-contain px-6 py-4 [scrollbar-gutter:stable]", children: [
220
+ /* @__PURE__ */ jsxs("div", { className: "min-h-0 flex-1 space-y-4 overflow-y-auto overscroll-contain px-6 py-4", children: [
221
221
  topError,
222
222
  bodyChildren,
223
223
  bottomError
package/dist/Form.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"Form.js","sources":["../lib/utils/formHelpers.ts","../lib/components/Form/Form.tsx"],"sourcesContent":["import type { FieldPath, FieldValues, UseFormReturn } from 'react-hook-form';\n\nexport interface FieldMapping {\n [apiField: string]: string;\n}\n\ninterface AxiosLikeError {\n response?: {\n data?: unknown;\n };\n}\n\nexport interface FieldError {\n field: string;\n message: string;\n}\n\nexport interface ApiErrorResponse {\n type?: string;\n title?: string;\n status?: number;\n label?: string;\n detail?: string;\n instance?: string;\n errors?: FieldError[];\n}\n\nexport interface MapApiErrorsOptions {\n fieldMapping?: FieldMapping;\n setRootError?: boolean;\n}\n\n// Maps an RFC 9457 Problem Details API error response to react-hook-form root + field errors.\nexport function mapApiErrorsToForm<TFieldValues extends FieldValues = FieldValues>(\n error: unknown,\n form: UseFormReturn<TFieldValues>,\n options: MapApiErrorsOptions = {},\n): void {\n const { fieldMapping = {}, setRootError = true } = options;\n\n if (!error || typeof error !== 'object') {\n if (setRootError) {\n form.setError('root', {\n type: 'Error',\n message: 'An error occurred',\n });\n }\n return;\n }\n\n // Extract error data from axios response structure\n const axiosError = error as AxiosLikeError;\n const errorData = axiosError.response?.data || error;\n const apiError = errorData as ApiErrorResponse;\n\n // Extract title/label for error heading (RFC 9457)\n const errorTitle = apiError.label || apiError.title || 'Error';\n const generalMessage = apiError.detail;\n\n // Map field-specific errors (field is always present in RFC 9457)\n let mappedFieldErrorsCount = 0;\n if (apiError.errors && Array.isArray(apiError.errors)) {\n for (const errorItem of apiError.errors) {\n const formField = fieldMapping[errorItem.field] || errorItem.field;\n\n form.setError(formField as FieldPath<TFieldValues>, {\n type: 'manual',\n message: errorItem.message,\n });\n mappedFieldErrorsCount += 1;\n }\n }\n\n // Root error is shown only when no field errors are present\n if (generalMessage && setRootError && mappedFieldErrorsCount === 0) {\n form.setError('root', {\n type: errorTitle,\n message: generalMessage,\n });\n }\n}\n","import type { UseMutationResult } from '@tanstack/react-query';\nimport type React from 'react';\nimport { Children, cloneElement, Fragment, isValidElement, useCallback } from 'react';\nimport {\n Controller,\n type ControllerProps,\n type FieldPath,\n type FieldValues,\n FormProvider,\n type UseFormReturn,\n} from 'react-hook-form';\nimport type { Country } from 'react-phone-number-input';\nimport { cn } from '../../../shadcn/utils';\nimport { axios } from '../../utils/axios';\nimport { type FieldMapping, mapApiErrorsToForm } from '../../utils/formHelpers';\nimport { Alert } from '../Alert';\nimport { Button } from '../Button';\nimport { Checkbox } from '../Checkbox';\nimport { CheckboxGroup } from '../CheckboxGroup';\nimport { DatePicker } from '../DatePicker';\nimport { DateTimePicker } from '../DateTimePicker';\nimport { PhoneField } from '../PhoneField';\nimport { RadioGroup } from '../RadioGroup';\nimport { Switch } from '../Switch';\nimport { UploadFile } from '../UploadFile';\n\n// Re-export Controller for explicit usage\nexport { Controller } from 'react-hook-form';\n\n// Recursively process children to wrap form fields with Controller and inject loading state into submit buttons\nfunction processChildren<\n TFieldValues extends FieldValues = FieldValues,\n _TContext = any,\n TTransformedValues extends FieldValues | undefined = TFieldValues,\n>(\n children: React.ReactNode,\n control: ControllerProps<TFieldValues, FieldPath<TFieldValues>, TTransformedValues>['control'],\n isSubmitting: boolean,\n setValue: UseFormReturn<TFieldValues, _TContext, TTransformedValues>['setValue'],\n onCancel?: () => void,\n reset?: UseFormReturn<TFieldValues, _TContext, TTransformedValues>['reset'],\n): React.ReactNode {\n return Children.map(children, (child) => {\n // Handle non-element children (strings, numbers, null, etc.)\n if (!isValidElement(child)) {\n return child;\n }\n\n const childProps = child.props as any;\n const isFragment = child.type === Fragment;\n\n // Handle form fields with name prop (but not Fragments)\n if (!isFragment && childProps.name && typeof childProps.name === 'string') {\n const name = childProps.name as FieldPath<TFieldValues>;\n\n return (\n <Controller\n key={name}\n control={control}\n name={name}\n render={({ field, fieldState }) => {\n // Check if this is a Checkbox, Switch, RadioGroup, or CheckboxGroup component\n const isCheckbox = child.type === Checkbox;\n const isSwitch = child.type === Switch;\n const isRadioGroup = child.type === RadioGroup;\n const isCheckboxGroup = child.type === CheckboxGroup;\n const isPhone = child.type === PhoneField;\n const isDatePicker = child.type === DatePicker;\n const isDateTimePicker = child.type === DateTimePicker;\n\n const fieldProps =\n isCheckbox || isSwitch\n ? {\n checked: field.value,\n onCheckedChange: field.onChange,\n onBlur: field.onBlur,\n ref: field.ref,\n }\n : isRadioGroup || isCheckboxGroup\n ? {\n value: field.value,\n onValueChange: field.onChange,\n onBlur: field.onBlur,\n }\n : isDatePicker\n ? {\n value: field.value,\n onValueChange: field.onChange,\n onBlur: field.onBlur,\n ref: field.ref,\n }\n : isDateTimePicker\n ? {\n value: field.value,\n onValueChange: field.onChange,\n onBlur: field.onBlur,\n ref: field.ref,\n }\n : isPhone\n ? {\n ...field,\n onCountryChange: (country: Country | undefined) => {\n setValue(`${name}Country` as FieldPath<TFieldValues>, country as any);\n },\n }\n : field;\n\n const isUploadFile = child.type === UploadFile;\n\n return cloneElement(child, {\n ...childProps,\n ...fieldProps,\n error: fieldState.error?.message || (fieldState.error ? 'Invalid' : undefined),\n name: undefined, // Remove name to avoid passing it to the underlying input\n ...(isUploadFile ? { isLoading: isSubmitting } : {}),\n });\n }}\n />\n );\n }\n\n // Handle cancel buttons - wire up form.reset() + onCancel callback\n if (childProps['data-cancel'] && onCancel && reset) {\n return cloneElement(child, {\n ...childProps,\n onClick: () => {\n reset();\n onCancel();\n },\n });\n }\n\n // Handle submit buttons - inject loading state via isLoading prop\n if (childProps.type === 'submit') {\n const isButtonElement =\n child.type === Button || (typeof child.type === 'function' && (child.type as any).displayName === 'Button');\n\n if (isButtonElement) {\n return cloneElement(child, {\n ...childProps,\n isLoading: isSubmitting,\n });\n }\n }\n\n // Handle React Fragments - process their children directly\n if (isFragment) {\n return processChildren(childProps.children, control, isSubmitting, setValue, onCancel, reset);\n }\n\n // Recurse into children for container elements (divs, FieldGroups, etc.)\n if (childProps.children != null) {\n return cloneElement(child, {\n ...childProps,\n children: processChildren(childProps.children, control, isSubmitting, setValue, onCancel, reset),\n });\n }\n\n // Return unchanged if no name prop and no children\n return child;\n });\n}\n\nexport interface FormProps<\n TFieldValues extends FieldValues = FieldValues,\n TContext = any,\n TTransformedValues extends FieldValues | undefined = TFieldValues,\n TMutationData = unknown,\n TMutationError = Error,\n TMutationVariables = any,\n> extends Omit<React.FormHTMLAttributes<HTMLFormElement>, 'onSubmit'> {\n form: UseFormReturn<TFieldValues, TContext, TTransformedValues>;\n\n onSubmit?: Parameters<UseFormReturn<TFieldValues, TContext, TTransformedValues>['handleSubmit']>[0];\n\n children: React.ReactNode;\n\n rootErrorPosition?: 'top' | 'bottom';\n\n rootErrorClassName?: string;\n\n rootErrorAction?: React.ReactNode;\n\n fieldMapping?: FieldMapping;\n\n mutation?: UseMutationResult<TMutationData, TMutationError, TMutationVariables, unknown>;\n\n transformSubmit?: (\n data: TTransformedValues extends undefined ? TFieldValues : TTransformedValues,\n ) => TMutationVariables;\n\n resetOnSuccess?: boolean;\n\n onCancel?: () => void;\n}\n\n// Smart Form component that automatically wraps children with Controller\nexport function Form<\n TFieldValues extends FieldValues = FieldValues,\n TContext = any,\n TTransformedValues extends FieldValues | undefined = TFieldValues,\n TMutationData = unknown,\n TMutationError = Error,\n TMutationVariables = any,\n>({\n form,\n onSubmit,\n children,\n rootErrorPosition = 'bottom',\n rootErrorClassName,\n rootErrorAction,\n fieldMapping,\n mutation,\n transformSubmit,\n resetOnSuccess,\n onCancel,\n className,\n ...props\n}: FormProps<TFieldValues, TContext, TTransformedValues, TMutationData, TMutationError, TMutationVariables>) {\n // Compute isSubmitting from both form state and mutation state\n const isSubmitting = form.formState.isSubmitting || (mutation?.isPending ?? false);\n\n // Wrap the submit handler with automatic error mapping; the mutation's own callbacks fire automatically\n const wrappedOnSubmit = useCallback(\n async (data: TTransformedValues extends undefined ? TFieldValues : TTransformedValues) => {\n // Suppress error toasts during form submission — Form handles errors inline\n const interceptorId = axios.interceptors.request.use((config) => ({\n ...config,\n showErrorToast: false,\n }));\n\n try {\n if (mutation) {\n const variables = transformSubmit ? transformSubmit(data) : data;\n // mutateAsync will trigger the mutation's onSuccess/onError callbacks\n await mutation.mutateAsync(variables as TMutationVariables);\n } else if (onSubmit) {\n await onSubmit(data as any);\n }\n\n // Reset form after successful submission (default: true)\n if (resetOnSuccess !== false) form.reset();\n } catch (error) {\n // Map API errors to form fields — mapApiErrorsToForm extracts the axios error structure internally\n mapApiErrorsToForm(error, form as any, {\n fieldMapping,\n });\n // Log error for debugging\n console.error('[Form Submission Error]', error);\n // Error is swallowed, not re-thrown (mutation's onError already fired)\n } finally {\n axios.interceptors.request.eject(interceptorId);\n }\n },\n [onSubmit, mutation, transformSubmit, fieldMapping, form, resetOnSuccess],\n );\n\n const handleSubmit = form.handleSubmit(wrappedOnSubmit as any);\n\n // Process children recursively to automatically wrap with Controller\n const processedChildren = processChildren(children, form.control, isSubmitting, form.setValue, onCancel, form.reset);\n\n const childArray = Children.toArray(processedChildren);\n const actionsIndex = childArray.findIndex(\n (child) => isValidElement(child) && (child.type as { displayName?: string })?.displayName === 'DialogActions',\n );\n const hasActions = actionsIndex !== -1;\n const bodyChildren = hasActions ? childArray.filter((_, index) => index !== actionsIndex) : processedChildren;\n const actions = hasActions ? childArray[actionsIndex] : null;\n\n const topError =\n rootErrorPosition === 'top' && form.formState.errors.root ? (\n <Alert\n variant=\"destructive\"\n title={form.formState.errors.root.type || 'Error'}\n description={form.formState.errors.root.message}\n action={rootErrorAction}\n className={cn('mb-4', rootErrorClassName)}\n />\n ) : null;\n const bottomError =\n rootErrorPosition === 'bottom' && form.formState.errors.root ? (\n <Alert\n variant=\"destructive\"\n title={form.formState.errors.root.type || 'Error'}\n description={form.formState.errors.root.message}\n action={rootErrorAction}\n className={cn('mt-4', rootErrorClassName)}\n />\n ) : null;\n\n return (\n <FormProvider {...form}>\n <form\n onSubmit={handleSubmit}\n className={cn(hasActions ? 'flex min-h-0 flex-1 flex-col' : 'space-y-4', className)}\n {...props}\n >\n {hasActions ? (\n <>\n <div className=\"min-h-0 flex-1 space-y-4 overflow-y-auto overscroll-contain px-6 py-4 [scrollbar-gutter:stable]\">\n {topError}\n {bodyChildren}\n {bottomError}\n </div>\n {actions}\n </>\n ) : (\n <>\n {topError}\n {processedChildren}\n {bottomError}\n </>\n )}\n </form>\n </FormProvider>\n );\n}\n\nForm.displayName = 'Form';\n"],"names":["Fragment"],"mappings":"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"}
1
+ {"version":3,"file":"Form.js","sources":["../lib/utils/formHelpers.ts","../lib/components/Form/Form.tsx"],"sourcesContent":["import type { FieldPath, FieldValues, UseFormReturn } from 'react-hook-form';\n\nexport interface FieldMapping {\n [apiField: string]: string;\n}\n\ninterface AxiosLikeError {\n response?: {\n data?: unknown;\n };\n}\n\nexport interface FieldError {\n field: string;\n message: string;\n}\n\nexport interface ApiErrorResponse {\n type?: string;\n title?: string;\n status?: number;\n label?: string;\n detail?: string;\n instance?: string;\n errors?: FieldError[];\n}\n\nexport interface MapApiErrorsOptions {\n fieldMapping?: FieldMapping;\n setRootError?: boolean;\n}\n\n// Maps an RFC 9457 Problem Details API error response to react-hook-form root + field errors.\nexport function mapApiErrorsToForm<TFieldValues extends FieldValues = FieldValues>(\n error: unknown,\n form: UseFormReturn<TFieldValues>,\n options: MapApiErrorsOptions = {},\n): void {\n const { fieldMapping = {}, setRootError = true } = options;\n\n if (!error || typeof error !== 'object') {\n if (setRootError) {\n form.setError('root', {\n type: 'Error',\n message: 'An error occurred',\n });\n }\n return;\n }\n\n // Extract error data from axios response structure\n const axiosError = error as AxiosLikeError;\n const errorData = axiosError.response?.data || error;\n const apiError = errorData as ApiErrorResponse;\n\n // Extract title/label for error heading (RFC 9457)\n const errorTitle = apiError.label || apiError.title || 'Error';\n const generalMessage = apiError.detail;\n\n // Map field-specific errors (field is always present in RFC 9457)\n let mappedFieldErrorsCount = 0;\n if (apiError.errors && Array.isArray(apiError.errors)) {\n for (const errorItem of apiError.errors) {\n const formField = fieldMapping[errorItem.field] || errorItem.field;\n\n form.setError(formField as FieldPath<TFieldValues>, {\n type: 'manual',\n message: errorItem.message,\n });\n mappedFieldErrorsCount += 1;\n }\n }\n\n // Root error is shown only when no field errors are present\n if (generalMessage && setRootError && mappedFieldErrorsCount === 0) {\n form.setError('root', {\n type: errorTitle,\n message: generalMessage,\n });\n }\n}\n","import type { UseMutationResult } from '@tanstack/react-query';\nimport type React from 'react';\nimport { Children, cloneElement, Fragment, isValidElement, useCallback } from 'react';\nimport {\n Controller,\n type ControllerProps,\n type FieldPath,\n type FieldValues,\n FormProvider,\n type UseFormReturn,\n} from 'react-hook-form';\nimport type { Country } from 'react-phone-number-input';\nimport { cn } from '../../../shadcn/utils';\nimport { axios } from '../../utils/axios';\nimport { type FieldMapping, mapApiErrorsToForm } from '../../utils/formHelpers';\nimport { Alert } from '../Alert';\nimport { Button } from '../Button';\nimport { Checkbox } from '../Checkbox';\nimport { CheckboxGroup } from '../CheckboxGroup';\nimport { DatePicker } from '../DatePicker';\nimport { DateTimePicker } from '../DateTimePicker';\nimport { PhoneField } from '../PhoneField';\nimport { RadioGroup } from '../RadioGroup';\nimport { Switch } from '../Switch';\nimport { UploadFile } from '../UploadFile';\n\n// Re-export Controller for explicit usage\nexport { Controller } from 'react-hook-form';\n\n// Recursively process children to wrap form fields with Controller and inject loading state into submit buttons\nfunction processChildren<\n TFieldValues extends FieldValues = FieldValues,\n _TContext = any,\n TTransformedValues extends FieldValues | undefined = TFieldValues,\n>(\n children: React.ReactNode,\n control: ControllerProps<TFieldValues, FieldPath<TFieldValues>, TTransformedValues>['control'],\n isSubmitting: boolean,\n setValue: UseFormReturn<TFieldValues, _TContext, TTransformedValues>['setValue'],\n onCancel?: () => void,\n reset?: UseFormReturn<TFieldValues, _TContext, TTransformedValues>['reset'],\n): React.ReactNode {\n return Children.map(children, (child) => {\n // Handle non-element children (strings, numbers, null, etc.)\n if (!isValidElement(child)) {\n return child;\n }\n\n const childProps = child.props as any;\n const isFragment = child.type === Fragment;\n\n // Handle form fields with name prop (but not Fragments)\n if (!isFragment && childProps.name && typeof childProps.name === 'string') {\n const name = childProps.name as FieldPath<TFieldValues>;\n\n return (\n <Controller\n key={name}\n control={control}\n name={name}\n render={({ field, fieldState }) => {\n // Check if this is a Checkbox, Switch, RadioGroup, or CheckboxGroup component\n const isCheckbox = child.type === Checkbox;\n const isSwitch = child.type === Switch;\n const isRadioGroup = child.type === RadioGroup;\n const isCheckboxGroup = child.type === CheckboxGroup;\n const isPhone = child.type === PhoneField;\n const isDatePicker = child.type === DatePicker;\n const isDateTimePicker = child.type === DateTimePicker;\n\n const fieldProps =\n isCheckbox || isSwitch\n ? {\n checked: field.value,\n onCheckedChange: field.onChange,\n onBlur: field.onBlur,\n ref: field.ref,\n }\n : isRadioGroup || isCheckboxGroup\n ? {\n value: field.value,\n onValueChange: field.onChange,\n onBlur: field.onBlur,\n }\n : isDatePicker\n ? {\n value: field.value,\n onValueChange: field.onChange,\n onBlur: field.onBlur,\n ref: field.ref,\n }\n : isDateTimePicker\n ? {\n value: field.value,\n onValueChange: field.onChange,\n onBlur: field.onBlur,\n ref: field.ref,\n }\n : isPhone\n ? {\n ...field,\n onCountryChange: (country: Country | undefined) => {\n setValue(`${name}Country` as FieldPath<TFieldValues>, country as any);\n },\n }\n : field;\n\n const isUploadFile = child.type === UploadFile;\n\n return cloneElement(child, {\n ...childProps,\n ...fieldProps,\n error: fieldState.error?.message || (fieldState.error ? 'Invalid' : undefined),\n name: undefined, // Remove name to avoid passing it to the underlying input\n ...(isUploadFile ? { isLoading: isSubmitting } : {}),\n });\n }}\n />\n );\n }\n\n // Handle cancel buttons - wire up form.reset() + onCancel callback\n if (childProps['data-cancel'] && onCancel && reset) {\n return cloneElement(child, {\n ...childProps,\n onClick: () => {\n reset();\n onCancel();\n },\n });\n }\n\n // Handle submit buttons - inject loading state via isLoading prop\n if (childProps.type === 'submit') {\n const isButtonElement =\n child.type === Button || (typeof child.type === 'function' && (child.type as any).displayName === 'Button');\n\n if (isButtonElement) {\n return cloneElement(child, {\n ...childProps,\n isLoading: isSubmitting,\n });\n }\n }\n\n // Handle React Fragments - process their children directly\n if (isFragment) {\n return processChildren(childProps.children, control, isSubmitting, setValue, onCancel, reset);\n }\n\n // Recurse into children for container elements (divs, FieldGroups, etc.)\n if (childProps.children != null) {\n return cloneElement(child, {\n ...childProps,\n children: processChildren(childProps.children, control, isSubmitting, setValue, onCancel, reset),\n });\n }\n\n // Return unchanged if no name prop and no children\n return child;\n });\n}\n\nexport interface FormProps<\n TFieldValues extends FieldValues = FieldValues,\n TContext = any,\n TTransformedValues extends FieldValues | undefined = TFieldValues,\n TMutationData = unknown,\n TMutationError = Error,\n TMutationVariables = any,\n> extends Omit<React.FormHTMLAttributes<HTMLFormElement>, 'onSubmit'> {\n form: UseFormReturn<TFieldValues, TContext, TTransformedValues>;\n\n onSubmit?: Parameters<UseFormReturn<TFieldValues, TContext, TTransformedValues>['handleSubmit']>[0];\n\n children: React.ReactNode;\n\n rootErrorPosition?: 'top' | 'bottom';\n\n rootErrorClassName?: string;\n\n rootErrorAction?: React.ReactNode;\n\n fieldMapping?: FieldMapping;\n\n mutation?: UseMutationResult<TMutationData, TMutationError, TMutationVariables, unknown>;\n\n transformSubmit?: (\n data: TTransformedValues extends undefined ? TFieldValues : TTransformedValues,\n ) => TMutationVariables;\n\n resetOnSuccess?: boolean;\n\n onCancel?: () => void;\n}\n\n// Smart Form component that automatically wraps children with Controller\nexport function Form<\n TFieldValues extends FieldValues = FieldValues,\n TContext = any,\n TTransformedValues extends FieldValues | undefined = TFieldValues,\n TMutationData = unknown,\n TMutationError = Error,\n TMutationVariables = any,\n>({\n form,\n onSubmit,\n children,\n rootErrorPosition = 'bottom',\n rootErrorClassName,\n rootErrorAction,\n fieldMapping,\n mutation,\n transformSubmit,\n resetOnSuccess,\n onCancel,\n className,\n ...props\n}: FormProps<TFieldValues, TContext, TTransformedValues, TMutationData, TMutationError, TMutationVariables>) {\n // Compute isSubmitting from both form state and mutation state\n const isSubmitting = form.formState.isSubmitting || (mutation?.isPending ?? false);\n\n // Wrap the submit handler with automatic error mapping; the mutation's own callbacks fire automatically\n const wrappedOnSubmit = useCallback(\n async (data: TTransformedValues extends undefined ? TFieldValues : TTransformedValues) => {\n // Suppress error toasts during form submission — Form handles errors inline\n const interceptorId = axios.interceptors.request.use((config) => ({\n ...config,\n showErrorToast: false,\n }));\n\n try {\n if (mutation) {\n const variables = transformSubmit ? transformSubmit(data) : data;\n // mutateAsync will trigger the mutation's onSuccess/onError callbacks\n await mutation.mutateAsync(variables as TMutationVariables);\n } else if (onSubmit) {\n await onSubmit(data as any);\n }\n\n // Reset form after successful submission (default: true)\n if (resetOnSuccess !== false) form.reset();\n } catch (error) {\n // Map API errors to form fields — mapApiErrorsToForm extracts the axios error structure internally\n mapApiErrorsToForm(error, form as any, {\n fieldMapping,\n });\n // Log error for debugging\n console.error('[Form Submission Error]', error);\n // Error is swallowed, not re-thrown (mutation's onError already fired)\n } finally {\n axios.interceptors.request.eject(interceptorId);\n }\n },\n [onSubmit, mutation, transformSubmit, fieldMapping, form, resetOnSuccess],\n );\n\n const handleSubmit = form.handleSubmit(wrappedOnSubmit as any);\n\n // Process children recursively to automatically wrap with Controller\n const processedChildren = processChildren(children, form.control, isSubmitting, form.setValue, onCancel, form.reset);\n\n const childArray = Children.toArray(processedChildren);\n const actionsIndex = childArray.findIndex(\n (child) => isValidElement(child) && (child.type as { displayName?: string })?.displayName === 'DialogActions',\n );\n const hasActions = actionsIndex !== -1;\n const bodyChildren = hasActions ? childArray.filter((_, index) => index !== actionsIndex) : processedChildren;\n const actions = hasActions ? childArray[actionsIndex] : null;\n\n const topError =\n rootErrorPosition === 'top' && form.formState.errors.root ? (\n <Alert\n variant=\"destructive\"\n title={form.formState.errors.root.type || 'Error'}\n description={form.formState.errors.root.message}\n action={rootErrorAction}\n className={cn('mb-4', rootErrorClassName)}\n />\n ) : null;\n const bottomError =\n rootErrorPosition === 'bottom' && form.formState.errors.root ? (\n <Alert\n variant=\"destructive\"\n title={form.formState.errors.root.type || 'Error'}\n description={form.formState.errors.root.message}\n action={rootErrorAction}\n className={cn('mt-4', rootErrorClassName)}\n />\n ) : null;\n\n return (\n <FormProvider {...form}>\n <form\n onSubmit={handleSubmit}\n className={cn(hasActions ? 'flex min-h-0 flex-1 flex-col' : 'space-y-4', className)}\n {...props}\n >\n {hasActions ? (\n <>\n <div className=\"min-h-0 flex-1 space-y-4 overflow-y-auto overscroll-contain px-6 py-4\">\n {topError}\n {bodyChildren}\n {bottomError}\n </div>\n {actions}\n </>\n ) : (\n <>\n {topError}\n {processedChildren}\n {bottomError}\n </>\n )}\n </form>\n </FormProvider>\n );\n}\n\nForm.displayName = 'Form';\n"],"names":["Fragment"],"mappings":"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"}
package/dist/Switch.js CHANGED
@@ -182,19 +182,17 @@ const Switch = React__default.forwardRef(
182
182
  const fieldId = id || generatedId;
183
183
  const hasError = !!error;
184
184
  return /* @__PURE__ */ jsxs(Field, { "data-disabled": props.disabled, "data-invalid": hasError, children: [
185
- /* @__PURE__ */ jsxs("div", { className: "flex min-h-9 items-center justify-between gap-4", children: [
186
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-0.5", children: [
187
- label && /* @__PURE__ */ jsx(FieldLabel, { htmlFor: fieldId, className: "font-normal cursor-pointer", children: label }),
188
- /* @__PURE__ */ jsx(
189
- "label",
190
- {
191
- htmlFor: fieldId,
192
- id: `${fieldId}-description`,
193
- className: "text-sm text-muted-foreground leading-normal cursor-pointer",
194
- children: description
195
- }
196
- )
197
- ] }),
185
+ label && /* @__PURE__ */ jsx(FieldLabel, { htmlFor: fieldId, className: "cursor-pointer", children: label }),
186
+ /* @__PURE__ */ jsxs("div", { className: "flex min-h-9 items-center gap-3", children: [
187
+ description && /* @__PURE__ */ jsx(
188
+ "label",
189
+ {
190
+ htmlFor: fieldId,
191
+ id: `${fieldId}-description`,
192
+ className: "flex-1 cursor-pointer text-sm leading-snug text-muted-foreground",
193
+ children: description
194
+ }
195
+ ),
198
196
  /* @__PURE__ */ jsx(
199
197
  Switch$1,
200
198
  {
@@ -1 +1 @@
1
- {"version":3,"file":"Switch.js","sources":["../node_modules/.pnpm/@radix-ui+react-switch@1.2.6_@types+react-dom@19.2.3_@types+react@19.2.14__@types+react_c3445f43106be928beab9f2bef095c25/node_modules/@radix-ui/react-switch/dist/index.mjs","../shadcn/shadcnSwitch/Switch.tsx","../lib/components/Switch/Switch.tsx"],"sourcesContent":["\"use client\";\n\n// src/switch.tsx\nimport * as React from \"react\";\nimport { composeEventHandlers } from \"@radix-ui/primitive\";\nimport { useComposedRefs } from \"@radix-ui/react-compose-refs\";\nimport { createContextScope } from \"@radix-ui/react-context\";\nimport { useControllableState } from \"@radix-ui/react-use-controllable-state\";\nimport { usePrevious } from \"@radix-ui/react-use-previous\";\nimport { useSize } from \"@radix-ui/react-use-size\";\nimport { Primitive } from \"@radix-ui/react-primitive\";\nimport { jsx, jsxs } from \"react/jsx-runtime\";\nvar SWITCH_NAME = \"Switch\";\nvar [createSwitchContext, createSwitchScope] = createContextScope(SWITCH_NAME);\nvar [SwitchProvider, useSwitchContext] = createSwitchContext(SWITCH_NAME);\nvar Switch = React.forwardRef(\n (props, forwardedRef) => {\n const {\n __scopeSwitch,\n name,\n checked: checkedProp,\n defaultChecked,\n required,\n disabled,\n value = \"on\",\n onCheckedChange,\n form,\n ...switchProps\n } = props;\n const [button, setButton] = React.useState(null);\n const composedRefs = useComposedRefs(forwardedRef, (node) => setButton(node));\n const hasConsumerStoppedPropagationRef = React.useRef(false);\n const isFormControl = button ? form || !!button.closest(\"form\") : true;\n const [checked, setChecked] = useControllableState({\n prop: checkedProp,\n defaultProp: defaultChecked ?? false,\n onChange: onCheckedChange,\n caller: SWITCH_NAME\n });\n return /* @__PURE__ */ jsxs(SwitchProvider, { scope: __scopeSwitch, checked, disabled, children: [\n /* @__PURE__ */ jsx(\n Primitive.button,\n {\n type: \"button\",\n role: \"switch\",\n \"aria-checked\": checked,\n \"aria-required\": required,\n \"data-state\": getState(checked),\n \"data-disabled\": disabled ? \"\" : void 0,\n disabled,\n value,\n ...switchProps,\n ref: composedRefs,\n onClick: composeEventHandlers(props.onClick, (event) => {\n setChecked((prevChecked) => !prevChecked);\n if (isFormControl) {\n hasConsumerStoppedPropagationRef.current = event.isPropagationStopped();\n if (!hasConsumerStoppedPropagationRef.current) event.stopPropagation();\n }\n })\n }\n ),\n isFormControl && /* @__PURE__ */ jsx(\n SwitchBubbleInput,\n {\n control: button,\n bubbles: !hasConsumerStoppedPropagationRef.current,\n name,\n value,\n checked,\n required,\n disabled,\n form,\n style: { transform: \"translateX(-100%)\" }\n }\n )\n ] });\n }\n);\nSwitch.displayName = SWITCH_NAME;\nvar THUMB_NAME = \"SwitchThumb\";\nvar SwitchThumb = React.forwardRef(\n (props, forwardedRef) => {\n const { __scopeSwitch, ...thumbProps } = props;\n const context = useSwitchContext(THUMB_NAME, __scopeSwitch);\n return /* @__PURE__ */ jsx(\n Primitive.span,\n {\n \"data-state\": getState(context.checked),\n \"data-disabled\": context.disabled ? \"\" : void 0,\n ...thumbProps,\n ref: forwardedRef\n }\n );\n }\n);\nSwitchThumb.displayName = THUMB_NAME;\nvar BUBBLE_INPUT_NAME = \"SwitchBubbleInput\";\nvar SwitchBubbleInput = React.forwardRef(\n ({\n __scopeSwitch,\n control,\n checked,\n bubbles = true,\n ...props\n }, forwardedRef) => {\n const ref = React.useRef(null);\n const composedRefs = useComposedRefs(ref, forwardedRef);\n const prevChecked = usePrevious(checked);\n const controlSize = useSize(control);\n React.useEffect(() => {\n const input = ref.current;\n if (!input) return;\n const inputProto = window.HTMLInputElement.prototype;\n const descriptor = Object.getOwnPropertyDescriptor(\n inputProto,\n \"checked\"\n );\n const setChecked = descriptor.set;\n if (prevChecked !== checked && setChecked) {\n const event = new Event(\"click\", { bubbles });\n setChecked.call(input, checked);\n input.dispatchEvent(event);\n }\n }, [prevChecked, checked, bubbles]);\n return /* @__PURE__ */ jsx(\n \"input\",\n {\n type: \"checkbox\",\n \"aria-hidden\": true,\n defaultChecked: checked,\n ...props,\n tabIndex: -1,\n ref: composedRefs,\n style: {\n ...props.style,\n ...controlSize,\n position: \"absolute\",\n pointerEvents: \"none\",\n opacity: 0,\n margin: 0\n }\n }\n );\n }\n);\nSwitchBubbleInput.displayName = BUBBLE_INPUT_NAME;\nfunction getState(checked) {\n return checked ? \"checked\" : \"unchecked\";\n}\nvar Root = Switch;\nvar Thumb = SwitchThumb;\nexport {\n Root,\n Switch,\n SwitchThumb,\n Thumb,\n createSwitchScope\n};\n//# sourceMappingURL=index.mjs.map\n","'use client';\n\nimport * as SwitchPrimitive from '@radix-ui/react-switch';\nimport type * as React from 'react';\n\nimport { cn } from '../utils';\n\nfunction Switch({\n className,\n size = 'default',\n ...props\n}: React.ComponentProps<typeof SwitchPrimitive.Root> & {\n size?: 'sm' | 'default' | 'lg';\n}) {\n return (\n <SwitchPrimitive.Root\n data-slot=\"switch\"\n data-size={size}\n className={cn(\n 'peer group/switch relative inline-flex shrink-0 items-center rounded-full border border-transparent outline-none transition-all focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input data-[size=default]:h-[18.4px] data-[size=default]:w-[32px] data-[size=sm]:h-[14px] data-[size=sm]:w-[24px] data-[size=lg]:h-[24px] data-[size=lg]:w-[40px]',\n className,\n )}\n {...props}\n >\n <SwitchPrimitive.Thumb\n data-slot=\"switch-thumb\"\n className=\"bg-primary-foreground shadow-sm pointer-events-none block rounded-full ring-0 transition-transform group-data-[size=default]/switch:size-4 group-data-[size=sm]/switch:size-3 group-data-[size=lg]/switch:size-5 data-[state=checked]:translate-x-[calc(100%-2px)] data-[state=unchecked]:translate-x-0\"\n />\n </SwitchPrimitive.Root>\n );\n}\n\nexport { Switch };\n","import React from 'react';\nimport { Field, FieldError, FieldLabel } from '../../../shadcn/shadcnField';\nimport { Switch as ShadcnSwitch } from '../../../shadcn/shadcnSwitch';\n\nexport interface SwitchProps extends React.ComponentPropsWithoutRef<typeof ShadcnSwitch> {\n label?: React.ReactNode;\n\n description: React.ReactNode;\n\n error?: string;\n}\n\n// Switch for toggling on/off; label + description stack left with the toggle pinned right (description required)\nexport const Switch = React.forwardRef<React.ElementRef<typeof ShadcnSwitch>, SwitchProps>(\n ({ label, description, error, id, size = 'lg', ...props }, ref) => {\n const generatedId = React.useId();\n const fieldId = id || generatedId;\n const hasError = !!error;\n\n return (\n <Field data-disabled={props.disabled} data-invalid={hasError}>\n <div className=\"flex min-h-9 items-center justify-between gap-4\">\n <div className=\"flex flex-col gap-0.5\">\n {label && (\n <FieldLabel htmlFor={fieldId} className=\"font-normal cursor-pointer\">\n {label}\n </FieldLabel>\n )}\n <label\n htmlFor={fieldId}\n id={`${fieldId}-description`}\n className=\"text-sm text-muted-foreground leading-normal cursor-pointer\"\n >\n {description}\n </label>\n </div>\n <ShadcnSwitch\n {...props}\n ref={ref}\n id={fieldId}\n size={size}\n aria-describedby={description || error ? `${fieldId}-description ${fieldId}-error` : undefined}\n aria-invalid={hasError}\n />\n </div>\n\n {error && <FieldError id={`${fieldId}-error`}>{error}</FieldError>}\n </Field>\n );\n },\n);\n\nSwitch.displayName = 'Switch';\n\nexport type CompactSwitchProps = React.ComponentProps<typeof ShadcnSwitch>;\n\n// Bare compact switch with no Field wrapper, defaults to sm size for dense layouts like table/matrix cells\nexport const CompactSwitch: React.FC<CompactSwitchProps> = ({ size = 'sm', ...props }) => (\n <ShadcnSwitch size={size} {...props} />\n);\n\nCompactSwitch.displayName = 'CompactSwitch';\n"],"names":["Switch","SwitchPrimitive.Root","SwitchPrimitive.Thumb","React","ShadcnSwitch"],"mappings":"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","x_google_ignoreList":[0]}
1
+ {"version":3,"file":"Switch.js","sources":["../node_modules/.pnpm/@radix-ui+react-switch@1.2.6_@types+react-dom@19.2.3_@types+react@19.2.14__@types+react_c3445f43106be928beab9f2bef095c25/node_modules/@radix-ui/react-switch/dist/index.mjs","../shadcn/shadcnSwitch/Switch.tsx","../lib/components/Switch/Switch.tsx"],"sourcesContent":["\"use client\";\n\n// src/switch.tsx\nimport * as React from \"react\";\nimport { composeEventHandlers } from \"@radix-ui/primitive\";\nimport { useComposedRefs } from \"@radix-ui/react-compose-refs\";\nimport { createContextScope } from \"@radix-ui/react-context\";\nimport { useControllableState } from \"@radix-ui/react-use-controllable-state\";\nimport { usePrevious } from \"@radix-ui/react-use-previous\";\nimport { useSize } from \"@radix-ui/react-use-size\";\nimport { Primitive } from \"@radix-ui/react-primitive\";\nimport { jsx, jsxs } from \"react/jsx-runtime\";\nvar SWITCH_NAME = \"Switch\";\nvar [createSwitchContext, createSwitchScope] = createContextScope(SWITCH_NAME);\nvar [SwitchProvider, useSwitchContext] = createSwitchContext(SWITCH_NAME);\nvar Switch = React.forwardRef(\n (props, forwardedRef) => {\n const {\n __scopeSwitch,\n name,\n checked: checkedProp,\n defaultChecked,\n required,\n disabled,\n value = \"on\",\n onCheckedChange,\n form,\n ...switchProps\n } = props;\n const [button, setButton] = React.useState(null);\n const composedRefs = useComposedRefs(forwardedRef, (node) => setButton(node));\n const hasConsumerStoppedPropagationRef = React.useRef(false);\n const isFormControl = button ? form || !!button.closest(\"form\") : true;\n const [checked, setChecked] = useControllableState({\n prop: checkedProp,\n defaultProp: defaultChecked ?? false,\n onChange: onCheckedChange,\n caller: SWITCH_NAME\n });\n return /* @__PURE__ */ jsxs(SwitchProvider, { scope: __scopeSwitch, checked, disabled, children: [\n /* @__PURE__ */ jsx(\n Primitive.button,\n {\n type: \"button\",\n role: \"switch\",\n \"aria-checked\": checked,\n \"aria-required\": required,\n \"data-state\": getState(checked),\n \"data-disabled\": disabled ? \"\" : void 0,\n disabled,\n value,\n ...switchProps,\n ref: composedRefs,\n onClick: composeEventHandlers(props.onClick, (event) => {\n setChecked((prevChecked) => !prevChecked);\n if (isFormControl) {\n hasConsumerStoppedPropagationRef.current = event.isPropagationStopped();\n if (!hasConsumerStoppedPropagationRef.current) event.stopPropagation();\n }\n })\n }\n ),\n isFormControl && /* @__PURE__ */ jsx(\n SwitchBubbleInput,\n {\n control: button,\n bubbles: !hasConsumerStoppedPropagationRef.current,\n name,\n value,\n checked,\n required,\n disabled,\n form,\n style: { transform: \"translateX(-100%)\" }\n }\n )\n ] });\n }\n);\nSwitch.displayName = SWITCH_NAME;\nvar THUMB_NAME = \"SwitchThumb\";\nvar SwitchThumb = React.forwardRef(\n (props, forwardedRef) => {\n const { __scopeSwitch, ...thumbProps } = props;\n const context = useSwitchContext(THUMB_NAME, __scopeSwitch);\n return /* @__PURE__ */ jsx(\n Primitive.span,\n {\n \"data-state\": getState(context.checked),\n \"data-disabled\": context.disabled ? \"\" : void 0,\n ...thumbProps,\n ref: forwardedRef\n }\n );\n }\n);\nSwitchThumb.displayName = THUMB_NAME;\nvar BUBBLE_INPUT_NAME = \"SwitchBubbleInput\";\nvar SwitchBubbleInput = React.forwardRef(\n ({\n __scopeSwitch,\n control,\n checked,\n bubbles = true,\n ...props\n }, forwardedRef) => {\n const ref = React.useRef(null);\n const composedRefs = useComposedRefs(ref, forwardedRef);\n const prevChecked = usePrevious(checked);\n const controlSize = useSize(control);\n React.useEffect(() => {\n const input = ref.current;\n if (!input) return;\n const inputProto = window.HTMLInputElement.prototype;\n const descriptor = Object.getOwnPropertyDescriptor(\n inputProto,\n \"checked\"\n );\n const setChecked = descriptor.set;\n if (prevChecked !== checked && setChecked) {\n const event = new Event(\"click\", { bubbles });\n setChecked.call(input, checked);\n input.dispatchEvent(event);\n }\n }, [prevChecked, checked, bubbles]);\n return /* @__PURE__ */ jsx(\n \"input\",\n {\n type: \"checkbox\",\n \"aria-hidden\": true,\n defaultChecked: checked,\n ...props,\n tabIndex: -1,\n ref: composedRefs,\n style: {\n ...props.style,\n ...controlSize,\n position: \"absolute\",\n pointerEvents: \"none\",\n opacity: 0,\n margin: 0\n }\n }\n );\n }\n);\nSwitchBubbleInput.displayName = BUBBLE_INPUT_NAME;\nfunction getState(checked) {\n return checked ? \"checked\" : \"unchecked\";\n}\nvar Root = Switch;\nvar Thumb = SwitchThumb;\nexport {\n Root,\n Switch,\n SwitchThumb,\n Thumb,\n createSwitchScope\n};\n//# sourceMappingURL=index.mjs.map\n","'use client';\n\nimport * as SwitchPrimitive from '@radix-ui/react-switch';\nimport type * as React from 'react';\n\nimport { cn } from '../utils';\n\nfunction Switch({\n className,\n size = 'default',\n ...props\n}: React.ComponentProps<typeof SwitchPrimitive.Root> & {\n size?: 'sm' | 'default' | 'lg';\n}) {\n return (\n <SwitchPrimitive.Root\n data-slot=\"switch\"\n data-size={size}\n className={cn(\n 'peer group/switch relative inline-flex shrink-0 items-center rounded-full border border-transparent outline-none transition-all focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input data-[size=default]:h-[18.4px] data-[size=default]:w-[32px] data-[size=sm]:h-[14px] data-[size=sm]:w-[24px] data-[size=lg]:h-[24px] data-[size=lg]:w-[40px]',\n className,\n )}\n {...props}\n >\n <SwitchPrimitive.Thumb\n data-slot=\"switch-thumb\"\n className=\"bg-primary-foreground shadow-sm pointer-events-none block rounded-full ring-0 transition-transform group-data-[size=default]/switch:size-4 group-data-[size=sm]/switch:size-3 group-data-[size=lg]/switch:size-5 data-[state=checked]:translate-x-[calc(100%-2px)] data-[state=unchecked]:translate-x-0\"\n />\n </SwitchPrimitive.Root>\n );\n}\n\nexport { Switch };\n","import React from 'react';\nimport { Field, FieldError, FieldLabel } from '../../../shadcn/shadcnField';\nimport { Switch as ShadcnSwitch } from '../../../shadcn/shadcnSwitch';\n\nexport interface SwitchProps extends React.ComponentPropsWithoutRef<typeof ShadcnSwitch> {\n label?: React.ReactNode;\n\n description: React.ReactNode;\n\n error?: string;\n}\n\n// Switch for toggling on/off; label + description on the left with the toggle pinned right (description required)\nexport const Switch = React.forwardRef<React.ElementRef<typeof ShadcnSwitch>, SwitchProps>(\n ({ label, description, error, id, size = 'lg', ...props }, ref) => {\n const generatedId = React.useId();\n const fieldId = id || generatedId;\n const hasError = !!error;\n\n return (\n <Field data-disabled={props.disabled} data-invalid={hasError}>\n {label && (\n <FieldLabel htmlFor={fieldId} className=\"cursor-pointer\">\n {label}\n </FieldLabel>\n )}\n <div className=\"flex min-h-9 items-center gap-3\">\n {description && (\n <label\n htmlFor={fieldId}\n id={`${fieldId}-description`}\n className=\"flex-1 cursor-pointer text-sm leading-snug text-muted-foreground\"\n >\n {description}\n </label>\n )}\n <ShadcnSwitch\n {...props}\n ref={ref}\n id={fieldId}\n size={size}\n aria-describedby={description || error ? `${fieldId}-description ${fieldId}-error` : undefined}\n aria-invalid={hasError}\n />\n </div>\n {error && <FieldError id={`${fieldId}-error`}>{error}</FieldError>}\n </Field>\n );\n },\n);\n\nSwitch.displayName = 'Switch';\n\nexport type CompactSwitchProps = React.ComponentProps<typeof ShadcnSwitch>;\n\n// Bare compact switch with no Field wrapper, defaults to sm size for dense layouts like table/matrix cells\nexport const CompactSwitch: React.FC<CompactSwitchProps> = ({ size = 'sm', ...props }) => (\n <ShadcnSwitch size={size} {...props} />\n);\n\nCompactSwitch.displayName = 'CompactSwitch';\n"],"names":["Switch","SwitchPrimitive.Root","SwitchPrimitive.Thumb","React","ShadcnSwitch"],"mappings":"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","x_google_ignoreList":[0]}
@@ -1,5 +1,5 @@
1
1
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
2
- import { useRef, useState, useEffect } from 'react';
2
+ import { useRef, useMemo, useEffect } from 'react';
3
3
  import { c as cn } from './utils.js';
4
4
  import { B as Button } from './Button.js';
5
5
  import { F as FilePreview } from './FilePreview.js';
@@ -8,40 +8,35 @@ import { U as Upload } from './upload.js';
8
8
  import { C as Camera, U as User } from './user.js';
9
9
  import { X } from './x.js';
10
10
 
11
- const AvatarPreview = ({ file, size }) => {
12
- const [objectUrl, setObjectUrl] = useState(null);
11
+ function useImageObjectUrl(file) {
12
+ const objectUrl = useMemo(() => file?.type.startsWith("image/") ? URL.createObjectURL(file) : null, [file]);
13
13
  useEffect(() => {
14
- const url = URL.createObjectURL(file);
15
- setObjectUrl(url);
16
- return () => URL.revokeObjectURL(url);
17
- }, [file]);
18
- if (!objectUrl) return null;
19
- return /* @__PURE__ */ jsx(
20
- "img",
21
- {
22
- src: objectUrl,
23
- alt: file.name,
24
- className: "rounded-full object-cover w-full h-full",
25
- style: { width: size, height: size }
26
- }
27
- );
28
- };
14
+ if (!objectUrl) return;
15
+ return () => URL.revokeObjectURL(objectUrl);
16
+ }, [objectUrl]);
17
+ return objectUrl;
18
+ }
29
19
  const UploadFile = ({
30
20
  anchor = "dropzone",
31
21
  multiple = false,
32
22
  accept,
23
+ className,
33
24
  disabled,
34
25
  label,
35
26
  error,
36
27
  placeholder,
37
28
  hint,
38
29
  value,
30
+ previewUrl,
39
31
  onChange,
40
32
  isLoading
41
33
  }) => {
42
34
  const inputRef = useRef(null);
43
35
  const files = !value ? [] : Array.isArray(value) ? value : [value];
44
36
  const hasFiles = files.length > 0;
37
+ const firstFile = files[0];
38
+ const selectedImageUrl = useImageObjectUrl(firstFile);
39
+ const imageSrc = hasFiles ? selectedImageUrl : previewUrl ?? null;
45
40
  const isPreset = anchor === "dropzone" || anchor === "button" || anchor === "avatar";
46
41
  function handleClick() {
47
42
  if (disabled) return;
@@ -94,7 +89,7 @@ const UploadFile = ({
94
89
  disabled ? "cursor-default opacity-50" : "cursor-pointer hover:bg-muted/50"
95
90
  ),
96
91
  children: [
97
- /* @__PURE__ */ jsx(Upload, { className: "h-6 w-6 text-muted-foreground" }),
92
+ imageSrc ? /* @__PURE__ */ jsx("img", { src: imageSrc, alt: "", className: "h-16 w-16 rounded object-cover" }) : /* @__PURE__ */ jsx(Upload, { className: "h-6 w-6 text-muted-foreground" }),
98
93
  /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: placeholder ?? "Click or drag to upload" }),
99
94
  hint && /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: hint })
100
95
  ]
@@ -110,8 +105,6 @@ const UploadFile = ({
110
105
  }
111
106
  if (anchor === "avatar") {
112
107
  const avatarSize = 80;
113
- const firstFile = files[0];
114
- const hasImage = hasFiles && firstFile.type.startsWith("image/");
115
108
  return (
116
109
  // Wrapper provides positioning context for the badge outside overflow-hidden
117
110
  /* @__PURE__ */ jsxs("div", { className: "relative inline-block", style: { width: avatarSize, height: avatarSize }, children: [
@@ -123,15 +116,25 @@ const UploadFile = ({
123
116
  disabled,
124
117
  className: cn(
125
118
  "group relative h-full w-full overflow-hidden rounded-full bg-muted",
126
- disabled ? "cursor-default opacity-50" : "cursor-pointer"
119
+ disabled ? "cursor-default" : "cursor-pointer",
120
+ // A shown image is content, not an affordance — only dim the empty placeholder
121
+ disabled && !imageSrc && "opacity-50"
127
122
  ),
128
- children: hasImage ? /* @__PURE__ */ jsxs(Fragment, { children: [
129
- /* @__PURE__ */ jsx(AvatarPreview, { file: firstFile, size: avatarSize }),
130
- /* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex items-center justify-center rounded-full bg-black/40 opacity-0 transition-opacity group-hover:opacity-100", children: /* @__PURE__ */ jsx(Camera, { className: "h-5 w-5 text-white" }) })
123
+ children: imageSrc ? /* @__PURE__ */ jsxs(Fragment, { children: [
124
+ /* @__PURE__ */ jsx(
125
+ "img",
126
+ {
127
+ src: imageSrc,
128
+ alt: firstFile?.name ?? "",
129
+ className: "rounded-full object-cover w-full h-full",
130
+ style: { width: avatarSize, height: avatarSize }
131
+ }
132
+ ),
133
+ !disabled && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex items-center justify-center rounded-full bg-black/40 opacity-0 transition-opacity group-hover:opacity-100", children: /* @__PURE__ */ jsx(Camera, { className: "h-5 w-5 text-white" }) })
131
134
  ] }) : /* @__PURE__ */ jsx("div", { className: "flex h-full w-full items-center justify-center", children: /* @__PURE__ */ jsx(User, { className: "h-8 w-8 text-muted-foreground" }) })
132
135
  }
133
136
  ),
134
- !hasImage && /* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute -bottom-0.5 -right-0.5 flex h-6 w-6 items-center justify-center rounded-full bg-primary ring-2 ring-background", children: /* @__PURE__ */ jsx(Upload, { className: "h-3 w-3 text-primary-foreground" }) })
137
+ !imageSrc && /* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute -bottom-0.5 -right-0.5 flex h-6 w-6 items-center justify-center rounded-full bg-primary ring-2 ring-background", children: /* @__PURE__ */ jsx(Upload, { className: "h-3 w-3 text-primary-foreground" }) })
135
138
  ] })
136
139
  );
137
140
  }
@@ -172,26 +175,30 @@ const UploadFile = ({
172
175
  `${file.name}-${file.size}`
173
176
  )) });
174
177
  }
175
- return /* @__PURE__ */ jsxs(Field, { "data-disabled": disabled, children: [
176
- label && /* @__PURE__ */ jsx(FieldLabel, { children: label }),
177
- renderAnchor(),
178
- renderFileList(),
179
- /* @__PURE__ */ jsx(
180
- "input",
181
- {
182
- ref: inputRef,
183
- type: "file",
184
- multiple,
185
- accept,
186
- disabled,
187
- onChange: handleChange,
188
- style: { display: "none" },
189
- "aria-hidden": "true",
190
- tabIndex: -1
191
- }
192
- ),
193
- error && /* @__PURE__ */ jsx(FieldError, { children: error })
194
- ] });
178
+ return (
179
+ // Field is w-full by default; the avatar is a fixed 80px circle, so it hugs its content
180
+ // instead of claiming the whole row and pushing sibling content to the far edge
181
+ /* @__PURE__ */ jsxs(Field, { "data-disabled": disabled, className: cn(anchor === "avatar" && "w-fit", className), children: [
182
+ label && /* @__PURE__ */ jsx(FieldLabel, { children: label }),
183
+ renderAnchor(),
184
+ renderFileList(),
185
+ /* @__PURE__ */ jsx(
186
+ "input",
187
+ {
188
+ ref: inputRef,
189
+ type: "file",
190
+ multiple,
191
+ accept,
192
+ disabled,
193
+ onChange: handleChange,
194
+ style: { display: "none" },
195
+ "aria-hidden": "true",
196
+ tabIndex: -1
197
+ }
198
+ ),
199
+ error && /* @__PURE__ */ jsx(FieldError, { children: error })
200
+ ] })
201
+ );
195
202
  };
196
203
  UploadFile.displayName = "UploadFile";
197
204
 
@@ -1 +1 @@
1
- {"version":3,"file":"UploadFile.js","sources":["../lib/components/UploadFile/UploadFile.tsx"],"sourcesContent":["import { Camera, Upload, User, X } from 'lucide-react';\nimport type React from 'react';\nimport { useEffect, useRef, useState } from 'react';\nimport { cn } from '../../../shadcn/utils';\nimport { Button } from '../Button';\nimport { Field, FieldError, FieldLabel } from '../Field';\nimport { FilePreview } from '../FilePreview';\n\ntype AnchorPreset = 'dropzone' | 'button' | 'avatar';\n\ninterface UploadFileBaseProps {\n anchor?: AnchorPreset | React.ReactNode;\n multiple?: boolean;\n accept?: string;\n disabled?: boolean;\n label?: string;\n error?: string;\n placeholder?: string;\n hint?: string;\n value?: File | File[] | null;\n isLoading?: boolean;\n}\n\ninterface UploadFileStandaloneProps extends UploadFileBaseProps {\n name?: never;\n onChange: (files: File | File[] | undefined) => void;\n}\n\ninterface UploadFileFormProps extends UploadFileBaseProps {\n name: string;\n onChange?: (files: File | File[] | undefined) => void;\n}\n\nexport type UploadFileProps = UploadFileStandaloneProps | UploadFileFormProps;\n\n// Circular avatar preview used by the avatar anchor preset\nconst AvatarPreview: React.FC<{ file: File; size: number }> = ({ file, size }) => {\n const [objectUrl, setObjectUrl] = useState<string | null>(null);\n\n useEffect(() => {\n const url = URL.createObjectURL(file);\n setObjectUrl(url);\n return () => URL.revokeObjectURL(url);\n }, [file]);\n\n if (!objectUrl) return null;\n\n return (\n <img\n src={objectUrl}\n alt={file.name}\n className=\"rounded-full object-cover w-full h-full\"\n style={{ width: size, height: size }}\n />\n );\n};\n\n// File upload trigger with optional preset anchors and built-in file preview\nexport const UploadFile: React.FC<UploadFileProps> = ({\n anchor = 'dropzone',\n multiple = false,\n accept,\n disabled,\n label,\n error,\n placeholder,\n hint,\n value,\n onChange,\n isLoading,\n}) => {\n const inputRef = useRef<HTMLInputElement>(null);\n\n // Normalize value to an array for consistent handling\n const files: File[] = !value ? [] : Array.isArray(value) ? value : [value];\n const hasFiles = files.length > 0;\n\n // True when using a preset string anchor (not a custom ReactNode)\n const isPreset = anchor === 'dropzone' || anchor === 'button' || anchor === 'avatar';\n\n // Opens the native file picker\n function handleClick() {\n if (disabled) return;\n inputRef.current?.click();\n }\n\n // Forwards selected files to consumer and resets input\n function handleChange(event: React.ChangeEvent<HTMLInputElement>) {\n const fileList = event.target.files;\n if (!fileList || fileList.length === 0) return;\n\n if (multiple) {\n // Merge with existing files, avoiding duplicates by name+size\n const incoming = Array.from(fileList);\n const merged = [...files, ...incoming.filter((f) => !files.some((e) => e.name === f.name && e.size === f.size))];\n onChange?.(merged);\n } else {\n onChange?.(fileList[0]);\n }\n\n // Reset so the same file can be re-selected\n event.target.value = '';\n }\n\n // Removes a specific file from the selection\n function handleRemove(file: File) {\n if (multiple) {\n const remaining = files.filter((f) => f !== file);\n onChange?.(remaining.length ? remaining : undefined);\n } else {\n onChange?.(undefined);\n }\n }\n\n // Renders the clickable anchor element based on the anchor prop\n function renderAnchor() {\n // Custom ReactNode — preserve original headless behaviour\n if (!isPreset) {\n return (\n <button\n type=\"button\"\n onClick={handleClick}\n disabled={disabled}\n style={{ all: 'unset', display: 'inline-block', cursor: disabled ? 'default' : 'pointer' }}\n >\n {anchor as React.ReactNode}\n </button>\n );\n }\n\n if (anchor === 'dropzone') {\n // In single mode with a file selected, the file row replaces the dropzone\n if (!multiple && hasFiles) return null;\n\n return (\n <button\n type=\"button\"\n onClick={handleClick}\n disabled={disabled}\n className={cn(\n 'flex w-full flex-col items-center justify-center gap-2 rounded-lg border-2 border-dashed p-8 transition-colors',\n error ? 'border-destructive' : 'border-border',\n disabled ? 'cursor-default opacity-50' : 'cursor-pointer hover:bg-muted/50',\n )}\n >\n <Upload className=\"h-6 w-6 text-muted-foreground\" />\n <p className=\"text-sm text-muted-foreground\">{placeholder ?? 'Click or drag to upload'}</p>\n {hint && <p className=\"text-xs text-muted-foreground\">{hint}</p>}\n </button>\n );\n }\n\n if (anchor === 'button') {\n // In single mode with a file selected, the file row replaces the button\n if (!multiple && hasFiles) return null;\n\n return (\n <Button type=\"button\" variant=\"outline\" onClick={handleClick} disabled={disabled}>\n <Upload className=\"h-4 w-4\" />\n {placeholder ?? 'Upload file'}\n </Button>\n );\n }\n\n if (anchor === 'avatar') {\n const avatarSize = 80;\n const firstFile = files[0];\n const hasImage = hasFiles && firstFile.type.startsWith('image/');\n\n return (\n // Wrapper provides positioning context for the badge outside overflow-hidden\n <div className=\"relative inline-block\" style={{ width: avatarSize, height: avatarSize }}>\n <button\n type=\"button\"\n onClick={handleClick}\n disabled={disabled}\n className={cn(\n 'group relative h-full w-full overflow-hidden rounded-full bg-muted',\n disabled ? 'cursor-default opacity-50' : 'cursor-pointer',\n )}\n >\n {hasImage ? (\n <>\n <AvatarPreview file={firstFile} size={avatarSize} />\n {/* Camera overlay on hover */}\n <div className=\"absolute inset-0 flex items-center justify-center rounded-full bg-black/40 opacity-0 transition-opacity group-hover:opacity-100\">\n <Camera className=\"h-5 w-5 text-white\" />\n </div>\n </>\n ) : (\n <div className=\"flex h-full w-full items-center justify-center\">\n <User className=\"h-8 w-8 text-muted-foreground\" />\n </div>\n )}\n </button>\n\n {/* Badge sits outside overflow-hidden so it's never clipped */}\n {!hasImage && (\n <div className=\"pointer-events-none absolute -bottom-0.5 -right-0.5 flex h-6 w-6 items-center justify-center rounded-full bg-primary ring-2 ring-background\">\n <Upload className=\"h-3 w-3 text-primary-foreground\" />\n </div>\n )}\n </div>\n );\n }\n\n return null;\n }\n\n // Renders the file list below the anchor for preset anchors (not avatar)\n function renderFileList() {\n if (!isPreset || !hasFiles || anchor === 'avatar') return null;\n\n return (\n <div className=\"flex flex-col gap-2\">\n {files.map((file) => (\n <div\n key={`${file.name}-${file.size}`}\n className={cn(\n 'relative overflow-hidden flex items-center gap-3 rounded-lg border border-dashed p-3',\n isLoading ? 'border-primary/40 animate-pulse' : 'border-border',\n )}\n >\n {isLoading && <div className=\"absolute inset-0 bg-primary/5\" />}\n <div className=\"relative flex items-center gap-3 flex-1 min-w-0\">\n <FilePreview file={file} size={40} />\n <div className=\"flex-1 min-w-0\">\n <span className=\"block truncate text-sm\">{file.name}</span>\n {isLoading && <span className=\"text-xs text-muted-foreground\">Uploading...</span>}\n </div>\n {!isLoading && (\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-8 w-8 shrink-0\"\n onClick={() => handleRemove(file)}\n disabled={disabled}\n >\n <X className=\"h-4 w-4\" />\n </Button>\n )}\n </div>\n </div>\n ))}\n </div>\n );\n }\n\n return (\n <Field data-disabled={disabled}>\n {label && <FieldLabel>{label}</FieldLabel>}\n\n {renderAnchor()}\n {renderFileList()}\n\n <input\n ref={inputRef}\n type=\"file\"\n multiple={multiple}\n accept={accept}\n disabled={disabled}\n onChange={handleChange}\n style={{ display: 'none' }}\n aria-hidden=\"true\"\n tabIndex={-1}\n />\n\n {error && <FieldError>{error}</FieldError>}\n </Field>\n );\n};\n\nUploadFile.displayName = 'UploadFile';\n"],"names":[],"mappings":";;;;;;;;;;AAoCA,MAAM,aAAA,GAAwD,CAAC,EAAE,IAAA,EAAM,MAAK,KAAM;AAChF,EAAA,MAAM,CAAC,SAAA,EAAW,YAAY,CAAA,GAAI,SAAwB,IAAI,CAAA;AAE9D,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,MAAM,GAAA,GAAM,GAAA,CAAI,eAAA,CAAgB,IAAI,CAAA;AACpC,IAAA,YAAA,CAAa,GAAG,CAAA;AAChB,IAAA,OAAO,MAAM,GAAA,CAAI,eAAA,CAAgB,GAAG,CAAA;AAAA,EACtC,CAAA,EAAG,CAAC,IAAI,CAAC,CAAA;AAET,EAAA,IAAI,CAAC,WAAW,OAAO,IAAA;AAEvB,EAAA,uBACE,GAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,GAAA,EAAK,SAAA;AAAA,MACL,KAAK,IAAA,CAAK,IAAA;AAAA,MACV,SAAA,EAAU,yCAAA;AAAA,MACV,KAAA,EAAO,EAAE,KAAA,EAAO,IAAA,EAAM,QAAQ,IAAA;AAAK;AAAA,GACrC;AAEJ,CAAA;AAGO,MAAM,aAAwC,CAAC;AAAA,EACpD,MAAA,GAAS,UAAA;AAAA,EACT,QAAA,GAAW,KAAA;AAAA,EACX,MAAA;AAAA,EACA,QAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,WAAA;AAAA,EACA,IAAA;AAAA,EACA,KAAA;AAAA,EACA,QAAA;AAAA,EACA;AACF,CAAA,KAAM;AACJ,EAAA,MAAM,QAAA,GAAW,OAAyB,IAAI,CAAA;AAG9C,EAAA,MAAM,KAAA,GAAgB,CAAC,KAAA,GAAQ,EAAC,GAAI,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,GAAI,KAAA,GAAQ,CAAC,KAAK,CAAA;AACzE,EAAA,MAAM,QAAA,GAAW,MAAM,MAAA,GAAS,CAAA;AAGhC,EAAA,MAAM,QAAA,GAAW,MAAA,KAAW,UAAA,IAAc,MAAA,KAAW,YAAY,MAAA,KAAW,QAAA;AAG5E,EAAA,SAAS,WAAA,GAAc;AACrB,IAAA,IAAI,QAAA,EAAU;AACd,IAAA,QAAA,CAAS,SAAS,KAAA,EAAM;AAAA,EAC1B;AAGA,EAAA,SAAS,aAAa,KAAA,EAA4C;AAChE,IAAA,MAAM,QAAA,GAAW,MAAM,MAAA,CAAO,KAAA;AAC9B,IAAA,IAAI,CAAC,QAAA,IAAY,QAAA,CAAS,MAAA,KAAW,CAAA,EAAG;AAExC,IAAA,IAAI,QAAA,EAAU;AAEZ,MAAA,MAAM,QAAA,GAAW,KAAA,CAAM,IAAA,CAAK,QAAQ,CAAA;AACpC,MAAA,MAAM,MAAA,GAAS,CAAC,GAAG,KAAA,EAAO,GAAG,QAAA,CAAS,MAAA,CAAO,CAAC,CAAA,KAAM,CAAC,KAAA,CAAM,KAAK,CAAC,CAAA,KAAM,CAAA,CAAE,IAAA,KAAS,CAAA,CAAE,IAAA,IAAQ,EAAE,IAAA,KAAS,CAAA,CAAE,IAAI,CAAC,CAAC,CAAA;AAC/G,MAAA,QAAA,GAAW,MAAM,CAAA;AAAA,IACnB,CAAA,MAAO;AACL,MAAA,QAAA,GAAW,QAAA,CAAS,CAAC,CAAC,CAAA;AAAA,IACxB;AAGA,IAAA,KAAA,CAAM,OAAO,KAAA,GAAQ,EAAA;AAAA,EACvB;AAGA,EAAA,SAAS,aAAa,IAAA,EAAY;AAChC,IAAA,IAAI,QAAA,EAAU;AACZ,MAAA,MAAM,YAAY,KAAA,CAAM,MAAA,CAAO,CAAC,CAAA,KAAM,MAAM,IAAI,CAAA;AAChD,MAAA,QAAA,GAAW,SAAA,CAAU,MAAA,GAAS,SAAA,GAAY,MAAS,CAAA;AAAA,IACrD,CAAA,MAAO;AACL,MAAA,QAAA,GAAW,MAAS,CAAA;AAAA,IACtB;AAAA,EACF;AAGA,EAAA,SAAS,YAAA,GAAe;AAEtB,IAAA,IAAI,CAAC,QAAA,EAAU;AACb,MAAA,uBACE,GAAA;AAAA,QAAC,QAAA;AAAA,QAAA;AAAA,UACC,IAAA,EAAK,QAAA;AAAA,UACL,OAAA,EAAS,WAAA;AAAA,UACT,QAAA;AAAA,UACA,KAAA,EAAO,EAAE,GAAA,EAAK,OAAA,EAAS,SAAS,cAAA,EAAgB,MAAA,EAAQ,QAAA,GAAW,SAAA,GAAY,SAAA,EAAU;AAAA,UAExF,QAAA,EAAA;AAAA;AAAA,OACH;AAAA,IAEJ;AAEA,IAAA,IAAI,WAAW,UAAA,EAAY;AAEzB,MAAA,IAAI,CAAC,QAAA,IAAY,QAAA,EAAU,OAAO,IAAA;AAElC,MAAA,uBACE,IAAA;AAAA,QAAC,QAAA;AAAA,QAAA;AAAA,UACC,IAAA,EAAK,QAAA;AAAA,UACL,OAAA,EAAS,WAAA;AAAA,UACT,QAAA;AAAA,UACA,SAAA,EAAW,EAAA;AAAA,YACT,gHAAA;AAAA,YACA,QAAQ,oBAAA,GAAuB,eAAA;AAAA,YAC/B,WAAW,2BAAA,GAA8B;AAAA,WAC3C;AAAA,UAEA,QAAA,EAAA;AAAA,4BAAA,GAAA,CAAC,MAAA,EAAA,EAAO,WAAU,+BAAA,EAAgC,CAAA;AAAA,4BAClD,GAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,+BAAA,EAAiC,yBAAe,yBAAA,EAA0B,CAAA;AAAA,YACtF,IAAA,oBAAQ,GAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,iCAAiC,QAAA,EAAA,IAAA,EAAK;AAAA;AAAA;AAAA,OAC9D;AAAA,IAEJ;AAEA,IAAA,IAAI,WAAW,QAAA,EAAU;AAEvB,MAAA,IAAI,CAAC,QAAA,IAAY,QAAA,EAAU,OAAO,IAAA;AAElC,MAAA,uBACE,IAAA,CAAC,UAAO,IAAA,EAAK,QAAA,EAAS,SAAQ,SAAA,EAAU,OAAA,EAAS,aAAa,QAAA,EAC5D,QAAA,EAAA;AAAA,wBAAA,GAAA,CAAC,MAAA,EAAA,EAAO,WAAU,SAAA,EAAU,CAAA;AAAA,QAC3B,WAAA,IAAe;AAAA,OAAA,EAClB,CAAA;AAAA,IAEJ;AAEA,IAAA,IAAI,WAAW,QAAA,EAAU;AACvB,MAAA,MAAM,UAAA,GAAa,EAAA;AACnB,MAAA,MAAM,SAAA,GAAY,MAAM,CAAC,CAAA;AACzB,MAAA,MAAM,QAAA,GAAW,QAAA,IAAY,SAAA,CAAU,IAAA,CAAK,WAAW,QAAQ,CAAA;AAE/D,MAAA;AAAA;AAAA,wBAEE,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,uBAAA,EAAwB,KAAA,EAAO,EAAE,KAAA,EAAO,UAAA,EAAY,MAAA,EAAQ,UAAA,EAAW,EACpF,QAAA,EAAA;AAAA,0BAAA,GAAA;AAAA,YAAC,QAAA;AAAA,YAAA;AAAA,cACC,IAAA,EAAK,QAAA;AAAA,cACL,OAAA,EAAS,WAAA;AAAA,cACT,QAAA;AAAA,cACA,SAAA,EAAW,EAAA;AAAA,gBACT,oEAAA;AAAA,gBACA,WAAW,2BAAA,GAA8B;AAAA,eAC3C;AAAA,cAEC,qCACC,IAAA,CAAA,QAAA,EAAA,EACE,QAAA,EAAA;AAAA,gCAAA,GAAA,CAAC,aAAA,EAAA,EAAc,IAAA,EAAM,SAAA,EAAW,IAAA,EAAM,UAAA,EAAY,CAAA;AAAA,gCAElD,GAAA,CAAC,SAAI,SAAA,EAAU,iIAAA,EACb,8BAAC,MAAA,EAAA,EAAO,SAAA,EAAU,sBAAqB,CAAA,EACzC;AAAA,eAAA,EACF,CAAA,uBAEC,KAAA,EAAA,EAAI,SAAA,EAAU,kDACb,QAAA,kBAAA,GAAA,CAAC,IAAA,EAAA,EAAK,SAAA,EAAU,+BAAA,EAAgC,CAAA,EAClD;AAAA;AAAA,WAEJ;AAAA,UAGC,CAAC,QAAA,oBACA,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,+IACb,QAAA,kBAAA,GAAA,CAAC,MAAA,EAAA,EAAO,SAAA,EAAU,iCAAA,EAAkC,CAAA,EACtD;AAAA,SAAA,EAEJ;AAAA;AAAA,IAEJ;AAEA,IAAA,OAAO,IAAA;AAAA,EACT;AAGA,EAAA,SAAS,cAAA,GAAiB;AACxB,IAAA,IAAI,CAAC,QAAA,IAAY,CAAC,QAAA,IAAY,MAAA,KAAW,UAAU,OAAO,IAAA;AAE1D,IAAA,2BACG,KAAA,EAAA,EAAI,SAAA,EAAU,uBACZ,QAAA,EAAA,KAAA,CAAM,GAAA,CAAI,CAAC,IAAA,qBACV,IAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QAEC,SAAA,EAAW,EAAA;AAAA,UACT,sFAAA;AAAA,UACA,YAAY,iCAAA,GAAoC;AAAA,SAClD;AAAA,QAEC,QAAA,EAAA;AAAA,UAAA,SAAA,oBAAa,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,+BAAA,EAAgC,CAAA;AAAA,0BAC7D,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,iDAAA,EACb,QAAA,EAAA;AAAA,4BAAA,GAAA,CAAC,WAAA,EAAA,EAAY,IAAA,EAAY,IAAA,EAAM,EAAA,EAAI,CAAA;AAAA,4BACnC,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,gBAAA,EACb,QAAA,EAAA;AAAA,8BAAA,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,wBAAA,EAA0B,QAAA,EAAA,IAAA,CAAK,IAAA,EAAK,CAAA;AAAA,cACnD,SAAA,oBAAa,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,iCAAgC,QAAA,EAAA,cAAA,EAAY;AAAA,aAAA,EAC5E,CAAA;AAAA,YACC,CAAC,SAAA,oBACA,GAAA;AAAA,cAAC,MAAA;AAAA,cAAA;AAAA,gBACC,IAAA,EAAK,QAAA;AAAA,gBACL,OAAA,EAAQ,OAAA;AAAA,gBACR,IAAA,EAAK,MAAA;AAAA,gBACL,SAAA,EAAU,kBAAA;AAAA,gBACV,OAAA,EAAS,MAAM,YAAA,CAAa,IAAI,CAAA;AAAA,gBAChC,QAAA;AAAA,gBAEA,QAAA,kBAAA,GAAA,CAAC,CAAA,EAAA,EAAE,SAAA,EAAU,SAAA,EAAU;AAAA;AAAA;AACzB,WAAA,EAEJ;AAAA;AAAA,OAAA;AAAA,MAzBK,CAAA,EAAG,IAAA,CAAK,IAAI,CAAA,CAAA,EAAI,KAAK,IAAI,CAAA;AAAA,KA2BjC,CAAA,EACH,CAAA;AAAA,EAEJ;AAEA,EAAA,uBACE,IAAA,CAAC,KAAA,EAAA,EAAM,eAAA,EAAe,QAAA,EACnB,QAAA,EAAA;AAAA,IAAA,KAAA,oBAAS,GAAA,CAAC,cAAY,QAAA,EAAA,KAAA,EAAM,CAAA;AAAA,IAE5B,YAAA,EAAa;AAAA,IACb,cAAA,EAAe;AAAA,oBAEhB,GAAA;AAAA,MAAC,OAAA;AAAA,MAAA;AAAA,QACC,GAAA,EAAK,QAAA;AAAA,QACL,IAAA,EAAK,MAAA;AAAA,QACL,QAAA;AAAA,QACA,MAAA;AAAA,QACA,QAAA;AAAA,QACA,QAAA,EAAU,YAAA;AAAA,QACV,KAAA,EAAO,EAAE,OAAA,EAAS,MAAA,EAAO;AAAA,QACzB,aAAA,EAAY,MAAA;AAAA,QACZ,QAAA,EAAU;AAAA;AAAA,KACZ;AAAA,IAEC,KAAA,oBAAS,GAAA,CAAC,UAAA,EAAA,EAAY,QAAA,EAAA,KAAA,EAAM;AAAA,GAAA,EAC/B,CAAA;AAEJ;AAEA,UAAA,CAAW,WAAA,GAAc,YAAA;;;;"}
1
+ {"version":3,"file":"UploadFile.js","sources":["../lib/components/UploadFile/UploadFile.tsx"],"sourcesContent":["import { Camera, Upload, User, X } from 'lucide-react';\nimport type React from 'react';\nimport { useEffect, useMemo, useRef } from 'react';\nimport { cn } from '../../../shadcn/utils';\nimport { Button } from '../Button';\nimport { Field, FieldError, FieldLabel } from '../Field';\nimport { FilePreview } from '../FilePreview';\n\ntype AnchorPreset = 'dropzone' | 'button' | 'avatar';\n\ninterface UploadFileBaseProps {\n anchor?: AnchorPreset | React.ReactNode;\n multiple?: boolean;\n accept?: string;\n className?: string;\n disabled?: boolean;\n label?: string;\n error?: string;\n placeholder?: string;\n hint?: string;\n value?: File | File[] | null;\n /** URL of an already-persisted file (e.g. a saved avatar). Shown as the preview until a new file is picked. */\n previewUrl?: string;\n isLoading?: boolean;\n}\n\ninterface UploadFileStandaloneProps extends UploadFileBaseProps {\n name?: never;\n onChange: (files: File | File[] | undefined) => void;\n}\n\ninterface UploadFileFormProps extends UploadFileBaseProps {\n name: string;\n onChange?: (files: File | File[] | undefined) => void;\n}\n\nexport type UploadFileProps = UploadFileStandaloneProps | UploadFileFormProps;\n\n// Creates a revocable object URL for an image File; null for non-images or no file.\n// Built during render, not in an effect, so the preview never flashes a placeholder first.\nfunction useImageObjectUrl(file: File | undefined): string | null {\n const objectUrl = useMemo(() => (file?.type.startsWith('image/') ? URL.createObjectURL(file) : null), [file]);\n\n useEffect(() => {\n if (!objectUrl) return;\n return () => URL.revokeObjectURL(objectUrl);\n }, [objectUrl]);\n\n return objectUrl;\n}\n\n// File upload trigger with optional preset anchors and built-in file preview\nexport const UploadFile: React.FC<UploadFileProps> = ({\n anchor = 'dropzone',\n multiple = false,\n accept,\n className,\n disabled,\n label,\n error,\n placeholder,\n hint,\n value,\n previewUrl,\n onChange,\n isLoading,\n}) => {\n const inputRef = useRef<HTMLInputElement>(null);\n\n // Normalize value to an array for consistent handling\n const files: File[] = !value ? [] : Array.isArray(value) ? value : [value];\n const hasFiles = files.length > 0;\n\n const firstFile: File | undefined = files[0];\n const selectedImageUrl = useImageObjectUrl(firstFile);\n // A picked file always wins; previewUrl only fills in when nothing is selected, so\n // picking a non-image never falls back to the stale remote image\n const imageSrc = hasFiles ? selectedImageUrl : (previewUrl ?? null);\n\n // True when using a preset string anchor (not a custom ReactNode)\n const isPreset = anchor === 'dropzone' || anchor === 'button' || anchor === 'avatar';\n\n // Opens the native file picker\n function handleClick() {\n if (disabled) return;\n inputRef.current?.click();\n }\n\n // Forwards selected files to consumer and resets input\n function handleChange(event: React.ChangeEvent<HTMLInputElement>) {\n const fileList = event.target.files;\n if (!fileList || fileList.length === 0) return;\n\n if (multiple) {\n // Merge with existing files, avoiding duplicates by name+size\n const incoming = Array.from(fileList);\n const merged = [...files, ...incoming.filter((f) => !files.some((e) => e.name === f.name && e.size === f.size))];\n onChange?.(merged);\n } else {\n onChange?.(fileList[0]);\n }\n\n // Reset so the same file can be re-selected\n event.target.value = '';\n }\n\n // Removes a specific file from the selection\n function handleRemove(file: File) {\n if (multiple) {\n const remaining = files.filter((f) => f !== file);\n onChange?.(remaining.length ? remaining : undefined);\n } else {\n onChange?.(undefined);\n }\n }\n\n // Renders the clickable anchor element based on the anchor prop\n function renderAnchor() {\n // Custom ReactNode — preserve original headless behaviour\n if (!isPreset) {\n return (\n <button\n type=\"button\"\n onClick={handleClick}\n disabled={disabled}\n style={{ all: 'unset', display: 'inline-block', cursor: disabled ? 'default' : 'pointer' }}\n >\n {anchor as React.ReactNode}\n </button>\n );\n }\n\n if (anchor === 'dropzone') {\n // In single mode with a file selected, the file row replaces the dropzone\n if (!multiple && hasFiles) return null;\n\n return (\n <button\n type=\"button\"\n onClick={handleClick}\n disabled={disabled}\n className={cn(\n 'flex w-full flex-col items-center justify-center gap-2 rounded-lg border-2 border-dashed p-8 transition-colors',\n error ? 'border-destructive' : 'border-border',\n disabled ? 'cursor-default opacity-50' : 'cursor-pointer hover:bg-muted/50',\n )}\n >\n {imageSrc ? (\n <img src={imageSrc} alt=\"\" className=\"h-16 w-16 rounded object-cover\" />\n ) : (\n <Upload className=\"h-6 w-6 text-muted-foreground\" />\n )}\n <p className=\"text-sm text-muted-foreground\">{placeholder ?? 'Click or drag to upload'}</p>\n {hint && <p className=\"text-xs text-muted-foreground\">{hint}</p>}\n </button>\n );\n }\n\n if (anchor === 'button') {\n // In single mode with a file selected, the file row replaces the button\n if (!multiple && hasFiles) return null;\n\n return (\n <Button type=\"button\" variant=\"outline\" onClick={handleClick} disabled={disabled}>\n <Upload className=\"h-4 w-4\" />\n {placeholder ?? 'Upload file'}\n </Button>\n );\n }\n\n if (anchor === 'avatar') {\n const avatarSize = 80;\n\n return (\n // Wrapper provides positioning context for the badge outside overflow-hidden\n <div className=\"relative inline-block\" style={{ width: avatarSize, height: avatarSize }}>\n <button\n type=\"button\"\n onClick={handleClick}\n disabled={disabled}\n className={cn(\n 'group relative h-full w-full overflow-hidden rounded-full bg-muted',\n disabled ? 'cursor-default' : 'cursor-pointer',\n // A shown image is content, not an affordance — only dim the empty placeholder\n disabled && !imageSrc && 'opacity-50',\n )}\n >\n {imageSrc ? (\n <>\n <img\n src={imageSrc}\n alt={firstFile?.name ?? ''}\n className=\"rounded-full object-cover w-full h-full\"\n style={{ width: avatarSize, height: avatarSize }}\n />\n {/* Camera overlay on hover — omitted when read-only, since nothing can be picked */}\n {!disabled && (\n <div className=\"absolute inset-0 flex items-center justify-center rounded-full bg-black/40 opacity-0 transition-opacity group-hover:opacity-100\">\n <Camera className=\"h-5 w-5 text-white\" />\n </div>\n )}\n </>\n ) : (\n <div className=\"flex h-full w-full items-center justify-center\">\n <User className=\"h-8 w-8 text-muted-foreground\" />\n </div>\n )}\n </button>\n\n {/* Badge sits outside overflow-hidden so it's never clipped */}\n {!imageSrc && (\n <div className=\"pointer-events-none absolute -bottom-0.5 -right-0.5 flex h-6 w-6 items-center justify-center rounded-full bg-primary ring-2 ring-background\">\n <Upload className=\"h-3 w-3 text-primary-foreground\" />\n </div>\n )}\n </div>\n );\n }\n\n return null;\n }\n\n // Renders the file list below the anchor for preset anchors (not avatar)\n function renderFileList() {\n if (!isPreset || !hasFiles || anchor === 'avatar') return null;\n\n return (\n <div className=\"flex flex-col gap-2\">\n {files.map((file) => (\n <div\n key={`${file.name}-${file.size}`}\n className={cn(\n 'relative overflow-hidden flex items-center gap-3 rounded-lg border border-dashed p-3',\n isLoading ? 'border-primary/40 animate-pulse' : 'border-border',\n )}\n >\n {isLoading && <div className=\"absolute inset-0 bg-primary/5\" />}\n <div className=\"relative flex items-center gap-3 flex-1 min-w-0\">\n <FilePreview file={file} size={40} />\n <div className=\"flex-1 min-w-0\">\n <span className=\"block truncate text-sm\">{file.name}</span>\n {isLoading && <span className=\"text-xs text-muted-foreground\">Uploading...</span>}\n </div>\n {!isLoading && (\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-8 w-8 shrink-0\"\n onClick={() => handleRemove(file)}\n disabled={disabled}\n >\n <X className=\"h-4 w-4\" />\n </Button>\n )}\n </div>\n </div>\n ))}\n </div>\n );\n }\n\n return (\n // Field is w-full by default; the avatar is a fixed 80px circle, so it hugs its content\n // instead of claiming the whole row and pushing sibling content to the far edge\n <Field data-disabled={disabled} className={cn(anchor === 'avatar' && 'w-fit', className)}>\n {label && <FieldLabel>{label}</FieldLabel>}\n\n {renderAnchor()}\n {renderFileList()}\n\n <input\n ref={inputRef}\n type=\"file\"\n multiple={multiple}\n accept={accept}\n disabled={disabled}\n onChange={handleChange}\n style={{ display: 'none' }}\n aria-hidden=\"true\"\n tabIndex={-1}\n />\n\n {error && <FieldError>{error}</FieldError>}\n </Field>\n );\n};\n\nUploadFile.displayName = 'UploadFile';\n"],"names":[],"mappings":";;;;;;;;;;AAwCA,SAAS,kBAAkB,IAAA,EAAuC;AAChE,EAAA,MAAM,SAAA,GAAY,OAAA,CAAQ,MAAO,IAAA,EAAM,KAAK,UAAA,CAAW,QAAQ,CAAA,GAAI,GAAA,CAAI,gBAAgB,IAAI,CAAA,GAAI,IAAA,EAAO,CAAC,IAAI,CAAC,CAAA;AAE5G,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,SAAA,EAAW;AAChB,IAAA,OAAO,MAAM,GAAA,CAAI,eAAA,CAAgB,SAAS,CAAA;AAAA,EAC5C,CAAA,EAAG,CAAC,SAAS,CAAC,CAAA;AAEd,EAAA,OAAO,SAAA;AACT;AAGO,MAAM,aAAwC,CAAC;AAAA,EACpD,MAAA,GAAS,UAAA;AAAA,EACT,QAAA,GAAW,KAAA;AAAA,EACX,MAAA;AAAA,EACA,SAAA;AAAA,EACA,QAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,WAAA;AAAA,EACA,IAAA;AAAA,EACA,KAAA;AAAA,EACA,UAAA;AAAA,EACA,QAAA;AAAA,EACA;AACF,CAAA,KAAM;AACJ,EAAA,MAAM,QAAA,GAAW,OAAyB,IAAI,CAAA;AAG9C,EAAA,MAAM,KAAA,GAAgB,CAAC,KAAA,GAAQ,EAAC,GAAI,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,GAAI,KAAA,GAAQ,CAAC,KAAK,CAAA;AACzE,EAAA,MAAM,QAAA,GAAW,MAAM,MAAA,GAAS,CAAA;AAEhC,EAAA,MAAM,SAAA,GAA8B,MAAM,CAAC,CAAA;AAC3C,EAAA,MAAM,gBAAA,GAAmB,kBAAkB,SAAS,CAAA;AAGpD,EAAA,MAAM,QAAA,GAAW,QAAA,GAAW,gBAAA,GAAoB,UAAA,IAAc,IAAA;AAG9D,EAAA,MAAM,QAAA,GAAW,MAAA,KAAW,UAAA,IAAc,MAAA,KAAW,YAAY,MAAA,KAAW,QAAA;AAG5E,EAAA,SAAS,WAAA,GAAc;AACrB,IAAA,IAAI,QAAA,EAAU;AACd,IAAA,QAAA,CAAS,SAAS,KAAA,EAAM;AAAA,EAC1B;AAGA,EAAA,SAAS,aAAa,KAAA,EAA4C;AAChE,IAAA,MAAM,QAAA,GAAW,MAAM,MAAA,CAAO,KAAA;AAC9B,IAAA,IAAI,CAAC,QAAA,IAAY,QAAA,CAAS,MAAA,KAAW,CAAA,EAAG;AAExC,IAAA,IAAI,QAAA,EAAU;AAEZ,MAAA,MAAM,QAAA,GAAW,KAAA,CAAM,IAAA,CAAK,QAAQ,CAAA;AACpC,MAAA,MAAM,MAAA,GAAS,CAAC,GAAG,KAAA,EAAO,GAAG,QAAA,CAAS,MAAA,CAAO,CAAC,CAAA,KAAM,CAAC,KAAA,CAAM,KAAK,CAAC,CAAA,KAAM,CAAA,CAAE,IAAA,KAAS,CAAA,CAAE,IAAA,IAAQ,EAAE,IAAA,KAAS,CAAA,CAAE,IAAI,CAAC,CAAC,CAAA;AAC/G,MAAA,QAAA,GAAW,MAAM,CAAA;AAAA,IACnB,CAAA,MAAO;AACL,MAAA,QAAA,GAAW,QAAA,CAAS,CAAC,CAAC,CAAA;AAAA,IACxB;AAGA,IAAA,KAAA,CAAM,OAAO,KAAA,GAAQ,EAAA;AAAA,EACvB;AAGA,EAAA,SAAS,aAAa,IAAA,EAAY;AAChC,IAAA,IAAI,QAAA,EAAU;AACZ,MAAA,MAAM,YAAY,KAAA,CAAM,MAAA,CAAO,CAAC,CAAA,KAAM,MAAM,IAAI,CAAA;AAChD,MAAA,QAAA,GAAW,SAAA,CAAU,MAAA,GAAS,SAAA,GAAY,MAAS,CAAA;AAAA,IACrD,CAAA,MAAO;AACL,MAAA,QAAA,GAAW,MAAS,CAAA;AAAA,IACtB;AAAA,EACF;AAGA,EAAA,SAAS,YAAA,GAAe;AAEtB,IAAA,IAAI,CAAC,QAAA,EAAU;AACb,MAAA,uBACE,GAAA;AAAA,QAAC,QAAA;AAAA,QAAA;AAAA,UACC,IAAA,EAAK,QAAA;AAAA,UACL,OAAA,EAAS,WAAA;AAAA,UACT,QAAA;AAAA,UACA,KAAA,EAAO,EAAE,GAAA,EAAK,OAAA,EAAS,SAAS,cAAA,EAAgB,MAAA,EAAQ,QAAA,GAAW,SAAA,GAAY,SAAA,EAAU;AAAA,UAExF,QAAA,EAAA;AAAA;AAAA,OACH;AAAA,IAEJ;AAEA,IAAA,IAAI,WAAW,UAAA,EAAY;AAEzB,MAAA,IAAI,CAAC,QAAA,IAAY,QAAA,EAAU,OAAO,IAAA;AAElC,MAAA,uBACE,IAAA;AAAA,QAAC,QAAA;AAAA,QAAA;AAAA,UACC,IAAA,EAAK,QAAA;AAAA,UACL,OAAA,EAAS,WAAA;AAAA,UACT,QAAA;AAAA,UACA,SAAA,EAAW,EAAA;AAAA,YACT,gHAAA;AAAA,YACA,QAAQ,oBAAA,GAAuB,eAAA;AAAA,YAC/B,WAAW,2BAAA,GAA8B;AAAA,WAC3C;AAAA,UAEC,QAAA,EAAA;AAAA,YAAA,QAAA,mBACC,GAAA,CAAC,KAAA,EAAA,EAAI,GAAA,EAAK,QAAA,EAAU,GAAA,EAAI,EAAA,EAAG,SAAA,EAAU,gCAAA,EAAiC,CAAA,mBAEtE,GAAA,CAAC,MAAA,EAAA,EAAO,SAAA,EAAU,+BAAA,EAAgC,CAAA;AAAA,4BAEpD,GAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,+BAAA,EAAiC,yBAAe,yBAAA,EAA0B,CAAA;AAAA,YACtF,IAAA,oBAAQ,GAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,iCAAiC,QAAA,EAAA,IAAA,EAAK;AAAA;AAAA;AAAA,OAC9D;AAAA,IAEJ;AAEA,IAAA,IAAI,WAAW,QAAA,EAAU;AAEvB,MAAA,IAAI,CAAC,QAAA,IAAY,QAAA,EAAU,OAAO,IAAA;AAElC,MAAA,uBACE,IAAA,CAAC,UAAO,IAAA,EAAK,QAAA,EAAS,SAAQ,SAAA,EAAU,OAAA,EAAS,aAAa,QAAA,EAC5D,QAAA,EAAA;AAAA,wBAAA,GAAA,CAAC,MAAA,EAAA,EAAO,WAAU,SAAA,EAAU,CAAA;AAAA,QAC3B,WAAA,IAAe;AAAA,OAAA,EAClB,CAAA;AAAA,IAEJ;AAEA,IAAA,IAAI,WAAW,QAAA,EAAU;AACvB,MAAA,MAAM,UAAA,GAAa,EAAA;AAEnB,MAAA;AAAA;AAAA,wBAEE,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,uBAAA,EAAwB,KAAA,EAAO,EAAE,KAAA,EAAO,UAAA,EAAY,MAAA,EAAQ,UAAA,EAAW,EACpF,QAAA,EAAA;AAAA,0BAAA,GAAA;AAAA,YAAC,QAAA;AAAA,YAAA;AAAA,cACC,IAAA,EAAK,QAAA;AAAA,cACL,OAAA,EAAS,WAAA;AAAA,cACT,QAAA;AAAA,cACA,SAAA,EAAW,EAAA;AAAA,gBACT,oEAAA;AAAA,gBACA,WAAW,gBAAA,GAAmB,gBAAA;AAAA;AAAA,gBAE9B,QAAA,IAAY,CAAC,QAAA,IAAY;AAAA,eAC3B;AAAA,cAEC,qCACC,IAAA,CAAA,QAAA,EAAA,EACE,QAAA,EAAA;AAAA,gCAAA,GAAA;AAAA,kBAAC,KAAA;AAAA,kBAAA;AAAA,oBACC,GAAA,EAAK,QAAA;AAAA,oBACL,GAAA,EAAK,WAAW,IAAA,IAAQ,EAAA;AAAA,oBACxB,SAAA,EAAU,yCAAA;AAAA,oBACV,KAAA,EAAO,EAAE,KAAA,EAAO,UAAA,EAAY,QAAQ,UAAA;AAAW;AAAA,iBACjD;AAAA,gBAEC,CAAC,QAAA,oBACA,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,mIACb,QAAA,kBAAA,GAAA,CAAC,MAAA,EAAA,EAAO,SAAA,EAAU,oBAAA,EAAqB,CAAA,EACzC;AAAA,eAAA,EAEJ,CAAA,uBAEC,KAAA,EAAA,EAAI,SAAA,EAAU,kDACb,QAAA,kBAAA,GAAA,CAAC,IAAA,EAAA,EAAK,SAAA,EAAU,+BAAA,EAAgC,CAAA,EAClD;AAAA;AAAA,WAEJ;AAAA,UAGC,CAAC,QAAA,oBACA,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,+IACb,QAAA,kBAAA,GAAA,CAAC,MAAA,EAAA,EAAO,SAAA,EAAU,iCAAA,EAAkC,CAAA,EACtD;AAAA,SAAA,EAEJ;AAAA;AAAA,IAEJ;AAEA,IAAA,OAAO,IAAA;AAAA,EACT;AAGA,EAAA,SAAS,cAAA,GAAiB;AACxB,IAAA,IAAI,CAAC,QAAA,IAAY,CAAC,QAAA,IAAY,MAAA,KAAW,UAAU,OAAO,IAAA;AAE1D,IAAA,2BACG,KAAA,EAAA,EAAI,SAAA,EAAU,uBACZ,QAAA,EAAA,KAAA,CAAM,GAAA,CAAI,CAAC,IAAA,qBACV,IAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QAEC,SAAA,EAAW,EAAA;AAAA,UACT,sFAAA;AAAA,UACA,YAAY,iCAAA,GAAoC;AAAA,SAClD;AAAA,QAEC,QAAA,EAAA;AAAA,UAAA,SAAA,oBAAa,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,+BAAA,EAAgC,CAAA;AAAA,0BAC7D,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,iDAAA,EACb,QAAA,EAAA;AAAA,4BAAA,GAAA,CAAC,WAAA,EAAA,EAAY,IAAA,EAAY,IAAA,EAAM,EAAA,EAAI,CAAA;AAAA,4BACnC,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,gBAAA,EACb,QAAA,EAAA;AAAA,8BAAA,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,wBAAA,EAA0B,QAAA,EAAA,IAAA,CAAK,IAAA,EAAK,CAAA;AAAA,cACnD,SAAA,oBAAa,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,iCAAgC,QAAA,EAAA,cAAA,EAAY;AAAA,aAAA,EAC5E,CAAA;AAAA,YACC,CAAC,SAAA,oBACA,GAAA;AAAA,cAAC,MAAA;AAAA,cAAA;AAAA,gBACC,IAAA,EAAK,QAAA;AAAA,gBACL,OAAA,EAAQ,OAAA;AAAA,gBACR,IAAA,EAAK,MAAA;AAAA,gBACL,SAAA,EAAU,kBAAA;AAAA,gBACV,OAAA,EAAS,MAAM,YAAA,CAAa,IAAI,CAAA;AAAA,gBAChC,QAAA;AAAA,gBAEA,QAAA,kBAAA,GAAA,CAAC,CAAA,EAAA,EAAE,SAAA,EAAU,SAAA,EAAU;AAAA;AAAA;AACzB,WAAA,EAEJ;AAAA;AAAA,OAAA;AAAA,MAzBK,CAAA,EAAG,IAAA,CAAK,IAAI,CAAA,CAAA,EAAI,KAAK,IAAI,CAAA;AAAA,KA2BjC,CAAA,EACH,CAAA;AAAA,EAEJ;AAEA,EAAA;AAAA;AAAA;AAAA,oBAGE,IAAA,CAAC,KAAA,EAAA,EAAM,eAAA,EAAe,QAAA,EAAU,SAAA,EAAW,GAAG,MAAA,KAAW,QAAA,IAAY,OAAA,EAAS,SAAS,CAAA,EACpF,QAAA,EAAA;AAAA,MAAA,KAAA,oBAAS,GAAA,CAAC,cAAY,QAAA,EAAA,KAAA,EAAM,CAAA;AAAA,MAE5B,YAAA,EAAa;AAAA,MACb,cAAA,EAAe;AAAA,sBAEhB,GAAA;AAAA,QAAC,OAAA;AAAA,QAAA;AAAA,UACC,GAAA,EAAK,QAAA;AAAA,UACL,IAAA,EAAK,MAAA;AAAA,UACL,QAAA;AAAA,UACA,MAAA;AAAA,UACA,QAAA;AAAA,UACA,QAAA,EAAU,YAAA;AAAA,UACV,KAAA,EAAO,EAAE,OAAA,EAAS,MAAA,EAAO;AAAA,UACzB,aAAA,EAAY,MAAA;AAAA,UACZ,QAAA,EAAU;AAAA;AAAA,OACZ;AAAA,MAEC,KAAA,oBAAS,GAAA,CAAC,UAAA,EAAA,EAAY,QAAA,EAAA,KAAA,EAAM;AAAA,KAAA,EAC/B;AAAA;AAEJ;AAEA,UAAA,CAAW,WAAA,GAAc,YAAA;;;;"}
@@ -967,7 +967,7 @@ svg.react-flow__connectionline {
967
967
  --font-sans: "IBM Plex Sans", sans-serif;
968
968
  --font-serif: "Playfair Display", serif;
969
969
  --font-mono: "JetBrains Mono", monospace;
970
- --radius: 0.75rem;
970
+ --radius: 0.625rem;
971
971
  --shadow-x: 0rem;
972
972
  --shadow-y: 0.5rem;
973
973
  --shadow-blur: 1rem;
@@ -1043,7 +1043,7 @@ svg.react-flow__connectionline {
1043
1043
  --font-sans: "IBM Plex Sans", sans-serif;
1044
1044
  --font-serif: "Playfair Display", serif;
1045
1045
  --font-mono: "JetBrains Mono", monospace;
1046
- --radius: 0.75rem;
1046
+ --radius: 0.625rem;
1047
1047
  --shadow-x: 0rem;
1048
1048
  --shadow-y: 0.5rem;
1049
1049
  --shadow-blur: 1.25rem;
@@ -4704,10 +4704,6 @@ select:-webkit-autofill:active {
4704
4704
  -moz-appearance: textfield;
4705
4705
  }
4706
4706
 
4707
- .\[scrollbar-gutter\:stable\] {
4708
- scrollbar-gutter: stable;
4709
- }
4710
-
4711
4707
  .\[text-decoration\:underline_line-through\] {
4712
4708
  text-decoration: underline line-through;
4713
4709
  }
@@ -5296,8 +5292,8 @@ select:-webkit-autofill:active {
5296
5292
  padding-top: calc(var(--spacing) * 0);
5297
5293
  }
5298
5294
 
5299
- .last\:mt-0:last-child {
5300
- margin-top: calc(var(--spacing) * 0);
5295
+ .last\:-mt-1:last-child {
5296
+ margin-top: calc(var(--spacing) * -1);
5301
5297
  }
5302
5298
 
5303
5299
  .last\:mb-0:last-child {
@@ -0,0 +1,2 @@
1
+ export { C as CopyButton } from '../CopyButton.js';
2
+ //# sourceMappingURL=CopyButton.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CopyButton.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}
package/dist/field.js CHANGED
@@ -127,8 +127,8 @@ function FieldDescription({ className, ...props }) {
127
127
  {
128
128
  "data-slot": "field-description",
129
129
  className: cn(
130
- "text-muted-foreground text-sm leading-normal font-normal group-has-[[data-orientation=horizontal]]/field:text-balance",
131
- "last:mt-0 nth-last-2:-mt-1 [[data-variant=legend]+&]:-mt-1.5",
130
+ "text-muted-foreground text-xs leading-normal font-normal group-has-[[data-orientation=horizontal]]/field:text-balance",
131
+ "last:-mt-1 nth-last-2:-mt-1 [[data-variant=legend]+&]:-mt-1.5",
132
132
  "[&>a:hover]:text-primary [&>a]:underline [&>a]:underline-offset-4",
133
133
  className
134
134
  ),