@alaarab/ogrid-core 1.6.0 → 1.7.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.
- package/README.md +1 -2
- package/dist/esm/components/OGridLayout.js +15 -4
- package/dist/esm/hooks/useDataGridState.js +2 -0
- package/dist/esm/hooks/useOGrid.js +2 -1
- package/dist/esm/hooks/useRowSelection.js +2 -2
- package/dist/types/components/OGridLayout.d.ts +2 -0
- package/dist/types/hooks/useOGrid.d.ts +1 -0
- package/dist/types/types/dataGridTypes.d.ts +2 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -32,14 +32,13 @@ npm install @alaarab/ogrid-core
|
|
|
32
32
|
|
|
33
33
|
### Components
|
|
34
34
|
|
|
35
|
-
- `OGridLayout` --
|
|
35
|
+
- `OGridLayout` -- Unified bordered layout: toolbar strip (custom content + column chooser), optional secondary toolbar row, sidebar, grid area, and footer strip (pagination).
|
|
36
36
|
|
|
37
37
|
### Utilities
|
|
38
38
|
|
|
39
39
|
- `getPaginationViewModel(...)` -- Page numbers, ellipsis, start/end item for PaginationControls
|
|
40
40
|
- `getHeaderFilterConfig(col, input)` -- ColumnHeaderFilter props from column + filter/sort state
|
|
41
41
|
- `getCellRenderDescriptor(item, col, rowIndex, colIdx, input)` -- Cell mode (editing-inline / editing-popover / display) and flags for DataGridTable
|
|
42
|
-
- `toDataGridFilterProps(filters)` -- Splits `IFilters` into `multiSelectFilters`, `textFilters`, `peopleFilters`
|
|
43
42
|
- `toUserLike(user)` -- Converts a user-like object to `UserLike`
|
|
44
43
|
- `exportToCsv(items, columns, getValue, filename)` -- Full CSV export
|
|
45
44
|
- `buildCsvHeader`, `buildCsvRows`, `triggerCsvDownload`, `escapeCsvValue` -- Low-level CSV helpers
|
|
@@ -11,22 +11,33 @@ const borderedContainerStyle = {
|
|
|
11
11
|
minHeight: 0,
|
|
12
12
|
background: 'var(--ogrid-bg, #fff)',
|
|
13
13
|
};
|
|
14
|
-
const
|
|
14
|
+
const toolbarStripBase = {
|
|
15
15
|
display: 'flex',
|
|
16
16
|
justifyContent: 'space-between',
|
|
17
17
|
alignItems: 'center',
|
|
18
18
|
padding: '6px 12px',
|
|
19
|
-
borderBottom: '1px solid var(--ogrid-border, #e0e0e0)',
|
|
20
19
|
background: 'var(--ogrid-header-bg, #f5f5f5)',
|
|
21
20
|
gap: 8,
|
|
22
21
|
flexWrap: 'wrap',
|
|
23
22
|
minHeight: 0,
|
|
24
23
|
};
|
|
24
|
+
/** Toolbar strip with border-bottom (when it's the only toolbar row). */
|
|
25
|
+
const toolbarStripStyle = {
|
|
26
|
+
...toolbarStripBase,
|
|
27
|
+
borderBottom: '1px solid var(--ogrid-border, #e0e0e0)',
|
|
28
|
+
};
|
|
29
|
+
/** Toolbar strip without border-bottom (when toolbarBelow follows — it owns the border). */
|
|
30
|
+
const toolbarStripNoBorderStyle = toolbarStripBase;
|
|
25
31
|
const toolbarSectionStyle = {
|
|
26
32
|
display: 'flex',
|
|
27
33
|
alignItems: 'center',
|
|
28
34
|
gap: 8,
|
|
29
35
|
};
|
|
36
|
+
const toolbarBelowStyle = {
|
|
37
|
+
padding: '6px 12px',
|
|
38
|
+
borderBottom: '1px solid var(--ogrid-border, #e0e0e0)',
|
|
39
|
+
background: 'var(--ogrid-header-bg, #f5f5f5)',
|
|
40
|
+
};
|
|
30
41
|
const footerStripStyle = {
|
|
31
42
|
borderTop: '1px solid var(--ogrid-border, #e0e0e0)',
|
|
32
43
|
background: 'var(--ogrid-header-bg, #f5f5f5)',
|
|
@@ -65,7 +76,7 @@ const gridChildStyle = {
|
|
|
65
76
|
* └────────────────────────────────────┘
|
|
66
77
|
*/
|
|
67
78
|
export function OGridLayout(props) {
|
|
68
|
-
const { containerComponent: Container = 'div', containerProps = {}, className, toolbar, toolbarEnd, children, pagination, sideBar, } = props;
|
|
79
|
+
const { containerComponent: Container = 'div', containerProps = {}, className, toolbar, toolbarEnd, toolbarBelow, children, pagination, sideBar, } = props;
|
|
69
80
|
const hasSideBar = sideBar != null;
|
|
70
81
|
const sideBarPosition = sideBar?.position ?? 'right';
|
|
71
82
|
const hasToolbar = toolbar != null || toolbarEnd != null;
|
|
@@ -74,5 +85,5 @@ export function OGridLayout(props) {
|
|
|
74
85
|
flexDirection: 'column',
|
|
75
86
|
height: '100%',
|
|
76
87
|
};
|
|
77
|
-
return (_jsx(Container, { className: className, style: rootStyle, ...containerProps, children: _jsxs("div", { style: borderedContainerStyle, children: [hasToolbar && (_jsxs("div", { style: toolbarStripStyle, children: [_jsx("div", { style: toolbarSectionStyle, children: toolbar }), _jsx("div", { style: toolbarSectionStyle, children: toolbarEnd })] })), hasSideBar ? (_jsxs("div", { style: gridAreaFlexStyle, children: [sideBarPosition === 'left' && _jsx(SideBar, { ...sideBar }), _jsx("div", { style: gridChildStyle, children: children }), sideBarPosition !== 'left' && _jsx(SideBar, { ...sideBar })] })) : (_jsx("div", { style: gridAreaSoloStyle, children: children })), pagination && (_jsx("div", { style: footerStripStyle, children: pagination }))] }) }));
|
|
88
|
+
return (_jsx(Container, { className: className, style: rootStyle, ...containerProps, children: _jsxs("div", { style: borderedContainerStyle, children: [hasToolbar && (_jsxs("div", { style: toolbarBelow ? toolbarStripNoBorderStyle : toolbarStripStyle, children: [_jsx("div", { style: toolbarSectionStyle, children: toolbar }), _jsx("div", { style: toolbarSectionStyle, children: toolbarEnd })] })), toolbarBelow && (_jsx("div", { style: toolbarBelowStyle, children: toolbarBelow })), hasSideBar ? (_jsxs("div", { style: gridAreaFlexStyle, children: [sideBarPosition === 'left' && _jsx(SideBar, { ...sideBar }), _jsx("div", { style: gridChildStyle, children: children }), sideBarPosition !== 'left' && _jsx(SideBar, { ...sideBar })] })) : (_jsx("div", { style: gridAreaSoloStyle, children: children })), pagination && (_jsx("div", { style: footerStripStyle, children: pagination }))] }) }));
|
|
78
89
|
}
|
|
@@ -99,6 +99,8 @@ export function useDataGridState(params) {
|
|
|
99
99
|
endBatch: undoRedo.endBatch,
|
|
100
100
|
});
|
|
101
101
|
const handleCellMouseDown = useCallback((e, rowIndex, globalColIndex) => {
|
|
102
|
+
if (e.button !== 0)
|
|
103
|
+
return;
|
|
102
104
|
wrapperRef.current?.focus();
|
|
103
105
|
clearClipboardRanges();
|
|
104
106
|
handleCellMouseDownBase(e, rowIndex, globalColIndex);
|
|
@@ -5,7 +5,7 @@ import { useFilterOptions } from './useFilterOptions';
|
|
|
5
5
|
import { useSideBarState } from './useSideBarState';
|
|
6
6
|
const DEFAULT_PAGE_SIZE = 25;
|
|
7
7
|
export function useOGrid(props, ref) {
|
|
8
|
-
const { columns: columnsProp, getRowId, data, dataSource, page: controlledPage, pageSize: controlledPageSize, sort: controlledSort, filters: controlledFilters, visibleColumns: controlledVisibleColumns, isLoading: controlledLoading, onPageChange, onPageSizeChange, onSortChange, onFiltersChange, onVisibleColumnsChange, columnOrder, onColumnOrderChange, onColumnResized, onColumnPinned, freezeRows, freezeCols, defaultPageSize = DEFAULT_PAGE_SIZE, defaultSortBy, defaultSortDirection = 'asc', toolbar, emptyState, entityLabelPlural = 'items', className, layoutMode = 'fill', suppressHorizontalScroll, editable, cellSelection, onCellValueChanged, onUndo, onRedo, canUndo, canRedo, rowSelection = 'none', selectedRows, onSelectionChange, statusBar, pageSizeOptions, sideBar, onFirstDataRendered, onError, columnChooser: columnChooserProp, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledBy, } = props;
|
|
8
|
+
const { columns: columnsProp, getRowId, data, dataSource, page: controlledPage, pageSize: controlledPageSize, sort: controlledSort, filters: controlledFilters, visibleColumns: controlledVisibleColumns, isLoading: controlledLoading, onPageChange, onPageSizeChange, onSortChange, onFiltersChange, onVisibleColumnsChange, columnOrder, onColumnOrderChange, onColumnResized, onColumnPinned, freezeRows, freezeCols, defaultPageSize = DEFAULT_PAGE_SIZE, defaultSortBy, defaultSortDirection = 'asc', toolbar, toolbarBelow, emptyState, entityLabelPlural = 'items', className, layoutMode = 'fill', suppressHorizontalScroll, editable, cellSelection, onCellValueChanged, onUndo, onRedo, canUndo, canRedo, rowSelection = 'none', selectedRows, onSelectionChange, statusBar, pageSizeOptions, sideBar, onFirstDataRendered, onError, columnChooser: columnChooserProp, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledBy, } = props;
|
|
9
9
|
// Resolve column chooser placement
|
|
10
10
|
const columnChooserPlacement = columnChooserProp === false ? 'none'
|
|
11
11
|
: columnChooserProp === 'sidebar' ? 'sidebar'
|
|
@@ -402,6 +402,7 @@ export function useOGrid(props, ref) {
|
|
|
402
402
|
handleVisibilityChange,
|
|
403
403
|
columnChooserPlacement,
|
|
404
404
|
toolbar,
|
|
405
|
+
toolbarBelow,
|
|
405
406
|
className,
|
|
406
407
|
entityLabelPlural,
|
|
407
408
|
emptyState,
|
|
@@ -55,8 +55,8 @@ export function useRowSelection(params) {
|
|
|
55
55
|
updateSelection(new Set());
|
|
56
56
|
}
|
|
57
57
|
}, [items, getRowId, updateSelection]);
|
|
58
|
-
const allSelected = items.length > 0 && items.every((item) => selectedRowIds.has(getRowId(item)));
|
|
59
|
-
const someSelected = !allSelected && items.some((item) => selectedRowIds.has(getRowId(item)));
|
|
58
|
+
const allSelected = useMemo(() => items.length > 0 && items.every((item) => selectedRowIds.has(getRowId(item))), [items, selectedRowIds, getRowId]);
|
|
59
|
+
const someSelected = useMemo(() => !allSelected && items.some((item) => selectedRowIds.has(getRowId(item))), [allSelected, items, selectedRowIds, getRowId]);
|
|
60
60
|
return {
|
|
61
61
|
selectedRowIds,
|
|
62
62
|
updateSelection,
|
|
@@ -15,6 +15,8 @@ export interface OGridLayoutProps {
|
|
|
15
15
|
toolbar?: React.ReactNode;
|
|
16
16
|
/** Built-in toolbar items rendered on the right side (column chooser, etc.). */
|
|
17
17
|
toolbarEnd?: React.ReactNode;
|
|
18
|
+
/** Secondary toolbar row below the primary toolbar (e.g. active filter chips). Full width. */
|
|
19
|
+
toolbarBelow?: React.ReactNode;
|
|
18
20
|
/** Grid content (DataGridTable). */
|
|
19
21
|
children: React.ReactNode;
|
|
20
22
|
/** Pagination controls (rendered in footer strip inside the bordered container). */
|
|
@@ -16,6 +16,7 @@ export interface UseOGridResult<T> {
|
|
|
16
16
|
/** Resolved placement of the column chooser. */
|
|
17
17
|
columnChooserPlacement: ColumnChooserPlacement;
|
|
18
18
|
toolbar: React.ReactNode;
|
|
19
|
+
toolbarBelow: React.ReactNode;
|
|
19
20
|
className?: string;
|
|
20
21
|
entityLabelPlural: string;
|
|
21
22
|
emptyState?: {
|
|
@@ -197,6 +197,8 @@ export interface IOGridProps<T> {
|
|
|
197
197
|
defaultSortBy?: string;
|
|
198
198
|
defaultSortDirection?: 'asc' | 'desc';
|
|
199
199
|
toolbar?: ReactNode;
|
|
200
|
+
/** Secondary toolbar row rendered below the primary toolbar (e.g. active filter chips). */
|
|
201
|
+
toolbarBelow?: ReactNode;
|
|
200
202
|
emptyState?: {
|
|
201
203
|
message?: ReactNode;
|
|
202
204
|
render?: () => ReactNode;
|
package/package.json
CHANGED