@hunterchen/canvas 0.8.0 → 0.9.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/dist/components/canvas/backgrounds.js +67 -38
- package/dist/components/canvas/backgrounds.js.map +1 -1
- package/dist/components/canvas/canvas.js +451 -387
- package/dist/components/canvas/canvas.js.map +1 -1
- package/dist/components/canvas/component.js +108 -174
- package/dist/components/canvas/component.js.map +1 -1
- package/dist/components/canvas/draggable.js +168 -151
- package/dist/components/canvas/draggable.js.map +1 -1
- package/dist/components/canvas/navbar/index.js +164 -142
- package/dist/components/canvas/navbar/index.js.map +1 -1
- package/dist/components/canvas/navbar/single-button.js +176 -149
- package/dist/components/canvas/navbar/single-button.js.map +1 -1
- package/dist/components/canvas/toolbar.js +121 -82
- package/dist/components/canvas/toolbar.js.map +1 -1
- package/dist/components/canvas/wrapper.js +127 -99
- package/dist/components/canvas/wrapper.js.map +1 -1
- package/dist/contexts/CanvasContext.js +25 -17
- package/dist/contexts/CanvasContext.js.map +1 -1
- package/dist/contexts/PerformanceContext.js +51 -50
- package/dist/contexts/PerformanceContext.js.map +1 -1
- package/dist/hooks/usePerformanceMode.js +36 -37
- package/dist/hooks/usePerformanceMode.js.map +1 -1
- package/dist/hooks/useWindowDimensions.js +22 -18
- package/dist/hooks/useWindowDimensions.js.map +1 -1
- package/dist/index.js +17 -21
- package/dist/lib/canvas.js +65 -72
- package/dist/lib/canvas.js.map +1 -1
- package/dist/lib/constants.js +78 -92
- package/dist/lib/constants.js.map +1 -1
- package/dist/lib/utils.js +10 -5
- package/dist/lib/utils.js.map +1 -1
- package/dist/utils/performance.js +18 -23
- package/dist/utils/performance.js.map +1 -1
- package/package.json +7 -21
- package/dist/components/canvas/offest.js +0 -12
- package/dist/components/canvas/offest.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/types/index.js +0 -6
- package/dist/types/index.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toolbar.js","
|
|
1
|
+
{"version":3,"file":"toolbar.js","names":[],"sources":["../../../src/components/canvas/toolbar.tsx"],"sourcesContent":["import { type Point, useTransform, motion } from \"framer-motion\";\nimport { useEffect, useState, useMemo } from \"react\";\nimport { useCanvasContext } from \"../../contexts/CanvasContext\";\nimport {\n TOOLBAR_OPACITY_POS_EPS,\n TOOLBAR_OPACITY_SCALE_EPS,\n} from \"../../lib/constants\";\nimport { cn } from \"../../lib/utils\";\nimport type { ToolbarConfig, ToolbarPosition } from \"../../types\";\n\ntype ToolbarProps = {\n homeCoordinates?: Point;\n config?: ToolbarConfig;\n};\n\nconst positionStyles: Record<ToolbarPosition, string> = {\n \"top-left\": \"left-4 top-6 sm:top-4\",\n \"top-right\": \"right-4 top-6 sm:top-4\",\n \"bottom-left\": \"left-4 bottom-6 sm:bottom-4\",\n \"bottom-right\": \"right-4 bottom-6 sm:bottom-4\",\n};\n\nconst Toolbar = ({\n homeCoordinates = { x: 0, y: 0 },\n config = {},\n}: ToolbarProps) => {\n const { x, y, scale } = useCanvasContext();\n const [hasMounted, setHasMounted] = useState(false);\n\n const {\n display = \"both\",\n position = \"top-left\",\n disableAutoHide = false,\n className,\n coordinatesClassName,\n scaleClassName,\n separatorClassName,\n style,\n coordinatesStyle,\n scaleStyle,\n separator = \"|\",\n separatorGap,\n coordinatesFormat,\n scaleFormat,\n } = config;\n\n const separatorStyle: React.CSSProperties | undefined = separatorGap\n ? {\n marginInline:\n typeof separatorGap === \"number\" ? `${separatorGap}px` : separatorGap,\n }\n : undefined;\n\n useEffect(() => {\n setHasMounted(true);\n }, []);\n\n // numeric MotionValues\n const rawDx = useTransform(\n [x, scale],\n ([lx, ls]) => -((lx as number) / (ls as number)) + homeCoordinates.x\n );\n const rawDy = useTransform(\n [y, scale],\n ([ly, ls]) => -((ly as number) / (ls as number)) + homeCoordinates.y\n );\n\n // formatted MotionValues for default display\n const displayX = useTransform(rawDx, (v) => Math.round(v).toString());\n const displayY = useTransform(rawDy, (v) => Math.round(v).toString());\n const displayScale = useTransform(scale, (v) => v.toFixed(2));\n\n // For custom formatters, we need to use state to track values\n const [currentX, setCurrentX] = useState(0);\n const [currentY, setCurrentY] = useState(0);\n const [currentScale, setCurrentScale] = useState(1);\n\n useEffect(() => {\n const unsubX = rawDx.on(\"change\", (v) => setCurrentX(Math.round(v)));\n const unsubY = rawDy.on(\"change\", (v) => setCurrentY(Math.round(v)));\n const unsubScale = scale.on(\"change\", (v) => setCurrentScale(v));\n return () => {\n unsubX();\n unsubY();\n unsubScale();\n };\n }, [rawDx, rawDy, scale]);\n\n const opacity = useTransform([rawDx, rawDy, scale], ([dx, dy, ls]) => {\n if (disableAutoHide) return 1;\n return Math.abs(dx as number) < TOOLBAR_OPACITY_POS_EPS &&\n Math.abs(dy as number) < TOOLBAR_OPACITY_POS_EPS &&\n Math.abs((ls as number) - 1) < TOOLBAR_OPACITY_SCALE_EPS\n ? 0\n : 1;\n });\n\n const handlePointerDown = (e: React.PointerEvent) => e.stopPropagation();\n\n const showCoordinates = display === \"coordinates\" || display === \"both\";\n const showScale = display === \"scale\" || display === \"both\";\n const showSeparator = display === \"both\";\n\n // Compute formatted values\n const formattedCoordinates = useMemo(() => {\n if (coordinatesFormat) {\n return coordinatesFormat(currentX, currentY);\n }\n return null; // Will use motion spans for default\n }, [coordinatesFormat, currentX, currentY]);\n\n const formattedScale = useMemo(() => {\n if (scaleFormat) {\n return scaleFormat(currentScale);\n }\n return null; // Will use motion span for default\n }, [scaleFormat, currentScale]);\n\n // Placeholder content for SSR/initial render\n const placeholderContent = useMemo(() => {\n const parts: string[] = [];\n if (showCoordinates) parts.push(\"(0, 0)\");\n if (showSeparator) parts.push(separator);\n if (showScale) parts.push(\"1.00x\");\n return parts.join(\"\");\n }, [showCoordinates, showScale, showSeparator, separator]);\n\n return (\n <motion.div\n className={cn(\n \"absolute z-[1000] cursor-default select-none rounded-[10px] border border-border bg-canvas-offwhite p-2 font-mono text-xs text-canvas-heavy shadow-[0_6px_12px_rgba(0,0,0,0.10)] md:text-sm\",\n positionStyles[position],\n className\n )}\n onPointerDown={handlePointerDown}\n data-toolbar-button\n style={{ opacity, ...style }}\n >\n {hasMounted ? (\n <>\n {showCoordinates && (\n <span className={coordinatesClassName} style={coordinatesStyle}>\n {formattedCoordinates !== null ? (\n formattedCoordinates\n ) : (\n <>\n (<motion.span>{displayX}</motion.span>,{\" \"}\n <motion.span>{displayY}</motion.span>)\n </>\n )}\n </span>\n )}\n {showSeparator && (\n <span\n className={cn(\"text-canvas-light\", separatorClassName)}\n style={separatorStyle}\n >\n {separator}\n </span>\n )}\n {showScale && (\n <span className={scaleClassName} style={scaleStyle}>\n {formattedScale !== null ? (\n formattedScale\n ) : (\n <>\n <motion.span>{displayScale}</motion.span>x\n </>\n )}\n </span>\n )}\n </>\n ) : (\n <span style={{ opacity: 0 }}>{placeholderContent}</span>\n )}\n </motion.div>\n );\n};\n\nexport default Toolbar;\n"],"mappings":"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"}
|
|
@@ -1,102 +1,130 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { BLUR_TRANSITION, GROW_TRANSITION, INTRO_ASPECT_RATIO, MAX_DIM_RATIO } from "../../lib/constants.js";
|
|
2
2
|
import { motion } from "framer-motion";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
3
|
+
import { useEffect, useRef, useState } from "react";
|
|
4
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
|
|
6
|
+
//#region src/components/canvas/wrapper.tsx
|
|
7
|
+
const CanvasWrapper = ({ children, introProgress, onIntroGrowComplete, skipIntro = false, introContent, loadingText = "LOADING CANVAS", introBackgroundGradient = "linear-gradient(to top, #d4d4d4 0%, #e5e5e5 50%, #f5f5f5 100%)", wrapperBackground, canvasBoxGradient = "radial-gradient(130.38% 95% at 50.03% 97.25%, #d4d4d4 0%, #e5e5e5 48.09%, #f5f5f5 100%)", growTransition = GROW_TRANSITION, blurTransition = BLUR_TRANSITION }) => {
|
|
8
|
+
const [dimensions, setDimensions] = useState(null);
|
|
9
|
+
const [dots, setDots] = useState("..");
|
|
10
|
+
const [stage1NotFinished, setStage1NotFinished] = useState(true);
|
|
11
|
+
const completedRef = useRef(false);
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
if (skipIntro && !completedRef.current) {
|
|
14
|
+
completedRef.current = true;
|
|
15
|
+
introProgress.set(1);
|
|
16
|
+
onIntroGrowComplete?.();
|
|
17
|
+
}
|
|
18
|
+
}, [
|
|
19
|
+
skipIntro,
|
|
20
|
+
introProgress,
|
|
21
|
+
onIntroGrowComplete
|
|
22
|
+
]);
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
if (skipIntro) return;
|
|
25
|
+
const interval = setInterval(() => {
|
|
26
|
+
setDots((prevDots) => {
|
|
27
|
+
if (prevDots.length < 3) return prevDots + ".";
|
|
28
|
+
else return ".";
|
|
29
|
+
});
|
|
30
|
+
}, 500);
|
|
31
|
+
return () => clearInterval(interval);
|
|
32
|
+
}, [skipIntro]);
|
|
33
|
+
useEffect(() => {
|
|
34
|
+
if (skipIntro) return;
|
|
35
|
+
const calculateInitialSize = () => {
|
|
36
|
+
const vw = window.innerWidth;
|
|
37
|
+
const vh = window.innerHeight;
|
|
38
|
+
const maxWidth = vw * MAX_DIM_RATIO.width;
|
|
39
|
+
const maxHeight = vh * MAX_DIM_RATIO.height;
|
|
40
|
+
if (maxWidth / INTRO_ASPECT_RATIO <= maxHeight) return {
|
|
41
|
+
width: maxWidth,
|
|
42
|
+
height: maxWidth / INTRO_ASPECT_RATIO
|
|
43
|
+
};
|
|
44
|
+
else return {
|
|
45
|
+
height: maxHeight,
|
|
46
|
+
width: maxHeight * INTRO_ASPECT_RATIO
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
setDimensions(calculateInitialSize());
|
|
50
|
+
}, [skipIntro]);
|
|
51
|
+
if (skipIntro) return /* @__PURE__ */ jsx(motion.div, {
|
|
52
|
+
className: "fixed inset-0 overflow-hidden",
|
|
53
|
+
style: {
|
|
54
|
+
touchAction: "none",
|
|
55
|
+
userSelect: "none",
|
|
56
|
+
pointerEvents: "none"
|
|
57
|
+
},
|
|
58
|
+
onContextMenu: (e) => e.preventDefault(),
|
|
59
|
+
children
|
|
60
|
+
});
|
|
61
|
+
return /* @__PURE__ */ jsxs(motion.div, {
|
|
62
|
+
className: "fixed inset-0 overflow-hidden",
|
|
63
|
+
style: {
|
|
64
|
+
backgroundImage: stage1NotFinished && !wrapperBackground ? introBackgroundGradient : void 0,
|
|
65
|
+
touchAction: "none",
|
|
66
|
+
userSelect: "none",
|
|
67
|
+
pointerEvents: "none"
|
|
68
|
+
},
|
|
69
|
+
onContextMenu: (e) => e.preventDefault(),
|
|
70
|
+
children: [
|
|
71
|
+
stage1NotFinished && wrapperBackground,
|
|
72
|
+
stage1NotFinished && /* @__PURE__ */ jsx(Fragment, { children: introContent }),
|
|
73
|
+
dimensions && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(motion.div, {
|
|
74
|
+
initial: {
|
|
75
|
+
width: dimensions.width,
|
|
76
|
+
height: dimensions.height,
|
|
77
|
+
opacity: 1,
|
|
78
|
+
backgroundImage: canvasBoxGradient
|
|
79
|
+
},
|
|
80
|
+
animate: {
|
|
81
|
+
opacity: 0,
|
|
82
|
+
display: "none"
|
|
83
|
+
},
|
|
84
|
+
transition: blurTransition,
|
|
85
|
+
className: "absolute left-1/2 top-1/2 z-20 origin-center -translate-x-1/2 -translate-y-1/2 overflow-hidden rounded-lg"
|
|
86
|
+
}), /* @__PURE__ */ jsx(motion.div, {
|
|
87
|
+
initial: {
|
|
88
|
+
width: dimensions.width,
|
|
89
|
+
height: dimensions.height
|
|
90
|
+
},
|
|
91
|
+
animate: {
|
|
92
|
+
width: "100vw",
|
|
93
|
+
height: "100vh"
|
|
94
|
+
},
|
|
95
|
+
transition: growTransition,
|
|
96
|
+
onUpdate: (latest) => {
|
|
97
|
+
if (completedRef.current) return;
|
|
98
|
+
if (typeof latest.width === "number") {
|
|
99
|
+
const w0 = dimensions.width;
|
|
100
|
+
const w1 = window.innerWidth;
|
|
101
|
+
const progress = w1 === w0 ? 1 : (latest.width - w0) / (w1 - w0);
|
|
102
|
+
const clamped = Math.min(Math.max(progress, 0), 1);
|
|
103
|
+
introProgress.set(clamped);
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
onAnimationComplete: () => {
|
|
107
|
+
if (!completedRef.current) {
|
|
108
|
+
completedRef.current = true;
|
|
109
|
+
introProgress.set(1);
|
|
110
|
+
setStage1NotFinished(false);
|
|
111
|
+
onIntroGrowComplete?.();
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
className: "absolute left-1/2 top-1/2 z-10 origin-center -translate-x-1/2 -translate-y-1/2 overflow-hidden rounded-lg shadow-[0_20px_40px_rgba(103,86,86,0.15)]",
|
|
115
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
116
|
+
className: "h-full w-full",
|
|
117
|
+
children
|
|
118
|
+
})
|
|
119
|
+
})] }),
|
|
120
|
+
stage1NotFinished && loadingText && /* @__PURE__ */ jsxs("div", {
|
|
121
|
+
className: "absolute bottom-24 left-1/2 -translate-x-1/2 text-center font-mono font-semibold text-neutral-500",
|
|
122
|
+
children: [loadingText, dots]
|
|
123
|
+
})
|
|
124
|
+
]
|
|
125
|
+
});
|
|
101
126
|
};
|
|
127
|
+
|
|
128
|
+
//#endregion
|
|
129
|
+
export { CanvasWrapper };
|
|
102
130
|
//# sourceMappingURL=wrapper.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wrapper.js","
|
|
1
|
+
{"version":3,"file":"wrapper.js","names":[],"sources":["../../../src/components/canvas/wrapper.tsx"],"sourcesContent":["import { motion, type MotionValue, type Transition, useMotionValue } from \"framer-motion\";\nimport { useState, useEffect, useRef, type ReactNode } from \"react\";\nimport {\n MAX_DIM_RATIO,\n GROW_TRANSITION,\n BLUR_TRANSITION,\n INTRO_ASPECT_RATIO,\n} from \"../../lib/constants\";\n\n// Re-export for backward compatibility\nexport { GROW_TRANSITION as growTransition } from \"../../lib/constants\";\n\ninterface CanvasWrapperProps {\n children: React.ReactNode;\n /** Shared progress MV (0->1) for the grow animation */\n introProgress: MotionValue<number>;\n /** Callback when the grow (stage1) completes */\n onIntroGrowComplete?: () => void;\n\n // ============== Intro Customization ==============\n /** Disable intro animation entirely (starts at full size) */\n skipIntro?: boolean;\n /** Custom intro content to show during loading */\n introContent?: ReactNode;\n /** Custom loading text (default: \"LOADING CANVAS\") */\n loadingText?: string;\n /** Background gradient for intro screen (CSS gradient string) */\n introBackgroundGradient?: string;\n /** Custom wrapper background component (overrides introBackgroundGradient if provided) */\n wrapperBackground?: ReactNode;\n /** Canvas box gradient for blur mask */\n canvasBoxGradient?: string;\n /** Grow animation transition config */\n growTransition?: Transition;\n /** Blur animation transition config */\n blurTransition?: Transition;\n}\n\nexport const CanvasWrapper = ({\n children,\n introProgress,\n onIntroGrowComplete,\n skipIntro = false,\n introContent,\n loadingText = \"LOADING CANVAS\",\n introBackgroundGradient = \"linear-gradient(to top, #d4d4d4 0%, #e5e5e5 50%, #f5f5f5 100%)\",\n wrapperBackground,\n canvasBoxGradient = \"radial-gradient(130.38% 95% at 50.03% 97.25%, #d4d4d4 0%, #e5e5e5 48.09%, #f5f5f5 100%)\",\n growTransition = GROW_TRANSITION,\n blurTransition = BLUR_TRANSITION,\n}: CanvasWrapperProps) => {\n const [dimensions, setDimensions] = useState<{\n width: number;\n height: number;\n } | null>(null);\n const [dots, setDots] = useState<string>(\"..\");\n const [stage1NotFinished, setStage1NotFinished] = useState(true);\n const completedRef = useRef(false);\n\n // If skipIntro is true, immediately complete the intro\n useEffect(() => {\n if (skipIntro && !completedRef.current) {\n completedRef.current = true;\n introProgress.set(1);\n onIntroGrowComplete?.();\n }\n }, [skipIntro, introProgress, onIntroGrowComplete]);\n\n // add up to 4 dots, then go back down to 2\n useEffect(() => {\n if (skipIntro) return; // Don't animate dots if skipping intro\n\n const interval = setInterval(() => {\n setDots((prevDots) => {\n if (prevDots.length < 3) {\n return prevDots + \".\";\n } else {\n return \".\";\n }\n });\n }, 500);\n return () => clearInterval(interval);\n }, [skipIntro]);\n\n useEffect(() => {\n if (skipIntro) return; // Don't calculate dimensions if skipping intro\n\n // calculate the initial 3:2 box size with margins (client-only)\n const calculateInitialSize = () => {\n const vw = window.innerWidth;\n const vh = window.innerHeight;\n\n const maxWidth = vw * MAX_DIM_RATIO.width;\n const maxHeight = vh * MAX_DIM_RATIO.height;\n\n // width or height as limiter\n if (maxWidth / INTRO_ASPECT_RATIO <= maxHeight) {\n return { width: maxWidth, height: maxWidth / INTRO_ASPECT_RATIO };\n } else {\n return { height: maxHeight, width: maxHeight * INTRO_ASPECT_RATIO };\n }\n };\n\n setDimensions(calculateInitialSize());\n }, [skipIntro]);\n\n // If skipIntro, render children directly without animation wrapper\n if (skipIntro) {\n return (\n <motion.div\n className=\"fixed inset-0 overflow-hidden\"\n style={{\n touchAction: \"none\",\n userSelect: \"none\",\n pointerEvents: \"none\",\n }}\n onContextMenu={(e) => e.preventDefault()}\n >\n {children}\n </motion.div>\n );\n }\n\n return (\n <motion.div\n className=\"fixed inset-0 overflow-hidden\"\n style={{\n // Only use gradient style if no custom wrapperBackground is provided\n backgroundImage: stage1NotFinished && !wrapperBackground ? introBackgroundGradient : undefined,\n touchAction: \"none\",\n userSelect: \"none\",\n pointerEvents: \"none\",\n }}\n onContextMenu={(e) => e.preventDefault()}\n >\n {/* Custom wrapper background (renders behind everything) */}\n {stage1NotFinished && wrapperBackground}\n\n {stage1NotFinished && (\n <>\n {introContent}\n </>\n )}\n\n {dimensions && (\n <>\n {/* Blurring mask box */}\n <motion.div\n initial={{\n width: dimensions.width,\n height: dimensions.height,\n opacity: 1,\n backgroundImage: canvasBoxGradient,\n }}\n animate={{\n opacity: 0,\n display: \"none\",\n }}\n transition={blurTransition}\n className=\"absolute left-1/2 top-1/2 z-20 origin-center -translate-x-1/2 -translate-y-1/2 overflow-hidden rounded-lg\"\n />\n {/* Growing wrapper drives introProgress */}\n <motion.div\n initial={{\n width: dimensions.width,\n height: dimensions.height,\n }}\n animate={{\n width: \"100vw\",\n height: \"100vh\",\n }}\n transition={growTransition}\n onUpdate={(latest: { width?: number; height?: number }) => {\n if (completedRef.current) return;\n if (typeof latest.width === \"number\") {\n const w0 = dimensions.width;\n const w1 = window.innerWidth;\n const progress =\n w1 === w0 ? 1 : (latest.width - w0) / (w1 - w0);\n const clamped = Math.min(Math.max(progress, 0), 1);\n introProgress.set(clamped);\n }\n }}\n onAnimationComplete={() => {\n if (!completedRef.current) {\n completedRef.current = true;\n introProgress.set(1);\n setStage1NotFinished(false);\n onIntroGrowComplete?.();\n }\n }}\n className=\"absolute left-1/2 top-1/2 z-10 origin-center -translate-x-1/2 -translate-y-1/2 overflow-hidden rounded-lg shadow-[0_20px_40px_rgba(103,86,86,0.15)]\"\n >\n <div className=\"h-full w-full\">{children}</div>\n </motion.div>\n </>\n )}\n {stage1NotFinished && loadingText && (\n <div className=\"absolute bottom-24 left-1/2 -translate-x-1/2 text-center font-mono font-semibold text-neutral-500\">\n {loadingText}{dots}\n </div>\n )}\n </motion.div>\n );\n};\n"],"mappings":";;;;;;AAsCA,MAAa,iBAAiB,EAC5B,UACA,eACA,qBACA,YAAY,OACZ,cACA,cAAc,kBACd,0BAA0B,kEAC1B,mBACA,oBAAoB,2FACpB,iBAAiB,iBACjB,iBAAiB,sBACO;CACxB,MAAM,CAAC,YAAY,iBAAiB,SAG1B,KAAK;CACf,MAAM,CAAC,MAAM,WAAW,SAAiB,KAAK;CAC9C,MAAM,CAAC,mBAAmB,wBAAwB,SAAS,KAAK;CAChE,MAAM,eAAe,OAAO,MAAM;AAGlC,iBAAgB;AACd,MAAI,aAAa,CAAC,aAAa,SAAS;AACtC,gBAAa,UAAU;AACvB,iBAAc,IAAI,EAAE;AACpB,0BAAuB;;IAExB;EAAC;EAAW;EAAe;EAAoB,CAAC;AAGnD,iBAAgB;AACd,MAAI,UAAW;EAEf,MAAM,WAAW,kBAAkB;AACjC,YAAS,aAAa;AACpB,QAAI,SAAS,SAAS,EACpB,QAAO,WAAW;QAElB,QAAO;KAET;KACD,IAAI;AACP,eAAa,cAAc,SAAS;IACnC,CAAC,UAAU,CAAC;AAEf,iBAAgB;AACd,MAAI,UAAW;EAGf,MAAM,6BAA6B;GACjC,MAAM,KAAK,OAAO;GAClB,MAAM,KAAK,OAAO;GAElB,MAAM,WAAW,KAAK,cAAc;GACpC,MAAM,YAAY,KAAK,cAAc;AAGrC,OAAI,WAAW,sBAAsB,UACnC,QAAO;IAAE,OAAO;IAAU,QAAQ,WAAW;IAAoB;OAEjE,QAAO;IAAE,QAAQ;IAAW,OAAO,YAAY;IAAoB;;AAIvE,gBAAc,sBAAsB,CAAC;IACpC,CAAC,UAAU,CAAC;AAGf,KAAI,UACF,QACE,oBAAC,OAAO;EACN,WAAU;EACV,OAAO;GACL,aAAa;GACb,YAAY;GACZ,eAAe;GAChB;EACD,gBAAgB,MAAM,EAAE,gBAAgB;EAEvC;GACU;AAIjB,QACE,qBAAC,OAAO;EACN,WAAU;EACV,OAAO;GAEL,iBAAiB,qBAAqB,CAAC,oBAAoB,0BAA0B;GACrF,aAAa;GACb,YAAY;GACZ,eAAe;GAChB;EACD,gBAAgB,MAAM,EAAE,gBAAgB;;GAGvC,qBAAqB;GAErB,qBACC,0CACG,eACA;GAGJ,cACC,4CAEE,oBAAC,OAAO;IACN,SAAS;KACP,OAAO,WAAW;KAClB,QAAQ,WAAW;KACnB,SAAS;KACT,iBAAiB;KAClB;IACD,SAAS;KACP,SAAS;KACT,SAAS;KACV;IACD,YAAY;IACZ,WAAU;KACV,EAEF,oBAAC,OAAO;IACN,SAAS;KACP,OAAO,WAAW;KAClB,QAAQ,WAAW;KACpB;IACD,SAAS;KACP,OAAO;KACP,QAAQ;KACT;IACD,YAAY;IACZ,WAAW,WAAgD;AACzD,SAAI,aAAa,QAAS;AAC1B,SAAI,OAAO,OAAO,UAAU,UAAU;MACpC,MAAM,KAAK,WAAW;MACtB,MAAM,KAAK,OAAO;MAClB,MAAM,WACJ,OAAO,KAAK,KAAK,OAAO,QAAQ,OAAO,KAAK;MAC9C,MAAM,UAAU,KAAK,IAAI,KAAK,IAAI,UAAU,EAAE,EAAE,EAAE;AAClD,oBAAc,IAAI,QAAQ;;;IAG9B,2BAA2B;AACzB,SAAI,CAAC,aAAa,SAAS;AACzB,mBAAa,UAAU;AACvB,oBAAc,IAAI,EAAE;AACpB,2BAAqB,MAAM;AAC3B,6BAAuB;;;IAG3B,WAAU;cAEV,oBAAC;KAAI,WAAU;KAAiB;MAAe;KACpC,IACZ;GAEJ,qBAAqB,eACpB,qBAAC;IAAI,WAAU;eACZ,aAAa;KACV;;GAEG"}
|
|
@@ -1,22 +1,30 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
1
|
import React, { createContext, useContext } from "react";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
|
|
4
|
+
//#region src/contexts/CanvasContext.tsx
|
|
3
5
|
const defaultState = {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
6
|
+
x: void 0,
|
|
7
|
+
y: void 0,
|
|
8
|
+
scale: 1,
|
|
9
|
+
isResetting: false,
|
|
10
|
+
maxZIndex: 1,
|
|
11
|
+
setMaxZIndex: () => {
|
|
12
|
+
console.log("setMaxZIndex not set");
|
|
13
|
+
},
|
|
14
|
+
animationStage: 0,
|
|
15
|
+
nextTargetSection: null,
|
|
16
|
+
setNextTargetSection: () => {
|
|
17
|
+
console.log("setNextTargetSection not set");
|
|
18
|
+
}
|
|
17
19
|
};
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
20
|
+
const CanvasContext = createContext(defaultState);
|
|
21
|
+
const useCanvasContext = () => useContext(CanvasContext);
|
|
22
|
+
const CanvasProvider = React.memo(({ children, ...value }) => /* @__PURE__ */ jsx(CanvasContext.Provider, {
|
|
23
|
+
value,
|
|
24
|
+
children
|
|
25
|
+
}));
|
|
21
26
|
CanvasProvider.displayName = "CanvasProvider";
|
|
27
|
+
|
|
28
|
+
//#endregion
|
|
29
|
+
export { CanvasContext, CanvasProvider, useCanvasContext };
|
|
22
30
|
//# sourceMappingURL=CanvasContext.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CanvasContext.js","
|
|
1
|
+
{"version":3,"file":"CanvasContext.js","names":[],"sources":["../../src/contexts/CanvasContext.tsx"],"sourcesContent":["import React, { createContext, useContext, type ReactNode } from \"react\";\nimport { type MotionValue } from \"framer-motion\";\nimport { CanvasSection } from \"../types\";\n\nexport interface Point {\n x: number;\n y: number;\n}\n\nexport interface CanvasContextState {\n x: MotionValue<number>;\n y: MotionValue<number>;\n scale: MotionValue<number>;\n isResetting: boolean;\n maxZIndex: number;\n setMaxZIndex: (zIndex: number) => void;\n animationStage: number;\n nextTargetSection: CanvasSection | null; // predictive pre-render target\n setNextTargetSection: (section: CanvasSection | null) => void;\n}\n\nconst defaultState = {\n x: undefined as unknown as MotionValue<number>,\n y: undefined as unknown as MotionValue<number>,\n scale: 1 as unknown as MotionValue<number>,\n isResetting: false,\n maxZIndex: 1,\n setMaxZIndex: () => {\n console.log(\"setMaxZIndex not set\");\n },\n animationStage: 0,\n nextTargetSection: null,\n setNextTargetSection: () => {\n console.log(\"setNextTargetSection not set\");\n },\n} as const;\n\nexport const CanvasContext = createContext<CanvasContextState>(defaultState);\n\nexport const useCanvasContext = () => useContext(CanvasContext);\n\ninterface CanvasProviderProps extends CanvasContextState {\n children: ReactNode;\n}\n\nexport const CanvasProvider: React.FC<CanvasProviderProps> = React.memo(\n ({ children, ...value }) => (\n <CanvasContext.Provider value={value as CanvasContextState}>\n {children}\n </CanvasContext.Provider>\n ),\n);\n\nCanvasProvider.displayName = \"CanvasProvider\";\n"],"mappings":";;;;AAqBA,MAAM,eAAe;CACnB,GAAG;CACH,GAAG;CACH,OAAO;CACP,aAAa;CACb,WAAW;CACX,oBAAoB;AAClB,UAAQ,IAAI,uBAAuB;;CAErC,gBAAgB;CAChB,mBAAmB;CACnB,4BAA4B;AAC1B,UAAQ,IAAI,+BAA+B;;CAE9C;AAED,MAAa,gBAAgB,cAAkC,aAAa;AAE5E,MAAa,yBAAyB,WAAW,cAAc;AAM/D,MAAa,iBAAgD,MAAM,MAChE,EAAE,UAAU,GAAG,YACd,oBAAC,cAAc;CAAgB;CAC5B;EACsB,CAE5B;AAED,eAAe,cAAc"}
|
|
@@ -1,56 +1,57 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
1
|
+
import useWindowDimensions_default from "../hooks/useWindowDimensions.js";
|
|
2
|
+
import { isIOS, isMobile, prefersReducedMotion } from "../utils/performance.js";
|
|
3
|
+
import React, { createContext, useContext, useEffect, useState } from "react";
|
|
4
|
+
import { jsx } from "react/jsx-runtime";
|
|
5
|
+
|
|
6
|
+
//#region src/contexts/PerformanceContext.tsx
|
|
5
7
|
const defaultConfig = {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
mode: "high",
|
|
9
|
+
isIOS: false,
|
|
10
|
+
isMobile: false,
|
|
11
|
+
prefersReducedMotion: false,
|
|
12
|
+
enableComplexShadows: true
|
|
11
13
|
};
|
|
12
14
|
const PerformanceContext = createContext(defaultConfig);
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
export const usePerformanceMode = usePerformance;
|
|
15
|
+
const usePerformance = () => useContext(PerformanceContext);
|
|
16
|
+
const usePerformanceMode = usePerformance;
|
|
16
17
|
/**
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
});
|
|
53
|
-
}, [width]);
|
|
54
|
-
return (_jsx(PerformanceContext.Provider, { value: config, children: children }));
|
|
18
|
+
* Performance Provider - Centralized performance mode detection
|
|
19
|
+
*
|
|
20
|
+
* Detects device capabilities and user preferences once at the top level,
|
|
21
|
+
* avoiding redundant device detection across multiple components.
|
|
22
|
+
*
|
|
23
|
+
* Usage:
|
|
24
|
+
* <PerformanceProvider>
|
|
25
|
+
* <App />
|
|
26
|
+
* </PerformanceProvider>
|
|
27
|
+
*
|
|
28
|
+
* Then in components:
|
|
29
|
+
* const { mode, isIOS, enableComplexShadows } = usePerformance();
|
|
30
|
+
*/
|
|
31
|
+
const PerformanceProvider = ({ children }) => {
|
|
32
|
+
const [config, setConfig] = useState(defaultConfig);
|
|
33
|
+
const { width } = useWindowDimensions_default();
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
const isIOSDevice = isIOS();
|
|
36
|
+
const isMobileDevice = isMobile();
|
|
37
|
+
const reducedMotion = prefersReducedMotion();
|
|
38
|
+
let mode = "high";
|
|
39
|
+
if (isIOSDevice || reducedMotion || width < 768) mode = "low";
|
|
40
|
+
else if (isMobileDevice || width < 1024) mode = "medium";
|
|
41
|
+
setConfig({
|
|
42
|
+
mode,
|
|
43
|
+
isIOS: isIOSDevice,
|
|
44
|
+
isMobile: isMobileDevice,
|
|
45
|
+
prefersReducedMotion: reducedMotion,
|
|
46
|
+
enableComplexShadows: mode !== "low"
|
|
47
|
+
});
|
|
48
|
+
}, [width]);
|
|
49
|
+
return /* @__PURE__ */ jsx(PerformanceContext.Provider, {
|
|
50
|
+
value: config,
|
|
51
|
+
children
|
|
52
|
+
});
|
|
55
53
|
};
|
|
54
|
+
|
|
55
|
+
//#endregion
|
|
56
|
+
export { PerformanceProvider, usePerformance, usePerformanceMode };
|
|
56
57
|
//# sourceMappingURL=PerformanceContext.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PerformanceContext.js","
|
|
1
|
+
{"version":3,"file":"PerformanceContext.js","names":["useWindowDimensions"],"sources":["../../src/contexts/PerformanceContext.tsx"],"sourcesContent":["import React, { createContext, useContext, useEffect, useState, type ReactNode } from \"react\";\nimport useWindowDimensions from \"../hooks/useWindowDimensions\";\nimport { isIOS, isMobile, prefersReducedMotion } from \"../utils/performance\";\n\nexport type PerformanceMode = \"high\" | \"medium\" | \"low\";\n\nexport interface PerformanceConfig {\n mode: PerformanceMode;\n isIOS: boolean;\n isMobile: boolean;\n prefersReducedMotion: boolean;\n enableComplexShadows: boolean;\n}\n\nconst defaultConfig: PerformanceConfig = {\n mode: \"high\",\n isIOS: false,\n isMobile: false,\n prefersReducedMotion: false,\n enableComplexShadows: true,\n};\n\nconst PerformanceContext = createContext<PerformanceConfig>(defaultConfig);\n\nexport const usePerformance = () => useContext(PerformanceContext);\n\n// Backward compatibility alias\nexport const usePerformanceMode = usePerformance;\n\ninterface PerformanceProviderProps {\n children: ReactNode;\n}\n\n/**\n * Performance Provider - Centralized performance mode detection\n * \n * Detects device capabilities and user preferences once at the top level,\n * avoiding redundant device detection across multiple components.\n * \n * Usage:\n * <PerformanceProvider>\n * <App />\n * </PerformanceProvider>\n * \n * Then in components:\n * const { mode, isIOS, enableComplexShadows } = usePerformance();\n */\nexport const PerformanceProvider: React.FC<PerformanceProviderProps> = ({ children }) => {\n const [config, setConfig] = useState<PerformanceConfig>(defaultConfig);\n const { width } = useWindowDimensions();\n\n useEffect(() => {\n const isIOSDevice = isIOS();\n const isMobileDevice = isMobile();\n const reducedMotion = prefersReducedMotion();\n\n let mode: PerformanceMode = \"high\";\n\n // Determine performance mode based on device and screen size\n if (isIOSDevice || reducedMotion || width < 768) {\n mode = \"low\";\n } else if (isMobileDevice || width < 1024) {\n mode = \"medium\";\n }\n\n setConfig({\n mode,\n isIOS: isIOSDevice,\n isMobile: isMobileDevice,\n prefersReducedMotion: reducedMotion,\n // Use simpler shadows on iOS and low-end devices for better performance\n enableComplexShadows: mode !== \"low\",\n });\n }, [width]);\n\n return (\n <PerformanceContext.Provider value={config}>\n {children}\n </PerformanceContext.Provider>\n );\n};\n"],"mappings":";;;;;;AAcA,MAAM,gBAAmC;CACrC,MAAM;CACN,OAAO;CACP,UAAU;CACV,sBAAsB;CACtB,sBAAsB;CACzB;AAED,MAAM,qBAAqB,cAAiC,cAAc;AAE1E,MAAa,uBAAuB,WAAW,mBAAmB;AAGlE,MAAa,qBAAqB;;;;;;;;;;;;;;;AAoBlC,MAAa,uBAA2D,EAAE,eAAe;CACrF,MAAM,CAAC,QAAQ,aAAa,SAA4B,cAAc;CACtE,MAAM,EAAE,UAAUA,6BAAqB;AAEvC,iBAAgB;EACZ,MAAM,cAAc,OAAO;EAC3B,MAAM,iBAAiB,UAAU;EACjC,MAAM,gBAAgB,sBAAsB;EAE5C,IAAI,OAAwB;AAG5B,MAAI,eAAe,iBAAiB,QAAQ,IACxC,QAAO;WACA,kBAAkB,QAAQ,KACjC,QAAO;AAGX,YAAU;GACN;GACA,OAAO;GACP,UAAU;GACV,sBAAsB;GAEtB,sBAAsB,SAAS;GAClC,CAAC;IACH,CAAC,MAAM,CAAC;AAEX,QACI,oBAAC,mBAAmB;EAAS,OAAO;EAC/B;GACyB"}
|
|
@@ -1,40 +1,39 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { isIOS, isMobile, prefersReducedMotion } from "../utils/performance";
|
|
3
|
-
import
|
|
1
|
+
import useWindowDimensions_default from "./useWindowDimensions.js";
|
|
2
|
+
import { isIOS, isMobile, prefersReducedMotion } from "../utils/performance.js";
|
|
3
|
+
import { useEffect, useState } from "react";
|
|
4
|
+
|
|
5
|
+
//#region src/hooks/usePerformanceMode.ts
|
|
4
6
|
/**
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
prefersReducedMotion: reducedMotion,
|
|
34
|
-
// Use simpler shadows on iOS for better performance
|
|
35
|
-
enableComplexShadows: mode !== "low",
|
|
36
|
-
});
|
|
37
|
-
}, []);
|
|
38
|
-
return config;
|
|
7
|
+
* Hook to determine optimal performance settings based on device capabilities
|
|
8
|
+
* Does not disable any animations - only provides info for optimization
|
|
9
|
+
*/
|
|
10
|
+
const usePerformanceMode = () => {
|
|
11
|
+
const [config, setConfig] = useState({
|
|
12
|
+
mode: "high",
|
|
13
|
+
isIOS: false,
|
|
14
|
+
isMobile: false,
|
|
15
|
+
prefersReducedMotion: false,
|
|
16
|
+
enableComplexShadows: true
|
|
17
|
+
});
|
|
18
|
+
const { width } = useWindowDimensions_default();
|
|
19
|
+
useEffect(() => {
|
|
20
|
+
const isIOSDevice = isIOS();
|
|
21
|
+
const isMobileDevice = isMobile();
|
|
22
|
+
const reducedMotion = prefersReducedMotion();
|
|
23
|
+
let mode = "high";
|
|
24
|
+
if (isIOSDevice || reducedMotion || width < 768) mode = "low";
|
|
25
|
+
else if (isMobileDevice || width < 1024) mode = "medium";
|
|
26
|
+
setConfig({
|
|
27
|
+
mode,
|
|
28
|
+
isIOS: isIOSDevice,
|
|
29
|
+
isMobile: isMobileDevice,
|
|
30
|
+
prefersReducedMotion: reducedMotion,
|
|
31
|
+
enableComplexShadows: mode !== "low"
|
|
32
|
+
});
|
|
33
|
+
}, []);
|
|
34
|
+
return config;
|
|
39
35
|
};
|
|
36
|
+
|
|
37
|
+
//#endregion
|
|
38
|
+
export { usePerformanceMode };
|
|
40
39
|
//# sourceMappingURL=usePerformanceMode.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usePerformanceMode.js","
|
|
1
|
+
{"version":3,"file":"usePerformanceMode.js","names":["useWindowDimensions"],"sources":["../../src/hooks/usePerformanceMode.ts"],"sourcesContent":["import { useState, useEffect } from \"react\";\nimport { isIOS, isMobile, prefersReducedMotion } from \"../utils/performance\";\nimport useWindowDimensions from \"./useWindowDimensions\";\n\nexport type PerformanceMode = \"high\" | \"medium\" | \"low\";\n\nexport interface PerformanceConfig {\n mode: PerformanceMode;\n isIOS: boolean;\n isMobile: boolean;\n prefersReducedMotion: boolean;\n enableComplexShadows: boolean;\n}\n\n/**\n * Hook to determine optimal performance settings based on device capabilities\n * Does not disable any animations - only provides info for optimization\n */\nexport const usePerformanceMode = (): PerformanceConfig => {\n const [config, setConfig] = useState<PerformanceConfig>({\n mode: \"high\",\n isIOS: false,\n isMobile: false,\n prefersReducedMotion: false,\n enableComplexShadows: true,\n });\n\n const { width } = useWindowDimensions();\n\n useEffect(() => {\n const isIOSDevice = isIOS();\n const isMobileDevice = isMobile();\n const reducedMotion = prefersReducedMotion();\n\n let mode: PerformanceMode = \"high\";\n\n // Determine performance mode\n if (isIOSDevice || reducedMotion || width < 768) {\n mode = \"low\";\n } else if (isMobileDevice || width < 1024) {\n mode = \"medium\";\n }\n\n setConfig({\n mode,\n isIOS: isIOSDevice,\n isMobile: isMobileDevice,\n prefersReducedMotion: reducedMotion,\n // Use simpler shadows on iOS for better performance\n enableComplexShadows: mode !== \"low\",\n });\n }, []);\n\n return config;\n};\n"],"mappings":";;;;;;;;;AAkBA,MAAa,2BAA8C;CACzD,MAAM,CAAC,QAAQ,aAAa,SAA4B;EACtD,MAAM;EACN,OAAO;EACP,UAAU;EACV,sBAAsB;EACtB,sBAAsB;EACvB,CAAC;CAEF,MAAM,EAAE,UAAUA,6BAAqB;AAEvC,iBAAgB;EACd,MAAM,cAAc,OAAO;EAC3B,MAAM,iBAAiB,UAAU;EACjC,MAAM,gBAAgB,sBAAsB;EAE5C,IAAI,OAAwB;AAG5B,MAAI,eAAe,iBAAiB,QAAQ,IAC1C,QAAO;WACE,kBAAkB,QAAQ,KACnC,QAAO;AAGT,YAAU;GACR;GACA,OAAO;GACP,UAAU;GACV,sBAAsB;GAEtB,sBAAsB,SAAS;GAChC,CAAC;IACD,EAAE,CAAC;AAEN,QAAO"}
|