Browse Source

RadioButton component.

Pedro Semeano 4 years ago
parent
commit
8934837841

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

@@ -0,0 +1,70 @@
+import { css } from "@emotion/core"
+import { typography, colors, spacing } from "../../theme"
+
+export type RadioButtonStyleProps = {
+  selected?: boolean
+  disabled?: boolean
+  position?: "end" | "start" | "top" | "bottom"
+}
+
+export let makeStyles = ({
+  selected = false,
+  disabled = 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] : 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]};` :
+        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

@@ -3,6 +3,7 @@ export { default as Dropdown } from "./components/Dropdown"
 export { default as Grid } from "./components/Grid"
 export { default as Header } from "./components/Header"
 export { default as NavButton } from "./components/NavButton"
+export { default as RadioButton } from "./components/RadioButton"
 export { default as TagButton } from "./components/TagButton"
 export { default as Tag } from "./components/Tag"
 export { default as TextField } from "./components/TextField"

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

@@ -0,0 +1,70 @@
+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 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>
+  )
+}