about summary refs log tree commit diff
path: root/src/components/forms/ToggleButton.tsx
diff options
context:
space:
mode:
authorEric Bailey <git@esb.lol>2024-01-18 20:28:04 -0600
committerGitHub <noreply@github.com>2024-01-18 20:28:04 -0600
commit66b8774ecb9c5d465987909577ddad3dd4a3ab8e (patch)
treeb1874c6cedd0111eca41db237e606f8e50739d55 /src/components/forms/ToggleButton.tsx
parent9cbd3c0937d22e8dccbd9c086d3a3a24dbd27b3a (diff)
downloadvoidsky-66b8774ecb9c5d465987909577ddad3dd4a3ab8e.tar.zst
New component library based on ALF (#2459)
* Install on native as well

* Add button and link components

* Comments

* Use new prop

* Add some form elements

* Add labels to input

* Fix line height, add suffix

* Date inputs

* Autofill styles

* Clean up InputDate types

* Improve types for InputText, value handling

* Enforce a11y props on buttons

* Add Dialog, Portal

* Dialog contents

* Native dialog

* Clean up

* Fix animations

* Improvements to web modal, exiting still broken

* Clean up dialog types

* Add Prompt, Dialog refinement, mobile refinement

* Integrate new design tokens, reorg storybook

* Button colors

* Dim mode

* Reorg

* Some styles

* Toggles

* Improve a11y

* Autosize dialog, handle max height, Dialog.ScrolLView not working

* Try to use BottomSheet's own APIs

* Scrollable dialogs

* Add web shadow

* Handle overscroll

* Styles

* Dialog text input

* Shadows

* Button focus states

* Button pressed states

* Gradient poc

* Gradient colors and hovers

* Add hrefAttrs to Link

* Some more a11y

* Toggle invalid states

* Update dialog descriptions for demo

* Icons

* WIP Toggle cleanup

* Refactor toggle to not rely on immediate children

* Make Toggle controlled

* Clean up Toggles storybook

* ToggleButton styles

* Improve a11y labels

* ToggleButton hover darkmode

* Some i18n

* Refactor input

* Allow extension of input

* Remove old input

* Improve icons, add CalendarDays

* Refactor DateField, web done

* Add label example

* Clean up old InputDate, DateField android, text area example

* Consistent imports

* Button context, icons

* Add todo

* Add closeAllDialogs control

* Alignment

* Expand color palette

* Hitslops, add shortcut to Storybook in dev

* Fix multiline on ios

* Mark dialog close button as unused
Diffstat (limited to 'src/components/forms/ToggleButton.tsx')
-rw-r--r--src/components/forms/ToggleButton.tsx124
1 files changed, 124 insertions, 0 deletions
diff --git a/src/components/forms/ToggleButton.tsx b/src/components/forms/ToggleButton.tsx
new file mode 100644
index 000000000..615fedae8
--- /dev/null
+++ b/src/components/forms/ToggleButton.tsx
@@ -0,0 +1,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>
+  )
+}