diff --git a/src/components/graph/SelectionOverlay.vue b/src/components/graph/SelectionOverlay.vue
index d0b6e9eb6..3bc41574a 100644
--- a/src/components/graph/SelectionOverlay.vue
+++ b/src/components/graph/SelectionOverlay.vue
@@ -14,12 +14,13 @@
+ * ```
+ */
+export function useRetriggerableAnimation(
+ trigger?: WatchSource | Ref,
+ options: {
+ animateOnMount?: boolean
+ animationDelay?: number
+ } = {}
+) {
+ const { animateOnMount = true, animationDelay = 0 } = options
+
+ const shouldAnimate = ref(false)
+
+ /**
+ * Retriggers the animation by removing and re-adding the animation class
+ */
+ const retriggerAnimation = () => {
+ // Remove animation class
+ shouldAnimate.value = false
+ // Force browser reflow to ensure the class removal is processed
+ void document.body.offsetHeight
+ // Re-add animation class in the next frame
+ requestAnimationFrame(() => {
+ if (animationDelay > 0) {
+ setTimeout(() => {
+ shouldAnimate.value = true
+ }, animationDelay)
+ } else {
+ shouldAnimate.value = true
+ }
+ })
+ }
+
+ // Trigger animation on mount if requested
+ if (animateOnMount) {
+ onMounted(() => {
+ if (animationDelay > 0) {
+ setTimeout(() => {
+ shouldAnimate.value = true
+ }, animationDelay)
+ } else {
+ shouldAnimate.value = true
+ }
+ })
+ }
+
+ // Watch for trigger changes to retrigger animation
+ if (trigger) {
+ watch(trigger, () => {
+ retriggerAnimation()
+ })
+ }
+
+ return {
+ shouldAnimate,
+ retriggerAnimation
+ }
+}
diff --git a/src/lib/litegraph/src/LGraphCanvas.ts b/src/lib/litegraph/src/LGraphCanvas.ts
index cbb644cbf..d7778d5a1 100644
--- a/src/lib/litegraph/src/LGraphCanvas.ts
+++ b/src/lib/litegraph/src/LGraphCanvas.ts
@@ -4130,6 +4130,7 @@ export class LGraphCanvas
const selected = this.selectedItems
if (!selected.size) return
+ const initialSelectionSize = selected.size
let wasSelected: Positionable | undefined
for (const sel of selected) {
if (sel === keepSelected) {
@@ -4170,8 +4171,12 @@ export class LGraphCanvas
}
}
- this.state.selectionChanged = true
- this.onSelectionChange?.(this.selected_nodes)
+ // Only set selectionChanged if selection actually changed
+ const finalSelectionSize = selected.size
+ if (initialSelectionSize !== finalSelectionSize) {
+ this.state.selectionChanged = true
+ this.onSelectionChange?.(this.selected_nodes)
+ }
}
/** @deprecated See {@link LGraphCanvas.deselectAll} */
diff --git a/src/types/selectionOverlayTypes.ts b/src/types/selectionOverlayTypes.ts
new file mode 100644
index 000000000..ee370e274
--- /dev/null
+++ b/src/types/selectionOverlayTypes.ts
@@ -0,0 +1,9 @@
+import type { InjectionKey, Ref } from 'vue'
+
+export interface SelectionOverlayState {
+ visible: Readonly[>
+ updateCount: Readonly][>
+}
+
+export const SelectionOverlayInjectionKey: InjectionKey =
+ Symbol('selectionOverlayState')
]