@alaarab/ogrid-react-fluent 2.0.19 → 2.0.22

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.
@@ -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 { ArrowUpRegular, ArrowDownRegular, ArrowSortRegular, FilterRegular } from '@fluentui/react-icons';
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, isSorted = false, isSortedDescending = false, onSort, options, isLoadingOptions = false, selectedUser, } = props;
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 }) }), _jsxs("div", { className: styles.headerActions, children: [onSort && (_jsx("button", { type: "button", className: `${styles.sortIcon} ${isSorted ? styles.sortActive : ''}`, onClick: handlers.handleSortClick, "aria-label": `Sort by ${columnName}`, title: isSorted ? (isSortedDescending ? 'Sorted descending' : 'Sorted ascending') : 'Sort', children: isSorted ? (isSortedDescending ? _jsx(ArrowDownRegular, {}) : _jsx(ArrowUpRegular, {})) : (_jsx(ArrowSortRegular, {})) })), 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)] }) })] }))] })] }));
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;
@@ -144,6 +114,9 @@
144
114
  border: 1px solid var(--colorNeutralStroke1, #d1d1d1);
145
115
  border-radius: var(--borderRadiusMedium, 4px);
146
116
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.14);
117
+ font-family: var(--fontFamilyBase, "Segoe UI", -apple-system, BlinkMacSystemFont, "Helvetica Neue", Arial, sans-serif);
118
+ font-size: 14px;
119
+ color: var(--colorNeutralForeground1, #242424);
147
120
  }
148
121
 
