@onewelcome/react-lib-components 0.2.6 → 1.0.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/LICENSE +202 -21
- package/dist/Breadcrumbs/Breadcrumbs.d.ts +2 -2
- package/dist/Button/BaseButton.d.ts +1 -1
- package/dist/Button/Button.d.ts +1 -1
- package/dist/Button/IconButton.d.ts +1 -1
- package/dist/ContextMenu/ContextMenu.d.ts +1 -1
- package/dist/ContextMenu/ContextMenuItem.d.ts +1 -1
- package/dist/DataGrid/DataGridActions/DataGridActions.d.ts +1 -1
- package/dist/DataGrid/DataGridActions/DataGridColumnsToggle.d.ts +1 -1
- package/dist/DataGrid/DataGridBody/DataGridCell.d.ts +1 -1
- package/dist/DataGrid/DataGridBody/DataGridRow.d.ts +1 -1
- package/dist/DataGrid/DataGridHeader/DataGridHeader.d.ts +1 -1
- package/dist/DataGrid/DataGridHeader/DataGridHeaderCell.d.ts +1 -1
- package/dist/Form/Checkbox/Checkbox.d.ts +1 -1
- package/dist/Form/Fieldset/Fieldset.d.ts +1 -1
- package/dist/Form/FormControl/FormControl.d.ts +1 -1
- package/dist/Form/FormGroup/FormGroup.d.ts +1 -1
- package/dist/Form/FormHelperText/FormHelperText.d.ts +1 -1
- package/dist/Form/FormSelectorWrapper/FormSelectorWrapper.d.ts +1 -1
- package/dist/Form/Input/Input.d.ts +2 -3
- package/dist/Form/Label/Label.d.ts +1 -1
- package/dist/Form/Radio/Radio.d.ts +1 -1
- package/dist/Form/Select/Option.d.ts +1 -1
- package/dist/Form/Select/Select.d.ts +1 -2
- package/dist/Form/Select/Select.interfaces.d.ts +22 -0
- package/dist/Form/Select/SelectService.d.ts +12 -0
- package/dist/Form/Textarea/Textarea.d.ts +1 -1
- package/dist/Form/Toggle/Toggle.d.ts +1 -1
- package/dist/Form/Wrapper/CheckboxWrapper/CheckboxWrapper.d.ts +1 -1
- package/dist/Form/Wrapper/InputWrapper/InputWrapper.d.ts +1 -1
- package/dist/Form/Wrapper/RadioWrapper/RadioWrapper.d.ts +1 -1
- package/dist/Form/Wrapper/SelectWrapper/SelectWrapper.d.ts +1 -2
- package/dist/Form/Wrapper/TextareaWrapper/TextareaWrapper.d.ts +1 -1
- package/dist/Form/Wrapper/Wrapper/Wrapper.d.ts +1 -1
- package/dist/Icon/Icon.d.ts +1 -1
- package/dist/Link/Link.d.ts +3 -4
- package/dist/Notifications/BaseModal/BaseModal.d.ts +1 -1
- package/dist/Notifications/BaseModal/BaseModalActions/BaseModalActions.d.ts +2 -2
- package/dist/Notifications/BaseModal/BaseModalContent/BaseModalContent.d.ts +1 -1
- package/dist/Notifications/BaseModal/BaseModalHeader/BaseModalHeader.d.ts +2 -2
- package/dist/Notifications/Dialog/Dialog.d.ts +1 -1
- package/dist/Notifications/Dialog/DialogActions/DialogActions.d.ts +1 -1
- package/dist/Notifications/Dialog/DialogTitle/DialogTitle.d.ts +1 -1
- package/dist/Notifications/DiscardChangesModal/DiscardChangesDialog/DiscardChangesDialog.d.ts +1 -1
- package/dist/Notifications/SlideInModal/SlideInModal.d.ts +1 -1
- package/dist/Notifications/Snackbar/SnackbarProvider/SnackbarProvider.d.ts +11 -0
- package/dist/Notifications/Snackbar/SnackbarProvider/SnackbarStateProvider.d.ts +3 -0
- package/dist/Notifications/Snackbar/useSnackbar.d.ts +5 -1
- package/dist/Pagination/Pagination.d.ts +1 -1
- package/dist/Popover/Popover.d.ts +1 -1
- package/dist/Skeleton/Skeleton.d.ts +1 -1
- package/dist/StatusIndicator/StatusIndicator.d.ts +1 -1
- package/dist/Tabs/TabButton.d.ts +1 -1
- package/dist/Tabs/TabPanel.d.ts +1 -1
- package/dist/TextEllipsis/TextEllipsis.d.ts +1 -1
- package/dist/Tiles/Tile.d.ts +1 -1
- package/dist/Tiles/Tiles.d.ts +1 -1
- package/dist/Tooltip/Tooltip.d.ts +1 -1
- package/dist/Wizard/BaseWizardSteps/BaseWizardSteps.d.ts +1 -2
- package/dist/Wizard/Wizard.d.ts +0 -1
- package/dist/Wizard/WizardSteps/WizardSteps.d.ts +1 -1
- package/dist/Wizard/wizardStateReducer.d.ts +1 -3
- package/dist/_BaseStyling_/BaseStyling.d.ts +10 -4
- package/dist/react-lib-components.cjs.development.js +1171 -1565
- package/dist/react-lib-components.cjs.development.js.map +1 -1
- package/dist/react-lib-components.cjs.production.min.js +1 -1
- package/dist/react-lib-components.cjs.production.min.js.map +1 -1
- package/dist/react-lib-components.esm.js +1171 -1565
- package/dist/react-lib-components.esm.js.map +1 -1
- package/package.json +31 -24
- package/src/Breadcrumbs/Breadcrumbs.module.scss +16 -0
- package/src/Breadcrumbs/Breadcrumbs.test.tsx +17 -1
- package/src/Breadcrumbs/Breadcrumbs.tsx +18 -2
- package/src/Button/BaseButton.module.scss +16 -0
- package/src/Button/BaseButton.test.tsx +16 -0
- package/src/Button/BaseButton.tsx +16 -0
- package/src/Button/Button.module.scss +16 -0
- package/src/Button/Button.test.tsx +16 -0
- package/src/Button/Button.tsx +16 -0
- package/src/Button/IconButton.module.scss +16 -0
- package/src/Button/IconButton.test.tsx +16 -0
- package/src/Button/IconButton.tsx +16 -0
- package/src/ContextMenu/ContextMenu.module.scss +16 -0
- package/src/ContextMenu/ContextMenu.test.tsx +16 -0
- package/src/ContextMenu/ContextMenu.tsx +16 -0
- package/src/ContextMenu/ContextMenuItem.module.scss +16 -0
- package/src/ContextMenu/ContextMenuItem.tsx +16 -0
- package/src/DataGrid/DataGrid.module.scss +16 -0
- package/src/DataGrid/DataGrid.test.tsx +16 -0
- package/src/DataGrid/DataGrid.tsx +16 -0
- package/src/DataGrid/DataGridActions/DataGridActions.module.scss +16 -0
- package/src/DataGrid/DataGridActions/DataGridActions.test.tsx +16 -0
- package/src/DataGrid/DataGridActions/DataGridActions.tsx +16 -0
- package/src/DataGrid/DataGridActions/DataGridColumnsToggle.module.scss +16 -0
- package/src/DataGrid/DataGridActions/DataGridColumnsToggle.test.tsx +16 -0
- package/src/DataGrid/DataGridActions/DataGridColumnsToggle.tsx +16 -0
- package/src/DataGrid/DataGridBody/DataGridBody.module.scss +16 -0
- package/src/DataGrid/DataGridBody/DataGridBody.test.tsx +16 -0
- package/src/DataGrid/DataGridBody/DataGridBody.tsx +16 -0
- package/src/DataGrid/DataGridBody/DataGridCell.module.scss +16 -0
- package/src/DataGrid/DataGridBody/DataGridCell.test.tsx +16 -0
- package/src/DataGrid/DataGridBody/DataGridCell.tsx +16 -0
- package/src/DataGrid/DataGridBody/DataGridRow.module.scss +16 -0
- package/src/DataGrid/DataGridBody/DataGridRow.test.tsx +16 -0
- package/src/DataGrid/DataGridBody/DataGridRow.tsx +16 -0
- package/src/DataGrid/DataGridHeader/DataGridHeader.module.scss +17 -1
- package/src/DataGrid/DataGridHeader/DataGridHeader.test.tsx +16 -0
- package/src/DataGrid/DataGridHeader/DataGridHeader.tsx +16 -0
- package/src/DataGrid/DataGridHeader/DataGridHeaderCell.module.scss +16 -0
- package/src/DataGrid/DataGridHeader/DataGridHeaderCell.test.tsx +16 -0
- package/src/DataGrid/DataGridHeader/DataGridHeaderCell.tsx +16 -0
- package/src/DataGrid/datagrid.interfaces.ts +16 -0
- package/src/Form/Checkbox/Checkbox.module.scss +20 -6
- package/src/Form/Checkbox/Checkbox.test.tsx +16 -0
- package/src/Form/Checkbox/Checkbox.tsx +16 -0
- package/src/Form/Fieldset/Fieldset.module.scss +16 -0
- package/src/Form/Fieldset/Fieldset.test.tsx +16 -0
- package/src/Form/Fieldset/Fieldset.tsx +21 -3
- package/src/Form/Form.module.scss +16 -0
- package/src/Form/Form.test.tsx +16 -0
- package/src/Form/Form.tsx +16 -0
- package/src/Form/FormControl/FormControl.module.scss +16 -0
- package/src/Form/FormControl/FormControl.test.tsx +16 -0
- package/src/Form/FormControl/FormControl.tsx +16 -0
- package/src/Form/FormGroup/FormGroup.module.scss +16 -0
- package/src/Form/FormGroup/FormGroup.test.tsx +16 -0
- package/src/Form/FormGroup/FormGroup.tsx +17 -1
- package/src/Form/FormHelperText/FormHelperText.module.scss +16 -0
- package/src/Form/FormHelperText/FormHelperText.test.tsx +16 -0
- package/src/Form/FormHelperText/FormHelperText.tsx +16 -0
- package/src/Form/FormSelectorWrapper/FormSelectorWrapper.module.scss +16 -0
- package/src/Form/FormSelectorWrapper/FormSelectorWrapper.test.tsx +16 -0
- package/src/Form/FormSelectorWrapper/FormSelectorWrapper.tsx +16 -0
- package/src/Form/Input/Input.module.scss +65 -5
- package/src/Form/Input/Input.test.tsx +16 -0
- package/src/Form/Input/Input.tsx +19 -57
- package/src/Form/Label/Label.module.scss +16 -0
- package/src/Form/Label/Label.test.tsx +16 -0
- package/src/Form/Label/Label.tsx +16 -0
- package/src/Form/Radio/Radio.module.scss +20 -6
- package/src/Form/Radio/Radio.test.tsx +16 -0
- package/src/Form/Radio/Radio.tsx +16 -0
- package/src/Form/Select/Option.test.tsx +16 -0
- package/src/Form/Select/Option.tsx +16 -0
- package/src/Form/Select/Select.interfaces.ts +39 -0
- package/src/Form/Select/Select.module.scss +28 -13
- package/src/Form/Select/Select.test.tsx +16 -57
- package/src/Form/Select/Select.tsx +36 -190
- package/src/Form/Select/SelectService.ts +204 -0
- package/src/Form/Textarea/Textarea.module.scss +16 -0
- package/src/Form/Textarea/Textarea.test.tsx +16 -0
- package/src/Form/Textarea/Textarea.tsx +16 -0
- package/src/Form/Toggle/Toggle.module.scss +17 -1
- package/src/Form/Toggle/Toggle.test.tsx +16 -0
- package/src/Form/Toggle/Toggle.tsx +16 -0
- package/src/Form/Wrapper/CheckboxWrapper/CheckboxWrapper.module.scss +16 -0
- package/src/Form/Wrapper/CheckboxWrapper/CheckboxWrapper.test.tsx +16 -0
- package/src/Form/Wrapper/CheckboxWrapper/CheckboxWrapper.tsx +16 -0
- package/src/Form/Wrapper/InputWrapper/InputWrapper.module.scss +45 -14
- package/src/Form/Wrapper/InputWrapper/InputWrapper.test.tsx +36 -0
- package/src/Form/Wrapper/InputWrapper/InputWrapper.tsx +26 -4
- package/src/Form/Wrapper/RadioWrapper/RadioWrapper.module.scss +16 -0
- package/src/Form/Wrapper/RadioWrapper/RadioWrapper.test.tsx +16 -0
- package/src/Form/Wrapper/RadioWrapper/RadioWrapper.tsx +16 -0
- package/src/Form/Wrapper/SelectWrapper/SelectWrapper.module.scss +16 -0
- package/src/Form/Wrapper/SelectWrapper/SelectWrapper.test.tsx +17 -19
- package/src/Form/Wrapper/SelectWrapper/SelectWrapper.tsx +17 -15
- package/src/Form/Wrapper/TextareaWrapper/TextareaWrapper.module.scss +41 -33
- package/src/Form/Wrapper/TextareaWrapper/TextareaWrapper.test.tsx +16 -0
- package/src/Form/Wrapper/TextareaWrapper/TextareaWrapper.tsx +23 -7
- package/src/Form/Wrapper/Wrapper/Wrapper.module.scss +38 -18
- package/src/Form/Wrapper/Wrapper/Wrapper.test.tsx +16 -0
- package/src/Form/Wrapper/Wrapper/Wrapper.tsx +18 -1
- package/src/Form/form.interfaces.ts +16 -0
- package/src/Icon/Icon.module.scss +16 -0
- package/src/Icon/Icon.test.tsx +16 -0
- package/src/Icon/Icon.tsx +16 -0
- package/src/Link/Link.module.scss +21 -5
- package/src/Link/Link.test.tsx +16 -0
- package/src/Link/Link.tsx +18 -8
- package/src/Notifications/BaseModal/BaseModal.module.scss +16 -0
- package/src/Notifications/BaseModal/BaseModal.test.tsx +16 -0
- package/src/Notifications/BaseModal/BaseModal.tsx +16 -0
- package/src/Notifications/BaseModal/BaseModalActions/BaseModalActions.module.scss +16 -0
- package/src/Notifications/BaseModal/BaseModalActions/BaseModalActions.test.tsx +16 -0
- package/src/Notifications/BaseModal/BaseModalActions/BaseModalActions.tsx +20 -4
- package/src/Notifications/BaseModal/BaseModalContent/BaseModalContent.module.scss +16 -0
- package/src/Notifications/BaseModal/BaseModalContent/BaseModalContent.test.tsx +16 -0
- package/src/Notifications/BaseModal/BaseModalContent/BaseModalContent.tsx +16 -0
- package/src/Notifications/BaseModal/BaseModalContext.ts +16 -0
- package/src/Notifications/BaseModal/BaseModalHeader/BaseModalHeader.module.scss +16 -0
- package/src/Notifications/BaseModal/BaseModalHeader/BaseModalHeader.test.tsx +16 -0
- package/src/Notifications/BaseModal/BaseModalHeader/BaseModalHeader.tsx +17 -1
- package/src/Notifications/Dialog/Dialog.module.scss +16 -0
- package/src/Notifications/Dialog/Dialog.test.tsx +18 -2
- package/src/Notifications/Dialog/Dialog.tsx +16 -0
- package/src/Notifications/Dialog/DialogActions/DialogActions.module.scss +16 -0
- package/src/Notifications/Dialog/DialogActions/DialogActions.test.tsx +16 -0
- package/src/Notifications/Dialog/DialogActions/DialogActions.tsx +17 -1
- package/src/Notifications/Dialog/DialogTitle/DialogTitle.module.scss +16 -0
- package/src/Notifications/Dialog/DialogTitle/DialogTitle.test.tsx +16 -0
- package/src/Notifications/Dialog/DialogTitle/DialogTitle.tsx +16 -0
- package/src/Notifications/DiscardChangesModal/DiscardChangesDialog/DiscardChangesDialog.test.tsx +16 -0
- package/src/Notifications/DiscardChangesModal/DiscardChangesDialog/DiscardChangesDialog.tsx +16 -0
- package/src/Notifications/DiscardChangesModal/DiscardChangesModal.test.tsx +16 -0
- package/src/Notifications/DiscardChangesModal/DiscardChangesModal.tsx +16 -0
- package/src/Notifications/Modal/Modal.tsx +16 -0
- package/src/Notifications/Modal/ModalActions/ModalActions.tsx +16 -0
- package/src/Notifications/Modal/ModalContent/ModalContent.tsx +16 -0
- package/src/Notifications/Modal/ModalHeader/ModalHeader.tsx +16 -0
- package/src/Notifications/SlideInModal/SlideInModal.module.scss +16 -0
- package/src/Notifications/SlideInModal/SlideInModal.test.tsx +16 -0
- package/src/Notifications/SlideInModal/SlideInModal.tsx +16 -0
- package/src/Notifications/Snackbar/SnackbarContainer/SnackbarContainer.module.scss +19 -0
- package/src/Notifications/Snackbar/SnackbarContainer/SnackbarContainer.test.tsx +16 -0
- package/src/Notifications/Snackbar/SnackbarContainer/SnackbarContainer.tsx +57 -2
- package/src/Notifications/Snackbar/SnackbarItem/SnackbarItem.module.scss +18 -0
- package/src/Notifications/Snackbar/SnackbarItem/SnackbarItem.test.tsx +16 -0
- package/src/Notifications/Snackbar/SnackbarItem/SnackbarItem.tsx +34 -1
- package/src/Notifications/Snackbar/SnackbarProvider/SnackbarProvider.test.tsx +18 -2
- package/src/Notifications/Snackbar/SnackbarProvider/SnackbarProvider.tsx +38 -2
- package/src/Notifications/Snackbar/SnackbarProvider/SnackbarStateProvider.tsx +22 -1
- package/src/Notifications/Snackbar/interfaces.ts +16 -0
- package/src/Notifications/Snackbar/useSnackbar.ts +25 -1
- package/src/Pagination/Pagination.module.scss +17 -1
- package/src/Pagination/Pagination.test.tsx +17 -1
- package/src/Pagination/Pagination.tsx +16 -0
- package/src/Popover/Popover.module.scss +17 -1
- package/src/Popover/Popover.test.tsx +16 -0
- package/src/Popover/Popover.tsx +22 -0
- package/src/Skeleton/Skeleton.module.scss +16 -0
- package/src/Skeleton/Skeleton.test.tsx +17 -1
- package/src/Skeleton/Skeleton.tsx +16 -0
- package/src/StatusIndicator/StatusIndicator.module.scss +16 -0
- package/src/StatusIndicator/StatusIndicator.test.tsx +16 -0
- package/src/StatusIndicator/StatusIndicator.tsx +16 -0
- package/src/Tabs/Tab.test.tsx +16 -0
- package/src/Tabs/Tab.tsx +16 -0
- package/src/Tabs/TabButton.module.scss +20 -0
- package/src/Tabs/TabButton.test.tsx +16 -0
- package/src/Tabs/TabButton.tsx +16 -0
- package/src/Tabs/TabPanel.module.scss +20 -0
- package/src/Tabs/TabPanel.test.tsx +16 -0
- package/src/Tabs/TabPanel.tsx +16 -0
- package/src/Tabs/Tabs.module.scss +18 -2
- package/src/Tabs/Tabs.test.tsx +16 -0
- package/src/Tabs/Tabs.tsx +17 -1
- package/src/TextEllipsis/TextEllipsis.module.scss +16 -0
- package/src/TextEllipsis/TextEllipsis.test.tsx +16 -0
- package/src/TextEllipsis/TextEllipsis.tsx +16 -0
- package/src/Tiles/Tile.module.scss +18 -2
- package/src/Tiles/Tile.test.tsx +16 -0
- package/src/Tiles/Tile.tsx +16 -0
- package/src/Tiles/Tiles.module.scss +16 -0
- package/src/Tiles/Tiles.test.tsx +16 -0
- package/src/Tiles/Tiles.tsx +16 -0
- package/src/Tooltip/Tooltip.module.scss +17 -1
- package/src/Tooltip/Tooltip.test.tsx +26 -0
- package/src/Tooltip/Tooltip.tsx +18 -1
- package/src/Typography/Typography.module.scss +16 -0
- package/src/Typography/Typography.test.tsx +16 -0
- package/src/Typography/Typography.tsx +16 -0
- package/src/Wizard/BaseWizardSteps/BaseWizardSteps.module.scss +19 -7
- package/src/Wizard/BaseWizardSteps/BaseWizardSteps.test.tsx +16 -1
- package/src/Wizard/BaseWizardSteps/BaseWizardSteps.tsx +18 -19
- package/src/Wizard/Wizard.test.tsx +16 -1
- package/src/Wizard/Wizard.tsx +23 -8
- package/src/Wizard/WizardActions/WizardActions.test.tsx +16 -1
- package/src/Wizard/WizardActions/WizardActions.tsx +16 -0
- package/src/Wizard/WizardStateProvider.tsx +16 -0
- package/src/Wizard/WizardSteps/WizardSteps.test.tsx +16 -1
- package/src/Wizard/WizardSteps/WizardSteps.tsx +17 -2
- package/src/Wizard/wizardStateReducer.ts +18 -8
- package/src/_BaseStyling_/BaseStyling.test.tsx +16 -0
- package/src/_BaseStyling_/BaseStyling.tsx +41 -16
- package/src/hooks/useAnimation.test.tsx +16 -0
- package/src/hooks/useAnimation.ts +16 -0
- package/src/hooks/useBodyClick.test.tsx +16 -0
- package/src/hooks/useBodyClick.ts +16 -0
- package/src/hooks/useFormSelector.test.ts +16 -0
- package/src/hooks/useFormSelector.ts +16 -0
- package/src/hooks/usePosition.test.tsx +16 -0
- package/src/hooks/usePosition.ts +16 -0
- package/src/hooks/useRepeater.test.tsx +16 -0
- package/src/hooks/useRepeater.ts +16 -0
- package/src/hooks/useScroll.test.tsx +16 -0
- package/src/hooks/useScroll.ts +16 -0
- package/src/hooks/useSpacing.test.ts +16 -0
- package/src/hooks/useSpacing.ts +16 -0
- package/src/hooks/useWrapper.test.ts +16 -0
- package/src/hooks/useWrapper.ts +16 -0
- package/src/index.ts +16 -0
- package/src/interfaces.ts +16 -0
- package/src/mixins.module.scss +22 -7
- package/src/readyclasses.module.scss +16 -0
- package/src/types.d.ts +16 -0
- package/src/util/helper.test.tsx +16 -0
- package/src/util/helper.tsx +16 -0
- package/src/Link/types.d.ts +0 -9
|
@@ -1,3 +1,19 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright 2022 OneWelcome B.V.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
1
17
|
@import "../../readyclasses.module.scss";
|
|
2
18
|
|
|
3
19
|
$listItemHeight: 2.125rem;
|
|
@@ -13,25 +29,24 @@ $listItemHeight: 2.125rem;
|
|
|
13
29
|
|
|
14
30
|
[data-display] {
|
|
15
31
|
color: var(--greyed-out);
|
|
32
|
+
font-family: var(--font-family);
|
|
16
33
|
}
|
|
17
34
|
|
|
18
35
|
&.expanded {
|
|
19
|
-
border: var(--input-border-width) solid transparent;
|
|
20
|
-
|
|
21
36
|
.list-wrapper {
|
|
22
|
-
background:
|
|
37
|
+
background: var(--light);
|
|
23
38
|
}
|
|
24
39
|
}
|
|
25
40
|
|
|
26
41
|
&:not(.expanded) {
|
|
27
|
-
button:focus
|
|
28
|
-
border: var(--input-border-width-focus) solid var(--color-
|
|
42
|
+
button:focus:not(.error) {
|
|
43
|
+
border: var(--input-border-width-focus) solid var(--color-focus);
|
|
29
44
|
padding: 0 calc(1.25rem - var(--input-border-width-focus) + var(--input-border-width));
|
|
30
45
|
}
|
|
31
46
|
}
|
|
32
47
|
|
|
33
48
|
&:hover:not(.disabled):not(.expanded):not(.error) {
|
|
34
|
-
button {
|
|
49
|
+
button:not(:focus) {
|
|
35
50
|
border-color: var(--default);
|
|
36
51
|
border-width: var(--input-border-width);
|
|
37
52
|
}
|
|
@@ -44,7 +59,7 @@ $listItemHeight: 2.125rem;
|
|
|
44
59
|
border: 0;
|
|
45
60
|
padding: 0 1.25rem;
|
|
46
61
|
background-color: transparent;
|
|
47
|
-
border-color: var(--
|
|
62
|
+
border-color: var(--light-grey-border);
|
|
48
63
|
border-style: var(--input-border-style);
|
|
49
64
|
border-width: var(--input-border-width);
|
|
50
65
|
border-radius: var(--input-border-radius);
|
|
@@ -52,7 +67,7 @@ $listItemHeight: 2.125rem;
|
|
|
52
67
|
cursor: pointer;
|
|
53
68
|
transition: all 0.2s ease-in-out;
|
|
54
69
|
|
|
55
|
-
&:focus
|
|
70
|
+
&:focus {
|
|
56
71
|
outline: 0;
|
|
57
72
|
}
|
|
58
73
|
|
|
@@ -61,19 +76,19 @@ $listItemHeight: 2.125rem;
|
|
|
61
76
|
color: var(--error);
|
|
62
77
|
}
|
|
63
78
|
|
|
64
|
-
&.error:focus
|
|
79
|
+
&.error:focus {
|
|
65
80
|
border-width: var(--input-border-width-focus);
|
|
66
81
|
}
|
|
67
82
|
}
|
|
68
83
|
|
|
69
84
|
.list-wrapper {
|
|
70
|
-
border-color: var(--
|
|
85
|
+
border-color: var(--light-grey-border);
|
|
71
86
|
border-style: var(--input-border-style);
|
|
72
87
|
border-width: var(--input-border-width);
|
|
73
88
|
border-radius: var(--input-border-radius);
|
|
74
89
|
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.29);
|
|
75
90
|
position: absolute;
|
|
76
|
-
z-index:
|
|
91
|
+
z-index: 11;
|
|
77
92
|
top: 0;
|
|
78
93
|
left: 0;
|
|
79
94
|
width: 100%;
|
|
@@ -86,7 +101,7 @@ $listItemHeight: 2.125rem;
|
|
|
86
101
|
width: 100%;
|
|
87
102
|
margin: 0;
|
|
88
103
|
list-style: none;
|
|
89
|
-
background-color:
|
|
104
|
+
background-color: var(--light);
|
|
90
105
|
border-radius: var(--input-border-radius);
|
|
91
106
|
color: var(--default);
|
|
92
107
|
text-align: left;
|
|
@@ -111,7 +126,7 @@ $listItemHeight: 2.125rem;
|
|
|
111
126
|
opacity: 0.05;
|
|
112
127
|
}
|
|
113
128
|
|
|
114
|
-
&:focus
|
|
129
|
+
&:focus {
|
|
115
130
|
outline: 1px solid var(--color-primary);
|
|
116
131
|
outline-offset: -1px;
|
|
117
132
|
}
|
|
@@ -1,3 +1,19 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2022 OneWelcome B.V.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
1
17
|
import React, { useEffect, useRef } from "react";
|
|
2
18
|
import { Select as SelectComponent, Props } from "./Select";
|
|
3
19
|
import { render, waitFor } from "@testing-library/react";
|
|
@@ -280,63 +296,6 @@ describe("List expansion", () => {
|
|
|
280
296
|
});
|
|
281
297
|
});
|
|
282
298
|
|
|
283
|
-
describe("onClear method", () => {
|
|
284
|
-
it("should show a cross and fire the passed onClear function with enter", async () => {
|
|
285
|
-
const onClearHandler = jest.fn();
|
|
286
|
-
|
|
287
|
-
const { select, button } = createSelect(defaultParams => ({
|
|
288
|
-
...defaultParams,
|
|
289
|
-
onClear: onClearHandler,
|
|
290
|
-
value: "option4"
|
|
291
|
-
}));
|
|
292
|
-
|
|
293
|
-
button.focus();
|
|
294
|
-
const clearButton = select.querySelector("[data-clear]");
|
|
295
|
-
|
|
296
|
-
userEvent.tab();
|
|
297
|
-
|
|
298
|
-
expect(clearButton).toHaveFocus();
|
|
299
|
-
|
|
300
|
-
userEvent.keyboard("{enter}");
|
|
301
|
-
|
|
302
|
-
expect(onClearHandler).toHaveBeenCalled();
|
|
303
|
-
expect(button?.getAttribute("aria-expanded")).toBe("false");
|
|
304
|
-
});
|
|
305
|
-
|
|
306
|
-
it("should show a cross and fire the passed onClear function with enter", async () => {
|
|
307
|
-
const onClearHandler = jest.fn();
|
|
308
|
-
|
|
309
|
-
const { select, button } = createSelect(defaultParams => ({
|
|
310
|
-
...defaultParams,
|
|
311
|
-
onClear: onClearHandler,
|
|
312
|
-
value: "option4"
|
|
313
|
-
}));
|
|
314
|
-
|
|
315
|
-
button.focus();
|
|
316
|
-
const clearButton = select.querySelector("[data-clear]");
|
|
317
|
-
expect(document.querySelector("[data-display-inner]")).toBeInTheDocument();
|
|
318
|
-
|
|
319
|
-
userEvent.tab();
|
|
320
|
-
|
|
321
|
-
expect(clearButton).toHaveFocus();
|
|
322
|
-
|
|
323
|
-
userEvent.keyboard("{space}");
|
|
324
|
-
|
|
325
|
-
expect(onClearHandler).toHaveBeenCalled();
|
|
326
|
-
expect(button?.getAttribute("aria-expanded")).toBe("false");
|
|
327
|
-
});
|
|
328
|
-
|
|
329
|
-
it("should not show cross", () => {
|
|
330
|
-
createSelect(defaultParams => ({
|
|
331
|
-
...defaultParams,
|
|
332
|
-
value: ""
|
|
333
|
-
}));
|
|
334
|
-
|
|
335
|
-
expect(document.querySelector("[data-clear]")).not.toBeInTheDocument();
|
|
336
|
-
expect(document.querySelector("[data-display-inner]")).not.toBeInTheDocument();
|
|
337
|
-
});
|
|
338
|
-
});
|
|
339
|
-
|
|
340
299
|
describe("previously selected item", () => {
|
|
341
300
|
it("should have focus", () => {
|
|
342
301
|
const { select, button } = createSelect(defaultParams => ({
|
|
@@ -1,3 +1,19 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2022 OneWelcome B.V.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
1
17
|
import classes from "./Select.module.scss";
|
|
2
18
|
|
|
3
19
|
import React, {
|
|
@@ -15,6 +31,7 @@ import { FormElement } from "../form.interfaces";
|
|
|
15
31
|
import { useBodyClick } from "../../hooks/useBodyClick";
|
|
16
32
|
import readyclasses from "../../readyclasses.module.scss";
|
|
17
33
|
import { filterProps } from "../../util/helper";
|
|
34
|
+
import { useArrowNavigation, useSelectPositionList } from "./SelectService";
|
|
18
35
|
|
|
19
36
|
type PartialInputProps = Partial<InputProps>;
|
|
20
37
|
|
|
@@ -31,14 +48,8 @@ export interface Props extends ComponentPropsWithRef<"select">, FormElement {
|
|
|
31
48
|
value: string;
|
|
32
49
|
clearLabel?: string;
|
|
33
50
|
onChange?: (event: React.ChangeEvent<HTMLSelectElement>, child?: ReactElement) => void;
|
|
34
|
-
onClear?: (event: React.MouseEvent<HTMLDivElement> | React.KeyboardEvent<HTMLDivElement>) => void;
|
|
35
51
|
}
|
|
36
52
|
|
|
37
|
-
type Position = {
|
|
38
|
-
top: 0 | "initial";
|
|
39
|
-
bottom: 0 | "initial";
|
|
40
|
-
};
|
|
41
|
-
|
|
42
53
|
/** Amount of items to be rendered before a search input is rendered */
|
|
43
54
|
const renderSearchCondition = 10;
|
|
44
55
|
|
|
@@ -59,17 +70,13 @@ export const Select = React.forwardRef<HTMLSelectElement, Props>(
|
|
|
59
70
|
value,
|
|
60
71
|
clearLabel = "Clear selection",
|
|
61
72
|
onChange,
|
|
62
|
-
onClear,
|
|
63
73
|
...rest
|
|
64
74
|
}: Props,
|
|
65
75
|
ref
|
|
66
76
|
) => {
|
|
67
77
|
const [expanded, setExpanded] = useState(false);
|
|
68
|
-
const [opacity, setOpacity] = useState(0); // We set opacity because other wise if we calculate the max height you see the list full height for a split second and then it shortens.
|
|
69
78
|
const [filter, setFilter] = useState("");
|
|
70
79
|
const [display, setDisplay] = useState("");
|
|
71
|
-
const [listPosition, setListPosition] = useState<Partial<Position>>({});
|
|
72
|
-
const [optionsListMaxHeight, setOptionsListMaxHeight] = useState("none");
|
|
73
80
|
const containerReference = useRef<HTMLDivElement>(null);
|
|
74
81
|
const optionListReference = useRef<HTMLDivElement>(null);
|
|
75
82
|
const [isSearching, setIsSearching] = useState(false);
|
|
@@ -82,105 +89,23 @@ export const Select = React.forwardRef<HTMLSelectElement, Props>(
|
|
|
82
89
|
|
|
83
90
|
const nativeSelect = (ref as React.RefObject<HTMLSelectElement>) || createRef();
|
|
84
91
|
const searchInputRef = useRef<HTMLInputElement>(null);
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
codesToPreventDefault.push("Tab");
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/** We will handle the way certain key strokes affect the Select, unless we're searching */
|
|
106
|
-
if (codesToPreventDefault.includes(event.code) && !isSearching) {
|
|
107
|
-
event.preventDefault();
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
if (isSearching && codesToPreventDefaultWhenSearching.includes(event.code)) {
|
|
111
|
-
event.preventDefault();
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
if (isSearching) {
|
|
115
|
-
switch (event.code) {
|
|
116
|
-
case "ArrowDown":
|
|
117
|
-
case "Enter":
|
|
118
|
-
setIsSearching(false);
|
|
119
|
-
setFocusedSelectItem(0);
|
|
120
|
-
return;
|
|
121
|
-
case "ArrowUp":
|
|
122
|
-
setIsSearching(false);
|
|
123
|
-
setFocusedSelectItem(childrenCount - 1);
|
|
124
|
-
return;
|
|
125
|
-
case "Escape":
|
|
126
|
-
case "Tab":
|
|
127
|
-
setIsSearching(false);
|
|
128
|
-
setExpanded(false);
|
|
129
|
-
containerReference.current &&
|
|
130
|
-
containerReference.current.querySelector("button")!.focus();
|
|
131
|
-
}
|
|
132
|
-
} else {
|
|
133
|
-
switch (event.code) {
|
|
134
|
-
case "ArrowDown":
|
|
135
|
-
if (!expanded) {
|
|
136
|
-
setExpanded(true);
|
|
137
|
-
return;
|
|
138
|
-
}
|
|
139
|
-
setFocusedSelectItem(prevState => {
|
|
140
|
-
return prevState + 1 > childrenCount - 1 ? 0 : prevState + 1;
|
|
141
|
-
});
|
|
142
|
-
return;
|
|
143
|
-
case "ArrowUp":
|
|
144
|
-
setFocusedSelectItem(prevState => {
|
|
145
|
-
return prevState - 1 < 0 ? childrenCount - 1 : prevState - 1;
|
|
146
|
-
});
|
|
147
|
-
return;
|
|
148
|
-
case "Space":
|
|
149
|
-
if (!expanded) {
|
|
150
|
-
setExpanded(true);
|
|
151
|
-
return;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
setShouldClick(true);
|
|
155
|
-
setExpanded(false);
|
|
156
|
-
containerReference.current &&
|
|
157
|
-
containerReference.current.querySelector("button")!.focus();
|
|
158
|
-
return;
|
|
159
|
-
case "Tab":
|
|
160
|
-
if (childrenCount >= renderSearchCondition && expanded) {
|
|
161
|
-
setIsSearching(true);
|
|
162
|
-
searchInputRef.current && searchInputRef.current.focus();
|
|
163
|
-
return;
|
|
164
|
-
}
|
|
165
|
-
setExpanded(false);
|
|
166
|
-
|
|
167
|
-
return;
|
|
168
|
-
case "Escape":
|
|
169
|
-
if (expanded) {
|
|
170
|
-
setExpanded(false);
|
|
171
|
-
containerReference.current &&
|
|
172
|
-
containerReference.current.querySelector("button")!.focus();
|
|
173
|
-
}
|
|
174
|
-
return;
|
|
175
|
-
case "End":
|
|
176
|
-
setFocusedSelectItem(childrenCount - 1);
|
|
177
|
-
return;
|
|
178
|
-
case "Home":
|
|
179
|
-
setFocusedSelectItem(0);
|
|
180
|
-
return;
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
};
|
|
92
|
+
const customSelectButtonRef = useRef<HTMLButtonElement>(null);
|
|
93
|
+
|
|
94
|
+
const { onArrowNavigation } = useArrowNavigation({
|
|
95
|
+
expanded,
|
|
96
|
+
setExpanded,
|
|
97
|
+
isSearching,
|
|
98
|
+
setIsSearching,
|
|
99
|
+
setFocusedSelectItem,
|
|
100
|
+
childrenCount,
|
|
101
|
+
customSelectButtonRef,
|
|
102
|
+
setShouldClick,
|
|
103
|
+
searchInputRef,
|
|
104
|
+
renderSearchCondition
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
const { listPosition, opacity, optionsListMaxHeight, setListPosition, setOpacity } =
|
|
108
|
+
useSelectPositionList({ expanded, optionListReference, containerReference });
|
|
184
109
|
|
|
185
110
|
const syncDisplayValue = (val: string) => {
|
|
186
111
|
React.Children.forEach(children, child => {
|
|
@@ -190,55 +115,6 @@ export const Select = React.forwardRef<HTMLSelectElement, Props>(
|
|
|
190
115
|
});
|
|
191
116
|
};
|
|
192
117
|
|
|
193
|
-
const rePositionList = () => {
|
|
194
|
-
if (!expanded || !optionListReference.current || !containerReference.current) {
|
|
195
|
-
return;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
// Check whether there is more space above or below the select
|
|
199
|
-
// Check space between the bottom of select and top of viewport
|
|
200
|
-
const spaceOnTopOfSelect = containerReference.current.getBoundingClientRect().bottom;
|
|
201
|
-
|
|
202
|
-
// Check space between the top of the select and bottom of viewport
|
|
203
|
-
const spaceOnBottomOfSelect =
|
|
204
|
-
window.innerHeight - containerReference.current.getBoundingClientRect().top;
|
|
205
|
-
|
|
206
|
-
// Set position as if there's more space on the bottom
|
|
207
|
-
let position: Position = { top: 0, bottom: "initial" };
|
|
208
|
-
|
|
209
|
-
// Set the position of the select
|
|
210
|
-
if (spaceOnTopOfSelect > spaceOnBottomOfSelect) {
|
|
211
|
-
position = { top: "initial", bottom: 0 };
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
setListPosition(position);
|
|
215
|
-
|
|
216
|
-
// Calculate the potential max height of the options list
|
|
217
|
-
calculateOptionListMaxHeight(position);
|
|
218
|
-
};
|
|
219
|
-
|
|
220
|
-
const calculateOptionListMaxHeight = (position: Position) => {
|
|
221
|
-
// Calculate max height if there's more space below the select
|
|
222
|
-
const listHeight = optionListReference.current!.getBoundingClientRect().height;
|
|
223
|
-
const transformOrigin = position.top !== "initial" ? "top" : "bottom";
|
|
224
|
-
|
|
225
|
-
const availableSpace =
|
|
226
|
-
transformOrigin === "top"
|
|
227
|
-
? window.innerHeight -
|
|
228
|
-
containerReference.current!.getBoundingClientRect()[transformOrigin] -
|
|
229
|
-
16
|
|
230
|
-
: containerReference.current!.getBoundingClientRect()[transformOrigin] - 16;
|
|
231
|
-
|
|
232
|
-
if (availableSpace < listHeight) {
|
|
233
|
-
setOptionsListMaxHeight(`${availableSpace}px`);
|
|
234
|
-
setOpacity(100);
|
|
235
|
-
return;
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
setOptionsListMaxHeight("none");
|
|
239
|
-
setOpacity(100);
|
|
240
|
-
};
|
|
241
|
-
|
|
242
118
|
const onOptionChangeHandler = (optionRef: React.RefObject<HTMLLIElement>) => {
|
|
243
119
|
if (nativeSelect.current && optionRef.current) {
|
|
244
120
|
nativeSelect.current.value = optionRef.current.getAttribute("data-value")!;
|
|
@@ -247,7 +123,7 @@ export const Select = React.forwardRef<HTMLSelectElement, Props>(
|
|
|
247
123
|
|
|
248
124
|
setExpanded(false);
|
|
249
125
|
|
|
250
|
-
|
|
126
|
+
customSelectButtonRef.current && customSelectButtonRef.current.focus();
|
|
251
127
|
};
|
|
252
128
|
|
|
253
129
|
/**
|
|
@@ -313,33 +189,6 @@ export const Select = React.forwardRef<HTMLSelectElement, Props>(
|
|
|
313
189
|
return <Icon className={classes["warning"]} icon={Icons.Warning} />;
|
|
314
190
|
}
|
|
315
191
|
|
|
316
|
-
if (value?.length !== 0 && onClear) {
|
|
317
|
-
return (
|
|
318
|
-
<div
|
|
319
|
-
aria-hidden={false}
|
|
320
|
-
role="button"
|
|
321
|
-
tabIndex={0}
|
|
322
|
-
data-clear
|
|
323
|
-
onClick={(e: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
|
|
324
|
-
e.preventDefault();
|
|
325
|
-
e.stopPropagation();
|
|
326
|
-
onClear(e);
|
|
327
|
-
}}
|
|
328
|
-
onKeyDown={(e: React.KeyboardEvent<HTMLDivElement>) => {
|
|
329
|
-
if (e.code === "Enter" || e.code === "Space") {
|
|
330
|
-
e.preventDefault();
|
|
331
|
-
e.stopPropagation();
|
|
332
|
-
onClear(e);
|
|
333
|
-
containerReference.current &&
|
|
334
|
-
containerReference.current.querySelector("button")!.focus();
|
|
335
|
-
}
|
|
336
|
-
}}
|
|
337
|
-
>
|
|
338
|
-
<span className={readyclasses["sr-only"]}>{clearLabel}</span>
|
|
339
|
-
<Icon tag="span" icon={Icons.TimesThin} />
|
|
340
|
-
</div>
|
|
341
|
-
);
|
|
342
|
-
}
|
|
343
192
|
return null;
|
|
344
193
|
};
|
|
345
194
|
|
|
@@ -351,10 +200,6 @@ export const Select = React.forwardRef<HTMLSelectElement, Props>(
|
|
|
351
200
|
syncDisplayValue(value);
|
|
352
201
|
}, [value]);
|
|
353
202
|
|
|
354
|
-
useEffect(() => {
|
|
355
|
-
rePositionList();
|
|
356
|
-
}, [expanded]);
|
|
357
|
-
|
|
358
203
|
useBodyClick(
|
|
359
204
|
(event: MouseEvent) => !(event.target as Element).closest(".custom-select") && expanded,
|
|
360
205
|
() => {
|
|
@@ -401,6 +246,7 @@ export const Select = React.forwardRef<HTMLSelectElement, Props>(
|
|
|
401
246
|
onClick={() => {
|
|
402
247
|
setExpanded(!expanded);
|
|
403
248
|
}}
|
|
249
|
+
ref={customSelectButtonRef}
|
|
404
250
|
type="button"
|
|
405
251
|
name={name}
|
|
406
252
|
className={`${classes["custom-select"]} ${additionalClasses.join(" ")} `}
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2022 OneWelcome B.V.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import React, { useEffect, useState } from "react";
|
|
18
|
+
import {
|
|
19
|
+
Position,
|
|
20
|
+
UseArrowNavigationParams,
|
|
21
|
+
UseSelectPositionListParams
|
|
22
|
+
} from "./Select.interfaces";
|
|
23
|
+
|
|
24
|
+
export const useArrowNavigation = ({
|
|
25
|
+
expanded,
|
|
26
|
+
setExpanded,
|
|
27
|
+
isSearching,
|
|
28
|
+
setIsSearching,
|
|
29
|
+
setFocusedSelectItem,
|
|
30
|
+
childrenCount,
|
|
31
|
+
customSelectButtonRef,
|
|
32
|
+
setShouldClick,
|
|
33
|
+
searchInputRef,
|
|
34
|
+
renderSearchCondition
|
|
35
|
+
}: UseArrowNavigationParams) => {
|
|
36
|
+
const onArrowNavigation = (event: React.KeyboardEvent) => {
|
|
37
|
+
const codesToPreventDefault = [
|
|
38
|
+
"ArrowDown",
|
|
39
|
+
"ArrowUp",
|
|
40
|
+
"ArrowLeft",
|
|
41
|
+
"ArrowRight",
|
|
42
|
+
"Space",
|
|
43
|
+
"Escape",
|
|
44
|
+
"End",
|
|
45
|
+
"Home"
|
|
46
|
+
];
|
|
47
|
+
|
|
48
|
+
const codesToPreventDefaultWhenSearching = ["ArrowDown", "ArrowUp", "Enter", "Escape"];
|
|
49
|
+
|
|
50
|
+
/** If the select is expanded, we also want to control the Tab key */
|
|
51
|
+
if (expanded) {
|
|
52
|
+
codesToPreventDefault.push("Tab");
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** We will handle the way certain key strokes affect the Select, unless we're searching */
|
|
56
|
+
if (codesToPreventDefault.includes(event.code) && !isSearching) {
|
|
57
|
+
event.preventDefault();
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (isSearching && codesToPreventDefaultWhenSearching.includes(event.code)) {
|
|
61
|
+
event.preventDefault();
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (isSearching) {
|
|
65
|
+
switch (event.code) {
|
|
66
|
+
case "ArrowDown":
|
|
67
|
+
case "Enter":
|
|
68
|
+
setIsSearching(false);
|
|
69
|
+
setFocusedSelectItem(0);
|
|
70
|
+
return;
|
|
71
|
+
case "ArrowUp":
|
|
72
|
+
setIsSearching(false);
|
|
73
|
+
setFocusedSelectItem(childrenCount - 1);
|
|
74
|
+
return;
|
|
75
|
+
case "Escape":
|
|
76
|
+
case "Tab":
|
|
77
|
+
setIsSearching(false);
|
|
78
|
+
setExpanded(false);
|
|
79
|
+
customSelectButtonRef.current && customSelectButtonRef.current.focus();
|
|
80
|
+
}
|
|
81
|
+
} else {
|
|
82
|
+
switch (event.code) {
|
|
83
|
+
case "ArrowDown":
|
|
84
|
+
if (!expanded) {
|
|
85
|
+
setExpanded(true);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
setFocusedSelectItem(prevState => {
|
|
89
|
+
return prevState + 1 > childrenCount - 1 ? 0 : prevState + 1;
|
|
90
|
+
});
|
|
91
|
+
return;
|
|
92
|
+
case "ArrowUp":
|
|
93
|
+
setFocusedSelectItem(prevState => {
|
|
94
|
+
return prevState - 1 < 0 ? childrenCount - 1 : prevState - 1;
|
|
95
|
+
});
|
|
96
|
+
return;
|
|
97
|
+
case "Space":
|
|
98
|
+
if (!expanded) {
|
|
99
|
+
setExpanded(true);
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
setShouldClick(true);
|
|
104
|
+
setExpanded(false);
|
|
105
|
+
customSelectButtonRef.current && customSelectButtonRef.current.focus();
|
|
106
|
+
return;
|
|
107
|
+
case "Tab":
|
|
108
|
+
if (childrenCount >= renderSearchCondition && expanded) {
|
|
109
|
+
setIsSearching(true);
|
|
110
|
+
searchInputRef.current && searchInputRef.current.focus();
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
setExpanded(false);
|
|
114
|
+
|
|
115
|
+
return;
|
|
116
|
+
case "Escape":
|
|
117
|
+
if (expanded) {
|
|
118
|
+
setExpanded(false);
|
|
119
|
+
customSelectButtonRef.current && customSelectButtonRef.current.focus();
|
|
120
|
+
}
|
|
121
|
+
return;
|
|
122
|
+
case "End":
|
|
123
|
+
setFocusedSelectItem(childrenCount - 1);
|
|
124
|
+
return;
|
|
125
|
+
case "Home":
|
|
126
|
+
setFocusedSelectItem(0);
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
return { onArrowNavigation };
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
export const useSelectPositionList = ({
|
|
136
|
+
expanded,
|
|
137
|
+
optionListReference,
|
|
138
|
+
containerReference
|
|
139
|
+
}: UseSelectPositionListParams) => {
|
|
140
|
+
const [optionsListMaxHeight, setOptionsListMaxHeight] = useState("none");
|
|
141
|
+
const [opacity, setOpacity] = useState(0); // We set opacity because other wise if we calculate the max height you see the list full height for a split second and then it shortens.
|
|
142
|
+
const [listPosition, setListPosition] = useState<Partial<Position>>({});
|
|
143
|
+
|
|
144
|
+
useEffect(() => {
|
|
145
|
+
rePositionList();
|
|
146
|
+
}, [expanded]);
|
|
147
|
+
|
|
148
|
+
const rePositionList = () => {
|
|
149
|
+
if (!expanded || !optionListReference.current || !containerReference.current) {
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Check whether there is more space above or below the select
|
|
154
|
+
// Check space between the bottom of select and top of viewport
|
|
155
|
+
const spaceOnTopOfSelect = containerReference.current.getBoundingClientRect().bottom;
|
|
156
|
+
|
|
157
|
+
// Check space between the top of the select and bottom of viewport
|
|
158
|
+
const spaceOnBottomOfSelect =
|
|
159
|
+
window.innerHeight - containerReference.current.getBoundingClientRect().top;
|
|
160
|
+
|
|
161
|
+
// Set position as if there's more space on the bottom
|
|
162
|
+
let position: Position = { top: 0, bottom: "initial" };
|
|
163
|
+
|
|
164
|
+
// Set the position of the select
|
|
165
|
+
if (spaceOnTopOfSelect > spaceOnBottomOfSelect) {
|
|
166
|
+
position = { top: "initial", bottom: 0 };
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
setListPosition(position);
|
|
170
|
+
|
|
171
|
+
// Calculate the potential max height of the options list
|
|
172
|
+
calculateOptionListMaxHeight(position);
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
const calculateOptionListMaxHeight = (position: Position) => {
|
|
176
|
+
// Calculate max height if there's more space below the select
|
|
177
|
+
const listHeight = optionListReference.current!.getBoundingClientRect().height;
|
|
178
|
+
const transformOrigin = position.top !== "initial" ? "top" : "bottom";
|
|
179
|
+
|
|
180
|
+
const availableSpace =
|
|
181
|
+
transformOrigin === "top"
|
|
182
|
+
? window.innerHeight -
|
|
183
|
+
containerReference.current!.getBoundingClientRect()[transformOrigin] -
|
|
184
|
+
16
|
|
185
|
+
: containerReference.current!.getBoundingClientRect()[transformOrigin] - 16;
|
|
186
|
+
|
|
187
|
+
if (availableSpace < listHeight) {
|
|
188
|
+
setOptionsListMaxHeight(`${availableSpace}px`);
|
|
189
|
+
setOpacity(100);
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
setOptionsListMaxHeight("none");
|
|
194
|
+
setOpacity(100);
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
return {
|
|
198
|
+
optionsListMaxHeight,
|
|
199
|
+
opacity,
|
|
200
|
+
setOpacity,
|
|
201
|
+
listPosition,
|
|
202
|
+
setListPosition
|
|
203
|
+
};
|
|
204
|
+
};
|