tablero 1.0.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/dist/ui.mjs ADDED
@@ -0,0 +1,309 @@
1
+ import React2, { useState, useRef, useCallback } from 'react';
2
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
3
+
4
+ // packages/ui/DataTable.tsx
5
+ function TableHeader({
6
+ columns,
7
+ sortState,
8
+ onSort,
9
+ onResize,
10
+ renderHeader,
11
+ sticky = false,
12
+ stickyFirstColumn = false,
13
+ bordered = true,
14
+ className = ""
15
+ }) {
16
+ const [resizingColumn, setResizingColumn] = useState(null);
17
+ const resizeStartX = useRef(0);
18
+ const resizeStartWidth = useRef(0);
19
+ const resizeColumnId = useRef(null);
20
+ const handleResizeStart = useCallback(
21
+ (e, columnId, currentWidth) => {
22
+ e.preventDefault();
23
+ e.stopPropagation();
24
+ setResizingColumn(columnId);
25
+ resizeStartX.current = e.clientX;
26
+ resizeStartWidth.current = currentWidth || 150;
27
+ resizeColumnId.current = columnId;
28
+ const handleMouseMove = (e2) => {
29
+ if (!resizeColumnId.current || !onResize) return;
30
+ const diff = e2.clientX - resizeStartX.current;
31
+ const newWidth = Math.max(50, resizeStartWidth.current + diff);
32
+ onResize(resizeColumnId.current, newWidth);
33
+ };
34
+ const handleMouseUp = () => {
35
+ setResizingColumn(null);
36
+ resizeColumnId.current = null;
37
+ document.removeEventListener("mousemove", handleMouseMove);
38
+ document.removeEventListener("mouseup", handleMouseUp);
39
+ };
40
+ document.addEventListener("mousemove", handleMouseMove);
41
+ document.addEventListener("mouseup", handleMouseUp);
42
+ },
43
+ [onResize]
44
+ );
45
+ return /* @__PURE__ */ jsx(
46
+ "thead",
47
+ {
48
+ className: `table-x-header ${sticky ? "table-x-header--sticky" : ""} ${bordered ? "table-x-header--bordered" : "table-x-header--borderless"} ${className}`,
49
+ style: sticky ? {
50
+ position: "sticky",
51
+ top: 0,
52
+ zIndex: 10,
53
+ backgroundColor: "var(--table-x-header-bg, #f9fafb)"
54
+ } : void 0,
55
+ children: /* @__PURE__ */ jsx("tr", { role: "row", children: columns.map((column, index) => {
56
+ const isFirstColumn = index === 0;
57
+ const isSticky = stickyFirstColumn && isFirstColumn;
58
+ const isSorted = sortState.columnId === column.id;
59
+ const sortDirection = isSorted ? sortState.direction : null;
60
+ return /* @__PURE__ */ jsxs(
61
+ "th",
62
+ {
63
+ className: `table-x-header-cell ${column.sortable ? "table-x-header-cell--sortable" : ""} ${isSorted ? "table-x-header-cell--sorted" : ""} ${isSticky ? "table-x-header-cell--sticky" : ""} ${resizingColumn === column.id ? "table-x-header-cell--resizing" : ""} ${bordered ? "table-x-header-cell--bordered" : "table-x-header-cell--borderless"}`,
64
+ style: {
65
+ textAlign: column.align || "left",
66
+ width: column.width ? `${column.width}px` : void 0,
67
+ minWidth: column.def.minWidth ? `${column.def.minWidth}px` : void 0,
68
+ maxWidth: column.def.maxWidth ? `${column.def.maxWidth}px` : void 0,
69
+ position: isSticky ? "sticky" : sticky ? "relative" : void 0,
70
+ left: isSticky ? 0 : void 0,
71
+ zIndex: isSticky ? 12 : sticky ? 10 : void 0,
72
+ backgroundColor: sticky ? "var(--table-x-header-bg, #f9fafb)" : isSticky ? "var(--table-x-sticky-bg, #fff)" : void 0
73
+ },
74
+ role: "columnheader",
75
+ "aria-sort": isSorted ? sortDirection === "asc" ? "ascending" : "descending" : column.sortable ? "none" : void 0,
76
+ onClick: () => {
77
+ if (column.sortable) {
78
+ onSort(column.id);
79
+ }
80
+ },
81
+ children: [
82
+ /* @__PURE__ */ jsx("div", { className: "table-x-header-cell-content", children: renderHeader ? renderHeader(column, sortState) : /* @__PURE__ */ jsxs(Fragment, { children: [
83
+ /* @__PURE__ */ jsx("span", { children: column.header }),
84
+ column.sortable && /* @__PURE__ */ jsx("span", { className: "table-x-sort-indicator", "aria-hidden": "true", children: sortDirection === "asc" ? "\u2191" : sortDirection === "desc" ? "\u2193" : "\u21C5" })
85
+ ] }) }),
86
+ onResize && /* @__PURE__ */ jsx(
87
+ "div",
88
+ {
89
+ className: "table-x-resize-handle",
90
+ onMouseDown: (e) => handleResizeStart(e, column.id, column.width),
91
+ role: "separator",
92
+ "aria-orientation": "vertical",
93
+ "aria-label": `Resize column ${column.header}`
94
+ }
95
+ )
96
+ ]
97
+ },
98
+ column.id
99
+ );
100
+ }) })
101
+ }
102
+ );
103
+ }
104
+ function TableCell({
105
+ column,
106
+ row,
107
+ rowIndex,
108
+ columnIndex,
109
+ renderCell,
110
+ className = ""
111
+ }) {
112
+ const value = column.accessor(row);
113
+ const content = renderCell ? renderCell(value, row, column) : String(value ?? "");
114
+ const align = column.align || "left";
115
+ const isSticky = className.includes("table-x-cell--sticky");
116
+ return /* @__PURE__ */ jsx(
117
+ "td",
118
+ {
119
+ className: `table-x-cell table-x-cell--${align} ${className}`,
120
+ style: {
121
+ textAlign: align,
122
+ width: column.width ? `${column.width}px` : void 0,
123
+ minWidth: column.def.minWidth ? `${column.def.minWidth}px` : void 0,
124
+ maxWidth: column.def.maxWidth ? `${column.def.maxWidth}px` : void 0,
125
+ position: isSticky ? "sticky" : void 0,
126
+ left: isSticky ? 0 : void 0,
127
+ zIndex: isSticky ? 1 : void 0,
128
+ backgroundColor: isSticky ? "var(--table-x-sticky-bg, inherit)" : void 0
129
+ },
130
+ role: "gridcell",
131
+ "aria-colindex": columnIndex + 1,
132
+ children: content
133
+ }
134
+ );
135
+ }
136
+ function TableBody({
137
+ data,
138
+ columns,
139
+ getRowKey = (_, index) => index,
140
+ renderCell,
141
+ renderRow,
142
+ stickyFirstColumn = false,
143
+ isLoading = false,
144
+ error = null,
145
+ emptyComponent: EmptyComponent,
146
+ loadingComponent: LoadingComponent,
147
+ errorComponent: ErrorComponent,
148
+ bordered = true,
149
+ className = ""
150
+ }) {
151
+ if (isLoading && LoadingComponent) {
152
+ return /* @__PURE__ */ jsx("tbody", { className: `table-x-body table-x-body--loading ${className}`, children: /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx("td", { colSpan: columns.length, className: "table-x-body-empty", children: /* @__PURE__ */ jsx(LoadingComponent, {}) }) }) });
153
+ }
154
+ if (error && ErrorComponent) {
155
+ return /* @__PURE__ */ jsx("tbody", { className: `table-x-body table-x-body--error ${className}`, children: /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx("td", { colSpan: columns.length, className: "table-x-body-empty", children: /* @__PURE__ */ jsx(ErrorComponent, { error }) }) }) });
156
+ }
157
+ if (data.length === 0) {
158
+ if (EmptyComponent) {
159
+ return /* @__PURE__ */ jsx("tbody", { className: `table-x-body table-x-body--empty ${className}`, children: /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx("td", { colSpan: columns.length, className: "table-x-body-empty", children: /* @__PURE__ */ jsx(EmptyComponent, { columns }) }) }) });
160
+ }
161
+ return /* @__PURE__ */ jsx("tbody", { className: `table-x-body table-x-body--empty ${className}`, children: /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx("td", { colSpan: columns.length, className: "table-x-body-empty", children: "No data available" }) }) });
162
+ }
163
+ return /* @__PURE__ */ jsx("tbody", { className: `table-x-body ${bordered ? "table-x-body--bordered" : "table-x-body--borderless"} ${className}`, children: data.map((row, rowIndex) => {
164
+ const key = getRowKey(row, rowIndex);
165
+ const cells = columns.map((column, columnIndex) => {
166
+ const isFirstColumn = columnIndex === 0;
167
+ const isSticky = stickyFirstColumn && isFirstColumn;
168
+ return /* @__PURE__ */ jsx(
169
+ TableCell,
170
+ {
171
+ column,
172
+ row,
173
+ rowIndex,
174
+ columnIndex,
175
+ renderCell,
176
+ className: `${isSticky ? "table-x-cell--sticky" : ""} ${bordered ? "table-x-cell--bordered" : "table-x-cell--borderless"}`
177
+ },
178
+ column.id
179
+ );
180
+ });
181
+ if (renderRow) {
182
+ return /* @__PURE__ */ jsx(React2.Fragment, { children: renderRow(row, rowIndex, cells) }, key);
183
+ }
184
+ return /* @__PURE__ */ jsx(
185
+ "tr",
186
+ {
187
+ role: "row",
188
+ className: "table-x-row",
189
+ children: cells
190
+ },
191
+ key
192
+ );
193
+ }) });
194
+ }
195
+ function DataTable({
196
+ table,
197
+ slots = {},
198
+ renderCell,
199
+ renderHeader,
200
+ renderRow,
201
+ getRowKey,
202
+ stickyHeader = false,
203
+ stickyFirstColumn = false,
204
+ enableResizing = false,
205
+ maxHeight,
206
+ bordered = true,
207
+ className = "",
208
+ isLoading = false,
209
+ error = null
210
+ }) {
211
+ const [columnWidths, setColumnWidths] = useState({});
212
+ const handleResize = useCallback(
213
+ (columnId, width) => {
214
+ setColumnWidths((prev) => ({
215
+ ...prev,
216
+ [columnId]: width
217
+ }));
218
+ },
219
+ []
220
+ );
221
+ const columnsWithWidths = table.visibleColumns.map((column) => {
222
+ const customWidth = columnWidths[column.id];
223
+ if (customWidth) {
224
+ return {
225
+ ...column,
226
+ width: customWidth
227
+ };
228
+ }
229
+ return column;
230
+ });
231
+ const maxHeightValue = maxHeight ? typeof maxHeight === "number" ? `${maxHeight}px` : maxHeight : void 0;
232
+ const hasVerticalScroll = maxHeight !== void 0;
233
+ return /* @__PURE__ */ jsx(
234
+ "div",
235
+ {
236
+ className: `table-x-container ${bordered ? "table-x-container--bordered" : "table-x-container--borderless"} ${className}`,
237
+ style: {
238
+ // CSS variables for theming
239
+ "--table-x-sticky-bg": "var(--table-x-bg, #fff)",
240
+ "--table-x-border-color": "var(--table-x-border-color, #e5e7eb)",
241
+ "--table-x-border-width": "var(--table-x-border-width, 1px)",
242
+ "--table-x-header-bg": "var(--table-x-header-bg, #f9fafb)",
243
+ "--table-x-hover-bg": "var(--table-x-hover-bg, #f3f4f6)"
244
+ },
245
+ children: /* @__PURE__ */ jsx(
246
+ "div",
247
+ {
248
+ className: `table-x-wrapper ${hasVerticalScroll ? "table-x-wrapper--scrollable" : ""}`,
249
+ style: {
250
+ overflowX: "auto",
251
+ overflowY: hasVerticalScroll ? "auto" : "visible",
252
+ maxHeight: maxHeightValue,
253
+ position: "relative"
254
+ },
255
+ children: /* @__PURE__ */ jsxs(
256
+ "table",
257
+ {
258
+ className: `table-x-table ${bordered ? "table-x-table--bordered" : "table-x-table--borderless"}`,
259
+ role: "table",
260
+ "aria-label": "Data table",
261
+ style: {
262
+ width: "100%",
263
+ borderCollapse: "separate",
264
+ borderSpacing: 0,
265
+ tableLayout: "auto"
266
+ },
267
+ children: [
268
+ /* @__PURE__ */ jsx(
269
+ TableHeader,
270
+ {
271
+ columns: columnsWithWidths,
272
+ sortState: table.sorting.state,
273
+ onSort: table.sorting.toggle,
274
+ onResize: enableResizing ? handleResize : void 0,
275
+ renderHeader,
276
+ sticky: stickyHeader,
277
+ stickyFirstColumn,
278
+ bordered
279
+ }
280
+ ),
281
+ /* @__PURE__ */ jsx(
282
+ TableBody,
283
+ {
284
+ data: table.paginatedData,
285
+ columns: columnsWithWidths,
286
+ getRowKey,
287
+ renderCell,
288
+ renderRow,
289
+ stickyFirstColumn,
290
+ isLoading,
291
+ error,
292
+ emptyComponent: slots.empty,
293
+ loadingComponent: slots.loader,
294
+ errorComponent: slots.error,
295
+ bordered
296
+ }
297
+ )
298
+ ]
299
+ }
300
+ )
301
+ }
302
+ )
303
+ }
304
+ );
305
+ }
306
+
307
+ export { DataTable, TableBody, TableCell, TableHeader };
308
+ //# sourceMappingURL=ui.mjs.map
309
+ //# sourceMappingURL=ui.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../packages/ui/TableHeader.tsx","../packages/ui/TableCell.tsx","../packages/ui/TableBody.tsx","../packages/ui/DataTable.tsx"],"names":["e","jsx","React","useState","useCallback","jsxs"],"mappings":"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","file":"ui.mjs","sourcesContent":["/**\n * Table header component\n *\n * Renders table headers with support for:\n * - Sortable columns with sort indicators\n * - Column resizing (pointer-based)\n * - Custom header renderers\n * - Sticky header support\n */\n\nimport React, { useState, useCallback, useRef } from \"react\";\nimport type { Column } from \"../core/columns\";\nimport type { SortState } from \"../core/sorting\";\n\nexport interface TableHeaderProps<TData> {\n /** Visible columns */\n columns: Column<TData>[];\n \n /** Current sort state */\n sortState: SortState;\n \n /** Sort toggle handler */\n onSort: (columnId: string) => void;\n \n /** Column resize handler */\n onResize?: (columnId: string, width: number) => void;\n \n /** Custom header renderer */\n renderHeader?: (column: Column<TData>, sortState: SortState) => React.ReactNode;\n \n /** Whether header is sticky */\n sticky?: boolean;\n \n /** Whether first column is sticky */\n stickyFirstColumn?: boolean;\n \n /** Whether borders are enabled */\n bordered?: boolean;\n \n /** Additional className */\n className?: string;\n}\n\n/**\n * TableHeader component\n * \n * Renders table header row with sortable columns and resizing support.\n */\nexport function TableHeader<TData>({\n columns,\n sortState,\n onSort,\n onResize,\n renderHeader,\n sticky = false,\n stickyFirstColumn = false,\n bordered = true,\n className = \"\",\n}: TableHeaderProps<TData>) {\n const [resizingColumn, setResizingColumn] = useState<string | null>(null);\n const resizeStartX = useRef<number>(0);\n const resizeStartWidth = useRef<number>(0);\n const resizeColumnId = useRef<string | null>(null);\n\n const handleResizeStart = useCallback(\n (e: React.MouseEvent, columnId: string, currentWidth?: number) => {\n e.preventDefault();\n e.stopPropagation();\n \n setResizingColumn(columnId);\n resizeStartX.current = e.clientX;\n resizeStartWidth.current = currentWidth || 150;\n resizeColumnId.current = columnId;\n \n const handleMouseMove = (e: MouseEvent) => {\n if (!resizeColumnId.current || !onResize) return;\n \n const diff = e.clientX - resizeStartX.current;\n const newWidth = Math.max(50, resizeStartWidth.current + diff);\n onResize(resizeColumnId.current, newWidth);\n };\n \n const handleMouseUp = () => {\n setResizingColumn(null);\n resizeColumnId.current = null;\n document.removeEventListener(\"mousemove\", handleMouseMove);\n document.removeEventListener(\"mouseup\", handleMouseUp);\n };\n \n document.addEventListener(\"mousemove\", handleMouseMove);\n document.addEventListener(\"mouseup\", handleMouseUp);\n },\n [onResize]\n );\n\n return (\n <thead\n className={`table-x-header ${sticky ? \"table-x-header--sticky\" : \"\"} ${bordered ? \"table-x-header--bordered\" : \"table-x-header--borderless\"} ${className}`}\n style={\n sticky\n ? {\n position: \"sticky\",\n top: 0,\n zIndex: 10,\n backgroundColor: \"var(--table-x-header-bg, #f9fafb)\",\n }\n : undefined\n }\n >\n <tr role=\"row\">\n {columns.map((column, index) => {\n const isFirstColumn = index === 0;\n const isSticky = stickyFirstColumn && isFirstColumn;\n const isSorted = sortState.columnId === column.id;\n const sortDirection = isSorted ? sortState.direction : null;\n \n return (\n <th\n key={column.id}\n className={`table-x-header-cell ${\n column.sortable ? \"table-x-header-cell--sortable\" : \"\"\n } ${isSorted ? \"table-x-header-cell--sorted\" : \"\"} ${\n isSticky ? \"table-x-header-cell--sticky\" : \"\"\n } ${resizingColumn === column.id ? \"table-x-header-cell--resizing\" : \"\"} ${\n bordered ? \"table-x-header-cell--bordered\" : \"table-x-header-cell--borderless\"\n }`}\n style={{\n textAlign: column.align || \"left\",\n width: column.width ? `${column.width}px` : undefined,\n minWidth: column.def.minWidth ? `${column.def.minWidth}px` : undefined,\n maxWidth: column.def.maxWidth ? `${column.def.maxWidth}px` : undefined,\n position: isSticky ? \"sticky\" : sticky ? \"relative\" : undefined,\n left: isSticky ? 0 : undefined,\n zIndex: isSticky ? 12 : sticky ? 10 : undefined,\n backgroundColor: sticky\n ? \"var(--table-x-header-bg, #f9fafb)\"\n : isSticky\n ? \"var(--table-x-sticky-bg, #fff)\"\n : undefined,\n }}\n role=\"columnheader\"\n aria-sort={\n isSorted\n ? sortDirection === \"asc\"\n ? \"ascending\"\n : \"descending\"\n : column.sortable\n ? \"none\"\n : undefined\n }\n onClick={() => {\n if (column.sortable) {\n onSort(column.id);\n }\n }}\n >\n <div className=\"table-x-header-cell-content\">\n {renderHeader ? (\n renderHeader(column, sortState)\n ) : (\n <>\n <span>{column.header}</span>\n {column.sortable && (\n <span className=\"table-x-sort-indicator\" aria-hidden=\"true\">\n {sortDirection === \"asc\" ? \"↑\" : sortDirection === \"desc\" ? \"↓\" : \"⇅\"}\n </span>\n )}\n </>\n )}\n </div>\n {onResize && (\n <div\n className=\"table-x-resize-handle\"\n onMouseDown={(e) => handleResizeStart(e, column.id, column.width)}\n role=\"separator\"\n aria-orientation=\"vertical\"\n aria-label={`Resize column ${column.header}`}\n />\n )}\n </th>\n );\n })}\n </tr>\n </thead>\n );\n}\n","/**\r\n * Table cell component\r\n *\r\n * Renders individual table cells with support for:\r\n * - Custom cell renderers\r\n * - Cell alignment\r\n * - Cell styling via CSS variables\r\n */\r\n\r\nimport React from \"react\";\r\nimport type { Column } from \"../core/columns\";\r\n\r\nexport interface TableCellProps<TData> {\r\n /** Column definition */\r\n column: Column<TData>;\r\n \r\n /** Data row */\r\n row: TData;\r\n \r\n /** Row index */\r\n rowIndex: number;\r\n \r\n /** Column index */\r\n columnIndex: number;\r\n \r\n /** Custom cell renderer */\r\n renderCell?: (value: unknown, row: TData, column: Column<TData>) => React.ReactNode;\r\n \r\n /** Additional className */\r\n className?: string;\r\n}\r\n\r\n/**\r\n * TableCell component\r\n * \r\n * Renders a single table cell with proper alignment and styling.\r\n */\r\nexport function TableCell<TData>({\r\n column,\r\n row,\r\n rowIndex,\r\n columnIndex,\r\n renderCell,\r\n className = \"\",\r\n}: TableCellProps<TData>) {\r\n const value = column.accessor(row);\r\n \r\n // Use custom renderer if provided, otherwise use default rendering\r\n const content = renderCell\r\n ? renderCell(value, row, column)\r\n : String(value ?? \"\");\r\n \r\n const align = column.align || \"left\";\r\n \r\n const isSticky = className.includes(\"table-x-cell--sticky\");\r\n \r\n return (\r\n <td\r\n className={`table-x-cell table-x-cell--${align} ${className}`}\r\n style={{\r\n textAlign: align,\r\n width: column.width ? `${column.width}px` : undefined,\r\n minWidth: column.def.minWidth ? `${column.def.minWidth}px` : undefined,\r\n maxWidth: column.def.maxWidth ? `${column.def.maxWidth}px` : undefined,\r\n position: isSticky ? \"sticky\" : undefined,\r\n left: isSticky ? 0 : undefined,\r\n zIndex: isSticky ? 1 : undefined,\r\n backgroundColor: isSticky ? \"var(--table-x-sticky-bg, inherit)\" : undefined,\r\n }}\r\n role=\"gridcell\"\r\n aria-colindex={columnIndex + 1}\r\n >\r\n {content}\r\n </td>\r\n );\r\n}\r\n","/**\n * Table body component\n *\n * Renders table body with support for:\n * - Row rendering with proper keys\n * - Custom row renderers\n * - Empty state\n * - Loading state\n * - Error state\n */\n\nimport React from \"react\";\nimport type { Column } from \"../core/columns\";\nimport { TableCell } from \"./TableCell\";\n\nexport interface TableBodyProps<TData> {\n /** Data rows to render */\n data: TData[];\n \n /** Visible columns */\n columns: Column<TData>[];\n \n /** Row key extractor */\n getRowKey?: (row: TData, index: number) => string | number;\n \n /** Custom cell renderer */\n renderCell?: (value: unknown, row: TData, column: Column<TData>) => React.ReactNode;\n \n /** Custom row renderer */\n renderRow?: (\n row: TData,\n index: number,\n cells: React.ReactNode[]\n ) => React.ReactNode;\n \n /** Whether first column is sticky */\n stickyFirstColumn?: boolean;\n \n /** Loading state */\n isLoading?: boolean;\n \n /** Error state */\n error?: Error | string | null;\n \n /** Empty state component */\n emptyComponent?: React.ComponentType<{ columns: Column<TData>[] }>;\n \n /** Loading state component */\n loadingComponent?: React.ComponentType;\n \n /** Error state component */\n errorComponent?: React.ComponentType<{ error: Error | string }>;\n \n /** Whether borders are enabled */\n bordered?: boolean;\n \n /** Additional className */\n className?: string;\n}\n\n/**\n * TableBody component\n * \n * Renders table body rows with support for loading, error, and empty states.\n */\nexport function TableBody<TData>({\n data,\n columns,\n getRowKey = (_, index) => index,\n renderCell,\n renderRow,\n stickyFirstColumn = false,\n isLoading = false,\n error = null,\n emptyComponent: EmptyComponent,\n loadingComponent: LoadingComponent,\n errorComponent: ErrorComponent,\n bordered = true,\n className = \"\",\n}: TableBodyProps<TData>) {\n // Loading state\n if (isLoading && LoadingComponent) {\n return (\n <tbody className={`table-x-body table-x-body--loading ${className}`}>\n <tr>\n <td colSpan={columns.length} className=\"table-x-body-empty\">\n <LoadingComponent />\n </td>\n </tr>\n </tbody>\n );\n }\n\n // Error state\n if (error && ErrorComponent) {\n return (\n <tbody className={`table-x-body table-x-body--error ${className}`}>\n <tr>\n <td colSpan={columns.length} className=\"table-x-body-empty\">\n <ErrorComponent error={error} />\n </td>\n </tr>\n </tbody>\n );\n }\n\n // Empty state\n if (data.length === 0) {\n if (EmptyComponent) {\n return (\n <tbody className={`table-x-body table-x-body--empty ${className}`}>\n <tr>\n <td colSpan={columns.length} className=\"table-x-body-empty\">\n <EmptyComponent columns={columns} />\n </td>\n </tr>\n </tbody>\n );\n }\n \n return (\n <tbody className={`table-x-body table-x-body--empty ${className}`}>\n <tr>\n <td colSpan={columns.length} className=\"table-x-body-empty\">\n No data available\n </td>\n </tr>\n </tbody>\n );\n }\n\n // Render rows\n return (\n <tbody className={`table-x-body ${bordered ? \"table-x-body--bordered\" : \"table-x-body--borderless\"} ${className}`}>\n {data.map((row, rowIndex) => {\n const key = getRowKey(row, rowIndex);\n \n const cells = columns.map((column, columnIndex) => {\n const isFirstColumn = columnIndex === 0;\n const isSticky = stickyFirstColumn && isFirstColumn;\n \n return (\n <TableCell\n key={column.id}\n column={column}\n row={row}\n rowIndex={rowIndex}\n columnIndex={columnIndex}\n renderCell={renderCell}\n className={`${isSticky ? \"table-x-cell--sticky\" : \"\"} ${bordered ? \"table-x-cell--bordered\" : \"table-x-cell--borderless\"}`}\n />\n );\n });\n\n if (renderRow) {\n return (\n <React.Fragment key={key}>\n {renderRow(row, rowIndex, cells)}\n </React.Fragment>\n );\n }\n\n return (\n <tr\n key={key}\n role=\"row\"\n className=\"table-x-row\"\n >\n {cells}\n </tr>\n );\n })}\n </tbody>\n );\n}\n","/**\n * Main DataTable component\n *\n * Renders a complete data table with:\n * - Header and body\n * - Sticky header and first column\n * - Column resizing\n * - Custom renderers\n * - Loading/empty/error states via slots\n */\n\nimport React, { useCallback, useState } from \"react\";\nimport type { TableInstance } from \"../react/useDataTable\";\nimport { TableHeader } from \"./TableHeader\";\nimport { TableBody } from \"./TableBody\";\n\nexport interface DataTableSlots<TData> {\n /** Loading state component */\n loader?: React.ComponentType;\n \n /** Empty state component */\n empty?: React.ComponentType<{ columns: import(\"../core/columns\").Column<TData>[] }>;\n \n /** Error state component */\n error?: React.ComponentType<{ error: Error | string }>;\n}\n\nexport interface DataTableProps<TData> {\n /** Table instance from useDataTable hook */\n table: TableInstance<TData>;\n \n /** Custom slots for loading/empty/error states */\n slots?: DataTableSlots<TData>;\n \n /** Custom cell renderer */\n renderCell?: (value: unknown, row: TData, column: import(\"../core/columns\").Column<TData>) => React.ReactNode;\n \n /** Custom header renderer */\n renderHeader?: (\n column: import(\"../core/columns\").Column<TData>,\n sortState: import(\"../core/sorting\").SortState\n ) => React.ReactNode;\n \n /** Custom row renderer */\n renderRow?: (\n row: TData,\n index: number,\n cells: React.ReactNode[]\n ) => React.ReactNode;\n \n /** Row key extractor */\n getRowKey?: (row: TData, index: number) => string | number;\n \n /** Whether header is sticky */\n stickyHeader?: boolean;\n \n /** Whether first column is sticky */\n stickyFirstColumn?: boolean;\n \n /** Enable column resizing */\n enableResizing?: boolean;\n \n /** Maximum height for vertical scrolling (in pixels) */\n maxHeight?: number | string;\n \n /** Whether to show borders (default: true) */\n bordered?: boolean;\n \n /** Additional className */\n className?: string;\n \n /** Loading state */\n isLoading?: boolean;\n \n /** Error state */\n error?: Error | string | null;\n}\n\n/**\n * DataTable component\n * \n * Main table component that renders a complete data table with all features.\n * \n * @example\n * ```tsx\n * const table = useDataTable({ data, columns });\n * \n * <DataTable\n * table={table}\n * stickyHeader\n * stickyFirstColumn\n * enableResizing\n * maxHeight={400}\n * bordered\n * slots={{\n * loader: () => <div>Loading...</div>,\n * empty: () => <div>No data</div>,\n * }}\n * />\n * ```\n */\nexport function DataTable<TData>({\n table,\n slots = {},\n renderCell,\n renderHeader,\n renderRow,\n getRowKey,\n stickyHeader = false,\n stickyFirstColumn = false,\n enableResizing = false,\n maxHeight,\n bordered = true,\n className = \"\",\n isLoading = false,\n error = null,\n}: DataTableProps<TData>) {\n // Track column widths for resizing\n const [columnWidths, setColumnWidths] = useState<Record<string, number>>({});\n\n const handleResize = useCallback(\n (columnId: string, width: number) => {\n setColumnWidths((prev) => ({\n ...prev,\n [columnId]: width,\n }));\n \n // TODO: Persist column widths to state/URL/localStorage\n // TODO: Update column definitions with new widths\n },\n []\n );\n\n // Apply custom widths to columns\n const columnsWithWidths = table.visibleColumns.map((column) => {\n const customWidth = columnWidths[column.id];\n if (customWidth) {\n return {\n ...column,\n width: customWidth,\n };\n }\n return column;\n });\n\n // Normalize maxHeight to CSS value\n const maxHeightValue = maxHeight\n ? typeof maxHeight === \"number\"\n ? `${maxHeight}px`\n : maxHeight\n : undefined;\n\n // Determine if we need a scroll container\n const hasVerticalScroll = maxHeight !== undefined;\n\n return (\n <div\n className={`table-x-container ${bordered ? \"table-x-container--bordered\" : \"table-x-container--borderless\"} ${className}`}\n style={{\n // CSS variables for theming\n \"--table-x-sticky-bg\": \"var(--table-x-bg, #fff)\",\n \"--table-x-border-color\": \"var(--table-x-border-color, #e5e7eb)\",\n \"--table-x-border-width\": \"var(--table-x-border-width, 1px)\",\n \"--table-x-header-bg\": \"var(--table-x-header-bg, #f9fafb)\",\n \"--table-x-hover-bg\": \"var(--table-x-hover-bg, #f3f4f6)\",\n } as React.CSSProperties}\n >\n <div\n className={`table-x-wrapper ${hasVerticalScroll ? \"table-x-wrapper--scrollable\" : \"\"}`}\n style={{\n overflowX: \"auto\",\n overflowY: hasVerticalScroll ? \"auto\" : \"visible\",\n maxHeight: maxHeightValue,\n position: \"relative\",\n }}\n >\n <table\n className={`table-x-table ${bordered ? \"table-x-table--bordered\" : \"table-x-table--borderless\"}`}\n role=\"table\"\n aria-label=\"Data table\"\n style={{\n width: \"100%\",\n borderCollapse: \"separate\",\n borderSpacing: 0,\n tableLayout: \"auto\",\n }}\n >\n <TableHeader\n columns={columnsWithWidths}\n sortState={table.sorting.state}\n onSort={table.sorting.toggle}\n onResize={enableResizing ? handleResize : undefined}\n renderHeader={renderHeader}\n sticky={stickyHeader}\n stickyFirstColumn={stickyFirstColumn}\n bordered={bordered}\n />\n <TableBody\n data={table.paginatedData}\n columns={columnsWithWidths}\n getRowKey={getRowKey}\n renderCell={renderCell}\n renderRow={renderRow}\n stickyFirstColumn={stickyFirstColumn}\n isLoading={isLoading}\n error={error}\n emptyComponent={slots.empty}\n loadingComponent={slots.loader}\n errorComponent={slots.error}\n bordered={bordered}\n />\n </table>\n </div>\n \n {/* TODO: Add footer with pagination controls */}\n {/* TODO: Add column visibility toggle UI */}\n {/* TODO: Add export functionality */}\n </div>\n );\n}\n"]}
package/package.json ADDED
@@ -0,0 +1,81 @@
1
+ {
2
+ "name": "tablero",
3
+ "version": "1.0.0",
4
+ "description": "A type-safe, framework-agnostic data table library with React bindings",
5
+ "main": "./dist/core.js",
6
+ "module": "./dist/core.js",
7
+ "types": "./dist/core.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/core.d.ts",
11
+ "import": "./dist/core.js",
12
+ "require": "./dist/core.cjs"
13
+ },
14
+ "./core": {
15
+ "types": "./dist/core.d.ts",
16
+ "import": "./dist/core.js",
17
+ "require": "./dist/core.cjs"
18
+ },
19
+ "./react": {
20
+ "types": "./dist/react.d.ts",
21
+ "import": "./dist/react.js",
22
+ "require": "./dist/react.cjs"
23
+ },
24
+ "./ui": {
25
+ "types": "./dist/ui.d.ts",
26
+ "import": "./dist/ui.js",
27
+ "require": "./dist/ui.cjs"
28
+ },
29
+ "./package.json": "./package.json"
30
+ },
31
+ "files": [
32
+ "dist",
33
+ "README.md"
34
+ ],
35
+ "scripts": {
36
+ "build": "tsup",
37
+ "dev": "vite",
38
+ "preview": "vite preview",
39
+ "example": "tsx examples/basic-example.ts",
40
+ "prepublishOnly": "npm run build"
41
+ },
42
+ "keywords": [
43
+ "table",
44
+ "data-table",
45
+ "datatable",
46
+ "react-table",
47
+ "typescript",
48
+ "sorting",
49
+ "pagination",
50
+ "filtering",
51
+ "data-grid"
52
+ ],
53
+ "author": "Ojas",
54
+ "license": "MIT",
55
+ "repository": {
56
+ "type": "git",
57
+ "url": "https://github.com/ojas-elawadhi/table-x"
58
+ },
59
+ "peerDependencies": {
60
+ "react": ">=18.0.0",
61
+ "react-dom": ">=18.0.0"
62
+ },
63
+ "peerDependenciesMeta": {
64
+ "react": {
65
+ "optional": false
66
+ },
67
+ "react-dom": {
68
+ "optional": false
69
+ }
70
+ },
71
+ "devDependencies": {
72
+ "@types/react": "^19.2.7",
73
+ "@vitejs/plugin-react": "^4.3.4",
74
+ "react": "^19.2.3",
75
+ "react-dom": "^19.2.3",
76
+ "tsup": "^8.5.1",
77
+ "tsx": "^4.19.2",
78
+ "typescript": "^5.9.3",
79
+ "vite": "^6.0.5"
80
+ }
81
+ }