Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(ui/react): Portal 단순화, ModalPortal, ModalContext 변경 및 개편 #206

Merged
merged 13 commits into from
Jul 5, 2024
Merged
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
10 changes: 10 additions & 0 deletions packages/ui/icons/src/close.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { createIcon } from './icon';

export const CloseIcon = createIcon({
defaultProps: {
width: '1em',
height: '1em',
fill: 'none',
},
d: 'M10.0001 11.0628L6.58346 14.4795C6.43068 14.6323 6.25707 14.7052 6.06263 14.6982C5.86818 14.6913 5.69457 14.6114 5.54179 14.4587C5.38902 14.3059 5.31263 14.1288 5.31263 13.9274C5.31263 13.726 5.38902 13.5489 5.54179 13.3962L8.93763 10.0003L5.52096 6.58366C5.36818 6.43088 5.29527 6.2538 5.30221 6.05241C5.30916 5.85102 5.38902 5.67394 5.54179 5.52116C5.69457 5.36838 5.87166 5.29199 6.07304 5.29199C6.27443 5.29199 6.45152 5.36838 6.60429 5.52116L10.0001 8.93783L13.4168 5.52116C13.5696 5.36838 13.7467 5.29199 13.948 5.29199C14.1494 5.29199 14.3265 5.36838 14.4793 5.52116C14.6321 5.67394 14.7085 5.85102 14.7085 6.05241C14.7085 6.2538 14.6321 6.43088 14.4793 6.58366L11.0626 10.0003L14.4793 13.417C14.6321 13.5698 14.7085 13.7434 14.7085 13.9378C14.7085 14.1323 14.6321 14.3059 14.4793 14.4587C14.3265 14.6114 14.1494 14.6878 13.948 14.6878C13.7467 14.6878 13.5696 14.6114 13.4168 14.4587L10.0001 11.0628Z',
});
2 changes: 1 addition & 1 deletion packages/ui/icons/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
/* eslint-disable @stylistic/padding-line-between-statements, react-refresh/only-export-components */
export * from './icon';

export * from './add';
export * from './bell';
export * from './cancel';
export * from './chevron-down';
export * from './chevron-left';
export * from './chevron-right';
export * from './chevron-up';
export * from './close';
export * from './drawer';
export * from './edit';
export * from './heart';
Expand Down
31 changes: 31 additions & 0 deletions packages/ui/react/src/components/modal/modal-close.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import {
type HTMLFavolinkProps,
favolink,
forwardRef,
} from '@favolink-ui/system';
import { cx, mergeFns } from '@favolink-ui/utils';
import { useModalContext } from './modal.context';

export type ModalCloseProps = HTMLFavolinkProps<'button'>;

export const ModalClose = forwardRef<ModalCloseProps, 'button'>(
function ModalClose(props, ref) {
const { children, className, onClick, ...restProps } = props;

const { onOpenChange } = useModalContext();

return (
<favolink.button
{...restProps}
asChild
ref={ref}
className={cx('favolink-modal__close', className)}
onClick={mergeFns(onClick, () => {
onOpenChange(false);
})}
>
{children}
</favolink.button>
);
},
);
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ import { vars } from '../../styles/vars.css';
export const modalContentBase = style({
display: 'flex',
gap: 16,
position: 'relative',
zIndex: 98,
position: 'fixed',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
flexDirection: 'column',
padding: 24,
minWidth: 300,
padding: '20px 24px',
maxWidth: 'max-content',
backgroundColor: vars.color.gray[200],
borderRadius: 20,
});
32 changes: 11 additions & 21 deletions packages/ui/react/src/components/modal/modal-content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,35 +5,25 @@ import {
} from '@favolink-ui/system';
import { cx } from '@favolink-ui/utils';
import * as styles from './modal-content.styles.css';
import { ModalOverlay } from './modal-overlay';
import { useModalContext } from './modal.context';

