Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions apps/docs/src/stories/Tag.stories.tsx
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

사소하지만 필요하다면 args들에 간단한 description 달아주면 좋을 것 같아요

Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Meta, StoryObj } from '@storybook/react';

import { Tag, TagProps } from '@sopt-makers/ui';
import { IconLocationFilled } from '@sopt-makers/icons';

export default {
title: 'Components/Tag',
Expand All @@ -10,17 +11,29 @@ export default {
size: { control: 'radio', options: ['sm', 'md', 'lg'] },
shape: { control: 'radio', options: ['rect', 'pill'] },
variant: { control: 'radio', options: ['default', 'primary', 'secondary'] },
type: { control: 'radio', options: ['solid', 'line'] },
type: { control: 'radio', options: ['solid', 'line', 'accent'] },
LeftIcon: { control: false },
},
} as Meta<TagProps>;

// 기본 태그 스토리
export const Default: StoryObj<TagProps> = {
args: {
children: 'Default Tag',
size: 'sm',
size: 'lg',
shape: 'rect',
variant: 'default',
type: 'solid',
},
};

// Primary Variant 스토리들
export const LeftIcon: StoryObj<TagProps> = {
args: {
children: 'Tag w Icon',
size: 'lg',
variant: 'primary',
type: 'line',
LeftIcon: IconLocationFilled,
},
};
22 changes: 20 additions & 2 deletions packages/ui/Tag/Tag.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,40 @@
import { forwardRef, type HTMLAttributes } from 'react';
import * as S from './style.css';
import createTagStyle from './utils';
import { iconSizes } from './constants';

interface IconProps {
color?: string;
width: number;
height: number;
}
export interface TagProps extends HTMLAttributes<HTMLDivElement> {
children?: React.ReactNode;
Copy link
Member

@namdaeun namdaeun Dec 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tag 요소 특성상 children 값이 필수로 필요할 거라고 생각해요.
옵셔널로 두는 이유가 있는지 궁금합니다! 개발자의 편의를 고려한 걸까요 ??

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

그냥 이전코드에서 수정되지 않은 부분인 것 같은데 children으로 사용의 확장성을 두기보다는
잘못된 사용을 방지하기 위해 text 를 interface로 받는 게 좋을 것 같다는 의견입니다!
저희 Tag는 왼쪽에 아이콘이 같이 오는 단순 읽기 전용 라벨입니다 (클릭, 포커스가 없는)
그래서 내부에서 잘못된 사용을 방지하기 위해 사용법을 단일화해야하지 않을까? 하는 의견인데 어떻게 생각하시나요?

className?: string;
size?: 'sm' | 'md' | 'lg';
shape?: 'rect' | 'pill';
variant?: 'default' | 'primary' | 'secondary';
type?: 'solid' | 'line';
type?: 'solid' | 'line' | 'accent';
Comment on lines 14 to +17
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

해당 union type은 types.ts에 정의되어 있는 것 같은데 따로 사용하시지 않은 이유가 있을까요??

LeftIcon?: React.ComponentType<IconProps>;
}

