@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,224 @@
1
+ import React, { ReactNode } from "react"
2
+ import { useDataGrid } from "@/components/reui/data-grid/data-grid"
3
+
4
+ import { cn } from "@/lib/utils"
5
+ import { Button } from "@/components/ui/button"
6
+ import {
7
+ Select,
8
+ SelectContent,
9
+ SelectItem,
10
+ SelectTrigger,
11
+ SelectValue,
12
+ } from "@/components/ui/select"
13
+ import { Skeleton } from "@/components/ui/skeleton"
14
+ import { ChevronLeftIcon, ChevronRightIcon } from "lucide-react"
15
+
16
+ interface DataGridPaginationProps {
17
+ sizes?: number[]
18
+ sizesInfo?: string
19
+ sizesLabel?: string
20
+ sizesDescription?: string
21
+ sizesSkeleton?: ReactNode
22
+ more?: boolean
23
+ moreLimit?: number
24
+ info?: string
25
+ infoSkeleton?: ReactNode
26
+ className?: string
27
+ rowsPerPageLabel?: string
28
+ previousPageLabel?: string
29
+ nextPageLabel?: string
30
+ ellipsisText?: string
31
+ }
32
+
33
+ function DataGridPagination(props: DataGridPaginationProps): React.JSX.Element {
34
+ const { table, recordCount, isLoading } = useDataGrid()
35
+
36
+ const defaultProps: Partial<DataGridPaginationProps> = {
37
+ sizes: [5, 10, 25, 50, 100],
38
+ sizesLabel: "Show",
39
+ sizesDescription: "per page",
40
+ sizesSkeleton: <Skeleton className="h-8 w-44" />,
41
+ moreLimit: 5,
42
+ more: false,
43
+ info: "{from} - {to} of {count}",
44
+ infoSkeleton: <Skeleton className="h-8 w-60" />,
45
+ rowsPerPageLabel: "Rows per page",
46
+ previousPageLabel: "Go to previous page",
47
+ nextPageLabel: "Go to next page",
48
+ ellipsisText: "...",
49
+ }
50
+
51
+ const mergedProps: DataGridPaginationProps = { ...defaultProps, ...props }
52
+
53
+ const btnBaseClasses = "size-7 p-0 text-sm"
54
+ const btnArrowClasses = btnBaseClasses + " rtl:transform rtl:rotate-180"
55
+ const pageIndex = table.getState().pagination.pageIndex
56
+ const pageSize = table.getState().pagination.pageSize
57
+ const from = pageIndex * pageSize + 1
58
+ const to = Math.min((pageIndex + 1) * pageSize, recordCount)
59
+ const pageCount = table.getPageCount()
60
+
61
+ // Replace placeholders in paginationInfo
62
+ const paginationInfo = mergedProps?.info
63
+ ? mergedProps.info
64
+ .replace("{from}", from.toString())
65
+ .replace("{to}", to.toString())
66
+ .replace("{count}", recordCount.toString())
67
+ : `${from} - ${to} of ${recordCount}`
68
+
69
+ // Pagination limit logic
70
+ const paginationMoreLimit = mergedProps?.moreLimit || 5
71
+
72
+ // Determine the start and end of the pagination group
73
+ const currentGroupStart =
74
+ Math.floor(pageIndex / paginationMoreLimit) * paginationMoreLimit
75
+ const currentGroupEnd = Math.min(
76
+ currentGroupStart + paginationMoreLimit,
77
+ pageCount
78
+ )
79
+
80
+ // Render page buttons based on the current group
81
+ const renderPageButtons = () => {
82
+ const buttons = []
83
+ for (let i = currentGroupStart; i < currentGroupEnd; i++) {
84
+ buttons.push(
85
+ <Button
86
+ key={i}
87
+ size="icon-sm"
88
+ variant="ghost"
89
+ className={cn(btnBaseClasses, "text-muted-foreground", {
90
+ "bg-accent text-accent-foreground": pageIndex === i,
91
+ })}
92
+ onClick={() => {
93
+ if (pageIndex !== i) {
94
+ table.setPageIndex(i)
95
+ }
96
+ }}
97
+ >
98
+ {i + 1}
99
+ </Button>
100
+ )
101
+ }
102
+ return buttons
103
+ }
104
+
105
+ // Render a "previous" ellipsis button if there are previous pages to show
106
+ const renderEllipsisPrevButton = () => {
107
+ if (currentGroupStart > 0) {
108
+ return (
109
+ <Button
110
+ size="icon-sm"
111
+ className={btnBaseClasses}
112
+ variant="ghost"
113
+ onClick={() => table.setPageIndex(currentGroupStart - 1)}
114
+ >
115
+ {mergedProps.ellipsisText}
116
+ </Button>
117
+ )
118
+ }
119
+ return null
120
+ }
121
+
122
+ // Render a "next" ellipsis button if there are more pages to show after the current group
123
+ const renderEllipsisNextButton = () => {
124
+ if (currentGroupEnd < pageCount) {
125
+ return (
126
+ <Button
127
+ className={btnBaseClasses}
128
+ variant="ghost"
129
+ size="icon-sm"
130
+ onClick={() => table.setPageIndex(currentGroupEnd)}
131
+ >
132
+ {mergedProps.ellipsisText}
133
+ </Button>
134
+ )
135
+ }
136
+ return null
137
+ }
138
+
139
+ return (
140
+ <div
141
+ data-slot="data-grid-pagination"
142
+ className={cn(
143
+ "flex grow flex-col flex-wrap items-center justify-between gap-2.5 py-2.5 sm:flex-row sm:py-0",
144
+ mergedProps?.className
145
+ )}
146
+ >
147
+ <div className="order-2 flex flex-wrap items-center space-x-2.5 pb-2.5 sm:order-1 sm:pb-0">
148
+ {isLoading ? (
149
+ mergedProps?.sizesSkeleton
150
+ ) : (
151
+ <>
152
+ <div className="text-muted-foreground text-sm">
153
+ {mergedProps.rowsPerPageLabel}
154
+ </div>
155
+ <Select
156
+ value={`${pageSize}`}
157
+ onValueChange={(value) => {
158
+ const newPageSize = Number(value)
159
+ table.setPageSize(newPageSize)
160
+ }}
161
+ >
162
+ <SelectTrigger className="w-14" size="sm">
163
+ <SelectValue />
164
+ </SelectTrigger>
165
+ <SelectContent side="top" className="min-w-18">
166
+ {mergedProps?.sizes?.map((size: number) => (
167
+ <SelectItem key={size} value={`${size}`}>
168
+ {size}
169
+ </SelectItem>
170
+ ))}
171
+ </SelectContent>
172
+ </Select>
173
+ </>
174
+ )}
175
+ </div>
176
+ <div className="order-1 flex flex-col items-center justify-center gap-2.5 pt-2.5 sm:order-2 sm:flex-row sm:justify-end sm:pt-0">
177
+ {isLoading ? (
178
+ mergedProps?.infoSkeleton
179
+ ) : (
180
+ <>
181
+ <div className="text-muted-foreground text-sm order-2 text-nowrap sm:order-1">
182
+ {paginationInfo}
183
+ </div>
184
+ {pageCount > 1 && (
185
+ <div className="order-1 flex items-center space-x-1 sm:order-2">
186
+ <Button
187
+ size="icon-sm"
188
+ variant="ghost"
189
+ className={btnArrowClasses}
190
+ onClick={() => table.previousPage()}
191
+ disabled={!table.getCanPreviousPage()}
192
+ >
193
+ <span className="sr-only">
194
+ {mergedProps.previousPageLabel}
195
+ </span>
196
+ <ChevronLeftIcon className="size-4" />
197
+ </Button>
198
+
199
+ {renderEllipsisPrevButton()}
200
+
201
+ {renderPageButtons()}
202
+
203
+ {renderEllipsisNextButton()}
204
+
205
+ <Button
206
+ size="icon-sm"
207
+ variant="ghost"
208
+ className={btnArrowClasses}
209
+ onClick={() => table.nextPage()}
210
+ disabled={!table.getCanNextPage()}
211
+ >
212
+ <span className="sr-only">{mergedProps.nextPageLabel}</span>
213
+ <ChevronRightIcon className="size-4" />
214
+ </Button>
215
+ </div>
216
+ )}
217
+ </>
218
+ )}
219
+ </div>
220
+ </div>
221
+ )
222
+ }
223
+
224
+ export { DataGridPagination, type DataGridPaginationProps }
@@ -0,0 +1,260 @@
1
+ "use client"
2
+
3
+ import {
4
+ createContext,
5
+ CSSProperties,
6
+ useContext,
7
+ useId,
8
+ useMemo,
9
+ useRef,
10
+ } from "react"
11
+ import { useDataGrid } from "@/components/reui/data-grid/data-grid"
12
+ import {
13
+ DataGridTableBase,
14
+ DataGridTableBody,
15
+ DataGridTableBodyRow,
16
+ DataGridTableBodyRowCell,
17
+ DataGridTableBodyRowSkeleton,
18
+ DataGridTableBodyRowSkeletonCell,
19
+ DataGridTableEmpty,
20
+ DataGridTableHead,
21
+ DataGridTableHeadRow,
22
+ DataGridTableHeadRowCell,
23
+ DataGridTableHeadRowCellResize,
24
+ DataGridTableRowSpacer,
25
+ } from "@/components/reui/data-grid/data-grid-table"
26
+ import {
27
+ closestCenter,
28
+ DndContext,
29
+ KeyboardSensor,
30
+ MouseSensor,
31
+ TouchSensor,
32
+ UniqueIdentifier,
33
+ useSensor,
34
+ useSensors,
35
+ type DragEndEvent,
36
+ type Modifier,
37
+ } from "@dnd-kit/core"
38
+ import { restrictToVerticalAxis } from "@dnd-kit/modifiers"
39
+ import {
40
+ SortableContext,
41
+ useSortable,
42
+ verticalListSortingStrategy,
43
+ } from "@dnd-kit/sortable"
44
+ import { CSS } from "@dnd-kit/utilities"
45
+ import { Cell, flexRender, HeaderGroup, Row } from "@tanstack/react-table"
46
+
47
+ import { cn } from "@/lib/utils"
48
+ import { Button } from "@/components/ui/button"
49
+ import { GripHorizontalIcon } from "lucide-react"
50
+
51
+ // Context to share sortable listeners from row to handle
52
+ type SortableContextValue = ReturnType<typeof useSortable>
53
+ const SortableRowContext = createContext<Pick<
54
+ SortableContextValue,
55
+ "attributes" | "listeners"
56
+ > | null>(null)
57
+
58
+ function DataGridTableDndRowHandle({ className }: { className?: string }) {
59
+ const context = useContext(SortableRowContext)
60
+
61
+ if (!context) {
62
+ // Fallback if context is not available (shouldn't happen in normal usage)
63
+ return (
64
+ <Button
65
+ variant="ghost"
66
+ size="icon-sm"
67
+ className={cn(
68
+ "size-7 cursor-move opacity-70 hover:bg-transparent hover:opacity-100",
69
+ className
70
+ )}
71
+ disabled
72
+ >
73
+ <GripHorizontalIcon
74
+ />
75
+ </Button>
76
+ )
77
+ }
78
+
79
+ return (
80
+ <Button
81
+ variant="ghost"
82
+ size="icon-sm"
83
+ className={cn(
84
+ "size-7 cursor-move opacity-70 hover:bg-transparent hover:opacity-100",
85
+ className
86
+ )}
87
+ {...context.attributes}
88
+ {...context.listeners}
89
+ >
90
+ <GripHorizontalIcon
91
+ />
92
+ </Button>
93
+ )
94
+ }
95
+
96
+ function DataGridTableDndRow<TData>({ row }: { row: Row<TData> }) {
97
+ const {
98
+ transform,
99
+ transition,
100
+ setNodeRef,
101
+ isDragging,
102
+ attributes,
103
+ listeners,
104
+ } = useSortable({
105
+ id: row.id,
106
+ })
107
+
108
+ const style: CSSProperties = {
109
+ transform: CSS.Transform.toString(transform),
110
+ transition: transition,
111
+ opacity: isDragging ? 0.8 : 1,
112
+ zIndex: isDragging ? 1 : 0,
113
+ position: "relative",
114
+ }
115
+
116
+ return (
117
+ <SortableRowContext.Provider value={{ attributes, listeners }}>
118
+ <DataGridTableBodyRow
119
+ row={row}
120
+ dndRef={setNodeRef}
121
+ dndStyle={style}
122
+ key={row.id}
123
+ >
124
+ {row.getVisibleCells().map((cell: Cell<TData, unknown>, colIndex) => {
125
+ return (
126
+ <DataGridTableBodyRowCell cell={cell} key={colIndex}>
127
+ {flexRender(cell.column.columnDef.cell, cell.getContext())}
128
+ </DataGridTableBodyRowCell>
129
+ )
130
+ })}
131
+ </DataGridTableBodyRow>
132
+ </SortableRowContext.Provider>
133
+ )
134
+ }
135
+
136
+ function DataGridTableDndRows<TData>({
137
+ handleDragEnd,
138
+ dataIds,
139
+ }: {
140
+ handleDragEnd: (event: DragEndEvent) => void
141
+ dataIds: UniqueIdentifier[]
142
+ }) {
143
+ const { table, isLoading, props } = useDataGrid()
144
+ const pagination = table.getState().pagination
145
+ const tableContainerRef = useRef<HTMLDivElement>(null)
146
+
147
+ const sensors = useSensors(
148
+ useSensor(MouseSensor, {}),
149
+ useSensor(TouchSensor, {}),
150
+ useSensor(KeyboardSensor, {})
151
+ )
152
+
153
+ const modifiers = useMemo(() => {
154
+ const restrictToTableContainer: Modifier = ({
155
+ transform,
156
+ draggingNodeRect,
157
+ }) => {
158
+ if (!tableContainerRef.current || !draggingNodeRect) {
159
+ return transform
160
+ }
161
+
162
+ const containerRect = tableContainerRef.current.getBoundingClientRect()
163
+ const { x, y } = transform
164
+
165
+ const minX = containerRect.left - draggingNodeRect.left
166
+ const maxX = containerRect.right - draggingNodeRect.right
167
+ const minY = containerRect.top - draggingNodeRect.top
168
+ const maxY = containerRect.bottom - draggingNodeRect.bottom
169
+
170
+ return {
171
+ ...transform,
172
+ x: Math.max(minX, Math.min(maxX, x)),
173
+ y: Math.max(minY, Math.min(maxY, y)),
174
+ }
175
+ }
176
+
177
+ return [restrictToVerticalAxis, restrictToTableContainer]
178
+ }, [])
179
+
180
+ return (
181
+ <DndContext
182
+ id={useId()}
183
+ collisionDetection={closestCenter}
184
+ modifiers={modifiers}
185
+ onDragEnd={handleDragEnd}
186
+ sensors={sensors}
187
+ >
188
+ <div ref={tableContainerRef} className="relative">
189
+ <DataGridTableBase>
190
+ <DataGridTableHead>
191
+ {table
192
+ .getHeaderGroups()
193
+ .map((headerGroup: HeaderGroup<TData>, index) => {
194
+ return (
195
+ <DataGridTableHeadRow headerGroup={headerGroup} key={index}>
196
+ {headerGroup.headers.map((header, index) => {
197
+ const { column } = header
198
+
199
+ return (
200
+ <DataGridTableHeadRowCell header={header} key={index}>
201
+ {header.isPlaceholder
202
+ ? null
203
+ : flexRender(
204
+ header.column.columnDef.header,
205
+ header.getContext()
206
+ )}
207
+ {props.tableLayout?.columnsResizable &&
208
+ column.getCanResize() && (
209
+ <DataGridTableHeadRowCellResize header={header} />
210
+ )}
211
+ </DataGridTableHeadRowCell>
212
+ )
213
+ })}
214
+ </DataGridTableHeadRow>
215
+ )
216
+ })}
217
+ </DataGridTableHead>
218
+
219
+ {(props.tableLayout?.stripped || !props.tableLayout?.rowBorder) && (
220
+ <DataGridTableRowSpacer />
221
+ )}
222
+
223
+ <DataGridTableBody>
224
+ {props.loadingMode === "skeleton" &&
225
+ isLoading &&
226
+ pagination?.pageSize ? (
227
+ Array.from({ length: pagination.pageSize }).map((_, rowIndex) => (
228
+ <DataGridTableBodyRowSkeleton key={rowIndex}>
229
+ {table.getVisibleFlatColumns().map((column, colIndex) => {
230
+ return (
231
+ <DataGridTableBodyRowSkeletonCell
232
+ column={column}
233
+ key={colIndex}
234
+ >
235
+ {column.columnDef.meta?.skeleton}
236
+ </DataGridTableBodyRowSkeletonCell>
237
+ )
238
+ })}
239
+ </DataGridTableBodyRowSkeleton>
240
+ ))
241
+ ) : table.getRowModel().rows.length ? (
242
+ <SortableContext
243
+ items={dataIds}
244
+ strategy={verticalListSortingStrategy}
245
+ >
246
+ {table.getRowModel().rows.map((row: Row<TData>) => {
247
+ return <DataGridTableDndRow row={row} key={row.id} />
248
+ })}
249
+ </SortableContext>
250
+ ) : (
251
+ <DataGridTableEmpty />
252
+ )}
253
+ </DataGridTableBody>
254
+ </DataGridTableBase>
255
+ </div>
256
+ </DndContext>
257
+ )
258
+ }
259
+
260
+ export { DataGridTableDndRowHandle, DataGridTableDndRows }