์ฌ์ฌ์ฉ ๊ฐ๋ฅํ UI ์ปดํฌ๋ํธ๋ฅผ ๋ฐฐํฌํ๋ ๊ณผ์ ์ ๊ธฐ๋กํฉ๋๋ค.
2 ์ผ์ฐจ
-
const ๋จ์ธ์ผ๋ก ์์ ๊ด๋ฆฌ
Color๊ฐ์ฒด๋ฅผ ์ ์ํ ๋ TypeScript์ as const๋ฅผ ์ฌ์ฉํ์ฌ ๋ชจ๋ ํ๋๋ฅผ ๋ฆฌํฐ๋ด ํ์ ์ผ๋ก ์ ์ธํ๋ฉด, ์ฝ๊ธฐ ์ ์ฉ์ผ๋ก ํ์ ์ด ์ถ๋ก ๋์ด ์ง์ ๋ ๊ฐ ์ธ์ ๊ฐ์ ํ ๋นํ ์ ์๋ค. ๋ฐ๋ผ์ ์๋ํ์ง ์์ ๊ฐ ๋ณ๊ฒฝ์ ๋ฐฉ์งํ ์ ์๋ค.
3 ์ผ์ฐจ
spacing์ @emotion์ SerializedStyles๋ฅผ return ํ๋ ํจ์๋ก ์๋ ์ฝ๋์ ๊ฐ์ด ์ฌ์ฉํ ์ ์์ง๋ง Emotion css props ์๋ฌ๊ฐ ๋ฐ์ํ๋ค. ์ด ์๋ฌ๋ Emotion์ css ํจ์๋ฅผ ์ฌ์ฉํ์ฌ ์์ฑ๋ ์คํ์ผ ๊ฐ์ฒด๋ฅผ ๋ฌธ์์ด๋ก ๋ณํํ๋ ค๊ณ ์๋ํ๊ธฐ ๋๋ฌธ์ ๋ฐ์ํ ํ์์ด๋ค.
<button css={[spacing.mx(3), spacing.my(4)]}>๋ฒํผ</button>
- ์๋ฌ ๋ฉ์ธ์ง
You have tried to stringify object returned from
css
function. It isn't supposed to be used directly (e.g. as value of theclassName
prop), but rather handed to emotion so it can handle it (e.g. as value ofcss
prop).,You have tried to stringify object returned fromcss
function. It isn't supposed to be used directly (e.g. as value of theclassName
prop), but rather handed to emotion so it can handle it (e.g. as value ofcss
prop).
<button css={spacing.my(4)}>๋ฒํผ</button>
- ์๋ฌ ๋ฉ์ธ์ง
css="You have tried to stringify object returned from
css
function. It isn't supposed to be used directly (e.g. as value of theclassName
prop), but rather handed to emotion so it can handle it (e.g. as value ofcss
prop)."
๋ฐ๋ผ์ ๊ฐ ํ์ด์ง๋ง๋ค /** @jsxImportSource @emotion/react */
์ฃผ์์ ๋ฌ์์ฃผ๋ ๋ฐฉ๋ฒ์ด ์๊ณ , craco ์ค์น
๋ฐ ์ค์ ํด ์ฃผ๋ ๋ฐฉ๋ฒ์ด ์๋๋ฐ ์๋์ ๊ฐ์ด styled ์ปดํฌ๋ํธ
๋ฅผ ์์ฑํด์ ์ ์ฉํ๋ ๋ฐฉ๋ฒ๋ ์๋ค.
import { spacing } from "./spacing";
import styled from "@emotion/styled";
const Button = styled.button`
${[spacing.mx(2), spacing.my(6)]}
`;
const Box = styled.div`
${spacing.m(2)}
`;
export const Test = () => {
return (
<>
<Button>button</Button>
<Box>box</Box>
</>
);
7 ์ผ์ฐจ
input ์ปดํฌ๋ํธ๋ฅผ ๊ตฌํํ๋ ์ค ๋ฒํผ ์ปดํฌ๋ํธ์ฒ๋ผ ์ฌ์ด์ฆ๋ฅผ prop์ผ๋ก ๋ฐ์์์ ์คํ์ผ์ ๋์ ์ผ๋ก ๋ณ๊ฒฝํ๋ ๊ฒ ์ข์ ๊ฑฐ ๊ฐ๋ค ์๊ฐํด์ width: 100%, height: auto
๋ก ํ๊ณ padding ๊ฐ์ผ๋ก๋ง ์ฌ์ด์ฆ๋ฅผ ์กฐ์ ํ๊ฒ ๋ ๊ตฌํํ์๋ค.
์ฒ์์ ์๋์ ๊ฐ์ด icon์ด ์๋ input๊ณผ ์๋ Input์ padding-left, padding-right์ ๋ค๋ฅด๊ฒ ์ค์ผ ํ๊ฒ ๋๋ฌธ์ hasIcon, default๋ก ๋๋๊ณ , ํด๋นํ๋ size ๊ฐ์ ๋ฐํํด ์คํ์ผ์ ์ง์ ํด ์คฌ์๋ค. ์ฌ์ด์ฆ๋ ๋ฐ์์ ์คํ์ผ์ ์ฃผ๋ ๊ฒ ์ข์์ง, height ๊ฐ์ prop์ผ๋ก ๋ฐ์์ ์คํ์ผ์ ์ ๋์ ์ผ๋ก ๋ณ๊ฒฝํ๋ ๊ฒ ์ข์์ง ๊ณ ๋ฏผ์ด๋ค. height์ผ๋ก ๋์ด๋ง ์ง์ ํ๊ณ , padding์ ๋น๋กํ๊ฒ ํ๋ฉด ๋ ๊น?
์ผ๋จ size์ ๋ฐ๋ผ ๋ค๋ฅด๊ฒ height์ padding์ด ์ง์ ๋๋๋ก ํด์ ์์ด์ฝ ์ ๋ฌด์ ๋ฐ๋ผ padding ๊ฐ์ ๋ ์ฃผ๋ ์์ผ๋ก ์ฝ๋๋ฅผ ๋ณ๊ฒฝํ๋ค. ๋๊ฐ์ ๋น์จ๋ก ๋ณ๊ฒฝํ๋ ค๊ณ ํ๋ค๊ฐ ํ๋ ์ฝ๋ฉํ ๊ฑฐ ๊ฐ๋ค..๐ฅฒ
์ฃผ์ ์ฝ๋๋ง ๋ณด๋ฉด ๋ค์๊ณผ ๊ฐ๋ค.
///...
const SIZE_SET: {
[key in Size]: {
paddingLeft: string | SpacingStyles;
paddingRight: string | SpacingStyles;
};
} = {
sm: {
paddingLeft: spacing.pl(3),
paddingRight: spacing.pr(3),
},
md: {
paddingLeft: spacing.pl(4),
paddingRight: spacing.pr(4),
},
lg: {
paddingLeft: spacing.pl(6),
paddingRight: spacing.pr(6),
},
} as const;
const HEIGHT_SIZE_SET: { [key in Size]: string } = {
sm: '2rem',
md: '3rem',
lg: '4rem',
} as const;
const FONT_SIZE_SET: { [key in Size]: string } = {
sm: '.875rem',
md: '1rem',
lg: '1.125rem',
} as const;
///...
const Input = (
{
type = 'text',
leftIcon,
rightIcon,
variant,
helperText,
inputSize = 'md',
radius = 'default',
iconSize,
...props
}: InputProps,
ref: ForwardedRef<HTMLInputElement>,
) => {
const borderColor = getColorStyle(variant);
const helperTextColor = getColorStyle(variant);
const hasLeftIcon = !!leftIcon;
const hasRightIcon = !!rightIcon;
const sizeStyle = SIZE_SET[inputSize];
let paddingLeft = sizeStyle.paddingLeft;
let paddingRight = sizeStyle.paddingRight;
if (hasLeftIcon) {
paddingLeft = css`
padding-left: calc(32px + ${iconSize ? `${iconSize}px` : '30px'});
`;
}
if (hasRightIcon) {
paddingRight = css`
padding-right: calc(32px + ${iconSize ? `${iconSize}px` : '30px'});
`;
}
return (
<Wrapper>
<div style={{ position: 'relative', display: 'flex', width: '100%' }}>
{leftIcon && (
<IconBox className="leftIcon" iconSize={iconSize}>
{leftIcon}
</IconBox>
)}
<BaseInput
type={type}
ref={ref}
borderColor={borderColor}
radius={radius}
textSize={inputSize}
heightSize={HEIGHT_SIZE_SET[inputSize]}
paddingLeft={paddingLeft}
paddingRight={paddingRight}
{...props}
/>
{rightIcon && (
<IconBox className="rightIcon" iconSize={iconSize}>
{rightIcon}
</IconBox>
)}
</div>
{helperText && (
<HelperText
color={helperTextColor}
textSize={inputSize}
heightSize={HEIGHT_SIZE_SET[inputSize]}
>
{helperText}
</HelperText>
)}
</Wrapper>
);
};
//...
const BaseInput = styled.input<{
borderColor: string;
radius: ComponentBorderKey;
textSize: Size;
heightSize: string;
paddingLeft: string | SpacingStyles;
paddingRight: string | SpacingStyles;
}>`
height: ${({ heightSize }) => heightSize};
font-size: ${({ textSize }) => FONT_SIZE_SET[textSize]};
${({ paddingLeft }) => paddingLeft};
${({ paddingRight }) => paddingRight};
`;
export default forwardRef(Input);
8 ์ผ์ฐจ
Breadcrumb
์ ์ ์ ์๊ฒ ์น์ฌ์ดํธ ๋ด์์ ํ์ฌ ์์น๋ฅผ ์๊ฐ์ ์ผ๋ก ์๋ ค์ฃผ๋ ๋ค๋น๊ฒ์ด์
์์์ด๋ค.
๊ฐ ๊ฒฝ๋ก name๊ณผ url์ ๋ด์ breadcrumbItems๋ฐฐ์ด์ ๊ธฐ๋ฐ์ผ๋ก ํด๋น ํ์ด์ง๋ ์ด๋ค ์นดํ
๊ณ ๋ฆฌ์ ์ํด์๋์ง๋ฅผ ์๋ ค์ฃผ๋ ์ญํ ์ ํ๋ค.
Components > Breadcrumb
์ด๋ฐ์์ผ๋ก >
๋ก ๊ตฌ๋ถ๋์ด ํ์๋๊ฒ ๊ตฌํํ์๋ค.
์๋์ ๊ฐ์ด Breadcrumb ์ปดํฌ๋ํธ๋ฅผ ์ฌ์ฉํ ์ ์๋ค.
//next.js ์ฌ์ฉ์์
'use client';
import React from 'react';
import { usePathname } from 'next/navigation';
const paths = usePathname();
// ๊ฒฝ๋ก name๊ณผ url์ ๋ด์ breadcrumbItems๋ฐฐ์ด๋ก current pathname์ ๋ฐ์์ ์ฌ์ฉํ ์๋ ์๋ค.
const breadcrumbItems = [
{ name: 'Home', url: '/' },
{ name: 'Ui', url: `${paths}` },
];
//..
<Breadcrumb
paths={breadcrumbItems}
containerClasses="breadcrumb-container"
listClasses="breadcrumb-item"
activeClasses="active"
/>;
์ง๊ธ Breadcrumb ์ปดํฌ๋ํธ์ ์คํ์ผ์ ๊ณ ์ ์ ์ด๊ธฐ ๋๋ฌธ์ ์ฌ์ด์ฆ๋ ๊ตฌ๋ถ์๋ฅผ ์ ํํ ์ ์๊ฒ ๋ฆฌํฉํ ๋ง ํด์ผ ํ ๊ฒ ๊ฐ๋ค.
9 ์ผ์ฐจ
Tooltip ์ปดํฌ๋ํธ๋ ํ ์คํธ, ์์ด์ฝ, ๋ฒํผ ๋ฑ ํ ์คํธ ์์ด ๊ทธ๋ํฝ ํํ๋ก๋ง ์ด๋ฃจ์ด์ง ์์ด์ฝ์ด๋ ์๋น์ค์ ๋ฐ๋ผ ํน๋ณํ ์ฌ์ฉ๋๋ ๋ฒํผ๋ช ๋ฑ๋ฑ ui ์์์ ๊ธฐ๋ฅ์ ๋ณด์กฐ ์ค๋ช ํ๊ธฐ ์ํด ํ์ํ ์ปดํฌ๋ํธ์ด๋ค.
์๋์ ๊ฐ์ด Tooltip ์ปดํฌ๋ํธ๋ฅผ ์ฌ์ฉํ ์ ์๋ค.
// ์ฌ์ฉ์์
<Tooltip message="๋ฉ๋ด" direction="left" variant="info">
<Menu />
</Tooltip>
Tooltip ์์ ๋ค์ด๊ฐ message, Tooltip์ ๋ํ๋ผ ๋ฐฉํฅ, Tooltip ๋ฐฐ๊ฒฝ์์ ๋ํ๋ด์ค variant ์์ฑ์ ์ ๋ฌํด ์ค์ผ ํ๋ค.
// Tooltip ์ปดํฌ๋ํธ
const Tooltip = (
{ children, message, variant, direction }: TooltipProps,
ref: ForwardedRef<HTMLDivElement>,
) => {
return (
<Wrapper ref={ref}>
{children}
<TooltipContainer
variant={variant}
className={`tooltip ${direction}`}
direction={direction}
>
{message}
</TooltipContainer>
</Wrapper>
);
};
Menu ์ปดํฌ๋ํธ(children)๋ฅผ ์ค์ฌ์ผ๋ก TooltipContainer๋ direction ์์ฑ์ ๋ฐ๋ผ Tooltip์ ๋ฐฉํฅ์ ๊ฒฐ์ ๋๋ค.
๋ง์ฐ์ค ํธ๋ฒ ์ธํฐ๋์ ์ ์ํด ๋ํ๋๋๋ฐ ๋ง์ฐ์ค ์ฅ์น๊ฐ ์์ ํ๊ฒฝ์ ๊ณ ๋ คํด์ ํค๋ณด๋ ์ฅ์น๋ก๋ ์๋๋ ์ ์๋๋ก ์ถ๊ฐํด์ผ๊ฒ ๋ค.