@alaarab/ogrid 1.3.0 → 1.3.2

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.
@@ -79,47 +79,48 @@ function DataGridTableInner(props) {
79
79
  ['--data-table-width']: showEmptyInGrid ? '100%' : allowOverflowX ? 'fit-content' : fitToContent ? 'fit-content' : '100%',
80
80
  ['--data-table-min-width']: showEmptyInGrid ? '100%' : allowOverflowX ? 'max-content' : fitToContent ? 'max-content' : '100%',
81
81
  ['--data-table-total-min-width']: `${minTableWidth}px`,
82
- }, children: [_jsxs("div", { className: styles.tableScrollContent, children: [_jsxs("div", { className: isLoading && items.length > 0 ? styles.loadingOverlayContainer : undefined, children: [isLoading && items.length > 0 && (_jsx("div", { className: styles.loadingOverlay, "aria-live": "polite", children: _jsxs("div", { className: styles.loadingOverlayContent, children: [_jsx("div", { className: styles.spinner }), _jsx("span", { className: styles.loadingOverlayText, children: loadingMessage })] }) })), _jsx("div", { className: isLoading && items.length > 0 ? styles.loadingDimmed : undefined, children: _jsxs("div", { className: styles.tableWidthAnchor, ref: tableContainerRef, children: [_jsxs("table", { className: styles.dataTable, children: [_jsx("thead", { className: freezeRows != null && freezeRows >= 1 ? styles.stickyHeader : undefined, children: _jsxs("tr", { children: [hasCheckboxCol && (_jsx("th", { className: styles.selectionHeaderCell, scope: "col", children: _jsx("div", { className: styles.selectionHeaderCellInner, children: _jsx(Checkbox.Root, { className: styles.rowCheckbox, checked: allSelected ? true : someSelected ? 'indeterminate' : false, onCheckedChange: (c) => handleSelectAll(!!c), "aria-label": "Select all rows", children: _jsx(Checkbox.Indicator, { className: styles.rowCheckboxIndicator, children: someSelected && !allSelected ? '–' : '✓' }) }) }) })), visibleCols.map((col, colIdx) => {
83
- const isFreezeCol = freezeCols != null && freezeCols >= 1 && colIdx < freezeCols;
84
- const isPinnedLeft = col.pinned === 'left';
85
- const isPinnedRight = col.pinned === 'right';
86
- const columnWidth = getColumnWidth(col);
87
- return (_jsxs("th", { scope: "col", "data-column-id": col.columnId, className: [
88
- isFreezeCol ? styles.freezeCol : '',
89
- isFreezeCol && colIdx === 0 ? styles.freezeColFirst : '',
90
- isPinnedLeft ? styles.pinnedColLeft : '',
91
- isPinnedRight ? styles.pinnedColRight : '',
92
- ].filter(Boolean).join(' '), style: {
93
- minWidth: col.minWidth ?? 80,
94
- width: columnWidth,
95
- maxWidth: columnWidth,
96
- position: 'relative',
97
- }, children: [_jsx(ColumnHeaderFilter, { ...getHeaderFilterConfig(col, headerFilterInput) }), _jsx("div", { className: styles.resizeHandle, onMouseDown: (e) => handleResizeStart(e, col), "aria-label": `Resize ${col.name}` })] }, col.columnId));
98
- })] }) }), !showEmptyInGrid && (_jsx("tbody", { children: items.map((item, rowIndex) => {
99
- const rowIdStr = getRowId(item);
100
- const isSelected = selectedRowIds.has(rowIdStr);
101
- return (_jsxs("tr", { className: isSelected ? styles.selectedRow : '', onClick: () => {
102
- if (rowSelection === 'single') {
103
- const id = getRowId(item);
104
- updateSelection(selectedRowIds.has(id) ? new Set() : new Set([id]));
105
- }
106
- }, children: [hasCheckboxCol && (_jsx("td", { className: styles.selectionCell, children: _jsx("div", { className: styles.selectionCellInner, "data-row-index": rowIndex, "data-col-index": 0, onClick: (e) => e.stopPropagation(), children: _jsx(Checkbox.Root, { className: styles.rowCheckbox, checked: selectedRowIds.has(rowIdStr), onCheckedChange: (c) => handleRowCheckboxChange(rowIdStr, !!c, rowIndex, lastMouseShiftRef.current), "aria-label": `Select row ${rowIndex + 1}`, children: _jsx(Checkbox.Indicator, { className: styles.rowCheckboxIndicator, children: "\u2713" }) }) }) })), visibleCols.map((col, colIdx) => {
107
- const isFreezeCol = freezeCols != null && freezeCols >= 1 && colIdx < freezeCols;
108
- const isPinnedLeft = col.pinned === 'left';
109
- const isPinnedRight = col.pinned === 'right';
110
- const columnWidth = getColumnWidth(col);
111
- return (_jsx("td", { className: [
112
- isFreezeCol ? styles.freezeCol : '',
113
- isFreezeCol && colIdx === 0 ? styles.freezeColFirst : '',
114
- isPinnedLeft ? styles.pinnedColLeft : '',
115
- isPinnedRight ? styles.pinnedColRight : '',
116
- ].filter(Boolean).join(' '), style: {
117
- minWidth: col.minWidth ?? 80,
118
- width: columnWidth,
119
- maxWidth: columnWidth,
120
- }, children: renderCellContent(item, col, rowIndex, colIdx) }, col.columnId));
121
- })] }, rowIdStr));
122
- }) }))] }), _jsx(MarchingAntsOverlay, { containerRef: tableContainerRef, selectionRange: selectionRange, copyRange: copyRange, cutRange: cutRange, colOffset: colOffset }), statusBarConfig && (_jsx(StatusBar, { totalCount: statusBarConfig.totalCount, filteredCount: statusBarConfig.filteredCount, selectedCount: statusBarConfig.selectedCount ?? selectedRowIds.size, selectedCellCount: selectionRange ? (Math.abs(selectionRange.endRow - selectionRange.startRow) + 1) * (Math.abs(selectionRange.endCol - selectionRange.startCol) + 1) : undefined }))] }) })] }), showEmptyInGrid && emptyState && (_jsx("div", { className: styles.emptyStateInGrid, children: _jsx("div", { children: emptyState.render ? (emptyState.render()) : (_jsxs(_Fragment, { children: [_jsx("div", { className: styles.emptyStateInGridTitle, children: "No results found" }), _jsx("div", { className: styles.emptyStateInGridMessage, children: emptyState.message != null ? (emptyState.message) : emptyState.hasActiveFilters ? (_jsxs(_Fragment, { children: ["No items match your current filters. Try adjusting your search or", ' ', _jsx("button", { type: "button", className: styles.emptyStateInGridLink, onClick: emptyState.onClearAll, children: "clear all filters" }), ' ', "to see all items."] })) : ('There are no items available at this time.') })] })) }) }))] }), contextMenu &&
82
+ }, children: [isLoading && items.length > 0 && (_jsx("div", { className: styles.loadingOverlay, "aria-live": "polite", children: _jsxs("div", { className: styles.loadingOverlayContent, children: [_jsx("div", { className: styles.spinner }), _jsx("span", { className: styles.loadingOverlayText, children: loadingMessage })] }) })), _jsx("div", { className: styles.tableScrollContent, children: _jsx("div", { className: isLoading && items.length > 0 ? styles.loadingDimmed : undefined, children: _jsxs("div", { className: styles.tableWidthAnchor, ref: tableContainerRef, children: [_jsxs("table", { className: styles.dataTable, children: [_jsx("thead", { className: freezeRows != null && freezeRows >= 1 ? styles.stickyHeader : undefined, children: _jsxs("tr", { children: [hasCheckboxCol && (_jsx("th", { className: styles.selectionHeaderCell, scope: "col", children: _jsx("div", { className: styles.selectionHeaderCellInner, children: _jsx(Checkbox.Root, { className: styles.rowCheckbox, checked: allSelected ? true : someSelected ? 'indeterminate' : false, onCheckedChange: (c) => handleSelectAll(!!c), "aria-label": "Select all rows", children: _jsx(Checkbox.Indicator, { className: styles.rowCheckboxIndicator, children: someSelected && !allSelected ? '–' : '✓' }) }) }) })), visibleCols.map((col, colIdx) => {
83
+ const isFreezeCol = freezeCols != null && freezeCols >= 1 && colIdx < freezeCols;
84
+ const isPinnedLeft = col.pinned === 'left';
85
+ const isPinnedRight = col.pinned === 'right';
86
+ const columnWidth = getColumnWidth(col);
87
+ const hasExplicitWidth = !!(columnSizingOverrides[col.columnId] || col.idealWidth != null || col.defaultWidth != null);
88
+ return (_jsxs("th", { scope: "col", "data-column-id": col.columnId, className: [
89
+ isFreezeCol ? styles.freezeCol : '',
90
+ isFreezeCol && colIdx === 0 ? styles.freezeColFirst : '',
91
+ isPinnedLeft ? styles.pinnedColLeft : '',
92
+ isPinnedRight ? styles.pinnedColRight : '',
93
+ ].filter(Boolean).join(' '), style: {
94
+ minWidth: col.minWidth ?? 80,
95
+ width: hasExplicitWidth ? columnWidth : undefined,
96
+ maxWidth: hasExplicitWidth ? columnWidth : undefined,
97
+ }, children: [_jsx(ColumnHeaderFilter, { ...getHeaderFilterConfig(col, headerFilterInput) }), _jsx("div", { className: styles.resizeHandle, onMouseDown: (e) => handleResizeStart(e, col), "aria-label": `Resize ${col.name}` })] }, col.columnId));
98
+ })] }) }), !showEmptyInGrid && (_jsx("tbody", { children: items.map((item, rowIndex) => {
99
+ const rowIdStr = getRowId(item);
100
+ const isSelected = selectedRowIds.has(rowIdStr);
101
+ return (_jsxs("tr", { className: isSelected ? styles.selectedRow : '', onClick: () => {
102
+ if (rowSelection === 'single') {
103
+ const id = getRowId(item);
104
+ updateSelection(selectedRowIds.has(id) ? new Set() : new Set([id]));
105
+ }
106
+ }, children: [hasCheckboxCol && (_jsx("td", { className: styles.selectionCell, children: _jsx("div", { className: styles.selectionCellInner, "data-row-index": rowIndex, "data-col-index": 0, onClick: (e) => e.stopPropagation(), children: _jsx(Checkbox.Root, { className: styles.rowCheckbox, checked: selectedRowIds.has(rowIdStr), onCheckedChange: (c) => handleRowCheckboxChange(rowIdStr, !!c, rowIndex, lastMouseShiftRef.current), "aria-label": `Select row ${rowIndex + 1}`, children: _jsx(Checkbox.Indicator, { className: styles.rowCheckboxIndicator, children: "\u2713" }) }) }) })), visibleCols.map((col, colIdx) => {
107
+ const isFreezeCol = freezeCols != null && freezeCols >= 1 && colIdx < freezeCols;
108
+ const isPinnedLeft = col.pinned === 'left';
109
+ const isPinnedRight = col.pinned === 'right';
110
+ const columnWidth = getColumnWidth(col);
111
+ const hasExplicitWidth = !!(columnSizingOverrides[col.columnId] || col.idealWidth != null || col.defaultWidth != null);
112
+ return (_jsx("td", { className: [
113
+ isFreezeCol ? styles.freezeCol : '',
114
+ isFreezeCol && colIdx === 0 ? styles.freezeColFirst : '',
115
+ isPinnedLeft ? styles.pinnedColLeft : '',
116
+ isPinnedRight ? styles.pinnedColRight : '',
117
+ ].filter(Boolean).join(' '), style: {
118
+ minWidth: col.minWidth ?? 80,
119
+ width: hasExplicitWidth ? columnWidth : undefined,
120
+ maxWidth: hasExplicitWidth ? columnWidth : undefined,
121
+ }, children: renderCellContent(item, col, rowIndex, colIdx) }, col.columnId));
122
+ })] }, rowIdStr));
123
+ }) }))] }), _jsx(MarchingAntsOverlay, { containerRef: tableContainerRef, selectionRange: selectionRange, copyRange: copyRange, cutRange: cutRange, colOffset: colOffset }), statusBarConfig && (_jsx(StatusBar, { totalCount: statusBarConfig.totalCount, filteredCount: statusBarConfig.filteredCount, selectedCount: statusBarConfig.selectedCount ?? selectedRowIds.size, selectedCellCount: selectionRange ? (Math.abs(selectionRange.endRow - selectionRange.startRow) + 1) * (Math.abs(selectionRange.endCol - selectionRange.startCol) + 1) : undefined })), showEmptyInGrid && emptyState && (_jsx("div", { className: styles.emptyStateInGrid, children: _jsx("div", { children: emptyState.render ? (emptyState.render()) : (_jsxs(_Fragment, { children: [_jsx("div", { className: styles.emptyStateInGridTitle, children: "No results found" }), _jsx("div", { className: styles.emptyStateInGridMessage, children: emptyState.message != null ? (emptyState.message) : emptyState.hasActiveFilters ? (_jsxs(_Fragment, { children: ["No items match your current filters. Try adjusting your search or", ' ', _jsx("button", { type: "button", className: styles.emptyStateInGridLink, onClick: emptyState.onClearAll, children: "clear all filters" }), ' ', "to see all items."] })) : ('There are no items available at this time.') })] })) }) }))] }) }) }), contextMenu &&
123
124
  createPortal(_jsx(GridContextMenu, { x: contextMenu.x, y: contextMenu.y, hasSelection: hasCellSelection, canUndo: canUndo, canRedo: canRedo, onUndo: onUndo ?? (() => { }), onRedo: onRedo ?? (() => { }), onCopy: handleCopy, onCut: handleCut, onPaste: () => void handlePaste(), onSelectAll: handleSelectAllCells, onClose: closeContextMenu }), document.body)] }));
