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 =
 93            options.variant === Button.variant.Ghost
 94                ? null
 95                : background(layer, options.background ?? color)
 96
 97        const m = {
 98            top: options.margin?.top ?? 0,
 99            bottom: options.margin?.bottom ?? 0,
100            left: options.margin?.left ?? 0,
101            right: options.margin?.right ?? 0,
102        }
103        const size = options.size || Button.size.Medium
104        const padding = 2
105
106        const base: BaseStyle = {
107            background: background_color,
108            corder_radius: Button.CORNER_RADIUS,
109            padding: {
110                top: padding,
111                bottom: padding,
112                left:
113                    options.shape === Button.shape.Rectangle
114                        ? padding + Button.RECTANGLE_PADDING
115                        : padding,
116                right:
117                    options.shape === Button.shape.Rectangle
118                        ? padding + Button.RECTANGLE_PADDING
119                        : padding,
120            },
121            margin: m,
122            button_height: 16,
123        }
124
125        return base
126    }
127}