mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-03-25 07:05:43 -03:00
feat(ui): add keyboard navigation for LoRA strength inputs, #432
This commit is contained in:
@@ -75,6 +75,61 @@ export function addLorasWidget(node, name, opts, callback) {
|
|||||||
|
|
||||||
// Parse the loras data
|
// Parse the loras data
|
||||||
const lorasData = parseLoraValue(value);
|
const lorasData = parseLoraValue(value);
|
||||||
|
const focusSequence = [];
|
||||||
|
|
||||||
|
const createFocusEntry = (loraName, type) => {
|
||||||
|
const entry = { name: loraName, type };
|
||||||
|
focusSequence.push(entry);
|
||||||
|
return entry;
|
||||||
|
};
|
||||||
|
|
||||||
|
const escapeLoraName = (loraName) => {
|
||||||
|
const css =
|
||||||
|
(typeof window !== "undefined" && window.CSS) ||
|
||||||
|
(typeof globalThis !== "undefined" && globalThis.CSS);
|
||||||
|
if (css && typeof css.escape === "function") {
|
||||||
|
return css.escape(loraName);
|
||||||
|
}
|
||||||
|
return loraName.replace(/"|\\/g, "\\$&");
|
||||||
|
};
|
||||||
|
|
||||||
|
const focusAdjacentFrom = (currentEntry, direction) => {
|
||||||
|
const currentIndex = focusSequence.indexOf(currentEntry);
|
||||||
|
if (currentIndex === -1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const targetEntry = focusSequence[currentIndex + direction];
|
||||||
|
if (!targetEntry) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
const safeName = escapeLoraName(targetEntry.name);
|
||||||
|
let selector = "";
|
||||||
|
|
||||||
|
if (targetEntry.type === "strength") {
|
||||||
|
selector = `.comfy-lora-entry[data-lora-name="${safeName}"] .comfy-lora-strength-input`;
|
||||||
|
} else if (targetEntry.type === "clip") {
|
||||||
|
selector = `.comfy-lora-clip-entry[data-lora-name="${safeName}"] .comfy-lora-clip-strength-input`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!selector) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const targetInput = container.querySelector(selector);
|
||||||
|
if (targetInput) {
|
||||||
|
targetInput.focus();
|
||||||
|
if (typeof targetInput.select === "function") {
|
||||||
|
targetInput.select();
|
||||||
|
}
|
||||||
|
selectLora(targetEntry.name);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
if (lorasData.length === 0) {
|
if (lorasData.length === 0) {
|
||||||
// Show message when no loras are added
|
// Show message when no loras are added
|
||||||
@@ -194,6 +249,7 @@ export function addLorasWidget(node, name, opts, callback) {
|
|||||||
|
|
||||||
// Determine expansion state using our helper function
|
// Determine expansion state using our helper function
|
||||||
const isExpanded = shouldShowClipEntry(loraData);
|
const isExpanded = shouldShowClipEntry(loraData);
|
||||||
|
const strengthFocusEntry = createFocusEntry(name, "strength");
|
||||||
|
|
||||||
// Create the main LoRA entry
|
// Create the main LoRA entry
|
||||||
const loraEl = document.createElement("div");
|
const loraEl = document.createElement("div");
|
||||||
@@ -351,6 +407,7 @@ export function addLorasWidget(node, name, opts, callback) {
|
|||||||
|
|
||||||
// Strength display
|
// Strength display
|
||||||
const strengthEl = document.createElement("input");
|
const strengthEl = document.createElement("input");
|
||||||
|
strengthEl.classList.add("comfy-lora-strength-input");
|
||||||
strengthEl.type = "text";
|
strengthEl.type = "text";
|
||||||
strengthEl.value = typeof strength === 'number' ? strength.toFixed(2) : Number(strength).toFixed(2);
|
strengthEl.value = typeof strength === 'number' ? strength.toFixed(2) : Number(strength).toFixed(2);
|
||||||
Object.assign(strengthEl.style, {
|
Object.assign(strengthEl.style, {
|
||||||
@@ -383,6 +440,7 @@ export function addLorasWidget(node, name, opts, callback) {
|
|||||||
strengthEl.style.background = "rgba(0, 0, 0, 0.2)";
|
strengthEl.style.background = "rgba(0, 0, 0, 0.2)";
|
||||||
// Auto-select all content
|
// Auto-select all content
|
||||||
strengthEl.select();
|
strengthEl.select();
|
||||||
|
selectLora(name);
|
||||||
});
|
});
|
||||||
|
|
||||||
strengthEl.addEventListener('blur', () => {
|
strengthEl.addEventListener('blur', () => {
|
||||||
@@ -391,33 +449,41 @@ export function addLorasWidget(node, name, opts, callback) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Handle input changes
|
// Handle input changes
|
||||||
strengthEl.addEventListener('change', () => {
|
const commitStrengthValue = () => {
|
||||||
let newValue = parseFloat(strengthEl.value);
|
let parsedValue = parseFloat(strengthEl.value);
|
||||||
|
if (isNaN(parsedValue)) {
|
||||||
// Validate input
|
parsedValue = 1.0;
|
||||||
if (isNaN(newValue)) {
|
|
||||||
newValue = 1.0;
|
|
||||||
}
|
}
|
||||||
|
const normalizedValue = parsedValue.toFixed(2);
|
||||||
// Update value
|
|
||||||
const lorasData = parseLoraValue(widget.value);
|
const currentLoras = parseLoraValue(widget.value);
|
||||||
const loraIndex = lorasData.findIndex(l => l.name === name);
|
const loraIndex = currentLoras.findIndex(l => l.name === name);
|
||||||
|
|
||||||
if (loraIndex >= 0) {
|
if (loraIndex >= 0) {
|
||||||
lorasData[loraIndex].strength = newValue.toFixed(2);
|
currentLoras[loraIndex].strength = normalizedValue;
|
||||||
// Sync clipStrength if collapsed
|
// Sync clipStrength if collapsed
|
||||||
syncClipStrengthIfCollapsed(lorasData[loraIndex]);
|
syncClipStrengthIfCollapsed(currentLoras[loraIndex]);
|
||||||
|
|
||||||
// Update value and trigger callback
|
strengthEl.value = normalizedValue;
|
||||||
const newLorasValue = formatLoraValue(lorasData);
|
const newLorasValue = formatLoraValue(currentLoras);
|
||||||
widget.value = newLorasValue;
|
widget.value = newLorasValue;
|
||||||
|
} else {
|
||||||
|
strengthEl.value = normalizedValue;
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
|
strengthEl.addEventListener('change', commitStrengthValue);
|
||||||
|
|
||||||
// Handle key events
|
// Handle key events
|
||||||
strengthEl.addEventListener('keydown', (e) => {
|
strengthEl.addEventListener('keydown', (e) => {
|
||||||
if (e.key === 'Enter') {
|
if (e.key === 'Enter') {
|
||||||
strengthEl.blur();
|
strengthEl.blur();
|
||||||
|
} else if (e.key === 'Tab') {
|
||||||
|
commitStrengthValue();
|
||||||
|
const moved = focusAdjacentFrom(strengthFocusEntry, e.shiftKey ? -1 : 1);
|
||||||
|
if (moved) {
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -524,6 +590,7 @@ export function addLorasWidget(node, name, opts, callback) {
|
|||||||
|
|
||||||
// Clip strength display
|
// Clip strength display
|
||||||
const clipStrengthEl = document.createElement("input");
|
const clipStrengthEl = document.createElement("input");
|
||||||
|
clipStrengthEl.classList.add("comfy-lora-strength-input", "comfy-lora-clip-strength-input");
|
||||||
clipStrengthEl.type = "text";
|
clipStrengthEl.type = "text";
|
||||||
clipStrengthEl.value = typeof clipStrength === 'number' ? clipStrength.toFixed(2) : Number(clipStrength).toFixed(2);
|
clipStrengthEl.value = typeof clipStrength === 'number' ? clipStrength.toFixed(2) : Number(clipStrength).toFixed(2);
|
||||||
Object.assign(clipStrengthEl.style, {
|
Object.assign(clipStrengthEl.style, {
|
||||||
@@ -556,6 +623,7 @@ export function addLorasWidget(node, name, opts, callback) {
|
|||||||
clipStrengthEl.style.background = "rgba(0, 0, 0, 0.2)";
|
clipStrengthEl.style.background = "rgba(0, 0, 0, 0.2)";
|
||||||
// Auto-select all content
|
// Auto-select all content
|
||||||
clipStrengthEl.select();
|
clipStrengthEl.select();
|
||||||
|
selectLora(name);
|
||||||
});
|
});
|
||||||
|
|
||||||
clipStrengthEl.addEventListener('blur', () => {
|
clipStrengthEl.addEventListener('blur', () => {
|
||||||
@@ -564,31 +632,41 @@ export function addLorasWidget(node, name, opts, callback) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Handle input changes
|
// Handle input changes
|
||||||
clipStrengthEl.addEventListener('change', () => {
|
const clipFocusEntry = createFocusEntry(name, "clip");
|
||||||
let newValue = parseFloat(clipStrengthEl.value);
|
|
||||||
|
const commitClipStrengthValue = () => {
|
||||||
// Validate input
|
let parsedValue = parseFloat(clipStrengthEl.value);
|
||||||
if (isNaN(newValue)) {
|
if (isNaN(parsedValue)) {
|
||||||
newValue = 1.0;
|
parsedValue = 1.0;
|
||||||
}
|
}
|
||||||
|
const normalizedValue = parsedValue.toFixed(2);
|
||||||
// Update value
|
|
||||||
const lorasData = parseLoraValue(widget.value);
|
const currentLoras = parseLoraValue(widget.value);
|
||||||
const loraIndex = lorasData.findIndex(l => l.name === name);
|
const loraIndex = currentLoras.findIndex(l => l.name === name);
|
||||||
|
|
||||||
if (loraIndex >= 0) {
|
if (loraIndex >= 0) {
|
||||||
lorasData[loraIndex].clipStrength = newValue.toFixed(2);
|
currentLoras[loraIndex].clipStrength = normalizedValue;
|
||||||
|
clipStrengthEl.value = normalizedValue;
|
||||||
// Update value and trigger callback
|
|
||||||
const newLorasValue = formatLoraValue(lorasData);
|
const newLorasValue = formatLoraValue(currentLoras);
|
||||||
widget.value = newLorasValue;
|
widget.value = newLorasValue;
|
||||||
|
} else {
|
||||||
|
clipStrengthEl.value = normalizedValue;
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
|
clipStrengthEl.addEventListener('change', commitClipStrengthValue);
|
||||||
|
|
||||||
// Handle key events
|
// Handle key events
|
||||||
clipStrengthEl.addEventListener('keydown', (e) => {
|
clipStrengthEl.addEventListener('keydown', (e) => {
|
||||||
if (e.key === 'Enter') {
|
if (e.key === 'Enter') {
|
||||||
clipStrengthEl.blur();
|
clipStrengthEl.blur();
|
||||||
|
} else if (e.key === 'Tab') {
|
||||||
|
commitClipStrengthValue();
|
||||||
|
const moved = focusAdjacentFrom(clipFocusEntry, e.shiftKey ? -1 : 1);
|
||||||
|
if (moved) {
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -220,6 +220,7 @@ export function createExpandButton(isExpanded, onClick) {
|
|||||||
const button = document.createElement("button");
|
const button = document.createElement("button");
|
||||||
button.className = "comfy-lora-expand-button";
|
button.className = "comfy-lora-expand-button";
|
||||||
button.type = "button";
|
button.type = "button";
|
||||||
|
button.tabIndex = -1;
|
||||||
|
|
||||||
Object.assign(button.style, {
|
Object.assign(button.style, {
|
||||||
width: "20px",
|
width: "20px",
|
||||||
|
|||||||
Reference in New Issue
Block a user