-
Notifications
You must be signed in to change notification settings - Fork 476
feat: Add visual crop preview widget for ImageCrop node - widget ImageCrop #7825
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
📝 WalkthroughWalkthroughAdds image-cropping and bounding-box editing: new Vue components, composables, litegraph widget types and classes, widget registry and scripts, schema and locale keys, a core extension enforcing minimum node sizes, and BaseWidget canvas placeholder support. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant WidgetImageCrop as WidgetImageCrop
participant Composable as useImageCrop
participant Store as NodeOutputStore
User->>WidgetImageCrop: open node panel / interact
WidgetImageCrop->>Composable: init(nodeId) / bind v-model
Composable->>Store: resolve image URL for nodeId
Store-->>Composable: imageUrl
Composable-->>WidgetImageCrop: imageUrl, isLoading, styles
User->>WidgetImageCrop: drag/resize crop box or edit inputs
WidgetImageCrop->>Composable: handleDragStart/Move/End or handleResizeStart/Move/End or handleInputChange
Composable->>Composable: enforce bounds/scale, update crop values
Composable-->>WidgetImageCrop: updated crop region (v-model)
Suggested reviewers
✨ Finishing touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
🎭 Playwright Tests:
|
🎨 Storybook Build Status✅ Build completed successfully! ⏰ Completed at: 01/17/2026, 07:46:59 PM UTC 🔗 Links🎉 Your Storybook is ready for review! |
Bundle Size ReportSummary
Category Glance Per-category breakdownApp Entry Points — 3.36 MB (baseline 3.36 MB) • 🔴 +4 kBMain entry bundles and manifests
Status: 3 added / 3 removed Graph Workspace — 1.14 MB (baseline 1.14 MB) • ⚪ 0 BGraph editor runtime, canvas, workflow orchestration
Status: 1 added / 1 removed Views & Navigation — 6.66 kB (baseline 6.66 kB) • ⚪ 0 BTop-level views, pages, and routed surfaces
Status: 1 added / 1 removed Panels & Settings — 376 kB (baseline 376 kB) • ⚪ 0 BConfiguration panels, inspectors, and settings screens
Status: 6 added / 6 removed UI Components — 208 kB (baseline 203 kB) • 🔴 +4.7 kBReusable component library chunks
Status: 9 added / 8 removed Data & Services — 12.5 kB (baseline 12.5 kB) • ⚪ 0 BStores, services, APIs, and repositories
Status: 2 added / 2 removed Utilities & Hooks — 1.86 kB (baseline 1.86 kB) • ⚪ 0 BHelpers, composables, and utility bundles
Status: 1 added / 1 removed Vendor & Third-Party — 9.34 MB (baseline 9.34 MB) • ⚪ 0 BExternal libraries and shared vendor chunks
Other — 5.4 MB (baseline 5.38 MB) • 🔴 +19.4 kBBundles that do not match a named category
Status: 18 added / 16 removed |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 7
📜 Review details
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (12)
src/components/imagecrop/WidgetImageCrop.vuesrc/composables/useImageCrop.tssrc/extensions/core/imageCrop.tssrc/extensions/core/index.tssrc/lib/litegraph/src/types/widgets.tssrc/lib/litegraph/src/widgets/ImageCropWidget.tssrc/lib/litegraph/src/widgets/widgetMap.tssrc/locales/en/main.jsonsrc/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.tssrc/renderer/extensions/vueNodes/widgets/registry/widgetRegistry.tssrc/schemas/nodeDef/nodeDefSchemaV2.tssrc/scripts/widgets.ts
🧰 Additional context used
📓 Path-based instructions (19)
src/**/*.{vue,ts}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.{vue,ts}: Leverage VueUse functions for performance-enhancing styles
Implement proper error handling
Use vue-i18n in composition API for any string literals. Place new translation entries in src/locales/en/main.json
Files:
src/lib/litegraph/src/types/widgets.tssrc/extensions/core/imageCrop.tssrc/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.tssrc/composables/useImageCrop.tssrc/lib/litegraph/src/widgets/ImageCropWidget.tssrc/schemas/nodeDef/nodeDefSchemaV2.tssrc/scripts/widgets.tssrc/lib/litegraph/src/widgets/widgetMap.tssrc/extensions/core/index.tssrc/components/imagecrop/WidgetImageCrop.vuesrc/renderer/extensions/vueNodes/widgets/registry/widgetRegistry.ts
src/**/*.ts
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.ts: Use es-toolkit for utility functions
Use TypeScript for type safety
Files:
src/lib/litegraph/src/types/widgets.tssrc/extensions/core/imageCrop.tssrc/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.tssrc/composables/useImageCrop.tssrc/lib/litegraph/src/widgets/ImageCropWidget.tssrc/schemas/nodeDef/nodeDefSchemaV2.tssrc/scripts/widgets.tssrc/lib/litegraph/src/widgets/widgetMap.tssrc/extensions/core/index.tssrc/renderer/extensions/vueNodes/widgets/registry/widgetRegistry.ts
src/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
src/**/*.{ts,tsx,vue}: Sanitize HTML with DOMPurify to prevent XSS attacks
Avoid using @ts-expect-error; use proper TypeScript types instead
Use es-toolkit for utility functions instead of other utility libraries
Implement proper TypeScript types throughout the codebase
Files:
src/lib/litegraph/src/types/widgets.tssrc/extensions/core/imageCrop.tssrc/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.tssrc/composables/useImageCrop.tssrc/lib/litegraph/src/widgets/ImageCropWidget.tssrc/schemas/nodeDef/nodeDefSchemaV2.tssrc/scripts/widgets.tssrc/lib/litegraph/src/widgets/widgetMap.tssrc/extensions/core/index.tssrc/components/imagecrop/WidgetImageCrop.vuesrc/renderer/extensions/vueNodes/widgets/registry/widgetRegistry.ts
src/**/*.{vue,ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Follow Vue 3 composition API style guide
Files:
src/lib/litegraph/src/types/widgets.tssrc/extensions/core/imageCrop.tssrc/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.tssrc/composables/useImageCrop.tssrc/lib/litegraph/src/widgets/ImageCropWidget.tssrc/schemas/nodeDef/nodeDefSchemaV2.tssrc/scripts/widgets.tssrc/lib/litegraph/src/widgets/widgetMap.tssrc/extensions/core/index.tssrc/components/imagecrop/WidgetImageCrop.vuesrc/renderer/extensions/vueNodes/widgets/registry/widgetRegistry.ts
src/lib/litegraph/**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (src/lib/litegraph/CLAUDE.md)
src/lib/litegraph/**/*.{js,ts,jsx,tsx}: Run ESLint instead of manually figuring out whitespace fixes or other trivial style concerns using thepnpm lint:fixcommand
Take advantage ofTypedArraysubarraywhen appropriate
Thesizeandposproperties ofRectangleshare the same array buffer (subarray); they may be used to set the rectangle's size and position
Prefer single lineifsyntax over adding curly braces, when the statement has a very concise expression and concise, single line statement
Do not replace&&=or||=with=when there is no reason to do so. If you do find a reason to remove either&&=or||=, leave a comment explaining why the removal occurred
When writing methods, prefer returning idiomatic JavaScriptundefinedovernull
Files:
src/lib/litegraph/src/types/widgets.tssrc/lib/litegraph/src/widgets/ImageCropWidget.tssrc/lib/litegraph/src/widgets/widgetMap.ts
src/lib/litegraph/**/*.{ts,tsx}
📄 CodeRabbit inference engine (src/lib/litegraph/CLAUDE.md)
Type assertions are an absolute last resort. In almost all cases, they are a crutch that leads to brittle code
Files:
src/lib/litegraph/src/types/widgets.tssrc/lib/litegraph/src/widgets/ImageCropWidget.tssrc/lib/litegraph/src/widgets/widgetMap.ts
**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx,vue}: Use TypeScript exclusively; do not write new JavaScript code
Use sorted and grouped imports organized by plugin/source
Enforce ESLint rules including Vue + TypeScript rules, disallow floating promises, disallow unused imports, and restrict i18n raw text in templates
Do not useanytype oras anytype assertions; fix the underlying type issue instead
Write code that is expressive and self-documenting; avoid redundant comments and clean as you go
Keep functions short and functional; minimize nesting and follow the arrow anti-pattern
Avoid mutable state; prefer immutability and assignment at point of declaration
Use function declarations instead of function expressions when possible
Use es-toolkit for utility functions
Implement proper error handling in code
Files:
src/lib/litegraph/src/types/widgets.tssrc/extensions/core/imageCrop.tssrc/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.tssrc/composables/useImageCrop.tssrc/lib/litegraph/src/widgets/ImageCropWidget.tssrc/schemas/nodeDef/nodeDefSchemaV2.tssrc/scripts/widgets.tssrc/lib/litegraph/src/widgets/widgetMap.tssrc/extensions/core/index.tssrc/components/imagecrop/WidgetImageCrop.vuesrc/renderer/extensions/vueNodes/widgets/registry/widgetRegistry.ts
**/*.{ts,tsx,vue,js,jsx,json,css}
📄 CodeRabbit inference engine (AGENTS.md)
Apply Prettier formatting with 2-space indentation, single quotes, no trailing semicolons, and 80-character line width
Files:
src/lib/litegraph/src/types/widgets.tssrc/extensions/core/imageCrop.tssrc/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.tssrc/composables/useImageCrop.tssrc/lib/litegraph/src/widgets/ImageCropWidget.tssrc/locales/en/main.jsonsrc/schemas/nodeDef/nodeDefSchemaV2.tssrc/scripts/widgets.tssrc/lib/litegraph/src/widgets/widgetMap.tssrc/extensions/core/index.tssrc/components/imagecrop/WidgetImageCrop.vuesrc/renderer/extensions/vueNodes/widgets/registry/widgetRegistry.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Minimize the surface area (exported values) of each module and composable
Files:
src/lib/litegraph/src/types/widgets.tssrc/extensions/core/imageCrop.tssrc/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.tssrc/composables/useImageCrop.tssrc/lib/litegraph/src/widgets/ImageCropWidget.tssrc/schemas/nodeDef/nodeDefSchemaV2.tssrc/scripts/widgets.tssrc/lib/litegraph/src/widgets/widgetMap.tssrc/extensions/core/index.tssrc/renderer/extensions/vueNodes/widgets/registry/widgetRegistry.ts
src/**/{services,composables}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
src/**/{services,composables}/**/*.{ts,tsx}: Useapi.apiURL()for backend endpoints instead of constructing URLs directly
Useapi.fileURL()for static file access instead of constructing URLs directly
Files:
src/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.tssrc/composables/useImageCrop.ts
src/**/{composables,components}/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Clean up subscriptions in state management to prevent memory leaks
Files:
src/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.tssrc/composables/useImageCrop.tssrc/components/imagecrop/WidgetImageCrop.vue
src/**/{components,composables}/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Use vue-i18n for ALL user-facing strings by adding them to
src/locales/en/main.json
Files:
src/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.tssrc/composables/useImageCrop.tssrc/components/imagecrop/WidgetImageCrop.vue
**/**/use[A-Z]*.ts
📄 CodeRabbit inference engine (AGENTS.md)
Name composables using the pattern
useXyz.ts
Files:
src/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.tssrc/composables/useImageCrop.ts
src/**/index.ts
📄 CodeRabbit inference engine (AGENTS.md)
Do not use barrel files (e.g.,
/some/package/index.ts) to re-export within/src
Files:
src/extensions/core/index.ts
src/**/*.vue
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.vue: Use the Vue 3 Composition API instead of the Options API when writing Vue components (exception: when overriding or extending PrimeVue components for compatibility)
Use setup() function for component logic
Utilize ref and reactive for reactive state
Implement computed properties with computed()
Use watch and watchEffect for side effects
Implement lifecycle hooks with onMounted, onUpdated, etc.
Utilize provide/inject for dependency injection
Use vue 3.5 style of default prop declaration
Use Tailwind CSS for styling
Implement proper props and emits definitions
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Follow Vue 3 style guide and naming conventions
Files:
src/components/imagecrop/WidgetImageCrop.vue
src/components/**/*.vue
📄 CodeRabbit inference engine (src/components/CLAUDE.md)
src/components/**/*.vue: Use setup() function in Vue 3 Composition API
Destructure props using Vue 3.5 style in Vue components
Use ref/reactive for state management in Vue 3 Composition API
Implement computed() for derived state in Vue 3 Composition API
Use provide/inject for dependency injection in Vue components
Prefer emit/@event-name for state changes over other communication patterns
Use defineExpose only for imperative operations (such as form.validate(), modal.open())
Replace PrimeVue Dropdown component with Select
Replace PrimeVue OverlayPanel component with Popover
Replace PrimeVue Calendar component with DatePicker
Replace PrimeVue InputSwitch component with ToggleSwitch
Replace PrimeVue Sidebar component with Drawer
Replace PrimeVue Chips component with AutoComplete with multiple enabled
Replace PrimeVue TabMenu component with Tabs without panels
Replace PrimeVue Steps component with Stepper without panels
Replace PrimeVue InlineMessage component with Message
Extract complex conditionals to computed properties
Implement cleanup for async operations in Vue components
Use lifecycle hooks: onMounted, onUpdated in Vue 3 Composition API
Use Teleport/Suspense when needed for component rendering
Define proper props and emits definitions in Vue components
Files:
src/components/imagecrop/WidgetImageCrop.vue
src/components/**/*.{vue,css}
📄 CodeRabbit inference engine (src/components/CLAUDE.md)
src/components/**/*.{vue,css}: Use Tailwind CSS only for styling (no custom CSS)
Use the correct tokens from style.css in the design system package
Files:
src/components/imagecrop/WidgetImageCrop.vue
src/components/**/*.{vue,ts,js}
📄 CodeRabbit inference engine (src/components/CLAUDE.md)
src/components/**/*.{vue,ts,js}: Use existing VueUse composables (such as useElementHover) instead of manually managing event listeners
Use useIntersectionObserver for visibility detection instead of custom scroll handlers
Use vue-i18n for ALL UI strings
Files:
src/components/imagecrop/WidgetImageCrop.vue
**/*.vue
📄 CodeRabbit inference engine (AGENTS.md)
**/*.vue: Use Vue 3.5+ with TypeScript in.vuefiles, exclusively using Composition API with<script setup lang="ts">syntax
Use Tailwind 4 for styling in Vue components; avoid<style>blocks
Name Vue components using PascalCase (e.g.,MenuHamburger.vue)
Use Vue 3.5 TypeScript-style default prop declaration with reactive props destructuring; do not usewithDefaultsor runtime props declaration
Prefercomputed()overrefwithwatchwhen deriving values
PreferuseModelover separately defining prop and emit for two-way binding
Usevue-i18nin composition API for string literals; place new translation entries insrc/locales/en/main.json
Usecn()utility function from@/utils/tailwindUtilfor merging Tailwind class names; do not use:class="[]"syntax
Do not use thedark:Tailwind variant; use semantic values from thestyle.csstheme instead (e.g.,bg-node-component-surface)
Do not use!importantor the!important prefix for Tailwind classes; find and correct interfering!importantclasses instead
Avoid new usage of PrimeVue components; use VueUse, shadcn/vue, or Reka UI instead
Leverage VueUse functions for performance-enhancing styles in Vue components
Implement proper props and emits definitions in Vue components
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Follow Vue 3 style guide and naming conventions
Files:
src/components/imagecrop/WidgetImageCrop.vue
🧠 Learnings (20)
📓 Common learnings
Learnt from: simula-r
Repo: Comfy-Org/ComfyUI_frontend PR: 7252
File: src/renderer/extensions/vueNodes/components/ImagePreview.vue:151-158
Timestamp: 2025-12-11T03:55:57.926Z
Learning: In src/renderer/extensions/vueNodes/components/ImagePreview.vue and LGraphNode.vue, keyboard navigation for image galleries should respond to node-level focus (via keyEvent injection from LGraphNode), not require focus within the image preview wrapper itself. This allows users to navigate the gallery with arrow keys immediately when the node is focused/selected.
📚 Learning: 2025-12-09T03:39:54.501Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7169
File: src/platform/remote/comfyui/jobs/jobTypes.ts:1-107
Timestamp: 2025-12-09T03:39:54.501Z
Learning: In the ComfyUI_frontend project, Zod is on v3.x. Do not suggest Zod v4 standalone validators (z.uuid, z.ulid, z.cuid2, z.nanoid) until an upgrade to Zod 4 is performed. When reviewing TypeScript files (e.g., src/platform/remote/comfyui/jobs/jobTypes.ts) validate against Zod 3 capabilities and avoid introducing v4-specific features; flag any proposal to upgrade or incorporate v4-only validators and propose staying with compatible 3.x patterns.
Applied to files:
src/lib/litegraph/src/types/widgets.tssrc/extensions/core/imageCrop.tssrc/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.tssrc/composables/useImageCrop.tssrc/lib/litegraph/src/widgets/ImageCropWidget.tssrc/schemas/nodeDef/nodeDefSchemaV2.tssrc/scripts/widgets.tssrc/lib/litegraph/src/widgets/widgetMap.tssrc/extensions/core/index.tssrc/renderer/extensions/vueNodes/widgets/registry/widgetRegistry.ts
📚 Learning: 2025-12-13T11:03:11.264Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7416
File: src/stores/imagePreviewStore.ts:5-7
Timestamp: 2025-12-13T11:03:11.264Z
Learning: In the ComfyUI_frontend repository, lint rules require keeping 'import type' statements separate from non-type imports, even if importing from the same module. Do not suggest consolidating them into a single import statement. Ensure type imports remain on their own line (import type { ... } from 'module') and regular imports stay on separate lines.
Applied to files:
src/lib/litegraph/src/types/widgets.tssrc/extensions/core/imageCrop.tssrc/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.tssrc/composables/useImageCrop.tssrc/lib/litegraph/src/widgets/ImageCropWidget.tssrc/schemas/nodeDef/nodeDefSchemaV2.tssrc/scripts/widgets.tssrc/lib/litegraph/src/widgets/widgetMap.tssrc/extensions/core/index.tssrc/renderer/extensions/vueNodes/widgets/registry/widgetRegistry.ts
📚 Learning: 2025-12-17T00:40:09.635Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.stories.ts:45-55
Timestamp: 2025-12-17T00:40:09.635Z
Learning: Prefer pure function declarations over function expressions (e.g., use function foo() { ... } instead of const foo = () => { ... }) for pure functions in the repository. Function declarations are more functional-leaning, offer better hoisting clarity, and can improve readability and tooling consistency. Apply this guideline across TypeScript files in Comfy-Org/ComfyUI_frontend, including story and UI component code, except where a function expression is semantically required (e.g., callbacks, higher-order functions with closures).
Applied to files:
src/lib/litegraph/src/types/widgets.tssrc/extensions/core/imageCrop.tssrc/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.tssrc/composables/useImageCrop.tssrc/lib/litegraph/src/widgets/ImageCropWidget.tssrc/schemas/nodeDef/nodeDefSchemaV2.tssrc/scripts/widgets.tssrc/lib/litegraph/src/widgets/widgetMap.tssrc/extensions/core/index.tssrc/renderer/extensions/vueNodes/widgets/registry/widgetRegistry.ts
📚 Learning: 2025-12-30T22:22:33.836Z
Learnt from: kaili-yang
Repo: Comfy-Org/ComfyUI_frontend PR: 7805
File: src/composables/useCoreCommands.ts:439-439
Timestamp: 2025-12-30T22:22:33.836Z
Learning: When accessing reactive properties from Pinia stores in TypeScript files, avoid using .value on direct property access (e.g., useStore().isOverlayExpanded). Pinia auto-wraps refs when accessed directly, returning the primitive value. The .value accessor is only needed when destructuring store properties or when using storeToRefs().
Applied to files:
src/lib/litegraph/src/types/widgets.tssrc/extensions/core/imageCrop.tssrc/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.tssrc/composables/useImageCrop.tssrc/lib/litegraph/src/widgets/ImageCropWidget.tssrc/schemas/nodeDef/nodeDefSchemaV2.tssrc/scripts/widgets.tssrc/lib/litegraph/src/widgets/widgetMap.tssrc/extensions/core/index.tssrc/renderer/extensions/vueNodes/widgets/registry/widgetRegistry.ts
📚 Learning: 2025-12-11T12:25:15.470Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7358
File: src/components/dialog/content/signin/SignUpForm.vue:45-54
Timestamp: 2025-12-11T12:25:15.470Z
Learning: This repository uses CI automation to format code (pnpm format). Do not include manual formatting suggestions in code reviews for Comfy-Org/ComfyUI_frontend. If formatting issues are detected, rely on the CI formatter or re-run pnpm format. Focus reviews on correctness, readability, performance, accessibility, and maintainability rather than style formatting.
Applied to files:
src/lib/litegraph/src/types/widgets.tssrc/extensions/core/imageCrop.tssrc/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.tssrc/composables/useImageCrop.tssrc/lib/litegraph/src/widgets/ImageCropWidget.tssrc/schemas/nodeDef/nodeDefSchemaV2.tssrc/scripts/widgets.tssrc/lib/litegraph/src/widgets/widgetMap.tssrc/extensions/core/index.tssrc/components/imagecrop/WidgetImageCrop.vuesrc/renderer/extensions/vueNodes/widgets/registry/widgetRegistry.ts
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.{vue,ts,js} : Use existing VueUse composables (such as useElementHover) instead of manually managing event listeners
Applied to files:
src/composables/useImageCrop.tssrc/scripts/widgets.ts
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.{vue,ts} : Leverage VueUse functions for performance-enhancing styles
Applied to files:
src/composables/useImageCrop.tssrc/scripts/widgets.ts
📚 Learning: 2025-12-09T04:35:43.971Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 6300
File: src/locales/en/main.json:774-780
Timestamp: 2025-12-09T04:35:43.971Z
Learning: In the Comfy-Org/ComfyUI_frontend repository, locale files other than `src/locales/en/main.json` are generated automatically on every release. Developers only need to add English (en) key/values in `src/locales/en/main.json` when making PRs; manual updates to other locale files (fr, ja, ko, ru, zh, zh-TW, es, ar, tr, etc.) are not required and should not be suggested in reviews.
Applied to files:
src/locales/en/main.json
📚 Learning: 2025-11-24T19:47:34.324Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:34.324Z
Learning: Applies to src/**/{components,composables}/**/*.{ts,tsx,vue} : Use vue-i18n for ALL user-facing strings by adding them to `src/locales/en/main.json`
Applied to files:
src/locales/en/main.json
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*.vue : Leverage VueUse functions for performance-enhancing styles in Vue components
Applied to files:
src/scripts/widgets.ts
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*.vue : Avoid new usage of PrimeVue components; use VueUse, shadcn/vue, or Reka UI instead
Applied to files:
src/scripts/widgets.ts
📚 Learning: 2025-12-09T03:49:52.828Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 6300
File: src/platform/updates/components/WhatsNewPopup.vue:5-13
Timestamp: 2025-12-09T03:49:52.828Z
Learning: In Vue files across the ComfyUI_frontend repo, when a button is needed, prefer the repo's common button components from src/components/button/ (IconButton.vue, TextButton.vue, IconTextButton.vue) over plain HTML <button> elements. These components wrap PrimeVue with the project’s design system styling. Use only the common button components for consistency and theming, and import them from src/components/button/ as needed.
Applied to files:
src/components/imagecrop/WidgetImageCrop.vue
📚 Learning: 2025-12-09T21:40:12.361Z
Learnt from: benceruleanlu
Repo: Comfy-Org/ComfyUI_frontend PR: 7297
File: src/components/actionbar/ComfyActionbar.vue:33-43
Timestamp: 2025-12-09T21:40:12.361Z
Learning: In Vue single-file components, allow inline Tailwind CSS class strings for static classes and avoid extracting them into computed properties solely for readability. Prefer keeping static class names inline for simplicity and performance. For dynamic or conditional classes, use Vue bindings (e.g., :class) to compose classes.
Applies to all Vue files in the repository (e.g., src/**/*.vue) where Tailwind utilities are used for static styling.
Applied to files:
src/components/imagecrop/WidgetImageCrop.vue
📚 Learning: 2025-12-16T22:26:49.463Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.vue:17-17
Timestamp: 2025-12-16T22:26:49.463Z
Learning: In Vue 3.5+ with <script setup>, when using defineProps<Props>() with partial destructuring (e.g., const { as = 'button', class: customClass = '' } = defineProps<Props>() ), props that are not destructured (e.g., variant, size) stay accessible by name in the template scope. This pattern is valid: you can destructure only a subset of props for convenience while referencing the remaining props directly in template expressions. Apply this guideline to Vue components across the codebase (all .vue files).
Applied to files:
src/components/imagecrop/WidgetImageCrop.vue
📚 Learning: 2025-12-22T21:36:08.369Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7649
File: src/platform/cloud/subscription/components/PricingTable.vue:185-201
Timestamp: 2025-12-22T21:36:08.369Z
Learning: In Vue components, avoid creating single-use variants for common UI components (e.g., Button and other shared components). Aim for reusable variants that cover multiple use cases. It’s acceptable to temporarily mix variant props with inline Tailwind classes when a styling need is unique to one place, but plan and consolidate into shared, reusable variants as patterns emerge across the codebase.
Applied to files:
src/components/imagecrop/WidgetImageCrop.vue
📚 Learning: 2025-12-18T02:07:38.870Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7598
File: src/components/sidebar/tabs/AssetsSidebarTab.vue:131-131
Timestamp: 2025-12-18T02:07:38.870Z
Learning: Tailwind CSS v4 safe utilities (e.g., items-center-safe, justify-*-safe, place-*-safe) are allowed in Vue components under src/ and in story files. Do not flag these specific safe variants as invalid when reviewing code in src/**/*.vue or related stories.
Applied to files:
src/components/imagecrop/WidgetImageCrop.vue
📚 Learning: 2025-12-18T21:15:46.862Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7603
File: src/components/queue/QueueOverlayHeader.vue:49-59
Timestamp: 2025-12-18T21:15:46.862Z
Learning: In the ComfyUI_frontend repository, for Vue components, do not add aria-label to buttons that have visible text content (e.g., buttons containing <span> text). The visible text provides the accessible name. Use aria-label only for elements without visible labels (e.g., icon-only buttons). If a button has no visible label, provide a clear aria-label or associate with an aria-labelledby describing its action.
Applied to files:
src/components/imagecrop/WidgetImageCrop.vue
📚 Learning: 2025-12-21T01:06:02.786Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7649
File: src/components/graph/selectionToolbox/ColorPickerButton.vue:15-18
Timestamp: 2025-12-21T01:06:02.786Z
Learning: In Comfy-Org/ComfyUI_frontend, in Vue component files, when a filled icon is required (e.g., 'pi pi-circle-fill'), you may mix PrimeIcons with Lucide icons since Lucide lacks filled variants. This mixed usage is acceptable when one icon library does not provide an equivalent filled icon. Apply consistently across Vue components in the src directory where icons are used, and document the rationale when a mixed approach is chosen.
Applied to files:
src/components/imagecrop/WidgetImageCrop.vue
📚 Learning: 2025-12-18T16:03:02.066Z
Learnt from: henrikvilhelmberglund
Repo: Comfy-Org/ComfyUI_frontend PR: 7617
File: src/components/actionbar/ComfyActionbar.vue:301-308
Timestamp: 2025-12-18T16:03:02.066Z
Learning: In the ComfyUI frontend queue system, useQueuePendingTaskCountStore().count indicates the number of tasks in the queue, where count = 1 means a single active/running task and count > 1 means there are pending tasks in addition to the active task. Therefore, in src/components/actionbar/ComfyActionbar.vue, enable the 'Clear Pending Tasks' button only when count > 1 to avoid clearing the currently running task. The active task should be canceled using the 'Cancel current run' button instead. This rule should be enforced via a conditional check on the queue count, with appropriate disabled/aria-disabled states for accessibility, and tests should verify behavior for count = 1 and count > 1.
Applied to files:
src/components/imagecrop/WidgetImageCrop.vue
🧬 Code graph analysis (5)
src/extensions/core/imageCrop.ts (1)
src/services/extensionService.ts (1)
useExtensionService(16-215)
src/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.ts (3)
src/scripts/widgets.ts (1)
ComfyWidgetConstructorV2(31-34)src/lib/litegraph/src/types/widgets.ts (1)
IImageCropWidget(266-272)src/schemas/nodeDef/nodeDefSchemaV2.ts (1)
ImageCropInputSpec(180-180)
src/lib/litegraph/src/widgets/ImageCropWidget.ts (3)
src/lib/litegraph/src/litegraph.ts (1)
BaseWidget(147-147)src/lib/litegraph/src/types/widgets.ts (1)
IImageCropWidget(266-272)src/lib/litegraph/src/widgets/BaseWidget.ts (2)
DrawWidgetOptions(14-19)WidgetEventOptions(30-34)
src/scripts/widgets.ts (1)
src/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.ts (1)
useImageCropWidget(9-26)
src/lib/litegraph/src/widgets/widgetMap.ts (2)
src/lib/litegraph/src/widgets/ImageCropWidget.ts (1)
ImageCropWidget(9-47)src/lib/litegraph/src/utils/type.ts (1)
toClass(13-18)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: deploy-and-comment
- GitHub Check: test
- GitHub Check: lint-and-format
- GitHub Check: setup
- GitHub Check: collect
🔇 Additional comments (29)
src/locales/en/main.json (1)
1679-1683: LGTM!The new locale entries follow the established pattern and provide appropriate i18n keys for the image crop widget. Good inclusion of
cropPreviewAltfor accessibility.src/composables/useImageCrop.ts (11)
1-28: LGTM!Good use of
useResizeObserverfrom VueUse as per coding guidelines. Type imports are properly separated, and the interface is well-defined.
30-66: LGTM!State management is well-organized with clear separation between image metrics, crop region, drag state, and resize state.
90-108: LGTM!The image URL retrieval logic correctly uses optional chaining and safely handles missing nodes or URLs by returning
null.
110-147: LGTM!The dimension calculation correctly handles aspect ratio fitting with appropriate guards against division by zero.
149-165: LGTM!Good handling of CSS transforms by comparing
getBoundingClientRecttoclientWidthfor accurate scale calculation during drag operations.
196-281: LGTM!Resize handles are well-structured with appropriate cursor classes and positioning. Good use of
Math.max(0, ...)to prevent negative dimensions when crop area is small.
283-295: LGTM!Event handlers correctly manage loading state and error recovery.
297-340: LGTM!Drag implementation correctly uses pointer capture for reliable tracking and properly clamps coordinates to image bounds.
358-414: LGTM!The resize logic correctly handles all 8 directions with proper bounds clamping and minimum size enforcement. The left/top edge handling that adjusts both position and size is implemented correctly.
454-477: LGTM!The composable exposes a clean, well-organized API with all necessary reactive values and event handlers for the component.
174-183: No action needed. TheimageUrlis properly constructed usingapi.apiURL(), which is the recommended approach for backend endpoints per coding guidelines. Image data originates from internal node outputs throughURLSearchParamsand the trusted API utility, not from user input, making CSS injection a non-issue.Likely an incorrect or invalid review comment.
src/lib/litegraph/src/widgets/widgetMap.ts (3)
21-21: LGTM!Import follows alphabetical ordering and existing patterns.
54-54: LGTM!Type mapping entry follows the established pattern.
125-126: LGTM!Switch case follows the same pattern as other widget types (e.g.,
imagecompare,asset).src/extensions/core/index.ts (1)
13-13: LGTM!Extension import follows the established alphabetical ordering pattern.
src/schemas/nodeDef/nodeDefSchemaV2.ts (3)
67-72: LGTM!The schema follows the established pattern (matching
zImageCompareInputSpec) and uses valid Zod v3 syntax.
136-136: LGTM!Union membership correctly placed.
180-180: LGTM!Type export follows the established pattern.
src/scripts/widgets.ts (2)
17-17: LGTM!Import follows alphabetical ordering and existing patterns.
299-299: LGTM!Widget registration follows the established pattern, using
transformWidgetConstructorV2ToV1consistently with other V2 widgets likeIMAGECOMPARE.src/extensions/core/imageCrop.ts (1)
1-11: The extension correctly enforces minimum node dimensions for the ImageCrop widget to ensure adequate space for the crop UI. The pattern matches other core extensions.The
'ImageCrop'comfyClass name is correct and matches the backend node definition, as confirmed by node definition entries across multiple locales.src/renderer/extensions/vueNodes/widgets/registry/widgetRegistry.ts (2)
57-59: LGTM!The async component import follows the established pattern used by other widgets in this registry.
163-171: LGTM!The widget registration follows the existing convention with appropriate type, alias, and
essential: falsesetting for this specialized widget.src/lib/litegraph/src/types/widgets.ts (2)
257-272: LGTM!The
CropRegionValueinterface andIImageCropWidgettype definition follow the established patterns for widget types in this file. The interface properly extendsIBaseWidgetwith appropriate generic parameters.
85-85: LGTM!The
IImageCropWidgetis correctly added to the discriminated union type.src/lib/litegraph/src/widgets/ImageCropWidget.ts (1)
44-46: LGTM!The no-op
onClickis appropriate for a Vue-only widget where interactions are handled by the Vue component.src/components/imagecrop/WidgetImageCrop.vue (2)
81-101: LGTM!The crop box and resize handle implementation with pointer event handlers is well-structured. The conditional rendering with
v-ifandv-showis appropriate for the different elements.
52-79: LGTM!Good use of i18n for user-facing strings in loading, empty, and alt text states. The image element properly prevents default drag behavior and handles load/error events.
|
If possible, I would request adding a ratio input which accepts values like "1.00" or "16:9" to lock the aspect ratio while resizing/dragging. I do a lot of crop work and it is a huge time saver. The current best custom implementation of visual crop is here, if you want to take a look. Yours is less visually cluttered though, which I like! |
|
Lets say i detect a face in some image and get bbox location, i want to crop that location from the image, do some sampling and return that crop back to the original image. How can i do it with this node if only input and output are image and no other data? |
91fc236 to
bc6c542
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 8
🤖 Fix all issues with AI Agents
In @src/components/imagecrop/WidgetImageCrop.vue:
- Around line 81-90: Make the crop box keyboard-accessible: add tabindex="0" and
a focus-visible style to the crop box div (the same element using
:style="cropBoxStyle") and wire an @keydown handler that calls a new
handleKeyboardMove function; implement handleKeyboardMove in the composable that
responds to ArrowUp/Down/Left/Right (preventDefault), computes a small nudge
delta (e.g., 1px or 1 unit, shift for larger step), and updates the same
state/update logic used by handleDragMove/handleDragEnd so keyboard moves behave
identically and remain constrained within image bounds; ensure focus cleanup if
needed and keep naming consistent with
handleDragStart/handleDragMove/handleDragEnd.
- Around line 112-117: The CropRegion type declared in WidgetImageCrop.vue
duplicates the existing CropRegionValue type from
'@/lib/litegraph/src/types/widgets'; instead of a local declaration, import
CropRegionValue and re-export or alias it (e.g., type CropRegion =
CropRegionValue) so there is a single source of truth; update any local
references to use the imported/aliased symbol and remove the duplicate
CropRegion declaration.
- Around line 119-121: Replace the current props object with Vue 3.5 reactive
destructuring: instead of const props = defineProps<{ nodeId: NodeId }>(), call
defineProps with the same type and destructure nodeId directly (i.e., use the
destructured nodeId from defineProps) so the component uses the reactive prop
binding; update all usages that reference props.nodeId to use nodeId.
In @src/composables/useImageCrop.ts:
- Around line 434-444: The deep watchers are monitoring entire stores
(nodeOutputStore.nodeOutputs and nodeOutputStore.nodePreviewImages), causing
unnecessary updates; change the watches to observe only the current node's data
by using a getter that returns nodeOutputStore.nodeOutputs[currentNodeId] and
nodeOutputStore.nodePreviewImages[currentNodeId] (or a computed that derives the
specific output/preview for the active node) and remove deep: true where not
needed, keeping the callback to call updateImageUrl() so only relevant changes
trigger the update.
In @src/extensions/core/imageCrop.ts:
- Around line 1-12: Extract the hard-coded minimum dimensions 300 and 450 into
named constants to improve maintainability: define constants (e.g.,
MIN_IMAGE_CROP_WIDTH and MIN_IMAGE_CROP_HEIGHT) near the top of the module and
replace the literal 300 and 450 in the nodeCreated handler where
node.setSize([Math.max(oldWidth, 300), Math.max(oldHeight, 450)]) is called;
keep the early return and comfyClass check in the async nodeCreated function
unchanged.
In @src/lib/litegraph/src/widgets/ImageCropWidget.ts:
- Around line 15-42: The drawWidget method in ImageCropWidget.ts manually saves
and restores canvas state via destructuring and Object.assign; replace that with
the standard canvas pattern by calling ctx.save() at the start of state changes
in drawWidget (before setting fillStyle, strokeStyle, font, textAlign,
textBaseline) and call ctx.restore() at the end (after drawing the text and
rectangles) to restore all canvas state properties; keep the same drawing logic
and use the existing method name drawWidget and class ImageCropWidget.
In @src/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.ts:
- Around line 9-25: The exported arrow assigned to useImageCropWidget should be
a function declaration per guidelines; change "export const useImageCropWidget =
(): ComfyWidgetConstructorV2 => { ... }" to a named function declaration "export
function useImageCropWidget(): ComfyWidgetConstructorV2 { ... }" and likewise
replace the inner anonymous arrow returned (the (node: LGraphNode, inputSpec:
InputSpecV2) => { ... }) with a named function (e.g., createImageCropWidget) so
both useImageCropWidget and the returned constructor are declared as functions
rather than function expressions; keep the same parameter names, types, body,
and return value IImageCropWidget.
In @src/renderer/extensions/vueNodes/widgets/registry/widgetRegistry.ts:
- Around line 163-171: The registry currently marks 'load3D' as expandable but
not 'imagecrop', causing the WidgetImageCrop component (registered as
'imagecrop' with component WidgetImageCrop) to not get the EXPANDING_TYPES
treatment; update EXPANDING_TYPES to include the 'imagecrop' key so the image
crop widget uses the same expanded/flex layout behavior as Load3D, ensuring the
image preview container can fill available vertical space and provide consistent
interaction area.
📜 Review details
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (12)
src/components/imagecrop/WidgetImageCrop.vuesrc/composables/useImageCrop.tssrc/extensions/core/imageCrop.tssrc/extensions/core/index.tssrc/lib/litegraph/src/types/widgets.tssrc/lib/litegraph/src/widgets/ImageCropWidget.tssrc/lib/litegraph/src/widgets/widgetMap.tssrc/locales/en/main.jsonsrc/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.tssrc/renderer/extensions/vueNodes/widgets/registry/widgetRegistry.tssrc/schemas/nodeDef/nodeDefSchemaV2.tssrc/scripts/widgets.ts
🧰 Additional context used
📓 Path-based instructions (19)
src/**/*.{vue,ts}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.{vue,ts}: Leverage VueUse functions for performance-enhancing styles
Implement proper error handling
Use vue-i18n in composition API for any string literals. Place new translation entries in src/locales/en/main.json
Files:
src/lib/litegraph/src/types/widgets.tssrc/extensions/core/index.tssrc/composables/useImageCrop.tssrc/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.tssrc/lib/litegraph/src/widgets/widgetMap.tssrc/lib/litegraph/src/widgets/ImageCropWidget.tssrc/components/imagecrop/WidgetImageCrop.vuesrc/extensions/core/imageCrop.tssrc/renderer/extensions/vueNodes/widgets/registry/widgetRegistry.tssrc/schemas/nodeDef/nodeDefSchemaV2.tssrc/scripts/widgets.ts
src/**/*.ts
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.ts: Use es-toolkit for utility functions
Use TypeScript for type safety
Files:
src/lib/litegraph/src/types/widgets.tssrc/extensions/core/index.tssrc/composables/useImageCrop.tssrc/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.tssrc/lib/litegraph/src/widgets/widgetMap.tssrc/lib/litegraph/src/widgets/ImageCropWidget.tssrc/extensions/core/imageCrop.tssrc/renderer/extensions/vueNodes/widgets/registry/widgetRegistry.tssrc/schemas/nodeDef/nodeDefSchemaV2.tssrc/scripts/widgets.ts
src/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
src/**/*.{ts,tsx,vue}: Sanitize HTML with DOMPurify to prevent XSS attacks
Avoid using @ts-expect-error; use proper TypeScript types instead
Use es-toolkit for utility functions instead of other utility libraries
Implement proper TypeScript types throughout the codebase
Files:
src/lib/litegraph/src/types/widgets.tssrc/extensions/core/index.tssrc/composables/useImageCrop.tssrc/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.tssrc/lib/litegraph/src/widgets/widgetMap.tssrc/lib/litegraph/src/widgets/ImageCropWidget.tssrc/components/imagecrop/WidgetImageCrop.vuesrc/extensions/core/imageCrop.tssrc/renderer/extensions/vueNodes/widgets/registry/widgetRegistry.tssrc/schemas/nodeDef/nodeDefSchemaV2.tssrc/scripts/widgets.ts
src/**/*.{vue,ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Follow Vue 3 composition API style guide
Files:
src/lib/litegraph/src/types/widgets.tssrc/extensions/core/index.tssrc/composables/useImageCrop.tssrc/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.tssrc/lib/litegraph/src/widgets/widgetMap.tssrc/lib/litegraph/src/widgets/ImageCropWidget.tssrc/components/imagecrop/WidgetImageCrop.vuesrc/extensions/core/imageCrop.tssrc/renderer/extensions/vueNodes/widgets/registry/widgetRegistry.tssrc/schemas/nodeDef/nodeDefSchemaV2.tssrc/scripts/widgets.ts
src/lib/litegraph/**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (src/lib/litegraph/CLAUDE.md)
src/lib/litegraph/**/*.{js,ts,jsx,tsx}: Run ESLint instead of manually figuring out whitespace fixes or other trivial style concerns using thepnpm lint:fixcommand
Take advantage ofTypedArraysubarraywhen appropriate
Thesizeandposproperties ofRectangleshare the same array buffer (subarray); they may be used to set the rectangle's size and position
Prefer single lineifsyntax over adding curly braces, when the statement has a very concise expression and concise, single line statement
Do not replace&&=or||=with=when there is no reason to do so. If you do find a reason to remove either&&=or||=, leave a comment explaining why the removal occurred
When writing methods, prefer returning idiomatic JavaScriptundefinedovernull
Files:
src/lib/litegraph/src/types/widgets.tssrc/lib/litegraph/src/widgets/widgetMap.tssrc/lib/litegraph/src/widgets/ImageCropWidget.ts
src/lib/litegraph/**/*.{ts,tsx}
📄 CodeRabbit inference engine (src/lib/litegraph/CLAUDE.md)
Type assertions are an absolute last resort. In almost all cases, they are a crutch that leads to brittle code
Files:
src/lib/litegraph/src/types/widgets.tssrc/lib/litegraph/src/widgets/widgetMap.tssrc/lib/litegraph/src/widgets/ImageCropWidget.ts
**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx,vue}: Use TypeScript exclusively; do not write new JavaScript code
Use sorted and grouped imports organized by plugin/source
Enforce ESLint rules including Vue + TypeScript rules, disallow floating promises, disallow unused imports, and restrict i18n raw text in templates
Do not useanytype oras anytype assertions; fix the underlying type issue instead
Write code that is expressive and self-documenting; avoid redundant comments and clean as you go
Keep functions short and functional; minimize nesting and follow the arrow anti-pattern
Avoid mutable state; prefer immutability and assignment at point of declaration
Use function declarations instead of function expressions when possible
Use es-toolkit for utility functions
Implement proper error handling in code
Files:
src/lib/litegraph/src/types/widgets.tssrc/extensions/core/index.tssrc/composables/useImageCrop.tssrc/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.tssrc/lib/litegraph/src/widgets/widgetMap.tssrc/lib/litegraph/src/widgets/ImageCropWidget.tssrc/components/imagecrop/WidgetImageCrop.vuesrc/extensions/core/imageCrop.tssrc/renderer/extensions/vueNodes/widgets/registry/widgetRegistry.tssrc/schemas/nodeDef/nodeDefSchemaV2.tssrc/scripts/widgets.ts
**/*.{ts,tsx,vue,js,jsx,json,css}
📄 CodeRabbit inference engine (AGENTS.md)
Apply Prettier formatting with 2-space indentation, single quotes, no trailing semicolons, and 80-character line width
Files:
src/lib/litegraph/src/types/widgets.tssrc/extensions/core/index.tssrc/composables/useImageCrop.tssrc/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.tssrc/lib/litegraph/src/widgets/widgetMap.tssrc/lib/litegraph/src/widgets/ImageCropWidget.tssrc/components/imagecrop/WidgetImageCrop.vuesrc/locales/en/main.jsonsrc/extensions/core/imageCrop.tssrc/renderer/extensions/vueNodes/widgets/registry/widgetRegistry.tssrc/schemas/nodeDef/nodeDefSchemaV2.tssrc/scripts/widgets.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Minimize the surface area (exported values) of each module and composable
Files:
src/lib/litegraph/src/types/widgets.tssrc/extensions/core/index.tssrc/composables/useImageCrop.tssrc/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.tssrc/lib/litegraph/src/widgets/widgetMap.tssrc/lib/litegraph/src/widgets/ImageCropWidget.tssrc/extensions/core/imageCrop.tssrc/renderer/extensions/vueNodes/widgets/registry/widgetRegistry.tssrc/schemas/nodeDef/nodeDefSchemaV2.tssrc/scripts/widgets.ts
src/**/index.ts
📄 CodeRabbit inference engine (AGENTS.md)
Do not use barrel files (e.g.,
/some/package/index.ts) to re-export within/src
Files:
src/extensions/core/index.ts
src/**/{services,composables}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
src/**/{services,composables}/**/*.{ts,tsx}: Useapi.apiURL()for backend endpoints instead of constructing URLs directly
Useapi.fileURL()for static file access instead of constructing URLs directly
Files:
src/composables/useImageCrop.tssrc/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.ts
src/**/{composables,components}/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Clean up subscriptions in state management to prevent memory leaks
Files:
src/composables/useImageCrop.tssrc/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.tssrc/components/imagecrop/WidgetImageCrop.vue
src/**/{components,composables}/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Use vue-i18n for ALL user-facing strings by adding them to
src/locales/en/main.json
Files:
src/composables/useImageCrop.tssrc/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.tssrc/components/imagecrop/WidgetImageCrop.vue
**/**/use[A-Z]*.ts
📄 CodeRabbit inference engine (AGENTS.md)
Name composables using the pattern
useXyz.ts
Files:
src/composables/useImageCrop.tssrc/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.ts
src/**/*.vue
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.vue: Use the Vue 3 Composition API instead of the Options API when writing Vue components (exception: when overriding or extending PrimeVue components for compatibility)
Use setup() function for component logic
Utilize ref and reactive for reactive state
Implement computed properties with computed()
Use watch and watchEffect for side effects
Implement lifecycle hooks with onMounted, onUpdated, etc.
Utilize provide/inject for dependency injection
Use vue 3.5 style of default prop declaration
Use Tailwind CSS for styling
Implement proper props and emits definitions
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Follow Vue 3 style guide and naming conventions
Files:
src/components/imagecrop/WidgetImageCrop.vue
src/components/**/*.vue
📄 CodeRabbit inference engine (src/components/CLAUDE.md)
src/components/**/*.vue: Use setup() function in Vue 3 Composition API
Destructure props using Vue 3.5 style in Vue components
Use ref/reactive for state management in Vue 3 Composition API
Implement computed() for derived state in Vue 3 Composition API
Use provide/inject for dependency injection in Vue components
Prefer emit/@event-name for state changes over other communication patterns
Use defineExpose only for imperative operations (such as form.validate(), modal.open())
Replace PrimeVue Dropdown component with Select
Replace PrimeVue OverlayPanel component with Popover
Replace PrimeVue Calendar component with DatePicker
Replace PrimeVue InputSwitch component with ToggleSwitch
Replace PrimeVue Sidebar component with Drawer
Replace PrimeVue Chips component with AutoComplete with multiple enabled
Replace PrimeVue TabMenu component with Tabs without panels
Replace PrimeVue Steps component with Stepper without panels
Replace PrimeVue InlineMessage component with Message
Extract complex conditionals to computed properties
Implement cleanup for async operations in Vue components
Use lifecycle hooks: onMounted, onUpdated in Vue 3 Composition API
Use Teleport/Suspense when needed for component rendering
Define proper props and emits definitions in Vue components
Files:
src/components/imagecrop/WidgetImageCrop.vue
src/components/**/*.{vue,css}
📄 CodeRabbit inference engine (src/components/CLAUDE.md)
src/components/**/*.{vue,css}: Use Tailwind CSS only for styling (no custom CSS)
Use the correct tokens from style.css in the design system package
Files:
src/components/imagecrop/WidgetImageCrop.vue
src/components/**/*.{vue,ts,js}
📄 CodeRabbit inference engine (src/components/CLAUDE.md)
src/components/**/*.{vue,ts,js}: Use existing VueUse composables (such as useElementHover) instead of manually managing event listeners
Use useIntersectionObserver for visibility detection instead of custom scroll handlers
Use vue-i18n for ALL UI strings
Files:
src/components/imagecrop/WidgetImageCrop.vue
**/*.vue
📄 CodeRabbit inference engine (AGENTS.md)
**/*.vue: Use Vue 3.5+ with TypeScript in.vuefiles, exclusively using Composition API with<script setup lang="ts">syntax
Use Tailwind 4 for styling in Vue components; avoid<style>blocks
Name Vue components using PascalCase (e.g.,MenuHamburger.vue)
Use Vue 3.5 TypeScript-style default prop declaration with reactive props destructuring; do not usewithDefaultsor runtime props declaration
Prefercomputed()overrefwithwatchwhen deriving values
PreferuseModelover separately defining prop and emit for two-way binding
Usevue-i18nin composition API for string literals; place new translation entries insrc/locales/en/main.json
Usecn()utility function from@/utils/tailwindUtilfor merging Tailwind class names; do not use:class="[]"syntax
Do not use thedark:Tailwind variant; use semantic values from thestyle.csstheme instead (e.g.,bg-node-component-surface)
Do not use!importantor the!important prefix for Tailwind classes; find and correct interfering!importantclasses instead
Avoid new usage of PrimeVue components; use VueUse, shadcn/vue, or Reka UI instead
Leverage VueUse functions for performance-enhancing styles in Vue components
Implement proper props and emits definitions in Vue components
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Follow Vue 3 style guide and naming conventions
Files:
src/components/imagecrop/WidgetImageCrop.vue
🧠 Learnings (31)
📓 Common learnings
Learnt from: simula-r
Repo: Comfy-Org/ComfyUI_frontend PR: 7252
File: src/renderer/extensions/vueNodes/components/ImagePreview.vue:151-158
Timestamp: 2025-12-11T03:55:57.926Z
Learning: In src/renderer/extensions/vueNodes/components/ImagePreview.vue and LGraphNode.vue, keyboard navigation for image galleries should respond to node-level focus (via keyEvent injection from LGraphNode), not require focus within the image preview wrapper itself. This allows users to navigate the gallery with arrow keys immediately when the node is focused/selected.
📚 Learning: 2025-12-09T03:39:54.501Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7169
File: src/platform/remote/comfyui/jobs/jobTypes.ts:1-107
Timestamp: 2025-12-09T03:39:54.501Z
Learning: In the ComfyUI_frontend project, Zod is on v3.x. Do not suggest Zod v4 standalone validators (z.uuid, z.ulid, z.cuid2, z.nanoid) until an upgrade to Zod 4 is performed. When reviewing TypeScript files (e.g., src/platform/remote/comfyui/jobs/jobTypes.ts) validate against Zod 3 capabilities and avoid introducing v4-specific features; flag any proposal to upgrade or incorporate v4-only validators and propose staying with compatible 3.x patterns.
Applied to files:
src/lib/litegraph/src/types/widgets.tssrc/extensions/core/index.tssrc/composables/useImageCrop.tssrc/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.tssrc/lib/litegraph/src/widgets/widgetMap.tssrc/lib/litegraph/src/widgets/ImageCropWidget.tssrc/extensions/core/imageCrop.tssrc/renderer/extensions/vueNodes/widgets/registry/widgetRegistry.tssrc/schemas/nodeDef/nodeDefSchemaV2.tssrc/scripts/widgets.ts
📚 Learning: 2025-12-13T11:03:11.264Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7416
File: src/stores/imagePreviewStore.ts:5-7
Timestamp: 2025-12-13T11:03:11.264Z
Learning: In the ComfyUI_frontend repository, lint rules require keeping 'import type' statements separate from non-type imports, even if importing from the same module. Do not suggest consolidating them into a single import statement. Ensure type imports remain on their own line (import type { ... } from 'module') and regular imports stay on separate lines.
Applied to files:
src/lib/litegraph/src/types/widgets.tssrc/extensions/core/index.tssrc/composables/useImageCrop.tssrc/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.tssrc/lib/litegraph/src/widgets/widgetMap.tssrc/lib/litegraph/src/widgets/ImageCropWidget.tssrc/extensions/core/imageCrop.tssrc/renderer/extensions/vueNodes/widgets/registry/widgetRegistry.tssrc/schemas/nodeDef/nodeDefSchemaV2.tssrc/scripts/widgets.ts
📚 Learning: 2025-12-17T00:40:09.635Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.stories.ts:45-55
Timestamp: 2025-12-17T00:40:09.635Z
Learning: Prefer pure function declarations over function expressions (e.g., use function foo() { ... } instead of const foo = () => { ... }) for pure functions in the repository. Function declarations are more functional-leaning, offer better hoisting clarity, and can improve readability and tooling consistency. Apply this guideline across TypeScript files in Comfy-Org/ComfyUI_frontend, including story and UI component code, except where a function expression is semantically required (e.g., callbacks, higher-order functions with closures).
Applied to files:
src/lib/litegraph/src/types/widgets.tssrc/extensions/core/index.tssrc/composables/useImageCrop.tssrc/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.tssrc/lib/litegraph/src/widgets/widgetMap.tssrc/lib/litegraph/src/widgets/ImageCropWidget.tssrc/extensions/core/imageCrop.tssrc/renderer/extensions/vueNodes/widgets/registry/widgetRegistry.tssrc/schemas/nodeDef/nodeDefSchemaV2.tssrc/scripts/widgets.ts
📚 Learning: 2025-12-30T22:22:33.836Z
Learnt from: kaili-yang
Repo: Comfy-Org/ComfyUI_frontend PR: 7805
File: src/composables/useCoreCommands.ts:439-439
Timestamp: 2025-12-30T22:22:33.836Z
Learning: When accessing reactive properties from Pinia stores in TypeScript files, avoid using .value on direct property access (e.g., useStore().isOverlayExpanded). Pinia auto-wraps refs when accessed directly, returning the primitive value. The .value accessor is only needed when destructuring store properties or when using storeToRefs().
Applied to files:
src/lib/litegraph/src/types/widgets.tssrc/extensions/core/index.tssrc/composables/useImageCrop.tssrc/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.tssrc/lib/litegraph/src/widgets/widgetMap.tssrc/lib/litegraph/src/widgets/ImageCropWidget.tssrc/extensions/core/imageCrop.tssrc/renderer/extensions/vueNodes/widgets/registry/widgetRegistry.tssrc/schemas/nodeDef/nodeDefSchemaV2.tssrc/scripts/widgets.ts
📚 Learning: 2025-12-11T12:25:15.470Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7358
File: src/components/dialog/content/signin/SignUpForm.vue:45-54
Timestamp: 2025-12-11T12:25:15.470Z
Learning: This repository uses CI automation to format code (pnpm format). Do not include manual formatting suggestions in code reviews for Comfy-Org/ComfyUI_frontend. If formatting issues are detected, rely on the CI formatter or re-run pnpm format. Focus reviews on correctness, readability, performance, accessibility, and maintainability rather than style formatting.
Applied to files:
src/lib/litegraph/src/types/widgets.tssrc/extensions/core/index.tssrc/composables/useImageCrop.tssrc/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.tssrc/lib/litegraph/src/widgets/widgetMap.tssrc/lib/litegraph/src/widgets/ImageCropWidget.tssrc/components/imagecrop/WidgetImageCrop.vuesrc/extensions/core/imageCrop.tssrc/renderer/extensions/vueNodes/widgets/registry/widgetRegistry.tssrc/schemas/nodeDef/nodeDefSchemaV2.tssrc/scripts/widgets.ts
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.{vue,ts,js} : Use existing VueUse composables (such as useElementHover) instead of manually managing event listeners
Applied to files:
src/composables/useImageCrop.tssrc/scripts/widgets.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{js,ts,jsx,tsx} : Do not replace `&&=` or `||=` with `=` when there is no reason to do so. If you do find a reason to remove either `&&=` or `||=`, leave a comment explaining why the removal occurred
Applied to files:
src/composables/useImageCrop.tssrc/lib/litegraph/src/widgets/ImageCropWidget.ts
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*.{ts,tsx,vue} : Use function declarations instead of function expressions when possible
Applied to files:
src/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.ts
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*.{ts,tsx,vue} : Keep functions short and functional; minimize nesting and follow the arrow anti-pattern
Applied to files:
src/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.ts
📚 Learning: 2025-12-18T21:15:46.862Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7603
File: src/components/queue/QueueOverlayHeader.vue:49-59
Timestamp: 2025-12-18T21:15:46.862Z
Learning: In the ComfyUI_frontend repository, for Vue components, do not add aria-label to buttons that have visible text content (e.g., buttons containing <span> text). The visible text provides the accessible name. Use aria-label only for elements without visible labels (e.g., icon-only buttons). If a button has no visible label, provide a clear aria-label or associate with an aria-labelledby describing its action.
Applied to files:
src/components/imagecrop/WidgetImageCrop.vue
📚 Learning: 2025-12-04T21:43:49.363Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7137
File: src/components/rightSidePanel/parameters/TabParameters.vue:10-0
Timestamp: 2025-12-04T21:43:49.363Z
Learning: Vue 3.5+ supports reactive props destructure in <script setup>. Destructuring props directly (e.g., `const { nodes } = defineProps<{ nodes: LGraphNode[] }>()`) maintains reactivity through compiler transformation. This is the recommended modern approach and does not require using `props.x` or `toRef`/`toRefs`.
Applied to files:
src/components/imagecrop/WidgetImageCrop.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Destructure props using Vue 3.5 style in Vue components
Applied to files:
src/components/imagecrop/WidgetImageCrop.vue
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*.vue : Use Vue 3.5 TypeScript-style default prop declaration with reactive props destructuring; do not use `withDefaults` or runtime props declaration
Applied to files:
src/components/imagecrop/WidgetImageCrop.vue
📚 Learning: 2025-12-16T22:26:49.463Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.vue:17-17
Timestamp: 2025-12-16T22:26:49.463Z
Learning: In Vue 3.5+ with <script setup>, when using defineProps<Props>() with partial destructuring (e.g., const { as = 'button', class: customClass = '' } = defineProps<Props>() ), props that are not destructured (e.g., variant, size) stay accessible by name in the template scope. This pattern is valid: you can destructure only a subset of props for convenience while referencing the remaining props directly in template expressions. Apply this guideline to Vue components across the codebase (all .vue files).
Applied to files:
src/components/imagecrop/WidgetImageCrop.vue
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.vue : Use vue 3.5 style of default prop declaration
Applied to files:
src/components/imagecrop/WidgetImageCrop.vue
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.vue : Utilize ref and reactive for reactive state
Applied to files:
src/components/imagecrop/WidgetImageCrop.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Use ref/reactive for state management in Vue 3 Composition API
Applied to files:
src/components/imagecrop/WidgetImageCrop.vue
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*.vue : Prefer `useModel` over separately defining prop and emit for two-way binding
Applied to files:
src/components/imagecrop/WidgetImageCrop.vue
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*.vue : Avoid new usage of PrimeVue components; use VueUse, shadcn/vue, or Reka UI instead
Applied to files:
src/components/imagecrop/WidgetImageCrop.vuesrc/scripts/widgets.ts
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.vue : Implement proper props and emits definitions
Applied to files:
src/components/imagecrop/WidgetImageCrop.vue
📚 Learning: 2025-12-09T03:49:52.828Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 6300
File: src/platform/updates/components/WhatsNewPopup.vue:5-13
Timestamp: 2025-12-09T03:49:52.828Z
Learning: In Vue files across the ComfyUI_frontend repo, when a button is needed, prefer the repo's common button components from src/components/button/ (IconButton.vue, TextButton.vue, IconTextButton.vue) over plain HTML <button> elements. These components wrap PrimeVue with the project’s design system styling. Use only the common button components for consistency and theming, and import them from src/components/button/ as needed.
Applied to files:
src/components/imagecrop/WidgetImageCrop.vue
📚 Learning: 2025-12-09T21:40:12.361Z
Learnt from: benceruleanlu
Repo: Comfy-Org/ComfyUI_frontend PR: 7297
File: src/components/actionbar/ComfyActionbar.vue:33-43
Timestamp: 2025-12-09T21:40:12.361Z
Learning: In Vue single-file components, allow inline Tailwind CSS class strings for static classes and avoid extracting them into computed properties solely for readability. Prefer keeping static class names inline for simplicity and performance. For dynamic or conditional classes, use Vue bindings (e.g., :class) to compose classes.
Applies to all Vue files in the repository (e.g., src/**/*.vue) where Tailwind utilities are used for static styling.
Applied to files:
src/components/imagecrop/WidgetImageCrop.vue
📚 Learning: 2025-12-22T21:36:08.369Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7649
File: src/platform/cloud/subscription/components/PricingTable.vue:185-201
Timestamp: 2025-12-22T21:36:08.369Z
Learning: In Vue components, avoid creating single-use variants for common UI components (e.g., Button and other shared components). Aim for reusable variants that cover multiple use cases. It’s acceptable to temporarily mix variant props with inline Tailwind classes when a styling need is unique to one place, but plan and consolidate into shared, reusable variants as patterns emerge across the codebase.
Applied to files:
src/components/imagecrop/WidgetImageCrop.vue
📚 Learning: 2025-12-18T02:07:38.870Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7598
File: src/components/sidebar/tabs/AssetsSidebarTab.vue:131-131
Timestamp: 2025-12-18T02:07:38.870Z
Learning: Tailwind CSS v4 safe utilities (e.g., items-center-safe, justify-*-safe, place-*-safe) are allowed in Vue components under src/ and in story files. Do not flag these specific safe variants as invalid when reviewing code in src/**/*.vue or related stories.
Applied to files:
src/components/imagecrop/WidgetImageCrop.vue
📚 Learning: 2025-12-21T01:06:02.786Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7649
File: src/components/graph/selectionToolbox/ColorPickerButton.vue:15-18
Timestamp: 2025-12-21T01:06:02.786Z
Learning: In Comfy-Org/ComfyUI_frontend, in Vue component files, when a filled icon is required (e.g., 'pi pi-circle-fill'), you may mix PrimeIcons with Lucide icons since Lucide lacks filled variants. This mixed usage is acceptable when one icon library does not provide an equivalent filled icon. Apply consistently across Vue components in the src directory where icons are used, and document the rationale when a mixed approach is chosen.
Applied to files:
src/components/imagecrop/WidgetImageCrop.vue
📚 Learning: 2025-12-18T16:03:02.066Z
Learnt from: henrikvilhelmberglund
Repo: Comfy-Org/ComfyUI_frontend PR: 7617
File: src/components/actionbar/ComfyActionbar.vue:301-308
Timestamp: 2025-12-18T16:03:02.066Z
Learning: In the ComfyUI frontend queue system, useQueuePendingTaskCountStore().count indicates the number of tasks in the queue, where count = 1 means a single active/running task and count > 1 means there are pending tasks in addition to the active task. Therefore, in src/components/actionbar/ComfyActionbar.vue, enable the 'Clear Pending Tasks' button only when count > 1 to avoid clearing the currently running task. The active task should be canceled using the 'Cancel current run' button instead. This rule should be enforced via a conditional check on the queue count, with appropriate disabled/aria-disabled states for accessibility, and tests should verify behavior for count = 1 and count > 1.
Applied to files:
src/components/imagecrop/WidgetImageCrop.vue
📚 Learning: 2025-12-09T04:35:43.971Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 6300
File: src/locales/en/main.json:774-780
Timestamp: 2025-12-09T04:35:43.971Z
Learning: In the Comfy-Org/ComfyUI_frontend repository, locale files other than `src/locales/en/main.json` are generated automatically on every release. Developers only need to add English (en) key/values in `src/locales/en/main.json` when making PRs; manual updates to other locale files (fr, ja, ko, ru, zh, zh-TW, es, ar, tr, etc.) are not required and should not be suggested in reviews.
Applied to files:
src/locales/en/main.json
📚 Learning: 2025-11-24T19:47:34.324Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:34.324Z
Learning: Applies to src/**/{components,composables}/**/*.{ts,tsx,vue} : Use vue-i18n for ALL user-facing strings by adding them to `src/locales/en/main.json`
Applied to files:
src/locales/en/main.json
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*.vue : Leverage VueUse functions for performance-enhancing styles in Vue components
Applied to files:
src/scripts/widgets.ts
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.{vue,ts} : Leverage VueUse functions for performance-enhancing styles
Applied to files:
src/scripts/widgets.ts
🧬 Code graph analysis (7)
src/composables/useImageCrop.ts (2)
src/lib/litegraph/src/types/widgets.ts (1)
CropRegionValue(258-263)src/scripts/app.ts (1)
app(1772-1772)
src/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.ts (3)
src/scripts/widgets.ts (1)
ComfyWidgetConstructorV2(31-34)src/lib/litegraph/src/types/widgets.ts (1)
IImageCropWidget(266-272)src/schemas/nodeDef/nodeDefSchemaV2.ts (1)
ImageCropInputSpec(180-180)
src/lib/litegraph/src/widgets/widgetMap.ts (2)
src/lib/litegraph/src/widgets/ImageCropWidget.ts (1)
ImageCropWidget(9-47)src/lib/litegraph/src/utils/type.ts (1)
toClass(13-18)
src/lib/litegraph/src/widgets/ImageCropWidget.ts (2)
src/lib/litegraph/src/types/widgets.ts (1)
IImageCropWidget(266-272)src/lib/litegraph/src/widgets/BaseWidget.ts (2)
DrawWidgetOptions(14-19)WidgetEventOptions(30-34)
src/extensions/core/imageCrop.ts (1)
src/services/extensionService.ts (1)
useExtensionService(16-215)
src/schemas/nodeDef/nodeDefSchemaV2.ts (1)
src/schemas/nodeDefSchema.ts (1)
zBaseInputOptions(22-37)
src/scripts/widgets.ts (1)
src/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.ts (1)
useImageCropWidget(9-26)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: playwright-tests-chromium-sharded (3, 8)
- GitHub Check: playwright-tests-chromium-sharded (5, 8)
- GitHub Check: lint-and-format
- GitHub Check: test
- GitHub Check: collect
🔇 Additional comments (13)
src/schemas/nodeDef/nodeDefSchemaV2.ts (1)
67-72: LGTM! Schema definition follows existing patterns.The new
zImageCropInputSpecschema is consistent with similar input specs (IMAGE, IMAGECOMPARE) and properly integrated into the type system. The use ofz.record(z.unknown()).optional()for options is Zod v3 compatible and matches the pattern used by other image-related widgets.Also applies to: 136-136, 180-180
src/extensions/core/index.ts (1)
13-13: LGTM! Import properly added.The imageCrop extension import is correctly placed in alphabetical order and follows the established pattern for core extensions.
src/lib/litegraph/src/widgets/widgetMap.ts (1)
21-21: LGTM! Widget integration follows established patterns.The ImageCropWidget is properly integrated into the widget type system:
- Import is correctly ordered
- Added to WidgetTypeMap with proper typing
- Switch case uses the
toClasshelper consistently with other widgetsAlso applies to: 54-54, 125-126
src/scripts/widgets.ts (1)
17-17: LGTM! Widget constructor properly registered.The IMAGECROP widget is correctly integrated into ComfyWidgets:
- Import follows alphabetical ordering convention
- Uses the V2-to-V1 transformation wrapper consistently with other modern widgets
- Placement in ComfyWidgets object maintains logical grouping with other image-related widgets
Also applies to: 299-299
src/renderer/extensions/vueNodes/widgets/registry/widgetRegistry.ts (1)
57-59: LGTM!The async component registration follows the established pattern used by other widgets in this file.
src/locales/en/main.json (1)
1688-1692: LGTM!The locale entries are well-structured and follow the established patterns. All keys are consumed by the
WidgetImageCrop.vuecomponent.src/lib/litegraph/src/widgets/ImageCropWidget.ts (1)
44-46: LGTM!The no-op
onClickwith clear documentation that this is a Vue-only widget is appropriate.src/lib/litegraph/src/types/widgets.ts (2)
85-85: LGTM!The
IImageCropWidgetis correctly added to the discriminated union, maintaining consistency with other widget types.
257-272: LGTM!The
CropRegionValueinterface andIImageCropWidgetare well-defined and follow the established patterns for widget types in this file.src/composables/useImageCrop.ts (3)
30-31: LGTM!The composable is well-structured with clear separation of concerns. The
onMountedinitialization and reactive state management follow Vue 3 Composition API best practices.Also applies to: 452-452
73-79: Consider using nullish coalescing for explicit intent.Using
||for defaults treats0as falsy. While0is an invalid crop size (belowMIN_CROP_SIZE), using??would make the intent clearer that you're defaulting only forundefined/null.🔎 Proposed change
const syncFromModelValue = () => { const value = modelValue.value cropX.value = value.x cropY.value = value.y - cropWidth.value = value.width || 512 - cropHeight.value = value.height || 512 + cropWidth.value = value.width ?? 512 + cropHeight.value = value.height ?? 512 }Likely an incorrect or invalid review comment.
149-165: Potential division by zero not fully guarded.
getEffectiveScalechecks for zero values but the check at line 159 happens afterrect.widthis already used in a potential division context. The guard is correct, but consider returning early before accessingrect.widthifclientWidthis falsy.🔎 Proposed fix
const getEffectiveScale = (): number => { const container = containerEl.value if (!container || naturalWidth.value <= 0 || displayedWidth.value <= 0) { return 1 } const rect = container.getBoundingClientRect() const clientWidth = container.clientWidth - if (!clientWidth || !rect.width) return 1 + if (!clientWidth || rect.width <= 0) return 1 const renderedDisplayedWidth = (displayedWidth.value / clientWidth) * rect.width return renderedDisplayedWidth / naturalWidth.value }Likely an incorrect or invalid review comment.
src/components/imagecrop/WidgetImageCrop.vue (1)
11-48: Improve accessibility by associating labels with inputs.The
<label>elements are not programmatically associated with their corresponding inputs. Useidandforattributes for proper accessibility.🔎 Proposed fix
<div class="flex flex-1 items-center gap-1"> - <label class="w-6 text-xs text-muted">X</label> + <label for="crop-x" class="w-6 text-xs text-muted">X</label> <input + id="crop-x" v-model.number="cropX" type="number" :min="0" class="h-6 w-full rounded border border-border bg-input px-1 text-xs" @change="handleInputChange" /> </div> <div class="flex flex-1 items-center gap-1"> - <label class="w-6 text-xs text-muted">Y</label> + <label for="crop-y" class="w-6 text-xs text-muted">Y</label> <input + id="crop-y" v-model.number="cropY" ... </div> <div class="flex flex-1 items-center gap-1"> - <label class="w-6 text-xs text-muted">W</label> + <label for="crop-width" class="w-6 text-xs text-muted">W</label> <input + id="crop-width" v-model.number="cropWidth" ... </div> <div class="flex flex-1 items-center gap-1"> - <label class="w-6 text-xs text-muted">H</label> + <label for="crop-height" class="w-6 text-xs text-muted">H</label> <input + id="crop-height" v-model.number="cropHeight" ...Note: If multiple instances of this widget can exist on the same page, consider using unique IDs by incorporating
nodeId.⛔ Skipped due to learnings
Learnt from: DrJKL Repo: Comfy-Org/ComfyUI_frontend PR: 7603 File: src/components/queue/QueueOverlayHeader.vue:49-59 Timestamp: 2025-12-18T21:15:54.349Z Learning: For Vue components in Comfy-Org/ComfyUI_frontend: Do not suggest adding aria-label to buttons that already have visible text content (e.g., <span> elements with labels). The visible text automatically provides the accessible name. aria-label should only be used for elements without visible labels, such as icon-only buttons.Learnt from: simula-r Repo: Comfy-Org/ComfyUI_frontend PR: 7252 File: src/renderer/extensions/vueNodes/components/ImagePreview.vue:151-158 Timestamp: 2025-12-11T03:55:57.926Z Learning: In src/renderer/extensions/vueNodes/components/ImagePreview.vue and LGraphNode.vue, keyboard navigation for image galleries should respond to node-level focus (via keyEvent injection from LGraphNode), not require focus within the image preview wrapper itself. This allows users to navigate the gallery with arrow keys immediately when the node is focused/selected.
src/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.ts
Outdated
Show resolved
Hide resolved
bc6c542 to
567a771
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 10
🤖 Fix all issues with AI Agents
In @src/components/imagecrop/WidgetImageCrop.vue:
- Line 96: The Vue template uses array class binding :class="['absolute',
handle.class]" in WidgetImageCrop.vue; replace this with the cn() utility from
@/utils/tailwindUtil: import cn in the script (or setup) and change the binding
to use :class="cn('absolute', handle.class)" so Tailwind class merging follows
project conventions; ensure the import name is cn and update any other similar
bindings in this component to use cn() for consistency.
- Around line 113-115: The current use of defineProps should be converted to Vue
3.5 reactive props destructuring: keep the typed defineProps call (defineProps<{
nodeId: NodeId }>()), then call toRefs on the returned props and extract nodeId
(e.g., const { nodeId } = toRefs(props)), and update usages to read nodeId.value
where needed; change references to the original props object to use the
destructured ref instead.
In @src/composables/useImageCrop.ts:
- Around line 73-79: In syncFromModelValue replace the `||` fallbacks with
nullish coalescing so defaults only apply for null/undefined: read
modelValue.value and set cropWidth.value = value.width ?? 512 and
cropHeight.value = value.height ?? 512 (leave cropX/cropY assignment as-is);
this clarifies intent that 0 is a deliberate value rather than treated as
missing.
- Around line 434-444: The current deep watchers on nodeOutputStore.nodeOutputs
and nodeOutputStore.nodePreviewImages fire on any mutation across all nodes;
change them to watch only the specific node's outputs/preview for the node being
edited (e.g., replace watch(() => nodeOutputStore.nodeOutputs, ...) with
watch(() => nodeOutputStore.nodeOutputs[nodeId] or a store getter like
nodeOutputStore.getNodeOutputs(nodeId), and similarly for nodePreviewImages) and
remove deep: true unless nested mutation detection for that specific node is
required; call updateImageUrl() in those targeted watchers so unrelated node
changes no longer trigger updates.
In @src/extensions/core/imageCrop.ts:
- Around line 9-10: Extract the magic numbers used when constraining image crop
sizes into named constants to improve readability and maintainability: define
MIN_IMAGECROP_WIDTH and MIN_IMAGECROP_HEIGHT near the top of the module and
replace the literal 300 and 450 in the node.setSize call (the code that reads
node.size and calls node.setSize([Math.max(oldWidth, 300), Math.max(oldHeight,
450)]) ) with those constants so the intent is clear and easy to update.
In @src/lib/litegraph/src/types/widgets.ts:
- Around line 257-263: CropRegionValue currently only enforces numeric types at
compile time; add runtime validation in the ImageCrop widget implementation to
ensure CropRegionValue.width and CropRegionValue.height are positive (>0) and
x/y are within expected bounds (e.g., non-negative and not outside image
dimensions if available). Validate inputs when constructing/updating the crop
region (e.g., in the widget's setValue/updateValue/handleChange functions) and
reject or normalize invalid values (throw error or clamp to valid range and log)
so downstream code always receives a valid CropRegionValue.
In @src/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.ts:
- Line 22: The code uses a type assertion "as IImageCropWidget" on the result of
node.addWidget; remove the assertion by fixing typings so the call infers the
correct widget type — either call node.addWidget with a generic parameter (e.g.,
node.addWidget<IImageCropWidget>(...)) or update the widget API signature so
addWidget's return type is strongly typed for this widget. If changing the API
isn't possible now, keep the assertion but add a brief comment above it
explaining why the assertion is unavoidable and reference the related typing
limitation (IImageCropWidget / node.addWidget) so future refactors can remove
it.
In @src/renderer/extensions/vueNodes/widgets/registry/widgetRegistry.ts:
- Around line 163-171: The EXPANDING_TYPES set should include the 'imagecrop'
widget so it can expand vertically like 'load3D'; update the EXPANDING_TYPES
declaration (referencing the EXPANDING_TYPES symbol in widgetRegistry.ts) to add
the 'imagecrop' key (matching the widget id used in the registry entry for
component WidgetImageCrop) so the image crop preview can use available vertical
space and improve UX.
📜 Review details
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (12)
src/components/imagecrop/WidgetImageCrop.vuesrc/composables/useImageCrop.tssrc/extensions/core/imageCrop.tssrc/extensions/core/index.tssrc/lib/litegraph/src/types/widgets.tssrc/lib/litegraph/src/widgets/ImageCropWidget.tssrc/lib/litegraph/src/widgets/widgetMap.tssrc/locales/en/main.jsonsrc/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.tssrc/renderer/extensions/vueNodes/widgets/registry/widgetRegistry.tssrc/schemas/nodeDef/nodeDefSchemaV2.tssrc/scripts/widgets.ts
🧰 Additional context used
📓 Path-based instructions (19)
src/**/*.{vue,ts}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.{vue,ts}: Leverage VueUse functions for performance-enhancing styles
Implement proper error handling
Use vue-i18n in composition API for any string literals. Place new translation entries in src/locales/en/main.json
Files:
src/lib/litegraph/src/types/widgets.tssrc/extensions/core/index.tssrc/lib/litegraph/src/widgets/widgetMap.tssrc/composables/useImageCrop.tssrc/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.tssrc/scripts/widgets.tssrc/lib/litegraph/src/widgets/ImageCropWidget.tssrc/components/imagecrop/WidgetImageCrop.vuesrc/schemas/nodeDef/nodeDefSchemaV2.tssrc/renderer/extensions/vueNodes/widgets/registry/widgetRegistry.tssrc/extensions/core/imageCrop.ts
src/**/*.ts
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.ts: Use es-toolkit for utility functions
Use TypeScript for type safety
Files:
src/lib/litegraph/src/types/widgets.tssrc/extensions/core/index.tssrc/lib/litegraph/src/widgets/widgetMap.tssrc/composables/useImageCrop.tssrc/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.tssrc/scripts/widgets.tssrc/lib/litegraph/src/widgets/ImageCropWidget.tssrc/schemas/nodeDef/nodeDefSchemaV2.tssrc/renderer/extensions/vueNodes/widgets/registry/widgetRegistry.tssrc/extensions/core/imageCrop.ts
src/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
src/**/*.{ts,tsx,vue}: Sanitize HTML with DOMPurify to prevent XSS attacks
Avoid using @ts-expect-error; use proper TypeScript types instead
Use es-toolkit for utility functions instead of other utility libraries
Implement proper TypeScript types throughout the codebase
Files:
src/lib/litegraph/src/types/widgets.tssrc/extensions/core/index.tssrc/lib/litegraph/src/widgets/widgetMap.tssrc/composables/useImageCrop.tssrc/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.tssrc/scripts/widgets.tssrc/lib/litegraph/src/widgets/ImageCropWidget.tssrc/components/imagecrop/WidgetImageCrop.vuesrc/schemas/nodeDef/nodeDefSchemaV2.tssrc/renderer/extensions/vueNodes/widgets/registry/widgetRegistry.tssrc/extensions/core/imageCrop.ts
src/**/*.{vue,ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Follow Vue 3 composition API style guide
Files:
src/lib/litegraph/src/types/widgets.tssrc/extensions/core/index.tssrc/lib/litegraph/src/widgets/widgetMap.tssrc/composables/useImageCrop.tssrc/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.tssrc/scripts/widgets.tssrc/lib/litegraph/src/widgets/ImageCropWidget.tssrc/components/imagecrop/WidgetImageCrop.vuesrc/schemas/nodeDef/nodeDefSchemaV2.tssrc/renderer/extensions/vueNodes/widgets/registry/widgetRegistry.tssrc/extensions/core/imageCrop.ts
src/lib/litegraph/**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (src/lib/litegraph/CLAUDE.md)
src/lib/litegraph/**/*.{js,ts,jsx,tsx}: Run ESLint instead of manually figuring out whitespace fixes or other trivial style concerns using thepnpm lint:fixcommand
Take advantage ofTypedArraysubarraywhen appropriate
Thesizeandposproperties ofRectangleshare the same array buffer (subarray); they may be used to set the rectangle's size and position
Prefer single lineifsyntax over adding curly braces, when the statement has a very concise expression and concise, single line statement
Do not replace&&=or||=with=when there is no reason to do so. If you do find a reason to remove either&&=or||=, leave a comment explaining why the removal occurred
When writing methods, prefer returning idiomatic JavaScriptundefinedovernull
Files:
src/lib/litegraph/src/types/widgets.tssrc/lib/litegraph/src/widgets/widgetMap.tssrc/lib/litegraph/src/widgets/ImageCropWidget.ts
src/lib/litegraph/**/*.{ts,tsx}
📄 CodeRabbit inference engine (src/lib/litegraph/CLAUDE.md)
Type assertions are an absolute last resort. In almost all cases, they are a crutch that leads to brittle code
Files:
src/lib/litegraph/src/types/widgets.tssrc/lib/litegraph/src/widgets/widgetMap.tssrc/lib/litegraph/src/widgets/ImageCropWidget.ts
**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx,vue}: Use TypeScript exclusively; do not write new JavaScript code
Use sorted and grouped imports organized by plugin/source
Enforce ESLint rules including Vue + TypeScript rules, disallow floating promises, disallow unused imports, and restrict i18n raw text in templates
Do not useanytype oras anytype assertions; fix the underlying type issue instead
Write code that is expressive and self-documenting; avoid redundant comments and clean as you go
Keep functions short and functional; minimize nesting and follow the arrow anti-pattern
Avoid mutable state; prefer immutability and assignment at point of declaration
Use function declarations instead of function expressions when possible
Use es-toolkit for utility functions
Implement proper error handling in code
Files:
src/lib/litegraph/src/types/widgets.tssrc/extensions/core/index.tssrc/lib/litegraph/src/widgets/widgetMap.tssrc/composables/useImageCrop.tssrc/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.tssrc/scripts/widgets.tssrc/lib/litegraph/src/widgets/ImageCropWidget.tssrc/components/imagecrop/WidgetImageCrop.vuesrc/schemas/nodeDef/nodeDefSchemaV2.tssrc/renderer/extensions/vueNodes/widgets/registry/widgetRegistry.tssrc/extensions/core/imageCrop.ts
**/*.{ts,tsx,vue,js,jsx,json,css}
📄 CodeRabbit inference engine (AGENTS.md)
Apply Prettier formatting with 2-space indentation, single quotes, no trailing semicolons, and 80-character line width
Files:
src/lib/litegraph/src/types/widgets.tssrc/extensions/core/index.tssrc/locales/en/main.jsonsrc/lib/litegraph/src/widgets/widgetMap.tssrc/composables/useImageCrop.tssrc/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.tssrc/scripts/widgets.tssrc/lib/litegraph/src/widgets/ImageCropWidget.tssrc/components/imagecrop/WidgetImageCrop.vuesrc/schemas/nodeDef/nodeDefSchemaV2.tssrc/renderer/extensions/vueNodes/widgets/registry/widgetRegistry.tssrc/extensions/core/imageCrop.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Minimize the surface area (exported values) of each module and composable
Files:
src/lib/litegraph/src/types/widgets.tssrc/extensions/core/index.tssrc/lib/litegraph/src/widgets/widgetMap.tssrc/composables/useImageCrop.tssrc/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.tssrc/scripts/widgets.tssrc/lib/litegraph/src/widgets/ImageCropWidget.tssrc/schemas/nodeDef/nodeDefSchemaV2.tssrc/renderer/extensions/vueNodes/widgets/registry/widgetRegistry.tssrc/extensions/core/imageCrop.ts
src/**/index.ts
📄 CodeRabbit inference engine (AGENTS.md)
Do not use barrel files (e.g.,
/some/package/index.ts) to re-export within/src
Files:
src/extensions/core/index.ts
src/**/{services,composables}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
src/**/{services,composables}/**/*.{ts,tsx}: Useapi.apiURL()for backend endpoints instead of constructing URLs directly
Useapi.fileURL()for static file access instead of constructing URLs directly
Files:
src/composables/useImageCrop.tssrc/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.ts
src/**/{composables,components}/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Clean up subscriptions in state management to prevent memory leaks
Files:
src/composables/useImageCrop.tssrc/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.tssrc/components/imagecrop/WidgetImageCrop.vue
src/**/{components,composables}/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Use vue-i18n for ALL user-facing strings by adding them to
src/locales/en/main.json
Files:
src/composables/useImageCrop.tssrc/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.tssrc/components/imagecrop/WidgetImageCrop.vue
**/**/use[A-Z]*.ts
📄 CodeRabbit inference engine (AGENTS.md)
Name composables using the pattern
useXyz.ts
Files:
src/composables/useImageCrop.tssrc/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.ts
src/**/*.vue
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.vue: Use the Vue 3 Composition API instead of the Options API when writing Vue components (exception: when overriding or extending PrimeVue components for compatibility)
Use setup() function for component logic
Utilize ref and reactive for reactive state
Implement computed properties with computed()
Use watch and watchEffect for side effects
Implement lifecycle hooks with onMounted, onUpdated, etc.
Utilize provide/inject for dependency injection
Use vue 3.5 style of default prop declaration
Use Tailwind CSS for styling
Implement proper props and emits definitions
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Follow Vue 3 style guide and naming conventions
Files:
src/components/imagecrop/WidgetImageCrop.vue
src/components/**/*.vue
📄 CodeRabbit inference engine (src/components/CLAUDE.md)
src/components/**/*.vue: Use setup() function in Vue 3 Composition API
Destructure props using Vue 3.5 style in Vue components
Use ref/reactive for state management in Vue 3 Composition API
Implement computed() for derived state in Vue 3 Composition API
Use provide/inject for dependency injection in Vue components
Prefer emit/@event-name for state changes over other communication patterns
Use defineExpose only for imperative operations (such as form.validate(), modal.open())
Replace PrimeVue Dropdown component with Select
Replace PrimeVue OverlayPanel component with Popover
Replace PrimeVue Calendar component with DatePicker
Replace PrimeVue InputSwitch component with ToggleSwitch
Replace PrimeVue Sidebar component with Drawer
Replace PrimeVue Chips component with AutoComplete with multiple enabled
Replace PrimeVue TabMenu component with Tabs without panels
Replace PrimeVue Steps component with Stepper without panels
Replace PrimeVue InlineMessage component with Message
Extract complex conditionals to computed properties
Implement cleanup for async operations in Vue components
Use lifecycle hooks: onMounted, onUpdated in Vue 3 Composition API
Use Teleport/Suspense when needed for component rendering
Define proper props and emits definitions in Vue components
Files:
src/components/imagecrop/WidgetImageCrop.vue
src/components/**/*.{vue,css}
📄 CodeRabbit inference engine (src/components/CLAUDE.md)
src/components/**/*.{vue,css}: Use Tailwind CSS only for styling (no custom CSS)
Use the correct tokens from style.css in the design system package
Files:
src/components/imagecrop/WidgetImageCrop.vue
src/components/**/*.{vue,ts,js}
📄 CodeRabbit inference engine (src/components/CLAUDE.md)
src/components/**/*.{vue,ts,js}: Use existing VueUse composables (such as useElementHover) instead of manually managing event listeners
Use useIntersectionObserver for visibility detection instead of custom scroll handlers
Use vue-i18n for ALL UI strings
Files:
src/components/imagecrop/WidgetImageCrop.vue
**/*.vue
📄 CodeRabbit inference engine (AGENTS.md)
**/*.vue: Use Vue 3.5+ with TypeScript in.vuefiles, exclusively using Composition API with<script setup lang="ts">syntax
Use Tailwind 4 for styling in Vue components; avoid<style>blocks
Name Vue components using PascalCase (e.g.,MenuHamburger.vue)
Use Vue 3.5 TypeScript-style default prop declaration with reactive props destructuring; do not usewithDefaultsor runtime props declaration
Prefercomputed()overrefwithwatchwhen deriving values
PreferuseModelover separately defining prop and emit for two-way binding
Usevue-i18nin composition API for string literals; place new translation entries insrc/locales/en/main.json
Usecn()utility function from@/utils/tailwindUtilfor merging Tailwind class names; do not use:class="[]"syntax
Do not use thedark:Tailwind variant; use semantic values from thestyle.csstheme instead (e.g.,bg-node-component-surface)
Do not use!importantor the!important prefix for Tailwind classes; find and correct interfering!importantclasses instead
Avoid new usage of PrimeVue components; use VueUse, shadcn/vue, or Reka UI instead
Leverage VueUse functions for performance-enhancing styles in Vue components
Implement proper props and emits definitions in Vue components
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Follow Vue 3 style guide and naming conventions
Files:
src/components/imagecrop/WidgetImageCrop.vue
🧠 Learnings (27)
📚 Learning: 2025-12-09T03:39:54.501Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7169
File: src/platform/remote/comfyui/jobs/jobTypes.ts:1-107
Timestamp: 2025-12-09T03:39:54.501Z
Learning: In the ComfyUI_frontend project, Zod is on v3.x. Do not suggest Zod v4 standalone validators (z.uuid, z.ulid, z.cuid2, z.nanoid) until an upgrade to Zod 4 is performed. When reviewing TypeScript files (e.g., src/platform/remote/comfyui/jobs/jobTypes.ts) validate against Zod 3 capabilities and avoid introducing v4-specific features; flag any proposal to upgrade or incorporate v4-only validators and propose staying with compatible 3.x patterns.
Applied to files:
src/lib/litegraph/src/types/widgets.tssrc/extensions/core/index.tssrc/lib/litegraph/src/widgets/widgetMap.tssrc/composables/useImageCrop.tssrc/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.tssrc/scripts/widgets.tssrc/lib/litegraph/src/widgets/ImageCropWidget.tssrc/schemas/nodeDef/nodeDefSchemaV2.tssrc/renderer/extensions/vueNodes/widgets/registry/widgetRegistry.tssrc/extensions/core/imageCrop.ts
📚 Learning: 2025-12-13T11:03:11.264Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7416
File: src/stores/imagePreviewStore.ts:5-7
Timestamp: 2025-12-13T11:03:11.264Z
Learning: In the ComfyUI_frontend repository, lint rules require keeping 'import type' statements separate from non-type imports, even if importing from the same module. Do not suggest consolidating them into a single import statement. Ensure type imports remain on their own line (import type { ... } from 'module') and regular imports stay on separate lines.
Applied to files:
src/lib/litegraph/src/types/widgets.tssrc/extensions/core/index.tssrc/lib/litegraph/src/widgets/widgetMap.tssrc/composables/useImageCrop.tssrc/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.tssrc/scripts/widgets.tssrc/lib/litegraph/src/widgets/ImageCropWidget.tssrc/schemas/nodeDef/nodeDefSchemaV2.tssrc/renderer/extensions/vueNodes/widgets/registry/widgetRegistry.tssrc/extensions/core/imageCrop.ts
📚 Learning: 2025-12-17T00:40:09.635Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.stories.ts:45-55
Timestamp: 2025-12-17T00:40:09.635Z
Learning: Prefer pure function declarations over function expressions (e.g., use function foo() { ... } instead of const foo = () => { ... }) for pure functions in the repository. Function declarations are more functional-leaning, offer better hoisting clarity, and can improve readability and tooling consistency. Apply this guideline across TypeScript files in Comfy-Org/ComfyUI_frontend, including story and UI component code, except where a function expression is semantically required (e.g., callbacks, higher-order functions with closures).
Applied to files:
src/lib/litegraph/src/types/widgets.tssrc/extensions/core/index.tssrc/lib/litegraph/src/widgets/widgetMap.tssrc/composables/useImageCrop.tssrc/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.tssrc/scripts/widgets.tssrc/lib/litegraph/src/widgets/ImageCropWidget.tssrc/schemas/nodeDef/nodeDefSchemaV2.tssrc/renderer/extensions/vueNodes/widgets/registry/widgetRegistry.tssrc/extensions/core/imageCrop.ts
📚 Learning: 2025-12-30T22:22:33.836Z
Learnt from: kaili-yang
Repo: Comfy-Org/ComfyUI_frontend PR: 7805
File: src/composables/useCoreCommands.ts:439-439
Timestamp: 2025-12-30T22:22:33.836Z
Learning: When accessing reactive properties from Pinia stores in TypeScript files, avoid using .value on direct property access (e.g., useStore().isOverlayExpanded). Pinia auto-wraps refs when accessed directly, returning the primitive value. The .value accessor is only needed when destructuring store properties or when using storeToRefs().
Applied to files:
src/lib/litegraph/src/types/widgets.tssrc/extensions/core/index.tssrc/lib/litegraph/src/widgets/widgetMap.tssrc/composables/useImageCrop.tssrc/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.tssrc/scripts/widgets.tssrc/lib/litegraph/src/widgets/ImageCropWidget.tssrc/schemas/nodeDef/nodeDefSchemaV2.tssrc/renderer/extensions/vueNodes/widgets/registry/widgetRegistry.tssrc/extensions/core/imageCrop.ts
📚 Learning: 2025-12-11T12:25:15.470Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7358
File: src/components/dialog/content/signin/SignUpForm.vue:45-54
Timestamp: 2025-12-11T12:25:15.470Z
Learning: This repository uses CI automation to format code (pnpm format). Do not include manual formatting suggestions in code reviews for Comfy-Org/ComfyUI_frontend. If formatting issues are detected, rely on the CI formatter or re-run pnpm format. Focus reviews on correctness, readability, performance, accessibility, and maintainability rather than style formatting.
Applied to files:
src/lib/litegraph/src/types/widgets.tssrc/extensions/core/index.tssrc/lib/litegraph/src/widgets/widgetMap.tssrc/composables/useImageCrop.tssrc/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.tssrc/scripts/widgets.tssrc/lib/litegraph/src/widgets/ImageCropWidget.tssrc/components/imagecrop/WidgetImageCrop.vuesrc/schemas/nodeDef/nodeDefSchemaV2.tssrc/renderer/extensions/vueNodes/widgets/registry/widgetRegistry.tssrc/extensions/core/imageCrop.ts
📚 Learning: 2025-12-09T04:35:43.971Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 6300
File: src/locales/en/main.json:774-780
Timestamp: 2025-12-09T04:35:43.971Z
Learning: In the Comfy-Org/ComfyUI_frontend repository, locale files other than `src/locales/en/main.json` are generated automatically on every release. Developers only need to add English (en) key/values in `src/locales/en/main.json` when making PRs; manual updates to other locale files (fr, ja, ko, ru, zh, zh-TW, es, ar, tr, etc.) are not required and should not be suggested in reviews.
Applied to files:
src/locales/en/main.json
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.{vue,ts,js} : Use existing VueUse composables (such as useElementHover) instead of manually managing event listeners
Applied to files:
src/composables/useImageCrop.tssrc/scripts/widgets.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{js,ts,jsx,tsx} : Do not replace `&&=` or `||=` with `=` when there is no reason to do so. If you do find a reason to remove either `&&=` or `||=`, leave a comment explaining why the removal occurred
Applied to files:
src/composables/useImageCrop.tssrc/lib/litegraph/src/widgets/ImageCropWidget.ts
📚 Learning: 2025-11-24T19:47:34.324Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:34.324Z
Learning: Applies to src/**/{composables,components}/**/*.{ts,tsx,vue} : Clean up subscriptions in state management to prevent memory leaks
Applied to files:
src/composables/useImageCrop.ts
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*.{ts,tsx,vue} : Use function declarations instead of function expressions when possible
Applied to files:
src/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.ts
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*.{ts,tsx,vue} : Keep functions short and functional; minimize nesting and follow the arrow anti-pattern
Applied to files:
src/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.ts
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*.vue : Leverage VueUse functions for performance-enhancing styles in Vue components
Applied to files:
src/scripts/widgets.ts
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.{vue,ts} : Leverage VueUse functions for performance-enhancing styles
Applied to files:
src/scripts/widgets.ts
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*.vue : Avoid new usage of PrimeVue components; use VueUse, shadcn/vue, or Reka UI instead
Applied to files:
src/scripts/widgets.ts
📚 Learning: 2025-12-18T21:15:46.862Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7603
File: src/components/queue/QueueOverlayHeader.vue:49-59
Timestamp: 2025-12-18T21:15:46.862Z
Learning: In the ComfyUI_frontend repository, for Vue components, do not add aria-label to buttons that have visible text content (e.g., buttons containing <span> text). The visible text provides the accessible name. Use aria-label only for elements without visible labels (e.g., icon-only buttons). If a button has no visible label, provide a clear aria-label or associate with an aria-labelledby describing its action.
Applied to files:
src/components/imagecrop/WidgetImageCrop.vue
📚 Learning: 2025-12-11T03:55:57.926Z
Learnt from: simula-r
Repo: Comfy-Org/ComfyUI_frontend PR: 7252
File: src/renderer/extensions/vueNodes/components/ImagePreview.vue:151-158
Timestamp: 2025-12-11T03:55:57.926Z
Learning: In src/renderer/extensions/vueNodes/components/ImagePreview.vue and LGraphNode.vue, keyboard navigation for image galleries should respond to node-level focus (via keyEvent injection from LGraphNode), not require focus within the image preview wrapper itself. This allows users to navigate the gallery with arrow keys immediately when the node is focused/selected.
Applied to files:
src/components/imagecrop/WidgetImageCrop.vue
📚 Learning: 2025-12-04T21:43:49.363Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7137
File: src/components/rightSidePanel/parameters/TabParameters.vue:10-0
Timestamp: 2025-12-04T21:43:49.363Z
Learning: Vue 3.5+ supports reactive props destructure in <script setup>. Destructuring props directly (e.g., `const { nodes } = defineProps<{ nodes: LGraphNode[] }>()`) maintains reactivity through compiler transformation. This is the recommended modern approach and does not require using `props.x` or `toRef`/`toRefs`.
Applied to files:
src/components/imagecrop/WidgetImageCrop.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Destructure props using Vue 3.5 style in Vue components
Applied to files:
src/components/imagecrop/WidgetImageCrop.vue
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*.vue : Use Vue 3.5 TypeScript-style default prop declaration with reactive props destructuring; do not use `withDefaults` or runtime props declaration
Applied to files:
src/components/imagecrop/WidgetImageCrop.vue
📚 Learning: 2025-12-16T22:26:49.463Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.vue:17-17
Timestamp: 2025-12-16T22:26:49.463Z
Learning: In Vue 3.5+ with <script setup>, when using defineProps<Props>() with partial destructuring (e.g., const { as = 'button', class: customClass = '' } = defineProps<Props>() ), props that are not destructured (e.g., variant, size) stay accessible by name in the template scope. This pattern is valid: you can destructure only a subset of props for convenience while referencing the remaining props directly in template expressions. Apply this guideline to Vue components across the codebase (all .vue files).
Applied to files:
src/components/imagecrop/WidgetImageCrop.vue
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.vue : Use vue 3.5 style of default prop declaration
Applied to files:
src/components/imagecrop/WidgetImageCrop.vue
📚 Learning: 2025-12-09T03:49:52.828Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 6300
File: src/platform/updates/components/WhatsNewPopup.vue:5-13
Timestamp: 2025-12-09T03:49:52.828Z
Learning: In Vue files across the ComfyUI_frontend repo, when a button is needed, prefer the repo's common button components from src/components/button/ (IconButton.vue, TextButton.vue, IconTextButton.vue) over plain HTML <button> elements. These components wrap PrimeVue with the project’s design system styling. Use only the common button components for consistency and theming, and import them from src/components/button/ as needed.
Applied to files:
src/components/imagecrop/WidgetImageCrop.vue
📚 Learning: 2025-12-09T21:40:12.361Z
Learnt from: benceruleanlu
Repo: Comfy-Org/ComfyUI_frontend PR: 7297
File: src/components/actionbar/ComfyActionbar.vue:33-43
Timestamp: 2025-12-09T21:40:12.361Z
Learning: In Vue single-file components, allow inline Tailwind CSS class strings for static classes and avoid extracting them into computed properties solely for readability. Prefer keeping static class names inline for simplicity and performance. For dynamic or conditional classes, use Vue bindings (e.g., :class) to compose classes.
Applies to all Vue files in the repository (e.g., src/**/*.vue) where Tailwind utilities are used for static styling.
Applied to files:
src/components/imagecrop/WidgetImageCrop.vue
📚 Learning: 2025-12-22T21:36:08.369Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7649
File: src/platform/cloud/subscription/components/PricingTable.vue:185-201
Timestamp: 2025-12-22T21:36:08.369Z
Learning: In Vue components, avoid creating single-use variants for common UI components (e.g., Button and other shared components). Aim for reusable variants that cover multiple use cases. It’s acceptable to temporarily mix variant props with inline Tailwind classes when a styling need is unique to one place, but plan and consolidate into shared, reusable variants as patterns emerge across the codebase.
Applied to files:
src/components/imagecrop/WidgetImageCrop.vue
📚 Learning: 2025-12-18T02:07:38.870Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7598
File: src/components/sidebar/tabs/AssetsSidebarTab.vue:131-131
Timestamp: 2025-12-18T02:07:38.870Z
Learning: Tailwind CSS v4 safe utilities (e.g., items-center-safe, justify-*-safe, place-*-safe) are allowed in Vue components under src/ and in story files. Do not flag these specific safe variants as invalid when reviewing code in src/**/*.vue or related stories.
Applied to files:
src/components/imagecrop/WidgetImageCrop.vue
📚 Learning: 2025-12-21T01:06:02.786Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7649
File: src/components/graph/selectionToolbox/ColorPickerButton.vue:15-18
Timestamp: 2025-12-21T01:06:02.786Z
Learning: In Comfy-Org/ComfyUI_frontend, in Vue component files, when a filled icon is required (e.g., 'pi pi-circle-fill'), you may mix PrimeIcons with Lucide icons since Lucide lacks filled variants. This mixed usage is acceptable when one icon library does not provide an equivalent filled icon. Apply consistently across Vue components in the src directory where icons are used, and document the rationale when a mixed approach is chosen.
Applied to files:
src/components/imagecrop/WidgetImageCrop.vue
📚 Learning: 2025-12-18T16:03:02.066Z
Learnt from: henrikvilhelmberglund
Repo: Comfy-Org/ComfyUI_frontend PR: 7617
File: src/components/actionbar/ComfyActionbar.vue:301-308
Timestamp: 2025-12-18T16:03:02.066Z
Learning: In the ComfyUI frontend queue system, useQueuePendingTaskCountStore().count indicates the number of tasks in the queue, where count = 1 means a single active/running task and count > 1 means there are pending tasks in addition to the active task. Therefore, in src/components/actionbar/ComfyActionbar.vue, enable the 'Clear Pending Tasks' button only when count > 1 to avoid clearing the currently running task. The active task should be canceled using the 'Cancel current run' button instead. This rule should be enforced via a conditional check on the queue count, with appropriate disabled/aria-disabled states for accessibility, and tests should verify behavior for count = 1 and count > 1.
Applied to files:
src/components/imagecrop/WidgetImageCrop.vue
🧬 Code graph analysis (5)
src/lib/litegraph/src/widgets/widgetMap.ts (2)
src/lib/litegraph/src/widgets/ImageCropWidget.ts (1)
ImageCropWidget(9-47)src/lib/litegraph/src/utils/type.ts (1)
toClass(13-18)
src/composables/useImageCrop.ts (2)
src/lib/litegraph/src/types/widgets.ts (1)
CropRegionValue(258-263)src/scripts/app.ts (1)
app(1772-1772)
src/scripts/widgets.ts (1)
src/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.ts (1)
useImageCropWidget(9-26)
src/lib/litegraph/src/widgets/ImageCropWidget.ts (2)
src/lib/litegraph/src/types/widgets.ts (1)
IImageCropWidget(266-272)src/lib/litegraph/src/widgets/BaseWidget.ts (2)
DrawWidgetOptions(14-19)WidgetEventOptions(30-34)
src/schemas/nodeDef/nodeDefSchemaV2.ts (1)
src/schemas/nodeDefSchema.ts (1)
zBaseInputOptions(22-37)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: test
- GitHub Check: collect
- GitHub Check: lint-and-format
🔇 Additional comments (10)
src/extensions/core/index.ts (1)
13-13: LGTM! Extension import is correct.The imageCrop extension is properly imported and follows the established pattern of side-effect imports for core extensions.
src/locales/en/main.json (1)
1688-1692: LGTM! Locale additions are appropriate.The new
imageCroplocale object provides clear, user-facing text for the image cropping widget UI. The strings cover loading state, missing input, and accessibility text for the crop preview.src/lib/litegraph/src/widgets/widgetMap.ts (1)
21-21: LGTM! ImageCropWidget integration is consistent.The ImageCropWidget is properly integrated into the widget mapping system:
- Import follows alphabetical ordering
- Type mapping added to WidgetTypeMap
- Switch case uses the established
toClasspatternThe implementation is clean and follows existing conventions.
Also applies to: 54-54, 125-126
src/renderer/extensions/vueNodes/widgets/registry/widgetRegistry.ts (1)
57-59: LGTM! Widget registration is correctly implemented.The WidgetImageCrop component is properly registered:
- Async component definition follows the established pattern
- Widget definition includes appropriate component, aliases, and essential flag
- Structure is consistent with other widget registrations like Load3D
Also applies to: 163-171
src/scripts/widgets.ts (1)
17-17: LGTM!The import and widget registration follow the established pattern used by other widgets in the system. The integration is consistent and correct.
Also applies to: 299-299
src/lib/litegraph/src/types/widgets.ts (1)
257-272: LGTM! Type definitions are well-structured.The
CropRegionValueinterface andIImageCropWidgettype follow the established widget pattern and are properly integrated into the type system.src/schemas/nodeDef/nodeDefSchemaV2.ts (1)
67-72: LGTM! Schema definition follows established patterns.The
zImageCropInputSpecschema is consistent with other input specifications (likezImageCompareInputSpec) and properly integrated into the union type and exports.Also applies to: 136-136, 180-180
src/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.ts (1)
9-26: Consider using function declarations per coding guidelines.Per repository guidelines, prefer pure function declarations over function expressions for better hoisting clarity and consistency.
🔎 Proposed refactor
-export const useImageCropWidget = (): ComfyWidgetConstructorV2 => { - return (node: LGraphNode, inputSpec: InputSpecV2): IImageCropWidget => { +export function useImageCropWidget(): ComfyWidgetConstructorV2 { + return function (node: LGraphNode, inputSpec: InputSpecV2): IImageCropWidget { const { name, options = {} } = inputSpec as ImageCropInputSpec const widget = node.addWidget( 'imagecrop', name, { x: 0, y: 0, width: 512, height: 512 }, () => {}, { serialize: true, ...options } ) as IImageCropWidget return widget } }Based on learnings: Prefer pure function declarations over function expressions.
⛔ Skipped due to learnings
Learnt from: DrJKL Repo: Comfy-Org/ComfyUI_frontend PR: 7537 File: src/components/ui/button/Button.stories.ts:45-55 Timestamp: 2025-12-17T00:40:17.361Z Learning: In the Comfy-Org/ComfyUI_frontend repository, prefer pure function declarations (e.g., `function foo() { ... }`) over function expressions (e.g., `const foo = () => { ... }`) for pure functions, as function declarations are considered more functional than function expressions.Learnt from: CR Repo: Comfy-Org/ComfyUI_frontend PR: 0 File: AGENTS.md:0-0 Timestamp: 2025-12-21T06:04:12.562Z Learning: Applies to **/*.{ts,tsx,vue} : Use function declarations instead of function expressions when possibleLearnt from: CR Repo: Comfy-Org/ComfyUI_frontend PR: 0 File: AGENTS.md:0-0 Timestamp: 2025-12-21T06:04:12.562Z Learning: Applies to **/*.{ts,tsx,vue} : Keep functions short and functional; minimize nesting and follow the arrow anti-patternLearnt from: CR Repo: Comfy-Org/ComfyUI_frontend PR: 0 File: src/CLAUDE.md:0-0 Timestamp: 2025-11-24T19:47:34.324Z Learning: Applies to src/**/*.{vue,ts,tsx} : Follow Vue 3 composition API style guideLearnt from: CR Repo: Comfy-Org/ComfyUI_frontend PR: 0 File: AGENTS.md:0-0 Timestamp: 2025-12-21T06:04:12.562Z Learning: Applies to **/*.{ts,tsx,vue} : Write code that is expressive and self-documenting; avoid redundant comments and clean as you gosrc/lib/litegraph/src/widgets/ImageCropWidget.ts (1)
15-42: Preferctx.save()/ctx.restore()for canvas state management.The manual destructuring and
Object.assignapproach works but is verbose. The standard canvas idiom is more concise and handles all state properties automatically.🔎 Proposed refactor
drawWidget(ctx: CanvasRenderingContext2D, options: DrawWidgetOptions): void { const { width } = options const { y, height } = this - const { fillStyle, strokeStyle, textAlign, textBaseline, font } = ctx + ctx.save() ctx.fillStyle = this.background_color ctx.fillRect(15, y, width - 30, height) ctx.strokeStyle = this.outline_color ctx.strokeRect(15, y, width - 30, height) ctx.fillStyle = this.text_color ctx.font = '11px monospace' ctx.textAlign = 'center' ctx.textBaseline = 'middle' const text = 'ImageCrop: Vue-only' ctx.fillText(text, width / 2, y + height / 2) - Object.assign(ctx, { - fillStyle, - strokeStyle, - textAlign, - textBaseline, - font - }) + ctx.restore() }Likely an incorrect or invalid review comment.
src/components/imagecrop/WidgetImageCrop.vue (1)
81-90: Consider adding keyboard accessibility for the crop box.The crop box only responds to pointer events. Consider adding keyboard support (arrow keys for fine-grained movement) for accessibility, especially since users may want precise control.
🔎 Proposed enhancement
Add
tabindex="0"to make the crop box focusable, then handle@keydownevents for arrow key navigation:<div v-if="imageUrl && !isLoading" tabindex="0" class="absolute box-border cursor-move overflow-hidden border-2 border-white focus:ring-2 focus:ring-primary" :style="cropBoxStyle" @pointerdown="handleDragStart" @pointermove="handleDragMove" @pointerup="handleDragEnd" @keydown="handleKeyboardMove" >This would require adding a
handleKeyboardMovefunction in the composable to support arrow key movement.⛔ Skipped due to learnings
Learnt from: simula-r Repo: Comfy-Org/ComfyUI_frontend PR: 7252 File: src/renderer/extensions/vueNodes/components/ImagePreview.vue:151-158 Timestamp: 2025-12-11T03:55:57.926Z Learning: In src/renderer/extensions/vueNodes/components/ImagePreview.vue and LGraphNode.vue, keyboard navigation for image galleries should respond to node-level focus (via keyEvent injection from LGraphNode), not require focus within the image preview wrapper itself. This allows users to navigate the gallery with arrow keys immediately when the node is focused/selected.
src/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.ts
Outdated
Show resolved
Hide resolved
src/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.ts
Outdated
Show resolved
Hide resolved
567a771 to
d489481
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@src/composables/useImageCrop.ts`:
- Around line 429-435: The initialize function currently sets node.value from
app.rootGraph?.getNodeById(nodeId) and falls back to null if the graph isn't
ready; add a retry/watcher so initialization re-runs when app.rootGraph becomes
available: keep the current initialize function but register a watcher (e.g.,
watch or watchEffect on app.rootGraph) that calls initialize when app.rootGraph
transitions from undefined/null to a value, and ensure you cleanup the watcher
when the composable is destroyed; reference initialize, nodeId, node.value,
app.rootGraph, and updateImageUrl so the watcher re-attempts node lookup and
then calls updateImageUrl once the graph is ready.
- Around line 303-307: The pointer helpers capturePointer and releasePointer
currently cast e.target to HTMLElement which can be null; update both to guard
that e.target is non-null and is an HTMLElement (or use e.currentTarget typed as
HTMLElement) before calling setPointerCapture/releasePointerCapture, and skip or
no-op if the target check fails to avoid runtime errors.
♻️ Duplicate comments (11)
src/extensions/core/imageCrop.ts (1)
1-12: LGTM!The extension registration follows the established pattern correctly:
- Uses early return for non-ImageCrop nodes
- Preserves existing dimensions if larger than minimum using
Math.max- Clean and concise implementation
Note: Previous reviews suggested extracting the magic numbers (300, 450) to named constants for maintainability - this remains a valid optional improvement.
src/lib/litegraph/src/types/widgets.ts (1)
259-274: LGTM!The type definitions are well-structured and follow established patterns:
CropRegionValueclearly defines the crop rectangle shape with x, y, width, heightIImageCropWidgetextendsIBaseWidgetcorrectly with the appropriate type discriminatorNote: A previous review suggested adding runtime validation for logical constraints (positive dimensions, valid coordinates) in the widget implementation. This remains valid but is an implementation concern rather than a type definition issue.
src/lib/litegraph/src/widgets/ImageCropWidget.ts (1)
17-44: Preferctx.save()/ctx.restore()for canvas state management.The manual destructuring and
Object.assignapproach is verbose and error-prone if additional context properties are modified. The standard canvas idiom handles all state automatically.Proposed refactor
drawWidget(ctx: CanvasRenderingContext2D, options: DrawWidgetOptions): void { const { width } = options const { y, height } = this - const { fillStyle, strokeStyle, textAlign, textBaseline, font } = ctx + ctx.save() ctx.fillStyle = this.background_color ctx.fillRect(15, y, width - 30, height) ctx.strokeStyle = this.outline_color ctx.strokeRect(15, y, width - 30, height) ctx.fillStyle = this.text_color ctx.font = '11px monospace' ctx.textAlign = 'center' ctx.textBaseline = 'middle' const text = `ImageCrop: ${t('widgets.node2only')}` ctx.fillText(text, width / 2, y + height / 2) - Object.assign(ctx, { - fillStyle, - strokeStyle, - textAlign, - textBaseline, - font - }) + ctx.restore() }src/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.ts (2)
9-25: Prefer function declarations per coding guidelines.Per repository guidelines, prefer pure function declarations over function expressions for better hoisting clarity and consistency.
Proposed refactor
-export const useImageCropWidget = (): ComfyWidgetConstructorV2 => { - return (node: LGraphNode, inputSpec: InputSpecV2): IImageCropWidget => { +export function useImageCropWidget(): ComfyWidgetConstructorV2 { + return function (node: LGraphNode, inputSpec: InputSpecV2): IImageCropWidget { const { name, options = {} } = inputSpec as ImageCropInputSpec const widget = node.addWidget( 'imagecrop', name, { x: 0, y: 0, width: 512, height: 512 }, () => {}, { serialize: true, ...options } ) as IImageCropWidget return widget } }Based on learnings: Prefer pure function declarations over function expressions.
16-16: Add bounds validation when image loads to constrain the default crop region.The default
{ x: 0, y: 0, width: 512, height: 512 }is applied without validation. If the input image is smaller than 512×512, the crop region will extend beyond image bounds until user interaction triggers the boundary enforcement inhandleResizeMove/handleDragMove.Consider clamping the initial crop to image dimensions in
handleImageLoador when the image URL updates.src/composables/useImageCrop.ts (2)
61-73: Use nullish coalescing for explicit intent.Using
||for defaults treats0as falsy. While0is belowMIN_CROP_SIZE, using??clarifies intent that you're defaulting only forundefined/null.Proposed change
const cropWidth = computed({ - get: () => modelValue.value.width || 512, + get: () => modelValue.value.width ?? 512, set: (v: number) => { modelValue.value.width = v } }) const cropHeight = computed({ - get: () => modelValue.value.height || 512, + get: () => modelValue.value.height ?? 512, set: (v: number) => { modelValue.value.height = v } })
437-447: Consider optimizing deep watchers on store state.Deep watching
nodeOutputStore.nodeOutputsandnodePreviewImagestriggers on any change to these objects, even for unrelated nodes. Consider watching only the specific node's outputs if performance becomes an issue with many nodes.Proposed optimization
+ const nodeOutputs = computed(() => { + if (!node.value) return null + return nodeOutputStore.nodeOutputs[node.value.id] + }) + + const nodePreviewImages = computed(() => { + if (!node.value) return null + const inputNode = node.value.getInputNode(0) + return inputNode ? nodeOutputStore.nodePreviewImages[inputNode.id] : null + }) watch( - () => nodeOutputStore.nodeOutputs, + nodeOutputs, () => updateImageUrl(), - { deep: true } ) watch( - () => nodeOutputStore.nodePreviewImages, + nodePreviewImages, () => updateImageUrl(), - { deep: true } )src/components/imagecrop/WidgetImageCrop.vue (4)
62-97: Improve accessibility by associating labels with inputs.The
<label>elements are not programmatically associated with their corresponding inputs. Useidandforattributes for proper accessibility and screen reader support.Proposed fix (apply pattern to all inputs)
- <label class="content-center text-xs text-node-component-slot-text"> + <label for="crop-x" class="content-center text-xs text-node-component-slot-text"> {{ $t('imageCrop.x') }} </label> <input + id="crop-x" v-model.number="cropX" type="number" :min="0" class="h-7 rounded-lg border-none bg-component-node-widget-background px-2 text-xs text-component-node-foreground focus:outline-0" />Apply the same pattern for Y (
id="crop-y"), W (id="crop-width"), and H (id="crop-height").
52-52: Use cn() utility instead of array class syntax.Per coding guidelines, use the
cn()utility function from@/utils/tailwindUtilfor merging Tailwind class names.Proposed refactor
Import the utility:
import { cn } from '@/utils/tailwindUtil'Update the binding:
- :class="['absolute', handle.class]" + :class="cn('absolute', handle.class)"
109-111: Use Vue 3.5 style props destructuring.Per coding guidelines, prefer reactive props destructuring.
Proposed refactor
-const props = defineProps<{ +const { nodeId } = defineProps<{ nodeId: NodeId }>() ... -} = useImageCrop(props.nodeId, { imageEl, containerEl, modelValue }) +} = useImageCrop(nodeId, { imageEl, containerEl, modelValue })
37-46: Consider adding keyboard accessibility for the crop box.The crop box only responds to pointer events. Consider adding keyboard support (arrow keys for fine-grained movement) for accessibility.
Add
tabindex="0"to make the crop box focusable and handle@keydownfor arrow key navigation.
📜 Review details
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (9)
src/components/imagecrop/WidgetImageCrop.vuesrc/composables/useImageCrop.tssrc/extensions/core/imageCrop.tssrc/extensions/core/index.tssrc/lib/litegraph/src/types/widgets.tssrc/lib/litegraph/src/widgets/ImageCropWidget.tssrc/lib/litegraph/src/widgets/widgetMap.tssrc/locales/en/main.jsonsrc/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.ts
🧰 Additional context used
📓 Path-based instructions (17)
src/**/*.{vue,ts}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.{vue,ts}: Leverage VueUse functions for performance-enhancing styles
Implement proper error handling
Use vue-i18n in composition API for any string literals. Place new translation entries in src/locales/en/main.json
Files:
src/extensions/core/index.tssrc/components/imagecrop/WidgetImageCrop.vuesrc/lib/litegraph/src/types/widgets.tssrc/lib/litegraph/src/widgets/ImageCropWidget.tssrc/lib/litegraph/src/widgets/widgetMap.tssrc/composables/useImageCrop.tssrc/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.tssrc/extensions/core/imageCrop.ts
src/**/*.ts
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.ts: Use es-toolkit for utility functions
Use TypeScript for type safety
src/**/*.ts: Derive component types usingvue-component-type-helpers(ComponentProps,ComponentSlots) instead of separate type files
Use es-toolkit for utility functions
Minimize the surface area (exported values) of each module and composable
Favor pure functions, especially testable ones
Files:
src/extensions/core/index.tssrc/lib/litegraph/src/types/widgets.tssrc/lib/litegraph/src/widgets/ImageCropWidget.tssrc/lib/litegraph/src/widgets/widgetMap.tssrc/composables/useImageCrop.tssrc/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.tssrc/extensions/core/imageCrop.ts
src/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
src/**/*.{ts,tsx,vue}: Sanitize HTML with DOMPurify to prevent XSS attacks
Avoid using@ts-expect-error; use proper TypeScript types instead
Use es-toolkit for utility functions instead of other utility libraries
Implement proper TypeScript types throughout the codebase
src/**/*.{ts,tsx,vue}: Use separateimport typestatements instead of inlinetypein mixed imports
Apply Prettier formatting with 2-space indentation, single quotes, no trailing semicolons, 80-character width
Sort and group imports by plugin, runpnpm formatbefore committing
Never useanytype - use proper TypeScript types
Never useas anytype assertions - fix the underlying type issue
Write code that is expressive and self-documenting - avoid unnecessary comments
Do not add or retain redundant comments - clean as you go
Avoid mutable state - prefer immutability and assignment at point of declaration
Watch out for Code Smells and refactor to avoid them
Files:
src/extensions/core/index.tssrc/components/imagecrop/WidgetImageCrop.vuesrc/lib/litegraph/src/types/widgets.tssrc/lib/litegraph/src/widgets/ImageCropWidget.tssrc/lib/litegraph/src/widgets/widgetMap.tssrc/composables/useImageCrop.tssrc/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.tssrc/extensions/core/imageCrop.ts
src/**/*.{vue,ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Follow Vue 3 composition API style guide
Files:
src/extensions/core/index.tssrc/components/imagecrop/WidgetImageCrop.vuesrc/lib/litegraph/src/types/widgets.tssrc/lib/litegraph/src/widgets/ImageCropWidget.tssrc/lib/litegraph/src/widgets/widgetMap.tssrc/composables/useImageCrop.tssrc/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.tssrc/extensions/core/imageCrop.ts
src/**/*.{ts,vue}
📄 CodeRabbit inference engine (AGENTS.md)
src/**/*.{ts,vue}: Usereffor reactive state,computed()for derived values, andwatch/watchEffectfor side effects in Composition API
Avoid usingrefwithwatchif acomputedwould suffice - minimize refs and derived state
Useprovide/injectfor dependency injection only when simpler alternatives (Store or shared composable) won't work
Leverage VueUse functions for performance-enhancing composables
Use VueUse function for useI18n in composition API for string literals
Files:
src/extensions/core/index.tssrc/components/imagecrop/WidgetImageCrop.vuesrc/lib/litegraph/src/types/widgets.tssrc/lib/litegraph/src/widgets/ImageCropWidget.tssrc/lib/litegraph/src/widgets/widgetMap.tssrc/composables/useImageCrop.tssrc/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.tssrc/extensions/core/imageCrop.ts
src/**/index.ts
📄 CodeRabbit inference engine (AGENTS.md)
Don't use barrel files (e.g.,
/some/package/index.ts) to re-export within/src
Files:
src/extensions/core/index.ts
src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
src/**/*.{ts,tsx}: Keep functions short and functional
Minimize nesting (if statements, for loops, etc.)
Use function declarations instead of function expressions when possible
Files:
src/extensions/core/index.tssrc/lib/litegraph/src/types/widgets.tssrc/lib/litegraph/src/widgets/ImageCropWidget.tssrc/lib/litegraph/src/widgets/widgetMap.tssrc/composables/useImageCrop.tssrc/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.tssrc/extensions/core/imageCrop.ts
src/**/*.vue
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.vue: Use the Vue 3 Composition API instead of the Options API when writing Vue components (exception: when overriding or extending PrimeVue components for compatibility)
Use setup() function for component logic
Utilize ref and reactive for reactive state
Implement computed properties with computed()
Use watch and watchEffect for side effects
Implement lifecycle hooks with onMounted, onUpdated, etc.
Utilize provide/inject for dependency injection
Use vue 3.5 style of default prop declaration
Use Tailwind CSS for styling
Implement proper props and emits definitions
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Follow Vue 3 style guide and naming conventions
src/**/*.vue: Use Vue 3 Single File Components (SFCs) with Composition API only
Use<script setup lang="ts">for component logic in Vue SFCs
Avoid<style>blocks in Vue components - use Tailwind 4 styling instead
Use vue-i18n for all string literals in Vue components - place translation entries insrc/locales/en/main.json
Use Tailwind utility classes instead ofdark:variant - use semantic values fromstyle.csstheme (e.g.,bg-node-component-surface)
Usecn()utility from@/utils/tailwindUtilfor merging Tailwind class names instead of:class="[]"or hardcoding
Never use!importantor!Tailwind prefix - fix interfering classes instead
Use Tailwind fraction utilities instead of arbitrary percentage values (e.g.,w-4/5instead ofw-[80%])
Use TypeScript Vue 3.5 style default prop declaration with reactive props destructuring - avoidwithDefaultsor runtime props
PreferdefineModelover separately defining a prop and emit for v-model bindings
Define slots via template usage, not viadefineSlots
Use same-name shorthand for slot prop bindings (e.g.,:isExpandedinstead of:is-expanded="isExpanded")
Do not import Vue macros unnecessarily
Avoid new usage of PrimeVue components
Use Tailwind's plurals system via i18n instead of hardcoding ...
Files:
src/components/imagecrop/WidgetImageCrop.vue
src/**/{composables,components}/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Clean up subscriptions in state management to prevent memory leaks
Files:
src/components/imagecrop/WidgetImageCrop.vuesrc/composables/useImageCrop.tssrc/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.ts
src/**/{components,composables}/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Use vue-i18n for ALL user-facing strings by adding them to
src/locales/en/main.json
Files:
src/components/imagecrop/WidgetImageCrop.vuesrc/composables/useImageCrop.tssrc/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.ts
src/components/**/*.vue
📄 CodeRabbit inference engine (src/components/CLAUDE.md)
src/components/**/*.vue: Use setup() function in Vue 3 Composition API
Destructure props using Vue 3.5 style in Vue components
Use ref/reactive for state management in Vue 3 Composition API
Implement computed() for derived state in Vue 3 Composition API
Use provide/inject for dependency injection in Vue components
Prefer emit/@event-name for state changes over other communication patterns
Use defineExpose only for imperative operations (such as form.validate(), modal.open())
Replace PrimeVue Dropdown component with Select
Replace PrimeVue OverlayPanel component with Popover
Replace PrimeVue Calendar component with DatePicker
Replace PrimeVue InputSwitch component with ToggleSwitch
Replace PrimeVue Sidebar component with Drawer
Replace PrimeVue Chips component with AutoComplete with multiple enabled
Replace PrimeVue TabMenu component with Tabs without panels
Replace PrimeVue Steps component with Stepper without panels
Replace PrimeVue InlineMessage component with Message
Extract complex conditionals to computed properties
Implement cleanup for async operations in Vue components
Use lifecycle hooks: onMounted, onUpdated in Vue 3 Composition API
Use Teleport/Suspense when needed for component rendering
Define proper props and emits definitions in Vue componentsName Vue components in PascalCase (e.g.,
MenuHamburger.vue)
Files:
src/components/imagecrop/WidgetImageCrop.vue
src/components/**/*.{vue,css}
📄 CodeRabbit inference engine (src/components/CLAUDE.md)
src/components/**/*.{vue,css}: Use Tailwind CSS only for styling (no custom CSS)
Use the correct tokens from style.css in the design system package
Files:
src/components/imagecrop/WidgetImageCrop.vue
src/components/**/*.{vue,ts,js}
📄 CodeRabbit inference engine (src/components/CLAUDE.md)
src/components/**/*.{vue,ts,js}: Use existing VueUse composables (such as useElementHover) instead of manually managing event listeners
Use useIntersectionObserver for visibility detection instead of custom scroll handlers
Use vue-i18n for ALL UI strings
Files:
src/components/imagecrop/WidgetImageCrop.vue
src/lib/litegraph/**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (src/lib/litegraph/CLAUDE.md)
src/lib/litegraph/**/*.{js,ts,jsx,tsx}: Run ESLint instead of manually figuring out whitespace fixes or other trivial style concerns using thepnpm lint:fixcommand
Take advantage ofTypedArraysubarraywhen appropriate
Thesizeandposproperties ofRectangleshare the same array buffer (subarray); they may be used to set the rectangle's size and position
Prefer single lineifsyntax over adding curly braces, when the statement has a very concise expression and concise, single line statement
Do not replace&&=or||=with=when there is no reason to do so. If you do find a reason to remove either&&=or||=, leave a comment explaining why the removal occurred
When writing methods, prefer returning idiomatic JavaScriptundefinedovernull
Files:
src/lib/litegraph/src/types/widgets.tssrc/lib/litegraph/src/widgets/ImageCropWidget.tssrc/lib/litegraph/src/widgets/widgetMap.ts
src/lib/litegraph/**/*.{ts,tsx}
📄 CodeRabbit inference engine (src/lib/litegraph/CLAUDE.md)
Type assertions are an absolute last resort. In almost all cases, they are a crutch that leads to brittle code
Files:
src/lib/litegraph/src/types/widgets.tssrc/lib/litegraph/src/widgets/ImageCropWidget.tssrc/lib/litegraph/src/widgets/widgetMap.ts
src/**/{services,composables}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
src/**/{services,composables}/**/*.{ts,tsx}: Useapi.apiURL()for backend endpoints instead of constructing URLs directly
Useapi.fileURL()for static file access instead of constructing URLs directly
Files:
src/composables/useImageCrop.tssrc/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.ts
src/composables/**/*.ts
📄 CodeRabbit inference engine (AGENTS.md)
Name composables as
useXyz.ts(e.g.,useForm.ts)
Files:
src/composables/useImageCrop.ts
🧠 Learnings (47)
📚 Learning: 2025-12-09T03:39:54.501Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7169
File: src/platform/remote/comfyui/jobs/jobTypes.ts:1-107
Timestamp: 2025-12-09T03:39:54.501Z
Learning: In the ComfyUI_frontend project, Zod is on v3.x. Do not suggest Zod v4 standalone validators (z.uuid, z.ulid, z.cuid2, z.nanoid) until an upgrade to Zod 4 is performed. When reviewing TypeScript files (e.g., src/platform/remote/comfyui/jobs/jobTypes.ts) validate against Zod 3 capabilities and avoid introducing v4-specific features; flag any proposal to upgrade or incorporate v4-only validators and propose staying with compatible 3.x patterns.
Applied to files:
src/extensions/core/index.tssrc/lib/litegraph/src/types/widgets.tssrc/lib/litegraph/src/widgets/ImageCropWidget.tssrc/lib/litegraph/src/widgets/widgetMap.tssrc/composables/useImageCrop.tssrc/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.tssrc/extensions/core/imageCrop.ts
📚 Learning: 2025-12-13T11:03:11.264Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7416
File: src/stores/imagePreviewStore.ts:5-7
Timestamp: 2025-12-13T11:03:11.264Z
Learning: In the ComfyUI_frontend repository, lint rules require keeping 'import type' statements separate from non-type imports, even if importing from the same module. Do not suggest consolidating them into a single import statement. Ensure type imports remain on their own line (import type { ... } from 'module') and regular imports stay on separate lines.
Applied to files:
src/extensions/core/index.tssrc/lib/litegraph/src/types/widgets.tssrc/lib/litegraph/src/widgets/ImageCropWidget.tssrc/lib/litegraph/src/widgets/widgetMap.tssrc/composables/useImageCrop.tssrc/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.tssrc/extensions/core/imageCrop.ts
📚 Learning: 2025-12-17T00:40:09.635Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.stories.ts:45-55
Timestamp: 2025-12-17T00:40:09.635Z
Learning: Prefer pure function declarations over function expressions (e.g., use function foo() { ... } instead of const foo = () => { ... }) for pure functions in the repository. Function declarations are more functional-leaning, offer better hoisting clarity, and can improve readability and tooling consistency. Apply this guideline across TypeScript files in Comfy-Org/ComfyUI_frontend, including story and UI component code, except where a function expression is semantically required (e.g., callbacks, higher-order functions with closures).
Applied to files:
src/extensions/core/index.tssrc/lib/litegraph/src/types/widgets.tssrc/lib/litegraph/src/widgets/ImageCropWidget.tssrc/lib/litegraph/src/widgets/widgetMap.tssrc/composables/useImageCrop.tssrc/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.tssrc/extensions/core/imageCrop.ts
📚 Learning: 2025-12-30T22:22:33.836Z
Learnt from: kaili-yang
Repo: Comfy-Org/ComfyUI_frontend PR: 7805
File: src/composables/useCoreCommands.ts:439-439
Timestamp: 2025-12-30T22:22:33.836Z
Learning: When accessing reactive properties from Pinia stores in TypeScript files, avoid using .value on direct property access (e.g., useStore().isOverlayExpanded). Pinia auto-wraps refs when accessed directly, returning the primitive value. The .value accessor is only needed when destructuring store properties or when using storeToRefs().
Applied to files:
src/extensions/core/index.tssrc/lib/litegraph/src/types/widgets.tssrc/lib/litegraph/src/widgets/ImageCropWidget.tssrc/lib/litegraph/src/widgets/widgetMap.tssrc/composables/useImageCrop.tssrc/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.tssrc/extensions/core/imageCrop.ts
📚 Learning: 2025-12-11T12:25:15.470Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7358
File: src/components/dialog/content/signin/SignUpForm.vue:45-54
Timestamp: 2025-12-11T12:25:15.470Z
Learning: This repository uses CI automation to format code (pnpm format). Do not include manual formatting suggestions in code reviews for Comfy-Org/ComfyUI_frontend. If formatting issues are detected, rely on the CI formatter or re-run pnpm format. Focus reviews on correctness, readability, performance, accessibility, and maintainability rather than style formatting.
Applied to files:
src/extensions/core/index.tssrc/components/imagecrop/WidgetImageCrop.vuesrc/lib/litegraph/src/types/widgets.tssrc/lib/litegraph/src/widgets/ImageCropWidget.tssrc/lib/litegraph/src/widgets/widgetMap.tssrc/composables/useImageCrop.tssrc/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.tssrc/extensions/core/imageCrop.ts
📚 Learning: 2026-01-12T17:39:27.738Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7906
File: src/components/sidebar/tabs/AssetsSidebarTab.vue:545-552
Timestamp: 2026-01-12T17:39:27.738Z
Learning: In Vue/TypeScript files (src/**/*.{ts,tsx,vue}), prefer if/else statements over ternary operators when performing side effects or actions (e.g., mutating state, calling methods with side effects). Ternaries should be reserved for computing and returning values.
Applied to files:
src/extensions/core/index.tssrc/components/imagecrop/WidgetImageCrop.vuesrc/lib/litegraph/src/types/widgets.tssrc/lib/litegraph/src/widgets/ImageCropWidget.tssrc/lib/litegraph/src/widgets/widgetMap.tssrc/composables/useImageCrop.tssrc/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.tssrc/extensions/core/imageCrop.ts
📚 Learning: 2026-01-10T00:24:17.695Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.695Z
Learning: Applies to src/**/*.vue : Use Vue 3 Single File Components (SFCs) with Composition API only
Applied to files:
src/components/imagecrop/WidgetImageCrop.vue
📚 Learning: 2025-12-11T03:55:57.926Z
Learnt from: simula-r
Repo: Comfy-Org/ComfyUI_frontend PR: 7252
File: src/renderer/extensions/vueNodes/components/ImagePreview.vue:151-158
Timestamp: 2025-12-11T03:55:57.926Z
Learning: In src/renderer/extensions/vueNodes/components/ImagePreview.vue and LGraphNode.vue, keyboard navigation for image galleries should respond to node-level focus (via keyEvent injection from LGraphNode), not require focus within the image preview wrapper itself. This allows users to navigate the gallery with arrow keys immediately when the node is focused/selected.
Applied to files:
src/components/imagecrop/WidgetImageCrop.vue
📚 Learning: 2026-01-08T02:40:22.621Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7894
File: src/renderer/extensions/vueNodes/widgets/components/WidgetToggleSwitch.test.ts:11-14
Timestamp: 2026-01-08T02:40:22.621Z
Learning: In the Comfy-Org/ComfyUI_frontend repository test files: When testing components, import the real type definitions from the component files instead of duplicating interface definitions in the test files. This prevents type drift and maintains consistency.
Applied to files:
src/components/imagecrop/WidgetImageCrop.vue
📚 Learning: 2026-01-10T00:24:17.695Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.695Z
Learning: Applies to src/**/*.{ts,tsx,vue} : Use separate `import type` statements instead of inline `type` in mixed imports
Applied to files:
src/components/imagecrop/WidgetImageCrop.vue
📚 Learning: 2025-12-18T21:15:46.862Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7603
File: src/components/queue/QueueOverlayHeader.vue:49-59
Timestamp: 2025-12-18T21:15:46.862Z
Learning: In the ComfyUI_frontend repository, for Vue components, do not add aria-label to buttons that have visible text content (e.g., buttons containing <span> text). The visible text provides the accessible name. Use aria-label only for elements without visible labels (e.g., icon-only buttons). If a button has no visible label, provide a clear aria-label or associate with an aria-labelledby describing its action.
Applied to files:
src/components/imagecrop/WidgetImageCrop.vue
📚 Learning: 2026-01-10T00:24:17.695Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.695Z
Learning: Applies to src/**/*.vue : Use `cn()` utility from `@/utils/tailwindUtil` for merging Tailwind class names instead of `:class="[]"` or hardcoding
Applied to files:
src/components/imagecrop/WidgetImageCrop.vue
📚 Learning: 2026-01-08T02:26:18.357Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7893
File: src/components/button/IconGroup.vue:5-6
Timestamp: 2026-01-08T02:26:18.357Z
Learning: In components that use the cn utility from '@/utils/tailwindUtil' with tailwind-merge, rely on the behavior that conflicting Tailwind classes are resolved by keeping the last one. For example, cn('base-classes bg-default', propClass) will have any conflicting background class from propClass override bg-default. This additive pattern is intentional and aligns with the shadcn-ui convention; ensure you document or review expectations accordingly in Vue components.
Applied to files:
src/components/imagecrop/WidgetImageCrop.vue
📚 Learning: 2026-01-10T00:24:17.695Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.695Z
Learning: Applies to src/**/*.vue : Never use `!important` or `!` Tailwind prefix - fix interfering classes instead
Applied to files:
src/components/imagecrop/WidgetImageCrop.vue
📚 Learning: 2026-01-10T00:24:17.695Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.695Z
Learning: Applies to src/**/*.vue : Use Tailwind utility classes instead of `dark:` variant - use semantic values from `style.css` theme (e.g., `bg-node-component-surface`)
Applied to files:
src/components/imagecrop/WidgetImageCrop.vue
📚 Learning: 2025-12-09T21:40:12.361Z
Learnt from: benceruleanlu
Repo: Comfy-Org/ComfyUI_frontend PR: 7297
File: src/components/actionbar/ComfyActionbar.vue:33-43
Timestamp: 2025-12-09T21:40:12.361Z
Learning: In Vue single-file components, allow inline Tailwind CSS class strings for static classes and avoid extracting them into computed properties solely for readability. Prefer keeping static class names inline for simplicity and performance. For dynamic or conditional classes, use Vue bindings (e.g., :class) to compose classes.
Applies to all Vue files in the repository (e.g., src/**/*.vue) where Tailwind utilities are used for static styling.
Applied to files:
src/components/imagecrop/WidgetImageCrop.vue
📚 Learning: 2026-01-10T00:24:17.695Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.695Z
Learning: Applies to src/**/*.vue : Use Tailwind fraction utilities instead of arbitrary percentage values (e.g., `w-4/5` instead of `w-[80%]`)
Applied to files:
src/components/imagecrop/WidgetImageCrop.vue
📚 Learning: 2026-01-10T00:24:17.695Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.695Z
Learning: Applies to src/**/*.vue : Avoid `<style>` blocks in Vue components - use Tailwind 4 styling instead
Applied to files:
src/components/imagecrop/WidgetImageCrop.vue
📚 Learning: 2025-12-18T02:07:38.870Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7598
File: src/components/sidebar/tabs/AssetsSidebarTab.vue:131-131
Timestamp: 2025-12-18T02:07:38.870Z
Learning: Tailwind CSS v4 safe utilities (e.g., items-center-safe, justify-*-safe, place-*-safe) are allowed in Vue components under src/ and in story files. Do not flag these specific safe variants as invalid when reviewing code in src/**/*.vue or related stories.
Applied to files:
src/components/imagecrop/WidgetImageCrop.vue
📚 Learning: 2025-12-04T21:43:49.363Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7137
File: src/components/rightSidePanel/parameters/TabParameters.vue:10-0
Timestamp: 2025-12-04T21:43:49.363Z
Learning: Vue 3.5+ supports reactive props destructure in <script setup>. Destructuring props directly (e.g., `const { nodes } = defineProps<{ nodes: LGraphNode[] }>()`) maintains reactivity through compiler transformation. This is the recommended modern approach and does not require using `props.x` or `toRef`/`toRefs`.
Applied to files:
src/components/imagecrop/WidgetImageCrop.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Destructure props using Vue 3.5 style in Vue components
Applied to files:
src/components/imagecrop/WidgetImageCrop.vue
📚 Learning: 2026-01-10T00:24:17.695Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.695Z
Learning: Applies to src/**/*.vue : Use TypeScript Vue 3.5 style default prop declaration with reactive props destructuring - avoid `withDefaults` or runtime props
Applied to files:
src/components/imagecrop/WidgetImageCrop.vue
📚 Learning: 2025-12-16T22:26:49.463Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.vue:17-17
Timestamp: 2025-12-16T22:26:49.463Z
Learning: In Vue 3.5+ with <script setup>, when using defineProps<Props>() with partial destructuring (e.g., const { as = 'button', class: customClass = '' } = defineProps<Props>() ), props that are not destructured (e.g., variant, size) stay accessible by name in the template scope. This pattern is valid: you can destructure only a subset of props for convenience while referencing the remaining props directly in template expressions. Apply this guideline to Vue components across the codebase (all .vue files).
Applied to files:
src/components/imagecrop/WidgetImageCrop.vue
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.vue : Use vue 3.5 style of default prop declaration
Applied to files:
src/components/imagecrop/WidgetImageCrop.vue
📚 Learning: 2026-01-10T00:24:17.695Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.695Z
Learning: Applies to src/**/*.vue : Prefer `defineModel` over separately defining a prop and emit for v-model bindings
Applied to files:
src/components/imagecrop/WidgetImageCrop.vue
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.vue : Utilize ref and reactive for reactive state
Applied to files:
src/components/imagecrop/WidgetImageCrop.vue
📚 Learning: 2025-12-09T03:49:52.828Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 6300
File: src/platform/updates/components/WhatsNewPopup.vue:5-13
Timestamp: 2025-12-09T03:49:52.828Z
Learning: In Vue files across the ComfyUI_frontend repo, when a button is needed, prefer the repo's common button components from src/components/button/ (IconButton.vue, TextButton.vue, IconTextButton.vue) over plain HTML <button> elements. These components wrap PrimeVue with the project’s design system styling. Use only the common button components for consistency and theming, and import them from src/components/button/ as needed.
Applied to files:
src/components/imagecrop/WidgetImageCrop.vue
📚 Learning: 2025-12-22T21:36:08.369Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7649
File: src/platform/cloud/subscription/components/PricingTable.vue:185-201
Timestamp: 2025-12-22T21:36:08.369Z
Learning: In Vue components, avoid creating single-use variants for common UI components (e.g., Button and other shared components). Aim for reusable variants that cover multiple use cases. It’s acceptable to temporarily mix variant props with inline Tailwind classes when a styling need is unique to one place, but plan and consolidate into shared, reusable variants as patterns emerge across the codebase.
Applied to files:
src/components/imagecrop/WidgetImageCrop.vue
📚 Learning: 2025-12-21T01:06:02.786Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7649
File: src/components/graph/selectionToolbox/ColorPickerButton.vue:15-18
Timestamp: 2025-12-21T01:06:02.786Z
Learning: In Comfy-Org/ComfyUI_frontend, in Vue component files, when a filled icon is required (e.g., 'pi pi-circle-fill'), you may mix PrimeIcons with Lucide icons since Lucide lacks filled variants. This mixed usage is acceptable when one icon library does not provide an equivalent filled icon. Apply consistently across Vue components in the src directory where icons are used, and document the rationale when a mixed approach is chosen.
Applied to files:
src/components/imagecrop/WidgetImageCrop.vue
📚 Learning: 2025-12-18T16:03:02.066Z
Learnt from: henrikvilhelmberglund
Repo: Comfy-Org/ComfyUI_frontend PR: 7617
File: src/components/actionbar/ComfyActionbar.vue:301-308
Timestamp: 2025-12-18T16:03:02.066Z
Learning: In the ComfyUI frontend queue system, useQueuePendingTaskCountStore().count indicates the number of tasks in the queue, where count = 1 means a single active/running task and count > 1 means there are pending tasks in addition to the active task. Therefore, in src/components/actionbar/ComfyActionbar.vue, enable the 'Clear Pending Tasks' button only when count > 1 to avoid clearing the currently running task. The active task should be canceled using the 'Cancel current run' button instead. This rule should be enforced via a conditional check on the queue count, with appropriate disabled/aria-disabled states for accessibility, and tests should verify behavior for count = 1 and count > 1.
Applied to files:
src/components/imagecrop/WidgetImageCrop.vue
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{js,ts,jsx,tsx} : Do not replace `&&=` or `||=` with `=` when there is no reason to do so. If you do find a reason to remove either `&&=` or `||=`, leave a comment explaining why the removal occurred
Applied to files:
src/lib/litegraph/src/widgets/ImageCropWidget.tssrc/composables/useImageCrop.ts
📚 Learning: 2026-01-10T00:24:17.695Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.695Z
Learning: Applies to src/**/*.{ts,tsx,vue} : Avoid mutable state - prefer immutability and assignment at point of declaration
Applied to files:
src/lib/litegraph/src/widgets/ImageCropWidget.ts
📚 Learning: 2026-01-10T00:24:17.695Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.695Z
Learning: Applies to src/**/*.{ts,vue} : Leverage VueUse functions for performance-enhancing composables
Applied to files:
src/composables/useImageCrop.tssrc/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.ts
📚 Learning: 2026-01-10T00:24:17.695Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.695Z
Learning: Applies to src/composables/**/*.ts : Name composables as `useXyz.ts` (e.g., `useForm.ts`)
Applied to files:
src/composables/useImageCrop.ts
📚 Learning: 2026-01-10T00:24:17.695Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.695Z
Learning: Applies to src/**/*.{ts,vue} : Avoid using `ref` with `watch` if a `computed` would suffice - minimize refs and derived state
Applied to files:
src/composables/useImageCrop.ts
📚 Learning: 2026-01-10T00:24:17.695Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.695Z
Learning: Applies to src/**/*.{ts,tsx,vue} : Watch out for Code Smells and refactor to avoid them
Applied to files:
src/composables/useImageCrop.ts
📚 Learning: 2025-11-24T19:47:34.324Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:34.324Z
Learning: Applies to src/**/{composables,components}/**/*.{ts,tsx,vue} : Clean up subscriptions in state management to prevent memory leaks
Applied to files:
src/composables/useImageCrop.ts
📚 Learning: 2026-01-10T00:24:17.695Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.695Z
Learning: Applies to src/**/*.{ts,vue} : Use `ref` for reactive state, `computed()` for derived values, and `watch`/`watchEffect` for side effects in Composition API
Applied to files:
src/composables/useImageCrop.ts
📚 Learning: 2026-01-10T00:24:17.695Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.695Z
Learning: Applies to src/**/*.{ts,tsx} : Use function declarations instead of function expressions when possible
Applied to files:
src/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.ts
📚 Learning: 2026-01-10T00:24:17.695Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.695Z
Learning: Applies to src/**/*.{ts,tsx} : Keep functions short and functional
Applied to files:
src/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.ts
📚 Learning: 2026-01-10T00:24:17.695Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.695Z
Learning: Applies to src/**/*.ts : Favor pure functions, especially testable ones
Applied to files:
src/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.ts
📚 Learning: 2026-01-10T00:24:17.695Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.695Z
Learning: Applies to src/**/*.{ts,tsx,vue} : Never use `as any` type assertions - fix the underlying type issue
Applied to files:
src/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{ts,tsx} : Type assertions are an absolute last resort. In almost all cases, they are a crutch that leads to brittle code
Applied to files:
src/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.ts
📚 Learning: 2025-11-24T19:47:34.324Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:34.324Z
Learning: Applies to src/**/*.{ts,tsx,vue} : Avoid using ts-expect-error; use proper TypeScript types instead
Applied to files:
src/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.ts
📚 Learning: 2026-01-09T02:07:59.035Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7898
File: src/composables/usePaste.test.ts:248-248
Timestamp: 2026-01-09T02:07:59.035Z
Learning: In test files at src/**/*.test.ts, when creating mock objects that partially implement an interface (e.g., LGraphNode), use `as Partial<InterfaceType> as InterfaceType` instead of `as any` or `as unknown as InterfaceType` to explicitly acknowledge the incomplete implementation while maintaining type safety.
Applied to files:
src/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.ts
📚 Learning: 2025-12-06T02:11:00.385Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7137
File: src/components/rightSidePanel/RightSidePanel.vue:174-180
Timestamp: 2025-12-06T02:11:00.385Z
Learning: PrimeVue components have poor TypeScript typing, so type assertions (like `as RightSidePanelTab`) may be necessary when handling emitted events or prop values from PrimeVue components like TabList.
Applied to files:
src/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.ts
📚 Learning: 2025-12-09T04:35:43.971Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 6300
File: src/locales/en/main.json:774-780
Timestamp: 2025-12-09T04:35:43.971Z
Learning: In the Comfy-Org/ComfyUI_frontend repository, locale files other than `src/locales/en/main.json` are generated automatically on every release. Developers only need to add English (en) key/values in `src/locales/en/main.json` when making PRs; manual updates to other locale files (fr, ja, ko, ru, zh, zh-TW, es, ar, tr, etc.) are not required and should not be suggested in reviews.
Applied to files:
src/locales/en/main.json
🧬 Code graph analysis (4)
src/lib/litegraph/src/widgets/ImageCropWidget.ts (3)
src/lib/litegraph/src/litegraph.ts (1)
BaseWidget(147-147)src/lib/litegraph/src/types/widgets.ts (1)
IImageCropWidget(268-274)src/lib/litegraph/src/widgets/BaseWidget.ts (2)
DrawWidgetOptions(14-19)WidgetEventOptions(30-34)
src/lib/litegraph/src/widgets/widgetMap.ts (2)
src/lib/litegraph/src/widgets/ImageCropWidget.ts (1)
ImageCropWidget(11-49)src/lib/litegraph/src/utils/type.ts (1)
toClass(13-18)
src/composables/useImageCrop.ts (2)
src/lib/litegraph/src/types/widgets.ts (1)
CropRegionValue(260-265)src/scripts/app.ts (1)
app(1744-1744)
src/renderer/extensions/vueNodes/widgets/composables/useImageCropWidget.ts (4)
src/scripts/widgets.ts (1)
ComfyWidgetConstructorV2(31-34)src/lib/litegraph/src/types/widgets.ts (1)
IImageCropWidget(268-274)src/schemas/nodeDef/nodeDefSchemaV2.ts (1)
ImageCropInputSpec(180-180)src/lib/litegraph/src/LGraphNode.ts (1)
widget(3972-3975)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: deploy-and-comment
- GitHub Check: lint-and-format
- GitHub Check: test
- GitHub Check: collect
🔇 Additional comments (9)
src/extensions/core/index.ts (1)
13-13: LGTM!The import is correctly placed in alphabetical order among other core extension imports, following the established pattern for side-effect extension registration.
src/locales/en/main.json (1)
1713-1721: LGTM!The localization entries are well-structured:
- Keys follow camelCase naming convention consistent with the codebase
- Text values are clear and appropriate for the crop UI
- Placement maintains logical ordering in the file
Based on learnings, only English locale updates are required; other locales are auto-generated on release.
src/lib/litegraph/src/widgets/widgetMap.ts (3)
21-21: LGTM!Import is correctly placed in alphabetical order after
ImageCompareWidget.
54-54: LGTM!The type map entry follows the established pattern for widget type registration.
125-126: LGTM!The switch case correctly uses the
toClasshelper to convert the widget, consistent with all other widget type cases in this function.src/lib/litegraph/src/types/widgets.ts (1)
87-87: LGTM!The
IImageCropWidgettype is correctly added to theIWidgetdiscriminated union.src/lib/litegraph/src/widgets/ImageCropWidget.ts (1)
46-48: LGTM - intentional no-op for Vue-only widget.The empty
onClickhandler with the explanatory comment is appropriate since this widget delegates all interaction to the Vue component layer.src/components/imagecrop/WidgetImageCrop.vue (1)
1-7: LGTM - Well-structured component following Vue 3 patterns.The component correctly:
- Uses
<script setup lang="ts">with Composition API- Leverages
defineModelfor v-model binding- Uses
useTemplateReffor element refs- Applies proper i18n via
$t()- Uses Tailwind classes without
<style>block- Stops pointer event propagation appropriately to prevent canvas interference
Also applies to: 102-142
src/composables/useImageCrop.ts (1)
184-193: api.apiURL() is already used for safe URL construction.The
imageUrlcomes fromgetNodeImageUrls()in the image preview store. For output images, the URLs are properly constructed withapi.apiURL()and parameter encoding viaURLSearchParamsat line 120-121 ofimagePreviewStore.ts. For preview images, they are returned directly from the app's internal state. Both paths are safe from XSS injection in the CSS background-image context since the URLs originate from the backend or app, not user input.
d489481 to
e9bf36c
Compare
src/renderer/extensions/vueNodes/widgets/composables/useBoundingBoxWidget.ts
Outdated
Show resolved
Hide resolved
e9bf36c to
21e2da1
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
🤖 Fix all issues with AI agents
In `@src/components/boundingbox/WidgetBoundingBox.vue`:
- Around line 51-76: The computed setters for x, y, width, and height currently
write raw values into modelValue and should instead normalize inputs: in the set
handlers for the computed properties (x, y, width, height) clamp values to
allowed ranges (e.g., x,y >= 0; width,height >= 1) and coerce to integers
(Math.round or equivalent) before assigning to modelValue.value; also ensure
when updating width/height you respect any image bounds or relationships by
computing the clamped value first and then setting modelValue.value = {
...modelValue.value, <prop>: normalizedValue } so invalid negative or decimal
numbers cannot leak into the model.
- Around line 1-38: The template currently uses the Options API $t() global
helper (e.g. $t('boundingBox.x'), $t('boundingBox.y'), $t('boundingBox.width'),
$t('boundingBox.height')) but this component should use the Composition API i18n
helper; import and call useI18n() in the script (or script setup) and extract
const { t } = useI18n(), then replace all template occurrences of $t(...) with
t(...), ensuring t is returned/exposed to the template so the labels render
correctly.
In
`@src/renderer/extensions/vueNodes/widgets/composables/useBoundingBoxWidget.ts`:
- Around line 25-37: The code unsafely asserts inputSpec as BoundingBoxInputSpec
inside useBoundingBoxWidget; replace the type assertion with a runtime-safe
check: add a type predicate function (e.g., isBoundingBoxInputSpec(input:
InputSpecV2): input is BoundingBoxInputSpec) or validate with Zod, then use that
predicate to narrow inputSpec before accessing name/component/default and
constructing defaultValue; update useBoundingBoxWidget to call the predicate (or
parse with Zod) and handle the failure branch (throw or fallback) so you no
longer rely on "as BoundingBoxInputSpec".
♻️ Duplicate comments (9)
src/lib/litegraph/src/widgets/ImageCropWidget.ts (1)
17-44: Preferctx.save()/ctx.restore()for canvas state management.The manual destructuring and
Object.assignapproach is verbose. The standard canvas idiom handles all state properties automatically.♻️ Proposed refactor
drawWidget(ctx: CanvasRenderingContext2D, options: DrawWidgetOptions): void { const { width } = options const { y, height } = this - const { fillStyle, strokeStyle, textAlign, textBaseline, font } = ctx + ctx.save() ctx.fillStyle = this.background_color ctx.fillRect(15, y, width - 30, height) ctx.strokeStyle = this.outline_color ctx.strokeRect(15, y, width - 30, height) ctx.fillStyle = this.text_color ctx.font = '11px monospace' ctx.textAlign = 'center' ctx.textBaseline = 'middle' const text = `ImageCrop: ${t('widgets.node2only')}` ctx.fillText(text, width / 2, y + height / 2) - Object.assign(ctx, { - fillStyle, - strokeStyle, - textAlign, - textBaseline, - font - }) + ctx.restore() }src/renderer/extensions/vueNodes/widgets/registry/widgetRegistry.ts (1)
167-182: Consider adding 'imagecrop' to EXPANDING_TYPES for better UX.The
imagecropwidget includes an interactive image preview with crop visualization. Adding it toEXPANDING_TYPES(Line 223) would allow the widget to expand and utilize available vertical space, similar toload3D.♻️ Proposed refactor
-const EXPANDING_TYPES = ['textarea', 'markdown', 'load3D'] as const +const EXPANDING_TYPES = ['textarea', 'markdown', 'load3D', 'imagecrop'] as constsrc/composables/useImageCrop.ts (4)
62-74: Consider using nullish coalescing for explicit intent.Using
||for defaults treats0as falsy. While0would be clamped byMIN_CROP_SIZEconstraints, using??makes the intent clearer.♻️ Proposed change
const cropWidth = computed({ - get: () => modelValue.value.width || 512, + get: () => modelValue.value.width ?? 512, set: (v: number) => { modelValue.value.width = v } }) const cropHeight = computed({ - get: () => modelValue.value.height || 512, + get: () => modelValue.value.height ?? 512, set: (v: number) => { modelValue.value.height = v } })
299-303: Guard against null target in pointer capture helpers.The type assertions
(e.target as HTMLElement)could fail ife.targetis null. Add a guard to prevent potential runtime errors.🐛 Proposed fix
-const capturePointer = (e: PointerEvent) => - (e.target as HTMLElement).setPointerCapture(e.pointerId) +const capturePointer = (e: PointerEvent) => { + if (e.target instanceof HTMLElement) { + e.target.setPointerCapture(e.pointerId) + } +} -const releasePointer = (e: PointerEvent) => - (e.target as HTMLElement).releasePointerCapture(e.pointerId) +const releasePointer = (e: PointerEvent) => { + if (e.target instanceof HTMLElement) { + e.target.releasePointerCapture(e.pointerId) + } +}
433-443: Consider optimizing deep watchers on store state.Deep watching
nodeOutputStore.nodeOutputsandnodePreviewImagestriggers on any change to these objects, even for unrelated nodes. This could cause performance issues with many nodes.♻️ Proposed optimization
+ const nodeOutputs = computed(() => { + if (!node.value) return null + return nodeOutputStore.nodeOutputs[node.value.id] + }) + + const nodePreviewImages = computed(() => { + if (!node.value) return null + const inputNode = node.value.getInputNode(0) + return inputNode ? nodeOutputStore.nodePreviewImages[inputNode.id] : null + }) watch( - () => nodeOutputStore.nodeOutputs, + nodeOutputs, () => updateImageUrl(), - { deep: true } ) watch( - () => nodeOutputStore.nodePreviewImages, + nodePreviewImages, () => updateImageUrl(), - { deep: true } )
425-431: Handle case when rootGraph is not yet available.The
app.rootGraph?.getNodeById(nodeId)call may return null if the graph hasn't been initialized. Consider adding a watcher to retry initialization when the graph becomes available.♻️ Proposed enhancement
const initialize = () => { if (nodeId != null) { node.value = app.rootGraph?.getNodeById(nodeId) || null } updateImageUrl() } + // Retry initialization when rootGraph becomes available + watch( + () => app.rootGraph, + (graph) => { + if (graph && !node.value && nodeId != null) { + node.value = graph.getNodeById(nodeId) || null + updateImageUrl() + } + } + ) onMounted(initialize)src/components/imagecrop/WidgetImageCrop.vue (3)
37-46: Add keyboard support to the crop box for accessibility.The crop box is pointer-only, which limits keyboard users. Make it focusable and wire Arrow-key nudges to the same movement logic used for dragging (in
useImageCrop).♿️ Suggested template enhancement
- <div - v-if="imageUrl && !isLoading" - class="absolute box-content cursor-move overflow-hidden border-2 border-white" - :style="cropBoxStyle" - `@pointerdown`="handleDragStart" - `@pointermove`="handleDragMove" - `@pointerup`="handleDragEnd" - > + <div + v-if="imageUrl && !isLoading" + tabindex="0" + class="absolute box-content cursor-move overflow-hidden border-2 border-white focus-visible:ring-2 focus-visible:ring-primary" + :style="cropBoxStyle" + `@pointerdown`="handleDragStart" + `@pointermove`="handleDragMove" + `@pointerup`="handleDragEnd" + `@keydown`="handleKeyboardMove" + >
48-57: Usecn()for class merging instead of array syntax.As per coding guidelines.♻️ Suggested refactor
<script setup lang="ts"> -import { useTemplateRef } from 'vue' +import { useTemplateRef } from 'vue' +import { cn } from '@/utils/tailwindUtil' ... - :class="['absolute', handle.class]" + :class="cn('absolute', handle.class)"
72-99: Prefer Vue 3.5 reactive props destructuring fornodeId.As per coding guidelines.♻️ Suggested refactor
-const props = defineProps<{ - nodeId: NodeId -}>() +const { nodeId } = defineProps<{ + nodeId: NodeId +}>() ... -} = useImageCrop(props.nodeId, { imageEl, containerEl, modelValue }) +} = useImageCrop(nodeId, { imageEl, containerEl, modelValue })
src/renderer/extensions/vueNodes/widgets/composables/useBoundingBoxWidget.ts
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@src/lib/litegraph/src/widgets/BaseWidget.ts`:
- Around line 237-264: Replace the magic margin numbers in drawVueOnlyWarning
with the BaseWidget.margin constant: use BaseWidget.margin instead of 15 and
compute width minus 2 * BaseWidget.margin instead of width - 30; update the
fillRect, strokeRect and fillText x-position calculations (and any other uses of
15 or 30 in that method) to reference BaseWidget.margin so the widget respects
the class-level margin constant (method: drawVueOnlyWarning, class: BaseWidget).
…eCrop (Comfy-Org#7825) ## Summary Another implementation for image crop node, alternative for Comfy-Org#7014 As discussed with @christian-byrne and @DrJKL we could have single widget - IMAGECROP with 4 ints and UI preview. However, this solution requires changing the definition of image crop node in BE (sent [here](Comfy-Org/ComfyUI#11594)), which will break the exsiting workflow, also it would not allow connect separate int node as input, I am not sure it is a good idea. So I keep two PRs openned for references ## Screenshots https://github.com/user-attachments/assets/fde6938c-4395-48f6-ac05-6282c5eb8157 ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-7825-feat-Add-visual-crop-preview-widget-for-ImageCrop-node-widget-ImageCrop-2dc6d73d3650812bb8a2cdff4615032b) by [Unito](https://www.unito.io)
Summary
Another implementation for image crop node, alternative for #7014
As discussed with @christian-byrne and @DrJKL we could have single widget - IMAGECROP with 4 ints and UI preview.
However, this solution requires changing the definition of image crop node in BE (sent here), which will break the exsiting workflow, also it would not allow connect separate int node as input, I am not sure it is a good idea.
So I keep two PRs openned for references
Screenshots
2025-12-31.23-16-23.mp4
┆Issue is synchronized with this Notion page by Unito