@synerise/ds-search 1.3.9 → 1.3.11

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,26 @@
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
+ ## [1.3.11](https://github.com/Synerise/synerise-design/compare/@synerise/ds-search@1.3.10...@synerise/ds-search@1.3.11) (2025-11-28)
7
+
8
+
9
+ ### Bug Fixes
10
+
11
+ * **search:** fix types ([44042fa](https://github.com/Synerise/synerise-design/commit/44042fa0e22f04800969f5a25ea6335b4552f4ab))
12
+ * **search:** refactor search component from class to function ([16e3c0c](https://github.com/Synerise/synerise-design/commit/16e3c0c2b04082e811cdd625f564321faf8811ed))
13
+
14
+
15
+
16
+
17
+
18
+ ## [1.3.10](https://github.com/Synerise/synerise-design/compare/@synerise/ds-search@1.3.9...@synerise/ds-search@1.3.10) (2025-11-06)
19
+
20
+ **Note:** Version bump only for package @synerise/ds-search
21
+
22
+
23
+
24
+
25
+
6
26
  ## [1.3.9](https://github.com/Synerise/synerise-design/compare/@synerise/ds-search@1.3.8...@synerise/ds-search@1.3.9) (2025-10-22)
7
27
 
8
28
  **Note:** Version bump only for package @synerise/ds-search
@@ -0,0 +1,3 @@
1
+ import { type SearchRendererProps } from './SearchRenderer.types';
2
+ declare const SearchRenderer: ({ title, tooltip, data, width, height, rowHeight, listProps, itemRender, highlight, onItemClick, }: SearchRendererProps) => JSX.Element | null;
3
+ export default SearchRenderer;
@@ -0,0 +1,34 @@
1
+ import React from 'react';
2
+ import SearchHeader from '../SearchHeader/SearchHeader';
3
+ import SearchItems from '../SearchItems/SearchItems';
4
+ var SearchRenderer = function SearchRenderer(_ref) {
5
+ var title = _ref.title,
6
+ tooltip = _ref.tooltip,
7
+ data = _ref.data,
8
+ width = _ref.width,
9
+ height = _ref.height,
10
+ _ref$rowHeight = _ref.rowHeight,
11
+ rowHeight = _ref$rowHeight === void 0 ? 30 : _ref$rowHeight,
12
+ listProps = _ref.listProps,
13
+ _ref$itemRender = _ref.itemRender,
14
+ itemRender = _ref$itemRender === void 0 ? function (item) {
15
+ return /*#__PURE__*/React.createElement(React.Fragment, null, item);
16
+ } : _ref$itemRender,
17
+ highlight = _ref.highlight,
18
+ onItemClick = _ref.onItemClick;
19
+ return /*#__PURE__*/React.createElement(React.Fragment, null, !!title && /*#__PURE__*/React.createElement(SearchHeader, {
20
+ headerText: title,
21
+ tooltip: tooltip
22
+ }), /*#__PURE__*/React.createElement(SearchItems, {
23
+ data: data,
24
+ height: height,
25
+ highlight: highlight,
26
+ width: width,
27
+ rowHeight: rowHeight,
28
+ itemRender: itemRender,
29
+ onItemClick: onItemClick,
30
+ listProps: listProps,
31
+ renderInMenu: false
32
+ }));
33
+ };
34
+ export default SearchRenderer;
@@ -0,0 +1,14 @@
1
+ import { type ReactElement } from 'react';
2
+ import { type AnyObject } from '../../Search.types';
3
+ export type SearchRendererProps = {
4
+ title?: string;
5
+ tooltip?: string;
6
+ data: AnyObject[] | undefined;
7
+ width: number;
8
+ height?: number;
9
+ rowHeight?: number;
10
+ listProps?: Record<string, unknown>;
11
+ itemRender?: (item: AnyObject) => ReactElement;
12
+ onItemClick: (item: AnyObject) => void;
13
+ highlight: string;
14
+ };
@@ -1,3 +1,9 @@
1
- export declare const getAllElementsFiltered: <T extends object>(data: T[] | undefined | null, value: string, elementTextLookupKey: keyof T) => object[];
2
- export declare const hasSomeElementFiltered: <T extends object>(data: T[] | undefined | null, currentValue: string, elementTextLookupKey: keyof T) => boolean;
1
+ import { type AnyObject } from '../../Search.types';
2
+ export declare const getAllElementsFiltered: <T extends AnyObject>(data: T[] | undefined | null, value: string, elementTextLookupKey: keyof T) => T[];
3
+ export declare const hasSomeElementFiltered: <T extends AnyObject>(data: T[] | undefined | null, currentValue: string, elementTextLookupKey: keyof T) => boolean;
3
4
  export declare const hasSomeElement: (data: Record<string, unknown>[] | undefined) => boolean;
5
+ export declare const getParametersScrollTop: ({ scrollTop, rowHeight, recent, }: {
6
+ scrollTop: number;
7
+ rowHeight: number;
8
+ recent: AnyObject[];
9
+ }) => number;
@@ -1,3 +1,4 @@
1
+ import { LIST_HEADER_HEIGHT } from '../../const';
1
2
  export var getAllElementsFiltered = function getAllElementsFiltered(data, value, elementTextLookupKey) {
2
3
  return data && data.filter(function (el) {
3
4
  return String(el[elementTextLookupKey]).toLowerCase().includes(value.toLocaleLowerCase());
@@ -10,4 +11,10 @@ export var hasSomeElementFiltered = function hasSomeElementFiltered(data, curren
10
11
  };
11
12
  export var hasSomeElement = function hasSomeElement(data) {
12
13
  return !!data && data.length > 0;
14
+ };
15
+ export var getParametersScrollTop = function getParametersScrollTop(_ref) {
16
+ var scrollTop = _ref.scrollTop,
17
+ rowHeight = _ref.rowHeight,
18
+ recent = _ref.recent;
19
+ return scrollTop - LIST_HEADER_HEIGHT - (hasSomeElement(recent) ? recent.length * rowHeight : 0);
13
20
  };
package/dist/Search.d.ts CHANGED
@@ -1,23 +1,5 @@
1
1
  import React from 'react';
2
- import { type AnyObject, type SearchProps, type SearchState, SelectResultDataKeys } from './Search.types';
2
+ import { type AnyObject, type SearchProps } from './Search.types';
3
3
  import './style/index.less';
4
- declare class Search extends React.PureComponent<SearchProps<AnyObject, AnyObject>, SearchState<AnyObject>> {
5
- private wrapperRef;
6
- constructor(props: SearchProps<AnyObject, AnyObject>);
7
- componentDidUpdate(prevProps: SearchProps<AnyObject, AnyObject>): void;
8
- onKeyDown(e: React.KeyboardEvent<HTMLInputElement>): void;
9
- getSearchWrapperWidth(): number;
10
- handleClickOutside: () => void;
11
- handleClearValue: () => void;
12
- handleChange(currentValue: string): void;
13
- isListItemRendered(): boolean;
14
- selectResult(item: object, dataKey: SelectResultDataKeys): void;
15
- selectFilter(item: object): void;
16
- renderRecentItems(): React.ReactNode | false;
17
- renderParameters(): React.ReactNode | false;
18
- renderSuggestions(): React.ReactNode | false;
19
- renderInputWrapper(): React.ReactNode;
20
- render(): React.ReactElement;
21
- }
22
- declare const _default: import("react-onclickoutside").WrapperClass<SearchProps<AnyObject, AnyObject>, typeof Search>;
23
- export default _default;
4
+ export declare function Search<T extends AnyObject, U extends AnyObject, S extends AnyObject>({ divider, dropdownMaxHeight, width, searchWidth, style, dropdownWidth, recent, suggestions, parameters, value, textLookupConfig, hideLabel, parameterValue, onParameterValueChange, alwaysExpanded, onClear, onValueChange, filterLookupKey, recentDisplayProps, parametersDisplayProps, suggestionsDisplayProps, placeholder, clearTooltip, disableInput, inputProps, searchTooltipProps, }: SearchProps<T, U, S>): React.JSX.Element;
5
+ export default Search;
package/dist/Search.js CHANGED
@@ -1,396 +1,269 @@
1
1
  function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
2
- function _inheritsLoose(t, o) { t.prototype = Object.create(o.prototype), t.prototype.constructor = t, _setPrototypeOf(t, o); }
3
- function _setPrototypeOf(t, e) { return _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function (t, e) { return t.__proto__ = e, t; }, _setPrototypeOf(t, e); }
4
- import React from 'react';
5
- import onClickOutside from 'react-onclickoutside';
2
+ import React, { useEffect, useRef, useState } from 'react';
6
3
  import Scrollbar from '@synerise/ds-scrollbar';
7
- import { focusWithArrowKeys } from '@synerise/ds-utils';
8
- import { SearchHeader, SearchInput, SearchItems } from './Elements';
9
- import { getAllElementsFiltered, hasSomeElement, hasSomeElementFiltered } from './Elements/utils/searchUtils';
4
+ import { focusWithArrowKeys, useOnClickOutside } from '@synerise/ds-utils';
5
+ import { SearchInput } from './Elements';
6
+ import SearchRenderer from './Elements/SearchRenderer/SearchRenderer';
7
+ import { getAllElementsFiltered, getParametersScrollTop, hasSomeElement, hasSomeElementFiltered } from './Elements/utils/searchUtils';
10
8
  import * as S from './Search.styles';
11
9
  import { SelectResultDataKeys } from './Search.types';
12
- import { INPUT_EXPAND_ANIMATION_DURATION, LIST_HEADER_HEIGHT, MENU_WIDTH_OFFSET, SCROLLBAR_HEIGHT_OFFSET } from './const';
10
+ import { INPUT_EXPAND_ANIMATION_DURATION, MENU_WIDTH_OFFSET, SCROLLBAR_HEIGHT_OFFSET } from './const';
13
11
  import "./style/index.css";
14
- var getParametersScrollTop = function getParametersScrollTop(_ref) {
15
- var scrollTop = _ref.scrollTop,
16
- rowHeight = _ref.rowHeight,
17
- recent = _ref.recent;
18
- return scrollTop - LIST_HEADER_HEIGHT - (hasSomeElement(recent) ? recent.length * rowHeight : 0);
19
- };
20
- var Search = /*#__PURE__*/function (_React$PureComponent) {
21
- function Search(props) {
22
- var _this;
23
- _this = _React$PureComponent.call(this, props) || this;
24
- _this.wrapperRef = /*#__PURE__*/React.createRef();
25
- // This handler is used for onClickOutside HOC
26
- _this.handleClickOutside = function () {
27
- var _this$state = _this.state,
28
- isInputOpen = _this$state.isInputOpen,
29
- label = _this$state.label,
30
- toggleInputTrigger = _this$state.toggleInputTrigger;
31
- var _this$props = _this.props,
32
- value = _this$props.value,
33
- alwaysExpanded = _this$props.alwaysExpanded;
34
- if (isInputOpen && !value && !label && !alwaysExpanded) {
35
- _this.setState({
36
- toggleInputTrigger: !toggleInputTrigger
12
+ export function Search(_ref) {
13
+ var divider = _ref.divider,
14
+ dropdownMaxHeight = _ref.dropdownMaxHeight,
15
+ width = _ref.width,
16
+ searchWidth = _ref.searchWidth,
17
+ style = _ref.style,
18
+ dropdownWidth = _ref.dropdownWidth,
19
+ recent = _ref.recent,
20
+ _ref$suggestions = _ref.suggestions,
21
+ suggestions = _ref$suggestions === void 0 ? null : _ref$suggestions,
22
+ parameters = _ref.parameters,
23
+ value = _ref.value,
24
+ textLookupConfig = _ref.textLookupConfig,
25
+ hideLabel = _ref.hideLabel,
26
+ parameterValue = _ref.parameterValue,
27
+ onParameterValueChange = _ref.onParameterValueChange,
28
+ alwaysExpanded = _ref.alwaysExpanded,
29
+ onClear = _ref.onClear,
30
+ onValueChange = _ref.onValueChange,
31
+ filterLookupKey = _ref.filterLookupKey,
32
+ recentDisplayProps = _ref.recentDisplayProps,
33
+ parametersDisplayProps = _ref.parametersDisplayProps,
34
+ suggestionsDisplayProps = _ref.suggestionsDisplayProps,
35
+ placeholder = _ref.placeholder,
36
+ clearTooltip = _ref.clearTooltip,
37
+ disableInput = _ref.disableInput,
38
+ inputProps = _ref.inputProps,
39
+ searchTooltipProps = _ref.searchTooltipProps;
40
+ var wrapperRef = useRef(null);
41
+ var _useState = useState(function () {
42
+ if (parameterValue) {
43
+ var _ref2;
44
+ var found = parameters.find(function (param) {
45
+ return param[textLookupConfig.parameters] === parameterValue;
37
46
  });
47
+ return (_ref2 = found) != null ? _ref2 : null;
38
48
  }
39
- _this.setState({
40
- isListVisible: false,
41
- scrollbarScrollTop: 0
42
- });
43
- };
44
- _this.handleClearValue = function () {
45
- var _this$props2 = _this.props,
46
- parameters = _this$props2.parameters,
47
- recent = _this$props2.recent,
48
- suggestions = _this$props2.suggestions,
49
- onClear = _this$props2.onClear;
50
- onClear && onClear();
51
- _this.setState({
52
- label: null,
53
- filteredRecent: recent,
54
- filteredParameters: parameters,
55
- filteredSuggestions: suggestions,
56
- isResultChosen: false
57
- });
58
- };
59
- var searchWidth = props.width || props.searchWidth;
60
- // eslint-disable-next-line react/state-in-constructor
61
- _this.state = {
62
- isInputOpen: !!props.value || !!props.parameterValue || !!props.alwaysExpanded,
63
- label: props.parameterValue ? props.parameters.find(function (param) {
64
- return param[props.textLookupConfig.parameters] === props.parameterValue;
65
- }) : null,
66
- filteredParameters: props.parameters,
67
- filteredRecent: props.recent,
68
- filteredSuggestions: props.suggestions,
69
- isListVisible: false,
70
- isResultChosen: false,
71
- itemsListWidth: searchWidth ? searchWidth - MENU_WIDTH_OFFSET : 0,
72
- toggleInputTrigger: false,
73
- focusInputTrigger: false,
74
- scrollbarScrollTop: 0,
75
- moveCursorToEnd: true
76
- };
77
- return _this;
78
- }
79
- _inheritsLoose(Search, _React$PureComponent);
80
- var _proto = Search.prototype;
81
- _proto.componentDidUpdate = function componentDidUpdate(prevProps) {
82
- var _prevProps$suggestion;
83
- var _this$props3 = this.props,
84
- recent = _this$props3.recent,
85
- suggestions = _this$props3.suggestions,
86
- parameters = _this$props3.parameters,
87
- value = _this$props3.value,
88
- textLookupConfig = _this$props3.textLookupConfig,
89
- hideLabel = _this$props3.hideLabel,
90
- parameterValue = _this$props3.parameterValue;
91
- if (prevProps.value !== value && !value || prevProps.parameterValue && !parameterValue) {
92
- this.handleChange(value);
93
- this.setState({
94
- isResultChosen: false
49
+ return null;
50
+ }),
51
+ label = _useState[0],
52
+ setLabel = _useState[1];
53
+ var _useState2 = useState(parameters),
54
+ filteredParameters = _useState2[0],
55
+ setFilteredParameters = _useState2[1];
56
+ var _useState3 = useState(recent),
57
+ filteredRecent = _useState3[0],
58
+ setFilteredRecent = _useState3[1];
59
+ var _useState4 = useState(suggestions != null ? suggestions : null),
60
+ filteredSuggestions = _useState4[0],
61
+ setFilteredSuggestions = _useState4[1];
62
+ var _useState5 = useState(false),
63
+ isListVisible = _useState5[0],
64
+ setIsListVisible = _useState5[1];
65
+ var _useState6 = useState(false),
66
+ isResultChosen = _useState6[0],
67
+ setIsResultChosen = _useState6[1];
68
+ var _useState7 = useState(false),
69
+ toggleInputTrigger = _useState7[0],
70
+ setToggleInputTrigger = _useState7[1];
71
+ var _useState8 = useState(false),
72
+ focusInputTrigger = _useState8[0],
73
+ setFocusInputTrigger = _useState8[1];
74
+ var _useState9 = useState(0),
75
+ scrollbarScrollTop = _useState9[0],
76
+ setScrollbarScrollTop = _useState9[1];
77
+ var _useState10 = useState(true),
78
+ moveCursorToEnd = _useState10[0],
79
+ setMoveCursorToEnd = _useState10[1];
80
+ var _useState11 = useState(width || searchWidth ? (width || searchWidth) - MENU_WIDTH_OFFSET : 0),
81
+ itemsListWidth = _useState11[0],
82
+ setItemsListWidth = _useState11[1];
83
+ useEffect(function () {
84
+ if (parameterValue) {
85
+ var _ref3;
86
+ var found = parameters.find(function (param) {
87
+ return param[textLookupConfig.parameters] === parameterValue;
95
88
  });
89
+ setLabel((_ref3 = found) != null ? _ref3 : null);
90
+ } else {
91
+ setLabel(null);
96
92
  }
97
- if (prevProps.recent.length !== recent.length) {
98
- this.setState({
99
- filteredRecent: getAllElementsFiltered(recent, value, textLookupConfig.recent)
100
- });
93
+ }, [parameterValue, parameters, textLookupConfig.parameters]);
94
+ useEffect(function () {
95
+ setFilteredRecent(getAllElementsFiltered(recent, value, textLookupConfig.recent));
96
+ }, [recent, value, textLookupConfig.recent]);
97
+ useEffect(function () {
98
+ setFilteredParameters(parameterValue ? parameters : getAllElementsFiltered(parameters, value, textLookupConfig.parameters));
99
+ }, [parameters, value, parameterValue, textLookupConfig.parameters]);
100
+ useEffect(function () {
101
+ if (suggestions) {
102
+ setFilteredSuggestions(getAllElementsFiltered(suggestions, value, textLookupConfig.suggestions));
103
+ } else {
104
+ setFilteredSuggestions(null);
101
105
  }
102
- if (prevProps.parameters.length !== parameters.length) {
103
- this.setState({
104
- filteredParameters: parameterValue ? parameters : getAllElementsFiltered(parameters, value, textLookupConfig.parameters)
105
- });
106
+ }, [suggestions, value, textLookupConfig.suggestions]);
107
+ useEffect(function () {
108
+ var newWidth = (width || searchWidth || 0) - MENU_WIDTH_OFFSET;
109
+ setItemsListWidth(Math.max(0, newWidth));
110
+ }, [width, searchWidth]);
111
+ useEffect(function () {
112
+ if (hideLabel) {
113
+ setLabel(null);
114
+ setIsResultChosen(false);
106
115
  }
107
- if (suggestions && ((_prevProps$suggestion = prevProps.suggestions) == null ? void 0 : _prevProps$suggestion.length) !== suggestions.length) {
108
- this.setState({
109
- filteredSuggestions: getAllElementsFiltered(suggestions, value, textLookupConfig.suggestions)
110
- });
111
- }
112
- if (hideLabel && prevProps.hideLabel !== hideLabel) {
113
- this.setState({
114
- label: null,
115
- isResultChosen: false
116
- });
116
+ }, [hideLabel]);
117
+ useEffect(function () {
118
+ if (!value) {
119
+ setIsResultChosen(false);
117
120
  }
121
+ }, [value]);
122
+ var handleScroll = function handleScroll(event) {
123
+ var scrollTop = event.currentTarget.scrollTop;
124
+ setScrollbarScrollTop(scrollTop);
118
125
  };
119
- _proto.onKeyDown = function onKeyDown(e) {
120
- var _this$props4 = this.props,
121
- value = _this$props4.value,
122
- onParameterValueChange = _this$props4.onParameterValueChange,
123
- recent = _this$props4.recent;
124
- var isInputOpen = this.state.isInputOpen;
125
- if (e.key === 'Backspace' && value === '' && isInputOpen) {
126
- this.setState({
127
- label: null,
128
- filteredRecent: recent
126
+ var handleKeyDownWrapper = function handleKeyDownWrapper(event) {
127
+ focusWithArrowKeys(event, 'ds-search-item', function () {
128
+ setFocusInputTrigger(function (prev) {
129
+ return !prev;
129
130
  });
130
- onParameterValueChange('', null);
131
+ });
132
+ };
133
+ var handleDropdownClick = function handleDropdownClick() {
134
+ setFocusInputTrigger(function (prev) {
135
+ return !prev;
136
+ });
137
+ };
138
+ var mergedWidth = searchWidth !== undefined ? searchWidth : width;
139
+ var onKeyDown = function onKeyDown(event) {
140
+ if (event.key === 'Backspace' && value === '' && isOpen) {
141
+ setLabel(null);
142
+ setFilteredRecent(recent);
143
+ onParameterValueChange == null || onParameterValueChange('', null);
131
144
  return;
132
145
  }
133
- if (e.key === 'Enter' && isInputOpen) {
134
- this.setState({
135
- isResultChosen: !!value
136
- });
146
+ if (event.key === 'Enter' && isOpen) {
147
+ setIsResultChosen(!!value);
137
148
  }
138
- this.setState({
139
- moveCursorToEnd: false
140
- });
149
+ setMoveCursorToEnd(false);
141
150
  };
142
- _proto.getSearchWrapperWidth = function getSearchWrapperWidth() {
143
- var width = this.props.width;
151
+ var getSearchWrapperWidth = function getSearchWrapperWidth() {
144
152
  if (width) {
145
153
  return width - MENU_WIDTH_OFFSET;
146
154
  }
147
- if (this.wrapperRef !== null && this.wrapperRef.current && this.wrapperRef.current.clientWidth > MENU_WIDTH_OFFSET) {
148
- return this.wrapperRef.current.clientWidth - MENU_WIDTH_OFFSET;
155
+ if (wrapperRef.current && wrapperRef.current.clientWidth > MENU_WIDTH_OFFSET) {
156
+ return wrapperRef.current.clientWidth - MENU_WIDTH_OFFSET;
149
157
  }
150
158
  return 0;
151
159
  };
152
- _proto.handleChange = function handleChange(currentValue) {
153
- var _this$props5 = this.props,
154
- parameterValue = _this$props5.parameterValue,
155
- recent = _this$props5.recent,
156
- suggestions = _this$props5.suggestions,
157
- parameters = _this$props5.parameters,
158
- onValueChange = _this$props5.onValueChange,
159
- textLookupConfig = _this$props5.textLookupConfig;
160
- var isAnythingToShow;
161
- onValueChange(currentValue);
162
- if (parameterValue) {
163
- var matchingSuggestions = getAllElementsFiltered(suggestions, currentValue, textLookupConfig.suggestions);
164
- this.setState({
165
- filteredSuggestions: matchingSuggestions
160
+ var _useState12 = useState(false),
161
+ isOpen = _useState12[0],
162
+ setIsOpen = _useState12[1];
163
+ useOnClickOutside(wrapperRef, function () {
164
+ if (isOpen && !value && !label && !alwaysExpanded) {
165
+ setToggleInputTrigger(function (prev) {
166
+ return !prev;
166
167
  });
167
- isAnythingToShow = matchingSuggestions.length > 0;
168
+ }
169
+ setIsOpen(false);
170
+ setIsListVisible(false);
171
+ setScrollbarScrollTop(0);
172
+ });
173
+ var handleClearValue = function handleClearValue() {
174
+ onClear == null || onClear();
175
+ setLabel(null);
176
+ setFilteredRecent(recent);
177
+ setFilteredParameters(parameters);
178
+ setFilteredSuggestions(suggestions != null ? suggestions : null);
179
+ setIsResultChosen(false);
180
+ };
181
+ var handleChange = function handleChange(currentValue) {
182
+ onValueChange == null || onValueChange(currentValue);
183
+ if (parameterValue) {
184
+ var matchingSuggestions = getAllElementsFiltered(suggestions != null ? suggestions : [], currentValue, textLookupConfig.suggestions);
185
+ setFilteredSuggestions(matchingSuggestions);
186
+ setIsResultChosen(false);
187
+ setIsListVisible(matchingSuggestions.length > 0);
168
188
  } else {
169
189
  var matchingRecent = getAllElementsFiltered(recent, currentValue, textLookupConfig.recent);
170
190
  var matchingParameters = getAllElementsFiltered(parameters, currentValue, textLookupConfig.parameters);
171
- this.setState({
172
- filteredParameters: matchingParameters,
173
- filteredRecent: matchingRecent
174
- });
175
- isAnythingToShow = matchingRecent.length > 0 || matchingParameters.length > 0;
191
+ setFilteredParameters(matchingParameters);
192
+ setFilteredRecent(matchingRecent);
193
+ setIsResultChosen(false);
194
+ setIsListVisible(matchingRecent.length > 0 || matchingParameters.length > 0);
176
195
  }
177
- this.setState({
178
- isResultChosen: false,
179
- isListVisible: isAnythingToShow
180
- });
181
196
  };
182
- _proto.isListItemRendered = function isListItemRendered() {
183
- var _this$props6 = this.props,
184
- suggestions = _this$props6.suggestions,
185
- recent = _this$props6.recent,
186
- parameters = _this$props6.parameters,
187
- value = _this$props6.value,
188
- parameterValue = _this$props6.parameterValue,
189
- textLookupConfig = _this$props6.textLookupConfig;
190
- var isAnythingToShow;
197
+ var isListItemRendered = function isListItemRendered() {
191
198
  if (parameterValue) {
192
- isAnythingToShow = hasSomeElementFiltered(suggestions, value, textLookupConfig.suggestions);
199
+ return hasSomeElementFiltered(suggestions, value, textLookupConfig.suggestions);
193
200
  } else {
194
201
  var anyRecentItem = hasSomeElementFiltered(recent, value, textLookupConfig.recent);
195
202
  var anyFilter = hasSomeElementFiltered(parameters, value, textLookupConfig.parameters);
196
- isAnythingToShow = anyFilter || anyRecentItem;
203
+ return anyRecentItem || anyFilter;
197
204
  }
198
- return isAnythingToShow;
199
205
  };
200
- _proto.selectResult = function selectResult(item, dataKey) {
201
- var _this$props7 = this.props,
202
- onValueChange = _this$props7.onValueChange,
203
- textLookupConfig = _this$props7.textLookupConfig;
204
- this.setState({
205
- isResultChosen: true,
206
- moveCursorToEnd: true
207
- });
208
- onValueChange(item[textLookupConfig[dataKey]]);
206
+ var selectResult = function selectResult(item, dataKey) {
207
+ var newValue = item[textLookupConfig[dataKey]];
208
+ onValueChange == null || onValueChange(newValue);
209
+ setIsResultChosen(true);
210
+ setMoveCursorToEnd(true);
209
211
  };
210
- _proto.selectFilter = function selectFilter(item) {
211
- var _this$props8 = this.props,
212
- onValueChange = _this$props8.onValueChange,
213
- onParameterValueChange = _this$props8.onParameterValueChange,
214
- filterLookupKey = _this$props8.filterLookupKey,
215
- textLookupConfig = _this$props8.textLookupConfig;
216
- var focusInputTrigger = this.state.focusInputTrigger;
217
- onValueChange('');
218
- this.setState({
219
- label: item,
220
- focusInputTrigger: !focusInputTrigger,
221
- moveCursorToEnd: true
212
+ var selectFilter = function selectFilter(item) {
213
+ var paramKey = textLookupConfig.parameters;
214
+ var paramValue = item[paramKey];
215
+ onValueChange == null || onValueChange('');
216
+ setLabel(item);
217
+ setFocusInputTrigger(function (prev) {
218
+ return !prev;
222
219
  });
220
+ setMoveCursorToEnd(true);
223
221
  if (filterLookupKey && item[filterLookupKey]) {
224
- onValueChange(item[textLookupConfig.parameters]);
225
- onParameterValueChange(item[filterLookupKey], item);
226
- this.setState({
227
- isResultChosen: true
228
- });
222
+ var inputValue = item[paramKey];
223
+ var filterValue = item[filterLookupKey];
224
+ onValueChange == null || onValueChange(inputValue);
225
+ onParameterValueChange == null || onParameterValueChange(filterValue, item);
226
+ setIsResultChosen(true);
229
227
  } else {
230
- onParameterValueChange(item[textLookupConfig.parameters], item);
228
+ onParameterValueChange == null || onParameterValueChange(paramValue, item);
231
229
  }
232
230
  };
233
- _proto.renderRecentItems = function renderRecentItems() {
234
- var _this2 = this;
235
- var _this$props9 = this.props,
236
- recent = _this$props9.recent,
237
- recentDisplayProps = _this$props9.recentDisplayProps,
238
- dropdownWidth = _this$props9.dropdownWidth,
239
- value = _this$props9.value;
240
- var _this$state2 = this.state,
241
- label = _this$state2.label,
242
- filteredRecent = _this$state2.filteredRecent,
243
- itemsListWidth = _this$state2.itemsListWidth;
244
- var title = recentDisplayProps.title,
245
- tooltip = recentDisplayProps.tooltip,
246
- rowHeight = recentDisplayProps.rowHeight,
247
- itemRender = recentDisplayProps.itemRender;
248
- return recent && !label && hasSomeElement(filteredRecent) && /*#__PURE__*/React.createElement(React.Fragment, null, !!title && /*#__PURE__*/React.createElement(SearchHeader, {
249
- headerText: title,
250
- tooltip: tooltip
251
- }), /*#__PURE__*/React.createElement(SearchItems, {
252
- data: filteredRecent,
253
- highlight: value,
254
- itemRender: itemRender,
255
- onItemClick: function onItemClick(item) {
256
- return _this2.selectResult(item, SelectResultDataKeys.RECENT);
257
- },
258
- rowHeight: rowHeight,
259
- width: dropdownWidth ? dropdownWidth - MENU_WIDTH_OFFSET : itemsListWidth,
260
- renderInMenu: false
261
- }));
262
- };
263
- _proto.renderParameters = function renderParameters() {
264
- var _this3 = this;
265
- var _this$props10 = this.props,
266
- parameters = _this$props10.parameters,
267
- parametersDisplayProps = _this$props10.parametersDisplayProps,
268
- value = _this$props10.value,
269
- dropdownMaxHeight = _this$props10.dropdownMaxHeight,
270
- dropdownWidth = _this$props10.dropdownWidth,
271
- recentDisplayProps = _this$props10.recentDisplayProps;
272
- var _this$state3 = this.state,
273
- label = _this$state3.label,
274
- filteredParameters = _this$state3.filteredParameters,
275
- itemsListWidth = _this$state3.itemsListWidth,
276
- scrollbarScrollTop = _this$state3.scrollbarScrollTop,
277
- filteredRecent = _this$state3.filteredRecent;
278
- var title = parametersDisplayProps.title,
279
- tooltip = parametersDisplayProps.tooltip,
280
- rowHeight = parametersDisplayProps.rowHeight,
281
- itemRender = parametersDisplayProps.itemRender,
282
- listProps = parametersDisplayProps.listProps;
283
- return parameters && !label && hasSomeElement(filteredParameters) && /*#__PURE__*/React.createElement(React.Fragment, null, !!title && /*#__PURE__*/React.createElement(SearchHeader, {
284
- headerText: title,
285
- tooltip: tooltip
286
- }), /*#__PURE__*/React.createElement(SearchItems, {
287
- data: filteredParameters,
288
- height: dropdownMaxHeight,
289
- highlight: value,
290
- itemRender: itemRender,
291
- onItemClick: function onItemClick(item) {
292
- return _this3.selectFilter(item);
293
- },
294
- rowHeight: rowHeight,
295
- width: dropdownWidth ? dropdownWidth - MENU_WIDTH_OFFSET : itemsListWidth,
296
- listProps: _extends({
297
- scrollTop: getParametersScrollTop({
298
- scrollTop: scrollbarScrollTop,
299
- recent: filteredRecent,
300
- rowHeight: recentDisplayProps.rowHeight
301
- })
302
- }, listProps || {}),
303
- renderInMenu: false
304
- }));
305
- };
306
- _proto.renderSuggestions = function renderSuggestions() {
307
- var _this4 = this;
308
- var _this$props11 = this.props,
309
- suggestions = _this$props11.suggestions,
310
- parameterValue = _this$props11.parameterValue,
311
- suggestionsDisplayProps = _this$props11.suggestionsDisplayProps,
312
- value = _this$props11.value,
313
- dropdownWidth = _this$props11.dropdownWidth,
314
- dropdownMaxHeight = _this$props11.dropdownMaxHeight;
315
- var _this$state4 = this.state,
316
- isResultChosen = _this$state4.isResultChosen,
317
- itemsListWidth = _this$state4.itemsListWidth,
318
- filteredSuggestions = _this$state4.filteredSuggestions,
319
- scrollbarScrollTop = _this$state4.scrollbarScrollTop;
320
- return suggestions && suggestionsDisplayProps && parameterValue && !isResultChosen && filteredSuggestions && hasSomeElement(filteredSuggestions) && /*#__PURE__*/React.createElement(React.Fragment, null, !!suggestionsDisplayProps.title && /*#__PURE__*/React.createElement(SearchHeader, {
321
- headerText: suggestionsDisplayProps.title,
322
- tooltip: suggestionsDisplayProps.tooltip
323
- }), /*#__PURE__*/React.createElement(SearchItems, {
324
- data: filteredSuggestions,
325
- height: dropdownMaxHeight,
326
- highlight: value,
327
- itemRender: suggestionsDisplayProps.itemRender,
328
- onItemClick: function onItemClick(item) {
329
- return _this4.selectResult(item, SelectResultDataKeys.SUGGESTIONS);
330
- },
331
- rowHeight: suggestionsDisplayProps.rowHeight,
332
- width: dropdownWidth ? dropdownWidth - MENU_WIDTH_OFFSET : itemsListWidth,
333
- listProps: _extends({
334
- scrollTop: scrollbarScrollTop
335
- }, suggestionsDisplayProps.listProps || {}),
336
- renderInMenu: false
337
- }));
338
- };
339
- _proto.renderInputWrapper = function renderInputWrapper() {
340
- var _this5 = this;
341
- var _this$props12 = this.props,
342
- placeholder = _this$props12.placeholder,
343
- clearTooltip = _this$props12.clearTooltip,
344
- value = _this$props12.value,
345
- textLookupConfig = _this$props12.textLookupConfig,
346
- filterLookupKey = _this$props12.filterLookupKey,
347
- disableInput = _this$props12.disableInput,
348
- inputProps = _this$props12.inputProps,
349
- alwaysExpanded = _this$props12.alwaysExpanded,
350
- searchTooltipProps = _this$props12.searchTooltipProps;
351
- var _this$state5 = this.state,
352
- label = _this$state5.label,
353
- isListVisible = _this$state5.isListVisible,
354
- focusInputTrigger = _this$state5.focusInputTrigger,
355
- toggleInputTrigger = _this$state5.toggleInputTrigger,
356
- moveCursorToEnd = _this$state5.moveCursorToEnd;
231
+ var widthDropdownSearch = dropdownWidth ? dropdownWidth - MENU_WIDTH_OFFSET : itemsListWidth;
232
+ var shouldRenderRecent = Boolean(recent && !label && hasSomeElement(filteredRecent));
233
+ var shouldRenderParameters = Boolean(parameters && !label && hasSomeElement(filteredParameters));
234
+ var shouldRenderSuggestions = Boolean(suggestions && suggestionsDisplayProps && parameterValue && !isResultChosen && filteredSuggestions && hasSomeElement(filteredSuggestions));
235
+ var renderInputWrapper = function renderInputWrapper() {
236
+ var handleInputClick = function handleInputClick() {
237
+ setIsOpen(true);
238
+ setIsListVisible(true);
239
+ setItemsListWidth(getSearchWrapperWidth());
240
+ };
241
+ var handleToggle = function handleToggle(toggle) {
242
+ setIsOpen(toggle);
243
+ setIsListVisible(toggle);
244
+ setTimeout(function () {
245
+ setItemsListWidth(getSearchWrapperWidth());
246
+ }, INPUT_EXPAND_ANIMATION_DURATION);
247
+ };
248
+ var handleButtonClick = function handleButtonClick() {
249
+ setFocusInputTrigger(function (prev) {
250
+ return !prev;
251
+ });
252
+ };
357
253
  return /*#__PURE__*/React.createElement(SearchInput, {
358
254
  alwaysHighlight: true,
359
255
  clearTooltip: clearTooltip,
360
256
  searchTooltipProps: searchTooltipProps,
361
257
  filterLookupKey: filterLookupKey,
362
- textLookupKey: textLookupConfig.parameters,
258
+ textLookupKey: String(textLookupConfig.parameters),
363
259
  filterLabel: label,
364
260
  focusTrigger: focusInputTrigger,
365
- onButtonClick: function onButtonClick() {
366
- return _this5.setState({
367
- focusInputTrigger: !focusInputTrigger
368
- });
369
- },
370
- onChange: function onChange(newValue) {
371
- return _this5.handleChange(newValue);
372
- },
373
- onClear: this.handleClearValue,
374
- onClick: function onClick() {
375
- _this5.setState({
376
- isListVisible: true,
377
- itemsListWidth: _this5.getSearchWrapperWidth()
378
- });
379
- },
380
- onKeyDown: function onKeyDown(e) {
381
- return _this5.onKeyDown(e);
382
- },
383
- onToggle: function onToggle(toggle) {
384
- _this5.setState({
385
- isListVisible: toggle,
386
- isInputOpen: toggle
387
- });
388
- setTimeout(function () {
389
- _this5.setState({
390
- itemsListWidth: _this5.getSearchWrapperWidth()
391
- });
392
- }, INPUT_EXPAND_ANIMATION_DURATION);
393
- },
261
+ onButtonClick: handleButtonClick,
262
+ onChange: handleChange,
263
+ onClear: handleClearValue,
264
+ onClick: handleInputClick,
265
+ onKeyDown: onKeyDown,
266
+ onToggle: handleToggle,
394
267
  placeholder: placeholder,
395
268
  toggleTrigger: toggleInputTrigger,
396
269
  value: value,
@@ -401,58 +274,56 @@ var Search = /*#__PURE__*/function (_React$PureComponent) {
401
274
  closeOnClickOutside: !alwaysExpanded && !isListVisible && !value && !label
402
275
  });
403
276
  };
404
- _proto.render = function render() {
405
- var _this6 = this;
406
- var _this$props13 = this.props,
407
- divider = _this$props13.divider,
408
- dropdownMaxHeight = _this$props13.dropdownMaxHeight,
409
- width = _this$props13.width,
410
- searchWidth = _this$props13.searchWidth,
411
- style = _this$props13.style,
412
- dropdownWidth = _this$props13.dropdownWidth;
413
- var _this$state6 = this.state,
414
- isInputOpen = _this$state6.isInputOpen,
415
- label = _this$state6.label,
416
- isListVisible = _this$state6.isListVisible,
417
- focusInputTrigger = _this$state6.focusInputTrigger,
418
- isResultChosen = _this$state6.isResultChosen,
419
- filteredParameters = _this$state6.filteredParameters,
420
- filteredRecent = _this$state6.filteredRecent;
421
- var mergedWidth = searchWidth !== undefined ? searchWidth : width;
422
- return /*#__PURE__*/React.createElement(S.SearchWrapper, {
423
- ref: this.wrapperRef,
424
- className: "SearchWrapper",
425
- inputOpen: isInputOpen,
426
- $width: mergedWidth,
427
- onKeyDown: function onKeyDown(e) {
428
- focusWithArrowKeys(e, 'ds-search-item', function () {
429
- _this6.setState({
430
- focusInputTrigger: !focusInputTrigger
431
- });
432
- });
433
- },
434
- style: style
435
- }, this.renderInputWrapper(), isListVisible && /*#__PURE__*/React.createElement(S.SearchDropdownWrapper, {
436
- dropdownWidth: dropdownWidth,
437
- onClick: function onClick() {
438
- _this6.setState({
439
- focusInputTrigger: !focusInputTrigger
440
- });
441
- }
442
- }, /*#__PURE__*/React.createElement(S.SearchDropdownContent, {
443
- maxHeight: dropdownMaxHeight,
444
- className: isInputOpen && !isResultChosen && this.isListItemRendered() ? 'search-list-open' : ''
445
- }, /*#__PURE__*/React.createElement(Scrollbar, {
446
- absolute: true,
447
- maxHeight: dropdownMaxHeight - SCROLLBAR_HEIGHT_OFFSET,
448
- onScroll: function onScroll(_ref2) {
449
- var currentTarget = _ref2.currentTarget;
450
- _this6.setState({
451
- scrollbarScrollTop: currentTarget.scrollTop
452
- });
453
- }
454
- }, this.renderRecentItems(), !!(filteredParameters != null && filteredParameters.length) && !!(filteredRecent != null && filteredRecent.length) && !label && divider, this.renderParameters(), this.renderSuggestions()))));
455
- };
456
- return Search;
457
- }(React.PureComponent);
458
- export default onClickOutside(Search);
277
+ return /*#__PURE__*/React.createElement(S.SearchWrapper, {
278
+ ref: wrapperRef,
279
+ className: "SearchWrapper",
280
+ inputOpen: isOpen,
281
+ $width: mergedWidth,
282
+ onKeyDown: handleKeyDownWrapper,
283
+ style: style
284
+ }, renderInputWrapper(), isListVisible && /*#__PURE__*/React.createElement(S.SearchDropdownWrapper, {
285
+ dropdownWidth: dropdownWidth,
286
+ onClick: handleDropdownClick
287
+ }, /*#__PURE__*/React.createElement(S.SearchDropdownContent, {
288
+ maxHeight: dropdownMaxHeight,
289
+ className: isOpen && !isResultChosen && isListItemRendered() ? 'search-list-open' : ''
290
+ }, /*#__PURE__*/React.createElement(Scrollbar, {
291
+ absolute: true,
292
+ maxHeight: dropdownMaxHeight - SCROLLBAR_HEIGHT_OFFSET,
293
+ onScroll: handleScroll
294
+ }, shouldRenderRecent && /*#__PURE__*/React.createElement(SearchRenderer, _extends({
295
+ data: filteredRecent,
296
+ highlight: value,
297
+ width: widthDropdownSearch,
298
+ onItemClick: function onItemClick(item) {
299
+ return selectResult(item, SelectResultDataKeys.RECENT);
300
+ }
301
+ }, recentDisplayProps)), !!(filteredParameters != null && filteredParameters.length) && !!(filteredRecent != null && filteredRecent.length) && !label && divider, shouldRenderParameters && /*#__PURE__*/React.createElement(SearchRenderer, _extends({
302
+ data: filteredParameters,
303
+ highlight: value,
304
+ width: widthDropdownSearch,
305
+ height: dropdownMaxHeight,
306
+ listProps: _extends({
307
+ scrollTop: getParametersScrollTop({
308
+ scrollTop: scrollbarScrollTop,
309
+ recent: filteredRecent,
310
+ rowHeight: recentDisplayProps.rowHeight
311
+ })
312
+ }, parametersDisplayProps.listProps || {}),
313
+ onItemClick: function onItemClick(item) {
314
+ return selectFilter(item);
315
+ }
316
+ }, parametersDisplayProps)), shouldRenderSuggestions && /*#__PURE__*/React.createElement(SearchRenderer, _extends({
317
+ data: filteredSuggestions || [],
318
+ highlight: value,
319
+ width: widthDropdownSearch,
320
+ height: dropdownMaxHeight,
321
+ listProps: _extends({
322
+ scrollTop: scrollbarScrollTop
323
+ }, (suggestionsDisplayProps == null ? void 0 : suggestionsDisplayProps.listProps) || {}),
324
+ onItemClick: function onItemClick(item) {
325
+ return selectResult(item, SelectResultDataKeys.SUGGESTIONS);
326
+ }
327
+ }, suggestionsDisplayProps))))));
328
+ }
329
+ export default Search;
@@ -11,12 +11,12 @@ export type DataSetProps = {
11
11
  visibleRows?: number;
12
12
  listProps?: Partial<ListProps>;
13
13
  };
14
- export type SearchLookupConfig<T extends AnyObject, U extends AnyObject> = {
14
+ export type SearchLookupConfig<T extends AnyObject, U extends AnyObject, S extends AnyObject> = {
15
15
  parameters: keyof U;
16
16
  recent: keyof T;
17
- suggestions: keyof T;
17
+ suggestions: keyof S;
18
18
  };
19
- export type SearchProps<T extends AnyObject, U extends AnyObject> = {
19
+ export type SearchProps<T extends AnyObject, U extends AnyObject, S extends AnyObject> = {
20
20
  clearTooltip: string;
21
21
  divider?: React.ReactNode;
22
22
  dropdownMaxHeight: number;
@@ -32,9 +32,9 @@ export type SearchProps<T extends AnyObject, U extends AnyObject> = {
32
32
  recent: T[];
33
33
  recentDisplayProps: DataSetProps;
34
34
  style?: React.CSSProperties;
35
- suggestions?: T[] | null;
35
+ suggestions?: S[] | null;
36
36
  suggestionsDisplayProps?: DataSetProps | null;
37
- textLookupConfig: SearchLookupConfig<T, U>;
37
+ textLookupConfig: SearchLookupConfig<T, U, S>;
38
38
  value: string;
39
39
  /** @deprecated - use searchWidth instead */
40
40
  width?: number;
@@ -47,20 +47,6 @@ export type SearchProps<T extends AnyObject, U extends AnyObject> = {
47
47
  alwaysExpanded?: boolean;
48
48
  searchTooltipProps?: TooltipProps;
49
49
  };
50
- export type SearchState<T extends AnyObject> = {
51
- isInputOpen: boolean;
52
- label: T | null | undefined;
53
- filteredParameters: T[];
54
- filteredRecent: T[];
55
- filteredSuggestions?: T[] | null;
56
- isListVisible: boolean;
57
- focusInputTrigger: boolean;
58
- toggleInputTrigger: boolean;
59
- isResultChosen: boolean;
60
- itemsListWidth: number;
61
- scrollbarScrollTop: number;
62
- moveCursorToEnd: boolean;
63
- };
64
50
  export declare enum SelectResultDataKeys {
65
51
  RECENT = "recent",
66
52
  SUGGESTIONS = "suggestions"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@synerise/ds-search",
3
- "version": "1.3.9",
3
+ "version": "1.3.11",
4
4
  "description": "Search UI Component for the Synerise Design System",
5
5
  "license": "ISC",
6
6
  "repository": "Synerise/synerise-design",
@@ -35,11 +35,11 @@
35
35
  ],
36
36
  "types": "dist/index.d.ts",
37
37
  "dependencies": {
38
- "@synerise/ds-button": "^1.4.16",
39
- "@synerise/ds-icon": "^1.7.3",
40
- "@synerise/ds-menu": "^1.1.2",
41
- "@synerise/ds-scrollbar": "^1.1.9",
42
- "@synerise/ds-tooltip": "^1.2.1",
38
+ "@synerise/ds-button": "^1.5.1",
39
+ "@synerise/ds-icon": "^1.9.0",
40
+ "@synerise/ds-menu": "^1.2.1",
41
+ "@synerise/ds-scrollbar": "^1.2.1",
42
+ "@synerise/ds-tooltip": "^1.3.1",
43
43
  "@synerise/ds-utils": "^1.5.0",
44
44
  "react-onclickoutside": "^6.9.0",
45
45
  "react-window": "^1.8.11"
@@ -50,5 +50,5 @@
50
50
  "react": ">=16.9.0 <= 18.3.1",
51
51
  "styled-components": "^5.3.3"
52
52
  },
53
- "gitHead": "a40fca2cc78eda64afa96d18dc4d177538a22404"
53
+ "gitHead": "d5bd7fbc9d840ac30e2b79b36c451b486e178445"
54
54
  }