entity-react-modals 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +327 -0
- package/dist/index.cjs +353 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +65 -0
- package/dist/index.d.ts +65 -0
- package/dist/index.js +345 -0
- package/dist/index.js.map +1 -0
- package/dist/styles.css +99 -0
- package/package.json +68 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/ModalContext.tsx","../src/Modal.tsx","../src/ModalTrigger.tsx","../src/spring.ts","../src/animate.ts","../src/hooks/useEscapeKey.ts","../src/hooks/useClickOutside.ts","../src/ModalContent.tsx","../src/ModalClose.tsx","../src/ModalHeader.tsx","../src/ModalBody.tsx","../src/ModalFooter.tsx"],"names":["createContext","useContext","useState","useCallback","jsx","isValidElement","cloneElement","useEffect","useRef","createPortal"],"mappings":"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","file":"index.cjs","sourcesContent":["import { createContext, useContext } from 'react';\nimport type { SpringPreset, SpringConfig } from './spring';\n\nexport interface ModalContextValue {\n open: boolean;\n onClose: () => void;\n onOpen: () => void;\n spring?: SpringPreset | SpringConfig;\n backdropColor?: string;\n backdropBlur?: number;\n size?: 'sm' | 'md' | 'lg' | 'xl';\n animationDuration?: number;\n}\n\nexport const ModalContext = createContext<ModalContextValue | null>(null);\n\nexport function useModalContext() {\n const ctx = useContext(ModalContext);\n if (!ctx) throw new Error('Modal compound components must be used within <Modal>');\n return ctx;\n}\n","import { useState, useCallback, type ReactNode } from 'react';\nimport { ModalContext, type ModalContextValue } from './ModalContext';\nimport type { SpringPreset, SpringConfig } from './spring';\n\nexport interface ModalProps {\n children: ReactNode;\n open?: boolean;\n defaultOpen?: boolean;\n onOpenChange?: (open: boolean) => void;\n spring?: SpringPreset | SpringConfig;\n backdropColor?: string;\n backdropBlur?: number;\n size?: 'sm' | 'md' | 'lg' | 'xl';\n animationDuration?: number;\n}\n\nexport default function Modal({\n children,\n open: controlledOpen,\n defaultOpen = false,\n onOpenChange,\n spring,\n backdropColor,\n backdropBlur,\n size,\n animationDuration,\n}: ModalProps) {\n const [internalOpen, setInternalOpen] = useState(defaultOpen);\n\n const isControlled = controlledOpen !== undefined;\n const open = isControlled ? controlledOpen : internalOpen;\n\n const onClose = useCallback(() => {\n if (isControlled) {\n onOpenChange?.(false);\n } else {\n setInternalOpen(false);\n onOpenChange?.(false);\n }\n }, [isControlled, onOpenChange]);\n\n const onOpen = useCallback(() => {\n if (isControlled) {\n onOpenChange?.(true);\n } else {\n setInternalOpen(true);\n onOpenChange?.(true);\n }\n }, [isControlled, onOpenChange]);\n\n const value: ModalContextValue = {\n open,\n onClose,\n onOpen,\n spring,\n backdropColor,\n backdropBlur,\n size,\n animationDuration,\n };\n\n return <ModalContext.Provider value={value}>{children}</ModalContext.Provider>;\n}\n","import { cloneElement, isValidElement, type ReactNode } from 'react';\nimport { useModalContext } from './ModalContext';\n\nexport interface ModalTriggerProps {\n children: ReactNode;\n}\n\nexport default function ModalTrigger({ children }: ModalTriggerProps) {\n const { onOpen } = useModalContext();\n\n if (!isValidElement(children)) {\n return <button onClick={onOpen}>{children}</button>;\n }\n\n return cloneElement(children as React.ReactElement<Record<string, unknown>>, {\n onClick: (e: React.MouseEvent) => {\n onOpen();\n const existing = (children as React.ReactElement<Record<string, unknown>>).props.onClick;\n if (typeof existing === 'function') existing(e);\n },\n });\n}\n","export interface SpringConfig {\n stiffness: number;\n damping: number;\n mass: number;\n}\n\nexport type SpringPreset = 'default' | 'gentle' | 'wobbly' | 'stiff' | 'slow';\n\nconst PRESETS: Record<SpringPreset, SpringConfig> = {\n default: { stiffness: 100, damping: 10, mass: 1 },\n gentle: { stiffness: 100, damping: 20, mass: 1 },\n wobbly: { stiffness: 200, damping: 10, mass: 1 },\n stiff: { stiffness: 400, damping: 30, mass: 1 },\n slow: { stiffness: 50, damping: 20, mass: 1 },\n};\n\nconst VELOCITY_THRESHOLD = 0.001;\nconst DISPLACEMENT_THRESHOLD = 0.001;\nconst MAX_SIMULATION_STEPS = 1200;\nconst FIXED_DT = 1 / 120;\n\nexport function resolveSpringConfig(input?: SpringPreset | Partial<SpringConfig>): SpringConfig {\n if (!input) return PRESETS.default;\n if (typeof input === 'string') return PRESETS[input] ?? PRESETS.default;\n return { ...PRESETS.default, ...input };\n}\n\nfunction isAtRest(value: number, velocity: number, target: number): boolean {\n return (\n Math.abs(velocity) < VELOCITY_THRESHOLD &&\n Math.abs(value - target) < DISPLACEMENT_THRESHOLD\n );\n}\n\nexport interface GenerateOptions {\n maxDuration?: number;\n}\n\nexport function generateSpringKeyframes(\n from: number,\n to: number,\n config: SpringConfig,\n options?: GenerateOptions,\n): { keyframes: number[]; duration: number } {\n const { stiffness, damping, mass } = config;\n const maxSteps = options?.maxDuration\n ? Math.min(MAX_SIMULATION_STEPS, Math.ceil((options.maxDuration / 1000) / FIXED_DT))\n : MAX_SIMULATION_STEPS;\n\n let value = from;\n let velocity = 0;\n const positions: number[] = [from];\n let steps = 0;\n\n while (steps < maxSteps) {\n if (isAtRest(value, velocity, to)) {\n positions.push(to);\n break;\n }\n\n const displacement = value - to;\n const springForce = -stiffness * displacement;\n const dampingForce = -damping * velocity;\n const acceleration = (springForce + dampingForce) / mass;\n\n velocity += acceleration * FIXED_DT;\n value += velocity * FIXED_DT;\n positions.push(value);\n steps++;\n }\n\n if (steps >= maxSteps) {\n positions.push(to);\n }\n\n const duration = steps * FIXED_DT * 1000;\n return { keyframes: positions, duration };\n}\n\nexport interface WAAPIKeyframeOptions {\n maxDuration?: number;\n}\n\nexport function springToWAAPIKeyframes(\n fromValue: number,\n toValue: number,\n property: 'opacity' | 'transform',\n config: SpringConfig,\n options?: WAAPIKeyframeOptions,\n): { keyframes: Keyframe[]; duration: number } {\n const { keyframes: positions, duration } = generateSpringKeyframes(fromValue, toValue, config, options);\n\n const waapiKeyframes: Keyframe[] = positions.map((pos, i) => {\n const offset = i / (positions.length - 1);\n\n if (property === 'opacity') {\n return { opacity: String(pos), offset } as Keyframe;\n }\n\n const scale = 0.95 + 0.05 * pos;\n return {\n transform: `scale(${scale})`,\n opacity: String(pos),\n offset,\n } as Keyframe;\n });\n\n return { keyframes: waapiKeyframes, duration };\n}\n","import { resolveSpringConfig, springToWAAPIKeyframes, type SpringPreset, type SpringConfig } from './spring';\n\nfunction prefersReducedMotion(): boolean {\n return window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n}\n\nexport interface AnimateConfig {\n spring?: SpringPreset | SpringConfig;\n duration?: number;\n}\n\nconst EXIT_MAX_DURATION = 400;\n\nexport function animateIn(\n backdropEl: HTMLElement,\n panelEl: HTMLElement,\n config?: AnimateConfig,\n): Animation[] {\n if (prefersReducedMotion()) {\n backdropEl.style.opacity = '1';\n panelEl.style.opacity = '1';\n panelEl.style.transform = 'scale(1)';\n return [];\n }\n\n const springConfig = resolveSpringConfig(config?.spring);\n\n const { keyframes: backdropKF, duration: backdropDur } = springToWAAPIKeyframes(0, 1, 'opacity', {\n ...springConfig,\n stiffness: springConfig.stiffness * 0.8,\n });\n\n const { keyframes: panelKF, duration: panelDur } = springToWAAPIKeyframes(0, 1, 'transform', springConfig);\n\n const backdropAnim = backdropEl.animate(backdropKF, {\n duration: backdropDur,\n easing: 'linear',\n fill: 'forwards',\n });\n\n const panelAnim = panelEl.animate(panelKF, {\n duration: panelDur,\n easing: 'linear',\n fill: 'forwards',\n });\n\n return [backdropAnim, panelAnim];\n}\n\nexport function animateOut(\n backdropEl: HTMLElement,\n panelEl: HTMLElement,\n config?: AnimateConfig,\n): Promise<void> {\n if (prefersReducedMotion()) {\n return Promise.resolve();\n }\n\n const springConfig = resolveSpringConfig(config?.spring);\n const exitConfig = {\n stiffness: springConfig.stiffness * 2,\n damping: springConfig.damping * 1.5,\n mass: springConfig.mass,\n };\n\n const { keyframes: backdropKF, duration: backdropDur } = springToWAAPIKeyframes(1, 0, 'opacity', {\n ...exitConfig,\n stiffness: exitConfig.stiffness * 0.8,\n }, { maxDuration: EXIT_MAX_DURATION });\n\n const { keyframes: panelKF, duration: panelDur } = springToWAAPIKeyframes(1, 0, 'transform', exitConfig, {\n maxDuration: EXIT_MAX_DURATION,\n });\n\n const backdropAnim = backdropEl.animate(backdropKF, {\n duration: backdropDur,\n easing: 'linear',\n fill: 'forwards',\n });\n\n const panelAnim = panelEl.animate(panelKF, {\n duration: panelDur,\n easing: 'linear',\n fill: 'forwards',\n });\n\n return Promise.all([backdropAnim.finished, panelAnim.finished]).then(() => {});\n}\n","import { useEffect } from 'react';\n\nexport function useEscapeKey(enabled: boolean, onEscape: () => void) {\n useEffect(() => {\n if (!enabled) return;\n\n function handleKeyDown(e: KeyboardEvent) {\n if (e.key === 'Escape') onEscape();\n }\n\n document.addEventListener('keydown', handleKeyDown);\n return () => document.removeEventListener('keydown', handleKeyDown);\n }, [enabled, onEscape]);\n}\n","import { useEffect, useRef, useCallback } from 'react';\n\nexport function useClickOutside(enabled: boolean, onClick: () => void) {\n const panelRef = useRef<HTMLDivElement>(null);\n\n const handleClick = useCallback(\n (e: MouseEvent) => {\n if (!enabled || !panelRef.current) return;\n if (!panelRef.current.contains(e.target as Node)) {\n onClick();\n }\n },\n [enabled, onClick],\n );\n\n useEffect(() => {\n if (!enabled) return;\n\n document.addEventListener('mousedown', handleClick);\n return () => document.removeEventListener('mousedown', handleClick);\n }, [enabled, handleClick]);\n\n return panelRef;\n}\n","import { useState, useRef, useCallback, useEffect, type MutableRefObject, type ReactNode } from 'react';\nimport { createPortal } from 'react-dom';\nimport { useModalContext } from './ModalContext';\nimport { animateIn, animateOut } from './animate';\nimport { useEscapeKey } from './hooks/useEscapeKey';\nimport { useClickOutside } from './hooks/useClickOutside';\nimport type { SpringPreset, SpringConfig } from './spring';\n\nexport interface ModalContentProps {\n children: ReactNode;\n size?: 'sm' | 'md' | 'lg' | 'xl';\n closeOnBackdropClick?: boolean;\n closeOnEscape?: boolean;\n backdropColor?: string;\n backdropBlur?: number;\n spring?: SpringPreset | SpringConfig;\n animationDuration?: number;\n}\n\nconst SIZE_MAP = {\n sm: '400px',\n md: '560px',\n lg: '720px',\n xl: '900px',\n};\n\nconst SAFETY_UNMOUNT_MS = 600;\n\nexport default function ModalContent({\n children,\n size: sizeProp,\n closeOnBackdropClick = true,\n closeOnEscape = true,\n backdropColor,\n backdropBlur,\n spring,\n animationDuration,\n}: ModalContentProps) {\n const ctx = useModalContext();\n const size = sizeProp ?? ctx.size ?? 'md';\n const resolvedBackdropColor = backdropColor ?? ctx.backdropColor ?? 'rgba(0, 0, 0, 0.6)';\n const resolvedBackdropBlur = backdropBlur ?? ctx.backdropBlur ?? 4;\n const resolvedSpring = spring ?? ctx.spring;\n\n const [render, setRender] = useState(ctx.open);\n\n const backdropRef = useRef<HTMLDivElement>(null);\n const panelRef = useRef<HTMLDivElement>(null);\n const animatingRef = useRef(false);\n const prevOpen = useRef(ctx.open);\n const safetyTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const clearSafetyTimer = useCallback(() => {\n if (safetyTimerRef.current !== null) {\n clearTimeout(safetyTimerRef.current);\n safetyTimerRef.current = null;\n }\n }, []);\n\n const handleClose = useCallback(() => {\n if (animatingRef.current) return;\n ctx.onClose();\n }, [ctx]);\n\n useEscapeKey(closeOnEscape && ctx.open, handleClose);\n const clickOutsideRef = useClickOutside(closeOnBackdropClick && ctx.open, handleClose);\n\n useEffect(() => {\n if (ctx.open && !prevOpen.current) {\n clearSafetyTimer();\n setRender(true);\n animatingRef.current = true;\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n if (backdropRef.current && panelRef.current) {\n animateIn(backdropRef.current, panelRef.current, {\n spring: resolvedSpring,\n duration: animationDuration,\n });\n setTimeout(() => {\n animatingRef.current = false;\n }, 500);\n }\n });\n });\n } else if (!ctx.open && prevOpen.current) {\n animatingRef.current = true;\n\n if (backdropRef.current) {\n backdropRef.current.style.pointerEvents = 'none';\n }\n\n const unmount = () => {\n clearSafetyTimer();\n setRender(false);\n animatingRef.current = false;\n };\n\n safetyTimerRef.current = setTimeout(unmount, SAFETY_UNMOUNT_MS);\n\n if (backdropRef.current && panelRef.current) {\n animateOut(backdropRef.current, panelRef.current, {\n spring: resolvedSpring,\n duration: animationDuration,\n }).then(unmount);\n } else {\n unmount();\n }\n }\n prevOpen.current = ctx.open;\n\n return clearSafetyTimer;\n }, [ctx.open, resolvedSpring, animationDuration, clearSafetyTimer]);\n\n if (!render) return null;\n\n const setRefs = (el: HTMLDivElement | null) => {\n clickOutsideRef.current = el;\n (panelRef as MutableRefObject<HTMLDivElement | null>).current = el;\n };\n\n return createPortal(\n <div\n className=\"rm-backdrop\"\n ref={backdropRef}\n style={{\n background: resolvedBackdropColor,\n backdropFilter: `blur(${resolvedBackdropBlur}px)`,\n WebkitBackdropFilter: `blur(${resolvedBackdropBlur}px)`,\n }}\n >\n <div\n ref={setRefs}\n className={`rm-panel rm-panel--${size}`}\n role=\"dialog\"\n aria-modal=\"true\"\n style={{ maxWidth: SIZE_MAP[size] }}\n >\n {children}\n </div>\n </div>,\n document.body,\n );\n}\n","import { type ReactNode } from 'react';\nimport { useModalContext } from './ModalContext';\n\nexport interface ModalCloseProps {\n children?: ReactNode;\n className?: string;\n}\n\nexport default function ModalClose({ children = '×', className }: ModalCloseProps) {\n const { onClose } = useModalContext();\n\n return (\n <button className={`rm-close ${className ?? ''}`} onClick={onClose} aria-label=\"Close\">\n {children}\n </button>\n );\n}\n","import type { ReactNode } from 'react';\n\nexport interface ModalHeaderProps {\n children: ReactNode;\n className?: string;\n}\n\nexport default function ModalHeader({ children, className }: ModalHeaderProps) {\n return <div className={`rm-header ${className ?? ''}`}>{children}</div>;\n}\n","import type { ReactNode } from 'react';\n\nexport interface ModalBodyProps {\n children: ReactNode;\n className?: string;\n}\n\nexport default function ModalBody({ children, className }: ModalBodyProps) {\n return <div className={`rm-body ${className ?? ''}`}>{children}</div>;\n}\n","import type { ReactNode } from 'react';\n\nexport interface ModalFooterProps {\n children: ReactNode;\n className?: string;\n}\n\nexport default function ModalFooter({ children, className }: ModalFooterProps) {\n return <div className={`rm-footer ${className ?? ''}`}>{children}</div>;\n}\n"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
interface SpringConfig {
|
|
5
|
+
stiffness: number;
|
|
6
|
+
damping: number;
|
|
7
|
+
mass: number;
|
|
8
|
+
}
|
|
9
|
+
type SpringPreset = 'default' | 'gentle' | 'wobbly' | 'stiff' | 'slow';
|
|
10
|
+
|
|
11
|
+
interface ModalProps {
|
|
12
|
+
children: ReactNode;
|
|
13
|
+
open?: boolean;
|
|
14
|
+
defaultOpen?: boolean;
|
|
15
|
+
onOpenChange?: (open: boolean) => void;
|
|
16
|
+
spring?: SpringPreset | SpringConfig;
|
|
17
|
+
backdropColor?: string;
|
|
18
|
+
backdropBlur?: number;
|
|
19
|
+
size?: 'sm' | 'md' | 'lg' | 'xl';
|
|
20
|
+
animationDuration?: number;
|
|
21
|
+
}
|
|
22
|
+
declare function Modal({ children, open: controlledOpen, defaultOpen, onOpenChange, spring, backdropColor, backdropBlur, size, animationDuration, }: ModalProps): react.JSX.Element;
|
|
23
|
+
|
|
24
|
+
interface ModalTriggerProps {
|
|
25
|
+
children: ReactNode;
|
|
26
|
+
}
|
|
27
|
+
declare function ModalTrigger({ children }: ModalTriggerProps): react.JSX.Element;
|
|
28
|
+
|
|
29
|
+
interface ModalContentProps {
|
|
30
|
+
children: ReactNode;
|
|
31
|
+
size?: 'sm' | 'md' | 'lg' | 'xl';
|
|
32
|
+
closeOnBackdropClick?: boolean;
|
|
33
|
+
closeOnEscape?: boolean;
|
|
34
|
+
backdropColor?: string;
|
|
35
|
+
backdropBlur?: number;
|
|
36
|
+
spring?: SpringPreset | SpringConfig;
|
|
37
|
+
animationDuration?: number;
|
|
38
|
+
}
|
|
39
|
+
declare function ModalContent({ children, size: sizeProp, closeOnBackdropClick, closeOnEscape, backdropColor, backdropBlur, spring, animationDuration, }: ModalContentProps): react.ReactPortal | null;
|
|
40
|
+
|
|
41
|
+
interface ModalCloseProps {
|
|
42
|
+
children?: ReactNode;
|
|
43
|
+
className?: string;
|
|
44
|
+
}
|
|
45
|
+
declare function ModalClose({ children, className }: ModalCloseProps): react.JSX.Element;
|
|
46
|
+
|
|
47
|
+
interface ModalHeaderProps {
|
|
48
|
+
children: ReactNode;
|
|
49
|
+
className?: string;
|
|
50
|
+
}
|
|
51
|
+
declare function ModalHeader({ children, className }: ModalHeaderProps): react.JSX.Element;
|
|
52
|
+
|
|
53
|
+
interface ModalBodyProps {
|
|
54
|
+
children: ReactNode;
|
|
55
|
+
className?: string;
|
|
56
|
+
}
|
|
57
|
+
declare function ModalBody({ children, className }: ModalBodyProps): react.JSX.Element;
|
|
58
|
+
|
|
59
|
+
interface ModalFooterProps {
|
|
60
|
+
children: ReactNode;
|
|
61
|
+
className?: string;
|
|
62
|
+
}
|
|
63
|
+
declare function ModalFooter({ children, className }: ModalFooterProps): react.JSX.Element;
|
|
64
|
+
|
|
65
|
+
export { Modal, ModalBody, type ModalBodyProps, ModalClose, type ModalCloseProps, ModalContent, type ModalContentProps, ModalFooter, type ModalFooterProps, ModalHeader, type ModalHeaderProps, type ModalProps, ModalTrigger, type ModalTriggerProps, type SpringConfig, type SpringPreset };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
interface SpringConfig {
|
|
5
|
+
stiffness: number;
|
|
6
|
+
damping: number;
|
|
7
|
+
mass: number;
|
|
8
|
+
}
|
|
9
|
+
type SpringPreset = 'default' | 'gentle' | 'wobbly' | 'stiff' | 'slow';
|
|
10
|
+
|
|
11
|
+
interface ModalProps {
|
|
12
|
+
children: ReactNode;
|
|
13
|
+
open?: boolean;
|
|
14
|
+
defaultOpen?: boolean;
|
|
15
|
+
onOpenChange?: (open: boolean) => void;
|
|
16
|
+
spring?: SpringPreset | SpringConfig;
|
|
17
|
+
backdropColor?: string;
|
|
18
|
+
backdropBlur?: number;
|
|
19
|
+
size?: 'sm' | 'md' | 'lg' | 'xl';
|
|
20
|
+
animationDuration?: number;
|
|
21
|
+
}
|
|
22
|
+
declare function Modal({ children, open: controlledOpen, defaultOpen, onOpenChange, spring, backdropColor, backdropBlur, size, animationDuration, }: ModalProps): react.JSX.Element;
|
|
23
|
+
|
|
24
|
+
interface ModalTriggerProps {
|
|
25
|
+
children: ReactNode;
|
|
26
|
+
}
|
|
27
|
+
declare function ModalTrigger({ children }: ModalTriggerProps): react.JSX.Element;
|
|
28
|
+
|
|
29
|
+
interface ModalContentProps {
|
|
30
|
+
children: ReactNode;
|
|
31
|
+
size?: 'sm' | 'md' | 'lg' | 'xl';
|
|
32
|
+
closeOnBackdropClick?: boolean;
|
|
33
|
+
closeOnEscape?: boolean;
|
|
34
|
+
backdropColor?: string;
|
|
35
|
+
backdropBlur?: number;
|
|
36
|
+
spring?: SpringPreset | SpringConfig;
|
|
37
|
+
animationDuration?: number;
|
|
38
|
+
}
|
|
39
|
+
declare function ModalContent({ children, size: sizeProp, closeOnBackdropClick, closeOnEscape, backdropColor, backdropBlur, spring, animationDuration, }: ModalContentProps): react.ReactPortal | null;
|
|
40
|
+
|
|
41
|
+
interface ModalCloseProps {
|
|
42
|
+
children?: ReactNode;
|
|
43
|
+
className?: string;
|
|
44
|
+
}
|
|
45
|
+
declare function ModalClose({ children, className }: ModalCloseProps): react.JSX.Element;
|
|
46
|
+
|
|
47
|
+
interface ModalHeaderProps {
|
|
48
|
+
children: ReactNode;
|
|
49
|
+
className?: string;
|
|
50
|
+
}
|
|
51
|
+
declare function ModalHeader({ children, className }: ModalHeaderProps): react.JSX.Element;
|
|
52
|
+
|
|
53
|
+
interface ModalBodyProps {
|
|
54
|
+
children: ReactNode;
|
|
55
|
+
className?: string;
|
|
56
|
+
}
|
|
57
|
+
declare function ModalBody({ children, className }: ModalBodyProps): react.JSX.Element;
|
|
58
|
+
|
|
59
|
+
interface ModalFooterProps {
|
|
60
|
+
children: ReactNode;
|
|
61
|
+
className?: string;
|
|
62
|
+
}
|
|
63
|
+
declare function ModalFooter({ children, className }: ModalFooterProps): react.JSX.Element;
|
|
64
|
+
|
|
65
|
+
export { Modal, ModalBody, type ModalBodyProps, ModalClose, type ModalCloseProps, ModalContent, type ModalContentProps, ModalFooter, type ModalFooterProps, ModalHeader, type ModalHeaderProps, type ModalProps, ModalTrigger, type ModalTriggerProps, type SpringConfig, type SpringPreset };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
import { createContext, useState, useCallback, isValidElement, cloneElement, useRef, useEffect, useContext } from 'react';
|
|
2
|
+
import { jsx } from 'react/jsx-runtime';
|
|
3
|
+
import { createPortal } from 'react-dom';
|
|
4
|
+
|
|
5
|
+
// src/Modal.tsx
|
|
6
|
+
var ModalContext = createContext(null);
|
|
7
|
+
function useModalContext() {
|
|
8
|
+
const ctx = useContext(ModalContext);
|
|
9
|
+
if (!ctx) throw new Error("Modal compound components must be used within <Modal>");
|
|
10
|
+
return ctx;
|
|
11
|
+
}
|
|
12
|
+
function Modal({
|
|
13
|
+
children,
|
|
14
|
+
open: controlledOpen,
|
|
15
|
+
defaultOpen = false,
|
|
16
|
+
onOpenChange,
|
|
17
|
+
spring,
|
|
18
|
+
backdropColor,
|
|
19
|
+
backdropBlur,
|
|
20
|
+
size,
|
|
21
|
+
animationDuration
|
|
22
|
+
}) {
|
|
23
|
+
const [internalOpen, setInternalOpen] = useState(defaultOpen);
|
|
24
|
+
const isControlled = controlledOpen !== void 0;
|
|
25
|
+
const open = isControlled ? controlledOpen : internalOpen;
|
|
26
|
+
const onClose = useCallback(() => {
|
|
27
|
+
if (isControlled) {
|
|
28
|
+
onOpenChange?.(false);
|
|
29
|
+
} else {
|
|
30
|
+
setInternalOpen(false);
|
|
31
|
+
onOpenChange?.(false);
|
|
32
|
+
}
|
|
33
|
+
}, [isControlled, onOpenChange]);
|
|
34
|
+
const onOpen = useCallback(() => {
|
|
35
|
+
if (isControlled) {
|
|
36
|
+
onOpenChange?.(true);
|
|
37
|
+
} else {
|
|
38
|
+
setInternalOpen(true);
|
|
39
|
+
onOpenChange?.(true);
|
|
40
|
+
}
|
|
41
|
+
}, [isControlled, onOpenChange]);
|
|
42
|
+
const value = {
|
|
43
|
+
open,
|
|
44
|
+
onClose,
|
|
45
|
+
onOpen,
|
|
46
|
+
spring,
|
|
47
|
+
backdropColor,
|
|
48
|
+
backdropBlur,
|
|
49
|
+
size,
|
|
50
|
+
animationDuration
|
|
51
|
+
};
|
|
52
|
+
return /* @__PURE__ */ jsx(ModalContext.Provider, { value, children });
|
|
53
|
+
}
|
|
54
|
+
function ModalTrigger({ children }) {
|
|
55
|
+
const { onOpen } = useModalContext();
|
|
56
|
+
if (!isValidElement(children)) {
|
|
57
|
+
return /* @__PURE__ */ jsx("button", { onClick: onOpen, children });
|
|
58
|
+
}
|
|
59
|
+
return cloneElement(children, {
|
|
60
|
+
onClick: (e) => {
|
|
61
|
+
onOpen();
|
|
62
|
+
const existing = children.props.onClick;
|
|
63
|
+
if (typeof existing === "function") existing(e);
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// src/spring.ts
|
|
69
|
+
var PRESETS = {
|
|
70
|
+
default: { stiffness: 100, damping: 10, mass: 1 },
|
|
71
|
+
gentle: { stiffness: 100, damping: 20, mass: 1 },
|
|
72
|
+
wobbly: { stiffness: 200, damping: 10, mass: 1 },
|
|
73
|
+
stiff: { stiffness: 400, damping: 30, mass: 1 },
|
|
74
|
+
slow: { stiffness: 50, damping: 20, mass: 1 }
|
|
75
|
+
};
|
|
76
|
+
var VELOCITY_THRESHOLD = 1e-3;
|
|
77
|
+
var DISPLACEMENT_THRESHOLD = 1e-3;
|
|
78
|
+
var MAX_SIMULATION_STEPS = 1200;
|
|
79
|
+
var FIXED_DT = 1 / 120;
|
|
80
|
+
function resolveSpringConfig(input) {
|
|
81
|
+
if (!input) return PRESETS.default;
|
|
82
|
+
if (typeof input === "string") return PRESETS[input] ?? PRESETS.default;
|
|
83
|
+
return { ...PRESETS.default, ...input };
|
|
84
|
+
}
|
|
85
|
+
function isAtRest(value, velocity, target) {
|
|
86
|
+
return Math.abs(velocity) < VELOCITY_THRESHOLD && Math.abs(value - target) < DISPLACEMENT_THRESHOLD;
|
|
87
|
+
}
|
|
88
|
+
function generateSpringKeyframes(from, to, config, options) {
|
|
89
|
+
const { stiffness, damping, mass } = config;
|
|
90
|
+
const maxSteps = options?.maxDuration ? Math.min(MAX_SIMULATION_STEPS, Math.ceil(options.maxDuration / 1e3 / FIXED_DT)) : MAX_SIMULATION_STEPS;
|
|
91
|
+
let value = from;
|
|
92
|
+
let velocity = 0;
|
|
93
|
+
const positions = [from];
|
|
94
|
+
let steps = 0;
|
|
95
|
+
while (steps < maxSteps) {
|
|
96
|
+
if (isAtRest(value, velocity, to)) {
|
|
97
|
+
positions.push(to);
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
const displacement = value - to;
|
|
101
|
+
const springForce = -stiffness * displacement;
|
|
102
|
+
const dampingForce = -damping * velocity;
|
|
103
|
+
const acceleration = (springForce + dampingForce) / mass;
|
|
104
|
+
velocity += acceleration * FIXED_DT;
|
|
105
|
+
value += velocity * FIXED_DT;
|
|
106
|
+
positions.push(value);
|
|
107
|
+
steps++;
|
|
108
|
+
}
|
|
109
|
+
if (steps >= maxSteps) {
|
|
110
|
+
positions.push(to);
|
|
111
|
+
}
|
|
112
|
+
const duration = steps * FIXED_DT * 1e3;
|
|
113
|
+
return { keyframes: positions, duration };
|
|
114
|
+
}
|
|
115
|
+
function springToWAAPIKeyframes(fromValue, toValue, property, config, options) {
|
|
116
|
+
const { keyframes: positions, duration } = generateSpringKeyframes(fromValue, toValue, config, options);
|
|
117
|
+
const waapiKeyframes = positions.map((pos, i) => {
|
|
118
|
+
const offset = i / (positions.length - 1);
|
|
119
|
+
if (property === "opacity") {
|
|
120
|
+
return { opacity: String(pos), offset };
|
|
121
|
+
}
|
|
122
|
+
const scale = 0.95 + 0.05 * pos;
|
|
123
|
+
return {
|
|
124
|
+
transform: `scale(${scale})`,
|
|
125
|
+
opacity: String(pos),
|
|
126
|
+
offset
|
|
127
|
+
};
|
|
128
|
+
});
|
|
129
|
+
return { keyframes: waapiKeyframes, duration };
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// src/animate.ts
|
|
133
|
+
function prefersReducedMotion() {
|
|
134
|
+
return window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
135
|
+
}
|
|
136
|
+
var EXIT_MAX_DURATION = 400;
|
|
137
|
+
function animateIn(backdropEl, panelEl, config) {
|
|
138
|
+
if (prefersReducedMotion()) {
|
|
139
|
+
backdropEl.style.opacity = "1";
|
|
140
|
+
panelEl.style.opacity = "1";
|
|
141
|
+
panelEl.style.transform = "scale(1)";
|
|
142
|
+
return [];
|
|
143
|
+
}
|
|
144
|
+
const springConfig = resolveSpringConfig(config?.spring);
|
|
145
|
+
const { keyframes: backdropKF, duration: backdropDur } = springToWAAPIKeyframes(0, 1, "opacity", {
|
|
146
|
+
...springConfig,
|
|
147
|
+
stiffness: springConfig.stiffness * 0.8
|
|
148
|
+
});
|
|
149
|
+
const { keyframes: panelKF, duration: panelDur } = springToWAAPIKeyframes(0, 1, "transform", springConfig);
|
|
150
|
+
const backdropAnim = backdropEl.animate(backdropKF, {
|
|
151
|
+
duration: backdropDur,
|
|
152
|
+
easing: "linear",
|
|
153
|
+
fill: "forwards"
|
|
154
|
+
});
|
|
155
|
+
const panelAnim = panelEl.animate(panelKF, {
|
|
156
|
+
duration: panelDur,
|
|
157
|
+
easing: "linear",
|
|
158
|
+
fill: "forwards"
|
|
159
|
+
});
|
|
160
|
+
return [backdropAnim, panelAnim];
|
|
161
|
+
}
|
|
162
|
+
function animateOut(backdropEl, panelEl, config) {
|
|
163
|
+
if (prefersReducedMotion()) {
|
|
164
|
+
return Promise.resolve();
|
|
165
|
+
}
|
|
166
|
+
const springConfig = resolveSpringConfig(config?.spring);
|
|
167
|
+
const exitConfig = {
|
|
168
|
+
stiffness: springConfig.stiffness * 2,
|
|
169
|
+
damping: springConfig.damping * 1.5,
|
|
170
|
+
mass: springConfig.mass
|
|
171
|
+
};
|
|
172
|
+
const { keyframes: backdropKF, duration: backdropDur } = springToWAAPIKeyframes(1, 0, "opacity", {
|
|
173
|
+
...exitConfig,
|
|
174
|
+
stiffness: exitConfig.stiffness * 0.8
|
|
175
|
+
}, { maxDuration: EXIT_MAX_DURATION });
|
|
176
|
+
const { keyframes: panelKF, duration: panelDur } = springToWAAPIKeyframes(1, 0, "transform", exitConfig, {
|
|
177
|
+
maxDuration: EXIT_MAX_DURATION
|
|
178
|
+
});
|
|
179
|
+
const backdropAnim = backdropEl.animate(backdropKF, {
|
|
180
|
+
duration: backdropDur,
|
|
181
|
+
easing: "linear",
|
|
182
|
+
fill: "forwards"
|
|
183
|
+
});
|
|
184
|
+
const panelAnim = panelEl.animate(panelKF, {
|
|
185
|
+
duration: panelDur,
|
|
186
|
+
easing: "linear",
|
|
187
|
+
fill: "forwards"
|
|
188
|
+
});
|
|
189
|
+
return Promise.all([backdropAnim.finished, panelAnim.finished]).then(() => {
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
function useEscapeKey(enabled, onEscape) {
|
|
193
|
+
useEffect(() => {
|
|
194
|
+
if (!enabled) return;
|
|
195
|
+
function handleKeyDown(e) {
|
|
196
|
+
if (e.key === "Escape") onEscape();
|
|
197
|
+
}
|
|
198
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
199
|
+
return () => document.removeEventListener("keydown", handleKeyDown);
|
|
200
|
+
}, [enabled, onEscape]);
|
|
201
|
+
}
|
|
202
|
+
function useClickOutside(enabled, onClick) {
|
|
203
|
+
const panelRef = useRef(null);
|
|
204
|
+
const handleClick = useCallback(
|
|
205
|
+
(e) => {
|
|
206
|
+
if (!enabled || !panelRef.current) return;
|
|
207
|
+
if (!panelRef.current.contains(e.target)) {
|
|
208
|
+
onClick();
|
|
209
|
+
}
|
|
210
|
+
},
|
|
211
|
+
[enabled, onClick]
|
|
212
|
+
);
|
|
213
|
+
useEffect(() => {
|
|
214
|
+
if (!enabled) return;
|
|
215
|
+
document.addEventListener("mousedown", handleClick);
|
|
216
|
+
return () => document.removeEventListener("mousedown", handleClick);
|
|
217
|
+
}, [enabled, handleClick]);
|
|
218
|
+
return panelRef;
|
|
219
|
+
}
|
|
220
|
+
var SIZE_MAP = {
|
|
221
|
+
sm: "400px",
|
|
222
|
+
md: "560px",
|
|
223
|
+
lg: "720px",
|
|
224
|
+
xl: "900px"
|
|
225
|
+
};
|
|
226
|
+
var SAFETY_UNMOUNT_MS = 600;
|
|
227
|
+
function ModalContent({
|
|
228
|
+
children,
|
|
229
|
+
size: sizeProp,
|
|
230
|
+
closeOnBackdropClick = true,
|
|
231
|
+
closeOnEscape = true,
|
|
232
|
+
backdropColor,
|
|
233
|
+
backdropBlur,
|
|
234
|
+
spring,
|
|
235
|
+
animationDuration
|
|
236
|
+
}) {
|
|
237
|
+
const ctx = useModalContext();
|
|
238
|
+
const size = sizeProp ?? ctx.size ?? "md";
|
|
239
|
+
const resolvedBackdropColor = backdropColor ?? ctx.backdropColor ?? "rgba(0, 0, 0, 0.6)";
|
|
240
|
+
const resolvedBackdropBlur = backdropBlur ?? ctx.backdropBlur ?? 4;
|
|
241
|
+
const resolvedSpring = spring ?? ctx.spring;
|
|
242
|
+
const [render, setRender] = useState(ctx.open);
|
|
243
|
+
const backdropRef = useRef(null);
|
|
244
|
+
const panelRef = useRef(null);
|
|
245
|
+
const animatingRef = useRef(false);
|
|
246
|
+
const prevOpen = useRef(ctx.open);
|
|
247
|
+
const safetyTimerRef = useRef(null);
|
|
248
|
+
const clearSafetyTimer = useCallback(() => {
|
|
249
|
+
if (safetyTimerRef.current !== null) {
|
|
250
|
+
clearTimeout(safetyTimerRef.current);
|
|
251
|
+
safetyTimerRef.current = null;
|
|
252
|
+
}
|
|
253
|
+
}, []);
|
|
254
|
+
const handleClose = useCallback(() => {
|
|
255
|
+
if (animatingRef.current) return;
|
|
256
|
+
ctx.onClose();
|
|
257
|
+
}, [ctx]);
|
|
258
|
+
useEscapeKey(closeOnEscape && ctx.open, handleClose);
|
|
259
|
+
const clickOutsideRef = useClickOutside(closeOnBackdropClick && ctx.open, handleClose);
|
|
260
|
+
useEffect(() => {
|
|
261
|
+
if (ctx.open && !prevOpen.current) {
|
|
262
|
+
clearSafetyTimer();
|
|
263
|
+
setRender(true);
|
|
264
|
+
animatingRef.current = true;
|
|
265
|
+
requestAnimationFrame(() => {
|
|
266
|
+
requestAnimationFrame(() => {
|
|
267
|
+
if (backdropRef.current && panelRef.current) {
|
|
268
|
+
animateIn(backdropRef.current, panelRef.current, {
|
|
269
|
+
spring: resolvedSpring});
|
|
270
|
+
setTimeout(() => {
|
|
271
|
+
animatingRef.current = false;
|
|
272
|
+
}, 500);
|
|
273
|
+
}
|
|
274
|
+
});
|
|
275
|
+
});
|
|
276
|
+
} else if (!ctx.open && prevOpen.current) {
|
|
277
|
+
animatingRef.current = true;
|
|
278
|
+
if (backdropRef.current) {
|
|
279
|
+
backdropRef.current.style.pointerEvents = "none";
|
|
280
|
+
}
|
|
281
|
+
const unmount = () => {
|
|
282
|
+
clearSafetyTimer();
|
|
283
|
+
setRender(false);
|
|
284
|
+
animatingRef.current = false;
|
|
285
|
+
};
|
|
286
|
+
safetyTimerRef.current = setTimeout(unmount, SAFETY_UNMOUNT_MS);
|
|
287
|
+
if (backdropRef.current && panelRef.current) {
|
|
288
|
+
animateOut(backdropRef.current, panelRef.current, {
|
|
289
|
+
spring: resolvedSpring}).then(unmount);
|
|
290
|
+
} else {
|
|
291
|
+
unmount();
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
prevOpen.current = ctx.open;
|
|
295
|
+
return clearSafetyTimer;
|
|
296
|
+
}, [ctx.open, resolvedSpring, animationDuration, clearSafetyTimer]);
|
|
297
|
+
if (!render) return null;
|
|
298
|
+
const setRefs = (el) => {
|
|
299
|
+
clickOutsideRef.current = el;
|
|
300
|
+
panelRef.current = el;
|
|
301
|
+
};
|
|
302
|
+
return createPortal(
|
|
303
|
+
/* @__PURE__ */ jsx(
|
|
304
|
+
"div",
|
|
305
|
+
{
|
|
306
|
+
className: "rm-backdrop",
|
|
307
|
+
ref: backdropRef,
|
|
308
|
+
style: {
|
|
309
|
+
background: resolvedBackdropColor,
|
|
310
|
+
backdropFilter: `blur(${resolvedBackdropBlur}px)`,
|
|
311
|
+
WebkitBackdropFilter: `blur(${resolvedBackdropBlur}px)`
|
|
312
|
+
},
|
|
313
|
+
children: /* @__PURE__ */ jsx(
|
|
314
|
+
"div",
|
|
315
|
+
{
|
|
316
|
+
ref: setRefs,
|
|
317
|
+
className: `rm-panel rm-panel--${size}`,
|
|
318
|
+
role: "dialog",
|
|
319
|
+
"aria-modal": "true",
|
|
320
|
+
style: { maxWidth: SIZE_MAP[size] },
|
|
321
|
+
children
|
|
322
|
+
}
|
|
323
|
+
)
|
|
324
|
+
}
|
|
325
|
+
),
|
|
326
|
+
document.body
|
|
327
|
+
);
|
|
328
|
+
}
|
|
329
|
+
function ModalClose({ children = "\xD7", className }) {
|
|
330
|
+
const { onClose } = useModalContext();
|
|
331
|
+
return /* @__PURE__ */ jsx("button", { className: `rm-close ${className ?? ""}`, onClick: onClose, "aria-label": "Close", children });
|
|
332
|
+
}
|
|
333
|
+
function ModalHeader({ children, className }) {
|
|
334
|
+
return /* @__PURE__ */ jsx("div", { className: `rm-header ${className ?? ""}`, children });
|
|
335
|
+
}
|
|
336
|
+
function ModalBody({ children, className }) {
|
|
337
|
+
return /* @__PURE__ */ jsx("div", { className: `rm-body ${className ?? ""}`, children });
|
|
338
|
+
}
|
|
339
|
+
function ModalFooter({ children, className }) {
|
|
340
|
+
return /* @__PURE__ */ jsx("div", { className: `rm-footer ${className ?? ""}`, children });
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
export { Modal, ModalBody, ModalClose, ModalContent, ModalFooter, ModalHeader, ModalTrigger };
|
|
344
|
+
//# sourceMappingURL=index.js.map
|
|
345
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/ModalContext.tsx","../src/Modal.tsx","../src/ModalTrigger.tsx","../src/spring.ts","../src/animate.ts","../src/hooks/useEscapeKey.ts","../src/hooks/useClickOutside.ts","../src/ModalContent.tsx","../src/ModalClose.tsx","../src/ModalHeader.tsx","../src/ModalBody.tsx","../src/ModalFooter.tsx"],"names":["jsx","useCallback","useEffect","useState","useRef"],"mappings":"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","file":"index.js","sourcesContent":["import { createContext, useContext } from 'react';\nimport type { SpringPreset, SpringConfig } from './spring';\n\nexport interface ModalContextValue {\n open: boolean;\n onClose: () => void;\n onOpen: () => void;\n spring?: SpringPreset | SpringConfig;\n backdropColor?: string;\n backdropBlur?: number;\n size?: 'sm' | 'md' | 'lg' | 'xl';\n animationDuration?: number;\n}\n\nexport const ModalContext = createContext<ModalContextValue | null>(null);\n\nexport function useModalContext() {\n const ctx = useContext(ModalContext);\n if (!ctx) throw new Error('Modal compound components must be used within <Modal>');\n return ctx;\n}\n","import { useState, useCallback, type ReactNode } from 'react';\nimport { ModalContext, type ModalContextValue } from './ModalContext';\nimport type { SpringPreset, SpringConfig } from './spring';\n\nexport interface ModalProps {\n children: ReactNode;\n open?: boolean;\n defaultOpen?: boolean;\n onOpenChange?: (open: boolean) => void;\n spring?: SpringPreset | SpringConfig;\n backdropColor?: string;\n backdropBlur?: number;\n size?: 'sm' | 'md' | 'lg' | 'xl';\n animationDuration?: number;\n}\n\nexport default function Modal({\n children,\n open: controlledOpen,\n defaultOpen = false,\n onOpenChange,\n spring,\n backdropColor,\n backdropBlur,\n size,\n animationDuration,\n}: ModalProps) {\n const [internalOpen, setInternalOpen] = useState(defaultOpen);\n\n const isControlled = controlledOpen !== undefined;\n const open = isControlled ? controlledOpen : internalOpen;\n\n const onClose = useCallback(() => {\n if (isControlled) {\n onOpenChange?.(false);\n } else {\n setInternalOpen(false);\n onOpenChange?.(false);\n }\n }, [isControlled, onOpenChange]);\n\n const onOpen = useCallback(() => {\n if (isControlled) {\n onOpenChange?.(true);\n } else {\n setInternalOpen(true);\n onOpenChange?.(true);\n }\n }, [isControlled, onOpenChange]);\n\n const value: ModalContextValue = {\n open,\n onClose,\n onOpen,\n spring,\n backdropColor,\n backdropBlur,\n size,\n animationDuration,\n };\n\n return <ModalContext.Provider value={value}>{children}</ModalContext.Provider>;\n}\n","import { cloneElement, isValidElement, type ReactNode } from 'react';\nimport { useModalContext } from './ModalContext';\n\nexport interface ModalTriggerProps {\n children: ReactNode;\n}\n\nexport default function ModalTrigger({ children }: ModalTriggerProps) {\n const { onOpen } = useModalContext();\n\n if (!isValidElement(children)) {\n return <button onClick={onOpen}>{children}</button>;\n }\n\n return cloneElement(children as React.ReactElement<Record<string, unknown>>, {\n onClick: (e: React.MouseEvent) => {\n onOpen();\n const existing = (children as React.ReactElement<Record<string, unknown>>).props.onClick;\n if (typeof existing === 'function') existing(e);\n },\n });\n}\n","export interface SpringConfig {\n stiffness: number;\n damping: number;\n mass: number;\n}\n\nexport type SpringPreset = 'default' | 'gentle' | 'wobbly' | 'stiff' | 'slow';\n\nconst PRESETS: Record<SpringPreset, SpringConfig> = {\n default: { stiffness: 100, damping: 10, mass: 1 },\n gentle: { stiffness: 100, damping: 20, mass: 1 },\n wobbly: { stiffness: 200, damping: 10, mass: 1 },\n stiff: { stiffness: 400, damping: 30, mass: 1 },\n slow: { stiffness: 50, damping: 20, mass: 1 },\n};\n\nconst VELOCITY_THRESHOLD = 0.001;\nconst DISPLACEMENT_THRESHOLD = 0.001;\nconst MAX_SIMULATION_STEPS = 1200;\nconst FIXED_DT = 1 / 120;\n\nexport function resolveSpringConfig(input?: SpringPreset | Partial<SpringConfig>): SpringConfig {\n if (!input) return PRESETS.default;\n if (typeof input === 'string') return PRESETS[input] ?? PRESETS.default;\n return { ...PRESETS.default, ...input };\n}\n\nfunction isAtRest(value: number, velocity: number, target: number): boolean {\n return (\n Math.abs(velocity) < VELOCITY_THRESHOLD &&\n Math.abs(value - target) < DISPLACEMENT_THRESHOLD\n );\n}\n\nexport interface GenerateOptions {\n maxDuration?: number;\n}\n\nexport function generateSpringKeyframes(\n from: number,\n to: number,\n config: SpringConfig,\n options?: GenerateOptions,\n): { keyframes: number[]; duration: number } {\n const { stiffness, damping, mass } = config;\n const maxSteps = options?.maxDuration\n ? Math.min(MAX_SIMULATION_STEPS, Math.ceil((options.maxDuration / 1000) / FIXED_DT))\n : MAX_SIMULATION_STEPS;\n\n let value = from;\n let velocity = 0;\n const positions: number[] = [from];\n let steps = 0;\n\n while (steps < maxSteps) {\n if (isAtRest(value, velocity, to)) {\n positions.push(to);\n break;\n }\n\n const displacement = value - to;\n const springForce = -stiffness * displacement;\n const dampingForce = -damping * velocity;\n const acceleration = (springForce + dampingForce) / mass;\n\n velocity += acceleration * FIXED_DT;\n value += velocity * FIXED_DT;\n positions.push(value);\n steps++;\n }\n\n if (steps >= maxSteps) {\n positions.push(to);\n }\n\n const duration = steps * FIXED_DT * 1000;\n return { keyframes: positions, duration };\n}\n\nexport interface WAAPIKeyframeOptions {\n maxDuration?: number;\n}\n\nexport function springToWAAPIKeyframes(\n fromValue: number,\n toValue: number,\n property: 'opacity' | 'transform',\n config: SpringConfig,\n options?: WAAPIKeyframeOptions,\n): { keyframes: Keyframe[]; duration: number } {\n const { keyframes: positions, duration } = generateSpringKeyframes(fromValue, toValue, config, options);\n\n const waapiKeyframes: Keyframe[] = positions.map((pos, i) => {\n const offset = i / (positions.length - 1);\n\n if (property === 'opacity') {\n return { opacity: String(pos), offset } as Keyframe;\n }\n\n const scale = 0.95 + 0.05 * pos;\n return {\n transform: `scale(${scale})`,\n opacity: String(pos),\n offset,\n } as Keyframe;\n });\n\n return { keyframes: waapiKeyframes, duration };\n}\n","import { resolveSpringConfig, springToWAAPIKeyframes, type SpringPreset, type SpringConfig } from './spring';\n\nfunction prefersReducedMotion(): boolean {\n return window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n}\n\nexport interface AnimateConfig {\n spring?: SpringPreset | SpringConfig;\n duration?: number;\n}\n\nconst EXIT_MAX_DURATION = 400;\n\nexport function animateIn(\n backdropEl: HTMLElement,\n panelEl: HTMLElement,\n config?: AnimateConfig,\n): Animation[] {\n if (prefersReducedMotion()) {\n backdropEl.style.opacity = '1';\n panelEl.style.opacity = '1';\n panelEl.style.transform = 'scale(1)';\n return [];\n }\n\n const springConfig = resolveSpringConfig(config?.spring);\n\n const { keyframes: backdropKF, duration: backdropDur } = springToWAAPIKeyframes(0, 1, 'opacity', {\n ...springConfig,\n stiffness: springConfig.stiffness * 0.8,\n });\n\n const { keyframes: panelKF, duration: panelDur } = springToWAAPIKeyframes(0, 1, 'transform', springConfig);\n\n const backdropAnim = backdropEl.animate(backdropKF, {\n duration: backdropDur,\n easing: 'linear',\n fill: 'forwards',\n });\n\n const panelAnim = panelEl.animate(panelKF, {\n duration: panelDur,\n easing: 'linear',\n fill: 'forwards',\n });\n\n return [backdropAnim, panelAnim];\n}\n\nexport function animateOut(\n backdropEl: HTMLElement,\n panelEl: HTMLElement,\n config?: AnimateConfig,\n): Promise<void> {\n if (prefersReducedMotion()) {\n return Promise.resolve();\n }\n\n const springConfig = resolveSpringConfig(config?.spring);\n const exitConfig = {\n stiffness: springConfig.stiffness * 2,\n damping: springConfig.damping * 1.5,\n mass: springConfig.mass,\n };\n\n const { keyframes: backdropKF, duration: backdropDur } = springToWAAPIKeyframes(1, 0, 'opacity', {\n ...exitConfig,\n stiffness: exitConfig.stiffness * 0.8,\n }, { maxDuration: EXIT_MAX_DURATION });\n\n const { keyframes: panelKF, duration: panelDur } = springToWAAPIKeyframes(1, 0, 'transform', exitConfig, {\n maxDuration: EXIT_MAX_DURATION,\n });\n\n const backdropAnim = backdropEl.animate(backdropKF, {\n duration: backdropDur,\n easing: 'linear',\n fill: 'forwards',\n });\n\n const panelAnim = panelEl.animate(panelKF, {\n duration: panelDur,\n easing: 'linear',\n fill: 'forwards',\n });\n\n return Promise.all([backdropAnim.finished, panelAnim.finished]).then(() => {});\n}\n","import { useEffect } from 'react';\n\nexport function useEscapeKey(enabled: boolean, onEscape: () => void) {\n useEffect(() => {\n if (!enabled) return;\n\n function handleKeyDown(e: KeyboardEvent) {\n if (e.key === 'Escape') onEscape();\n }\n\n document.addEventListener('keydown', handleKeyDown);\n return () => document.removeEventListener('keydown', handleKeyDown);\n }, [enabled, onEscape]);\n}\n","import { useEffect, useRef, useCallback } from 'react';\n\nexport function useClickOutside(enabled: boolean, onClick: () => void) {\n const panelRef = useRef<HTMLDivElement>(null);\n\n const handleClick = useCallback(\n (e: MouseEvent) => {\n if (!enabled || !panelRef.current) return;\n if (!panelRef.current.contains(e.target as Node)) {\n onClick();\n }\n },\n [enabled, onClick],\n );\n\n useEffect(() => {\n if (!enabled) return;\n\n document.addEventListener('mousedown', handleClick);\n return () => document.removeEventListener('mousedown', handleClick);\n }, [enabled, handleClick]);\n\n return panelRef;\n}\n","import { useState, useRef, useCallback, useEffect, type MutableRefObject, type ReactNode } from 'react';\nimport { createPortal } from 'react-dom';\nimport { useModalContext } from './ModalContext';\nimport { animateIn, animateOut } from './animate';\nimport { useEscapeKey } from './hooks/useEscapeKey';\nimport { useClickOutside } from './hooks/useClickOutside';\nimport type { SpringPreset, SpringConfig } from './spring';\n\nexport interface ModalContentProps {\n children: ReactNode;\n size?: 'sm' | 'md' | 'lg' | 'xl';\n closeOnBackdropClick?: boolean;\n closeOnEscape?: boolean;\n backdropColor?: string;\n backdropBlur?: number;\n spring?: SpringPreset | SpringConfig;\n animationDuration?: number;\n}\n\nconst SIZE_MAP = {\n sm: '400px',\n md: '560px',\n lg: '720px',\n xl: '900px',\n};\n\nconst SAFETY_UNMOUNT_MS = 600;\n\nexport default function ModalContent({\n children,\n size: sizeProp,\n closeOnBackdropClick = true,\n closeOnEscape = true,\n backdropColor,\n backdropBlur,\n spring,\n animationDuration,\n}: ModalContentProps) {\n const ctx = useModalContext();\n const size = sizeProp ?? ctx.size ?? 'md';\n const resolvedBackdropColor = backdropColor ?? ctx.backdropColor ?? 'rgba(0, 0, 0, 0.6)';\n const resolvedBackdropBlur = backdropBlur ?? ctx.backdropBlur ?? 4;\n const resolvedSpring = spring ?? ctx.spring;\n\n const [render, setRender] = useState(ctx.open);\n\n const backdropRef = useRef<HTMLDivElement>(null);\n const panelRef = useRef<HTMLDivElement>(null);\n const animatingRef = useRef(false);\n const prevOpen = useRef(ctx.open);\n const safetyTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const clearSafetyTimer = useCallback(() => {\n if (safetyTimerRef.current !== null) {\n clearTimeout(safetyTimerRef.current);\n safetyTimerRef.current = null;\n }\n }, []);\n\n const handleClose = useCallback(() => {\n if (animatingRef.current) return;\n ctx.onClose();\n }, [ctx]);\n\n useEscapeKey(closeOnEscape && ctx.open, handleClose);\n const clickOutsideRef = useClickOutside(closeOnBackdropClick && ctx.open, handleClose);\n\n useEffect(() => {\n if (ctx.open && !prevOpen.current) {\n clearSafetyTimer();\n setRender(true);\n animatingRef.current = true;\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n if (backdropRef.current && panelRef.current) {\n animateIn(backdropRef.current, panelRef.current, {\n spring: resolvedSpring,\n duration: animationDuration,\n });\n setTimeout(() => {\n animatingRef.current = false;\n }, 500);\n }\n });\n });\n } else if (!ctx.open && prevOpen.current) {\n animatingRef.current = true;\n\n if (backdropRef.current) {\n backdropRef.current.style.pointerEvents = 'none';\n }\n\n const unmount = () => {\n clearSafetyTimer();\n setRender(false);\n animatingRef.current = false;\n };\n\n safetyTimerRef.current = setTimeout(unmount, SAFETY_UNMOUNT_MS);\n\n if (backdropRef.current && panelRef.current) {\n animateOut(backdropRef.current, panelRef.current, {\n spring: resolvedSpring,\n duration: animationDuration,\n }).then(unmount);\n } else {\n unmount();\n }\n }\n prevOpen.current = ctx.open;\n\n return clearSafetyTimer;\n }, [ctx.open, resolvedSpring, animationDuration, clearSafetyTimer]);\n\n if (!render) return null;\n\n const setRefs = (el: HTMLDivElement | null) => {\n clickOutsideRef.current = el;\n (panelRef as MutableRefObject<HTMLDivElement | null>).current = el;\n };\n\n return createPortal(\n <div\n className=\"rm-backdrop\"\n ref={backdropRef}\n style={{\n background: resolvedBackdropColor,\n backdropFilter: `blur(${resolvedBackdropBlur}px)`,\n WebkitBackdropFilter: `blur(${resolvedBackdropBlur}px)`,\n }}\n >\n <div\n ref={setRefs}\n className={`rm-panel rm-panel--${size}`}\n role=\"dialog\"\n aria-modal=\"true\"\n style={{ maxWidth: SIZE_MAP[size] }}\n >\n {children}\n </div>\n </div>,\n document.body,\n );\n}\n","import { type ReactNode } from 'react';\nimport { useModalContext } from './ModalContext';\n\nexport interface ModalCloseProps {\n children?: ReactNode;\n className?: string;\n}\n\nexport default function ModalClose({ children = '×', className }: ModalCloseProps) {\n const { onClose } = useModalContext();\n\n return (\n <button className={`rm-close ${className ?? ''}`} onClick={onClose} aria-label=\"Close\">\n {children}\n </button>\n );\n}\n","import type { ReactNode } from 'react';\n\nexport interface ModalHeaderProps {\n children: ReactNode;\n className?: string;\n}\n\nexport default function ModalHeader({ children, className }: ModalHeaderProps) {\n return <div className={`rm-header ${className ?? ''}`}>{children}</div>;\n}\n","import type { ReactNode } from 'react';\n\nexport interface ModalBodyProps {\n children: ReactNode;\n className?: string;\n}\n\nexport default function ModalBody({ children, className }: ModalBodyProps) {\n return <div className={`rm-body ${className ?? ''}`}>{children}</div>;\n}\n","import type { ReactNode } from 'react';\n\nexport interface ModalFooterProps {\n children: ReactNode;\n className?: string;\n}\n\nexport default function ModalFooter({ children, className }: ModalFooterProps) {\n return <div className={`rm-footer ${className ?? ''}`}>{children}</div>;\n}\n"]}
|