@uncinc/uncinc-react-kitchen-sink 2.3.6 → 2.4.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/dist/Context/ViewportContext.js +5 -5
- package/dist/components/AbbreviationAnnotation/stories.js +1 -1
- package/dist/components/AbbreviationAnnotation/stories.scss +1 -1
- package/dist/components/AbbreviationAnnotation/style.scss +0 -2
- package/dist/components/Accordion/AccordionItem/index.js +1 -0
- package/dist/components/Accordion/stories.js +1 -1
- package/dist/components/ApiAutocomplete/stories.js +1 -1
- package/dist/components/Button/index.js +11 -7
- package/dist/components/Button/stories.js +1 -1
- package/dist/components/Cookie/Checkbox/index.js +1 -1
- package/dist/components/Cookie/index.js +28 -13
- package/dist/components/Cookie/stories.js +16 -16
- package/dist/components/Dialog/index.js +89 -0
- package/dist/components/Dialog/stories.js +28 -0
- package/dist/components/Dialog/style.scss +72 -0
- package/dist/components/FontSizeSwitcher/index.js +10 -4
- package/dist/components/FontSizeSwitcher/stories.js +1 -1
- package/dist/components/Form/Checkbox/index.js +1 -1
- package/dist/components/Form/Checkboxes/index.js +1 -1
- package/dist/components/Form/Checkboxes/index.test.js +1 -1
- package/dist/components/Form/DatePicker/index.js +3 -3
- package/dist/components/Form/DateSelect/index.js +3 -4
- package/dist/components/Form/DateSelect/stories.js +1 -1
- package/dist/components/Form/GenericFormElement/index.js +2 -2
- package/dist/components/Form/Number/index.js +1 -1
- package/dist/components/Form/SearchField/index.js +2 -2
- package/dist/components/Form/Select/Input/index.js +21 -23
- package/dist/components/Form/Select/index.js +1 -1
- package/dist/components/Form/TextField/index.js +2 -2
- package/dist/components/Form/TextField/index.test.js +1 -1
- package/dist/components/Form/TextField/stories.js +1 -1
- package/dist/components/Form/Textarea/index.js +1 -1
- package/dist/components/Hamburger/stories.js +3 -3
- package/dist/components/Header/index.js +3 -3
- package/dist/components/Header/stories.js +1 -1
- package/dist/components/Image/Picture/index.js +0 -1
- package/dist/components/Image/stories.js +9 -9
- package/dist/components/InlineMenu/index.js +2 -4
- package/dist/components/InlineMenu/stories.js +1 -1
- package/dist/components/Layout/Container/stories.js +29 -29
- package/dist/components/Layout/QuickLayout/stories.js +1 -1
- package/dist/components/Lottie/LottieAnimation/index.js +21 -17
- package/dist/components/Lottie/LottieAnimationWithMousePosition.js +4 -4
- package/dist/components/Lottie/index.js +3 -2
- package/dist/components/Lottie/stories.js +1 -1
- package/dist/components/MagicLine/index.js +3 -3
- package/dist/components/MagicLine/stories.js +4 -4
- package/dist/components/NavigationScroll/index.js +8 -11
- package/dist/components/NavigationScroll/stories.js +1 -1
- package/dist/components/Pagination/index.js +6 -0
- package/dist/components/Pagination/stories.js +11 -11
- package/dist/components/SearchKit/Facets/ChipFacet/index.js +1 -1
- package/dist/components/SearchKit/Facets/ListFacet/index.js +1 -0
- package/dist/components/SearchKit/Facets/SelectFacet/index.js +2 -2
- package/dist/components/SearchKit/SearchFacets/index.js +1 -3
- package/dist/components/SearchKit/SearchField/index.js +4 -4
- package/dist/components/SearchKit/SearchPage/index.js +9 -2
- package/dist/components/SearchKit/SearchReset/index.js +20 -8
- package/dist/components/SearchKit/SearchResults/index.js +10 -6
- package/dist/components/SearchKit/SearchSelectedFilters/Filters/CustomValue/index.js +15 -0
- package/dist/components/SearchKit/SearchSelectedFilters/Filters/DateRange/index.js +17 -0
- package/dist/components/SearchKit/SearchSelectedFilters/Filters/NumericRange/index.js +17 -0
- package/dist/components/SearchKit/SearchSelectedFilters/Filters/Value/index.js +19 -0
- package/dist/components/SearchKit/SearchSelectedFilters/index.js +30 -23
- package/dist/components/SearchKit/SearchSelectedFilters/style.scss +4 -0
- package/dist/components/SearchKit/SearchSorting/index.js +1 -1
- package/dist/components/SearchKit/index.js +10 -3
- package/dist/components/SearchKit/stories.js +83 -77
- package/dist/components/Share/index.js +4 -4
- package/dist/components/Share/stories.js +1 -1
- package/dist/components/Sliders/SliderRelated/index.js +1 -1
- package/dist/components/Sliders/SliderRelated/stories.js +13 -13
- package/dist/components/Webform/WebformDate/index.js +5 -4
- package/dist/components/Webform/WebformNumber/index.js +1 -1
- package/dist/components/Webform/WebformTextField/index.js +1 -1
- package/dist/components/Webform/stories.actions.js +17 -17
- package/dist/components/Webform/stories.checkboxes.js +22 -22
- package/dist/components/Webform/stories.checked.js +35 -35
- package/dist/components/Webform/stories.container.js +29 -29
- package/dist/components/Webform/stories.date.js +17 -17
- package/dist/components/Webform/stories.filled.js +35 -35
- package/dist/components/Webform/stories.number.js +18 -18
- package/dist/components/Webform/stories.radiobuttons.js +22 -22
- package/dist/components/Webform/stories.select.js +22 -22
- package/dist/components/Webform/stories.textarea.js +1 -1
- package/dist/components/Webform/stories.textfield.js +1 -1
- package/dist/components/Webform/stories.wizard.js +115 -115
- package/dist/components/WysiwygField/index.js +0 -1
- package/dist/components/WysiwygField/stories.js +2 -2
- package/dist/config/i18next/locales/en.json +4 -0
- package/dist/config/i18next/locales/nl.json +7 -0
- package/dist/helpers/date.js +8 -0
- package/dist/hooks/useBoolean.ts +20 -0
- package/dist/hooks/useClickOutside.ts +38 -0
- package/dist/hooks/useDialog.ts +29 -0
- package/dist/hooks/useDialogHelpers.ts +95 -0
- package/dist/hooks/useEscape.ts +26 -0
- package/dist/hooks/usePrevious.js +1 -2
- package/dist/hooks/useTrapFocus.ts +80 -0
- package/dist/index.js +1 -0
- package/package.json +39 -17
- package/dist/components/Form/SearchField/stories.js +0 -0
- package/dist/components/SearchKit/Facets/HierarchicalFilterFacet/index.js +0 -60
- package/dist/components/SearchKit/Facets/HierarchicalMenuFacet/index.js +0 -60
|
@@ -1,32 +1,32 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import Immutable from 'immutable';
|
|
3
|
-
import Webform from '
|
|
3
|
+
import Webform from '.';
|
|
4
4
|
export default {
|
|
5
5
|
title: 'Organisms/Webform/Mapper'
|
|
6
6
|
};
|
|
7
7
|
const entities = Immutable.fromJS({
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
'#description':
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
8
|
+
'field_3': {
|
|
9
|
+
'#type': 'select',
|
|
10
|
+
'#title': 'Pick your poison',
|
|
11
|
+
'#description': 'Please select your poison.',
|
|
12
|
+
'#options': {
|
|
13
|
+
'beer': 'Beer',
|
|
14
|
+
'wine': 'Wine',
|
|
15
|
+
'rum': 'Rum',
|
|
16
|
+
'whisky': 'Whisk(e)y'
|
|
17
17
|
},
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
18
|
+
'#webform': 'test_conditionals',
|
|
19
|
+
'#webform_id': 'test_conditionals--field_3',
|
|
20
|
+
'#webform_key': 'field_3',
|
|
21
|
+
'#webform_parent_key': '',
|
|
22
|
+
'#webform_parent_flexbox': false,
|
|
23
|
+
'#webform_depth': 0,
|
|
24
|
+
'#webform_children': [],
|
|
25
|
+
'#webform_multiple': false,
|
|
26
|
+
'#webform_composite': false,
|
|
27
|
+
'#webform_parents': ['field_3'],
|
|
28
|
+
'#admin_title': 'Pick your poison',
|
|
29
|
+
'#webform_plugin_id': 'select'
|
|
30
30
|
}
|
|
31
31
|
});
|
|
32
32
|
export const Select = () => /*#__PURE__*/React.createElement(Webform, {
|
|
@@ -1,133 +1,133 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import Immutable from 'immutable';
|
|
3
|
-
import Webform from '
|
|
3
|
+
import Webform from '.';
|
|
4
4
|
export default {
|
|
5
5
|
title: 'Organisms/Webform/Mapper'
|
|
6
6
|
};
|
|
7
7
|
const entities = Immutable.fromJS({
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
8
|
+
'page_1': {
|
|
9
|
+
'#type': 'webform_wizard_page',
|
|
10
|
+
'#title': 'Page 1',
|
|
11
|
+
'number': {
|
|
12
|
+
'#type': 'number',
|
|
13
|
+
'#title': 'Number',
|
|
14
|
+
'#min': 1,
|
|
15
|
+
'#max': 100,
|
|
16
|
+
'#step': 1,
|
|
17
|
+
'#webform': 'test',
|
|
18
|
+
'#webform_id': 'test--number',
|
|
19
|
+
'#webform_key': 'number',
|
|
20
|
+
'#webform_parent_key': 'page_1',
|
|
21
|
+
'#webform_parent_flexbox': false,
|
|
22
|
+
'#webform_depth': 1,
|
|
23
23
|
'#required': true,
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
24
|
+
'#webform_multiple': false,
|
|
25
|
+
'#webform_composite': false,
|
|
26
|
+
'#webform_parents': ['page_1', 'number'],
|
|
27
|
+
'#admin_title': 'Number',
|
|
28
|
+
'#webform_plugin_id': 'number'
|
|
29
29
|
},
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
30
|
+
'#webform': 'test',
|
|
31
|
+
'#webform_id': 'test--page_1',
|
|
32
|
+
'#webform_key': 'page_1',
|
|
33
|
+
'#webform_parent_key': '',
|
|
34
|
+
'#webform_parent_flexbox': false,
|
|
35
|
+
'#webform_depth': 0,
|
|
36
|
+
'#webform_children': [],
|
|
37
|
+
'#webform_multiple': false,
|
|
38
|
+
'#webform_composite': false,
|
|
39
|
+
'#webform_parents': ['page_1'],
|
|
40
|
+
'#admin_title': 'Page 1',
|
|
41
|
+
'#webform_plugin_id': 'webform_wizard_page'
|
|
42
42
|
},
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
43
|
+
'page_2': {
|
|
44
|
+
'#type': 'webform_wizard_page',
|
|
45
|
+
'#title': 'Page 2',
|
|
46
|
+
'radio': {
|
|
47
|
+
'#type': 'radios',
|
|
48
|
+
'#title': 'Radio',
|
|
49
|
+
'#options': {
|
|
50
|
+
'1': 'Optie 1',
|
|
51
|
+
'2': 'Optie 2'
|
|
52
52
|
},
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
53
|
+
'#webform': 'test',
|
|
54
|
+
'#webform_id': 'test--radio',
|
|
55
|
+
'#webform_key': 'radio',
|
|
56
|
+
'#webform_parent_key': 'page_2',
|
|
57
|
+
'#webform_parent_flexbox': false,
|
|
58
|
+
'#webform_depth': 1,
|
|
59
|
+
'#webform_children': [],
|
|
60
|
+
'#webform_multiple': false,
|
|
61
|
+
'#webform_composite': false,
|
|
62
|
+
'#webform_parents': ['page_2', 'radio'],
|
|
63
|
+
'#admin_title': 'Radio',
|
|
64
|
+
'#webform_plugin_id': 'radios'
|
|
65
65
|
},
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
66
|
+
'#webform': 'test',
|
|
67
|
+
'#webform_id': 'test--page_2',
|
|
68
|
+
'#webform_key': 'page_2',
|
|
69
|
+
'#webform_parent_key': '',
|
|
70
|
+
'#webform_parent_flexbox': false,
|
|
71
|
+
'#webform_depth': 0,
|
|
72
|
+
'#webform_children': [],
|
|
73
|
+
'#webform_multiple': false,
|
|
74
|
+
'#webform_composite': false,
|
|
75
|
+
'#webform_parents': ['page_2'],
|
|
76
|
+
'#admin_title': 'Page 2',
|
|
77
|
+
'#webform_plugin_id': 'webform_wizard_page'
|
|
78
78
|
},
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
79
|
+
'page_3': {
|
|
80
|
+
'#type': 'webform_wizard_page',
|
|
81
|
+
'#title': 'Page 3',
|
|
82
|
+
'checkboxes': {
|
|
83
|
+
'#type': 'checkboxes',
|
|
84
|
+
'#title': 'Checkboxes',
|
|
85
|
+
'#options': {
|
|
86
|
+
'1': '1',
|
|
87
|
+
'2': '2'
|
|
88
88
|
},
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
89
|
+
'#webform': 'test',
|
|
90
|
+
'#webform_id': 'test--checkboxes',
|
|
91
|
+
'#webform_key': 'checkboxes',
|
|
92
|
+
'#webform_parent_key': 'page_3',
|
|
93
|
+
'#webform_parent_flexbox': false,
|
|
94
|
+
'#webform_depth': 1,
|
|
95
|
+
'#webform_children': [],
|
|
96
|
+
'#webform_multiple': true,
|
|
97
|
+
'#webform_composite': false,
|
|
98
|
+
'#webform_parents': ['page_3', 'checkboxes'],
|
|
99
|
+
'#admin_title': 'Checkboxes',
|
|
100
|
+
'#webform_plugin_id': 'checkboxes'
|
|
101
101
|
},
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
102
|
+
'#webform': 'test',
|
|
103
|
+
'#webform_id': 'test--page_3',
|
|
104
|
+
'#webform_key': 'page_3',
|
|
105
|
+
'#webform_parent_key': '',
|
|
106
|
+
'#webform_parent_flexbox': false,
|
|
107
|
+
'#webform_depth': 0,
|
|
108
|
+
'#webform_children': [],
|
|
109
|
+
'#webform_multiple': false,
|
|
110
|
+
'#webform_composite': false,
|
|
111
|
+
'#webform_parents': ['page_3'],
|
|
112
|
+
'#admin_title': 'Page 3',
|
|
113
|
+
'#webform_plugin_id': 'webform_wizard_page'
|
|
114
114
|
},
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
115
|
+
'actions': {
|
|
116
|
+
'#type': 'webform_actions',
|
|
117
|
+
'#title': 'Submit button(s)',
|
|
118
|
+
'#submit__label': 'Verstuur',
|
|
119
|
+
'#webform': 'test',
|
|
120
|
+
'#webform_id': 'test--actions',
|
|
121
|
+
'#webform_key': 'actions',
|
|
122
|
+
'#webform_parent_key': '',
|
|
123
|
+
'#webform_parent_flexbox': false,
|
|
124
|
+
'#webform_depth': 0,
|
|
125
|
+
'#webform_children': [],
|
|
126
|
+
'#webform_multiple': false,
|
|
127
|
+
'#webform_composite': false,
|
|
128
|
+
'#webform_parents': ['actions'],
|
|
129
|
+
'#admin_title': 'Submit button(s)',
|
|
130
|
+
'#webform_plugin_id': 'webform_actions'
|
|
131
131
|
}
|
|
132
132
|
});
|
|
133
133
|
export const Wizard = () => /*#__PURE__*/React.createElement(Webform, {
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
|
|
2
2
|
import React from 'react';
|
|
3
|
-
import WysiwygField from '
|
|
3
|
+
import WysiwygField from '.';
|
|
4
4
|
import AbbreviationAnnotation from '../AbbreviationAnnotation';
|
|
5
5
|
export default {
|
|
6
6
|
title: 'Atoms/WysiwygField'
|
|
7
7
|
};
|
|
8
|
-
const html =
|
|
8
|
+
const html = '<p>This is <em>some</em> example <a href=\'https://www.uncinc.nl\'>HTML</a>.</p>';
|
|
9
9
|
export const Primary = () => /*#__PURE__*/React.createElement(WysiwygField, {
|
|
10
10
|
html: html
|
|
11
11
|
});
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
{
|
|
2
|
+
"general": {
|
|
3
|
+
"open": "Openen",
|
|
4
|
+
"close": "Sluiten"
|
|
5
|
+
},
|
|
2
6
|
"dateselect" : {
|
|
3
7
|
"months": {
|
|
4
8
|
"jan": "Januari",
|
|
@@ -18,5 +22,8 @@
|
|
|
18
22
|
"form": {
|
|
19
23
|
"required": "vereist",
|
|
20
24
|
"optional": "optioneel"
|
|
25
|
+
},
|
|
26
|
+
"searchkit": {
|
|
27
|
+
"reset_search": "Zoeken opnieuw instellen"
|
|
21
28
|
}
|
|
22
29
|
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export const parseDateWithTimezoneOffset = date => {
|
|
2
|
+
const offset = date.getTimezoneOffset();
|
|
3
|
+
const dateWithTimezoneOffset = new Date(date.getTime() - offset * 60 * 1000);
|
|
4
|
+
return dateWithTimezoneOffset.toISOString();
|
|
5
|
+
};
|
|
6
|
+
export const isValidDate = date => {
|
|
7
|
+
return date instanceof Date && !Number.isNaN(date);
|
|
8
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { useCallback, useState } from 'react';
|
|
2
|
+
|
|
3
|
+
export default function useBoolean(defaultValue: boolean = false) {
|
|
4
|
+
const [value, setValue] = useState(defaultValue);
|
|
5
|
+
|
|
6
|
+
const toggle = useCallback(() => {
|
|
7
|
+
setValue((current) => !current);
|
|
8
|
+
}, [setValue]);
|
|
9
|
+
|
|
10
|
+
const setTrue = useCallback(() => { setValue(true); }, []);
|
|
11
|
+
const setFalse = useCallback(() => { setValue(false); }, []);
|
|
12
|
+
|
|
13
|
+
return {
|
|
14
|
+
value,
|
|
15
|
+
setValue,
|
|
16
|
+
setTrue,
|
|
17
|
+
setFalse,
|
|
18
|
+
toggle,
|
|
19
|
+
} as const;
|
|
20
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { MutableRefObject, useEffect } from 'react';
|
|
2
|
+
|
|
3
|
+
interface UseClickOutsideOptions {
|
|
4
|
+
refs: MutableRefObject<HTMLElement>[] | MutableRefObject<HTMLElement>;
|
|
5
|
+
unless?: boolean | ((e: globalThis.MouseEvent) => boolean);
|
|
6
|
+
onClick: (e: globalThis.MouseEvent) => void;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export default function useClickOutside({
|
|
10
|
+
refs,
|
|
11
|
+
unless = false,
|
|
12
|
+
onClick,
|
|
13
|
+
}: UseClickOutsideOptions) {
|
|
14
|
+
const refsAsArray = Array.isArray(refs) ? refs : [refs];
|
|
15
|
+
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
function handleOutsideClick(e: globalThis.MouseEvent) {
|
|
18
|
+
const allRefsHaveCurrent = refsAsArray.every((ref) => !!ref.current);
|
|
19
|
+
const shouldNotExecute = typeof unless === 'function' ? unless(e) : unless;
|
|
20
|
+
|
|
21
|
+
if (!allRefsHaveCurrent || shouldNotExecute) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const isOutsideClick = refsAsArray.every((ref) => !ref.current.contains(e.target as Node));
|
|
26
|
+
|
|
27
|
+
if (isOutsideClick) {
|
|
28
|
+
onClick(e);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
document.addEventListener('mousedown', handleOutsideClick);
|
|
33
|
+
|
|
34
|
+
return () => {
|
|
35
|
+
document.removeEventListener('mousedown', handleOutsideClick);
|
|
36
|
+
};
|
|
37
|
+
}, [unless, onClick, refs]);
|
|
38
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import Dialog from '../components/Dialog';
|
|
4
|
+
import useBoolean from './useBoolean';
|
|
5
|
+
|
|
6
|
+
export default function useDialog() {
|
|
7
|
+
const {
|
|
8
|
+
value: dialogIsOpen,
|
|
9
|
+
setTrue: openDialog,
|
|
10
|
+
setFalse: closeDialog,
|
|
11
|
+
} = useBoolean();
|
|
12
|
+
|
|
13
|
+
const DialogComponent = ({ children, ...props }) => React.createElement(
|
|
14
|
+
Dialog,
|
|
15
|
+
{
|
|
16
|
+
...props,
|
|
17
|
+
isOpen: dialogIsOpen,
|
|
18
|
+
closeFunction: closeDialog,
|
|
19
|
+
},
|
|
20
|
+
children,
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
return {
|
|
24
|
+
dialogIsOpen,
|
|
25
|
+
openDialog,
|
|
26
|
+
closeDialog,
|
|
27
|
+
DialogComponent,
|
|
28
|
+
} as const;
|
|
29
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { useEffect, MutableRefObject } from 'react';
|
|
2
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
3
|
+
|
|
4
|
+
import useClickOutside from './useClickOutside';
|
|
5
|
+
import useEscape from './useEscape';
|
|
6
|
+
import useTrapFocus from './useTrapFocus';
|
|
7
|
+
|
|
8
|
+
export interface UseDialogHelpersOptions<T extends HTMLElement> {
|
|
9
|
+
id?: string;
|
|
10
|
+
wrapperElement: MutableRefObject<T>;
|
|
11
|
+
closeFunction: () => void;
|
|
12
|
+
isOpen: boolean;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Hook to allow you to implement your own Dialog component.
|
|
17
|
+
* This takes care of focus, and closing the Dialog by
|
|
18
|
+
* click outside it, or hitting Escape.
|
|
19
|
+
*/
|
|
20
|
+
export default function useDialogHelpers<T extends HTMLElement>(
|
|
21
|
+
options: UseDialogHelpersOptions<T>,
|
|
22
|
+
) {
|
|
23
|
+
const {
|
|
24
|
+
id = uuidv4(),
|
|
25
|
+
wrapperElement,
|
|
26
|
+
closeFunction,
|
|
27
|
+
isOpen,
|
|
28
|
+
} = options;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Close the Dialog by pressing Escape.
|
|
32
|
+
*/
|
|
33
|
+
useClickOutside({
|
|
34
|
+
refs: [wrapperElement],
|
|
35
|
+
onClick: closeFunction,
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Close the Dialog by pressing Escape.
|
|
40
|
+
*/
|
|
41
|
+
useEscape({
|
|
42
|
+
onPress: closeFunction,
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Make sure focus does not leave the Dialog while it's open.
|
|
47
|
+
*/
|
|
48
|
+
useTrapFocus({
|
|
49
|
+
ref: wrapperElement,
|
|
50
|
+
isActive: isOpen,
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Sets focus on the popup so that screen readers announce
|
|
55
|
+
* that the user is currently on a dialog.
|
|
56
|
+
*/
|
|
57
|
+
useEffect(() => {
|
|
58
|
+
if (isOpen && wrapperElement.current) {
|
|
59
|
+
wrapperElement.current.setAttribute('tabindex', '-1');
|
|
60
|
+
wrapperElement.current.focus();
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function removeFocusProperties() {
|
|
64
|
+
if (wrapperElement.current) {
|
|
65
|
+
wrapperElement.current.removeAttribute('tabindex');
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (wrapperElement.current) {
|
|
70
|
+
wrapperElement.current.addEventListener('blur', removeFocusProperties);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return () => {
|
|
74
|
+
if (wrapperElement.current) {
|
|
75
|
+
wrapperElement.current.removeEventListener('blur', removeFocusProperties);
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
}, [isOpen]);
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Create a labelId for A11Y
|
|
82
|
+
*/
|
|
83
|
+
const labelId = `${id}-label`;
|
|
84
|
+
|
|
85
|
+
const dialogHelpersProps = {
|
|
86
|
+
'aria-role': 'dialog',
|
|
87
|
+
'aria-labelledby': labelId,
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
return {
|
|
91
|
+
id,
|
|
92
|
+
labelId,
|
|
93
|
+
dialogHelpersProps,
|
|
94
|
+
} as const;
|
|
95
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { useEffect } from 'react';
|
|
2
|
+
|
|
3
|
+
interface UseEscapeOption {
|
|
4
|
+
unless?: boolean | ((e: KeyboardEvent) => boolean);
|
|
5
|
+
onPress: (e: KeyboardEvent) => void;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export default function useEscape({ unless, onPress }: UseEscapeOption) {
|
|
9
|
+
useEffect(() => {
|
|
10
|
+
function handleOnPress(e: KeyboardEvent) {
|
|
11
|
+
const shouldNotExecute = typeof unless === 'function' ? unless(e) : unless;
|
|
12
|
+
|
|
13
|
+
if (shouldNotExecute || e.key !== 'Escape') {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
onPress(e);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
document.addEventListener('keyup', handleOnPress);
|
|
21
|
+
|
|
22
|
+
return () => {
|
|
23
|
+
document.removeEventListener('keyup', handleOnPress);
|
|
24
|
+
};
|
|
25
|
+
}, [unless]);
|
|
26
|
+
}
|