export const Tag = forwardRef<HTMLDivElement, TagProps>((props, forwardedRef) => {
const { children, className, size = 'sm', shape = 'rect', variant = 'default', type = 'solid', ...restProps } = props;
const {
children,
className,
size = 'sm',
shape = 'rect',
variant = 'default',
type = 'solid',
LeftIcon,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ComponentType보다는 react node를 받도록하고, 외부에서 icon 요소를 주입하도록 하면 더 좋을 것 같은데, 이와 관해 제약이 있었나요 ?

위와 같이 된다면 prop name은 leftAddon 정도로 하면 좋을 것 같아요.

...restProps
} = props;
const style = createTagStyle(type, variant, shape, size);
const iconSize = iconSizes[size];

return (
<div className={`${S.root} ${style} ${className}`} ref={forwardedRef} {...restProps}>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

text를 받는다면 span 태그를 사용하면 좋을 것 같아요

{LeftIcon ? <LeftIcon height={iconSize} width={iconSize} /> : null}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

leftIcon 값이 없을 때 null을 리턴하는 거면 불필요한 코드를 방지하는 측면에서 &&연산자를 사용해도 좋을 것 같아보여요 !

{children}
</div>
);
Expand Down
27 changes: 22 additions & 5 deletions packages/ui/Tag/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import type {
TagBgColorTheme,
TagShapeTheme,
TagSizeTheme,
TagVariantTheme,
} from "./types";

export const bgColors: Record<TagBgColorTheme, string> = {
Expand All @@ -13,6 +12,9 @@ export const bgColors: Record<TagBgColorTheme, string> = {
"default-line": "unset",
"primary-line": "unset",
"secondary-line": "unset",
"default-accent": theme.colors.gray10,
"primary-accent": theme.colors.secondary,
"secondary-accent": theme.colors.success,
};

export const borders: Record<TagBgColorTheme, string> = {
Expand All @@ -22,12 +24,21 @@ export const borders: Record<TagBgColorTheme, string> = {
"default-line": `0 0 0 1px ${theme.colors.gray300} inset`,
"primary-line": `0 0 0 1px ${theme.colors.orange700} inset`,
"secondary-line": `0 0 0 1px ${theme.colors.blue700} inset`,
"default-accent": "none",
"primary-accent": "none",
"secondary-accent": "none",
};

export const textColors: Record<TagVariantTheme, string> = {
default: theme.colors.gray10,
primary: theme.colors.secondary,
secondary: theme.colors.success,
export const textColors: Record<TagBgColorTheme, string> = {
"default-solid": theme.colors.gray10,
"primary-solid": theme.colors.secondary,
"secondary-solid": theme.colors.success,
"default-line": theme.colors.gray10,
"primary-line": theme.colors.secondary,
"secondary-line": theme.colors.success,
"default-accent": theme.colors.gray950,
"primary-accent": theme.colors.gray950,
"secondary-accent": theme.colors.gray50,
};

export const borderRadiuses: Record<TagShapeTheme, string> = {
Expand All @@ -46,3 +57,9 @@ export const fonts = {
md: theme.fontsObject.LABEL_3_14_SB,
lg: theme.fontsObject.LABEL_2_16_SB,
};

export const iconSizes: Record<TagSizeTheme, number> = {
sm: 14,
md: 16,
lg: 18,
};
24 changes: 9 additions & 15 deletions packages/ui/Tag/style.css.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,14 @@
import { createSprinkles, defineProperties } from "@vanilla-extract/sprinkles";
import { style } from "@vanilla-extract/css";
import {
bgColors,
borderRadiuses,
borders,
fonts,
paddings,
textColors,
} from "./constants";
import { createSprinkles, defineProperties } from '@vanilla-extract/sprinkles';
import { style } from '@vanilla-extract/css';
import { bgColors, borderRadiuses, borders, fonts, paddings, textColors } from './constants';

export const root = style({
display: "flex",
justifyContent: "center",
alignItems: "center",
width: "fit-content",
height: "fit-content",
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
width: 'fit-content',
height: 'fit-content',
gap: '4px',
});

const sprinkleProperties = defineProperties({
Expand Down
2 changes: 1 addition & 1 deletion packages/ui/Tag/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ export type TagShapeTheme = "rect" | "pill";

export type TagVariantTheme = "default" | "primary" | "secondary";

export type TagTypeTheme = "solid" | "line";
export type TagTypeTheme = "solid" | "line" | "accent";

export type TagBgColorTheme = `${TagVariantTheme}-${TagTypeTheme}`;
2 changes: 1 addition & 1 deletion packages/ui/Tag/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ function createTagStyle(
return sprinkles({
backgroundColor: `${variantTheme}-${typeTheme}`,
boxShadow: `${variantTheme}-${typeTheme}`,
color: variantTheme,
color: `${variantTheme}-${typeTheme}`,
borderRadius: shapeTheme,
padding: sizeTheme,
fontStyle: sizeTheme,
Expand Down