Compare commits

...

18 Commits

Author SHA1 Message Date
Alexander Brown
16ad2c5975 Merge branch 'main' into fix/spacebar-panning-vue-nodes 2026-01-13 13:27:54 -08:00
Jin Yi
6f3855f5f1 fix: reduce media asset card hover background opacity for button visibility (#8020)
## Summary
Reduces the MediaAssetCard hover background opacity to 20% so buttons
within the card stand out during hover interactions.

## Changes
- **What**: Changed `hover:bg-modal-card-background-hovered` to
`hover:bg-modal-card-background-hovered/20` in MediaAssetCard.vue

## Context
During design review, it was identified that the button hover color
matches the card hover color, making it difficult to distinguish button
hover states. This fix applies reduced opacity to the card background
hover, ensuring buttons remain visually distinct.

<img width="659" height="302" alt="스크린샷 2026-01-13 오후 2 39 40"
src="https://github.com/user-attachments/assets/a77b408e-46a5-4725-9afb-2260bda0f8c9"
/>

🤖 Generated with [Claude Code](https://claude.com/claude-code)

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8020-fix-reduce-media-asset-card-hover-background-opacity-for-button-visibility-2e76d73d365081b1afcefe17ac6db6ac)
by [Unito](https://www.unito.io)
2026-01-12 23:49:10 -07:00
Comfy Org PR Bot
0f1e54530c 1.38.0 (#8021)
Minor version increment to 1.38.0

**Base branch:** `main`

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8021-1-38-0-2e76d73d3650812d98c4ffa5a5f351ce)
by [Unito](https://www.unito.io)

---------

Co-authored-by: christian-byrne <72887196+christian-byrne@users.noreply.github.com>
Co-authored-by: github-actions <github-actions@github.com>
2026-01-12 22:56:51 -07:00
github-actions
813f54bff4 [automated] Update test expectations 2026-01-06 19:54:57 +00:00
Johnpaul
0f6fb90d04 format files 2026-01-06 20:34:16 +01:00
Johnpaul
0972a46a15 Merge remote-tracking branch 'origin/main' into fix/spacebar-panning-vue-nodes 2026-01-06 20:32:17 +01:00
Johnpaul
f5cdee82e9 fix: add capture flag to removeEventListener calls and reuse target variable
- Add capture:true to removeEventListener calls that were added with capture
  to prevent event listener leaks when unbinding
- Reuse existing target variable in Delete/Backspace check instead of
  re-accessing e.target with @ts-expect-error
- Add isContentEditable check to Delete/Backspace guard for consistency
2026-01-06 20:31:51 +01:00
GitHub Action
571bb51ab5 [automated] Apply ESLint and Prettier fixes 2026-01-06 19:16:58 +00:00
Johnpaul
a47081c169 fix: skip text-editable elements in processKey
Broaden the target guard in processKey to skip all text-editable surfaces
(input, textarea, contenteditable) before handling shortcuts. This prevents
space/Ctrl+A/C from being blocked when typing in prompt textareas or other
multiline fields in Vue nodes mode.
2026-01-06 20:14:58 +01:00
Johnpaul
0e47f9fb10 fix: always remove document keydown listener in unbindEvents
Remove the LiteGraph.vueNodesMode check when removing the document-level
keydown listener in unbindEvents. If vueNodesMode was true during bindEvents
but changed before unbindEvents, the listener would be left dangling.
Now guarded only by existence of _key_callback.
2026-01-05 22:48:08 +01:00
Johnpaul
9427d7ed60 Merge remote-tracking branch 'origin/main' into fix/spacebar-panning-vue-nodes 2026-01-05 22:24:39 +01:00
Johnpaul
d114b01a75 refactor: consolidate panning state in litegraph
Remove duplicate panning state management from useSlotLinkInteraction.
Instead of Vue manually manipulating canvas.ds.offset, sync pointer.isDown
with litegraph and let events bubble when in panning mode (read_only).

- Remove isPanningDuringLinkDrag and lastPanningMouse local state
- Remove manual offset manipulation in handlePointerMove
- Conditionally stopPropagation only when NOT in panning mode
- Set canvas.pointer.isDown so spacebar triggers litegraph panning
2026-01-05 22:22:59 +01:00
Johnpaul
53bdf7f6c3 fix: enable spacebar panning during slot link drag
Move spacebar detection to document-level listener in LGraphCanvas when
vueNodesMode is enabled. Implement direct panning in useSlotLinkInteraction
when spacebar is held during connection drag, bypassing litegraph event
handling for smoother panning while maintaining link position updates.

Fixes #7806
2026-01-05 22:09:11 +01:00
Johnpaul
fc082d84b9 refactor: use read_only as signal, let events bubble to litegraph
- Set canvas.read_only directly when spacebar pressed
- Skip stopPropagation when read_only is true in slot link handler
- Remove manual dragging_canvas and processMouseMove management
- Litegraph handles panning through its normal event handlers
2025-12-31 06:58:50 +01:00
Johnpaul
3cf19af173 fix: Explicitly pass null to isEditableElement when activeElement.value is falsy. 2025-12-31 02:15:39 +01:00
Johnpaul
1d1e16b62d refactor: simplify spacebar forwarding to module-level initialization 2025-12-31 02:04:45 +01:00
Johnpaul
2f8f5253b5 refactor: address review comments - use useMagicKeys and derive button state
- Refactored spacebar forwarding to use useMagicKeys from VueUse instead of raw event listeners
- Added filtering for editable elements (input, textarea, contentEditable)
- Changed panning check in useSlotLinkInteraction to derive button state from event.buttons instead of storing canvas.pointer.isDown statefully
- Updated tests to work with the new useMagicKeys approach using vi.hoisted pattern
2025-12-31 01:28:27 +01:00
Johnpaul
f5ac48c5be fix: spacebar panning in vueNodes mode
Forward keydown events to litegraph's processKey when Vue nodes have
focus. Litegraph only binds keydown to the canvas element, so spacebar
panning didn't work when Vue nodes were focused.

Also sync pointer state with litegraph canvas during link dragging to
enable spacebar panning while dragging connections.

Fixes #7806
2025-12-31 00:48:35 +01:00
34 changed files with 167 additions and 59 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 103 KiB

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 57 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 99 KiB

After

Width:  |  Height:  |  Size: 98 KiB

View File

@@ -1,7 +1,7 @@
{
"name": "@comfyorg/comfyui-frontend",
"private": true,
"version": "1.37.10",
"version": "1.38.0",
"type": "module",
"repository": "https://github.com/Comfy-Org/ComfyUI_frontend",
"homepage": "https://comfy.org",

View File

@@ -1953,6 +1953,10 @@ export class LGraphCanvas implements CustomEventDispatcher<LGraphCanvasEventMap>
this._key_callback = this.processKey.bind(this)
canvas.addEventListener('keydown', this._key_callback, true)
// In Vue nodes mode, also listen on document for keydown since Vue elements may have focus
if (LiteGraph.vueNodesMode) {
document.addEventListener('keydown', this._key_callback, true)
}
// keyup event must be bound on the document
document.addEventListener('keyup', this._key_callback, true)
@@ -1977,14 +1981,24 @@ export class LGraphCanvas implements CustomEventDispatcher<LGraphCanvasEventMap>
const { canvas } = this
// Assertions: removing nullish is fine.
canvas.removeEventListener('pointercancel', this._mousecancel_callback!)
// Note: capture flag must match addEventListener for removal to work
canvas.removeEventListener(
'pointercancel',
this._mousecancel_callback!,
true
)
canvas.removeEventListener('pointerout', this._mouseout_callback!)
canvas.removeEventListener('pointermove', this._mousemove_callback!)
canvas.removeEventListener('pointerup', this._mouseup_callback!)
canvas.removeEventListener('pointerdown', this._mousedown_callback!)
canvas.removeEventListener('pointerup', this._mouseup_callback!, true)
canvas.removeEventListener('pointerdown', this._mousedown_callback!, true)
canvas.removeEventListener('wheel', this._mousewheel_callback!)
canvas.removeEventListener('keydown', this._key_callback!)
document.removeEventListener('keyup', this._key_callback!)
canvas.removeEventListener('keydown', this._key_callback!, true)
// Always remove document keydown listener - it may have been added if vueNodesMode
// was true during bindEvents, even if vueNodesMode has since changed
if (this._key_callback) {
document.removeEventListener('keydown', this._key_callback, true)
}
document.removeEventListener('keyup', this._key_callback!, true)
canvas.removeEventListener('contextmenu', this._doNothing)
canvas.removeEventListener('dragenter', this._doReturnTrue)
@@ -3668,8 +3682,14 @@ export class LGraphCanvas implements CustomEventDispatcher<LGraphCanvasEventMap>
if (!graph) return
let block_default = false
// @ts-expect-error EventTarget.localName is not in standard types
if (e.target.localName == 'input') return
// Skip all text-editable surfaces to avoid blocking typing/selection/copy
const target = e.target as HTMLElement | null
if (
target?.localName === 'input' ||
target?.localName === 'textarea' ||
target?.isContentEditable
)
return
if (e.type == 'keydown') {
// TODO: Switch
@@ -3705,9 +3725,12 @@ export class LGraphCanvas implements CustomEventDispatcher<LGraphCanvasEventMap>
// paste
this.pasteFromClipboard({ connectInputs: e.shiftKey })
} else if (e.key === 'Delete' || e.key === 'Backspace') {
// delete or backspace
// @ts-expect-error EventTarget.localName is not in standard types
if (e.target.localName != 'input' && e.target.localName != 'textarea') {
// delete or backspace (but don't intercept when editing text)
if (
target?.localName !== 'input' &&
target?.localName !== 'textarea' &&
!target?.isContentEditable
) {
if (this.selectedItems.size === 0) {
this.#noItemsSelected()
return

View File

@@ -254,6 +254,9 @@
"Comfy_RefreshNodeDefinitions": {
"label": "تحديث تعريفات العقد"
},
"Comfy_RenameWorkflow": {
"label": "إعادة تسمية سير العمل"
},
"Comfy_SaveWorkflow": {
"label": "حفظ سير العمل"
},

View File

@@ -60,6 +60,7 @@
"findInLibrary": "ابحث عنه في قسم {type} من مكتبة النماذج.",
"finish": "إنهاء",
"genericLinkPlaceholder": "الصق الرابط هنا",
"importAnother": "استيراد آخر",
"jobId": "معرّف المهمة",
"loadingModels": "جارٍ تحميل {type}...",
"maxFileSize": "الحد الأقصى لحجم الملف: {size}",
@@ -1520,6 +1521,7 @@
"Redo": "إعادة",
"Refresh Node Definitions": "تحديث تعريفات العقد",
"Reinstall": "إعادة التثبيت",
"Rename": "إعادة التسمية",
"Reset View": "إعادة تعيين العرض",
"Resize Selected Nodes": "تغيير حجم العقد المحددة",
"Restart": "إعادة التشغيل",

View File

@@ -254,6 +254,9 @@
"Comfy_RefreshNodeDefinitions": {
"label": "Refresh Node Definitions"
},
"Comfy_RenameWorkflow": {
"label": "Rename Workflow"
},
"Comfy_SaveWorkflow": {
"label": "Save Workflow"
},

View File

@@ -1176,6 +1176,7 @@
"Queue Selected Output Nodes": "Queue Selected Output Nodes",
"Redo": "Redo",
"Refresh Node Definitions": "Refresh Node Definitions",
"Rename": "Rename",
"Save": "Save",
"Save As": "Save As",
"Show Settings Dialog": "Show Settings Dialog",

View File

@@ -254,6 +254,9 @@
"Comfy_RefreshNodeDefinitions": {
"label": "Actualizar Definiciones de Nodo"
},
"Comfy_RenameWorkflow": {
"label": "Renombrar flujo de trabajo"
},
"Comfy_SaveWorkflow": {
"label": "Guardar Flujo de Trabajo"
},

View File

@@ -60,6 +60,7 @@
"findInLibrary": "Encuéntralo en la sección {type} de la biblioteca de modelos.",
"finish": "Finalizar",
"genericLinkPlaceholder": "Pega el enlace aquí",
"importAnother": "Importar otro",
"jobId": "ID de tarea",
"loadingModels": "Cargando {type}...",
"maxFileSize": "Tamaño máximo de archivo: {size}",
@@ -1520,6 +1521,7 @@
"Redo": "Rehacer",
"Refresh Node Definitions": "Actualizar definiciones de nodo",
"Reinstall": "Reinstalar",
"Rename": "Renombrar",
"Reset View": "Restablecer vista",
"Resize Selected Nodes": "Redimensionar Nodos Seleccionados",
"Restart": "Reiniciar",

View File

@@ -254,6 +254,9 @@
"Comfy_RefreshNodeDefinitions": {
"label": "به‌روزرسانی تعاریف نود"
},
"Comfy_RenameWorkflow": {
"label": "تغییر نام Workflow"
},
"Comfy_SaveWorkflow": {
"label": "ذخیره ورک‌فلو"
},

View File

@@ -60,6 +60,7 @@
"findInLibrary": "در بخش {type} کتابخانه مدل‌ها پیدا کنید.",
"finish": "پایان",
"genericLinkPlaceholder": "لینک را اینجا وارد کنید",
"importAnother": "وارد کردن مورد دیگر",
"jobId": "شناسه کار: {jobId}",
"loadingModels": "در حال بارگذاری {type}...",
"maxFileSize": "حداکثر اندازه فایل: {size}",
@@ -237,22 +238,6 @@
"title": "ایجاد حساب کاربری"
}
},
"authTimeout": {
"causes": [
"فایروال یا پراکسی سازمانی که سرویس‌های احراز هویت را مسدود می‌کند",
"محدودیت‌های VPN یا شبکه",
"افزونه‌های مرورگر که در درخواست‌ها اختلال ایجاد می‌کنند",
"محدودیت‌های منطقه‌ای شبکه",
"امتحان مرورگر یا شبکه دیگر"
],
"helpText": "نیاز به کمک دارید؟ تماس با",
"message": "در اتصال به ComfyUI Cloud با مشکل مواجه شده‌ایم. ممکن است به دلیل کندی اتصال یا مشکل موقت سرویس باشد.",
"restart": "خروج و تلاش مجدد",
"supportLink": "پشتیبانی",
"technicalDetails": "جزئیات فنی",
"title": "اتصال بیش از حد طول کشید",
"troubleshooting": "دلایل رایج:"
},
"breadcrumbsMenu": {
"clearWorkflow": "پاک‌سازی workflow",
"deleteBlueprint": "حذف blueprint",
@@ -261,7 +246,6 @@
"enterNewName": "نام جدید را وارد کنید",
"missingNodesWarning": "workflow شامل نودهای پشتیبانی‌نشده است (با رنگ قرمز مشخص شده‌اند)."
},
"checkingStatus": "در حال بررسی وضعیت حساب شما...",
"clipboard": {
"errorMessage": "کپی به کلیپ‌بورد ناموفق بود",
"errorNotSupported": "Clipboard API در مرورگر شما پشتیبانی نمی‌شود",
@@ -279,6 +263,49 @@
"cloudForgotPassword_sendResetLink": "ارسال لینک بازنشانی",
"cloudForgotPassword_title": "فراموشی رمز عبور",
"cloudOnboarding": {
"authTimeout": {
"causes": [
"فایروال یا پراکسی سازمانی که سرویس‌های احراز هویت را مسدود می‌کند",
"محدودیت‌های VPN یا شبکه",
"افزونه‌های مرورگر که در درخواست‌ها اختلال ایجاد می‌کنند",
"محدودیت‌های منطقه‌ای شبکه",
"استفاده از مرورگر یا شبکه دیگر را امتحان کنید"
],
"helpText": "نیاز به راهنمایی دارید؟ تماس با",
"message": "در اتصال به ComfyUI Cloud با مشکل مواجه شدیم. این مشکل ممکن است به دلیل کندی اتصال یا اختلال موقت سرویس باشد.",
"restart": "خروج و تلاش مجدد",
"supportLink": "پشتیبانی",
"technicalDetails": "جزئیات فنی",
"title": "اتصال بیش از حد طول کشید",
"troubleshooting": "دلایل رایج:"
},
"checkingStatus": "در حال بررسی وضعیت حساب شما...",
"forgotPassword": {
"backToLogin": "بازگشت به ورود",
"didntReceiveEmail": "ایمیلی دریافت نکردید؟ با ما تماس بگیرید:",
"emailLabel": "ایمیل",
"emailPlaceholder": "ایمیل خود را وارد کنید",
"emailRequired": "وارد کردن ایمیل الزامی است",
"instructions": "آدرس ایمیل خود را وارد کنید تا لینک بازنشانی رمز عبور برای شما ارسال شود.",
"passwordResetError": "ارسال ایمیل بازنشانی رمز عبور ناموفق بود. لطفاً دوباره تلاش کنید.",
"passwordResetSent": "ایمیل بازنشانی رمز عبور ارسال شد",
"sendResetLink": "ارسال لینک بازنشانی",
"title": "فراموشی رمز عبور"
},
"privateBeta": {
"desc": "برای پیوستن به لیست انتظار وارد شوید. زمانی که نوبت شما شد به شما اطلاع خواهیم داد. قبلاً اطلاع داده شده‌اید؟ وارد شوید و از Cloud استفاده کنید.",
"title": "کلود در حال حاضر در نسخه بتای خصوصی است"
},
"retry": "تلاش دوباره",
"retrying": "در حال تلاش مجدد...",
"start": {
"desc": "بدون نیاز به تنظیمات اولیه. روی هر دستگاهی کار می‌کند.",
"download": "دانلود ComfyUI",
"explain": "چندین خروجی را به طور همزمان تولید کنید. گردش‌کارها را به راحتی به اشتراک بگذارید.",
"learnAboutButton": "درباره Cloud بیشتر بدانید",
"title": "در چند ثانیه شروع به خلق کنید",
"wantToRun": "می‌خواهید ComfyUI را به صورت محلی اجرا کنید؟"
},
"survey": {
"options": {
"familiarity": {
@@ -616,18 +643,6 @@
"noStackTrace": "هیچ stacktraceی موجود نیست",
"promptExecutionError": "اجرای prompt با شکست مواجه شد"
},
"forgotPassword": {
"backToLogin": "بازگشت به ورود",
"didntReceiveEmail": "ایمیلی دریافت نکردید؟ با ما تماس بگیرید:",
"emailLabel": "ایمیل",
"emailPlaceholder": "ایمیل خود را وارد کنید",
"emailRequired": "وارد کردن ایمیل الزامی است",
"instructions": "آدرس ایمیل خود را وارد کنید تا لینک بازنشانی رمز عبور برای شما ارسال شود.",
"passwordResetError": "ارسال ایمیل بازنشانی رمز عبور ناموفق بود. لطفاً دوباره تلاش کنید.",
"passwordResetSent": "ایمیل بازنشانی رمز عبور ارسال شد",
"sendResetLink": "ارسال لینک بازنشانی",
"title": "فراموشی رمز عبور"
},
"g": {
"1x": "۱x",
"2x": "۲x",
@@ -1506,6 +1521,7 @@
"Redo": "انجام مجدد",
"Refresh Node Definitions": "به‌روزرسانی تعاریف Node",
"Reinstall": "نصب مجدد",
"Rename": "تغییر نام",
"Reset View": "بازنشانی نما",
"Resize Selected Nodes": "تغییر اندازه Nodeهای انتخاب‌شده",
"Restart": "راه‌اندازی مجدد",
@@ -1694,10 +1710,6 @@
},
"title": "دستگاه شما پشتیبانی نمی‌شود"
},
"privateBeta": {
"desc": "برای پیوستن به لیست انتظار وارد شوید. زمانی که نوبت شما شد به شما اطلاع خواهیم داد. قبلاً اطلاع‌رسانی شده‌اید؟ وارد شوید و از Cloud استفاده کنید.",
"title": "Cloud در حال حاضر در نسخه بتای خصوصی است"
},
"progressToast": {
"allDownloadsCompleted": "همه دانلودها تکمیل شدند",
"downloadingModel": "در حال دانلود مدل...",
@@ -1773,8 +1785,6 @@
"update": "به‌روزرسانی",
"whatsNew": "مشاهده تغییرات جدید"
},
"retry": "تلاش دوباره",
"retrying": "در حال تلاش مجدد...",
"rightSidePanel": {
"bypass": "عبور",
"color": "رنگ نود",
@@ -2165,14 +2175,6 @@
},
"workflows": "Workflowها"
},
"start": {
"desc": "بدون نیاز به تنظیمات. روی هر دستگاهی کار می‌کند.",
"download": "دانلود ComfyUI",
"explain": "چندین خروجی را همزمان تولید کنید. workflowها را به راحتی به اشتراک بگذارید.",
"learnAboutButton": "درباره Cloud بیشتر بدانید",
"title": "در چند ثانیه شروع به خلق کنید",
"wantToRun": "مایلید ComfyUI را به صورت محلی اجرا کنید؟"
},
"subgraphStore": {
"blueprintName": "نام زیرگراف",
"confirmDelete": "این عمل باعث حذف دائمی بلوپرینت از کتابخانه شما می‌شود",

View File

@@ -254,6 +254,9 @@
"Comfy_RefreshNodeDefinitions": {
"label": "Actualiser les définitions de nœud"
},
"Comfy_RenameWorkflow": {
"label": "Renommer le workflow"
},
"Comfy_SaveWorkflow": {
"label": "Enregistrer le flux de travail"
},

View File

@@ -60,6 +60,7 @@
"findInLibrary": "Trouvez-le dans la section {type} de la bibliothèque de modèles.",
"finish": "Terminer",
"genericLinkPlaceholder": "Collez le lien ici",
"importAnother": "Importer un autre",
"jobId": "ID de tâche",
"loadingModels": "Chargement de {type}...",
"maxFileSize": "Taille maximale du fichier : {size}",
@@ -1520,6 +1521,7 @@
"Redo": "Refaire",
"Refresh Node Definitions": "Actualiser les définitions de nœud",
"Reinstall": "Réinstaller",
"Rename": "Renommer",
"Reset View": "Réinitialiser la vue",
"Resize Selected Nodes": "Redimensionner les nœuds sélectionnés",
"Restart": "Redémarrer",

View File

@@ -254,6 +254,9 @@
"Comfy_RefreshNodeDefinitions": {
"label": "ノード定義を更新"
},
"Comfy_RenameWorkflow": {
"label": "ワークフローの名前を変更"
},
"Comfy_SaveWorkflow": {
"label": "ワークフローを保存する"
},

View File

@@ -60,6 +60,7 @@
"findInLibrary": "モデルライブラリの{type}セクションで見つけることができます。",
"finish": "完了",
"genericLinkPlaceholder": "ここにリンクを貼り付けてください",
"importAnother": "別のファイルをインポート",
"jobId": "ジョブID",
"loadingModels": "{type}を読み込み中...",
"maxFileSize": "最大ファイルサイズ:{size}",
@@ -1520,6 +1521,7 @@
"Redo": "やり直す",
"Refresh Node Definitions": "ノード定義を更新",
"Reinstall": "再インストール",
"Rename": "名前を変更",
"Reset View": "ビューをリセット",
"Resize Selected Nodes": "選択したノードのサイズ変更",
"Restart": "再起動",

View File

@@ -254,6 +254,9 @@
"Comfy_RefreshNodeDefinitions": {
"label": "노드 정의 새로 고침"
},
"Comfy_RenameWorkflow": {
"label": "워크플로우 이름 변경"
},
"Comfy_SaveWorkflow": {
"label": "워크플로 저장"
},

View File

@@ -60,6 +60,7 @@
"findInLibrary": "모델 라이브러리의 {type} 섹션에서 찾을 수 있습니다.",
"finish": "완료",
"genericLinkPlaceholder": "여기에 링크를 붙여넣으세요",
"importAnother": "다른 항목 가져오기",
"jobId": "작업 ID",
"loadingModels": "{type} 불러오는 중...",
"maxFileSize": "최대 파일 크기: {size}",
@@ -1520,6 +1521,7 @@
"Redo": "다시 실행",
"Refresh Node Definitions": "노드 정의 새로 고침",
"Reinstall": "재설치",
"Rename": "이름 바꾸기",
"Reset View": "보기 초기화",
"Resize Selected Nodes": "선택된 노드 크기 조정",
"Restart": "재시작",

View File

@@ -254,6 +254,9 @@
"Comfy_RefreshNodeDefinitions": {
"label": "Atualizar Definições de Nós"
},
"Comfy_RenameWorkflow": {
"label": "Renomear fluxo de trabalho"
},
"Comfy_SaveWorkflow": {
"label": "Salvar Fluxo de Trabalho"
},

View File

@@ -60,6 +60,7 @@
"findInLibrary": "Encontre na seção {type} da biblioteca de modelos.",
"finish": "Concluir",
"genericLinkPlaceholder": "Cole o link aqui",
"importAnother": "Importar outro",
"jobId": "ID do trabalho",
"loadingModels": "Carregando {type}...",
"maxFileSize": "Tamanho máximo do arquivo: {size}",
@@ -1520,6 +1521,7 @@
"Redo": "Refazer",
"Refresh Node Definitions": "Atualizar definições de nós",
"Reinstall": "Reinstalar",
"Rename": "Renomear",
"Reset View": "Redefinir visualização",
"Resize Selected Nodes": "Redimensionar nós selecionados",
"Restart": "Reiniciar",

View File

@@ -254,6 +254,9 @@
"Comfy_RefreshNodeDefinitions": {
"label": "Обновить определения нод"
},
"Comfy_RenameWorkflow": {
"label": "Переименовать рабочий процесс"
},
"Comfy_SaveWorkflow": {
"label": "Сохранить рабочий процесс"
},

View File

@@ -60,6 +60,7 @@
"findInLibrary": "Найдите это в разделе {type} библиотеки моделей.",
"finish": "Готово",
"genericLinkPlaceholder": "Вставьте ссылку сюда",
"importAnother": "Импортировать другой",
"jobId": "ID задачи",
"loadingModels": "Загрузка {type}...",
"maxFileSize": "Максимальный размер файла: {size}",
@@ -1520,6 +1521,7 @@
"Redo": "Повторить",
"Refresh Node Definitions": "Обновить определения нод",
"Reinstall": "Переустановить",
"Rename": "Переименовать",
"Reset View": "Сбросить вид",
"Resize Selected Nodes": "Изменить размер выбранных узлов",
"Restart": "Перезапустить",

View File

@@ -254,6 +254,9 @@
"Comfy_RefreshNodeDefinitions": {
"label": "Düğüm Tanımlarını Yenile"
},
"Comfy_RenameWorkflow": {
"label": "Çalışma Akışını Yeniden Adlandır"
},
"Comfy_SaveWorkflow": {
"label": "İş Akışını Kaydet"
},

View File

@@ -60,6 +60,7 @@
"findInLibrary": "Bunu modeller kütüphanesinin {type} bölümünde bulabilirsiniz.",
"finish": "Bitir",
"genericLinkPlaceholder": "Bağlantıyı buraya yapıştırın",
"importAnother": "Başka Birini İçe Aktar",
"jobId": "İş ID",
"loadingModels": "{type} yükleniyor...",
"maxFileSize": "Maksimum dosya boyutu: {size}",
@@ -1520,6 +1521,7 @@
"Redo": "Yinele",
"Refresh Node Definitions": "Düğüm Tanımlarını Yenile",
"Reinstall": "Yeniden Yükle",
"Rename": "Yeniden Adlandır",
"Reset View": "Görünümü Sıfırla",
"Resize Selected Nodes": "Seçili Düğümleri Yeniden Boyutlandır",
"Restart": "Yeniden Başlat",

View File

@@ -254,6 +254,9 @@
"Comfy_RefreshNodeDefinitions": {
"label": "重新整理節點定義"
},
"Comfy_RenameWorkflow": {
"label": "重新命名工作流程"
},
"Comfy_SaveWorkflow": {
"label": "儲存工作流程"
},

View File

@@ -60,6 +60,7 @@
"findInLibrary": "可在模型庫的 {type} 區段找到。",
"finish": "完成",
"genericLinkPlaceholder": "請在此貼上連結",
"importAnother": "匯入其他",
"jobId": "工作 ID",
"loadingModels": "正在載入 {type}...",
"maxFileSize": "最大檔案大小:{size}",
@@ -1520,6 +1521,7 @@
"Redo": "重做",
"Refresh Node Definitions": "重新整理節點定義",
"Reinstall": "重新安裝",
"Rename": "重新命名",
"Reset View": "重設視圖",
"Resize Selected Nodes": "調整選取節點大小",
"Restart": "重新啟動",

View File

@@ -254,6 +254,9 @@
"Comfy_RefreshNodeDefinitions": {
"label": "刷新节点定义"
},
"Comfy_RenameWorkflow": {
"label": "重命名工作流"
},
"Comfy_SaveWorkflow": {
"label": "保存工作流"
},

View File

@@ -60,6 +60,7 @@
"findInLibrary": "模型在模型库的{type}区里",
"finish": "完成",
"genericLinkPlaceholder": "粘贴链接到这",
"importAnother": "导入其他",
"jobId": "任务ID",
"loadingModels": "正在加载{type}...",
"maxFileSize": "最大文件大小:{size}",
@@ -1520,6 +1521,7 @@
"Redo": "重做",
"Refresh Node Definitions": "刷新节点定义",
"Reinstall": "重装",
"Rename": "重命名",
"Reset View": "重置视图",
"Resize Selected Nodes": "调整选定节点的大小",
"Restart": "重启",

View File

@@ -17,7 +17,7 @@
'gap-2 select-none group',
selected
? 'ring-3 ring-inset ring-modal-card-border-highlighted'
: 'hover:bg-modal-card-background-hovered'
: 'hover:bg-modal-card-background-hovered/20'
)
"
:data-selected="selected"

View File

@@ -2,11 +2,12 @@ import { setActivePinia } from 'pinia'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { nextTick, ref } from 'vue'
import { useNodePointerInteractions } from '@/renderer/extensions/vueNodes/composables/useNodePointerInteractions'
import { useNodeEventHandlers } from '@/renderer/extensions/vueNodes/composables/useNodeEventHandlers'
import { createTestingPinia } from '@pinia/testing'
import { layoutStore } from '@/renderer/core/layout/store/layoutStore'
import type { NodeLayout } from '@/renderer/core/layout/types'
import { useNodeEventHandlers } from '@/renderer/extensions/vueNodes/composables/useNodeEventHandlers'
import { useNodePointerInteractions } from '@/renderer/extensions/vueNodes/composables/useNodePointerInteractions'
import { useNodeDrag } from '@/renderer/extensions/vueNodes/layout/useNodeDrag'
const forwardEventToCanvasMock = vi.fn()

View File

@@ -6,8 +6,8 @@ import { useVueNodeLifecycle } from '@/composables/graph/useVueNodeLifecycle'
import { useCanvasInteractions } from '@/renderer/core/canvas/useCanvasInteractions'
import { layoutStore } from '@/renderer/core/layout/store/layoutStore'
import { useNodeEventHandlers } from '@/renderer/extensions/vueNodes/composables/useNodeEventHandlers'
import { isMultiSelectKey } from '@/renderer/extensions/vueNodes/utils/selectionUtils'
import { useNodeDrag } from '@/renderer/extensions/vueNodes/layout/useNodeDrag'
import { isMultiSelectKey } from '@/renderer/extensions/vueNodes/utils/selectionUtils'
export function useNodePointerInteractions(
nodeIdRef: MaybeRefOrGetter<string>
@@ -65,6 +65,12 @@ export function useNodePointerInteractions(
function onPointermove(event: PointerEvent) {
if (forwardMiddlePointerIfNeeded(event)) return
// Don't handle pointer events when canvas is in panning mode - forward to canvas instead
if (!shouldHandleNodePointerEvents.value) {
forwardEventToCanvas(event)
return
}
// Don't activate drag while resizing
if (layoutStore.isResizingVueNodes.value) return

View File

@@ -293,6 +293,10 @@ export function useSlotLinkInteraction({
raf.cancel()
dragContext.dispose()
clearCompatible()
// Reset litegraph pointer state
if (app.canvas) {
app.canvas.pointer.isDown = false
}
}
const updatePointerState = (event: PointerEvent) => {
@@ -409,6 +413,11 @@ export function useSlotLinkInteraction({
const handlePointerMove = (event: PointerEvent) => {
if (!pointerSession.matches(event)) return
// When in panning mode (read_only), let litegraph handle panning - don't stop propagation
if (app.canvas?.read_only) return
// Not in panning mode - Vue handles link drag, stop propagation to prevent litegraph interference
event.stopPropagation()
dragContext.pendingPointerMove = {
@@ -539,7 +548,10 @@ export function useSlotLinkInteraction({
}
const handlePointerUp = (event: PointerEvent) => {
event.stopPropagation()
// When in panning mode, let litegraph handle - but still cleanup our link drag state
if (!app.canvas?.read_only) {
event.stopPropagation()
}
finishInteraction(event)
}
@@ -584,6 +596,10 @@ export function useSlotLinkInteraction({
if (event.button !== 0) return
if (!nodeId) return
if (pointerSession.isActive()) return
// Don't start link drag if in panning mode - let litegraph handle panning
if (app.canvas?.read_only) return
event.preventDefault()
event.stopPropagation()
@@ -703,6 +719,9 @@ export function useSlotLinkInteraction({
)
pointerSession.begin(event.pointerId)
// Sync pointer state with litegraph so spacebar panning works
canvas.last_mouse = [event.clientX, event.clientY]
canvas.pointer.isDown = true
toCanvasPointerEvent(event)
updatePointerState(event)