feat(loras): add drag event callbacks and preview suppression

- Add onDragStart and onDragEnd callbacks to initDrag function
- Implement preview suppression during and briefly after strength dragging
- Clear preview timer on drag start/end to prevent tooltip conflicts
- Update tests to verify drag callbacks are properly triggered

This prevents tooltip previews from interfering with drag interactions and provides better control over drag lifecycle events.
This commit is contained in:
Will Miao
2025-11-03 12:18:59 +08:00
parent 707d0cb8a4
commit 30f9e3e2ec
3 changed files with 83 additions and 10 deletions

View File

@@ -36,6 +36,28 @@ export function addLorasWidget(node, name, opts, callback) {
// Selection state - only one LoRA can be selected at a time
let selectedLora = null;
let pendingFocusTarget = null;
const PREVIEW_SUPPRESSION_AFTER_DRAG_MS = 500;
let strengthDragActive = false;
let lastStrengthDragEndAt = 0;
const shouldSuppressPreview = () => {
if (strengthDragActive) {
return true;
}
return Date.now() - lastStrengthDragEndAt < PREVIEW_SUPPRESSION_AFTER_DRAG_MS;
};
const markStrengthDragStart = () => {
strengthDragActive = true;
previewTooltip.hide();
};
const markStrengthDragEnd = () => {
strengthDragActive = false;
lastStrengthDragEndAt = Date.now();
previewTooltip.hide();
};
// Function to select a LoRA
const selectLora = (loraName) => {
@@ -259,23 +281,47 @@ export function addLorasWidget(node, name, opts, callback) {
nameEl.className = "lm-lora-name";
// Move preview tooltip events to nameEl instead of loraEl
let previewTimer; // Timer for delayed preview
nameEl.addEventListener('mouseenter', async (e) => {
let previewTimer = null; // Timer for delayed preview
const clearPreviewTimer = () => {
if (previewTimer) {
clearTimeout(previewTimer);
previewTimer = null;
}
};
nameEl.addEventListener('mouseenter', (e) => {
e.stopPropagation();
const rect = nameEl.getBoundingClientRect();
if (shouldSuppressPreview()) {
return;
}
previewTimer = setTimeout(async () => {
previewTimer = null;
if (shouldSuppressPreview()) {
return;
}
const rect = nameEl.getBoundingClientRect();
await previewTooltip.show(name, rect.right, rect.top);
}, 400); // 400ms delay
});
nameEl.addEventListener('mouseleave', (e) => {
e.stopPropagation();
clearTimeout(previewTimer); // Cancel if not triggered
clearPreviewTimer(); // Cancel if not triggered
previewTooltip.hide();
});
// Initialize drag functionality for strength adjustment
initDrag(loraEl, name, widget, false, previewTooltip, renderLoras);
initDrag(loraEl, name, widget, false, previewTooltip, renderLoras, {
onDragStart: () => {
clearPreviewTimer();
markStrengthDragStart();
},
onDragEnd: () => {
clearPreviewTimer();
markStrengthDragEnd();
}
});
// Add context menu event
loraEl.addEventListener('contextmenu', (e) => {
@@ -511,7 +557,10 @@ export function addLorasWidget(node, name, opts, callback) {
clipEl.appendChild(clipStrengthControl);
// Add drag functionality to clip entry
initDrag(clipEl, name, widget, true, previewTooltip, renderLoras);
initDrag(clipEl, name, widget, true, previewTooltip, renderLoras, {
onDragStart: markStrengthDragStart,
onDragEnd: markStrengthDragEnd
});
container.appendChild(clipEl);
}

View File

@@ -97,10 +97,19 @@ export function handleAllStrengthsDrag(initialStrengths, initialX, event, widget
}
// Function to initialize drag operation
export function initDrag(dragEl, name, widget, isClipStrength = false, previewTooltip, renderFunction) {
export function initDrag(
dragEl,
name,
widget,
isClipStrength = false,
previewTooltip,
renderFunction,
dragCallbacks = {}
) {
let isDragging = false;
let initialX = 0;
let initialStrength = 0;
const { onDragStart, onDragEnd } = dragCallbacks;
// Create a drag handler
dragEl.addEventListener('mousedown', (e) => {
@@ -122,10 +131,14 @@ export function initDrag(dragEl, name, widget, isClipStrength = false, previewTo
initialX = e.clientX;
initialStrength = isClipStrength ? loraData.clipStrength : loraData.strength;
isDragging = true;
// Add class to body to enforce cursor style globally
document.body.classList.add('lm-lora-strength-dragging');
if (typeof onDragStart === 'function') {
onDragStart();
}
// Prevent text selection during drag
e.preventDefault();
});
@@ -154,6 +167,10 @@ export function initDrag(dragEl, name, widget, isClipStrength = false, previewTo
isDragging = false;
// Remove the class to restore normal cursor behavior
document.body.classList.remove('lm-lora-strength-dragging');
if (typeof onDragEnd === 'function') {
onDragEnd();
}
}
});
}