@alaarab/ogrid-vue 2.0.6 → 2.0.7
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/composables/index.js +2 -0
- package/dist/esm/composables/useCellSelection.js +40 -3
- package/dist/esm/composables/useColumnHeaderMenuState.js +56 -0
- package/dist/esm/composables/useColumnPinning.js +64 -0
- package/dist/esm/composables/useDataGridState.js +36 -0
- package/dist/esm/composables/useOGrid.js +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/types/composables/index.d.ts +5 -1
- package/dist/types/composables/useColumnHeaderMenuState.d.ts +24 -0
- package/dist/types/composables/useColumnPinning.d.ts +33 -0
- package/dist/types/composables/useDataGridState.d.ts +27 -0
- package/dist/types/index.d.ts +2 -2
- package/dist/types/types/dataGridTypes.d.ts +8 -0
- package/package.json +2 -2
|
@@ -28,4 +28,6 @@ export { useRichSelectState } from './useRichSelectState';
|
|
|
28
28
|
export { useSideBarState } from './useSideBarState';
|
|
29
29
|
export { useColumnReorder } from './useColumnReorder';
|
|
30
30
|
export { useVirtualScroll } from './useVirtualScroll';
|
|
31
|
+
export { useColumnPinning } from './useColumnPinning';
|
|
32
|
+
export { useColumnHeaderMenuState } from './useColumnHeaderMenuState';
|
|
31
33
|
export { useDataGridTableSetup } from './useDataGridTableSetup';
|
|
@@ -10,8 +10,9 @@ function rangesEqual(a, b) {
|
|
|
10
10
|
return a.startRow === b.startRow && a.endRow === b.endRow &&
|
|
11
11
|
a.startCol === b.startCol && a.endCol === b.endCol;
|
|
12
12
|
}
|
|
13
|
-
/** DOM attribute
|
|
13
|
+
/** DOM attribute names used for drag-range highlighting (bypasses Vue). */
|
|
14
14
|
const DRAG_ATTR = 'data-drag-range';
|
|
15
|
+
const DRAG_ANCHOR_ATTR = 'data-drag-anchor';
|
|
15
16
|
/** Auto-scroll config */
|
|
16
17
|
const AUTO_SCROLL_EDGE = 40;
|
|
17
18
|
const AUTO_SCROLL_MIN_SPEED = 2;
|
|
@@ -72,6 +73,9 @@ export function useCellSelection(params) {
|
|
|
72
73
|
liveDragRange = initial;
|
|
73
74
|
setActiveCell({ rowIndex, columnIndex: globalColIndex });
|
|
74
75
|
isDraggingInternal = true;
|
|
76
|
+
// Apply drag attrs immediately for the initial cell so the anchor styling shows
|
|
77
|
+
// even before the first mousemove. This ensures instant visual feedback.
|
|
78
|
+
setTimeout(() => applyDragAttrs(initial), 0);
|
|
75
79
|
}
|
|
76
80
|
};
|
|
77
81
|
const handleSelectAllCells = () => {
|
|
@@ -87,6 +91,9 @@ export function useCellSelection(params) {
|
|
|
87
91
|
setActiveCell({ rowIndex: 0, columnIndex: colOffset });
|
|
88
92
|
};
|
|
89
93
|
// --- Window mouse move/up for drag selection ---
|
|
94
|
+
/** Toggle DRAG_ATTR on cells to show the range highlight via CSS.
|
|
95
|
+
* Also sets edge box-shadows for a green border around the selection range,
|
|
96
|
+
* and marks the anchor cell with DRAG_ANCHOR_ATTR (white background). */
|
|
90
97
|
const applyDragAttrs = (range) => {
|
|
91
98
|
const wrapper = wrapperRef.value;
|
|
92
99
|
if (!wrapper)
|
|
@@ -95,6 +102,7 @@ export function useCellSelection(params) {
|
|
|
95
102
|
const maxR = Math.max(range.startRow, range.endRow);
|
|
96
103
|
const minC = Math.min(range.startCol, range.endCol);
|
|
97
104
|
const maxC = Math.max(range.startCol, range.endCol);
|
|
105
|
+
const anchor = dragStart;
|
|
98
106
|
const cells = wrapper.querySelectorAll('[data-row-index][data-col-index]');
|
|
99
107
|
for (let i = 0; i < cells.length; i++) {
|
|
100
108
|
const el = cells[i];
|
|
@@ -104,10 +112,35 @@ export function useCellSelection(params) {
|
|
|
104
112
|
if (inRange) {
|
|
105
113
|
if (!el.hasAttribute(DRAG_ATTR))
|
|
106
114
|
el.setAttribute(DRAG_ATTR, '');
|
|
115
|
+
// Anchor cell gets white background instead of green
|
|
116
|
+
const isAnchor = anchor && r === anchor.row && c === anchor.col;
|
|
117
|
+
if (isAnchor) {
|
|
118
|
+
if (!el.hasAttribute(DRAG_ANCHOR_ATTR))
|
|
119
|
+
el.setAttribute(DRAG_ANCHOR_ATTR, '');
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
if (el.hasAttribute(DRAG_ANCHOR_ATTR))
|
|
123
|
+
el.removeAttribute(DRAG_ANCHOR_ATTR);
|
|
124
|
+
}
|
|
125
|
+
// Edge borders via inset box-shadow (no layout shift)
|
|
126
|
+
const shadows = [];
|
|
127
|
+
if (r === minR)
|
|
128
|
+
shadows.push('inset 0 2px 0 0 var(--ogrid-selection, #217346)');
|
|
129
|
+
if (r === maxR)
|
|
130
|
+
shadows.push('inset 0 -2px 0 0 var(--ogrid-selection, #217346)');
|
|
131
|
+
if (c === minC)
|
|
132
|
+
shadows.push('inset 2px 0 0 0 var(--ogrid-selection, #217346)');
|
|
133
|
+
if (c === maxC)
|
|
134
|
+
shadows.push('inset -2px 0 0 0 var(--ogrid-selection, #217346)');
|
|
135
|
+
el.style.boxShadow = shadows.length > 0 ? shadows.join(', ') : '';
|
|
107
136
|
}
|
|
108
137
|
else {
|
|
109
138
|
if (el.hasAttribute(DRAG_ATTR))
|
|
110
139
|
el.removeAttribute(DRAG_ATTR);
|
|
140
|
+
if (el.hasAttribute(DRAG_ANCHOR_ATTR))
|
|
141
|
+
el.removeAttribute(DRAG_ANCHOR_ATTR);
|
|
142
|
+
if (el.style.boxShadow)
|
|
143
|
+
el.style.boxShadow = '';
|
|
111
144
|
}
|
|
112
145
|
}
|
|
113
146
|
};
|
|
@@ -116,8 +149,12 @@ export function useCellSelection(params) {
|
|
|
116
149
|
if (!wrapper)
|
|
117
150
|
return;
|
|
118
151
|
const marked = wrapper.querySelectorAll(`[${DRAG_ATTR}]`);
|
|
119
|
-
for (let i = 0; i < marked.length; i++)
|
|
120
|
-
marked[i]
|
|
152
|
+
for (let i = 0; i < marked.length; i++) {
|
|
153
|
+
const el = marked[i];
|
|
154
|
+
el.removeAttribute(DRAG_ATTR);
|
|
155
|
+
el.removeAttribute(DRAG_ANCHOR_ATTR);
|
|
156
|
+
el.style.boxShadow = '';
|
|
157
|
+
}
|
|
121
158
|
};
|
|
122
159
|
const resolveRange = (cx, cy) => {
|
|
123
160
|
if (!dragStart)
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { ref, computed } from 'vue';
|
|
2
|
+
/**
|
|
3
|
+
* Manages state for the column header menu (pin left/right/unpin actions).
|
|
4
|
+
* Tracks which column's menu is open, anchor element, and action handlers.
|
|
5
|
+
*/
|
|
6
|
+
export function useColumnHeaderMenuState(params) {
|
|
7
|
+
const { pinnedColumns, onPinColumn, onUnpinColumn } = params;
|
|
8
|
+
const isOpen = ref(false);
|
|
9
|
+
const openForColumn = ref(null);
|
|
10
|
+
const anchorElement = ref(null);
|
|
11
|
+
const open = (columnId, anchorEl) => {
|
|
12
|
+
openForColumn.value = columnId;
|
|
13
|
+
anchorElement.value = anchorEl;
|
|
14
|
+
isOpen.value = true;
|
|
15
|
+
};
|
|
16
|
+
const close = () => {
|
|
17
|
+
isOpen.value = false;
|
|
18
|
+
openForColumn.value = null;
|
|
19
|
+
anchorElement.value = null;
|
|
20
|
+
};
|
|
21
|
+
const currentPinState = computed(() => openForColumn.value ? pinnedColumns.value[openForColumn.value] : undefined);
|
|
22
|
+
const canPinLeft = computed(() => currentPinState.value !== 'left');
|
|
23
|
+
const canPinRight = computed(() => currentPinState.value !== 'right');
|
|
24
|
+
const canUnpin = computed(() => !!currentPinState.value);
|
|
25
|
+
const handlePinLeft = () => {
|
|
26
|
+
if (openForColumn.value && canPinLeft.value) {
|
|
27
|
+
onPinColumn(openForColumn.value, 'left');
|
|
28
|
+
close();
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
const handlePinRight = () => {
|
|
32
|
+
if (openForColumn.value && canPinRight.value) {
|
|
33
|
+
onPinColumn(openForColumn.value, 'right');
|
|
34
|
+
close();
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
const handleUnpin = () => {
|
|
38
|
+
if (openForColumn.value && canUnpin.value) {
|
|
39
|
+
onUnpinColumn(openForColumn.value);
|
|
40
|
+
close();
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
return {
|
|
44
|
+
isOpen,
|
|
45
|
+
openForColumn,
|
|
46
|
+
anchorElement,
|
|
47
|
+
open,
|
|
48
|
+
close,
|
|
49
|
+
handlePinLeft,
|
|
50
|
+
handlePinRight,
|
|
51
|
+
handleUnpin,
|
|
52
|
+
canPinLeft,
|
|
53
|
+
canPinRight,
|
|
54
|
+
canUnpin,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { ref, computed } from 'vue';
|
|
2
|
+
/**
|
|
3
|
+
* Manages column pinning state (left/right sticky positioning).
|
|
4
|
+
* Supports controlled and uncontrolled modes.
|
|
5
|
+
* Initializes from column.pinned definitions and pinnedColumns prop.
|
|
6
|
+
*/
|
|
7
|
+
export function useColumnPinning(params) {
|
|
8
|
+
const { columns, pinnedColumns: controlledPinnedColumns, onColumnPinned } = params;
|
|
9
|
+
// Initialize internal state from column.pinned definitions (only on mount)
|
|
10
|
+
const initialPinnedColumns = {};
|
|
11
|
+
for (const col of columns.value) {
|
|
12
|
+
if (col.pinned) {
|
|
13
|
+
initialPinnedColumns[col.columnId] = col.pinned;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
const internalPinnedColumns = ref(initialPinnedColumns);
|
|
17
|
+
// Use controlled state if provided, otherwise internal
|
|
18
|
+
const pinnedColumns = computed(() => controlledPinnedColumns?.value ?? internalPinnedColumns.value);
|
|
19
|
+
const pinColumn = (columnId, side) => {
|
|
20
|
+
const next = { ...pinnedColumns.value, [columnId]: side };
|
|
21
|
+
internalPinnedColumns.value = next;
|
|
22
|
+
onColumnPinned?.(columnId, side);
|
|
23
|
+
};
|
|
24
|
+
const unpinColumn = (columnId) => {
|
|
25
|
+
const next = { ...pinnedColumns.value };
|
|
26
|
+
delete next[columnId];
|
|
27
|
+
internalPinnedColumns.value = next;
|
|
28
|
+
onColumnPinned?.(columnId, null);
|
|
29
|
+
};
|
|
30
|
+
const isPinned = (columnId) => {
|
|
31
|
+
return pinnedColumns.value[columnId];
|
|
32
|
+
};
|
|
33
|
+
const computeLeftOffsets = (visibleCols, columnWidths, defaultWidth, hasCheckboxColumn, checkboxColumnWidth) => {
|
|
34
|
+
const offsets = {};
|
|
35
|
+
let left = hasCheckboxColumn ? checkboxColumnWidth : 0;
|
|
36
|
+
for (const col of visibleCols) {
|
|
37
|
+
if (pinnedColumns.value[col.columnId] === 'left') {
|
|
38
|
+
offsets[col.columnId] = left;
|
|
39
|
+
left += columnWidths[col.columnId] ?? defaultWidth;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return offsets;
|
|
43
|
+
};
|
|
44
|
+
const computeRightOffsets = (visibleCols, columnWidths, defaultWidth) => {
|
|
45
|
+
const offsets = {};
|
|
46
|
+
let right = 0;
|
|
47
|
+
for (let i = visibleCols.length - 1; i >= 0; i--) {
|
|
48
|
+
const col = visibleCols[i];
|
|
49
|
+
if (pinnedColumns.value[col.columnId] === 'right') {
|
|
50
|
+
offsets[col.columnId] = right;
|
|
51
|
+
right += columnWidths[col.columnId] ?? defaultWidth;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return offsets;
|
|
55
|
+
};
|
|
56
|
+
return {
|
|
57
|
+
pinnedColumns,
|
|
58
|
+
pinColumn,
|
|
59
|
+
unpinColumn,
|
|
60
|
+
isPinned,
|
|
61
|
+
computeLeftOffsets,
|
|
62
|
+
computeRightOffsets,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
@@ -10,6 +10,8 @@ import { useKeyboardNavigation } from './useKeyboardNavigation';
|
|
|
10
10
|
import { useFillHandle } from './useFillHandle';
|
|
11
11
|
import { useUndoRedo } from './useUndoRedo';
|
|
12
12
|
import { useTableLayout } from './useTableLayout';
|
|
13
|
+
import { useColumnPinning } from './useColumnPinning';
|
|
14
|
+
import { useColumnHeaderMenuState } from './useColumnHeaderMenuState';
|
|
13
15
|
// Stable no-op handlers
|
|
14
16
|
const NOOP = () => { };
|
|
15
17
|
const NOOP_ASYNC = async () => { };
|
|
@@ -39,6 +41,7 @@ export function useDataGridState(params) {
|
|
|
39
41
|
const initialColumnWidths = computed(() => props.value.initialColumnWidths);
|
|
40
42
|
const onColumnResizedProp = computed(() => props.value.onColumnResized);
|
|
41
43
|
const pinnedColumnsProp = computed(() => props.value.pinnedColumns);
|
|
44
|
+
const onColumnPinnedProp = computed(() => props.value.onColumnPinned);
|
|
42
45
|
const onCellErrorProp = computed(() => props.value.onCellError);
|
|
43
46
|
// Undo/redo wrapping
|
|
44
47
|
const undoRedo = useUndoRedo({ onCellValueChanged: onCellValueChangedProp.value });
|
|
@@ -166,6 +169,17 @@ export function useDataGridState(params) {
|
|
|
166
169
|
initialColumnWidths: initialColumnWidths.value,
|
|
167
170
|
onColumnResized: onColumnResizedProp.value,
|
|
168
171
|
});
|
|
172
|
+
// --- Column pinning ---
|
|
173
|
+
const pinningResult = useColumnPinning({
|
|
174
|
+
columns: flatColumns,
|
|
175
|
+
pinnedColumns: pinnedColumnsProp,
|
|
176
|
+
onColumnPinned: onColumnPinnedProp.value,
|
|
177
|
+
});
|
|
178
|
+
const headerMenuResult = useColumnHeaderMenuState({
|
|
179
|
+
pinnedColumns: pinningResult.pinnedColumns,
|
|
180
|
+
onPinColumn: pinningResult.pinColumn,
|
|
181
|
+
onUnpinColumn: pinningResult.unpinColumn,
|
|
182
|
+
});
|
|
169
183
|
const aggregation = computed(() => computeAggregations(items.value, visibleCols.value, cellSelection.value ? selectionRange.value : null));
|
|
170
184
|
const statusBarConfig = computed(() => {
|
|
171
185
|
const base = getDataGridStatusBarConfig(statusBarProp.value, items.value.length, rowSelectionResult.selectedRowIds.value.size);
|
|
@@ -305,6 +319,27 @@ export function useDataGridState(params) {
|
|
|
305
319
|
showEmptyInGrid: showEmptyInGrid.value,
|
|
306
320
|
onCellError: onCellErrorProp.value,
|
|
307
321
|
}));
|
|
322
|
+
const pinningState = computed(() => ({
|
|
323
|
+
pinnedColumns: pinningResult.pinnedColumns.value,
|
|
324
|
+
pinColumn: pinningResult.pinColumn,
|
|
325
|
+
unpinColumn: pinningResult.unpinColumn,
|
|
326
|
+
isPinned: pinningResult.isPinned,
|
|
327
|
+
computeLeftOffsets: pinningResult.computeLeftOffsets,
|
|
328
|
+
computeRightOffsets: pinningResult.computeRightOffsets,
|
|
329
|
+
headerMenu: {
|
|
330
|
+
isOpen: headerMenuResult.isOpen.value,
|
|
331
|
+
openForColumn: headerMenuResult.openForColumn.value,
|
|
332
|
+
anchorElement: headerMenuResult.anchorElement.value,
|
|
333
|
+
open: headerMenuResult.open,
|
|
334
|
+
close: headerMenuResult.close,
|
|
335
|
+
handlePinLeft: headerMenuResult.handlePinLeft,
|
|
336
|
+
handlePinRight: headerMenuResult.handlePinRight,
|
|
337
|
+
handleUnpin: headerMenuResult.handleUnpin,
|
|
338
|
+
canPinLeft: headerMenuResult.canPinLeft.value,
|
|
339
|
+
canPinRight: headerMenuResult.canPinRight.value,
|
|
340
|
+
canUnpin: headerMenuResult.canUnpin.value,
|
|
341
|
+
},
|
|
342
|
+
}));
|
|
308
343
|
return {
|
|
309
344
|
layout: layoutState,
|
|
310
345
|
rowSelection: rowSelectionState,
|
|
@@ -312,5 +347,6 @@ export function useDataGridState(params) {
|
|
|
312
347
|
interaction: interactionState,
|
|
313
348
|
contextMenu: contextMenuState,
|
|
314
349
|
viewModels: viewModelsState,
|
|
350
|
+
pinning: pinningState,
|
|
315
351
|
};
|
|
316
352
|
}
|
|
@@ -252,7 +252,7 @@ export function useOGrid(props) {
|
|
|
252
252
|
};
|
|
253
253
|
const handleColumnPinned = (columnId, pinned) => {
|
|
254
254
|
if (pinned === null) {
|
|
255
|
-
const { [columnId]:
|
|
255
|
+
const { [columnId]: _removed, ...rest } = pinnedOverrides.value;
|
|
256
256
|
pinnedOverrides.value = rest;
|
|
257
257
|
}
|
|
258
258
|
else {
|
package/dist/esm/index.js
CHANGED
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
export * from '@alaarab/ogrid-core';
|
|
3
3
|
export { toUserLike, isInSelectionRange, normalizeSelectionRange } from './types';
|
|
4
4
|
// Composables
|
|
5
|
-
export { useOGrid, useDataGridState, useActiveCell, useCellEditing, useCellSelection, useClipboard, useRowSelection, useKeyboardNavigation, useFillHandle, useUndoRedo, useContextMenu, useColumnResize, useColumnReorder, useVirtualScroll, useFilterOptions, useDebounce, useDebouncedCallback, useTableLayout, useColumnHeaderFilterState, useTextFilterState, useMultiSelectFilterState, usePeopleFilterState, useDateFilterState, useColumnChooserState, useInlineCellEditorState, useRichSelectState, useSideBarState, useDataGridTableSetup, } from './composables';
|
|
5
|
+
export { useOGrid, useDataGridState, useActiveCell, useCellEditing, useCellSelection, useClipboard, useRowSelection, useKeyboardNavigation, useFillHandle, useUndoRedo, useContextMenu, useColumnResize, useColumnReorder, useVirtualScroll, useFilterOptions, useDebounce, useDebouncedCallback, useTableLayout, useColumnHeaderFilterState, useTextFilterState, useMultiSelectFilterState, usePeopleFilterState, useDateFilterState, useColumnChooserState, useInlineCellEditorState, useRichSelectState, useSideBarState, useColumnPinning, useColumnHeaderMenuState, useDataGridTableSetup, } from './composables';
|
|
6
6
|
// View model utilities (for UI packages)
|
|
7
7
|
export { getHeaderFilterConfig, getCellRenderDescriptor, resolveCellDisplayContent, resolveCellStyle, buildInlineEditorProps, buildPopoverEditorProps, getCellInteractionProps, } from './utils';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { useOGrid } from './useOGrid';
|
|
2
2
|
export type { UseOGridResult, UseOGridPagination, UseOGridColumnChooser, UseOGridLayout, UseOGridFilters, ColumnChooserPlacement, } from './useOGrid';
|
|
3
3
|
export { useDataGridState } from './useDataGridState';
|
|
4
|
-
export type { UseDataGridStateParams, UseDataGridStateResult, DataGridLayoutState, DataGridRowSelectionState, DataGridEditingState, DataGridCellInteractionState, DataGridContextMenuState, DataGridViewModelState, } from './useDataGridState';
|
|
4
|
+
export type { UseDataGridStateParams, UseDataGridStateResult, DataGridLayoutState, DataGridRowSelectionState, DataGridEditingState, DataGridCellInteractionState, DataGridContextMenuState, DataGridViewModelState, DataGridPinningState, } from './useDataGridState';
|
|
5
5
|
export { useActiveCell } from './useActiveCell';
|
|
6
6
|
export type { UseActiveCellResult } from './useActiveCell';
|
|
7
7
|
export { useCellEditing } from './useCellEditing';
|
|
@@ -51,5 +51,9 @@ export { useColumnReorder } from './useColumnReorder';
|
|
|
51
51
|
export type { UseColumnReorderParams, UseColumnReorderResult } from './useColumnReorder';
|
|
52
52
|
export { useVirtualScroll } from './useVirtualScroll';
|
|
53
53
|
export type { UseVirtualScrollParams, UseVirtualScrollResult } from './useVirtualScroll';
|
|
54
|
+
export { useColumnPinning } from './useColumnPinning';
|
|
55
|
+
export type { UseColumnPinningParams, UseColumnPinningResult } from './useColumnPinning';
|
|
56
|
+
export { useColumnHeaderMenuState } from './useColumnHeaderMenuState';
|
|
57
|
+
export type { UseColumnHeaderMenuStateParams, UseColumnHeaderMenuStateResult } from './useColumnHeaderMenuState';
|
|
54
58
|
export { useDataGridTableSetup } from './useDataGridTableSetup';
|
|
55
59
|
export type { UseDataGridTableSetupParams, UseDataGridTableSetupResult } from './useDataGridTableSetup';
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { type Ref } from 'vue';
|
|
2
|
+
export interface UseColumnHeaderMenuStateParams {
|
|
3
|
+
pinnedColumns: Ref<Record<string, 'left' | 'right'>>;
|
|
4
|
+
onPinColumn: (columnId: string, side: 'left' | 'right') => void;
|
|
5
|
+
onUnpinColumn: (columnId: string) => void;
|
|
6
|
+
}
|
|
7
|
+
export interface UseColumnHeaderMenuStateResult {
|
|
8
|
+
isOpen: Ref<boolean>;
|
|
9
|
+
openForColumn: Ref<string | null>;
|
|
10
|
+
anchorElement: Ref<HTMLElement | null>;
|
|
11
|
+
open: (columnId: string, anchorEl: HTMLElement) => void;
|
|
12
|
+
close: () => void;
|
|
13
|
+
handlePinLeft: () => void;
|
|
14
|
+
handlePinRight: () => void;
|
|
15
|
+
handleUnpin: () => void;
|
|
16
|
+
canPinLeft: Ref<boolean>;
|
|
17
|
+
canPinRight: Ref<boolean>;
|
|
18
|
+
canUnpin: Ref<boolean>;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Manages state for the column header menu (pin left/right/unpin actions).
|
|
22
|
+
* Tracks which column's menu is open, anchor element, and action handlers.
|
|
23
|
+
*/
|
|
24
|
+
export declare function useColumnHeaderMenuState(params: UseColumnHeaderMenuStateParams): UseColumnHeaderMenuStateResult;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { type Ref } from 'vue';
|
|
2
|
+
import type { IColumnDef } from '../types';
|
|
3
|
+
export interface UseColumnPinningParams<T = unknown> {
|
|
4
|
+
columns: Ref<IColumnDef<T>[]>;
|
|
5
|
+
/** Controlled pinned columns state. If provided, component is controlled. */
|
|
6
|
+
pinnedColumns?: Ref<Record<string, 'left' | 'right'> | undefined>;
|
|
7
|
+
/** Called when user pins/unpins a column via UI. */
|
|
8
|
+
onColumnPinned?: (columnId: string, pinned: 'left' | 'right' | null) => void;
|
|
9
|
+
}
|
|
10
|
+
export interface UseColumnPinningResult {
|
|
11
|
+
/** Current pinned columns (controlled or internal). */
|
|
12
|
+
pinnedColumns: Ref<Record<string, 'left' | 'right'>>;
|
|
13
|
+
/** Pin a column to left or right. */
|
|
14
|
+
pinColumn: (columnId: string, side: 'left' | 'right') => void;
|
|
15
|
+
/** Unpin a column. */
|
|
16
|
+
unpinColumn: (columnId: string) => void;
|
|
17
|
+
/** Check if a column is pinned and which side. */
|
|
18
|
+
isPinned: (columnId: string) => 'left' | 'right' | undefined;
|
|
19
|
+
/** Compute sticky left offsets for pinned columns. */
|
|
20
|
+
computeLeftOffsets: (visibleCols: {
|
|
21
|
+
columnId: string;
|
|
22
|
+
}[], columnWidths: Record<string, number>, defaultWidth: number, hasCheckboxColumn: boolean, checkboxColumnWidth: number) => Record<string, number>;
|
|
23
|
+
/** Compute sticky right offsets for pinned columns. */
|
|
24
|
+
computeRightOffsets: (visibleCols: {
|
|
25
|
+
columnId: string;
|
|
26
|
+
}[], columnWidths: Record<string, number>, defaultWidth: number) => Record<string, number>;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Manages column pinning state (left/right sticky positioning).
|
|
30
|
+
* Supports controlled and uncontrolled modes.
|
|
31
|
+
* Initializes from column.pinned definitions and pinnedColumns prop.
|
|
32
|
+
*/
|
|
33
|
+
export declare function useColumnPinning<T = unknown>(params: UseColumnPinningParams<T>): UseColumnPinningResult;
|
|
@@ -115,6 +115,32 @@ export interface DataGridViewModelState<T> {
|
|
|
115
115
|
showEmptyInGrid: boolean;
|
|
116
116
|
onCellError?: (error: Error, info: unknown) => void;
|
|
117
117
|
}
|
|
118
|
+
/** Column pinning state and column header menu. */
|
|
119
|
+
export interface DataGridPinningState {
|
|
120
|
+
pinnedColumns: Record<string, 'left' | 'right'>;
|
|
121
|
+
pinColumn: (columnId: string, side: 'left' | 'right') => void;
|
|
122
|
+
unpinColumn: (columnId: string) => void;
|
|
123
|
+
isPinned: (columnId: string) => 'left' | 'right' | undefined;
|
|
124
|
+
computeLeftOffsets: (visibleCols: {
|
|
125
|
+
columnId: string;
|
|
126
|
+
}[], columnWidths: Record<string, number>, defaultWidth: number, hasCheckboxColumn: boolean, checkboxColumnWidth: number) => Record<string, number>;
|
|
127
|
+
computeRightOffsets: (visibleCols: {
|
|
128
|
+
columnId: string;
|
|
129
|
+
}[], columnWidths: Record<string, number>, defaultWidth: number) => Record<string, number>;
|
|
130
|
+
headerMenu: {
|
|
131
|
+
isOpen: boolean;
|
|
132
|
+
openForColumn: string | null;
|
|
133
|
+
anchorElement: HTMLElement | null;
|
|
134
|
+
open: (columnId: string, anchorEl: HTMLElement) => void;
|
|
135
|
+
close: () => void;
|
|
136
|
+
handlePinLeft: () => void;
|
|
137
|
+
handlePinRight: () => void;
|
|
138
|
+
handleUnpin: () => void;
|
|
139
|
+
canPinLeft: boolean;
|
|
140
|
+
canPinRight: boolean;
|
|
141
|
+
canUnpin: boolean;
|
|
142
|
+
};
|
|
143
|
+
}
|
|
118
144
|
export interface UseDataGridStateResult<T> {
|
|
119
145
|
layout: Ref<DataGridLayoutState<T>>;
|
|
120
146
|
rowSelection: Ref<DataGridRowSelectionState>;
|
|
@@ -122,6 +148,7 @@ export interface UseDataGridStateResult<T> {
|
|
|
122
148
|
interaction: Ref<DataGridCellInteractionState>;
|
|
123
149
|
contextMenu: Ref<DataGridContextMenuState>;
|
|
124
150
|
viewModels: Ref<DataGridViewModelState<T>>;
|
|
151
|
+
pinning: Ref<DataGridPinningState>;
|
|
125
152
|
}
|
|
126
153
|
/**
|
|
127
154
|
* Single orchestration composable for DataGridTable. Takes grid props and wrapper ref,
|
package/dist/types/index.d.ts
CHANGED
|
@@ -2,8 +2,8 @@ export * from '@alaarab/ogrid-core';
|
|
|
2
2
|
export type { IColumnDef, ICellEditorProps, IOGridProps, IOGridClientProps, IOGridServerProps, IOGridDataGridProps, } from './types';
|
|
3
3
|
export type { ColumnFilterType, IColumnFilterDef, IColumnMeta, IColumnGroupDef, IColumnDefinition, ICellValueChangedEvent, CellEditorParams, IValueParserParams, IDateFilterValue, HeaderCell, HeaderRow, RowId, UserLike, UserLikeInput, FilterValue, IFilters, IFetchParams, IPageResult, IDataSource, IGridColumnState, IOGridApi, RowSelectionMode, IRowSelectionChangeEvent, StatusBarPanel, IStatusBarProps, IActiveCell, ISelectionRange, SideBarPanelId, ISideBarDef, IVirtualScrollConfig, } from './types';
|
|
4
4
|
export { toUserLike, isInSelectionRange, normalizeSelectionRange } from './types';
|
|
5
|
-
export { useOGrid, useDataGridState, useActiveCell, useCellEditing, useCellSelection, useClipboard, useRowSelection, useKeyboardNavigation, useFillHandle, useUndoRedo, useContextMenu, useColumnResize, useColumnReorder, useVirtualScroll, useFilterOptions, useDebounce, useDebouncedCallback, useTableLayout, useColumnHeaderFilterState, useTextFilterState, useMultiSelectFilterState, usePeopleFilterState, useDateFilterState, useColumnChooserState, useInlineCellEditorState, useRichSelectState, useSideBarState, useDataGridTableSetup, } from './composables';
|
|
6
|
-
export type { UseOGridResult, UseOGridPagination, UseOGridColumnChooser, UseOGridLayout, UseOGridFilters, ColumnChooserPlacement, UseDataGridStateParams, UseDataGridStateResult, DataGridLayoutState, DataGridRowSelectionState, DataGridEditingState, DataGridCellInteractionState, DataGridContextMenuState, DataGridViewModelState, UseActiveCellResult, EditingCell, UseCellEditingParams, UseCellEditingResult, UseCellSelectionParams, UseCellSelectionResult, UseClipboardParams, UseClipboardResult, UseRowSelectionParams, UseRowSelectionResult, UseKeyboardNavigationParams, UseKeyboardNavigationResult, UseFillHandleParams, UseFillHandleResult, UseUndoRedoParams, UseUndoRedoResult, ContextMenuPosition, UseContextMenuResult, UseColumnResizeParams, UseColumnResizeResult, UseColumnReorderParams, UseColumnReorderResult, UseVirtualScrollParams, UseVirtualScrollResult, UseFilterOptionsResult, UseTableLayoutParams, UseTableLayoutResult, UseColumnHeaderFilterStateParams, UseColumnHeaderFilterStateResult, UseTextFilterStateParams, UseTextFilterStateResult, UseMultiSelectFilterStateParams, UseMultiSelectFilterStateResult, UsePeopleFilterStateParams, UsePeopleFilterStateResult, UseDateFilterStateParams, UseDateFilterStateResult, UseColumnChooserStateParams, UseColumnChooserStateResult, InlineCellEditorType, UseInlineCellEditorStateParams, UseInlineCellEditorStateResult, UseRichSelectStateParams, UseRichSelectStateResult, UseSideBarStateParams, UseSideBarStateResult, DebouncedFn, UseDataGridTableSetupParams, UseDataGridTableSetupResult, } from './composables';
|
|
5
|
+
export { useOGrid, useDataGridState, useActiveCell, useCellEditing, useCellSelection, useClipboard, useRowSelection, useKeyboardNavigation, useFillHandle, useUndoRedo, useContextMenu, useColumnResize, useColumnReorder, useVirtualScroll, useFilterOptions, useDebounce, useDebouncedCallback, useTableLayout, useColumnHeaderFilterState, useTextFilterState, useMultiSelectFilterState, usePeopleFilterState, useDateFilterState, useColumnChooserState, useInlineCellEditorState, useRichSelectState, useSideBarState, useColumnPinning, useColumnHeaderMenuState, useDataGridTableSetup, } from './composables';
|
|
6
|
+
export type { UseOGridResult, UseOGridPagination, UseOGridColumnChooser, UseOGridLayout, UseOGridFilters, ColumnChooserPlacement, UseDataGridStateParams, UseDataGridStateResult, DataGridLayoutState, DataGridRowSelectionState, DataGridEditingState, DataGridCellInteractionState, DataGridContextMenuState, DataGridViewModelState, DataGridPinningState, UseActiveCellResult, EditingCell, UseCellEditingParams, UseCellEditingResult, UseCellSelectionParams, UseCellSelectionResult, UseClipboardParams, UseClipboardResult, UseRowSelectionParams, UseRowSelectionResult, UseKeyboardNavigationParams, UseKeyboardNavigationResult, UseFillHandleParams, UseFillHandleResult, UseUndoRedoParams, UseUndoRedoResult, ContextMenuPosition, UseContextMenuResult, UseColumnResizeParams, UseColumnResizeResult, UseColumnReorderParams, UseColumnReorderResult, UseVirtualScrollParams, UseVirtualScrollResult, UseFilterOptionsResult, UseTableLayoutParams, UseTableLayoutResult, UseColumnHeaderFilterStateParams, UseColumnHeaderFilterStateResult, UseTextFilterStateParams, UseTextFilterStateResult, UseMultiSelectFilterStateParams, UseMultiSelectFilterStateResult, UsePeopleFilterStateParams, UsePeopleFilterStateResult, UseDateFilterStateParams, UseDateFilterStateResult, UseColumnChooserStateParams, UseColumnChooserStateResult, InlineCellEditorType, UseInlineCellEditorStateParams, UseInlineCellEditorStateResult, UseRichSelectStateParams, UseRichSelectStateResult, UseSideBarStateParams, UseSideBarStateResult, DebouncedFn, UseColumnPinningParams, UseColumnPinningResult, UseColumnHeaderMenuStateParams, UseColumnHeaderMenuStateResult, UseDataGridTableSetupParams, UseDataGridTableSetupResult, } from './composables';
|
|
7
7
|
export { getHeaderFilterConfig, getCellRenderDescriptor, resolveCellDisplayContent, resolveCellStyle, buildInlineEditorProps, buildPopoverEditorProps, getCellInteractionProps, } from './utils';
|
|
8
8
|
export type { HeaderFilterConfigInput, HeaderFilterConfig, CellRenderDescriptorInput, CellRenderDescriptor, CellRenderMode, CellInteractionHandlers, CellInteractionProps, } from './utils';
|
|
9
9
|
export type { SideBarProps, SideBarFilterColumn } from './components/SideBar';
|
|
@@ -73,8 +73,12 @@ interface IOGridBaseProps<T> {
|
|
|
73
73
|
onError?: (error: unknown) => void;
|
|
74
74
|
/** Called when a cell renderer or custom editor throws an error. */
|
|
75
75
|
onCellError?: (error: Error, info: unknown) => void;
|
|
76
|
+
/** Enable column reordering via drag-and-drop on header cells. Default: false. */
|
|
77
|
+
columnReorder?: boolean;
|
|
76
78
|
/** Virtual scrolling configuration. Set `enabled: true` with a fixed `rowHeight` to virtualize large datasets. */
|
|
77
79
|
virtualScroll?: IVirtualScrollConfig;
|
|
80
|
+
/** Cell spacing/density preset. Controls cell padding throughout the grid. Default: 'normal'. */
|
|
81
|
+
density?: 'compact' | 'normal' | 'comfortable';
|
|
78
82
|
'aria-label'?: string;
|
|
79
83
|
'aria-labelledby'?: string;
|
|
80
84
|
}
|
|
@@ -151,8 +155,12 @@ export interface IOGridDataGridProps<T> {
|
|
|
151
155
|
};
|
|
152
156
|
/** Called when a cell renderer or custom editor throws an error. */
|
|
153
157
|
onCellError?: (error: Error, info: unknown) => void;
|
|
158
|
+
/** Enable column reordering via drag-and-drop on header cells. Default: false. */
|
|
159
|
+
columnReorder?: boolean;
|
|
154
160
|
/** Virtual scrolling configuration. */
|
|
155
161
|
virtualScroll?: IVirtualScrollConfig;
|
|
162
|
+
/** Cell spacing/density preset. Controls cell padding throughout the grid. Default: 'normal'. */
|
|
163
|
+
density?: 'compact' | 'normal' | 'comfortable';
|
|
156
164
|
'aria-label'?: string;
|
|
157
165
|
'aria-labelledby'?: string;
|
|
158
166
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alaarab/ogrid-vue",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.7",
|
|
4
4
|
"description": "OGrid Vue – Vue 3 composables, headless components, and utilities for OGrid data grids.",
|
|
5
5
|
"main": "dist/esm/index.js",
|
|
6
6
|
"module": "dist/esm/index.js",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"files": ["dist", "README.md", "LICENSE"],
|
|
23
23
|
"engines": { "node": ">=18" },
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@alaarab/ogrid-core": "2.0.
|
|
25
|
+
"@alaarab/ogrid-core": "2.0.7"
|
|
26
26
|
},
|
|
27
27
|
"peerDependencies": {
|
|
28
28
|
"vue": "^3.3.0"
|