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