@mhamz.01/easyflow-whiteboard 2.98.0 → 2.100.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/toolbar/layers-control.d.ts +6 -0
- package/dist/components/toolbar/layers-control.d.ts.map +1 -1
- package/dist/components/toolbar/layers-control.js +29 -67
- package/dist/components/toolbar/tooloptions-panel.d.ts.map +1 -1
- package/dist/components/toolbar/tooloptions-panel.js +7 -23
- package/dist/hooks/useSelection.d.ts.map +1 -1
- package/dist/hooks/useSelection.js +14 -0
- package/dist/store/whiteboard-store.d.ts +5 -1
- package/dist/store/whiteboard-store.d.ts.map +1 -1
- package/dist/store/whiteboard-store.js +29 -0
- package/package.json +1 -1
|
@@ -1 +1,7 @@
|
|
|
1
|
+
import { Canvas } from "fabric";
|
|
2
|
+
interface LayerControlsProps {
|
|
3
|
+
fabricCanvas: React.RefObject<Canvas | null>;
|
|
4
|
+
}
|
|
5
|
+
export default function LayerControls({ fabricCanvas }: LayerControlsProps): import("react/jsx-runtime").JSX.Element;
|
|
6
|
+
export {};
|
|
1
7
|
//# sourceMappingURL=layers-control.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"layers-control.d.ts","sourceRoot":"","sources":["../../../src/components/toolbar/layers-control.tsx"],"names":[],"mappings":""}
|
|
1
|
+
{"version":3,"file":"layers-control.d.ts","sourceRoot":"","sources":["../../../src/components/toolbar/layers-control.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,UAAU,kBAAkB;IAC1B,YAAY,EAAE,KAAK,CAAC,SAAS,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;CAC9C;AAED,MAAM,CAAC,OAAO,UAAU,aAAa,CAAC,EAAE,YAAY,EAAE,EAAE,kBAAkB,2CAkEzE"}
|
|
@@ -1,67 +1,29 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
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
|
-
// <p className="text-xs text-white/60 mb-1">Layer Order</p>
|
|
31
|
-
// <div className="flex gap-1">
|
|
32
|
-
// {/* Bring to Front */}
|
|
33
|
-
// <button
|
|
34
|
-
// onClick={handleBringToFront}
|
|
35
|
-
// className="p-2 hover:bg-white/10 rounded transition-colors"
|
|
36
|
-
// title="Bring to Front"
|
|
37
|
-
// >
|
|
38
|
-
// <MoveUp size={16} className="text-white" />
|
|
39
|
-
// </button>
|
|
40
|
-
// {/* Bring Forward */}
|
|
41
|
-
// <button
|
|
42
|
-
// onClick={handleBringForward}
|
|
43
|
-
// className="p-2 hover:bg-white/10 rounded transition-colors"
|
|
44
|
-
// title="Bring Forward"
|
|
45
|
-
// >
|
|
46
|
-
// <ArrowUp size={16} className="text-white" />
|
|
47
|
-
// </button>
|
|
48
|
-
// {/* Send Backward */}
|
|
49
|
-
// <button
|
|
50
|
-
// onClick={handleSendBackward}
|
|
51
|
-
// className="p-2 hover:bg-white/10 rounded transition-colors"
|
|
52
|
-
// title="Send Backward"
|
|
53
|
-
// >
|
|
54
|
-
// <ArrowDown size={16} className="text-white" />
|
|
55
|
-
// </button>
|
|
56
|
-
// {/* Send to Back */}
|
|
57
|
-
// <button
|
|
58
|
-
// onClick={handleSendToBack}
|
|
59
|
-
// className="p-2 hover:bg-white/10 rounded transition-colors"
|
|
60
|
-
// title="Send to Back"
|
|
61
|
-
// >
|
|
62
|
-
// <MoveDown size={16} className="text-white" />
|
|
63
|
-
// </button>
|
|
64
|
-
// </div>
|
|
65
|
-
// </div>
|
|
66
|
-
// );
|
|
67
|
-
// }
|
|
1
|
+
// components/toolbar/layer-controls.tsx
|
|
2
|
+
"use client";
|
|
3
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
4
|
+
import { ArrowUp, ArrowDown, MoveUp, MoveDown } from "lucide-react";
|
|
5
|
+
import { useWhiteboardStore } from "../../store/whiteboard-store";
|
|
6
|
+
export default function LayerControls({ fabricCanvas }) {
|
|
7
|
+
const { bringToFront, sendToBack, bringForward, sendBackward } = useWhiteboardStore();
|
|
8
|
+
const handleBringToFront = () => {
|
|
9
|
+
const canvas = fabricCanvas.current;
|
|
10
|
+
if (canvas)
|
|
11
|
+
bringToFront(canvas);
|
|
12
|
+
};
|
|
13
|
+
const handleSendToBack = () => {
|
|
14
|
+
const canvas = fabricCanvas.current;
|
|
15
|
+
if (canvas)
|
|
16
|
+
sendToBack(canvas);
|
|
17
|
+
};
|
|
18
|
+
const handleBringForward = () => {
|
|
19
|
+
const canvas = fabricCanvas.current;
|
|
20
|
+
if (canvas)
|
|
21
|
+
bringForward(canvas);
|
|
22
|
+
};
|
|
23
|
+
const handleSendBackward = () => {
|
|
24
|
+
const canvas = fabricCanvas.current;
|
|
25
|
+
if (canvas)
|
|
26
|
+
sendBackward(canvas);
|
|
27
|
+
};
|
|
28
|
+
return (_jsxs("div", { className: "flex flex-col gap-1 p-2 bg-black/90 rounded-lg border border-white/10", children: [_jsx("p", { className: "text-xs text-white/60 mb-1", children: "Layer Order" }), _jsxs("div", { className: "flex gap-1", children: [_jsx("button", { onClick: handleBringToFront, className: "p-2 hover:bg-white/10 rounded transition-colors", title: "Bring to Front", children: _jsx(MoveUp, { size: 16, className: "text-white" }) }), _jsx("button", { onClick: handleBringForward, className: "p-2 hover:bg-white/10 rounded transition-colors", title: "Bring Forward", children: _jsx(ArrowUp, { size: 16, className: "text-white" }) }), _jsx("button", { onClick: handleSendBackward, className: "p-2 hover:bg-white/10 rounded transition-colors", title: "Send Backward", children: _jsx(ArrowDown, { size: 16, className: "text-white" }) }), _jsx("button", { onClick: handleSendToBack, className: "p-2 hover:bg-white/10 rounded transition-colors", title: "Send to Back", children: _jsx(MoveDown, { size: 16, className: "text-white" }) })] })] }));
|
|
29
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tooloptions-panel.d.ts","sourceRoot":"","sources":["../../../src/components/toolbar/tooloptions-panel.tsx"],"names":[],"mappings":"AAGA,OAAc,EAAE,SAAS,
|
|
1
|
+
{"version":3,"file":"tooloptions-panel.d.ts","sourceRoot":"","sources":["../../../src/components/toolbar/tooloptions-panel.tsx"],"names":[],"mappings":"AAGA,OAAc,EAAE,SAAS,EAAgC,MAAM,OAAO,CAAC;AAUvE,OAAO,MAA2C,MAAM,QAAQ,CAAC;AAIjE,UAAU,qBAAqB;IAC7B,YAAY,EAAE,SAAS,CAAC,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;CAC/C;AAED,MAAM,CAAC,OAAO,UAAU,gBAAgB,CAAC,EACvC,YAAY,GACb,EAAE,qBAAqB,2CA0MvB"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
-
import { useEffect, useMemo,
|
|
3
|
+
import { useEffect, useMemo, useState } from "react";
|
|
4
4
|
import { cn } from "../../lib/utils";
|
|
5
5
|
import { useWhiteboardStore } from "../../store/whiteboard-store";
|
|
6
6
|
import PenOptions from "./options/pen-option";
|
|
@@ -11,13 +11,13 @@ import LineOptions from "./options/line-options";
|
|
|
11
11
|
import ArrowOptions from "./options/arrow-options";
|
|
12
12
|
import { Rect, Circle, IText } from "fabric";
|
|
13
13
|
import { Settings2, ChevronDown } from "lucide-react";
|
|
14
|
+
import LayerControls from "./layers-control";
|
|
14
15
|
export default function ToolOptionsPanel({ fabricCanvas, }) {
|
|
15
16
|
const activeTool = useWhiteboardStore((state) => state.activeTool);
|
|
16
17
|
const selectedObjectType = useWhiteboardStore((state) => state.selectedObjectType);
|
|
17
18
|
const toolOptions = useWhiteboardStore((state) => state.toolOptions);
|
|
18
19
|
const [isMobileExpanded, setIsMobileExpanded] = useState(false);
|
|
19
20
|
const displayTool = selectedObjectType || activeTool;
|
|
20
|
-
const isUpdatingRef = useRef(false);
|
|
21
21
|
// Real-time fabric updates
|
|
22
22
|
useEffect(() => {
|
|
23
23
|
const canvas = fabricCanvas.current;
|
|
@@ -26,27 +26,10 @@ export default function ToolOptionsPanel({ fabricCanvas, }) {
|
|
|
26
26
|
const selectedObject = canvas.getActiveObject();
|
|
27
27
|
if (!selectedObject || !selectedObjectType)
|
|
28
28
|
return;
|
|
29
|
-
// ⚠️ CRITICAL CHECK:
|
|
30
|
-
// We only want to push Store -> Canvas if the Store values
|
|
31
|
-
// are different from the Object's current values.
|
|
32
|
-
const updateIfChanged = (props) => {
|
|
33
|
-
let hasChanged = false;
|
|
34
|
-
Object.entries(props).forEach(([key, value]) => {
|
|
35
|
-
if (selectedObject.get(key) !== value) {
|
|
36
|
-
hasChanged = true;
|
|
37
|
-
}
|
|
38
|
-
});
|
|
39
|
-
if (hasChanged) {
|
|
40
|
-
selectedObject.set(props);
|
|
41
|
-
canvas.renderAll();
|
|
42
|
-
// Only push history if a real change happened
|
|
43
|
-
// pushHistory(JSON.stringify(canvas.toJSON(['fill', 'stroke', 'strokeWidth', 'id'])));
|
|
44
|
-
}
|
|
45
|
-
};
|
|
46
29
|
switch (selectedObjectType) {
|
|
47
30
|
case "rectangle":
|
|
48
31
|
if (selectedObject instanceof Rect) {
|
|
49
|
-
|
|
32
|
+
selectedObject.set({
|
|
50
33
|
fill: toolOptions.rectangle.fillColor,
|
|
51
34
|
stroke: toolOptions.rectangle.strokeColor,
|
|
52
35
|
strokeWidth: toolOptions.rectangle.strokeWidth,
|
|
@@ -55,7 +38,7 @@ export default function ToolOptionsPanel({ fabricCanvas, }) {
|
|
|
55
38
|
break;
|
|
56
39
|
case "circle":
|
|
57
40
|
if (selectedObject instanceof Circle) {
|
|
58
|
-
|
|
41
|
+
selectedObject.set({
|
|
59
42
|
fill: toolOptions.circle.fillColor,
|
|
60
43
|
stroke: toolOptions.circle.strokeColor,
|
|
61
44
|
strokeWidth: toolOptions.circle.strokeWidth,
|
|
@@ -64,7 +47,7 @@ export default function ToolOptionsPanel({ fabricCanvas, }) {
|
|
|
64
47
|
break;
|
|
65
48
|
case "text":
|
|
66
49
|
if (selectedObject instanceof IText) {
|
|
67
|
-
|
|
50
|
+
selectedObject.set({
|
|
68
51
|
fill: toolOptions.text.color,
|
|
69
52
|
fontSize: toolOptions.text.fontSize,
|
|
70
53
|
fontFamily: toolOptions.text.fontFamily,
|
|
@@ -72,6 +55,7 @@ export default function ToolOptionsPanel({ fabricCanvas, }) {
|
|
|
72
55
|
}
|
|
73
56
|
break;
|
|
74
57
|
}
|
|
58
|
+
canvas.renderAll();
|
|
75
59
|
}, [toolOptions, selectedObjectType, fabricCanvas]);
|
|
76
60
|
const toolsWithoutOptions = ["select", "pan", "undo", "redo", "eraser"];
|
|
77
61
|
const isOpen = useMemo(() => {
|
|
@@ -85,7 +69,7 @@ export default function ToolOptionsPanel({ fabricCanvas, }) {
|
|
|
85
69
|
}, [isOpen]);
|
|
86
70
|
return (_jsxs(_Fragment, { children: [_jsxs("aside", { className: cn("hidden md:flex", "absolute left-4 top-1/2 -translate-y-1/2 z-40", "flex-col", "w-64 max-h-[85vh]", "bg-[#1A1A1E]/90 backdrop-blur-xl", "border border-white/10", "shadow-[0_20px_50px_rgba(0,0,0,0.5)]", "rounded-[24px]", "transition-all duration-500 cubic-bezier(0.16, 1, 0.3, 1)", isOpen
|
|
87
71
|
? "translate-x-0 opacity-100 visible scale-100"
|
|
88
|
-
: "-translate-x-12 opacity-0 invisible scale-95 pointer-events-none"), children: [_jsx("div", { className: "absolute -left-[1px] top-1/2 -translate-y-1/2 w-[3px] h-12 bg-[#029AFF] rounded-r-full shadow-[0_0_15px_#029AFF]" }), _jsxs("div", { className: "flex items-center justify-between px-5 py-4 border-b border-white/5", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Settings2, { className: "w-4 h-4 text-[#029AFF]" }), _jsx("h3", { className: "text-[11px] font-bold uppercase tracking-[0.1em] text-neutral-400", children: "Properties" })] }), _jsx("div", { className: "text-[10px] px-2 py-0.5 rounded-full bg-white/5 text-white/40 border border-white/5", children: displayTool })] }), _jsx("div", { className: "flex-1 overflow-y-auto p-5 custom-scrollbar scroll-smooth", children: _jsxs("div", { className: "space-y-6 text-neutral-200", children: [displayTool === "pen" && _jsx(PenOptions, {}), (displayTool === "rectangle" || displayTool === "circle" || displayTool === "frame") && (_jsx(ShapeOptions, { shapeType: displayTool })), displayTool === "text" && _jsx(TextOptions, {}), displayTool === "image" && _jsx(ImageOptions, {}), displayTool === "line" && _jsx(LineOptions, {}), displayTool === "arrow" && _jsx(ArrowOptions, { fabricCanvas: fabricCanvas })] }) }), _jsx("div", { className: "p-3 flex justify-center", children: _jsx("div", { className: "w-8 h-1 rounded-full bg-white/10" }) })] }), isOpen && (_jsxs("div", { className: cn("md:hidden", "fixed left-3 top-4 z-40", // Positioned Top-Left to stay clear of Top-Right zoom
|
|
72
|
+
: "-translate-x-12 opacity-0 invisible scale-95 pointer-events-none"), children: [_jsx("div", { className: "absolute -left-[1px] top-1/2 -translate-y-1/2 w-[3px] h-12 bg-[#029AFF] rounded-r-full shadow-[0_0_15px_#029AFF]" }), _jsxs("div", { className: "flex items-center justify-between px-5 py-4 border-b border-white/5", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Settings2, { className: "w-4 h-4 text-[#029AFF]" }), _jsx("h3", { className: "text-[11px] font-bold uppercase tracking-[0.1em] text-neutral-400", children: "Properties" })] }), _jsx("div", { className: "text-[10px] px-2 py-0.5 rounded-full bg-white/5 text-white/40 border border-white/5", children: displayTool })] }), _jsx("div", { className: "flex-1 overflow-y-auto p-5 custom-scrollbar scroll-smooth", children: _jsxs("div", { className: "space-y-6 text-neutral-200", children: [displayTool === "pen" && _jsx(PenOptions, {}), (displayTool === "rectangle" || displayTool === "circle" || displayTool === "frame") && (_jsx(ShapeOptions, { shapeType: displayTool })), displayTool === "text" && _jsx(TextOptions, {}), displayTool === "image" && _jsx(ImageOptions, {}), displayTool === "line" && _jsx(LineOptions, {}), displayTool === "arrow" && _jsx(ArrowOptions, { fabricCanvas: fabricCanvas }), selectedObjectType && (_jsx(LayerControls, { fabricCanvas: fabricCanvas }))] }) }), _jsx("div", { className: "p-3 flex justify-center", children: _jsx("div", { className: "w-8 h-1 rounded-full bg-white/10" }) })] }), isOpen && (_jsxs("div", { className: cn("md:hidden", "fixed left-3 top-4 z-40", // Positioned Top-Left to stay clear of Top-Right zoom
|
|
89
73
|
"w-[calc(100%-80px)] max-w-[180px]", // Leave room on the right to tap canvas
|
|
90
74
|
"bg-[#1A1A1E]/95 backdrop-blur-xl", "border border-white/10", "rounded-2xl shadow-2xl", "transition-all duration-300 ease-in-out", isMobileExpanded ? "max-h-[70vh]" : "h-[48px]"), children: [_jsxs("div", { className: "flex items-center justify-between px-4 h-[48px] cursor-pointer", onClick: () => setIsMobileExpanded(!isMobileExpanded), children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Settings2, { className: "w-4 h-4 text-[#029AFF]" }), _jsxs("span", { className: "text-[10px] font-bold uppercase tracking-wider text-neutral-300", children: [displayTool, " Settings"] })] }), _jsx("div", { className: "flex items-center gap-2", children: _jsx("div", { className: cn("transition-transform duration-300", isMobileExpanded ? "rotate-180" : "rotate-0"), children: _jsx(ChevronDown, { className: "w-4 h-4 text-white/50" }) }) })] }), _jsx("div", { className: cn("overflow-hidden transition-all duration-300", isMobileExpanded ? "opacity-100 h-auto" : "opacity-0 h-0"), children: _jsxs("div", { className: "px-4 pb-5 pt-2 space-y-4 overflow-y-auto max-h-[60vh] custom-scrollbar", children: [_jsx("div", { className: "h-[1px] w-full bg-white/5 mb-4" }), displayTool === "pen" && _jsx(PenOptions, {}), (displayTool === "rectangle" || displayTool === "circle" || displayTool === "frame") && (_jsx(ShapeOptions, { shapeType: displayTool })), displayTool === "text" && _jsx(TextOptions, {}), displayTool === "image" && _jsx(ImageOptions, {}), displayTool === "line" && _jsx(LineOptions, {}), displayTool === "arrow" && _jsx(ArrowOptions, { fabricCanvas: fabricCanvas })] }) })] })), _jsx("style", { children: `
|
|
91
75
|
.custom-scrollbar::-webkit-scrollbar {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useSelection.d.ts","sourceRoot":"","sources":["../../src/hooks/useSelection.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAQ,YAAY,EAAe,MAAM,QAAQ,CAAC;AAMjE,UAAU,iBAAiB;IACzB,YAAY,EAAE,KAAK,CAAC,SAAS,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC7C,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACzC,eAAe,EAAE,CAAC,GAAG,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,KAAK,IAAI,CAAC;IAC1F,wBAAwB,EAAE,CAAC,OAAO,EAAE,YAAY,EAAE,KAAK,IAAI,CAAC;IAC5D,YAAY,EAAE,KAAK,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;CAC/C;AAED,eAAO,MAAM,YAAY,GAAI,wFAM1B,iBAAiB,
|
|
1
|
+
{"version":3,"file":"useSelection.d.ts","sourceRoot":"","sources":["../../src/hooks/useSelection.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAQ,YAAY,EAAe,MAAM,QAAQ,CAAC;AAMjE,UAAU,iBAAiB;IACzB,YAAY,EAAE,KAAK,CAAC,SAAS,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC7C,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACzC,eAAe,EAAE,CAAC,GAAG,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,KAAK,IAAI,CAAC;IAC1F,wBAAwB,EAAE,CAAC,OAAO,EAAE,YAAY,EAAE,KAAK,IAAI,CAAC;IAC5D,YAAY,EAAE,KAAK,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;CAC/C;AAED,eAAO,MAAM,YAAY,GAAI,wFAM1B,iBAAiB,SAsKnB,CAAC"}
|
|
@@ -103,6 +103,20 @@ export const useSelection = ({ fabricCanvas, activeTool, setSelectionBox, setSel
|
|
|
103
103
|
: sel instanceof BidirectionalArrow ? "arrow"
|
|
104
104
|
: typeMap[sel.type] ?? null;
|
|
105
105
|
setSelectedObjectType(t);
|
|
106
|
+
if (t && sel.type !== "activeSelection") {
|
|
107
|
+
const store = useWhiteboardStore.getState();
|
|
108
|
+
if (t === "rectangle" && sel.fill) {
|
|
109
|
+
store.setToolOption("rectangle", "fillColor", sel.fill);
|
|
110
|
+
store.setToolOption("rectangle", "strokeColor", sel.stroke || "#ffffff");
|
|
111
|
+
store.setToolOption("rectangle", "strokeWidth", sel.strokeWidth || 2);
|
|
112
|
+
}
|
|
113
|
+
else if (t === "circle" && sel.fill) {
|
|
114
|
+
store.setToolOption("circle", "fillColor", sel.fill);
|
|
115
|
+
store.setToolOption("circle", "strokeColor", sel.stroke || "#ffffff");
|
|
116
|
+
store.setToolOption("circle", "strokeWidth", sel.strokeWidth || 2);
|
|
117
|
+
}
|
|
118
|
+
// Add for other types as needed...
|
|
119
|
+
}
|
|
106
120
|
};
|
|
107
121
|
const onDeselected = () => {
|
|
108
122
|
setSelectedObjectType(null);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { FabricObject } from "fabric";
|
|
1
|
+
import { Canvas, FabricObject } from "fabric";
|
|
2
2
|
export type Tool = "select" | "pan" | "pen" | "rectangle" | "circle" | "line" | "arrow" | "frame" | "text" | "image" | "eraser" | "connector" | "undo" | "redo";
|
|
3
3
|
export type ActiveDropdown = "task" | "document" | null;
|
|
4
4
|
export interface ToolOptions {
|
|
@@ -62,6 +62,10 @@ interface WhiteboardState {
|
|
|
62
62
|
addCanvasObject: (obj: FabricObject) => void;
|
|
63
63
|
removeCanvasObject: (obj: FabricObject) => void;
|
|
64
64
|
clearCanvasObjects: () => void;
|
|
65
|
+
bringToFront: (canvas: Canvas) => void;
|
|
66
|
+
sendToBack: (canvas: Canvas) => void;
|
|
67
|
+
bringForward: (canvas: Canvas) => void;
|
|
68
|
+
sendBackward: (canvas: Canvas) => void;
|
|
65
69
|
selectedObjects: FabricObject[];
|
|
66
70
|
setSelectedObjects: (objects: FabricObject[]) => void;
|
|
67
71
|
toolOptions: ToolOptions;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"whiteboard-store.d.ts","sourceRoot":"","sources":["../../src/store/whiteboard-store.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"whiteboard-store.d.ts","sourceRoot":"","sources":["../../src/store/whiteboard-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -81,4 +81,33 @@ export const useWhiteboardStore = create()((set, get) => ({
|
|
|
81
81
|
// ── Zoom ──────────────────────────────────────────────────────────────────
|
|
82
82
|
zoom: 1,
|
|
83
83
|
setZoom: (zoom) => set({ zoom }),
|
|
84
|
+
// ── Layer ordering ─────────────────────────────────────────────────────
|
|
85
|
+
bringToFront: (canvas) => {
|
|
86
|
+
const active = canvas.getActiveObject();
|
|
87
|
+
if (active) {
|
|
88
|
+
canvas.bringObjectToFront(active);
|
|
89
|
+
canvas.requestRenderAll();
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
sendToBack: (canvas) => {
|
|
93
|
+
const active = canvas.getActiveObject();
|
|
94
|
+
if (active) {
|
|
95
|
+
canvas.sendObjectToBack(active);
|
|
96
|
+
canvas.requestRenderAll();
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
bringForward: (canvas) => {
|
|
100
|
+
const active = canvas.getActiveObject();
|
|
101
|
+
if (active) {
|
|
102
|
+
canvas.bringObjectForward(active);
|
|
103
|
+
canvas.requestRenderAll();
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
sendBackward: (canvas) => {
|
|
107
|
+
const active = canvas.getActiveObject();
|
|
108
|
+
if (active) {
|
|
109
|
+
canvas.sendObjectBackwards(active);
|
|
110
|
+
canvas.requestRenderAll();
|
|
111
|
+
}
|
|
112
|
+
},
|
|
84
113
|
}));
|