@zvndev/yable-react 0.5.1 → 0.6.1
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 +53 -35
- package/dist/index.cjs +329 -25
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +36 -5
- package/dist/index.d.ts +36 -5
- package/dist/index.js +329 -25
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -73,37 +73,37 @@ const table = useTable({
|
|
|
73
73
|
|
|
74
74
|
### Layout Components
|
|
75
75
|
|
|
76
|
-
| Component
|
|
77
|
-
|
|
78
|
-
| `Table`
|
|
79
|
-
| `TableHeader` | Renders `<thead>` with header groups and sort indicators.
|
|
80
|
-
| `TableBody`
|
|
81
|
-
| `TableCell`
|
|
82
|
-
| `TableFooter` | Renders `<tfoot>` with footer content.
|
|
76
|
+
| Component | Description |
|
|
77
|
+
| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
78
|
+
| `Table` | Root container -- wraps everything in a `<div>` with a desktop table or adaptive card layout inside. Accepts `table`, `striped`, `bordered`, `compact`, `stickyHeader`, `theme`, `loading`, `emptyMessage`, `footer`, `adaptiveLayout`, and `children` props. |
|
|
79
|
+
| `TableHeader` | Renders `<thead>` with header groups and sort indicators. |
|
|
80
|
+
| `TableBody` | Renders `<tbody>` with rows and cells. |
|
|
81
|
+
| `TableCell` | Renders a single `<td>` with editing support. |
|
|
82
|
+
| `TableFooter` | Renders `<tfoot>` with footer content. |
|
|
83
83
|
|
|
84
84
|
### Interactive Components
|
|
85
85
|
|
|
86
|
-
| Component
|
|
87
|
-
|
|
88
|
-
| `Pagination`
|
|
89
|
-
| `GlobalFilter`
|
|
90
|
-
| `SortIndicator` | Sort direction arrow icon. Props: `direction`, `index` (for multi-sort badge).
|
|
86
|
+
| Component | Description |
|
|
87
|
+
| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
88
|
+
| `Pagination` | Page navigation with first/last/prev/next buttons, page numbers, and page size selector. Props: `table`, `showPageSize`, `pageSizes`, `showInfo`, `showFirstLast`. |
|
|
89
|
+
| `GlobalFilter` | Debounced search input for the global filter. Props: `table`, `placeholder`, `debounce`, `className`. |
|
|
90
|
+
| `SortIndicator` | Sort direction arrow icon. Props: `direction`, `index` (for multi-sort badge). |
|
|
91
91
|
|
|
92
92
|
### Form Components (In-Cell Editing)
|
|
93
93
|
|
|
94
|
-
| Component
|
|
95
|
-
|
|
96
|
-
| `CellInput`
|
|
97
|
-
| `CellSelect`
|
|
98
|
-
| `CellCheckbox`
|
|
99
|
-
| `CellToggle`
|
|
100
|
-
| `CellDatePicker` | Date input for cell editing.
|
|
94
|
+
| Component | Description |
|
|
95
|
+
| ---------------- | --------------------------------------------------------------------------------------------------- |
|
|
96
|
+
| `CellInput` | Text/number input for cell editing. Props: `context`, `type`, `placeholder`, `inline`, `autoFocus`. |
|
|
97
|
+
| `CellSelect` | Dropdown select for cell editing. |
|
|
98
|
+
| `CellCheckbox` | Checkbox for boolean cell values. |
|
|
99
|
+
| `CellToggle` | Toggle switch for boolean cell values. |
|
|
100
|
+
| `CellDatePicker` | Date input for cell editing. |
|
|
101
101
|
|
|
102
102
|
### Context
|
|
103
103
|
|
|
104
|
-
| Export
|
|
105
|
-
|
|
106
|
-
| `TableProvider`
|
|
104
|
+
| Export | Description |
|
|
105
|
+
| ------------------- | ----------------------------------------------------------- |
|
|
106
|
+
| `TableProvider` | React context provider for the table instance. |
|
|
107
107
|
| `useTableContext()` | Hook to access the table instance from any child component. |
|
|
108
108
|
|
|
109
109
|
## Re-exports from @zvndev/yable-core
|
|
@@ -123,23 +123,41 @@ The `<Table>` component accepts these props:
|
|
|
123
123
|
|
|
124
124
|
```typescript
|
|
125
125
|
interface TableProps<TData> {
|
|
126
|
-
table: Table<TData>
|
|
127
|
-
stickyHeader?: boolean
|
|
128
|
-
striped?: boolean
|
|
129
|
-
bordered?: boolean
|
|
130
|
-
compact?: boolean
|
|
131
|
-
theme?: string
|
|
132
|
-
clickableRows?: boolean
|
|
133
|
-
footer?: boolean
|
|
134
|
-
loading?: boolean
|
|
135
|
-
emptyMessage?: string
|
|
136
|
-
renderEmpty?: () => ReactNode
|
|
126
|
+
table: Table<TData> // Required -- the table instance from useTable
|
|
127
|
+
stickyHeader?: boolean // Pin header to top on scroll
|
|
128
|
+
striped?: boolean // Alternate row backgrounds
|
|
129
|
+
bordered?: boolean // Add cell borders
|
|
130
|
+
compact?: boolean // Reduce padding
|
|
131
|
+
theme?: string // Theme variant name
|
|
132
|
+
clickableRows?: boolean // Add pointer cursor + hover to rows
|
|
133
|
+
footer?: boolean // Show table footer
|
|
134
|
+
loading?: boolean // Show loading overlay
|
|
135
|
+
emptyMessage?: string // Text when no rows (default: "No data")
|
|
136
|
+
renderEmpty?: () => ReactNode // Custom empty state
|
|
137
137
|
renderLoading?: () => ReactNode // Custom loading state
|
|
138
|
-
|
|
139
|
-
|
|
138
|
+
adaptiveLayout?: boolean | AdaptiveTableLayoutOptions<TData>
|
|
139
|
+
children?: ReactNode // Extra content (e.g. Pagination)
|
|
140
|
+
className?: string // Additional CSS class
|
|
140
141
|
}
|
|
141
142
|
```
|
|
142
143
|
|
|
144
|
+
### Adaptive tablet and mobile layouts
|
|
145
|
+
|
|
146
|
+
Use `adaptiveLayout` when the same table instance should become a structural card layout on narrower containers instead of only scrolling horizontally.
|
|
147
|
+
|
|
148
|
+
```tsx
|
|
149
|
+
<Table
|
|
150
|
+
table={table}
|
|
151
|
+
adaptiveLayout={{
|
|
152
|
+
breakpoint: 720,
|
|
153
|
+
primaryColumnId: 'name',
|
|
154
|
+
secondaryColumnIds: ['status', 'owner', 'updatedAt'],
|
|
155
|
+
}}
|
|
156
|
+
/>
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Set `mode: 'cards'` or `mode: 'table'` to force a surface, or provide `renderCard` for a product-specific mobile layout while still receiving the row, cells, and table instance.
|
|
160
|
+
|
|
143
161
|
## License
|
|
144
162
|
|
|
145
163
|
MIT
|
package/dist/index.cjs
CHANGED
|
@@ -2218,6 +2218,62 @@ function FillHandle({
|
|
|
2218
2218
|
}
|
|
2219
2219
|
);
|
|
2220
2220
|
}
|
|
2221
|
+
function renderCellContent(cell, table) {
|
|
2222
|
+
const column = cell.column;
|
|
2223
|
+
const isEditing = cell.getIsEditing();
|
|
2224
|
+
const isAlwaysEditable = cell.getIsAlwaysEditable();
|
|
2225
|
+
const cellStatus = table.getCellStatus(cell.row.id, column.id);
|
|
2226
|
+
const overrideValue = cellStatus !== "idle" ? table.getCellRenderValue(cell.row.id, column.id) : void 0;
|
|
2227
|
+
let content;
|
|
2228
|
+
const cellDef = column.columnDef.cell;
|
|
2229
|
+
const cellType = column.columnDef.cellType;
|
|
2230
|
+
if (typeof cellDef === "function") {
|
|
2231
|
+
const ctx = cell.getContext();
|
|
2232
|
+
if (overrideValue !== void 0) {
|
|
2233
|
+
const overriddenCtx = {
|
|
2234
|
+
...ctx,
|
|
2235
|
+
getValue: () => overrideValue,
|
|
2236
|
+
renderValue: () => overrideValue
|
|
2237
|
+
};
|
|
2238
|
+
content = cellDef(overriddenCtx);
|
|
2239
|
+
} else {
|
|
2240
|
+
content = cellDef(ctx);
|
|
2241
|
+
}
|
|
2242
|
+
} else if (cellType && !(isEditing || isAlwaysEditable)) {
|
|
2243
|
+
content = resolveCellType(cellType, cell.getContext(), column.columnDef.cellTypeProps);
|
|
2244
|
+
} else {
|
|
2245
|
+
content = overrideValue !== void 0 ? overrideValue : cell.renderValue();
|
|
2246
|
+
}
|
|
2247
|
+
if (!cell.row.getIsGrouped()) return content;
|
|
2248
|
+
if (column.id === cell.row.groupingColumnId) {
|
|
2249
|
+
const expanded = cell.row.getIsExpanded();
|
|
2250
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "yable-group-cell", style: { paddingLeft: cell.row.depth * 16 }, children: [
|
|
2251
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2252
|
+
"button",
|
|
2253
|
+
{
|
|
2254
|
+
type: "button",
|
|
2255
|
+
className: "yable-group-toggle",
|
|
2256
|
+
"aria-label": expanded ? "Collapse group" : "Expand group",
|
|
2257
|
+
"aria-expanded": expanded,
|
|
2258
|
+
onClick: cell.row.getToggleExpandedHandler(),
|
|
2259
|
+
children: expanded ? "\u25BE" : "\u25B8"
|
|
2260
|
+
}
|
|
2261
|
+
),
|
|
2262
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "yable-group-value", children: String(cell.row.groupingValue ?? "") }),
|
|
2263
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "yable-group-count", children: [
|
|
2264
|
+
"(",
|
|
2265
|
+
cell.row.getLeafRows().length,
|
|
2266
|
+
")"
|
|
2267
|
+
] })
|
|
2268
|
+
] });
|
|
2269
|
+
}
|
|
2270
|
+
const aggDef = column.columnDef.aggregatedCell;
|
|
2271
|
+
if (typeof aggDef === "function") {
|
|
2272
|
+
return aggDef(cell.getContext());
|
|
2273
|
+
}
|
|
2274
|
+
const aggVal = cell.getValue();
|
|
2275
|
+
return aggVal == null ? null : aggVal;
|
|
2276
|
+
}
|
|
2221
2277
|
function TableCell({
|
|
2222
2278
|
cell,
|
|
2223
2279
|
table,
|
|
@@ -2253,29 +2309,11 @@ function TableCell({
|
|
|
2253
2309
|
const selectionEdges = table.getCellSelectionEdges(rowIndex, columnIndex);
|
|
2254
2310
|
const isCellSelected = selectionEdges !== null;
|
|
2255
2311
|
const isMultiCellSelection = selectionRange !== null && (selectionRange.start.rowIndex !== selectionRange.end.rowIndex || selectionRange.start.columnIndex !== selectionRange.end.columnIndex);
|
|
2256
|
-
const
|
|
2257
|
-
|
|
2258
|
-
const cellDef = column.columnDef.cell;
|
|
2259
|
-
const cellType = column.columnDef.cellType;
|
|
2260
|
-
if (typeof cellDef === "function") {
|
|
2261
|
-
const ctx = cell.getContext();
|
|
2262
|
-
if (overrideValue !== void 0) {
|
|
2263
|
-
const overriddenCtx = {
|
|
2264
|
-
...ctx,
|
|
2265
|
-
getValue: () => overrideValue,
|
|
2266
|
-
renderValue: () => overrideValue
|
|
2267
|
-
};
|
|
2268
|
-
content = cellDef(overriddenCtx);
|
|
2269
|
-
} else {
|
|
2270
|
-
content = cellDef(ctx);
|
|
2271
|
-
}
|
|
2272
|
-
} else if (cellType && !(isEditing || isAlwaysEditable)) {
|
|
2273
|
-
content = resolveCellType(cellType, cell.getContext(), column.columnDef.cellTypeProps);
|
|
2274
|
-
} else {
|
|
2275
|
-
content = overrideValue !== void 0 ? overrideValue : cell.renderValue();
|
|
2276
|
-
}
|
|
2312
|
+
const isGroupRow = cell.row.getIsGrouped();
|
|
2313
|
+
const content = renderCellContent(cell, table);
|
|
2277
2314
|
const handleClick = React4.useCallback(
|
|
2278
2315
|
(e) => {
|
|
2316
|
+
if (cell.row.getIsGrouped()) return;
|
|
2279
2317
|
table.events.emit("cell:click", {
|
|
2280
2318
|
cell,
|
|
2281
2319
|
row: cell.row,
|
|
@@ -2341,7 +2379,7 @@ function TableCell({
|
|
|
2341
2379
|
const cellStyleDef = column.columnDef.cellStyle;
|
|
2342
2380
|
const userStyle = typeof cellStyleDef === "function" ? cellStyleDef(cell.getContext()) : cellStyleDef;
|
|
2343
2381
|
const mergedStyle = userStyle ? { ...style, ...userStyle } : style;
|
|
2344
|
-
const showFillHandle = isFocused && Boolean(table.options.enableFillHandle) && onFillHandleMouseDown != null;
|
|
2382
|
+
const showFillHandle = isFocused && Boolean(table.options.enableFillHandle) && onFillHandleMouseDown != null && !isGroupRow;
|
|
2345
2383
|
const classNames = [
|
|
2346
2384
|
"yable-td",
|
|
2347
2385
|
isFocused && "yable-cell--focused",
|
|
@@ -2362,6 +2400,7 @@ function TableCell({
|
|
|
2362
2400
|
"data-pinned": pinned || void 0,
|
|
2363
2401
|
"data-cell-status": cellStatus !== "idle" ? cellStatus : void 0,
|
|
2364
2402
|
"data-column-id": column.id,
|
|
2403
|
+
"data-grouped": isGroupRow || void 0,
|
|
2365
2404
|
"data-row-index": rowIndex,
|
|
2366
2405
|
"data-column-index": columnIndex,
|
|
2367
2406
|
"data-cell-selected": isCellSelected || void 0,
|
|
@@ -2836,6 +2875,202 @@ function isInteractiveClickTarget2(target) {
|
|
|
2836
2875
|
target.closest('input, textarea, select, button, a[href], [contenteditable="true"]')
|
|
2837
2876
|
);
|
|
2838
2877
|
}
|
|
2878
|
+
function AdaptiveTableCards({
|
|
2879
|
+
table,
|
|
2880
|
+
layout,
|
|
2881
|
+
clickableRows
|
|
2882
|
+
}) {
|
|
2883
|
+
const rows = table.getRowModel().rows;
|
|
2884
|
+
const visibleColumns = table.getVisibleLeafColumns();
|
|
2885
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "yable-adaptive-cards", role: "rowgroup", children: rows.map((row, rowIndex) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
2886
|
+
AdaptiveTableCard,
|
|
2887
|
+
{
|
|
2888
|
+
row,
|
|
2889
|
+
table,
|
|
2890
|
+
rowIndex,
|
|
2891
|
+
visibleColumns,
|
|
2892
|
+
layout,
|
|
2893
|
+
clickable: clickableRows
|
|
2894
|
+
},
|
|
2895
|
+
row.id
|
|
2896
|
+
)) });
|
|
2897
|
+
}
|
|
2898
|
+
function AdaptiveTableCard({
|
|
2899
|
+
row,
|
|
2900
|
+
table,
|
|
2901
|
+
rowIndex,
|
|
2902
|
+
visibleColumns,
|
|
2903
|
+
layout,
|
|
2904
|
+
clickable
|
|
2905
|
+
}) {
|
|
2906
|
+
const { cells, primaryCell, secondaryCells } = getAdaptiveCells(row, visibleColumns, layout);
|
|
2907
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2908
|
+
"article",
|
|
2909
|
+
{
|
|
2910
|
+
className: "yable-adaptive-card",
|
|
2911
|
+
role: "row",
|
|
2912
|
+
"data-selected": row.getIsSelected() || void 0,
|
|
2913
|
+
"data-expanded": row.getIsExpanded() || void 0,
|
|
2914
|
+
"data-clickable": clickable || void 0,
|
|
2915
|
+
"data-row-id": row.id,
|
|
2916
|
+
"data-row-index": rowIndex,
|
|
2917
|
+
"aria-selected": table.options.enableRowSelection ? row.getIsSelected() : void 0,
|
|
2918
|
+
onClick: (e) => {
|
|
2919
|
+
if (table.options.enableRowClickSelection && row.getCanSelect() && !isInteractiveClickTarget3(e.target)) {
|
|
2920
|
+
row.toggleSelected();
|
|
2921
|
+
}
|
|
2922
|
+
if (clickable) emitRowEvent(table, "row:click", row, e.nativeEvent);
|
|
2923
|
+
},
|
|
2924
|
+
onDoubleClick: (e) => emitRowEvent(table, "row:dblclick", row, e.nativeEvent),
|
|
2925
|
+
onContextMenu: (e) => emitRowEvent(table, "row:contextmenu", row, e.nativeEvent),
|
|
2926
|
+
children: layout.renderCard ? layout.renderCard({
|
|
2927
|
+
table,
|
|
2928
|
+
row,
|
|
2929
|
+
rowIndex,
|
|
2930
|
+
cells,
|
|
2931
|
+
primaryCell,
|
|
2932
|
+
secondaryCells,
|
|
2933
|
+
visibleColumns
|
|
2934
|
+
}) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2935
|
+
primaryCell && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "yable-adaptive-card-header", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "yable-adaptive-card-title", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2936
|
+
AdaptiveTableCardCell,
|
|
2937
|
+
{
|
|
2938
|
+
cell: primaryCell,
|
|
2939
|
+
table,
|
|
2940
|
+
rowIndex,
|
|
2941
|
+
columnIndex: 0,
|
|
2942
|
+
primary: true
|
|
2943
|
+
}
|
|
2944
|
+
) }) }),
|
|
2945
|
+
secondaryCells.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "yable-adaptive-card-fields", children: secondaryCells.map((cell, index) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
2946
|
+
AdaptiveTableCardCell,
|
|
2947
|
+
{
|
|
2948
|
+
cell,
|
|
2949
|
+
table,
|
|
2950
|
+
rowIndex,
|
|
2951
|
+
columnIndex: index + 1
|
|
2952
|
+
},
|
|
2953
|
+
cell.id
|
|
2954
|
+
)) })
|
|
2955
|
+
] })
|
|
2956
|
+
}
|
|
2957
|
+
);
|
|
2958
|
+
}
|
|
2959
|
+
function emitRowEvent(table, event, row, originalEvent) {
|
|
2960
|
+
table.events.emit(event, {
|
|
2961
|
+
row,
|
|
2962
|
+
cells: row.getAllCells(),
|
|
2963
|
+
originalEvent
|
|
2964
|
+
});
|
|
2965
|
+
}
|
|
2966
|
+
function emitCellEvent(table, event, cell, originalEvent) {
|
|
2967
|
+
table.events.emit(event, {
|
|
2968
|
+
cell,
|
|
2969
|
+
row: cell.row,
|
|
2970
|
+
column: cell.column,
|
|
2971
|
+
originalEvent
|
|
2972
|
+
});
|
|
2973
|
+
}
|
|
2974
|
+
function AdaptiveTableCardCell({
|
|
2975
|
+
cell,
|
|
2976
|
+
table,
|
|
2977
|
+
rowIndex,
|
|
2978
|
+
columnIndex,
|
|
2979
|
+
primary
|
|
2980
|
+
}) {
|
|
2981
|
+
const column = cell.column;
|
|
2982
|
+
const isEditing = cell.getIsEditing();
|
|
2983
|
+
const isAlwaysEditable = cell.getIsAlwaysEditable();
|
|
2984
|
+
const cellStatus = table.getCellStatus(cell.row.id, column.id);
|
|
2985
|
+
const cellErrorMessage = table.getCellErrorMessage(cell.row.id, column.id);
|
|
2986
|
+
const cellConflictWith = table.getCellConflictWith(cell.row.id, column.id);
|
|
2987
|
+
const content = renderCellContent(cell, table);
|
|
2988
|
+
const header = column.columnDef.header;
|
|
2989
|
+
const label = typeof header === "string" ? header : column.id;
|
|
2990
|
+
return /* @__PURE__ */ jsxRuntime.jsx(CellErrorBoundary, { resetKeys: [cell.getValue(), cellStatus], children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2991
|
+
"div",
|
|
2992
|
+
{
|
|
2993
|
+
className: primary ? "yable-adaptive-card-primary" : "yable-adaptive-card-cell",
|
|
2994
|
+
"data-column-id": column.id,
|
|
2995
|
+
"data-cell-status": cellStatus !== "idle" ? cellStatus : void 0,
|
|
2996
|
+
"data-row-index": rowIndex,
|
|
2997
|
+
"data-column-index": columnIndex,
|
|
2998
|
+
role: "gridcell",
|
|
2999
|
+
"aria-colindex": columnIndex + 1,
|
|
3000
|
+
onClick: (e) => {
|
|
3001
|
+
if (cell.row.getIsGrouped()) return;
|
|
3002
|
+
emitCellEvent(table, "cell:click", cell, e.nativeEvent);
|
|
3003
|
+
if (yableCore.canCellEnterEditMode(table, cell.row, column) && !isAlwaysEditable && !isEditing && !e.shiftKey && !e.metaKey && !e.ctrlKey) {
|
|
3004
|
+
table.startEditing(cell.row.id, column.id);
|
|
3005
|
+
}
|
|
3006
|
+
},
|
|
3007
|
+
onDoubleClick: (e) => emitCellEvent(table, "cell:dblclick", cell, e.nativeEvent),
|
|
3008
|
+
onContextMenu: (e) => emitCellEvent(table, "cell:contextmenu", cell, e.nativeEvent),
|
|
3009
|
+
children: [
|
|
3010
|
+
!primary && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "yable-adaptive-card-label", children: label }),
|
|
3011
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "yable-adaptive-card-value", children: [
|
|
3012
|
+
content,
|
|
3013
|
+
cellStatus === "error" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3014
|
+
CellStatusBadge,
|
|
3015
|
+
{
|
|
3016
|
+
status: "error",
|
|
3017
|
+
message: cellErrorMessage,
|
|
3018
|
+
onRetry: () => void table.retryCommit(cell.row.id, column.id),
|
|
3019
|
+
onDismiss: () => table.dismissCommit(cell.row.id, column.id)
|
|
3020
|
+
}
|
|
3021
|
+
),
|
|
3022
|
+
cellStatus === "conflict" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3023
|
+
CellStatusBadge,
|
|
3024
|
+
{
|
|
3025
|
+
status: "conflict",
|
|
3026
|
+
conflictWith: cellConflictWith,
|
|
3027
|
+
onRetry: () => void table.retryCommit(cell.row.id, column.id),
|
|
3028
|
+
onDismiss: () => table.dismissCommit(cell.row.id, column.id)
|
|
3029
|
+
}
|
|
3030
|
+
)
|
|
3031
|
+
] })
|
|
3032
|
+
]
|
|
3033
|
+
}
|
|
3034
|
+
) });
|
|
3035
|
+
}
|
|
3036
|
+
function getAdaptiveCells(row, visibleColumns, layout) {
|
|
3037
|
+
const hidden = new Set(layout.hiddenColumnIds ?? []);
|
|
3038
|
+
const allCellsByColumn = new Map(row.getAllCells().map((cell) => [cell.column.id, cell]));
|
|
3039
|
+
const visibleCells = [];
|
|
3040
|
+
for (const column of visibleColumns) {
|
|
3041
|
+
if (hidden.has(column.id)) continue;
|
|
3042
|
+
const cell = allCellsByColumn.get(column.id);
|
|
3043
|
+
if (cell) visibleCells.push(cell);
|
|
3044
|
+
}
|
|
3045
|
+
const cellsByColumn = new Map(visibleCells.map((cell) => [cell.column.id, cell]));
|
|
3046
|
+
const primaryCell = (layout.primaryColumnId ? cellsByColumn.get(layout.primaryColumnId) : void 0) ?? visibleCells[0];
|
|
3047
|
+
const primaryColumnId = primaryCell?.column.id;
|
|
3048
|
+
let secondaryCells;
|
|
3049
|
+
if (layout.secondaryColumnIds) {
|
|
3050
|
+
secondaryCells = [];
|
|
3051
|
+
for (const columnId of layout.secondaryColumnIds) {
|
|
3052
|
+
if (hidden.has(columnId) || columnId === primaryColumnId) continue;
|
|
3053
|
+
const cell = cellsByColumn.get(columnId);
|
|
3054
|
+
if (cell) secondaryCells.push(cell);
|
|
3055
|
+
}
|
|
3056
|
+
} else {
|
|
3057
|
+
secondaryCells = visibleCells.filter((cell) => cell.column.id !== primaryColumnId);
|
|
3058
|
+
if (secondaryCells.length > layout.maxSecondaryColumns) {
|
|
3059
|
+
secondaryCells = secondaryCells.slice(0, layout.maxSecondaryColumns);
|
|
3060
|
+
}
|
|
3061
|
+
}
|
|
3062
|
+
return {
|
|
3063
|
+
cells: visibleCells,
|
|
3064
|
+
primaryCell,
|
|
3065
|
+
secondaryCells
|
|
3066
|
+
};
|
|
3067
|
+
}
|
|
3068
|
+
function isInteractiveClickTarget3(target) {
|
|
3069
|
+
if (!(target instanceof HTMLElement)) return false;
|
|
3070
|
+
return Boolean(
|
|
3071
|
+
target.closest('input, textarea, select, button, a[href], [contenteditable="true"]')
|
|
3072
|
+
);
|
|
3073
|
+
}
|
|
2839
3074
|
function TableFooter({ table }) {
|
|
2840
3075
|
const footerGroups = table.getFooterGroups();
|
|
2841
3076
|
if (!footerGroups.length) return null;
|
|
@@ -4163,6 +4398,7 @@ function Table({
|
|
|
4163
4398
|
floatingFilters,
|
|
4164
4399
|
columnVirtualization,
|
|
4165
4400
|
columnVirtualizationOverscan,
|
|
4401
|
+
adaptiveLayout: adaptiveLayoutProp,
|
|
4166
4402
|
ariaLabel: ariaLabelProp,
|
|
4167
4403
|
...rest
|
|
4168
4404
|
}) {
|
|
@@ -4188,6 +4424,7 @@ function Table({
|
|
|
4188
4424
|
const resolvedFloatingFilters = floatingFilters ?? profileTableProps?.floatingFilters;
|
|
4189
4425
|
const resolvedColumnVirtualization = columnVirtualization ?? profileTableProps?.columnVirtualization;
|
|
4190
4426
|
const resolvedColumnVirtualizationOverscan = columnVirtualizationOverscan ?? profileTableProps?.columnVirtualizationOverscan;
|
|
4427
|
+
const resolvedAdaptiveLayout = adaptiveLayoutProp ?? profileTableProps?.adaptiveLayout ?? providerTableProps?.adaptiveLayout;
|
|
4191
4428
|
const [sidebarOpen, setSidebarOpen] = React4.useState(false);
|
|
4192
4429
|
const [sidebarPanel, setSidebarPanel] = React4.useState(
|
|
4193
4430
|
resolvedDefaultSidebarPanel ?? "columns"
|
|
@@ -4195,6 +4432,11 @@ function Table({
|
|
|
4195
4432
|
const containerRef = React4.useRef(null);
|
|
4196
4433
|
const horizontalScrollRef = React4.useRef(null);
|
|
4197
4434
|
const isRtl = direction === "rtl";
|
|
4435
|
+
const adaptiveLayout = React4.useMemo(
|
|
4436
|
+
() => normalizeAdaptiveLayout(resolvedAdaptiveLayout),
|
|
4437
|
+
[resolvedAdaptiveLayout]
|
|
4438
|
+
);
|
|
4439
|
+
const adaptiveLayoutActive = useAdaptiveLayoutActive(containerRef, adaptiveLayout);
|
|
4198
4440
|
const classNames = [
|
|
4199
4441
|
"yable",
|
|
4200
4442
|
theme && `yable-theme-${theme}`,
|
|
@@ -4205,6 +4447,8 @@ function Table({
|
|
|
4205
4447
|
loading && "yable-loading",
|
|
4206
4448
|
isRtl && "yable--rtl",
|
|
4207
4449
|
sidebarOpen && "yable--sidebar-open",
|
|
4450
|
+
adaptiveLayout && adaptiveLayout.mode !== "table" && "yable--adaptive-layout",
|
|
4451
|
+
adaptiveLayoutActive && "yable--adaptive-cards-active",
|
|
4208
4452
|
className
|
|
4209
4453
|
].filter(Boolean).join(" ");
|
|
4210
4454
|
const rows = table.getRowModel().rows;
|
|
@@ -4214,7 +4458,7 @@ function Table({
|
|
|
4214
4458
|
const allVisibleColumns = table.getVisibleLeafColumns();
|
|
4215
4459
|
const hasPinnedColumns = table.getLeftVisibleLeafColumns().length > 0 || table.getRightVisibleLeafColumns().length > 0;
|
|
4216
4460
|
const hasGroupedHeaders = table.getHeaderGroups().length > 1;
|
|
4217
|
-
const canVirtualizeColumns = Boolean(resolvedColumnVirtualization) && !hasPinnedColumns && !hasGroupedHeaders && allVisibleColumns.length > 0;
|
|
4461
|
+
const canVirtualizeColumns = !adaptiveLayoutActive && Boolean(resolvedColumnVirtualization) && !hasPinnedColumns && !hasGroupedHeaders && allVisibleColumns.length > 0;
|
|
4218
4462
|
const allVisibleColumnSizeSignature = allVisibleColumns.map((column) => `${column.id}:${column.getSize()}`).join("|");
|
|
4219
4463
|
const columnVirtualState = useColumnVirtualization({
|
|
4220
4464
|
containerRef: horizontalScrollRef,
|
|
@@ -4330,7 +4574,7 @@ function Table({
|
|
|
4330
4574
|
columnVirtualState.startOffset,
|
|
4331
4575
|
visibleColumnTotalSize
|
|
4332
4576
|
]);
|
|
4333
|
-
const
|
|
4577
|
+
const desktopTableNode = /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4334
4578
|
"table",
|
|
4335
4579
|
{
|
|
4336
4580
|
className: "yable-table",
|
|
@@ -4352,6 +4596,14 @@ function Table({
|
|
|
4352
4596
|
]
|
|
4353
4597
|
}
|
|
4354
4598
|
);
|
|
4599
|
+
const tableNode = adaptiveLayoutActive && adaptiveLayout ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
4600
|
+
AdaptiveTableCards,
|
|
4601
|
+
{
|
|
4602
|
+
table,
|
|
4603
|
+
layout: adaptiveLayout,
|
|
4604
|
+
clickableRows: resolvedClickableRows
|
|
4605
|
+
}
|
|
4606
|
+
) : desktopTableNode;
|
|
4355
4607
|
return /* @__PURE__ */ jsxRuntime.jsx(TableProvider, { value: table, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4356
4608
|
"div",
|
|
4357
4609
|
{
|
|
@@ -4367,7 +4619,7 @@ function Table({
|
|
|
4367
4619
|
...rest,
|
|
4368
4620
|
children: [
|
|
4369
4621
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "yable-main", children: [
|
|
4370
|
-
showColumnVirtualizationShell ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
4622
|
+
showColumnVirtualizationShell && !adaptiveLayoutActive ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
4371
4623
|
"div",
|
|
4372
4624
|
{
|
|
4373
4625
|
ref: horizontalScrollRef,
|
|
@@ -4483,6 +4735,58 @@ function Table({
|
|
|
4483
4735
|
}
|
|
4484
4736
|
) });
|
|
4485
4737
|
}
|
|
4738
|
+
var DEFAULT_ADAPTIVE_BREAKPOINT = 720;
|
|
4739
|
+
var DEFAULT_ADAPTIVE_SECONDARY_COLUMNS = 8;
|
|
4740
|
+
function normalizeAdaptiveLayout(layout) {
|
|
4741
|
+
if (!layout) return null;
|
|
4742
|
+
if (layout === true) {
|
|
4743
|
+
return {
|
|
4744
|
+
mode: "auto",
|
|
4745
|
+
breakpoint: DEFAULT_ADAPTIVE_BREAKPOINT,
|
|
4746
|
+
maxSecondaryColumns: DEFAULT_ADAPTIVE_SECONDARY_COLUMNS
|
|
4747
|
+
};
|
|
4748
|
+
}
|
|
4749
|
+
return {
|
|
4750
|
+
mode: layout.mode ?? "auto",
|
|
4751
|
+
breakpoint: layout.breakpoint ?? DEFAULT_ADAPTIVE_BREAKPOINT,
|
|
4752
|
+
primaryColumnId: layout.primaryColumnId,
|
|
4753
|
+
secondaryColumnIds: layout.secondaryColumnIds,
|
|
4754
|
+
hiddenColumnIds: layout.hiddenColumnIds,
|
|
4755
|
+
maxSecondaryColumns: layout.maxSecondaryColumns ?? DEFAULT_ADAPTIVE_SECONDARY_COLUMNS,
|
|
4756
|
+
renderCard: layout.renderCard
|
|
4757
|
+
};
|
|
4758
|
+
}
|
|
4759
|
+
function useAdaptiveLayoutActive(containerRef, layout) {
|
|
4760
|
+
const [active, setActive] = React4.useState(() => layout?.mode === "cards");
|
|
4761
|
+
React4.useEffect(() => {
|
|
4762
|
+
if (!layout) {
|
|
4763
|
+
setActive(false);
|
|
4764
|
+
return;
|
|
4765
|
+
}
|
|
4766
|
+
if (layout.mode === "cards" || layout.mode === "table") {
|
|
4767
|
+
setActive(layout.mode === "cards");
|
|
4768
|
+
return;
|
|
4769
|
+
}
|
|
4770
|
+
const node = containerRef.current;
|
|
4771
|
+
if (!node) return;
|
|
4772
|
+
const update = (width) => {
|
|
4773
|
+
setActive(width <= layout.breakpoint);
|
|
4774
|
+
};
|
|
4775
|
+
update(node.getBoundingClientRect().width || node.clientWidth);
|
|
4776
|
+
if (typeof ResizeObserver === "undefined") {
|
|
4777
|
+
const handleResize = () => update(node.getBoundingClientRect().width || node.clientWidth);
|
|
4778
|
+
window.addEventListener("resize", handleResize);
|
|
4779
|
+
return () => window.removeEventListener("resize", handleResize);
|
|
4780
|
+
}
|
|
4781
|
+
const observer = new ResizeObserver((entries) => {
|
|
4782
|
+
const width = entries[0]?.contentRect.width ?? node.getBoundingClientRect().width;
|
|
4783
|
+
update(width);
|
|
4784
|
+
});
|
|
4785
|
+
observer.observe(node);
|
|
4786
|
+
return () => observer.disconnect();
|
|
4787
|
+
}, [containerRef, layout]);
|
|
4788
|
+
return active;
|
|
4789
|
+
}
|
|
4486
4790
|
function ChevronLeftIcon() {
|
|
4487
4791
|
return /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M8.5 3L4.5 7L8.5 11", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) });
|
|
4488
4792
|
}
|