@telus-uds/components-base 1.19.0 → 1.20.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.
Files changed (94) hide show
  1. package/CHANGELOG.md +22 -2
  2. package/__tests17__/ThemeProvider/ThemeProvider.test.jsx +2 -1
  3. package/component-docs.json +834 -125
  4. package/lib/BaseProvider/index.js +2 -1
  5. package/lib/Box/Box.js +14 -1
  6. package/lib/Button/ButtonDropdown.js +207 -0
  7. package/lib/Button/index.js +8 -0
  8. package/lib/Carousel/Carousel.js +2 -2
  9. package/lib/Carousel/CarouselItem/CarouselItem.js +7 -1
  10. package/lib/Carousel/CarouselTabs/CarouselTabsPanel.js +21 -4
  11. package/lib/FlexGrid/Col/Col.js +1 -3
  12. package/lib/FlexGrid/FlexGrid.js +3 -5
  13. package/lib/FlexGrid/Row/Row.js +3 -3
  14. package/lib/IconButton/IconButton.js +12 -4
  15. package/lib/MultiSelectFilter/MultiSelectFilter.js +276 -0
  16. package/lib/MultiSelectFilter/dictionary.js +19 -0
  17. package/lib/MultiSelectFilter/index.js +13 -0
  18. package/lib/Search/Search.js +4 -1
  19. package/lib/Select/Picker.native.js +16 -13
  20. package/lib/Select/Select.js +7 -1
  21. package/lib/Select/constants.js +15 -0
  22. package/lib/StepTracker/Step.js +2 -1
  23. package/lib/TextInput/TextInput.js +9 -2
  24. package/lib/TextInput/TextInputBase.js +52 -8
  25. package/lib/TextInput/dictionary.js +15 -0
  26. package/lib/ThemeProvider/ThemeProvider.js +6 -1
  27. package/lib/index.js +9 -0
  28. package/lib/utils/BaseView/BaseView.js +64 -0
  29. package/lib/utils/BaseView/BaseView.native.js +16 -0
  30. package/lib/utils/BaseView/index.js +13 -0
  31. package/lib/utils/index.js +10 -1
  32. package/lib/utils/input.js +11 -3
  33. package/lib/utils/props/handlerProps.js +5 -0
  34. package/lib-module/BaseProvider/index.js +2 -1
  35. package/lib-module/Box/Box.js +14 -1
  36. package/lib-module/Button/ButtonDropdown.js +181 -0
  37. package/lib-module/Button/index.js +2 -1
  38. package/lib-module/Carousel/Carousel.js +2 -2
  39. package/lib-module/Carousel/CarouselItem/CarouselItem.js +8 -2
  40. package/lib-module/Carousel/CarouselTabs/CarouselTabsPanel.js +23 -6
  41. package/lib-module/FlexGrid/Col/Col.js +2 -3
  42. package/lib-module/FlexGrid/FlexGrid.js +2 -3
  43. package/lib-module/FlexGrid/Row/Row.js +2 -2
  44. package/lib-module/IconButton/IconButton.js +14 -4
  45. package/lib-module/MultiSelectFilter/MultiSelectFilter.js +248 -0
  46. package/lib-module/MultiSelectFilter/dictionary.js +12 -0
  47. package/lib-module/MultiSelectFilter/index.js +2 -0
  48. package/lib-module/Search/Search.js +4 -1
  49. package/lib-module/Select/Picker.native.js +15 -13
  50. package/lib-module/Select/Select.js +6 -1
  51. package/lib-module/Select/constants.js +5 -0
  52. package/lib-module/StepTracker/Step.js +2 -1
  53. package/lib-module/TextInput/TextInput.js +6 -0
  54. package/lib-module/TextInput/TextInputBase.js +52 -10
  55. package/lib-module/TextInput/dictionary.js +8 -0
  56. package/lib-module/ThemeProvider/ThemeProvider.js +6 -1
  57. package/lib-module/index.js +1 -0
  58. package/lib-module/utils/BaseView/BaseView.js +43 -0
  59. package/lib-module/utils/BaseView/BaseView.native.js +6 -0
  60. package/lib-module/utils/BaseView/index.js +2 -0
  61. package/lib-module/utils/index.js +2 -1
  62. package/lib-module/utils/input.js +11 -3
  63. package/lib-module/utils/props/handlerProps.js +5 -0
  64. package/package.json +3 -3
  65. package/src/BaseProvider/index.jsx +4 -1
  66. package/src/Box/Box.jsx +14 -1
  67. package/src/Button/ButtonDropdown.jsx +179 -0
  68. package/src/Button/index.js +2 -1
  69. package/src/Carousel/Carousel.jsx +6 -3
  70. package/src/Carousel/CarouselItem/CarouselItem.jsx +9 -2
  71. package/src/Carousel/CarouselTabs/CarouselTabsPanel.jsx +19 -5
  72. package/src/FlexGrid/Col/Col.jsx +4 -4
  73. package/src/FlexGrid/FlexGrid.jsx +11 -10
  74. package/src/FlexGrid/Row/Row.jsx +4 -3
  75. package/src/IconButton/IconButton.jsx +3 -1
  76. package/src/MultiSelectFilter/MultiSelectFilter.jsx +227 -0
  77. package/src/MultiSelectFilter/dictionary.js +12 -0
  78. package/src/MultiSelectFilter/index.js +3 -0
  79. package/src/Search/Search.jsx +2 -1
  80. package/src/Select/Picker.native.jsx +29 -14
  81. package/src/Select/Select.jsx +7 -1
  82. package/src/Select/constants.js +5 -0
  83. package/src/StepTracker/Step.jsx +5 -1
  84. package/src/TextInput/TextInput.jsx +5 -0
  85. package/src/TextInput/TextInputBase.jsx +43 -8
  86. package/src/TextInput/dictionary.js +8 -0
  87. package/src/ThemeProvider/ThemeProvider.jsx +5 -1
  88. package/src/index.js +1 -0
  89. package/src/utils/BaseView/BaseView.jsx +38 -0
  90. package/src/utils/BaseView/BaseView.native.jsx +6 -0
  91. package/src/utils/BaseView/index.js +3 -0
  92. package/src/utils/index.js +1 -0
  93. package/src/utils/input.js +9 -4
  94. package/src/utils/props/handlerProps.js +4 -0
