button.ts

  1import { font_sizes, useTheme } from "../common"
  2import { Layer, Theme } from "../theme"
  3import { TextStyle, background } from "../style_tree/components"
  4
  5// eslint-disable-next-line @typescript-eslint/no-namespace
  6export namespace Button {
  7    export type Options = {
  8        layer: Layer,
  9        background: keyof Theme["lowest"]
 10        color: keyof Theme["lowest"]
 11        variant: Button.Variant
 12        size: Button.Size
 13        shape: Button.Shape
 14        margin: {
 15            top?: number
 16            bottom?: number
 17            left?: number
 18            right?: number
 19        },
 20        states: {
 21            enabled?: boolean,
 22            hovered?: boolean,
 23            pressed?: boolean,
 24            focused?: boolean,
 25            disabled?: boolean,
 26        }
 27    }
 28
 29    export type ToggleableOptions = Options & {
 30        active_background: keyof Theme["lowest"]
 31        active_color: keyof Theme["lowest"]
 32    }
 33
 34    /** Padding added to each side of a Shape.Rectangle button */
 35    export const RECTANGLE_PADDING = 2
 36    export const FONT_SIZE = font_sizes.sm
 37    export const ICON_SIZE = 14
 38    export const CORNER_RADIUS = 6
 39
 40    export const variant = {
 41        Default: 'filled',
 42        Outline: 'outline',
 43        Ghost: 'ghost'
 44    } as const
 45
 46    export type Variant = typeof variant[keyof typeof variant]
 47
 48    export const shape = {
 49        Rectangle: 'rectangle',
 50        Square: 'square'
 51    } as const
 52
 53    export type Shape = typeof shape[keyof typeof shape]
 54
 55    export const size = {
 56        Small: "sm",
 57        Medium: "md"
 58    } as const
 59
 60    export type Size = typeof size[keyof typeof size]
 61
 62    export type BaseStyle = {
 63        corder_radius: number
 64        background: string | null
 65        padding: {
 66            top: number
 67            bottom: number
 68            left: number
 69            right: number
 70        },
 71        margin: Button.Options['margin']
 72        button_height: number
 73    }
 74
 75    export type LabelButtonStyle = BaseStyle & TextStyle
 76    // export type IconButtonStyle = ButtonStyle
 77
 78    export const button_base = (
 79        options: Partial<Button.Options> = {
 80            variant: Button.variant.Default,
 81            shape: Button.shape.Rectangle,
 82            states: {
 83                hovered: true,
 84                pressed: true
 85            }
 86        }
 87    ): BaseStyle => {
 88        const theme = useTheme()
 89
 90        const layer = options.layer ?? theme.middle
 91        const color = options.color ?? "base"
 92        const background_color = options.variant === Button.variant.Ghost ? null : background(layer, options.background ?? color)
 93
 94        const m = {
 95            top: options.margin?.top ?? 0,
 96            bottom: options.margin?.bottom ?? 0,
 97            left: options.margin?.left ?? 0,
 98            right: options.margin?.right ?? 0,
 99        }
100        const size = options.size || Button.size.Medium
101        const padding = 2
102
103        const base: BaseStyle = {
104            background: background_color,
105            corder_radius: Button.CORNER_RADIUS,
106            padding: {
107                top: padding,
108                bottom: padding,
109                left: options.shape === Button.shape.Rectangle ? padding + Button.RECTANGLE_PADDING : padding,
110                right: options.shape === Button.shape.Rectangle ? padding + Button.RECTANGLE_PADDING : padding
111            },
112            margin: m,
113            button_height: 16,
114        }
115
116        return base
117    }
118}