@andreagiugni/tailwind-dashboard-ui 0.3.0 → 0.4.0

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 CHANGED
@@ -153,8 +153,8 @@ Legend: **(+native)** = also extends the element's native HTML attributes.
153
153
  | `DropdownItem` | `variant` (default/primary/outline, like Button), `bgColor`/`textColor`/`borderColor` overrides, `tag` (a/button), `href`, `onClick`, `onItemClick`, `baseClassName` (full override) |
154
154
  | `Modal` | `isOpen`, `onClose`, `showCloseButton`, `isFullscreen`, `closeOnBackdrop?`, `closeOnEsc?`; **alert preset** → `variant` (`success`/`info`/`warning`/`danger`) + `title`, `description`, `actionText?`, `onAction?`; (+native div) |
155
155
  | `Table` (composable) | `TableHeader` / `TableBody` / `TableRow` / `TableCell` with `children`, `isHeader` (cell), (+native table elements; `onClick` / `onDoubleClick` on rows & cells) |
156
- | `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?`, `showSizeSelector?`, `onRowClick?`, `getRowId?`, `emptyContent?` |
157
- | `Pagination` | `currentPage`, `totalPages`, `onPageChange` |
156
+ | `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?` |
157
+ | `Pagination` | `currentPage`, `totalPages`, `onPageChange`, `align?` (`left`/`center`/`right`/`full` — `full` pins Previous/Next to the edges with page indices centered) |
158
158
  | `Breadcrumb` | `pageTitle`, `items?`, (+native) |
159
159
  | `ThemeToggleButton` | `theme?` (controlled), `onToggle?`, (+native button) |
160
160
  | `Card` | `title?`, `description?`, `icon?`, `image?`, `imageAlt?`, `horizontal?`, `footer?`, `children?`, (+native div) (+override) |
