diff --git a/apps/web/package.json b/apps/web/package.json index cf59cfc..95c48a3 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -14,13 +14,14 @@ "@repo/theme": "workspace:^", "@repo/ui": "workspace:^", "next": "14.2.21", + "overlay-kit": "^1.4.1", "react": "^18", "react-dom": "^18" }, "devDependencies": { "@repo/eslint-config": "workspace:*", - "@repo/typescript-config": "workspace:*", "@repo/theme": "workspace:*", + "@repo/typescript-config": "workspace:*", "@repo/ui": "workspace:*", "@types/node": "^20.11.24", "@types/react": "18.3.0", diff --git a/apps/web/src/app/layout.tsx b/apps/web/src/app/layout.tsx index 488ca85..5acbefe 100644 --- a/apps/web/src/app/layout.tsx +++ b/apps/web/src/app/layout.tsx @@ -3,7 +3,7 @@ import localFont from 'next/font/local'; import './globals.css'; import '@repo/theme/styles'; import '@repo/ui/styles'; -import { ThemeProvider } from '@repo/theme'; +import { Providers } from '../components/Providers/Providers'; const geistSans = localFont({ src: './fonts/GeistVF.woff', @@ -29,8 +29,7 @@ export default function RootLayout({ return ( - {children}{' '} - {/** TODO: 추후 시스템 감지 설정 추가 예정 */} + {children} ); diff --git a/apps/web/src/app/page.tsx b/apps/web/src/app/page.tsx index c193fbf..7fe9155 100644 --- a/apps/web/src/app/page.tsx +++ b/apps/web/src/app/page.tsx @@ -1,11 +1,41 @@ -import { Icon, Text } from '@repo/ui'; +'use client'; + +import { Icon, Toast, Text } from '@repo/ui'; +import { overlay } from 'overlay-kit'; + export default function Home() { + const notify1 = () => + overlay.open(({ isOpen, close, unmount }) => ( + } + onExited={unmount} + > + 생성된 본문이 업데이트 됐어요! + + )); + + const notify2 = () => + overlay.open(({ isOpen, close, unmount }) => ( + } + onExited={unmount} + > + 1개 이상의 게시물을 선택해주세요 + + )); + return (
웹 1팀 파이팅! + + hihi diff --git a/apps/web/src/components/Providers/Providers.tsx b/apps/web/src/components/Providers/Providers.tsx new file mode 100644 index 0000000..7bf654f --- /dev/null +++ b/apps/web/src/components/Providers/Providers.tsx @@ -0,0 +1,17 @@ +'use client'; + +import { ThemeProvider } from '@repo/theme'; +import { OverlayProvider } from 'overlay-kit'; +import { ReactNode } from 'react'; + +type ProvidersProps = { + children: ReactNode; +}; + +export function Providers({ children }: ProvidersProps) { + return ( + + {children} + + ); +} diff --git a/packages/theme/src/themes/contract.ts b/packages/theme/src/themes/contract.ts index c8167e1..15132ea 100644 --- a/packages/theme/src/themes/contract.ts +++ b/packages/theme/src/themes/contract.ts @@ -51,6 +51,12 @@ export type ThemeContract = { blue200: string; blue400: string; blue800: string; + + violet0: string; + violet100: string; + violet200: string; + violet400: string; + violet800: string; }; space: { [K in keyof typeof tokens.spacing]: string; diff --git a/packages/theme/src/themes/dark.ts b/packages/theme/src/themes/dark.ts index c95393e..9dcf642 100644 --- a/packages/theme/src/themes/dark.ts +++ b/packages/theme/src/themes/dark.ts @@ -55,6 +55,12 @@ export const darkTheme: ThemeContract = { blue200: tokens.colors.blue200, blue400: tokens.colors.blue400, blue800: tokens.colors.blue800, + + violet0: tokens.colors.violet0, + violet100: tokens.colors.violet100, + violet200: tokens.colors.violet200, + violet400: tokens.colors.violet400, + violet800: tokens.colors.violet800, }, space: tokens.spacing, borderRadius: tokens.radius, diff --git a/packages/theme/src/themes/light.ts b/packages/theme/src/themes/light.ts index ed4537d..7337ae3 100644 --- a/packages/theme/src/themes/light.ts +++ b/packages/theme/src/themes/light.ts @@ -55,6 +55,12 @@ export const lightTheme: ThemeContract = { blue200: tokens.colors.blue200, blue400: tokens.colors.blue400, blue800: tokens.colors.blue800, + + violet0: tokens.colors.violet0, + violet100: tokens.colors.violet100, + violet200: tokens.colors.violet200, + violet400: tokens.colors.violet400, + violet800: tokens.colors.violet800, }, space: tokens.spacing, borderRadius: tokens.radius, diff --git a/packages/theme/src/tokens/colors.ts b/packages/theme/src/tokens/colors.ts index a9e6ebe..280fe26 100644 --- a/packages/theme/src/tokens/colors.ts +++ b/packages/theme/src/tokens/colors.ts @@ -26,6 +26,12 @@ export const colors = { blue400: '#7698E2', blue800: '#153C66', + violet0: '#F2F3FF', + violet100: '#DFE1FE', + violet200: '#B7B4FF', + violet400: '#817ED5', + violet800: '#4A46A3', + grey0: '#FFFFFF', grey25: '#F7F9FB', grey50: '#EAEFF4', diff --git a/packages/ui/esbuild.config.mjs b/packages/ui/esbuild.config.mjs index 31e5e03..508cc3d 100644 --- a/packages/ui/esbuild.config.mjs +++ b/packages/ui/esbuild.config.mjs @@ -20,6 +20,7 @@ const buildOptions = { }), ], loader: { '.css': 'file' }, + allowOverwrite: true, outdir, external: ['react'], }; diff --git a/packages/ui/package.json b/packages/ui/package.json index 492b468..ad8353c 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -21,8 +21,10 @@ }, "dependencies": { "@repo/theme": "workspace:^", + "@types/react-dom": "18.3.1", "@vanilla-extract/css": "^1.17.0", "@vanilla-extract/recipes": "^0.5.5", + "motion": "^11.17.0", "react": "^18" }, "devDependencies": { diff --git a/packages/ui/src/components/Toast/Toast.css.ts b/packages/ui/src/components/Toast/Toast.css.ts new file mode 100644 index 0000000..aff1ee4 --- /dev/null +++ b/packages/ui/src/components/Toast/Toast.css.ts @@ -0,0 +1,24 @@ +import { style } from '@vanilla-extract/css'; +import { tokens } from '@repo/theme'; + +export const container = style({ + position: 'fixed', + bottom: 40, + right: 40, + padding: `${tokens.spacing[20]} ${tokens.spacing[32]}`, + borderRadius: 100, + backgroundColor: tokens.colors.grey700, + color: tokens.colors.grey0, +}); + +export const content = style({ + display: 'flex', + alignItems: 'center', + gap: tokens.spacing[8], +}); + +export const message = style({ + fontSize: tokens.typography.fontSize[20], + fontWeight: tokens.typography.fontWeight.semibold, + lineHeight: '24px', +}); diff --git a/packages/ui/src/components/Toast/Toast.tsx b/packages/ui/src/components/Toast/Toast.tsx new file mode 100644 index 0000000..ab5d776 --- /dev/null +++ b/packages/ui/src/components/Toast/Toast.tsx @@ -0,0 +1,141 @@ +import { motion, AnimatePresence, HTMLMotionProps } from 'motion/react'; +import { + ForwardRefExoticComponent, + ReactNode, + forwardRef, + useEffect, + KeyboardEvent, + useRef, +} from 'react'; +import { ToastIcon } from './compounds/Icon/Icon'; +import * as styles from './Toast.css'; +import { useTimer } from './hooks/useTimer'; +import { mergeRefs } from '@/utils'; + +export type ToastType = 'default' | 'success' | 'error'; + +export type ToastProps = { + /** + * 토스트 타입 + * @default 'default' + */ + toastType?: ToastType; + /** + * 왼쪽 추가 요소 (아이콘 등) + */ + leftAddon?: ReactNode; + /** + * 토스트 지속 시간 + * @default 2000 + */ + duration?: number; + /** + * 자식 요소 + */ + children?: ReactNode; + /** + * 토스트 열기 여부 + */ + open: boolean; + /** + * 토스트가 열릴 때 호출되는 함수 + */ + onOpen?: VoidFunction; + /** + * 토스트가 닫힐 때 호출되는 함수 + */ + onClose?: VoidFunction; + /** + * 토스트가 완전히 닫힌 후 호출되는 함수 + */ + onExited?: VoidFunction; +} & Omit, 'children'>; + +const ToastComponent = forwardRef( + ( + { + toastType = 'default', + leftAddon, + duration = 2000, + children, + open, + onOpen, + onClose, + onExited, + style: toastStyle, + ...restProps + }, + ref + ) => { + const { startCurrentTimer, clearCurrentTimeout } = useTimer({ + onTimerEnd: onClose, + timeoutSecond: duration, + }); + const toastRef = useRef(null); + + useEffect(() => { + if (open) { + onOpen?.(); + startCurrentTimer(); + toastRef.current?.focus(); + } + }, [open, onOpen, startCurrentTimer]); + + const handleKeyDown = (event: KeyboardEvent) => { + if (event.key === 'Escape') { + onClose?.(); + } + }; + + return ( + + {open && ( + +
+ {leftAddon ?? ( +
+
+ )} +
+ ); + } +); + +type ToastComposition = { + Icon: typeof ToastIcon; +}; + +export const Toast: ForwardRefExoticComponent & ToastComposition = + Object.assign(ToastComponent, { + Icon: ToastIcon, + }); + +Toast.displayName = 'Toast'; diff --git a/packages/ui/src/components/Toast/compounds/Icon/Icon.tsx b/packages/ui/src/components/Toast/compounds/Icon/Icon.tsx new file mode 100644 index 0000000..0d074b4 --- /dev/null +++ b/packages/ui/src/components/Toast/compounds/Icon/Icon.tsx @@ -0,0 +1,38 @@ +import { Icon } from '@repo/ui'; +import type { IconProps } from '@repo/ui'; +import { ToastType } from '../../Toast'; + +export type ToastIconProps = Omit & { + toastType?: ToastType; +}; + +export function ToastIcon({ + toastType = 'default', + ...restProps +}: ToastIconProps) { + const iconName = (() => { + switch (toastType) { + case 'success': + return 'check'; + case 'error': + return 'notice'; + default: + return null; + } + })(); + + if (!iconName) { + return null; + } + + const iconColor = (() => { + switch (toastType) { + case 'success': + return 'violet200'; + case 'error': + return 'warning300'; + } + })(); + + return ; +} diff --git a/packages/ui/src/components/Toast/hooks/useTimer.ts b/packages/ui/src/components/Toast/hooks/useTimer.ts new file mode 100644 index 0000000..0499995 --- /dev/null +++ b/packages/ui/src/components/Toast/hooks/useTimer.ts @@ -0,0 +1,42 @@ +import { useRef, useCallback, useEffect } from 'react'; + +type UseTimerParameters = { + onTimerEnd?: () => void; + timeoutSecond?: number; +}; + +export function useTimer({ + onTimerEnd, + timeoutSecond = 3000, +}: UseTimerParameters) { + const timerRef = useRef>(); + + const startCurrentTimer = useCallback(() => { + if (!onTimerEnd) { + return; + } + + timerRef.current = setTimeout(() => { + onTimerEnd(); + }, timeoutSecond); + }, [timeoutSecond, onTimerEnd]); + + const clearCurrentTimeout = useCallback(() => { + if (timerRef.current) { + clearTimeout(timerRef.current); + } + }, []); + + useEffect(() => { + return () => { + if (timerRef.current) { + clearTimeout(timerRef.current); + } + }; + }, [timerRef]); + + return { + startCurrentTimer, + clearCurrentTimeout, + }; +} diff --git a/packages/ui/src/components/Toast/index.ts b/packages/ui/src/components/Toast/index.ts new file mode 100644 index 0000000..7b412d7 --- /dev/null +++ b/packages/ui/src/components/Toast/index.ts @@ -0,0 +1,4 @@ +export { Toast } from './Toast'; +export type { ToastProps, ToastType } from './Toast'; +export { ToastIcon } from './compounds/Icon/Icon'; +export type { ToastIconProps } from './compounds/Icon/Icon'; diff --git a/packages/ui/src/components/index.ts b/packages/ui/src/components/index.ts index dc4ef55..00bc8ba 100644 --- a/packages/ui/src/components/index.ts +++ b/packages/ui/src/components/index.ts @@ -2,5 +2,7 @@ export { Spacing } from './Spacing/Spacing'; export type { SpacingDirection, SpacingProps } from './Spacing/Spacing'; export { Icon } from './Icon/Icon'; export type { IconName, IconProps } from './Icon/Icon'; +export { Toast } from './Toast'; +export type { ToastProps, ToastType, ToastIconProps } from './Toast'; export { Text } from './Text/Text.subComponents'; export type { AllowedTags, TextProps } from './Text/Text'; diff --git a/packages/ui/src/utils/index.ts b/packages/ui/src/utils/index.ts new file mode 100644 index 0000000..7d5fa86 --- /dev/null +++ b/packages/ui/src/utils/index.ts @@ -0,0 +1 @@ +export { mergeRefs } from '@/utils/mergeRefs'; diff --git a/packages/ui/src/utils/mergeRefs.ts b/packages/ui/src/utils/mergeRefs.ts new file mode 100644 index 0000000..ffd63cc --- /dev/null +++ b/packages/ui/src/utils/mergeRefs.ts @@ -0,0 +1,22 @@ +import type { MutableRefObject, LegacyRef, ForwardedRef, Ref } from 'react'; + +export function mergeRefs( + ...refs: Array< + | MutableRefObject + | LegacyRef + | ForwardedRef + | Ref + | undefined + | null + > +): Ref { + return (value) => { + refs.forEach((ref) => { + if (typeof ref === 'function') { + ref(value); + } else if (ref != null) { + (ref as MutableRefObject).current = value; + } + }); + }; +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4020780..47ac5d0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -63,6 +63,9 @@ importers: next: specifier: 14.2.21 version: 14.2.21(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + overlay-kit: + specifier: ^1.4.1 + version: 1.4.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: specifier: ^18 version: 18.3.1 @@ -87,7 +90,7 @@ importers: version: 18.3.1 '@vanilla-extract/next-plugin': specifier: ^2.4.8 - version: 2.4.8(@types/node@20.17.6)(next@14.2.21(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(terser@5.37.0)(webpack@5.97.1) + version: 2.4.8(@types/node@20.17.6)(next@14.2.21(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(webpack@5.97.1) eslint-config-next: specifier: 14.2.21 version: 14.2.21(eslint@9.17.0)(typescript@5.5.4) @@ -169,12 +172,18 @@ importers: '@repo/theme': specifier: workspace:^ version: link:../theme + '@types/react-dom': + specifier: 18.3.1 + version: 18.3.1 '@vanilla-extract/css': specifier: ^1.17.0 version: 1.17.0 '@vanilla-extract/recipes': specifier: ^0.5.5 version: 0.5.5(@vanilla-extract/css@1.17.0) + motion: + specifier: ^11.17.0 + version: 11.17.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: specifier: ^18 version: 18.3.1 @@ -982,6 +991,7 @@ packages: acorn@8.14.0: resolution: {integrity: sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==} engines: {node: '>=0.4.0'} + hasBin: true ajv-formats@2.1.1: resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==} @@ -1594,6 +1604,20 @@ packages: resolution: {integrity: sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==} engines: {node: '>=14'} + framer-motion@11.17.0: + resolution: {integrity: sha512-uTNLH9JPMD3ad14WBt3KYRTR+If4tGPLgKTKTIIPaEBMkvazs6EkWNcmCh65qA/tyinOqIbQiuCorXX0qQsNoQ==} + peerDependencies: + '@emotion/is-prop-valid': '*' + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@emotion/is-prop-valid': + optional: true + react: + optional: true + react-dom: + optional: true + fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -1869,6 +1893,7 @@ packages: js-yaml@4.1.0: resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true jsesc@3.1.0: resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} @@ -1954,6 +1979,7 @@ packages: loose-envify@1.4.0: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + hasBin: true lower-case@2.0.2: resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==} @@ -2017,6 +2043,26 @@ packages: modern-ahocorasick@1.1.0: resolution: {integrity: sha512-sEKPVl2rM+MNVkGQt3ChdmD8YsigmXdn5NifZn6jiwn9LRJpWm8F3guhaqrJT/JOat6pwpbXEk6kv+b9DMIjsQ==} + motion-dom@11.16.4: + resolution: {integrity: sha512-2wuCie206pCiP2K23uvwJeci4pMFfyQKpWI0Vy6HrCTDzDCer4TsYtT7IVnuGbDeoIV37UuZiUr6SZMHEc1Vww==} + + motion-utils@11.16.0: + resolution: {integrity: sha512-ngdWPjg31rD4WGXFi0eZ00DQQqKKu04QExyv/ymlC+3k+WIgYVFbt6gS5JsFPbJODTF/r8XiE/X+SsoT9c0ocw==} + + motion@11.17.0: + resolution: {integrity: sha512-mWZhIOWH2slNXPUWhr6cEu98bl9NMX7u9r7vdNI+Bm3/jrOEa3e44GmyUuwXr9hWR+rWII27YTnKb6CDD1vU2g==} + peerDependencies: + '@emotion/is-prop-valid': '*' + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@emotion/is-prop-valid': + optional: true + react: + optional: true + react-dom: + optional: true + ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} @@ -2103,6 +2149,12 @@ packages: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} + overlay-kit@1.4.1: + resolution: {integrity: sha512-BSzpilw1pM1j6/r04Qwc/FHnWe0Hio0qbhdepJuihx352q+n/FPUAr297MqjKanniH722VDPxFdq7JFjErIXdQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + p-limit@3.1.0: resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} engines: {node: '>=10'} @@ -2179,6 +2231,7 @@ packages: prettier@3.3.3: resolution: {integrity: sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==} engines: {node: '>=14'} + hasBin: true prop-types@15.8.1: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} @@ -2232,9 +2285,11 @@ packages: resolve@1.22.8: resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} + hasBin: true resolve@2.0.0-next.5: resolution: {integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==} + hasBin: true restore-cursor@5.1.0: resolution: {integrity: sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==} @@ -2279,10 +2334,12 @@ packages: semver@6.3.1: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true semver@7.6.3: resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} engines: {node: '>=10'} + hasBin: true serialize-javascript@6.0.2: resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} @@ -2568,6 +2625,11 @@ packages: uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + use-sync-external-store@1.4.0: + resolution: {integrity: sha512-9WXSPC5fMv61vaupRkCKCxsPxBocVnwakBEkMIHHpkTTg6icbJtg6jzgtLDm4bl3cSHAca52rYWih0k4K3PfHw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + v8-compile-cache-lib@3.0.1: resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} @@ -2643,6 +2705,7 @@ packages: which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} + hasBin: true word-wrap@1.2.5: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} @@ -3359,6 +3422,32 @@ snapshots: - supports-color - terser + '@vanilla-extract/integration@7.1.12(@types/node@20.17.6)': + dependencies: + '@babel/core': 7.26.0 + '@babel/plugin-syntax-typescript': 7.25.9(@babel/core@7.26.0) + '@vanilla-extract/babel-plugin-debug-ids': 1.2.0 + '@vanilla-extract/css': 1.17.0 + dedent: 1.5.3 + esbuild: 0.21.5 + eval: 0.1.8 + find-up: 5.0.0 + javascript-stringify: 2.1.0 + mlly: 1.7.3 + vite: 5.4.11(@types/node@20.17.6)(terser@5.37.0) + vite-node: 1.6.0(@types/node@20.17.6)(terser@5.37.0) + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + '@vanilla-extract/integration@7.1.12(@types/node@20.17.6)(terser@5.37.0)': dependencies: '@babel/core': 7.26.0 @@ -3402,9 +3491,9 @@ snapshots: - terser - webpack - '@vanilla-extract/next-plugin@2.4.8(@types/node@20.17.6)(next@14.2.21(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(terser@5.37.0)(webpack@5.97.1)': + '@vanilla-extract/next-plugin@2.4.8(@types/node@20.17.6)(next@14.2.21(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(webpack@5.97.1)': dependencies: - '@vanilla-extract/webpack-plugin': 2.3.16(@types/node@20.17.6)(terser@5.37.0)(webpack@5.97.1) + '@vanilla-extract/webpack-plugin': 2.3.16(@types/node@20.17.6)(webpack@5.97.1) next: 14.2.21(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) transitivePeerDependencies: - '@types/node' @@ -3448,9 +3537,9 @@ snapshots: - supports-color - terser - '@vanilla-extract/webpack-plugin@2.3.16(@types/node@20.17.6)(terser@5.37.0)(webpack@5.97.1)': + '@vanilla-extract/webpack-plugin@2.3.16(@types/node@20.17.6)(webpack@5.97.1)': dependencies: - '@vanilla-extract/integration': 7.1.12(@types/node@20.17.6)(terser@5.37.0) + '@vanilla-extract/integration': 7.1.12(@types/node@20.17.6) debug: 4.4.0 loader-utils: 2.0.4 picocolors: 1.1.1 @@ -4064,7 +4153,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@8.15.0(eslint@9.17.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0)(eslint@9.17.0))(eslint@9.17.0): + eslint-module-utils@2.12.0(@typescript-eslint/parser@8.15.0(eslint@9.17.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0)(eslint@9.17.0): dependencies: debug: 3.2.7 optionalDependencies: @@ -4086,7 +4175,7 @@ snapshots: doctrine: 2.1.0 eslint: 9.17.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.15.0(eslint@9.17.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0)(eslint@9.17.0))(eslint@9.17.0) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.15.0(eslint@9.17.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0)(eslint@9.17.0) hasown: 2.0.2 is-core-module: 2.15.1 is-glob: 4.0.3 @@ -4311,6 +4400,15 @@ snapshots: cross-spawn: 7.0.6 signal-exit: 4.1.0 + framer-motion@11.17.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + dependencies: + motion-dom: 11.16.4 + motion-utils: 11.16.0 + tslib: 2.8.1 + optionalDependencies: + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + fsevents@2.3.3: optional: true @@ -4713,6 +4811,20 @@ snapshots: modern-ahocorasick@1.1.0: {} + motion-dom@11.16.4: + dependencies: + motion-utils: 11.16.0 + + motion-utils@11.16.0: {} + + motion@11.17.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + dependencies: + framer-motion: 11.17.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + tslib: 2.8.1 + optionalDependencies: + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + ms@2.1.3: {} nanoid@3.3.7: {} @@ -4812,6 +4924,12 @@ snapshots: type-check: 0.4.0 word-wrap: 1.2.5 + overlay-kit@1.4.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + dependencies: + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + use-sync-external-store: 1.4.0(react@18.3.1) + p-limit@3.1.0: dependencies: yocto-queue: 0.1.0 @@ -5340,6 +5458,10 @@ snapshots: dependencies: punycode: 2.3.1 + use-sync-external-store@1.4.0(react@18.3.1): + dependencies: + react: 18.3.1 + v8-compile-cache-lib@3.0.1: {} vite-node@1.6.0(@types/node@20.17.12)(terser@5.37.0):