@bbl-digital/snorre 3.0.3 → 3.0.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. package/dist/bundle.js +208 -100
  2. package/esm/core/Autocomplete/hooks/useAutocomplete.js +242 -0
  3. package/esm/core/Autocomplete/hooks/useHandleDimentions.js +19 -0
  4. package/esm/core/Autocomplete/index.d.js +1 -0
  5. package/esm/core/Autocomplete/index.interfaces.js +1 -0
  6. package/esm/core/Autocomplete/index.js +50 -184
  7. package/esm/core/Autocomplete/styles.js +30 -25
  8. package/esm/core/DatepickerRange/YearMonthForm.js +56 -0
  9. package/esm/core/Radio/styles.js +4 -4
  10. package/lib/core/Autocomplete/hooks/useAutocomplete.d.ts +21 -0
  11. package/lib/core/Autocomplete/hooks/useAutocomplete.d.ts.map +1 -0
  12. package/lib/core/Autocomplete/hooks/useAutocomplete.js +242 -0
  13. package/lib/core/Autocomplete/hooks/useHandleDimentions.d.ts +8 -0
  14. package/lib/core/Autocomplete/hooks/useHandleDimentions.d.ts.map +1 -0
  15. package/lib/core/Autocomplete/hooks/useHandleDimentions.js +19 -0
  16. package/lib/core/Autocomplete/index.d.js +1 -0
  17. package/lib/core/Autocomplete/index.d.ts +2 -74
  18. package/lib/core/Autocomplete/index.d.ts.map +1 -1
  19. package/lib/core/Autocomplete/index.interfaces.d.ts +80 -0
  20. package/lib/core/Autocomplete/index.interfaces.d.ts.map +1 -0
  21. package/lib/core/Autocomplete/index.interfaces.js +1 -0
  22. package/lib/core/Autocomplete/index.js +50 -184
  23. package/lib/core/Autocomplete/styles.d.ts +18 -1
  24. package/lib/core/Autocomplete/styles.d.ts.map +1 -1
  25. package/lib/core/Autocomplete/styles.js +30 -25
  26. package/lib/core/DatepickerRange/YearMonthForm.d.ts +10 -0
  27. package/lib/core/DatepickerRange/YearMonthForm.d.ts.map +1 -0
  28. package/lib/core/DatepickerRange/YearMonthForm.js +56 -0
  29. package/lib/core/Radio/styles.d.ts.map +1 -1
  30. package/lib/core/Radio/styles.js +4 -4
  31. package/package.json +2 -1
  32. package/esm/enums/ModifierKey.js +0 -13
  33. package/lib/enums/ModifierKey.d.ts +0 -12
  34. package/lib/enums/ModifierKey.d.ts.map +0 -1
  35. package/lib/enums/ModifierKey.js +0 -13
