Skip to content

Commit

Permalink
feat: 공용 swiper 모듈 구현
Browse files Browse the repository at this point in the history
  • Loading branch information
steven-yn committed Feb 26, 2024
1 parent 8caae55 commit 3ac2aad
Show file tree
Hide file tree
Showing 12 changed files with 253 additions and 55 deletions.
4 changes: 2 additions & 2 deletions src/components/History/History.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import React from 'react';
import OceanSwiper from '../OceanSwiper/OceanSwiper';
import HistorySwiper from '../HistorySwiper/HistorySwiper';

const History = () => {
return (
<section>
<OceanSwiper />
<HistorySwiper />
</section>
);
};
Expand Down
12 changes: 12 additions & 0 deletions src/components/HistorySlideButton/HistorySlideButton.css.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { style, styleVariants } from '@vanilla-extract/css';

export const buttonStyle = style({});

export const iconVariants = styleVariants({
PREV: [{}],
NEXT: [
{
transform: 'rotate(180deg)',
},
],
});
26 changes: 26 additions & 0 deletions src/components/HistorySlideButton/HistorySlideButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
'use client';

import React from 'react';
import CommonIcon from '@/composable/Icon/CommonIcon';
import useOceanSwiperButton from '../../hook/useOceanSwiperButton';
import { iconVariants } from './HistorySlideButton.css';

interface Props {
direction: ButtonDirection;
}

const HistorySlideButton = ({ direction }: Props) => {
const { handleClick } = useOceanSwiperButton(direction);
return (
<button type="button" onClick={handleClick}>
<CommonIcon
className={iconVariants[direction]}
variant="LEFT_ARROW_SECONDARY_VARIANT"
width={24}
height={24}
/>
</button>
);
};

export default HistorySlideButton;
62 changes: 62 additions & 0 deletions src/components/HistorySwiper/HistorySwiper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
'use client';

import 'swiper/css';

import React from 'react';
import HistoryCard from '../Card/History/HistoryCard';
import HistorySlideButton from '../HistorySlideButton/HistorySlideButton';
import HistoryTab from '../HistoryTab/HistoryTab';
import OceanSwiper from '../OceanSwiper/OceanSwiper';

const HistorySwiper = () => {
const mock1 = ['a', 'b', 'c'];
const mock2 = ['d', 'e', 'f'];
const mock3 = ['g', 'h', 'i'];

return (
<OceanSwiper>
<OceanSwiper.Top className="">
<HistorySlideButton direction="PREV" />
<HistoryTab />
<HistorySlideButton direction="NEXT" />
</OceanSwiper.Top>
<OceanSwiper.Main hiddenNavigation>
<OceanSwiper.Slide>
{mock1.map((id) => {
return (
<HistoryCard key={id} visible_status="VISIBLE" sizeToken="LARGE">
<HistoryCard.Company companyName="회사명" />
<HistoryCard.Position positionName="직책명" />
<HistoryCard.Period period="기간" />
</HistoryCard>
);
})}
</OceanSwiper.Slide>
<OceanSwiper.Slide>
{mock2.map((id) => {
return (
<HistoryCard key={id} visible_status="VISIBLE" sizeToken="LARGE">
<HistoryCard.Company companyName="회사명" />
<HistoryCard.Position positionName="직책명" />
<HistoryCard.Period period="기간" />
</HistoryCard>
);
})}
</OceanSwiper.Slide>
<OceanSwiper.Slide>
{mock3.map((id) => {
return (
<HistoryCard key={id} visible_status="VISIBLE" sizeToken="LARGE">
<HistoryCard.Company companyName="회사명" />
<HistoryCard.Position positionName="직책명" />
<HistoryCard.Period period="기간" />
</HistoryCard>
);
})}
</OceanSwiper.Slide>
</OceanSwiper.Main>
</OceanSwiper>
);
};

export default HistorySwiper;
10 changes: 10 additions & 0 deletions src/components/HistoryTab/HistoryTab.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import React from 'react';
import { useOceanSwiperIndex } from '@/hook/useOceanSwiperIndex';

const HistoryTab = () => {
const { readIndex } = useOceanSwiperIndex();

return <div>{readIndex}</div>;
};

export default HistoryTab;
20 changes: 20 additions & 0 deletions src/components/OceanSwiper/OceanSwiper.context.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { createStaticContext } from '@/utils/context/StaticContext';

export interface ContextDispatchOceanSwiperProps {}

interface ContextOceanSwiper {
buttonRefs: {
prev: HTMLButtonElement | null;
next: HTMLButtonElement | null;
};
}

export const ContextDispatchOceanSwiper =
createStaticContext<ContextDispatchOceanSwiperProps>({});

export const ContextValueOceanSwiper = createStaticContext<ContextOceanSwiper>({
buttonRefs: {
prev: null,
next: null,
},
});
97 changes: 61 additions & 36 deletions src/components/OceanSwiper/OceanSwiper.tsx
Original file line number Diff line number Diff line change
@@ -1,45 +1,73 @@
'use client';

import 'swiper/css';

import React, { PropsWithChildren } from 'react';
import React, { PropsWithChildren, useEffect, useRef, useState } from 'react';
import { A11y } from 'swiper/modules';
import { Swiper, SwiperSlide, useSwiper } from 'swiper/react';
import { Swiper, SwiperRef, SwiperSlide, useSwiper } from 'swiper/react';
import { SwiperOptions } from 'swiper/types';
import Tag from '@/composable/Tag/Tag';
import { customEvents } from '@/const/customEvents';
import { getStaticContext } from '@/utils/context/StaticContext';
import {
ContextDispatchOceanSwiper,
ContextValueOceanSwiper,
} from './OceanSwiper.context';

