@telus-uds/components-base 1.18.1 → 1.19.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 +22 -2
- package/component-docs.json +111 -16
- package/jest.config-android.js +17 -0
- package/jest.config-ios.js +18 -0
- package/jest.config-web.js +31 -0
- package/lib/Button/ButtonBase.js +6 -2
- package/lib/Carousel/Carousel.js +32 -4
- package/lib/Carousel/CarouselTabs/CarouselTabsPanel.js +1 -10
- package/lib/Pagination/SideButton.js +6 -4
- package/lib/Responsive/Responsive.js +58 -0
- package/lib/Responsive/index.js +13 -0
- package/lib/Search/Search.js +29 -62
- package/lib/Tags/Tags.js +10 -4
- package/lib/TextInput/TextInputBase.js +53 -19
- package/lib/index.js +9 -0
- package/lib-module/Button/ButtonBase.js +6 -2
- package/lib-module/Carousel/Carousel.js +32 -4
- package/lib-module/Carousel/CarouselTabs/CarouselTabsPanel.js +1 -10
- package/lib-module/Pagination/SideButton.js +6 -4
- package/lib-module/Responsive/Responsive.js +45 -0
- package/lib-module/Responsive/index.js +2 -0
- package/lib-module/Search/Search.js +29 -60
- package/lib-module/Tags/Tags.js +10 -4
- package/lib-module/TextInput/TextInputBase.js +52 -19
- package/lib-module/index.js +1 -0
- package/package.json +6 -3
- package/src/Button/ButtonBase.jsx +4 -2
- package/src/Carousel/Carousel.jsx +42 -10
- package/src/Carousel/CarouselTabs/CarouselTabsPanel.jsx +0 -10
- package/src/Pagination/SideButton.jsx +5 -5
- package/src/Responsive/Responsive.jsx +33 -0
- package/src/Responsive/index.js +3 -0
- package/src/Search/Search.jsx +17 -32
- package/src/Tags/Tags.jsx +46 -33
- package/src/TextInput/TextInputBase.jsx +46 -16
- package/src/index.js +1 -0
|
@@ -1,16 +1,13 @@
|
|
|
1
1
|
import React, { forwardRef } from 'react';
|
|
2
2
|
import View from "react-native-web/dist/exports/View";
|
|
3
|
-
import StyleSheet from "react-native-web/dist/exports/StyleSheet";
|
|
4
3
|
import PropTypes from 'prop-types';
|
|
5
4
|
import { useThemeTokens, useThemeTokensCallback } from '../ThemeProvider';
|
|
6
5
|
import { a11yProps, getTokensPropType, selectSystemProps, selectTokens, useInputValue, useSpacingScale, textInputHandlerProps, textInputProps, variantProp, viewProps } from '../utils';
|
|
7
6
|
import TextInputBase from '../TextInput/TextInputBase';
|
|
8
7
|
import ButtonBase from '../Button/ButtonBase';
|
|
9
|
-
import StackView from '../StackView';
|
|
10
8
|
import useCopy from '../utils/useCopy';
|
|
11
9
|
import dictionary from './dictionary';
|
|
12
10
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
13
|
-
import { jsxs as _jsxs } from "react/jsx-runtime";
|
|
14
11
|
const [selectContainerProps, selectedContainerPropTypes] = selectSystemProps([a11yProps, viewProps]);
|
|
15
12
|
const [selectInputProps, selectedInputPropTypes] = selectSystemProps([textInputHandlerProps, textInputProps]);
|
|
16
13
|
|
|
@@ -39,20 +36,11 @@ const selectInputTokens = _ref => {
|
|
|
39
36
|
|
|
40
37
|
const selectButtonTokens = tokens => selectTokens('Button', tokens);
|
|
41
38
|
|
|
42
|
-
const
|
|
43
|
-
let {
|
|
44
|
-
paddingRight
|
|
45
|
-
} = _ref2;
|
|
46
|
-
return {
|
|
47
|
-
paddingRight
|
|
48
|
-
};
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
const selectIconTokens = _ref3 => {
|
|
39
|
+
const selectIconTokens = _ref2 => {
|
|
52
40
|
let {
|
|
53
41
|
iconSize,
|
|
54
42
|
iconColor
|
|
55
|
-
} =
|
|
43
|
+
} = _ref2;
|
|
56
44
|
return {
|
|
57
45
|
color: iconColor,
|
|
58
46
|
size: iconSize
|
|
@@ -73,7 +61,7 @@ const selectIconTokens = _ref3 => {
|
|
|
73
61
|
*/
|
|
74
62
|
|
|
75
63
|
|
|
76
|
-
const Search = /*#__PURE__*/forwardRef((
|
|
64
|
+
const Search = /*#__PURE__*/forwardRef((_ref3, ref) => {
|
|
77
65
|
let {
|
|
78
66
|
initialValue,
|
|
79
67
|
value,
|
|
@@ -88,7 +76,7 @@ const Search = /*#__PURE__*/forwardRef((_ref4, ref) => {
|
|
|
88
76
|
tokens,
|
|
89
77
|
variant,
|
|
90
78
|
...rest
|
|
91
|
-
} =
|
|
79
|
+
} = _ref3;
|
|
92
80
|
const {
|
|
93
81
|
currentValue = '',
|
|
94
82
|
setValue
|
|
@@ -140,10 +128,8 @@ const Search = /*#__PURE__*/forwardRef((_ref4, ref) => {
|
|
|
140
128
|
testID,
|
|
141
129
|
...containerProps
|
|
142
130
|
} = selectContainerProps(rest);
|
|
143
|
-
return /*#__PURE__*/
|
|
144
|
-
|
|
145
|
-
...containerProps,
|
|
146
|
-
children: [/*#__PURE__*/_jsx(TextInputBase, {
|
|
131
|
+
return /*#__PURE__*/_jsx(View, { ...containerProps,
|
|
132
|
+
children: /*#__PURE__*/_jsx(TextInputBase, {
|
|
147
133
|
nativeID: nativeID,
|
|
148
134
|
testID: testID,
|
|
149
135
|
...selectInputProps(rest),
|
|
@@ -163,35 +149,29 @@ const Search = /*#__PURE__*/forwardRef((_ref4, ref) => {
|
|
|
163
149
|
onChange: setValue,
|
|
164
150
|
onSubmitEditing: handleSubmit,
|
|
165
151
|
onFocus: handleFocus,
|
|
166
|
-
accessibilityLabel: a11yLabelText
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
accessibilityLabel: getCopy('submitButtonAccessibilityLabel'),
|
|
185
|
-
tokens: buttonState => selectButtonTokens(getButtonTokens({ ...buttonState,
|
|
152
|
+
accessibilityLabel: a11yLabelText,
|
|
153
|
+
buttons: [ClearButtonIcon && !isEmpty && /*#__PURE__*/_jsx(ButtonBase, {
|
|
154
|
+
accessibilityLabel: getCopy('clearButtonAccessibilityLabel'),
|
|
155
|
+
accessibilityRole: "button",
|
|
156
|
+
inactive: inactive,
|
|
157
|
+
onPress: handleClear,
|
|
158
|
+
tokens: appearances => selectButtonTokens(getButtonTokens(appearances)),
|
|
159
|
+
children: buttonState => /*#__PURE__*/_jsx(ClearButtonIcon, { ...selectIconTokens(getButtonTokens(buttonState))
|
|
160
|
+
})
|
|
161
|
+
}, "clear"), SubmitButtonIcon && /*#__PURE__*/_jsx(ButtonBase, {
|
|
162
|
+
accessibilityLabel: getCopy('submitButtonAccessibilityLabel'),
|
|
163
|
+
accessibilityRole: "button",
|
|
164
|
+
inactive: inactive,
|
|
165
|
+
onPress: handleSubmit,
|
|
166
|
+
tokens: buttonState => selectButtonTokens(getButtonTokens({ ...buttonState,
|
|
167
|
+
priority: 'high'
|
|
168
|
+
})),
|
|
169
|
+
children: buttonState => /*#__PURE__*/_jsx(SubmitButtonIcon, { ...selectIconTokens(getButtonTokens({ ...buttonState,
|
|
186
170
|
priority: 'high'
|
|
187
|
-
}))
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
})
|
|
192
|
-
})]
|
|
193
|
-
})
|
|
194
|
-
})]
|
|
171
|
+
}))
|
|
172
|
+
})
|
|
173
|
+
}, "submit")]
|
|
174
|
+
})
|
|
195
175
|
});
|
|
196
176
|
});
|
|
197
177
|
Search.displayName = 'Search';
|
|
@@ -255,15 +235,4 @@ Search.propTypes = { ...selectedContainerPropTypes,
|
|
|
255
235
|
tokens: getTokensPropType('Search'),
|
|
256
236
|
variant: variantProp.propType
|
|
257
237
|
};
|
|
258
|
-
export default Search;
|
|
259
|
-
const staticStyles = StyleSheet.create({
|
|
260
|
-
container: {// No styles needed here except the View defaults (position: relative etc)
|
|
261
|
-
},
|
|
262
|
-
iconsContainer: {
|
|
263
|
-
position: 'absolute',
|
|
264
|
-
right: 0,
|
|
265
|
-
top: 0,
|
|
266
|
-
bottom: 0,
|
|
267
|
-
justifyContent: 'center'
|
|
268
|
-
}
|
|
269
|
-
});
|
|
238
|
+
export default Search;
|
package/lib-module/Tags/Tags.js
CHANGED
|
@@ -15,7 +15,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
15
15
|
const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, viewProps]);
|
|
16
16
|
const [selectItemProps, selectedItemPropTypes] = selectSystemProps([a11yProps, focusHandlerProps, pressProps, viewProps]);
|
|
17
17
|
|
|
18
|
-
const
|
|
18
|
+
const separateIconTextTokens = (_ref, returnRest) => {
|
|
19
19
|
let {
|
|
20
20
|
icon,
|
|
21
21
|
iconPosition,
|
|
@@ -27,9 +27,10 @@ const selectIconTextTokens = _ref => {
|
|
|
27
27
|
iconAlignSelf,
|
|
28
28
|
iconPadding,
|
|
29
29
|
iconTranslateX,
|
|
30
|
-
iconTranslateY
|
|
30
|
+
iconTranslateY,
|
|
31
|
+
...rest
|
|
31
32
|
} = _ref;
|
|
32
|
-
return {
|
|
33
|
+
return returnRest ? rest : {
|
|
33
34
|
icon,
|
|
34
35
|
iconPosition,
|
|
35
36
|
iconSpace,
|
|
@@ -54,6 +55,10 @@ const selectIconTextTokens = _ref => {
|
|
|
54
55
|
};
|
|
55
56
|
};
|
|
56
57
|
|
|
58
|
+
const selectIconTextTokens = tokens => separateIconTextTokens(tokens, false);
|
|
59
|
+
|
|
60
|
+
const selectNonIconTextTokens = tokens => separateIconTextTokens(tokens, true);
|
|
61
|
+
|
|
57
62
|
const Tags = /*#__PURE__*/forwardRef((_ref2, ref) => {
|
|
58
63
|
let {
|
|
59
64
|
variant,
|
|
@@ -82,7 +87,8 @@ const Tags = /*#__PURE__*/forwardRef((_ref2, ref) => {
|
|
|
82
87
|
} = themeTokens;
|
|
83
88
|
const getItemTokens = useThemeTokensCallback('TagsItem', tokens, variant);
|
|
84
89
|
|
|
85
|
-
const getButtonTokens = buttonState =>
|
|
90
|
+
const getButtonTokens = buttonState => // Remove icon-text-related tokens, since we want to handle them ourselves, not use ButtonBase's handling
|
|
91
|
+
selectTokens('Button', selectNonIconTextTokens(getItemTokens(buttonState)));
|
|
86
92
|
|
|
87
93
|
const {
|
|
88
94
|
currentValues,
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import React, { forwardRef, useEffect, useState } from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
2
3
|
import Platform from "react-native-web/dist/exports/Platform";
|
|
3
4
|
import StyleSheet from "react-native-web/dist/exports/StyleSheet";
|
|
4
5
|
import NativeTextInput from "react-native-web/dist/exports/TextInput";
|
|
5
6
|
import View from "react-native-web/dist/exports/View";
|
|
6
|
-
import PropTypes from 'prop-types';
|
|
7
7
|
import { applyTextStyles, useTheme, useThemeTokens, applyOuterBorder } from '../ThemeProvider';
|
|
8
|
-
import
|
|
8
|
+
import StackView from '../StackView';
|
|
9
|
+
import { a11yProps, getTokensPropType, selectSystemProps, textInputHandlerProps, textInputProps, useInputValue, useSpacingScale, variantProp, viewProps } from '../utils';
|
|
9
10
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
10
11
|
import { jsxs as _jsxs } from "react/jsx-runtime";
|
|
11
12
|
const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, textInputHandlerProps, textInputProps, viewProps]);
|
|
@@ -110,35 +111,47 @@ const selectIconTokens = _ref3 => {
|
|
|
110
111
|
};
|
|
111
112
|
};
|
|
112
113
|
|
|
113
|
-
const selectIconContainerStyles = _ref4 => {
|
|
114
|
+
const selectIconContainerStyles = (_ref4, buttonCount) => {
|
|
114
115
|
let {
|
|
116
|
+
buttonSize,
|
|
117
|
+
buttonsGapSize,
|
|
115
118
|
paddingRight,
|
|
116
119
|
paddingBottom
|
|
117
120
|
} = _ref4;
|
|
118
121
|
return {
|
|
119
|
-
paddingRight,
|
|
122
|
+
paddingRight: paddingRight + buttonCount * (buttonSize + buttonsGapSize),
|
|
120
123
|
paddingBottom
|
|
121
124
|
};
|
|
122
125
|
};
|
|
123
126
|
|
|
124
|
-
const
|
|
127
|
+
const selectButtonsContainerStyle = _ref5 => {
|
|
125
128
|
let {
|
|
126
|
-
|
|
129
|
+
buttonsPaddingRight
|
|
130
|
+
} = _ref5;
|
|
131
|
+
return {
|
|
132
|
+
paddingRight: buttonsPaddingRight
|
|
133
|
+
};
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
const TextInputBase = /*#__PURE__*/forwardRef((_ref6, ref) => {
|
|
137
|
+
let {
|
|
138
|
+
buttons = [],
|
|
127
139
|
height,
|
|
128
|
-
initialValue,
|
|
129
140
|
inactive,
|
|
130
|
-
|
|
141
|
+
initialValue,
|
|
142
|
+
onBlur,
|
|
131
143
|
onChange,
|
|
132
144
|
onChangeText,
|
|
133
145
|
onFocus,
|
|
134
|
-
onBlur,
|
|
135
|
-
onMouseOver,
|
|
136
146
|
onMouseOut,
|
|
147
|
+
onMouseOver,
|
|
137
148
|
pattern,
|
|
149
|
+
readOnly,
|
|
138
150
|
tokens,
|
|
151
|
+
value,
|
|
139
152
|
variant = {},
|
|
140
153
|
...rest
|
|
141
|
-
} =
|
|
154
|
+
} = _ref6;
|
|
142
155
|
const [isFocused, setIsFocused] = useState(false);
|
|
143
156
|
|
|
144
157
|
const handleFocus = event => {
|
|
@@ -197,7 +210,8 @@ const TextInputBase = /*#__PURE__*/forwardRef((_ref5, ref) => {
|
|
|
197
210
|
};
|
|
198
211
|
const themeTokens = useThemeTokens('TextInput', tokens, variant, states);
|
|
199
212
|
const {
|
|
200
|
-
icon: IconComponent
|
|
213
|
+
icon: IconComponent,
|
|
214
|
+
buttonsGap
|
|
201
215
|
} = themeTokens;
|
|
202
216
|
const inputProps = { ...selectProps(rest),
|
|
203
217
|
editable: !inactive,
|
|
@@ -210,7 +224,9 @@ const TextInputBase = /*#__PURE__*/forwardRef((_ref5, ref) => {
|
|
|
210
224
|
// currentValue is being updated even if the input is not controlled, passing it down to the
|
|
211
225
|
// Input could lead to changing its state from uncontrolled to controlled
|
|
212
226
|
value: isControlled ? currentValue : undefined
|
|
213
|
-
};
|
|
227
|
+
}; // Get the actual gap value for the current viewport
|
|
228
|
+
|
|
229
|
+
const buttonsGapSize = useSpacingScale(buttonsGap);
|
|
214
230
|
const {
|
|
215
231
|
themeOptions
|
|
216
232
|
} = useTheme();
|
|
@@ -226,30 +242,47 @@ const TextInputBase = /*#__PURE__*/forwardRef((_ref5, ref) => {
|
|
|
226
242
|
}), IconComponent && /*#__PURE__*/_jsx(View, {
|
|
227
243
|
pointerEvents: "none" // avoid hijacking input press events
|
|
228
244
|
,
|
|
229
|
-
style: [staticStyles.iconContainer, selectIconContainerStyles(themeTokens
|
|
245
|
+
style: [staticStyles.iconContainer, selectIconContainerStyles({ ...themeTokens,
|
|
246
|
+
buttonsGapSize
|
|
247
|
+
}, buttons === null || buttons === void 0 ? void 0 : buttons.length)],
|
|
230
248
|
children: /*#__PURE__*/_jsx(IconComponent, { ...selectIconTokens(themeTokens)
|
|
231
249
|
})
|
|
250
|
+
}), (buttons === null || buttons === void 0 ? void 0 : buttons.length) > 0 && /*#__PURE__*/_jsx(View, {
|
|
251
|
+
style: [staticStyles.buttonsContainer, selectButtonsContainerStyle(themeTokens)],
|
|
252
|
+
children: /*#__PURE__*/_jsx(StackView, {
|
|
253
|
+
direction: "row",
|
|
254
|
+
space: buttonsGap,
|
|
255
|
+
children: buttons
|
|
256
|
+
})
|
|
232
257
|
})]
|
|
233
258
|
});
|
|
234
259
|
});
|
|
235
260
|
TextInputBase.displayName = 'TextInputBase';
|
|
236
261
|
TextInputBase.propTypes = { ...selectedSystemPropTypes,
|
|
237
|
-
|
|
262
|
+
buttons: PropTypes.arrayOf(PropTypes.node),
|
|
238
263
|
height: PropTypes.number,
|
|
239
|
-
initialValue: PropTypes.string,
|
|
240
264
|
inactive: PropTypes.bool,
|
|
241
|
-
|
|
265
|
+
initialValue: PropTypes.string,
|
|
266
|
+
onBlur: PropTypes.func,
|
|
242
267
|
onChange: PropTypes.func,
|
|
243
268
|
onChangeText: PropTypes.func,
|
|
244
269
|
onFocus: PropTypes.func,
|
|
245
|
-
onBlur: PropTypes.func,
|
|
246
|
-
onMouseOver: PropTypes.func,
|
|
247
270
|
onMouseOut: PropTypes.func,
|
|
271
|
+
onMouseOver: PropTypes.func,
|
|
272
|
+
readOnly: PropTypes.bool,
|
|
248
273
|
tokens: getTokensPropType('TextInput', 'TextArea'),
|
|
274
|
+
value: PropTypes.string,
|
|
249
275
|
variant: variantProp.propType
|
|
250
276
|
};
|
|
251
277
|
export default TextInputBase;
|
|
252
278
|
const staticStyles = StyleSheet.create({
|
|
279
|
+
buttonsContainer: {
|
|
280
|
+
position: 'absolute',
|
|
281
|
+
right: 0,
|
|
282
|
+
top: 0,
|
|
283
|
+
bottom: 0,
|
|
284
|
+
justifyContent: 'center'
|
|
285
|
+
},
|
|
253
286
|
iconContainer: {
|
|
254
287
|
position: 'absolute',
|
|
255
288
|
right: 0,
|
package/lib-module/index.js
CHANGED
|
@@ -29,6 +29,7 @@ export { default as Radio } from './Radio';
|
|
|
29
29
|
export * from './Radio';
|
|
30
30
|
export { default as RadioCard } from './RadioCard';
|
|
31
31
|
export * from './RadioCard';
|
|
32
|
+
export { default as Responsive } from './Responsive';
|
|
32
33
|
export { default as Search } from './Search';
|
|
33
34
|
export { default as Select } from './Select';
|
|
34
35
|
export { default as SideNav } from './SideNav';
|
package/package.json
CHANGED
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
},
|
|
9
9
|
"dependencies": {
|
|
10
10
|
"@gorhom/portal": "^1.0.14",
|
|
11
|
-
"@telus-uds/system-constants": "^1.0
|
|
12
|
-
"@telus-uds/system-theme-tokens": "^2.
|
|
11
|
+
"@telus-uds/system-constants": "^1.1.0",
|
|
12
|
+
"@telus-uds/system-theme-tokens": "^2.7.0",
|
|
13
13
|
"airbnb-prop-types": "^2.16.0",
|
|
14
14
|
"lodash.debounce": "^4.0.8",
|
|
15
15
|
"lodash.merge": "^4.6.2",
|
|
@@ -54,6 +54,9 @@
|
|
|
54
54
|
},
|
|
55
55
|
"scripts": {
|
|
56
56
|
"test": "jest",
|
|
57
|
+
"test:web": "jest --config jest.config-web.js",
|
|
58
|
+
"test:ios": "jest --config jest.config-ios.js",
|
|
59
|
+
"test:android": "jest --config jest.config-android.js",
|
|
57
60
|
"lint": "npm run --prefix ../.. lint:path -- --color packages/components-base",
|
|
58
61
|
"lint:fix": "npm run --prefix ../.. lint:path -- --fix packages/components-base",
|
|
59
62
|
"format": "prettier --write .",
|
|
@@ -67,5 +70,5 @@
|
|
|
67
70
|
"standard-engine": {
|
|
68
71
|
"skip": true
|
|
69
72
|
},
|
|
70
|
-
"version": "1.
|
|
73
|
+
"version": "1.19.0"
|
|
71
74
|
}
|
|
@@ -123,7 +123,7 @@ const selectBorderStyles = ({ borderColor, borderWidth, borderRadius }) => ({
|
|
|
123
123
|
})
|
|
124
124
|
|
|
125
125
|
const selectTextStyles = (
|
|
126
|
-
{ fontSize, color, lineHeight, fontName, fontWeight, textAlign },
|
|
126
|
+
{ fontSize, color, lineHeight, fontName, fontWeight, textAlign, textLine, textLineStyle },
|
|
127
127
|
themeOptions
|
|
128
128
|
) =>
|
|
129
129
|
applyTextStyles({
|
|
@@ -133,7 +133,9 @@ const selectTextStyles = (
|
|
|
133
133
|
fontName,
|
|
134
134
|
fontWeight,
|
|
135
135
|
themeOptions,
|
|
136
|
-
textAlign
|
|
136
|
+
textAlign,
|
|
137
|
+
textDecorationLine: textLine,
|
|
138
|
+
textDecorationStyle: textLineStyle
|
|
137
139
|
})
|
|
138
140
|
|
|
139
141
|
const selectWebOnlyStyles = (inactive, themeTokens, { accessibilityRole }) => {
|
|
@@ -164,7 +164,7 @@ const Carousel = React.forwardRef(
|
|
|
164
164
|
),
|
|
165
165
|
tag = 'ul',
|
|
166
166
|
accessibilityRole,
|
|
167
|
-
accessibilityLabel
|
|
167
|
+
accessibilityLabel,
|
|
168
168
|
accessibilityLiveRegion = 'polite',
|
|
169
169
|
copy,
|
|
170
170
|
...rest
|
|
@@ -422,6 +422,32 @@ const Carousel = React.forwardRef(
|
|
|
422
422
|
const activePanelNavigation =
|
|
423
423
|
tabs && showPanelTabs ? <CarouselTabsPanel items={tabs} /> : panelNavigation
|
|
424
424
|
|
|
425
|
+
const isFirstFocusContainer = Boolean(refocus && !skipLinkHref)
|
|
426
|
+
const containerRef = (element) => {
|
|
427
|
+
// Apply both firstFocusRef to the container
|
|
428
|
+
firstFocusRef.current = element
|
|
429
|
+
// Also apply forwarded ref if there is one (which could be a function ref)
|
|
430
|
+
if (ref) {
|
|
431
|
+
if (typeof ref === 'object') {
|
|
432
|
+
// eslint-disable-next-line no-param-reassign
|
|
433
|
+
ref.current = element
|
|
434
|
+
} else if (typeof ref === 'function') {
|
|
435
|
+
ref(element)
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
// If container isn't used for focus, give it a label of title if none is passed in,
|
|
440
|
+
// otherwise read the current position on focus
|
|
441
|
+
const containerAccessibilityLabel =
|
|
442
|
+
systemProps.accessibilityLabel ?? isFirstFocusContainer
|
|
443
|
+
? `${title ? `${title} ` : ''}${getCopyWithPlaceholders('stepTrackerLabel')}`
|
|
444
|
+
: title
|
|
445
|
+
const containerProps = {
|
|
446
|
+
accessibilityLabel: containerAccessibilityLabel,
|
|
447
|
+
// If used for focus, attach the ref and draw a focus box around the whole carousel
|
|
448
|
+
...(isFirstFocusContainer && { ref: containerRef, focusable: true })
|
|
449
|
+
}
|
|
450
|
+
|
|
425
451
|
return (
|
|
426
452
|
<CarouselProvider
|
|
427
453
|
activeIndex={activeIndex}
|
|
@@ -434,7 +460,13 @@ const Carousel = React.forwardRef(
|
|
|
434
460
|
refocus={refocus}
|
|
435
461
|
width={containerLayout.width}
|
|
436
462
|
>
|
|
437
|
-
<View
|
|
463
|
+
<View
|
|
464
|
+
style={staticStyles.root}
|
|
465
|
+
onLayout={onContainerLayout}
|
|
466
|
+
ref={ref}
|
|
467
|
+
{...systemProps}
|
|
468
|
+
{...containerProps}
|
|
469
|
+
>
|
|
438
470
|
{showPreviousNextNavigation && (
|
|
439
471
|
<View
|
|
440
472
|
style={selectPreviousNextNavigationButtonStyles(
|
|
@@ -464,14 +496,14 @@ const Carousel = React.forwardRef(
|
|
|
464
496
|
{getCopyWithPlaceholders('skipLink')}
|
|
465
497
|
</SkipLink>
|
|
466
498
|
)}
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
499
|
+
{!isFirstFocusContainer && (
|
|
500
|
+
<A11yText
|
|
501
|
+
// Read the current slide position to screen readers on slide.
|
|
502
|
+
// If it's set to refocus and doesn't have a SkipLink to focus to, focus this.
|
|
503
|
+
accessibilityLiveRegion={!skipLinkHref && refocus ? undefined : 'polite'}
|
|
504
|
+
text={getCopyWithPlaceholders('stepTrackerLabel')}
|
|
505
|
+
/>
|
|
506
|
+
)}
|
|
475
507
|
<View style={selectContainerStyles(containerLayout.width)}>
|
|
476
508
|
<Animated.View
|
|
477
509
|
style={StyleSheet.flatten([
|
|
@@ -21,16 +21,6 @@ const CarouselTabsPanel = forwardRef(({ items }, ref) => {
|
|
|
21
21
|
|
|
22
22
|
return (
|
|
23
23
|
<>
|
|
24
|
-
<View
|
|
25
|
-
focusable
|
|
26
|
-
accessible
|
|
27
|
-
onFocus={(event) => {
|
|
28
|
-
// When user forward-tabs into this section, focus the next tab; if they backwards-tab
|
|
29
|
-
// (shift-tab) back into the carousel content, don't interfere.
|
|
30
|
-
const previousWebFocus = event.relatedTarget
|
|
31
|
-
if (previousWebFocus !== firstTabRef.current) nextFocusRef.current.focus()
|
|
32
|
-
}}
|
|
33
|
-
/>
|
|
34
24
|
<StackView direction="row" space={3} divider={{ variant: dividerVariant }} ref={ref}>
|
|
35
25
|
{items.map(({ title, onPress, ...panelItemProps }, index) => {
|
|
36
26
|
const selected = index === activeIndex
|
|
@@ -13,8 +13,9 @@ import dictionary from './dictionary'
|
|
|
13
13
|
import useCopy from '../utils/useCopy'
|
|
14
14
|
|
|
15
15
|
// We need to drop the icon here since it gets rendered via children and not
|
|
16
|
-
// `ButtonBase` in order to tap into the state of the button
|
|
17
|
-
|
|
16
|
+
// `ButtonBase` in order to tap into the state of the button; `displayLabel` flag
|
|
17
|
+
// is also not needed
|
|
18
|
+
const selectButtonTokens = ({ icon: _, displayLabel: __, ...rest }) => selectTokens('Button', rest)
|
|
18
19
|
const selectIconTokens = ({ color, iconSize, iconDisplace }, direction) => {
|
|
19
20
|
return {
|
|
20
21
|
color,
|
|
@@ -36,13 +37,12 @@ const SideButton = forwardRef(
|
|
|
36
37
|
|
|
37
38
|
const getCopy = useCopy({ dictionary, copy })
|
|
38
39
|
|
|
39
|
-
const { icon } = getTokens(tokens, buttonVariant)
|
|
40
|
+
const { icon, displayLabel } = getTokens(tokens, buttonVariant)
|
|
40
41
|
|
|
41
42
|
const getButtonTokens = (buttonState) => selectButtonTokens(getTokens(buttonState))
|
|
42
43
|
const getIconTokens = (buttonState) => selectIconTokens(getTokens(buttonState), direction)
|
|
43
44
|
|
|
44
45
|
const label = direction === 'previous' ? getCopy('previousText') : getCopy('nextText')
|
|
45
|
-
const showLabel = viewport !== 'sm' && viewport !== 'xs'
|
|
46
46
|
|
|
47
47
|
const accessibilityLabel =
|
|
48
48
|
direction === 'previous' ? getCopy('previousLabel') : getCopy('nextLabel')
|
|
@@ -69,7 +69,7 @@ const SideButton = forwardRef(
|
|
|
69
69
|
iconPosition={directionToSide[direction]}
|
|
70
70
|
iconProps={iconProps}
|
|
71
71
|
>
|
|
72
|
-
{
|
|
72
|
+
{displayLabel && <Text style={textStyles}>{label}</Text>}
|
|
73
73
|
</IconText>
|
|
74
74
|
)
|
|
75
75
|
}}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import PropTypes from 'prop-types'
|
|
3
|
+
import { viewports } from '@telus-uds/system-constants'
|
|
4
|
+
import { useResponsiveProp } from '../utils'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Responsive conditionally renders children based on whether the viewport matches the provided
|
|
8
|
+
* min and max viewports.
|
|
9
|
+
*
|
|
10
|
+
* In SSR, like other viewport utilities, it treats the viewport as `xs` both in SSR itself and
|
|
11
|
+
* during first hydration on the client side; then if the viewport is not `xs`, it re-renders
|
|
12
|
+
* after hydration. This may cause a layout shift on devices other than the narrowest.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
const Responsive = ({ min = 'xs', max, children }) => {
|
|
16
|
+
// Start returning children at the 'min' viewport or greater
|
|
17
|
+
const byViewports = { [min]: children }
|
|
18
|
+
if (max && max !== 'xl') {
|
|
19
|
+
// Stop returning children at the viewport one above 'max' or greater
|
|
20
|
+
const maxIndex = viewports.keys.indexOf(max)
|
|
21
|
+
const maxPlusOne = maxIndex >= 0 ? viewports.keys[maxIndex + 1] : null
|
|
22
|
+
if (maxPlusOne) byViewports[maxPlusOne] = null
|
|
23
|
+
}
|
|
24
|
+
return <>{useResponsiveProp(byViewports, null)}</>
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
Responsive.propTypes = {
|
|
28
|
+
min: PropTypes.oneOf(['xs', 'sm', 'md', 'lg', 'xl']),
|
|
29
|
+
max: PropTypes.oneOf(['sm', 'md', 'lg', 'xl']),
|
|
30
|
+
children: PropTypes.node.isRequired
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export default Responsive
|
package/src/Search/Search.jsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { forwardRef } from 'react'
|
|
2
|
-
import { View
|
|
2
|
+
import { View } from 'react-native'
|
|
3
3
|
|
|
4
4
|
import PropTypes from 'prop-types'
|
|
5
5
|
import { useThemeTokens, useThemeTokensCallback } from '../ThemeProvider'
|
|
@@ -17,7 +17,6 @@ import {
|
|
|
17
17
|
} from '../utils'
|
|
18
18
|
import TextInputBase from '../TextInput/TextInputBase'
|
|
19
19
|
import ButtonBase from '../Button/ButtonBase'
|
|
20
|
-
import StackView from '../StackView'
|
|
21
20
|
import useCopy from '../utils/useCopy'
|
|
22
21
|
import dictionary from './dictionary'
|
|
23
22
|
|
|
@@ -42,7 +41,6 @@ const selectInputTokens = ({ searchTokens, buttonTokens, buttonsGapSize }) => {
|
|
|
42
41
|
}
|
|
43
42
|
const selectButtonTokens = (tokens) => selectTokens('Button', tokens)
|
|
44
43
|
|
|
45
|
-
const selectIconsContainerStyle = ({ paddingRight }) => ({ paddingRight })
|
|
46
44
|
const selectIconTokens = ({ iconSize, iconColor }) => ({ color: iconColor, size: iconSize })
|
|
47
45
|
|
|
48
46
|
/**
|
|
@@ -126,7 +124,7 @@ const Search = forwardRef(
|
|
|
126
124
|
const { nativeID, testID, ...containerProps } = selectContainerProps(rest)
|
|
127
125
|
|
|
128
126
|
return (
|
|
129
|
-
<View
|
|
127
|
+
<View {...containerProps}>
|
|
130
128
|
<TextInputBase
|
|
131
129
|
nativeID={nativeID}
|
|
132
130
|
testID={testID}
|
|
@@ -150,28 +148,28 @@ const Search = forwardRef(
|
|
|
150
148
|
onSubmitEditing={handleSubmit}
|
|
151
149
|
onFocus={handleFocus}
|
|
152
150
|
accessibilityLabel={a11yLabelText}
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
<StackView direction="row" space={buttonsGap}>
|
|
156
|
-
{ClearButtonIcon && !isEmpty && (
|
|
151
|
+
buttons={[
|
|
152
|
+
ClearButtonIcon && !isEmpty && (
|
|
157
153
|
<ButtonBase
|
|
158
|
-
onPress={handleClear}
|
|
159
|
-
inactive={inactive}
|
|
160
|
-
accessibilityRole="button"
|
|
161
154
|
accessibilityLabel={getCopy('clearButtonAccessibilityLabel')}
|
|
155
|
+
accessibilityRole="button"
|
|
156
|
+
inactive={inactive}
|
|
157
|
+
key="clear"
|
|
158
|
+
onPress={handleClear}
|
|
162
159
|
tokens={(appearances) => selectButtonTokens(getButtonTokens(appearances))}
|
|
163
160
|
>
|
|
164
161
|
{(buttonState) => (
|
|
165
162
|
<ClearButtonIcon {...selectIconTokens(getButtonTokens(buttonState))} />
|
|
166
163
|
)}
|
|
167
164
|
</ButtonBase>
|
|
168
|
-
)
|
|
169
|
-
|
|
165
|
+
),
|
|
166
|
+
SubmitButtonIcon && (
|
|
170
167
|
<ButtonBase
|
|
171
|
-
onPress={handleSubmit}
|
|
172
|
-
inactive={inactive}
|
|
173
|
-
accessibilityRole="button"
|
|
174
168
|
accessibilityLabel={getCopy('submitButtonAccessibilityLabel')}
|
|
169
|
+
accessibilityRole="button"
|
|
170
|
+
inactive={inactive}
|
|
171
|
+
key="submit"
|
|
172
|
+
onPress={handleSubmit}
|
|
175
173
|
tokens={(buttonState) =>
|
|
176
174
|
selectButtonTokens(getButtonTokens({ ...buttonState, priority: 'high' }))
|
|
177
175
|
}
|
|
@@ -182,9 +180,9 @@ const Search = forwardRef(
|
|
|
182
180
|
/>
|
|
183
181
|
)}
|
|
184
182
|
</ButtonBase>
|
|
185
|
-
)
|
|
186
|
-
|
|
187
|
-
|
|
183
|
+
)
|
|
184
|
+
]}
|
|
185
|
+
/>
|
|
188
186
|
</View>
|
|
189
187
|
)
|
|
190
188
|
}
|
|
@@ -248,16 +246,3 @@ Search.propTypes = {
|
|
|
248
246
|
}
|
|
249
247
|
|
|
250
248
|
export default Search
|
|
251
|
-
|
|
252
|
-
const staticStyles = StyleSheet.create({
|
|
253
|
-
container: {
|
|
254
|
-
// No styles needed here except the View defaults (position: relative etc)
|
|
255
|
-
},
|
|
256
|
-
iconsContainer: {
|
|
257
|
-
position: 'absolute',
|
|
258
|
-
right: 0,
|
|
259
|
-
top: 0,
|
|
260
|
-
bottom: 0,
|
|
261
|
-
justifyContent: 'center'
|
|
262
|
-
}
|
|
263
|
-
})
|