@@ -0,0 +1,242 @@
1
+ /* eslint-disable react-hooks/exhaustive-deps */
2
+ import { matchSorter } from 'match-sorter';
3
+ import { useEffect, useMemo, useState } from 'react';
4
+ import { useDebounce } from '../../utils/debounce';
5
+
6
+ const useAutocomplete = props => {
7
+ const [showValues, setShowValues] = useState(!!props.isOpen);
8
+ const [highlightedIndex, setHighlightedIndex] = useState(null);
9
+ const [value, setValueChanged] = useState(props.value ?? '');
10
+ const [inputDirty, setInputDirty] = useState(false);
11
+ const debouncedValue = useDebounce(value, props.debounceDelay ?? 0);
12
+ const [inputValues, setInputValues] = useState(props.values);
13
+
14
+ const handleValueClick = value => {
15
+ props.onSelectItem?.(value);
16
+ setShowValues(false);
17
+ };
18
+
19
+ const clearSelectedItem = () => handleValueClick({
20
+ [props.labelFromValues ?? 'label']: '',
21
+ [props.keyFromValues ?? 'key']: ''
22
+ });
23
+
24
+ const onInputChange = e => {
25
+ setInputDirty(true);
26
+ if (inputValues) setHighlightedIndex(0);
27
+ setValueChanged(e.target.value); // Should not use onChange whenever we have fuzzy search on
28
+
29
+ if (props.fuzzy) return;
30
+ if (props.onChange) props.onChange(e);
31
+ };
32
+
33
+ const handleOnInputClick = () => {
34
+ if (inputValues?.length) setHighlightedIndex(0);
35
+ setShowValues(true);
36
+ };
37
+
38
+ const onFuzzyBlur = e => {
39
+ // If the value of the input is changed, and does not match the value of the values array,
40
+ // we should revert back the input value to the original value
41
+ //What
42
+ // if (!e.target.value.length) clearSelectedItem()
43
+ if (e.target.value === props.value) return; // If target value is the same as a value from the values array, we should set the value for the user
44
+
45
+ if (inputValues?.length) {
46
+ const valueInInputValues = inputValues.find(item => item[props.labelFromValues ?? 'label'].length && item[props.labelFromValues ?? 'label'].toLowerCase() === e.target.value.toLowerCase());
47
+
48
+ if (valueInInputValues) {
49
+ const val = valueInInputValues[props.labelFromValues ?? 'label'];
50
+ setValueChanged(val);
51
+ handleValueClick(valueInInputValues);
52
+ return;
53
+ } // Otherwise we should return to the original input value
54
+
55
+
56
+ setValueChanged(props.value ?? '');
57
+ }
58
+ };
59
+
60
+ const onFuzzyFocus = () => {
61
+ setValueChanged('');
62
+ if (props.values?.length) setShowValues(true);
63
+ };
64
+
65
+ const renderedValues = useMemo(() => {
66
+ if (!props.values?.length) return [];
67
+
68
+ if (props.fuzzy) {
69
+ const fuzzyOptions = {
70
+ keys: [props.labelFromValues ?? 'label']
71
+ };
72
+ setShowValues(Boolean(value));
73
+ return matchSorter(props.values, value ?? '', fuzzyOptions);
74
+ }
75
+
76
+ return props.values;
77
+ }, [value]);
78
+
79
+ const handleEscape = () => {
80
+ setShowValues(false);
81
+ setHighlightedIndex(null);
82
+ };
83
+
84
+ const handleClear = () => {
85
+ clearSelectedItem();
86
+ handleEscape();
87
+ };
88
+
89
+ const handleEnter = e => {
90
+ e.preventDefault();
91
+ e.stopPropagation();
92
+ if (!showValues) return;
93
+
94
+ if (!inputValues?.length) {
95
+ // If there is no autocomplete value in the list, send object with just { value }
96
+ handleValueClick({
97
+ value
98
+ });
99
+ }
100
+
101
+ if (highlightedIndex === null || !inputValues?.length) {
102
+ return;
103
+ }
104
+
105
+ const item = inputValues[highlightedIndex];
106
+ handleValueClick(item);
107
+ setShowValues(false);
108
+ };
109
+
110
+ const handleUp = e => {
111
+ e.preventDefault();
112
+ e.stopPropagation();
113
+ if (!showValues) return;
114
+
115
+ if (highlightedIndex === null || !inputValues?.length) {
116
+ return;
117
+ }
118
+
119
+ const newHighlightIndex = highlightedIndex - 1;
120
+
121
+ if (newHighlightIndex < 0) {
122
+ setHighlightedIndex(null);
123
+ setShowValues(false);
124
+ return;
125
+ }
126
+
127
+ setHighlightedIndex(newHighlightIndex);
128
+ };
129
+
130
+ const handleDown = e => {
131
+ if (!showValues) return;
132
+ e.preventDefault();
133
+ e.stopPropagation();
134
+
135
+ if (highlightedIndex === null || !inputValues?.length) {
136
+ return;
137
+ }
138
+
139
+ const newHighlightIndex = highlightedIndex + 1;
140
+
141
+ if (newHighlightIndex === inputValues.length) {
142
+ setHighlightedIndex(null);
143
+ setShowValues(false);
144
+ return;
145
+ }
146
+
147
+ setHighlightedIndex(newHighlightIndex);
148
+ };
149
+
150
+ const handleCustomOnKeyDown = e => {
151
+ const {
152
+ key
153
+ } = e;
154
+
155
+ if (key === 'Escape') {
156
+ handleEscape();
157
+ return;
158
+ }
159
+
160
+ props.onKeyDown?.(e);
161
+ }; // Makes it possible to navigate using keyboard shortcuts
162
+
163
+
164
+ const handleOnKeyDown = e => {
165
+ const {
166
+ key
167
+ } = e;
168
+
169
+ if (showValues && inputValues?.length) {
170
+ setHighlightedIndex(0);
171
+ } else {
172
+ setHighlightedIndex(null);
173
+ }
174
+
175
+ switch (key) {
176
+ case 'Enter':
177
+ handleEnter(e);
178
+ break;
179
+
180
+ case 'ArrowUp':
181
+ handleUp(e);
182
+ break;
183
+
184
+ case 'ArrowDown':
185
+ case 'Tab':
186
+ handleDown(e);
187
+ break;
188
+
189
+ case 'Escape':
190
+ handleEscape();
191
+ break;
192
+
193
+ default:
194
+ break;
195
+ }
196
+ }; // Handle debounce
197
+
198
+
199
+ useEffect(() => {
200
+ const handleDebounceChange = value => {
201
+ if (props.onDebounceChange && inputDirty) {
202
+ props.onDebounceChange(value);
203
+ }
204
+ };
205
+
206
+ handleDebounceChange(debouncedValue);
207
+ }, [debouncedValue]); // Change local open state if props.isOpen changes
208
+
209
+ useEffect(() => {
210
+ setShowValues(!!props.isOpen);
211
+ }, [props.isOpen]); // Update local values state if props.values changes
212
+
213
+ useEffect(() => {
214
+ setInputValues(props.values);
215
+ }, [props.values]); // Update local value if props.value changes
216
+
217
+ useEffect(() => {
218
+ const value = props.value ?? '';
219
+ setValueChanged(value);
220
+ }, [props.value]);
221
+ useEffect(() => {
222
+ if (!props.openCustomValueInputOnKeyPress) return;
223
+ if (value.length) setShowValues(true);
224
+ }, [value]);
225
+ return {
226
+ setShowValues,
227
+ handleClear,
228
+ handleValueClick,
229
+ onInputChange,
230
+ handleOnKeyDown,
231
+ handleCustomOnKeyDown,
232
+ handleOnInputClick,
233
+ onFuzzyBlur,
234
+ onFuzzyFocus,
235
+ value,
236
+ highlightedIndex,
237
+ showValues,
238
+ renderedValues
239
+ };
240
+ };
241
+
242
+ export default useAutocomplete;
@@ -0,0 +1,19 @@
1
+ import { createRef, useEffect, useState } from 'react';
2
+
3
+ const useHandleDimentions = () => {
4
+ const [height, setHeight] = useState(0);
5
+ const [width, setWidth] = useState(0);
6
+ const dimentionsRef = /*#__PURE__*/createRef();
7
+ useEffect(() => {
8
+ const rect = dimentionsRef.current?.getBoundingClientRect();
9
+ setHeight(rect?.height || 0);
10
+ setWidth(rect?.width || 0); // eslint-disable-next-line react-hooks/exhaustive-deps
11
+ }, [dimentionsRef.current]);
12
+ return {
13
+ height,
14
+ width,
15
+ dimentionsRef
16
+ };
17
+ };
18
+
19
+ export default useHandleDimentions;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -1,192 +1,49 @@
1
1
  /** @jsxImportSource @emotion/react */