124
125
  }
125
126
  export const DataGridTable = React.memo(DataGridTableInner);
@@ -1,3 +1,4 @@
1
+ @charset "UTF-8";
1
2
  .tableScrollContent {
2
3
  display: flex;
3
4
  flex-direction: column;
@@ -7,12 +8,12 @@
7
8
  }
8
9
 
9
10
  .tableWrapper {
11
+ position: relative;
10
12
  overflow-x: hidden;
11
13
  overflow-y: visible;
12
14
  width: 100%;
13
15
  min-width: 0;
14
16
  max-width: 100%;
15
- margin-bottom: 15px;
16
17
  border-radius: 6px;
17
18
  box-sizing: border-box;
18
19
  }
@@ -26,7 +27,8 @@
26
27
  .tableWidthAnchor {
27
28
  position: relative;
28
29
  width: max-content;
29
- min-width: max(100%, var(--data-table-total-min-width, 0px));
30
+ /* No min-width: 100% — anchor sizes to grid content so status bar aligns with the table border.
31
+ .tableScrollContent provides the full-width background so no gap is visible. */
30
32
  background: var(--ogrid-bg, #fff);
31
33
  }
32
34
 
@@ -98,14 +100,16 @@
98
100
  background: var(--ogrid-bg-subtle, #f3f2f1);
99
101
  }
100
102
 
101
- /* Pinned columns: sticky positioning based on column pinned property */
102
- .pinnedColLeft {
103
+ /* Pinned columns: sticky positioning based on column pinned property.
104
+ Selectors use .dataTable qualifier to beat .dataTable thead th / .dataTable tbody td
105
+ which set position: relative. */
106
+ .dataTable .pinnedColLeft {
103
107
  position: sticky;
104
108
  left: 0;
105
109
  z-index: 2;
106
110
  background: var(--ogrid-bg, #ffffff);
107
111
  }
108
- .pinnedColLeft::after {
112
+ .dataTable .pinnedColLeft::after {
109
113
  content: "";
110
114
  position: absolute;
111
115
  top: 0;
@@ -120,13 +124,13 @@
120
124
  background: var(--ogrid-bg-subtle, #f3f2f1);
121
125
  }
122
126
 
123
- .pinnedColRight {
127
+ .dataTable .pinnedColRight {
124
128
  position: sticky;
125
129
  right: 0;
126
130
  z-index: 2;
127
131
  background: var(--ogrid-bg, #ffffff);
128
132
  }
129
- .pinnedColRight::before {
133
+ .dataTable .pinnedColRight::before {
130
134
  content: "";
131
135
  position: absolute;
132
136
  top: 0;
@@ -220,6 +224,10 @@
220
224
  background: var(--ogrid-bg-range, rgba(33, 115, 70, 0.12)) !important;
221
225
  }
222
226
 
227
+ :global([data-drag-range]) {
228
+ background: var(--ogrid-bg-range, rgba(33, 115, 70, 0.12)) !important;
229
+ }
230
+
223
231
  .cellCut {
224
232
  background: var(--ogrid-bg-hover, rgba(0, 0, 0, 0.04)) !important;
225
233
  opacity: 0.7;
@@ -289,6 +297,7 @@
289
297
  gap: 16px;
290
298
  width: 100%;
291
299
  padding: 6px 12px;
300
+ box-sizing: border-box;
292
301
  font-size: 12px;
293
302
  color: var(--ogrid-muted, #616161);
294
303
  background: var(--ogrid-bg-subtle, #f3f2f1);
@@ -368,10 +377,6 @@
368
377
  background: var(--ogrid-border, #e0e0e0);
369
378
  }
370
379
 
371
- .loadingOverlayContainer {
372
- position: relative;
373
- }
374
-
375
380
  .loadingOverlay {
376
381
  position: absolute;
377
382
  inset: 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alaarab/ogrid",
3
- "version": "1.3.0",
3
+ "version": "1.3.2",
4
4
  "description": "OGrid default (Radix) – Data grid with sorting, filtering, pagination, column chooser, and CSV export. Packed with Radix UI; no Fluent or Material required.",
5
5
  "main": "dist/esm/index.js",
6
6
  "module": "dist/esm/index.js",