@unif/react-native-ui 0.2.31 → 0.3.5
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 +15 -9
- package/lib/commonjs/action-sheet/index.js +7 -3
- package/lib/commonjs/action-sheet/index.js.map +1 -1
- package/lib/commonjs/action-sheet/style/index.js +6 -0
- package/lib/commonjs/action-sheet/style/index.js.map +1 -1
- package/lib/commonjs/avatar/style/index.js.map +1 -1
- package/lib/commonjs/button/index.js +5 -4
- package/lib/commonjs/button/index.js.map +1 -1
- package/lib/commonjs/button/style/index.js.map +1 -1
- package/lib/commonjs/index.js +7 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/input/index.js +1 -0
- package/lib/commonjs/input/index.js.map +1 -1
- package/lib/commonjs/menu/index.js +1 -0
- package/lib/commonjs/menu/index.js.map +1 -1
- package/lib/commonjs/popover/index.js +9 -1
- package/lib/commonjs/popover/index.js.map +1 -1
- package/lib/commonjs/tag/index.js +57 -0
- package/lib/commonjs/tag/index.js.map +1 -0
- package/lib/commonjs/tag/style/index.js +91 -0
- package/lib/commonjs/tag/style/index.js.map +1 -0
- package/lib/module/action-sheet/index.js +7 -3
- package/lib/module/action-sheet/index.js.map +1 -1
- package/lib/module/action-sheet/style/index.js +6 -0
- package/lib/module/action-sheet/style/index.js.map +1 -1
- package/lib/module/avatar/style/index.js.map +1 -1
- package/lib/module/button/index.js +5 -4
- package/lib/module/button/index.js.map +1 -1
- package/lib/module/button/style/index.js.map +1 -1
- package/lib/module/index.js +1 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/input/index.js +1 -0
- package/lib/module/input/index.js.map +1 -1
- package/lib/module/menu/index.js +1 -0
- package/lib/module/menu/index.js.map +1 -1
- package/lib/module/popover/index.js +10 -2
- package/lib/module/popover/index.js.map +1 -1
- package/lib/module/tag/index.js +52 -0
- package/lib/module/tag/index.js.map +1 -0
- package/lib/module/tag/style/index.js +81 -0
- package/lib/module/tag/style/index.js.map +1 -0
- package/lib/typescript/commonjs/docusaurus.config.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/action-sheet/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/action-sheet/style/index.d.ts +1 -0
- package/lib/typescript/commonjs/src/action-sheet/style/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/button/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/button/style/index.d.ts +2 -2
- package/lib/typescript/commonjs/src/button/style/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/index.d.ts +3 -0
- package/lib/typescript/commonjs/src/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/input/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/menu/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/popover/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/tag/index.d.ts +25 -0
- package/lib/typescript/commonjs/src/tag/index.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/tag/style/index.d.ts +17 -0
- package/lib/typescript/commonjs/src/tag/style/index.d.ts.map +1 -0
- package/lib/typescript/module/docusaurus.config.d.ts.map +1 -1
- package/lib/typescript/module/src/action-sheet/index.d.ts.map +1 -1
- package/lib/typescript/module/src/action-sheet/style/index.d.ts +1 -0
- package/lib/typescript/module/src/action-sheet/style/index.d.ts.map +1 -1
- package/lib/typescript/module/src/button/index.d.ts.map +1 -1
- package/lib/typescript/module/src/button/style/index.d.ts +2 -2
- package/lib/typescript/module/src/button/style/index.d.ts.map +1 -1
- package/lib/typescript/module/src/index.d.ts +3 -0
- package/lib/typescript/module/src/index.d.ts.map +1 -1
- package/lib/typescript/module/src/input/index.d.ts.map +1 -1
- package/lib/typescript/module/src/menu/index.d.ts.map +1 -1
- package/lib/typescript/module/src/popover/index.d.ts.map +1 -1
- package/lib/typescript/module/src/tag/index.d.ts +25 -0
- package/lib/typescript/module/src/tag/index.d.ts.map +1 -0
- package/lib/typescript/module/src/tag/style/index.d.ts +17 -0
- package/lib/typescript/module/src/tag/style/index.d.ts.map +1 -0
- package/package.json +1 -1
- package/src/action-sheet/index.tsx +4 -2
- package/src/action-sheet/style/index.tsx +7 -0
- package/src/avatar/style/index.tsx +2 -2
- package/src/button/index.tsx +3 -1
- package/src/button/style/index.tsx +8 -2
- package/src/index.tsx +3 -0
- package/src/input/index.tsx +1 -0
- package/src/menu/index.tsx +1 -0
- package/src/popover/index.tsx +21 -4
- package/src/tag/index.tsx +78 -0
- package/src/tag/style/index.tsx +99 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tag 标签组件
|
|
3
|
+
*
|
|
4
|
+
* 信息展示标签,支持三种变体:
|
|
5
|
+
* - filled(默认):浅色底 + 深色字
|
|
6
|
+
* - solid:纯色底 + 白字
|
|
7
|
+
* - outlined:边框 + 深色字
|
|
8
|
+
*
|
|
9
|
+
* color 支持预设语义色(success/processing/warning/error/default)或自定义 hex。
|
|
10
|
+
*/
|
|
11
|
+
import React from 'react';
|
|
12
|
+
import type { ViewStyle } from 'react-native';
|
|
13
|
+
import type { TagSemanticStyles } from './style';
|
|
14
|
+
export interface TagProps {
|
|
15
|
+
children: React.ReactNode;
|
|
16
|
+
variant?: 'filled' | 'solid' | 'outlined';
|
|
17
|
+
color?: string;
|
|
18
|
+
size?: 'default' | 'small';
|
|
19
|
+
style?: ViewStyle;
|
|
20
|
+
styles?: Partial<TagSemanticStyles>;
|
|
21
|
+
testID?: string;
|
|
22
|
+
}
|
|
23
|
+
declare const Tag: React.FC<TagProps>;
|
|
24
|
+
export default Tag;
|
|
25
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/tag/index.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAkB,MAAM,OAAO,CAAC;AAEvC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAG9C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAUjD,MAAM,WAAW,QAAQ;IACvB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,OAAO,CAAC,EAAE,QAAQ,GAAG,OAAO,GAAG,UAAU,CAAC;IAC1C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC;IAC3B,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC,iBAAiB,CAAC,CAAC;IACpC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,QAAA,MAAM,GAAG,EAAE,KAAK,CAAC,EAAE,CAAC,QAAQ,CAuC3B,CAAC;AAEF,eAAe,GAAG,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ViewStyle, TextStyle } from 'react-native';
|
|
2
|
+
import type { Tokens } from '../../theme/tokens';
|
|
3
|
+
export type TagSemanticStyles = {
|
|
4
|
+
root?: ViewStyle;
|
|
5
|
+
content?: TextStyle;
|
|
6
|
+
};
|
|
7
|
+
/** 解析颜色:支持预设名或自定义 hex */
|
|
8
|
+
export declare function resolveColor(color: string | undefined): string;
|
|
9
|
+
export declare const createDefaultStyles: (t: Tokens) => TagSemanticStyles;
|
|
10
|
+
export declare const createSmallStyles: () => Partial<TagSemanticStyles>;
|
|
11
|
+
/** filled: 浅色底 + 深色字(默认) */
|
|
12
|
+
export declare const createFilledStyles: (color: string) => Partial<TagSemanticStyles>;
|
|
13
|
+
/** solid: 纯色底 + 白字 */
|
|
14
|
+
export declare const createSolidStyles: (color: string) => Partial<TagSemanticStyles>;
|
|
15
|
+
/** outlined: 边框 + 深色字 + 透明底 */
|
|
16
|
+
export declare const createOutlinedStyles: (color: string) => Partial<TagSemanticStyles>;
|
|
17
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../src/tag/style/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAEjD,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,OAAO,CAAC,EAAE,SAAS,CAAC;CACrB,CAAC;AAaF,yBAAyB;AACzB,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAI9D;AAcD,eAAO,MAAM,mBAAmB,GAAI,GAAG,MAAM,KAAG,iBAY9C,CAAC;AAEH,eAAO,MAAM,iBAAiB,QAAO,OAAO,CAAC,iBAAiB,CAQ5D,CAAC;AAEH,4BAA4B;AAC5B,eAAO,MAAM,kBAAkB,GAC7B,OAAO,MAAM,KACZ,OAAO,CAAC,iBAAiB,CAO1B,CAAC;AAEH,sBAAsB;AACtB,eAAO,MAAM,iBAAiB,GAC5B,OAAO,MAAM,KACZ,OAAO,CAAC,iBAAiB,CAO1B,CAAC;AAEH,+BAA+B;AAC/B,eAAO,MAAM,oBAAoB,GAC/B,OAAO,MAAM,KACZ,OAAO,CAAC,iBAAiB,CAS1B,CAAC"}
|
package/package.json
CHANGED
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
TouchableWithoutFeedback,
|
|
13
13
|
Modal,
|
|
14
14
|
} from 'react-native';
|
|
15
|
-
import type { ViewStyle } from 'react-native';
|
|
15
|
+
import type { ViewStyle, DimensionValue } from 'react-native';
|
|
16
16
|
import { mergeStyles } from '../hooks';
|
|
17
17
|
import { useTokens } from '../theme/context';
|
|
18
18
|
import type { ActionSheetSemanticStyles, ActionSheetOption } from './style';
|
|
@@ -33,6 +33,7 @@ export interface ActionSheetProps {
|
|
|
33
33
|
const ActionSheet: React.FC<ActionSheetProps> = ({
|
|
34
34
|
visible,
|
|
35
35
|
onClose,
|
|
36
|
+
title,
|
|
36
37
|
options,
|
|
37
38
|
onSelect,
|
|
38
39
|
columns = 3,
|
|
@@ -64,13 +65,14 @@ const ActionSheet: React.FC<ActionSheetProps> = ({
|
|
|
64
65
|
</TouchableWithoutFeedback>
|
|
65
66
|
|
|
66
67
|
<View style={[s.panel, style]} testID={testID}>
|
|
68
|
+
{title ? <Text style={s.title}>{title}</Text> : null}
|
|
67
69
|
<View style={s.grid}>
|
|
68
70
|
{options.map((item) => (
|
|
69
71
|
<TouchableOpacity
|
|
70
72
|
key={item.key}
|
|
71
73
|
style={[
|
|
72
74
|
s.option,
|
|
73
|
-
{ width: `${Math.floor(100 / columns)}%` as
|
|
75
|
+
{ width: `${Math.floor(100 / columns)}%` as DimensionValue },
|
|
74
76
|
]}
|
|
75
77
|
onPress={() => onSelect(item.key)}
|
|
76
78
|
activeOpacity={0.7}
|
|
@@ -4,6 +4,7 @@ import type { Tokens } from '../../theme/tokens';
|
|
|
4
4
|
export type ActionSheetSemanticStyles = {
|
|
5
5
|
overlay?: ViewStyle;
|
|
6
6
|
panel?: ViewStyle;
|
|
7
|
+
title?: TextStyle;
|
|
7
8
|
grid?: ViewStyle;
|
|
8
9
|
option?: ViewStyle;
|
|
9
10
|
optionIcon?: ViewStyle;
|
|
@@ -29,6 +30,12 @@ export const createDefaultStyles = (t: Tokens): ActionSheetSemanticStyles => ({
|
|
|
29
30
|
paddingBottom: 24,
|
|
30
31
|
paddingHorizontal: t.spaceMd,
|
|
31
32
|
},
|
|
33
|
+
title: {
|
|
34
|
+
fontSize: t.fontSizeMd,
|
|
35
|
+
color: t.colorText,
|
|
36
|
+
textAlign: 'center',
|
|
37
|
+
paddingBottom: t.spaceMd,
|
|
38
|
+
},
|
|
32
39
|
grid: {
|
|
33
40
|
flexDirection: 'row',
|
|
34
41
|
justifyContent: 'space-around',
|
package/src/button/index.tsx
CHANGED
|
@@ -68,6 +68,8 @@ const Button: React.FC<ButtonProps> = ({
|
|
|
68
68
|
style={({ pressed }) => [s.root, pressed && PRESSED_STYLE, style]}
|
|
69
69
|
onPress={onPress}
|
|
70
70
|
disabled={disabled || loading}
|
|
71
|
+
accessibilityRole="button"
|
|
72
|
+
accessibilityState={{ disabled: !!disabled || !!loading }}
|
|
71
73
|
testID={testID}
|
|
72
74
|
>
|
|
73
75
|
{icon && <View style={s.icon}>{icon}</View>}
|
|
@@ -81,7 +83,7 @@ const Button: React.FC<ButtonProps> = ({
|
|
|
81
83
|
{typeof children === 'string' ? (
|
|
82
84
|
<Text style={s.content}>{children}</Text>
|
|
83
85
|
) : (
|
|
84
|
-
|
|
86
|
+
children
|
|
85
87
|
)}
|
|
86
88
|
</Pressable>
|
|
87
89
|
);
|
|
@@ -22,7 +22,10 @@ export const DEFAULT_STYLES: ButtonSemanticStyles = {
|
|
|
22
22
|
},
|
|
23
23
|
};
|
|
24
24
|
|
|
25
|
-
export const SIZE_STYLES: Record<
|
|
25
|
+
export const SIZE_STYLES: Record<
|
|
26
|
+
'default' | 'small',
|
|
27
|
+
Partial<ButtonSemanticStyles>
|
|
28
|
+
> = {
|
|
26
29
|
default: {
|
|
27
30
|
root: { paddingVertical: 10, borderRadius: 8 },
|
|
28
31
|
content: { fontSize: 14 },
|
|
@@ -35,7 +38,10 @@ export const SIZE_STYLES: Record<string, Partial<ButtonSemanticStyles>> = {
|
|
|
35
38
|
|
|
36
39
|
export const createTypeStyles = (
|
|
37
40
|
t: Tokens
|
|
38
|
-
): Record<
|
|
41
|
+
): Record<
|
|
42
|
+
'primary' | 'outline' | 'ghost' | 'danger',
|
|
43
|
+
Partial<ButtonSemanticStyles>
|
|
44
|
+
> => ({
|
|
39
45
|
primary: {
|
|
40
46
|
root: { backgroundColor: t.colorPrimary },
|
|
41
47
|
content: { color: '#FFF', fontWeight: '600' },
|
package/src/index.tsx
CHANGED
|
@@ -42,6 +42,9 @@ export type { InputSemanticStyles } from './input/style';
|
|
|
42
42
|
export { default as Chip } from './chip';
|
|
43
43
|
export type { ChipProps } from './chip';
|
|
44
44
|
export type { ChipSemanticStyles } from './chip/style';
|
|
45
|
+
export { default as Tag } from './tag';
|
|
46
|
+
export type { TagProps } from './tag';
|
|
47
|
+
export type { TagSemanticStyles } from './tag/style';
|
|
45
48
|
export { default as ActionSheet } from './action-sheet';
|
|
46
49
|
export type { ActionSheetProps } from './action-sheet';
|
|
47
50
|
export type {
|
package/src/input/index.tsx
CHANGED
|
@@ -82,6 +82,7 @@ const Input = forwardRef<InputRef, InputProps>(
|
|
|
82
82
|
onChangeText={onChangeText}
|
|
83
83
|
placeholder={placeholder}
|
|
84
84
|
placeholderTextColor={tokens.colorTextPlaceholder}
|
|
85
|
+
accessibilityLabel={placeholder}
|
|
85
86
|
multiline={multiline}
|
|
86
87
|
maxLength={maxLength}
|
|
87
88
|
returnKeyType={returnKeyType}
|
package/src/menu/index.tsx
CHANGED
package/src/popover/index.tsx
CHANGED
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
* 锚定定位下拉容器,仅做定位,内容由 children 传入。
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import React, { useMemo } from 'react';
|
|
7
|
+
import React, { useCallback, useMemo, useState } from 'react';
|
|
8
8
|
import { View, TouchableWithoutFeedback, Modal } from 'react-native';
|
|
9
|
-
import type { ViewStyle } from 'react-native';
|
|
9
|
+
import type { LayoutChangeEvent, ViewStyle } from 'react-native';
|
|
10
10
|
import { mergeStyles } from '../hooks';
|
|
11
11
|
import { useTokens } from '../theme/context';
|
|
12
12
|
import type { PopoverSemanticStyles } from './style';
|
|
@@ -39,23 +39,33 @@ const Popover: React.FC<PopoverProps> = ({
|
|
|
39
39
|
}) => {
|
|
40
40
|
const tokens = useTokens();
|
|
41
41
|
const defaultStyles = useMemo(() => createDefaultStyles(tokens), [tokens]);
|
|
42
|
+
const [contentHeight, setContentHeight] = useState(0);
|
|
42
43
|
|
|
43
44
|
const s = useMemo(
|
|
44
45
|
() => mergeStyles<PopoverSemanticStyles>(defaultStyles, semanticStyles),
|
|
45
46
|
[defaultStyles, semanticStyles]
|
|
46
47
|
);
|
|
47
48
|
|
|
49
|
+
const handleLayout = useCallback((e: LayoutChangeEvent) => {
|
|
50
|
+
setContentHeight(e.nativeEvent.layout.height);
|
|
51
|
+
}, []);
|
|
52
|
+
|
|
48
53
|
if (!visible) {
|
|
49
54
|
return null;
|
|
50
55
|
}
|
|
51
56
|
|
|
57
|
+
const needsHeight = placement === 'top' && contentHeight === 0;
|
|
58
|
+
|
|
52
59
|
const positionStyle: ViewStyle =
|
|
53
60
|
placement === 'bottom'
|
|
54
61
|
? {
|
|
55
62
|
top: anchorLayout.y + anchorLayout.height + GAP,
|
|
56
63
|
left: anchorLayout.x,
|
|
57
64
|
}
|
|
58
|
-
: {
|
|
65
|
+
: {
|
|
66
|
+
top: anchorLayout.y - contentHeight - GAP,
|
|
67
|
+
left: anchorLayout.x,
|
|
68
|
+
};
|
|
59
69
|
|
|
60
70
|
return (
|
|
61
71
|
<Modal
|
|
@@ -68,7 +78,14 @@ const Popover: React.FC<PopoverProps> = ({
|
|
|
68
78
|
<View style={s.overlay}>
|
|
69
79
|
<TouchableWithoutFeedback>
|
|
70
80
|
<View
|
|
71
|
-
|
|
81
|
+
onLayout={handleLayout}
|
|
82
|
+
style={[
|
|
83
|
+
s.content,
|
|
84
|
+
positionStyle,
|
|
85
|
+
{ width },
|
|
86
|
+
needsHeight && { opacity: 0 },
|
|
87
|
+
style,
|
|
88
|
+
]}
|
|
72
89
|
testID={testID}
|
|
73
90
|
>
|
|
74
91
|
{children}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tag 标签组件
|
|
3
|
+
*
|
|
4
|
+
* 信息展示标签,支持三种变体:
|
|
5
|
+
* - filled(默认):浅色底 + 深色字
|
|
6
|
+
* - solid:纯色底 + 白字
|
|
7
|
+
* - outlined:边框 + 深色字
|
|
8
|
+
*
|
|
9
|
+
* color 支持预设语义色(success/processing/warning/error/default)或自定义 hex。
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import React, { useMemo } from 'react';
|
|
13
|
+
import { View, Text } from 'react-native';
|
|
14
|
+
import type { ViewStyle } from 'react-native';
|
|
15
|
+
import { mergeStyles } from '../hooks';
|
|
16
|
+
import { useTokens } from '../theme/context';
|
|
17
|
+
import type { TagSemanticStyles } from './style';
|
|
18
|
+
import {
|
|
19
|
+
createDefaultStyles,
|
|
20
|
+
createSmallStyles,
|
|
21
|
+
createFilledStyles,
|
|
22
|
+
createSolidStyles,
|
|
23
|
+
createOutlinedStyles,
|
|
24
|
+
resolveColor,
|
|
25
|
+
} from './style';
|
|
26
|
+
|
|
27
|
+
export interface TagProps {
|
|
28
|
+
children: React.ReactNode;
|
|
29
|
+
variant?: 'filled' | 'solid' | 'outlined';
|
|
30
|
+
color?: string;
|
|
31
|
+
size?: 'default' | 'small';
|
|
32
|
+
style?: ViewStyle;
|
|
33
|
+
styles?: Partial<TagSemanticStyles>;
|
|
34
|
+
testID?: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const Tag: React.FC<TagProps> = ({
|
|
38
|
+
children,
|
|
39
|
+
variant = 'filled',
|
|
40
|
+
color,
|
|
41
|
+
size = 'default',
|
|
42
|
+
style,
|
|
43
|
+
styles: semanticStyles,
|
|
44
|
+
testID,
|
|
45
|
+
}) => {
|
|
46
|
+
const tokens = useTokens();
|
|
47
|
+
const resolved = resolveColor(color);
|
|
48
|
+
|
|
49
|
+
const s = useMemo(() => {
|
|
50
|
+
let variantStyles;
|
|
51
|
+
if (variant === 'solid') {
|
|
52
|
+
variantStyles = createSolidStyles(resolved);
|
|
53
|
+
} else if (variant === 'outlined') {
|
|
54
|
+
variantStyles = createOutlinedStyles(resolved);
|
|
55
|
+
} else {
|
|
56
|
+
variantStyles = createFilledStyles(resolved);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return mergeStyles<TagSemanticStyles>(
|
|
60
|
+
createDefaultStyles(tokens),
|
|
61
|
+
size === 'small' ? createSmallStyles() : undefined,
|
|
62
|
+
variantStyles,
|
|
63
|
+
semanticStyles
|
|
64
|
+
);
|
|
65
|
+
}, [variant, resolved, size, tokens, semanticStyles]);
|
|
66
|
+
|
|
67
|
+
return (
|
|
68
|
+
<View style={[s.root, style]} testID={testID}>
|
|
69
|
+
{typeof children === 'string' ? (
|
|
70
|
+
<Text style={s.content}>{children}</Text>
|
|
71
|
+
) : (
|
|
72
|
+
children
|
|
73
|
+
)}
|
|
74
|
+
</View>
|
|
75
|
+
);
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
export default Tag;
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import type { ViewStyle, TextStyle } from 'react-native';
|
|
2
|
+
import type { Tokens } from '../../theme/tokens';
|
|
3
|
+
|
|
4
|
+
export type TagSemanticStyles = {
|
|
5
|
+
root?: ViewStyle;
|
|
6
|
+
content?: TextStyle;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
/** 预设语义色 → 实际色值映射 */
|
|
10
|
+
const PRESET_COLORS = {
|
|
11
|
+
success: '#52C41A',
|
|
12
|
+
processing: '#1677FF',
|
|
13
|
+
warning: '#FF9500',
|
|
14
|
+
error: '#FF3B30',
|
|
15
|
+
default: '#8C8C8C',
|
|
16
|
+
} as const;
|
|
17
|
+
|
|
18
|
+
type PresetName = keyof typeof PRESET_COLORS;
|
|
19
|
+
|
|
20
|
+
/** 解析颜色:支持预设名或自定义 hex */
|
|
21
|
+
export function resolveColor(color: string | undefined): string {
|
|
22
|
+
if (!color) return PRESET_COLORS.default;
|
|
23
|
+
if (color in PRESET_COLORS) return PRESET_COLORS[color as PresetName];
|
|
24
|
+
return color;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* 十六进制颜色追加透明度
|
|
29
|
+
* '#1677FF' + 0.1 → '#1677FF1A'
|
|
30
|
+
*/
|
|
31
|
+
function withAlpha(hex: string, alpha: number): string {
|
|
32
|
+
const a = Math.round(alpha * 255)
|
|
33
|
+
.toString(16)
|
|
34
|
+
.padStart(2, '0');
|
|
35
|
+
const base = hex.length === 9 ? hex.slice(0, 7) : hex;
|
|
36
|
+
return `${base}${a}`;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export const createDefaultStyles = (t: Tokens): TagSemanticStyles => ({
|
|
40
|
+
root: {
|
|
41
|
+
flexDirection: 'row',
|
|
42
|
+
alignItems: 'center',
|
|
43
|
+
alignSelf: 'flex-start',
|
|
44
|
+
borderRadius: t.radiusSm,
|
|
45
|
+
paddingHorizontal: 8,
|
|
46
|
+
paddingVertical: 2,
|
|
47
|
+
},
|
|
48
|
+
content: {
|
|
49
|
+
fontSize: t.fontSizeXs,
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
export const createSmallStyles = (): Partial<TagSemanticStyles> => ({
|
|
54
|
+
root: {
|
|
55
|
+
paddingHorizontal: 6,
|
|
56
|
+
paddingVertical: 1,
|
|
57
|
+
},
|
|
58
|
+
content: {
|
|
59
|
+
fontSize: 10,
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
/** filled: 浅色底 + 深色字(默认) */
|
|
64
|
+
export const createFilledStyles = (
|
|
65
|
+
color: string
|
|
66
|
+
): Partial<TagSemanticStyles> => ({
|
|
67
|
+
root: {
|
|
68
|
+
backgroundColor: withAlpha(color, 0.1),
|
|
69
|
+
},
|
|
70
|
+
content: {
|
|
71
|
+
color,
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
/** solid: 纯色底 + 白字 */
|
|
76
|
+
export const createSolidStyles = (
|
|
77
|
+
color: string
|
|
78
|
+
): Partial<TagSemanticStyles> => ({
|
|
79
|
+
root: {
|
|
80
|
+
backgroundColor: color,
|
|
81
|
+
},
|
|
82
|
+
content: {
|
|
83
|
+
color: '#FFFFFF',
|
|
84
|
+
},
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
/** outlined: 边框 + 深色字 + 透明底 */
|
|
88
|
+
export const createOutlinedStyles = (
|
|
89
|
+
color: string
|
|
90
|
+
): Partial<TagSemanticStyles> => ({
|
|
91
|
+
root: {
|
|
92
|
+
backgroundColor: 'transparent',
|
|
93
|
+
borderWidth: 1,
|
|
94
|
+
borderColor: color,
|
|
95
|
+
},
|
|
96
|
+
content: {
|
|
97
|
+
color,
|
|
98
|
+
},
|
|
99
|
+
});
|