2
- import React, { createRef, useState } from 'react';
3
- import { styles, ErrorMessage } from './styles';
2
+ import React, { createRef } from 'react';
3
+ import { styles, ErrorMessage, Clear } from './styles';
4
4
  import { useEffect } from 'react';
5
- import { useDebounce } from '../utils/debounce';
6
5
  import IconErrorOutline from '../../icons/General/IconErrorOutline';
7
6
  import Spinner from '../Spinner';
8
- import useHandleOptionsHeight from './utils/useHandleOptionsHeight';
7
+ import useHandleDimentions from './hooks/useHandleDimentions';
9
8
  import Link from '../Link';
9
+ import IconClose from '../../icons/General/IconClose';
10
+ import useAutocomplete from './hooks/useAutocomplete';
10
11
  import { jsx as _jsx } from "@emotion/react/jsx-runtime";
11
12
  import { jsxs as _jsxs } from "@emotion/react/jsx-runtime";
12
13
  import { Fragment as _Fragment } from "@emotion/react/jsx-runtime";
13
14
  const Autocomplete = /*#__PURE__*/React.forwardRef(({
14
- onDebounceChange,
15
- debounceDelay,
16
15
  height,
17
16
  css,
18
17
  ...props
19
18
  }, ref) => {
20
- const {
21
- optionsHeight,
22
- optionsRef
23
- } = useHandleOptionsHeight();
24
19
  const valuesRef = /*#__PURE__*/createRef();
25
- const [showValues, setShowValues] = useState(!!props.isOpen);
26
- const [highlightedIndex, setHighlightedIndex] = useState(null);
27
- const [value, setValueChanged] = useState(props.value ? props.value : '');
28
- const [inputDirty, setInputDirty] = useState(false);
29
- const debouncedValue = useDebounce(value, debounceDelay ? debounceDelay : 0);
30
-
31
- const onInputChange = e => {
32
- setInputDirty(true);
33
- setValueChanged(e.target.value);
34
- if (props.values) setHighlightedIndex(0);
35
- if (props.onChange) props.onChange(e);
36
- };
37
-
38
- const handleOnInputClick = () => {
39
- if (props.values?.length) setHighlightedIndex(0);
40
- setShowValues(true);
41
- };
42
-
43
- const handleValueClick = value => {
44
- setShowValues(false);
45
- props.onSelectItem?.(value);
46
- };
47
-
48
- const handleEnter = e => {
49
- e.preventDefault();
50
- e.stopPropagation();
51
- if (!showValues) return;
52
-
53
- if (!props.values?.length) {
54
- // If there is no autocomplete value in the list, send object with just { value }
55
- props.onSelectItem?.({
56
- value
57
- });
58
- }
59
-
60
- if (highlightedIndex === null || !props.values?.length) {
61
- return;
62
- }
63
-
64
- const item = props.values[highlightedIndex];
65
- props.onSelectItem?.(item);
66
- setShowValues(false);
67
- };
68
-
69
- const handleUp = e => {
70
- e.preventDefault();
71
- e.stopPropagation();
72
- if (!showValues) return;
73
-
74
- if (highlightedIndex === null || !props.values?.length) {
75
- return;
76
- }
77
-
78
- const newHighlightIndex = highlightedIndex - 1;
79
-
80
- if (newHighlightIndex < 0) {
81
- setHighlightedIndex(null);
82
- setShowValues(false);
83
- return;
84
- }
85
-
86
- setHighlightedIndex(newHighlightIndex);
87
- };
88
-
89
- const handleDown = e => {
90
- if (!showValues) return;
91
- e.preventDefault();
92
- e.stopPropagation();
93
-
94
- if (highlightedIndex === null || !props.values?.length) {
95
- return;
96
- }
97
-
98
- const newHighlightIndex = highlightedIndex + 1;
99
-
100
- if (newHighlightIndex === props.values.length) {
101
- setHighlightedIndex(null);
102
- setShowValues(false);
103
- return;
104
- }
105
-
106
- setHighlightedIndex(newHighlightIndex);
107
- };
108
-
109
- const handleEscape = () => {
110
- setShowValues(false);
111
- setHighlightedIndex(null);
112
- };
113
-
114
- const handleCustomOnKeyDown = e => {
115
- const {
116
- key
117
- } = e;
118
-
119
- if (key === 'Escape') {
120
- handleEscape();
121
- return;
122
- }
123
-
124
- props.onKeyDown?.(e);
125
- };
126
-
127
- const handleOnKeyDown = e => {
128
- const {
129
- key
130
- } = e;
131
-
132
- if (showValues && props.values?.length) {
133
- setHighlightedIndex(0);
134
- } else {
135
- setHighlightedIndex(null);
136
- }
137
-
138
- switch (key) {
139
- case 'Enter':
140
- handleEnter(e);
141
- break;
142
-
143
- case 'ArrowUp':
144
- handleUp(e);
145
- break;
146
-
147
- case 'ArrowDown':
148
- case 'Tab':
149
- handleDown(e);
150
- break;
151
-
152
- case 'Escape':
153
- handleEscape();
154
- break;
155
-
156
- default:
157
- break;
158
- }
159
- }; // Handle debounce
160
-
161
-
162
- useEffect(() => {
163
- const handleDebounceChange = value => {
164
- if (onDebounceChange && inputDirty) {
165
- onDebounceChange(value);
166
- }
167
- };
168
-
169
- handleDebounceChange(debouncedValue); // eslint-disable-next-line react-hooks/exhaustive-deps
170
- }, [debouncedValue]);
171
- useEffect(() => {
172
- setShowValues(!!props.isOpen);
173
- }, [props.isOpen]);
174
- useEffect(() => {
175
- const value = props.value ? props.value : '';
176
- setValueChanged(value);
177
- }, [props.value]);
178
- useEffect(() => {
179
- if (!props.openCustomValueInputOnKeyPress) return;
180
- if (value.length) setShowValues(true); // eslint-disable-next-line react-hooks/exhaustive-deps
181
- }, [value]);
20
+ const {
21
+ height: optionsHeight,
22
+ dimentionsRef: optionsRef
23
+ } = useHandleDimentions();
24
+ const {
25
+ width: inputWrapperWidth,
26
+ dimentionsRef: inputWrapperRef
27
+ } = useHandleDimentions();
28
+ const {
29
+ value,
30
+ highlightedIndex,
31
+ showValues,
32
+ renderedValues,
33
+ setShowValues,
34
+ handleClear,
35
+ handleOnInputClick,
36
+ handleCustomOnKeyDown,
37
+ handleOnKeyDown,
38
+ handleValueClick,
39
+ onInputChange,
40
+ onFuzzyBlur,
41
+ onFuzzyFocus
42
+ } = useAutocomplete(props);
182
43
  useEffect(() => {
183
44
  const handleClickOutside = e => {
184
45
  const node = valuesRef.current;
185
-
186
- if (node && node.contains(e.target)) {
187
- return;
188
- }
189
-
46
+ if (node && node.contains(e.target)) return;
190
47
  setShowValues(false);
191
48
  };
192
49
 
@@ -198,10 +55,11 @@ const Autocomplete = /*#__PURE__*/React.forwardRef(({
198
55
 
199
56
  return () => {
200
57
  document.removeEventListener('mousedown', handleClickOutside);
201
- };
58
+ }; // eslint-disable-next-line react-hooks/exhaustive-deps
202
59
  }, [showValues, valuesRef]);
203
60
  return _jsxs(_Fragment, {
204
61
  children: [_jsxs("label", {
62
+ ref: inputWrapperRef,
205
63
  css: theme => [styles.default(theme), (props.invalid || props.invalidMessage) && styles.invalid(theme), props.validation && styles.validation, props.onLabelClick && styles.clickableLabel, height && styles.height(height), css && css],
206
64
  onClick: props.onLabelClick ? e => e.preventDefault() : undefined,
207
65
  children: [_jsxs("span", {
@@ -224,8 +82,8 @@ const Autocomplete = /*#__PURE__*/React.forwardRef(({
224
82
  value: value,
225
83
  disabled: props.disabled,
226
84
  autoFocus: props.focus,
227
- onBlur: props.onBlur,
228
- onFocus: props.onFocus,
85
+ onBlur: props.fuzzy ? onFuzzyBlur : props.onBlur,
86
+ onFocus: props.fuzzy ? onFuzzyFocus : props.onFocus,
229
87
  onChange: onInputChange,
230
88
  onKeyDown: props.onKeyDown ? handleCustomOnKeyDown : handleOnKeyDown,
231
89
  onClick: handleOnInputClick,
@@ -234,6 +92,12 @@ const Autocomplete = /*#__PURE__*/React.forwardRef(({
234
92
  autoComplete: "off",
235
93
  css: theme => [props.disabled && styles.disabled(theme)],
236
94
  children: React.Children.map(props.children, child => child || null)
95
+ }), props.clear && _jsx(Clear, {
96
+ nostyle: true,
97
+ onClick: handleClear,
98
+ children: _jsx(IconClose, {
99
+ size: 14
100
+ })
237
101
  }), props.loading && _jsx(Spinner, {
238
102
  size: 14
239
103
  }), props.actions && _jsx("div", {
@@ -253,17 +117,19 @@ const Autocomplete = /*#__PURE__*/React.forwardRef(({
253
117
  children: props.invalidMessage
254
118
  })]
255
119
  })]
256
- }), (props.values?.length || props.renderCustomValueInput) && !props.loading && showValues && _jsxs("div", {
120
+ }), (Boolean(props.values?.length) || props.renderCustomValueInput) && !props.loading && showValues && _jsxs("div", {
257
121
  ref: valuesRef,
258
- css: () => [!props.renderCustomValueInput && styles.listWrapper, props.dynamicallyPlaceInput && Boolean(optionsHeight) && styles.listWrapperTopPosition(optionsHeight), props.dynamicallyPlaceInput && Boolean(optionsHeight) && props.invalidMessage && styles.listWrapperTopPosition(optionsHeight + 30), props.inputValuesMaxWidth && styles.listWrapperMaxWidth(props.inputValuesMaxWidth)],
259
- children: [props.values?.length && _jsx("ul", {
122
+ css: () => [!props.renderCustomValueInput && styles.listWrapper(inputWrapperWidth), props.dynamicallyPlaceInput && Boolean(optionsHeight) && styles.listWrapperTopPosition(optionsHeight), props.dynamicallyPlaceInput && Boolean(optionsHeight) && props.invalidMessage && styles.listWrapperTopPosition(optionsHeight + 30), props.inputValuesMaxWidth && styles.listWrapperMaxWidth(props.inputValuesMaxWidth)],
123
+ children: [Boolean(renderedValues?.length) && _jsx("ul", {
260
124
  css: theme => [styles.list(theme)],
261
- children: props.values.map((item, index) => _jsx("li", {
262
- tabIndex: 0,
263
- css: index === highlightedIndex ? styles.highlightedItem : null,
264
- onClick: () => handleValueClick(item),
265
- children: props.labelFromValues ? item[props.labelFromValues] : item.label
266
- }, props.keyFromValues ? item[props.keyFromValues] : item.key))
125
+ children: renderedValues.map((item, index) => {
126
+ return _jsx("li", {
127
+ tabIndex: 0,
128
+ css: index === highlightedIndex ? styles.highlightedItem : null,
129
+ onClick: () => handleValueClick(item),
130
+ children: props.labelFromValues ? item[props.labelFromValues] : item.label
131
+ }, props.keyFromValues ? item[props.keyFromValues] : item.key);
132
+ })
267
133
  }), props.renderCustomValueInput && _jsx("div", {
268
134
  children: props.renderCustomValueInput
269
135
  })]