@mhamz.01/easyflow-whiteboard 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/dist/components/node/custom-node-overlay-layer.d.ts +44 -0
- package/dist/components/node/custom-node-overlay-layer.d.ts.map +1 -0
- package/dist/components/node/custom-node-overlay-layer.js +353 -0
- package/dist/components/node/custom-node.d.ts +17 -0
- package/dist/components/node/custom-node.d.ts.map +1 -0
- package/dist/components/node/custom-node.js +63 -0
- package/dist/components/node/document-node.d.ts +14 -0
- package/dist/components/node/document-node.d.ts.map +1 -0
- package/dist/components/node/document-node.js +58 -0
- package/dist/components/toolbar/document-dropdown.d.ts +14 -0
- package/dist/components/toolbar/document-dropdown.d.ts.map +1 -0
- package/dist/components/toolbar/document-dropdown.js +66 -0
- package/dist/components/toolbar/options/arrow-options.d.ts +8 -0
- package/dist/components/toolbar/options/arrow-options.d.ts.map +1 -0
- package/dist/components/toolbar/options/arrow-options.js +109 -0
- package/dist/components/toolbar/options/erase-option.d.ts +2 -0
- package/dist/components/toolbar/options/erase-option.d.ts.map +1 -0
- package/dist/components/toolbar/options/erase-option.js +20 -0
- package/dist/components/toolbar/options/image-options.d.ts +2 -0
- package/dist/components/toolbar/options/image-options.d.ts.map +1 -0
- package/dist/components/toolbar/options/image-options.js +10 -0
- package/dist/components/toolbar/options/line-options.d.ts +2 -0
- package/dist/components/toolbar/options/line-options.d.ts.map +1 -0
- package/dist/components/toolbar/options/line-options.js +46 -0
- package/dist/components/toolbar/options/pen-option.d.ts +2 -0
- package/dist/components/toolbar/options/pen-option.d.ts.map +1 -0
- package/dist/components/toolbar/options/pen-option.js +53 -0
- package/dist/components/toolbar/options/shape-option.d.ts +6 -0
- package/dist/components/toolbar/options/shape-option.d.ts.map +1 -0
- package/dist/components/toolbar/options/shape-option.js +58 -0
- package/dist/components/toolbar/options/text-option.d.ts +2 -0
- package/dist/components/toolbar/options/text-option.d.ts.map +1 -0
- package/dist/components/toolbar/options/text-option.js +73 -0
- package/dist/components/toolbar/task-dropdown.d.ts +15 -0
- package/dist/components/toolbar/task-dropdown.d.ts.map +1 -0
- package/dist/components/toolbar/task-dropdown.js +85 -0
- package/dist/components/toolbar/toolbar-button.d.ts +12 -0
- package/dist/components/toolbar/toolbar-button.d.ts.map +1 -0
- package/dist/components/toolbar/toolbar-button.js +8 -0
- package/dist/components/toolbar/toolbar-seperator.d.ts +6 -0
- package/dist/components/toolbar/toolbar-seperator.d.ts.map +1 -0
- package/dist/components/toolbar/toolbar-seperator.js +5 -0
- package/dist/components/toolbar/tooloptions-panel.d.ts +8 -0
- package/dist/components/toolbar/tooloptions-panel.d.ts.map +1 -0
- package/dist/components/toolbar/tooloptions-panel.js +88 -0
- package/dist/components/toolbar/whiteboard-toolbar.d.ts +28 -0
- package/dist/components/toolbar/whiteboard-toolbar.d.ts.map +1 -0
- package/dist/components/toolbar/whiteboard-toolbar.js +160 -0
- package/dist/components/ui/dropdown-menu.d.ts +26 -0
- package/dist/components/ui/dropdown-menu.d.ts.map +1 -0
- package/dist/components/ui/dropdown-menu.js +51 -0
- package/dist/components/ui/label.d.ts +5 -0
- package/dist/components/ui/label.d.ts.map +1 -0
- package/dist/components/ui/label.js +8 -0
- package/dist/components/ui/slider.d.ts +5 -0
- package/dist/components/ui/slider.d.ts.map +1 -0
- package/dist/components/ui/slider.js +14 -0
- package/dist/components/whiteboard/whiteboard-test.d.ts +2 -0
- package/dist/components/whiteboard/whiteboard-test.d.ts.map +1 -0
- package/dist/components/whiteboard/whiteboard-test.js +207 -0
- package/dist/components/whiteboard/whiteboard.d.ts +1 -0
- package/dist/components/whiteboard/whiteboard.d.ts.map +1 -0
- package/dist/components/whiteboard/whiteboard.js +911 -0
- package/dist/components/zoomcontrol/zoom-control.d.ts +9 -0
- package/dist/components/zoomcontrol/zoom-control.d.ts.map +1 -0
- package/dist/components/zoomcontrol/zoom-control.js +7 -0
- package/dist/hooks/useCanvasInit.d.ts +15 -0
- package/dist/hooks/useCanvasInit.d.ts.map +1 -0
- package/dist/hooks/useCanvasInit.js +89 -0
- package/dist/hooks/useDrawing.d.ts +23 -0
- package/dist/hooks/useDrawing.d.ts.map +1 -0
- package/dist/hooks/useDrawing.js +142 -0
- package/dist/hooks/useEraser.d.ts +27 -0
- package/dist/hooks/useEraser.d.ts.map +1 -0
- package/dist/hooks/useEraser.js +143 -0
- package/dist/hooks/useLiveUpdate.d.ts +9 -0
- package/dist/hooks/useLiveUpdate.d.ts.map +1 -0
- package/dist/hooks/useLiveUpdate.js +63 -0
- package/dist/hooks/useMouseHandlers.d.ts +25 -0
- package/dist/hooks/useMouseHandlers.d.ts.map +1 -0
- package/dist/hooks/useMouseHandlers.js +44 -0
- package/dist/hooks/usePan.d.ts +17 -0
- package/dist/hooks/usePan.d.ts.map +1 -0
- package/dist/hooks/usePan.js +80 -0
- package/dist/hooks/usePersistance.d.ts +13 -0
- package/dist/hooks/usePersistance.d.ts.map +1 -0
- package/dist/hooks/usePersistance.js +79 -0
- package/dist/hooks/useSelection.d.ts +21 -0
- package/dist/hooks/useSelection.d.ts.map +1 -0
- package/dist/hooks/useSelection.js +142 -0
- package/dist/hooks/useTextStyle.d.ts +9 -0
- package/dist/hooks/useTextStyle.d.ts.map +1 -0
- package/dist/hooks/useTextStyle.js +32 -0
- package/dist/hooks/useToolManager.d.ts +15 -0
- package/dist/hooks/useToolManager.d.ts.map +1 -0
- package/dist/hooks/useToolManager.js +115 -0
- package/dist/hooks/useZoom.d.ts +25 -0
- package/dist/hooks/useZoom.d.ts.map +1 -0
- package/dist/hooks/useZoom.js +133 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +30 -0
- package/dist/lib/eraser-brush.d.ts +1 -0
- package/dist/lib/eraser-brush.d.ts.map +1 -0
- package/dist/lib/eraser-brush.js +21 -0
- package/dist/lib/fabric-arrow.d.ts +16 -0
- package/dist/lib/fabric-arrow.d.ts.map +1 -0
- package/dist/lib/fabric-arrow.js +50 -0
- package/dist/lib/fabric-bidirectional-arrow.d.ts +20 -0
- package/dist/lib/fabric-bidirectional-arrow.d.ts.map +1 -0
- package/dist/lib/fabric-bidirectional-arrow.js +65 -0
- package/dist/lib/fabric-frame.d.ts +7 -0
- package/dist/lib/fabric-frame.d.ts.map +1 -0
- package/dist/lib/fabric-frame.js +25 -0
- package/dist/lib/fabric-utils.d.ts +30 -0
- package/dist/lib/fabric-utils.d.ts.map +1 -0
- package/dist/lib/fabric-utils.js +273 -0
- package/dist/lib/utils.d.ts +3 -0
- package/dist/lib/utils.d.ts.map +1 -0
- package/dist/lib/utils.js +5 -0
- package/dist/store/whiteboard-store.d.ts +99 -0
- package/dist/store/whiteboard-store.d.ts.map +1 -0
- package/dist/store/whiteboard-store.js +137 -0
- package/dist/types/canvas-node.d.ts +24 -0
- package/dist/types/canvas-node.d.ts.map +1 -0
- package/dist/types/canvas-node.js +1 -0
- package/package.json +34 -0
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, } from "../ui/dropdown-menu";
|
|
4
|
+
import { CheckSquare, Plus, Calendar, Hash } from "lucide-react";
|
|
5
|
+
import { useWhiteboardStore } from "../../store/whiteboard-store";
|
|
6
|
+
const AVAILABLE_TASKS = [
|
|
7
|
+
{
|
|
8
|
+
id: "task-1",
|
|
9
|
+
title: "Design landing page mockups",
|
|
10
|
+
status: "in-progress",
|
|
11
|
+
assignee: "Sarah Chen",
|
|
12
|
+
project: "Website Redesign",
|
|
13
|
+
priority: "high",
|
|
14
|
+
dueDate: "Feb 15",
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
id: "task-2",
|
|
18
|
+
title: "Implement user authentication",
|
|
19
|
+
status: "todo",
|
|
20
|
+
assignee: "John Doe",
|
|
21
|
+
project: "Backend API",
|
|
22
|
+
priority: "high",
|
|
23
|
+
dueDate: "Feb 18",
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
id: "task-3",
|
|
27
|
+
title: "Write API documentation",
|
|
28
|
+
status: "done",
|
|
29
|
+
assignee: "Mike Wilson",
|
|
30
|
+
project: "Documentation",
|
|
31
|
+
priority: "medium",
|
|
32
|
+
dueDate: "Feb 10",
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
id: "task-4",
|
|
36
|
+
title: "Setup CI/CD pipeline",
|
|
37
|
+
status: "todo",
|
|
38
|
+
assignee: "Alex Turner",
|
|
39
|
+
project: "DevOps",
|
|
40
|
+
priority: "low",
|
|
41
|
+
dueDate: "Feb 20",
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
id: "task-5",
|
|
45
|
+
title: "Database schema optimization",
|
|
46
|
+
status: "todo",
|
|
47
|
+
assignee: "Emma Davis",
|
|
48
|
+
project: "Backend API",
|
|
49
|
+
priority: "medium",
|
|
50
|
+
dueDate: "Feb 22",
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
id: "task-6",
|
|
54
|
+
title: "Mobile responsive testing",
|
|
55
|
+
status: "in-progress",
|
|
56
|
+
assignee: "Sarah Chen",
|
|
57
|
+
project: "Website Redesign",
|
|
58
|
+
priority: "high",
|
|
59
|
+
dueDate: "Feb 16",
|
|
60
|
+
},
|
|
61
|
+
];
|
|
62
|
+
export default function TaskDropdown({ onAddTask }) {
|
|
63
|
+
const setActiveTool = useWhiteboardStore((state) => state.setActiveTool);
|
|
64
|
+
const activeDropdown = useWhiteboardStore((s) => s.activeDropdown);
|
|
65
|
+
const setActiveDropdown = useWhiteboardStore((s) => s.setActiveDropdown);
|
|
66
|
+
const priorityColors = {
|
|
67
|
+
high: "bg-red-500",
|
|
68
|
+
medium: "bg-orange-500",
|
|
69
|
+
low: "bg-emerald-500",
|
|
70
|
+
};
|
|
71
|
+
return (_jsxs(DropdownMenu, { open: activeDropdown === "task", onOpenChange: (open) => {
|
|
72
|
+
if (open) {
|
|
73
|
+
setActiveTool("select");
|
|
74
|
+
setActiveDropdown("task");
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
setActiveDropdown(null);
|
|
78
|
+
}
|
|
79
|
+
}, children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx("button", { className: "flex items-center justify-center w-10 h-10 rounded-xl transition-all duration-300 text-white hover:bg-white/10", children: _jsx(CheckSquare, { className: "w-5 h-5", strokeWidth: 2.5 }) }) }), _jsxs(DropdownMenuContent, { side: "top", align: "start", sideOffset: 10, className: "w-[340px] bg-[#121214]/95 backdrop-blur-2xl border border-white/10 rounded-2xl shadow-[0_32px_64px_rgba(0,0,0,0.6)] p-0 z-[100]", children: [_jsx("div", { className: "flex items-center justify-between p-4 border-b border-white/5", children: _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("div", { className: "w-2 h-2 rounded-full bg-[#10B981] animate-pulse" }), _jsx("h3", { className: "text-xs font-bold uppercase tracking-widest text-gray-400", children: "Task Library" })] }) }), _jsx("div", { className: "max-h-80 overflow-y-auto p-2", children: AVAILABLE_TASKS.map((task) => (_jsxs("button", { onClick: () => {
|
|
80
|
+
// 1. Add the task to the canvas
|
|
81
|
+
onAddTask(task);
|
|
82
|
+
// 2. CLOSE the dropdown immediately
|
|
83
|
+
setActiveDropdown(null);
|
|
84
|
+
}, className: "group relative w-full p-3 hover:bg-white/5 rounded-xl transition-all text-left border border-transparent hover:border-white/5", children: [_jsx("div", { className: `absolute left-0 top-3 bottom-3 w-1 rounded-r-full ${priorityColors[task.priority || "low"]}` }), _jsxs("div", { className: "pl-3", children: [_jsx("h4", { className: "text-sm font-semibold text-gray-100 group-hover:text-[#10B981] transition-colors mb-1", children: task.title }), _jsxs("div", { className: "flex items-center gap-3 mt-2", children: [_jsxs("div", { className: "flex items-center gap-1 text-[10px] text-gray-500 font-medium", children: [_jsx(Hash, { className: "w-3 h-3" }), " ", task.project] }), task.dueDate && (_jsxs("div", { className: "flex items-center gap-1 text-[10px] text-gray-500 font-medium", children: [_jsx(Calendar, { className: "w-3 h-3" }), " ", task.dueDate] }))] })] })] }, task.id))) }), _jsx("div", { className: "p-3 bg-white/[0.02] border-t border-white/5", children: _jsxs("button", { className: "w-full py-2.5 flex items-center justify-center gap-2 text-xs font-bold text-gray-400 hover:text-white hover:bg-[#10B981] hover:text-black rounded-xl transition-all", children: [_jsx(Plus, { className: "w-4 h-4" }), " NEW TASK TEMPLATE"] }) })] })] }));
|
|
85
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { LucideIcon } from "lucide-react";
|
|
2
|
+
interface ToolButtonProps {
|
|
3
|
+
icon: LucideIcon;
|
|
4
|
+
label: string;
|
|
5
|
+
isActive: boolean;
|
|
6
|
+
onClick: () => void;
|
|
7
|
+
disabled?: boolean;
|
|
8
|
+
shortcut?: string;
|
|
9
|
+
}
|
|
10
|
+
export default function ToolButton({ icon: Icon, label, isActive, onClick, disabled, shortcut, }: ToolButtonProps): import("react/jsx-runtime").JSX.Element;
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=toolbar-button.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toolbar-button.d.ts","sourceRoot":"","sources":["../../../src/components/toolbar/toolbar-button.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAG1C,UAAU,eAAe;IACvB,IAAI,EAAE,UAAU,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,CAAC,OAAO,UAAU,UAAU,CAAC,EACjC,IAAI,EAAE,IAAI,EACV,KAAK,EACL,QAAQ,EACR,OAAO,EACP,QAAgB,EAChB,QAAQ,GACT,EAAE,eAAe,2CAkDjB"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { cn } from "../../lib/utils";
|
|
4
|
+
export default function ToolButton({ icon: Icon, label, isActive, onClick, disabled = false, shortcut, }) {
|
|
5
|
+
return (_jsxs("div", { className: "group/tooltip relative", children: [_jsx("button", { onClick: onClick, disabled: disabled, className: cn("relative flex items-center justify-center", "w-10 h-10 rounded-xl", "transition-all duration-200 ease-out", "focus-visible:outline-none focus-visible:ring-2", "focus-visible:ring-blue-500 focus-visible:ring-offset-2", "active:scale-95", "disabled:opacity-40 disabled:cursor-not-allowed", isActive
|
|
6
|
+
? "bg-[#A1A1A1] text-white shadow-sm"
|
|
7
|
+
: "text-white hover:bg-gray-100 hover:text-gray-900"), "aria-label": label, "aria-pressed": isActive, type: "button", children: _jsx(Icon, { size: 20, strokeWidth: 2, className: "transition-transform duration-200 group-hover:scale-110" }) }), _jsxs("div", { className: cn("absolute -top-11 left-1/2 -translate-x-1/2", "px-2 py-1.5 bg-gray-900 text-white rounded-md", "opacity-0 group-hover/tooltip:opacity-100", "transition-opacity duration-200", "pointer-events-none whitespace-nowrap z-[60]", "text-xs font-medium", "after:content-[''] after:absolute after:top-0 after:left-1/2", "after:-translate-x-1/2 after:-translate-y-full", "after:border-4 after:border-transparent after:border-b-gray-900"), children: [_jsx("span", { children: label }), shortcut && (_jsx("span", { className: "ml-2 opacity-70 text-[10px]", children: shortcut }))] })] }));
|
|
8
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toolbar-seperator.d.ts","sourceRoot":"","sources":["../../../src/components/toolbar/toolbar-seperator.tsx"],"names":[],"mappings":"AAEA,UAAU,qBAAqB;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,CAAC,OAAO,UAAU,gBAAgB,CAAC,EACvC,SAAc,GACf,EAAE,qBAAqB,2CAQvB"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { RefObject } from "react";
|
|
2
|
+
import * as fabric from "fabric";
|
|
3
|
+
interface ToolOptionsPanelProps {
|
|
4
|
+
fabricCanvas: RefObject<fabric.Canvas | null>;
|
|
5
|
+
}
|
|
6
|
+
export default function ToolOptionsPanel({ fabricCanvas, }: ToolOptionsPanelProps): import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
export {};
|
|
8
|
+
//# sourceMappingURL=tooloptions-panel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
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;AACvE,OAAO,KAAK,MAAM,MAAM,QAAQ,CAAC;AAYjC,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,2CAuMvB"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import { useEffect, useMemo, useState } from "react";
|
|
4
|
+
import { cn } from "../../lib/utils";
|
|
5
|
+
import { useWhiteboardStore } from "../../store/whiteboard-store";
|
|
6
|
+
import PenOptions from "./options/pen-option";
|
|
7
|
+
import ShapeOptions from "./options/shape-option";
|
|
8
|
+
import TextOptions from "./options/text-option";
|
|
9
|
+
import ImageOptions from "./options/image-options";
|
|
10
|
+
import LineOptions from "./options/line-options";
|
|
11
|
+
import ArrowOptions from "./options/arrow-options";
|
|
12
|
+
import { Rect, Circle, IText } from "fabric";
|
|
13
|
+
import { Settings2, ChevronDown } from "lucide-react";
|
|
14
|
+
export default function ToolOptionsPanel({ fabricCanvas, }) {
|
|
15
|
+
const activeTool = useWhiteboardStore((state) => state.activeTool);
|
|
16
|
+
const selectedObjectType = useWhiteboardStore((state) => state.selectedObjectType);
|
|
17
|
+
const toolOptions = useWhiteboardStore((state) => state.toolOptions);
|
|
18
|
+
const [isMobileExpanded, setIsMobileExpanded] = useState(false);
|
|
19
|
+
const displayTool = selectedObjectType || activeTool;
|
|
20
|
+
// Real-time fabric updates
|
|
21
|
+
useEffect(() => {
|
|
22
|
+
const canvas = fabricCanvas.current;
|
|
23
|
+
if (!canvas)
|
|
24
|
+
return;
|
|
25
|
+
const selectedObject = canvas.getActiveObject();
|
|
26
|
+
if (!selectedObject || !selectedObjectType)
|
|
27
|
+
return;
|
|
28
|
+
switch (selectedObjectType) {
|
|
29
|
+
case "rectangle":
|
|
30
|
+
if (selectedObject instanceof Rect) {
|
|
31
|
+
selectedObject.set({
|
|
32
|
+
fill: toolOptions.rectangle.fillColor,
|
|
33
|
+
stroke: toolOptions.rectangle.strokeColor,
|
|
34
|
+
strokeWidth: toolOptions.rectangle.strokeWidth,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
break;
|
|
38
|
+
case "circle":
|
|
39
|
+
if (selectedObject instanceof Circle) {
|
|
40
|
+
selectedObject.set({
|
|
41
|
+
fill: toolOptions.circle.fillColor,
|
|
42
|
+
stroke: toolOptions.circle.strokeColor,
|
|
43
|
+
strokeWidth: toolOptions.circle.strokeWidth,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
break;
|
|
47
|
+
case "text":
|
|
48
|
+
if (selectedObject instanceof IText) {
|
|
49
|
+
selectedObject.set({
|
|
50
|
+
fill: toolOptions.text.color,
|
|
51
|
+
fontSize: toolOptions.text.fontSize,
|
|
52
|
+
fontFamily: toolOptions.text.fontFamily,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
break;
|
|
56
|
+
}
|
|
57
|
+
canvas.renderAll();
|
|
58
|
+
}, [toolOptions, selectedObjectType, fabricCanvas]);
|
|
59
|
+
const toolsWithoutOptions = ["select", "pan", "undo", "redo", "eraser"];
|
|
60
|
+
const isOpen = useMemo(() => {
|
|
61
|
+
const target = selectedObjectType || activeTool;
|
|
62
|
+
return target && !toolsWithoutOptions.includes(target);
|
|
63
|
+
}, [activeTool, selectedObjectType]);
|
|
64
|
+
useEffect(() => {
|
|
65
|
+
if (!isOpen) {
|
|
66
|
+
setIsMobileExpanded(false);
|
|
67
|
+
}
|
|
68
|
+
}, [isOpen]);
|
|
69
|
+
return (_jsxs(_Fragment, { children: [_jsxs("aside", { className: cn("hidden md:flex", "fixed 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
|
|
70
|
+
? "translate-x-0 opacity-100 visible scale-100"
|
|
71
|
+
: "-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
|
+
"w-[calc(100%-80px)] max-w-[180px]", // Leave room on the right to tap canvas
|
|
73
|
+
"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: `
|
|
74
|
+
.custom-scrollbar::-webkit-scrollbar {
|
|
75
|
+
width: 4px;
|
|
76
|
+
}
|
|
77
|
+
.custom-scrollbar::-webkit-scrollbar-track {
|
|
78
|
+
background: transparent;
|
|
79
|
+
}
|
|
80
|
+
.custom-scrollbar::-webkit-scrollbar-thumb {
|
|
81
|
+
background: rgba(255, 255, 255, 0.1);
|
|
82
|
+
border-radius: 10px;
|
|
83
|
+
}
|
|
84
|
+
.custom-scrollbar::-webkit-scrollbar-thumb:hover {
|
|
85
|
+
background: #029AFF;
|
|
86
|
+
}
|
|
87
|
+
` })] }));
|
|
88
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { MutableRefObject } from "react";
|
|
2
|
+
import { Canvas } from "fabric";
|
|
3
|
+
interface TaskTemplate {
|
|
4
|
+
id: string;
|
|
5
|
+
title: string;
|
|
6
|
+
status: "todo" | "in-progress" | "done";
|
|
7
|
+
assignee?: string;
|
|
8
|
+
project?: string;
|
|
9
|
+
priority?: "low" | "medium" | "high";
|
|
10
|
+
dueDate?: string;
|
|
11
|
+
}
|
|
12
|
+
interface DocumentTemplate {
|
|
13
|
+
id: string;
|
|
14
|
+
title: string;
|
|
15
|
+
project: string;
|
|
16
|
+
breadcrumb?: string[];
|
|
17
|
+
preview: string;
|
|
18
|
+
updatedAt?: string;
|
|
19
|
+
}
|
|
20
|
+
interface WhiteboardToolbarProps {
|
|
21
|
+
fabricCanvas: MutableRefObject<Canvas | null>;
|
|
22
|
+
isRestoringRef: MutableRefObject<boolean>;
|
|
23
|
+
onAddTask?: (task: TaskTemplate) => void;
|
|
24
|
+
onAddDocument?: (doc: DocumentTemplate) => void;
|
|
25
|
+
}
|
|
26
|
+
export default function WhiteboardToolbar({ fabricCanvas, isRestoringRef, onAddTask, onAddDocument }: WhiteboardToolbarProps): import("react/jsx-runtime").JSX.Element;
|
|
27
|
+
export {};
|
|
28
|
+
//# sourceMappingURL=whiteboard-toolbar.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"whiteboard-toolbar.d.ts","sourceRoot":"","sources":["../../../src/components/toolbar/whiteboard-toolbar.tsx"],"names":[],"mappings":"AAEA,OAAa,EAAqB,gBAAgB,EAAY,MAAM,OAAO,CAAC;AAI5E,OAAO,EAAE,MAAM,EAAQ,MAAM,QAAQ,CAAC;AAOtC,UAAU,YAAY;IACpB,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,GAAG,aAAa,GAAG,MAAM,CAAC;IACnE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC7F;AACD,UAAU,gBAAgB;IACxB,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAC3C,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC5D;AAkBD,UAAU,sBAAsB;IAC9B,YAAY,EAAE,gBAAgB,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC9C,cAAc,EAAE,gBAAgB,CAAC,OAAO,CAAC,CAAC;IAC1C,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,IAAI,CAAC;IACzC,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,gBAAgB,KAAK,IAAI,CAAC;CACjD;AAED,MAAM,CAAC,OAAO,UAAU,iBAAiB,CAAC,EAAE,YAAY,EAAE,cAAc,EAAE,SAAS,EAAE,aAAa,EAAE,EAAE,sBAAsB,2CAiM3H"}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import { useEffect, useRef, useState } from "react";
|
|
4
|
+
import { MousePointer2, Pencil, Square, Circle, Minus, MoveRight, Type, Eraser, Hand, Frame, Undo2, Redo2, Image as ImageIcon, } from "lucide-react";
|
|
5
|
+
import { util } from "fabric";
|
|
6
|
+
import { useWhiteboardStore } from "../../store/whiteboard-store";
|
|
7
|
+
import ToolButton from "./toolbar-button";
|
|
8
|
+
import ToolbarSeparator from "./toolbar-seperator";
|
|
9
|
+
import TaskDropdown from "./task-dropdown";
|
|
10
|
+
import DocumentDropdown from "./document-dropdown";
|
|
11
|
+
import { deleteSelectedObjects, addImageToCanvas } from "../../lib/fabric-utils";
|
|
12
|
+
const TOOLS = [
|
|
13
|
+
{ id: "select", icon: MousePointer2, label: "Select", shortcut: "V", category: "basic" },
|
|
14
|
+
{ id: "pan", icon: Hand, label: "Pan", shortcut: "H", category: "navigation" },
|
|
15
|
+
{ id: "pen", icon: Pencil, label: "Pen", shortcut: "P", category: "drawing" },
|
|
16
|
+
{ id: "rectangle", icon: Square, label: "Rectangle", shortcut: "R", category: "shapes" },
|
|
17
|
+
{ id: "circle", icon: Circle, label: "Circle", shortcut: "C", category: "shapes" },
|
|
18
|
+
{ id: "frame", icon: Frame, label: "Frame", shortcut: "F", category: "shapes" },
|
|
19
|
+
{ id: "line", icon: Minus, label: "Line", shortcut: "L", category: "shapes" },
|
|
20
|
+
{ id: "arrow", icon: MoveRight, label: "Arrow", shortcut: "A", category: "shapes" },
|
|
21
|
+
{ id: "text", icon: Type, label: "Text", shortcut: "T", category: "drawing" },
|
|
22
|
+
{ id: "image", icon: ImageIcon, label: "Image", shortcut: "I", category: "media" },
|
|
23
|
+
{ id: "eraser", icon: Eraser, label: "Eraser", shortcut: "E", category: "drawing" },
|
|
24
|
+
{ id: "undo", icon: Undo2, label: "Undo", shortcut: "⌘Z", category: "history" },
|
|
25
|
+
{ id: "redo", icon: Redo2, label: "Redo", shortcut: "⌘⇧Z", category: "history" },
|
|
26
|
+
];
|
|
27
|
+
export default function WhiteboardToolbar({ fabricCanvas, isRestoringRef, onAddTask, onAddDocument }) {
|
|
28
|
+
const activeTool = useWhiteboardStore((s) => s.activeTool);
|
|
29
|
+
const setActiveTool = useWhiteboardStore((s) => s.setActiveTool);
|
|
30
|
+
const canUndo = useWhiteboardStore((s) => s.canUndo);
|
|
31
|
+
const canRedo = useWhiteboardStore((s) => s.canRedo);
|
|
32
|
+
const undo = useWhiteboardStore((s) => s.undo);
|
|
33
|
+
const redo = useWhiteboardStore((s) => s.redo);
|
|
34
|
+
const scrollRef = useRef(null);
|
|
35
|
+
const [scrollPosition, setScrollPosition] = useState(0);
|
|
36
|
+
const fileInputRef = useRef(null);
|
|
37
|
+
const handleScroll = () => {
|
|
38
|
+
if (scrollRef.current) {
|
|
39
|
+
const { scrollLeft, scrollWidth, clientWidth } = scrollRef.current;
|
|
40
|
+
const position = scrollLeft / (scrollWidth - clientWidth);
|
|
41
|
+
setScrollPosition(position);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
// fade out and remove the welcome hero when user selects a tool for the first time
|
|
45
|
+
useEffect(() => {
|
|
46
|
+
const canvas = fabricCanvas.current;
|
|
47
|
+
// If the user selects something other than the default 'select' tool
|
|
48
|
+
if (!canvas || activeTool === "select")
|
|
49
|
+
return;
|
|
50
|
+
const hero = canvas.getObjects().find((obj) => obj.id === "welcome-hero");
|
|
51
|
+
if (hero) {
|
|
52
|
+
hero.animate({
|
|
53
|
+
opacity: 0,
|
|
54
|
+
top: (hero.top || 0) - 20 // Subtle "lift" animation on exit
|
|
55
|
+
}, {
|
|
56
|
+
duration: 500,
|
|
57
|
+
easing: util.ease.easeInQuad,
|
|
58
|
+
onChange: () => canvas.requestRenderAll(),
|
|
59
|
+
onComplete: () => {
|
|
60
|
+
canvas.remove(hero);
|
|
61
|
+
canvas.requestRenderAll();
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}, [activeTool]);
|
|
66
|
+
// ── Restore helper ───────────────────────────────────────────────────────────
|
|
67
|
+
// Sets isRestoringRef=true BEFORE loadFromJSON so that the object:added events
|
|
68
|
+
// fired during restore do NOT push new entries onto the history stack.
|
|
69
|
+
// Without this, undo corrupts the stack and redo breaks permanently.
|
|
70
|
+
const restoreCanvas = (canvas, json) => {
|
|
71
|
+
isRestoringRef.current = true; // ← block saveState during restore
|
|
72
|
+
canvas.loadFromJSON(JSON.parse(json)).then(() => {
|
|
73
|
+
canvas.isDrawingMode = false;
|
|
74
|
+
canvas.selection = true;
|
|
75
|
+
canvas.forEachObject((obj) => { obj.selectable = true; obj.evented = true; });
|
|
76
|
+
canvas.renderAll();
|
|
77
|
+
setActiveTool("select");
|
|
78
|
+
isRestoringRef.current = false; // ← re-enable saveState after restore done
|
|
79
|
+
});
|
|
80
|
+
};
|
|
81
|
+
const handleToolClick = (toolId) => {
|
|
82
|
+
const canvas = fabricCanvas.current;
|
|
83
|
+
if (!canvas)
|
|
84
|
+
return;
|
|
85
|
+
canvas.discardActiveObject();
|
|
86
|
+
canvas.renderAll();
|
|
87
|
+
if (toolId === "undo") {
|
|
88
|
+
const state = undo();
|
|
89
|
+
if (state)
|
|
90
|
+
restoreCanvas(canvas, state);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
if (toolId === "redo") {
|
|
94
|
+
const state = redo();
|
|
95
|
+
if (state)
|
|
96
|
+
restoreCanvas(canvas, state);
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
if (toolId === "image") {
|
|
100
|
+
fileInputRef.current?.click();
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
setActiveTool(toolId);
|
|
104
|
+
};
|
|
105
|
+
const handleImageUpload = (e) => {
|
|
106
|
+
const file = e.target.files?.[0];
|
|
107
|
+
if (!file || !file.type.startsWith("image/"))
|
|
108
|
+
return;
|
|
109
|
+
const canvas = fabricCanvas.current;
|
|
110
|
+
if (!canvas)
|
|
111
|
+
return;
|
|
112
|
+
const reader = new FileReader();
|
|
113
|
+
reader.onload = (ev) => { const url = ev.target?.result; if (url)
|
|
114
|
+
addImageToCanvas(canvas, url); };
|
|
115
|
+
reader.readAsDataURL(file);
|
|
116
|
+
e.target.value = "";
|
|
117
|
+
};
|
|
118
|
+
// Keyboard shortcuts
|
|
119
|
+
useEffect(() => {
|
|
120
|
+
const onKey = (e) => {
|
|
121
|
+
if (e.target instanceof HTMLInputElement || e.target instanceof HTMLTextAreaElement)
|
|
122
|
+
return;
|
|
123
|
+
const key = e.key.toLowerCase();
|
|
124
|
+
const ctrl = e.ctrlKey || e.metaKey;
|
|
125
|
+
const shortcuts = { v: "select", h: "pan", p: "pen", r: "rectangle", c: "circle", f: "frame", l: "line", a: "arrow", t: "text", i: "image", e: "eraser" };
|
|
126
|
+
if (shortcuts[key] && !ctrl) {
|
|
127
|
+
e.preventDefault();
|
|
128
|
+
handleToolClick(shortcuts[key]);
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
if (key === "delete" || key === "backspace") {
|
|
132
|
+
if (fabricCanvas.current && activeTool === "select") {
|
|
133
|
+
e.preventDefault();
|
|
134
|
+
deleteSelectedObjects(fabricCanvas.current);
|
|
135
|
+
}
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
if (ctrl) {
|
|
139
|
+
if (key === "z" && !e.shiftKey) {
|
|
140
|
+
e.preventDefault();
|
|
141
|
+
handleToolClick("undo");
|
|
142
|
+
}
|
|
143
|
+
else if ((key === "z" && e.shiftKey) || key === "y") {
|
|
144
|
+
e.preventDefault();
|
|
145
|
+
handleToolClick("redo");
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
window.addEventListener("keydown", onKey);
|
|
150
|
+
return () => window.removeEventListener("keydown", onKey);
|
|
151
|
+
}, [canUndo, canRedo, activeTool]);
|
|
152
|
+
return (_jsxs(_Fragment, { children: [_jsx("input", { ref: fileInputRef, type: "file", accept: "image/*", onChange: handleImageUpload, className: "hidden" }), _jsxs("div", { className: "fixed bottom-4 md:bottom-6 left-0 right-0 z-50 flex flex-col items-center gap-2 px-4 pointer-events-none", children: [_jsxs("div", { className: "relative w-full md:w-auto max-w-full pointer-events-auto", children: [_jsx("div", { className: "absolute left-0 top-0 bottom-0 w-8 bg-gradient-to-r from-[#0b0b0b] to-transparent pointer-events-none z-10 md:hidden rounded-l-2xl" }), _jsx("div", { className: "absolute right-0 top-0 bottom-0 w-8 bg-gradient-to-l from-[#0b0b0b] to-transparent pointer-events-none z-10 md:hidden rounded-r-2xl" }), _jsxs("div", { ref: scrollRef, onScroll: handleScroll, className: "flex items-center gap-1 px-2 py-2 bg-black/95 backdrop-blur-md border border-[#A1A1A1] rounded-2xl shadow-2xl overflow-x-auto md:overflow-x-visible snap-x snap-mandatory md:snap-none scrollbar-hide scroll-smooth", children: [TOOLS.map((tool, index) => (_jsxs("div", { className: "flex items-center snap-center", children: [_jsx(ToolButton, { icon: tool.icon, label: tool.label, isActive: activeTool === tool.id, onClick: () => handleToolClick(tool.id), disabled: (tool.id === "undo" && !canUndo) || (tool.id === "redo" && !canRedo), shortcut: tool.shortcut }), (index === 1 || index === 9) && (_jsx("div", { className: "hidden md:block mx-1", children: _jsx(ToolbarSeparator, {}) }))] }, tool.id))), (onAddTask || onAddDocument) && (_jsxs("div", { className: "flex items-center gap-1 snap-center pr-2", children: [_jsx("div", { className: "mx-1 flex-shrink-0", children: _jsx(ToolbarSeparator, {}) }), onAddTask && _jsx(TaskDropdown, { onAddTask: onAddTask }), onAddDocument && _jsx(DocumentDropdown, { onAddDocument: onAddDocument })] }))] })] }), _jsxs("div", { className: "flex gap-1.5 md:hidden", children: [_jsx("div", { className: `w-1.5 h-1.5 rounded-full transition-all duration-300 ${scrollPosition < 0.5 ? "bg-white w-6" : "bg-white/30"}` }), _jsx("div", { className: `w-1.5 h-1.5 rounded-full transition-all duration-300 ${scrollPosition >= 0.5 ? "bg-white w-6" : "bg-white/30"}` })] })] }), _jsx("style", { children: `
|
|
153
|
+
.scrollbar-hide::-webkit-scrollbar { display: none; }
|
|
154
|
+
.scrollbar-hide {
|
|
155
|
+
-ms-overflow-style: none;
|
|
156
|
+
scrollbar-width: none;
|
|
157
|
+
-webkit-overflow-scrolling: touch;
|
|
158
|
+
}
|
|
159
|
+
` })] }));
|
|
160
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { DropdownMenu as DropdownMenuPrimitive } from "radix-ui";
|
|
3
|
+
declare function DropdownMenu({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Root>): import("react/jsx-runtime").JSX.Element;
|
|
4
|
+
declare function DropdownMenuPortal({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Portal>): import("react/jsx-runtime").JSX.Element;
|
|
5
|
+
declare function DropdownMenuTrigger({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Trigger>): import("react/jsx-runtime").JSX.Element;
|
|
6
|
+
declare function DropdownMenuContent({ className, sideOffset, ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Content>): import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
declare function DropdownMenuGroup({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Group>): import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
declare function DropdownMenuItem({ className, inset, variant, ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Item> & {
|
|
9
|
+
inset?: boolean;
|
|
10
|
+
variant?: "default" | "destructive";
|
|
11
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
declare function DropdownMenuCheckboxItem({ className, children, checked, ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.CheckboxItem>): import("react/jsx-runtime").JSX.Element;
|
|
13
|
+
declare function DropdownMenuRadioGroup({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.RadioGroup>): import("react/jsx-runtime").JSX.Element;
|
|
14
|
+
declare function DropdownMenuRadioItem({ className, children, ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.RadioItem>): import("react/jsx-runtime").JSX.Element;
|
|
15
|
+
declare function DropdownMenuLabel({ className, inset, ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Label> & {
|
|
16
|
+
inset?: boolean;
|
|
17
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
18
|
+
declare function DropdownMenuSeparator({ className, ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Separator>): import("react/jsx-runtime").JSX.Element;
|
|
19
|
+
declare function DropdownMenuShortcut({ className, ...props }: React.ComponentProps<"span">): import("react/jsx-runtime").JSX.Element;
|
|
20
|
+
declare function DropdownMenuSub({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Sub>): import("react/jsx-runtime").JSX.Element;
|
|
21
|
+
declare function DropdownMenuSubTrigger({ className, inset, children, ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.SubTrigger> & {
|
|
22
|
+
inset?: boolean;
|
|
23
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
24
|
+
declare function DropdownMenuSubContent({ className, ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.SubContent>): import("react/jsx-runtime").JSX.Element;
|
|
25
|
+
export { DropdownMenu, DropdownMenuPortal, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuGroup, DropdownMenuLabel, DropdownMenuItem, DropdownMenuCheckboxItem, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubTrigger, DropdownMenuSubContent, };
|
|
26
|
+
//# sourceMappingURL=dropdown-menu.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dropdown-menu.d.ts","sourceRoot":"","sources":["../../../src/components/ui/dropdown-menu.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react";
|
|
4
|
+
import { DropdownMenu as DropdownMenuPrimitive } from "radix-ui";
|
|
5
|
+
import { cn } from "../../lib/utils";
|
|
6
|
+
function DropdownMenu({ ...props }) {
|
|
7
|
+
return _jsx(DropdownMenuPrimitive.Root, { "data-slot": "dropdown-menu", ...props });
|
|
8
|
+
}
|
|
9
|
+
function DropdownMenuPortal({ ...props }) {
|
|
10
|
+
return (_jsx(DropdownMenuPrimitive.Portal, { "data-slot": "dropdown-menu-portal", ...props }));
|
|
11
|
+
}
|
|
12
|
+
function DropdownMenuTrigger({ ...props }) {
|
|
13
|
+
return (_jsx(DropdownMenuPrimitive.Trigger, { "data-slot": "dropdown-menu-trigger", ...props }));
|
|
14
|
+
}
|
|
15
|
+
function DropdownMenuContent({ className, sideOffset = 4, ...props }) {
|
|
16
|
+
return (_jsx(DropdownMenuPrimitive.Portal, { children: _jsx(DropdownMenuPrimitive.Content, { "data-slot": "dropdown-menu-content", sideOffset: sideOffset, className: cn("z-50 max-h-(--radix-dropdown-menu-content-available-height) min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95", className), ...props }) }));
|
|
17
|
+
}
|
|
18
|
+
function DropdownMenuGroup({ ...props }) {
|
|
19
|
+
return (_jsx(DropdownMenuPrimitive.Group, { "data-slot": "dropdown-menu-group", ...props }));
|
|
20
|
+
}
|
|
21
|
+
function DropdownMenuItem({ className, inset, variant = "default", ...props }) {
|
|
22
|
+
return (_jsx(DropdownMenuPrimitive.Item, { "data-slot": "dropdown-menu-item", "data-inset": inset, "data-variant": variant, className: cn("relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/20 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground data-[variant=destructive]:*:[svg]:text-destructive!", className), ...props }));
|
|
23
|
+
}
|
|
24
|
+
function DropdownMenuCheckboxItem({ className, children, checked, ...props }) {
|
|
25
|
+
return (_jsxs(DropdownMenuPrimitive.CheckboxItem, { "data-slot": "dropdown-menu-checkbox-item", className: cn("relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", className), checked: checked, ...props, children: [_jsx("span", { className: "pointer-events-none absolute left-2 flex size-3.5 items-center justify-center", children: _jsx(DropdownMenuPrimitive.ItemIndicator, { children: _jsx(CheckIcon, { className: "size-4" }) }) }), children] }));
|
|
26
|
+
}
|
|
27
|
+
function DropdownMenuRadioGroup({ ...props }) {
|
|
28
|
+
return (_jsx(DropdownMenuPrimitive.RadioGroup, { "data-slot": "dropdown-menu-radio-group", ...props }));
|
|
29
|
+
}
|
|
30
|
+
function DropdownMenuRadioItem({ className, children, ...props }) {
|
|
31
|
+
return (_jsxs(DropdownMenuPrimitive.RadioItem, { "data-slot": "dropdown-menu-radio-item", className: cn("relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", className), ...props, children: [_jsx("span", { className: "pointer-events-none absolute left-2 flex size-3.5 items-center justify-center", children: _jsx(DropdownMenuPrimitive.ItemIndicator, { children: _jsx(CircleIcon, { className: "size-2 fill-current" }) }) }), children] }));
|
|
32
|
+
}
|
|
33
|
+
function DropdownMenuLabel({ className, inset, ...props }) {
|
|
34
|
+
return (_jsx(DropdownMenuPrimitive.Label, { "data-slot": "dropdown-menu-label", "data-inset": inset, className: cn("px-2 py-1.5 text-sm font-medium data-[inset]:pl-8", className), ...props }));
|
|
35
|
+
}
|
|
36
|
+
function DropdownMenuSeparator({ className, ...props }) {
|
|
37
|
+
return (_jsx(DropdownMenuPrimitive.Separator, { "data-slot": "dropdown-menu-separator", className: cn("-mx-1 my-1 h-px bg-border", className), ...props }));
|
|
38
|
+
}
|
|
39
|
+
function DropdownMenuShortcut({ className, ...props }) {
|
|
40
|
+
return (_jsx("span", { "data-slot": "dropdown-menu-shortcut", className: cn("ml-auto text-xs tracking-widest text-muted-foreground", className), ...props }));
|
|
41
|
+
}
|
|
42
|
+
function DropdownMenuSub({ ...props }) {
|
|
43
|
+
return _jsx(DropdownMenuPrimitive.Sub, { "data-slot": "dropdown-menu-sub", ...props });
|
|
44
|
+
}
|
|
45
|
+
function DropdownMenuSubTrigger({ className, inset, children, ...props }) {
|
|
46
|
+
return (_jsxs(DropdownMenuPrimitive.SubTrigger, { "data-slot": "dropdown-menu-sub-trigger", "data-inset": inset, className: cn("flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[inset]:pl-8 data-[state=open]:bg-accent data-[state=open]:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground", className), ...props, children: [children, _jsx(ChevronRightIcon, { className: "ml-auto size-4" })] }));
|
|
47
|
+
}
|
|
48
|
+
function DropdownMenuSubContent({ className, ...props }) {
|
|
49
|
+
return (_jsx(DropdownMenuPrimitive.SubContent, { "data-slot": "dropdown-menu-sub-content", className: cn("z-50 min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95", className), ...props }));
|
|
50
|
+
}
|
|
51
|
+
export { DropdownMenu, DropdownMenuPortal, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuGroup, DropdownMenuLabel, DropdownMenuItem, DropdownMenuCheckboxItem, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubTrigger, DropdownMenuSubContent, };
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { Label as LabelPrimitive } from "radix-ui";
|
|
3
|
+
declare function Label({ className, ...props }: React.ComponentProps<typeof LabelPrimitive.Root>): import("react/jsx-runtime").JSX.Element;
|
|
4
|
+
export { Label };
|
|
5
|
+
//# sourceMappingURL=label.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"label.d.ts","sourceRoot":"","sources":["../../../src/components/ui/label.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EAAE,KAAK,IAAI,cAAc,EAAE,MAAM,UAAU,CAAA;AAIlD,iBAAS,KAAK,CAAC,EACb,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,cAAc,CAAC,IAAI,CAAC,2CAWlD;AAED,OAAO,EAAE,KAAK,EAAE,CAAA"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { Label as LabelPrimitive } from "radix-ui";
|
|
4
|
+
import { cn } from "../../lib/utils";
|
|
5
|
+
function Label({ className, ...props }) {
|
|
6
|
+
return (_jsx(LabelPrimitive.Root, { "data-slot": "label", className: cn("flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50", className), ...props }));
|
|
7
|
+
}
|
|
8
|
+
export { Label };
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { Slider as SliderPrimitive } from "radix-ui";
|
|
3
|
+
declare function Slider({ className, defaultValue, value, min, max, ...props }: React.ComponentProps<typeof SliderPrimitive.Root>): import("react/jsx-runtime").JSX.Element;
|
|
4
|
+
export { Slider };
|
|
5
|
+
//# sourceMappingURL=slider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slider.d.ts","sourceRoot":"","sources":["../../../src/components/ui/slider.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EAAE,MAAM,IAAI,eAAe,EAAE,MAAM,UAAU,CAAA;AAIpD,iBAAS,MAAM,CAAC,EACd,SAAS,EACT,YAAY,EACZ,KAAK,EACL,GAAO,EACP,GAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,eAAe,CAAC,IAAI,CAAC,2CA8CnD;AAED,OAAO,EAAE,MAAM,EAAE,CAAA"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { Slider as SliderPrimitive } from "radix-ui";
|
|
5
|
+
import { cn } from "../../lib/utils";
|
|
6
|
+
function Slider({ className, defaultValue, value, min = 0, max = 100, ...props }) {
|
|
7
|
+
const _values = React.useMemo(() => Array.isArray(value)
|
|
8
|
+
? value
|
|
9
|
+
: Array.isArray(defaultValue)
|
|
10
|
+
? defaultValue
|
|
11
|
+
: [min, max], [value, defaultValue, min, max]);
|
|
12
|
+
return (_jsxs(SliderPrimitive.Root, { "data-slot": "slider", defaultValue: defaultValue, value: value, min: min, max: max, className: cn("relative flex w-full touch-none items-center select-none data-[disabled]:opacity-50 data-[orientation=vertical]:h-full data-[orientation=vertical]:min-h-44 data-[orientation=vertical]:w-auto data-[orientation=vertical]:flex-col", className), ...props, children: [_jsx(SliderPrimitive.Track, { "data-slot": "slider-track", className: cn("bg-muted relative grow overflow-hidden rounded-full data-[orientation=horizontal]:h-1.5 data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-1.5"), children: _jsx(SliderPrimitive.Range, { "data-slot": "slider-range", className: cn("bg-primary absolute data-[orientation=horizontal]:h-full data-[orientation=vertical]:w-full") }) }), Array.from({ length: _values.length }, (_, index) => (_jsx(SliderPrimitive.Thumb, { "data-slot": "slider-thumb", className: "border-primary ring-ring/50 block size-4 shrink-0 rounded-full border bg-white shadow-sm transition-[color,box-shadow] hover:ring-4 focus-visible:ring-4 focus-visible:outline-hidden disabled:pointer-events-none disabled:opacity-50" }, index)))] }));
|
|
13
|
+
}
|
|
14
|
+
export { Slider };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"whiteboard-test.d.ts","sourceRoot":"","sources":["../../../src/components/whiteboard/whiteboard-test.tsx"],"names":[],"mappings":"AA4CA,MAAM,CAAC,OAAO,UAAU,gBAAgB,4CAkQvC"}
|