Commit Graph

103 Commits

Author SHA1 Message Date
Christian Byrne
598d170d10 [style] update dropdown button text class in Vue node upload widgets (#6062)
## Summary

Change colors to match Figma variables.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-6062-style-update-dropdown-button-text-class-in-Vue-node-upload-widgets-28c6d73d365081ae8857ddcef06784ef)
by [Unito](https://www.unito.io)

---------

Co-authored-by: github-actions <github-actions@github.com>
2025-10-18 02:09:38 -07:00
AustinMroz
15b1b91b16 Implement a legacy canvas widget for vue mode (#6011)
![updated-legacy-widget](https://github.com/user-attachments/assets/3f0a1623-9445-4059-acbb-086baec54980)

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-6011-Implement-a-legacy-canvas-widget-for-vue-mode-2896d73d36508127a5d1debcccb519a0)
by [Unito](https://www.unito.io)

---------

Co-authored-by: GitHub Action <action@github.com>
2025-10-16 18:50:19 -07:00
Christian Byrne
5bc7c8a5c2 add aria labels on vue node widgets (2/2) (#6037)
## Summary

Continuation of https://github.com/Comfy-Org/ComfyUI_frontend/pull/6032

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-6037-add-aria-labels-on-vue-node-widgets-2-2-28b6d73d365081d68795f5dfaca0b89a)
by [Unito](https://www.unito.io)
2025-10-14 11:33:15 -07:00
Christian Byrne
d54923f766 fix FLOAT widget incrementing broken & disabled state styles on widget number input (Vue) (#6036)
## Summary

Align Vue node number widgets with Figma by centralising button styling
and surfacing disabled-state tokens in the design system.

## Changes

- **What**: Added shared
[`useNumberWidgetButtonPt`](src/renderer/extensions/vueNodes/widgets/composables/useNumberWidgetButtonPt.ts)
helper so both PrimeVue `InputNumber` widgets reuse the same Tailwind
token classes, and added the `color/tokens/alpha` values in
[`packages/design-system/src/css/style.css`](packages/design-system/src/css/style.css#L89-L212)
so semantic aliases remain token-driven ([PrimeVue passthrough
docs](https://www.primefaces.org/primevue/passthrough) w
[`color-mix`](https://www.w3.org/TR/css-color-5/#color-mix))

## Review Focus

Confirm hover/active/disabled colours match the design tokens in both
light and dark themes and that float precision still respects the
safe-range guard.

<img width="1377" height="1150" alt="Screenshot from 2025-10-12
17-53-23"
src="https://github.com/user-attachments/assets/c7d34870-5d07-4ce1-9272-7def7ae813b6"
/>

<img width="1377" height="1150" alt="Screenshot from 2025-10-12
17-53-32"
src="https://github.com/user-attachments/assets/86872ec8-979b-4586-879c-41a126a5f932"
/>

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-6036-fix-disabled-state-styles-on-Vue-widget-number-input-INT-and-FLOAT-widgets-28b6d73d365081f8aef7fa860b641f7d)
by [Unito](https://www.unito.io)

---------

Co-authored-by: github-actions <github-actions@github.com>
2025-10-12 23:34:08 -07:00
Christian Byrne
0497421349 add aria labels on vue node widgets (#6032)
## Summary

Adds aria labels to buttons and widgets without pre-existing text
labels.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-6032-add-aria-labels-on-vue-node-widgets-28a6d73d36508198a1c0ef7098ad24e8)
by [Unito](https://www.unito.io)
2025-10-12 17:44:03 -07:00
Christian Byrne
31c85387ba [style] match widget border/outline styles with designs (#6021)
## Summary

Use semantic color variables from
https://github.com/Comfy-Org/ComfyUI_frontend/pull/6018 on widget
borders to match
[design](https://www.figma.com/design/vALUV83vIdBzEsTJAhQgXq/Comfy-Design-System?node-id=2-5739&m=dev)

The layouting of the widgets doesn't align yet, but it's somewhat
annoying to change the `WidgetSelect` height without using line height.
But, the gap should be 4 (16px) instead of 2, the height of the rows
should be 35px instead of 30px and the widgets should be 32px instead of
30px.

## Before

<img width="2061" height="1386" alt="Screenshot from 2025-10-11
12-23-24"
src="https://github.com/user-attachments/assets/5aa7ba1e-9309-4bd5-95b4-8d8e3d95b50b"
/>

<img width="2061" height="1386" alt="Screenshot from 2025-10-11
12-23-16"
src="https://github.com/user-attachments/assets/9dbabd1b-2174-4dfd-83c2-fef8178c7206"
/>

## After

<img width="2061" height="1386" alt="Screenshot from 2025-10-11
12-23-06"
src="https://github.com/user-attachments/assets/d0b0a611-e65b-462f-ad94-c42639502951"
/>

<img width="2061" height="1386" alt="Screenshot from 2025-10-11
12-22-57"
src="https://github.com/user-attachments/assets/64fb42c8-3d9a-4a2b-956f-482fcd63b64c"
/>

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-6021-style-match-widget-border-outline-styles-with-designs-2896d73d365081d18dd9cca41cc2b95e)
by [Unito](https://www.unito.io)

---------

Co-authored-by: github-actions <github-actions@github.com>
2025-10-12 00:32:51 -07:00
Christian Byrne
bc281b2513 [style] make Vue widget/slot/label width and spacing align with designs (#6023)
Make the widths and spacing of the widgets/slots/labels match the
[design](https://www.figma.com/design/31uH3r4x3xbIctuRWYW6NM/V3---Vue-Nodes?node-id=6489-33817&m=dev)
which also better matches the interal layout of litegraph nodes.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-6023-style-make-Vue-widget-slot-label-width-and-spacing-align-with-designs-2896d73d365081a1a831f396cb4eafc8)
by [Unito](https://www.unito.io)

---------

Co-authored-by: github-actions <github-actions@github.com>
2025-10-11 20:08:05 -07:00
AustinMroz
2599136296 Implement DOMWidget for vue (#6006)
![vue-dom-widget](https://github.com/user-attachments/assets/d0c0e5f6-bacb-4fd9-957e-4f19e8071c3d)

Did testing on about a dozen custom nodes. Most just work.
- Some custom nodes have copy/pasted the `addDOMWidget` call with types
like `customtext` and get converted to textareas -> Not feasible to fix
here. Can open PRs into custom nodes if complaints arise.
- Only the KJNodes spline editor had mouse issues -> Can
investigate/open PR into KJNodes later.
- Many nodes don't resize gracefully. Probably best handled in a future
PR.
- Some expect to be handled like textareas. These currently have minsize
and don't scale.
- Others, like VHS previews, scale self properly, but don't update
height inside a drag operation -> node height can be set to less than
fit.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-6006-Implement-DOMWidget-for-vue-2886d73d3650817ca497c15d87d70f4f)
by [Unito](https://www.unito.io)
2025-10-10 14:11:38 -07:00
Johnpaul Chiwetelu
d7796fcda4 Vuenodes/audio widgets (#5627)
This pull request introduces a new audio playback widget for node UIs
and integrates it into the node widget system. The main changes include
the implementation of the `WidgetAudioUI` component, its registration in
the widget registry, and updates to pass node data to the new widget.
Additionally, some logging was added for debugging purposes.

**Audio Widget Implementation and Integration:**

* Added a new `WidgetAudioUI.vue` component that provides audio playback
controls (play/pause, progress slider, volume, options) and loads audio
files from the server based on node data.
* Registered the new `WidgetAudioUI` component in the widget registry by
importing it and adding an entry for the `audioUI` type.
[[1]](diffhunk://#diff-c2a60954f7fdf638716fa1f83e437774d5250e9c99f3aa83c84a1c0e9cc5769bR21)
[[2]](diffhunk://#diff-c2a60954f7fdf638716fa1f83e437774d5250e9c99f3aa83c84a1c0e9cc5769bR112-R115)
* Updated `NodeWidgets.vue` to pass `nodeInfo` as the `node-data` prop
to widgets of type `audioUI`, enabling the widget to access
node-specific audio file information.

**Debugging and Logging:**

* Added logging of `nodeData` in `LGraphNode.vue` and
`WidgetAudioUI.vue` to help with debugging and understanding the data
structure.
[[1]](diffhunk://#diff-a7744614cf842e54416047326db79ad81f7c7ab7bfb66ae2b46f5c73ac7d47f2R188-R189)
[[2]](diffhunk://#diff-71cce190d74c6b5359288857ab9917caededb8cdf1a7e6377578b78aa32be2fcR1-R284)

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-5627-Vuenodes-audio-widgets-2716d73d365081fbbc06c1e6cf4ebf4d)
by [Unito](https://www.unito.io)

---------

Co-authored-by: GitHub Action <action@github.com>
Co-authored-by: Arjan Singh <1598641+arjansingh@users.noreply.github.com>
Co-authored-by: filtered <176114999+webfiltered@users.noreply.github.com>
Co-authored-by: Christian Byrne <cbyrne@comfy.org>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Alexander Brown <drjkl@comfy.org>
Co-authored-by: Jin Yi <jin12cc@gmail.com>
Co-authored-by: DrJKL <DrJKL@users.noreply.github.com>
Co-authored-by: Robin Huang <robin.j.huang@gmail.com>
Co-authored-by: github-actions <github-actions@github.com>
2025-10-09 21:29:06 -07:00
Christian Byrne
06b0eecfe4 fix Vue node widgets should be in disabled state if their slots are connected with a link (#5834)
## Summary

Fixes https://github.com/Comfy-Org/ComfyUI_frontend/issues/5692 by
making widget link connection status trigger on change so Vue widgets
with connected links could properly switch to the `disabled` state when
they are implicitly converted to inputs.

## Changes

- **What**: Added `node:slot-links:changed` event tracking and reactive
slot data synchronization for Vue widgets

```mermaid
graph TD
    A[Widget Link Change] --> B[NodeInputSlot.link setter]
    B --> C{Is Widget Input?}
    C -->|Yes| D[Trigger slot-links:changed]
    C -->|No| E[End]
    D --> F[Graph Event Handler]
    F --> G[syncNodeSlotData]
    G --> H[Update Vue Reactive Data]
    H --> I[Widget Re-render]
    
    style A fill:#f9f9f9,stroke:#333,color:#000
    style I fill:#f9f9f9,stroke:#333,color:#000
```

## Review Focus

Widget reactivity performance with frequent link changes and event
handler memory management in graph operations.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-5834-fix-Vue-node-widgets-should-be-in-disabled-state-if-their-slots-are-connected-with-a-link-27c6d73d365081f6a6c3c1ddc3905c5e)
by [Unito](https://www.unito.io)
2025-10-09 10:30:12 -07:00
Alexander Brown
b943c0fa75 Lint: Add tailwind linter (#5984)
## Summary

Adds the [tailwind lint
plugin](https://github.com/francoismassart/eslint-plugin-tailwindcss/?tab=readme-ov-file#eslint-plugin-tailwindcss)
and fixes the currently fixable rules ([v4 is still in
beta](https://github.com/francoismassart/eslint-plugin-tailwindcss/?tab=readme-ov-file#about-tailwind-css-4-support)).

## Changes

- **What**: Enforces things like consistent class order, and eventually
can prohibit extra classes that could be utilities instead
- **Dependencies**: The plugin and its types

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-5984-Lint-Add-tailwind-linter-2866d73d365081d89db0d998232533bb)
by [Unito](https://www.unito.io)

---------

Co-authored-by: GitHub Action <action@github.com>
2025-10-08 19:39:14 -07:00
Alexander Brown
874ef3ba0c Lint: Add eslint import plugin (#5955)
## Summary

Adds the linter, turns on the recommended and a few extra rules, fixes
existing violations.

Doesn't prohibit `../../...` imports yet, that'll be it's own PR.

## Changes

- **What**: Consistent and fixable imports
- **Dependencies**: The plugin and parser

## Review Focus

How do you feel about the recommended rules?
What about the extra ones?
[Any
more](https://github.com/un-ts/eslint-plugin-import-x?tab=readme-ov-file#rules)
you'd want to turn on?

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-5955-Lint-Add-eslint-import-plugin-2856d73d3650819985c0fb9ca3fa94b0)
by [Unito](https://www.unito.io)
2025-10-07 20:31:00 -07:00
Alexander Brown
99b3a59679 Style: Standardize icon use Part 1 (#5947)
## Summary

Remove the mix of class based and component style icons in favor of just
[classes](https://iconify.design/docs/usage/css/tailwind/tailwind4/#basic-usage).

## Changes

- **What**: Migrate existing lucide icons

## Review Focus

What differs between the icons before and now?

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-5947-Style-Standardize-icon-use-Part-1-2846d73d365081bfa66ceb6bdaa9ff02)
by [Unito](https://www.unito.io)

---------

Co-authored-by: github-actions <github-actions@github.com>
2025-10-07 17:53:38 -07:00
Alexander Brown
e7745eb2be Style: Make components themeable (#5908)
## Summary

Replace color/dark-color pairs in components with design tokens to allow
for easy overriding.
<!-- Also standardizes the icon pattern to simplify the tailwind config.
-->

## Changes

- **What**: Token based colors, for now, mostly.
- **Breaking**: Got approval from Design to collapse some very similar
pairs of colors that seem to have diverged in implementations over time.
Some of the colors might be a little different, but we can tweak them
later.

## Review Focus

Still have quite a few places from which to remove `dark-theme`, but
this at least gets the theming much closer.
Need to decide if I want to keep going in here or cut this and do the
rest in a subsequent PR.

## 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-5908-WIP-Make-components-themeable-2816d73d365081ffbc05d189fe71084b)
by [Unito](https://www.unito.io)

---------

Co-authored-by: github-actions <github-actions@github.com>
2025-10-06 16:27:08 -07:00
Rizumu Ayaka
661885f5e5 feat(widgets): lazy load images in FormDropdown (#5904)
some users may have a very large number of files, so we only need to
request/render the ones that are visible.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-5904-feat-widgets-lazy-load-images-in-FormDropdown-2816d73d36508195b283ff469061f3f3)
by [Unito](https://www.unito.io)

Co-authored-by: Claude <noreply@anthropic.com>
2025-10-03 13:03:36 -07:00
Alexander Brown
b994608506 Tests: Vitest configuration cleanup (#5888)
## Summary

Simplify default scripts. Filtering is still available to users, we can
revisit tagging or grouping later.
This fixes the issue where we had tests that were in the codebase but
never run because they weren't under `/src/components`

Also deletes the duplicate litegraph tests and their associated vitest
config file.

## Changes

- **What**: Test cleanup

## Review Focus

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-5888-Tests-Vitest-configuration-cleanup-2806d73d36508197b800f68f0b028279)
by [Unito](https://www.unito.io)
2025-10-02 21:01:42 -07:00
Simula_r
0d3d258995 Fix/vue nodes video (#5870)
## Summary

Fix the video preview widget and associated dropdown to load and select
videos.

Fixes:
-
https://www.notion.so/comfy-org/Video-thumbnails-not-being-used-in-asset-explorer-dialog-27e6d73d365080ec8a3ee7c7ec413657?source=copy_link
-
https://www.notion.so/comfy-org/Image-Video-upload-dialog-doesnt-set-mime-type-27e6d73d365080c5bffdf08842855ba0?source=copy_link
-
https://www.notion.so/comfy-org/Video-Previews-are-not-displayed-2756d73d365080b2bfb9e0004e9d784d?source=copy_link
-
https://www.notion.so/comfy-org/Cannot-load-video-in-Load-Video-node-2756d73d365080009c21d3a67add96c4?source=copy_link

## Screenshots (if applicable)


https://github.com/user-attachments/assets/b71dbecb-c9a7-4feb-83a3-c3e044a9c93c

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-5870-Fix-vue-nodes-video-27e6d73d36508182b44bef8e90ef4018)
by [Unito](https://www.unito.io)

---------

Co-authored-by: JakeSchroeder <jake@axiom.co>
Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: Jake Schroeder <jake.schroeder@isophex.com>
Co-authored-by: Rizumu Ayaka <rizumu@ayaka.moe>
2025-10-02 13:58:47 -07:00
Rizumu Ayaka
7e4c756258 feat: inputs/outputs filter to widget dropdown (#5894)
related https://github.com/Comfy-Org/ComfyUI_frontend/issues/5827

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-5894-feat-inputs-outputs-filter-to-widget-dropdown-2806d73d365081498d92d0576b7da6a8)
by [Unito](https://www.unito.io)

---------

Co-authored-by: bymyself <cbyrne@comfy.org>
2025-10-02 13:06:08 -07:00
Alexander Brown
37fab21daf Cleanup: YAGNI readonly props, private swap on ComfyApp, Canvas resize events simplification, v-memos on individual instances (#5869)
## Summary

Assorted cleanup opportunities found while working through the Vue node
rendering logic cleanup.

## Review Focus

Am I wrong that the readonly logic was never actually executing because
it was defined as False in GraphCanvas when making each LGraphNode?

Is there an edge case or some other reason that the ResizeObserver
wouldn't work as a single signal to resize the canvas?

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-5869-Cleanup-YAGNI-readonly-props-private-swap-on-ComfyApp-Canvas-resize-events-simplificat-27e6d73d3650811ba1dcf29e8d43091e)
by [Unito](https://www.unito.io)

---------

Co-authored-by: github-actions <github-actions@github.com>
2025-10-02 10:35:10 -07:00
Johnpaul Chiwetelu
01b3aeae68 Prune console.log() (#5867)
Introduce a no-console rule in ESLint configuration and remove existing
console log statements throughout the codebase, replacing some with
warnings or comments.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-5867-Prune-console-log-27e6d73d365081bcbad8c36cfb5b258c)
by [Unito](https://www.unito.io)
2025-10-01 18:34:58 -07:00
Terry Jia
28a779d41a Check if the wheel event is from an element that wants to capture wheel events (#5821)
## Summary

Add generic wheel event capture mechanism for interactive widgets in
vueNodes system to prevent event bubbling to canvas.

  ## Changes

- What: Add event handling logic in LGraphNode.vue and GraphCanvas.vue
that checks for data-capture-wheel attribute to determine whether wheel
events should be forwarded to the canvas
- How it works: Components that need to capture wheel events (like
Three.js scenes) can add data-capture-wheel="true" attribute to prevent
wheel events from bubbling up to the canvas zoom handler

prerequirist for https://github.com/Comfy-Org/ComfyUI_frontend/pull/5765

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-5821-Check-if-the-wheel-event-is-from-an-element-that-wants-to-capture-wheel-events-27b6d73d3650812493b5f13849147e6c)
by [Unito](https://www.unito.io)
2025-09-29 19:51:37 -07:00
Christian Byrne
4b9d448b6c fix style of Select COMBO Vue node widget (#5785)
## Summary

Fixed `WidgetSelect` component styling to match other Vue node widgets
by using shared base styles.

## Changes

- **What**: Replaced hardcoded color classes with `WidgetInputBaseClass`
for consistent styling across Vue node widgets

## Review Focus

Visual consistency with other input widgets in Vue nodes interface and
proper styling inheritance.

## Screenshots (if applicable)

*Before*:

<img width="1645" height="1436" alt="Screenshot from 2025-09-25
18-12-16"
src="https://github.com/user-attachments/assets/0b985616-0cf5-44e3-8459-739d194dec7a"
/>

*After*:

<img width="1645" height="1436" alt="Screenshot from 2025-09-25
18-12-07"
src="https://github.com/user-attachments/assets/235437cf-3e1f-4bc0-8822-26fb8606b437"
/>

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-5785-fix-style-of-Select-COMBO-Vue-node-widget-27a6d73d3650811a959ef8a955274987)
by [Unito](https://www.unito.io)

---------

Co-authored-by: github-actions <github-actions@github.com>
2025-09-27 10:28:26 -07:00
Christian Byrne
75d31f9d57 fix large integer precision handling in Vue int widgets (#5787)
## Summary

Fixed increment/decrement button lockup in number widgets when values
exceed JavaScript's safe integer limit (2^53 - 1).

## Changes

- **What**: Added precision-aware button disabling and user feedback to
`WidgetInputNumberInput` component using
[Number.isSafeInteger()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isSafeInteger)
- We still need to support values greater than 2^53 because they may be
in workflows.

## Review Focus

JavaScript floating-point precision behavior at scale - buttons hide
when arithmetic operations like `value + 1` would be unreliable due to
IEEE 754 limitations. Test coverage includes edge cases (NaN, Infinity)
and boundary conditions at MAX_SAFE_INTEGER.

```mermaid
graph TD
    A[User Input] --> B{Value > 2^53?}
    B -->|No| C[Show Buttons]
    B -->|Yes| D[Hide Buttons]
    D --> E[Show Tooltip]
    E --> F[User Can Still Type]
    
    style A fill:#f9f9f9,stroke:#333,color:#000
    style F fill:#f9f9f9,stroke:#333,color:#000
```

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-5787-fix-large-integer-precision-handling-in-Vue-int-widgets-27a6d73d365081d9ae00e485740cfafb)
by [Unito](https://www.unito.io)
2025-09-26 18:11:41 -07:00
Rizumu Ayaka
c96f719f91 feat: dropdown widgets vue node ui (#5624)
- Load media dropdown widgets
- Load models dropdown widgets

I added a lot of feedback effects during interactions.
I tried my best to break the Dropdown into small components.
To make it more flexible, I provided many configurable props and
v-model.

<img width="1000" alt="CleanShot 2025-09-18 at 01 54 38"
src="https://github.com/user-attachments/assets/1a413078-1547-44b8-8b48-1ce8f8e764b5"
/>

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-5624-feat-dropdown-widgets-vue-node-ui-2716d73d36508115a52bc1fb6d6376d0)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Christian Byrne <cbyrne@comfy.org>
2025-09-26 12:04:39 -07:00
Christian Byrne
a6600aa109 Use localized labels for Vue node slots and inputs/outputs (fallback to names) (#5773)
## Summary

Fixes https://github.com/Comfy-Org/ComfyUI_frontend/issues/5697 by
adding internationalization support for Vue node widget labels and
output slot names with fallback to original names.

## Changes

- **What**: Added `label` field to widget data structures and
`localized_name` support for output slots
- **Breaking**: None - all changes maintain backward compatibility with
fallback to original names

## Review Focus

Translation key resolution for node definitions and proper fallback
chain for widget labels and slot names.

## Screenshots (if applicable)

Observe that there is parity between Litegraph and Vue nodes w.r.t.
localization of labels/names.

<img width="3455" height="1417" alt="Screenshot from 2025-09-25
13-19-54"
src="https://github.com/user-attachments/assets/93ee8fae-3671-4175-a941-6462f942d0f1"
/>

<img width="3455" height="1417" alt="Screenshot from 2025-09-25
13-19-38"
src="https://github.com/user-attachments/assets/9573eb86-d74a-40ed-a0b5-e30afd3da6eb"
/>

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-5773-Use-localized-labels-for-Vue-node-slots-and-inputs-outputs-fallback-to-names-2796d73d365081e08fb7d38464f4aa90)
by [Unito](https://www.unito.io)

---------

Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: Alexander Brown <drjkl@comfy.org>
2025-09-25 19:47:18 -07:00
Christian Byrne
ac93a6ba3f Disable number grouping (thousands comma separators) by default in Vue node number widgets (#5776)
## Summary

Makes the
[useGrouping](https://primevue.org/inputnumber/#api.inputnumber.props.useGrouping)
prop for number widgets disabled by default, aligning with the old UI
(also requested via design). Node authors can still enable if they want
by setting prop explicitly.

## Changes

- **What**: Modified
[WidgetInputNumberInput](https://primevue.org/inputnumber/) to disable
`useGrouping` by default, requiring explicit opt-in via widget options
- **Testing**: Added component tests covering value binding, component
rendering, step calculations, and grouping behavior

## Review Focus

UX impact on existing nodes that may have relied on default grouping
behavior and test coverage for edge cases with precision calculations.

## Screenshots (if applicable)

*Before*:

<img width="1685" height="879" alt="Screenshot from 2025-09-25 11-34-34"
src="https://github.com/user-attachments/assets/432097ab-203d-4f86-8ca0-721b27ee33de"
/>

*After*:

<img width="1951" height="1175" alt="Screenshot from 2025-09-25
11-35-27"
src="https://github.com/user-attachments/assets/74d35b62-612e-4dbf-b6e2-0ac17af03ea1"
/>


┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-5776-Disable-number-grouping-thousands-comma-separators-by-default-in-Vue-node-number-widget-2796d73d365081369ca6c155335d0d57)
by [Unito](https://www.unito.io)

---------

Co-authored-by: DrJKL <448862+DrJKL@users.noreply.github.com>
Co-authored-by: Alexander Brown <drjkl@comfy.org>
Co-authored-by: github-actions <github-actions@github.com>
2025-09-25 17:46:46 -07:00
Simula_r
703de3e669 Fix/vue nodes markdown (#5771)
## Summary

Improve markdown node by making the textarea match the rendered output
width and height.

## Screenshots (if applicable)


https://github.com/user-attachments/assets/4701f947-0a4f-40f3-83c0-94e53cd10106


┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-5771-Fix-vue-nodes-markdown-2796d73d365081129428fe9c38178cc4)
by [Unito](https://www.unito.io)
2025-09-25 13:21:17 -07:00
Simula_r
e4022c455a fix: add LODFallback to markdown widget (#5734)
## Summary

Add LOD fallback to markdown widget

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-5734-fix-add-LODFallback-to-markdown-widget-2776d73d36508128b923d45beab50f03)
by [Unito](https://www.unito.io)

---------

Co-authored-by: JakeSchroeder <jake@axiom.co>
2025-09-23 13:05:15 -07:00
Simula_r
cec1de0147 feat: vue nodes LOD system (#5631)
## Summary

Replaced reactive (Vue-based) widget LOD with CSS visibility control.
Performance doesn't dramatically improve, but we avoid the mount/unmount
overhead during zoom/pan operations. This PR implements the visual
component of LOD—complex widgets that need lifecycle management will be
addressed separately.

### Problem & Solution
Problem: we want LOD to improve rendering performance and visual
feedback but discovered using reactivity in the current setup for it
meant mounting/unmounting caused worse lag than the performance it aimed
to fix. Switching to render all the details all the time but using css
visibility proved to be the best solution. However, it doesn't improve
rendering performance by much because the GPU texture size is the
bottleneck (from TransformPane.vue CSS transforms) and not
rasterization.

Solution: Keep all nodes/widgets mounted, use CSS visibility: hidden for
LOD. Trade memory for performance stability during zoom/pan/drag
operations.

### Technical Decision
We chose Performance > Memory:

- CSS transforms create a single GPU texture whose size depends on node
count, not widget complexity
- Mounting/unmounting hundreds of widgets during zoom = noticeable lag
from Vue VDOM diffing (since all components are mounted all the time
because of viewport culling challenge/trade off see
https://github.com/Comfy-Org/ComfyUI_frontend/pull/5510.)
- CSS visibility changes = no reactivity overhead, smooth interactions
- Result: Similar performance, but without interaction stutters

This is the visual layer only. If we want a hook into the LOD state per
node / widget that would be the next follow up system to implement.

### Next Steps (maybe)
- Chunked (split up single Transform Pane transform layer) when
rendering 1000+ nodes (maybe)
- ~~Selective unmounting API for widgets that register as "expensive"~~
- ~~Client bound hydration system~~

## Screenshots (if applicable)

<!-- Add screenshots or video recording to help explain your changes -->

<img width="1355" height="960" alt="image"
src="https://github.com/user-attachments/assets/41474d1b-9dbe-4240-a8cf-f4c9ff51d8e0"
/>
<img width="1354" height="963" alt="image"
src="https://github.com/user-attachments/assets/9f55edaa-5858-41b9-b6a8-c2d37e1649bd"
/>


┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-5631-feat-vue-nodes-LOD-system-2726d73d365081c6a6c4e14aa634f19c)
by [Unito](https://www.unito.io)

---------

Co-authored-by: github-actions <github-actions@github.com>
2025-09-22 20:05:13 -07:00
Christian Byrne
5e625a5002 [test] add Vue FormSelectButton widget component tests (#5576)
## Summary

Added comprehensive component tests for FormSelectButton widget with 497
test cases covering all interaction patterns and edge cases.

## Changes

- **What**: Created test suite for
[FormSelectButton.vue](https://vuejs.org/guide/scaling-up/testing.html)
component with full coverage of string/number/object options, PrimeVue
compatibility, disabled states, and visual styling
- **Dependencies**: No new dependencies (uses existing vitest,
@vue/test-utils)

## Review Focus

Test completeness covering edge cases like unicode characters, duplicate
values, and objects with missing properties. Verify test helper
functions correctly simulate user interactions.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-5576-Add-Vue-FormSelectButton-widget-component-tests-26f6d73d36508171ae08ee74d0605db2)
by [Unito](https://www.unito.io)

---------

Co-authored-by: DrJKL <DrJKL@users.noreply.github.com>
2025-09-19 00:12:25 -07:00
Christian Byrne
37975e4eac [test] Add component test for image compare widget (#5549)
## Summary

Added comprehensive component test suite for WidgetImageCompare widget
with 410 test assertions covering display, edge cases, and integration
scenarios.

## Changes

- **What**: Created [Vue Test Utils](https://vue-test-utils.vuejs.org/)
test suite for [WidgetImageCompare
component](src/renderer/extensions/vueNodes/widgets/components/WidgetImageCompare.vue)
using [Vitest](https://vitest.dev/) testing framework

## Review Focus

Test coverage completeness for string vs object value handling,
accessibility attribute propagation, and edge case robustness including
malformed URLs and empty states.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-5549-test-Add-component-test-for-image-compare-widget-26e6d73d365081189fe0d010f87d1eec)
by [Unito](https://www.unito.io)

---------

Co-authored-by: DrJKL <DrJKL@users.noreply.github.com>
2025-09-18 13:44:21 -07:00
Alexander Brown
08220d50d9 Lint: Turn on rules that should allow for verbatimModuleSyntax (#5616)
* lint: turn on type import rules setting up for verbatimModuleSyntax

* lint: --fix for type imports
2025-09-16 22:03:41 -07:00
Alexander Brown
6b59f839e0 Devex: Faster linting (#5611)
* devex: Keep the presubmit from wiping the lint cache

* devex: typescript for eslint config

* devex: upgrade lint plugins and dedupe lockfile

* lint: Fix autofixable rules with updated vue linter

* lint: Remove default for required prop

* lint: temporarily disable warnings for missing defaults

* deps: Update vue-tsc

* lint: use the config convenience utility, switch to using projectService

* lint: Fix redundant eslint config blocks and misplaced parser

* lint: Split up parsing options for typescript vs vue files
2025-09-16 19:23:03 -07:00
Christian Byrne
f5b949762d [test] Add Vue node markdown widget component test (#5575)
* add markdown widget test

* [fix] correct test comments from 'is exposed' to 'is not exposed' - addresses review feedback

The TypeScript suppression comments incorrectly stated that properties
were exposed when they should indicate they are not exposed, since
@ts-expect-error is used to access private properties.

Co-authored-by: christian-byrne <christian-byrne@users.noreply.github.com>

---------

Co-authored-by: christian-byrne <christian-byrne@users.noreply.github.com>
2025-09-16 16:06:33 -07:00
Christian Byrne
71ca28a46f [test] Add component test for TreeSelect Vue widget (#5551)
* add tree select widget component test

* [refactor] export TreeNode type from component - addresses review feedback

Co-authored-by: DrJKL <DrJKL@users.noreply.github.com>

* [refactor] move createTreeData to module scope - addresses review feedback

Co-authored-by: DrJKL <DrJKL@users.noreply.github.com>

---------

Co-authored-by: DrJKL <DrJKL@users.noreply.github.com>
2025-09-16 14:40:02 -07:00
Christian Byrne
96a663704f fix prop bindings on Vue nodes' gallery widgets (#5542)
* fix gallery widget navigators binding

* [refactor] improve test structure and type organization - addresses @DrJKL's review feedback

- Move types comment to reference component file (types already exist there)
- Extract helper functions outside describe blocks as pure functions
- Convert to function declarations for better clarity
- Fix 0-indexed vs 1-indexed consistency in test data generation
- Add placeholder for future test constants organization

* [test] Add WidgetTextarea component test with improved structure - addresses @DrJKL's review feedback

- Move helper functions outside describe blocks as pure function declarations
- Fix options type in createMockWidget to use SimplifiedWidget['options'] instead of Partial<TextareaProps>
- Replace emitted\![0] with safer emitted?.[0] optional chaining pattern
- Add comprehensive test coverage for textarea value binding, events, readonly mode, and edge cases

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

Co-Authored-By: Claude <noreply@anthropic.com>

* Update src/renderer/extensions/vueNodes/widgets/components/WidgetGalleria.vue

Co-authored-by: Alexander Brown <drjkl@comfy.org>

* [refactor] export types from component and use 0-indexed numbering - addresses @DrJKL's review feedback

- Export GalleryImage and GalleryValue types from WidgetGalleria.vue component
- Import types in test file instead of redefining them locally
- Change image alt text from 1-indexed to 0-indexed (Image 0, Image 1, etc.)
- Move helper functions outside describe blocks using function declarations
- Add readonly test data constants for better test isolation
- Fix type compatibility issues with readonly arrays

This addresses DrJKL's review comments about:
1. Types being defined in test suite instead of component
2. Helper functions placement and clarity
3. 1-indexed numbering preference
4. Better test organization with readonly constants

* [refactor] implement remaining review feedback - addresses accessibility and factory pattern suggestions

- Fix accessibility: Add descriptive alt text with position context for screen readers
  instead of repetitive "Gallery image" (e.g., "Gallery image 2 of 5")
- Implement factory pattern: Add createGalleriaWrapper() function that takes images,
  creates widget internally, and returns wrapper for cleaner test code
- Update tests to use factory pattern for readonly constant test cases
- Add proper i18n translations for galleryImage and galleryThumbnail
- Use more descriptive alt text following WebAIM accessibility guidelines

Addresses review comments about screen reader accessibility and test factory pattern

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Alexander Brown <drjkl@comfy.org>
2025-09-14 16:31:56 -07:00
Christian Byrne
6e2a3a0d07 [test] Add component test for SelectButton Vue widget (#5530)
* add component test for select button

* [refactor] improve test structure and typing - addresses @DrJKL review comments

- Use proper SimplifiedWidget['options'] type instead of loose object type
- Extract helper functions as module-level function declarations for better organization
- Remove type assertion violation by using proper union type for null/undefined values
- Format code with prettier to maintain consistency

* [refactor] use safer optional chaining in test assertions - addresses @DrJKL's safety preference

Replace emitted\![0] with emitted?.[0] for safer array access in test expectations.
This follows the same pattern as applied to the textarea widget tests for consistency.
2025-09-14 00:20:56 -07:00
Christian Byrne
c7325c4da9 fix: File Upload widget disabled prop treats undefined as true (#5528)
* fix file upload widget disabled prop

* [test] extract createMockWidget to shared test utility - addresses @DrJKL's code replication concern

Creates testUtils.ts with shared createMockWidget and createMockFile functions
to reduce duplication across widget component tests. This ensures consistency
and maintainability of test setup code.

* [test] replace type assertions with type narrowing - addresses @DrJKL's type safety suggestion

Replaces unsafe `as HTMLInputElement` casts with proper instanceof checks
and error throwing. Also refactors File Type Detection tests to use it.for
instead of conditionals to eliminate anti-pattern.

* [feat] use destructuring with default value for readonly prop - addresses @DrJKL's Vue best practice suggestion

Replace manual fallback expressions like `readonly || false` with modern Vue 3
destructuring pattern: `const { readonly = false } = defineProps()`.
This is cleaner than withDefaults() and follows current Vue best practices.

* [test] improve test utilities usage - addresses @DrJKL's additional suggestions

- Replace findComponent with getComponent for better error handling
- Use optional chaining (?.()) instead of conditional checks for cleaner syntax
- Remove unnecessary existence checks since getComponent throws on failure
2025-09-14 00:20:30 -07:00
Christian Byrne
c04af09956 [test] Add component test for Vue Textarea widget (multiline STRING widget) (#5539)
* add component test for textarea widget

* [refactor] improve test structure and typing - addresses @DrJKL's review feedback

- Move helper functions outside describe block for better scoping
- Fix SimplifiedWidget options typing from Partial<TextareaProps> to Record<string, any>
- Replace emitted\![0] with emitted?.[0] for safer optional chaining
- Remove unused TextareaProps import
2025-09-13 23:10:43 -07:00
Christian Byrne
8804755ffa fix: Use generic type in multi-select widget and fix options binding (#5525)
* use generic type and fix options binding

* [refactor] improve type safety in WidgetMultiSelect - addresses review comments

- Simplify array check to use Array.isArray(options?.values)
- Add generic type parameter to useWidgetValue call
- Remove unnecessary type assertion by leveraging TypeScript inference
2025-09-13 21:45:49 -07:00
Christian Byrne
f28ebcac19 Fix Vue slot label colors for light theme (#5529)
* [fix] use stone-200 for Vue slot labels in light theme

Updates Vue node slot label components to use stone-200 color (#828282)
for light theme instead of the previous #888682 color. This improves
theme consistency across the Vue nodes system.

Components updated:
- InputSlot.vue: Input slot labels
- OutputSlot.vue: Output slot labels
- NodeHeader.vue: Collapse/expand icon
- WidgetLayoutField.vue: Widget labels

* Update src/renderer/extensions/vueNodes/components/NodeHeader.vue

Co-authored-by: Alexander Brown <drjkl@comfy.org>

---------

Co-authored-by: Alexander Brown <drjkl@comfy.org>
2025-09-13 21:32:55 -07:00
Christian Byrne
4604bbd669 fix: make Color Picker Widget coerce to HEX with hashtag regardless of format/value in the UI (#5472)
* fix color picker value prefix and add component tests

* test(widgets): make color text assertion specific in WidgetColorPicker.test per review (DrJKL)

* test(widgets): use expect.soft for valid hex colors loop (suggestion by DrJKL)

* test(widgets): normalize color display to single leading # to address review question (AustinMroz)

* feat(widgets): normalize color widget values to #hex across inputs (hex/rgb/hsb); always emit with leading # using colorUtil conversions

* test(widgets): use data-testid selector for color text instead of generic span; add data-testid to component span for robustness

* support hsb|rgb|hex and coerce to hex with hashtag internally

refactor(widgets,utils): format-driven color normalization to lowercase #hex without casts; add typed toHexFromFormat and guards; simplify WidgetColorPicker state and types\n\n- utils: add ColorFormat, HSB/HSV types, isColorFormat/isHSBObject/isHSVObject, toHexFromFormat; reuse parseToRgb/hsbToRgb/rgbToHex\n- widgets: emit normalized #hex, display derived via toHexFromFormat, keep picker native v-model; typed widget options {format?}\n- tests: consolidate colorUtil tests into tests-ui/tests/colorUtil.test.ts; keep conversion + adjustColor suites; selectors robust\n- docs: add PR-5472-change-summary.md explaining changes\n\nAll type checks pass; ready for your final review before push.

refactor(widgets,utils): format-driven color normalization to lowercase #hex without casts; add typed toHexFromFormat and guards; simplify WidgetColorPicker state and types\n\n- utils: add ColorFormat, HSB/HSV types, isColorFormat/isHSBObject/isHSVObject, toHexFromFormat; reuse parseToRgb/hsbToRgb/rgbToHex\n- widgets: emit normalized #hex, display derived via toHexFromFormat, keep picker native v-model; typed widget options {format?}\n- tests: consolidate colorUtil tests into tests-ui/tests/colorUtil.test.ts; keep conversion + adjustColor suites; selectors robust\n- docs: add PR-5472-change-summary.md explaining changes\n\nAll type checks pass; ready for your final review before push.

chore: untrack PR-5472-change-summary.md and ignore locally (keep file on disk)

* fix(utils): use floor in hsbToRgb to match expected hex (#7f0000) for 50% brightness rounding behavior

* test(widgets): restore invalid-format fallback test and use data-testid selector in hex loop; chore: revert .gitignore change (remove PR-5472-change-summary.md entry)

* chore: restore .gitignore to match main (remove local note/comment)

* [refactor] improve color parsing in ColorPicker widget - addresses review feedback

- Use fancy color parsing for initial value normalization per @DrJKL's suggestion
- Simplify onPickerUpdate to trust configured format per @AustinMroz's feedback
- Remove redundant type checking and format guessing logic

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

Co-Authored-By: Claude <noreply@anthropic.com>

* [refactor] simplify color parsing - remove unnecessary helper function

- Remove normalizeColorValue helper and inline null checks
- Remove verbose comments
- Keep the same functionality with cleaner code

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

Co-Authored-By: Claude <noreply@anthropic.com>

* remove unused exports

---------

Co-authored-by: Claude <noreply@anthropic.com>
2025-09-13 19:58:26 -07:00
Christian Byrne
8ae50d140d [test] Add component test for Vue button widget (#5468)
* add component test for button widget

* [move] relocate WidgetButton test to proper directory

Move test from src/ to tests-ui/ directory structure and update import path
to work from new location - addresses review comment about test organization

* [refactor] make widget name optional in mock factory

Add optional name parameter to createMockWidget function for more flexible
test setup - addresses @DrJKL's suggestion about optional parameters

* [refactor] use it.for for parameterized button tests

Replace forEach loops with it.for syntax for testing button severities
and variants - addresses @DrJKL's suggestion for better test structure

* [auto-fix] Apply ESLint and Prettier fixes

* Revert "[move] relocate WidgetButton test to proper directory"

This reverts commit e9f4d57334.

* [test] increase rapid clicks test from 5 to 16

Better test coverage for concurrent click handling

* name click number a shared variable

---------

Co-authored-by: GitHub Action <action@github.com>
2025-09-13 14:51:39 -07:00
Alexander Brown
1845708ddb Component: Vue Widget Slider (new) (#5516)
* feat: Initial shadcn configuration

* component: Add Slider component from shadcn-vue

* deps: Add tw-animate-css

* component: Align slider with Figma styles

* component: Set the step value for the slider, update styles

* fix: update component tests to work with Array of values

* vite: Don't reload dev server for test changes

* component: Swap text for a number input kept in sync with the slider

* cleanup: Don't need the override if the input isn't type="number"

* test: add step size tests

* cleanup: Don't need cn for these

* css: Update token names to match new Figma Variables

* lint: Fix camelCase vs train-case in passthrough

* feat: If the value is deleted, revert to the slider state cc: @PabloWiedemann

* feat: Improve cursor styles, grabbable thumb, clickable track

* lint: temporarily disable some warnings

* feat: Grabbing while sliding (most of the time)
2025-09-12 18:52:18 -07:00
Christian Byrne
169d7404fe fix text prop area type error (#5471) 2025-09-09 22:24:04 -07:00
Rizumu Ayaka
6da2cf7b4d feat: vue based input number widget (#5435)
* feat: vue based input number widget

* fix: remove min and max
2025-09-08 23:34:07 -07:00
Alexander Brown
fa9f5fbca6 Fix: Vue node/widget positioning and scroll issue (#5441)
* [feat] Refactor overlay compatibility into reusable composable

- Create useTransformCompatOverlayProps composable for centralized overlay prop management
- Update Select, MultiSelect, TreeSelect, and FileUpload components to use composable
- Provides appendTo='self' for transform inheritance in CSS-transformed parents
- Enables easy future additions of other transform compatibility props
- Fix duplicate v-bind attributes by combining props into single computed object

* fix: Keep the canvas container from being scrolled by children

* types: Align the appendTo type with primevue internals

* Update test expectations [skip ci]

---------

Co-authored-by: bymyself <cbyrne@comfy.org>
Co-authored-by: github-actions <github-actions@github.com>
2025-09-08 16:05:33 -07:00
Benjamin Lu
0e44a4a354 Remove COMFY_VUE_NODE_DIMENSIONS constant (#5398)
* Remove COMFY_VUE_NODE_DIMENSIONS

* Update litegraph snapshot test
2025-09-08 12:53:42 -07:00
Alexander Brown
9a89869517 lint: Fix missing defaults for Props with Defaults (#5439) 2025-09-08 12:05:49 -07:00
Alexander Brown
6c7adf954a fix: Prevent pointer events on widgets from propagating to the containing node. (#5424) 2025-09-07 18:45:45 -07:00