@@ -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
+ };
@@ -0,0 +1,2 @@
1
+ import MultiSelectFilter from './MultiSelectFilter';
2
+ export default MultiSelectFilter;
@@ -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
- if (onClear !== undefined) onClear('', event);
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'; // styling of the native input is very limited, most of the styles have to be applied to an additional View
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: height - paddingTop - paddingBottom - 2 * borderWidth,
19
+ height,
20
+ paddingBottom: 0,
21
+ paddingTop: 0,
22
22
  color
23
23
  };
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
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 = 0,
30
- paddingRight = 0,
29
+ paddingLeft = ANDROID_DEFAULT_PADDING,
30
+ paddingRight = ANDROID_DEFAULT_PADDING,
31
31
  ...rest
32
32
  } = _ref2;
33
- return {
34
- paddingLeft: paddingLeft > 8 ? paddingLeft - 8 : 0,
35
- paddingRight: paddingRight > 8 ? paddingRight - 8 : 0,
36
- ...rest
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
- // ungroup items, since there's no way to support groups on native
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
- paddingBottom
146
+ ...(Platform.OS === 'android' ? {
147
+ paddingBottom: paddingBottom + ANDROID_VALIDATION_ICON_CONTAINER_OFFSET
148
+ } : {
149
+ paddingBottom
150
+ })
146
151
  };
147
152
  };
148
153
  /**
@@ -0,0 +1,5 @@
1
+ // Because Android
2
+ export const ANDROID_VALIDATION_ICON_CONTAINER_OFFSET = 5;
3
+ export const ANDROID_HEIGHT_OFFSET = 12;
4
+ export const ANDROID_HORIZONTAL_PADDING_OFFSET = 8;
5
+ export const ANDROID_DEFAULT_PADDING = 0;
@@ -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 { a11yProps, getTokensPropType, selectSystemProps, textInputHandlerProps, textInputProps, useInputValue, useSpacingScale, variantProp, viewProps } from '../utils';
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 = ref === null || ref === void 0 ? void 0 : ref.current;
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
- icon: IconComponent,
214
- buttonsGap
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
- }; // Get the actual gap value for the current viewport
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: 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,
@@ -0,0 +1,8 @@
1
+ export default {
2
+ en: {
3
+ clearButtonAccessibilityLabel: 'Clear'
4
+ },
5
+ fr: {
6
+ clearButtonAccessibilityLabel: 'Effacer'
7
+ }
8
+ };
@@ -12,8 +12,10 @@ const ThemeProvider = _ref => {
12
12
  children,
13
13
  defaultTheme,
14
14
  // TODO: switch `forceAbsoluteFontSizing` to be false by default in the next major version
15
+ // TODO: switch `forceZIndex` to be false by default in the next major version
15
16
  themeOptions = {
16
- forceAbsoluteFontSizing: true
17
+ forceAbsoluteFontSizing: true,
18
+ forceZIndex: true
17
19
  }
18
20
  } = _ref;
19
21
  const [theme, setTheme] = useState(defaultTheme); // Validate the theme tokens version on every render.
@@ -48,9 +50,12 @@ ThemeProvider.propTypes = {
48
50
  * relative sizing (in `rem`, scales depending on the browser settings)
49
51
  * - `contentMaxWidth`: allows configuration of the content max width to be used in components
50
52
  * such as Footnote and Notification to avoid content to stretch width more then the page's width
53
+ * - `forceZIndex`: available on web only, when set to false, sets zIndex on `View` to be `auto`
54
+ * and when true, sets zIndex to be `0` (the default from `react-native-web`)
51
55
  */
