@mostrom/app-shell 0.1.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.
Files changed (142) hide show
  1. package/.claude/ralph-loop.local.md +9 -0
  2. package/README.md +172 -0
  3. package/bin/init.js +269 -0
  4. package/bun.lock +401 -0
  5. package/components.json +28 -0
  6. package/package.json +74 -0
  7. package/scripts/publish-npm.sh +202 -0
  8. package/src/AppShell.tsx +847 -0
  9. package/src/components/PageHeader.tsx +160 -0
  10. package/src/components/data-table/README.md +447 -0
  11. package/src/components/data-table/data-table-preferences.tsx +184 -0
  12. package/src/components/data-table/data-table-toolbar.tsx +118 -0
  13. package/src/components/data-table/data-table.tsx +37 -0
  14. package/src/components/data-table/index.ts +32 -0
  15. package/src/components/global-header/AllServicesButton.tsx +127 -0
  16. package/src/components/global-header/CategoriesButton.tsx +120 -0
  17. package/src/components/global-header/GlobalHeader.tsx +59 -0
  18. package/src/components/global-header/GlobalHeaderSearch.tsx +57 -0
  19. package/src/components/global-header/HeaderUtilities.tsx +243 -0
  20. package/src/components/global-header/ServicesMenu.tsx +246 -0
  21. package/src/components/layout/AppBreadcrumb.tsx +70 -0
  22. package/src/components/layout/AppFlashbar.tsx +95 -0
  23. package/src/components/layout/AppLayout.tsx +271 -0
  24. package/src/components/layout/AppNavigation.tsx +313 -0
  25. package/src/components/layout/AppSidebar.tsx +229 -0
  26. package/src/components/patterns/index.ts +14 -0
  27. package/src/components/patterns/p-alert-5.tsx +19 -0
  28. package/src/components/patterns/p-autocomplete-5.tsx +89 -0
  29. package/src/components/patterns/p-breadcrumb-1.tsx +28 -0
  30. package/src/components/patterns/p-button-42.tsx +37 -0
  31. package/src/components/patterns/p-button-51.tsx +14 -0
  32. package/src/components/patterns/p-button-6.tsx +5 -0
  33. package/src/components/patterns/p-calendar-1.tsx +18 -0
  34. package/src/components/patterns/p-card-1.tsx +33 -0
  35. package/src/components/patterns/p-card-2.tsx +26 -0
  36. package/src/components/patterns/p-card-5.tsx +31 -0
  37. package/src/components/patterns/p-collapsible-7.tsx +121 -0
  38. package/src/components/patterns/p-command-6.tsx +113 -0
  39. package/src/components/patterns/p-dialog-1.tsx +56 -0
  40. package/src/components/patterns/p-dropdown-menu-1.tsx +38 -0
  41. package/src/components/patterns/p-dropdown-menu-11.tsx +122 -0
  42. package/src/components/patterns/p-dropdown-menu-14.tsx +165 -0
  43. package/src/components/patterns/p-dropdown-menu-9.tsx +108 -0
  44. package/src/components/patterns/p-empty-2.tsx +34 -0
  45. package/src/components/patterns/p-file-upload-1.tsx +72 -0
  46. package/src/components/patterns/p-filters-1.tsx +666 -0
  47. package/src/components/patterns/p-frame-2.tsx +26 -0
  48. package/src/components/patterns/p-tabs-2.tsx +129 -0
  49. package/src/components/reui/alert.tsx +92 -0
  50. package/src/components/reui/autocomplete.tsx +343 -0
  51. package/src/components/reui/badge.tsx +87 -0
  52. package/src/components/reui/data-grid/data-grid-column-filter.tsx +165 -0
  53. package/src/components/reui/data-grid/data-grid-column-header.tsx +339 -0
  54. package/src/components/reui/data-grid/data-grid-column-visibility.tsx +55 -0
  55. package/src/components/reui/data-grid/data-grid-pagination.tsx +224 -0
  56. package/src/components/reui/data-grid/data-grid-table-dnd-rows.tsx +260 -0
  57. package/src/components/reui/data-grid/data-grid-table-dnd.tsx +253 -0
  58. package/src/components/reui/data-grid/data-grid-table.tsx +639 -0
  59. package/src/components/reui/data-grid/data-grid.tsx +209 -0
  60. package/src/components/reui/date-selector.tsx +1330 -0
  61. package/src/components/reui/filters.tsx +1869 -0
  62. package/src/components/reui/frame.tsx +134 -0
  63. package/src/components/reui/index.ts +17 -0
  64. package/src/components/reui/timeline.tsx +219 -0
  65. package/src/components/search/Autocomplete.tsx +183 -0
  66. package/src/components/search/AutocompleteClient.tsx +293 -0
  67. package/src/components/search/GlobalSearch.tsx +187 -0
  68. package/src/components/section-drawer/deal-drawer-content.tsx +891 -0
  69. package/src/components/section-drawer/index.ts +19 -0
  70. package/src/components/section-drawer/section-drawer.css +665 -0
  71. package/src/components/section-drawer/section-drawer.tsx +467 -0
  72. package/src/components/sectioned-list-board/README.md +78 -0
  73. package/src/components/sectioned-list-board/board-card-content.tsx +340 -0
  74. package/src/components/sectioned-list-board/date-range-filter.tsx +249 -0
  75. package/src/components/sectioned-list-board/index.ts +19 -0
  76. package/src/components/sectioned-list-board/sectioned-list-board.css +564 -0
  77. package/src/components/sectioned-list-board/sectioned-list-board.tsx +731 -0
  78. package/src/components/sectioned-list-board/sortable-card.tsx +314 -0
  79. package/src/components/sectioned-list-board/sortable-section.tsx +319 -0
  80. package/src/components/sectioned-list-board/types.ts +216 -0
  81. package/src/components/sectioned-list-table/README.md +80 -0
  82. package/src/components/sectioned-list-table/index.ts +14 -0
  83. package/src/components/sectioned-list-table/sectioned-list-table.css +534 -0
  84. package/src/components/sectioned-list-table/sectioned-list-table.tsx +740 -0
  85. package/src/components/sectioned-list-table/sortable-column-header.tsx +120 -0
  86. package/src/components/sectioned-list-table/sortable-row.tsx +420 -0
  87. package/src/components/sectioned-list-table/sortable-section.tsx +251 -0
  88. package/src/components/sectioned-list-table/table-cell-content.tsx +129 -0
  89. package/src/components/sectioned-list-table/types.ts +120 -0
  90. package/src/components/sectioned-list-table/use-column-preferences.ts +103 -0
  91. package/src/components/ui/actions-dropdown.tsx +109 -0
  92. package/src/components/ui/assignee-selector.tsx +209 -0
  93. package/src/components/ui/avatar.tsx +107 -0
  94. package/src/components/ui/breadcrumb.tsx +109 -0
  95. package/src/components/ui/button-group.tsx +83 -0
  96. package/src/components/ui/button.tsx +64 -0
  97. package/src/components/ui/calendar.tsx +220 -0
  98. package/src/components/ui/card.tsx +92 -0
  99. package/src/components/ui/chart.tsx +376 -0
  100. package/src/components/ui/checkbox.tsx +30 -0
  101. package/src/components/ui/collapsible.tsx +33 -0
  102. package/src/components/ui/command.tsx +182 -0
  103. package/src/components/ui/context-menu.tsx +250 -0
  104. package/src/components/ui/create-button-group.tsx +128 -0
  105. package/src/components/ui/dialog.tsx +156 -0
  106. package/src/components/ui/drawer.tsx +133 -0
  107. package/src/components/ui/dropdown-menu.tsx +255 -0
  108. package/src/components/ui/empty.tsx +104 -0
  109. package/src/components/ui/field.tsx +248 -0
  110. package/src/components/ui/form.tsx +165 -0
  111. package/src/components/ui/index.ts +37 -0
  112. package/src/components/ui/input-group.tsx +168 -0
  113. package/src/components/ui/input.tsx +21 -0
  114. package/src/components/ui/kbd.tsx +28 -0
  115. package/src/components/ui/label.tsx +22 -0
  116. package/src/components/ui/navigation-menu.tsx +168 -0
  117. package/src/components/ui/page-header.tsx +80 -0
  118. package/src/components/ui/popover.tsx +87 -0
  119. package/src/components/ui/scroll-area.tsx +56 -0
  120. package/src/components/ui/select.tsx +190 -0
  121. package/src/components/ui/separator.tsx +26 -0
  122. package/src/components/ui/sheet.tsx +141 -0
  123. package/src/components/ui/sidebar.tsx +726 -0
  124. package/src/components/ui/skeleton.tsx +13 -0
  125. package/src/components/ui/sonner.tsx +38 -0
  126. package/src/components/ui/switch.tsx +33 -0
  127. package/src/components/ui/tabs.tsx +91 -0
  128. package/src/components/ui/textarea.tsx +18 -0
  129. package/src/components/ui/toggle-group.tsx +83 -0
  130. package/src/components/ui/toggle.tsx +45 -0
  131. package/src/components/ui/tooltip.tsx +57 -0
  132. package/src/hooks/use-copy-to-clipboard.ts +37 -0
  133. package/src/hooks/use-file-upload.ts +415 -0
  134. package/src/hooks/use-mobile.ts +19 -0
  135. package/src/index.ts +95 -0
  136. package/src/lib/utils.ts +6 -0
  137. package/src/styles.css +1859 -0
  138. package/src/urls.ts +83 -0
  139. package/src/vite.d.ts +22 -0
  140. package/src/vite.js +241 -0
  141. package/tsconfig.base.json +18 -0
  142. package/tsconfig.json +24 -0
