@andreagiugni/tailwind-dashboard-ui 0.2.0 → 0.3.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 +22 -16
- package/dist/index.cjs +62 -24
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +36 -36
- package/dist/index.d.ts +36 -36
- package/dist/index.js +64 -25
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -152,9 +152,9 @@ Legend: **(+native)** = also extends the element's native HTML attributes.
|
|
|
152
152
|
| `Dropdown` | `isOpen`, `onClose`, `children`, (+native div) |
|
|
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
|
-
| `Table`
|
|
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?` |
|
|
156
157
|
| `Pagination` | `currentPage`, `totalPages`, `onPageChange` |
|
|
157
|
-
| `DataTable` | `data`, `columns` (`key`, `header`, `sortable?`, `align?`, `render?`), `rowsPerPage?`, `rowsPerPageOptions?`, `searchable?`, `searchKeys?`, `defaultSortKey?` / `defaultSortDirection?`, `pagination?`, `showSizeSelector?`, `onRowClick?`, `getRowId?`, `emptyContent?` — generic, search + per-column sort + pagination built in |
|
|
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) |
|
|
@@ -232,14 +232,18 @@ const Editor = dynamic(
|
|
|
232
232
|
/>
|
|
233
233
|
```
|
|
234
234
|
|
|
235
|
-
##
|
|
235
|
+
## Table
|
|
236
236
|
|
|
237
|
-
`
|
|
238
|
-
|
|
239
|
-
|
|
237
|
+
`Table` has **two modes**, both under the same component:
|
|
238
|
+
|
|
239
|
+
1. **Composable** — use `Table` / `TableHeader` / `TableBody` / `TableRow` / `TableCell` as thin,
|
|
240
|
+
styled wrappers around the native table elements when you want full control over the markup.
|
|
241
|
+
2. **Data-driven** — pass a `data` array and a `columns` definition and you get live search,
|
|
242
|
+
per-column click-to-sort, a "Show N entries" selector and pagination out of the box. The mode
|
|
243
|
+
switches on automatically as soon as `columns` is provided.
|
|
240
244
|
|
|
241
245
|
```tsx
|
|
242
|
-
import {
|
|
246
|
+
import { Table, type TableColumn } from '@andreagiugni/tailwind-dashboard-ui';
|
|
243
247
|
|
|
244
248
|
type Person = { name: string; office: string; salary: number };
|
|
245
249
|
|
|
@@ -249,7 +253,7 @@ const people: Person[] = [
|
|
|
249
253
|
// …
|
|
250
254
|
];
|
|
251
255
|
|
|
252
|
-
const columns:
|
|
256
|
+
const columns: TableColumn<Person>[] = [
|
|
253
257
|
{ key: 'name', header: 'User', sortable: true },
|
|
254
258
|
{ key: 'office', header: 'Office', sortable: true },
|
|
255
259
|
{
|
|
@@ -261,23 +265,25 @@ const columns: DataTableColumn<Person>[] = [
|
|
|
261
265
|
},
|
|
262
266
|
];
|
|
263
267
|
|
|
264
|
-
<
|
|
268
|
+
<Table
|
|
265
269
|
data={people}
|
|
266
270
|
columns={columns}
|
|
267
|
-
rowsPerPage={5}
|
|
271
|
+
rowsPerPage={5} // max rows per page (default 10)
|
|
268
272
|
rowsPerPageOptions={[5, 10, 25]}
|
|
269
273
|
defaultSortKey="name"
|
|
270
|
-
searchKeys={['name', 'office']}
|
|
274
|
+
searchKeys={['name', 'office']} // omit to hide the search box
|
|
271
275
|
onRowClick={(row) => console.log(row)}
|
|
272
276
|
/>
|
|
273
277
|
```
|
|
274
278
|
|
|
275
|
-
Key props: `data`, `columns` (each: `key`, `header`, `sortable?`, `align?`, `render?`,
|
|
279
|
+
Key data-driven props: `data`, `columns` (each: `key`, `header`, `sortable?`, `align?`, `render?`,
|
|
276
280
|
`className?`), `rowsPerPage` (default 10), `rowsPerPageOptions` (default `[5,10,25,50]`),
|
|
277
|
-
`
|
|
278
|
-
`
|
|
279
|
-
|
|
280
|
-
|
|
281
|
+
`searchKeys` / `searchPlaceholder`, `defaultSortKey` / `defaultSortDirection`, `pagination`,
|
|
282
|
+
`showSizeSelector`, `onRowClick`, `getRowId`, `emptyContent`.
|
|
283
|
+
|
|
284
|
+
> **Search visibility:** the search input renders **only** when you pass a non-empty `searchKeys`
|
|
285
|
+
> array — those are also the exact fields the query matches. Omit `searchKeys` (or pass `[]`) to
|
|
286
|
+
> hide search entirely.
|
|
281
287
|
|
|
282
288
|
## License
|
|
283
289
|
|
package/dist/index.cjs
CHANGED
|
@@ -552,19 +552,6 @@ var Dropzone = ({
|
|
|
552
552
|
}
|
|
553
553
|
);
|
|
554
554
|
};
|
|
555
|
-
var Table = ({ children, className, ...rest }) => /* @__PURE__ */ jsxRuntime.jsx("table", { className: chunkYERNSNT4_cjs.cn("min-w-full", className), ...rest, children });
|
|
556
|
-
var TableHeader = ({ children, className, ...rest }) => /* @__PURE__ */ jsxRuntime.jsx("thead", { className, ...rest, children });
|
|
557
|
-
var TableBody = ({ children, className, ...rest }) => /* @__PURE__ */ jsxRuntime.jsx("tbody", { className, ...rest, children });
|
|
558
|
-
var TableRow = ({ children, className, ...rest }) => /* @__PURE__ */ jsxRuntime.jsx("tr", { className, ...rest, children });
|
|
559
|
-
var TableCell = ({
|
|
560
|
-
children,
|
|
561
|
-
isHeader = false,
|
|
562
|
-
className,
|
|
563
|
-
...rest
|
|
564
|
-
}) => {
|
|
565
|
-
const Tag = isHeader ? "th" : "td";
|
|
566
|
-
return /* @__PURE__ */ jsxRuntime.jsx(Tag, { className, ...rest, children });
|
|
567
|
-
};
|
|
568
555
|
var Pagination = ({
|
|
569
556
|
currentPage,
|
|
570
557
|
totalPages,
|
|
@@ -654,6 +641,18 @@ var Input = ({
|
|
|
654
641
|
hint && /* @__PURE__ */ jsxRuntime.jsx("p", { className: chunkYERNSNT4_cjs.cn("mt-1.5 text-xs", error ? "text-error-500" : success ? "text-success-500" : "text-gray-500"), children: hint })
|
|
655
642
|
] });
|
|
656
643
|
};
|
|
644
|
+
var TableHeader = ({ children, className, ...rest }) => /* @__PURE__ */ jsxRuntime.jsx("thead", { className, ...rest, children });
|
|
645
|
+
var TableBody = ({ children, className, ...rest }) => /* @__PURE__ */ jsxRuntime.jsx("tbody", { className, ...rest, children });
|
|
646
|
+
var TableRow = ({ children, className, ...rest }) => /* @__PURE__ */ jsxRuntime.jsx("tr", { className, ...rest, children });
|
|
647
|
+
var TableCell = ({
|
|
648
|
+
children,
|
|
649
|
+
isHeader = false,
|
|
650
|
+
className,
|
|
651
|
+
...rest
|
|
652
|
+
}) => {
|
|
653
|
+
const Tag = isHeader ? "th" : "td";
|
|
654
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Tag, { className, ...rest, children });
|
|
655
|
+
};
|
|
657
656
|
var alignClass = {
|
|
658
657
|
left: "text-left",
|
|
659
658
|
center: "text-center",
|
|
@@ -670,16 +669,15 @@ function SortIcon({
|
|
|
670
669
|
/* @__PURE__ */ jsxRuntime.jsx("svg", { width: "10", height: "6", viewBox: "0 0 10 6", fill: "currentColor", "aria-hidden": "true", className: active && direction === "desc" ? on : off, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M5 6 1 1h8z" }) })
|
|
671
670
|
] });
|
|
672
671
|
}
|
|
673
|
-
function
|
|
672
|
+
function DataDrivenTable({
|
|
674
673
|
data,
|
|
675
674
|
columns,
|
|
676
675
|
rowsPerPage = 10,
|
|
677
676
|
rowsPerPageOptions = [5, 10, 25, 50],
|
|
678
677
|
pagination = true,
|
|
679
678
|
showSizeSelector = true,
|
|
680
|
-
searchable = true,
|
|
681
|
-
searchPlaceholder = "Search...",
|
|
682
679
|
searchKeys,
|
|
680
|
+
searchPlaceholder = "Search...",
|
|
683
681
|
defaultSortKey,
|
|
684
682
|
defaultSortDirection = "asc",
|
|
685
683
|
getRowId,
|
|
@@ -692,13 +690,13 @@ function DataTable({
|
|
|
692
690
|
const [sortKey, setSortKey] = React5.useState(defaultSortKey);
|
|
693
691
|
const [sortDir, setSortDir] = React5.useState(defaultSortDirection);
|
|
694
692
|
const [page, setPage] = React5.useState(1);
|
|
693
|
+
const showSearch = !!(searchKeys && searchKeys.length > 0);
|
|
695
694
|
const filtered = React5.useMemo(() => {
|
|
696
|
-
const keys = searchKeys ?? columns.map((c) => c.key);
|
|
697
695
|
const q = search.trim().toLowerCase();
|
|
698
696
|
let rows = data;
|
|
699
|
-
if (
|
|
697
|
+
if (showSearch && q) {
|
|
700
698
|
rows = rows.filter(
|
|
701
|
-
(row) =>
|
|
699
|
+
(row) => searchKeys.some((k) => String(row[k] ?? "").toLowerCase().includes(q))
|
|
702
700
|
);
|
|
703
701
|
}
|
|
704
702
|
if (sortKey) {
|
|
@@ -710,7 +708,7 @@ function DataTable({
|
|
|
710
708
|
});
|
|
711
709
|
}
|
|
712
710
|
return rows;
|
|
713
|
-
}, [data,
|
|
711
|
+
}, [data, search, showSearch, searchKeys, sortKey, sortDir]);
|
|
714
712
|
const total = filtered.length;
|
|
715
713
|
const totalPages = pagination ? Math.max(1, Math.ceil(total / pageSize)) : 1;
|
|
716
714
|
const current = Math.min(page, totalPages);
|
|
@@ -727,7 +725,7 @@ function DataTable({
|
|
|
727
725
|
};
|
|
728
726
|
const sizeOptions = rowsPerPageOptions.length ? rowsPerPageOptions : [];
|
|
729
727
|
const showSelector = pagination && showSizeSelector && sizeOptions.length > 1;
|
|
730
|
-
const showControls =
|
|
728
|
+
const showControls = showSearch || showSelector;
|
|
731
729
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
732
730
|
"div",
|
|
733
731
|
{
|
|
@@ -754,7 +752,7 @@ function DataTable({
|
|
|
754
752
|
),
|
|
755
753
|
"entries"
|
|
756
754
|
] }) : /* @__PURE__ */ jsxRuntime.jsx("span", {}),
|
|
757
|
-
|
|
755
|
+
showSearch && /* @__PURE__ */ jsxRuntime.jsx(
|
|
758
756
|
Input,
|
|
759
757
|
{
|
|
760
758
|
type: "search",
|
|
@@ -769,7 +767,7 @@ function DataTable({
|
|
|
769
767
|
}
|
|
770
768
|
)
|
|
771
769
|
] }),
|
|
772
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-x-auto border-y border-gray-100 dark:border-white/[0.05]", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
770
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-x-auto border-y border-gray-100 dark:border-white/[0.05]", children: /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "min-w-full", children: [
|
|
773
771
|
/* @__PURE__ */ jsxRuntime.jsx(TableHeader, { className: "border-b border-gray-100 bg-gray-50 dark:border-white/[0.05] dark:bg-white/[0.06]", children: /* @__PURE__ */ jsxRuntime.jsx(TableRow, { children: columns.map((col) => {
|
|
774
772
|
const isActive = sortKey === col.key;
|
|
775
773
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -834,6 +832,47 @@ function DataTable({
|
|
|
834
832
|
}
|
|
835
833
|
);
|
|
836
834
|
}
|
|
835
|
+
function Table({
|
|
836
|
+
children,
|
|
837
|
+
data,
|
|
838
|
+
columns,
|
|
839
|
+
rowsPerPage,
|
|
840
|
+
rowsPerPageOptions,
|
|
841
|
+
pagination,
|
|
842
|
+
showSizeSelector,
|
|
843
|
+
searchKeys,
|
|
844
|
+
searchPlaceholder,
|
|
845
|
+
defaultSortKey,
|
|
846
|
+
defaultSortDirection,
|
|
847
|
+
getRowId,
|
|
848
|
+
onRowClick,
|
|
849
|
+
emptyContent,
|
|
850
|
+
className,
|
|
851
|
+
...rest
|
|
852
|
+
}) {
|
|
853
|
+
if (columns && data) {
|
|
854
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
855
|
+
DataDrivenTable,
|
|
856
|
+
{
|
|
857
|
+
data,
|
|
858
|
+
columns,
|
|
859
|
+
rowsPerPage,
|
|
860
|
+
rowsPerPageOptions,
|
|
861
|
+
pagination,
|
|
862
|
+
showSizeSelector,
|
|
863
|
+
searchKeys,
|
|
864
|
+
searchPlaceholder,
|
|
865
|
+
defaultSortKey,
|
|
866
|
+
defaultSortDirection,
|
|
867
|
+
getRowId,
|
|
868
|
+
onRowClick,
|
|
869
|
+
emptyContent,
|
|
870
|
+
className
|
|
871
|
+
}
|
|
872
|
+
);
|
|
873
|
+
}
|
|
874
|
+
return /* @__PURE__ */ jsxRuntime.jsx("table", { className: chunkYERNSNT4_cjs.cn("min-w-full", className), ...rest, children });
|
|
875
|
+
}
|
|
837
876
|
var ChevronIcon = () => /* @__PURE__ */ jsxRuntime.jsx(
|
|
838
877
|
"svg",
|
|
839
878
|
{
|
|
@@ -3081,7 +3120,6 @@ exports.Card = Card;
|
|
|
3081
3120
|
exports.Checkbox = Checkbox;
|
|
3082
3121
|
exports.Chip = Chip;
|
|
3083
3122
|
exports.Code = Code;
|
|
3084
|
-
exports.DataTable = DataTable;
|
|
3085
3123
|
exports.DatePicker = DatePicker;
|
|
3086
3124
|
exports.DateTimePicker = DateTimePicker;
|
|
3087
3125
|
exports.Drawer = Drawer;
|