@telus-uds/components-base 1.19.0 → 1.21.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/CHANGELOG.md +34 -2
- package/__tests17__/ThemeProvider/ThemeProvider.test.jsx +3 -1
- package/component-docs.json +838 -125
- package/lib/BaseProvider/index.js +2 -1
- package/lib/Box/Box.js +14 -1
- package/lib/Button/ButtonDropdown.js +207 -0
- package/lib/Button/index.js +8 -0
- package/lib/Carousel/Carousel.js +2 -2
- package/lib/Carousel/CarouselItem/CarouselItem.js +7 -1
- package/lib/Carousel/CarouselTabs/CarouselTabsPanel.js +21 -4
- package/lib/FlexGrid/Col/Col.js +1 -3
- package/lib/FlexGrid/FlexGrid.js +3 -5
- package/lib/FlexGrid/Row/Row.js +3 -3
- package/lib/IconButton/IconButton.js +12 -4
- package/lib/MultiSelectFilter/MultiSelectFilter.js +276 -0
- package/lib/MultiSelectFilter/dictionary.js +19 -0
- package/lib/MultiSelectFilter/index.js +13 -0
- package/lib/Search/Search.js +4 -1
- package/lib/Select/Picker.native.js +16 -13
- package/lib/Select/Select.js +7 -1
- package/lib/Select/constants.js +15 -0
- package/lib/StepTracker/Step.js +2 -1
- package/lib/TextInput/TextInput.js +9 -2
- package/lib/TextInput/TextInputBase.js +52 -8
- package/lib/TextInput/dictionary.js +15 -0
- package/lib/ThemeProvider/ThemeProvider.js +24 -7
- package/lib/ThemeProvider/utils/styles.js +3 -1
- package/lib/index.js +18 -0
- package/lib/utils/BaseView/BaseView.js +64 -0
- package/lib/utils/BaseView/BaseView.native.js +16 -0
- package/lib/utils/BaseView/index.js +13 -0
- package/lib/utils/index.js +10 -1
- package/lib/utils/input.js +11 -3
- package/lib/utils/props/handlerProps.js +5 -0
- package/lib-module/BaseProvider/index.js +2 -1
- package/lib-module/Box/Box.js +14 -1
- package/lib-module/Button/ButtonDropdown.js +181 -0
- package/lib-module/Button/index.js +2 -1
- package/lib-module/Carousel/Carousel.js +2 -2
- package/lib-module/Carousel/CarouselItem/CarouselItem.js +8 -2
- package/lib-module/Carousel/CarouselTabs/CarouselTabsPanel.js +23 -6
- package/lib-module/FlexGrid/Col/Col.js +2 -3
- package/lib-module/FlexGrid/FlexGrid.js +2 -3
- package/lib-module/FlexGrid/Row/Row.js +2 -2
- package/lib-module/IconButton/IconButton.js +14 -4
- package/lib-module/MultiSelectFilter/MultiSelectFilter.js +248 -0
- package/lib-module/MultiSelectFilter/dictionary.js +12 -0
- package/lib-module/MultiSelectFilter/index.js +2 -0
- package/lib-module/Search/Search.js +4 -1
- package/lib-module/Select/Picker.native.js +15 -13
- package/lib-module/Select/Select.js +6 -1
- package/lib-module/Select/constants.js +5 -0
- package/lib-module/StepTracker/Step.js +2 -1
- package/lib-module/TextInput/TextInput.js +6 -0
- package/lib-module/TextInput/TextInputBase.js +52 -10
- package/lib-module/TextInput/dictionary.js +8 -0
- package/lib-module/ThemeProvider/ThemeProvider.js +24 -7
- package/lib-module/ThemeProvider/utils/styles.js +3 -1
- package/lib-module/index.js +2 -0
- package/lib-module/utils/BaseView/BaseView.js +43 -0
- package/lib-module/utils/BaseView/BaseView.native.js +6 -0
- package/lib-module/utils/BaseView/index.js +2 -0
- package/lib-module/utils/index.js +2 -1
- package/lib-module/utils/input.js +11 -3
- package/lib-module/utils/props/handlerProps.js +5 -0
- package/package.json +3 -3
- package/src/BaseProvider/index.jsx +4 -1
- package/src/Box/Box.jsx +14 -1
- package/src/Button/ButtonDropdown.jsx +179 -0
- package/src/Button/index.js +2 -1
- package/src/Carousel/Carousel.jsx +6 -3
- package/src/Carousel/CarouselItem/CarouselItem.jsx +9 -2
- package/src/Carousel/CarouselTabs/CarouselTabsPanel.jsx +19 -5
- package/src/FlexGrid/Col/Col.jsx +4 -4
- package/src/FlexGrid/FlexGrid.jsx +11 -10
- package/src/FlexGrid/Row/Row.jsx +4 -3
- package/src/IconButton/IconButton.jsx +3 -1
- package/src/MultiSelectFilter/MultiSelectFilter.jsx +227 -0
- package/src/MultiSelectFilter/dictionary.js +12 -0
- package/src/MultiSelectFilter/index.js +3 -0
- package/src/Search/Search.jsx +2 -1
- package/src/Select/Picker.native.jsx +29 -14
- package/src/Select/Select.jsx +7 -1
- package/src/Select/constants.js +5 -0
- package/src/StepTracker/Step.jsx +5 -1
- package/src/TextInput/TextInput.jsx +5 -0
- package/src/TextInput/TextInputBase.jsx +43 -8
- package/src/TextInput/dictionary.js +8 -0
- package/src/ThemeProvider/ThemeProvider.jsx +23 -6
- package/src/ThemeProvider/utils/styles.js +3 -1
- package/src/index.js +2 -0
- package/src/utils/BaseView/BaseView.jsx +38 -0
- package/src/utils/BaseView/BaseView.native.jsx +6 -0
- package/src/utils/BaseView/index.js +3 -0
- package/src/utils/index.js +1 -0
- package/src/utils/input.js +9 -4
- package/src/utils/props/handlerProps.js +4 -0
|
@@ -77,10 +77,20 @@ const IconButton = /*#__PURE__*/forwardRef((_ref3, ref) => {
|
|
|
77
77
|
const selectedProps = selectProps({ ...rest,
|
|
78
78
|
accessibilityRole
|
|
79
79
|
});
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
80
|
+
|
|
81
|
+
const handlePress = () => {
|
|
82
|
+
var _ref$current;
|
|
83
|
+
|
|
84
|
+
linkProps.handleHref({
|
|
85
|
+
href,
|
|
86
|
+
onPress
|
|
87
|
+
})({
|
|
88
|
+
nativeEvent: {
|
|
89
|
+
target: ref === null || ref === void 0 ? void 0 : (_ref$current = ref.current) === null || _ref$current === void 0 ? void 0 : _ref$current.id
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
};
|
|
93
|
+
|
|
84
94
|
const getTokens = useThemeTokensCallback('IconButton', tokens, variant);
|
|
85
95
|
|
|
86
96
|
const getOuterStyle = pressableState => selectOuterStyle(getTokens(resolvePressableState(pressableState)));
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
import React, { forwardRef, useState } from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import { useThemeTokensCallback } from '../ThemeProvider';
|
|
4
|
+
import { containUniqueFields, getTokensPropType, getPressHandlersWithArgs, selectTokens, useCopy, useMultipleInputValues, variantProp } from '../utils';
|
|
5
|
+
import dictionary from './dictionary';
|
|
6
|
+
import Box from '../Box';
|
|
7
|
+
import { Button, ButtonDropdown } from '../Button';
|
|
8
|
+
import { CheckboxGroup } from '../Checkbox';
|
|
9
|
+
import Divider from '../Divider';
|
|
10
|
+
import FlexGrid from '../FlexGrid';
|
|
11
|
+
import Modal from '../Modal';
|
|
12
|
+
import Spacer from '../Spacer';
|
|
13
|
+
import StackView from '../StackView';
|
|
14
|
+
import Typography from '../Typography';
|
|
15
|
+
import { TextButton } from '../Link';
|
|
16
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
17
|
+
import { jsxs as _jsxs } from "react/jsx-runtime";
|
|
18
|
+
import { Fragment as _Fragment } from "react/jsx-runtime";
|
|
19
|
+
const {
|
|
20
|
+
Col,
|
|
21
|
+
Row
|
|
22
|
+
} = FlexGrid;
|
|
23
|
+
const MultiSelectFilter = /*#__PURE__*/forwardRef((_ref, ref) => {
|
|
24
|
+
let {
|
|
25
|
+
label,
|
|
26
|
+
id = label,
|
|
27
|
+
variant,
|
|
28
|
+
tokens,
|
|
29
|
+
items = [],
|
|
30
|
+
values,
|
|
31
|
+
initialValues,
|
|
32
|
+
maxValues,
|
|
33
|
+
onChange,
|
|
34
|
+
copy = 'en',
|
|
35
|
+
readOnly = false,
|
|
36
|
+
inactive = false,
|
|
37
|
+
rowLimit = 12,
|
|
38
|
+
...rest
|
|
39
|
+
} = _ref;
|
|
40
|
+
const {
|
|
41
|
+
currentValues,
|
|
42
|
+
setValues
|
|
43
|
+
} = useMultipleInputValues({
|
|
44
|
+
initialValues,
|
|
45
|
+
values,
|
|
46
|
+
maxValues,
|
|
47
|
+
onChange,
|
|
48
|
+
readOnly
|
|
49
|
+
});
|
|
50
|
+
const getItemTokens = useThemeTokensCallback('ButtonDropdown', tokens, variant);
|
|
51
|
+
|
|
52
|
+
const getButtonTokens = buttonState => selectTokens('Button', getItemTokens(buttonState));
|
|
53
|
+
|
|
54
|
+
const getCopy = useCopy({
|
|
55
|
+
dictionary,
|
|
56
|
+
copy
|
|
57
|
+
});
|
|
58
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
59
|
+
const [checkedIds, setCheckedIds] = useState(currentValues !== null && currentValues !== void 0 ? currentValues : []);
|
|
60
|
+
const colSize = items.length > rowLimit ? 2 : 1;
|
|
61
|
+
const isSelected = currentValues.length > 0;
|
|
62
|
+
const uniqueFields = ['id', 'label'];
|
|
63
|
+
|
|
64
|
+
if (!containUniqueFields(items, uniqueFields)) {
|
|
65
|
+
throw new Error("MultiSelectFilter items must have unique ".concat(uniqueFields.join(', ')));
|
|
66
|
+
} // Pass an object of relevant component state as first argument for any passed-in press handlers
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
const pressHandlers = getPressHandlersWithArgs(rest, [{
|
|
70
|
+
id,
|
|
71
|
+
label,
|
|
72
|
+
currentValues
|
|
73
|
+
}]);
|
|
74
|
+
|
|
75
|
+
const handleChange = event => {
|
|
76
|
+
if (pressHandlers.onPress) pressHandlers === null || pressHandlers === void 0 ? void 0 : pressHandlers.onPress(event);
|
|
77
|
+
setIsOpen(true);
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
const onApply = e => {
|
|
81
|
+
setValues(e);
|
|
82
|
+
setIsOpen(false);
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
return /*#__PURE__*/_jsxs(_Fragment, {
|
|
86
|
+
children: [/*#__PURE__*/_jsxs(Modal, {
|
|
87
|
+
isOpen: isOpen,
|
|
88
|
+
onClose: () => setIsOpen(false),
|
|
89
|
+
variant: {
|
|
90
|
+
width: colSize > 1 ? 'size576' : 's'
|
|
91
|
+
},
|
|
92
|
+
children: [/*#__PURE__*/_jsx(Row, {
|
|
93
|
+
children: /*#__PURE__*/_jsx(Typography, {
|
|
94
|
+
variant: {
|
|
95
|
+
size: 'h4'
|
|
96
|
+
},
|
|
97
|
+
children: getCopy('filterByLabel').replace(/%\{filterCategory\}/g, label.toLowerCase())
|
|
98
|
+
})
|
|
99
|
+
}), /*#__PURE__*/_jsx(Spacer, {
|
|
100
|
+
space: 4
|
|
101
|
+
}), /*#__PURE__*/_jsx(Spacer, {
|
|
102
|
+
space: 1
|
|
103
|
+
}), /*#__PURE__*/_jsx(Box, {
|
|
104
|
+
scroll: true,
|
|
105
|
+
children: /*#__PURE__*/_jsx(Row, {
|
|
106
|
+
distribute: "between",
|
|
107
|
+
children: [...Array(colSize).keys()].map(i => /*#__PURE__*/_jsxs(Col, {
|
|
108
|
+
xs: 12 / colSize,
|
|
109
|
+
children: [/*#__PURE__*/_jsx(CheckboxGroup, {
|
|
110
|
+
items: items.slice(i * rowLimit, (i + 1) * rowLimit),
|
|
111
|
+
checkedIds: checkedIds,
|
|
112
|
+
onChange: e => setCheckedIds(e, i)
|
|
113
|
+
}), /*#__PURE__*/_jsx(Spacer, {
|
|
114
|
+
size: 4
|
|
115
|
+
})]
|
|
116
|
+
}, i))
|
|
117
|
+
})
|
|
118
|
+
}), /*#__PURE__*/_jsx(Divider, {
|
|
119
|
+
variant: {
|
|
120
|
+
width: 'full',
|
|
121
|
+
color: 'E3E6E8',
|
|
122
|
+
decorative: true,
|
|
123
|
+
weight: 'thin'
|
|
124
|
+
},
|
|
125
|
+
space: 4
|
|
126
|
+
}), /*#__PURE__*/_jsx(Row, {
|
|
127
|
+
children: /*#__PURE__*/_jsxs(StackView, {
|
|
128
|
+
direction: "row",
|
|
129
|
+
space: 3,
|
|
130
|
+
tokens: {
|
|
131
|
+
alignItems: 'center'
|
|
132
|
+
},
|
|
133
|
+
children: [/*#__PURE__*/_jsx(Button, {
|
|
134
|
+
onPress: () => onApply(checkedIds),
|
|
135
|
+
variant: {
|
|
136
|
+
size: 'small',
|
|
137
|
+
priority: 'high'
|
|
138
|
+
},
|
|
139
|
+
children: getCopy('applyButtonLabel')
|
|
140
|
+
}), /*#__PURE__*/_jsx(Box, {
|
|
141
|
+
children: /*#__PURE__*/_jsx(TextButton, {
|
|
142
|
+
onPress: () => setCheckedIds([]),
|
|
143
|
+
children: getCopy('clearButtonLabel')
|
|
144
|
+
})
|
|
145
|
+
})]
|
|
146
|
+
})
|
|
147
|
+
})]
|
|
148
|
+
}), /*#__PURE__*/_jsx(ButtonDropdown, {
|
|
149
|
+
ref: ref,
|
|
150
|
+
...pressHandlers,
|
|
151
|
+
value: isOpen,
|
|
152
|
+
selected: isSelected,
|
|
153
|
+
label: label,
|
|
154
|
+
onChange: handleChange,
|
|
155
|
+
tokens: getButtonTokens,
|
|
156
|
+
inactive: inactive
|
|
157
|
+
}, id)]
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
MultiSelectFilter.displayName = 'MultiSelectFilter';
|
|
161
|
+
MultiSelectFilter.propTypes = {
|
|
162
|
+
/**
|
|
163
|
+
* The text displayed to the user in a ButtonDropdown.
|
|
164
|
+
*/
|
|
165
|
+
label: PropTypes.string.isRequired,
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* An optional unique string may be provided to identify the ButtonDropdown.
|
|
169
|
+
* If not provided, the label is used.
|
|
170
|
+
*/
|
|
171
|
+
id: PropTypes.string,
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Sets the variant for ButtonDropdown element.
|
|
175
|
+
*/
|
|
176
|
+
variant: variantProp.propType,
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Sets the tokens for ButtonDropdown element.
|
|
180
|
+
*/
|
|
181
|
+
tokens: getTokensPropType('ButtonDropdown'),
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* The options a user may select.
|
|
185
|
+
*/
|
|
186
|
+
items: PropTypes.arrayOf(PropTypes.shape({
|
|
187
|
+
/**
|
|
188
|
+
* The text displayed to the user with a checkbox, describing this option.
|
|
189
|
+
*/
|
|
190
|
+
label: PropTypes.string.isRequired,
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* An optional unique string may be provided to identify this option.
|
|
194
|
+
* If not provided, the label is used.
|
|
195
|
+
*/
|
|
196
|
+
id: PropTypes.string
|
|
197
|
+
})),
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* If the selected item(s) in the checkbox group(s) are to be controlled externally by
|
|
201
|
+
* a parent component, pass an array of strings as well as an `onChange` handler.
|
|
202
|
+
* Passing an array for "values" makes the MultiSelectFilter a "controlled" component that
|
|
203
|
+
* expects its state to be handled via `onChange` and so doesn't handle it itself.
|
|
204
|
+
*/
|
|
205
|
+
values: PropTypes.arrayOf(PropTypes.string),
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* If `values` is not passed, making the MultiSelectFilter an "uncontrolled" component
|
|
209
|
+
* managing its own selected state, a default set of selections may be provided.
|
|
210
|
+
* Changing the `initialValues` does not change the user's selections.
|
|
211
|
+
*/
|
|
212
|
+
initialValues: PropTypes.arrayOf(PropTypes.string),
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* If provided, sets a maximum number of items a user may select at once.
|
|
216
|
+
*/
|
|
217
|
+
maxValues: PropTypes.number,
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* If provided, this function is called when the current selection is changed
|
|
221
|
+
* and is passed an array of the `id`s of all currently selected `items`.
|
|
222
|
+
*/
|
|
223
|
+
onChange: PropTypes.func,
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Select English or French copy for the accessible label.
|
|
227
|
+
*/
|
|
228
|
+
copy: PropTypes.oneOf(['en', 'fr']),
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* If true, the ButtonDropdown cannot be selected by the user and simply show their current state.
|
|
232
|
+
*/
|
|
233
|
+
readOnly: PropTypes.string,
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* If true, the MultiSelectFilter cannot be interacted with, ButtonDropdown is
|
|
237
|
+
* set as `disabled` and if the theme supports `inactive` appearances rules, these
|
|
238
|
+
* are applied.
|
|
239
|
+
*/
|
|
240
|
+
inactive: PropTypes.string,
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Sets the maximum number of items in one column. If number of items are more
|
|
244
|
+
* than the `rowLimit`, they will be rendered in 2 columns.
|
|
245
|
+
*/
|
|
246
|
+
rowLimit: PropTypes.number
|
|
247
|
+
};
|
|
248
|
+
export default MultiSelectFilter;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
en: {
|
|
3
|
+
filterByLabel: 'Filter by %{filterCategory}:',
|
|
4
|
+
applyButtonLabel: 'Apply',
|
|
5
|
+
clearButtonLabel: 'Clear'
|
|
6
|
+
},
|
|
7
|
+
fr: {
|
|
8
|
+
filterByLabel: 'Filtrer par %{filterCategory}:',
|
|
9
|
+
applyButtonLabel: 'Appliquer',
|
|
10
|
+
clearButtonLabel: 'Effacer'
|
|
11
|
+
}
|
|
12
|
+
};
|
|
@@ -110,8 +110,11 @@ const Search = /*#__PURE__*/forwardRef((_ref3, ref) => {
|
|
|
110
110
|
};
|
|
111
111
|
|
|
112
112
|
const handleClear = event => {
|
|
113
|
+
var _ref$current;
|
|
114
|
+
|
|
113
115
|
setValue('', event);
|
|
114
|
-
|
|
116
|
+
onClear === null || onClear === void 0 ? void 0 : onClear('', event);
|
|
117
|
+
ref === null || ref === void 0 ? void 0 : (_ref$current = ref.current) === null || _ref$current === void 0 ? void 0 : _ref$current.focus();
|
|
115
118
|
};
|
|
116
119
|
|
|
117
120
|
const handleFocus = event => {
|
|
@@ -4,7 +4,8 @@ import View from "react-native-web/dist/exports/View";
|
|
|
4
4
|
import Platform from "react-native-web/dist/exports/Platform";
|
|
5
5
|
import NativePicker from 'react-native-picker-select';
|
|
6
6
|
import { a11yProps, componentPropType } from '../utils';
|
|
7
|
-
import Group from './Group';
|
|
7
|
+
import Group from './Group';
|
|
8
|
+
import { ANDROID_HEIGHT_OFFSET, ANDROID_HORIZONTAL_PADDING_OFFSET, ANDROID_DEFAULT_PADDING } from './constants'; // Styling of the native input is very limited, most of the styles have to be applied to an additional View
|
|
8
9
|
|
|
9
10
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
10
11
|
import { Fragment as _Fragment } from "react/jsx-runtime";
|
|
@@ -12,28 +13,29 @@ import { Fragment as _Fragment } from "react/jsx-runtime";
|
|
|
12
13
|
const selectAndroidInputStyles = _ref => {
|
|
13
14
|
let {
|
|
14
15
|
height = 0,
|
|
15
|
-
paddingBottom = 0,
|
|
16
|
-
paddingTop = 0,
|
|
17
|
-
borderWidth = 0,
|
|
18
16
|
color
|
|
19
17
|
} = _ref;
|
|
20
18
|
return {
|
|
21
|
-
height
|
|
19
|
+
height,
|
|
20
|
+
paddingBottom: 0,
|
|
21
|
+
paddingTop: 0,
|
|
22
22
|
color
|
|
23
23
|
};
|
|
24
|
-
}; //
|
|
24
|
+
}; // The native input has a side padding of 8px, which can't be adjusted, so we have to account for that in the container
|
|
25
25
|
|
|
26
26
|
|
|
27
27
|
const selectAndroidContainerStyles = _ref2 => {
|
|
28
28
|
let {
|
|
29
|
-
paddingLeft =
|
|
30
|
-
paddingRight =
|
|
29
|
+
paddingLeft = ANDROID_DEFAULT_PADDING,
|
|
30
|
+
paddingRight = ANDROID_DEFAULT_PADDING,
|
|
31
31
|
...rest
|
|
32
32
|
} = _ref2;
|
|
33
|
-
return {
|
|
34
|
-
paddingLeft: paddingLeft >
|
|
35
|
-
paddingRight: paddingRight >
|
|
36
|
-
|
|
33
|
+
return { ...rest,
|
|
34
|
+
paddingLeft: paddingLeft > ANDROID_HORIZONTAL_PADDING_OFFSET ? paddingLeft - ANDROID_HORIZONTAL_PADDING_OFFSET : ANDROID_DEFAULT_PADDING,
|
|
35
|
+
paddingRight: paddingRight > ANDROID_HORIZONTAL_PADDING_OFFSET ? paddingRight - ANDROID_HORIZONTAL_PADDING_OFFSET : ANDROID_DEFAULT_PADDING,
|
|
36
|
+
paddingBottom: ANDROID_DEFAULT_PADDING,
|
|
37
|
+
paddingTop: ANDROID_DEFAULT_PADDING,
|
|
38
|
+
height: rest.height + ANDROID_HEIGHT_OFFSET
|
|
37
39
|
};
|
|
38
40
|
};
|
|
39
41
|
|
|
@@ -49,7 +51,7 @@ const Picker = /*#__PURE__*/forwardRef((_ref3, ref) => {
|
|
|
49
51
|
placeholder,
|
|
50
52
|
...rest
|
|
51
53
|
} = _ref3;
|
|
52
|
-
//
|
|
54
|
+
// Ungroup items, since there's no way to support groups on native
|
|
53
55
|
const flatChildren = Children.toArray(children).flatMap(child => {
|
|
54
56
|
if (child.type === Group) {
|
|
55
57
|
return child.props.children;
|
|
@@ -7,6 +7,7 @@ import { applyTextStyles, useThemeTokens, applyOuterBorder, useTheme } from '../
|
|
|
7
7
|
import { a11yProps, componentPropType, getTokensPropType, inputSupportsProps, selectSystemProps, useInputValue, variantProp, viewProps } from '../utils';
|
|
8
8
|
import Picker from './Picker';
|
|
9
9
|
import InputSupports from '../InputSupports';
|
|
10
|
+
import { ANDROID_VALIDATION_ICON_CONTAINER_OFFSET } from './constants';
|
|
10
11
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
11
12
|
import { jsxs as _jsxs } from "react/jsx-runtime";
|
|
12
13
|
const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, inputSupportsProps, viewProps]);
|
|
@@ -142,7 +143,11 @@ const selectValidationIconContainerStyles = _ref6 => {
|
|
|
142
143
|
} = _ref6;
|
|
143
144
|
return {
|
|
144
145
|
paddingRight: icon ? paddingRight + iconSize : paddingRight,
|
|
145
|
-
|
|
146
|
+
...(Platform.OS === 'android' ? {
|
|
147
|
+
paddingBottom: paddingBottom + ANDROID_VALIDATION_ICON_CONTAINER_OFFSET
|
|
148
|
+
} : {
|
|
149
|
+
paddingBottom
|
|
150
|
+
})
|
|
146
151
|
};
|
|
147
152
|
};
|
|
148
153
|
/**
|
|
@@ -185,7 +185,8 @@ const Step = _ref7 => {
|
|
|
185
185
|
space: 0,
|
|
186
186
|
tokens: {
|
|
187
187
|
alignItems: 'center',
|
|
188
|
-
flexGrow: 0
|
|
188
|
+
flexGrow: 0,
|
|
189
|
+
justifyContent: 'center'
|
|
189
190
|
},
|
|
190
191
|
children: [/*#__PURE__*/_jsx(View, {
|
|
191
192
|
style: [staticStyles.connector, !isFirst && selectConnectorStyles(themeTokens, isActive)]
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React, { forwardRef } from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
2
3
|
import { a11yProps, focusHandlerProps, getTokensPropType, inputSupportsProps, selectSystemProps, textInputHandlerProps, textInputProps, variantProp, viewProps } from '../utils';
|
|
3
4
|
import InputSupports from '../InputSupports';
|
|
4
5
|
import TextInputBase from './TextInputBase';
|
|
@@ -61,6 +62,11 @@ const TextInput = /*#__PURE__*/forwardRef((_ref, ref) => {
|
|
|
61
62
|
TextInput.displayName = 'TextInput';
|
|
62
63
|
TextInput.propTypes = { ...selectedSystemPropTypes,
|
|
63
64
|
...textInputPropTypes,
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* A callback which if provided will get a clear button rendered and will be called whenever that button gets pressed.
|
|
68
|
+
*/
|
|
69
|
+
onClear: PropTypes.func,
|
|
64
70
|
tokens: getTokensPropType('TextInput'),
|
|
65
71
|
variant: variantProp.propType
|
|
66
72
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { forwardRef, useEffect, useState } from 'react';
|
|
1
|
+
import React, { forwardRef, useEffect, useRef, useState } from 'react';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
3
|
import Platform from "react-native-web/dist/exports/Platform";
|
|
4
4
|
import StyleSheet from "react-native-web/dist/exports/StyleSheet";
|
|
@@ -6,7 +6,9 @@ import NativeTextInput from "react-native-web/dist/exports/TextInput";
|
|
|
6
6
|
import View from "react-native-web/dist/exports/View";
|
|
7
7
|
import { applyTextStyles, useTheme, useThemeTokens, applyOuterBorder } from '../ThemeProvider';
|
|
8
8
|
import StackView from '../StackView';
|
|
9
|
-
import
|
|
9
|
+
import IconButton from '../IconButton';
|
|
10
|
+
import { a11yProps, getTokensPropType, selectSystemProps, textInputHandlerProps, textInputProps, useCopy, useInputValue, useSpacingScale, variantProp, viewProps } from '../utils';
|
|
11
|
+
import dictionary from './dictionary';
|
|
10
12
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
11
13
|
import { jsxs as _jsxs } from "react/jsx-runtime";
|
|
12
14
|
const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, textInputHandlerProps, textInputProps, viewProps]);
|
|
@@ -136,12 +138,14 @@ const selectButtonsContainerStyle = _ref5 => {
|
|
|
136
138
|
const TextInputBase = /*#__PURE__*/forwardRef((_ref6, ref) => {
|
|
137
139
|
let {
|
|
138
140
|
buttons = [],
|
|
141
|
+
copy = 'en',
|
|
139
142
|
height,
|
|
140
143
|
inactive,
|
|
141
144
|
initialValue,
|
|
142
145
|
onBlur,
|
|
143
146
|
onChange,
|
|
144
147
|
onChangeText,
|
|
148
|
+
onClear,
|
|
145
149
|
onFocus,
|
|
146
150
|
onMouseOut,
|
|
147
151
|
onMouseOver,
|
|
@@ -176,17 +180,22 @@ const TextInputBase = /*#__PURE__*/forwardRef((_ref6, ref) => {
|
|
|
176
180
|
if (typeof onMouseOut === 'function') onMouseOut(event);
|
|
177
181
|
};
|
|
178
182
|
|
|
183
|
+
const defaultRef = useRef();
|
|
184
|
+
const inputRef = ref !== null && ref !== void 0 ? ref : defaultRef;
|
|
179
185
|
const {
|
|
180
186
|
currentValue,
|
|
187
|
+
resetValue,
|
|
181
188
|
setValue,
|
|
182
|
-
isControlled
|
|
189
|
+
isControlled,
|
|
190
|
+
isDirty
|
|
183
191
|
} = useInputValue({
|
|
184
192
|
value,
|
|
185
193
|
initialValue,
|
|
194
|
+
inputRef,
|
|
186
195
|
onChange,
|
|
187
196
|
readOnly
|
|
188
197
|
});
|
|
189
|
-
const element =
|
|
198
|
+
const element = inputRef === null || inputRef === void 0 ? void 0 : inputRef.current;
|
|
190
199
|
useEffect(() => {
|
|
191
200
|
if (Platform.OS === 'web' && pattern && element) {
|
|
192
201
|
// React Native Web doesn't support `pattern`, so we have to attach it via a ref,
|
|
@@ -210,9 +219,35 @@ const TextInputBase = /*#__PURE__*/forwardRef((_ref6, ref) => {
|
|
|
210
219
|
};
|
|
211
220
|
const themeTokens = useThemeTokens('TextInput', tokens, variant, states);
|
|
212
221
|
const {
|
|
213
|
-
|
|
214
|
-
|
|
222
|
+
buttonsGap,
|
|
223
|
+
clearButtonIcon: ClearButtonIcon,
|
|
224
|
+
icon: IconComponent
|
|
215
225
|
} = themeTokens;
|
|
226
|
+
const buttonsGapSize = useSpacingScale(buttonsGap);
|
|
227
|
+
const getCopy = useCopy({
|
|
228
|
+
dictionary,
|
|
229
|
+
copy
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
if (onClear && isDirty) {
|
|
233
|
+
const handleClear = event => {
|
|
234
|
+
var _inputRef$current;
|
|
235
|
+
|
|
236
|
+
onClear === null || onClear === void 0 ? void 0 : onClear(event);
|
|
237
|
+
resetValue(event);
|
|
238
|
+
inputRef === null || inputRef === void 0 ? void 0 : (_inputRef$current = inputRef.current) === null || _inputRef$current === void 0 ? void 0 : _inputRef$current.focus();
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
buttons === null || buttons === void 0 ? void 0 : buttons.unshift( /*#__PURE__*/_jsx(IconButton, {
|
|
242
|
+
accessibilityLabel: getCopy('clearButtonAccessibilityLabel'),
|
|
243
|
+
icon: ClearButtonIcon,
|
|
244
|
+
onPress: handleClear,
|
|
245
|
+
variant: {
|
|
246
|
+
compact: true
|
|
247
|
+
}
|
|
248
|
+
}, "clear"));
|
|
249
|
+
}
|
|
250
|
+
|
|
216
251
|
const inputProps = { ...selectProps(rest),
|
|
217
252
|
editable: !inactive,
|
|
218
253
|
onFocus: handleFocus,
|
|
@@ -224,9 +259,7 @@ const TextInputBase = /*#__PURE__*/forwardRef((_ref6, ref) => {
|
|
|
224
259
|
// currentValue is being updated even if the input is not controlled, passing it down to the
|
|
225
260
|
// Input could lead to changing its state from uncontrolled to controlled
|
|
226
261
|
value: isControlled ? currentValue : undefined
|
|
227
|
-
};
|
|
228
|
-
|
|
229
|
-
const buttonsGapSize = useSpacingScale(buttonsGap);
|
|
262
|
+
};
|
|
230
263
|
const {
|
|
231
264
|
themeOptions
|
|
232
265
|
} = useTheme();
|
|
@@ -236,7 +269,7 @@ const TextInputBase = /*#__PURE__*/forwardRef((_ref6, ref) => {
|
|
|
236
269
|
return /*#__PURE__*/_jsxs(View, {
|
|
237
270
|
style: selectOuterBorderStyles(themeTokens),
|
|
238
271
|
children: [/*#__PURE__*/_jsx(NativeTextInput, {
|
|
239
|
-
ref:
|
|
272
|
+
ref: inputRef,
|
|
240
273
|
style: nativeInputStyle,
|
|
241
274
|
...inputProps
|
|
242
275
|
}), IconComponent && /*#__PURE__*/_jsx(View, {
|
|
@@ -260,12 +293,21 @@ const TextInputBase = /*#__PURE__*/forwardRef((_ref6, ref) => {
|
|
|
260
293
|
TextInputBase.displayName = 'TextInputBase';
|
|
261
294
|
TextInputBase.propTypes = { ...selectedSystemPropTypes,
|
|
262
295
|
buttons: PropTypes.arrayOf(PropTypes.node),
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Select English or French copy for the accessible labels.
|
|
299
|
+
* You may also pass in a custom dictionary object.
|
|
300
|
+
*/
|
|
301
|
+
copy: PropTypes.oneOfType([PropTypes.oneOf(['en', 'fr']), PropTypes.shape({
|
|
302
|
+
clearButtonAccessibilityLabel: PropTypes.string
|
|
303
|
+
})]),
|
|
263
304
|
height: PropTypes.number,
|
|
264
305
|
inactive: PropTypes.bool,
|
|
265
306
|
initialValue: PropTypes.string,
|
|
266
307
|
onBlur: PropTypes.func,
|
|
267
308
|
onChange: PropTypes.func,
|
|
268
309
|
onChangeText: PropTypes.func,
|
|
310
|
+
onClear: PropTypes.func,
|
|
269
311
|
onFocus: PropTypes.func,
|
|
270
312
|
onMouseOut: PropTypes.func,
|
|
271
313
|
onMouseOver: PropTypes.func,
|
|
@@ -5,18 +5,28 @@ import responsiveProps from '../utils/props/responsiveProps';
|
|
|
5
5
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
6
6
|
export const uninitialisedError = new Error('Theme context used outside of ThemeProvider');
|
|
7
7
|
export const ThemeContext = /*#__PURE__*/createContext(uninitialisedError);
|
|
8
|
-
export const ThemeSetterContext = /*#__PURE__*/createContext(uninitialisedError);
|
|
8
|
+
export const ThemeSetterContext = /*#__PURE__*/createContext(uninitialisedError); // These options default to `true` in v1.x to match legacy defaults and avoid breaking changes.
|
|
9
|
+
// This should change in future major releases to become "opt-in" legacy support.
|
|
10
|
+
|
|
11
|
+
const defaultThemeOptions = {
|
|
12
|
+
// TODO: switch `forceAbsoluteFontSizing` to be false by default in the next major version
|
|
13
|
+
forceAbsoluteFontSizing: true,
|
|
14
|
+
// TODO: switch `forceZIndex` to be false by default in the next major version
|
|
15
|
+
forceZIndex: true,
|
|
16
|
+
// TODO: switch `enableHelmetSSR` to be false by default in the next major version
|
|
17
|
+
enableHelmetSSR: true
|
|
18
|
+
};
|
|
9
19
|
|
|
10
20
|
const ThemeProvider = _ref => {
|
|
11
21
|
let {
|
|
12
22
|
children,
|
|
13
23
|
defaultTheme,
|
|
14
|
-
|
|
15
|
-
themeOptions = {
|
|
16
|
-
forceAbsoluteFontSizing: true
|
|
17
|
-
}
|
|
24
|
+
themeOptions = {}
|
|
18
25
|
} = _ref;
|
|
19
|
-
const [theme, setTheme] = useState(defaultTheme);
|
|
26
|
+
const [theme, setTheme] = useState(defaultTheme);
|
|
27
|
+
const appliedThemeOptions = { ...defaultThemeOptions,
|
|
28
|
+
...themeOptions
|
|
29
|
+
}; // Validate the theme tokens version on every render.
|
|
20
30
|
// This will intentionally break the application when attempting to use an invalid theme.
|
|
21
31
|
// This will surface an incompatibility quickly rather than allowing the potential for strange bugs due to missing or incompatible tokens.
|
|
22
32
|
|
|
@@ -25,7 +35,7 @@ const ThemeProvider = _ref => {
|
|
|
25
35
|
value: setTheme,
|
|
26
36
|
children: /*#__PURE__*/_jsx(ThemeContext.Provider, {
|
|
27
37
|
value: { ...theme,
|
|
28
|
-
themeOptions
|
|
38
|
+
themeOptions: appliedThemeOptions
|
|
29
39
|
},
|
|
30
40
|
children: children
|
|
31
41
|
})
|
|
@@ -48,9 +58,16 @@ ThemeProvider.propTypes = {
|
|
|
48
58
|
* relative sizing (in `rem`, scales depending on the browser settings)
|
|
49
59
|
* - `contentMaxWidth`: allows configuration of the content max width to be used in components
|
|
50
60
|
* such as Footnote and Notification to avoid content to stretch width more then the page's width
|
|
61
|
+
* - `forceZIndex`: available on web only, when set to false, sets zIndex on `View` to be `auto`
|
|
62
|
+
* and when true, sets zIndex to be `0` (the default from `react-native-web`)
|
|
63
|
+
* - `enableHelmetSSR`: on Web SSR, allows React Helmet to run during server-side rendering. This should be
|
|
64
|
+
* disabled unless a web app has been specifically configured to stop React Helmet accumulating
|
|
65
|
+
* instances (which may cause a memory leak). See React Helmet's docs: https://github.com/nfl/react-helmet
|
|
51
66
|
*/
|
|
52
67
|
themeOptions: PropTypes.shape({
|
|
53
68
|
forceAbsoluteFontSizing: PropTypes.bool,
|
|
69
|
+
forceZIndex: PropTypes.bool,
|
|
70
|
+
enableHelmetSSR: PropTypes.bool,
|
|
54
71
|
contentMaxWidth: responsiveProps.getTypeOptionallyByViewport(PropTypes.number)
|
|
55
72
|
})
|
|
56
73
|
};
|
|
@@ -45,7 +45,9 @@ export function applyTextStyles(_ref) {
|
|
|
45
45
|
// Don't set undefined font families. May need some validation here that the font is available.
|
|
46
46
|
// Android doesn't recognise font weights natively so apply custom font weights via `fontFamily`.
|
|
47
47
|
styles.fontFamily = "".concat(fontName).concat(fontWeight).concat(fontStyle);
|
|
48
|
-
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (fontWeight) {
|
|
49
51
|
// If using system default font, apply the font weight directly.
|
|
50
52
|
// Font weight support in Android is limited to 'bold' or anything else === 'normal'.
|
|
51
53
|
styles.fontWeight = Platform.OS === 'android' && Number(fontWeight) > 400 ? 'bold' : fontWeight;
|
package/lib-module/index.js
CHANGED
|
@@ -21,6 +21,7 @@ export { default as InputSupports } from './InputSupports';
|
|
|
21
21
|
export * from './Link';
|
|
22
22
|
export { default as List, ListItem, ListBase } from './List';
|
|
23
23
|
export { default as Modal } from './Modal';
|
|
24
|
+
export { default as MultiSelectFilter } from './MultiSelectFilter';
|
|
24
25
|
export { default as Notification } from './Notification';
|
|
25
26
|
export { default as Pagination } from './Pagination';
|
|
26
27
|
export { default as Progress } from './Progress';
|
|
@@ -49,6 +50,7 @@ export { default as TooltipButton } from './TooltipButton';
|
|
|
49
50
|
export { default as Typography } from './Typography';
|
|
50
51
|
export { default as A11yInfoProvider, useA11yInfo } from './A11yInfoProvider';
|
|
51
52
|
export { default as BaseProvider } from './BaseProvider';
|
|
53
|
+
export { useHydrationContext } from './BaseProvider/HydrationContext';
|
|
52
54
|
export { default as ViewportProvider, useViewport, ViewportContext } from './ViewportProvider';
|
|
53
55
|
export { default as ThemeProvider, useTheme, useSetTheme, useThemeTokens, getThemeTokens, applyOuterBorder, applyTextStyles, applyShadowToken } from './ThemeProvider';
|
|
54
56
|
export * from './utils';
|