@@ -279,7 +279,8 @@ const columns: TableColumn<Person>[] = [
279
279
  Key data-driven props: `data`, `columns` (each: `key`, `header`, `sortable?`, `align?`, `render?`,
280
280
  `className?`), `rowsPerPage` (default 10), `rowsPerPageOptions` (default `[5,10,25,50]`),
281
281
  `searchKeys` / `searchPlaceholder`, `defaultSortKey` / `defaultSortDirection`, `pagination`,
282
- `showSizeSelector`, `onRowClick`, `getRowId`, `emptyContent`.
282
+ `paginationAlign` (`left` / `center` / `right` / `full`, default `right`), `showSizeSelector`,
283
+ `onRowClick`, `getRowId`, `emptyContent`.
283
284
 
284
285
  > **Search visibility:** the search input renders **only** when you pass a non-empty `searchKeys`
285
286
  > array — those are also the exact fields the query matches. Omit `searchKeys` (or pass `[]`) to
package/dist/index.cjs CHANGED
@@ -31,7 +31,7 @@ function styleOverride({
31
31
  }
32
32
  var sizeClasses = {
33
33
  sm: "px-4 py-3 text-sm",
34
- md: "px-5 py-3.5 text-sm"
34
+ md: "px-5 py-2.5 text-sm"
35
35
  };
36
36
  var variantClasses = {
37
37
  primary: "bg-brand-500 text-white shadow-theme-xs hover:bg-brand-600 disabled:bg-brand-300",
@@ -552,64 +552,87 @@ var Dropzone = ({
552
552
  }
553
553
  );
554
554
  };
555
+ var navButton = "flex h-10 items-center justify-center rounded-lg border border-gray-300 bg-white px-3.5 py-2.5 text-sm text-gray-700 shadow-theme-xs hover:bg-gray-50 disabled:opacity-50 dark:border-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:hover:bg-white/[0.03]";
556
+ var justifyByAlign = {
557
+ left: "justify-start",
558
+ center: "justify-center",
559
+ right: "justify-end"
560
+ };
555
561
  var Pagination = ({
556
562
  currentPage,
557
563
  totalPages,
558
- onPageChange
564
+ onPageChange,
565
+ align
559
566
  }) => {
560
567
  const pagesAroundCurrent = Array.from(
561
568
  { length: Math.min(3, totalPages) },
562
569
  (_, i) => i + Math.max(currentPage - 1, 1)
563
570
  );
564
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center ", children: [
565
- /* @__PURE__ */ jsxRuntime.jsx(
566
- "button",
567
- {
568
- onClick: () => onPageChange(currentPage - 1),
569
- disabled: currentPage === 1,
570
- "aria-label": "Previous",
571
- className: chunkYERNSNT4_cjs.cn(
572
- "mr-2.5 flex items-center h-10 justify-center rounded-lg border border-gray-300 bg-white px-3.5 py-2.5 text-gray-700 shadow-theme-xs hover:bg-gray-50 disabled:opacity-50 dark:border-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:hover:bg-white/[0.03] text-sm"
573
- ),
574
- children: "Previous"
575
- }
576
- ),
577
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
578
- currentPage > 3 && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "px-2", children: "..." }),
579
- pagesAroundCurrent.map((page) => /* @__PURE__ */ jsxRuntime.jsx(
580
- "button",
581
- {
582
- onClick: () => onPageChange(page),
583
- "aria-current": currentPage === page ? "page" : void 0,
584
- className: chunkYERNSNT4_cjs.cn(
585
- "flex w-10 items-center justify-center h-10 rounded-lg text-sm font-medium",
586
- currentPage === page ? (
587
- // active page keeps its color on hover (no hover restyle)
588
- "bg-brand-500 text-white"
589
- ) : (
590
- // hover effect applies only to non-active page indices
591
- "text-gray-700 hover:bg-blue-500/[0.08] hover:text-brand-500 dark:text-gray-400 dark:hover:text-brand-500"
592
- )
593
- ),
594
- children: page
595
- },
596
- page
597
- )),
598
- currentPage < totalPages - 2 && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "px-2", children: "..." })
599
- ] }),
600
- /* @__PURE__ */ jsxRuntime.jsx(
571
+ const prev = /* @__PURE__ */ jsxRuntime.jsx(
572
+ "button",
573
+ {
574
+ onClick: () => onPageChange(currentPage - 1),
575
+ disabled: currentPage === 1,
576
+ "aria-label": "Previous",
577
+ className: navButton,
578
+ children: "Previous"
579
+ }
580
+ );
581
+ const indices = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
582
+ currentPage > 3 && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "px-2", children: "..." }),
583
+ pagesAroundCurrent.map((page) => /* @__PURE__ */ jsxRuntime.jsx(
601
584
  "button",
602
585
  {
603
- onClick: () => onPageChange(currentPage + 1),
604
- disabled: currentPage === totalPages,
605
- "aria-label": "Next",
586
+ onClick: () => onPageChange(page),
587
+ "aria-current": currentPage === page ? "page" : void 0,
606
588
  className: chunkYERNSNT4_cjs.cn(
607
- "ml-2.5 flex items-center justify-center rounded-lg border border-gray-300 bg-white px-3.5 py-2.5 text-gray-700 shadow-theme-xs text-sm hover:bg-gray-50 h-10 disabled:opacity-50 dark:border-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:hover:bg-white/[0.03]"
589
+ "flex w-10 items-center justify-center h-10 rounded-lg text-sm font-medium",
590
+ currentPage === page ? (
591
+ // active page keeps its color on hover (no hover restyle)
592
+ "bg-brand-500 text-white"
593
+ ) : (
594
+ // hover effect applies only to non-active page indices
595
+ "text-gray-700 hover:bg-blue-500/[0.08] hover:text-brand-500 dark:text-gray-400 dark:hover:text-brand-500"
596
+ )
608
597
  ),
609
- children: "Next"
610
- }
611
- )
598
+ children: page
599
+ },
600
+ page
601
+ )),
602
+ currentPage < totalPages - 2 && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "px-2", children: "..." })
612
603
  ] });
