diff --git a/packages/kit/src/components/internal/Button.tsx b/packages/kit/src/components/internal/Button.tsx index b0848fb77..06a34fd52 100644 --- a/packages/kit/src/components/internal/Button.tsx +++ b/packages/kit/src/components/internal/Button.tsx @@ -14,18 +14,20 @@ export const Button: React.FC = ({ ...props }) => { const {colors} = useTheme() + const buttonVariant = colors[variant] const baseStyles = "px-4 py-2 rounded-md font-medium transition-colors" - const variantStyles = { - primary: colors.primary, - secondary: colors.secondary, - outline: colors.outline, - link: colors.link, - } + + const variantClasses = twMerge( + buttonVariant.background, + buttonVariant.text, + buttonVariant.hover, + buttonVariant.border + ) return ( ) diff --git a/packages/kit/src/core/theme.tsx b/packages/kit/src/core/theme.tsx index 9746d5e3b..0fdd72b20 100644 --- a/packages/kit/src/core/theme.tsx +++ b/packages/kit/src/core/theme.tsx @@ -1,10 +1,17 @@ import React, {createContext, useContext} from "react" +export type ButtonVariant = { + background: string + text: string + hover: string + border?: string +} + export type ThemeColors = { - primary: string - secondary: string - outline: string - link: string + primary: ButtonVariant + secondary: ButtonVariant + outline: ButtonVariant + link: ButtonVariant } export type Theme = { @@ -13,32 +20,74 @@ export type Theme = { const defaultTheme: Theme = { colors: { - primary: "bg-slate-900 text-white hover:bg-slate-800", - secondary: "bg-slate-100 text-slate-900 hover:bg-slate-200", - outline: - "bg-transparent border border-slate-200 text-slate-900 hover:bg-slate-100", - link: "bg-transparent text-black hover:underline hover:text-black", + primary: { + background: "bg-slate-900", + text: "text-white", + hover: "hover:bg-slate-800", + border: undefined, + }, + secondary: { + background: "bg-slate-100", + text: "text-slate-900", + hover: "hover:bg-slate-200", + border: undefined, + }, + outline: { + background: "bg-transparent", + text: "text-slate-900", + hover: "hover:bg-slate-100", + border: "border border-slate-200", + }, + link: { + background: "bg-transparent", + text: "text-slate-900", + hover: "hover:underline", + border: undefined, + }, }, } const ThemeContext = createContext(defaultTheme) export const useTheme = () => useContext(ThemeContext) +type DeepPartial = { + [P in keyof T]?: T[P] extends object ? DeepPartial : T[P] +} + type ThemeProviderProps = React.PropsWithChildren<{ - theme?: Partial + theme?: DeepPartial }> +const deepMerge = (target: T, source?: DeepPartial): T => { + if (!source) return target + const result = {...target} + + Object.keys(source).forEach(key => { + const targetValue = target[key as keyof T] + const sourceValue = source[key as keyof DeepPartial] + + if ( + sourceValue && + typeof sourceValue === "object" && + targetValue && + typeof targetValue === "object" + ) { + result[key as keyof T] = deepMerge( + targetValue as object, + sourceValue as object + ) as T[keyof T] + } else if (sourceValue !== undefined) { + result[key as keyof T] = sourceValue as T[keyof T] + } + }) + + return result +} + export const ThemeProvider = ({ theme: customTheme, children, }: ThemeProviderProps) => { - const theme = { - ...defaultTheme, - ...customTheme, - colors: { - ...defaultTheme.colors, - ...customTheme?.colors, - }, - } + const theme = deepMerge(defaultTheme, customTheme) return {children} } diff --git a/packages/kit/src/provider/FlowProvider.tsx b/packages/kit/src/provider/FlowProvider.tsx index 6d515fa4a..92221db77 100644 --- a/packages/kit/src/provider/FlowProvider.tsx +++ b/packages/kit/src/provider/FlowProvider.tsx @@ -4,13 +4,14 @@ import {FlowConfig, FlowConfigContext} from "../core/context" import {DefaultOptions, QueryClient} from "@tanstack/react-query" import {FlowQueryClientProvider} from "./FlowQueryClient" import {deepEqual} from "../utils/deepEqual" -import {ThemeProvider} from "../core/theme" +import {ThemeProvider, Theme} from "../core/theme" import tailwindStyles from "../styles/tailwind.css" interface FlowProviderProps { config?: FlowConfig queryClient?: QueryClient flowJson?: Record + theme?: Partial } const mappings: Array<{fcl: string; typed: keyof FlowConfig}> = [ @@ -93,6 +94,7 @@ export function FlowProvider({ config: initialConfig = {}, queryClient: _queryClient, flowJson, + theme: customTheme, children, }: PropsWithChildren) { const [queryClient] = useState( @@ -144,7 +146,7 @@ export function FlowProvider({ - {children} + {children} )