Browse Source

Radio Button Refactor

Francesco Baccetti 4 years ago
parent
commit
3e6c82e57e

+ 37 - 33
packages/components/src/components/Button/Button.style.ts

@@ -1,15 +1,15 @@
-import { typography, colors } from "../../theme";
-import { makeStyles, StyleFn, StyleObj } from "../../utils";
-import { disabled, dimensionsFromProps, log } from "../../theme/fragments";
+import { typography, colors } from "../../theme"
+import { makeStyles, StyleFn } from "../../utils"
+import { disabled, dimensionsFromProps, log } from "../../theme/fragments"
 
 export type ButtonStyleProps = {
-	text?: string;
-	type?: "primary" | "secondary";
-	full?: boolean;
-	size?: "regular" | "small" | "smaller";
-	children?: React.ReactNode;
-	disabled?: boolean;
-};
+	text?: string
+	type?: "primary" | "secondary"
+	full?: boolean
+	size?: "regular" | "small" | "smaller"
+	children?: React.ReactNode
+	disabled?: boolean
+}
 
 const baseStyles: StyleFn = () => ({
 	borderWidth: "1px",
@@ -21,9 +21,9 @@ const baseStyles: StyleFn = () => ({
 	alignItems: "center",
 	color: colors.white,
 	"&::selected": {
-		background: "transparent",
-	},
-});
+		background: "transparent"
+	}
+})
 const colorFromType: StyleFn = (styles, { type }: ButtonStyleProps) => {
 	switch (type) {
 		case "primary":
@@ -35,14 +35,14 @@ const colorFromType: StyleFn = (styles, { type }: ButtonStyleProps) => {
 				"&:hover": {
 					backgroundColor: colors.blue[700],
 					borderColor: colors.blue[700],
-					color: colors.white,
+					color: colors.white
 				},
 				"&:active": {
 					backgroundColor: colors.blue[900],
 					borderColor: colors.blue[900],
-					color: colors.white,
-				},
-			};
+					color: colors.white
+				}
+			}
 
 		case "secondary":
 			return {
@@ -53,21 +53,25 @@ const colorFromType: StyleFn = (styles, { type }: ButtonStyleProps) => {
 
 				"&:hover": {
 					borderColor: colors.blue[700],
-					color: colors.blue[300],
+					color: colors.blue[300]
 				},
 
 				"&:active": {
 					borderColor: colors.blue[700],
-					color: colors.blue[700],
-				},
-			};
+					color: colors.blue[700]
+				}
+			}
 	}
-};
+}
 const paddingFromType: StyleFn = (
 	styles,
-	{ size, children, full }: { size: "regular" | "small" | "smaller"; children?: React.ReactNode; full: boolean }
+	{
+		size = "regular",
+		children,
+		full
+	}: { size: "regular" | "small" | "smaller"; children?: React.ReactNode; full: boolean }
 ) => {
-	const buttonHeight = size === "regular" ? "20px" : size === "small" ? "15px" : "10px";
+	const buttonHeight = size === "regular" ? "20px" : size === "small" ? "15px" : "10px"
 	return {
 		...styles,
 		margin: `0 ${full ? "0" : "15px"} 0 0`,
@@ -89,9 +93,9 @@ const paddingFromType: StyleFn = (
 				: typography.sizes.button.small,
 
 		height: buttonHeight,
-		maxHeight: buttonHeight,
-	};
-};
+		maxHeight: buttonHeight
+	}
+}
 
 const iconStyles: StyleFn = (styles, { children, size }) => {
 	return {
@@ -106,15 +110,15 @@ const iconStyles: StyleFn = (styles, { children, size }) => {
 
 		flexShrink: 0,
 		"& > *": {
-			stroke: "currentColor",
-		},
-	};
-};
+			stroke: "currentColor"
+		}
+	}
+}
 
 export const useCSS = (props: ButtonStyleProps) => ({
 	container: makeStyles([baseStyles, colorFromType, dimensionsFromProps, paddingFromType, disabled])(props),
-	icon: makeStyles([iconStyles])(props),
-});
+	icon: makeStyles([iconStyles])(props)
+})
 
 // 	text,
 // 	type = "primary",

+ 0 - 0
packages/components/src/components/Checkbox/Checkbox.style.ts


+ 0 - 0
packages/components/src/components/Checkbox/Checkbox.tsx


