@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 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` / `TableHeader` / `TableBody` / `TableRow` / `TableCell` | `children`, `isHeader` (cell), (+native table elements; `onClick` / `onDoubleClick` on rows & cells) |
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
- ## Data table
235
+ ## Table
236
236
 
237
- `DataTable` is a generic, batteries-included table: pass your `data` array and a `columns`
238
- definition and you get live search, per-column click-to-sort, a "Show N entries" selector and
239
- pagination out of the box. Light/dark styling follows the standard `.dark` variant.
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 { DataTable, type DataTableColumn } from '@andreagiugni/tailwind-dashboard-ui';
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: DataTableColumn<Person>[] = [
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
- <DataTable
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
- `searchable` / `searchPlaceholder` / `searchKeys`, `defaultSortKey` / `defaultSortDirection`,
278
- `pagination`, `showSizeSelector`, `onRowClick`, `getRowId`, `emptyContent`. It is built on the
279
- exported `Table`, `Input` and `Pagination` primitives — drop down to those directly if you need
280
- full control over the markup.
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 DataTable({
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 (searchable && q) {
697
+ if (showSearch && q) {
700
698
  rows = rows.filter(
701
- (row) => keys.some((k) => String(row[k] ?? "").toLowerCase().includes(q))
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, columns, search, searchable, searchKeys, sortKey, sortDir]);
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 = searchable || showSelector;
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
- searchable && /* @__PURE__ */ jsxRuntime.jsx(
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(Table, { children: [
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;