@synerise/ds-context-selector 0.24.7 → 0.25.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/CHANGELOG.md CHANGED
@@ -3,6 +3,29 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ # [0.25.0](https://github.com/Synerise/synerise-design/compare/@synerise/ds-context-selector@0.24.8...@synerise/ds-context-selector@0.25.0) (2024-09-13)
7
+
8
+
9
+ ### Features
10
+
11
+ * **context-selector:** reset tabs on item select ([34b398a](https://github.com/Synerise/synerise-design/commit/34b398a4e5cdf948031ec1ab311acf712674b2a8))
12
+
13
+
14
+
15
+
16
+
17
+ ## [0.24.8](https://github.com/Synerise/synerise-design/compare/@synerise/ds-context-selector@0.24.7...@synerise/ds-context-selector@0.24.8) (2024-09-11)
18
+
19
+
20
+ ### Bug Fixes
21
+
22
+ * **context-selector:** updated search logic ([dfadc02](https://github.com/Synerise/synerise-design/commit/dfadc02928651905f31c58a374d48368b8375eb3))
23
+ * **factors:** make all dropdowns same fixed height ([40e86d1](https://github.com/Synerise/synerise-design/commit/40e86d183dddb925c2b75c499615c1455b93b7c4))
24
+
25
+
26
+
27
+
28
+
6
29
  ## [0.24.7](https://github.com/Synerise/synerise-design/compare/@synerise/ds-context-selector@0.24.6...@synerise/ds-context-selector@0.24.7) (2024-09-03)
7
30
 
8
31
  **Note:** Version bump only for package @synerise/ds-context-selector
@@ -1,4 +1,4 @@
1
1
  import React from 'react';
2
2
  import { ContextProps } from './ContextSelector.types';
3
- declare const ContextSelector: ({ defaultDropdownVisibility, selectedItem, onSelectItem, onSetGroup, groups, items, texts, opened, addMode, loading, customTriggerComponent, trigger, menuItemHeight, dropdownWrapperStyles, onClickOutsideEvents, onClickOutside, onSearch, hideSearchField, hasMoreItems, onFetchData, onActivate, onDeactivate, onOpen, getPopupContainerOverride, type, dropdownProps, disabled, errorText, readOnly, getMenuEntryProps, }: ContextProps) => React.JSX.Element;
3
+ declare const ContextSelector: ({ defaultDropdownVisibility, selectedItem, onSelectItem, onSetGroup, groups, items, texts, opened, addMode, loading, customTriggerComponent, trigger, menuItemHeight, dropdownWrapperStyles, onClickOutsideEvents, onClickOutside, onSearch, hideSearchField, hasMoreItems, onFetchData, onActivate, onDeactivate, onOpen, getPopupContainerOverride, type, dropdownProps, disabled, errorText, readOnly, getMenuEntryProps, dropdownDimensionsConfig, }: ContextProps) => React.JSX.Element;
4
4
  export default ContextSelector;
@@ -15,6 +15,7 @@ import InformationCard from '@synerise/ds-information-card';
15
15
  import { getPopupContainer } from '@synerise/ds-utils';
16
16
  import ContextSelectorDropdown from './ContextSelectorDropdown/ContextSelectorDropdown';
17
17
  import { ItemWrapper, ErrorWrapper } from './ContextSelector.styles';
18
+ import { DROPDOWN_HEIGHT, DROPDOWN_HEIGHT_BELOW_THRESHOLD, DROPDOWN_HEIGHT_THRESHOLD } from './constants';
18
19
 
19
20
  var ContextSelector = function ContextSelector(_ref) {
20
21
  var defaultDropdownVisibility = _ref.defaultDropdownVisibility,
@@ -49,12 +50,34 @@ var ContextSelector = function ContextSelector(_ref) {
49
50
  errorText = _ref.errorText,
50
51
  _ref$readOnly = _ref.readOnly,
51
52
  readOnly = _ref$readOnly === void 0 ? false : _ref$readOnly,
52
- getMenuEntryProps = _ref.getMenuEntryProps;
53
+ getMenuEntryProps = _ref.getMenuEntryProps,
54
+ dropdownDimensionsConfig = _ref.dropdownDimensionsConfig;
53
55
 
54
56
  var _useState = useState(defaultDropdownVisibility != null ? defaultDropdownVisibility : false),
55
57
  dropdownVisible = _useState[0],
56
58
  setDropdownVisible = _useState[1];
57
59
 
60
+ var dimensionsConfig = _objectSpread({
61
+ defaultHeight: DROPDOWN_HEIGHT,
62
+ lowerHeight: DROPDOWN_HEIGHT_BELOW_THRESHOLD,
63
+ threshold: DROPDOWN_HEIGHT_THRESHOLD
64
+ }, dropdownDimensionsConfig);
65
+
66
+ var _useState2 = useState(dimensionsConfig.defaultHeight),
67
+ outerHeight = _useState2[0],
68
+ setOuterHeight = _useState2[1];
69
+
70
+ useEffect(function () {
71
+ var checkViewportHeight = function checkViewportHeight() {
72
+ return setOuterHeight(window.innerHeight < dimensionsConfig.threshold ? dimensionsConfig.lowerHeight : dimensionsConfig.defaultHeight);
73
+ };
74
+
75
+ checkViewportHeight();
76
+ window.addEventListener('resize', checkViewportHeight);
77
+ return function () {
78
+ window.removeEventListener('resize', checkViewportHeight);
79
+ };
80
+ }, [dimensionsConfig.defaultHeight, dimensionsConfig.lowerHeight, dimensionsConfig.threshold]);
58
81
  useEffect(function () {
59
82
  setDropdownVisible(defaultDropdownVisibility != null ? defaultDropdownVisibility : false);
60
83
  }, [defaultDropdownVisibility]);
@@ -169,7 +192,8 @@ var ContextSelector = function ContextSelector(_ref) {
169
192
  onSearch: onSearch,
170
193
  hideSearchField: hideSearchField,
171
194
  hasMoreItems: hasMoreItems,
172
- onFetchData: onFetchData
195
+ onFetchData: onFetchData,
196
+ outerHeight: outerHeight
173
197
  })
174
198
  }), customTriggerComponent != null ? customTriggerComponent : triggerButton)), errorText && /*#__PURE__*/React.createElement(ErrorWrapper, null, errorText));
175
199
  };
@@ -1,8 +1,15 @@
1
+ /// <reference types="react" />
1
2
  export declare const TabsWrapper: import("styled-components").StyledComponent<"div", any, {}, never>;
2
3
  export declare const ContentPlaceholder: import("styled-components").StyledComponent<"div", any, {}, never>;
3
- export declare const ItemsList: import("styled-components").StyledComponent<"div", any, {}, never>;
4
+ export declare const ItemsList: import("styled-components").StyledComponent<"div", any, {
5
+ contentHeight?: number | undefined;
6
+ }, never>;
4
7
  export declare const SearchResult: import("styled-components").StyledComponent<"span", any, {}, never>;
5
8
  export declare const SearchResultHighlight: import("styled-components").StyledComponent<"span", any, {}, never>;
6
9
  export declare const Title: import("styled-components").StyledComponent<"div", any, {}, never>;
7
10
  export declare const ItemWrapper: import("styled-components").StyledComponent<"span", any, {}, never>;
11
+ export declare const ShowMoreItem: import("styled-components").StyledComponent<"div", any, {}, never>;
8
12
  export declare const ErrorWrapper: import("styled-components").StyledComponent<"div", any, {}, never>;
13
+ export declare const Skeleton: import("styled-components").StyledComponent<({ size, numberOfSkeletons, width, height, className }: import("@synerise/ds-skeleton").SkeletonProps) => import("react").JSX.Element, any, {
14
+ contentHeight?: number | undefined;
15
+ }, never>;
@@ -1,4 +1,5 @@
1
1
  import styled from 'styled-components';
2
+ import DropdownSkeleton from '@synerise/ds-skeleton';
2
3
  export var TabsWrapper = styled.div.withConfig({
3
4
  displayName: "ContextSelectorstyles__TabsWrapper",
4
5
  componentId: "sc-1tuu6xk-0"
@@ -10,8 +11,10 @@ export var ContentPlaceholder = styled.div.withConfig({
10
11
  export var ItemsList = styled.div.withConfig({
11
12
  displayName: "ContextSelectorstyles__ItemsList",
12
13
  componentId: "sc-1tuu6xk-2"
13
- })(["width:100%;background:", ";.ds-context-selector-list{height:auto !important;max-height:300px;}"], function (props) {
14
+ })(["width:100%;background:", ";.ds-context-selector-list{height:auto !important;max-height:300px;}", ""], function (props) {
14
15
  return props.theme.palette.white;
16
+ }, function (props) {
17
+ return props.contentHeight !== undefined && "height: " + props.contentHeight + "px;";
15
18
  });
16
19
  export var SearchResult = styled.span.withConfig({
17
20
  displayName: "ContextSelectorstyles__SearchResult",
@@ -35,9 +38,19 @@ export var ItemWrapper = styled.span.withConfig({
35
38
  displayName: "ContextSelectorstyles__ItemWrapper",
36
39
  componentId: "sc-1tuu6xk-6"
37
40
  })(["max-width:170px;overflow:hidden;text-overflow:ellipsis;"]);
41
+ export var ShowMoreItem = styled.div.withConfig({
42
+ displayName: "ContextSelectorstyles__ShowMoreItem",
43
+ componentId: "sc-1tuu6xk-7"
44
+ })(["font-weight:500;"]);
38
45
  export var ErrorWrapper = styled.div.withConfig({
39
46
  displayName: "ContextSelectorstyles__ErrorWrapper",
40
- componentId: "sc-1tuu6xk-7"
47
+ componentId: "sc-1tuu6xk-8"
41
48
  })(["color:", ";margin-top:8px;"], function (props) {
42
49
  return props.theme.palette['red-600'];
50
+ });
51
+ export var Skeleton = styled(DropdownSkeleton).withConfig({
52
+ displayName: "ContextSelectorstyles__Skeleton",
53
+ componentId: "sc-1tuu6xk-9"
54
+ })(["", ""], function (props) {
55
+ return props.contentHeight !== undefined && "height: " + props.contentHeight + "px;";
43
56
  });
@@ -1,15 +1,15 @@
1
- import { CSSProperties, ReactNode, ReactText } from 'react';
2
- import { HandledEventsType } from '@synerise/ds-utils';
3
- import { ItemSize } from '@synerise/ds-menu';
4
- import { DropdownProps } from '@synerise/ds-dropdown/dist/Dropdown';
1
+ import type { CSSProperties, ReactNode, ReactText } from 'react';
2
+ import type { HandledEventsType } from '@synerise/ds-utils';
3
+ import type { DropdownProps } from '@synerise/ds-dropdown';
5
4
  import type { FactorsProps } from '@synerise/ds-factors';
6
- import { InformationCardProps } from '@synerise/ds-information-card';
7
- import { ListItemProps } from '@synerise/ds-list-item';
5
+ import type { InformationCardProps } from '@synerise/ds-information-card';
6
+ import type { ListItemProps, ItemSize } from '@synerise/ds-list-item';
8
7
  export type ContextTexts = {
9
8
  buttonLabel: string;
10
9
  searchPlaceholder: string;
11
10
  loadingResults: string;
12
11
  noResults: string;
12
+ showMore: string;
13
13
  };
14
14
  export type ContextItem = Pick<ListItemProps, 'renderHoverTooltip' | 'hoverTooltipProps' | 'disabled'> & {
15
15
  id: ReactText | null;
@@ -71,6 +71,11 @@ export type ContextProps = {
71
71
  dropdownProps?: Omit<DropdownProps, 'trigger' | 'getPopupContainer' | 'onVisibleChange' | 'visible' | 'overlay'>;
72
72
  errorText?: ReactNode | string;
73
73
  getMenuEntryProps?: FactorsProps['getMenuEntryProps'];
74
+ dropdownDimensionsConfig?: {
75
+ defaultHeight?: number;
76
+ lowerHeight?: number;
77
+ threshold?: number;
78
+ };
74
79
  };
75
80
  export type ContextDropdownProps = {
76
81
  setDropdownVisible: (show: boolean) => void;
@@ -91,30 +96,23 @@ export type ContextDropdownProps = {
91
96
  onFetchData?: () => void;
92
97
  hasMoreItems?: boolean;
93
98
  style?: CSSProperties;
99
+ outerHeight?: number;
100
+ maxSearchResultsInGroup?: number;
94
101
  };
95
102
  export type ContextSelectorDropdownItemProps = {
96
- item: ContextItem | ContextGroup;
97
- searchQuery: string;
103
+ className: string;
98
104
  clearSearch?: () => void;
99
105
  hideDropdown?: () => void;
100
- select: (item: ContextItem | ContextGroup) => void;
101
- selected?: boolean;
102
- className: string;
103
- menuItemHeight?: ItemSize;
104
- style?: CSSProperties;
105
- };
106
- export type ListItem = {
107
- className: string;
108
106
  item: ContextItem | ContextGroup;
109
- searchQuery: string;
110
- select: (item: ContextItem | ContextGroup) => void;
111
107
  menuItemHeight?: ItemSize;
108
+ searchQuery?: string;
109
+ select: (item: ContextItem | ContextGroup) => void;
112
110
  selected?: boolean;
113
- clearSearch?: () => void;
114
- hideDropdown?: () => void;
111
+ style?: CSSProperties;
112
+ label?: ReactNode;
115
113
  };
116
114
  export type ListTitle = {
117
115
  title?: string;
118
116
  type?: string;
119
117
  };
120
- export type DropdownItemProps = ListTitle | ListItem;
118
+ export type DropdownItemProps = ListTitle | ContextSelectorDropdownItemProps;
@@ -1,4 +1,4 @@
1
- import * as React from 'react';
1
+ import React from 'react';
2
2
  import { ContextDropdownProps } from '../ContextSelector.types';
3
- declare const ContextSelectorDropdown: React.FC<ContextDropdownProps>;
3
+ declare const ContextSelectorDropdown: ({ texts, setSelected, onSetGroup, groups, items, setDropdownVisible, value, visible, hideSearchField, loading, menuItemHeight, dropdownWrapperStyles, onClickOutsideEvents, onClickOutside, onSearch, onFetchData, hasMoreItems, outerHeight, maxSearchResultsInGroup, }: ContextDropdownProps) => React.JSX.Element;
4
4
  export default ContextSelectorDropdown;
@@ -1,5 +1,3 @@
1
- var _ITEM_SIZE;
2
-
3
1
  function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
4
2
 
5
3
  function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
@@ -8,30 +6,21 @@ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { va
8
6
 
9
7
  function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
10
8
 
11
- import * as React from 'react';
9
+ import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
10
+ import { v4 as uuid } from 'uuid';
11
+ import { VariableSizeList } from 'react-window';
12
12
  import Dropdown from '@synerise/ds-dropdown';
13
- import Icon, { SearchM } from '@synerise/ds-icon';
13
+ import Icon, { ArrowRightCircleM, SearchM } from '@synerise/ds-icon';
14
14
  import Tabs from '@synerise/ds-tabs';
15
- import { focusWithArrowKeys, getClosest, useOnClickOutside } from '@synerise/ds-utils';
15
+ import { focusWithArrowKeys, getClosest, useOnClickOutside, useSearchResults, getActiveTabGroup, getGroupName } from '@synerise/ds-utils';
16
16
  import Result from '@synerise/ds-result';
17
17
  import Scrollbar from '@synerise/ds-scrollbar';
18
18
  import { theme } from '@synerise/ds-core';
19
- import { v4 as uuid } from 'uuid';
20
- import { VariableSizeList as List } from 'react-window';
21
- import { ItemSize } from '@synerise/ds-menu';
22
- import DropdownSkeleton from '@synerise/ds-skeleton';
19
+ import { itemSizes } from '@synerise/ds-list-item';
23
20
  import * as S from '../ContextSelector.styles';
24
21
  import ContextSelectorDropdownItem from './ContextSelectorDropdownItem';
25
- var NO_GROUP_NAME = 'NO_GROUP_NAME';
26
- var ITEM_SIZE = (_ITEM_SIZE = {}, _ITEM_SIZE[ItemSize.LARGE] = 50, _ITEM_SIZE[ItemSize.DEFAULT] = 32, _ITEM_SIZE.title = 32, _ITEM_SIZE);
27
-
28
- function isListTitle(element) {
29
- return element.title !== undefined;
30
- }
31
-
32
- function isGroup(item) {
33
- return 'isGroup' in item;
34
- }
22
+ import { NO_GROUP_NAME, ITEM_SIZE, DROPDOWN_HEIGHT, TABS_HEIGHT, SUBGROUP_HEADER_HEIGHT, SEARCH_HEIGHT } from '../constants';
23
+ import { isGroup, isListTitle } from './utils';
35
24
 
36
25
  var ContextSelectorDropdown = function ContextSelectorDropdown(_ref) {
37
26
  var texts = _ref.texts,
@@ -51,44 +40,49 @@ var ContextSelectorDropdown = function ContextSelectorDropdown(_ref) {
51
40
  onClickOutside = _ref.onClickOutside,
52
41
  onSearch = _ref.onSearch,
53
42
  onFetchData = _ref.onFetchData,
54
- hasMoreItems = _ref.hasMoreItems;
55
- var listRef = React.createRef();
43
+ hasMoreItems = _ref.hasMoreItems,
44
+ _ref$outerHeight = _ref.outerHeight,
45
+ outerHeight = _ref$outerHeight === void 0 ? DROPDOWN_HEIGHT : _ref$outerHeight,
46
+ _ref$maxSearchResults = _ref.maxSearchResultsInGroup,
47
+ maxSearchResultsInGroup = _ref$maxSearchResults === void 0 ? 4 : _ref$maxSearchResults;
56
48
  var listStyle = {
57
49
  overflowX: 'unset',
58
50
  overflowY: 'unset'
59
51
  };
60
- var defaultTab = React.useMemo(function () {
52
+ var defaultTab = useMemo(function () {
61
53
  var defaultIndex = groups == null ? void 0 : groups.findIndex(function (group) {
62
54
  return group.defaultGroup;
63
55
  });
64
56
  return defaultIndex || 0;
65
57
  }, [groups]);
66
- var overlayRef = React.useRef(null);
58
+ var listRef = useRef(null);
59
+ var overlayRef = useRef(null);
60
+ var scrollBarRef = useRef(null);
67
61
 
68
- var _React$useState = React.useState(),
69
- searchInputHandle = _React$useState[0],
70
- setSearchInputHandle = _React$useState[1];
62
+ var _useState = useState(),
63
+ searchInputHandle = _useState[0],
64
+ setSearchInputHandle = _useState[1];
71
65
 
72
- var _React$useState2 = React.useState(''),
73
- searchQuery = _React$useState2[0],
74
- setSearchQuery = _React$useState2[1];
66
+ var _useState2 = useState(''),
67
+ searchQuery = _useState2[0],
68
+ setSearchQuery = _useState2[1];
75
69
 
76
- var _React$useState3 = React.useState(defaultTab),
77
- activeTab = _React$useState3[0],
78
- setActiveTab = _React$useState3[1];
70
+ var _useState3 = useState(defaultTab),
71
+ activeTab = _useState3[0],
72
+ setActiveTab = _useState3[1];
79
73
 
80
- var _React$useState4 = React.useState(undefined),
81
- activeGroup = _React$useState4[0],
82
- setActiveGroup = _React$useState4[1];
74
+ var _useState4 = useState(undefined),
75
+ activeGroup = _useState4[0],
76
+ setActiveGroup = _useState4[1];
83
77
 
84
- var _React$useState5 = React.useState(true),
85
- searchInputCanBeFocused = _React$useState5[0],
86
- setSearchInputFocus = _React$useState5[1];
78
+ var _useState5 = useState(true),
79
+ searchInputCanBeFocused = _useState5[0],
80
+ setSearchInputFocus = _useState5[1];
87
81
 
88
- var classNames = React.useMemo(function () {
82
+ var classNames = useMemo(function () {
89
83
  return "ds-context-item ds-context-item-" + uuid();
90
84
  }, []);
91
- var handleOnSetGroup = React.useCallback(function (item) {
85
+ var handleOnSetGroup = useCallback(function (item) {
92
86
  if (isGroup(item)) {
93
87
  onSetGroup && onSetGroup(item);
94
88
  setActiveGroup(item);
@@ -100,23 +94,27 @@ var ContextSelectorDropdown = function ContextSelectorDropdown(_ref) {
100
94
  setDropdownVisible(false);
101
95
  }
102
96
  }, onClickOutsideEvents);
103
- var clearSearch = React.useCallback(function () {
97
+ var clearSearch = useCallback(function () {
104
98
  setSearchQuery('');
105
99
  }, []);
106
- var hideDropdown = React.useCallback(function () {
100
+ var hideDropdown = useCallback(function () {
107
101
  setDropdownVisible(false);
108
102
  }, [setDropdownVisible]);
109
- var currentTabItems = React.useMemo(function () {
110
- return groups == null ? void 0 : groups.find(function (group, index) {
111
- return activeTab === index;
112
- });
103
+ var handleSelect = useCallback(function (parameter) {
104
+ setSelected(parameter);
105
+ setActiveGroup(undefined);
106
+ setActiveTab(defaultTab);
107
+ }, [defaultTab, setSelected]);
108
+ var currentTabItems = useMemo(function () {
109
+ return groups ? getActiveTabGroup(activeTab, groups) : undefined;
113
110
  }, [groups, activeTab]);
114
- var groupByGroupName = React.useCallback(function (activeItems) {
115
- var itemsNumber = activeItems.length;
111
+ var groupByGroupName = useCallback(function (dropdownItems, maxItemsInGroup) {
112
+ var itemsNumber = dropdownItems == null ? void 0 : dropdownItems.length;
116
113
  var groupedItems = {};
117
114
 
118
115
  for (var i = 0; i < itemsNumber; i += 1) {
119
- var item = activeItems[i];
116
+ var item = dropdownItems[i]; // @ts-ignore
117
+
120
118
  var groupName = item.groupName || NO_GROUP_NAME;
121
119
  var group = groupedItems[groupName] || [];
122
120
  group.push(item);
@@ -132,7 +130,8 @@ var ContextSelectorDropdown = function ContextSelectorDropdown(_ref) {
132
130
  });
133
131
  }
134
132
 
135
- groupedItems[key].forEach(function (item) {
133
+ var groupItems = maxItemsInGroup ? groupedItems[key].slice(0, maxItemsInGroup) : groupedItems[key];
134
+ groupItems.forEach(function (item) {
136
135
  var resultItem = item.isGroup ? {
137
136
  className: classNames,
138
137
  item: item,
@@ -143,49 +142,41 @@ var ContextSelectorDropdown = function ContextSelectorDropdown(_ref) {
143
142
  className: classNames,
144
143
  item: item,
145
144
  searchQuery: searchQuery,
145
+ clearSearch: clearSearch,
146
146
  hideDropdown: hideDropdown,
147
- select: setSelected,
147
+ select: handleSelect,
148
148
  selected: Boolean(value) && item.id === (value == null ? void 0 : value.id),
149
149
  menuItemHeight: menuItemHeight
150
150
  };
151
151
  resultItems.push(resultItem);
152
152
  });
153
- });
154
- return resultItems;
155
- }, [activeGroup, classNames, searchQuery, handleOnSetGroup, menuItemHeight, hideDropdown, setSelected, value]);
156
- var searchResults = React.useMemo(function () {
157
- var result = [];
158
- var itemsNumber = items.length;
159
153
 
160
- for (var i = 0; i < itemsNumber; i += 1) {
161
- var _item$name, _item$subtitle;
162
-
163
- var item = items[i];
164
- var searchQueryInLowerCase = searchQuery.toLowerCase();
165
- var isMatchingName = (_item$name = item.name) == null ? void 0 : _item$name.toLowerCase().includes(searchQueryInLowerCase);
166
- var isMatchingSubtitle = (_item$subtitle = item.subtitle) == null ? void 0 : _item$subtitle.toLowerCase().includes(searchQueryInLowerCase);
167
- var matching = !searchQuery || isMatchingName || isMatchingSubtitle;
168
-
169
- if (matching) {
170
- result.push({
154
+ if (maxItemsInGroup && groupedItems[key].length > maxItemsInGroup) {
155
+ var anyItem = groupItems[0];
156
+ resultItems.push({
171
157
  className: classNames,
172
- item: item,
173
- searchQuery: searchQuery,
174
- clearSearch: clearSearch,
175
- hideDropdown: hideDropdown,
176
- select: setSelected,
177
- selected: Boolean(value) && item.id === (value == null ? void 0 : value.id),
178
- menuItemHeight: menuItemHeight
158
+ select: handleOnSetGroup,
159
+ menuItemHeight: menuItemHeight,
160
+ label: /*#__PURE__*/React.createElement(S.ShowMoreItem, null, texts.showMore),
161
+ item: {
162
+ isGroup: true,
163
+ id: anyItem.groupId,
164
+ name: getGroupName(anyItem.groupId, groups) || '',
165
+ icon: /*#__PURE__*/React.createElement(ArrowRightCircleM, null)
166
+ }
179
167
  });
180
168
  }
181
- }
169
+ });
170
+ return resultItems;
171
+ }, [activeGroup, classNames, searchQuery, handleOnSetGroup, menuItemHeight, clearSearch, hideDropdown, handleSelect, value, texts.showMore, groups]);
182
172
 
183
- return result;
184
- }, [classNames, clearSearch, hideDropdown, items, menuItemHeight, searchQuery, setSelected, value]);
185
- var hasSubgroups = React.useMemo(function () {
173
+ var _useSearchResults = useSearchResults(items, groups, activeTab, groupByGroupName, activeGroup, searchQuery, maxSearchResultsInGroup),
174
+ searchResults = _useSearchResults.searchResults;
175
+
176
+ var hasSubgroups = useMemo(function () {
186
177
  return Boolean(currentTabItems == null ? void 0 : currentTabItems.subGroups);
187
178
  }, [currentTabItems]);
188
- var activeItems = React.useMemo(function () {
179
+ var activeItems = useMemo(function () {
189
180
  if (!onSearch && searchQuery) {
190
181
  return searchResults;
191
182
  }
@@ -193,7 +184,7 @@ var ContextSelectorDropdown = function ContextSelectorDropdown(_ref) {
193
184
  if (hasSubgroups && !activeGroup) {
194
185
  var _currentTabItems$subG;
195
186
 
196
- var subGroups = currentTabItems != null && currentTabItems.subGroups ? currentTabItems == null || (_currentTabItems$subG = currentTabItems.subGroups) == null ? void 0 : _currentTabItems$subG.map(function (group) {
187
+ var subGroups = hasSubgroups ? currentTabItems == null || (_currentTabItems$subG = currentTabItems.subGroups) == null ? void 0 : _currentTabItems$subG.map(function (group) {
197
188
  return _objectSpread({}, group, {
198
189
  isGroup: true
199
190
  });
@@ -207,7 +198,7 @@ var ContextSelectorDropdown = function ContextSelectorDropdown(_ref) {
207
198
 
208
199
  return prev;
209
200
  }, []);
210
- return groupByGroupName([].concat(subGroups, subItems));
201
+ return groupByGroupName([].concat(subGroups || [], subItems));
211
202
  }
212
203
 
213
204
  if (activeGroup) {
@@ -223,25 +214,26 @@ var ContextSelectorDropdown = function ContextSelectorDropdown(_ref) {
223
214
  }
224
215
 
225
216
  return groupByGroupName(items);
226
- }, [activeGroup, activeTab, currentTabItems, groupByGroupName, groups, hasSubgroups, items, onSearch, searchQuery, searchResults]);
227
- React.useEffect(function () {
217
+ }, [onSearch, searchQuery, hasSubgroups, activeGroup, activeTab, groups, groupByGroupName, items, searchResults, currentTabItems == null ? void 0 : currentTabItems.subGroups, currentTabItems == null ? void 0 : currentTabItems.id]);
218
+ useEffect(function () {
228
219
  var _listRef$current;
229
220
 
230
221
  // eslint-disable-next-line no-unused-expressions
231
222
  (_listRef$current = listRef.current) == null || _listRef$current.resetAfterIndex(0, false);
232
223
  }, [activeItems, listRef]);
233
- var handleSearch = React.useCallback(function (val) {
224
+ var handleSearch = useCallback(function (val) {
234
225
  setSearchQuery(val);
235
226
  onSearch && onSearch(val);
236
227
  }, [onSearch]);
237
- var getTabs = React.useMemo(function () {
228
+ var getTabs = useMemo(function () {
238
229
  return (groups == null ? void 0 : groups.map(function (group) {
239
230
  return {
240
231
  label: group.name
241
232
  };
242
233
  })) || [];
243
234
  }, [groups]);
244
- var getNoResultContainer = React.useMemo(function () {
235
+ var hasTabs = getTabs.length > 1;
236
+ var getNoResultContainer = useMemo(function () {
245
237
  return /*#__PURE__*/React.createElement(Result, {
246
238
  noSearchResults: true,
247
239
  type: "no-results",
@@ -261,22 +253,33 @@ var ContextSelectorDropdown = function ContextSelectorDropdown(_ref) {
261
253
  var getItemSize = function getItemSize(index) {
262
254
  var item = activeItems[index];
263
255
  if (isListTitle(item)) return ITEM_SIZE.title;
264
- return menuItemHeight ? ITEM_SIZE[menuItemHeight] : ITEM_SIZE[ItemSize.DEFAULT];
256
+ return menuItemHeight ? ITEM_SIZE[menuItemHeight] : ITEM_SIZE[itemSizes.DEFAULT];
265
257
  };
266
258
 
259
+ var dropdownContentHeight = useMemo(function () {
260
+ return outerHeight - (hasTabs && !searchQuery ? TABS_HEIGHT : 0) - (activeGroup ? SUBGROUP_HEADER_HEIGHT : 0) - SEARCH_HEIGHT;
261
+ }, [activeGroup, hasTabs, outerHeight, searchQuery]);
262
+ useEffect(function () {
263
+ if (scrollBarRef.current && listRef.current) {
264
+ scrollBarRef.current.scrollTo({
265
+ top: 0
266
+ });
267
+ listRef.current.resetAfterIndex(0);
268
+ }
269
+ }, [searchQuery, activeGroup, activeTab]);
267
270
  return /*#__PURE__*/React.createElement(Dropdown.Wrapper, {
268
271
  style: _objectSpread({
269
272
  width: '300px'
270
273
  }, dropdownWrapperStyles),
271
274
  ref: overlayRef,
272
- onKeyDown: function onKeyDown(e) {
275
+ onKeyDown: function onKeyDown(event) {
273
276
  var _document;
274
277
 
275
278
  if (((_document = document) == null ? void 0 : _document.activeElement) === (searchInputHandle == null ? void 0 : searchInputHandle.current)) {
276
279
  setSearchInputFocus(false);
277
280
  }
278
281
 
279
- searchQuery && focusWithArrowKeys(e, classNames.split(' ')[1], function () {
282
+ searchQuery && focusWithArrowKeys(event, classNames.split(' ')[1], function () {
280
283
  setSearchInputFocus(true);
281
284
  });
282
285
  }
@@ -297,7 +300,7 @@ var ContextSelectorDropdown = function ContextSelectorDropdown(_ref) {
297
300
  component: /*#__PURE__*/React.createElement(SearchM, null),
298
301
  color: theme.palette['grey-600']
299
302
  })
300
- }), searchQuery === '' && getTabs.length > 1 && /*#__PURE__*/React.createElement(S.TabsWrapper, null, /*#__PURE__*/React.createElement(Tabs, {
303
+ }), hasTabs && /*#__PURE__*/React.createElement(S.TabsWrapper, null, /*#__PURE__*/React.createElement(Tabs, {
301
304
  block: true,
302
305
  tabs: getTabs,
303
306
  activeTab: activeTab,
@@ -306,14 +309,18 @@ var ContextSelectorDropdown = function ContextSelectorDropdown(_ref) {
306
309
  setActiveGroup(undefined);
307
310
  },
308
311
  visible: visible
309
- })), activeGroup && !searchQuery && /*#__PURE__*/React.createElement(Dropdown.BackAction, {
312
+ })), activeGroup && /*#__PURE__*/React.createElement(Dropdown.BackAction, {
310
313
  label: activeGroup.name,
311
314
  onClick: function onClick() {
312
315
  return setActiveGroup(undefined);
313
316
  }
314
- }), loading ? /*#__PURE__*/React.createElement(DropdownSkeleton, {
315
- size: "M"
316
- }) : /*#__PURE__*/React.createElement(S.ItemsList, null, activeItems != null && activeItems.length ? /*#__PURE__*/React.createElement(Scrollbar, {
317
+ }), loading ? /*#__PURE__*/React.createElement(S.Skeleton, {
318
+ contentHeight: dropdownContentHeight,
319
+ size: "M",
320
+ numberOfSkeletons: 3
321
+ }) : /*#__PURE__*/React.createElement(S.ItemsList, {
322
+ contentHeight: dropdownContentHeight
323
+ }, activeItems != null && activeItems.length ? /*#__PURE__*/React.createElement(Scrollbar, {
317
324
  absolute: true,
318
325
  style: {
319
326
  padding: 8
@@ -321,8 +328,9 @@ var ContextSelectorDropdown = function ContextSelectorDropdown(_ref) {
321
328
  loading: loading,
322
329
  hasMore: hasMoreItems,
323
330
  onYReachEnd: onFetchData,
324
- onScroll: handleScroll
325
- }, /*#__PURE__*/React.createElement(List, {
331
+ onScroll: handleScroll,
332
+ ref: scrollBarRef
333
+ }, /*#__PURE__*/React.createElement(VariableSizeList, {
326
334
  className: "ds-context-selector-list",
327
335
  key: "list-" + activeGroup + "-" + activeTab,
328
336
  width: "100%",
@@ -1,4 +1,4 @@
1
1
  import React from 'react';
2
2
  import { ContextSelectorDropdownItemProps } from '../ContextSelector.types';
3
- declare const ContextSelectorDropdownItem: ({ item, clearSearch, searchQuery, hideDropdown, select, selected, className, menuItemHeight, style, }: ContextSelectorDropdownItemProps) => React.JSX.Element;
3
+ declare const ContextSelectorDropdownItem: ({ item, clearSearch, searchQuery, hideDropdown, select, selected, className, menuItemHeight, style, label, }: ContextSelectorDropdownItemProps) => React.JSX.Element;
4
4
  export default ContextSelectorDropdownItem;
@@ -18,7 +18,8 @@ var ContextSelectorDropdownItem = function ContextSelectorDropdownItem(_ref) {
18
18
  selected = _ref.selected,
19
19
  className = _ref.className,
20
20
  menuItemHeight = _ref.menuItemHeight,
21
- style = _ref.style;
21
+ style = _ref.style,
22
+ label = _ref.label;
22
23
 
23
24
  var id = item.id,
24
25
  _ = item.icon,
@@ -43,7 +44,7 @@ var ContextSelectorDropdownItem = function ContextSelectorDropdownItem(_ref) {
43
44
  },
44
45
  size: menuItemHeight,
45
46
  description: item.description
46
- }, itemProps), item.name);
47
+ }, itemProps), label || item.name);
47
48
  };
48
49
 
49
50
  export default ContextSelectorDropdownItem;
@@ -0,0 +1,3 @@
1
+ import type { ContextGroup, ContextItem, DropdownItemProps, ListTitle } from '../ContextSelector.types';
2
+ export declare const isListTitle: (element: DropdownItemProps) => element is ListTitle;
3
+ export declare const isGroup: (item: ContextItem | ContextGroup) => item is ContextGroup;
@@ -0,0 +1,6 @@
1
+ export var isListTitle = function isListTitle(element) {
2
+ return element.title !== undefined;
3
+ };
4
+ export var isGroup = function isGroup(item) {
5
+ return 'isGroup' in item;
6
+ };
@@ -0,0 +1,12 @@
1
+ export declare const NO_GROUP_NAME = "NO_GROUP_NAME";
2
+ export declare const ITEM_SIZE: {
3
+ large: number;
4
+ default: number;
5
+ title: number;
6
+ };
7
+ export declare const DROPDOWN_HEIGHT = 420;
8
+ export declare const DROPDOWN_HEIGHT_BELOW_THRESHOLD = 350;
9
+ export declare const DROPDOWN_HEIGHT_THRESHOLD = 900;
10
+ export declare const SEARCH_HEIGHT = 53;
11
+ export declare const TABS_HEIGHT = 50;
12
+ export declare const SUBGROUP_HEADER_HEIGHT = 53;
@@ -0,0 +1,11 @@
1
+ var _ITEM_SIZE;
2
+
3
+ import { ItemSize } from '@synerise/ds-menu';
4
+ export var NO_GROUP_NAME = 'NO_GROUP_NAME';
5
+ export var ITEM_SIZE = (_ITEM_SIZE = {}, _ITEM_SIZE[ItemSize.LARGE] = 50, _ITEM_SIZE[ItemSize.DEFAULT] = 32, _ITEM_SIZE.title = 32, _ITEM_SIZE);
6
+ export var DROPDOWN_HEIGHT = 420;
7
+ export var DROPDOWN_HEIGHT_BELOW_THRESHOLD = 350;
8
+ export var DROPDOWN_HEIGHT_THRESHOLD = 900;
9
+ export var SEARCH_HEIGHT = 53;
10
+ export var TABS_HEIGHT = 50;
11
+ export var SUBGROUP_HEADER_HEIGHT = 53;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@synerise/ds-context-selector",
3
- "version": "0.24.7",
3
+ "version": "0.25.0",
4
4
  "description": "ContextSelector UI Component for the Synerise Design System",
5
5
  "license": "ISC",
6
6
  "repository": "Synerise/synerise-design",
@@ -27,25 +27,25 @@
27
27
  "test:watch": "npm run test -- --watchAll",
28
28
  "types": "tsc --noEmit"
29
29
  },
30
- "gitHead": "6fe94d574f25c5267c7593dec9399527f441b23a",
30
+ "gitHead": "6f3231e4a9e0720ffee61b748488cecd590da6e6",
31
31
  "sideEffects": [
32
32
  "dist/style/*",
33
33
  "*.less"
34
34
  ],
35
35
  "types": "dist/index.d.ts",
36
36
  "dependencies": {
37
- "@synerise/ds-button": "^0.21.8",
38
- "@synerise/ds-dropdown": "^0.18.12",
39
- "@synerise/ds-factors": "^0.25.0",
40
- "@synerise/ds-icon": "^0.65.3",
41
- "@synerise/ds-information-card": "^0.5.6",
42
- "@synerise/ds-list-item": "^0.4.8",
43
- "@synerise/ds-menu": "^0.19.12",
44
- "@synerise/ds-result": "^0.7.2",
45
- "@synerise/ds-scrollbar": "^0.11.8",
46
- "@synerise/ds-skeleton": "^0.6.6",
47
- "@synerise/ds-tabs": "^0.15.5",
48
- "@synerise/ds-utils": "^0.29.0",
37
+ "@synerise/ds-button": "^0.21.10",
38
+ "@synerise/ds-dropdown": "^0.18.14",
39
+ "@synerise/ds-factors": "^0.25.2",
40
+ "@synerise/ds-icon": "^0.65.5",
41
+ "@synerise/ds-information-card": "^0.5.8",
42
+ "@synerise/ds-list-item": "^0.4.10",
43
+ "@synerise/ds-menu": "^0.19.14",
44
+ "@synerise/ds-result": "^0.7.4",
45
+ "@synerise/ds-scrollbar": "^0.11.10",
46
+ "@synerise/ds-skeleton": "^0.6.8",
47
+ "@synerise/ds-tabs": "^0.16.0",
48
+ "@synerise/ds-utils": "^0.29.2",
49
49
  "react-window": "1.8.5",
50
50
  "uuid": "^8.3.2"
51
51
  },