@ishibashi0112/spreadsheet-grid 0.7.0 → 0.8.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/SpreadsheetGrid.d.ts +1 -1
- package/dist/hooks/useCellContextMenuController.d.ts +23 -0
- package/dist/hooks/useColumnHeaderDragController.d.ts +1 -0
- package/dist/hooks/useGlobalFilteredOrder.d.ts +17 -0
- package/dist/hooks/useGridBarContext.d.ts +5 -3
- package/dist/hooks/useGridPointerInteractions.d.ts +6 -1
- package/dist/index.cjs +8 -8
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2126 -1554
- package/dist/logic/contextMenuTarget.d.ts +4 -0
- package/dist/logic/filtering.d.ts +1 -0
- package/dist/logic/rowSelection.d.ts +16 -0
- package/dist/model/gridActions.d.ts +5 -1
- package/dist/model/gridTypes.d.ts +84 -0
- package/dist/style.css +1 -1
- package/dist/view/CellContextMenuPopover.d.ts +12 -0
- package/dist/view/DefaultGridTopBar.d.ts +4 -1
- package/dist/view/GridBodyLayer.d.ts +4 -2
- package/dist/view/GridHeaderRow.d.ts +4 -2
- package/dist/view/RowSelectionCheckbox.d.ts +8 -0
- package/package.json +1 -1
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { GridColumn, GridSelection } from '../model/gridTypes';
|
|
2
|
+
export declare const resolveContextMenuColIndex: <T>(orderedColumns: GridColumn<T>[], columnKey: string) => number;
|
|
3
|
+
export declare const isContextMenuCellSelected: (selection: GridSelection, rowIndex: number, colIndex: number) => boolean;
|
|
4
|
+
export declare const isContextMenuRowSelected: (selection: GridSelection, rowIndex: number) => boolean;
|
|
@@ -8,5 +8,6 @@ export declare const isNumberColumnFilterValue: (value: ColumnFilterValue | unde
|
|
|
8
8
|
export declare const buildNumberColumnFilterValue: (rawInput: string) => NumberColumnFilterValue | null;
|
|
9
9
|
export declare const columnFilterValueToDraftText: (value: ColumnFilterValue | undefined) => string;
|
|
10
10
|
export declare const applyNumberFilter: (cellValue: unknown, filterValue: unknown) => boolean;
|
|
11
|
+
export declare const rowMatchesGlobalText: <T>(row: T, columns: GridColumn<T>[], normalizedNeedle: string) => boolean;
|
|
11
12
|
export declare const filterOrderByGlobalText: <T>(rows: T[], order: RowOrder, columns: GridColumn<T>[], globalText: string) => RowOrder;
|
|
12
13
|
export declare const filterOrderByColumns: <T>(rows: T[], order: RowOrder, columns: GridColumn<T>[], columnFilters: Record<string, ColumnFilterValue>, numericKeys?: ReadonlyMap<string, Float64Array>) => RowOrder;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { GridRowKey, RowSelectionModel, RowSelectionState, SelectAllState } from '../model/gridTypes';
|
|
2
|
+
export type { RowSelectionModel, RowSelectionState, SelectAllState };
|
|
3
|
+
export declare const createEmptyRowSelection: () => RowSelectionState;
|
|
4
|
+
export declare const resolveIsRowSelected: (state: RowSelectionState, rowKey: GridRowKey) => boolean;
|
|
5
|
+
export declare const toggleRowKey: (state: RowSelectionState, rowKey: GridRowKey) => RowSelectionState;
|
|
6
|
+
export declare const selectSingleRow: (rowKey: GridRowKey) => RowSelectionState;
|
|
7
|
+
export declare const selectRowRange: (rangeKeys: GridRowKey[]) => RowSelectionState;
|
|
8
|
+
export declare const addRowRange: (base: RowSelectionState, rangeKeys: GridRowKey[]) => RowSelectionState;
|
|
9
|
+
export declare const selectAllRows: () => RowSelectionState;
|
|
10
|
+
export declare const clearRowSelection: () => RowSelectionState;
|
|
11
|
+
export declare const countSelectedRows: (state: RowSelectionState, totalRowCount: number) => number;
|
|
12
|
+
export declare const getSelectAllState: (state: RowSelectionState, totalRowCount: number) => SelectAllState;
|
|
13
|
+
export declare const rowSelectionToModel: (state: RowSelectionState) => RowSelectionModel;
|
|
14
|
+
export declare const rowSelectionFromModel: (model: RowSelectionModel) => RowSelectionState;
|
|
15
|
+
export declare const rowSelectionStateEquals: (a: RowSelectionState, b: RowSelectionState) => boolean;
|
|
16
|
+
export declare const rowSelectionModelEquals: (a: RowSelectionModel, b: RowSelectionModel) => boolean;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { CellCoord, ColumnFilterValue, GridFilterState, GridSortEntry } from './gridTypes';
|
|
1
|
+
import type { CellCoord, ColumnFilterValue, GridFilterState, GridSortEntry, RowSelectionState } from './gridTypes';
|
|
2
2
|
export type GridUiAction = {
|
|
3
3
|
type: 'cell/activate';
|
|
4
4
|
cell: CellCoord | null;
|
|
@@ -67,6 +67,9 @@ export type GridUiAction = {
|
|
|
67
67
|
entries: GridSortEntry[];
|
|
68
68
|
} | {
|
|
69
69
|
type: 'sort/clear';
|
|
70
|
+
} | {
|
|
71
|
+
type: 'rowSelect/set';
|
|
72
|
+
state: RowSelectionState;
|
|
70
73
|
};
|
|
71
74
|
export declare const gridActions: {
|
|
72
75
|
activateCell: (cell: CellCoord | null) => GridUiAction;
|
|
@@ -92,4 +95,5 @@ export declare const gridActions: {
|
|
|
92
95
|
setAllFilters: (filters: GridFilterState) => GridUiAction;
|
|
93
96
|
setSort: (entries: GridSortEntry[]) => GridUiAction;
|
|
94
97
|
clearSort: () => GridUiAction;
|
|
98
|
+
setRowSelectionState: (state: RowSelectionState) => GridUiAction;
|
|
95
99
|
};
|
|
@@ -47,6 +47,19 @@ export type GridSelection = {
|
|
|
47
47
|
startCol: number;
|
|
48
48
|
endCol: number;
|
|
49
49
|
} | null;
|
|
50
|
+
export type RowSelectionState = {
|
|
51
|
+
mode: 'include' | 'exclude';
|
|
52
|
+
keys: ReadonlySet<GridRowKey>;
|
|
53
|
+
};
|
|
54
|
+
export type RowSelectionModel = {
|
|
55
|
+
type: 'include';
|
|
56
|
+
rowKeys: GridRowKey[];
|
|
57
|
+
} | {
|
|
58
|
+
type: 'exclude';
|
|
59
|
+
rowKeys: GridRowKey[];
|
|
60
|
+
};
|
|
61
|
+
export type RowSelectionMode = 'single' | 'multiple';
|
|
62
|
+
export type SelectAllState = 'none' | 'some' | 'all';
|
|
50
63
|
export type GridFilterState = {
|
|
51
64
|
globalText: string;
|
|
52
65
|
columnFilters: Record<string, ColumnFilterValue>;
|
|
@@ -194,6 +207,7 @@ export type ColumnSelectionDragState = {
|
|
|
194
207
|
export type GridUiState = {
|
|
195
208
|
activeCell: CellCoord | null;
|
|
196
209
|
selection: GridSelection;
|
|
210
|
+
rowSelection: RowSelectionState;
|
|
197
211
|
editingCell: CellCoord | null;
|
|
198
212
|
dragState: CellSelectionDragState | RowSelectionDragState | ColumnSelectionDragState | ColumnResizeDragState | null;
|
|
199
213
|
columnWidths: Record<string, number>;
|
|
@@ -221,6 +235,7 @@ export type SpreadsheetGridDerivedSummary = {
|
|
|
221
235
|
hasSorting: boolean;
|
|
222
236
|
sortedColumnLabel: string | null;
|
|
223
237
|
};
|
|
238
|
+
export type GlobalFilterStatus = 'idle' | 'filtering' | 'ready';
|
|
224
239
|
export type SpreadsheetGridSlotContext<T> = {
|
|
225
240
|
rows: T[];
|
|
226
241
|
filteredRows: T[];
|
|
@@ -233,7 +248,57 @@ export type SpreadsheetGridSlotContext<T> = {
|
|
|
233
248
|
activeCell: CellCoord | null;
|
|
234
249
|
selection: GridSelection;
|
|
235
250
|
derivedSummary: SpreadsheetGridDerivedSummary;
|
|
251
|
+
globalFilterStatus: GlobalFilterStatus;
|
|
252
|
+
globalFilterProgress: number;
|
|
253
|
+
};
|
|
254
|
+
export type GridContextMenuTarget<T> = {
|
|
255
|
+
type: 'cell';
|
|
256
|
+
rowIndex: number;
|
|
257
|
+
colIndex: number;
|
|
258
|
+
rowKey: GridRowKey;
|
|
259
|
+
row: T;
|
|
260
|
+
column: GridColumn<T>;
|
|
261
|
+
value: unknown;
|
|
262
|
+
} | {
|
|
263
|
+
type: 'rowHeader';
|
|
264
|
+
rowIndex: number;
|
|
265
|
+
rowKey: GridRowKey;
|
|
266
|
+
row: T;
|
|
267
|
+
};
|
|
268
|
+
export type GridContextMenuParams<T> = {
|
|
269
|
+
target: GridContextMenuTarget<T>;
|
|
270
|
+
clientX: number;
|
|
271
|
+
clientY: number;
|
|
272
|
+
selection: GridSelection;
|
|
273
|
+
activeCell: CellCoord | null;
|
|
274
|
+
isTargetSelected: boolean;
|
|
275
|
+
};
|
|
276
|
+
export type GridContextMenuActionItem = {
|
|
277
|
+
kind?: 'action';
|
|
278
|
+
id?: string;
|
|
279
|
+
label: ReactNode;
|
|
280
|
+
icon?: ReactNode;
|
|
281
|
+
disabled?: boolean;
|
|
282
|
+
danger?: boolean;
|
|
283
|
+
onSelect: () => void;
|
|
284
|
+
};
|
|
285
|
+
export type GridContextMenuLabelItem = {
|
|
286
|
+
kind: 'label';
|
|
287
|
+
id?: string;
|
|
288
|
+
label: ReactNode;
|
|
289
|
+
};
|
|
290
|
+
export type GridContextMenuSeparatorItem = {
|
|
291
|
+
kind: 'separator';
|
|
292
|
+
id?: string;
|
|
293
|
+
};
|
|
294
|
+
export type GridContextMenuCustomItem = {
|
|
295
|
+
kind: 'custom';
|
|
296
|
+
id?: string;
|
|
297
|
+
render: (ctx: {
|
|
298
|
+
close: () => void;
|
|
299
|
+
}) => ReactNode;
|
|
236
300
|
};
|
|
301
|
+
export type GridContextMenuItem = GridContextMenuActionItem | GridContextMenuLabelItem | GridContextMenuSeparatorItem | GridContextMenuCustomItem;
|
|
237
302
|
export type GridClassNames = {
|
|
238
303
|
root?: string;
|
|
239
304
|
toolbar?: string;
|
|
@@ -310,6 +375,14 @@ export type SpreadsheetGridHandle<T> = {
|
|
|
310
375
|
getExportData: (options?: GridExportOptions) => GridExportData;
|
|
311
376
|
getState: () => GridState;
|
|
312
377
|
applyState: (state: GridState) => void;
|
|
378
|
+
getRowSelection: () => RowSelectionModel;
|
|
379
|
+
setRowSelection: (model: RowSelectionModel) => void;
|
|
380
|
+
getSelectedRowKeys: () => GridRowKey[];
|
|
381
|
+
getSelectedRowData: () => T[];
|
|
382
|
+
getSelectedRowCount: () => number;
|
|
383
|
+
isRowSelected: (rowKey: GridRowKey) => boolean;
|
|
384
|
+
selectAllRows: () => void;
|
|
385
|
+
clearRowSelection: () => void;
|
|
313
386
|
};
|
|
314
387
|
export type SpreadsheetGridProps<T> = {
|
|
315
388
|
ref?: Ref<SpreadsheetGridHandle<T>>;
|
|
@@ -333,6 +406,12 @@ export type SpreadsheetGridProps<T> = {
|
|
|
333
406
|
readOnly?: boolean;
|
|
334
407
|
canEditCell?: (rowIndex: number, colIndex: number, row: T, column: GridColumn<T>) => boolean;
|
|
335
408
|
enableRangeSelection?: boolean;
|
|
409
|
+
enableRowSelection?: boolean;
|
|
410
|
+
rowSelectionMode?: RowSelectionMode;
|
|
411
|
+
enableSelectAllRows?: boolean;
|
|
412
|
+
rowSelection?: RowSelectionModel;
|
|
413
|
+
selectedRowKeys?: GridRowKey[];
|
|
414
|
+
onRowSelectionChange?: (model: RowSelectionModel) => void;
|
|
336
415
|
enableGlobalFilter?: boolean;
|
|
337
416
|
enableColumnFilter?: boolean;
|
|
338
417
|
enableSorting?: boolean;
|
|
@@ -346,6 +425,8 @@ export type SpreadsheetGridProps<T> = {
|
|
|
346
425
|
showTopBarSummary?: boolean;
|
|
347
426
|
showTopBarCounts?: boolean;
|
|
348
427
|
showTopBarFilter?: boolean;
|
|
428
|
+
globalFilterPlaceholder?: string;
|
|
429
|
+
globalFilterIcon?: ReactNode;
|
|
349
430
|
showBottomBar?: boolean;
|
|
350
431
|
showBottomBarCounts?: boolean;
|
|
351
432
|
renderTopBar?: (context: SpreadsheetGridSlotContext<T>) => ReactNode;
|
|
@@ -353,4 +434,7 @@ export type SpreadsheetGridProps<T> = {
|
|
|
353
434
|
className?: string;
|
|
354
435
|
classNames?: GridClassNames;
|
|
355
436
|
getRowClassName?: (row: T, rowIndex: number) => string | undefined;
|
|
437
|
+
enableContextMenu?: boolean;
|
|
438
|
+
getContextMenuItems?: (params: GridContextMenuParams<T>) => GridContextMenuItem[];
|
|
439
|
+
onContextMenuOpen?: (params: GridContextMenuParams<T>) => void;
|
|
356
440
|
};
|
package/dist/style.css
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
@layer ssg-base{.ssg-root{--ssg-accent:#3461c9;--ssg-accent-strong:#1d4ed8;--ssg-line:#f1f5f9;--ssg-line-strong:#e5e7eb;--ssg-divider:#d7dce3;--ssg-header-bg:#f8fafc;--ssg-row-hover-bg:#f1f5f9;--ssg-glyph:#94a3b8;--ssg-glyph-hover:#475569;--ssg-icon-hover-bg:#d6dee8;--ssg-icon-active-bg:#e3e9f5;--ssg-icon-active-bg-hover:#d4ddf0;--ssg-icon-active-border:#c7d3ea;--ssg-cell-bg:#fff;--ssg-cell-text:#0f172a;--ssg-readonly-bg:#f8fafc;--ssg-readonly-text:#64748b;--ssg-readonly-hover-bg:#eef2f7;--ssg-header-text:#334155;--ssg-header-hover-bg:#e2e8f0;--ssg-select-bg:#e3e9f5;--ssg-select-bg-hover:#ccd7ee;--ssg-selection-fill:#3461c914;--ssg-radius:8px;--ssg-icon-btn-size:20px;border:1px solid var(--ssg-divider);border-radius:var(--ssg-radius);background-color:var(--ssg-cell-bg);overflow:hidden;box-shadow:0 4px 14px #0f172a0a}.ssg-icon-btn{width:var(--ssg-icon-btn-size);height:var(--ssg-icon-btn-size);color:var(--ssg-glyph);cursor:pointer;background-color:#0000;border:1px solid #0000;border-radius:6px;flex:none;justify-content:center;align-items:center;padding:0;font-size:11px;line-height:1;transition:background-color .1s,color .1s;display:inline-flex}.ssg-icon-btn:hover{background-color:var(--ssg-icon-hover-bg);color:var(--ssg-glyph-hover)}.ssg-icon-btn--active{border-color:var(--ssg-icon-active-border);background-color:var(--ssg-icon-active-bg);color:var(--ssg-accent)}.ssg-icon-btn--active:hover{background-color:var(--ssg-icon-active-bg-hover);color:var(--ssg-accent)}.ssg-body-cell{box-sizing:border-box;border-right:1px solid var(--ssg-line);border-bottom:1px solid var(--ssg-line-strong);background-color:var(--ssg-cell-bg);color:var(--ssg-cell-text);white-space:nowrap;cursor:default;-webkit-user-select:none;user-select:none;outline:none;align-items:center;padding:0 10px;display:flex;position:absolute;top:0;overflow:hidden}.ssg-body-cell--autoheight{white-space:normal;word-break:break-word;align-items:flex-start;overflow:visible}.ssg-body-cell--align-center{text-align:center;justify-content:center}.ssg-body-cell--align-right{text-align:right;justify-content:flex-end}.ssg-body-cell--row-hovered{background-color:var(--ssg-row-hover-bg)}.ssg-body-cell--readonly{background-color:var(--ssg-readonly-bg);color:var(--ssg-readonly-text)}.ssg-body-cell--readonly.ssg-body-cell--row-hovered{background-color:var(--ssg-readonly-hover-bg)}.ssg-header-row{z-index:6;background-color:var(--ssg-header-bg);position:sticky;top:0}.ssg-header-cell{box-sizing:border-box;border-right:1px solid var(--ssg-line);border-bottom:1px solid var(--ssg-divider);background-color:var(--ssg-header-bg);color:var(--ssg-header-text);align-items:center;gap:4px;padding:0 6px;font-size:13px;font-weight:600;display:flex;position:absolute;top:0}.ssg-header-cell--hovered{background-color:var(--ssg-header-hover-bg)}.ssg-header-cell--selected{background-color:var(--ssg-select-bg)}.ssg-header-cell--selected.ssg-header-cell--hovered{background-color:var(--ssg-select-bg-hover)}.ssg-row-header-cell{z-index:5;justify-content:center;font-weight:500;left:0}.ssg-corner-cell{z-index:7;border-right:1px solid var(--ssg-line-strong);justify-content:center;padding:0;line-height:1;left:0}.ssg-active-cell-overlay{box-sizing:border-box;border:2px solid var(--ssg-accent);pointer-events:none;z-index:4}.ssg-selection-overlay{box-sizing:border-box;border:2px solid var(--ssg-accent);background-color:var(--ssg-selection-fill);pointer-events:none;z-index:2}.ssg-cell-editor{pointer-events:none;z-index:5}.ssg-cell-editor-input{box-sizing:border-box;border:2px solid var(--ssg-accent);width:100%;height:100%;color:var(--ssg-cell-text);background-color:var(--ssg-cell-bg);pointer-events:auto;outline:none;margin:0;padding:0 10px;font-size:16px}.ssg-bar--top{border-bottom:1px solid var(--ssg-divider)}.ssg-bar--bottom{border-top:1px solid var(--ssg-divider)}.ssg-bar-container{background-color:var(--ssg-header-bg);flex-wrap:wrap;justify-content:space-between;align-items:center;gap:6px;padding:5px 10px;display:flex}.ssg-bar-group{flex-wrap:wrap;align-items:center;gap:4px;display:flex}.ssg-bar-leading{min-width:0;color:var(--ssg-header-text);flex:auto;font-size:12px}.ssg-bar-title{letter-spacing:.06em;text-transform:uppercase;color:var(--ssg-glyph);margin-right:2px;font-size:10px;font-weight:600}.ssg-bar-chip{color:var(--ssg-header-text);font-variant-numeric:tabular-nums;white-space:nowrap;background-color:#0000;border:none;border-radius:5px;align-items:center;padding:1px 6px;font-size:11.5px;display:inline-flex}.ssg-bar-chip--emphasis{background-color:var(--ssg-header-hover-bg);color:var(--ssg-header-text);font-weight:600}.ssg-bar-input{box-sizing:border-box;background-color:var(--ssg-cell-bg);width:100%;min-width:0;color:var(--ssg-cell-text);caret-color:var(--ssg-cell-text);-webkit-text-fill-color:var(--ssg-cell-text);border:1px solid #cbd5e1;border-radius:6px;outline:none;padding:6px 10px;font-size:13px;line-height:1.4}.ssg-bar-input-group{align-items:center;gap:6px;width:100%;max-width:380px;display:flex}.ssg-bar-container>.ssg-bar-input-group:only-child{flex:auto;max-width:480px}.ssg-bar-clear-btn{background-color:var(--ssg-cell-bg);color:#475569;cursor:pointer;white-space:nowrap;border:1px solid #cbd5e1;border-radius:6px;flex:none;padding:6px 10px;font-size:12px;line-height:1}.ssg-popover{box-sizing:border-box;z-index:1000;background-color:#fff;border:1px solid #cbd5e1;border-radius:12px;flex-direction:column;padding:12px;display:flex;position:fixed;box-shadow:0 12px 28px #0f172a29}.ssg-popover-header{border-bottom:1px solid #e2e8f0;justify-content:space-between;align-items:center;gap:8px;margin-bottom:8px;padding-bottom:8px;display:flex}.ssg-popover-title{color:#1e293b;-webkit-user-select:none;user-select:none;font-size:13px;font-weight:700}.ssg-popover-close{color:#64748b;cursor:pointer;background-color:#0000;border:none;border-radius:6px;justify-content:center;align-items:center;width:24px;height:24px;font-size:16px;line-height:1;display:flex}.ssg-popover-close:hover{background-color:#f1f5f9}.ssg-popover-footer{border-top:1px solid #e2e8f0;gap:8px;margin-top:8px;padding-top:8px;display:flex}.ssg-sort-panel{max-height:420px}.ssg-sort-list{flex-direction:column;flex:1;gap:6px;min-height:0;margin:0 -4px;padding:0 4px;display:flex;overflow-y:auto}.ssg-sort-empty{color:#94a3b8;-webkit-user-select:none;user-select:none;padding:10px 4px;font-size:12px}.ssg-sort-level{opacity:1;border-top:2px solid #0000;align-items:center;gap:6px;display:flex}.ssg-sort-level--drop-before{border-top-color:#2563eb}.ssg-sort-level--dragging{opacity:.4}.ssg-sort-handle{cursor:grab;touch-action:none;border-radius:6px;flex:none;justify-content:center;align-items:center;width:16px;height:26px;display:flex}.ssg-sort-handle--dragging{cursor:grabbing}.ssg-sort-handle--disabled{cursor:default}.ssg-sort-handle:not(.ssg-sort-handle--disabled):hover{background-color:#f1f5f9}.ssg-sort-badge{color:#2563eb;-webkit-user-select:none;user-select:none;background-color:#eff6ff;border-radius:9px;flex:none;justify-content:center;align-items:center;width:18px;height:18px;font-size:11px;font-weight:700;display:flex}.ssg-sort-select{box-sizing:border-box;color:#334155;cursor:pointer;background-color:#fff;border:1px solid #cbd5e1;border-radius:6px;flex:1;min-width:0;padding:5px 6px;font-size:13px}.ssg-sort-select:disabled{cursor:default}.ssg-sort-dir-group{flex:none;display:flex}.ssg-sort-dir-btn{box-sizing:border-box;color:#475569;cursor:pointer;background-color:#fff;border:1px solid #cbd5e1;flex:none;padding:4px 9px;font-size:12px;line-height:1.4}.ssg-sort-dir-group>.ssg-sort-dir-btn:first-child{border-right:none;border-top-left-radius:6px;border-bottom-left-radius:6px}.ssg-sort-dir-group>.ssg-sort-dir-btn:last-child{border-top-right-radius:6px;border-bottom-right-radius:6px}.ssg-sort-dir-btn--active{color:#fff;background-color:#2563eb;border-color:#2563eb}.ssg-sort-dir-btn:disabled{color:#cbd5e1;cursor:default}.ssg-sort-delete{color:#64748b;cursor:pointer;background-color:#0000;border:none;border-radius:6px;flex:none;justify-content:center;align-items:center;width:26px;height:26px;font-size:15px;line-height:1;display:flex}.ssg-sort-delete:disabled{color:#cbd5e1;cursor:default}.ssg-sort-delete:not(:disabled):hover{color:#dc2626;background-color:#fef2f2}.ssg-sort-drop-end{border-top:2px solid #2563eb;height:0}.ssg-sort-footer-btn{box-sizing:border-box;color:#334155;cursor:pointer;text-align:center;-webkit-user-select:none;user-select:none;background-color:#0000;border:1px solid #e2e8f0;border-radius:8px;font-size:13px}.ssg-sort-footer-btn--add{flex:1;padding:7px 8px}.ssg-sort-footer-btn--clear{flex:none;padding:7px 12px}.ssg-sort-footer-btn:disabled{color:#cbd5e1;cursor:default}.ssg-sort-footer-btn:not(:disabled):hover{background-color:#f1f5f9}.ssg-sort-note{color:#94a3b8;-webkit-user-select:none;user-select:none;margin-top:8px;font-size:11px}.ssg-chooser-panel{max-height:420px}.ssg-chooser-search-row{align-items:center;gap:8px;margin-bottom:8px;display:flex}.ssg-chooser-master-btn{cursor:pointer;background:0 0;border:none;align-items:center;padding:0;display:flex}.ssg-chooser-master-btn:disabled{cursor:default}.ssg-chooser-search-field{flex:1;min-width:0;position:relative}.ssg-chooser-search-icon{color:#94a3b8;pointer-events:none;font-size:13px;line-height:1;position:absolute;top:50%;left:9px;transform:translateY(-50%)}.ssg-chooser-search-input{box-sizing:border-box;color:#334155;border:1px solid #cbd5e1;border-radius:8px;outline:none;width:100%;padding:7px 10px 7px 26px;font-size:13px}.ssg-chooser-list{flex:1;min-height:0;margin:0 -4px;padding:0 4px;overflow-y:auto}.ssg-chooser-empty{color:#94a3b8;-webkit-user-select:none;user-select:none;padding:10px 4px;font-size:12px}.ssg-chooser-section-heading{color:#94a3b8;letter-spacing:.4px;-webkit-user-select:none;user-select:none;padding:8px 4px 4px;font-size:11px;font-weight:700}.ssg-chooser-row{opacity:1;border-top:2px solid #0000;align-items:center;gap:4px;display:flex}.ssg-chooser-row--drop-before{border-top-color:#2563eb}.ssg-chooser-row--dragging{opacity:.4}.ssg-chooser-handle{cursor:grab;touch-action:none;border-radius:6px;flex:none;justify-content:center;align-items:center;width:18px;height:28px;display:flex}.ssg-chooser-handle--dragging{cursor:grabbing}.ssg-chooser-handle--disabled{cursor:default}.ssg-chooser-handle:not(.ssg-chooser-handle--disabled):hover{background-color:#f1f5f9}.ssg-chooser-toggle{box-sizing:border-box;cursor:pointer;text-align:left;background-color:#0000;border:none;border-radius:8px;flex:1;align-items:center;gap:10px;min-width:0;padding:7px 8px;display:flex}.ssg-chooser-toggle:disabled{cursor:default}.ssg-chooser-toggle:not(:disabled):hover{background-color:#f1f5f9}.ssg-chooser-label{color:#334155;text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0;font-size:13px;overflow:hidden}.ssg-chooser-label--muted{color:#94a3b8}.ssg-chooser-drop-end{border-top:2px solid #2563eb;height:0}.ssg-chooser-footer{border-top:1px solid #e2e8f0;margin-top:8px;padding-top:8px}.ssg-chooser-reset-btn{box-sizing:border-box;color:#334155;cursor:pointer;text-align:center;-webkit-user-select:none;user-select:none;background-color:#0000;border:1px solid #e2e8f0;border-radius:8px;width:100%;padding:7px 8px;font-size:13px;display:block}.ssg-chooser-reset-btn:disabled{color:#cbd5e1;cursor:default}.ssg-chooser-reset-btn:not(:disabled):hover{background-color:#f1f5f9}.ssg-chooser-note{color:#94a3b8;-webkit-user-select:none;user-select:none;margin-top:8px;font-size:11px}.ssg-checkbox{background-color:#fff;border:1.5px solid #94a3b8;border-radius:5px;flex:none;justify-content:center;align-items:center;width:18px;height:18px;transition:background-color 80ms,border-color 80ms;display:flex}.ssg-checkbox--filled{background-color:#2563eb;border-color:#2563eb}.ssg-checkbox--disabled{background-color:#f1f5f9;border-color:#cbd5e1}.ssg-checkbox-dash{background-color:#fff;border-radius:1px;width:9px;height:2px}.ssg-filter-popover{box-sizing:border-box;z-index:1000;background-color:#fff;border:1px solid #cbd5e1;border-radius:10px;padding:12px;position:fixed;box-shadow:0 10px 24px #0f172a1f}.ssg-filter-title{color:#334155;margin-bottom:8px;font-size:12px;font-weight:700}.ssg-filter-hint{color:#64748b;margin-bottom:8px;font-size:11px}.ssg-filter-meta{color:#64748b;margin-bottom:10px;font-size:11px}.ssg-filter-meta--ellipsis{white-space:nowrap;text-overflow:ellipsis;overflow:hidden}.ssg-filter-collecting{text-align:center;color:#64748b;padding:24px;font-size:12px}.ssg-filter-input{box-sizing:border-box;border:1px solid #cbd5e1;border-radius:8px;outline:none;width:100%;margin-bottom:8px;padding:8px 10px}.ssg-filter-select{box-sizing:border-box;background-color:#fff;border:1px solid #cbd5e1;border-radius:8px;outline:none;width:100%;margin-bottom:8px;padding:8px 10px}.ssg-filter-selectall{cursor:pointer;color:#334155;-webkit-user-select:none;user-select:none;border-bottom:1px solid #e2e8f0;align-items:center;gap:8px;height:28px;padding:0 8px;font-size:12px;display:flex}.ssg-filter-selectall-label{font-weight:600}.ssg-filter-list{border:1px solid #e2e8f0;border-top:none;border-radius:0 0 8px 8px;height:208px;margin-bottom:8px;overflow-y:auto}.ssg-filter-empty{color:#94a3b8;text-align:center;padding:12px;font-size:12px}.ssg-filter-virt{width:100%;position:relative}.ssg-filter-option{box-sizing:border-box;cursor:pointer;color:#334155;-webkit-user-select:none;user-select:none;align-items:center;gap:8px;padding:0 8px;font-size:12px;display:flex;position:absolute;top:0;left:0;right:0}.ssg-filter-option-label{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.ssg-filter-footer{justify-content:flex-end;gap:8px;display:flex}.ssg-filter-btn-secondary{color:#475569;cursor:pointer;background-color:#fff;border:1px solid #cbd5e1;border-radius:8px;padding:6px 10px;font-size:12px}.ssg-filter-btn-primary{color:#fff;cursor:pointer;background-color:#2563eb;border:1px solid #2563eb;border-radius:8px;padding:6px 10px;font-size:12px}.ssg-menu-panel{box-sizing:border-box;background-color:#fff;border:1px solid #cbd5e1;border-radius:10px;padding:8px;box-shadow:0 10px 24px #0f172a1f}.ssg-menu-title{color:#334155;text-overflow:ellipsis;white-space:nowrap;-webkit-user-select:none;user-select:none;border-bottom:1px solid #e2e8f0;margin-bottom:4px;padding:2px 8px 6px;font-size:12px;font-weight:700;overflow:hidden}.ssg-menu-item{box-sizing:border-box;color:#334155;text-align:left;cursor:pointer;background-color:#0000;border:none;border-radius:8px;align-items:center;gap:8px;width:100%;padding:7px 8px;font-size:13px;display:flex}.ssg-menu-item:disabled,.ssg-menu-item--disabled{color:#94a3b8;cursor:default}.ssg-menu-item--active,.ssg-menu-item:not(:disabled):not(.ssg-menu-item--disabled):hover{background-color:#f1f5f9}.ssg-menu-submenu-anchor{position:relative}.ssg-menu-icon{text-align:center;flex:none;width:14px}.ssg-menu-sort-icon{text-align:center;color:#94a3b8;flex:none;width:14px;font-weight:400}.ssg-menu-sort-icon--active{color:#2563eb;font-weight:700}.ssg-menu-check{text-align:center;color:#2563eb;flex:none;width:14px;font-weight:700}.ssg-menu-check--hidden{visibility:hidden}.ssg-menu-label{flex:1;min-width:0}.ssg-menu-label--sorted{color:#1d4ed8}.ssg-menu-caret{color:#94a3b8;flex:none;font-size:12px;line-height:1}.ssg-menu-separator{border-top:1px solid #e2e8f0;margin:4px 0}.ssg-menu-note{color:#94a3b8;-webkit-user-select:none;user-select:none;padding:4px 8px 2px;font-size:11px}.ssg-menu-footer{border-top:1px solid #e2e8f0;justify-content:flex-end;margin-top:4px;padding-top:6px;display:flex}.ssg-menu-close-btn{color:#475569;cursor:pointer;background-color:#fff;border:1px solid #cbd5e1;border-radius:8px;padding:5px 10px;font-size:12px}.ssg-body-row{contain:layout style paint;width:100%;position:absolute;top:0;left:0}.ssg-header-grip{color:#cbd5e1;cursor:grab;touch-action:none;-webkit-user-select:none;user-select:none;flex:none;justify-content:center;align-items:center;width:12px;height:20px;display:inline-flex}.ssg-header-status{flex:none;align-items:center;gap:3px;display:inline-flex}.ssg-header-actions{background-color:var(--ssg-header-bg);opacity:0;pointer-events:none;align-items:center;gap:2px;height:100%;padding:0 6px 0 14px;transition:opacity .1s;display:flex;position:absolute;top:0;right:0}.ssg-header-cell:hover .ssg-header-actions{opacity:1;pointer-events:auto;background-color:var(--ssg-header-hover-bg)}@media (hover:none){.ssg-header-actions{opacity:1;pointer-events:auto;background-color:#0000;height:auto;padding:0;position:static}}.ssg-header-actions .ssg-header-grip,.ssg-header-actions .ssg-icon-btn:not(.ssg-icon-btn--active){color:#475569}.ssg-header-label{min-width:0;color:var(--ssg-header-text);text-overflow:ellipsis;white-space:nowrap;flex:1;overflow:hidden}.ssg-header-label--filtered{color:var(--ssg-accent-strong)}.ssg-header-sort{color:var(--ssg-accent);flex:none;align-items:center;gap:1px;font-size:12px;font-weight:700;line-height:1;display:inline-flex}.ssg-header-sort-priority{font-size:9px;font-weight:700;line-height:1}.ssg-header-filtered-mark{color:var(--ssg-accent-strong);flex:none;align-items:center;display:inline-flex}.ssg-header-resize{cursor:col-resize;z-index:3;width:6px;height:100%;position:absolute;top:0;right:-3px}.ssg-skeleton-rowheader{color:#94a3b8}.ssg-skeleton-bar{background-color:#e2e8f0;border-radius:4px;height:10px}.ssg-shell{background-color:var(--ssg-cell-bg);position:relative;overflow:hidden}.ssg-scroll-container{max-height:480px;position:relative;overflow:auto}.ssg-inner-row{display:flex}.ssg-center-pane{z-index:1;flex-shrink:0;position:relative}.ssg-empty-state{color:#94a3b8;-webkit-user-select:none;user-select:none;justify-content:center;align-items:center;height:160px;font-size:13px;display:flex;position:sticky;left:0}.ssg-autosize-overlay{pointer-events:none;z-index:5;justify-content:center;align-items:center;display:flex;position:absolute;inset:0}.ssg-autosize-pill{color:#f8fafc;-webkit-user-select:none;user-select:none;background-color:#0f172ad1;border-radius:8px;padding:8px 14px;font-size:13px;font-weight:600;box-shadow:0 6px 20px #0f172a40}}
|
|
1
|
+
@layer ssg-base{.ssg-root{--ssg-accent:#3461c9;--ssg-accent-strong:#1d4ed8;--ssg-line:#f1f5f9;--ssg-line-strong:#e5e7eb;--ssg-divider:#d7dce3;--ssg-header-bg:#f8fafc;--ssg-row-hover-bg:#f1f5f9;--ssg-glyph:#94a3b8;--ssg-glyph-hover:#475569;--ssg-icon-hover-bg:#d6dee8;--ssg-icon-active-bg:#e3e9f5;--ssg-icon-active-bg-hover:#d4ddf0;--ssg-icon-active-border:#c7d3ea;--ssg-cell-bg:#fff;--ssg-cell-text:#0f172a;--ssg-readonly-bg:#f8fafc;--ssg-readonly-text:#64748b;--ssg-readonly-hover-bg:#eef2f7;--ssg-header-text:#334155;--ssg-header-hover-bg:#e2e8f0;--ssg-select-bg:#e3e9f5;--ssg-select-bg-hover:#ccd7ee;--ssg-row-selected-bg:#eff4ff;--ssg-checkbox-border:#94a3b8;--ssg-checkbox-bg:#fff;--ssg-checkbox-checked-bg:var(--ssg-accent);--ssg-checkbox-checked-mark:#fff;--ssg-checkbox-hover-border:var(--ssg-accent);--ssg-selection-fill:#3461c914;--ssg-radius:8px;--ssg-icon-btn-size:20px;border:1px solid var(--ssg-divider);border-radius:var(--ssg-radius);background-color:var(--ssg-cell-bg);overflow:hidden;box-shadow:0 4px 14px #0f172a0a}.ssg-icon-btn{width:var(--ssg-icon-btn-size);height:var(--ssg-icon-btn-size);color:var(--ssg-glyph);cursor:pointer;background-color:#0000;border:1px solid #0000;border-radius:6px;flex:none;justify-content:center;align-items:center;padding:0;font-size:11px;line-height:1;transition:background-color .1s,color .1s;display:inline-flex}.ssg-icon-btn:hover{background-color:var(--ssg-icon-hover-bg);color:var(--ssg-glyph-hover)}.ssg-icon-btn--active{border-color:var(--ssg-icon-active-border);background-color:var(--ssg-icon-active-bg);color:var(--ssg-accent)}.ssg-icon-btn--active:hover{background-color:var(--ssg-icon-active-bg-hover);color:var(--ssg-accent)}.ssg-body-cell{box-sizing:border-box;border-right:1px solid var(--ssg-line);border-bottom:1px solid var(--ssg-line-strong);background-color:var(--ssg-cell-bg);color:var(--ssg-cell-text);white-space:nowrap;cursor:default;-webkit-user-select:none;user-select:none;outline:none;align-items:center;padding:0 10px;display:flex;position:absolute;top:0;overflow:hidden}.ssg-body-cell--autoheight{white-space:normal;word-break:break-word;align-items:flex-start;overflow:visible}.ssg-body-cell--align-center{text-align:center;justify-content:center}.ssg-body-cell--align-right{text-align:right;justify-content:flex-end}.ssg-body-cell--row-hovered{background-color:var(--ssg-row-hover-bg)}.ssg-body-cell--readonly{background-color:var(--ssg-readonly-bg);color:var(--ssg-readonly-text)}.ssg-body-cell--readonly.ssg-body-cell--row-hovered{background-color:var(--ssg-readonly-hover-bg)}.ssg-header-row{z-index:6;background-color:var(--ssg-header-bg);position:sticky;top:0}.ssg-header-cell{box-sizing:border-box;border-right:1px solid var(--ssg-line);border-bottom:1px solid var(--ssg-divider);background-color:var(--ssg-header-bg);color:var(--ssg-header-text);align-items:center;gap:4px;padding:0 6px;font-size:13px;font-weight:600;display:flex;position:absolute;top:0}.ssg-header-cell--hovered{background-color:var(--ssg-header-hover-bg)}.ssg-header-cell--selected{background-color:var(--ssg-select-bg)}.ssg-header-cell--selected.ssg-header-cell--hovered{background-color:var(--ssg-select-bg-hover)}.ssg-row-header-cell{z-index:5;justify-content:center;font-weight:500;left:0}.ssg-corner-cell{z-index:7;border-right:1px solid var(--ssg-line-strong);justify-content:center;padding:0;line-height:1;left:0}.ssg-row-checkbox{box-sizing:border-box;border:1.5px solid var(--ssg-checkbox-border);background-color:var(--ssg-checkbox-bg);border-radius:4px;width:16px;height:16px;transition:background-color .12s,border-color .12s;display:inline-block;position:relative}.ssg-row-checkbox[data-state=checked],.ssg-row-checkbox[data-state=indeterminate]{border-color:var(--ssg-checkbox-checked-bg);background-color:var(--ssg-checkbox-checked-bg)}.ssg-row-checkbox[data-state=checked]:after{content:"";border:solid var(--ssg-checkbox-checked-mark);border-width:0 2px 2px 0;width:4px;height:8px;position:absolute;top:1.5px;left:4.5px;transform:rotate(45deg)}.ssg-row-checkbox[data-state=indeterminate]:after{content:"";background-color:var(--ssg-checkbox-checked-mark);border-radius:1px;height:2px;position:absolute;top:6.5px;left:3px;right:3px}.ssg-row-checkbox[data-disabled=true]{opacity:.45}.ssg-row-header-cell--checkbox:hover .ssg-row-checkbox[data-state=unchecked],.ssg-corner-cell--checkbox:hover .ssg-row-checkbox[data-state=unchecked]{border-color:var(--ssg-checkbox-hover-border)}.ssg-active-cell-overlay{box-sizing:border-box;border:2px solid var(--ssg-accent);pointer-events:none;z-index:4}.ssg-selection-overlay{box-sizing:border-box;border:2px solid var(--ssg-accent);background-color:var(--ssg-selection-fill);pointer-events:none;z-index:2}.ssg-cell-editor{pointer-events:none;z-index:5}.ssg-cell-editor-input{box-sizing:border-box;border:2px solid var(--ssg-accent);width:100%;height:100%;color:var(--ssg-cell-text);background-color:var(--ssg-cell-bg);pointer-events:auto;outline:none;margin:0;padding:0 10px;font-size:16px}.ssg-bar--top{border-bottom:1px solid var(--ssg-divider)}.ssg-bar--bottom{border-top:1px solid var(--ssg-divider)}.ssg-bar-container{background-color:var(--ssg-header-bg);flex-wrap:wrap;justify-content:space-between;align-items:center;gap:6px;padding:5px 10px;display:flex}.ssg-bar-group{flex-wrap:wrap;align-items:center;gap:4px;display:flex}.ssg-bar-leading{min-width:0;color:var(--ssg-header-text);flex:auto;font-size:12px}.ssg-bar-title{letter-spacing:.06em;text-transform:uppercase;color:var(--ssg-glyph);margin-right:2px;font-size:10px;font-weight:600}.ssg-bar-chip{color:var(--ssg-header-text);font-variant-numeric:tabular-nums;white-space:nowrap;background-color:#0000;border:none;border-radius:5px;align-items:center;padding:1px 6px;font-size:11.5px;display:inline-flex}.ssg-bar-chip--emphasis{background-color:var(--ssg-header-hover-bg);color:var(--ssg-header-text);font-weight:600}.ssg-bar-input{box-sizing:border-box;min-width:0;color:var(--ssg-cell-text);caret-color:var(--ssg-cell-text);-webkit-text-fill-color:var(--ssg-cell-text);background-color:#0000;border:none;outline:none;flex:auto;padding:6px 0;font-size:13px;line-height:1.4}.ssg-bar-input-group{box-sizing:border-box;background-color:var(--ssg-cell-bg);border:1px solid #cbd5e1;border-radius:6px;align-items:center;gap:6px;width:100%;max-width:380px;padding:0 8px;display:flex}.ssg-bar-input-group:focus-within{border-color:var(--ssg-accent)}.ssg-bar-container>.ssg-bar-input-group:only-child{flex:auto;max-width:480px}.ssg-bar-input-icon{color:var(--ssg-glyph);pointer-events:none;flex:none;justify-content:center;align-items:center;display:inline-flex}.ssg-bar-input-clear{width:18px;height:18px;color:var(--ssg-glyph);cursor:pointer;background-color:#0000;border:none;border-radius:4px;flex:none;justify-content:center;align-items:center;padding:0;display:inline-flex}.ssg-bar-input-clear:hover{background-color:var(--ssg-row-hover-bg);color:var(--ssg-glyph-hover)}.ssg-popover{box-sizing:border-box;z-index:1000;background-color:#fff;border:1px solid #cbd5e1;border-radius:12px;flex-direction:column;padding:12px;display:flex;position:fixed;box-shadow:0 12px 28px #0f172a29}.ssg-popover-header{border-bottom:1px solid #e2e8f0;justify-content:space-between;align-items:center;gap:8px;margin-bottom:8px;padding-bottom:8px;display:flex}.ssg-popover-title{color:#1e293b;-webkit-user-select:none;user-select:none;font-size:13px;font-weight:700}.ssg-popover-close{color:#64748b;cursor:pointer;background-color:#0000;border:none;border-radius:6px;justify-content:center;align-items:center;width:24px;height:24px;font-size:16px;line-height:1;display:flex}.ssg-popover-close:hover{background-color:#f1f5f9}.ssg-popover-footer{border-top:1px solid #e2e8f0;gap:8px;margin-top:8px;padding-top:8px;display:flex}.ssg-sort-panel{max-height:420px}.ssg-sort-list{flex-direction:column;flex:1;gap:6px;min-height:0;margin:0 -4px;padding:0 4px;display:flex;overflow-y:auto}.ssg-sort-empty{color:#94a3b8;-webkit-user-select:none;user-select:none;padding:10px 4px;font-size:12px}.ssg-sort-level{opacity:1;border-top:2px solid #0000;align-items:center;gap:6px;display:flex}.ssg-sort-level--drop-before{border-top-color:#2563eb}.ssg-sort-level--dragging{opacity:.4}.ssg-sort-handle{cursor:grab;touch-action:none;border-radius:6px;flex:none;justify-content:center;align-items:center;width:16px;height:26px;display:flex}.ssg-sort-handle--dragging{cursor:grabbing}.ssg-sort-handle--disabled{cursor:default}.ssg-sort-handle:not(.ssg-sort-handle--disabled):hover{background-color:#f1f5f9}.ssg-sort-badge{color:#2563eb;-webkit-user-select:none;user-select:none;background-color:#eff6ff;border-radius:9px;flex:none;justify-content:center;align-items:center;width:18px;height:18px;font-size:11px;font-weight:700;display:flex}.ssg-sort-select{box-sizing:border-box;color:#334155;cursor:pointer;background-color:#fff;border:1px solid #cbd5e1;border-radius:6px;flex:1;min-width:0;padding:5px 6px;font-size:13px}.ssg-sort-select:disabled{cursor:default}.ssg-sort-dir-group{flex:none;display:flex}.ssg-sort-dir-btn{box-sizing:border-box;color:#475569;cursor:pointer;background-color:#fff;border:1px solid #cbd5e1;flex:none;padding:4px 9px;font-size:12px;line-height:1.4}.ssg-sort-dir-group>.ssg-sort-dir-btn:first-child{border-right:none;border-top-left-radius:6px;border-bottom-left-radius:6px}.ssg-sort-dir-group>.ssg-sort-dir-btn:last-child{border-top-right-radius:6px;border-bottom-right-radius:6px}.ssg-sort-dir-btn--active{color:#fff;background-color:#2563eb;border-color:#2563eb}.ssg-sort-dir-btn:disabled{color:#cbd5e1;cursor:default}.ssg-sort-delete{color:#64748b;cursor:pointer;background-color:#0000;border:none;border-radius:6px;flex:none;justify-content:center;align-items:center;width:26px;height:26px;font-size:15px;line-height:1;display:flex}.ssg-sort-delete:disabled{color:#cbd5e1;cursor:default}.ssg-sort-delete:not(:disabled):hover{color:#dc2626;background-color:#fef2f2}.ssg-sort-drop-end{border-top:2px solid #2563eb;height:0}.ssg-sort-footer-btn{box-sizing:border-box;color:#334155;cursor:pointer;text-align:center;-webkit-user-select:none;user-select:none;background-color:#0000;border:1px solid #e2e8f0;border-radius:8px;font-size:13px}.ssg-sort-footer-btn--add{flex:1;padding:7px 8px}.ssg-sort-footer-btn--clear{flex:none;padding:7px 12px}.ssg-sort-footer-btn:disabled{color:#cbd5e1;cursor:default}.ssg-sort-footer-btn:not(:disabled):hover{background-color:#f1f5f9}.ssg-sort-note{color:#94a3b8;-webkit-user-select:none;user-select:none;margin-top:8px;font-size:11px}.ssg-chooser-panel{max-height:420px}.ssg-chooser-search-row{align-items:center;gap:8px;margin-bottom:8px;display:flex}.ssg-chooser-master-btn{cursor:pointer;background:0 0;border:none;align-items:center;padding:0;display:flex}.ssg-chooser-master-btn:disabled{cursor:default}.ssg-chooser-search-field{flex:1;min-width:0;position:relative}.ssg-chooser-search-icon{color:#94a3b8;pointer-events:none;font-size:13px;line-height:1;position:absolute;top:50%;left:9px;transform:translateY(-50%)}.ssg-chooser-search-input{box-sizing:border-box;color:#334155;border:1px solid #cbd5e1;border-radius:8px;outline:none;width:100%;padding:7px 10px 7px 26px;font-size:13px}.ssg-chooser-list{flex:1;min-height:0;margin:0 -4px;padding:0 4px;overflow-y:auto}.ssg-chooser-empty{color:#94a3b8;-webkit-user-select:none;user-select:none;padding:10px 4px;font-size:12px}.ssg-chooser-section-heading{color:#94a3b8;letter-spacing:.4px;-webkit-user-select:none;user-select:none;padding:8px 4px 4px;font-size:11px;font-weight:700}.ssg-chooser-row{opacity:1;border-top:2px solid #0000;align-items:center;gap:4px;display:flex}.ssg-chooser-row--drop-before{border-top-color:#2563eb}.ssg-chooser-row--dragging{opacity:.4}.ssg-chooser-handle{cursor:grab;touch-action:none;border-radius:6px;flex:none;justify-content:center;align-items:center;width:18px;height:28px;display:flex}.ssg-chooser-handle--dragging{cursor:grabbing}.ssg-chooser-handle--disabled{cursor:default}.ssg-chooser-handle:not(.ssg-chooser-handle--disabled):hover{background-color:#f1f5f9}.ssg-chooser-toggle{box-sizing:border-box;cursor:pointer;text-align:left;background-color:#0000;border:none;border-radius:8px;flex:1;align-items:center;gap:10px;min-width:0;padding:7px 8px;display:flex}.ssg-chooser-toggle:disabled{cursor:default}.ssg-chooser-toggle:not(:disabled):hover{background-color:#f1f5f9}.ssg-chooser-label{color:#334155;text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0;font-size:13px;overflow:hidden}.ssg-chooser-label--muted{color:#94a3b8}.ssg-chooser-drop-end{border-top:2px solid #2563eb;height:0}.ssg-chooser-footer{border-top:1px solid #e2e8f0;margin-top:8px;padding-top:8px}.ssg-chooser-reset-btn{box-sizing:border-box;color:#334155;cursor:pointer;text-align:center;-webkit-user-select:none;user-select:none;background-color:#0000;border:1px solid #e2e8f0;border-radius:8px;width:100%;padding:7px 8px;font-size:13px;display:block}.ssg-chooser-reset-btn:disabled{color:#cbd5e1;cursor:default}.ssg-chooser-reset-btn:not(:disabled):hover{background-color:#f1f5f9}.ssg-chooser-note{color:#94a3b8;-webkit-user-select:none;user-select:none;margin-top:8px;font-size:11px}.ssg-checkbox{background-color:#fff;border:1.5px solid #94a3b8;border-radius:5px;flex:none;justify-content:center;align-items:center;width:18px;height:18px;transition:background-color 80ms,border-color 80ms;display:flex}.ssg-checkbox--filled{background-color:#2563eb;border-color:#2563eb}.ssg-checkbox--disabled{background-color:#f1f5f9;border-color:#cbd5e1}.ssg-checkbox-dash{background-color:#fff;border-radius:1px;width:9px;height:2px}.ssg-filter-popover{box-sizing:border-box;z-index:1000;background-color:#fff;border:1px solid #cbd5e1;border-radius:10px;padding:12px;position:fixed;box-shadow:0 10px 24px #0f172a1f}.ssg-filter-title{color:#334155;margin-bottom:8px;font-size:12px;font-weight:700}.ssg-filter-hint{color:#64748b;margin-bottom:8px;font-size:11px}.ssg-filter-meta{color:#64748b;margin-bottom:10px;font-size:11px}.ssg-filter-meta--ellipsis{white-space:nowrap;text-overflow:ellipsis;overflow:hidden}.ssg-filter-collecting{text-align:center;color:#64748b;padding:24px;font-size:12px}.ssg-filter-input{box-sizing:border-box;border:1px solid #cbd5e1;border-radius:8px;outline:none;width:100%;margin-bottom:8px;padding:8px 10px}.ssg-filter-select{box-sizing:border-box;background-color:#fff;border:1px solid #cbd5e1;border-radius:8px;outline:none;width:100%;margin-bottom:8px;padding:8px 10px}.ssg-filter-selectall{cursor:pointer;color:#334155;-webkit-user-select:none;user-select:none;border-bottom:1px solid #e2e8f0;align-items:center;gap:8px;height:28px;padding:0 8px;font-size:12px;display:flex}.ssg-filter-selectall-label{font-weight:600}.ssg-filter-list{border:1px solid #e2e8f0;border-top:none;border-radius:0 0 8px 8px;height:208px;margin-bottom:8px;overflow-y:auto}.ssg-filter-empty{color:#94a3b8;text-align:center;padding:12px;font-size:12px}.ssg-filter-virt{width:100%;position:relative}.ssg-filter-option{box-sizing:border-box;cursor:pointer;color:#334155;-webkit-user-select:none;user-select:none;align-items:center;gap:8px;padding:0 8px;font-size:12px;display:flex;position:absolute;top:0;left:0;right:0}.ssg-filter-option-label{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.ssg-filter-footer{justify-content:flex-end;gap:8px;display:flex}.ssg-filter-btn-secondary{color:#475569;cursor:pointer;background-color:#fff;border:1px solid #cbd5e1;border-radius:8px;padding:6px 10px;font-size:12px}.ssg-filter-btn-primary{color:#fff;cursor:pointer;background-color:#2563eb;border:1px solid #2563eb;border-radius:8px;padding:6px 10px;font-size:12px}.ssg-menu-panel{box-sizing:border-box;background-color:#fff;border:1px solid #cbd5e1;border-radius:10px;padding:8px;box-shadow:0 10px 24px #0f172a1f}.ssg-menu-title{color:#334155;text-overflow:ellipsis;white-space:nowrap;-webkit-user-select:none;user-select:none;border-bottom:1px solid #e2e8f0;margin-bottom:4px;padding:2px 8px 6px;font-size:12px;font-weight:700;overflow:hidden}.ssg-menu-item{box-sizing:border-box;color:#334155;text-align:left;cursor:pointer;background-color:#0000;border:none;border-radius:8px;align-items:center;gap:8px;width:100%;padding:7px 8px;font-size:13px;display:flex}.ssg-menu-item:disabled,.ssg-menu-item--disabled{color:#94a3b8;cursor:default}.ssg-menu-item--active,.ssg-menu-item:not(:disabled):not(.ssg-menu-item--disabled):hover{background-color:#f1f5f9}.ssg-menu-section-label{color:#94a3b8;-webkit-user-select:none;user-select:none;padding:6px 8px 2px;font-size:11px;font-weight:600}.ssg-menu-item--danger{color:#dc2626}.ssg-menu-item--danger:not(:disabled):not(.ssg-menu-item--disabled):hover{background-color:#fef2f2}.ssg-menu-submenu-anchor{position:relative}.ssg-menu-icon{text-align:center;flex:none;width:14px}.ssg-menu-sort-icon{text-align:center;color:#94a3b8;flex:none;width:14px;font-weight:400}.ssg-menu-sort-icon--active{color:#2563eb;font-weight:700}.ssg-menu-check{text-align:center;color:#2563eb;flex:none;width:14px;font-weight:700}.ssg-menu-check--hidden{visibility:hidden}.ssg-menu-label{flex:1;min-width:0}.ssg-menu-label--sorted{color:#1d4ed8}.ssg-menu-caret{color:#94a3b8;flex:none;font-size:12px;line-height:1}.ssg-menu-separator{border-top:1px solid #e2e8f0;margin:4px 0}.ssg-menu-note{color:#94a3b8;-webkit-user-select:none;user-select:none;padding:4px 8px 2px;font-size:11px}.ssg-menu-footer{border-top:1px solid #e2e8f0;justify-content:flex-end;margin-top:4px;padding-top:6px;display:flex}.ssg-menu-close-btn{color:#475569;cursor:pointer;background-color:#fff;border:1px solid #cbd5e1;border-radius:8px;padding:5px 10px;font-size:12px}.ssg-body-row{contain:layout style paint;width:100%;position:absolute;top:0;left:0}.ssg-body-row--checked{background-color:var(--ssg-row-selected-bg)}.ssg-body-row--checked .ssg-body-cell:not(.ssg-body-cell--row-hovered){background-color:#0000}.ssg-header-grip{color:#cbd5e1;cursor:grab;touch-action:none;-webkit-user-select:none;user-select:none;flex:none;justify-content:center;align-items:center;width:12px;height:20px;display:inline-flex}.ssg-header-status{flex:none;align-items:center;gap:3px;display:inline-flex}.ssg-header-actions{background-color:var(--ssg-header-bg);opacity:0;pointer-events:none;align-items:center;gap:2px;height:100%;padding:0 6px 0 14px;transition:opacity .1s;display:flex;position:absolute;top:0;right:0}.ssg-header-cell:hover .ssg-header-actions{opacity:1;pointer-events:auto;background-color:var(--ssg-header-hover-bg)}@media (hover:none){.ssg-header-actions{opacity:1;pointer-events:auto;background-color:#0000;height:auto;padding:0;position:static}}.ssg-header-actions .ssg-header-grip,.ssg-header-actions .ssg-icon-btn:not(.ssg-icon-btn--active){color:#475569}.ssg-header-label{min-width:0;color:var(--ssg-header-text);text-overflow:ellipsis;white-space:nowrap;flex:1;overflow:hidden}.ssg-header-label--filtered{color:var(--ssg-accent-strong)}.ssg-header-sort{color:var(--ssg-accent);flex:none;align-items:center;gap:1px;font-size:12px;font-weight:700;line-height:1;display:inline-flex}.ssg-header-sort-priority{font-size:9px;font-weight:700;line-height:1}.ssg-header-filtered-mark{color:var(--ssg-accent-strong);flex:none;align-items:center;display:inline-flex}.ssg-header-resize{cursor:col-resize;z-index:3;width:6px;height:100%;position:absolute;top:0;right:-3px}.ssg-skeleton-rowheader{color:#94a3b8}.ssg-skeleton-bar{background-color:#e2e8f0;border-radius:4px;height:10px}.ssg-shell{background-color:var(--ssg-cell-bg);position:relative;overflow:hidden}.ssg-scroll-container{max-height:480px;position:relative;overflow:auto}.ssg-inner-row{display:flex}.ssg-center-pane{z-index:1;flex-shrink:0;position:relative}.ssg-empty-state{color:#94a3b8;-webkit-user-select:none;user-select:none;justify-content:center;align-items:center;height:160px;font-size:13px;display:flex;position:sticky;left:0}.ssg-autosize-overlay{pointer-events:none;z-index:5;justify-content:center;align-items:center;display:flex;position:absolute;inset:0}.ssg-autosize-pill{color:#f8fafc;-webkit-user-select:none;user-select:none;background-color:#0f172ad1;border-radius:8px;padding:8px 14px;font-size:13px;font-weight:600;box-shadow:0 6px 20px #0f172a40}.ssg-filter-overlay{pointer-events:none;z-index:5;justify-content:center;align-items:center;display:flex;position:absolute;inset:0}.ssg-filter-overlay-chip{background-color:var(--ssg-cell-bg);border:1px solid var(--ssg-line-strong);color:var(--ssg-readonly-text);font-variant-numeric:tabular-nums;white-space:nowrap;-webkit-user-select:none;user-select:none;border-radius:999px;align-items:center;gap:8px;padding:6px 12px;font-size:12px;display:inline-flex;box-shadow:0 6px 20px #0f172a2e}.ssg-filter-overlay-text{text-align:center;min-width:5.5em}.ssg-filter-spinner{border:2px solid var(--ssg-line-strong);border-top-color:var(--ssg-accent);border-radius:50%;width:14px;height:14px;animation:.7s linear infinite ssg-filter-spin}@keyframes ssg-filter-spin{to{transform:rotate(360deg)}}@media (prefers-reduced-motion:reduce){.ssg-filter-spinner{animation:none}}.ssg-col-drop-indicator{background-color:#0f172a;width:2px}.ssg-col-drop-indicator:before,.ssg-col-drop-indicator:after{content:"";background-color:#0f172a;width:7px;height:7px;position:absolute;left:50%;transform:translate(-50%)rotate(45deg)}.ssg-col-drop-indicator:before{top:-3px}.ssg-col-drop-indicator:after{bottom:-3px}}
|
|
2
2
|
/*$vite$:1*/
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { RefObject } from 'react';
|
|
2
|
+
import type { GridContextMenuItem } from '../model/gridTypes';
|
|
3
|
+
import type { CellContextMenuLayout } from '../hooks/useCellContextMenuController';
|
|
4
|
+
type CellContextMenuPopoverProps = {
|
|
5
|
+
isOpen: boolean;
|
|
6
|
+
items: GridContextMenuItem[];
|
|
7
|
+
layout: CellContextMenuLayout | null;
|
|
8
|
+
popoverRef: RefObject<HTMLDivElement | null>;
|
|
9
|
+
onRequestClose: () => void;
|
|
10
|
+
};
|
|
11
|
+
export declare function CellContextMenuPopover({ isOpen, items, layout, popoverRef, onRequestClose, }: CellContextMenuPopoverProps): import("react").ReactPortal | null;
|
|
12
|
+
export default CellContextMenuPopover;
|
|
@@ -1,9 +1,12 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
1
2
|
import type { SpreadsheetGridSlotContext } from '../model/gridTypes';
|
|
2
3
|
type DefaultGridTopBarProps<T> = {
|
|
3
4
|
context: SpreadsheetGridSlotContext<T>;
|
|
4
5
|
showSummary?: boolean;
|
|
5
6
|
showFilter?: boolean;
|
|
6
7
|
showCounts?: boolean;
|
|
8
|
+
globalFilterPlaceholder?: string;
|
|
9
|
+
globalFilterIcon?: ReactNode;
|
|
7
10
|
};
|
|
8
|
-
export declare function DefaultGridTopBar<T>({ context, showSummary, showFilter, showCounts, }: DefaultGridTopBarProps<T>): import("react").JSX.Element;
|
|
11
|
+
export declare function DefaultGridTopBar<T>({ context, showSummary, showFilter, showCounts, globalFilterPlaceholder, globalFilterIcon, }: DefaultGridTopBarProps<T>): import("react").JSX.Element;
|
|
9
12
|
export default DefaultGridTopBar;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { CSSProperties, PointerEvent, ReactNode } from 'react';
|
|
2
2
|
import type { SelectionSnapshot } from '../model/gridSelectors';
|
|
3
|
-
import type { CellCoord, CellRenderState, GridColumn, RowModel, SpreadsheetGridProps } from '../model/gridTypes';
|
|
3
|
+
import type { CellCoord, CellRenderState, GridColumn, RowModel, RowSelectionState, SpreadsheetGridProps } from '../model/gridTypes';
|
|
4
4
|
import type { PaneColumnEntry } from '../logic/geometry';
|
|
5
5
|
import type { GridPaneKind } from './GridHeaderRow';
|
|
6
6
|
type VirtualRowLike = {
|
|
@@ -22,6 +22,8 @@ type GridBodyLayerProps<T> = {
|
|
|
22
22
|
rowHeaderCellStyle: CSSProperties;
|
|
23
23
|
hoveredRowIndex: number | null;
|
|
24
24
|
isWholeGridSelected: boolean;
|
|
25
|
+
enableRowSelection: boolean;
|
|
26
|
+
rowSelectionState: RowSelectionState;
|
|
25
27
|
activeCell: CellCoord | null;
|
|
26
28
|
editingCell: CellCoord | null;
|
|
27
29
|
selectionSnapshot: SelectionSnapshot;
|
|
@@ -39,5 +41,5 @@ type GridBodyLayerProps<T> = {
|
|
|
39
41
|
bodyRowClassName?: string;
|
|
40
42
|
rowHeaderCellClassName?: string;
|
|
41
43
|
};
|
|
42
|
-
export declare function GridBodyLayer<T>({ pane, ownsRowHeader, leadingWidth, rowModel, virtualRows, virtualRowIndexes, renderEntries, rowHeight, autoHeight, isServerSide, rowHeaderCellStyle, hoveredRowIndex, isWholeGridSelected, activeCell, editingCell, selectionSnapshot, readOnly, canEditCell, onRowHeaderPointerDown, onRowHeaderPointerEnter, onRowHeaderPointerLeave, onCellPointerDown, onCellPointerEnter, onCellDoubleClick, renderCellContent, getRowClassName, bodyCellClassName, bodyRowClassName, rowHeaderCellClassName, }: GridBodyLayerProps<T>): import("react").JSX.Element;
|
|
44
|
+
export declare function GridBodyLayer<T>({ pane, ownsRowHeader, leadingWidth, rowModel, virtualRows, virtualRowIndexes, renderEntries, rowHeight, autoHeight, isServerSide, rowHeaderCellStyle, hoveredRowIndex, isWholeGridSelected, enableRowSelection, rowSelectionState, activeCell, editingCell, selectionSnapshot, readOnly, canEditCell, onRowHeaderPointerDown, onRowHeaderPointerEnter, onRowHeaderPointerLeave, onCellPointerDown, onCellPointerEnter, onCellDoubleClick, renderCellContent, getRowClassName, bodyCellClassName, bodyRowClassName, rowHeaderCellClassName, }: GridBodyLayerProps<T>): import("react").JSX.Element;
|
|
43
45
|
export default GridBodyLayer;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type CSSProperties, type MouseEvent, type PointerEvent } from 'react';
|
|
2
2
|
import type { SelectionSnapshot } from '../model/gridSelectors';
|
|
3
|
-
import type { ColumnFilterValue, GridColumn, GridSortState } from '../model/gridTypes';
|
|
3
|
+
import type { ColumnFilterValue, GridColumn, GridSortState, SelectAllState } from '../model/gridTypes';
|
|
4
4
|
import type { PaneColumnEntry } from '../logic/geometry';
|
|
5
5
|
export type GridPaneKind = 'left' | 'center' | 'right';
|
|
6
6
|
type GridHeaderRowProps<T> = {
|
|
@@ -14,6 +14,8 @@ type GridHeaderRowProps<T> = {
|
|
|
14
14
|
rowHeaderCellClassName?: string;
|
|
15
15
|
isCornerHovered: boolean;
|
|
16
16
|
isWholeGridSelected: boolean;
|
|
17
|
+
showSelectAllCheckbox: boolean;
|
|
18
|
+
selectAllState: SelectAllState;
|
|
17
19
|
filteredRowsLength: number;
|
|
18
20
|
visibleColumnsLength: number;
|
|
19
21
|
renderEntries: PaneColumnEntry<T>[];
|
|
@@ -36,6 +38,6 @@ type GridHeaderRowProps<T> = {
|
|
|
36
38
|
onColumnHeaderContextMenu: (column: GridColumn<T>, event: MouseEvent<HTMLDivElement>) => void;
|
|
37
39
|
onColumnDragHandlePointerDown?: (column: GridColumn<T>, event: PointerEvent<HTMLSpanElement>) => void;
|
|
38
40
|
};
|
|
39
|
-
declare function GridHeaderRowInner<T>({ pane, ownsRowHeader, leadingWidth, headerHeight, rowHeaderCellStyle, headerRowClassName, headerCellClassName, rowHeaderCellClassName, isCornerHovered, isWholeGridSelected, filteredRowsLength, visibleColumnsLength, renderEntries, hoveredColumnIndex, selectionSnapshot, columnFilterValues, sortState, iconButtonClassName, onCornerPointerDown, onCornerPointerEnter, onCornerPointerLeave, onColumnHeaderPointerDown, onColumnHeaderPointerEnter, onColumnHeaderPointerLeave, onColumnResizePointerDown, enableColumnResize, enableColumnMenu, openedMenuColumnKey, onColumnMenuButtonPointerDown, onColumnHeaderContextMenu, onColumnDragHandlePointerDown, }: GridHeaderRowProps<T>): import("react").JSX.Element;
|
|
41
|
+
declare function GridHeaderRowInner<T>({ pane, ownsRowHeader, leadingWidth, headerHeight, rowHeaderCellStyle, headerRowClassName, headerCellClassName, rowHeaderCellClassName, isCornerHovered, isWholeGridSelected, showSelectAllCheckbox, selectAllState, filteredRowsLength, visibleColumnsLength, renderEntries, hoveredColumnIndex, selectionSnapshot, columnFilterValues, sortState, iconButtonClassName, onCornerPointerDown, onCornerPointerEnter, onCornerPointerLeave, onColumnHeaderPointerDown, onColumnHeaderPointerEnter, onColumnHeaderPointerLeave, onColumnResizePointerDown, enableColumnResize, enableColumnMenu, openedMenuColumnKey, onColumnMenuButtonPointerDown, onColumnHeaderContextMenu, onColumnDragHandlePointerDown, }: GridHeaderRowProps<T>): import("react").JSX.Element;
|
|
40
42
|
export declare const GridHeaderRow: typeof GridHeaderRowInner;
|
|
41
43
|
export default GridHeaderRow;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export type RowCheckboxState = 'unchecked' | 'checked' | 'indeterminate';
|
|
2
|
+
type RowSelectionCheckboxProps = {
|
|
3
|
+
state: RowCheckboxState;
|
|
4
|
+
disabled?: boolean;
|
|
5
|
+
};
|
|
6
|
+
declare function RowSelectionCheckboxInner({ state, disabled, }: RowSelectionCheckboxProps): import("react").JSX.Element;
|
|
7
|
+
export declare const RowSelectionCheckbox: import("react").MemoExoticComponent<typeof RowSelectionCheckboxInner>;
|
|
8
|
+
export default RowSelectionCheckbox;
|