@mgcrea/react-native-tailwind 0.3.0 → 0.5.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.
Files changed (71) hide show
  1. package/README.md +459 -39
  2. package/dist/babel/index.cjs +810 -279
  3. package/dist/babel/index.d.ts +2 -1
  4. package/dist/babel/index.ts +328 -22
  5. package/dist/components/Pressable.d.ts +32 -0
  6. package/dist/components/Pressable.js +1 -0
  7. package/dist/components/TextInput.d.ts +56 -0
  8. package/dist/components/TextInput.js +1 -0
  9. package/dist/index.d.ts +9 -2
  10. package/dist/index.js +1 -1
  11. package/dist/parser/aspectRatio.d.ts +16 -0
  12. package/dist/parser/aspectRatio.js +1 -0
  13. package/dist/parser/aspectRatio.test.d.ts +1 -0
  14. package/dist/parser/aspectRatio.test.js +1 -0
  15. package/dist/parser/borders.js +1 -1
  16. package/dist/parser/borders.test.d.ts +1 -0
  17. package/dist/parser/borders.test.js +1 -0
  18. package/dist/parser/colors.d.ts +1 -0
  19. package/dist/parser/colors.js +1 -1
  20. package/dist/parser/colors.test.d.ts +1 -0
  21. package/dist/parser/colors.test.js +1 -0
  22. package/dist/parser/index.d.ts +4 -0
  23. package/dist/parser/index.js +1 -1
  24. package/dist/parser/layout.d.ts +2 -0
  25. package/dist/parser/layout.js +1 -1
  26. package/dist/parser/layout.test.d.ts +1 -0
  27. package/dist/parser/layout.test.js +1 -0
  28. package/dist/parser/modifiers.d.ts +47 -0
  29. package/dist/parser/modifiers.js +1 -0
  30. package/dist/parser/modifiers.test.d.ts +1 -0
  31. package/dist/parser/modifiers.test.js +1 -0
  32. package/dist/parser/shadows.d.ts +26 -0
  33. package/dist/parser/shadows.js +1 -0
  34. package/dist/parser/shadows.test.d.ts +1 -0
  35. package/dist/parser/shadows.test.js +1 -0
  36. package/dist/parser/sizing.test.d.ts +1 -0
  37. package/dist/parser/sizing.test.js +1 -0
  38. package/dist/parser/spacing.d.ts +1 -1
  39. package/dist/parser/spacing.js +1 -1
  40. package/dist/parser/spacing.test.d.ts +1 -0
  41. package/dist/parser/spacing.test.js +1 -0
  42. package/dist/parser/typography.d.ts +2 -1
  43. package/dist/parser/typography.js +1 -1
  44. package/dist/parser/typography.test.d.ts +1 -0
  45. package/dist/parser/typography.test.js +1 -0
  46. package/dist/types.d.ts +5 -2
  47. package/package.json +7 -6
  48. package/src/babel/index.ts +328 -22
  49. package/src/components/Pressable.tsx +46 -0
  50. package/src/components/TextInput.tsx +90 -0
  51. package/src/index.ts +20 -2
  52. package/src/parser/aspectRatio.test.ts +191 -0
  53. package/src/parser/aspectRatio.ts +73 -0
  54. package/src/parser/borders.test.ts +329 -0
  55. package/src/parser/borders.ts +187 -108
  56. package/src/parser/colors.test.ts +335 -0
  57. package/src/parser/colors.ts +117 -6
  58. package/src/parser/index.ts +13 -2
  59. package/src/parser/layout.test.ts +459 -0
  60. package/src/parser/layout.ts +128 -0
  61. package/src/parser/modifiers.test.ts +375 -0
  62. package/src/parser/modifiers.ts +104 -0
  63. package/src/parser/shadows.test.ts +201 -0
  64. package/src/parser/shadows.ts +133 -0
  65. package/src/parser/sizing.test.ts +256 -0
  66. package/src/parser/spacing.test.ts +226 -0
  67. package/src/parser/spacing.ts +93 -138
  68. package/src/parser/typography.test.ts +221 -0
  69. package/src/parser/typography.ts +143 -112
  70. package/src/types.ts +2 -2
  71. package/dist/react-native.d.js +0 -1
@@ -43,92 +43,85 @@ export const SPACING_SCALE: Record<string, number> = {
43
43
  };
44
44
 