// TODO : 이벤트 위임 구현과 UI 컨트롤 로직을 위한 컨텍스트 API 사용
interface Props {}

const OceanSwiper = ({ children }: PropsWithChildren<Props>) => {
return <div>{children}</div>;
};

const Top = ({ children }: PropsWithChildren) => {
return { children };
const OceanSwiper = ({ children }: PropsWithChildren) => {
return (
<ContextDispatchOceanSwiper.Provider value={{}}>
<ContextValueOceanSwiper.Provider
value={{
buttonRefs: {
prev: null,
next: null,
},
}}
>
<div>{children}</div>
</ContextValueOceanSwiper.Provider>
</ContextDispatchOceanSwiper.Provider>
);
};

interface MainProps extends SwiperOptions {
eventDelegation?: boolean;
prevButton: React.ReactNode;
nextButton: React.ReactNode;
hiddenNavigation?: boolean;
prevButton?: React.ReactNode;
nextButton?: React.ReactNode;
}

const Main = ({
children,
eventDelegation,
hiddenNavigation,
prevButton,
nextButton,
...rest
}: PropsWithChildren<MainProps>) => {
const swiperRef = useRef<SwiperRef | null>(null);

return (
<Swiper {...rest} modules={[A11y]} slidesPerView={1}>
{eventDelegation === true ? (
<Swiper
{...rest}
ref={swiperRef}
modules={[A11y]}
slidesPerView={1}
onRealIndexChange={(e) => {
typeof window !== 'undefined' &&
window.dispatchEvent(
new CustomEvent(customEvents.SWIPER_REAL_INDEX_CHANGE, {
detail: e,
}),
);
}}
>
{hiddenNavigation === true ? (
<OceanSwiper.Button hidden direction="PREV" />
) : (
prevButton
)}
{children}
{eventDelegation === true ? (
{hiddenNavigation === true ? (
<OceanSwiper.Button hidden direction="NEXT" />
) : (
nextButton
Expand All @@ -48,21 +76,6 @@ const Main = ({
);
};

interface SlideProps {
ids: string[];
childs: React.ReactNode[];
}

const Slide = ({ ids, childs }: SlideProps) => {
return (
<div>
{childs.map((child, index) => (
<SwiperSlide key={ids[index]}>{child}</SwiperSlide>
))}
</div>
);
};

interface ButtonProps {
className?: string;
style?: React.CSSProperties;
Expand All @@ -72,17 +85,29 @@ interface ButtonProps {

const Button = ({ className, style, direction, hidden }: ButtonProps) => {
const swiper = useSwiper();

const handleClick = () => {
if (direction === 'PREV') {
swiper.slidePrev();
} else {
swiper.slideNext();
}
};

const { buttonRefs } = getStaticContext(ContextValueOceanSwiper);
const buttonRef = useRef<HTMLButtonElement>(null);

useEffect(() => {
if (direction === 'PREV') {
buttonRefs.prev = buttonRef.current;
} else {
buttonRefs.next = buttonRef.current;
}
}, []);

return (
<button
type="button"
ref={buttonRef}
className={className}
style={style}
hidden={hidden}
Expand All @@ -91,9 +116,9 @@ const Button = ({ className, style, direction, hidden }: ButtonProps) => {
);
};

OceanSwiper.Top = Top;
OceanSwiper.Top = Tag;
OceanSwiper.Main = Main;
OceanSwiper.slide = Slide;
OceanSwiper.Slide = SwiperSlide;
OceanSwiper.Button = Button;

export default OceanSwiper;
17 changes: 0 additions & 17 deletions src/components/OceanSwiper/useOceanSwiperButton.ts

This file was deleted.

3 changes: 3 additions & 0 deletions src/const/customEvents.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const customEvents = {
SWIPER_REAL_INDEX_CHANGE: 'SWIPER_REAL_INDEX_CHANGE',
} as const;
21 changes: 21 additions & 0 deletions src/hook/useEventListener.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import React, { useEffect } from 'react';

const useEventListener = <T extends Event>(
target: EventTarget,
event: string,
callback: (event: T) => void,
options?: boolean | AddEventListenerOptions,
) => {
const eventListener: EventListener = (event: Event) => {
return callback(event as T);
};

useEffect(() => {
target.addEventListener(event, eventListener, options);
return () => {
target.removeEventListener(event, eventListener, options);
};
}, []);
};

export default useEventListener;
18 changes: 18 additions & 0 deletions src/hook/useOceanSwiperButton.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { getStaticContext } from '@/utils/context/StaticContext';
import { ContextValueOceanSwiper } from '../components/OceanSwiper/OceanSwiper.context';

const useOceanSwiperButton = (direction: ButtonDirection) => {
const { buttonRefs } = getStaticContext(ContextValueOceanSwiper);

const handleClick = () => {
if (direction === 'PREV') {
buttonRefs.prev?.click();
} else {
buttonRefs.next?.click();
}
};

return { handleClick };
};

export default useOceanSwiperButton;
18 changes: 18 additions & 0 deletions src/hook/useOceanSwiperIndex.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { useState } from 'react';
import Swiper from 'swiper';
import { customEvents } from '@/const/customEvents';
import useEventListener from './useEventListener';

export const useOceanSwiperIndex = () => {
const [readIndex, setIndex] = useState(0);

useEventListener<CustomEvent<Swiper>>(
window,
customEvents.SWIPER_REAL_INDEX_CHANGE,
(e) => {
setIndex(e.detail.realIndex);
},
);

return { readIndex };
};

0 comments on commit 3ac2aad

Please sign in to comment.