@coinbase/cds-mobile 9.0.2 → 9.1.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 +10 -0
- package/dts/dots/DotCount.d.ts +11 -13
- package/dts/dots/DotCount.d.ts.map +1 -1
- package/esm/dots/DotCount.js +57 -44
- package/esm/system/__stories__/componentConfigStickerSheet/customComponentConfig.js +6 -0
- package/esm/system/__stories__/componentConfigStickerSheet/examples/DotCount.js +15 -22
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,16 @@ All notable changes to this project will be documented in this file.
|
|
|
8
8
|
|
|
9
9
|
<!-- template-start -->
|
|
10
10
|
|
|
11
|
+
## 9.1.0 (5/26/2026 PST)
|
|
12
|
+
|
|
13
|
+
#### 🚀 Updates
|
|
14
|
+
|
|
15
|
+
- Feat: support DotCount theming. [[#723](https://github.com/coinbase/cds/pull/723)]
|
|
16
|
+
|
|
17
|
+
#### 🐞 Fixes
|
|
18
|
+
|
|
19
|
+
- Fix: DotCount border mixing with background color. [[#723](https://github.com/coinbase/cds/pull/723)]
|
|
20
|
+
|
|
11
21
|
## 9.0.2 ((5/22/2026, 09:54 AM PST))
|
|
12
22
|
|
|
13
23
|
This is an artificial version bump with no new change.
|
package/dts/dots/DotCount.d.ts
CHANGED
|
@@ -7,13 +7,18 @@ import type {
|
|
|
7
7
|
SharedAccessibilityProps,
|
|
8
8
|
SharedProps,
|
|
9
9
|
} from '@coinbase/cds-common/types';
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
import {
|
|
11
|
+
MAX_OVERFLOW_COUNT,
|
|
12
|
+
parseDotCountMaxOverflow,
|
|
13
|
+
} from '@coinbase/cds-common/utils/parseDotCountMaxOverflow';
|
|
14
|
+
import { type BoxBaseProps } from '../layout/Box';
|
|
15
|
+
export { MAX_OVERFLOW_COUNT, parseDotCountMaxOverflow };
|
|
12
16
|
export type DotCountBaseProps = SharedProps &
|
|
13
17
|
Pick<
|
|
14
18
|
SharedAccessibilityProps,
|
|
15
19
|
'accessibilityLabel' | 'accessibilityLabelledBy' | 'accessibilityHint'
|
|
16
|
-
> &
|
|
20
|
+
> &
|
|
21
|
+
Omit<BoxBaseProps, 'children' | 'background' | 'pin' | 'style' | 'height'> & {
|
|
17
22
|
/**
|
|
18
23
|
* The number value to be shown in the dot. If count is <= 0, dot will not show up.
|
|
19
24
|
* */
|
|
@@ -35,17 +40,10 @@ export type DotCountBaseProps = SharedProps &
|
|
|
35
40
|
/** Indicates what shape Dot is overlapping */
|
|
36
41
|
overlap?: DotOverlap;
|
|
37
42
|
/**
|
|
38
|
-
*
|
|
39
|
-
* Width grows based on content length.
|
|
43
|
+
* Fixed height of the DotCount badge container. Width grows based on content length.
|
|
40
44
|
* @default 24
|
|
41
|
-
|
|
42
|
-
height?:
|
|
43
|
-
/**
|
|
44
|
-
* An optional fixed width of the DotCount component.
|
|
45
|
-
* By default, width grows based on content length.
|
|
46
|
-
* @default auto
|
|
47
|
-
* */
|
|
48
|
-
width?: number;
|
|
45
|
+
*/
|
|
46
|
+
height?: BoxBaseProps['height'];
|
|
49
47
|
};
|
|
50
48
|
export type DotCountProps = DotCountBaseProps & {
|
|
51
49
|
style?: StyleProp<ViewStyle>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DotCount.d.ts","sourceRoot":"","sources":["../../src/dots/DotCount.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA6C,MAAM,OAAO,CAAC;AAClE,OAAO,EAEL,KAAK,SAAS,
|
|
1
|
+
{"version":3,"file":"DotCount.d.ts","sourceRoot":"","sources":["../../src/dots/DotCount.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA6C,MAAM,OAAO,CAAC;AAClE,OAAO,EAEL,KAAK,SAAS,EACd,KAAK,SAAS,EAEd,KAAK,SAAS,EACf,MAAM,cAAc,CAAC;AAgBtB,OAAO,KAAK,EACV,oBAAoB,EACpB,gBAAgB,EAChB,UAAU,EACV,wBAAwB,EACxB,WAAW,EACZ,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,kBAAkB,EAClB,wBAAwB,EACzB,MAAM,qDAAqD,CAAC;AAK7D,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,eAAe,CAAC;AASvD,OAAO,EAAE,kBAAkB,EAAE,wBAAwB,EAAE,CAAC;AAexD,MAAM,MAAM,iBAAiB,GAAG,WAAW,GACzC,IAAI,CACF,wBAAwB,EACxB,oBAAoB,GAAG,yBAAyB,GAAG,mBAAmB,CACvE,GACD,IAAI,CAAC,YAAY,EAAE,UAAU,GAAG,YAAY,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,CAAC,GAAG;IAC3E;;UAEM;IACN,KAAK,EAAE,MAAM,CAAC;IACd;;;UAGM;IACN,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;;SAGK;IACL,OAAO,CAAC,EAAE,gBAAgB,CAAC;IAC3B,6CAA6C;IAC7C,GAAG,CAAC,EAAE,oBAAoB,CAAC;IAC3B,+CAA+C;IAC/C,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,8CAA8C;IAC9C,OAAO,CAAC,EAAE,UAAU,CAAC;IACrB;;;OAGG;IACH,MAAM,CAAC,EAAE,YAAY,CAAC,QAAQ,CAAC,CAAC;CACjC,CAAC;AAEJ,MAAM,MAAM,aAAa,GAAG,iBAAiB,GAAG;IAC9C,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC7B,sEAAsE;IACtE,MAAM,CAAC,EAAE;QACP,mBAAmB;QACnB,IAAI,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;QAC5B,wBAAwB;QACxB,SAAS,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;QACjC,mBAAmB;QACnB,IAAI,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;KAC7B,CAAC;CACH,CAAC;AAEF,eAAO,MAAM,QAAQ,qCAAiB,aAAa,6CAyJjD,CAAC"}
|
package/esm/dots/DotCount.js
CHANGED
|
@@ -1,31 +1,26 @@
|
|
|
1
|
-
const _excluded = ["children", "pin", "variant", "count", "max", "height", "width", "overlap", "style", "styles"];
|
|
1
|
+
const _excluded = ["children", "pin", "variant", "count", "max", "height", "width", "testID", "accessibilityLabel", "accessibilityLabelledBy", "accessibilityHint", "overlap", "style", "styles", "alignItems", "justifyContent", "paddingX", "borderWidth", "borderRadius", "borderColor", "font", "color", "fontFamily", "fontSize", "fontWeight", "lineHeight", "overflow"];
|
|
2
2
|
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
|
|
3
3
|
function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
|
|
4
4
|
import React, { memo, useEffect, useMemo, useState } from 'react';
|
|
5
|
-
import {
|
|
5
|
+
import { View } from 'react-native';
|
|
6
6
|
import Animated, { runOnJS, useAnimatedReaction, useAnimatedStyle, useSharedValue } from 'react-native-reanimated';
|
|
7
7
|
import { usePreviousValue } from '@coinbase/cds-common/hooks/usePreviousValue';
|
|
8
8
|
import { dotOpacityEnterConfig, dotOpacityExitConfig, dotScaleEnterConfig, dotScaleExitConfig } from '@coinbase/cds-common/motion/dot';
|
|
9
9
|
import { dotCountSize } from '@coinbase/cds-common/tokens/dot';
|
|
10
|
+
import { MAX_OVERFLOW_COUNT, parseDotCountMaxOverflow } from '@coinbase/cds-common/utils/parseDotCountMaxOverflow';
|
|
10
11
|
import { useComponentConfig } from '../hooks/useComponentConfig';
|
|
11
12
|
import { useDotPinStyles } from '../hooks/useDotPinStyles';
|
|
12
|
-
import {
|
|
13
|
+
import { Box } from '../layout/Box';
|
|
13
14
|
import { convertMotionConfigs } from '../motion/convertMotionConfig';
|
|
14
15
|
import { withMotionTiming } from '../motion/withMotionTiming';
|
|
15
16
|
import { Text } from '../typography/Text';
|
|
16
17
|
import { getTransform } from './dotStyles';
|
|
17
18
|
import { useDotsLayout } from './useDotsLayout';
|
|
18
19
|
|
|
19
|
-
//
|
|
20
|
-
// truncate the numbers so its x+.
|
|
20
|
+
// Re-exporting for backwards compatibility
|
|
21
21
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
22
|
-
export
|
|
23
|
-
|
|
24
|
-
if (max === void 0) {
|
|
25
|
-
max = MAX_OVERFLOW_COUNT;
|
|
26
|
-
}
|
|
27
|
-
return count <= max ? count : max + "+";
|
|
28
|
-
};
|
|
22
|
+
export { MAX_OVERFLOW_COUNT, parseDotCountMaxOverflow };
|
|
23
|
+
const AnimatedBox = Animated.createAnimatedComponent(Box);
|
|
29
24
|
const [opacityEnter, opacityExit, scaleEnter, scaleExit] = convertMotionConfigs([dotOpacityEnterConfig, dotOpacityExitConfig, dotScaleEnterConfig, dotScaleExitConfig]);
|
|
30
25
|
const variantColorMap = {
|
|
31
26
|
negative: 'bgNegative'
|
|
@@ -40,12 +35,28 @@ export const DotCount = /*#__PURE__*/memo(_props => {
|
|
|
40
35
|
max,
|
|
41
36
|
height = dotCountSize,
|
|
42
37
|
width,
|
|
38
|
+
testID = 'dot-count',
|
|
39
|
+
accessibilityLabel,
|
|
40
|
+
accessibilityLabelledBy,
|
|
41
|
+
accessibilityHint,
|
|
43
42
|
overlap,
|
|
44
43
|
style,
|
|
45
|
-
styles
|
|
44
|
+
styles,
|
|
45
|
+
alignItems = 'center',
|
|
46
|
+
justifyContent = 'center',
|
|
47
|
+
paddingX = 0.75,
|
|
48
|
+
borderWidth = 100,
|
|
49
|
+
borderRadius = 400,
|
|
50
|
+
borderColor = 'bgSecondary',
|
|
51
|
+
font = 'caption',
|
|
52
|
+
color = 'fgInverse',
|
|
53
|
+
fontFamily,
|
|
54
|
+
fontSize,
|
|
55
|
+
fontWeight,
|
|
56
|
+
lineHeight,
|
|
57
|
+
overflow = 'hidden'
|
|
46
58
|
} = mergedProps,
|
|
47
59
|
props = _objectWithoutPropertiesLoose(mergedProps, _excluded);
|
|
48
|
-
const theme = useTheme();
|
|
49
60
|
const [childrenSize, onChildrenLayout] = useDotsLayout();
|
|
50
61
|
const transforms = useDotPinStyles(childrenSize, {
|
|
51
62
|
width: width != null ? width : height,
|
|
@@ -63,18 +74,6 @@ export const DotCount = /*#__PURE__*/memo(_props => {
|
|
|
63
74
|
}
|
|
64
75
|
return {};
|
|
65
76
|
}, [pin, transforms]);
|
|
66
|
-
const containerStyles = useMemo(() => {
|
|
67
|
-
return [styleSheet.container, {
|
|
68
|
-
height,
|
|
69
|
-
minWidth: height,
|
|
70
|
-
width,
|
|
71
|
-
paddingHorizontal: theme.space[0.75],
|
|
72
|
-
borderWidth: theme.borderWidth[100],
|
|
73
|
-
borderRadius: theme.borderRadius[400],
|
|
74
|
-
borderColor: theme.color.bgSecondary,
|
|
75
|
-
backgroundColor: theme.color[variantColorMap[variant]]
|
|
76
|
-
}];
|
|
77
|
-
}, [height, width, theme.space, theme.borderWidth, theme.borderRadius, theme.color, variant]);
|
|
78
77
|
|
|
79
78
|
// avoid displaying 0 during animations and preserve exit animation
|
|
80
79
|
useEffect(() => {
|
|
@@ -106,37 +105,51 @@ export const DotCount = /*#__PURE__*/memo(_props => {
|
|
|
106
105
|
}]
|
|
107
106
|
};
|
|
108
107
|
});
|
|
109
|
-
const dotCountContainerStyle = useMemo(() => [
|
|
108
|
+
const dotCountContainerStyle = useMemo(() => [animatedStyles, styles == null ? void 0 : styles.container], [animatedStyles, styles == null ? void 0 : styles.container]);
|
|
110
109
|
const rootStyles = useMemo(() => [style, styles == null ? void 0 : styles.root], [styles == null ? void 0 : styles.root, style]);
|
|
110
|
+
const displayCount = useMemo(() => parseDotCountMaxOverflow(countInternal, max), [countInternal, max]);
|
|
111
111
|
|
|
112
112
|
// only check childrenSize when children is defined
|
|
113
113
|
const shouldShow = children !== undefined ? childrenSize !== null : true;
|
|
114
|
-
return /*#__PURE__*/_jsxs(View,
|
|
115
|
-
|
|
116
|
-
|
|
114
|
+
return /*#__PURE__*/_jsxs(View, {
|
|
115
|
+
accessibilityHint: accessibilityHint,
|
|
116
|
+
accessibilityLabel: accessibilityLabel,
|
|
117
|
+
accessibilityLabelledBy: accessibilityLabelledBy,
|
|
118
|
+
style: rootStyles,
|
|
119
|
+
testID: testID,
|
|
117
120
|
children: [/*#__PURE__*/_jsx(View, {
|
|
118
121
|
onLayout: onChildrenLayout,
|
|
119
|
-
testID:
|
|
122
|
+
testID: testID + "-children",
|
|
120
123
|
children: children
|
|
121
124
|
}), !shouldUnmount && shouldShow && /*#__PURE__*/_jsx(View, {
|
|
122
125
|
style: pinStyles,
|
|
123
|
-
children: /*#__PURE__*/_jsx(
|
|
126
|
+
children: /*#__PURE__*/_jsx(AnimatedBox, _extends({
|
|
127
|
+
animated: true,
|
|
128
|
+
alignItems: alignItems,
|
|
129
|
+
background: variantColorMap[variant],
|
|
130
|
+
borderColor: borderColor,
|
|
131
|
+
borderRadius: borderRadius,
|
|
132
|
+
borderWidth: borderWidth,
|
|
133
|
+
height: height,
|
|
134
|
+
justifyContent: justifyContent,
|
|
135
|
+
minWidth: height,
|
|
136
|
+
overflow: overflow,
|
|
137
|
+
paddingX: paddingX,
|
|
124
138
|
style: dotCountContainerStyle,
|
|
125
139
|
testID: "dotcount-container",
|
|
140
|
+
width: width
|
|
141
|
+
}, props, {
|
|
126
142
|
children: /*#__PURE__*/_jsx(Text, {
|
|
127
|
-
color:
|
|
128
|
-
font:
|
|
143
|
+
color: color,
|
|
144
|
+
font: font,
|
|
145
|
+
fontFamily: fontFamily,
|
|
146
|
+
fontSize: fontSize,
|
|
147
|
+
fontWeight: fontWeight,
|
|
148
|
+
lineHeight: lineHeight,
|
|
129
149
|
style: styles == null ? void 0 : styles.text,
|
|
130
|
-
children:
|
|
150
|
+
children: displayCount
|
|
131
151
|
})
|
|
132
|
-
})
|
|
152
|
+
}))
|
|
133
153
|
})]
|
|
134
|
-
})
|
|
135
|
-
});
|
|
136
|
-
const styleSheet = StyleSheet.create({
|
|
137
|
-
container: {
|
|
138
|
-
alignItems: 'center',
|
|
139
|
-
justifyContent: 'center',
|
|
140
|
-
display: 'flex'
|
|
141
|
-
}
|
|
154
|
+
});
|
|
142
155
|
});
|
|
@@ -126,5 +126,11 @@ export const customComponentConfig = {
|
|
|
126
126
|
paddingX: 1,
|
|
127
127
|
font: 'caption',
|
|
128
128
|
emphasis: 'low'
|
|
129
|
+
},
|
|
130
|
+
DotCount: {
|
|
131
|
+
height: 16,
|
|
132
|
+
// Design is 1.5 but this causes the badge to be too wide for some single-digit counts
|
|
133
|
+
paddingX: 1,
|
|
134
|
+
paddingY: 0
|
|
129
135
|
}
|
|
130
136
|
};
|
|
@@ -1,28 +1,21 @@
|
|
|
1
1
|
import React, { memo } from 'react';
|
|
2
|
+
import { IconButton } from '../../../../buttons/IconButton';
|
|
2
3
|
import { DotCount } from '../../../../dots/DotCount';
|
|
3
|
-
import {
|
|
4
|
-
import { jsx as _jsx
|
|
4
|
+
import { HStack } from '../../../../layout/HStack';
|
|
5
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
6
|
+
const dotCounts = [3, 12, 100];
|
|
5
7
|
export const DotCountExample = /*#__PURE__*/memo(() => {
|
|
6
|
-
return /*#__PURE__*/
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
return /*#__PURE__*/_jsx(HStack, {
|
|
9
|
+
gap: 2,
|
|
10
|
+
children: dotCounts.map(count => /*#__PURE__*/_jsx(DotCount, {
|
|
11
|
+
count: count,
|
|
12
|
+
pin: "top-end",
|
|
13
|
+
children: /*#__PURE__*/_jsx(IconButton, {
|
|
14
|
+
transparent: true,
|
|
15
|
+
accessibilityLabel: "Notifications",
|
|
16
|
+
iconSize: "m",
|
|
17
|
+
name: "bell"
|
|
12
18
|
})
|
|
13
|
-
}
|
|
14
|
-
count: 12,
|
|
15
|
-
children: /*#__PURE__*/_jsx(Icon, {
|
|
16
|
-
name: "bell",
|
|
17
|
-
size: "m"
|
|
18
|
-
})
|
|
19
|
-
}), /*#__PURE__*/_jsx(DotCount, {
|
|
20
|
-
count: 100,
|
|
21
|
-
max: 99,
|
|
22
|
-
children: /*#__PURE__*/_jsx(Icon, {
|
|
23
|
-
name: "bell",
|
|
24
|
-
size: "m"
|
|
25
|
-
})
|
|
26
|
-
})]
|
|
19
|
+
}, count))
|
|
27
20
|
});
|
|
28
21
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coinbase/cds-mobile",
|
|
3
|
-
"version": "9.0
|
|
3
|
+
"version": "9.1.0",
|
|
4
4
|
"description": "Coinbase Design System - Mobile",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -202,7 +202,7 @@
|
|
|
202
202
|
"react-native-worklets": "0.5.2"
|
|
203
203
|
},
|
|
204
204
|
"dependencies": {
|
|
205
|
-
"@coinbase/cds-common": "^9.0
|
|
205
|
+
"@coinbase/cds-common": "^9.1.0",
|
|
206
206
|
"@coinbase/cds-icons": "^5.17.0",
|
|
207
207
|
"@coinbase/cds-illustrations": "^4.40.1",
|
|
208
208
|
"@coinbase/cds-lottie-files": "^3.3.4",
|