import { isArray } from 'lodash'; import React, { AnchorHTMLAttributes, ButtonHTMLAttributes, FormHTMLAttributes, HTMLAttributes, InputHTMLAttributes, LabelHTMLAttributes, } from 'react'; import { Link, LinkProps as RouterLinkProps } from 'react-router-dom'; import { SilkeColor } from '../../silke-theme-provider'; import styles from './silke-box.scss'; export type BoxSpace = | 'xxs' | 'xs' | 's' | 'sm' | 'm' | 'l' | 'xl' | 'xxl' | 'xxxl' | 'none' | boolean; export type BoxSize = 'xs' | 's' | 'base' | 'm' | 'l' | 'xl' | 'xxl' | '256' | '512'; export type BoxAlign = 'center' | 'start' | 'end' | 'spread' | 'space' | boolean; export type TagAttributes = { a: Omit, 'color'>; button: Omit, 'color'>; input: Omit, 'color'>; div: Omit, 'color'>; label: Omit, 'color'>; form: Omit, 'color'>; ol: Omit, 'color'>; ul: Omit, 'color'>; li: Omit, 'color'>; header: Omit, 'color'>; dl: Omit, 'color'>; }; export const Flex = ({ weight = 100 }: { weight?: number }) => (
); type BaseProps = { /** Layout contnet in column */ column?: boolean; /** Should fill container */ fill?: boolean; /** Flex gap */ gap?: BoxSpace; /** Vertical/horizontal space */ pad?: BoxSpace; /** Vertical padding in element */ vPad?: BoxSpace; /** Horizontal padding in element */ hPad?: BoxSpace; /** Sets both width and height */ size?: BoxSize; /** Width of the box (x2 of the spaceing, example: 'm' = 32px wide) */ height?: BoxSize; /** Width of the box (x2 of the spaceing, example: 'm' = 32px wide) */ width?: BoxSize; /** Width of the box (x2 of the spaceing, example: 'm' = 32px wide) */ minHeight?: BoxSize; /** Width of the box (x2 of the spaceing, example: 'm' = 32px wide) */ minWidth?: BoxSize; /** Background color */ bg?: SilkeColor | 'blur'; /** Background color on hover */ bgHover?: SilkeColor; /** Text color */ color?: SilkeColor; /** Border radius */ rounded?: boolean | 'tiny' | 'small' | 'medium' | 'full'; shadow?: 'level1' | 'level2' | 'level3' | 'level4'; overflow?: 'hidden' | 'scroll-y'; cursor?: 'pointer' | 'grab' | 'text'; userSelect?: 'none' | 'text'; /** Text color on hover */ colorHover?: SilkeColor; aspectRatio?: '16:9' | '4:3' | '1:1'; /** Flex item */ flex?: boolean; /** Wrap items */ wrap?: boolean; /** Align content of box, use array to define separat for x and y axis */ align?: BoxAlign | [BoxAlign, BoxAlign]; vAlign?: BoxAlign; hAlign?: BoxAlign; /** Debug adds an out line to all box and child boxes */ debug?: boolean; scroll?: boolean | 'show'; rel?: string; }; type InputProps = { tag: 'input'; } & TagAttributes['input'] & BaseProps; export type BoxButtonProps = { tag?: 'button'; } & TagAttributes['button'] & BaseProps; type AnchorProps = { tag: 'a'; } & TagAttributes['a'] & BaseProps; export type BoxLinkProps = { tag: 'link'; } & RouterLinkProps & BaseProps; export type BoxDivProps = { tag?: 'div'; } & TagAttributes['div'] & BaseProps; export type BoxNavProps = { tag?: 'nav'; } & TagAttributes['div'] & BaseProps; export type BoxOlProps = { tag?: 'ol'; } & TagAttributes['ol'] & BaseProps; export type BoxUlProps = { tag?: 'ul'; } & TagAttributes['ul'] & BaseProps; export type BoxLiProps = { tag?: 'li'; } & TagAttributes['li'] & BaseProps; export type BoxLabelProps = { tag?: 'label'; } & TagAttributes['label'] & BaseProps; export type BoxFormProps = { tag?: 'form'; } & TagAttributes['form'] & BaseProps; export type BoxHeaderProps = { tag?: 'header'; } & TagAttributes['header'] & BaseProps; export type BoxDlProps = { tag?: 'dl'; } & TagAttributes['dl'] & BaseProps; export type BoxDtProps = { tag?: 'dt'; } & TagAttributes['dl'] & BaseProps; export type BoxDdProps = { tag?: 'dd'; } & TagAttributes['dl'] & BaseProps; export type BoxProps = | InputProps | BoxButtonProps | AnchorProps | BoxLinkProps | BoxDivProps | BoxLabelProps | BoxFormProps | BoxNavProps | BoxOlProps | BoxUlProps | BoxLiProps | BoxHeaderProps | BoxDlProps | BoxDtProps | BoxDdProps; function BoxComp( { aspectRatio, column, fill, gap, pad, vPad, hPad, size, width = size, height = size, minWidth, minHeight, children, color, colorHover, bg, bgHover, tag, flex, wrap, align, vAlign, hAlign, className, debug, scroll, rounded, shadow, overflow, cursor, userSelect, ...rest }: BoxProps, ref: any, ) { const cl = [styles.box]; if (className) cl.push(className); if (column) cl.push(styles.column); if (flex) cl.push(styles.flex); if (fill) cl.push(styles.fill); if (overflow) cl.push(styles['overflow-' + overflow]); if (wrap) cl.push(styles.wrap); if (shadow) cl.push(styles['shadow-' + shadow]); if (rounded) cl.push(styles[`rounded-${rounded === true ? 'small' : rounded}`]); if (cursor) cl.push(styles['cursor-' + cursor]); if (aspectRatio) { rest.style = { ...rest.style, aspectRatio: aspectRatio.replace(':', '/') }; } if (pad) { if (pad === true) pad = 'm'; cl.push(styles['hPad-' + pad], styles['vPad-' + pad]); } else { if (vPad) cl.push(styles['vPad-' + (vPad === true ? 'm' : vPad)]); if (hPad) cl.push(styles['hPad-' + (hPad === true ? 'm' : hPad)]); } if (gap) cl.push(styles['gap-' + (gap === true ? 'm' : gap)]); if (width) cl.push(styles['width-' + width]); if (height) cl.push(styles['height-' + height]); if (minWidth) cl.push(styles['minWidth-' + minWidth]); if (minHeight) cl.push(styles['minHeight-' + minHeight]); if (color) cl.push('color-' + color); if (colorHover) cl.push('color-hover-' + colorHover); if (bg) cl.push('bg-' + bg); if (bgHover) cl.push('bg-hover-' + bgHover); if (userSelect) cl.push(styles['user-select-' + userSelect]); if (isArray(align)) { [hAlign, vAlign] = align; } else if (align) { hAlign = align; vAlign = align; } if (hAlign) cl.push(styles['h-' + (hAlign === true ? 'center' : hAlign)]); if (vAlign) cl.push(styles['v-' + (vAlign === true ? 'center' : vAlign)]); if (scroll) cl.push(scroll === 'show' ? styles.showScroll : styles.scroll); if (debug) cl.push(styles.debug); return React.createElement( tag === 'link' ? Link : tag || 'div', { className: cl.join(' '), ref, ...rest } as any, children, ); } export const SilkeBox = React.forwardRef(BoxComp); SilkeBox.displayName = 'SilkeBox';