about summary refs log tree commit diff
path: root/src/view/com/util/forms/ToggleButton.tsx
diff options
context:
space:
mode:
authorPaul Frazee <pfrazee@gmail.com>2022-12-28 14:06:01 -0600
committerGitHub <noreply@github.com>2022-12-28 14:06:01 -0600
commit7e31645e9a355f2a0b3c8d62430a53dbb4714674 (patch)
tree24db1b09b9065472f5c7e08f9e2798d63fee8b1a /src/view/com/util/forms/ToggleButton.tsx
parentcc63660982199a989859d3b5328ba43a4edec755 (diff)
downloadvoidsky-7e31645e9a355f2a0b3c8d62430a53dbb4714674.tar.zst
Add a design system (#34)
* Add theming system

* Add standard Button control and update RadioButtons

* Unify radiobutton with design system

* Update debug screen to have multiple views

* Add ToggleButton

* Update error controls to use design system

* Add typography to <Text> element

* Move DropdownButton into the design system

* Clean out old code

* Move Text into design system

* Add 'inverted' color palette

* Move LoadingPlaceholder into the design system
Diffstat (limited to 'src/view/com/util/forms/ToggleButton.tsx')
-rw-r--r--src/view/com/util/forms/ToggleButton.tsx165
1 files changed, 165 insertions, 0 deletions
diff --git a/src/view/com/util/forms/ToggleButton.tsx b/src/view/com/util/forms/ToggleButton.tsx
new file mode 100644
index 000000000..77e8fa203
--- /dev/null
+++ b/src/view/com/util/forms/ToggleButton.tsx
@@ -0,0 +1,165 @@
+import React from 'react'
+import {StyleProp, StyleSheet, TextStyle, View, ViewStyle} from 'react-native'
+import {Text} from '../text/Text'
+import {Button, ButtonType} from './Button'
+import {useTheme} from '../../../lib/ThemeContext'
+import {choose} from '../../../../lib/functions'
+import {colors} from '../../../lib/styles'
+
+export function ToggleButton({
+  type = 'default-light',
+  label,
+  isSelected,
+  style,
+  onPress,
+}: {
+  type?: ButtonType
+  label: string
+  isSelected: boolean
+  style?: StyleProp<ViewStyle>
+  onPress: () => void
+}) {
+  const theme = useTheme()
+  const circleStyle = choose<TextStyle, Record<ButtonType, TextStyle>>(type, {
+    primary: {
+      borderColor: theme.palette.primary.text,
+    },
+    secondary: {
+      borderColor: theme.palette.secondary.text,
+    },
+    inverted: {
+      borderColor: theme.palette.inverted.text,
+    },
+    'primary-outline': {
+      borderColor: theme.palette.primary.border,
+    },
+    'secondary-outline': {
+      borderColor: theme.palette.secondary.border,
+    },
+    'primary-light': {
+      borderColor: theme.palette.primary.border,
+    },
+    'secondary-light': {
+      borderColor: theme.palette.secondary.border,
+    },
+    'default-light': {
+      borderColor: theme.palette.default.border,
+    },
+  })
+  const circleFillStyle = choose<TextStyle, Record<ButtonType, TextStyle>>(
+    type,
+    {
+      primary: {
+        backgroundColor: theme.palette.primary.text,
+        opacity: isSelected ? 1 : 0.33,
+      },
+      secondary: {
+        backgroundColor: theme.palette.secondary.text,
+        opacity: isSelected ? 1 : 0.33,
+      },
+      inverted: {
+        backgroundColor: theme.palette.inverted.text,
+        opacity: isSelected ? 1 : 0.33,
+      },
+      'primary-outline': {
+        backgroundColor: theme.palette.primary.background,
+        opacity: isSelected ? 1 : 0.5,
+      },
+      'secondary-outline': {
+        backgroundColor: theme.palette.secondary.background,
+        opacity: isSelected ? 1 : 0.5,
+      },
+      'primary-light': {
+        backgroundColor: theme.palette.primary.background,
+        opacity: isSelected ? 1 : 0.5,
+      },
+      'secondary-light': {
+        backgroundColor: theme.palette.secondary.background,
+        opacity: isSelected ? 1 : 0.5,
+      },
+      'default-light': {
+        backgroundColor: isSelected
+          ? theme.palette.primary.background
+          : colors.gray3,
+      },
+    },
+  )
+  const labelStyle = choose<TextStyle, Record<ButtonType, TextStyle>>(type, {
+    primary: {
+      color: theme.palette.primary.text,
+      fontWeight: theme.palette.primary.isLowContrast ? '500' : undefined,
+    },
+    secondary: {
+      color: theme.palette.secondary.text,
+      fontWeight: theme.palette.secondary.isLowContrast ? '500' : undefined,
+    },
+    inverted: {
+      color: theme.palette.inverted.text,
+      fontWeight: theme.palette.inverted.isLowContrast ? '500' : undefined,
+    },
+    'primary-outline': {
+      color: theme.palette.primary.textInverted,
+      fontWeight: theme.palette.primary.isLowContrast ? '500' : undefined,
+    },
+    'secondary-outline': {
+      color: theme.palette.secondary.textInverted,
+      fontWeight: theme.palette.secondary.isLowContrast ? '500' : undefined,
+    },
+    'primary-light': {
+      color: theme.palette.primary.textInverted,
+      fontWeight: theme.palette.primary.isLowContrast ? '500' : undefined,
+    },
+    'secondary-light': {
+      color: theme.palette.secondary.textInverted,
+      fontWeight: theme.palette.secondary.isLowContrast ? '500' : undefined,
+    },
+    'default-light': {
+      color: theme.palette.default.text,
+      fontWeight: theme.palette.default.isLowContrast ? '500' : undefined,
+    },
+  })
+  return (
+    <Button type={type} onPress={onPress} style={style}>
+      <View style={styles.outer}>
+        <View style={[circleStyle, styles.circle]}>
+          <View
+            style={[
+              circleFillStyle,
+              styles.circleFill,
+              isSelected ? styles.circleFillSelected : undefined,
+            ]}
+          />
+        </View>
+        <Text type="button" style={[labelStyle, styles.label]}>
+          {label}
+        </Text>
+      </View>
+    </Button>
+  )
+}
+
+const styles = StyleSheet.create({
+  outer: {
+    flexDirection: 'row',
+    alignItems: 'center',
+  },
+  circle: {
+    width: 42,
+    height: 26,
+    borderRadius: 15,
+    padding: 4,
+    borderWidth: 1,
+    marginRight: 10,
+  },
+  circleFill: {
+    width: 16,
+    height: 16,
+    borderRadius: 10,
+  },
+  circleFillSelected: {
+    marginLeft: 16,
+  },
+  label: {
+    flex: 1,
+  },
+})