@@ -0,0 +1,160 @@
1
+ import React from "react";
2
+ import { cn } from "@/lib/utils";
3
+
4
+ export interface PageHeaderProps {
5
+ /** The title text for the header */
6
+ title: React.ReactNode;
7
+ /** Optional description text below the title */
8
+ description?: React.ReactNode;
9
+ /** Optional counter to display next to the title (e.g., "(42)") */
10
+ counter?: string | number;
11
+ /** Optional info link/icon to display next to the title */
12
+ info?: React.ReactNode;
13
+ /** Action buttons/elements to display on the right side */
14
+ actions?: React.ReactNode;
15
+ /** Header variant controlling the heading level and styling */
16
+ variant?: "h1" | "h2" | "h3";
17
+ /** Whether the header should be sticky at the top */
18
+ sticky?: boolean;
19
+ /** Additional class name for the header container */
20
+ className?: string;
21
+ /** Content to render below the header (e.g., breadcrumbs) */
22
+ children?: React.ReactNode;
23
+ }
24
+
25
+ const variantStyles = {
26
+ h1: "text-2xl font-semibold",
27
+ h2: "text-xl font-semibold",
28
+ h3: "text-lg font-medium",
29
+ };
30
+
31
+ /**
32
+ * PageHeader - A flexible page header component with title, description, and actions
33
+ *
34
+ * Features:
35
+ * - Multiple heading variants (h1, h2, h3)
36
+ * - Optional description below title
37
+ * - Counter display next to title
38
+ * - Info link/icon slot
39
+ * - Actions slot for buttons
40
+ * - Optional sticky positioning
41
+ */
42
+ export function PageHeader({
43
+ title,
44
+ description,
45
+ counter,
46
+ info,
47
+ actions,
48
+ variant = "h1",
49
+ sticky = false,
50
+ className,
51
+ children,
52
+ }: PageHeaderProps) {
53
+ const titleContent = (
54
+ <>
55
+ {title}
56
+ {counter !== undefined && (
57
+ <span className="text-muted-foreground font-normal ml-2">
58
+ ({counter})
59
+ </span>
60
+ )}
61
+ </>
62
+ );
63
+
64
+ return (
65
+ <div
66
+ className={cn(
67
+ "flex flex-col gap-2",
68
+ sticky && "sticky top-0 z-10 bg-background py-4 border-b border-border",
69
+ className
70
+ )}
71
+ >
72
+ {children}
73
+ <div className="flex items-start justify-between gap-4">
74
+ <div className="flex flex-col gap-1 min-w-0">
75
+ <div className="flex items-center gap-2">
76
+ {variant === "h1" && (
77
+ <h1 className={cn("text-foreground", variantStyles.h1)}>
78
+ {titleContent}
79
+ </h1>
80
+ )}
81
+ {variant === "h2" && (
82
+ <h2 className={cn("text-foreground", variantStyles.h2)}>
83
+ {titleContent}
84
+ </h2>
85
+ )}
86
+ {variant === "h3" && (
87
+ <h3 className={cn("text-foreground", variantStyles.h3)}>
88
+ {titleContent}
89
+ </h3>
90
+ )}
91
+ {info && (
92
+ <span className="text-muted-foreground">{info}</span>
93
+ )}
94
+ </div>
95
+ {description && (
96
+ <p className="text-sm text-muted-foreground">{description}</p>
97
+ )}
98
+ </div>
99
+ {actions && (
100
+ <div className="flex items-center gap-2 shrink-0">
101
+ {actions}
102
+ </div>
103
+ )}
104
+ </div>
105
+ </div>
106
+ );
107
+ }
108
+
109
+ /**
110
+ * PageHeaderTitle - Standalone title component for more custom layouts
111
+ */
112
+ export function PageHeaderTitle({
113
+ children,
114
+ className,
115
+ variant = "h1",
116
+ }: {
117
+ children: React.ReactNode;
118
+ className?: string;
119
+ variant?: "h1" | "h2" | "h3";
120
+ }) {
121
+ const classes = cn("text-foreground", variantStyles[variant], className);
122
+
123
+ if (variant === "h1") return <h1 className={classes}>{children}</h1>;
124
+ if (variant === "h2") return <h2 className={classes}>{children}</h2>;
125
+ return <h3 className={classes}>{children}</h3>;
126
+ }
127
+
128
+ /**
129
+ * PageHeaderDescription - Standalone description component
130
+ */
131
+ export function PageHeaderDescription({
132
+ children,
133
+ className,
134
+ }: {
135
+ children: React.ReactNode;
136
+ className?: string;
137
+ }) {
138
+ return (
139
+ <p className={cn("text-sm text-muted-foreground", className)}>
140
+ {children}
141
+ </p>
142
+ );
143
+ }
144
+
145
+ /**
146
+ * PageHeaderActions - Container for action buttons
147
+ */
148
+ export function PageHeaderActions({
149
+ children,
150
+ className,
151
+ }: {
152
+ children: React.ReactNode;
153
+ className?: string;
154
+ }) {
155
+ return (
156
+ <div className={cn("flex items-center gap-2", className)}>
157
+ {children}
158
+ </div>
159
+ );
160
+ }
@@ -0,0 +1,447 @@
1
+ # Data Table
2
+
3
+ A feature-rich data table component built on TanStack Table with support for sorting, pagination, row selection, column resizing, column reordering (drag & drop), and column pinning.
4
+
5
+ ## Important: Button Placement
6
+
7
+ **Create/Import/Export buttons should be placed OUTSIDE the table, not in the toolbar.**
8
+
9
+ The table toolbar should only contain:
10
+ - Search/filter input
11
+ - Column visibility toggle
12
+ - Selection-based bulk actions (e.g., "Delete Selected", "Archive Selected")
13
+
14
+ Use `CreateButtonGroup` above the table for create/import/export actions:
15
+
16
+ ```tsx
17
+ import {
18
+ DataGrid,
19
+ DataTableToolbar,
20
+ CreateButtonGroup,
21
+ } from "@platform/app-shell/components/data-table"
22
+
23
+ function MyPage() {
24
+ return (
25
+ <div className="space-y-4">
26
+ {/* Header with Create button OUTSIDE the table */}
27
+ <div className="flex items-center justify-between">
28
+ <h1 className="text-xl font-semibold">Items ({data.length})</h1>
29
+ <CreateButtonGroup
30
+ createLabel="Create Item"
31
+ onCreate={() => openCreateModal()}
32
+ onImport={() => openImportDialog()}
33
+ onExport={() => exportData()}
34
+ />
35
+ </div>
36
+
37
+ {/* Table with only table-specific controls */}
38
+ <DataGrid table={table}>
39
+ <DataTableToolbar
40
+ table={table}
41
+ filterValue={filterText}
42
+ onFilterChange={setFilterText}
43
+ bulkActions={
44
+ selectedCount > 0 && (
45
+ <Button variant="destructive" size="sm">
46
+ Delete Selected ({selectedCount})
47
+ </Button>
48
+ )
49
+ }
50
+ />
51
+ ...
52
+ </DataGrid>
53
+ </div>
54
+ )
55
+ }
56
+ ```
57
+
58
+ ## Installation
59
+
60
+ The data table components are part of `@platform/app-shell`. Import from the data-table module:
61
+
62
+ ```tsx
63
+ import {
64
+ DataGrid,
65
+ DataGridTableDnd,
66
+ DataGridPagination,
67
+ DataGridColumnHeader,
68
+ DataGridTableRowSelect,
69
+ DataGridTableRowSelectAll,
70
+ useReactTable,
71
+ getCoreRowModel,
72
+ getFilteredRowModel,
73
+ getPaginationRowModel,
74
+ getSortedRowModel,
75
+ } from "@platform/app-shell/components/data-table"
76
+
77
+ import type {
78
+ ColumnDef,
79
+ ColumnOrderState,
80
+ PaginationState,
81
+ SortingState,
82
+ RowSelectionState,
83
+ } from "@platform/app-shell/components/data-table"
84
+ ```
85
+
86
+ For drag & drop functionality, also install:
87
+
88
+ ```bash
89
+ bun add @dnd-kit/core @dnd-kit/sortable
90
+ ```
91
+
92
+ ## Basic Usage
93
+
94
+ ```tsx
95
+ import * as React from "react"
96
+ import {
97
+ DataGrid,
98
+ DataGridTableDnd,
99
+ DataGridPagination,
100
+ DataGridColumnHeader,
101
+ DataGridTableRowSelect,
102
+ DataGridTableRowSelectAll,
103
+ useReactTable,
104
+ getCoreRowModel,
105
+ getFilteredRowModel,
106
+ getPaginationRowModel,
107
+ getSortedRowModel,
108
+ } from "@platform/app-shell/components/data-table"
109
+ import type {
110
+ ColumnDef,
111
+ ColumnOrderState,
112
+ PaginationState,
113
+ SortingState,
114
+ RowSelectionState,
115
+ } from "@platform/app-shell/components/data-table"
116
+ import type { DragEndEvent } from "@dnd-kit/core"
117
+ import { arrayMove } from "@dnd-kit/sortable"
118
+ import { Card, CardFooter } from "@platform/app-shell/components/ui/card"
119
+ import { ScrollArea, ScrollBar } from "@platform/app-shell/components/ui/scroll-area"
120
+
121
+ interface DataRow {
122
+ id: string
123
+ name: string
124
+ email: string
125
+ }
126
+
127
+ export function MyTable({ data }: { data: DataRow[] }) {
128
+ // Table state
129
+ const [pagination, setPagination] = React.useState<PaginationState>({
130
+ pageIndex: 0,
131
+ pageSize: 10,
132
+ })
133
+ const [sorting, setSorting] = React.useState<SortingState>([])
134
+ const [rowSelection, setRowSelection] = React.useState<RowSelectionState>({})
135
+ const [columnOrder, setColumnOrder] = React.useState<ColumnOrderState>([
136
+ "select",
137
+ "name",
138
+ "email",
139
+ ])
140
+
141
+ // Handle column drag and drop
142
+ const handleDragEnd = (event: DragEndEvent) => {
143
+ const { active, over } = event
144
+ if (active && over && active.id !== over.id) {
145
+ setColumnOrder((columnOrder) => {
146
+ const oldIndex = columnOrder.indexOf(active.id as string)
147
+ const newIndex = columnOrder.indexOf(over.id as string)
148
+ return arrayMove(columnOrder, oldIndex, newIndex)
149
+ })
150
+ }
151
+ }
152
+
153
+ // Define columns
154
+ const columns = React.useMemo<ColumnDef<DataRow>[]>(
155
+ () => [
156
+ {
157
+ id: "select",
158
+ header: () => <DataGridTableRowSelectAll />,
159
+ cell: ({ row }) => <DataGridTableRowSelect row={row} />,
160
+ size: 40,
161
+ enableSorting: false,
162
+ enableHiding: false,
163
+ enableResizing: false,
164
+ enableColumnOrdering: false, // Disable dragging for this column
165
+ },
166
+ {
167
+ accessorKey: "name",
168
+ id: "name",
169
+ header: ({ column }) => (
170
+ <DataGridColumnHeader title="Name" column={column} />
171
+ ),
172
+ cell: ({ row }) => row.original.name,
173
+ size: 200,
174
+ enableSorting: true,
175
+ enableHiding: false,
176
+ enableResizing: true,
177
+ meta: {
178
+ headerTitle: "Name",
179
+ },
180
+ },
181
+ {
182
+ accessorKey: "email",
183
+ id: "email",
184
+ header: ({ column }) => (
185
+ <DataGridColumnHeader title="Email" column={column} />
186
+ ),
187
+ cell: ({ row }) => row.original.email,
188
+ size: 250,
189
+ enableSorting: true,
190
+ enableHiding: true,
191
+ enableResizing: true,
192
+ meta: {
193
+ headerTitle: "Email",
194
+ },
195
+ },
196
+ ],
197
+ []
198
+ )
199
+
200
+ // Create table instance
201
+ const table = useReactTable({
202
+ columns,
203
+ data,
204
+ pageCount: Math.ceil(data.length / pagination.pageSize),
205
+ getRowId: (row) => row.id,
206
+ state: {
207
+ pagination,
208
+ sorting,
209
+ rowSelection,
210
+ columnOrder,
211
+ },
212
+ enableRowSelection: true,
213
+ columnResizeMode: "onChange",
214
+ onPaginationChange: setPagination,
215
+ onSortingChange: setSorting,
216
+ onRowSelectionChange: setRowSelection,
217
+ onColumnOrderChange: setColumnOrder,
218
+ getCoreRowModel: getCoreRowModel(),
219
+ getFilteredRowModel: getFilteredRowModel(),
220
+ getPaginationRowModel: getPaginationRowModel(),
221
+ getSortedRowModel: getSortedRowModel(),
222
+ })
223
+
224
+ return (
225
+ <DataGrid
226
+ table={table}
227
+ recordCount={data.length}
228
+ tableLayout={{
229
+ columnsResizable: true,
230
+ columnsMovable: true,
231
+ columnsDraggable: true,
232
+ columnsPinnable: true,
233
+ columnsVisibility: true,
234
+ }}
235
+ >
236
+ <Card className="w-full gap-3 py-3.5">
237
+ {/* Table */}
238
+ <div className="w-full border-y">
239
+ <ScrollArea>
240
+ <DataGridTableDnd handleDragEnd={handleDragEnd} />
241
+ <ScrollBar orientation="horizontal" />
242
+ </ScrollArea>
243
+ </div>
244
+
245
+ {/* Pagination */}
246
+ <CardFooter className="border-none bg-transparent px-3.5 py-0">
247
+ <DataGridPagination sizes={[10, 20, 50]} />
248
+ </CardFooter>
249
+ </Card>
250
+ </DataGrid>
251
+ )
252
+ }
253
+ ```
254
+
255
+ ## Components
256
+
257
+ ### DataGrid
258
+
259
+ The main wrapper component that provides context to all child components.
260
+
261
+ ```tsx
262
+ <DataGrid
263
+ table={table} // TanStack table instance
264
+ recordCount={data.length} // Total number of records
265
+ tableLayout={{
266
+ dense: false, // Compact row height
267
+ columnsResizable: true, // Enable column resizing
268
+ columnsMovable: true, // Enable column reordering via menu
269
+ columnsDraggable: true, // Enable drag & drop column reordering
270
+ columnsPinnable: true, // Enable column pinning
271
+ columnsVisibility: true, // Enable column visibility toggle
272
+ }}
273
+ >
274
+ {children}
275
+ </DataGrid>
276
+ ```
277
+
278
+ ### DataGridTableDnd
279
+
280
+ The table component with drag & drop support for column reordering.
281
+
282
+ ```tsx
283
+ <DataGridTableDnd handleDragEnd={handleDragEnd} />
284
+ ```
285
+
286
+ ### DataGridColumnHeader
287
+
288
+ Column header with sorting controls and dropdown menu for column actions.
289
+
290
+ ```tsx
291
+ <DataGridColumnHeader
292
+ title="Column Name"
293
+ column={column}
294
+ icon={<IconComponent />} // Optional icon
295
+ pinnable={true} // Enable pinning option in menu
296
+ visibility={true} // Show column visibility in menu
297
+ filter={<FilterComponent />} // Optional filter component
298
+ />
299
+ ```
300
+
301
+ ### DataGridTableRowSelect / DataGridTableRowSelectAll
302
+
303
+ Row selection checkboxes.
304
+
305
+ ```tsx
306
+ // In header
307
+ header: () => <DataGridTableRowSelectAll />
308
+
309
+ // In cell
310
+ cell: ({ row }) => <DataGridTableRowSelect row={row} />
311
+ ```
312
+
313
+ ### DataGridPagination
314
+
315
+ Pagination controls with page size selector.
316
+
317
+ ```tsx
318
+ <DataGridPagination sizes={[10, 20, 50]} />
319
+ ```
320
+
321
+ ### CreateButtonGroup
322
+
323
+ Button group for create/import/export actions. **Place this ABOVE the table, not in the toolbar.**
324
+
325
+ ```tsx
326
+ <CreateButtonGroup
327
+ createLabel="Create Item" // Primary button label
328
+ onCreate={() => {}} // Primary action handler
329
+ importLabel="Import" // Optional, defaults to "Import"
330
+ onImport={() => {}} // Import action handler
331
+ exportLabel="Export" // Optional, defaults to "Export"
332
+ onExport={() => {}} // Export action handler
333
+ showDropdown={true} // Show dropdown, defaults to true
334
+ additionalItems={[ // Optional extra dropdown items
335
+ {
336
+ id: "bulk-create",
337
+ label: "Bulk Create",
338
+ onClick: () => {},
339
+ },
340
+ ]}
341
+ />
342
+ ```
343
+
344
+ ### DataTableToolbar
345
+
346
+ Toolbar for table-specific controls. The `bulkActions` prop is for selection-based actions only.
347
+
348
+ ```tsx
349
+ <DataTableToolbar
350
+ table={table}
351
+ filterValue={filterText}
352
+ onFilterChange={setFilterText}
353
+ filterPlaceholder="Search items..."
354
+ showColumnVisibility={true}
355
+ selectedCount={selectedCount}
356
+ totalCount={data.length}
357
+ bulkActions={
358
+ selectedCount > 0 && (
359
+ <Button variant="destructive" size="sm">
360
+ Delete Selected ({selectedCount})
361
+ </Button>
362
+ )
363
+ }
364
+ />
365
+ ```
366
+
367
+ ## Column Definition Options
368
+
369
+ ```tsx
370
+ {
371
+ id: "columnId",
372
+ accessorKey: "dataField",
373
+ header: ({ column }) => <DataGridColumnHeader title="Title" column={column} />,
374
+ cell: ({ row }) => row.original.field,
375
+ size: 200, // Column width in pixels
376
+ enableSorting: true, // Allow sorting
377
+ enableHiding: true, // Allow hiding via visibility toggle
378
+ enableResizing: true, // Allow resizing
379
+ enableColumnOrdering: true, // Allow drag reordering (default: true)
380
+ meta: {
381
+ headerTitle: "Display Name", // Used in column visibility menu
382
+ cellClassName: "custom-class",
383
+ headerClassName: "custom-class",
384
+ },
385
+ }
386
+ ```
387
+
388
+ ## Table Layout Options
389
+
390
+ | Option | Type | Default | Description |
391
+ |--------|------|---------|-------------|
392
+ | `dense` | boolean | false | Use compact row height |
393
+ | `columnsResizable` | boolean | false | Enable column resizing |
394
+ | `columnsMovable` | boolean | false | Enable move left/right in column menu |
395
+ | `columnsDraggable` | boolean | false | Enable drag & drop column reordering |
396
+ | `columnsPinnable` | boolean | false | Enable column pinning (left/right) |
397
+ | `columnsVisibility` | boolean | false | Enable column visibility toggle |
398
+ | `rowBorder` | boolean | true | Show row borders |
399
+ | `cellBorder` | boolean | false | Show cell borders |
400
+ | `stripped` | boolean | false | Alternating row colors |
401
+ | `headerSticky` | boolean | false | Sticky header on scroll |
402
+
403
+ ## Disabling Drag on Specific Columns
404
+
405
+ To prevent a column from being draggable (e.g., selection checkbox column):
406
+
407
+ ```tsx
408
+ {
409
+ id: "select",
410
+ enableColumnOrdering: false, // This column cannot be dragged
411
+ // ...
412
+ }
413
+ ```
414
+
415
+ ## Selection Counter in Header
416
+
417
+ Display selection count in the table header instead of a separate line:
418
+
419
+ ```tsx
420
+ const selectedCount = Object.keys(rowSelection).length
421
+
422
+ <div className="text-xl font-semibold">
423
+ Items
424
+ <span className="text-muted-foreground font-normal">
425
+ {" "}({selectedCount > 0 ? `${selectedCount}/${data.length}` : data.length})
426
+ </span>
427
+ </div>
428
+ ```
429
+
430
+ This shows:
431
+ - `Items (10)` when no rows selected
432
+ - `Items (3/10)` when 3 of 10 rows selected
433
+
434
+ ## Styling
435
+
436
+ The table inherits from the app's theme. Common customizations:
437
+
438
+ ```tsx
439
+ // Italic placeholder in search input
440
+ <Input
441
+ placeholder="Search..."
442
+ className="placeholder:italic"
443
+ />
444
+
445
+ // Custom badge sizes in cells
446
+ <Badge variant="outline">{tag}</Badge> // Uses default size (text-xs)
447
+ ```