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