diff --git a/.storybook/decorators.tsx b/.storybook/decorators.tsx index 703dfe6..c354e01 100644 --- a/.storybook/decorators.tsx +++ b/.storybook/decorators.tsx @@ -4,18 +4,20 @@ import {ThemeProvider} from '../src/providers/ThemeProvider'; import {dark, light} from '../src/utils/colors'; import styled from '@emotion/native'; import {CpkProvider} from '../src/providers'; +import {ThemeParam} from '../src/utils/theme'; -export const withThemeProvider = (Story: React.FC, context: any) => { +export const withThemeProvider = ( + Story: React.FC, + context: any, + customTheme?: ThemeParam, +) => { const isDarkMode = context.globals.theme === 'dark'; return ( diff --git a/src/components/uis/Button/Button.stories.tsx b/src/components/uis/Button/Button.stories.tsx index 80e7b7e..052fff7 100644 --- a/src/components/uis/Button/Button.stories.tsx +++ b/src/components/uis/Button/Button.stories.tsx @@ -5,6 +5,7 @@ import {withThemeProvider} from '../../../../.storybook/decorators'; import type {ButtonColorType, ButtonSizeType, ButtonType} from './Button'; import {Button} from './Button'; +import {ThemeParam} from '../../../utils/theme'; const buttonTypes: ButtonType[] = ['outlined', 'solid', 'text']; const buttonSizes: ButtonSizeType[] = ['large', 'medium', 'small']; @@ -43,7 +44,15 @@ const meta = { options: buttonSizes, }, }, - decorators: [withThemeProvider], + decorators: [ + (Story, context) => + withThemeProvider( + Story, + context, + // @ts-ignore + context.args.theme, + ), + ], } satisfies Meta; export default meta; @@ -79,3 +88,54 @@ export const Danger: Story = { onPress: action('onPress'), }, }; + +const disableAllExcept = (allowedField: string) => { + const argTypes = { + text: {table: {disable: true}}, + type: {table: {disable: true}}, + color: {table: {disable: true}}, + size: {table: {disable: true}}, + onPress: {table: {disable: true}}, + testID: {table: {disable: true}}, + disabled: {table: {disable: true}}, + loadingElement: {table: {disable: true}}, + borderRadius: {table: {disable: true}}, + startElement: {table: {disable: true}}, + endElement: {table: {disable: true}}, + activeOpacity: {table: {disable: true}}, + touchableHighlightProps: {table: {disable: true}}, + hitSlop: {table: {disable: true}}, + theme: {control: 'object'}, + }; + + if (argTypes[allowedField]) { + argTypes[allowedField] = {table: {disable: false}}; + } + + return argTypes; +}; + +export const CustomColor: Story = { + args: { + // @ts-ignore + theme: { + light: { + button: { + primary: { + bg: 'red', + text: 'white', + }, + }, + }, + dark: { + button: { + primary: { + bg: 'pink', + text: 'red', + }, + }, + }, + } as ThemeParam, + }, + argTypes: disableAllExcept('theme'), +}; diff --git a/src/components/uis/Button/Button.tsx b/src/components/uis/Button/Button.tsx index 2c1fef0..6a988b8 100644 --- a/src/components/uis/Button/Button.tsx +++ b/src/components/uis/Button/Button.tsx @@ -236,9 +236,11 @@ export function Button({ const LoadingView = loadingElement ?? ( @@ -285,13 +287,11 @@ export function Button({ ], ); - function resolveStyle( - style: StyleProp - ): T | undefined { + function resolveStyle(style: StyleProp): T | undefined { if (Array.isArray(style)) { return style.find((s): s is T => !!s); } - return style as T || undefined; + return (style as T) || undefined; } const viewStyle = resolveStyle(compositeStyles.container); diff --git a/src/components/uis/Typography/Typography.stories.tsx b/src/components/uis/Typography/Typography.stories.tsx new file mode 100644 index 0000000..e31151d --- /dev/null +++ b/src/components/uis/Typography/Typography.stories.tsx @@ -0,0 +1,58 @@ +import type {Meta, StoryObj} from '@storybook/react'; +import {Typography} from './Typography'; +import {withThemeProvider} from '../../../../.storybook/decorators'; +import {ScrollView, View} from 'react-native'; +import {ThemeParam} from '../../../utils/theme'; + +const meta = { + title: 'Typography', + component: Typography.Title, + decorators: [ + (Story, context) => + withThemeProvider( + Story, + context, + (context.args.theme as any) || undefined, + ), + ], +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +export const AllTypography: Story = { + render: (args) => ( + + {Object.entries(Typography).map(([key, Component]) => ( + + + {key} {args.children} + + + ))} + + ), + args: { + children: 'Hello world', + }, +}; + +export const CustomTitle: Story = { + args: { + children: 'Custom Color', + // @ts-ignore + theme: { + light: { + text: { + basic: 'blue', + }, + }, + dark: { + text: { + basic: 'skyblue', + }, + }, + } as ThemeParam, + }, +}; diff --git a/src/utils/colors.ts b/src/utils/colors.ts index 779a3c8..5a4390b 100644 --- a/src/utils/colors.ts +++ b/src/utils/colors.ts @@ -1,127 +1,151 @@ -export const light = { - bg: { - basic: "#FFFFFF", - paper: "#EDEDED", - disabled: "#BEBEBE", +const baseColors = { + success: '#1CD66C', + warning: '#E2B101', + danger: '#F84444', + info: '#307EF1', + accent: '#6BF3C5', + link: '#A351F4', +}; + +const buttonColors = { + light: { + primary: {bg: '#1B1B1B', text: '#FFFFFF'}, + secondary: {bg: '#3D8BFF', text: '#FFFFFF'}, + success: {bg: '#1CD66C', text: '#FFFFFF'}, + danger: {bg: '#F84444', text: '#FFFFFF'}, + warning: {bg: '#E2B101', text: '#FFFFFF'}, + info: {bg: '#307EF1', text: '#FFFFFF'}, + light: {bg: '#E8E8E8', text: '#232323'}, + disabled: {bg: '#EDEDED', text: '#BEBEBE'}, }, - role: { - primary: "#1B1B1B", - secondary: "#3D8BFF", - accent: "#6BF3C5", - info: "#307EF1", - link: "#A351F4", - success: "#1CD66C", - warning: "#E2B101", - danger: "#F84444", - border: "#CCCCCC", - underlay: "rgba(0, 0, 0, 0.16)", - underlayContrast: "rgba(0, 0, 0, 0.8)", + dark: { + primary: {bg: '#FFFFFF', text: '#000000'}, + secondary: {bg: '#3D8BFF', text: '#000000'}, + success: {bg: '#2FFA86', text: '#000000'}, + danger: {bg: '#FF3C3C', text: '#000000'}, + warning: {bg: '#F4CC3E', text: '#000000'}, + info: {bg: '#2998FF', text: '#000000'}, + light: {bg: '#313131', text: '#FFFFFF'}, + disabled: {bg: '#292929', text: '#474747'}, }, - text: { - basic: "#000000", - label: "#4D4D4D", - placeholder: "#787878", - disabled: "#BEBEBE", - validation: "#DA0000", - contrast: "#FFFFFF", +}; + +const colors: { + light: Partial; + dark: Partial; +} = { + light: { + bg: { + basic: '#FFFFFF', + paper: '#EDEDED', + disabled: '#BEBEBE', + }, + role: { + primary: '#1B1B1B', + secondary: '#3D8BFF', + success: baseColors.success, + warning: baseColors.warning, + danger: baseColors.danger, + info: baseColors.info, + accent: baseColors.accent, + link: baseColors.link, + border: '#CCCCCC', + underlay: 'rgba(0, 0, 0, 0.16)', + underlayContrast: 'rgba(0, 0, 0, 0.8)', + }, + text: { + basic: '#000000', + label: '#4D4D4D', + placeholder: '#787878', + disabled: '#BEBEBE', + validation: '#DA0000', + contrast: '#FFFFFF', + }, + button: buttonColors.light, }, - button: { - primary: { - bg: "#1B1B1B", - text: "#FFFFFF", - }, - secondary: { - bg: "#3D8BFF", - text: "#FFFFFF", - }, - success: { - bg: "#1CD66C", - text: "#FFFFFF", - }, - danger: { - bg: "#F84444", - text: "#FFFFFF", - }, - warning: { - bg: "#E2B101", - text: "#FFFFFF", - }, - info: { - bg: "#307EF1", - text: "#FFFFFF", - }, - light: { - bg: "#E8E8E8", - text: "#232323", - }, - disabled: { - bg: "#EDEDED", - text: "#BEBEBE", - }, + + dark: { + bg: { + basic: '#242424', + paper: '#1E1D1D', + disabled: '#474747', + }, + role: { + primary: '#FFFFFF', + secondary: '#3D8BFF', + success: '#2FFA86', + warning: '#F4CC3E', + danger: '#FF3C3C', + info: '#2998FF', + accent: '#4AE3AD', + link: baseColors.link, + border: '#363636', + underlay: 'rgba(255, 255, 255, 0.16)', + underlayContrast: 'rgba(255, 255, 255, 0.8)', + }, + text: { + basic: '#FFFFFF', + label: '#BEBEBE', + placeholder: '#909090', + disabled: '#6D6D6D', + validation: '#FF2C2C', + contrast: '#000000', + }, + button: buttonColors.dark, }, }; -export const dark: typeof light = { +type ThemeColors = { bg: { - basic: "#242424", - paper: "#1E1D1D", - disabled: "#474747", - }, + basic: string; + paper: string; + disabled: string; + }; role: { - primary: "#FFFFFF", - secondary: "#3D8BFF", - accent: "#6BF3C5", - info: "#2998FF", - link: "#A351F4", - success: "#2FFA86", - warning: "#F4CC3E", - danger: "#FF3C3C", - border: "#363636", - underlay: "rgba(255, 255, 255, 0.16)", - underlayContrast: "rgba(255, 255, 255, 0.8)", - }, + primary: string; + secondary: string; + success: string; + warning: string; + danger: string; + info: string; + accent: string; + link: string; + border: string; + underlay: string; + underlayContrast: string; + }; text: { - basic: "#FFFFFF", - label: "#BEBEBE", - placeholder: "#909090", - disabled: "#4D4D4D", - validation: "#FF2C2C", - contrast: "#000000", - }, + basic: string; + label: string; + placeholder: string; + disabled: string; + validation: string; + contrast: string; + }; button: { - primary: { - bg: "#FFFFFF", - text: "#000000", - }, - secondary: { - bg: "#3D8BFF", - text: "#000000", - }, - success: { - bg: "#2FFA86", - text: "#000000", - }, - danger: { - bg: "#FF3C3C", - text: "#000000", - }, - warning: { - bg: "#F4CC3E", - text: "#000000", - }, - info: { - bg: "#2998FF", - text: "#000000", - }, - light: { - bg: "#313131", - text: "#EBEBEB", - }, - disabled: { - bg: "#292929", - text: "#474747", - }, - }, + primary: {bg: string; text: string}; + secondary: {bg: string; text: string}; + success: {bg: string; text: string}; + danger: {bg: string; text: string}; + warning: {bg: string; text: string}; + info: {bg: string; text: string}; + light: {bg: string; text: string}; + disabled: {bg: string; text: string}; + }; }; +const createTheme = (mode: 'light' | 'dark'): ThemeColors => { + const themeColors = colors[mode]; + + return { + bg: themeColors.bg as ThemeColors['bg'], + role: themeColors.role as ThemeColors['role'], + text: themeColors.text as ThemeColors['text'], + button: themeColors.button as ThemeColors['button'], + }; +}; + +export const light = createTheme('light'); +export const dark = createTheme('dark'); + export type Colors = typeof light;