@alaarab/ogrid-vue 2.7.3 → 2.9.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/esm/index.js +1 -1
- package/dist/esm/styles/ogrid-layout.css +7 -3
- package/dist/esm/styles/ogrid-theme.css +137 -28
- package/dist/types/composables/index.d.ts +12 -0
- package/dist/types/composables/useCellClipboard.d.ts +28 -0
- package/dist/types/composables/useFillHandle.d.ts +21 -29
- package/dist/types/composables/useFillHandleInternal.d.ts +34 -0
- package/dist/types/composables/useGridFocus.d.ts +33 -0
- package/dist/types/composables/useHeadlessGrid.d.ts +103 -0
- package/dist/types/composables/useInlineEdit.d.ts +48 -0
- package/dist/types/composables/useRangeSelection.d.ts +30 -0
- package/dist/types/index.d.ts +2 -2
- package/package.json +2 -2
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
/* Cell selection highlighting.
|
|
11
11
|
Qualify with .ogrid-outer-container (specificity 0,2,0) to beat row-level hover backgrounds. */
|
|
12
12
|
.ogrid-outer-container .ogrid-cell-in-range {
|
|
13
|
-
background: var(--ogrid-bg
|
|
13
|
+
background: var(--ogrid-range-bg, rgba(33, 115, 70, 0.12));
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
/* Cut range highlighting */
|
|
@@ -62,6 +62,10 @@
|
|
|
62
62
|
font-size: 0.875rem;
|
|
63
63
|
background-color: var(--ogrid-bg);
|
|
64
64
|
color: var(--ogrid-fg);
|
|
65
|
+
font-family: var(--ogrid-font, inherit);
|
|
66
|
+
/* Tabular numerics + OpenType features so digits align in columns. */
|
|
67
|
+
font-variant-numeric: tabular-nums;
|
|
68
|
+
font-feature-settings: "tnum" 1, "ss01" 1, "cv11" 1;
|
|
65
69
|
}
|
|
66
70
|
|
|
67
71
|
/* No left border on first column — the grid container provides the left edge */
|
|
@@ -279,7 +283,7 @@
|
|
|
279
283
|
}
|
|
280
284
|
|
|
281
285
|
.ogrid-cell-content--active {
|
|
282
|
-
outline: 2px solid var(--ogrid-selection, #217346);
|
|
286
|
+
outline: 2px solid var(--ogrid-selection-color, #217346);
|
|
283
287
|
outline-offset: -1px;
|
|
284
288
|
z-index: var(--ogrid-z-active-cell, 2);
|
|
285
289
|
position: relative;
|
|
@@ -327,7 +331,7 @@
|
|
|
327
331
|
bottom: -3px;
|
|
328
332
|
width: 7px;
|
|
329
333
|
height: 7px;
|
|
330
|
-
background-color: var(--ogrid-selection, #217346);
|
|
334
|
+
background-color: var(--ogrid-selection-color, #217346);
|
|
331
335
|
border: 1px solid var(--ogrid-bg);
|
|
332
336
|
border-radius: 1px;
|
|
333
337
|
cursor: crosshair;
|
|
@@ -1,119 +1,228 @@
|
|
|
1
|
-
/* OGrid
|
|
1
|
+
/* OGrid Vue theme — generated from packages/core/src/styles/_ogrid-theme.scss
|
|
2
|
+
* Run `node scripts/sync-theme.mjs` to regenerate. Do not edit by hand.
|
|
2
3
|
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
4
|
+
* Dark mode activates via:
|
|
5
|
+
* 1. System preference (prefers-color-scheme: dark) unless [data-theme="light"]
|
|
6
|
+
* or .light is set on root.
|
|
7
|
+
* 2. Explicit attribute: [data-theme="dark"] on any ancestor.
|
|
8
|
+
* 3. Tailwind/shadcn convention: .dark class on any ancestor.
|
|
9
|
+
*
|
|
10
|
+
* To opt OUT of auto-dark: set .light or [data-theme="light"] on :root.
|
|
5
11
|
*/
|
|
6
12
|
|
|
7
13
|
/* ─── Light Theme (default) ─── */
|
|
8
14
|
:where(:root) {
|
|
9
|
-
/* Cell padding — override for row density
|
|
10
|
-
--ogrid-cell-padding
|
|
11
|
-
--ogrid-cell-padding-vertical
|
|
15
|
+
/* ── Cell padding — override for row density ──
|
|
16
|
+
--ogrid-cell-padding : shorthand (default 6px 10px)
|
|
17
|
+
--ogrid-cell-padding-vertical : vertical only (default 6px)
|
|
12
18
|
--ogrid-cell-padding-horizontal: horizontal only (default 10px) */
|
|
13
19
|
--ogrid-cell-padding: 6px 10px;
|
|
14
20
|
--ogrid-cell-padding-vertical: 6px;
|
|
15
21
|
--ogrid-cell-padding-horizontal: 10px;
|
|
22
|
+
|
|
23
|
+
/* ── Radius scale — override --ogrid-radius to scale all corners ──
|
|
24
|
+
--ogrid-radius : base (default 6px) — buttons, inputs, popovers
|
|
25
|
+
--ogrid-radius-sm : tighter (calc 0.6x) — checkboxes, tags
|
|
26
|
+
--ogrid-radius-lg : looser (calc 1.4x) — cards, dialogs
|
|
27
|
+
--ogrid-radius-xl : largest (calc 1.8x) — hero surfaces
|
|
28
|
+
--ogrid-radius-full: 9999px — pills, dots */
|
|
29
|
+
--ogrid-radius: 6px;
|
|
30
|
+
--ogrid-radius-sm: calc(var(--ogrid-radius) * 0.6);
|
|
31
|
+
--ogrid-radius-lg: calc(var(--ogrid-radius) * 1.4);
|
|
32
|
+
--ogrid-radius-xl: calc(var(--ogrid-radius) * 1.8);
|
|
33
|
+
--ogrid-radius-full: 9999px;
|
|
34
|
+
|
|
35
|
+
/* ── Typography — override --ogrid-font to re-skin the type stack ──
|
|
36
|
+
--ogrid-font : font-family for grid chrome (default: inherit from host)
|
|
37
|
+
--ogrid-font-size: base body font-size (default 13px) */
|
|
38
|
+
--ogrid-font: inherit;
|
|
39
|
+
--ogrid-font-size: 13px;
|
|
40
|
+
|
|
41
|
+
/* ── Focus ring — color used for focus outlines / rings ──
|
|
42
|
+
--ogrid-ring: focus ring color (defaults to accent) */
|
|
43
|
+
--ogrid-ring: var(--ogrid-accent, #0078d4);
|
|
44
|
+
|
|
45
|
+
/* ── Z-Index Stacking Order ──
|
|
46
|
+
--ogrid-z-resize-handle : 1 column resize drag handle
|
|
47
|
+
--ogrid-z-active-cell : 2 active/editing cell outline
|
|
48
|
+
--ogrid-z-fill-handle : 3 fill handle dot
|
|
49
|
+
--ogrid-z-row-number : 5 row number column
|
|
50
|
+
--ogrid-z-pinned : 6 sticky pinned body cells
|
|
51
|
+
--ogrid-z-selection-cell : 7 selection checkbox column in body
|
|
52
|
+
--ogrid-z-thead : 8 sticky thead row
|
|
53
|
+
--ogrid-z-pinned-header : 10 pinned header cells (sticky both axes)
|
|
54
|
+
--ogrid-z-header-focus : 11 focused header cell
|
|
55
|
+
--ogrid-z-selection-header-pinned: 12 checkbox column in sticky header (sticky both axes)
|
|
56
|
+
--ogrid-z-checkbox : 12 alias — checkbox column in sticky header
|
|
57
|
+
--ogrid-z-loading : 2 loading overlay within table
|
|
58
|
+
--ogrid-z-drop-indicator : 100 column reorder drop indicator
|
|
59
|
+
--ogrid-z-filter-popover : 1000 filter popovers
|
|
60
|
+
--ogrid-z-popover : 1000 alias — filter popovers
|
|
61
|
+
--ogrid-z-fullscreen : 9999 fullscreen grid container
|
|
62
|
+
--ogrid-z-context-menu : 10000 context menu (fixed, above everything) */
|
|
63
|
+
--ogrid-z-resize-handle: 1;
|
|
64
|
+
--ogrid-z-active-cell: 2;
|
|
65
|
+
--ogrid-z-fill-handle: 3;
|
|
66
|
+
--ogrid-z-row-number: 5;
|
|
67
|
+
--ogrid-z-pinned: 6;
|
|
68
|
+
--ogrid-z-selection-cell: 7;
|
|
69
|
+
--ogrid-z-thead: 8;
|
|
70
|
+
--ogrid-z-pinned-header: 10;
|
|
71
|
+
--ogrid-z-header-focus: 11;
|
|
72
|
+
--ogrid-z-selection-header-pinned: 12;
|
|
73
|
+
--ogrid-z-checkbox: 12;
|
|
74
|
+
--ogrid-z-loading: 2;
|
|
75
|
+
--ogrid-z-drop-indicator: 100;
|
|
76
|
+
--ogrid-z-filter-popover: 1000;
|
|
77
|
+
--ogrid-z-popover: 1000;
|
|
78
|
+
--ogrid-z-fullscreen: 9999;
|
|
79
|
+
--ogrid-z-context-menu: 10000;
|
|
80
|
+
|
|
81
|
+
/* Core */
|
|
16
82
|
--ogrid-bg: #ffffff;
|
|
17
83
|
--ogrid-fg: rgba(0, 0, 0, 0.87);
|
|
18
84
|
--ogrid-fg-secondary: rgba(0, 0, 0, 0.6);
|
|
19
85
|
--ogrid-fg-muted: rgba(0, 0, 0, 0.5);
|
|
86
|
+
|
|
87
|
+
/* Borders */
|
|
20
88
|
--ogrid-border: rgba(0, 0, 0, 0.12);
|
|
21
89
|
--ogrid-border-strong: rgba(0, 0, 0, 0.5);
|
|
22
90
|
--ogrid-border-hover: rgba(0, 0, 0, 0.3);
|
|
91
|
+
|
|
92
|
+
/* Table */
|
|
23
93
|
--ogrid-header-bg: #f5f5f5;
|
|
24
94
|
--ogrid-hover-bg: rgba(0, 0, 0, 0.04);
|
|
25
95
|
--ogrid-selected-row-bg: #e6f0fb;
|
|
26
96
|
--ogrid-bg-selected-hover: #dae8f8;
|
|
27
97
|
--ogrid-active-cell-bg: rgba(0, 0, 0, 0.02);
|
|
28
98
|
--ogrid-range-bg: rgba(33, 115, 70, 0.12);
|
|
99
|
+
|
|
100
|
+
/* Accent & Selection */
|
|
29
101
|
--ogrid-accent: #0078d4;
|
|
30
102
|
--ogrid-accent-dark: #005a9e;
|
|
31
103
|
--ogrid-selection-color: #217346;
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
--ogrid-primary
|
|
104
|
+
|
|
105
|
+
/* Primary (buttons, badges) — neutral by default; host theme should override */
|
|
106
|
+
--ogrid-primary: oklch(0.55 0 0);
|
|
107
|
+
--ogrid-primary-fg: oklch(1 0 0);
|
|
108
|
+
--ogrid-primary-hover: oklch(0.45 0 0);
|
|
109
|
+
|
|
110
|
+
/* Surfaces */
|
|
35
111
|
--ogrid-bg-subtle: #f5f5f5;
|
|
36
112
|
--ogrid-bg-hover: rgba(0, 0, 0, 0.04);
|
|
37
113
|
--ogrid-active-bg: rgba(0, 0, 0, 0.06);
|
|
38
114
|
--ogrid-muted: rgba(0, 0, 0, 0.5);
|
|
115
|
+
|
|
116
|
+
/* Shadows */
|
|
39
117
|
--ogrid-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
|
|
40
118
|
--ogrid-shadow-sm: 0 2px 4px rgba(0, 0, 0, 0.08);
|
|
41
119
|
--ogrid-pinned-shadow: rgba(0, 0, 0, 0.1);
|
|
120
|
+
|
|
121
|
+
/* Loading */
|
|
42
122
|
--ogrid-loading-overlay: rgba(255, 255, 255, 0.7);
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
--ogrid-
|
|
46
|
-
--ogrid-loading-bg: rgba(255, 255, 255, 0.7);
|
|
123
|
+
|
|
124
|
+
/* Formula errors */
|
|
125
|
+
--ogrid-formula-error-color: #d32f2f;
|
|
47
126
|
}
|
|
48
127
|
|
|
49
|
-
/* ─── Auto Dark (system preference) ─── */
|
|
128
|
+
/* ─── Auto Dark (system preference, unless explicitly set to light) ─── */
|
|
50
129
|
@media (prefers-color-scheme: dark) {
|
|
51
|
-
:where(:root:not([data-theme="light"])) {
|
|
130
|
+
:where(:root:not([data-theme="light"]):not(.light)) {
|
|
131
|
+
/* Core */
|
|
52
132
|
--ogrid-bg: #1e1e1e;
|
|
53
133
|
--ogrid-fg: rgba(255, 255, 255, 0.87);
|
|
54
134
|
--ogrid-fg-secondary: rgba(255, 255, 255, 0.6);
|
|
55
135
|
--ogrid-fg-muted: rgba(255, 255, 255, 0.5);
|
|
136
|
+
|
|
137
|
+
/* Borders */
|
|
56
138
|
--ogrid-border: rgba(255, 255, 255, 0.12);
|
|
57
139
|
--ogrid-border-strong: rgba(255, 255, 255, 0.5);
|
|
58
140
|
--ogrid-border-hover: rgba(255, 255, 255, 0.3);
|
|
141
|
+
|
|
142
|
+
/* Table */
|
|
59
143
|
--ogrid-header-bg: #2c2c2c;
|
|
60
144
|
--ogrid-hover-bg: rgba(255, 255, 255, 0.08);
|
|
61
145
|
--ogrid-selected-row-bg: #1a3a5c;
|
|
62
146
|
--ogrid-bg-selected-hover: #1f3650;
|
|
63
147
|
--ogrid-active-cell-bg: rgba(255, 255, 255, 0.06);
|
|
64
148
|
--ogrid-range-bg: rgba(46, 160, 67, 0.15);
|
|
149
|
+
|
|
150
|
+
/* Accent & Selection */
|
|
65
151
|
--ogrid-accent: #4da6ff;
|
|
66
152
|
--ogrid-accent-dark: #3390e0;
|
|
67
153
|
--ogrid-selection-color: #2ea043;
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
--ogrid-primary
|
|
154
|
+
|
|
155
|
+
/* Primary — neutral by default; host theme should override */
|
|
156
|
+
--ogrid-primary: oklch(0.7 0 0);
|
|
157
|
+
--ogrid-primary-fg: oklch(0.1 0 0);
|
|
158
|
+
--ogrid-primary-hover: oklch(0.8 0 0);
|
|
159
|
+
|
|
160
|
+
/* Surfaces */
|
|
71
161
|
--ogrid-bg-subtle: rgba(255, 255, 255, 0.04);
|
|
72
162
|
--ogrid-bg-hover: rgba(255, 255, 255, 0.08);
|
|
73
163
|
--ogrid-active-bg: rgba(255, 255, 255, 0.08);
|
|
74
164
|
--ogrid-muted: rgba(255, 255, 255, 0.5);
|
|
165
|
+
|
|
166
|
+
/* Shadows */
|
|
75
167
|
--ogrid-shadow: 0 4px 16px rgba(0, 0, 0, 0.4);
|
|
76
168
|
--ogrid-shadow-sm: 0 2px 4px rgba(0, 0, 0, 0.25);
|
|
77
169
|
--ogrid-pinned-shadow: rgba(0, 0, 0, 0.3);
|
|
170
|
+
|
|
171
|
+
/* Loading */
|
|
78
172
|
--ogrid-loading-overlay: rgba(0, 0, 0, 0.7);
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
--ogrid-
|
|
82
|
-
--ogrid-loading-bg: rgba(0, 0, 0, 0.7);
|
|
173
|
+
|
|
174
|
+
/* Formula errors */
|
|
175
|
+
--ogrid-formula-error-color: #ef5350;
|
|
83
176
|
}
|
|
84
177
|
}
|
|
85
178
|
|
|
86
|
-
/* ─── Explicit Dark ─── */
|
|
87
|
-
:where([data-theme="dark"]) {
|
|
179
|
+
/* ─── Explicit Dark (data-theme="dark" or .dark — Tailwind/shadcn convention) ─── */
|
|
180
|
+
:where([data-theme="dark"], .dark) {
|
|
181
|
+
/* Core */
|
|
88
182
|
--ogrid-bg: #1e1e1e;
|
|
89
183
|
--ogrid-fg: rgba(255, 255, 255, 0.87);
|
|
90
184
|
--ogrid-fg-secondary: rgba(255, 255, 255, 0.6);
|
|
91
185
|
--ogrid-fg-muted: rgba(255, 255, 255, 0.5);
|
|
186
|
+
|
|
187
|
+
/* Borders */
|
|
92
188
|
--ogrid-border: rgba(255, 255, 255, 0.12);
|
|
93
189
|
--ogrid-border-strong: rgba(255, 255, 255, 0.5);
|
|
94
190
|
--ogrid-border-hover: rgba(255, 255, 255, 0.3);
|
|
191
|
+
|
|
192
|
+
/* Table */
|
|
95
193
|
--ogrid-header-bg: #2c2c2c;
|
|
96
194
|
--ogrid-hover-bg: rgba(255, 255, 255, 0.08);
|
|
97
195
|
--ogrid-selected-row-bg: #1a3a5c;
|
|
98
196
|
--ogrid-bg-selected-hover: #1f3650;
|
|
99
197
|
--ogrid-active-cell-bg: rgba(255, 255, 255, 0.06);
|
|
100
198
|
--ogrid-range-bg: rgba(46, 160, 67, 0.15);
|
|
199
|
+
|
|
200
|
+
/* Accent & Selection */
|
|
101
201
|
--ogrid-accent: #4da6ff;
|
|
102
202
|
--ogrid-accent-dark: #3390e0;
|
|
103
203
|
--ogrid-selection-color: #2ea043;
|
|
204
|
+
|
|
205
|
+
/* Primary */
|
|
104
206
|
--ogrid-primary: #4da6ff;
|
|
105
207
|
--ogrid-primary-fg: #fff;
|
|
106
208
|
--ogrid-primary-hover: #66b3ff;
|
|
209
|
+
|
|
210
|
+
/* Surfaces */
|
|
107
211
|
--ogrid-bg-subtle: rgba(255, 255, 255, 0.04);
|
|
108
212
|
--ogrid-bg-hover: rgba(255, 255, 255, 0.08);
|
|
109
213
|
--ogrid-active-bg: rgba(255, 255, 255, 0.08);
|
|
110
214
|
--ogrid-muted: rgba(255, 255, 255, 0.5);
|
|
215
|
+
|
|
216
|
+
/* Shadows */
|
|
111
217
|
--ogrid-shadow: 0 4px 16px rgba(0, 0, 0, 0.4);
|
|
112
218
|
--ogrid-shadow-sm: 0 2px 4px rgba(0, 0, 0, 0.25);
|
|
113
219
|
--ogrid-pinned-shadow: rgba(0, 0, 0, 0.3);
|
|
220
|
+
|
|
221
|
+
/* Loading */
|
|
114
222
|
--ogrid-loading-overlay: rgba(0, 0, 0, 0.7);
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
--ogrid-
|
|
118
|
-
|
|
223
|
+
|
|
224
|
+
/* Formula errors */
|
|
225
|
+
--ogrid-formula-error-color: #ef5350;
|
|
226
|
+
|
|
119
227
|
}
|
|
228
|
+
/* @sync-end — do not move; sync-theme.mjs anchors here when splicing. */
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export { useOGrid } from './useOGrid';
|
|
2
2
|
export type { UseOGridResult, UseOGridPagination, UseOGridColumnChooser, UseOGridLayout, UseOGridFilters, ColumnChooserPlacement, } from './useOGrid';
|
|
3
|
+
export { useHeadlessGrid } from './useHeadlessGrid';
|
|
4
|
+
export type { UseHeadlessGridParams, UseHeadlessGridResult, RowId as HeadlessGridRowId, SortState as HeadlessGridSortState, } from './useHeadlessGrid';
|
|
3
5
|
export { useDataGridState } from './useDataGridState';
|
|
4
6
|
export type { UseDataGridStateParams, UseDataGridStateResult, DataGridLayoutState, DataGridRowSelectionState, DataGridEditingState, DataGridCellInteractionState, DataGridContextMenuState, DataGridViewModelState, DataGridPinningState, } from './useDataGridState';
|
|
5
7
|
export { useActiveCell } from './useActiveCell';
|
|
@@ -14,8 +16,18 @@ export { useRowSelection } from './useRowSelection';
|
|
|
14
16
|
export type { UseRowSelectionParams, UseRowSelectionResult } from './useRowSelection';
|
|
15
17
|
export { useKeyboardNavigation } from './useKeyboardNavigation';
|
|
16
18
|
export type { UseKeyboardNavigationParams, UseKeyboardNavigationResult } from './useKeyboardNavigation';
|
|
19
|
+
export { useFillHandleInternal } from './useFillHandleInternal';
|
|
20
|
+
export type { UseFillHandleInternalParams, UseFillHandleInternalResult, } from './useFillHandleInternal';
|
|
17
21
|
export { useFillHandle } from './useFillHandle';
|
|
18
22
|
export type { UseFillHandleParams, UseFillHandleResult } from './useFillHandle';
|
|
23
|
+
export { useInlineEdit } from './useInlineEdit';
|
|
24
|
+
export type { UseInlineEditParams, UseInlineEditResult, InlineEditEvent, InlineEditorProps, } from './useInlineEdit';
|
|
25
|
+
export { useRangeSelection } from './useRangeSelection';
|
|
26
|
+
export type { UseRangeSelectionParams, UseRangeSelectionResult, CellCoord, } from './useRangeSelection';
|
|
27
|
+
export { useCellClipboard } from './useCellClipboard';
|
|
28
|
+
export type { UseCellClipboardParams, UseCellClipboardResult, } from './useCellClipboard';
|
|
29
|
+
export { useGridFocus } from './useGridFocus';
|
|
30
|
+
export type { UseGridFocusParams, UseGridFocusResult, } from './useGridFocus';
|
|
19
31
|
export { useUndoRedo } from './useUndoRedo';
|
|
20
32
|
export type { UseUndoRedoParams, UseUndoRedoResult } from './useUndoRedo';
|
|
21
33
|
export { useContextMenu } from './useContextMenu';
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useCellClipboard (Vue) — TSV copy/cut/paste for cell ranges.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors the React API. Honors clipboardFormatter (copy) + valueParser (paste).
|
|
5
|
+
*/
|
|
6
|
+
import { type ComputedRef, type Ref } from 'vue';
|
|
7
|
+
import type { IColumnDef as ICoreColumnDef, ISelectionRange, ICellValueChangedEvent } from '@alaarab/ogrid-core';
|
|
8
|
+
import type { UseRangeSelectionResult } from './useRangeSelection';
|
|
9
|
+
export interface UseCellClipboardParams<T> {
|
|
10
|
+
rangeSelection: UseRangeSelectionResult;
|
|
11
|
+
rows: T[];
|
|
12
|
+
columns: ICoreColumnDef<T>[];
|
|
13
|
+
onCellEdit: (events: ICellValueChangedEvent<T>[]) => void;
|
|
14
|
+
clipboard?: {
|
|
15
|
+
readText: () => Promise<string>;
|
|
16
|
+
writeText: (text: string) => Promise<void>;
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
export interface UseCellClipboardResult {
|
|
20
|
+
copyRange: () => Promise<void>;
|
|
21
|
+
cutRange: () => Promise<void>;
|
|
22
|
+
pasteRange: () => Promise<void>;
|
|
23
|
+
canPaste: ComputedRef<boolean>;
|
|
24
|
+
activeCutRange: Ref<ISelectionRange | null>;
|
|
25
|
+
activeCopyRange: Ref<ISelectionRange | null>;
|
|
26
|
+
clearClipboard: () => void;
|
|
27
|
+
}
|
|
28
|
+
export declare function useCellClipboard<T>(params: UseCellClipboardParams<T>): UseCellClipboardResult;
|
|
@@ -1,34 +1,26 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
/**
|
|
2
|
+
* useFillHandle (Vue) — headless drag-to-fill.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors React useFillHandle. Pairs with useRangeSelection. On commit,
|
|
5
|
+
* applies fill via core's applyFillValues and emits cell-change events.
|
|
6
|
+
*/
|
|
7
|
+
import { type ComputedRef, type Ref } from 'vue';
|
|
8
|
+
import type { IColumnDef as ICoreColumnDef, ISelectionRange, ICellValueChangedEvent } from '@alaarab/ogrid-core';
|
|
9
|
+
import type { CellCoord, UseRangeSelectionResult } from './useRangeSelection';
|
|
4
10
|
export interface UseFillHandleParams<T> {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
selectionRange: Ref<ISelectionRange | null> | ShallowRef<ISelectionRange | null>;
|
|
10
|
-
setSelectionRange: (range: ISelectionRange | null) => void;
|
|
11
|
-
setActiveCell: (cell: IActiveCell | null) => void;
|
|
12
|
-
colOffset: Ref<number> | number;
|
|
13
|
-
wrapperRef: Ref<HTMLElement | null> | ShallowRef<HTMLElement | null>;
|
|
14
|
-
beginBatch?: () => void;
|
|
15
|
-
endBatch?: () => void;
|
|
16
|
-
visibleRange?: Ref<IVisibleRange | null>;
|
|
11
|
+
rangeSelection: UseRangeSelectionResult;
|
|
12
|
+
rows: T[];
|
|
13
|
+
columns: ICoreColumnDef<T>[];
|
|
14
|
+
onFillCells: (events: ICellValueChangedEvent<T>[]) => void;
|
|
17
15
|
}
|
|
18
16
|
export interface UseFillHandleResult {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
handleFillHandleMouseDown: (e: PointerEvent) => void;
|
|
28
|
-
/** Fill the current selection down from the top row (Ctrl+D). No-op if no selection or editable=false. */
|
|
29
|
-
fillDown: () => void;
|
|
17
|
+
fillTarget: Ref<CellCoord | null>;
|
|
18
|
+
isFilling: ComputedRef<boolean>;
|
|
19
|
+
startFill: () => void;
|
|
20
|
+
updateFill: (row: number, col: number) => void;
|
|
21
|
+
commitFill: () => void;
|
|
22
|
+
cancelFill: () => void;
|
|
23
|
+
fillRange: ComputedRef<ISelectionRange | null>;
|
|
24
|
+
isInFillRange: (row: number, col: number) => boolean;
|
|
30
25
|
}
|
|
31
|
-
/**
|
|
32
|
-
* Manages Excel-style fill handle drag-to-fill for cell ranges.
|
|
33
|
-
*/
|
|
34
26
|
export declare function useFillHandle<T>(params: UseFillHandleParams<T>): UseFillHandleResult;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { type Ref, type ShallowRef } from 'vue';
|
|
2
|
+
import type { ISelectionRange, IActiveCell, IColumnDef, ICellValueChangedEvent } from '../types';
|
|
3
|
+
import type { IVisibleRange } from '@alaarab/ogrid-core';
|
|
4
|
+
export interface UseFillHandleInternalParams<T> {
|
|
5
|
+
items: Ref<T[]>;
|
|
6
|
+
visibleCols: Ref<IColumnDef<T>[]>;
|
|
7
|
+
editable: Ref<boolean | undefined>;
|
|
8
|
+
onCellValueChanged: Ref<((event: ICellValueChangedEvent<T>) => void) | undefined>;
|
|
9
|
+
selectionRange: Ref<ISelectionRange | null> | ShallowRef<ISelectionRange | null>;
|
|
10
|
+
setSelectionRange: (range: ISelectionRange | null) => void;
|
|
11
|
+
setActiveCell: (cell: IActiveCell | null) => void;
|
|
12
|
+
colOffset: Ref<number> | number;
|
|
13
|
+
wrapperRef: Ref<HTMLElement | null> | ShallowRef<HTMLElement | null>;
|
|
14
|
+
beginBatch?: () => void;
|
|
15
|
+
endBatch?: () => void;
|
|
16
|
+
visibleRange?: Ref<IVisibleRange | null>;
|
|
17
|
+
}
|
|
18
|
+
export interface UseFillHandleInternalResult {
|
|
19
|
+
fillDrag: ShallowRef<{
|
|
20
|
+
startRow: number;
|
|
21
|
+
startCol: number;
|
|
22
|
+
} | null>;
|
|
23
|
+
setFillDrag: (value: {
|
|
24
|
+
startRow: number;
|
|
25
|
+
startCol: number;
|
|
26
|
+
} | null) => void;
|
|
27
|
+
handleFillHandleMouseDown: (e: PointerEvent) => void;
|
|
28
|
+
/** Fill the current selection down from the top row (Ctrl+D). No-op if no selection or editable=false. */
|
|
29
|
+
fillDown: () => void;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Manages Excel-style fill handle drag-to-fill for cell ranges.
|
|
33
|
+
*/
|
|
34
|
+
export declare function useFillHandleInternal<T>(params: UseFillHandleInternalParams<T>): UseFillHandleInternalResult;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useGridFocus (Vue) — headless arrow-key cell navigation.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors React API with Vue refs.
|
|
5
|
+
*/
|
|
6
|
+
import { type Ref } from 'vue';
|
|
7
|
+
import type { CellCoord, UseRangeSelectionResult } from './useRangeSelection';
|
|
8
|
+
export interface UseGridFocusParams {
|
|
9
|
+
rowCount: number;
|
|
10
|
+
colCount: number;
|
|
11
|
+
pageSize?: number;
|
|
12
|
+
rangeSelection?: UseRangeSelectionResult;
|
|
13
|
+
}
|
|
14
|
+
export interface UseGridFocusResult {
|
|
15
|
+
activeCell: Ref<CellCoord | null>;
|
|
16
|
+
setActiveCell: (cell: CellCoord | null) => void;
|
|
17
|
+
moveUp: (n?: number) => void;
|
|
18
|
+
moveDown: (n?: number) => void;
|
|
19
|
+
moveLeft: (n?: number) => void;
|
|
20
|
+
moveRight: (n?: number) => void;
|
|
21
|
+
moveToRowStart: () => void;
|
|
22
|
+
moveToRowEnd: () => void;
|
|
23
|
+
moveToStart: () => void;
|
|
24
|
+
moveToEnd: () => void;
|
|
25
|
+
getKeyDownHandler: () => (e: {
|
|
26
|
+
key: string;
|
|
27
|
+
shiftKey?: boolean;
|
|
28
|
+
ctrlKey?: boolean;
|
|
29
|
+
metaKey?: boolean;
|
|
30
|
+
preventDefault?: () => void;
|
|
31
|
+
}) => void;
|
|
32
|
+
}
|
|
33
|
+
export declare function useGridFocus(params: UseGridFocusParams): UseGridFocusResult;
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useHeadlessGrid — the v3 headless API for OGrid (Vue).
|
|
3
|
+
*
|
|
4
|
+
* Returns reactive sort/filter/paginate state and rows, without imposing
|
|
5
|
+
* any chrome. Render with your own table primitives.
|
|
6
|
+
*
|
|
7
|
+
* Mirrors the React `useHeadlessGrid` API (see `@alaarab/ogrid-react`)
|
|
8
|
+
* with Vue-idiomatic returns: refs for state, computed for derived
|
|
9
|
+
* values, plain functions for actions. Inputs accept refs, getters, or
|
|
10
|
+
* plain values via `toValue()`.
|
|
11
|
+
*
|
|
12
|
+
* Example:
|
|
13
|
+
*
|
|
14
|
+
* const grid = useHeadlessGrid({
|
|
15
|
+
* columns,
|
|
16
|
+
* data,
|
|
17
|
+
* getRowId: (r) => r.id,
|
|
18
|
+
* initialSort: { field: 'name', direction: 'asc' },
|
|
19
|
+
* });
|
|
20
|
+
*
|
|
21
|
+
* <template>
|
|
22
|
+
* <table>
|
|
23
|
+
* <thead>
|
|
24
|
+
* <tr>
|
|
25
|
+
* <th v-for="col in grid.columns.value" :key="col.columnId"
|
|
26
|
+
* @click="grid.toggleSort(col.columnId)">
|
|
27
|
+
* {{ col.name }} {{ grid.sortIndicator(col.columnId).value }}
|
|
28
|
+
* </th>
|
|
29
|
+
* </tr>
|
|
30
|
+
* </thead>
|
|
31
|
+
* <tbody>
|
|
32
|
+
* <tr v-for="row in grid.rows.value" :key="grid.getRowId(row)">
|
|
33
|
+
* <td v-for="col in grid.columns.value" :key="col.columnId">
|
|
34
|
+
* {{ grid.getCellValue(row, col.columnId) }}
|
|
35
|
+
* </td>
|
|
36
|
+
* </tr>
|
|
37
|
+
* </tbody>
|
|
38
|
+
* </table>
|
|
39
|
+
* </template>
|
|
40
|
+
*/
|
|
41
|
+
import { type ComputedRef, type Ref, type MaybeRefOrGetter } from 'vue';
|
|
42
|
+
import type { IColumnDef, IFilters, FilterValue } from '@alaarab/ogrid-core';
|
|
43
|
+
export type RowId = string | number;
|
|
44
|
+
export interface SortState {
|
|
45
|
+
field: string;
|
|
46
|
+
direction: 'asc' | 'desc';
|
|
47
|
+
}
|
|
48
|
+
export interface UseHeadlessGridParams<T> {
|
|
49
|
+
columns: MaybeRefOrGetter<IColumnDef<T>[]>;
|
|
50
|
+
data: MaybeRefOrGetter<T[]>;
|
|
51
|
+
/** Stable row ID extractor — must return the same ID for the same row across renders. */
|
|
52
|
+
getRowId: (row: T) => RowId;
|
|
53
|
+
initialSort?: SortState;
|
|
54
|
+
initialFilters?: IFilters;
|
|
55
|
+
initialPage?: number;
|
|
56
|
+
initialPageSize?: number;
|
|
57
|
+
}
|
|
58
|
+
export interface UseHeadlessGridResult<T> {
|
|
59
|
+
/** Resolved column definitions (reactive). */
|
|
60
|
+
columns: ComputedRef<IColumnDef<T>[]>;
|
|
61
|
+
/** Rows on the current page after sort + filter (reactive). */
|
|
62
|
+
rows: ComputedRef<T[]>;
|
|
63
|
+
/** Post-filter total row count (reactive). */
|
|
64
|
+
totalCount: ComputedRef<number>;
|
|
65
|
+
/** Total number of pages at current page size (reactive). */
|
|
66
|
+
totalPages: ComputedRef<number>;
|
|
67
|
+
/** Filtered + sorted rows across all pages (reactive). */
|
|
68
|
+
allFilteredRows: ComputedRef<T[]>;
|
|
69
|
+
/** Current sort state (mutable ref). */
|
|
70
|
+
sort: Ref<SortState>;
|
|
71
|
+
setSort: (sort: SortState) => void;
|
|
72
|
+
/** Cycle a column's sort: asc → desc → reset. */
|
|
73
|
+
toggleSort: (columnId: string) => void;
|
|
74
|
+
/** Reactive sort indicator: returns ComputedRef<'▲' | '▼' | ''>. */
|
|
75
|
+
sortIndicator: (columnId: string) => ComputedRef<'▲' | '▼' | ''>;
|
|
76
|
+
/** Current filter state (mutable ref). */
|
|
77
|
+
filters: Ref<IFilters>;
|
|
78
|
+
setFilters: (filters: IFilters) => void;
|
|
79
|
+
setFilter: (key: string, value: FilterValue | undefined) => void;
|
|
80
|
+
hasActiveFilters: ComputedRef<boolean>;
|
|
81
|
+
/** Pagination (mutable refs). */
|
|
82
|
+
page: Ref<number>;
|
|
83
|
+
pageSize: Ref<number>;
|
|
84
|
+
setPage: (page: number) => void;
|
|
85
|
+
setPageSize: (size: number) => void;
|
|
86
|
+
/** Stable row identity. */
|
|
87
|
+
getRowId: (row: T) => RowId;
|
|
88
|
+
/** Read a cell value with full column-resolution (valueGetter, key, etc). */
|
|
89
|
+
getCellValue: (row: T, columnId: string) => unknown;
|
|
90
|
+
/** Row selection — minimal Set-based API. */
|
|
91
|
+
selectedRowIds: Ref<Set<RowId>>;
|
|
92
|
+
isRowSelected: (row: T) => boolean;
|
|
93
|
+
toggleRowSelection: (row: T) => void;
|
|
94
|
+
selectAllOnPage: () => void;
|
|
95
|
+
clearSelection: () => void;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Headless grid state + actions composable for Vue.
|
|
99
|
+
*
|
|
100
|
+
* Pure data layer — does not render anything. Use this when you want to
|
|
101
|
+
* compose OGrid's sort/filter/paginate logic with your own table chrome.
|
|
102
|
+
*/
|
|
103
|
+
export declare function useHeadlessGrid<T>(params: UseHeadlessGridParams<T>): UseHeadlessGridResult<T>;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useInlineEdit (Vue) — headless inline-edit lifecycle for OGrid cells.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors the React useInlineEdit API with Vue-native reactivity (refs,
|
|
5
|
+
* computeds). Pairs with `useHeadlessGrid` for shadcn-style table chrome.
|
|
6
|
+
*/
|
|
7
|
+
import { type Ref } from 'vue';
|
|
8
|
+
import type { IColumnDef as ICoreColumnDef } from '@alaarab/ogrid-core';
|
|
9
|
+
export type RowId = string | number;
|
|
10
|
+
export interface InlineEditEvent<T> {
|
|
11
|
+
item: T;
|
|
12
|
+
columnId: string;
|
|
13
|
+
oldValue: unknown;
|
|
14
|
+
newValue: unknown;
|
|
15
|
+
}
|
|
16
|
+
export interface UseInlineEditParams<T> {
|
|
17
|
+
columns: ICoreColumnDef<T>[];
|
|
18
|
+
getRowId: (row: T) => RowId;
|
|
19
|
+
onCellEdit: (event: InlineEditEvent<T>) => void;
|
|
20
|
+
isCellEditable?: (row: T, columnId: string) => boolean;
|
|
21
|
+
}
|
|
22
|
+
export interface InlineEditorProps {
|
|
23
|
+
value: unknown;
|
|
24
|
+
onChange: (value: unknown) => void;
|
|
25
|
+
onCommit: () => void;
|
|
26
|
+
onCancel: () => void;
|
|
27
|
+
onKeyDown: (e: {
|
|
28
|
+
key: string;
|
|
29
|
+
preventDefault?: () => void;
|
|
30
|
+
stopPropagation?: () => void;
|
|
31
|
+
}) => void;
|
|
32
|
+
onBlur: () => void;
|
|
33
|
+
}
|
|
34
|
+
export interface UseInlineEditResult<T> {
|
|
35
|
+
editingCell: Ref<{
|
|
36
|
+
rowId: RowId;
|
|
37
|
+
columnId: string;
|
|
38
|
+
} | null>;
|
|
39
|
+
pendingValue: Ref<unknown>;
|
|
40
|
+
setPendingValue: (value: unknown) => void;
|
|
41
|
+
startEdit: (row: T, columnId: string) => void;
|
|
42
|
+
commitEdit: () => void;
|
|
43
|
+
cancelEdit: () => void;
|
|
44
|
+
isEditing: (row: T, columnId: string) => boolean;
|
|
45
|
+
canEdit: (row: T, columnId: string) => boolean;
|
|
46
|
+
getEditorProps: (row: T, columnId: string) => InlineEditorProps;
|
|
47
|
+
}
|
|
48
|
+
export declare function useInlineEdit<T>(params: UseInlineEditParams<T>): UseInlineEditResult<T>;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useRangeSelection (Vue) — headless cell-range selection for OGrid.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors the React API with Vue refs/computeds. Anchor + focus model.
|
|
5
|
+
* Foundation for useFillHandle and useCellClipboard.
|
|
6
|
+
*/
|
|
7
|
+
import { type ComputedRef, type Ref } from 'vue';
|
|
8
|
+
import type { ISelectionRange } from '@alaarab/ogrid-core';
|
|
9
|
+
export interface CellCoord {
|
|
10
|
+
row: number;
|
|
11
|
+
col: number;
|
|
12
|
+
}
|
|
13
|
+
export interface UseRangeSelectionParams {
|
|
14
|
+
rowCount: number;
|
|
15
|
+
colCount: number;
|
|
16
|
+
}
|
|
17
|
+
export interface UseRangeSelectionResult {
|
|
18
|
+
range: ComputedRef<ISelectionRange | null>;
|
|
19
|
+
anchor: Ref<CellCoord | null>;
|
|
20
|
+
focus: Ref<CellCoord | null>;
|
|
21
|
+
startRange: (row: number, col: number) => void;
|
|
22
|
+
extendRange: (row: number, col: number) => void;
|
|
23
|
+
setRange: (range: ISelectionRange | null) => void;
|
|
24
|
+
clearRange: () => void;
|
|
25
|
+
selectAll: () => void;
|
|
26
|
+
isInRange: (row: number, col: number) => boolean;
|
|
27
|
+
getRangeRows: () => number[];
|
|
28
|
+
getRangeCells: () => CellCoord[];
|
|
29
|
+
}
|
|
30
|
+
export declare function useRangeSelection(params: UseRangeSelectionParams): UseRangeSelectionResult;
|