@rio-cloud/rio-uikit 1.7.1 → 1.9.0
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/BarList.d.ts +2 -0
- package/BarList.js +2 -0
- package/README.md +4 -0
- package/SaveableDateInput.d.ts +2 -0
- package/SaveableDateInput.js +2 -0
- package/SvgImage.d.ts +2 -0
- package/SvgImage.js +2 -0
- package/TableCol.d.ts +2 -0
- package/TableCol.js +2 -0
- package/TableHead.d.ts +2 -0
- package/TableHead.js +2 -0
- package/components/actionBarItem/ActionBarItemIcon.js +1 -1
- package/components/actionBarItem/ActionBarOverlay.js +1 -1
- package/components/activity/Activity.d.ts +2 -2
- package/components/applicationHeader/CollapsedNavItem.js +1 -0
- package/components/assetTree/Tree.d.ts +20 -0
- package/components/assetTree/Tree.js +75 -38
- package/components/assetTree/TreeLeaf.js +1 -1
- package/components/assetTree/TreeNodeContainer.d.ts +1 -1
- package/components/assetTree/TreeSearch.js +1 -1
- package/components/assetTree/TreeSummary.js +1 -1
- package/components/assetTree/TypeCounter.d.ts +2 -0
- package/components/assetTree/TypeCounter.js +1 -1
- package/components/assetTree/useTreeExpansion.d.ts +4 -0
- package/components/assetTree/useTreeExpansion.js +25 -0
- package/components/assetTree/useTreeHeight.d.ts +1 -0
- package/components/assetTree/useTreeHeight.js +60 -0
- package/components/assetTree/useTreeScrollPosition.d.ts +3 -0
- package/components/assetTree/useTreeScrollPosition.js +19 -0
- package/components/assetTree/useTreeVirtualization.d.ts +17 -0
- package/components/assetTree/useTreeVirtualization.js +71 -0
- package/components/autosuggest/AutoSuggest.js +2 -1
- package/components/barList/BarList.d.ts +97 -0
- package/components/barList/BarList.js +42 -0
- package/components/barList/useSortedBars.d.ts +2 -0
- package/components/barList/useSortedBars.js +14 -0
- package/components/button/ButtonToolbar.d.ts +1 -1
- package/components/button/ButtonToolbar.js +1 -1
- package/components/button/ToggleButton.js +0 -1
- package/components/charts/PieChart.js +1 -1
- package/components/clearableInput/ClearableInput.d.ts +20 -7
- package/components/clearableInput/ClearableInput.js +68 -8
- package/components/dialog/Dialog.js +1 -1
- package/components/dialog/FrameDialog.js +1 -1
- package/components/dropdown/ButtonDropdown.d.ts +11 -3
- package/components/dropdown/ButtonDropdown.js +79 -64
- package/components/dropdown/DropdownToggleButton.d.ts +7 -4
- package/components/dropdown/DropdownToggleButton.js +11 -3
- package/components/formLabel/FormLabel.d.ts +2 -2
- package/components/formLabel/FormLabel.js +1 -1
- package/components/listMenu/ListMenu.js +4 -1
- package/components/map/components/Map.js +21 -6
- package/components/map/components/constants.d.ts +2 -0
- package/components/map/components/constants.js +3 -0
- package/components/map/components/features/basics/InfoBubble.js +1 -1
- package/components/map/components/features/layers/overlayLayers/IncidentsLayer.js +1 -1
- package/components/map/utils/mapTypes.d.ts +5 -0
- package/components/map/utils/rendering.d.ts +5 -2
- package/components/map/utils/rendering.js +46 -39
- package/components/menuItems/MenuItem.js +1 -1
- package/components/notification/Notification.js +1 -1
- package/components/overlay/OverlayTrigger.js +3 -3
- package/components/saveableInput/SaveableDateInput.d.ts +83 -0
- package/components/saveableInput/SaveableDateInput.js +122 -0
- package/components/selects/BaseSelectDropdown.js +1 -1
- package/components/selects/Multiselect.d.ts +8 -0
- package/components/selects/Multiselect.js +4 -4
- package/components/smoothScrollbars/SmoothScrollbars.d.ts +1 -0
- package/components/smoothScrollbars/SmoothScrollbars.js +3 -3
- package/components/statsWidget/StatsWidget.d.ts +2 -2
- package/components/statsWidget/StatsWidgets.d.ts +2 -2
- package/components/svgImage/SvgElement.d.ts +8 -0
- package/components/svgImage/SvgElement.js +11 -0
- package/components/svgImage/SvgImage.d.ts +30 -0
- package/components/svgImage/SvgImage.js +20 -0
- package/components/svgImage/svgConverter.d.ts +17 -0
- package/components/svgImage/svgConverter.js +78 -0
- package/components/svgImage/useSvgLoader.d.ts +9 -0
- package/components/svgImage/useSvgLoader.js +43 -0
- package/components/switch/Switch.d.ts +4 -0
- package/components/switch/Switch.js +5 -6
- package/components/table/TableCardsSorting.d.ts +0 -1
- package/components/table/TableCol.d.ts +18 -0
- package/components/table/TableCol.js +11 -0
- package/components/table/TableHead.d.ts +33 -0
- package/components/table/TableHead.js +11 -0
- package/components/table/TableSettingsDialog.js +1 -1
- package/components/tag/Tag.js +1 -1
- package/components/timepicker/TimePicker.d.ts +1 -2
- package/components/timepicker/TimePicker.js +35 -8
- package/components/tooltip/SimpleTooltip.d.ts +1 -1
- package/components/virtualList/VirtualList.js +1 -1
- package/hooks/useIsFocusWithin.d.ts +33 -0
- package/hooks/useIsFocusWithin.js +55 -0
- package/hooks/useLocationSuggestions.d.ts +27 -0
- package/hooks/useLocationSuggestions.js +94 -0
- package/hooks/useOnboarding.d.ts +17 -5
- package/hooks/useOnboarding.js +7 -1
- package/hooks/usePostMessage.js +0 -1
- package/hooks/useSearch.d.ts +63 -0
- package/hooks/useSearch.js +73 -0
- package/hooks/useSorting.d.ts +6 -0
- package/hooks/useSorting.js +7 -4
- package/hooks/useTableExport.d.ts +49 -0
- package/hooks/useTableExport.js +57 -0
- package/hooks/useTableSelection.d.ts +166 -0
- package/hooks/useTableSelection.js +201 -0
- package/lib/es/BarList.d.ts +2 -0
- package/lib/es/BarList.js +7 -0
- package/lib/es/SaveableDateInput.d.ts +2 -0
- package/lib/es/SaveableDateInput.js +7 -0
- package/lib/es/SvgImage.d.ts +2 -0
- package/lib/es/SvgImage.js +7 -0
- package/lib/es/TableCol.d.ts +2 -0
- package/lib/es/TableCol.js +7 -0
- package/lib/es/TableHead.d.ts +2 -0
- package/lib/es/TableHead.js +7 -0
- package/lib/es/components/actionBarItem/ActionBarItemIcon.js +1 -1
- package/lib/es/components/actionBarItem/ActionBarOverlay.js +1 -1
- package/lib/es/components/activity/Activity.d.ts +2 -2
- package/lib/es/components/applicationHeader/CollapsedNavItem.js +1 -0
- package/lib/es/components/assetTree/Tree.d.ts +20 -0
- package/lib/es/components/assetTree/Tree.js +74 -37
- package/lib/es/components/assetTree/TreeLeaf.js +1 -1
- package/lib/es/components/assetTree/TreeNodeContainer.d.ts +1 -1
- package/lib/es/components/assetTree/TreeSearch.js +1 -1
- package/lib/es/components/assetTree/TreeSummary.js +1 -1
- package/lib/es/components/assetTree/TypeCounter.d.ts +2 -0
- package/lib/es/components/assetTree/TypeCounter.js +1 -1
- package/lib/es/components/assetTree/useTreeExpansion.d.ts +4 -0
- package/lib/es/components/assetTree/useTreeExpansion.js +29 -0
- package/lib/es/components/assetTree/useTreeHeight.d.ts +1 -0
- package/lib/es/components/assetTree/useTreeHeight.js +64 -0
- package/lib/es/components/assetTree/useTreeScrollPosition.d.ts +3 -0
- package/lib/es/components/assetTree/useTreeScrollPosition.js +23 -0
- package/lib/es/components/assetTree/useTreeVirtualization.d.ts +17 -0
- package/lib/es/components/assetTree/useTreeVirtualization.js +76 -0
- package/lib/es/components/autosuggest/AutoSuggest.js +2 -1
- package/lib/es/components/barList/BarList.d.ts +97 -0
- package/lib/es/components/barList/BarList.js +45 -0
- package/lib/es/components/barList/useSortedBars.d.ts +2 -0
- package/lib/es/components/barList/useSortedBars.js +17 -0
- package/lib/es/components/button/ButtonToolbar.d.ts +1 -1
- package/lib/es/components/button/ButtonToolbar.js +1 -1
- package/lib/es/components/button/ToggleButton.js +0 -1
- package/lib/es/components/charts/PieChart.js +1 -1
- package/lib/es/components/clearableInput/ClearableInput.d.ts +20 -7
- package/lib/es/components/clearableInput/ClearableInput.js +67 -7
- package/lib/es/components/dialog/Dialog.js +1 -1
- package/lib/es/components/dialog/FrameDialog.js +1 -1
- package/lib/es/components/dropdown/ButtonDropdown.d.ts +11 -3
- package/lib/es/components/dropdown/ButtonDropdown.js +79 -64
- package/lib/es/components/dropdown/DropdownToggleButton.d.ts +7 -4
- package/lib/es/components/dropdown/DropdownToggleButton.js +11 -3
- package/lib/es/components/formLabel/FormLabel.d.ts +2 -2
- package/lib/es/components/formLabel/FormLabel.js +1 -1
- package/lib/es/components/listMenu/ListMenu.js +4 -1
- package/lib/es/components/map/components/Map.js +20 -5
- package/lib/es/components/map/components/constants.d.ts +2 -0
- package/lib/es/components/map/components/constants.js +4 -1
- package/lib/es/components/map/components/features/basics/InfoBubble.js +1 -1
- package/lib/es/components/map/components/features/layers/overlayLayers/IncidentsLayer.js +1 -1
- package/lib/es/components/map/utils/mapTypes.d.ts +5 -0
- package/lib/es/components/map/utils/rendering.d.ts +5 -2
- package/lib/es/components/map/utils/rendering.js +46 -39
- package/lib/es/components/menuItems/MenuItem.js +1 -1
- package/lib/es/components/notification/Notification.js +1 -1
- package/lib/es/components/overlay/OverlayTrigger.js +3 -3
- package/lib/es/components/saveableInput/SaveableDateInput.d.ts +83 -0
- package/lib/es/components/saveableInput/SaveableDateInput.js +125 -0
- package/lib/es/components/selects/BaseSelectDropdown.js +1 -1
- package/lib/es/components/selects/Multiselect.d.ts +8 -0
- package/lib/es/components/selects/Multiselect.js +4 -4
- package/lib/es/components/smoothScrollbars/SmoothScrollbars.d.ts +1 -0
- package/lib/es/components/smoothScrollbars/SmoothScrollbars.js +3 -3
- package/lib/es/components/statsWidget/StatsWidget.d.ts +2 -2
- package/lib/es/components/statsWidget/StatsWidgets.d.ts +2 -2
- package/lib/es/components/svgImage/SvgElement.d.ts +8 -0
- package/lib/es/components/svgImage/SvgElement.js +14 -0
- package/lib/es/components/svgImage/SvgImage.d.ts +30 -0
- package/lib/es/components/svgImage/SvgImage.js +23 -0
- package/lib/es/components/svgImage/svgConverter.d.ts +17 -0
- package/lib/es/components/svgImage/svgConverter.js +84 -0
- package/lib/es/components/svgImage/useSvgLoader.d.ts +9 -0
- package/lib/es/components/svgImage/useSvgLoader.js +48 -0
- package/lib/es/components/switch/Switch.d.ts +4 -0
- package/lib/es/components/switch/Switch.js +5 -6
- package/lib/es/components/table/TableCardsSorting.d.ts +0 -1
- package/lib/es/components/table/TableCol.d.ts +18 -0
- package/lib/es/components/table/TableCol.js +13 -0
- package/lib/es/components/table/TableHead.d.ts +33 -0
- package/lib/es/components/table/TableHead.js +14 -0
- package/lib/es/components/table/TableSettingsDialog.js +1 -1
- package/lib/es/components/tag/Tag.js +1 -1
- package/lib/es/components/timepicker/TimePicker.d.ts +1 -2
- package/lib/es/components/timepicker/TimePicker.js +35 -8
- package/lib/es/components/tooltip/SimpleTooltip.d.ts +1 -1
- package/lib/es/components/virtualList/VirtualList.js +1 -1
- package/lib/es/hooks/useIsFocusWithin.d.ts +33 -0
- package/lib/es/hooks/useIsFocusWithin.js +57 -0
- package/lib/es/hooks/useLocationSuggestions.d.ts +27 -0
- package/lib/es/hooks/useLocationSuggestions.js +97 -0
- package/lib/es/hooks/useOnboarding.d.ts +17 -5
- package/lib/es/hooks/useOnboarding.js +7 -1
- package/lib/es/hooks/usePostMessage.js +0 -1
- package/lib/es/hooks/useSearch.d.ts +63 -0
- package/lib/es/hooks/useSearch.js +75 -0
- package/lib/es/hooks/useSorting.d.ts +6 -0
- package/lib/es/hooks/useSorting.js +7 -4
- package/lib/es/hooks/useTableExport.d.ts +49 -0
- package/lib/es/hooks/useTableExport.js +59 -0
- package/lib/es/hooks/useTableSelection.d.ts +166 -0
- package/lib/es/hooks/useTableSelection.js +210 -0
- package/lib/es/themes/Volkswagen/components/applicationHeader/VolkswagenApplicationHeader.js +1 -1
- package/lib/es/useIsFocusWithin.d.ts +2 -0
- package/lib/es/useIsFocusWithin.js +7 -0
- package/lib/es/useLocationSuggestions.d.ts +2 -0
- package/lib/es/useLocationSuggestions.js +7 -0
- package/lib/es/useSearch.d.ts +2 -0
- package/lib/es/useSearch.js +7 -0
- package/lib/es/useTableExport.d.ts +2 -0
- package/lib/es/useTableExport.js +7 -0
- package/lib/es/useTableSelection.d.ts +2 -0
- package/lib/es/useTableSelection.js +7 -0
- package/lib/es/utils/storageUtils.d.ts +2 -2
- package/lib/es/utils/storageUtils.js +2 -0
- package/lib/es/utils/urlFeatureToggles.d.ts +12 -6
- package/lib/es/utils/urlFeatureToggles.js +14 -8
- package/lib/es/utils/useDropDirection.js +1 -0
- package/lib/es/version.json +1 -1
- package/package.json +48 -40
- package/themes/Volkswagen/components/applicationHeader/VolkswagenApplicationHeader.js +1 -1
- package/useIsFocusWithin.d.ts +2 -0
- package/useIsFocusWithin.js +2 -0
- package/useLocationSuggestions.d.ts +2 -0
- package/useLocationSuggestions.js +2 -0
- package/useSearch.d.ts +2 -0
- package/useSearch.js +2 -0
- package/useTableExport.d.ts +2 -0
- package/useTableExport.js +2 -0
- package/useTableSelection.d.ts +2 -0
- package/useTableSelection.js +2 -0
- package/utils/storageUtils.d.ts +2 -2
- package/utils/storageUtils.js +2 -0
- package/utils/urlFeatureToggles.d.ts +12 -6
- package/utils/urlFeatureToggles.js +10 -7
- package/utils/useDropDirection.js +1 -0
- package/version.json +1 -1
package/BarList.d.ts
ADDED
package/BarList.js
ADDED
package/README.md
CHANGED
|
@@ -4,6 +4,10 @@
|
|
|
4
4
|
|
|
5
5
|
The documentation and how to integrate the UIKIT in your project can be found here: https://uikit.developers.rio.cloud/
|
|
6
6
|
|
|
7
|
+
## Changelog
|
|
8
|
+
|
|
9
|
+
All changes, updates, and improvements for each version are documented in the changelog (https://uikit.developers.rio.cloud/#start/changelog). Refer to it for a detailed overview of new features, bug fixes, and other modifications.
|
|
10
|
+
|
|
7
11
|
## Release
|
|
8
12
|
|
|
9
13
|
Starting with version `0.12.8`, all versions of the uikit will be available under https://uikit.developers.rio.cloud/${VERSION}/.
|
package/SvgImage.d.ts
ADDED
package/SvgImage.js
ADDED
package/TableCol.d.ts
ADDED
package/TableCol.js
ADDED
package/TableHead.d.ts
ADDED
package/TableHead.js
ADDED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
//
|
|
2
|
+
// biome-ignore lint/style/useImportType: required for JSX runtime compatibility with older toolchains
|
|
3
3
|
import { forwardRef } from 'react';
|
|
4
4
|
import classNames from 'classnames';
|
|
5
5
|
const ActionBarItemIcon = forwardRef((props, ref) => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
//
|
|
2
|
+
// biome-ignore lint/style/useImportType: required for JSX runtime compatibility with older toolchains
|
|
3
3
|
import { forwardRef } from 'react';
|
|
4
4
|
import classNames from 'classnames';
|
|
5
5
|
import noop from 'lodash/fp/noop';
|
|
@@ -7,13 +7,13 @@ declare const STATUS_MAP: {
|
|
|
7
7
|
readonly RESTING: "resting";
|
|
8
8
|
readonly WORKING: "working";
|
|
9
9
|
};
|
|
10
|
-
type ActivityStatus = ObjectValues<typeof STATUS_MAP>;
|
|
10
|
+
export type ActivityStatus = ObjectValues<typeof STATUS_MAP>;
|
|
11
11
|
declare const SIZE_MAP: {
|
|
12
12
|
readonly SIZE_SM: "sm";
|
|
13
13
|
readonly SIZE_LG: "lg";
|
|
14
14
|
readonly SIZE_XL: "xl";
|
|
15
15
|
};
|
|
16
|
-
type ActivitySize = ObjectValues<typeof SIZE_MAP>;
|
|
16
|
+
export type ActivitySize = ObjectValues<typeof SIZE_MAP>;
|
|
17
17
|
export type ActivityProps = {
|
|
18
18
|
/**
|
|
19
19
|
* Defines the type of activity.
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
// biome-ignore lint/style/useImportType: required for JSX runtime compatibility with older toolchains
|
|
2
3
|
import { forwardRef } from 'react';
|
|
3
4
|
import isEmpty from 'lodash/fp/isEmpty';
|
|
4
5
|
const CollapsedNavItem = forwardRef((props, ref) => {
|
|
@@ -150,6 +150,14 @@ export type TreeProps = {
|
|
|
150
150
|
* @default false
|
|
151
151
|
*/
|
|
152
152
|
hideSummary?: boolean;
|
|
153
|
+
/**
|
|
154
|
+
* Callback triggered when the built-in asset type filter changes.
|
|
155
|
+
* This is only available when the default summary is used.
|
|
156
|
+
*
|
|
157
|
+
* @param type
|
|
158
|
+
* @returns
|
|
159
|
+
*/
|
|
160
|
+
onTypeFilterChange?: (currentTypes: string[]) => void;
|
|
153
161
|
/**
|
|
154
162
|
* Defines whether the entire area below the search field is shown or not. Note: Disabling the
|
|
155
163
|
* tree head will hide the select all checkbox and the tree options as well as the tree summary.
|
|
@@ -192,6 +200,18 @@ export type TreeProps = {
|
|
|
192
200
|
* @default false
|
|
193
201
|
*/
|
|
194
202
|
disableAnimation?: boolean;
|
|
203
|
+
/**
|
|
204
|
+
* The number of items (including groups and children) used for virtualizing the tree.
|
|
205
|
+
*
|
|
206
|
+
* @default 50
|
|
207
|
+
*/
|
|
208
|
+
virtualizeThreshold?: number;
|
|
209
|
+
/**
|
|
210
|
+
* The number of items rendered beyond the visible area of a virtualized tree.
|
|
211
|
+
*
|
|
212
|
+
* @default 5
|
|
213
|
+
*/
|
|
214
|
+
overscan?: number;
|
|
195
215
|
/**
|
|
196
216
|
* Additional classes added to the wrapping element.
|
|
197
217
|
*/
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
/* eslint-disable no-use-before-define */
|
|
3
|
-
import React, { useEffect, useReducer, useRef
|
|
3
|
+
import React, { useCallback, useEffect, useReducer, useRef } from 'react';
|
|
4
4
|
import classNames from 'classnames';
|
|
5
5
|
import isNil from 'lodash/fp/isNil';
|
|
6
6
|
import isEmpty from 'lodash/fp/isEmpty';
|
|
@@ -27,6 +27,11 @@ import TreeRoot from './TreeRoot';
|
|
|
27
27
|
import TypeCounter from './TypeCounter';
|
|
28
28
|
import { containsItemById, debounceFn, filterAssetByType, filterEmptyGroups, filterOutByItemId, getTypeCounts, getFlatItems, getListIds, notEmpty, notEqual, excludeFromList, getMappedItemsToGroups, sortGroupItemsByName, sortGroupsByName, addOrRemoveFromList, } from './treeUtils';
|
|
29
29
|
import { treeReducer, assetCounted, allCheckedChanged, visibleTypeCountersChanged, searchValueChanged, flatItemsChanged, emptyGroupsChanged, groupedItemsChanged, typeFilterChanged, } from './treeReducer';
|
|
30
|
+
import { useTreeVirtualization } from './useTreeVirtualization';
|
|
31
|
+
import { useTreeExpansion } from './useTreeExpansion';
|
|
32
|
+
import { useTreeHeight } from './useTreeHeight';
|
|
33
|
+
import { useTreeScrollPosition } from './useTreeScrollPosition';
|
|
34
|
+
import SmoothScrollbars from '../../SmoothScrollbars';
|
|
30
35
|
export { getTypeCounts, getSubTypeCounts } from './treeUtils';
|
|
31
36
|
const filterProps = omit([
|
|
32
37
|
'expandedGroups',
|
|
@@ -36,8 +41,10 @@ const filterProps = omit([
|
|
|
36
41
|
'treeOptions',
|
|
37
42
|
]);
|
|
38
43
|
const customCompare = (prevProps, nextProps) => isEqual(filterProps(prevProps), filterProps(nextProps));
|
|
44
|
+
const VIRTUALIZED_THRESHOLD = 50;
|
|
45
|
+
const DEFAULT_VIRTUALIZED_OVERSCAN = 5;
|
|
39
46
|
const Tree = React.memo((props) => {
|
|
40
|
-
const { groups = [], items = [], selectedGroups = [], selectedItems = [], onSelectionChange = noop, hasMultiselect = true, showRadioButtons = false, hideSearch = false, hideTreeHead, treeHeaderContent, summary, hideSummary = false, search, searchPlaceholder = 'Type here to filter by name', onSearchChange = noop, className, scrollHeight, expandedGroups, onExpandGroupsChange = noop, showEmptyGroups = true, treeOptions = [], treeOptionsTooltip, disableAnimation = false, ...remainingProps } = props;
|
|
47
|
+
const { groups = [], items = [], selectedGroups = [], selectedItems = [], onSelectionChange = noop, hasMultiselect = true, showRadioButtons = false, hideSearch = false, hideTreeHead, treeHeaderContent, summary, hideSummary = false, search, searchPlaceholder = 'Type here to filter by name', onSearchChange = noop, className, scrollHeight, expandedGroups, onExpandGroupsChange = noop, showEmptyGroups = true, treeOptions = [], treeOptionsTooltip, disableAnimation = false, onTypeFilterChange = noop, virtualizeThreshold = VIRTUALIZED_THRESHOLD, overscan = DEFAULT_VIRTUALIZED_OVERSCAN, ...remainingProps } = props;
|
|
41
48
|
const [state, dispatch] = useReducer(treeReducer, {
|
|
42
49
|
groupedItems: [],
|
|
43
50
|
flatItems: [],
|
|
@@ -52,7 +59,26 @@ const Tree = React.memo((props) => {
|
|
|
52
59
|
const previousItems = useRef();
|
|
53
60
|
const previousGroups = useRef();
|
|
54
61
|
const previousSearchValue = useRef('');
|
|
55
|
-
const internalExpandedGroups =
|
|
62
|
+
const { internalExpandedGroups, handleToggleNode } = useTreeExpansion(props.expandedGroups, props.onExpandGroupsChange);
|
|
63
|
+
const hasGroups = () => groups && notEmpty(groups);
|
|
64
|
+
const hasInternalSearchValue = () => notEmpty(state.searchValue);
|
|
65
|
+
const hasSearchAndGroups = () => hasInternalSearchValue() && hasGroups();
|
|
66
|
+
const hasNoSearchAndGroups = () => !hasInternalSearchValue() && hasGroups();
|
|
67
|
+
const scrollElementRef = useRef(null);
|
|
68
|
+
const { virtualizedItems, virtualizer } = useTreeVirtualization(state.groupedItems, state.flatItems, hasInternalSearchValue(), hasGroups(), internalExpandedGroups, scrollElementRef, overscan);
|
|
69
|
+
const { scrollToTop } = useTreeScrollPosition(virtualizer, scrollElementRef);
|
|
70
|
+
// Enhance the handleToggleNode function
|
|
71
|
+
const enhancedHandleToggleNode = useCallback((nodeId) => {
|
|
72
|
+
// Execute the original toggle logic
|
|
73
|
+
handleToggleNode(nodeId);
|
|
74
|
+
}, [handleToggleNode]);
|
|
75
|
+
// Create a callback for scroll events that works with the virtualizer
|
|
76
|
+
const handleVirtualizedScroll = useCallback((event) => {
|
|
77
|
+
if (virtualizer && event?.target) {
|
|
78
|
+
const scrollElement = event.target;
|
|
79
|
+
virtualizer.scrollToOffset(scrollElement.scrollTop, { align: 'start' });
|
|
80
|
+
}
|
|
81
|
+
}, [virtualizer]);
|
|
56
82
|
useEffect(() => {
|
|
57
83
|
// Update Tree when items or groups have changed
|
|
58
84
|
if (notEqual(previousItems.current, items) || notEqual(previousGroups.current, groups)) {
|
|
@@ -79,12 +105,6 @@ const Tree = React.memo((props) => {
|
|
|
79
105
|
useEffect(() => makeTree(groups, items), [state.typeFilter]);
|
|
80
106
|
// Update tree when empty groups are toggled from outside
|
|
81
107
|
useEffect(() => makeTree(groups, items), [showEmptyGroups]);
|
|
82
|
-
// Update expanded groups from outside
|
|
83
|
-
const [previousExpandedGroups, setPreviousExpandedGroups] = useState(expandedGroups);
|
|
84
|
-
if (!isEqual(expandedGroups, previousExpandedGroups)) {
|
|
85
|
-
internalExpandedGroups.current = expandedGroups;
|
|
86
|
-
setPreviousExpandedGroups(expandedGroups);
|
|
87
|
-
}
|
|
88
108
|
// Update "select all" state from outside when groups are selected outside programmatically
|
|
89
109
|
// without using the "select all" checkbox
|
|
90
110
|
useEffect(() => {
|
|
@@ -115,28 +135,6 @@ const Tree = React.memo((props) => {
|
|
|
115
135
|
const unselectedItems = updatedItems.filter(filterOutByItemId(updatedSelectedItems));
|
|
116
136
|
return isEmpty(unselectedItems);
|
|
117
137
|
};
|
|
118
|
-
const handleToggleNode = (nodeId) => {
|
|
119
|
-
const nodeContainer = getNodeContainerDomElementById(nodeId);
|
|
120
|
-
if (!internalExpandedGroups?.current || !nodeContainer) {
|
|
121
|
-
return;
|
|
122
|
-
}
|
|
123
|
-
const openGroups = internalExpandedGroups.current;
|
|
124
|
-
const newExpandedNodes = openGroups.includes(nodeId)
|
|
125
|
-
? openGroups.filter(item => item !== nodeId)
|
|
126
|
-
: [...openGroups, nodeId];
|
|
127
|
-
// Performance improvement to skip on render cycle and change "open" class directly
|
|
128
|
-
if (openGroups.includes(nodeId)) {
|
|
129
|
-
nodeContainer.classList.remove('open');
|
|
130
|
-
}
|
|
131
|
-
else {
|
|
132
|
-
nodeContainer.classList.add('open');
|
|
133
|
-
}
|
|
134
|
-
internalExpandedGroups.current = newExpandedNodes;
|
|
135
|
-
onExpandGroupsChange(newExpandedNodes);
|
|
136
|
-
};
|
|
137
|
-
const getNodeContainerDomElementById = (nodeId) => {
|
|
138
|
-
return treeRef?.current?.querySelector(`.TreeNodeContainer[data-id="${nodeId}"]`);
|
|
139
|
-
};
|
|
140
138
|
const selectAllSearchResultItems = (shouldSelect) => selectAllFlatItems(shouldSelect);
|
|
141
139
|
const handleSelectAll = (shouldSelect, isStateIndeterminate) => {
|
|
142
140
|
const shouldSelectAll = shouldSelect && !isStateIndeterminate;
|
|
@@ -178,10 +176,13 @@ const Tree = React.memo((props) => {
|
|
|
178
176
|
const handleSearchChange = (updatedSearchValue) => {
|
|
179
177
|
onSearchChange(updatedSearchValue);
|
|
180
178
|
dispatch(searchValueChanged(updatedSearchValue));
|
|
179
|
+
if (virtualizer) {
|
|
180
|
+
// Every time search changes or is cleared, scroll to the top
|
|
181
|
+
setTimeout(() => {
|
|
182
|
+
scrollToTop();
|
|
183
|
+
}, 10);
|
|
184
|
+
}
|
|
181
185
|
};
|
|
182
|
-
const hasGroups = () => groups && notEmpty(groups);
|
|
183
|
-
const hasSearchAndGroups = () => hasInternalSearchValue() && hasGroups();
|
|
184
|
-
const hasNoSearchAndGroups = () => !hasInternalSearchValue() && hasGroups();
|
|
185
186
|
const setFlatItemList = (updatedItems, searchValue) => {
|
|
186
187
|
const flatItems = getFlatItems(updatedItems, searchValue);
|
|
187
188
|
dispatch(flatItemsChanged(flatItems));
|
|
@@ -218,30 +219,64 @@ const Tree = React.memo((props) => {
|
|
|
218
219
|
[otherwise, setFlatItems],
|
|
219
220
|
])();
|
|
220
221
|
};
|
|
222
|
+
const containerHeight = useTreeHeight(treeRef, scrollHeight);
|
|
223
|
+
const renderVirtualizedTree = () => {
|
|
224
|
+
const items = virtualizer.getVirtualItems();
|
|
225
|
+
const isGroupedList = hasGroups() && !hasInternalSearchValue();
|
|
226
|
+
return (_jsx(SmoothScrollbars, { ref: scrollElementRef, className: 'tree-virtual-scrollbar', onScroll: handleVirtualizedScroll, autoHeight: false, slideIn: true, style: {
|
|
227
|
+
height: `${containerHeight}px`,
|
|
228
|
+
}, children: _jsx("div", { className: isGroupedList ? 'grouped-list' : 'flat-list', style: {
|
|
229
|
+
height: `${virtualizer.getTotalSize()}px`,
|
|
230
|
+
position: 'relative',
|
|
231
|
+
}, children: items.map(virtualItem => {
|
|
232
|
+
const item = virtualizedItems[virtualItem.index];
|
|
233
|
+
if (!item) {
|
|
234
|
+
return null;
|
|
235
|
+
}
|
|
236
|
+
const isGroupSelected = selectedGroups.includes(item.id) ||
|
|
237
|
+
(item.type === 'leaf' && selectedGroups.includes(item.groupId));
|
|
238
|
+
return (_jsx("div", { "data-index": virtualItem.index, ref: virtualizer.measureElement, className: `virtualized-tree-item ${item.type === 'group' ? 'group-item' : 'leaf-item'} ${isGroupSelected ? 'checked' : ''}`, style: {
|
|
239
|
+
position: 'absolute',
|
|
240
|
+
top: 0,
|
|
241
|
+
left: 0,
|
|
242
|
+
width: '100%',
|
|
243
|
+
height: `${virtualItem.size}px`,
|
|
244
|
+
transform: `translateY(${virtualItem.start}px)`,
|
|
245
|
+
}, children: item.type === 'group' ? (_jsx(TreeNodeContainer, { groupId: item.id, isOpen: item.isExpanded, disableAnimation: disableAnimation, children: _jsx(TreeNode, { node: item.data, hasMultiselect: hasMultiselect, onToggleNode: enhancedHandleToggleNode, onSelect: handleGroupSelection, isSelected: isGroupSelected, isIndeterminate: !isGroupSelected &&
|
|
246
|
+
item.data.items.some(groupItem => selectedItems.includes(groupItem.id)) }) }, item.id)) : (
|
|
247
|
+
// Render individual leaf item with proper styling
|
|
248
|
+
_jsx(TreeNodeContainer, { isOpen: true, disableAnimation: disableAnimation, children: _jsx(TreeLeafList, { leafList: [item.data], hasMultiselect: hasMultiselect, showRadioButtons: showRadioButtons, selectedItems: selectedItems, selectedGroups: selectedGroups, onSelectionChange: respondSelection }) }, item.id)) }, `${item.type}-${item.id}-${virtualItem.index}`));
|
|
249
|
+
}) }) }));
|
|
250
|
+
};
|
|
221
251
|
const renderTree = () => {
|
|
222
252
|
const { groupedItems } = state;
|
|
223
253
|
if (isEmpty(groupedItems)) {
|
|
224
254
|
return _jsx(TreeNothingFound, {});
|
|
225
255
|
}
|
|
256
|
+
if (virtualizedItems.length > virtualizeThreshold) {
|
|
257
|
+
return renderVirtualizedTree();
|
|
258
|
+
}
|
|
226
259
|
const result = map((group) => {
|
|
227
260
|
const groupId = group.id;
|
|
228
261
|
const groupItems = group.items;
|
|
229
|
-
const isOpen = internalExpandedGroups
|
|
262
|
+
const isOpen = internalExpandedGroups?.includes(groupId) ?? false;
|
|
230
263
|
const numSelectedGroupItems = filter(containsItemById(selectedItems))(groupItems).length;
|
|
231
264
|
const isGroupSelected = selectedGroups.includes(groupId);
|
|
232
265
|
const isStateIndeterminate = !isGroupSelected && numSelectedGroupItems > 0;
|
|
233
|
-
return (_jsxs(TreeNodeContainer, { groupId: groupId, isOpen: isOpen, disableAnimation: disableAnimation, children: [_jsx(TreeNode, { node: group, hasMultiselect: hasMultiselect, onToggleNode: handleToggleNode, onSelect: handleGroupSelection, isSelected: isGroupSelected, isIndeterminate: isStateIndeterminate }), _jsx(TreeLeafList, { leafList: groupItems, hasMultiselect: hasMultiselect, showRadioButtons: showRadioButtons, selectedItems: selectedItems, selectedGroups: selectedGroups, onSelectionChange: respondSelection })] }, groupId));
|
|
266
|
+
return (_jsxs(TreeNodeContainer, { groupId: groupId, isOpen: isOpen, disableAnimation: disableAnimation, children: [_jsx(TreeNode, { node: group, hasMultiselect: hasMultiselect, onToggleNode: handleToggleNode, onSelect: handleGroupSelection, isSelected: isGroupSelected, isIndeterminate: isStateIndeterminate }), isOpen && (_jsx(TreeLeafList, { leafList: groupItems, hasMultiselect: hasMultiselect, showRadioButtons: showRadioButtons, selectedItems: selectedItems, selectedGroups: selectedGroups, onSelectionChange: respondSelection }))] }, groupId));
|
|
234
267
|
})(groupedItems);
|
|
235
268
|
return result;
|
|
236
269
|
};
|
|
237
270
|
const renderFlatList = () => {
|
|
238
271
|
const { flatItems } = state;
|
|
239
272
|
const hasLeafs = isEmpty(flatItems);
|
|
273
|
+
if (virtualizedItems.length > virtualizeThreshold) {
|
|
274
|
+
return renderVirtualizedTree();
|
|
275
|
+
}
|
|
240
276
|
const getLeafs = () => (_jsx(TreeLeafList, { leafList: flatItems, hasMultiselect: hasMultiselect, showRadioButtons: showRadioButtons, selectedItems: selectedItems, selectedGroups: selectedGroups, onSelectionChange: respondSelection }));
|
|
241
277
|
return (_jsx(TreeNodeContainer, { disableAnimation: disableAnimation, isOpen: true, children: hasLeafs ? _jsx(TreeNothingFound, {}) : getLeafs() }));
|
|
242
278
|
};
|
|
243
279
|
const hasExternalGroups = notEmpty(groups);
|
|
244
|
-
const hasInternalSearchValue = () => notEmpty(state.searchValue);
|
|
245
280
|
const hasSelectedAllItems = () => isEqual(size(selectedItems), size(state.flatItems));
|
|
246
281
|
const hasPartiallySelectedItems = () => notEmpty(selectedItems) && !hasSelectedAllItems();
|
|
247
282
|
const hasSelectedAllGroups = () => {
|
|
@@ -261,7 +296,9 @@ const Tree = React.memo((props) => {
|
|
|
261
296
|
[otherwise, () => renderFlatList()],
|
|
262
297
|
])();
|
|
263
298
|
const handleFilterByType = (type) => {
|
|
264
|
-
|
|
299
|
+
const updatedTypeFilter = addOrRemoveFromList(state.typeFilter, type);
|
|
300
|
+
dispatch(typeFilterChanged(updatedTypeFilter));
|
|
301
|
+
onTypeFilterChange(updatedTypeFilter);
|
|
265
302
|
};
|
|
266
303
|
const enableActivity = size(state.visibleTypeCounters) !== 1;
|
|
267
304
|
const isFilterActive = notEmpty(state.typeFilter);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
//
|
|
2
|
+
// biome-ignore lint/style/useImportType: required for JSX runtime compatibility with older toolchains
|
|
3
3
|
import React from 'react';
|
|
4
4
|
import classNames from 'classnames';
|
|
5
5
|
import isObject from 'lodash/fp/isObject';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
//
|
|
2
|
+
// biome-ignore lint/style/useImportType: required for JSX runtime compatibility with older toolchains
|
|
3
3
|
import React from 'react';
|
|
4
4
|
import classNames from 'classnames';
|
|
5
5
|
import noop from 'lodash/fp/noop';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
//
|
|
2
|
+
// biome-ignore lint/style/useImportType: required for JSX runtime compatibility with older toolchains
|
|
3
3
|
import React from 'react';
|
|
4
4
|
import classNames from 'classnames';
|
|
5
5
|
import TypeCounter from './TypeCounter';
|
|
@@ -33,6 +33,8 @@ export type TypeCounterProps = {
|
|
|
33
33
|
hideOnZero?: boolean;
|
|
34
34
|
/**
|
|
35
35
|
* Callback function when the counter is clicked. It returns the type value.
|
|
36
|
+
* Make sure the "type" prop is defined to receive the value in the callback.
|
|
37
|
+
*
|
|
36
38
|
* @param type
|
|
37
39
|
* @returns
|
|
38
40
|
*/
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
//
|
|
2
|
+
// biome-ignore lint/style/useImportType: required for JSX runtime compatibility with older toolchains
|
|
3
3
|
import { forwardRef, useRef } from 'react';
|
|
4
4
|
import classNames from 'classnames';
|
|
5
5
|
import noop from 'lodash/fp/noop';
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { useState } from 'react';
|
|
2
|
+
import { isEqual } from 'lodash/fp';
|
|
3
|
+
export const useTreeExpansion = (expandedGroups, onExpandGroupsChange) => {
|
|
4
|
+
const [internalExpandedGroups, setInternalExpandedGroups] = useState(expandedGroups);
|
|
5
|
+
const [previousExpandedGroups, setPreviousExpandedGroups] = useState(expandedGroups);
|
|
6
|
+
// Sync with external prop changes and update expanded groups from outside in case
|
|
7
|
+
if (!isEqual(expandedGroups, previousExpandedGroups)) {
|
|
8
|
+
setInternalExpandedGroups(expandedGroups);
|
|
9
|
+
setPreviousExpandedGroups(expandedGroups);
|
|
10
|
+
}
|
|
11
|
+
const handleToggleNode = (nodeId) => {
|
|
12
|
+
if (!internalExpandedGroups) {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
const newExpandedNodes = internalExpandedGroups.includes(nodeId)
|
|
16
|
+
? internalExpandedGroups.filter(item => item !== nodeId)
|
|
17
|
+
: [...internalExpandedGroups, nodeId];
|
|
18
|
+
setInternalExpandedGroups(newExpandedNodes);
|
|
19
|
+
onExpandGroupsChange?.(newExpandedNodes);
|
|
20
|
+
};
|
|
21
|
+
return {
|
|
22
|
+
internalExpandedGroups,
|
|
23
|
+
handleToggleNode,
|
|
24
|
+
};
|
|
25
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const useTreeHeight: (treeRef: React.RefObject<HTMLDivElement>, scrollHeight?: number) => number;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { useEffect, useState } from 'react';
|
|
2
|
+
const DEFAULT_TREE_ROOT_HEIGHT = 300;
|
|
3
|
+
export const useTreeHeight = (treeRef, scrollHeight) => {
|
|
4
|
+
const [containerHeight, setContainerHeight] = useState(350);
|
|
5
|
+
// Enhanced height calculation with multiple fallback strategies
|
|
6
|
+
useEffect(() => {
|
|
7
|
+
const calculateHeight = () => {
|
|
8
|
+
if (!treeRef.current) {
|
|
9
|
+
return DEFAULT_TREE_ROOT_HEIGHT;
|
|
10
|
+
}
|
|
11
|
+
const parentElement = treeRef.current;
|
|
12
|
+
const treeHeaderElement = parentElement.querySelector('.TreeHeader');
|
|
13
|
+
if (scrollHeight) {
|
|
14
|
+
// Use scrollHeight prop if provided
|
|
15
|
+
return scrollHeight;
|
|
16
|
+
}
|
|
17
|
+
const treeRoot = treeRef.current.querySelector('.TreeRoot');
|
|
18
|
+
return treeRoot?.clientHeight ?? DEFAULT_TREE_ROOT_HEIGHT;
|
|
19
|
+
};
|
|
20
|
+
const updateHeight = () => {
|
|
21
|
+
const newHeight = calculateHeight();
|
|
22
|
+
setContainerHeight(newHeight);
|
|
23
|
+
};
|
|
24
|
+
// Debounce height updates to avoid excessive recalculations
|
|
25
|
+
let timeoutId;
|
|
26
|
+
const debouncedUpdate = () => {
|
|
27
|
+
clearTimeout(timeoutId);
|
|
28
|
+
timeoutId = setTimeout(updateHeight, 16); // ~60fps
|
|
29
|
+
};
|
|
30
|
+
// Initial calculation with small delay to ensure DOM is ready
|
|
31
|
+
const initialTimeout = setTimeout(updateHeight, 50);
|
|
32
|
+
// Set up observers
|
|
33
|
+
const resizeObserver = new ResizeObserver(debouncedUpdate);
|
|
34
|
+
const mutationObserver = new MutationObserver(debouncedUpdate);
|
|
35
|
+
if (treeRef.current) {
|
|
36
|
+
// Watch parent for size changes
|
|
37
|
+
resizeObserver.observe(treeRef.current);
|
|
38
|
+
if (treeRef.current.parentElement) {
|
|
39
|
+
resizeObserver.observe(treeRef.current.parentElement);
|
|
40
|
+
}
|
|
41
|
+
// Watch for DOM changes that might affect layout
|
|
42
|
+
mutationObserver.observe(treeRef.current, {
|
|
43
|
+
childList: true,
|
|
44
|
+
subtree: true,
|
|
45
|
+
attributes: true,
|
|
46
|
+
attributeFilter: ['style', 'class'],
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
// Window resize listener
|
|
50
|
+
window.addEventListener('resize', debouncedUpdate);
|
|
51
|
+
return () => {
|
|
52
|
+
clearTimeout(initialTimeout);
|
|
53
|
+
clearTimeout(timeoutId);
|
|
54
|
+
resizeObserver.disconnect();
|
|
55
|
+
mutationObserver.disconnect();
|
|
56
|
+
window.removeEventListener('resize', debouncedUpdate);
|
|
57
|
+
};
|
|
58
|
+
}, [scrollHeight, treeRef]); // Re-run if scrollHeight prop changes or treeRef changes
|
|
59
|
+
return containerHeight;
|
|
60
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { useCallback, useRef } from 'react';
|
|
2
|
+
export const useTreeScrollPosition = (virtualizer, scrollElementRef) => {
|
|
3
|
+
const scrollOffsetRef = useRef(0);
|
|
4
|
+
const scrollToTop = useCallback(() => {
|
|
5
|
+
if (scrollElementRef.current) {
|
|
6
|
+
requestAnimationFrame(() => {
|
|
7
|
+
// Reset scroll position to top
|
|
8
|
+
scrollElementRef.current.scrollTop(0);
|
|
9
|
+
// Also reset the stored scroll offset
|
|
10
|
+
scrollOffsetRef.current = 0;
|
|
11
|
+
// Force virtualizer to sync
|
|
12
|
+
if (virtualizer) {
|
|
13
|
+
virtualizer.scrollToOffset(0);
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
}, [scrollElementRef, virtualizer]);
|
|
18
|
+
return { scrollToTop };
|
|
19
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { TreeItem, GroupedItem } from './Tree';
|
|
2
|
+
type VirtualizedItem = {
|
|
3
|
+
type: 'group';
|
|
4
|
+
data: GroupedItem;
|
|
5
|
+
id: string;
|
|
6
|
+
isExpanded: boolean;
|
|
7
|
+
} | {
|
|
8
|
+
type: 'leaf';
|
|
9
|
+
data: TreeItem;
|
|
10
|
+
id: string;
|
|
11
|
+
groupId: string;
|
|
12
|
+
};
|
|
13
|
+
export declare const useTreeVirtualization: (groupedItems: GroupedItem[], flatItems: TreeItem[], hasSearchValue: boolean, hasGroups: boolean, internalExpandedGroups: string[] | undefined, scrollElementRef: React.RefObject<HTMLDivElement>, overscan: number) => {
|
|
14
|
+
virtualizedItems: VirtualizedItem[];
|
|
15
|
+
virtualizer: import("@tanstack/virtual-core").Virtualizer<any, Element>;
|
|
16
|
+
};
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { useMemo } from 'react';
|
|
2
|
+
import map from 'lodash/fp/map';
|
|
3
|
+
import { useVirtualizer } from '@tanstack/react-virtual';
|
|
4
|
+
export const useTreeVirtualization = (groupedItems, flatItems, hasSearchValue, hasGroups, internalExpandedGroups, scrollElementRef, overscan) => {
|
|
5
|
+
const virtualizedItems = useMemo(() => {
|
|
6
|
+
// When there's a search value, always show flat items (no groups)
|
|
7
|
+
if (hasSearchValue) {
|
|
8
|
+
return flatItems.map((item) => ({
|
|
9
|
+
type: 'leaf',
|
|
10
|
+
data: item,
|
|
11
|
+
id: item.id,
|
|
12
|
+
}));
|
|
13
|
+
}
|
|
14
|
+
// Virtualize grouped list, when there's no search value and we have groups
|
|
15
|
+
if (hasGroups) {
|
|
16
|
+
const flatList = [];
|
|
17
|
+
map((group) => {
|
|
18
|
+
const isExpanded = internalExpandedGroups?.includes(group.id) ?? false;
|
|
19
|
+
// Add the group header
|
|
20
|
+
flatList.push({
|
|
21
|
+
type: 'group',
|
|
22
|
+
data: group,
|
|
23
|
+
id: group.id,
|
|
24
|
+
isExpanded,
|
|
25
|
+
});
|
|
26
|
+
// Add expanded items
|
|
27
|
+
if (isExpanded) {
|
|
28
|
+
group.items.forEach((item) => {
|
|
29
|
+
flatList.push({
|
|
30
|
+
type: 'leaf',
|
|
31
|
+
data: item,
|
|
32
|
+
id: item.id,
|
|
33
|
+
groupId: group.id,
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
})(groupedItems);
|
|
38
|
+
return flatList;
|
|
39
|
+
}
|
|
40
|
+
// Virtualize flat list when no groups are provided initially
|
|
41
|
+
return flatItems.map((item) => ({
|
|
42
|
+
type: 'leaf',
|
|
43
|
+
data: item,
|
|
44
|
+
id: item.id,
|
|
45
|
+
}));
|
|
46
|
+
}, [groupedItems, flatItems, hasSearchValue, hasGroups, internalExpandedGroups]);
|
|
47
|
+
const virtualizer = useVirtualizer({
|
|
48
|
+
count: virtualizedItems.length,
|
|
49
|
+
// getScrollElement: () => scrollElementRef.current,
|
|
50
|
+
getScrollElement: () => {
|
|
51
|
+
// For SmoothScrollbars, we need to get the actual scroll container
|
|
52
|
+
if (scrollElementRef.current) {
|
|
53
|
+
// SmoothScrollbars exposes the scroll container through its view
|
|
54
|
+
const scrollbarsInstance = scrollElementRef.current;
|
|
55
|
+
// Access the internal scroll container
|
|
56
|
+
// This depends on how react-custom-scrollbars-2 exposes its internals
|
|
57
|
+
return scrollbarsInstance?.view;
|
|
58
|
+
}
|
|
59
|
+
return null;
|
|
60
|
+
},
|
|
61
|
+
estimateSize: () => 41, // typical single line height without line-break
|
|
62
|
+
measureElement: element => {
|
|
63
|
+
// This will measure the actual rendered height for more accuracy
|
|
64
|
+
return element?.children[0].clientHeight ?? 41;
|
|
65
|
+
},
|
|
66
|
+
overscan, // Render 10 extra items above and below visible area
|
|
67
|
+
// Add this to enable more aggressive remeasurement
|
|
68
|
+
lanes: 1,
|
|
69
|
+
});
|
|
70
|
+
return { virtualizedItems, virtualizer };
|
|
71
|
+
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
// biome-ignore lint/style/useImportType: <explanation>
|
|
2
3
|
import { useEffect, useRef, useState } from 'react';
|
|
3
4
|
import classNames from 'classnames';
|
|
4
5
|
import isEmpty from 'lodash/fp/isEmpty';
|
|
@@ -21,7 +22,7 @@ export const AutoSuggest = (props) => {
|
|
|
21
22
|
onClear: noop,
|
|
22
23
|
onBlur: noop,
|
|
23
24
|
onFocus: noop,
|
|
24
|
-
placeholder: 'Start typing
|
|
25
|
+
placeholder: 'Start typing',
|
|
25
26
|
hasError: false,
|
|
26
27
|
tabIndex: 0,
|
|
27
28
|
value: undefined,
|