about summary refs log tree commit diff
path: root/src/components/forms/ToggleButton.tsx
blob: 615fedae8b9cf19e6366d64999d3546940df38bd (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
import React from 'react'
import {View, AccessibilityProps, TextStyle, ViewStyle} from 'react-native'

import {atoms as a, useTheme, native} from '#/alf'
import {Text} from '#/components/Typography'

import * as Toggle from '#/components/forms/Toggle'

export type ItemProps = Omit<Toggle.ItemProps, 'style' | 'role' | 'children'> &
  AccessibilityProps &
  React.PropsWithChildren<{}>

export type GroupProps = Omit<Toggle.GroupProps, 'style' | 'type'> & {
  multiple?: boolean
}

export function Group({children, multiple, ...props}: GroupProps) {
  const t = useTheme()
  return (
    <Toggle.Group type={multiple ? 'checkbox' : 'radio'} {...props}>
      <View
        style={[
          a.flex_row,
          a.border,
          a.rounded_sm,
          a.overflow_hidden,
          t.atoms.border,
        ]}>
        {children}
      </View>
    </Toggle.Group>
  )
}

export function Button({children, ...props}: ItemProps) {
  return (
    <Toggle.Item {...props}>
      <ButtonInner>{children}</ButtonInner>
    </Toggle.Item>
  )
}

function ButtonInner({children}: React.PropsWithChildren<{}>) {
  const t = useTheme()
  const state = Toggle.useItemContext()

  const {baseStyles, hoverStyles, activeStyles, textStyles} =
    React.useMemo(() => {
      const base: ViewStyle[] = []
      const hover: ViewStyle[] = []
      const active: ViewStyle[] = []
      const text: TextStyle[] = []

      hover.push(
        t.name === 'light' ? t.atoms.bg_contrast_100 : t.atoms.bg_contrast_25,
      )

      if (state.selected) {
        active.push({
          backgroundColor: t.palette.contrast_800,
        })
        text.push(t.atoms.text_inverted)
        hover.push({
          backgroundColor: t.palette.contrast_800,
        })

        if (state.disabled) {
          active.push({
            backgroundColor: t.palette.contrast_500,
          })
        }
      }

      if (state.disabled) {
        base.push({
          backgroundColor: t.palette.contrast_100,
        })
        text.push({
          opacity: 0.5,
        })
      }

      return {
        baseStyles: base,
        hoverStyles: hover,
        activeStyles: active,
        textStyles: text,
      }
    }, [t, state])

  return (
    <View
      style={[
        {
          borderLeftWidth: 1,
          marginLeft: -1,
        },
        a.px_lg,
        a.py_md,
        native({
          paddingTop: 14,
        }),
        t.atoms.bg,
        t.atoms.border,
        baseStyles,
        activeStyles,
        (state.hovered || state.focused || state.pressed) && hoverStyles,
      ]}>
      {typeof children === 'string' ? (
        <Text
          style={[
            a.text_center,
            a.font_bold,
            t.atoms.text_contrast_500,
            textStyles,
          ]}>
          {children}
        </Text>
      ) : (
        children
      )}
    </View>
  )
}