@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.
@@ -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 name used for drag-range highlighting (bypasses Vue). */
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].removeAttribute(DRAG_ATTR);
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]: _, ...rest } = pinnedOverrides.value;
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,
@@ -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.6",
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.6"
25
+ "@alaarab/ogrid-core": "2.0.7"
26
26
  },
27
27
  "peerDependencies": {
28
28
  "vue": "^3.3.0"