104 lines
3.7 KiB
TypeScript
104 lines
3.7 KiB
TypeScript
import React, { ElementType, ForwardedRef, forwardRef, ReactNode } from 'react';
|
|
import { Box, BoxProps } from './Box';
|
|
import { ThemeRadii, ThemeShadows } from './theme/Theme';
|
|
|
|
/**
|
|
* WARNING: DO NOT VIOLATE THE PURPOSE OF THIS PRIMITIVE.
|
|
*
|
|
* Surface is a styled container with background, border, and shadow.
|
|
*
|
|
* - DO NOT add layout props (flex, grid, gap) - use Stack or Grid instead.
|
|
* - DO NOT add positioning props (absolute, top, zIndex).
|
|
*
|
|
* If you need a more specific layout, create a new component in apps/website/components.
|
|
*/
|
|
|
|
export interface SurfaceProps<T extends ElementType = 'div'> extends BoxProps<T> {
|
|
as?: T;
|
|
children?: ReactNode;
|
|
variant?: 'default' | 'dark' | 'muted' | 'glass' | 'discord' | 'gradient-blue' | 'gradient-gold' | 'gradient-purple' | 'gradient-green' | 'discord-inner' | 'outline' | 'rarity-common' | 'rarity-rare' | 'rarity-epic' | 'rarity-legendary' | 'precision';
|
|
rounded?: keyof ThemeRadii | 'none' | '2xl' | string | boolean;
|
|
shadow?: keyof ThemeShadows | 'none' | string;
|
|
}
|
|
|
|
export const Surface = forwardRef(<T extends ElementType = 'div'>(
|
|
{
|
|
as,
|
|
children,
|
|
variant = 'default',
|
|
rounded = 'none',
|
|
shadow = 'none',
|
|
...props
|
|
}: SurfaceProps<T>,
|
|
ref: ForwardedRef<HTMLElement>
|
|
) => {
|
|
const variantStyles: Record<string, React.CSSProperties> = {
|
|
default: { backgroundColor: 'var(--ui-color-bg-surface)' },
|
|
dark: { backgroundColor: 'var(--ui-color-bg-base)' },
|
|
muted: { backgroundColor: 'var(--ui-color-bg-surface-muted)' },
|
|
precision: {
|
|
backgroundColor: 'var(--ui-color-bg-surface)',
|
|
border: '1px solid var(--ui-color-border-default)',
|
|
boxShadow: 'inset 0 1px 0 0 rgba(255, 255, 255, 0.02)'
|
|
},
|
|
glass: {
|
|
backgroundColor: 'rgba(20, 22, 25, 0.6)',
|
|
backdropFilter: 'blur(12px)',
|
|
WebkitBackdropFilter: 'blur(12px)'
|
|
},
|
|
discord: {
|
|
background: 'linear-gradient(to bottom, var(--ui-color-bg-base), var(--ui-color-bg-surface))'
|
|
},
|
|
'discord-inner': {
|
|
background: 'linear-gradient(to br, var(--ui-color-bg-surface), var(--ui-color-bg-base), var(--ui-color-bg-surface))'
|
|
},
|
|
'gradient-blue': {
|
|
background: 'linear-gradient(to br, rgba(25, 140, 255, 0.1), var(--ui-color-bg-surface), var(--ui-color-bg-base))'
|
|
},
|
|
'gradient-gold': {
|
|
background: 'linear-gradient(to br, rgba(255, 190, 77, 0.1), var(--ui-color-bg-surface), var(--ui-color-bg-base))'
|
|
},
|
|
'gradient-purple': {
|
|
background: 'linear-gradient(to br, rgba(147, 51, 234, 0.1), var(--ui-color-bg-surface), var(--ui-color-bg-base))'
|
|
},
|
|
'gradient-green': {
|
|
background: 'linear-gradient(to br, rgba(111, 227, 122, 0.1), var(--ui-color-bg-surface), var(--ui-color-bg-base))'
|
|
},
|
|
outline: {
|
|
backgroundColor: 'transparent',
|
|
border: '1px solid var(--ui-color-border-default)'
|
|
},
|
|
'rarity-common': {
|
|
backgroundColor: 'rgba(107, 114, 128, 0.1)',
|
|
border: '1px solid rgba(107, 114, 128, 0.5)'
|
|
},
|
|
'rarity-rare': {
|
|
backgroundColor: 'rgba(96, 165, 250, 0.1)',
|
|
border: '1px solid rgba(96, 165, 250, 0.5)'
|
|
},
|
|
'rarity-epic': {
|
|
backgroundColor: 'rgba(192, 132, 252, 0.1)',
|
|
border: '1px solid rgba(192, 132, 252, 0.5)'
|
|
},
|
|
'rarity-legendary': {
|
|
backgroundColor: 'rgba(255, 190, 77, 0.1)',
|
|
border: '1px solid rgba(255, 190, 77, 0.5)'
|
|
}
|
|
};
|
|
|
|
const style: React.CSSProperties = {
|
|
...(props.style || {}),
|
|
...variantStyles[variant],
|
|
borderRadius: rounded !== 'none' ? `var(--ui-radius-${String(rounded)})` : undefined,
|
|
boxShadow: shadow !== 'none' ? `var(--ui-shadow-${String(shadow)})` : undefined,
|
|
};
|
|
|
|
return (
|
|
<Box as={as} ref={ref} {...(props as any)} style={style}>
|
|
{children}
|
|
</Box>
|
|
);
|
|
});
|
|
|
|
Surface.displayName = 'Surface';
|