@butternutbox/pawprint-native 0.15.0 → 0.15.1

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.1",
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
  })