@pk-design/react-tailwind 1.1.5 → 1.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/react-tailwind.cjs.js +77 -55
- package/dist/react-tailwind.cjs.js.map +1 -1
- package/dist/react-tailwind.es.js +78 -56
- package/dist/react-tailwind.es.js.map +1 -1
- package/dist/types/components/PasswordInput/PasswordInput.d.ts +1 -1
- package/package.json +1 -1
- package/dist/types/components/RangeInput/-backup.d.ts +0 -10
|
@@ -243,7 +243,7 @@ const TypeClassMap = {
|
|
|
243
243
|
const Alert = (props) => {
|
|
244
244
|
const { type = 'info', className = '', message, children, removable = false, onRemove = () => { }, ...restProps } = props;
|
|
245
245
|
const Icon = AlertTypeIconMap[type] || SvgInfo;
|
|
246
|
-
return (jsxRuntime.jsxs("div", { className: buildClassName(className, 'flex items-center justify-between rounded-md p-3 text-sm ring-1 ring-inset gap-2', TypeClassMap[type]), ...restProps, children: [jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-2", children: [jsxRuntime.jsx(Icon, { className: "size-5", "data-testid": `alert-${type}-icon` }), jsxRuntime.jsx("span", { className: "pr-2 inline-flex items-center", children: message || children })] }), removable && (jsxRuntime.jsx(Button, { iconOnly: true, size: "xs", variant: "plain", theme: "secondary", className: "hover:bg-black/5 text-gray-600 dark:hover:bg-black/5 dark:text-gray-600", onClick: () => onRemove(), "data-testid": "alert-remove-btn", children: jsxRuntime.jsx(SvgX, { className: "size-4.5", "data-testid": "alert-remove-icon" }) }))] }));
|
|
246
|
+
return (jsxRuntime.jsxs("div", { className: buildClassName(className, 'flex items-center justify-between rounded-md p-3 text-sm ring-1 ring-inset gap-2', TypeClassMap[type]), ...restProps, children: [jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-2", children: [jsxRuntime.jsx(Icon, { className: "size-5", "data-testid": `alert-${type}-icon` }), jsxRuntime.jsx("span", { className: "pr-2 inline-flex items-center", children: message || children })] }), removable && (jsxRuntime.jsx(Button, { iconOnly: true, "aria-label": "Dismiss alert", size: "xs", variant: "plain", theme: "secondary", className: "hover:bg-black/5 text-gray-600 dark:hover:bg-black/5 dark:text-gray-600", onClick: () => onRemove(), "data-testid": "alert-remove-btn", children: jsxRuntime.jsx(SvgX, { className: "size-4.5", "data-testid": "alert-remove-icon" }) }))] }));
|
|
247
247
|
};
|
|
248
248
|
Alert.displayName = 'Alert';
|
|
249
249
|
|
|
@@ -256,7 +256,12 @@ const ThemeClassMap = {
|
|
|
256
256
|
};
|
|
257
257
|
const Badge = React.forwardRef((props, ref) => {
|
|
258
258
|
const { theme = 'info', className = '', children, removable = false, rounded = false, onRemove = () => { }, ...restProps } = props;
|
|
259
|
-
return (jsxRuntime.jsxs(TextContent, { ref: ref, className: buildClassName(className, 'inline-flex items-center pl-3 py-1 text-xs font-medium ring-1 ring-inset', ThemeClassMap[theme], rounded ? 'rounded-full' : 'rounded-md'), "data-testid": `badge-${theme}`, ...restProps, children: [jsxRuntime.jsx(TextContent, { className: "pr-3 inline-flex items-center", children: children }), removable ? (jsxRuntime.jsx(SvgX, { className: "size-5 px-0.5 mr-1 hover:bg-slate-200 dark:hover:bg-white/10 rounded-sm cursor-pointer text-gray-600 dark:text-gray-300", role: "button", onClick: () => onRemove()
|
|
259
|
+
return (jsxRuntime.jsxs(TextContent, { ref: ref, className: buildClassName(className, 'inline-flex items-center pl-3 py-1 text-xs font-medium ring-1 ring-inset', ThemeClassMap[theme], rounded ? 'rounded-full' : 'rounded-md'), "data-testid": `badge-${theme}`, ...restProps, children: [jsxRuntime.jsx(TextContent, { className: "pr-3 inline-flex items-center", children: children }), removable ? (jsxRuntime.jsx(SvgX, { className: "size-5 px-0.5 mr-1 hover:bg-slate-200 dark:hover:bg-white/10 rounded-sm cursor-pointer text-gray-600 dark:text-gray-300", role: "button", tabIndex: 0, "aria-label": "Remove", onClick: () => onRemove(), onKeyDown: (e) => {
|
|
260
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
261
|
+
e.preventDefault();
|
|
262
|
+
onRemove();
|
|
263
|
+
}
|
|
264
|
+
} })) : null] }));
|
|
260
265
|
});
|
|
261
266
|
Badge.displayName = 'Badge';
|
|
262
267
|
|
|
@@ -360,7 +365,7 @@ var SvgSlash = function SvgSlash(props) {
|
|
|
360
365
|
const Breadcrumb = ({ items, render }) => {
|
|
361
366
|
const count = items.length;
|
|
362
367
|
const isLast = (index) => index === count - 1;
|
|
363
|
-
return (jsxRuntime.jsx("
|
|
368
|
+
return (jsxRuntime.jsx("nav", { "aria-label": "Breadcrumb", className: "flex flex-wrap items-center gap-2", "data-testid": "breadcrumb-container", children: items.map((item, index) => (jsxRuntime.jsxs("span", { className: "inline-flex gap-2 items-center dark:text-white", "data-testid": `breadcrumb-item-${item.key}`, children: [jsxRuntime.jsx("span", { className: "font-medium", ...(isLast(index) ? { 'aria-current': 'page' } : {}), children: isLast(index) ? item.text : render(item) }), !isLast(index) && (jsxRuntime.jsx(SvgSlash, { "data-testid": `breadcrumb-divider-${index}`, className: "size-4" }))] }, item.key))) }));
|
|
364
369
|
};
|
|
365
370
|
Breadcrumb.displayName = 'Breadcrumb';
|
|
366
371
|
|
|
@@ -387,7 +392,8 @@ const Checkbox = React.forwardRef((props, ref) => {
|
|
|
387
392
|
const { id, name, label, labelClass = '', wrapperClass = '', containerClass = '', error, disabled = false, className = '',
|
|
388
393
|
// Checkbox-only props removed from rest
|
|
389
394
|
...rest } = props;
|
|
390
|
-
const
|
|
395
|
+
const generatedId = React.useId();
|
|
396
|
+
const checkboxId = (_a = id !== null && id !== void 0 ? id : name) !== null && _a !== void 0 ? _a : generatedId;
|
|
391
397
|
return (jsxRuntime.jsxs("div", { className: buildClassName(wrapperClass), children: [jsxRuntime.jsxs("div", { className: buildClassName('flex items-center', containerClass), children: [jsxRuntime.jsxs("label", { htmlFor: checkboxId, className: buildClassName('inline-flex items-center relative select-none', disabled ? 'cursor-not-allowed opacity-70' : 'cursor-pointer'), children: [jsxRuntime.jsx("input", { ref: ref, ...rest, id: checkboxId, name: name, type: "checkbox", disabled: disabled, "aria-checked": rest.checked, className: buildClassName('peer size-4.5 cursor-pointer transition-all appearance-none rounded', 'border focus:ring-2 focus:ring-offset-2', 'checked:bg-blue-600 checked:border-blue-600', 'focus:ring-blue-500 dark:focus:ring-offset-gray-900', disabled
|
|
392
398
|
? 'border-gray-200 dark:border-gray-700 bg-gray-100 dark:bg-gray-800 pointer-events-none'
|
|
393
399
|
: 'bg-white dark:bg-gray-700 border-gray-300 dark:border-gray-600 hover:border-gray-400 dark:hover:border-gray-500 hover:shadow-md', className) }), jsxRuntime.jsx("span", { className: "absolute text-white opacity-0 peer-checked:opacity-100 \n top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2", children: jsxRuntime.jsx("svg", { xmlns: "http://www.w3.org/2000/svg", className: "h-3.25 w-3.25", viewBox: "0 0 20 20", fill: "currentColor", stroke: "currentColor", strokeWidth: "1", children: jsxRuntime.jsx("path", { fillRule: "evenodd", d: "M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z", clipRule: "evenodd" }) }) })] }), label && (jsxRuntime.jsx(Label, { htmlFor: checkboxId, className: buildClassName(disabled
|
|
@@ -398,15 +404,8 @@ Checkbox.displayName = 'Checkbox';
|
|
|
398
404
|
|
|
399
405
|
const CheckboxGroup = (props) => {
|
|
400
406
|
const { name, options, label, labelClass = '', labelWrapperClass = '', labelHint, containerClass = '', value = [], onChange, inline = false, } = props;
|
|
401
|
-
const
|
|
402
|
-
const
|
|
403
|
-
/**
|
|
404
|
-
* Normalize options (strings → {label, value})
|
|
405
|
-
*/
|
|
406
|
-
React.useEffect(() => {
|
|
407
|
-
const normalized = options.map((opt) => typeof opt === 'string' ? { label: opt, value: opt } : opt);
|
|
408
|
-
setItems(normalized);
|
|
409
|
-
}, [options]);
|
|
407
|
+
const groupId = React.useId();
|
|
408
|
+
const items = React.useMemo(() => options.map((opt) => typeof opt === 'string' ? { label: opt, value: opt } : opt), [options]);
|
|
410
409
|
/**
|
|
411
410
|
* Group-level change handler. Converts raw checkbox change events
|
|
412
411
|
* into a typed updated values array.
|
|
@@ -557,14 +556,14 @@ const Pagination = ({ page: currentPage, limit, total, onChange, className, elli
|
|
|
557
556
|
onChange({ page: nextVal });
|
|
558
557
|
};
|
|
559
558
|
if (ellipsis) {
|
|
560
|
-
return (jsxRuntime.jsxs("div", { "data-testid": "pagination-container", className: buildClassName('flex items-center justify-between bg-white dark:bg-gray-800 px-4 py-3 sm:px-6', className), children: [jsxRuntime.jsxs("div", { className: "flex flex-1 justify-between sm:hidden", children: [jsxRuntime.jsxs(Button, { size: "xs", theme: "secondary", variant: "plain", disabled: isFirstPage, onClick: () => handlePageChange(currentPage - 1), "data-testid": "ellipsis-mobile-prev-btn", children: [jsxRuntime.jsx("span", { children: "Previous" }), jsxRuntime.jsx(SvgChevronLeft, { className: "size-4" })] }), jsxRuntime.jsxs(Button, { size: "xs", theme: "secondary", variant: "plain", disabled: isLastPage, onClick: () => handlePageChange(currentPage + 1), "data-testid": "ellipsis-mobile-next-btn", children: [jsxRuntime.jsx("span", { children: "Next" }), jsxRuntime.jsx(SvgChevronRight, { className: "size-4" })] })] }), jsxRuntime.jsxs("div", { className: "hidden sm:flex sm:flex-1 sm:items-center sm:justify-between", children: [jsxRuntime.jsxs("p", { "data-testid": "pagination-summary", className: "text-sm text-gray-600 dark:text-gray-400 flex items-center gap-1", children: ["Showing", jsxRuntime.jsx("span", { className: "font-medium", children: total === 0 ? 0 : Math.max(currentPage * limit - limit + 1, 1) }), "to", jsxRuntime.jsx("span", { className: "font-medium", children: Math.min(currentPage * limit, total) }), "of", jsxRuntime.jsx("span", { className: "font-medium", children: total }), "results"] }), jsxRuntime.jsxs("ul", { className: "flex items-center space-x-2 text-sm", children: [jsxRuntime.jsx("li", { children: jsxRuntime.jsx(Button, { size: "xs", theme: "secondary", variant: "plain", disabled: isFirstPage, onClick: () => handlePageChange(currentPage - 1), "data-testid": "ellipsis-
|
|
559
|
+
return (jsxRuntime.jsxs("div", { "data-testid": "pagination-container", className: buildClassName('flex items-center justify-between bg-white dark:bg-gray-800 px-4 py-3 sm:px-6', className), children: [jsxRuntime.jsxs("div", { className: "flex flex-1 justify-between sm:hidden", children: [jsxRuntime.jsxs(Button, { size: "xs", theme: "secondary", variant: "plain", disabled: isFirstPage, onClick: () => handlePageChange(currentPage - 1), "data-testid": "ellipsis-mobile-prev-btn", children: [jsxRuntime.jsx("span", { children: "Previous" }), jsxRuntime.jsx(SvgChevronLeft, { className: "size-4" })] }), jsxRuntime.jsxs(Button, { size: "xs", theme: "secondary", variant: "plain", disabled: isLastPage, onClick: () => handlePageChange(currentPage + 1), "data-testid": "ellipsis-mobile-next-btn", children: [jsxRuntime.jsx("span", { children: "Next" }), jsxRuntime.jsx(SvgChevronRight, { className: "size-4" })] })] }), jsxRuntime.jsxs("div", { className: "hidden sm:flex sm:flex-1 sm:items-center sm:justify-between", children: [jsxRuntime.jsxs("p", { "data-testid": "pagination-summary", className: "text-sm text-gray-600 dark:text-gray-400 flex items-center gap-1", children: ["Showing", jsxRuntime.jsx("span", { className: "font-medium", children: total === 0 ? 0 : Math.max(currentPage * limit - limit + 1, 1) }), "to", jsxRuntime.jsx("span", { className: "font-medium", children: Math.min(currentPage * limit, total) }), "of", jsxRuntime.jsx("span", { className: "font-medium", children: total }), "results"] }), jsxRuntime.jsxs("ul", { className: "flex items-center space-x-2 text-sm", children: [jsxRuntime.jsx("li", { children: jsxRuntime.jsx(Button, { size: "xs", theme: "secondary", variant: "plain", disabled: isFirstPage, onClick: () => handlePageChange(currentPage - 1), "data-testid": "ellipsis-prev-btn", children: "Prev" }) }), range.map((page, idx) => {
|
|
561
560
|
if (page === DOTS) {
|
|
562
561
|
return (jsxRuntime.jsx("li", { "data-testid": `page-${page}`, className: "px-2 py-1 text-gray-400", children: "\u2026" }, `${page}-${idx}`));
|
|
563
562
|
}
|
|
564
563
|
return (jsxRuntime.jsx("li", { children: jsxRuntime.jsx(Button, { size: "xs", theme: page === currentPage ? 'primary' : 'secondary', variant: page === currentPage ? 'default' : 'plain', "aria-current": page === currentPage ? 'page' : undefined, onClick: () => handlePageChange(page), children: page }) }, `${page}-${idx}`));
|
|
565
|
-
}), jsxRuntime.jsx("li", { children: jsxRuntime.jsx(Button, { size: "xs", theme: "secondary", variant: "plain", disabled: isLastPage, onClick: () => handlePageChange(currentPage + 1), "data-testid": "ellipsis-
|
|
564
|
+
}), jsxRuntime.jsx("li", { children: jsxRuntime.jsx(Button, { size: "xs", theme: "secondary", variant: "plain", disabled: isLastPage, onClick: () => handlePageChange(currentPage + 1), "data-testid": "ellipsis-next-btn", children: "Next" }) })] })] })] }));
|
|
566
565
|
}
|
|
567
|
-
return (jsxRuntime.jsxs("div", { "data-testid": "pagination-container", className: buildClassName('flex items-center justify-between bg-white dark:bg-gray-800 px-4 py-3 sm:px-6', className), children: [jsxRuntime.jsxs("div", { className: "flex flex-1 justify-between sm:hidden", children: [jsxRuntime.jsxs(Button, { size: "xs", theme: "secondary", variant: "plain", disabled: isFirstPage, onClick: () => handlePageChange(currentPage - 1), "data-testid": "mobile-prev-btn", children: [jsxRuntime.jsx("span", { children: "Previous" }), jsxRuntime.jsx(SvgChevronLeft, { className: "size-4" })] }), jsxRuntime.jsxs(Button, { size: "xs", theme: "secondary", variant: "plain", disabled: isLastPage, onClick: () => handlePageChange(currentPage + 1), "data-testid": "mobile-next-btn", children: [jsxRuntime.jsx("span", { children: "Next" }), jsxRuntime.jsx(SvgChevronRight, { className: "size-4" })] })] }), jsxRuntime.jsxs("div", { className: "hidden sm:flex sm:flex-1 sm:items-center sm:justify-between", children: [jsxRuntime.jsxs("p", { "data-testid": "pagination-summary", className: "text-sm text-gray-600 dark:text-gray-400 flex items-center gap-1", children: ["Showing", jsxRuntime.jsx("span", { className: "font-medium", children: total === 0 ? 0 : Math.max(currentPage * limit - limit + 1, 1) }), "to", jsxRuntime.jsx("span", { className: "font-medium", children: Math.min(currentPage * limit, total) }), "of", jsxRuntime.jsx("span", { className: "font-medium", children: total }), "results"] }), jsxRuntime.jsxs("nav", { className: "isolate inline-flex items-center rounded-md", "aria-label": "Pagination", children: [jsxRuntime.jsxs(Button, { size: "xs", theme: "secondary", variant: "plain", disabled: isFirstPage, onClick: () => handlePageChange(currentPage - 1), "data-testid": "
|
|
566
|
+
return (jsxRuntime.jsxs("div", { "data-testid": "pagination-container", className: buildClassName('flex items-center justify-between bg-white dark:bg-gray-800 px-4 py-3 sm:px-6', className), children: [jsxRuntime.jsxs("div", { className: "flex flex-1 justify-between sm:hidden", children: [jsxRuntime.jsxs(Button, { size: "xs", theme: "secondary", variant: "plain", disabled: isFirstPage, onClick: () => handlePageChange(currentPage - 1), "data-testid": "mobile-prev-btn", children: [jsxRuntime.jsx("span", { children: "Previous" }), jsxRuntime.jsx(SvgChevronLeft, { className: "size-4" })] }), jsxRuntime.jsxs(Button, { size: "xs", theme: "secondary", variant: "plain", disabled: isLastPage, onClick: () => handlePageChange(currentPage + 1), "data-testid": "mobile-next-btn", children: [jsxRuntime.jsx("span", { children: "Next" }), jsxRuntime.jsx(SvgChevronRight, { className: "size-4" })] })] }), jsxRuntime.jsxs("div", { className: "hidden sm:flex sm:flex-1 sm:items-center sm:justify-between", children: [jsxRuntime.jsxs("p", { "data-testid": "pagination-summary", className: "text-sm text-gray-600 dark:text-gray-400 flex items-center gap-1", children: ["Showing", jsxRuntime.jsx("span", { className: "font-medium", children: total === 0 ? 0 : Math.max(currentPage * limit - limit + 1, 1) }), "to", jsxRuntime.jsx("span", { className: "font-medium", children: Math.min(currentPage * limit, total) }), "of", jsxRuntime.jsx("span", { className: "font-medium", children: total }), "results"] }), jsxRuntime.jsxs("nav", { className: "isolate inline-flex items-center rounded-md", "aria-label": "Pagination", children: [jsxRuntime.jsxs(Button, { size: "xs", theme: "secondary", variant: "plain", disabled: isFirstPage, onClick: () => handlePageChange(currentPage - 1), "data-testid": "prev-btn", children: [jsxRuntime.jsx("span", { className: "sr-only", children: "Previous" }), jsxRuntime.jsx(SvgChevronLeft, { className: "size-4" })] }), pages.map((page) => (jsxRuntime.jsx(Button, { size: "xs", theme: page === currentPage ? 'primary' : 'secondary', variant: page === currentPage ? 'default' : 'plain', "aria-current": page === currentPage ? 'page' : undefined, onClick: () => handlePageChange(page), children: jsxRuntime.jsx("span", { className: "size-4 block", children: page }) }, page))), jsxRuntime.jsxs(Button, { size: "xs", theme: "secondary", variant: "plain", disabled: isLastPage, onClick: () => handlePageChange(currentPage + 1), "data-testid": "next-btn", children: [jsxRuntime.jsx("span", { className: "sr-only", children: "Next" }), jsxRuntime.jsx(SvgChevronRight, { className: "size-4" })] })] })] })] }));
|
|
568
567
|
};
|
|
569
568
|
|
|
570
569
|
function get(obj, path, defaultValue) {
|
|
@@ -753,9 +752,13 @@ const autoSortItems = (items, column, sort) => {
|
|
|
753
752
|
};
|
|
754
753
|
const DataTable = ({ items, columns, sorting = {}, onSort, loading, pagination = null, setPagination = () => { }, emptyMessage = 'No data found', containerClass = '', wrapperClass = '', layout = 'auto', }) => {
|
|
755
754
|
const internalSorting = React.useRef({});
|
|
755
|
+
const [sortedItems, setSortedItems] = React.useState(items);
|
|
756
|
+
React.useEffect(() => {
|
|
757
|
+
setSortedItems(items);
|
|
758
|
+
}, [items]);
|
|
756
759
|
const doAutoSort = (column) => {
|
|
757
760
|
internalSorting.current = updateSortQuery(internalSorting.current, column.name, column.type);
|
|
758
|
-
autoSortItems(items, column, internalSorting.current[column.name]);
|
|
761
|
+
setSortedItems(autoSortItems(items, column, internalSorting.current[column.name]));
|
|
759
762
|
};
|
|
760
763
|
const handleSort = (column) => {
|
|
761
764
|
if (!column.sortable)
|
|
@@ -764,7 +767,7 @@ const DataTable = ({ items, columns, sorting = {}, onSort, loading, pagination =
|
|
|
764
767
|
};
|
|
765
768
|
return (jsxRuntime.jsxs("div", { className: buildClassName('w-full rounded-lg relative', containerClass), children: [jsxRuntime.jsx("div", { className: buildClassName('overflow-x-auto overflow-y-hidden rounded-lg border border-gray-200 dark:border-gray-800', wrapperClass, pagination && 'rounded-b-none border-b-0'), children: jsxRuntime.jsxs(Table, { className: "relative w-full max-w-full h-fit", layout: layout, children: [jsxRuntime.jsx(TableHead, { children: columns.map((column) => (jsxRuntime.jsx(TableHeaderCell, { align: column.headerAlign, style: { width: column.width || 'auto' }, className: buildClassName('bg-gray-50 dark:bg-gray-800', column.sticky === 'left' &&
|
|
766
769
|
'sticky left-0 z-10 shadow-[2px_0_6px_rgba(0,0,0,0.06)]', column.sticky === 'right' &&
|
|
767
|
-
'sticky right-0 z-10 shadow-[-2px_0_6px_rgba(0,0,0,0.06)]'), children: jsxRuntime.jsxs(TextContent, { role: column.sortable ? 'button' : undefined, className: buildClassName('group', column.sortable && 'inline-flex items-center gap-2 cursor-pointer select-none'), onClick: () => handleSort(column), children: [jsxRuntime.jsx(TextContent, { className: "shrink-0", children: column.label }), column.sortable ? getSortIcon(sorting[column.name]) : null] }) }, column.name))) }), jsxRuntime.jsx(TableBody, { loading: loading, colSize: columns.length, rowSize: (pagination === null || pagination === void 0 ? void 0 : pagination.limit) || 5, children: !loading &&
|
|
770
|
+
'sticky right-0 z-10 shadow-[-2px_0_6px_rgba(0,0,0,0.06)]'), children: jsxRuntime.jsxs(TextContent, { role: column.sortable ? 'button' : undefined, className: buildClassName('group', column.sortable && 'inline-flex items-center gap-2 cursor-pointer select-none'), onClick: () => handleSort(column), children: [jsxRuntime.jsx(TextContent, { className: "shrink-0", children: column.label }), column.sortable ? getSortIcon(sorting[column.name]) : null] }) }, column.name))) }), jsxRuntime.jsx(TableBody, { loading: loading, colSize: columns.length, rowSize: (pagination === null || pagination === void 0 ? void 0 : pagination.limit) || 5, children: !loading && sortedItems.length === 0 ? (jsxRuntime.jsx(EmptyTableRow, { colSpan: columns.length, children: emptyMessage })) : (sortedItems.map((item) => (jsxRuntime.jsx(TableRow, { className: "group", children: columns.map((column) => {
|
|
768
771
|
var _a;
|
|
769
772
|
return (jsxRuntime.jsx(TableCell, { align: column.align, className: buildClassName(column.sticky === 'left' &&
|
|
770
773
|
'sticky left-0 z-10 shadow-[2px_0_6px_rgba(0,0,0,0.06)]', column.sticky === 'right' &&
|
|
@@ -878,7 +881,7 @@ Input.displayName = 'Input';
|
|
|
878
881
|
const PASSWORD_TYPE = 'password';
|
|
879
882
|
const PASSWORD_PLACEHOLDER = '••••••••••';
|
|
880
883
|
const PasswordInput = (props) => {
|
|
881
|
-
const {
|
|
884
|
+
const { ...inputProps } = props;
|
|
882
885
|
const [showPassword, setShowPassword] = React.useState(false);
|
|
883
886
|
return (jsxRuntime.jsx(Input, { ...inputProps, type: showPassword ? 'text' : PASSWORD_TYPE, placeholder: PASSWORD_PLACEHOLDER, rightGroup: jsxRuntime.jsx(Button, { theme: "secondary", variant: "plain", size: "xs", className: "px-1 mr-1", type: "button", onClick: () => setShowPassword(() => !showPassword), tabIndex: -1, children: showPassword ? (jsxRuntime.jsx("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", strokeWidth: "1.5", stroke: "currentColor", className: "size-4", children: jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3.98 8.223A10.477 10.477 0 0 0 1.934 12C3.226 16.338 7.244 19.5 12 19.5c.993 0 1.953-.138 2.863-.395M6.228 6.228A10.451 10.451 0 0 1 12 4.5c4.756 0 8.773 3.162 10.065 7.498a10.522 10.522 0 0 1-4.293 5.774M6.228 6.228 3 3m3.228 3.228 3.65 3.65m7.894 7.894L21 21m-3.228-3.228-3.65-3.65m0 0a3 3 0 1 0-4.243-4.243m4.242 4.242L9.88 9.88" }) })) : (jsxRuntime.jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", strokeWidth: "1.5", stroke: "currentColor", className: "size-4", children: [jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M2.036 12.322a1.012 1.012 0 0 1 0-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178Z" }), jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z" })] })) }) }));
|
|
884
887
|
};
|
|
@@ -888,8 +891,9 @@ const Radio = React.forwardRef((props, ref) => {
|
|
|
888
891
|
const { id, name, label, labelClass = '', wrapperClass = '', containerClass = '', error, disabled = false, className = '',
|
|
889
892
|
// RadioButton-only props removed from rest
|
|
890
893
|
...rest } = props;
|
|
891
|
-
const
|
|
892
|
-
|
|
894
|
+
const generatedId = React.useId();
|
|
895
|
+
const radioId = (_a = id !== null && id !== void 0 ? id : name) !== null && _a !== void 0 ? _a : generatedId;
|
|
896
|
+
return (jsxRuntime.jsxs("div", { className: buildClassName(wrapperClass), children: [jsxRuntime.jsxs("div", { className: buildClassName('flex items-center gap-2', containerClass), children: [jsxRuntime.jsx("div", { className: "grid place-items-center", children: jsxRuntime.jsx("input", { ref: ref, ...rest, id: radioId, name: name, type: "radio", disabled: disabled, "aria-checked": rest.checked, className: buildClassName('peer transition-all col-start-1 row-start-1 appearance-none shrink-0 size-4.5 rounded-full', 'border focus:ring-2 focus:ring-offset-2', 'checked:border-5 checked:bg-white', 'focus:ring-blue-500 checked:focus:ring-blue-600 dark:focus:ring-offset-gray-800', disabled
|
|
893
897
|
? 'border-gray-200 dark:border-gray-700 bg-gray-100 dark:bg-gray-800 pointer-events-none'
|
|
894
898
|
: buildClassName('bg-white dark:bg-gray-700 border-gray-300 dark:border-gray-600 hover:border-gray-400 dark:hover:border-gray-500', 'checked:border-blue-600 checked:hover:border-blue-600 dark:checked:border-blue-600 dark:checked:hover:border-blue-600'), className) }) }), label && (jsxRuntime.jsx(Label, { htmlFor: radioId, className: buildClassName(disabled
|
|
895
899
|
? 'cursor-not-allowed text-gray-400 dark:text-gray-500'
|
|
@@ -898,16 +902,9 @@ const Radio = React.forwardRef((props, ref) => {
|
|
|
898
902
|
|
|
899
903
|
const RadioGroup = (props) => {
|
|
900
904
|
const { name, label, labelClass, labelWrapperClass, labelHint, containerClass, options, value, row, error, showErrorMessage, onChange, } = props;
|
|
901
|
-
const
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
return options === null || options === void 0 ? void 0 : options.map((option) => {
|
|
905
|
-
if (typeof option === 'string') {
|
|
906
|
-
return { label: option, value: option };
|
|
907
|
-
}
|
|
908
|
-
return option;
|
|
909
|
-
});
|
|
910
|
-
});
|
|
905
|
+
const items = React.useMemo(() => {
|
|
906
|
+
var _a;
|
|
907
|
+
return (_a = options === null || options === void 0 ? void 0 : options.map((option) => typeof option === 'string' ? { label: option, value: option } : option)) !== null && _a !== void 0 ? _a : [];
|
|
911
908
|
}, [options]);
|
|
912
909
|
return (jsxRuntime.jsxs("div", { className: buildClassName(containerClass), children: [label && (jsxRuntime.jsxs("div", { className: buildClassName('flex items-center justify-between mb-4', labelWrapperClass), children: [jsxRuntime.jsx(Label, { className: labelClass, children: label }), labelHint] })), jsxRuntime.jsx("div", { className: buildClassName('flex gap-4', row ? 'flex-row items-center' : 'flex-col items-start'), children: items.map((item) => (jsxRuntime.jsx(Radio, { name: name, id: `${name}-${item.value}`, label: item.label, value: item.value, checked: value === item.value, onChange: onChange }, item.value))) }), showErrorMessage && error && (jsxRuntime.jsx("div", { className: "mt-1", children: jsxRuntime.jsx(TextContent, { error: true, small: true, children: error }) }))] }));
|
|
913
910
|
};
|
|
@@ -1001,35 +998,53 @@ const RangeSlider = ({ label, labelHint, labelClass = '', containerClass = '', c
|
|
|
1001
998
|
const activeThumbRef = React.useRef(null);
|
|
1002
999
|
// State for UI styling
|
|
1003
1000
|
const [activeThumbState, setActiveThumbState] = React.useState(null);
|
|
1001
|
+
// Keep prop values in refs so drag handlers always use latest values (no stale closure)
|
|
1002
|
+
const valueMinRef = React.useRef(valueMin);
|
|
1003
|
+
const valueMaxRef = React.useRef(valueMax);
|
|
1004
|
+
const onChangeRef = React.useRef(onChange);
|
|
1005
|
+
valueMinRef.current = valueMin;
|
|
1006
|
+
valueMaxRef.current = valueMax;
|
|
1007
|
+
onChangeRef.current = onChange;
|
|
1004
1008
|
const hasError = !isEmpty(error);
|
|
1005
1009
|
const percent = (v) => ((v - min) / (max - min)) * 100;
|
|
1006
|
-
//
|
|
1007
|
-
//
|
|
1008
|
-
|
|
1009
|
-
const pointerMoveHandler = (e) => {
|
|
1010
|
+
// Stable handler references registered on window — these never change identity
|
|
1011
|
+
// so removeEventListener always finds the right listener to remove.
|
|
1012
|
+
const stablePointerMoveRef = React.useRef((e) => {
|
|
1010
1013
|
if (!trackRef.current || !activeThumbRef.current)
|
|
1011
1014
|
return;
|
|
1012
1015
|
const rect = trackRef.current.getBoundingClientRect();
|
|
1013
1016
|
const x = Math.min(Math.max(e.clientX - rect.left, 0), rect.width);
|
|
1014
1017
|
const rawVal = min + (x / rect.width) * (max - min);
|
|
1015
1018
|
if (activeThumbRef.current === 'min') {
|
|
1016
|
-
|
|
1019
|
+
onChangeRef.current(Math.min(rawVal, valueMaxRef.current - 1), valueMaxRef.current);
|
|
1017
1020
|
}
|
|
1018
1021
|
else {
|
|
1019
|
-
|
|
1022
|
+
onChangeRef.current(valueMinRef.current, Math.max(rawVal, valueMinRef.current + 1));
|
|
1020
1023
|
}
|
|
1021
|
-
};
|
|
1022
|
-
const
|
|
1024
|
+
});
|
|
1025
|
+
const stablePointerUpRef = React.useRef(() => {
|
|
1023
1026
|
activeThumbRef.current = null;
|
|
1024
1027
|
setActiveThumbState(null);
|
|
1025
|
-
window.removeEventListener('pointermove',
|
|
1026
|
-
window.removeEventListener('pointerup',
|
|
1027
|
-
};
|
|
1028
|
-
|
|
1028
|
+
window.removeEventListener('pointermove', stablePointerMoveRef.current);
|
|
1029
|
+
window.removeEventListener('pointerup', stablePointerUpRef.current);
|
|
1030
|
+
});
|
|
1031
|
+
// Remove listeners on unmount in case a drag is in progress
|
|
1032
|
+
React.useEffect(() => {
|
|
1033
|
+
const move = stablePointerMoveRef.current;
|
|
1034
|
+
const up = stablePointerUpRef.current;
|
|
1035
|
+
return () => {
|
|
1036
|
+
window.removeEventListener('pointermove', move);
|
|
1037
|
+
window.removeEventListener('pointerup', up);
|
|
1038
|
+
};
|
|
1039
|
+
}, []);
|
|
1040
|
+
// ---------------------------------------------
|
|
1041
|
+
// Pointer Move (drag)
|
|
1042
|
+
// ---------------------------------------------
|
|
1043
|
+
const startDrag = (thumb) => (_e) => {
|
|
1029
1044
|
activeThumbRef.current = thumb;
|
|
1030
1045
|
setActiveThumbState(thumb);
|
|
1031
|
-
window.addEventListener('pointermove',
|
|
1032
|
-
window.addEventListener('pointerup',
|
|
1046
|
+
window.addEventListener('pointermove', stablePointerMoveRef.current);
|
|
1047
|
+
window.addEventListener('pointerup', stablePointerUpRef.current);
|
|
1033
1048
|
};
|
|
1034
1049
|
// ---------------------------------------------
|
|
1035
1050
|
// Click Track to move closest thumb
|
|
@@ -1091,6 +1106,9 @@ const useDebounce = (value, delay) => {
|
|
|
1091
1106
|
};
|
|
1092
1107
|
const useDebounceFn = (fn, ms) => {
|
|
1093
1108
|
const timeout = React.useRef(null);
|
|
1109
|
+
React.useEffect(() => {
|
|
1110
|
+
return () => clearTimeout(timeout.current);
|
|
1111
|
+
}, []);
|
|
1094
1112
|
return React.useCallback((...args) => {
|
|
1095
1113
|
clearTimeout(timeout.current);
|
|
1096
1114
|
timeout.current = setTimeout(() => fn(...args), ms);
|
|
@@ -1255,7 +1273,7 @@ const SelectBox = React.forwardRef((props, forwardedRef) => {
|
|
|
1255
1273
|
console.error('onAdd handler error', err);
|
|
1256
1274
|
}
|
|
1257
1275
|
}, [onAdd, handleOnChangeInternal]);
|
|
1258
|
-
const handleSearch = async (searchString) => {
|
|
1276
|
+
const handleSearch = React.useCallback(async (searchString) => {
|
|
1259
1277
|
var _a;
|
|
1260
1278
|
try {
|
|
1261
1279
|
setOptionsLoading(true);
|
|
@@ -1267,11 +1285,11 @@ const SelectBox = React.forwardRef((props, forwardedRef) => {
|
|
|
1267
1285
|
finally {
|
|
1268
1286
|
setOptionsLoading(false);
|
|
1269
1287
|
}
|
|
1270
|
-
};
|
|
1288
|
+
}, [props.onSearch]);
|
|
1271
1289
|
React.useEffect(() => {
|
|
1272
1290
|
if (async && debouncedQuery)
|
|
1273
1291
|
handleSearch(debouncedQuery);
|
|
1274
|
-
}, [debouncedQuery, async]);
|
|
1292
|
+
}, [debouncedQuery, async, handleSearch]);
|
|
1275
1293
|
return (jsxRuntime.jsxs("div", { className: buildClassName('group space-y-2', hasError && 'has-error', containerClass), ref: containerRef, children: [label && (jsxRuntime.jsxs("div", { className: buildClassName('flex items-center justify-between', labelWrapperClass), children: [jsxRuntime.jsx(Label, { className: labelClass, htmlFor: id, "aria-required": required, children: label }), labelHint] })), jsxRuntime.jsxs(react.Combobox, { multiple: multiple, immediate: immediate, name: name, value: selected, onChange: comboboxOnChangeWrapper, onClose: () => setQuery(''), disabled: disabled, children: [multiple ? (jsxRuntime.jsxs("div", { className: buildClassName(inputClass, 'flex flex-wrap gap-2 peer relative'), ref: forwardedRef, children: [isArray(selected) &&
|
|
1276
1294
|
(selected === null || selected === void 0 ? void 0 : selected.length) > 0 &&
|
|
1277
1295
|
selected.map((option, idx) => (jsxRuntime.jsx(Badge, { theme: "secondary", removable: !disabled, onRemove: () => removeSelection(idx), children: getDisplayValue(option) }, `${getValue(option)}-${idx}`))), jsxRuntime.jsx(react.ComboboxInput, { className: "outline-none flex-1 dark:placeholder-gray-400 placeholder-gray-400", "aria-label": name, value: query, autoComplete: "off", placeholder: (selected === null || selected === void 0 ? void 0 : selected.length) ? '' : placeholder, onChange: (e) => setQuery(e.target.value), id: id, ref: inputRef, onKeyDown: (e) => {
|
|
@@ -1384,7 +1402,11 @@ const ToastProvider = ({ children, placement = 'top-center' }) => {
|
|
|
1384
1402
|
timeoutRefs.current.delete(id);
|
|
1385
1403
|
}
|
|
1386
1404
|
};
|
|
1387
|
-
const
|
|
1405
|
+
const closeToast = React.useCallback((id) => {
|
|
1406
|
+
clearTimer(id);
|
|
1407
|
+
setToasts((prev) => prev.filter((t) => t.id !== id));
|
|
1408
|
+
}, []);
|
|
1409
|
+
const scheduleClose = React.useCallback((toast) => {
|
|
1388
1410
|
if (!toast.autoClose)
|
|
1389
1411
|
return;
|
|
1390
1412
|
clearTimer(toast.id);
|
|
@@ -1392,7 +1414,11 @@ const ToastProvider = ({ children, placement = 'top-center' }) => {
|
|
|
1392
1414
|
closeToast(toast.id);
|
|
1393
1415
|
}, toast.duration);
|
|
1394
1416
|
timeoutRefs.current.set(toast.id, timeout);
|
|
1395
|
-
};
|
|
1417
|
+
}, [closeToast]);
|
|
1418
|
+
React.useEffect(() => {
|
|
1419
|
+
const refs = timeoutRefs.current;
|
|
1420
|
+
return () => refs.forEach((id) => clearTimeout(id));
|
|
1421
|
+
}, []);
|
|
1396
1422
|
const showToast = React.useCallback((message, options) => {
|
|
1397
1423
|
var _a, _b, _c, _d;
|
|
1398
1424
|
const id = ++toastCounter;
|
|
@@ -1411,11 +1437,7 @@ const ToastProvider = ({ children, placement = 'top-center' }) => {
|
|
|
1411
1437
|
return updated;
|
|
1412
1438
|
});
|
|
1413
1439
|
scheduleClose(newToast);
|
|
1414
|
-
}, []);
|
|
1415
|
-
const closeToast = React.useCallback((id) => {
|
|
1416
|
-
clearTimer(id);
|
|
1417
|
-
setToasts((prev) => prev.filter((t) => t.id !== id));
|
|
1418
|
-
}, []);
|
|
1440
|
+
}, [scheduleClose]);
|
|
1419
1441
|
return (jsxRuntime.jsxs(ToastContext.Provider, { value: { showToast, closeToast }, children: [children, jsxRuntime.jsx("div", { className: buildClassName('fixed z-50 flex flex-col gap-3 pointer-events-none', placementClass[placement]), children: toasts.map((toast, index) => (jsxRuntime.jsx("div", { className: "pointer-events-auto", onMouseEnter: () => toast.pauseOnHover && clearTimer(toast.id), onMouseLeave: () => toast.pauseOnHover && scheduleClose(toast), children: jsxRuntime.jsx(Toast, { ...toast, isTop: placement.startsWith('top'), onClose: () => closeToast(toast.id) }) }, toast.id))) })] }));
|
|
1420
1442
|
};
|
|
1421
1443
|
|