Skip to content

Commit

Permalink
feat(price): creating a price (#10)
Browse files Browse the repository at this point in the history
* feat(price): created a Price Component

LH-372

* feat(price): created a Price Component

LH-372

* feat(price): percentText 타입 변경

LH-372

* feat(price): delete a children props

LH-372
  • Loading branch information
sgd122 authored Apr 5, 2023
1 parent 2946578 commit 9f86953
Show file tree
Hide file tree
Showing 6 changed files with 306 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import { createStyles } from "@travelmakers-design-v2/styles";
import { Props } from "./Price";

export default createStyles((theme, { type }: Pick<Props, "type">) => {
return {
root: {
display: "flex",
flexDirection: "row",
alignItems: "center",
width: "100%",
},

percentText: {
...theme.typography.display6,
fontWeight: "700",
width: "39px",
color: theme.colors.error,
},
nightText: {
...theme.typography.body3,
fontWeight: "700",
textAlign: "right",
width: "28px",
color: theme.colors.primary1,
},
priceText: {
...theme.typography.display4,
fontWeight: "700",
color: theme.colors.primary1,
marginLeft: theme.spacing.spacing5,
},
priceBeforeText: {
...theme.typography.body2,
fontWeight: "700",
color: theme.colors.primary1,
},
priceStartText: {
...theme.typography.body3,
fontWeight: "400",
color: theme.colors.primary2,
marginLeft: theme.spacing.spacing5,
},

// NOTE: Type is 'secondary'
labelSecondary: {
...theme.typography.body3,
fontWeight: "400",
color: theme.colors.primary1,
marginRight: theme.spacing.spacing5,
},
nightSecondaryText: {
...theme.typography.body3,
fontWeight: "700",
color: theme.colors.primary1,
textAlign: "right",
marginRight: theme.spacing.spacing5,
},
priceSecondaryText: {
...theme.typography.body3,
fontWeight: "400",
color: theme.colors.primary2,
},
priceBeforeSecondaryText: {
...theme.typography.body3,
fontWeight: "400",
color: theme.colors.primary2,
},
couponWrap: {
display: "flex",
alignItems: "center",
width: "74px",
background: theme.colors.secondaryContainer,
borderRadius: theme.spacing.spacing5,
marginLeft: theme.spacing.spacing5,
},
couponWord: {
...theme.typography.caption,
fontWeight: "700",
color: theme.colors.secondary1,
},
};
});
122 changes: 122 additions & 0 deletions packages/travelmakers-design-core/src/components/Price/Price.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import { PolymorphicRef } from "@travelmakers-design-v2/styles";
import { forwardRef, PropsWithChildren } from "react";
import { View } from "../View";
import useStyles from "./Price.style";
import { PriceProps, PriceComponent } from "./Price.type";
import { Icon } from "../Icon";

export interface Props {
/** Price 컴포넌트의 타입을 정합니다. */
type?: "primary" | "secondary";

/** (secondary type 한정) Price 컴포넌트의 레이블을 표시합니다. */
label?: string;

/** Price 컴포넌트의 할인율을 표시합니다. */
percentText?: number;

/** Price 컴포넌트의 1박을 표시합니다. */
nightText?: number;

/** Price 컴포넌트의 가격을 표시합니다. */
priceText?: number;

/** Price 컴포넌트의 시작가격을 표시합니다. */
priceStartText?: string;

/** (secondary type 한정) Price 컴포넌트의 쿠폰 표시여부를 결정합니다. */
isCoupon?: boolean;
}

export const Price: PriceComponent & {
displayName?: string;
} = forwardRef(
<C extends React.ElementType = "div">(
{
type = "primary",
label,
percentText,
nightText,
priceText,
priceStartText,
isCoupon = true,
className,
...props
}: PropsWithChildren<PriceProps<C>>,
ref: PolymorphicRef<C>
) => {
const { classes, cx } = useStyles({ type });

const Primary = () => {
return (
<View<React.ElementType>
component={"div"}
ref={ref}
className={cx(classes.root, className)}
{...props}
>
{percentText && (
<span className={cx(classes.percentText)}>{percentText}%</span>
)}
{nightText && (
<span className={cx(classes.nightText)}>{nightText}</span>
)}
{priceText && (
<>
<span className={cx(classes.priceText)}>
{priceText.toLocaleString("ko")}
</span>
<span className={cx(classes.priceBeforeText)}>원~</span>
</>
)}
{priceStartText && (
<span className={cx(classes.priceStartText)}>
| {priceStartText}
</span>
)}
</View>
);
};

const Secondary = () => {
return (
<View<React.ElementType>
component={"div"}
ref={ref}
className={cx(classes.root, className)}
{...props}
>
{label && <span className={cx(classes.labelSecondary)}>{label}</span>}
{nightText && (
<span className={cx(classes.nightSecondaryText)}>
{nightText}
</span>
)}
{priceText && (
<>
<span className={cx(classes.priceSecondaryText)}>
{priceText?.toLocaleString("ko")}
</span>
<span className={cx(classes.priceBeforeSecondaryText)}></span>
</>
)}
{isCoupon && (
<div className={cx(classes.couponWrap)}>
<Icon
src="IcDiscount"
width={16}
height={16}
style={{ margin: "0 4px" }}
/>
<span className={cx(classes.couponWord)}>쿠폰 적용가</span>
</div>
)}
</View>
);
};

return type === "primary" ? <Primary /> : <Secondary />;
}
);

Price.displayName = "Price";
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import {
ClassNames,
PolymorphicComponentProps,
TmComponentProps,
} from "@travelmakers-design-v2/styles";
import { Props } from "./Price";
import useStyles from "./Price.style";

type PriceStylesNames = ClassNames<typeof useStyles>;

interface SharedPriceProps extends Props, TmComponentProps<PriceStylesNames> {}

export type PriceProps<C extends React.ElementType> = PolymorphicComponentProps<
C,
SharedPriceProps
>;

export type PriceComponent = <C extends React.ElementType = "div">(
props: PriceProps<C>
) => React.ReactElement;
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { Price } from "./Price";
export type { PriceProps } from "./Price.type";
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import React from "react";
import { Price } from "../Price";

export default {
title: "@travelmakers-design-v2/core/General/Price",
component: Price,
argTypes: {
type: {
defaultValue: "primary",
description: "Price 컴포넌트의 타입을 정합니다.",
options: ["primary", "secondary"],
control: { type: "inline-radio" },
},
label: {
defaultValue: "",
description: "(secondary type 한정)Price 컴포넌트의 레이블을 표시합니다.",
table: {
type: {
summary: "string",
},
},
control: { type: "text" },
},
percentText: {
defaultValue: 70,
description: "Price 컴포넌트의 할인율을 표시합니다.",
table: {
type: {
summary: "number",
},
},
control: { type: "number" },
},
nightText: {
defaultValue: 1,
description: "Price 컴포넌트의 1박을 표시합니다.",
table: {
type: {
summary: "number",
},
},
control: { type: "number" },
},
priceText: {
defaultValue: 10000,
description: "Price 컴포넌트의 가격을 표시합니다.",
table: {
type: {
summary: "number",
},
},
control: { type: "number" },
},
priceStartText: {
defaultValue: "1박 100,000원부터",
description: "Price 컴포넌트의 시작가격을 표시합니다.",
table: {
type: {
summary: "string",
},
},
control: { type: "text" },
},
isCoupon: {
defaultValue: true,
description:
" (secondary type 한정) Price 컴포넌트의 쿠폰 표시여부를 결정합니다.",
table: {
type: {
summary: "boolean",
},
},
control: { type: "boolean" },
},
},
};

export const Default = (props) => {
return <Price {...props} />;
};
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { TmSize } from "../types/TmSize";
export type CoBreakpoints = TmSize;

export const DEFAULT_BREAKPOINTS: Record<CoBreakpoints, number> = {
xsmall: 576,
small: 768,
medium: 1024,
large: 1408,
Expand Down

0 comments on commit 9f86953

Please sign in to comment.