icon_button.ts

  1import { interactive, toggleable } from "../element"
  2import { background, foreground } from "../style_tree/components"
  3import { useTheme, Theme, Layer } from "../theme"
  4import { Button } from "./button"
  5
  6export type Margin = {
  7    top: number
  8    bottom: number
  9    left: number
 10    right: number
 11}
 12
 13interface IconButtonOptions {
 14    layer?: Theme["lowest"] | Theme["middle"] | Theme["highest"]
 15    color?: keyof Theme["lowest"]
 16    background_color?: keyof Theme["lowest"]
 17    margin?: Partial<Margin>
 18    variant?: Button.Variant
 19    size?: Button.Size
 20}
 21
 22type ToggleableIconButtonOptions = IconButtonOptions & {
 23    active_color?: keyof Theme["lowest"]
 24    active_background_color?: keyof Theme["lowest"]
 25    active_layer?: Layer
 26    active_variant?: Button.Variant
 27}
 28
 29export function icon_button(
 30    { color, background_color, margin, layer, variant, size }: IconButtonOptions = {
 31        variant: Button.variant.Default,
 32        size: Button.size.Medium,
 33    }
 34) {
 35    const theme = useTheme()
 36
 37    if (!color) color = "base"
 38
 39    const default_background =
 40        variant === Button.variant.Ghost
 41            ? null
 42            : background(layer ?? theme.lowest, background_color ?? color)
 43
 44    const m = {
 45        top: margin?.top ?? 0,
 46        bottom: margin?.bottom ?? 0,
 47        left: margin?.left ?? 0,
 48        right: margin?.right ?? 0,
 49    }
 50
 51    const padding = {
 52        top: size === Button.size.Small ? 2 : 2,
 53        bottom: size === Button.size.Small ? 2 : 2,
 54        left: size === Button.size.Small ? 2 : 4,
 55        right: size === Button.size.Small ? 2 : 4,
 56    }
 57
 58    return interactive({
 59        base: {
 60            corner_radius: 6,
 61            padding: padding,
 62            margin: m,
 63            icon_width: 14,
 64            icon_height: 14,
 65            button_width: size === Button.size.Small ? 16 : 20,
 66            button_height: 14,
 67        },
 68        state: {
 69            default: {
 70                background: default_background,
 71                color: foreground(layer ?? theme.lowest, color),
 72            },
 73            hovered: {
 74                background: background(layer ?? theme.lowest, background_color ?? color, "hovered"),
 75                color: foreground(layer ?? theme.lowest, color, "hovered"),
 76            },
 77            clicked: {
 78                background: background(layer ?? theme.lowest, background_color ?? color, "pressed"),
 79                color: foreground(layer ?? theme.lowest, color, "pressed"),
 80            },
 81        },
 82    })
 83}
 84
 85export function toggleable_icon_button({
 86    color,
 87    background_color,
 88    active_color,
 89    active_background_color,
 90    active_variant,
 91    margin,
 92    variant,
 93    size,
 94    active_layer,
 95}: ToggleableIconButtonOptions) {
 96    if (!color) color = "base"
 97
 98    return toggleable({
 99        state: {
100            inactive: icon_button({ color, background_color, margin, variant, size }),
101            active: icon_button({
102                color: active_color ? active_color : color,
103                background_color: active_background_color ? active_background_color : background_color,
104                margin,
105                layer: active_layer,
106                variant: active_variant || variant,
107                size,
108            }),
109        },
110    })
111}