react-native-terra-ui 0.11.1 → 0.11.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/lib/module/components/badge/Badge.js +12 -94
- package/lib/module/components/badge/Badge.js.map +1 -1
- package/lib/module/components/badge/parts/BadgeIndicator.js +31 -10
- package/lib/module/components/badge/parts/BadgeIndicator.js.map +1 -1
- package/lib/module/components/badge/utils.js +58 -0
- package/lib/module/components/badge/utils.js.map +1 -1
- package/lib/typescript/src/components/badge/Badge.d.ts +2 -1
- package/lib/typescript/src/components/badge/Badge.d.ts.map +1 -1
- package/lib/typescript/src/components/badge/parts/BadgeIndicator.d.ts.map +1 -1
- package/lib/typescript/src/components/badge/types.d.ts +14 -1
- package/lib/typescript/src/components/badge/types.d.ts.map +1 -1
- package/lib/typescript/src/components/badge/utils.d.ts +27 -0
- package/lib/typescript/src/components/badge/utils.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/badge/Badge.tsx +10 -43
- package/src/components/badge/parts/BadgeIndicator.tsx +16 -4
- package/src/components/badge/types.ts +11 -1
- package/src/components/badge/utils.ts +53 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.11.2](https://github.com/earthlin9/react-native-terra-ui/compare/v0.11.1...v0.11.2) (2026-09-12)
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
|
|
7
|
+
* **ui:** [badge] add offset prop and enlarge the indicator ([da293fa](https://github.com/earthlin9/react-native-terra-ui/commit/da293fa887d81cfeaf45f19067734e05ac4c6320))
|
|
8
|
+
|
|
3
9
|
## [0.11.1](https://github.com/earthlin9/react-native-terra-ui/compare/v0.11.0...v0.11.1) (2026-09-12)
|
|
4
10
|
|
|
5
11
|
### Features
|
|
@@ -4,7 +4,8 @@ import { View } from "react-native-unistyles/components/native/View";
|
|
|
4
4
|
import { forwardRef } from "react";
|
|
5
5
|
import { StyleSheet } from "react-native-unistyles";
|
|
6
6
|
import { BadgeIndicator } from "./parts/BadgeIndicator.js";
|
|
7
|
-
import {
|
|
7
|
+
import { getAnchorPosition } from "./utils.js";
|
|
8
|
+
|
|
8
9
|
/**
|
|
9
10
|
* Overlays a count or status indicator on one corner of the element it wraps.
|
|
10
11
|
*
|
|
@@ -15,14 +16,17 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
15
16
|
* ```
|
|
16
17
|
*
|
|
17
18
|
* The child renders untouched — `Badge` contributes the positioning context and
|
|
18
|
-
* the overlay, nothing else.
|
|
19
|
+
* the overlay, nothing else. A round child usually wants a negative `offset`,
|
|
20
|
+
* since the corner being anchored to is the bounding box's, not the circle's.
|
|
19
21
|
*/
|
|
22
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
20
23
|
const Badge = /*#__PURE__*/forwardRef(function Badge({
|
|
21
24
|
children,
|
|
22
25
|
placement = "top-right",
|
|
23
26
|
label,
|
|
24
27
|
color = "danger",
|
|
25
28
|
size = "md",
|
|
29
|
+
offset = 0,
|
|
26
30
|
isVisible = true,
|
|
27
31
|
fullWidth = false,
|
|
28
32
|
accessibilityLabel,
|
|
@@ -32,8 +36,6 @@ const Badge = /*#__PURE__*/forwardRef(function Badge({
|
|
|
32
36
|
const _styles = styles;
|
|
33
37
|
{
|
|
34
38
|
const styles = _styles.useVariants({
|
|
35
|
-
placement,
|
|
36
|
-
size,
|
|
37
39
|
fullWidth
|
|
38
40
|
});
|
|
39
41
|
return (
|
|
@@ -45,7 +47,7 @@ const Badge = /*#__PURE__*/forwardRef(function Badge({
|
|
|
45
47
|
...rest,
|
|
46
48
|
children: [children, isVisible ? /*#__PURE__*/_jsx(View, {
|
|
47
49
|
pointerEvents: "box-none",
|
|
48
|
-
style: styles.anchor,
|
|
50
|
+
style: [styles.anchor, getAnchorPosition(placement, size, offset)],
|
|
49
51
|
children: /*#__PURE__*/_jsx(BadgeIndicator, {
|
|
50
52
|
label: label,
|
|
51
53
|
color: color,
|
|
@@ -61,14 +63,10 @@ export { Badge };
|
|
|
61
63
|
|
|
62
64
|
// ─── Styles ───────────────────────────────────────────────────────────────────
|
|
63
65
|
//
|
|
64
|
-
// The indicator
|
|
65
|
-
//
|
|
66
|
-
//
|
|
67
|
-
//
|
|
68
|
-
//
|
|
69
|
-
// The inset equals the dot's radius, which puts a dot's centre exactly on the
|
|
70
|
-
// child's corner. A pill keeps the same anchored edges and grows inward from
|
|
71
|
-
// them, so a longer label extends across the child rather than away from it.
|
|
66
|
+
// The indicator's insets are computed in `getAnchorPosition`, not declared here:
|
|
67
|
+
// `offset` is an open-ended number, so it could never be a variant condition,
|
|
68
|
+
// and the position involves no theme tokens at all. That leaves this stylesheet
|
|
69
|
+
// with only what genuinely varies declaratively.
|
|
72
70
|
const styles = StyleSheet.create(() => ({
|
|
73
71
|
wrapper: {
|
|
74
72
|
position: "relative",
|
|
@@ -83,92 +81,12 @@ const styles = StyleSheet.create(() => ({
|
|
|
83
81
|
false: {
|
|
84
82
|
alignSelf: "flex-start"
|
|
85
83
|
}
|
|
86
|
-
},
|
|
87
|
-
placement: {
|
|
88
|
-
"top-right": {},
|
|
89
|
-
"top-left": {},
|
|
90
|
-
"bottom-right": {},
|
|
91
|
-
"bottom-left": {}
|
|
92
|
-
},
|
|
93
|
-
size: {
|
|
94
|
-
sm: {},
|
|
95
|
-
md: {}
|
|
96
84
|
}
|
|
97
85
|
},
|
|
98
86
|
uni__dependencies: [4]
|
|
99
87
|
},
|
|
100
88
|
anchor: {
|
|
101
|
-
position: "absolute"
|
|
102
|
-
variants: {
|
|
103
|
-
placement: {
|
|
104
|
-
"top-right": {},
|
|
105
|
-
"top-left": {},
|
|
106
|
-
"bottom-right": {},
|
|
107
|
-
"bottom-left": {}
|
|
108
|
-
},
|
|
109
|
-
size: {
|
|
110
|
-
sm: {},
|
|
111
|
-
md: {}
|
|
112
|
-
}
|
|
113
|
-
},
|
|
114
|
-
compoundVariants: [{
|
|
115
|
-
placement: "top-right",
|
|
116
|
-
size: "sm",
|
|
117
|
-
styles: {
|
|
118
|
-
top: -5,
|
|
119
|
-
right: -5
|
|
120
|
-
}
|
|
121
|
-
}, {
|
|
122
|
-
placement: "top-right",
|
|
123
|
-
size: "md",
|
|
124
|
-
styles: {
|
|
125
|
-
top: -6,
|
|
126
|
-
right: -6
|
|
127
|
-
}
|
|
128
|
-
}, {
|
|
129
|
-
placement: "top-left",
|
|
130
|
-
size: "sm",
|
|
131
|
-
styles: {
|
|
132
|
-
top: -5,
|
|
133
|
-
left: -5
|
|
134
|
-
}
|
|
135
|
-
}, {
|
|
136
|
-
placement: "top-left",
|
|
137
|
-
size: "md",
|
|
138
|
-
styles: {
|
|
139
|
-
top: -6,
|
|
140
|
-
left: -6
|
|
141
|
-
}
|
|
142
|
-
}, {
|
|
143
|
-
placement: "bottom-right",
|
|
144
|
-
size: "sm",
|
|
145
|
-
styles: {
|
|
146
|
-
bottom: -5,
|
|
147
|
-
right: -5
|
|
148
|
-
}
|
|
149
|
-
}, {
|
|
150
|
-
placement: "bottom-right",
|
|
151
|
-
size: "md",
|
|
152
|
-
styles: {
|
|
153
|
-
bottom: -6,
|
|
154
|
-
right: -6
|
|
155
|
-
}
|
|
156
|
-
}, {
|
|
157
|
-
placement: "bottom-left",
|
|
158
|
-
size: "sm",
|
|
159
|
-
styles: {
|
|
160
|
-
bottom: -5,
|
|
161
|
-
left: -5
|
|
162
|
-
}
|
|
163
|
-
}, {
|
|
164
|
-
placement: "bottom-left",
|
|
165
|
-
size: "md",
|
|
166
|
-
styles: {
|
|
167
|
-
bottom: -6,
|
|
168
|
-
left: -6
|
|
169
|
-
}
|
|
170
|
-
}],
|
|
171
|
-
uni__dependencies: [4]
|
|
89
|
+
position: "absolute"
|
|
172
90
|
}
|
|
173
91
|
}));
|
|
174
92
|
//# sourceMappingURL=Badge.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["forwardRef","StyleSheet","BadgeIndicator","jsx","_jsx","jsxs","_jsxs","Badge","children","placement","label","color","size","isVisible","fullWidth","accessibilityLabel","style","rest","ref","_styles","styles","useVariants","View","wrapper","pointerEvents","anchor","create","position","variants","true","alignSelf","false","
|
|
1
|
+
{"version":3,"names":["forwardRef","StyleSheet","BadgeIndicator","getAnchorPosition","jsx","_jsx","jsxs","_jsxs","Badge","children","placement","label","color","size","offset","isVisible","fullWidth","accessibilityLabel","style","rest","ref","_styles","styles","useVariants","View","wrapper","pointerEvents","anchor","create","position","variants","true","alignSelf","false","uni__dependencies"],"sourceRoot":"../../../../src","sources":["components/badge/Badge.tsx"],"mappings":";;;AAAA,SAA4BA,UAAU,QAAQ,OAAO;AAGrD,SAASC,UAAU,QAAQ,wBAAwB;AAEnD,SAASC,cAAc;AAEvB,SAASC,iBAAiB;;AAE1B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAZA,SAAAC,GAAA,IAAAC,IAAA,EAAAC,IAAA,IAAAC,KAAA;AAaA,MAAMC,KAAK,gBAAGR,UAAU,CAAwC,SAASQ,KAAKA,CAC5E;EACEC,QAAQ;EACRC,SAAS,GAAG,WAAW;EACvBC,KAAK;EACLC,KAAK,GAAG,QAAQ;EAChBC,IAAI,GAAG,IAAI;EACXC,MAAM,GAAG,CAAC;EACVC,SAAS,GAAG,IAAI;EAChBC,SAAS,GAAG,KAAK;EACjBC,kBAAkB;EAClBC,KAAK;EACL,GAAGC;AACL,CAAC,EACDC,GAAG,EACH;EAAA,MAAAC,OAAA,GAAAC,MAAA;EAAA;IAAA,MAAAA,MAAA,GAAAD,OAAA,CAAAE,WAAA,CACmB;MAAEP;IAAU,CAAC;IAEhC;MAAA;MACE;MACAT,KAAA,CAACiB,IAAI;QAACJ,GAAG,EAAEA,GAAI;QAACF,KAAK,EAAE,CAACI,MAAM,CAACG,OAAO,EAAEP,KAAK,CAAE;QAAA,GAAKC,IAAI;QAAAV,QAAA,GACrDA,QAAQ,EACRM,SAAS,gBACRV,IAAA,CAACmB,IAAI;UAACE,aAAa,EAAC,UAAU;UAACR,KAAK,EAAE,CAACI,MAAM,CAACK,MAAM,EAAExB,iBAAiB,CAACO,SAAS,EAAEG,IAAI,EAAEC,MAAM,CAAC,CAAE;UAAAL,QAAA,eAChGJ,IAAA,CAACH,cAAc;YAACS,KAAK,EAAEA,KAAM;YAACC,KAAK,EAAEA,KAAM;YAACC,IAAI,EAAEA,IAAK;YAACI,kBAAkB,EAAEA;UAAmB,CAAE;QAAC,CAC9F,CAAC,GACL,IAAI;MAAA,CACJ;IAAC;EACP;AACJ,CAAC,CAAC;AAEF,SAAST,KAAK;;AAEd;AACA;AACA;AACA;AACA;AACA;AACA,MAAMc,MAAM,GAAGrB,UAAU,CAAC2B,MAAM,CAAC,OAAO;EACtCH,OAAO,EAAE;IACPI,QAAQ,EAAE,UAAU;IACpBC,QAAQ,EAAE;MACR;MACA;MACA;MACAd,SAAS,EAAE;QACTe,IAAI,EAAE;UAAEC,SAAS,EAAE;QAAU,CAAC;QAC9BC,KAAK,EAAE;UAAED,SAAS,EAAE;QAAa;MACnC;IACF,CAAC;IAAAE,iBAAA;EACH,CAAC;EACDP,MAAM,EAAE;IACNE,QAAQ,EAAE;EACZ;AACF,CAAC,CAAC,CAAC","ignoreList":[]}
|
|
@@ -18,7 +18,8 @@ const FG_TOKEN = {
|
|
|
18
18
|
};
|
|
19
19
|
const LABEL_VARIANT = {
|
|
20
20
|
sm: "label-sm",
|
|
21
|
-
md: "label-md"
|
|
21
|
+
md: "label-md",
|
|
22
|
+
lg: "label-lg"
|
|
22
23
|
};
|
|
23
24
|
/**
|
|
24
25
|
* The overlay itself: a dot, or a pill carrying the label. Owns the paint, the
|
|
@@ -109,6 +110,9 @@ const styles = StyleSheet.create(theme => {
|
|
|
109
110
|
},
|
|
110
111
|
md: {
|
|
111
112
|
borderWidth: 2
|
|
113
|
+
},
|
|
114
|
+
lg: {
|
|
115
|
+
borderWidth: 2
|
|
112
116
|
}
|
|
113
117
|
},
|
|
114
118
|
color: {
|
|
@@ -131,16 +135,23 @@ const styles = StyleSheet.create(theme => {
|
|
|
131
135
|
},
|
|
132
136
|
uni__dependencies: [0, 4]
|
|
133
137
|
},
|
|
138
|
+
// These diameters are mirrored by `DOT_SIZE` in `../utils.ts`, which the
|
|
139
|
+
// anchor arithmetic reads. The Babel plugin needs them literal here, so a
|
|
140
|
+
// test asserts the two stay equal.
|
|
134
141
|
dot: {
|
|
135
142
|
variants: {
|
|
136
143
|
size: {
|
|
137
144
|
sm: {
|
|
138
|
-
width: 10,
|
|
139
|
-
height: 10
|
|
140
|
-
},
|
|
141
|
-
md: {
|
|
142
145
|
width: 12,
|
|
143
146
|
height: 12
|
|
147
|
+
},
|
|
148
|
+
md: {
|
|
149
|
+
width: 16,
|
|
150
|
+
height: 16
|
|
151
|
+
},
|
|
152
|
+
lg: {
|
|
153
|
+
width: 20,
|
|
154
|
+
height: 20
|
|
144
155
|
}
|
|
145
156
|
}
|
|
146
157
|
},
|
|
@@ -150,14 +161,19 @@ const styles = StyleSheet.create(theme => {
|
|
|
150
161
|
variants: {
|
|
151
162
|
size: {
|
|
152
163
|
sm: {
|
|
153
|
-
height:
|
|
154
|
-
minWidth:
|
|
155
|
-
paddingHorizontal:
|
|
164
|
+
height: 18,
|
|
165
|
+
minWidth: 18,
|
|
166
|
+
paddingHorizontal: 5
|
|
156
167
|
},
|
|
157
168
|
md: {
|
|
158
|
-
height:
|
|
159
|
-
minWidth:
|
|
169
|
+
height: 22,
|
|
170
|
+
minWidth: 22,
|
|
160
171
|
paddingHorizontal: 6
|
|
172
|
+
},
|
|
173
|
+
lg: {
|
|
174
|
+
height: 26,
|
|
175
|
+
minWidth: 26,
|
|
176
|
+
paddingHorizontal: 8
|
|
161
177
|
}
|
|
162
178
|
}
|
|
163
179
|
},
|
|
@@ -181,6 +197,11 @@ const styles = StyleSheet.create(theme => {
|
|
|
181
197
|
fontSize: theme.typography.variants["label-md"].fontSize,
|
|
182
198
|
lineHeight: theme.typography.variants["label-md"].lineHeight,
|
|
183
199
|
letterSpacing: theme.typography.variants["label-md"].letterSpacing
|
|
200
|
+
},
|
|
201
|
+
lg: {
|
|
202
|
+
fontSize: theme.typography.variants["label-lg"].fontSize,
|
|
203
|
+
lineHeight: theme.typography.variants["label-lg"].lineHeight,
|
|
204
|
+
letterSpacing: theme.typography.variants["label-lg"].letterSpacing
|
|
184
205
|
}
|
|
185
206
|
}
|
|
186
207
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["StyleSheet","useUnistyles","resolveThemeColor","FONT_WEIGHT_VALUE","SYSTEM_FONT","getCustomBadgeColors","hasLabel","jsx","_jsx","SCHEME_NAMES","Set","FG_TOKEN","primary","secondary","success","warning","danger","LABEL_VARIANT","sm","md","BadgeIndicator","label","color","size","accessibilityLabel","theme","_styles","styles","useVariants","custom","has","labelled","foreground","fg","announced","String","undefined","accessibility","accessible","accessibilityElementsHidden","importantForAccessibility","View","style","indicator","pill","dot","backgroundColor","bg","children","RNText","maxFontSizeMultiplier","typography","variants","numberOfLines","create","c","labelFont","fonts","semibold","isSystemLabelFont","alignItems","justifyContent","borderRadius","radius","full","borderColor","borderWidth","uni__dependencies","width","height","minWidth","paddingHorizontal","textAlign","fontFamily","fontWeight","fontSize","lineHeight","letterSpacing"],"sourceRoot":"../../../../../src","sources":["components/badge/parts/BadgeIndicator.tsx"],"mappings":";;;;AAEA,SAASA,UAAU,EAAEC,YAAY,QAAQ,wBAAwB;AAGjE,SAASC,iBAAiB;AAC1B,SAASC,iBAAiB,EAAEC,WAAW;AAEvC,SAASC,oBAAoB,EAAEC,QAAQ;AAAmB,SAAAC,GAAA,IAAAC,IAAA;AAE1D,MAAMC,YAAY,GAAG,IAAIC,GAAG,CAAC,CAAC,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC;AAItF;AACA,MAAMC,QAAyC,GAAG;EAChDC,OAAO,EAAE,iBAAiB;EAC1BC,SAAS,EAAE,kBAAkB;EAC7BC,OAAO,EAAE,kBAAkB;EAC3BC,OAAO,EAAE,kBAAkB;EAC3BC,MAAM,EAAE;AACV,CAAC;AAED,MAAMC,aAAiD,GAAG;EACxDC,EAAE,EAAE,UAAU;EACdC,EAAE,EAAE;AACN,CAAC;AASD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,MAAMC,cAAc,GAAGA,CAAC;EAAEC,KAAK;EAAEC,KAAK;EAAEC,IAAI;EAAEC;AAAwC,CAAC,KAAK;EACjG,MAAM;IAAEC;EAAM,CAAC,
|
|
1
|
+
{"version":3,"names":["StyleSheet","useUnistyles","resolveThemeColor","FONT_WEIGHT_VALUE","SYSTEM_FONT","getCustomBadgeColors","hasLabel","jsx","_jsx","SCHEME_NAMES","Set","FG_TOKEN","primary","secondary","success","warning","danger","LABEL_VARIANT","sm","md","lg","BadgeIndicator","label","color","size","accessibilityLabel","theme","_styles","styles","useVariants","custom","has","labelled","foreground","fg","announced","String","undefined","accessibility","accessible","accessibilityElementsHidden","importantForAccessibility","View","style","indicator","pill","dot","backgroundColor","bg","children","RNText","maxFontSizeMultiplier","typography","variants","numberOfLines","create","c","labelFont","fonts","semibold","isSystemLabelFont","alignItems","justifyContent","borderRadius","radius","full","borderColor","borderWidth","uni__dependencies","width","height","minWidth","paddingHorizontal","textAlign","fontFamily","fontWeight","fontSize","lineHeight","letterSpacing"],"sourceRoot":"../../../../../src","sources":["components/badge/parts/BadgeIndicator.tsx"],"mappings":"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","ignoreList":[]}
|
|
@@ -22,4 +22,62 @@ export function getCustomBadgeColors(literal) {
|
|
|
22
22
|
export function hasLabel(label) {
|
|
23
23
|
return label !== undefined && label !== "";
|
|
24
24
|
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Outer diameter of the dot per size. The indicator's own stylesheet repeats
|
|
28
|
+
* these as literals — the unistyles Babel plugin reads that object statically,
|
|
29
|
+
* so it cannot reference this table — and `anchorOffsetsMatchDotRadius` in the
|
|
30
|
+
* test suite is what keeps the two in step.
|
|
31
|
+
*/
|
|
32
|
+
export const DOT_SIZE = {
|
|
33
|
+
sm: 12,
|
|
34
|
+
md: 16,
|
|
35
|
+
lg: 20
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Absolute insets for the indicator, in pure arithmetic rather than one
|
|
39
|
+
* compound variant per (placement, size) cell: `offset` is an open-ended number
|
|
40
|
+
* and could never be a variant condition, and nothing here touches the theme.
|
|
41
|
+
*
|
|
42
|
+
* The base inset is the dot's radius, which puts a dot's centre exactly on the
|
|
43
|
+
* child's bounding-box corner. `offset` moves it from there — positive away
|
|
44
|
+
* from the child's centre, negative toward it.
|
|
45
|
+
*/
|
|
46
|
+
export function getAnchorPosition(placement, size, offset = 0) {
|
|
47
|
+
const base = DOT_SIZE[size] / 2;
|
|
48
|
+
const {
|
|
49
|
+
x,
|
|
50
|
+
y
|
|
51
|
+
} = typeof offset === "number" ? {
|
|
52
|
+
x: offset,
|
|
53
|
+
y: offset
|
|
54
|
+
} : {
|
|
55
|
+
x: offset.x ?? 0,
|
|
56
|
+
y: offset.y ?? 0
|
|
57
|
+
};
|
|
58
|
+
const insetX = -(base + x);
|
|
59
|
+
const insetY = -(base + y);
|
|
60
|
+
switch (placement) {
|
|
61
|
+
case "top-left":
|
|
62
|
+
return {
|
|
63
|
+
top: insetY,
|
|
64
|
+
left: insetX
|
|
65
|
+
};
|
|
66
|
+
case "bottom-right":
|
|
67
|
+
return {
|
|
68
|
+
bottom: insetY,
|
|
69
|
+
right: insetX
|
|
70
|
+
};
|
|
71
|
+
case "bottom-left":
|
|
72
|
+
return {
|
|
73
|
+
bottom: insetY,
|
|
74
|
+
left: insetX
|
|
75
|
+
};
|
|
76
|
+
default:
|
|
77
|
+
return {
|
|
78
|
+
top: insetY,
|
|
79
|
+
right: insetX
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
}
|
|
25
83
|
//# sourceMappingURL=utils.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["readableOn","getCustomBadgeColors","literal","bg","fg","hasLabel","label","undefined"],"sourceRoot":"../../../../src","sources":["components/badge/utils.ts"],"mappings":";;AAAA,SAASA,UAAU;;
|
|
1
|
+
{"version":3,"names":["readableOn","getCustomBadgeColors","literal","bg","fg","hasLabel","label","undefined","DOT_SIZE","sm","md","lg","getAnchorPosition","placement","size","offset","base","x","y","insetX","insetY","top","left","bottom","right"],"sourceRoot":"../../../../src","sources":["components/badge/utils.ts"],"mappings":";;AAAA,SAASA,UAAU;;AAGnB;AACA;AACA;;AAOA;AACA,OAAO,SAASC,oBAAoBA,CAACC,OAAe,EAAqB;EACvE,OAAO;IAAEC,EAAE,EAAED,OAAO;IAAEE,EAAE,EAAEJ,UAAU,CAACE,OAAO;EAAE,CAAC;AACjD;;AAEA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASG,QAAQA,CAACC,KAAkC,EAA4B;EACrF,OAAOA,KAAK,KAAKC,SAAS,IAAID,KAAK,KAAK,EAAE;AAC5C;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,MAAME,QAAmC,GAAG;EACjDC,EAAE,EAAE,EAAE;EACNC,EAAE,EAAE,EAAE;EACNC,EAAE,EAAE;AACN,CAAC;AASD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,iBAAiBA,CAC/BC,SAAyB,EACzBC,IAAe,EACfC,MAA2C,GAAG,CAAC,EAC/B;EAChB,MAAMC,IAAI,GAAGR,QAAQ,CAACM,IAAI,CAAC,GAAG,CAAC;EAC/B,MAAM;IAAEG,CAAC;IAAEC;EAAE,CAAC,GACZ,OAAOH,MAAM,KAAK,QAAQ,GAAG;IAAEE,CAAC,EAAEF,MAAM;IAAEG,CAAC,EAAEH;EAAO,CAAC,GAAG;IAAEE,CAAC,EAAEF,MAAM,CAACE,CAAC,IAAI,CAAC;IAAEC,CAAC,EAAEH,MAAM,CAACG,CAAC,IAAI;EAAE,CAAC;EAEhG,MAAMC,MAAM,GAAG,EAAEH,IAAI,GAAGC,CAAC,CAAC;EAC1B,MAAMG,MAAM,GAAG,EAAEJ,IAAI,GAAGE,CAAC,CAAC;EAE1B,QAAQL,SAAS;IACf,KAAK,UAAU;MACb,OAAO;QAAEQ,GAAG,EAAED,MAAM;QAAEE,IAAI,EAAEH;MAAO,CAAC;IACtC,KAAK,cAAc;MACjB,OAAO;QAAEI,MAAM,EAAEH,MAAM;QAAEI,KAAK,EAAEL;MAAO,CAAC;IAC1C,KAAK,aAAa;MAChB,OAAO;QAAEI,MAAM,EAAEH,MAAM;QAAEE,IAAI,EAAEH;MAAO,CAAC;IACzC;MACE,OAAO;QAAEE,GAAG,EAAED,MAAM;QAAEI,KAAK,EAAEL;MAAO,CAAC;EACzC;AACF","ignoreList":[]}
|
|
@@ -9,7 +9,8 @@ import type { BadgeProps } from "./types.js";
|
|
|
9
9
|
* ```
|
|
10
10
|
*
|
|
11
11
|
* The child renders untouched — `Badge` contributes the positioning context and
|
|
12
|
-
* the overlay, nothing else.
|
|
12
|
+
* the overlay, nothing else. A round child usually wants a negative `offset`,
|
|
13
|
+
* since the corner being anchored to is the bounding box's, not the circle's.
|
|
13
14
|
*/
|
|
14
15
|
declare const Badge: import("react").ForwardRefExoticComponent<BadgeProps & import("react").RefAttributes<import("react-native/types_generated/src/private/webapis/dom/nodes/ReactNativeElement").default>>;
|
|
15
16
|
export { Badge };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Badge.d.ts","sourceRoot":"","sources":["../../../../../src/components/badge/Badge.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"Badge.d.ts","sourceRoot":"","sources":["../../../../../src/components/badge/Badge.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAS,CAAC;AAG1C;;;;;;;;;;;;GAYG;AACH,QAAA,MAAM,KAAK,wLA6BT,CAAC;AAEH,OAAO,EAAE,KAAK,EAAE,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BadgeIndicator.d.ts","sourceRoot":"","sources":["../../../../../../src/components/badge/parts/BadgeIndicator.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,aAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"BadgeIndicator.d.ts","sourceRoot":"","sources":["../../../../../../src/components/badge/parts/BadgeIndicator.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,aAAU,CAAC;AAsBtD,MAAM,WAAW,mBAAmB;IAClC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,KAAK,EAAE,UAAU,CAAC;IAClB,IAAI,EAAE,SAAS,CAAC;IAChB,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,cAAc,GAAI,4CAA4C,mBAAmB,gCA0C7F,CAAC"}
|
|
@@ -3,7 +3,7 @@ import type { ViewProps } from "react-native";
|
|
|
3
3
|
/** Corner of the wrapped child the indicator is anchored to. */
|
|
4
4
|
export type BadgePlacement = "top-right" | "top-left" | "bottom-right" | "bottom-left";
|
|
5
5
|
/** Scale of the dot, pill, and label. */
|
|
6
|
-
export type BadgeSize = "sm" | "md";
|
|
6
|
+
export type BadgeSize = "sm" | "md" | "lg";
|
|
7
7
|
/**
|
|
8
8
|
* Semantic color scheme, or a raw CSS color literal (`#fff`, `rgb(...)`, `hsl(...)`).
|
|
9
9
|
* A literal paints the indicator with that exact value and derives a readable
|
|
@@ -30,6 +30,19 @@ export interface BadgeProps extends ViewProps {
|
|
|
30
30
|
color?: BadgeColor;
|
|
31
31
|
/** Scale of the indicator. Defaults to `'md'`. */
|
|
32
32
|
size?: BadgeSize;
|
|
33
|
+
/**
|
|
34
|
+
* Nudges the indicator along both axes from the corner `placement` picked.
|
|
35
|
+
* Positive moves it away from the child's centre, negative pulls it in.
|
|
36
|
+
* A number applies to both axes; `{ x, y }` sets them separately.
|
|
37
|
+
*
|
|
38
|
+
* The corner it anchors to is the child's **bounding box**, so a round child
|
|
39
|
+
* needs a negative offset to bring the indicator onto the visible edge — a
|
|
40
|
+
* circle only meets its box at 45°, about `0.21 × width` away. Defaults to `0`.
|
|
41
|
+
*/
|
|
42
|
+
offset?: number | {
|
|
43
|
+
x?: number;
|
|
44
|
+
y?: number;
|
|
45
|
+
};
|
|
33
46
|
/** Renders the indicator. The child renders either way. Defaults to `true`. */
|
|
34
47
|
isVisible?: boolean;
|
|
35
48
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../src/components/badge/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAE9C,gEAAgE;AAChE,MAAM,MAAM,cAAc,GAAG,WAAW,GAAG,UAAU,GAAG,cAAc,GAAG,aAAa,CAAC;AAEvF,yCAAyC;AACzC,MAAM,MAAM,SAAS,GAAG,IAAI,GAAG,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../src/components/badge/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAE9C,gEAAgE;AAChE,MAAM,MAAM,cAAc,GAAG,WAAW,GAAG,UAAU,GAAG,cAAc,GAAG,aAAa,CAAC;AAEvF,yCAAyC;AACzC,MAAM,MAAM,SAAS,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAE3C;;;;GAIG;AACH,MAAM,MAAM,UAAU,GAClB,SAAS,GACT,WAAW,GACX,SAAS,GACT,SAAS,GACT,QAAQ,GAER,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;AAElB,MAAM,WAAW,UAAW,SAAQ,SAAS;IAC3C,mFAAmF;IACnF,QAAQ,EAAE,SAAS,CAAC;IACpB;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,cAAc,CAAC;IAC3B;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,oEAAoE;IACpE,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,kDAAkD;IAClD,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB;;;;;;;;OAQG;IACH,MAAM,CAAC,EAAE,MAAM,GAAG;QAAE,CAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7C,+EAA+E;IAC/E,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;;;OAKG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;OAGG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { BadgePlacement, BadgeSize } from "./types.js";
|
|
1
2
|
export interface CustomBadgeColors {
|
|
2
3
|
bg: string;
|
|
3
4
|
fg: string;
|
|
@@ -10,4 +11,30 @@ export declare function getCustomBadgeColors(literal: string): CustomBadgeColors
|
|
|
10
11
|
* `isVisible` rather than relying on falsiness.
|
|
11
12
|
*/
|
|
12
13
|
export declare function hasLabel(label: string | number | undefined): label is string | number;
|
|
14
|
+
/**
|
|
15
|
+
* Outer diameter of the dot per size. The indicator's own stylesheet repeats
|
|
16
|
+
* these as literals — the unistyles Babel plugin reads that object statically,
|
|
17
|
+
* so it cannot reference this table — and `anchorOffsetsMatchDotRadius` in the
|
|
18
|
+
* test suite is what keeps the two in step.
|
|
19
|
+
*/
|
|
20
|
+
export declare const DOT_SIZE: Record<BadgeSize, number>;
|
|
21
|
+
export interface AnchorPosition {
|
|
22
|
+
top?: number;
|
|
23
|
+
right?: number;
|
|
24
|
+
bottom?: number;
|
|
25
|
+
left?: number;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Absolute insets for the indicator, in pure arithmetic rather than one
|
|
29
|
+
* compound variant per (placement, size) cell: `offset` is an open-ended number
|
|
30
|
+
* and could never be a variant condition, and nothing here touches the theme.
|
|
31
|
+
*
|
|
32
|
+
* The base inset is the dot's radius, which puts a dot's centre exactly on the
|
|
33
|
+
* child's bounding-box corner. `offset` moves it from there — positive away
|
|
34
|
+
* from the child's centre, negative toward it.
|
|
35
|
+
*/
|
|
36
|
+
export declare function getAnchorPosition(placement: BadgePlacement, size: BadgeSize, offset?: number | {
|
|
37
|
+
x?: number;
|
|
38
|
+
y?: number;
|
|
39
|
+
}): AnchorPosition;
|
|
13
40
|
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../../../src/components/badge/utils.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../../../src/components/badge/utils.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,YAAS,CAAC;AAMzD,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,0FAA0F;AAC1F,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,iBAAiB,CAEvE;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,GAAG,KAAK,IAAI,MAAM,GAAG,MAAM,CAErF;AAED;;;;;GAKG;AACH,eAAO,MAAM,QAAQ,EAAE,MAAM,CAAC,SAAS,EAAE,MAAM,CAI9C,CAAC;AAEF,MAAM,WAAW,cAAc;IAC7B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,cAAc,EACzB,IAAI,EAAE,SAAS,EACf,MAAM,GAAE,MAAM,GAAG;IAAE,CAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,CAAC,EAAE,MAAM,CAAA;CAAM,GAC9C,cAAc,CAkBhB"}
|
package/package.json
CHANGED
|
@@ -5,6 +5,7 @@ import { StyleSheet } from "react-native-unistyles";
|
|
|
5
5
|
|
|
6
6
|
import { BadgeIndicator } from "./parts/BadgeIndicator";
|
|
7
7
|
import type { BadgeProps } from "./types";
|
|
8
|
+
import { getAnchorPosition } from "./utils";
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* Overlays a count or status indicator on one corner of the element it wraps.
|
|
@@ -16,7 +17,8 @@ import type { BadgeProps } from "./types";
|
|
|
16
17
|
* ```
|
|
17
18
|
*
|
|
18
19
|
* The child renders untouched — `Badge` contributes the positioning context and
|
|
19
|
-
* the overlay, nothing else.
|
|
20
|
+
* the overlay, nothing else. A round child usually wants a negative `offset`,
|
|
21
|
+
* since the corner being anchored to is the bounding box's, not the circle's.
|
|
20
22
|
*/
|
|
21
23
|
const Badge = forwardRef<ComponentRef<typeof View>, BadgeProps>(function Badge(
|
|
22
24
|
{
|
|
@@ -25,6 +27,7 @@ const Badge = forwardRef<ComponentRef<typeof View>, BadgeProps>(function Badge(
|
|
|
25
27
|
label,
|
|
26
28
|
color = "danger",
|
|
27
29
|
size = "md",
|
|
30
|
+
offset = 0,
|
|
28
31
|
isVisible = true,
|
|
29
32
|
fullWidth = false,
|
|
30
33
|
accessibilityLabel,
|
|
@@ -33,14 +36,14 @@ const Badge = forwardRef<ComponentRef<typeof View>, BadgeProps>(function Badge(
|
|
|
33
36
|
},
|
|
34
37
|
ref
|
|
35
38
|
) {
|
|
36
|
-
styles.useVariants({
|
|
39
|
+
styles.useVariants({ fullWidth });
|
|
37
40
|
|
|
38
41
|
return (
|
|
39
42
|
// `style` last so an explicit `alignSelf` beats `fullWidth`.
|
|
40
43
|
<View ref={ref} style={[styles.wrapper, style]} {...rest}>
|
|
41
44
|
{children}
|
|
42
45
|
{isVisible ? (
|
|
43
|
-
<View pointerEvents="box-none" style={styles.anchor}>
|
|
46
|
+
<View pointerEvents="box-none" style={[styles.anchor, getAnchorPosition(placement, size, offset)]}>
|
|
44
47
|
<BadgeIndicator label={label} color={color} size={size} accessibilityLabel={accessibilityLabel} />
|
|
45
48
|
</View>
|
|
46
49
|
) : null}
|
|
@@ -52,14 +55,10 @@ export { Badge };
|
|
|
52
55
|
|
|
53
56
|
// ─── Styles ───────────────────────────────────────────────────────────────────
|
|
54
57
|
//
|
|
55
|
-
// The indicator
|
|
56
|
-
//
|
|
57
|
-
//
|
|
58
|
-
//
|
|
59
|
-
//
|
|
60
|
-
// The inset equals the dot's radius, which puts a dot's centre exactly on the
|
|
61
|
-
// child's corner. A pill keeps the same anchored edges and grows inward from
|
|
62
|
-
// them, so a longer label extends across the child rather than away from it.
|
|
58
|
+
// The indicator's insets are computed in `getAnchorPosition`, not declared here:
|
|
59
|
+
// `offset` is an open-ended number, so it could never be a variant condition,
|
|
60
|
+
// and the position involves no theme tokens at all. That leaves this stylesheet
|
|
61
|
+
// with only what genuinely varies declaratively.
|
|
63
62
|
const styles = StyleSheet.create(() => ({
|
|
64
63
|
wrapper: {
|
|
65
64
|
position: "relative",
|
|
@@ -71,41 +70,9 @@ const styles = StyleSheet.create(() => ({
|
|
|
71
70
|
true: { alignSelf: "stretch" },
|
|
72
71
|
false: { alignSelf: "flex-start" },
|
|
73
72
|
},
|
|
74
|
-
placement: {
|
|
75
|
-
"top-right": {},
|
|
76
|
-
"top-left": {},
|
|
77
|
-
"bottom-right": {},
|
|
78
|
-
"bottom-left": {},
|
|
79
|
-
},
|
|
80
|
-
size: {
|
|
81
|
-
sm: {},
|
|
82
|
-
md: {},
|
|
83
|
-
},
|
|
84
73
|
},
|
|
85
74
|
},
|
|
86
75
|
anchor: {
|
|
87
76
|
position: "absolute",
|
|
88
|
-
variants: {
|
|
89
|
-
placement: {
|
|
90
|
-
"top-right": {},
|
|
91
|
-
"top-left": {},
|
|
92
|
-
"bottom-right": {},
|
|
93
|
-
"bottom-left": {},
|
|
94
|
-
},
|
|
95
|
-
size: {
|
|
96
|
-
sm: {},
|
|
97
|
-
md: {},
|
|
98
|
-
},
|
|
99
|
-
},
|
|
100
|
-
compoundVariants: [
|
|
101
|
-
{ placement: "top-right", size: "sm", styles: { top: -5, right: -5 } },
|
|
102
|
-
{ placement: "top-right", size: "md", styles: { top: -6, right: -6 } },
|
|
103
|
-
{ placement: "top-left", size: "sm", styles: { top: -5, left: -5 } },
|
|
104
|
-
{ placement: "top-left", size: "md", styles: { top: -6, left: -6 } },
|
|
105
|
-
{ placement: "bottom-right", size: "sm", styles: { bottom: -5, right: -5 } },
|
|
106
|
-
{ placement: "bottom-right", size: "md", styles: { bottom: -6, right: -6 } },
|
|
107
|
-
{ placement: "bottom-left", size: "sm", styles: { bottom: -5, left: -5 } },
|
|
108
|
-
{ placement: "bottom-left", size: "md", styles: { bottom: -6, left: -6 } },
|
|
109
|
-
],
|
|
110
77
|
},
|
|
111
78
|
}));
|
|
@@ -24,6 +24,7 @@ const FG_TOKEN: Record<BadgeScheme, ColorToken> = {
|
|
|
24
24
|
const LABEL_VARIANT: Record<BadgeSize, RoleTextVariant> = {
|
|
25
25
|
sm: "label-sm",
|
|
26
26
|
md: "label-md",
|
|
27
|
+
lg: "label-lg",
|
|
27
28
|
};
|
|
28
29
|
|
|
29
30
|
export interface BadgeIndicatorProps {
|
|
@@ -114,6 +115,7 @@ const styles = StyleSheet.create((theme) => {
|
|
|
114
115
|
size: {
|
|
115
116
|
sm: { borderWidth: 1.5 },
|
|
116
117
|
md: { borderWidth: 2 },
|
|
118
|
+
lg: { borderWidth: 2 },
|
|
117
119
|
},
|
|
118
120
|
color: {
|
|
119
121
|
primary: { backgroundColor: c["accent.solid.bg"] },
|
|
@@ -124,19 +126,24 @@ const styles = StyleSheet.create((theme) => {
|
|
|
124
126
|
},
|
|
125
127
|
},
|
|
126
128
|
},
|
|
129
|
+
// These diameters are mirrored by `DOT_SIZE` in `../utils.ts`, which the
|
|
130
|
+
// anchor arithmetic reads. The Babel plugin needs them literal here, so a
|
|
131
|
+
// test asserts the two stay equal.
|
|
127
132
|
dot: {
|
|
128
133
|
variants: {
|
|
129
134
|
size: {
|
|
130
|
-
sm: { width:
|
|
131
|
-
md: { width:
|
|
135
|
+
sm: { width: 12, height: 12 },
|
|
136
|
+
md: { width: 16, height: 16 },
|
|
137
|
+
lg: { width: 20, height: 20 },
|
|
132
138
|
},
|
|
133
139
|
},
|
|
134
140
|
},
|
|
135
141
|
pill: {
|
|
136
142
|
variants: {
|
|
137
143
|
size: {
|
|
138
|
-
sm: { height:
|
|
139
|
-
md: { height:
|
|
144
|
+
sm: { height: 18, minWidth: 18, paddingHorizontal: 5 },
|
|
145
|
+
md: { height: 22, minWidth: 22, paddingHorizontal: 6 },
|
|
146
|
+
lg: { height: 26, minWidth: 26, paddingHorizontal: 8 },
|
|
140
147
|
},
|
|
141
148
|
},
|
|
142
149
|
},
|
|
@@ -159,6 +166,11 @@ const styles = StyleSheet.create((theme) => {
|
|
|
159
166
|
lineHeight: theme.typography.variants["label-md"].lineHeight,
|
|
160
167
|
letterSpacing: theme.typography.variants["label-md"].letterSpacing,
|
|
161
168
|
},
|
|
169
|
+
lg: {
|
|
170
|
+
fontSize: theme.typography.variants["label-lg"].fontSize,
|
|
171
|
+
lineHeight: theme.typography.variants["label-lg"].lineHeight,
|
|
172
|
+
letterSpacing: theme.typography.variants["label-lg"].letterSpacing,
|
|
173
|
+
},
|
|
162
174
|
},
|
|
163
175
|
},
|
|
164
176
|
},
|
|
@@ -5,7 +5,7 @@ import type { ViewProps } from "react-native";
|
|
|
5
5
|
export type BadgePlacement = "top-right" | "top-left" | "bottom-right" | "bottom-left";
|
|
6
6
|
|
|
7
7
|
/** Scale of the dot, pill, and label. */
|
|
8
|
-
export type BadgeSize = "sm" | "md";
|
|
8
|
+
export type BadgeSize = "sm" | "md" | "lg";
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Semantic color scheme, or a raw CSS color literal (`#fff`, `rgb(...)`, `hsl(...)`).
|
|
@@ -41,6 +41,16 @@ export interface BadgeProps extends ViewProps {
|
|
|
41
41
|
color?: BadgeColor;
|
|
42
42
|
/** Scale of the indicator. Defaults to `'md'`. */
|
|
43
43
|
size?: BadgeSize;
|
|
44
|
+
/**
|
|
45
|
+
* Nudges the indicator along both axes from the corner `placement` picked.
|
|
46
|
+
* Positive moves it away from the child's centre, negative pulls it in.
|
|
47
|
+
* A number applies to both axes; `{ x, y }` sets them separately.
|
|
48
|
+
*
|
|
49
|
+
* The corner it anchors to is the child's **bounding box**, so a round child
|
|
50
|
+
* needs a negative offset to bring the indicator onto the visible edge — a
|
|
51
|
+
* circle only meets its box at 45°, about `0.21 × width` away. Defaults to `0`.
|
|
52
|
+
*/
|
|
53
|
+
offset?: number | { x?: number; y?: number };
|
|
44
54
|
/** Renders the indicator. The child renders either way. Defaults to `true`. */
|
|
45
55
|
isVisible?: boolean;
|
|
46
56
|
/**
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { readableOn } from "#utils/color-utils";
|
|
2
|
+
import type { BadgePlacement, BadgeSize } from "./types";
|
|
2
3
|
|
|
3
4
|
// A custom color literal (hex/rgb/hsl) isn't a bounded set of options, so it
|
|
4
5
|
// can't be a unistyles variant condition — it's derived here instead, the same
|
|
@@ -22,3 +23,55 @@ export function getCustomBadgeColors(literal: string): CustomBadgeColors {
|
|
|
22
23
|
export function hasLabel(label: string | number | undefined): label is string | number {
|
|
23
24
|
return label !== undefined && label !== "";
|
|
24
25
|
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Outer diameter of the dot per size. The indicator's own stylesheet repeats
|
|
29
|
+
* these as literals — the unistyles Babel plugin reads that object statically,
|
|
30
|
+
* so it cannot reference this table — and `anchorOffsetsMatchDotRadius` in the
|
|
31
|
+
* test suite is what keeps the two in step.
|
|
32
|
+
*/
|
|
33
|
+
export const DOT_SIZE: Record<BadgeSize, number> = {
|
|
34
|
+
sm: 12,
|
|
35
|
+
md: 16,
|
|
36
|
+
lg: 20,
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export interface AnchorPosition {
|
|
40
|
+
top?: number;
|
|
41
|
+
right?: number;
|
|
42
|
+
bottom?: number;
|
|
43
|
+
left?: number;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Absolute insets for the indicator, in pure arithmetic rather than one
|
|
48
|
+
* compound variant per (placement, size) cell: `offset` is an open-ended number
|
|
49
|
+
* and could never be a variant condition, and nothing here touches the theme.
|
|
50
|
+
*
|
|
51
|
+
* The base inset is the dot's radius, which puts a dot's centre exactly on the
|
|
52
|
+
* child's bounding-box corner. `offset` moves it from there — positive away
|
|
53
|
+
* from the child's centre, negative toward it.
|
|
54
|
+
*/
|
|
55
|
+
export function getAnchorPosition(
|
|
56
|
+
placement: BadgePlacement,
|
|
57
|
+
size: BadgeSize,
|
|
58
|
+
offset: number | { x?: number; y?: number } = 0
|
|
59
|
+
): AnchorPosition {
|
|
60
|
+
const base = DOT_SIZE[size] / 2;
|
|
61
|
+
const { x, y } =
|
|
62
|
+
typeof offset === "number" ? { x: offset, y: offset } : { x: offset.x ?? 0, y: offset.y ?? 0 };
|
|
63
|
+
|
|
64
|
+
const insetX = -(base + x);
|
|
65
|
+
const insetY = -(base + y);
|
|
66
|
+
|
|
67
|
+
switch (placement) {
|
|
68
|
+
case "top-left":
|
|
69
|
+
return { top: insetY, left: insetX };
|
|
70
|
+
case "bottom-right":
|
|
71
|
+
return { bottom: insetY, right: insetX };
|
|
72
|
+
case "bottom-left":
|
|
73
|
+
return { bottom: insetY, left: insetX };
|
|
74
|
+
default:
|
|
75
|
+
return { top: insetY, right: insetX };
|
|
76
|
+
}
|
|
77
|
+
}
|