@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.
@@ -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 are selected or removed */
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", null, error ? (React.createElement("p", { className: "text-xs text-destructive" }, error)) : info ? (React.createElement("p", { className: "text-xs text-blue-600 dark:text-blue-400" }, info)) : null))));
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", null, error ? (React.createElement("p", { className: "text-xs text-destructive" }, error)) : info ? (React.createElement("p", { className: "text-xs text-blue-600 dark:text-blue-400" }, info)) : null))));
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", null, error ? (React.createElement("p", { className: "text-xs text-destructive" }, error)) : info ? (React.createElement("p", { className: "text-xs text-blue-600 dark:text-blue-400" }, info)) : null))));
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", null, error ? (React.createElement("p", { className: "text-xs text-destructive" }, error)) : info ? (React.createElement("p", { className: "text-xs text-blue-600 dark:text-blue-400" }, info)) : null))));
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", null, error ? (React.createElement("p", { className: "text-xs text-destructive" }, error)) : info ? (React.createElement("p", { className: "text-xs text-blue-600 dark:text-blue-400" }, info)) : null))));
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 {};