@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,149 +1,171 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useCanvasContext } from "../../../contexts/CanvasContext.js";
|
|
2
|
+
import { NAVBAR_DEBOUNCE_MS, RESPONSIVE_ZOOM_MAP } from "../../../lib/constants.js";
|
|
3
|
+
import { getScreenSizeEnum, getSectionPanCoordinates } from "../../../lib/canvas.js";
|
|
4
|
+
import useWindowDimensions_default from "../../../hooks/useWindowDimensions.js";
|
|
5
|
+
import { cn } from "../../../lib/utils.js";
|
|
6
|
+
import SingleButton from "./single-button.js";
|
|
7
|
+
import { usePerformanceMode } from "../../../hooks/usePerformanceMode.js";
|
|
2
8
|
import { motion, useMotionValueEvent } from "framer-motion";
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
import { usePerformanceMode } from "../../../hooks/usePerformanceMode";
|
|
8
|
-
import { getScreenSizeEnum, getSectionPanCoordinates, } from "../../../lib/canvas";
|
|
9
|
-
import { RESPONSIVE_ZOOM_MAP, NAVBAR_DEBOUNCE_MS, } from "../../../lib/constants";
|
|
10
|
-
import { cn } from "../../../lib/utils";
|
|
9
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
10
|
+
import { jsx } from "react/jsx-runtime";
|
|
11
|
+
|
|
12
|
+
//#region src/components/canvas/navbar/index.tsx
|
|
11
13
|
const positionStyles = {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
14
|
+
top: {
|
|
15
|
+
top: "1rem",
|
|
16
|
+
bottom: "auto",
|
|
17
|
+
left: "50%",
|
|
18
|
+
transform: "translateX(-50%)"
|
|
19
|
+
},
|
|
20
|
+
bottom: {
|
|
21
|
+
bottom: "1rem",
|
|
22
|
+
top: "auto",
|
|
23
|
+
left: "50%",
|
|
24
|
+
transform: "translateX(-50%)"
|
|
25
|
+
},
|
|
26
|
+
left: {
|
|
27
|
+
left: "1rem",
|
|
28
|
+
right: "auto",
|
|
29
|
+
top: "50%",
|
|
30
|
+
transform: "translateY(-50%)"
|
|
31
|
+
},
|
|
32
|
+
right: {
|
|
33
|
+
right: "1rem",
|
|
34
|
+
left: "auto",
|
|
35
|
+
top: "50%",
|
|
36
|
+
transform: "translateY(-50%)"
|
|
37
|
+
}
|
|
36
38
|
};
|
|
37
|
-
// Responsive position adjustments (mobile vs desktop)
|
|
38
39
|
const responsivePositionClasses = {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
top: "top-12 md:top-4",
|
|
41
|
+
bottom: "bottom-12 md:bottom-4",
|
|
42
|
+
left: "left-4",
|
|
43
|
+
right: "right-4"
|
|
43
44
|
};
|
|
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
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
45
|
+
function Navbar({ panToOffset, onReset, items, config = {} }) {
|
|
46
|
+
const { x, y, scale, animationStage, setNextTargetSection } = useCanvasContext();
|
|
47
|
+
const [expandedButton, setExpandedButton] = useState(null);
|
|
48
|
+
const activePans = useRef(0);
|
|
49
|
+
const panTimeout = useRef(null);
|
|
50
|
+
const debounceBlocked = useRef(false);
|
|
51
|
+
const debounceCooldownTimeout = useRef(null);
|
|
52
|
+
const { height, width } = useWindowDimensions_default();
|
|
53
|
+
const { mode } = usePerformanceMode();
|
|
54
|
+
const defaultZoom = RESPONSIVE_ZOOM_MAP[getScreenSizeEnum(width)];
|
|
55
|
+
const debounceMs = NAVBAR_DEBOUNCE_MS[mode] ?? 0;
|
|
56
|
+
const { display = "icons", position = "bottom", className, style, buttonConfig, tooltipConfig, gap, padding } = config;
|
|
57
|
+
const isVertical = position === "left" || position === "right";
|
|
58
|
+
const homeItem = useMemo(() => items.find((item) => item.isHome), [items]);
|
|
59
|
+
const handleDebouncedClick = useCallback((callback) => {
|
|
60
|
+
if (debounceMs === 0) {
|
|
61
|
+
callback();
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
if (debounceBlocked.current) return;
|
|
65
|
+
debounceBlocked.current = true;
|
|
66
|
+
callback();
|
|
67
|
+
if (debounceCooldownTimeout.current) clearTimeout(debounceCooldownTimeout.current);
|
|
68
|
+
debounceCooldownTimeout.current = setTimeout(() => {
|
|
69
|
+
debounceBlocked.current = false;
|
|
70
|
+
debounceCooldownTimeout.current = null;
|
|
71
|
+
}, debounceMs);
|
|
72
|
+
}, [debounceMs]);
|
|
73
|
+
const updateExpandedButton = () => {
|
|
74
|
+
if (panTimeout.current) clearTimeout(panTimeout.current);
|
|
75
|
+
panTimeout.current = setTimeout(() => {
|
|
76
|
+
activePans.current = 0;
|
|
77
|
+
}, 500);
|
|
78
|
+
if (activePans.current == 0) setExpandedButton(null);
|
|
79
|
+
};
|
|
80
|
+
useMotionValueEvent(x, "change", updateExpandedButton);
|
|
81
|
+
useMotionValueEvent(y, "change", updateExpandedButton);
|
|
82
|
+
useMotionValueEvent(scale, "change", updateExpandedButton);
|
|
83
|
+
const handlePan = useCallback(function handlePan(item) {
|
|
84
|
+
setExpandedButton(item.id);
|
|
85
|
+
activePans.current++;
|
|
86
|
+
setNextTargetSection(item.id);
|
|
87
|
+
if (item.isHome) {
|
|
88
|
+
onReset();
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
panToOffset(getSectionPanCoordinates({
|
|
92
|
+
windowDimensions: {
|
|
93
|
+
width,
|
|
94
|
+
height
|
|
95
|
+
},
|
|
96
|
+
coords: {
|
|
97
|
+
x: item.x,
|
|
98
|
+
y: item.y,
|
|
99
|
+
width: item.width,
|
|
100
|
+
height: item.height
|
|
101
|
+
},
|
|
102
|
+
targetZoom: defaultZoom,
|
|
103
|
+
negative: true
|
|
104
|
+
}), () => {
|
|
105
|
+
activePans.current--;
|
|
106
|
+
}, defaultZoom);
|
|
107
|
+
}, [
|
|
108
|
+
panToOffset,
|
|
109
|
+
onReset,
|
|
110
|
+
width,
|
|
111
|
+
height,
|
|
112
|
+
defaultZoom,
|
|
113
|
+
setNextTargetSection
|
|
114
|
+
]);
|
|
115
|
+
useEffect(() => {
|
|
116
|
+
if (animationStage < 2) return;
|
|
117
|
+
if (homeItem) handlePan(homeItem);
|
|
118
|
+
return () => {
|
|
119
|
+
if (panTimeout.current) clearTimeout(panTimeout.current);
|
|
120
|
+
if (debounceCooldownTimeout.current) clearTimeout(debounceCooldownTimeout.current);
|
|
121
|
+
};
|
|
122
|
+
}, [
|
|
123
|
+
handlePan,
|
|
124
|
+
animationStage,
|
|
125
|
+
homeItem
|
|
126
|
+
]);
|
|
127
|
+
const containerStyle = {
|
|
128
|
+
position: "fixed",
|
|
129
|
+
zIndex: 1e3,
|
|
130
|
+
pointerEvents: "auto",
|
|
131
|
+
display: "flex",
|
|
132
|
+
justifyContent: "center",
|
|
133
|
+
alignItems: "center",
|
|
134
|
+
...positionStyles[position]
|
|
135
|
+
};
|
|
136
|
+
const innerStyle = {
|
|
137
|
+
...gap !== void 0 && { gap: `${gap}px` },
|
|
138
|
+
...padding !== void 0 && { padding: `${padding}px` },
|
|
139
|
+
...isVertical && { flexDirection: "column" },
|
|
140
|
+
...style
|
|
141
|
+
};
|
|
142
|
+
return /* @__PURE__ */ jsx("div", {
|
|
143
|
+
className: responsivePositionClasses[position],
|
|
144
|
+
style: containerStyle,
|
|
145
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
146
|
+
className: isVertical ? "py-4 md:py-8" : "px-4 md:px-8",
|
|
147
|
+
children: /* @__PURE__ */ jsx(motion.div, {
|
|
148
|
+
className: cn("flex select-none items-center justify-center gap-1 rounded-[10px] border p-1 shadow-[0_6px_12px_rgba(0,0,0,0.08)]", !style?.backgroundColor && "bg-white", !style?.borderColor && "border-neutral-200", isVertical && "flex-col", className),
|
|
149
|
+
style: innerStyle,
|
|
150
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
151
|
+
className: cn("flex items-center gap-1", isVertical && "flex-col"),
|
|
152
|
+
children: items.map((item) => /* @__PURE__ */ jsx(SingleButton, {
|
|
153
|
+
label: item.label,
|
|
154
|
+
icon: item.icon,
|
|
155
|
+
onClick: () => handlePan(item),
|
|
156
|
+
isPushed: expandedButton === item.id,
|
|
157
|
+
onDebouncedClick: handleDebouncedClick,
|
|
158
|
+
displayMode: display,
|
|
159
|
+
buttonConfig,
|
|
160
|
+
tooltipConfig,
|
|
161
|
+
isVertical
|
|
162
|
+
}, item.id))
|
|
163
|
+
})
|
|
164
|
+
})
|
|
165
|
+
})
|
|
166
|
+
});
|
|
148
167
|
}
|
|
168
|
+
|
|
169
|
+
//#endregion
|
|
170
|
+
export { Navbar as default };
|
|
149
171
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/components/canvas/navbar/index.tsx"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["useWindowDimensions"],"sources":["../../../../src/components/canvas/navbar/index.tsx"],"sourcesContent":["import { motion, useMotionValueEvent } from \"framer-motion\";\nimport { useState, useRef, useEffect, useCallback, useMemo } from \"react\";\nimport SingleButton from \"./single-button\";\nimport type { NavItem, NavbarConfig, NavbarPosition } from \"../../../types\";\nimport { useCanvasContext } from \"../../../contexts/CanvasContext\";\nimport useWindowDimensions from \"../../../hooks/useWindowDimensions\";\nimport { usePerformanceMode } from \"../../../hooks/usePerformanceMode\";\nimport {\n getScreenSizeEnum,\n getSectionPanCoordinates,\n} from \"../../../lib/canvas\";\nimport {\n RESPONSIVE_ZOOM_MAP,\n NAVBAR_DEBOUNCE_MS,\n} from \"../../../lib/constants\";\nimport { cn } from \"../../../lib/utils\";\n\ninterface NavbarProps {\n panToOffset: (\n offset: { x: number; y: number },\n onComplete?: () => void,\n zoom?: number,\n ) => void;\n onReset: () => void;\n /** Array of navigation items defining sections, their icons, and coordinates */\n items: NavItem[];\n /** Navbar configuration options */\n config?: NavbarConfig;\n}\n\nconst positionStyles: Record<NavbarPosition, React.CSSProperties> = {\n top: {\n top: \"1rem\",\n bottom: \"auto\",\n left: \"50%\",\n transform: \"translateX(-50%)\",\n },\n bottom: {\n bottom: \"1rem\",\n top: \"auto\",\n left: \"50%\",\n transform: \"translateX(-50%)\",\n },\n left: {\n left: \"1rem\",\n right: \"auto\",\n top: \"50%\",\n transform: \"translateY(-50%)\",\n },\n right: {\n right: \"1rem\",\n left: \"auto\",\n top: \"50%\",\n transform: \"translateY(-50%)\",\n },\n};\n\n// Responsive position adjustments (mobile vs desktop)\nconst responsivePositionClasses: Record<NavbarPosition, string> = {\n top: \"top-12 md:top-4\",\n bottom: \"bottom-12 md:bottom-4\",\n left: \"left-4\",\n right: \"right-4\",\n};\n\nexport default function Navbar({\n panToOffset,\n onReset,\n items,\n config = {},\n}: NavbarProps) {\n const { x, y, scale, animationStage, setNextTargetSection } =\n useCanvasContext();\n const [expandedButton, setExpandedButton] = useState<string | null>(null);\n const activePans = useRef(0);\n const panTimeout = useRef<NodeJS.Timeout | null>(null);\n\n // Debounce state\n const debounceBlocked = useRef(false);\n const debounceCooldownTimeout = useRef<ReturnType<typeof setTimeout> | null>(\n null,\n );\n\n const { height, width } = useWindowDimensions();\n const { mode } = usePerformanceMode();\n\n const defaultZoom = RESPONSIVE_ZOOM_MAP[getScreenSizeEnum(width)];\n\n // Derive debounce duration from performance mode\n const debounceMs = NAVBAR_DEBOUNCE_MS[mode] ?? 0;\n\n // Extract config values\n const {\n display = \"icons\",\n position = \"bottom\",\n className,\n style,\n buttonConfig,\n tooltipConfig,\n gap,\n padding,\n } = config;\n\n const isVertical = position === \"left\" || position === \"right\";\n\n // Find the home section from items\n const homeItem = useMemo(() => items.find((item) => item.isHome), [items]);\n\n // Leading-edge debounce handler\n const handleDebouncedClick = useCallback(\n (callback: () => void) => {\n if (debounceMs === 0) {\n callback();\n return;\n }\n\n if (debounceBlocked.current) {\n // We're in the cooldown window; ignore this click\n return;\n }\n\n // Enter cooldown and perform the click immediately\n debounceBlocked.current = true;\n callback();\n\n if (debounceCooldownTimeout.current) {\n clearTimeout(debounceCooldownTimeout.current);\n }\n\n debounceCooldownTimeout.current = setTimeout(() => {\n debounceBlocked.current = false;\n debounceCooldownTimeout.current = null;\n }, debounceMs);\n },\n [debounceMs],\n );\n\n const updateExpandedButton = () => {\n // reset activePans if no movement has occurred recently\n if (panTimeout.current) clearTimeout(panTimeout.current);\n panTimeout.current = setTimeout(() => {\n activePans.current = 0;\n }, 500);\n\n if (activePans.current == 0) setExpandedButton(null);\n };\n\n useMotionValueEvent(x, \"change\", updateExpandedButton);\n useMotionValueEvent(y, \"change\", updateExpandedButton);\n useMotionValueEvent(scale, \"change\", updateExpandedButton);\n\n const handlePan = useCallback(\n function handlePan(item: NavItem) {\n setExpandedButton(item.id);\n activePans.current++;\n\n // Predictive pre-render hint: mark the target section so its CanvasComponent can\n // render even before it comes fully into view.\n setNextTargetSection(item.id);\n\n if (item.isHome) {\n onReset();\n return;\n }\n\n const panCoords = getSectionPanCoordinates({\n windowDimensions: { width, height },\n coords: { x: item.x, y: item.y, width: item.width, height: item.height },\n targetZoom: defaultZoom,\n negative: true,\n });\n\n panToOffset(\n panCoords,\n () => {\n activePans.current--;\n },\n defaultZoom,\n );\n },\n [panToOffset, onReset, width, height, defaultZoom, setNextTargetSection],\n );\n\n // Clean up timers on unmount and pan to home on animation complete\n useEffect(() => {\n if (animationStage < 2) return;\n if (homeItem) {\n handlePan(homeItem);\n }\n return () => {\n if (panTimeout.current) clearTimeout(panTimeout.current);\n if (debounceCooldownTimeout.current)\n clearTimeout(debounceCooldownTimeout.current);\n };\n }, [handlePan, animationStage, homeItem]);\n\n // Compute container styles (positioning only)\n const containerStyle: React.CSSProperties = {\n position: \"fixed\",\n zIndex: 1000,\n pointerEvents: \"auto\",\n display: \"flex\",\n justifyContent: \"center\",\n alignItems: \"center\",\n ...positionStyles[position],\n };\n\n // Compute inner container styles (visual styling)\n const innerStyle: React.CSSProperties = {\n ...(gap !== undefined && { gap: `${gap}px` }),\n ...(padding !== undefined && { padding: `${padding}px` }),\n ...(isVertical && { flexDirection: \"column\" }),\n ...style,\n };\n\n return (\n <div\n className={responsivePositionClasses[position]}\n style={containerStyle}\n >\n {/* padding to prevent edge bug */}\n <div className={isVertical ? \"py-4 md:py-8\" : \"px-4 md:px-8\"}>\n <motion.div\n className={cn(\n \"flex select-none items-center justify-center gap-1 rounded-[10px] border p-1 shadow-[0_6px_12px_rgba(0,0,0,0.08)]\",\n !style?.backgroundColor && \"bg-white\",\n !style?.borderColor && \"border-neutral-200\",\n isVertical && \"flex-col\",\n className,\n )}\n style={innerStyle}\n >\n <div className={cn(\"flex items-center gap-1\", isVertical && \"flex-col\")}>\n {items.map((item) => (\n <SingleButton\n key={item.id}\n label={item.label}\n icon={item.icon}\n onClick={() => handlePan(item)}\n isPushed={expandedButton === item.id}\n onDebouncedClick={handleDebouncedClick}\n displayMode={display}\n buttonConfig={buttonConfig}\n tooltipConfig={tooltipConfig}\n isVertical={isVertical}\n />\n ))}\n </div>\n </motion.div>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|