export type ModalContentProps = HTMLFavolinkProps<'div'>;

export const ModalContent = forwardRef<ModalContentProps, 'div'>(
function ModalContent(props, ref) {
const { children, className, ...restPorps } = props;

const { onClose, closeOnOverlayClick } = useModalContext();

return (
<>
<ModalOverlay
onClick={closeOnOverlayClick ? onClose : undefined}
variant="withContent"
/>
<favolink.div
{...restPorps}
ref={ref}
className={cx(
'favolink-modal__content',
styles.modalContentBase,
className,
)}
>
{children}
</favolink.div>
</>
<favolink.div
{...restPorps}
ref={ref}
className={cx(
'favolink-modal__content',
styles.modalContentBase,
className,
)}
>
{children}
</favolink.div>
);
},
);
Original file line number Diff line number Diff line change
@@ -1,32 +1,7 @@
import { type RecipeVariants, recipe } from '@vanilla-extract/recipes';
import { style } from '@vanilla-extract/css';

export const modalOverlay = recipe({
base: {
position: 'fixed',
top: 0,
left: 0,
right: 0,
bottom: 0,
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
},

variants: {
variant: {
original: {
backgroundColor: 'rgba(0, 0, 0, 0.5)',
zIndex: 96,
},
withContent: {
zIndex: 97,
},
},
},

defaultVariants: {
variant: 'original',
},
export const modalOverlayBase = style({
position: 'fixed',
inset: 0,
backgroundColor: 'rgba(0, 0, 0, 0.5)',
});

export type ModalOverlayVariants = RecipeVariants<typeof modalOverlay>;
20 changes: 15 additions & 5 deletions packages/ui/react/src/components/modal/modal-overlay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,33 @@ import {
favolink,
forwardRef,
} from '@favolink-ui/system';
import { cx } from '@favolink-ui/utils';
import { cx, mergeFns } from '@favolink-ui/utils';
import * as styles from './modal-overlay.styles.css';
import { useModalContext } from './modal.context';

export type ModalOverlayProps = HTMLFavolinkProps<'div'> &
styles.ModalOverlayVariants;
export type ModalOverlayProps = HTMLFavolinkProps<'div'>;

export const ModalOverlay = forwardRef<ModalOverlayProps, 'div'>(
function ModalOverlay(props, ref) {
const { variant, ...restProps } = props;
const { className, onClick, ...restProps } = props;

const { onOpenChange, closeOnOverlayClick } = useModalContext();

return (
<favolink.div
{...restProps}
ref={ref}
onClick={
closeOnOverlayClick
? mergeFns(() => {
onOpenChange(false);
}, onClick)
: onClick
}
className={cx(
'favolink-modal__overlay',
styles.modalOverlay({ variant }),
styles.modalOverlayBase,
className,
)}
/>
);
Expand Down
22 changes: 22 additions & 0 deletions packages/ui/react/src/components/modal/modal-portal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Children } from 'react';
import { useModalContext } from './modal.context';
import { Portal, type PortalProps } from '../portal/';

export type ModalPortalProps = PortalProps;

export function ModalPortal(props: ModalPortalProps) {
const { children, ...restProps } = props;

const { onOpen } = useModalContext();

return (
onOpen &&
Children.map(children, (child) => {
return (
<Portal {...restProps} asChild>
{child}
</Portal>
);
})
);
}
Original file line number Diff line number Diff line change
@@ -1,22 +1,24 @@
import { style } from '@vanilla-extract/css';
import { type RecipeVariants, recipe } from '@vanilla-extract/recipes';
import { vars } from '../../styles/vars.css';

export const modalTitle = recipe({
base: {
display: 'flex',
color: vars.color.gray[1000],
},
const base = style({
color: vars.color.gray[1000],
});

export const modalTitleVariants = recipe({
base,

variants: {
layout: {
left: {
justifyContent: 'flex-start',
textAlign: 'left',
},
center: {
justifyContent: 'center',
textAlign: 'center',
},
right: {
justifyContent: 'flex-end',
textAlign: 'right',
},
},
},
Expand All @@ -26,4 +28,4 @@ export const modalTitle = recipe({
},
});

export type ModalTitleVariants = RecipeVariants<typeof modalTitle>;
export type ModalTitleVariants = RecipeVariants<typeof modalTitleVariants>;
28 changes: 13 additions & 15 deletions packages/ui/react/src/components/modal/modal-title.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { favolink, forwardRef } from '@favolink-ui/system';
import { forwardRef } from '@favolink-ui/system';
import { cx } from '@favolink-ui/utils';
import * as styles from './modal-title.styles.css';
import { Heading, type HeadingProps } from '../typography';
Expand All @@ -10,20 +10,18 @@ export const ModalTitle = forwardRef<ModalTitleProps, typeof Heading>(
const { children, className, layout, ...restProps } = props;

return (
<favolink.div className={styles.modalTitle({ layout })}>
<Heading
as="h4"
{...restProps}
ref={ref}
className={cx(
'favolink-modal__title',
styles.modalTitle.classNames.base,
className,
)}
>
{children}
</Heading>
</favolink.div>
<Heading
as="h4"
{...restProps}
ref={ref}
className={cx(
'favolink-modal__title',
styles.modalTitleVariants({ layout }),
className,
)}
>
{children}
</Heading>
);
},
);
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import { style } from '@vanilla-extract/css';
import { type RecipeVariants, recipe } from '@vanilla-extract/recipes';

const base = style({
display: 'flex',
});

export const modalTopbar = recipe({
base: {
display: 'flex',
},
base,

variants: {
layout: {
Expand All @@ -17,8 +20,14 @@ export const modalTopbar = recipe({
},

defaultVariants: {
layout: 'couple',
layout: 'single',
},
});

export type ModalTopbarVariants = RecipeVariants<typeof modalTopbar>;

export const modalTopbarIcon = style({
width: 20,
height: 20,
cursor: 'pointer',
});
34 changes: 27 additions & 7 deletions packages/ui/react/src/components/modal/modal-topbar.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,31 @@
import { ChevronLeftIcon, CloseIcon } from '@favolink-ui/icons';
import {
type HTMLFavolinkProps,
favolink,
forwardRef,
} from '@favolink-ui/system';
import { cx } from '@favolink-ui/utils';
import { cx, mergeFns } from '@favolink-ui/utils';
import { type MouseEvent } from 'react';
import * as styles from './modal-topbar.styles.css';
import { useModalContext } from './modal.context';
import { Text } from '../typography';

export type ModalTopbarProps = HTMLFavolinkProps<'div'> &
styles.ModalTopbarVariants;
styles.ModalTopbarVariants & {
onLeftIconClick?: (event: MouseEvent) => void;
onRightIconClick?: (event: MouseEvent) => void;
};

export const ModalTopbar = forwardRef<ModalTopbarProps, 'div'>(
function ModalTopBar(props, ref) {
const { children, layout, className, ...restProps } = props;
const {
layout,
className,
onLeftIconClick,
onRightIconClick,
...restProps
} = props;

const { onClose } = useModalContext();
const { onOpenChange } = useModalContext();

const isCouple = layout !== 'single';

Expand All @@ -29,8 +39,18 @@ export const ModalTopbar = forwardRef<ModalTopbarProps, 'div'>(
className,
)}
>
{isCouple && <Text>{children}</Text>}
<Text onClick={onClose}>닫기</Text>
{isCouple && (
<ChevronLeftIcon
className={styles.modalTopbarIcon}
onClick={onLeftIconClick}
/>
)}
<CloseIcon
className={styles.modalTopbarIcon}
onClick={mergeFns(() => {
onOpenChange(false);
}, onRightIconClick)}
/>
</favolink.div>
);
},
Expand Down
Loading
Loading