From db44ce0f2435ee9bda9cdf05c54b5fdfe9e4e76e Mon Sep 17 00:00:00 2001 From: Wonsuk Choi Date: Thu, 22 Aug 2024 17:00:15 +0900 Subject: [PATCH] =?UTF-8?q?feat(ui/components):=20Checkbox=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20(#326)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(ui/icons): CheckIcon 추가 * feat(ui/components): Checkbox 추가 --- .../src/components/checkbox/checkbox.css.ts | 100 ++++++++++++++++++ .../ui/src/components/checkbox/checkbox.tsx | 42 ++++++++ packages/ui/src/components/checkbox/index.ts | 4 +- packages/ui/src/icons/check.tsx | 10 ++ packages/ui/src/icons/index.ts | 1 + 5 files changed, 156 insertions(+), 1 deletion(-) create mode 100644 packages/ui/src/components/checkbox/checkbox.css.ts create mode 100644 packages/ui/src/components/checkbox/checkbox.tsx create mode 100644 packages/ui/src/icons/check.tsx diff --git a/packages/ui/src/components/checkbox/checkbox.css.ts b/packages/ui/src/components/checkbox/checkbox.css.ts new file mode 100644 index 0000000..163b55e --- /dev/null +++ b/packages/ui/src/components/checkbox/checkbox.css.ts @@ -0,0 +1,100 @@ +import { + createGlobalThemeContract, + createTheme, + style, + styleVariants, +} from '@vanilla-extract/css'; +import { calc } from '@vanilla-extract/css-utils'; +import { type RecipeVariants, recipe } from '@vanilla-extract/recipes'; +import { alignItems, display, justifyContent } from '../../styles'; +import { globalVars, paletteTokens } from '../../theme.css'; + +const color = styleVariants(paletteTokens, (_, paletteTokenKey) => ({ + backgroundColor: globalVars.palette[paletteTokenKey], +})); + +const borderColor = styleVariants(paletteTokens, (_, paletteTokenKey) => ({ + borderColor: globalVars.palette[paletteTokenKey], +})); + +const sizeTokens = { + '1': '1', + '2': '2', + '3': '3', +}; + +const sizeVars = createGlobalThemeContract( + sizeTokens, + (value) => `favolink-checkbox-size-${value}`, +); + +const sizeClass = createTheme(sizeVars, { + '1': '16px', + '2': '24px', + '3': '32px', +}); + +const borderSizeVars = createGlobalThemeContract( + sizeTokens, + (value) => `favolink-checkbox-border-size-${value}`, +); + +const borderSizeClass = createTheme(borderSizeVars, { + '1': '1px', + '2': '1.5px', + '3': '2px', +}); + +const size = styleVariants(sizeVars, (_, sizeKey) => ({ + width: sizeVars[sizeKey], + height: sizeVars[sizeKey], + borderWidth: calc.multiply(borderSizeVars[sizeKey], 1.75), + borderRadius: calc.multiply(borderSizeVars[sizeKey], 3), +})); + +const base = style([ + sizeClass, + borderSizeClass, + display['inline-flex'], + alignItems.center, + justifyContent.center, + { + boxSizing: 'border-box', + padding: 0, + borderColor: globalVars.palette.gray800, + borderStyle: 'solid', + + selectors: { + '&[data-state="false"]': { + backgroundColor: 'transparent', + }, + }, + }, +]); + +export const checkboxVariants = recipe({ + base, + + variants: { + color, + borderColor, + size, + }, + + defaultVariants: { + color: 'black', + borderColor: 'gray700', + size: '1', + }, +}); + +export type CheckboxVariants = Exclude< + RecipeVariants, + undefined +>; + +export const icon = style({ + width: '100%', + height: '100%', + color: globalVars.palette.white, +}); diff --git a/packages/ui/src/components/checkbox/checkbox.tsx b/packages/ui/src/components/checkbox/checkbox.tsx new file mode 100644 index 0000000..d9bf8bd --- /dev/null +++ b/packages/ui/src/components/checkbox/checkbox.tsx @@ -0,0 +1,42 @@ +import * as Styles from './checkbox.css'; +import * as CheckboxPrimitive from './checkbox.primitive'; +import { CheckIcon } from '../../icons'; +import { type ComponentPropsWithout, forwardRef } from '../../system'; +import { cx } from '../../utils'; +import { type MarginVariants, extractMarginProps } from '../margin'; + +export type CheckboxProps = ComponentPropsWithout< + typeof CheckboxPrimitive.Root, + 'asChild' | 'children' | 'color' | 'defaultValue' +> & + MarginVariants & + Styles.CheckboxVariants; + +export const Checkbox = forwardRef< + CheckboxProps, + typeof CheckboxPrimitive.Root +>(function Checkbox(props, forwardedRef) { + const { className, color, borderColor, size, ...restProps } = + extractMarginProps(props); + + return ( + + + + + + ); +}); + +Checkbox.displayName = 'Checkbox'; diff --git a/packages/ui/src/components/checkbox/index.ts b/packages/ui/src/components/checkbox/index.ts index 24486f6..01f4784 100644 --- a/packages/ui/src/components/checkbox/index.ts +++ b/packages/ui/src/components/checkbox/index.ts @@ -1,2 +1,4 @@ -/* eslint-disable @stylistic/padding-line-between-statements, react-refresh/only-export-components */ +/* eslint-disable @stylistic/padding-line-between-statements */ export * as CheckboxPrimitive from './checkbox.primitive'; + +export { Checkbox, type CheckboxProps } from './checkbox'; diff --git a/packages/ui/src/icons/check.tsx b/packages/ui/src/icons/check.tsx new file mode 100644 index 0000000..36d457e --- /dev/null +++ b/packages/ui/src/icons/check.tsx @@ -0,0 +1,10 @@ +import { createIcon } from './icon'; + +export const CheckIcon = createIcon({ + defaultProps: { + width: '1em', + height: '1em', + fill: 'currentColor', + }, + d: 'M8.33268 11.6045L13.416 6.52116C13.5688 6.36838 13.7459 6.29199 13.9473 6.29199C14.1487 6.29199 14.3257 6.36838 14.4785 6.52116C14.6313 6.67394 14.7077 6.85102 14.7077 7.05241C14.7077 7.2538 14.6313 7.43088 14.4785 7.58366L8.85352 13.2087C8.70074 13.3614 8.52365 13.4378 8.32227 13.4378C8.12088 13.4378 7.94379 13.3614 7.79102 13.2087L5.52018 10.9378C5.3674 10.785 5.29102 10.608 5.29102 10.4066C5.29102 10.2052 5.3674 10.0281 5.52018 9.87533C5.67296 9.72255 5.85004 9.64616 6.05143 9.64616C6.25282 9.64616 6.4299 9.72255 6.58268 9.87533L8.33268 11.6045Z', +}); diff --git a/packages/ui/src/icons/index.ts b/packages/ui/src/icons/index.ts index fb4fee4..0302af3 100644 --- a/packages/ui/src/icons/index.ts +++ b/packages/ui/src/icons/index.ts @@ -2,6 +2,7 @@ export * from './add'; export * from './bell'; export * from './cancel'; +export * from './check'; export * from './chevron-down'; export * from './chevron-left'; export * from './chevron-right';