Browse Source

Merge pull request #431 from semeano/init_atlas

RadioButton component.
Bedeho Mender 4 years ago
parent
commit
4714fbf90c

+ 3 - 0
packages/components/src/components/Dropdown/Dropdown.style.ts

@@ -92,6 +92,9 @@ export let makeStyles = ({
       width: 100%;
       position: absolute;
       top: 50px;
+      max-height: 145px;
+      overflow-x: none;
+      overflow-y: auto;
     `,
     option: css`
       padding: ${spacing.s};

+ 74 - 0
packages/components/src/components/RadioButton/RadioButton.style.ts

@@ -0,0 +1,74 @@
+import { css } from "@emotion/core"
+import { typography, colors, spacing } from "../../theme"
+
+export type RadioButtonStyleProps = {
+  selected?: boolean
+  disabled?: boolean
+  error?: boolean
+  position?: "end" | "start" | "top" | "bottom"
+}
+
+export let makeStyles = ({
+  selected = false,
+  disabled = false,
+  error = false,
+  position = "end"
+}: RadioButtonStyleProps) => {
+
+  return {
+    container: css`
+      font-family: ${typography.fonts.base};
+      display: ${(position === "bottom" || position === "top") ? "inline-block" : "inline-flex"};
+      align-items: center;
+      &:focus {
+        outline: none;
+      }`,
+    outterDot: css`
+      width: ${spacing.xxl};
+      height: ${spacing.xxl};
+      border-radius: 50%;
+      position: relative;
+      ${position === "bottom" ? `margin: 0 auto ${spacing.xs};` :
+        position === "top" ? `margin: ${spacing.xs} auto 0;` : ""}
+      ${disabled ? "cursor: not-allowed;" : ""}
+      &:hover {
+        background-color: ${disabled ? "none" : colors.gray[50]};
+      }
+      &:active {
+        background-color: ${disabled ? "none" : colors.gray[100]};
+      }
+      &:focus {
+        background-color: ${disabled ? "none" : colors.blue[100]};
+        outline: none;
+      }
+    `,
+    dot: css`
+      width: ${spacing.m};
+      height: ${spacing.m};
+      border: 1px solid ${disabled ? colors.gray[200] :
+        error ? colors.error :
+        selected ? colors.blue[500] : colors.gray[300]};
+      border-radius: 50%;
+      ${disabled ? `background-color: ${colors.gray[50]};` : ""}
+      ${disabled && selected ?
+        `background-image: repeating-radial-gradient(circle, ${colors.gray[200]} 0px, ${colors.gray[200]} 3px, transparent 3px, transparent 6px, ${colors.gray[200]} 6px, ${colors.gray[200]} 8px);` :
+        disabled && !selected ? `background-color: ${colors.gray[50]};` :
+        error && selected ? `background-image: repeating-radial-gradient(circle, ${colors.error} 0px, ${colors.error} 3px, transparent 3px, transparent 6px, ${colors.error} 6px, ${colors.error} 8px);` :
+        selected ? `background-image: repeating-radial-gradient(circle, ${colors.blue[500]} 0px, ${colors.blue[500]} 3px, transparent 3px, transparent 6px, ${colors.blue[500]} 6px, ${colors.blue[500]} 8px);` : ""}
+      position: absolute;
+      top: 7px;
+      left: 7px;
+      &:focus,
+      &:active {
+        border-color: ${disabled ? colors.gray[200] : colors.gray[700]};
+      }
+    `,
+    label: css`
+      color: ${colors.white};
+      ${position === "end" ? `margin-left: ${spacing.xs};` :
+        position === "start" ? `margin-right: ${spacing.xs};` :
+        position === "bottom" ? `margin: 0 auto ${spacing.xs};` :
+        position === "top" ? `margin: ${spacing.xs} auto 0;` : ""}
+    `
+  }
+}

+ 32 - 0
packages/components/src/components/RadioButton/RadioButton.tsx

@@ -0,0 +1,32 @@
+import React, { useState } from "react"
+import { makeStyles, RadioButtonStyleProps } from "./RadioButton.style"
+
+type RadioButtonProps = {
+  label?: string
+  onClick?: (e: React.MouseEvent<HTMLDivElement>) => void
+} & RadioButtonStyleProps
+
+export default function RadioButton({
+  label = "",
+  position = "end",
+  disabled = false,
+  onClick,
+  ...styleProps
+}: RadioButtonProps) {
+
+  const styles = makeStyles({ disabled, position, ...styleProps })
+
+  return (
+    <div css={styles.container} onClick={disabled ? null : onClick}>
+      {(position === "start" || position === "top") &&
+        <label css={styles.label}>{label}</label>
+      }
+      <div css={styles.outterDot}>
+        <div css={styles.dot}></div>
+      </div>
+      {(position === "end" || position === "bottom") &&
+        <label css={styles.label}>{label}</label>
+      }
+    </div>
+  )
+}

+ 3 - 0
packages/components/src/components/RadioButton/index.ts

@@ -0,0 +1,3 @@
+import { memo } from "react"
+import RadioButton from "./RadioButton"
+export default memo(RadioButton)

+ 1 - 0
packages/components/src/index.ts

@@ -5,6 +5,7 @@ export { default as Grid } from "./components/Grid"
 export { default as Header } from "./components/Header"
 export { default as Link } from "./components/Link"
 export { default as NavButton } from "./components/NavButton"
+export { default as RadioButton } from "./components/RadioButton"
 export { default as TagButton } from "./components/TagButton"
 export { default as Tabs } from "./components/Tabs"
 export { default as Tab } from "./components/Tabs/Tab"

+ 53 - 4
packages/components/stories/07-Dropdown.stories.tsx

@@ -21,26 +21,75 @@ const options = [
   }
 ]
 
-export const Primary = () => (
+const manyOptions = [
+  {
+    text: "Option 1",
+    value: "1"
+  },
+  {
+    text: "Option 2",
+    value: "2"
+  },
+  {
+    text: "Option 3",
+    value: "3"
+  },
+  {
+    text: "Option 4",
+    value: "4"
+  },
+  {
+    text: "Option 5",
+    value: "5"
+  },
+  {
+    text: "Option 6",
+    value: "6"
+  },
+  {
+    text: "Option 7",
+    value: "7"
+  },
+  {
+    text: "Option 8",
+    value: "8"
+  },
+  {
+    text: "Option 9",
+    value: "9"
+  },
+  {
+    text: "Option 10",
+    value: "10"
+  }
+]
+
+export const Default = () => (
   <div style={{ backgroundColor: "black", padding: "50px 20px" }}>
     <Dropdown label="Label" options={options} />
   </div>
 )
 
-export const PrimaryWithValue = () => (
+export const DefaultWithValue = () => (
   <div style={{ backgroundColor: "black", padding: "50px 20px" }}>
     <Dropdown label="Label" options={options} value={options[1].value} />
   </div>
 )
 
-export const PrimaryFocus = () => (
+export const DefaultFocus = () => (
   <div style={{ backgroundColor: "black", padding: "50px 20px" }}>
     <Dropdown label="Label" options={options} focus={true} />
   </div>
 )
 
-export const PrimaryError = () => (
+export const DefaultError = () => (
   <div style={{ backgroundColor: "black", padding: "50px 20px" }}>
     <Dropdown label="Label" options={options} error={true} />
   </div>
 )
+
+export const DefaultWithManyOptions = () => (
+  <div style={{ backgroundColor: "black", padding: "50px 20px" }}>
+    <Dropdown label="Label" options={manyOptions} />
+  </div>
+)

+ 79 - 0
packages/components/stories/09-RadioButton.stories.tsx

@@ -0,0 +1,79 @@
+import React, { useState } from "react"
+import { RadioButton } from "./../src"
+
+export default {
+  title: "RadioButton",
+  component: RadioButton,
+}
+
+export const Primary = () => {
+  const [isSelected, setIsSelected] = useState(false)
+  return (
+    <div style={{ backgroundColor: "black", padding: "50px 20px" }}>
+      <RadioButton selected={isSelected} onClick={() => setIsSelected(!isSelected)} />
+    </div>
+  )
+}
+
+export const SelectedDisabled = () => {
+  const [isSelected, setIsSelected] = useState(true)
+  return (
+    <div style={{ backgroundColor: "black", padding: "50px 20px" }}>
+      <RadioButton selected={isSelected} disabled={true} onClick={() => setIsSelected(!isSelected)} />
+    </div>
+  )
+}
+
+export const UnselectedDisabled = () => {
+  const [isSelected, setIsSelected] = useState(false)
+  return (
+    <div style={{ backgroundColor: "black", padding: "50px 20px" }}>
+      <RadioButton selected={isSelected} disabled={true} onClick={() => setIsSelected(!isSelected)} />
+    </div>
+  )
+}
+
+export const Error = () => {
+  const [isSelected, setIsSelected] = useState(false)
+  return (
+    <div style={{ backgroundColor: "black", padding: "50px 20px" }}>
+      <RadioButton selected={isSelected} error={true} onClick={() => setIsSelected(!isSelected)} />
+    </div>
+  )
+}
+
+export const WithLabel = () => {
+  const [isSelected, setIsSelected] = useState(false)
+  return (
+    <div style={{ backgroundColor: "black", padding: "50px 20px" }}>
+      <RadioButton label="Label" selected={isSelected} onClick={() => setIsSelected(!isSelected)} />
+    </div>
+  )
+}
+
+export const WithLabelStart = () => {
+  const [isSelected, setIsSelected] = useState(false)
+  return (
+    <div style={{ backgroundColor: "black", padding: "50px 20px" }}>
+      <RadioButton label="Label" position="start" selected={isSelected} onClick={() => setIsSelected(!isSelected)} />
+    </div>
+  )
+}
+
+export const WithLabelBottom = () => {
+  const [isSelected, setIsSelected] = useState(false)
+  return (
+    <div style={{ backgroundColor: "black", padding: "50px 20px" }}>
+      <RadioButton label="A longer label than normal" position="bottom" selected={isSelected} onClick={() => setIsSelected(!isSelected)} />
+    </div>
+  )
+}
+
+export const WithLabelTop = () => {
+  const [isSelected, setIsSelected] = useState(false)
+  return (
+    <div style={{ backgroundColor: "black", padding: "50px 20px" }}>
+      <RadioButton label="A longer label than normal" position="top" selected={isSelected} onClick={() => setIsSelected(!isSelected)} />
+    </div>
+  )
+}