@telus-uds/components-base 1.85.1 → 1.87.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 +34 -2
- package/lib/ActionCard/ActionCard.js +350 -0
- package/lib/ActionCard/index.js +10 -0
- package/lib/Card/Card.js +3 -3
- package/lib/Card/PressableCardBase.js +1 -1
- package/lib/Checkbox/Checkbox.js +4 -0
- package/lib/Link/TextButton.js +17 -7
- package/lib/List/List.js +9 -2
- package/lib/List/ListItemContent.js +3 -2
- package/lib/Modal/ModalContent.js +6 -8
- package/lib/Modal/WebModal.js +2 -1
- package/lib/Notification/Notification.js +20 -15
- package/lib/Radio/Radio.js +4 -0
- package/lib/Select/Picker.js +4 -0
- package/lib/Select/Select.js +1 -1
- package/lib/Tabs/Tabs.js +4 -1
- package/lib/Tabs/TabsItem.js +7 -1
- package/lib/index.js +8 -0
- package/lib/utils/animation/useVerticalExpandAnimation.js +3 -3
- package/lib/utils/props/tokens.js +2 -2
- package/lib-module/ActionCard/ActionCard.js +343 -0
- package/lib-module/ActionCard/index.js +2 -0
- package/lib-module/Card/Card.js +4 -4
- package/lib-module/Card/PressableCardBase.js +1 -1
- package/lib-module/Checkbox/Checkbox.js +4 -0
- package/lib-module/Link/TextButton.js +17 -7
- package/lib-module/List/List.js +9 -2
- package/lib-module/List/ListItemContent.js +3 -2
- package/lib-module/Modal/ModalContent.js +6 -8
- package/lib-module/Modal/WebModal.js +2 -1
- package/lib-module/Notification/Notification.js +20 -15
- package/lib-module/Radio/Radio.js +4 -0
- package/lib-module/Select/Picker.js +5 -1
- package/lib-module/Select/Select.js +2 -2
- package/lib-module/Tabs/Tabs.js +4 -1
- package/lib-module/Tabs/TabsItem.js +7 -1
- package/lib-module/index.js +1 -0
- package/lib-module/utils/animation/useVerticalExpandAnimation.js +3 -3
- package/lib-module/utils/props/tokens.js +2 -2
- package/package.json +2 -2
- package/src/ActionCard/ActionCard.jsx +306 -0
- package/src/ActionCard/index.js +3 -0
- package/src/Card/Card.jsx +6 -4
- package/src/Card/PressableCardBase.jsx +1 -1
- package/src/Checkbox/Checkbox.jsx +3 -1
- package/src/Link/TextButton.jsx +17 -9
- package/src/List/List.jsx +7 -2
- package/src/List/ListItemContent.jsx +2 -2
- package/src/Modal/ModalContent.jsx +3 -5
- package/src/Modal/WebModal.jsx +2 -1
- package/src/Notification/Notification.jsx +36 -16
- package/src/Radio/Radio.jsx +3 -1
- package/src/Select/Picker.jsx +6 -1
- package/src/Select/Select.jsx +4 -2
- package/src/Tabs/Tabs.jsx +4 -1
- package/src/Tabs/TabsItem.jsx +5 -1
- package/src/index.js +1 -0
- package/src/utils/animation/useVerticalExpandAnimation.js +3 -3
- package/src/utils/props/tokens.js +4 -2
|
@@ -60,13 +60,17 @@ const selectDismissButtonContainerStyles = _ref4 => {
|
|
|
60
60
|
} = _ref4;
|
|
61
61
|
return {
|
|
62
62
|
paddingLeft: dismissButtonGap,
|
|
63
|
-
placeContent: '
|
|
63
|
+
placeContent: 'start'
|
|
64
64
|
};
|
|
65
65
|
};
|
|
66
|
-
const selectContentContainerStyle = maxWidth => ({
|
|
67
|
-
maxWidth: maxWidth
|
|
66
|
+
const selectContentContainerStyle = (themeTokens, maxWidth, viewport, system) => ({
|
|
67
|
+
maxWidth: viewport === 'xl' && system === true ? maxWidth : 'auto',
|
|
68
|
+
minWidth: viewport === 'xl' && system === true ? maxWidth : 'auto',
|
|
69
|
+
paddingRight: themeTokens === null || themeTokens === void 0 ? void 0 : themeTokens.containerPaddingRight,
|
|
70
|
+
paddingLeft: themeTokens === null || themeTokens === void 0 ? void 0 : themeTokens.containerPaddingLeft
|
|
68
71
|
});
|
|
69
|
-
const getMediaQueryStyles = (themeTokens, themeOptions,
|
|
72
|
+
const getMediaQueryStyles = (themeTokens, themeOptions, mediaIdsRef, dismissible, viewport, system) => {
|
|
73
|
+
var _themeOptions$content, _themeOptions$content2, _themeOptions$content3, _themeOptions$content4, _themeOptions$content5;
|
|
70
74
|
const transformedSelectContainerStyles = Object.entries(themeTokens).reduce((acc, _ref5) => {
|
|
71
75
|
let [vp, viewportTokens] = _ref5;
|
|
72
76
|
acc[vp] = selectContainerStyles({
|
|
@@ -80,7 +84,7 @@ const getMediaQueryStyles = (themeTokens, themeOptions, viewport, mediaIdsRef, d
|
|
|
80
84
|
styles: containerStyles
|
|
81
85
|
} = StyleSheet.create({
|
|
82
86
|
container: {
|
|
83
|
-
flexDirection: 'row',
|
|
87
|
+
flexDirection: system === true && viewport === 'xl' ? 'row' : 'inherit',
|
|
84
88
|
...selectContainerMediaQueryStyles
|
|
85
89
|
}
|
|
86
90
|
});
|
|
@@ -94,19 +98,19 @@ const getMediaQueryStyles = (themeTokens, themeOptions, viewport, mediaIdsRef, d
|
|
|
94
98
|
justifyContent: 'space-between',
|
|
95
99
|
...createMediaQueryStyles({
|
|
96
100
|
xs: {
|
|
97
|
-
width: (themeOptions === null || themeOptions === void 0 ? void 0 : themeOptions.contentMaxWidth.xs) || '100%'
|
|
101
|
+
width: (themeOptions === null || themeOptions === void 0 ? void 0 : (_themeOptions$content = themeOptions.contentMaxWidth) === null || _themeOptions$content === void 0 ? void 0 : _themeOptions$content.xs) || '100%'
|
|
98
102
|
},
|
|
99
103
|
md: {
|
|
100
|
-
width: (themeOptions === null || themeOptions === void 0 ? void 0 : themeOptions.contentMaxWidth.md) || '100%'
|
|
104
|
+
width: (themeOptions === null || themeOptions === void 0 ? void 0 : (_themeOptions$content2 = themeOptions.contentMaxWidth) === null || _themeOptions$content2 === void 0 ? void 0 : _themeOptions$content2.md) || '100%'
|
|
101
105
|
},
|
|
102
106
|
lg: {
|
|
103
|
-
width: (themeOptions === null || themeOptions === void 0 ? void 0 : themeOptions.contentMaxWidth.lg) || '100%'
|
|
107
|
+
width: (themeOptions === null || themeOptions === void 0 ? void 0 : (_themeOptions$content3 = themeOptions.contentMaxWidth) === null || _themeOptions$content3 === void 0 ? void 0 : _themeOptions$content3.lg) || '100%'
|
|
104
108
|
},
|
|
105
109
|
sm: {
|
|
106
|
-
width: (themeOptions === null || themeOptions === void 0 ? void 0 : themeOptions.contentMaxWidth.sm) || '100%'
|
|
110
|
+
width: (themeOptions === null || themeOptions === void 0 ? void 0 : (_themeOptions$content4 = themeOptions.contentMaxWidth) === null || _themeOptions$content4 === void 0 ? void 0 : _themeOptions$content4.sm) || '100%'
|
|
107
111
|
},
|
|
108
112
|
xl: {
|
|
109
|
-
width: (themeOptions === null || themeOptions === void 0 ? void 0 : themeOptions.contentMaxWidth.xl) || '100%'
|
|
113
|
+
width: (themeOptions === null || themeOptions === void 0 ? void 0 : (_themeOptions$content5 = themeOptions.contentMaxWidth) === null || _themeOptions$content5 === void 0 ? void 0 : _themeOptions$content5.xl) || '100%'
|
|
110
114
|
}
|
|
111
115
|
})
|
|
112
116
|
}
|
|
@@ -169,19 +173,20 @@ const getMediaQueryStyles = (themeTokens, themeOptions, viewport, mediaIdsRef, d
|
|
|
169
173
|
selectDismissIconPropsStyles
|
|
170
174
|
};
|
|
171
175
|
};
|
|
172
|
-
const getDefaultStyles = (themeTokens, themeOptions, maxWidth, dismissible) => ({
|
|
176
|
+
const getDefaultStyles = (themeTokens, themeOptions, maxWidth, dismissible, viewport, system) => ({
|
|
173
177
|
containerStyles: {
|
|
174
178
|
container: {
|
|
175
|
-
flexDirection: 'row',
|
|
179
|
+
flexDirection: system === true && viewport === 'xl' ? 'row' : 'inherit',
|
|
176
180
|
...selectContainerStyles(themeTokens)
|
|
177
181
|
}
|
|
178
182
|
},
|
|
179
183
|
contentContainerStyles: {
|
|
180
184
|
contentContainer: {
|
|
185
|
+
flex: 1,
|
|
181
186
|
flexDirection: 'row',
|
|
182
187
|
flexShrink: 1,
|
|
183
188
|
justifyContent: 'space-between',
|
|
184
|
-
...selectContentContainerStyle(maxWidth)
|
|
189
|
+
...selectContentContainerStyle(themeTokens, maxWidth, viewport, system)
|
|
185
190
|
}
|
|
186
191
|
},
|
|
187
192
|
staticContentContainerStyles: {
|
|
@@ -317,9 +322,9 @@ const Notification = /*#__PURE__*/React.forwardRef((_ref6, ref) => {
|
|
|
317
322
|
selectDismissIconPropsIds: {}
|
|
318
323
|
});
|
|
319
324
|
if (enableMediaQueryStyleSheet) {
|
|
320
|
-
notificationComponentRef.current = getMediaQueryStyles(themeTokens, themeOptions,
|
|
325
|
+
notificationComponentRef.current = getMediaQueryStyles(themeTokens, themeOptions, mediaIdsRef, dismissible, viewport, system);
|
|
321
326
|
} else {
|
|
322
|
-
notificationComponentRef.current = getDefaultStyles(themeTokens, themeOptions, maxWidth, dismissible);
|
|
327
|
+
notificationComponentRef.current = getDefaultStyles(themeTokens, themeOptions, maxWidth, dismissible, viewport, system);
|
|
323
328
|
}
|
|
324
329
|
if (isDismissed) {
|
|
325
330
|
return null;
|
|
@@ -164,6 +164,7 @@ const Radio = /*#__PURE__*/React.forwardRef((_ref4, ref) => {
|
|
|
164
164
|
onKeyDown: handleKeyDown,
|
|
165
165
|
onPress: handleChange,
|
|
166
166
|
...selectedProps,
|
|
167
|
+
style: staticStyles.removeOutline,
|
|
167
168
|
children: _ref5 => {
|
|
168
169
|
let {
|
|
169
170
|
focused: focus,
|
|
@@ -275,5 +276,8 @@ const staticStyles = StyleSheet.create({
|
|
|
275
276
|
alignWithLabel: {
|
|
276
277
|
alignSelf: 'flex-start',
|
|
277
278
|
justifyContent: 'center'
|
|
279
|
+
},
|
|
280
|
+
removeOutline: {
|
|
281
|
+
outlineStyle: 'none'
|
|
278
282
|
}
|
|
279
283
|
});
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
|
-
import { componentPropType } from '../utils';
|
|
3
|
+
import { componentPropType, selectSystemProps, htmlAttrs } from '../utils';
|
|
4
4
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
5
5
|
import { jsxs as _jsxs } from "react/jsx-runtime";
|
|
6
|
+
const [selectProps, selectedSystemPropTypes] = selectSystemProps([htmlAttrs]);
|
|
6
7
|
const Picker = /*#__PURE__*/React.forwardRef((_ref, ref) => {
|
|
7
8
|
let {
|
|
8
9
|
value,
|
|
@@ -19,6 +20,7 @@ const Picker = /*#__PURE__*/React.forwardRef((_ref, ref) => {
|
|
|
19
20
|
testID,
|
|
20
21
|
...rest
|
|
21
22
|
} = _ref;
|
|
23
|
+
const selectedProps = selectProps(rest);
|
|
22
24
|
const {
|
|
23
25
|
accessibilityLabel,
|
|
24
26
|
accessibilityDescribedBy,
|
|
@@ -39,6 +41,7 @@ const Picker = /*#__PURE__*/React.forwardRef((_ref, ref) => {
|
|
|
39
41
|
"aria-describedby": accessibilityDescribedBy,
|
|
40
42
|
"aria-invalid": accessibilityInvalid,
|
|
41
43
|
"data-testid": testID,
|
|
44
|
+
...selectedProps,
|
|
42
45
|
children: [placeholder !== undefined && /*#__PURE__*/_jsx("option", {
|
|
43
46
|
value: placeholder.value,
|
|
44
47
|
disabled: true,
|
|
@@ -50,6 +53,7 @@ const Picker = /*#__PURE__*/React.forwardRef((_ref, ref) => {
|
|
|
50
53
|
Picker.displayName = 'Picker';
|
|
51
54
|
export default Picker;
|
|
52
55
|
Picker.propTypes = {
|
|
56
|
+
...selectedSystemPropTypes,
|
|
53
57
|
value: PropTypes.string,
|
|
54
58
|
onChange: PropTypes.func,
|
|
55
59
|
onFocus: PropTypes.func,
|
|
@@ -4,13 +4,13 @@ import Platform from "react-native-web/dist/exports/Platform";
|
|
|
4
4
|
import StyleSheet from "react-native-web/dist/exports/StyleSheet";
|
|
5
5
|
import PropTypes from 'prop-types';
|
|
6
6
|
import { applyTextStyles, useThemeTokens, applyOuterBorder, useTheme } from '../ThemeProvider';
|
|
7
|
-
import { a11yProps, componentPropType, getTokensPropType, inputSupportsProps, selectSystemProps, useInputValue, variantProp, viewProps } from '../utils';
|
|
7
|
+
import { a11yProps, componentPropType, getTokensPropType, inputSupportsProps, selectSystemProps, useInputValue, variantProp, viewProps, htmlAttrs } from '../utils';
|
|
8
8
|
import Picker from './Picker';
|
|
9
9
|
import InputSupports from '../InputSupports';
|
|
10
10
|
import { ANDROID_VALIDATION_ICON_CONTAINER_OFFSET } from './constants';
|
|
11
11
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
12
12
|
import { jsxs as _jsxs } from "react/jsx-runtime";
|
|
13
|
-
const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, inputSupportsProps, viewProps]);
|
|
13
|
+
const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, inputSupportsProps, viewProps, htmlAttrs]);
|
|
14
14
|
const selectInputStyles = (_ref, themeOptions, inactive) => {
|
|
15
15
|
let {
|
|
16
16
|
backgroundColor,
|
package/lib-module/Tabs/Tabs.js
CHANGED
|
@@ -106,6 +106,7 @@ const Tabs = /*#__PURE__*/React.forwardRef((_ref, ref) => {
|
|
|
106
106
|
ref: itemRef,
|
|
107
107
|
LinkRouter: ItemLinkRouter = LinkRouter,
|
|
108
108
|
linkRouterProps: itemLinkRouterProps,
|
|
109
|
+
render,
|
|
109
110
|
...itemRest
|
|
110
111
|
} = _ref3;
|
|
111
112
|
const itemId = id ?? label;
|
|
@@ -131,6 +132,7 @@ const Tabs = /*#__PURE__*/React.forwardRef((_ref, ref) => {
|
|
|
131
132
|
...linkRouterProps,
|
|
132
133
|
...itemLinkRouterProps
|
|
133
134
|
},
|
|
135
|
+
render: render,
|
|
134
136
|
...itemProps,
|
|
135
137
|
children: label
|
|
136
138
|
}, itemId);
|
|
@@ -151,7 +153,8 @@ Tabs.propTypes = {
|
|
|
151
153
|
href: PropTypes.string,
|
|
152
154
|
label: PropTypes.string,
|
|
153
155
|
id: PropTypes.string,
|
|
154
|
-
ref: ABBPropTypes.ref()
|
|
156
|
+
ref: ABBPropTypes.ref(),
|
|
157
|
+
render: PropTypes.func
|
|
155
158
|
})),
|
|
156
159
|
/**
|
|
157
160
|
* `id` property of the current tab in the items array
|
|
@@ -95,6 +95,7 @@ const TabsItem = /*#__PURE__*/React.forwardRef((_ref4, ref) => {
|
|
|
95
95
|
selected
|
|
96
96
|
} : undefined,
|
|
97
97
|
id,
|
|
98
|
+
render,
|
|
98
99
|
...rawRest
|
|
99
100
|
} = _ref4;
|
|
100
101
|
// Convert onClick etc to onPress etc if used in an integration
|
|
@@ -150,6 +151,10 @@ const TabsItem = /*#__PURE__*/React.forwardRef((_ref4, ref) => {
|
|
|
150
151
|
}
|
|
151
152
|
// itemPositions is a ref object so this should only re-run when `selected` (or `index`) change
|
|
152
153
|
}, [selected, index, itemPositions]);
|
|
154
|
+
if (render) return render({
|
|
155
|
+
selected,
|
|
156
|
+
handlePress
|
|
157
|
+
});
|
|
153
158
|
return /*#__PURE__*/_jsx(Pressable, {
|
|
154
159
|
ref: ref,
|
|
155
160
|
onPress: handlePress,
|
|
@@ -207,7 +212,8 @@ TabsItem.propTypes = {
|
|
|
207
212
|
selected: PropTypes.bool,
|
|
208
213
|
itemPositions: itemPositionsPropType,
|
|
209
214
|
children: PropTypes.string,
|
|
210
|
-
id: PropTypes.string
|
|
215
|
+
id: PropTypes.string,
|
|
216
|
+
render: PropTypes.func
|
|
211
217
|
};
|
|
212
218
|
const staticStyles = StyleSheet.create({
|
|
213
219
|
center: {
|
package/lib-module/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { default as A11yText } from './A11yText';
|
|
2
|
+
export { default as ActionCard } from './ActionCard';
|
|
2
3
|
export { default as ActivityIndicator } from './ActivityIndicator';
|
|
3
4
|
export { default as Autocomplete } from './Autocomplete';
|
|
4
5
|
export { default as Box } from './Box';
|
|
@@ -52,8 +52,8 @@ function useVerticalExpandAnimation(_ref) {
|
|
|
52
52
|
if (isAnimating || expandStateChanged) containerStyles.overflow = 'hidden';
|
|
53
53
|
if (!isExpanded && !isAnimating && !expandStateChanged) {
|
|
54
54
|
if (Platform.OS === 'web') {
|
|
55
|
-
// Without `
|
|
56
|
-
containerStyles.
|
|
55
|
+
// Without `display: 'none', descendents are focusable on web even when collapsed.
|
|
56
|
+
containerStyles.display = 'none';
|
|
57
57
|
} else {
|
|
58
58
|
// There's no `visibility: hidden` in React Native, and display: none causes a flicker on expand.
|
|
59
59
|
// Without some form of hiding, some children leak through even when closed e.g. `List.Item` bullets.
|
|
@@ -67,7 +67,7 @@ function useVerticalExpandAnimation(_ref) {
|
|
|
67
67
|
// on web we can hide the contents until we have the container measured and avoid occasional jitter
|
|
68
68
|
// this won't work on native platforms
|
|
69
69
|
containerStyles.height = 0;
|
|
70
|
-
containerStyles.
|
|
70
|
+
containerStyles.display = 'none';
|
|
71
71
|
}
|
|
72
72
|
} else if (Platform.OS === 'web') {
|
|
73
73
|
const transitionDuration = isExpanded ? expandDuration : collapseDuration;
|
|
@@ -105,7 +105,7 @@ export const getTokensPropType = function () {
|
|
|
105
105
|
* For example, for a set of tokens used in a common style, or for a set of tokens required by
|
|
106
106
|
* a themeless component whose tokens are set by a parent but requires tokens of a certain shape.
|
|
107
107
|
*
|
|
108
|
-
* By default, requires an object with a complete set of tokens (allowing `null
|
|
108
|
+
* By default, requires an object with a complete set of tokens (allowing `null` and `undefined`).
|
|
109
109
|
*
|
|
110
110
|
* @param {string[]} componentTokenKeys - array of strings of token names
|
|
111
111
|
* @param {object} [options]
|
|
@@ -124,7 +124,7 @@ export const getTokensSetPropType = function (componentTokenKeys) {
|
|
|
124
124
|
for (var _len2 = arguments.length, args = new Array(_len2 > 2 ? _len2 - 2 : 0), _key2 = 2; _key2 < _len2; _key2++) {
|
|
125
125
|
args[_key2 - 2] = arguments[_key2];
|
|
126
126
|
}
|
|
127
|
-
return props[propName] !== null && tokenValueType.isRequired(props, propName, ...args);
|
|
127
|
+
return props[propName] !== null && props[propName] !== undefined && tokenValueType.isRequired(props, propName, ...args);
|
|
128
128
|
}])));
|
|
129
129
|
return allowFunction ? PropTypes.oneOfType([tokensObjectValidator, PropTypes.func]) : tokensObjectValidator;
|
|
130
130
|
};
|
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.58.0",
|
|
15
15
|
"airbnb-prop-types": "^2.16.0",
|
|
16
16
|
"css-mediaquery": "^0.1.2",
|
|
17
17
|
"expo-linear-gradient": "^12.5.0",
|
|
@@ -85,6 +85,6 @@
|
|
|
85
85
|
"standard-engine": {
|
|
86
86
|
"skip": true
|
|
87
87
|
},
|
|
88
|
-
"version": "1.
|
|
88
|
+
"version": "1.87.0",
|
|
89
89
|
"types": "types/index.d.ts"
|
|
90
90
|
}
|
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { Animated, View, StyleSheet, Text } from 'react-native'
|
|
3
|
+
import PropTypes from 'prop-types'
|
|
4
|
+
|
|
5
|
+
import { applyTextStyles, useThemeTokens } from '../ThemeProvider'
|
|
6
|
+
import {
|
|
7
|
+
a11yProps,
|
|
8
|
+
getTokensPropType,
|
|
9
|
+
selectSystemProps,
|
|
10
|
+
variantProp,
|
|
11
|
+
viewProps,
|
|
12
|
+
wrapStringsInText,
|
|
13
|
+
clickProps,
|
|
14
|
+
hrefAttrsProp,
|
|
15
|
+
linkProps
|
|
16
|
+
} from '../utils'
|
|
17
|
+
import Icon from '../Icon'
|
|
18
|
+
import Card from '../Card'
|
|
19
|
+
|
|
20
|
+
const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, linkProps, viewProps])
|
|
21
|
+
|
|
22
|
+
const selectCardStyles = (styles) =>
|
|
23
|
+
['borderColor', 'borderRadius', 'borderWidth'].reduce((acc, key) => {
|
|
24
|
+
if (styles[key]) acc[key] = styles[key]
|
|
25
|
+
return acc
|
|
26
|
+
}, {})
|
|
27
|
+
|
|
28
|
+
const selectInteractiveCardStyles = ({
|
|
29
|
+
backgroundColor,
|
|
30
|
+
paddingBottom,
|
|
31
|
+
paddingLeft,
|
|
32
|
+
paddingRight,
|
|
33
|
+
paddingTop
|
|
34
|
+
}) => ({
|
|
35
|
+
...(backgroundColor && { backgroundColor }),
|
|
36
|
+
paddingBottom,
|
|
37
|
+
paddingLeft,
|
|
38
|
+
paddingRight,
|
|
39
|
+
paddingTop
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
const selectIconStyles = ({
|
|
43
|
+
iconMarginBottom,
|
|
44
|
+
iconMarginLeft,
|
|
45
|
+
iconMarginRight,
|
|
46
|
+
iconMarginTop
|
|
47
|
+
}) => ({
|
|
48
|
+
marginBottom: iconMarginBottom,
|
|
49
|
+
marginLeft: iconMarginLeft,
|
|
50
|
+
marginRight: iconMarginRight,
|
|
51
|
+
marginTop: iconMarginTop
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
const selectIconProps = ({ icon, iconBackgroundColor, iconColor }) => ({
|
|
55
|
+
icon,
|
|
56
|
+
variant: { background: true, padding: 'small' },
|
|
57
|
+
tokens: { backgroundColor: iconBackgroundColor, color: iconColor }
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
const selectTitleStyles = ({
|
|
61
|
+
titleMarginBottom,
|
|
62
|
+
titleMarginLeft,
|
|
63
|
+
titleMarginRight,
|
|
64
|
+
titleMarginTop
|
|
65
|
+
}) => ({
|
|
66
|
+
marginBottom: titleMarginBottom,
|
|
67
|
+
marginLeft: titleMarginLeft,
|
|
68
|
+
marginRight: titleMarginRight,
|
|
69
|
+
marginTop: titleMarginTop
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
const selectTitleTextStyles = ({
|
|
73
|
+
titleFontColor,
|
|
74
|
+
titleFontName,
|
|
75
|
+
titleFontSize,
|
|
76
|
+
titleFontWeight,
|
|
77
|
+
titleLineHeight
|
|
78
|
+
}) =>
|
|
79
|
+
applyTextStyles({
|
|
80
|
+
fontColor: titleFontColor,
|
|
81
|
+
fontName: titleFontName,
|
|
82
|
+
fontSize: titleFontSize,
|
|
83
|
+
fontWeight: titleFontWeight,
|
|
84
|
+
lineHeight: titleLineHeight
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
const selectContentStyles = ({
|
|
88
|
+
contentMarginBottom,
|
|
89
|
+
contentMarginLeft,
|
|
90
|
+
contentMarginRight,
|
|
91
|
+
contentMarginTop
|
|
92
|
+
}) => ({
|
|
93
|
+
marginBottom: contentMarginBottom,
|
|
94
|
+
marginLeft: contentMarginLeft,
|
|
95
|
+
marginRight: contentMarginRight,
|
|
96
|
+
marginTop: contentMarginTop
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
const selectContentTextStyles = ({
|
|
100
|
+
contentFontColor,
|
|
101
|
+
contentFontName,
|
|
102
|
+
contentFontSize,
|
|
103
|
+
contentFontWeight,
|
|
104
|
+
contentLineHeight
|
|
105
|
+
}) =>
|
|
106
|
+
applyTextStyles({
|
|
107
|
+
fontColor: contentFontColor,
|
|
108
|
+
fontName: contentFontName,
|
|
109
|
+
fontSize: contentFontSize,
|
|
110
|
+
fontWeight: contentFontWeight,
|
|
111
|
+
lineHeight: contentLineHeight
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
const selectStatusIconProps = ({ statusIcon, statusIconColor }) => ({
|
|
115
|
+
icon: statusIcon,
|
|
116
|
+
tokens: { color: statusIconColor },
|
|
117
|
+
variant: { size: 'micro' }
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
const selectActionIconStyles = ({
|
|
121
|
+
actionIconMarginBottom,
|
|
122
|
+
actionIconMarginLeft,
|
|
123
|
+
actionIconMarginRight,
|
|
124
|
+
actionIconMarginTop
|
|
125
|
+
}) => ({
|
|
126
|
+
marginBottom: actionIconMarginBottom,
|
|
127
|
+
marginLeft: actionIconMarginLeft,
|
|
128
|
+
marginRight: actionIconMarginRight,
|
|
129
|
+
marginTop: actionIconMarginTop
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
const selectActionIconProps = ({ actionIcon, actionIconColor }) => ({
|
|
133
|
+
icon: actionIcon,
|
|
134
|
+
tokens: { color: actionIconColor }
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
const ACTION_ICON_ANIMATION_DURATION = 100
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* ActionCard component represents a card with an action that can be triggered by the user.
|
|
141
|
+
*
|
|
142
|
+
* @component
|
|
143
|
+
* @example
|
|
144
|
+
* return (
|
|
145
|
+
* <ActionCard
|
|
146
|
+
* icon={<Icon icon={Icons.EyeMasked} />}
|
|
147
|
+
* title="Like"
|
|
148
|
+
* href="/like"
|
|
149
|
+
* accessibilityRole="link"
|
|
150
|
+
* tokens={themeTokens}
|
|
151
|
+
* variant={{validation: 'warning'}}
|
|
152
|
+
* onPress={() => handleLike()}
|
|
153
|
+
* >
|
|
154
|
+
* Click here to like the post
|
|
155
|
+
* </ActionCard>
|
|
156
|
+
* )
|
|
157
|
+
*/
|
|
158
|
+
const ActionCard = React.forwardRef(
|
|
159
|
+
(
|
|
160
|
+
{ icon, title, children, href, direction = true, accessibilityRole, tokens, variant, ...rest },
|
|
161
|
+
ref
|
|
162
|
+
) => {
|
|
163
|
+
const themeTokens = useThemeTokens('ActionCard', tokens, variant)
|
|
164
|
+
|
|
165
|
+
const actionIconAnimation = React.useRef(new Animated.Value(0)).current
|
|
166
|
+
|
|
167
|
+
const { onPress, ...props } = clickProps.toPressProps(rest)
|
|
168
|
+
const { hrefAttrs, rawRest } = hrefAttrsProp.bundle(props)
|
|
169
|
+
const selectedProps = selectProps({
|
|
170
|
+
accessibilityRole,
|
|
171
|
+
href,
|
|
172
|
+
onPress: linkProps.handleHref({ href, onPress }),
|
|
173
|
+
hrefAttrs,
|
|
174
|
+
...rawRest
|
|
175
|
+
})
|
|
176
|
+
|
|
177
|
+
return (
|
|
178
|
+
<Card
|
|
179
|
+
ref={ref}
|
|
180
|
+
interactiveCard={{
|
|
181
|
+
body: (pressableState) => {
|
|
182
|
+
const animate = pressableState.pressed || pressableState.hover || pressableState.focus
|
|
183
|
+
Animated.timing(actionIconAnimation, {
|
|
184
|
+
toValue: animate ? themeTokens.actionIconTranslate : 0,
|
|
185
|
+
duration: ACTION_ICON_ANIMATION_DURATION,
|
|
186
|
+
useNativeDriver: false
|
|
187
|
+
}).start()
|
|
188
|
+
|
|
189
|
+
return (
|
|
190
|
+
<View style={staticStyles.container}>
|
|
191
|
+
{icon && (
|
|
192
|
+
<View style={selectIconStyles(themeTokens)}>
|
|
193
|
+
<Icon
|
|
194
|
+
{...selectIconProps({
|
|
195
|
+
icon,
|
|
196
|
+
...themeTokens
|
|
197
|
+
})}
|
|
198
|
+
/>
|
|
199
|
+
</View>
|
|
200
|
+
)}
|
|
201
|
+
<View style={staticStyles.content}>
|
|
202
|
+
<View style={staticStyles.header}>
|
|
203
|
+
<View style={[selectTitleStyles(themeTokens), staticStyles.title]}>
|
|
204
|
+
<Text>
|
|
205
|
+
{wrapStringsInText(title, { style: selectTitleTextStyles(themeTokens) })}
|
|
206
|
+
{themeTokens.statusIcon && (
|
|
207
|
+
<View style={staticStyles.statusIcon}>
|
|
208
|
+
<Icon {...selectStatusIconProps(themeTokens)} />
|
|
209
|
+
</View>
|
|
210
|
+
)}
|
|
211
|
+
</Text>
|
|
212
|
+
</View>
|
|
213
|
+
<View style={staticStyles.icons}>
|
|
214
|
+
{direction && (
|
|
215
|
+
<Animated.View
|
|
216
|
+
style={[
|
|
217
|
+
selectActionIconStyles(themeTokens),
|
|
218
|
+
{ transform: [{ translateX: actionIconAnimation }] }
|
|
219
|
+
]}
|
|
220
|
+
>
|
|
221
|
+
<Icon {...selectActionIconProps(themeTokens)} />
|
|
222
|
+
</Animated.View>
|
|
223
|
+
)}
|
|
224
|
+
</View>
|
|
225
|
+
</View>
|
|
226
|
+
<View style={[staticStyles.body, selectContentStyles(themeTokens)]}>
|
|
227
|
+
{typeof children === 'string'
|
|
228
|
+
? wrapStringsInText(children, {
|
|
229
|
+
style: selectContentTextStyles(themeTokens)
|
|
230
|
+
})
|
|
231
|
+
: children}
|
|
232
|
+
</View>
|
|
233
|
+
</View>
|
|
234
|
+
</View>
|
|
235
|
+
)
|
|
236
|
+
},
|
|
237
|
+
tokens: selectInteractiveCardStyles(themeTokens)
|
|
238
|
+
}}
|
|
239
|
+
tokens={selectCardStyles(themeTokens)}
|
|
240
|
+
{...selectedProps}
|
|
241
|
+
/>
|
|
242
|
+
)
|
|
243
|
+
}
|
|
244
|
+
)
|
|
245
|
+
|
|
246
|
+
ActionCard.displayName = 'ActionCard'
|
|
247
|
+
|
|
248
|
+
ActionCard.propTypes = {
|
|
249
|
+
...selectedSystemPropTypes,
|
|
250
|
+
tokens: getTokensPropType('ActionCard'),
|
|
251
|
+
variant: variantProp.propType,
|
|
252
|
+
/**
|
|
253
|
+
* Icon for the ActionCard
|
|
254
|
+
*/
|
|
255
|
+
icon: PropTypes.elementType,
|
|
256
|
+
/**
|
|
257
|
+
* Title for the ActionCard
|
|
258
|
+
*/
|
|
259
|
+
title: PropTypes.string,
|
|
260
|
+
/**
|
|
261
|
+
* Children for the ActionCard
|
|
262
|
+
*/
|
|
263
|
+
children: PropTypes.oneOfType([PropTypes.string, PropTypes.elementType]),
|
|
264
|
+
/**
|
|
265
|
+
* href for the ActionCard
|
|
266
|
+
*/
|
|
267
|
+
href: PropTypes.string,
|
|
268
|
+
/**
|
|
269
|
+
* Enable or disable the direction of the ActionCard
|
|
270
|
+
*/
|
|
271
|
+
direction: PropTypes.bool,
|
|
272
|
+
/**
|
|
273
|
+
* AccesibilityRole for the ActionCard
|
|
274
|
+
*/
|
|
275
|
+
accessibilityRole: PropTypes.string
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
const staticStyles = StyleSheet.create({
|
|
279
|
+
body: {
|
|
280
|
+
flexDirection: 'column'
|
|
281
|
+
},
|
|
282
|
+
container: {
|
|
283
|
+
flex: 1,
|
|
284
|
+
flexDirection: 'row'
|
|
285
|
+
},
|
|
286
|
+
content: {
|
|
287
|
+
flex: 1,
|
|
288
|
+
flexDirection: 'column'
|
|
289
|
+
},
|
|
290
|
+
icons: {
|
|
291
|
+
flexDirection: 'row',
|
|
292
|
+
alignItems: 'center'
|
|
293
|
+
},
|
|
294
|
+
header: {
|
|
295
|
+
flexDirection: 'row',
|
|
296
|
+
justifyContent: 'space-between'
|
|
297
|
+
},
|
|
298
|
+
title: {
|
|
299
|
+
flexShrink: 1
|
|
300
|
+
},
|
|
301
|
+
statusIcon: {
|
|
302
|
+
marginLeft: 4
|
|
303
|
+
}
|
|
304
|
+
})
|
|
305
|
+
|
|
306
|
+
export default ActionCard
|
package/src/Card/Card.jsx
CHANGED
|
@@ -9,13 +9,13 @@ import {
|
|
|
9
9
|
} from '../ThemeProvider'
|
|
10
10
|
import { getTokensPropType, variantProp, StyleSheet, createMediaQueryStyles } from '../utils'
|
|
11
11
|
import { useViewport } from '../ViewportProvider'
|
|
12
|
-
import { a11yProps, selectSystemProps, viewProps } from '../utils/props'
|
|
12
|
+
import { a11yProps, linkProps, selectSystemProps, viewProps } from '../utils/props'
|
|
13
13
|
import CardBase from './CardBase'
|
|
14
14
|
import PressableCardBase from './PressableCardBase'
|
|
15
15
|
import CheckboxButton from '../Checkbox/CheckboxButton'
|
|
16
16
|
import RadioButton from '../Radio/RadioButton'
|
|
17
17
|
|
|
18
|
-
const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, viewProps])
|
|
18
|
+
const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, viewProps, linkProps])
|
|
19
19
|
|
|
20
20
|
const SelectionType = {
|
|
21
21
|
Checkbox: 'checkbox',
|
|
@@ -253,7 +253,9 @@ const Card = React.forwardRef(
|
|
|
253
253
|
onPress
|
|
254
254
|
})
|
|
255
255
|
)}
|
|
256
|
-
{interactiveCard?.body
|
|
256
|
+
{typeof interactiveCard?.body === 'function'
|
|
257
|
+
? interactiveCard.body(cardState)
|
|
258
|
+
: interactiveCard.body}
|
|
257
259
|
</>
|
|
258
260
|
)
|
|
259
261
|
}}
|
|
@@ -304,7 +306,7 @@ Card.propTypes = {
|
|
|
304
306
|
* - variant: The variant to be used for the interactive card
|
|
305
307
|
*/
|
|
306
308
|
interactiveCard: PropTypes.shape({
|
|
307
|
-
body: PropTypes.node,
|
|
309
|
+
body: PropTypes.oneOfType([PropTypes.node, PropTypes.func]),
|
|
308
310
|
tokens: getTokensPropType('Card'),
|
|
309
311
|
selectionType: PropTypes.oneOf(Object.values(SelectionType)),
|
|
310
312
|
variant: variantProp.propType
|
|
@@ -135,7 +135,7 @@ PressableCardBase.displayName = 'PressableCardBase'
|
|
|
135
135
|
PressableCardBase.propTypes = {
|
|
136
136
|
...selectedSystemPropTypes,
|
|
137
137
|
children: PropTypes.oneOfType([PropTypes.func, PropTypes.node]),
|
|
138
|
-
tokens: getTokensSetPropType(tokenKeys, {
|
|
138
|
+
tokens: getTokensSetPropType(tokenKeys, { partial: true, allowFunction: true }),
|
|
139
139
|
variant: variantProp.propType
|
|
140
140
|
}
|
|
141
141
|
|
|
@@ -192,6 +192,7 @@ const Checkbox = React.forwardRef(
|
|
|
192
192
|
onKeyDown={handleKeyDown}
|
|
193
193
|
onPress={handleChange}
|
|
194
194
|
{...selectedProps}
|
|
195
|
+
style={staticStyles.removeOutline}
|
|
195
196
|
>
|
|
196
197
|
{({ focused: focus, hovered: hover, pressed }) => {
|
|
197
198
|
const { icon: IconComponent, ...stateTokens } = getTokens({ focus, hover, pressed })
|
|
@@ -311,5 +312,6 @@ const staticStyles = StyleSheet.create({
|
|
|
311
312
|
wrapper: { backgroundColor: 'transparent' },
|
|
312
313
|
container: { flexDirection: 'row', alignItems: 'center' },
|
|
313
314
|
defaultInputStyles: { alignItems: 'center', justifyContent: 'center' },
|
|
314
|
-
alignWithLabel: { alignSelf: 'flex-start', justifyContent: 'center' }
|
|
315
|
+
alignWithLabel: { alignSelf: 'flex-start', justifyContent: 'center' },
|
|
316
|
+
removeOutline: { outlineStyle: 'none' }
|
|
315
317
|
})
|