Skip to content

Commit

Permalink
LH-361/callout (#7)
Browse files Browse the repository at this point in the history
* fix(normalizeCSS): sr-only 추가

* feat(callout): Callout 컴포넌트 제작

* fix(normalizeCSS): body 테스트 스타일 제거

---------

Co-authored-by: baegofda <[email protected]>
  • Loading branch information
baegofda and baegofda authored Apr 3, 2023
1 parent b2d8c53 commit 9bc266e
Show file tree
Hide file tree
Showing 13 changed files with 323 additions and 6 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { createStyles } from "@travelmakers-design-v2/styles";

export default createStyles((theme) => {
const { spacing, radius, colors } = theme;

return {
root: {
display: "inline-flex",
flexDirection: "column",
rowGap: spacing.spacing10,
margin: 0,
padding: spacing.spacing30,
borderRadius: radius.radius20,
backgroundColor: colors.surface,
},
};
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import {
ClassNames,
PolymorphicComponentProps,
PolymorphicRef,
TmComponentProps,
} from "@travelmakers-design-v2/styles";
import { forwardRef } from "react";
import { View } from "../../View";
import { CalloutHeader } from "../CalloutHader";
import { CalloutItem } from "../CalloutItem";
import useStyles from "./Callout.style";

export type CalloutStylesNames = ClassNames<typeof useStyles>;

export type CalloutType = "default" | "warning";

export interface Props {
type?: CalloutType;
title: string;
items?: string[];
emptyText?: string;
}
export interface SharedCalloutProps
extends Props,
TmComponentProps<CalloutStylesNames> {}

export type CalloutProps<C extends React.ElementType> =
PolymorphicComponentProps<C, SharedCalloutProps>;

type CalloutComponent = <C extends React.ElementType = "dl">(
props: CalloutProps<C>
) => React.ReactElement;

export const Callout: CalloutComponent & {
displayName?: string;
} = forwardRef(
<C extends React.ElementType = "dl">(
{
type = "default",
title,
items = [],
emptyText = "",
className,
...props
}: CalloutProps<C>,
ref: PolymorphicRef<C>
) => {
const isEmptyItems = items.length === 0;
const { classes, cx } = useStyles();

const _items = !isEmptyItems ? (
items.map((item, idx) => <CalloutItem key={idx} content={item} />)
) : (
<CalloutItem content={emptyText} isEmpty />
);

return (
<View<React.ElementType>
component={"dl"}
ref={ref}
className={cx(classes.root, className)}
{...props}
>
<CalloutHeader type={type} title={title} />
{_items}
</View>
);
}
);

Callout.displayName = "Callout";
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { Callout } from "./Callout";
export type { CalloutProps } from "./Callout";
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { createStyles } from "@travelmakers-design-v2/styles";
import { CalloutType } from "../Callout/Callout";
import { CALLOUT_COLOR } from "./CalloutHeader";

export default createStyles((theme, { type }: { type: CalloutType }) => {
const { colors, typography, spacing } = theme;

return {
root: {
display: "flex",
alignItems: "center",
color: colors[CALLOUT_COLOR[type]],
...typography.body3,
fontWeight: 700,
columnGap: spacing.spacing10,
},
};
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import {
ClassNames,
PolymorphicComponentProps,
PolymorphicRef,
TmColor,
TmComponentProps,
useTmTheme,
} from "@travelmakers-design-v2/styles";
import { forwardRef } from "react";
import { Icon } from "../../Icon";
import { View } from "../../View";
import { CalloutType } from "../Callout/Callout";
import useStyles from "./CalloutHeader.style";

export type CalloutHeaderStylesNames = ClassNames<typeof useStyles>;

export interface Props {
type: CalloutType;
title: string;
}
export interface SharedCalloutHeaderProps
extends Props,
TmComponentProps<CalloutHeaderStylesNames> {}

export type CalloutHeaderProps<C extends React.ElementType> =
PolymorphicComponentProps<C, SharedCalloutHeaderProps>;

type CalloutHeaderComponent = <C extends React.ElementType = "dt">(
props: CalloutHeaderProps<C>
) => React.ReactElement;

export const CALLOUT_COLOR: Record<CalloutType, TmColor> = {
default: "secondary",
warning: "error",
};

export const CalloutHeader: CalloutHeaderComponent & {
displayName?: string;
} = forwardRef(
<C extends React.ElementType = "dt">(
{ type, title, className, ...props }: CalloutHeaderProps<C>,
ref: PolymorphicRef<C>
) => {
const { colors } = useTmTheme();
const { classes, cx } = useStyles({ type });

return (
<View<React.ElementType>
component={"dt"}
ref={ref}
className={cx(classes.root, className)}
{...props}
>
<Icon
src="IcAlert"
width={14}
height={14}
color={colors[CALLOUT_COLOR[type]]}
/>
{title}
</View>
);
}
);

CalloutHeader.displayName = "CalloutHeader";
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { CalloutHeader } from "./CalloutHeader";
export type { CalloutHeaderProps } from "./CalloutHeader";
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { TmTheme, createStyles } from "@travelmakers-design-v2/styles";

export default createStyles((theme: TmTheme) => {
const { colors, typography } = theme;

return {
root: {
margin: 0,
color: colors.onSurface,
...typography.body3,
},
};
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import {
ClassNames,
PolymorphicComponentProps,
PolymorphicRef,
TmComponentProps,
} from "@travelmakers-design-v2/styles";
import { forwardRef } from "react";
import { View } from "../../View";
import useStyles from "./CalloutItem.style";

export type CalloutItemStylesNames = ClassNames<typeof useStyles>;

export interface Props {
content: string;
isEmpty?: boolean;
}
export interface SharedCalloutItemProps
extends Props,
TmComponentProps<CalloutItemStylesNames> {}

export type CalloutItemProps<C extends React.ElementType> =
PolymorphicComponentProps<C, SharedCalloutItemProps>;

type CalloutItemComponent = <C extends React.ElementType = "dd">(
props: CalloutItemProps<C>
) => React.ReactElement;

export const CalloutItem: CalloutItemComponent & {
displayName?: string;
} = forwardRef(
<C extends React.ElementType = "dd">(
{ content, isEmpty = false, className, ...props }: CalloutItemProps<C>,
ref: PolymorphicRef<C>
) => {
const { classes, cx } = useStyles();

return (
<View<React.ElementType>
component={"dd"}
ref={ref}
className={cx(classes.root, className, { "sr-only": isEmpty })}
{...props}
>
{content}
</View>
);
}
);

CalloutItem.displayName = "CalloutItem";
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { CalloutItem } from "./CalloutItem";
export type { CalloutItemProps } from "./CalloutItem";
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./Callout";
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { Meta } from "@storybook/react";
import { Callout } from "../Callout";

const data = { title: "타이틀", items: ["추가 설명을 위한 영역입니다."] };
const dataWithoutItems = { title: "타이틀(추가적인 설명 없음)", items: [] };

export default {
title: "@travelmakers-design-v2/core/General/Callouts",
component: Callout,
argTypes: {
type: {
control: { type: "radio", options: ["default", "warning"] },
defaultValue: "default",
description: "Callout의 type을 지정합니다.",
table: {
type: {
summary: "string",
},
},
},
title: {
type: "string",
description: "Callout에서 사용될 title을 나타냅니다.",
table: {
type: {
summary: "string",
},
},
},
items: {
control: { type: "object" },
description: "Callout에서 title에 대한 추가 설명을 작성합니다.",
defaultValue: [],
table: {
type: {
summary: "string[]",
},
},
},
emptyText: {
type: "string",
defaultValue: "",
table: {
type: {
summary: "string",
},
},
},
},
} as Meta;

export const Default = (props) => {
return <Callout title={data.title} {...props} items={data.items} />;
};

export const CalloutWithoutItems = (props) => {
return (
<Callout
title={dataWithoutItems.title}
items={dataWithoutItems.items}
{...props}
/>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export const TagItem: TagItemComponent & {
const { classes, cx } = useStyles({ type, color, size, roundness });

return (
<View
<View<React.ElementType>
component={"li"}
ref={ref}
className={cx(classes.item, className)}
Expand Down
21 changes: 16 additions & 5 deletions packages/travelmakers-design-styles/src/theme/NormalizeCSS.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,28 @@
import React from "react";
import { Global } from "@emotion/react";
import { Global, css } from "@emotion/react";

const styles = {
const styles = css`
html: {
fontFamily: "sans-serif",
lineHeight: "1.15",
textSizeAdjust: "100%",
},
body: {
margin: 0,
margin: 0;
},
} as const;
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0,0,0,0);
white-space: nowrap;
border-width: 0;
}
`;

export const NormalizeCSS = () => {
return <Global styles={styles} />;
Expand Down

0 comments on commit 9bc266e

Please sign in to comment.