@telus-uds/components-base 1.24.0 → 1.24.2
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 +21 -2
- package/component-docs.json +0 -11
- package/lib/Box/Box.js +3 -1
- package/lib/Divider/Divider.js +3 -0
- package/lib/Feedback/Feedback.js +2 -5
- package/lib/Fieldset/Fieldset.js +3 -1
- package/lib/FlexGrid/FlexGrid.js +3 -1
- package/lib/Link/InlinePressable.js +8 -1
- package/lib/Link/LinkBase.js +6 -8
- package/lib/List/ListItem.js +10 -2
- package/lib/Radio/RadioGroup.js +1 -1
- package/lib/StackView/StackView.js +3 -1
- package/lib/StackView/StackWrapBox.js +3 -1
- package/lib/StackView/StackWrapGap.js +3 -1
- package/lib/ThemeProvider/utils/styles.js +1 -3
- package/lib/Tooltip/Tooltip.js +85 -158
- package/lib/Tooltip/Tooltip.native.js +357 -0
- package/lib/Tooltip/index.js +6 -1
- package/lib/Tooltip/shared.js +39 -0
- package/lib/Typography/Typography.js +3 -1
- package/lib/utils/floating-ui/index.js +43 -0
- package/lib/utils/floating-ui/index.native.js +43 -0
- package/lib-module/Box/Box.js +3 -1
- package/lib-module/Divider/Divider.js +3 -0
- package/lib-module/Feedback/Feedback.js +2 -5
- package/lib-module/Fieldset/Fieldset.js +3 -1
- package/lib-module/FlexGrid/FlexGrid.js +3 -1
- package/lib-module/Link/InlinePressable.js +8 -1
- package/lib-module/Link/LinkBase.js +6 -8
- package/lib-module/List/ListItem.js +10 -2
- package/lib-module/Radio/RadioGroup.js +1 -1
- package/lib-module/StackView/StackView.js +3 -1
- package/lib-module/StackView/StackWrapBox.js +3 -1
- package/lib-module/StackView/StackWrapGap.js +3 -1
- package/lib-module/ThemeProvider/utils/styles.js +1 -3
- package/lib-module/Tooltip/Tooltip.js +85 -155
- package/lib-module/Tooltip/Tooltip.native.js +326 -0
- package/lib-module/Tooltip/index.js +4 -1
- package/lib-module/Tooltip/shared.js +27 -0
- package/lib-module/Typography/Typography.js +3 -1
- package/lib-module/utils/floating-ui/index.js +1 -0
- package/lib-module/utils/floating-ui/index.native.js +1 -0
- package/package.json +4 -2
- package/src/Box/Box.jsx +1 -0
- package/src/Divider/Divider.jsx +3 -0
- package/src/Feedback/Feedback.jsx +3 -8
- package/src/Fieldset/Fieldset.jsx +1 -1
- package/src/FlexGrid/FlexGrid.jsx +1 -0
- package/src/Link/InlinePressable.jsx +9 -3
- package/src/Link/LinkBase.jsx +17 -10
- package/src/List/ListItem.jsx +3 -1
- package/src/Radio/RadioGroup.jsx +1 -1
- package/src/StackView/StackView.jsx +1 -0
- package/src/StackView/StackWrapBox.jsx +1 -0
- package/src/StackView/StackWrapGap.jsx +1 -0
- package/src/ThemeProvider/utils/styles.js +1 -3
- package/src/Tooltip/Tooltip.jsx +79 -156
- package/src/Tooltip/Tooltip.native.jsx +283 -0
- package/src/Tooltip/index.js +5 -1
- package/src/Tooltip/shared.js +27 -0
- package/src/Typography/Typography.jsx +1 -0
- package/src/utils/floating-ui/index.js +1 -0
- package/src/utils/floating-ui/index.native.js +1 -0
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
import React, { forwardRef, useEffect, useRef, useState } from 'react';
|
|
2
|
+
import Dimensions from "react-native-web/dist/exports/Dimensions";
|
|
3
|
+
import Platform from "react-native-web/dist/exports/Platform";
|
|
4
|
+
import Pressable from "react-native-web/dist/exports/Pressable";
|
|
5
|
+
import StyleSheet from "react-native-web/dist/exports/StyleSheet";
|
|
6
|
+
import Text from "react-native-web/dist/exports/Text";
|
|
7
|
+
import View from "react-native-web/dist/exports/View";
|
|
8
|
+
import propTypes from './shared';
|
|
9
|
+
import { applyShadowToken, applyTextStyles, useThemeTokens } from '../ThemeProvider';
|
|
10
|
+
import { a11yProps, selectSystemProps, selectTokens, viewProps } from '../utils';
|
|
11
|
+
import Backdrop from './Backdrop';
|
|
12
|
+
import getTooltipPosition from './getTooltipPosition';
|
|
13
|
+
import TooltipButton from '../TooltipButton';
|
|
14
|
+
import useCopy from '../utils/useCopy';
|
|
15
|
+
import dictionary from './dictionary';
|
|
16
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
17
|
+
import { jsxs as _jsxs } from "react/jsx-runtime";
|
|
18
|
+
const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, viewProps]);
|
|
19
|
+
|
|
20
|
+
const selectTooltipStyles = _ref => {
|
|
21
|
+
let {
|
|
22
|
+
backgroundColor,
|
|
23
|
+
paddingTop,
|
|
24
|
+
paddingBottom,
|
|
25
|
+
paddingLeft,
|
|
26
|
+
paddingRight,
|
|
27
|
+
borderRadius
|
|
28
|
+
} = _ref;
|
|
29
|
+
return {
|
|
30
|
+
backgroundColor,
|
|
31
|
+
paddingTop,
|
|
32
|
+
paddingBottom,
|
|
33
|
+
paddingLeft,
|
|
34
|
+
paddingRight,
|
|
35
|
+
borderRadius
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const selectTooltipShadowStyles = _ref2 => {
|
|
40
|
+
let {
|
|
41
|
+
shadow,
|
|
42
|
+
borderRadius
|
|
43
|
+
} = _ref2;
|
|
44
|
+
return {
|
|
45
|
+
borderRadius,
|
|
46
|
+
...applyShadowToken(shadow)
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const selectTooltipPositionStyles = _ref3 => {
|
|
51
|
+
let {
|
|
52
|
+
top,
|
|
53
|
+
left,
|
|
54
|
+
width
|
|
55
|
+
} = _ref3;
|
|
56
|
+
return {
|
|
57
|
+
top,
|
|
58
|
+
left,
|
|
59
|
+
width
|
|
60
|
+
};
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const selectArrowStyles = (_ref4, _ref5) => {
|
|
64
|
+
let {
|
|
65
|
+
backgroundColor,
|
|
66
|
+
arrowWidth,
|
|
67
|
+
arrowBorderRadius,
|
|
68
|
+
shadow
|
|
69
|
+
} = _ref4;
|
|
70
|
+
let {
|
|
71
|
+
position,
|
|
72
|
+
width: tooltipWidth,
|
|
73
|
+
height: tooltipHeight
|
|
74
|
+
} = _ref5;
|
|
75
|
+
// the arrow width is actually a diagonal of the rectangle that we'll use as a tip
|
|
76
|
+
const rectangleSide = Math.sqrt(arrowWidth * arrowWidth / 2); // position the arrow at the side and center of the tooltip - this happens before rotation
|
|
77
|
+
// so we use the rectangle size as basis
|
|
78
|
+
|
|
79
|
+
const verticalOffset = -1 * rectangleSide / 2;
|
|
80
|
+
const horizontalOffset = rectangleSide / 2; // percentage-based absolute positioning doesn't act well on native, so we have to
|
|
81
|
+
// calculate the pixel values
|
|
82
|
+
|
|
83
|
+
const directionalStyles = {
|
|
84
|
+
above: {
|
|
85
|
+
bottom: verticalOffset,
|
|
86
|
+
left: tooltipWidth / 2 - horizontalOffset,
|
|
87
|
+
transform: [{
|
|
88
|
+
rotateZ: '45deg'
|
|
89
|
+
}]
|
|
90
|
+
},
|
|
91
|
+
below: {
|
|
92
|
+
top: verticalOffset,
|
|
93
|
+
left: tooltipWidth / 2 - horizontalOffset,
|
|
94
|
+
transform: [{
|
|
95
|
+
rotateZ: '-135deg'
|
|
96
|
+
}]
|
|
97
|
+
},
|
|
98
|
+
left: {
|
|
99
|
+
right: verticalOffset,
|
|
100
|
+
top: tooltipHeight / 2 - horizontalOffset,
|
|
101
|
+
transform: [{
|
|
102
|
+
rotateZ: '-45deg'
|
|
103
|
+
}]
|
|
104
|
+
},
|
|
105
|
+
right: {
|
|
106
|
+
left: verticalOffset,
|
|
107
|
+
top: tooltipHeight / 2 - horizontalOffset,
|
|
108
|
+
transform: [{
|
|
109
|
+
rotateZ: '135deg'
|
|
110
|
+
}]
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
return {
|
|
114
|
+
backgroundColor,
|
|
115
|
+
width: rectangleSide,
|
|
116
|
+
height: rectangleSide,
|
|
117
|
+
borderBottomRightRadius: arrowBorderRadius,
|
|
118
|
+
// this corner will be the arrow tip after rotation
|
|
119
|
+
...applyShadowToken(shadow),
|
|
120
|
+
...directionalStyles[position]
|
|
121
|
+
};
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
const selectTextStyles = tokens => applyTextStyles(selectTokens('Typography', tokens));
|
|
125
|
+
|
|
126
|
+
const defaultControl = (pressableState, variant) => /*#__PURE__*/_jsx(TooltipButton, {
|
|
127
|
+
pressableState: pressableState,
|
|
128
|
+
variant: variant
|
|
129
|
+
});
|
|
130
|
+
/**
|
|
131
|
+
* Tooltip provides a descriptive and detailed explanation or instructions. It can be used next to an input label
|
|
132
|
+
* to help a user fill it in, or as a standalone component.
|
|
133
|
+
*
|
|
134
|
+
* By default the TooltipButton component will be used as a control for triggering the tooltip, but you may attach
|
|
135
|
+
* a tooltip to any other component. A render function can be used to adjust the control's styling on state changes (hover, focus, etc.).
|
|
136
|
+
*
|
|
137
|
+
* ### Positioning
|
|
138
|
+
* By default a Tooltip will be automatically positioned in a way that ensures it fits within the viewport.
|
|
139
|
+
* You may suggest a position with a prop - it will be used, unless the tooltip would end up outside the viewport.
|
|
140
|
+
*
|
|
141
|
+
* ### Usage criteria
|
|
142
|
+
* - You may use one when the information is useful only to a small percentage of users (ie. tech savvy people wouldn't need this info).
|
|
143
|
+
* - Tooltips may also be useful when vertical space is an issue.
|
|
144
|
+
*/
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
const Tooltip = /*#__PURE__*/forwardRef((_ref6, ref) => {
|
|
148
|
+
let {
|
|
149
|
+
children,
|
|
150
|
+
content,
|
|
151
|
+
position = 'auto',
|
|
152
|
+
copy = 'en',
|
|
153
|
+
tokens,
|
|
154
|
+
variant,
|
|
155
|
+
...rest
|
|
156
|
+
} = _ref6;
|
|
157
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
158
|
+
const controlRef = useRef();
|
|
159
|
+
const [controlLayout, setControlLayout] = useState(null);
|
|
160
|
+
const [tooltipDimensions, setTooltipDimensions] = useState(null);
|
|
161
|
+
const [windowDimensions, setWindowDimensions] = useState(Dimensions.get('window'));
|
|
162
|
+
const [tooltipPosition, setTooltipPosition] = useState(null);
|
|
163
|
+
const getCopy = useCopy({
|
|
164
|
+
dictionary,
|
|
165
|
+
copy
|
|
166
|
+
});
|
|
167
|
+
const themeTokens = useThemeTokens('Tooltip', tokens, variant);
|
|
168
|
+
const {
|
|
169
|
+
arrowWidth,
|
|
170
|
+
arrowOffset
|
|
171
|
+
} = themeTokens;
|
|
172
|
+
useEffect(() => {
|
|
173
|
+
const subscription = Dimensions.addEventListener('change', _ref7 => {
|
|
174
|
+
let {
|
|
175
|
+
window
|
|
176
|
+
} = _ref7;
|
|
177
|
+
setWindowDimensions(window);
|
|
178
|
+
});
|
|
179
|
+
return () => subscription === null || subscription === void 0 ? void 0 : subscription.remove();
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
const toggleIsOpen = () => setIsOpen(!isOpen);
|
|
183
|
+
|
|
184
|
+
const close = () => setIsOpen(false);
|
|
185
|
+
|
|
186
|
+
const getPressableState = _ref8 => {
|
|
187
|
+
let {
|
|
188
|
+
pressed,
|
|
189
|
+
hovered,
|
|
190
|
+
focused
|
|
191
|
+
} = _ref8;
|
|
192
|
+
return {
|
|
193
|
+
pressed,
|
|
194
|
+
hover: hovered,
|
|
195
|
+
focus: focused
|
|
196
|
+
};
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
const onTooltipLayout = _ref9 => {
|
|
200
|
+
let {
|
|
201
|
+
nativeEvent: {
|
|
202
|
+
layout: {
|
|
203
|
+
width,
|
|
204
|
+
height
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
} = _ref9;
|
|
208
|
+
|
|
209
|
+
if (tooltipDimensions === null || tooltipDimensions.width !== width || tooltipDimensions.height !== height) {
|
|
210
|
+
setTooltipDimensions({
|
|
211
|
+
width: Platform.select({
|
|
212
|
+
web: width + 0.3,
|
|
213
|
+
// avoids often unnecessary line breaks due to subpixel rendering of fonts
|
|
214
|
+
native: width
|
|
215
|
+
}),
|
|
216
|
+
height
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
useEffect(() => {
|
|
222
|
+
if (isOpen) {
|
|
223
|
+
controlRef.current.measureInWindow((x, y, width, height) => {
|
|
224
|
+
setControlLayout({
|
|
225
|
+
x,
|
|
226
|
+
y,
|
|
227
|
+
width,
|
|
228
|
+
height
|
|
229
|
+
});
|
|
230
|
+
});
|
|
231
|
+
} else {
|
|
232
|
+
setControlLayout(null);
|
|
233
|
+
setTooltipDimensions(null);
|
|
234
|
+
setTooltipPosition(null);
|
|
235
|
+
}
|
|
236
|
+
}, [isOpen]);
|
|
237
|
+
useEffect(() => {
|
|
238
|
+
setIsOpen(false);
|
|
239
|
+
}, [windowDimensions]);
|
|
240
|
+
useEffect(() => {
|
|
241
|
+
if (tooltipPosition !== null && !(tooltipPosition !== null && tooltipPosition !== void 0 && tooltipPosition.isNormalized) || !isOpen || controlLayout === null || tooltipDimensions == null) {
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
const updatedPosition = getTooltipPosition(position, {
|
|
246
|
+
controlLayout,
|
|
247
|
+
tooltipDimensions,
|
|
248
|
+
windowDimensions,
|
|
249
|
+
arrowWidth,
|
|
250
|
+
arrowOffset
|
|
251
|
+
}); // avoid ending up in an infinite normalization loop
|
|
252
|
+
|
|
253
|
+
if (tooltipPosition !== null && tooltipPosition !== void 0 && tooltipPosition.isNormalized && updatedPosition.isNormalized) {
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
setTooltipPosition(updatedPosition);
|
|
258
|
+
}, [isOpen, position, tooltipDimensions, controlLayout, windowDimensions, arrowWidth, arrowOffset, tooltipPosition]);
|
|
259
|
+
const control = children !== undefined ? children : defaultControl;
|
|
260
|
+
const pressableStyles = control === defaultControl ? Platform.select({
|
|
261
|
+
web: {
|
|
262
|
+
outline: 'none'
|
|
263
|
+
}
|
|
264
|
+
}) : undefined;
|
|
265
|
+
const pressableHitSlop = control === defaultControl ? {
|
|
266
|
+
top: 10,
|
|
267
|
+
bottom: 10,
|
|
268
|
+
left: 10,
|
|
269
|
+
right: 10
|
|
270
|
+
} : undefined;
|
|
271
|
+
return /*#__PURE__*/_jsxs(View, {
|
|
272
|
+
style: staticStyles.container,
|
|
273
|
+
...selectProps(rest),
|
|
274
|
+
children: [/*#__PURE__*/_jsx(Pressable, {
|
|
275
|
+
onPress: toggleIsOpen,
|
|
276
|
+
ref: controlRef,
|
|
277
|
+
onBlur: close,
|
|
278
|
+
style: pressableStyles,
|
|
279
|
+
hitSlop: pressableHitSlop,
|
|
280
|
+
accessibilityLabel: getCopy('a11yText'),
|
|
281
|
+
accessibilityRole: "button",
|
|
282
|
+
children: typeof control === 'function' ? pressableState => control(getPressableState(pressableState), variant) : control
|
|
283
|
+
}), isOpen && /*#__PURE__*/_jsx(Backdrop, {
|
|
284
|
+
onPress: close,
|
|
285
|
+
children: /*#__PURE__*/_jsxs(View, {
|
|
286
|
+
ref: ref,
|
|
287
|
+
style: [staticStyles.tooltip, selectTooltipShadowStyles(themeTokens), // applied separately so that it doesn't cover the arrow
|
|
288
|
+
tooltipPosition && selectTooltipPositionStyles(tooltipPosition), (tooltipPosition === null || (tooltipPosition === null || tooltipPosition === void 0 ? void 0 : tooltipPosition.isNormalized)) && staticStyles.tooltipHidden // visually hide the tooltip until we have a final measurement
|
|
289
|
+
],
|
|
290
|
+
onLayout: onTooltipLayout,
|
|
291
|
+
accessibilityRole: "alert",
|
|
292
|
+
children: [/*#__PURE__*/_jsx(View, {
|
|
293
|
+
style: [staticStyles.arrow, tooltipPosition && selectArrowStyles(themeTokens, tooltipPosition)]
|
|
294
|
+
}), /*#__PURE__*/_jsx(View, {
|
|
295
|
+
style: selectTooltipStyles(themeTokens),
|
|
296
|
+
children: /*#__PURE__*/_jsx(Text, {
|
|
297
|
+
style: selectTextStyles(themeTokens),
|
|
298
|
+
children: content
|
|
299
|
+
})
|
|
300
|
+
})]
|
|
301
|
+
})
|
|
302
|
+
})]
|
|
303
|
+
});
|
|
304
|
+
});
|
|
305
|
+
Tooltip.displayName = 'NativeTooltip';
|
|
306
|
+
Tooltip.propTypes = { ...selectedSystemPropTypes,
|
|
307
|
+
...propTypes
|
|
308
|
+
};
|
|
309
|
+
export default Tooltip;
|
|
310
|
+
const staticStyles = StyleSheet.create({
|
|
311
|
+
container: {
|
|
312
|
+
alignItems: 'flex-start'
|
|
313
|
+
},
|
|
314
|
+
tooltip: {
|
|
315
|
+
position: 'absolute',
|
|
316
|
+
maxWidth: 240,
|
|
317
|
+
top: 0,
|
|
318
|
+
left: 0
|
|
319
|
+
},
|
|
320
|
+
tooltipHidden: {
|
|
321
|
+
opacity: 0
|
|
322
|
+
},
|
|
323
|
+
arrow: {
|
|
324
|
+
position: 'absolute'
|
|
325
|
+
}
|
|
326
|
+
});
|
|
@@ -1,2 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import Dimensions from "react-native-web/dist/exports/Dimensions";
|
|
2
|
+
import NonNativeTooltip from './Tooltip';
|
|
3
|
+
import NativeToolTip from './Tooltip.native';
|
|
4
|
+
const Tooltip = !Dimensions.get('screen').width <= 340 ? NativeToolTip : NonNativeTooltip;
|
|
2
5
|
export default Tooltip;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import PropTypes from 'prop-types';
|
|
2
|
+
import { getTokensPropType, variantProp } from '../utils';
|
|
3
|
+
const propTypes = {
|
|
4
|
+
/**
|
|
5
|
+
* Used to render the control (i.e. tooltip trigger). If a render function is used it will receive the
|
|
6
|
+
* pressable state and tooltip variant as an argument.
|
|
7
|
+
*/
|
|
8
|
+
children: PropTypes.oneOfType([PropTypes.func, PropTypes.node]),
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* The message. Can be raw text or text components.
|
|
12
|
+
*/
|
|
13
|
+
content: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Select English or French copy for the accessible label.
|
|
17
|
+
*/
|
|
18
|
+
copy: PropTypes.oneOf(['en', 'fr']),
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Use to place the tooltip in a specific location (only if it fits within viewport).
|
|
22
|
+
*/
|
|
23
|
+
position: PropTypes.oneOf(['auto', 'above', 'right', 'below', 'left']),
|
|
24
|
+
tokens: getTokensPropType('Tooltip'),
|
|
25
|
+
variant: variantProp.propType
|
|
26
|
+
};
|
|
27
|
+
export default propTypes;
|
|
@@ -66,7 +66,9 @@ const Typography = /*#__PURE__*/forwardRef((_ref2, ref) => {
|
|
|
66
66
|
dataSet,
|
|
67
67
|
maxFontSizeMultiplier: getMaxFontMultiplier(themeTokens)
|
|
68
68
|
};
|
|
69
|
-
const containerProps = {
|
|
69
|
+
const containerProps = {
|
|
70
|
+
accessibilityRole,
|
|
71
|
+
...getA11yPropsFromHtmlTag(tag, accessibilityRole),
|
|
70
72
|
...selectContainerProps(rest)
|
|
71
73
|
};
|
|
72
74
|
return block ? /*#__PURE__*/_jsx(View, {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { useFloating, arrow, offset, shift, flip, autoPlacement } from '@floating-ui/react-dom';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { useFloating, arrow, offset, shift, flip, autoPlacement } from '@floating-ui/react-native';
|
package/package.json
CHANGED
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
"url": "https://github.com/telus/universal-design-system/issues"
|
|
8
8
|
},
|
|
9
9
|
"dependencies": {
|
|
10
|
+
"@floating-ui/react-dom": "^1.0.1",
|
|
11
|
+
"@floating-ui/react-native": "^0.8.1",
|
|
10
12
|
"@gorhom/portal": "^1.0.14",
|
|
11
13
|
"@telus-uds/system-constants": "^1.2.0",
|
|
12
14
|
"@telus-uds/system-theme-tokens": "^2.9.0",
|
|
@@ -64,11 +66,11 @@
|
|
|
64
66
|
"build:main": "babel src -d lib",
|
|
65
67
|
"build:module": "babel src -d lib-module --env-name module",
|
|
66
68
|
"build:code": "npm run build:main && npm run build:module",
|
|
67
|
-
"build:docs": "babel-node --plugins=@
|
|
69
|
+
"build:docs": "babel-node --plugins=@telus-uds/babel-plugin-react-docgen generate-component-docs.js"
|
|
68
70
|
},
|
|
69
71
|
"sideEffects": false,
|
|
70
72
|
"standard-engine": {
|
|
71
73
|
"skip": true
|
|
72
74
|
},
|
|
73
|
-
"version": "1.24.
|
|
75
|
+
"version": "1.24.2"
|
|
74
76
|
}
|
package/src/Box/Box.jsx
CHANGED
package/src/Divider/Divider.jsx
CHANGED
|
@@ -72,7 +72,10 @@ const Divider = forwardRef(({ variant, vertical = false, space, tokens, ...rest
|
|
|
72
72
|
Platform.OS === 'web'
|
|
73
73
|
? // There are aria attributes for dividers on web
|
|
74
74
|
{
|
|
75
|
+
// Early versions of React Native Web support 'aria-orientation' while
|
|
76
|
+
// later versions only support accessibilityOrientation and map it. Supply both.
|
|
75
77
|
'aria-orientation': vertical ? 'vertical' : 'horizontal',
|
|
78
|
+
accessibilityOrientation: vertical ? 'vertical' : 'horizontal',
|
|
76
79
|
accessibilityRole: 'separator'
|
|
77
80
|
}
|
|
78
81
|
: // There are no such equivalent attributes for native
|
|
@@ -56,14 +56,10 @@ const selectIconContainerStyles = ({ iconGap }) => ({
|
|
|
56
56
|
* All accessibility props set on this component will be applied to the outer container.
|
|
57
57
|
*/
|
|
58
58
|
const Feedback = forwardRef(
|
|
59
|
-
(
|
|
60
|
-
{ title, children, id, validation, tokens, variant, showFeedbackIcon = false, ...rest },
|
|
61
|
-
ref
|
|
62
|
-
) => {
|
|
59
|
+
({ title, children, id, validation, tokens, variant, ...rest }, ref) => {
|
|
63
60
|
const themeTokens = useThemeTokens('Feedback', tokens, {
|
|
64
61
|
...variant,
|
|
65
|
-
validation
|
|
66
|
-
icon: showFeedbackIcon
|
|
62
|
+
validation
|
|
67
63
|
})
|
|
68
64
|
const { space } = themeTokens
|
|
69
65
|
|
|
@@ -121,8 +117,7 @@ Feedback.propTypes = {
|
|
|
121
117
|
/** @ignore */
|
|
122
118
|
id: PropTypes.string,
|
|
123
119
|
tokens: getTokensPropType('Feedback'),
|
|
124
|
-
variant: variantProp.propType
|
|
125
|
-
showFeedbackIcon: PropTypes.bool
|
|
120
|
+
variant: variantProp.propType
|
|
126
121
|
}
|
|
127
122
|
|
|
128
123
|
export default Feedback
|
|
@@ -9,16 +9,18 @@ import { Pressable, StyleSheet } from 'react-native'
|
|
|
9
9
|
* InlinePressable is an alternative to React Native's Pressable that works better when nested
|
|
10
10
|
* inline inside Text. It accepts the same props as React Native's Pressable.
|
|
11
11
|
*
|
|
12
|
+
* On Web it simply passes its props to Pressable and defaults to `inline-flex` instead of `flex`.
|
|
13
|
+
*
|
|
12
14
|
* @param {PressableProps} PressableProps
|
|
13
15
|
*/
|
|
14
16
|
// React Native exports prop Types but not propTypes, use JSDoc types here rather than duplicate RN
|
|
15
17
|
// eslint-disable-next-line react/prop-types
|
|
16
|
-
const InlinePressable = forwardRef(({ children, style, ...props }, ref) => (
|
|
18
|
+
const InlinePressable = forwardRef(({ children, inlineFlex = true, style, ...props }, ref) => (
|
|
17
19
|
<Pressable
|
|
18
20
|
ref={ref}
|
|
19
21
|
style={(pressState) => [
|
|
20
|
-
|
|
21
|
-
|
|
22
|
+
typeof style === 'function' ? style(pressState) : style,
|
|
23
|
+
staticStyles[inlineFlex ? 'inlineFlex' : 'inline']
|
|
22
24
|
]}
|
|
23
25
|
{...props}
|
|
24
26
|
>
|
|
@@ -29,7 +31,11 @@ InlinePressable.displayName = 'InlinePressable'
|
|
|
29
31
|
|
|
30
32
|
const staticStyles = StyleSheet.create({
|
|
31
33
|
inline: {
|
|
34
|
+
// Stop Pressable defaulting to (block) flex
|
|
32
35
|
display: 'inline'
|
|
36
|
+
},
|
|
37
|
+
inlineFlex: {
|
|
38
|
+
display: 'inline-flex'
|
|
33
39
|
}
|
|
34
40
|
})
|
|
35
41
|
|
package/src/Link/LinkBase.jsx
CHANGED
|
@@ -20,10 +20,13 @@ import { IconText, iconComponentPropTypes } from '../Icon'
|
|
|
20
20
|
|
|
21
21
|
const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, linkProps, viewProps])
|
|
22
22
|
|
|
23
|
-
const selectOuterBorderStyles = (
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
const selectOuterBorderStyles = ({
|
|
24
|
+
outerBorderColor,
|
|
25
|
+
outerBorderWidth,
|
|
26
|
+
outerBorderGap,
|
|
27
|
+
borderRadius,
|
|
28
|
+
outerBorderOutline
|
|
29
|
+
}) =>
|
|
27
30
|
// A view wrapper with a border on native messes up inline text alignment
|
|
28
31
|
// so for now make focus styles strictly web-only
|
|
29
32
|
Platform.OS === 'web'
|
|
@@ -35,10 +38,7 @@ const selectOuterBorderStyles = (
|
|
|
35
38
|
outerBorderWidth,
|
|
36
39
|
outerBorderGap,
|
|
37
40
|
borderRadius
|
|
38
|
-
})
|
|
39
|
-
// Stops focus ring stretching horizontally if parent has display: block
|
|
40
|
-
// width: fit-content isn't supported on Firefox; can't cascade props like CSS `width: fit-content; width: --moz-fit-content;`
|
|
41
|
-
display: hasIcon ? 'inline-flex' : 'inline' // Stop Pressable defaulting to (block) flex
|
|
41
|
+
})
|
|
42
42
|
}
|
|
43
43
|
: {}
|
|
44
44
|
|
|
@@ -144,12 +144,19 @@ const LinkBase = forwardRef(
|
|
|
144
144
|
return (
|
|
145
145
|
<InlinePressable
|
|
146
146
|
{...selectedProps}
|
|
147
|
+
inlineFlex={hasIcon} // assuming links without icons should be inline (even if they are long)
|
|
147
148
|
ref={ref}
|
|
148
149
|
style={(linkState) => {
|
|
149
150
|
const themeTokens = resolveLinkTokens(linkState)
|
|
150
|
-
const outerBorderStyles = selectOuterBorderStyles(themeTokens
|
|
151
|
+
const outerBorderStyles = selectOuterBorderStyles(themeTokens)
|
|
151
152
|
const decorationStyles = selectDecorationStyles(themeTokens)
|
|
152
|
-
|
|
153
|
+
|
|
154
|
+
return [
|
|
155
|
+
outerBorderStyles,
|
|
156
|
+
blockLeftStyle,
|
|
157
|
+
decorationStyles,
|
|
158
|
+
hasIcon && staticStyles.rowContainer
|
|
159
|
+
]
|
|
153
160
|
}}
|
|
154
161
|
>
|
|
155
162
|
{(linkState) => {
|
package/src/List/ListItem.jsx
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
import React, { forwardRef } from 'react'
|
|
2
2
|
|
|
3
3
|
import ListItemBase from './ListItemBase'
|
|
4
|
+
import Typography from '../Typography'
|
|
4
5
|
import { useThemeTokens } from '../ThemeProvider'
|
|
5
6
|
import { variantProp } from '../utils'
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* ListItem is responsible for rendering icon or a bullet as side item
|
|
9
10
|
*/
|
|
10
|
-
const ListItem = forwardRef(({ tokens, variant, children, ...listItemProps }, ref) => {
|
|
11
|
+
const ListItem = forwardRef(({ tokens, variant, children, title, ...listItemProps }, ref) => {
|
|
11
12
|
const themeTokens = useThemeTokens('List', tokens, variant)
|
|
12
13
|
return (
|
|
13
14
|
<ListItemBase tokens={themeTokens} ref={ref} {...listItemProps}>
|
|
15
|
+
{Boolean(title) && <Typography variant={{ size: 'h4' }}>{title}</Typography>}
|
|
14
16
|
{children}
|
|
15
17
|
</ListItemBase>
|
|
16
18
|
)
|
package/src/Radio/RadioGroup.jsx
CHANGED
|
@@ -67,6 +67,7 @@ const StackWrapBox = forwardRef(
|
|
|
67
67
|
const themeTokens = useThemeTokens('StackView', tokens, variant, { viewport })
|
|
68
68
|
const flexStyles = selectFlexStyles(themeTokens)
|
|
69
69
|
const selectedProps = selectProps({
|
|
70
|
+
accessibilityRole,
|
|
70
71
|
...getA11yPropsFromHtmlTag(tag, accessibilityRole),
|
|
71
72
|
...rest
|
|
72
73
|
})
|
|
@@ -46,6 +46,7 @@ const StackWrapGap = forwardRef(
|
|
|
46
46
|
const themeTokens = useThemeTokens('StackView', tokens, variant, { viewport })
|
|
47
47
|
const flexStyles = selectFlexStyles(themeTokens)
|
|
48
48
|
const selectedProps = selectProps({
|
|
49
|
+
accessibilityRole,
|
|
49
50
|
...getA11yPropsFromHtmlTag(tag, accessibilityRole),
|
|
50
51
|
...rest
|
|
51
52
|
})
|
|
@@ -45,9 +45,7 @@ export function applyTextStyles({
|
|
|
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 = `${fontName}${fontWeight}${fontStyle}`
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
if (fontWeight) {
|
|
48
|
+
} else if (fontWeight) {
|
|
51
49
|
// If using system default font, apply the font weight directly.
|
|
52
50
|
// Font weight support in Android is limited to 'bold' or anything else === 'normal'.
|
|
53
51
|
styles.fontWeight = Platform.OS === 'android' && Number(fontWeight) > 400 ? 'bold' : fontWeight
|