@syuttechnologies/layout 1.0.2 → 1.0.21
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 +536 -0
- package/dist/components/ChangePasswordModal.d.ts.map +1 -1
- package/dist/components/ChangePasswordModal.js +22 -11
- package/dist/components/EnterpriseLayout.d.ts.map +1 -1
- package/dist/components/EnterpriseLayout.js +21 -6
- package/dist/components/ui/ActionMenu/ActionMenu.d.ts +52 -0
- package/dist/components/ui/ActionMenu/ActionMenu.d.ts.map +1 -0
- package/dist/components/ui/ActionMenu/ActionMenu.js +116 -0
- package/dist/components/ui/ActionMenu/index.d.ts +3 -0
- package/dist/components/ui/ActionMenu/index.d.ts.map +1 -0
- package/dist/components/ui/ActionMenu/index.js +2 -0
- package/dist/components/ui/ModuleHeader/ModuleHeader.d.ts +90 -0
- package/dist/components/ui/ModuleHeader/ModuleHeader.d.ts.map +1 -0
- package/dist/components/ui/ModuleHeader/ModuleHeader.js +433 -0
- package/dist/components/ui/ModuleHeader/index.d.ts +3 -0
- package/dist/components/ui/ModuleHeader/index.d.ts.map +1 -0
- package/dist/components/ui/ModuleHeader/index.js +1 -0
- package/dist/components/ui/SyutGrid/SyutGrid.d.ts +74 -0
- package/dist/components/ui/SyutGrid/SyutGrid.d.ts.map +1 -0
- package/dist/components/ui/SyutGrid/SyutGrid.js +306 -0
- package/dist/components/ui/SyutGrid/index.d.ts +3 -0
- package/dist/components/ui/SyutGrid/index.d.ts.map +1 -0
- package/dist/components/ui/SyutGrid/index.js +2 -0
- package/dist/components/ui/SyutSelect/SyutSelectUnified.d.ts +128 -0
- package/dist/components/ui/SyutSelect/SyutSelectUnified.d.ts.map +1 -0
- package/dist/components/ui/SyutSelect/SyutSelectUnified.js +679 -0
- package/dist/components/ui/SyutSelect/index.d.ts +3 -0
- package/dist/components/ui/SyutSelect/index.d.ts.map +1 -0
- package/dist/components/ui/SyutSelect/index.js +2 -0
- package/dist/icon-collection/icon-systems.d.ts +89 -0
- package/dist/icon-collection/icon-systems.d.ts.map +1 -0
- package/dist/icon-collection/icon-systems.js +70 -0
- package/dist/icon-collection/index.d.ts +4 -0
- package/dist/icon-collection/index.d.ts.map +1 -0
- package/dist/icon-collection/index.js +8 -0
- package/dist/index.d.ts +12 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +19 -1
- package/package.json +9 -4
- package/src/components/ChangePasswordModal.tsx +26 -14
- package/src/components/EnterpriseLayout.tsx +23 -8
- package/src/components/ui/ActionMenu/ActionMenu.tsx +222 -0
- package/src/components/ui/ActionMenu/index.ts +2 -0
- package/src/components/ui/ModuleHeader/ModuleHeader.tsx +722 -0
- package/src/components/ui/ModuleHeader/index.ts +9 -0
- package/src/components/ui/SyutGrid/SyutGrid.tsx +483 -0
- package/src/components/ui/SyutGrid/index.ts +2 -0
- package/src/components/ui/SyutSelect/SyutSelectUnified.tsx +1115 -0
- package/src/components/ui/SyutSelect/index.ts +3 -0
- package/src/icon-collection/icon-systems.tsx +464 -0
- package/src/icon-collection/index.ts +13 -0
- package/src/index.ts +47 -1
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useMemo, useState, useCallback, useEffect } from 'react';
|
|
3
|
+
import { useReactTable, getCoreRowModel, getSortedRowModel, getFilteredRowModel, getPaginationRowModel, flexRender, } from '@tanstack/react-table';
|
|
4
|
+
import IconSystem from '../../../icon-collection/icon-systems';
|
|
5
|
+
import { ActionMenu } from '../ActionMenu';
|
|
6
|
+
if (typeof document !== 'undefined') {
|
|
7
|
+
const styleId = 'syut-grid-styles';
|
|
8
|
+
if (!document.getElementById(styleId)) {
|
|
9
|
+
const style = document.createElement('style');
|
|
10
|
+
style.id = styleId;
|
|
11
|
+
style.textContent = `
|
|
12
|
+
.syut-grid-component { display: flex; flex-direction: column; height: 100%; font-family: inherit; }
|
|
13
|
+
.syut-grid-wrapper { flex: 1; overflow: auto; min-height: 0; border: 1px solid var(--border-color, #e2e8f0); border-radius: 8px 8px 0 0; }
|
|
14
|
+
.syut-grid { width: 100%; border-collapse: collapse; font-size: 0.875rem; background: var(--bg-primary, #ffffff); }
|
|
15
|
+
.syut-grid thead { position: sticky; top: 0; z-index: 3; }
|
|
16
|
+
.syut-grid th { padding: 0.75rem 1rem; text-align: left; font-weight: 600; color: var(--text-primary, #1e293b); background: var(--bg-secondary, #f8fafc); border-bottom: 2px solid var(--border-color, #e2e8f0); white-space: nowrap; user-select: none; }
|
|
17
|
+
.syut-grid th.frozen-column { background: var(--bg-secondary, #f8fafc); box-shadow: -2px 0 4px rgba(0, 0, 0, 0.1); z-index: 4; }
|
|
18
|
+
.syut-grid td { padding: 0.625rem 1rem; color: var(--text-primary, #1e293b); border-bottom: 1px solid var(--border-color, #e2e8f0); background: var(--bg-primary, #ffffff); }
|
|
19
|
+
.syut-grid td.frozen-column { background: var(--bg-primary, #ffffff); box-shadow: -2px 0 4px rgba(0, 0, 0, 0.1); z-index: 1; }
|
|
20
|
+
.syut-grid tbody tr:hover td { background: var(--bg-secondary, #f8fafc); }
|
|
21
|
+
.syut-grid tbody tr:hover td.frozen-column { background: var(--bg-secondary, #f8fafc); }
|
|
22
|
+
.syut-grid th.action-column, .syut-grid td.action-column { text-align: center; width: 80px; }
|
|
23
|
+
.syut-grid .row-select, .syut-grid .row-select-all { width: 16px; height: 16px; cursor: pointer; accent-color: var(--primary, #3b82f6); }
|
|
24
|
+
.syut-grid-component .pagination-footer { display: flex; align-items: center; justify-content: space-between; padding: 0.75rem 1rem; background: var(--bg-secondary, #f8fafc); border: 1px solid var(--border-color, #e2e8f0); border-top: none; border-radius: 0 0 8px 8px; flex-shrink: 0; gap: 0.5rem; flex-wrap: wrap; }
|
|
25
|
+
.syut-grid-component .pagination-info { font-size: 0.85rem; color: var(--text-muted, #64748b); white-space: nowrap; }
|
|
26
|
+
.syut-grid-component .pagination-controls { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
|
|
27
|
+
.syut-grid-component .pagination-controls select { padding: 0.375rem 0.5rem; border-radius: 0.375rem; border: 1px solid var(--border-color, #e2e8f0); font-size: 0.85rem; background: var(--bg-primary, #ffffff); color: var(--text-primary, #1e293b); cursor: pointer; }
|
|
28
|
+
.syut-grid-component .page-btn { display: inline-flex; align-items: center; justify-content: center; padding: 0.375rem 0.5rem; border: 1px solid var(--border-color, #e2e8f0); border-radius: 0.375rem; background: var(--bg-primary, #ffffff); color: var(--text-primary, #1e293b); cursor: pointer; transition: all 0.15s ease; }
|
|
29
|
+
.syut-grid-component .page-btn:hover:not(:disabled) { background: var(--bg-secondary, #f8fafc); border-color: var(--primary, #3b82f6); color: var(--primary, #3b82f6); }
|
|
30
|
+
.syut-grid-component .page-btn:disabled { opacity: 0.5; cursor: not-allowed; }
|
|
31
|
+
.syut-grid-component .page-info { padding: 0 0.75rem; font-size: 0.85rem; white-space: nowrap; }
|
|
32
|
+
.syut-grid-component .page-nav-buttons { display: flex; align-items: center; gap: 0.25rem; }
|
|
33
|
+
|
|
34
|
+
/* Mobile responsive styles for pagination footer */
|
|
35
|
+
@media (max-width: 768px) {
|
|
36
|
+
.syut-grid-component .pagination-footer {
|
|
37
|
+
flex-direction: column;
|
|
38
|
+
align-items: stretch;
|
|
39
|
+
padding: 0.625rem 0.75rem;
|
|
40
|
+
gap: 0.625rem;
|
|
41
|
+
}
|
|
42
|
+
.syut-grid-component .pagination-info {
|
|
43
|
+
text-align: center;
|
|
44
|
+
font-size: 0.8rem;
|
|
45
|
+
}
|
|
46
|
+
.syut-grid-component .pagination-controls {
|
|
47
|
+
justify-content: center;
|
|
48
|
+
gap: 0.375rem;
|
|
49
|
+
}
|
|
50
|
+
.syut-grid-component .pagination-controls select {
|
|
51
|
+
padding: 0.3rem 0.4rem;
|
|
52
|
+
font-size: 0.8rem;
|
|
53
|
+
margin-right: 0.5rem;
|
|
54
|
+
}
|
|
55
|
+
.syut-grid-component .page-btn {
|
|
56
|
+
padding: 0.3rem 0.4rem;
|
|
57
|
+
}
|
|
58
|
+
.syut-grid-component .page-info {
|
|
59
|
+
font-size: 0.8rem;
|
|
60
|
+
padding: 0 0.5rem;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
@media (max-width: 480px) {
|
|
65
|
+
.syut-grid-component .pagination-footer {
|
|
66
|
+
padding: 0.5rem;
|
|
67
|
+
gap: 0.5rem;
|
|
68
|
+
}
|
|
69
|
+
.syut-grid-component .pagination-info {
|
|
70
|
+
font-size: 0.75rem;
|
|
71
|
+
}
|
|
72
|
+
.syut-grid-component .pagination-controls {
|
|
73
|
+
flex-wrap: wrap;
|
|
74
|
+
justify-content: center;
|
|
75
|
+
}
|
|
76
|
+
.syut-grid-component .pagination-controls select {
|
|
77
|
+
font-size: 0.75rem;
|
|
78
|
+
margin-right: 0;
|
|
79
|
+
margin-bottom: 0.25rem;
|
|
80
|
+
}
|
|
81
|
+
.syut-grid-component .page-info {
|
|
82
|
+
font-size: 0.75rem;
|
|
83
|
+
padding: 0 0.25rem;
|
|
84
|
+
order: -1;
|
|
85
|
+
width: 100%;
|
|
86
|
+
text-align: center;
|
|
87
|
+
margin-bottom: 0.25rem;
|
|
88
|
+
}
|
|
89
|
+
.syut-grid-component .page-nav-buttons {
|
|
90
|
+
width: 100%;
|
|
91
|
+
justify-content: center;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
`;
|
|
95
|
+
document.head.appendChild(style);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
function ColumnFilter({ column, placeholder }) {
|
|
99
|
+
const columnFilterValue = column.getFilterValue();
|
|
100
|
+
return (_jsx("input", { type: "text", value: columnFilterValue ?? '', onChange: (e) => column.setFilterValue(e.target.value), placeholder: placeholder || 'Filter...', onClick: (e) => e.stopPropagation(), style: { width: '100%', padding: '0.25rem 0.5rem', fontSize: '0.75rem', border: '1px solid var(--border-color)', borderRadius: '0.25rem', marginTop: '0.375rem', background: 'var(--bg-primary)' } }));
|
|
101
|
+
}
|
|
102
|
+
export function SyutGrid({ data: dataProp, columns, enableRowSelection: enableRowSelectionProp = false, enablePagination: enablePaginationProp, pageSizeOptions: pageSizeOptionsProp = [10, 25, 50, 100], defaultPageSize: defaultPageSizeProp = 10, enableSorting = true, enableColumnFilters = false, rowActions, emptyMessage: emptyMessageProp = 'No data found', onSelectionChange, isLoading: isLoadingProp = false, className = '', frozenLeftColumns = [], frozenRightColumns = [], visibleColumns, selectable, selectedRows: selectedRowsProp, pagination: paginationConfig,
|
|
103
|
+
// Legacy props
|
|
104
|
+
dataSource, rowSelection: rowSelectionConfig, loading, emptyText, }) {
|
|
105
|
+
// Handle legacy props
|
|
106
|
+
const data = dataProp || dataSource || [];
|
|
107
|
+
const isLoading = loading ?? isLoadingProp;
|
|
108
|
+
const emptyMessage = emptyText || emptyMessageProp;
|
|
109
|
+
const enableRowSelection = selectable ?? (rowSelectionConfig !== undefined ? true : enableRowSelectionProp);
|
|
110
|
+
const enablePagination = paginationConfig?.enabled ?? enablePaginationProp ?? true;
|
|
111
|
+
const pageSizeOptions = paginationConfig?.pageSizeOptions ?? pageSizeOptionsProp;
|
|
112
|
+
const defaultPageSize = paginationConfig?.pageSize ?? defaultPageSizeProp;
|
|
113
|
+
// Get initial selected rows from either new or legacy prop
|
|
114
|
+
const initialSelectedRows = selectedRowsProp || rowSelectionConfig?.selectedRowKeys || [];
|
|
115
|
+
const [sorting, setSorting] = useState([]);
|
|
116
|
+
const [columnFilters, setColumnFilters] = useState([]);
|
|
117
|
+
const [rowSelection, setRowSelection] = useState(() => {
|
|
118
|
+
if (initialSelectedRows.length > 0) {
|
|
119
|
+
const selection = {};
|
|
120
|
+
initialSelectedRows.forEach(id => { selection[id] = true; });
|
|
121
|
+
return selection;
|
|
122
|
+
}
|
|
123
|
+
return {};
|
|
124
|
+
});
|
|
125
|
+
const [pagination, setPagination] = useState({ pageIndex: 0, pageSize: defaultPageSize });
|
|
126
|
+
useEffect(() => {
|
|
127
|
+
const selectedRows = selectedRowsProp || rowSelectionConfig?.selectedRowKeys;
|
|
128
|
+
if (selectedRows) {
|
|
129
|
+
const selection = {};
|
|
130
|
+
selectedRows.forEach(id => { selection[id] = true; });
|
|
131
|
+
setRowSelection(selection);
|
|
132
|
+
}
|
|
133
|
+
}, [selectedRowsProp, rowSelectionConfig?.selectedRowKeys]);
|
|
134
|
+
const normalizedColumns = useMemo(() => {
|
|
135
|
+
return columns.map(col => ({
|
|
136
|
+
...col,
|
|
137
|
+
id: col.id || col.key || '',
|
|
138
|
+
header: col.header || col.title || '',
|
|
139
|
+
// Use accessorKey, or dataIndex, or key as the accessor for getting cell values
|
|
140
|
+
accessorKey: col.accessorKey || col.dataIndex || col.key,
|
|
141
|
+
size: col.size || col.width,
|
|
142
|
+
enableSorting: col.enableSorting ?? col.sortable ?? true,
|
|
143
|
+
}));
|
|
144
|
+
}, [columns]);
|
|
145
|
+
const columnVisibility = useMemo(() => {
|
|
146
|
+
const legacyVisibility = {};
|
|
147
|
+
normalizedColumns.forEach(col => {
|
|
148
|
+
if (col.visible !== undefined)
|
|
149
|
+
legacyVisibility[col.id] = col.visible;
|
|
150
|
+
});
|
|
151
|
+
if (Object.keys(legacyVisibility).length > 0)
|
|
152
|
+
return legacyVisibility;
|
|
153
|
+
if (!visibleColumns)
|
|
154
|
+
return {};
|
|
155
|
+
const visibility = {};
|
|
156
|
+
const allColumnIds = [...(enableRowSelection ? ['select'] : []), ...normalizedColumns.map(col => col.id), ...(rowActions ? ['actions'] : [])];
|
|
157
|
+
allColumnIds.forEach(colId => { visibility[colId] = visibleColumns.includes(colId); });
|
|
158
|
+
return visibility;
|
|
159
|
+
}, [visibleColumns, normalizedColumns, enableRowSelection, rowActions]);
|
|
160
|
+
const frozenColumnMap = useMemo(() => {
|
|
161
|
+
const map = {};
|
|
162
|
+
const getColumnWidth = (colId) => {
|
|
163
|
+
if (colId === 'select')
|
|
164
|
+
return 50;
|
|
165
|
+
if (colId === 'actions')
|
|
166
|
+
return 80;
|
|
167
|
+
const col = normalizedColumns.find(c => c.id === colId);
|
|
168
|
+
return col?.size || 150;
|
|
169
|
+
};
|
|
170
|
+
let leftOffset = 0;
|
|
171
|
+
frozenLeftColumns.forEach((colId) => { map[colId] = { frozen: 'left', leftOffset, rightOffset: 0 }; leftOffset += getColumnWidth(colId); });
|
|
172
|
+
let rightOffset = 0;
|
|
173
|
+
[...frozenRightColumns].reverse().forEach((colId) => { map[colId] = { frozen: 'right', leftOffset: 0, rightOffset }; rightOffset += getColumnWidth(colId); });
|
|
174
|
+
return map;
|
|
175
|
+
}, [normalizedColumns, frozenLeftColumns, frozenRightColumns]);
|
|
176
|
+
const getStickyStyles = useCallback((columnId) => {
|
|
177
|
+
const frozenInfo = frozenColumnMap[columnId];
|
|
178
|
+
if (!frozenInfo || !frozenInfo.frozen)
|
|
179
|
+
return {};
|
|
180
|
+
return { position: 'sticky', [frozenInfo.frozen]: frozenInfo.frozen === 'left' ? frozenInfo.leftOffset : frozenInfo.rightOffset, zIndex: 1 };
|
|
181
|
+
}, [frozenColumnMap]);
|
|
182
|
+
const tableColumns = useMemo(() => {
|
|
183
|
+
const cols = [];
|
|
184
|
+
if (enableRowSelection) {
|
|
185
|
+
cols.push({
|
|
186
|
+
id: 'select',
|
|
187
|
+
header: ({ table }) => (_jsx("input", { type: "checkbox", className: "row-select-all", checked: table.getIsAllRowsSelected(), onChange: table.getToggleAllRowsSelectedHandler() })),
|
|
188
|
+
cell: ({ row }) => (_jsx("input", { type: "checkbox", className: "row-select", checked: row.getIsSelected(), onChange: row.getToggleSelectedHandler() })),
|
|
189
|
+
size: 50,
|
|
190
|
+
enableColumnFilter: false,
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
normalizedColumns.forEach((col) => {
|
|
194
|
+
const canFilter = enableColumnFilters && col.enableFiltering !== false;
|
|
195
|
+
let cellRenderer;
|
|
196
|
+
if (col.cell) {
|
|
197
|
+
cellRenderer = (info) => col.cell({ row: info.row, getValue: info.getValue });
|
|
198
|
+
}
|
|
199
|
+
else if (col.render) {
|
|
200
|
+
// Support both render signatures:
|
|
201
|
+
// 1. render(value, row) - value first, row second (when column has accessor)
|
|
202
|
+
// 2. render(row) - just the row object (when column has no accessor)
|
|
203
|
+
// We detect based on whether there's an accessor key defined
|
|
204
|
+
const hasAccessor = col.accessorKey || col.dataIndex || col.key;
|
|
205
|
+
cellRenderer = (info) => {
|
|
206
|
+
if (hasAccessor) {
|
|
207
|
+
// Column has accessor - pass value and row (legacy pattern)
|
|
208
|
+
return col.render(info.getValue(), info.row.original);
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
// No accessor - pass just the row object
|
|
212
|
+
return col.render(info.row.original);
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
else {
|
|
217
|
+
cellRenderer = (info) => info.getValue();
|
|
218
|
+
}
|
|
219
|
+
cols.push({
|
|
220
|
+
id: col.id,
|
|
221
|
+
accessorKey: col.accessorKey,
|
|
222
|
+
header: typeof col.header === 'string' ? ({ column }) => {
|
|
223
|
+
const headerText = col.header;
|
|
224
|
+
const isSortable = enableSorting && col.enableSorting !== false;
|
|
225
|
+
return (_jsxs("div", { children: [_jsxs("div", { style: { cursor: isSortable ? 'pointer' : 'default', display: 'flex', alignItems: 'center', gap: '4px' }, onClick: () => isSortable && column.toggleSorting(), children: [_jsx("span", { children: headerText }), isSortable && (_jsx("span", { children: column.getIsSorted() === 'asc' ? (_jsx(IconSystem.chevronUp, { size: 14 })) : column.getIsSorted() === 'desc' ? (_jsx(IconSystem.chevronDown, { size: 14 })) : (_jsx(IconSystem.chevronUp, { size: 14, style: { opacity: 0.3 } })) }))] }), canFilter && (_jsx(ColumnFilter, { column: column, placeholder: `Filter ${headerText}...` }))] }));
|
|
226
|
+
} : col.header,
|
|
227
|
+
cell: cellRenderer,
|
|
228
|
+
size: col.size,
|
|
229
|
+
enableSorting: enableSorting && col.enableSorting !== false,
|
|
230
|
+
enableColumnFilter: canFilter,
|
|
231
|
+
});
|
|
232
|
+
});
|
|
233
|
+
if (rowActions) {
|
|
234
|
+
cols.push({
|
|
235
|
+
id: 'actions',
|
|
236
|
+
header: 'Actions',
|
|
237
|
+
cell: ({ row }) => {
|
|
238
|
+
// Handle both patterns: function that returns items, or array of items with row-accepting onClick
|
|
239
|
+
let items;
|
|
240
|
+
if (typeof rowActions === 'function') {
|
|
241
|
+
// Function pattern - items are already processed
|
|
242
|
+
items = rowActions(row.original);
|
|
243
|
+
}
|
|
244
|
+
else {
|
|
245
|
+
// Array pattern - need to filter by isVisible and wrap onClick with row
|
|
246
|
+
items = rowActions
|
|
247
|
+
.filter(item => !item.isVisible || item.isVisible(row.original))
|
|
248
|
+
.map(item => ({
|
|
249
|
+
id: item.id,
|
|
250
|
+
label: item.label,
|
|
251
|
+
icon: item.icon,
|
|
252
|
+
variant: item.variant,
|
|
253
|
+
disabled: item.disabled,
|
|
254
|
+
onClick: () => item.onClick(row.original)
|
|
255
|
+
}));
|
|
256
|
+
}
|
|
257
|
+
return _jsx(ActionMenu, { items: items });
|
|
258
|
+
},
|
|
259
|
+
size: 80,
|
|
260
|
+
enableColumnFilter: false
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
return cols;
|
|
264
|
+
}, [normalizedColumns, enableRowSelection, enableSorting, enableColumnFilters, rowActions]);
|
|
265
|
+
const handleRowSelectionChange = useCallback((updaterOrValue) => {
|
|
266
|
+
setRowSelection((prev) => {
|
|
267
|
+
const newSelection = typeof updaterOrValue === 'function' ? updaterOrValue(prev) : updaterOrValue;
|
|
268
|
+
const selectedIds = Object.keys(newSelection).filter((key) => newSelection[key]);
|
|
269
|
+
// Call new API callback
|
|
270
|
+
if (onSelectionChange) {
|
|
271
|
+
onSelectionChange(selectedIds);
|
|
272
|
+
}
|
|
273
|
+
// Call legacy API callback
|
|
274
|
+
if (rowSelectionConfig?.onChange) {
|
|
275
|
+
rowSelectionConfig.onChange(selectedIds);
|
|
276
|
+
}
|
|
277
|
+
return newSelection;
|
|
278
|
+
});
|
|
279
|
+
}, [onSelectionChange, rowSelectionConfig]);
|
|
280
|
+
const table = useReactTable({
|
|
281
|
+
data,
|
|
282
|
+
columns: tableColumns,
|
|
283
|
+
state: { sorting, columnFilters, rowSelection, pagination, columnVisibility },
|
|
284
|
+
onSortingChange: setSorting,
|
|
285
|
+
onColumnFiltersChange: setColumnFilters,
|
|
286
|
+
onRowSelectionChange: handleRowSelectionChange,
|
|
287
|
+
onPaginationChange: setPagination,
|
|
288
|
+
getCoreRowModel: getCoreRowModel(),
|
|
289
|
+
getSortedRowModel: getSortedRowModel(),
|
|
290
|
+
getFilteredRowModel: getFilteredRowModel(),
|
|
291
|
+
getPaginationRowModel: enablePagination ? getPaginationRowModel() : undefined,
|
|
292
|
+
enableRowSelection,
|
|
293
|
+
getRowId: (row) => row.id,
|
|
294
|
+
});
|
|
295
|
+
return (_jsxs("div", { className: `syut-grid-component ${className}`, style: { display: 'flex', flexDirection: 'column', height: '100%' }, children: [_jsx("div", { className: "syut-grid-wrapper", style: { flex: 1, overflow: 'auto', minHeight: 0 }, children: _jsxs("table", { className: "syut-grid", children: [_jsx("thead", { children: table.getHeaderGroups().map((headerGroup) => (_jsx("tr", { children: headerGroup.headers.map((header) => {
|
|
296
|
+
const stickyStyles = getStickyStyles(header.id);
|
|
297
|
+
const isFrozen = !!frozenColumnMap[header.id];
|
|
298
|
+
return (_jsx("th", { style: { width: header.getSize() !== 150 ? header.getSize() : undefined, ...stickyStyles, ...(isFrozen && { zIndex: 4 }) }, className: `${header.id === 'actions' ? 'action-column' : ''} ${isFrozen ? 'frozen-column' : ''}`, children: header.isPlaceholder ? null : flexRender(header.column.columnDef.header, header.getContext()) }, header.id));
|
|
299
|
+
}) }, headerGroup.id))) }), _jsx("tbody", { children: isLoading ? (_jsx("tr", { children: _jsx("td", { colSpan: table.getAllColumns().length, style: { textAlign: 'center', padding: '2rem', color: 'var(--text-muted)' }, children: "Loading..." }) })) : table.getRowModel().rows.length === 0 ? (_jsx("tr", { children: _jsx("td", { colSpan: table.getAllColumns().length, style: { textAlign: 'center', padding: '2rem', color: 'var(--text-muted)' }, children: emptyMessage }) })) : (table.getRowModel().rows.map((row) => (_jsx("tr", { children: row.getVisibleCells().map((cell) => {
|
|
300
|
+
const stickyStyles = getStickyStyles(cell.column.id);
|
|
301
|
+
const isFrozen = !!frozenColumnMap[cell.column.id];
|
|
302
|
+
const isActionsColumn = cell.column.id === 'actions';
|
|
303
|
+
return (_jsx("td", { className: `${isActionsColumn ? 'action-column' : ''} ${isFrozen ? 'frozen-column' : ''}`, style: { ...stickyStyles, ...(isActionsColumn && { overflow: 'visible' }) }, children: flexRender(cell.column.columnDef.cell, cell.getContext()) }, cell.id));
|
|
304
|
+
}) }, row.id)))) })] }) }), enablePagination && (_jsxs("div", { className: "pagination-footer", children: [_jsxs("div", { className: "pagination-info", children: ["Showing ", table.getRowModel().rows.length, " of ", table.getFilteredRowModel().rows.length, " items", Object.keys(rowSelection).length > 0 && (_jsxs("span", { style: { marginLeft: '0.5rem', color: 'var(--primary)' }, children: ["(", Object.keys(rowSelection).length, " selected)"] }))] }), _jsxs("div", { className: "pagination-controls", children: [_jsx("select", { value: pagination.pageSize, onChange: (e) => table.setPageSize(Number(e.target.value)), children: pageSizeOptions.map((size) => (_jsxs("option", { value: size, children: [size, " / page"] }, size))) }), _jsxs("div", { className: "page-nav-buttons", children: [_jsxs("button", { className: "page-btn", onClick: () => table.firstPage(), disabled: !table.getCanPreviousPage(), title: "First page", children: [_jsx(IconSystem.chevronLeft, { size: 16 }), _jsx(IconSystem.chevronLeft, { size: 16, style: { marginLeft: '-8px' } })] }), _jsx("button", { className: "page-btn", onClick: () => table.previousPage(), disabled: !table.getCanPreviousPage(), title: "Previous page", children: _jsx(IconSystem.chevronLeft, { size: 16 }) }), _jsxs("span", { className: "page-info", children: ["Page ", table.getState().pagination.pageIndex + 1, " of ", table.getPageCount()] }), _jsx("button", { className: "page-btn", onClick: () => table.nextPage(), disabled: !table.getCanNextPage(), title: "Next page", children: _jsx(IconSystem.chevronRight, { size: 16 }) }), _jsxs("button", { className: "page-btn", onClick: () => table.lastPage(), disabled: !table.getCanNextPage(), title: "Last page", children: [_jsx(IconSystem.chevronRight, { size: 16 }), _jsx(IconSystem.chevronRight, { size: 16, style: { marginLeft: '-8px' } })] })] })] })] }))] }));
|
|
305
|
+
}
|
|
306
|
+
export default SyutGrid;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/ui/SyutGrid/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,KAAK,aAAa,EAAE,KAAK,cAAc,EAAE,MAAM,YAAY,CAAC;AAC/E,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export interface SelectOption {
|
|
3
|
+
value: string;
|
|
4
|
+
label: string;
|
|
5
|
+
isDisabled?: boolean;
|
|
6
|
+
[key: string]: any;
|
|
7
|
+
}
|
|
8
|
+
export interface SyutSelectUnifiedProps {
|
|
9
|
+
/** Unique identifier for the select */
|
|
10
|
+
id?: string;
|
|
11
|
+
/** Name attribute for form handling */
|
|
12
|
+
name?: string;
|
|
13
|
+
/** Options to display in the dropdown */
|
|
14
|
+
options?: SelectOption[];
|
|
15
|
+
/** Currently selected value(s) - string[] for multi, string for single */
|
|
16
|
+
value?: string | string[];
|
|
17
|
+
/** Callback when selection changes */
|
|
18
|
+
onChange?: (value: any) => void;
|
|
19
|
+
/** Placeholder text */
|
|
20
|
+
placeholder?: string;
|
|
21
|
+
/** Whether the select is disabled */
|
|
22
|
+
isDisabled?: boolean;
|
|
23
|
+
/** Whether the select is in loading state */
|
|
24
|
+
isLoading?: boolean;
|
|
25
|
+
/** Whether to allow multiple selections */
|
|
26
|
+
isMulti?: boolean;
|
|
27
|
+
/** Whether the select is searchable */
|
|
28
|
+
isSearchable?: boolean;
|
|
29
|
+
/** Legacy alias for isSearchable */
|
|
30
|
+
searchable?: boolean;
|
|
31
|
+
/** Whether the value can be cleared */
|
|
32
|
+
isClearable?: boolean;
|
|
33
|
+
/** Whether to allow creating new options */
|
|
34
|
+
isCreatable?: boolean;
|
|
35
|
+
/** Callback for creating new options */
|
|
36
|
+
onCreateOption?: (inputValue: string) => void;
|
|
37
|
+
/** Format for the create option label */
|
|
38
|
+
formatCreateLabel?: (inputValue: string) => React.ReactNode;
|
|
39
|
+
/** Whether to use async loading */
|
|
40
|
+
isAsync?: boolean;
|
|
41
|
+
/** Async function to load options */
|
|
42
|
+
loadOptions?: (inputValue: string, callback: (options: SelectOption[]) => void) => Promise<SelectOption[]> | void;
|
|
43
|
+
/** Default options to show before search (for async) */
|
|
44
|
+
defaultOptions?: boolean | SelectOption[];
|
|
45
|
+
/** Cache loaded options */
|
|
46
|
+
cacheOptions?: boolean;
|
|
47
|
+
/** Label for the select (optional) */
|
|
48
|
+
label?: string;
|
|
49
|
+
/** Error message to display */
|
|
50
|
+
error?: string;
|
|
51
|
+
/** Helper text below the select */
|
|
52
|
+
helperText?: string;
|
|
53
|
+
/** Whether the field is required */
|
|
54
|
+
required?: boolean;
|
|
55
|
+
/** Additional class name for the container */
|
|
56
|
+
className?: string;
|
|
57
|
+
/** Size variant */
|
|
58
|
+
size?: 'sm' | 'md' | 'lg';
|
|
59
|
+
/** Auto focus the select */
|
|
60
|
+
autoFocus?: boolean;
|
|
61
|
+
/** Menu placement */
|
|
62
|
+
menuPlacement?: 'auto' | 'top' | 'bottom';
|
|
63
|
+
/** Maximum height of dropdown menu */
|
|
64
|
+
maxMenuHeight?: number;
|
|
65
|
+
/**
|
|
66
|
+
* Variant style:
|
|
67
|
+
* - 'default': Uses react-select (tags for multi, dropdown for single)
|
|
68
|
+
* - 'checkbox': Custom checkbox-style multi-select with search and select all
|
|
69
|
+
*/
|
|
70
|
+
variant?: 'default' | 'checkbox';
|
|
71
|
+
/** Show select all option (only for checkbox variant) */
|
|
72
|
+
showSelectAll?: boolean;
|
|
73
|
+
/** Label for select all option */
|
|
74
|
+
selectAllLabel?: string;
|
|
75
|
+
/** Search placeholder (for checkbox variant) */
|
|
76
|
+
searchPlaceholder?: string;
|
|
77
|
+
/** No options message */
|
|
78
|
+
noOptionsMessage?: string;
|
|
79
|
+
/** Debounce delay in ms for async search (default: 300) */
|
|
80
|
+
debounceDelay?: number;
|
|
81
|
+
/** Minimum characters before triggering async search (default: 1) */
|
|
82
|
+
minSearchLength?: number;
|
|
83
|
+
/** Message to show while loading async results */
|
|
84
|
+
loadingMessage?: string;
|
|
85
|
+
/** Message to show when search query is too short */
|
|
86
|
+
minSearchMessage?: string;
|
|
87
|
+
/** Inline styles for the container */
|
|
88
|
+
style?: React.CSSProperties;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* SyutSelectUnified - A unified select component with multiple variants
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
94
|
+
* Single select (default variant):
|
|
95
|
+
* ```tsx
|
|
96
|
+
* <SyutSelectUnified
|
|
97
|
+
* options={options}
|
|
98
|
+
* value={selectedValue}
|
|
99
|
+
* onChange={setSelectedValue}
|
|
100
|
+
* />
|
|
101
|
+
* ```
|
|
102
|
+
*
|
|
103
|
+
* @example
|
|
104
|
+
* Multi-select with checkbox variant:
|
|
105
|
+
* ```tsx
|
|
106
|
+
* <SyutSelectUnified
|
|
107
|
+
* isMulti
|
|
108
|
+
* variant="checkbox"
|
|
109
|
+
* options={options}
|
|
110
|
+
* value={selectedValues}
|
|
111
|
+
* onChange={setSelectedValues}
|
|
112
|
+
* showSelectAll
|
|
113
|
+
* />
|
|
114
|
+
* ```
|
|
115
|
+
*
|
|
116
|
+
* @example
|
|
117
|
+
* Creatable select:
|
|
118
|
+
* ```tsx
|
|
119
|
+
* <SyutSelectUnified
|
|
120
|
+
* isCreatable
|
|
121
|
+
* options={options}
|
|
122
|
+
* onCreateOption={(value) => addOption(value)}
|
|
123
|
+
* />
|
|
124
|
+
* ```
|
|
125
|
+
*/
|
|
126
|
+
export declare function SyutSelectUnified({ id, name, options, value, onChange, placeholder, isDisabled, isLoading, isMulti, isSearchable: isSearchableProp, searchable, isClearable, isCreatable, onCreateOption, formatCreateLabel, isAsync, loadOptions, defaultOptions, cacheOptions, label, error, helperText, required, className, size, autoFocus, menuPlacement, maxMenuHeight, variant, showSelectAll, selectAllLabel, searchPlaceholder, noOptionsMessage, debounceDelay, minSearchLength, loadingMessage, minSearchMessage, style, }: SyutSelectUnifiedProps): import("react/jsx-runtime").JSX.Element;
|
|
127
|
+
export default SyutSelectUnified;
|
|
128
|
+
//# sourceMappingURL=SyutSelectUnified.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SyutSelectUnified.d.ts","sourceRoot":"","sources":["../../../../src/components/ui/SyutSelect/SyutSelectUnified.tsx"],"names":[],"mappings":"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"}
|