@comicrelief/component-library 8.10.0 → 8.10.1
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/components/Atoms/TextInputWithDropdown/TextInputWithDropdown.js +33 -9
- package/dist/components/Atoms/TextInputWithDropdown/TextInputWithDropdown.style.js +11 -6
- package/dist/components/Molecules/SchoolLookup/SchoolLookup.js +3 -0
- package/package.json +1 -1
- package/src/components/Atoms/TextInputWithDropdown/TextInputWithDropdown.js +42 -11
- package/src/components/Atoms/TextInputWithDropdown/TextInputWithDropdown.style.js +1 -1
- package/src/components/Molecules/SchoolLookup/SchoolLookup.js +6 -1
|
@@ -24,7 +24,7 @@ const KEY_CODE_ESCAPE = 27;
|
|
|
24
24
|
*
|
|
25
25
|
* See the Typeahead and SchoolLookup molecules for the full implementation
|
|
26
26
|
*/
|
|
27
|
-
const TextInputWithDropdown = /*#__PURE__*/_react.default.forwardRef((_ref,
|
|
27
|
+
const TextInputWithDropdown = /*#__PURE__*/_react.default.forwardRef((_ref, forwardedRef) => {
|
|
28
28
|
let {
|
|
29
29
|
options,
|
|
30
30
|
onChange,
|
|
@@ -34,14 +34,33 @@ const TextInputWithDropdown = /*#__PURE__*/_react.default.forwardRef((_ref, ref)
|
|
|
34
34
|
label,
|
|
35
35
|
dropdownInstruction = null,
|
|
36
36
|
className = '',
|
|
37
|
+
hideBorder = false,
|
|
37
38
|
...otherInputProps
|
|
38
39
|
} = _ref;
|
|
39
40
|
const [activeOption, setActiveOption] = (0, _react.useState)(-1);
|
|
40
41
|
const [forceClosed, setForceClosed] = (0, _react.useState)(false);
|
|
42
|
+
const dropdownRef = (0, _react.useRef)(null);
|
|
43
|
+
const containerRef = (0, _react.useRef)(null);
|
|
44
|
+
(0, _react.useEffect)(() => {
|
|
45
|
+
const handleClickOutside = event => {
|
|
46
|
+
if (dropdownRef.current && !dropdownRef.current.contains(event.target) && !containerRef.current.contains(event.target)) {
|
|
47
|
+
setForceClosed(true);
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
// Only add the listeners if we have options showing
|
|
52
|
+
if (options.length > 0 && !forceClosed) {
|
|
53
|
+
['mousedown', 'touchstart'].forEach(event => document.addEventListener(event, handleClickOutside));
|
|
54
|
+
}
|
|
55
|
+
return () => {
|
|
56
|
+
['mousedown', 'touchstart'].forEach(event => document.removeEventListener(event, handleClickOutside));
|
|
57
|
+
};
|
|
58
|
+
}, [options.length, forceClosed, onChange]);
|
|
59
|
+
|
|
60
|
+
// Reset forceClosed when options change
|
|
41
61
|
(0, _react.useEffect)(() => {
|
|
42
|
-
// reset if options change
|
|
43
|
-
setActiveOption(-1);
|
|
44
62
|
setForceClosed(false);
|
|
63
|
+
setActiveOption(-1);
|
|
45
64
|
}, [options]);
|
|
46
65
|
const down = () => activeOption < options.length - 1 ? setActiveOption(activeOption + 1) : setActiveOption(0);
|
|
47
66
|
const up = () => activeOption < 1 ? setActiveOption(options.length - 1) : setActiveOption(activeOption - 1);
|
|
@@ -78,15 +97,18 @@ const TextInputWithDropdown = /*#__PURE__*/_react.default.forwardRef((_ref, ref)
|
|
|
78
97
|
};
|
|
79
98
|
return /*#__PURE__*/_react.default.createElement(_TextInputWithDropdown.Container, {
|
|
80
99
|
className: "TextInputWithDropdown ".concat(className).trim(),
|
|
81
|
-
onKeyDown: navigateOptions
|
|
100
|
+
onKeyDown: navigateOptions,
|
|
101
|
+
ref: containerRef
|
|
82
102
|
}, /*#__PURE__*/_react.default.createElement(_Input.default, Object.assign({}, inputProps, {
|
|
83
103
|
className: "TextInputWithDropdown__input",
|
|
84
|
-
ref:
|
|
85
|
-
})), options.length > 0 && forceClosed
|
|
86
|
-
className: "TextInputWithDropdown__options"
|
|
104
|
+
ref: forwardedRef
|
|
105
|
+
})), options.length > 0 && !forceClosed && /*#__PURE__*/_react.default.createElement(Options, Object.assign({}, optionsProps, {
|
|
106
|
+
className: "TextInputWithDropdown__options",
|
|
107
|
+
ref: dropdownRef,
|
|
108
|
+
hideBorder: hideBorder
|
|
87
109
|
})));
|
|
88
110
|
});
|
|
89
|
-
const Options = _ref2 => {
|
|
111
|
+
const Options = /*#__PURE__*/_react.default.forwardRef((_ref2, ref) => {
|
|
90
112
|
let {
|
|
91
113
|
options,
|
|
92
114
|
dropdownInstruction,
|
|
@@ -109,6 +131,7 @@ const Options = _ref2 => {
|
|
|
109
131
|
}, 100);
|
|
110
132
|
};
|
|
111
133
|
return /*#__PURE__*/_react.default.createElement(_TextInputWithDropdown.Dropdown, rest, /*#__PURE__*/_react.default.createElement(_TextInputWithDropdown.DropdownList, {
|
|
134
|
+
ref: ref,
|
|
112
135
|
role: "listbox",
|
|
113
136
|
onBlur: onBlur,
|
|
114
137
|
"aria-activedescendant": activeOption > -1 ? "option-".concat(activeOption) : undefined
|
|
@@ -129,5 +152,6 @@ const Options = _ref2 => {
|
|
|
129
152
|
"aria-selected": index === activeOption,
|
|
130
153
|
ref: index === activeOption ? element => element && element.focus() : null
|
|
131
154
|
}, /*#__PURE__*/_react.default.createElement(_Text.default, null, option)))));
|
|
132
|
-
};
|
|
155
|
+
});
|
|
156
|
+
TextInputWithDropdown.displayName = 'TextInputWithDropdown';
|
|
133
157
|
var _default = exports.default = TextInputWithDropdown;
|
|
@@ -16,7 +16,7 @@ const Container = exports.Container = _styledComponents.default.div.withConfig({
|
|
|
16
16
|
const Dropdown = exports.Dropdown = _styledComponents.default.div.withConfig({
|
|
17
17
|
displayName: "TextInputWithDropdownstyle__Dropdown",
|
|
18
18
|
componentId: "sc-1s4bv7m-1"
|
|
19
|
-
})(["", " font-family:", ";position:absolute;left:0;max-height:300px;overflow:auto;background-color:", ";border:
|
|
19
|
+
})(["", " font-family:", ";position:absolute;left:0;max-height:300px;overflow:auto;background-color:", ";border:", ";margin-top:-1px;width:100%;@media ", "{max-width:500px;}"], (0, _zIndex.default)('high'), _ref => {
|
|
20
20
|
let {
|
|
21
21
|
theme
|
|
22
22
|
} = _ref;
|
|
@@ -28,8 +28,13 @@ const Dropdown = exports.Dropdown = _styledComponents.default.div.withConfig({
|
|
|
28
28
|
return theme.color('white');
|
|
29
29
|
}, _ref3 => {
|
|
30
30
|
let {
|
|
31
|
-
|
|
31
|
+
hideBorder
|
|
32
32
|
} = _ref3;
|
|
33
|
+
return hideBorder ? 'none' : '1px solid';
|
|
34
|
+
}, _ref4 => {
|
|
35
|
+
let {
|
|
36
|
+
theme
|
|
37
|
+
} = _ref4;
|
|
33
38
|
return theme.allBreakpoints('M');
|
|
34
39
|
});
|
|
35
40
|
const DropdownList = exports.DropdownList = _styledComponents.default.ul.withConfig({
|
|
@@ -43,15 +48,15 @@ const DropdownItem = exports.DropdownItem = _styledComponents.default.li.withCon
|
|
|
43
48
|
const DropdownItemSelectable = exports.DropdownItemSelectable = (0, _styledComponents.default)(DropdownItem).withConfig({
|
|
44
49
|
displayName: "TextInputWithDropdownstyle__DropdownItemSelectable",
|
|
45
50
|
componentId: "sc-1s4bv7m-4"
|
|
46
|
-
})(["cursor:pointer;border-top:1px solid ", ";&:hover,&:focus{background-color:", ";}"],
|
|
51
|
+
})(["cursor:pointer;border-top:1px solid ", ";&:hover,&:focus{background-color:", ";}"], _ref5 => {
|
|
47
52
|
let {
|
|
48
53
|
theme
|
|
49
|
-
} =
|
|
54
|
+
} = _ref5;
|
|
50
55
|
return theme.color('grey_light');
|
|
51
|
-
},
|
|
56
|
+
}, _ref6 => {
|
|
52
57
|
let {
|
|
53
58
|
theme
|
|
54
|
-
} =
|
|
59
|
+
} = _ref6;
|
|
55
60
|
return theme.color('grey_light');
|
|
56
61
|
});
|
|
57
62
|
const TextItalic = exports.TextItalic = (0, _styledComponents.default)(_Text.default).withConfig({
|
|
@@ -25,6 +25,7 @@ const SchoolLookup = /*#__PURE__*/_react.default.forwardRef((_ref, ref) => {
|
|
|
25
25
|
dropdownInstruction = 'Please select a school from the list below',
|
|
26
26
|
notFoundMessage = "Sorry, we can't find this school",
|
|
27
27
|
onSelect,
|
|
28
|
+
hideBorder = false,
|
|
28
29
|
...rest
|
|
29
30
|
} = _ref;
|
|
30
31
|
const props = {
|
|
@@ -37,10 +38,12 @@ const SchoolLookup = /*#__PURE__*/_react.default.forwardRef((_ref, ref) => {
|
|
|
37
38
|
placeholder,
|
|
38
39
|
notFoundMessage,
|
|
39
40
|
dropdownInstruction,
|
|
41
|
+
hideBorder,
|
|
40
42
|
...rest
|
|
41
43
|
};
|
|
42
44
|
return /*#__PURE__*/_react.default.createElement(_Typeahead.default, Object.assign({}, props, {
|
|
43
45
|
ref: ref
|
|
44
46
|
}));
|
|
45
47
|
});
|
|
48
|
+
SchoolLookup.displayName = 'SchoolLookup';
|
|
46
49
|
var _default = exports.default = SchoolLookup;
|
package/package.json
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useState, useEffect } from 'react';
|
|
1
|
+
import React, { useState, useEffect, useRef } from 'react';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
3
|
|
|
4
4
|
import Input from '../Input/Input';
|
|
@@ -37,16 +37,39 @@ const TextInputWithDropdown = React.forwardRef(
|
|
|
37
37
|
label,
|
|
38
38
|
dropdownInstruction = null,
|
|
39
39
|
className = '',
|
|
40
|
+
hideBorder = false,
|
|
40
41
|
...otherInputProps
|
|
41
42
|
},
|
|
42
|
-
|
|
43
|
+
forwardedRef
|
|
43
44
|
) => {
|
|
44
45
|
const [activeOption, setActiveOption] = useState(-1);
|
|
45
46
|
const [forceClosed, setForceClosed] = useState(false);
|
|
47
|
+
const dropdownRef = useRef(null);
|
|
48
|
+
const containerRef = useRef(null);
|
|
49
|
+
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
const handleClickOutside = event => {
|
|
52
|
+
if (dropdownRef.current
|
|
53
|
+
&& !dropdownRef.current.contains(event.target)
|
|
54
|
+
&& !containerRef.current.contains(event.target)) {
|
|
55
|
+
setForceClosed(true);
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
// Only add the listeners if we have options showing
|
|
60
|
+
if (options.length > 0 && !forceClosed) {
|
|
61
|
+
['mousedown', 'touchstart'].forEach(event => document.addEventListener(event, handleClickOutside));
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return () => {
|
|
65
|
+
['mousedown', 'touchstart'].forEach(event => document.removeEventListener(event, handleClickOutside));
|
|
66
|
+
};
|
|
67
|
+
}, [options.length, forceClosed, onChange]);
|
|
68
|
+
|
|
69
|
+
// Reset forceClosed when options change
|
|
46
70
|
useEffect(() => {
|
|
47
|
-
// reset if options change
|
|
48
|
-
setActiveOption(-1);
|
|
49
71
|
setForceClosed(false);
|
|
72
|
+
setActiveOption(-1);
|
|
50
73
|
}, [options]);
|
|
51
74
|
|
|
52
75
|
const down = () => (activeOption < options.length - 1
|
|
@@ -96,16 +119,19 @@ const TextInputWithDropdown = React.forwardRef(
|
|
|
96
119
|
<Container
|
|
97
120
|
className={`TextInputWithDropdown ${className}`.trim()}
|
|
98
121
|
onKeyDown={navigateOptions}
|
|
122
|
+
ref={containerRef}
|
|
99
123
|
>
|
|
100
124
|
<Input
|
|
101
125
|
{...inputProps}
|
|
102
126
|
className="TextInputWithDropdown__input"
|
|
103
|
-
ref={
|
|
127
|
+
ref={forwardedRef}
|
|
104
128
|
/>
|
|
105
|
-
{options.length > 0 && forceClosed
|
|
129
|
+
{options.length > 0 && !forceClosed && (
|
|
106
130
|
<Options
|
|
107
131
|
{...optionsProps}
|
|
108
132
|
className="TextInputWithDropdown__options"
|
|
133
|
+
ref={dropdownRef}
|
|
134
|
+
hideBorder={hideBorder}
|
|
109
135
|
/>
|
|
110
136
|
)}
|
|
111
137
|
</Container>
|
|
@@ -113,14 +139,14 @@ const TextInputWithDropdown = React.forwardRef(
|
|
|
113
139
|
}
|
|
114
140
|
);
|
|
115
141
|
|
|
116
|
-
const Options = ({
|
|
142
|
+
const Options = React.forwardRef(({
|
|
117
143
|
options,
|
|
118
144
|
dropdownInstruction,
|
|
119
145
|
onSelect,
|
|
120
146
|
activeOption,
|
|
121
147
|
resetActiveOption,
|
|
122
148
|
...rest
|
|
123
|
-
}) => {
|
|
149
|
+
}, ref) => {
|
|
124
150
|
// Reset 'activeOption' when the list is unfocused.
|
|
125
151
|
const onBlur = e => {
|
|
126
152
|
const { target } = e;
|
|
@@ -136,6 +162,7 @@ const Options = ({
|
|
|
136
162
|
return (
|
|
137
163
|
<Dropdown {...rest}>
|
|
138
164
|
<DropdownList
|
|
165
|
+
ref={ref}
|
|
139
166
|
role="listbox"
|
|
140
167
|
onBlur={onBlur}
|
|
141
168
|
aria-activedescendant={
|
|
@@ -173,7 +200,7 @@ const Options = ({
|
|
|
173
200
|
</DropdownList>
|
|
174
201
|
</Dropdown>
|
|
175
202
|
);
|
|
176
|
-
};
|
|
203
|
+
});
|
|
177
204
|
|
|
178
205
|
TextInputWithDropdown.propTypes = {
|
|
179
206
|
options: PropTypes.arrayOf(PropTypes.string).isRequired,
|
|
@@ -183,7 +210,8 @@ TextInputWithDropdown.propTypes = {
|
|
|
183
210
|
name: PropTypes.string.isRequired,
|
|
184
211
|
label: PropTypes.string.isRequired,
|
|
185
212
|
className: PropTypes.string,
|
|
186
|
-
dropdownInstruction: PropTypes.string
|
|
213
|
+
dropdownInstruction: PropTypes.string,
|
|
214
|
+
hideBorder: PropTypes.bool
|
|
187
215
|
};
|
|
188
216
|
|
|
189
217
|
Options.propTypes = {
|
|
@@ -191,7 +219,10 @@ Options.propTypes = {
|
|
|
191
219
|
onSelect: PropTypes.func.isRequired,
|
|
192
220
|
dropdownInstruction: PropTypes.string,
|
|
193
221
|
activeOption: PropTypes.number.isRequired,
|
|
194
|
-
resetActiveOption: PropTypes.func.isRequired
|
|
222
|
+
resetActiveOption: PropTypes.func.isRequired,
|
|
223
|
+
hideBorder: PropTypes.bool
|
|
195
224
|
};
|
|
196
225
|
|
|
226
|
+
TextInputWithDropdown.displayName = 'TextInputWithDropdown';
|
|
227
|
+
|
|
197
228
|
export default TextInputWithDropdown;
|
|
@@ -16,7 +16,7 @@ const Dropdown = styled.div`
|
|
|
16
16
|
max-height: 300px;
|
|
17
17
|
overflow: auto;
|
|
18
18
|
background-color: ${({ theme }) => theme.color('white')};
|
|
19
|
-
border: 1px solid;
|
|
19
|
+
border: ${({ hideBorder }) => (hideBorder ? 'none' : '1px solid')};
|
|
20
20
|
margin-top: -1px;
|
|
21
21
|
width: 100%;
|
|
22
22
|
|
|
@@ -25,6 +25,7 @@ const SchoolLookup = React.forwardRef(
|
|
|
25
25
|
dropdownInstruction = 'Please select a school from the list below',
|
|
26
26
|
notFoundMessage = "Sorry, we can't find this school",
|
|
27
27
|
onSelect,
|
|
28
|
+
hideBorder = false,
|
|
28
29
|
...rest
|
|
29
30
|
},
|
|
30
31
|
ref
|
|
@@ -39,6 +40,7 @@ const SchoolLookup = React.forwardRef(
|
|
|
39
40
|
placeholder,
|
|
40
41
|
notFoundMessage,
|
|
41
42
|
dropdownInstruction,
|
|
43
|
+
hideBorder,
|
|
42
44
|
...rest
|
|
43
45
|
};
|
|
44
46
|
|
|
@@ -52,7 +54,10 @@ SchoolLookup.propTypes = {
|
|
|
52
54
|
label: PropTypes.string,
|
|
53
55
|
placeholder: PropTypes.string,
|
|
54
56
|
dropdownInstruction: PropTypes.string,
|
|
55
|
-
notFoundMessage: PropTypes.string
|
|
57
|
+
notFoundMessage: PropTypes.string,
|
|
58
|
+
hideBorder: PropTypes.bool
|
|
56
59
|
};
|
|
57
60
|
|
|
61
|
+
SchoolLookup.displayName = 'SchoolLookup';
|
|
62
|
+
|
|
58
63
|
export default SchoolLookup;
|