mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-03-21 21:22:11 -03:00
feat(autocomplete): support input element sharing for subgraph promotion
Store textarea reference on container element to allow cloned widgets to access inputEl when promoted to subgraph nodes. This ensures both original and cloned widgets can properly get and set values through the shared DOM element.
This commit is contained in:
@@ -117,6 +117,16 @@ onMounted(() => {
|
|||||||
// Register textarea reference with widget
|
// Register textarea reference with widget
|
||||||
if (textareaRef.value) {
|
if (textareaRef.value) {
|
||||||
props.widget.inputEl = textareaRef.value
|
props.widget.inputEl = textareaRef.value
|
||||||
|
|
||||||
|
// Also store on the container element for cloned widgets (subgraph promotion)
|
||||||
|
// When widgets are promoted to subgraph nodes, the cloned widget shares the same
|
||||||
|
// DOM element but has its own inputEl property. We store the reference on the
|
||||||
|
// container so both original and cloned widgets can access it.
|
||||||
|
const container = textareaRef.value.closest('[id^="autocomplete-text-widget-"]') as HTMLElement
|
||||||
|
if (container && (container as any).__widgetInputEl) {
|
||||||
|
(container as any).__widgetInputEl.inputEl = textareaRef.value
|
||||||
|
}
|
||||||
|
|
||||||
// Initialize hasText state
|
// Initialize hasText state
|
||||||
hasText.value = textareaRef.value.value.length > 0
|
hasText.value = textareaRef.value.value.length > 0
|
||||||
|
|
||||||
|
|||||||
@@ -405,19 +405,29 @@ function createAutocompleteTextWidgetFactory(
|
|||||||
|
|
||||||
forwardMiddleMouseToCanvas(container)
|
forwardMiddleMouseToCanvas(container)
|
||||||
|
|
||||||
|
// Store textarea reference on the container element so cloned widgets can access it
|
||||||
|
// This is necessary because when widgets are promoted to subgraph nodes,
|
||||||
|
// the cloned widget shares the same element but needs access to inputEl
|
||||||
|
const widgetElementRef = { inputEl: undefined as HTMLTextAreaElement | undefined }
|
||||||
|
;(container as any).__widgetInputEl = widgetElementRef
|
||||||
|
|
||||||
const widget = node.addDOMWidget(
|
const widget = node.addDOMWidget(
|
||||||
widgetName,
|
widgetName,
|
||||||
`AUTOCOMPLETE_TEXT_${modelType.toUpperCase()}`,
|
`AUTOCOMPLETE_TEXT_${modelType.toUpperCase()}`,
|
||||||
container,
|
container,
|
||||||
{
|
{
|
||||||
getValue() {
|
getValue() {
|
||||||
return widget.inputEl?.value ?? ''
|
// Access inputEl from widget or from the shared element reference
|
||||||
|
const inputEl = widget.inputEl ?? (container as any).__widgetInputEl?.inputEl
|
||||||
|
return inputEl?.value ?? ''
|
||||||
},
|
},
|
||||||
setValue(v: string) {
|
setValue(v: string) {
|
||||||
if (widget.inputEl) {
|
// Access inputEl from widget or from the shared element reference
|
||||||
widget.inputEl.value = v ?? ''
|
const inputEl = widget.inputEl ?? (container as any).__widgetInputEl?.inputEl
|
||||||
|
if (inputEl) {
|
||||||
|
inputEl.value = v ?? ''
|
||||||
// Notify Vue component of value change via custom event
|
// Notify Vue component of value change via custom event
|
||||||
widget.inputEl.dispatchEvent(new CustomEvent('lora-manager:autocomplete-value-changed', {
|
inputEl.dispatchEvent(new CustomEvent('lora-manager:autocomplete-value-changed', {
|
||||||
detail: { value: v ?? '' }
|
detail: { value: v ?? '' }
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1988,14 +1988,14 @@ to { transform: rotate(360deg);
|
|||||||
padding: 20px 0;
|
padding: 20px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.autocomplete-text-widget[data-v-2081708c] {
|
.autocomplete-text-widget[data-v-653446fd] {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
.input-wrapper[data-v-2081708c] {
|
.input-wrapper[data-v-653446fd] {
|
||||||
position: relative;
|
position: relative;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -2003,7 +2003,7 @@ to { transform: rotate(360deg);
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Canvas mode styles (default) - matches built-in comfy-multiline-input */
|
/* Canvas mode styles (default) - matches built-in comfy-multiline-input */
|
||||||
.text-input[data-v-2081708c] {
|
.text-input[data-v-653446fd] {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background-color: var(--comfy-input-bg, #222);
|
background-color: var(--comfy-input-bg, #222);
|
||||||
@@ -2020,7 +2020,7 @@ to { transform: rotate(360deg);
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Vue DOM mode styles - matches built-in p-textarea in Vue DOM mode */
|
/* Vue DOM mode styles - matches built-in p-textarea in Vue DOM mode */
|
||||||
.text-input.vue-dom-mode[data-v-2081708c] {
|
.text-input.vue-dom-mode[data-v-653446fd] {
|
||||||
background-color: var(--color-charcoal-400, #313235);
|
background-color: var(--color-charcoal-400, #313235);
|
||||||
color: #fff;
|
color: #fff;
|
||||||
padding: 8px 12px;
|
padding: 8px 12px;
|
||||||
@@ -2029,12 +2029,12 @@ to { transform: rotate(360deg);
|
|||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
font-family: inherit;
|
font-family: inherit;
|
||||||
}
|
}
|
||||||
.text-input[data-v-2081708c]:focus {
|
.text-input[data-v-653446fd]:focus {
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Clear button styles */
|
/* Clear button styles */
|
||||||
.clear-button[data-v-2081708c] {
|
.clear-button[data-v-653446fd] {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 4px;
|
right: 4px;
|
||||||
top: 4px;
|
top: 4px;
|
||||||
@@ -2054,27 +2054,27 @@ to { transform: rotate(360deg);
|
|||||||
transition: opacity 0.2s ease, background-color 0.2s ease;
|
transition: opacity 0.2s ease, background-color 0.2s ease;
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
}
|
}
|
||||||
.clear-button[data-v-2081708c]:hover {
|
.clear-button[data-v-653446fd]:hover {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
background: rgba(255, 100, 100, 0.8);
|
background: rgba(255, 100, 100, 0.8);
|
||||||
}
|
}
|
||||||
.clear-button svg[data-v-2081708c] {
|
.clear-button svg[data-v-653446fd] {
|
||||||
width: 12px;
|
width: 12px;
|
||||||
height: 12px;
|
height: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Vue DOM mode adjustments for clear button */
|
/* Vue DOM mode adjustments for clear button */
|
||||||
.text-input.vue-dom-mode ~ .clear-button[data-v-2081708c] {
|
.text-input.vue-dom-mode ~ .clear-button[data-v-653446fd] {
|
||||||
right: 8px;
|
right: 8px;
|
||||||
top: 8px;
|
top: 8px;
|
||||||
width: 20px;
|
width: 20px;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
background: rgba(107, 114, 128, 0.6);
|
background: rgba(107, 114, 128, 0.6);
|
||||||
}
|
}
|
||||||
.text-input.vue-dom-mode ~ .clear-button[data-v-2081708c]:hover {
|
.text-input.vue-dom-mode ~ .clear-button[data-v-653446fd]:hover {
|
||||||
background: oklch(62% 0.18 25);
|
background: oklch(62% 0.18 25);
|
||||||
}
|
}
|
||||||
.text-input.vue-dom-mode ~ .clear-button svg[data-v-2081708c] {
|
.text-input.vue-dom-mode ~ .clear-button svg[data-v-653446fd] {
|
||||||
width: 14px;
|
width: 14px;
|
||||||
height: 14px;
|
height: 14px;
|
||||||
}`));
|
}`));
|
||||||
@@ -14256,6 +14256,10 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
if (textareaRef.value) {
|
if (textareaRef.value) {
|
||||||
props.widget.inputEl = textareaRef.value;
|
props.widget.inputEl = textareaRef.value;
|
||||||
|
const container = textareaRef.value.closest('[id^="autocomplete-text-widget-"]');
|
||||||
|
if (container && container.__widgetInputEl) {
|
||||||
|
container.__widgetInputEl.inputEl = textareaRef.value;
|
||||||
|
}
|
||||||
hasText.value = textareaRef.value.value.length > 0;
|
hasText.value = textareaRef.value.value.length > 0;
|
||||||
textareaRef.value.addEventListener("lora-manager:autocomplete-value-changed", onExternalValueChange);
|
textareaRef.value.addEventListener("lora-manager:autocomplete-value-changed", onExternalValueChange);
|
||||||
}
|
}
|
||||||
@@ -14320,7 +14324,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const AutocompleteTextWidget = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-2081708c"]]);
|
const AutocompleteTextWidget = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-653446fd"]]);
|
||||||
const LORA_PROVIDER_NODE_TYPES$1 = [
|
const LORA_PROVIDER_NODE_TYPES$1 = [
|
||||||
"Lora Stacker (LoraManager)",
|
"Lora Stacker (LoraManager)",
|
||||||
"Lora Randomizer (LoraManager)",
|
"Lora Randomizer (LoraManager)",
|
||||||
@@ -14890,6 +14894,8 @@ function createAutocompleteTextWidgetFactory(node, widgetName, modelType, inputO
|
|||||||
container.style.flexDirection = "column";
|
container.style.flexDirection = "column";
|
||||||
container.style.overflow = "hidden";
|
container.style.overflow = "hidden";
|
||||||
forwardMiddleMouseToCanvas(container);
|
forwardMiddleMouseToCanvas(container);
|
||||||
|
const widgetElementRef = { inputEl: void 0 };
|
||||||
|
container.__widgetInputEl = widgetElementRef;
|
||||||
const widget = node.addDOMWidget(
|
const widget = node.addDOMWidget(
|
||||||
widgetName,
|
widgetName,
|
||||||
`AUTOCOMPLETE_TEXT_${modelType.toUpperCase()}`,
|
`AUTOCOMPLETE_TEXT_${modelType.toUpperCase()}`,
|
||||||
@@ -14897,12 +14903,15 @@ function createAutocompleteTextWidgetFactory(node, widgetName, modelType, inputO
|
|||||||
{
|
{
|
||||||
getValue() {
|
getValue() {
|
||||||
var _a3;
|
var _a3;
|
||||||
return ((_a3 = widget.inputEl) == null ? void 0 : _a3.value) ?? "";
|
const inputEl = widget.inputEl ?? ((_a3 = container.__widgetInputEl) == null ? void 0 : _a3.inputEl);
|
||||||
|
return (inputEl == null ? void 0 : inputEl.value) ?? "";
|
||||||
},
|
},
|
||||||
setValue(v2) {
|
setValue(v2) {
|
||||||
if (widget.inputEl) {
|
var _a3;
|
||||||
widget.inputEl.value = v2 ?? "";
|
const inputEl = widget.inputEl ?? ((_a3 = container.__widgetInputEl) == null ? void 0 : _a3.inputEl);
|
||||||
widget.inputEl.dispatchEvent(new CustomEvent("lora-manager:autocomplete-value-changed", {
|
if (inputEl) {
|
||||||
|
inputEl.value = v2 ?? "";
|
||||||
|
inputEl.dispatchEvent(new CustomEvent("lora-manager:autocomplete-value-changed", {
|
||||||
detail: { value: v2 ?? "" }
|
detail: { value: v2 ?? "" }
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user