@butternutbox/pawprint-native 0.15.0 → 0.15.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@butternutbox/pawprint-native",
3
- "version": "0.15.0",
3
+ "version": "0.15.2",
4
4
  "type": "module",
5
5
  "description": "ButternutBox Pawprint Design System - React Native Components",
6
6
  "main": "./dist/index.cjs",
@@ -140,7 +140,16 @@ const VARIANT_DEFAULTS = {
140
140
  display: { size: "lg" } as const
141
141
  }
142
142
 
143
- const StyledText = styled(Text)({})
143
+ // Android reserves extra vertical padding from the font's ascent/descent
144
+ // (`includeFontPadding`, on by default) and top-aligns glyphs within that box.
145
+ // With the tall Ida Narrow metrics this shifts/clips copy — headings and button
146
+ // labels that sit on one line on iOS get squeezed or clipped on Android. Turning
147
+ // it off and centring vertically makes Android match iOS. Both props are
148
+ // Android-only; iOS ignores them.
149
+ const StyledText = styled(Text)({
150
+ includeFontPadding: false,
151
+ textAlignVertical: "center"
152
+ })
144
153
 
145
154
  /**
146
155
  * Typography component for body text, headings, and display copy.
@@ -3,6 +3,8 @@ import { View, Text } from "react-native"
3
3
  import Animated from "react-native-reanimated"
4
4
  import { DEFAULT_THEME_OPTIONS } from "@butternutbox/pawprint-tokens"
5
5
 
6
+ import { resolveFont } from "../../../fonts"
7
+
6
8
  type AndroidOptionTextProps = {
7
9
  isSelected: boolean
8
10
  }
@@ -16,6 +18,31 @@ const parseSize = (value: string): number => {
16
18
  return parseInt(value.replace("px", ""), 10)
17
19
  }
18
20
 
21
+ type TypographyToken = {
22
+ fontFamily: string
23
+ fontWeight: string
24
+ fontSize: string
25
+ letterSpacing?: string
26
+ }
27
+
28
+ // Resolve the brand PostScript font from a typography token. Without this the
29
+ // text falls back to the system font (the weight-encoded family isn't set by
30
+ // fontWeight alone), so we resolve fontFamily and drop the separate fontWeight.
31
+ const resolveTypography = (
32
+ typography: TypographyToken
33
+ ): { fontFamily: string; fontSize: number; letterSpacing: number } => {
34
+ const { fontFamily } = resolveFont(
35
+ typography.fontFamily,
36
+ typography.fontWeight
37
+ )
38
+ const fontSize = parseSize(typography.fontSize)
39
+ const letterSpacing = typography.letterSpacing?.endsWith("%")
40
+ ? (parseFloat(typography.letterSpacing) / 100) * fontSize
41
+ : parseFloat(typography.letterSpacing ?? "0")
42
+
43
+ return { fontFamily, fontSize, letterSpacing }
44
+ }
45
+
19
46
  const Wrapper = styled(View)({
20
47
  borderWidth: parseSize(inputTokens.borderWidth.field.selected),
21
48
  borderColor: inputTokens.colour.field.border.selected,
@@ -37,15 +64,13 @@ const SelectIcon = styled(Animated.View)({
37
64
 
38
65
  const InputText = styled(Text)({
39
66
  color: inputTokens.colour.field.text.default,
40
- fontSize: parseSize(inputTokens.field.placeholder.default.fontSize),
41
- fontWeight: inputTokens.field.placeholder.default.fontWeight,
67
+ ...resolveTypography(inputTokens.field.placeholder.default),
42
68
  flex: 1
43
69
  })
44
70
 
45
71
  const PlaceholderText = styled(Text)({
46
72
  color: inputTokens.colour.field.text.placeholder,
47
- fontSize: parseSize(inputTokens.field.placeholder.default.fontSize),
48
- fontWeight: inputTokens.field.placeholder.default.fontWeight,
73
+ ...resolveTypography(inputTokens.field.placeholder.default),
49
74
  flex: 1
50
75
  })
51
76
 
@@ -67,8 +92,7 @@ const AndroidDialog = styled(View)({
67
92
  })
68
93
 
69
94
  const DialogTitle = styled(Text)({
70
- fontSize: parseSize(inputTokens.field.placeholder.default.fontSize),
71
- fontWeight: inputTokens.text.label.fontWeight,
95
+ ...resolveTypography(inputTokens.text.label),
72
96
  color: inputTokens.colour.field.text.default,
73
97
  marginBottom: parseSize(dimensions.spacing.md),
74
98
  marginLeft: parseSize(dimensions.spacing.xs)
@@ -103,10 +127,11 @@ const RadioInner = styled(View)({
103
127
 
104
128
  const AndroidOptionText = styled(Text)<AndroidOptionTextProps>(
105
129
  ({ isSelected }) => ({
106
- fontSize: parseSize(inputTokens.field.placeholder.default.fontSize),
107
- fontWeight: isSelected
108
- ? inputTokens.text.label.fontWeight
109
- : inputTokens.field.placeholder.default.fontWeight,
130
+ ...resolveTypography(
131
+ isSelected
132
+ ? inputTokens.text.label
133
+ : inputTokens.field.placeholder.default
134
+ ),
110
135
  color: inputTokens.colour.field.text.default,
111
136
  flex: 1
112
137
  })
@@ -143,6 +143,27 @@ export const InContext = () => (
143
143
  </View>
144
144
  )
145
145
 
146
+ export const RichText = () => (
147
+ <View style={styles.column}>
148
+ <Typography variant="heading" size="sm">
149
+ Rich text — emphasise part of the copy
150
+ </Typography>
151
+ <Tooltip
152
+ alignment="left"
153
+ position="bottom"
154
+ text={
155
+ <React.Fragment>
156
+ Your order is below{" "}
157
+ <Typography variant="body" weight="bold" size="md">
158
+ £8.00
159
+ </Typography>{" "}
160
+ minimum. Add more items to remove this fee.
161
+ </React.Fragment>
162
+ }
163
+ />
164
+ </View>
165
+ )
166
+
146
167
  const styles = StyleSheet.create({
147
168
  container: {
148
169
  padding: 24,
@@ -12,7 +12,14 @@ type TooltipAlignment = "left" | "middle" | "right"
12
12
  type TooltipPosition = "top" | "bottom"
13
13
 
14
14
  type TooltipOwnProps = {
15
- text: string
15
+ /**
16
+ * Tooltip body content. Pass a plain string for simple copy, or a
17
+ * `ReactNode` (e.g. a `<Trans>` / nested `<Text>`) when part of the text
18
+ * needs its own styling — bold, colour, underline, etc. A node is rendered
19
+ * inside the tooltip's own `<Typography>`, so it inherits the base font and
20
+ * only the emphasised spans override it.
21
+ */
22
+ text: string | React.ReactNode
16
23
  alignment?: TooltipAlignment
17
24
  position?: TooltipPosition
18
25
  /**
@@ -221,7 +228,7 @@ export const Tooltip = React.forwardRef<View, TooltipProps>(
221
228
  ref={ref}
222
229
  accessible={true}
223
230
  accessibilityRole="none"
224
- accessibilityLabel={text}
231
+ accessibilityLabel={typeof text === "string" ? text : undefined}
225
232
  accessibilityLiveRegion="polite"
226
233
  {...props}
227
234
  >