@lerianstudio/sindarian-ui 1.4.0-beta.8 → 2.0.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/card/account-card/index.d.ts.map +1 -1
- package/dist/components/card/account-card/index.js +1 -1
- package/dist/components/card/entity-card/index.js +3 -3
- package/dist/components/dialog/confirmation-dialog/index.d.ts +36 -5
- package/dist/components/dialog/confirmation-dialog/index.d.ts.map +1 -1
- package/dist/components/dialog/confirmation-dialog/index.js +2 -2
- package/dist/components/entity-box/index.js +1 -1
- package/dist/components/entity-data-table/index.d.ts.map +1 -1
- package/dist/components/entity-data-table/index.js +1 -1
- package/dist/components/form/file-upload-field/index.d.ts +11 -2
- package/dist/components/form/file-upload-field/index.d.ts.map +1 -1
- package/dist/components/form/file-upload-field/index.js +8 -3
- package/dist/components/form/input-field/index.d.ts +41 -2
- package/dist/components/form/input-field/index.d.ts.map +1 -1
- package/dist/components/form/input-field/index.js +73 -15
- package/dist/components/form/select-field/index.d.ts +9 -1
- package/dist/components/form/select-field/index.d.ts.map +1 -1
- package/dist/components/form/select-field/index.js +2 -2
- package/dist/components/page-header/index.d.ts.map +1 -1
- package/dist/components/page-header/index.js +2 -2
- package/dist/components/ui/autocomplete/index.d.ts +34 -6
- package/dist/components/ui/autocomplete/index.d.ts.map +1 -1
- package/dist/components/ui/autocomplete/index.js +72 -16
- package/dist/components/ui/badge/index.d.ts.map +1 -1
- package/dist/components/ui/badge/index.js +11 -1
- package/dist/components/ui/button/styles.css +31 -1
- package/dist/components/ui/calendar/index.d.ts.map +1 -1
- package/dist/components/ui/calendar/index.js +7 -1
- package/dist/components/ui/card/index.d.ts.map +1 -1
- package/dist/components/ui/card/index.js +1 -1
- package/dist/components/ui/dropdown-menu/index.d.ts.map +1 -1
- package/dist/components/ui/dropdown-menu/index.js +4 -1
- package/dist/components/ui/field/index.d.ts.map +1 -1
- package/dist/components/ui/field/index.js +5 -2
- package/dist/components/ui/file-upload/index.d.ts +76 -9
- package/dist/components/ui/file-upload/index.d.ts.map +1 -1
- package/dist/components/ui/file-upload/index.js +47 -12
- package/dist/components/ui/form.d.ts +4 -0
- package/dist/components/ui/form.d.ts.map +1 -1
- package/dist/components/ui/form.js +53 -8
- package/dist/components/ui/multiple-select/index.js +2 -2
- package/dist/components/ui/progress/index.d.ts +15 -1
- package/dist/components/ui/progress/index.d.ts.map +1 -1
- package/dist/components/ui/progress/index.js +25 -2
- package/dist/components/ui/sidebar/sidebar-expand-button.d.ts.map +1 -1
- package/dist/components/ui/sidebar/sidebar-expand-button.js +17 -1
- package/dist/components/ui/toggle-group/index.d.ts +1 -1
- package/dist/components/ui/toggle-group/index.d.ts.map +1 -1
- package/dist/components/ui/toggle-group/index.js +73 -4
- package/dist/components/ui/tooltip/index.d.ts +15 -0
- package/dist/components/ui/tooltip/index.d.ts.map +1 -1
- package/dist/components/ui/tooltip/index.js +16 -1
- package/dist/domain/blotter/index.d.ts +4 -2
- package/dist/domain/blotter/index.d.ts.map +1 -1
- package/dist/domain/delinquency-aging/aging-buckets.d.ts.map +1 -1
- package/dist/domain/delinquency-aging/aging-buckets.js +8 -3
- package/dist/domain/delinquency-aging/index.d.ts.map +1 -1
- package/dist/domain/delinquency-aging/index.js +8 -3
- package/dist/domain/key-id/index.js +1 -1
- package/dist/domain/status-rail/index.js +1 -1
- package/dist/domain/threshold-gauge/index.d.ts.map +1 -1
- package/dist/domain/threshold-gauge/index.js +9 -5
- package/dist/enterprise/stat-card/index.d.ts.map +1 -1
- package/dist/enterprise/stat-card/index.js +12 -4
- package/dist/esm/components/card/account-card/index.d.ts.map +1 -1
- package/dist/esm/components/card/account-card/index.js +1 -1
- package/dist/esm/components/card/entity-card/index.js +3 -3
- package/dist/esm/components/dialog/confirmation-dialog/index.d.ts +36 -5
- package/dist/esm/components/dialog/confirmation-dialog/index.d.ts.map +1 -1
- package/dist/esm/components/dialog/confirmation-dialog/index.js +2 -2
- package/dist/esm/components/entity-box/index.js +1 -1
- package/dist/esm/components/entity-data-table/index.d.ts.map +1 -1
- package/dist/esm/components/entity-data-table/index.js +1 -1
- package/dist/esm/components/form/file-upload-field/index.d.ts +11 -2
- package/dist/esm/components/form/file-upload-field/index.d.ts.map +1 -1
- package/dist/esm/components/form/file-upload-field/index.js +8 -3
- package/dist/esm/components/form/input-field/index.d.ts +41 -2
- package/dist/esm/components/form/input-field/index.d.ts.map +1 -1
- package/dist/esm/components/form/input-field/index.js +73 -15
- package/dist/esm/components/form/select-field/index.d.ts +9 -1
- package/dist/esm/components/form/select-field/index.d.ts.map +1 -1
- package/dist/esm/components/form/select-field/index.js +2 -2
- package/dist/esm/components/page-header/index.d.ts.map +1 -1
- package/dist/esm/components/page-header/index.js +2 -2
- package/dist/esm/components/ui/autocomplete/index.d.ts +34 -6
- package/dist/esm/components/ui/autocomplete/index.d.ts.map +1 -1
- package/dist/esm/components/ui/autocomplete/index.js +72 -16
- package/dist/esm/components/ui/badge/index.d.ts.map +1 -1
- package/dist/esm/components/ui/badge/index.js +11 -1
- package/dist/esm/components/ui/calendar/index.d.ts.map +1 -1
- package/dist/esm/components/ui/calendar/index.js +8 -2
- package/dist/esm/components/ui/card/index.d.ts.map +1 -1
- package/dist/esm/components/ui/card/index.js +1 -1
- package/dist/esm/components/ui/dropdown-menu/index.d.ts.map +1 -1
- package/dist/esm/components/ui/dropdown-menu/index.js +4 -1
- package/dist/esm/components/ui/field/index.d.ts.map +1 -1
- package/dist/esm/components/ui/field/index.js +5 -2
- package/dist/esm/components/ui/file-upload/index.d.ts +76 -9
- package/dist/esm/components/ui/file-upload/index.d.ts.map +1 -1
- package/dist/esm/components/ui/file-upload/index.js +47 -13
- package/dist/esm/components/ui/form.d.ts +4 -0
- package/dist/esm/components/ui/form.d.ts.map +1 -1
- package/dist/esm/components/ui/form.js +53 -8
- package/dist/esm/components/ui/multiple-select/index.js +2 -2
- package/dist/esm/components/ui/progress/index.d.ts +15 -1
- package/dist/esm/components/ui/progress/index.d.ts.map +1 -1
- package/dist/esm/components/ui/progress/index.js +25 -2
- package/dist/esm/components/ui/sidebar/sidebar-expand-button.d.ts.map +1 -1
- package/dist/esm/components/ui/sidebar/sidebar-expand-button.js +17 -1
- package/dist/esm/components/ui/toggle-group/index.d.ts +1 -1
- package/dist/esm/components/ui/toggle-group/index.d.ts.map +1 -1
- package/dist/esm/components/ui/toggle-group/index.js +73 -4
- package/dist/esm/components/ui/tooltip/index.d.ts +15 -0
- package/dist/esm/components/ui/tooltip/index.d.ts.map +1 -1
- package/dist/esm/components/ui/tooltip/index.js +16 -1
- package/dist/esm/domain/blotter/index.d.ts +4 -2
- package/dist/esm/domain/blotter/index.d.ts.map +1 -1
- package/dist/esm/domain/delinquency-aging/aging-buckets.d.ts.map +1 -1
- package/dist/esm/domain/delinquency-aging/aging-buckets.js +8 -3
- package/dist/esm/domain/delinquency-aging/index.d.ts.map +1 -1
- package/dist/esm/domain/delinquency-aging/index.js +8 -3
- package/dist/esm/domain/key-id/index.js +1 -1
- package/dist/esm/domain/status-rail/index.js +1 -1
- package/dist/esm/domain/threshold-gauge/index.d.ts.map +1 -1
- package/dist/esm/domain/threshold-gauge/index.js +9 -5
- package/dist/esm/enterprise/stat-card/index.d.ts.map +1 -1
- package/dist/esm/enterprise/stat-card/index.js +12 -4
- package/dist/globals.css +24 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/ui/autocomplete/index.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,OAAO,CAAA;AAMzB,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAmB,MAAM,MAAM,CAAA;AAInE,MAAM,MAAM,uBAAuB,GACjC,KAAK,CAAC,kBAAkB,CAAC,gBAAgB,CAAC,GAAG;IAC3C,sCAAsC;IACtC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,EAAE,CAAA;IAC7B,aAAa,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAAA;IACzC,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAElB,6BAA6B;IAC7B,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,YAAY,EAAE,CAAC,KAAK,CAAC,EAAE,MAAM,KAAK,IAAI,CAAA;IACtC,WAAW,EAAE,MAAM,IAAI,CAAA;IACvB,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,cAAc,EAAE,CAAC,WAAW,EAAE,OAAO,KAAK,IAAI,CAAA;IAC9C,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,OAAO,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IAChC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC/B,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,IAAI,CAAA;IAEnD,2BAA2B;IAC3B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAA;CACnD,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/ui/autocomplete/index.tsx"],"names":[],"mappings":"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"}
|
|
@@ -27,12 +27,31 @@ const useAutocomplete = () => {
|
|
|
27
27
|
}
|
|
28
28
|
return context;
|
|
29
29
|
};
|
|
30
|
-
|
|
30
|
+
/**
|
|
31
|
+
* The text a value reads as.
|
|
32
|
+
*
|
|
33
|
+
* An item registers a label only when it HAS one to give: a string child, or an
|
|
34
|
+
* explicit `label` when its children are markup. Everything downstream renders
|
|
35
|
+
* this map as text (the input's value, a chip's `aria-label`), so a value with
|
|
36
|
+
* no registered label falls back to the value itself. The alternatives are both
|
|
37
|
+
* defects that shipped: `undefined` drops a controlled input to uncontrolled,
|
|
38
|
+
* and a React element interpolates into a template literal as "[object
|
|
39
|
+
* Object]".
|
|
40
|
+
*/
|
|
41
|
+
function labelOf(options, value) {
|
|
42
|
+
return options[value] ?? value;
|
|
43
|
+
}
|
|
44
|
+
export function AutocompleteTrigger({ ref, className, onClear, clearLabel = 'Clear', children }) {
|
|
31
45
|
const _ref = React.useRef(null);
|
|
32
46
|
const { open, readOnly, setOpen, disabled, value, inputRef, handleClear } = useAutocomplete();
|
|
33
47
|
React.useImperativeHandle(ref, () => _ref.current);
|
|
34
48
|
const isNoSelection = disabled || readOnly || value.length < 1;
|
|
35
|
-
return (_jsxs("div", { ref: _ref, className: cn(
|
|
49
|
+
return (_jsxs("div", { ref: _ref, className: cn(
|
|
50
|
+
// `border-input-border`, NOT `border-input`: `--input` is a SURFACE
|
|
51
|
+
// token and is white in light, so the border it paints is invisible
|
|
52
|
+
// against the field's own `bg-background`. This is the same edge
|
|
53
|
+
// MultipleSelect and DateRangePicker draw, and the same token.
|
|
54
|
+
'bg-background ring-offset-background placeholder:text-input-placeholder data-[disabled=true]:bg-shadcn-100 data-[read-only=true]:bg-shadcn-100 border-input-border flex rounded-md border text-sm focus:outline-hidden focus-visible:outline-hidden data-[disabled=true]:cursor-not-allowed data-[disabled=true]:opacity-50 data-[read-only=true]:opacity-50 md:text-sm [&>span]:line-clamp-1', {
|
|
36
55
|
'h-9': value.length === 0,
|
|
37
56
|
'min-h-9': value.length > 0,
|
|
38
57
|
'cursor-text': !disabled && value.length !== 0
|
|
@@ -48,11 +67,19 @@ export function AutocompleteTrigger({ ref, className, onClear, children }) {
|
|
|
48
67
|
inputRef?.current?.focus();
|
|
49
68
|
}
|
|
50
69
|
setOpen(!open);
|
|
51
|
-
}, "data-disabled": disabled, "data-read-only": readOnly, children: [_jsx("div", { className: "flex grow flex-wrap gap-1 px-3 py-2", children: children }), _jsxs("div", { className: "flex shrink-0 items-center justify-end", children: [_jsx("button", { type: "button", className: cn(isNoSelection && 'hidden'),
|
|
70
|
+
}, "data-disabled": disabled, "data-read-only": readOnly, children: [_jsx("div", { className: "flex grow flex-wrap gap-1 px-3 py-2", children: children }), _jsxs("div", { className: "flex shrink-0 items-center justify-end", children: [_jsx("button", { type: "button", "aria-label": clearLabel, className: cn('cursor-pointer', isNoSelection && 'hidden'), onKeyDown: (event) => {
|
|
71
|
+
// cmdk's Command root calls preventDefault() on EVERY Enter that
|
|
72
|
+
// reaches it, which cancels this button's implicit activation, so
|
|
73
|
+
// the keydown must not get there. Enter only: the root's other
|
|
74
|
+
// keys (Escape, the arrows) still belong to the panel.
|
|
75
|
+
if (event.key === 'Enter') {
|
|
52
76
|
event.stopPropagation();
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
77
|
+
}
|
|
78
|
+
}, onClick: (event) => {
|
|
79
|
+
event.stopPropagation();
|
|
80
|
+
handleClear();
|
|
81
|
+
onClear?.();
|
|
82
|
+
}, children: _jsx(X, { "aria-hidden": true, className: "text-muted-foreground mx-2 h-4" }) }), _jsx(Separator, { orientation: "vertical", className: cn(isNoSelection && 'hidden') }), _jsx(SelectPrimitive.Icon, { className: "cursor-pointer data-[disabled=true]:cursor-not-allowed data-[read-only=true]:cursor-default", "data-disabled": disabled, "data-read-only": readOnly, children: _jsx(ChevronDown, { className: "mx-3 my-2 h-4 w-4 opacity-50" }) })] })] }));
|
|
56
83
|
}
|
|
57
84
|
export function AutocompleteValue({ ref, className, value: valueProp, onValueChange, onBlur, ...props }) {
|
|
58
85
|
const [search, setSearch] = React.useState(valueProp);
|
|
@@ -67,7 +94,7 @@ export function AutocompleteValue({ ref, className, value: valueProp, onValueCha
|
|
|
67
94
|
handleValueChange('');
|
|
68
95
|
return;
|
|
69
96
|
}
|
|
70
|
-
handleValueChange(showValue ? v : options
|
|
97
|
+
handleValueChange(showValue ? v : labelOf(options, v));
|
|
71
98
|
};
|
|
72
99
|
const handleValueChange = (value) => {
|
|
73
100
|
setSearch(value);
|
|
@@ -86,21 +113,29 @@ export function AutocompleteValue({ ref, className, value: valueProp, onValueCha
|
|
|
86
113
|
if (v === '') {
|
|
87
114
|
return;
|
|
88
115
|
}
|
|
89
|
-
setSearch(showValue ? v : options
|
|
116
|
+
setSearch(showValue ? v : labelOf(options, v));
|
|
90
117
|
}, [options]);
|
|
91
118
|
React.useEffect(() => {
|
|
92
119
|
updateSearch(value);
|
|
93
120
|
}, [value]);
|
|
94
121
|
return (_jsx(CommandPrimitive.Input, { ...props, ref: inputRef, value: search, onValueChange: handleValueChange, disabled: disabled, readOnly: readOnly, className: cn('placeholder:text-muted-foreground w-full bg-transparent outline-hidden read-only:opacity-50 read-only:placeholder:opacity-0 focus:outline-hidden disabled:cursor-not-allowed disabled:opacity-50 disabled:placeholder:opacity-0', className), onBlur: handleBlur }));
|
|
95
122
|
}
|
|
96
|
-
export function AutocompleteMultipleValue({ ref, className, ...props }) {
|
|
123
|
+
export function AutocompleteMultipleValue({ ref, className, clearLabel = 'Clear', ...props }) {
|
|
97
124
|
const { value, disabled, handleChange, options, showValue, inputRef } = useAutocomplete();
|
|
98
125
|
React.useImperativeHandle(ref, () => inputRef.current);
|
|
99
126
|
return (_jsxs(_Fragment, { children: [options &&
|
|
100
|
-
value?.map((value) => (_jsxs(Badge, { variant: "secondary", className: cn('data-disabled:bg-muted-foreground data-fixed:bg-muted-foreground data-disabled:text-muted data-fixed:text-muted data-disabled:hover:bg-muted-foreground data-fixed:hover:bg-muted-foreground'), children: [showValue ? value : options
|
|
127
|
+
value?.map((value) => (_jsxs(Badge, { variant: "secondary", className: cn('data-disabled:bg-muted-foreground data-fixed:bg-muted-foreground data-disabled:text-muted data-fixed:text-muted data-disabled:hover:bg-muted-foreground data-fixed:hover:bg-muted-foreground'), children: [showValue ? value : labelOf(options, value), _jsx("button", { type: "button", "aria-label": `${clearLabel} ${showValue ? value : labelOf(options, value)}`, className: cn('ring-offset-background focus:ring-ring ml-1 rounded-full outline-hidden focus:ring-2 focus:ring-offset-2', disabled && 'hidden'), onKeyDown: (event) => {
|
|
128
|
+
// cmdk's Command root calls preventDefault() on EVERY Enter that
|
|
129
|
+
// reaches it, which cancels this button's implicit activation, so
|
|
130
|
+
// the keydown must not get there. Enter only: the root's other
|
|
131
|
+
// keys (Escape, the arrows) still belong to the panel.
|
|
132
|
+
if (event.key === 'Enter') {
|
|
101
133
|
event.stopPropagation();
|
|
102
|
-
|
|
103
|
-
|
|
134
|
+
}
|
|
135
|
+
}, onClick: (event) => {
|
|
136
|
+
event.stopPropagation();
|
|
137
|
+
handleChange(value);
|
|
138
|
+
}, children: _jsx(X, { "aria-hidden": true, className: "text-muted-foreground hover:text-foreground h-3 w-3" }) })] }, value))), _jsx(CommandPrimitive.Input, { ...props, ref: inputRef, disabled: disabled, className: cn('placeholder:text-muted-foreground w-full bg-transparent outline-hidden focus:outline-hidden disabled:cursor-not-allowed disabled:opacity-50 disabled:placeholder:opacity-0', className) })] }));
|
|
104
139
|
}
|
|
105
140
|
export function AutocompleteEmpty({ className, ...props }) {
|
|
106
141
|
const render = useCommandState((state) => state.filtered.count === 0);
|
|
@@ -152,9 +187,16 @@ export function AutocompleteContent({ className, position = 'popper', side = 'bo
|
|
|
152
187
|
child.type.displayName === 'AutocompleteItem') {
|
|
153
188
|
// Check if the item was proper filled with a value prop
|
|
154
189
|
if (child.props.value) {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
190
|
+
// NOT `children as string`. That cast is how a React ELEMENT got into
|
|
191
|
+
// a map every reader treats as text. An item with markup children
|
|
192
|
+
// registers nothing unless it declares a `label`, and `labelOf` reads
|
|
193
|
+
// the absence as "use the value".
|
|
194
|
+
const { label, children: itemChildren } = child.props;
|
|
195
|
+
const text = label ??
|
|
196
|
+
(typeof itemChildren === 'string' ? itemChildren : undefined);
|
|
197
|
+
if (text !== undefined) {
|
|
198
|
+
addOption({ [child.props.value]: text });
|
|
199
|
+
}
|
|
158
200
|
}
|
|
159
201
|
return;
|
|
160
202
|
}
|
|
@@ -210,7 +252,11 @@ export function AutocompleteContent({ className, position = 'popper', side = 'bo
|
|
|
210
252
|
export function AutocompleteGroup({ className, ...props }) {
|
|
211
253
|
return (_jsx(CommandPrimitive.Group, { "data-slot": "autocomplete-group", className: cn('text-foreground [&_[cmdk-group-heading]]:text-muted-foreground overflow-hidden p-1 [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium', className), ...props }));
|
|
212
254
|
}
|
|
213
|
-
export function AutocompleteItem({ className, value,
|
|
255
|
+
export function AutocompleteItem({ className, value,
|
|
256
|
+
// Read off the element by `AutocompleteContent._searchChildren`, never
|
|
257
|
+
// rendered: destructured here only to keep it out of `...props` and off the
|
|
258
|
+
// div cmdk spreads them onto.
|
|
259
|
+
label: _label, onSelect, ...props }) {
|
|
214
260
|
const { handleChange } = useAutocomplete();
|
|
215
261
|
return (_jsx(CommandPrimitive.Item, { "data-slot": "autocomplete-item", value: value, className: cn("data-[selected='true']:bg-accent data-[selected=true]:text-accent-foreground relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0", className), ...props, onMouseDown: (e) => {
|
|
216
262
|
e.preventDefault();
|
|
@@ -220,6 +266,16 @@ export function AutocompleteItem({ className, value, onSelect, ...props }) {
|
|
|
220
266
|
onSelect?.(value);
|
|
221
267
|
} }));
|
|
222
268
|
}
|
|
269
|
+
/**
|
|
270
|
+
* ⛔ LOAD-BEARING, NOT A DEBUG LABEL. `AutocompleteContent._searchChildren`
|
|
271
|
+
* recognises an option by `child.type.displayName === 'AutocompleteItem'`, and
|
|
272
|
+
* a function component carries no displayName unless it is assigned one. It
|
|
273
|
+
* never was, so the walk matched nothing and the option registry stayed empty
|
|
274
|
+
* for every consumer: a multiple-select chip rendered `options[value]` as
|
|
275
|
+
* `undefined` (an empty chip), and `AutocompleteValue.updateSearch` set the
|
|
276
|
+
* input to `undefined` on every selection outside `showValue` mode.
|
|
277
|
+
*/
|
|
278
|
+
AutocompleteItem.displayName = 'AutocompleteItem';
|
|
223
279
|
export function Autocomplete({ ref, value, defaultValue, onValueChange, onClear, className, open: openProp, onOpenChange, showValue, readOnly, disabled, multiple, onKeyDown, children, ...props }) {
|
|
224
280
|
const _ref = React.useRef(null);
|
|
225
281
|
const [open, _setOpen] = React.useState(openProp);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/ui/badge/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAKjE;;;;;;GAMG;AACH;;;;;;;GAOG;AACH,QAAA,MAAM,aAAa;;;8EA6ClB,CAAA;AAED,MAAM,MAAM,UAAU,GAAG,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,GACnD,YAAY,CAAC,OAAO,aAAa,CAAC,GAAG;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAA;AAE5D,iBAAS,KAAK,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,KAAK,EAAE,EAAE,UAAU,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/ui/badge/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAKjE;;;;;;GAMG;AACH;;;;;;;GAOG;AACH,QAAA,MAAM,aAAa;;;8EA6ClB,CAAA;AAED,MAAM,MAAM,UAAU,GAAG,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,GACnD,YAAY,CAAC,OAAO,aAAa,CAAC,GAAG;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAA;AAE5D,iBAAS,KAAK,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,KAAK,EAAE,EAAE,UAAU,qBAsBzE;AAED,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,CAAA"}
|
|
@@ -52,6 +52,16 @@ const badgeVariants = cva('inline-flex items-center gap-1 rounded-full border bo
|
|
|
52
52
|
});
|
|
53
53
|
function Badge({ className, variant, size, asChild, ...props }) {
|
|
54
54
|
const Comp = asChild ? Slot : 'span';
|
|
55
|
-
|
|
55
|
+
/**
|
|
56
|
+
* A bare `span` is generic, and ARIA prohibits an accessible name on a
|
|
57
|
+
* generic element: a caller's `aria-label` was dropped by assistive tech and
|
|
58
|
+
* flagged by axe as `aria-prohibited-attr`. `role="img"` is the smallest role
|
|
59
|
+
* that permits the name and lets it stand in for the visible text, which is
|
|
60
|
+
* exactly what a labelled span badge wants. Unlabelled badges stay generic;
|
|
61
|
+
* `asChild` keeps the child's native role; and a caller's own `role` still wins
|
|
62
|
+
* because it arrives with the spread below.
|
|
63
|
+
*/
|
|
64
|
+
const labelled = props['aria-label'] !== undefined || props['aria-labelledby'] !== undefined;
|
|
65
|
+
return (_jsx(Comp, { "data-slot": "badge", role: !asChild && labelled ? 'img' : undefined, className: cn(badgeVariants({ variant, size }), className), ...props }));
|
|
56
66
|
}
|
|
57
67
|
export { Badge, badgeVariants };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/ui/calendar/index.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EACL,SAAS,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/ui/calendar/index.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EACL,SAAS,EAGT,KAAK,SAAS,EACf,MAAM,kBAAkB,CAAA;AAGzB,OAAO,EAAE,MAAM,EAAkB,MAAM,wBAAwB,CAAA;AAO/D,iBAAS,QAAQ,CAAC,EAChB,SAAS,EACT,UAAU,EACV,eAAsB,EACtB,aAAuB,EACvB,aAAuB,EACvB,UAAU,EACV,UAAU,EACV,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,SAAS,CAAC,GAAG;IAC1C,aAAa,CAAC,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,MAAM,CAAC,CAAC,SAAS,CAAC,CAAA;CAC/D,qBAgKA;AAED,iBAAS,iBAAiB,CAAC,EACzB,SAAS,EACT,GAAG,EACH,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,SAAS,CAAC,qBAqCxC;AAED,OAAO,EAAE,QAAQ,EAAE,iBAAiB,EAAE,CAAA"}
|
|
@@ -1,14 +1,20 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
3
|
import * as React from 'react';
|
|
4
|
-
import { DayPicker, getDefaultClassNames } from 'react-day-picker';
|
|
4
|
+
import { DayPicker, defaultDateLib, getDefaultClassNames } from 'react-day-picker';
|
|
5
5
|
import { cn } from '../../../lib/utils.js';
|
|
6
6
|
import { Button, buttonVariants } from '../../../components/ui/button/index.js';
|
|
7
7
|
import { ChevronLeftIcon, ChevronRightIcon, ChevronDownIcon } from 'lucide-react';
|
|
8
8
|
function Calendar({ className, classNames, showOutsideDays = true, captionLayout = 'label', buttonVariant = 'plain', formatters, components, ...props }) {
|
|
9
9
|
const defaultClassNames = getDefaultClassNames();
|
|
10
10
|
return (_jsx(DayPicker, { showOutsideDays: showOutsideDays, className: cn('bg-background group/calendar p-2 [--cell-radius:var(--radius-md)] [--cell-size:34px] [--nav-size:28px] [[data-slot=card-content]_&]:bg-transparent [[data-slot=popover-content]_&]:bg-transparent', String.raw `rtl:**:[.rdp-button\_next>svg]:rotate-180`, String.raw `rtl:**:[.rdp-button\_previous>svg]:rotate-180`, className), captionLayout: captionLayout, formatters: {
|
|
11
|
-
|
|
11
|
+
// react-day-picker's own default is dateLib.format(month, 'LLLL'), the
|
|
12
|
+
// full month name in the locale it was given. Shortening it has to go
|
|
13
|
+
// through the same dateLib: Date.toLocaleString('default') reads the
|
|
14
|
+
// runtime locale instead, so the dropdown fell back to English while
|
|
15
|
+
// the weekdays and the caption around it stayed in the consumer's
|
|
16
|
+
// language. 'LLL' is the abbreviated form of the same standalone month.
|
|
17
|
+
formatMonthDropdown: (month, dateLib = defaultDateLib) => dateLib.format(month, 'LLL'),
|
|
12
18
|
...formatters
|
|
13
19
|
}, classNames: {
|
|
14
20
|
root: cn('w-fit', defaultClassNames.root),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/ui/card/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAI9B,iBAAS,IAAI,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAWjE;AAED,iBAAS,UAAU,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAQvE;AAED,KAAK,cAAc,GAAG,KAAK,CAAC,cAAc,CAAC,IAAI,CAAC,GAAG;IACjD;;;;OAIG;IACH,EAAE,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;CAC7C,CAAA;AAED,iBAAS,SAAS,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,IAAW,EAAE,GAAG,KAAK,EAAE,EAAE,cAAc,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/ui/card/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAI9B,iBAAS,IAAI,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAWjE;AAED,iBAAS,UAAU,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAQvE;AAED,KAAK,cAAc,GAAG,KAAK,CAAC,cAAc,CAAC,IAAI,CAAC,GAAG;IACjD;;;;OAIG;IACH,EAAE,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;CAC7C,CAAA;AAED,iBAAS,SAAS,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,IAAW,EAAE,GAAG,KAAK,EAAE,EAAE,cAAc,qBAQ1E;AAED,iBAAS,eAAe,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,GAAG,CAAC,qBAQ1E;AAED,iBAAS,UAAU,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAWvE;AAED,iBAAS,WAAW,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAQxE;AAED,iBAAS,UAAU,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAQvE;AAED,OAAO,EACL,IAAI,EACJ,UAAU,EACV,UAAU,EACV,SAAS,EACT,UAAU,EACV,eAAe,EACf,WAAW,EACZ,CAAA"}
|
|
@@ -7,7 +7,7 @@ function CardHeader({ className, ...props }) {
|
|
|
7
7
|
return (_jsx("div", { "data-slot": "card-header", className: cn('flex flex-col space-y-1.5', className), ...props }));
|
|
8
8
|
}
|
|
9
9
|
function CardTitle({ className, as: Comp = 'h3', ...props }) {
|
|
10
|
-
return (_jsx(Comp, { "data-slot": "card-title", className: cn('text-sm leading-none font-medium
|
|
10
|
+
return (_jsx(Comp, { "data-slot": "card-title", className: cn('text-sm leading-none font-medium', className), ...props }));
|
|
11
11
|
}
|
|
12
12
|
function CardDescription({ className, ...props }) {
|
|
13
13
|
return (_jsx("p", { "data-slot": "card-description", className: cn('text-muted-foreground text-sm', className), ...props }));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/ui/dropdown-menu/index.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,KAAK,qBAAqB,MAAM,+BAA+B,CAAA;AAKtE,iBAAS,YAAY,CAAC,EACpB,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,qBAAqB,CAAC,IAAI,CAAC,qBAEzD;AAED,iBAAS,kBAAkB,CAAC,EAC1B,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,qBAAqB,CAAC,MAAM,CAAC,qBAI3D;AAED,iBAAS,mBAAmB,CAAC,EAC3B,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,qBAAqB,CAAC,OAAO,CAAC,qBAW5D;AAED,iBAAS,mBAAmB,CAAC,EAC3B,SAAS,EACT,UAAc,EACd,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,qBAAqB,CAAC,OAAO,CAAC,qBAc5D;AAED,iBAAS,iBAAiB,CAAC,EACzB,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,qBAAqB,CAAC,KAAK,CAAC,qBAI1D;AAED,iBAAS,gBAAgB,CAAC,EACxB,SAAS,EACT,KAAK,EACL,OAAmB,EACnB,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,qBAAqB,CAAC,IAAI,CAAC,GAAG;IAC3D,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,OAAO,CAAC,EAAE,SAAS,GAAG,aAAa,CAAA;CACpC,qBAaA;AAED,iBAAS,oBAAoB,CAAC,EAC5B,SAAS,EACT,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/ui/dropdown-menu/index.tsx"],"names":[],"mappings":"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"}
|
|
@@ -23,7 +23,10 @@ function DropdownMenuItem({ className, inset, variant = 'default', ...props }) {
|
|
|
23
23
|
return (_jsx(DropdownMenuPrimitive.Item, { "data-slot": "dropdown-menu-item", "data-inset": inset, "data-variant": variant, className: cn('focus:bg-shadcn-100 focus:text-accent-foreground text-muted-foreground relative flex cursor-pointer items-center gap-3 px-3 py-2 text-sm font-medium outline-hidden transition-colors select-none data-disabled:pointer-events-none data-disabled:opacity-50', className), ...props }));
|
|
24
24
|
}
|
|
25
25
|
function DropdownMenuItemIcon({ className, children, ...props }) {
|
|
26
|
-
return (_jsx("span", { "data-slot": "dropdown-menu-item-icon",
|
|
26
|
+
return (_jsx("span", { "data-slot": "dropdown-menu-item-icon",
|
|
27
|
+
// A meaningful glyph inside an interactive item answers to the 3:1 floor
|
|
28
|
+
// of SC 1.4.11. base/400 reads 2.56:1 on the popover surface in light.
|
|
29
|
+
className: cn('text-muted-foreground', className), ...props, children: React.Children.map(React.Children.toArray(children), (child) => React.isValidElement(child)
|
|
27
30
|
? React.cloneElement(child, { size: 16 })
|
|
28
31
|
: child) }));
|
|
29
32
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/ui/field/index.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAGjE,OAAO,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAA;AAG7C,iBAAS,QAAQ,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,UAAU,CAAC,+BAW1E;AAED,iBAAS,WAAW,CAAC,EACnB,SAAS,EACT,OAAkB,EAClB,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,QAAQ,CAAC,GAAG;IAAE,OAAO,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAA;CAAE,+BAYnE;AAED,iBAAS,UAAU,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,+BAWvE;AAED,QAAA,MAAM,aAAa;;8EAgBlB,CAAA;AAED,iBAAS,KAAK,CAAC,EACb,SAAS,EACT,WAAwB,EACxB,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,GAAG,YAAY,CAAC,OAAO,aAAa,CAAC,+BAUlE;AAED,iBAAS,YAAY,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,+BAWzE;AAED,iBAAS,UAAU,CAAC,EAClB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,KAAK,CAAC,+BAYpC;AAED,iBAAS,UAAU,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,+BAWvE;AAED,iBAAS,gBAAgB,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,GAAG,CAAC,+BAa3E;AAED,iBAAS,cAAc,CAAC,EACtB,QAAQ,EACR,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,GAAG;IAC/B,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CAC3B,+BAsBA;AAED,iBAAS,UAAU,CAAC,EAClB,SAAS,EACT,QAAQ,EACR,MAAM,EACN,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,GAAG;IAC/B,MAAM,CAAC,EAAE,KAAK,CAAC;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAC,CAAA;CACjD,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/ui/field/index.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAGjE,OAAO,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAA;AAG7C,iBAAS,QAAQ,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,UAAU,CAAC,+BAW1E;AAED,iBAAS,WAAW,CAAC,EACnB,SAAS,EACT,OAAkB,EAClB,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,QAAQ,CAAC,GAAG;IAAE,OAAO,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAA;CAAE,+BAYnE;AAED,iBAAS,UAAU,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,+BAWvE;AAED,QAAA,MAAM,aAAa;;8EAgBlB,CAAA;AAED,iBAAS,KAAK,CAAC,EACb,SAAS,EACT,WAAwB,EACxB,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,GAAG,YAAY,CAAC,OAAO,aAAa,CAAC,+BAUlE;AAED,iBAAS,YAAY,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,+BAWzE;AAED,iBAAS,UAAU,CAAC,EAClB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,KAAK,CAAC,+BAYpC;AAED,iBAAS,UAAU,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,+BAWvE;AAED,iBAAS,gBAAgB,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,GAAG,CAAC,+BAa3E;AAED,iBAAS,cAAc,CAAC,EACtB,QAAQ,EACR,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,GAAG;IAC/B,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CAC3B,+BAsBA;AAED,iBAAS,UAAU,CAAC,EAClB,SAAS,EACT,QAAQ,EACR,MAAM,EACN,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,GAAG;IAC/B,MAAM,CAAC,EAAE,KAAK,CAAC;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAC,CAAA;CACjD,sCA4CA;AAED,OAAO,EACL,KAAK,EACL,UAAU,EACV,gBAAgB,EAChB,UAAU,EACV,UAAU,EACV,WAAW,EACX,cAAc,EACd,QAAQ,EACR,YAAY,EACZ,UAAU,EACX,CAAA"}
|
|
@@ -14,7 +14,7 @@ function FieldLegend({ className, variant = 'legend', ...props }) {
|
|
|
14
14
|
function FieldGroup({ className, ...props }) {
|
|
15
15
|
return (_jsx("div", { "data-slot": "field-group", className: cn('group/field-group @container/field-group flex w-full flex-col gap-5 data-[slot=checkbox-group]:gap-3 [&>[data-slot=field-group]]:gap-4', className), ...props }));
|
|
16
16
|
}
|
|
17
|
-
const fieldVariants = cva('data-[invalid=true]:text-
|
|
17
|
+
const fieldVariants = cva('data-[invalid=true]:text-system-error-h1a gap-2 group/field flex w-full', {
|
|
18
18
|
variants: {
|
|
19
19
|
orientation: {
|
|
20
20
|
vertical: 'flex-col [&>*]:w-full [&>.sr-only]:w-auto',
|
|
@@ -63,6 +63,9 @@ function FieldError({ className, children, errors, ...props }) {
|
|
|
63
63
|
if (!content) {
|
|
64
64
|
return null;
|
|
65
65
|
}
|
|
66
|
-
return (_jsx("div", { role: "alert", "data-slot": "field-error",
|
|
66
|
+
return (_jsx("div", { role: "alert", "data-slot": "field-error",
|
|
67
|
+
// The error TEXT token, not `text-destructive`: that is the badge/fill
|
|
68
|
+
// family and measures 3.80:1 as ink on the dark card, under AA.
|
|
69
|
+
className: cn('text-system-error-h1a text-sm font-normal', className), ...props, children: content }));
|
|
67
70
|
}
|
|
68
71
|
export { Field, FieldLabel, FieldDescription, FieldError, FieldGroup, FieldLegend, FieldSeparator, FieldSet, FieldContent, FieldTitle };
|
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* FileUpload — a controlled "pick a file,
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
2
|
+
* FileUpload — a controlled "pick a file, hand it back" primitive. The defining
|
|
3
|
+
* job: select one file (by click, keyboard, or drag-and-drop), validate it
|
|
4
|
+
* against an accept filter + a byte ceiling, and emit `{ file, text }`.
|
|
5
|
+
*
|
|
6
|
+
* `readAs` decides whether the bytes are decoded on the way through. `'text'`
|
|
7
|
+
* (the default) reads UTF-8 via FileReader.readAsText, which is what a PEM/CSV
|
|
8
|
+
* host wants. `'none'` hands the `File` over untouched and is the only mode a
|
|
9
|
+
* BINARY file can use: a PDF, XLSX or PFX put through readAsText decodes into
|
|
10
|
+
* replacement-character garbage, and that garbage string is then retained for
|
|
11
|
+
* as long as the host holds the value — 20 MiB of PDF became a useless 20 MiB
|
|
12
|
+
* string, and the host still had to read the file a second time to get at the
|
|
13
|
+
* real bytes.
|
|
7
14
|
*
|
|
8
15
|
* The real `<input type="file">` IS the accessible control: it is `sr-only`
|
|
9
16
|
* (visually hidden) but focusable and labelable — never `aria-hidden`, never
|
|
@@ -24,6 +31,11 @@
|
|
|
24
31
|
* a value, so it cannot masquerade as valid. `accept` is validated against
|
|
25
32
|
* BOTH extension and MIME because the native `accept` attribute is only a
|
|
26
33
|
* browser hint and is bypassable via drag-drop.
|
|
34
|
+
*
|
|
35
|
+
* A host that already announces the rejection itself — a toast in its own
|
|
36
|
+
* locale, driven off `onError` — silences this one by returning nothing from
|
|
37
|
+
* `labels.error`. Two announcements for one event, in two languages, is the
|
|
38
|
+
* accessibility defect; the wording is not.
|
|
27
39
|
*/
|
|
28
40
|
import * as React from 'react';
|
|
29
41
|
export type FileUploadResult = {
|
|
@@ -42,6 +54,33 @@ export type FileUploadError = {
|
|
|
42
54
|
kind: 'read-failed';
|
|
43
55
|
file: File;
|
|
44
56
|
};
|
|
57
|
+
/** How the picked file's bytes are handled on the way to `onSelect`. */
|
|
58
|
+
export type FileUploadReadAs = 'text' | 'none';
|
|
59
|
+
/**
|
|
60
|
+
* Overrides for the fixed English copy. Every field is optional and defaults to
|
|
61
|
+
* the current value, so a consumer that passes nothing renders exactly as
|
|
62
|
+
* before. These four strings were the whole of the component's user-visible
|
|
63
|
+
* text, and none of them was reachable — a pt-BR console rendered an English
|
|
64
|
+
* affordance and handed a screen reader an English accessible name.
|
|
65
|
+
*/
|
|
66
|
+
export interface FileUploadLabels {
|
|
67
|
+
/** Emphasised call to action in the empty zone. Defaults to "Choose a file". */
|
|
68
|
+
action?: string;
|
|
69
|
+
/** Trailing hint after the action. Defaults to "or drag and drop". */
|
|
70
|
+
hint?: string;
|
|
71
|
+
/** Accessible name of the clear button. Defaults to "Remove file". */
|
|
72
|
+
remove?: string;
|
|
73
|
+
/**
|
|
74
|
+
* Copy for the component's own `role="alert"` refusal. Receives the rejection
|
|
75
|
+
* so the message can interpolate the cap or the accept filter; use the
|
|
76
|
+
* exported `humanizeSize` to format `maxSizeBytes` the way the chip does.
|
|
77
|
+
*
|
|
78
|
+
* Return `null`, `undefined` or `''` to stay SILENT and leave the
|
|
79
|
+
* announcement to the host's own `onError` handling. Defaults to the
|
|
80
|
+
* built-in English messages.
|
|
81
|
+
*/
|
|
82
|
+
error?: (error: FileUploadError) => string | null | undefined;
|
|
83
|
+
}
|
|
45
84
|
export type FileUploadProps = {
|
|
46
85
|
/** Comma-separated accept filter, e.g. ".pem,.key" or "text/plain". Mirrors the native input accept. */
|
|
47
86
|
accept?: string;
|
|
@@ -49,7 +88,18 @@ export type FileUploadProps = {
|
|
|
49
88
|
maxSizeBytes?: number;
|
|
50
89
|
/** Controlled selection. `null` = empty. The host owns state. */
|
|
51
90
|
value?: FileUploadResult | null;
|
|
52
|
-
/**
|
|
91
|
+
/**
|
|
92
|
+
* How the accepted file is handed over.
|
|
93
|
+
* - `'text'` (default): decode as UTF-8 via FileReader.readAsText and emit
|
|
94
|
+
* `{ file, text }`. Unchanged behaviour for every existing consumer.
|
|
95
|
+
* - `'none'`: skip decoding entirely and emit `{ file, text: '' }`. The mode
|
|
96
|
+
* for BINARY files (PDF, XLSX, PFX/DER): the host gets the `File` intact
|
|
97
|
+
* and `text` carries nothing, so do not read it in this mode.
|
|
98
|
+
*/
|
|
99
|
+
readAs?: FileUploadReadAs;
|
|
100
|
+
/** Override the fixed English copy. Omitted fields keep their defaults. */
|
|
101
|
+
labels?: FileUploadLabels;
|
|
102
|
+
/** Fires on accept (with the result) or clear (null). See `readAs` for whether `text` is populated. */
|
|
53
103
|
onSelect: (result: FileUploadResult | null) => void;
|
|
54
104
|
/** Fires when a pick is rejected (size/type/read). Optional — the component also shows its own inline error. */
|
|
55
105
|
onError?: (error: FileUploadError) => void;
|
|
@@ -60,7 +110,7 @@ export type FileUploadProps = {
|
|
|
60
110
|
'aria-required'?: boolean;
|
|
61
111
|
'aria-describedby'?: string;
|
|
62
112
|
'aria-label'?: string;
|
|
63
|
-
} & Omit<React.InputHTMLAttributes<HTMLInputElement>, 'type' | 'accept' | 'value' | 'disabled' | 'onChange' | 'onSelect' | 'className' | 'multiple'>;
|
|
113
|
+
} & Omit<React.InputHTMLAttributes<HTMLInputElement>, 'type' | 'accept' | 'value' | 'disabled' | 'onChange' | 'onSelect' | 'className' | 'onError' | 'multiple'>;
|
|
64
114
|
/**
|
|
65
115
|
* Validate a chosen file against an accept filter and a byte ceiling. Exported
|
|
66
116
|
* so hosts can pre-validate before handing a file over. `accept` is matched
|
|
@@ -72,6 +122,12 @@ export declare function validateFile(file: File, opts: {
|
|
|
72
122
|
accept?: string;
|
|
73
123
|
maxSizeBytes?: number;
|
|
74
124
|
}): FileUploadError | null;
|
|
125
|
+
/**
|
|
126
|
+
* Humanize a byte count for the selected-file chip. Binary units, 1 decimal.
|
|
127
|
+
* Exported so a `labels.error` override can format `maxSizeBytes` exactly the
|
|
128
|
+
* way the chip and the default message do, instead of re-deriving binary units.
|
|
129
|
+
*/
|
|
130
|
+
export declare function humanizeSize(bytes: number): string;
|
|
75
131
|
export declare const FileUpload: React.ForwardRefExoticComponent<{
|
|
76
132
|
/** Comma-separated accept filter, e.g. ".pem,.key" or "text/plain". Mirrors the native input accept. */
|
|
77
133
|
accept?: string;
|
|
@@ -79,7 +135,18 @@ export declare const FileUpload: React.ForwardRefExoticComponent<{
|
|
|
79
135
|
maxSizeBytes?: number;
|
|
80
136
|
/** Controlled selection. `null` = empty. The host owns state. */
|
|
81
137
|
value?: FileUploadResult | null;
|
|
82
|
-
/**
|
|
138
|
+
/**
|
|
139
|
+
* How the accepted file is handed over.
|
|
140
|
+
* - `'text'` (default): decode as UTF-8 via FileReader.readAsText and emit
|
|
141
|
+
* `{ file, text }`. Unchanged behaviour for every existing consumer.
|
|
142
|
+
* - `'none'`: skip decoding entirely and emit `{ file, text: '' }`. The mode
|
|
143
|
+
* for BINARY files (PDF, XLSX, PFX/DER): the host gets the `File` intact
|
|
144
|
+
* and `text` carries nothing, so do not read it in this mode.
|
|
145
|
+
*/
|
|
146
|
+
readAs?: FileUploadReadAs;
|
|
147
|
+
/** Override the fixed English copy. Omitted fields keep their defaults. */
|
|
148
|
+
labels?: FileUploadLabels;
|
|
149
|
+
/** Fires on accept (with the result) or clear (null). See `readAs` for whether `text` is populated. */
|
|
83
150
|
onSelect: (result: FileUploadResult | null) => void;
|
|
84
151
|
/** Fires when a pick is rejected (size/type/read). Optional — the component also shows its own inline error. */
|
|
85
152
|
onError?: (error: FileUploadError) => void;
|
|
@@ -90,5 +157,5 @@ export declare const FileUpload: React.ForwardRefExoticComponent<{
|
|
|
90
157
|
'aria-required'?: boolean;
|
|
91
158
|
'aria-describedby'?: string;
|
|
92
159
|
'aria-label'?: string;
|
|
93
|
-
} & Omit<React.InputHTMLAttributes<HTMLInputElement>, "className" | "disabled" | "type" | "value" | "onChange" | "onSelect" | "accept" | "multiple"> & React.RefAttributes<HTMLInputElement>>;
|
|
160
|
+
} & Omit<React.InputHTMLAttributes<HTMLInputElement>, "className" | "disabled" | "type" | "value" | "onChange" | "onError" | "onSelect" | "accept" | "multiple"> & React.RefAttributes<HTMLInputElement>>;
|
|
94
161
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/ui/file-upload/index.tsx"],"names":[],"mappings":"AAEA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/ui/file-upload/index.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
3
|
/**
|
|
4
|
-
* FileUpload — a controlled "pick a file,
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
4
|
+
* FileUpload — a controlled "pick a file, hand it back" primitive. The defining
|
|
5
|
+
* job: select one file (by click, keyboard, or drag-and-drop), validate it
|
|
6
|
+
* against an accept filter + a byte ceiling, and emit `{ file, text }`.
|
|
7
|
+
*
|
|
8
|
+
* `readAs` decides whether the bytes are decoded on the way through. `'text'`
|
|
9
|
+
* (the default) reads UTF-8 via FileReader.readAsText, which is what a PEM/CSV
|
|
10
|
+
* host wants. `'none'` hands the `File` over untouched and is the only mode a
|
|
11
|
+
* BINARY file can use: a PDF, XLSX or PFX put through readAsText decodes into
|
|
12
|
+
* replacement-character garbage, and that garbage string is then retained for
|
|
13
|
+
* as long as the host holds the value — 20 MiB of PDF became a useless 20 MiB
|
|
14
|
+
* string, and the host still had to read the file a second time to get at the
|
|
15
|
+
* real bytes.
|
|
9
16
|
*
|
|
10
17
|
* The real `<input type="file">` IS the accessible control: it is `sr-only`
|
|
11
18
|
* (visually hidden) but focusable and labelable — never `aria-hidden`, never
|
|
@@ -26,6 +33,11 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
26
33
|
* a value, so it cannot masquerade as valid. `accept` is validated against
|
|
27
34
|
* BOTH extension and MIME because the native `accept` attribute is only a
|
|
28
35
|
* browser hint and is bypassable via drag-drop.
|
|
36
|
+
*
|
|
37
|
+
* A host that already announces the rejection itself — a toast in its own
|
|
38
|
+
* locale, driven off `onError` — silences this one by returning nothing from
|
|
39
|
+
* `labels.error`. Two announcements for one event, in two languages, is the
|
|
40
|
+
* accessibility defect; the wording is not.
|
|
29
41
|
*/
|
|
30
42
|
import * as React from 'react';
|
|
31
43
|
import { Upload, X } from 'lucide-react';
|
|
@@ -68,8 +80,12 @@ function matchesAccept(file, accept) {
|
|
|
68
80
|
return mime === token;
|
|
69
81
|
});
|
|
70
82
|
}
|
|
71
|
-
/**
|
|
72
|
-
|
|
83
|
+
/**
|
|
84
|
+
* Humanize a byte count for the selected-file chip. Binary units, 1 decimal.
|
|
85
|
+
* Exported so a `labels.error` override can format `maxSizeBytes` exactly the
|
|
86
|
+
* way the chip and the default message do, instead of re-deriving binary units.
|
|
87
|
+
*/
|
|
88
|
+
export function humanizeSize(bytes) {
|
|
73
89
|
if (bytes < 1024)
|
|
74
90
|
return `${bytes} B`;
|
|
75
91
|
const units = ['KB', 'MB', 'GB'];
|
|
@@ -81,8 +97,8 @@ function humanizeSize(bytes) {
|
|
|
81
97
|
}
|
|
82
98
|
return `${size.toFixed(1)} ${units[unit]}`;
|
|
83
99
|
}
|
|
84
|
-
/**
|
|
85
|
-
function
|
|
100
|
+
/** The default English announcement for each rejection kind. */
|
|
101
|
+
function defaultErrorMessage(error) {
|
|
86
102
|
switch (error.kind) {
|
|
87
103
|
case 'too-large':
|
|
88
104
|
return `File is too large (max ${humanizeSize(error.maxSizeBytes)}).`;
|
|
@@ -92,7 +108,7 @@ function errorMessage(error) {
|
|
|
92
108
|
return 'Could not read the file.';
|
|
93
109
|
}
|
|
94
110
|
}
|
|
95
|
-
export const FileUpload = React.forwardRef(function FileUpload({ accept, maxSizeBytes, value, onSelect, onError, disabled = false, id, className, 'aria-invalid': ariaInvalid, 'aria-required': ariaRequired, 'aria-describedby': ariaDescribedby, 'aria-label': ariaLabel, ...rest }, ref) {
|
|
111
|
+
export const FileUpload = React.forwardRef(function FileUpload({ accept, maxSizeBytes, value, readAs = 'text', labels, onSelect, onError, disabled = false, id, className, 'aria-invalid': ariaInvalid, 'aria-required': ariaRequired, 'aria-describedby': ariaDescribedby, 'aria-label': ariaLabel, ...rest }, ref) {
|
|
96
112
|
const internalRef = React.useRef(null);
|
|
97
113
|
React.useImperativeHandle(ref, () => internalRef.current);
|
|
98
114
|
const reactId = React.useId();
|
|
@@ -104,12 +120,21 @@ export const FileUpload = React.forwardRef(function FileUpload({ accept, maxSize
|
|
|
104
120
|
// component's own validation/read error — a self-detected bad pick must read
|
|
105
121
|
// as invalid even outside a form.
|
|
106
122
|
const invalid = ariaInvalid || error !== null;
|
|
123
|
+
// Resolve the announcement BEFORE deciding whether the alert exists: a
|
|
124
|
+
// consumer that returns nothing is opting out of this surface entirely,
|
|
125
|
+
// and an association pointing at an unrendered node is worse than none.
|
|
126
|
+
const resolved = error
|
|
127
|
+
? labels?.error
|
|
128
|
+
? labels.error(error)
|
|
129
|
+
: defaultErrorMessage(error)
|
|
130
|
+
: null;
|
|
131
|
+
const errorText = resolved ? resolved : null;
|
|
107
132
|
// Radix Slot OVERWRITES aria-describedby (it does not merge), so merge the
|
|
108
133
|
// primitive's own role=alert error id with the FormControl-injected one so
|
|
109
134
|
// both associations coexist on the input. A plain join, never `cn` —
|
|
110
135
|
// tailwind-merge treats these as class names and would drop an id that
|
|
111
136
|
// happens to look like a conflicting utility.
|
|
112
|
-
const describedBy = [ariaDescribedby,
|
|
137
|
+
const describedBy = [ariaDescribedby, errorText ? errorId : undefined]
|
|
113
138
|
.filter(Boolean)
|
|
114
139
|
.join(' ') || undefined;
|
|
115
140
|
// Last-resolved-wins: a slow read for pick A must not overwrite a newer
|
|
@@ -125,6 +150,15 @@ export const FileUpload = React.forwardRef(function FileUpload({ accept, maxSize
|
|
|
125
150
|
onError?.(validationError);
|
|
126
151
|
return;
|
|
127
152
|
}
|
|
153
|
+
// Binary path: no decode, no reader, no retained garbage string. The
|
|
154
|
+
// stale-rejection clear still has to happen here — the alert is this
|
|
155
|
+
// component's own state and a good pick must retire it.
|
|
156
|
+
if (readAs === 'none') {
|
|
157
|
+
readerRef.current = null;
|
|
158
|
+
setError(null);
|
|
159
|
+
onSelect({ file, text: '' });
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
128
162
|
const reader = new FileReader();
|
|
129
163
|
readerRef.current = reader;
|
|
130
164
|
reader.onload = () => {
|
|
@@ -191,10 +225,10 @@ export const FileUpload = React.forwardRef(function FileUpload({ accept, maxSize
|
|
|
191
225
|
return (_jsxs("div", { className: cn('space-y-2', className), children: [_jsxs("div", { onClick: openPicker, onDragOver: onDragOver, onDragLeave: onDragLeave, onDrop: onDrop, className: cn('border-input bg-card focus-within:ring-ring focus-within:ring-offset-background aria-[invalid=true]:border-destructive aria-[invalid=true]:focus-within:ring-destructive flex w-full items-center gap-3 rounded-md border px-3 py-4 text-sm shadow-xs transition-colors focus-within:ring-2 focus-within:ring-offset-1 focus-within:outline-none', dragActive &&
|
|
192
226
|
'border-ring ring-ring ring-offset-background ring-2 ring-offset-1', disabled
|
|
193
227
|
? 'border-muted bg-muted/30 cursor-not-allowed shadow-none'
|
|
194
|
-
: 'cursor-pointer'), "aria-invalid": invalid || undefined, children: [_jsx("input", { ref: internalRef, id: inputId, type: "file", accept: accept, disabled: disabled, className: "sr-only", "aria-invalid": invalid || undefined, "aria-required": ariaRequired || undefined, "aria-describedby": describedBy, "aria-label": ariaLabel, onChange: onInputChange, ...rest }), _jsx(Upload, { className: "text-muted-foreground size-4 shrink-0", "aria-hidden": "true" }), value ? (_jsxs(_Fragment, { children: [_jsxs("span", { className: "min-w-0 flex-1 truncate", children: [_jsx("span", { className: "text-foreground font-medium", children: value.file.name }), ' ', _jsx("span", { className: "text-muted-foreground tabular-nums", children: humanizeSize(value.file.size) })] }), _jsx(IconButton, { type: "button", variant: "plain", size: "small", disabled: disabled, "aria-label":
|
|
228
|
+
: 'cursor-pointer'), "aria-invalid": invalid || undefined, children: [_jsx("input", { ref: internalRef, id: inputId, type: "file", accept: accept, disabled: disabled, className: "sr-only", "aria-invalid": invalid || undefined, "aria-required": ariaRequired || undefined, "aria-describedby": describedBy, "aria-label": ariaLabel, onChange: onInputChange, ...rest }), _jsx(Upload, { className: "text-muted-foreground size-4 shrink-0", "aria-hidden": "true" }), value ? (_jsxs(_Fragment, { children: [_jsxs("span", { className: "min-w-0 flex-1 truncate", children: [_jsx("span", { className: "text-foreground font-medium", children: value.file.name }), ' ', _jsx("span", { className: "text-muted-foreground tabular-nums", children: humanizeSize(value.file.size) })] }), _jsx(IconButton, { type: "button", variant: "plain", size: "small", disabled: disabled, "aria-label": labels?.remove?.trim() ? labels.remove : 'Remove file', onClick: (event) => {
|
|
195
229
|
// Don't bubble to the zone's openPicker and re-open the dialog.
|
|
196
230
|
event.stopPropagation();
|
|
197
231
|
clear();
|
|
198
|
-
}, children: _jsx(X, { className: "size-4", "aria-hidden": "true" }) })] })) : (_jsxs("span", { className: "text-muted-foreground", children: [_jsx("span", { className: "text-foreground font-medium", children:
|
|
232
|
+
}, children: _jsx(X, { className: "size-4", "aria-hidden": "true" }) })] })) : (_jsxs("span", { className: "text-muted-foreground", children: [_jsx("span", { className: "text-foreground font-medium", children: labels?.action ?? 'Choose a file' }), ' ', labels?.hint ?? 'or drag and drop'] }))] }), errorText ? (_jsx("p", { id: errorId, role: "alert", className: "text-system-error-h1a text-xs font-medium", children: errorText })) : null] }));
|
|
199
233
|
});
|
|
200
234
|
FileUpload.displayName = 'FileUpload';
|
|
@@ -16,7 +16,11 @@ declare const useFormField: () => {
|
|
|
16
16
|
formDescriptionId: string;
|
|
17
17
|
formMessageId: string;
|
|
18
18
|
required: boolean | undefined;
|
|
19
|
+
described: Record<DescribingSlot, boolean> | undefined;
|
|
20
|
+
onDescribedChange: ((slot: DescribingSlot, rendered: boolean) => void) | undefined;
|
|
19
21
|
};
|
|
22
|
+
/** The two slots that can describe a control, in the order a reader hears them. */
|
|
23
|
+
type DescribingSlot = 'message' | 'description';
|
|
20
24
|
export type FormItemProps = React.HTMLAttributes<HTMLDivElement> & {
|
|
21
25
|
required?: boolean;
|
|
22
26
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"form.d.ts","sourceRoot":"","sources":["../../../../src/components/ui/form.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,KAAK,cAAc,MAAM,uBAAuB,CAAA;AAEvD,OAAO,EAEL,eAAe,EACf,SAAS,EACT,WAAW,EAGZ,MAAM,iBAAiB,CAAA;AAKxB,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAA;AAS9D,QAAA,MAAM,IAAI,4MAAe,CAAA;AAazB,QAAA,MAAM,SAAS,GACb,YAAY,SAAS,WAAW,GAAG,WAAW,EAC9C,KAAK,SAAS,SAAS,CAAC,YAAY,CAAC,GAAG,SAAS,CAAC,YAAY,CAAC,EAC/D,cAEC,eAAe,CAAC,YAAY,EAAE,KAAK,CAAC,sBAMtC,CAAA;AAED,QAAA,MAAM,YAAY
|
|
1
|
+
{"version":3,"file":"form.d.ts","sourceRoot":"","sources":["../../../../src/components/ui/form.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,KAAK,cAAc,MAAM,uBAAuB,CAAA;AAEvD,OAAO,EAEL,eAAe,EACf,SAAS,EACT,WAAW,EAGZ,MAAM,iBAAiB,CAAA;AAKxB,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAA;AAS9D,QAAA,MAAM,IAAI,4MAAe,CAAA;AAazB,QAAA,MAAM,SAAS,GACb,YAAY,SAAS,WAAW,GAAG,WAAW,EAC9C,KAAK,SAAS,SAAS,CAAC,YAAY,CAAC,GAAG,SAAS,CAAC,YAAY,CAAC,EAC/D,cAEC,eAAe,CAAC,YAAY,EAAE,KAAK,CAAC,sBAMtC,CAAA;AAED,QAAA,MAAM,YAAY;;;;;;;;;;;;;+BA4CW,cAAc,YAAY,OAAO,KAAK,IAAI;CAjBtE,CAAA;AAED,mFAAmF;AACnF,KAAK,cAAc,GAAG,SAAS,GAAG,aAAa,CAAA;AAwC/C,MAAM,MAAM,aAAa,GAAG,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,GAAG;IACjE,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB,CAAA;AAED,QAAA,MAAM,QAAQ;eAHD,OAAO;wCA8BnB,CAAA;AAGD,MAAM,MAAM,cAAc,GAAG,KAAK,CAAC,wBAAwB,CACzD,OAAO,cAAc,CAAC,IAAI,CAC3B,GAAG;IACF,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CACxB,CAAA;AAED,QAAA,MAAM,SAAS;YAHL,KAAK,CAAC,SAAS;0CA6BvB,CAAA;AAGF,eAAO,MAAM,WAAW,GAAI,yBAAyB,oBAAoB,sBASxE,CAAA;AAED,QAAA,MAAM,WAAW;;gFAgCf,CAAA;AAGF,QAAA,MAAM,eAAe,yHAgBnB,CAAA;AAGF,QAAA,MAAM,WAAW,yHA6Bf,CAAA;AAGF,OAAO,EACL,YAAY,EACZ,IAAI,EACJ,QAAQ,EACR,SAAS,EACT,WAAW,EACX,eAAe,EACf,WAAW,EACX,SAAS,EACV,CAAA"}
|