diff --git a/code/components/actions/color-token-tool/color-token-tool.ts b/code/components/actions/color-token-tool/color-token-tool.ts index 077f994d..40fdf776 100644 --- a/code/components/actions/color-token-tool/color-token-tool.ts +++ b/code/components/actions/color-token-tool/color-token-tool.ts @@ -137,7 +137,7 @@ export class ColorTokenToolAction extends WeaveAction { } this.instance.emitEvent( - "onAddingColorToken" + "onAddingColorToken", ); this.colorTokenId = null; @@ -166,7 +166,7 @@ export class ColorTokenToolAction extends WeaveAction { this.instance.addNode(node, this.container?.getAttrs().id); this.instance.emitEvent( - "onAddedColorToken" + "onAddedColorToken", ); } @@ -175,7 +175,7 @@ export class ColorTokenToolAction extends WeaveAction { trigger( cancelAction: () => void, - params?: ColorTokenToolActionTriggerParams + params?: ColorTokenToolActionTriggerParams, ) { if (!this.instance) { throw new Error("Instance not defined"); diff --git a/code/components/actions/image-template-tool/image-template-tool.ts b/code/components/actions/image-template-tool/image-template-tool.ts index bb3ecb22..7d8928fc 100644 --- a/code/components/actions/image-template-tool/image-template-tool.ts +++ b/code/components/actions/image-template-tool/image-template-tool.ts @@ -157,7 +157,7 @@ export class ImageTemplateToolAction extends WeaveAction { this.setCursor(); this.instance.emitEvent( - "onAddingImageTemplate" + "onAddingImageTemplate", ); this.imageTemplateId = null; @@ -203,7 +203,7 @@ export class ImageTemplateToolAction extends WeaveAction { this.container ) { const { mousePoint } = this.instance.getMousePointerRelativeToContainer( - this.container + this.container, ); const rectPos: Konva.Vector2d = { @@ -243,7 +243,7 @@ export class ImageTemplateToolAction extends WeaveAction { } this.instance.emitEvent( - "onAddedImageTemplate" + "onAddedImageTemplate", ); } @@ -264,7 +264,7 @@ export class ImageTemplateToolAction extends WeaveAction { this.moved = true; const { mousePoint } = this.instance.getMousePointerRelativeToContainer( - this.measureContainer + this.measureContainer, ); const deltaX = mousePoint.x - this.clickPoint?.x; diff --git a/code/components/actions/images-tool/images-tool.ts b/code/components/actions/images-tool/images-tool.ts index 6facc5b8..52784225 100644 --- a/code/components/actions/images-tool/images-tool.ts +++ b/code/components/actions/images-tool/images-tool.ts @@ -17,6 +17,7 @@ import { ImageInfo, ImagesToolActionOnAddedImageEvent, ImagesToolActionOnAddingImageEvent, + // ImagesToolDragAndDropProperties, } from "./types"; import { IMAGES_TOOL_ACTION_NAME, IMAGES_TOOL_STATE } from "./constants"; @@ -29,6 +30,7 @@ export class ImagesToolAction extends WeaveAction { protected tempImageNode: Konva.Group | null; protected pointers: Map; protected container: Konva.Layer | Konva.Group | undefined; + protected imagesIds: string[] = []; protected images: Record< string, { @@ -42,6 +44,7 @@ export class ImagesToolAction extends WeaveAction { protected preloadImgs: Record; protected clickPoint: Vector2d | null; protected cancelAction!: () => void; + onInit = undefined; onPropsChange = undefined; update = undefined; @@ -77,26 +80,6 @@ export class ImagesToolAction extends WeaveAction { }; } - onInit(): void { - this.instance.addEventListener("onStageDrop", (e) => { - if (window.weaveDragImageURL) { - this.instance.getStage().setPointersPositions(e); - const position = this.instance.getStage().getRelativePointerPosition(); - this.instance.triggerAction("imageTool", { - imageURL: window.weaveDragImageURL, - position, - }); - if (window.weaveDragImageId) { - this.instance.updatePropsAction("imageTool", { - imageId: window.weaveDragImageId, - }); - window.weaveDragImageId = undefined; - } - window.weaveDragImageURL = undefined; - } - }); - } - private setupEvents() { const stage = this.instance.getStage(); @@ -190,14 +173,14 @@ export class ImagesToolAction extends WeaveAction { this.preloadImgs[imageId].onerror = () => { this.instance.emitEvent( "onImageLoadEnd", - new Error("Error loading image") + new Error("Error loading image"), ); this.cancelAction(); }; this.preloadImgs[imageId].onload = () => { this.instance.emitEvent( "onImageLoadEnd", - undefined + undefined, ); this.images[imageId].loaded = true; @@ -277,7 +260,7 @@ export class ImagesToolAction extends WeaveAction { this.instance.emitEvent( "onAddingImages", - { imagesURL: images } + { imagesURL: images }, ); this.clickPoint = null; @@ -335,7 +318,7 @@ export class ImagesToolAction extends WeaveAction { this.instance.emitEvent( "onAddedImages", - { imagesURL: images } + { imagesURL: images }, ); this.setState(IMAGES_TOOL_STATE.FINISHED); @@ -345,7 +328,7 @@ export class ImagesToolAction extends WeaveAction { trigger( cancelAction: () => void, - params: ImagesToolActionTriggerParams + params: ImagesToolActionTriggerParams, ): void { if (!this.instance) { throw new Error("Instance not defined"); @@ -363,6 +346,10 @@ export class ImagesToolAction extends WeaveAction { selectionPlugin.setSelectedNodes([]); } + if (params.imagesIds) { + this.imagesIds = params.imagesIds; + } + this.instance.addEventListener("imageLoaded", () => { if (this.allImagesLoaded()) { this.addImages(params?.position); diff --git a/code/components/actions/images-tool/types.ts b/code/components/actions/images-tool/types.ts index 724f4c59..65f62102 100644 --- a/code/components/actions/images-tool/types.ts +++ b/code/components/actions/images-tool/types.ts @@ -21,6 +21,12 @@ export type ImageInfo = { export type ImagesToolActionTriggerParams = { images: ImageInfo[]; + imagesIds?: string[]; padding?: number; position?: Vector2d; }; + +export type ImagesToolDragAndDropProperties = { + imageURL: string; + imageId?: string; +}; diff --git a/code/components/actions/mask-eraser-tool/mask-eraser-tool.ts b/code/components/actions/mask-eraser-tool/mask-eraser-tool.ts index d774a007..6ada5dc6 100644 --- a/code/components/actions/mask-eraser-tool/mask-eraser-tool.ts +++ b/code/components/actions/mask-eraser-tool/mask-eraser-tool.ts @@ -51,13 +51,13 @@ export class MaskEraserToolAction extends WeaveAction { stage.container().addEventListener("keydown", (e) => { if (e.key === "Backspace" || e.key === "Delete") { const maskTransformer: Konva.Transformer | undefined = stage.findOne( - "#maskSelectionTransformer" + "#maskSelectionTransformer", ); if (maskTransformer) { const selectedNodes: Konva.Node[] = maskTransformer.getNodes(); const selectedNodesIds: string[] = selectedNodes.map( - (node) => node.getAttrs().id ?? "" + (node) => node.getAttrs().id ?? "", ); maskTransformer.nodes([ @@ -65,7 +65,7 @@ export class MaskEraserToolAction extends WeaveAction { .nodes() .filter( (node: Konva.Node) => - !selectedNodesIds.includes(node.getAttrs().id ?? "") + !selectedNodesIds.includes(node.getAttrs().id ?? ""), ), ]); for (const node of selectedNodes) { @@ -87,11 +87,11 @@ export class MaskEraserToolAction extends WeaveAction { (node: Konva.Node) => (node.getType() === "Line" && node.getAttrs().nodeType === "mask") || (node.getType() === "Group" && - node.getAttrs().nodeType === "fuzzy-mask") + node.getAttrs().nodeType === "fuzzy-mask"), ); const maskTransformer: Konva.Transformer | undefined = stage.findOne( - "#maskSelectionTransformer" + "#maskSelectionTransformer", ); for (const node of nodes) { diff --git a/code/components/room-components/ai-components/chatbot.conversation.tsx b/code/components/room-components/ai-components/chatbot.conversation.tsx index 62cad802..36cdedf2 100644 --- a/code/components/room-components/ai-components/chatbot.conversation.tsx +++ b/code/components/room-components/ai-components/chatbot.conversation.tsx @@ -39,6 +39,11 @@ import { GeneratedImage } from "@google/genai"; import { useCollaborationRoom } from "@/store/store"; import { Button } from "@/components/ui/button"; import { usePromptInputAttachments } from "@/components/ai-elements/prompt-input"; +import { + IMAGE_TOOL_ACTION_NAME, + WeaveImageToolAction, +} from "@inditextech/weave-sdk"; +import { useWeave } from "@inditextech/weave-react"; type ChatBotConversationProps = { // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -48,6 +53,8 @@ type ChatBotConversationProps = { export const ChatBotConversation = ({ initialMessages, }: ChatBotConversationProps) => { + const instance = useWeave((state) => state.instance); + const room = useCollaborationRoom((state) => state.room); const threadId = useIAChat((state) => state.threadId); @@ -84,8 +91,25 @@ export const ChatBotConversation = ({ className="gap-4" onDragStart={(e) => { if (e.target instanceof HTMLImageElement) { - window.weaveDragImageURL = e.target.src; - window.weaveDragImageId = e.target.dataset.imageId; + if (!instance) { + return; + } + if (e.target instanceof HTMLImageElement) { + const imageTool = instance.getActionHandler( + IMAGE_TOOL_ACTION_NAME, + ) as WeaveImageToolAction | undefined; + + if (!imageTool) { + return; + } + + imageTool.setDragAndDropProperties({ + imageURL: e.target.src, + imageId: e.target.dataset.imageId, + imageWidth: e.target.naturalWidth, + imageHeight: e.target.naturalHeight, + }); + } } }} > @@ -98,7 +122,7 @@ export const ChatBotConversation = ({ )} {messages?.map((message, messageIndex) => { const attachments = message.parts.filter( - (part) => part.type === "file" + (part) => part.type === "file", ); return ( @@ -171,7 +195,7 @@ export const ChatBotConversation = ({ className="rounded-none !cursor-pointer uppercase !text-xs w-[40px]" onClick={async () => { const blob = await fetch( - image.url + image.url, ).then((res) => res.blob()); const file = new File( @@ -179,11 +203,11 @@ export const ChatBotConversation = ({ "image.png", { type: "image/png", - } + }, ); promptInputAttachmentsController.add( - [file] + [file], ); }} > diff --git a/code/components/room-components/ai-components/chatbot.prompt.tsx b/code/components/room-components/ai-components/chatbot.prompt.tsx index d8d5c13d..a4edf435 100644 --- a/code/components/room-components/ai-components/chatbot.prompt.tsx +++ b/code/components/room-components/ai-components/chatbot.prompt.tsx @@ -101,7 +101,7 @@ const ChatBotPrompt = () => { const chefs = Array.from(new Set(MODELS.map((model) => model.chef))); const setSidebarActive = useCollaborationRoom( - (state) => state.setSidebarActive + (state) => state.setSidebarActive, ); const handleSubmit = React.useCallback( @@ -146,7 +146,7 @@ const ChatBotPrompt = () => { setAiView, setSidebarActive, scrollToBottom, - ] + ], ); const attachments = usePromptInputAttachments(); @@ -154,21 +154,29 @@ const ChatBotPrompt = () => { return (
{hidden && ( - +
+ +
)} {attachments.files.length > 0 && (
@@ -240,7 +248,7 @@ const ChatBotPrompt = () => {
)} - ) + ), )} ))} diff --git a/code/components/room-components/ai-components/chatbot.tsx b/code/components/room-components/ai-components/chatbot.tsx index 36a0fdd5..a6a6b8f0 100644 --- a/code/components/room-components/ai-components/chatbot.tsx +++ b/code/components/room-components/ai-components/chatbot.tsx @@ -25,6 +25,7 @@ import { cn } from "@/lib/utils"; import { OrbitProgress } from "react-loading-indicators"; import { postChat } from "@/api/post-chat"; import { ChatBotChatInfo } from "./chatbot.chat-info"; +import { SIDEBAR_ELEMENTS } from "@/lib/constants"; export const ChatBot = () => { const threadId = useIAChat((state) => state.threadId); @@ -36,6 +37,7 @@ export const ChatBot = () => { const user = useCollaborationRoom((state) => state.user); const room = useCollaborationRoom((state) => state.room); + const activeSidebar = useCollaborationRoom((state) => state.sidebar.active); const queryClient = useQueryClient(); @@ -109,7 +111,7 @@ export const ChatBot = () => { if (threadId === "undefined") { const storedThreadId = sessionStorage.getItem( - `weave.js_${room}_${user.name}_ai_thread_id` + `weave.js_${room}_${user.name}_ai_thread_id`, ); if (storedThreadId) { @@ -118,7 +120,7 @@ export const ChatBot = () => { actualThreadId = uuidv4(); sessionStorage.setItem( `weave.js_${room}_${user.name}_ai_thread_id`, - actualThreadId + actualThreadId, ); } @@ -131,6 +133,10 @@ export const ChatBot = () => { } }, [user, room, threadId, resourceId, setThreadId, setResourceId]); + if (activeSidebar !== SIDEBAR_ELEMENTS.aiChat) { + return null; + } + return ( <>
@@ -152,7 +158,7 @@ export const ChatBot = () => { sessionStorage.setItem( `weave.js_${room}_${user.name}_ai_thread_id`, - newTreadId + newTreadId, ); await postChat(room, newTreadId, resourceId, { diff --git a/code/components/room-components/connected-users.tsx b/code/components/room-components/connected-users.tsx index 17510e4a..73a1f38f 100644 --- a/code/components/room-components/connected-users.tsx +++ b/code/components/room-components/connected-users.tsx @@ -19,8 +19,8 @@ import { DropdownMenuTrigger, DropdownMenuSeparator, } from "../ui/dropdown-menu"; -import { OPERATIONS_MAP } from "../utils/constants"; import { WeaveUserMutexLock } from "@inditextech/weave-types"; +import { OPERATIONS_MAP } from "../utils/weave/constants"; const SHOW_USERS_LIMIT = 4; @@ -34,14 +34,14 @@ export const ConnectedUsers = () => { const connectedUserKey = React.useMemo(() => { const filterOwnUser = Object.keys(connectedUsers).filter( - (actUser) => actUser === user?.name + (actUser) => actUser === user?.name, ); return filterOwnUser?.[0]; }, [user, connectedUsers]); const { showUsers, restUsers } = React.useMemo(() => { const filterOwnUser = Object.keys(connectedUsers).filter( - (actUser) => actUser !== user?.name + (actUser) => actUser !== user?.name, ); return { showUsers: filterOwnUser.slice(0, SHOW_USERS_LIMIT - 1), diff --git a/code/components/room-components/elements-tree/elements-tree.tsx b/code/components/room-components/elements-tree/elements-tree.tsx index be1fe672..ec9975ad 100644 --- a/code/components/room-components/elements-tree/elements-tree.tsx +++ b/code/components/room-components/elements-tree/elements-tree.tsx @@ -4,6 +4,7 @@ import { TreeView, TreeDataItem } from "@/components/ui/tree-view"; import { + WEAVE_INSTANCE_STATUS, WeaveSelection, WeaveStateElement, WeaveUser, @@ -48,10 +49,10 @@ import { } from "@inditextech/weave-sdk"; import { SIDEBAR_ELEMENTS } from "@/lib/constants"; import { ScrollArea } from "@/components/ui/scroll-area"; -import { SidebarSelector } from "../sidebar-selector"; -import { SidebarHeader } from "../sidebar-header"; -import { OPERATIONS_MAP } from "@/components/utils/constants"; +// import { SidebarSelector } from "../sidebar-selector"; +// import { SidebarHeader } from "../sidebar-header"; import { stringToColor } from "@/lib/utils"; +import { OPERATIONS_MAP } from "@/components/utils/weave/constants"; // eslint-disable-next-line @typescript-eslint/no-explicit-any const iconsMap: Record = { @@ -271,12 +272,16 @@ function mapElementsToTree( export const ElementsTree = () => { const instance = useWeave((state) => state.instance); + const status = useWeave((state) => state.status); const initialSelectedNodes = useWeave((state) => state.selection.nodes); const usersLocks = useWeave((state) => state.usersLocks); const user = useCollaborationRoom((state) => state.user); + const setSidebarActive = useCollaborationRoom( + (state) => state.setSidebarActive, + ); - const sidebarActive = useCollaborationRoom((state) => state.sidebar.active); + // const sidebarActive = useCollaborationRoom((state) => state.sidebar.active); const [elementsTree, setElementsTree] = React.useState( [], @@ -307,7 +312,7 @@ export const ElementsTree = () => { setElementsTree(nodesTree); } - if (instance) { + if (instance && status === WEAVE_INSTANCE_STATUS.RUNNING) { instance.addEventListener("onStateChange", handleOnStateChange); setElementsTree(instance.getElementsTree()); } @@ -318,10 +323,17 @@ export const ElementsTree = () => { } }; // eslint-disable-next-line react-hooks/exhaustive-deps - }, [sidebarActive]); + }, [status]); React.useEffect(() => { function handleOnNodesSelectedChange(nodes: WeaveSelection[]) { + if (nodes.length > 1) { + setSidebarActive(SIDEBAR_ELEMENTS.nodeProperties); + } + if (nodes.length === 0) { + setSidebarActive(SIDEBAR_ELEMENTS.images); + } + setSelectedNodes( nodes .map((node) => node.node?.key) @@ -329,7 +341,7 @@ export const ElementsTree = () => { ); } - if (instance) { + if (instance && status === WEAVE_INSTANCE_STATUS.RUNNING) { instance.addEventListener("onNodesChange", handleOnNodesSelectedChange); } @@ -342,7 +354,7 @@ export const ElementsTree = () => { } }; // eslint-disable-next-line react-hooks/exhaustive-deps - }, [sidebarActive]); + }, [status]); const lockedNodes: Record = React.useMemo(() => { @@ -383,16 +395,19 @@ export const ElementsTree = () => { return null; } - if (sidebarActive !== SIDEBAR_ELEMENTS.nodesTree) { - return null; - } + // if (sidebarActive !== SIDEBAR_ELEMENTS.nodesTree) { + // return null; + // } return (
- +
+
Elements
+
+ {/* - - +
*/} +
{elementsTree.length === 0 && (
diff --git a/code/components/room-components/frames-library/frames-library.tsx b/code/components/room-components/frames-library/frames-library.tsx index a41fb8a2..231f0601 100644 --- a/code/components/room-components/frames-library/frames-library.tsx +++ b/code/components/room-components/frames-library/frames-library.tsx @@ -292,7 +292,7 @@ export const FramesLibrary = () => { > - +
( + null, + ); + + React.useEffect(() => { + if (!renderer) { + const konvaBaseRenderer = new WeaveKonvaBaseRenderer(); + + setRenderer(konvaBaseRenderer); + } + }, [renderer]); + + return renderer; +} + +export default useGetRendererKonvaBase; diff --git a/code/components/room-components/hooks/use-get-renderer-konva-react-reconciler.ts b/code/components/room-components/hooks/use-get-renderer-konva-react-reconciler.ts new file mode 100644 index 00000000..8fb6ef68 --- /dev/null +++ b/code/components/room-components/hooks/use-get-renderer-konva-react-reconciler.ts @@ -0,0 +1,24 @@ +// SPDX-FileCopyrightText: 2025 2025 INDUSTRIA DE DISEÑO TEXTIL S.A. (INDITEX S.A.) +// +// SPDX-License-Identifier: Apache-2.0 + +import React from "react"; +import { WeaveKonvaReactReconcilerRenderer } from "@inditextech/weave-renderer-konva-react-reconciler"; + +function useGetRendererKonvaReactReconciler() { + const [renderer, setRenderer] = + React.useState(null); + + React.useEffect(() => { + if (!renderer) { + const konvaReactReconcilerRenderer = + new WeaveKonvaReactReconcilerRenderer(); + + setRenderer(konvaReactReconcilerRenderer); + } + }, [renderer]); + + return renderer; +} + +export default useGetRendererKonvaReactReconciler; diff --git a/code/components/room-components/hooks/use-on-paste-external-image.ts b/code/components/room-components/hooks/use-on-paste-external-image.ts index 79db7a01..7dbb710c 100644 --- a/code/components/room-components/hooks/use-on-paste-external-image.ts +++ b/code/components/room-components/hooks/use-on-paste-external-image.ts @@ -5,6 +5,7 @@ "use client"; import React from "react"; +import { v4 as uuidv4 } from "uuid"; import { toast } from "sonner"; import { WeaveImageToolActionOnAddedEvent, @@ -162,38 +163,64 @@ export function useOnPasteExternalImage() { return; } - pastingToastIdRef.current = toast.loading("Pasting..."); - - setUploadingImage(true); - const file = new File([blob], "external.image"); - mutationUpload.mutate(file, { - onSuccess: (data) => { - const room: string = data.image.fileName.split("/")[0]; - const imageId = data.image.fileName.split("/")[1]; - - const queryKey = ["getImages", room]; - queryClient.invalidateQueries({ queryKey }); - - instance?.triggerAction( - "imageTool", - { - position, - forceMainContainer: true, - imageURL: `${process.env.NEXT_PUBLIC_API_ENDPOINT}/weavejs/rooms/${room}/images/${imageId}`, - }, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - ) as any; - - addImageRef.current = imageId; - - setPositionCalculated(positionCalculated); - }, - onError: (ex) => { - console.error(ex); - setUploadingImage(false); - console.error("Error uploading image"); - }, - }); + const resourceId = uuidv4(); + + const reader = new FileReader(); + reader.onloadend = () => { + pastingToastIdRef.current = toast.loading("Pasting..."); + + if (!instance) { + return; + } + + const { nodeId, finishUploadCallback } = instance.triggerAction( + "imageTool", + { + imageId: resourceId, + imageData: reader.result as string, + ...(position && { position, forceMainContainer: true }), + }, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + ) as any; + + const toastId = toast.loading("Uploading image...", { + duration: Infinity, + }); + + const file = new File([blob], "external.image"); + mutationUpload.mutate(file, { + onSuccess: (data) => { + toast.dismiss(toastId); + toast.success("Image uploaded successfully"); + + const room: string = data.image.fileName.split("/")[0]; + const imageId = data.image.fileName.split("/")[1]; + + const queryKey = ["getImages", room]; + queryClient.invalidateQueries({ queryKey }); + + finishUploadCallback?.( + nodeId, + `${process.env.NEXT_PUBLIC_API_ENDPOINT}/weavejs/rooms/${room}/images/${imageId}`, + ); + + addImageRef.current = imageId; + + setPositionCalculated(positionCalculated); + }, + onError: (ex) => { + toast.dismiss(toastId); + toast.error("Error uploading image"); + + console.error(ex); + console.error("Error uploading image"); + }, + }); + }; + reader.onerror = () => { + toast.error("Error reading pasted image"); + }; + reader.readAsDataURL(blob); }; if (instance) { diff --git a/code/components/room-components/hooks/use-tools-events.tsx b/code/components/room-components/hooks/use-tools-events.tsx index baf65ea0..401d206e 100644 --- a/code/components/room-components/hooks/use-tools-events.tsx +++ b/code/components/room-components/hooks/use-tools-events.tsx @@ -372,7 +372,6 @@ export const useToolsEvents = () => { if (actualAction === "commentTool" && action !== "commentTool") { sidebarToggle(null); } - // toast.dismiss(); }; instance.addEventListener("onPropsChange", handlePropsChange); @@ -402,15 +401,18 @@ export const useToolsEvents = () => { React.useEffect(() => { if (!instance) return; + let toastId: string | number = 0; + const handleStartCommentAdding = () => { - toast("Add comments", { + toastId = toast("Add comments", { + toasterId: "info", description: `${isTouchDevice ? "Tap" : "Click"} to add a comment.`, duration: Infinity, }); }; const handleFinishCommentAdding = () => { - toast.dismiss(); + toast.dismiss(toastId); }; instance.addEventListener("onStartAddingComment", handleStartCommentAdding); @@ -437,20 +439,23 @@ export const useToolsEvents = () => { React.useEffect(() => { if (!instance) return; + let toastId: string | number = 0; + const handleRectangleAdding = () => { - toast("Add a rectangle", { + toastId = toast("Add a rectangle", { + toasterId: "info", description: `${isTouchDevice ? "Tap" : "Click"} to add a fixed size rectangle or ${isTouchDevice ? "tap" : "click"} and drag to add a rectangle with a defined size.`, duration: Infinity, }); }; const handleRectangleAdded = () => { - toast.dismiss(); + toast.dismiss(toastId); }; const handleRectangleCancelled = (activeAction: string) => { if (activeAction !== "rectangleTool") { - toast.dismiss(); + toast.dismiss(toastId); } }; @@ -476,20 +481,23 @@ export const useToolsEvents = () => { React.useEffect(() => { if (!instance) return; + let toastId: string | number = 0; + const handleEllipseAdding = () => { - toast("Add an ellipse", { + toastId = toast("Add an ellipse", { + toasterId: "info", description: `${isTouchDevice ? "Tap" : "Click"} to add a fixed size ellipse or ${isTouchDevice ? "tap" : "click"} and drag to add a ellipse with a defined size.`, duration: Infinity, }); }; const handleEllipseAdded = () => { - toast.dismiss(); + toast.dismiss(toastId); }; const handleEllipseCancelled = (activeAction: string) => { if (activeAction !== "ellipseTool") { - toast.dismiss(); + toast.dismiss(toastId); } }; @@ -513,20 +521,23 @@ export const useToolsEvents = () => { React.useEffect(() => { if (!instance) return; + let toastId: string | number = 0; + const handleRegularPolygonAdding = () => { - toast("Add a regular polygon", { + toastId = toast("Add a regular polygon", { + toasterId: "info", description: `${isTouchDevice ? "Tap" : "Click"} to add a fixed size regular polygon or ${isTouchDevice ? "tap" : "click"} and drag to add a regular polygon with a defined size.`, duration: Infinity, }); }; const handleRegularPolygonAdded = () => { - toast.dismiss(); + toast.dismiss(toastId); }; const handleRegularPolygonCancelled = (activeAction: string) => { if (activeAction !== "regularPolygonTool") { - toast.dismiss(); + toast.dismiss(toastId); } }; @@ -565,20 +576,23 @@ export const useToolsEvents = () => { React.useEffect(() => { if (!instance) return; + let toastId: string | number = 0; + const handleStarAdding = () => { - toast("Add a star", { + toastId = toast("Add a star", { + toasterId: "info", description: `${isTouchDevice ? "Tap" : "Click"} to add a fixed size star or ${isTouchDevice ? "tap" : "click"} and drag to add a star with a defined size, movement on the x-axis defines the outer radius and movement on the y-axis defines the inner radius.`, duration: Infinity, }); }; const handleStarAdded = () => { - toast.dismiss(); + toast.dismiss(toastId); }; const handleStarCancelled = (activeAction: string) => { if (activeAction !== "starTool") { - toast.dismiss(); + toast.dismiss(toastId); } }; @@ -602,20 +616,23 @@ export const useToolsEvents = () => { React.useEffect(() => { if (!instance) return; + let toastId: string | number = 0; + const handleColorTokenAdding = () => { - toast("Add a color token", { + toastId = toast("Add a color token", { + toasterId: "info", description: `${isTouchDevice ? "Tap" : "Click"} to add the color token. You can select the color of the token on the right toolbar.`, duration: Infinity, }); }; const handleColorTokenAdded = () => { - toast.dismiss(); + toast.dismiss(toastId); }; const handleColorTokenCancelled = (activeAction: string) => { if (activeAction !== "colorTokenTool") { - toast.dismiss(); + toast.dismiss(toastId); } }; @@ -648,9 +665,12 @@ export const useToolsEvents = () => { React.useEffect(() => { if (!instance) return; + let toastId: string | number = 0; + const handleStrokeAdding = ({ actionName }: { actionName: string }) => { if (actionName === "strokeTool") { - toast("Add a stroke", { + toastId = toast("Add a stroke", { + toasterId: "info", description: `${isTouchDevice ? "Tap" : "Click"} and drag to paint a stroke.`, duration: Infinity, }); @@ -659,13 +679,13 @@ export const useToolsEvents = () => { const handleStrokeAdded = ({ actionName }: { actionName: string }) => { if (actionName === "strokeTool") { - toast.dismiss(); + toast.dismiss(toastId); } }; const handleStrokeCancelled = (activeAction: string) => { if (activeAction !== "strokeTool") { - toast.dismiss(); + toast.dismiss(toastId); } }; @@ -689,9 +709,12 @@ export const useToolsEvents = () => { React.useEffect(() => { if (!instance) return; + let toastId: string | number = 0; + const handleArrowAdding = ({ actionName }: { actionName: string }) => { if (actionName === "arrowTool") { - toast("Add an arrow", { + toastId = toast("Add an arrow", { + toasterId: "info", description: `${isTouchDevice ? "Tap" : "Click"} and drag to paint an arrow.`, duration: Infinity, }); @@ -700,13 +723,13 @@ export const useToolsEvents = () => { const handleArrowAdded = ({ actionName }: { actionName: string }) => { if (actionName === "arrowTool") { - toast.dismiss(); + toast.dismiss(toastId); } }; const handleArrowCancelled = (activeAction: string) => { if (activeAction !== "arrowTool") { - toast.dismiss(); + toast.dismiss(toastId); } }; @@ -730,20 +753,23 @@ export const useToolsEvents = () => { React.useEffect(() => { if (!instance) return; + let toastId: string | number = 0; + const handleBrushAdding = () => { - toast("Free-hand drawing", { + toastId = toast("Free-hand drawing", { + toasterId: "info", description: `${isTouchDevice ? "Tap" : "Click"} and move to draw a stroke.`, duration: Infinity, }); }; const handleBrushAdded = () => { - toast.dismiss(); + toast.dismiss(toastId); }; const handleBrushCancelled = (activeAction: string) => { if (activeAction !== "brushTool") { - toast.dismiss(); + toast.dismiss(toastId); } }; @@ -767,20 +793,23 @@ export const useToolsEvents = () => { React.useEffect(() => { if (!instance) return; + let toastId: string | number = 0; + const handleConnectorAdding = () => { - toast("Add connector", { + toastId = toast("Add connector", { + toasterId: "info", description: `${isTouchDevice ? "Tap" : "Click"} on an element anchor to set the start point and then ${isTouchDevice ? "tap" : "click"} on another anchor to add the connector.`, duration: Infinity, }); }; const handleConnectorAdded = () => { - toast.dismiss(); + toast.dismiss(toastId); }; const handleConnectorCancelled = (activeAction: string) => { if (activeAction !== "connectorTool") { - toast.dismiss(); + toast.dismiss(toastId); } }; @@ -807,20 +836,23 @@ export const useToolsEvents = () => { React.useEffect(() => { if (!instance) return; + let toastId: string | number = 0; + const handleImageAdding = () => { - toast("Add an image", { + toastId = toast("Add an image", { + toasterId: "info", description: `${isTouchDevice ? "Tap" : "Click"} to add the image to the room.`, duration: Infinity, }); }; const handleImageAdded = () => { - toast.dismiss(); + toast.dismiss(toastId); }; const handleImageCancelled = (activeAction: string) => { if (activeAction !== "imageTool") { - toast.dismiss(); + toast.dismiss(toastId); } }; @@ -844,20 +876,23 @@ export const useToolsEvents = () => { React.useEffect(() => { if (!instance) return; + let toastId: string | number = 0; + const handleImagesAdding = () => { - toast("Add multiple images", { + toastId = toast("Add multiple images", { + toasterId: "info", description: `${isTouchDevice ? "Tap" : "Click"} to add the images to the room.`, duration: Infinity, }); }; const handleImagesAdded = () => { - toast.dismiss(); + toast.dismiss(toastId); }; const handleImagesCancelled = (activeAction: string) => { if (activeAction !== "imagesTool") { - toast.dismiss(); + toast.dismiss(toastId); } }; @@ -881,20 +916,23 @@ export const useToolsEvents = () => { React.useEffect(() => { if (!instance) return; + let toastId: string | number = 0; + const handleVideoAdding = () => { - toast("Add a video", { + toastId = toast("Add a video", { + toasterId: "info", description: `${isTouchDevice ? "Tap" : "Click"} to add the video to the room.`, duration: Infinity, }); }; const handleVideoAdded = () => { - toast.dismiss(); + toast.dismiss(toastId); }; const handleVideoCancelled = (activeAction: string) => { if (activeAction !== "videoTool") { - toast.dismiss(); + toast.dismiss(toastId); } }; @@ -918,20 +956,23 @@ export const useToolsEvents = () => { React.useEffect(() => { if (!instance) return; + let toastId: string | number = 0; + const handleTextAdding = () => { - toast("Add text", { + toastId = toast("Add text", { + toasterId: "info", description: `${isTouchDevice ? "Tap" : "Click"} to set the text position. Then type and ${isTouchDevice ? "tap" : "click"} outside the text to confirm and add it.`, duration: Infinity, }); }; const handleTextAdded = () => { - toast.dismiss(); + toast.dismiss(toastId); }; const handleTextCancelled = (activeAction: string) => { if (activeAction !== "textTool") { - toast.dismiss(); + toast.dismiss(toastId); } }; @@ -955,8 +996,11 @@ export const useToolsEvents = () => { React.useEffect(() => { if (!instance) return; + let toastId: string | number = 0; + const handleFrameAdding = () => { - toast("Add a frame", { + toastId = toast("Add a frame", { + toasterId: "info", description: AddFrameToast, duration: Infinity, @@ -964,12 +1008,12 @@ export const useToolsEvents = () => { }; const handleFrameAdded = () => { - toast.dismiss(); + toast.dismiss(toastId); }; const handleFrameCancelled = (activeAction: string) => { if (activeAction !== "frameTool") { - toast.dismiss(); + toast.dismiss(toastId); } }; diff --git a/code/components/room-components/images-library/images-library.tsx b/code/components/room-components/images-library/images-library.tsx index 95dba29b..c2777873 100644 --- a/code/components/room-components/images-library/images-library.tsx +++ b/code/components/room-components/images-library/images-library.tsx @@ -33,7 +33,12 @@ import { useCollaborationRoom } from "@/store/store"; import { SIDEBAR_ELEMENTS } from "@/lib/constants"; import { ScrollArea } from "@/components/ui/scroll-area"; import { SidebarSelector } from "../sidebar-selector"; -import { WeaveImageNode } from "@inditextech/weave-sdk"; +import { + IMAGE_TOOL_ACTION_NAME, + // Weave, + WeaveImageNode, + WeaveImageToolAction, +} from "@inditextech/weave-sdk"; import { getImages } from "@/api/get-images"; import { getImages as getImagesV2 } from "@/api/v2/get-images"; import { postRemoveBackground as postRemoveBackgroundV2 } from "@/api/v2/post-remove-background"; @@ -76,7 +81,7 @@ export const ImagesLibrary = () => { const room = useCollaborationRoom((state) => state.room); const sidebarActive = useCollaborationRoom((state) => state.sidebar.active); const workloadsEnabled = useCollaborationRoom( - (state) => state.features.workloads + (state) => state.features.workloads, ); const aiChatEnabled = useIAChat((state) => state.enabled); @@ -103,7 +108,7 @@ export const ImagesLibrary = () => { clientId, room ?? "", imageId, - image + image, ); }, onMutate: () => { @@ -127,7 +132,7 @@ export const ImagesLibrary = () => { user?.name ?? "", clientId ?? "", room ?? "", - imageId + imageId, ); }, onMutate: () => { @@ -154,7 +159,7 @@ export const ImagesLibrary = () => { mutationDelete.mutate(image.imageId); }, - [instance, mutationDelete] + [instance, mutationDelete], ); const handleRemoveBackground = React.useCallback( @@ -164,7 +169,7 @@ export const ImagesLibrary = () => { } const element = document.querySelector( - `img[id="${image.imageId}"]` + `img[id="${image.imageId}"]`, ) as HTMLImageElement | null; if (!element) { @@ -193,7 +198,7 @@ export const ImagesLibrary = () => { }); } }, - [instance, clientId, user, mutationUploadV2] + [instance, clientId, user, mutationUploadV2], ); const query = useInfiniteQuery({ @@ -219,7 +224,7 @@ export const ImagesLibrary = () => { } const loadedSoFar = allPages.reduce( (sum, page) => sum + page.items.length, - 0 + 0, ); if (loadedSoFar < lastPage.total) { return loadedSoFar; // next offset @@ -232,7 +237,7 @@ export const ImagesLibrary = () => { const appImages = React.useMemo(() => { function extractImages( images: WeaveStateElement[], - node: WeaveStateElement + node: WeaveStateElement, ) { if (node.props && node.props.nodeType === "image" && node.props.imageId) { images.push(node); @@ -273,9 +278,9 @@ export const ImagesLibrary = () => { prev.find( (oldItem) => oldItem.imageId === newItem.imageId && - oldItem.updatedAt === newItem.updatedAt - ) || newItem - ) + oldItem.updatedAt === newItem.updatedAt, + ) || newItem, + ), ); }, [query.data]); @@ -300,7 +305,7 @@ export const ImagesLibrary = () => { for (const image of images) { const appImage = appImages.find( - (appImage) => appImage.props.imageId === image.imageId + (appImage) => appImage.props.imageId === image.imageId, ); if ( @@ -322,13 +327,13 @@ export const ImagesLibrary = () => { newSelectedImages.push(image); } else { newSelectedImages = newSelectedImages.filter( - (actImage) => actImage !== image + (actImage) => actImage !== image, ); } const unique = [...new Set(newSelectedImages)]; setSelectedImages(unique); }, - [selectedImages] + [selectedImages], ); if (!instance) { @@ -371,9 +376,24 @@ export const ImagesLibrary = () => {
{ + if (!instance) { + return; + } if (e.target instanceof HTMLImageElement) { - window.weaveDragImageURL = e.target.src; - window.weaveDragImageId = e.target.dataset.imageId; + const imageTool = instance.getActionHandler( + IMAGE_TOOL_ACTION_NAME, + ) as WeaveImageToolAction | undefined; + + if (!imageTool) { + return; + } + + imageTool.setDragAndDropProperties({ + imageURL: e.target.src, + imageId: e.target.dataset.imageId, + imageWidth: e.target.naturalWidth, + imageHeight: e.target.naturalHeight, + }); } }} > @@ -435,7 +455,7 @@ export const ImagesLibrary = () => { if (node) { const nodeHandler = instance.getNodeHandler( - node.getAttrs().nodeType + node.getAttrs().nodeType, ); if (!nodeHandler) { return; @@ -443,8 +463,8 @@ export const ImagesLibrary = () => { instance.removeNode( nodeHandler.serialize( - node as WeaveElementInstance - ) + node as WeaveElementInstance, + ), ); } }} @@ -498,9 +518,24 @@ export const ImagesLibrary = () => {
{ + if (!instance) { + return; + } if (e.target instanceof HTMLImageElement) { - window.weaveDragImageURL = e.target.src; - window.weaveDragImageId = e.target.dataset.imageId; + const imageTool = instance.getActionHandler( + IMAGE_TOOL_ACTION_NAME, + ) as WeaveImageToolAction | undefined; + + if (!imageTool) { + return; + } + + imageTool.setDragAndDropProperties({ + imageURL: e.target.src, + imageId: e.target.dataset.imageId, + imageWidth: e.target.naturalWidth, + imageHeight: e.target.naturalHeight, + }); } }} > @@ -524,7 +559,7 @@ export const ImagesLibrary = () => { {images.length > 0 && images.map((image) => { const appImage = appImages.find( - (appImage) => appImage.props.imageId === image.imageId + (appImage) => appImage.props.imageId === image.imageId, ); const isChecked = realSelectedImages.includes(image); @@ -568,7 +603,7 @@ export const ImagesLibrary = () => { (image.removalJobId !== null && image.removalStatus !== null && ["pending", "working"].includes( - image.removalStatus + image.removalStatus, )) ) ) { @@ -587,7 +622,7 @@ export const ImagesLibrary = () => { (image.removalJobId !== null && image.removalStatus !== null && ["pending", "working"].includes( - image.removalStatus + image.removalStatus, )) ) && (
diff --git a/code/components/room-components/inputs/input-font-family.tsx b/code/components/room-components/inputs/input-font-family.tsx index ec2dbe62..0625ef80 100644 --- a/code/components/room-components/inputs/input-font-family.tsx +++ b/code/components/room-components/inputs/input-font-family.tsx @@ -16,7 +16,6 @@ import { PopoverTrigger, } from "@/components/ui/popover"; import { Check, ChevronDown } from "lucide-react"; - import { Button } from "@/components/ui/button"; import React from "react"; import { useCollaborationRoom } from "@/store/store"; @@ -34,6 +33,10 @@ function InputFontFamily({ const fontsValues = useCollaborationRoom((state) => state.fonts.values); + React.useEffect(() => { + setSelectedFont(value); + }, [value]); + React.useEffect(() => { if (onChange && selectedFont !== lastSelectedFontFamily.current) { lastSelectedFontFamily.current = selectedFont; diff --git a/code/components/room-components/node-properties/size-properties.tsx b/code/components/room-components/node-properties/size-properties.tsx index 652fd983..43542a36 100644 --- a/code/components/room-components/node-properties/size-properties.tsx +++ b/code/components/room-components/node-properties/size-properties.tsx @@ -12,6 +12,7 @@ import { InputNumber } from "../inputs/input-number"; import { ToggleIconButton } from "../toggle-icon-button"; import { Scaling } from "lucide-react"; import { cn } from "@/lib/utils"; +import { TEXT_LAYOUT } from "@inditextech/weave-sdk"; export function SizeProperties() { const instance = useWeave((state) => state.instance); @@ -20,11 +21,11 @@ export function SizeProperties() { const actualAction = useWeave((state) => state.actions.actual); const nodePropertiesAction = useCollaborationRoom( - (state) => state.nodeProperties.action + (state) => state.nodeProperties.action, ); const nodeCreateProps = useCollaborationRoom( - (state) => state.nodeProperties.createProps + (state) => state.nodeProperties.createProps, ); const [maintainAspectRatio, setMaintainAspectRatio] = React.useState(true); @@ -55,7 +56,7 @@ export function SizeProperties() { instance.updateNode(updatedNode); } }, - [instance, actualAction, nodePropertiesAction] + [instance, actualAction, nodePropertiesAction], ); React.useEffect(() => { @@ -79,7 +80,7 @@ export function SizeProperties() { actualAction && ["selectionTool"].includes(actualAction) && ["mask", "fuzzy-mask", "ellipse", "regular-polygon", "star"].includes( - actualNode.type + actualNode.type, ) ) { return null; @@ -108,14 +109,52 @@ export function SizeProperties() { Auto width
} - pressed={(actualNode.props.layout ?? "auto-all") === "auto-all"} + icon={ +
+ Smart +
+ size +
+ } + pressed={ + (actualNode.props.layout ?? TEXT_LAYOUT.SMART) === + TEXT_LAYOUT.SMART + } + onClick={() => { + const updatedNode: WeaveStateElement = { + ...actualNode, + props: { + ...actualNode.props, + layout: TEXT_LAYOUT.SMART, + smartFixedWidth: false, + smartFixedHeight: false, + }, + }; + updateElement(updatedNode); + }} + /> + + Auto +
+ size +
+ } + pressed={ + (actualNode.props.layout ?? TEXT_LAYOUT.AUTO_ALL) === + TEXT_LAYOUT.AUTO_ALL + } onClick={() => { const updatedNode: WeaveStateElement = { ...actualNode, props: { ...actualNode.props, - layout: "auto-all", + layout: TEXT_LAYOUT.AUTO_ALL, + smartFixedWidth: false, + smartFixedHeight: false, }, }; updateElement(updatedNode); @@ -126,14 +165,17 @@ export function SizeProperties() { className="w-full" icon={
Auto height
} pressed={ - (actualNode.props.layout ?? "auto-all") === "auto-height" + (actualNode.props.layout ?? TEXT_LAYOUT.AUTO_ALL) === + TEXT_LAYOUT.AUTO_HEIGHT } onClick={() => { const updatedNode: WeaveStateElement = { ...actualNode, props: { ...actualNode.props, - layout: "auto-height", + layout: TEXT_LAYOUT.AUTO_HEIGHT, + smartFixedWidth: false, + smartFixedHeight: false, }, }; updateElement(updatedNode); @@ -142,14 +184,25 @@ export function SizeProperties() { Fixed size
} - pressed={(actualNode.props.layout ?? "auto-all") === "fixed"} + icon={ +
+ Fixed +
+ size +
+ } + pressed={ + (actualNode.props.layout ?? TEXT_LAYOUT.AUTO_ALL) === + TEXT_LAYOUT.FIXED + } onClick={() => { const updatedNode: WeaveStateElement = { ...actualNode, props: { ...actualNode.props, - layout: "fixed", + layout: TEXT_LAYOUT.FIXED, + smartFixedWidth: false, + smartFixedHeight: false, }, }; updateElement(updatedNode); diff --git a/code/components/room-components/node-properties/text-properties.tsx b/code/components/room-components/node-properties/text-properties.tsx index a4036ae5..c6158966 100644 --- a/code/components/room-components/node-properties/text-properties.tsx +++ b/code/components/room-components/node-properties/text-properties.tsx @@ -13,14 +13,12 @@ import { AlignRight, AlignStartHorizontal, Bold, - CaseSensitive, - CaseUpper, Italic, RemoveFormatting, Strikethrough, Underline, } from "lucide-react"; -import { WeaveStateElement } from "@inditextech/weave-types"; +import { WeaveFont, WeaveStateElement } from "@inditextech/weave-types"; import { useWeave } from "@inditextech/weave-react"; import { useCollaborationRoom } from "@/store/store"; import { InputColor } from "../inputs/input-color"; @@ -33,14 +31,19 @@ export function TextProperties() { const node = useWeave((state) => state.selection.node); const actualAction = useWeave((state) => state.actions.actual); + const fontsValues = useCollaborationRoom((state) => state.fonts.values); const nodePropertiesAction = useCollaborationRoom( - (state) => state.nodeProperties.action + (state) => state.nodeProperties.action, ); const nodeCreateProps = useCollaborationRoom( - (state) => state.nodeProperties.createProps + (state) => state.nodeProperties.createProps, ); + const [selectedFontFamily, setSelectedFontFamily] = React.useState< + string | null + >(null); + const actualNode = React.useMemo(() => { if (actualAction && nodePropertiesAction === "create") { return { @@ -57,6 +60,16 @@ export function TextProperties() { return undefined; }, [actualAction, node, nodePropertiesAction, nodeCreateProps]); + React.useEffect(() => { + setSelectedFontFamily(actualNode?.props?.fontFamily ?? null); + }, [actualNode]); + + const weaveFont = React.useMemo(() => { + return fontsValues.find( + (font: WeaveFont) => font.name === selectedFontFamily, + ); + }, [fontsValues, selectedFontFamily]); + const updateElement = React.useCallback( (updatedNode: WeaveStateElement) => { if (!instance) return; @@ -67,7 +80,7 @@ export function TextProperties() { instance.updateNode(updatedNode); } }, - [instance, actualAction, nodePropertiesAction] + [instance, actualAction, nodePropertiesAction], ); if (!instance || !actualAction || !actualNode) { @@ -162,6 +175,7 @@ export function TextProperties() { } + disabled={!weaveFont?.supportedStyles?.includes("normal")} pressed={ (actualNode.props.fontStyle ?? "normal").indexOf("normal") !== -1 @@ -180,6 +194,7 @@ export function TextProperties() { /> } pressed={ (actualNode.props.fontStyle ?? "normal").indexOf("italic") !== @@ -223,6 +238,7 @@ export function TextProperties() { } + disabled={!weaveFont?.supportedStyles?.includes("bold")} pressed={ (actualNode.props.fontStyle ?? "normal").indexOf("bold") !== -1 } @@ -263,46 +279,6 @@ export function TextProperties() { />
-
-
- Variant -
-
- } - pressed={ - !actualNode.props.fontVariant || - actualNode.props.fontVariant === "normal" - } - onClick={() => { - const updatedNode: WeaveStateElement = { - ...actualNode, - props: { - ...actualNode.props, - fontVariant: "normal", - }, - }; - updateElement(updatedNode); - }} - /> - } - pressed={actualNode.props.fontVariant === "small-caps"} - onClick={() => { - const updatedNode: WeaveStateElement = { - ...actualNode, - props: { - ...actualNode.props, - fontVariant: "small-caps", - }, - }; - updateElement(updatedNode); - }} - /> -
-
Decoration diff --git a/code/components/room-components/overlay/hooks/use-images-tools.tsx b/code/components/room-components/overlay/hooks/use-images-tools.tsx index 8ff17e61..ee40c7e8 100644 --- a/code/components/room-components/overlay/hooks/use-images-tools.tsx +++ b/code/components/room-components/overlay/hooks/use-images-tools.tsx @@ -10,28 +10,28 @@ import { Image, Images } from "lucide-react"; import { useCollaborationRoom } from "@/store/store"; export const useImagesTools = () => { - const instance = useWeave((state) => state.instance); + // const instance = useWeave((state) => state.instance); const actualAction = useWeave((state) => state.actions.actual); const setShowSelectFileImage = useCollaborationRoom( - (state) => state.setShowSelectFileImage + (state) => state.setShowSelectFileImage, ); const setShowSelectFilesImages = useCollaborationRoom( - (state) => state.setShowSelectFilesImages + (state) => state.setShowSelectFilesImages, ); - const triggerTool = React.useCallback( - (toolName: string, params?: unknown) => { - if (instance && actualAction !== toolName) { - instance.triggerAction(toolName, params); - return; - } - if (instance && actualAction === toolName) { - instance.cancelAction(toolName); - } - }, - [instance, actualAction] - ); + // const triggerTool = React.useCallback( + // (toolName: string, params?: unknown) => { + // if (instance && actualAction !== toolName) { + // instance.triggerAction(toolName, params); + // return; + // } + // if (instance && actualAction === toolName) { + // instance.cancelAction(toolName); + // } + // }, + // [instance, actualAction], + // ); const IMAGES_TOOLS: Record< string, @@ -58,7 +58,7 @@ export const useImagesTools = () => {
), onClick: () => { - triggerTool("imageTool"); + // triggerTool("imageTool"); setShowSelectFileImage(true); }, active: () => actualAction === "imageTool", @@ -82,12 +82,7 @@ export const useImagesTools = () => { active: () => actualAction === "imagesTool", }, }), - [ - actualAction, - setShowSelectFileImage, - setShowSelectFilesImages, - triggerTool, - ] + [actualAction, setShowSelectFileImage, setShowSelectFilesImages], ); return IMAGES_TOOLS; diff --git a/code/components/room-components/overlay/node-properties.tsx b/code/components/room-components/overlay/node-properties.tsx index 21f0ec6a..0dacc0f6 100644 --- a/code/components/room-components/overlay/node-properties.tsx +++ b/code/components/room-components/overlay/node-properties.tsx @@ -31,6 +31,7 @@ import { ImageTemplateProperties } from "../node-properties/image-template-prope // import { SIDEBAR_ELEMENTS } from "@/lib/constants"; import { SidebarSelector } from "../sidebar-selector"; import { SidebarHeader } from "../sidebar-header"; +import { SIDEBAR_ELEMENTS } from "@/lib/constants"; export const NodeProperties = () => { const instance = useWeave((state) => state.instance); @@ -80,16 +81,17 @@ export const NodeProperties = () => { return; } - // if (!actualAction || !node) { - // setNodePropertiesAction(undefined); - // setSidebarActive(SIDEBAR_ELEMENTS.nodesTree); - // return; - // } + if ((!actualAction || !node) && nodes.length === 0) { + setNodePropertiesAction(undefined); + setSidebarActive(SIDEBAR_ELEMENTS.images); + return; + } if (node) { setNodePropertiesAction("update"); + setSidebarActive(SIDEBAR_ELEMENTS.nodeProperties); } - }, [actualAction, node, setSidebarActive, setNodePropertiesAction]); + }, [actualAction, node, nodes, setSidebarActive, setNodePropertiesAction]); React.useEffect(() => { if (!instance) return; diff --git a/code/components/room-components/overlay/node-toolbar.tsx b/code/components/room-components/overlay/node-toolbar.tsx index 88cfc3b8..2b2c6979 100644 --- a/code/components/room-components/overlay/node-toolbar.tsx +++ b/code/components/room-components/overlay/node-toolbar.tsx @@ -37,7 +37,7 @@ import { ArrowDown, SendToBack, Trash, - Settings, + // Settings, Paintbrush, Crop, BrushCleaning, @@ -79,6 +79,8 @@ import { WeaveConnectorNode, WEAVE_CONNECTOR_NODE_LINE_ORIGIN, WEAVE_CONNECTOR_NODE_DECORATOR_TYPE, + WeaveTextNode, + TEXT_LAYOUT, } from "@inditextech/weave-sdk"; import { ToolbarDivider } from "../toolbar/toolbar-divider"; import { SIDEBAR_ELEMENTS } from "@/lib/constants"; @@ -93,7 +95,7 @@ import { ImageTemplateNode } from "@/components/nodes/image-template/image-templ import { IMAGE_TEMPLATE_FIT } from "@/components/nodes/image-template/constants"; import { usePromptInputAttachments } from "@/components/ai-elements/prompt-input"; import { useIAChat } from "@/store/ia-chat"; -import { useNodeActionName } from "./hooks/use-node-action-name"; +// import { useNodeActionName } from "./hooks/use-node-action-name"; export const NodeToolbar = () => { const actualNodeRef = React.useRef(undefined); @@ -115,6 +117,7 @@ export const NodeToolbar = () => { const node = useWeave((state) => state.selection.node); const nodes = useWeave((state) => state.selection.nodes); + // const viewType = useCollaborationRoom((state) => state.viewType); const user = useCollaborationRoom((state) => state.user); const clientId = useCollaborationRoom((state) => state.clientId); const room = useCollaborationRoom((state) => state.room); @@ -262,7 +265,7 @@ export const NodeToolbar = () => { }; }, [instance, movingImageTemplate]); - const title = useNodeActionName(); + // const title = useNodeActionName(); const mutationRemoveBackground = useMutation({ mutationFn: async ({ @@ -567,12 +570,12 @@ export const NodeToolbar = () => { return ( <> -
+ {/*
{title.toUpperCase()} -
-
-
-
+
*/} +
+
+
{!isGroup && isColorTokenNode && ( { asChild > { <> {!isVideoPlaying && ( } disabled={ weaveConnectionStatus !== @@ -702,7 +705,7 @@ export const NodeToolbar = () => { )} {isVideoPlaying && ( } disabled={ weaveConnectionStatus !== @@ -734,7 +737,7 @@ export const NodeToolbar = () => { /> )} } @@ -765,10 +768,7 @@ export const NodeToolbar = () => { tooltipSide="left" tooltipAlign="center" /> - + )} {isConnectorNode && ( @@ -793,7 +793,7 @@ export const NodeToolbar = () => { asChild > { asChild > {(actualNode?.props?.["startNodeDecoratorType"] === @@ -1051,7 +1051,7 @@ export const NodeToolbar = () => { >
{actualNode?.props?.["startNodeDecoratorType"] === @@ -1101,7 +1101,7 @@ export const NodeToolbar = () => { tooltipAlign="end" /> {actualNode?.props?.["startNodeDecoratorType"] === @@ -1151,7 +1151,7 @@ export const NodeToolbar = () => { tooltipAlign="end" /> {actualNode?.props?.["startNodeDecoratorType"] === @@ -1223,7 +1223,7 @@ export const NodeToolbar = () => { asChild > { asChild > {(actualNode?.props?.["endNodeDecoratorType"] === @@ -1475,7 +1475,7 @@ export const NodeToolbar = () => { >
{actualNode?.props?.["endNodeDecoratorType"] === @@ -1523,7 +1523,7 @@ export const NodeToolbar = () => { tooltipAlign="end" /> {actualNode?.props?.["endNodeDecoratorType"] === @@ -1571,7 +1571,7 @@ export const NodeToolbar = () => { tooltipAlign="end" /> {actualNode?.props?.["endNodeDecoratorType"] === @@ -1641,7 +1641,7 @@ export const NodeToolbar = () => { asChild > } @@ -1807,7 +1807,7 @@ export const NodeToolbar = () => { {isMeasureNode && ( <> } @@ -1841,7 +1841,7 @@ export const NodeToolbar = () => { tooltipAlign="center" /> } disabled={ weaveConnectionStatus !== @@ -1910,7 +1910,7 @@ export const NodeToolbar = () => { <> {!actualNode?.props.isUsed && ( } disabled={ !linkedNode || @@ -1975,7 +1975,7 @@ export const NodeToolbar = () => { asChild > { } @@ -2218,10 +2218,7 @@ export const NodeToolbar = () => { /> )} - + )} {!isGroup && canSetNodeStyling && ( @@ -2245,7 +2242,7 @@ export const NodeToolbar = () => { asChild > } @@ -2303,7 +2300,7 @@ export const NodeToolbar = () => { asChild > { asChild > { asChild > { asChild > { asChild > { >
{ tooltipAlign="end" /> { tooltipAlign="end" /> { /> { tooltipAlign="end" /> { /> { asChild > { >
{ tooltipAlign="end" /> { /> { {isImage && ( <> } @@ -3274,7 +3271,7 @@ export const NodeToolbar = () => { tooltipAlign="center" /> } disabled={ weaveConnectionStatus !== @@ -3301,14 +3298,11 @@ export const NodeToolbar = () => { tooltipSide="left" tooltipAlign="end" /> - + {workloadsEnabled && ( <> { tooltipAlign="center" /> } @@ -3462,7 +3456,7 @@ export const NodeToolbar = () => { tooltipAlign="center" /> { tooltipAlign="center" /> { tooltipAlign="center" /> { )} } disabled={ weaveConnectionStatus !== @@ -3731,7 +3725,7 @@ export const NodeToolbar = () => { tooltipAlign="center" /> } @@ -3760,16 +3754,13 @@ export const NodeToolbar = () => { tooltipSide="left" tooltipAlign="center" /> - + )} {isMultiNodesSelected && ( <> } @@ -3852,10 +3843,7 @@ export const NodeToolbar = () => { tooltipSide="left" tooltipAlign="center" /> - + { asChild > { >
{ tooltipAlign="end" /> { tooltipAlign="end" /> { asChild > { >
{ tooltipAlign="end" /> { tooltipAlign="end" /> { asChild > { asChild > } disabled={ weaveConnectionStatus !== @@ -4823,7 +4811,7 @@ export const NodeToolbar = () => { >
{ tooltipAlign="end" /> } @@ -4909,7 +4897,7 @@ export const NodeToolbar = () => { tooltipAlign="end" /> } @@ -4949,7 +4937,7 @@ export const NodeToolbar = () => { tooltipAlign="end" /> { )} - + {isTextNode && + actualNode?.props.layout === TEXT_LAYOUT.SMART && + ((actualNode?.props.smartFixedWidth ?? false) || + (actualNode?.props.smartFixedHeight ?? false)) && ( + + } + disabled={ + weaveConnectionStatus !== + WEAVE_STORE_CONNECTION_STATUS.CONNECTED + } + onClick={() => { + setActualMenusOpen([]); + + if (!instance) { + return; + } + + const nodeHandler = + instance.getNodeHandler("text"); + + if (!nodeHandler) { + return; + } + + const stage = instance.getStage(); + const nodeInstance = stage.findOne( + `#${actualNode?.key ?? ""}`, + ); + + if (!nodeInstance) { + return; + } + + nodeHandler.resetSmartLayout(nodeInstance as Konva.Text); + }} + label={ +
+

Reset

+
+ } + tooltipSide="left" + tooltipAlign="center" + /> + )} + {isMultiNodesSelected && ( } disabled={ weaveConnectionStatus !== @@ -5035,7 +5070,7 @@ export const NodeToolbar = () => { )} {isGroup && ( } disabled={ weaveConnectionStatus !== @@ -5066,7 +5101,7 @@ export const NodeToolbar = () => { /> )} } disabled={ weaveConnectionStatus !== @@ -5113,7 +5148,7 @@ export const NodeToolbar = () => { tooltipAlign="center" /> } disabled={ weaveConnectionStatus !== @@ -5160,7 +5195,7 @@ export const NodeToolbar = () => { tooltipAlign="center" /> } disabled={ weaveConnectionStatus !== @@ -5196,7 +5231,7 @@ export const NodeToolbar = () => { tooltipAlign="center" /> } disabled={ weaveConnectionStatus !== @@ -5236,42 +5271,6 @@ export const NodeToolbar = () => { tooltipSide="left" tooltipAlign="center" /> - {isSingleNodeSelected && ( - <> - - } - disabled={ - weaveConnectionStatus !== - WEAVE_STORE_CONNECTION_STATUS.CONNECTED || - typeof nodePropertiesAction === "undefined" || - typeof actualNode === "undefined" || - (typeof actualNode === "undefined" && nodes.length < 2) - } - onClick={() => { - setActualMenusOpen([]); - setSidebarActive(SIDEBAR_ELEMENTS.nodeProperties); - }} - label={ -
-

Node Properties

- -
- } - tooltipSide="left" - tooltipAlign="center" - /> - - )}
diff --git a/code/components/room-components/overlay/room-header.tsx b/code/components/room-components/overlay/room-header.tsx index c9520904..90935273 100644 --- a/code/components/room-components/overlay/room-header.tsx +++ b/code/components/room-components/overlay/room-header.tsx @@ -8,7 +8,7 @@ import React from "react"; import { cn, SYSTEM_OS } from "@/lib/utils"; import { useRouter } from "next/navigation"; import { motion } from "framer-motion"; -import { ConnectionStatus } from "../connection-status"; +// import { ConnectionStatus } from "../connection-status"; import { useWeave } from "@inditextech/weave-react"; import { BACKGROUND_COLOR, @@ -37,6 +37,7 @@ import { IdCard, Bookmark, Contact, + PanelRight, } from "lucide-react"; import { WEAVE_GRID_TYPES, @@ -73,25 +74,28 @@ export function RoomHeader() { const room = useCollaborationRoom((state) => state.room); const setExportNodes = useCollaborationRoom((state) => state.setExportNodes); const setExportConfigVisible = useCollaborationRoom( - (state) => state.setExportConfigVisible + (state) => state.setExportConfigVisible, ); const backgroundColor = useCollaborationRoom( - (state) => state.backgroundColor + (state) => state.backgroundColor, ); const setBackgroundColor = useCollaborationRoom( - (state) => state.setBackgroundColor + (state) => state.setBackgroundColor, ); const connectionTestsShow = useCollaborationRoom( - (state) => state.connection.tests.show + (state) => state.connection.tests.show, ); const setConnectionTestsShow = useCollaborationRoom( - (state) => state.setConnectionTestsShow + (state) => state.setConnectionTestsShow, ); const setConfigurationOpen = useCollaborationRoom( - (state) => state.setConfigurationOpen + (state) => state.setConfigurationOpen, ); + const viewType = useCollaborationRoom((state) => state.viewType); + const setViewType = useCollaborationRoom((state) => state.setViewType); + const aiChatEnabled = useIAChat((state) => state.enabled); const setAiChatSetupVisible = useIAChat((state) => state.setSetupVisible); @@ -100,7 +104,7 @@ export function RoomHeader() { const [commentsEnabled, setCommentsEnabled] = React.useState(true); const [gridEnabled, setGridEnabled] = React.useState(true); const [gridType, setGridType] = React.useState( - WEAVE_GRID_TYPES.LINES + WEAVE_GRID_TYPES.LINES, ); const { @@ -194,14 +198,14 @@ export function RoomHeader() { sessionConfig.backgroundColor = color; setSessionConfig(room, sessionConfig); }, - [instance, room, setBackgroundColor] + [instance, room, setBackgroundColor], ); const handleSetGridType = React.useCallback( (type: WeaveStageGridType) => { if (instance) { (instance.getPlugin("stageGrid") as WeaveStageGridPlugin)?.setType( - type + type, ); setGridType(type); @@ -215,7 +219,7 @@ export function RoomHeader() { } setMenuOpen(false); }, - [instance, room] + [instance, room], ); React.useEffect(() => { @@ -234,7 +238,7 @@ export function RoomHeader() { const sessionConfig = getSessionConfig(room); const stageGridPlugin = instance.getPlugin( - "stageGrid" + "stageGrid", ) as WeaveStageGridPlugin; stageGridPlugin?.setType(sessionConfig.grid.type); @@ -259,7 +263,7 @@ export function RoomHeader() { React.useEffect(() => { if (instance) { const stageGridPlugin = instance.getPlugin( - "stageGrid" + "stageGrid", ) as WeaveStageGridPlugin; setGridType(stageGridPlugin?.getType()); } @@ -305,7 +309,7 @@ export function RoomHeader() { { ["pointer-events-none"]: selectionActive, ["pointer-events-auto"]: !selectionActive, - } + }, )} > @@ -318,15 +322,17 @@ export function RoomHeader() { exit="hidden" variants={topElementVariants} className={cn( - "w-auto z-1 flex gap-1 justify-center items-center absolute top-[16px] left-[16px]", + "w-auto z-1 flex gap-1 justify-center items-center top-[16px] left-[16px] min-w-[400px] max-w-[400px]", { ["pointer-events-none"]: selectionActive, ["pointer-events-auto"]: !selectionActive, - } + ["block"]: viewType === "fixed", + ["absolute"]: viewType === "floating", + }, )} > -
-
+
+
{ @@ -339,11 +345,11 @@ export function RoomHeader() { { ["font-normal"]: menuOpen, ["font-extralight"]: !menuOpen, - } + }, )} > -
-
+
+
{menuOpen ? ( @@ -629,7 +635,7 @@ export function RoomHeader() { window.open( GITHUB_URL, "_blank", - "noopener,noreferrer" + "noopener,noreferrer", ); }} > @@ -641,7 +647,7 @@ export function RoomHeader() { window.open( DOCUMENTATION_URL, "_blank", - "noopener,noreferrer" + "noopener,noreferrer", ); }} > @@ -752,13 +758,23 @@ export function RoomHeader() { -
+
-
{room}
+
+ {room} +
- - + + {/* */} + {/* */}
diff --git a/code/components/room-components/overlay/tools-node-overlay.tsx b/code/components/room-components/overlay/tools-node-overlay.tsx index 432bc01f..89227a90 100644 --- a/code/components/room-components/overlay/tools-node-overlay.tsx +++ b/code/components/room-components/overlay/tools-node-overlay.tsx @@ -208,21 +208,23 @@ export function ToolsNodeOverlay() { return; } - if (!actualAction || !node) { + if ((!actualAction || !node) && nodes.length === 0) { setNodePropertiesAction(undefined); setSidebarActive( - aiChatEnabled ? SIDEBAR_ELEMENTS.aiChat : SIDEBAR_ELEMENTS.nodesTree, + aiChatEnabled ? SIDEBAR_ELEMENTS.aiChat : SIDEBAR_ELEMENTS.images, ); return; } if (node) { setNodePropertiesAction("update"); + setSidebarActive(SIDEBAR_ELEMENTS.nodeProperties); } }, [ aiChatEnabled, actualAction, node, + nodes, setSidebarActive, setNodePropertiesAction, ]); @@ -3352,7 +3354,7 @@ export function ToolsNodeOverlay() { nodePropertiesAction === "create" && !["textTool", "frameTool"].includes(actualAction ?? "") && ( {imageEditionTools} @@ -3364,7 +3366,7 @@ export function ToolsNodeOverlay() { )} {secondElements > 0 && ( {commonShapeManagementTools} diff --git a/code/components/room-components/overlay/tools-overlay.touch.tsx b/code/components/room-components/overlay/tools-overlay.touch.tsx index aee2afbf..7b54c685 100644 --- a/code/components/room-components/overlay/tools-overlay.touch.tsx +++ b/code/components/room-components/overlay/tools-overlay.touch.tsx @@ -20,8 +20,8 @@ import { Circle, Star, Hexagon, - ChevronRight, - ChevronLeft, + // ChevronRight, + // ChevronLeft, MessageSquare, ChevronsLeftRightEllipsis, // MapPinned, @@ -31,6 +31,8 @@ import { PenLine, RulerDimensionLine, MoveUpRight, + ChevronUp, + ChevronDown, } from "lucide-react"; import { DropdownMenu, @@ -41,7 +43,7 @@ import { import { useWeave } from "@inditextech/weave-react"; import { Toolbar } from "../toolbar/toolbar"; import { motion } from "framer-motion"; -import { leftElementVariants } from "./variants"; +import { bottomElementVariants } from "./variants"; import { SidebarActive, useCollaborationRoom } from "@/store/store"; import { cn } from "@/lib/utils"; import { WEAVE_STORE_CONNECTION_STATUS } from "@inditextech/weave-types"; @@ -51,6 +53,7 @@ import { ToolbarDivider } from "../toolbar/toolbar-divider"; import { useShapesTools } from "./hooks/use-shapes-tools"; import { useStrokesTools } from "./hooks/use-strokes-tools"; import { useImagesTools } from "./hooks/use-images-tools"; +import { useIAChat } from "@/store/ia-chat"; export function ToolsOverlayTouch() { const [actualShapeTool, setActualShapeTool] = React.useState("rectangleTool"); @@ -67,6 +70,8 @@ export function ToolsOverlayTouch() { const canRedo = useWeave((state) => state.undoRedo.canRedo); const weaveConnectionStatus = useWeave((state) => state.connection.status); + const aiChatEnabled = useIAChat((state) => state.enabled); + const nodeCreateProps = useCollaborationRoom( (state) => state.nodeProperties.createProps, ); @@ -125,16 +130,24 @@ export function ToolsOverlayTouch() { return null; } + const barOrientation = "horizontal"; + return ( - - + + } @@ -148,7 +161,7 @@ export function ToolsOverlayTouch() {

Selection

} - tooltipSide="right" + tooltipSide="top" tooltipAlign="center" /> Erase

} - tooltipSide="right" + tooltipSide="top" tooltipAlign="center" /> - +
@@ -198,12 +211,12 @@ export function ToolsOverlayTouch() { asChild > + ) : ( - + ) } disabled={ @@ -221,8 +234,9 @@ export function ToolsOverlayTouch() {

More shapes tools

} - tooltipSide="right" - tooltipAlign="start" + tooltipSideOffset={4} + tooltipSide="top" + tooltipAlign="center" /> @@ -331,12 +345,12 @@ export function ToolsOverlayTouch() { asChild > + ) : ( - + ) } disabled={ @@ -353,8 +367,9 @@ export function ToolsOverlayTouch() {

More strokes tools

} - tooltipSide="right" - tooltipAlign="start" + tooltipSideOffset={4} + tooltipSide="top" + tooltipAlign="center" /> Connector Tool

} - tooltipSide="right" + tooltipSide="top" tooltipAlign="center" />
@@ -448,7 +463,7 @@ export function ToolsOverlayTouch() { active={IMAGES_TOOLS[actualImagesTool].active()} onClick={IMAGES_TOOLS[actualImagesTool].onClick} label={IMAGES_TOOLS[actualImagesTool].label} - tooltipSide="right" + tooltipSide="top" tooltipAlign="center" /> @@ -468,12 +483,12 @@ export function ToolsOverlayTouch() { asChild > + ) : ( - + ) } disabled={ @@ -490,8 +505,9 @@ export function ToolsOverlayTouch() {

More images tools

} - tooltipSide="right" - tooltipAlign="start" + tooltipSideOffset={4} + tooltipSide="top" + tooltipAlign="center" /> Video tool

} - tooltipSide="right" + tooltipSide="top" tooltipAlign="center" /> Text tool

} - tooltipSide="right" + tooltipSide="top" tooltipAlign="center" /> Frame tool

} - tooltipSide="right" + tooltipSide="top" tooltipAlign="center" /> Image Template Tool

} - tooltipSide="right" + tooltipSide="top" tooltipAlign="center" /> {threadsEnabled && ( @@ -619,7 +635,7 @@ export function ToolsOverlayTouch() {

Comment tool

} - tooltipSide="right" + tooltipSide="top" tooltipAlign="center" /> )} @@ -652,7 +668,7 @@ export function ToolsOverlayTouch() {

Measure tool

} - tooltipSide="right" + tooltipSide="top" tooltipAlign="center" /> {/* - */} - + */} + } @@ -693,7 +709,7 @@ export function ToolsOverlayTouch() {

Undo latest changes

} - tooltipSide="right" + tooltipSide="top" tooltipAlign="center" /> Redo latest changes

} - tooltipSide="right" + tooltipSide="top" tooltipAlign="center" /> diff --git a/code/components/room-components/sidebar-selector.tsx b/code/components/room-components/sidebar-selector.tsx index 24713e5f..972cecb4 100644 --- a/code/components/room-components/sidebar-selector.tsx +++ b/code/components/room-components/sidebar-selector.tsx @@ -17,7 +17,7 @@ import { import { cn, SYSTEM_OS } from "@/lib/utils"; import { SwatchBook, - ListTree, + // ListTree, Projector, Images, ChevronDown, @@ -43,10 +43,10 @@ export const SidebarSelector = ({ title }: Readonly) => { const selectedNodes = useWeave((state) => state.selection.nodes); const setSidebarActive = useCollaborationRoom( - (state) => state.setSidebarActive + (state) => state.setSidebarActive, ); const threadsEnabled = useCollaborationRoom( - (state) => state.features.threads + (state) => state.features.threads, ); const aiChatEnabled = useIAChat((state) => state.enabled); @@ -55,18 +55,22 @@ export const SidebarSelector = ({ title }: Readonly) => { (element: SidebarActive) => { setSidebarActive(element); }, - [setSidebarActive] + [setSidebarActive], ); return ( - setMenuOpen(open)}> + setMenuOpen(open)} + // open={menuOpen} + modal={false} + > {title} @@ -85,18 +89,24 @@ export const SidebarSelector = ({ title }: Readonly) => { > {selectedNodes.length > 0 && ( - { - sidebarToggle(SIDEBAR_ELEMENTS.nodeProperties); - }} - > - Selection - + <> + { + e.stopPropagation(); + sidebarToggle(SIDEBAR_ELEMENTS.nodeProperties); + }} + > + Selection + + + + )} - { + onPointerDown={(e) => { + e.stopPropagation(); sidebarToggle(SIDEBAR_ELEMENTS.nodesTree); }} > @@ -104,11 +114,11 @@ export const SidebarSelector = ({ title }: Readonly) => { {SYSTEM_OS.MAC ? "⌥ ⌘ E" : "Alt Ctrl E"} - - + */} { + onPointerDown={(e) => { + e.stopPropagation(); sidebarToggle(SIDEBAR_ELEMENTS.images); }} > @@ -119,7 +129,8 @@ export const SidebarSelector = ({ title }: Readonly) => { { + onPointerDown={(e) => { + e.stopPropagation(); sidebarToggle(SIDEBAR_ELEMENTS.videos); }} > @@ -130,7 +141,8 @@ export const SidebarSelector = ({ title }: Readonly) => { { + onPointerDown={(e) => { + e.stopPropagation(); sidebarToggle(SIDEBAR_ELEMENTS.frames); }} > @@ -141,7 +153,8 @@ export const SidebarSelector = ({ title }: Readonly) => { { + onPointerDown={(e) => { + e.stopPropagation(); sidebarToggle(SIDEBAR_ELEMENTS.templates); }} > @@ -152,7 +165,8 @@ export const SidebarSelector = ({ title }: Readonly) => { { + onPointerDown={(e) => { + e.stopPropagation(); sidebarToggle(SIDEBAR_ELEMENTS.colorTokens); }} > @@ -164,7 +178,8 @@ export const SidebarSelector = ({ title }: Readonly) => { {threadsEnabled && ( { + onPointerDown={(e) => { + e.stopPropagation(); sidebarToggle(SIDEBAR_ELEMENTS.comments); }} > @@ -179,7 +194,8 @@ export const SidebarSelector = ({ title }: Readonly) => { { + onPointerDown={(e) => { + e.stopPropagation(); sidebarToggle(SIDEBAR_ELEMENTS.aiChat); }} > diff --git a/code/components/room-components/templates-library/templates-library.tsx b/code/components/room-components/templates-library/templates-library.tsx index 0e2b10a4..efd8391f 100644 --- a/code/components/room-components/templates-library/templates-library.tsx +++ b/code/components/room-components/templates-library/templates-library.tsx @@ -56,7 +56,7 @@ export const TemplatesLibrary = () => { user?.name ?? "", clientId ?? "", room ?? "", - templateId + templateId, ); }, onMutate: () => { @@ -83,7 +83,7 @@ export const TemplatesLibrary = () => { mutationDelete.mutate(template.templateId); }, - [instance, mutationDelete] + [instance, mutationDelete], ); React.useEffect(() => { @@ -97,7 +97,12 @@ export const TemplatesLibrary = () => { return; } - if (window.weaveDragTemplateData) { + const dragId = instance.getDragStartedId(); + const dragProperties = instance.getDragProperties<{ + templateData: string; + }>(); + + if (dragProperties && dragId === "add-template-to-room") { instance.getStage().setPointersPositions(e); const position: Konva.Vector2d | null | undefined = instance .getStage() @@ -112,13 +117,13 @@ export const TemplatesLibrary = () => { setTemplateOnPosition( instance, - window.weaveDragTemplateData - ? JSON.parse(window.weaveDragTemplateData.templateData) + dragProperties.templateData + ? JSON.parse(dragProperties.templateData) : {}, - mousePoint + mousePoint, ); - window.weaveDragTemplateData = undefined; + instance.endDrag("add-template-to-room"); } } @@ -139,7 +144,7 @@ export const TemplatesLibrary = () => { return await getTemplates( room ?? "", pageParam as number, - TEMPLATES_LIMIT + TEMPLATES_LIMIT, ); }, select: (newData) => newData, // keep shape stable @@ -148,7 +153,7 @@ export const TemplatesLibrary = () => { getNextPageParam: (lastPage, allPages) => { const loadedSoFar = allPages.reduce( (sum, page) => sum + page.items.length, - 0 + 0, ); if (loadedSoFar < lastPage.total) { return loadedSoFar; // next offset @@ -166,9 +171,9 @@ export const TemplatesLibrary = () => { prev.find( (oldItem) => oldItem.templateId === newItem.templateId && - oldItem.updatedAt === newItem.updatedAt - ) || newItem - ) + oldItem.updatedAt === newItem.updatedAt, + ) || newItem, + ), ); }, [query.data]); @@ -205,13 +210,13 @@ export const TemplatesLibrary = () => { newSelectedTemplates.push(template); } else { newSelectedTemplates = newSelectedTemplates.filter( - (actTemplate) => actTemplate !== template + (actTemplate) => actTemplate !== template, ); } const unique = [...new Set(newSelectedTemplates)]; setSelectedTemplates(unique); }, - [selectedTemplates] + [selectedTemplates], ); if (!instance) { @@ -286,10 +291,15 @@ export const TemplatesLibrary = () => {
{ + if (!instance) { + return; + } + if (e.target instanceof HTMLImageElement) { - window.weaveDragTemplateData = { - templateData: e.target.dataset.templateData, - }; + instance.startDrag("add-template-to-room"); + instance.setDragProperties<{ templateData: string }>({ + templateData: e.target.dataset.templateData ?? "", + }); } }} > diff --git a/code/components/room-components/toolbar/toolbar-divider.tsx b/code/components/room-components/toolbar/toolbar-divider.tsx index 91ef723a..a58bb495 100644 --- a/code/components/room-components/toolbar/toolbar-divider.tsx +++ b/code/components/room-components/toolbar/toolbar-divider.tsx @@ -17,11 +17,16 @@ export function ToolbarDivider({ orientation = "vertical", }: Readonly) { return ( -
+
diff --git a/code/components/room-components/upload-image.tsx b/code/components/room-components/upload-image.tsx index 8eec0dc9..d51f8a08 100644 --- a/code/components/room-components/upload-image.tsx +++ b/code/components/room-components/upload-image.tsx @@ -3,6 +3,8 @@ // SPDX-License-Identifier: Apache-2.0 import React from "react"; +import { v4 as uuidv4 } from "uuid"; +import { toast } from "sonner"; import { useCollaborationRoom } from "@/store/store"; import { useMutation, useQueryClient } from "@tanstack/react-query"; import { postImage } from "@/api/post-image"; @@ -19,16 +21,16 @@ export function UploadImage() { const room = useCollaborationRoom((state) => state.room); const showSelectFile = useCollaborationRoom( - (state) => state.images.showSelectFile + (state) => state.images.showSelectFile, ); const setUploadingImage = useCollaborationRoom( - (state) => state.setUploadingImage + (state) => state.setUploadingImage, ); const setShowSelectFileImage = useCollaborationRoom( - (state) => state.setShowSelectFileImage + (state) => state.setShowSelectFileImage, ); const workloadsEnabled = useCollaborationRoom( - (state) => state.features.workloads + (state) => state.features.workloads, ); const queryClient = useQueryClient(); @@ -44,97 +46,66 @@ export function UploadImage() { const handleUploadFile = React.useCallback( (file: File, position?: Konva.Vector2d) => { - setUploadingImage(true); - mutationUpload.mutate(file, { - onSuccess: (data) => { - const queryKey = ["getImages", room]; - queryClient.invalidateQueries({ queryKey }); - - if (!instance) { - return; - } + const resourceId = uuidv4(); + + const reader = new FileReader(); + reader.onloadend = () => { + if (!instance) { + return; + } + + const { nodeId, finishUploadCallback } = instance.triggerAction( + "imageTool", + { + imageId: resourceId, + imageData: reader.result as string, + ...(position && { position, forceMainContainer: true }), + }, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + ) as any; + + const toastId = toast.loading("Uploading image...", { + duration: Infinity, + }); + + mutationUpload.mutate(file, { + onSuccess: (data) => { + toast.dismiss(toastId); + toast.success("Image uploaded successfully"); - if (!workloadsEnabled) { - inputFileRef.current.value = null; - const room = data.fileName.split("/")[0]; - const imageId = data.fileName.split("/")[1]; - - if (position) { - instance.triggerAction( - "imageTool", - { - imageId, - imageURL: `${process.env.NEXT_PUBLIC_API_ENDPOINT}/weavejs/rooms/${room}/images/${imageId}`, - position, - forceMainContainer: true, - } - // eslint-disable-next-line @typescript-eslint/no-explicit-any - ) as any; - } else { - const { finishUploadCallback } = instance.triggerAction( - "imageTool" - // eslint-disable-next-line @typescript-eslint/no-explicit-any - ) as any; - - instance.updatePropsAction("imageTool", { - imageId, - }); - - finishUploadCallback?.({ - imageURL: `${process.env.NEXT_PUBLIC_API_ENDPOINT}/weavejs/rooms/${room}/images/${imageId}`, - }); + const queryKey = ["getImages", room]; + queryClient.invalidateQueries({ queryKey }); + + if (!instance) { + return; } - } - if (workloadsEnabled) { - inputFileRef.current.value = null; - const room = data.image.roomId; - const imageId = data.image.imageId; - - if (position) { - instance.triggerAction( - "imageTool", - { - imageId, - imageURL: `${process.env.NEXT_PUBLIC_API_ENDPOINT}/weavejs/rooms/${room}/images/${imageId}`, - position, - forceMainContainer: true, - } - // eslint-disable-next-line @typescript-eslint/no-explicit-any - ) as any; - } else { - const { finishUploadCallback } = instance.triggerAction( - "imageTool" - // eslint-disable-next-line @typescript-eslint/no-explicit-any - ) as any; - - instance.updatePropsAction("imageTool", { - imageId, - }); + if (workloadsEnabled) { + inputFileRef.current.value = null; + const room = data.image.roomId; + const imageId = data.image.imageId; finishUploadCallback?.( - `${process.env.NEXT_PUBLIC_API_ENDPOINT}/weavejs/rooms/${room}/images/${imageId}` + nodeId, + `${process.env.NEXT_PUBLIC_API_ENDPOINT}/weavejs/rooms/${room}/images/${imageId}`, ); } - } - }, - onError: (ex) => { - console.error(ex); - console.error("Error uploading image"); - }, - onSettled: () => { - setUploadingImage(false); - }, - }); + }, + onError: (ex) => { + toast.dismiss(toastId); + toast.error("Error uploading image"); + + console.error(ex); + console.error("Error uploading image"); + }, + }); + }; + reader.onerror = () => { + toast.error("Error reading image file"); + }; + reader.readAsDataURL(file); }, - [ - instance, - room, - workloadsEnabled, - mutationUpload, - queryClient, - setUploadingImage, - ] + [instance, room, workloadsEnabled, mutationUpload, queryClient], ); React.useEffect(() => { @@ -143,7 +114,7 @@ export function UploadImage() { return; } - if (window.weaveDragImageURL) { + if (instance.isDragStarted()) { return; } @@ -207,7 +178,7 @@ export function UploadImage() { return ( state.room); const showSelectFiles = useCollaborationRoom( - (state) => state.images.showSelectFiles + (state) => state.images.showSelectFiles, ); const setUploadingImage = useCollaborationRoom( - (state) => state.setUploadingImage + (state) => state.setUploadingImage, ); const setShowSelectFilesImages = useCollaborationRoom( - (state) => state.setShowSelectFilesImages + (state) => state.setShowSelectFilesImages, ); const workloadsEnabled = useCollaborationRoom( - (state) => state.features.workloads + (state) => state.features.workloads, ); const queryClient = useQueryClient(); @@ -40,7 +40,7 @@ export function UploadImages() { let promises = []; if (workloadsEnabled) { promises = Array.from(files).map((file) => - postImageV2(room ?? "", file) + postImageV2(room ?? "", file), ); } else { promises = Array.from(files).map((file) => postImage(room ?? "", file)); @@ -75,7 +75,7 @@ export function UploadImages() { { images, padding: 20, - } + }, // eslint-disable-next-line @typescript-eslint/no-explicit-any ) as any; } @@ -88,7 +88,7 @@ export function UploadImages() { }, }); }, - [instance, queryClient, room, mutationUploadMulti, setUploadingImage] + [instance, queryClient, room, mutationUploadMulti, setUploadingImage], ); React.useEffect(() => { @@ -104,7 +104,7 @@ export function UploadImages() { return ( state.room); const showSelectFile = useCollaborationRoom( - (state) => state.videos.showSelectFile + (state) => state.videos.showSelectFile, ); const setUploadingVideo = useCollaborationRoom( - (state) => state.setUploadingVideo + (state) => state.setUploadingVideo, ); const setShowSelectFileVideo = useCollaborationRoom( - (state) => state.setShowSelectFileVideo + (state) => state.setShowSelectFileVideo, ); const queryClient = useQueryClient(); @@ -65,12 +65,12 @@ export function UploadVideo() { }, position, forceMainContainer: true, - } + }, // eslint-disable-next-line @typescript-eslint/no-explicit-any ) as any; } else { const { finishUploadCallback } = instance.triggerAction( - "videoTool" + "videoTool", // eslint-disable-next-line @typescript-eslint/no-explicit-any ) as any; @@ -99,7 +99,7 @@ export function UploadVideo() { }, }); }, - [instance, room, mutationUpload, queryClient, setUploadingVideo] + [instance, room, mutationUpload, queryClient, setUploadingVideo], ); React.useEffect(() => { @@ -108,7 +108,7 @@ export function UploadVideo() { return; } - if (window.weaveDragVideoParams) { + if (instance.isDragStarted()) { return; } diff --git a/code/components/room-components/videos-library/videos-library.tsx b/code/components/room-components/videos-library/videos-library.tsx index 67c7edd7..edcee7ec 100644 --- a/code/components/room-components/videos-library/videos-library.tsx +++ b/code/components/room-components/videos-library/videos-library.tsx @@ -36,6 +36,10 @@ import { VideoEntity } from "./types"; import { VideosLibraryActions } from "./videos-ibrary.actions"; import { getVideos } from "@/api/get-videos"; import { SidebarHeader } from "../sidebar-header"; +import { + VIDEO_TOOL_ACTION_NAME, + WeaveVideoToolAction, +} from "@inditextech/weave-sdk"; const VIDEOS_LIMIT = 20; @@ -52,7 +56,7 @@ export const VideosLibrary = () => { const room = useCollaborationRoom((state) => state.room); const sidebarActive = useCollaborationRoom((state) => state.sidebar.active); const workloadsEnabled = useCollaborationRoom( - (state) => state.features.workloads + (state) => state.features.workloads, ); const mutationDelete = useMutation({ @@ -61,7 +65,7 @@ export const VideosLibrary = () => { user?.name ?? "", clientId ?? "", room ?? "", - videoId + videoId, ); }, onMutate: () => { @@ -88,7 +92,7 @@ export const VideosLibrary = () => { mutationDelete.mutate(video.videoId); }, - [instance, mutationDelete] + [instance, mutationDelete], ); const query = useInfiniteQuery({ @@ -108,7 +112,7 @@ export const VideosLibrary = () => { } const loadedSoFar = allPages.reduce( (sum, page) => sum + page.items.length, - 0 + 0, ); if (loadedSoFar < lastPage.total) { return loadedSoFar; // next offset @@ -121,7 +125,7 @@ export const VideosLibrary = () => { const appVideos = React.useMemo(() => { function extractVideos( videos: WeaveStateElement[], - node: WeaveStateElement + node: WeaveStateElement, ) { if (node.props && node.props.nodeType === "video" && node.props.videoId) { videos.push(node); @@ -162,9 +166,9 @@ export const VideosLibrary = () => { prev.find( (oldItem) => oldItem.videoId === newItem.videoId && - oldItem.updatedAt === newItem.updatedAt - ) || newItem - ) + oldItem.updatedAt === newItem.updatedAt, + ) || newItem, + ), ); }, [query.data]); @@ -189,7 +193,7 @@ export const VideosLibrary = () => { for (const video of videos) { const appVideo = appVideos.find( - (appVideo) => appVideo.props.videoId === video.videoId + (appVideo) => appVideo.props.videoId === video.videoId, ); if ( @@ -211,13 +215,13 @@ export const VideosLibrary = () => { newSelectedVideos.push(video); } else { newSelectedVideos = newSelectedVideos.filter( - (actVideo) => actVideo !== video + (actVideo) => actVideo !== video, ); } const unique = [...new Set(newSelectedVideos)]; setSelectedVideos(unique); }, - [selectedVideos] + [selectedVideos], ); if (!instance) { @@ -292,14 +296,28 @@ export const VideosLibrary = () => {
{ + if (!instance) { + return; + } + if (e.target instanceof HTMLVideoElement) { - window.weaveDragVideoParams = { - placeholderUrl: e.target.dataset.videoPlaceholderUrl, - url: e.target.dataset.videoUrl, - width: parseInt(e.target.dataset.videoWidth ?? "0"), - height: parseInt(e.target.dataset.videoHeight ?? "0"), - }; - window.weaveDragVideoId = e.target.dataset.videoId; + const videoTool = instance.getActionHandler( + VIDEO_TOOL_ACTION_NAME, + ) as WeaveVideoToolAction | undefined; + + if (!videoTool) { + return; + } + + videoTool.setDragAndDropProperties({ + videoId: e.target.dataset.videoId ?? "", + videoParams: { + placeholderUrl: e.target.dataset.videoPlaceholderUrl ?? "", + url: e.target.dataset.videoUrl ?? "", + width: parseInt(e.target.dataset.videoWidth ?? "0"), + height: parseInt(e.target.dataset.videoHeight ?? "0"), + }, + }); } }} > @@ -313,7 +331,7 @@ export const VideosLibrary = () => { {videos.length > 0 && videos.map((video) => { const appVideo = appVideos.find( - (appVideo) => appVideo.props.videoId === video.videoId + (appVideo) => appVideo.props.videoId === video.videoId, ); const isChecked = realSelectedVideos.includes(video); @@ -338,7 +356,7 @@ export const VideosLibrary = () => { (video.removalJobId !== null && video.removalStatus !== null && ["pending", "working"].includes( - video.removalStatus + video.removalStatus, )) ) ) { @@ -357,7 +375,7 @@ export const VideosLibrary = () => { (video.removalJobId !== null && video.removalStatus !== null && ["pending", "working"].includes( - video.removalStatus + video.removalStatus, )) ) && (
diff --git a/code/components/room/room-shadow-dom.tsx b/code/components/room/room-shadow-dom.tsx index f14197e2..428dc7bb 100644 --- a/code/components/room/room-shadow-dom.tsx +++ b/code/components/room/room-shadow-dom.tsx @@ -8,7 +8,6 @@ import React from "react"; import { Toaster } from "@/components/ui/sonner"; import { WeaveUser, WEAVE_INSTANCE_STATUS } from "@inditextech/weave-types"; import { useCollaborationRoom } from "@/store/store"; -import { ACTIONS, FONTS, NODES, PLUGINS } from "@/components/utils/constants"; import { useWeave, WeaveProvider } from "@inditextech/weave-react"; import { RoomLayout } from "./room.layout"; import { RoomLoader } from "../room-components/room-loader/room-loader"; @@ -21,6 +20,12 @@ import UserForm from "../room-components/user-form"; import { HelpDrawer } from "../room-components/help/help-drawer"; import { AppProviders } from "@/app/providers"; import { UploadVideo } from "../room-components/upload-video"; +import { FONTS } from "../utils/weave/fonts"; +import { NODES } from "../utils/weave/nodes"; +import { PLUGINS } from "../utils/weave/plugins"; +import { ACTIONS } from "../utils/weave/actions"; +import useGetRendererKonvaBase from "../room-components/hooks/use-get-renderer-konva-base"; +// import useGetRendererKonvaReactReconciler from "../room-components/hooks/use-get-renderer-konva-react-reconciler"; // eslint-disable-next-line @typescript-eslint/no-explicit-any const statusMap: any = { @@ -56,13 +61,13 @@ export const Room = () => { const room = useCollaborationRoom((state) => state.room); const user = useCollaborationRoom((state) => state.user); const loadingFetchConnectionUrl = useCollaborationRoom( - (state) => state.fetchConnectionUrl.loading + (state) => state.fetchConnectionUrl.loading, ); const errorFetchConnectionUrl = useCollaborationRoom( - (state) => state.fetchConnectionUrl.error + (state) => state.fetchConnectionUrl.error, ); const setFetchConnectionUrlError = useCollaborationRoom( - (state) => state.setFetchConnectionUrlError + (state) => state.setFetchConnectionUrlError, ); const setUser = useCollaborationRoom((state) => state.setUser); @@ -97,6 +102,9 @@ export const Room = () => { return ""; }, [loadingFetchConnectionUrl, status]); + const rendererProvider = useGetRendererKonvaBase(); + // const rendererProvider = useGetRendererKonvaReactReconciler(); + const storeProvider = useGetAzureWebPubSubProvider({ loadedParams: true, getUser, @@ -190,23 +198,20 @@ export const Room = () => { )} - {room && user && storeProvider && ( + {room && user && storeProvider && rendererProvider && ( { const shadowHost = document.getElementById("shadow-host"); return shadowHost?.shadowRoot?.querySelector( - "#weave" + "#weave", ) as HTMLDivElement; }} - // eslint-disable-next-line @typescript-eslint/no-explicit-any - store={storeProvider as any} + store={storeProvider} + renderer={rendererProvider} fonts={FONTS} - // eslint-disable-next-line @typescript-eslint/no-explicit-any - nodes={NODES() as any[]} - // eslint-disable-next-line @typescript-eslint/no-explicit-any - plugins={PLUGINS(getUser) as any[]} - // eslint-disable-next-line @typescript-eslint/no-explicit-any - actions={ACTIONS(getUser) as any[]} + nodes={NODES()} + plugins={PLUGINS(getUser)} + actions={ACTIONS(getUser)} > diff --git a/code/components/room/room.layout.tsx b/code/components/room/room.layout.tsx index 24d3ac73..3926fdba 100644 --- a/code/components/room/room.layout.tsx +++ b/code/components/room/room.layout.tsx @@ -79,6 +79,7 @@ export const RoomLayout = ({ inShadowDom }: Readonly) => { const status = useWeave((state) => state.status); const roomLoaded = useWeave((state) => state.room.loaded); const room = useCollaborationRoom((state) => state.room); + const nodes = useWeave((state) => state.selection.nodes); const weaveConnectionStatus = useWeave((state) => state.connection.status); const asyncElementsLoaded = useWeave((state) => state.asyncElements.loaded); const asyncElementsTotal = useWeave((state) => state.asyncElements.total); @@ -86,6 +87,7 @@ export const RoomLayout = ({ inShadowDom }: Readonly) => { (state) => state.asyncElements.allLoaded, ); + const viewType = useCollaborationRoom((state) => state.viewType); const contextMenuShow = useCollaborationRoom( (state) => state.contextMenu.show, ); @@ -211,7 +213,31 @@ export const RoomLayout = ({ inShadowDom }: Readonly) => { animate={controls} className="w-full h-full flex flex-col relative overflow-hidden" > -
+ {WEAVE_STORE_CONNECTION_STATUS.CONNECTED === weaveConnectionStatus && ( +
+ {viewType === "fixed" && inShadowDom && } + {viewType === "fixed" && !inShadowDom && } + +
+ )} +
) => { )}
- {inShadowDom ? : } + {viewType === "floating" && inShadowDom && } + {viewType === "floating" && !inShadowDom && } {WEAVE_STORE_CONNECTION_STATUS.CONNECTED === weaveConnectionStatus && ( -
+
0, + }, + )} + > - - {WEAVE_STORE_CONNECTION_STATUS.CONNECTED === - weaveConnectionStatus && ( - <> - - - - - - - - - {aiChatEnabled && } - - )} - +
0) || + viewType === "fixed", + ["invisible"]: viewType === "floating" && nodes.length === 0, + })} + > + + {WEAVE_STORE_CONNECTION_STATUS.CONNECTED === + weaveConnectionStatus && ( + <> + + + + + + + + {/* */} + {aiChatEnabled && } + + )} + +
)} {uploadingImage && ( diff --git a/code/components/room/room.tsx b/code/components/room/room.tsx index d6bd165e..24c1fcc8 100644 --- a/code/components/room/room.tsx +++ b/code/components/room/room.tsx @@ -10,7 +10,6 @@ import { Toaster } from "@/components/ui/sonner"; import { useRouter } from "next/navigation"; import { WeaveUser, WEAVE_INSTANCE_STATUS } from "@inditextech/weave-types"; import { useCollaborationRoom } from "@/store/store"; -import { ACTIONS, FONTS, NODES, PLUGINS } from "@/components/utils/constants"; import { useWeave, WeaveProvider } from "@inditextech/weave-react"; import { RoomLayout } from "./room.layout"; import { RoomLoader } from "../room-components/room-loader/room-loader"; @@ -26,6 +25,12 @@ import { useTasksEvents } from "../room-components/hooks/use-tasks-events"; import { useCommentsHandler } from "../room-components/hooks/use-comments-handler"; import { UploadVideo } from "../room-components/upload-video"; import ChatBotPromptProvider from "../room-components/ai-components/chatbot.prompt.provider"; +import useGetRendererKonvaBase from "../room-components/hooks/use-get-renderer-konva-base"; +import { NODES } from "../utils/weave/nodes"; +import { PLUGINS } from "../utils/weave/plugins"; +import { ACTIONS } from "../utils/weave/actions"; +import { FONTS } from "../utils/weave/fonts"; +// import useGetRendererKonvaReactReconciler from "../room-components/hooks/use-get-renderer-konva-react-reconciler"; // eslint-disable-next-line @typescript-eslint/no-explicit-any const statusMap: any = { @@ -142,6 +147,9 @@ const RoomInternal = () => { return ""; }, [loadedParams, loadingFetchConnectionUrl, status, comBusConnected]); + const rendererProvider = useGetRendererKonvaBase(); + // const rendererProvider = useGetRendererKonvaReactReconciler(); + const storeProvider = useGetAzureWebPubSubProvider({ loadedParams, getUser, @@ -236,56 +244,77 @@ const RoomInternal = () => { )} - {loadedParams && room && user && storeProvider && comBusConnected && ( - - { - return document?.getElementById("weave") as HTMLDivElement; - }} - // eslint-disable-next-line @typescript-eslint/no-explicit-any - store={storeProvider as any} - fonts={FONTS} - // eslint-disable-next-line @typescript-eslint/no-explicit-any - nodes={NODES() as any[]} - // eslint-disable-next-line @typescript-eslint/no-explicit-any - plugins={PLUGINS(getUser) as any[]} - // eslint-disable-next-line @typescript-eslint/no-explicit-any - actions={ACTIONS(getUser) as any[]} - performance={performanceConfiguration} - logModules={[]} - > - - - - - - - - )} + {loadedParams && + room && + user && + storeProvider && + rendererProvider && + comBusConnected && ( + + { + return document?.getElementById("weave") as HTMLDivElement; + }} + renderer={rendererProvider} + store={storeProvider} + fonts={FONTS} + nodes={NODES()} + plugins={PLUGINS(getUser)} + actions={ACTIONS(getUser)} + performance={performanceConfiguration} + logModules={[]} + > + + + + + + + + )} ); }; const Toasts = () => { const toasterContent = ( - + <> + + + ); // Only render in the browser diff --git a/code/components/use-cases/standalone/components/image-canvas/image-canvas.weave.tsx b/code/components/use-cases/standalone/components/image-canvas/image-canvas.weave.tsx index 1dd28059..10c7c625 100644 --- a/code/components/use-cases/standalone/components/image-canvas/image-canvas.weave.tsx +++ b/code/components/use-cases/standalone/components/image-canvas/image-canvas.weave.tsx @@ -10,6 +10,7 @@ import { ACTIONS, FONTS, NODES, PLUGINS } from "../../weave"; import { useGetStandaloneStore } from "../../hooks/use-get-standalone-store"; import { ImageCanvasLayout } from "./image-canvas.layout"; import { useStandaloneUseCase } from "../../store/store"; +import useGetRendererKonvaBase from "@/components/room-components/hooks/use-get-renderer-konva-base"; type ImageCanvasWeaveProps = { data: string | undefined; @@ -19,13 +20,13 @@ export const ImageCanvasWeave = ({ data }: ImageCanvasWeaveProps) => { const instanceId = useStandaloneUseCase((state) => state.instanceId); const user = useStandaloneUseCase((state) => state.user); const managingImageId = useStandaloneUseCase( - (state) => state.managing.imageId + (state) => state.managing.imageId, ); const managingImageWidth = useStandaloneUseCase( - (state) => state.managing.width + (state) => state.managing.width, ); const managingImageHeight = useStandaloneUseCase( - (state) => state.managing.height + (state) => state.managing.height, ); const getUser = React.useCallback(() => { @@ -39,6 +40,9 @@ export const ImageCanvasWeave = ({ data }: ImageCanvasWeaveProps) => { return user; }, [user]); + const renderer = useGetRendererKonvaBase(); + // const rendererProvider = useGetRendererKonvaReactReconciler(); + const store = useGetStandaloneStore({ instanceId, imageId: managingImageId!, @@ -47,7 +51,7 @@ export const ImageCanvasWeave = ({ data }: ImageCanvasWeaveProps) => { getUser, }); - if (!store) { + if (!store || !renderer) { return null; } @@ -57,6 +61,7 @@ export const ImageCanvasWeave = ({ data }: ImageCanvasWeaveProps) => { return document?.getElementById("weave") as HTMLDivElement; }} store={store} + renderer={renderer} fonts={FONTS} nodes={NODES()} plugins={PLUGINS(getUser)} diff --git a/code/components/use-cases/standalone/components/overlays/tools.tsx b/code/components/use-cases/standalone/components/overlays/tools.tsx index bd7493eb..8b35de54 100644 --- a/code/components/use-cases/standalone/components/overlays/tools.tsx +++ b/code/components/use-cases/standalone/components/overlays/tools.tsx @@ -16,6 +16,9 @@ import { Eraser, MessageSquare, RulerDimensionLine, + PenLine, + MoveUpRight, + Image, } from "lucide-react"; import { useWeave } from "@inditextech/weave-react"; import { Toolbar } from "@/components/room-components/toolbar/toolbar"; @@ -40,7 +43,7 @@ export function Tools() { instance.cancelAction(toolName); } }, - [instance, actualAction] + [instance, actualAction], ); return ( @@ -96,6 +99,54 @@ export function Tools() { tooltipSide="top" tooltipAlign="center" /> + } + disabled={ + weaveConnectionStatus !== WEAVE_STORE_CONNECTION_STATUS.CONNECTED + } + active={actualAction === "strokeTool"} + onClick={() => triggerTool("strokeTool")} + label={ +
+

Line tool

+
+ } + tooltipSide="top" + tooltipAlign="center" + /> + } + disabled={ + weaveConnectionStatus !== WEAVE_STORE_CONNECTION_STATUS.CONNECTED + } + active={actualAction === "arrowTool"} + onClick={() => triggerTool("arrowTool")} + label={ +
+

Arrow tool

+
+ } + tooltipSide="top" + tooltipAlign="center" + /> + } + disabled={ + weaveConnectionStatus !== WEAVE_STORE_CONNECTION_STATUS.CONNECTED + } + active={actualAction === "imageTool"} + onClick={() => triggerTool("imageTool")} + label={ +
+

Image tool

+
+ } + tooltipSide="top" + tooltipAlign="center" + /> } diff --git a/code/components/use-cases/standalone/components/upload-image.tsx b/code/components/use-cases/standalone/components/upload-image.tsx index aab0b42b..be2975ef 100644 --- a/code/components/use-cases/standalone/components/upload-image.tsx +++ b/code/components/use-cases/standalone/components/upload-image.tsx @@ -16,13 +16,13 @@ export function UploadImage() { const instanceId = useStandaloneUseCase((state) => state.instanceId); const showSelectFile = useStandaloneUseCase( - (state) => state.images.showSelectFile + (state) => state.images.showSelectFile, ); const setUploadingImage = useStandaloneUseCase( - (state) => state.setUploadingImage + (state) => state.setUploadingImage, ); const setShowSelectFileImage = useStandaloneUseCase( - (state) => state.setShowSelectFileImage + (state) => state.setShowSelectFileImage, ); const queryClient = useQueryClient(); @@ -50,7 +50,7 @@ export function UploadImage() { }, }); }, - [instanceId, mutationUpload, queryClient, setUploadingImage] + [instanceId, mutationUpload, queryClient, setUploadingImage], ); React.useEffect(() => { @@ -73,7 +73,7 @@ export function UploadImage() { return ( [ new WeaveEllipseNode(), new WeaveLineNode(), new WeaveStrokeNode(), + new WeaveStrokeSingleNode(), new WeaveTextNode(), new WeaveImageNode({ config: { @@ -523,10 +524,9 @@ const ACTIONS = (getUser: () => WeaveUser) => [ new WeaveEraserToolAction(), new WeaveRectangleToolAction(), new WeaveEllipseToolAction(), - new WeaveLineToolAction(), + new WeaveStrokeToolAction(), new WeaveBrushToolAction(), new WeaveImageToolAction(), - new WeaveArrowToolAction(), new WeaveTextToolAction(), new WeaveZoomOutToolAction(), new WeaveZoomInToolAction(), diff --git a/code/components/use-cases/templates/components/add-to-room/add-to-room.select-template.tsx b/code/components/use-cases/templates/components/add-to-room/add-to-room.select-template.tsx index e6a4f265..273243b3 100644 --- a/code/components/use-cases/templates/components/add-to-room/add-to-room.select-template.tsx +++ b/code/components/use-cases/templates/components/add-to-room/add-to-room.select-template.tsx @@ -18,10 +18,13 @@ import { Label } from "@/components/ui/label"; import { ScrollArea } from "@/components/ui/scroll-area"; import { LayoutTemplateIcon } from "lucide-react"; import { AddToRoomTemplate } from "./add-to-room.template"; +import { useWeave } from "@inditextech/weave-react"; const TEMPLATES_LIMIT = 20; export function AddToRoomSelectTemplate() { + const instance = useWeave((state) => state.instance); + const instanceId = useTemplatesUseCase((state) => state.instanceId); const addToRoomOpen = useTemplatesUseCase((state) => state.addToRoom.open); @@ -105,10 +108,15 @@ export function AddToRoomSelectTemplate() {
{ + if (!instance) { + return; + } + if (e.target instanceof HTMLImageElement) { - window.weaveDragTemplateData = { - templateData: e.target.dataset.templateData, - }; + instance.startDrag("add-template-to-room"); + instance.setDragProperties<{ templateData: string }>({ + templateData: e.target.dataset.templateData ?? "", + }); } }} > diff --git a/code/components/use-cases/templates/components/templates/templates.tsx b/code/components/use-cases/templates/components/templates/templates.tsx index e2525aee..7132bf4f 100644 --- a/code/components/use-cases/templates/components/templates/templates.tsx +++ b/code/components/use-cases/templates/components/templates/templates.tsx @@ -11,10 +11,13 @@ import { ScrollArea } from "@/components/ui/scroll-area"; import { TemplateEntity } from "./types"; import { Template } from "./template"; import { CogIcon, LayoutTemplateIcon } from "lucide-react"; +import { useWeave } from "@inditextech/weave-react"; const TEMPLATES_LIMIT = 20; export const Templates = () => { + const instance = useWeave((state) => state.instance); + const instanceId = useTemplatesUseCase((state) => state.instanceId); const templatesManage = useTemplatesUseCase( (state) => state.templates.manage, @@ -127,10 +130,15 @@ export const Templates = () => {
{ + if (!instance) { + return; + } + if (e.target instanceof HTMLImageElement) { - window.weaveDragTemplateData = { - templateData: e.target.dataset.templateData, - }; + instance.startDrag("add-template-to-room"); + instance.setDragProperties<{ templateData: string }>({ + templateData: e.target.dataset.templateData ?? "", + }); } }} > diff --git a/code/components/use-cases/templates/components/upload-image.tsx b/code/components/use-cases/templates/components/upload-image.tsx index 30308675..2d20ac4b 100644 --- a/code/components/use-cases/templates/components/upload-image.tsx +++ b/code/components/use-cases/templates/components/upload-image.tsx @@ -3,10 +3,13 @@ // SPDX-License-Identifier: Apache-2.0 import React from "react"; +import { v4 as uuidv4 } from "uuid"; +import { toast } from "sonner"; import { useMutation, useQueryClient } from "@tanstack/react-query"; import { useWeave } from "@inditextech/weave-react"; import { useTemplatesUseCase } from "../store/store"; import { postTemplatesImage } from "@/api/templates/post-templates-image"; +import Konva from "konva"; export function UploadImage() { // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -34,23 +37,65 @@ export function UploadImage() { }); const handleUploadFile = React.useCallback( - (file: File) => { - setUploadingImage(true); - mutationUpload.mutate(file, { - onSuccess: () => { - const queryKey = ["getTemplatesImages", instanceId]; - queryClient.invalidateQueries({ queryKey }); - }, - onError: (ex) => { - console.error(ex); - console.error("Error uploading image"); - }, - onSettled: () => { - setUploadingImage(false); - }, - }); + (file: File, position?: Konva.Vector2d) => { + const resourceId = uuidv4(); + + const reader = new FileReader(); + reader.onloadend = () => { + if (!instance) { + return; + } + + const { nodeId, finishUploadCallback } = instance.triggerAction( + "imageTool", + { + imageId: resourceId, + imageData: reader.result as string, + ...(position && { position, forceMainContainer: true }), + }, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + ) as any; + + const toastId = toast.loading("Uploading image...", { + duration: Infinity, + }); + + mutationUpload.mutate(file, { + onSuccess: (data) => { + toast.dismiss(toastId); + toast.success("Image uploaded successfully"); + + const queryKey = ["getTemplatesImages", instanceId]; + queryClient.invalidateQueries({ queryKey }); + + if (!instance) { + return; + } + + inputFileRef.current.value = null; + const room = data.image.roomId; + const imageId = data.image.imageId; + + finishUploadCallback?.( + nodeId, + `${process.env.NEXT_PUBLIC_API_ENDPOINT}/weavejs/rooms/${room}/images/${imageId}`, + ); + }, + onError: (ex) => { + toast.dismiss(toastId); + toast.error("Error uploading image"); + + console.error(ex); + console.error("Error uploading image"); + }, + }); + }; + reader.onerror = () => { + toast.error("Error reading image file"); + }; + reader.readAsDataURL(file); }, - [instanceId, mutationUpload, queryClient, setUploadingImage], + [instance, instanceId, mutationUpload, queryClient, setUploadingImage], ); React.useEffect(() => { @@ -70,7 +115,7 @@ export function UploadImage() { return ( = { - ["node-transform"]: "transforming element", - ["node-drag"]: "dragging element", - ["image-crop"]: "cropping image", - ["text-edit"]: "editing text", - ["nodes-transform"]: "transforming selection", - ["nodes-drag"]: "dragging selection", -}; - -const FONTS = async (): Promise => { - const interRegular = new FontFace("Inter", "url(/fonts/inter-regular.ttf)", { - weight: "400", - style: "normal", - }); - await interRegular.load(); - document.fonts.add(interRegular); - - const interBold = new FontFace("Inter", "url(/fonts/inter-bold.ttf)", { - weight: "700", - style: "normal", - }); - await interBold.load(); - document.fonts.add(interBold); - - const interItalic = new FontFace("Inter", "url(/fonts/inter-italic.ttf)", { - weight: "400", - style: "italic", - }); - await interItalic.load(); - document.fonts.add(interItalic); - - const interItalicBold = new FontFace( - "Inter", - "url(/fonts/inter-italic-bold.ttf)", - { weight: "700", style: "italic" }, - ); - await interItalicBold.load(); - document.fonts.add(interItalicBold); - - const sansitaRegular = new FontFace( - "Sansita", - "url(/fonts/sansita-regular.ttf)", - { weight: "400", style: "normal" }, - ); - await sansitaRegular.load(); - document.fonts.add(sansitaRegular); - - const sansitaBold = new FontFace("Sansita", "url(/fonts/sansita-bold.ttf)", { - weight: "700", - style: "normal", - }); - await sansitaBold.load(); - document.fonts.add(sansitaBold); - - const notoSansRegular = new FontFace( - "NotoSansMono", - "url(/fonts/NotoSansMono-Regular.ttf)", - { weight: "400", style: "normal" }, - ); - await notoSansRegular.load(); - document.fonts.add(notoSansRegular); - - return [ - { - id: "Inter", - name: `Inter, sans-serif`, - offsetY: -1.4, - }, - { - id: "Sansita", - name: `Sansita, sans-serif`, - offsetY: -1.6, - }, - { - id: "Arial", - name: "Arial", - offsetY: -1.6, - }, - { - id: "Helvetica", - name: "Helvetica, sans-serif", - offsetY: -1, - }, - { - id: "TimesNewRoman", - name: '"Times New Roman", serif', - offsetY: -1.6, - }, - { - id: "Times", - name: "Times, serif", - offsetY: -1.6, - }, - { - id: "CourierNew", - name: '"Courier New", monospace', - }, - { - id: "Courier", - name: "Courier, monospace", - offsetY: -1.2, - }, - { - id: "Verdana", - name: "Verdana, sans-serif", - offsetY: -2.2, - }, - { - id: "Georgia", - name: "Georgia, serif", - offsetY: -1.6, - }, - { - id: "Palatino", - name: "Palatino, serif", - offsetY: -0.8, - }, - { - id: "Garamond", - name: "Garamond, serif", - offsetY: -1.6, - }, - { - id: "Bookman", - name: "Bookman, serif", - offsetY: -1.6, - }, - { - id: "ComicSansMS", - name: '"Comic Sans MS", cursive', - offsetY: -3.6, - }, - { - id: "TrebuchetMS", - name: '"Trebuchet MS", sans-serif', - offsetY: -1.6, - }, - { - id: "ArialBlack", - name: '"Arial Black", sans-serif', - offsetY: -2.4, - }, - { - id: "Impact", - name: "Impact, sans-serif", - offsetY: -0.6, - }, - { - id: "NotoSansMono", - name: "NotoSansMono, monospace", - offsetY: -0.6, - }, - ]; -}; - -const NODES = () => [ - new WeaveStageNode(), - new WeaveLayerNode(), - new WeaveGroupNode(), - new WeaveRectangleNode(), - new WeaveEllipseNode(), - new WeaveLineNode(), - new WeaveStrokeNode(), - new WeaveStrokeSingleNode(), - new WeaveTextNode({ - config: { - outline: { - enabled: false, - // color: "#ffffff", - // width: 2, - }, - }, - }), - new WeaveImageNode({ - config: { - performance: { - cache: { - enabled: true, - pixelRatio: 2, - }, - }, - transform: { - enabledAnchors: [ - WEAVE_TRANSFORMER_ANCHORS.TOP_LEFT, - WEAVE_TRANSFORMER_ANCHORS.TOP_RIGHT, - WEAVE_TRANSFORMER_ANCHORS.BOTTOM_LEFT, - WEAVE_TRANSFORMER_ANCHORS.BOTTOM_RIGHT, - ], - keepRatio: true, - }, - urlTransformer: ( - url: string, - // , node?: Konva.Node - ) => { - // let resourceId: string | null = null; - // let resource = null; - - // if (node?.getAttrs().resourceId) { - // resourceId = node.getAttrs().resourceId; - // resource = resources.find((res) => res.resourceId === resourceId); - // } - - // if (resource) { - // return resource.downloadUrl; - // } - - return url; - }, - onDblClick: (instance: WeaveImageNode, node: Konva.Group) => { - instance.triggerCrop(node, { cmdCtrl: { triggered: false } }); - }, - }, - }), - new WeaveStarNode(), - new WeaveRegularPolygonNode(), - new WeaveFrameNode({ - config: { - fontFamily: "'Inter', sans-serif", - fontStyle: "normal", - fontSize: 14, - borderColor: "#757575", - fontColor: "#757575", - titleMargin: 5, - transform: { - rotateEnabled: false, - resizeEnabled: false, - enabledAnchors: [] as string[], - }, - }, - }), - new WeaveCommentNode({ - config: { - style: { - contracted: { - userName: { - fontFamily: "'Inter', sans-serif", - }, - }, - expanded: { - userName: { - fontFamily: "'Inter', sans-serif", - }, - date: { - fontFamily: "'Inter', sans-serif", - }, - content: { - fontFamily: "'Inter', sans-serif", - }, - }, - }, - model: { - getDate: (comment: ThreadEntity) => { - return (comment.updatedAt as unknown as string) ?? ""; - }, - getId: (comment: ThreadEntity) => { - return comment.threadId; - }, - getUserId: (comment: ThreadEntity) => { - return comment.userMetadata.name; - }, - getStatus: (comment: ThreadEntity) => { - return comment.status; - }, - getUserShortName: (comment: ThreadEntity) => { - return getUserShort(comment.userMetadata.name).toUpperCase(); - }, - getUserFullName: (comment: ThreadEntity) => { - return comment.userMetadata.name; - }, - canUserDrag: () => { - return true; - }, - getContent: (comment: ThreadEntity) => { - return comment.content; - }, - setMarkResolved: (comment: ThreadEntity) => { - return { ...comment, status: WEAVE_COMMENT_STATUS.RESOLVED }; - }, - setContent: (comment: ThreadEntity, content: string) => { - return { ...comment, content }; - }, - }, - formatDate: (date: string) => { - return formatDistanceToNow(new Date(date).toISOString(), { - addSuffix: true, - }); - }, - createComment: async ( - ele: HTMLDivElement, - node: WeaveElementInstance, - finish: ( - node: WeaveElementInstance, - content: string, - action: WeaveCommentNodeCreateAction, - ) => void, - ) => { - createCommentDOM({ ele, node, finish }); - }, - viewComment: async ( - ele: HTMLDivElement, - node: WeaveElementInstance, - finish: ( - node: WeaveElementInstance, - content: string, - action: WeaveCommentNodeViewAction, - ) => void, - ) => { - viewCommentDOM({ ele, node, finish }); - }, - }, - }), - new WeaveVideoNode({ - config: { - style: { - track: { - resetOnEnd: true, - onlyOnHover: false, - }, - }, - }, - }), - new WeaveConnectorNode(), - new WeaveMeasureNode(), - new ColorTokenNode(), - new ImageTemplateNode(), - new PantoneNode(), -]; - -const PLUGINS = (getUser: () => WeaveUser) => [ - new WeaveStageGridPlugin({ - config: { - gridColor: "rgba(0,0,0,0.3)", - gridOriginColor: "rgba(255,0,0,0.5)", - }, - }), - new WeaveStagePanningPlugin(), - new WeaveStageResizePlugin(), - new WeaveStageZoomPlugin({ - config: { - zoomSteps: [ - 0.01, 0.05, 0.1, 0.25, 0.5, 0.75, 0.9, 1, 1.25, 1.5, 1.75, 2, 3, 4, 6, - 8, 10, - ], - zoomInertia: { - friction: 0.9, - mouseWheelStep: 0.01, - }, - }, - }), - new WeaveNodesSelectionPlugin({ - config: { - selection: { - ignoreStroke: true, - padding: 0, - borderStrokeWidth: 2, - borderStroke: "#1a1aff", - }, - hover: { - ignoreStroke: true, - padding: 0, - borderStrokeWidth: 2, - borderStroke: "#1a1aff", - }, - selectionArea: { - fill: "#1a1aff11", - strokeWidth: 2, - stroke: "#1a1aff", - dash: [12, 4], - }, - behaviors: { - singleSelection: { - enabled: true, - }, - multipleSelection: { - enabled: true, - }, - onMultipleSelection: (nodes: Konva.Node[]) => { - const containsColorToken = nodes.some( - (node) => node.getAttrs().nodeType === COLOR_TOKEN_ACTION_NAME, - ); - - const containsFrame = nodes.some( - (node) => node.getAttrs().nodeType === WEAVE_FRAME_NODE_TYPE, - ); - - if (containsColorToken || containsFrame) { - return { - resizeEnabled: false, - rotateEnabled: false, - enabledAnchors: [], - }; - } - - const containsArrow = nodes.some( - (node) => - node.getAttrs().nodeType === WEAVE_STROKE_SINGLE_NODE_TYPE, - ); - - if (containsArrow) { - return { - resizeEnabled: true, - rotateEnabled: true, - enabledAnchors: [ - "top-left", - "top-right", - "bottom-left", - "bottom-right", - ], - }; - } - - const containsImage = nodes.some( - (node) => node.getAttrs().nodeType === WEAVE_IMAGE_NODE_TYPE, - ); - - if (containsImage) { - return { - resizeEnabled: true, - rotateEnabled: true, - enabledAnchors: [ - "top-left", - "top-right", - "bottom-left", - "bottom-right", - ], - }; - } - - return { - resizeEnabled: true, - rotateEnabled: true, - enabledAnchors: [ - "top-left", - "top-center", - "top-right", - "middle-right", - "middle-left", - "bottom-left", - "bottom-center", - "bottom-right", - ], - }; - }, - }, - }, - }), - new WeaveNodesEdgeSnappingPlugin(), - new WeaveNodesDistanceSnappingPlugin({ - config: { - ui: { - label: { - fontSize: 12, - fontFamily: "'Inter', sans-serif", - }, - }, - }, - }), - new WeaveStageDropAreaPlugin(), - new WeaveCopyPasteNodesPlugin({ - config: { - paddingOnPaste: { - enabled: true, - paddingX: 20, - paddingY: 20, - }, - }, - getImageBase64: async (instance, nodes) => { - try { - const res = await getImageBase64({ - instance: instance, - nodes: nodes.map((node) => node.getAttrs().id ?? ""), - options: { format: "image/png", padding: 0, pixelRatio: 1 }, - }); - return res.url; - } catch (error) { - console.error("Error getting image base64:", error); - throw error; - } - }, - }), - new WeaveConnectedUsersPlugin({ - config: { - getUser, - }, - }), - new WeaveUsersPointersPlugin({ - config: { - getOperationName: (operation: string) => - OPERATIONS_MAP[operation] ?? operation, - getUser, - getUserBackgroundColor: (user: WeaveUser) => - stringToColor(user?.name ?? "#000000"), - getUserForegroundColor: (user: WeaveUser) => { - const bgColor = stringToColor(user?.name ?? "#000000"); - return getContrastTextColor(bgColor); - }, - }, - }), - new WeaveUsersPresencePlugin({ - config: { - getUser, - }, - }), - new WeaveUsersSelectionPlugin({ - config: { - getUser, - getUserColor: (user: WeaveUser) => stringToColor(user?.name ?? "#000000"), - }, - }), - new WeaveContextMenuPlugin({ - config: { - xOffset: 10, - yOffset: 10, - }, - }), - new WeaveCommentsRendererPlugin({ - config: { - model: { - getId: (comment: ThreadEntity) => comment.threadId, - getPosition: (comment: ThreadEntity) => ({ - x: comment.x, - y: comment.y, - }), - getUser: (comment: ThreadEntity) => comment.userMetadata, - getStatus: (comment: ThreadEntity) => comment.status, - }, - getUser, - getUserBackgroundColor: (user: WeaveUser) => - stringToColor(user?.name ?? "#000000"), - getUserForegroundColor: (user: WeaveUser) => { - const bgColor = stringToColor(user?.name ?? "#ffffff"); - return getContrastTextColor(bgColor); - }, - }, - }), - new WeaveNodesMultiSelectionFeedbackPlugin(), - // new WeaveStageMinimapPlugin({ - // config: { - // getContainer: () => { - // return document?.getElementById("minimap") as HTMLElement; - // }, - // id: "weave_stage_minimap", - // width: window.innerWidth * 0.2, - // fitToContentPadding: 5, - // }, - // }), - new WeaveStageKeyboardMovePlugin({ - config: { - movementDelta: 5, - }, - }), -]; - -const ACTIONS = (getUser: () => WeaveUser) => [ - new WeaveMoveToolAction(), - new WeaveSelectionToolAction(), - new WeaveEraserToolAction(), - new WeaveRectangleToolAction(), - new WeaveEllipseToolAction(), - new WeavePenToolAction(), - new WeaveBrushToolAction(), - new WeaveImageToolAction(), - new WeaveFrameToolAction(), - new WeaveStarToolAction(), - new WeaveStrokeToolAction(), - new WeaveRegularPolygonToolAction(), - new ColorTokenToolAction(), - new ImageTemplateToolAction(), - new WeaveTextToolAction(), - new WeaveVideoToolAction(), - new WeaveConnectorToolAction(), - new WeaveZoomOutToolAction(), - new WeaveZoomInToolAction(), - new WeaveFitToScreenToolAction(), - new WeaveFitToSelectionToolAction(), - new WeaveAlignNodesToolAction(), - new WeaveExportNodesToolAction(), - new WeaveMeasureToolAction(), - new ImagesToolAction(), - new MaskToolAction(), - new FuzzyMaskToolAction(), - new MaskEraserToolAction(), - new WeaveCommentToolAction({ - config: { - style: { - cursor: { - add: "url(/cursors/message-square-plus.svg) 0 20, crosshair", - block: "url(/cursors/message-square-off.svg) 0 20, not-allowed", - }, - }, - model: { - getCreateModel: () => { - const createDate = new Date(); - - return { - userMetadata: getUser(), - createdAt: createDate, - updatedAt: createDate, - } as Partial; - }, - }, - getUser, - getUserBackgroundColor: (user: WeaveUser) => - stringToColor(user?.name ?? "#000000"), - getUserForegroundColor: (user: WeaveUser) => { - const bgColor = stringToColor(user?.name ?? "#ffffff"); - return getContrastTextColor(bgColor); - }, - }, - }), -]; - -export { FONTS, NODES, ACTIONS, PLUGINS }; diff --git a/code/components/utils/weave/actions.ts b/code/components/utils/weave/actions.ts new file mode 100644 index 00000000..c7a581d9 --- /dev/null +++ b/code/components/utils/weave/actions.ts @@ -0,0 +1,99 @@ +// SPDX-FileCopyrightText: 2025 2025 INDUSTRIA DE DISEÑO TEXTIL S.A. (INDITEX S.A.) +// +// SPDX-License-Identifier: Apache-2.0 + +"use client"; + +import { + WeaveMoveToolAction, + WeaveSelectionToolAction, + WeaveEraserToolAction, + WeaveBrushToolAction, + WeaveFrameToolAction, + WeaveImageToolAction, + WeavePenToolAction, + WeaveRectangleToolAction, + WeaveEllipseToolAction, + WeaveTextToolAction, + WeaveStarToolAction, + WeaveStrokeToolAction, + WeaveRegularPolygonToolAction, + WeaveZoomOutToolAction, + WeaveZoomInToolAction, + WeaveFitToScreenToolAction, + WeaveFitToSelectionToolAction, + WeaveAlignNodesToolAction, + WeaveCommentToolAction, + WeaveExportNodesToolAction, + WeaveVideoToolAction, + WeaveMeasureToolAction, + WeaveConnectorToolAction, +} from "@inditextech/weave-sdk"; +import { type WeaveUser } from "@inditextech/weave-types"; +import { ColorTokenToolAction } from "../../actions/color-token-tool/color-token-tool"; +import { ImagesToolAction } from "../../actions/images-tool/images-tool"; +import { ImageTemplateToolAction } from "../../actions/image-template-tool/image-template-tool"; +import { MaskToolAction } from "../../actions/mask-tool/mask-tool"; +import { FuzzyMaskToolAction } from "../../actions/fuzzy-mask-tool/fuzzy-mask-tool"; +import { MaskEraserToolAction } from "../../actions/mask-eraser-tool/mask-eraser-tool"; +import { getContrastTextColor, stringToColor } from "@/lib/utils"; +import { ThreadEntity } from "../../room-components/hooks/types"; + +export const ACTIONS = (getUser: () => WeaveUser) => [ + new WeaveMoveToolAction(), + new WeaveSelectionToolAction(), + new WeaveEraserToolAction(), + new WeaveRectangleToolAction(), + new WeaveEllipseToolAction(), + new WeavePenToolAction(), + new WeaveBrushToolAction(), + new WeaveImageToolAction(), + new WeaveFrameToolAction(), + new WeaveStarToolAction(), + new WeaveStrokeToolAction(), + new WeaveRegularPolygonToolAction(), + new ColorTokenToolAction(), + new ImageTemplateToolAction(), + new WeaveTextToolAction(), + new WeaveVideoToolAction(), + new WeaveConnectorToolAction(), + new WeaveZoomOutToolAction(), + new WeaveZoomInToolAction(), + new WeaveFitToScreenToolAction(), + new WeaveFitToSelectionToolAction(), + new WeaveAlignNodesToolAction(), + new WeaveExportNodesToolAction(), + new WeaveMeasureToolAction(), + new ImagesToolAction(), + new MaskToolAction(), + new FuzzyMaskToolAction(), + new MaskEraserToolAction(), + new WeaveCommentToolAction({ + config: { + style: { + cursor: { + add: "url(/cursors/message-square-plus.svg) 0 20, crosshair", + block: "url(/cursors/message-square-off.svg) 0 20, not-allowed", + }, + }, + model: { + getCreateModel: () => { + const createDate = new Date(); + + return { + userMetadata: getUser(), + createdAt: createDate, + updatedAt: createDate, + } as Partial; + }, + }, + getUser, + getUserBackgroundColor: (user: WeaveUser) => + stringToColor(user?.name ?? "#000000"), + getUserForegroundColor: (user: WeaveUser) => { + const bgColor = stringToColor(user?.name ?? "#ffffff"); + return getContrastTextColor(bgColor); + }, + }, + }), +]; diff --git a/code/components/utils/weave/constants.ts b/code/components/utils/weave/constants.ts new file mode 100644 index 00000000..2209151b --- /dev/null +++ b/code/components/utils/weave/constants.ts @@ -0,0 +1,14 @@ +// SPDX-FileCopyrightText: 2025 2025 INDUSTRIA DE DISEÑO TEXTIL S.A. (INDITEX S.A.) +// +// SPDX-License-Identifier: Apache-2.0 + +"use client"; + +export const OPERATIONS_MAP: Record = { + ["node-transform"]: "transforming element", + ["node-drag"]: "dragging element", + ["image-crop"]: "cropping image", + ["text-edit"]: "editing text", + ["nodes-transform"]: "transforming selection", + ["nodes-drag"]: "dragging selection", +}; diff --git a/code/components/utils/weave/fonts.ts b/code/components/utils/weave/fonts.ts new file mode 100644 index 00000000..a7a8c72b --- /dev/null +++ b/code/components/utils/weave/fonts.ts @@ -0,0 +1,218 @@ +// SPDX-FileCopyrightText: 2025 2025 INDUSTRIA DE DISEÑO TEXTIL S.A. (INDITEX S.A.) +// +// SPDX-License-Identifier: Apache-2.0 + +"use client"; + +import { WeaveFont } from "@inditextech/weave-types"; + +export const FONTS = async (): Promise => { + const fonts: WeaveFont[] = []; + + // ARIAL FONT + const arialRegular = new FontFace("Arial", "url(/fonts/ARIAL.TTF)", { + weight: "400", + style: "normal", + }); + await arialRegular.load(); + document.fonts.add(arialRegular); + + const arialBold = new FontFace("Arial", "url(/fonts/ARIALBD.TTF)", { + weight: "700", + style: "normal", + }); + await arialBold.load(); + document.fonts.add(arialBold); + + const arialItalic = new FontFace("Arial", "url(/fonts/ARIALI.TTF)", { + weight: "400", + style: "italic", + }); + await arialItalic.load(); + document.fonts.add(arialItalic); + + const arialItalicBold = new FontFace("Arial", "url(/fonts/ARIALBI.TTF)", { + weight: "700", + style: "italic", + }); + await arialItalicBold.load(); + document.fonts.add(arialItalicBold); + + fonts.push({ + id: "Arial", + name: "Arial, sans-serif", + offsetY: -1.6, + supportedStyles: ["normal", "italic", "bold"], + }); + + // FUZZY BUBBLES + + const fuzzyBubblesRegular = new FontFace( + "Fuzzy Bubbles", + "url(/fonts/FuzzyBubbles-Regular.ttf)", + { weight: "400", style: "normal" }, + ); + await fuzzyBubblesRegular.load(); + document.fonts.add(fuzzyBubblesRegular); + + const fuzzyBubblesBold = new FontFace( + "Fuzzy Bubbles", + "url(/fonts/FuzzyBubbles-Bold.ttf)", + { weight: "700", style: "normal" }, + ); + await fuzzyBubblesBold.load(); + document.fonts.add(fuzzyBubblesBold); + + fonts.push({ + id: "FuzzyBubbles", + name: "Fuzzy Bubbles, cursive", + offsetY: -0.6, + supportedStyles: ["normal", "bold"], + }); + + // INTER FONT + const interRegular = new FontFace("Inter", "url(/fonts/inter-regular.ttf)", { + weight: "400", + style: "normal", + }); + await interRegular.load(); + document.fonts.add(interRegular); + + const interBold = new FontFace("Inter", "url(/fonts/inter-bold.ttf)", { + weight: "700", + style: "normal", + }); + await interBold.load(); + document.fonts.add(interBold); + + const interItalic = new FontFace("Inter", "url(/fonts/inter-italic.ttf)", { + weight: "400", + style: "italic", + }); + await interItalic.load(); + document.fonts.add(interItalic); + + const interItalicBold = new FontFace( + "Inter", + "url(/fonts/inter-italic-bold.ttf)", + { weight: "700", style: "italic" }, + ); + await interItalicBold.load(); + document.fonts.add(interItalicBold); + + fonts.push({ + id: "Inter", + name: `Inter, sans-serif`, + offsetY: -1.4, + supportedStyles: ["normal", "italic", "bold"], + }); + + // NOTO SANS MONO + + const notoSansMonoRegular = new FontFace( + "Noto Sans Mono", + "url(/fonts/NotoSansMono-Regular.ttf)", + { weight: "400", style: "normal" }, + ); + await notoSansMonoRegular.load(); + document.fonts.add(notoSansMonoRegular); + + const notoSansMonoBold = new FontFace( + "Noto Sans Mono", + "url(/fonts/NotoSansMono-Bold.ttf)", + { weight: "700", style: "normal" }, + ); + await notoSansMonoBold.load(); + document.fonts.add(notoSansMonoBold); + + fonts.push({ + id: "Noto Sans Mono", + name: "Noto Sans Mono, monospace", + offsetY: -0.6, + supportedStyles: ["normal", "bold"], + }); + + // ROBOTO MONO FONT + + const robotoMonoRegular = new FontFace( + "RobotoMono", + "url(/fonts/RobotoMono-Regular.ttf)", + { weight: "400", style: "normal" }, + ); + await robotoMonoRegular.load(); + document.fonts.add(robotoMonoRegular); + + const robotoMonoItalic = new FontFace( + "RobotoMono", + "url(/fonts/RobotoMono-Italic.ttf)", + { weight: "400", style: "italic" }, + ); + await robotoMonoItalic.load(); + document.fonts.add(robotoMonoItalic); + + const robotoMonoBold = new FontFace( + "RobotoMono", + "url(/fonts/RobotoMono-Bold.ttf)", + { weight: "700", style: "normal" }, + ); + await robotoMonoBold.load(); + document.fonts.add(robotoMonoBold); + + const robotoMonoItalicBold = new FontFace( + "RobotoMono", + "url(/fonts/RobotoMono-BoldItalic.ttf)", + { weight: "700", style: "italic" }, + ); + await robotoMonoItalicBold.load(); + document.fonts.add(robotoMonoItalicBold); + + fonts.push({ + id: "RobotoMono", + name: "Roboto Mono, monospace", + offsetY: -0.6, + supportedStyles: ["normal", "italic", "bold"], + }); + + // SANSITA FONT + + const sansitaRegular = new FontFace( + "Sansita", + "url(/fonts/sansita-regular.ttf)", + { weight: "400", style: "normal" }, + ); + await sansitaRegular.load(); + document.fonts.add(sansitaRegular); + + const sansitaBold = new FontFace("Sansita", "url(/fonts/sansita-bold.ttf)", { + weight: "700", + style: "normal", + }); + await sansitaBold.load(); + document.fonts.add(sansitaBold); + + fonts.push({ + id: "Sansita", + name: `Sansita, sans-serif`, + offsetY: -1.6, + supportedStyles: ["normal", "bold"], + }); + + // SPECIAL GOTHIC CONDENSED + + const specialGothicCondensedOneRegular = new FontFace( + "Special Gothic Condensed One", + "url(/fonts/SpecialGothicCondensedOne-Regular.ttf)", + { weight: "400", style: "normal" }, + ); + await specialGothicCondensedOneRegular.load(); + document.fonts.add(specialGothicCondensedOneRegular); + + fonts.push({ + id: "SpecialGothicCondensedOne", + name: "Special Gothic Condensed One, sans-serif", + offsetY: -0.6, + supportedStyles: ["normal"], + }); + + return fonts; +}; diff --git a/code/components/utils/weave/nodes.ts b/code/components/utils/weave/nodes.ts new file mode 100644 index 00000000..070368a1 --- /dev/null +++ b/code/components/utils/weave/nodes.ts @@ -0,0 +1,222 @@ +// SPDX-FileCopyrightText: 2025 2025 INDUSTRIA DE DISEÑO TEXTIL S.A. (INDITEX S.A.) +// +// SPDX-License-Identifier: Apache-2.0 + +"use client"; + +import Konva from "konva"; +import { formatDistanceToNow } from "date-fns"; +import { + WeaveStageNode, + WeaveLayerNode, + WeaveGroupNode, + WeaveRectangleNode, + WeaveEllipseNode, + WeaveTextNode, + WeaveImageNode, + WeaveStarNode, + WeaveLineNode, + WeaveRegularPolygonNode, + WeaveFrameNode, + WeaveStrokeNode, + WeaveStrokeSingleNode, + WeaveCommentNode, + WeaveVideoNode, + WeaveMeasureNode, + WeaveConnectorNode, + WeaveCommentNodeCreateAction, + WeaveCommentNodeViewAction, + WEAVE_COMMENT_STATUS, +} from "@inditextech/weave-sdk"; +import { WeaveElementInstance } from "@inditextech/weave-types"; +import { PantoneNode } from "@/components/nodes/pantone/pantone"; +import { ColorTokenNode } from "@/components/nodes/color-token/color-token"; +import { ImageTemplateNode } from "@/components/nodes/image-template/image-template"; +import { WEAVE_TRANSFORMER_ANCHORS } from "@inditextech/weave-types"; +import { + createCommentDOM, + viewCommentDOM, +} from "../../room-components/comment/comment-dom"; +import { getUserShort } from "./../users"; +import { ThreadEntity } from "../../room-components/hooks/types"; +// import resources from "./resources/resources2.json"; +import { BACKGROUND_COLOR } from "@/store/store"; + +const ENABLED_RESOURCES = false; + +export const NODES = () => [ + new WeaveStageNode(), + new WeaveLayerNode(), + new WeaveGroupNode(), + new WeaveRectangleNode(), + new WeaveEllipseNode(), + new WeaveLineNode(), + new WeaveStrokeNode(), + new WeaveStrokeSingleNode(), + new WeaveTextNode({ + config: { + outline: { + enabled: true, + color: BACKGROUND_COLOR.GRAY, + width: 2, + }, + }, + }), + new WeaveImageNode({ + config: { + performance: { + cache: { + enabled: true, + pixelRatio: 2, + }, + }, + transform: { + enabledAnchors: [ + WEAVE_TRANSFORMER_ANCHORS.TOP_LEFT, + WEAVE_TRANSFORMER_ANCHORS.TOP_RIGHT, + WEAVE_TRANSFORMER_ANCHORS.BOTTOM_LEFT, + WEAVE_TRANSFORMER_ANCHORS.BOTTOM_RIGHT, + ], + keepRatio: true, + }, + urlTransformer: ( + url: string, + //node?: Konva.Node + ) => { + if (!ENABLED_RESOURCES) { + return url; + } + + // let resourceId: string | null = null; + // let resource = null; + + // if (node?.getAttrs().resourceId) { + // resourceId = node.getAttrs().resourceId; + // resource = resources.find((res) => res.resourceId === resourceId); + // } + + // if (resource) { + // return resource.downloadUrl; + // } + + return url; + }, + onDblClick: (instance: WeaveImageNode, node: Konva.Group) => { + instance.triggerCrop(node, { cmdCtrl: { triggered: false } }); + }, + }, + }), + new WeaveStarNode(), + new WeaveRegularPolygonNode(), + new WeaveFrameNode({ + config: { + fontFamily: "'Inter', sans-serif", + fontStyle: "normal", + fontSize: 14, + borderColor: "#757575", + fontColor: "#757575", + titleMargin: 5, + transform: { + rotateEnabled: false, + resizeEnabled: false, + enabledAnchors: [] as string[], + }, + }, + }), + new WeaveCommentNode({ + config: { + style: { + contracted: { + userName: { + fontFamily: "'Inter', sans-serif", + }, + }, + expanded: { + userName: { + fontFamily: "'Inter', sans-serif", + }, + date: { + fontFamily: "'Inter', sans-serif", + }, + content: { + fontFamily: "'Inter', sans-serif", + }, + }, + }, + model: { + getDate: (comment: ThreadEntity) => { + return (comment.updatedAt as unknown as string) ?? ""; + }, + getId: (comment: ThreadEntity) => { + return comment.threadId; + }, + getUserId: (comment: ThreadEntity) => { + return comment.userMetadata.name; + }, + getStatus: (comment: ThreadEntity) => { + return comment.status; + }, + getUserShortName: (comment: ThreadEntity) => { + return getUserShort(comment.userMetadata.name).toUpperCase(); + }, + getUserFullName: (comment: ThreadEntity) => { + return comment.userMetadata.name; + }, + canUserDrag: () => { + return true; + }, + getContent: (comment: ThreadEntity) => { + return comment.content; + }, + setMarkResolved: (comment: ThreadEntity) => { + return { ...comment, status: WEAVE_COMMENT_STATUS.RESOLVED }; + }, + setContent: (comment: ThreadEntity, content: string) => { + return { ...comment, content }; + }, + }, + formatDate: (date: string) => { + return formatDistanceToNow(new Date(date).toISOString(), { + addSuffix: true, + }); + }, + createComment: async ( + ele: HTMLDivElement, + node: WeaveElementInstance, + finish: ( + node: WeaveElementInstance, + content: string, + action: WeaveCommentNodeCreateAction, + ) => void, + ) => { + createCommentDOM({ ele, node, finish }); + }, + viewComment: async ( + ele: HTMLDivElement, + node: WeaveElementInstance, + finish: ( + node: WeaveElementInstance, + content: string, + action: WeaveCommentNodeViewAction, + ) => void, + ) => { + viewCommentDOM({ ele, node, finish }); + }, + }, + }), + new WeaveVideoNode({ + config: { + style: { + track: { + resetOnEnd: true, + onlyOnHover: false, + }, + }, + }, + }), + new WeaveConnectorNode(), + new WeaveMeasureNode(), + new ColorTokenNode(), + new ImageTemplateNode(), + new PantoneNode(), +]; diff --git a/code/components/utils/weave/plugins.ts b/code/components/utils/weave/plugins.ts new file mode 100644 index 00000000..f3ae50a2 --- /dev/null +++ b/code/components/utils/weave/plugins.ts @@ -0,0 +1,261 @@ +// SPDX-FileCopyrightText: 2025 2025 INDUSTRIA DE DISEÑO TEXTIL S.A. (INDITEX S.A.) +// +// SPDX-License-Identifier: Apache-2.0 + +"use client"; + +import Konva from "konva"; +import { + WeaveStageGridPlugin, + WeaveNodesSelectionPlugin, + WeaveStagePanningPlugin, + WeaveStageResizePlugin, + WeaveStageZoomPlugin, + WeaveConnectedUsersPlugin, + WeaveUsersPointersPlugin, + WeaveUsersPresencePlugin, + WeaveUsersSelectionPlugin, + WeaveStageDropAreaPlugin, + WeaveCopyPasteNodesPlugin, + WeaveContextMenuPlugin, + WeaveNodesEdgeSnappingPlugin, + // WeaveNodesDistanceSnappingPlugin, + WeaveCommentsRendererPlugin, + // WeaveStageMinimapPlugin, + WeaveNodesMultiSelectionFeedbackPlugin, + WeaveStageKeyboardMovePlugin, + WEAVE_FRAME_NODE_TYPE, + WEAVE_IMAGE_NODE_TYPE, + WEAVE_STROKE_SINGLE_NODE_TYPE, +} from "@inditextech/weave-sdk"; +import { type WeaveUser } from "@inditextech/weave-types"; +import { getContrastTextColor, stringToColor } from "@/lib/utils"; +import { ThreadEntity } from "../../room-components/hooks/types"; +import { getImageBase64 } from "./../images"; +import { COLOR_TOKEN_ACTION_NAME } from "../../actions/color-token-tool/constants"; +import { OPERATIONS_MAP } from "./constants"; + +export const PLUGINS = (getUser: () => WeaveUser) => [ + new WeaveStageGridPlugin({ + config: { + gridColor: "rgba(0,0,0,0.3)", + gridOriginColor: "rgba(255,0,0,0.5)", + }, + }), + new WeaveStagePanningPlugin(), + new WeaveStageResizePlugin(), + new WeaveStageZoomPlugin({ + config: { + zoomSteps: [ + 0.01, 0.05, 0.1, 0.25, 0.5, 0.75, 0.9, 1, 1.25, 1.5, 1.75, 2, 3, 4, 6, + 8, 10, + ], + zoomInertia: { + friction: 0.9, + mouseWheelStep: 0.01, + }, + }, + }), + new WeaveNodesSelectionPlugin({ + config: { + selection: { + ignoreStroke: true, + padding: 0, + borderStrokeWidth: 2, + borderStroke: "#1a1aff", + }, + hover: { + ignoreStroke: true, + padding: 0, + borderStrokeWidth: 2, + borderStroke: "#1a1aff", + }, + selectionArea: { + fill: "#1a1aff11", + strokeWidth: 2, + stroke: "#1a1aff", + dash: [12, 4], + }, + behaviors: { + singleSelection: { + enabled: true, + }, + multipleSelection: { + enabled: true, + }, + onMultipleSelection: (nodes: Konva.Node[]) => { + const containsColorToken = nodes.some( + (node) => node.getAttrs().nodeType === COLOR_TOKEN_ACTION_NAME, + ); + + const containsFrame = nodes.some( + (node) => node.getAttrs().nodeType === WEAVE_FRAME_NODE_TYPE, + ); + + if (containsColorToken || containsFrame) { + return { + resizeEnabled: false, + rotateEnabled: false, + enabledAnchors: [], + }; + } + + const containsArrow = nodes.some( + (node) => + node.getAttrs().nodeType === WEAVE_STROKE_SINGLE_NODE_TYPE, + ); + + if (containsArrow) { + return { + resizeEnabled: true, + rotateEnabled: true, + enabledAnchors: [ + "top-left", + "top-right", + "bottom-left", + "bottom-right", + ], + }; + } + + const containsImage = nodes.some( + (node) => node.getAttrs().nodeType === WEAVE_IMAGE_NODE_TYPE, + ); + + if (containsImage) { + return { + resizeEnabled: true, + rotateEnabled: true, + enabledAnchors: [ + "top-left", + "top-right", + "bottom-left", + "bottom-right", + ], + }; + } + + return { + resizeEnabled: true, + rotateEnabled: true, + enabledAnchors: [ + "top-left", + "top-center", + "top-right", + "middle-right", + "middle-left", + "bottom-left", + "bottom-center", + "bottom-right", + ], + }; + }, + }, + }, + }), + new WeaveNodesEdgeSnappingPlugin(), + // new WeaveNodesDistanceSnappingPlugin({ + // config: { + // ui: { + // label: { + // fontSize: 12, + // fontFamily: "'Inter', sans-serif", + // }, + // }, + // }, + // }), + new WeaveStageDropAreaPlugin(), + new WeaveCopyPasteNodesPlugin({ + config: { + paddingOnPaste: { + enabled: true, + paddingX: 20, + paddingY: 20, + }, + }, + getImageBase64: async (instance, nodes) => { + try { + const res = await getImageBase64({ + instance: instance, + nodes: nodes.map((node) => node.getAttrs().id ?? ""), + options: { format: "image/png", padding: 0, pixelRatio: 1 }, + }); + return res.url; + } catch (error) { + console.error("Error getting image base64:", error); + throw error; + } + }, + }), + new WeaveConnectedUsersPlugin({ + config: { + getUser, + }, + }), + new WeaveUsersPointersPlugin({ + config: { + getOperationName: (operation: string) => + OPERATIONS_MAP[operation] ?? operation, + getUser, + getUserBackgroundColor: (user: WeaveUser) => + stringToColor(user?.name ?? "#000000"), + getUserForegroundColor: (user: WeaveUser) => { + const bgColor = stringToColor(user?.name ?? "#000000"); + return getContrastTextColor(bgColor); + }, + }, + }), + new WeaveUsersPresencePlugin({ + config: { + getUser, + }, + }), + new WeaveUsersSelectionPlugin({ + config: { + getUser, + getUserColor: (user: WeaveUser) => stringToColor(user?.name ?? "#000000"), + }, + }), + new WeaveContextMenuPlugin({ + config: { + xOffset: 10, + yOffset: 10, + }, + }), + new WeaveCommentsRendererPlugin({ + config: { + model: { + getId: (comment: ThreadEntity) => comment.threadId, + getPosition: (comment: ThreadEntity) => ({ + x: comment.x, + y: comment.y, + }), + getUser: (comment: ThreadEntity) => comment.userMetadata, + getStatus: (comment: ThreadEntity) => comment.status, + }, + getUser, + getUserBackgroundColor: (user: WeaveUser) => + stringToColor(user?.name ?? "#000000"), + getUserForegroundColor: (user: WeaveUser) => { + const bgColor = stringToColor(user?.name ?? "#ffffff"); + return getContrastTextColor(bgColor); + }, + }, + }), + new WeaveNodesMultiSelectionFeedbackPlugin(), + // new WeaveStageMinimapPlugin({ + // config: { + // getContainer: () => { + // return document?.getElementById("minimap") as HTMLElement; + // }, + // id: "weave_stage_minimap", + // width: window.innerWidth * 0.2, + // fitToContentPadding: 5, + // }, + // }), + new WeaveStageKeyboardMovePlugin({ + config: { + movementDelta: 5, + }, + }), +]; diff --git a/code/justfile b/code/justfile index f7f9c707..500f08bd 100644 --- a/code/justfile +++ b/code/justfile @@ -4,7 +4,7 @@ alias ld := link-deps alias uld := unlink-deps link-deps: - npm link @inditextech/weave-types @inditextech/weave-sdk @inditextech/weave-react @inditextech/weave-store-websockets @inditextech/weave-store-azure-web-pubsub @inditextech/weave-store-standalone + npm link @inditextech/weave-types @inditextech/weave-sdk @inditextech/weave-react @inditextech/weave-store-websockets @inditextech/weave-store-azure-web-pubsub @inditextech/weave-store-standalone @inditextech/weave-renderer-konva-react-reconciler @inditextech/weave-renderer-konva-base unlink-deps: - npm unlink @inditextech/weave-types @inditextech/weave-sdk @inditextech/weave-react @inditextech/weave-store-websockets @inditextech/weave-store-azure-web-pubsub @inditextech/weave-store-standalone + npm unlink @inditextech/weave-types @inditextech/weave-sdk @inditextech/weave-react @inditextech/weave-store-websockets @inditextech/weave-store-azure-web-pubsub @inditextech/weave-store-standalone @inditextech/weave-renderer-konva-react-reconciler @inditextech/weave-renderer-konva-base diff --git a/code/package-lock.json b/code/package-lock.json index 59c88cdf..a9355d21 100644 --- a/code/package-lock.json +++ b/code/package-lock.json @@ -16,9 +16,11 @@ "@commitlint/config-conventional": "19.2.2", "@google/genai": "^1.30.0", "@hookform/resolvers": "^4.1.3", - "@inditextech/weave-react": "2.23.0", - "@inditextech/weave-store-azure-web-pubsub": "2.23.0", - "@inditextech/weave-store-standalone": "2.23.0", + "@inditextech/weave-react": "3.1.0", + "@inditextech/weave-renderer-konva-base": "3.1.0", + "@inditextech/weave-renderer-konva-react-reconciler": "3.1.0", + "@inditextech/weave-store-azure-web-pubsub": "3.1.0", + "@inditextech/weave-store-standalone": "3.1.0", "@next/env": "^15.2.1", "@openrouter/ai-sdk-provider": "^1.2.5", "@radix-ui/react-accordion": "^1.2.10", @@ -131,13 +133,13 @@ } }, "node_modules/@ai-sdk/gateway": { - "version": "2.0.44", - "resolved": "https://registry.npmjs.org/@ai-sdk/gateway/-/gateway-2.0.44.tgz", - "integrity": "sha512-hunEcN60Fugfc3NVqCS1H4WqoaVwTjnSskNMwcp3ztzSmBn/QQ7ox1DWd2Jh1FAZEDcjxYtdgneRrXQId3ovtw==", + "version": "2.0.54", + "resolved": "https://registry.npmjs.org/@ai-sdk/gateway/-/gateway-2.0.54.tgz", + "integrity": "sha512-bK47JS1IYanXc5ruhfEVLDUcig7Im3gQr5p52AB4x//mT/wcGLf85SxwGWzw42pyOsW8ee38Wy567WWJc90s/A==", "license": "Apache-2.0", "dependencies": { "@ai-sdk/provider": "2.0.1", - "@ai-sdk/provider-utils": "3.0.21", + "@ai-sdk/provider-utils": "3.0.22", "@vercel/oidc": "3.1.0" }, "engines": { @@ -160,9 +162,9 @@ } }, "node_modules/@ai-sdk/provider-utils": { - "version": "3.0.21", - "resolved": "https://registry.npmjs.org/@ai-sdk/provider-utils/-/provider-utils-3.0.21.tgz", - "integrity": "sha512-veuMwTLxsgh31Jjn0SnBABnM1f7ebHhRWcV2ZuY3hP3iJDCZ8VXBaYqcHXoOQDqUXTCas08sKQcHyWK+zl882Q==", + "version": "3.0.22", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider-utils/-/provider-utils-3.0.22.tgz", + "integrity": "sha512-fFT1KfUUKktfAFm5mClJhS1oux9tP2qgzmEZVl5UdwltQ1LO/s8hd7znVrgKzivwv1s1FIPza0s9OpJaNB/vHw==", "license": "Apache-2.0", "dependencies": { "@ai-sdk/provider": "2.0.1", @@ -177,13 +179,13 @@ } }, "node_modules/@ai-sdk/react": { - "version": "2.0.140", - "resolved": "https://registry.npmjs.org/@ai-sdk/react/-/react-2.0.140.tgz", - "integrity": "sha512-mK2hoZRpzFD+0dyhsSthlMUHRDR25vaTwfFzP5Lij2gs/Dty+h8Q8tJD65/kf4FTWEq3Nrk6onZC20HpVX3QSQ==", + "version": "2.0.151", + "resolved": "https://registry.npmjs.org/@ai-sdk/react/-/react-2.0.151.tgz", + "integrity": "sha512-C1T9LmADK2a2AxLyeh8rITaCPTmJdQQUC2avdctkIa5odHehj0eOFjkg7S4e6UDlZ+unFauB9DiE1N18Pr5XEA==", "license": "Apache-2.0", "dependencies": { - "@ai-sdk/provider-utils": "3.0.21", - "ai": "5.0.138", + "@ai-sdk/provider-utils": "3.0.22", + "ai": "5.0.149", "swr": "^2.2.5", "throttleit": "2.1.0" }, @@ -349,9 +351,9 @@ } }, "node_modules/@azure/core-rest-pipeline": { - "version": "1.22.2", - "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.22.2.tgz", - "integrity": "sha512-MzHym+wOi8CLUlKCQu12de0nwcq9k9Kuv43j4Wa++CsCpJwps2eeBQwD2Bu8snkxTtDKDx4GwjuR9E8yC8LNrg==", + "version": "1.23.0", + "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.23.0.tgz", + "integrity": "sha512-Evs1INHo+jUjwHi1T6SG6Ua/LHOQBCLuKEEE6efIpt4ZOoNonaT1kP32GoOcdNDbfqsD2445CPri3MubBy5DEQ==", "license": "MIT", "dependencies": { "@azure/abort-controller": "^2.1.2", @@ -359,7 +361,7 @@ "@azure/core-tracing": "^1.3.0", "@azure/core-util": "^1.13.0", "@azure/logger": "^1.3.0", - "@typespec/ts-http-runtime": "^0.3.0", + "@typespec/ts-http-runtime": "^0.3.4", "tslib": "^2.6.2" }, "engines": { @@ -874,42 +876,42 @@ "license": "MIT" }, "node_modules/@chevrotain/cst-dts-gen": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/@chevrotain/cst-dts-gen/-/cst-dts-gen-11.1.1.tgz", - "integrity": "sha512-fRHyv6/f542qQqiRGalrfJl/evD39mAvbJLCekPazhiextEatq1Jx1K/i9gSd5NNO0ds03ek0Cbo/4uVKmOBcw==", + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/@chevrotain/cst-dts-gen/-/cst-dts-gen-11.1.2.tgz", + "integrity": "sha512-XTsjvDVB5nDZBQB8o0o/0ozNelQtn2KrUVteIHSlPd2VAV2utEb6JzyCJaJ8tGxACR4RiBNWy5uYUHX2eji88Q==", "license": "Apache-2.0", "dependencies": { - "@chevrotain/gast": "11.1.1", - "@chevrotain/types": "11.1.1", + "@chevrotain/gast": "11.1.2", + "@chevrotain/types": "11.1.2", "lodash-es": "4.17.23" } }, "node_modules/@chevrotain/gast": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/@chevrotain/gast/-/gast-11.1.1.tgz", - "integrity": "sha512-Ko/5vPEYy1vn5CbCjjvnSO4U7GgxyGm+dfUZZJIWTlQFkXkyym0jFYrWEU10hyCjrA7rQtiHtBr0EaZqvHFZvg==", + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/@chevrotain/gast/-/gast-11.1.2.tgz", + "integrity": "sha512-Z9zfXR5jNZb1Hlsd/p+4XWeUFugrHirq36bKzPWDSIacV+GPSVXdk+ahVWZTwjhNwofAWg/sZg58fyucKSQx5g==", "license": "Apache-2.0", "dependencies": { - "@chevrotain/types": "11.1.1", + "@chevrotain/types": "11.1.2", "lodash-es": "4.17.23" } }, "node_modules/@chevrotain/regexp-to-ast": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/@chevrotain/regexp-to-ast/-/regexp-to-ast-11.1.1.tgz", - "integrity": "sha512-ctRw1OKSXkOrR8VTvOxrQ5USEc4sNrfwXHa1NuTcR7wre4YbjPcKw+82C2uylg/TEwFRgwLmbhlln4qkmDyteg==", + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/@chevrotain/regexp-to-ast/-/regexp-to-ast-11.1.2.tgz", + "integrity": "sha512-nMU3Uj8naWer7xpZTYJdxbAs6RIv/dxYzkYU8GSwgUtcAAlzjcPfX1w+RKRcYG8POlzMeayOQ/znfwxEGo5ulw==", "license": "Apache-2.0" }, "node_modules/@chevrotain/types": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-11.1.1.tgz", - "integrity": "sha512-wb2ToxG8LkgPYnKe9FH8oGn3TMCBdnwiuNC5l5y+CtlaVRbCytU0kbVsk6CGrqTL4ZN4ksJa0TXOYbxpbthtqw==", + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-11.1.2.tgz", + "integrity": "sha512-U+HFai5+zmJCkK86QsaJtoITlboZHBqrVketcO2ROv865xfCMSFpELQoz1GkX5GzME8pTa+3kbKrZHQtI0gdbw==", "license": "Apache-2.0" }, "node_modules/@chevrotain/utils": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/@chevrotain/utils/-/utils-11.1.1.tgz", - "integrity": "sha512-71eTYMzYXYSFPrbg/ZwftSaSDld7UYlS8OQa3lNnn9jzNtpFbaReRRyghzqS7rI3CDaorqpPJJcXGHK+FE1TVQ==", + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/@chevrotain/utils/-/utils-11.1.2.tgz", + "integrity": "sha512-4mudFAQ6H+MqBTfqLmU7G1ZwRzCLfJEooL/fsF6rCX5eePMbGhoy5n4g+G4vlh2muDcsCTJtL+uKbOzWxs5LHA==", "license": "Apache-2.0" }, "node_modules/@commitlint/cli": { @@ -1837,31 +1839,31 @@ } }, "node_modules/@floating-ui/core": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.4.tgz", - "integrity": "sha512-C3HlIdsBxszvm5McXlB8PeOEWfBhcGBTZGkGlWc2U0KFY5IwG5OQEuQ8rq52DZmcHDlPLd+YFBK+cZcytwIFWg==", + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.5.tgz", + "integrity": "sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==", "license": "MIT", "dependencies": { - "@floating-ui/utils": "^0.2.10" + "@floating-ui/utils": "^0.2.11" } }, "node_modules/@floating-ui/dom": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.5.tgz", - "integrity": "sha512-N0bD2kIPInNHUHehXhMke1rBGs1dwqvC9O9KYMyyjK7iXt7GAhnro7UlcuYcGdS/yYOlq0MAVgrow8IbWJwyqg==", + "version": "1.7.6", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.6.tgz", + "integrity": "sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==", "license": "MIT", "dependencies": { - "@floating-ui/core": "^1.7.4", - "@floating-ui/utils": "^0.2.10" + "@floating-ui/core": "^1.7.5", + "@floating-ui/utils": "^0.2.11" } }, "node_modules/@floating-ui/react-dom": { - "version": "2.1.7", - "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.7.tgz", - "integrity": "sha512-0tLRojf/1Go2JgEVm+3Frg9A3IW8bJgKgdO0BN5RkF//ufuz2joZM63Npau2ff3J6lUVYgDSNzNkR+aH3IVfjg==", + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.8.tgz", + "integrity": "sha512-cC52bHwM/n/CxS87FH0yWdngEZrjdtLW/qVruo68qg+prK7ZQ4YGdut2GyDVpoGeAYe/h899rVeOVm6Oi40k2A==", "license": "MIT", "dependencies": { - "@floating-ui/dom": "^1.7.5" + "@floating-ui/dom": "^1.7.6" }, "peerDependencies": { "react": ">=16.8.0", @@ -1869,15 +1871,15 @@ } }, "node_modules/@floating-ui/utils": { - "version": "0.2.10", - "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz", - "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==", + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.11.tgz", + "integrity": "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==", "license": "MIT" }, "node_modules/@google/genai": { - "version": "1.42.0", - "resolved": "https://registry.npmjs.org/@google/genai/-/genai-1.42.0.tgz", - "integrity": "sha512-+3nlMTcrQufbQ8IumGkOphxD5Pd5kKyJOzLcnY0/1IuE8upJk5aLmoexZ2BJhBp1zAjRJMEB4a2CJwKI9e2EYw==", + "version": "1.44.0", + "resolved": "https://registry.npmjs.org/@google/genai/-/genai-1.44.0.tgz", + "integrity": "sha512-kRt9ZtuXmz+tLlcNntN/VV4LRdpl6ZOu5B1KbfNgfR65db15O6sUQcwnwLka8sT/V6qysD93fWrgJHF2L7dA9A==", "license": "Apache-2.0", "dependencies": { "google-auth-library": "^10.3.0", @@ -2326,17 +2328,17 @@ } }, "node_modules/@inditextech/weave-react": { - "version": "2.23.0", - "resolved": "https://registry.npmjs.org/@inditextech/weave-react/-/weave-react-2.23.0.tgz", - "integrity": "sha512-ozJKy/Ap61kCuhJmNNP4mQtbRUI352x+2QuaSJ7GPrqt/qqz2fHeEcL+kJqT/6ugQuc5C3dSPnrCigXouEDUbA==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@inditextech/weave-react/-/weave-react-3.1.0.tgz", + "integrity": "sha512-ZbmCbjSnS8WOVCbkvlvq5XW45Ir5WwwFGj8CcoOm28miGyIa9H9PJ//GUvWnqmMhVf68BOE5O1QyY/JtNKWAAw==", "license": "Apache-2.0", "dependencies": { - "@inditextech/weave-sdk": "2.23.0", - "@inditextech/weave-types": "2.23.0", + "@inditextech/weave-sdk": "3.1.0", + "@inditextech/weave-types": "3.1.0", "@syncedstore/core": "0.6.0" }, "engines": { - "node": "^18.12 || ^20.11 || ^22.11", + "node": ">=18.12", "npm": ">= 8.19.x" }, "peerDependencies": { @@ -2348,20 +2350,42 @@ "yjs": "13.6.27" } }, - "node_modules/@inditextech/weave-sdk": { - "version": "2.23.0", - "resolved": "https://registry.npmjs.org/@inditextech/weave-sdk/-/weave-sdk-2.23.0.tgz", - "integrity": "sha512-jVy2bKfhMWOzemdvFKwQfib/1c2r4JSfztheuga4s+j09kFgsXkwiUgc9pZnOC/+lTU/ZHMtwAZ9bweTAgLxfQ==", + "node_modules/@inditextech/weave-renderer-konva-base": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@inditextech/weave-renderer-konva-base/-/weave-renderer-konva-base-3.1.0.tgz", + "integrity": "sha512-YiUIGY1j+5zIMMalK4SUKGyqtVdqS3a4RDk0YcyB+F4tForGfhjp7K5OAE0/1oslsogcmYQJClElklvJvgEWHQ==", "license": "Apache-2.0", "dependencies": { - "@inditextech/weave-types": "2.23.0", + "@inditextech/weave-sdk": "3.1.0", + "@inditextech/weave-types": "3.1.0", + "pino": "9.6.0", + "pino-pretty": "13.0.0" + }, + "engines": { + "node": ">=18.12", + "npm": ">= 8.19.x" + }, + "peerDependencies": { + "canvas": "3.2.0", + "konva": "10.0.2", + "skia-canvas": "3.0.8" + } + }, + "node_modules/@inditextech/weave-renderer-konva-react-reconciler": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@inditextech/weave-renderer-konva-react-reconciler/-/weave-renderer-konva-react-reconciler-3.1.0.tgz", + "integrity": "sha512-CBaLVDYIrBwU5sw60tG/bPM/4XXRi9meMSaAVY65Tsj7FQvUIiaJFzpUbV0RmhoYO9YyYThps4R34+qdpuTckg==", + "license": "Apache-2.0", + "dependencies": { + "@inditextech/weave-sdk": "3.1.0", + "@inditextech/weave-types": "3.1.0", "@syncedstore/core": "0.6.0", "pino": "9.6.0", "pino-pretty": "13.0.0", "react-reconciler": "~0.28.0" }, "engines": { - "node": "^18.12 || ^20.11 || ^22.11", + "node": ">=18.12", "npm": ">= 8.19.x" }, "peerDependencies": { @@ -2373,16 +2397,38 @@ "yjs": "13.6.27" } }, + "node_modules/@inditextech/weave-sdk": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@inditextech/weave-sdk/-/weave-sdk-3.1.0.tgz", + "integrity": "sha512-fvTkxKS5rKWmy5XLxfMHMbREd4ddQLs1R87UJNXmnboxmfLDmvOWD7RtoUDwb2O6dwF7snNZFyow7R2cCA+BTg==", + "license": "Apache-2.0", + "dependencies": { + "@inditextech/weave-types": "3.1.0", + "@syncedstore/core": "0.6.0", + "pino": "9.6.0", + "pino-pretty": "13.0.0" + }, + "engines": { + "node": ">=18.12", + "npm": ">= 8.19.x" + }, + "peerDependencies": { + "canvas": "3.2.0", + "konva": "10.0.2", + "skia-canvas": "3.0.8", + "yjs": "13.6.27" + } + }, "node_modules/@inditextech/weave-store-azure-web-pubsub": { - "version": "2.23.0", - "resolved": "https://registry.npmjs.org/@inditextech/weave-store-azure-web-pubsub/-/weave-store-azure-web-pubsub-2.23.0.tgz", - "integrity": "sha512-P/Da4Fq10hivb6XOH0PvKB09dAwoxST7+LsdPvITfpijrh+1FXn5DKncq4CbcodSaabDXLuKgHXhDfFBk788Yg==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@inditextech/weave-store-azure-web-pubsub/-/weave-store-azure-web-pubsub-3.1.0.tgz", + "integrity": "sha512-ySjOH2WiTg3CvTnO2w71OjP33Mor7MupNolgnk2ZK0i8zvK49PZtqACUEH73JTuFw639G/U+YqGrVukNTxVHQg==", "license": "Apache-2.0", "dependencies": { "@azure/identity": "4.10.2", "@azure/web-pubsub": "1.2.0", - "@inditextech/weave-sdk": "2.23.0", - "@inditextech/weave-types": "2.23.0", + "@inditextech/weave-sdk": "3.1.0", + "@inditextech/weave-types": "3.1.0", "@syncedstore/core": "0.6.0", "buffer": "6.0.3", "reconnecting-websocket": "4.4.0", @@ -2390,7 +2436,7 @@ "ws": "8.18.1" }, "engines": { - "node": "^18.12 || ^20.11 || ^22.11", + "node": ">=18.12", "npm": ">= 8.19.x" }, "peerDependencies": { @@ -2443,17 +2489,17 @@ } }, "node_modules/@inditextech/weave-store-standalone": { - "version": "2.23.0", - "resolved": "https://registry.npmjs.org/@inditextech/weave-store-standalone/-/weave-store-standalone-2.23.0.tgz", - "integrity": "sha512-byUeyIS5LD7j0BapDU6w0JCIxEr4t/qr5dRMp0K/GonqorBwEvWfVU32RZrfw6f2fcHjDDG/PG9hz94ljtUTdQ==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@inditextech/weave-store-standalone/-/weave-store-standalone-3.1.0.tgz", + "integrity": "sha512-4jHCG5UymgSZNQGuPaZ1qL/e7dcGprGxXcdzienWptt8jbGZPEi6eweYpRVNE+6hlwpf6IEhEeG4W8e2HdKPmQ==", "license": "Apache-2.0", "dependencies": { - "@inditextech/weave-sdk": "2.23.0", - "@inditextech/weave-types": "2.23.0", + "@inditextech/weave-sdk": "3.1.0", + "@inditextech/weave-types": "3.1.0", "@syncedstore/core": "0.6.0" }, "engines": { - "node": "^18.12 || ^20.11 || ^22.11", + "node": ">=18.12", "npm": ">= 8.19.x" }, "peerDependencies": { @@ -2462,12 +2508,12 @@ } }, "node_modules/@inditextech/weave-types": { - "version": "2.23.0", - "resolved": "https://registry.npmjs.org/@inditextech/weave-types/-/weave-types-2.23.0.tgz", - "integrity": "sha512-l0pHh4UY5YaRDtN3YAqdGFrXC0XGxqlAkqJXOy0Nc1L9aSNkerd9c1WpzKuNEctcKt8c69pgwnFZ6CgJdCPCPQ==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@inditextech/weave-types/-/weave-types-3.1.0.tgz", + "integrity": "sha512-UJE2oq0WLt9aiykoJ9Yu0iPgOq5r3opVb1GTPyJFc6qL0oT+PM7j8WLwj4gOEAXFZo6vnF3mhGcVFDCiD5GieA==", "license": "Apache-2.0", "engines": { - "node": "^18.12 || ^20.11 || ^22.11", + "node": ">=18.12", "npm": ">= 8.19.x" }, "peerDependencies": { @@ -2476,9 +2522,9 @@ } }, "node_modules/@ioredis/commands": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.5.0.tgz", - "integrity": "sha512-eUgLqrMf8nJkZxT24JvVRrQya1vZkQh8BBeYNwGDqa5I0VUi8ACx7uFvAaLxintokpTenkK6DASvo/bvNbBGow==", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.5.1.tgz", + "integrity": "sha512-JH8ZL/ywcJyR9MmJ5BNqZllXNZQqQbnVZOqpPQqE1vHiFgAw4NHbvE0FOduNU8IX9babitBT46571OnPTT0Zcw==", "license": "MIT", "peer": true }, @@ -2512,12 +2558,12 @@ } }, "node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", - "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", "license": "MIT", "dependencies": { - "ansi-regex": "^6.0.1" + "ansi-regex": "^6.2.2" }, "engines": { "node": ">=12" @@ -6259,9 +6305,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "20.19.33", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.33.tgz", - "integrity": "sha512-Rs1bVAIdBs5gbTIKza/tgpMuG1k3U/UMJLWecIMxNdJFDMzcM5LOiLVRYh3PilWEYDIeUDv7bpiHPLPsbydGcw==", + "version": "20.19.37", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.37.tgz", + "integrity": "sha512-8kzdPJ3FsNsVIurqBs7oodNnCEVbni9yUEkaHbgptDACOPW04jimGagZ51E6+lXUwJjgnBw+hyko/lkFWCldqw==", "license": "MIT", "dependencies": { "undici-types": "~6.21.0" @@ -6575,9 +6621,9 @@ } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.3.tgz", - "integrity": "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", + "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", "dev": true, "license": "MIT", "dependencies": { @@ -6588,9 +6634,9 @@ } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "10.2.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.3.tgz", - "integrity": "sha512-Rwi3pnapEqirPSbWbrZaa6N3nmqq4Xer/2XooiOKyV3q12ML06f7MOuc5DVH8ONZIFhwIYQ3yzPH4nt7iWHaTg==", + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { @@ -6659,9 +6705,9 @@ } }, "node_modules/@typespec/ts-http-runtime": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@typespec/ts-http-runtime/-/ts-http-runtime-0.3.3.tgz", - "integrity": "sha512-91fp6CAAJSRtH5ja95T1FHSKa8aPW9/Zw6cta81jlZTUw/+Vq8jM/AfF/14h2b71wwR84JUTW/3Y8QPhDAawFA==", + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/@typespec/ts-http-runtime/-/ts-http-runtime-0.3.4.tgz", + "integrity": "sha512-CI0NhTrz4EBaa0U+HaaUZrJhPoso8sG7ZFya8uQoBA57fjzrjRSv87ekCjLZOFExN+gXE/z0xuN2QfH4H2HrLQ==", "license": "MIT", "dependencies": { "http-proxy-agent": "^7.0.0", @@ -7431,14 +7477,14 @@ } }, "node_modules/ai": { - "version": "5.0.138", - "resolved": "https://registry.npmjs.org/ai/-/ai-5.0.138.tgz", - "integrity": "sha512-ORkQfHFBnLHgaNhJh1N3fmMQwETLxIHNy5eIDae8qOOZ7FHYxZZVMPQs8T0FiC7MGYFScBmiDJ3s61XvJVBomw==", + "version": "5.0.149", + "resolved": "https://registry.npmjs.org/ai/-/ai-5.0.149.tgz", + "integrity": "sha512-ebOvqbUZ4njabaKC7gpuFBbNsyvH8y/9eyIDgKefu9PB8j5GdkWKsXNtPxhz4PDFnDb0GClCtsJ4j/gWy71UNg==", "license": "Apache-2.0", "dependencies": { - "@ai-sdk/gateway": "2.0.44", + "@ai-sdk/gateway": "2.0.54", "@ai-sdk/provider": "2.0.1", - "@ai-sdk/provider-utils": "3.0.21", + "@ai-sdk/provider-utils": "3.0.22", "@opentelemetry/api": "1.9.0" }, "engines": { @@ -7744,9 +7790,9 @@ "license": "MIT" }, "node_modules/ast-v8-to-istanbul": { - "version": "0.3.11", - "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-0.3.11.tgz", - "integrity": "sha512-Qya9fkoofMjCBNVdWINMjB5KZvkYfaO9/anwkWnjxibpWUxo5iHl2sOdP7/uAqaRuUYuoo8rDwnbaaKVFxoUvw==", + "version": "0.3.12", + "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-0.3.12.tgz", + "integrity": "sha512-BRRC8VRZY2R4Z4lFIL35MwNXmwVqBityvOIwETtsCSwvjl0IdgFsy9NhdaA6j74nUdtJJlIypeRhpDam19Wq3g==", "dev": true, "license": "MIT", "dependencies": { @@ -7831,7 +7877,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, "license": "MIT" }, "node_modules/base64-js": { @@ -8120,9 +8165,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001774", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001774.tgz", - "integrity": "sha512-DDdwPGz99nmIEv216hKSgLD+D4ikHQHjBC/seF98N9CPqRX4M5mSxT9eTV6oyisnJcuzxtZy4n17yKKQYmYQOA==", + "version": "1.0.30001777", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001777.tgz", + "integrity": "sha512-tmN+fJxroPndC74efCdp12j+0rk0RHwV5Jwa1zWaFVyw2ZxAuPeG8ZgWC3Wz7uSjT3qMRQ5XHZ4COgQmsCMJAQ==", "funding": [ { "type": "opencollective", @@ -8260,16 +8305,16 @@ } }, "node_modules/chevrotain": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-11.1.1.tgz", - "integrity": "sha512-f0yv5CPKaFxfsPTBzX7vGuim4oIC1/gcS7LUGdBSwl2dU6+FON6LVUksdOo1qJjoUvXNn45urgh8C+0a24pACQ==", + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-11.1.2.tgz", + "integrity": "sha512-opLQzEVriiH1uUQ4Kctsd49bRoFDXGGSC4GUqj7pGyxM3RehRhvTlZJc1FL/Flew2p5uwxa1tUDWKzI4wNM8pg==", "license": "Apache-2.0", "dependencies": { - "@chevrotain/cst-dts-gen": "11.1.1", - "@chevrotain/gast": "11.1.1", - "@chevrotain/regexp-to-ast": "11.1.1", - "@chevrotain/types": "11.1.1", - "@chevrotain/utils": "11.1.1", + "@chevrotain/cst-dts-gen": "11.1.2", + "@chevrotain/gast": "11.1.2", + "@chevrotain/regexp-to-ast": "11.1.2", + "@chevrotain/types": "11.1.2", + "@chevrotain/utils": "11.1.2", "lodash-es": "4.17.23" } }, @@ -8609,9 +8654,9 @@ } }, "node_modules/cosmiconfig": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", - "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.1.tgz", + "integrity": "sha512-hr4ihw+DBqcvrsEDioRO31Z17x71pUYoNe/4h6Z0wB72p7MU7/9gH8Q3s12NFhHPfYBBOV3qyfUxmr/Yn3shnQ==", "license": "MIT", "dependencies": { "env-paths": "^2.2.1", @@ -9547,10 +9592,13 @@ "license": "MIT" }, "node_modules/dompurify": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.3.1.tgz", - "integrity": "sha512-qkdCKzLNtrgPFP1Vo+98FRzJnBRGe4ffyCea9IwHB1fyxPOeNTHpLKYGd4Uk9xvNoH0ZoOjwZxNptyMwqrId1Q==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.3.2.tgz", + "integrity": "sha512-6obghkliLdmKa56xdbLOpUZ43pAR6xFy1uOrxBaIDjT+yaRuuybLjGS9eVBoSR/UPU5fq3OXClEHLJNGvbxKpQ==", "license": "(MPL-2.0 OR Apache-2.0)", + "engines": { + "node": ">=20" + }, "optionalDependencies": { "@types/trusted-types": "^2.0.7" } @@ -9604,9 +9652,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.302", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.302.tgz", - "integrity": "sha512-sM6HAN2LyK82IyPBpznDRqlTQAtuSaO+ShzFiWTvoMJLHyZ+Y39r8VMfHzwbU8MVBzQ4Wdn85+wlZl2TLGIlwg==", + "version": "1.5.307", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.307.tgz", + "integrity": "sha512-5z3uFKBWjiNR44nFcYdkcXjKMbg5KXNdciu7mhTPo9tB7NbqSNP2sSnGR+fqknZSCwKkBN+oxiiajWs4dT6ORg==", "dev": true, "license": "ISC" }, @@ -9671,9 +9719,9 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.19.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.19.0.tgz", - "integrity": "sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg==", + "version": "5.20.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.20.0.tgz", + "integrity": "sha512-/ce7+jQ1PQ6rVXwe+jKEg5hW5ciicHwIQUagZkp6IufBoY3YDgdTTY1azVs0qoRgVmvsNB+rbjLJxDAeHHtwsQ==", "dev": true, "license": "MIT", "dependencies": { @@ -10863,9 +10911,9 @@ "license": "MIT" }, "node_modules/fast-xml-parser": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.4.1.tgz", - "integrity": "sha512-BQ30U1mKkvXQXXkAGcuyUA/GA26oEB7NzOtsxCDtyu62sjGw5QraKFhx2Em3WQNjPw9PG6MQ9yuIIgkSDfGu5A==", + "version": "5.4.2", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.4.2.tgz", + "integrity": "sha512-pw/6pIl4k0CSpElPEJhDppLzaixDEuWui2CUQQBH/ECDf7+y6YwA4Gf7Tyb0Rfe4DIMuZipYj4AEL0nACKglvQ==", "funding": [ { "type": "github", @@ -10984,9 +11032,9 @@ "license": "Apache-2.0" }, "node_modules/flatted": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", - "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.4.tgz", + "integrity": "sha512-3+mMldrTAPdta5kjX2G2J7iX4zxtnwpdA8Tr2ZSjkyPSanvbZAcy6flmtnXbEybHrDcU9641lxrMfFuUxVz9vA==", "dev": true, "license": "ISC" }, @@ -11362,6 +11410,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-4.0.0.tgz", "integrity": "sha512-ICsMM1Wk8xSGMowkOmPrzo2Fgmfo4bMHLNX6ytHjajRJUqvHOw/TFapQ+QG75c3X/tTDDhOSRPGC52dDbNM8FQ==", + "deprecated": "This package is no longer maintained. For the JavaScript API, please use @conventional-changelog/git-client instead.", "license": "MIT", "dependencies": { "dargs": "^8.0.0", @@ -11426,34 +11475,22 @@ "license": "BSD-2-Clause", "peer": true }, - "node_modules/glob/node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", - "license": "MIT", - "engines": { - "node": "18 || 20 || >=22" - } - }, "node_modules/glob/node_modules/brace-expansion": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.3.tgz", - "integrity": "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "license": "MIT", "dependencies": { - "balanced-match": "^4.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" + "balanced-match": "^1.0.0" } }, "node_modules/glob/node_modules/minimatch": { - "version": "9.0.7", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.7.tgz", - "integrity": "sha512-MOwgjc8tfrpn5QQEvjijjmDVtMw2oL88ugTevzxQnzRLm6l3fVEF2gzU0kYeYYKD8C66+IdGX6peJ4MyUlUnPg==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "license": "ISC", "dependencies": { - "brace-expansion": "^5.0.2" + "brace-expansion": "^2.0.2" }, "engines": { "node": ">=16 || 14 >=14.17" @@ -12176,13 +12213,13 @@ } }, "node_modules/ioredis": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.9.3.tgz", - "integrity": "sha512-VI5tMCdeoxZWU5vjHWsiE/Su76JGhBvWF1MJnV9ZtGltHk9BmD48oDq8Tj8haZ85aceXZMxLNDQZRVo5QKNgXA==", + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.10.0.tgz", + "integrity": "sha512-HVBe9OFuqs+Z6n64q09PQvP1/R4Bm+30PAyyD4wIEqssh3v9L21QjCVk4kRLucMBcDokJTcLjsGeVRlq/nH6DA==", "license": "MIT", "peer": true, "dependencies": { - "@ioredis/commands": "1.5.0", + "@ioredis/commands": "1.5.1", "cluster-key-slot": "^1.1.0", "debug": "^4.3.4", "denque": "^2.1.0", @@ -13163,9 +13200,9 @@ } }, "node_modules/katex": { - "version": "0.16.33", - "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.33.tgz", - "integrity": "sha512-q3N5u+1sY9Bu7T4nlXoiRBXWfwSefNGoKeOwekV+gw0cAXQlz2Ww6BLcmBxVDeXBMUDQv6fK5bcNaJLxob3ZQA==", + "version": "0.16.35", + "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.35.tgz", + "integrity": "sha512-S0+riEvy1CK4VKse1ivMff8gmabe/prY7sKB3njjhyoLLsNFDQYtKNgXrbWUggGDCJBz7Fctl5i8fLCESHXzSg==", "funding": [ "https://opencollective.com/katex", "https://github.com/sponsors/katex" @@ -14944,9 +14981,9 @@ } }, "node_modules/minimatch": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.4.tgz", - "integrity": "sha512-twmL+S8+7yIsE9wsqgzU3E8/LumN3M3QELrBZ20OdmQ9jB2JvW5oZtBEmft84k/Gs5CG9mqtWc6Y9vW+JEzGxw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "license": "ISC", "dependencies": { @@ -14982,24 +15019,24 @@ "peer": true }, "node_modules/mlly": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.0.tgz", - "integrity": "sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.1.tgz", + "integrity": "sha512-SnL6sNutTwRWWR/vcmCYHSADjiEesp5TGQQ0pXyLhW5IoeibRlF/CbSLailbB3CNqJUk9cVJ9dUDnbD7GrcHBQ==", "license": "MIT", "dependencies": { - "acorn": "^8.15.0", + "acorn": "^8.16.0", "pathe": "^2.0.3", "pkg-types": "^1.3.1", - "ufo": "^1.6.1" + "ufo": "^1.6.3" } }, "node_modules/motion": { - "version": "12.34.3", - "resolved": "https://registry.npmjs.org/motion/-/motion-12.34.3.tgz", - "integrity": "sha512-xZIkBGO7v/Uvm+EyaqYd+9IpXu0sZqLywVlGdCFrrMiaO9JI4Kx51mO9KlHSWwll+gZUVY5OJsWgYI5FywJ/tw==", + "version": "12.35.0", + "resolved": "https://registry.npmjs.org/motion/-/motion-12.35.0.tgz", + "integrity": "sha512-BQUhNUIGvUcwXCzwmnT1JpjUqab34lIwxHnXUyWRht1WC1vAyp7/4qgMiUXxN3K6hgUhyoR+HNnLeQMwUZjVjw==", "license": "MIT", "dependencies": { - "framer-motion": "^12.34.3", + "framer-motion": "^12.35.0", "tslib": "^2.4.0" }, "peerDependencies": { @@ -15035,12 +15072,12 @@ "license": "MIT" }, "node_modules/motion/node_modules/framer-motion": { - "version": "12.34.3", - "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.34.3.tgz", - "integrity": "sha512-v81ecyZKYO/DfpTwHivqkxSUBzvceOpoI+wLfgCgoUIKxlFKEXdg0oR9imxwXumT4SFy8vRk9xzJ5l3/Du/55Q==", + "version": "12.35.0", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.35.0.tgz", + "integrity": "sha512-w8hghCMQ4oq10j6aZh3U2yeEQv5K69O/seDI/41PK4HtgkLrcBovUNc0ayBC3UyyU7V1mrY2yLzvYdWJX9pGZQ==", "license": "MIT", "dependencies": { - "motion-dom": "^12.34.3", + "motion-dom": "^12.35.0", "motion-utils": "^12.29.2", "tslib": "^2.4.0" }, @@ -15062,9 +15099,9 @@ } }, "node_modules/motion/node_modules/motion-dom": { - "version": "12.34.3", - "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.34.3.tgz", - "integrity": "sha512-sYgFe+pR9aIM7o4fhs2aXtOI+oqlUd33N9Yoxcgo1Fv7M20sRkHtCmzE/VRNIcq7uNJ+qio+Xubt1FXH3pQ+eQ==", + "version": "12.35.0", + "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.35.0.tgz", + "integrity": "sha512-FFMLEnIejK/zDABn+vqGVAUN4T0+3fw+cVAY8MMT65yR+j5uMuvWdd4npACWhh94OVWQs79CrBBuwOwGRZAQiA==", "license": "MIT", "dependencies": { "motion-utils": "^12.29.2" @@ -15365,9 +15402,9 @@ } }, "node_modules/node-releases": { - "version": "2.0.27", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", - "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", + "version": "2.0.36", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.36.tgz", + "integrity": "sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==", "dev": true, "license": "MIT" }, @@ -15605,21 +15642,21 @@ } }, "node_modules/onnxruntime-common": { - "version": "1.24.2", - "resolved": "https://registry.npmjs.org/onnxruntime-common/-/onnxruntime-common-1.24.2.tgz", - "integrity": "sha512-S0FFhJaI05jr1c3HVJ/DuPFB/aYdXmnUBuuQfuvLtcNn7WAfpm2ewSXn1vHs9Wa1l8T8OznhfCEdFv8qCn0/xw==", + "version": "1.24.3", + "resolved": "https://registry.npmjs.org/onnxruntime-common/-/onnxruntime-common-1.24.3.tgz", + "integrity": "sha512-GeuPZO6U/LBJXvwdaqHbuUmoXiEdeCjWi/EG7Y1HNnDwJYuk6WUbNXpF6luSUY8yASul3cmUlLGrCCL1ZgVXqA==", "license": "MIT" }, "node_modules/onnxruntime-web": { - "version": "1.24.2", - "resolved": "https://registry.npmjs.org/onnxruntime-web/-/onnxruntime-web-1.24.2.tgz", - "integrity": "sha512-L0vyau30A5reN/eBY/NsaJh0VTpu6Xc/c7y//S6wjU0p82CiaiYYktobDknZus8B6cQCMfufwgHCEHYxr2JQsA==", + "version": "1.24.3", + "resolved": "https://registry.npmjs.org/onnxruntime-web/-/onnxruntime-web-1.24.3.tgz", + "integrity": "sha512-41dDq7fxtTm0XzGE7N0d6m8FcOY8EWtUA65GkOixJPB/G7DGzBmiDAnVVXHznRw9bgUZpb+4/1lQK/PNxGpbrQ==", "license": "MIT", "dependencies": { "flatbuffers": "^25.1.24", "guid-typescript": "^1.0.9", "long": "^5.2.3", - "onnxruntime-common": "1.24.2", + "onnxruntime-common": "1.24.3", "platform": "^1.3.6", "protobufjs": "^7.2.4" } @@ -16085,9 +16122,9 @@ } }, "node_modules/postcss": { - "version": "8.5.6", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", - "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", + "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", "dev": true, "funding": [ { @@ -16284,9 +16321,9 @@ } }, "node_modules/pump": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", - "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz", + "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==", "license": "MIT", "dependencies": { "end-of-stream": "^1.1.0", @@ -16521,17 +16558,6 @@ } } }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, "node_modules/raw-loader": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/raw-loader/-/raw-loader-4.0.2.tgz", @@ -17597,17 +17623,6 @@ "node": ">=10" } }, - "node_modules/serialize-javascript": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", - "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", - "dev": true, - "license": "BSD-3-Clause", - "peer": true, - "dependencies": { - "randombytes": "^2.1.0" - } - }, "node_modules/set-function-length": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", @@ -18192,12 +18207,12 @@ } }, "node_modules/string-width/node_modules/strip-ansi": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", - "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", "license": "MIT", "dependencies": { - "ansi-regex": "^6.0.1" + "ansi-regex": "^6.2.2" }, "engines": { "node": ">=12" @@ -18413,9 +18428,9 @@ "license": "MIT" }, "node_modules/strnum": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.1.2.tgz", - "integrity": "sha512-l63NF9y/cLROq/yqKXSLtcMeeyOfnSQlfMSlzFt/K73oIaD8DGaQWd7Z34X9GPiKqP5rbSh84Hl4bOlLcjiSrQ==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.2.0.tgz", + "integrity": "sha512-Y7Bj8XyJxnPAORMZj/xltsfo55uOiyHcU2tnAVzHUnSJR/KsEX+9RoDeXEnsXtl/CX4fAcrt64gZ13aGaWPeBg==", "funding": [ { "type": "github", @@ -18507,9 +18522,9 @@ } }, "node_modules/swr": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/swr/-/swr-2.4.0.tgz", - "integrity": "sha512-sUlC20T8EOt1pHmDiqueUWMmRRX03W7w5YxovWX7VR2KHEPCTMly85x05vpkP5i6Bu4h44ePSMD9Tc+G2MItFw==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/swr/-/swr-2.4.1.tgz", + "integrity": "sha512-2CC6CiKQtEwaEeNiqWTAw9PGykW8SR5zZX8MZk6TeAvEAnVS7Visz8WzphqgtQ8v2xz/4Q5K+j+SeMaKXeeQIA==", "license": "MIT", "dependencies": { "dequal": "^2.0.3", @@ -18616,9 +18631,9 @@ } }, "node_modules/terser-webpack-plugin": { - "version": "5.3.16", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.16.tgz", - "integrity": "sha512-h9oBFCWrq78NyWWVcSwZarJkZ01c2AyGrzs1crmHZO3QUg9D61Wu4NPjBy69n7JqylFF5y+CsUZYmYEIZ3mR+Q==", + "version": "5.3.17", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.17.tgz", + "integrity": "sha512-YR7PtUp6GMU91BgSJmlaX/rS2lGDbAF7D+Wtq7hRO+MiljNmodYvqslzCFiYVAgW+Qoaaia/QUIP4lGXufjdZw==", "dev": true, "license": "MIT", "peer": true, @@ -18626,7 +18641,6 @@ "@jridgewell/trace-mapping": "^0.3.25", "jest-worker": "^27.4.5", "schema-utils": "^4.3.0", - "serialize-javascript": "^6.0.2", "terser": "^5.31.1" }, "engines": { @@ -18706,9 +18720,9 @@ } }, "node_modules/test-exclude/node_modules/brace-expansion": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.3.tgz", - "integrity": "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", + "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", "dev": true, "license": "MIT", "dependencies": { @@ -18740,14 +18754,31 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/test-exclude/node_modules/glob/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/test-exclude/node_modules/glob/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, "node_modules/test-exclude/node_modules/glob/node_modules/minimatch": { - "version": "9.0.7", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.7.tgz", - "integrity": "sha512-MOwgjc8tfrpn5QQEvjijjmDVtMw2oL88ugTevzxQnzRLm6l3fVEF2gzU0kYeYYKD8C66+IdGX6peJ4MyUlUnPg==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "dev": true, "license": "ISC", "dependencies": { - "brace-expansion": "^5.0.2" + "brace-expansion": "^2.0.2" }, "engines": { "node": ">=16 || 14 >=14.17" @@ -18773,9 +18804,9 @@ } }, "node_modules/test-exclude/node_modules/minimatch": { - "version": "10.2.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.3.tgz", - "integrity": "sha512-Rwi3pnapEqirPSbWbrZaa6N3nmqq4Xer/2XooiOKyV3q12ML06f7MOuc5DVH8ONZIFhwIYQ3yzPH4nt7iWHaTg==", + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { @@ -20569,9 +20600,9 @@ } }, "node_modules/webpack": { - "version": "5.105.2", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.105.2.tgz", - "integrity": "sha512-dRXm0a2qcHPUBEzVk8uph0xWSjV/xZxenQQbLwnwP7caQCYpqG1qddwlyEkIDkYn0K8tvmcrZ+bOrzoQ3HxCDw==", + "version": "5.105.4", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.105.4.tgz", + "integrity": "sha512-jTywjboN9aHxFlToqb0K0Zs9SbBoW4zRUlGzI2tYNxVYcEi/IPpn+Xi4ye5jTLvX2YeLuic/IvxNot+Q1jMoOw==", "dev": true, "license": "MIT", "peer": true, @@ -20582,11 +20613,11 @@ "@webassemblyjs/ast": "^1.14.1", "@webassemblyjs/wasm-edit": "^1.14.1", "@webassemblyjs/wasm-parser": "^1.14.1", - "acorn": "^8.15.0", + "acorn": "^8.16.0", "acorn-import-phases": "^1.0.3", "browserslist": "^4.28.1", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.19.0", + "enhanced-resolve": "^5.20.0", "es-module-lexer": "^2.0.0", "eslint-scope": "5.1.1", "events": "^3.2.0", @@ -20598,9 +20629,9 @@ "neo-async": "^2.6.2", "schema-utils": "^4.3.3", "tapable": "^2.3.0", - "terser-webpack-plugin": "^5.3.16", + "terser-webpack-plugin": "^5.3.17", "watchpack": "^2.5.1", - "webpack-sources": "^3.3.3" + "webpack-sources": "^3.3.4" }, "bin": { "webpack": "bin/webpack.js" @@ -20966,12 +20997,12 @@ } }, "node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", - "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", "license": "MIT", "dependencies": { - "ansi-regex": "^6.0.1" + "ansi-regex": "^6.2.2" }, "engines": { "node": ">=12" diff --git a/code/package.json b/code/package.json index dda0e94f..9547d85e 100644 --- a/code/package.json +++ b/code/package.json @@ -42,9 +42,11 @@ "@commitlint/config-conventional": "19.2.2", "@google/genai": "^1.30.0", "@hookform/resolvers": "^4.1.3", - "@inditextech/weave-react": "2.23.0", - "@inditextech/weave-store-azure-web-pubsub": "2.23.0", - "@inditextech/weave-store-standalone": "2.23.0", + "@inditextech/weave-react": "3.1.0", + "@inditextech/weave-renderer-konva-base": "3.1.0", + "@inditextech/weave-renderer-konva-react-reconciler": "3.1.0", + "@inditextech/weave-store-azure-web-pubsub": "3.1.0", + "@inditextech/weave-store-standalone": "3.1.0", "@next/env": "^15.2.1", "@openrouter/ai-sdk-provider": "^1.2.5", "@radix-ui/react-accordion": "^1.2.10", diff --git a/code/public/fonts/ARIAL.TTF b/code/public/fonts/ARIAL.TTF new file mode 100644 index 00000000..8682d946 Binary files /dev/null and b/code/public/fonts/ARIAL.TTF differ diff --git a/code/public/fonts/ARIALBD.TTF b/code/public/fonts/ARIALBD.TTF new file mode 100644 index 00000000..a6037e68 Binary files /dev/null and b/code/public/fonts/ARIALBD.TTF differ diff --git a/code/public/fonts/ARIALBI.TTF b/code/public/fonts/ARIALBI.TTF new file mode 100644 index 00000000..6a1fa0fa Binary files /dev/null and b/code/public/fonts/ARIALBI.TTF differ diff --git a/code/public/fonts/ARIALI.TTF b/code/public/fonts/ARIALI.TTF new file mode 100644 index 00000000..38019978 Binary files /dev/null and b/code/public/fonts/ARIALI.TTF differ diff --git a/code/public/fonts/FuzzyBubbles-Bold.ttf b/code/public/fonts/FuzzyBubbles-Bold.ttf new file mode 100644 index 00000000..627055fa Binary files /dev/null and b/code/public/fonts/FuzzyBubbles-Bold.ttf differ diff --git a/code/public/fonts/FuzzyBubbles-Regular.ttf b/code/public/fonts/FuzzyBubbles-Regular.ttf new file mode 100644 index 00000000..f3bea8f5 Binary files /dev/null and b/code/public/fonts/FuzzyBubbles-Regular.ttf differ diff --git a/code/public/fonts/NotoSansMono-Bold.ttf b/code/public/fonts/NotoSansMono-Bold.ttf new file mode 100644 index 00000000..c56c765c Binary files /dev/null and b/code/public/fonts/NotoSansMono-Bold.ttf differ diff --git a/code/public/fonts/RobotoMono-Bold.ttf b/code/public/fonts/RobotoMono-Bold.ttf new file mode 100644 index 00000000..bef439f3 Binary files /dev/null and b/code/public/fonts/RobotoMono-Bold.ttf differ diff --git a/code/public/fonts/RobotoMono-BoldItalic.ttf b/code/public/fonts/RobotoMono-BoldItalic.ttf new file mode 100644 index 00000000..642dd058 Binary files /dev/null and b/code/public/fonts/RobotoMono-BoldItalic.ttf differ diff --git a/code/public/fonts/RobotoMono-Italic.ttf b/code/public/fonts/RobotoMono-Italic.ttf new file mode 100644 index 00000000..781eff8c Binary files /dev/null and b/code/public/fonts/RobotoMono-Italic.ttf differ diff --git a/code/public/fonts/RobotoMono-Regular.ttf b/code/public/fonts/RobotoMono-Regular.ttf new file mode 100644 index 00000000..3806bfb1 Binary files /dev/null and b/code/public/fonts/RobotoMono-Regular.ttf differ diff --git a/code/public/fonts/SpecialGothicCondensedOne-Regular.ttf b/code/public/fonts/SpecialGothicCondensedOne-Regular.ttf new file mode 100644 index 00000000..ea760aab Binary files /dev/null and b/code/public/fonts/SpecialGothicCondensedOne-Regular.ttf differ diff --git a/code/store/store.ts b/code/store/store.ts index 764a4276..31bad014 100644 --- a/code/store/store.ts +++ b/code/store/store.ts @@ -6,7 +6,7 @@ import Konva from "konva"; import { Vector2d } from "konva/lib/types"; import { create } from "zustand"; import { ContextMenuOption } from "@/components/room-components/context-menu"; -import { WeaveElementAttributes } from "@inditextech/weave-types"; +import { WeaveElementAttributes, WeaveFont } from "@inditextech/weave-types"; import { DRAWER_ELEMENTS, SIDEBAR_ELEMENTS } from "@/lib/constants"; import { merge } from "lodash"; @@ -40,6 +40,8 @@ export type TransformingOperation = type FinishUploadCallback = (imageURL: string) => void; +type ViewType = "fixed" | "floating"; + type DrawerKeyKeys = keyof typeof DRAWER_ELEMENTS; export type DrawerKey = (typeof DRAWER_ELEMENTS)[DrawerKeyKeys]; @@ -47,6 +49,7 @@ type SidebarActiveKeys = keyof typeof SIDEBAR_ELEMENTS; export type SidebarActive = (typeof SIDEBAR_ELEMENTS)[SidebarActiveKeys] | null; interface CollaborationRoomState { + viewType: ViewType; backgroundColor: BackgroundColor; configuration: { open: boolean; @@ -74,7 +77,7 @@ interface CollaborationRoomState { fonts: { loaded: boolean; // eslint-disable-next-line @typescript-eslint/no-explicit-any - values: { id: string; name: string }[]; + values: WeaveFont[]; }; ui: { show: boolean; @@ -221,6 +224,7 @@ interface CollaborationRoomState { setFramesExportVisible: (newVisible: boolean) => void; setFramesExporting: (newExporting: boolean) => void; setFramesPages: (newPages: { title: string; nodes: string[] }[]) => void; + setViewType: (newView: ViewType) => void; } export const useCollaborationRoom = create()((set) => { @@ -247,6 +251,7 @@ export const useCollaborationRoom = create()((set) => { ); return { + viewType: "floating", backgroundColor: BACKGROUND_COLOR.GRAY, measurement: { units: "cms", @@ -277,7 +282,7 @@ export const useCollaborationRoom = create()((set) => { room: undefined, sidebar: { previouslyActive: null, - active: SIDEBAR_ELEMENTS.nodesTree, + active: SIDEBAR_ELEMENTS.nodeProperties, }, fonts: { loaded: false, @@ -703,5 +708,10 @@ export const useCollaborationRoom = create()((set) => { pages: newPages, }, })), + setViewType: (newView) => + set((state) => ({ + ...state, + viewType: newView, + })), }; }); diff --git a/code/weave.d.ts b/code/weave.d.ts index 2418c530..0ef526ff 100644 --- a/code/weave.d.ts +++ b/code/weave.d.ts @@ -46,11 +46,6 @@ declare global { weave: Weave; weaveOnFieldFocus?: boolean; weaveTextEditing?: Record; - weaveDragImageURL?: string; - weaveDragImageId?: string; - weaveDragVideoParams?: WeaveVideoToolDragParams; - weaveDragVideoId?: string; - weaveDragTemplateData?: WeaveTemplateDragParams; colorTokenDragColor?: string; } }