@telus-uds/components-base 1.95.0 → 1.97.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 +42 -2
- package/lib/Autocomplete/Autocomplete.js +36 -2
- package/lib/Card/CardBase.js +4 -0
- package/lib/Carousel/Carousel.js +1 -1
- package/lib/Carousel/CarouselItem/CarouselItem.js +15 -19
- package/lib/InputLabel/InputLabel.js +2 -3
- package/lib/List/ListItemBase.js +3 -1
- package/lib/Listbox/GroupControl.js +4 -0
- package/lib/Modal/Modal.js +34 -13
- package/lib/Modal/ModalContent.js +4 -3
- package/lib/Modal/WebModal.js +1 -0
- package/lib/Notification/Notification.js +5 -5
- package/lib/Pagination/Pagination.js +9 -2
- package/lib/Pagination/constants.js +12 -0
- package/lib/Pagination/usePagination.js +13 -3
- package/lib/PriceLockup/PriceLockup.js +11 -3
- package/lib/Progress/Progress.js +5 -2
- package/lib/Progress/ProgressBar.js +4 -1
- package/lib/Tooltip/Tooltip.native.js +31 -3
- package/lib/Tooltip/shared.js +5 -0
- package/lib/Typography/Typography.js +42 -19
- package/lib/index.js +7 -0
- package/lib-module/Autocomplete/Autocomplete.js +36 -2
- package/lib-module/Card/CardBase.js +4 -0
- package/lib-module/Carousel/Carousel.js +1 -1
- package/lib-module/Carousel/CarouselItem/CarouselItem.js +15 -19
- package/lib-module/InputLabel/InputLabel.js +2 -3
- package/lib-module/List/ListItemBase.js +3 -1
- package/lib-module/Listbox/GroupControl.js +4 -0
- package/lib-module/Modal/Modal.js +34 -13
- package/lib-module/Modal/ModalContent.js +4 -3
- package/lib-module/Modal/WebModal.js +1 -0
- package/lib-module/Notification/Notification.js +5 -5
- package/lib-module/Pagination/Pagination.js +9 -2
- package/lib-module/Pagination/constants.js +3 -0
- package/lib-module/Pagination/usePagination.js +13 -3
- package/lib-module/PriceLockup/PriceLockup.js +11 -3
- package/lib-module/Progress/Progress.js +6 -3
- package/lib-module/Progress/ProgressBar.js +5 -2
- package/lib-module/Tooltip/Tooltip.native.js +31 -3
- package/lib-module/Tooltip/shared.js +5 -0
- package/lib-module/Typography/Typography.js +42 -19
- package/lib-module/index.js +1 -1
- package/package.json +2 -2
- package/src/Autocomplete/Autocomplete.jsx +41 -2
- package/src/Card/CardBase.jsx +6 -0
- package/src/Carousel/Carousel.jsx +1 -1
- package/src/Carousel/CarouselItem/CarouselItem.jsx +16 -22
- package/src/InputLabel/InputLabel.jsx +2 -3
- package/src/List/ListItemBase.jsx +6 -1
- package/src/Listbox/GroupControl.jsx +6 -1
- package/src/Modal/Modal.jsx +40 -14
- package/src/Modal/ModalContent.jsx +4 -3
- package/src/Modal/WebModal.jsx +1 -1
- package/src/Notification/Notification.jsx +5 -5
- package/src/Pagination/Pagination.jsx +9 -2
- package/src/Pagination/constants.js +3 -0
- package/src/Pagination/usePagination.js +14 -3
- package/src/PriceLockup/PriceLockup.jsx +9 -1
- package/src/Progress/Progress.jsx +6 -3
- package/src/Progress/ProgressBar.jsx +4 -2
- package/src/Tooltip/Tooltip.native.jsx +31 -3
- package/src/Tooltip/shared.js +5 -0
- package/src/Typography/Typography.jsx +37 -13
- package/src/index.js +2 -1
- package/types/FileUpload.d.ts +40 -0
- package/types/index.d.ts +3 -0
|
@@ -119,9 +119,10 @@ const selectArrowStyles = (_ref4, _ref5) => {
|
|
|
119
119
|
};
|
|
120
120
|
};
|
|
121
121
|
const selectTextStyles = tokens => applyTextStyles(selectTokens('Typography', tokens));
|
|
122
|
-
const defaultControl = (pressableState, variant) => /*#__PURE__*/_jsx(TooltipButton, {
|
|
122
|
+
const defaultControl = (pressableState, variant, tokens) => /*#__PURE__*/_jsx(TooltipButton, {
|
|
123
123
|
pressableState: pressableState,
|
|
124
|
-
variant: variant
|
|
124
|
+
variant: variant,
|
|
125
|
+
tokens: tokens
|
|
125
126
|
});
|
|
126
127
|
|
|
127
128
|
/**
|
|
@@ -150,6 +151,8 @@ const Tooltip = /*#__PURE__*/React.forwardRef((_ref6, ref) => {
|
|
|
150
151
|
variant,
|
|
151
152
|
inline = false,
|
|
152
153
|
nativeID,
|
|
154
|
+
activateOnHover = false,
|
|
155
|
+
tooltipButtonTokens,
|
|
153
156
|
...rest
|
|
154
157
|
} = _ref6;
|
|
155
158
|
const [isOpen, setIsOpen] = React.useState(false);
|
|
@@ -250,6 +253,31 @@ const Tooltip = /*#__PURE__*/React.forwardRef((_ref6, ref) => {
|
|
|
250
253
|
}
|
|
251
254
|
setTooltipPosition(updatedPosition);
|
|
252
255
|
}, [isOpen, position, tooltipDimensions, controlLayout, windowDimensions, arrowWidth, arrowOffset, tooltipPosition]);
|
|
256
|
+
React.useEffect(() => {
|
|
257
|
+
if (Platform.OS !== 'web') {
|
|
258
|
+
return undefined;
|
|
259
|
+
}
|
|
260
|
+
const handleHover = event => {
|
|
261
|
+
if (activateOnHover) {
|
|
262
|
+
const isInsideControl = controlRef.current && controlRef.current.contains(event.target);
|
|
263
|
+
if (isInsideControl) {
|
|
264
|
+
if (!isOpen) {
|
|
265
|
+
setIsOpen(!isOpen);
|
|
266
|
+
}
|
|
267
|
+
} else {
|
|
268
|
+
close();
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
};
|
|
272
|
+
document.addEventListener('mouseover', handleHover, {
|
|
273
|
+
capture: true
|
|
274
|
+
});
|
|
275
|
+
return () => {
|
|
276
|
+
document.removeEventListener('mouseover', handleHover, {
|
|
277
|
+
capture: true
|
|
278
|
+
});
|
|
279
|
+
};
|
|
280
|
+
}, [controlLayout, activateOnHover, isOpen, onPress]);
|
|
253
281
|
const control = children !== undefined ? children : defaultControl;
|
|
254
282
|
const pressableStyles = control === defaultControl ? Platform.select({
|
|
255
283
|
web: {
|
|
@@ -278,7 +306,7 @@ const Tooltip = /*#__PURE__*/React.forwardRef((_ref6, ref) => {
|
|
|
278
306
|
accessibilityLabel: getCopy('a11yText'),
|
|
279
307
|
accessibilityRole: "button",
|
|
280
308
|
nativeID: nativeID,
|
|
281
|
-
children: typeof control === 'function' ? pressableState => control(getPressableState(pressableState), variant) : control
|
|
309
|
+
children: typeof control === 'function' ? pressableState => control(getPressableState(pressableState), variant, tooltipButtonTokens) : control
|
|
282
310
|
}), isOpen && /*#__PURE__*/_jsx(Backdrop, {
|
|
283
311
|
onPress: close,
|
|
284
312
|
children: /*#__PURE__*/_jsxs(View, {
|
|
@@ -30,6 +30,11 @@ const propTypes = {
|
|
|
30
30
|
* The `id` of the tooltip button.
|
|
31
31
|
*/
|
|
32
32
|
nativeID: PropTypes.string,
|
|
33
|
+
/**
|
|
34
|
+
* Set to `true` to open the tooltip on hover
|
|
35
|
+
*/
|
|
36
|
+
activateOnHover: PropTypes.bool,
|
|
37
|
+
tooltipButtonTokens: getTokensPropType('TooltipButton'),
|
|
33
38
|
tokens: getTokensPropType('Tooltip'),
|
|
34
39
|
variant: variantProp.propType
|
|
35
40
|
};
|
|
@@ -2,6 +2,7 @@ import React from 'react';
|
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
3
|
import Text from "react-native-web/dist/exports/Text";
|
|
4
4
|
import View from "react-native-web/dist/exports/View";
|
|
5
|
+
import Platform from "react-native-web/dist/exports/Platform";
|
|
5
6
|
import { useResponsiveThemeTokens, useTheme, useThemeTokens } from '../ThemeProvider';
|
|
6
7
|
import { applyTextStyles } from '../ThemeProvider/utils';
|
|
7
8
|
import { a11yProps, variantProp, getTokensPropType, getMaxFontMultiplier, headingTags, selectSystemProps, textTags, textProps, viewProps, getA11yPropsFromHtmlTag, StyleSheet, createMediaQueryStyles } from '../utils';
|
|
@@ -39,9 +40,22 @@ const selectTextStyles = (_ref, themeOptions) => {
|
|
|
39
40
|
gradient
|
|
40
41
|
});
|
|
41
42
|
};
|
|
43
|
+
const HALF_FONT_SIZE = 2;
|
|
44
|
+
const QUARTER_FONT_SIZE = 4;
|
|
45
|
+
const selectMobileSubSupStyles = (_ref2, type) => {
|
|
46
|
+
let {
|
|
47
|
+
fontSize
|
|
48
|
+
} = _ref2;
|
|
49
|
+
return {
|
|
50
|
+
fontSize: fontSize / HALF_FONT_SIZE,
|
|
51
|
+
lineHeight: fontSize,
|
|
52
|
+
position: 'relative',
|
|
53
|
+
top: type === 'sub' ? fontSize / QUARTER_FONT_SIZE : -fontSize / QUARTER_FONT_SIZE
|
|
54
|
+
};
|
|
55
|
+
};
|
|
42
56
|
|
|
43
57
|
// General-purpose flexible theme-neutral base component for text
|
|
44
|
-
const Typography = /*#__PURE__*/React.forwardRef((
|
|
58
|
+
const Typography = /*#__PURE__*/React.forwardRef((_ref3, ref) => {
|
|
45
59
|
let {
|
|
46
60
|
children,
|
|
47
61
|
variant,
|
|
@@ -54,7 +68,7 @@ const Typography = /*#__PURE__*/React.forwardRef((_ref2, ref) => {
|
|
|
54
68
|
dataSet,
|
|
55
69
|
strikeThrough = false,
|
|
56
70
|
...rest
|
|
57
|
-
} =
|
|
71
|
+
} = _ref3;
|
|
58
72
|
const viewport = useViewport();
|
|
59
73
|
const {
|
|
60
74
|
themeOptions
|
|
@@ -101,8 +115,8 @@ const Typography = /*#__PURE__*/React.forwardRef((_ref2, ref) => {
|
|
|
101
115
|
let textStyles;
|
|
102
116
|
let mediaIds;
|
|
103
117
|
if (enableMediaQueryStyleSheet) {
|
|
104
|
-
const transformedThemeTokens = Object.entries(themeTokens).reduce((acc,
|
|
105
|
-
let [vp, viewportTokens] =
|
|
118
|
+
const transformedThemeTokens = Object.entries(themeTokens).reduce((acc, _ref4) => {
|
|
119
|
+
let [vp, viewportTokens] = _ref4;
|
|
106
120
|
acc[vp] = selectTextStyles({
|
|
107
121
|
textAlign: align,
|
|
108
122
|
textDecorationLine,
|
|
@@ -136,22 +150,31 @@ const Typography = /*#__PURE__*/React.forwardRef((_ref2, ref) => {
|
|
|
136
150
|
...selectContainerProps(rest)
|
|
137
151
|
};
|
|
138
152
|
const resetTagStyling = child => {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
const supFontSize = childStyles.fontSize ?? themeTokens.superScriptFontSize;
|
|
143
|
-
const sanitizedChild = /*#__PURE__*/React.cloneElement(child, {
|
|
144
|
-
style: {
|
|
145
|
-
...childStyles,
|
|
146
|
-
...(supFontSize ? {
|
|
147
|
-
fontSize: supFontSize
|
|
148
|
-
} : {}),
|
|
149
|
-
lineHeight: 0
|
|
150
|
-
}
|
|
151
|
-
});
|
|
152
|
-
return sanitizedChild;
|
|
153
|
+
var _child$props;
|
|
154
|
+
if (typeof child !== 'object' || !((child === null || child === void 0 ? void 0 : child.type) === 'sub' || (child === null || child === void 0 ? void 0 : child.type) === 'sup')) {
|
|
155
|
+
return child;
|
|
153
156
|
}
|
|
154
|
-
|
|
157
|
+
const childStyles = (child === null || child === void 0 ? void 0 : (_child$props = child.props) === null || _child$props === void 0 ? void 0 : _child$props.style) || {};
|
|
158
|
+
const supFontSize = childStyles.fontSize ?? themeTokens.superScriptFontSize;
|
|
159
|
+
const isMobile = Platform.OS === 'ios' || Platform.OS === 'android';
|
|
160
|
+
const isSubSup = (child === null || child === void 0 ? void 0 : child.type) === 'sub' || (child === null || child === void 0 ? void 0 : child.type) === 'sup';
|
|
161
|
+
const mobileStyles = isMobile && isSubSup ? selectMobileSubSupStyles(themeTokens, child === null || child === void 0 ? void 0 : child.type) : {};
|
|
162
|
+
const defaultStyles = !isMobile && isSubSup ? {
|
|
163
|
+
fontSize: supFontSize,
|
|
164
|
+
lineHeight: 0
|
|
165
|
+
} : {};
|
|
166
|
+
const sanitizedChild = /*#__PURE__*/React.cloneElement(isMobile && isSubSup ? /*#__PURE__*/_jsx(View, {
|
|
167
|
+
children: /*#__PURE__*/_jsx(Text, {
|
|
168
|
+
style: [childStyles, mobileStyles],
|
|
169
|
+
children: child.props.children
|
|
170
|
+
})
|
|
171
|
+
}) : child, {
|
|
172
|
+
style: {
|
|
173
|
+
...childStyles,
|
|
174
|
+
...defaultStyles
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
return sanitizedChild;
|
|
155
178
|
};
|
|
156
179
|
const sanitizeChildren = () => {
|
|
157
180
|
if (Array.isArray(children)) {
|
package/lib-module/index.js
CHANGED
|
@@ -71,6 +71,6 @@ export { default as BaseProvider } from './BaseProvider';
|
|
|
71
71
|
export { useHydrationContext } from './BaseProvider/HydrationContext';
|
|
72
72
|
export { default as Validator } from './Validator';
|
|
73
73
|
export { default as ViewportProvider, useViewport, ViewportContext } from './ViewportProvider';
|
|
74
|
-
export { default as ThemeProvider, useTheme, useSetTheme, useThemeTokens, useThemeTokensCallback, getThemeTokens, applyOuterBorder, applyTextStyles, applyShadowToken } from './ThemeProvider';
|
|
74
|
+
export { default as ThemeProvider, useTheme, useSetTheme, useThemeTokens, useThemeTokensCallback, getThemeTokens, applyOuterBorder, applyTextStyles, applyShadowToken, useResponsiveThemeTokens } from './ThemeProvider';
|
|
75
75
|
export * from './utils';
|
|
76
76
|
export { default as Portal } from './Portal';
|
package/package.json
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"@floating-ui/react-native": "^0.8.1",
|
|
12
12
|
"@gorhom/portal": "^1.0.14",
|
|
13
13
|
"@telus-uds/system-constants": "^1.3.0",
|
|
14
|
-
"@telus-uds/system-theme-tokens": "^2.
|
|
14
|
+
"@telus-uds/system-theme-tokens": "^2.66.0",
|
|
15
15
|
"airbnb-prop-types": "^2.16.0",
|
|
16
16
|
"css-mediaquery": "^0.1.2",
|
|
17
17
|
"expo-linear-gradient": "^12.5.0",
|
|
@@ -86,6 +86,6 @@
|
|
|
86
86
|
"standard-engine": {
|
|
87
87
|
"skip": true
|
|
88
88
|
},
|
|
89
|
-
"version": "1.
|
|
89
|
+
"version": "1.97.0",
|
|
90
90
|
"types": "types/index.d.ts"
|
|
91
91
|
}
|
|
@@ -135,6 +135,8 @@ const Autocomplete = React.forwardRef(
|
|
|
135
135
|
// When it's nested, selected value
|
|
136
136
|
const [nestedSelectedValue, setNestedSelectedValue] = React.useState(null)
|
|
137
137
|
|
|
138
|
+
const [isInputVisible, setIsInputVisible] = React.useState(true)
|
|
139
|
+
|
|
138
140
|
const { supportsProps, ...selectedProps } = selectProps(rest)
|
|
139
141
|
const { hint, label: inputLabel } = supportsProps
|
|
140
142
|
const hintExpansionEnabled = isFocused && helpText && !currentValue
|
|
@@ -244,6 +246,32 @@ const Autocomplete = React.forwardRef(
|
|
|
244
246
|
}
|
|
245
247
|
}, [nestedSelectedValue, items])
|
|
246
248
|
|
|
249
|
+
React.useEffect(() => {
|
|
250
|
+
if (Platform.OS === 'ios' || Platform.OS === 'android') {
|
|
251
|
+
return undefined
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
const observer = new IntersectionObserver((entries) => {
|
|
255
|
+
const [entry] = entries
|
|
256
|
+
setIsInputVisible(entry.isIntersecting)
|
|
257
|
+
if (!entry.isIntersecting) {
|
|
258
|
+
setIsExpanded(false)
|
|
259
|
+
}
|
|
260
|
+
})
|
|
261
|
+
|
|
262
|
+
const currentInputRef = inputRef.current
|
|
263
|
+
|
|
264
|
+
if (currentInputRef) {
|
|
265
|
+
observer.observe(currentInputRef)
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
return () => {
|
|
269
|
+
if (currentInputRef) {
|
|
270
|
+
observer.unobserve(currentInputRef)
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}, [inputRef])
|
|
274
|
+
|
|
247
275
|
const handleClose = (event) => {
|
|
248
276
|
if (
|
|
249
277
|
(event.type === 'keydown' && (event.key === 'Escape' || event.key === '27')) ||
|
|
@@ -313,7 +341,18 @@ const Autocomplete = React.forwardRef(
|
|
|
313
341
|
readOnly={readOnly}
|
|
314
342
|
ref={inputRef}
|
|
315
343
|
{...(Platform.OS !== 'web'
|
|
316
|
-
? {
|
|
344
|
+
? {
|
|
345
|
+
onLayout: (event) => {
|
|
346
|
+
setSourceLayout(event.nativeEvent.layout)
|
|
347
|
+
const { y, height } = event.nativeEvent.layout
|
|
348
|
+
if (y >= 0 && height > 0) {
|
|
349
|
+
setIsInputVisible(true)
|
|
350
|
+
} else {
|
|
351
|
+
setIsInputVisible(false)
|
|
352
|
+
setIsExpanded(false)
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
}
|
|
317
356
|
: {})}
|
|
318
357
|
tokens={inputTokens}
|
|
319
358
|
validation={validation}
|
|
@@ -324,7 +363,7 @@ const Autocomplete = React.forwardRef(
|
|
|
324
363
|
)
|
|
325
364
|
}}
|
|
326
365
|
</InputSupports>
|
|
327
|
-
{(isExpanded || hintExpansionEnabled) && (
|
|
366
|
+
{(isExpanded || hintExpansionEnabled) && isInputVisible && (
|
|
328
367
|
<>
|
|
329
368
|
<Listbox.Overlay
|
|
330
369
|
overlaidPosition={overlaidPosition}
|
package/src/Card/CardBase.jsx
CHANGED
|
@@ -21,6 +21,7 @@ const selectStyles = ({
|
|
|
21
21
|
paddingTop,
|
|
22
22
|
minWidth,
|
|
23
23
|
shadow,
|
|
24
|
+
backgroundGradient,
|
|
24
25
|
gradient
|
|
25
26
|
}) => {
|
|
26
27
|
return {
|
|
@@ -42,6 +43,11 @@ const selectStyles = ({
|
|
|
42
43
|
boxShadow: `inset 0 1000px white`,
|
|
43
44
|
border: `${borderWidth}px solid transparent`
|
|
44
45
|
}
|
|
46
|
+
: {}),
|
|
47
|
+
...(backgroundGradient && Platform.OS === 'web'
|
|
48
|
+
? {
|
|
49
|
+
backgroundImage: `linear-gradient(${backgroundGradient.angle}deg, ${backgroundGradient.stops[0].color}, ${backgroundGradient.stops[1].color})`
|
|
50
|
+
}
|
|
45
51
|
: {})
|
|
46
52
|
}
|
|
47
53
|
}
|
|
@@ -120,7 +120,7 @@ const selectPreviousNextNavigationButtonStyles = (
|
|
|
120
120
|
}
|
|
121
121
|
|
|
122
122
|
const getPeekingProps = (viewport) => {
|
|
123
|
-
if (viewport === 'xs' || viewport === 'sm') {
|
|
123
|
+
if (viewport === 'xs' || viewport === 'sm' || viewport === 'md') {
|
|
124
124
|
return {
|
|
125
125
|
peekingFirstSpace: 48,
|
|
126
126
|
peekingGap: 16,
|
|
@@ -20,43 +20,37 @@ const selectContainerStyle = ({
|
|
|
20
20
|
totalItems,
|
|
21
21
|
enablePeeking,
|
|
22
22
|
peekingMarginLeft,
|
|
23
|
-
peekingMarginRight,
|
|
24
23
|
peekingFirstSpace,
|
|
25
24
|
peekingLastSpace,
|
|
26
25
|
peekingMiddleSpace,
|
|
27
26
|
peekingGap,
|
|
28
27
|
hidden
|
|
29
28
|
}) => {
|
|
30
|
-
const isFirst = elementIndex === 0
|
|
31
|
-
const isLast = elementIndex === totalItems - 1
|
|
32
|
-
const isMiddle = !isFirst && !isLast
|
|
33
|
-
const isActive = activeIndex === elementIndex
|
|
34
|
-
|
|
35
29
|
let adjustedWidth = width
|
|
36
30
|
let marginLeft = 0
|
|
37
|
-
|
|
31
|
+
const marginRight = 0
|
|
38
32
|
|
|
39
33
|
if (enablePeeking) {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
adjustedWidth = width - peekingGap
|
|
44
|
-
}
|
|
34
|
+
adjustedWidth = width - (peekingMarginLeft + peekingGap + peekingFirstSpace)
|
|
35
|
+
const isFirst = elementIndex === 0
|
|
36
|
+
const isActive = activeIndex === elementIndex
|
|
45
37
|
|
|
46
|
-
if (
|
|
47
|
-
if (
|
|
38
|
+
if (isActive) {
|
|
39
|
+
if (isFirst) {
|
|
48
40
|
marginLeft = peekingMarginLeft
|
|
49
|
-
} else if (activeIndex === totalItems - 1) {
|
|
50
|
-
marginLeft = peekingLastSpace
|
|
51
41
|
} else {
|
|
52
|
-
marginLeft =
|
|
42
|
+
marginLeft = peekingGap
|
|
43
|
+
}
|
|
44
|
+
} else if (isFirst) {
|
|
45
|
+
marginLeft = peekingMarginLeft + peekingGap + peekingFirstSpace + peekingMiddleSpace
|
|
46
|
+
if (activeIndex > 1) {
|
|
47
|
+
marginLeft += (peekingGap + peekingMiddleSpace * 2) * (activeIndex - 1)
|
|
48
|
+
}
|
|
49
|
+
if (activeIndex === totalItems - 1) {
|
|
50
|
+
marginLeft += peekingLastSpace - peekingMiddleSpace
|
|
53
51
|
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
if (isLast && isActive) {
|
|
57
|
-
marginRight = peekingMarginRight
|
|
58
52
|
} else {
|
|
59
|
-
|
|
53
|
+
marginLeft = peekingGap
|
|
60
54
|
}
|
|
61
55
|
}
|
|
62
56
|
|
|
@@ -146,8 +146,7 @@ export default InputLabel
|
|
|
146
146
|
const staticStyles = StyleSheet.create({
|
|
147
147
|
container: {
|
|
148
148
|
flexShrink: 1,
|
|
149
|
-
flexDirection: 'row'
|
|
150
|
-
alignItems: 'baseline'
|
|
149
|
+
flexDirection: 'row'
|
|
151
150
|
},
|
|
152
151
|
label: {
|
|
153
152
|
flexShrink: 1
|
|
@@ -157,7 +156,7 @@ const staticStyles = StyleSheet.create({
|
|
|
157
156
|
flexShrink: 0
|
|
158
157
|
},
|
|
159
158
|
tooltipAlign: {
|
|
160
|
-
alignSelf: '
|
|
159
|
+
alignSelf: 'center',
|
|
161
160
|
justifyContent: 'center'
|
|
162
161
|
}
|
|
163
162
|
})
|
|
@@ -107,7 +107,12 @@ const staticStyles = StyleSheet.create({
|
|
|
107
107
|
flex: 1,
|
|
108
108
|
flexDirection: 'row'
|
|
109
109
|
},
|
|
110
|
-
titleAndContentContainer: {
|
|
110
|
+
titleAndContentContainer: {
|
|
111
|
+
flexDirection: 'column',
|
|
112
|
+
flexShrink: 1,
|
|
113
|
+
flexGrow: 1,
|
|
114
|
+
textAlign: 'justify'
|
|
115
|
+
}
|
|
111
116
|
})
|
|
112
117
|
|
|
113
118
|
ListItemBase.propTypes = {
|
|
@@ -48,6 +48,11 @@ const GroupControl = React.forwardRef(({ expanded, pressed, hover, focus, label,
|
|
|
48
48
|
itemOutline,
|
|
49
49
|
groupHeight
|
|
50
50
|
} = tokens
|
|
51
|
+
|
|
52
|
+
const getTextStyles = () => ({
|
|
53
|
+
color: groupColor
|
|
54
|
+
})
|
|
55
|
+
|
|
51
56
|
return (
|
|
52
57
|
<View
|
|
53
58
|
onPress={() => setSelectedId(id)}
|
|
@@ -71,7 +76,7 @@ const GroupControl = React.forwardRef(({ expanded, pressed, hover, focus, label,
|
|
|
71
76
|
]}
|
|
72
77
|
ref={ref}
|
|
73
78
|
>
|
|
74
|
-
<Text>{label}</Text>
|
|
79
|
+
<Text style={getTextStyles()}>{label}</Text>
|
|
75
80
|
<Spacer space={1} direction="row" />
|
|
76
81
|
<Icon
|
|
77
82
|
icon={tokens.groupIcon}
|
package/src/Modal/Modal.jsx
CHANGED
|
@@ -121,6 +121,8 @@ const Modal = React.forwardRef(
|
|
|
121
121
|
const viewport = useViewport()
|
|
122
122
|
const themeTokens = useThemeTokens('Modal', tokens, variant, { viewport, maxWidth })
|
|
123
123
|
const modalRef = useScrollBlocking(isOpen)
|
|
124
|
+
const modalBodyRef = React.useRef(ref)
|
|
125
|
+
const modalContentRef = React.useRef(null)
|
|
124
126
|
|
|
125
127
|
const { closeIcon: CloseIconComponent } = themeTokens
|
|
126
128
|
|
|
@@ -135,6 +137,32 @@ const Modal = React.forwardRef(
|
|
|
135
137
|
if (event.key === 'Escape') onClose()
|
|
136
138
|
}
|
|
137
139
|
|
|
140
|
+
const manageFocus = React.useCallback(
|
|
141
|
+
(event) => {
|
|
142
|
+
if (event.key === 'Tab') {
|
|
143
|
+
const focusableElements = Array.from(
|
|
144
|
+
modalBodyRef?.current?.querySelectorAll(`
|
|
145
|
+
a[href], button, textarea, input, select,
|
|
146
|
+
[tabindex]:not([tabindex="-1"]),
|
|
147
|
+
[contenteditable="true"]
|
|
148
|
+
`)
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
const firstElement = focusableElements[0]
|
|
152
|
+
const lastElement = focusableElements[focusableElements.length - 1]
|
|
153
|
+
|
|
154
|
+
if (event.shiftKey && document.activeElement === firstElement) {
|
|
155
|
+
event.preventDefault()
|
|
156
|
+
lastElement.focus()
|
|
157
|
+
} else if (!event.shiftKey && document.activeElement === lastElement) {
|
|
158
|
+
event.preventDefault()
|
|
159
|
+
firstElement.focus()
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
},
|
|
163
|
+
[modalBodyRef]
|
|
164
|
+
)
|
|
165
|
+
|
|
138
166
|
// Show the custom react node passed to `closedButton` or the default close button if `closeButton` is `undefined`.
|
|
139
167
|
// Hide the close button if `closeButton` is `null`.
|
|
140
168
|
const showCloseButton = closeButton !== null
|
|
@@ -145,22 +173,20 @@ const Modal = React.forwardRef(
|
|
|
145
173
|
|
|
146
174
|
React.useEffect(() => {
|
|
147
175
|
if (Platform.OS === 'web') {
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
if (document.activeElement === focusTrapRef.current && closeButtonRef.current) {
|
|
151
|
-
closeButtonRef.current.focus()
|
|
152
|
-
}
|
|
153
|
-
return undefined
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
// Add an event listener to manage focus in the web modal container
|
|
157
|
-
document.addEventListener('focusin', handleFocus)
|
|
176
|
+
// Add an event listener to manage keydown and focus in the web modal container
|
|
177
|
+
document.addEventListener('keydown', manageFocus)
|
|
158
178
|
|
|
159
179
|
// Clean up the event listener
|
|
160
|
-
return () => document.removeEventListener('
|
|
180
|
+
return () => document.removeEventListener('keydown', manageFocus)
|
|
161
181
|
}
|
|
162
182
|
return undefined
|
|
163
|
-
}, [])
|
|
183
|
+
}, [manageFocus])
|
|
184
|
+
|
|
185
|
+
React.useEffect(() => {
|
|
186
|
+
if (isOpen) {
|
|
187
|
+
modalContentRef?.current?.focus()
|
|
188
|
+
}
|
|
189
|
+
}, [isOpen, modalContentRef?.current?.focus])
|
|
164
190
|
|
|
165
191
|
if (!isOpen) {
|
|
166
192
|
return null
|
|
@@ -174,7 +200,7 @@ const Modal = React.forwardRef(
|
|
|
174
200
|
pointerEvents="box-none" // don't capture backdrop press events
|
|
175
201
|
>
|
|
176
202
|
<View
|
|
177
|
-
ref={
|
|
203
|
+
ref={modalBodyRef}
|
|
178
204
|
style={[staticStyles.modal, selectModalStyles(themeTokens)]}
|
|
179
205
|
onKeyUp={handleKeyUp}
|
|
180
206
|
>
|
|
@@ -230,7 +256,7 @@ const Modal = React.forwardRef(
|
|
|
230
256
|
|
|
231
257
|
if (Platform.OS === 'web') {
|
|
232
258
|
return (
|
|
233
|
-
<WebModal {...selectProps(rest)}>
|
|
259
|
+
<WebModal {...selectProps(rest)} ref={modalContentRef}>
|
|
234
260
|
{content}
|
|
235
261
|
<View accessibilityRole="button" ref={focusTrapRef} />
|
|
236
262
|
</WebModal>
|
|
@@ -60,6 +60,7 @@ const ModalContent = React.forwardRef(
|
|
|
60
60
|
borderColor,
|
|
61
61
|
gap,
|
|
62
62
|
direction,
|
|
63
|
+
footerTopWidth,
|
|
63
64
|
hasBorder
|
|
64
65
|
}) => ({
|
|
65
66
|
flexDirection: direction,
|
|
@@ -70,8 +71,8 @@ const ModalContent = React.forwardRef(
|
|
|
70
71
|
paddingLeft,
|
|
71
72
|
paddingRight,
|
|
72
73
|
paddingTop,
|
|
73
|
-
|
|
74
|
-
|
|
74
|
+
borderTopWidth: footerTopWidth > 0 ? footerTopWidth : (hasBorder && 1) || 0,
|
|
75
|
+
borderTopColor: borderColor
|
|
75
76
|
})
|
|
76
77
|
|
|
77
78
|
const headingStyles = {
|
|
@@ -155,7 +156,7 @@ const styles = StyleSheet.create({
|
|
|
155
156
|
minHeight: Platform.OS === 'web' ? '100%' : 'auto'
|
|
156
157
|
},
|
|
157
158
|
cancelButton: {
|
|
158
|
-
|
|
159
|
+
display: 'flex'
|
|
159
160
|
}
|
|
160
161
|
})
|
|
161
162
|
|
package/src/Modal/WebModal.jsx
CHANGED
|
@@ -17,7 +17,7 @@ const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, vie
|
|
|
17
17
|
const WebModal = React.forwardRef(({ children, ...rest }, ref) => {
|
|
18
18
|
return (
|
|
19
19
|
<Portal>
|
|
20
|
-
<View style={staticStyles.container} {...selectProps(rest)} ref={ref}>
|
|
20
|
+
<View style={staticStyles.container} {...selectProps(rest)} focusable={true} ref={ref}>
|
|
21
21
|
<div style={staticStyles.content} role="dialog" aria-modal={true}>
|
|
22
22
|
{children}
|
|
23
23
|
</div>
|
|
@@ -102,11 +102,11 @@ const getMediaQueryStyles = (
|
|
|
102
102
|
flexShrink: 1,
|
|
103
103
|
justifyContent: 'space-between',
|
|
104
104
|
...createMediaQueryStyles({
|
|
105
|
-
xs: {
|
|
106
|
-
md: {
|
|
107
|
-
lg: {
|
|
108
|
-
sm: {
|
|
109
|
-
xl: {
|
|
105
|
+
xs: { maxWidth: themeOptions?.contentMaxWidth?.xs || '100%' },
|
|
106
|
+
md: { maxWidth: themeOptions?.contentMaxWidth?.md || '100%' },
|
|
107
|
+
lg: { maxWidth: themeOptions?.contentMaxWidth?.lg || '100%' },
|
|
108
|
+
sm: { maxWidth: themeOptions?.contentMaxWidth?.sm || '100%' },
|
|
109
|
+
xl: { maxWidth: themeOptions?.contentMaxWidth?.xl || '100%' }
|
|
110
110
|
})
|
|
111
111
|
}
|
|
112
112
|
})
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
|
+
import PropTypes from 'prop-types'
|
|
2
3
|
import { View, Text, StyleSheet } from 'react-native'
|
|
3
4
|
|
|
4
5
|
import {
|
|
@@ -42,6 +43,7 @@ const Pagination = React.forwardRef(
|
|
|
42
43
|
sideButtonTokens,
|
|
43
44
|
LinkRouter,
|
|
44
45
|
linkRouterProps,
|
|
46
|
+
numberOfPagesBeforeEllipsis = 4,
|
|
45
47
|
...rest
|
|
46
48
|
},
|
|
47
49
|
ref
|
|
@@ -80,7 +82,8 @@ const Pagination = React.forwardRef(
|
|
|
80
82
|
shouldRenderEllipsis
|
|
81
83
|
} = usePagination({
|
|
82
84
|
items,
|
|
83
|
-
truncateAbove
|
|
85
|
+
truncateAbove,
|
|
86
|
+
numberOfPagesBeforeEllipsis
|
|
84
87
|
})
|
|
85
88
|
|
|
86
89
|
const ellipsisTextStyles = selectTextStyles(themeTokens, themeOptions)
|
|
@@ -220,7 +223,11 @@ Pagination.propTypes = {
|
|
|
220
223
|
/**
|
|
221
224
|
* Custom tokens for `PaginationSideButton`
|
|
222
225
|
*/
|
|
223
|
-
sideButtonTokens: getTokensPropType('PaginationSideButton')
|
|
226
|
+
sideButtonTokens: getTokensPropType('PaginationSideButton'),
|
|
227
|
+
/**
|
|
228
|
+
* The number of pages before the ellipsis is shown
|
|
229
|
+
*/
|
|
230
|
+
numberOfPagesBeforeEllipsis: PropTypes.number
|
|
224
231
|
}
|
|
225
232
|
|
|
226
233
|
const staticStyles = StyleSheet.create({
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
+
import { DEFAULT_PAGE_TO_SHOW_VALUE, MIN_PAGES_TO_SHOW, TRUNCATE_ABOVE_VALUE } from './constants'
|
|
1
2
|
/**
|
|
2
3
|
* Handles configurable truncating of pagination items.
|
|
3
4
|
*
|
|
4
5
|
* @param {object} props
|
|
5
6
|
* @param {React.Element[]} items
|
|
6
7
|
* @param {number} truncateAbove
|
|
8
|
+
* @param {number} numberOfPagesBeforeEllipsis
|
|
7
9
|
*/
|
|
8
|
-
function usePagination({ items, truncateAbove }) {
|
|
10
|
+
function usePagination({ items, truncateAbove, numberOfPagesBeforeEllipsis }) {
|
|
9
11
|
const activeItemIndex = Math.max(
|
|
10
12
|
items.findIndex((item) => item.props.isActive),
|
|
11
13
|
0 // default to the first item if none is marked as active
|
|
@@ -16,8 +18,17 @@ function usePagination({ items, truncateAbove }) {
|
|
|
16
18
|
return { onPress, href, hrefAttrs, variant, tokens }
|
|
17
19
|
}
|
|
18
20
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
+
let windowSize
|
|
22
|
+
|
|
23
|
+
if (numberOfPagesBeforeEllipsis >= 1 && numberOfPagesBeforeEllipsis < items.length) {
|
|
24
|
+
windowSize = numberOfPagesBeforeEllipsis
|
|
25
|
+
} else if (truncateAbove > TRUNCATE_ABOVE_VALUE) {
|
|
26
|
+
windowSize = MIN_PAGES_TO_SHOW
|
|
27
|
+
} else {
|
|
28
|
+
windowSize = DEFAULT_PAGE_TO_SHOW_VALUE
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const truncateEnabled = items.length > windowSize
|
|
21
32
|
|
|
22
33
|
const truncateWindowStart = windowSize
|
|
23
34
|
const truncateWindowEnd = items.length - 1 - windowSize
|
|
@@ -61,6 +61,10 @@ const selectBottomTextTypographyTokens = ({ bottomTextFontSize, bottomTextLineHe
|
|
|
61
61
|
lineHeight: bottomTextLineHeight
|
|
62
62
|
})
|
|
63
63
|
|
|
64
|
+
const selectContainertokens = ({ alignItemsText }) => ({
|
|
65
|
+
alignItems: alignItemsText
|
|
66
|
+
})
|
|
67
|
+
|
|
64
68
|
const PriceLockup = React.forwardRef(
|
|
65
69
|
(
|
|
66
70
|
{
|
|
@@ -106,7 +110,11 @@ const PriceLockup = React.forwardRef(
|
|
|
106
110
|
const bottomTextTypographyTokens = selectBottomTextTypographyTokens(themeTokens)
|
|
107
111
|
|
|
108
112
|
return (
|
|
109
|
-
<View
|
|
113
|
+
<View
|
|
114
|
+
style={[staticStyles.priceLockupContainer, selectContainertokens(themeTokens)]}
|
|
115
|
+
ref={ref}
|
|
116
|
+
{...selectProps(rest)}
|
|
117
|
+
>
|
|
110
118
|
{topText ? (
|
|
111
119
|
<View style={staticStyles.topText}>
|
|
112
120
|
{renderTypography(topText, topTextTypographyTokens)}
|