+ 2 - 0
packages/components/src/components/Checkbox/index.ts

@@ -0,0 +1,2 @@
+import Checkbox from "./Checkbox"
+export default Checkbox

+ 107 - 67
packages/components/src/components/RadioButton/RadioButton.style.ts

@@ -1,74 +1,114 @@
-import { css } from "@emotion/core"
+import { StyleFn, makeStyles } from "../../utils"
 import { typography, colors, spacing } from "../../theme"
 
 export type RadioButtonStyleProps = {
-  selected?: boolean
-  disabled?: boolean
-  error?: boolean
-  position?: "end" | "start" | "top" | "bottom"
+	selected?: boolean
+	disabled?: boolean
+	error?: boolean
+	position?: "end" | "start" | "top" | "bottom"
 }
+const container: StyleFn = (_, { position }) => ({
+	fontFamily: typography.fonts.base,
+	display: position === "bottom" || position === "bottom" ? "inline-block" : "inline-flex",
+	alignItems: "center",
+	"&:focus": {
+		outline: "none"
+	}
+})
 
-export let makeStyles = ({
-  selected = false,
-  disabled = false,
-  error = false,
-  position = "end"
-}: RadioButtonStyleProps) => {
+const outerDot: StyleFn = (_, { position, disabled }) => ({
+	width: spacing.xxl,
+	height: spacing.xxl,
+	borderRadius: "50%",
+	position: "relative",
+	margin: position === "bottom" ? `0 auto ${spacing.xs}` : position === "top" ? `${spacing.xs} auto 0` : "",
+	"&:hover": {
+		backgroundColor: disabled ? "none" : colors.gray[50]
+	},
+	"&:active": {
+		backgroundColor: disabled ? "none" : colors.gray[100]
+	},
+	"&:focus": {
+		backgroundColor: disabled ? "none" : colors.blue[100],
+		outline: "none"
+	}
+})
+
+const dot: StyleFn = (_, { disabled, selected, error }) => {
+	return {
+		width: spacing.m,
+		height: spacing.m,
+		borderWidth: 1,
+		borderColor: disabled
+			? colors.gray[200]
+			: error
+			? colors.error
+			: selected
+			? colors.blue[500]
+			: colors.gray[300],
+		borderStyle: "solid",
+		borderRadius: "50%",
+		position: "absolute",
+		top: "7px",
+		left: "7px",
+		"&:focus": {
+			borderColor: disabled ? colors.gray[200] : colors.gray[700]
+		},
+		"&:active": {
+			borderColor: disabled ? colors.gray[200] : colors.gray[700]
+		}
+	}
+}
+
+const BackgroundFromProps: StyleFn = (styles, { disabled, selected, error }) => {
+	let key = selected ? `backgroundImage` : `backgroundColor`
+	const SELECTED_ERROR = `repeating-radial-gradient(circle, ${colors.error} 0px, ${colors.error} 3px, transparent 3px, transparent 6px, ${colors.error} 6px, ${colors.error} 8px)`
+	const SELECTED_DISABLED = `repeating-radial-gradient(circle, ${colors.gray[200]} 0px, ${colors.gray[200]} 3px, transparent 3px, transparent 6px, ${colors.gray[200]} 6px, ${colors.gray[200]} 8px)`
+	const SELECTED_DEFAULT = `repeating-radial-gradient(circle, ${colors.blue[500]} 0px, ${colors.blue[500]} 3px, transparent 3px, transparent 6px, ${colors.blue[500]} 6px, ${colors.blue[500]} 8px)`
+	const UNSELECTED_DISABLED = colors.gray[50]
+
+	let value =
+		selected && error
+			? SELECTED_ERROR
+			: selected && disabled
+			? SELECTED_DISABLED
+			: selected
+			? SELECTED_DEFAULT
+			: disabled
+			? UNSELECTED_DISABLED
+			: styles[key]
+	return {
+		...styles,
+		[key]: value
+	}
+}
+
+const label: StyleFn = (_, { position }) => {
+	const key = position === "end" ? "margin-left" : position === "start" ? "margin-right" : "margin"
+	const value =
+		key === "margin-left" || key === "margin-right"
+			? spacing.xs
+			: position === "bottom"
+			? `0 auto ${spacing.xs}`
+			: `${spacing.xs} auto 0`
 
-  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;` : ""}
-    `
-  }
+	return {
+		color: colors.white,
+		[key]: value
+	}
+}
+
+export const useCSS = ({
+	selected = false,
+	disabled = false,
+	error = false,
+	position = "end"
+}: RadioButtonStyleProps) => {
+	const props = { selected, disabled, error, position }
+	return {
+		container: makeStyles([container])(props),
+		outterDot: makeStyles([outerDot])(props),
+		dot: makeStyles([dot, BackgroundFromProps])(props),
+		label: makeStyles([label])(props)
+	}
 }

