@alaarab/ogrid-react-fluent 2.0.19 → 2.0.21
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/ColumnHeaderFilter/ColumnHeaderFilter.js +4 -4
- package/dist/esm/ColumnHeaderFilter/ColumnHeaderFilter.module.css +26 -30
- package/dist/esm/ColumnHeaderFilter/PeopleFilterPopover.js +12 -3
- package/dist/esm/ColumnHeaderMenu/ColumnHeaderMenu.js +6 -71
- package/dist/esm/DataGridTable/DataGridTable.js +5 -3
- package/dist/esm/DataGridTable/DataGridTable.module.css +3 -0
- package/dist/esm/DataGridTable/DropIndicator.js +2 -1
- package/dist/esm/DataGridTable/EmptyState.js +11 -2
- package/dist/esm/DataGridTable/LoadingOverlay.js +9 -2
- package/dist/esm/DataGridTable/StatusBar.js +9 -4
- package/dist/esm/OGrid/OGrid.js +5 -12
- package/dist/esm/index.js +3 -1
- package/dist/types/ColumnHeaderMenu/ColumnHeaderMenu.d.ts +4 -22
- package/dist/types/DataGridTable/EmptyState.d.ts +2 -6
- package/dist/types/DataGridTable/InlineCellEditor.d.ts +2 -10
- package/dist/types/DataGridTable/StatusBar.d.ts +2 -14
- package/dist/types/OGrid/OGrid.d.ts +1 -4
- package/package.json +2 -2
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import * as React from 'react';
|
|
3
3
|
import { Popover, PopoverSurface } from '@fluentui/react-components';
|
|
4
|
-
import {
|
|
4
|
+
import { FilterRegular } from '@fluentui/react-icons';
|
|
5
5
|
import { useColumnHeaderFilterState, getColumnHeaderFilterStateParams, DateFilterContent, renderFilterContent, } from '@alaarab/ogrid-react';
|
|
6
6
|
import { TextFilterPopover } from './TextFilterPopover';
|
|
7
7
|
import { MultiSelectFilterPopover } from './MultiSelectFilterPopover';
|
|
8
8
|
import { PeopleFilterPopover } from './PeopleFilterPopover';
|
|
9
9
|
import styles from './ColumnHeaderFilter.module.css';
|
|
10
10
|
export const ColumnHeaderFilter = React.memo((props) => {
|
|
11
|
-
const { columnName, filterType,
|
|
11
|
+
const { columnName, filterType, options, isLoadingOptions = false, selectedUser, } = props;
|
|
12
12
|
const state = useColumnHeaderFilterState(getColumnHeaderFilterStateParams(props));
|
|
13
13
|
const { headerRef, popoverRef, isFilterOpen, setFilterOpen, hasActiveFilter, handlers, } = state;
|
|
14
14
|
const filterBtnRef = React.useRef(null);
|
|
@@ -23,7 +23,7 @@ export const ColumnHeaderFilter = React.memo((props) => {
|
|
|
23
23
|
applyButton: styles.applyButton,
|
|
24
24
|
} }) })),
|
|
25
25
|
}), [handlers]);
|
|
26
|
-
return (_jsxs("div", { className: styles.columnHeader, ref: headerRef, children: [_jsx("div", { className: styles.headerContent, children: _jsx("span", { className: styles.columnName, title: columnName, "data-header-label": true, children: columnName }) }),
|
|
27
|
-
|
|
26
|
+
return (_jsxs("div", { className: styles.columnHeader, ref: headerRef, children: [_jsx("div", { className: styles.headerContent, children: _jsx("span", { className: styles.columnName, title: columnName, "data-header-label": true, children: columnName }) }), _jsx("div", { className: styles.headerActions, children: filterType !== 'none' && (_jsxs(_Fragment, { children: [_jsxs("button", { ref: filterBtnRef, type: "button", className: `${styles.filterIcon} ${hasActiveFilter ? styles.filterActive : ''} ${isFilterOpen ? styles.filterOpen : ''}`, onClick: handlers.handleFilterIconClick, "aria-label": `Filter ${columnName}`, title: `Filter ${columnName}`, children: [_jsx(FilterRegular, {}), hasActiveFilter && _jsx("span", { className: styles.filterBadge })] }), _jsx(Popover, { open: isFilterOpen, onOpenChange: (_, data) => { if (!data.open)
|
|
27
|
+
setFilterOpen(false); }, positioning: { target: filterBtnRef.current ?? undefined, position: 'below', align: 'start', offset: 4 }, trapFocus: false, children: _jsxs(PopoverSurface, { ref: popoverRef, className: styles.filterPopover, onClick: handlers.handlePopoverClick, style: { padding: 0 }, children: [_jsxs("div", { className: styles.popoverHeader, children: ["Filter: ", columnName] }), renderFilterContent(filterType, state, options ?? [], isLoadingOptions, selectedUser, fluentRenderers)] }) })] })) })] }));
|
|
28
28
|
});
|
|
29
29
|
ColumnHeaderFilter.displayName = 'ColumnHeaderFilter';
|
|
@@ -58,36 +58,6 @@
|
|
|
58
58
|
flex-shrink: 0;
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
.sortIcon {
|
|
62
|
-
display: flex;
|
|
63
|
-
align-items: center;
|
|
64
|
-
justify-content: center;
|
|
65
|
-
width: 24px;
|
|
66
|
-
height: 24px;
|
|
67
|
-
padding: 4px;
|
|
68
|
-
border: none;
|
|
69
|
-
border-radius: var(--borderRadiusSmall, 4px);
|
|
70
|
-
background-color: transparent;
|
|
71
|
-
color: var(--colorNeutralForeground2, #616161);
|
|
72
|
-
cursor: pointer;
|
|
73
|
-
flex-shrink: 0;
|
|
74
|
-
transition: all 0.15s ease;
|
|
75
|
-
}
|
|
76
|
-
.sortIcon svg {
|
|
77
|
-
font-size: 14px;
|
|
78
|
-
}
|
|
79
|
-
.sortIcon:hover {
|
|
80
|
-
background-color: var(--colorSubtleBackgroundHover, #f5f5f5);
|
|
81
|
-
color: var(--colorNeutralForeground2Hover, #424242);
|
|
82
|
-
}
|
|
83
|
-
.sortIcon.sortActive {
|
|
84
|
-
background-color: var(--colorSubtleBackgroundSelected, #e0e0e0);
|
|
85
|
-
color: var(--colorNeutralForeground2, #616161);
|
|
86
|
-
}
|
|
87
|
-
.sortIcon.sortActive:hover {
|
|
88
|
-
background-color: var(--colorSubtleBackgroundHover, #f5f5f5);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
61
|
.filterIcon {
|
|
92
62
|
display: flex;
|
|
93
63
|
align-items: center;
|
|
@@ -323,6 +293,32 @@
|
|
|
323
293
|
gap: 8px;
|
|
324
294
|
}
|
|
325
295
|
|
|
296
|
+
.avatar {
|
|
297
|
+
width: 32px;
|
|
298
|
+
height: 32px;
|
|
299
|
+
border-radius: 50%;
|
|
300
|
+
background-color: var(--colorBrandBackground, #0f6cbd);
|
|
301
|
+
display: flex;
|
|
302
|
+
align-items: center;
|
|
303
|
+
justify-content: center;
|
|
304
|
+
flex-shrink: 0;
|
|
305
|
+
overflow: hidden;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
.avatarImg {
|
|
309
|
+
width: 100%;
|
|
310
|
+
height: 100%;
|
|
311
|
+
object-fit: cover;
|
|
312
|
+
border-radius: 50%;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
.avatarInitials {
|
|
316
|
+
color: var(--colorNeutralForegroundOnBrand, #ffffff);
|
|
317
|
+
font-size: 12px;
|
|
318
|
+
font-weight: 600;
|
|
319
|
+
line-height: 1;
|
|
320
|
+
}
|
|
321
|
+
|
|
326
322
|
.userText {
|
|
327
323
|
display: flex;
|
|
328
324
|
flex-direction: column;
|
|
@@ -1,9 +1,18 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import { Avatar } from '@fluentui/react-components';
|
|
3
2
|
import { SearchRegular, FilterRegular } from '@fluentui/react-icons';
|
|
4
3
|
import styles from './ColumnHeaderFilter.module.css';
|
|
5
|
-
|
|
4
|
+
function getInitials(name) {
|
|
5
|
+
const parts = name.trim().split(/\s+/);
|
|
6
|
+
if (parts.length >= 2)
|
|
7
|
+
return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase();
|
|
8
|
+
return (parts[0]?.[0] ?? '').toUpperCase();
|
|
9
|
+
}
|
|
10
|
+
export const PeopleFilterPopover = ({ selectedUser, searchText, onSearchChange, suggestions, isLoading, onUserSelect, onClearUser, onPopoverClick, inputRef, }) => (_jsxs(_Fragment, { children: [selectedUser && (_jsxs("div", { className: styles.selectedUserSection, onClick: onPopoverClick, children: [_jsx("div", { className: styles.selectedUserLabel, children: "Currently filtered by:" }), _jsxs("div", { className: styles.selectedUser, children: [_jsxs("div", { className: styles.userInfo, children: [_jsx("div", { className: styles.avatar, children: selectedUser.photo
|
|
11
|
+
? _jsx("img", { src: selectedUser.photo, alt: "", className: styles.avatarImg })
|
|
12
|
+
: _jsx("span", { className: styles.avatarInitials, children: getInitials(selectedUser.displayName) }) }), _jsxs("div", { className: styles.userText, children: [_jsx("div", { children: selectedUser.displayName }), _jsx("div", { className: styles.userSecondary, children: selectedUser.email })] })] }), _jsx("button", { type: "button", className: styles.removeUserButton, onClick: onClearUser, "aria-label": "Remove filter", children: _jsx(FilterRegular, {}) })] })] })), _jsx("div", { className: styles.popoverSearch, onClick: onPopoverClick, children: _jsxs("div", { className: styles.nativeInputWrapper, children: [_jsx(SearchRegular, { className: styles.nativeInputIcon }), _jsx("input", { ref: inputRef, type: "text", placeholder: "Search for a person...", value: searchText, onChange: (e) => onSearchChange(e.target.value), onFocus: (e) => e.stopPropagation(), onMouseDown: (e) => e.stopPropagation(), onClick: (e) => e.stopPropagation(), onKeyDown: (e) => e.stopPropagation(), autoComplete: "off", className: styles.nativeInput })] }) }), _jsx("div", { className: styles.popoverOptions, onClick: onPopoverClick, children: isLoading && searchText.trim() ? (_jsxs("div", { className: styles.loadingContainer, children: [_jsx("div", { className: styles.filterSpinner }), _jsx("span", { style: { fontSize: 12, color: 'var(--colorNeutralForeground2, #616161)' }, children: "Searching..." })] })) : suggestions.length === 0 && searchText.trim() ? (_jsx("div", { className: styles.noResults, children: "No results found" })) : searchText.trim() ? (suggestions.map((user) => (_jsx("div", { className: styles.personOption, onClick: (e) => {
|
|
6
13
|
e.stopPropagation();
|
|
7
14
|
onUserSelect(user);
|
|
8
|
-
}, children: _jsxs("div", { className: styles.userInfo, children: [_jsx(
|
|
15
|
+
}, children: _jsxs("div", { className: styles.userInfo, children: [_jsx("div", { className: styles.avatar, children: user.photo
|
|
16
|
+
? _jsx("img", { src: user.photo, alt: "", className: styles.avatarImg })
|
|
17
|
+
: _jsx("span", { className: styles.avatarInitials, children: getInitials(user.displayName) }) }), _jsxs("div", { className: styles.userText, children: [_jsx("div", { children: user.displayName }), _jsx("div", { className: styles.userSecondary, children: user.email })] })] }) }, user.id ?? user.email ?? user.displayName)))) : (_jsx("div", { className: styles.noResults, children: "Type to search..." })) }), selectedUser && (_jsx("div", { className: styles.popoverActions, onClick: onPopoverClick, children: _jsx("button", { type: "button", className: styles.clearButton, onClick: onClearUser, children: "Clear Filter" }) }))] }));
|
|
9
18
|
PeopleFilterPopover.displayName = 'PeopleFilterPopover';
|
|
@@ -1,77 +1,12 @@
|
|
|
1
|
-
import { jsx as _jsx
|
|
2
|
-
import
|
|
3
|
-
import { createPortal } from 'react-dom';
|
|
4
|
-
import { getColumnHeaderMenuItems } from '@alaarab/ogrid-react';
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { BaseColumnHeaderMenu } from '@alaarab/ogrid-react';
|
|
5
3
|
import styles from './ColumnHeaderMenu.module.css';
|
|
4
|
+
/** Portal into the closest FluentProvider so --ogrid-* bridged variables are available */
|
|
5
|
+
const getFluentPortalTarget = (anchorElement) => anchorElement.closest('.fui-FluentProvider') ?? document.body;
|
|
6
6
|
/**
|
|
7
7
|
* Column header dropdown menu for pin/sort/autosize actions.
|
|
8
|
-
*
|
|
8
|
+
* Thin wrapper over BaseColumnHeaderMenu — portals into FluentProvider.
|
|
9
9
|
*/
|
|
10
10
|
export function ColumnHeaderMenu(props) {
|
|
11
|
-
|
|
12
|
-
const [position, setPosition] = useState(null);
|
|
13
|
-
const menuRef = useRef(null);
|
|
14
|
-
useEffect(() => {
|
|
15
|
-
if (!isOpen || !anchorElement) {
|
|
16
|
-
setPosition(null);
|
|
17
|
-
return;
|
|
18
|
-
}
|
|
19
|
-
const rect = anchorElement.getBoundingClientRect();
|
|
20
|
-
setPosition({
|
|
21
|
-
top: rect.bottom + 4,
|
|
22
|
-
left: rect.left,
|
|
23
|
-
});
|
|
24
|
-
const handleClickOutside = (e) => {
|
|
25
|
-
const target = e.target;
|
|
26
|
-
// Don't close if clicking inside the menu itself (portal) — let onClick fire first
|
|
27
|
-
if (menuRef.current && menuRef.current.contains(target))
|
|
28
|
-
return;
|
|
29
|
-
if (anchorElement && !anchorElement.contains(target)) {
|
|
30
|
-
onClose();
|
|
31
|
-
}
|
|
32
|
-
};
|
|
33
|
-
const handleEscape = (e) => {
|
|
34
|
-
if (e.key === 'Escape') {
|
|
35
|
-
onClose();
|
|
36
|
-
}
|
|
37
|
-
};
|
|
38
|
-
document.addEventListener('mousedown', handleClickOutside);
|
|
39
|
-
document.addEventListener('keydown', handleEscape);
|
|
40
|
-
return () => {
|
|
41
|
-
document.removeEventListener('mousedown', handleClickOutside);
|
|
42
|
-
document.removeEventListener('keydown', handleEscape);
|
|
43
|
-
};
|
|
44
|
-
}, [isOpen, anchorElement, onClose]);
|
|
45
|
-
const menuInput = useMemo(() => ({
|
|
46
|
-
canPinLeft,
|
|
47
|
-
canPinRight,
|
|
48
|
-
canUnpin,
|
|
49
|
-
currentSort,
|
|
50
|
-
isSortable,
|
|
51
|
-
isResizable,
|
|
52
|
-
}), [canPinLeft, canPinRight, canUnpin, currentSort, isSortable, isResizable]);
|
|
53
|
-
const items = useMemo(() => getColumnHeaderMenuItems(menuInput), [menuInput]);
|
|
54
|
-
const handlers = {
|
|
55
|
-
pinLeft: onPinLeft,
|
|
56
|
-
pinRight: onPinRight,
|
|
57
|
-
unpin: onUnpin,
|
|
58
|
-
sortAsc: onSortAsc,
|
|
59
|
-
sortDesc: onSortDesc,
|
|
60
|
-
clearSort: onClearSort,
|
|
61
|
-
autosizeThis: onAutosizeThis,
|
|
62
|
-
autosizeAll: onAutosizeAll,
|
|
63
|
-
};
|
|
64
|
-
if (!isOpen || !position)
|
|
65
|
-
return null;
|
|
66
|
-
// Portal into the closest FluentProvider so --ogrid-* bridged variables are available
|
|
67
|
-
const portalTarget = anchorElement?.closest('.fui-FluentProvider') ?? document.body;
|
|
68
|
-
return createPortal(_jsx("div", { ref: menuRef, className: styles.content, style: {
|
|
69
|
-
position: 'fixed',
|
|
70
|
-
top: position.top,
|
|
71
|
-
left: position.left,
|
|
72
|
-
zIndex: 1000,
|
|
73
|
-
}, children: items.map((item, idx) => (_jsxs(React.Fragment, { children: [_jsx("button", { className: styles.item, disabled: item.disabled, onClick: () => {
|
|
74
|
-
handlers[item.id]();
|
|
75
|
-
onClose();
|
|
76
|
-
}, children: item.label }), item.divider && idx < items.length - 1 && (_jsx("div", { className: styles.separator }))] }, item.id))) }), portalTarget);
|
|
11
|
+
return (_jsx(BaseColumnHeaderMenu, { ...props, classNames: styles, getPortalTarget: getFluentPortalTarget }));
|
|
77
12
|
}
|
|
@@ -11,18 +11,19 @@ import { GridContextMenu } from './GridContextMenu';
|
|
|
11
11
|
import { EmptyState } from './EmptyState';
|
|
12
12
|
import { LoadingOverlay } from './LoadingOverlay';
|
|
13
13
|
import { DropIndicator } from './DropIndicator';
|
|
14
|
-
import { useDataGridTableOrchestration, getHeaderFilterConfig, getCellRenderDescriptor, MarchingAntsOverlay, resolveCellDisplayContent, resolveCellStyle, buildInlineEditorProps, buildPopoverEditorProps, getCellInteractionProps, areGridRowPropsEqual, CellErrorBoundary, DEFAULT_MIN_COLUMN_WIDTH, GRID_ROOT_STYLE, CURSOR_CELL_STYLE, POPOVER_ANCHOR_STYLE, PREVENT_DEFAULT, NOOP, } from '@alaarab/ogrid-react';
|
|
14
|
+
import { useDataGridTableOrchestration, getHeaderFilterConfig, getCellRenderDescriptor, MarchingAntsOverlay, resolveCellDisplayContent, resolveCellStyle, buildInlineEditorProps, buildPopoverEditorProps, getCellInteractionProps, areGridRowPropsEqual, CellErrorBoundary, DEFAULT_MIN_COLUMN_WIDTH, GRID_ROOT_STYLE, CURSOR_CELL_STYLE, POPOVER_ANCHOR_STYLE, PREVENT_DEFAULT, NOOP, STOP_PROPAGATION, } from '@alaarab/ogrid-react';
|
|
15
15
|
import styles from './DataGridTable.module.css';
|
|
16
|
+
// --- Memoized row component (skips re-render for rows unaffected by selection changes) ---
|
|
16
17
|
function GridRowInner(props) {
|
|
17
18
|
const { item, rowIndex, rowId, isSelected, visibleCols, columnMeta, renderCellContent, handleSingleRowClick, handleRowCheckboxChange, lastMouseShiftRef, hasCheckboxCol, hasRowNumbersCol, rowNumberOffset, } = props;
|
|
18
|
-
return (_jsxs(TableRow, { className: isSelected ? styles.selectedRow : undefined, "data-row-id": rowId, onClick: handleSingleRowClick, children: [hasCheckboxCol && (_jsx(TableCell, { className: styles.selectionCellWrapper, children: _jsx("div", { className: styles.selectionCellInner, "data-row-index": rowIndex, "data-col-index": 0, onClick:
|
|
19
|
+
return (_jsxs(TableRow, { className: isSelected ? styles.selectedRow : undefined, "data-row-id": rowId, onClick: handleSingleRowClick, children: [hasCheckboxCol && (_jsx(TableCell, { className: styles.selectionCellWrapper, children: _jsx("div", { className: styles.selectionCellInner, "data-row-index": rowIndex, "data-col-index": 0, onClick: STOP_PROPAGATION, children: _jsx(Checkbox, { checked: isSelected, onChange: (e, data) => {
|
|
19
20
|
handleRowCheckboxChange(rowId, !!data.checked, rowIndex, lastMouseShiftRef.current);
|
|
20
21
|
}, "aria-label": `Select row ${rowIndex + 1}` }) }) })), hasRowNumbersCol && (_jsx(TableCell, { className: styles.rowNumberCellWrapper, children: _jsx("div", { className: styles.rowNumberCellInner, children: rowNumberOffset + rowIndex + 1 }) })), visibleCols.map((col, colIdx) => (_jsx(TableCell, { "data-column-id": col.columnId, className: columnMeta.cellClasses[col.columnId] || undefined, style: columnMeta.cellStyles[col.columnId], children: renderCellContent(item, col, rowIndex, colIdx) }, col.columnId)))] }));
|
|
21
22
|
}
|
|
22
23
|
const GridRow = React.memo(GridRowInner, areGridRowPropsEqual);
|
|
23
24
|
function DataGridTableInner(props) {
|
|
24
25
|
const o = useDataGridTableOrchestration({ props });
|
|
25
|
-
const { wrapperRef, tableContainerRef, lastMouseShiftRef, interaction, pinning, handleResizeStart, getColumnWidth, isReorderDragging, dropIndicatorX, handleHeaderMouseDown, virtualScrollEnabled, visibleRange, items, getRowId, emptyState, rowSelection, isLoading, loadingMessage, ariaLabel, ariaLabelledBy, visibleColumns, columnOrder, columnReorder, density, rowNumberOffset, headerRows, allowOverflowX, fitToContent, editCallbacks, interactionHandlers, cellDescriptorInputRef, pendingEditorValueRef, popoverAnchorElRef, handleSingleRowClick, handlePasteVoid, visibleCols, totalColCount, hasCheckboxCol, hasRowNumbersCol, colOffset, containerWidth, minTableWidth, columnSizingOverrides, measuredColumnWidths, selectedRowIds, handleRowCheckboxChange, handleSelectAll, allSelected, someSelected, editingCell, setPopoverAnchorEl, cancelPopoverEdit, setActiveCell, selectionRange, hasCellSelection, handleGridKeyDown, handleFillHandleMouseDown, handleCopy, handleCut, cutRange, copyRange, canUndo, canRedo, onUndo, onRedo, isDragging, menuPosition, closeContextMenu, headerFilterInput, statusBarConfig, showEmptyInGrid, onCellError, headerMenu, } = o;
|
|
26
|
+
const { wrapperRef, tableContainerRef, lastMouseShiftRef, interaction, pinning, handleResizeStart, getColumnWidth, isReorderDragging, dropIndicatorX, handleHeaderMouseDown, virtualScrollEnabled, visibleRange, items, getRowId, emptyState, rowSelection, isLoading, loadingMessage, ariaLabel, ariaLabelledBy, visibleColumns, columnOrder, columnReorder, density, rowHeight, rowNumberOffset, headerRows, allowOverflowX, fitToContent, editCallbacks, interactionHandlers, cellDescriptorInputRef, pendingEditorValueRef, popoverAnchorElRef, handleSingleRowClick, handlePasteVoid, visibleCols, totalColCount, hasCheckboxCol, hasRowNumbersCol, colOffset, containerWidth, minTableWidth, columnSizingOverrides, measuredColumnWidths, selectedRowIds, handleRowCheckboxChange, handleSelectAll, allSelected, someSelected, editingCell, setPopoverAnchorEl, cancelPopoverEdit, setActiveCell, selectionRange, hasCellSelection, handleGridKeyDown, handleFillHandleMouseDown, handleCopy, handleCut, cutRange, copyRange, canUndo, canRedo, onUndo, onRedo, isDragging, menuPosition, closeContextMenu, headerFilterInput, statusBarConfig, showEmptyInGrid, onCellError, headerMenu, } = o;
|
|
26
27
|
// Pre-compute column styles and classNames (avoids per-cell object creation in the row loop)
|
|
27
28
|
const columnMeta = useMemo(() => {
|
|
28
29
|
const cellStyles = {};
|
|
@@ -105,6 +106,7 @@ function DataGridTableInner(props) {
|
|
|
105
106
|
['--data-table-width']: showEmptyInGrid ? '100%' : allowOverflowX ? 'fit-content' : fitToContent ? 'fit-content' : '100%',
|
|
106
107
|
['--data-table-min-width']: showEmptyInGrid ? '100%' : allowOverflowX ? 'max-content' : fitToContent ? 'max-content' : '100%',
|
|
107
108
|
['--data-table-total-min-width']: `${minTableWidth}px`,
|
|
109
|
+
...(rowHeight ? { ['--ogrid-row-height']: `${rowHeight}px` } : {}),
|
|
108
110
|
}, children: [_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, { role: "grid", className: styles.dataTable, children: [_jsx(TableHeader, { className: styles.stickyHeader, children: headerRows.map((row, rowIdx) => (_jsxs(TableRow, { children: [rowIdx === headerRows.length - 1 && hasCheckboxCol && (_jsx(TableHeaderCell, { className: styles.selectionHeaderCellWrapper, children: _jsx("div", { className: styles.selectionHeaderCellInner, children: _jsx(Checkbox, { checked: allSelected ? true : someSelected ? 'mixed' : false, onChange: (_, data) => handleSelectAll(!!data.checked), "aria-label": "Select all rows" }) }) }, "__selection__")), rowIdx === 0 && rowIdx < headerRows.length - 1 && hasCheckboxCol && (_jsx("th", { rowSpan: headerRows.length - 1 }, "__selection_placeholder__")), rowIdx === headerRows.length - 1 && hasRowNumbersCol && (_jsx(TableHeaderCell, { className: styles.rowNumberHeaderCellWrapper, children: _jsx("div", { className: styles.rowNumberHeaderCellInner, children: "#" }) }, "__row_number__")), rowIdx === 0 && rowIdx < headerRows.length - 1 && hasRowNumbersCol && (_jsx("th", { rowSpan: headerRows.length - 1 }, "__row_number_placeholder__")), row.map((cell, cellIdx) => {
|
|
109
111
|
if (cell.isGroup) {
|
|
110
112
|
return (_jsx("th", { colSpan: cell.colSpan, className: styles.groupHeaderCell, scope: "colgroup", children: cell.label }, cellIdx));
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { BaseDropIndicator } from '@alaarab/ogrid-react';
|
|
2
3
|
import styles from './DataGridTable.module.css';
|
|
3
4
|
export function DropIndicator({ dropIndicatorX, wrapperLeft }) {
|
|
4
|
-
return
|
|
5
|
+
return _jsx(BaseDropIndicator, { dropIndicatorX: dropIndicatorX, wrapperLeft: wrapperLeft, className: styles.dropIndicator });
|
|
5
6
|
}
|
|
@@ -1,5 +1,14 @@
|
|
|
1
|
-
import { jsx as _jsx
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { BaseEmptyState } from '@alaarab/ogrid-react';
|
|
2
3
|
import styles from './DataGridTable.module.css';
|
|
4
|
+
const classNames = {
|
|
5
|
+
emptyStateInGrid: styles.emptyStateInGrid,
|
|
6
|
+
emptyStateInGridInner: styles.emptyStateInGridMessageSticky,
|
|
7
|
+
emptyStateInGridIcon: styles.emptyStateInGridIcon,
|
|
8
|
+
emptyStateInGridTitle: styles.emptyStateInGridTitle,
|
|
9
|
+
emptyStateInGridMessage: styles.emptyStateInGridMessage,
|
|
10
|
+
emptyStateInGridLink: styles.emptyStateInGridLink,
|
|
11
|
+
};
|
|
3
12
|
export function EmptyState({ emptyState }) {
|
|
4
|
-
return
|
|
13
|
+
return _jsx(BaseEmptyState, { emptyState: emptyState, classNames: classNames, icon: '\uD83D\uDCCB' });
|
|
5
14
|
}
|
|
@@ -1,5 +1,12 @@
|
|
|
1
|
-
import { jsx as _jsx
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { BaseLoadingOverlay } from '@alaarab/ogrid-react';
|
|
2
3
|
import styles from './DataGridTable.module.css';
|
|
4
|
+
const classNames = {
|
|
5
|
+
loadingOverlay: styles.loadingOverlay,
|
|
6
|
+
loadingOverlayContent: styles.loadingOverlayContent,
|
|
7
|
+
spinner: styles.spinner,
|
|
8
|
+
loadingOverlayText: styles.loadingOverlayText,
|
|
9
|
+
};
|
|
3
10
|
export function LoadingOverlay({ message }) {
|
|
4
|
-
return
|
|
11
|
+
return _jsx(BaseLoadingOverlay, { message: message, classNames: classNames });
|
|
5
12
|
}
|
|
@@ -1,7 +1,12 @@
|
|
|
1
|
-
import { jsx as _jsx
|
|
2
|
-
import {
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { StatusBar as BaseStatusBar } from '@alaarab/ogrid-react';
|
|
3
3
|
import styles from './DataGridTable.module.css';
|
|
4
|
+
const statusBarClassNames = {
|
|
5
|
+
statusBar: styles.statusBar,
|
|
6
|
+
statusBarItem: styles.statusBarItem,
|
|
7
|
+
statusBarLabel: styles.statusBarLabel,
|
|
8
|
+
statusBarValue: styles.statusBarValue,
|
|
9
|
+
};
|
|
4
10
|
export function StatusBar(props) {
|
|
5
|
-
|
|
6
|
-
return (_jsx("div", { className: styles.statusBar, role: "status", "aria-live": "polite", children: parts.map((p) => (_jsxs("span", { className: styles.statusBarItem, children: [_jsx("span", { className: styles.statusBarLabel, children: p.label }), _jsx("span", { className: styles.statusBarValue, children: p.value.toLocaleString() })] }, p.key))) }));
|
|
11
|
+
return _jsx(BaseStatusBar, { ...props, classNames: statusBarClassNames });
|
|
7
12
|
}
|
package/dist/esm/OGrid/OGrid.js
CHANGED
|
@@ -1,16 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import * as React from 'react';
|
|
3
|
-
import { forwardRef } from 'react';
|
|
1
|
+
import { createOGrid } from '@alaarab/ogrid-react';
|
|
4
2
|
import { DataGridTable } from '../DataGridTable/DataGridTable';
|
|
5
3
|
import { ColumnChooser } from '../ColumnChooser/ColumnChooser';
|
|
6
4
|
import { PaginationControls } from '../PaginationControls/PaginationControls';
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
pagination.setPageSize(size);
|
|
12
|
-
pagination.setPage(1);
|
|
13
|
-
}, pageSizeOptions: pagination.pageSizeOptions, entityLabelPlural: pagination.entityLabelPlural }), children: _jsx(DataGridTable, { ...dataGridProps }) }));
|
|
5
|
+
export const OGrid = createOGrid({
|
|
6
|
+
DataGridTable: DataGridTable,
|
|
7
|
+
ColumnChooser: ColumnChooser,
|
|
8
|
+
PaginationControls,
|
|
14
9
|
});
|
|
15
|
-
OGridInner.displayName = 'OGrid';
|
|
16
|
-
export const OGrid = React.memo(OGridInner);
|
package/dist/esm/index.js
CHANGED
|
@@ -5,5 +5,7 @@ export { ColumnChooser } from './ColumnChooser/ColumnChooser';
|
|
|
5
5
|
export { ColumnHeaderFilter } from './ColumnHeaderFilter/ColumnHeaderFilter';
|
|
6
6
|
export { ColumnHeaderMenu } from './ColumnHeaderMenu/ColumnHeaderMenu';
|
|
7
7
|
export { PaginationControls } from './PaginationControls/PaginationControls';
|
|
8
|
-
// Re-export
|
|
8
|
+
// Re-export all from base package for consumer convenience.
|
|
9
|
+
// Note: This prevents tree-shaking of unused utilities.
|
|
10
|
+
// Consider explicit named exports in a future major version.
|
|
9
11
|
export * from '@alaarab/ogrid-react';
|
|
@@ -1,25 +1,7 @@
|
|
|
1
|
-
import
|
|
2
|
-
export
|
|
3
|
-
isOpen: boolean;
|
|
4
|
-
anchorElement: HTMLElement | null;
|
|
5
|
-
onClose: () => void;
|
|
6
|
-
onPinLeft: () => void;
|
|
7
|
-
onPinRight: () => void;
|
|
8
|
-
onUnpin: () => void;
|
|
9
|
-
onSortAsc: () => void;
|
|
10
|
-
onSortDesc: () => void;
|
|
11
|
-
onClearSort: () => void;
|
|
12
|
-
onAutosizeThis: () => void;
|
|
13
|
-
onAutosizeAll: () => void;
|
|
14
|
-
canPinLeft: boolean;
|
|
15
|
-
canPinRight: boolean;
|
|
16
|
-
canUnpin: boolean;
|
|
17
|
-
currentSort: 'asc' | 'desc' | null;
|
|
18
|
-
isSortable: boolean;
|
|
19
|
-
isResizable: boolean;
|
|
20
|
-
}
|
|
1
|
+
import type { BaseColumnHeaderMenuProps } from '@alaarab/ogrid-react';
|
|
2
|
+
export type ColumnHeaderMenuProps = Omit<BaseColumnHeaderMenuProps, 'classNames' | 'getPortalTarget'>;
|
|
21
3
|
/**
|
|
22
4
|
* Column header dropdown menu for pin/sort/autosize actions.
|
|
23
|
-
*
|
|
5
|
+
* Thin wrapper over BaseColumnHeaderMenu — portals into FluentProvider.
|
|
24
6
|
*/
|
|
25
|
-
export declare function ColumnHeaderMenu(props: ColumnHeaderMenuProps):
|
|
7
|
+
export declare function ColumnHeaderMenu(props: ColumnHeaderMenuProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
+
import type { BaseEmptyStateProps } from '@alaarab/ogrid-react';
|
|
2
3
|
interface EmptyStateProps {
|
|
3
|
-
emptyState:
|
|
4
|
-
render?: () => React.ReactNode;
|
|
5
|
-
message?: React.ReactNode;
|
|
6
|
-
hasActiveFilters?: boolean;
|
|
7
|
-
onClearAll?: () => void;
|
|
8
|
-
};
|
|
4
|
+
emptyState: BaseEmptyStateProps['emptyState'];
|
|
9
5
|
}
|
|
10
6
|
export declare function EmptyState({ emptyState }: EmptyStateProps): React.ReactElement;
|
|
11
7
|
export {};
|
|
@@ -1,12 +1,4 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import type {
|
|
3
|
-
export
|
|
4
|
-
value: unknown;
|
|
5
|
-
item: T;
|
|
6
|
-
column: IColumnDef<T>;
|
|
7
|
-
rowIndex: number;
|
|
8
|
-
editorType: 'text' | 'select' | 'checkbox' | 'richSelect' | 'date';
|
|
9
|
-
onCommit: (value: unknown) => void;
|
|
10
|
-
onCancel: () => void;
|
|
11
|
-
}
|
|
2
|
+
import type { InlineCellEditorProps } from '@alaarab/ogrid-react';
|
|
3
|
+
export type { InlineCellEditorProps } from '@alaarab/ogrid-react';
|
|
12
4
|
export declare function InlineCellEditor<T>(props: InlineCellEditorProps<T>): React.ReactElement;
|
|
@@ -1,16 +1,4 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
filteredCount?: number;
|
|
5
|
-
selectedCount?: number;
|
|
6
|
-
selectedCellCount?: number;
|
|
7
|
-
aggregation?: {
|
|
8
|
-
sum: number;
|
|
9
|
-
avg: number;
|
|
10
|
-
min: number;
|
|
11
|
-
max: number;
|
|
12
|
-
count: number;
|
|
13
|
-
} | null;
|
|
14
|
-
suppressRowCount?: boolean;
|
|
15
|
-
}
|
|
2
|
+
import type { StatusBarProps as BaseStatusBarProps } from '@alaarab/ogrid-react';
|
|
3
|
+
export type StatusBarProps = Omit<BaseStatusBarProps, 'classNames'>;
|
|
16
4
|
export declare function StatusBar(props: StatusBarProps): React.ReactElement;
|
|
@@ -1,5 +1,2 @@
|
|
|
1
|
-
import * as React from 'react';
|
|
2
|
-
import { type IOGridProps, type IOGridApi } from '@alaarab/ogrid-react';
|
|
3
1
|
export type { IOGridProps } from '@alaarab/ogrid-react';
|
|
4
|
-
declare const
|
|
5
|
-
export declare const OGrid: typeof OGridInner;
|
|
2
|
+
export declare const OGrid: import("react").ForwardRefExoticComponent<import("@alaarab/ogrid-react").IOGridProps<unknown> & import("react").RefAttributes<import("@alaarab/ogrid-react").IOGridApi<unknown>>>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alaarab/ogrid-react-fluent",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.21",
|
|
4
4
|
"description": "OGrid React Fluent implementation – DataGrid-powered data table with sorting, filtering, pagination, column chooser, and CSV export.",
|
|
5
5
|
"main": "dist/esm/index.js",
|
|
6
6
|
"module": "dist/esm/index.js",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"node": ">=18"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@alaarab/ogrid-react": "2.0.
|
|
43
|
+
"@alaarab/ogrid-react": "2.0.21"
|
|
44
44
|
},
|
|
45
45
|
"peerDependencies": {
|
|
46
46
|
"@fluentui/react-components": "^9.0.0",
|