@gaozh1024/rn-kit 0.2.0-beta.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.
- package/README.md +363 -0
- package/TAILWIND_SETUP.md +307 -0
- package/dist/index.d.mts +3465 -0
- package/dist/index.d.ts +3465 -0
- package/dist/index.js +4627 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +4504 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +63 -0
package/README.md
ADDED
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
# @gaozh1024/rn-kit
|
|
2
|
+
|
|
3
|
+
> Panther Expo Framework - All-in-one React Native framework
|
|
4
|
+
|
|
5
|
+
一个集成的 React Native 开发框架,包含主题系统、UI 组件、API 工厂和导航组件。
|
|
6
|
+
|
|
7
|
+
## ✅ 推荐初始化方式
|
|
8
|
+
|
|
9
|
+
业务 App 推荐优先使用 `AppProvider`,而不是只手动包一层 `ThemeProvider`。
|
|
10
|
+
|
|
11
|
+
`AppProvider` 默认会整合:
|
|
12
|
+
|
|
13
|
+
- `SafeAreaProvider`
|
|
14
|
+
- `ThemeProvider`
|
|
15
|
+
- `NavigationProvider`
|
|
16
|
+
- `OverlayProvider`
|
|
17
|
+
- `AppStatusBar`
|
|
18
|
+
|
|
19
|
+
这样页面切换、主题切换时,状态栏会自动跟随全局主题变化。
|
|
20
|
+
|
|
21
|
+
## 📦 安装
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm install @gaozh1024/rn-kit
|
|
25
|
+
# 或
|
|
26
|
+
pnpm add @gaozh1024/rn-kit
|
|
27
|
+
# 或
|
|
28
|
+
yarn add @gaozh1024/rn-kit
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### 前置依赖
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npm install react react-native
|
|
35
|
+
npm install react-native-screens react-native-safe-area-context
|
|
36
|
+
npm install react-native-gesture-handler react-native-reanimated
|
|
37
|
+
npm install react-native-svg
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### ⚠️ 样式配置(必看)
|
|
41
|
+
|
|
42
|
+
本框架使用 **Tailwind CSS** 类名实现样式(如 `bg-primary-500`, `flex-1`, `p-4`),需要在你的项目中配置 **NativeWind** 才能正常显示样式。
|
|
43
|
+
|
|
44
|
+
如果你发现 `AppHeader`、`AppView`、`AppButton` 没有样式或布局错乱,通常不是框架内部渲染失败,而是消费方 app 没有把 NativeWind 和 Tailwind 扫描范围配置完整。
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
npm install nativewind
|
|
48
|
+
npm install -D tailwindcss
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
创建 `tailwind.config.js`:
|
|
52
|
+
|
|
53
|
+
```javascript
|
|
54
|
+
module.exports = {
|
|
55
|
+
content: [
|
|
56
|
+
'./App.{js,jsx,ts,tsx}',
|
|
57
|
+
'./src/**/*.{js,jsx,ts,tsx}',
|
|
58
|
+
'./node_modules/@gaozh1024/rn-kit/dist/**/*.{js,mjs}', // 必须包含框架路径
|
|
59
|
+
],
|
|
60
|
+
safelist: [
|
|
61
|
+
{ pattern: /^(flex)-(1|2|3|4|5|6|7|8|9|10|11|12)$/ },
|
|
62
|
+
{ pattern: /^(items)-(start|center|end|stretch)$/ },
|
|
63
|
+
{ pattern: /^(justify)-(start|center|end|between|around)$/ },
|
|
64
|
+
{ pattern: /^(p|px|py|gap)-(0|1|2|3|4|5|6|8|10|12)$/ },
|
|
65
|
+
{ pattern: /^(rounded)-(none|sm|md|lg|xl|2xl|full)$/ },
|
|
66
|
+
{
|
|
67
|
+
pattern: /^(bg|text)-(primary|secondary|success|warning|error|info|gray|white|black)(-.+)?$/,
|
|
68
|
+
},
|
|
69
|
+
],
|
|
70
|
+
theme: { extend: {} },
|
|
71
|
+
plugins: [],
|
|
72
|
+
};
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
修改 `babel.config.js`:
|
|
76
|
+
|
|
77
|
+
```javascript
|
|
78
|
+
module.exports = function (api) {
|
|
79
|
+
api.cache(true);
|
|
80
|
+
return {
|
|
81
|
+
presets: [['babel-preset-expo', { jsxImportSource: 'nativewind' }], 'nativewind/babel'],
|
|
82
|
+
};
|
|
83
|
+
};
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
📖 [查看完整 Tailwind 配置指南](./TAILWIND_SETUP.md)
|
|
87
|
+
|
|
88
|
+
## 🚀 快速开始
|
|
89
|
+
|
|
90
|
+
```tsx
|
|
91
|
+
import { AppProvider, AppView, AppText, AppButton, useToggle } from '@gaozh1024/rn-kit';
|
|
92
|
+
|
|
93
|
+
function App() {
|
|
94
|
+
const [visible, { toggle }] = useToggle(false);
|
|
95
|
+
|
|
96
|
+
return (
|
|
97
|
+
<AppProvider>
|
|
98
|
+
<AppView flex p={4}>
|
|
99
|
+
<AppText size="xl">Hello Panther!</AppText>
|
|
100
|
+
<AppButton onPress={toggle}>{visible ? '隐藏' : '显示'}</AppButton>
|
|
101
|
+
</AppView>
|
|
102
|
+
</AppProvider>
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
如果你只需要最小主题能力,也可以单独使用:
|
|
108
|
+
|
|
109
|
+
```tsx
|
|
110
|
+
import { ThemeProvider, createTheme } from '@gaozh1024/rn-kit';
|
|
111
|
+
|
|
112
|
+
const theme = createTheme({
|
|
113
|
+
colors: {
|
|
114
|
+
primary: '#f38b32',
|
|
115
|
+
},
|
|
116
|
+
});
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## 📚 API 概览
|
|
120
|
+
|
|
121
|
+
### 🎨 主题系统
|
|
122
|
+
|
|
123
|
+
```tsx
|
|
124
|
+
import { ThemeProvider, createTheme, useTheme } from '@gaozh1024/rn-kit';
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### 🧱 应用初始化与状态栏
|
|
128
|
+
|
|
129
|
+
```tsx
|
|
130
|
+
import { AppProvider, AppStatusBar } from '@gaozh1024/rn-kit';
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
受控切换主题时,推荐直接给 `AppProvider` / `ThemeProvider` 传 `isDark`,不要再通过重建根组件强制刷新:
|
|
134
|
+
|
|
135
|
+
```tsx
|
|
136
|
+
<AppProvider lightTheme={lightTheme} darkTheme={darkTheme} isDark={themeMode === 'dark'}>
|
|
137
|
+
<RootNavigator />
|
|
138
|
+
</AppProvider>
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### 🧩 UI 组件
|
|
142
|
+
|
|
143
|
+
```tsx
|
|
144
|
+
import {
|
|
145
|
+
AppView,
|
|
146
|
+
AppScrollView,
|
|
147
|
+
AppText,
|
|
148
|
+
AppPressable,
|
|
149
|
+
AppInput, // 原子组件
|
|
150
|
+
Row,
|
|
151
|
+
Col,
|
|
152
|
+
Center, // 布局
|
|
153
|
+
AppButton, // 组合组件
|
|
154
|
+
Toast,
|
|
155
|
+
Alert,
|
|
156
|
+
Loading,
|
|
157
|
+
Progress, // 反馈
|
|
158
|
+
Card,
|
|
159
|
+
Icon,
|
|
160
|
+
AppImage,
|
|
161
|
+
AppList, // 数据展示
|
|
162
|
+
Checkbox,
|
|
163
|
+
Radio,
|
|
164
|
+
Switch,
|
|
165
|
+
Select,
|
|
166
|
+
DatePicker, // 表单
|
|
167
|
+
} from '@gaozh1024/rn-kit';
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### 🪝 Hooks
|
|
171
|
+
|
|
172
|
+
```tsx
|
|
173
|
+
import {
|
|
174
|
+
// UI Hooks
|
|
175
|
+
useToggle,
|
|
176
|
+
useDebounce,
|
|
177
|
+
useThrottle,
|
|
178
|
+
useKeyboard,
|
|
179
|
+
useDimensions,
|
|
180
|
+
useOrientation,
|
|
181
|
+
// Core Hooks
|
|
182
|
+
useAsyncState,
|
|
183
|
+
useRequest,
|
|
184
|
+
usePagination,
|
|
185
|
+
useRefresh,
|
|
186
|
+
useInfinite,
|
|
187
|
+
useStorage,
|
|
188
|
+
} from '@gaozh1024/rn-kit';
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### 🧭 导航
|
|
192
|
+
|
|
193
|
+
```tsx
|
|
194
|
+
import {
|
|
195
|
+
NavigationProvider,
|
|
196
|
+
StackNavigator,
|
|
197
|
+
TabNavigator,
|
|
198
|
+
BottomTabBar,
|
|
199
|
+
DrawerNavigator,
|
|
200
|
+
useNavigation,
|
|
201
|
+
useRoute,
|
|
202
|
+
} from '@gaozh1024/rn-kit';
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
`TabNavigator` 在未显式传入 `tabBar` 时,会默认使用框架内置的 `BottomTabBar`(默认高度 `65`)。
|
|
206
|
+
|
|
207
|
+
```tsx
|
|
208
|
+
<TabNavigator
|
|
209
|
+
tabBarOptions={{
|
|
210
|
+
activeTintColor: '#f38b32',
|
|
211
|
+
inactiveTintColor: '#9ca3af',
|
|
212
|
+
height: 72,
|
|
213
|
+
style: { borderTopWidth: 0 },
|
|
214
|
+
}}
|
|
215
|
+
>
|
|
216
|
+
{/* screens */}
|
|
217
|
+
</TabNavigator>
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
如果你需要完全自定义底栏,也可以手动覆盖:
|
|
221
|
+
|
|
222
|
+
```tsx
|
|
223
|
+
<TabNavigator tabBar={props => <BottomTabBar {...props} height={72} />}>
|
|
224
|
+
{/* screens */}
|
|
225
|
+
</TabNavigator>
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### 🔌 API 工厂
|
|
229
|
+
|
|
230
|
+
```tsx
|
|
231
|
+
import { createAPI, z, storage, ErrorCode } from '@gaozh1024/rn-kit';
|
|
232
|
+
|
|
233
|
+
const api = createAPI({
|
|
234
|
+
baseURL: 'https://api.example.com',
|
|
235
|
+
endpoints: {
|
|
236
|
+
getUser: {
|
|
237
|
+
method: 'GET',
|
|
238
|
+
path: '/users/:id',
|
|
239
|
+
},
|
|
240
|
+
},
|
|
241
|
+
});
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
## 📄 文档
|
|
245
|
+
|
|
246
|
+
- [框架文档](../../docs/README.md) - 完整文档索引
|
|
247
|
+
|
|
248
|
+
## 📱 状态栏使用说明
|
|
249
|
+
|
|
250
|
+
### 1. 全局默认行为
|
|
251
|
+
|
|
252
|
+
推荐:
|
|
253
|
+
|
|
254
|
+
```tsx
|
|
255
|
+
import { AppProvider } from '@gaozh1024/rn-kit';
|
|
256
|
+
|
|
257
|
+
export default function App() {
|
|
258
|
+
return (
|
|
259
|
+
<AppProvider>
|
|
260
|
+
<RootNavigator />
|
|
261
|
+
</AppProvider>
|
|
262
|
+
);
|
|
263
|
+
}
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
此时框架会自动注入全局 `AppStatusBar`:
|
|
267
|
+
|
|
268
|
+
- 亮色主题:`dark-content`
|
|
269
|
+
- 暗色主题:`light-content`
|
|
270
|
+
- Android 状态栏背景默认跟随当前主题背景色
|
|
271
|
+
|
|
272
|
+
### 2. 页面级覆盖
|
|
273
|
+
|
|
274
|
+
如果某个页面需要单独控制状态栏,可以在页面内显式渲染:
|
|
275
|
+
|
|
276
|
+
```tsx
|
|
277
|
+
import { AppStatusBar } from '@gaozh1024/rn-kit';
|
|
278
|
+
|
|
279
|
+
<AppStatusBar barStyle="light-content" backgroundColor="#f38b32" />;
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
适合:
|
|
283
|
+
|
|
284
|
+
- 登录页
|
|
285
|
+
- 沉浸式详情页
|
|
286
|
+
- 顶部大图/渐变背景页
|
|
287
|
+
|
|
288
|
+
### 3. 登录页全屏背景示例
|
|
289
|
+
|
|
290
|
+
如果登录页希望顶部状态栏区域也和页面背景保持一致,不要直接使用默认白底容器。
|
|
291
|
+
|
|
292
|
+
推荐:
|
|
293
|
+
|
|
294
|
+
```tsx
|
|
295
|
+
import { AppStatusBar, SafeScreen, AppView } from '@gaozh1024/rn-kit';
|
|
296
|
+
|
|
297
|
+
export function LoginScreen() {
|
|
298
|
+
return (
|
|
299
|
+
<>
|
|
300
|
+
<AppStatusBar barStyle="light-content" backgroundColor="#f38b32" translucent={false} />
|
|
301
|
+
|
|
302
|
+
<SafeScreen bg="primary-500">
|
|
303
|
+
<AppView flex className="bg-primary-500">
|
|
304
|
+
{/* page content */}
|
|
305
|
+
</AppView>
|
|
306
|
+
</SafeScreen>
|
|
307
|
+
</>
|
|
308
|
+
);
|
|
309
|
+
}
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
### 4. 沉浸式状态栏示例
|
|
313
|
+
|
|
314
|
+
```tsx
|
|
315
|
+
import { AppStatusBar, SafeScreen, AppView } from '@gaozh1024/rn-kit';
|
|
316
|
+
|
|
317
|
+
export function HeroScreen() {
|
|
318
|
+
return (
|
|
319
|
+
<>
|
|
320
|
+
<AppStatusBar barStyle="light-content" backgroundColor="transparent" translucent />
|
|
321
|
+
|
|
322
|
+
<SafeScreen top={false} bottom={false}>
|
|
323
|
+
<AppView flex className="bg-black">
|
|
324
|
+
{/* hero content */}
|
|
325
|
+
</AppView>
|
|
326
|
+
</SafeScreen>
|
|
327
|
+
</>
|
|
328
|
+
);
|
|
329
|
+
}
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
### 5. 常见问题
|
|
333
|
+
|
|
334
|
+
#### 为什么顶部还是白色?
|
|
335
|
+
|
|
336
|
+
通常是以下原因之一:
|
|
337
|
+
|
|
338
|
+
1. 当前页面没有单独覆盖 `AppStatusBar`
|
|
339
|
+
2. 页面容器本身是白底
|
|
340
|
+
3. 使用了 `Page` / `SafeScreen`,但没有设置 `bg`
|
|
341
|
+
4. 顶部安全区没有和页面背景统一
|
|
342
|
+
|
|
343
|
+
如果你用的是:
|
|
344
|
+
|
|
345
|
+
```tsx
|
|
346
|
+
<Page>
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
那它默认不适合登录页这类全屏品牌色场景。请改成:
|
|
350
|
+
|
|
351
|
+
```tsx
|
|
352
|
+
<Page bg="primary-500">
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
或者直接用:
|
|
356
|
+
|
|
357
|
+
```tsx
|
|
358
|
+
<SafeScreen bg="primary-500">
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
## 📄 许可证
|
|
362
|
+
|
|
363
|
+
MIT
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
# Tailwind CSS / NativeWind 配置指南
|
|
2
|
+
|
|
3
|
+
> 本框架使用 Tailwind CSS 类名来实现样式,需要在你的项目中配置 NativeWind 才能正常使用。
|
|
4
|
+
|
|
5
|
+
## 为什么需要这个配置?
|
|
6
|
+
|
|
7
|
+
框架的 UI 组件(如 `AppView`, `AppText`, `AppButton` 等)使用 Tailwind CSS 类名(如 `bg-primary-500`, `flex-1`, `p-4`)来定义样式。
|
|
8
|
+
|
|
9
|
+
这些类名需要 **NativeWind** 在构建时解析并转换为 React Native 的 StyleSheet。
|
|
10
|
+
|
|
11
|
+
`AppHeader` 也是同样的机制。它的布局依赖 `AppView` 生成的 `flex-row`、`items-center`、`px-4` 等类名,所以如果 app 没把 NativeWind 和 Tailwind 配完整,`AppHeader` 会直接表现成“没有样式”。
|
|
12
|
+
|
|
13
|
+
## 安装依赖
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install nativewind
|
|
17
|
+
npm install -D tailwindcss
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## 配置文件
|
|
21
|
+
|
|
22
|
+
### 1. 创建 Tailwind 配置文件
|
|
23
|
+
|
|
24
|
+
在项目根目录创建 `tailwind.config.js`:
|
|
25
|
+
|
|
26
|
+
```javascript
|
|
27
|
+
/** @type {import('tailwindcss').Config} */
|
|
28
|
+
module.exports = {
|
|
29
|
+
content: [
|
|
30
|
+
// 你的项目文件
|
|
31
|
+
'./App.{js,jsx,ts,tsx}',
|
|
32
|
+
'./src/**/*.{js,jsx,ts,tsx}',
|
|
33
|
+
|
|
34
|
+
// 使用发布包时,必须包含框架产物路径
|
|
35
|
+
'./node_modules/@gaozh1024/rn-kit/dist/**/*.{js,mjs}',
|
|
36
|
+
|
|
37
|
+
// 如果你通过 workspace / file: / 本地源码接入框架,
|
|
38
|
+
// 还需要把实际源码路径加进来
|
|
39
|
+
// '../rn-monorepo/packages/framework/src/**/*.{ts,tsx}',
|
|
40
|
+
],
|
|
41
|
+
safelist: [
|
|
42
|
+
{ pattern: /^(flex)-(1|2|3|4|5|6|7|8|9|10|11|12)$/ },
|
|
43
|
+
{ pattern: /^(items)-(start|center|end|stretch)$/ },
|
|
44
|
+
{ pattern: /^(justify)-(start|center|end|between|around)$/ },
|
|
45
|
+
{ pattern: /^(p|px|py|gap)-(0|1|2|3|4|5|6|8|10|12)$/ },
|
|
46
|
+
{ pattern: /^(rounded)-(none|sm|md|lg|xl|2xl|full)$/ },
|
|
47
|
+
{
|
|
48
|
+
pattern: /^(bg|text)-(primary|secondary|success|warning|error|info|gray|white|black)(-.+)?$/,
|
|
49
|
+
},
|
|
50
|
+
],
|
|
51
|
+
theme: {
|
|
52
|
+
extend: {
|
|
53
|
+
// 可以扩展或覆盖框架主题
|
|
54
|
+
colors: {
|
|
55
|
+
primary: {
|
|
56
|
+
DEFAULT: '#f38b32',
|
|
57
|
+
50: '#fff7ed',
|
|
58
|
+
100: '#ffedd5',
|
|
59
|
+
200: '#fed7aa',
|
|
60
|
+
300: '#fdba74',
|
|
61
|
+
400: '#fb923c',
|
|
62
|
+
500: '#f38b32',
|
|
63
|
+
600: '#ea580c',
|
|
64
|
+
700: '#c2410c',
|
|
65
|
+
800: '#9a3412',
|
|
66
|
+
900: '#7c2d12',
|
|
67
|
+
950: '#431407',
|
|
68
|
+
},
|
|
69
|
+
// ... 其他颜色
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
plugins: [],
|
|
74
|
+
};
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### 为什么还需要 `safelist`?
|
|
78
|
+
|
|
79
|
+
因为框架部分组件会通过 props 动态生成类名,例如:
|
|
80
|
+
|
|
81
|
+
```tsx
|
|
82
|
+
<AppView px={4} items="center" bg="primary-500" rounded="lg" />
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
这类写法在运行时才会变成:
|
|
86
|
+
|
|
87
|
+
- `px-4`
|
|
88
|
+
- `items-center`
|
|
89
|
+
- `bg-primary-500`
|
|
90
|
+
- `rounded-lg`
|
|
91
|
+
|
|
92
|
+
如果不通过 `safelist` 提前告诉 Tailwind,这些类名可能不会被生成,最终表现为:
|
|
93
|
+
|
|
94
|
+
- 间距不生效
|
|
95
|
+
- 背景色不生效
|
|
96
|
+
- 圆角不生效
|
|
97
|
+
- `AppHeader` 没有布局
|
|
98
|
+
|
|
99
|
+
### 2. 配置 Babel
|
|
100
|
+
|
|
101
|
+
修改 `babel.config.js`:
|
|
102
|
+
|
|
103
|
+
```javascript
|
|
104
|
+
module.exports = function (api) {
|
|
105
|
+
api.cache(true);
|
|
106
|
+
return {
|
|
107
|
+
presets: [['babel-preset-expo', { jsxImportSource: 'nativewind' }], 'nativewind/babel'],
|
|
108
|
+
};
|
|
109
|
+
};
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
关键点:
|
|
113
|
+
|
|
114
|
+
- `nativewind/babel` 在 NativeWind 4.x 里是 `preset`,不要放进 `plugins`
|
|
115
|
+
- Expo 项目需要在 `babel-preset-expo` 上补 `jsxImportSource: 'nativewind'`
|
|
116
|
+
- 对 Expo SDK 54 + Reanimated 4 场景,不需要再额外挂 `react-native-reanimated/plugin`
|
|
117
|
+
|
|
118
|
+
错误示例:
|
|
119
|
+
|
|
120
|
+
```javascript
|
|
121
|
+
module.exports = function (api) {
|
|
122
|
+
api.cache(true);
|
|
123
|
+
return {
|
|
124
|
+
presets: ['babel-preset-expo'],
|
|
125
|
+
plugins: ['nativewind/babel'], // 错误:这里会触发 .plugins is not a valid Plugin property
|
|
126
|
+
};
|
|
127
|
+
};
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### 3. 配置 Metro(如果需要)
|
|
131
|
+
|
|
132
|
+
对于某些 React Native 版本,可能需要配置 `metro.config.js`:
|
|
133
|
+
|
|
134
|
+
```javascript
|
|
135
|
+
const { getDefaultConfig } = require('metro-config');
|
|
136
|
+
|
|
137
|
+
module.exports = (async () => {
|
|
138
|
+
const {
|
|
139
|
+
resolver: { sourceExts, assetExts },
|
|
140
|
+
} = await getDefaultConfig();
|
|
141
|
+
|
|
142
|
+
return {
|
|
143
|
+
transformer: {
|
|
144
|
+
babelTransformerPath: require.resolve('nativewind/src/css-interop/transformer'),
|
|
145
|
+
},
|
|
146
|
+
resolver: {
|
|
147
|
+
assetExts: assetExts.filter(ext => ext !== 'css'),
|
|
148
|
+
sourceExts: [...sourceExts, 'css'],
|
|
149
|
+
},
|
|
150
|
+
};
|
|
151
|
+
})();
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### 4. 创建 CSS 入口文件(推荐)
|
|
155
|
+
|
|
156
|
+
创建 `global.css` 文件:
|
|
157
|
+
|
|
158
|
+
```css
|
|
159
|
+
@tailwind base;
|
|
160
|
+
@tailwind components;
|
|
161
|
+
@tailwind utilities;
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
在应用入口导入(如 `App.tsx`):
|
|
165
|
+
|
|
166
|
+
```tsx
|
|
167
|
+
import './global.css';
|
|
168
|
+
// ... 其他导入
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## 验证配置
|
|
172
|
+
|
|
173
|
+
创建一个测试页面验证样式是否正常:
|
|
174
|
+
|
|
175
|
+
```tsx
|
|
176
|
+
import { AppView, AppText, AppButton } from '@gaozh1024/rn-kit';
|
|
177
|
+
|
|
178
|
+
export function TestScreen() {
|
|
179
|
+
return (
|
|
180
|
+
<AppView flex center p={4} bg="gray-100">
|
|
181
|
+
<AppText size="xl" weight="bold" color="primary-500">
|
|
182
|
+
如果这行文字是橙色,说明配置成功!
|
|
183
|
+
</AppText>
|
|
184
|
+
|
|
185
|
+
<AppButton
|
|
186
|
+
className="mt-4 px-6 py-3 bg-primary-500 rounded-lg"
|
|
187
|
+
onPress={() => console.log('Clicked!')}
|
|
188
|
+
>
|
|
189
|
+
测试按钮
|
|
190
|
+
</AppButton>
|
|
191
|
+
</AppView>
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
## 常见问题
|
|
197
|
+
|
|
198
|
+
### Q: 样式不生效,组件显示默认样式?
|
|
199
|
+
|
|
200
|
+
**检查清单**:
|
|
201
|
+
|
|
202
|
+
1. ✅ `tailwind.config.js` 中的 `content` 是否包含框架路径?
|
|
203
|
+
2. ✅ `babel.config.js` 是否按 NativeWind 4.x 写成 `presets` 配置?
|
|
204
|
+
3. ✅ `tailwind.config.js` 是否添加了框架需要的 `safelist`?
|
|
205
|
+
4. ✅ 是否重启了 Metro bundler?(修改配置后需要重启)
|
|
206
|
+
5. ✅ 是否清除了缓存?(Expo 推荐 `npx expo start -c`,React Native CLI 可用 `npx react-native start --reset-cache`)
|
|
207
|
+
6. ✅ `babel-preset-expo` 是否配置了 `jsxImportSource: 'nativewind'`?
|
|
208
|
+
|
|
209
|
+
### Q: 为什么 `AppHeader` 也没有样式?
|
|
210
|
+
|
|
211
|
+
`AppHeader` 不是纯 `StyleSheet` 组件,它依赖框架内部的:
|
|
212
|
+
|
|
213
|
+
- `AppView row`
|
|
214
|
+
- `items="center"`
|
|
215
|
+
- `px={4}`
|
|
216
|
+
|
|
217
|
+
这些最终都会走 NativeWind 的 `className` 管线。所以如果:
|
|
218
|
+
|
|
219
|
+
- Babel 没加 `nativewind/babel`
|
|
220
|
+
- `content` 没扫到框架文件
|
|
221
|
+
- `safelist` 没覆盖动态类
|
|
222
|
+
|
|
223
|
+
那么 `AppHeader` 会非常像“完全没有样式”。
|
|
224
|
+
|
|
225
|
+
### Q: 这是框架 bug 吗?
|
|
226
|
+
|
|
227
|
+
通常不是渲染 bug,而是消费方配置不完整。
|
|
228
|
+
|
|
229
|
+
但要注意一点:框架当前确实使用了部分**动态 className** 生成方式,因此消费方 app 不能只配最基础的 NativeWind,还必须把 `safelist` 配上。
|
|
230
|
+
|
|
231
|
+
另一个常见例外是本地链接包没有同步:
|
|
232
|
+
|
|
233
|
+
- 如果你通过 `yalc`、`file:`、workspace 或本地源码方式接入框架,app 里跑的未必是最新构建产物
|
|
234
|
+
- 框架源码虽然已经修复,但 app 里的 `.yalc` 或本地链接目录如果没更新,最终表现仍然会是“没有样式”
|
|
235
|
+
|
|
236
|
+
推荐排查顺序:
|
|
237
|
+
|
|
238
|
+
```bash
|
|
239
|
+
# 在框架仓库
|
|
240
|
+
pnpm --filter @gaozh1024/rn-kit build
|
|
241
|
+
|
|
242
|
+
# 如果使用 yalc
|
|
243
|
+
yalc publish
|
|
244
|
+
|
|
245
|
+
# 在 app 仓库
|
|
246
|
+
yalc update @gaozh1024/rn-kit
|
|
247
|
+
npx expo start -c
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### Q: `AppHeader` 没样式,但 `tailwind.config.js` 已经配了,为什么?
|
|
251
|
+
|
|
252
|
+
优先检查 `babel.config.js` 有没有把 `nativewind/babel` 错写到 `plugins`,或者漏掉 `jsxImportSource: 'nativewind'`。
|
|
253
|
+
|
|
254
|
+
这类错误会让 NativeWind 转换根本没有接通,表现通常是:
|
|
255
|
+
|
|
256
|
+
- `AppHeader` 没有左右内边距
|
|
257
|
+
- 标题不居中
|
|
258
|
+
- `AppView` 的 `row`、`items="center"`、`px={4}` 像完全失效
|
|
259
|
+
|
|
260
|
+
### Q: 如何自定义主题颜色?
|
|
261
|
+
|
|
262
|
+
在 `tailwind.config.js` 中扩展主题:
|
|
263
|
+
|
|
264
|
+
```javascript
|
|
265
|
+
module.exports = {
|
|
266
|
+
content: [
|
|
267
|
+
/* ... */
|
|
268
|
+
],
|
|
269
|
+
theme: {
|
|
270
|
+
extend: {
|
|
271
|
+
colors: {
|
|
272
|
+
// 覆盖框架默认主色
|
|
273
|
+
primary: {
|
|
274
|
+
500: '#1890ff', // 改为蓝色
|
|
275
|
+
},
|
|
276
|
+
// 添加自定义颜色
|
|
277
|
+
brand: {
|
|
278
|
+
500: '#ff6b6b',
|
|
279
|
+
},
|
|
280
|
+
},
|
|
281
|
+
},
|
|
282
|
+
},
|
|
283
|
+
};
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
然后在组件中使用:
|
|
287
|
+
|
|
288
|
+
```tsx
|
|
289
|
+
<AppView bg="brand-500" /> // 使用自定义颜色
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
### Q: 与框架主题系统的关系?
|
|
293
|
+
|
|
294
|
+
框架的 `ThemeProvider` 和 `createTheme` 提供**运行时主题数据**(如颜色值、间距值)。
|
|
295
|
+
|
|
296
|
+
Tailwind CSS 提供**构建时样式类名**。
|
|
297
|
+
|
|
298
|
+
两者配合工作:
|
|
299
|
+
|
|
300
|
+
- Tailwind 类名决定样式结构(如 `flex`, `p-4`, `rounded-lg`)
|
|
301
|
+
- 主题系统提供具体的颜色值(如 `primary-500` 对应的颜色)
|
|
302
|
+
|
|
303
|
+
## 相关文档
|
|
304
|
+
|
|
305
|
+
- [NativeWind 官方文档](https://www.nativewind.dev/)
|
|
306
|
+
- [Tailwind CSS 文档](https://tailwindcss.com/docs)
|
|
307
|
+
- [框架快速开始](../SETUP.md)
|