@gaozh1024/rn-kit 0.3.3 → 0.4.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 CHANGED
@@ -16,6 +16,13 @@
16
16
  - `OverlayProvider`
17
17
  - `AppStatusBar`
18
18
 
19
+ 另外在**开发环境**下,`AppProvider` 默认会启用一套轻量的开发日志基础设施:
20
+
21
+ - `LoggerProvider`
22
+ - CLI 彩色日志输出
23
+ - App 内 `LogOverlay` 浮层
24
+ - `AppErrorBoundary` React 渲染错误兜底
25
+
19
26
  这样页面切换、主题切换时,状态栏会自动跟随全局主题变化。
20
27
 
21
28
  ## 📦 安装
@@ -61,6 +68,7 @@ module.exports = {
61
68
  ],
62
69
  safelist: [
63
70
  { pattern: /^(flex)-(1|2|3|4|5|6|7|8|9|10|11|12)$/ },
71
+ 'flex-wrap',
64
72
  { pattern: /^(items)-(start|center|end|stretch)$/ },
65
73
  { pattern: /^(justify)-(start|center|end|between|around)$/ },
66
74
  { pattern: /^(p|px|py|gap)-(0|1|2|3|4|5|6|8|10|12)$/ },
@@ -148,6 +156,7 @@ import {
148
156
  AppScrollView,
149
157
  AppText,
150
158
  AppPressable,
159
+ KeyboardDismissView,
151
160
  AppInput, // 原子组件
152
161
  Row,
153
162
  Col,
@@ -167,10 +176,85 @@ import {
167
176
  Radio,
168
177
  Switch,
169
178
  Select,
179
+ Picker,
170
180
  DatePicker, // 表单
171
181
  } from '@gaozh1024/rn-kit';
172
182
  ```
173
183
 
184
+ #### 布局与容器约定
185
+
186
+ - `AppView` / `Row` 支持 `wrap`,等价于 `flex-wrap`
187
+ - `Card` 支持常用间距快捷属性:`p` / `px` / `py` / `gap`
188
+ - `SafeScreen` / `AppScreen` 同时支持:
189
+ - `bg="primary-500"` 这类显式颜色
190
+ - `surface="background" | "card" | "muted"` 这类语义背景
191
+ - `dismissKeyboardOnPressOutside`:点击非输入区域时收起键盘
192
+ - `AppScrollView` 支持 `dismissKeyboardOnPressOutside`
193
+ - 开启后会自动启用点击空白收起键盘
194
+ - 并默认补上 `keyboardShouldPersistTaps="handled"`
195
+ - `KeyboardDismissView` 适合非页面容器、自定义布局场景下单独包裹使用
196
+
197
+ #### Button 颜色语义
198
+
199
+ `AppButton` 目前支持以下 `color`:
200
+
201
+ - `primary`
202
+ - `secondary`
203
+ - `success`
204
+ - `warning`
205
+ - `info`
206
+ - `error`
207
+ - `danger`(`error` 的兼容别名)
208
+ - `muted`
209
+
210
+ ```tsx
211
+ <AppButton color="success">保存成功</AppButton>
212
+ <AppButton color="warning" variant="outline">
213
+ 继续操作
214
+ </AppButton>
215
+ <AppButton color="danger">删除</AppButton>
216
+ ```
217
+
218
+ #### 键盘收起交互
219
+
220
+ `AppButton` 新增:
221
+
222
+ - `dismissKeyboardOnPress?: boolean`
223
+ - 默认值:`true`
224
+
225
+ 也就是说,大多数提交/保存/登录按钮在点击前会先自动收起键盘:
226
+
227
+ ```tsx
228
+ <AppButton onPress={handleSubmit}>提交</AppButton>
229
+
230
+ <AppButton dismissKeyboardOnPress={false} onPress={handleToolbarAction}>
231
+ 保持键盘
232
+ </AppButton>
233
+ ```
234
+
235
+ 容器侧推荐这样使用:
236
+
237
+ ```tsx
238
+ <AppScreen dismissKeyboardOnPressOutside>
239
+ <AppScrollView dismissKeyboardOnPressOutside>
240
+ <AppInput placeholder="请输入手机号" />
241
+ <AppInput placeholder="请输入密码" secureTextEntry />
242
+ <AppButton onPress={handleLogin}>登录</AppButton>
243
+ </AppScrollView>
244
+ </AppScreen>
245
+ ```
246
+
247
+ 如果不是整页容器,而是局部自定义布局,也可以单独使用:
248
+
249
+ ```tsx
250
+ <KeyboardDismissView>
251
+ <AppView p={4} gap={3}>
252
+ <AppInput placeholder="搜索内容" />
253
+ <AppButton onPress={handleSearch}>搜索</AppButton>
254
+ </AppView>
255
+ </KeyboardDismissView>
256
+ ```
257
+
174
258
  #### 可本地化文案参数(i18n 推荐)
175
259
 
176
260
  - `AppList`
@@ -183,13 +267,189 @@ import {
183
267
  - `emptyText`:空状态文案
184
268
  - `selectedCountText`:多选计数模板,支持 `{{count}}`
185
269
  - `confirmText`:多选确认按钮文案
270
+ - `Picker`
271
+ - `pickerTitle` / `cancelText` / `confirmText`:弹窗文案
272
+ - `renderDisplayText`:自定义触发区展示文本
273
+ - `renderFooter`:自定义底部区域,适合扩展省市区、级联选择等场景
186
274
  - `DatePicker`
187
275
  - `cancelText` / `confirmText`:弹窗操作按钮文案
188
276
  - `pickerTitle`:弹窗标题文案
189
- - `pickerDateFormat`:弹窗顶部日期格式
190
277
  - `yearLabel` / `monthLabel` / `dayLabel`:列标题文案
191
278
  - `todayText` / `minDateText` / `maxDateText`:快捷按钮文案
192
279
 
280
+ #### 表单与反馈 Hook 当前 API
281
+
282
+ ```tsx
283
+ import { useForm, useToast, useLoading, useAlert, useLogger } from '@gaozh1024/rn-kit';
284
+
285
+ const form = useForm({
286
+ schema,
287
+ defaultValues: { name: '' },
288
+ });
289
+
290
+ form.values;
291
+ form.errors;
292
+ form.setValue('name', 'Panther');
293
+ await form.validate();
294
+ await form.validateField('name');
295
+ await form.handleSubmit(async values => {
296
+ console.log(values);
297
+ });
298
+
299
+ const toast = useToast();
300
+ toast.show('已保存', 'success', 2000);
301
+ toast.success('成功');
302
+
303
+ const loading = useLoading();
304
+ loading.show('加载中...');
305
+ loading.hide();
306
+
307
+ const alert = useAlert();
308
+ alert.alert({ title: '提示', message: '操作完成' });
309
+ alert.confirm({ title: '确认删除', message: '删除后不可恢复' });
310
+
311
+ const logger = useLogger('auth');
312
+ logger.info('开始登录', { page: 'Login' });
313
+ logger.error('登录失败', { code: 401 });
314
+ ```
315
+
316
+ 说明:
317
+
318
+ - `useForm` 使用 `defaultValues`,不是 `initialValues`
319
+ - `useForm` 提供 `setValue` / `handleSubmit`,不是 `setFieldValue` / `submit`
320
+ - `useToast` 当前签名为 `show(message, type?, duration?)`
321
+ - `useLoading` 当前签名为 `show(text?)` / `hide()`
322
+ - `useAlert` 当前提供 `alert()` / `confirm()`,不包含 `prompt()` / `custom()`
323
+ - `useLogger(namespace?)` 提供 `debug / info / warn / error / clear / entries`
324
+
325
+ #### 开发日志 / 可观测性基础设施
326
+
327
+ 框架现在内置了一套**开发态可观测性基础设施**,目标是帮助排查问题,而不是直接做线上监控平台。
328
+
329
+ 默认能力:
330
+
331
+ - `useLogger(namespace?)`:组件内打点
332
+ - 内存日志缓冲:保留最近若干条日志
333
+ - Console Transport:CLI 中按 level 彩色输出
334
+ - `LogOverlay`:App 内浮动日志面板
335
+ - 浮层增强:level 筛选 / namespace 筛选 / 关键字搜索 / 导出当前日志
336
+
337
+ ##### 1. 最简单用法:直接跟随 `AppProvider`
338
+
339
+ ```tsx
340
+ import { AppProvider, useLogger, AppButton } from '@gaozh1024/rn-kit';
341
+
342
+ function LoginButton() {
343
+ const logger = useLogger('login');
344
+
345
+ return (
346
+ <AppButton
347
+ onPress={() => {
348
+ logger.info('点击登录按钮');
349
+ }}
350
+ >
351
+ 登录
352
+ </AppButton>
353
+ );
354
+ }
355
+
356
+ export default function App() {
357
+ return (
358
+ <AppProvider>
359
+ <LoginButton />
360
+ </AppProvider>
361
+ );
362
+ }
363
+ ```
364
+
365
+ 说明:
366
+
367
+ - `AppProvider` 在开发环境下默认 `enableLogger = true`
368
+ - 生产环境默认关闭
369
+ - 开启后会同时启用 console 输出和 App 内日志浮层
370
+
371
+ ##### 2. 显式控制是否启用
372
+
373
+ ```tsx
374
+ <AppProvider
375
+ enableLogger
376
+ enableErrorBoundary
377
+ loggerProps={{
378
+ level: 'info',
379
+ maxEntries: 300,
380
+ consoleEnabled: true,
381
+ defaultExpanded: false,
382
+ }}
383
+ >
384
+ <App />
385
+ </AppProvider>
386
+ ```
387
+
388
+ 常用 `loggerProps`:
389
+
390
+ - `enabled`
391
+ - `level`: `'debug' | 'info' | 'warn' | 'error'`
392
+ - `maxEntries`
393
+ - `consoleEnabled`
394
+ - `overlayEnabled`
395
+ - `defaultExpanded`
396
+ - `exportEnabled`
397
+ - `onExport`
398
+
399
+ `onExport` 会收到:
400
+
401
+ ```tsx
402
+ {
403
+ entries: LogEntry[];
404
+ serialized: string;
405
+ }
406
+ ```
407
+
408
+ 错误边界相关:
409
+
410
+ - `enableErrorBoundary`:是否启用 React 错误边界
411
+ - `errorBoundaryProps.title`:兜底标题
412
+ - `errorBoundaryProps.description`:兜底说明
413
+ - `errorBoundaryProps.showDetails`:是否显示错误详情
414
+ - `errorBoundaryProps.resetText`:重试按钮文案
415
+
416
+ 当错误边界与 logger 同时开启时,组件渲染异常会自动写入 `react` 命名空间日志,便于在控制台和 `LogOverlay` 中回看。
417
+
418
+ ##### 3. 单独使用 `OverlayProvider` / `LoggerProvider`
419
+
420
+ 如果你不是通过 `AppProvider` 接入,而是自己手动包 Provider,需要注意:
421
+
422
+ - `LoggerProvider` 默认 `enabled = false`
423
+ - `OverlayProvider` 里传入的 logger 也默认不主动开启
424
+
425
+ 所以需要显式打开:
426
+
427
+ ```tsx
428
+ import { OverlayProvider } from '@gaozh1024/rn-kit';
429
+
430
+ <OverlayProvider
431
+ loggerProps={{
432
+ enabled: true,
433
+ overlayEnabled: true,
434
+ consoleEnabled: true,
435
+ }}
436
+ >
437
+ <App />
438
+ </OverlayProvider>;
439
+ ```
440
+
441
+ 或者:
442
+
443
+ ```tsx
444
+ import { AppErrorBoundary, LoggerProvider } from '@gaozh1024/rn-kit';
445
+
446
+ <LoggerProvider enabled overlayEnabled consoleEnabled>
447
+ <AppErrorBoundary enabled showDetails>
448
+ <App />
449
+ </AppErrorBoundary>
450
+ </LoggerProvider>;
451
+ ```
452
+
193
453
  ### 🪝 Hooks
194
454
 
195
455
  ```tsx
@@ -317,6 +577,14 @@ import { GradientView, AppText } from '@gaozh1024/rn-kit';
317
577
  </GradientView>;
318
578
  ```
319
579
 
580
+ TypeScript 下如果你把颜色数组先提到变量里,建议写成 tuple:
581
+
582
+ ```tsx
583
+ const heroColors = ['#f38b32', '#fb923c'] as const;
584
+
585
+ <GradientView colors={heroColors} />;
586
+ ```
587
+
320
588
  如果你的应用是手动集成 `@gaozh1024/rn-kit`,请同时安装:
321
589
 
322
590
  ```bash
@@ -359,7 +627,7 @@ import { DrawerContent, DrawerNavigator } from '@gaozh1024/rn-kit';
359
627
  ### 🔌 API 工厂
360
628
 
361
629
  ```tsx
362
- import { createAPI, z, storage, ErrorCode } from '@gaozh1024/rn-kit';
630
+ import { createAPI, createApiLoggerTransport, z, storage, ErrorCode } from '@gaozh1024/rn-kit';
363
631
 
364
632
  const api = createAPI({
365
633
  baseURL: 'https://api.example.com',
@@ -372,6 +640,85 @@ const api = createAPI({
372
640
  });
373
641
  ```
374
642
 
643
+ #### API 自动打点(request / response / error)
644
+
645
+ `createAPI` 已支持开发态自动打点。
646
+
647
+ 默认行为:
648
+
649
+ - 开发环境下 `observability.enabled` 默认开启
650
+ - 如果当前 App 已通过 `AppProvider` / `LoggerProvider` 启用了 logger
651
+ - 那么 API 请求会自动写入 `api` 命名空间日志
652
+
653
+ 记录阶段:
654
+
655
+ - request
656
+ - response
657
+ - error
658
+
659
+ ```tsx
660
+ const api = createAPI({
661
+ baseURL: 'https://api.example.com',
662
+ observability: {
663
+ enabled: true,
664
+ includeInput: true,
665
+ includeResponseData: false,
666
+ },
667
+ endpoints: {
668
+ getProfile: {
669
+ method: 'GET',
670
+ path: '/profile',
671
+ },
672
+ },
673
+ });
674
+ ```
675
+
676
+ 也可以添加自定义 transport:
677
+
678
+ ```tsx
679
+ const api = createAPI({
680
+ baseURL: 'https://api.example.com',
681
+ observability: {
682
+ enabled: true,
683
+ transports: [
684
+ event => {
685
+ console.log('api event', event.stage, event.endpointName);
686
+ },
687
+ ],
688
+ },
689
+ endpoints: {
690
+ getProfile: {
691
+ method: 'GET',
692
+ path: '/profile',
693
+ },
694
+ },
695
+ });
696
+ ```
697
+
698
+ 如果你想手动指定写到某个 logger,也可以:
699
+
700
+ ```tsx
701
+ const transport = createApiLoggerTransport({
702
+ namespace: 'network',
703
+ includeInput: true,
704
+ includeResponseData: true,
705
+ });
706
+
707
+ const api = createAPI({
708
+ baseURL: 'https://api.example.com',
709
+ observability: {
710
+ enabled: true,
711
+ transports: [transport],
712
+ },
713
+ endpoints: {
714
+ getProfile: {
715
+ method: 'GET',
716
+ path: '/profile',
717
+ },
718
+ },
719
+ });
720
+ ```
721
+
375
722
  ## 📄 文档
376
723
 
377
724
  - [框架文档](../../docs/README.md) - 完整文档索引
@@ -398,16 +745,31 @@ export default function App() {
398
745
 
399
746
  - 亮色主题:`dark-content`
400
747
  - 暗色主题:`light-content`
748
+ - 默认 `translucent={false}`
401
749
  - Android 状态栏背景默认跟随当前主题背景色
402
750
 
403
- ### 2. 页面级覆盖
751
+ ### 2. 使用 `AppHeader` 时的默认行为
752
+
753
+ 如果页面使用了 `AppHeader`,通常不需要再单独处理状态栏:
754
+
755
+ - `AppHeader` 内部会自动注入 `AppFocusedStatusBar`
756
+ - 配置为 `translucent + backgroundColor="transparent"`
757
+ - 顶部状态栏区域会直接显示 Header 自身背景色
758
+
759
+ 适合:
760
+
761
+ - 普通详情页
762
+ - 设置页
763
+ - 使用有色 Header 的二级页面
764
+
765
+ ### 3. 页面级覆盖
404
766
 
405
767
  如果某个页面需要单独控制状态栏,可以在页面内显式渲染:
406
768
 
407
769
  ```tsx
408
- import { AppStatusBar } from '@gaozh1024/rn-kit';
770
+ import { AppFocusedStatusBar } from '@gaozh1024/rn-kit';
409
771
 
410
- <AppStatusBar barStyle="light-content" backgroundColor="#f38b32" />;
772
+ <AppFocusedStatusBar barStyle="light-content" backgroundColor="transparent" translucent />;
411
773
  ```
412
774
 
413
775
  适合:
@@ -416,19 +778,21 @@ import { AppStatusBar } from '@gaozh1024/rn-kit';
416
778
  - 沉浸式详情页
417
779
  - 顶部大图/渐变背景页
418
780
 
419
- ### 3. 登录页全屏背景示例
781
+ 对于导航页面,优先使用 `AppFocusedStatusBar`,这样只有当前聚焦页面会覆盖状态栏配置。
782
+
783
+ ### 4. 登录页全屏背景示例
420
784
 
421
785
  如果登录页希望顶部状态栏区域也和页面背景保持一致,不要直接使用默认白底容器。
422
786
 
423
787
  推荐:
424
788
 
425
789
  ```tsx
426
- import { AppStatusBar, SafeScreen, AppView } from '@gaozh1024/rn-kit';
790
+ import { AppFocusedStatusBar, SafeScreen, AppView } from '@gaozh1024/rn-kit';
427
791
 
428
792
  export function LoginScreen() {
429
793
  return (
430
794
  <>
431
- <AppStatusBar barStyle="light-content" backgroundColor="#f38b32" translucent={false} />
795
+ <AppFocusedStatusBar barStyle="light-content" backgroundColor="transparent" translucent />
432
796
 
433
797
  <SafeScreen bg="primary-500">
434
798
  <AppView flex className="bg-primary-500">
@@ -440,15 +804,15 @@ export function LoginScreen() {
440
804
  }
441
805
  ```
442
806
 
443
- ### 4. 沉浸式状态栏示例
807
+ ### 5. 沉浸式状态栏示例
444
808
 
445
809
  ```tsx
446
- import { AppStatusBar, SafeScreen, AppView } from '@gaozh1024/rn-kit';
810
+ import { AppFocusedStatusBar, SafeScreen, AppView } from '@gaozh1024/rn-kit';
447
811
 
448
812
  export function HeroScreen() {
449
813
  return (
450
814
  <>
451
- <AppStatusBar barStyle="light-content" backgroundColor="transparent" translucent />
815
+ <AppFocusedStatusBar barStyle="light-content" backgroundColor="transparent" translucent />
452
816
 
453
817
  <SafeScreen top={false} bottom={false}>
454
818
  <AppView flex className="bg-black">
@@ -460,13 +824,13 @@ export function HeroScreen() {
460
824
  }
461
825
  ```
462
826
 
463
- ### 5. 常见问题
827
+ ### 6. 常见问题
464
828
 
465
829
  #### 为什么顶部还是白色?
466
830
 
467
831
  通常是以下原因之一:
468
832
 
469
- 1. 当前页面没有单独覆盖 `AppStatusBar`
833
+ 1. 当前页面没有使用 `AppHeader`,也没有单独覆盖 `AppFocusedStatusBar` / `AppStatusBar`
470
834
  2. 页面容器本身是白底
471
835
  3. 使用了 `AppScreen` / `SafeScreen`,但没有设置 `bg`
472
836
  4. 顶部安全区没有和页面背景统一
package/TAILWIND_SETUP.md CHANGED
@@ -40,6 +40,7 @@ module.exports = {
40
40
  ],
41
41
  safelist: [
42
42
  { pattern: /^(flex)-(1|2|3|4|5|6|7|8|9|10|11|12)$/ },
43
+ 'flex-wrap',
43
44
  { pattern: /^(items)-(start|center|end|stretch)$/ },
44
45
  { pattern: /^(justify)-(start|center|end|between|around)$/ },
45
46
  { pattern: /^(p|px|py|gap)-(0|1|2|3|4|5|6|8|10|12)$/ },