+ 20 - 25
packages/components/src/components/RadioButton/RadioButton.tsx

@@ -1,32 +1,27 @@
-import React, { useState } from "react"
-import { makeStyles, RadioButtonStyleProps } from "./RadioButton.style"
+import React, { useState } from "react";
+import { useCSS, RadioButtonStyleProps } from "./RadioButton.style";
 
 type RadioButtonProps = {
-  label?: string
-  onClick?: (e: React.MouseEvent<HTMLDivElement>) => void
-} & RadioButtonStyleProps
+	label?: string;
+	onClick?: (e: React.MouseEvent<HTMLDivElement>) => void;
+} & RadioButtonStyleProps;
 
 export default function RadioButton({
-  label = "",
-  position = "end",
-  disabled = false,
-  onClick,
-  ...styleProps
+	label = "",
+	position = "end",
+	disabled = false,
+	onClick,
+	...styleProps
 }: RadioButtonProps) {
+	const styles = useCSS({ disabled, position, ...styleProps });
 
-  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>
-  )
+	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>
+	);
 }

+ 1 - 1
packages/components/src/components/Tabs/Tab.tsx

@@ -5,7 +5,7 @@ type TabProps = {
 	children: ReactNode;
 };
 
-//FIXME: Actually add markup for the tab
+// FIXME: This looks incomplete
 export default function Tab({ label, children }: TabProps) {
 	// let styles = makeStyles(styleProps)
 

+ 28 - 36
packages/components/src/components/Tabs/Tabs.tsx

@@ -1,43 +1,35 @@
-import React, { useState } from "react"
-import { makeStyles, TabsStyleProps } from "./Tabs.style"
+import React, { useState } from "react";
+import { useCSS, TabsStyleProps } from "./Tabs.style";
 
 type TabsProps = {
-  children: Array<React.ReactNode>,
-  onChange?: (tab: string) => void
-} & TabsStyleProps
+	children: Array<React.ReactNode>;
+	onChange?: (tab: string) => void;
+} & TabsStyleProps;
 
-export default function Tabs({
-  children,
-  onChange,
-  ...styleProps
-}: TabsProps) {
+export default function Tabs({ children, onChange, ...styleProps }: TabsProps) {
+	const [activeTab, setActiveTab] = useState(0);
 
-  const [activeTab, setActiveTab] = useState(0)
+	function onTabChange(tab: any): void {
+		setActiveTab(tab);
+		onChange(tab);
+	}
 
-  function onTabChange(tab: any): void {
-    setActiveTab(tab)
-    onChange(tab)
-  }
+	let styles = useCSS(styleProps);
 
-  let styles = makeStyles(styleProps)
-
-  return (
-    <div css={styles.container}>
-      <div css={styles.tabs}>
-        {children.map((tab: any, index: any) => 
-        <div
-          key={`tab-${index}`}
-          css={index === activeTab ? styles.activeTab : styles.tab}
-          onClick={() => onTabChange(index)}
-        >
-          {tab.props.label}
-        </div>)}
-      </div>
-      <div>
-        {children
-          .filter((tab: any, index: any) => index === activeTab)
-          .map((tab: any) => tab)}
-      </div>
-    </div>
-  )
+	return (
+		<div css={styles.container}>
+			<div css={styles.tabs}>
+				{children.map((tab: any, index: any) => (
+					<div
+						key={`tab-${index}`}
+						css={index === activeTab ? styles.activeTab : styles.tab}
+						onClick={() => onTabChange(index)}
+					>
+						{tab.props.label}
+					</div>
+				))}
+			</div>
+			<div>{children.filter((tab: any, index: any) => index === activeTab).map((tab: any) => tab)}</div>
+		</div>
+	);
 }