604
+ const next = /* @__PURE__ */ jsxRuntime.jsx(
605
+ "button",
606
+ {
607
+ onClick: () => onPageChange(currentPage + 1),
608
+ disabled: currentPage === totalPages,
609
+ "aria-label": "Next",
610
+ className: navButton,
611
+ children: "Next"
612
+ }
613
+ );
614
+ if (align === "full") {
615
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex w-full items-center justify-between", children: [
616
+ prev,
617
+ indices,
618
+ next
619
+ ] });
620
+ }
621
+ return /* @__PURE__ */ jsxRuntime.jsxs(
622
+ "div",
623
+ {
624
+ className: chunkYERNSNT4_cjs.cn(
625
+ "flex items-center gap-2.5",
626
+ align && "w-full",
627
+ align && justifyByAlign[align]
628
+ ),
629
+ children: [
630
+ prev,
631
+ indices,
632
+ next
633
+ ]
634
+ }
635
+ );
613
636
  };
614
637
  var Input = ({
615
638
  className,
@@ -675,6 +698,7 @@ function DataDrivenTable({
675
698
  rowsPerPage = 10,
676
699
  rowsPerPageOptions = [5, 10, 25, 50],
677
700
  pagination = true,
701
+ paginationAlign = "right",
678
702
  showSizeSelector = true,
679
703
  searchKeys,
680
704
  searchPlaceholder = "Search...",
@@ -726,6 +750,7 @@ function DataDrivenTable({
726
750
  const sizeOptions = rowsPerPageOptions.length ? rowsPerPageOptions : [];
727
751
  const showSelector = pagination && showSizeSelector && sizeOptions.length > 1;
728
752
  const showControls = showSearch || showSelector;
753
+ const counterText = total === 0 ? "Showing 0 entries" : `Showing ${start + 1} to ${Math.min(start + pageSize, total)} of ${total} entries`;
729
754
  return /* @__PURE__ */ jsxRuntime.jsxs(
730
755
  "div",
731
756
  {
@@ -824,10 +849,36 @@ function DataDrivenTable({
824
849
  pageRows.length === 0 && /* @__PURE__ */ jsxRuntime.jsx(TableRow, { children: /* @__PURE__ */ jsxRuntime.jsx(TableCell, { colSpan: columns.length, className: "px-5 py-6 text-center text-sm text-gray-400", children: emptyContent }) })
825
850
  ] })
826
851
  ] }) }),
827
- pagination && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3 p-4", children: [
828
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-500 dark:text-gray-400", children: total === 0 ? "Showing 0 entries" : `Showing ${start + 1} to ${Math.min(start + pageSize, total)} of ${total} entries` }),
829
- totalPages > 1 && /* @__PURE__ */ jsxRuntime.jsx(Pagination, { currentPage: current, totalPages, onPageChange: setPage })
830
- ] })
852
+ pagination && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4", children: paginationAlign === "right" ? (
853
+ // Default layout: entry counter on the left, controls on the right.
854
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3", children: [
855
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-500 dark:text-gray-400", children: counterText }),
856
+ totalPages > 1 && /* @__PURE__ */ jsxRuntime.jsx(Pagination, { currentPage: current, totalPages, onPageChange: setPage })
857
+ ] })
858
+ ) : (
859
+ // Aligned layout: controls aligned/stretched, counter underneath.
860
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3", children: [
861
+ totalPages > 1 && /* @__PURE__ */ jsxRuntime.jsx(
862
+ Pagination,
863
+ {
864
+ align: paginationAlign,
865
+ currentPage: current,
866
+ totalPages,
867
+ onPageChange: setPage
868
+ }
869
+ ),
870
+ /* @__PURE__ */ jsxRuntime.jsx(
871
+ "p",
872
+ {
873
+ className: chunkYERNSNT4_cjs.cn(
874
+ "text-sm text-gray-500 dark:text-gray-400",
875
+ paginationAlign === "center" && "text-center"
876
+ ),
877
+ children: counterText
878
+ }
879
+ )
880
+ ] })
881
+ ) })
831
882
  ]
832
883
  }
833
884
  );
@@ -839,6 +890,7 @@ function Table({
839
890
  rowsPerPage,
840
891
  rowsPerPageOptions,
841
892
  pagination,
893
+ paginationAlign,
842
894
  showSizeSelector,
843
895
  searchKeys,
844
896
  searchPlaceholder,
@@ -859,6 +911,7 @@ function Table({
859
911
  rowsPerPage,
860
912
  rowsPerPageOptions,
861
913
  pagination,
914
+ paginationAlign,
862
915
  showSizeSelector,
863
916
  searchKeys,
864
917
  searchPlaceholder,