- Fix deserialization of matchtype inputs spawned by autogrow.
- Rotate multitype slot indicators to align with design changes.
- Fix several instance of incorrect group matching
- MatchType reactively updates input type in vue
- Support the "hollow circle" optional input indicator in vue
- Custom combo sends index of selection to backend
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8026-Further-dynamic-input-fixes-2e76d73d3650819680fef327a94f4294)
by [Unito](https://www.unito.io)
## Summary
Continues the TypeScript strict typing improvements by removing `any`
types from core scripts and dialog components.
### Changes
**api.ts (6 instances)**
- Define `V1RawPrompt` and `CloudRawPrompt` tuple types for queue prompt
formats
- Export `QueueIndex`, `PromptInputs`, `ExtraData`, `OutputsToExecute`
from apiSchema
- Type `#postItem` body, `storeUserData` data, and `getCustomNodesI18n`
return
**groupNodeManage.ts (all @ts-expect-error removed)**
- Add `GroupNodeConfigEntry` interface to LGraph.ts
- Extend `GroupNodeWorkflowData` with `title`, `widgets_values`, and
typed `config`
- Type all class properties with definite assignment assertions
- Type all method parameters and event handlers
- Fix save button callback with proper generic types for node ordering
**changeTracker.ts (4 instances)**
- Type `nodeOutputs` as `Record<string, ExecutedWsMessage['output']>`
- Type prompt callback with `CanvasPointerEvent` and proper value types
**asyncDialog.ts and dialog.ts**
- Make `ComfyAsyncDialog` generic with `DialogAction<T>` type
- Type `ComfyDialog` constructor and show method parameters
- Update `ManageGroupDialog.show` signature to match base class
## Test plan
- [x] `pnpm typecheck` passes
- [x] `pnpm lint` passes
- [x] Sourcegraph checks for external usage
---
Related: Continues from #8083
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8092-Road-to-No-Explicit-Any-Part-7-Scripts-and-Dialog-Cleanup-2ea6d73d365081fbb890e73646a6ad16)
by [Unito](https://www.unito.io)
#8112 updated control widgets to be disabled when the controlled widget
is disabled. However, some workflows already exist that contain a
promoted control widget which does not function. This widget wouldn't be
marked as disabled (and thus, demoted) until the interior subgraph was
entered as updating `computedDisabled` is tacked to node draw. This is
fixed by having subgraphs eagerly update the `computedDisabled` state on
each node when configured.
Additionally, when `createCopyForNode` was used, linkedWidget retained
pointers to widgets which no longer have relation to the newly cloned
widget. This is resolved by instead not copying linkedWidgets.
Functionally, linkedWidgets is only used for control widgets and not
copying has the effect of ensuring that seed widgets linked to a
subgraph input will not display a control popover button in vue mode
which does nothing.
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8160-Control-widget-fixes-2ed6d73d3650816cb397f83f558471b3)
by [Unito](https://www.unito.io)
The parentId property on links and reroutes was not handled at all in
the "Convert to Subgraph" code.
This needs to be addressed in 4 cases
- A new external input link must have parentId set to the first
non-migrated reroute
- A new external output link must have the parentId of it's eldest
remaining child set to undefined
- A new internal input link must have the parentId of it's eldest
remaining child set to undefined
- A new internal output link must have the parentId set to the first
migrated reroute
This is handled in two parts by adding logic where the boundry links is
created
- The change involves mutation of inputs (which isn't great) but the
function here was already mutating inputs into an invalid state
- @DrJKL Do you see a quick way to better fix both these cases?
Looks like litegraph tests aren't enabled and cursory glance shows
multiple need to be updated to reflect recent changes. I'll still try to
add some tests anyways.
EDIT: Tests are non functional. Seems the subgraph conversion call
requires the rest of the frontend is running and has event listeners to
register the subgraph node def. More work than anticipated, best
revisited later
Resolves#5669
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-5708-Migrate-parentIds-when-converting-to-subgraph-2746d73d365081f78acff4454092c74a)
by [Unito](https://www.unito.io)
---------
Co-authored-by: Alexander Brown <drjkl@comfy.org>
#8074 included some refactoring to the asset dialogue to ensure that it
wouldn't pop up multiple times in vue mode
But moving the openModal function to be contained in options means that
`this` is no longer the widget, but instead the options object. This is
fixed by requiring that widget be explicitly passed as a parameter.
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8117-Fix-asset-selection-in-litegraph-2eb6d73d36508176b5a3f6d21964be39)
by [Unito](https://www.unito.io)
Copying a subgraph which contains primitive nodes would cause the
primitives to fail to initialize. This was caused because they did not
have their `onGraphConfigured` and `onAfterGraphConfigured` callbacks
applied.
There's already a copy of `forEachNode` in
`@/utils/graphTraversalUtil.ts`, but the method is small and I want to
avoid litegraph referencing outside code.
See also #6606, where a similar fix was needed
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8094-Fix-copypasted-primitives-inside-subgraphs-2ea6d73d365081f189f1ea4c9248f5ed)
by [Unito](https://www.unito.io)
## Summary
- Remove all remaining `any` types from LiteGraph module
- Define proper `Panel` interface for createPanel function and related
callbacks
- Type `SlotTypeDefaultNodeOpts` for slot type defaults configuration
- Fix type inference issues in sendActionToCanvas and contextMenuCompat
## Changes
- **SubgraphIONodeBase.ts**: Remove unnecessary `as any` cast in
showSlotContextMenu
- **interfaces.ts**: Add Panel, PanelButton, PanelWidget,
PanelWidgetOptions, PanelWidgetCallback types
- **LGraphNode.ts**: Type panel callbacks (onShowCustomPanelInfo,
onAddPropertyToPanel) and onGetPropertyInfo
- **LGraphCanvas.ts**:
- Type node_panel and options_panel as Panel
- Type inner_clicked callback parameters
- Type local variables (nodeNewType, nodeNewOpts, prevent_timeout, iS,
sIn, sOut)
- Add SlotTypeDefaultNodeOpts interface for slot type configuration
- **LGraph.ts**: Fix sendActionToCanvas type inference with proper array
handling
- **contextMenuCompat.ts**: Add null guard for newImpl parameter
## Test plan
- [x] pnpm typecheck passes
- [x] pnpm lint passes
- [x] knip passes (no unused exports)
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7970-Road-to-No-Explicit-Any-Part-4-LiteGraph-Cleanup-2e66d73d3650812c939bf9b2cb0ff2f5)
by [Unito](https://www.unito.io)
---------
Co-authored-by: GitHub Action <action@github.com>
Adds support for entering math inside number widgets in vue mode

Migrates components to simple html elements (div and button) by
borrowing styling from the (reverted) reka-ui migration in #6985. The
existing (evil) litegraph eval code is extracted as a utility function
and reused.
This PR means we're entirely writing our own NumberField.
Also adds support for scrubbing widgets like in litegraph

### Known Issue
- Scrubbing causes text to be highlighted, ~~starting a scrub from
highlighted text will instead drag the text~~.
- It seems this can only be prevented with `pointerdown.prevent`, but
this requires a manual `input.focus()` which does not place the cursor
at location of mouse click.
(Obligatory: _It won't do you a bit of good to review math_)
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7759-Implement-vue-math-2d46d73d365081b9acd4d6422669016e)
by [Unito](https://www.unito.io)
---------
Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: DrJKL <DrJKL0424@gmail.com>
## Summary
- Adds missing `beforeChange()` and `afterChange()` lifecycle calls to
`convertToSubgraph()` method
## Problem
When converting nodes to a subgraph and then pressing Ctrl+Z to undo,
the node positions were being changed from their original locations
instead of being properly restored.
## Root Cause
The `convertToSubgraph()` method in `LGraph.ts` was missing the
`beforeChange()` and `afterChange()` lifecycle calls that are needed for
proper undo/redo state tracking. These calls record the graph state
before and after modifications.
The inverse operation `unpackSubgraph()` already has these calls (see
line 1742), so this is simply matching the existing pattern.
## Solution
Add `beforeChange()` at the start of the method (after validation) and
`afterChange()` before the return.
## Testing
1. Create a workflow with several nodes positioned in specific locations
2. Select 2-3 nodes
3. Right-click → "Convert Selection to Subgraph"
4. Press Ctrl+Z to undo
5. Verify nodes return to their exact original positions
Fixescomfyanonymous/ComfyUI#11514
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7791-fix-add-beforeChange-afterChange-to-convertToSubgraph-for-proper-undo-2d86d73d36508125a2c4e4a412cced4a)
by [Unito](https://www.unito.io)
---------
Co-authored-by: RUiNtheExtinct <deepkarma001@gmail.com>
## Summary
Removes **254** `@ts-expect-error` suppressions through proper type
fixes rather than type assertions.
## Key Changes
### Type System Improvements
- Add `globalDefs` and `groupNodes` types to `ComfyAppWindowExtension`
- Extract interfaces for group node handling (`GroupNodeHandler`,
`InnerNodeOutput`, etc.)
- Add `getHandler()` helper to consolidate GROUP symbol access pattern
### Files Fixed
- **pnginfo.ts**: 39 suppressions removed via proper typing of
workflow/prompt data
- **app.ts**: 39 suppressions removed via interface extraction and type
narrowing
- **Tier 1 files**: 17 suppressions removed (maskeditor, imageDrawer,
groupNode, etc.)
- **groupNode.ts**: Major refactoring with proper interface organization
## Approach
Following established constraints:
- No `any` types
- No `as unknown as T` casts (except legacy API boundaries)
- Priority: Fix actual types > Type narrowing > Targeted suppressions as
last resort
- Prefix unused callback parameters with underscore
- Extract repeated inline types into named interfaces
## Validation
- ✅ `pnpm typecheck` passes
- ✅ `pnpm lint` passes
- ✅ `pnpm knip` passes
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7884-Chore-TypeScript-cleanup-remove-254-ts-expect-error-suppressions-2e26d73d3650812e9b48da203ce1d296)
by [Unito](https://www.unito.io)
---------
Co-authored-by: Amp <amp@ampcode.com>
## Summary
Part 2 of the type safety remediation plan. This PR focuses on the
Litegraph Library Layer as part of the **No Explicit Any** mission.
### Changes
**LiteGraphGlobal.ts:**
- `DEFAULT_GROUP_FONT_SIZE`: Changed from `any` (with no value) to
`number = 24`. The internal fallback was already 24, so the constant was
effectively useless without an assigned value.
- `getParameterNames`: Replace `any` with `unknown` in function
signature
- `extendClass`: Replace deprecated
`__lookupGetter__`/`__defineGetter__` with modern
`Object.getOwnPropertyDescriptor`/`defineProperty` and add proper Record
types
**LGraphNodeProperties.ts:**
- Replace `any` with `unknown` for property values
- Use `Record<string, unknown>` with proper type assertions for dynamic
property access
**types/widgets.ts & BaseWidget.ts:**
- Change `callback` value parameter from `any` to properly typed
(`unknown` in interface, `TWidget['value']` in implementation)
**Consuming code fixes:**
- `previewAny.ts`: Add explicit `boolean` type annotation for callback
value
- `ButtonWidget.ts`: Pass widget value instead of widget instance to
callback (matching the interface signature)
## Breaking Change Analysis (Sourcegraph Verified)
### ButtonWidget callback fix (`this` → `this.value`)
This PR fixes the ButtonWidget callback to pass `value` instead of
`this`, matching the interface definition.
**Verification via Sourcegraph** - all external usages are safe:
-
[comfyui-ollama](https://cs.comfy.org/github.com/stavsap/comfyui-ollama/-/blob/web/js/OllamaNode.js?L84)
- doesn't use callback args
-
[ComfyLab-Pack](https://cs.comfy.org/github.com/bugltd/ComfyLab-Pack/-/blob/dist/js/nodes/list.js?L8)
- doesn't use callback args
-
[ComfyUI_PaintingCoderUtils](https://cs.comfy.org/github.com/jammyfu/ComfyUI_PaintingCoderUtils/-/blob/web/js/click_popup.js?L18)
- doesn't use callback args
-
[ComfyUI-ShaderNoiseKSampler](https://cs.comfy.org/github.com/AEmotionStudio/ComfyUI-ShaderNoiseKSampler/-/blob/web/matrix_button.js?L3055-3056)
- was already working around this bug
---------
Co-authored-by: GitHub Action <action@github.com>
## Summary
Remove 178 `@ts-expect-error` suppressions (935 → 757, 19% reduction) by
fixing underlying type issues instead of suppressing errors.
## Changes
- **What**: Type safety improvements across `src/lib/litegraph/` and
related test files
- Prefix unused callback parameters with `_` instead of suppressing
- Use type intersections for mock methods on real objects
- Use `Partial<T>` for incomplete test objects instead of `as unknown`
- Add non-null assertions after `.toBeDefined()` checks in tests
- Let TypeScript infer vitest fixture parameter types
- **Breaking**: None
## Review Focus
- `LGraphCanvas.ts` has the largest changes (232 lines) — all mechanical
unused parameter fixes
- Test files use type intersection pattern for mocks: `node as
LGraphNode & { mockFn: ... }`
- Removed dead code: `src/platform/cloud/onboarding/auth.ts` (47 lines,
unused)
### Key Files
| File | Change |
|------|--------|
| `LGraphCanvas.ts` | 57 suppressions removed (unused params) |
| `subgraph/__fixtures__/*` | Fixture type improvements |
| `*.test.ts` files | Mock typing with intersections |
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7817-WIP-Chore-Typescript-cleanup-2da6d73d365081d1ade9e09a6c5bf935)
by [Unito](https://www.unito.io)
---------
Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: GitHub Action <action@github.com>
## Summary
Migrates all unit tests from `tests-ui/` to colocate with their source
files in `src/`, improving discoverability and maintainability.
## Changes
- **What**: Relocated all unit tests to be adjacent to the code they
test, following the `<source>.test.ts` naming convention
- **Config**: Updated `vitest.config.ts` to remove `tests-ui` include
pattern and `@tests-ui` alias
- **Docs**: Moved testing documentation to `docs/testing/` with updated
paths and patterns
## Review Focus
- Migration patterns documented in
`temp/plans/migrate-tests-ui-to-src.md`
- Tests use `@/` path aliases instead of relative imports
- Shared fixtures placed in `__fixtures__/` directories
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7811-chore-migrate-tests-from-tests-ui-to-colocate-with-source-files-2da6d73d36508147a4cce85365dee614)
by [Unito](https://www.unito.io)
---------
Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: GitHub Action <action@github.com>
#7435 introduced a tricky regression which will cause extremely small
levels of zoom with nodes spread far apart when in vue mode. I am able
to consistently reproduce this behaviour by
- Being in vue mode
- Swapping to a different tab so that ComfyUI is in the background
- Making a pointless line change to frontend code so that vite forces a
reload
- Waiting ~1 minute to ensure the reload completes
- Swapping back to the ComfyUI tab
From testing, if a reload occurs while the tab is backgrounded, the
canvas has an uninitialized size of 300x150. This PR proposes falling
back to a more sane default width and height of 1920x1080 if it is
detected that the canvas element is unitialized.
| Before | After |
| ------ | ----- |
| <img width="360" alt="before"
src="https://github.com/user-attachments/assets/8e19fc98-7187-4008-98cc-fb5ea3bcdce2"/>
| <img width="360" alt="after"
src="https://github.com/user-attachments/assets/add88614-3451-44df-ae9a-b0b867486459"
/>|
This appears to have consistently good results, but second opinions or
further testing would be appreciated. A more reasonable option (like
skipping this automatic fitView if the canvas has uninitialized size) is
likely to be safer, even if it results in a return of edge cases
resulting in a graph having no nodes in view after load.
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7751-Workaround-for-reload-causing-node-spread-2d36d73d365081b9ae74d5f0e6f436f5)
by [Unito](https://www.unito.io)
Fixes a bug where swapping to a different workflow from the inside of a
subgraph would cause nodes to be in an incorrect position after swapping
back. in vue mode
Prior to an unknown-but-recent PR, all nodes would would stack on the
origin. This PR instead solves the remaining issue where having
`ComfyEnableWorkflowViewRestore` would cause incorrect node positions.
This is done by not delaying the fitView by a frame (which causes it to
occur after the graph is no longer in the configuring state). In order
to accomplish this, the code in LGraphNode has been updated to allow
measuring node bounds without requiring a ctx argument. This arg is only
used to ensure sufficient width for a node's title and is irrelevant
when loading an existing graph.
| Before | After |
| ------ | ----- |
| <img width="360" alt="before"
src="https://github.com/user-attachments/assets/7f73817b-36e9-4400-8342-9e660cb36628"/>
| <img width="360" alt="after"
src="https://github.com/user-attachments/assets/c7ab4b99-2797-4276-9703-58d489cc3eaf"
/>|
See also #7591, which solves similar issues, but does not resolve this
bug.
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7645-Do-not-delay-fit-to-view-on-graph-restore-2ce6d73d36508153972cc7b5948ce375)
by [Unito](https://www.unito.io)
## Summary
Add real-time selection feedback during marquee drag, matching the
behavior users expect from other applications.
## Changes
- Nodes and groups are now selected/deselected instantly as the
selection rectangle moves
- Supports all modifier keys (Shift to add, Alt to subtract) during drag
- Added Comfy.Graph.LiveSelection setting (off by default)
## Rationale
This interaction pattern is standard across virtually all design and
productivity software:
- Operating Systems: Windows Explorer, macOS Finder, and Linux file
managers all show live selection feedback when dragging
- Design Tools: Figma, Sketch, Adobe Illustrator, Photoshop, and Blender
use real-time selection
- IDEs: VS Code, JetBrains IDEs show live selection in file explorers
- Node Editors: Unreal Engine Blueprints, Unity Shader Graph, and
Houdini all support live selection
## Screenshots
https://github.com/user-attachments/assets/8b0c2217-47f9-4422-9cab-cb39e145310c
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7465-live-selection-2c96d73d36508133a4a6f917955d55b3)
by [Unito](https://www.unito.io)
## Summary
- Add `contextMenuConverter.ts` with utilities for converting LiteGraph
context menu items to Vue menu format
- Improve `contextMenuCompat.ts` with set-based diffing for more
reliable legacy extension detection
- Extend `MenuOption`/`SubMenuOption` types with `source`, `disabled`,
`isColorPicker`, and `category` type fields
- Add unit tests for converter functions
## Context
This is foundational work for migrating the node context menu from a
custom Popover-based component to PrimeVue ContextMenu.
The converter provides:
- Menu ordering and section grouping (core items first, then extensions)
- Deduplication with preference for Vue-native items over LiteGraph
items
- Extension categorization with labeled section
- Support for disabled states and color picker submenus
## Test plan
- [x] Unit tests pass for `buildStructuredMenu` (9 tests)
- [x] Unit tests pass for `convertContextMenuToOptions` (7 tests)
- [x] Typecheck passes
- [x] Lint passes
- [x] Knip passes (no unused exports)
## Related
This is PR 1 of 2 for the node context menu migration. PR 2 will wire up
the UI component.
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7113-feat-Add-context-menu-converter-infrastructure-2be6d73d3650816ca6c9d2cf50f10159)
by [Unito](https://www.unito.io)
## Summary
Fixes issue when dragging a group that had inner groups when in vue
mode.
When dragging the outer group in Vue mode:
1. getAllNestedItems(selected) returns ALL items: outer group + inner
groups + nodes
2. moveChildNodesInGroupVueMode loops through all items
3. For outer group G1: calls G1.move(delta, true) then
moveGroupChildren(G1, ...)
4. moveGroupChildren calls G2.move(delta) (no skipChildren) - this moves
G2 AND G2's children!
5. Then the loop reaches G2: calls G2.move(delta, true) - moves G2 again
6. Plus moveGroupChildren(G2, ...) processes G2's children again
This PR fixes it by adding `skipChildren=true` to the `move` call.
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7447-fix-inner-groups-being-moved-double-when-moving-outer-group-in-vue-mode-2c86d73d365081ce97abec682f2a8518)
by [Unito](https://www.unito.io)
## Cause
When graphs are actually exported, several layers of cleanup are
applied. Among these is link compression. Any widgets with inputs that
aren't used do not have inputs stored in the workflow. This was
implemented for backwards compatibility with the old "convert to input"
system for widgets. As part of this process, the target_slots on links
are rewritten such that they point to the index of the widget as if
unconnected widgets did not exist.
This "incorrect" state for links is only corrected AFTER a workflow has
loaded because the 'fix' method needs nodes to be initialized in order
to calculate the correct target_slot
This becomes a problem when subgraphs are introduced. SubgraphInputs
need to resolve a link to its target slot in order to construct a clone
of the linked widget DURING the loading process. Since this target slot
is not accurate, this can result in the cloned widget having the wrong
type.
For a minimal reproduction:
- Create a subgraph with an Empty Latent Image with batch_size linked to
the Subgraph Input
- Export the workflow
- On load, the batch_size has step and min attributes which incorrectly
correspond to width
## Fix
There's multiple possible ways to address this and input on direction is
appreciated
- Fix links before loading graph
- Likely to break with any dynamic state
- Fix links, then load graph again
- Ugly, bad performance, dynamic state may require multiple passes to
correctly ripple
- In the Subgraph code, ignore target_slot and instead `.find()` input
with matching linkId (proposed)
- Promising, but means accepting that state is just wrong sometimes.
Another forever footgun.
- Entirely remove the input compression
- Some people may complain, and old workflows still need to be supported
- Only remove target_slot redirection inside subgraphs
- Creates ugly logical difference between what happens inside and
outside subgraphs.
- Still leaves old workflows broken
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7388-Remove-target_slot-compression-from-subgraph-exports-2c66d73d3650815d8c96c5047958ab67)
by [Unito](https://www.unito.io)
## Summary
Fixes the issue where unpacking a subgraph containing missing nodes
causes those nodes to disappear. Missing nodes are now automatically
restored as placeholder nodes that preserve their original data,
allowing them to be recovered when the node types are installed later.
## Changes
- **What**:
- Modified `multiClone()` to preserve missing nodes as serialized data
when creating subgraphs
- Added `skipMissingNodes` option to `unpackSubgraph()` method to
restore missing nodes as placeholder nodes instead of throwing errors
- Updated `useSubgraphOperations.unpackSubgraph()` to automatically
restore missing nodes as placeholders (removed confirmation dialog)
- Replaced deprecated `LiteGraph.cloneObject()` with `structuredClone()`
- Removed unused i18n keys and debugging logs
## Review Focus
- **Placeholder node restoration**: Missing nodes are restored using the
same mechanism as `LGraph.configure()` (creating `LGraphNode` with
`last_serialization` and `has_errors` flags). This ensures compatibility
with the existing missing node manager.
- **Performance**: Optimized `getMissingNodeTypes()` to check
`registered_node_types` first before attempting node creation, and uses
Set for O(1) duplicate checking.
- **Data preservation**: Missing nodes preserve their original type,
title, and serialized data in `last_serialization`, allowing automatic
recovery when node types are installed.
- **Backward compatibility**: The `skipMissingNodes` option defaults to
`false`, maintaining original behavior for other code paths. Only the
UI-level `unpackSubgraph()` always uses `skipMissingNodes: true`.
<!-- If this PR fixes an issue, uncomment and update the line below -->
<!-- Fixes#7279 -->
## Demo
Before:
https://github.com/user-attachments/assets/e0327d05-802d-4a64-a9db-4d174e185d82
After:
https://github.com/user-attachments/assets/37ab3140-0ada-480e-b9d5-fef8856f8b27
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7341-fix-unpacking-a-missing-node-causes-it-to-disappear-2c66d73d36508151ac6be70a7b2bc56d)
by [Unito](https://www.unito.io)
## Summary
Reduce lower level font definitions in most places. Default to Inter.
See #6912
## Review Focus
Comic Sans is still an option...
## Screenshots (if applicable)
<!-- Add screenshots or video recording to help explain your changes -->
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7220-Style-Font-Consistency-2c26d73d365081348f2dd8909dd9bb8f)
by [Unito](https://www.unito.io)
---------
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: github-actions <github-actions@github.com>
When moving an existing link with subgraphInput as source to a new node,
the prior link is removed, but the previous target node would not have
it's link property cleared.
Resolves#7225
Also re-enables several functional skipped tests.
It feels like I'm having to play whack-a-mole reimplementing the same
fixes on every permutation of subgraphIO links. I'd like to setup up a
unified test set that covers them all, but wouldn't want the added work
to further delay this fix.
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7229-When-moving-subgraphInput-link-properly-disconnect-old-link-2c36d73d36508149aca0ce477fee5c9e)
by [Unito](https://www.unito.io)
Previously the color of a link would simply use the type of the target
slot and fallback to the type of the origin slot. When a connection is
made to a node that accepts the any type ('*'), the link has the green
color of an unknown type.
Instead, when a connection is made, the type of a link is now calculated
as the greatest common type of the source and destination. This means
that connections to reroutes are correctly colored.
| Before | After |
| ------ | ----- |
| <img width="360" alt="before"
src="https://github.com/user-attachments/assets/a5544730-e69a-4c85-af33-b303bb30ae71"
/>| <img width="360" alt="after"
src="https://github.com/user-attachments/assets/7d7b59fd-1b79-440b-a97d-a1657313c484"
/>|
The code for calculating common types already exists, it has simply been
moved into litegraph and given a more descriptive name.
Resolves#7196
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7211-Color-links-as-common-type-2c16d73d365081188460f6b5973db962)
by [Unito](https://www.unito.io)
---------
Co-authored-by: Alexander Brown <drjkl@comfy.org>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Before node v2, you could use getInputPos, getOutputPos. In node v2,
that is not possible.
## Summary
Want to get the position of the output / inputs on the graph like before
node v2.
## Changes
- **What**: <!-- Core functionality added/modified --> Added
LGraphNode.getSlotPosition
## Review Focus
## Screenshots (if applicable)
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7042-Expose-LGraphNode-getSlotPosition-2ba6d73d36508195a0fed2d1fe2b64f6)
by [Unito](https://www.unito.io)
## Summary
Changes the layout store to treat node sizes as body-only measurements
while LiteGraph continues to reason about full heights. DOM-driven
updates are tagged with `LayoutSource.DOM`, which lets the store strip
the title height exactly once before persisting. That classification (a
new mutation source - `LayoutSource.DOM`) is accurate because those
mutations are triggered by the browser’s layout engine via
ResizeObserver, rather than by direct calls into the layout APIs (e.g.,
`moveNodeTo`, `useNodeDrag`). So all sources are:
- `LayoutSource.DOM`: browser layout/ResizeObserver measurements that
include the title bar
- `LayoutSource.Vue`: direct Vue-driven mutations routed through the
layout store
- `LayoutSource.Canvas`: legacy LiteGraph/canvas updates that will be
phased out over time
- `LayoutSource.External`: for multiplayer or syncing with a when going
online after making changes offline (in teams/workspace)
When layout state flows back into LiteGraph we add the title height just
in time for `liteNode.setSize`, so LiteGraph’s rendering stays
unchanged. This makes Vue node resizing and workflow persistence
deterministic - multiline widgets hold their dimensions across reloads
because every path that crosses the layout/LiteGraph boundary performs
the same normalization.
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-6966-normalize-height-at-sites-2b76d73d365081b6bcb4f4ce6a27663a)
by [Unito](https://www.unito.io)
---------
Co-authored-by: github-actions <github-actions@github.com>
This pull request introduces improvements to widget customization and UI
consistency in the application. The most notable changes are the
addition of support for icon classes in widget options, updates to
button rendering logic, and enhanced visual consistency for button
components.
Widget customization enhancements:
* Added an optional `iconClass` property to the `IWidgetOptions`
interface in `widgets.ts`, allowing widgets to specify custom icons.
UI and rendering updates:
* Updated `WidgetButton.vue` to render the widget label and, if
provided, an icon using the new `iconClass` option. Also standardized
button styling and label usage.
* Improved button styling in `WidgetRecordAudio.vue` for better visual
consistency with other components.
<img width="662" height="534" alt="Screenshot 2025-11-25 at 01 36 45"
src="https://github.com/user-attachments/assets/43bbe226-07fd-48be-9b98-78b08a726b1b"
/>
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-6900-Style-button-widgets-2b66d73d3650818ebeadd9315a47ba0f)
by [Unito](https://www.unito.io)