@mgcrea/react-native-tailwind 0.10.0 → 0.11.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/README.md +159 -13
- package/dist/babel/config-loader.d.ts +12 -3
- package/dist/babel/config-loader.test.ts +14 -12
- package/dist/babel/config-loader.ts +41 -9
- package/dist/babel/index.cjs +91 -54
- package/dist/babel/plugin.d.ts +39 -1
- package/dist/babel/plugin.test.ts +275 -1
- package/dist/babel/plugin.ts +84 -25
- package/dist/babel/utils/colorSchemeModifierProcessing.d.ts +3 -3
- package/dist/babel/utils/colorSchemeModifierProcessing.ts +4 -4
- package/dist/babel/utils/dynamicProcessing.d.ts +5 -5
- package/dist/babel/utils/dynamicProcessing.ts +11 -11
- package/dist/babel/utils/modifierProcessing.d.ts +3 -3
- package/dist/babel/utils/modifierProcessing.ts +5 -5
- package/dist/babel/utils/platformModifierProcessing.d.ts +3 -3
- package/dist/babel/utils/platformModifierProcessing.ts +4 -4
- package/dist/babel/utils/styleInjection.d.ts +5 -3
- package/dist/babel/utils/styleInjection.ts +38 -23
- package/dist/babel/utils/twProcessing.d.ts +3 -3
- package/dist/babel/utils/twProcessing.ts +6 -6
- package/dist/parser/index.d.ts +11 -4
- package/dist/parser/index.js +1 -1
- package/dist/parser/typography.d.ts +3 -1
- package/dist/parser/typography.js +1 -1
- package/dist/runtime.cjs +1 -1
- package/dist/runtime.cjs.map +3 -3
- package/dist/runtime.d.ts +8 -1
- package/dist/runtime.js +1 -1
- package/dist/runtime.js.map +3 -3
- package/dist/runtime.test.js +1 -1
- package/package.json +1 -1
- package/src/babel/config-loader.test.ts +14 -12
- package/src/babel/config-loader.ts +41 -9
- package/src/babel/plugin.test.ts +275 -1
- package/src/babel/plugin.ts +84 -25
- package/src/babel/utils/colorSchemeModifierProcessing.ts +4 -4
- package/src/babel/utils/dynamicProcessing.ts +11 -11
- package/src/babel/utils/modifierProcessing.ts +5 -5
- package/src/babel/utils/platformModifierProcessing.ts +4 -4
- package/src/babel/utils/styleInjection.ts +38 -23
- package/src/babel/utils/twProcessing.ts +6 -6
- package/src/parser/index.ts +16 -8
- package/src/parser/typography.ts +14 -2
- package/src/runtime.test.ts +7 -7
- package/src/runtime.ts +37 -14
package/README.md
CHANGED
|
@@ -425,7 +425,7 @@ export function RuntimeExample() {
|
|
|
425
425
|
|
|
426
426
|
#### Configuration
|
|
427
427
|
|
|
428
|
-
Configure custom colors and
|
|
428
|
+
Configure custom colors and font families using `setConfig()`:
|
|
429
429
|
|
|
430
430
|
```typescript
|
|
431
431
|
import { setConfig } from '@mgcrea/react-native-tailwind/runtime';
|
|
@@ -442,13 +442,17 @@ setConfig({
|
|
|
442
442
|
dark: '#CC0000',
|
|
443
443
|
},
|
|
444
444
|
},
|
|
445
|
+
fontFamily: {
|
|
446
|
+
sans: ['"SF Pro Rounded"'],
|
|
447
|
+
custom: ['"My Custom Font"'],
|
|
448
|
+
},
|
|
445
449
|
},
|
|
446
450
|
},
|
|
447
451
|
});
|
|
448
452
|
|
|
449
|
-
// Now you can use custom
|
|
453
|
+
// Now you can use custom theme
|
|
450
454
|
<View style={tw`bg-primary p-4`} />
|
|
451
|
-
<Text style={tw`text-brand-light`}>Custom
|
|
455
|
+
<Text style={tw`text-brand-light font-custom`}>Custom styling</Text>
|
|
452
456
|
```
|
|
453
457
|
|
|
454
458
|
#### API Reference
|
|
@@ -1365,7 +1369,7 @@ This pattern allows you to build component libraries with optimized default styl
|
|
|
1365
1369
|
|
|
1366
1370
|
**Available shades:** `50`, `100`, `200`, `300`, `400`, `500`, `600`, `700`, `800`, `900`
|
|
1367
1371
|
|
|
1368
|
-
> **Note:** You can extend the color palette with custom colors via `tailwind.config.*` — see [Custom
|
|
1372
|
+
> **Note:** You can extend the color palette with custom colors via `tailwind.config.*` — see [Custom Theme Extensions](#custom-theme-extensions)
|
|
1369
1373
|
|
|
1370
1374
|
**Opacity Modifiers:**
|
|
1371
1375
|
|
|
@@ -1883,6 +1887,135 @@ const styles = StyleSheet.create({
|
|
|
1883
1887
|
- Choose a name that won't conflict with existing variables in your files
|
|
1884
1888
|
- The same identifier is used across all files in your project
|
|
1885
1889
|
|
|
1890
|
+
### Custom Color Scheme Hook
|
|
1891
|
+
|
|
1892
|
+
By default, the plugin uses React Native's built-in `useColorScheme()` hook for `dark:` and `light:` modifiers. You can configure it to use a custom color scheme hook from theme providers like React Navigation, Expo, or your own implementation.
|
|
1893
|
+
|
|
1894
|
+
**Configuration:**
|
|
1895
|
+
|
|
1896
|
+
```javascript
|
|
1897
|
+
// babel.config.js
|
|
1898
|
+
module.exports = {
|
|
1899
|
+
plugins: [
|
|
1900
|
+
[
|
|
1901
|
+
"@mgcrea/react-native-tailwind/babel",
|
|
1902
|
+
{
|
|
1903
|
+
colorScheme: {
|
|
1904
|
+
importFrom: "@/hooks/useColorScheme", // Module to import from
|
|
1905
|
+
importName: "useColorScheme", // Hook name to import
|
|
1906
|
+
},
|
|
1907
|
+
},
|
|
1908
|
+
],
|
|
1909
|
+
],
|
|
1910
|
+
};
|
|
1911
|
+
```
|
|
1912
|
+
|
|
1913
|
+
**Use Cases:**
|
|
1914
|
+
|
|
1915
|
+
#### 1. Custom Theme Provider
|
|
1916
|
+
|
|
1917
|
+
Override system color scheme with user preferences from a store:
|
|
1918
|
+
|
|
1919
|
+
```typescript
|
|
1920
|
+
// src/hooks/useColorScheme.ts
|
|
1921
|
+
import { useColorScheme as useSystemColorScheme } from "react-native";
|
|
1922
|
+
import { profileStore } from "@/stores/profileStore";
|
|
1923
|
+
import { type ColorSchemeName } from "react-native";
|
|
1924
|
+
|
|
1925
|
+
export const useColorScheme = (): ColorSchemeName => {
|
|
1926
|
+
const systemColorScheme = useSystemColorScheme();
|
|
1927
|
+
const userTheme = profileStore.theme; // 'dark' | 'light' | 'auto'
|
|
1928
|
+
|
|
1929
|
+
// Return user preference, or fall back to system if set to 'auto'
|
|
1930
|
+
return userTheme === 'auto' ? systemColorScheme : userTheme;
|
|
1931
|
+
};
|
|
1932
|
+
```
|
|
1933
|
+
|
|
1934
|
+
```javascript
|
|
1935
|
+
// babel.config.js
|
|
1936
|
+
{
|
|
1937
|
+
colorScheme: {
|
|
1938
|
+
importFrom: "@/hooks/useColorScheme",
|
|
1939
|
+
importName: "useColorScheme"
|
|
1940
|
+
}
|
|
1941
|
+
}
|
|
1942
|
+
```
|
|
1943
|
+
|
|
1944
|
+
#### 2. React Navigation Theme
|
|
1945
|
+
|
|
1946
|
+
Integrate with React Navigation's theme system:
|
|
1947
|
+
|
|
1948
|
+
```typescript
|
|
1949
|
+
// Wrap React Navigation's useTheme to return ColorSchemeName
|
|
1950
|
+
import { useTheme as useNavTheme } from "@react-navigation/native";
|
|
1951
|
+
import { type ColorSchemeName } from "react-native";
|
|
1952
|
+
|
|
1953
|
+
export const useColorScheme = (): ColorSchemeName => {
|
|
1954
|
+
const { dark } = useNavTheme();
|
|
1955
|
+
return dark ? "dark" : "light";
|
|
1956
|
+
};
|
|
1957
|
+
```
|
|
1958
|
+
|
|
1959
|
+
#### 3. Expo Router Theme
|
|
1960
|
+
|
|
1961
|
+
Use Expo Router's theme hook:
|
|
1962
|
+
|
|
1963
|
+
```javascript
|
|
1964
|
+
// babel.config.js
|
|
1965
|
+
{
|
|
1966
|
+
colorScheme: {
|
|
1967
|
+
importFrom: "expo-router",
|
|
1968
|
+
importName: "useColorScheme"
|
|
1969
|
+
}
|
|
1970
|
+
}
|
|
1971
|
+
```
|
|
1972
|
+
|
|
1973
|
+
#### 4. Testing
|
|
1974
|
+
|
|
1975
|
+
Mock color scheme for tests:
|
|
1976
|
+
|
|
1977
|
+
```typescript
|
|
1978
|
+
// test/mocks/useColorScheme.ts
|
|
1979
|
+
export const useColorScheme = () => "light"; // Or "dark" for dark mode tests
|
|
1980
|
+
```
|
|
1981
|
+
|
|
1982
|
+
```javascript
|
|
1983
|
+
// babel.config.js (test environment)
|
|
1984
|
+
{
|
|
1985
|
+
colorScheme: {
|
|
1986
|
+
importFrom: "@/test/mocks/useColorScheme",
|
|
1987
|
+
importName: "useColorScheme"
|
|
1988
|
+
}
|
|
1989
|
+
}
|
|
1990
|
+
```
|
|
1991
|
+
|
|
1992
|
+
#### How it works
|
|
1993
|
+
|
|
1994
|
+
When you use `dark:` or `light:` modifiers:
|
|
1995
|
+
|
|
1996
|
+
```tsx
|
|
1997
|
+
<View className="bg-white dark:bg-gray-900" />
|
|
1998
|
+
```
|
|
1999
|
+
|
|
2000
|
+
The plugin will:
|
|
2001
|
+
|
|
2002
|
+
1. Import your custom hook: `import { useColorScheme } from "@/hooks/useColorScheme"`
|
|
2003
|
+
2. Inject it in components: `const _twColorScheme = useColorScheme();`
|
|
2004
|
+
3. Generate conditionals: `_twColorScheme === "dark" && styles._dark_bg_gray_900`
|
|
2005
|
+
|
|
2006
|
+
#### Default behavior (no configuration)
|
|
2007
|
+
|
|
2008
|
+
Without custom configuration, the plugin uses React Native's built-in hook:
|
|
2009
|
+
|
|
2010
|
+
- Import: `import { useColorScheme } from "react-native"`
|
|
2011
|
+
- This works out of the box for basic system color scheme detection
|
|
2012
|
+
|
|
2013
|
+
#### Requirements
|
|
2014
|
+
|
|
2015
|
+
- Your custom hook must return `ColorSchemeName` (type from React Native: `"light" | "dark" | null | undefined`)
|
|
2016
|
+
- The hook must be compatible with React's rules of hooks (can only be called in function components)
|
|
2017
|
+
- Import merging works automatically if you already import from the same source
|
|
2018
|
+
|
|
1886
2019
|
### Arbitrary Values
|
|
1887
2020
|
|
|
1888
2021
|
Use arbitrary values for custom sizes, spacing, and borders not in the preset scales:
|
|
@@ -1911,9 +2044,9 @@ Use arbitrary values for custom sizes, spacing, and borders not in the preset sc
|
|
|
1911
2044
|
|
|
1912
2045
|
> **Note:** CSS units (`rem`, `em`, `vh`, `vw`) are not supported by React Native.
|
|
1913
2046
|
|
|
1914
|
-
### Custom
|
|
2047
|
+
### Custom Theme Extensions
|
|
1915
2048
|
|
|
1916
|
-
Extend the default color palette via `tailwind.config.*` in your project root:
|
|
2049
|
+
Extend the default color palette and font families via `tailwind.config.*` in your project root:
|
|
1917
2050
|
|
|
1918
2051
|
```javascript
|
|
1919
2052
|
// tailwind.config.mjs
|
|
@@ -1929,16 +2062,21 @@ export default {
|
|
|
1929
2062
|
dark: "#0c4a6e",
|
|
1930
2063
|
},
|
|
1931
2064
|
},
|
|
2065
|
+
fontFamily: {
|
|
2066
|
+
sans: ['"SF Pro Rounded"'],
|
|
2067
|
+
custom: ['"My Custom Font"'],
|
|
2068
|
+
},
|
|
1932
2069
|
},
|
|
1933
2070
|
},
|
|
1934
2071
|
};
|
|
1935
2072
|
```
|
|
1936
2073
|
|
|
1937
|
-
Then use your custom
|
|
2074
|
+
Then use your custom theme:
|
|
1938
2075
|
|
|
1939
2076
|
```tsx
|
|
1940
2077
|
<View className="bg-primary p-4">
|
|
1941
|
-
<Text className="text-brand">Custom branded text</Text>
|
|
2078
|
+
<Text className="text-brand font-custom">Custom branded text</Text>
|
|
2079
|
+
<Text className="font-sans">SF Pro Rounded text</Text>
|
|
1942
2080
|
<View className="bg-brand-light rounded-lg" />
|
|
1943
2081
|
</View>
|
|
1944
2082
|
```
|
|
@@ -1946,13 +2084,14 @@ Then use your custom colors:
|
|
|
1946
2084
|
**How it works:**
|
|
1947
2085
|
|
|
1948
2086
|
- Babel plugin discovers config by traversing up from source files
|
|
1949
|
-
- Custom
|
|
1950
|
-
- Nested objects flattened with dash notation: `brand.light` → `brand-light`
|
|
2087
|
+
- Custom theme merged with defaults at build time (custom takes precedence)
|
|
2088
|
+
- Nested color objects flattened with dash notation: `brand.light` → `brand-light`
|
|
2089
|
+
- Font families use first font in array (React Native doesn't support font stacks)
|
|
1951
2090
|
- Zero runtime overhead — all loading happens during compilation
|
|
1952
2091
|
|
|
1953
2092
|
**Supported formats:** `.js`, `.mjs`, `.cjs`, `.ts`
|
|
1954
2093
|
|
|
1955
|
-
> **Tip:** Use `theme.extend
|
|
2094
|
+
> **Tip:** Use `theme.extend.*` to keep defaults. Using `theme.colors` or `theme.fontFamily` directly will override all defaults.
|
|
1956
2095
|
|
|
1957
2096
|
### Programmatic API
|
|
1958
2097
|
|
|
@@ -1961,10 +2100,17 @@ Access the parser and constants programmatically:
|
|
|
1961
2100
|
```typescript
|
|
1962
2101
|
import { parseClassName, COLORS, SPACING_SCALE } from "@mgcrea/react-native-tailwind";
|
|
1963
2102
|
|
|
1964
|
-
// Parse className strings
|
|
1965
|
-
const
|
|
2103
|
+
// Parse className strings (no custom theme)
|
|
2104
|
+
const styles = parseClassName("m-4 p-2 bg-blue-500");
|
|
1966
2105
|
// Returns: { margin: 16, padding: 8, backgroundColor: '#3B82F6' }
|
|
1967
2106
|
|
|
2107
|
+
// Parse with custom theme
|
|
2108
|
+
const customStyles = parseClassName("m-4 bg-primary font-custom", {
|
|
2109
|
+
colors: { primary: "#1d4ed8" },
|
|
2110
|
+
fontFamily: { custom: "My Custom Font" },
|
|
2111
|
+
});
|
|
2112
|
+
// Returns: { margin: 16, backgroundColor: '#1d4ed8', fontFamily: 'My Custom Font' }
|
|
2113
|
+
|
|
1968
2114
|
// Access default scales
|
|
1969
2115
|
const blueColor = COLORS["blue-500"]; // '#3B82F6'
|
|
1970
2116
|
const spacing = SPACING_SCALE[4]; // 16
|
|
@@ -6,8 +6,10 @@ export type TailwindConfig = {
|
|
|
6
6
|
theme?: {
|
|
7
7
|
extend?: {
|
|
8
8
|
colors?: Record<string, string | Record<string, string>>;
|
|
9
|
+
fontFamily?: Record<string, string | string[]>;
|
|
9
10
|
};
|
|
10
11
|
colors?: Record<string, string | Record<string, string>>;
|
|
12
|
+
fontFamily?: Record<string, string | string[]>;
|
|
11
13
|
};
|
|
12
14
|
};
|
|
13
15
|
/**
|
|
@@ -19,7 +21,14 @@ export declare function findTailwindConfig(startDir: string): string | null;
|
|
|
19
21
|
*/
|
|
20
22
|
export declare function loadTailwindConfig(configPath: string): TailwindConfig | null;
|
|
21
23
|
/**
|
|
22
|
-
*
|
|
23
|
-
* Prefers theme.extend.colors over theme.colors to avoid overriding defaults
|
|
24
|
+
* Custom theme configuration extracted from tailwind.config
|
|
24
25
|
*/
|
|
25
|
-
export
|
|
26
|
+
export type CustomTheme = {
|
|
27
|
+
colors: Record<string, string>;
|
|
28
|
+
fontFamily: Record<string, string>;
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Extract all custom theme extensions from tailwind config
|
|
32
|
+
* Prefers theme.extend.* over theme.* to avoid overriding defaults
|
|
33
|
+
*/
|
|
34
|
+
export declare function extractCustomTheme(filename: string): CustomTheme;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as fs from "fs";
|
|
2
2
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
3
|
-
import {
|
|
3
|
+
import { extractCustomTheme, findTailwindConfig, loadTailwindConfig } from "./config-loader";
|
|
4
4
|
|
|
5
5
|
// Mock fs
|
|
6
6
|
vi.mock("fs");
|
|
@@ -115,15 +115,15 @@ describe("config-loader", () => {
|
|
|
115
115
|
});
|
|
116
116
|
});
|
|
117
117
|
|
|
118
|
-
describe("
|
|
119
|
-
it("should return empty
|
|
118
|
+
describe("extractCustomTheme", () => {
|
|
119
|
+
it("should return empty theme when no config found", () => {
|
|
120
120
|
vi.spyOn(fs, "existsSync").mockReturnValue(false);
|
|
121
121
|
|
|
122
|
-
const result =
|
|
123
|
-
expect(result).toEqual({});
|
|
122
|
+
const result = extractCustomTheme("/project/src/file.ts");
|
|
123
|
+
expect(result).toEqual({ colors: {}, fontFamily: {} });
|
|
124
124
|
});
|
|
125
125
|
|
|
126
|
-
it("should return empty
|
|
126
|
+
it("should return empty theme when config has no theme", () => {
|
|
127
127
|
const configPath = "/project/tailwind.config.js";
|
|
128
128
|
|
|
129
129
|
vi.spyOn(fs, "existsSync").mockImplementation((filepath) => filepath === configPath);
|
|
@@ -131,22 +131,24 @@ describe("config-loader", () => {
|
|
|
131
131
|
|
|
132
132
|
// loadTailwindConfig will be called, but we've already tested it
|
|
133
133
|
// For integration, we'd need to mock the entire flow
|
|
134
|
-
const result =
|
|
134
|
+
const result = extractCustomTheme("/project/src/file.ts");
|
|
135
135
|
|
|
136
136
|
// Without actual config loading, this returns empty
|
|
137
|
-
expect(result).toEqual({});
|
|
137
|
+
expect(result).toEqual({ colors: {}, fontFamily: {} });
|
|
138
138
|
});
|
|
139
139
|
|
|
140
|
-
it("should extract colors from theme.extend
|
|
140
|
+
it("should extract colors and fontFamily from theme.extend", () => {
|
|
141
141
|
// This would require complex mocking of the entire require flow
|
|
142
|
-
// Testing the logic: theme.extend
|
|
142
|
+
// Testing the logic: theme.extend is preferred
|
|
143
143
|
const colors = { brand: { light: "#fff", dark: "#000" } };
|
|
144
|
+
const fontFamily = { sans: ['"SF Pro"'], custom: ['"Custom Font"'] };
|
|
144
145
|
const theme = {
|
|
145
|
-
extend: { colors },
|
|
146
|
+
extend: { colors, fontFamily },
|
|
146
147
|
};
|
|
147
148
|
|
|
148
|
-
// If we had the config, we'd flatten the colors
|
|
149
|
+
// If we had the config, we'd flatten the colors and convert fontFamily
|
|
149
150
|
expect(theme.extend.colors).toEqual(colors);
|
|
151
|
+
expect(theme.extend.fontFamily).toEqual(fontFamily);
|
|
150
152
|
});
|
|
151
153
|
});
|
|
152
154
|
});
|
|
@@ -13,8 +13,10 @@ export type TailwindConfig = {
|
|
|
13
13
|
theme?: {
|
|
14
14
|
extend?: {
|
|
15
15
|
colors?: Record<string, string | Record<string, string>>;
|
|
16
|
+
fontFamily?: Record<string, string | string[]>;
|
|
16
17
|
};
|
|
17
18
|
colors?: Record<string, string | Record<string, string>>;
|
|
19
|
+
fontFamily?: Record<string, string | string[]>;
|
|
18
20
|
};
|
|
19
21
|
};
|
|
20
22
|
|
|
@@ -82,23 +84,31 @@ export function loadTailwindConfig(configPath: string): TailwindConfig | null {
|
|
|
82
84
|
}
|
|
83
85
|
|
|
84
86
|
/**
|
|
85
|
-
*
|
|
86
|
-
* Prefers theme.extend.colors over theme.colors to avoid overriding defaults
|
|
87
|
+
* Custom theme configuration extracted from tailwind.config
|
|
87
88
|
*/
|
|
88
|
-
export
|
|
89
|
+
export type CustomTheme = {
|
|
90
|
+
colors: Record<string, string>;
|
|
91
|
+
fontFamily: Record<string, string>;
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Extract all custom theme extensions from tailwind config
|
|
96
|
+
* Prefers theme.extend.* over theme.* to avoid overriding defaults
|
|
97
|
+
*/
|
|
98
|
+
export function extractCustomTheme(filename: string): CustomTheme {
|
|
89
99
|
const projectDir = path.dirname(filename);
|
|
90
100
|
const configPath = findTailwindConfig(projectDir);
|
|
91
101
|
|
|
92
102
|
if (!configPath) {
|
|
93
|
-
return {};
|
|
103
|
+
return { colors: {}, fontFamily: {} };
|
|
94
104
|
}
|
|
95
105
|
|
|
96
106
|
const config = loadTailwindConfig(configPath);
|
|
97
107
|
if (!config?.theme) {
|
|
98
|
-
return {};
|
|
108
|
+
return { colors: {}, fontFamily: {} };
|
|
99
109
|
}
|
|
100
110
|
|
|
101
|
-
//
|
|
111
|
+
// Extract colors
|
|
102
112
|
/* v8 ignore next 5 */
|
|
103
113
|
if (config.theme.colors && !config.theme.extend?.colors && process.env.NODE_ENV !== "production") {
|
|
104
114
|
console.warn(
|
|
@@ -106,9 +116,31 @@ export function extractCustomColors(filename: string): Record<string, string> {
|
|
|
106
116
|
"Use theme.extend.colors to add custom colors while keeping defaults.",
|
|
107
117
|
);
|
|
108
118
|
}
|
|
109
|
-
|
|
110
|
-
// Prefer theme.extend.colors
|
|
111
119
|
const colors = config.theme.extend?.colors ?? config.theme.colors ?? {};
|
|
112
120
|
|
|
113
|
-
|
|
121
|
+
// Extract fontFamily
|
|
122
|
+
/* v8 ignore next 5 */
|
|
123
|
+
if (config.theme.fontFamily && !config.theme.extend?.fontFamily && process.env.NODE_ENV !== "production") {
|
|
124
|
+
console.warn(
|
|
125
|
+
"[react-native-tailwind] Using theme.fontFamily will override all default font families. " +
|
|
126
|
+
"Use theme.extend.fontFamily to add custom fonts while keeping defaults.",
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
const fontFamily = config.theme.extend?.fontFamily ?? config.theme.fontFamily ?? {};
|
|
130
|
+
|
|
131
|
+
// Convert fontFamily values to strings (take first value if array)
|
|
132
|
+
const fontFamilyResult: Record<string, string> = {};
|
|
133
|
+
for (const [key, value] of Object.entries(fontFamily)) {
|
|
134
|
+
if (Array.isArray(value)) {
|
|
135
|
+
// Take first font in the array (React Native doesn't support font stacks)
|
|
136
|
+
fontFamilyResult[key] = value[0];
|
|
137
|
+
} else {
|
|
138
|
+
fontFamilyResult[key] = value;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return {
|
|
143
|
+
colors: flattenColors(colors),
|
|
144
|
+
fontFamily: fontFamilyResult,
|
|
145
|
+
};
|
|
114
146
|
}
|