@tcbs/react-native-mazic-ui 0.1.1 → 0.1.3
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/lib/components/ExampleScreen.d.ts +3 -0
- package/lib/components/ExampleScreen.js +10 -0
- package/lib/components/TcbsButton.js +53 -18
- package/lib/components/TcbsButton.types.d.ts +5 -0
- package/lib/components/TcbsButton.types.js +2 -0
- package/lib/components/ThemeModal.d.ts +7 -0
- package/lib/components/ThemeModal.js +63 -0
- package/lib/components/error/AppErrorBoundary.d.ts +27 -0
- package/lib/components/error/AppErrorBoundary.js +117 -0
- package/lib/index.d.ts +3 -1
- package/lib/index.js +3 -1
- package/lib/store/themeStore.d.ts +52 -0
- package/lib/store/themeStore.js +258 -0
- package/package.json +6 -4
- package/src/components/TcbsButton.tsx +36 -15
- package/src/components/TcbsButton.types.ts +3 -0
- package/src/components/ThemeModal.tsx +124 -0
- package/src/components/error/AppErrorBoundary.d.ts +20 -0
- package/src/components/error/AppErrorBoundary.tsx +179 -0
- package/src/components/error/setupGlobalExceptionHandlers.js +41 -0
- package/src/index.ts +3 -1
- package/src/store/themeStore.ts +301 -34
- package/src/components/Button.tsx +0 -26
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { View, Text } from 'react-native';
|
|
3
|
+
import { useTcbsColorStore } from '../store/themeStore';
|
|
4
|
+
const ExampleScreen = () => {
|
|
5
|
+
const { colors, mode } = useTcbsColorStore();
|
|
6
|
+
const screenBgColor = colors[mode].screenBgColor;
|
|
7
|
+
return (React.createElement(View, { style: { flex: 1, backgroundColor: screenBgColor } },
|
|
8
|
+
React.createElement(Text, { style: { color: colors[mode].btnTextColor } }, "This screen uses theme screenBgColor!")));
|
|
9
|
+
};
|
|
10
|
+
export default ExampleScreen;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React, { useMemo } from 'react';
|
|
2
|
+
import { Appearance } from 'react-native';
|
|
2
3
|
import { TouchableOpacity, Text, View } from 'react-native';
|
|
3
4
|
import AntDesign from 'react-native-vector-icons/AntDesign';
|
|
4
5
|
import Feather from 'react-native-vector-icons/Feather';
|
|
@@ -9,6 +10,7 @@ import MaterialDesignIcons from 'react-native-vector-icons/MaterialCommunityIcon
|
|
|
9
10
|
import Octicons from 'react-native-vector-icons/Octicons';
|
|
10
11
|
// import Lucide from 'react-native-vector-icons/Lucide';
|
|
11
12
|
import { BUTTON_SIZE, BUTTON_VARIANT, BORDER_RADIUS, } from './TcbsButton.types';
|
|
13
|
+
import { useTcbsColorStore } from '../store/themeStore';
|
|
12
14
|
const HEIGHTS = {
|
|
13
15
|
[BUTTON_SIZE.LARGE]: 56,
|
|
14
16
|
[BUTTON_SIZE.MEDIUM]: 40,
|
|
@@ -19,6 +21,7 @@ const FONT_SIZES = {
|
|
|
19
21
|
[BUTTON_SIZE.MEDIUM]: 16,
|
|
20
22
|
[BUTTON_SIZE.SMALL]: 14,
|
|
21
23
|
};
|
|
24
|
+
// Support for BORDER_RADIUS.NONE and BORDER_RADIUS.FULL (50%)
|
|
22
25
|
const BORDER_RADIUSES = {
|
|
23
26
|
[BUTTON_SIZE.LARGE]: BORDER_RADIUS.MEDIUM,
|
|
24
27
|
[BUTTON_SIZE.MEDIUM]: BORDER_RADIUS.SMALL,
|
|
@@ -39,37 +42,70 @@ const BORDER_RADIUSES = {
|
|
|
39
42
|
* />
|
|
40
43
|
* ```
|
|
41
44
|
*/
|
|
42
|
-
export const TcbsButton = ({ title, onPress, size = BUTTON_SIZE.LARGE, variant = BUTTON_VARIANT.PRIMARY, borderRadius, disabled = false, style, textStyle, iconName, iconGroup = 'MaterialDesignIcons', iconColor, iconSize, iconPosition = 'top', accessibilityLabel, accessibilityHint, accessibilityRole = 'button', accessibilityState,
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
const
|
|
45
|
+
export const TcbsButton = ({ title, onPress, size = BUTTON_SIZE.LARGE, variant = BUTTON_VARIANT.PRIMARY, borderRadius, disabled = false, style, textStyle, iconName, iconGroup = 'MaterialDesignIcons', iconColor, iconSize, iconPosition = 'top', accessibilityLabel, accessibilityHint, accessibilityRole = 'button', accessibilityState, }) => {
|
|
46
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
47
|
+
// Use themeColors from store if not provided as prop
|
|
48
|
+
const { themeColors, tcbsTheme } = useTcbsColorStore();
|
|
49
|
+
const effectiveThemeColor = themeColors;
|
|
50
|
+
// Normalize colors: if only one color is set, use it for all
|
|
51
|
+
const normalizedColors = {
|
|
52
|
+
btnColor: (_b = (_a = effectiveThemeColor === null || effectiveThemeColor === void 0 ? void 0 : effectiveThemeColor.btnColor) !== null && _a !== void 0 ? _a : effectiveThemeColor === null || effectiveThemeColor === void 0 ? void 0 : effectiveThemeColor.themeColor) !== null && _b !== void 0 ? _b : '#007AFF',
|
|
53
|
+
btnBorderColor: (_d = (_c = effectiveThemeColor === null || effectiveThemeColor === void 0 ? void 0 : effectiveThemeColor.btnBorderColor) !== null && _c !== void 0 ? _c : effectiveThemeColor === null || effectiveThemeColor === void 0 ? void 0 : effectiveThemeColor.btnColor) !== null && _d !== void 0 ? _d : '#007AFF',
|
|
54
|
+
btnIconColor: effectiveThemeColor === null || effectiveThemeColor === void 0 ? void 0 : effectiveThemeColor.btnIconColor,
|
|
55
|
+
btnTextColor: (_e = effectiveThemeColor === null || effectiveThemeColor === void 0 ? void 0 : effectiveThemeColor.btnTextColor) !== null && _e !== void 0 ? _e : effectiveThemeColor === null || effectiveThemeColor === void 0 ? void 0 : effectiveThemeColor.btnTxtColor,
|
|
56
|
+
themeColor: (_g = (_f = effectiveThemeColor === null || effectiveThemeColor === void 0 ? void 0 : effectiveThemeColor.themeColor) !== null && _f !== void 0 ? _f : effectiveThemeColor === null || effectiveThemeColor === void 0 ? void 0 : effectiveThemeColor.btnColor) !== null && _g !== void 0 ? _g : '#007AFF',
|
|
57
|
+
};
|
|
49
58
|
const buttonStyle = useMemo(() => {
|
|
59
|
+
const height = HEIGHTS[size];
|
|
60
|
+
let computedBorderRadius;
|
|
61
|
+
if (borderRadius === BORDER_RADIUS.NONE) {
|
|
62
|
+
computedBorderRadius = 0;
|
|
63
|
+
}
|
|
64
|
+
else if (borderRadius === BORDER_RADIUS.FULL) {
|
|
65
|
+
computedBorderRadius = height / 2;
|
|
66
|
+
}
|
|
67
|
+
else if (borderRadius !== undefined) {
|
|
68
|
+
computedBorderRadius = borderRadius;
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
computedBorderRadius = BORDER_RADIUSES[size];
|
|
72
|
+
}
|
|
50
73
|
const baseStyle = {
|
|
51
|
-
height
|
|
52
|
-
borderRadius:
|
|
74
|
+
height,
|
|
75
|
+
borderRadius: computedBorderRadius,
|
|
53
76
|
alignItems: 'center',
|
|
54
77
|
justifyContent: 'center',
|
|
55
78
|
opacity: disabled ? 0.6 : 1,
|
|
56
79
|
paddingHorizontal: 24,
|
|
57
80
|
};
|
|
58
81
|
if (variant === BUTTON_VARIANT.SECONDARY) {
|
|
59
|
-
return Object.assign(Object.assign(Object.assign({}, baseStyle), { backgroundColor: '#fff', borderWidth: 2, borderColor:
|
|
82
|
+
return Object.assign(Object.assign(Object.assign({}, baseStyle), { backgroundColor: '#fff', borderWidth: 2, borderColor: normalizedColors.btnBorderColor }), style);
|
|
60
83
|
}
|
|
61
84
|
if (variant === BUTTON_VARIANT.NO_BORDER) {
|
|
62
|
-
return Object.assign(Object.assign(Object.assign({}, baseStyle), { backgroundColor: '
|
|
85
|
+
return Object.assign(Object.assign(Object.assign({}, baseStyle), { backgroundColor: 'transparent' }), style);
|
|
63
86
|
}
|
|
64
87
|
// Primary variant (default)
|
|
65
|
-
return Object.assign(Object.assign(Object.assign({}, baseStyle), { backgroundColor:
|
|
66
|
-
}, [size, variant,
|
|
88
|
+
return Object.assign(Object.assign(Object.assign({}, baseStyle), { backgroundColor: normalizedColors.btnColor, shadowColor: normalizedColors.btnColor, shadowOpacity: 0.15, shadowRadius: 6, shadowOffset: { width: 0, height: 2 }, elevation: 2 }), style);
|
|
89
|
+
}, [size, variant, normalizedColors, style, disabled, borderRadius]);
|
|
67
90
|
const themedTextStyle = useMemo(() => {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
91
|
+
let baseTextColor;
|
|
92
|
+
if (variant === BUTTON_VARIANT.PRIMARY) {
|
|
93
|
+
baseTextColor = normalizedColors.btnTextColor || '#FFFFFF';
|
|
94
|
+
}
|
|
95
|
+
else if (variant === BUTTON_VARIANT.NO_BORDER) {
|
|
96
|
+
let colorScheme = tcbsTheme;
|
|
97
|
+
if (tcbsTheme === 'system') {
|
|
98
|
+
colorScheme = Appearance.getColorScheme() || 'light';
|
|
99
|
+
}
|
|
100
|
+
baseTextColor = colorScheme === 'dark'
|
|
101
|
+
? normalizedColors.btnTextColor || '#FFFFFF'
|
|
102
|
+
: (normalizedColors === null || normalizedColors === void 0 ? void 0 : normalizedColors.btnColor) || '#007AFF';
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
baseTextColor = (normalizedColors === null || normalizedColors === void 0 ? void 0 : normalizedColors.btnColor) || '#FFFFFF';
|
|
106
|
+
}
|
|
71
107
|
return Object.assign({ color: baseTextColor, fontSize: FONT_SIZES[size], fontWeight: '700' }, textStyle);
|
|
72
|
-
}, [size, variant,
|
|
108
|
+
}, [size, variant, normalizedColors, textStyle, tcbsTheme]);
|
|
73
109
|
const renderIcon = (IconComponent) => (React.createElement(IconComponent, { name: iconName, size: iconSize || FONT_SIZES[size] * 2, color: iconColor || themedTextStyle.color, style: iconPosition === 'top'
|
|
74
110
|
? { marginBottom: 2 }
|
|
75
111
|
: iconPosition === 'left'
|
|
@@ -113,5 +149,4 @@ export const TcbsButton = ({ title, onPress, size = BUTTON_SIZE.LARGE, variant =
|
|
|
113
149
|
};
|
|
114
150
|
return (React.createElement(TouchableOpacity, { onPress: onPress, disabled: disabled, style: buttonStyle, accessibilityLabel: accessibilityLabel || title, accessibilityHint: accessibilityHint, accessibilityRole: accessibilityRole, accessibilityState: accessibilityState || { disabled } }, renderContent()));
|
|
115
151
|
};
|
|
116
|
-
// Export constants for use in consuming applications
|
|
117
152
|
export { BUTTON_SIZE, BUTTON_VARIANT, BORDER_RADIUS };
|
|
@@ -20,6 +20,8 @@ export declare const BORDER_RADIUS: {
|
|
|
20
20
|
readonly SMALL: 8;
|
|
21
21
|
readonly MEDIUM: 12;
|
|
22
22
|
readonly LARGE: 16;
|
|
23
|
+
readonly NONE: 0;
|
|
24
|
+
readonly FULL: "50%";
|
|
23
25
|
};
|
|
24
26
|
export type ButtonSize = (typeof BUTTON_SIZE)[keyof typeof BUTTON_SIZE];
|
|
25
27
|
export type ButtonVariant = (typeof BUTTON_VARIANT)[keyof typeof BUTTON_VARIANT];
|
|
@@ -45,8 +47,11 @@ export interface TcbsButtonProps {
|
|
|
45
47
|
accessibilityState?: AccessibilityState;
|
|
46
48
|
themeColor?: {
|
|
47
49
|
btnColor?: string;
|
|
50
|
+
btnBorderColor?: string;
|
|
51
|
+
btnIconColor?: string;
|
|
48
52
|
themeColor?: string;
|
|
49
53
|
btnTextColor?: string;
|
|
50
54
|
btnTxtColor?: string;
|
|
51
55
|
};
|
|
56
|
+
screenBgColor?: string;
|
|
52
57
|
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Modal, Pressable, View, Text, StyleSheet } from 'react-native';
|
|
3
|
+
import { useTcbsColorStore } from '../store/themeStore';
|
|
4
|
+
import { BUTTON_VARIANT, TcbsButton } from './TcbsButton';
|
|
5
|
+
export const ThemeModal = ({ visible, onClose }) => {
|
|
6
|
+
const { tcbsTheme, setTcbsTheme, themeColors } = useTcbsColorStore();
|
|
7
|
+
// You can customize these colors or get them from your theme
|
|
8
|
+
const colors = {
|
|
9
|
+
menuCardBkgColor: themeColors.screenBgColor || '#fff',
|
|
10
|
+
textDark: themeColors.modalTitleColor || '#222',
|
|
11
|
+
textGray: '#888',
|
|
12
|
+
};
|
|
13
|
+
return (React.createElement(Modal, { transparent: true, animationType: "fade", visible: visible, onRequestClose: onClose },
|
|
14
|
+
React.createElement(Pressable, { style: styles.modalOverlay, onPress: onClose },
|
|
15
|
+
React.createElement(Pressable, { style: [styles.modalCard, { backgroundColor: themeColors.modalBgColor || "#00000080" }], onPress: () => { } },
|
|
16
|
+
React.createElement(View, { style: styles.modalClose },
|
|
17
|
+
React.createElement(TcbsButton, { onPress: onClose, iconName: "close", iconColor: colors.textDark, iconPosition: "left", variant: BUTTON_VARIANT.NO_BORDER, iconSize: 22, accessibilityLabel: "Close", style: { padding: 8, marginRight: 0, minWidth: 0, minHeight: 0, alignSelf: 'flex-end' } })),
|
|
18
|
+
React.createElement(Text, { style: [styles.modalTitle, { color: colors.textDark }] }, "Theme"),
|
|
19
|
+
React.createElement(Text, { style: [styles.modalSubtitle, { color: colors.textDark }] }, "Choose how the app looks on this device."),
|
|
20
|
+
React.createElement(View, { style: { marginTop: 18 } },
|
|
21
|
+
React.createElement(TcbsButton, { title: "Light", onPress: () => setTcbsTheme('light'), style: { marginBottom: 8 }, variant: tcbsTheme === 'light' ? 'primary' : 'secondary', iconGroup: "Ionicons", iconName: "sunny", iconPosition: "left", textStyle: { flex: 1, textAlign: 'center' } }),
|
|
22
|
+
React.createElement(TcbsButton, { title: "Dark", onPress: () => setTcbsTheme('dark'), style: { marginBottom: 8 }, variant: tcbsTheme === 'dark' ? 'primary' : 'secondary', iconGroup: "Ionicons", iconName: "moon", iconPosition: "left", textStyle: { flex: 1, textAlign: 'center' } }),
|
|
23
|
+
React.createElement(TcbsButton, { title: "System (default)", onPress: () => setTcbsTheme('system'), variant: tcbsTheme === 'system' ? 'primary' : 'secondary', iconGroup: "Ionicons", iconName: "settings", iconPosition: "left", textStyle: { flex: 1, textAlign: 'center' } }))))));
|
|
24
|
+
};
|
|
25
|
+
const styles = StyleSheet.create({
|
|
26
|
+
modalOverlay: {
|
|
27
|
+
flex: 1,
|
|
28
|
+
backgroundColor: 'rgba(0,0,0,0.3)',
|
|
29
|
+
justifyContent: 'center',
|
|
30
|
+
alignItems: 'center',
|
|
31
|
+
},
|
|
32
|
+
modalCard: {
|
|
33
|
+
minWidth: 300,
|
|
34
|
+
borderRadius: 16,
|
|
35
|
+
padding: 24,
|
|
36
|
+
alignItems: 'stretch',
|
|
37
|
+
// shadowColor: '#000',
|
|
38
|
+
// shadowOpacity: 0.15,
|
|
39
|
+
shadowRadius: 12,
|
|
40
|
+
// shadowOffset: { width: 0, height: 4 },
|
|
41
|
+
// elevation: 4,
|
|
42
|
+
},
|
|
43
|
+
modalClose: {
|
|
44
|
+
position: 'absolute',
|
|
45
|
+
top: 8,
|
|
46
|
+
right: 8,
|
|
47
|
+
zIndex: 2,
|
|
48
|
+
},
|
|
49
|
+
modalTitle: {
|
|
50
|
+
fontSize: 20,
|
|
51
|
+
fontWeight: '700',
|
|
52
|
+
marginTop: 8,
|
|
53
|
+
marginBottom: 2,
|
|
54
|
+
textAlign: 'center',
|
|
55
|
+
},
|
|
56
|
+
modalSubtitle: {
|
|
57
|
+
fontSize: 14,
|
|
58
|
+
fontWeight: '400',
|
|
59
|
+
marginBottom: 8,
|
|
60
|
+
textAlign: 'center',
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
export default ThemeModal;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export interface AppErrorBoundaryProps {
|
|
3
|
+
children?: React.ReactNode;
|
|
4
|
+
}
|
|
5
|
+
export interface AppErrorBoundaryState {
|
|
6
|
+
hasError: boolean;
|
|
7
|
+
error: any;
|
|
8
|
+
reactError: {
|
|
9
|
+
name?: string;
|
|
10
|
+
message?: string;
|
|
11
|
+
stack?: string;
|
|
12
|
+
} | null;
|
|
13
|
+
errorInfo: {
|
|
14
|
+
componentStack?: string;
|
|
15
|
+
} | null;
|
|
16
|
+
}
|
|
17
|
+
export declare class AppErrorBoundary extends React.Component<AppErrorBoundaryProps, AppErrorBoundaryState> {
|
|
18
|
+
state: AppErrorBoundaryState;
|
|
19
|
+
static getDerivedStateFromError(error: any): {
|
|
20
|
+
hasError: boolean;
|
|
21
|
+
error: any;
|
|
22
|
+
};
|
|
23
|
+
componentDidCatch(error: any, errorInfo: any): void;
|
|
24
|
+
renderDevError(): React.JSX.Element | null;
|
|
25
|
+
renderProdError(): React.JSX.Element;
|
|
26
|
+
render(): React.ReactNode;
|
|
27
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { View, Text, StyleSheet, ScrollView, } from 'react-native';
|
|
3
|
+
import { SafeAreaView } from 'react-native-safe-area-context';
|
|
4
|
+
import { setupGlobalExceptionHandlers } from './setupGlobalExceptionHandlers';
|
|
5
|
+
setupGlobalExceptionHandlers();
|
|
6
|
+
export class AppErrorBoundary extends React.Component {
|
|
7
|
+
constructor() {
|
|
8
|
+
super(...arguments);
|
|
9
|
+
this.state = {
|
|
10
|
+
hasError: false,
|
|
11
|
+
error: null,
|
|
12
|
+
reactError: null,
|
|
13
|
+
errorInfo: null,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
static getDerivedStateFromError(error) {
|
|
17
|
+
return { hasError: true, error };
|
|
18
|
+
}
|
|
19
|
+
componentDidCatch(error, errorInfo) {
|
|
20
|
+
// Log exactly what React gives
|
|
21
|
+
console.log('React Render Error:', error);
|
|
22
|
+
// Store everything needed for UI
|
|
23
|
+
this.setState({
|
|
24
|
+
error,
|
|
25
|
+
reactError: {
|
|
26
|
+
name: error === null || error === void 0 ? void 0 : error.name,
|
|
27
|
+
message: error === null || error === void 0 ? void 0 : error.message,
|
|
28
|
+
stack: error === null || error === void 0 ? void 0 : error.stack,
|
|
29
|
+
},
|
|
30
|
+
errorInfo,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
renderDevError() {
|
|
34
|
+
const { error, reactError, errorInfo } = this.state;
|
|
35
|
+
if (!error)
|
|
36
|
+
return null;
|
|
37
|
+
return (React.createElement(SafeAreaView, { style: { flex: 1 } },
|
|
38
|
+
React.createElement(ScrollView, { style: styles.container },
|
|
39
|
+
React.createElement(Text, { style: styles.title }, "\uD83D\uDEA8 Application Error (DEV)"),
|
|
40
|
+
React.createElement(Section, { title: "\u274C What happened" },
|
|
41
|
+
React.createElement(Text, { style: styles.errorText },
|
|
42
|
+
error.name,
|
|
43
|
+
": ",
|
|
44
|
+
error.message)),
|
|
45
|
+
React.createElement(Section, { title: "\u269B\uFE0F React render error" },
|
|
46
|
+
React.createElement(Text, { style: styles.mono }, reactError === null || reactError === void 0 ? void 0 : reactError.stack)),
|
|
47
|
+
React.createElement(Section, { title: "\uD83D\uDCDC Component stack (Advanced)" },
|
|
48
|
+
React.createElement(Text, { style: styles.stack }, errorInfo === null || errorInfo === void 0 ? void 0 : errorInfo.componentStack)))));
|
|
49
|
+
}
|
|
50
|
+
renderProdError() {
|
|
51
|
+
return (React.createElement(View, { style: styles.prodContainer },
|
|
52
|
+
React.createElement(Text, { style: styles.prodTitle }, "Something went wrong"),
|
|
53
|
+
React.createElement(Text, { style: styles.prodSubtitle }, "Please restart the application.")));
|
|
54
|
+
}
|
|
55
|
+
render() {
|
|
56
|
+
if (this.state.hasError) {
|
|
57
|
+
return __DEV__ ? this.renderDevError() : this.renderProdError();
|
|
58
|
+
}
|
|
59
|
+
return this.props.children;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
const Section = ({ title, children }) => (React.createElement(View, { style: styles.section },
|
|
63
|
+
React.createElement(Text, { style: styles.sectionTitle }, title),
|
|
64
|
+
children));
|
|
65
|
+
/* ---------- Styles ---------- */
|
|
66
|
+
const styles = StyleSheet.create({
|
|
67
|
+
container: {
|
|
68
|
+
flex: 1,
|
|
69
|
+
backgroundColor: '#0f172a',
|
|
70
|
+
padding: 16,
|
|
71
|
+
},
|
|
72
|
+
title: {
|
|
73
|
+
fontSize: 18,
|
|
74
|
+
fontWeight: '700',
|
|
75
|
+
color: '#f87171',
|
|
76
|
+
marginBottom: 12,
|
|
77
|
+
},
|
|
78
|
+
section: {
|
|
79
|
+
marginBottom: 16,
|
|
80
|
+
},
|
|
81
|
+
sectionTitle: {
|
|
82
|
+
fontSize: 14,
|
|
83
|
+
fontWeight: '600',
|
|
84
|
+
color: '#38bdf8',
|
|
85
|
+
marginBottom: 6,
|
|
86
|
+
},
|
|
87
|
+
errorText: {
|
|
88
|
+
color: '#fecaca',
|
|
89
|
+
fontSize: 14,
|
|
90
|
+
},
|
|
91
|
+
mono: {
|
|
92
|
+
fontSize: 12,
|
|
93
|
+
color: '#e5e7eb',
|
|
94
|
+
lineHeight: 16,
|
|
95
|
+
},
|
|
96
|
+
stack: {
|
|
97
|
+
fontSize: 11,
|
|
98
|
+
color: '#94a3b8',
|
|
99
|
+
lineHeight: 16,
|
|
100
|
+
},
|
|
101
|
+
prodContainer: {
|
|
102
|
+
flex: 1,
|
|
103
|
+
alignItems: 'center',
|
|
104
|
+
justifyContent: 'center',
|
|
105
|
+
padding: 24,
|
|
106
|
+
},
|
|
107
|
+
prodTitle: {
|
|
108
|
+
fontSize: 18,
|
|
109
|
+
fontWeight: '600',
|
|
110
|
+
marginBottom: 8,
|
|
111
|
+
},
|
|
112
|
+
prodSubtitle: {
|
|
113
|
+
fontSize: 14,
|
|
114
|
+
color: '#666',
|
|
115
|
+
textAlign: 'center',
|
|
116
|
+
},
|
|
117
|
+
});
|
package/lib/index.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
-
export { Button } from './components/Button';
|
|
2
1
|
export { TcbsButton } from './components/TcbsButton';
|
|
3
2
|
export { BUTTON_SIZE, BUTTON_VARIANT, BORDER_RADIUS, ButtonSize, ButtonVariant, IconGroupType, IconPosition, TcbsButtonProps, IconComponentType, } from './components/TcbsButton.types';
|
|
3
|
+
export { useTcbsColorStore } from './store/themeStore';
|
|
4
|
+
export { ThemeModal } from './components/ThemeModal';
|
|
5
|
+
export { AppErrorBoundary } from './components/error/AppErrorBoundary';
|
package/lib/index.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
-
export { Button } from './components/Button';
|
|
2
1
|
export { TcbsButton } from './components/TcbsButton';
|
|
3
2
|
export { BUTTON_SIZE, BUTTON_VARIANT, BORDER_RADIUS, } from './components/TcbsButton.types';
|
|
3
|
+
export { useTcbsColorStore } from './store/themeStore';
|
|
4
|
+
export { ThemeModal } from './components/ThemeModal';
|
|
5
|
+
export { AppErrorBoundary } from './components/error/AppErrorBoundary';
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
export type ThemeColor = {
|
|
2
|
+
btnColor: string;
|
|
3
|
+
btnBorderColor?: string;
|
|
4
|
+
btnIconColor?: string;
|
|
5
|
+
themeColor: string;
|
|
6
|
+
btnTextColor: string;
|
|
7
|
+
tabBarIconActiveColor?: string;
|
|
8
|
+
tabBarIconInactiveColor?: string;
|
|
9
|
+
modalBgColor?: string;
|
|
10
|
+
primaryColor?: string;
|
|
11
|
+
secondaryColor?: string;
|
|
12
|
+
tertiaryColor?: string;
|
|
13
|
+
screenBgColor?: string;
|
|
14
|
+
modalHeaderBgColor?: string;
|
|
15
|
+
modalCardBgColor?: string;
|
|
16
|
+
modalTitleColor?: string;
|
|
17
|
+
textPrimary?: string;
|
|
18
|
+
textSecondary?: string;
|
|
19
|
+
borderColor?: string;
|
|
20
|
+
dividerColor?: string;
|
|
21
|
+
inputBgColor?: string;
|
|
22
|
+
inputBorderColor?: string;
|
|
23
|
+
cardBgColor?: string;
|
|
24
|
+
cardBorderColor?: string;
|
|
25
|
+
accentColor?: string;
|
|
26
|
+
errorColor?: string;
|
|
27
|
+
successColor?: string;
|
|
28
|
+
warningColor?: string;
|
|
29
|
+
};
|
|
30
|
+
export type ThemeMode = 'light' | 'dark' | 'system';
|
|
31
|
+
export type ThemeColors = {
|
|
32
|
+
light: ThemeColor;
|
|
33
|
+
dark: ThemeColor;
|
|
34
|
+
};
|
|
35
|
+
export interface ThemeStore {
|
|
36
|
+
colors: ThemeColors;
|
|
37
|
+
tcbsTheme: ThemeMode;
|
|
38
|
+
themeColors: ThemeColor;
|
|
39
|
+
/**
|
|
40
|
+
* Returns the current theme as 'light' or 'dark' (never 'system').
|
|
41
|
+
* If tcbsTheme is 'system', resolves to the current system color scheme.
|
|
42
|
+
*/
|
|
43
|
+
currentThemeMode: 'light' | 'dark';
|
|
44
|
+
setTcbsColor: (colors: Partial<ThemeColor> & {
|
|
45
|
+
light?: Partial<ThemeColor>;
|
|
46
|
+
dark?: Partial<ThemeColor>;
|
|
47
|
+
}) => void;
|
|
48
|
+
setTcbsTheme: (mode: ThemeMode) => void;
|
|
49
|
+
toggleTcbsTheme: () => void;
|
|
50
|
+
setMazicColor: (baseColor: string) => void;
|
|
51
|
+
}
|
|
52
|
+
export declare const useTcbsColorStore: any;
|