var __defProp = Object.defineProperty;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
import { c as cn, _ as _sfc_main$a, f as useToastStore, t, L as useQueueStore, a as api, W as useAssetsStore, cB as isComboInputSpec } from "./index-BqxAUePh.js";
import { E as computed, bq as defineComponent, cF as mergeModels, cG as useModel, j as createBlock, d as openBlock, k as withCtx, z as createVNode, e as createBaseVNode, br as unref, m as mergeProps, p as renderSlot, c as createElementBlock, s as normalizeClass, q as createCommentVNode, u as toDisplayString, dt as useTemplateRef, r as ref, l as withDirectives, d9 as vModelText, F as Fragment, y as renderList, i as inject, h as resolveDirective, A as createTextVNode, dh as refDebounced, w as watch, bu as provide, ex as capitalize, be as toRef } from "./vendor-other-DdEHkzYa.js";
import { i as script, p as script$1 } from "./vendor-primevue-DmDWdkDd.js";
import "./vendor-xterm-BF8peZ5_.js";
import { f as filterWidgetProps, P as PANEL_EXCLUDED_PROPS } from "./widgetPropFilter-BIbGSUAt.js";
import { W as WidgetInputBaseClass } from "./index-Csoifk32.js";
import { _ as _sfc_main$9 } from "./WidgetLayoutField.vue_vue_type_script_setup_true_lang-BZ0_zQzJ.js";
import { a as useModelUpload, c as _sfc_main$b } from "./LazyImage.vue_vue_type_script_setup_true_lang-q3mcFzhk.js";
import { _ as _sfc_main$c } from "./WidgetWithControl.vue_vue_type_script_setup_true_lang-Dugrx1Hx.js";
function useTransformCompatOverlayProps(overrides = {}) {
  return computed(() => ({
    appendTo: "self",
    ...overrides
  }));
}
__name(useTransformCompatOverlayProps, "useTransformCompatOverlayProps");
const _hoisted_1$5 = { class: "absolute top-5 right-8 h-4 w-7 -translate-y-4/5 flex" };
const _sfc_main$8 = /* @__PURE__ */ defineComponent({
  __name: "WidgetSelectDefault",
  props: /* @__PURE__ */ mergeModels({
    widget: {}
  }, {
    "modelValue": {
      default(props) {
        return props.widget.options?.values?.[0] || "";
      }
    },
    "modelModifiers": {}
  }),
  emits: ["update:modelValue"],
  setup(__props) {
    const props = __props;
    const modelValue = useModel(__props, "modelValue");
    const transformCompatProps = useTransformCompatOverlayProps();
    const selectOptions = computed(() => {
      const options = props.widget.options;
      if (options?.values && Array.isArray(options.values)) {
        return options.values;
      }
      return [];
    });
    const invalid = computed(
      () => !!modelValue.value && !selectOptions.value.includes(modelValue.value)
    );
    const combinedProps = computed(() => ({
      ...filterWidgetProps(props.widget.options, PANEL_EXCLUDED_PROPS),
      ...transformCompatProps.value,
      ...invalid.value ? { placeholder: `${modelValue.value}` } : {}
    }));
    return (_ctx, _cache) => {
      return openBlock(), createBlock(_sfc_main$9, { widget: _ctx.widget }, {
        default: withCtx(() => [
          createVNode(unref(script), mergeProps({
            modelValue: modelValue.value,
            "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => modelValue.value = $event),
            invalid: invalid.value,
            filter: selectOptions.value.length > 4,
            "auto-filter-focus": selectOptions.value.length > 4,
            options: selectOptions.value
          }, combinedProps.value, {
            class: unref(cn)(unref(WidgetInputBaseClass), "w-full text-xs"),
            "aria-label": _ctx.widget.name,
            size: "small",
            pt: {
              option: "text-xs",
              dropdown: "w-8",
              label: unref(cn)("truncate min-w-[4ch]", _ctx.$slots.default && "mr-5"),
              overlay: "w-fit min-w-full"
            },
            "data-capture-wheel": "true"
          }), null, 16, ["modelValue", "invalid", "filter", "auto-filter-focus", "options", "class", "aria-label", "pt"]),
          createBaseVNode("div", _hoisted_1$5, [
            renderSlot(_ctx.$slots, "default")
          ])
        ]),
        _: 3
      }, 8, ["widget"]);
    };
  }
});
const _hoisted_1$4 = { class: "min-w-0 flex-1 px-1 py-2 text-left truncate" };
const _hoisted_2$4 = { key: 0 };
const _hoisted_3$3 = { key: 1 };
const _hoisted_4$3 = ["multiple", "disabled", "accept"];
const _sfc_main$7 = /* @__PURE__ */ defineComponent({
  __name: "FormDropdownInput",
  props: {
    isOpen: { type: Boolean, default: false },
    placeholder: { default: "Select..." },
    items: {},
    selected: {},
    maxSelectable: {},
    uploadable: { type: Boolean },
    disabled: { type: Boolean },
    accept: {}
  },
  emits: ["select-click", "file-change"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const selectedItems = computed(() => {
      return props.items.filter((item) => props.selected.has(item.id));
    });
    const theButtonStyle = computed(
      () => cn(
        "border-0 bg-component-node-widget-background outline-none text-text-secondary",
        props.disabled ? "cursor-not-allowed" : "hover:bg-component-node-widget-background-hovered cursor-pointer",
        selectedItems.value.length > 0 && "text-text-primary"
      )
    );
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", {
        class: normalizeClass(
          unref(cn)(unref(WidgetInputBaseClass), "flex text-base leading-none", {
            "opacity-50 cursor-not-allowed !outline-zinc-300/10": _ctx.disabled
          })
        )
      }, [
        createBaseVNode("button", {
          class: normalizeClass(
            unref(cn)(
              theButtonStyle.value,
              "flex justify-between items-center flex-1 min-w-0 h-8",
              {
                "rounded-l-lg": _ctx.uploadable,
                "rounded-lg": !_ctx.uploadable
              }
            )
          ),
          onClick: _cache[0] || (_cache[0] = ($event) => emit("select-click", $event))
        }, [
          createBaseVNode("span", _hoisted_1$4, [
            !selectedItems.value.length ? (openBlock(), createElementBlock("span", _hoisted_2$4, toDisplayString(_ctx.placeholder), 1)) : (openBlock(), createElementBlock("span", _hoisted_3$3, toDisplayString(selectedItems.value.map((item) => item.label ?? item.name).join(", ")), 1))
          ]),
          createBaseVNode("i", {
            class: normalizeClass([
              "icon-[lucide--chevron-down]",
              unref(cn)(
                "mr-2 size-4 transition-transform duration-200 flex-shrink-0 text-component-node-foreground-secondary",
                _ctx.isOpen && "rotate-180"
              )
            ])
          }, null, 2)
        ], 2),
        _ctx.uploadable ? (openBlock(), createElementBlock("label", {
          key: 0,
          class: normalizeClass(
            unref(cn)(
              theButtonStyle.value,
              "relative",
              "size-8 flex justify-center items-center border-l rounded-r-lg border-zinc-300/10"
            )
          )
        }, [
          _cache[2] || (_cache[2] = createBaseVNode("i", { class: "icon-[lucide--folder-search] size-4" }, null, -1)),
          createBaseVNode("input", {
            type: "file",
            class: "absolute inset-0 -z-1 opacity-0",
            multiple: _ctx.maxSelectable > 1,
            disabled: _ctx.disabled,
            accept: _ctx.accept,
            onChange: _cache[1] || (_cache[1] = ($event) => emit("file-change", $event))
          }, null, 40, _hoisted_4$3)
        ], 2)) : createCommentVNode("", true)
      ], 2);
    };
  }
});
const _hoisted_1$3 = { class: "text-secondary flex gap-2 px-4" };
const _hoisted_2$3 = {
  key: 0,
  class: "mr-2 icon-[lucide--loader-circle] size-4 animate-spin"
};
const _hoisted_3$2 = {
  key: 1,
  class: "mr-2 icon-[lucide--search] size-4"
};
const _hoisted_4$2 = ["placeholder"];
const _hoisted_5 = {
  key: 0,
  class: "absolute top-[-2px] left-[-2px] size-2 rounded-full bg-component-node-widget-background-highlighted"
};
const _hoisted_6 = ["onClick"];
const _hoisted_7 = {
  key: 0,
  class: "icon-[lucide--check] size-4"
};
const resetInputStyle = "bg-transparent border-0 outline-0 ring-0 text-left";
const layoutSwitchItemStyle = "size-6 flex justify-center items-center rounded-sm cursor-pointer transition-all duration-150 hover:scale-108 hover:text-base-foreground active:scale-95";
const _sfc_main$6 = /* @__PURE__ */ defineComponent({
  __name: "FormDropdownMenuActions",
  props: /* @__PURE__ */ mergeModels({
    isQuerying: { type: Boolean },
    sortOptions: {}
  }, {
    "layoutMode": {},
    "layoutModeModifiers": {},
    "searchQuery": {},
    "searchQueryModifiers": {},
    "sortSelected": {},
    "sortSelectedModifiers": {}
  }),
  emits: ["update:layoutMode", "update:searchQuery", "update:sortSelected"],
  setup(__props) {
    const layoutMode = useModel(__props, "layoutMode");
    const searchQuery = useModel(__props, "searchQuery");
    const sortSelected = useModel(__props, "sortSelected");
    const actionButtonStyle = cn(
      "h-8 bg-zinc-500/20 rounded-lg outline outline-1 outline-offset-[-1px] outline-node-component-border transition-all duration-150"
    );
    const sortPopoverRef = useTemplateRef("sortPopoverRef");
    const sortTriggerRef = useTemplateRef("sortTriggerRef");
    const isSortPopoverOpen = ref(false);
    function toggleSortPopover(event) {
      if (!sortPopoverRef.value || !sortTriggerRef.value) return;
      isSortPopoverOpen.value = !isSortPopoverOpen.value;
      sortPopoverRef.value.toggle(event, sortTriggerRef.value);
    }
    __name(toggleSortPopover, "toggleSortPopover");
    function closeSortPopover() {
      isSortPopoverOpen.value = false;
      sortPopoverRef.value?.hide();
    }
    __name(closeSortPopover, "closeSortPopover");
    function handleSortSelected(item) {
      sortSelected.value = item.id;
      closeSortPopover();
    }
    __name(handleSortSelected, "handleSortSelected");
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$3, [
        createBaseVNode("label", {
          class: normalizeClass(
            unref(cn)(
              unref(actionButtonStyle),
              "flex-1 flex px-2 items-center text-base leading-none cursor-text",
              searchQuery.value?.trim() !== "" ? "text-base-foreground" : "",
              "hover:outline-component-node-widget-background-highlighted/80",
              "focus-within:outline-component-node-widget-background-highlighted/80"
            )
          )
        }, [
          _ctx.isQuerying ? (openBlock(), createElementBlock("i", _hoisted_2$3)) : (openBlock(), createElementBlock("i", _hoisted_3$2)),
          withDirectives(createBaseVNode("input", {
            "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => searchQuery.value = $event),
            type: "text",
            autofocus: "",
            class: normalizeClass(resetInputStyle),
            placeholder: _ctx.$t("g.search")
          }, null, 8, _hoisted_4$2), [
            [vModelText, searchQuery.value]
          ])
        ], 2),
        createBaseVNode("button", {
          ref_key: "sortTriggerRef",
          ref: sortTriggerRef,
          class: normalizeClass(
            unref(cn)(
              resetInputStyle,
              unref(actionButtonStyle),
              "relative w-8 flex justify-center items-center cursor-pointer",
              "hover:outline-component-node-widget-background-highlighted",
              "active:!scale-95"
            )
          ),
          onClick: toggleSortPopover
        }, [
          sortSelected.value !== "default" ? (openBlock(), createElementBlock("div", _hoisted_5)) : createCommentVNode("", true),
          _cache[4] || (_cache[4] = createBaseVNode("i", { class: "icon-[lucide--arrow-up-down] size-4" }, null, -1))
        ], 2),
        createVNode(unref(script$1), {
          ref_key: "sortPopoverRef",
          ref: sortPopoverRef,
          dismissable: true,
          "close-on-escape": true,
          unstyled: "",
          pt: {
            root: {
              class: "absolute z-50"
            },
            content: {
              class: ["bg-transparent border-none p-0 pt-2 rounded-lg shadow-lg"]
            }
          },
          onHide: _cache[1] || (_cache[1] = ($event) => isSortPopoverOpen.value = false)
        }, {
          default: withCtx(() => [
            createBaseVNode("div", {
              class: normalizeClass(
                unref(cn)(
                  "flex flex-col gap-2 p-2 min-w-32",
                  "bg-component-node-background",
                  "rounded-lg outline outline-offset-[-1px] outline-component-node-border"
                )
              )
            }, [
              (openBlock(true), createElementBlock(Fragment, null, renderList(_ctx.sortOptions, (item) => {
                return openBlock(), createElementBlock("button", {
                  key: item.name,
                  class: normalizeClass(
                    unref(cn)(
                      resetInputStyle,
                      "flex justify-between items-center h-6 cursor-pointer",
                      "hover:!text-blue-500"
                    )
                  ),
                  onClick: /* @__PURE__ */ __name(($event) => handleSortSelected(item), "onClick")
                }, [
                  createBaseVNode("span", null, toDisplayString(item.name), 1),
                  sortSelected.value === item.id ? (openBlock(), createElementBlock("i", _hoisted_7)) : createCommentVNode("", true)
                ], 10, _hoisted_6);
              }), 128))
            ], 2)
          ]),
          _: 1
        }, 512),
        createBaseVNode("div", {
          class: normalizeClass(
            unref(cn)(
              unref(actionButtonStyle),
              "flex justify-center items-center p-1 gap-1 hover:outline-component-node-widget-background-highlighted"
            )
          )
        }, [
          createBaseVNode("button", {
            class: normalizeClass(
              unref(cn)(
                resetInputStyle,
                layoutSwitchItemStyle,
                layoutMode.value === "list" ? "bg-neutral-500/50 text-base-foreground" : ""
              )
            ),
            onClick: _cache[2] || (_cache[2] = ($event) => layoutMode.value = "list")
          }, _cache[5] || (_cache[5] = [
            createBaseVNode("i", { class: "icon-[lucide--list] size-4" }, null, -1)
          ]), 2),
          createBaseVNode("button", {
            class: normalizeClass(
              unref(cn)(
                resetInputStyle,
                layoutSwitchItemStyle,
                layoutMode.value === "grid" ? "bg-neutral-500/50 text-base-foreground" : ""
              )
            ),
            onClick: _cache[3] || (_cache[3] = ($event) => layoutMode.value = "grid")
          }, _cache[6] || (_cache[6] = [
            createBaseVNode("i", { class: "icon-[lucide--layout-grid] size-4" }, null, -1)
          ]), 2)
        ], 2)
      ]);
    };
  }
});
const _hoisted_1$2 = { class: "text-secondary mb-4 flex gap-1 px-4 justify-start" };
const _hoisted_2$2 = ["disabled", "onClick"];
const _sfc_main$5 = /* @__PURE__ */ defineComponent({
  __name: "FormDropdownMenuFilter",
  props: /* @__PURE__ */ mergeModels({
    filterOptions: {}
  }, {
    "filterSelected": {},
    "filterSelectedModifiers": {}
  }),
  emits: ["update:filterSelected"],
  setup(__props) {
    const filterSelected = useModel(__props, "filterSelected");
    const { isUploadButtonEnabled, showUploadDialog } = useModelUpload();
    const singleFilterOption = computed(() => __props.filterOptions.length === 1);
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$2, [
        (openBlock(true), createElementBlock(Fragment, null, renderList(_ctx.filterOptions, (option) => {
          return openBlock(), createElementBlock("button", {
            key: option.id,
            type: "button",
            disabled: singleFilterOption.value,
            class: normalizeClass(
              unref(cn)(
                "px-4 py-2 rounded-md inline-flex justify-center items-center select-none appearance-none border-0 text-base-foreground",
                !singleFilterOption.value && "transition-all duration-150 hover:text-base-foreground hover:bg-interface-menu-component-surface-hovered cursor-pointer active:scale-95",
                !singleFilterOption.value && filterSelected.value === option.id ? "!bg-interface-menu-component-surface-selected text-base-foreground" : "bg-transparent"
              )
            ),
            onClick: /* @__PURE__ */ __name(($event) => filterSelected.value = option.id, "onClick")
          }, toDisplayString(option.name), 11, _hoisted_2$2);
        }), 128)),
        unref(isUploadButtonEnabled) && singleFilterOption.value ? (openBlock(), createBlock(_sfc_main$a, {
          key: 0,
          class: "ml-auto",
          size: "md",
          variant: "textonly",
          onClick: unref(showUploadDialog)
        }, {
          default: withCtx(() => [
            _cache[0] || (_cache[0] = createBaseVNode("i", { class: "icon-[lucide--folder-input]" }, null, -1)),
            createBaseVNode("span", null, toDisplayString(_ctx.$t("g.import")), 1)
          ]),
          _: 1
        }, 8, ["onClick"])) : createCommentVNode("", true)
      ]);
    };
  }
});
const AssetKindKey = /* @__PURE__ */ Symbol("assetKind");
const _hoisted_1$1 = {
  key: 0,
  class: "absolute top-1 left-1 size-4 rounded-full border-1 border-base-foreground bg-primary-background"
};
const _hoisted_2$1 = ["src"];
const _hoisted_3$1 = {
  key: 3,
  class: "size-full bg-gradient-to-tr from-blue-400 via-teal-500 to-green-400"
};
const _hoisted_4$1 = { class: "text-secondary block text-xs" };
const _sfc_main$4 = /* @__PURE__ */ defineComponent({
  __name: "FormDropdownMenuItem",
  props: {
    index: {},
    selected: { type: Boolean },
    mediaSrc: {},
    name: {},
    label: {},
    metadata: {},
    layout: {}
  },
  emits: ["click", "mediaLoad"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const actualDimensions = ref(null);
    const assetKind = inject(AssetKindKey);
    const isVideo = computed(() => assetKind?.value === "video");
    function handleClick() {
      emit("click", props.index);
    }
    __name(handleClick, "handleClick");
    function handleImageLoad(event) {
      emit("mediaLoad", event);
      if (!event.target || !(event.target instanceof HTMLImageElement)) return;
      const img = event.target;
      if (img.naturalWidth && img.naturalHeight) {
        actualDimensions.value = `${img.naturalWidth} x ${img.naturalHeight}`;
      }
    }
    __name(handleImageLoad, "handleImageLoad");
    function handleVideoLoad(event) {
      emit("mediaLoad", event);
      if (!event.target || !(event.target instanceof HTMLVideoElement)) return;
      const video = event.target;
      if (video.videoWidth && video.videoHeight) {
        actualDimensions.value = `${video.videoWidth} x ${video.videoHeight}`;
      }
    }
    __name(handleVideoLoad, "handleVideoLoad");
    return (_ctx, _cache) => {
      const _directive_tooltip = resolveDirective("tooltip");
      return openBlock(), createElementBlock("div", {
        class: normalizeClass(
          unref(cn)(
            "flex gap-1 select-none group/item cursor-pointer bg-component-node-widget-background",
            "transition-all duration-150",
            {
              "flex-col text-center": _ctx.layout === "grid",
              "flex-row text-left max-h-16 rounded-lg hover:scale-102 active:scale-98": _ctx.layout === "list",
              "flex-row text-left hover:bg-component-node-widget-background-hovered rounded-lg": _ctx.layout === "list-small",
              // selection
              "ring-2 ring-component-node-widget-background-highlighted": _ctx.layout === "list" && _ctx.selected
            }
          )
        ),
        onClick: handleClick
      }, [
        _ctx.layout !== "list-small" ? (openBlock(), createElementBlock("div", {
          key: 0,
          class: normalizeClass(
            unref(cn)(
              "relative",
              "w-full aspect-square overflow-hidden outline-1 outline-offset-[-1px] outline-interface-stroke",
              "transition-all duration-150",
              {
                "min-w-16 max-w-16 rounded-l-lg": _ctx.layout === "list",
                "rounded-sm group-hover/item:scale-108 group-active/item:scale-95": _ctx.layout === "grid",
                // selection
                "ring-2 ring-component-node-widget-background-highlighted": _ctx.layout === "grid" && _ctx.selected
              }
            )
          )
        }, [
          _ctx.selected ? (openBlock(), createElementBlock("div", _hoisted_1$1, _cache[0] || (_cache[0] = [
            createBaseVNode("i", { class: "icon-[lucide--check] size-3 translate-y-[-0.5px] text-base-foreground bold" }, null, -1)
          ]))) : createCommentVNode("", true),
          _ctx.mediaSrc && isVideo.value ? (openBlock(), createElementBlock("video", {
            key: 1,
            src: _ctx.mediaSrc,
            class: "size-full object-cover",
            preload: "metadata",
            muted: "",
            onLoadeddata: handleVideoLoad
          }, null, 40, _hoisted_2$1)) : _ctx.mediaSrc ? (openBlock(), createBlock(_sfc_main$b, {
            key: 2,
            src: _ctx.mediaSrc,
            alt: _ctx.name,
            "image-class": "size-full object-cover",
            onLoad: handleImageLoad
          }, null, 8, ["src", "alt"])) : (openBlock(), createElementBlock("div", _hoisted_3$1))
        ], 2)) : createCommentVNode("", true),
        createBaseVNode("div", {
          class: normalizeClass(
            unref(cn)("flex gap-1", {
              "flex-col": _ctx.layout === "grid",
              "flex-col px-4 py-1 w-full justify-center min-w-0": _ctx.layout === "list",
              "flex-row p-2 items-center justify-between w-full": _ctx.layout === "list-small"
            })
          )
        }, [
          withDirectives((openBlock(), createElementBlock("span", {
            class: normalizeClass(
              unref(cn)(
                "block text-xs line-clamp-2 break-words overflow-hidden",
                "transition-colors duration-150",
                // selection
                !!_ctx.selected && "text-base-foreground"
              )
            )
          }, [
            createTextVNode(toDisplayString(_ctx.label ?? _ctx.name), 1)
          ], 2)), [
            [_directive_tooltip, _ctx.layout === "grid" ? _ctx.label ?? _ctx.name : void 0]
          ]),
          createBaseVNode("span", _hoisted_4$1, toDisplayString(_ctx.metadata || actualDimensions.value), 1)
        ], 2)
      ], 2);
    };
  }
});
const _hoisted_1 = { class: "flex max-h-[640px] w-103 flex-col rounded-lg bg-component-node-background pt-4 outline outline-offset-[-1px] outline-node-component-border" };
const _hoisted_2 = { class: "relative flex h-full mt-2 overflow-y-scroll" };
const _hoisted_3 = {
  key: 0,
  class: "h-50 col-span-full flex items-center justify-center"
};
const _hoisted_4 = ["title", "aria-label"];
const _sfc_main$3 = /* @__PURE__ */ defineComponent({
  __name: "FormDropdownMenu",
  props: /* @__PURE__ */ mergeModels({
    items: {},
    isSelected: { type: Function },
    isQuerying: { type: Boolean },
    filterOptions: {},
    sortOptions: {}
  }, {
    "filterSelected": {},
    "filterSelectedModifiers": {},
    "layoutMode": {},
    "layoutModeModifiers": {},
    "sortSelected": {},
    "sortSelectedModifiers": {},
    "searchQuery": {},
    "searchQueryModifiers": {}
  }),
  emits: /* @__PURE__ */ mergeModels(["item-click"], ["update:filterSelected", "update:layoutMode", "update:sortSelected", "update:searchQuery"]),
  setup(__props, { emit: __emit }) {
    const emit = __emit;
    const filterSelected = useModel(__props, "filterSelected");
    const layoutMode = useModel(__props, "layoutMode");
    const sortSelected = useModel(__props, "sortSelected");
    const searchQuery = useModel(__props, "searchQuery");
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1, [
        _ctx.filterOptions.length > 0 ? (openBlock(), createBlock(_sfc_main$5, {
          key: 0,
          "filter-selected": filterSelected.value,
          "onUpdate:filterSelected": _cache[0] || (_cache[0] = ($event) => filterSelected.value = $event),
          "filter-options": _ctx.filterOptions
        }, null, 8, ["filter-selected", "filter-options"])) : createCommentVNode("", true),
        createVNode(_sfc_main$6, {
          "layout-mode": layoutMode.value,
          "onUpdate:layoutMode": _cache[1] || (_cache[1] = ($event) => layoutMode.value = $event),
          "sort-selected": sortSelected.value,
          "onUpdate:sortSelected": _cache[2] || (_cache[2] = ($event) => sortSelected.value = $event),
          "search-query": searchQuery.value,
          "onUpdate:searchQuery": _cache[3] || (_cache[3] = ($event) => searchQuery.value = $event),
          "sort-options": _ctx.sortOptions,
          "is-querying": _ctx.isQuerying
        }, null, 8, ["layout-mode", "sort-selected", "search-query", "sort-options", "is-querying"]),
        createBaseVNode("div", _hoisted_2, [
          createBaseVNode("div", {
            class: normalizeClass(
              unref(cn)(
                "h-full max-h-full grid gap-x-2 gap-y-4 overflow-y-auto px-4 pt-4 pb-4 w-full",
                {
                  "grid-cols-4": layoutMode.value === "grid",
                  "grid-cols-1 gap-y-2": layoutMode.value === "list",
                  "grid-cols-1 gap-y-1": layoutMode.value === "list-small"
                }
              )
            )
          }, [
            _cache[4] || (_cache[4] = createBaseVNode("div", { class: "pointer-events-none absolute inset-x-3 top-0 z-10 h-5" }, null, -1)),
            _ctx.items.length === 0 ? (openBlock(), createElementBlock("div", _hoisted_3, [
              createBaseVNode("i", {
                title: _ctx.$t("g.noItems"),
                "aria-label": _ctx.$t("g.noItems"),
                class: "icon-[lucide--circle-off] size-30 text-zinc-500/20"
              }, null, 8, _hoisted_4)
            ])) : createCommentVNode("", true),
            (openBlock(true), createElementBlock(Fragment, null, renderList(_ctx.items, (item, index) => {
              return openBlock(), createBlock(_sfc_main$4, {
                key: item.id,
                index,
                selected: _ctx.isSelected(item, index),
                "media-src": item.mediaSrc,
                name: item.name,
                label: item.label,
                metadata: item.metadata,
                layout: layoutMode.value,
                onClick: /* @__PURE__ */ __name(($event) => emit("item-click", item, index), "onClick")
              }, null, 8, ["index", "selected", "media-src", "name", "label", "metadata", "layout", "onClick"]);
            }), 128))
          ], 2)
        ])
      ]);
    };
  }
});
async function defaultSearcher(query, items) {
  if (query.trim() === "") return items;
  const words = query.trim().toLowerCase().split(" ");
  return items.filter((item) => {
    const name = item.name.toLowerCase();
    return words.every((word) => name.includes(word));
  });
}
__name(defaultSearcher, "defaultSearcher");
function getDefaultSortOptions() {
  return [
    {
      name: "Default",
      id: "default",
      sorter: /* @__PURE__ */ __name(({ items }) => items.slice(), "sorter")
    },
    {
      name: "A-Z",
      id: "a-z",
      sorter: /* @__PURE__ */ __name(({ items }) => items.slice().sort((a, b) => {
        return a.name.localeCompare(b.name);
      }), "sorter")
    }
  ];
}
__name(getDefaultSortOptions, "getDefaultSortOptions");
const _sfc_main$2 = /* @__PURE__ */ defineComponent({
  __name: "FormDropdown",
  props: /* @__PURE__ */ mergeModels({
    items: {},
    placeholder: { default: t("widgets.uploadSelect.placeholder") },
    multiple: { type: [Boolean, Number], default: false },
    uploadable: { type: Boolean, default: false },
    disabled: { type: Boolean, default: false },
    accept: {},
    filterOptions: { default: /* @__PURE__ */ __name(() => [], "default") },
    sortOptions: { default: /* @__PURE__ */ __name(() => getDefaultSortOptions(), "default") },
    isSelected: { type: Function, default: /* @__PURE__ */ __name((selected, item, _index) => selected.has(item.id), "default") },
    searcher: { type: Function, default: defaultSearcher }
  }, {
    "selected": {
      default: /* @__PURE__ */ new Set()
    },
    "selectedModifiers": {},
    "filterSelected": { default: "" },
    "filterSelectedModifiers": {},
    "sortSelected": {
      default: "default"
    },
    "sortSelectedModifiers": {},
    "layoutMode": {
      default: "grid"
    },
    "layoutModeModifiers": {},
    "files": { default: [] },
    "filesModifiers": {},
    "searchQuery": { default: "" },
    "searchQueryModifiers": {}
  }),
  emits: ["update:selected", "update:filterSelected", "update:sortSelected", "update:layoutMode", "update:files", "update:searchQuery"],
  setup(__props) {
    const props = __props;
    const selected = useModel(__props, "selected");
    const filterSelected = useModel(__props, "filterSelected");
    const sortSelected = useModel(__props, "sortSelected");
    const layoutMode = useModel(__props, "layoutMode");
    const files = useModel(__props, "files");
    const searchQuery = useModel(__props, "searchQuery");
    const debouncedSearchQuery = refDebounced(searchQuery, 700, {
      maxWait: 700
    });
    const isQuerying = ref(false);
    const toastStore = useToastStore();
    const popoverRef = ref();
    const triggerRef = useTemplateRef("triggerRef");
    const isOpen = ref(false);
    const maxSelectable = computed(() => {
      if (props.multiple === true) return Infinity;
      if (typeof props.multiple === "number") return props.multiple;
      return 1;
    });
    const filteredItems = ref([]);
    watch(searchQuery, (value) => {
      isQuerying.value = value !== debouncedSearchQuery.value;
    });
    watch(
      [debouncedSearchQuery, () => props.items],
      (_, __, onCleanup) => {
        let isCleanup = false;
        let cleanupFn;
        onCleanup(() => {
          isCleanup = true;
          cleanupFn?.();
        });
        void props.searcher(
          debouncedSearchQuery.value,
          props.items,
          (cb) => cleanupFn = cb
        ).then((result) => {
          if (!isCleanup) filteredItems.value = result;
        }).finally(() => {
          if (!isCleanup) isQuerying.value = false;
        });
      },
      { immediate: true }
    );
    const defaultSorter = computed(() => {
      const sorter = props.sortOptions.find(
        (option) => option.id === "default"
      )?.sorter;
      return sorter || (({ items }) => items.slice());
    });
    const selectedSorter = computed(() => {
      if (sortSelected.value === "default") return defaultSorter.value;
      const sorter = props.sortOptions.find(
        (option) => option.id === sortSelected.value
      )?.sorter;
      return sorter || defaultSorter.value;
    });
    const sortedItems = computed(() => {
      return selectedSorter.value({ items: filteredItems.value }) || [];
    });
    function internalIsSelected(item, index) {
      return props.isSelected?.(selected.value, item, index) ?? false;
    }
    __name(internalIsSelected, "internalIsSelected");
    const toggleDropdown = /* @__PURE__ */ __name((event) => {
      if (props.disabled) return;
      if (popoverRef.value && triggerRef.value) {
        popoverRef.value.toggle(event, triggerRef.value);
        isOpen.value = !isOpen.value;
      }
    }, "toggleDropdown");
    const closeDropdown = /* @__PURE__ */ __name(() => {
      if (popoverRef.value) {
        popoverRef.value.hide();
        isOpen.value = false;
      }
    }, "closeDropdown");
    function handleFileChange(event) {
      if (props.disabled) return;
      const input = event.target;
      if (input.files) {
        files.value = Array.from(input.files);
      }
      input.value = "";
    }
    __name(handleFileChange, "handleFileChange");
    function handleSelection(item, index) {
      if (props.disabled) return;
      const sel = selected.value;
      if (internalIsSelected(item, index)) {
        sel.delete(item.id);
      } else {
        if (sel.size < maxSelectable.value) {
          sel.add(item.id);
        } else if (maxSelectable.value === 1) {
          sel.clear();
          sel.add(item.id);
        } else {
          toastStore.addAlert(`Maximum selection limit reached`);
          return;
        }
      }
      selected.value = new Set(sel);
      if (maxSelectable.value === 1) {
        closeDropdown();
      }
    }
    __name(handleSelection, "handleSelection");
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", {
        ref_key: "triggerRef",
        ref: triggerRef
      }, [
        createVNode(_sfc_main$7, {
          files: files.value,
          "is-open": isOpen.value,
          placeholder: _ctx.placeholder,
          items: _ctx.items,
          "max-selectable": maxSelectable.value,
          selected: selected.value,
          uploadable: _ctx.uploadable,
          disabled: _ctx.disabled,
          accept: _ctx.accept,
          onSelectClick: toggleDropdown,
          onFileChange: handleFileChange
        }, null, 8, ["files", "is-open", "placeholder", "items", "max-selectable", "selected", "uploadable", "disabled", "accept"]),
        createVNode(unref(script$1), {
          ref_key: "popoverRef",
          ref: popoverRef,
          dismissable: true,
          "close-on-escape": true,
          unstyled: "",
          pt: {
            root: {
              class: "absolute z-50"
            },
            content: {
              class: ["bg-transparent border-none p-0 pt-2 rounded-lg shadow-lg"]
            }
          },
          onHide: _cache[4] || (_cache[4] = ($event) => isOpen.value = false)
        }, {
          default: withCtx(() => [
            createVNode(_sfc_main$3, {
              "filter-selected": filterSelected.value,
              "onUpdate:filterSelected": _cache[0] || (_cache[0] = ($event) => filterSelected.value = $event),
              "layout-mode": layoutMode.value,
              "onUpdate:layoutMode": _cache[1] || (_cache[1] = ($event) => layoutMode.value = $event),
              "sort-selected": sortSelected.value,
              "onUpdate:sortSelected": _cache[2] || (_cache[2] = ($event) => sortSelected.value = $event),
              "search-query": searchQuery.value,
              "onUpdate:searchQuery": _cache[3] || (_cache[3] = ($event) => searchQuery.value = $event),
              "filter-options": _ctx.filterOptions,
              "sort-options": _ctx.sortOptions,
              disabled: _ctx.disabled,
              "is-querying": isQuerying.value,
              items: sortedItems.value,
              "is-selected": internalIsSelected,
              "max-selectable": maxSelectable.value,
              onClose: closeDropdown,
              onItemClick: handleSelection
            }, null, 8, ["filter-selected", "layout-mode", "sort-selected", "search-query", "filter-options", "sort-options", "disabled", "is-querying", "items", "max-selectable"])
          ]),
          _: 1
        }, 512)
      ], 512);
    };
  }
});
function useAssetWidgetData(nodeType) {
  return {
    category: computed(() => void 0),
    assets: computed(() => []),
    dropdownItems: computed(() => []),
    isLoading: computed(() => false),
    error: computed(() => null)
  };
}
__name(useAssetWidgetData, "useAssetWidgetData");
const _sfc_main$1 = /* @__PURE__ */ defineComponent({
  __name: "WidgetSelectDropdown",
  props: /* @__PURE__ */ mergeModels({
    widget: {},
    nodeType: {},
    assetKind: {},
    allowUpload: { type: Boolean },
    uploadFolder: {},
    isAssetMode: { type: Boolean },
    defaultLayoutMode: {}
  }, {
    "modelValue": {
      default(props) {
        return props.widget.options?.values?.[0] || "";
      }
    },
    "modelModifiers": {}
  }),
  emits: ["update:modelValue"],
  setup(__props) {
    const props = __props;
    provide(
      AssetKindKey,
      computed(() => props.assetKind)
    );
    const modelValue = useModel(__props, "modelValue");
    const toastStore = useToastStore();
    const queueStore = useQueueStore();
    const transformCompatProps = useTransformCompatOverlayProps();
    const combinedProps = computed(() => ({
      ...filterWidgetProps(props.widget.options, PANEL_EXCLUDED_PROPS),
      ...transformCompatProps.value
    }));
    const getAssetData = /* @__PURE__ */ __name(() => {
      const nodeType = props.widget.options?.nodeType ?? props.nodeType;
      if (props.isAssetMode && nodeType) {
        return useAssetWidgetData(toRef(nodeType));
      }
      return null;
    }, "getAssetData");
    const assetData = getAssetData();
    const filterSelected = ref("all");
    const filterOptions = computed(() => {
      if (props.isAssetMode) {
        const categoryName = assetData?.category.value ?? "All";
        return [{ id: "all", name: capitalize(categoryName) }];
      }
      return [
        { id: "all", name: "All" },
        { id: "inputs", name: "Inputs" },
        { id: "outputs", name: "Outputs" }
      ];
    });
    const selectedSet = ref(/* @__PURE__ */ new Set());
    function getDisplayLabel(value) {
      const getOptionLabel = props.widget.options?.getOptionLabel;
      if (!getOptionLabel) return value;
      try {
        return getOptionLabel(value);
      } catch (e) {
        console.error("Failed to map value:", e);
        return value;
      }
    }
    __name(getDisplayLabel, "getDisplayLabel");
    const inputItems = computed(() => {
      const values = props.widget.options?.values || [];
      if (!Array.isArray(values)) {
        return [];
      }
      return values.map((value, index) => ({
        id: `input-${index}`,
        mediaSrc: getMediaUrl(value, "input"),
        name: value,
        label: getDisplayLabel(value),
        metadata: ""
      }));
    });
    const outputItems = computed(() => {
      if (!["image", "video"].includes(props.assetKind ?? "")) return [];
      const outputs = /* @__PURE__ */ new Set();
      queueStore.historyTasks.forEach((task) => {
        task.flatOutputs.forEach((output) => {
          const isTargetType = props.assetKind === "image" && output.mediaType === "images" || props.assetKind === "video" && output.mediaType === "video";
          if (output.type === "output" && isTargetType) {
            const path = output.subfolder ? `${output.subfolder}/${output.filename}` : output.filename;
            const annotatedPath = `${path} [output]`;
            outputs.add(annotatedPath);
          }
        });
      });
      return Array.from(outputs).map((output) => ({
        id: `output-${output}`,
        mediaSrc: getMediaUrl(output.replace(" [output]", ""), "output"),
        name: output,
        label: getDisplayLabel(output),
        metadata: ""
      }));
    });
    const allItems = computed(() => {
      if (props.isAssetMode && assetData) {
        return assetData.dropdownItems.value;
      }
      return [...inputItems.value, ...outputItems.value];
    });
    const dropdownItems = computed(() => {
      if (props.isAssetMode) {
        return allItems.value;
      }
      switch (filterSelected.value) {
        case "inputs":
          return inputItems.value;
        case "outputs":
          return outputItems.value;
        case "all":
        default:
          return [...inputItems.value, ...outputItems.value];
      }
    });
    const mediaPlaceholder = computed(() => {
      const options = props.widget.options;
      if (options?.placeholder) {
        return options.placeholder;
      }
      switch (props.assetKind) {
        case "image":
          return t("widgets.uploadSelect.placeholderImage");
        case "video":
          return t("widgets.uploadSelect.placeholderVideo");
        case "audio":
          return t("widgets.uploadSelect.placeholderAudio");
        case "model":
          return t("widgets.uploadSelect.placeholderModel");
        case "unknown":
          return t("widgets.uploadSelect.placeholderUnknown");
      }
      return t("widgets.uploadSelect.placeholder");
    });
    const uploadable = computed(() => {
      if (props.isAssetMode) return false;
      return props.allowUpload === true;
    });
    const acceptTypes = computed(() => {
      switch (props.assetKind) {
        case "image":
          return "image/*";
        case "video":
          return "video/*";
        case "audio":
          return "audio/*";
        default:
          return void 0;
      }
    });
    const layoutMode = ref(props.defaultLayoutMode ?? "grid");
    watch(
      [modelValue, dropdownItems],
      ([currentValue, _dropdownItems]) => {
        if (currentValue === void 0) {
          selectedSet.value.clear();
          return;
        }
        const item = dropdownItems.value.find((item2) => item2.name === currentValue);
        if (item) {
          selectedSet.value.clear();
          selectedSet.value.add(item.id);
        }
      },
      { immediate: true }
    );
    function updateSelectedItems(selectedItems) {
      let id = void 0;
      if (selectedItems.size > 0) {
        id = selectedItems.values().next().value;
      }
      if (id == null) {
        modelValue.value = void 0;
        return;
      }
      const name = dropdownItems.value.find((item) => item.id === id)?.name;
      if (!name) {
        modelValue.value = void 0;
        return;
      }
      modelValue.value = name;
    }
    __name(updateSelectedItems, "updateSelectedItems");
    const uploadFile = /* @__PURE__ */ __name(async (file, isPasted = false, formFields = {}) => {
      const body = new FormData();
      body.append("image", file);
      if (isPasted) body.append("subfolder", "pasted");
      if (formFields.type) body.append("type", formFields.type);
      const resp = await api.fetchApi("/upload/image", {
        method: "POST",
        body
      });
      if (resp.status !== 200) {
        toastStore.addAlert(resp.status + " - " + resp.statusText);
        return null;
      }
      const data = await resp.json();
      if (formFields.type === "input" || !formFields.type && !isPasted) {
        const assetsStore = useAssetsStore();
        await assetsStore.updateInputs();
      }
      return data.subfolder ? `${data.subfolder}/${data.name}` : data.name;
    }, "uploadFile");
    const uploadFiles = /* @__PURE__ */ __name(async (files) => {
      const folder = props.uploadFolder ?? "input";
      const uploadPromises = files.map(
        (file) => uploadFile(file, false, { type: folder })
      );
      const results = await Promise.all(uploadPromises);
      return results.filter((path) => path !== null);
    }, "uploadFiles");
    async function handleFilesUpdate(files) {
      if (!files || files.length === 0) return;
      try {
        const uploadedPaths = await uploadFiles(files);
        if (uploadedPaths.length === 0) {
          toastStore.addAlert("File upload failed");
          return;
        }
        if (props.widget.options?.values) {
          uploadedPaths.forEach((path) => {
            const values = props.widget.options.values;
            if (!values.includes(path)) {
              values.push(path);
            }
          });
        }
        modelValue.value = uploadedPaths[0];
        if (props.widget.callback) {
          props.widget.callback(uploadedPaths[0]);
        }
      } catch (error) {
        console.error("Upload error:", error);
        toastStore.addAlert(`Upload failed: ${error}`);
      }
    }
    __name(handleFilesUpdate, "handleFilesUpdate");
    function getMediaUrl(filename, type = "input") {
      if (!["image", "video"].includes(props.assetKind ?? "")) return "";
      return `/api/view?filename=${encodeURIComponent(filename)}&type=${type}`;
    }
    __name(getMediaUrl, "getMediaUrl");
    return (_ctx, _cache) => {
      return openBlock(), createBlock(_sfc_main$9, { widget: _ctx.widget }, {
        default: withCtx(() => [
          createVNode(_sfc_main$2, mergeProps({
            selected: selectedSet.value,
            "onUpdate:selected": _cache[0] || (_cache[0] = ($event) => selectedSet.value = $event),
            "filter-selected": filterSelected.value,
            "onUpdate:filterSelected": _cache[1] || (_cache[1] = ($event) => filterSelected.value = $event),
            "layout-mode": layoutMode.value,
            "onUpdate:layoutMode": _cache[2] || (_cache[2] = ($event) => layoutMode.value = $event),
            items: dropdownItems.value,
            placeholder: mediaPlaceholder.value,
            multiple: false,
            uploadable: uploadable.value,
            accept: acceptTypes.value,
            "filter-options": filterOptions.value
          }, combinedProps.value, {
            class: "w-full",
            "onUpdate:selected": updateSelectedItems,
            "onUpdate:files": handleFilesUpdate
          }), null, 16, ["selected", "filter-selected", "layout-mode", "items", "placeholder", "uploadable", "accept", "filter-options"])
        ]),
        _: 1
      }, 8, ["widget"]);
    };
  }
});
const _sfc_main = /* @__PURE__ */ defineComponent({
  __name: "WidgetSelect",
  props: /* @__PURE__ */ mergeModels({
    widget: {},
    nodeType: {}
  }, {
    "modelValue": {},
    "modelModifiers": {}
  }),
  emits: ["update:modelValue"],
  setup(__props) {
    const props = __props;
    const modelValue = useModel(__props, "modelValue");
    const comboSpec = computed(() => {
      if (props.widget.spec && isComboInputSpec(props.widget.spec)) {
        return props.widget.spec;
      }
      return void 0;
    });
    const specDescriptor = computed(() => {
      const spec = comboSpec.value;
      if (!spec) {
        return {
          kind: "unknown",
          allowUpload: false,
          folder: void 0
        };
      }
      const {
        image_upload,
        animated_image_upload,
        video_upload,
        image_folder,
        audio_upload
      } = spec;
      let kind = "unknown";
      if (video_upload) {
        kind = "video";
      } else if (image_upload || animated_image_upload) {
        kind = "image";
      } else if (audio_upload) {
        kind = "audio";
      }
      const allowUpload2 = image_upload === true || animated_image_upload === true || video_upload === true || audio_upload === true;
      return {
        kind,
        allowUpload: allowUpload2,
        folder: image_folder
      };
    });
    const isAssetMode = computed(() => {
      return false;
    });
    const assetKind = computed(() => specDescriptor.value.kind);
    const isDropdownUIWidget = computed(
      () => isAssetMode.value || assetKind.value !== "unknown"
    );
    const allowUpload = computed(() => specDescriptor.value.allowUpload);
    const uploadFolder = computed(() => {
      return specDescriptor.value.folder ?? "input";
    });
    const defaultLayoutMode = computed(() => {
      return isAssetMode.value ? "list" : "grid";
    });
    return (_ctx, _cache) => {
      return isDropdownUIWidget.value ? (openBlock(), createBlock(_sfc_main$1, {
        key: 0,
        modelValue: modelValue.value,
        "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => modelValue.value = $event),
        widget: _ctx.widget,
        "node-type": _ctx.widget.nodeType ?? _ctx.nodeType,
        "asset-kind": assetKind.value,
        "allow-upload": allowUpload.value,
        "upload-folder": uploadFolder.value,
        "is-asset-mode": isAssetMode.value,
        "default-layout-mode": defaultLayoutMode.value
      }, null, 8, ["modelValue", "widget", "node-type", "asset-kind", "allow-upload", "upload-folder", "is-asset-mode", "default-layout-mode"])) : _ctx.widget.controlWidget ? (openBlock(), createBlock(_sfc_main$c, {
        key: 1,
        modelValue: modelValue.value,
        "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => modelValue.value = $event),
        component: _sfc_main$8,
        widget: _ctx.widget
      }, null, 8, ["modelValue", "widget"])) : (openBlock(), createBlock(_sfc_main$8, {
        key: 2,
        modelValue: modelValue.value,
        "onUpdate:modelValue": _cache[2] || (_cache[2] = ($event) => modelValue.value = $event),
        widget: _ctx.widget
      }, null, 8, ["modelValue", "widget"]));
    };
  }
});
export {
  _sfc_main as _
};
//# sourceMappingURL=WidgetSelect.vue_vue_type_script_setup_true_lang-Dlin4Adg.js.map