149
122
  .popoverHeader {
@@ -159,12 +132,6 @@
159
132
  padding: 10px 12px;
160
133
  border-bottom: 1px solid var(--colorNeutralStroke2, #e0e0e0);
161
134
  }
162
- .popoverSearch .searchInput {
163
- width: 100%;
164
- }
165
- .popoverSearch .searchInput :global .fui-Input__input {
166
- border-width: 1px !important;
167
- }
168
135
 
169
136
  .nativeInputWrapper {
170
137
  display: flex;
@@ -255,11 +222,32 @@
255
222
  .popoverOption {
256
223
  padding: 4px 12px;
257
224
  transition: background-color 0.1s ease;
225
+ cursor: pointer;
258
226
  }
259
227
  .popoverOption:hover {
260
228
  background-color: var(--colorNeutralBackground1Hover, #f5f5f5);
261
229
  }
262
230
 
231
+ .nativeCheckbox {
232
+ width: 16px;
233
+ height: 16px;
234
+ margin: 0;
235
+ cursor: pointer;
236
+ accent-color: var(--colorBrandBackground, #0f6cbd);
237
+ flex-shrink: 0;
238
+ }
239
+
240
+ .checkboxLabel {
241
+ margin-left: 8px;
242
+ font-size: 14px;
243
+ color: var(--colorNeutralForeground1, #242424);
244
+ overflow: hidden;
245
+ text-overflow: ellipsis;
246
+ white-space: nowrap;
247
+ min-width: 0;
248
+ cursor: pointer;
249
+ }
250
+
263
251
  .personOption {
264
252
  padding: 8px 12px;
265
253
  cursor: pointer;
@@ -323,6 +311,32 @@
323
311
  gap: 8px;
324
312
  }
325
313
 
314
+ .avatar {
315
+ width: 32px;
316
+ height: 32px;
317
+ border-radius: 50%;
318
+ background-color: var(--colorBrandBackground, #0f6cbd);
319
+ display: flex;
320
+ align-items: center;
321
+ justify-content: center;
322
+ flex-shrink: 0;
323
+ overflow: hidden;
324
+ }
325
+
326
+ .avatarImg {
327
+ width: 100%;
328
+ height: 100%;
329
+ object-fit: cover;
330
+ border-radius: 50%;
331
+ }
332
+
333
+ .avatarInitials {
334
+ color: var(--colorNeutralForegroundOnBrand, #ffffff);
335
+ font-size: 12px;
336
+ font-weight: 600;
337
+ line-height: 1;
338
+ }
339
+
326
340
  .userText {
327
341
  display: flex;
328
342
  flex-direction: column;
@@ -1,17 +1,17 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { Input, Checkbox } from '@fluentui/react-components';
3
2
  import { SearchRegular } from '@fluentui/react-icons';
4
3
  import { useListVirtualizer } from '@alaarab/ogrid-react';
5
4
  import styles from './ColumnHeaderFilter.module.css';
6
5
  const ITEM_HEIGHT = 40;
7
6
  export const MultiSelectFilterPopover = ({ searchText, onSearchChange, options, filteredOptions, selected, onOptionToggle, onSelectAll, onClearSelection, onApply, isLoading, onPopoverClick, onInputFocus, onInputMouseDown, onInputClick, onInputKeyDown, }) => {
8
7
  const virt = useListVirtualizer({ count: filteredOptions.length, itemHeight: ITEM_HEIGHT });
9
- return (_jsxs(_Fragment, { children: [_jsxs("div", { className: styles.popoverSearch, onClick: onPopoverClick, children: [_jsx(Input, { placeholder: "Search...", value: searchText, onChange: (e, data) => onSearchChange(data.value ?? ''), onFocus: onInputFocus, onMouseDown: onInputMouseDown, onClick: onInputClick, onKeyDown: onInputKeyDown, autoComplete: "off", className: styles.searchInput, contentBefore: _jsx(SearchRegular, {}) }), _jsxs("div", { className: styles.resultCount, children: [filteredOptions.length, " of ", options.length, " options"] })] }), _jsxs("div", { className: styles.selectAllRow, onClick: onPopoverClick, children: [_jsxs("button", { type: "button", className: styles.selectAllButton, onClick: onSelectAll, children: ["Select All (", filteredOptions.length, ")"] }), _jsx("button", { type: "button", className: styles.selectAllButton, onClick: onClearSelection, children: "Clear" })] }), _jsx("div", { ref: virt.containerRef, onScroll: virt.onScroll, className: styles.popoverOptions, onClick: onPopoverClick, children: isLoading ? (_jsxs("div", { className: styles.loadingContainer, children: [_jsx("div", { className: styles.filterSpinner }), _jsx("span", { style: { fontSize: 12, color: 'var(--colorNeutralForeground2, #616161)' }, children: "Loading..." })] })) : filteredOptions.length === 0 ? (_jsx("div", { className: styles.noResults, children: "No options found" })) : (_jsx("div", { style: { height: virt.totalHeight, position: 'relative' }, children: virt.visibleItems.map(({ index, offsetTop }) => {
8
+ return (_jsxs(_Fragment, { children: [_jsxs("div", { className: styles.popoverSearch, onClick: onPopoverClick, children: [_jsxs("div", { className: styles.nativeInputWrapper, children: [_jsx(SearchRegular, { className: styles.nativeInputIcon }), _jsx("input", { type: "text", placeholder: "Search...", value: searchText, onChange: (e) => onSearchChange(e.target.value), onFocus: onInputFocus, onMouseDown: onInputMouseDown, onClick: onInputClick, onKeyDown: onInputKeyDown, autoComplete: "off", className: styles.nativeInput })] }), _jsxs("div", { className: styles.resultCount, children: [filteredOptions.length, " of ", options.length, " options"] })] }), _jsxs("div", { className: styles.selectAllRow, onClick: onPopoverClick, children: [_jsxs("button", { type: "button", className: styles.selectAllButton, onClick: onSelectAll, children: ["Select All (", filteredOptions.length, ")"] }), _jsx("button", { type: "button", className: styles.selectAllButton, onClick: onClearSelection, children: "Clear" })] }), _jsx("div", { ref: virt.containerRef, onScroll: virt.onScroll, className: styles.popoverOptions, onClick: onPopoverClick, children: isLoading ? (_jsxs("div", { className: styles.loadingContainer, children: [_jsx("div", { className: styles.filterSpinner }), _jsx("span", { style: { fontSize: 12, color: 'var(--colorNeutralForeground2, #616161)' }, children: "Loading..." })] })) : filteredOptions.length === 0 ? (_jsx("div", { className: styles.noResults, children: "No options found" })) : (_jsx("div", { style: { height: virt.totalHeight, position: 'relative' }, children: virt.visibleItems.map(({ index, offsetTop }) => {
10
9
  const option = filteredOptions[index];
11
- return (_jsx("div", { className: styles.popoverOption, style: { position: 'absolute', top: offsetTop, width: '100%', height: ITEM_HEIGHT, boxSizing: 'border-box', display: 'flex', alignItems: 'center' }, children: _jsx(Checkbox, { label: option, checked: selected.has(option), onChange: (ev, data) => {
12
- ev.stopPropagation();
13
- onOptionToggle(option, data.checked === true);
14
- } }) }, option));
10
+ const isChecked = selected.has(option);
11
+ return (_jsxs("label", { className: styles.popoverOption, style: { position: 'absolute', top: offsetTop, width: '100%', height: ITEM_HEIGHT, boxSizing: 'border-box', display: 'flex', alignItems: 'center' }, children: [_jsx("input", { type: "checkbox", checked: isChecked, onChange: (ev) => {
12
+ ev.stopPropagation();
13
+ onOptionToggle(option, ev.target.checked);
14
+ }, className: styles.nativeCheckbox }), _jsx("span", { className: styles.checkboxLabel, children: option })] }, option));
15
15
  }) })) }), _jsxs("div", { className: styles.popoverActions, onClick: onPopoverClick, children: [_jsx("button", { type: "button", className: styles.clearButton, onClick: onClearSelection, children: "Clear" }), _jsx("button", { type: "button", className: styles.applyButton, onClick: onApply, children: "Apply" })] })] }));
16
16
  };
17
17
  MultiSelectFilterPopover.displayName = 'MultiSelectFilterPopover';
@@ -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
- 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(Avatar, { name: selectedUser.displayName, image: { src: selectedUser.photo }, size: 32 }), _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) => {
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(Avatar, { name: user.displayName, image: { src: user.photo }, size: 32 }), _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" }) }))] }));
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,12 +1,11 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { Input } from '@fluentui/react-components';
3
2
  import { SearchRegular } from '@fluentui/react-icons';
4
3
  import styles from './ColumnHeaderFilter.module.css';
5
- export const TextFilterPopover = ({ value, onValueChange, onApply, onClear, onPopoverClick, onInputFocus, onInputMouseDown, onInputClick, onInputKeyDown, }) => (_jsxs(_Fragment, { children: [_jsx("div", { className: styles.popoverSearch, onClick: onPopoverClick, children: _jsx(Input, { placeholder: "Enter search term...", value: value, onChange: (e, data) => onValueChange(data.value ?? ''), onKeyDown: (e) => {
6
- onInputKeyDown(e);
7
- if (e.key === 'Enter') {
8
- e.preventDefault();
9
- onApply();
10
- }
11
- }, onFocus: onInputFocus, onMouseDown: onInputMouseDown, onClick: onInputClick, autoComplete: "off", className: styles.searchInput, contentBefore: _jsx(SearchRegular, {}) }) }), _jsxs("div", { className: styles.popoverActions, onClick: onPopoverClick, children: [_jsx("button", { type: "button", className: styles.clearButton, onClick: onClear, disabled: !value, children: "Clear" }), _jsx("button", { type: "button", className: styles.applyButton, onClick: onApply, children: "Apply" })] })] }));
4
+ export const TextFilterPopover = ({ value, onValueChange, onApply, onClear, onPopoverClick, onInputFocus, onInputMouseDown, onInputClick, onInputKeyDown, }) => (_jsxs(_Fragment, { children: [_jsx("div", { className: styles.popoverSearch, onClick: onPopoverClick, children: _jsxs("div", { className: styles.nativeInputWrapper, children: [_jsx(SearchRegular, { className: styles.nativeInputIcon }), _jsx("input", { type: "text", placeholder: "Enter search term...", value: value, onChange: (e) => onValueChange(e.target.value), onKeyDown: (e) => {
5
+ onInputKeyDown(e);
6
+ if (e.key === 'Enter') {
7
+ e.preventDefault();
8
+ onApply();
9
+ }
10
+ }, onFocus: onInputFocus, onMouseDown: onInputMouseDown, onClick: onInputClick, autoComplete: "off", className: styles.nativeInput })] }) }), _jsxs("div", { className: styles.popoverActions, onClick: onPopoverClick, children: [_jsx("button", { type: "button", className: styles.clearButton, onClick: onClear, disabled: !value, children: "Clear" }), _jsx("button", { type: "button", className: styles.applyButton, onClick: onApply, children: "Apply" })] })] }));
12
11
  TextFilterPopover.displayName = 'TextFilterPopover';
@@ -1,77 +1,12 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import React, { useMemo, useEffect, useState, useRef } from 'react';
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
- * Uses positioned div with portal rendering.
8
+ * Thin wrapper over BaseColumnHeaderMenu portals into FluentProvider.
9
9
  */
10
10
  export function ColumnHeaderMenu(props) {
11
- const { isOpen, anchorElement, onClose, onPinLeft, onPinRight, onUnpin, onSortAsc, onSortDesc, onClearSort, onAutosizeThis, onAutosizeAll, canPinLeft, canPinRight, canUnpin, currentSort, isSortable, isResizable, } = props;
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: (e) => e.stopPropagation(), children: _jsx(Checkbox, { checked: isSelected, onChange: (e, data) => {
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));
@@ -48,6 +48,9 @@
48
48
  background-color: var(--ogrid-bg, #fff);
49
49
  color: var(--ogrid-fg, rgba(0, 0, 0, 0.87));
50
50
  }
51
+ .dataTable tbody tr {
52
+ height: var(--ogrid-row-height, auto);
53
+ }
51
54
 
52
55
  .groupHeaderCell {
53
56
  text-align: center;
@@ -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 (_jsx("div", { className: styles.dropIndicator, style: { left: dropIndicatorX - wrapperLeft } }));
5
+ return _jsx(BaseDropIndicator, { dropIndicatorX: dropIndicatorX, wrapperLeft: wrapperLeft, className: styles.dropIndicator });
5
6
  }
@@ -1,5 +1,14 @@
1
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
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 (_jsx("div", { className: styles.emptyStateInGrid, children: _jsx("div", { className: styles.emptyStateInGridMessageSticky, children: emptyState.render ? (emptyState.render()) : (_jsxs(_Fragment, { children: [_jsx("span", { className: styles.emptyStateInGridIcon, "aria-hidden": true, children: '\uD83D\uDCCB' }), _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.') })] })) }) }));
13
+ return _jsx(BaseEmptyState, { emptyState: emptyState, classNames: classNames, icon: '\uD83D\uDCCB' });
5
14
  }
@@ -1,5 +1,12 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
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 (_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: message })] }) }));
11
+ return _jsx(BaseLoadingOverlay, { message: message, classNames: classNames });
5
12
  }
@@ -1,7 +1,12 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { getStatusBarParts } from '@alaarab/ogrid-react';
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
- const parts = getStatusBarParts(props);
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
  }
@@ -1,16 +1,9 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
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
- import { useOGrid, OGridLayout, } from '@alaarab/ogrid-react';
8
- const OGridInner = forwardRef(function OGridInner(props, ref) {
9
- const { dataGridProps, pagination, columnChooser, layout } = useOGrid(props, ref);
10
- return (_jsx(OGridLayout, { className: layout.className, sideBar: layout.sideBarProps, toolbar: layout.toolbar, toolbarBelow: layout.toolbarBelow, toolbarEnd: columnChooser.placement === 'toolbar' ? (_jsx(ColumnChooser, { columns: columnChooser.columns, visibleColumns: columnChooser.visibleColumns, onVisibilityChange: columnChooser.onVisibilityChange })) : undefined, pagination: _jsx(PaginationControls, { currentPage: pagination.page, pageSize: pagination.pageSize, totalCount: pagination.displayTotalCount, onPageChange: pagination.setPage, onPageSizeChange: (size) => {
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 everything from core
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 React from 'react';
2
- export interface ColumnHeaderMenuProps {
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
- * Uses positioned div with portal rendering.
5
+ * Thin wrapper over BaseColumnHeaderMenu portals into FluentProvider.
24
6
  */
25
- export declare function ColumnHeaderMenu(props: ColumnHeaderMenuProps): React.ReactPortal | null;
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 { IColumnDef } from '@alaarab/ogrid-react';
3
- export interface InlineCellEditorProps<T> {
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
- export interface StatusBarProps {
3
- totalCount: number;
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 OGridInner: React.ForwardRefExoticComponent<IOGridProps<unknown> & React.RefAttributes<IOGridApi<unknown>>>;
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.19",
3
+ "version": "2.0.22",
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.19"
43
+ "@alaarab/ogrid-react": "2.0.22"
44
44
  },
45
45
  "peerDependencies": {
46
46
  "@fluentui/react-components": "^9.0.0",