@unif/react-native-ui 0.1.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 (227) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +103 -0
  3. package/lib/module/README.md +99 -0
  4. package/lib/module/action-sheet/index.js +63 -0
  5. package/lib/module/action-sheet/index.js.map +1 -0
  6. package/lib/module/action-sheet/index.md +69 -0
  7. package/lib/module/action-sheet/style/index.js +38 -0
  8. package/lib/module/action-sheet/style/index.js.map +1 -0
  9. package/lib/module/avatar/index.js +42 -0
  10. package/lib/module/avatar/index.js.map +1 -0
  11. package/lib/module/avatar/index.md +51 -0
  12. package/lib/module/avatar/style/index.js +17 -0
  13. package/lib/module/avatar/style/index.js.map +1 -0
  14. package/lib/module/button/index.js +52 -0
  15. package/lib/module/button/index.js.map +1 -0
  16. package/lib/module/button/index.md +90 -0
  17. package/lib/module/button/style/index.js +94 -0
  18. package/lib/module/button/style/index.js.map +1 -0
  19. package/lib/module/center/index.js +21 -0
  20. package/lib/module/center/index.js.map +1 -0
  21. package/lib/module/center/index.md +28 -0
  22. package/lib/module/center/style/index.js +10 -0
  23. package/lib/module/center/style/index.js.map +1 -0
  24. package/lib/module/chip/index.js +59 -0
  25. package/lib/module/chip/index.js.map +1 -0
  26. package/lib/module/chip/index.md +60 -0
  27. package/lib/module/chip/style/index.js +40 -0
  28. package/lib/module/chip/style/index.js.map +1 -0
  29. package/lib/module/column/index.js +30 -0
  30. package/lib/module/column/index.js.map +1 -0
  31. package/lib/module/column/index.md +34 -0
  32. package/lib/module/column/style/index.js +9 -0
  33. package/lib/module/column/style/index.js.map +1 -0
  34. package/lib/module/divider/index.js +21 -0
  35. package/lib/module/divider/index.js.map +1 -0
  36. package/lib/module/divider/index.md +44 -0
  37. package/lib/module/divider/style/index.js +17 -0
  38. package/lib/module/divider/style/index.js.map +1 -0
  39. package/lib/module/hooks/index.js +4 -0
  40. package/lib/module/hooks/index.js.map +1 -0
  41. package/lib/module/hooks/index.md +71 -0
  42. package/lib/module/hooks/useMergeStyles.js +27 -0
  43. package/lib/module/hooks/useMergeStyles.js.map +1 -0
  44. package/lib/module/index.js +29 -0
  45. package/lib/module/index.js.map +1 -0
  46. package/lib/module/input/index.js +69 -0
  47. package/lib/module/input/index.js.map +1 -0
  48. package/lib/module/input/index.md +73 -0
  49. package/lib/module/input/style/index.js +27 -0
  50. package/lib/module/input/style/index.js.map +1 -0
  51. package/lib/module/list-item/index.js +69 -0
  52. package/lib/module/list-item/index.js.map +1 -0
  53. package/lib/module/list-item/index.md +101 -0
  54. package/lib/module/list-item/style/index.js +39 -0
  55. package/lib/module/list-item/style/index.js.map +1 -0
  56. package/lib/module/package.json +1 -0
  57. package/lib/module/popover/index.js +60 -0
  58. package/lib/module/popover/index.js.map +1 -0
  59. package/lib/module/popover/index.md +57 -0
  60. package/lib/module/popover/style/index.js +22 -0
  61. package/lib/module/popover/style/index.js.map +1 -0
  62. package/lib/module/row/index.js +31 -0
  63. package/lib/module/row/index.js.map +1 -0
  64. package/lib/module/row/index.md +46 -0
  65. package/lib/module/row/style/index.js +15 -0
  66. package/lib/module/row/style/index.js.map +1 -0
  67. package/lib/module/space/index.js +20 -0
  68. package/lib/module/space/index.js.map +1 -0
  69. package/lib/module/space/index.md +31 -0
  70. package/lib/module/space/style/index.js +9 -0
  71. package/lib/module/space/style/index.js.map +1 -0
  72. package/lib/module/text/index.js +30 -0
  73. package/lib/module/text/index.js.map +1 -0
  74. package/lib/module/text/index.md +63 -0
  75. package/lib/module/text/style/index.js +51 -0
  76. package/lib/module/text/style/index.js.map +1 -0
  77. package/lib/module/theme/config.js +27 -0
  78. package/lib/module/theme/config.js.map +1 -0
  79. package/lib/module/theme/tokens.js +67 -0
  80. package/lib/module/theme/tokens.js.map +1 -0
  81. package/lib/module/touchable/index.js +35 -0
  82. package/lib/module/touchable/index.js.map +1 -0
  83. package/lib/module/touchable/index.md +42 -0
  84. package/lib/module/touchable/style/index.js +9 -0
  85. package/lib/module/touchable/style/index.js.map +1 -0
  86. package/lib/module/wave-animation/index.js +67 -0
  87. package/lib/module/wave-animation/index.js.map +1 -0
  88. package/lib/module/wave-animation/index.md +50 -0
  89. package/lib/typescript/jest.setup.d.ts +1 -0
  90. package/lib/typescript/jest.setup.d.ts.map +1 -0
  91. package/lib/typescript/package.json +1 -0
  92. package/lib/typescript/src/action-sheet/index.d.ts +22 -0
  93. package/lib/typescript/src/action-sheet/index.d.ts.map +1 -0
  94. package/lib/typescript/src/action-sheet/style/index.d.ts +16 -0
  95. package/lib/typescript/src/action-sheet/style/index.d.ts.map +1 -0
  96. package/lib/typescript/src/avatar/index.d.ts +19 -0
  97. package/lib/typescript/src/avatar/index.d.ts.map +1 -0
  98. package/lib/typescript/src/avatar/style/index.d.ts +7 -0
  99. package/lib/typescript/src/avatar/style/index.d.ts.map +1 -0
  100. package/lib/typescript/src/button/index.d.ts +24 -0
  101. package/lib/typescript/src/button/index.d.ts.map +1 -0
  102. package/lib/typescript/src/button/style/index.d.ts +16 -0
  103. package/lib/typescript/src/button/style/index.d.ts.map +1 -0
  104. package/lib/typescript/src/center/index.d.ts +11 -0
  105. package/lib/typescript/src/center/index.d.ts.map +1 -0
  106. package/lib/typescript/src/center/style/index.d.ts +5 -0
  107. package/lib/typescript/src/center/style/index.d.ts.map +1 -0
  108. package/lib/typescript/src/chip/index.d.ts +22 -0
  109. package/lib/typescript/src/chip/index.d.ts.map +1 -0
  110. package/lib/typescript/src/chip/style/index.d.ts +10 -0
  111. package/lib/typescript/src/chip/style/index.d.ts.map +1 -0
  112. package/lib/typescript/src/column/index.d.ts +20 -0
  113. package/lib/typescript/src/column/index.d.ts.map +1 -0
  114. package/lib/typescript/src/column/style/index.d.ts +4 -0
  115. package/lib/typescript/src/column/style/index.d.ts.map +1 -0
  116. package/lib/typescript/src/divider/index.d.ts +13 -0
  117. package/lib/typescript/src/divider/index.d.ts.map +1 -0
  118. package/lib/typescript/src/divider/style/index.d.ts +9 -0
  119. package/lib/typescript/src/divider/style/index.d.ts.map +1 -0
  120. package/lib/typescript/src/hooks/index.d.ts +2 -0
  121. package/lib/typescript/src/hooks/index.d.ts.map +1 -0
  122. package/lib/typescript/src/hooks/useMergeStyles.d.ts +13 -0
  123. package/lib/typescript/src/hooks/useMergeStyles.d.ts.map +1 -0
  124. package/lib/typescript/src/index.d.ts +39 -0
  125. package/lib/typescript/src/index.d.ts.map +1 -0
  126. package/lib/typescript/src/input/index.d.ts +29 -0
  127. package/lib/typescript/src/input/index.d.ts.map +1 -0
  128. package/lib/typescript/src/input/style/index.d.ts +8 -0
  129. package/lib/typescript/src/input/style/index.d.ts.map +1 -0
  130. package/lib/typescript/src/list-item/index.d.ts +25 -0
  131. package/lib/typescript/src/list-item/index.d.ts.map +1 -0
  132. package/lib/typescript/src/list-item/style/index.d.ts +17 -0
  133. package/lib/typescript/src/list-item/style/index.d.ts.map +1 -0
  134. package/lib/typescript/src/popover/index.d.ts +27 -0
  135. package/lib/typescript/src/popover/index.d.ts.map +1 -0
  136. package/lib/typescript/src/popover/style/index.d.ts +7 -0
  137. package/lib/typescript/src/popover/style/index.d.ts.map +1 -0
  138. package/lib/typescript/src/row/index.d.ts +22 -0
  139. package/lib/typescript/src/row/index.d.ts.map +1 -0
  140. package/lib/typescript/src/row/style/index.d.ts +8 -0
  141. package/lib/typescript/src/row/style/index.d.ts.map +1 -0
  142. package/lib/typescript/src/space/index.d.ts +15 -0
  143. package/lib/typescript/src/space/index.d.ts.map +1 -0
  144. package/lib/typescript/src/space/style/index.d.ts +7 -0
  145. package/lib/typescript/src/space/style/index.d.ts.map +1 -0
  146. package/lib/typescript/src/text/index.d.ts +18 -0
  147. package/lib/typescript/src/text/index.d.ts.map +1 -0
  148. package/lib/typescript/src/text/style/index.d.ts +35 -0
  149. package/lib/typescript/src/text/style/index.d.ts.map +1 -0
  150. package/lib/typescript/src/theme/config.d.ts +18 -0
  151. package/lib/typescript/src/theme/config.d.ts.map +1 -0
  152. package/lib/typescript/src/theme/tokens.d.ts +61 -0
  153. package/lib/typescript/src/theme/tokens.d.ts.map +1 -0
  154. package/lib/typescript/src/touchable/index.d.ts +19 -0
  155. package/lib/typescript/src/touchable/index.d.ts.map +1 -0
  156. package/lib/typescript/src/touchable/style/index.d.ts +4 -0
  157. package/lib/typescript/src/touchable/style/index.d.ts.map +1 -0
  158. package/lib/typescript/src/wave-animation/index.d.ts +20 -0
  159. package/lib/typescript/src/wave-animation/index.d.ts.map +1 -0
  160. package/lib/typescript/tests/component/component.coverage.test.d.ts +2 -0
  161. package/lib/typescript/tests/component/component.coverage.test.d.ts.map +1 -0
  162. package/lib/typescript/tests/component/component.interaction.test.d.ts +2 -0
  163. package/lib/typescript/tests/component/component.interaction.test.d.ts.map +1 -0
  164. package/lib/typescript/tests/component/component.snapshot.test.d.ts +2 -0
  165. package/lib/typescript/tests/component/component.snapshot.test.d.ts.map +1 -0
  166. package/lib/typescript/tests/e2e/app.e2e.test.d.ts +2 -0
  167. package/lib/typescript/tests/e2e/app.e2e.test.d.ts.map +1 -0
  168. package/lib/typescript/tests/integration/ui.integration.test.d.ts +2 -0
  169. package/lib/typescript/tests/integration/ui.integration.test.d.ts.map +1 -0
  170. package/lib/typescript/tests/unit/mergeStyles.unit.test.d.ts +2 -0
  171. package/lib/typescript/tests/unit/mergeStyles.unit.test.d.ts.map +1 -0
  172. package/lib/typescript/tests/unit/public-api.unit.test.d.ts +2 -0
  173. package/lib/typescript/tests/unit/public-api.unit.test.d.ts.map +1 -0
  174. package/lib/typescript/tests/unit/theme-config.unit.test.d.ts +2 -0
  175. package/lib/typescript/tests/unit/theme-config.unit.test.d.ts.map +1 -0
  176. package/package.json +134 -0
  177. package/src/README.md +99 -0
  178. package/src/action-sheet/index.md +69 -0
  179. package/src/action-sheet/index.tsx +85 -0
  180. package/src/action-sheet/style/index.tsx +52 -0
  181. package/src/avatar/index.md +51 -0
  182. package/src/avatar/index.tsx +56 -0
  183. package/src/avatar/style/index.tsx +21 -0
  184. package/src/button/index.md +90 -0
  185. package/src/button/index.tsx +86 -0
  186. package/src/button/style/index.tsx +67 -0
  187. package/src/center/index.md +28 -0
  188. package/src/center/index.tsx +18 -0
  189. package/src/center/style/index.tsx +8 -0
  190. package/src/chip/index.md +60 -0
  191. package/src/chip/index.tsx +80 -0
  192. package/src/chip/style/index.tsx +47 -0
  193. package/src/column/index.md +34 -0
  194. package/src/column/index.tsx +43 -0
  195. package/src/column/style/index.tsx +7 -0
  196. package/src/divider/index.md +44 -0
  197. package/src/divider/index.tsx +30 -0
  198. package/src/divider/style/index.tsx +13 -0
  199. package/src/hooks/index.md +71 -0
  200. package/src/hooks/index.ts +1 -0
  201. package/src/hooks/useMergeStyles.ts +27 -0
  202. package/src/index.tsx +49 -0
  203. package/src/input/index.md +73 -0
  204. package/src/input/index.tsx +95 -0
  205. package/src/input/style/index.tsx +32 -0
  206. package/src/list-item/index.md +101 -0
  207. package/src/list-item/index.tsx +91 -0
  208. package/src/list-item/style/index.tsx +41 -0
  209. package/src/popover/index.md +57 -0
  210. package/src/popover/index.tsx +80 -0
  211. package/src/popover/style/index.tsx +23 -0
  212. package/src/row/index.md +46 -0
  213. package/src/row/index.tsx +47 -0
  214. package/src/row/style/index.tsx +14 -0
  215. package/src/space/index.md +31 -0
  216. package/src/space/index.tsx +28 -0
  217. package/src/space/style/index.tsx +3 -0
  218. package/src/text/index.md +63 -0
  219. package/src/text/index.tsx +45 -0
  220. package/src/text/style/index.tsx +32 -0
  221. package/src/theme/config.ts +26 -0
  222. package/src/theme/tokens.ts +66 -0
  223. package/src/touchable/index.md +42 -0
  224. package/src/touchable/index.tsx +45 -0
  225. package/src/touchable/style/index.tsx +5 -0
  226. package/src/wave-animation/index.md +50 -0
  227. package/src/wave-animation/index.tsx +93 -0
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Popover 基础组件
3
+ *
4
+ * 锚定定位下拉容器,仅做定位,内容由 children 传入。
5
+ */
6
+
7
+ import React, { useMemo } from 'react';
8
+ import {
9
+ View,
10
+ TouchableWithoutFeedback,
11
+ Modal,
12
+ } from 'react-native';
13
+ import type { ViewStyle } from 'react-native';
14
+ import { mergeStyles } from '../hooks';
15
+ import type { PopoverSemanticStyles } from './style';
16
+ import { DEFAULT_STYLES } from './style';
17
+
18
+ export interface PopoverProps {
19
+ visible: boolean;
20
+ onClose: () => void;
21
+ anchorLayout: { x: number; y: number; width: number; height: number };
22
+ width?: number;
23
+ placement?: 'bottom' | 'top';
24
+ children: React.ReactNode;
25
+ style?: ViewStyle;
26
+ styles?: Partial<PopoverSemanticStyles>;
27
+ testID?: string;
28
+ }
29
+
30
+ const GAP = 4;
31
+
32
+ const Popover: React.FC<PopoverProps> = ({
33
+ visible,
34
+ onClose,
35
+ anchorLayout,
36
+ width = 180,
37
+ placement = 'bottom',
38
+ children,
39
+ style,
40
+ styles: semanticStyles,
41
+ testID,
42
+ }) => {
43
+ const s = useMemo(
44
+ () => mergeStyles<PopoverSemanticStyles>(DEFAULT_STYLES, semanticStyles),
45
+ [semanticStyles],
46
+ );
47
+
48
+ if (!visible) {
49
+ return null;
50
+ }
51
+
52
+ const positionStyle: ViewStyle =
53
+ placement === 'bottom'
54
+ ? { top: anchorLayout.y + anchorLayout.height + GAP, left: anchorLayout.x }
55
+ : { bottom: anchorLayout.y - GAP, left: anchorLayout.x };
56
+
57
+ return (
58
+ <Modal
59
+ visible={visible}
60
+ transparent
61
+ animationType="fade"
62
+ onRequestClose={onClose}
63
+ >
64
+ <TouchableWithoutFeedback onPress={onClose}>
65
+ <View style={s.overlay}>
66
+ <TouchableWithoutFeedback>
67
+ <View
68
+ style={[s.content, positionStyle, { width }, style]}
69
+ testID={testID}
70
+ >
71
+ {children}
72
+ </View>
73
+ </TouchableWithoutFeedback>
74
+ </View>
75
+ </TouchableWithoutFeedback>
76
+ </Modal>
77
+ );
78
+ };
79
+
80
+ export default Popover;
@@ -0,0 +1,23 @@
1
+ import type { ViewStyle } from 'react-native';
2
+ import { tokens } from '../../theme/tokens';
3
+
4
+ export type PopoverSemanticStyles = {
5
+ overlay?: ViewStyle;
6
+ content?: ViewStyle;
7
+ };
8
+
9
+ export const DEFAULT_STYLES: PopoverSemanticStyles = {
10
+ overlay: {
11
+ flex: 1,
12
+ },
13
+ content: {
14
+ position: 'absolute',
15
+ backgroundColor: tokens.colorBgElevated,
16
+ borderRadius: 12,
17
+ shadowColor: '#000',
18
+ shadowOffset: { width: 0, height: 4 },
19
+ shadowOpacity: 0.12,
20
+ shadowRadius: 12,
21
+ elevation: 8,
22
+ },
23
+ };
@@ -0,0 +1,46 @@
1
+ # Row 水平布局
2
+
3
+ 水平排列子元素,默认垂直居中。替代 `flexDirection: 'row' + alignItems: 'center'` 的手写样式。
4
+
5
+ ## 何时使用
6
+
7
+ - 需要水平排列元素时
8
+ - 替代 `<View style={{flexDirection: 'row', alignItems: 'center'}}>` 的场景
9
+
10
+ ## 代码演示
11
+
12
+ ```tsx
13
+ // 基础用法 — 默认 alignItems: 'center'
14
+ <Row>
15
+ <Icon name="star" />
16
+ <Text>标题</Text>
17
+ </Row>
18
+
19
+ // 两端对齐
20
+ <Row justify="space-between">
21
+ <Text>左侧</Text>
22
+ <Text>右侧</Text>
23
+ </Row>
24
+
25
+ // 间距
26
+ <Row gap={10}>
27
+ <Button block onPress={...}>修改</Button>
28
+ <Button block onPress={...}>确认</Button>
29
+ </Row>
30
+
31
+ // 换行
32
+ <Row wrap gap={8}>
33
+ {tags.map(tag => <Tag key={tag}>{tag}</Tag>)}
34
+ </Row>
35
+ ```
36
+
37
+ ## API
38
+
39
+ | 属性 | 说明 | 类型 | 默认值 |
40
+ |------|------|------|--------|
41
+ | align | alignItems | `ViewStyle['alignItems']` | `'center'` |
42
+ | justify | justifyContent | `ViewStyle['justifyContent']` | - |
43
+ | gap | 子元素间距 | `number` | - |
44
+ | wrap | 是否换行 | `boolean` | `false` |
45
+
46
+ > 继承所有 RN `ViewProps`(`style`、`testID` 等)
@@ -0,0 +1,47 @@
1
+ /**
2
+ * 水平布局容器
3
+ *
4
+ * 默认 flexDirection: 'row' + alignItems: 'center'。
5
+ */
6
+
7
+ import React from 'react';
8
+ import { View } from 'react-native';
9
+ import type { ViewProps, ViewStyle } from 'react-native';
10
+ import { baseStyle, wrapStyle } from './style';
11
+
12
+ type AlignItems = ViewStyle['alignItems'];
13
+ type JustifyContent = ViewStyle['justifyContent'];
14
+
15
+ export interface RowProps extends ViewProps {
16
+ /** alignItems,默认 'center' */
17
+ align?: AlignItems;
18
+ /** justifyContent */
19
+ justify?: JustifyContent;
20
+ /** 子元素间距 */
21
+ gap?: number;
22
+ /** 是否换行 */
23
+ wrap?: boolean;
24
+ }
25
+
26
+ const Row: React.FC<RowProps> = ({
27
+ align,
28
+ justify,
29
+ gap,
30
+ wrap,
31
+ style,
32
+ ...rest
33
+ }: RowProps) => (
34
+ <View
35
+ style={[
36
+ baseStyle,
37
+ align != null && { alignItems: align },
38
+ justify != null && { justifyContent: justify },
39
+ gap != null && { gap },
40
+ wrap && wrapStyle,
41
+ style,
42
+ ]}
43
+ {...rest}
44
+ />
45
+ );
46
+
47
+ export default Row;
@@ -0,0 +1,14 @@
1
+ import { StyleSheet } from 'react-native';
2
+
3
+ export const baseStyle = StyleSheet.create({
4
+ row: {
5
+ flexDirection: 'row',
6
+ alignItems: 'center',
7
+ },
8
+ }).row;
9
+
10
+ export const wrapStyle = StyleSheet.create({
11
+ wrap: {
12
+ flexWrap: 'wrap',
13
+ },
14
+ }).wrap;
@@ -0,0 +1,31 @@
1
+ # Space 间距占位
2
+
3
+ 在两个元素之间插入固定间距。替代 `<View style={{height: 12}} />` 或 `marginTop` 手写。
4
+
5
+ ## 何时使用
6
+
7
+ - 两个块级元素之间需要固定间距
8
+ - 不想在元素上写 margin 时
9
+
10
+ ## 代码演示
11
+
12
+ ```tsx
13
+ // 垂直间距(默认)
14
+ <Text variant="title">标题</Text>
15
+ <Space size={16} />
16
+ <Text variant="body">正文内容</Text>
17
+
18
+ // 水平间距
19
+ <Row>
20
+ <Icon name="star" />
21
+ <Space size={8} direction="horizontal" />
22
+ <Text>收藏</Text>
23
+ </Row>
24
+ ```
25
+
26
+ ## API
27
+
28
+ | 属性 | 说明 | 类型 | 默认值 |
29
+ |------|------|------|--------|
30
+ | size | 间距大小(px) | `number` | `12` |
31
+ | direction | 方向 | `'vertical'` \| `'horizontal'` | `'vertical'` |
@@ -0,0 +1,28 @@
1
+ /**
2
+ * 间距占位组件
3
+ *
4
+ * 在两个元素之间插入固定间距。
5
+ */
6
+
7
+ import React from 'react';
8
+ import { View } from 'react-native';
9
+ import { verticalStyle, horizontalStyle } from './style';
10
+
11
+ export interface SpaceProps {
12
+ /** 间距大小,默认 12 */
13
+ size?: number;
14
+ /** 方向,默认 'vertical' */
15
+ direction?: 'horizontal' | 'vertical';
16
+ }
17
+
18
+ const Space: React.FC<SpaceProps> = ({ size = 12, direction = 'vertical' }) => (
19
+ <View
20
+ style={
21
+ direction === 'vertical'
22
+ ? verticalStyle(size)
23
+ : horizontalStyle(size)
24
+ }
25
+ />
26
+ );
27
+
28
+ export default Space;
@@ -0,0 +1,3 @@
1
+ export const verticalStyle = (size: number) => ({ height: size });
2
+
3
+ export const horizontalStyle = (size: number) => ({ width: size });
@@ -0,0 +1,63 @@
1
+ # Text 语义化文字
2
+
3
+ 通过 `variant` 驱动排版样式。继承 RN `Text`,支持嵌套。
4
+
5
+ ## 何时使用
6
+
7
+ - 替代直接写 `fontSize` + `fontWeight` + `color` 的 `<Text>` 组合
8
+ - 需要统一排版规范时
9
+
10
+ ## 代码演示
11
+
12
+ ```tsx
13
+ // 基础用法
14
+ <Text variant="title">标题文字</Text>
15
+ <Text variant="caption" secondary>辅助说明</Text>
16
+
17
+ // 颜色与字重
18
+ <Text variant="caption" primary weight="bold">¥88.00</Text>
19
+
20
+ // 嵌套 Text
21
+ <Text variant="body" numberOfLines={1}>
22
+ <Text primary weight="semibold">新 </Text>
23
+ {productName}
24
+ </Text>
25
+ ```
26
+
27
+ ## API
28
+
29
+ | 属性 | 说明 | 类型 | 默认值 |
30
+ |------|------|------|--------|
31
+ | variant | 排版变体 | `'title'` \| `'heading'` \| `'body'` \| `'caption'` \| `'micro'` | `'body'` |
32
+ | secondary | 次要色(colorTextSecondary) | `boolean` | `false` |
33
+ | primary | 主题色(colorPrimary) | `boolean` | `false` |
34
+ | color | 自定义颜色 | `string` | - |
35
+ | weight | 字重 | `'medium'` \| `'semibold'` \| `'bold'` | - |
36
+
37
+ > 继承所有 RN `TextProps`(`numberOfLines`、`ellipsizeMode`、`onPress`、`style` 等)
38
+
39
+ ## Variant 规格
40
+
41
+ | variant | fontSize | lineHeight | fontWeight | 场景 |
42
+ |---------|----------|------------|------------|------|
43
+ | title | 20 | 26 | 600 | 页面标题、问候语 |
44
+ | heading | 16 | 22 | 600 | 弹窗标题、区块标题 |
45
+ | body | 15 | 22 | 正常 | 默认正文 |
46
+ | caption | 13 | 18 | 正常 | 信息行、标签 |
47
+ | micro | 12 | 18 | 正常 | 地址、规格、描述 |
48
+
49
+ ## Weight 映射
50
+
51
+ | weight | fontWeight | 场景 |
52
+ |--------|----------|------|
53
+ | medium | 500 | 产品名、模型名 |
54
+ | semibold | 600 | 标题、按钮文字、客户名 |
55
+ | bold | 700 | 价格金额 |
56
+
57
+ ## 样式优先级
58
+
59
+ ```
60
+ VARIANT_MAP → secondary/primary → color → weight → style
61
+ ```
62
+
63
+ 后传入的属性覆盖先传入的,`style` prop 拥有最高优先级。
@@ -0,0 +1,45 @@
1
+ /**
2
+ * 语义化文字组件
3
+ *
4
+ * variant 驱动样式,支持嵌套 Text。
5
+ */
6
+
7
+ import React from 'react';
8
+ import { Text as RNText } from 'react-native';
9
+ import type { TextProps as RNTextProps } from 'react-native';
10
+ import type { FontWeight } from './style';
11
+ import { VARIANT_MAP, WEIGHT_MAP, secondaryStyle, primaryStyle } from './style';
12
+
13
+ export interface TextProps extends RNTextProps {
14
+ variant?: 'title' | 'heading' | 'body' | 'caption' | 'micro';
15
+ secondary?: boolean;
16
+ primary?: boolean;
17
+ color?: string;
18
+ weight?: FontWeight;
19
+ }
20
+
21
+ const Text: React.FC<TextProps> = ({
22
+ variant = 'body',
23
+ secondary,
24
+ primary,
25
+ color,
26
+ weight,
27
+ style,
28
+ ...rest
29
+ }: TextProps) => {
30
+ return (
31
+ <RNText
32
+ style={[
33
+ VARIANT_MAP[variant],
34
+ secondary && secondaryStyle,
35
+ primary && primaryStyle,
36
+ color != null && { color },
37
+ weight != null && WEIGHT_MAP[weight],
38
+ style,
39
+ ]}
40
+ {...rest}
41
+ />
42
+ );
43
+ };
44
+
45
+ export default Text;
@@ -0,0 +1,32 @@
1
+ import { StyleSheet } from 'react-native';
2
+ import type { TextStyle } from 'react-native';
3
+ import { tokens } from '../../theme/tokens';
4
+
5
+ export type FontWeight = 'medium' | 'semibold' | 'bold';
6
+
7
+ export const VARIANT_MAP = StyleSheet.create({
8
+ title: {
9
+ fontSize: 20,
10
+ lineHeight: 26,
11
+ fontWeight: '600',
12
+ color: tokens.colorText,
13
+ },
14
+ heading: {
15
+ fontSize: 16,
16
+ lineHeight: 22,
17
+ fontWeight: '600',
18
+ color: tokens.colorText,
19
+ },
20
+ body: { fontSize: 15, lineHeight: 22, color: tokens.colorText },
21
+ caption: { fontSize: 13, lineHeight: 18, color: tokens.colorText },
22
+ micro: { fontSize: 12, lineHeight: 18, color: tokens.colorText },
23
+ });
24
+
25
+ export const WEIGHT_MAP: Record<FontWeight, TextStyle> = {
26
+ medium: { fontWeight: '500' },
27
+ semibold: { fontWeight: '600' },
28
+ bold: { fontWeight: '700' },
29
+ };
30
+
31
+ export const secondaryStyle: TextStyle = { color: tokens.colorTextSecondary };
32
+ export const primaryStyle: TextStyle = { color: tokens.colorPrimary };
@@ -0,0 +1,26 @@
1
+ /**
2
+ * 主题配置
3
+ *
4
+ * 消费方通过 configure() 注入主题色,实现包与业务解耦。
5
+ */
6
+
7
+ export interface ThemeConfig {
8
+ primaryColor?: string;
9
+ }
10
+
11
+ let _config: ThemeConfig = {};
12
+
13
+ /**
14
+ * 配置主题
15
+ *
16
+ * @example
17
+ * import { configure } from '@unif/react-native-ui';
18
+ * configure({ primaryColor: getAppThemeColor() });
19
+ */
20
+ export function configure(options: ThemeConfig): void {
21
+ _config = { ..._config, ...options };
22
+ }
23
+
24
+ export function getPrimaryColor(): string {
25
+ return _config.primaryColor || '#EB6E00';
26
+ }
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Design Tokens
3
+ */
4
+
5
+ import { getPrimaryColor } from './config';
6
+
7
+ export const tokens = {
8
+ get colorPrimary() {
9
+ return getPrimaryColor();
10
+ },
11
+ colorSuccess: '#34C759',
12
+ colorWarning: '#FF9500',
13
+ colorError: '#FF3B30',
14
+
15
+ colorBgPage: '#F7F7F8',
16
+ colorBgElevated: '#FFFFFF',
17
+ colorBgUserMsg: '#F0F0F0',
18
+
19
+ colorText: '#1D1D1F',
20
+ colorTextSecondary: '#8E8E93',
21
+ colorTextPlaceholder: '#C7C7CC',
22
+ colorBorder: '#E5E5EA',
23
+ colorLink: '#007AFF',
24
+
25
+ colorBgHeader: '#FFFFFF',
26
+ colorHeaderText: '#1D1D1F',
27
+ colorHeaderIcon: '#8E8E93',
28
+
29
+ fontSizeXs: 11,
30
+ fontSizeSm: 13,
31
+ fontSize: 15,
32
+ fontSizeMd: 16,
33
+ fontSizeLg: 17,
34
+ fontSizeXl: 20,
35
+ lineHeight: 22,
36
+ lineHeightLg: 26,
37
+
38
+ spaceXs: 4,
39
+ spaceSm: 8,
40
+ space: 12,
41
+ spaceMd: 16,
42
+ spaceLg: 20,
43
+ spaceXl: 24,
44
+ spaceXxl: 32,
45
+
46
+ radiusSm: 6,
47
+ radius: 10,
48
+ radiusLg: 16,
49
+ radiusXl: 20,
50
+ radiusFull: 999,
51
+
52
+ shadowSm: {
53
+ shadowColor: '#000',
54
+ shadowOffset: { width: 0, height: 1 },
55
+ shadowOpacity: 0.04,
56
+ shadowRadius: 2,
57
+ elevation: 1,
58
+ },
59
+ shadow: {
60
+ shadowColor: '#000',
61
+ shadowOffset: { width: 0, height: 2 },
62
+ shadowOpacity: 0.06,
63
+ shadowRadius: 4,
64
+ elevation: 2,
65
+ },
66
+ };
@@ -0,0 +1,42 @@
1
+ # Touchable 统一触摸反馈
2
+
3
+ 基于 `Pressable`,统一替代 `TouchableOpacity`。按下时降低透明度,支持自定义 `activeOpacity`。
4
+
5
+ ## 何时使用
6
+
7
+ - 替代所有 `TouchableOpacity` 的场景
8
+ - 需要可点击区域(非按钮语义)时
9
+
10
+ ## 代码演示
11
+
12
+ ```tsx
13
+ // 基础用法
14
+ <Touchable onPress={handlePress}>
15
+ <Row gap={10}>
16
+ <Icon name="settings" />
17
+ <Text>设置</Text>
18
+ </Row>
19
+ </Touchable>
20
+
21
+ // 自定义按下透明度
22
+ <Touchable onPress={handlePress} activeOpacity={0.5}>
23
+ <Text>更明显的按下效果</Text>
24
+ </Touchable>
25
+
26
+ // 长按
27
+ <Touchable onPress={handlePress} onLongPress={handleLongPress}>
28
+ <Text>支持长按</Text>
29
+ </Touchable>
30
+ ```
31
+
32
+ ## API
33
+
34
+ | 属性 | 说明 | 类型 | 默认值 |
35
+ |------|------|------|--------|
36
+ | onPress | 点击回调 | `() => void` | - |
37
+ | onLongPress | 长按回调 | `() => void` | - |
38
+ | disabled | 禁用状态 | `boolean` | `false` |
39
+ | activeOpacity | 按下态透明度 | `number` | `0.7` |
40
+ | testID | 测试标识 | `string` | - |
41
+
42
+ > 继承所有 RN `ViewProps`
@@ -0,0 +1,45 @@
1
+ /**
2
+ * 统一触摸反馈组件
3
+ *
4
+ * 基于 Pressable,替代 TouchableOpacity。
5
+ * 按下时透明度降低,支持 activeOpacity 自定义。
6
+ */
7
+
8
+ import React from 'react';
9
+ import { Pressable } from 'react-native';
10
+ import type { ViewProps, ViewStyle } from 'react-native';
11
+ import { disabledStyle } from './style';
12
+
13
+ export interface TouchableProps extends ViewProps {
14
+ onPress?: () => void;
15
+ onLongPress?: () => void;
16
+ disabled?: boolean;
17
+ /** 按下态透明度,默认 0.7 */
18
+ activeOpacity?: number;
19
+ testID?: string;
20
+ }
21
+
22
+ const Touchable: React.FC<TouchableProps> = ({
23
+ onPress,
24
+ onLongPress,
25
+ disabled,
26
+ activeOpacity = 0.7,
27
+ style,
28
+ testID,
29
+ ...rest
30
+ }: TouchableProps) => (
31
+ <Pressable
32
+ onPress={onPress}
33
+ onLongPress={onLongPress}
34
+ disabled={disabled}
35
+ testID={testID}
36
+ style={({ pressed }) => [
37
+ style as ViewStyle,
38
+ pressed && { opacity: activeOpacity },
39
+ disabled && disabledStyle,
40
+ ]}
41
+ {...rest}
42
+ />
43
+ );
44
+
45
+ export default Touchable;
@@ -0,0 +1,5 @@
1
+ import { StyleSheet } from 'react-native';
2
+
3
+ export const disabledStyle = StyleSheet.create({
4
+ s: { opacity: 0.4 },
5
+ }).s;
@@ -0,0 +1,50 @@
1
+ ---
2
+ title: WaveAnimation
3
+ nav:
4
+ title: 组件
5
+ order: 1
6
+ group:
7
+ title: 原子
8
+ order: 1
9
+ ---
10
+
11
+ # WaveAnimation 声波动画
12
+
13
+ 柱状声波动画,适用于语音录制等场景的视觉反馈。
14
+
15
+ ## 何时使用
16
+
17
+ - 语音录制时展示声波效果
18
+ - 需要节奏性动画反馈时
19
+
20
+ ## 代码演示
21
+
22
+ ```tsx
23
+ import { WaveAnimation } from '@unif/react-native-ui';
24
+
25
+ // 基本用法
26
+ <WaveAnimation active={isRecording} />
27
+
28
+ // 自定义参数
29
+ <WaveAnimation
30
+ active={true}
31
+ color="#EB6E00"
32
+ barCount={5}
33
+ barWidth={4}
34
+ minHeight={4}
35
+ maxHeight={24}
36
+ />
37
+ ```
38
+
39
+ ## API
40
+
41
+ | 属性 | 说明 | 类型 | 默认值 |
42
+ | --------- | ------------ | ---------- | ----------- |
43
+ | active | 控制动画启停 | `boolean` | - |
44
+ | color | 柱体颜色 | `string` | `'#FFFFFF'` |
45
+ | barCount | 柱数 | `number` | `4` |
46
+ | barWidth | 柱宽 | `number` | `3` |
47
+ | minHeight | 最小高度 | `number` | `6` |
48
+ | maxHeight | 最大高度 | `number` | `20` |
49
+ | style | 容器样式 | `ViewStyle`| - |
50
+ | testID | 测试标识 | `string` | - |