@c-time/simple-ex-grid 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +208 -0
- package/dist/SimpleExGrid.d.ts +3 -0
- package/dist/__tests__/setup.d.ts +1 -0
- package/dist/components/CellEditor.d.ts +9 -0
- package/dist/components/ContextMenu.d.ts +17 -0
- package/dist/hooks/useClipboard.d.ts +29 -0
- package/dist/hooks/useEditing.d.ts +30 -0
- package/dist/hooks/useGripSelection.d.ts +15 -0
- package/dist/hooks/useHistory.d.ts +27 -0
- package/dist/hooks/useKeyboardNavigation.d.ts +14 -0
- package/dist/hooks/useOverlayScrollbar.d.ts +18 -0
- package/dist/hooks/usePagination.d.ts +22 -0
- package/dist/hooks/usePointerSelection.d.ts +14 -0
- package/dist/hooks/useSelection.d.ts +37 -0
- package/dist/index.cjs +5 -0
- package/dist/index.css +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1525 -0
- package/dist/types.d.ts +84 -0
- package/dist/utils/colspan.d.ts +33 -0
- package/dist/utils/html.d.ts +9 -0
- package/dist/utils/tsv.d.ts +8 -0
- package/package.json +66 -0
package/README.md
ADDED
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
# @c-time/simple-ex-grid
|
|
2
|
+
|
|
3
|
+
Excel-like grid component for React. Touch-first design with clipboard support, drag selection, and three operating modes.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @c-time/simple-ex-grid
|
|
9
|
+
# or
|
|
10
|
+
pnpm add @c-time/simple-ex-grid
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
**Peer dependencies:** React 19+
|
|
14
|
+
|
|
15
|
+
## Quick Start
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
import { SimpleExGrid } from '@c-time/simple-ex-grid'
|
|
19
|
+
import type { ColumnDef } from '@c-time/simple-ex-grid'
|
|
20
|
+
|
|
21
|
+
interface Row {
|
|
22
|
+
id: number
|
|
23
|
+
name: string
|
|
24
|
+
price: number
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const columns: ColumnDef<Row>[] = [
|
|
28
|
+
{ key: 'id', header: 'ID', width: 60, editable: false },
|
|
29
|
+
{ key: 'name', header: 'Name', width: 200 },
|
|
30
|
+
{ key: 'price', header: 'Price', width: 120, parser: (s) => Number(s) || 0 },
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
function App() {
|
|
34
|
+
const [rows, setRows] = useState<Row[]>([
|
|
35
|
+
{ id: 1, name: 'Item A', price: 100 },
|
|
36
|
+
{ id: 2, name: 'Item B', price: 200 },
|
|
37
|
+
])
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<SimpleExGrid
|
|
41
|
+
rows={rows}
|
|
42
|
+
columns={columns}
|
|
43
|
+
mode="edit"
|
|
44
|
+
onChange={setRows}
|
|
45
|
+
/>
|
|
46
|
+
)
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Modes
|
|
51
|
+
|
|
52
|
+
| Mode | Description |
|
|
53
|
+
|------|-------------|
|
|
54
|
+
| `select` (default) | Selection and copy/paste only. No cell editing. |
|
|
55
|
+
| `edit` | Re-tap active cell or press Enter/F2 to start editing. |
|
|
56
|
+
| `readonly` | Selection and copy only. All mutations disabled. |
|
|
57
|
+
|
|
58
|
+
## Props
|
|
59
|
+
|
|
60
|
+
### Data
|
|
61
|
+
|
|
62
|
+
| Prop | Type | Default | Description |
|
|
63
|
+
|------|------|---------|-------------|
|
|
64
|
+
| `rows` | `Row[]` | required | Row data array |
|
|
65
|
+
| `columns` | `ColumnDef<Row>[]` | required | Column definitions |
|
|
66
|
+
| `onChange` | `(rows, changes) => void` | - | Called when cell values change |
|
|
67
|
+
|
|
68
|
+
### Mode & Display
|
|
69
|
+
|
|
70
|
+
| Prop | Type | Default | Description |
|
|
71
|
+
|------|------|---------|-------------|
|
|
72
|
+
| `mode` | `'select' \| 'edit' \| 'readonly'` | `'select'` | Operating mode |
|
|
73
|
+
| `showRowGripHeader` | `boolean` | `true` | Show row grip headers (left) |
|
|
74
|
+
| `showColumnGripHeader` | `boolean` | `true` | Show column grip headers (top) |
|
|
75
|
+
| `rowHeight` | `'single-line' \| 'fit-content'` | `'single-line'` | `single-line`: truncate with ellipsis. `fit-content`: wrap text |
|
|
76
|
+
|
|
77
|
+
### Column Definition
|
|
78
|
+
|
|
79
|
+
| Property | Type | Default | Description |
|
|
80
|
+
|----------|------|---------|-------------|
|
|
81
|
+
| `key` | `keyof Row & string` | required | Row property key |
|
|
82
|
+
| `header` | `string` | required | Header display text |
|
|
83
|
+
| `width` | `number \| '${n}%' \| 'fit-content'` | `120` | Column width. Fixed px, percentage, or auto |
|
|
84
|
+
| `editable` | `boolean` | `true` | Set `false` to make column read-only |
|
|
85
|
+
| `formatter` | `(value, row) => string` | - | Display formatter |
|
|
86
|
+
| `parser` | `(input) => unknown` | - | Input parser (string to value) |
|
|
87
|
+
| `validator` | `(value) => string \| null` | - | Validation (return error message or null) |
|
|
88
|
+
| `sortMark` | `'asc' \| 'desc' \| null` | `null` | Display sort indicator (▲/▼) in header. Display only — sorting logic is the caller's responsibility. |
|
|
89
|
+
| `align` | `'left' \| 'center' \| 'right'` | - | Default text alignment for the column |
|
|
90
|
+
| `headerAlign` | `'left' \| 'center' \| 'right'` | - | Header text alignment (overrides `align`) |
|
|
91
|
+
| `hidden` | `boolean` | `false` | Hide column visually. Hidden columns are still included in clipboard operations. |
|
|
92
|
+
| `render` | `(value, row, rowIndex) => ReactNode` | - | Custom cell renderer. Returned node replaces default text display. |
|
|
93
|
+
|
|
94
|
+
### Pagination
|
|
95
|
+
|
|
96
|
+
| Prop | Type | Default | Description |
|
|
97
|
+
|------|------|---------|-------------|
|
|
98
|
+
| `pagination` | `boolean` | `false` | Enable pagination UI |
|
|
99
|
+
| `pageSize` | `number` | `20` | Rows per page |
|
|
100
|
+
| `page` | `number` | - | Controlled current page (0-indexed) |
|
|
101
|
+
| `onPageChange` | `(page) => void` | - | Page change callback |
|
|
102
|
+
| `onPageSizeChange` | `(pageSize) => void` | - | Page size change callback |
|
|
103
|
+
|
|
104
|
+
### Selection
|
|
105
|
+
|
|
106
|
+
| Prop | Type | Default | Description |
|
|
107
|
+
|------|------|---------|-------------|
|
|
108
|
+
| `selection` | `CellRange \| null` | - | Controlled selection range |
|
|
109
|
+
| `onSelectionChange` | `(range) => void` | - | Selection change callback |
|
|
110
|
+
| `onActiveCellChange` | `(row, col) => void` | - | Active cell move callback |
|
|
111
|
+
|
|
112
|
+
### Clipboard
|
|
113
|
+
|
|
114
|
+
| Prop | Type | Default | Description |
|
|
115
|
+
|------|------|---------|-------------|
|
|
116
|
+
| `clipboard.enabled` | `boolean` | `true` | Enable clipboard operations |
|
|
117
|
+
| `clipboard.format` | `'tsv' \| 'html' \| 'both'` | `'both'` | Clipboard data format |
|
|
118
|
+
|
|
119
|
+
Keyboard shortcuts: `Ctrl+C` copy, `Ctrl+X` cut, `Ctrl+V` insert paste (add rows), `Ctrl+Shift+V` overwrite paste.
|
|
120
|
+
|
|
121
|
+
### Cell Layout
|
|
122
|
+
|
|
123
|
+
| Prop | Type | Default | Description |
|
|
124
|
+
|------|------|---------|-------------|
|
|
125
|
+
| `colSpan` | `(row, col) => number` | - | Return column span for a cell. Spanned cells are merged visually. |
|
|
126
|
+
| `cellAlign` | `(row, col) => 'left' \| 'center' \| 'right' \| undefined` | - | Per-cell text alignment override (takes priority over column `align`). |
|
|
127
|
+
|
|
128
|
+
### Row Mutation
|
|
129
|
+
|
|
130
|
+
| Prop | Type | Default | Description |
|
|
131
|
+
|------|------|---------|-------------|
|
|
132
|
+
| `allowRowAdd` | `boolean` | `false` | Allow adding rows (paste auto-extend, insert paste) |
|
|
133
|
+
| `allowRowDelete` | `boolean` | `false` | Allow deleting rows (context menu) |
|
|
134
|
+
| `onRowsAdd` | `(startRow, count) => void` | - | Fires after rows are added |
|
|
135
|
+
| `onRowsDelete` | `(startRow, count) => void` | - | Fires after rows are deleted |
|
|
136
|
+
|
|
137
|
+
### Undo / Redo
|
|
138
|
+
|
|
139
|
+
| Prop | Type | Default | Description |
|
|
140
|
+
|------|------|---------|-------------|
|
|
141
|
+
| `maxHistory` | `number` | - | Maximum number of history entries to keep |
|
|
142
|
+
| `shouldRecordHistory` | `(changes, rowEvent?) => boolean` | - | Filter which mutations are recorded. `rowEvent` is `{ kind, startRow, count }` for row add/delete. |
|
|
143
|
+
| `historyApiRef` | `React.MutableRefObject<HistoryApi<Row>>` | - | Ref to access undo/redo API externally |
|
|
144
|
+
|
|
145
|
+
`HistoryApi<Row>` exposes `undo()`, `redo()`, `canUndo`, `canRedo`, and `pushHistory(before, after)`.
|
|
146
|
+
|
|
147
|
+
Keyboard shortcuts: `Ctrl+Z` undo, `Ctrl+Y` / `Ctrl+Shift+Z` redo.
|
|
148
|
+
|
|
149
|
+
### Editing Lifecycle
|
|
150
|
+
|
|
151
|
+
| Prop | Type | Description |
|
|
152
|
+
|------|------|-------------|
|
|
153
|
+
| `onEditStart` | `(row, col) => boolean \| void` | Fires when editing begins. Return `false` to cancel. |
|
|
154
|
+
| `onEditCommit` | `(row, col, before, after) => boolean \| void` | Fires on edit confirm. Return `false` to prevent write. |
|
|
155
|
+
| `onEditCancel` | `(row, col) => void` | Fires when editing is cancelled (Escape). |
|
|
156
|
+
|
|
157
|
+
## Features
|
|
158
|
+
|
|
159
|
+
### Selection
|
|
160
|
+
|
|
161
|
+
- Click to select, Shift+Click to extend range, drag for rectangle selection
|
|
162
|
+
- Arrow keys to navigate, Tab to move right (wraps), Shift+Tab to move left
|
|
163
|
+
- `Ctrl+A` to select all, `Escape` to clear selection
|
|
164
|
+
- Grip headers: click to select entire row/column, drag to extend
|
|
165
|
+
|
|
166
|
+
### Editing (edit mode)
|
|
167
|
+
|
|
168
|
+
- Re-tap active cell, press Enter, F2, or type a character to begin editing
|
|
169
|
+
- Enter commits and moves down, Tab commits and moves right, Escape cancels
|
|
170
|
+
- Double-click also starts editing in any writable mode
|
|
171
|
+
|
|
172
|
+
### Clipboard
|
|
173
|
+
|
|
174
|
+
- Copy/cut/paste with Excel-compatible TSV + HTML table format
|
|
175
|
+
- Paste auto-extends rows when `allowRowAdd` is enabled
|
|
176
|
+
- Insert paste (`Ctrl+V`) inserts new rows at selection position
|
|
177
|
+
- Overwrite paste (`Ctrl+Shift+V`) overwrites existing cells
|
|
178
|
+
- `Ctrl+I` insert rows, `Ctrl+D` delete selected rows
|
|
179
|
+
- Right-click context menu for all clipboard and row operations
|
|
180
|
+
- Undo/redo (`Ctrl+Z` / `Ctrl+Y`) tracks all cell edits, paste, and row operations
|
|
181
|
+
|
|
182
|
+
### Touch Support
|
|
183
|
+
|
|
184
|
+
- Pointer Events API for unified mouse/touch/pen handling
|
|
185
|
+
- `setPointerCapture` for reliable touch drag selection
|
|
186
|
+
- Long-press opens context menu without losing selection (deferred selection pattern)
|
|
187
|
+
|
|
188
|
+
### Layout
|
|
189
|
+
|
|
190
|
+
- Sticky grip headers (row headers stick left, column headers stick top)
|
|
191
|
+
- Custom overlay scrollbars (no layout shift from native scrollbar appearance)
|
|
192
|
+
- Works in fixed-size containers, percentage-based layouts, and unconstrained layouts
|
|
193
|
+
- Flex-based scroll structure handles both constrained and auto-sized parents
|
|
194
|
+
|
|
195
|
+
## Development
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
pnpm install
|
|
199
|
+
pnpm dev # Storybook dev server
|
|
200
|
+
pnpm test # Vitest
|
|
201
|
+
pnpm typecheck # TypeScript
|
|
202
|
+
pnpm lint # ESLint
|
|
203
|
+
pnpm build # Vite library build
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
## License
|
|
207
|
+
|
|
208
|
+
MIT
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import '@testing-library/jest-dom/vitest';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
interface CellEditorProps {
|
|
2
|
+
value: string;
|
|
3
|
+
onChange: (value: string) => void;
|
|
4
|
+
onCommit: () => void;
|
|
5
|
+
onCancel: () => void;
|
|
6
|
+
onKeyDown: (e: React.KeyboardEvent) => void;
|
|
7
|
+
}
|
|
8
|
+
export declare function CellEditor({ value, onChange, onCommit, onKeyDown }: CellEditorProps): import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export type ContextMenuItem = {
|
|
2
|
+
type?: 'item';
|
|
3
|
+
label: string;
|
|
4
|
+
shortcut?: string;
|
|
5
|
+
disabled?: boolean;
|
|
6
|
+
onClick: () => void;
|
|
7
|
+
} | {
|
|
8
|
+
type: 'separator';
|
|
9
|
+
};
|
|
10
|
+
interface ContextMenuProps {
|
|
11
|
+
x: number;
|
|
12
|
+
y: number;
|
|
13
|
+
items: ContextMenuItem[];
|
|
14
|
+
onClose: () => void;
|
|
15
|
+
}
|
|
16
|
+
export declare function ContextMenu({ x, y, items, onClose }: ContextMenuProps): import("react/jsx-runtime").JSX.Element;
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { GridMode, ColumnDef, CellChange } from '../types';
|
|
2
|
+
import type { SelectionState } from './useSelection';
|
|
3
|
+
import type { ColSpanGetter } from '../utils/colspan';
|
|
4
|
+
interface UseClipboardOptions<Row> {
|
|
5
|
+
rows: Row[];
|
|
6
|
+
columns: ColumnDef<Row>[];
|
|
7
|
+
mode: GridMode;
|
|
8
|
+
selection: SelectionState;
|
|
9
|
+
onChange?: (next: Row[], changes: CellChange[]) => void;
|
|
10
|
+
clipboardFormat: 'tsv' | 'html' | 'both';
|
|
11
|
+
allowRowAdd: boolean;
|
|
12
|
+
allowRowDelete: boolean;
|
|
13
|
+
onRowsAdd?: (startRow: number, count: number) => void;
|
|
14
|
+
onRowsDelete?: (startRow: number, count: number) => void;
|
|
15
|
+
colSpan?: ColSpanGetter;
|
|
16
|
+
}
|
|
17
|
+
export interface ClipboardActions {
|
|
18
|
+
copy: () => Promise<void>;
|
|
19
|
+
cut: () => Promise<void>;
|
|
20
|
+
paste: () => Promise<void>;
|
|
21
|
+
pasteInsert: () => Promise<void>;
|
|
22
|
+
addRows: () => void;
|
|
23
|
+
deleteRows: () => void;
|
|
24
|
+
hasSelection: boolean;
|
|
25
|
+
allowRowAdd: boolean;
|
|
26
|
+
allowRowDelete: boolean;
|
|
27
|
+
}
|
|
28
|
+
export declare function useClipboard<Row>(options: UseClipboardOptions<Row>): ClipboardActions;
|
|
29
|
+
export {};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { GridMode, ColumnDef, CellChange } from '../types';
|
|
2
|
+
interface UseEditingOptions<Row> {
|
|
3
|
+
rows: Row[];
|
|
4
|
+
columns: ColumnDef<Row>[];
|
|
5
|
+
mode: GridMode;
|
|
6
|
+
activeCell: {
|
|
7
|
+
row: number;
|
|
8
|
+
col: number;
|
|
9
|
+
} | null;
|
|
10
|
+
onChange?: (next: Row[], changes: CellChange[]) => void;
|
|
11
|
+
onCommitMove: (dRow: number, dCol: number) => void;
|
|
12
|
+
onEditStart?: (row: number, col: number) => boolean | void;
|
|
13
|
+
onEditCommit?: (row: number, col: number, before: unknown, after: unknown) => boolean | void;
|
|
14
|
+
onEditCancel?: (row: number, col: number) => void;
|
|
15
|
+
}
|
|
16
|
+
export interface EditingState {
|
|
17
|
+
editingCell: {
|
|
18
|
+
row: number;
|
|
19
|
+
col: number;
|
|
20
|
+
} | null;
|
|
21
|
+
editValue: string;
|
|
22
|
+
setEditValue: (value: string) => void;
|
|
23
|
+
startEditing: (row: number, col: number, initialChar?: string) => void;
|
|
24
|
+
commitEdit: () => void;
|
|
25
|
+
cancelEdit: () => void;
|
|
26
|
+
isEditing: (row: number, col: number) => boolean;
|
|
27
|
+
onEditorKeyDown: (e: React.KeyboardEvent) => void;
|
|
28
|
+
}
|
|
29
|
+
export declare function useEditing<Row>(options: UseEditingOptions<Row>): EditingState;
|
|
30
|
+
export {};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { SelectionState } from './useSelection';
|
|
2
|
+
interface UseGripSelectionOptions {
|
|
3
|
+
selection: SelectionState;
|
|
4
|
+
rowCount: number;
|
|
5
|
+
colCount: number;
|
|
6
|
+
}
|
|
7
|
+
export declare function useGripSelection(options: UseGripSelectionOptions): {
|
|
8
|
+
onRowGripPointerDown: (e: React.PointerEvent) => void;
|
|
9
|
+
onRowGripPointerMove: (e: React.PointerEvent) => void;
|
|
10
|
+
onRowGripPointerUp: (e: React.PointerEvent) => void;
|
|
11
|
+
onColGripPointerDown: (e: React.PointerEvent) => void;
|
|
12
|
+
onColGripPointerMove: (e: React.PointerEvent) => void;
|
|
13
|
+
onColGripPointerUp: (e: React.PointerEvent) => void;
|
|
14
|
+
};
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { CellChange, HistoryApi } from '../types';
|
|
2
|
+
import type { SelectionState } from './useSelection';
|
|
3
|
+
interface UseHistoryOptions<Row> {
|
|
4
|
+
rows: Row[];
|
|
5
|
+
selection: SelectionState;
|
|
6
|
+
onChange?: (next: Row[], changes: CellChange[]) => void;
|
|
7
|
+
onRowsAdd?: (startRow: number, count: number) => void;
|
|
8
|
+
onRowsDelete?: (startRow: number, count: number) => void;
|
|
9
|
+
maxHistory: number;
|
|
10
|
+
shouldRecordHistory?: (changes: CellChange[], rowEvent?: {
|
|
11
|
+
kind: 'add' | 'delete';
|
|
12
|
+
startRow: number;
|
|
13
|
+
count: number;
|
|
14
|
+
}) => boolean;
|
|
15
|
+
historyApiRef?: React.MutableRefObject<HistoryApi<Row> | null>;
|
|
16
|
+
}
|
|
17
|
+
export interface HistoryActions<Row> {
|
|
18
|
+
wrappedOnChange: (next: Row[], changes: CellChange[]) => void;
|
|
19
|
+
wrappedOnRowsAdd: (startRow: number, count: number) => void;
|
|
20
|
+
wrappedOnRowsDelete: (startRow: number, count: number) => void;
|
|
21
|
+
undo: () => void;
|
|
22
|
+
redo: () => void;
|
|
23
|
+
canUndo: boolean;
|
|
24
|
+
canRedo: boolean;
|
|
25
|
+
}
|
|
26
|
+
export declare function useHistory<Row>(options: UseHistoryOptions<Row>): HistoryActions<Row>;
|
|
27
|
+
export {};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { GridMode } from '../types';
|
|
2
|
+
import type { SelectionState } from './useSelection';
|
|
3
|
+
import type { EditingState } from './useEditing';
|
|
4
|
+
interface UseKeyboardNavigationOptions {
|
|
5
|
+
selection: SelectionState;
|
|
6
|
+
editing: EditingState;
|
|
7
|
+
mode: GridMode;
|
|
8
|
+
rowCount: number;
|
|
9
|
+
colCount: number;
|
|
10
|
+
}
|
|
11
|
+
export declare function useKeyboardNavigation(options: UseKeyboardNavigationOptions): {
|
|
12
|
+
onKeyDown: (e: React.KeyboardEvent) => void;
|
|
13
|
+
};
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
interface ScrollbarState {
|
|
2
|
+
vTop: number;
|
|
3
|
+
vHeight: number;
|
|
4
|
+
showV: boolean;
|
|
5
|
+
hLeft: number;
|
|
6
|
+
hWidth: number;
|
|
7
|
+
showH: boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare function useOverlayScrollbar(): {
|
|
10
|
+
scrollRef: import("react").RefObject<HTMLDivElement | null>;
|
|
11
|
+
areaRef: import("react").RefObject<HTMLDivElement | null>;
|
|
12
|
+
state: ScrollbarState;
|
|
13
|
+
onVBarPointerDown: (e: React.PointerEvent) => void;
|
|
14
|
+
onHBarPointerDown: (e: React.PointerEvent) => void;
|
|
15
|
+
onBarPointerMove: (e: React.PointerEvent) => void;
|
|
16
|
+
onBarPointerUp: (e: React.PointerEvent) => void;
|
|
17
|
+
};
|
|
18
|
+
export {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
interface UsePaginationOptions {
|
|
2
|
+
totalRows: number;
|
|
3
|
+
pageSize: number;
|
|
4
|
+
page?: number;
|
|
5
|
+
onPageChange?: (page: number) => void;
|
|
6
|
+
onPageSizeChange?: (pageSize: number) => void;
|
|
7
|
+
}
|
|
8
|
+
export interface PaginationState {
|
|
9
|
+
currentPage: number;
|
|
10
|
+
pageSize: number;
|
|
11
|
+
totalPages: number;
|
|
12
|
+
startRow: number;
|
|
13
|
+
endRow: number;
|
|
14
|
+
setPage: (page: number) => void;
|
|
15
|
+
setPageSize: (size: number) => void;
|
|
16
|
+
goFirst: () => void;
|
|
17
|
+
goPrev: () => void;
|
|
18
|
+
goNext: () => void;
|
|
19
|
+
goLast: () => void;
|
|
20
|
+
}
|
|
21
|
+
export declare function usePagination(options: UsePaginationOptions): PaginationState;
|
|
22
|
+
export {};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { GridMode } from '../types';
|
|
2
|
+
import type { SelectionState } from './useSelection';
|
|
3
|
+
import type { EditingState } from './useEditing';
|
|
4
|
+
interface UsePointerSelectionOptions {
|
|
5
|
+
mode: GridMode;
|
|
6
|
+
selection: SelectionState;
|
|
7
|
+
editing: EditingState;
|
|
8
|
+
}
|
|
9
|
+
export declare function usePointerSelection(options: UsePointerSelectionOptions): {
|
|
10
|
+
onPointerDown: (e: React.PointerEvent) => void;
|
|
11
|
+
onPointerMove: (e: React.PointerEvent) => void;
|
|
12
|
+
onPointerUp: (e: React.PointerEvent) => void;
|
|
13
|
+
};
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { CellRange } from '../types';
|
|
2
|
+
import type { ColSpanGetter } from '../utils/colspan';
|
|
3
|
+
interface UseSelectionOptions {
|
|
4
|
+
rowCount: number;
|
|
5
|
+
colCount: number;
|
|
6
|
+
selection?: CellRange | null;
|
|
7
|
+
onSelectionChange?: (range: CellRange | null) => void;
|
|
8
|
+
onActiveCellChange?: (row: number, col: number) => void;
|
|
9
|
+
colSpan?: ColSpanGetter;
|
|
10
|
+
hiddenColumns?: Set<number>;
|
|
11
|
+
}
|
|
12
|
+
export interface SelectionState {
|
|
13
|
+
activeCell: {
|
|
14
|
+
row: number;
|
|
15
|
+
col: number;
|
|
16
|
+
} | null;
|
|
17
|
+
selectionRange: CellRange | null;
|
|
18
|
+
selectCell: (row: number, col: number) => void;
|
|
19
|
+
extendSelection: (row: number, col: number) => void;
|
|
20
|
+
setRangeEnd: (row: number, col: number) => void;
|
|
21
|
+
selectAll: () => void;
|
|
22
|
+
clearSelection: () => void;
|
|
23
|
+
moveActiveCell: (dRow: number, dCol: number) => void;
|
|
24
|
+
moveActiveCellTo: (row: number, col: number) => void;
|
|
25
|
+
isSelected: (row: number, col: number) => boolean;
|
|
26
|
+
isActiveCell: (row: number, col: number) => boolean;
|
|
27
|
+
selectEntireRow: (row: number) => void;
|
|
28
|
+
selectEntireCol: (col: number) => void;
|
|
29
|
+
extendRowSelection: (row: number) => void;
|
|
30
|
+
extendColSelection: (col: number) => void;
|
|
31
|
+
restoreSelection: (range: CellRange | null, activeCell: {
|
|
32
|
+
row: number;
|
|
33
|
+
col: number;
|
|
34
|
+
} | null) => void;
|
|
35
|
+
}
|
|
36
|
+
export declare function useSelection(options: UseSelectionOptions): SelectionState;
|
|
37
|
+
export {};
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require(`react`),t=require(`react/jsx-runtime`);function n(e,t,n,r){let i=0;for(;i<n&&i<=t;){let a=Math.max(1,Math.min(r(e,i),n-i));if(t<i+a)return i;i+=a}return t}function r(e,t,r,i){let a=n(e,t,r,i);return a+Math.max(1,Math.min(i(e,a),r-a))}function i(e,t,r,i){let a=n(e,t,r,i);return a===0?-1:n(e,a-1,r,i)}function a(e,t,r){return n(e,t-1,t,r)}function o(t){let{rowCount:o,colCount:s,selection:c,onSelectionChange:l,onActiveCellChange:u,colSpan:d,hiddenColumns:f}=t,[p,m]=(0,e.useState)(null),[h,g]=(0,e.useState)(null),[_,v]=(0,e.useState)(null),y=(0,e.useRef)(null),b=(0,e.useCallback)(e=>{let t=y.current;(t?.row!==e.row||t?.col!==e.col)&&u?.(e.row,e.col),y.current=e,m(e)},[u]),x=c!==void 0,S=x?c??null:h,C=p,w=(0,e.useCallback)(e=>{x?l?.(e):g(e)},[x,l]),T=(0,e.useCallback)((e,t)=>({row:Math.max(0,Math.min(e,o-1)),col:Math.max(0,Math.min(t,s-1))}),[o,s]),E=(0,e.useCallback)((e,t)=>{if(!f||f.size===0)return e;let n=e;for(;n>=0&&n<s&&f.has(n);)n+=t;return n},[f,s]),D=(0,e.useCallback)(()=>{if(!f||f.size===0)return 0;for(let e=0;e<s;e++)if(!f.has(e))return e;return 0},[f,s]),O=(0,e.useCallback)(()=>{if(!f||f.size===0)return s-1;for(let e=s-1;e>=0;e--)if(!f.has(e))return e;return s-1},[f,s]),k=(0,e.useCallback)((e,t)=>{let n=T(e,t);f?.has(n.col)&&(n.col=E(n.col,1),n.col>=s&&(n.col=E(t,-1)),n.col<0)||(b(n),v(n),w({start:n,end:n}))},[T,w,b,f,E,s]),A=(0,e.useCallback)((e,t)=>{let n=T(e,t),r=_??p??n;b(n),w({start:r,end:n})},[_,p,T,w,b]),j=(0,e.useCallback)((e,t)=>{let n=T(e,t);w({start:_??p??n,end:n})},[_,p,T,w]),M=(0,e.useCallback)(()=>{o===0||s===0||(b({row:0,col:0}),v({row:0,col:0}),w({start:{row:0,col:0},end:{row:o-1,col:s-1}}))},[o,s,w,b]),N=(0,e.useCallback)(()=>{y.current=null,m(null),v(null),w(null)},[w]),P=(0,e.useCallback)((e,t)=>{let c=p??{row:0,col:0},l=c.row+e,u=c.col+t;if(d){if(t>0&&e===0)u=r(c.row,c.col,s,d);else if(t<0&&e===0){let e=i(c.row,c.col,s,d);u=e>=0?e:c.col}u>=s?(u=0,l=c.row+1):u<0&&(l=c.row-1,u=l>=0?a(l,s,d):s-1),e!==0&&(u=n(Math.max(0,Math.min(l,o-1)),Math.max(0,Math.min(u,s-1)),s,d))}else f&&f.size>0&&t!==0&&e===0&&(u=E(u,t>0?1:-1)),u>=s?(u=D(),l+=1):u<0&&(u=O(),--l),f&&f.size>0&&e!==0&&(u=E(u,1),u>=s&&(u=O()));let m=T(l,u);b(m),v(m),w({start:m,end:m})},[p,s,o,T,w,b,d,f,E,D,O]),F=(0,e.useCallback)((e,t)=>{let r=T(e,t);d&&(r.col=n(r.row,r.col,s,d)),!(f?.has(r.col)&&(r.col=E(r.col,1),r.col>=s&&(r.col=E(t,-1)),r.col<0))&&(b(r),v(r),w({start:r,end:r}))},[T,s,w,b,d,f,E]),I=(0,e.useCallback)(e=>{let t=Math.max(0,Math.min(e,o-1));y.current||b({row:t,col:0}),v({row:t,col:0}),w({start:{row:t,col:0},end:{row:t,col:s-1}})},[o,s,w,b]),L=(0,e.useCallback)(e=>{let t=Math.max(0,Math.min(e,o-1));w({start:{row:(_??{row:t,col:0}).row,col:0},end:{row:t,col:s-1}})},[_,o,s,w]),R=(0,e.useCallback)(e=>{let t=Math.max(0,Math.min(e,s-1));y.current||b({row:0,col:t}),v({row:0,col:t}),w({start:{row:0,col:t},end:{row:o-1,col:t}})},[o,s,w,b]),z=(0,e.useCallback)(e=>{let t=Math.max(0,Math.min(e,s-1));w({start:{row:0,col:(_??{row:0,col:t}).col},end:{row:o-1,col:t}})},[_,o,s,w]),B=(0,e.useCallback)((e,t)=>{if(!S)return!1;let n=Math.min(S.start.row,S.end.row),r=Math.max(S.start.row,S.end.row),i=Math.min(S.start.col,S.end.col),a=Math.max(S.start.col,S.end.col);return e>=n&&e<=r&&t>=i&&t<=a},[S]),V=(0,e.useCallback)((e,t)=>C?.row===e&&C?.col===t,[C]),H=(0,e.useCallback)((e,t)=>{t?(y.current=t,m(t),v(t)):(y.current=null,m(null),v(null)),w(e)},[w]);return(0,e.useMemo)(()=>({activeCell:C,selectionRange:S,selectCell:k,extendSelection:A,setRangeEnd:j,selectAll:M,clearSelection:N,moveActiveCell:P,moveActiveCellTo:F,isSelected:B,isActiveCell:V,selectEntireRow:I,selectEntireCol:R,extendRowSelection:L,extendColSelection:z,restoreSelection:H}),[C,S,k,A,j,M,N,P,F,B,V,I,R,L,z,H])}function s(e){let t=e.target.closest(`[data-row][data-col]`);if(!t)return null;let n=parseInt(t.dataset.row,10),r=parseInt(t.dataset.col,10);return isNaN(n)||isNaN(r)?null:{row:n,col:r}}function c(e,t){let n=document.elementFromPoint(e,t)?.closest(`[data-row][data-col]`);if(!n)return null;let r=parseInt(n.dataset.row,10),i=parseInt(n.dataset.col,10);return isNaN(r)||isNaN(i)?null:{row:r,col:i}}function l(t){let{mode:n,selection:r,editing:i}=t,a=(0,e.useRef)(!1),o=(0,e.useRef)(!1),l=(0,e.useRef)(null),u=(0,e.useRef)(null),d=(0,e.useRef)(null),f=(0,e.useRef)(null),p=(0,e.useCallback)((e,t)=>{let n=e.closest(`.seg-scroll-inner`);n&&(n.setPointerCapture?.(t),l.current=n)},[]),m=(0,e.useCallback)(e=>{let t=e.target;if(t.closest(`[data-grip-row]`)||t.closest(`[data-grip-col]`))return;let c=s(e);if(c&&(u.current=null,o.current=!1,!(e.button===2&&r.isSelected(c.row,c.col)))){if(n===`edit`){f.current=null;let n=d.current;if(n!==null&&n.row===c.row&&n.col===c.col&&!i.editingCell){f.current=c;return}i.editingCell&&i.commitEdit(),r.selectCell(c.row,c.col),d.current=c,a.current=!0,p(t,e.pointerId);return}if(i.editingCell&&i.commitEdit(),e.shiftKey){r.extendSelection(c.row,c.col);return}if(r.isSelected(c.row,c.col)){u.current=c,a.current=!0,p(t,e.pointerId);return}r.selectCell(c.row,c.col),d.current=c,a.current=!0,p(t,e.pointerId)}},[n,r,i,p]),h=(0,e.useCallback)(e=>{if(!a.current)return;let t=c(e.clientX,e.clientY);t&&(u.current&&=(r.selectCell(u.current.row,u.current.col),null),o.current=!0,r.setRangeEnd(t.row,t.col))},[r]),g=(0,e.useCallback)(e=>{if(f.current){let e=f.current;f.current=null,i.startEditing(e.row,e.col);return}u.current&&!o.current&&(r.selectCell(u.current.row,u.current.col),d.current=u.current,u.current=null),u.current=null,a.current&&(a.current=!1,o.current=!1,l.current&&=(l.current.releasePointerCapture?.(e.pointerId),null))},[r,i]);return(0,e.useMemo)(()=>({onPointerDown:m,onPointerMove:h,onPointerUp:g}),[m,h,g])}function u(t){let{selection:n,colCount:r,rowCount:i}=t,a=(0,e.useRef)(!1),o=(0,e.useRef)(!1),s=(0,e.useRef)(!1),c=(0,e.useRef)(!1),l=(0,e.useRef)(null),u=(0,e.useRef)(null),d=(0,e.useCallback)(e=>{let t=n.selectionRange;if(!t)return!1;let i=Math.min(t.start.row,t.end.row),a=Math.max(t.start.row,t.end.row),o=Math.min(t.start.col,t.end.col),s=Math.max(t.start.col,t.end.col);return e>=i&&e<=a&&o===0&&s===r-1},[n.selectionRange,r]),f=(0,e.useCallback)(e=>{let t=n.selectionRange;if(!t)return!1;let r=Math.min(t.start.row,t.end.row),a=Math.max(t.start.row,t.end.row),o=Math.min(t.start.col,t.end.col),s=Math.max(t.start.col,t.end.col);return e>=o&&e<=s&&r===0&&a===i-1},[n.selectionRange,i]),p=(0,e.useCallback)(e=>{let t=e.currentTarget,r=parseInt(t.dataset.gripRow,10);isNaN(r)||e.button===2&&d(r)||(t.setPointerCapture?.(e.pointerId),a.current=!0,s.current=!1,l.current=null,e.shiftKey?n.extendRowSelection(r):d(r)?l.current=r:n.selectEntireRow(r))},[n,d]),m=(0,e.useCallback)(e=>{if(!a.current)return;let t=document.elementFromPoint(e.clientX,e.clientY)?.closest(`[data-grip-row]`);if(!t)return;let r=parseInt(t.dataset.gripRow,10);isNaN(r)||(l.current!==null&&(n.selectEntireRow(l.current),l.current=null),s.current=!0,n.extendRowSelection(r))},[n]),h=(0,e.useCallback)(e=>{l.current!==null&&!s.current&&n.selectEntireRow(l.current),l.current=null,a.current=!1,s.current=!1,e.currentTarget.releasePointerCapture?.(e.pointerId)},[n]),g=(0,e.useCallback)(e=>{let t=e.currentTarget,r=parseInt(t.dataset.gripCol,10);isNaN(r)||e.button===2&&f(r)||(t.setPointerCapture?.(e.pointerId),o.current=!0,c.current=!1,u.current=null,e.shiftKey?n.extendColSelection(r):f(r)?u.current=r:n.selectEntireCol(r))},[n,f]),_=(0,e.useCallback)(e=>{if(!o.current)return;let t=document.elementFromPoint(e.clientX,e.clientY)?.closest(`[data-grip-col]`);if(!t)return;let r=parseInt(t.dataset.gripCol,10);isNaN(r)||(u.current!==null&&(n.selectEntireCol(u.current),u.current=null),c.current=!0,n.extendColSelection(r))},[n]),v=(0,e.useCallback)(e=>{u.current!==null&&!c.current&&n.selectEntireCol(u.current),u.current=null,o.current=!1,c.current=!1,e.currentTarget.releasePointerCapture?.(e.pointerId)},[n]);return(0,e.useMemo)(()=>({onRowGripPointerDown:p,onRowGripPointerMove:m,onRowGripPointerUp:h,onColGripPointerDown:g,onColGripPointerMove:_,onColGripPointerUp:v}),[p,m,h,g,_,v])}function d(t){let{selection:n,editing:r,mode:i,rowCount:a,colCount:o}=t,s=(0,e.useCallback)(e=>{if(r.editingCell)return;let{key:t,shiftKey:s,ctrlKey:c,metaKey:l}=e,u=c||l;switch(t){case`ArrowUp`:e.preventDefault(),s?n.extendSelection((n.activeCell?.row??0)-1,n.activeCell?.col??0):n.moveActiveCell(-1,0);break;case`ArrowDown`:e.preventDefault(),s?n.extendSelection((n.activeCell?.row??0)+1,n.activeCell?.col??0):n.moveActiveCell(1,0);break;case`ArrowLeft`:e.preventDefault(),s?n.extendSelection(n.activeCell?.row??0,(n.activeCell?.col??0)-1):n.moveActiveCell(0,-1);break;case`ArrowRight`:e.preventDefault(),s?n.extendSelection(n.activeCell?.row??0,(n.activeCell?.col??0)+1):n.moveActiveCell(0,1);break;case`Tab`:e.preventDefault(),n.moveActiveCell(0,s?-1:1);break;case`Enter`:e.preventDefault(),i===`edit`&&n.activeCell?r.startEditing(n.activeCell.row,n.activeCell.col):n.moveActiveCell(1,0);break;case`F2`:e.preventDefault(),i===`edit`&&n.activeCell&&r.startEditing(n.activeCell.row,n.activeCell.col);break;case`Escape`:e.preventDefault(),n.clearSelection();break;case`Home`:e.preventDefault(),u?n.moveActiveCellTo(0,0):n.moveActiveCellTo(n.activeCell?.row??0,0);break;case`End`:e.preventDefault(),u?n.moveActiveCellTo(a-1,o-1):n.moveActiveCellTo(n.activeCell?.row??0,o-1);break;case`a`:u&&(e.preventDefault(),n.selectAll());break;default:i===`edit`&&n.activeCell&&t.length===1&&!u&&r.startEditing(n.activeCell.row,n.activeCell.col,t);break}},[n,r,i,a,o]);return(0,e.useMemo)(()=>({onKeyDown:s}),[s])}function f(t){let{rows:n,columns:r,mode:i,onChange:a,onCommitMove:o,onEditStart:s,onEditCommit:c,onEditCancel:l}=t,[u,d]=(0,e.useState)(null),[f,p]=(0,e.useState)(``),[m,h]=(0,e.useState)(!1),g=(0,e.useCallback)((e,t,a)=>{if(i===`readonly`||i===`select`)return;let o=r[t];if(o?.editable===!1||s?.(e,t)===!1)return;let c=n[e]?.[o.key],l=a??String(c??``);d({row:e,col:t}),p(l)},[i,r,n,s]),_=(0,e.useCallback)(()=>{if(!u)return;let{row:e,col:t}=u,i=r[t];if(!i){d(null);return}let o=i.parser?i.parser(f):f,s=n[e]?.[i.key];if(c?.(e,t,s,o)===!1){d(null);return}if(s!==o&&a){let r={...n[e],[i.key]:o},c=[...n];c[e]=r,a(c,[{row:e,col:t,before:s,after:o}])}d(null)},[u,r,f,n,a,c]),v=(0,e.useCallback)(()=>{u&&l?.(u.row,u.col),d(null)},[u,l]),y=(0,e.useCallback)((e,t)=>u?.row===e&&u?.col===t,[u]),b=(0,e.useCallback)(e=>{if(e.nativeEvent.type===`compositionstart`){h(!0);return}if(e.nativeEvent.type===`compositionend`){h(!1);return}if(!m)switch(e.key){case`Enter`:e.preventDefault(),e.stopPropagation(),_(),o(1,0);break;case`Tab`:e.preventDefault(),e.stopPropagation(),_(),o(0,e.shiftKey?-1:1);break;case`Escape`:e.preventDefault(),e.stopPropagation(),v();break}},[m,_,v,o]);return(0,e.useMemo)(()=>({editingCell:u,editValue:f,setEditValue:p,startEditing:g,commitEdit:_,cancelEdit:v,isEditing:y,onEditorKeyDown:b}),[u,f,g,_,v,y,b])}function p(e){return e.includes(` `)||e.includes(`
|
|
2
|
+
`)||e.includes(`\r`)||e.includes(`"`)?`"${e.replace(/"/g,`""`)}"`:e}function m(e){return e.map(e=>e.map(p).join(` `)).join(`\r
|
|
3
|
+
`)}function h(e){let t=[],n=``,r=!1,i=[];for(let a=0;a<e.length;a++){let o=e[a];r?o===`"`?e[a+1]===`"`?(n+=`"`,a++):r=!1:n+=o:o===`"`?r=!0:o===` `?(i.push(n),n=``):o===`\r`?(e[a+1]===`
|
|
4
|
+
`&&a++,i.push(n),n=``,t.push(i),i=[]):o===`
|
|
5
|
+
`?(i.push(n),n=``,t.push(i),i=[]):n+=o}return(n||i.length>0)&&(i.push(n),t.push(i)),t}function g(e){return e.replace(/&/g,`&`).replace(/</g,`<`).replace(/>/g,`>`).replace(/"/g,`"`)}function _(e,t){let n=t?.colSpan,r=t?.startRow??0,i=t?.startCol??0;return`<table>${e.map((e,t)=>{let a=r+t,o=``,s=0;for(;s<e.length;){let t=i+s,r=n?Math.max(1,Math.min(n(a,t),e.length-s)):1,c=r>1?` colspan="${r}"`:``;o+=`<td${c}>${g(e[s])}</td>`,s+=r}return`<tr>${o}</tr>`}).join(``)}</table>`}function v(e){let t=e.selectionRange;return t?{minRow:Math.min(t.start.row,t.end.row),maxRow:Math.max(t.start.row,t.end.row),minCol:Math.min(t.start.col,t.end.col),maxCol:Math.max(t.start.col,t.end.col)}:null}function y(t){let{rows:n,columns:r,mode:i,selection:a,onChange:o,clipboardFormat:s,allowRowAdd:c,allowRowDelete:l,onRowsAdd:u,onRowsDelete:d,colSpan:f}=t,p=(0,e.useCallback)(()=>{let e=v(a);if(!e)return null;let t=[];for(let i=e.minRow;i<=e.maxRow;i++){let a=[];for(let t=e.minCol;t<=e.maxCol;t++){let e=r[t],o=n[i]?.[e.key];a.push(String(o??``))}t.push(a)}return t},[n,r,a]),g=(0,e.useCallback)(async(e,t,n)=>{let r=m(e),i={};if((s===`tsv`||s===`both`)&&(i[`text/plain`]=new Blob([r],{type:`text/plain`})),s===`html`||s===`both`){let a=_(e,{colSpan:f,startRow:t,startCol:n});i[`text/html`]=new Blob([a],{type:`text/html`}),i[`text/plain`]||=new Blob([r],{type:`text/plain`})}await navigator.clipboard.write([new ClipboardItem(i)])},[s,f]),y=(0,e.useCallback)(async()=>{let e=p();if(!e)return;let t=v(a);await g(e,t?.minRow,t?.minCol)},[p,g,a]),b=(0,e.useCallback)(async()=>{if(i===`readonly`)return;let e=v(a);if(!e)return;let t=p();if(t)if(await g(t,e.minRow,e.minCol),l){let t=e.minRow,i=e.maxRow,s=i-t+1,c=[...n];c.splice(t,s);let l=[];for(let e=t;e<=i;e++)for(let t=0;t<r.length;t++)l.push({row:e,col:t,before:n[e][r[t].key],after:void 0});if(o?.(c,l),d?.(t,s),c.length===0)a.clearSelection();else{let n=Math.min(t,c.length-1);a.selectCell(n,e.minCol)}}else{let t=[...n],i=[];for(let n=e.minRow;n<=e.maxRow;n++){t[n]={...t[n]};for(let a=e.minCol;a<=e.maxCol;a++){let e=r[a];if(e.editable===!1)continue;let o=t[n][e.key],s=e.parser?e.parser(``):``;t[n][e.key]=s,i.push({row:n,col:a,before:o,after:s})}}i.length>0&&o?.(t,i)}},[i,n,r,a,p,g,o,l,d]),x=(0,e.useCallback)(async()=>{if(i===`readonly`)return;let e=v(a)??{minRow:0,maxRow:0,minCol:0,maxCol:0},t;try{t=await navigator.clipboard.readText()}catch{return}let s=h(t);if(s.length===0)return;let l=[...n],d=[],f=e.minRow,p=e.minCol;for(let e=0;e<s.length;e++){let t=f+e;if(t>=l.length){if(!c)break;let e={};for(let t of r)e[t.key]=t.parser?t.parser(``):``;l.push(e)}l[t]={...l[t]};for(let n=0;n<s[e].length;n++){let i=p+n;if(i>=r.length)break;let a=r[i];if(a.editable===!1)continue;let o=l[t][a.key],c=a.parser?a.parser(s[e][n]):s[e][n];l[t][a.key]=c,d.push({row:t,col:i,before:o,after:c})}}d.length>0&&o?.(l,d);let m=l.length-n.length;m>0&&u?.(n.length,m)},[i,n,r,a,o,c,u]),S=(0,e.useCallback)(async()=>{if(i===`readonly`||!c)return;let e=v(a)??{minRow:0,maxRow:-1,minCol:0,maxCol:0},t;try{t=await navigator.clipboard.readText()}catch{return}let s=h(t);if(s.length===0)return;let l=e.minCol,d=e.maxRow+1,f=n[e.minRow]??{},p=s.map(e=>{let t={...f};for(let n=0;n<e.length;n++){let i=l+n;if(i>=r.length)break;let a=r[i];a.editable!==!1&&(t[a.key]=a.parser?a.parser(e[n]):e[n])}return t}),m=[...n];m.splice(d,0,...p);let g=[];for(let e=0;e<p.length;e++)for(let t=0;t<(s[e]?.length??0);t++){let n=l+t;if(n>=r.length)break;let i=r[n];i.editable!==!1&&g.push({row:d+e,col:n,before:void 0,after:p[e][i.key]})}o&&o(m,g),u?.(d,p.length)},[i,c,n,r,a,o,u]),C=(0,e.useCallback)(()=>{if(i===`readonly`||!c)return;let e=v(a)??{minRow:0,maxRow:-1,minCol:0,maxCol:0},t=Math.max(1,e.maxRow-e.minRow+1),s=e.maxRow+1,l=[...n],d=Array.from({length:t},()=>{let e={};for(let t of r)e[t.key]=t.parser?t.parser(``):``;return e});l.splice(s,0,...d),o?.(l,[]),u?.(s,t)},[i,c,n,r,a,o,u]),w=(0,e.useCallback)(()=>{if(i===`readonly`||!l)return;let e=v(a);if(!e)return;let t=e.minRow,s=e.maxRow,c=s-t+1,u=[...n];u.splice(t,c);let f=[];for(let e=t;e<=s;e++)for(let t=0;t<r.length;t++)f.push({row:e,col:t,before:n[e][r[t].key],after:void 0});if(o?.(u,f),d?.(t,c),u.length===0)a.clearSelection();else{let n=Math.min(t,u.length-1);a.selectCell(n,e.minCol)}},[i,l,n,r,a,o,d]),T=a.selectionRange!==null;return(0,e.useMemo)(()=>({copy:y,cut:b,paste:x,pasteInsert:S,addRows:C,deleteRows:w,hasSelection:T,allowRowAdd:c,allowRowDelete:l}),[y,b,x,S,C,w,T,c,l])}function b(t){let{rows:n,selection:r,onChange:i,onRowsAdd:a,onRowsDelete:o,maxHistory:s,shouldRecordHistory:c,historyApiRef:l}=t,[u,d]=(0,e.useState)([]),[f,p]=(0,e.useState)([]),m=(0,e.useRef)(null),h=(0,e.useRef)(!1),g=(0,e.useCallback)(()=>({activeCell:r.activeCell,range:r.selectionRange}),[r]),_=(0,e.useCallback)(e=>{d(t=>{let n=[...t,e];return n.length>s&&n.splice(0,n.length-s),n}),p([])},[s]),v=(0,e.useCallback)((e,t)=>{h.current||(m.current={entry:{beforeRows:n,afterRows:e,beforeSelection:g()},changes:t},queueMicrotask(()=>{let e=m.current;e&&(m.current=null,!(c&&!c(e.changes,e.entry.rowEvent))&&_(e.entry))})),i?.(e,t)},[n,i,g,c,_]),y=(0,e.useCallback)((e,t)=>{!h.current&&m.current&&(m.current.entry.rowEvent={kind:`add`,startRow:e,count:t}),a?.(e,t)},[a]),b=(0,e.useCallback)((e,t)=>{!h.current&&m.current&&(m.current.entry.rowEvent={kind:`delete`,startRow:e,count:t}),o?.(e,t)},[o]),x=(0,e.useCallback)(()=>{d(e=>{if(e.length===0)return e;let t=e[e.length-1],n=e.slice(0,-1);return p(e=>[...e,t]),h.current=!0,i?.(t.beforeRows,[]),t.rowEvent&&(t.rowEvent.kind===`add`?o?.(t.rowEvent.startRow,t.rowEvent.count):a?.(t.rowEvent.startRow,t.rowEvent.count)),r.restoreSelection(t.beforeSelection.range,t.beforeSelection.activeCell),h.current=!1,n})},[i,a,o,r]),S=(0,e.useCallback)(()=>{p(e=>{if(e.length===0)return e;let t=e[e.length-1],n=e.slice(0,-1);return d(e=>{let n=[...e,t];return n.length>s&&n.splice(0,n.length-s),n}),h.current=!0,i?.(t.afterRows,[]),t.rowEvent&&(t.rowEvent.kind===`add`?a?.(t.rowEvent.startRow,t.rowEvent.count):o?.(t.rowEvent.startRow,t.rowEvent.count)),h.current=!1,n})},[s,i,a,o]),C=(0,e.useCallback)((e,t)=>{_({beforeRows:e,afterRows:t,beforeSelection:g()})},[g,_]),w=u.length>0,T=f.length>0;return(0,e.useEffect)(()=>{l&&(l.current={pushHistory:C,undo:x,redo:S,canUndo:w,canRedo:T})},[l,C,x,S,w,T]),(0,e.useMemo)(()=>({wrappedOnChange:v,wrappedOnRowsAdd:y,wrappedOnRowsDelete:b,undo:x,redo:S,canUndo:w,canRedo:T}),[v,y,b,x,S,w,T])}function x(){let t=(0,e.useRef)(null),n=(0,e.useRef)(null),[r,i]=(0,e.useState)({vTop:0,vHeight:0,showV:!1,hLeft:0,hWidth:0,showH:!1}),a=(0,e.useRef)(null),o=(0,e.useRef)(null),s=(0,e.useRef)({pos:0,scroll:0}),c=(0,e.useCallback)(()=>{let e=t.current;if(!e)return;let{scrollTop:r,scrollLeft:o,scrollWidth:s,scrollHeight:c,clientWidth:l,clientHeight:u}=e,d=c>u+1,f=s>l+1,p=u/c,m=l/s;i({showV:d,vTop:d?r/c*u:0,vHeight:d?Math.max(p*u,24):0,showH:f,hLeft:f?o/s*l:0,hWidth:f?Math.max(m*l,24):0});let h=n.current;h&&(h.classList.add(`seg-scrolling`),a.current&&clearTimeout(a.current),a.current=setTimeout(()=>{h.classList.remove(`seg-scrolling`)},800))},[]);return(0,e.useEffect)(()=>{let e=t.current;if(!e)return;e.addEventListener(`scroll`,c,{passive:!0});let n=new ResizeObserver(c);return n.observe(e),e.firstElementChild&&n.observe(e.firstElementChild),c(),()=>{e.removeEventListener(`scroll`,c),n.disconnect()}},[c]),{scrollRef:t,areaRef:n,state:r,onVBarPointerDown:(0,e.useCallback)(e=>{e.preventDefault(),e.stopPropagation(),o.current=`v`,s.current={pos:e.clientY,scroll:t.current?.scrollTop??0},e.target.setPointerCapture?.(e.pointerId)},[]),onHBarPointerDown:(0,e.useCallback)(e=>{e.preventDefault(),e.stopPropagation(),o.current=`h`,s.current={pos:e.clientX,scroll:t.current?.scrollLeft??0},e.target.setPointerCapture?.(e.pointerId)},[]),onBarPointerMove:(0,e.useCallback)(e=>{let n=t.current;if(!(!n||!o.current))if(o.current===`v`){let t=e.clientY-s.current.pos,r=n.scrollHeight/n.clientHeight;n.scrollTop=s.current.scroll+t*r}else{let t=e.clientX-s.current.pos,r=n.scrollWidth/n.clientWidth;n.scrollLeft=s.current.scroll+t*r}},[]),onBarPointerUp:(0,e.useCallback)(e=>{o.current=null,e.target.releasePointerCapture?.(e.pointerId)},[])}}function S(t){let{totalRows:n,pageSize:r,page:i,onPageChange:a,onPageSizeChange:o}=t,[s,c]=(0,e.useState)(0),[l,u]=(0,e.useState)(r),d=i!==void 0,f=d?i:s,p=l,m=Math.max(1,Math.ceil(n/p)),h=(0,e.useCallback)(e=>{let t=Math.max(0,Math.min(e,m-1));d||c(t),a?.(t)},[m,d,a]),g=(0,e.useCallback)(e=>{let t=Math.max(1,e);u(t),o?.(t),h(0)},[o,h]),_=(0,e.useCallback)(()=>h(0),[h]),v=(0,e.useCallback)(()=>h(f-1),[h,f]),y=(0,e.useCallback)(()=>h(f+1),[h,f]),b=(0,e.useCallback)(()=>h(m-1),[h,m]),x=f*p,S=Math.min(x+p,n);return(0,e.useMemo)(()=>({currentPage:f,pageSize:p,totalPages:m,startRow:x,endRow:S,setPage:h,setPageSize:g,goFirst:_,goPrev:v,goNext:y,goLast:b}),[f,p,m,x,S,h,g,_,v,y,b])}function C({value:n,onChange:r,onCommit:i,onKeyDown:a}){let o=(0,e.useRef)(null);return(0,e.useEffect)(()=>{let e=o.current;e&&(e.focus(),e.select())},[]),(0,t.jsx)(`input`,{ref:o,className:`seg-cell-editor`,value:n,onChange:e=>r(e.target.value),onKeyDown:a,onBlur:i,onPointerDown:e=>e.stopPropagation()})}function w({x:n,y:r,items:i,onClose:a}){let o=(0,e.useRef)(null);return(0,e.useEffect)(()=>{let e=e=>{o.current&&!o.current.contains(e.target)&&a()},t=e=>{e.key===`Escape`&&a()};return document.addEventListener(`mousedown`,e),document.addEventListener(`keydown`,t),()=>{document.removeEventListener(`mousedown`,e),document.removeEventListener(`keydown`,t)}},[a]),(0,e.useEffect)(()=>{let e=o.current;if(!e)return;let t=e.getBoundingClientRect();t.right>window.innerWidth&&(e.style.left=`${n-t.width}px`),t.bottom>window.innerHeight&&(e.style.top=`${r-t.height}px`)},[n,r]),(0,t.jsx)(`div`,{ref:o,className:`seg-context-menu`,style:{left:n,top:r},children:i.map((e,n)=>`type`in e&&e.type===`separator`?(0,t.jsx)(`hr`,{className:`seg-context-menu-separator`},n):(0,t.jsxs)(`button`,{className:`seg-context-menu-item`,disabled:`disabled`in e?e.disabled:!1,onClick:()=>{`onClick`in e&&e.onClick(),a()},children:[(0,t.jsx)(`span`,{className:`seg-context-menu-label`,children:`label`in e?e.label:``}),`shortcut`in e&&e.shortcut&&(0,t.jsx)(`span`,{className:`seg-context-menu-shortcut`,children:e.shortcut})]},n))})}function T(n){let{rows:r,columns:i,mode:a=`select`,onChange:s,showRowGripHeader:c=!0,showColumnGripHeader:p=!0,rowHeight:m=`single-line`,allowRowAdd:h=!1,allowRowDelete:g=!1,onEditStart:_,onEditCommit:v,onEditCancel:T,onActiveCellChange:E,onRowsAdd:D,onRowsDelete:O,pagination:k=!1,pageSize:A=20,page:j,onPageChange:M,onPageSizeChange:N,clipboard:P,colSpan:F,cellAlign:I,maxHistory:L=200,shouldRecordHistory:R,historyApiRef:z}=n,B=P?.enabled!==!1,V=P?.format??`both`,H=(0,e.useRef)(null),U=S({totalRows:r.length,pageSize:A,page:j,onPageChange:M,onPageSizeChange:N}),ee=k?r.slice(U.startRow,U.endRow):r,te=k?U.startRow:0,W=r.length,G=i.length,ne=(0,e.useMemo)(()=>{let e=new Set;return i.forEach((t,n)=>{t.hidden&&e.add(n)}),e},[i]),K=o({rowCount:W,colCount:G,selection:n.selection,onSelectionChange:n.onSelectionChange,onActiveCellChange:E,colSpan:F,hiddenColumns:ne}),q=b({rows:r,selection:K,onChange:s,onRowsAdd:D,onRowsDelete:O,maxHistory:L,shouldRecordHistory:R,historyApiRef:z}),J=f({rows:r,columns:i,mode:a,activeCell:K.activeCell,onChange:q.wrappedOnChange,onCommitMove:K.moveActiveCell,onEditStart:_,onEditCommit:v,onEditCancel:T}),Y=y({rows:r,columns:i,mode:a,selection:K,onChange:q.wrappedOnChange,clipboardFormat:V,allowRowAdd:h,allowRowDelete:g,onRowsAdd:q.wrappedOnRowsAdd,onRowsDelete:q.wrappedOnRowsDelete,colSpan:F}),X=l({mode:a,selection:K,editing:J}),Z=u({selection:K,rowCount:W,colCount:G}),re=d({selection:K,editing:J,mode:a,rowCount:W,colCount:G}),{scrollRef:ie,areaRef:ae,state:Q,onVBarPointerDown:oe,onHBarPointerDown:se,onBarPointerMove:ce,onBarPointerUp:le}=x(),[$,ue]=(0,e.useState)(null),de=(0,e.useCallback)(e=>{e.preventDefault();let t=e.target.closest(`[data-row][data-col]`);if(t){let e=parseInt(t.dataset.row,10),n=parseInt(t.dataset.col,10);!isNaN(e)&&!isNaN(n)&&!K.isSelected(e,n)&&K.selectCell(e,n)}ue({x:e.clientX,y:e.clientY})},[K]),fe=(0,e.useCallback)(()=>ue(null),[]),pe=(0,e.useMemo)(()=>{let e=a!==`readonly`,t=Y.hasSelection;return[{label:`元に戻す`,shortcut:`Ctrl+Z`,disabled:!q.canUndo,onClick:()=>q.undo()},{label:`やり直す`,shortcut:`Ctrl+Y`,disabled:!q.canRedo,onClick:()=>q.redo()},{type:`separator`},{label:`コピー`,shortcut:`Ctrl+C`,disabled:!t||!B,onClick:()=>void Y.copy()},{label:`切り取り`,shortcut:`Ctrl+X`,disabled:!t||!e||!B,onClick:()=>void Y.cut()},{label:`貼り付け`,shortcut:`Ctrl+V`,disabled:!e||!B||!h,onClick:()=>void Y.pasteInsert()},{label:`貼り付け(上書き)`,shortcut:`Ctrl+Shift+V`,disabled:!t||!e||!B,onClick:()=>void Y.paste()},{type:`separator`},{label:`行を追加`,shortcut:`Ctrl+I`,disabled:!e||!h,onClick:()=>Y.addRows()},{label:`行を削除`,shortcut:`Ctrl+D`,disabled:!t||!e||!g,onClick:()=>Y.deleteRows()},{type:`separator`},{label:`全選択`,shortcut:`Ctrl+A`,disabled:W===0,onClick:()=>K.selectAll()},{label:`選択解除`,shortcut:`Esc`,disabled:!t,onClick:()=>K.clearSelection()}]},[a,Y,B,h,g,W,K,q]),me=(0,e.useCallback)(e=>{if(!J.editingCell){if(e.ctrlKey||e.metaKey){if(e.key===`z`||e.key===`Z`){e.preventDefault(),e.shiftKey?q.redo():q.undo();return}if(e.key===`y`){e.preventDefault(),q.redo();return}if(B)switch(e.key){case`c`:e.preventDefault(),Y.copy();return;case`x`:e.preventDefault(),Y.cut();return;case`v`:e.preventDefault(),e.shiftKey?Y.paste():Y.pasteInsert();return}if(a!==`readonly`)switch(e.key){case`i`:h&&(e.preventDefault(),Y.addRows());return;case`d`:g&&Y.hasSelection&&(e.preventDefault(),Y.deleteRows());return}}if(e.key===`Escape`){e.preventDefault(),K.clearSelection();return}if((e.key===`Delete`||e.key===`Backspace`)&&a!==`readonly`){e.preventDefault(),Y.cut().catch(()=>{});return}re.onKeyDown(e)}},[J.editingCell,B,Y,a,re,h,g,K,q]),he=(0,e.useCallback)((e,t,n=1)=>{let r=[`seg-cell`],i=!1;for(let r=t;r<t+n;r++)if(K.isSelected(e,r)){i=!0;break}return i&&r.push(`seg-selected`),K.isActiveCell(e,t)&&r.push(`seg-active`),J.isEditing(e,t)&&r.push(`seg-editing`),r.join(` `)},[K,J]),ge=(0,e.useCallback)(e=>{let t=K.selectionRange;if(!t)return!1;let n=Math.min(t.start.row,t.end.row),r=Math.max(t.start.row,t.end.row),i=Math.min(t.start.col,t.end.col),a=Math.max(t.start.col,t.end.col);return e>=n&&e<=r&&i===0&&a===G-1},[K.selectionRange,G]),_e=(0,e.useMemo)(()=>i.map(e=>{let t=e.width;return t===void 0?{width:120}:t===`fit-content`?{width:`auto`}:{width:t}}),[i]),ve=m===`single-line`,ye=i.some(e=>e.width===`fit-content`||e.width===void 0)?void 0:`fixed`;return(0,t.jsxs)(`div`,{ref:H,className:`seg-container${ve?` seg-single-line`:``}`,role:`grid`,"data-mode":a,tabIndex:0,onKeyDown:me,onContextMenu:de,children:[(0,t.jsxs)(`div`,{className:`seg-scroll-area`,ref:ae,children:[(0,t.jsx)(`div`,{className:`seg-scroll-inner`,ref:ie,onPointerDown:X.onPointerDown,onPointerMove:X.onPointerMove,onPointerUp:X.onPointerUp,children:(0,t.jsxs)(`table`,{className:`seg-table`,style:ye?{tableLayout:ye}:void 0,children:[(0,t.jsxs)(`colgroup`,{children:[c&&(0,t.jsx)(`col`,{style:{width:32}}),i.map((e,n)=>e.hidden?null:(0,t.jsx)(`col`,{style:_e[n]},e.key))]}),(0,t.jsxs)(`thead`,{children:[p&&(0,t.jsxs)(`tr`,{className:`seg-grip-col-row`,children:[c&&(0,t.jsx)(`th`,{className:`seg-corner`,onClick:()=>K.clearSelection()}),i.map((e,n)=>e.hidden?null:(0,t.jsx)(`th`,{"data-grip-col":n,onPointerDown:Z.onColGripPointerDown,onPointerMove:Z.onColGripPointerMove,onPointerUp:Z.onColGripPointerUp},e.key))]}),(0,t.jsxs)(`tr`,{className:`seg-header-row`,children:[c&&(0,t.jsx)(`th`,{className:`seg-grip-placeholder`,onClick:()=>K.clearSelection()}),i.map(e=>e.hidden?null:(0,t.jsx)(`th`,{style:e.headerAlign?{textAlign:e.headerAlign}:void 0,children:(0,t.jsxs)(`span`,{className:`seg-header-content`,children:[e.header,e.sortMark===`asc`&&(0,t.jsx)(`span`,{className:`seg-sort-indicator`,children:` ▲`}),e.sortMark===`desc`&&(0,t.jsx)(`span`,{className:`seg-sort-indicator`,children:` ▼`})]})},e.key))]})]}),(0,t.jsx)(`tbody`,{children:ee.map((e,n)=>{let r=n+te;return(0,t.jsxs)(`tr`,{"data-row":r,children:[c&&(0,t.jsx)(`td`,{className:`seg-grip-row${ge(r)?` seg-selected`:``}`,"data-grip-row":r,onPointerDown:Z.onRowGripPointerDown,onPointerMove:Z.onRowGripPointerMove,onPointerUp:Z.onRowGripPointerUp}),(()=>{let n=[],a=0;for(;a<i.length;){let o=F?Math.max(1,Math.min(F(r,a),i.length-a)):1,s=i[a];if(s.hidden){a+=o;continue}let c=0;for(let e=0;e<o;e++)i[a+e]?.hidden||c++;let l=e[s.key],u=s.render?s.render(l,e,r):s.formatter?s.formatter(l,e):String(l??``),d=I?.(r,a)??s.align;n.push((0,t.jsx)(`td`,{className:he(r,a,o),"data-row":r,"data-col":a,colSpan:c>1?c:void 0,style:d?{textAlign:d}:void 0,onDoubleClick:()=>J.startEditing(r,a),children:J.isEditing(r,a)?(0,t.jsx)(C,{value:J.editValue,onChange:J.setEditValue,onCommit:J.commitEdit,onCancel:J.cancelEdit,onKeyDown:J.onEditorKeyDown}):u},s.key)),a+=o}return n})()]},r)})})]})}),Q.showV&&(0,t.jsx)(`div`,{className:`seg-scrollbar seg-scrollbar-v`,style:{top:Q.vTop,height:Q.vHeight},onPointerDown:oe,onPointerMove:ce,onPointerUp:le}),Q.showH&&(0,t.jsx)(`div`,{className:`seg-scrollbar seg-scrollbar-h`,style:{left:Q.hLeft,width:Q.hWidth},onPointerDown:se,onPointerMove:ce,onPointerUp:le})]}),k&&(0,t.jsxs)(`div`,{className:`seg-pagination`,children:[(0,t.jsx)(`div`,{className:`seg-pagination-info`,children:r.length===0?`0 件`:`${U.startRow+1}–${U.endRow} / ${r.length} 件`}),(0,t.jsxs)(`div`,{className:`seg-pagination-controls`,children:[(0,t.jsx)(`button`,{className:`seg-pagination-btn`,disabled:U.currentPage===0,onClick:U.goFirst,children:`«`}),(0,t.jsx)(`button`,{className:`seg-pagination-btn`,disabled:U.currentPage===0,onClick:U.goPrev,children:`‹`}),(0,t.jsxs)(`span`,{className:`seg-pagination-page`,children:[U.currentPage+1,` / `,U.totalPages]}),(0,t.jsx)(`button`,{className:`seg-pagination-btn`,disabled:U.currentPage>=U.totalPages-1,onClick:U.goNext,children:`›`}),(0,t.jsx)(`button`,{className:`seg-pagination-btn`,disabled:U.currentPage>=U.totalPages-1,onClick:U.goLast,children:`»`})]})]}),$&&(0,t.jsx)(w,{x:$.x,y:$.y,items:pe,onClose:fe})]})}exports.SimpleExGrid=T;
|
package/dist/index.css
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
.seg-container{color:#222;-webkit-user-select:none;user-select:none;touch-action:none;border:1px solid #b0b0b0;outline:none;flex-direction:column;flex:auto;min-height:0;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;font-size:13px;line-height:1.4;display:flex;position:relative;overflow:hidden}.seg-container:focus-within{border-color:#26c}.seg-scroll-area{flex-direction:column;flex:auto;min-height:0;display:flex;position:relative;overflow:hidden}.seg-scroll-inner{scrollbar-width:none;flex:auto;min-height:0;overflow:auto}.seg-scroll-inner::-webkit-scrollbar{display:none}.seg-scrollbar{z-index:10;opacity:0;pointer-events:auto;background:#00000026;border-radius:4px;transition:opacity .2s;position:absolute}.seg-scrollbar:hover,.seg-scrollbar.seg-scrollbar-active{background:#00000059}.seg-scroll-area:hover .seg-scrollbar,.seg-scroll-area.seg-scrolling .seg-scrollbar{opacity:1}.seg-scrollbar-v{width:6px;right:2px}.seg-scrollbar-h{height:6px;bottom:2px}.seg-table{border-collapse:separate;border-spacing:0}.seg-table thead th{z-index:3;position:sticky;top:0}.seg-grip-col-row th{z-index:3;top:0}.seg-header-row th{z-index:3}.seg-grip-col-row+.seg-header-row th{top:16px}.seg-grip-row,.seg-corner,.seg-grip-placeholder{z-index:2;position:sticky;left:0}.seg-table thead th.seg-corner{z-index:4;top:auto}.seg-table thead th.seg-grip-placeholder{z-index:4}.seg-corner{background:#e8e8e8;border-bottom:1px solid #b0b0b0;border-right:1px solid #b0b0b0;width:32px;min-width:32px;max-width:32px}.seg-grip-col-row th{background:#e8e8e8;border-bottom:1px solid #b0b0b0;border-right:1px solid #d0d0d0;height:16px;max-height:16px;padding:0}.seg-grip-col-row th:after{content:"";background:#217346;width:100%;height:4px;display:block;position:absolute;bottom:0;left:0}.seg-grip-col-row th.seg-corner:after{display:none}.seg-header-row th{text-align:left;white-space:nowrap;text-overflow:ellipsis;background:#f3f3f3;border-bottom:2px solid #b0b0b0;border-right:1px solid #d0d0d0;padding:6px 8px;font-weight:600;overflow:hidden}.seg-header-content{align-items:center;display:inline-flex}.seg-sort-indicator{color:#666;flex-shrink:0;font-size:10px}.seg-header-row th.seg-grip-placeholder{background:#f3f3f3;border-right:1px solid #b0b0b0;width:32px;min-width:32px;max-width:32px;padding:0}.seg-grip-row{cursor:pointer;background:#f3f3f3;border-bottom:1px solid #d0d0d0;border-right:1px solid #b0b0b0;width:32px;min-width:32px;max-width:32px;padding:0}.seg-grip-row:after{content:"";background:#217346;width:4px;height:100%;display:block;position:absolute;top:0;right:0}.seg-cell{cursor:cell;background:#fff;border-bottom:1px solid #d0d0d0;border-right:1px solid #d0d0d0;padding:4px 8px}.seg-single-line .seg-cell{white-space:nowrap;text-overflow:ellipsis;overflow:hidden}.seg-container:not(.seg-single-line) .seg-cell{white-space:normal;word-break:break-word}.seg-cell.seg-selected{background:#c6e0f5}.seg-cell.seg-active{outline-offset:-2px;z-index:1;outline:2px solid #26c;position:relative}.seg-grip-row.seg-selected{background:#d5e5d5}.seg-grip-col-row th.seg-selected:after{background:#145a30}.seg-cell.seg-editing{padding:0;overflow:visible}.seg-cell-editor{width:100%;height:100%;font:inherit;color:inherit;box-sizing:border-box;background:#fff;border:none;outline:none;padding:4px 8px}.seg-container[data-mode=readonly] .seg-cell{cursor:default}.seg-table tbody tr:nth-child(2n) .seg-cell:not(.seg-selected):not(.seg-active){background:#fafafa}.seg-context-menu{z-index:1000;background:#fff;border:1px solid #d0d0d0;border-radius:6px;min-width:180px;padding:4px 0;font-size:13px;position:fixed;box-shadow:0 4px 16px #00000026}.seg-context-menu-separator{border:none;border-top:1px solid #e0e0e0;margin:4px 0}.seg-context-menu-item{width:100%;font:inherit;color:#222;cursor:pointer;text-align:left;background:0 0;border:none;justify-content:space-between;align-items:center;padding:6px 14px;display:flex}.seg-context-menu-item:hover:not(:disabled){background:#e8f0fe}.seg-context-menu-item:disabled{color:#aaa;cursor:default}.seg-context-menu-shortcut{color:#888;margin-left:24px;font-size:12px}.seg-pagination{color:#555;background:#f8f8f8;border-top:1px solid #d0d0d0;flex-shrink:0;justify-content:space-between;align-items:center;padding:6px 12px;font-size:12px;display:flex}.seg-pagination-info{white-space:nowrap}.seg-pagination-controls{align-items:center;gap:4px;display:flex}.seg-pagination-btn{color:#333;cursor:pointer;background:#fff;border:1px solid #ccc;border-radius:3px;justify-content:center;align-items:center;width:28px;height:24px;padding:0;font-size:14px;line-height:1;display:inline-flex}.seg-pagination-btn:hover:not(:disabled){background:#e8f0fe;border-color:#aac}.seg-pagination-btn:disabled{color:#bbb;cursor:default;background:#f0f0f0}.seg-pagination-page{white-space:nowrap;padding:0 8px}
|
|
2
|
+
/*$vite$:1*/
|
package/dist/index.d.ts
ADDED