@telus-uds/components-base 3.19.0 → 3.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +29 -1
- package/lib/cjs/Button/ButtonDropdown.js +1 -0
- package/lib/cjs/ExpandCollapseMini/ExpandCollapseMiniControl.js +8 -21
- package/lib/cjs/Link/LinkBase.js +8 -9
- package/lib/cjs/MultiSelectFilter/MultiSelectFilter.js +8 -8
- package/lib/cjs/Responsive/ResponsiveWithMediaQueryStyleSheet.js +1 -1
- package/lib/cjs/Spacer/Spacer.js +65 -5
- package/lib/cjs/StackView/StackView.js +62 -12
- package/lib/cjs/Tabs/TabsDropdown.js +4 -5
- package/lib/cjs/utils/index.js +8 -0
- package/lib/cjs/utils/ssr-media-query/index.js +7 -0
- package/lib/cjs/utils/ssr-media-query/utils/use-all-viewport-tokens.js +53 -0
- package/lib/cjs/utils/useMediaQuerySpacing.js +121 -0
- package/lib/esm/Button/ButtonDropdown.js +1 -0
- package/lib/esm/ExpandCollapseMini/ExpandCollapseMiniControl.js +8 -21
- package/lib/esm/Link/LinkBase.js +8 -9
- package/lib/esm/MultiSelectFilter/MultiSelectFilter.js +8 -8
- package/lib/esm/Responsive/ResponsiveWithMediaQueryStyleSheet.js +1 -1
- package/lib/esm/Spacer/Spacer.js +66 -6
- package/lib/esm/StackView/StackView.js +63 -13
- package/lib/esm/Tabs/TabsDropdown.js +4 -5
- package/lib/esm/utils/index.js +1 -0
- package/lib/esm/utils/ssr-media-query/index.js +2 -1
- package/lib/esm/utils/ssr-media-query/utils/use-all-viewport-tokens.js +48 -0
- package/lib/esm/utils/useMediaQuerySpacing.js +116 -0
- package/lib/package.json +5 -5
- package/package.json +5 -5
- package/src/Button/ButtonDropdown.jsx +1 -0
- package/src/ExpandCollapseMini/ExpandCollapseMiniControl.jsx +9 -16
- package/src/Link/LinkBase.jsx +11 -9
- package/src/MultiSelectFilter/MultiSelectFilter.jsx +9 -8
- package/src/Responsive/ResponsiveWithMediaQueryStyleSheet.jsx +1 -1
- package/src/Spacer/Spacer.jsx +54 -7
- package/src/StackView/StackView.jsx +62 -9
- package/src/Tabs/TabsDropdown.jsx +10 -9
- package/src/utils/index.js +1 -0
- package/src/utils/ssr-media-query/index.js +2 -1
- package/src/utils/ssr-media-query/utils/use-all-viewport-tokens.js +32 -0
- package/src/utils/useMediaQuerySpacing.js +124 -0
|
@@ -66,35 +66,21 @@ const ExpandCollapseMiniControl = /*#__PURE__*/React.forwardRef((_ref, ref) => {
|
|
|
66
66
|
const isHovered = hover || linkHover;
|
|
67
67
|
const iconBaselineOffset = 0;
|
|
68
68
|
const hoverTranslateY = 4;
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
const
|
|
73
|
-
const iconBaseline = iconSize / hoverTranslateY; // Quarter of icon size - adjusts for icon's visual center point
|
|
74
|
-
const staticOffset = hoverTranslateY; // Fixed downward adjustment to fine-tune vertical alignment
|
|
75
|
-
const sizeCompensation = -Math.abs(iconSize - fontSize); // Compensates when icon and text sizes differ significantly
|
|
76
|
-
|
|
69
|
+
const fontBaseline = fontSize / hoverTranslateY;
|
|
70
|
+
const iconBaseline = iconSize / hoverTranslateY;
|
|
71
|
+
const staticOffset = hoverTranslateY;
|
|
72
|
+
const sizeCompensation = -Math.abs(iconSize - fontSize);
|
|
77
73
|
const baselineAlignment = fontBaseline + iconBaseline - staticOffset + sizeCompensation;
|
|
78
|
-
|
|
79
|
-
// For native platforms, use baseline alignment with optional offset
|
|
80
|
-
return {
|
|
81
|
-
iconTranslateY: baselineAlignment + iconBaselineOffset
|
|
82
|
-
};
|
|
83
|
-
}
|
|
74
|
+
const mobileAdjustment = Platform.OS !== 'web' ? -2 : 0;
|
|
84
75
|
if (isHovered) {
|
|
85
|
-
// Apply animation offset to the baseline-aligned position
|
|
86
|
-
// When expanded: move icon UP (1.3 the hover distance for clear movement)
|
|
87
|
-
// When collapsed: move icon DOWN (single hover distance)
|
|
88
76
|
const hoverMovementDistance = 1.3;
|
|
89
77
|
const animationOffset = expanded ? -(hoverTranslateY * hoverMovementDistance) : hoverTranslateY;
|
|
90
78
|
return {
|
|
91
|
-
iconTranslateY: baselineAlignment + iconBaselineOffset + animationOffset
|
|
79
|
+
iconTranslateY: baselineAlignment + iconBaselineOffset + animationOffset + mobileAdjustment
|
|
92
80
|
};
|
|
93
81
|
}
|
|
94
|
-
|
|
95
|
-
// Default state uses baseline alignment with optional offset
|
|
96
82
|
return {
|
|
97
|
-
iconTranslateY: baselineAlignment + iconBaselineOffset
|
|
83
|
+
iconTranslateY: baselineAlignment + iconBaselineOffset + mobileAdjustment
|
|
98
84
|
};
|
|
99
85
|
};
|
|
100
86
|
return /*#__PURE__*/_jsx(Link, {
|
|
@@ -105,6 +91,7 @@ const ExpandCollapseMiniControl = /*#__PURE__*/React.forwardRef((_ref, ref) => {
|
|
|
105
91
|
...linkTokens,
|
|
106
92
|
...getTokens(linkState),
|
|
107
93
|
iconSize,
|
|
94
|
+
blockFontSize: fontSize,
|
|
108
95
|
blockLineHeight: lineHeight
|
|
109
96
|
}),
|
|
110
97
|
ref: ref,
|
package/lib/esm/Link/LinkBase.js
CHANGED
|
@@ -180,7 +180,8 @@ const LinkBase = /*#__PURE__*/React.forwardRef((_ref6, ref) => {
|
|
|
180
180
|
const themeTokens = resolveLinkTokens(linkState);
|
|
181
181
|
const outerBorderStyles = selectOuterBorderStyles(themeTokens);
|
|
182
182
|
const decorationStyles = selectDecorationStyles(themeTokens);
|
|
183
|
-
|
|
183
|
+
const mobileCompensation = null;
|
|
184
|
+
return [outerBorderStyles, mobileCompensation, blockLeftStyle, decorationStyles, hasIcon && staticStyles.rowContainer];
|
|
184
185
|
},
|
|
185
186
|
children: linkState => {
|
|
186
187
|
const themeTokens = resolveLinkTokens(linkState);
|
|
@@ -193,10 +194,12 @@ const LinkBase = /*#__PURE__*/React.forwardRef((_ref6, ref) => {
|
|
|
193
194
|
const {
|
|
194
195
|
iconSpace
|
|
195
196
|
} = themeTokens;
|
|
197
|
+
const isTextOnlyLink = !IconComponent && !icon && accessibilityRole === 'link';
|
|
198
|
+
const adjustedIconSpace = Platform.OS !== 'web' && isTextOnlyLink ? 0 : iconSpace;
|
|
196
199
|
return /*#__PURE__*/_jsx(IconText, {
|
|
197
200
|
icon: IconComponent,
|
|
198
201
|
iconPosition: iconPosition,
|
|
199
|
-
space:
|
|
202
|
+
space: adjustedIconSpace,
|
|
200
203
|
iconProps: {
|
|
201
204
|
...iconProps,
|
|
202
205
|
tokens: iconTokens,
|
|
@@ -263,15 +266,11 @@ const staticStyles = StyleSheet.create({
|
|
|
263
266
|
}
|
|
264
267
|
})
|
|
265
268
|
},
|
|
266
|
-
|
|
269
|
+
outerBorderCompensation: {
|
|
267
270
|
...(Platform.OS !== 'web' && {
|
|
268
|
-
margin: 0,
|
|
269
271
|
marginHorizontal: 2,
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
...(Platform.OS === 'android' && {
|
|
273
|
-
paddingHorizontal: 2,
|
|
274
|
-
paddingTop: 2
|
|
272
|
+
paddingHorizontal: Platform.OS === 'android' ? 2 : 0,
|
|
273
|
+
paddingTop: Platform.OS === 'android' ? 2 : 0
|
|
275
274
|
})
|
|
276
275
|
}
|
|
277
276
|
});
|
|
@@ -64,7 +64,6 @@ const selectContainerStyle = (windowHeight, windowWidth) => ({
|
|
|
64
64
|
width: windowWidth
|
|
65
65
|
});
|
|
66
66
|
const TOTAL_COLUMNS = 12;
|
|
67
|
-
const MAX_ITEMS_THRESHOLD = 12;
|
|
68
67
|
const MultiSelectFilter = /*#__PURE__*/React.forwardRef((_ref3, ref) => {
|
|
69
68
|
let {
|
|
70
69
|
label,
|
|
@@ -171,12 +170,13 @@ const MultiSelectFilter = /*#__PURE__*/React.forwardRef((_ref3, ref) => {
|
|
|
171
170
|
});
|
|
172
171
|
const colSizeNotMobile = items.length > rowLimit ? 2 : 1;
|
|
173
172
|
const colSize = viewport !== 'xs' ? colSizeNotMobile : 1;
|
|
174
|
-
|
|
175
|
-
|
|
173
|
+
let rowLength = items.length;
|
|
174
|
+
if (viewport !== 'xs' && colSize === 2) {
|
|
175
|
+
rowLength = Math.ceil(items.length / 2);
|
|
176
|
+
}
|
|
176
177
|
React.useEffect(() => {
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
}, [colSize]);
|
|
178
|
+
setMaxWidth(items.length >= rowLimit);
|
|
179
|
+
}, [items.length, rowLimit]);
|
|
180
180
|
React.useEffect(() => setCheckedIds(currentValues ?? []), [currentValues]);
|
|
181
181
|
const uniqueFields = ['id', 'label'];
|
|
182
182
|
if (!containUniqueFields(items, uniqueFields)) {
|
|
@@ -423,14 +423,14 @@ const MultiSelectFilter = /*#__PURE__*/React.forwardRef((_ref3, ref) => {
|
|
|
423
423
|
dismissWhenPressedOutside: dismissWhenPressedOutside,
|
|
424
424
|
onClose: onClose,
|
|
425
425
|
overlaidPosition: overlaidPosition,
|
|
426
|
-
maxHeight: items.length
|
|
426
|
+
maxHeight: items.length >= rowLimit ? true : maxHeight,
|
|
427
427
|
maxHeightSize: maxHeightSize,
|
|
428
428
|
maxWidthSize: maxWidthSize,
|
|
429
429
|
minHeight: minHeight,
|
|
430
430
|
minWidth: minWidth,
|
|
431
431
|
tokens: {
|
|
432
432
|
...tokens,
|
|
433
|
-
maxWidth: items.length
|
|
433
|
+
maxWidth: items.length >= rowLimit ? true : maxWidth,
|
|
434
434
|
borderColor: containerBorderColor
|
|
435
435
|
},
|
|
436
436
|
copy: copy,
|
|
@@ -61,7 +61,7 @@ ResponsiveWithMediaQueryStyleSheet.propTypes = {
|
|
|
61
61
|
/**
|
|
62
62
|
* To hide children of `Responsive` if the current viewport is larger than `max`
|
|
63
63
|
*/
|
|
64
|
-
max: PropTypes.oneOf(['sm', 'md', 'lg', 'xl']),
|
|
64
|
+
max: PropTypes.oneOf(['xs', 'sm', 'md', 'lg', 'xl']),
|
|
65
65
|
inheritedStyles: PropTypes.arrayOf(PropTypes.string),
|
|
66
66
|
children: PropTypes.node.isRequired
|
|
67
67
|
};
|
package/lib/esm/Spacer/Spacer.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
|
-
import StyleSheet from "react-native-web/dist/exports/StyleSheet";
|
|
4
3
|
import View from "react-native-web/dist/exports/View";
|
|
5
|
-
import
|
|
4
|
+
import StyleSheet from "react-native-web/dist/exports/StyleSheet";
|
|
5
|
+
import { a11yProps, selectSystemProps, spacingProps, useSpacingScale, viewProps, StyleSheet as StyleSheetUtils, createMediaQueryStyles } from '../utils';
|
|
6
|
+
import useMediaQuerySpacing from '../utils/useMediaQuerySpacing';
|
|
7
|
+
import useTheme from '../ThemeProvider/useTheme';
|
|
6
8
|
|
|
7
9
|
/**
|
|
8
10
|
* @typedef {import('../utils/props/spacingProps.js').SpacingValue} SpacingValue
|
|
@@ -60,13 +62,66 @@ const Spacer = /*#__PURE__*/React.forwardRef((_ref, ref) => {
|
|
|
60
62
|
let {
|
|
61
63
|
space = 1,
|
|
62
64
|
direction = 'column',
|
|
65
|
+
dataSet,
|
|
63
66
|
...rest
|
|
64
67
|
} = _ref;
|
|
65
|
-
const
|
|
66
|
-
|
|
68
|
+
const {
|
|
69
|
+
themeOptions: {
|
|
70
|
+
enableMediaQueryStyleSheet
|
|
71
|
+
}
|
|
72
|
+
} = useTheme();
|
|
73
|
+
const {
|
|
74
|
+
sizeByViewport
|
|
75
|
+
} = useMediaQuerySpacing(space);
|
|
76
|
+
const fallbackSize = useSpacingScale(space);
|
|
77
|
+
const sizeStyle = selectSizeStyle(fallbackSize, direction);
|
|
78
|
+
let spacerStyles;
|
|
79
|
+
let dataSetValue = dataSet;
|
|
80
|
+
if (enableMediaQueryStyleSheet) {
|
|
81
|
+
const sizeKey = direction === 'row' ? 'width' : 'height';
|
|
82
|
+
const stylesByViewport = {
|
|
83
|
+
xs: {
|
|
84
|
+
[sizeKey]: sizeByViewport.xs,
|
|
85
|
+
...staticStyles.stretch
|
|
86
|
+
},
|
|
87
|
+
sm: {
|
|
88
|
+
[sizeKey]: sizeByViewport.sm,
|
|
89
|
+
...staticStyles.stretch
|
|
90
|
+
},
|
|
91
|
+
md: {
|
|
92
|
+
[sizeKey]: sizeByViewport.md,
|
|
93
|
+
...staticStyles.stretch
|
|
94
|
+
},
|
|
95
|
+
lg: {
|
|
96
|
+
[sizeKey]: sizeByViewport.lg,
|
|
97
|
+
...staticStyles.stretch
|
|
98
|
+
},
|
|
99
|
+
xl: {
|
|
100
|
+
[sizeKey]: sizeByViewport.xl,
|
|
101
|
+
...staticStyles.stretch
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
const mediaQueryStyles = createMediaQueryStyles(stylesByViewport);
|
|
105
|
+
const {
|
|
106
|
+
ids,
|
|
107
|
+
styles
|
|
108
|
+
} = StyleSheetUtils.create({
|
|
109
|
+
spacer: {
|
|
110
|
+
...mediaQueryStyles
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
spacerStyles = styles.spacer;
|
|
114
|
+
dataSetValue = {
|
|
115
|
+
media: ids.spacer,
|
|
116
|
+
...dataSet
|
|
117
|
+
};
|
|
118
|
+
} else {
|
|
119
|
+
spacerStyles = [staticStyles.stretch, sizeStyle];
|
|
120
|
+
}
|
|
67
121
|
return /*#__PURE__*/_jsx(View, {
|
|
68
122
|
ref: ref,
|
|
69
|
-
style:
|
|
123
|
+
style: spacerStyles,
|
|
124
|
+
dataSet: dataSetValue,
|
|
70
125
|
...selectProps(rest)
|
|
71
126
|
});
|
|
72
127
|
});
|
|
@@ -85,7 +140,12 @@ Spacer.propTypes = {
|
|
|
85
140
|
* - `'column'` (default) applies space vertically; has a fixed height and not width.
|
|
86
141
|
* - `'row'` applies space horizontally; has a fixed width and not height.
|
|
87
142
|
*/
|
|
88
|
-
direction: PropTypes.oneOf(['column', 'row'])
|
|
143
|
+
direction: PropTypes.oneOf(['column', 'row']),
|
|
144
|
+
/**
|
|
145
|
+
* Data attributes to be applied to the element. When media query stylesheet is enabled,
|
|
146
|
+
* this will include media query IDs for responsive styling.
|
|
147
|
+
*/
|
|
148
|
+
dataSet: PropTypes.object
|
|
89
149
|
};
|
|
90
150
|
const staticStyles = StyleSheet.create({
|
|
91
151
|
stretch: {
|
|
@@ -2,9 +2,8 @@ import React from 'react';
|
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
3
|
import View from "react-native-web/dist/exports/View";
|
|
4
4
|
import Divider from '../Divider';
|
|
5
|
-
import { a11yProps, getA11yPropsFromHtmlTag, getTokensPropType, layoutTags, responsiveProps, selectSystemProps, spacingProps, useResponsiveProp, variantProp, viewProps } from '../utils';
|
|
6
|
-
import
|
|
7
|
-
import { useViewport } from '../ViewportProvider';
|
|
5
|
+
import { a11yProps, getA11yPropsFromHtmlTag, getTokensPropType, layoutTags, responsiveProps, selectSystemProps, spacingProps, useResponsiveProp, variantProp, viewProps, StyleSheet as StyleSheetUtils, createMediaQueryStyles, useAllViewportTokens } from '../utils';
|
|
6
|
+
import useTheme from '../ThemeProvider/useTheme';
|
|
8
7
|
import getStackedContent from './getStackedContent';
|
|
9
8
|
import { staticStyles, selectFlexStyles } from './common';
|
|
10
9
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
@@ -62,10 +61,15 @@ const StackView = /*#__PURE__*/React.forwardRef((_ref, ref) => {
|
|
|
62
61
|
tokens,
|
|
63
62
|
tag,
|
|
64
63
|
accessibilityRole,
|
|
64
|
+
dataSet,
|
|
65
65
|
...rest
|
|
66
66
|
} = _ref;
|
|
67
|
-
const viewport = useViewport();
|
|
68
67
|
const direction = useResponsiveProp(directionProp, 'column');
|
|
68
|
+
const {
|
|
69
|
+
themeOptions: {
|
|
70
|
+
enableMediaQueryStyleSheet
|
|
71
|
+
}
|
|
72
|
+
} = useTheme();
|
|
69
73
|
const selectedProps = selectProps({
|
|
70
74
|
accessibilityRole,
|
|
71
75
|
...getA11yPropsFromHtmlTag(tag, accessibilityRole),
|
|
@@ -76,17 +80,58 @@ const StackView = /*#__PURE__*/React.forwardRef((_ref, ref) => {
|
|
|
76
80
|
divider,
|
|
77
81
|
space
|
|
78
82
|
});
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
83
|
+
const allTokens = useAllViewportTokens('StackView', tokens, variant);
|
|
84
|
+
let stackViewStyles;
|
|
85
|
+
let dataSetValue = dataSet;
|
|
86
|
+
if (enableMediaQueryStyleSheet) {
|
|
87
|
+
const stylesByViewport = {
|
|
88
|
+
xs: {
|
|
89
|
+
...selectFlexStyles(allTokens.xs),
|
|
90
|
+
width: allTokens.xs.width
|
|
91
|
+
},
|
|
92
|
+
sm: {
|
|
93
|
+
...selectFlexStyles(allTokens.sm),
|
|
94
|
+
width: allTokens.sm.width
|
|
95
|
+
},
|
|
96
|
+
md: {
|
|
97
|
+
...selectFlexStyles(allTokens.md),
|
|
98
|
+
width: allTokens.md.width
|
|
99
|
+
},
|
|
100
|
+
lg: {
|
|
101
|
+
...selectFlexStyles(allTokens.lg),
|
|
102
|
+
width: allTokens.lg.width
|
|
103
|
+
},
|
|
104
|
+
xl: {
|
|
105
|
+
...selectFlexStyles(allTokens.xl),
|
|
106
|
+
width: allTokens.xl.width
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
const mediaQueryStyles = createMediaQueryStyles(stylesByViewport);
|
|
110
|
+
const {
|
|
111
|
+
ids,
|
|
112
|
+
styles
|
|
113
|
+
} = StyleSheetUtils.create({
|
|
114
|
+
stackView: {
|
|
115
|
+
...mediaQueryStyles
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
stackViewStyles = [staticStyles[direction], styles.stackView];
|
|
119
|
+
dataSetValue = {
|
|
120
|
+
media: ids.stackView,
|
|
121
|
+
...dataSet
|
|
122
|
+
};
|
|
123
|
+
} else {
|
|
124
|
+
const flexStyles = selectFlexStyles(allTokens.current);
|
|
125
|
+
const size = {
|
|
126
|
+
width: allTokens.current.width
|
|
127
|
+
};
|
|
128
|
+
stackViewStyles = [flexStyles, staticStyles[direction], size];
|
|
129
|
+
}
|
|
86
130
|
return /*#__PURE__*/_jsx(View, {
|
|
87
131
|
ref: ref,
|
|
88
132
|
...selectedProps,
|
|
89
|
-
style:
|
|
133
|
+
style: stackViewStyles,
|
|
134
|
+
dataSet: dataSetValue,
|
|
90
135
|
children: content
|
|
91
136
|
});
|
|
92
137
|
});
|
|
@@ -121,6 +166,11 @@ StackView.propTypes = {
|
|
|
121
166
|
* A StackView may take any children, but will have no effect if it is only passed one child or is passed children
|
|
122
167
|
* wrapped in a component. If necessary, children may be wrapped in one React Fragment.
|
|
123
168
|
*/
|
|
124
|
-
children: PropTypes.node
|
|
169
|
+
children: PropTypes.node,
|
|
170
|
+
/**
|
|
171
|
+
* Data attributes to be applied to the element. When media query stylesheet is enabled,
|
|
172
|
+
* this will include media query IDs for responsive styling.
|
|
173
|
+
*/
|
|
174
|
+
dataSet: PropTypes.object
|
|
125
175
|
};
|
|
126
176
|
export default StackView;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
|
+
import Platform from "react-native-web/dist/exports/Platform";
|
|
3
4
|
import Pressable from "react-native-web/dist/exports/Pressable";
|
|
4
5
|
import StyleSheet from "react-native-web/dist/exports/StyleSheet";
|
|
5
6
|
import Text from "react-native-web/dist/exports/Text";
|
|
@@ -226,20 +227,18 @@ const styles = StyleSheet.create({
|
|
|
226
227
|
position: 'relative',
|
|
227
228
|
width: '100%'
|
|
228
229
|
},
|
|
229
|
-
pressable: {
|
|
230
|
+
pressable: Platform.OS === 'web' ? {
|
|
230
231
|
outlineWidth: 0,
|
|
231
232
|
outlineStyle: 'none',
|
|
232
233
|
outlineColor: 'transparent'
|
|
233
|
-
},
|
|
234
|
+
} : {},
|
|
234
235
|
buttonContent: {
|
|
235
236
|
display: 'flex',
|
|
236
237
|
flexDirection: 'row',
|
|
237
238
|
alignItems: 'center',
|
|
238
239
|
justifyContent: 'space-between',
|
|
239
240
|
width: '100%',
|
|
240
|
-
minHeight: 44
|
|
241
|
-
outline: 'none',
|
|
242
|
-
boxSizing: 'border-box'
|
|
241
|
+
minHeight: 44
|
|
243
242
|
}
|
|
244
243
|
});
|
|
245
244
|
export default TabsDropdown;
|
package/lib/esm/utils/index.js
CHANGED
|
@@ -9,6 +9,7 @@ export { default as info } from './info';
|
|
|
9
9
|
export { default as useCopy } from './useCopy';
|
|
10
10
|
export { default as useHash } from './useHash';
|
|
11
11
|
export { default as useSpacingScale } from './useSpacingScale';
|
|
12
|
+
export { default as useMediaQuerySpacing } from './useMediaQuerySpacing';
|
|
12
13
|
export { default as useResponsiveProp } from './useResponsiveProp';
|
|
13
14
|
export { default as useOverlaidPosition } from './useOverlaidPosition';
|
|
14
15
|
export { default as useSafeLayoutEffect } from './useSafeLayoutEffect';
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import createStyleSheet from './create-stylesheet';
|
|
2
2
|
import createMediaQueryStyles from './utils/create-media-query-styles';
|
|
3
|
+
import useAllViewportTokens from './utils/use-all-viewport-tokens';
|
|
3
4
|
const StyleSheet = {
|
|
4
5
|
create: createStyleSheet
|
|
5
6
|
};
|
|
6
|
-
export { StyleSheet, createMediaQueryStyles };
|
|
7
|
+
export { StyleSheet, createMediaQueryStyles, useAllViewportTokens };
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { useThemeTokens } from '../../../ThemeProvider';
|
|
2
|
+
import { useViewport } from '../../../ViewportProvider';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Hook to get theme tokens for all viewports at once.
|
|
6
|
+
* This is useful for components that need to support React Native Media Queries (RNMQ).
|
|
7
|
+
*
|
|
8
|
+
* All hooks are called unconditionally to comply with React's Rules of Hooks.
|
|
9
|
+
*
|
|
10
|
+
* @param {string} componentName - The name of the component to get tokens for
|
|
11
|
+
* @param {object|function} tokens - Custom tokens or token function
|
|
12
|
+
* @param {object} variant - Variant configuration
|
|
13
|
+
* @returns {object} Object with tokens for each viewport (xs, sm, md, lg, xl, current)
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* const allTokens = useAllViewportTokens('StackView', tokens, variant)
|
|
17
|
+
* // Returns: { xs: {...}, sm: {...}, md: {...}, lg: {...}, xl: {...}, current: {...} }
|
|
18
|
+
*/
|
|
19
|
+
const useAllViewportTokens = (componentName, tokens, variant) => {
|
|
20
|
+
const viewport = useViewport();
|
|
21
|
+
const xs = useThemeTokens(componentName, tokens, variant, {
|
|
22
|
+
viewport: 'xs'
|
|
23
|
+
});
|
|
24
|
+
const sm = useThemeTokens(componentName, tokens, variant, {
|
|
25
|
+
viewport: 'sm'
|
|
26
|
+
});
|
|
27
|
+
const md = useThemeTokens(componentName, tokens, variant, {
|
|
28
|
+
viewport: 'md'
|
|
29
|
+
});
|
|
30
|
+
const lg = useThemeTokens(componentName, tokens, variant, {
|
|
31
|
+
viewport: 'lg'
|
|
32
|
+
});
|
|
33
|
+
const xl = useThemeTokens(componentName, tokens, variant, {
|
|
34
|
+
viewport: 'xl'
|
|
35
|
+
});
|
|
36
|
+
const current = useThemeTokens(componentName, tokens, variant, {
|
|
37
|
+
viewport
|
|
38
|
+
});
|
|
39
|
+
return {
|
|
40
|
+
xs,
|
|
41
|
+
sm,
|
|
42
|
+
md,
|
|
43
|
+
lg,
|
|
44
|
+
xl,
|
|
45
|
+
current
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
export default useAllViewportTokens;
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { useThemeTokens } from '../ThemeProvider';
|
|
2
|
+
import { resolveResponsiveProp } from './useResponsiveProp';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @typedef {import('@telus-uds/system-constants/viewports').Viewport} Viewport
|
|
6
|
+
* @typedef {import('./props/spacingProps.js').SpacingValue} SpacingValue
|
|
7
|
+
* @typedef {import('./props/spacingProps.js').SpacingIndex} SpacingIndex
|
|
8
|
+
* @typedef {import('./props/spacingProps.js').SpacingObject} SpacingObject
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* A utility hook that simplifies implementing media query-based responsive spacing.
|
|
13
|
+
*
|
|
14
|
+
* This hook handles the complexity of:
|
|
15
|
+
* - Detecting if a space value is responsive (has viewport keys)
|
|
16
|
+
* - Fetching theme tokens for each viewport
|
|
17
|
+
* - Resolving the correct space index for each viewport
|
|
18
|
+
* - Extracting actual pixel values from theme tokens
|
|
19
|
+
*
|
|
20
|
+
* ## Usage
|
|
21
|
+
*
|
|
22
|
+
* ```jsx
|
|
23
|
+
* const { sizeByViewport } = useMediaQuerySpacing(space, 'spacingScale')
|
|
24
|
+
*
|
|
25
|
+
* // Use sizeByViewport to create media query styles
|
|
26
|
+
* const stylesByViewport = {
|
|
27
|
+
* xs: { padding: sizeByViewport.xs },
|
|
28
|
+
* sm: { padding: sizeByViewport.sm },
|
|
29
|
+
* md: { padding: sizeByViewport.md },
|
|
30
|
+
* lg: { padding: sizeByViewport.lg },
|
|
31
|
+
* xl: { padding: sizeByViewport.xl }
|
|
32
|
+
* }
|
|
33
|
+
* const mediaQueryStyles = createMediaQueryStyles(stylesByViewport)
|
|
34
|
+
* ```
|
|
35
|
+
*
|
|
36
|
+
* ## Parameters
|
|
37
|
+
*
|
|
38
|
+
* @param {SpacingValue} spaceValue - A spacing value (number or responsive object with viewport keys)
|
|
39
|
+
* @param {string} tokenKey - The theme token key to use (e.g., 'spacingScale', 'Typography')
|
|
40
|
+
* @param {object} [tokens={}] - Additional tokens to pass to useThemeTokens
|
|
41
|
+
* @param {object} [variant={}] - Variant to pass to useThemeTokens
|
|
42
|
+
*
|
|
43
|
+
* ## Returns
|
|
44
|
+
*
|
|
45
|
+
* @returns {{
|
|
46
|
+
* spaceIndexByViewport: { xs: number, sm: number, md: number, lg: number, xl: number },
|
|
47
|
+
* sizeByViewport: { xs: number, sm: number, md: number, lg: number, xl: number },
|
|
48
|
+
* tokensByViewport: { xs: object, sm: object, md: object, lg: object, xl: object }
|
|
49
|
+
* }}
|
|
50
|
+
*
|
|
51
|
+
* - `spaceIndexByViewport`: The resolved space index for each viewport
|
|
52
|
+
* - `sizeByViewport`: The actual pixel/number values for each viewport
|
|
53
|
+
* - `tokensByViewport`: The full theme tokens for each viewport (for advanced use cases)
|
|
54
|
+
*/
|
|
55
|
+
const useMediaQuerySpacing = function (spaceValue) {
|
|
56
|
+
let tokenKey = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'spacingScale';
|
|
57
|
+
let tokens = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
58
|
+
let variant = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
|
|
59
|
+
const isResponsive = typeof spaceValue === 'object' && spaceValue !== null && !spaceValue.space && !spaceValue.options;
|
|
60
|
+
const getSpaceIndex = viewport => {
|
|
61
|
+
if (isResponsive) {
|
|
62
|
+
return resolveResponsiveProp(spaceValue, viewport);
|
|
63
|
+
}
|
|
64
|
+
if (typeof spaceValue === 'number') {
|
|
65
|
+
return spaceValue;
|
|
66
|
+
}
|
|
67
|
+
return spaceValue?.space ?? 1;
|
|
68
|
+
};
|
|
69
|
+
const spaceIndexByViewport = {
|
|
70
|
+
xs: getSpaceIndex('xs'),
|
|
71
|
+
sm: getSpaceIndex('sm'),
|
|
72
|
+
md: getSpaceIndex('md'),
|
|
73
|
+
lg: getSpaceIndex('lg'),
|
|
74
|
+
xl: getSpaceIndex('xl')
|
|
75
|
+
};
|
|
76
|
+
const tokensXs = useThemeTokens(tokenKey, tokens, variant, {
|
|
77
|
+
space: spaceIndexByViewport.xs,
|
|
78
|
+
viewport: 'xs'
|
|
79
|
+
});
|
|
80
|
+
const tokensSm = useThemeTokens(tokenKey, tokens, variant, {
|
|
81
|
+
space: spaceIndexByViewport.sm,
|
|
82
|
+
viewport: 'sm'
|
|
83
|
+
});
|
|
84
|
+
const tokensMd = useThemeTokens(tokenKey, tokens, variant, {
|
|
85
|
+
space: spaceIndexByViewport.md,
|
|
86
|
+
viewport: 'md'
|
|
87
|
+
});
|
|
88
|
+
const tokensLg = useThemeTokens(tokenKey, tokens, variant, {
|
|
89
|
+
space: spaceIndexByViewport.lg,
|
|
90
|
+
viewport: 'lg'
|
|
91
|
+
});
|
|
92
|
+
const tokensXl = useThemeTokens(tokenKey, tokens, variant, {
|
|
93
|
+
space: spaceIndexByViewport.xl,
|
|
94
|
+
viewport: 'xl'
|
|
95
|
+
});
|
|
96
|
+
const sizeByViewport = {
|
|
97
|
+
xs: tokensXs.size ?? 0,
|
|
98
|
+
sm: tokensSm.size ?? 0,
|
|
99
|
+
md: tokensMd.size ?? 0,
|
|
100
|
+
lg: tokensLg.size ?? 0,
|
|
101
|
+
xl: tokensXl.size ?? 0
|
|
102
|
+
};
|
|
103
|
+
const tokensByViewport = {
|
|
104
|
+
xs: tokensXs,
|
|
105
|
+
sm: tokensSm,
|
|
106
|
+
md: tokensMd,
|
|
107
|
+
lg: tokensLg,
|
|
108
|
+
xl: tokensXl
|
|
109
|
+
};
|
|
110
|
+
return {
|
|
111
|
+
spaceIndexByViewport,
|
|
112
|
+
sizeByViewport,
|
|
113
|
+
tokensByViewport
|
|
114
|
+
};
|
|
115
|
+
};
|
|
116
|
+
export default useMediaQuerySpacing;
|
package/lib/package.json
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"@gorhom/portal": "^1.0.14",
|
|
13
13
|
"@react-native-picker/picker": "^2.9.0",
|
|
14
14
|
"@telus-uds/system-constants": "^3.0.0",
|
|
15
|
-
"@telus-uds/system-theme-tokens": "^4.15.
|
|
15
|
+
"@telus-uds/system-theme-tokens": "^4.15.1",
|
|
16
16
|
"airbnb-prop-types": "^2.16.0",
|
|
17
17
|
"css-mediaquery": "^0.1.2",
|
|
18
18
|
"expo-document-picker": "^13.0.1",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"@testing-library/react": "^13.3.0",
|
|
35
35
|
"@testing-library/react-hooks": "~7.0.1",
|
|
36
36
|
"@testing-library/react-native": "11.0.0",
|
|
37
|
-
"react-test-renderer": "
|
|
37
|
+
"react-test-renderer": "^18.0.0",
|
|
38
38
|
"webpack": "5.x"
|
|
39
39
|
},
|
|
40
40
|
"exports": {
|
|
@@ -59,8 +59,8 @@
|
|
|
59
59
|
"react": ">=18.2.0 <19.0.0",
|
|
60
60
|
"react-dom": ">=18.2.0 <19.0.0",
|
|
61
61
|
"react-native": "^0.74.5",
|
|
62
|
-
"react-native-
|
|
63
|
-
"react-native-
|
|
62
|
+
"react-native-svg": "15.7.1",
|
|
63
|
+
"react-native-web": "^0.19.10"
|
|
64
64
|
},
|
|
65
65
|
"react-native": "src/index.js",
|
|
66
66
|
"repository": {
|
|
@@ -84,6 +84,6 @@
|
|
|
84
84
|
"standard-engine": {
|
|
85
85
|
"skip": true
|
|
86
86
|
},
|
|
87
|
-
"version": "3.
|
|
87
|
+
"version": "3.21.0",
|
|
88
88
|
"types": "types/index.d.ts"
|
|
89
89
|
}
|
package/package.json
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"@gorhom/portal": "^1.0.14",
|
|
13
13
|
"@react-native-picker/picker": "^2.9.0",
|
|
14
14
|
"@telus-uds/system-constants": "^3.0.0",
|
|
15
|
-
"@telus-uds/system-theme-tokens": "^4.15.
|
|
15
|
+
"@telus-uds/system-theme-tokens": "^4.15.1",
|
|
16
16
|
"airbnb-prop-types": "^2.16.0",
|
|
17
17
|
"css-mediaquery": "^0.1.2",
|
|
18
18
|
"expo-document-picker": "^13.0.1",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"@testing-library/react": "^13.3.0",
|
|
35
35
|
"@testing-library/react-hooks": "~7.0.1",
|
|
36
36
|
"@testing-library/react-native": "11.0.0",
|
|
37
|
-
"react-test-renderer": "
|
|
37
|
+
"react-test-renderer": "^18.0.0",
|
|
38
38
|
"webpack": "5.x"
|
|
39
39
|
},
|
|
40
40
|
"exports": {
|
|
@@ -59,8 +59,8 @@
|
|
|
59
59
|
"react": ">=18.2.0 <19.0.0",
|
|
60
60
|
"react-dom": ">=18.2.0 <19.0.0",
|
|
61
61
|
"react-native": "^0.74.5",
|
|
62
|
-
"react-native-
|
|
63
|
-
"react-native-
|
|
62
|
+
"react-native-svg": "15.7.1",
|
|
63
|
+
"react-native-web": "^0.19.10"
|
|
64
64
|
},
|
|
65
65
|
"react-native": "src/index.js",
|
|
66
66
|
"repository": {
|
|
@@ -84,6 +84,6 @@
|
|
|
84
84
|
"standard-engine": {
|
|
85
85
|
"skip": true
|
|
86
86
|
},
|
|
87
|
-
"version": "3.
|
|
87
|
+
"version": "3.21.0",
|
|
88
88
|
"types": "types/index.d.ts"
|
|
89
89
|
}
|
|
@@ -56,6 +56,7 @@ const selectDescriptionTextStyles = (tokens) => ({
|
|
|
56
56
|
fontName: tokens?.descriptionFontName,
|
|
57
57
|
fontSize: tokens?.descriptionFontSize,
|
|
58
58
|
fontWeight: tokens?.descriptionFontWeight,
|
|
59
|
+
lineHeight: tokens?.descriptionLineHeight,
|
|
59
60
|
fontColor: tokens?.color
|
|
60
61
|
}),
|
|
61
62
|
paddingBottom: tokens?.descriptionTextPaddingBottom
|