52
56
  themeOptions: PropTypes.shape({
53
57
  forceAbsoluteFontSizing: PropTypes.bool,
58
+ forceZIndex: PropTypes.bool,
54
59
  contentMaxWidth: responsiveProps.getTypeOptionallyByViewport(PropTypes.number)
55
60
  })
56
61
  };
@@ -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';
@@ -0,0 +1,43 @@
1
+ import React, { forwardRef } from 'react';
2
+ import NativeView from "react-native-web/dist/exports/View";
3
+ import StyleSheet from "react-native-web/dist/exports/StyleSheet";
4
+ import PropTypes from 'prop-types';
5
+ import { useTheme } from '../../ThemeProvider';
6
+ /**
7
+ * Identical to React Native's View and supporting all the same props, but with:
8
+ * - a zIndex: 'auto' style added to prevent unexpectedly causing children to overlap other elements from other stacking contexts
9
+ */
10
+
11
+ import { jsx as _jsx } from "react/jsx-runtime";
12
+ const BaseView = /*#__PURE__*/forwardRef((_ref, ref) => {
13
+ let {
14
+ children,
15
+ style,
16
+ ...rest
17
+ } = _ref;
18
+ const {
19
+ themeOptions
20
+ } = useTheme();
21
+ const styleProp = Array.isArray(style) ? [...style] : [style];
22
+
23
+ if (!themeOptions.forceZIndex) {
24
+ styleProp.unshift(styles.resetZIndex);
25
+ }
26
+
27
+ return /*#__PURE__*/_jsx(NativeView, { ...rest,
28
+ style: styleProp,
29
+ ref: ref,
30
+ children: children
31
+ });
32
+ });
33
+ BaseView.displayName = 'BaseView';
34
+ const styles = StyleSheet.create({
35
+ resetZIndex: {
36
+ zIndex: 'auto'
37
+ }
38
+ });
39
+ BaseView.propTypes = {
40
+ children: PropTypes.node,
41
+ style: PropTypes.oneOfType([PropTypes.object, PropTypes.array])
42
+ };
43
+ export default BaseView;
@@ -0,0 +1,6 @@
1
+ import BaseView from "react-native-web/dist/exports/View";
2
+ /**
3
+ * Android crashes on non-standard style properties like `zIndex` so adding a `BaseView` for native platforms
4
+ */
5
+
6
+ export default BaseView;
@@ -0,0 +1,2 @@
1
+ import BaseView from './BaseView';
2
+ export default BaseView;
@@ -15,4 +15,5 @@ export * from './useResponsiveProp';
15
15
  export { default as useUniqueId } from './useUniqueId';
16
16
  export { default as withLinkRouter } from './withLinkRouter';
17
17
  export * from './ssr';
18
- export { default as containUniqueFields } from './containUniqueFields';
18
+ export { default as containUniqueFields } from './containUniqueFields';
19
+ export { default as BaseView } from './BaseView';
@@ -77,6 +77,7 @@ export const useInputValue = function () {
77
77
  const {
78
78
  value,
79
79
  initialValue,
80
+ inputRef,
80
81
  onChange,
81
82
  readOnly = false
82
83
  } = props;
@@ -90,19 +91,26 @@ export const useInputValue = function () {
90
91
  }); // Make current value accessible inside useCallback without rememoizing every time the value changes
91
92
 
92
93
  valueRef.current.value = currentValue;
94
+ const isDirty = currentValue !== valueRef.current.initial;
93
95
  const setValue = useCallback((arg, event) => {
94
96
  if (readOnly) return;
95
97
  const newValue = typeof arg === 'function' ? arg(valueRef.current.value) : arg;
96
- if (!isControlled) setOwnValue(newValue); // Call onChange handler if there's something for it to handle (event or a changed value)
98
+
99
+ if (!isControlled) {
100
+ setOwnValue(newValue);
101
+ if (inputRef !== null && inputRef !== void 0 && inputRef.current) inputRef.current.value = newValue !== null && newValue !== void 0 ? newValue : '';
102
+ } // Call onChange handler if there's something for it to handle (event or a changed value)
103
+
97
104
 
98
105
  if (onChange && (event || valueRef.current.value !== newValue)) onChange(newValue, event);
99
- }, [isControlled, onChange, readOnly]);
106
+ }, [inputRef, isControlled, onChange, readOnly]);
100
107
  const resetValue = useCallback(event => setValue(valueRef.current.initial, event), [setValue]);
101
108
  return {
102
109
  currentValue,
103
110
  setValue,
104
111
  resetValue,
105
- isControlled
112
+ isControlled,
113
+ isDirty
106
114
  };
107
115
  };
108
116
  /**