45
45
  /**
46
- * Parse spacing classes (margin, padding, gap)
47
- * Examples: m-4, mx-2, mt-8, p-4, px-2, pt-8, gap-4
46
+ * Parse arbitrary spacing value: [16px], [20]
47
+ * Returns number for px values, null for unsupported formats
48
48
  */
49
- export function parseSpacing(cls: string): StyleObject | null {
50
- // Margin
51
- if (cls.startsWith("m-") || cls.startsWith("m")) {
52
- return parseMargin(cls);
53
- }
54
-
55
- // Padding
56
- if (cls.startsWith("p-") || cls.startsWith("p")) {
57
- return parsePadding(cls);
58
- }
59
-
60
- // Gap
61
- if (cls.startsWith("gap-")) {
62
- return parseGap(cls);
49
+ function parseArbitrarySpacing(value: string): number | null {
50
+ // Match: [16px] or [16] (pixels only)
51
+ const pxMatch = value.match(/^\[(\d+)(?:px)?\]$/);
52
+ if (pxMatch) {
53
+ return parseInt(pxMatch[1], 10);
54
+ }
55
+
56
+ // Warn about unsupported formats
57
+ if (value.startsWith("[") && value.endsWith("]")) {
58
+ if (process.env.NODE_ENV !== "production") {
59
+ console.warn(
60
+ `[react-native-tailwind] Unsupported arbitrary spacing value: ${value}. Only px values are supported (e.g., [16px] or [16]).`,
61
+ );
62
+ }
63
+ return null;
63
64
  }
64
65
 
65
66
  return null;
66
67
  }
67
68
 
68
69
  /**
69
- * Parse margin classes
70
+ * Parse spacing classes (margin, padding, gap)
71
+ * Examples: m-4, mx-2, mt-8, p-4, px-2, pt-8, gap-4, m-[16px]
70
72
  */
71
- function parseMargin(cls: string): StyleObject | null {
72
- // m-4 -> margin: 16
73
- const allMatch = cls.match(/^m-(\d+(?:\.\d+)?)$/);
74
- if (allMatch) {
75
- const value = SPACING_SCALE[allMatch[1]];
76
- if (value !== undefined) {
77
- return { margin: value };
73
+ export function parseSpacing(cls: string): StyleObject | null {
74
+ // Margin: m-4, mx-2, mt-8, m-[16px], etc.
75
+ const marginMatch = cls.match(/^m([xytrbls]?)-(.+)$/);
76
+ if (marginMatch) {
77
+ const [, dir, valueStr] = marginMatch;
78
+
79
+ // Try arbitrary value first
80
+ const arbitraryValue = parseArbitrarySpacing(valueStr);
81
+ if (arbitraryValue !== null) {
82
+ return getMarginStyle(dir, arbitraryValue);
78
83
  }
79
- }
80
84
 
81
- // mx-4 -> marginHorizontal: 16
82
- const xMatch = cls.match(/^mx-(\d+(?:\.\d+)?)$/);
83
- if (xMatch) {
84
- const value = SPACING_SCALE[xMatch[1]];
85
- if (value !== undefined) {
86
- return { marginHorizontal: value };
85
+ // Try preset scale
86
+ const scaleValue = SPACING_SCALE[valueStr];
87
+ if (scaleValue !== undefined) {
88
+ return getMarginStyle(dir, scaleValue);
87
89
  }
88
90
  }
89
91
 
90
- // my-4 -> marginVertical: 16
91
- const yMatch = cls.match(/^my-(\d+(?:\.\d+)?)$/);
92
- if (yMatch) {
93
- const value = SPACING_SCALE[yMatch[1]];
94
- if (value !== undefined) {
95
- return { marginVertical: value };
96
- }
97
- }
92
+ // Padding: p-4, px-2, pt-8, p-[16px], etc.
93
+ const paddingMatch = cls.match(/^p([xytrbls]?)-(.+)$/);
94
+ if (paddingMatch) {
95
+ const [, dir, valueStr] = paddingMatch;
98
96
 
99
- // mt-4 -> marginTop: 16
100
- const tMatch = cls.match(/^mt-(\d+(?:\.\d+)?)$/);
101
- if (tMatch) {
102
- const value = SPACING_SCALE[tMatch[1]];
103
- if (value !== undefined) {
104
- return { marginTop: value };
97
+ // Try arbitrary value first
98
+ const arbitraryValue = parseArbitrarySpacing(valueStr);
99
+ if (arbitraryValue !== null) {
100
+ return getPaddingStyle(dir, arbitraryValue);
105
101
  }
106
- }
107
102
 
108
- // mr-4 -> marginRight: 16
109
- const rMatch = cls.match(/^mr-(\d+(?:\.\d+)?)$/);
110
- if (rMatch) {
111
- const value = SPACING_SCALE[rMatch[1]];
112
- if (value !== undefined) {
113
- return { marginRight: value };
103
+ // Try preset scale
104
+ const scaleValue = SPACING_SCALE[valueStr];
105
+ if (scaleValue !== undefined) {
106
+ return getPaddingStyle(dir, scaleValue);
114
107
  }
115
108
  }
116
109
 
117
- // mb-4 -> marginBottom: 16
118
- const bMatch = cls.match(/^mb-(\d+(?:\.\d+)?)$/);
119
- if (bMatch) {
120
- const value = SPACING_SCALE[bMatch[1]];
121
- if (value !== undefined) {
122
- return { marginBottom: value };
110
+ // Gap: gap-4, gap-[16px]
111
+ const gapMatch = cls.match(/^gap-(.+)$/);
112
+ if (gapMatch) {
113
+ const valueStr = gapMatch[1];
114
+
115
+ // Try arbitrary value first
116
+ const arbitraryValue = parseArbitrarySpacing(valueStr);
117
+ if (arbitraryValue !== null) {
118
+ return { gap: arbitraryValue };
123
119
  }
124
- }
125
120
 
126
- // ml-4 -> marginLeft: 16
127
- const lMatch = cls.match(/^ml-(\d+(?:\.\d+)?)$/);
128
- if (lMatch) {
129
- const value = SPACING_SCALE[lMatch[1]];
130
- if (value !== undefined) {
131
- return { marginLeft: value };
121
+ // Try preset scale
122
+ const scaleValue = SPACING_SCALE[valueStr];
123
+ if (scaleValue !== undefined) {
124
+ return { gap: scaleValue };
132
125
  }
133
126
  }
134
127
 
@@ -136,87 +129,49 @@ function parseMargin(cls: string): StyleObject | null {
136
129
  }
137
130
 
138
131
  /**
139
- * Parse padding classes
132
+ * Get margin style object based on direction
140
133
  */
141
- function parsePadding(cls: string): StyleObject | null {
142
- // p-4 -> padding: 16
143
- const allMatch = cls.match(/^p-(\d+(?:\.\d+)?)$/);
144
- if (allMatch) {
145
- const value = SPACING_SCALE[allMatch[1]];
146
- if (value !== undefined) {
147
- return { padding: value };
148
- }
134
+ function getMarginStyle(dir: string, value: number): StyleObject {
135
+ switch (dir) {
136
+ case "":
137
+ return { margin: value };
138
+ case "x":
139
+ return { marginHorizontal: value };
140
+ case "y":
141
+ return { marginVertical: value };
142
+ case "t":
143
+ return { marginTop: value };
144
+ case "r":
145
+ return { marginRight: value };
146
+ case "b":
147
+ return { marginBottom: value };
148
+ case "l":
149
+ return { marginLeft: value };
150
+ default:
151
+ return {};
149
152
  }
153
+ }
150
154
 
151
- // px-4 -> paddingHorizontal: 16
152
- const xMatch = cls.match(/^px-(\d+(?:\.\d+)?)$/);
153
- if (xMatch) {
154
- const value = SPACING_SCALE[xMatch[1]];
155
- if (value !== undefined) {
155
+ /**
156
+ * Get padding style object based on direction
157
+ */
158
+ function getPaddingStyle(dir: string, value: number): StyleObject {
159
+ switch (dir) {
160
+ case "":
161
+ return { padding: value };
162
+ case "x":
156
163
  return { paddingHorizontal: value };
157
- }
158
- }
159
-
160
- // py-4 -> paddingVertical: 16
161
- const yMatch = cls.match(/^py-(\d+(?:\.\d+)?)$/);
162
- if (yMatch) {
163
- const value = SPACING_SCALE[yMatch[1]];
164
- if (value !== undefined) {
164
+ case "y":
165
165
  return { paddingVertical: value };
166
- }
167
- }
168
-
169
- // pt-4 -> paddingTop: 16
170
- const tMatch = cls.match(/^pt-(\d+(?:\.\d+)?)$/);
171
- if (tMatch) {
172
- const value = SPACING_SCALE[tMatch[1]];
173
- if (value !== undefined) {
166
+ case "t":
174
167
  return { paddingTop: value };
175
- }
176
- }
177
-
178
- // pr-4 -> paddingRight: 16
179
- const rMatch = cls.match(/^pr-(\d+(?:\.\d+)?)$/);
180
- if (rMatch) {
181
- const value = SPACING_SCALE[rMatch[1]];
182
- if (value !== undefined) {
168
+ case "r":
183
169
  return { paddingRight: value };
184
- }
185
- }
186
-
187
- // pb-4 -> paddingBottom: 16
188
- const bMatch = cls.match(/^pb-(\d+(?:\.\d+)?)$/);
189
- if (bMatch) {
190
- const value = SPACING_SCALE[bMatch[1]];
191
- if (value !== undefined) {
170
+ case "b":
192
171
  return { paddingBottom: value };
193
- }
194
- }
195
-
196
- // pl-4 -> paddingLeft: 16
197
- const lMatch = cls.match(/^pl-(\d+(?:\.\d+)?)$/);
198
- if (lMatch) {
199
- const value = SPACING_SCALE[lMatch[1]];
200
- if (value !== undefined) {
172
+ case "l":
201
173
  return { paddingLeft: value };
202
- }
174
+ default:
175
+ return {};
203
176
  }
204
-
205
- return null;
206
- }
207
-
208
- /**
209
- * Parse gap classes
210
- */
211
- function parseGap(cls: string): StyleObject | null {
212
- // gap-4 -> gap: 16
213
- const match = cls.match(/^gap-(\d+(?:\.\d+)?)$/);
214
- if (match) {
215
- const value = SPACING_SCALE[match[1]];
216
- if (value !== undefined) {
217
- return { gap: value };
218
- }
219
- }
220
-
221
- return null;
222
177
  }
@@ -0,0 +1,221 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { FONT_SIZES, LETTER_SPACING_SCALE, parseTypography } from "./typography";
3
+
4
+ describe("FONT_SIZES", () => {
5
+ it("should export complete font size scale", () => {
6
+ expect(FONT_SIZES).toMatchSnapshot();
7
+ });
8
+ });
9
+
10
+ describe("LETTER_SPACING_SCALE", () => {
11
+ it("should export complete letter spacing scale", () => {
12
+ expect(LETTER_SPACING_SCALE).toMatchSnapshot();
13
+ });
14
+ });
15
+
16
+ describe("parseTypography - font size", () => {
17
+ it("should parse font size with preset values", () => {
18
+ expect(parseTypography("text-xs")).toEqual({ fontSize: 12 });
19
+ expect(parseTypography("text-sm")).toEqual({ fontSize: 14 });
20
+ expect(parseTypography("text-base")).toEqual({ fontSize: 16 });
21
+ expect(parseTypography("text-lg")).toEqual({ fontSize: 18 });
22
+ expect(parseTypography("text-xl")).toEqual({ fontSize: 20 });
23
+ expect(parseTypography("text-2xl")).toEqual({ fontSize: 24 });
24
+ expect(parseTypography("text-3xl")).toEqual({ fontSize: 30 });
25
+ expect(parseTypography("text-4xl")).toEqual({ fontSize: 36 });
26
+ expect(parseTypography("text-5xl")).toEqual({ fontSize: 48 });
27
+ expect(parseTypography("text-6xl")).toEqual({ fontSize: 60 });
28
+ expect(parseTypography("text-7xl")).toEqual({ fontSize: 72 });
29
+ expect(parseTypography("text-8xl")).toEqual({ fontSize: 96 });
30
+ expect(parseTypography("text-9xl")).toEqual({ fontSize: 128 });
31
+ });
32
+
33
+ it("should parse font size with arbitrary pixel values", () => {
34
+ expect(parseTypography("text-[18px]")).toEqual({ fontSize: 18 });
35
+ expect(parseTypography("text-[18]")).toEqual({ fontSize: 18 });
36
+ expect(parseTypography("text-[22px]")).toEqual({ fontSize: 22 });
37
+ expect(parseTypography("text-[22]")).toEqual({ fontSize: 22 });
38
+ expect(parseTypography("text-[100px]")).toEqual({ fontSize: 100 });
39
+ });
40
+ });
41
+
42
+ describe("parseTypography - font weight", () => {
43
+ it("should parse font weight values", () => {
44
+ expect(parseTypography("font-thin")).toEqual({ fontWeight: "100" });
45
+ expect(parseTypography("font-extralight")).toEqual({ fontWeight: "200" });
46
+ expect(parseTypography("font-light")).toEqual({ fontWeight: "300" });
47
+ expect(parseTypography("font-normal")).toEqual({ fontWeight: "400" });
48
+ expect(parseTypography("font-medium")).toEqual({ fontWeight: "500" });
49
+ expect(parseTypography("font-semibold")).toEqual({ fontWeight: "600" });
50
+ expect(parseTypography("font-bold")).toEqual({ fontWeight: "700" });
51
+ expect(parseTypography("font-extrabold")).toEqual({ fontWeight: "800" });
52
+ expect(parseTypography("font-black")).toEqual({ fontWeight: "900" });
53
+ });
54
+ });
55
+
56
+ describe("parseTypography - font style", () => {
57
+ it("should parse font style values", () => {
58
+ expect(parseTypography("italic")).toEqual({ fontStyle: "italic" });
59
+ expect(parseTypography("not-italic")).toEqual({ fontStyle: "normal" });
60
+ });
61
+ });
62
+
63
+ describe("parseTypography - text alignment", () => {
64
+ it("should parse text alignment values", () => {
65
+ expect(parseTypography("text-left")).toEqual({ textAlign: "left" });
66
+ expect(parseTypography("text-center")).toEqual({ textAlign: "center" });
67
+ expect(parseTypography("text-right")).toEqual({ textAlign: "right" });
68
+ expect(parseTypography("text-justify")).toEqual({ textAlign: "justify" });
69
+ });
70
+ });
71
+
72
+ describe("parseTypography - text decoration", () => {
73
+ it("should parse text decoration values", () => {
74
+ expect(parseTypography("underline")).toEqual({
75
+ textDecorationLine: "underline",
76
+ });
77
+ expect(parseTypography("line-through")).toEqual({
78
+ textDecorationLine: "line-through",
79
+ });
80
+ expect(parseTypography("no-underline")).toEqual({
81
+ textDecorationLine: "none",
82
+ });
83
+ });
84
+ });
85
+
86
+ describe("parseTypography - text transform", () => {
87
+ it("should parse text transform values", () => {
88
+ expect(parseTypography("uppercase")).toEqual({
89
+ textTransform: "uppercase",
90
+ });
91
+ expect(parseTypography("lowercase")).toEqual({
92
+ textTransform: "lowercase",
93
+ });
94
+ expect(parseTypography("capitalize")).toEqual({
95
+ textTransform: "capitalize",
96
+ });
97
+ expect(parseTypography("normal-case")).toEqual({ textTransform: "none" });
98
+ });
99
+ });
100
+
101
+ describe("parseTypography - line height", () => {
102
+ it("should parse line height with preset values", () => {
103
+ expect(parseTypography("leading-none")).toEqual({ lineHeight: 16 });
104
+ expect(parseTypography("leading-tight")).toEqual({ lineHeight: 20 });
105
+ expect(parseTypography("leading-snug")).toEqual({ lineHeight: 22 });
106
+ expect(parseTypography("leading-normal")).toEqual({ lineHeight: 24 });
107
+ expect(parseTypography("leading-relaxed")).toEqual({ lineHeight: 28 });
108
+ expect(parseTypography("leading-loose")).toEqual({ lineHeight: 32 });
109
+ });
110
+
111
+ it("should parse line height with arbitrary pixel values", () => {
112
+ expect(parseTypography("leading-[24px]")).toEqual({ lineHeight: 24 });
113
+ expect(parseTypography("leading-[24]")).toEqual({ lineHeight: 24 });
114
+ expect(parseTypography("leading-[30px]")).toEqual({ lineHeight: 30 });
115
+ expect(parseTypography("leading-[30]")).toEqual({ lineHeight: 30 });
116
+ expect(parseTypography("leading-[50px]")).toEqual({ lineHeight: 50 });
117
+ });
118
+ });
119
+
120
+ describe("parseTypography - letter spacing", () => {
121
+ it("should parse letter spacing with preset values", () => {
122
+ expect(parseTypography("tracking-tighter")).toEqual({
123
+ letterSpacing: -0.8,
124
+ });
125
+ expect(parseTypography("tracking-tight")).toEqual({ letterSpacing: -0.4 });
126
+ expect(parseTypography("tracking-normal")).toEqual({ letterSpacing: 0 });
127
+ expect(parseTypography("tracking-wide")).toEqual({ letterSpacing: 0.4 });
128
+ expect(parseTypography("tracking-wider")).toEqual({ letterSpacing: 0.8 });
129
+ expect(parseTypography("tracking-widest")).toEqual({ letterSpacing: 1.6 });
130
+ });
131
+ });
132
+
133
+ describe("parseTypography - edge cases", () => {
134
+ it("should return null for invalid classes", () => {
135
+ expect(parseTypography("invalid")).toBeNull();
136
+ expect(parseTypography("text")).toBeNull();
137
+ expect(parseTypography("font")).toBeNull();
138
+ expect(parseTypography("leading")).toBeNull();
139
+ expect(parseTypography("tracking")).toBeNull();
140
+ });
141
+
142
+ it("should return null for invalid font size values", () => {
143
+ expect(parseTypography("text-invalid")).toBeNull();
144
+ expect(parseTypography("text-10xl")).toBeNull();
145
+ });
146
+
147
+ it("should return null for invalid font weight values", () => {
148
+ expect(parseTypography("font-invalid")).toBeNull();
149
+ expect(parseTypography("font-100")).toBeNull();
150
+ });
151
+
152
+ it("should return null for arbitrary values with unsupported units", () => {
153
+ expect(parseTypography("text-[16rem]")).toBeNull();
154
+ expect(parseTypography("text-[2em]")).toBeNull();
155
+ expect(parseTypography("leading-[2rem]")).toBeNull();
156
+ expect(parseTypography("leading-[1.5em]")).toBeNull();
157
+ });
158
+
159
+ it("should return null for malformed arbitrary values", () => {
160
+ expect(parseTypography("text-[16")).toBeNull();
161
+ expect(parseTypography("text-16]")).toBeNull();
162
+ expect(parseTypography("text-[]")).toBeNull();
163
+ expect(parseTypography("leading-[24")).toBeNull();
164
+ expect(parseTypography("leading-24]")).toBeNull();
165
+ });
166
+
167
+ it("should not match partial class names", () => {
168
+ expect(parseTypography("mytext-lg")).toBeNull();
169
+ expect(parseTypography("font-bold-extra")).toBeNull();
170
+ expect(parseTypography("italic-text")).toBeNull();
171
+ });
172
+ });
173
+
174
+ describe("parseTypography - comprehensive coverage", () => {
175
+ it("should handle all typography categories independently", () => {
176
+ // Font size
177
+ expect(parseTypography("text-base")).toEqual({ fontSize: 16 });
178
+ // Font weight
179
+ expect(parseTypography("font-bold")).toEqual({ fontWeight: "700" });
180
+ // Font style
181
+ expect(parseTypography("italic")).toEqual({ fontStyle: "italic" });
182
+ // Text alignment
183
+ expect(parseTypography("text-center")).toEqual({ textAlign: "center" });
184
+ // Text decoration
185
+ expect(parseTypography("underline")).toEqual({
186
+ textDecorationLine: "underline",
187
+ });
188
+ // Text transform
189
+ expect(parseTypography("uppercase")).toEqual({
190
+ textTransform: "uppercase",
191
+ });
192
+ // Line height
193
+ expect(parseTypography("leading-normal")).toEqual({ lineHeight: 24 });
194
+ // Letter spacing
195
+ expect(parseTypography("tracking-wide")).toEqual({ letterSpacing: 0.4 });
196
+ });
197
+
198
+ it("should handle arbitrary values for font size and line height", () => {
199
+ expect(parseTypography("text-[19px]")).toEqual({ fontSize: 19 });
200
+ expect(parseTypography("text-[19]")).toEqual({ fontSize: 19 });
201
+ expect(parseTypography("leading-[26px]")).toEqual({ lineHeight: 26 });
202
+ expect(parseTypography("leading-[26]")).toEqual({ lineHeight: 26 });
203
+ });
204
+
205
+ it("should handle edge case values", () => {
206
+ // Smallest font size
207
+ expect(parseTypography("text-xs")).toEqual({ fontSize: 12 });
208
+ // Largest font size
209
+ expect(parseTypography("text-9xl")).toEqual({ fontSize: 128 });
210
+ // Smallest line height
211
+ expect(parseTypography("leading-none")).toEqual({ lineHeight: 16 });
212
+ // Largest line height
213
+ expect(parseTypography("leading-loose")).toEqual({ lineHeight: 32 });
214
+ // Negative letter spacing
215
+ expect(parseTypography("tracking-tighter")).toEqual({
216
+ letterSpacing: -0.8,
217
+ });
218
+ // Positive letter spacing
219
+ expect(parseTypography("tracking-widest")).toEqual({ letterSpacing: 1.6 });
220
+ });
221
+ });