Skip to content

Instantly share code, notes, and snippets.

@7iomka
Created September 23, 2023 17:19
Show Gist options
  • Save 7iomka/4dfd93afec586423c0f0cb4fc75b75dd to your computer and use it in GitHub Desktop.
Save 7iomka/4dfd93afec586423c0f0cb4fc75b75dd to your computer and use it in GitHub Desktop.
Theme-variant
import type { CSSProperties } from 'react';
import type { MantineGradient, MantineColor, MantineTheme } from '@mantine/core';
import { getReadableColor, themeColor } from './theme-color';
export interface VariantInput {
variant: string;
color?: MantineColor;
gradient?: MantineGradient;
primaryFallback?: boolean;
}
export interface VariantOutput {
border: CSSProperties['borderColor'];
background: CSSProperties['backgroundColor'];
color: CSSProperties['color'];
hover?: {
border?: CSSProperties['borderColor'] | null;
background?: CSSProperties['backgroundColor'] | null;
color?: CSSProperties['color'] | null;
};
}
interface ColorInfo {
isSplittedColor: boolean;
key?: string;
shade?: number;
}
function getColorIndexInfo(color: MantineColor | undefined, theme: MantineTheme): ColorInfo {
if (typeof color === 'string' && color.includes('.')) {
const [splittedColor, _splittedShade] = color.split('.');
const splittedShade = parseInt(_splittedShade, 10);
if (splittedColor in theme.colors && splittedShade >= 0 && splittedShade < 10) {
return { isSplittedColor: true, key: splittedColor, shade: splittedShade };
}
}
return { isSplittedColor: false };
}
export function themeVariant(theme: MantineTheme) {
const getThemeColor = themeColor(theme);
// eslint-disable-next-line @typescript-eslint/no-shadow
return ({ variant, color, gradient, primaryFallback }: VariantInput): VariantOutput => {
const colorInfo = getColorIndexInfo(color, theme);
switch (variant) {
case 'light': {
return {
border: 'transparent',
background: theme.fn.rgba(
getThemeColor({
color,
shade: theme.colorScheme === 'dark' ? 8 : 0,
primaryFallback,
useSplittedShade: false,
}),
theme.colorScheme === 'dark' ? 0.2 : 1,
),
color:
color === 'dark'
? theme.colorScheme === 'dark'
? theme.colors.dark[0]
: theme.colors.dark[9]
: getThemeColor({
color,
shade: theme.colorScheme === 'dark' ? 2 : theme.fn.primaryShade('light'),
}),
hover: {
background: theme.fn.rgba(
getThemeColor({
color,
shade: theme.colorScheme === 'dark' ? 7 : 1,
primaryFallback,
useSplittedShade: false,
}),
theme.colorScheme === 'dark' ? 0.25 : 0.65,
),
},
};
}
case 'subtle': {
const fallbackColor = 'var(--root-color)';
const fallbackBgColor =
theme.colorScheme === 'dark' ? theme.colors.dark[4] : theme.colors.gray[2];
// gray color is used by default for subtle text color for action icon - ignore it
const shouldUseFallbackColor = !color || color.includes('gray');
return {
border: 'transparent',
background: 'transparent',
color:
color === 'dark'
? theme.colorScheme === 'dark'
? theme.colors.dark[0]
: theme.colors.dark[9]
: shouldUseFallbackColor
? fallbackColor
: getThemeColor({
color,
shade: theme.colorScheme === 'dark' ? 2 : theme.fn.primaryShade('light'),
primaryFallback,
}),
hover: {
background: shouldUseFallbackColor
? fallbackBgColor
: theme.fn.rgba(
getThemeColor({
color,
shade: theme.colorScheme === 'dark' ? 8 : 0,
primaryFallback,
useSplittedShade: false,
}),
theme.colorScheme === 'dark' ? 0.2 : 1,
),
},
};
}
case 'outline': {
const fallbackColor = 'inherit';
const shouldUseFallbackColor = !color;
const isCurrentOrInheritColor = !!color && ['inherit', 'currentColor'].includes(color);
const fallbackBg = theme.colorScheme === 'dark' ? theme.colors.dark[6] : theme.white;
const fallbackBgOnHover =
theme.colorScheme === 'dark' ? theme.colors.dark[5] : theme.colors.gray[0];
return {
border: shouldUseFallbackColor
? theme.colorScheme === 'dark'
? theme.colors.dark[4]
: theme.colors.gray[4]
: isCurrentOrInheritColor
? 'currentcolor'
: getThemeColor({
color,
shade: theme.colorScheme === 'dark' ? 5 : theme.fn.primaryShade('light'),
primaryFallback: false,
}),
background: shouldUseFallbackColor ? fallbackBg : 'transparent',
color: shouldUseFallbackColor
? fallbackColor
: getThemeColor({
color,
shade: theme.colorScheme === 'dark' ? 5 : theme.fn.primaryShade('light'),
primaryFallback: false,
}),
hover: {
background:
shouldUseFallbackColor || isCurrentOrInheritColor
? fallbackBgOnHover
: theme.fn.rgba(
getThemeColor({ color }),
theme.colorScheme === 'dark' ? 0.05 : 0.1,
),
color:
shouldUseFallbackColor || isCurrentOrInheritColor
? getReadableColor({
color: fallbackBgOnHover,
colorVariants: [
theme.colorScheme === 'dark' ? theme.colors.dark[0] : '#fff',
theme.colors.dark[4],
],
})
: getThemeColor({
color,
shade: theme.colorScheme === 'dark' ? 5 : theme.fn.primaryShade('light'),
primaryFallback: false,
}),
// theme.colorScheme === 'dark'
// ? theme.fn.rgba(
// getThemeColor({ color, shade: 5, primaryFallback, useSplittedShade: false }),
// 0.05,
// )
// : theme.fn.rgba(
// getThemeColor({ color, shade: 0, primaryFallback, useSplittedShade: false }),
// 0.35,
// ),
},
};
}
case 'default': {
return {
border: theme.colorScheme === 'dark' ? theme.colors.dark[4] : theme.colors.gray[4],
background: theme.colorScheme === 'dark' ? theme.colors.dark[6] : theme.white,
color: theme.colorScheme === 'dark' ? theme.white : theme.black,
hover: {
background: theme.colorScheme === 'dark' ? theme.colors.dark[5] : theme.colors.gray[0],
},
};
}
case 'white': {
return {
border: 'transparent',
background: theme.white,
color: getThemeColor({ color, shade: theme.fn.primaryShade() }),
};
}
case 'transparent': {
return {
border: 'transparent',
color:
color === 'dark'
? theme.colorScheme === 'dark'
? theme.colors.dark[0]
: theme.colors.dark[9]
: getThemeColor({
color,
shade: theme.colorScheme === 'dark' ? 2 : theme.fn.primaryShade('light'),
}),
background: 'transparent',
};
}
case 'gradient': {
return {
background: theme.fn.gradient(gradient),
color: theme.white,
border: 'transparent',
};
}
default: {
const _primaryShade = theme.fn.primaryShade();
const _shade = colorInfo.isSplittedColor ? colorInfo.shade! : _primaryShade;
const _color = colorInfo.isSplittedColor ? colorInfo.key : color;
const shouldUseStaticColor = !!color && ['secondary', 'danger'].includes(_color!);
const bgColor = getThemeColor({ color: _color, shade: _shade, primaryFallback });
return {
border: 'transparent',
background: bgColor,
color: shouldUseStaticColor
? theme.white
: getReadableColor({
color: bgColor,
colorVariants: [
theme.colorScheme === 'dark' ? theme.colors.dark[0] : '#fff',
theme.colors.dark[4],
],
}),
hover: {
background: getThemeColor({
color: _color,
shade: _shade === 9 ? 8 : _shade + 1,
}),
},
};
}
}
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment