@appcorp/shadcn 1.1.16 → 1.1.18
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/components/enhanced-checkbox.d.ts +1 -0
- package/components/enhanced-checkbox.js +2 -2
- package/components/enhanced-combobox.d.ts +46 -1
- package/components/enhanced-combobox.js +12 -12
- package/components/enhanced-dropzone.d.ts +45 -3
- package/components/enhanced-dropzone.js +14 -14
- package/components/enhanced-input.d.ts +16 -0
- package/components/enhanced-input.js +7 -7
- package/components/enhanced-label.d.ts +7 -1
- package/components/enhanced-label.js +3 -3
- package/components/enhanced-select.d.ts +30 -1
- package/components/enhanced-select.js +4 -4
- package/components/enhanced-switch.d.ts +21 -0
- package/components/enhanced-switch.js +9 -9
- package/components/enhanced-table-footer-action.d.ts +10 -0
- package/components/enhanced-table-footer-action.js +6 -6
- package/components/enhanced-table-footer-page.d.ts +14 -0
- package/components/enhanced-table-footer-page.js +12 -12
- package/components/enhanced-table-footer-pagination.d.ts +12 -0
- package/components/enhanced-table-footer-pagination.js +8 -6
- package/components/enhanced-table-header-action.d.ts +11 -0
- package/components/enhanced-table-header-action.js +7 -5
- package/components/enhanced-table-header-search.d.ts +15 -0
- package/components/enhanced-table-header-search.js +5 -4
- package/components/enhanced-table.d.ts +112 -0
- package/components/enhanced-table.js +83 -15
- package/components/enhanced-textarea.d.ts +16 -0
- package/components/enhanced-textarea.js +7 -7
- package/package.json +1 -1
|
@@ -4,6 +4,7 @@ interface EnhancedCheckboxProps extends React.ComponentPropsWithoutRef<typeof Ch
|
|
|
4
4
|
error?: string;
|
|
5
5
|
info?: string;
|
|
6
6
|
label?: string;
|
|
7
|
+
testId?: string;
|
|
7
8
|
}
|
|
8
9
|
declare const EnhancedCheckbox: React.ForwardRefExoticComponent<EnhancedCheckboxProps & React.RefAttributes<HTMLButtonElement>>;
|
|
9
10
|
export { EnhancedCheckbox };
|
|
@@ -62,10 +62,10 @@ var utils_1 = require("../lib/utils");
|
|
|
62
62
|
var checkbox_1 = require("./ui/checkbox");
|
|
63
63
|
var enhanced_label_1 = require("./enhanced-label");
|
|
64
64
|
var EnhancedCheckbox = React.forwardRef(function (_a, ref) {
|
|
65
|
-
var className = _a.className, error = _a.error, info = _a.info, label = _a.label, id = _a.id, props = __rest(_a, ["className", "error", "info", "label", "id"]);
|
|
65
|
+
var className = _a.className, error = _a.error, info = _a.info, label = _a.label, id = _a.id, testId = _a.testId, props = __rest(_a, ["className", "error", "info", "label", "id", "testId"]);
|
|
66
66
|
// Determine if there's an error (for aria-invalid and styling)
|
|
67
67
|
var hasError = Boolean(error);
|
|
68
|
-
var checkboxElement = (React.createElement(checkbox_1.Checkbox, __assign({ ref: ref, id: id, "data-slot": "checkbox", "aria-invalid": hasError, className: (0, utils_1.cn)(
|
|
68
|
+
var checkboxElement = (React.createElement(checkbox_1.Checkbox, __assign({ ref: ref, id: id, "data-slot": "checkbox", "data-testid": testId, "aria-invalid": hasError, className: (0, utils_1.cn)(
|
|
69
69
|
// Error state styling
|
|
70
70
|
hasError &&
|
|
71
71
|
"data-[state=checked]:bg-destructive data-[state=unchecked]:bg-destructive/20 border-destructive focus-visible:border-destructive focus-visible:ring-destructive/20", className) }, props)));
|
|
@@ -4,27 +4,72 @@ export interface ComboboxOption {
|
|
|
4
4
|
label: string;
|
|
5
5
|
id?: string;
|
|
6
6
|
}
|
|
7
|
+
/**
|
|
8
|
+
* Props for the `EnhancedCombobox` component.
|
|
9
|
+
*
|
|
10
|
+
* This component is a fully-featured combobox with optional virtualization,
|
|
11
|
+
* search, and scroll indicators. All `testId*` props are optional and intended
|
|
12
|
+
* to be used only for testing (e.g. `data-testid` attributes).
|
|
13
|
+
*/
|
|
7
14
|
interface EnhancedComboboxProps {
|
|
15
|
+
/** Array of options to show in the list. */
|
|
8
16
|
options: ComboboxOption[];
|
|
17
|
+
/** Currently selected value. */
|
|
9
18
|
value?: string;
|
|
19
|
+
/** Called when the selected value changes. */
|
|
10
20
|
onValueChange: (value: string) => void;
|
|
21
|
+
/** Optional handler invoked when the search text changes. */
|
|
11
22
|
onSearchChange?: (search: string) => void;
|
|
23
|
+
/** Placeholder text shown in the trigger when no option is selected. */
|
|
12
24
|
placeholder?: string;
|
|
25
|
+
/** Placeholder shown inside the search input within the popover. */
|
|
13
26
|
searchPlaceholder?: string;
|
|
27
|
+
/** Text to display when no options are available. */
|
|
14
28
|
emptyText?: string;
|
|
29
|
+
/** Whether the component is in a loading/searching state. */
|
|
15
30
|
loading?: boolean;
|
|
31
|
+
/** Whether the combobox is disabled. */
|
|
16
32
|
disabled?: boolean;
|
|
33
|
+
/** Additional classes to apply to the trigger button. */
|
|
17
34
|
className?: string;
|
|
35
|
+
/** Maximum height of the dropdown list in pixels. */
|
|
18
36
|
maxHeight?: number;
|
|
37
|
+
/** Show gradient scroll indicators at the top/bottom of the list. */
|
|
19
38
|
showScrollIndicators?: boolean;
|
|
39
|
+
/** Number of options above which virtualization is enabled. */
|
|
20
40
|
virtualizeThreshold?: number;
|
|
41
|
+
/** Optional label displayed above the trigger. */
|
|
21
42
|
label?: string;
|
|
43
|
+
/** Whether the field is required. */
|
|
22
44
|
required?: boolean;
|
|
45
|
+
/** `id` applied to the trigger button (also used for label `htmlFor`). */
|
|
23
46
|
id?: string;
|
|
47
|
+
/** Optional informational text displayed below the component. */
|
|
24
48
|
info?: string;
|
|
49
|
+
/** Optional error text displayed below the component (error state). */
|
|
25
50
|
error?: string;
|
|
51
|
+
/** `data-testid` for the trigger button (e.g. `my-combobox-trigger`). */
|
|
52
|
+
testIdTrigger?: string;
|
|
53
|
+
/** `data-testid` for the search input inside the popover. */
|
|
54
|
+
testIdSearchInput?: string;
|
|
55
|
+
/** `data-testid` for the popover content container. */
|
|
56
|
+
testIdPopoverContent?: string;
|
|
57
|
+
/** `data-testid` used on the empty state element (no results). */
|
|
58
|
+
testIdEmpty?: string;
|
|
59
|
+
/** `data-testid` for the list container (scrollable element). */
|
|
60
|
+
testIdList?: string;
|
|
61
|
+
/**
|
|
62
|
+
* Prefix used for option items. Each option will receive a `data-testid`
|
|
63
|
+
* equal to `${testIdOptionPrefix}-${option.value}`. Defaults to
|
|
64
|
+
* `combobox-option` when not provided.
|
|
65
|
+
*/
|
|
66
|
+
testIdOptionPrefix?: string;
|
|
67
|
+
/** `data-testid` for the scroll-up button (when scroll indicators enabled). */
|
|
68
|
+
testIdScrollUp?: string;
|
|
69
|
+
/** `data-testid` for the scroll-down button (when scroll indicators enabled). */
|
|
70
|
+
testIdScrollDown?: string;
|
|
26
71
|
}
|
|
27
|
-
export declare function EnhancedCombobox({ className, disabled, emptyText, error, id, info, label, loading, maxHeight, onSearchChange, onValueChange, options, placeholder, required, searchPlaceholder, showScrollIndicators, value, virtualizeThreshold, }: EnhancedComboboxProps): React.JSX.Element;
|
|
72
|
+
export declare function EnhancedCombobox({ className, disabled, emptyText, error, id, info, label, loading, maxHeight, onSearchChange, onValueChange, options, placeholder, required, searchPlaceholder, showScrollIndicators, value, virtualizeThreshold, testIdTrigger, testIdSearchInput, testIdPopoverContent, testIdEmpty, testIdList, testIdOptionPrefix, testIdScrollUp, testIdScrollDown, }: EnhancedComboboxProps): React.JSX.Element;
|
|
28
73
|
interface CompanyComboboxProps {
|
|
29
74
|
companies: Array<{
|
|
30
75
|
id?: string;
|
|
@@ -45,7 +45,7 @@ var enhanced_label_1 = require("./enhanced-label");
|
|
|
45
45
|
var command_1 = require("./ui/command");
|
|
46
46
|
var popover_1 = require("./ui/popover");
|
|
47
47
|
function VirtualizedList(_a) {
|
|
48
|
-
var options = _a.options, selectedValue = _a.selectedValue, onSelect = _a.onSelect, scrollContainer = _a.scrollContainer;
|
|
48
|
+
var options = _a.options, selectedValue = _a.selectedValue, onSelect = _a.onSelect, scrollContainer = _a.scrollContainer, testIdOptionPrefix = _a.testIdOptionPrefix;
|
|
49
49
|
var _b = (0, react_1.useState)({
|
|
50
50
|
start: 0,
|
|
51
51
|
end: Math.min(options.length, 25), // Increased initial visible items
|
|
@@ -123,13 +123,13 @@ function VirtualizedList(_a) {
|
|
|
123
123
|
var bottomSpacer = Math.max(0, (options.length - safeEnd) * 32);
|
|
124
124
|
return (react_1.default.createElement(react_1.default.Fragment, null,
|
|
125
125
|
topSpacer > 0 && react_1.default.createElement("div", { style: { height: topSpacer } }),
|
|
126
|
-
visibleOptions.map(function (option, index) { return (react_1.default.createElement(command_1.CommandItem, { key: "".concat(option.value, "-").concat(safeStart + index), value: option.label, onSelect: function () { return onSelect(option.value); }, className: "cursor-pointer hover:bg-accent hover:text-accent-foreground transition-colors h-8 flex items-center" },
|
|
126
|
+
visibleOptions.map(function (option, index) { return (react_1.default.createElement(command_1.CommandItem, { key: "".concat(option.value, "-").concat(safeStart + index), value: option.label, onSelect: function () { return onSelect(option.value); }, "data-testid": "".concat(testIdOptionPrefix !== null && testIdOptionPrefix !== void 0 ? testIdOptionPrefix : "combobox-option", "-").concat(option.value), className: "cursor-pointer hover:bg-accent hover:text-accent-foreground transition-colors h-8 flex items-center" },
|
|
127
127
|
react_1.default.createElement(lucide_react_1.Check, { className: (0, utils_1.cn)("mr-2 h-4 w-4", selectedValue === option.value ? "opacity-100" : "opacity-0") }),
|
|
128
128
|
react_1.default.createElement("span", { className: "truncate" }, option.label))); }),
|
|
129
129
|
bottomSpacer > 0 && react_1.default.createElement("div", { style: { height: bottomSpacer } })));
|
|
130
130
|
}
|
|
131
131
|
function EnhancedCombobox(_a) {
|
|
132
|
-
var className = _a.className, _b = _a.disabled, disabled = _b === void 0 ? false : _b, _c = _a.emptyText, emptyText = _c === void 0 ? "No options found." : _c, error = _a.error, id = _a.id, info = _a.info, label = _a.label, _d = _a.loading, loading = _d === void 0 ? false : _d, _e = _a.maxHeight, maxHeight = _e === void 0 ? 256 : _e, onSearchChange = _a.onSearchChange, onValueChange = _a.onValueChange, _f = _a.options, options = _f === void 0 ? [] : _f, _g = _a.placeholder, placeholder = _g === void 0 ? "Select option..." : _g, _h = _a.required, required = _h === void 0 ? false : _h, _j = _a.searchPlaceholder, searchPlaceholder = _j === void 0 ? "Search..." : _j, _k = _a.showScrollIndicators, showScrollIndicators = _k === void 0 ? true : _k, value = _a.value, _l = _a.virtualizeThreshold, virtualizeThreshold = _l === void 0 ? 50 : _l;
|
|
132
|
+
var className = _a.className, _b = _a.disabled, disabled = _b === void 0 ? false : _b, _c = _a.emptyText, emptyText = _c === void 0 ? "No options found." : _c, error = _a.error, id = _a.id, info = _a.info, label = _a.label, _d = _a.loading, loading = _d === void 0 ? false : _d, _e = _a.maxHeight, maxHeight = _e === void 0 ? 256 : _e, onSearchChange = _a.onSearchChange, onValueChange = _a.onValueChange, _f = _a.options, options = _f === void 0 ? [] : _f, _g = _a.placeholder, placeholder = _g === void 0 ? "Select option..." : _g, _h = _a.required, required = _h === void 0 ? false : _h, _j = _a.searchPlaceholder, searchPlaceholder = _j === void 0 ? "Search..." : _j, _k = _a.showScrollIndicators, showScrollIndicators = _k === void 0 ? true : _k, value = _a.value, _l = _a.virtualizeThreshold, virtualizeThreshold = _l === void 0 ? 50 : _l, testIdTrigger = _a.testIdTrigger, testIdSearchInput = _a.testIdSearchInput, testIdPopoverContent = _a.testIdPopoverContent, testIdEmpty = _a.testIdEmpty, testIdList = _a.testIdList, testIdOptionPrefix = _a.testIdOptionPrefix, testIdScrollUp = _a.testIdScrollUp, testIdScrollDown = _a.testIdScrollDown;
|
|
133
133
|
var _m = (0, react_1.useState)(false), open = _m[0], setOpen = _m[1];
|
|
134
134
|
var _o = (0, react_1.useState)(""), searchValue = _o[0], setSearchValue = _o[1];
|
|
135
135
|
var _p = (0, react_1.useState)(false), canScrollUp = _p[0], setCanScrollUp = _p[1];
|
|
@@ -201,30 +201,30 @@ function EnhancedCombobox(_a) {
|
|
|
201
201
|
};
|
|
202
202
|
var comboboxElement = (react_1.default.createElement(popover_1.Popover, { open: open, onOpenChange: setOpen, modal: true },
|
|
203
203
|
react_1.default.createElement(popover_1.PopoverTrigger, { asChild: true },
|
|
204
|
-
react_1.default.createElement(button_1.Button, { id: id, variant: "outline", role: "combobox", "aria-expanded": open, disabled: disabled, className: (0, utils_1.cn)("w-full justify-between", !selectedOption && "text-muted-foreground", className) },
|
|
204
|
+
react_1.default.createElement(button_1.Button, { id: id, "data-testid": testIdTrigger, variant: "outline", role: "combobox", "aria-expanded": open, disabled: disabled, className: (0, utils_1.cn)("w-full justify-between", !selectedOption && "text-muted-foreground", className) },
|
|
205
205
|
(selectedOption === null || selectedOption === void 0 ? void 0 : selectedOption.label) || placeholder,
|
|
206
206
|
react_1.default.createElement(lucide_react_1.ChevronsUpDown, { className: "ml-2 h-4 w-4 shrink-0 opacity-50" }))),
|
|
207
|
-
react_1.default.createElement(popover_1.PopoverContent, { className: "w-[var(--radix-popover-trigger-width)] p-0", side: "bottom", align: "start", avoidCollisions: true, collisionPadding: 8, style: { zIndex: 1000 }, onOpenAutoFocus: function (e) { return e.preventDefault(); } },
|
|
207
|
+
react_1.default.createElement(popover_1.PopoverContent, { "data-testid": testIdPopoverContent, className: "w-[var(--radix-popover-trigger-width)] p-0", side: "bottom", align: "start", avoidCollisions: true, collisionPadding: 8, style: { zIndex: 1000 }, onOpenAutoFocus: function (e) { return e.preventDefault(); } },
|
|
208
208
|
react_1.default.createElement(command_1.Command, { shouldFilter: false },
|
|
209
|
-
react_1.default.createElement(command_1.CommandInput, { "data-slot": "command-input", placeholder: searchPlaceholder, value: searchValue, onValueChange: handleSearchChange }),
|
|
210
|
-
react_1.default.createElement(command_1.CommandEmpty, { "data-slot": "command-empty" }, loading ? (react_1.default.createElement("div", { className: "flex items-center justify-center py-6" },
|
|
209
|
+
react_1.default.createElement(command_1.CommandInput, { "data-slot": "command-input", "data-testid": testIdSearchInput, placeholder: searchPlaceholder, value: searchValue, onValueChange: handleSearchChange }),
|
|
210
|
+
react_1.default.createElement(command_1.CommandEmpty, { "data-slot": "command-empty", "data-testid": testIdEmpty }, loading ? (react_1.default.createElement("div", { className: "flex items-center justify-center py-6" },
|
|
211
211
|
react_1.default.createElement("div", { className: "animate-spin rounded-full h-4 w-4 border-b-2 border-primary" }),
|
|
212
212
|
react_1.default.createElement("span", { className: "ml-2 text-sm" }, "Searching..."))) : (emptyText)),
|
|
213
213
|
react_1.default.createElement("div", { className: "relative" },
|
|
214
214
|
showScrollIndicators && canScrollUp && (react_1.default.createElement("div", { className: "absolute top-0 left-0 right-0 z-10 h-8 bg-gradient-to-b from-background to-transparent pointer-events-none" },
|
|
215
|
-
react_1.default.createElement("button", { onClick: scrollToTop, className: "absolute top-1 left-1/2 transform -translate-x-1/2 p-1 rounded-full bg-background shadow-sm border pointer-events-auto hover:bg-muted transition-colors", "aria-label": "Scroll to top" },
|
|
215
|
+
react_1.default.createElement("button", { "data-testid": testIdScrollUp, onClick: scrollToTop, className: "absolute top-1 left-1/2 transform -translate-x-1/2 p-1 rounded-full bg-background shadow-sm border pointer-events-auto hover:bg-muted transition-colors", "aria-label": "Scroll to top" },
|
|
216
216
|
react_1.default.createElement(lucide_react_1.ChevronUp, { className: "h-3 w-3" })))),
|
|
217
|
-
react_1.default.createElement(command_1.CommandGroup, { ref: scrollContainerRef, className: (0, utils_1.cn)("overflow-y-auto smooth-scroll", "scrollbar-thin scrollbar-thumb-muted-foreground/20 scrollbar-track-transparent hover:scrollbar-thumb-muted-foreground/40", "scroll-smooth", filteredOptions.length > 10 && "pb-2" // Extra padding for many options
|
|
217
|
+
react_1.default.createElement(command_1.CommandGroup, { "data-testid": testIdList, ref: scrollContainerRef, className: (0, utils_1.cn)("overflow-y-auto smooth-scroll", "scrollbar-thin scrollbar-thumb-muted-foreground/20 scrollbar-track-transparent hover:scrollbar-thumb-muted-foreground/40", "scroll-smooth", filteredOptions.length > 10 && "pb-2" // Extra padding for many options
|
|
218
218
|
), style: { maxHeight: "".concat(maxHeight, "px") }, onScroll: updateScrollIndicators }, shouldVirtualize &&
|
|
219
219
|
filteredOptions.length > virtualizeThreshold ? (
|
|
220
220
|
// Virtualized rendering for large lists
|
|
221
|
-
react_1.default.createElement(VirtualizedList, { options: filteredOptions, selectedValue: value, onSelect: handleSelect, scrollContainer: scrollContainerRef })) : (
|
|
221
|
+
react_1.default.createElement(VirtualizedList, { options: filteredOptions, selectedValue: value, onSelect: handleSelect, scrollContainer: scrollContainerRef, testIdOptionPrefix: testIdOptionPrefix })) : (
|
|
222
222
|
// Regular rendering for smaller lists or filtered results
|
|
223
|
-
filteredOptions.map(function (option) { return (react_1.default.createElement(command_1.CommandItem, { key: option.value, value: option.label, onSelect: function () { return handleSelect(option.value); }, className: "cursor-pointer hover:bg-accent hover:text-accent-foreground transition-colors" },
|
|
223
|
+
filteredOptions.map(function (option) { return (react_1.default.createElement(command_1.CommandItem, { key: option.value, value: option.label, onSelect: function () { return handleSelect(option.value); }, "data-testid": "".concat(testIdOptionPrefix !== null && testIdOptionPrefix !== void 0 ? testIdOptionPrefix : "combobox-option", "-").concat(option.value), className: "cursor-pointer hover:bg-accent hover:text-accent-foreground transition-colors" },
|
|
224
224
|
react_1.default.createElement(lucide_react_1.Check, { className: (0, utils_1.cn)("mr-2 h-4 w-4", value === option.value ? "opacity-100" : "opacity-0") }),
|
|
225
225
|
react_1.default.createElement("span", { className: "truncate" }, option.label))); }))),
|
|
226
226
|
showScrollIndicators && canScrollDown && (react_1.default.createElement("div", { className: "absolute bottom-0 left-0 right-0 z-10 h-8 bg-gradient-to-t from-background to-transparent pointer-events-none" },
|
|
227
|
-
react_1.default.createElement("button", { onClick: scrollToBottom, className: "absolute bottom-1 left-1/2 transform -translate-x-1/2 p-1 rounded-full bg-background shadow-sm border pointer-events-auto hover:bg-muted transition-colors", "aria-label": "Scroll to bottom" },
|
|
227
|
+
react_1.default.createElement("button", { "data-testid": testIdScrollDown, onClick: scrollToBottom, className: "absolute bottom-1 left-1/2 transform -translate-x-1/2 p-1 rounded-full bg-background shadow-sm border pointer-events-auto hover:bg-muted transition-colors", "aria-label": "Scroll to bottom" },
|
|
228
228
|
react_1.default.createElement(lucide_react_1.ChevronDown, { className: "h-3 w-3" })))))))));
|
|
229
229
|
// If label is provided, render the complete combobox with label structure
|
|
230
230
|
if (label) {
|
|
@@ -1,21 +1,63 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import type { DropzoneOptions } from "react-dropzone";
|
|
3
|
+
/**
|
|
4
|
+
* Props for `EnhancedDropzone` component.
|
|
5
|
+
*/
|
|
3
6
|
export type EnhancedDropzoneProps = {
|
|
7
|
+
/** HTML id attribute applied to the hidden file input and used for labeling. */
|
|
4
8
|
id?: string;
|
|
9
|
+
/** Additional className(s) applied to the root container. */
|
|
5
10
|
className?: string;
|
|
11
|
+
/** Optional label text displayed above the dropzone. */
|
|
6
12
|
label?: string;
|
|
13
|
+
/** Informational helper text shown below the component (non-error). */
|
|
7
14
|
info?: string;
|
|
15
|
+
/** Error message text shown below the component; puts component into error state. */
|
|
8
16
|
error?: string;
|
|
17
|
+
/**
|
|
18
|
+
* Accepted file types. Matches `react-dropzone` `accept` option or a list of
|
|
19
|
+
* mime types / extensions (e.g. `['image/*']` or `{ 'image/*': [] }`).
|
|
20
|
+
*/
|
|
9
21
|
accept?: DropzoneOptions["accept"] | string[];
|
|
22
|
+
/** Maximum number of files allowed to be selected. Defaults to `10`. */
|
|
10
23
|
maxFiles?: number;
|
|
24
|
+
/** Maximum file size in bytes. */
|
|
11
25
|
maxSize?: number;
|
|
26
|
+
/** Minimum file size in bytes. */
|
|
12
27
|
minSize?: number;
|
|
28
|
+
/** Whether the dropzone is disabled (prevents interactions). */
|
|
13
29
|
disabled?: boolean;
|
|
14
|
-
/** Remote image URLs to display as previews */
|
|
30
|
+
/** Remote image URLs to display as previews (read-only remote values). */
|
|
15
31
|
value?: string[];
|
|
16
|
-
/** Called when files
|
|
32
|
+
/** Called when the selected files change (local additions/removals). */
|
|
17
33
|
onChange?: (files: File[]) => void;
|
|
18
|
-
/** Called when a remote URL is removed */
|
|
34
|
+
/** Called when a remote URL preview is removed by the user. */
|
|
19
35
|
onRemoveRemote?: (url: string) => void;
|
|
36
|
+
/** `data-testid` for the root dropzone container. */
|
|
37
|
+
testIdDropzone?: string;
|
|
38
|
+
/** `data-testid` for the hidden file input element. */
|
|
39
|
+
testIdInput?: string;
|
|
40
|
+
/** `data-testid` for the carousel previous button. */
|
|
41
|
+
testIdPrev?: string;
|
|
42
|
+
/** `data-testid` for the carousel next button. */
|
|
43
|
+
testIdNext?: string;
|
|
44
|
+
/** Prefix used for preview items: `${prefix}-${index}`. */
|
|
45
|
+
testIdPreviewPrefix?: string;
|
|
46
|
+
/** Prefix for preview image elements: `${prefix}-${index}`. */
|
|
47
|
+
testIdImagePrefix?: string;
|
|
48
|
+
/** Prefix for remove buttons on previews: `${prefix}-${index}`. */
|
|
49
|
+
testIdRemovePrefix?: string;
|
|
50
|
+
/** `data-testid` for the preview count text element. */
|
|
51
|
+
testIdCount?: string;
|
|
52
|
+
/** `data-testid` for the empty-state icon wrapper. */
|
|
53
|
+
testIdEmptyIcon?: string;
|
|
54
|
+
/** `data-testid` for the empty-state title. */
|
|
55
|
+
testIdEmptyTitle?: string;
|
|
56
|
+
/** `data-testid` for the empty-state subtitle. */
|
|
57
|
+
testIdEmptySubtitle?: string;
|
|
58
|
+
/** `data-testid` for the empty-state note (max files info). */
|
|
59
|
+
testIdEmptyNote?: string;
|
|
60
|
+
/** `data-testid` for the error/info message container. */
|
|
61
|
+
testIdMessage?: string;
|
|
20
62
|
};
|
|
21
63
|
export declare const EnhancedDropzone: React.FC<EnhancedDropzoneProps>;
|
|
@@ -62,7 +62,7 @@ var carousel_1 = require("./ui/carousel");
|
|
|
62
62
|
var button_1 = require("./ui/button");
|
|
63
63
|
var lucide_react_1 = require("lucide-react");
|
|
64
64
|
var EnhancedDropzone = function (_a) {
|
|
65
|
-
var id = _a.id, label = _a.label, info = _a.info, error = _a.error, accept = _a.accept, _b = _a.maxFiles, maxFiles = _b === void 0 ? 10 : _b, maxSize = _a.maxSize, minSize = _a.minSize, disabled = _a.disabled, _c = _a.value, value = _c === void 0 ? [] : _c, onChange = _a.onChange, onRemoveRemote = _a.onRemoveRemote, className = _a.className;
|
|
65
|
+
var id = _a.id, label = _a.label, info = _a.info, error = _a.error, accept = _a.accept, _b = _a.maxFiles, maxFiles = _b === void 0 ? 10 : _b, maxSize = _a.maxSize, minSize = _a.minSize, disabled = _a.disabled, _c = _a.value, value = _c === void 0 ? [] : _c, onChange = _a.onChange, onRemoveRemote = _a.onRemoveRemote, className = _a.className, testIdDropzone = _a.testIdDropzone, testIdInput = _a.testIdInput, testIdPrev = _a.testIdPrev, testIdNext = _a.testIdNext, testIdPreviewPrefix = _a.testIdPreviewPrefix, testIdImagePrefix = _a.testIdImagePrefix, testIdRemovePrefix = _a.testIdRemovePrefix, testIdCount = _a.testIdCount, testIdEmptyIcon = _a.testIdEmptyIcon, testIdEmptyTitle = _a.testIdEmptyTitle, testIdEmptySubtitle = _a.testIdEmptySubtitle, testIdEmptyNote = _a.testIdEmptyNote, testIdMessage = _a.testIdMessage;
|
|
66
66
|
// Local files selected by user
|
|
67
67
|
var _d = (0, react_1.useState)([]), localFiles = _d[0], setLocalFiles = _d[1];
|
|
68
68
|
// Track object URLs created for local files
|
|
@@ -139,18 +139,18 @@ var EnhancedDropzone = function (_a) {
|
|
|
139
139
|
url: localPreviewsRef.current.get(file) || "",
|
|
140
140
|
index: index,
|
|
141
141
|
}); }), true);
|
|
142
|
-
return (react_1.default.createElement("div", { className: (0, utils_1.cn)("w-full", className) },
|
|
142
|
+
return (react_1.default.createElement("div", { className: (0, utils_1.cn)("w-full", className), "data-testid": testIdDropzone },
|
|
143
143
|
label && (react_1.default.createElement("label", { className: "mb-2 block text-sm font-medium" }, label)),
|
|
144
144
|
react_1.default.createElement("div", __assign({}, getRootProps(), { className: (0, utils_1.cn)("relative w-full rounded-md border border-dashed p-6 text-center min-h-[280px] flex items-center justify-center", isDragActive && "ring-2 ring-ring ring-offset-2", disabled && "opacity-60 pointer-events-none") }),
|
|
145
|
-
react_1.default.createElement("input", __assign({}, getInputProps(), { id: id })),
|
|
145
|
+
react_1.default.createElement("input", __assign({}, getInputProps(), { id: id, "data-testid": testIdInput })),
|
|
146
146
|
allPreviews.length > 0 ? (react_1.default.createElement("div", { className: "flex flex-col items-center w-full" },
|
|
147
147
|
react_1.default.createElement("div", { className: "relative w-full max-w-md" },
|
|
148
148
|
react_1.default.createElement(carousel_1.Carousel, { className: "w-full" },
|
|
149
|
-
react_1.default.createElement(carousel_1.CarouselPrevious, { type: "button", onClick: function (e) { return e.stopPropagation(); }, onPointerDown: function (e) { return e.stopPropagation(); }, onMouseDown: function (e) { return e.stopPropagation(); } }),
|
|
150
|
-
react_1.default.createElement(carousel_1.CarouselNext, { type: "button", onClick: function (e) { return e.stopPropagation(); }, onPointerDown: function (e) { return e.stopPropagation(); }, onMouseDown: function (e) { return e.stopPropagation(); } }),
|
|
151
|
-
react_1.default.createElement(carousel_1.CarouselContent, { className: "ml-0" }, allPreviews.map(function (preview, idx) { return (react_1.default.createElement(carousel_1.CarouselItem, { key: "".concat(preview.type, "-").concat(preview.url, "-").concat(idx), className: "pl-4" },
|
|
149
|
+
react_1.default.createElement(carousel_1.CarouselPrevious, { type: "button", onClick: function (e) { return e.stopPropagation(); }, onPointerDown: function (e) { return e.stopPropagation(); }, onMouseDown: function (e) { return e.stopPropagation(); }, "data-testid": testIdPrev }),
|
|
150
|
+
react_1.default.createElement(carousel_1.CarouselNext, { type: "button", onClick: function (e) { return e.stopPropagation(); }, onPointerDown: function (e) { return e.stopPropagation(); }, onMouseDown: function (e) { return e.stopPropagation(); }, "data-testid": testIdNext }),
|
|
151
|
+
react_1.default.createElement(carousel_1.CarouselContent, { className: "ml-0" }, allPreviews.map(function (preview, idx) { return (react_1.default.createElement(carousel_1.CarouselItem, { key: "".concat(preview.type, "-").concat(preview.url, "-").concat(idx), className: "pl-4", "data-testid": "".concat(testIdPreviewPrefix !== null && testIdPreviewPrefix !== void 0 ? testIdPreviewPrefix : "dropzone-preview", "-").concat(idx) },
|
|
152
152
|
react_1.default.createElement("div", { className: "relative aspect-square w-full max-w-xs mx-auto" }, preview.url ? (react_1.default.createElement(react_1.default.Fragment, null,
|
|
153
|
-
react_1.default.createElement("img", { src: preview.url, alt: "Preview ".concat(idx + 1), className: "h-full w-full rounded-lg object-cover", onClick: function (e) { return e.stopPropagation(); } }),
|
|
153
|
+
react_1.default.createElement("img", { src: preview.url, alt: "Preview ".concat(idx + 1), className: "h-full w-full rounded-lg object-cover", onClick: function (e) { return e.stopPropagation(); }, "data-testid": "".concat(testIdImagePrefix !== null && testIdImagePrefix !== void 0 ? testIdImagePrefix : "dropzone-image", "-").concat(idx) }),
|
|
154
154
|
react_1.default.createElement(button_1.Button, { type: "button", size: "icon", variant: "destructive", onClick: function (e) {
|
|
155
155
|
e.stopPropagation();
|
|
156
156
|
if (preview.type === "remote") {
|
|
@@ -159,29 +159,29 @@ var EnhancedDropzone = function (_a) {
|
|
|
159
159
|
else {
|
|
160
160
|
handleRemoveLocal(preview.index);
|
|
161
161
|
}
|
|
162
|
-
}, className: "absolute right-2 top-2 h-8 w-8 rounded-full", "aria-label": "Remove image" },
|
|
162
|
+
}, className: "absolute right-2 top-2 h-8 w-8 rounded-full", "aria-label": "Remove image", "data-testid": "".concat(testIdRemovePrefix !== null && testIdRemovePrefix !== void 0 ? testIdRemovePrefix : "dropzone-remove", "-").concat(idx) },
|
|
163
163
|
react_1.default.createElement(lucide_react_1.XIcon, { className: "h-4 w-4" })))) : (react_1.default.createElement("div", { className: "flex h-full w-full items-center justify-center rounded-lg bg-muted text-muted-foreground" },
|
|
164
164
|
react_1.default.createElement("span", { className: "text-sm" }, "Loading...")))))); })))),
|
|
165
|
-
react_1.default.createElement("p", { className: "mt-4 text-sm font-medium text-muted-foreground" },
|
|
165
|
+
react_1.default.createElement("p", { className: "mt-4 text-sm font-medium text-muted-foreground", "data-testid": testIdCount },
|
|
166
166
|
allPreviews.length,
|
|
167
167
|
" image",
|
|
168
168
|
allPreviews.length !== 1 ? "s" : "",
|
|
169
169
|
" ",
|
|
170
170
|
"selected"))) : (react_1.default.createElement("div", { className: "flex flex-col items-center justify-center gap-2" },
|
|
171
|
-
react_1.default.createElement("div", { className: "flex h-12 w-12 items-center justify-center rounded-lg bg-muted text-muted-foreground" },
|
|
171
|
+
react_1.default.createElement("div", { className: "flex h-12 w-12 items-center justify-center rounded-lg bg-muted text-muted-foreground", "data-testid": testIdEmptyIcon },
|
|
172
172
|
react_1.default.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "lucide lucide-image" },
|
|
173
173
|
react_1.default.createElement("rect", { width: "18", height: "18", x: "3", y: "3", rx: "2", ry: "2" }),
|
|
174
174
|
react_1.default.createElement("circle", { cx: "9", cy: "9", r: "2" }),
|
|
175
175
|
react_1.default.createElement("path", { d: "m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21" }))),
|
|
176
176
|
react_1.default.createElement("div", { className: "space-y-1 text-center" },
|
|
177
|
-
react_1.default.createElement("p", { className: "font-medium text-sm" },
|
|
177
|
+
react_1.default.createElement("p", { className: "font-medium text-sm", "data-testid": testIdEmptyTitle },
|
|
178
178
|
"Upload ",
|
|
179
179
|
maxFiles === 1 ? "an image" : "images"),
|
|
180
|
-
react_1.default.createElement("p", { className: "text-muted-foreground text-xs" }, "Drag and drop or click to browse"),
|
|
181
|
-
maxFiles > 1 && (react_1.default.createElement("p", { className: "text-muted-foreground text-xs" },
|
|
180
|
+
react_1.default.createElement("p", { className: "text-muted-foreground text-xs", "data-testid": testIdEmptySubtitle }, "Drag and drop or click to browse"),
|
|
181
|
+
maxFiles > 1 && (react_1.default.createElement("p", { className: "text-muted-foreground text-xs", "data-testid": testIdEmptyNote },
|
|
182
182
|
"Up to ",
|
|
183
183
|
maxFiles,
|
|
184
184
|
" files")))))),
|
|
185
|
-
(error || info) && (react_1.default.createElement("div", { className: "mt-2" }, error ? (react_1.default.createElement("p", { className: "text-xs text-destructive" }, error)) : info ? (react_1.default.createElement("p", { className: "text-xs text-blue-600 dark:text-blue-400" }, info)) : null))));
|
|
185
|
+
(error || info) && (react_1.default.createElement("div", { className: "mt-2", "data-testid": testIdMessage }, error ? (react_1.default.createElement("p", { className: "text-xs text-destructive" }, error)) : info ? (react_1.default.createElement("p", { className: "text-xs text-blue-600 dark:text-blue-400" }, info)) : null))));
|
|
186
186
|
};
|
|
187
187
|
exports.EnhancedDropzone = EnhancedDropzone;
|
|
@@ -1,8 +1,24 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
+
/** Props for `EnhancedInput` component. */
|
|
2
3
|
interface EnhancedInputProps extends React.ComponentProps<"input"> {
|
|
4
|
+
/** Error message text shown below the input; sets error styling when present. */
|
|
3
5
|
error?: string;
|
|
6
|
+
/** Informational helper text shown below the input (when no error). */
|
|
4
7
|
info?: string;
|
|
8
|
+
/** Optional label text displayed above the input. */
|
|
5
9
|
label?: string;
|
|
10
|
+
/** `data-testid` for the root wrapper (the outermost `div`). */
|
|
11
|
+
testIdWrapper?: string;
|
|
12
|
+
/** `data-testid` for the native `input` element. */
|
|
13
|
+
testIdInput?: string;
|
|
14
|
+
/** `data-testid` for the label element (passes to `EnhancedLabel`). */
|
|
15
|
+
testIdLabel?: string;
|
|
16
|
+
/** `data-testid` for the message container (holds error/info). */
|
|
17
|
+
testIdMessage?: string;
|
|
18
|
+
/** `data-testid` for the error text element. */
|
|
19
|
+
testIdError?: string;
|
|
20
|
+
/** `data-testid` for the info text element. */
|
|
21
|
+
testIdInfo?: string;
|
|
6
22
|
}
|
|
7
23
|
declare const EnhancedInput: React.ForwardRefExoticComponent<Omit<EnhancedInputProps, "ref"> & React.RefAttributes<HTMLInputElement>>;
|
|
8
24
|
export { EnhancedInput };
|
|
@@ -61,10 +61,10 @@ var utils_1 = require("../lib/utils");
|
|
|
61
61
|
var enhanced_label_1 = require("./enhanced-label");
|
|
62
62
|
var input_1 = require("./ui/input");
|
|
63
63
|
var EnhancedInput = React.forwardRef(function (_a, ref) {
|
|
64
|
-
var className = _a.className, type = _a.type, error = _a.error, info = _a.info, label = _a.label, required = _a.required, id = _a.id, props = __rest(_a, ["className", "type", "error", "info", "label", "required", "id"]);
|
|
64
|
+
var className = _a.className, type = _a.type, error = _a.error, info = _a.info, label = _a.label, required = _a.required, id = _a.id, testIdWrapper = _a.testIdWrapper, testIdInput = _a.testIdInput, testIdLabel = _a.testIdLabel, testIdMessage = _a.testIdMessage, testIdError = _a.testIdError, testIdInfo = _a.testIdInfo, props = __rest(_a, ["className", "type", "error", "info", "label", "required", "id", "testIdWrapper", "testIdInput", "testIdLabel", "testIdMessage", "testIdError", "testIdInfo"]);
|
|
65
65
|
// Determine if there's an error (for aria-invalid and styling)
|
|
66
66
|
var hasError = Boolean(error);
|
|
67
|
-
var inputElement = (React.createElement(input_1.Input, __assign({ type: type, ref: ref, id: id, "aria-invalid": hasError, required: required, className: (0, utils_1.cn)(
|
|
67
|
+
var inputElement = (React.createElement(input_1.Input, __assign({ type: type, ref: ref, id: id, "aria-invalid": hasError, required: required, "data-testid": testIdInput, className: (0, utils_1.cn)(
|
|
68
68
|
// Error state styling
|
|
69
69
|
hasError &&
|
|
70
70
|
"border-destructive focus-visible:border-destructive focus-visible:ring-destructive/20",
|
|
@@ -73,15 +73,15 @@ var EnhancedInput = React.forwardRef(function (_a, ref) {
|
|
|
73
73
|
"aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive", className) }, props)));
|
|
74
74
|
// If label is provided, render the complete input with label structure
|
|
75
75
|
if (label) {
|
|
76
|
-
return (React.createElement("div", { className: "w-full space-y-2" },
|
|
77
|
-
React.createElement(enhanced_label_1.EnhancedLabel, { htmlFor: id, required: required }, label),
|
|
76
|
+
return (React.createElement("div", { className: "w-full space-y-2", "data-testid": testIdWrapper },
|
|
77
|
+
React.createElement(enhanced_label_1.EnhancedLabel, { htmlFor: id, required: required, "data-testid": testIdLabel }, label),
|
|
78
78
|
inputElement,
|
|
79
|
-
(error || info) && (React.createElement("div",
|
|
79
|
+
(error || info) && (React.createElement("div", { "data-testid": testIdMessage }, error ? (React.createElement("p", { className: "text-xs text-destructive", "data-testid": testIdError }, error)) : info ? (React.createElement("p", { className: "text-xs text-blue-600 dark:text-blue-400", "data-testid": testIdInfo }, info)) : null))));
|
|
80
80
|
}
|
|
81
81
|
// If no label, render just the input with messages (backward compatibility)
|
|
82
|
-
return (React.createElement("div", { className: "w-full" },
|
|
82
|
+
return (React.createElement("div", { className: "w-full", "data-testid": testIdWrapper },
|
|
83
83
|
inputElement,
|
|
84
|
-
(error || info) && (React.createElement("div",
|
|
84
|
+
(error || info) && (React.createElement("div", { "data-testid": testIdMessage }, error ? (React.createElement("p", { className: "text-xs text-destructive", "data-testid": testIdError }, error)) : info ? (React.createElement("p", { className: "text-xs text-blue-600 dark:text-blue-400", "data-testid": testIdInfo }, info)) : null))));
|
|
85
85
|
});
|
|
86
86
|
exports.EnhancedInput = EnhancedInput;
|
|
87
87
|
EnhancedInput.displayName = "EnhancedInput";
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import * as LabelPrimitive from "@radix-ui/react-label";
|
|
3
|
+
/** Props for `EnhancedLabel` component. */
|
|
3
4
|
interface EnhancedLabelProps extends React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> {
|
|
5
|
+
/** Show a required field indicator (asterisk). */
|
|
4
6
|
required?: boolean;
|
|
7
|
+
/** `data-testid` for the root label element. */
|
|
8
|
+
testIdLabel?: string;
|
|
9
|
+
/** `data-testid` for the required asterisk element when `required` is true. */
|
|
10
|
+
testIdRequired?: string;
|
|
5
11
|
}
|
|
6
|
-
declare function EnhancedLabel({ className, required, children, ...props }: EnhancedLabelProps): React.JSX.Element;
|
|
12
|
+
declare function EnhancedLabel({ className, required, children, testIdLabel, testIdRequired, ...props }: EnhancedLabelProps): React.JSX.Element;
|
|
7
13
|
export { EnhancedLabel };
|
|
@@ -61,8 +61,8 @@ var React = __importStar(require("react"));
|
|
|
61
61
|
var utils_1 = require("../lib/utils");
|
|
62
62
|
var label_1 = require("./ui/label");
|
|
63
63
|
function EnhancedLabel(_a) {
|
|
64
|
-
var className = _a.className, _b = _a.required, required = _b === void 0 ? false : _b, children = _a.children, props = __rest(_a, ["className", "required", "children"]);
|
|
65
|
-
return (React.createElement(label_1.Label, __assign({ "data-slot": "label", className: (0, utils_1.cn)("flex items-center gap-1 select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 min-h-5", className) }, props),
|
|
64
|
+
var className = _a.className, _b = _a.required, required = _b === void 0 ? false : _b, children = _a.children, testIdLabel = _a.testIdLabel, testIdRequired = _a.testIdRequired, props = __rest(_a, ["className", "required", "children", "testIdLabel", "testIdRequired"]);
|
|
65
|
+
return (React.createElement(label_1.Label, __assign({ "data-slot": "label", "data-testid": testIdLabel, className: (0, utils_1.cn)("flex items-center gap-1 select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 min-h-5", className) }, props),
|
|
66
66
|
children,
|
|
67
|
-
required && (React.createElement("span", { className: "text-destructive text-sm", "aria-label": "required" }, "*"))));
|
|
67
|
+
required && (React.createElement("span", { className: "text-destructive text-sm", "aria-label": "required", "data-testid": testIdRequired }, "*"))));
|
|
68
68
|
}
|
|
@@ -1,25 +1,54 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import * as SelectPrimitive from "@radix-ui/react-select";
|
|
3
|
+
/** Props for `EnhancedSelect` wrapper component. */
|
|
3
4
|
interface EnhancedSelectProps {
|
|
5
|
+
/** Error message text shown below the select; sets error styling when present. */
|
|
4
6
|
error?: string;
|
|
7
|
+
/** Informational helper text shown below the select (when no error). */
|
|
5
8
|
info?: string;
|
|
9
|
+
/** Optional label text displayed above the select. */
|
|
6
10
|
label?: string;
|
|
11
|
+
/** Whether the field is required (adds required indicator to label). */
|
|
7
12
|
required?: boolean;
|
|
13
|
+
/** HTML id used for labeling and accessibility. */
|
|
8
14
|
id?: string;
|
|
15
|
+
/** Child nodes, typically `SelectTrigger` and `SelectContent`/items. */
|
|
9
16
|
children?: React.ReactNode;
|
|
17
|
+
/** Controlled selected value. */
|
|
10
18
|
value?: string;
|
|
19
|
+
/** Uncontrolled initial value. */
|
|
11
20
|
defaultValue?: string;
|
|
21
|
+
/** Callback fired when the selected value changes. */
|
|
12
22
|
onValueChange?: (value: string) => void;
|
|
23
|
+
/** Disable the select input and interactions. */
|
|
13
24
|
disabled?: boolean;
|
|
25
|
+
/** Name attribute for form submissions. */
|
|
14
26
|
name?: string;
|
|
27
|
+
/** Text direction for the select: left-to-right or right-to-left. */
|
|
15
28
|
dir?: "ltr" | "rtl";
|
|
29
|
+
/** Control the open state of the select popup. */
|
|
16
30
|
open?: boolean;
|
|
31
|
+
/** Uncontrolled initial open state. */
|
|
17
32
|
defaultOpen?: boolean;
|
|
33
|
+
/** Called when the open state changes. */
|
|
18
34
|
onOpenChange?: (open: boolean) => void;
|
|
35
|
+
/** `data-testid` for the root wrapper (outermost `div`). */
|
|
36
|
+
testIdWrapper?: string;
|
|
37
|
+
/** `data-testid` forwarded to the `EnhancedLabel` component. */
|
|
38
|
+
testIdLabel?: string;
|
|
39
|
+
/** `data-testid` for the message container (holds error/info). */
|
|
40
|
+
testIdMessage?: string;
|
|
41
|
+
/** `data-testid` for the error text element. */
|
|
42
|
+
testIdError?: string;
|
|
43
|
+
/** `data-testid` for the info text element. */
|
|
44
|
+
testIdInfo?: string;
|
|
19
45
|
}
|
|
20
46
|
interface EnhancedSelectTriggerProps extends React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger> {
|
|
47
|
+
/** Error text used to style the trigger when present. */
|
|
21
48
|
error?: string;
|
|
49
|
+
/** `data-testid` for the trigger (the interactive button). */
|
|
50
|
+
testIdTrigger?: string;
|
|
22
51
|
}
|
|
23
|
-
declare const EnhancedSelect: ({ error, info, label, required, id, children, ...selectProps }: EnhancedSelectProps) => React.JSX.Element;
|
|
52
|
+
declare const EnhancedSelect: ({ error, info, label, required, id, children, testIdWrapper, testIdLabel, testIdMessage, testIdError, testIdInfo, ...selectProps }: EnhancedSelectProps) => React.JSX.Element;
|
|
24
53
|
declare const EnhancedSelectTrigger: React.ForwardRefExoticComponent<EnhancedSelectTriggerProps & React.RefAttributes<HTMLButtonElement>>;
|
|
25
54
|
export { EnhancedSelect, EnhancedSelectTrigger };
|
|
@@ -62,11 +62,11 @@ var utils_1 = require("../lib/utils");
|
|
|
62
62
|
var select_1 = require("./ui/select");
|
|
63
63
|
var enhanced_label_1 = require("./enhanced-label");
|
|
64
64
|
var EnhancedSelect = function (_a) {
|
|
65
|
-
var error = _a.error, info = _a.info, label = _a.label, required = _a.required, id = _a.id, children = _a.children, selectProps = __rest(_a, ["error", "info", "label", "required", "id", "children"]);
|
|
66
|
-
return (React.createElement("div", { className: "w-full space-y-2" },
|
|
67
|
-
label && (React.createElement(enhanced_label_1.EnhancedLabel, { htmlFor: id, required: required }, label)),
|
|
65
|
+
var error = _a.error, info = _a.info, label = _a.label, required = _a.required, id = _a.id, children = _a.children, testIdWrapper = _a.testIdWrapper, testIdLabel = _a.testIdLabel, testIdMessage = _a.testIdMessage, testIdError = _a.testIdError, testIdInfo = _a.testIdInfo, selectProps = __rest(_a, ["error", "info", "label", "required", "id", "children", "testIdWrapper", "testIdLabel", "testIdMessage", "testIdError", "testIdInfo"]);
|
|
66
|
+
return (React.createElement("div", { className: "w-full space-y-2", "data-testid": testIdWrapper },
|
|
67
|
+
label && (React.createElement(enhanced_label_1.EnhancedLabel, { htmlFor: id, required: required, testIdLabel: testIdLabel }, label)),
|
|
68
68
|
React.createElement(select_1.Select, __assign({}, selectProps), children),
|
|
69
|
-
(error || info) && (React.createElement("div",
|
|
69
|
+
(error || info) && (React.createElement("div", { "data-testid": testIdMessage }, error ? (React.createElement("p", { className: "text-xs text-destructive", "data-testid": testIdError }, error)) : info ? (React.createElement("p", { className: "text-xs text-blue-600 dark:text-blue-400", "data-testid": testIdInfo }, info)) : null))));
|
|
70
70
|
};
|
|
71
71
|
exports.EnhancedSelect = EnhancedSelect;
|
|
72
72
|
var EnhancedSelectTrigger = React.forwardRef(function (_a, ref) {
|
|
@@ -1,10 +1,31 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import * as SwitchPrimitives from "@radix-ui/react-switch";
|
|
3
|
+
/** Props for `EnhancedSwitch` component. */
|
|
3
4
|
interface EnhancedSwitchProps extends React.ComponentPropsWithoutRef<typeof SwitchPrimitives.Root> {
|
|
5
|
+
/** Error message text shown below the switch; sets error styling when present. */
|
|
4
6
|
error?: string;
|
|
7
|
+
/** Informational helper text shown below the switch (when no error). */
|
|
5
8
|
info?: string;
|
|
9
|
+
/** Optional label text displayed beside the switch. */
|
|
6
10
|
label?: string;
|
|
11
|
+
/** Optional description text shown under the label. */
|
|
7
12
|
description?: string;
|
|
13
|
+
/** `data-testid` for the root wrapper (outermost `div`). */
|
|
14
|
+
testIdWrapper?: string;
|
|
15
|
+
/** `data-testid` forwarded to the `EnhancedLabel` component. */
|
|
16
|
+
testIdLabel?: string;
|
|
17
|
+
/** `data-testid` for the switch root element. */
|
|
18
|
+
testIdSwitch?: string;
|
|
19
|
+
/** `data-testid` for the switch thumb element. */
|
|
20
|
+
testIdThumb?: string;
|
|
21
|
+
/** `data-testid` for the description paragraph. */
|
|
22
|
+
testIdDescription?: string;
|
|
23
|
+
/** `data-testid` for the message container (holds error/info). */
|
|
24
|
+
testIdMessage?: string;
|
|
25
|
+
/** `data-testid` for the error text element. */
|
|
26
|
+
testIdError?: string;
|
|
27
|
+
/** `data-testid` for the info text element. */
|
|
28
|
+
testIdInfo?: string;
|
|
8
29
|
}
|
|
9
30
|
declare const EnhancedSwitch: React.ForwardRefExoticComponent<EnhancedSwitchProps & React.RefAttributes<HTMLButtonElement>>;
|
|
10
31
|
export { EnhancedSwitch };
|
|
@@ -62,28 +62,28 @@ var SwitchPrimitives = __importStar(require("@radix-ui/react-switch"));
|
|
|
62
62
|
var utils_1 = require("../lib/utils");
|
|
63
63
|
var enhanced_label_1 = require("./enhanced-label");
|
|
64
64
|
var EnhancedSwitch = React.forwardRef(function (_a, ref) {
|
|
65
|
-
var className = _a.className, error = _a.error, info = _a.info, label = _a.label, required = _a.required, id = _a.id, description = _a.description, props = __rest(_a, ["className", "error", "info", "label", "required", "id", "description"]);
|
|
65
|
+
var className = _a.className, error = _a.error, info = _a.info, label = _a.label, required = _a.required, id = _a.id, description = _a.description, testIdWrapper = _a.testIdWrapper, testIdLabel = _a.testIdLabel, testIdSwitch = _a.testIdSwitch, testIdThumb = _a.testIdThumb, testIdDescription = _a.testIdDescription, testIdMessage = _a.testIdMessage, testIdError = _a.testIdError, testIdInfo = _a.testIdInfo, props = __rest(_a, ["className", "error", "info", "label", "required", "id", "description", "testIdWrapper", "testIdLabel", "testIdSwitch", "testIdThumb", "testIdDescription", "testIdMessage", "testIdError", "testIdInfo"]);
|
|
66
66
|
// Determine if there's an error (for aria-invalid and styling)
|
|
67
67
|
var hasError = Boolean(error);
|
|
68
|
-
var switchElement = (React.createElement(SwitchPrimitives.Root, __assign({ ref: ref, id: id, "data-slot": "switch", "aria-invalid": hasError, required: required, className: (0, utils_1.cn)("peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input",
|
|
68
|
+
var switchElement = (React.createElement(SwitchPrimitives.Root, __assign({ ref: ref, id: id, "data-slot": "switch", "data-testid": testIdSwitch, "aria-invalid": hasError, required: required, className: (0, utils_1.cn)("peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input",
|
|
69
69
|
// Error state styling
|
|
70
70
|
hasError &&
|
|
71
71
|
"data-[state=checked]:bg-destructive data-[state=unchecked]:bg-destructive/20 border-destructive focus-visible:border-destructive focus-visible:ring-destructive/20", className) }, props),
|
|
72
|
-
React.createElement(SwitchPrimitives.Thumb, { "data-slot": "switch-thumb", className: (0, utils_1.cn)("pointer-events-none block h-4 w-4 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0") })));
|
|
72
|
+
React.createElement(SwitchPrimitives.Thumb, { "data-slot": "switch-thumb", "data-testid": testIdThumb, className: (0, utils_1.cn)("pointer-events-none block h-4 w-4 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0") })));
|
|
73
73
|
// If label is provided, render the complete switch with label structure
|
|
74
74
|
if (label) {
|
|
75
|
-
return (React.createElement("div", { className: "w-full space-y-2" },
|
|
75
|
+
return (React.createElement("div", { className: "w-full space-y-2", "data-testid": testIdWrapper },
|
|
76
76
|
React.createElement("div", { className: "flex items-center justify-between space-x-2" },
|
|
77
77
|
React.createElement("div", null,
|
|
78
|
-
React.createElement(enhanced_label_1.EnhancedLabel, { htmlFor: id, required: required }, label),
|
|
79
|
-
description && (React.createElement("p", { className: "text-sm text-gray-400" }, description))),
|
|
78
|
+
React.createElement(enhanced_label_1.EnhancedLabel, { htmlFor: id, required: required, testIdLabel: testIdLabel }, label),
|
|
79
|
+
description && (React.createElement("p", { className: "text-sm text-gray-400", "data-testid": testIdDescription }, description))),
|
|
80
80
|
switchElement),
|
|
81
|
-
(error || info) && (React.createElement("div",
|
|
81
|
+
(error || info) && (React.createElement("div", { "data-testid": testIdMessage }, error ? (React.createElement("p", { className: "text-xs text-destructive", "data-testid": testIdError }, error)) : info ? (React.createElement("p", { className: "text-xs text-blue-600 dark:text-blue-400", "data-testid": testIdInfo }, info)) : null))));
|
|
82
82
|
}
|
|
83
83
|
// If no label, render just the switch with messages (backward compatibility)
|
|
84
|
-
return (React.createElement("div", { className: "w-full" },
|
|
84
|
+
return (React.createElement("div", { className: "w-full", "data-testid": testIdWrapper },
|
|
85
85
|
switchElement,
|
|
86
|
-
(error || info) && (React.createElement("div",
|
|
86
|
+
(error || info) && (React.createElement("div", { "data-testid": testIdMessage }, error ? (React.createElement("p", { className: "text-xs text-destructive", "data-testid": testIdError }, error)) : info ? (React.createElement("p", { className: "text-xs text-blue-600 dark:text-blue-400", "data-testid": testIdInfo }, info)) : null))));
|
|
87
87
|
});
|
|
88
88
|
exports.EnhancedSwitch = EnhancedSwitch;
|
|
89
89
|
EnhancedSwitch.displayName = "EnhancedSwitch";
|
|
@@ -30,6 +30,16 @@ interface EnhancedTableFooterActionProps {
|
|
|
30
30
|
previousPageLabel?: string;
|
|
31
31
|
/** Label for next page button */
|
|
32
32
|
nextPageLabel?: string;
|
|
33
|
+
/** `data-testid` for the root wrapper containing the action buttons. */
|
|
34
|
+
testIdWrapper?: string;
|
|
35
|
+
/** `data-testid` for the previous button. */
|
|
36
|
+
testIdPrevious?: string;
|
|
37
|
+
/** `data-testid` for the next button. */
|
|
38
|
+
testIdNext?: string;
|
|
39
|
+
/** `data-testid` for the previous icon element. */
|
|
40
|
+
testIdPreviousIcon?: string;
|
|
41
|
+
/** `data-testid` for the next icon element. */
|
|
42
|
+
testIdNextIcon?: string;
|
|
33
43
|
}
|
|
34
44
|
export declare const EnhancedTableFooterAction: FC<EnhancedTableFooterActionProps>;
|
|
35
45
|
export {};
|