@andreagiugni/tailwind-dashboard-ui 0.5.16 → 0.5.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/README.md +2 -2
- package/dist/index.cjs +80 -18
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +80 -18
- package/dist/index.js.map +1 -1
- package/package.json +6 -2
package/README.md
CHANGED
|
@@ -167,11 +167,11 @@ Legend: **(+native)** = also extends the element's native HTML attributes.
|
|
|
167
167
|
| `Alert` | `variant` (success/error/warning/info), `title`, `message`, `showLink`, `linkHref`, `linkText`, `icon?` (override icon), (+native div) |
|
|
168
168
|
| `Avatar` | `src`, `alt`, `size` (xsmall…xxlarge), `status` (online/offline/busy/none), `statusColor?`, (+native img) |
|
|
169
169
|
| `AvatarText` | `children`, `className`, (+native div) |
|
|
170
|
-
| `Dropdown` | `isOpen`, `onClose`, `children`, `portal?` (default `true`, prevents clipping inside tables/overflow containers), (+native div) |
|
|
170
|
+
| `Dropdown` | `isOpen`, `onClose`, `children`, `portal?` (default `true`, prevents clipping inside cards/tables/overflow containers), `triggerRef?` (optional custom trigger anchor), (+native div) |
|
|
171
171
|
| `DropdownItem` | `variant` (default/primary/outline, like Button), `icon?`, `bgColor`/`textColor`/`borderColor` overrides, `tag` (a/button), `href`, `onClick`, `onItemClick`, `baseClassName` (full override) |
|
|
172
172
|
| `Modal` | `isOpen`, `onClose`, `title?` (wrapping header aligned with close button), `showCloseButton`, `isFullscreen`, `closeOnBackdrop?`, `closeOnEsc?`; **alert preset** → `variant` (`success`/`info`/`warning`/`danger`) + `title`, `description`, `actionText?`, `onAction?`; (+native div) |
|
|
173
173
|
| `Table` (composable) | `TableHeader` / `TableBody` / `TableRow` / `TableCell` with `children`, `isHeader` (cell), (+native table elements; `onClick` / `onDoubleClick` on rows & cells) |
|
|
174
|
-
| `Table` (data-driven) | pass `data` + `columns` (`key`, `header`, `sortable?`, `align?`, `render?`, `className?`) to get search + per-column sort + pagination: `rowsPerPage?` (max rows/page, default 10), `rowsPerPageOptions?`, `searchKeys?` (**search box shown only when provided**), `searchPlaceholder?`, `defaultSortKey?` / `defaultSortDirection?`, `pagination?`, `paginationAlign?` (`left`/`center`/`right`/`full`, default `right`), `showSizeSelector?`, `onRowClick?`, `getRowId?`, `emptyContent?` |
|
|
174
|
+
| `Table` (data-driven) | pass `data` + `columns` (`key`, `header`, `sortable?`, `align?`, `render?`, `className?`) to get search + three-state per-column sort (neutral/ascending/descending) + pagination: `rowsPerPage?` (max rows/page, default 10), `rowsPerPageOptions?`, `searchKeys?` (**search box shown only when provided**), `searchPlaceholder?`, `defaultSortKey?` / `defaultSortDirection?`, `pagination?`, `paginationAlign?` (`left`/`center`/`right`/`full`, default `right`), `showSizeSelector?`, `onRowClick?`, `getRowId?`, `emptyContent?` |
|
|
175
175
|
| `Pagination` | `currentPage`, `totalPages`, `onPageChange`, `align?` (`left`/`center`/`right`/`full` — `full` pins Previous/Next to the edges with page indices centered) |
|
|
176
176
|
| `Breadcrumb` | `pageTitle`, `items?`, (+native) |
|
|
177
177
|
| `ThemeToggleButton` | `theme?` (controlled), `onToggle?`, (+native button) |
|
package/dist/index.cjs
CHANGED
|
@@ -416,12 +416,20 @@ var AvatarText = ({
|
|
|
416
416
|
}
|
|
417
417
|
);
|
|
418
418
|
};
|
|
419
|
+
function getTriggerElement(anchor, triggerRef) {
|
|
420
|
+
if (triggerRef?.current) return triggerRef.current;
|
|
421
|
+
if (!anchor) return null;
|
|
422
|
+
const previous = anchor.previousElementSibling;
|
|
423
|
+
const adjacentTrigger = previous?.matches(".dropdown-toggle, button, [aria-haspopup='menu']") ? previous : previous?.querySelector(".dropdown-toggle, button, [aria-haspopup='menu']");
|
|
424
|
+
return adjacentTrigger ?? anchor.parentElement?.querySelector(".dropdown-toggle");
|
|
425
|
+
}
|
|
419
426
|
var Dropdown = ({
|
|
420
427
|
isOpen,
|
|
421
428
|
onClose,
|
|
422
429
|
children,
|
|
423
430
|
className,
|
|
424
431
|
portal = true,
|
|
432
|
+
triggerRef,
|
|
425
433
|
style,
|
|
426
434
|
...rest
|
|
427
435
|
}) => {
|
|
@@ -430,7 +438,8 @@ var Dropdown = ({
|
|
|
430
438
|
const [position, setPosition] = React5.useState();
|
|
431
439
|
React5.useEffect(() => {
|
|
432
440
|
const handleClickOutside = (event) => {
|
|
433
|
-
|
|
441
|
+
const trigger = getTriggerElement(anchorRef.current, triggerRef);
|
|
442
|
+
if (dropdownRef.current && !dropdownRef.current.contains(event.target) && !trigger?.contains(event.target)) {
|
|
434
443
|
onClose();
|
|
435
444
|
}
|
|
436
445
|
};
|
|
@@ -438,13 +447,13 @@ var Dropdown = ({
|
|
|
438
447
|
return () => {
|
|
439
448
|
document.removeEventListener("mousedown", handleClickOutside);
|
|
440
449
|
};
|
|
441
|
-
}, [onClose]);
|
|
450
|
+
}, [onClose, triggerRef]);
|
|
442
451
|
React5.useLayoutEffect(() => {
|
|
443
452
|
if (!isOpen || !portal) return;
|
|
444
453
|
const updatePosition = () => {
|
|
445
454
|
const anchor = anchorRef.current;
|
|
446
455
|
const menu2 = dropdownRef.current;
|
|
447
|
-
const trigger = anchor
|
|
456
|
+
const trigger = getTriggerElement(anchor, triggerRef);
|
|
448
457
|
if (!anchor || !menu2) return;
|
|
449
458
|
const triggerRect = (trigger ?? anchor).getBoundingClientRect();
|
|
450
459
|
const menuRect = menu2.getBoundingClientRect();
|
|
@@ -465,7 +474,7 @@ var Dropdown = ({
|
|
|
465
474
|
window.removeEventListener("resize", updatePosition);
|
|
466
475
|
window.removeEventListener("scroll", updatePosition, true);
|
|
467
476
|
};
|
|
468
|
-
}, [isOpen, portal]);
|
|
477
|
+
}, [isOpen, portal, triggerRef]);
|
|
469
478
|
if (!isOpen) return null;
|
|
470
479
|
const menu = /* @__PURE__ */ jsxRuntime.jsx(
|
|
471
480
|
"div",
|
|
@@ -739,15 +748,63 @@ var alignClass = {
|
|
|
739
748
|
right: "text-right"
|
|
740
749
|
};
|
|
741
750
|
function SortIcon({
|
|
742
|
-
|
|
743
|
-
direction
|
|
751
|
+
state
|
|
744
752
|
}) {
|
|
745
|
-
const
|
|
746
|
-
const
|
|
747
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
753
|
+
const active = "text-brand-500";
|
|
754
|
+
const inactive = "text-gray-400 dark:text-gray-500";
|
|
755
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
756
|
+
"span",
|
|
757
|
+
{
|
|
758
|
+
"data-sort-state": state,
|
|
759
|
+
className: "inline-flex shrink-0 flex-col items-center -space-y-1",
|
|
760
|
+
children: [
|
|
761
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
762
|
+
"svg",
|
|
763
|
+
{
|
|
764
|
+
"data-sort-direction": "asc",
|
|
765
|
+
width: "12",
|
|
766
|
+
height: "12",
|
|
767
|
+
viewBox: "0 0 12 12",
|
|
768
|
+
fill: "none",
|
|
769
|
+
"aria-hidden": "true",
|
|
770
|
+
className: state === "asc" ? active : inactive,
|
|
771
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
772
|
+
"path",
|
|
773
|
+
{
|
|
774
|
+
d: "M3.5 7.25 6 4.75l2.5 2.5",
|
|
775
|
+
stroke: "currentColor",
|
|
776
|
+
strokeWidth: "1.5",
|
|
777
|
+
strokeLinecap: "round",
|
|
778
|
+
strokeLinejoin: "round"
|
|
779
|
+
}
|
|
780
|
+
)
|
|
781
|
+
}
|
|
782
|
+
),
|
|
783
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
784
|
+
"svg",
|
|
785
|
+
{
|
|
786
|
+
"data-sort-direction": "desc",
|
|
787
|
+
width: "12",
|
|
788
|
+
height: "12",
|
|
789
|
+
viewBox: "0 0 12 12",
|
|
790
|
+
fill: "none",
|
|
791
|
+
"aria-hidden": "true",
|
|
792
|
+
className: state === "desc" ? active : inactive,
|
|
793
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
794
|
+
"path",
|
|
795
|
+
{
|
|
796
|
+
d: "m3.5 4.75 2.5 2.5 2.5-2.5",
|
|
797
|
+
stroke: "currentColor",
|
|
798
|
+
strokeWidth: "1.5",
|
|
799
|
+
strokeLinecap: "round",
|
|
800
|
+
strokeLinejoin: "round"
|
|
801
|
+
}
|
|
802
|
+
)
|
|
803
|
+
}
|
|
804
|
+
)
|
|
805
|
+
]
|
|
806
|
+
}
|
|
807
|
+
);
|
|
751
808
|
}
|
|
752
809
|
function DataDrivenTable({
|
|
753
810
|
data,
|
|
@@ -797,10 +854,14 @@ function DataDrivenTable({
|
|
|
797
854
|
const pageRows = pagination ? filtered.slice(start, start + pageSize) : filtered;
|
|
798
855
|
const toggleSort = (col) => {
|
|
799
856
|
if (!col.sortable) return;
|
|
800
|
-
if (sortKey
|
|
801
|
-
else {
|
|
857
|
+
if (sortKey !== col.key) {
|
|
802
858
|
setSortKey(col.key);
|
|
803
859
|
setSortDir("asc");
|
|
860
|
+
} else if (sortDir === "asc") {
|
|
861
|
+
setSortDir("desc");
|
|
862
|
+
} else {
|
|
863
|
+
setSortKey(void 0);
|
|
864
|
+
setSortDir("asc");
|
|
804
865
|
}
|
|
805
866
|
setPage(1);
|
|
806
867
|
};
|
|
@@ -878,8 +939,9 @@ function DataDrivenTable({
|
|
|
878
939
|
TableCell,
|
|
879
940
|
{
|
|
880
941
|
isHeader: true,
|
|
942
|
+
"aria-sort": col.sortable ? isActive ? sortDir === "asc" ? "ascending" : "descending" : "none" : void 0,
|
|
881
943
|
className: chunkYERNSNT4_cjs.cn(
|
|
882
|
-
"whitespace-nowrap px-5 py-3 text-xs font-semibold text-gray-
|
|
944
|
+
"whitespace-nowrap px-5 py-3 text-xs font-semibold text-gray-500 dark:text-gray-400",
|
|
883
945
|
alignClass[col.align ?? "left"],
|
|
884
946
|
col.className
|
|
885
947
|
),
|
|
@@ -889,10 +951,10 @@ function DataDrivenTable({
|
|
|
889
951
|
type: "button",
|
|
890
952
|
onClick: () => toggleSort(col),
|
|
891
953
|
"aria-label": `Sort by ${typeof col.header === "string" ? col.header : col.key}`,
|
|
892
|
-
className: "inline-flex select-none items-center gap-
|
|
954
|
+
className: "inline-flex select-none items-center gap-2 text-gray-500 transition-colors hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200",
|
|
893
955
|
children: [
|
|
894
|
-
|
|
895
|
-
|
|
956
|
+
/* @__PURE__ */ jsxRuntime.jsx(SortIcon, { state: isActive ? sortDir : "none" }),
|
|
957
|
+
col.header
|
|
896
958
|
]
|
|
897
959
|
}
|
|
898
960
|
) : col.header
|