diff --git a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs index cb45bee2..bab86fab 100644 --- a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs +++ b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs @@ -321,7 +321,6 @@ impl NodeGraphMessageHandler { disabled: network.disabled.contains(id), }) } - log::debug!("Frontend Nodes:\n{:#?}\n\nLinks:\n{:#?}", nodes, links); responses.push_back(FrontendMessage::UpdateNodeGraph { nodes, links }.into()); } @@ -423,7 +422,6 @@ impl MessageHandler { - log::debug!("Connect primary output from node {output_node} to input of index {input_node_connector_index} on node {input_node}."); let node_id = input_node; let Some(network) = self.get_active_network(document) else { diff --git a/frontend-svelte/src/components/floating-menus/DialogModal.svelte b/frontend-svelte/src/components/floating-menus/DialogModal.svelte index 3dc5b797..23bf9b01 100644 --- a/frontend-svelte/src/components/floating-menus/DialogModal.svelte +++ b/frontend-svelte/src/components/floating-menus/DialogModal.svelte @@ -11,7 +11,7 @@ const dialog = getContext("dialog"); - let dialogModal: FloatingMenu; + let self: FloatingMenu; export function dismiss() { dialog.dismissDialog(); @@ -19,12 +19,12 @@ onMount(() => { // Focus the first button in the popup - const emphasizedOrFirstButton = (dialogModal.div().querySelector("[data-emphasized]") || dialogModal.div().querySelector("[data-text-button]") || undefined) as HTMLButtonElement | undefined; + const emphasizedOrFirstButton = (self.div().querySelector("[data-emphasized]") || self.div().querySelector("[data-text-button]") || undefined) as HTMLButtonElement | undefined; emphasizedOrFirstButton?.focus(); }); - + diff --git a/frontend-svelte/src/components/floating-menus/MenuList.svelte b/frontend-svelte/src/components/floating-menus/MenuList.svelte index d5194876..17ccabec 100644 --- a/frontend-svelte/src/components/floating-menus/MenuList.svelte +++ b/frontend-svelte/src/components/floating-menus/MenuList.svelte @@ -11,7 +11,7 @@ import TextLabel from "@/components/widgets/labels/TextLabel.svelte"; import UserInputLabel from "@/components/widgets/labels/UserInputLabel.svelte"; - let floatingMenu: FloatingMenu; + let self: FloatingMenu; let scroller: LayoutCol; // emits: ["update:open", "update:activeEntry", "naturalWidth"], @@ -35,8 +35,8 @@ // Called only when `open` is changed from outside this component (with v-model) $: watchOpen(open); $: dispatch("open", isOpen); - $: watchEntries(entries, floatingMenu); - $: watchDrawIcon(drawIcon, floatingMenu); + $: watchEntries(entries, self); + $: watchDrawIcon(drawIcon, self); $: virtualScrollingTotalHeight = entries.length === 0 ? 0 : entries[0].length * virtualScrollingEntryHeight; $: virtualScrollingStartIndex = Math.floor(virtualScrollingEntriesStart / virtualScrollingEntryHeight) || 0; $: virtualScrollingEndIndex = entries.length === 0 ? 0 : Math.min(entries[0].length, virtualScrollingStartIndex + 1 + 400 / virtualScrollingEntryHeight); @@ -48,12 +48,12 @@ // TODO: Svelte: fix infinite loop and reenable function watchEntries(_: MenuListEntry[][], floatingMenu: FloatingMenu) { - // floatingMenu?.measureAndEmitNaturalWidth(); + // floatingMenu?.div().measureAndEmitNaturalWidth(); } // TODO: Svelte: fix infinite loop and reenable function watchDrawIcon(_: boolean, floatingMenu: FloatingMenu) { - // floatingMenu?.measureAndEmitNaturalWidth(); + // floatingMenu?.div().measureAndEmitNaturalWidth(); } function onScroll(e: Event) { @@ -198,7 +198,7 @@ {direction} {minWidth} scrollableY={scrollableY && virtualScrollingEntryHeight === 0} - bind:this={floatingMenu} + bind:this={self} > diff --git a/frontend-svelte/src/components/layout/FloatingMenu.svelte b/frontend-svelte/src/components/layout/FloatingMenu.svelte index b26307d0..f4ad4c1e 100644 --- a/frontend-svelte/src/components/layout/FloatingMenu.svelte +++ b/frontend-svelte/src/components/layout/FloatingMenu.svelte @@ -132,10 +132,10 @@ // Required to correctly position content when scrolled (it has a `position: fixed` to prevent clipping) // We use `.style` on a ref (instead of a `:style` Vue binding) because the binding causes the `updated()` hook to call the function we're in recursively forever const tailOffset = type === "Popover" ? 10 : 0; - if (direction === "Bottom") floatingMenuContent.style.top = `${tailOffset + floatingMenuBounds.top}px`; - if (direction === "Top") floatingMenuContent.style.bottom = `${tailOffset + floatingMenuBounds.bottom}px`; - if (direction === "Right") floatingMenuContent.style.left = `${tailOffset + floatingMenuBounds.left}px`; - if (direction === "Left") floatingMenuContent.style.right = `${tailOffset + floatingMenuBounds.right}px`; + if (direction === "Bottom") floatingMenuContent.div().style.top = `${tailOffset + floatingMenuBounds.top}px`; + if (direction === "Top") floatingMenuContent.div().style.bottom = `${tailOffset + floatingMenuBounds.bottom}px`; + if (direction === "Right") floatingMenuContent.div().style.left = `${tailOffset + floatingMenuBounds.left}px`; + if (direction === "Left") floatingMenuContent.div().style.right = `${tailOffset + floatingMenuBounds.right}px`; // Required to correctly position tail when scrolled (it has a `position: fixed` to prevent clipping) // We use `.style` on a ref (instead of a `:style` Vue binding) because the binding causes the `updated()` hook to call the function we're in recursively forever @@ -154,11 +154,11 @@ // We use `.style` on a ref (instead of a `:style` Vue binding) because the binding causes the `updated()` hook to call the function we're in recursively forever if (floatingMenuContentBounds.left - windowEdgeMargin <= workspaceBounds.left) { - floatingMenuContent.style.left = `${windowEdgeMargin}px`; + floatingMenuContent.div().style.left = `${windowEdgeMargin}px`; if (workspaceBounds.left + floatingMenuContainerBounds.left === 12) zeroedBorderHorizontal = "Left"; } if (floatingMenuContentBounds.right + windowEdgeMargin >= workspaceBounds.right) { - floatingMenuContent.style.right = `${windowEdgeMargin}px`; + floatingMenuContent.div().style.right = `${windowEdgeMargin}px`; if (workspaceBounds.right - floatingMenuContainerBounds.right === 12) zeroedBorderHorizontal = "Right"; } } @@ -167,11 +167,11 @@ // We use `.style` on a ref (instead of a `:style` Vue binding) because the binding causes the `updated()` hook to call the function we're in recursively forever if (floatingMenuContentBounds.top - windowEdgeMargin <= workspaceBounds.top) { - floatingMenuContent.style.top = `${windowEdgeMargin}px`; + floatingMenuContent.div().style.top = `${windowEdgeMargin}px`; if (workspaceBounds.top + floatingMenuContainerBounds.top === 12) zeroedBorderVertical = "Top"; } if (floatingMenuContentBounds.bottom + windowEdgeMargin >= workspaceBounds.bottom) { - floatingMenuContent.style.bottom = `${windowEdgeMargin}px`; + floatingMenuContent.div().style.bottom = `${windowEdgeMargin}px`; if (workspaceBounds.bottom - floatingMenuContainerBounds.bottom === 12) zeroedBorderVertical = "Bottom"; } } @@ -181,16 +181,16 @@ // We use `.style` on a ref (instead of a `:style` Vue binding) because the binding causes the `updated()` hook to call the function we're in recursively forever switch (`${zeroedBorderVertical}${zeroedBorderHorizontal}`) { case "TopLeft": - floatingMenuContent.style.borderTopLeftRadius = "0"; + floatingMenuContent.div().style.borderTopLeftRadius = "0"; break; case "TopRight": - floatingMenuContent.style.borderTopRightRadius = "0"; + floatingMenuContent.div().style.borderTopRightRadius = "0"; break; case "BottomLeft": - floatingMenuContent.style.borderBottomLeftRadius = "0"; + floatingMenuContent.div().style.borderBottomLeftRadius = "0"; break; case "BottomRight": - floatingMenuContent.style.borderBottomRightRadius = "0"; + floatingMenuContent.div().style.borderBottomRightRadius = "0"; break; default: break; @@ -219,7 +219,7 @@ // Measure the width of the floating menu content element, if it's currently visible // The result will be `undefined` if the menu is invisible, perhaps because an ancestor component is hidden with a falsy `v-if` condition - const naturalWidth: number | undefined = floatingMenuContent?.clientWidth; + const naturalWidth: number | undefined = floatingMenuContent?.div().clientWidth; // Turn off measuring mode for the component, which triggers another call to the `updated()` Vue event, so we can turn off the protection after that has happened measuringOngoing = false; diff --git a/frontend-svelte/src/components/layout/LayoutCol.svelte b/frontend-svelte/src/components/layout/LayoutCol.svelte index 7b3b1e53..e181dfb3 100644 --- a/frontend-svelte/src/components/layout/LayoutCol.svelte +++ b/frontend-svelte/src/components/layout/LayoutCol.svelte @@ -9,7 +9,7 @@ export let scrollableX: boolean = false; export let scrollableY: boolean = false; - let divElement: HTMLDivElement; + let self: HTMLDivElement; $: extraClasses = Object.entries(classes) .flatMap((classAndState) => (classAndState[1] ? [classAndState[0]] : [])) @@ -19,7 +19,7 @@ .join(" "); export function div(): HTMLDivElement { - return divElement; + return self; } @@ -29,21 +29,52 @@ class:scrollable-y={scrollableY} style={`${styleName} ${extraStyles}`.trim() || undefined} title={tooltip} - bind:this={divElement} + bind:this={self} + on:focus + on:blur + on:fullscreenchange + on:fullscreenerror + on:scroll + on:cut + on:copy + on:paste + on:keydown + on:keypress + on:keyup + on:auxclick on:click + on:contextmenu on:dblclick + on:mousedown + on:mouseenter + on:mouseleave + on:mousemove + on:mouseover + on:mouseout + on:mouseup + on:select + on:wheel + on:drag + on:dragend + on:dragenter + on:dragstart + on:dragleave + on:dragover + on:drop + on:touchcancel + on:touchend + on:touchmove + on:touchstart + on:pointerover + on:pointerenter on:pointerdown on:pointermove on:pointerup - on:dragleave - on:dragover - on:dragstart - on:dragend - on:drop - on:wheel - on:scroll - on:focus - on:blur + on:pointercancel + on:pointerout + on:pointerleave + on:gotpointercapture + on:lostpointercapture {...$$restProps} > diff --git a/frontend-svelte/src/components/layout/LayoutRow.svelte b/frontend-svelte/src/components/layout/LayoutRow.svelte index 9624d0a9..9f43e59a 100644 --- a/frontend-svelte/src/components/layout/LayoutRow.svelte +++ b/frontend-svelte/src/components/layout/LayoutRow.svelte @@ -9,7 +9,7 @@ export let scrollableX: boolean = false; export let scrollableY: boolean = false; - let divElement: HTMLDivElement; + let self: HTMLDivElement; $: extraClasses = Object.entries(classes) .flatMap((classAndState) => (classAndState[1] ? [classAndState[0]] : [])) @@ -19,7 +19,7 @@ .join(" "); export function div(): HTMLDivElement { - return divElement; + return self; } @@ -29,21 +29,52 @@ class:scrollable-y={scrollableY} style={`${styleName} ${extraStyles}`.trim() || undefined} title={tooltip} - bind:this={divElement} + bind:this={self} + on:focus + on:blur + on:fullscreenchange + on:fullscreenerror + on:scroll + on:cut + on:copy + on:paste + on:keydown + on:keypress + on:keyup + on:auxclick on:click + on:contextmenu on:dblclick + on:mousedown + on:mouseenter + on:mouseleave + on:mousemove + on:mouseover + on:mouseout + on:mouseup + on:select + on:wheel + on:drag + on:dragend + on:dragenter + on:dragstart + on:dragleave + on:dragover + on:drop + on:touchcancel + on:touchend + on:touchmove + on:touchstart + on:pointerover + on:pointerenter on:pointerdown on:pointermove on:pointerup - on:dragleave - on:dragover - on:dragstart - on:dragend - on:drop - on:wheel - on:scroll - on:focus - on:blur + on:pointercancel + on:pointerout + on:pointerleave + on:gotpointercapture + on:lostpointercapture {...$$restProps} > diff --git a/frontend-svelte/src/components/panels/Document.svelte b/frontend-svelte/src/components/panels/Document.svelte index 52f223b4..a1725447 100644 --- a/frontend-svelte/src/components/panels/Document.svelte +++ b/frontend-svelte/src/components/panels/Document.svelte @@ -28,10 +28,9 @@ import { type Editor } from "@/wasm-communication/editor"; import { type DocumentState } from "@/state-providers/document"; - let self: LayoutCol; let rulerHorizontal: CanvasRuler; let rulerVertical: CanvasRuler; - let canvasDiv: HTMLDivElement; + let canvasContainer: HTMLDivElement; const editor = getContext("editor"); const document = getContext("document"); @@ -116,7 +115,7 @@ function canvasPointerDown(e: PointerEvent) { const onEditbox = e.target instanceof HTMLDivElement && e.target.contentEditable; - if (!onEditbox) canvasDiv?.setPointerCapture(e.pointerId); + if (!onEditbox) canvasContainer?.setPointerCapture(e.pointerId); } // Update rendered SVGs @@ -127,7 +126,7 @@ await tick(); if (textInput) { - const foreignObject = canvasDiv.getElementsByTagName("foreignObject")[0] as SVGForeignObjectElement; + const foreignObject = canvasContainer.getElementsByTagName("foreignObject")[0] as SVGForeignObjectElement; if (foreignObject.children.length > 0) return; const addedInput = foreignObject.appendChild(textInput); @@ -285,8 +284,8 @@ // Resize elements to render the new viewport size export function viewportResize() { // Resize the canvas - canvasSvgWidth = Math.ceil(parseFloat(getComputedStyle(canvasDiv).width)); - canvasSvgHeight = Math.ceil(parseFloat(getComputedStyle(canvasDiv).height)); + canvasSvgWidth = Math.ceil(parseFloat(getComputedStyle(canvasContainer).width)); + canvasSvgHeight = Math.ceil(parseFloat(getComputedStyle(canvasContainer).height)); // Resize the rulers rulerHorizontal?.resize(); @@ -382,7 +381,7 @@ }); - + @@ -422,7 +421,7 @@ y={cursorTop} /> {/if} -
canvasPointerDown(e)} on:dragover={(e) => e.preventDefault()} on:drop={(e) => pasteFile(e)} bind:this={canvasDiv} data-canvas> +
canvasPointerDown(e)} on:dragover={(e) => e.preventDefault()} on:drop={(e) => pasteFile(e)} bind:this={canvasContainer} data-canvas> {@html artboardSvg} diff --git a/frontend-svelte/src/components/panels/LayerTree.svelte b/frontend-svelte/src/components/panels/LayerTree.svelte index 1ef8fd24..0284e683 100644 --- a/frontend-svelte/src/components/panels/LayerTree.svelte +++ b/frontend-svelte/src/components/panels/LayerTree.svelte @@ -109,7 +109,7 @@ await tick(); - const textInput: HTMLInputElement | undefined = list?.querySelector("[data-text-input]:not([disabled])") || undefined; + const textInput = (list?.div().querySelector("[data-text-input]:not([disabled])") || undefined) as HTMLInputElement | undefined; textInput?.select(); } @@ -169,7 +169,7 @@ function calculateDragIndex(tree: LayoutCol, clientY: number, select?: () => void): DraggingData { const treeChildren = tree.div().children; - const treeOffset = tree.getBoundingClientRect().top; + const treeOffset = tree.div().getBoundingClientRect().top; // Closest distance to the middle of the row along the Y axis let closest = Infinity; diff --git a/frontend-svelte/src/components/panels/NodeGraph.svelte b/frontend-svelte/src/components/panels/NodeGraph.svelte index 9e359f2e..2a93f1c1 100644 --- a/frontend-svelte/src/components/panels/NodeGraph.svelte +++ b/frontend-svelte/src/components/panels/NodeGraph.svelte @@ -180,7 +180,7 @@ let zoomFactor = 1 + Math.abs(scrollY) * WHEEL_RATE; if (scrollY > 0) zoomFactor = 1 / zoomFactor; - const { x, y, width, height } = graph.getBoundingClientRect(); + const { x, y, width, height } = graph.div().getBoundingClientRect(); transform.scale *= zoomFactor; @@ -222,7 +222,7 @@ // Handle the add node popup on right click if (e.button === 2) { - const graphBounds = graph.getBoundingClientRect(); + const graphBounds = graph.div().getBoundingClientRect(); nodeListLocation = { x: Math.round(((e.clientX - graphBounds.x) / transform.scale - transform.x) / GRID_SIZE), y: Math.round(((e.clientY - graphBounds.y) / transform.scale - transform.y) / GRID_SIZE), diff --git a/frontend-svelte/src/components/widgets/inputs/FieldInput.svelte b/frontend-svelte/src/components/widgets/inputs/FieldInput.svelte index c0c9ff57..fdf1869d 100644 --- a/frontend-svelte/src/components/widgets/inputs/FieldInput.svelte +++ b/frontend-svelte/src/components/widgets/inputs/FieldInput.svelte @@ -28,7 +28,7 @@ export let sharpRightCorners = false; export let placeholder: string | undefined = undefined; - let input: HTMLInputElement | HTMLTextAreaElement; + let inputOrTextarea: HTMLInputElement | HTMLTextAreaElement; let id = `${Math.random()}`.substring(2); let macKeyboardLayout = platformIsMac(); let inputValue = value; @@ -40,20 +40,28 @@ export function selectAllText(currentText: string) { // Setting the value directly is required to make `input.select()` work // TODO: Svelte: Test if the above message is still true - input.value = currentText; - input.select(); + inputOrTextarea.value = currentText; + inputOrTextarea.select(); + } + + export function focus() { + inputOrTextarea.focus(); } export function unFocus() { - input.blur(); + inputOrTextarea.blur(); } - export function getInputElementValue(): string { - return input.value; + export function getValue(): string { + return inputOrTextarea.value; } export function setInputElementValue(value: string) { - input.value = value; + inputOrTextarea.value = value; + } + + export function element(): HTMLInputElement | HTMLTextAreaElement { + return inputOrTextarea; } @@ -68,7 +76,7 @@ {disabled} {placeholder} bind:value={inputValue} - bind:this={input} + bind:this={inputOrTextarea} on:focus={() => dispatch("textFocused")} on:blur={() => dispatch("textChanged")} on:change={() => dispatch("textChanged")} @@ -85,7 +93,7 @@ {spellcheck} {disabled} bind:value={inputValue} - bind:this={input} + bind:this={inputOrTextarea} on:focus={() => dispatch("textFocused")} on:blur={() => dispatch("textChanged")} on:change={() => dispatch("textChanged")} diff --git a/frontend-svelte/src/components/widgets/inputs/NumberInput.svelte b/frontend-svelte/src/components/widgets/inputs/NumberInput.svelte index aa98efd0..36ca5908 100644 --- a/frontend-svelte/src/components/widgets/inputs/NumberInput.svelte +++ b/frontend-svelte/src/components/widgets/inputs/NumberInput.svelte @@ -51,7 +51,7 @@ export let incrementCallbackIncrease: (() => void) | undefined = undefined; export let incrementCallbackDecrease: (() => void) | undefined = undefined; - let fieldInput: FieldInput; + let self: FieldInput; let text = displayText(value); let editing = false; // Stays in sync with a binding to the actual input range slider element. @@ -127,7 +127,7 @@ function sliderPointerUp() { // User clicked but didn't drag, so we focus the text input element if (rangeSliderClickDragState === "mousedown") { - const inputElement = fieldInput.querySelector("[data-input-element]") as HTMLInputElement | undefined; + const inputElement = self.element().querySelector("[data-input-element]") as HTMLInputElement | undefined; if (!inputElement) return; // Set the slider position back to the original position to undo the user moving it @@ -148,7 +148,7 @@ editing = true; - fieldInput.selectAllText(text); + self.selectAllText(text); } // Called only when `value` is changed from the element via user input and committed, either with the @@ -164,7 +164,7 @@ editing = false; - fieldInput.unFocus(); + self.unFocus(); } function onCancelTextChange() { @@ -172,7 +172,7 @@ editing = false; - fieldInput.unFocus(); + self.unFocus(); } function onIncrement(direction: "Decrease" | "Increase") { @@ -245,7 +245,7 @@ {sharpRightCorners} spellcheck={false} styles={{ "min-width": minWidth > 0 ? `${minWidth}px` : undefined, "--progress-factor": (rangeSliderValueAsRendered - rangeMin) / (rangeMax - rangeMin) }} - bind:this={fieldInput} + bind:this={self} > {#if value !== undefined && mode === "Increment" && incrementBehavior !== "None"}