Improve combo refresh logic
This commit is contained in:
@@ -82,8 +82,9 @@ export default class ComfyGraph extends LGraph {
|
|||||||
const [index, spec] = pair
|
const [index, spec] = pair
|
||||||
const input = comfyNode.inputs[index] as IComfyInputSlot;
|
const input = comfyNode.inputs[index] as IComfyInputSlot;
|
||||||
input.defaultWidgetNode = spec.defaultWidgetNode;
|
input.defaultWidgetNode = spec.defaultWidgetNode;
|
||||||
if (spec.config)
|
if (spec.config) {
|
||||||
input.config = spec.config
|
input.config = spec.config
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Block, BlockTitle } from "@gradio/atoms";
|
import { Block, BlockTitle } from "@gradio/atoms";
|
||||||
import { Accordion } from "@gradio/accordion";
|
import Accordion from "$lib/components/gradio/app/Accordion.svelte";
|
||||||
import uiState from "$lib/stores/uiState";
|
import uiState from "$lib/stores/uiState";
|
||||||
import WidgetContainer from "./WidgetContainer.svelte"
|
import WidgetContainer from "./WidgetContainer.svelte"
|
||||||
|
|
||||||
@@ -50,6 +50,10 @@
|
|||||||
children = layoutState.updateChildren(container, evt.detail.items)
|
children = layoutState.updateChildren(container, evt.detail.items)
|
||||||
// Ensure dragging is stopped on drag finish
|
// Ensure dragging is stopped on drag finish
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function handleClick({ clicked }: CustomEvent<boolean>) {
|
||||||
|
navigator.vibrate(20)
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if container && children}
|
{#if container && children}
|
||||||
@@ -100,7 +104,7 @@
|
|||||||
</Block>
|
</Block>
|
||||||
{:else}
|
{:else}
|
||||||
<Block elem_classes={["gradio-accordion"]}>
|
<Block elem_classes={["gradio-accordion"]}>
|
||||||
<Accordion label={container.attrs.title} bind:open={container.isOpen}>
|
<Accordion label={container.attrs.title} bind:open={container.isOpen} on:click={handleClick}>
|
||||||
{#each children.filter(item => item.id !== SHADOW_PLACEHOLDER_ITEM_ID) as item(item.id)}
|
{#each children.filter(item => item.id !== SHADOW_PLACEHOLDER_ITEM_ID) as item(item.id)}
|
||||||
<WidgetContainer dragItem={item} zIndex={zIndex+1} {isMobile} />
|
<WidgetContainer dragItem={item} zIndex={zIndex+1} {isMobile} />
|
||||||
{/each}
|
{/each}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import ComfyGraphCanvas, { type SerializedGraphCanvasState } from "$lib/ComfyGra
|
|||||||
import type ComfyGraphNode from "$lib/nodes/ComfyGraphNode";
|
import type ComfyGraphNode from "$lib/nodes/ComfyGraphNode";
|
||||||
import * as widgets from "$lib/widgets/index"
|
import * as widgets from "$lib/widgets/index"
|
||||||
import queueState from "$lib/stores/queueState";
|
import queueState from "$lib/stores/queueState";
|
||||||
import type { SvelteComponentDev } from "svelte/internal";
|
import { type SvelteComponentDev } from "svelte/internal";
|
||||||
import type IComfyInputSlot from "$lib/IComfyInputSlot";
|
import type IComfyInputSlot from "$lib/IComfyInputSlot";
|
||||||
import type { SerializedLayoutState } from "$lib/stores/layoutState";
|
import type { SerializedLayoutState } from "$lib/stores/layoutState";
|
||||||
import layoutState from "$lib/stores/layoutState";
|
import layoutState from "$lib/stores/layoutState";
|
||||||
@@ -27,8 +27,9 @@ import { toast } from '@zerodevx/svelte-toast'
|
|||||||
import ComfyGraph from "$lib/ComfyGraph";
|
import ComfyGraph from "$lib/ComfyGraph";
|
||||||
import { ComfyBackendNode } from "$lib/nodes/ComfyBackendNode";
|
import { ComfyBackendNode } from "$lib/nodes/ComfyBackendNode";
|
||||||
import { get } from "svelte/store";
|
import { get } from "svelte/store";
|
||||||
|
import { tick } from "svelte";
|
||||||
import uiState from "$lib/stores/uiState";
|
import uiState from "$lib/stores/uiState";
|
||||||
import { download, jsonToJsObject, promptToGraphVis, workflowToGraphVis } from "$lib/utils";
|
import { download, jsonToJsObject, promptToGraphVis, range, workflowToGraphVis } from "$lib/utils";
|
||||||
import notify from "$lib/notify";
|
import notify from "$lib/notify";
|
||||||
import configState from "$lib/stores/configState";
|
import configState from "$lib/stores/configState";
|
||||||
|
|
||||||
@@ -72,6 +73,12 @@ export type Progress = {
|
|||||||
max: number
|
max: number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type BackendComboNode = {
|
||||||
|
comboNode: nodes.ComfyComboNode
|
||||||
|
inputSlot: IComfyInputSlot,
|
||||||
|
backendNode: ComfyBackendNode
|
||||||
|
}
|
||||||
|
|
||||||
function isActiveBackendNode(node: ComfyGraphNode, tag: string | null): boolean {
|
function isActiveBackendNode(node: ComfyGraphNode, tag: string | null): boolean {
|
||||||
if (!node.isBackendNode)
|
if (!node.isBackendNode)
|
||||||
return false;
|
return false;
|
||||||
@@ -764,47 +771,78 @@ export default class ComfyApp {
|
|||||||
async refreshComboInNodes(flashUI: boolean = false) {
|
async refreshComboInNodes(flashUI: boolean = false) {
|
||||||
const defs = await this.api.getNodeDefs();
|
const defs = await this.api.getNodeDefs();
|
||||||
|
|
||||||
for (let nodeNum in this.lGraph._nodes) {
|
const toUpdate: BackendComboNode[] = []
|
||||||
const node = this.lGraph._nodes[nodeNum];
|
|
||||||
if (node.type === "ui/combo") {
|
const isComfyComboNode = (node: LGraphNode): boolean => {
|
||||||
(node as nodes.ComfyComboNode).valuesForCombo = null;
|
return node
|
||||||
(node as nodes.ComfyComboNode).comboRefreshed.set(true);
|
&& node.type === "ui/combo"
|
||||||
|
&& "doAutoConfig" in node;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Node IDs of combo widgets attached to a backend node
|
||||||
|
let backendCombos: Set<number> = new Set()
|
||||||
|
|
||||||
|
console.debug("[refreshComboInNodes] start")
|
||||||
|
|
||||||
|
// Figure out which combo nodes to update. They need to be connected to
|
||||||
|
// an input slot on a backend node with a backend config in the input
|
||||||
|
// slot connected to.
|
||||||
|
for (const node of this.lGraph.iterateNodesInOrder()) {
|
||||||
|
if (!(node as any).isBackendNode)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const backendNode = (node as ComfyBackendNode)
|
||||||
|
const inputIndex = range(backendNode.inputs.length)
|
||||||
|
.find(i => {
|
||||||
|
const input = backendNode.inputs[i]
|
||||||
|
const inputNode = backendNode.getInputNode(i)
|
||||||
|
|
||||||
|
// Does this input autocreate a combo box on creation?
|
||||||
|
const isComfyInput = "config" in input
|
||||||
|
&& "widgetNodeType" in input
|
||||||
|
&& input.widgetNodeType === "ui/combo";
|
||||||
|
|
||||||
|
return isComfyComboNode(inputNode) && isComfyInput
|
||||||
|
});
|
||||||
|
|
||||||
|
if (inputIndex != null) {
|
||||||
|
const comboNode = backendNode.getInputNode(inputIndex) as nodes.ComfyComboNode
|
||||||
|
const inputSlot = backendNode.inputs[inputIndex] as IComfyInputSlot;
|
||||||
|
const def = defs[backendNode.type];
|
||||||
|
|
||||||
|
const hasBackendConfig = def["input"]["required"][inputSlot.name] !== undefined
|
||||||
|
console.log("hasBackendConfig", node.title, inputSlot.name, hasBackendConfig)
|
||||||
|
|
||||||
|
if (hasBackendConfig) {
|
||||||
|
backendCombos.add(comboNode.id)
|
||||||
|
toUpdate.push({ comboNode, inputSlot, backendNode })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let seen = new Set()
|
console.debug("[refreshComboInNodes] found:", toUpdate.length, toUpdate)
|
||||||
|
|
||||||
for (let nodeNum in this.lGraph._nodes) {
|
// Mark combo nodes without backend configs as being loaded already.
|
||||||
const node = this.lGraph._nodes[nodeNum];
|
for (const node of this.lGraph.iterateNodesInOrder()) {
|
||||||
|
if (isComfyComboNode(node) && !backendCombos.has(node.id)) {
|
||||||
|
const comboNode = node as nodes.ComfyComboNode;
|
||||||
|
comboNode.formatValues(comboNode.properties.values);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const def = defs[node.type];
|
await tick();
|
||||||
|
|
||||||
for (let index = 0; index < node.inputs.length; index++) {
|
// Load definitions from the backend.
|
||||||
const input = node.inputs[index];
|
for (const { comboNode, inputSlot, backendNode } of toUpdate) {
|
||||||
if ("config" in input) {
|
const def = defs[backendNode.type];
|
||||||
const comfyInput = input as IComfyInputSlot;
|
const rawValues = def["input"]["required"][inputSlot.name][0];
|
||||||
|
|
||||||
if (comfyInput.defaultWidgetNode == nodes.ComfyComboNode && def["input"]["required"][comfyInput.name] !== undefined) {
|
console.warn("[ComfyApp] Reconfiguring combo widget", backendNode.type, "=>", comboNode.type, inputSlot.config.values.length)
|
||||||
const rawValues = def["input"]["required"][comfyInput.name][0];
|
comboNode.doAutoConfig(inputSlot, { includeProperties: new Set(["values"]), setWidgetTitle: false })
|
||||||
|
|
||||||
comfyInput.config.values = rawValues;
|
comboNode.formatValues(rawValues)
|
||||||
const inputNode = node.getInputNode(index)
|
if (!inputSlot.config.values.includes(get(comboNode.value))) {
|
||||||
|
comboNode.setValue(inputSlot.config.defaultValue || inputSlot.config.values[0])
|
||||||
if (inputNode && "doAutoConfig" in inputNode && comfyInput.widgetNodeType === inputNode.type && !seen.has(inputNode.id)) {
|
|
||||||
seen.add(inputNode.id)
|
|
||||||
console.warn("[ComfyApp] Reconfiguring combo widget", inputNode.type, comfyInput.config.values.length)
|
|
||||||
const comfyComboNode = inputNode as nodes.ComfyComboNode;
|
|
||||||
comfyComboNode.doAutoConfig(comfyInput, { includeProperties: new Set(["values"]), setWidgetTitle: false })
|
|
||||||
|
|
||||||
comfyComboNode.formatValues(rawValues)
|
|
||||||
if (!comfyInput.config.values.includes(get(comfyComboNode.value))) {
|
|
||||||
comfyComboNode.setValue(comfyInput.config.defaultValue || comfyInput.config.values[0])
|
|
||||||
}
|
|
||||||
if (flashUI)
|
|
||||||
comfyComboNode.comboRefreshed.set(true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,6 +61,10 @@
|
|||||||
|
|
||||||
return tabName
|
return tabName
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleSelect() {
|
||||||
|
navigator.vibrate(20)
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if container && children}
|
{#if container && children}
|
||||||
@@ -113,7 +117,7 @@
|
|||||||
{/if}
|
{/if}
|
||||||
</Block>
|
</Block>
|
||||||
{:else}
|
{:else}
|
||||||
<Tabs elem_classes={["gradio-tabs"]}>
|
<Tabs elem_classes={["gradio-tabs"]} on:select={handleSelect}>
|
||||||
{#each children.filter(item => item.id !== SHADOW_PLACEHOLDER_ITEM_ID) as item, i(item.id)}
|
{#each children.filter(item => item.id !== SHADOW_PLACEHOLDER_ITEM_ID) as item, i(item.id)}
|
||||||
{@const tabName = getTabName(container, i)}
|
{@const tabName = getTabName(container, i)}
|
||||||
<TabItem name={tabName}>
|
<TabItem name={tabName}>
|
||||||
|
|||||||
44
src/lib/components/gradio/app/Accordion.svelte
Normal file
44
src/lib/components/gradio/app/Accordion.svelte
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { createEventDispatcher } from "svelte";
|
||||||
|
export let label: string = "";
|
||||||
|
export let open: boolean = true;
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher<{
|
||||||
|
click: boolean;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
function handleClick() {
|
||||||
|
open = !open;
|
||||||
|
dispatch("click", open);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div on:click={handleClick} class="label-wrap" class:open>
|
||||||
|
<span>{label}</span>
|
||||||
|
<span style:transform={open ? "rotate(0)" : "rotate(90deg)"} class="icon">
|
||||||
|
▼
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div style:display={open ? "block" : "none"}>
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
span {
|
||||||
|
font-weight: var(--section-header-text-weight);
|
||||||
|
font-size: var(--section-header-text-size);
|
||||||
|
}
|
||||||
|
.label-wrap {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
cursor: pointer;
|
||||||
|
width: var(--size-full);
|
||||||
|
}
|
||||||
|
.label-wrap.open {
|
||||||
|
margin-bottom: var(--size-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
transition: 150ms;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -273,9 +273,15 @@ export abstract class ComfyWidgetNode<T = any> extends ComfyGraphNode {
|
|||||||
console.debug("Property copy", input, this.properties)
|
console.debug("Property copy", input, this.properties)
|
||||||
|
|
||||||
this.setValue(get(this.value))
|
this.setValue(get(this.value))
|
||||||
|
|
||||||
|
this.onAutoConfig(input);
|
||||||
|
|
||||||
this.notifyPropsChanged();
|
this.notifyPropsChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onAutoConfig(input: IComfyInputSlot) {
|
||||||
|
}
|
||||||
|
|
||||||
notifyPropsChanged() {
|
notifyPropsChanged() {
|
||||||
const layoutEntry = layoutState.findLayoutEntryForNode(this.id)
|
const layoutEntry = layoutState.findLayoutEntryForNode(this.id)
|
||||||
if (layoutEntry && layoutEntry.parent) {
|
if (layoutEntry && layoutEntry.parent) {
|
||||||
@@ -430,18 +436,20 @@ export class ComfyComboNode extends ComfyWidgetNode<string> {
|
|||||||
override defaultValue = "A";
|
override defaultValue = "A";
|
||||||
override saveUserState = false;
|
override saveUserState = false;
|
||||||
|
|
||||||
comboRefreshed: Writable<boolean>;
|
// True if at least one combo box refresh has taken place
|
||||||
|
// Wait until the initial graph load for combo to be valid.
|
||||||
valuesForCombo: any[] | null = null;
|
firstLoad: Writable<boolean>;
|
||||||
|
valuesForCombo: Writable<any[] | null>; // Changed when the combo box has values.
|
||||||
|
|
||||||
constructor(name?: string) {
|
constructor(name?: string) {
|
||||||
super(name, "A")
|
super(name, "A")
|
||||||
this.comboRefreshed = writable(false)
|
this.firstLoad = writable(false)
|
||||||
|
this.valuesForCombo = writable(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
override onPropertyChanged(property: any, value: any) {
|
override onPropertyChanged(property: any, value: any) {
|
||||||
if (property === "values" || property === "convertValueToLabelCode") {
|
if (property === "values" || property === "convertValueToLabelCode") {
|
||||||
this.formatValues(this.properties.values)
|
// this.formatValues(this.properties.values)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -455,10 +463,12 @@ export class ComfyComboNode extends ComfyWidgetNode<string> {
|
|||||||
if (this.properties.convertValueToLabelCode)
|
if (this.properties.convertValueToLabelCode)
|
||||||
formatter = new Function("value", this.properties.convertValueToLabelCode) as (v: string) => string;
|
formatter = new Function("value", this.properties.convertValueToLabelCode) as (v: string) => string;
|
||||||
else
|
else
|
||||||
formatter = (value) => `${value}`;
|
formatter = (value: any) => `${value}`;
|
||||||
|
|
||||||
|
let valuesForCombo = []
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.valuesForCombo = this.properties.values.map((value, index) => {
|
valuesForCombo = this.properties.values.map((value, index) => {
|
||||||
return {
|
return {
|
||||||
value,
|
value,
|
||||||
label: formatter(value),
|
label: formatter(value),
|
||||||
@@ -468,7 +478,7 @@ export class ComfyComboNode extends ComfyWidgetNode<string> {
|
|||||||
}
|
}
|
||||||
catch (err) {
|
catch (err) {
|
||||||
console.error("Failed formatting!", err)
|
console.error("Failed formatting!", err)
|
||||||
this.valuesForCombo = this.properties.values.map((value, index) => {
|
valuesForCombo = this.properties.values.map((value, index) => {
|
||||||
return {
|
return {
|
||||||
value,
|
value,
|
||||||
label: `${value}`,
|
label: `${value}`,
|
||||||
@@ -477,7 +487,8 @@ export class ComfyComboNode extends ComfyWidgetNode<string> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
this.comboRefreshed.set(true);
|
this.firstLoad.set(true)
|
||||||
|
this.valuesForCombo.set(valuesForCombo);
|
||||||
}
|
}
|
||||||
|
|
||||||
onConnectOutput(
|
onConnectOutput(
|
||||||
|
|||||||
@@ -13,8 +13,8 @@
|
|||||||
let node: ComfyComboNode | null = null;
|
let node: ComfyComboNode | null = null;
|
||||||
let nodeValue: Writable<string> | null = null;
|
let nodeValue: Writable<string> | null = null;
|
||||||
let propsChanged: Writable<number> | null = null;
|
let propsChanged: Writable<number> | null = null;
|
||||||
let comboRefreshed: Writable<boolean> | null = null;
|
let valuesForCombo: Writable<any[]> | null = null;
|
||||||
let wasComboRefreshed: boolean = false;
|
let lastConfigured: any = null;
|
||||||
let option: any = null;
|
let option: any = null;
|
||||||
|
|
||||||
export let debug: boolean = false;
|
export let debug: boolean = false;
|
||||||
@@ -40,23 +40,26 @@
|
|||||||
node = widget.node as ComfyComboNode
|
node = widget.node as ComfyComboNode
|
||||||
nodeValue = node.value;
|
nodeValue = node.value;
|
||||||
propsChanged = node.propsChanged;
|
propsChanged = node.propsChanged;
|
||||||
comboRefreshed = node.comboRefreshed;
|
valuesForCombo = node.valuesForCombo;
|
||||||
if ($comboRefreshed)
|
|
||||||
flashOnRefreshed();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$: node.valuesForCombo && updateActiveIndex(node.valuesForCombo)
|
$: $valuesForCombo != null && updateActiveIndex($valuesForCombo)
|
||||||
|
|
||||||
function updateActiveIndex(values: any) {
|
function updateActiveIndex(values: any) {
|
||||||
const value = $nodeValue;
|
const value = $nodeValue;
|
||||||
activeIndex = values.findIndex(v => v.value === value);
|
activeIndex = values.findIndex(v => v.value === value);
|
||||||
}
|
}
|
||||||
|
|
||||||
$: $comboRefreshed && flashOnRefreshed();
|
$: $valuesForCombo != lastConfigured && flashOnRefreshed();
|
||||||
|
let lightUp = false;
|
||||||
|
|
||||||
function flashOnRefreshed() {
|
function flashOnRefreshed() {
|
||||||
setTimeout(() => ($comboRefreshed = false), 1000);
|
lastConfigured = $valuesForCombo
|
||||||
|
if (lastConfigured != null) {
|
||||||
|
lightUp = true;
|
||||||
|
setTimeout(() => (lightUp = false), 1000);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getLinkValue() {
|
function getLinkValue() {
|
||||||
@@ -69,7 +72,10 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function onFocus() {
|
function onFocus() {
|
||||||
navigator.vibrate(20)
|
// console.warn("FOCUS")
|
||||||
|
if (listOpen) {
|
||||||
|
navigator.vibrate(20)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function onSelect(e: CustomEvent<any>) {
|
function onSelect(e: CustomEvent<any>) {
|
||||||
@@ -79,7 +85,7 @@
|
|||||||
|
|
||||||
const item = e.detail
|
const item = e.detail
|
||||||
|
|
||||||
console.warn("SELECT", item, item.index)
|
console.debug("[ComboWidget] SELECT", item, item.index)
|
||||||
$nodeValue = item.value;
|
$nodeValue = item.value;
|
||||||
activeIndex = item.index;
|
activeIndex = item.index;
|
||||||
listOpen = false;
|
listOpen = false;
|
||||||
@@ -94,14 +100,14 @@
|
|||||||
let end = 0;
|
let end = 0;
|
||||||
|
|
||||||
function handleHover(index: number) {
|
function handleHover(index: number) {
|
||||||
console.warn("HOV", index)
|
// console.warn("HOV", index)
|
||||||
hoverItemIndex = index;
|
hoverItemIndex = index;
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleSelect(index: number) {
|
function handleSelect(index: number) {
|
||||||
console.warn("SEL", index)
|
// console.warn("SEL", index)
|
||||||
navigator.vibrate(20)
|
navigator.vibrate(20)
|
||||||
const item = node.valuesForCombo[index]
|
const item = $valuesForCombo[index]
|
||||||
activeIndex = index;
|
activeIndex = index;
|
||||||
$nodeValue = item.value
|
$nodeValue = item.value
|
||||||
listOpen = false;
|
listOpen = false;
|
||||||
@@ -130,13 +136,13 @@
|
|||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="wrapper comfy-combo" class:updated={$comboRefreshed}>
|
<div class="wrapper comfy-combo" class:updated={lightUp}>
|
||||||
{#key $comboRefreshed}
|
{#key $valuesForCombo}
|
||||||
{#if node !== null && nodeValue !== null}
|
{#if node !== null && nodeValue !== null}
|
||||||
{#if node.valuesForCombo == null}
|
{#if $valuesForCombo == null}
|
||||||
<span>Loading...</span>
|
<span>Loading...</span>
|
||||||
{:else}
|
{:else}
|
||||||
<span>Count {node.valuesForCombo.length}</span>
|
<span>Count {$valuesForCombo.length}</span>
|
||||||
<label>
|
<label>
|
||||||
{#if widget.attrs.title !== ""}
|
{#if widget.attrs.title !== ""}
|
||||||
<BlockTitle show_label={true}>{widget.attrs.title}</BlockTitle>
|
<BlockTitle show_label={true}>{widget.attrs.title}</BlockTitle>
|
||||||
@@ -148,7 +154,7 @@
|
|||||||
bind:filterText
|
bind:filterText
|
||||||
bind:listOpen
|
bind:listOpen
|
||||||
bind:input
|
bind:input
|
||||||
items={node.valuesForCombo}
|
items={$valuesForCombo}
|
||||||
disabled={isDisabled(widget)}
|
disabled={isDisabled(widget)}
|
||||||
clearable={false}
|
clearable={false}
|
||||||
showChevron={true}
|
showChevron={true}
|
||||||
@@ -160,7 +166,7 @@
|
|||||||
on:select={(e) => handleSelect(e.detail.index)}
|
on:select={(e) => handleSelect(e.detail.index)}
|
||||||
on:blur
|
on:blur
|
||||||
on:filter={onFilter}>
|
on:filter={onFilter}>
|
||||||
<div class="list" slot="list" let:filteredItems>
|
<div class="comfy-select-list" slot="list" let:filteredItems>
|
||||||
{#if filteredItems.length > 0}
|
{#if filteredItems.length > 0}
|
||||||
<VirtualList
|
<VirtualList
|
||||||
items={filteredItems}
|
items={filteredItems}
|
||||||
@@ -170,20 +176,25 @@
|
|||||||
itemSize={50}
|
itemSize={50}
|
||||||
scrollToIndex={hoverItemIndex}>
|
scrollToIndex={hoverItemIndex}>
|
||||||
<div slot="item"
|
<div slot="item"
|
||||||
|
class="comfy-select-item"
|
||||||
let:index={i}
|
let:index={i}
|
||||||
let:style
|
let:style
|
||||||
{style}
|
{style}
|
||||||
class="item"
|
|
||||||
class:active={activeIndex === filteredItems[i].index}
|
class:active={activeIndex === filteredItems[i].index}
|
||||||
class:hover={hoverItemIndex === i}
|
class:hover={hoverItemIndex === i}
|
||||||
on:click={() => handleSelect(filteredItems[i].index)}
|
on:click={() => handleSelect(filteredItems[i].index)}
|
||||||
on:focus={() => handleHover(i)}
|
on:focus={() => handleHover(i)}
|
||||||
on:mouseover={() => handleHover(i)}>
|
on:mouseover={() => handleHover(i)}>
|
||||||
{@const item = filteredItems[i]}
|
{@const item = filteredItems[i]}
|
||||||
{item.label}
|
<span class="comfy-select-label">
|
||||||
|
{item.label}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</VirtualList>
|
</VirtualList>
|
||||||
<p class="details">active: {activeIndex}, hover: {hoverItemIndex}<p>
|
{:else}
|
||||||
|
<div class="comfy-empty-list">
|
||||||
|
<span>(No items)</span>
|
||||||
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</Select>
|
</Select>
|
||||||
@@ -240,12 +251,21 @@
|
|||||||
height: 100%
|
height: 100%
|
||||||
}
|
}
|
||||||
|
|
||||||
.list {
|
.comfy-select-list {
|
||||||
height: 30rem;
|
height: 300px;
|
||||||
width: 30rem;
|
width: 30rem;
|
||||||
background-color: white;
|
background-color: white;
|
||||||
|
|
||||||
.item {
|
.comfy-empty-list {
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
font-size: xx-large;
|
||||||
|
color: var(--neutral-700)
|
||||||
|
}
|
||||||
|
|
||||||
|
.comfy-select-item {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
padding: 1.2rem;
|
padding: 1.2rem;
|
||||||
border: 1px solid var(--neutral-300);
|
border: 1px solid var(--neutral-300);
|
||||||
@@ -253,6 +273,9 @@
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
&.hover {
|
&.hover {
|
||||||
color: white;
|
color: white;
|
||||||
background: var(--neutral-400);
|
background: var(--neutral-400);
|
||||||
@@ -262,6 +285,10 @@
|
|||||||
color: white;
|
color: white;
|
||||||
background: var(--color-blue-500);
|
background: var(--color-blue-500);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.comfy-select-label {
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.details {
|
.details {
|
||||||
|
|||||||
Reference in New Issue
Block a user