@elliemae/ds-controlled-form 2.3.2-next.0 → 2.4.0-rc.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/cjs/autocomplete/parts/controls/useKeyboardNavigation.js +93 -0
- package/cjs/autocomplete/parts/controls/useMaskedOnChange.js +28 -0
- package/cjs/autocomplete/react-desc-prop-types.js +19 -0
- package/cjs/autocomplete/sharedTypes.js +2 -0
- package/cjs/combobox/config/useComboBox.js +30 -6
- package/cjs/combobox/config/useCorrectOptions.js +1 -1
- package/cjs/combobox/parts/container/Container.js +25 -33
- package/cjs/combobox/parts/controls/Controls.js +4 -16
- package/cjs/combobox/parts/controls-input/useControlsInput.js +1 -3
- package/cjs/combobox/parts/controls-input/useKeyboardNavigation.js +36 -30
- package/cjs/combobox/parts/header-list/HeaderList.js +3 -4
- package/cjs/combobox/parts/header-list/useHeaderListHandlers.js +18 -9
- package/cjs/combobox/parts/menu-list/MenuList.js +0 -2
- package/cjs/combobox/parts/menu-list/useItemRenderer.js +9 -14
- package/cjs/combobox/parts/multi-selected-values-container/MultiSelectedValuesContainer.js +6 -17
- package/cjs/combobox/parts/multi-selected-values-container/RemovableSelectedValuePill.js +42 -0
- package/cjs/combobox/react-desc-prop-types.js +0 -2
- package/cjs/combobox/sharedTypes.js +3 -1
- package/cjs/combobox/utils/listHelper.js +47 -0
- package/cjs/mask-hook/hooks/useNumberMask.js +21 -17
- package/cjs/mask-hook/hooks/usePhoneMask.js +1 -1
- package/esm/autocomplete/parts/controls/useKeyboardNavigation.js +89 -0
- package/esm/autocomplete/parts/controls/useMaskedOnChange.js +24 -0
- package/esm/autocomplete/react-desc-prop-types.js +14 -0
- package/esm/autocomplete/sharedTypes.js +1 -0
- package/esm/combobox/config/useComboBox.js +31 -7
- package/esm/combobox/config/useCorrectOptions.js +1 -1
- package/esm/combobox/parts/container/Container.js +26 -34
- package/esm/combobox/parts/controls/Controls.js +4 -16
- package/esm/combobox/parts/controls-input/useControlsInput.js +1 -3
- package/esm/combobox/parts/controls-input/useKeyboardNavigation.js +38 -32
- package/esm/combobox/parts/header-list/HeaderList.js +3 -4
- package/esm/combobox/parts/header-list/useHeaderListHandlers.js +19 -10
- package/esm/combobox/parts/menu-list/MenuList.js +0 -2
- package/esm/combobox/parts/menu-list/useItemRenderer.js +10 -15
- package/esm/combobox/parts/multi-selected-values-container/MultiSelectedValuesContainer.js +6 -17
- package/esm/combobox/parts/multi-selected-values-container/RemovableSelectedValuePill.js +34 -0
- package/esm/combobox/react-desc-prop-types.js +0 -2
- package/esm/combobox/sharedTypes.js +3 -2
- package/esm/combobox/utils/listHelper.js +45 -1
- package/esm/mask-hook/hooks/useNumberMask.js +21 -17
- package/esm/mask-hook/hooks/usePhoneMask.js +1 -1
- package/package.json +35 -23
- package/types/autocomplete/parts/controls/useKeyboardNavigation.d.ts +4 -0
- package/types/autocomplete/parts/controls/useMaskedOnChange.d.ts +2 -0
- package/types/autocomplete/react-desc-prop-types.d.ts +54 -0
- package/types/autocomplete/sharedTypes.d.ts +20 -0
- package/types/combobox/parts/header-list/useHeaderListHandlers.d.ts +1 -1
- package/types/combobox/parts/multi-selected-values-container/RemovableSelectedValuePill.d.ts +5 -0
- package/types/combobox/react-desc-prop-types.d.ts +3 -4
- package/types/combobox/sharedTypes.d.ts +1 -0
- package/types/combobox/tests/{combobox-creatable.test.d.ts → creatable.test.d.ts} +0 -0
- package/types/combobox/tests/{combobox-disable.test.d.ts → disabled.test.d.ts} +0 -0
- package/types/combobox/tests/{combobox-general.test.d.ts → general.test.d.ts} +0 -0
- package/types/combobox/tests/{combobox-multi-select.test.d.ts → multi-select.test.d.ts} +0 -0
- package/types/combobox/tests/{combobox-onlyselectable.test.d.ts → onlyselectable.test.d.ts} +0 -0
- package/types/combobox/tests/{combobox-single-select.test.d.ts → single-select.test.d.ts} +0 -0
- package/types/combobox/tests/{combobox-usemask.test.d.ts → usemask.test.d.ts} +0 -0
- package/types/combobox/utils/listHelper.d.ts +3 -0
- package/cjs/combobox/utils/hooks/useKeyboardNavigation.js +0 -168
- package/cjs/combobox/utils/hooks/useOnElementResize.js +0 -37
- package/esm/combobox/utils/hooks/useKeyboardNavigation.js +0 -164
- package/esm/combobox/utils/hooks/useOnElementResize.js +0 -33
- package/types/combobox/utils/hooks/useKeyboardNavigation.d.ts +0 -4
- package/types/combobox/utils/hooks/useOnElementResize.d.ts +0 -3
|
@@ -1,57 +1,50 @@
|
|
|
1
1
|
import 'core-js/modules/esnext.async-iterator.find.js';
|
|
2
2
|
import 'core-js/modules/esnext.iterator.constructor.js';
|
|
3
3
|
import 'core-js/modules/esnext.iterator.find.js';
|
|
4
|
+
import 'core-js/modules/esnext.async-iterator.filter.js';
|
|
5
|
+
import 'core-js/modules/esnext.iterator.filter.js';
|
|
4
6
|
import { useContext, useCallback } from 'react';
|
|
5
7
|
import { ComboBoxContext } from '../../ComboBoxCTX.js';
|
|
6
|
-
import { getOptions, findInCircularList } from '../../utils/listHelper.js';
|
|
7
|
-
import { INTERNAL_MENU_OPTION_TYPES } from '../../constants.js';
|
|
8
|
+
import { getOptions, getSuggestedValueOnChange, findInCircularList, getLastValueSelected } from '../../utils/listHelper.js';
|
|
9
|
+
import { MENU_OPTION_TYPES, INTERNAL_MENU_OPTION_TYPES } from '../../constants.js';
|
|
8
10
|
|
|
9
11
|
const isOptionFocuseable = opt => !['section', 'separator'].includes(opt.type) && !opt.disabled;
|
|
10
12
|
|
|
11
13
|
const useKeyboardNavigation = () => {
|
|
12
14
|
const {
|
|
13
15
|
props: {
|
|
14
|
-
inline,
|
|
15
|
-
onSelectAll,
|
|
16
16
|
onCancel,
|
|
17
17
|
onKeyDown,
|
|
18
18
|
onChange,
|
|
19
19
|
onCreate,
|
|
20
|
+
onFilter,
|
|
21
|
+
onSelectAll,
|
|
22
|
+
inline,
|
|
20
23
|
options,
|
|
21
24
|
selectedValues,
|
|
22
|
-
onFilter,
|
|
23
25
|
withoutPortal
|
|
24
26
|
},
|
|
25
|
-
setShowPopover,
|
|
26
|
-
setInputValue,
|
|
27
27
|
inputValue,
|
|
28
28
|
showPopover,
|
|
29
29
|
focusOptionIdx,
|
|
30
|
-
setFocusOptionIdx,
|
|
31
30
|
selectAllCheckboxRef,
|
|
32
|
-
toggleSelectionButtonRef
|
|
31
|
+
toggleSelectionButtonRef,
|
|
32
|
+
setShowPopover,
|
|
33
|
+
setInputValue,
|
|
34
|
+
scrollOptionIntoView,
|
|
35
|
+
setFocusOptionIdx
|
|
33
36
|
} = useContext(ComboBoxContext);
|
|
34
37
|
const multiple = Array.isArray(selectedValues);
|
|
35
38
|
const selectableOptions = getOptions(options);
|
|
36
39
|
const currentItemIndex = options.findIndex(opt => opt.dsId === focusOptionIdx);
|
|
37
40
|
const currentItem = options.find(item => item.dsId === focusOptionIdx);
|
|
38
|
-
const selectOption = useCallback(() => {
|
|
39
|
-
const selectedOption = options.find(item => item.dsId === focusOptionIdx);
|
|
40
|
-
|
|
41
|
-
if (!selectedOption.disabled) {
|
|
42
|
-
if (onFilter) onFilter('');
|
|
43
|
-
setInputValue('');
|
|
44
|
-
onChange(selectedOption);
|
|
45
|
-
if (!multiple) setShowPopover(false);
|
|
46
|
-
}
|
|
47
|
-
}, [multiple, options, setInputValue, focusOptionIdx, setShowPopover, onFilter, onChange]);
|
|
48
41
|
const onInputKeyDown = useCallback(e => {
|
|
49
42
|
// =============================================================================
|
|
50
43
|
// CUSTOM KEYS
|
|
51
44
|
// =============================================================================
|
|
52
|
-
if (onKeyDown) onKeyDown(e, currentItem);
|
|
45
|
+
if (onKeyDown && (currentItem === null || currentItem === void 0 ? void 0 : currentItem.type) === MENU_OPTION_TYPES.OPTION) onKeyDown(e, currentItem);
|
|
53
46
|
|
|
54
|
-
if (
|
|
47
|
+
if (['ArrowDown', 'ArrowUp', 'Enter', 'Spacebar'].includes(e.key) || e.keyCode >= 48 && e.keyCode <= 90) {
|
|
55
48
|
setShowPopover(true);
|
|
56
49
|
} // =============================================================================
|
|
57
50
|
// ESCAPE
|
|
@@ -86,8 +79,17 @@ const useKeyboardNavigation = () => {
|
|
|
86
79
|
e.preventDefault();
|
|
87
80
|
e.stopPropagation();
|
|
88
81
|
|
|
89
|
-
if (focusOptionIdx !== '' && showPopover) {
|
|
90
|
-
|
|
82
|
+
if (focusOptionIdx !== '' && showPopover && (currentItem === null || currentItem === void 0 ? void 0 : currentItem.type) === MENU_OPTION_TYPES.OPTION) {
|
|
83
|
+
if ((currentItem === null || currentItem === void 0 ? void 0 : currentItem.type) === 'option' && !currentItem.disabled) {
|
|
84
|
+
if (onFilter) onFilter('');
|
|
85
|
+
setInputValue('');
|
|
86
|
+
|
|
87
|
+
if (!multiple) {
|
|
88
|
+
setShowPopover(false);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
onChange(getSuggestedValueOnChange(currentItem, selectedValues), currentItem, e);
|
|
92
|
+
}
|
|
91
93
|
}
|
|
92
94
|
}
|
|
93
95
|
|
|
@@ -95,8 +97,8 @@ const useKeyboardNavigation = () => {
|
|
|
95
97
|
setShowPopover(false);
|
|
96
98
|
}
|
|
97
99
|
|
|
98
|
-
if (e.key === 'a' && e.ctrlKey && multiple) {
|
|
99
|
-
|
|
100
|
+
if (e.key === 'a' && e.ctrlKey && multiple && onSelectAll) {
|
|
101
|
+
onSelectAll(options.filter(option => option.type === 'option' && !option.disabled), e);
|
|
100
102
|
} // =============================================================================
|
|
101
103
|
// ARROWS UP AND DOWN: LOGIC TO CALCULATE NEXT OR PREV ITEM TO PSEUDOFOCUS FROM INPUT
|
|
102
104
|
// =============================================================================
|
|
@@ -109,6 +111,7 @@ const useKeyboardNavigation = () => {
|
|
|
109
111
|
if ((showPopover || inline) && selectableOptions.length) {
|
|
110
112
|
const nextItemIndex = findInCircularList(options, currentItemIndex, isOptionFocuseable);
|
|
111
113
|
setFocusOptionIdx(options[nextItemIndex].dsId);
|
|
114
|
+
scrollOptionIntoView(options[nextItemIndex].dsId);
|
|
112
115
|
}
|
|
113
116
|
}
|
|
114
117
|
|
|
@@ -120,11 +123,13 @@ const useKeyboardNavigation = () => {
|
|
|
120
123
|
|
|
121
124
|
if (showPopover || inline) {
|
|
122
125
|
setFocusOptionIdx(options[prevItemIndex].dsId);
|
|
126
|
+
scrollOptionIntoView(options[prevItemIndex].dsId);
|
|
123
127
|
} else {
|
|
124
128
|
setShowPopover(true);
|
|
125
129
|
setTimeout(() => {
|
|
126
|
-
const
|
|
127
|
-
setFocusOptionIdx(options[
|
|
130
|
+
const prevItem = findInCircularList(options, 0, isOptionFocuseable, -1);
|
|
131
|
+
setFocusOptionIdx(options[prevItem].dsId);
|
|
132
|
+
scrollOptionIntoView(options[prevItem].dsId);
|
|
128
133
|
});
|
|
129
134
|
}
|
|
130
135
|
} // =============================================================================
|
|
@@ -133,10 +138,10 @@ const useKeyboardNavigation = () => {
|
|
|
133
138
|
|
|
134
139
|
|
|
135
140
|
if (e.key === 'Backspace' && inputValue.length <= 0 && !inline) {
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
onChange(
|
|
141
|
+
const lastValue = getLastValueSelected(selectedValues);
|
|
142
|
+
|
|
143
|
+
if (!inputValue && lastValue) {
|
|
144
|
+
onChange(getSuggestedValueOnChange(lastValue, selectedValues), lastValue, e);
|
|
140
145
|
}
|
|
141
146
|
|
|
142
147
|
if (onFilter) onFilter('');
|
|
@@ -155,7 +160,8 @@ const useKeyboardNavigation = () => {
|
|
|
155
160
|
// if (e.key === 'Tab' && multiple) {
|
|
156
161
|
// }
|
|
157
162
|
|
|
158
|
-
},
|
|
163
|
+
}, // eslint-disable-next-line react-hooks/exhaustive-deps
|
|
164
|
+
[onKeyDown, currentItem, onCreate, multiple, inputValue, inline, withoutPortal, setShowPopover, onCancel, onFilter, setInputValue, focusOptionIdx, showPopover, selectableOptions.length, options, currentItemIndex, setFocusOptionIdx, selectedValues, onChange, selectAllCheckboxRef, toggleSelectionButtonRef]);
|
|
159
165
|
return {
|
|
160
166
|
onInputKeyDown
|
|
161
167
|
};
|
|
@@ -13,9 +13,8 @@ var _StyledNoOptionsSelec;
|
|
|
13
13
|
const HeaderList = () => {
|
|
14
14
|
const {
|
|
15
15
|
props: {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
selectedValues
|
|
16
|
+
selectedValues,
|
|
17
|
+
onSelectAll
|
|
19
18
|
},
|
|
20
19
|
showSelectedOptions,
|
|
21
20
|
selectAllCheckboxRef,
|
|
@@ -34,7 +33,7 @@ const HeaderList = () => {
|
|
|
34
33
|
return /*#__PURE__*/_jsx(StyledHeaderListWrapper, {
|
|
35
34
|
onKeyDown: handleKeyDown,
|
|
36
35
|
onMouseDown: handleOnMouseDown
|
|
37
|
-
}, void 0, /*#__PURE__*/_jsx(StyledSelectAllCheckbox, {}, void 0, onSelectAll &&
|
|
36
|
+
}, void 0, /*#__PURE__*/_jsx(StyledSelectAllCheckbox, {}, void 0, onSelectAll && /*#__PURE__*/_jsx(DSControlledCheckbox, {
|
|
38
37
|
checked: checkboxStatus,
|
|
39
38
|
"aria-controls": checkboxStatus === 'mixed' ? multiSelectedValues.map(item => item.dsId).join(' ') : '',
|
|
40
39
|
name: "select-all-checkbox",
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import
|
|
1
|
+
import 'core-js/modules/web.dom-collections.iterator.js';
|
|
2
|
+
import 'core-js/modules/esnext.async-iterator.filter.js';
|
|
3
|
+
import 'core-js/modules/esnext.iterator.constructor.js';
|
|
4
|
+
import 'core-js/modules/esnext.iterator.filter.js';
|
|
5
|
+
import { useContext, useMemo, useState, useEffect, useCallback } from 'react';
|
|
2
6
|
import { getSelectableOptions } from '../../utils/listHelper.js';
|
|
3
7
|
import { ComboBoxContext } from '../../ComboBoxCTX.js';
|
|
4
8
|
|
|
@@ -8,7 +12,6 @@ const useHeaderListHandlers = () => {
|
|
|
8
12
|
selectedValues,
|
|
9
13
|
options,
|
|
10
14
|
onSelectAll,
|
|
11
|
-
onClearAll,
|
|
12
15
|
innerRef
|
|
13
16
|
},
|
|
14
17
|
showSelectedOptions,
|
|
@@ -17,8 +20,8 @@ const useHeaderListHandlers = () => {
|
|
|
17
20
|
} = useContext(ComboBoxContext);
|
|
18
21
|
const multiSelectedValues = selectedValues;
|
|
19
22
|
const selectableOptions = getSelectableOptions(options);
|
|
20
|
-
const
|
|
21
|
-
if (
|
|
23
|
+
const getCheckboxStatus = useMemo(() => {
|
|
24
|
+
if (multiSelectedValues.length === selectableOptions.length) {
|
|
22
25
|
return true;
|
|
23
26
|
}
|
|
24
27
|
|
|
@@ -27,17 +30,23 @@ const useHeaderListHandlers = () => {
|
|
|
27
30
|
}
|
|
28
31
|
|
|
29
32
|
return 'mixed';
|
|
30
|
-
}, [multiSelectedValues, selectableOptions]);
|
|
33
|
+
}, [multiSelectedValues.length, selectableOptions.length]);
|
|
34
|
+
const [checkboxStatus, setCheckboxStatus] = useState(false);
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
setCheckboxStatus(getCheckboxStatus);
|
|
37
|
+
}, [getCheckboxStatus, multiSelectedValues]);
|
|
31
38
|
const handleOnMouseDown = useCallback(e => {
|
|
32
39
|
e.preventDefault(); // this prevent the input control to lose focus
|
|
33
40
|
}, []);
|
|
34
|
-
const handleSelectAllCheckboxChange = useCallback(
|
|
41
|
+
const handleSelectAllCheckboxChange = useCallback(e => {
|
|
35
42
|
if ((!checkboxStatus || checkboxStatus === 'mixed') && onSelectAll) {
|
|
36
|
-
onSelectAll();
|
|
37
|
-
|
|
38
|
-
|
|
43
|
+
onSelectAll(options.filter(option => option.type === 'option' && !option.disabled), e);
|
|
44
|
+
setCheckboxStatus(true);
|
|
45
|
+
} else if (onSelectAll) {
|
|
46
|
+
onSelectAll([], e);
|
|
47
|
+
setCheckboxStatus(false);
|
|
39
48
|
}
|
|
40
|
-
}, [checkboxStatus, onSelectAll,
|
|
49
|
+
}, [checkboxStatus, onSelectAll, options]);
|
|
41
50
|
const handleToggleSelectedValuesFilter = useCallback(e => {
|
|
42
51
|
e.preventDefault();
|
|
43
52
|
setShowSelectedOptions(!showSelectedOptions);
|
|
@@ -5,7 +5,6 @@ import { ComboboxDataTestid } from '../../ComboboxDataTestids.js';
|
|
|
5
5
|
import { ComboBoxContext } from '../../ComboBoxCTX.js';
|
|
6
6
|
import { HeaderList } from '../header-list/HeaderList.js';
|
|
7
7
|
import { useItemRenderer } from './useItemRenderer.js';
|
|
8
|
-
import { useMenuListSetFocusOption } from './useMenuListSetFocusOption.js';
|
|
9
8
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
10
9
|
|
|
11
10
|
var _HeaderList, _StyledNoResultsWrapp;
|
|
@@ -28,7 +27,6 @@ const MenuList = () => {
|
|
|
28
27
|
const multiple = Array.isArray(selectedValues);
|
|
29
28
|
const withHeader = !inline && multiple && options.length > 0 && inputValue === '';
|
|
30
29
|
const ItemRenderer = useItemRenderer();
|
|
31
|
-
useMenuListSetFocusOption();
|
|
32
30
|
const preventLoseInputFocus = useCallback(e => {
|
|
33
31
|
e.preventDefault();
|
|
34
32
|
}, []);
|
|
@@ -12,7 +12,7 @@ import { Grid } from '@elliemae/ds-grid';
|
|
|
12
12
|
import { Section, Separator, SingleMenuItem, MultiMenuItem } from '@elliemae/ds-form';
|
|
13
13
|
import { ComboBoxContext } from '../../ComboBoxCTX.js';
|
|
14
14
|
import { StyledCreatableLabel } from './styled.js';
|
|
15
|
-
import { isSelected } from '../../utils/listHelper.js';
|
|
15
|
+
import { getSuggestedValueOnChange, isSelected } from '../../utils/listHelper.js';
|
|
16
16
|
import { ComboboxDataTestid } from '../../ComboboxDataTestids.js';
|
|
17
17
|
import { INTERNAL_MENU_OPTION_TYPES, MENU_OPTION_TYPES } from '../../constants.js';
|
|
18
18
|
import { jsx, Fragment } from 'react/jsx-runtime';
|
|
@@ -47,28 +47,23 @@ const useItemRenderer = () => {
|
|
|
47
47
|
setInputValue('');
|
|
48
48
|
onFilter('');
|
|
49
49
|
}
|
|
50
|
+
} else if (option.type === MENU_OPTION_TYPES.OPTION) {
|
|
51
|
+
if (!option.disabled) {
|
|
52
|
+
if (onFilter) onFilter('');
|
|
53
|
+
setInputValue('');
|
|
50
54
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
if (!option.disabled) {
|
|
55
|
-
var _innerRef$current;
|
|
55
|
+
if (!multiple) {
|
|
56
|
+
setShowPopover(false);
|
|
57
|
+
}
|
|
56
58
|
|
|
57
|
-
|
|
58
|
-
setShowPopover(false);
|
|
59
|
+
onChange(getSuggestedValueOnChange(option, selectedValues), option, e);
|
|
59
60
|
}
|
|
60
|
-
|
|
61
|
-
if (onFilter) onFilter('');
|
|
62
|
-
setInputValue('');
|
|
63
|
-
onChange(option); // if we are focus in the header list we go back to the input
|
|
64
|
-
|
|
65
|
-
(_innerRef$current = innerRef.current) === null || _innerRef$current === void 0 ? void 0 : _innerRef$current.focus();
|
|
66
61
|
} // prevent for loosing focus on input control
|
|
67
62
|
|
|
68
63
|
|
|
69
64
|
e.stopPropagation();
|
|
70
65
|
e.preventDefault();
|
|
71
|
-
}, [onFilter, onChange, setShowPopover, multiple, innerRef]); // prevent blur from controls input
|
|
66
|
+
}, [onFilter, selectedValues, onChange, setShowPopover, multiple, innerRef]); // prevent blur from controls input
|
|
72
67
|
|
|
73
68
|
const handleOnMouseDown = useCallback(e => {
|
|
74
69
|
e.preventDefault();
|
|
@@ -6,14 +6,13 @@ import { DSPillGroupV2, DSPillV2 } from '@elliemae/ds-pills';
|
|
|
6
6
|
import { ComboBoxContext } from '../../ComboBoxCTX.js';
|
|
7
7
|
import { useGroupPills } from './useGroupPills.js';
|
|
8
8
|
import { ComboboxDataTestid } from '../../ComboboxDataTestids.js';
|
|
9
|
+
import { RemovableSelectedValuePill } from './RemovableSelectedValuePill.js';
|
|
9
10
|
|
|
10
11
|
const MultiSelectedValuesContainer = () => {
|
|
11
12
|
const {
|
|
12
13
|
props: {
|
|
13
14
|
selectedValues,
|
|
14
|
-
disabled
|
|
15
|
-
onChange,
|
|
16
|
-
innerRef
|
|
15
|
+
disabled
|
|
17
16
|
},
|
|
18
17
|
pillGroupRef
|
|
19
18
|
} = useContext(ComboBoxContext); // this is always an array because logic in controls component
|
|
@@ -27,25 +26,15 @@ const MultiSelectedValuesContainer = () => {
|
|
|
27
26
|
"data-testid": ComboboxDataTestid.SELECTED_VALUES
|
|
28
27
|
}, void 0, /*#__PURE__*/_jsx(DSPillGroupV2, {
|
|
29
28
|
innerRef: pillGroupRef
|
|
30
|
-
}, void 0, multiSelectedValue.length > 0 && multiSelectedValue.slice(0, correctPillsToShow).map(
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
disabled: disabled,
|
|
34
|
-
type: disabled ? 'value' : 'removable',
|
|
35
|
-
tabIndex: -1,
|
|
36
|
-
onRemove: () => {
|
|
37
|
-
var _innerRef$current;
|
|
38
|
-
|
|
39
|
-
onChange(option);
|
|
40
|
-
(_innerRef$current = innerRef.current) === null || _innerRef$current === void 0 ? void 0 : _innerRef$current.focus();
|
|
41
|
-
}
|
|
42
|
-
}, option.value)), multiSelectedValue.length > 0 && correctPillsToShow !== multiSelectedValue.length && /*#__PURE__*/_jsx(DSPillV2, {
|
|
29
|
+
}, void 0, multiSelectedValue.length > 0 && multiSelectedValue.slice(0, correctPillsToShow).map(pill => /*#__PURE__*/_jsx(RemovableSelectedValuePill, {
|
|
30
|
+
pill: pill
|
|
31
|
+
}, pill.dsId)), multiSelectedValue.length > 0 && correctPillsToShow !== multiSelectedValue.length && /*#__PURE__*/_jsx(DSPillV2, {
|
|
43
32
|
size: "s",
|
|
44
33
|
labelTruncated: false,
|
|
45
34
|
label: "+".concat(multiSelectedValue.length - correctPillsToShow),
|
|
46
35
|
type: "value",
|
|
47
36
|
disabled: disabled
|
|
48
|
-
}, "grouped"))), [pillGroupRef, multiSelectedValue, correctPillsToShow, disabled
|
|
37
|
+
}, "grouped"))), [pillGroupRef, multiSelectedValue, correctPillsToShow, disabled]);
|
|
49
38
|
};
|
|
50
39
|
|
|
51
40
|
export { MultiSelectedValuesContainer };
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import _jsx from '@babel/runtime/helpers/esm/jsx';
|
|
2
|
+
import { useContext } from 'react';
|
|
3
|
+
import { DSPillV2 } from '@elliemae/ds-pills';
|
|
4
|
+
import { ComboBoxContext } from '../../ComboBoxCTX.js';
|
|
5
|
+
import { getSuggestedValueOnChange } from '../../utils/listHelper.js';
|
|
6
|
+
|
|
7
|
+
const RemovableSelectedValuePill = props => {
|
|
8
|
+
const {
|
|
9
|
+
pill
|
|
10
|
+
} = props;
|
|
11
|
+
const {
|
|
12
|
+
props: {
|
|
13
|
+
onChange,
|
|
14
|
+
disabled,
|
|
15
|
+
selectedValues,
|
|
16
|
+
innerRef
|
|
17
|
+
}
|
|
18
|
+
} = useContext(ComboBoxContext);
|
|
19
|
+
return /*#__PURE__*/_jsx(DSPillV2, {
|
|
20
|
+
size: "s",
|
|
21
|
+
label: pill.label,
|
|
22
|
+
disabled: disabled,
|
|
23
|
+
type: disabled ? 'value' : 'removable',
|
|
24
|
+
tabIndex: -1,
|
|
25
|
+
onRemove: e => {
|
|
26
|
+
var _innerRef$current;
|
|
27
|
+
|
|
28
|
+
onChange(getSuggestedValueOnChange(pill, selectedValues), pill, e);
|
|
29
|
+
(_innerRef$current = innerRef.current) === null || _innerRef$current === void 0 ? void 0 : _innerRef$current.focus();
|
|
30
|
+
}
|
|
31
|
+
}, pill.value);
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export { RemovableSelectedValuePill };
|
|
@@ -18,10 +18,8 @@ const ComboboxPropTypes = _objectSpread(_objectSpread({}, globalAttributesPropTy
|
|
|
18
18
|
autoFocus: PropTypes.bool.description('Whether the combo box uses auto focus or not').defaultValue('false'),
|
|
19
19
|
hasError: PropTypes.bool.description('Whether the combo box has error or not').defaultValue('false'),
|
|
20
20
|
onChange: PropTypes.func.isRequired.description('function triggered when an option is selected it will send the options selected').defaultValue('() => {}'),
|
|
21
|
-
onSelectAll: PropTypes.func.description('function triggered when ALL button is selected from the header menu list').defaultValue('() => {}'),
|
|
22
21
|
onFilter: PropTypes.func.description('function triggered when user type in the combobox input').defaultValue(''),
|
|
23
22
|
onCreate: PropTypes.func.description('function triggered when user select "create" a new item whenever is not a match in the all option list').defaultValue(''),
|
|
24
|
-
onClearAll: PropTypes.func.description('function triggered when user select CLEAR button from the header menu list').defaultValue(''),
|
|
25
23
|
onCancel: PropTypes.func.description('function triggered when user press ESC key').defaultValue('() => {}'),
|
|
26
24
|
onMenuOpen: PropTypes.func.description('function triggered when user open the menu list').defaultValue('() => {}'),
|
|
27
25
|
onMenuClose: PropTypes.func.description('function triggered when user close the menu list').defaultValue('() => {}'),
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { MENU_OPTION_TYPES } from './constants.js';
|
|
2
2
|
|
|
3
|
-
const isSeparator = el => (el === null || el === void 0 ? void 0 : el.type) === MENU_OPTION_TYPES.
|
|
3
|
+
const isSeparator = el => (el === null || el === void 0 ? void 0 : el.type) === MENU_OPTION_TYPES.SEPARATOR;
|
|
4
|
+
const isOption = el => (el === null || el === void 0 ? void 0 : el.type) === MENU_OPTION_TYPES.OPTION;
|
|
4
5
|
|
|
5
|
-
export { isSeparator };
|
|
6
|
+
export { isOption, isSeparator };
|
|
@@ -3,6 +3,9 @@ import 'core-js/modules/esnext.iterator.constructor.js';
|
|
|
3
3
|
import 'core-js/modules/esnext.iterator.filter.js';
|
|
4
4
|
import 'core-js/modules/esnext.async-iterator.some.js';
|
|
5
5
|
import 'core-js/modules/esnext.iterator.some.js';
|
|
6
|
+
import 'core-js/modules/esnext.async-iterator.find.js';
|
|
7
|
+
import 'core-js/modules/esnext.iterator.find.js';
|
|
8
|
+
import 'core-js/modules/web.dom-collections.iterator.js';
|
|
6
9
|
import { MENU_OPTION_TYPES } from '../constants.js';
|
|
7
10
|
|
|
8
11
|
const getSelectableOptions = options => options.filter(option => option.type === MENU_OPTION_TYPES.OPTION && !option.disabled);
|
|
@@ -27,5 +30,46 @@ const findInCircularList = function (list, from, criteria) {
|
|
|
27
30
|
|
|
28
31
|
return from; // return same item
|
|
29
32
|
};
|
|
33
|
+
const getFirstOption = (options, selectedValues, inputValue) => {
|
|
34
|
+
if (!inputValue) {
|
|
35
|
+
if (Array.isArray(selectedValues) && selectedValues.length > 0) {
|
|
36
|
+
return selectedValues[selectedValues.length - 1].dsId;
|
|
37
|
+
}
|
|
30
38
|
|
|
31
|
-
|
|
39
|
+
if (selectedValues !== null && selectedValues !== void 0 && selectedValues.dsId) {
|
|
40
|
+
return selectedValues.dsId;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
for (let i = 0; i < options.length; i += 1) if (!['section', 'separator'].includes(options[i].type) && !options[i].disabled) {
|
|
45
|
+
return options[i].dsId;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return '';
|
|
49
|
+
};
|
|
50
|
+
const getSuggestedValueOnChange = (selectedOption, selectedValues) => {
|
|
51
|
+
if (Array.isArray(selectedValues)) {
|
|
52
|
+
const isFound = selectedValues.find(item => item.type === 'option' && item.value === selectedOption.value);
|
|
53
|
+
|
|
54
|
+
if (isFound) {
|
|
55
|
+
return selectedValues.filter(item => item.type === 'option' && item.value !== selectedOption.value);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return [...selectedValues, selectedOption];
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (selectedValues && selectedValues.dsId === selectedOption.dsId) {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return selectedOption;
|
|
66
|
+
};
|
|
67
|
+
const getLastValueSelected = selectedValues => {
|
|
68
|
+
if (Array.isArray(selectedValues)) {
|
|
69
|
+
return selectedValues[selectedValues.length - 1];
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return selectedValues;
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
export { findInCircularList, getFirstOption, getLastValueSelected, getOptions, getSelectableOptions, getSuggestedValueOnChange, isSelected, isSelectedValueEmpty, isSelectedValueMultiple };
|
|
@@ -26,24 +26,16 @@ const conformValue = (rawValue, cursorPos, lastKeyCode, opts) => {
|
|
|
26
26
|
decimalRequired
|
|
27
27
|
} = opts;
|
|
28
28
|
const THOUSANDSSEPARATOR = ',';
|
|
29
|
-
let dotIdx = -1;
|
|
30
|
-
let isNegative = false;
|
|
31
|
-
let finalPrefix = ''; // Work with digits and dots only
|
|
29
|
+
let dotIdx = -1; // allow minus sign before and after the preffix
|
|
32
30
|
|
|
31
|
+
let finalPrefix = [prefix.length, 0].includes(rawValue.indexOf('-')) && allowNegative ? '-' : '';
|
|
33
32
|
let maskedValue = rawValue.split('').filter((char, idx) => {
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
// we take only the first dot
|
|
34
|
+
const validChar = char >= '0' && char <= '9' || char === '.' && dotIdx === -1 && decimalPlaces;
|
|
36
35
|
if (char === '.' && validChar) dotIdx = idx;
|
|
37
|
-
|
|
38
|
-
if (char === '-' && validChar) {
|
|
39
|
-
isNegative = true;
|
|
40
|
-
finalPrefix += '-';
|
|
41
|
-
return false;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
36
|
return validChar;
|
|
45
37
|
});
|
|
46
|
-
if (prefix) finalPrefix += prefix; // REMOVE FOLLOWING ZEROS IN INTEGER PART AFTER LEADER ZERO NUMBER
|
|
38
|
+
if (prefix && maskedValue.length) finalPrefix += prefix; // REMOVE FOLLOWING ZEROS IN INTEGER PART AFTER LEADER ZERO NUMBER
|
|
47
39
|
|
|
48
40
|
while (maskedValue.length >= 2 && maskedValue[0] === '0' && maskedValue[1] !== '.') {
|
|
49
41
|
maskedValue = maskedValue.splice(1);
|
|
@@ -59,18 +51,26 @@ const conformValue = (rawValue, cursorPos, lastKeyCode, opts) => {
|
|
|
59
51
|
|
|
60
52
|
|
|
61
53
|
if (dotIdx !== -1 && !(lastKeyCode === 'Backspace' && decimal.length === 1)) {
|
|
62
|
-
|
|
54
|
+
if (integer.length) {
|
|
55
|
+
maskedValue = [...integer, ...decimal];
|
|
56
|
+
} else {
|
|
57
|
+
// if theres no integer add a zero to the left of the dot to cover .23 => 0.23 case
|
|
58
|
+
maskedValue = ['0', ...decimal];
|
|
59
|
+
}
|
|
63
60
|
} else {
|
|
64
61
|
// If decimal is required we add a dot after integer if exists
|
|
65
62
|
maskedValue = decimalRequired && integer.length ? [...integer, '.'] : integer;
|
|
66
|
-
}
|
|
63
|
+
} // remove orphans prefix for example "-$"
|
|
64
|
+
|
|
67
65
|
|
|
68
66
|
if (lastKeyCode === 'Backspace' && maskedValue.length === 0) {
|
|
69
67
|
finalPrefix = '';
|
|
70
|
-
} // SET REAL CURSOR POSITION AFTER ADDING
|
|
68
|
+
} // SET REAL CURSOR POSITION AFTER ADDING DOT and COMMAS SEPARATORS
|
|
69
|
+
|
|
71
70
|
|
|
71
|
+
let maskedPos = 0; // 0 leading case we move the cursor to continue typing
|
|
72
72
|
|
|
73
|
-
|
|
73
|
+
if (maskedValue[maskedPos] === '0' && cursorPos === 1 + prefix.length) maskedPos += 1;
|
|
74
74
|
|
|
75
75
|
for (let i = 0; i < cursorPos; i += 1) {
|
|
76
76
|
if (maskedValue[maskedPos] === THOUSANDSSEPARATOR) maskedPos += 1;
|
|
@@ -106,6 +106,7 @@ const useNumberMask = props => {
|
|
|
106
106
|
const onBlur = useCallback(e => {
|
|
107
107
|
const maskedValue = e.target.value;
|
|
108
108
|
const dotIdx = maskedValue.indexOf('.');
|
|
109
|
+
const minusIndex = maskedValue.indexOf('-');
|
|
109
110
|
const {
|
|
110
111
|
decimalRequired,
|
|
111
112
|
decimalPlaces,
|
|
@@ -126,6 +127,9 @@ const useNumberMask = props => {
|
|
|
126
127
|
} else if (maskedValue.length - suffix.length - 1 === dotIdx) {
|
|
127
128
|
// removing orphans dots
|
|
128
129
|
valueSetter(maskedValue.replace('.', ''));
|
|
130
|
+
} else if (maskedValue.length - 1 === minusIndex) {
|
|
131
|
+
// removing orphans minus
|
|
132
|
+
valueSetter(maskedValue.replace('-', ''));
|
|
129
133
|
}
|
|
130
134
|
|
|
131
135
|
if (userOnBlur) userOnBlur(e);
|
|
@@ -13,7 +13,7 @@ import { DSMaskPhoneHookPropsTypes, DSMaskPhoneHookDefaultProps } from '../react
|
|
|
13
13
|
|
|
14
14
|
const _excluded = ["valueSetter", "onChange", "onKeyDown", "onBlur"];
|
|
15
15
|
const phoneSpecialChars = [['(', 0], [') ', 4], ['-', 9]];
|
|
16
|
-
const internationalPhoneSpecialChars = [['+1 (', 0], [') ', 7], ['-',
|
|
16
|
+
const internationalPhoneSpecialChars = [['+1 (', 0], [') ', 7], ['-', 12]];
|
|
17
17
|
|
|
18
18
|
const conformValue = (rawValue, cursorPos, lastKeyCode, opts) => {
|
|
19
19
|
const characters = rawValue.split(''); // Work with digits only
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elliemae/ds-controlled-form",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.0-rc.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "ICE MT - Dimsum - Controlled Form Controllers",
|
|
6
6
|
"module": "./esm/index.js",
|
|
@@ -499,14 +499,6 @@
|
|
|
499
499
|
"import": "./esm/combobox/utils/listHelper.js",
|
|
500
500
|
"require": "./cjs/combobox/utils/listHelper.js"
|
|
501
501
|
},
|
|
502
|
-
"./combobox/utils/hooks/useOnElementResize": {
|
|
503
|
-
"import": "./esm/combobox/utils/hooks/useOnElementResize.js",
|
|
504
|
-
"require": "./cjs/combobox/utils/hooks/useOnElementResize.js"
|
|
505
|
-
},
|
|
506
|
-
"./combobox/utils/hooks/useKeyboardNavigation": {
|
|
507
|
-
"import": "./esm/combobox/utils/hooks/useKeyboardNavigation.js",
|
|
508
|
-
"require": "./cjs/combobox/utils/hooks/useKeyboardNavigation.js"
|
|
509
|
-
},
|
|
510
502
|
"./combobox/tests/utils": {
|
|
511
503
|
"import": "./esm/combobox/tests/utils.js",
|
|
512
504
|
"require": "./cjs/combobox/tests/utils.js"
|
|
@@ -527,6 +519,10 @@
|
|
|
527
519
|
"import": "./esm/combobox/parts/multi-selected-values-container/useGroupPills.js",
|
|
528
520
|
"require": "./cjs/combobox/parts/multi-selected-values-container/useGroupPills.js"
|
|
529
521
|
},
|
|
522
|
+
"./combobox/parts/multi-selected-values-container/RemovableSelectedValuePill": {
|
|
523
|
+
"import": "./esm/combobox/parts/multi-selected-values-container/RemovableSelectedValuePill.js",
|
|
524
|
+
"require": "./cjs/combobox/parts/multi-selected-values-container/RemovableSelectedValuePill.js"
|
|
525
|
+
},
|
|
530
526
|
"./combobox/parts/multi-selected-values-container/MultiSelectedValuesContainer": {
|
|
531
527
|
"import": "./esm/combobox/parts/multi-selected-values-container/MultiSelectedValuesContainer.js",
|
|
532
528
|
"require": "./cjs/combobox/parts/multi-selected-values-container/MultiSelectedValuesContainer.js"
|
|
@@ -707,6 +703,14 @@
|
|
|
707
703
|
"import": "./esm/autocomplete/utils/hooks/useKeyboardNavigation.js",
|
|
708
704
|
"require": "./cjs/autocomplete/utils/hooks/useKeyboardNavigation.js"
|
|
709
705
|
},
|
|
706
|
+
"./autocomplete/sharedTypes": {
|
|
707
|
+
"import": "./esm/autocomplete/sharedTypes.js",
|
|
708
|
+
"require": "./cjs/autocomplete/sharedTypes.js"
|
|
709
|
+
},
|
|
710
|
+
"./autocomplete/react-desc-prop-types": {
|
|
711
|
+
"import": "./esm/autocomplete/react-desc-prop-types.js",
|
|
712
|
+
"require": "./cjs/autocomplete/react-desc-prop-types.js"
|
|
713
|
+
},
|
|
710
714
|
"./autocomplete/propTypes": {
|
|
711
715
|
"import": "./esm/autocomplete/propTypes.js",
|
|
712
716
|
"require": "./cjs/autocomplete/propTypes.js"
|
|
@@ -731,6 +735,14 @@
|
|
|
731
735
|
"import": "./esm/autocomplete/parts/menu-list/index.js",
|
|
732
736
|
"require": "./cjs/autocomplete/parts/menu-list/index.js"
|
|
733
737
|
},
|
|
738
|
+
"./autocomplete/parts/controls/useMaskedOnChange": {
|
|
739
|
+
"import": "./esm/autocomplete/parts/controls/useMaskedOnChange.js",
|
|
740
|
+
"require": "./cjs/autocomplete/parts/controls/useMaskedOnChange.js"
|
|
741
|
+
},
|
|
742
|
+
"./autocomplete/parts/controls/useKeyboardNavigation": {
|
|
743
|
+
"import": "./esm/autocomplete/parts/controls/useKeyboardNavigation.js",
|
|
744
|
+
"require": "./cjs/autocomplete/parts/controls/useKeyboardNavigation.js"
|
|
745
|
+
},
|
|
734
746
|
"./autocomplete/parts/controls/useControlsInput": {
|
|
735
747
|
"import": "./esm/autocomplete/parts/controls/useControlsInput.js",
|
|
736
748
|
"require": "./cjs/autocomplete/parts/controls/useControlsInput.js"
|
|
@@ -824,20 +836,20 @@
|
|
|
824
836
|
"build": "node ../../scripts/build/build.js"
|
|
825
837
|
},
|
|
826
838
|
"dependencies": {
|
|
827
|
-
"@elliemae/ds-button": "2.
|
|
828
|
-
"@elliemae/ds-circular-progress-indicator": "2.
|
|
829
|
-
"@elliemae/ds-controlled-form": "2.
|
|
830
|
-
"@elliemae/ds-form": "2.
|
|
831
|
-
"@elliemae/ds-form-layout-blocks": "2.
|
|
832
|
-
"@elliemae/ds-grid": "2.
|
|
833
|
-
"@elliemae/ds-icon": "2.
|
|
834
|
-
"@elliemae/ds-icons": "2.
|
|
835
|
-
"@elliemae/ds-pills": "2.
|
|
836
|
-
"@elliemae/ds-popperjs": "2.
|
|
837
|
-
"@elliemae/ds-props-helpers": "2.
|
|
838
|
-
"@elliemae/ds-system": "2.
|
|
839
|
-
"@elliemae/ds-tooltip": "2.
|
|
840
|
-
"@elliemae/ds-truncated-tooltip-text": "2.
|
|
839
|
+
"@elliemae/ds-button": "2.4.0-rc.0",
|
|
840
|
+
"@elliemae/ds-circular-progress-indicator": "2.4.0-rc.0",
|
|
841
|
+
"@elliemae/ds-controlled-form": "2.4.0-rc.0",
|
|
842
|
+
"@elliemae/ds-form": "2.4.0-rc.0",
|
|
843
|
+
"@elliemae/ds-form-layout-blocks": "2.4.0-rc.0",
|
|
844
|
+
"@elliemae/ds-grid": "2.4.0-rc.0",
|
|
845
|
+
"@elliemae/ds-icon": "2.4.0-rc.0",
|
|
846
|
+
"@elliemae/ds-icons": "2.4.0-rc.0",
|
|
847
|
+
"@elliemae/ds-pills": "2.4.0-rc.0",
|
|
848
|
+
"@elliemae/ds-popperjs": "2.4.0-rc.0",
|
|
849
|
+
"@elliemae/ds-props-helpers": "2.4.0-rc.0",
|
|
850
|
+
"@elliemae/ds-system": "2.4.0-rc.0",
|
|
851
|
+
"@elliemae/ds-tooltip": "2.4.0-rc.0",
|
|
852
|
+
"@elliemae/ds-truncated-tooltip-text": "2.4.0-rc.0",
|
|
841
853
|
"prop-types": "~15.7.2",
|
|
842
854
|
"react-desc": "~4.1.3",
|
|
843
855
|
"react-popper": "~2.2.5",
|