diff --git a/js/preview/host.js b/js/preview/host.js index c78ed50..78c4b6d 100644 --- a/js/preview/host.js +++ b/js/preview/host.js @@ -467,6 +467,7 @@ function registerImageOpsLivePreview() { startLoopIfVideo(node); } for (const w of node.widgets ?? []) { + if (typeof w.callback !== "function" && typeof w.callback !== "undefined") continue; const orig = w.callback; w.callback = function() { const r = orig?.apply(this, arguments); @@ -575,12 +576,15 @@ function registerImageOpsLivePreview() { app.registerExtension({ name: EXT_NAME, async beforeRegisterNodeDef(nodeType, _nodeData) { - nodeType.prototype.onNodeCreated = /* @__PURE__ */ (function(orig) { - return function() { - orig?.apply(this, arguments); - hookNode(this); - }; - })(nodeType.prototype.onNodeCreated); + const origOnNodeCreated = nodeType.prototype.onNodeCreated; + nodeType.prototype.onNodeCreated = function() { + origOnNodeCreated?.apply(this, arguments); + hookNode(this); + }; + }, + // Node 2.0 fallback: called per-instance after the node is fully constructed. + nodeCreated(node) { + hookNode(node); } }); } diff --git a/js/preview/interactions/draw.js b/js/preview/interactions/draw.js index df912ec..a87f2bb 100644 --- a/js/preview/interactions/draw.js +++ b/js/preview/interactions/draw.js @@ -131,13 +131,17 @@ function attachInteractions(node, ctx) { st.drawPressureSizeInput?.addEventListener("change", syncDrawDynamics); st.drawPressureOpacityInput?.addEventListener("change", syncDrawDynamics); st.drawTiltSizeInput?.addEventListener("change", syncDrawDynamics); - canvas.addEventListener("wheel", (event) => { + const handleDrawWheel = (event) => { + const target = event.target; + if (target !== canvas && !canvas.contains(target)) return; if (!st.drawGeometry) return; if (event.ctrlKey || event.metaKey) { + event.stopImmediatePropagation(); event.preventDefault(); const rect = canvas.getBoundingClientRect(); - const sx = canvas.width / Math.max(1, rect.width); - const sy = canvas.height / Math.max(1, rect.height); + if (rect.width < 1 || rect.height < 1) return; + const sx = canvas.width / rect.width; + const sy = canvas.height / rect.height; const mx = (event.clientX - rect.left) * sx - canvas.width / 2; const my = (event.clientY - rect.top) * sy - canvas.height / 2; const factor = event.deltaY < 0 ? 1.15 : 1 / 1.15; @@ -153,13 +157,15 @@ function attachInteractions(node, ctx) { const point = getCanvasPointer(canvas, event); const hover = canvasToSource(point.x, point.y); if (!hover.inside) return; + event.stopImmediatePropagation(); event.preventDefault(); const current = widgetNumber(node, "brush_size", 10); const step = event.shiftKey ? 8 : 2; const direction = event.deltaY > 0 ? -step : step; ctx.setDrawBrushSize(node, current + direction); void ctx.renderDrawNode(node, 0); - }, { passive: false }); + }; + document.addEventListener("wheel", handleDrawWheel, { capture: true, passive: false }); canvas.addEventListener("keydown", (event) => { if (!(event.ctrlKey || event.metaKey) || event.key.toLowerCase() !== "z") return; event.preventDefault(); @@ -186,8 +192,9 @@ function attachInteractions(node, ctx) { } catch { } const rect = canvas.getBoundingClientRect(); - const sx = canvas.width / Math.max(1, rect.width); - const sy = canvas.height / Math.max(1, rect.height); + if (rect.width < 1 || rect.height < 1) return; + const sx = canvas.width / rect.width; + const sy = canvas.height / rect.height; ctrlPanDrag = { pointerId: event.pointerId, startCanvasX: (event.clientX - rect.left) * sx, @@ -235,8 +242,9 @@ function attachInteractions(node, ctx) { canvas.addEventListener("pointermove", (event) => { if (ctrlPanDrag && ctrlPanDrag.pointerId === event.pointerId) { const rect = canvas.getBoundingClientRect(); - const sx = canvas.width / Math.max(1, rect.width); - const sy = canvas.height / Math.max(1, rect.height); + if (rect.width < 1 || rect.height < 1) return; + const sx = canvas.width / rect.width; + const sy = canvas.height / rect.height; const cx = (event.clientX - rect.left) * sx; const cy = (event.clientY - rect.top) * sy; st.previewPanX = ctrlPanDrag.startPanX + (cx - ctrlPanDrag.startCanvasX); diff --git a/js/preview/shared/geometry.js b/js/preview/shared/geometry.js index b3a4125..98e1950 100644 --- a/js/preview/shared/geometry.js +++ b/js/preview/shared/geometry.js @@ -40,8 +40,9 @@ function drawOutputFormatBox(ctx, fit, label = "Output") { } function getCanvasPointer(canvas, event) { const rect = canvas.getBoundingClientRect(); - const scaleX = canvas.width / Math.max(1, rect.width); - const scaleY = canvas.height / Math.max(1, rect.height); + if (rect.width < 1 || rect.height < 1) return { x: 0, y: 0 }; + const scaleX = canvas.width / rect.width; + const scaleY = canvas.height / rect.height; return { x: (event.clientX - rect.left) * scaleX, y: (event.clientY - rect.top) * scaleY diff --git a/js/preview/shared/navigation.js b/js/preview/shared/navigation.js index 0f430d1..2b55428 100644 --- a/js/preview/shared/navigation.js +++ b/js/preview/shared/navigation.js @@ -15,31 +15,35 @@ function attachPreviewNavigation(node, canvasSize) { if (!st.previewLastSource) return; blit(node, st, st.previewLastSource, canvasSize); }; + const safeRect = () => { + const rect = canvas.getBoundingClientRect(); + if (rect.width < 1 || rect.height < 1) return null; + return { rect, sx: canvas.width / rect.width, sy: canvas.height / rect.height }; + }; canvas.addEventListener("pointerdown", (event) => { if (event.button !== 1) return; event.preventDefault(); + event.stopPropagation(); try { canvas.setPointerCapture(event.pointerId); } catch { } - const rect = canvas.getBoundingClientRect(); - const sx = canvas.width / Math.max(1, rect.width); - const sy = canvas.height / Math.max(1, rect.height); + const r = safeRect(); + if (!r) return; st.previewPanDrag = { pointerId: event.pointerId, - startCanvasX: (event.clientX - rect.left) * sx, - startCanvasY: (event.clientY - rect.top) * sy, + startCanvasX: (event.clientX - r.rect.left) * r.sx, + startCanvasY: (event.clientY - r.rect.top) * r.sy, startPanX: st.previewPanX, startPanY: st.previewPanY }; }); canvas.addEventListener("pointermove", (event) => { if (!st.previewPanDrag || st.previewPanDrag.pointerId !== event.pointerId) return; - const rect = canvas.getBoundingClientRect(); - const sx = canvas.width / Math.max(1, rect.width); - const sy = canvas.height / Math.max(1, rect.height); - const cx = (event.clientX - rect.left) * sx; - const cy = (event.clientY - rect.top) * sy; + const r = safeRect(); + if (!r) return; + const cx = (event.clientX - r.rect.left) * r.sx; + const cy = (event.clientY - r.rect.top) * r.sy; st.previewPanX = st.previewPanDrag.startPanX + (cx - st.previewPanDrag.startCanvasX); st.previewPanY = st.previewPanDrag.startPanY + (cy - st.previewPanDrag.startCanvasY); reblitNow(); @@ -58,14 +62,16 @@ function attachPreviewNavigation(node, canvasSize) { st.previewPanDrag = null; } }); - canvas.addEventListener("wheel", (event) => { - if (isInteractiveNode(node)) return; + const handleWheel = (event) => { + const target = event.target; + if (target !== canvas && !canvas.contains(target)) return; + event.stopImmediatePropagation(); event.preventDefault(); - const rect = canvas.getBoundingClientRect(); - const sx = canvas.width / Math.max(1, rect.width); - const sy = canvas.height / Math.max(1, rect.height); - const mx = (event.clientX - rect.left) * sx - canvas.width / 2; - const my = (event.clientY - rect.top) * sy - canvas.height / 2; + if (isInteractiveNode(node)) return; + const r = safeRect(); + if (!r) return; + const mx = (event.clientX - r.rect.left) * r.sx - canvas.width / 2; + const my = (event.clientY - r.rect.top) * r.sy - canvas.height / 2; const factor = event.deltaY < 0 ? 1.1 : 1 / 1.1; const prevZoom = st.previewZoom ?? 1; const newZoom = clampPreviewZoom(prevZoom * factor); @@ -74,7 +80,8 @@ function attachPreviewNavigation(node, canvasSize) { st.previewPanY = my - (my - (st.previewPanY ?? 0)) * ratio; st.previewZoom = newZoom; reblitNow(); - }, { passive: false }); + }; + document.addEventListener("wheel", handleWheel, { capture: true, passive: false }); canvas.addEventListener("dblclick", () => { if (isInteractiveNode(node)) return; if (st.previewZoom === 1 && st.previewPanX === 0 && st.previewPanY === 0) return; diff --git a/js/preview/shared/preview-widget.js b/js/preview/shared/preview-widget.js index ca60e0e..b49c019 100644 --- a/js/preview/shared/preview-widget.js +++ b/js/preview/shared/preview-widget.js @@ -623,22 +623,32 @@ function ensurePreviewWidget(node, progress, canvasSize) { if (drawControls) root.appendChild(drawControls); if (compControls) root.appendChild(compControls); root.appendChild(progressWrap); + root.style.pointerEvents = "auto"; const domMinHeight = getNodePreviewMinHeight(node); - node.addDOMWidget("preview", "ImageOpsPreview", root, { - serialize: false, - hideOnZoom: false, - getMinHeight: () => { - const mediaH = mediaWrap.style.display !== "none" ? mediaWrap.offsetHeight : 0; - const imageH = Math.max(canvas.offsetHeight, mediaH); - if (imageH === 0) return domMinHeight; - const metaH = metaRow.offsetHeight + 6; - const activeControls = previewControls ?? colorControls ?? drawControls ?? compControls; - const controlsH = activeControls ? activeControls.offsetHeight + 8 : 0; - const progressH = progressWrap.offsetHeight; - const naturalH = imageH + metaH + controlsH + progressH + 12; - return Math.max(domMinHeight, naturalH); + if (typeof node.addDOMWidget === "function") { + node.addDOMWidget("preview", "ImageOpsPreview", root, { + serialize: false, + hideOnZoom: false, + getMinHeight: () => { + const mediaH = mediaWrap.style.display !== "none" ? mediaWrap.offsetHeight : 0; + const imageH = Math.max(canvas.offsetHeight, mediaH); + if (imageH === 0) return domMinHeight; + const metaH = metaRow.offsetHeight + 6; + const activeControls = previewControls ?? colorControls ?? drawControls ?? compControls; + const controlsH = activeControls ? activeControls.offsetHeight + 8 : 0; + const progressH = progressWrap.offsetHeight; + const naturalH = imageH + metaH + controlsH + progressH + 12; + return Math.max(domMinHeight, naturalH); + } + }); + } else { + const domEl = node.domElement ?? node.element; + if (domEl instanceof HTMLElement) { + domEl.appendChild(root); + } else { + console.warn("[ImageOps] addDOMWidget unavailable and no DOM container found on node", node.id); } - }); + } try { const widgets = node.widgets ?? []; const idx = widgets.findIndex((w) => w?.name === "preview"); diff --git a/src/preview/host.ts b/src/preview/host.ts index a271b51..6dbb671 100644 --- a/src/preview/host.ts +++ b/src/preview/host.ts @@ -524,6 +524,7 @@ export function registerImageOpsLivePreview(): void { } for (const w of (node.widgets ?? [])) { + if (typeof w.callback !== 'function' && typeof w.callback !== 'undefined') continue; const orig = w.callback; w.callback = function (this: any) { const r = orig?.apply(this, arguments as any); @@ -635,12 +636,15 @@ export function registerImageOpsLivePreview(): void { app.registerExtension({ name: EXT_NAME, async beforeRegisterNodeDef(nodeType: ComfyNodeConstructor, _nodeData: any) { - nodeType.prototype.onNodeCreated = (function (orig: any) { - return function (this: ComfyNode) { - orig?.apply(this, arguments); - hookNode(this); - }; - })(nodeType.prototype.onNodeCreated); + const origOnNodeCreated = nodeType.prototype.onNodeCreated; + nodeType.prototype.onNodeCreated = function (this: ComfyNode) { + origOnNodeCreated?.apply(this, arguments as any); + hookNode(this); + }; }, - }); + // Node 2.0 fallback: called per-instance after the node is fully constructed. + nodeCreated(node: ComfyNode) { + hookNode(node); + }, + } as any); } diff --git a/src/preview/interactions/draw.ts b/src/preview/interactions/draw.ts index 32cf289..2904c41 100644 --- a/src/preview/interactions/draw.ts +++ b/src/preview/interactions/draw.ts @@ -168,15 +168,21 @@ export function attachInteractions(node: ComfyNode, ctx: DrawInteractionContext) st.drawPressureOpacityInput?.addEventListener("change", syncDrawDynamics); st.drawTiltSizeInput?.addEventListener("change", syncDrawDynamics); - canvas.addEventListener("wheel", (event: WheelEvent) => { + // ── Wheel: zoom (Ctrl+scroll) and brush size (scroll) ── + // Use document capture phase to intercept before Node 2.0 graph container. + const handleDrawWheel = (event: WheelEvent): void => { + const target = event.target as Node | null; + if (target !== canvas && !canvas.contains(target)) return; if (!st.drawGeometry) return; // ── Ctrl+scroll: zoom the preview viewport ────────────────────────────── if (event.ctrlKey || event.metaKey) { + event.stopImmediatePropagation(); event.preventDefault(); const rect = canvas.getBoundingClientRect(); - const sx = canvas.width / Math.max(1, rect.width); - const sy = canvas.height / Math.max(1, rect.height); + if (rect.width < 1 || rect.height < 1) return; + const sx = canvas.width / rect.width; + const sy = canvas.height / rect.height; // Cursor position relative to canvas centre — zoom toward the cursor. const mx = (event.clientX - rect.left) * sx - canvas.width / 2; const my = (event.clientY - rect.top) * sy - canvas.height / 2; @@ -195,13 +201,15 @@ export function attachInteractions(node: ComfyNode, ctx: DrawInteractionContext) const point = getCanvasPointer(canvas, event as unknown as PointerEvent); const hover = canvasToSource(point.x, point.y); if (!hover.inside) return; + event.stopImmediatePropagation(); event.preventDefault(); const current = widgetNumber(node, "brush_size", 10); const step = event.shiftKey ? 8 : 2; const direction = event.deltaY > 0 ? -step : step; ctx.setDrawBrushSize(node, current + direction); void ctx.renderDrawNode(node, 0); - }, { passive: false }); + }; + document.addEventListener("wheel", handleDrawWheel, { capture: true, passive: false }); canvas.addEventListener("keydown", (event: KeyboardEvent) => { if (!(event.ctrlKey || event.metaKey) || event.key.toLowerCase() !== "z") return; @@ -230,8 +238,9 @@ export function attachInteractions(node: ComfyNode, ctx: DrawInteractionContext) canvas.focus(); try { canvas.setPointerCapture?.(event.pointerId); } catch {} const rect = canvas.getBoundingClientRect(); - const sx = canvas.width / Math.max(1, rect.width); - const sy = canvas.height / Math.max(1, rect.height); + if (rect.width < 1 || rect.height < 1) return; + const sx = canvas.width / rect.width; + const sy = canvas.height / rect.height; ctrlPanDrag = { pointerId: event.pointerId, startCanvasX: (event.clientX - rect.left) * sx, @@ -286,8 +295,9 @@ export function attachInteractions(node: ComfyNode, ctx: DrawInteractionContext) // ── Ctrl+drag pan in progress ──────────────────────────────────────────── if (ctrlPanDrag && ctrlPanDrag.pointerId === event.pointerId) { const rect = canvas.getBoundingClientRect(); - const sx = canvas.width / Math.max(1, rect.width); - const sy = canvas.height / Math.max(1, rect.height); + if (rect.width < 1 || rect.height < 1) return; + const sx = canvas.width / rect.width; + const sy = canvas.height / rect.height; const cx = (event.clientX - rect.left) * sx; const cy = (event.clientY - rect.top) * sy; st.previewPanX = ctrlPanDrag.startPanX + (cx - ctrlPanDrag.startCanvasX); diff --git a/src/preview/shared/geometry.ts b/src/preview/shared/geometry.ts index 2f1ed56..d05d503 100644 --- a/src/preview/shared/geometry.ts +++ b/src/preview/shared/geometry.ts @@ -75,8 +75,10 @@ export function drawOutputFormatBox(ctx: CanvasRenderingContext2D, fit: FitPlace export function getCanvasPointer(canvas: HTMLCanvasElement, event: PointerEvent): { x: number; y: number } { const rect = canvas.getBoundingClientRect(); - const scaleX = canvas.width / Math.max(1, rect.width); - const scaleY = canvas.height / Math.max(1, rect.height); + // Guard against detached or zero-size canvas (Node 2.0 deferred DOM insertion). + if (rect.width < 1 || rect.height < 1) return { x: 0, y: 0 }; + const scaleX = canvas.width / rect.width; + const scaleY = canvas.height / rect.height; return { x: (event.clientX - rect.left) * scaleX, y: (event.clientY - rect.top) * scaleY, diff --git a/src/preview/shared/navigation.ts b/src/preview/shared/navigation.ts index bf17d3c..ebc7439 100644 --- a/src/preview/shared/navigation.ts +++ b/src/preview/shared/navigation.ts @@ -21,18 +21,25 @@ export function attachPreviewNavigation(node: ComfyNode, canvasSize: number): vo blit(node, st, st.previewLastSource, canvasSize); }; + /** Safe rect helper — returns null if canvas is detached / zero-size. */ + const safeRect = (): { rect: DOMRect; sx: number; sy: number } | null => { + const rect = canvas.getBoundingClientRect(); + if (rect.width < 1 || rect.height < 1) return null; + return { rect, sx: canvas.width / rect.width, sy: canvas.height / rect.height }; + }; + // ── Middle-button pan ── canvas.addEventListener("pointerdown", (event: PointerEvent) => { if (event.button !== 1) return; event.preventDefault(); + event.stopPropagation(); try { canvas.setPointerCapture(event.pointerId); } catch {} - const rect = canvas.getBoundingClientRect(); - const sx = canvas.width / Math.max(1, rect.width); - const sy = canvas.height / Math.max(1, rect.height); + const r = safeRect(); + if (!r) return; st.previewPanDrag = { pointerId: event.pointerId, - startCanvasX: (event.clientX - rect.left) * sx, - startCanvasY: (event.clientY - rect.top) * sy, + startCanvasX: (event.clientX - r.rect.left) * r.sx, + startCanvasY: (event.clientY - r.rect.top) * r.sy, startPanX: st.previewPanX, startPanY: st.previewPanY, }; @@ -40,11 +47,10 @@ export function attachPreviewNavigation(node: ComfyNode, canvasSize: number): vo canvas.addEventListener("pointermove", (event: PointerEvent) => { if (!st.previewPanDrag || st.previewPanDrag.pointerId !== event.pointerId) return; - const rect = canvas.getBoundingClientRect(); - const sx = canvas.width / Math.max(1, rect.width); - const sy = canvas.height / Math.max(1, rect.height); - const cx = (event.clientX - rect.left) * sx; - const cy = (event.clientY - rect.top) * sy; + const r = safeRect(); + if (!r) return; + const cx = (event.clientX - r.rect.left) * r.sx; + const cy = (event.clientY - r.rect.top) * r.sy; st.previewPanX = st.previewPanDrag.startPanX + (cx - st.previewPanDrag.startCanvasX); st.previewPanY = st.previewPanDrag.startPanY + (cy - st.previewPanDrag.startCanvasY); reblitNow(); @@ -64,15 +70,21 @@ export function attachPreviewNavigation(node: ComfyNode, canvasSize: number): vo }); // ── Wheel: zoom toward cursor (disabled for interactive nodes — they handle wheel themselves) ── - canvas.addEventListener("wheel", (event: WheelEvent) => { - if (isInteractiveNode(node)) return; + // In Node 2.0, graph-canvas-container intercepts wheel events in capture phase + // before they reach our canvas. We therefore register our own capture-phase + // handler on the document so we can stop the event first. + const handleWheel = (event: WheelEvent): void => { + const target = event.target as Node | null; + if (target !== canvas && !canvas.contains(target)) return; + // Always prevent graph zoom when cursor is on our preview canvas + event.stopImmediatePropagation(); event.preventDefault(); - const rect = canvas.getBoundingClientRect(); - const sx = canvas.width / Math.max(1, rect.width); - const sy = canvas.height / Math.max(1, rect.height); + if (isInteractiveNode(node)) return; + const r = safeRect(); + if (!r) return; // Mouse position relative to canvas center - const mx = (event.clientX - rect.left) * sx - canvas.width / 2; - const my = (event.clientY - rect.top) * sy - canvas.height / 2; + const mx = (event.clientX - r.rect.left) * r.sx - canvas.width / 2; + const my = (event.clientY - r.rect.top) * r.sy - canvas.height / 2; const factor = event.deltaY < 0 ? 1.1 : 1 / 1.1; const prevZoom = st.previewZoom ?? 1; const newZoom = clampPreviewZoom(prevZoom * factor); @@ -82,7 +94,8 @@ export function attachPreviewNavigation(node: ComfyNode, canvasSize: number): vo st.previewPanY = my - (my - (st.previewPanY ?? 0)) * ratio; st.previewZoom = newZoom; reblitNow(); - }, { passive: false }); + }; + document.addEventListener("wheel", handleWheel, { capture: true, passive: false }); // ── Double-click: reset zoom/pan ── canvas.addEventListener("dblclick", () => { diff --git a/src/preview/shared/preview-widget.ts b/src/preview/shared/preview-widget.ts index a14debb..9484bff 100644 --- a/src/preview/shared/preview-widget.ts +++ b/src/preview/shared/preview-widget.ts @@ -735,24 +735,37 @@ export function ensurePreviewWidget(node: ComfyNode, progress: ProgressBus, canv if (compControls) root.appendChild(compControls); root.appendChild(progressWrap); + // Ensure pointer events reach our canvas even if Node 2.0 applies pointer-events:none on parent containers. + root.style.pointerEvents = "auto"; + const domMinHeight = getNodePreviewMinHeight(node); - node.addDOMWidget("preview", "ImageOpsPreview", root, { - serialize: false, - hideOnZoom: false, - getMinHeight: () => { - // Use canvas/mediaWrap rendered height (determined by node WIDTH, not height) to avoid - // the vertical feedback loop where a tall node makes the DOM tall which makes the node tall. - const mediaH = mediaWrap.style.display !== "none" ? mediaWrap.offsetHeight : 0; - const imageH = Math.max(canvas.offsetHeight, mediaH); - if (imageH === 0) return domMinHeight; - const metaH = metaRow.offsetHeight + 6; // 6px marginTop - const activeControls = previewControls ?? colorControls ?? drawControls ?? compControls; - const controlsH = activeControls ? activeControls.offsetHeight + 8 : 0; - const progressH = progressWrap.offsetHeight; - const naturalH = imageH + metaH + controlsH + progressH + 12; // 12px root padding - return Math.max(domMinHeight, naturalH); - }, - }); + if (typeof node.addDOMWidget === "function") { + node.addDOMWidget("preview", "ImageOpsPreview", root, { + serialize: false, + hideOnZoom: false, + getMinHeight: () => { + // Use canvas/mediaWrap rendered height (determined by node WIDTH, not height) to avoid + // the vertical feedback loop where a tall node makes the DOM tall which makes the node tall. + const mediaH = mediaWrap.style.display !== "none" ? mediaWrap.offsetHeight : 0; + const imageH = Math.max(canvas.offsetHeight, mediaH); + if (imageH === 0) return domMinHeight; + const metaH = metaRow.offsetHeight + 6; // 6px marginTop + const activeControls = previewControls ?? colorControls ?? drawControls ?? compControls; + const controlsH = activeControls ? activeControls.offsetHeight + 8 : 0; + const progressH = progressWrap.offsetHeight; + const naturalH = imageH + metaH + controlsH + progressH + 12; // 12px root padding + return Math.max(domMinHeight, naturalH); + }, + }); + } else { + // Node 2.0 fallback: inject the root element directly into the node's DOM container. + const domEl = (node as any).domElement ?? (node as any).element; + if (domEl instanceof HTMLElement) { + domEl.appendChild(root); + } else { + console.warn("[ImageOps] addDOMWidget unavailable and no DOM container found on node", node.id); + } + } // Force the preview widget to the top (before sliders), like KayTool. try { diff --git a/src/types.ts b/src/types.ts index 0090959..8852709 100644 --- a/src/types.ts +++ b/src/types.ts @@ -10,6 +10,7 @@ export interface ComfyApp { export interface ComfyExtension { name: string; beforeRegisterNodeDef?(nodeType: ComfyNodeConstructor, nodeData: any): Promise | void; + nodeCreated?(node: ComfyNode): void; } export interface ComfyNodeConstructor { @@ -86,7 +87,7 @@ export interface ComfyNode { onExecuted?(...args: any[]): any; onNodeCreated?(...args: any[]): any; setSize?(size: [number, number]): void; - addDOMWidget(name: string, type: string, el: HTMLElement, opts: any): void; + addDOMWidget?(name: string, type: string, el: HTMLElement, opts: any): void; addInput?(name: string, type?: string, extra_info?: any): void; removeInput?(slot: number): void; __imageops_state?: NodeState;