diff --git a/.changeset/real-gorillas-camp.md b/.changeset/real-gorillas-camp.md new file mode 100644 index 00000000..e16b0acc --- /dev/null +++ b/.changeset/real-gorillas-camp.md @@ -0,0 +1,7 @@ +--- +"wowds-tokens": patch +"wowds-theme": patch +"wowds-ui": patch +--- + +Tag 컴포넌트를 구현합니다. diff --git a/apps/wow-docs/styled-system/tokens/index.js b/apps/wow-docs/styled-system/tokens/index.js index b7ff2bf8..930662c7 100644 --- a/apps/wow-docs/styled-system/tokens/index.js +++ b/apps/wow-docs/styled-system/tokens/index.js @@ -475,6 +475,30 @@ const tokens = { value: "#000000", variable: "var(--colors-github)", }, + "colors.secondaryYellow": { + value: "#F9AB00", + variable: "var(--colors-secondary-yellow)", + }, + "colors.secondaryGreen": { + value: "#34A853", + variable: "var(--colors-secondary-green)", + }, + "colors.secondaryRed": { + value: "#EA4335", + variable: "var(--colors-secondary-red)", + }, + "colors.errorBackground": { + value: "#FBD9D7", + variable: "var(--colors-error-background)", + }, + "colors.blueDisabled": { + value: "#D7E9FD", + variable: "var(--colors-blue-disabled)", + }, + "colors.textBlueDisabled": { + value: "#AFD2FC", + variable: "var(--colors-text-blue-disabled)", + }, "spacing.-xxs": { value: "calc(var(--spacing-xxs) * -1)", variable: "var(--spacing-xxs)", diff --git a/apps/wow-docs/styled-system/tokens/tokens.d.ts b/apps/wow-docs/styled-system/tokens/tokens.d.ts index 33715555..24b9c593 100644 --- a/apps/wow-docs/styled-system/tokens/tokens.d.ts +++ b/apps/wow-docs/styled-system/tokens/tokens.d.ts @@ -119,6 +119,12 @@ export type Token = | "colors.blueShadow" | "colors.discord" | "colors.github" + | "colors.secondaryYellow" + | "colors.secondaryGreen" + | "colors.secondaryRed" + | "colors.errorBackground" + | "colors.blueDisabled" + | "colors.textBlueDisabled" | "spacing.-xxs" | "spacing.-xs" | "spacing.-sm" @@ -170,7 +176,13 @@ export type ColorPalette = | "shadowMedium" | "blueShadow" | "discord" - | "github"; + | "github" + | "secondaryYellow" + | "secondaryGreen" + | "secondaryRed" + | "errorBackground" + | "blueDisabled" + | "textBlueDisabled"; export type ColorToken = | "red.50" @@ -262,6 +274,12 @@ export type ColorToken = | "blueShadow" | "discord" | "github" + | "secondaryYellow" + | "secondaryGreen" + | "secondaryRed" + | "errorBackground" + | "blueDisabled" + | "textBlueDisabled" | "colorPalette.50" | "colorPalette.100" | "colorPalette.150" diff --git a/apps/wow-docs/styled-system/types/prop-type.d.ts b/apps/wow-docs/styled-system/types/prop-type.d.ts index 796e22e9..f5b289d2 100644 --- a/apps/wow-docs/styled-system/types/prop-type.d.ts +++ b/apps/wow-docs/styled-system/types/prop-type.d.ts @@ -660,7 +660,13 @@ export interface UtilityValues { | "shadowMedium" | "blueShadow" | "discord" - | "github"; + | "github" + | "secondaryYellow" + | "secondaryGreen" + | "secondaryRed" + | "errorBackground" + | "blueDisabled" + | "textBlueDisabled"; textStyle: | "display1" | "display2" diff --git a/packages/wow-theme/src/config/colorTokenList.ts b/packages/wow-theme/src/config/colorTokenList.ts index 4d7b12dd..1eafb762 100644 --- a/packages/wow-theme/src/config/colorTokenList.ts +++ b/packages/wow-theme/src/config/colorTokenList.ts @@ -80,12 +80,15 @@ export const colorTokenList = [ "backgroundNormal", "backgroundAlternative", "backgroundDimmer", + "errorBackground", "sub", "outline", "textBlack", "textWhite", "darkDisabled", "lightDisabled", + "blueDisabled", + "textBlueDisabled", "blueHover", "monoHover", "elevatedHover", @@ -97,6 +100,9 @@ export const colorTokenList = [ "blueShadow", "discord", "github", + "secondaryYellow", + "secondaryGreen", + "secondaryRed", "blueGradientDark", "blueGradientLight", "redGradientDark", diff --git a/packages/wow-theme/src/tokens/color.ts b/packages/wow-theme/src/tokens/color.ts index 059850fc..b1b656f7 100644 --- a/packages/wow-theme/src/tokens/color.ts +++ b/packages/wow-theme/src/tokens/color.ts @@ -105,6 +105,12 @@ export const semanticTokens = defineSemanticTokens({ blueShadow: { value: color.blueShadow }, discord: { value: color.discord }, github: { value: color.github }, + secondaryYellow: { value: color.secondaryYellow }, + secondaryGreen: { value: color.secondaryGreen }, + secondaryRed: { value: color.secondaryRed }, + errorBackground: { value: color.errorBackground }, + blueDisabled: { value: color.blueDisabled }, + textBlueDisabled: { value: color.textBlueDisabled }, }, }); diff --git a/packages/wow-tokens/src/color.ts b/packages/wow-tokens/src/color.ts index bc62adf9..67c3acb6 100644 --- a/packages/wow-tokens/src/color.ts +++ b/packages/wow-tokens/src/color.ts @@ -96,6 +96,7 @@ export const error = red600; export const backgroundNormal = white; export const backgroundAlternative = mono50; export const backgroundDimmer = blackOpacity80; +export const errorBackground = red100; export const sub = mono700; export const outline = mono400; @@ -104,10 +105,11 @@ export const textWhite = white; export const darkDisabled = mono400; export const lightDisabled = mono200; +export const blueDisabled = blue100; +export const textBlueDisabled = blue200; export const blueHover = blue600; export const monoHover = mono950; - export const elevatedHover = "rgba(16, 43, 74, 0.2)"; export const bluePressed = blue400; @@ -121,6 +123,10 @@ export const blueShadow = "rgba(16, 43, 74, 0.2)"; export const discord = "#5566FB"; export const github = black; +export const secondaryYellow = yellow500; +export const secondaryGreen = green500; +export const secondaryRed = red500; + export const blueGradientDark = { gradientFrom: blue500, gradientTo: blue700, diff --git a/packages/wow-ui/package.json b/packages/wow-ui/package.json index b9fe6fe5..7d4cc58e 100644 --- a/packages/wow-ui/package.json +++ b/packages/wow-ui/package.json @@ -30,6 +30,11 @@ "require": "./dist/TextButton.cjs", "import": "./dist/TextButton.js" }, + "./Tag": { + "types": "./dist/components/Tag/index.d.ts", + "require": "./dist/Tag.cjs", + "import": "./dist/Tag.js" + }, "./Switch": { "types": "./dist/components/Switch/index.d.ts", "require": "./dist/Switch.cjs", @@ -147,6 +152,7 @@ "typescript": "^5.3.3" }, "dependencies": { + "clsx": "^2.1.1", "lottie-react": "^2.4.0", "wowds-icons": "workspace:^" }, diff --git a/packages/wow-ui/rollup.config.js b/packages/wow-ui/rollup.config.js index b12cc0eb..f03811d6 100644 --- a/packages/wow-ui/rollup.config.js +++ b/packages/wow-ui/rollup.config.js @@ -22,6 +22,7 @@ export default { input: { TextField: "./src/components/TextField", TextButton: "./src/components/TextButton", + Tag: "./src/components/Tag", Switch: "./src/components/Switch", Stepper: "./src/components/Stepper", BlueSpinner: "./src/components/Spinner/BlueSpinner", diff --git a/packages/wow-ui/src/components/Tag/Tag.stories.tsx b/packages/wow-ui/src/components/Tag/Tag.stories.tsx new file mode 100644 index 00000000..cd0c88b2 --- /dev/null +++ b/packages/wow-ui/src/components/Tag/Tag.stories.tsx @@ -0,0 +1,91 @@ +import type { Meta, StoryObj } from "@storybook/react"; + +import Tag from "@/components/Tag"; + +const meta = { + title: "UI/Tag", + component: Tag, + tags: ["autodocs"], + parameters: { + componentSubtitle: "태그 컴포넌트", + a11y: { + config: { + rules: [{ id: "color-contrast", enabled: false }], + }, + }, + }, + argTypes: { + children: { + description: "태그의 자식 요소.", + table: { + type: { summary: "ReactNode" }, + }, + control: { + type: "text", + }, + }, + variant: { + description: "태그의 종류를 나타냅니다.", + table: { + type: { summary: "outline | solid1 | solid2" }, + defaultValue: { summary: "outline" }, + }, + control: { + type: "radio", + options: ["outline", "solid1", "solid2"], + }, + }, + color: { + description: "태그의 색상을 나타냅니다.", + table: { + type: { summary: "red | blue | green | yellow | grey" }, + }, + control: { + type: "radio", + options: ["red", "blue", "green", "yellow", "grey"], + }, + }, + style: { + description: "태그의 커스텀 스타일을 나타냅니다.", + table: { + type: { summary: "CSSProperties" }, + }, + control: false, + }, + className: { + description: "태그에 전달하는 커스텀 클래스를 나타냅니다.", + table: { + type: { summary: "string" }, + }, + control: false, + }, + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +export const Outline: Story = { + args: { + children: "Tag", + variant: "outline", + color: "blue", + }, +}; + +export const Solid1: Story = { + args: { + children: "Tag", + variant: "solid1", + color: "blue", + }, +}; + +export const Solid2: Story = { + args: { + children: "Tag", + variant: "solid2", + color: "blue", + }, +}; diff --git a/packages/wow-ui/src/components/Tag/index.tsx b/packages/wow-ui/src/components/Tag/index.tsx new file mode 100644 index 00000000..e2ecb259 --- /dev/null +++ b/packages/wow-ui/src/components/Tag/index.tsx @@ -0,0 +1,131 @@ +"use client"; + +import { cva } from "@styled-system/css/cva"; +import { styled } from "@styled-system/jsx"; +import { clsx } from "clsx"; +import type { HTMLAttributes, PropsWithChildren } from "react"; +import { forwardRef } from "react"; + +type Variant = "outline" | "solid1" | "solid2"; + +type OutlineColors = "red" | "blue" | "green" | "yellow"; +type Solid1Colors = "blue" | "yellow" | "green"; +type Solid2Colors = "blue" | "red" | "grey"; + +type VariantColorMap = { + outline: OutlineColors; + solid1: Solid1Colors; + solid2: Solid2Colors; +}; + +export interface BaseTagProps + extends HTMLAttributes, + PropsWithChildren {} + +/** + * @description 태그 컴포넌트의 속성을 정의합니다. + * + * @param {ReactNode} children - 태그의 자식 요소. + * @param {"outline" | "solid1" | 'solid2'} [variant] - 태그의 종류. + * @param {"red" | "blue" | "green" | "yellow" | "grey"} [color] - 태그의 색상. + * @param {ComponentPropsWithoutRef} rest 렌더링된 요소 또는 컴포넌트에 전달할 추가 props. + * @param {ComponentPropsWithRef["ref"]} ref 렌더링된 요소 또는 컴포넌트에 연결할 ref. + */ + +type TagProps = BaseTagProps & { + variant: Variant; + color: VariantColorMap[Variant]; +}; + +const Tag = forwardRef( + ( + { children, variant = "outline", color = "blue", className, ...rest }, + ref + ) => { + return ( + + {children} + + ); + } +); + +const TagStyle = cva({ + base: { + display: "flex", + alignItems: "center", + justifyContent: "center", + paddingX: "xs", + paddingY: "xxs", + borderRadius: "sm", + width: "fit-content", + border: "1px solid", + textStyle: "label2", + }, + variants: { + variant: { + outline: { + backgroundColor: "backgroundNormal", + }, + solid1: { + border: "none", + backgroundColor: "monoBackgroundPressed", + }, + solid2: { + border: "none", + }, + }, + color: { + red: { + borderColor: "secondaryRed", + color: "secondaryRed", + }, + green: { + borderColor: "secondaryGreen", + color: "secondaryGreen", + }, + blue: { + borderColor: "primary", + color: "primary", + }, + yellow: { + borderColor: "secondaryYellow", + color: "secondaryYellow", + }, + grey: {}, + }, + }, + compoundVariants: [ + { + variant: "solid2", + color: "blue", + css: { + backgroundColor: "blueDisabled", + color: "blueHover", + }, + }, + { + variant: "solid2", + color: "red", + css: { + backgroundColor: "errorBackground", + color: "error", + }, + }, + { + variant: "solid2", + color: "grey", + css: { + backgroundColor: "monoBackgroundPressed", + color: "sub", + }, + }, + ], +}); + +Tag.displayName = "Tag"; +export default Tag; diff --git a/packages/wow-ui/styled-system/tokens/index.js b/packages/wow-ui/styled-system/tokens/index.js index b7ff2bf8..930662c7 100644 --- a/packages/wow-ui/styled-system/tokens/index.js +++ b/packages/wow-ui/styled-system/tokens/index.js @@ -475,6 +475,30 @@ const tokens = { value: "#000000", variable: "var(--colors-github)", }, + "colors.secondaryYellow": { + value: "#F9AB00", + variable: "var(--colors-secondary-yellow)", + }, + "colors.secondaryGreen": { + value: "#34A853", + variable: "var(--colors-secondary-green)", + }, + "colors.secondaryRed": { + value: "#EA4335", + variable: "var(--colors-secondary-red)", + }, + "colors.errorBackground": { + value: "#FBD9D7", + variable: "var(--colors-error-background)", + }, + "colors.blueDisabled": { + value: "#D7E9FD", + variable: "var(--colors-blue-disabled)", + }, + "colors.textBlueDisabled": { + value: "#AFD2FC", + variable: "var(--colors-text-blue-disabled)", + }, "spacing.-xxs": { value: "calc(var(--spacing-xxs) * -1)", variable: "var(--spacing-xxs)", diff --git a/packages/wow-ui/styled-system/tokens/tokens.d.ts b/packages/wow-ui/styled-system/tokens/tokens.d.ts index 33715555..24b9c593 100644 --- a/packages/wow-ui/styled-system/tokens/tokens.d.ts +++ b/packages/wow-ui/styled-system/tokens/tokens.d.ts @@ -119,6 +119,12 @@ export type Token = | "colors.blueShadow" | "colors.discord" | "colors.github" + | "colors.secondaryYellow" + | "colors.secondaryGreen" + | "colors.secondaryRed" + | "colors.errorBackground" + | "colors.blueDisabled" + | "colors.textBlueDisabled" | "spacing.-xxs" | "spacing.-xs" | "spacing.-sm" @@ -170,7 +176,13 @@ export type ColorPalette = | "shadowMedium" | "blueShadow" | "discord" - | "github"; + | "github" + | "secondaryYellow" + | "secondaryGreen" + | "secondaryRed" + | "errorBackground" + | "blueDisabled" + | "textBlueDisabled"; export type ColorToken = | "red.50" @@ -262,6 +274,12 @@ export type ColorToken = | "blueShadow" | "discord" | "github" + | "secondaryYellow" + | "secondaryGreen" + | "secondaryRed" + | "errorBackground" + | "blueDisabled" + | "textBlueDisabled" | "colorPalette.50" | "colorPalette.100" | "colorPalette.150" diff --git a/packages/wow-ui/styled-system/types/prop-type.d.ts b/packages/wow-ui/styled-system/types/prop-type.d.ts index 796e22e9..f5b289d2 100644 --- a/packages/wow-ui/styled-system/types/prop-type.d.ts +++ b/packages/wow-ui/styled-system/types/prop-type.d.ts @@ -660,7 +660,13 @@ export interface UtilityValues { | "shadowMedium" | "blueShadow" | "discord" - | "github"; + | "github" + | "secondaryYellow" + | "secondaryGreen" + | "secondaryRed" + | "errorBackground" + | "blueDisabled" + | "textBlueDisabled"; textStyle: | "display1" | "display2" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 94bca27c..e3f8310b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -255,6 +255,9 @@ importers: packages/wow-ui: dependencies: + clsx: + specifier: ^2.1.1 + version: 2.1.1 lottie-react: specifier: ^2.4.0 version: 2.4.0(react-dom@18.2.0)(react@18.2.0) @@ -7197,6 +7200,11 @@ packages: engines: {node: '>=0.8'} dev: true + /clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} + dev: false + /co@4.6.0: resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'}