@dynostack/react-grid 0.3.0 → 0.3.2
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 +72 -12
- package/dist/index.cjs +24 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +25 -11
- package/dist/index.js.map +1 -1
- package/dist/styles.css +51 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -26,6 +26,8 @@ A single `<DataTable />` component that gives you ag-grid–level functionality
|
|
|
26
26
|
- **Selection + bulk actions** — pinned `__select` column with select-all, clear, bulk delete
|
|
27
27
|
- **Expandable rows** — provide a `renderSubRow` panel or use TanStack's nested `getSubRows`
|
|
28
28
|
- **CSV / Excel export** — selection-aware (export selected vs. all)
|
|
29
|
+
- **Built-in row Details panel** — `View` opens a scoped sheet with compact, relaxed, and comfy field layouts
|
|
30
|
+
- **Scoped delete confirmation** — row and bulk delete confirmations stay inside the table instead of covering the entire app
|
|
29
31
|
- **Theming that just works** — shadcn-compatible CSS variables, automatic OS dark-mode follow, cascade-layered defaults that never overwrite your app theme, full-repaint moded presets (`violet`, `emerald`, `amber`, `rose`, `sky`, `slate`, …), `buildPreset(hue)` for custom hues, and `isolate` to opt out of inheriting the app theme
|
|
30
32
|
- **Density** — `compact` · `default` · `comfortable`
|
|
31
33
|
- **i18n / labels** — every visible string is overridable
|
|
@@ -77,7 +79,28 @@ yarn add @dynostack/react-grid
|
|
|
77
79
|
|
|
78
80
|
## Tailwind setup
|
|
79
81
|
|
|
80
|
-
The component ships Tailwind class names verbatim
|
|
82
|
+
The component ships Tailwind class names verbatim, so your Tailwind build needs to know two things:
|
|
83
|
+
|
|
84
|
+
1. **Where to scan** for the class strings inside the bundle.
|
|
85
|
+
2. **Which semantic color tokens** (`bg-popover`, `bg-card`, `text-foreground`, …) exist.
|
|
86
|
+
|
|
87
|
+
The package's `styles.css` registers the tokens for you via Tailwind v4's `@theme inline`. You only need to wire scanning.
|
|
88
|
+
|
|
89
|
+
### Tailwind v4 — zero config
|
|
90
|
+
|
|
91
|
+
```css
|
|
92
|
+
/* your global stylesheet (e.g. src/index.css) */
|
|
93
|
+
@import "tailwindcss";
|
|
94
|
+
@source "../node_modules/@dynostack/react-grid/dist";
|
|
95
|
+
@import "@dynostack/react-grid/styles.css";
|
|
96
|
+
@import "@dynostack/react-grid/page.css"; /* optional: extend tokens to <body> */
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
That's the whole setup. No `tailwind.config.js`, no `@theme` block to copy-paste, no shadcn install required. Overlay surfaces (popovers, dropdowns, sheets, the row-actions menu) all render correctly out of the box.
|
|
100
|
+
|
|
101
|
+
### Tailwind v3
|
|
102
|
+
|
|
103
|
+
v3 doesn't read CSS `@theme` directives, so the semantic-color mapping has to live in your `tailwind.config.js`. The shadcn install guide for v3 covers the exact `theme.extend.colors` block you need — copy that, plus add the package's `dist` to your `content` array:
|
|
81
104
|
|
|
82
105
|
```js
|
|
83
106
|
// tailwind.config.{js,ts}
|
|
@@ -86,10 +109,28 @@ export default {
|
|
|
86
109
|
"./src/**/*.{ts,tsx}",
|
|
87
110
|
"./node_modules/@dynostack/react-grid/dist/**/*.{js,mjs,cjs}",
|
|
88
111
|
],
|
|
112
|
+
theme: {
|
|
113
|
+
extend: {
|
|
114
|
+
colors: {
|
|
115
|
+
// copy the shadcn v3 color mapping here
|
|
116
|
+
// (background, foreground, card, popover, primary, secondary,
|
|
117
|
+
// muted, accent, destructive, border, input, ring)
|
|
118
|
+
background: "hsl(var(--background))",
|
|
119
|
+
foreground: "hsl(var(--foreground))",
|
|
120
|
+
// … etc
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
},
|
|
89
124
|
}
|
|
90
125
|
```
|
|
91
126
|
|
|
92
|
-
|
|
127
|
+
Then import `styles.css` as usual:
|
|
128
|
+
|
|
129
|
+
```ts
|
|
130
|
+
import "@dynostack/react-grid/styles.css"
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
> Starting a new project? **Use Tailwind v4.** The v4 path above is meaningfully simpler — the package handles token registration for you.
|
|
93
134
|
|
|
94
135
|
## Theme tokens
|
|
95
136
|
|
|
@@ -104,15 +145,22 @@ The grid is built on **shadcn/ui CSS variables**. It auto-adjusts to whatever th
|
|
|
104
145
|
| Custom theme with non-shadcn names | Pass [`theme` prop](#theming) | Per-instance override mapped to shadcn vars. |
|
|
105
146
|
| Want one grid to ignore the app theme | Pass `isolate` | Grid uses bundled defaults regardless of `:root`. |
|
|
106
147
|
|
|
107
|
-
**Why this just works.** The bundled `styles.css
|
|
148
|
+
**Why this just works.** The bundled `styles.css`:
|
|
108
149
|
|
|
109
|
-
|
|
150
|
+
1. **Registers Tailwind v4 utility tokens** via a top-level `@theme inline` block — so `bg-popover`, `text-foreground`, `border-border`, etc. resolve to your tokens without any consumer-side `@theme` block.
|
|
151
|
+
2. **Declares variable values inside the `dynostack-grid-defaults` cascade layer** — any unlayered consumer rule (which is where shadcn and most app CSS lives) automatically wins, regardless of import order. You can't accidentally overwrite your app's theme by importing the grid's stylesheet.
|
|
110
152
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
153
|
+
### Minimal install (Tailwind v4)
|
|
154
|
+
|
|
155
|
+
```css
|
|
156
|
+
/* your global stylesheet */
|
|
157
|
+
@import "tailwindcss";
|
|
158
|
+
@source "../node_modules/@dynostack/react-grid/dist";
|
|
159
|
+
@import "@dynostack/react-grid/styles.css";
|
|
114
160
|
```
|
|
115
161
|
|
|
162
|
+
See the [Tailwind setup](#tailwind-setup) section for v3.
|
|
163
|
+
|
|
116
164
|
### Optional: extend the theme to the page
|
|
117
165
|
|
|
118
166
|
By default the grid only styles itself, not the surrounding page. If you want `<body>` to use the same background/foreground as the grid:
|
|
@@ -567,7 +615,7 @@ The set filter automatically derives unique values from the visible rows when `s
|
|
|
567
615
|
Selection is on by default (`enableSelection: true`). When any row is selected the toolbar swaps in:
|
|
568
616
|
|
|
569
617
|
- A `<count> selected` badge
|
|
570
|
-
- `Delete` button →
|
|
618
|
+
- `Delete` button → opens the confirmation dialog first, then calls `onBulkDelete?(rows)` after confirm
|
|
571
619
|
- `Clear` button → resets selection
|
|
572
620
|
|
|
573
621
|
```tsx
|
|
@@ -614,7 +662,15 @@ Mark a column non-exportable via `meta.exportable: false`.
|
|
|
614
662
|
|
|
615
663
|
## View sheet
|
|
616
664
|
|
|
617
|
-
Click the row action "View" → a right-side `Sheet` slides in showing every visible column as a `{Label}: {value}` card. The user can switch layout density inline
|
|
665
|
+
Click the row action "View" → a right-side `Sheet` slides in showing every visible column as a `{Label}: {value}` card. The user can switch layout density inline:
|
|
666
|
+
|
|
667
|
+
| Option | Layout | Intended use |
|
|
668
|
+
| --- | --- | --- |
|
|
669
|
+
| `Compact` | 3 columns, tighter cards | Scan more fields at once. |
|
|
670
|
+
| `Relaxed` | 2 columns, medium spacing | Balanced default for mixed values. |
|
|
671
|
+
| `Comfy` | 1 column, roomier cards | Read long values without cramped wrapping. |
|
|
672
|
+
|
|
673
|
+
The sheet is responsive and wider on desktop so the multi-column modes have enough room for real row data.
|
|
618
674
|
|
|
619
675
|
Works out of the box with no props. Customize via `viewSheet`:
|
|
620
676
|
|
|
@@ -622,7 +678,7 @@ Works out of the box with no props. Customize via `viewSheet`:
|
|
|
622
678
|
<DataTable
|
|
623
679
|
viewSheet={{
|
|
624
680
|
side: "right", // or "left"
|
|
625
|
-
defaultDensity: "relaxed", // initial
|
|
681
|
+
defaultDensity: "relaxed", // initial layout density
|
|
626
682
|
hideDensityTabs: true, // hide the layout picker
|
|
627
683
|
fields: ["name", "email", "role"], // limit / reorder shown columns
|
|
628
684
|
renderField: ({ column, value, row }) => // override how a value renders
|
|
@@ -632,7 +688,7 @@ Works out of the box with no props. Customize via `viewSheet`:
|
|
|
632
688
|
title: (row) => `${row.name} (${row.role})`,
|
|
633
689
|
description: (row) => `Joined ${row.joinedAt}`,
|
|
634
690
|
emptyValue: "—",
|
|
635
|
-
density: { compact: "
|
|
691
|
+
density: { compact: "3 cols", relaxed: "2 cols", comfy: "1 col" },
|
|
636
692
|
},
|
|
637
693
|
}}
|
|
638
694
|
onView={(row) => track("user.view", row)} // optional side-effect
|
|
@@ -653,6 +709,8 @@ Disable the built-in sheet entirely:
|
|
|
653
709
|
|
|
654
710
|
Both the row-action "Delete" and the toolbar "Bulk delete" open a confirmation `AlertDialog` by default. The user must confirm before `onDelete` or `onBulkDelete` fires.
|
|
655
711
|
|
|
712
|
+
The dialog is mounted inside the DataTable portal container, so its blur / dim overlay covers only that table instance. It does not block or blur the rest of the page.
|
|
713
|
+
|
|
656
714
|
```tsx
|
|
657
715
|
<DataTable
|
|
658
716
|
onDelete={(row) => api.deleteUser(row.id)}
|
|
@@ -670,6 +728,8 @@ Both the row-action "Delete" and the toolbar "Bulk delete" open a confirmation `
|
|
|
670
728
|
/>
|
|
671
729
|
```
|
|
672
730
|
|
|
731
|
+
Use `onDelete` for the built-in row delete action. Do not put the actual delete mutation in `onRowAction("delete")`, because the built-in delete action is handled by the confirmation flow.
|
|
732
|
+
|
|
673
733
|
Skip the dialog (fire immediately):
|
|
674
734
|
|
|
675
735
|
```tsx
|
|
@@ -694,10 +754,10 @@ Skip the dialog (fire immediately):
|
|
|
694
754
|
{ id: "archive", label: "Archive", icon: <ArchiveIcon /> },
|
|
695
755
|
]}
|
|
696
756
|
onRowAction={(action, row) => {
|
|
697
|
-
if (action === "delete") deleteMutation.mutate([row.id])
|
|
698
757
|
if (action === "suspend") saveMutation.mutate({ ...row, status: "suspended" })
|
|
699
758
|
// ...
|
|
700
759
|
}}
|
|
760
|
+
onDelete={(row) => deleteMutation.mutate([row.id])}
|
|
701
761
|
/>
|
|
702
762
|
```
|
|
703
763
|
|
package/dist/index.cjs
CHANGED
|
@@ -2216,8 +2216,8 @@ function SheetOverlay({
|
|
|
2216
2216
|
);
|
|
2217
2217
|
}
|
|
2218
2218
|
var SIDE_CLASS = {
|
|
2219
|
-
right: "right-0 top-0 h-full w-
|
|
2220
|
-
left: "left-0 top-0 h-full w-
|
|
2219
|
+
right: "right-0 top-0 h-full w-full border-l sm:w-[min(48rem,calc(100vw-2rem))] data-closed:slide-out-to-right data-open:slide-in-from-right",
|
|
2220
|
+
left: "left-0 top-0 h-full w-full border-r sm:w-[min(48rem,calc(100vw-2rem))] data-closed:slide-out-to-left data-open:slide-in-from-left",
|
|
2221
2221
|
top: "left-0 top-0 w-full max-h-[80vh] border-b data-closed:slide-out-to-top data-open:slide-in-from-top",
|
|
2222
2222
|
bottom: "left-0 bottom-0 w-full max-h-[80vh] border-t data-closed:slide-out-to-bottom data-open:slide-in-from-bottom"
|
|
2223
2223
|
};
|
|
@@ -2292,14 +2292,19 @@ function SheetDescription({
|
|
|
2292
2292
|
);
|
|
2293
2293
|
}
|
|
2294
2294
|
var COLS_CLASS = {
|
|
2295
|
-
compact: "grid-cols-1",
|
|
2295
|
+
compact: "grid-cols-1 sm:grid-cols-2 lg:grid-cols-3",
|
|
2296
2296
|
relaxed: "grid-cols-1 sm:grid-cols-2",
|
|
2297
|
-
comfy: "grid-cols-1
|
|
2297
|
+
comfy: "grid-cols-1"
|
|
2298
|
+
};
|
|
2299
|
+
var CARD_CLASS = {
|
|
2300
|
+
compact: "gap-0.5 p-2.5",
|
|
2301
|
+
relaxed: "gap-1 p-3",
|
|
2302
|
+
comfy: "gap-1.5 p-4"
|
|
2298
2303
|
};
|
|
2299
2304
|
var DENSITY_ICON = {
|
|
2300
|
-
compact: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.
|
|
2305
|
+
compact: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.LayoutGridIcon, { className: "size-3.5" }),
|
|
2301
2306
|
relaxed: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Rows3Icon, { className: "size-3.5" }),
|
|
2302
|
-
comfy: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.
|
|
2307
|
+
comfy: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ListIcon, { className: "size-3.5" })
|
|
2303
2308
|
};
|
|
2304
2309
|
function DataTableViewSheet({
|
|
2305
2310
|
table,
|
|
@@ -2372,10 +2377,13 @@ function DataTableViewSheet({
|
|
|
2372
2377
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2373
2378
|
"div",
|
|
2374
2379
|
{
|
|
2375
|
-
className:
|
|
2380
|
+
className: cn(
|
|
2381
|
+
"flex min-w-0 flex-col rounded-md border bg-card",
|
|
2382
|
+
CARD_CLASS[density]
|
|
2383
|
+
),
|
|
2376
2384
|
children: [
|
|
2377
2385
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[11px] uppercase tracking-wide text-muted-foreground", children: headerLabel }),
|
|
2378
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-foreground
|
|
2386
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "break-words text-sm text-foreground", children: rendered })
|
|
2379
2387
|
]
|
|
2380
2388
|
},
|
|
2381
2389
|
colId
|
|
@@ -2400,11 +2408,15 @@ function AlertDialogContent({
|
|
|
2400
2408
|
...props
|
|
2401
2409
|
}) {
|
|
2402
2410
|
const container = usePortalContainer();
|
|
2411
|
+
const positionClass = container ? "absolute" : "fixed";
|
|
2403
2412
|
return /* @__PURE__ */ jsxRuntime.jsxs(radixUi.AlertDialog.Portal, { container: container ?? void 0, children: [
|
|
2404
2413
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2405
2414
|
radixUi.AlertDialog.Overlay,
|
|
2406
2415
|
{
|
|
2407
|
-
className:
|
|
2416
|
+
className: cn(
|
|
2417
|
+
"inset-0 z-50 bg-foreground/30 backdrop-blur-sm data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0",
|
|
2418
|
+
positionClass
|
|
2419
|
+
)
|
|
2408
2420
|
}
|
|
2409
2421
|
),
|
|
2410
2422
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -2412,7 +2424,8 @@ function AlertDialogContent({
|
|
|
2412
2424
|
{
|
|
2413
2425
|
"data-slot": "alert-dialog-content",
|
|
2414
2426
|
className: cn(
|
|
2415
|
-
"
|
|
2427
|
+
"top-1/2 left-1/2 z-50 grid w-[calc(100%-2rem)] max-w-md -translate-x-1/2 -translate-y-1/2 gap-4 rounded-lg border bg-background p-6 shadow-lg outline-none data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
|
|
2428
|
+
positionClass,
|
|
2416
2429
|
className
|
|
2417
2430
|
),
|
|
2418
2431
|
...props,
|
|
@@ -2631,6 +2644,7 @@ function ActionsCellHost({ row }) {
|
|
|
2631
2644
|
onView?.(row.original);
|
|
2632
2645
|
} else if (a === "delete") {
|
|
2633
2646
|
onRequestDelete?.(row.original);
|
|
2647
|
+
return;
|
|
2634
2648
|
}
|
|
2635
2649
|
onRowAction?.(a, row.original);
|
|
2636
2650
|
}
|