diff --git a/.github/workflows/pullrequest-ci-run.yml b/.github/workflows/pullrequest-ci-run.yml index 691480bc..a2a4b265 100644 --- a/.github/workflows/pullrequest-ci-run.yml +++ b/.github/workflows/pullrequest-ci-run.yml @@ -23,7 +23,7 @@ jobs: runner_label: [self-hosted, Linux] flags: "" - os: windows - runner_label: [self-hosted, win] + runner_label: [self-hosted, Windows] flags: "" runs-on: ${{ matrix.runner_label }} steps: diff --git a/.github/workflows/test-ci.yml b/.github/workflows/test-ci.yml index be762290..ce4598b2 100644 --- a/.github/workflows/test-ci.yml +++ b/.github/workflows/test-ci.yml @@ -32,7 +32,7 @@ jobs: runner_label: [self-hosted, Linux] flags: "" - os: windows - runner_label: [self-hosted, win] + runner_label: [self-hosted, Windows] flags: "" runs-on: ${{ matrix.runner_label }} steps: @@ -55,7 +55,7 @@ jobs: torch_version: ["nightly"] include: - os: windows - runner_label: [self-hosted, win] + runner_label: [self-hosted, Windows] flags: "" runs-on: ${{ matrix.runner_label }} steps: diff --git a/app/logger.py b/app/logger.py index 17662c9e..4ca0ea88 100644 --- a/app/logger.py +++ b/app/logger.py @@ -10,14 +10,14 @@ def get_logs(): return "\n".join([formatter.format(x) for x in logs]) -def setup_logger(verbose: bool = False, capacity: int = 300): +def setup_logger(log_level: str = 'INFO', capacity: int = 300): global logs if logs: return # Setup default global logger logger = logging.getLogger() - logger.setLevel(logging.DEBUG if verbose else logging.INFO) + logger.setLevel(log_level) stream_handler = logging.StreamHandler() stream_handler.setFormatter(logging.Formatter("%(message)s")) diff --git a/comfy/cli_args.py b/comfy/cli_args.py index d0f70643..20b9f474 100644 --- a/comfy/cli_args.py +++ b/comfy/cli_args.py @@ -36,7 +36,7 @@ class EnumAction(argparse.Action): parser = argparse.ArgumentParser() -parser.add_argument("--listen", type=str, default="127.0.0.1", metavar="IP", nargs="?", const="0.0.0.0", help="Specify the IP address to listen on (default: 127.0.0.1). If --listen is provided without an argument, it defaults to 0.0.0.0. (listens on all)") +parser.add_argument("--listen", type=str, default="127.0.0.1", metavar="IP", nargs="?", const="0.0.0.0,::", help="Specify the IP address to listen on (default: 127.0.0.1). You can give a list of ip addresses by separating them with a comma like: 127.2.2.2,127.3.3.3 If --listen is provided without an argument, it defaults to 0.0.0.0,:: (listens on all ipv4 and ipv6)") parser.add_argument("--port", type=int, default=8188, help="Set the listen port.") parser.add_argument("--tls-keyfile", type=str, help="Path to TLS (SSL) key file. Enables TLS, makes app accessible at https://... requires --tls-certfile to function") parser.add_argument("--tls-certfile", type=str, help="Path to TLS (SSL) certificate file. Enables TLS, makes app accessible at https://... requires --tls-keyfile to function") @@ -136,7 +136,7 @@ parser.add_argument("--disable-all-custom-nodes", action="store_true", help="Dis parser.add_argument("--multi-user", action="store_true", help="Enables per-user storage.") -parser.add_argument("--verbose", action="store_true", help="Enables more debug prints.") +parser.add_argument("--verbose", default='INFO', const='DEBUG', nargs="?", choices=['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'], help='Set the logging level') # The default built-in provider hosted under web/ DEFAULT_VERSION_STRING = "comfyanonymous/ComfyUI@latest" diff --git a/comfy/clip_vision.py b/comfy/clip_vision.py index 20dc3345..64392e27 100644 --- a/comfy/clip_vision.py +++ b/comfy/clip_vision.py @@ -109,8 +109,7 @@ def load_clipvision_from_sd(sd, prefix="", convert_keys=False): keys = list(sd.keys()) for k in keys: if k not in u: - t = sd.pop(k) - del t + sd.pop(k) return clip def load(ckpt_path): diff --git a/comfy/controlnet.py b/comfy/controlnet.py index 37914e5f..1d24afa6 100644 --- a/comfy/controlnet.py +++ b/comfy/controlnet.py @@ -237,6 +237,7 @@ class ControlNet(ControlBase): if len(self.extra_concat_orig) > 0: to_concat = [] for c in self.extra_concat_orig: + c = c.to(self.cond_hint.device) c = comfy.utils.common_upscale(c, self.cond_hint.shape[3], self.cond_hint.shape[2], self.upscale_algorithm, "center") to_concat.append(comfy.utils.repeat_to_batch_size(c, self.cond_hint.shape[0])) self.cond_hint = torch.cat([self.cond_hint] + to_concat, dim=1) diff --git a/comfy/float.py b/comfy/float.py index 4a6ae677..0c8f1d6c 100644 --- a/comfy/float.py +++ b/comfy/float.py @@ -1,5 +1,4 @@ import torch -import math def calc_mantissa(abs_x, exponent, normal_mask, MANTISSA_BITS, EXPONENT_BIAS, generator=None): mantissa_scaled = torch.where( diff --git a/comfy/k_diffusion/sampling.py b/comfy/k_diffusion/sampling.py index f4e39bfb..d5fc05cb 100644 --- a/comfy/k_diffusion/sampling.py +++ b/comfy/k_diffusion/sampling.py @@ -1266,3 +1266,36 @@ def sample_dpmpp_2s_ancestral_cfg_pp(model, x, sigmas, extra_args=None, callback if sigmas[i + 1] > 0: x = x + noise_sampler(sigmas[i], sigmas[i + 1]) * s_noise * sigma_up return x + +@torch.no_grad() +def sample_dpmpp_2m_cfg_pp(model, x, sigmas, extra_args=None, callback=None, disable=None): + """DPM-Solver++(2M).""" + extra_args = {} if extra_args is None else extra_args + s_in = x.new_ones([x.shape[0]]) + t_fn = lambda sigma: sigma.log().neg() + + old_uncond_denoised = None + uncond_denoised = None + def post_cfg_function(args): + nonlocal uncond_denoised + uncond_denoised = args["uncond_denoised"] + return args["denoised"] + + model_options = extra_args.get("model_options", {}).copy() + extra_args["model_options"] = comfy.model_patcher.set_model_options_post_cfg_function(model_options, post_cfg_function, disable_cfg1_optimization=True) + + for i in trange(len(sigmas) - 1, disable=disable): + denoised = model(x, sigmas[i] * s_in, **extra_args) + if callback is not None: + callback({'x': x, 'i': i, 'sigma': sigmas[i], 'sigma_hat': sigmas[i], 'denoised': denoised}) + t, t_next = t_fn(sigmas[i]), t_fn(sigmas[i + 1]) + h = t_next - t + if old_uncond_denoised is None or sigmas[i + 1] == 0: + denoised_mix = -torch.exp(-h) * uncond_denoised + else: + h_last = t - t_fn(sigmas[i - 1]) + r = h_last / h + denoised_mix = -torch.exp(-h) * uncond_denoised - torch.expm1(-h) * (1 / (2 * r)) * (denoised - old_uncond_denoised) + x = denoised + denoised_mix + torch.exp(-h) * x + old_uncond_denoised = uncond_denoised + return x \ No newline at end of file diff --git a/comfy/latent_formats.py b/comfy/latent_formats.py index ee19faea..191c7091 100644 --- a/comfy/latent_formats.py +++ b/comfy/latent_formats.py @@ -4,6 +4,7 @@ class LatentFormat: scale_factor = 1.0 latent_channels = 4 latent_rgb_factors = None + latent_rgb_factors_bias = None taesd_decoder_name = None def process_in(self, latent): @@ -30,11 +31,13 @@ class SDXL(LatentFormat): def __init__(self): self.latent_rgb_factors = [ # R G B - [ 0.3920, 0.4054, 0.4549], - [-0.2634, -0.0196, 0.0653], - [ 0.0568, 0.1687, -0.0755], - [-0.3112, -0.2359, -0.2076] + [ 0.3651, 0.4232, 0.4341], + [-0.2533, -0.0042, 0.1068], + [ 0.1076, 0.1111, -0.0362], + [-0.3165, -0.2492, -0.2188] ] + self.latent_rgb_factors_bias = [ 0.1084, -0.0175, -0.0011] + self.taesd_decoder_name = "taesdxl_decoder" class SDXL_Playground_2_5(LatentFormat): @@ -112,23 +115,24 @@ class SD3(LatentFormat): self.scale_factor = 1.5305 self.shift_factor = 0.0609 self.latent_rgb_factors = [ - [-0.0645, 0.0177, 0.1052], - [ 0.0028, 0.0312, 0.0650], - [ 0.1848, 0.0762, 0.0360], - [ 0.0944, 0.0360, 0.0889], - [ 0.0897, 0.0506, -0.0364], - [-0.0020, 0.1203, 0.0284], - [ 0.0855, 0.0118, 0.0283], - [-0.0539, 0.0658, 0.1047], - [-0.0057, 0.0116, 0.0700], - [-0.0412, 0.0281, -0.0039], - [ 0.1106, 0.1171, 0.1220], - [-0.0248, 0.0682, -0.0481], - [ 0.0815, 0.0846, 0.1207], - [-0.0120, -0.0055, -0.0867], - [-0.0749, -0.0634, -0.0456], - [-0.1418, -0.1457, -0.1259] + [-0.0922, -0.0175, 0.0749], + [ 0.0311, 0.0633, 0.0954], + [ 0.1994, 0.0927, 0.0458], + [ 0.0856, 0.0339, 0.0902], + [ 0.0587, 0.0272, -0.0496], + [-0.0006, 0.1104, 0.0309], + [ 0.0978, 0.0306, 0.0427], + [-0.0042, 0.1038, 0.1358], + [-0.0194, 0.0020, 0.0669], + [-0.0488, 0.0130, -0.0268], + [ 0.0922, 0.0988, 0.0951], + [-0.0278, 0.0524, -0.0542], + [ 0.0332, 0.0456, 0.0895], + [-0.0069, -0.0030, -0.0810], + [-0.0596, -0.0465, -0.0293], + [-0.1448, -0.1463, -0.1189] ] + self.latent_rgb_factors_bias = [0.2394, 0.2135, 0.1925] self.taesd_decoder_name = "taesd3_decoder" def process_in(self, latent): @@ -146,23 +150,24 @@ class Flux(SD3): self.scale_factor = 0.3611 self.shift_factor = 0.1159 self.latent_rgb_factors =[ - [-0.0404, 0.0159, 0.0609], - [ 0.0043, 0.0298, 0.0850], - [ 0.0328, -0.0749, -0.0503], - [-0.0245, 0.0085, 0.0549], - [ 0.0966, 0.0894, 0.0530], - [ 0.0035, 0.0399, 0.0123], - [ 0.0583, 0.1184, 0.1262], - [-0.0191, -0.0206, -0.0306], - [-0.0324, 0.0055, 0.1001], - [ 0.0955, 0.0659, -0.0545], - [-0.0504, 0.0231, -0.0013], - [ 0.0500, -0.0008, -0.0088], - [ 0.0982, 0.0941, 0.0976], - [-0.1233, -0.0280, -0.0897], - [-0.0005, -0.0530, -0.0020], - [-0.1273, -0.0932, -0.0680] + [-0.0346, 0.0244, 0.0681], + [ 0.0034, 0.0210, 0.0687], + [ 0.0275, -0.0668, -0.0433], + [-0.0174, 0.0160, 0.0617], + [ 0.0859, 0.0721, 0.0329], + [ 0.0004, 0.0383, 0.0115], + [ 0.0405, 0.0861, 0.0915], + [-0.0236, -0.0185, -0.0259], + [-0.0245, 0.0250, 0.1180], + [ 0.1008, 0.0755, -0.0421], + [-0.0515, 0.0201, 0.0011], + [ 0.0428, -0.0012, -0.0036], + [ 0.0817, 0.0765, 0.0749], + [-0.1264, -0.0522, -0.1103], + [-0.0280, -0.0881, -0.0499], + [-0.1262, -0.0982, -0.0778] ] + self.latent_rgb_factors_bias = [-0.0329, -0.0718, -0.0851] self.taesd_decoder_name = "taef1_decoder" def process_in(self, latent): diff --git a/comfy/ldm/flux/model.py b/comfy/ldm/flux/model.py index 63970cad..b7d8a692 100644 --- a/comfy/ldm/flux/model.py +++ b/comfy/ldm/flux/model.py @@ -108,7 +108,7 @@ class Flux(nn.Module): raise ValueError("Didn't get guidance strength for guidance distilled model.") vec = vec + self.guidance_in(timestep_embedding(guidance, 256).to(img.dtype)) - vec = vec + self.vector_in(y) + vec = vec + self.vector_in(y[:,:self.params.vec_in_dim]) txt = self.txt_in(txt) ids = torch.cat((txt_ids, img_ids), dim=1) @@ -151,8 +151,8 @@ class Flux(nn.Module): h_len = ((h + (patch_size // 2)) // patch_size) w_len = ((w + (patch_size // 2)) // patch_size) img_ids = torch.zeros((h_len, w_len, 3), device=x.device, dtype=x.dtype) - img_ids[..., 1] = img_ids[..., 1] + torch.linspace(0, h_len - 1, steps=h_len, device=x.device, dtype=x.dtype)[:, None] - img_ids[..., 2] = img_ids[..., 2] + torch.linspace(0, w_len - 1, steps=w_len, device=x.device, dtype=x.dtype)[None, :] + img_ids[:, :, 1] = torch.linspace(0, h_len - 1, steps=h_len, device=x.device, dtype=x.dtype).unsqueeze(1) + img_ids[:, :, 2] = torch.linspace(0, w_len - 1, steps=w_len, device=x.device, dtype=x.dtype).unsqueeze(0) img_ids = repeat(img_ids, "h w c -> b (h w) c", b=bs) txt_ids = torch.zeros((bs, context.shape[1], 3), device=x.device, dtype=x.dtype) diff --git a/comfy/lora.py b/comfy/lora.py index 83e55ec0..80057cdd 100644 --- a/comfy/lora.py +++ b/comfy/lora.py @@ -294,6 +294,7 @@ def model_lora_keys_unet(model, key_map={}): unet_key = "diffusion_model.{}".format(diffusers_keys[k]) key_lora = k[:-len(".weight")].replace(".", "_") key_map["lora_unet_{}".format(key_lora)] = unet_key + key_map["lycoris_{}".format(key_lora)] = unet_key #simpletuner lycoris format diffusers_lora_prefix = ["", "unet."] for p in diffusers_lora_prefix: @@ -342,10 +343,10 @@ def model_lora_keys_unet(model, key_map={}): return key_map -def weight_decompose(dora_scale, weight, lora_diff, alpha, strength, intermediate_dtype): +def weight_decompose(dora_scale, weight, lora_diff, alpha, strength, intermediate_dtype, function): dora_scale = comfy.model_management.cast_to_device(dora_scale, weight.device, intermediate_dtype) lora_diff *= alpha - weight_calc = weight + lora_diff.type(weight.dtype) + weight_calc = weight + function(lora_diff).type(weight.dtype) weight_norm = ( weight_calc.transpose(0, 1) .reshape(weight_calc.shape[1], -1) @@ -452,7 +453,7 @@ def calculate_weight(patches, weight, key, intermediate_dtype=torch.float32): try: lora_diff = torch.mm(mat1.flatten(start_dim=1), mat2.flatten(start_dim=1)).reshape(weight.shape) if dora_scale is not None: - weight = function(weight_decompose(dora_scale, weight, lora_diff, alpha, strength, intermediate_dtype)) + weight = weight_decompose(dora_scale, weight, lora_diff, alpha, strength, intermediate_dtype, function) else: weight += function(((strength * alpha) * lora_diff).type(weight.dtype)) except Exception as e: @@ -498,7 +499,7 @@ def calculate_weight(patches, weight, key, intermediate_dtype=torch.float32): try: lora_diff = torch.kron(w1, w2).reshape(weight.shape) if dora_scale is not None: - weight = function(weight_decompose(dora_scale, weight, lora_diff, alpha, strength, intermediate_dtype)) + weight = weight_decompose(dora_scale, weight, lora_diff, alpha, strength, intermediate_dtype, function) else: weight += function(((strength * alpha) * lora_diff).type(weight.dtype)) except Exception as e: @@ -535,7 +536,7 @@ def calculate_weight(patches, weight, key, intermediate_dtype=torch.float32): try: lora_diff = (m1 * m2).reshape(weight.shape) if dora_scale is not None: - weight = function(weight_decompose(dora_scale, weight, lora_diff, alpha, strength, intermediate_dtype)) + weight = weight_decompose(dora_scale, weight, lora_diff, alpha, strength, intermediate_dtype, function) else: weight += function(((strength * alpha) * lora_diff).type(weight.dtype)) except Exception as e: @@ -576,7 +577,7 @@ def calculate_weight(patches, weight, key, intermediate_dtype=torch.float32): lora_diff += torch.mm(b1, b2).reshape(weight.shape) if dora_scale is not None: - weight = function(weight_decompose(dora_scale, weight, lora_diff, alpha, strength, intermediate_dtype)) + weight = weight_decompose(dora_scale, weight, lora_diff, alpha, strength, intermediate_dtype, function) else: weight += function(((strength * alpha) * lora_diff).type(weight.dtype)) except Exception as e: diff --git a/comfy/model_base.py b/comfy/model_base.py index 9bfdb3b3..a98fee1d 100644 --- a/comfy/model_base.py +++ b/comfy/model_base.py @@ -96,7 +96,7 @@ class BaseModel(torch.nn.Module): if not unet_config.get("disable_unet_model_creation", False): if model_config.custom_operations is None: - operations = comfy.ops.pick_operations(unet_config.get("dtype", None), self.manual_cast_dtype) + operations = comfy.ops.pick_operations(unet_config.get("dtype", None), self.manual_cast_dtype, fp8_optimizations=model_config.optimizations.get("fp8", False)) else: operations = model_config.custom_operations self.diffusion_model = unet_model(**unet_config, device=device, operations=operations) diff --git a/comfy/model_management.py b/comfy/model_management.py index a97d489d..2346d4ac 100644 --- a/comfy/model_management.py +++ b/comfy/model_management.py @@ -145,7 +145,7 @@ total_ram = psutil.virtual_memory().total / (1024 * 1024) logging.info("Total VRAM {:0.0f} MB, total RAM {:0.0f} MB".format(total_vram, total_ram)) try: - logging.info("pytorch version: {}".format(torch.version.__version__)) + logging.info("pytorch version: {}".format(torch_version)) except: pass @@ -899,7 +899,7 @@ def force_upcast_attention_dtype(): upcast = args.force_upcast_attention try: macos_version = tuple(int(n) for n in platform.mac_ver()[0].split(".")) - if (14, 5) <= macos_version < (14, 7): # black image bug on recent versions of MacOS + if (14, 5) <= macos_version <= (15, 0, 1): # black image bug on recent versions of macOS upcast = True except: pass @@ -1065,6 +1065,9 @@ def should_use_bf16(device=None, model_params=0, prioritize_performance=True, ma return False def supports_fp8_compute(device=None): + if not is_nvidia(): + return False + props = torch.cuda.get_device_properties(device) if props.major >= 9: return True @@ -1072,6 +1075,14 @@ def supports_fp8_compute(device=None): return False if props.minor < 9: return False + + if int(torch_version[0]) < 2 or (int(torch_version[0]) == 2 and int(torch_version[2]) < 3): + return False + + if WINDOWS: + if (int(torch_version[0]) == 2 and int(torch_version[2]) < 4): + return False + return True def soft_empty_cache(force=False): diff --git a/comfy/model_patcher.py b/comfy/model_patcher.py index 6ca124e6..2ba30633 100644 --- a/comfy/model_patcher.py +++ b/comfy/model_patcher.py @@ -88,8 +88,12 @@ class LowVramPatch: self.key = key self.patches = patches def __call__(self, weight): - return comfy.lora.calculate_weight(self.patches[self.key], weight, self.key, intermediate_dtype=weight.dtype) + intermediate_dtype = weight.dtype + if intermediate_dtype not in [torch.float32, torch.float16, torch.bfloat16]: #intermediate_dtype has to be one that is supported in math ops + intermediate_dtype = torch.float32 + return comfy.float.stochastic_rounding(comfy.lora.calculate_weight(self.patches[self.key], weight.to(intermediate_dtype), self.key, intermediate_dtype=intermediate_dtype), weight.dtype, seed=string_to_seed(self.key)) + return comfy.lora.calculate_weight(self.patches[self.key], weight, self.key, intermediate_dtype=intermediate_dtype) class ModelPatcher: def __init__(self, model, load_device, offload_device, size=0, weight_inplace_update=False): self.size = size diff --git a/comfy/ops.py b/comfy/ops.py index 1b386dba..c90e25ea 100644 --- a/comfy/ops.py +++ b/comfy/ops.py @@ -260,7 +260,6 @@ def fp8_linear(self, input): if len(input.shape) == 3: inn = input.reshape(-1, input.shape[2]).to(dtype) - non_blocking = comfy.model_management.device_supports_non_blocking(input.device) w, bias = cast_bias_weight(self, input, dtype=dtype, bias_dtype=input.dtype) w = w.t() @@ -300,7 +299,11 @@ class fp8_ops(manual_cast): return torch.nn.functional.linear(input, weight, bias) -def pick_operations(weight_dtype, compute_dtype, load_device=None, disable_fast_fp8=False): +def pick_operations(weight_dtype, compute_dtype, load_device=None, disable_fast_fp8=False, fp8_optimizations=False): + if comfy.model_management.supports_fp8_compute(load_device): + if (fp8_optimizations or args.fast) and not disable_fast_fp8: + return fp8_ops + if compute_dtype is None or weight_dtype == compute_dtype: return disable_weight_init if args.fast and not disable_fast_fp8: diff --git a/comfy/samplers.py b/comfy/samplers.py index 0787c17c..4a975af7 100644 --- a/comfy/samplers.py +++ b/comfy/samplers.py @@ -571,8 +571,8 @@ class Sampler: KSAMPLER_NAMES = ["euler", "euler_cfg_pp", "euler_ancestral", "euler_ancestral_cfg_pp", "heun", "heunpp2","dpm_2", "dpm_2_ancestral", "lms", "dpm_fast", "dpm_adaptive", "dpmpp_2s_ancestral", "dpmpp_2s_ancestral_cfg_pp", "dpmpp_sde", "dpmpp_sde_gpu", - "dpmpp_2m", "dpmpp_2m_sde", "dpmpp_2m_sde_gpu", "dpmpp_3m_sde", "dpmpp_3m_sde_gpu", "ddpm", "lcm", - "ipndm", "ipndm_v", "deis", 'sa_solver', "sa_solver_gpu", "sa_solver_pece", "sa_solver_pece_gpu"] + "dpmpp_2m", "dpmpp_2m_cfg_pp", "dpmpp_2m_sde", "dpmpp_2m_sde_gpu", "dpmpp_3m_sde", "dpmpp_3m_sde_gpu", "ddpm", "lcm", + "ipndm", "ipndm_v", "deis", "sa_solver", "sa_solver_gpu", "sa_solver_pece", "sa_solver_pece_gpu"] class KSAMPLER(Sampler): def __init__(self, sampler_function, extra_options={}, inpaint_options={}): diff --git a/comfy/sd.py b/comfy/sd.py index 99859d24..67b4ff0c 100644 --- a/comfy/sd.py +++ b/comfy/sd.py @@ -29,7 +29,6 @@ import comfy.text_encoders.long_clipl import comfy.model_patcher import comfy.lora import comfy.t2i_adapter.adapter -import comfy.supported_models_base import comfy.taesd.taesd def load_lora_for_models(model, clip, lora, strength_model, strength_clip): @@ -348,7 +347,7 @@ class VAE: memory_used = self.memory_used_encode(pixel_samples.shape, self.vae_dtype) model_management.load_models_gpu([self.patcher], memory_required=memory_used) free_memory = model_management.get_free_memory(self.device) - batch_number = int(free_memory / memory_used) + batch_number = int(free_memory / max(1, memory_used)) batch_number = max(1, batch_number) samples = torch.empty((pixel_samples.shape[0], self.latent_channels) + tuple(map(lambda a: a // self.downscale_ratio, pixel_samples.shape[2:])), device=self.output_device) for x in range(0, pixel_samples.shape[0], batch_number): @@ -406,8 +405,48 @@ def load_clip(ckpt_paths, embedding_directory=None, clip_type=CLIPType.STABLE_DI clip_data.append(comfy.utils.load_torch_file(p, safe_load=True)) return load_text_encoder_state_dicts(clip_data, embedding_directory=embedding_directory, clip_type=clip_type, model_options=model_options) + +class TEModel(Enum): + CLIP_L = 1 + CLIP_H = 2 + CLIP_G = 3 + T5_XXL = 4 + T5_XL = 5 + T5_BASE = 6 + +def detect_te_model(sd): + if "text_model.encoder.layers.30.mlp.fc1.weight" in sd: + return TEModel.CLIP_G + if "text_model.encoder.layers.22.mlp.fc1.weight" in sd: + return TEModel.CLIP_H + if "text_model.encoder.layers.0.mlp.fc1.weight" in sd: + return TEModel.CLIP_L + if "encoder.block.23.layer.1.DenseReluDense.wi_1.weight" in sd: + weight = sd["encoder.block.23.layer.1.DenseReluDense.wi_1.weight"] + if weight.shape[-1] == 4096: + return TEModel.T5_XXL + elif weight.shape[-1] == 2048: + return TEModel.T5_XL + if "encoder.block.0.layer.0.SelfAttention.k.weight" in sd: + return TEModel.T5_BASE + return None + + +def t5xxl_weight_dtype(clip_data): + weight_name = "encoder.block.23.layer.1.DenseReluDense.wi_1.weight" + + dtype_t5 = None + for sd in clip_data: + weight = sd.get(weight_name, None) + if weight is not None: + dtype_t5 = weight.dtype + break + return dtype_t5 + + def load_text_encoder_state_dicts(state_dicts=[], embedding_directory=None, clip_type=CLIPType.STABLE_DIFFUSION, model_options={}): clip_data = state_dicts + class EmptyClass: pass @@ -421,53 +460,52 @@ def load_text_encoder_state_dicts(state_dicts=[], embedding_directory=None, clip clip_target = EmptyClass() clip_target.params = {} if len(clip_data) == 1: - if "text_model.encoder.layers.30.mlp.fc1.weight" in clip_data[0]: + te_model = detect_te_model(clip_data[0]) + if te_model == TEModel.CLIP_G: if clip_type == CLIPType.STABLE_CASCADE: clip_target.clip = sdxl_clip.StableCascadeClipModel clip_target.tokenizer = sdxl_clip.StableCascadeTokenizer + elif clip_type == CLIPType.SD3: + clip_target.clip = comfy.text_encoders.sd3_clip.sd3_clip(clip_l=False, clip_g=True, t5=False) + clip_target.tokenizer = comfy.text_encoders.sd3_clip.SD3Tokenizer else: clip_target.clip = sdxl_clip.SDXLRefinerClipModel clip_target.tokenizer = sdxl_clip.SDXLTokenizer - elif "text_model.encoder.layers.22.mlp.fc1.weight" in clip_data[0]: + elif te_model == TEModel.CLIP_H: clip_target.clip = comfy.text_encoders.sd2_clip.SD2ClipModel clip_target.tokenizer = comfy.text_encoders.sd2_clip.SD2Tokenizer - elif "encoder.block.23.layer.1.DenseReluDense.wi_1.weight" in clip_data[0]: - weight = clip_data[0]["encoder.block.23.layer.1.DenseReluDense.wi_1.weight"] - dtype_t5 = weight.dtype - if weight.shape[-1] == 4096: - clip_target.clip = comfy.text_encoders.sd3_clip.sd3_clip(clip_l=False, clip_g=False, t5=True, dtype_t5=dtype_t5) - clip_target.tokenizer = comfy.text_encoders.sd3_clip.SD3Tokenizer - elif weight.shape[-1] == 2048: - clip_target.clip = comfy.text_encoders.aura_t5.AuraT5Model - clip_target.tokenizer = comfy.text_encoders.aura_t5.AuraT5Tokenizer - elif "encoder.block.0.layer.0.SelfAttention.k.weight" in clip_data[0]: + elif te_model == TEModel.T5_XXL: + clip_target.clip = comfy.text_encoders.sd3_clip.sd3_clip(clip_l=False, clip_g=False, t5=True, dtype_t5=t5xxl_weight_dtype(clip_data)) + clip_target.tokenizer = comfy.text_encoders.sd3_clip.SD3Tokenizer + elif te_model == TEModel.T5_XL: + clip_target.clip = comfy.text_encoders.aura_t5.AuraT5Model + clip_target.tokenizer = comfy.text_encoders.aura_t5.AuraT5Tokenizer + elif te_model == TEModel.T5_BASE: clip_target.clip = comfy.text_encoders.sa_t5.SAT5Model clip_target.tokenizer = comfy.text_encoders.sa_t5.SAT5Tokenizer else: - w = clip_data[0].get("text_model.embeddings.position_embedding.weight", None) - clip_target.clip = sd1_clip.SD1ClipModel - clip_target.tokenizer = sd1_clip.SD1Tokenizer + if clip_type == CLIPType.SD3: + clip_target.clip = comfy.text_encoders.sd3_clip.sd3_clip(clip_l=True, clip_g=False, t5=False) + clip_target.tokenizer = comfy.text_encoders.sd3_clip.SD3Tokenizer + else: + clip_target.clip = sd1_clip.SD1ClipModel + clip_target.tokenizer = sd1_clip.SD1Tokenizer elif len(clip_data) == 2: if clip_type == CLIPType.SD3: - clip_target.clip = comfy.text_encoders.sd3_clip.sd3_clip(clip_l=True, clip_g=True, t5=False) + te_models = [detect_te_model(clip_data[0]), detect_te_model(clip_data[1])] + clip_target.clip = comfy.text_encoders.sd3_clip.sd3_clip(clip_l=TEModel.CLIP_L in te_models, clip_g=TEModel.CLIP_G in te_models, t5=TEModel.T5_XXL in te_models, dtype_t5=t5xxl_weight_dtype(clip_data)) clip_target.tokenizer = comfy.text_encoders.sd3_clip.SD3Tokenizer elif clip_type == CLIPType.HUNYUAN_DIT: clip_target.clip = comfy.text_encoders.hydit.HyditModel clip_target.tokenizer = comfy.text_encoders.hydit.HyditTokenizer elif clip_type == CLIPType.FLUX: - weight_name = "encoder.block.23.layer.1.DenseReluDense.wi_1.weight" - weight = clip_data[0].get(weight_name, clip_data[1].get(weight_name, None)) - dtype_t5 = None - if weight is not None: - dtype_t5 = weight.dtype - - clip_target.clip = comfy.text_encoders.flux.flux_clip(dtype_t5=dtype_t5) + clip_target.clip = comfy.text_encoders.flux.flux_clip(dtype_t5=t5xxl_weight_dtype(clip_data)) clip_target.tokenizer = comfy.text_encoders.flux.FluxTokenizer else: clip_target.clip = sdxl_clip.SDXLClipModel clip_target.tokenizer = sdxl_clip.SDXLTokenizer elif len(clip_data) == 3: - clip_target.clip = comfy.text_encoders.sd3_clip.SD3ClipModel + clip_target.clip = comfy.text_encoders.sd3_clip.sd3_clip(dtype_t5=t5xxl_weight_dtype(clip_data)) clip_target.tokenizer = comfy.text_encoders.sd3_clip.SD3Tokenizer parameters = 0 @@ -546,7 +584,7 @@ def load_state_dict_guess_config(sd, output_vae=True, output_clip=True, output_c unet_weight_dtype.append(weight_dtype) model_config.custom_operations = model_options.get("custom_operations", None) - unet_dtype = model_options.get("weight_dtype", None) + unet_dtype = model_options.get("dtype", model_options.get("weight_dtype", None)) if unet_dtype is None: unet_dtype = model_management.unet_dtype(model_params=parameters, supported_dtypes=unet_weight_dtype) @@ -560,7 +598,6 @@ def load_state_dict_guess_config(sd, output_vae=True, output_clip=True, output_c if output_model: inital_load_device = model_management.unet_inital_load_device(parameters, unet_dtype) - offload_device = model_management.unet_offload_device() model = model_config.get_model(sd, diffusion_model_prefix, device=inital_load_device) model.load_model_weights(sd, diffusion_model_prefix) @@ -646,6 +683,9 @@ def load_diffusion_model_state_dict(sd, model_options={}): #load unet in diffuse manual_cast_dtype = model_management.unet_manual_cast(unet_dtype, load_device, model_config.supported_inference_dtypes) model_config.set_inference_dtype(unet_dtype, manual_cast_dtype) model_config.custom_operations = model_options.get("custom_operations", model_config.custom_operations) + if model_options.get("fp8_optimizations", False): + model_config.optimizations["fp8"] = True + model = model_config.get_model(new_sd, "") model = model.to(offload_device) model.load_model_weights(new_sd, "") diff --git a/comfy/sd1_clip.py b/comfy/sd1_clip.py index 9f0d95b0..bb240526 100644 --- a/comfy/sd1_clip.py +++ b/comfy/sd1_clip.py @@ -80,7 +80,7 @@ class SDClipModel(torch.nn.Module, ClipTokenWeightEncoder): "pooled", "hidden" ] - def __init__(self, version="openai/clip-vit-large-patch14", device="cpu", max_length=77, + def __init__(self, device="cpu", max_length=77, freeze=True, layer="last", layer_idx=None, textmodel_json_config=None, dtype=None, model_class=comfy.clip_model.CLIPTextModel, special_tokens={"start": 49406, "end": 49407, "pad": 49407}, layer_norm_hidden_state=True, enable_attention_masks=False, zero_out_masked=False, return_projected_pooled=True, return_attention_masks=False, model_options={}): # clip-vit-base-patch32 diff --git a/comfy/supported_models_base.py b/comfy/supported_models_base.py index 7a2152f9..e2b70e69 100644 --- a/comfy/supported_models_base.py +++ b/comfy/supported_models_base.py @@ -49,6 +49,7 @@ class BASE: manual_cast_dtype = None custom_operations = None + optimizations = {"fp8": False} @classmethod def matches(s, unet_config, state_dict=None): @@ -71,6 +72,7 @@ class BASE: self.unet_config = unet_config.copy() self.sampling_settings = self.sampling_settings.copy() self.latent_format = self.latent_format() + self.optimizations = self.optimizations.copy() for x in self.unet_extra_config: self.unet_config[x] = self.unet_extra_config[x] diff --git a/comfy/text_encoders/flux.py b/comfy/text_encoders/flux.py index 7c75fe64..b13fa5b4 100644 --- a/comfy/text_encoders/flux.py +++ b/comfy/text_encoders/flux.py @@ -13,7 +13,7 @@ class T5XXLModel(sd1_clip.SDClipModel): class T5XXLTokenizer(sd1_clip.SDTokenizer): def __init__(self, embedding_directory=None, tokenizer_data={}): tokenizer_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), "t5_tokenizer") - super().__init__(tokenizer_path, pad_with_end=False, embedding_size=4096, embedding_key='t5xxl', tokenizer_class=T5TokenizerFast, has_start_token=False, pad_to_max_length=False, max_length=99999999, min_length=256) + super().__init__(tokenizer_path, embedding_directory=embedding_directory, pad_with_end=False, embedding_size=4096, embedding_key='t5xxl', tokenizer_class=T5TokenizerFast, has_start_token=False, pad_to_max_length=False, max_length=99999999, min_length=256) class FluxTokenizer: diff --git a/comfy/text_encoders/sd3_clip.py b/comfy/text_encoders/sd3_clip.py index c54f2885..0340e65b 100644 --- a/comfy/text_encoders/sd3_clip.py +++ b/comfy/text_encoders/sd3_clip.py @@ -8,9 +8,9 @@ import comfy.model_management import logging class T5XXLModel(sd1_clip.SDClipModel): - def __init__(self, device="cpu", layer="last", layer_idx=None, dtype=None, model_options={}): + def __init__(self, device="cpu", layer="last", layer_idx=None, dtype=None, attention_mask=False, model_options={}): textmodel_json_config = os.path.join(os.path.dirname(os.path.realpath(__file__)), "t5_config_xxl.json") - super().__init__(device=device, layer=layer, layer_idx=layer_idx, textmodel_json_config=textmodel_json_config, dtype=dtype, special_tokens={"end": 1, "pad": 0}, model_class=comfy.text_encoders.t5.T5, model_options=model_options) + super().__init__(device=device, layer=layer, layer_idx=layer_idx, textmodel_json_config=textmodel_json_config, dtype=dtype, special_tokens={"end": 1, "pad": 0}, model_class=comfy.text_encoders.t5.T5, enable_attention_masks=attention_mask, return_attention_masks=attention_mask, model_options=model_options) class T5XXLTokenizer(sd1_clip.SDTokenizer): def __init__(self, embedding_directory=None, tokenizer_data={}): @@ -39,7 +39,7 @@ class SD3Tokenizer: return {} class SD3ClipModel(torch.nn.Module): - def __init__(self, clip_l=True, clip_g=True, t5=True, dtype_t5=None, device="cpu", dtype=None, model_options={}): + def __init__(self, clip_l=True, clip_g=True, t5=True, dtype_t5=None, t5_attention_mask=False, device="cpu", dtype=None, model_options={}): super().__init__() self.dtypes = set() if clip_l: @@ -57,7 +57,8 @@ class SD3ClipModel(torch.nn.Module): if t5: dtype_t5 = comfy.model_management.pick_weight_dtype(dtype_t5, dtype, device) - self.t5xxl = T5XXLModel(device=device, dtype=dtype_t5, model_options=model_options) + self.t5_attention_mask = t5_attention_mask + self.t5xxl = T5XXLModel(device=device, dtype=dtype_t5, model_options=model_options, attention_mask=self.t5_attention_mask) self.dtypes.add(dtype_t5) else: self.t5xxl = None @@ -87,6 +88,7 @@ class SD3ClipModel(torch.nn.Module): lg_out = None pooled = None out = None + extra = {} if len(token_weight_pairs_g) > 0 or len(token_weight_pairs_l) > 0: if self.clip_l is not None: @@ -111,7 +113,11 @@ class SD3ClipModel(torch.nn.Module): pooled = torch.cat((l_pooled, g_pooled), dim=-1) if self.t5xxl is not None: - t5_out, t5_pooled = self.t5xxl.encode_token_weights(token_weight_pairs_t5) + t5_output = self.t5xxl.encode_token_weights(token_weight_pairs_t5) + t5_out, t5_pooled = t5_output[:2] + if self.t5_attention_mask: + extra["attention_mask"] = t5_output[2]["attention_mask"] + if lg_out is not None: out = torch.cat([lg_out, t5_out], dim=-2) else: @@ -123,7 +129,7 @@ class SD3ClipModel(torch.nn.Module): if pooled is None: pooled = torch.zeros((1, 768 + 1280), device=comfy.model_management.intermediate_device()) - return out, pooled + return out, pooled, extra def load_sd(self, sd): if "text_model.encoder.layers.30.mlp.fc1.weight" in sd: @@ -133,8 +139,8 @@ class SD3ClipModel(torch.nn.Module): else: return self.t5xxl.load_sd(sd) -def sd3_clip(clip_l=True, clip_g=True, t5=True, dtype_t5=None): +def sd3_clip(clip_l=True, clip_g=True, t5=True, dtype_t5=None, t5_attention_mask=False): class SD3ClipModel_(SD3ClipModel): def __init__(self, device="cpu", dtype=None, model_options={}): - super().__init__(clip_l=clip_l, clip_g=clip_g, t5=t5, dtype_t5=dtype_t5, device=device, dtype=dtype, model_options=model_options) + super().__init__(clip_l=clip_l, clip_g=clip_g, t5=t5, dtype_t5=dtype_t5, t5_attention_mask=t5_attention_mask, device=device, dtype=dtype, model_options=model_options) return SD3ClipModel_ diff --git a/comfy_extras/nodes_audio.py b/comfy_extras/nodes_audio.py index 1c763f25..e5cc4dff 100644 --- a/comfy_extras/nodes_audio.py +++ b/comfy_extras/nodes_audio.py @@ -16,14 +16,15 @@ class EmptyLatentAudio: @classmethod def INPUT_TYPES(s): - return {"required": {"seconds": ("FLOAT", {"default": 47.6, "min": 1.0, "max": 1000.0, "step": 0.1})}} + return {"required": {"seconds": ("FLOAT", {"default": 47.6, "min": 1.0, "max": 1000.0, "step": 0.1}), + "batch_size": ("INT", {"default": 1, "min": 1, "max": 4096, "tooltip": "The number of latent images in the batch."}), + }} RETURN_TYPES = ("LATENT",) FUNCTION = "generate" CATEGORY = "latent/audio" - def generate(self, seconds): - batch_size = 1 + def generate(self, seconds, batch_size): length = round((seconds * 44100 / 2048) / 2) * 2 latent = torch.zeros([batch_size, 64, length], device=self.device) return ({"samples":latent, "type": "audio"}, ) diff --git a/comfy_extras/nodes_model_downscale.py b/comfy_extras/nodes_model_downscale.py index 58b5073e..15ffc4c8 100644 --- a/comfy_extras/nodes_model_downscale.py +++ b/comfy_extras/nodes_model_downscale.py @@ -17,7 +17,7 @@ class PatchModelAddDownscale: RETURN_TYPES = ("MODEL",) FUNCTION = "patch" - CATEGORY = "_for_testing" + CATEGORY = "model_patches/unet" def patch(self, model, block_number, downscale_factor, start_percent, end_percent, downscale_after_skip, downscale_method, upscale_method): model_sampling = model.get_model_object("model_sampling") diff --git a/comfy_extras/nodes_stable_cascade.py b/comfy_extras/nodes_stable_cascade.py index fcbbeb27..00340321 100644 --- a/comfy_extras/nodes_stable_cascade.py +++ b/comfy_extras/nodes_stable_cascade.py @@ -116,6 +116,7 @@ class StableCascade_SuperResolutionControlnet: RETURN_NAMES = ("controlnet_input", "stage_c", "stage_b") FUNCTION = "generate" + EXPERIMENTAL = True CATEGORY = "_for_testing/stable_cascade" def generate(self, image, vae): diff --git a/comfy_extras/nodes_tomesd.py b/comfy_extras/nodes_tomesd.py index df048506..ce7b32c7 100644 --- a/comfy_extras/nodes_tomesd.py +++ b/comfy_extras/nodes_tomesd.py @@ -154,7 +154,7 @@ class TomePatchModel: RETURN_TYPES = ("MODEL",) FUNCTION = "patch" - CATEGORY = "_for_testing" + CATEGORY = "model_patches/unet" def patch(self, model, ratio): self.u = None diff --git a/comfy_extras/nodes_torch_compile.py b/comfy_extras/nodes_torch_compile.py index 1d914fa9..1fe6f42c 100644 --- a/comfy_extras/nodes_torch_compile.py +++ b/comfy_extras/nodes_torch_compile.py @@ -4,6 +4,7 @@ class TorchCompileModel: @classmethod def INPUT_TYPES(s): return {"required": { "model": ("MODEL",), + "backend": (["inductor", "cudagraphs"],), }} RETURN_TYPES = ("MODEL",) FUNCTION = "patch" @@ -11,9 +12,9 @@ class TorchCompileModel: CATEGORY = "_for_testing" EXPERIMENTAL = True - def patch(self, model): + def patch(self, model, backend): m = model.clone() - m.add_object_patch("diffusion_model", torch.compile(model=m.get_model_object("diffusion_model"))) + m.add_object_patch("diffusion_model", torch.compile(model=m.get_model_object("diffusion_model"), backend=backend)) return (m, ) NODE_CLASS_MAPPINGS = { diff --git a/comfy_extras/nodes_video_model.py b/comfy_extras/nodes_video_model.py index 7f2146d1..e7a7ec18 100644 --- a/comfy_extras/nodes_video_model.py +++ b/comfy_extras/nodes_video_model.py @@ -107,7 +107,7 @@ class VideoTriangleCFGGuidance: return (m, ) class ImageOnlyCheckpointSave(comfy_extras.nodes_model_merging.CheckpointSave): - CATEGORY = "_for_testing" + CATEGORY = "advanced/model_merging" @classmethod def INPUT_TYPES(s): diff --git a/custom_nodes/websocket_image_save.py b/custom_nodes/websocket_image_save.py index 5aa57364..09fe1bde 100644 --- a/custom_nodes/websocket_image_save.py +++ b/custom_nodes/websocket_image_save.py @@ -37,6 +37,7 @@ class SaveImageWebsocket: return {} + @classmethod def IS_CHANGED(s, images): return time.time() diff --git a/folder_paths.py b/folder_paths.py index 1f03c08d..01ae821d 100644 --- a/folder_paths.py +++ b/folder_paths.py @@ -234,8 +234,12 @@ def recursive_search(directory: str, excluded_dir_names: list[str] | None=None) for dirpath, subdirs, filenames in os.walk(directory, followlinks=True, topdown=True): subdirs[:] = [d for d in subdirs if d not in excluded_dir_names] for file_name in filenames: - relative_path = os.path.relpath(os.path.join(dirpath, file_name), directory) - result.append(relative_path) + try: + relative_path = os.path.relpath(os.path.join(dirpath, file_name), directory) + result.append(relative_path) + except: + logging.warning(f"Warning: Unable to access {file_name}. Skipping this file.") + continue for d in subdirs: path: str = os.path.join(dirpath, d) diff --git a/latent_preview.py b/latent_preview.py index e14c72ce..ae9211a2 100644 --- a/latent_preview.py +++ b/latent_preview.py @@ -36,12 +36,20 @@ class TAESDPreviewerImpl(LatentPreviewer): class Latent2RGBPreviewer(LatentPreviewer): - def __init__(self, latent_rgb_factors): - self.latent_rgb_factors = torch.tensor(latent_rgb_factors, device="cpu") + def __init__(self, latent_rgb_factors, latent_rgb_factors_bias=None): + self.latent_rgb_factors = torch.tensor(latent_rgb_factors, device="cpu").transpose(0, 1) + self.latent_rgb_factors_bias = None + if latent_rgb_factors_bias is not None: + self.latent_rgb_factors_bias = torch.tensor(latent_rgb_factors_bias, device="cpu") def decode_latent_to_preview(self, x0): self.latent_rgb_factors = self.latent_rgb_factors.to(dtype=x0.dtype, device=x0.device) - latent_image = x0[0].permute(1, 2, 0) @ self.latent_rgb_factors + if self.latent_rgb_factors_bias is not None: + self.latent_rgb_factors_bias = self.latent_rgb_factors_bias.to(dtype=x0.dtype, device=x0.device) + + latent_image = torch.nn.functional.linear(x0[0].permute(1, 2, 0), self.latent_rgb_factors, bias=self.latent_rgb_factors_bias) + # latent_image = x0[0].permute(1, 2, 0) @ self.latent_rgb_factors + return preview_to_image(latent_image) @@ -71,7 +79,7 @@ def get_previewer(device, latent_format): if previewer is None: if latent_format.latent_rgb_factors is not None: - previewer = Latent2RGBPreviewer(latent_format.latent_rgb_factors) + previewer = Latent2RGBPreviewer(latent_format.latent_rgb_factors, latent_format.latent_rgb_factors_bias) return previewer def prepare_callback(model, steps, x0_output_dict=None): diff --git a/main.py b/main.py index f5b633e5..c2321086 100644 --- a/main.py +++ b/main.py @@ -9,7 +9,7 @@ from comfy.cli_args import args from app.logger import setup_logger -setup_logger(verbose=args.verbose) +setup_logger(log_level=args.verbose) def execute_prestartup_script(): @@ -160,7 +160,10 @@ def prompt_worker(q, server): need_gc = False async def run(server, address='', port=8188, verbose=True, call_on_start=None): - await asyncio.gather(server.start(address, port, verbose, call_on_start), server.publish_loop()) + addresses = [] + for addr in address.split(","): + addresses.append((addr, port)) + await asyncio.gather(server.start_multi_address(addresses, call_on_start), server.publish_loop()) def hijack_progress(server): @@ -248,6 +251,8 @@ if __name__ == "__main__": import webbrowser if os.name == 'nt' and address == '0.0.0.0': address = '127.0.0.1' + if ':' in address: + address = "[{}]".format(address) webbrowser.open(f"{scheme}://{address}:{port}") call_on_start = startup_server diff --git a/model_filemanager/__init__.py b/model_filemanager/__init__.py index e318351c..b7ac1625 100644 --- a/model_filemanager/__init__.py +++ b/model_filemanager/__init__.py @@ -1,2 +1,2 @@ # model_manager/__init__.py -from .download_models import download_model, DownloadModelStatus, DownloadStatusType, create_model_path, check_file_exists, track_download_progress, validate_model_subdirectory, validate_filename +from .download_models import download_model, DownloadModelStatus, DownloadStatusType, create_model_path, check_file_exists, track_download_progress, validate_filename diff --git a/model_filemanager/download_models.py b/model_filemanager/download_models.py index 712d5932..6722b6e1 100644 --- a/model_filemanager/download_models.py +++ b/model_filemanager/download_models.py @@ -1,9 +1,10 @@ +#NOTE: This was an experiment and WILL BE REMOVED from __future__ import annotations import aiohttp import os import traceback import logging -from folder_paths import models_dir +from folder_paths import folder_names_and_paths, get_folder_paths import re from typing import Callable, Any, Optional, Awaitable, Dict from enum import Enum @@ -17,6 +18,7 @@ class DownloadStatusType(Enum): COMPLETED = "completed" ERROR = "error" + @dataclass class DownloadModelStatus(): status: str @@ -29,7 +31,7 @@ class DownloadModelStatus(): self.progress_percentage = progress_percentage self.message = message self.already_existed = already_existed - + def to_dict(self) -> Dict[str, Any]: return { "status": self.status, @@ -38,102 +40,112 @@ class DownloadModelStatus(): "already_existed": self.already_existed } + async def download_model(model_download_request: Callable[[str], Awaitable[aiohttp.ClientResponse]], - model_name: str, - model_url: str, - model_sub_directory: str, + model_name: str, + model_url: str, + model_directory: str, + folder_path: str, progress_callback: Callable[[str, DownloadModelStatus], Awaitable[Any]], progress_interval: float = 1.0) -> DownloadModelStatus: """ Download a model file from a given URL into the models directory. Args: - model_download_request (Callable[[str], Awaitable[aiohttp.ClientResponse]]): + model_download_request (Callable[[str], Awaitable[aiohttp.ClientResponse]]): A function that makes an HTTP request. This makes it easier to mock in unit tests. - model_name (str): + model_name (str): The name of the model file to be downloaded. This will be the filename on disk. - model_url (str): + model_url (str): The URL from which to download the model. - model_sub_directory (str): - The subdirectory within the main models directory where the model + model_directory (str): + The subdirectory within the main models directory where the model should be saved (e.g., 'checkpoints', 'loras', etc.). - progress_callback (Callable[[str, DownloadModelStatus], Awaitable[Any]]): + progress_callback (Callable[[str, DownloadModelStatus], Awaitable[Any]]): An asynchronous function to call with progress updates. + folder_path (str); + Path to which model folder should be used as the root. Returns: DownloadModelStatus: The result of the download operation. """ - if not validate_model_subdirectory(model_sub_directory): - return DownloadModelStatus( - DownloadStatusType.ERROR, - 0, - "Invalid model subdirectory", - False - ) - if not validate_filename(model_name): return DownloadModelStatus( - DownloadStatusType.ERROR, + DownloadStatusType.ERROR, 0, - "Invalid model name", + "Invalid model name", False ) - file_path, relative_path = create_model_path(model_name, model_sub_directory, models_dir) - existing_file = await check_file_exists(file_path, model_name, progress_callback, relative_path) + if not model_directory in folder_names_and_paths: + return DownloadModelStatus( + DownloadStatusType.ERROR, + 0, + "Invalid or unrecognized model directory. model_directory must be a known model type (eg 'checkpoints'). If you are seeing this error for a custom model type, ensure the relevant custom nodes are installed and working.", + False + ) + + if not folder_path in get_folder_paths(model_directory): + return DownloadModelStatus( + DownloadStatusType.ERROR, + 0, + f"Invalid folder path '{folder_path}', does not match the list of known directories ({get_folder_paths(model_directory)}). If you're seeing this in the downloader UI, you may need to refresh the page.", + False + ) + + file_path = create_model_path(model_name, folder_path) + existing_file = await check_file_exists(file_path, model_name, progress_callback) if existing_file: return existing_file try: + logging.info(f"Downloading {model_name} from {model_url}") status = DownloadModelStatus(DownloadStatusType.PENDING, 0, f"Starting download of {model_name}", False) - await progress_callback(relative_path, status) + await progress_callback(model_name, status) response = await model_download_request(model_url) if response.status != 200: error_message = f"Failed to download {model_name}. Status code: {response.status}" logging.error(error_message) status = DownloadModelStatus(DownloadStatusType.ERROR, 0, error_message, False) - await progress_callback(relative_path, status) + await progress_callback(model_name, status) return DownloadModelStatus(DownloadStatusType.ERROR, 0, error_message, False) - return await track_download_progress(response, file_path, model_name, progress_callback, relative_path, progress_interval) + return await track_download_progress(response, file_path, model_name, progress_callback, progress_interval) except Exception as e: logging.error(f"Error in downloading model: {e}") - return await handle_download_error(e, model_name, progress_callback, relative_path) - + return await handle_download_error(e, model_name, progress_callback) -def create_model_path(model_name: str, model_directory: str, models_base_dir: str) -> tuple[str, str]: - full_model_dir = os.path.join(models_base_dir, model_directory) - os.makedirs(full_model_dir, exist_ok=True) - file_path = os.path.join(full_model_dir, model_name) + +def create_model_path(model_name: str, folder_path: str) -> tuple[str, str]: + os.makedirs(folder_path, exist_ok=True) + file_path = os.path.join(folder_path, model_name) # Ensure the resulting path is still within the base directory abs_file_path = os.path.abspath(file_path) - abs_base_dir = os.path.abspath(str(models_base_dir)) + abs_base_dir = os.path.abspath(folder_path) if os.path.commonprefix([abs_file_path, abs_base_dir]) != abs_base_dir: - raise Exception(f"Invalid model directory: {model_directory}/{model_name}") + raise Exception(f"Invalid model directory: {folder_path}/{model_name}") + + return file_path - relative_path = '/'.join([model_directory, model_name]) - return file_path, relative_path - -async def check_file_exists(file_path: str, - model_name: str, - progress_callback: Callable[[str, DownloadModelStatus], Awaitable[Any]], - relative_path: str) -> Optional[DownloadModelStatus]: +async def check_file_exists(file_path: str, + model_name: str, + progress_callback: Callable[[str, DownloadModelStatus], Awaitable[Any]] + ) -> Optional[DownloadModelStatus]: if os.path.exists(file_path): status = DownloadModelStatus(DownloadStatusType.COMPLETED, 100, f"{model_name} already exists", True) - await progress_callback(relative_path, status) + await progress_callback(model_name, status) return status return None -async def track_download_progress(response: aiohttp.ClientResponse, - file_path: str, - model_name: str, - progress_callback: Callable[[str, DownloadModelStatus], Awaitable[Any]], - relative_path: str, +async def track_download_progress(response: aiohttp.ClientResponse, + file_path: str, + model_name: str, + progress_callback: Callable[[str, DownloadModelStatus], Awaitable[Any]], interval: float = 1.0) -> DownloadModelStatus: try: total_size = int(response.headers.get('Content-Length', 0)) @@ -144,10 +156,11 @@ async def track_download_progress(response: aiohttp.ClientResponse, nonlocal last_update_time progress = (downloaded / total_size) * 100 if total_size > 0 else 0 status = DownloadModelStatus(DownloadStatusType.IN_PROGRESS, progress, f"Downloading {model_name}", False) - await progress_callback(relative_path, status) + await progress_callback(model_name, status) last_update_time = time.time() - with open(file_path, 'wb') as f: + temp_file_path = file_path + '.tmp' + with open(temp_file_path, 'wb') as f: chunk_iterator = response.content.iter_chunked(8192) while True: try: @@ -156,58 +169,39 @@ async def track_download_progress(response: aiohttp.ClientResponse, break f.write(chunk) downloaded += len(chunk) - + if time.time() - last_update_time >= interval: await update_progress() + os.rename(temp_file_path, file_path) + await update_progress() - + logging.info(f"Successfully downloaded {model_name}. Total downloaded: {downloaded}") status = DownloadModelStatus(DownloadStatusType.COMPLETED, 100, f"Successfully downloaded {model_name}", False) - await progress_callback(relative_path, status) + await progress_callback(model_name, status) return status except Exception as e: logging.error(f"Error in track_download_progress: {e}") logging.error(traceback.format_exc()) - return await handle_download_error(e, model_name, progress_callback, relative_path) + return await handle_download_error(e, model_name, progress_callback) -async def handle_download_error(e: Exception, - model_name: str, - progress_callback: Callable[[str, DownloadModelStatus], Any], - relative_path: str) -> DownloadModelStatus: + +async def handle_download_error(e: Exception, + model_name: str, + progress_callback: Callable[[str, DownloadModelStatus], Any] + ) -> DownloadModelStatus: error_message = f"Error downloading {model_name}: {str(e)}" status = DownloadModelStatus(DownloadStatusType.ERROR, 0, error_message, False) - await progress_callback(relative_path, status) + await progress_callback(model_name, status) return status -def validate_model_subdirectory(model_subdirectory: str) -> bool: - """ - Validate that the model subdirectory is safe to install into. - Must not contain relative paths, nested paths or special characters - other than underscores and hyphens. - - Args: - model_subdirectory (str): The subdirectory for the specific model type. - - Returns: - bool: True if the subdirectory is safe, False otherwise. - """ - if len(model_subdirectory) > 50: - return False - - if '..' in model_subdirectory or '/' in model_subdirectory: - return False - - if not re.match(r'^[a-zA-Z0-9_-]+$', model_subdirectory): - return False - - return True def validate_filename(filename: str)-> bool: """ Validate a filename to ensure it's safe and doesn't contain any path traversal attempts. - + Args: filename (str): The filename to validate diff --git a/nodes.py b/nodes.py index a4065c76..15a78352 100644 --- a/nodes.py +++ b/nodes.py @@ -861,7 +861,7 @@ class UNETLoader: @classmethod def INPUT_TYPES(s): return {"required": { "unet_name": (folder_paths.get_filename_list("diffusion_models"), ), - "weight_dtype": (["default", "fp8_e4m3fn", "fp8_e5m2"],) + "weight_dtype": (["default", "fp8_e4m3fn", "fp8_e4m3fn_fast", "fp8_e5m2"],) }} RETURN_TYPES = ("MODEL",) FUNCTION = "load_unet" @@ -872,6 +872,9 @@ class UNETLoader: model_options = {} if weight_dtype == "fp8_e4m3fn": model_options["dtype"] = torch.float8_e4m3fn + elif weight_dtype == "fp8_e4m3fn_fast": + model_options["dtype"] = torch.float8_e4m3fn + model_options["fp8_optimizations"] = True elif weight_dtype == "fp8_e5m2": model_options["dtype"] = torch.float8_e5m2 diff --git a/server.py b/server.py index 482185f6..c7bf6622 100644 --- a/server.py +++ b/server.py @@ -679,6 +679,7 @@ class PromptServer(): # Internal route. Should not be depended upon and is subject to change at any time. # TODO(robinhuang): Move to internal route table class once we refactor PromptServer to pass around Websocket. + # NOTE: This was an experiment and WILL BE REMOVED @routes.post("/internal/models/download") async def download_handler(request): async def report_progress(filename: str, status: DownloadModelStatus): @@ -689,10 +690,11 @@ class PromptServer(): data = await request.json() url = data.get('url') model_directory = data.get('model_directory') + folder_path = data.get('folder_path') model_filename = data.get('model_filename') progress_interval = data.get('progress_interval', 1.0) # In seconds, how often to report download progress. - if not url or not model_directory or not model_filename: + if not url or not model_directory or not model_filename or not folder_path: return web.json_response({"status": "error", "message": "Missing URL or folder path or filename"}, status=400) session = self.client_session @@ -700,7 +702,7 @@ class PromptServer(): logging.error("Client session is not initialized") return web.Response(status=500) - task = asyncio.create_task(download_model(lambda url: session.get(url), model_filename, url, model_directory, report_progress, progress_interval)) + task = asyncio.create_task(download_model(lambda url: session.get(url), model_filename, url, model_directory, folder_path, report_progress, progress_interval)) await task return web.json_response(task.result().to_dict()) @@ -817,6 +819,9 @@ class PromptServer(): await self.send(*msg) async def start(self, address, port, verbose=True, call_on_start=None): + await self.start_multi_address([(address, port)], call_on_start=call_on_start) + + async def start_multi_address(self, addresses, call_on_start=None): runner = web.AppRunner(self.app, access_log=None) await runner.setup() ssl_ctx = None @@ -827,17 +832,26 @@ class PromptServer(): keyfile=args.tls_keyfile) scheme = "https" - site = web.TCPSite(runner, address, port, ssl_context=ssl_ctx) - await site.start() + logging.info("Starting server\n") + for addr in addresses: + address = addr[0] + port = addr[1] + site = web.TCPSite(runner, address, port, ssl_context=ssl_ctx) + await site.start() - self.address = address - self.port = port + if not hasattr(self, 'address'): + self.address = address #TODO: remove this + self.port = port + + if ':' in address: + address_print = "[{}]".format(address) + else: + address_print = address + + logging.info("To see the GUI go to: {}://{}:{}".format(scheme, address_print, port)) - if verbose: - logging.info("Starting server\n") - logging.info("To see the GUI go to: {}://{}:{}".format(scheme, address, port)) if call_on_start is not None: - call_on_start(scheme, address, port) + call_on_start(scheme, self.address, self.port) def add_on_prompt_handler(self, handler): self.on_prompt_handlers.append(handler) diff --git a/tests-unit/prompt_server_test/download_models_test.py b/tests-unit/prompt_server_test/download_models_test.py index 66150a46..128dfeb9 100644 --- a/tests-unit/prompt_server_test/download_models_test.py +++ b/tests-unit/prompt_server_test/download_models_test.py @@ -1,10 +1,17 @@ import pytest +import tempfile import aiohttp from aiohttp import ClientResponse import itertools -import os +import os from unittest.mock import AsyncMock, patch, MagicMock -from model_filemanager import download_model, validate_model_subdirectory, track_download_progress, create_model_path, check_file_exists, DownloadStatusType, DownloadModelStatus, validate_filename +from model_filemanager import download_model, track_download_progress, create_model_path, check_file_exists, DownloadStatusType, DownloadModelStatus, validate_filename +import folder_paths + +@pytest.fixture +def temp_dir(): + with tempfile.TemporaryDirectory() as tmpdirname: + yield tmpdirname class AsyncIteratorMock: """ @@ -42,7 +49,7 @@ class ContentMock: return AsyncIteratorMock(self.chunks) @pytest.mark.asyncio -async def test_download_model_success(): +async def test_download_model_success(temp_dir): mock_response = AsyncMock(spec=aiohttp.ClientResponse) mock_response.status = 200 mock_response.headers = {'Content-Length': '1000'} @@ -53,15 +60,13 @@ async def test_download_model_success(): mock_make_request = AsyncMock(return_value=mock_response) mock_progress_callback = AsyncMock() - # Mock file operations - mock_open = MagicMock() - mock_file = MagicMock() - mock_open.return_value.__enter__.return_value = mock_file time_values = itertools.count(0, 0.1) - with patch('model_filemanager.create_model_path', return_value=('models/checkpoints/model.sft', 'checkpoints/model.sft')), \ + fake_paths = {'checkpoints': ([temp_dir], folder_paths.supported_pt_extensions)} + + with patch('model_filemanager.create_model_path', return_value=('models/checkpoints/model.sft', 'model.sft')), \ patch('model_filemanager.check_file_exists', return_value=None), \ - patch('builtins.open', mock_open), \ + patch('folder_paths.folder_names_and_paths', fake_paths), \ patch('time.time', side_effect=time_values): # Simulate time passing result = await download_model( @@ -69,6 +74,7 @@ async def test_download_model_success(): 'model.sft', 'http://example.com/model.sft', 'checkpoints', + temp_dir, mock_progress_callback ) @@ -83,44 +89,48 @@ async def test_download_model_success(): # Check initial call mock_progress_callback.assert_any_call( - 'checkpoints/model.sft', + 'model.sft', DownloadModelStatus(DownloadStatusType.PENDING, 0, "Starting download of model.sft", False) ) # Check final call mock_progress_callback.assert_any_call( - 'checkpoints/model.sft', + 'model.sft', DownloadModelStatus(DownloadStatusType.COMPLETED, 100, "Successfully downloaded model.sft", False) ) - # Verify file writing - mock_file.write.assert_any_call(b'a' * 500) - mock_file.write.assert_any_call(b'b' * 300) - mock_file.write.assert_any_call(b'c' * 200) + mock_file_path = os.path.join(temp_dir, 'model.sft') + assert os.path.exists(mock_file_path) + with open(mock_file_path, 'rb') as mock_file: + assert mock_file.read() == b''.join(chunks) + os.remove(mock_file_path) # Verify request was made mock_make_request.assert_called_once_with('http://example.com/model.sft') @pytest.mark.asyncio -async def test_download_model_url_request_failure(): +async def test_download_model_url_request_failure(temp_dir): # Mock dependencies mock_response = AsyncMock(spec=ClientResponse) mock_response.status = 404 # Simulate a "Not Found" error mock_get = AsyncMock(return_value=mock_response) mock_progress_callback = AsyncMock() + + fake_paths = {'checkpoints': ([temp_dir], folder_paths.supported_pt_extensions)} # Mock the create_model_path function - with patch('model_filemanager.create_model_path', return_value=('/mock/path/model.safetensors', 'mock/path/model.safetensors')): - # Mock the check_file_exists function to return None (file doesn't exist) - with patch('model_filemanager.check_file_exists', return_value=None): - # Call the function - result = await download_model( - mock_get, - 'model.safetensors', - 'http://example.com/model.safetensors', - 'mock_directory', - mock_progress_callback - ) + with patch('model_filemanager.create_model_path', return_value='/mock/path/model.safetensors'), \ + patch('model_filemanager.check_file_exists', return_value=None), \ + patch('folder_paths.folder_names_and_paths', fake_paths): + # Call the function + result = await download_model( + mock_get, + 'model.safetensors', + 'http://example.com/model.safetensors', + 'checkpoints', + temp_dir, + mock_progress_callback + ) # Assert the expected behavior assert isinstance(result, DownloadModelStatus) @@ -130,7 +140,7 @@ async def test_download_model_url_request_failure(): # Check that progress_callback was called with the correct arguments mock_progress_callback.assert_any_call( - 'mock_directory/model.safetensors', + 'model.safetensors', DownloadModelStatus( status=DownloadStatusType.PENDING, progress_percentage=0, @@ -139,7 +149,7 @@ async def test_download_model_url_request_failure(): ) ) mock_progress_callback.assert_called_with( - 'mock_directory/model.safetensors', + 'model.safetensors', DownloadModelStatus( status=DownloadStatusType.ERROR, progress_percentage=0, @@ -153,98 +163,125 @@ async def test_download_model_url_request_failure(): @pytest.mark.asyncio async def test_download_model_invalid_model_subdirectory(): - mock_make_request = AsyncMock() mock_progress_callback = AsyncMock() - result = await download_model( mock_make_request, 'model.sft', 'http://example.com/model.sft', '../bad_path', + '../bad_path', mock_progress_callback ) # Assert the result assert isinstance(result, DownloadModelStatus) - assert result.message == 'Invalid model subdirectory' + assert result.message.startswith('Invalid or unrecognized model directory') assert result.status == 'error' assert result.already_existed is False +@pytest.mark.asyncio +async def test_download_model_invalid_folder_path(): + mock_make_request = AsyncMock() + mock_progress_callback = AsyncMock() + + result = await download_model( + mock_make_request, + 'model.sft', + 'http://example.com/model.sft', + 'checkpoints', + 'invalid_path', + mock_progress_callback + ) + + # Assert the result + assert isinstance(result, DownloadModelStatus) + assert result.message.startswith("Invalid folder path") + assert result.status == 'error' + assert result.already_existed is False -# For create_model_path function def test_create_model_path(tmp_path, monkeypatch): - mock_models_dir = tmp_path / "models" - monkeypatch.setattr('folder_paths.models_dir', str(mock_models_dir)) - - model_name = "test_model.sft" - model_directory = "test_dir" - - file_path, relative_path = create_model_path(model_name, model_directory, mock_models_dir) - - assert file_path == str(mock_models_dir / model_directory / model_name) - assert relative_path == f"{model_directory}/{model_name}" + model_name = "model.safetensors" + folder_path = os.path.join(tmp_path, "mock_dir") + + file_path = create_model_path(model_name, folder_path) + + assert file_path == os.path.join(folder_path, "model.safetensors") assert os.path.exists(os.path.dirname(file_path)) + with pytest.raises(Exception, match="Invalid model directory"): + create_model_path("../path_traversal.safetensors", folder_path) + + with pytest.raises(Exception, match="Invalid model directory"): + create_model_path("/etc/some_root_path", folder_path) + @pytest.mark.asyncio async def test_check_file_exists_when_file_exists(tmp_path): file_path = tmp_path / "existing_model.sft" file_path.touch() # Create an empty file - + mock_callback = AsyncMock() - - result = await check_file_exists(str(file_path), "existing_model.sft", mock_callback, "test/existing_model.sft") - + + result = await check_file_exists(str(file_path), "existing_model.sft", mock_callback) + assert result is not None assert result.status == "completed" assert result.message == "existing_model.sft already exists" assert result.already_existed is True - + mock_callback.assert_called_once_with( - "test/existing_model.sft", + "existing_model.sft", DownloadModelStatus(DownloadStatusType.COMPLETED, 100, "existing_model.sft already exists", already_existed=True) ) @pytest.mark.asyncio async def test_check_file_exists_when_file_does_not_exist(tmp_path): file_path = tmp_path / "non_existing_model.sft" - + mock_callback = AsyncMock() - - result = await check_file_exists(str(file_path), "non_existing_model.sft", mock_callback, "test/non_existing_model.sft") - + + result = await check_file_exists(str(file_path), "non_existing_model.sft", mock_callback) + assert result is None mock_callback.assert_not_called() @pytest.mark.asyncio -async def test_track_download_progress_no_content_length(): +async def test_track_download_progress_no_content_length(temp_dir): mock_response = AsyncMock(spec=aiohttp.ClientResponse) mock_response.headers = {} # No Content-Length header - mock_response.content.iter_chunked.return_value = AsyncIteratorMock([b'a' * 500, b'b' * 500]) + chunks = [b'a' * 500, b'b' * 500] + mock_response.content.iter_chunked.return_value = AsyncIteratorMock(chunks) mock_callback = AsyncMock() - mock_open = MagicMock(return_value=MagicMock()) - with patch('builtins.open', mock_open): - result = await track_download_progress( - mock_response, '/mock/path/model.sft', 'model.sft', - mock_callback, 'models/model.sft', interval=0.1 - ) + full_path = os.path.join(temp_dir, 'model.sft') + + result = await track_download_progress( + mock_response, full_path, 'model.sft', + mock_callback, interval=0.1 + ) assert result.status == "completed" + + assert os.path.exists(full_path) + with open(full_path, 'rb') as f: + assert f.read() == b''.join(chunks) + os.remove(full_path) + # Check that progress was reported even without knowing the total size mock_callback.assert_any_call( - 'models/model.sft', + 'model.sft', DownloadModelStatus(DownloadStatusType.IN_PROGRESS, 0, "Downloading model.sft", already_existed=False) ) @pytest.mark.asyncio -async def test_track_download_progress_interval(): +async def test_track_download_progress_interval(temp_dir): mock_response = AsyncMock(spec=aiohttp.ClientResponse) mock_response.headers = {'Content-Length': '1000'} - mock_response.content.iter_chunked.return_value = AsyncIteratorMock([b'a' * 100] * 10) + chunks = [b'a' * 100] * 10 + mock_response.content.iter_chunked.return_value = AsyncIteratorMock(chunks) mock_callback = AsyncMock() mock_open = MagicMock(return_value=MagicMock()) @@ -253,18 +290,18 @@ async def test_track_download_progress_interval(): mock_time = MagicMock() mock_time.side_effect = [i * 0.5 for i in range(30)] # This should be enough for 10 chunks - with patch('builtins.open', mock_open), \ - patch('time.time', mock_time): - await track_download_progress( - mock_response, '/mock/path/model.sft', 'model.sft', - mock_callback, 'models/model.sft', interval=1.0 - ) + full_path = os.path.join(temp_dir, 'model.sft') - # Print out the actual call count and the arguments of each call for debugging - print(f"mock_callback was called {mock_callback.call_count} times") - for i, call in enumerate(mock_callback.call_args_list): - args, kwargs = call - print(f"Call {i + 1}: {args[1].status}, Progress: {args[1].progress_percentage:.2f}%") + with patch('time.time', mock_time): + await track_download_progress( + mock_response, full_path, 'model.sft', + mock_callback, interval=1.0 + ) + + assert os.path.exists(full_path) + with open(full_path, 'rb') as f: + assert f.read() == b''.join(chunks) + os.remove(full_path) # Assert that progress was updated at least 3 times (start, at least one interval, and end) assert mock_callback.call_count >= 3, f"Expected at least 3 calls, but got {mock_callback.call_count}" @@ -279,27 +316,6 @@ async def test_track_download_progress_interval(): assert last_call[0][1].status == "completed" assert last_call[0][1].progress_percentage == 100 -def test_valid_subdirectory(): - assert validate_model_subdirectory("valid-model123") is True - -def test_subdirectory_too_long(): - assert validate_model_subdirectory("a" * 51) is False - -def test_subdirectory_with_double_dots(): - assert validate_model_subdirectory("model/../unsafe") is False - -def test_subdirectory_with_slash(): - assert validate_model_subdirectory("model/unsafe") is False - -def test_subdirectory_with_special_characters(): - assert validate_model_subdirectory("model@unsafe") is False - -def test_subdirectory_with_underscore_and_dash(): - assert validate_model_subdirectory("valid_model-name") is True - -def test_empty_subdirectory(): - assert validate_model_subdirectory("") is False - @pytest.mark.parametrize("filename, expected", [ ("valid_model.safetensors", True), ("valid_model.sft", True), diff --git a/web/assets/GraphView-BGt8GmeB.css b/web/assets/GraphView-BGt8GmeB.css new file mode 100644 index 00000000..bae07e60 --- /dev/null +++ b/web/assets/GraphView-BGt8GmeB.css @@ -0,0 +1,792 @@ + +.editable-text[data-v-54da6fc9] { + display: inline; +} +.editable-text input[data-v-54da6fc9] { + width: 100%; + box-sizing: border-box; +} + +.group-title-editor.node-title-editor[data-v-fc3f26e3] { + z-index: 9999; + padding: 0.25rem; +} +[data-v-fc3f26e3] .editable-text { + width: 100%; + height: 100%; +} +[data-v-fc3f26e3] .editable-text input { + width: 100%; + height: 100%; + /* Override the default font size */ + font-size: inherit; +} + +.side-bar-button-icon { + font-size: var(--sidebar-icon-size) !important; +} +.side-bar-button-selected .side-bar-button-icon { + font-size: var(--sidebar-icon-size) !important; + font-weight: bold; +} + +.side-bar-button[data-v-caa3ee9c] { + width: var(--sidebar-width); + height: var(--sidebar-width); + border-radius: 0; +} +.comfyui-body-left .side-bar-button.side-bar-button-selected[data-v-caa3ee9c], +.comfyui-body-left .side-bar-button.side-bar-button-selected[data-v-caa3ee9c]:hover { + border-left: 4px solid var(--p-button-text-primary-color); +} +.comfyui-body-right .side-bar-button.side-bar-button-selected[data-v-caa3ee9c], +.comfyui-body-right .side-bar-button.side-bar-button-selected[data-v-caa3ee9c]:hover { + border-right: 4px solid var(--p-button-text-primary-color); +} + +:root { + --sidebar-width: 64px; + --sidebar-icon-size: 1.5rem; +} +:root .small-sidebar { + --sidebar-width: 40px; + --sidebar-icon-size: 1rem; +} + +.side-tool-bar-container[data-v-4da64512] { + display: flex; + flex-direction: column; + align-items: center; + + pointer-events: auto; + + width: var(--sidebar-width); + height: 100%; + + background-color: var(--comfy-menu-bg); + color: var(--fg-color); +} +.side-tool-bar-end[data-v-4da64512] { + align-self: flex-end; + margin-top: auto; +} +.sidebar-content-container[data-v-4da64512] { + height: 100%; + overflow-y: auto; +} + +.p-splitter-gutter { + pointer-events: auto; +} +.gutter-hidden { + display: none !important; +} + +.side-bar-panel[data-v-b9df3042] { + background-color: var(--bg-color); + pointer-events: auto; +} +.splitter-overlay[data-v-b9df3042] { + width: 100%; + height: 100%; + position: absolute; + top: 0; + left: 0; + background-color: transparent; + pointer-events: none; + /* Set it the same as the ComfyUI menu */ + /* Note: Lite-graph DOM widgets have the same z-index as the node id, so + 999 should be sufficient to make sure splitter overlays on node's DOM + widgets */ + z-index: 999; + border: none; +} + +._content[data-v-e7b35fd9] { + + display: flex; + + flex-direction: column +} +._content[data-v-e7b35fd9] > :not([hidden]) ~ :not([hidden]) { + + --tw-space-y-reverse: 0; + + margin-top: calc(0.5rem * calc(1 - var(--tw-space-y-reverse))); + + margin-bottom: calc(0.5rem * var(--tw-space-y-reverse)) +} +._footer[data-v-e7b35fd9] { + + display: flex; + + flex-direction: column; + + align-items: flex-end; + + padding-top: 1rem +} + +[data-v-37f672ab] .highlight { + background-color: var(--p-primary-color); + color: var(--p-primary-contrast-color); + font-weight: bold; + border-radius: 0.25rem; + padding: 0rem 0.125rem; + margin: -0.125rem 0.125rem; +} + +.slot_row[data-v-ff07c900] { + padding: 2px; +} + +/* Original N-Sidebar styles */ +._sb_dot[data-v-ff07c900] { + width: 8px; + height: 8px; + border-radius: 50%; + background-color: grey; +} +.node_header[data-v-ff07c900] { + line-height: 1; + padding: 8px 13px 7px; + margin-bottom: 5px; + font-size: 15px; + text-wrap: nowrap; + overflow: hidden; + display: flex; + align-items: center; +} +.headdot[data-v-ff07c900] { + width: 10px; + height: 10px; + float: inline-start; + margin-right: 8px; +} +.IMAGE[data-v-ff07c900] { + background-color: #64b5f6; +} +.VAE[data-v-ff07c900] { + background-color: #ff6e6e; +} +.LATENT[data-v-ff07c900] { + background-color: #ff9cf9; +} +.MASK[data-v-ff07c900] { + background-color: #81c784; +} +.CONDITIONING[data-v-ff07c900] { + background-color: #ffa931; +} +.CLIP[data-v-ff07c900] { + background-color: #ffd500; +} +.MODEL[data-v-ff07c900] { + background-color: #b39ddb; +} +.CONTROL_NET[data-v-ff07c900] { + background-color: #a5d6a7; +} +._sb_node_preview[data-v-ff07c900] { + background-color: var(--comfy-menu-bg); + font-family: 'Open Sans', sans-serif; + font-size: small; + color: var(--descrip-text); + border: 1px solid var(--descrip-text); + min-width: 300px; + width: -moz-min-content; + width: min-content; + height: -moz-fit-content; + height: fit-content; + z-index: 9999; + border-radius: 12px; + overflow: hidden; + font-size: 12px; + padding-bottom: 10px; +} +._sb_node_preview ._sb_description[data-v-ff07c900] { + margin: 10px; + padding: 6px; + background: var(--border-color); + border-radius: 5px; + font-style: italic; + font-weight: 500; + font-size: 0.9rem; + word-break: break-word; +} +._sb_table[data-v-ff07c900] { + display: grid; + + grid-column-gap: 10px; + /* Spazio tra le colonne */ + width: 100%; + /* Imposta la larghezza della tabella al 100% del contenitore */ +} +._sb_row[data-v-ff07c900] { + display: grid; + grid-template-columns: 10px 1fr 1fr 1fr 10px; + grid-column-gap: 10px; + align-items: center; + padding-left: 9px; + padding-right: 9px; +} +._sb_row_string[data-v-ff07c900] { + grid-template-columns: 10px 1fr 1fr 10fr 1fr; +} +._sb_col[data-v-ff07c900] { + border: 0px solid #000; + display: flex; + align-items: flex-end; + flex-direction: row-reverse; + flex-wrap: nowrap; + align-content: flex-start; + justify-content: flex-end; +} +._sb_inherit[data-v-ff07c900] { + display: inherit; +} +._long_field[data-v-ff07c900] { + background: var(--bg-color); + border: 2px solid var(--border-color); + margin: 5px 5px 0 5px; + border-radius: 10px; + line-height: 1.7; + text-wrap: nowrap; +} +._sb_arrow[data-v-ff07c900] { + color: var(--fg-color); +} +._sb_preview_badge[data-v-ff07c900] { + text-align: center; + background: var(--comfy-input-bg); + font-weight: bold; + color: var(--error-text); +} + +.comfy-vue-node-search-container[data-v-2d409367] { + display: flex; + width: 100%; + min-width: 26rem; + align-items: center; + justify-content: center; +} +.comfy-vue-node-search-container[data-v-2d409367] * { + pointer-events: auto; +} +.comfy-vue-node-preview-container[data-v-2d409367] { + position: absolute; + left: -350px; + top: 50px; +} +.comfy-vue-node-search-box[data-v-2d409367] { + z-index: 10; + flex-grow: 1; +} +._filter-button[data-v-2d409367] { + z-index: 10; +} +._dialog[data-v-2d409367] { + min-width: 26rem; +} + +.invisible-dialog-root { + width: 60%; + min-width: 24rem; + max-width: 48rem; + border: 0 !important; + background-color: transparent !important; + margin-top: 25vh; + margin-left: 400px; +} +@media all and (max-width: 768px) { +.invisible-dialog-root { + margin-left: 0px; +} +} +.node-search-box-dialog-mask { + align-items: flex-start !important; +} + +.node-tooltip[data-v-0a4402f9] { + background: var(--comfy-input-bg); + border-radius: 5px; + box-shadow: 0 0 5px rgba(0, 0, 0, 0.4); + color: var(--input-text); + font-family: sans-serif; + left: 0; + max-width: 30vw; + padding: 4px 8px; + position: absolute; + top: 0; + transform: translate(5px, calc(-100% - 5px)); + white-space: pre-wrap; + z-index: 99999; +} + +.p-buttongroup-vertical[data-v-ce8bd6ac] { + display: flex; + flex-direction: column; + border-radius: var(--p-button-border-radius); + overflow: hidden; + border: 1px solid var(--p-panel-border-color); +} +.p-buttongroup-vertical .p-button[data-v-ce8bd6ac] { + margin: 0; + border-radius: 0; +} + +.comfy-image-wrap[data-v-9bc23daf] { + display: contents; +} +.comfy-image-blur[data-v-9bc23daf] { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + -o-object-fit: cover; + object-fit: cover; +} +.comfy-image-main[data-v-9bc23daf] { + width: 100%; + height: 100%; + -o-object-fit: cover; + object-fit: cover; + -o-object-position: center; + object-position: center; + z-index: 1; +} +.contain .comfy-image-wrap[data-v-9bc23daf] { + position: relative; + width: 100%; + height: 100%; +} +.contain .comfy-image-main[data-v-9bc23daf] { + -o-object-fit: contain; + object-fit: contain; + -webkit-backdrop-filter: blur(10px); + backdrop-filter: blur(10px); + position: absolute; +} +.broken-image-placeholder[data-v-9bc23daf] { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + width: 100%; + height: 100%; + margin: 2rem; +} +.broken-image-placeholder i[data-v-9bc23daf] { + font-size: 3rem; + margin-bottom: 0.5rem; +} + +.result-container[data-v-d9c060ae] { + width: 100%; + height: 100%; + aspect-ratio: 1 / 1; + overflow: hidden; + position: relative; + display: flex; + justify-content: center; + align-items: center; +} +.image-preview-mask[data-v-d9c060ae] { + position: absolute; + left: 50%; + top: 50%; + transform: translate(-50%, -50%); + display: flex; + align-items: center; + justify-content: center; + opacity: 0; + transition: opacity 0.3s ease; + z-index: 1; +} +.result-container:hover .image-preview-mask[data-v-d9c060ae] { + opacity: 1; +} + +.task-result-preview[data-v-d4c8a1fe] { + aspect-ratio: 1 / 1; + overflow: hidden; + display: flex; + justify-content: center; + align-items: center; + width: 100%; + height: 100%; +} +.task-result-preview i[data-v-d4c8a1fe], +.task-result-preview span[data-v-d4c8a1fe] { + font-size: 2rem; +} +.task-item[data-v-d4c8a1fe] { + display: flex; + flex-direction: column; + border-radius: 4px; + overflow: hidden; + position: relative; +} +.task-item-details[data-v-d4c8a1fe] { + position: absolute; + bottom: 0; + padding: 0.6rem; + display: flex; + justify-content: space-between; + align-items: center; + width: 100%; + z-index: 1; +} +.task-node-link[data-v-d4c8a1fe] { + padding: 2px; +} + +/* In dark mode, transparent background color for tags is not ideal for tags that +are floating on top of images. */ +.tag-wrapper[data-v-d4c8a1fe] { + background-color: var(--p-primary-contrast-color); + border-radius: 6px; + display: inline-flex; +} +.node-name-tag[data-v-d4c8a1fe] { + word-break: break-all; +} +.status-tag-group[data-v-d4c8a1fe] { + display: flex; + flex-direction: column; +} +.progress-preview-img[data-v-d4c8a1fe] { + width: 100%; + height: 100%; + -o-object-fit: cover; + object-fit: cover; + -o-object-position: center; + object-position: center; +} + +/* PrimeVue's galleria teleports the fullscreen gallery out of subtree so we +cannot use scoped style here. */ +img.galleria-image { + max-width: 100vw; + max-height: 100vh; + -o-object-fit: contain; + object-fit: contain; +} +.p-galleria-close-button { + /* Set z-index so the close button doesn't get hidden behind the image when image is large */ + z-index: 1; +} + +.comfy-vue-side-bar-container[data-v-1b0a8fe3] { + display: flex; + flex-direction: column; + height: 100%; + overflow: hidden; +} +.comfy-vue-side-bar-header[data-v-1b0a8fe3] { + flex-shrink: 0; + border-left: none; + border-right: none; + border-top: none; + border-radius: 0; + padding: 0.25rem 1rem; + min-height: 2.5rem; +} +.comfy-vue-side-bar-header-span[data-v-1b0a8fe3] { + font-size: small; +} +.comfy-vue-side-bar-body[data-v-1b0a8fe3] { + flex-grow: 1; + overflow: auto; + scrollbar-width: thin; + scrollbar-color: transparent transparent; +} +.comfy-vue-side-bar-body[data-v-1b0a8fe3]::-webkit-scrollbar { + width: 1px; +} +.comfy-vue-side-bar-body[data-v-1b0a8fe3]::-webkit-scrollbar-thumb { + background-color: transparent; +} + +.scroll-container[data-v-08fa89b1] { + height: 100%; + overflow-y: auto; +} +.queue-grid[data-v-08fa89b1] { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); + padding: 0.5rem; + gap: 0.5rem; +} + +.tree-node[data-v-633e27ab] { + width: 100%; + display: flex; + align-items: center; + justify-content: space-between; +} +.leaf-count-badge[data-v-633e27ab] { + margin-left: 0.5rem; +} +.node-content[data-v-633e27ab] { + display: flex; + align-items: center; + flex-grow: 1; +} +.leaf-label[data-v-633e27ab] { + margin-left: 0.5rem; +} +[data-v-633e27ab] .editable-text span { + word-break: break-all; +} + +[data-v-bd7bae90] .tree-explorer-node-label { + width: 100%; + display: flex; + align-items: center; + margin-left: var(--p-tree-node-gap); + flex-grow: 1; +} + +/* + * The following styles are necessary to avoid layout shift when dragging nodes over folders. + * By setting the position to relative on the parent and using an absolutely positioned pseudo-element, + * we can create a visual indicator for the drop target without affecting the layout of other elements. + */ +[data-v-bd7bae90] .p-tree-node-content:has(.tree-folder) { + position: relative; +} +[data-v-bd7bae90] .p-tree-node-content:has(.tree-folder.can-drop)::after { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + border: 1px solid var(--p-content-color); + pointer-events: none; +} + +.node-lib-node-container[data-v-90dfee08] { + height: 100%; + width: 100% +} + +.p-selectbutton .p-button[data-v-91077f2a] { + padding: 0.5rem; +} +.p-selectbutton .p-button .pi[data-v-91077f2a] { + font-size: 1.5rem; +} +.field[data-v-91077f2a] { + display: flex; + flex-direction: column; + gap: 0.5rem; +} +.color-picker-container[data-v-91077f2a] { + display: flex; + align-items: center; + gap: 0.5rem; +} + +.node-lib-filter-popup { + margin-left: -13px; +} + +[data-v-f6a7371a] .comfy-vue-side-bar-body { + background: var(--p-tree-background); +} +[data-v-f6a7371a] .node-lib-bookmark-tree-explorer { + padding-bottom: 2px; +} +[data-v-f6a7371a] .p-divider { + margin: var(--comfy-tree-explorer-item-padding) 0px; +} + +.model_preview[data-v-32e6c4d9] { + background-color: var(--comfy-menu-bg); + font-family: 'Open Sans', sans-serif; + color: var(--descrip-text); + border: 1px solid var(--descrip-text); + min-width: 300px; + max-width: 500px; + width: -moz-fit-content; + width: fit-content; + height: -moz-fit-content; + height: fit-content; + z-index: 9999; + border-radius: 12px; + overflow: hidden; + font-size: 12px; + padding: 10px; +} +.model_preview_image[data-v-32e6c4d9] { + margin: auto; + width: -moz-fit-content; + width: fit-content; +} +.model_preview_image img[data-v-32e6c4d9] { + max-width: 100%; + max-height: 150px; + -o-object-fit: contain; + object-fit: contain; +} +.model_preview_title[data-v-32e6c4d9] { + font-weight: bold; + text-align: center; + font-size: 14px; +} +.model_preview_top_container[data-v-32e6c4d9] { + text-align: center; + line-height: 0.5; +} +.model_preview_filename[data-v-32e6c4d9], +.model_preview_author[data-v-32e6c4d9], +.model_preview_architecture[data-v-32e6c4d9] { + display: inline-block; + text-align: center; + margin: 5px; + font-size: 10px; +} +.model_preview_prefix[data-v-32e6c4d9] { + font-weight: bold; +} + +.model-lib-model-icon-container[data-v-70b69131] { + display: inline-block; + position: relative; + left: 0; + height: 1.5rem; + vertical-align: top; + width: 0px; +} +.model-lib-model-icon[data-v-70b69131] { + background-size: cover; + background-position: center; + display: inline-block; + position: relative; + left: -2.5rem; + height: 2rem; + width: 2rem; + vertical-align: top; +} + +.pi-fake-spacer { + height: 1px; + width: 16px; +} + +[data-v-74b01bce] .comfy-vue-side-bar-body { + background: var(--p-tree-background); +} + +[data-v-d2d58252] .comfy-vue-side-bar-body { + background: var(--p-tree-background); +} + +[data-v-84e785b8] .p-togglebutton::before { + display: none +} +[data-v-84e785b8] .p-togglebutton { + position: relative; + flex-shrink: 0; + border-radius: 0px; + background-color: transparent; + padding-left: 0.5rem; + padding-right: 0.5rem +} +[data-v-84e785b8] .p-togglebutton.p-togglebutton-checked { + border-bottom-width: 2px; + border-bottom-color: var(--p-button-text-primary-color) +} +[data-v-84e785b8] .p-togglebutton-checked .close-button,[data-v-84e785b8] .p-togglebutton:hover .close-button { + visibility: visible +} +.status-indicator[data-v-84e785b8] { + position: absolute; + font-weight: 700; + font-size: 1.5rem; + top: 50%; + left: 50%; + transform: translate(-50%, -50%) +} +[data-v-84e785b8] .p-togglebutton:hover .status-indicator { + display: none +} +[data-v-84e785b8] .p-togglebutton .close-button { + visibility: hidden +} + +.top-menubar[data-v-2ec1b620] .p-menubar-item-link svg { + display: none; +} +[data-v-2ec1b620] .p-menubar-submenu.dropdown-direction-up { + top: auto; + bottom: 100%; + flex-direction: column-reverse; +} +.keybinding-tag[data-v-2ec1b620] { + background: var(--p-content-hover-background); + border-color: var(--p-content-border-color); + border-style: solid; +} + +[data-v-713442be] .p-inputtext { + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} + +.comfyui-queue-button[data-v-fcd3efcd] .p-splitbutton-dropdown { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} + +.actionbar[data-v-bc6c78dd] { + pointer-events: all; + position: fixed; + z-index: 1000; +} +.actionbar.is-docked[data-v-bc6c78dd] { + position: static; + border-style: none; + background-color: transparent; + padding: 0px; +} +.actionbar.is-dragging[data-v-bc6c78dd] { + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} +[data-v-bc6c78dd] .p-panel-content { + padding: 0.25rem; +} +[data-v-bc6c78dd] .p-panel-header { + display: none; +} + +.comfyui-menu[data-v-b13fdc92] { + width: 100vw; + background: var(--comfy-menu-bg); + color: var(--fg-color); + font-family: Arial, Helvetica, sans-serif; + font-size: 0.8em; + box-sizing: border-box; + z-index: 1000; + order: 0; + grid-column: 1/-1; + max-height: 90vh; +} +.comfyui-menu.dropzone[data-v-b13fdc92] { + background: var(--p-highlight-background); +} +.comfyui-menu.dropzone-active[data-v-b13fdc92] { + background: var(--p-highlight-background-focus); +} +.comfyui-logo[data-v-b13fdc92] { + font-size: 1.2em; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; + cursor: default; +} diff --git a/web/assets/GraphView-CVV2XJjS.js b/web/assets/GraphView-CVV2XJjS.js new file mode 100644 index 00000000..1d43b2f6 --- /dev/null +++ b/web/assets/GraphView-CVV2XJjS.js @@ -0,0 +1,17465 @@ +var __defProp = Object.defineProperty; +var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); +import { d as defineComponent, r as ref, w as watch, n as nextTick, o as openBlock, c as createElementBlock, t as toDisplayString, a as withDirectives, b as createBlock, e as withKeys, f as withModifiers, u as unref, s as script$m, p as pushScopeId, g as popScopeId, _ as _export_sfc, h as useSettingStore, i as useTitleEditorStore, j as useCanvasStore, L as LGraphGroup, k as app, l as LGraphNode, m as onMounted, q as onUnmounted, v as createVNode, x as normalizeStyle, y as createCommentVNode, z as LiteGraph, B as BaseStyle, A as script$n, C as resolveComponent, D as mergeProps, E as renderSlot, F as computed, G as resolveDirective, H as withCtx, I as createBaseVNode, J as normalizeClass, K as script$o, M as useDialogStore, S as SettingDialogHeader, N as SettingDialogContent, O as useWorkspaceStore, P as onBeforeUnmount, Q as Fragment, R as renderList, T as Teleport, U as resolveDynamicComponent, V as script$p, W as getWidth, X as getHeight, Y as getOuterWidth, Z as getOuterHeight, $ as getVNodeProp, a0 as isArray, a1 as vShow, a2 as isNotEmpty, a3 as UniqueComponentId, a4 as ZIndex, a5 as resolveFieldData, a6 as focus, a7 as OverlayEventBus, a8 as isEmpty, a9 as addStyle, aa as relativePosition, ab as absolutePosition, ac as ConnectedOverlayScrollHandler, ad as isTouchDevice, ae as equals, af as findLastIndex, ag as findSingle, ah as script$q, ai as script$r, aj as script$s, ak as script$t, al as script$u, am as Ripple, an as Transition, ao as createSlots, ap as createTextVNode, aq as useNodeDefStore, ar as script$v, as as defineStore, at as createDummyFolderNodeDef, au as _, av as buildNodeDefTree, aw as useNodeFrequencyStore, ax as highlightQuery, ay as script$w, az as formatNumberWithSuffix, aA as NodeSourceType, aB as ComfyNodeDefImpl, aC as useI18n, aD as script$x, aE as SearchFilterChip, aF as watchEffect, aG as toRaw, aH as LinkReleaseTriggerAction, aI as commonjsGlobal, aJ as getDefaultExportFromCjs, aK as markRaw, aL as useCommandStore, aM as LGraph, aN as LLink, aO as DragAndScale, aP as LGraphCanvas, aQ as ContextMenu, aR as LGraphBadge, aS as ComfyModelDef, aT as useKeybindingStore, aU as ConfirmationEventBus, aV as getOffset, aW as $dt, aX as addClass, aY as FocusTrap, aZ as resolve, a_ as nestedPosition, a$ as script$y, b0 as isPrintableCharacter, b1 as getHiddenElementOuterWidth, b2 as getHiddenElementOuterHeight, b3 as getViewport, b4 as api, b5 as TaskItemDisplayStatus, b6 as script$z, b7 as find, b8 as getAttribute, b9 as script$A, ba as script$B, bb as removeClass, bc as setAttribute, bd as localeComparator, be as sort, bf as script$C, bg as unblockBodyScroll, bh as blockBodyScroll, bi as useConfirm, bj as useToast, bk as useQueueStore, bl as useInfiniteScroll, bm as useResizeObserver, bn as script$D, bo as NoResultsPlaceholder, bp as isClient, bq as script$E, br as script$F, bs as script$G, bt as script$H, bu as script$I, bv as script$J, bw as inject, bx as useErrorHandling, by as mergeModels, bz as useModel, bA as provide, bB as script$K, bC as findNodeByKey, bD as sortedTree, bE as SearchBox, bF as useModelStore, bG as buildTree, bH as toRef, bI as script$L, bJ as script$M, bK as script$N, bL as normalizeProps, bM as ToastEventBus, bN as TransitionGroup, bO as useToastStore, bP as useExecutionStore, bQ as useWorkflowStore, bR as useTitle, bS as useWorkflowBookmarkStore, bT as script$O, bU as script$P, bV as guardReactiveProps, bW as useMenuItemStore, bX as script$Q, bY as useQueueSettingsStore, bZ as storeToRefs, b_ as isRef, b$ as script$R, c0 as useQueuePendingTaskCountStore, c1 as useLocalStorage, c2 as useDraggable, c3 as watchDebounced, c4 as useEventListener, c5 as useElementBounding, c6 as lodashExports, c7 as useEventBus, c8 as i18n } from "./index-DGAbdBYF.js"; +import { g as getColorPalette, d as defaultColorPalette } from "./colorPalette-D5oi2-2V.js"; +const _withScopeId$l = /* @__PURE__ */ __name((n) => (pushScopeId("data-v-54da6fc9"), n = n(), popScopeId(), n), "_withScopeId$l"); +const _hoisted_1$F = { class: "editable-text" }; +const _hoisted_2$v = { key: 0 }; +const _sfc_main$I = /* @__PURE__ */ defineComponent({ + __name: "EditableText", + props: { + modelValue: {}, + isEditing: { type: Boolean, default: false } + }, + emits: ["update:modelValue", "edit"], + setup(__props, { emit: __emit }) { + const props = __props; + const emit = __emit; + const inputValue2 = ref(props.modelValue); + const isEditingFinished = ref(false); + const inputRef = ref(null); + const finishEditing = /* @__PURE__ */ __name(() => { + if (isEditingFinished.value) { + return; + } + isEditingFinished.value = true; + emit("edit", inputValue2.value); + }, "finishEditing"); + watch( + () => props.isEditing, + (newVal) => { + if (newVal) { + inputValue2.value = props.modelValue; + isEditingFinished.value = false; + nextTick(() => { + if (!inputRef.value) return; + const fileName = inputValue2.value.includes(".") ? inputValue2.value.split(".").slice(0, -1).join(".") : inputValue2.value; + const start2 = 0; + const end = fileName.length; + const inputElement = inputRef.value.$el; + inputElement.setSelectionRange?.(start2, end); + }); + } + }, + { immediate: true } + ); + const vFocus = { + mounted: /* @__PURE__ */ __name((el) => el.focus(), "mounted") + }; + return (_ctx, _cache) => { + return openBlock(), createElementBlock("div", _hoisted_1$F, [ + !props.isEditing ? (openBlock(), createElementBlock("span", _hoisted_2$v, toDisplayString(_ctx.modelValue), 1)) : withDirectives((openBlock(), createBlock(unref(script$m), { + key: 1, + type: "text", + size: "small", + fluid: "", + modelValue: inputValue2.value, + "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => inputValue2.value = $event), + ref_key: "inputRef", + ref: inputRef, + onKeyup: withKeys(finishEditing, ["enter"]), + onClick: _cache[1] || (_cache[1] = withModifiers(() => { + }, ["stop"])), + pt: { + root: { + onBlur: finishEditing + } + } + }, null, 8, ["modelValue", "pt"])), [ + [vFocus] + ]) + ]); + }; + } +}); +const EditableText = /* @__PURE__ */ _export_sfc(_sfc_main$I, [["__scopeId", "data-v-54da6fc9"]]); +const _sfc_main$H = /* @__PURE__ */ defineComponent({ + __name: "TitleEditor", + setup(__props) { + const settingStore = useSettingStore(); + const showInput = ref(false); + const editedTitle = ref(""); + const inputStyle = ref({ + position: "fixed", + left: "0px", + top: "0px", + width: "200px", + height: "20px", + fontSize: "12px" + }); + const titleEditorStore = useTitleEditorStore(); + const canvasStore = useCanvasStore(); + const previousCanvasDraggable = ref(true); + const onEdit = /* @__PURE__ */ __name((newValue) => { + if (titleEditorStore.titleEditorTarget && newValue.trim() !== "") { + titleEditorStore.titleEditorTarget.title = newValue.trim(); + app.graph.setDirtyCanvas(true, true); + } + showInput.value = false; + titleEditorStore.titleEditorTarget = null; + canvasStore.canvas.allow_dragcanvas = previousCanvasDraggable.value; + }, "onEdit"); + watch( + () => titleEditorStore.titleEditorTarget, + (target) => { + if (target === null) { + return; + } + editedTitle.value = target.title; + showInput.value = true; + previousCanvasDraggable.value = canvasStore.canvas.allow_dragcanvas; + canvasStore.canvas.allow_dragcanvas = false; + if (target instanceof LGraphGroup) { + const group = target; + const [x, y] = group.pos; + const [w, h] = group.size; + const [left, top] = app.canvasPosToClientPos([x, y]); + inputStyle.value.left = `${left}px`; + inputStyle.value.top = `${top}px`; + const width = w * app.canvas.ds.scale; + const height = group.titleHeight * app.canvas.ds.scale; + inputStyle.value.width = `${width}px`; + inputStyle.value.height = `${height}px`; + const fontSize = group.font_size * app.canvas.ds.scale; + inputStyle.value.fontSize = `${fontSize}px`; + } else if (target instanceof LGraphNode) { + const node2 = target; + const [x, y] = node2.getBounding(); + const canvasWidth = node2.width; + const canvasHeight = LiteGraph.NODE_TITLE_HEIGHT; + const [left, top] = app.canvasPosToClientPos([x, y]); + inputStyle.value.left = `${left}px`; + inputStyle.value.top = `${top}px`; + const width = canvasWidth * app.canvas.ds.scale; + const height = canvasHeight * app.canvas.ds.scale; + inputStyle.value.width = `${width}px`; + inputStyle.value.height = `${height}px`; + const fontSize = 12 * app.canvas.ds.scale; + inputStyle.value.fontSize = `${fontSize}px`; + } + } + ); + const canvasEventHandler = /* @__PURE__ */ __name((event) => { + if (!settingStore.get("Comfy.Group.DoubleClickTitleToEdit")) { + return; + } + if (event.detail.subType === "group-double-click") { + const group = event.detail.group; + const [x, y] = group.pos; + const e = event.detail.originalEvent; + const relativeY = e.canvasY - y; + if (relativeY > group.titleHeight) { + return; + } + titleEditorStore.titleEditorTarget = group; + } + }, "canvasEventHandler"); + const extension = { + name: "Comfy.NodeTitleEditor", + nodeCreated(node2) { + const originalCallback = node2.onNodeTitleDblClick; + node2.onNodeTitleDblClick = function(e, ...args) { + if (!settingStore.get("Comfy.Node.DoubleClickTitleToEdit")) { + return; + } + titleEditorStore.titleEditorTarget = this; + if (typeof originalCallback === "function") { + originalCallback.call(this, e, ...args); + } + }; + } + }; + onMounted(() => { + document.addEventListener("litegraph:canvas", canvasEventHandler); + app.registerExtension(extension); + }); + onUnmounted(() => { + document.removeEventListener("litegraph:canvas", canvasEventHandler); + }); + return (_ctx, _cache) => { + return showInput.value ? (openBlock(), createElementBlock("div", { + key: 0, + class: "group-title-editor node-title-editor", + style: normalizeStyle(inputStyle.value) + }, [ + createVNode(EditableText, { + isEditing: showInput.value, + modelValue: editedTitle.value, + onEdit + }, null, 8, ["isEditing", "modelValue"]) + ], 4)) : createCommentVNode("", true); + }; + } +}); +const TitleEditor = /* @__PURE__ */ _export_sfc(_sfc_main$H, [["__scopeId", "data-v-fc3f26e3"]]); +var theme$h = /* @__PURE__ */ __name(function theme(_ref) { + var dt = _ref.dt; + return "\n.p-overlaybadge {\n position: relative;\n}\n\n.p-overlaybadge .p-badge {\n position: absolute;\n top: 0;\n right: 0;\n transform: translate(50%, -50%);\n transform-origin: 100% 0;\n margin: 0;\n outline-width: ".concat(dt("overlaybadge.outline.width"), ";\n outline-style: solid;\n outline-color: ").concat(dt("overlaybadge.outline.color"), ";\n}\n"); +}, "theme"); +var classes$i = { + root: "p-overlaybadge" +}; +var OverlayBadgeStyle = BaseStyle.extend({ + name: "overlaybadge", + theme: theme$h, + classes: classes$i +}); +var script$1$i = { + name: "OverlayBadge", + "extends": script$n, + style: OverlayBadgeStyle, + provide: /* @__PURE__ */ __name(function provide2() { + return { + $pcOverlayBadge: this, + $parentInstance: this + }; + }, "provide") +}; +var script$l = { + name: "OverlayBadge", + "extends": script$1$i, + inheritAttrs: false, + components: { + Badge: script$n + } +}; +function render$m(_ctx, _cache, $props, $setup, $data, $options) { + var _component_Badge = resolveComponent("Badge"); + return openBlock(), createElementBlock("div", mergeProps({ + "class": _ctx.cx("root") + }, _ctx.ptmi("root")), [renderSlot(_ctx.$slots, "default"), createVNode(_component_Badge, mergeProps(_ctx.$props, { + pt: _ctx.ptm("pcBadge") + }), null, 16, ["pt"])], 16); +} +__name(render$m, "render$m"); +script$l.render = render$m; +const _sfc_main$G = /* @__PURE__ */ defineComponent({ + __name: "SidebarIcon", + props: { + icon: String, + selected: Boolean, + tooltip: { + type: String, + default: "" + }, + class: { + type: String, + default: "" + }, + iconBadge: { + type: [String, Function], + default: "" + } + }, + emits: ["click"], + setup(__props, { emit: __emit }) { + const props = __props; + const emit = __emit; + const overlayValue = computed( + () => typeof props.iconBadge === "function" ? props.iconBadge() || "" : props.iconBadge + ); + const shouldShowBadge = computed(() => !!overlayValue.value); + return (_ctx, _cache) => { + const _directive_tooltip = resolveDirective("tooltip"); + return withDirectives((openBlock(), createBlock(unref(script$o), { + class: normalizeClass(props.class), + text: "", + pt: { + root: { + class: `side-bar-button ${props.selected ? "p-button-primary side-bar-button-selected" : "p-button-secondary"}`, + "aria-label": props.tooltip + } + }, + onClick: _cache[0] || (_cache[0] = ($event) => emit("click", $event)) + }, { + icon: withCtx(() => [ + shouldShowBadge.value ? (openBlock(), createBlock(unref(script$l), { + key: 0, + value: overlayValue.value + }, { + default: withCtx(() => [ + createBaseVNode("i", { + class: normalizeClass(props.icon + " side-bar-button-icon") + }, null, 2) + ]), + _: 1 + }, 8, ["value"])) : (openBlock(), createElementBlock("i", { + key: 1, + class: normalizeClass(props.icon + " side-bar-button-icon") + }, null, 2)) + ]), + _: 1 + }, 8, ["class", "pt"])), [ + [_directive_tooltip, { value: props.tooltip, showDelay: 300, hideDelay: 300 }] + ]); + }; + } +}); +const SidebarIcon = /* @__PURE__ */ _export_sfc(_sfc_main$G, [["__scopeId", "data-v-caa3ee9c"]]); +const _sfc_main$F = /* @__PURE__ */ defineComponent({ + __name: "SidebarThemeToggleIcon", + setup(__props) { + const previousDarkTheme = ref("dark"); + const currentTheme = computed(() => useSettingStore().get("Comfy.ColorPalette")); + const isDarkMode = computed(() => currentTheme.value !== "light"); + const icon = computed(() => isDarkMode.value ? "pi pi-moon" : "pi pi-sun"); + const toggleTheme = /* @__PURE__ */ __name(() => { + if (isDarkMode.value) { + previousDarkTheme.value = currentTheme.value; + useSettingStore().set("Comfy.ColorPalette", "light"); + } else { + useSettingStore().set("Comfy.ColorPalette", previousDarkTheme.value); + } + }, "toggleTheme"); + return (_ctx, _cache) => { + return openBlock(), createBlock(SidebarIcon, { + icon: icon.value, + onClick: toggleTheme, + tooltip: _ctx.$t("sideToolbar.themeToggle"), + class: "comfy-vue-theme-toggle" + }, null, 8, ["icon", "tooltip"]); + }; + } +}); +const _sfc_main$E = /* @__PURE__ */ defineComponent({ + __name: "SidebarSettingsToggleIcon", + setup(__props) { + const dialogStore = useDialogStore(); + const showSetting = /* @__PURE__ */ __name(() => { + dialogStore.showDialog({ + headerComponent: SettingDialogHeader, + component: SettingDialogContent + }); + }, "showSetting"); + return (_ctx, _cache) => { + return openBlock(), createBlock(SidebarIcon, { + icon: "pi pi-cog", + class: "comfy-settings-btn", + onClick: showSetting, + tooltip: _ctx.$t("settings") + }, null, 8, ["tooltip"]); + }; + } +}); +const _withScopeId$k = /* @__PURE__ */ __name((n) => (pushScopeId("data-v-4da64512"), n = n(), popScopeId(), n), "_withScopeId$k"); +const _hoisted_1$E = { class: "side-tool-bar-end" }; +const _hoisted_2$u = { + key: 0, + class: "sidebar-content-container" +}; +const _sfc_main$D = /* @__PURE__ */ defineComponent({ + __name: "SideToolbar", + setup(__props) { + const workspaceStore = useWorkspaceStore(); + const settingStore = useSettingStore(); + const teleportTarget = computed( + () => settingStore.get("Comfy.Sidebar.Location") === "left" ? ".comfyui-body-left" : ".comfyui-body-right" + ); + const isSmall = computed( + () => settingStore.get("Comfy.Sidebar.Size") === "small" + ); + const tabs = computed(() => workspaceStore.getSidebarTabs()); + const selectedTab = computed(() => workspaceStore.sidebarTab.activeSidebarTab); + const mountCustomTab = /* @__PURE__ */ __name((tab, el) => { + tab.render(el); + }, "mountCustomTab"); + const onTabClick = /* @__PURE__ */ __name((item4) => { + workspaceStore.sidebarTab.toggleSidebarTab(item4.id); + }, "onTabClick"); + onBeforeUnmount(() => { + tabs.value.forEach((tab) => { + if (tab.type === "custom" && tab.destroy) { + tab.destroy(); + } + }); + }); + return (_ctx, _cache) => { + return openBlock(), createElementBlock(Fragment, null, [ + (openBlock(), createBlock(Teleport, { to: teleportTarget.value }, [ + createBaseVNode("nav", { + class: normalizeClass("side-tool-bar-container" + (isSmall.value ? " small-sidebar" : "")) + }, [ + (openBlock(true), createElementBlock(Fragment, null, renderList(tabs.value, (tab) => { + return openBlock(), createBlock(SidebarIcon, { + key: tab.id, + icon: tab.icon, + iconBadge: tab.iconBadge, + tooltip: tab.tooltip, + selected: tab.id === selectedTab.value?.id, + class: normalizeClass(tab.id + "-tab-button"), + onClick: /* @__PURE__ */ __name(($event) => onTabClick(tab), "onClick") + }, null, 8, ["icon", "iconBadge", "tooltip", "selected", "class", "onClick"]); + }), 128)), + createBaseVNode("div", _hoisted_1$E, [ + createVNode(_sfc_main$F), + createVNode(_sfc_main$E) + ]) + ], 2) + ], 8, ["to"])), + selectedTab.value ? (openBlock(), createElementBlock("div", _hoisted_2$u, [ + selectedTab.value.type === "vue" ? (openBlock(), createBlock(resolveDynamicComponent(selectedTab.value.component), { key: 0 })) : (openBlock(), createElementBlock("div", { + key: 1, + ref: /* @__PURE__ */ __name((el) => { + if (el) + mountCustomTab( + selectedTab.value, + el + ); + }, "ref") + }, null, 512)) + ])) : createCommentVNode("", true) + ], 64); + }; + } +}); +const SideToolbar = /* @__PURE__ */ _export_sfc(_sfc_main$D, [["__scopeId", "data-v-4da64512"]]); +var theme$g = /* @__PURE__ */ __name(function theme2(_ref) { + var dt = _ref.dt; + return "\n.p-splitter {\n display: flex;\n flex-wrap: nowrap;\n border: 1px solid ".concat(dt("splitter.border.color"), ";\n background: ").concat(dt("splitter.background"), ";\n border-radius: ").concat(dt("border.radius.md"), ";\n color: ").concat(dt("splitter.color"), ";\n}\n\n.p-splitter-vertical {\n flex-direction: column;\n}\n\n.p-splitter-gutter {\n flex-grow: 0;\n flex-shrink: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 1;\n background: ").concat(dt("splitter.gutter.background"), ";\n}\n\n.p-splitter-gutter-handle {\n border-radius: ").concat(dt("splitter.handle.border.radius"), ";\n background: ").concat(dt("splitter.handle.background"), ";\n transition: outline-color ").concat(dt("splitter.transition.duration"), ", box-shadow ").concat(dt("splitter.transition.duration"), ";\n outline-color: transparent;\n}\n\n.p-splitter-gutter-handle:focus-visible {\n box-shadow: ").concat(dt("splitter.handle.focus.ring.shadow"), ";\n outline: ").concat(dt("splitter.handle.focus.ring.width"), " ").concat(dt("splitter.handle.focus.ring.style"), " ").concat(dt("splitter.handle.focus.ring.color"), ";\n outline-offset: ").concat(dt("splitter.handle.focus.ring.offset"), ";\n}\n\n.p-splitter-horizontal.p-splitter-resizing {\n cursor: col-resize;\n user-select: none;\n}\n\n.p-splitter-vertical.p-splitter-resizing {\n cursor: row-resize;\n user-select: none;\n}\n\n.p-splitter-horizontal > .p-splitter-gutter > .p-splitter-gutter-handle {\n height: ").concat(dt("splitter.handle.size"), ";\n width: 100%;\n}\n\n.p-splitter-vertical > .p-splitter-gutter > .p-splitter-gutter-handle {\n width: ").concat(dt("splitter.handle.size"), ";\n height: 100%;\n}\n\n.p-splitter-horizontal > .p-splitter-gutter {\n cursor: col-resize;\n}\n\n.p-splitter-vertical > .p-splitter-gutter {\n cursor: row-resize;\n}\n\n.p-splitterpanel {\n flex-grow: 1;\n overflow: hidden;\n}\n\n.p-splitterpanel-nested {\n display: flex;\n}\n\n.p-splitterpanel .p-splitter {\n flex-grow: 1;\n border: 0 none;\n}\n"); +}, "theme"); +var classes$h = { + root: /* @__PURE__ */ __name(function root(_ref2) { + var props = _ref2.props; + return ["p-splitter p-component", "p-splitter-" + props.layout]; + }, "root"), + gutter: "p-splitter-gutter", + gutterHandle: "p-splitter-gutter-handle" +}; +var inlineStyles$4 = { + root: /* @__PURE__ */ __name(function root2(_ref3) { + var props = _ref3.props; + return [{ + display: "flex", + "flex-wrap": "nowrap" + }, props.layout === "vertical" ? { + "flex-direction": "column" + } : ""]; + }, "root") +}; +var SplitterStyle = BaseStyle.extend({ + name: "splitter", + theme: theme$g, + classes: classes$h, + inlineStyles: inlineStyles$4 +}); +var script$1$h = { + name: "BaseSplitter", + "extends": script$p, + props: { + layout: { + type: String, + "default": "horizontal" + }, + gutterSize: { + type: Number, + "default": 4 + }, + stateKey: { + type: String, + "default": null + }, + stateStorage: { + type: String, + "default": "session" + }, + step: { + type: Number, + "default": 5 + } + }, + style: SplitterStyle, + provide: /* @__PURE__ */ __name(function provide3() { + return { + $pcSplitter: this, + $parentInstance: this + }; + }, "provide") +}; +function _toConsumableArray$7(r) { + return _arrayWithoutHoles$7(r) || _iterableToArray$7(r) || _unsupportedIterableToArray$9(r) || _nonIterableSpread$7(); +} +__name(_toConsumableArray$7, "_toConsumableArray$7"); +function _nonIterableSpread$7() { + throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); +} +__name(_nonIterableSpread$7, "_nonIterableSpread$7"); +function _unsupportedIterableToArray$9(r, a) { + if (r) { + if ("string" == typeof r) return _arrayLikeToArray$9(r, a); + var t = {}.toString.call(r).slice(8, -1); + return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray$9(r, a) : void 0; + } +} +__name(_unsupportedIterableToArray$9, "_unsupportedIterableToArray$9"); +function _iterableToArray$7(r) { + if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); +} +__name(_iterableToArray$7, "_iterableToArray$7"); +function _arrayWithoutHoles$7(r) { + if (Array.isArray(r)) return _arrayLikeToArray$9(r); +} +__name(_arrayWithoutHoles$7, "_arrayWithoutHoles$7"); +function _arrayLikeToArray$9(r, a) { + (null == a || a > r.length) && (a = r.length); + for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; + return n; +} +__name(_arrayLikeToArray$9, "_arrayLikeToArray$9"); +var script$k = { + name: "Splitter", + "extends": script$1$h, + inheritAttrs: false, + emits: ["resizestart", "resizeend", "resize"], + dragging: false, + mouseMoveListener: null, + mouseUpListener: null, + touchMoveListener: null, + touchEndListener: null, + size: null, + gutterElement: null, + startPos: null, + prevPanelElement: null, + nextPanelElement: null, + nextPanelSize: null, + prevPanelSize: null, + panelSizes: null, + prevPanelIndex: null, + timer: null, + data: /* @__PURE__ */ __name(function data() { + return { + prevSize: null + }; + }, "data"), + mounted: /* @__PURE__ */ __name(function mounted() { + var _this = this; + if (this.panels && this.panels.length) { + var initialized = false; + if (this.isStateful()) { + initialized = this.restoreState(); + } + if (!initialized) { + var children = _toConsumableArray$7(this.$el.children).filter(function(child) { + return child.getAttribute("data-pc-name") === "splitterpanel"; + }); + var _panelSizes = []; + this.panels.map(function(panel2, i) { + var panelInitialSize = panel2.props && panel2.props.size ? panel2.props.size : null; + var panelSize = panelInitialSize || 100 / _this.panels.length; + _panelSizes[i] = panelSize; + children[i].style.flexBasis = "calc(" + panelSize + "% - " + (_this.panels.length - 1) * _this.gutterSize + "px)"; + }); + this.panelSizes = _panelSizes; + this.prevSize = parseFloat(_panelSizes[0]).toFixed(4); + } + } + }, "mounted"), + beforeUnmount: /* @__PURE__ */ __name(function beforeUnmount() { + this.clear(); + this.unbindMouseListeners(); + }, "beforeUnmount"), + methods: { + isSplitterPanel: /* @__PURE__ */ __name(function isSplitterPanel(child) { + return child.type.name === "SplitterPanel"; + }, "isSplitterPanel"), + onResizeStart: /* @__PURE__ */ __name(function onResizeStart(event, index2, isKeyDown) { + this.gutterElement = event.currentTarget || event.target.parentElement; + this.size = this.horizontal ? getWidth(this.$el) : getHeight(this.$el); + if (!isKeyDown) { + this.dragging = true; + this.startPos = this.layout === "horizontal" ? event.pageX || event.changedTouches[0].pageX : event.pageY || event.changedTouches[0].pageY; + } + this.prevPanelElement = this.gutterElement.previousElementSibling; + this.nextPanelElement = this.gutterElement.nextElementSibling; + if (isKeyDown) { + this.prevPanelSize = this.horizontal ? getOuterWidth(this.prevPanelElement, true) : getOuterHeight(this.prevPanelElement, true); + this.nextPanelSize = this.horizontal ? getOuterWidth(this.nextPanelElement, true) : getOuterHeight(this.nextPanelElement, true); + } else { + this.prevPanelSize = 100 * (this.horizontal ? getOuterWidth(this.prevPanelElement, true) : getOuterHeight(this.prevPanelElement, true)) / this.size; + this.nextPanelSize = 100 * (this.horizontal ? getOuterWidth(this.nextPanelElement, true) : getOuterHeight(this.nextPanelElement, true)) / this.size; + } + this.prevPanelIndex = index2; + this.$emit("resizestart", { + originalEvent: event, + sizes: this.panelSizes + }); + this.$refs.gutter[index2].setAttribute("data-p-gutter-resizing", true); + this.$el.setAttribute("data-p-resizing", true); + }, "onResizeStart"), + onResize: /* @__PURE__ */ __name(function onResize(event, step2, isKeyDown) { + var newPos, newPrevPanelSize, newNextPanelSize; + if (isKeyDown) { + if (this.horizontal) { + newPrevPanelSize = 100 * (this.prevPanelSize + step2) / this.size; + newNextPanelSize = 100 * (this.nextPanelSize - step2) / this.size; + } else { + newPrevPanelSize = 100 * (this.prevPanelSize - step2) / this.size; + newNextPanelSize = 100 * (this.nextPanelSize + step2) / this.size; + } + } else { + if (this.horizontal) newPos = event.pageX * 100 / this.size - this.startPos * 100 / this.size; + else newPos = event.pageY * 100 / this.size - this.startPos * 100 / this.size; + newPrevPanelSize = this.prevPanelSize + newPos; + newNextPanelSize = this.nextPanelSize - newPos; + } + if (this.validateResize(newPrevPanelSize, newNextPanelSize)) { + this.prevPanelElement.style.flexBasis = "calc(" + newPrevPanelSize + "% - " + (this.panels.length - 1) * this.gutterSize + "px)"; + this.nextPanelElement.style.flexBasis = "calc(" + newNextPanelSize + "% - " + (this.panels.length - 1) * this.gutterSize + "px)"; + this.panelSizes[this.prevPanelIndex] = newPrevPanelSize; + this.panelSizes[this.prevPanelIndex + 1] = newNextPanelSize; + this.prevSize = parseFloat(newPrevPanelSize).toFixed(4); + } + this.$emit("resize", { + originalEvent: event, + sizes: this.panelSizes + }); + }, "onResize"), + onResizeEnd: /* @__PURE__ */ __name(function onResizeEnd(event) { + if (this.isStateful()) { + this.saveState(); + } + this.$emit("resizeend", { + originalEvent: event, + sizes: this.panelSizes + }); + this.$refs.gutter.forEach(function(gutter) { + return gutter.setAttribute("data-p-gutter-resizing", false); + }); + this.$el.setAttribute("data-p-resizing", false); + this.clear(); + }, "onResizeEnd"), + repeat: /* @__PURE__ */ __name(function repeat(event, index2, step2) { + this.onResizeStart(event, index2, true); + this.onResize(event, step2, true); + }, "repeat"), + setTimer: /* @__PURE__ */ __name(function setTimer(event, index2, step2) { + var _this2 = this; + if (!this.timer) { + this.timer = setInterval(function() { + _this2.repeat(event, index2, step2); + }, 40); + } + }, "setTimer"), + clearTimer: /* @__PURE__ */ __name(function clearTimer() { + if (this.timer) { + clearInterval(this.timer); + this.timer = null; + } + }, "clearTimer"), + onGutterKeyUp: /* @__PURE__ */ __name(function onGutterKeyUp() { + this.clearTimer(); + this.onResizeEnd(); + }, "onGutterKeyUp"), + onGutterKeyDown: /* @__PURE__ */ __name(function onGutterKeyDown(event, index2) { + switch (event.code) { + case "ArrowLeft": { + if (this.layout === "horizontal") { + this.setTimer(event, index2, this.step * -1); + } + event.preventDefault(); + break; + } + case "ArrowRight": { + if (this.layout === "horizontal") { + this.setTimer(event, index2, this.step); + } + event.preventDefault(); + break; + } + case "ArrowDown": { + if (this.layout === "vertical") { + this.setTimer(event, index2, this.step * -1); + } + event.preventDefault(); + break; + } + case "ArrowUp": { + if (this.layout === "vertical") { + this.setTimer(event, index2, this.step); + } + event.preventDefault(); + break; + } + } + }, "onGutterKeyDown"), + onGutterMouseDown: /* @__PURE__ */ __name(function onGutterMouseDown(event, index2) { + this.onResizeStart(event, index2); + this.bindMouseListeners(); + }, "onGutterMouseDown"), + onGutterTouchStart: /* @__PURE__ */ __name(function onGutterTouchStart(event, index2) { + this.onResizeStart(event, index2); + this.bindTouchListeners(); + event.preventDefault(); + }, "onGutterTouchStart"), + onGutterTouchMove: /* @__PURE__ */ __name(function onGutterTouchMove(event) { + this.onResize(event); + event.preventDefault(); + }, "onGutterTouchMove"), + onGutterTouchEnd: /* @__PURE__ */ __name(function onGutterTouchEnd(event) { + this.onResizeEnd(event); + this.unbindTouchListeners(); + event.preventDefault(); + }, "onGutterTouchEnd"), + bindMouseListeners: /* @__PURE__ */ __name(function bindMouseListeners() { + var _this3 = this; + if (!this.mouseMoveListener) { + this.mouseMoveListener = function(event) { + return _this3.onResize(event); + }; + document.addEventListener("mousemove", this.mouseMoveListener); + } + if (!this.mouseUpListener) { + this.mouseUpListener = function(event) { + _this3.onResizeEnd(event); + _this3.unbindMouseListeners(); + }; + document.addEventListener("mouseup", this.mouseUpListener); + } + }, "bindMouseListeners"), + bindTouchListeners: /* @__PURE__ */ __name(function bindTouchListeners() { + var _this4 = this; + if (!this.touchMoveListener) { + this.touchMoveListener = function(event) { + return _this4.onResize(event.changedTouches[0]); + }; + document.addEventListener("touchmove", this.touchMoveListener); + } + if (!this.touchEndListener) { + this.touchEndListener = function(event) { + _this4.resizeEnd(event); + _this4.unbindTouchListeners(); + }; + document.addEventListener("touchend", this.touchEndListener); + } + }, "bindTouchListeners"), + validateResize: /* @__PURE__ */ __name(function validateResize(newPrevPanelSize, newNextPanelSize) { + if (newPrevPanelSize > 100 || newPrevPanelSize < 0) return false; + if (newNextPanelSize > 100 || newNextPanelSize < 0) return false; + var prevPanelMinSize = getVNodeProp(this.panels[this.prevPanelIndex], "minSize"); + if (this.panels[this.prevPanelIndex].props && prevPanelMinSize && prevPanelMinSize > newPrevPanelSize) { + return false; + } + var newPanelMinSize = getVNodeProp(this.panels[this.prevPanelIndex + 1], "minSize"); + if (this.panels[this.prevPanelIndex + 1].props && newPanelMinSize && newPanelMinSize > newNextPanelSize) { + return false; + } + return true; + }, "validateResize"), + unbindMouseListeners: /* @__PURE__ */ __name(function unbindMouseListeners() { + if (this.mouseMoveListener) { + document.removeEventListener("mousemove", this.mouseMoveListener); + this.mouseMoveListener = null; + } + if (this.mouseUpListener) { + document.removeEventListener("mouseup", this.mouseUpListener); + this.mouseUpListener = null; + } + }, "unbindMouseListeners"), + unbindTouchListeners: /* @__PURE__ */ __name(function unbindTouchListeners() { + if (this.touchMoveListener) { + document.removeEventListener("touchmove", this.touchMoveListener); + this.touchMoveListener = null; + } + if (this.touchEndListener) { + document.removeEventListener("touchend", this.touchEndListener); + this.touchEndListener = null; + } + }, "unbindTouchListeners"), + clear: /* @__PURE__ */ __name(function clear() { + this.dragging = false; + this.size = null; + this.startPos = null; + this.prevPanelElement = null; + this.nextPanelElement = null; + this.prevPanelSize = null; + this.nextPanelSize = null; + this.gutterElement = null; + this.prevPanelIndex = null; + }, "clear"), + isStateful: /* @__PURE__ */ __name(function isStateful() { + return this.stateKey != null; + }, "isStateful"), + getStorage: /* @__PURE__ */ __name(function getStorage() { + switch (this.stateStorage) { + case "local": + return window.localStorage; + case "session": + return window.sessionStorage; + default: + throw new Error(this.stateStorage + ' is not a valid value for the state storage, supported values are "local" and "session".'); + } + }, "getStorage"), + saveState: /* @__PURE__ */ __name(function saveState() { + if (isArray(this.panelSizes)) { + this.getStorage().setItem(this.stateKey, JSON.stringify(this.panelSizes)); + } + }, "saveState"), + restoreState: /* @__PURE__ */ __name(function restoreState() { + var _this5 = this; + var storage = this.getStorage(); + var stateString = storage.getItem(this.stateKey); + if (stateString) { + this.panelSizes = JSON.parse(stateString); + var children = _toConsumableArray$7(this.$el.children).filter(function(child) { + return child.getAttribute("data-pc-name") === "splitterpanel"; + }); + children.forEach(function(child, i) { + child.style.flexBasis = "calc(" + _this5.panelSizes[i] + "% - " + (_this5.panels.length - 1) * _this5.gutterSize + "px)"; + }); + return true; + } + return false; + }, "restoreState") + }, + computed: { + panels: /* @__PURE__ */ __name(function panels() { + var _this6 = this; + var panels2 = []; + this.$slots["default"]().forEach(function(child) { + if (_this6.isSplitterPanel(child)) { + panels2.push(child); + } else if (child.children instanceof Array) { + child.children.forEach(function(nestedChild) { + if (_this6.isSplitterPanel(nestedChild)) { + panels2.push(nestedChild); + } + }); + } + }); + return panels2; + }, "panels"), + gutterStyle: /* @__PURE__ */ __name(function gutterStyle() { + if (this.horizontal) return { + width: this.gutterSize + "px" + }; + else return { + height: this.gutterSize + "px" + }; + }, "gutterStyle"), + horizontal: /* @__PURE__ */ __name(function horizontal() { + return this.layout === "horizontal"; + }, "horizontal"), + getPTOptions: /* @__PURE__ */ __name(function getPTOptions() { + var _this$$parentInstance; + return { + context: { + nested: (_this$$parentInstance = this.$parentInstance) === null || _this$$parentInstance === void 0 ? void 0 : _this$$parentInstance.nestedState + } + }; + }, "getPTOptions") + } +}; +var _hoisted_1$D = ["onMousedown", "onTouchstart", "onTouchmove", "onTouchend"]; +var _hoisted_2$t = ["aria-orientation", "aria-valuenow", "onKeydown"]; +function render$l(_ctx, _cache, $props, $setup, $data, $options) { + return openBlock(), createElementBlock("div", mergeProps({ + "class": _ctx.cx("root"), + style: _ctx.sx("root"), + "data-p-resizing": false + }, _ctx.ptmi("root", $options.getPTOptions)), [(openBlock(true), createElementBlock(Fragment, null, renderList($options.panels, function(panel2, i) { + return openBlock(), createElementBlock(Fragment, { + key: i + }, [(openBlock(), createBlock(resolveDynamicComponent(panel2), { + tabindex: "-1" + })), i !== $options.panels.length - 1 ? (openBlock(), createElementBlock("div", mergeProps({ + key: 0, + ref_for: true, + ref: "gutter", + "class": _ctx.cx("gutter"), + role: "separator", + tabindex: "-1", + onMousedown: /* @__PURE__ */ __name(function onMousedown($event) { + return $options.onGutterMouseDown($event, i); + }, "onMousedown"), + onTouchstart: /* @__PURE__ */ __name(function onTouchstart($event) { + return $options.onGutterTouchStart($event, i); + }, "onTouchstart"), + onTouchmove: /* @__PURE__ */ __name(function onTouchmove($event) { + return $options.onGutterTouchMove($event, i); + }, "onTouchmove"), + onTouchend: /* @__PURE__ */ __name(function onTouchend($event) { + return $options.onGutterTouchEnd($event, i); + }, "onTouchend"), + "data-p-gutter-resizing": false + }, _ctx.ptm("gutter")), [createBaseVNode("div", mergeProps({ + "class": _ctx.cx("gutterHandle"), + tabindex: "0", + style: [$options.gutterStyle], + "aria-orientation": _ctx.layout, + "aria-valuenow": $data.prevSize, + onKeyup: _cache[0] || (_cache[0] = function() { + return $options.onGutterKeyUp && $options.onGutterKeyUp.apply($options, arguments); + }), + onKeydown: /* @__PURE__ */ __name(function onKeydown($event) { + return $options.onGutterKeyDown($event, i); + }, "onKeydown"), + ref_for: true + }, _ctx.ptm("gutterHandle")), null, 16, _hoisted_2$t)], 16, _hoisted_1$D)) : createCommentVNode("", true)], 64); + }), 128))], 16); +} +__name(render$l, "render$l"); +script$k.render = render$l; +var classes$g = { + root: /* @__PURE__ */ __name(function root3(_ref) { + var instance = _ref.instance; + return ["p-splitterpanel", { + "p-splitterpanel-nested": instance.isNested + }]; + }, "root") +}; +var SplitterPanelStyle = BaseStyle.extend({ + name: "splitterpanel", + classes: classes$g +}); +var script$1$g = { + name: "BaseSplitterPanel", + "extends": script$p, + props: { + size: { + type: Number, + "default": null + }, + minSize: { + type: Number, + "default": null + } + }, + style: SplitterPanelStyle, + provide: /* @__PURE__ */ __name(function provide4() { + return { + $pcSplitterPanel: this, + $parentInstance: this + }; + }, "provide") +}; +var script$j = { + name: "SplitterPanel", + "extends": script$1$g, + inheritAttrs: false, + data: /* @__PURE__ */ __name(function data2() { + return { + nestedState: null + }; + }, "data"), + computed: { + isNested: /* @__PURE__ */ __name(function isNested() { + var _this = this; + return this.$slots["default"]().some(function(child) { + _this.nestedState = child.type.name === "Splitter" ? true : null; + return _this.nestedState; + }); + }, "isNested"), + getPTOptions: /* @__PURE__ */ __name(function getPTOptions2() { + return { + context: { + nested: this.isNested + } + }; + }, "getPTOptions") + } +}; +function render$k(_ctx, _cache, $props, $setup, $data, $options) { + return openBlock(), createElementBlock("div", mergeProps({ + ref: "container", + "class": _ctx.cx("root") + }, _ctx.ptmi("root", $options.getPTOptions)), [renderSlot(_ctx.$slots, "default")], 16); +} +__name(render$k, "render$k"); +script$j.render = render$k; +const _sfc_main$C = /* @__PURE__ */ defineComponent({ + __name: "LiteGraphCanvasSplitterOverlay", + setup(__props) { + const settingStore = useSettingStore(); + const sidebarLocation = computed( + () => settingStore.get("Comfy.Sidebar.Location") + ); + const sidebarPanelVisible = computed( + () => useWorkspaceStore().sidebarTab.activeSidebarTab !== null + ); + const gutterClass = computed(() => { + return sidebarPanelVisible.value ? "" : "gutter-hidden"; + }); + return (_ctx, _cache) => { + return openBlock(), createBlock(unref(script$k), { + class: "splitter-overlay", + "pt:gutter": gutterClass.value + }, { + default: withCtx(() => [ + sidebarLocation.value === "left" ? withDirectives((openBlock(), createBlock(unref(script$j), { + key: 0, + class: "side-bar-panel", + minSize: 10, + size: 20 + }, { + default: withCtx(() => [ + renderSlot(_ctx.$slots, "side-bar-panel", {}, void 0, true) + ]), + _: 3 + }, 512)), [ + [vShow, sidebarPanelVisible.value] + ]) : createCommentVNode("", true), + createVNode(unref(script$j), { + class: "graph-canvas-panel relative", + size: 100 + }, { + default: withCtx(() => [ + renderSlot(_ctx.$slots, "graph-canvas-panel", {}, void 0, true) + ]), + _: 3 + }), + sidebarLocation.value === "right" ? withDirectives((openBlock(), createBlock(unref(script$j), { + key: 1, + class: "side-bar-panel", + minSize: 10, + size: 20 + }, { + default: withCtx(() => [ + renderSlot(_ctx.$slots, "side-bar-panel", {}, void 0, true) + ]), + _: 3 + }, 512)), [ + [vShow, sidebarPanelVisible.value] + ]) : createCommentVNode("", true) + ]), + _: 3 + }, 8, ["pt:gutter"]); + }; + } +}); +const LiteGraphCanvasSplitterOverlay = /* @__PURE__ */ _export_sfc(_sfc_main$C, [["__scopeId", "data-v-b9df3042"]]); +var theme$f = /* @__PURE__ */ __name(function theme3(_ref) { + var dt = _ref.dt; + return "\n.p-autocomplete {\n display: inline-flex;\n}\n\n.p-autocomplete-loader {\n position: absolute;\n top: 50%;\n margin-top: -0.5rem;\n right: ".concat(dt("autocomplete.padding.x"), ";\n}\n\n.p-autocomplete:has(.p-autocomplete-dropdown) .p-autocomplete-loader {\n right: calc(").concat(dt("autocomplete.dropdown.width"), " + ").concat(dt("autocomplete.padding.x"), ");\n}\n\n.p-autocomplete:has(.p-autocomplete-dropdown) .p-autocomplete-input {\n flex: 1 1 auto;\n width: 1%;\n}\n\n.p-autocomplete:has(.p-autocomplete-dropdown) .p-autocomplete-input,\n.p-autocomplete:has(.p-autocomplete-dropdown) .p-autocomplete-input-multiple {\n border-top-right-radius: 0;\n border-bottom-right-radius: 0;\n}\n\n.p-autocomplete-dropdown {\n cursor: pointer;\n display: inline-flex;\n cursor: pointer;\n user-select: none;\n align-items: center;\n justify-content: center;\n overflow: hidden;\n position: relative;\n width: ").concat(dt("autocomplete.dropdown.width"), ";\n border-top-right-radius: ").concat(dt("autocomplete.dropdown.border.radius"), ";\n border-bottom-right-radius: ").concat(dt("autocomplete.dropdown.border.radius"), ";\n background: ").concat(dt("autocomplete.dropdown.background"), ";\n border: 1px solid ").concat(dt("autocomplete.dropdown.border.color"), ";\n border-left: 0 none;\n color: ").concat(dt("autocomplete.dropdown.color"), ";\n transition: background ").concat(dt("autocomplete.transition.duration"), ", color ").concat(dt("autocomplete.transition.duration"), ", border-color ").concat(dt("autocomplete.transition.duration"), ", outline-color ").concat(dt("autocomplete.transition.duration"), ", box-shadow ").concat(dt("autocomplete.transition.duration"), ";\n outline-color: transparent;\n}\n\n.p-autocomplete-dropdown:not(:disabled):hover {\n background: ").concat(dt("autocomplete.dropdown.hover.background"), ";\n border-color: ").concat(dt("autocomplete.dropdown.hover.border.color"), ";\n color: ").concat(dt("autocomplete.dropdown.hover.color"), ";\n}\n\n.p-autocomplete-dropdown:not(:disabled):active {\n background: ").concat(dt("autocomplete.dropdown.active.background"), ";\n border-color: ").concat(dt("autocomplete.dropdown.active.border.color"), ";\n color: ").concat(dt("autocomplete.dropdown.active.color"), ";\n}\n\n.p-autocomplete-dropdown:focus-visible {\n box-shadow: ").concat(dt("autocomplete.dropdown.focus.ring.shadow"), ";\n outline: ").concat(dt("autocomplete.dropdown.focus.ring.width"), " ").concat(dt("autocomplete.dropdown.focus.ring.style"), " ").concat(dt("autocomplete.dropdown.focus.ring.color"), ";\n outline-offset: ").concat(dt("autocomplete.dropdown.focus.ring.offset"), ";\n}\n\n.p-autocomplete .p-autocomplete-overlay {\n min-width: 100%;\n}\n\n.p-autocomplete-overlay {\n position: absolute;\n overflow: auto;\n top: 0;\n left: 0;\n background: ").concat(dt("autocomplete.overlay.background"), ";\n color: ").concat(dt("autocomplete.overlay.color"), ";\n border: 1px solid ").concat(dt("autocomplete.overlay.border.color"), ";\n border-radius: ").concat(dt("autocomplete.overlay.border.radius"), ";\n box-shadow: ").concat(dt("autocomplete.overlay.shadow"), ";\n}\n\n.p-autocomplete-list {\n margin: 0;\n padding: 0;\n list-style-type: none;\n display: flex;\n flex-direction: column;\n gap: ").concat(dt("autocomplete.list.gap"), ";\n padding: ").concat(dt("autocomplete.list.padding"), ";\n}\n\n.p-autocomplete-option {\n cursor: pointer;\n white-space: nowrap;\n position: relative;\n overflow: hidden;\n display: flex;\n align-items: center;\n padding: ").concat(dt("autocomplete.option.padding"), ";\n border: 0 none;\n color: ").concat(dt("autocomplete.option.color"), ";\n background: transparent;\n transition: background ").concat(dt("autocomplete.transition.duration"), ", color ").concat(dt("autocomplete.transition.duration"), ", border-color ").concat(dt("autocomplete.transition.duration"), ";\n border-radius: ").concat(dt("autocomplete.option.border.radius"), ";\n}\n\n.p-autocomplete-option:not(.p-autocomplete-option-selected):not(.p-disabled).p-focus {\n background: ").concat(dt("autocomplete.option.focus.background"), ";\n color: ").concat(dt("autocomplete.option.focus.color"), ";\n}\n\n.p-autocomplete-option-selected {\n background: ").concat(dt("autocomplete.option.selected.background"), ";\n color: ").concat(dt("autocomplete.option.selected.color"), ";\n}\n\n.p-autocomplete-option-selected.p-focus {\n background: ").concat(dt("autocomplete.option.selected.focus.background"), ";\n color: ").concat(dt("autocomplete.option.selected.focus.color"), ";\n}\n\n.p-autocomplete-option-group {\n margin: 0;\n padding: ").concat(dt("autocomplete.option.group.padding"), ";\n color: ").concat(dt("autocomplete.option.group.color"), ";\n background: ").concat(dt("autocomplete.option.group.background"), ";\n font-weight: ").concat(dt("autocomplete.option.group.font.weight"), ";\n}\n\n.p-autocomplete-input-multiple {\n margin: 0;\n list-style-type: none;\n cursor: text;\n overflow: hidden;\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n padding: calc(").concat(dt("autocomplete.padding.y"), " / 2) ").concat(dt("autocomplete.padding.x"), ";\n gap: calc(").concat(dt("autocomplete.padding.y"), " / 2);\n color: ").concat(dt("autocomplete.color"), ";\n background: ").concat(dt("autocomplete.background"), ";\n border: 1px solid ").concat(dt("autocomplete.border.color"), ";\n border-radius: ").concat(dt("autocomplete.border.radius"), ";\n width: 100%;\n transition: background ").concat(dt("autocomplete.transition.duration"), ", color ").concat(dt("autocomplete.transition.duration"), ", border-color ").concat(dt("autocomplete.transition.duration"), ", outline-color ").concat(dt("autocomplete.transition.duration"), ", box-shadow ").concat(dt("autocomplete.transition.duration"), ";\n outline-color: transparent;\n box-shadow: ").concat(dt("autocomplete.shadow"), ";\n}\n\n.p-autocomplete:not(.p-disabled):hover .p-autocomplete-input-multiple {\n border-color: ").concat(dt("autocomplete.hover.border.color"), ";\n}\n\n.p-autocomplete:not(.p-disabled).p-focus .p-autocomplete-input-multiple {\n border-color: ").concat(dt("autocomplete.focus.border.color"), ";\n box-shadow: ").concat(dt("autocomplete.focus.ring.shadow"), ";\n outline: ").concat(dt("autocomplete.focus.ring.width"), " ").concat(dt("autocomplete.focus.ring.style"), " ").concat(dt("autocomplete.focus.ring.color"), ";\n outline-offset: ").concat(dt("autocomplete.focus.ring.offset"), ";\n}\n\n.p-autocomplete.p-invalid .p-autocomplete-input-multiple {\n border-color: ").concat(dt("autocomplete.invalid.border.color"), ";\n}\n\n.p-variant-filled.p-autocomplete-input-multiple {\n background: ").concat(dt("autocomplete.filled.background"), ";\n}\n\n.p-autocomplete:not(.p-disabled).p-focus .p-variant-filled.p-autocomplete-input-multiple {\n background: ").concat(dt("autocomplete.filled.focus.background"), ";\n}\n\n.p-autocomplete.p-disabled .p-autocomplete-input-multiple {\n opacity: 1;\n background: ").concat(dt("autocomplete.disabled.background"), ";\n color: ").concat(dt("autocomplete.disabled.color"), ";\n}\n\n.p-autocomplete-chip.p-chip {\n padding-top: calc(").concat(dt("autocomplete.padding.y"), " / 2);\n padding-bottom: calc(").concat(dt("autocomplete.padding.y"), " / 2);\n border-radius: ").concat(dt("autocomplete.chip.border.radius"), ";\n}\n\n.p-autocomplete-input-multiple:has(.p-autocomplete-chip) {\n padding-left: calc(").concat(dt("autocomplete.padding.y"), " / 2);\n padding-right: calc(").concat(dt("autocomplete.padding.y"), " / 2);\n}\n\n.p-autocomplete-chip-item.p-focus .p-autocomplete-chip {\n background: ").concat(dt("inputchips.chip.focus.background"), ";\n color: ").concat(dt("inputchips.chip.focus.color"), ";\n}\n\n.p-autocomplete-input-chip {\n flex: 1 1 auto;\n display: inline-flex;\n padding-top: calc(").concat(dt("autocomplete.padding.y"), " / 2);\n padding-bottom: calc(").concat(dt("autocomplete.padding.y"), " / 2);\n}\n\n.p-autocomplete-input-chip input {\n border: 0 none;\n outline: 0 none;\n background: transparent;\n margin: 0;\n padding: 0;\n box-shadow: none;\n border-radius: 0;\n width: 100%;\n font-family: inherit;\n font-feature-settings: inherit;\n font-size: 1rem;\n color: inherit;\n}\n\n.p-autocomplete-input-chip input::placeholder {\n color: ").concat(dt("autocomplete.placeholder.color"), ";\n}\n\n.p-autocomplete-empty-message {\n padding: ").concat(dt("autocomplete.empty.message.padding"), ";\n}\n\n.p-autocomplete-fluid {\n display: flex;\n}\n\n.p-autocomplete-fluid:has(.p-autocomplete-dropdown) .p-autocomplete-input {\n width: 1%;\n}\n"); +}, "theme"); +var inlineStyles$3 = { + root: { + position: "relative" + } +}; +var classes$f = { + root: /* @__PURE__ */ __name(function root4(_ref2) { + var instance = _ref2.instance, props = _ref2.props; + return ["p-autocomplete p-component p-inputwrapper", { + "p-disabled": props.disabled, + "p-invalid": props.invalid, + "p-focus": instance.focused, + "p-inputwrapper-filled": props.modelValue || isNotEmpty(instance.inputValue), + "p-inputwrapper-focus": instance.focused, + "p-autocomplete-open": instance.overlayVisible, + "p-autocomplete-fluid": instance.hasFluid + }]; + }, "root"), + pcInput: "p-autocomplete-input", + inputMultiple: /* @__PURE__ */ __name(function inputMultiple(_ref3) { + var props = _ref3.props, instance = _ref3.instance; + return ["p-autocomplete-input-multiple", { + "p-variant-filled": props.variant ? props.variant === "filled" : instance.$primevue.config.inputStyle === "filled" || instance.$primevue.config.inputVariant === "filled" + }]; + }, "inputMultiple"), + chipItem: /* @__PURE__ */ __name(function chipItem(_ref4) { + var instance = _ref4.instance, i = _ref4.i; + return ["p-autocomplete-chip-item", { + "p-focus": instance.focusedMultipleOptionIndex === i + }]; + }, "chipItem"), + pcChip: "p-autocomplete-chip", + chipIcon: "p-autocomplete-chip-icon", + inputChip: "p-autocomplete-input-chip", + loader: "p-autocomplete-loader", + dropdown: "p-autocomplete-dropdown", + overlay: "p-autocomplete-overlay p-component", + list: "p-autocomplete-list", + optionGroup: "p-autocomplete-option-group", + option: /* @__PURE__ */ __name(function option(_ref5) { + var instance = _ref5.instance, _option = _ref5.option, i = _ref5.i, getItemOptions = _ref5.getItemOptions; + return ["p-autocomplete-option", { + "p-autocomplete-option-selected": instance.isSelected(_option), + "p-focus": instance.focusedOptionIndex === instance.getOptionIndex(i, getItemOptions), + "p-disabled": instance.isOptionDisabled(_option) + }]; + }, "option"), + emptyMessage: "p-autocomplete-empty-message" +}; +var AutoCompleteStyle = BaseStyle.extend({ + name: "autocomplete", + theme: theme$f, + classes: classes$f, + inlineStyles: inlineStyles$3 +}); +var script$1$f = { + name: "BaseAutoComplete", + "extends": script$p, + props: { + modelValue: null, + suggestions: { + type: Array, + "default": null + }, + optionLabel: null, + optionDisabled: null, + optionGroupLabel: null, + optionGroupChildren: null, + scrollHeight: { + type: String, + "default": "14rem" + }, + dropdown: { + type: Boolean, + "default": false + }, + dropdownMode: { + type: String, + "default": "blank" + }, + multiple: { + type: Boolean, + "default": false + }, + loading: { + type: Boolean, + "default": false + }, + variant: { + type: String, + "default": null + }, + invalid: { + type: Boolean, + "default": false + }, + disabled: { + type: Boolean, + "default": false + }, + placeholder: { + type: String, + "default": null + }, + dataKey: { + type: String, + "default": null + }, + minLength: { + type: Number, + "default": 1 + }, + delay: { + type: Number, + "default": 300 + }, + appendTo: { + type: [String, Object], + "default": "body" + }, + forceSelection: { + type: Boolean, + "default": false + }, + completeOnFocus: { + type: Boolean, + "default": false + }, + inputId: { + type: String, + "default": null + }, + inputStyle: { + type: Object, + "default": null + }, + inputClass: { + type: [String, Object], + "default": null + }, + panelStyle: { + type: Object, + "default": null + }, + panelClass: { + type: [String, Object], + "default": null + }, + overlayStyle: { + type: Object, + "default": null + }, + overlayClass: { + type: [String, Object], + "default": null + }, + dropdownIcon: { + type: String, + "default": null + }, + dropdownClass: { + type: [String, Object], + "default": null + }, + loader: { + type: String, + "default": null + }, + loadingIcon: { + type: String, + "default": null + }, + removeTokenIcon: { + type: String, + "default": null + }, + chipIcon: { + type: String, + "default": null + }, + virtualScrollerOptions: { + type: Object, + "default": null + }, + autoOptionFocus: { + type: Boolean, + "default": false + }, + selectOnFocus: { + type: Boolean, + "default": false + }, + focusOnHover: { + type: Boolean, + "default": true + }, + searchLocale: { + type: String, + "default": void 0 + }, + searchMessage: { + type: String, + "default": null + }, + selectionMessage: { + type: String, + "default": null + }, + emptySelectionMessage: { + type: String, + "default": null + }, + emptySearchMessage: { + type: String, + "default": null + }, + tabindex: { + type: Number, + "default": 0 + }, + typeahead: { + type: Boolean, + "default": true + }, + ariaLabel: { + type: String, + "default": null + }, + ariaLabelledby: { + type: String, + "default": null + }, + fluid: { + type: Boolean, + "default": null + } + }, + style: AutoCompleteStyle, + provide: /* @__PURE__ */ __name(function provide5() { + return { + $pcAutoComplete: this, + $parentInstance: this + }; + }, "provide") +}; +function _typeof$1$3(o) { + "@babel/helpers - typeof"; + return _typeof$1$3 = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(o2) { + return typeof o2; + } : function(o2) { + return o2 && "function" == typeof Symbol && o2.constructor === Symbol && o2 !== Symbol.prototype ? "symbol" : typeof o2; + }, _typeof$1$3(o); +} +__name(_typeof$1$3, "_typeof$1$3"); +function _toConsumableArray$6(r) { + return _arrayWithoutHoles$6(r) || _iterableToArray$6(r) || _unsupportedIterableToArray$8(r) || _nonIterableSpread$6(); +} +__name(_toConsumableArray$6, "_toConsumableArray$6"); +function _nonIterableSpread$6() { + throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); +} +__name(_nonIterableSpread$6, "_nonIterableSpread$6"); +function _unsupportedIterableToArray$8(r, a) { + if (r) { + if ("string" == typeof r) return _arrayLikeToArray$8(r, a); + var t = {}.toString.call(r).slice(8, -1); + return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray$8(r, a) : void 0; + } +} +__name(_unsupportedIterableToArray$8, "_unsupportedIterableToArray$8"); +function _iterableToArray$6(r) { + if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); +} +__name(_iterableToArray$6, "_iterableToArray$6"); +function _arrayWithoutHoles$6(r) { + if (Array.isArray(r)) return _arrayLikeToArray$8(r); +} +__name(_arrayWithoutHoles$6, "_arrayWithoutHoles$6"); +function _arrayLikeToArray$8(r, a) { + (null == a || a > r.length) && (a = r.length); + for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; + return n; +} +__name(_arrayLikeToArray$8, "_arrayLikeToArray$8"); +var script$i = { + name: "AutoComplete", + "extends": script$1$f, + inheritAttrs: false, + emits: ["update:modelValue", "change", "focus", "blur", "item-select", "item-unselect", "option-select", "option-unselect", "dropdown-click", "clear", "complete", "before-show", "before-hide", "show", "hide"], + inject: { + $pcFluid: { + "default": null + } + }, + outsideClickListener: null, + resizeListener: null, + scrollHandler: null, + overlay: null, + virtualScroller: null, + searchTimeout: null, + dirty: false, + data: /* @__PURE__ */ __name(function data3() { + return { + id: this.$attrs.id, + clicked: false, + focused: false, + focusedOptionIndex: -1, + focusedMultipleOptionIndex: -1, + overlayVisible: false, + searching: false + }; + }, "data"), + watch: { + "$attrs.id": /* @__PURE__ */ __name(function $attrsId(newValue) { + this.id = newValue || UniqueComponentId(); + }, "$attrsId"), + suggestions: /* @__PURE__ */ __name(function suggestions() { + if (this.searching) { + this.show(); + this.focusedOptionIndex = this.overlayVisible && this.autoOptionFocus ? this.findFirstFocusedOptionIndex() : -1; + this.searching = false; + } + this.autoUpdateModel(); + }, "suggestions") + }, + mounted: /* @__PURE__ */ __name(function mounted2() { + this.id = this.id || UniqueComponentId(); + this.autoUpdateModel(); + }, "mounted"), + updated: /* @__PURE__ */ __name(function updated() { + if (this.overlayVisible) { + this.alignOverlay(); + } + }, "updated"), + beforeUnmount: /* @__PURE__ */ __name(function beforeUnmount2() { + this.unbindOutsideClickListener(); + this.unbindResizeListener(); + if (this.scrollHandler) { + this.scrollHandler.destroy(); + this.scrollHandler = null; + } + if (this.overlay) { + ZIndex.clear(this.overlay); + this.overlay = null; + } + }, "beforeUnmount"), + methods: { + getOptionIndex: /* @__PURE__ */ __name(function getOptionIndex(index2, fn) { + return this.virtualScrollerDisabled ? index2 : fn && fn(index2)["index"]; + }, "getOptionIndex"), + getOptionLabel: /* @__PURE__ */ __name(function getOptionLabel(option2) { + return this.optionLabel ? resolveFieldData(option2, this.optionLabel) : option2; + }, "getOptionLabel"), + getOptionValue: /* @__PURE__ */ __name(function getOptionValue(option2) { + return option2; + }, "getOptionValue"), + getOptionRenderKey: /* @__PURE__ */ __name(function getOptionRenderKey(option2, index2) { + return (this.dataKey ? resolveFieldData(option2, this.dataKey) : this.getOptionLabel(option2)) + "_" + index2; + }, "getOptionRenderKey"), + getPTOptions: /* @__PURE__ */ __name(function getPTOptions3(option2, itemOptions, index2, key) { + return this.ptm(key, { + context: { + selected: this.isSelected(option2), + focused: this.focusedOptionIndex === this.getOptionIndex(index2, itemOptions), + disabled: this.isOptionDisabled(option2) + } + }); + }, "getPTOptions"), + isOptionDisabled: /* @__PURE__ */ __name(function isOptionDisabled(option2) { + return this.optionDisabled ? resolveFieldData(option2, this.optionDisabled) : false; + }, "isOptionDisabled"), + isOptionGroup: /* @__PURE__ */ __name(function isOptionGroup(option2) { + return this.optionGroupLabel && option2.optionGroup && option2.group; + }, "isOptionGroup"), + getOptionGroupLabel: /* @__PURE__ */ __name(function getOptionGroupLabel(optionGroup) { + return resolveFieldData(optionGroup, this.optionGroupLabel); + }, "getOptionGroupLabel"), + getOptionGroupChildren: /* @__PURE__ */ __name(function getOptionGroupChildren(optionGroup) { + return resolveFieldData(optionGroup, this.optionGroupChildren); + }, "getOptionGroupChildren"), + getAriaPosInset: /* @__PURE__ */ __name(function getAriaPosInset(index2) { + var _this = this; + return (this.optionGroupLabel ? index2 - this.visibleOptions.slice(0, index2).filter(function(option2) { + return _this.isOptionGroup(option2); + }).length : index2) + 1; + }, "getAriaPosInset"), + show: /* @__PURE__ */ __name(function show(isFocus) { + this.$emit("before-show"); + this.dirty = true; + this.overlayVisible = true; + this.focusedOptionIndex = this.focusedOptionIndex !== -1 ? this.focusedOptionIndex : this.autoOptionFocus ? this.findFirstFocusedOptionIndex() : -1; + isFocus && focus(this.multiple ? this.$refs.focusInput : this.$refs.focusInput.$el); + }, "show"), + hide: /* @__PURE__ */ __name(function hide(isFocus) { + var _this2 = this; + var _hide = /* @__PURE__ */ __name(function _hide2() { + _this2.$emit("before-hide"); + _this2.dirty = isFocus; + _this2.overlayVisible = false; + _this2.clicked = false; + _this2.focusedOptionIndex = -1; + isFocus && focus(_this2.multiple ? _this2.$refs.focusInput : _this2.$refs.focusInput.$el); + }, "_hide"); + setTimeout(function() { + _hide(); + }, 0); + }, "hide"), + onFocus: /* @__PURE__ */ __name(function onFocus(event) { + if (this.disabled) { + return; + } + if (!this.dirty && this.completeOnFocus) { + this.search(event, event.target.value, "focus"); + } + this.dirty = true; + this.focused = true; + if (this.overlayVisible) { + this.focusedOptionIndex = this.focusedOptionIndex !== -1 ? this.focusedOptionIndex : this.overlayVisible && this.autoOptionFocus ? this.findFirstFocusedOptionIndex() : -1; + this.scrollInView(this.focusedOptionIndex); + } + this.$emit("focus", event); + }, "onFocus"), + onBlur: /* @__PURE__ */ __name(function onBlur(event) { + this.dirty = false; + this.focused = false; + this.focusedOptionIndex = -1; + this.$emit("blur", event); + }, "onBlur"), + onKeyDown: /* @__PURE__ */ __name(function onKeyDown(event) { + if (this.disabled) { + event.preventDefault(); + return; + } + switch (event.code) { + case "ArrowDown": + this.onArrowDownKey(event); + break; + case "ArrowUp": + this.onArrowUpKey(event); + break; + case "ArrowLeft": + this.onArrowLeftKey(event); + break; + case "ArrowRight": + this.onArrowRightKey(event); + break; + case "Home": + this.onHomeKey(event); + break; + case "End": + this.onEndKey(event); + break; + case "PageDown": + this.onPageDownKey(event); + break; + case "PageUp": + this.onPageUpKey(event); + break; + case "Enter": + case "NumpadEnter": + this.onEnterKey(event); + break; + case "Escape": + this.onEscapeKey(event); + break; + case "Tab": + this.onTabKey(event); + break; + case "Backspace": + this.onBackspaceKey(event); + break; + } + this.clicked = false; + }, "onKeyDown"), + onInput: /* @__PURE__ */ __name(function onInput(event) { + var _this3 = this; + if (this.typeahead) { + if (this.searchTimeout) { + clearTimeout(this.searchTimeout); + } + var query = event.target.value; + if (!this.multiple) { + this.updateModel(event, query); + } + if (query.length === 0) { + this.hide(); + this.$emit("clear"); + } else { + if (query.length >= this.minLength) { + this.focusedOptionIndex = -1; + this.searchTimeout = setTimeout(function() { + _this3.search(event, query, "input"); + }, this.delay); + } else { + this.hide(); + } + } + } + }, "onInput"), + onChange: /* @__PURE__ */ __name(function onChange(event) { + var _this4 = this; + if (this.forceSelection) { + var valid = false; + if (this.visibleOptions && !this.multiple) { + var value = this.multiple ? this.$refs.focusInput.value : this.$refs.focusInput.$el.value; + var matchedValue = this.visibleOptions.find(function(option2) { + return _this4.isOptionMatched(option2, value || ""); + }); + if (matchedValue !== void 0) { + valid = true; + !this.isSelected(matchedValue) && this.onOptionSelect(event, matchedValue); + } + } + if (!valid) { + if (this.multiple) this.$refs.focusInput.value = ""; + else this.$refs.focusInput.$el.value = ""; + this.$emit("clear"); + !this.multiple && this.updateModel(event, null); + } + } + }, "onChange"), + onMultipleContainerFocus: /* @__PURE__ */ __name(function onMultipleContainerFocus() { + if (this.disabled) { + return; + } + this.focused = true; + }, "onMultipleContainerFocus"), + onMultipleContainerBlur: /* @__PURE__ */ __name(function onMultipleContainerBlur() { + this.focusedMultipleOptionIndex = -1; + this.focused = false; + }, "onMultipleContainerBlur"), + onMultipleContainerKeyDown: /* @__PURE__ */ __name(function onMultipleContainerKeyDown(event) { + if (this.disabled) { + event.preventDefault(); + return; + } + switch (event.code) { + case "ArrowLeft": + this.onArrowLeftKeyOnMultiple(event); + break; + case "ArrowRight": + this.onArrowRightKeyOnMultiple(event); + break; + case "Backspace": + this.onBackspaceKeyOnMultiple(event); + break; + } + }, "onMultipleContainerKeyDown"), + onContainerClick: /* @__PURE__ */ __name(function onContainerClick(event) { + this.clicked = true; + if (this.disabled || this.searching || this.loading || this.isInputClicked(event) || this.isDropdownClicked(event)) { + return; + } + if (!this.overlay || !this.overlay.contains(event.target)) { + focus(this.multiple ? this.$refs.focusInput : this.$refs.focusInput.$el); + } + }, "onContainerClick"), + onDropdownClick: /* @__PURE__ */ __name(function onDropdownClick(event) { + var query = void 0; + if (this.overlayVisible) { + this.hide(true); + } else { + var target = this.multiple ? this.$refs.focusInput : this.$refs.focusInput.$el; + focus(target); + query = target.value; + if (this.dropdownMode === "blank") this.search(event, "", "dropdown"); + else if (this.dropdownMode === "current") this.search(event, query, "dropdown"); + } + this.$emit("dropdown-click", { + originalEvent: event, + query + }); + }, "onDropdownClick"), + onOptionSelect: /* @__PURE__ */ __name(function onOptionSelect(event, option2) { + var isHide = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : true; + var value = this.getOptionValue(option2); + if (this.multiple) { + this.$refs.focusInput.value = ""; + if (!this.isSelected(option2)) { + this.updateModel(event, [].concat(_toConsumableArray$6(this.modelValue || []), [value])); + } + } else { + this.updateModel(event, value); + } + this.$emit("item-select", { + originalEvent: event, + value: option2 + }); + this.$emit("option-select", { + originalEvent: event, + value: option2 + }); + isHide && this.hide(true); + }, "onOptionSelect"), + onOptionMouseMove: /* @__PURE__ */ __name(function onOptionMouseMove(event, index2) { + if (this.focusOnHover) { + this.changeFocusedOptionIndex(event, index2); + } + }, "onOptionMouseMove"), + onOverlayClick: /* @__PURE__ */ __name(function onOverlayClick(event) { + OverlayEventBus.emit("overlay-click", { + originalEvent: event, + target: this.$el + }); + }, "onOverlayClick"), + onOverlayKeyDown: /* @__PURE__ */ __name(function onOverlayKeyDown(event) { + switch (event.code) { + case "Escape": + this.onEscapeKey(event); + break; + } + }, "onOverlayKeyDown"), + onArrowDownKey: /* @__PURE__ */ __name(function onArrowDownKey(event) { + if (!this.overlayVisible) { + return; + } + var optionIndex = this.focusedOptionIndex !== -1 ? this.findNextOptionIndex(this.focusedOptionIndex) : this.clicked ? this.findFirstOptionIndex() : this.findFirstFocusedOptionIndex(); + this.changeFocusedOptionIndex(event, optionIndex); + event.preventDefault(); + }, "onArrowDownKey"), + onArrowUpKey: /* @__PURE__ */ __name(function onArrowUpKey(event) { + if (!this.overlayVisible) { + return; + } + if (event.altKey) { + if (this.focusedOptionIndex !== -1) { + this.onOptionSelect(event, this.visibleOptions[this.focusedOptionIndex]); + } + this.overlayVisible && this.hide(); + event.preventDefault(); + } else { + var optionIndex = this.focusedOptionIndex !== -1 ? this.findPrevOptionIndex(this.focusedOptionIndex) : this.clicked ? this.findLastOptionIndex() : this.findLastFocusedOptionIndex(); + this.changeFocusedOptionIndex(event, optionIndex); + event.preventDefault(); + } + }, "onArrowUpKey"), + onArrowLeftKey: /* @__PURE__ */ __name(function onArrowLeftKey(event) { + var target = event.currentTarget; + this.focusedOptionIndex = -1; + if (this.multiple) { + if (isEmpty(target.value) && this.hasSelectedOption) { + focus(this.$refs.multiContainer); + this.focusedMultipleOptionIndex = this.modelValue.length; + } else { + event.stopPropagation(); + } + } + }, "onArrowLeftKey"), + onArrowRightKey: /* @__PURE__ */ __name(function onArrowRightKey(event) { + this.focusedOptionIndex = -1; + this.multiple && event.stopPropagation(); + }, "onArrowRightKey"), + onHomeKey: /* @__PURE__ */ __name(function onHomeKey(event) { + var currentTarget = event.currentTarget; + var len = currentTarget.value.length; + currentTarget.setSelectionRange(0, event.shiftKey ? len : 0); + this.focusedOptionIndex = -1; + event.preventDefault(); + }, "onHomeKey"), + onEndKey: /* @__PURE__ */ __name(function onEndKey(event) { + var currentTarget = event.currentTarget; + var len = currentTarget.value.length; + currentTarget.setSelectionRange(event.shiftKey ? 0 : len, len); + this.focusedOptionIndex = -1; + event.preventDefault(); + }, "onEndKey"), + onPageUpKey: /* @__PURE__ */ __name(function onPageUpKey(event) { + this.scrollInView(0); + event.preventDefault(); + }, "onPageUpKey"), + onPageDownKey: /* @__PURE__ */ __name(function onPageDownKey(event) { + this.scrollInView(this.visibleOptions.length - 1); + event.preventDefault(); + }, "onPageDownKey"), + onEnterKey: /* @__PURE__ */ __name(function onEnterKey(event) { + if (!this.typeahead) { + if (this.multiple) { + this.updateModel(event, [].concat(_toConsumableArray$6(this.modelValue || []), [event.target.value])); + this.$refs.focusInput.value = ""; + } + } else { + if (!this.overlayVisible) { + this.focusedOptionIndex = -1; + this.onArrowDownKey(event); + } else { + if (this.focusedOptionIndex !== -1) { + this.onOptionSelect(event, this.visibleOptions[this.focusedOptionIndex]); + } + this.hide(); + } + } + }, "onEnterKey"), + onEscapeKey: /* @__PURE__ */ __name(function onEscapeKey(event) { + this.overlayVisible && this.hide(true); + event.preventDefault(); + }, "onEscapeKey"), + onTabKey: /* @__PURE__ */ __name(function onTabKey(event) { + if (this.focusedOptionIndex !== -1) { + this.onOptionSelect(event, this.visibleOptions[this.focusedOptionIndex]); + } + this.overlayVisible && this.hide(); + }, "onTabKey"), + onBackspaceKey: /* @__PURE__ */ __name(function onBackspaceKey(event) { + if (this.multiple) { + if (isNotEmpty(this.modelValue) && !this.$refs.focusInput.value) { + var removedValue = this.modelValue[this.modelValue.length - 1]; + var newValue = this.modelValue.slice(0, -1); + this.$emit("update:modelValue", newValue); + this.$emit("item-unselect", { + originalEvent: event, + value: removedValue + }); + this.$emit("option-unselect", { + originalEvent: event, + value: removedValue + }); + } + event.stopPropagation(); + } + }, "onBackspaceKey"), + onArrowLeftKeyOnMultiple: /* @__PURE__ */ __name(function onArrowLeftKeyOnMultiple() { + this.focusedMultipleOptionIndex = this.focusedMultipleOptionIndex < 1 ? 0 : this.focusedMultipleOptionIndex - 1; + }, "onArrowLeftKeyOnMultiple"), + onArrowRightKeyOnMultiple: /* @__PURE__ */ __name(function onArrowRightKeyOnMultiple() { + this.focusedMultipleOptionIndex++; + if (this.focusedMultipleOptionIndex > this.modelValue.length - 1) { + this.focusedMultipleOptionIndex = -1; + focus(this.$refs.focusInput); + } + }, "onArrowRightKeyOnMultiple"), + onBackspaceKeyOnMultiple: /* @__PURE__ */ __name(function onBackspaceKeyOnMultiple(event) { + if (this.focusedMultipleOptionIndex !== -1) { + this.removeOption(event, this.focusedMultipleOptionIndex); + } + }, "onBackspaceKeyOnMultiple"), + onOverlayEnter: /* @__PURE__ */ __name(function onOverlayEnter(el) { + ZIndex.set("overlay", el, this.$primevue.config.zIndex.overlay); + addStyle(el, { + position: "absolute", + top: "0", + left: "0" + }); + this.alignOverlay(); + }, "onOverlayEnter"), + onOverlayAfterEnter: /* @__PURE__ */ __name(function onOverlayAfterEnter() { + this.bindOutsideClickListener(); + this.bindScrollListener(); + this.bindResizeListener(); + this.$emit("show"); + }, "onOverlayAfterEnter"), + onOverlayLeave: /* @__PURE__ */ __name(function onOverlayLeave() { + this.unbindOutsideClickListener(); + this.unbindScrollListener(); + this.unbindResizeListener(); + this.$emit("hide"); + this.overlay = null; + }, "onOverlayLeave"), + onOverlayAfterLeave: /* @__PURE__ */ __name(function onOverlayAfterLeave(el) { + ZIndex.clear(el); + }, "onOverlayAfterLeave"), + alignOverlay: /* @__PURE__ */ __name(function alignOverlay() { + var target = this.multiple ? this.$refs.multiContainer : this.$refs.focusInput.$el; + if (this.appendTo === "self") { + relativePosition(this.overlay, target); + } else { + this.overlay.style.minWidth = getOuterWidth(target) + "px"; + absolutePosition(this.overlay, target); + } + }, "alignOverlay"), + bindOutsideClickListener: /* @__PURE__ */ __name(function bindOutsideClickListener() { + var _this5 = this; + if (!this.outsideClickListener) { + this.outsideClickListener = function(event) { + if (_this5.overlayVisible && _this5.overlay && _this5.isOutsideClicked(event)) { + _this5.hide(); + } + }; + document.addEventListener("click", this.outsideClickListener); + } + }, "bindOutsideClickListener"), + unbindOutsideClickListener: /* @__PURE__ */ __name(function unbindOutsideClickListener() { + if (this.outsideClickListener) { + document.removeEventListener("click", this.outsideClickListener); + this.outsideClickListener = null; + } + }, "unbindOutsideClickListener"), + bindScrollListener: /* @__PURE__ */ __name(function bindScrollListener() { + var _this6 = this; + if (!this.scrollHandler) { + this.scrollHandler = new ConnectedOverlayScrollHandler(this.$refs.container, function() { + if (_this6.overlayVisible) { + _this6.hide(); + } + }); + } + this.scrollHandler.bindScrollListener(); + }, "bindScrollListener"), + unbindScrollListener: /* @__PURE__ */ __name(function unbindScrollListener() { + if (this.scrollHandler) { + this.scrollHandler.unbindScrollListener(); + } + }, "unbindScrollListener"), + bindResizeListener: /* @__PURE__ */ __name(function bindResizeListener() { + var _this7 = this; + if (!this.resizeListener) { + this.resizeListener = function() { + if (_this7.overlayVisible && !isTouchDevice()) { + _this7.hide(); + } + }; + window.addEventListener("resize", this.resizeListener); + } + }, "bindResizeListener"), + unbindResizeListener: /* @__PURE__ */ __name(function unbindResizeListener() { + if (this.resizeListener) { + window.removeEventListener("resize", this.resizeListener); + this.resizeListener = null; + } + }, "unbindResizeListener"), + isOutsideClicked: /* @__PURE__ */ __name(function isOutsideClicked(event) { + return !this.overlay.contains(event.target) && !this.isInputClicked(event) && !this.isDropdownClicked(event); + }, "isOutsideClicked"), + isInputClicked: /* @__PURE__ */ __name(function isInputClicked(event) { + if (this.multiple) return event.target === this.$refs.multiContainer || this.$refs.multiContainer.contains(event.target); + else return event.target === this.$refs.focusInput.$el; + }, "isInputClicked"), + isDropdownClicked: /* @__PURE__ */ __name(function isDropdownClicked(event) { + return this.$refs.dropdownButton ? event.target === this.$refs.dropdownButton || this.$refs.dropdownButton.contains(event.target) : false; + }, "isDropdownClicked"), + isOptionMatched: /* @__PURE__ */ __name(function isOptionMatched(option2, value) { + var _this$getOptionLabel; + return this.isValidOption(option2) && ((_this$getOptionLabel = this.getOptionLabel(option2)) === null || _this$getOptionLabel === void 0 ? void 0 : _this$getOptionLabel.toLocaleLowerCase(this.searchLocale)) === value.toLocaleLowerCase(this.searchLocale); + }, "isOptionMatched"), + isValidOption: /* @__PURE__ */ __name(function isValidOption(option2) { + return isNotEmpty(option2) && !(this.isOptionDisabled(option2) || this.isOptionGroup(option2)); + }, "isValidOption"), + isValidSelectedOption: /* @__PURE__ */ __name(function isValidSelectedOption(option2) { + return this.isValidOption(option2) && this.isSelected(option2); + }, "isValidSelectedOption"), + isEquals: /* @__PURE__ */ __name(function isEquals(value1, value2) { + return equals(value1, value2, this.equalityKey); + }, "isEquals"), + isSelected: /* @__PURE__ */ __name(function isSelected(option2) { + var _this8 = this; + var optionValue = this.getOptionValue(option2); + return this.multiple ? (this.modelValue || []).some(function(value) { + return _this8.isEquals(value, optionValue); + }) : this.isEquals(this.modelValue, this.getOptionValue(option2)); + }, "isSelected"), + findFirstOptionIndex: /* @__PURE__ */ __name(function findFirstOptionIndex() { + var _this9 = this; + return this.visibleOptions.findIndex(function(option2) { + return _this9.isValidOption(option2); + }); + }, "findFirstOptionIndex"), + findLastOptionIndex: /* @__PURE__ */ __name(function findLastOptionIndex() { + var _this10 = this; + return findLastIndex(this.visibleOptions, function(option2) { + return _this10.isValidOption(option2); + }); + }, "findLastOptionIndex"), + findNextOptionIndex: /* @__PURE__ */ __name(function findNextOptionIndex(index2) { + var _this11 = this; + var matchedOptionIndex = index2 < this.visibleOptions.length - 1 ? this.visibleOptions.slice(index2 + 1).findIndex(function(option2) { + return _this11.isValidOption(option2); + }) : -1; + return matchedOptionIndex > -1 ? matchedOptionIndex + index2 + 1 : index2; + }, "findNextOptionIndex"), + findPrevOptionIndex: /* @__PURE__ */ __name(function findPrevOptionIndex(index2) { + var _this12 = this; + var matchedOptionIndex = index2 > 0 ? findLastIndex(this.visibleOptions.slice(0, index2), function(option2) { + return _this12.isValidOption(option2); + }) : -1; + return matchedOptionIndex > -1 ? matchedOptionIndex : index2; + }, "findPrevOptionIndex"), + findSelectedOptionIndex: /* @__PURE__ */ __name(function findSelectedOptionIndex() { + var _this13 = this; + return this.hasSelectedOption ? this.visibleOptions.findIndex(function(option2) { + return _this13.isValidSelectedOption(option2); + }) : -1; + }, "findSelectedOptionIndex"), + findFirstFocusedOptionIndex: /* @__PURE__ */ __name(function findFirstFocusedOptionIndex() { + var selectedIndex = this.findSelectedOptionIndex(); + return selectedIndex < 0 ? this.findFirstOptionIndex() : selectedIndex; + }, "findFirstFocusedOptionIndex"), + findLastFocusedOptionIndex: /* @__PURE__ */ __name(function findLastFocusedOptionIndex() { + var selectedIndex = this.findSelectedOptionIndex(); + return selectedIndex < 0 ? this.findLastOptionIndex() : selectedIndex; + }, "findLastFocusedOptionIndex"), + search: /* @__PURE__ */ __name(function search(event, query, source) { + if (query === void 0 || query === null) { + return; + } + if (source === "input" && query.trim().length === 0) { + return; + } + this.searching = true; + this.$emit("complete", { + originalEvent: event, + query + }); + }, "search"), + removeOption: /* @__PURE__ */ __name(function removeOption(event, index2) { + var _this14 = this; + var removedOption = this.modelValue[index2]; + var value = this.modelValue.filter(function(_2, i) { + return i !== index2; + }).map(function(option2) { + return _this14.getOptionValue(option2); + }); + this.updateModel(event, value); + this.$emit("item-unselect", { + originalEvent: event, + value: removedOption + }); + this.$emit("option-unselect", { + originalEvent: event, + value: removedOption + }); + this.dirty = true; + focus(this.multiple ? this.$refs.focusInput : this.$refs.focusInput.$el); + }, "removeOption"), + changeFocusedOptionIndex: /* @__PURE__ */ __name(function changeFocusedOptionIndex(event, index2) { + if (this.focusedOptionIndex !== index2) { + this.focusedOptionIndex = index2; + this.scrollInView(); + if (this.selectOnFocus) { + this.onOptionSelect(event, this.visibleOptions[index2], false); + } + } + }, "changeFocusedOptionIndex"), + scrollInView: /* @__PURE__ */ __name(function scrollInView() { + var _this15 = this; + var index2 = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : -1; + this.$nextTick(function() { + var id = index2 !== -1 ? "".concat(_this15.id, "_").concat(index2) : _this15.focusedOptionId; + var element = findSingle(_this15.list, 'li[id="'.concat(id, '"]')); + if (element) { + element.scrollIntoView && element.scrollIntoView({ + block: "nearest", + inline: "start" + }); + } else if (!_this15.virtualScrollerDisabled) { + _this15.virtualScroller && _this15.virtualScroller.scrollToIndex(index2 !== -1 ? index2 : _this15.focusedOptionIndex); + } + }); + }, "scrollInView"), + autoUpdateModel: /* @__PURE__ */ __name(function autoUpdateModel() { + if (this.selectOnFocus && this.autoOptionFocus && !this.hasSelectedOption) { + this.focusedOptionIndex = this.findFirstFocusedOptionIndex(); + this.onOptionSelect(null, this.visibleOptions[this.focusedOptionIndex], false); + } + }, "autoUpdateModel"), + updateModel: /* @__PURE__ */ __name(function updateModel(event, value) { + this.$emit("update:modelValue", value); + this.$emit("change", { + originalEvent: event, + value + }); + }, "updateModel"), + flatOptions: /* @__PURE__ */ __name(function flatOptions(options) { + var _this16 = this; + return (options || []).reduce(function(result, option2, index2) { + result.push({ + optionGroup: option2, + group: true, + index: index2 + }); + var optionGroupChildren = _this16.getOptionGroupChildren(option2); + optionGroupChildren && optionGroupChildren.forEach(function(o) { + return result.push(o); + }); + return result; + }, []); + }, "flatOptions"), + overlayRef: /* @__PURE__ */ __name(function overlayRef(el) { + this.overlay = el; + }, "overlayRef"), + listRef: /* @__PURE__ */ __name(function listRef(el, contentRef) { + this.list = el; + contentRef && contentRef(el); + }, "listRef"), + virtualScrollerRef: /* @__PURE__ */ __name(function virtualScrollerRef(el) { + this.virtualScroller = el; + }, "virtualScrollerRef") + }, + computed: { + visibleOptions: /* @__PURE__ */ __name(function visibleOptions() { + return this.optionGroupLabel ? this.flatOptions(this.suggestions) : this.suggestions || []; + }, "visibleOptions"), + inputValue: /* @__PURE__ */ __name(function inputValue() { + if (isNotEmpty(this.modelValue)) { + if (_typeof$1$3(this.modelValue) === "object") { + var label3 = this.getOptionLabel(this.modelValue); + return label3 != null ? label3 : this.modelValue; + } else { + return this.modelValue; + } + } else { + return ""; + } + }, "inputValue"), + hasSelectedOption: /* @__PURE__ */ __name(function hasSelectedOption() { + return isNotEmpty(this.modelValue); + }, "hasSelectedOption"), + equalityKey: /* @__PURE__ */ __name(function equalityKey() { + return this.dataKey; + }, "equalityKey"), + searchResultMessageText: /* @__PURE__ */ __name(function searchResultMessageText() { + return isNotEmpty(this.visibleOptions) && this.overlayVisible ? this.searchMessageText.replaceAll("{0}", this.visibleOptions.length) : this.emptySearchMessageText; + }, "searchResultMessageText"), + searchMessageText: /* @__PURE__ */ __name(function searchMessageText() { + return this.searchMessage || this.$primevue.config.locale.searchMessage || ""; + }, "searchMessageText"), + emptySearchMessageText: /* @__PURE__ */ __name(function emptySearchMessageText() { + return this.emptySearchMessage || this.$primevue.config.locale.emptySearchMessage || ""; + }, "emptySearchMessageText"), + selectionMessageText: /* @__PURE__ */ __name(function selectionMessageText() { + return this.selectionMessage || this.$primevue.config.locale.selectionMessage || ""; + }, "selectionMessageText"), + emptySelectionMessageText: /* @__PURE__ */ __name(function emptySelectionMessageText() { + return this.emptySelectionMessage || this.$primevue.config.locale.emptySelectionMessage || ""; + }, "emptySelectionMessageText"), + selectedMessageText: /* @__PURE__ */ __name(function selectedMessageText() { + return this.hasSelectedOption ? this.selectionMessageText.replaceAll("{0}", this.multiple ? this.modelValue.length : "1") : this.emptySelectionMessageText; + }, "selectedMessageText"), + listAriaLabel: /* @__PURE__ */ __name(function listAriaLabel() { + return this.$primevue.config.locale.aria ? this.$primevue.config.locale.aria.listLabel : void 0; + }, "listAriaLabel"), + focusedOptionId: /* @__PURE__ */ __name(function focusedOptionId() { + return this.focusedOptionIndex !== -1 ? "".concat(this.id, "_").concat(this.focusedOptionIndex) : null; + }, "focusedOptionId"), + focusedMultipleOptionId: /* @__PURE__ */ __name(function focusedMultipleOptionId() { + return this.focusedMultipleOptionIndex !== -1 ? "".concat(this.id, "_multiple_option_").concat(this.focusedMultipleOptionIndex) : null; + }, "focusedMultipleOptionId"), + ariaSetSize: /* @__PURE__ */ __name(function ariaSetSize() { + var _this17 = this; + return this.visibleOptions.filter(function(option2) { + return !_this17.isOptionGroup(option2); + }).length; + }, "ariaSetSize"), + virtualScrollerDisabled: /* @__PURE__ */ __name(function virtualScrollerDisabled() { + return !this.virtualScrollerOptions; + }, "virtualScrollerDisabled"), + panelId: /* @__PURE__ */ __name(function panelId() { + return this.id + "_panel"; + }, "panelId"), + hasFluid: /* @__PURE__ */ __name(function hasFluid() { + return isEmpty(this.fluid) ? !!this.$pcFluid : this.fluid; + }, "hasFluid") + }, + components: { + InputText: script$m, + VirtualScroller: script$q, + Portal: script$r, + ChevronDownIcon: script$s, + SpinnerIcon: script$t, + Chip: script$u + }, + directives: { + ripple: Ripple + } +}; +function _typeof$7(o) { + "@babel/helpers - typeof"; + return _typeof$7 = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(o2) { + return typeof o2; + } : function(o2) { + return o2 && "function" == typeof Symbol && o2.constructor === Symbol && o2 !== Symbol.prototype ? "symbol" : typeof o2; + }, _typeof$7(o); +} +__name(_typeof$7, "_typeof$7"); +function ownKeys$8(e, r) { + var t = Object.keys(e); + if (Object.getOwnPropertySymbols) { + var o = Object.getOwnPropertySymbols(e); + r && (o = o.filter(function(r2) { + return Object.getOwnPropertyDescriptor(e, r2).enumerable; + })), t.push.apply(t, o); + } + return t; +} +__name(ownKeys$8, "ownKeys$8"); +function _objectSpread$8(e) { + for (var r = 1; r < arguments.length; r++) { + var t = null != arguments[r] ? arguments[r] : {}; + r % 2 ? ownKeys$8(Object(t), true).forEach(function(r2) { + _defineProperty$7(e, r2, t[r2]); + }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$8(Object(t)).forEach(function(r2) { + Object.defineProperty(e, r2, Object.getOwnPropertyDescriptor(t, r2)); + }); + } + return e; +} +__name(_objectSpread$8, "_objectSpread$8"); +function _defineProperty$7(e, r, t) { + return (r = _toPropertyKey$6(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: true, configurable: true, writable: true }) : e[r] = t, e; +} +__name(_defineProperty$7, "_defineProperty$7"); +function _toPropertyKey$6(t) { + var i = _toPrimitive$6(t, "string"); + return "symbol" == _typeof$7(i) ? i : i + ""; +} +__name(_toPropertyKey$6, "_toPropertyKey$6"); +function _toPrimitive$6(t, r) { + if ("object" != _typeof$7(t) || !t) return t; + var e = t[Symbol.toPrimitive]; + if (void 0 !== e) { + var i = e.call(t, r || "default"); + if ("object" != _typeof$7(i)) return i; + throw new TypeError("@@toPrimitive must return a primitive value."); + } + return ("string" === r ? String : Number)(t); +} +__name(_toPrimitive$6, "_toPrimitive$6"); +var _hoisted_1$C = ["aria-activedescendant"]; +var _hoisted_2$s = ["id", "aria-label", "aria-setsize", "aria-posinset"]; +var _hoisted_3$l = ["id", "placeholder", "tabindex", "disabled", "aria-label", "aria-labelledby", "aria-expanded", "aria-controls", "aria-activedescendant", "aria-invalid"]; +var _hoisted_4$e = ["disabled", "aria-expanded", "aria-controls"]; +var _hoisted_5$a = ["id"]; +var _hoisted_6$8 = ["id", "aria-label"]; +var _hoisted_7$5 = ["id"]; +var _hoisted_8$4 = ["id", "aria-label", "aria-selected", "aria-disabled", "aria-setsize", "aria-posinset", "onClick", "onMousemove", "data-p-selected", "data-p-focus", "data-p-disabled"]; +function render$j(_ctx, _cache, $props, $setup, $data, $options) { + var _component_InputText = resolveComponent("InputText"); + var _component_Chip = resolveComponent("Chip"); + var _component_SpinnerIcon = resolveComponent("SpinnerIcon"); + var _component_VirtualScroller = resolveComponent("VirtualScroller"); + var _component_Portal = resolveComponent("Portal"); + var _directive_ripple = resolveDirective("ripple"); + return openBlock(), createElementBlock("div", mergeProps({ + ref: "container", + "class": _ctx.cx("root"), + style: _ctx.sx("root"), + onClick: _cache[11] || (_cache[11] = function() { + return $options.onContainerClick && $options.onContainerClick.apply($options, arguments); + }) + }, _ctx.ptmi("root")), [!_ctx.multiple ? (openBlock(), createBlock(_component_InputText, { + key: 0, + ref: "focusInput", + id: _ctx.inputId, + type: "text", + "class": normalizeClass([_ctx.cx("pcInput"), _ctx.inputClass]), + style: normalizeStyle(_ctx.inputStyle), + value: $options.inputValue, + placeholder: _ctx.placeholder, + tabindex: !_ctx.disabled ? _ctx.tabindex : -1, + fluid: $options.hasFluid, + disabled: _ctx.disabled, + invalid: _ctx.invalid, + variant: _ctx.variant, + autocomplete: "off", + role: "combobox", + "aria-label": _ctx.ariaLabel, + "aria-labelledby": _ctx.ariaLabelledby, + "aria-haspopup": "listbox", + "aria-autocomplete": "list", + "aria-expanded": $data.overlayVisible, + "aria-controls": $options.panelId, + "aria-activedescendant": $data.focused ? $options.focusedOptionId : void 0, + onFocus: $options.onFocus, + onBlur: $options.onBlur, + onKeydown: $options.onKeyDown, + onInput: $options.onInput, + onChange: $options.onChange, + unstyled: _ctx.unstyled, + pt: _ctx.ptm("pcInput") + }, null, 8, ["id", "class", "style", "value", "placeholder", "tabindex", "fluid", "disabled", "invalid", "variant", "aria-label", "aria-labelledby", "aria-expanded", "aria-controls", "aria-activedescendant", "onFocus", "onBlur", "onKeydown", "onInput", "onChange", "unstyled", "pt"])) : createCommentVNode("", true), _ctx.multiple ? (openBlock(), createElementBlock("ul", mergeProps({ + key: 1, + ref: "multiContainer", + "class": _ctx.cx("inputMultiple"), + tabindex: "-1", + role: "listbox", + "aria-orientation": "horizontal", + "aria-activedescendant": $data.focused ? $options.focusedMultipleOptionId : void 0, + onFocus: _cache[5] || (_cache[5] = function() { + return $options.onMultipleContainerFocus && $options.onMultipleContainerFocus.apply($options, arguments); + }), + onBlur: _cache[6] || (_cache[6] = function() { + return $options.onMultipleContainerBlur && $options.onMultipleContainerBlur.apply($options, arguments); + }), + onKeydown: _cache[7] || (_cache[7] = function() { + return $options.onMultipleContainerKeyDown && $options.onMultipleContainerKeyDown.apply($options, arguments); + }) + }, _ctx.ptm("inputMultiple")), [(openBlock(true), createElementBlock(Fragment, null, renderList(_ctx.modelValue, function(option2, i) { + return openBlock(), createElementBlock("li", mergeProps({ + key: "".concat(i, "_").concat($options.getOptionLabel(option2)), + id: $data.id + "_multiple_option_" + i, + "class": _ctx.cx("chipItem", { + i + }), + role: "option", + "aria-label": $options.getOptionLabel(option2), + "aria-selected": true, + "aria-setsize": _ctx.modelValue.length, + "aria-posinset": i + 1, + ref_for: true + }, _ctx.ptm("chipItem")), [renderSlot(_ctx.$slots, "chip", mergeProps({ + "class": _ctx.cx("pcChip"), + value: option2, + index: i, + removeCallback: /* @__PURE__ */ __name(function removeCallback(event) { + return $options.removeOption(event, i); + }, "removeCallback"), + ref_for: true + }, _ctx.ptm("pcChip")), function() { + return [createVNode(_component_Chip, { + "class": normalizeClass(_ctx.cx("pcChip")), + label: $options.getOptionLabel(option2), + removeIcon: _ctx.chipIcon || _ctx.removeTokenIcon, + removable: "", + unstyled: _ctx.unstyled, + onRemove: /* @__PURE__ */ __name(function onRemove2($event) { + return $options.removeOption($event, i); + }, "onRemove"), + pt: _ctx.ptm("pcChip") + }, { + removeicon: withCtx(function() { + return [renderSlot(_ctx.$slots, _ctx.$slots.chipicon ? "chipicon" : "removetokenicon", { + "class": normalizeClass(_ctx.cx("chipIcon")), + index: i, + removeCallback: /* @__PURE__ */ __name(function removeCallback(event) { + return $options.removeOption(event, i); + }, "removeCallback") + })]; + }), + _: 2 + }, 1032, ["class", "label", "removeIcon", "unstyled", "onRemove", "pt"])]; + })], 16, _hoisted_2$s); + }), 128)), createBaseVNode("li", mergeProps({ + "class": _ctx.cx("inputChip"), + role: "option" + }, _ctx.ptm("inputChip")), [createBaseVNode("input", mergeProps({ + ref: "focusInput", + id: _ctx.inputId, + type: "text", + style: _ctx.inputStyle, + "class": _ctx.inputClass, + placeholder: _ctx.placeholder, + tabindex: !_ctx.disabled ? _ctx.tabindex : -1, + disabled: _ctx.disabled, + autocomplete: "off", + role: "combobox", + "aria-label": _ctx.ariaLabel, + "aria-labelledby": _ctx.ariaLabelledby, + "aria-haspopup": "listbox", + "aria-autocomplete": "list", + "aria-expanded": $data.overlayVisible, + "aria-controls": $data.id + "_list", + "aria-activedescendant": $data.focused ? $options.focusedOptionId : void 0, + "aria-invalid": _ctx.invalid || void 0, + onFocus: _cache[0] || (_cache[0] = function() { + return $options.onFocus && $options.onFocus.apply($options, arguments); + }), + onBlur: _cache[1] || (_cache[1] = function() { + return $options.onBlur && $options.onBlur.apply($options, arguments); + }), + onKeydown: _cache[2] || (_cache[2] = function() { + return $options.onKeyDown && $options.onKeyDown.apply($options, arguments); + }), + onInput: _cache[3] || (_cache[3] = function() { + return $options.onInput && $options.onInput.apply($options, arguments); + }), + onChange: _cache[4] || (_cache[4] = function() { + return $options.onChange && $options.onChange.apply($options, arguments); + }) + }, _ctx.ptm("input")), null, 16, _hoisted_3$l)], 16)], 16, _hoisted_1$C)) : createCommentVNode("", true), $data.searching || _ctx.loading ? renderSlot(_ctx.$slots, _ctx.$slots.loader ? "loader" : "loadingicon", { + key: 2, + "class": normalizeClass(_ctx.cx("loader")) + }, function() { + return [_ctx.loader || _ctx.loadingIcon ? (openBlock(), createElementBlock("i", mergeProps({ + key: 0, + "class": ["pi-spin", _ctx.cx("loader"), _ctx.loader, _ctx.loadingIcon], + "aria-hidden": "true" + }, _ctx.ptm("loader")), null, 16)) : (openBlock(), createBlock(_component_SpinnerIcon, mergeProps({ + key: 1, + "class": _ctx.cx("loader"), + spin: "", + "aria-hidden": "true" + }, _ctx.ptm("loader")), null, 16, ["class"]))]; + }) : createCommentVNode("", true), renderSlot(_ctx.$slots, _ctx.$slots.dropdown ? "dropdown" : "dropdownbutton", { + toggleCallback: /* @__PURE__ */ __name(function toggleCallback(event) { + return $options.onDropdownClick(event); + }, "toggleCallback") + }, function() { + return [_ctx.dropdown ? (openBlock(), createElementBlock("button", mergeProps({ + key: 0, + ref: "dropdownButton", + type: "button", + "class": [_ctx.cx("dropdown"), _ctx.dropdownClass], + disabled: _ctx.disabled, + "aria-haspopup": "listbox", + "aria-expanded": $data.overlayVisible, + "aria-controls": $options.panelId, + onClick: _cache[8] || (_cache[8] = function() { + return $options.onDropdownClick && $options.onDropdownClick.apply($options, arguments); + }) + }, _ctx.ptm("dropdown")), [renderSlot(_ctx.$slots, "dropdownicon", { + "class": normalizeClass(_ctx.dropdownIcon) + }, function() { + return [(openBlock(), createBlock(resolveDynamicComponent(_ctx.dropdownIcon ? "span" : "ChevronDownIcon"), mergeProps({ + "class": _ctx.dropdownIcon + }, _ctx.ptm("dropdownIcon")), null, 16, ["class"]))]; + })], 16, _hoisted_4$e)) : createCommentVNode("", true)]; + }), createBaseVNode("span", mergeProps({ + role: "status", + "aria-live": "polite", + "class": "p-hidden-accessible" + }, _ctx.ptm("hiddenSearchResult"), { + "data-p-hidden-accessible": true + }), toDisplayString($options.searchResultMessageText), 17), createVNode(_component_Portal, { + appendTo: _ctx.appendTo + }, { + "default": withCtx(function() { + return [createVNode(Transition, mergeProps({ + name: "p-connected-overlay", + onEnter: $options.onOverlayEnter, + onAfterEnter: $options.onOverlayAfterEnter, + onLeave: $options.onOverlayLeave, + onAfterLeave: $options.onOverlayAfterLeave + }, _ctx.ptm("transition")), { + "default": withCtx(function() { + return [$data.overlayVisible ? (openBlock(), createElementBlock("div", mergeProps({ + key: 0, + ref: $options.overlayRef, + id: $options.panelId, + "class": [_ctx.cx("overlay"), _ctx.panelClass, _ctx.overlayClass], + style: _objectSpread$8(_objectSpread$8(_objectSpread$8({}, _ctx.panelStyle), _ctx.overlayStyle), {}, { + "max-height": $options.virtualScrollerDisabled ? _ctx.scrollHeight : "" + }), + onClick: _cache[9] || (_cache[9] = function() { + return $options.onOverlayClick && $options.onOverlayClick.apply($options, arguments); + }), + onKeydown: _cache[10] || (_cache[10] = function() { + return $options.onOverlayKeyDown && $options.onOverlayKeyDown.apply($options, arguments); + }) + }, _ctx.ptm("overlay")), [renderSlot(_ctx.$slots, "header", { + value: _ctx.modelValue, + suggestions: $options.visibleOptions + }), createVNode(_component_VirtualScroller, mergeProps({ + ref: $options.virtualScrollerRef + }, _ctx.virtualScrollerOptions, { + style: { + height: _ctx.scrollHeight + }, + items: $options.visibleOptions, + tabindex: -1, + disabled: $options.virtualScrollerDisabled, + pt: _ctx.ptm("virtualScroller") + }), createSlots({ + content: withCtx(function(_ref) { + var styleClass = _ref.styleClass, contentRef = _ref.contentRef, items = _ref.items, getItemOptions = _ref.getItemOptions, contentStyle = _ref.contentStyle, itemSize = _ref.itemSize; + return [createBaseVNode("ul", mergeProps({ + ref: /* @__PURE__ */ __name(function ref2(el) { + return $options.listRef(el, contentRef); + }, "ref"), + id: $data.id + "_list", + "class": [_ctx.cx("list"), styleClass], + style: contentStyle, + role: "listbox", + "aria-label": $options.listAriaLabel + }, _ctx.ptm("list")), [(openBlock(true), createElementBlock(Fragment, null, renderList(items, function(option2, i) { + return openBlock(), createElementBlock(Fragment, { + key: $options.getOptionRenderKey(option2, $options.getOptionIndex(i, getItemOptions)) + }, [$options.isOptionGroup(option2) ? (openBlock(), createElementBlock("li", mergeProps({ + key: 0, + id: $data.id + "_" + $options.getOptionIndex(i, getItemOptions), + style: { + height: itemSize ? itemSize + "px" : void 0 + }, + "class": _ctx.cx("optionGroup"), + role: "option", + ref_for: true + }, _ctx.ptm("optionGroup")), [renderSlot(_ctx.$slots, "optiongroup", { + option: option2.optionGroup, + index: $options.getOptionIndex(i, getItemOptions) + }, function() { + return [createTextVNode(toDisplayString($options.getOptionGroupLabel(option2.optionGroup)), 1)]; + })], 16, _hoisted_7$5)) : withDirectives((openBlock(), createElementBlock("li", mergeProps({ + key: 1, + id: $data.id + "_" + $options.getOptionIndex(i, getItemOptions), + style: { + height: itemSize ? itemSize + "px" : void 0 + }, + "class": _ctx.cx("option", { + option: option2, + i, + getItemOptions + }), + role: "option", + "aria-label": $options.getOptionLabel(option2), + "aria-selected": $options.isSelected(option2), + "aria-disabled": $options.isOptionDisabled(option2), + "aria-setsize": $options.ariaSetSize, + "aria-posinset": $options.getAriaPosInset($options.getOptionIndex(i, getItemOptions)), + onClick: /* @__PURE__ */ __name(function onClick2($event) { + return $options.onOptionSelect($event, option2); + }, "onClick"), + onMousemove: /* @__PURE__ */ __name(function onMousemove($event) { + return $options.onOptionMouseMove($event, $options.getOptionIndex(i, getItemOptions)); + }, "onMousemove"), + "data-p-selected": $options.isSelected(option2), + "data-p-focus": $data.focusedOptionIndex === $options.getOptionIndex(i, getItemOptions), + "data-p-disabled": $options.isOptionDisabled(option2), + ref_for: true + }, $options.getPTOptions(option2, getItemOptions, i, "option")), [renderSlot(_ctx.$slots, "option", { + option: option2, + index: $options.getOptionIndex(i, getItemOptions) + }, function() { + return [createTextVNode(toDisplayString($options.getOptionLabel(option2)), 1)]; + })], 16, _hoisted_8$4)), [[_directive_ripple]])], 64); + }), 128)), !items || items && items.length === 0 ? (openBlock(), createElementBlock("li", mergeProps({ + key: 0, + "class": _ctx.cx("emptyMessage"), + role: "option" + }, _ctx.ptm("emptyMessage")), [renderSlot(_ctx.$slots, "empty", {}, function() { + return [createTextVNode(toDisplayString($options.searchResultMessageText), 1)]; + })], 16)) : createCommentVNode("", true)], 16, _hoisted_6$8)]; + }), + _: 2 + }, [_ctx.$slots.loader ? { + name: "loader", + fn: withCtx(function(_ref2) { + var options = _ref2.options; + return [renderSlot(_ctx.$slots, "loader", { + options + })]; + }), + key: "0" + } : void 0]), 1040, ["style", "items", "disabled", "pt"]), renderSlot(_ctx.$slots, "footer", { + value: _ctx.modelValue, + suggestions: $options.visibleOptions + }), createBaseVNode("span", mergeProps({ + role: "status", + "aria-live": "polite", + "class": "p-hidden-accessible" + }, _ctx.ptm("hiddenSelectedMessage"), { + "data-p-hidden-accessible": true + }), toDisplayString($options.selectedMessageText), 17)], 16, _hoisted_5$a)) : createCommentVNode("", true)]; + }), + _: 3 + }, 16, ["onEnter", "onAfterEnter", "onLeave", "onAfterLeave"])]; + }), + _: 3 + }, 8, ["appendTo"])], 16); +} +__name(render$j, "render$j"); +script$i.render = render$j; +const _sfc_main$B = { + name: "AutoCompletePlus", + extends: script$i, + emits: ["focused-option-changed"], + mounted() { + if (typeof script$i.mounted === "function") { + script$i.mounted.call(this); + } + this.$watch( + () => this.focusedOptionIndex, + (newVal, oldVal) => { + this.$emit("focused-option-changed", newVal); + } + ); + } +}; +var theme$e = /* @__PURE__ */ __name(function theme4(_ref) { + var dt = _ref.dt; + return "\n.p-togglebutton {\n display: inline-flex;\n cursor: pointer;\n user-select: none;\n align-items: center;\n justify-content: center;\n overflow: hidden;\n position: relative;\n color: ".concat(dt("togglebutton.color"), ";\n background: ").concat(dt("togglebutton.background"), ";\n border: 1px solid ").concat(dt("togglebutton.border.color"), ";\n padding: ").concat(dt("togglebutton.padding"), ";\n font-size: 1rem;\n font-family: inherit;\n font-feature-settings: inherit;\n transition: background ").concat(dt("togglebutton.transition.duration"), ", color ").concat(dt("togglebutton.transition.duration"), ", border-color ").concat(dt("togglebutton.transition.duration"), ",\n outline-color ").concat(dt("togglebutton.transition.duration"), ", box-shadow ").concat(dt("togglebutton.transition.duration"), ";\n border-radius: ").concat(dt("togglebutton.border.radius"), ";\n outline-color: transparent;\n font-weight: ").concat(dt("togglebutton.font.weight"), ";\n}\n\n.p-togglebutton-content {\n position: relative;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: ").concat(dt("togglebutton.gap"), ';\n}\n\n.p-togglebutton-label,\n.p-togglebutton-icon {\n position: relative;\n transition: none;\n}\n\n.p-togglebutton::before {\n content: "";\n background: transparent;\n transition: background ').concat(dt("togglebutton.transition.duration"), ", color ").concat(dt("togglebutton.transition.duration"), ", border-color ").concat(dt("togglebutton.transition.duration"), ",\n outline-color ").concat(dt("togglebutton.transition.duration"), ", box-shadow ").concat(dt("togglebutton.transition.duration"), ";\n position: absolute;\n left: ").concat(dt("togglebutton.content.left"), ";\n top: ").concat(dt("togglebutton.content.top"), ";\n width: calc(100% - calc(2 * ").concat(dt("togglebutton.content.left"), "));\n height: calc(100% - calc(2 * ").concat(dt("togglebutton.content.top"), "));\n border-radius: ").concat(dt("togglebutton.border.radius"), ";\n}\n\n.p-togglebutton.p-togglebutton-checked::before {\n background: ").concat(dt("togglebutton.content.checked.background"), ";\n box-shadow: ").concat(dt("togglebutton.content.checked.shadow"), ";\n}\n\n.p-togglebutton:not(:disabled):not(.p-togglebutton-checked):hover {\n background: ").concat(dt("togglebutton.hover.background"), ";\n color: ").concat(dt("togglebutton.hover.color"), ";\n}\n\n.p-togglebutton.p-togglebutton-checked {\n background: ").concat(dt("togglebutton.checked.background"), ";\n border-color: ").concat(dt("togglebutton.checked.border.color"), ";\n color: ").concat(dt("togglebutton.checked.color"), ";\n}\n\n.p-togglebutton:focus-visible {\n box-shadow: ").concat(dt("togglebutton.focus.ring.shadow"), ";\n outline: ").concat(dt("togglebutton.focus.ring.width"), " ").concat(dt("togglebutton.focus.ring.style"), " ").concat(dt("togglebutton.focus.ring.color"), ";\n outline-offset: ").concat(dt("togglebutton.focus.ring.offset"), ";\n}\n\n.p-togglebutton.p-invalid {\n border-color: ").concat(dt("togglebutton.invalid.border.color"), ";\n}\n\n.p-togglebutton:disabled {\n opacity: 1;\n cursor: default;\n background: ").concat(dt("togglebutton.disabled.background"), ";\n border-color: ").concat(dt("togglebutton.disabled.border.color"), ";\n color: ").concat(dt("togglebutton.disabled.color"), ";\n}\n\n.p-togglebutton-icon {\n color: ").concat(dt("togglebutton.icon.color"), ";\n}\n\n.p-togglebutton:not(:disabled):not(.p-togglebutton-checked):hover .p-togglebutton-icon {\n color: ").concat(dt("togglebutton.icon.hover.color"), ";\n}\n\n.p-togglebutton.p-togglebutton-checked .p-togglebutton-icon {\n color: ").concat(dt("togglebutton.icon.checked.color"), ";\n}\n\n.p-togglebutton:disabled .p-togglebutton-icon {\n color: ").concat(dt("togglebutton.icon.disabled.color"), ";\n}\n"); +}, "theme"); +var classes$e = { + root: /* @__PURE__ */ __name(function root5(_ref2) { + var instance = _ref2.instance, props = _ref2.props; + return ["p-togglebutton p-component", { + "p-togglebutton-checked": instance.active, + "p-invalid": props.invalid + }]; + }, "root"), + content: "p-togglebutton-content", + icon: "p-togglebutton-icon", + label: "p-togglebutton-label" +}; +var ToggleButtonStyle = BaseStyle.extend({ + name: "togglebutton", + theme: theme$e, + classes: classes$e +}); +var script$1$e = { + name: "BaseToggleButton", + "extends": script$p, + props: { + modelValue: Boolean, + onIcon: String, + offIcon: String, + onLabel: { + type: String, + "default": "Yes" + }, + offLabel: { + type: String, + "default": "No" + }, + iconPos: { + type: String, + "default": "left" + }, + invalid: { + type: Boolean, + "default": false + }, + disabled: { + type: Boolean, + "default": false + }, + readonly: { + type: Boolean, + "default": false + }, + tabindex: { + type: Number, + "default": null + }, + ariaLabelledby: { + type: String, + "default": null + }, + ariaLabel: { + type: String, + "default": null + } + }, + style: ToggleButtonStyle, + provide: /* @__PURE__ */ __name(function provide6() { + return { + $pcToggleButton: this, + $parentInstance: this + }; + }, "provide") +}; +var script$h = { + name: "ToggleButton", + "extends": script$1$e, + inheritAttrs: false, + emits: ["update:modelValue", "change"], + methods: { + getPTOptions: /* @__PURE__ */ __name(function getPTOptions4(key) { + var _ptm = key === "root" ? this.ptmi : this.ptm; + return _ptm(key, { + context: { + active: this.active, + disabled: this.disabled + } + }); + }, "getPTOptions"), + onChange: /* @__PURE__ */ __name(function onChange2(event) { + if (!this.disabled && !this.readonly) { + this.$emit("update:modelValue", !this.modelValue); + this.$emit("change", event); + } + }, "onChange") + }, + computed: { + active: /* @__PURE__ */ __name(function active() { + return this.modelValue === true; + }, "active"), + hasLabel: /* @__PURE__ */ __name(function hasLabel() { + return isNotEmpty(this.onLabel) && isNotEmpty(this.offLabel); + }, "hasLabel"), + label: /* @__PURE__ */ __name(function label() { + return this.hasLabel ? this.modelValue ? this.onLabel : this.offLabel : " "; + }, "label") + }, + directives: { + ripple: Ripple + } +}; +var _hoisted_1$B = ["tabindex", "disabled", "aria-pressed", "data-p-checked", "data-p-disabled"]; +function render$i(_ctx, _cache, $props, $setup, $data, $options) { + var _directive_ripple = resolveDirective("ripple"); + return withDirectives((openBlock(), createElementBlock("button", mergeProps({ + type: "button", + "class": _ctx.cx("root"), + tabindex: _ctx.tabindex, + disabled: _ctx.disabled, + "aria-pressed": _ctx.modelValue, + onClick: _cache[0] || (_cache[0] = function() { + return $options.onChange && $options.onChange.apply($options, arguments); + }) + }, $options.getPTOptions("root"), { + "data-p-checked": $options.active, + "data-p-disabled": _ctx.disabled + }), [createBaseVNode("span", mergeProps({ + "class": _ctx.cx("content") + }, $options.getPTOptions("content")), [renderSlot(_ctx.$slots, "default", {}, function() { + return [renderSlot(_ctx.$slots, "icon", { + value: _ctx.modelValue, + "class": normalizeClass(_ctx.cx("icon")) + }, function() { + return [_ctx.onIcon || _ctx.offIcon ? (openBlock(), createElementBlock("span", mergeProps({ + key: 0, + "class": [_ctx.cx("icon"), _ctx.modelValue ? _ctx.onIcon : _ctx.offIcon] + }, $options.getPTOptions("icon")), null, 16)) : createCommentVNode("", true)]; + }), createBaseVNode("span", mergeProps({ + "class": _ctx.cx("label") + }, $options.getPTOptions("label")), toDisplayString($options.label), 17)]; + })], 16)], 16, _hoisted_1$B)), [[_directive_ripple]]); +} +__name(render$i, "render$i"); +script$h.render = render$i; +var theme$d = /* @__PURE__ */ __name(function theme5(_ref) { + var dt = _ref.dt; + return "\n.p-selectbutton {\n display: inline-flex;\n user-select: none;\n vertical-align: bottom;\n outline-color: transparent;\n border-radius: ".concat(dt("selectbutton.border.radius"), ";\n}\n\n.p-selectbutton .p-togglebutton {\n border-radius: 0;\n border-width: 1px 1px 1px 0;\n}\n\n.p-selectbutton .p-togglebutton:focus-visible {\n position: relative;\n z-index: 1;\n}\n\n.p-selectbutton .p-togglebutton:first-child {\n border-left-width: 1px;\n border-top-left-radius: ").concat(dt("selectbutton.border.radius"), ";\n border-bottom-left-radius: ").concat(dt("selectbutton.border.radius"), ";\n}\n\n.p-selectbutton .p-togglebutton:last-child {\n border-top-right-radius: ").concat(dt("selectbutton.border.radius"), ";\n border-bottom-right-radius: ").concat(dt("selectbutton.border.radius"), ";\n}\n\n.p-selectbutton.p-invalid {\n outline: 1px solid ").concat(dt("selectbutton.invalid.border.color"), ";\n outline-offset: 0;\n}\n"); +}, "theme"); +var classes$d = { + root: /* @__PURE__ */ __name(function root6(_ref2) { + var props = _ref2.props; + return ["p-selectbutton p-component", { + "p-invalid": props.invalid + }]; + }, "root") +}; +var SelectButtonStyle = BaseStyle.extend({ + name: "selectbutton", + theme: theme$d, + classes: classes$d +}); +var script$1$d = { + name: "BaseSelectButton", + "extends": script$p, + props: { + modelValue: null, + options: Array, + optionLabel: null, + optionValue: null, + optionDisabled: null, + multiple: Boolean, + allowEmpty: { + type: Boolean, + "default": true + }, + invalid: { + type: Boolean, + "default": false + }, + disabled: Boolean, + dataKey: null, + ariaLabelledby: { + type: String, + "default": null + } + }, + style: SelectButtonStyle, + provide: /* @__PURE__ */ __name(function provide7() { + return { + $pcSelectButton: this, + $parentInstance: this + }; + }, "provide") +}; +function _createForOfIteratorHelper$4(r, e) { + var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; + if (!t) { + if (Array.isArray(r) || (t = _unsupportedIterableToArray$7(r)) || e) { + t && (r = t); + var _n = 0, F = /* @__PURE__ */ __name(function F2() { + }, "F"); + return { s: F, n: /* @__PURE__ */ __name(function n() { + return _n >= r.length ? { done: true } : { done: false, value: r[_n++] }; + }, "n"), e: /* @__PURE__ */ __name(function e2(r2) { + throw r2; + }, "e"), f: F }; + } + throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); + } + var o, a = true, u = false; + return { s: /* @__PURE__ */ __name(function s() { + t = t.call(r); + }, "s"), n: /* @__PURE__ */ __name(function n() { + var r2 = t.next(); + return a = r2.done, r2; + }, "n"), e: /* @__PURE__ */ __name(function e2(r2) { + u = true, o = r2; + }, "e"), f: /* @__PURE__ */ __name(function f() { + try { + a || null == t["return"] || t["return"](); + } finally { + if (u) throw o; + } + }, "f") }; +} +__name(_createForOfIteratorHelper$4, "_createForOfIteratorHelper$4"); +function _toConsumableArray$5(r) { + return _arrayWithoutHoles$5(r) || _iterableToArray$5(r) || _unsupportedIterableToArray$7(r) || _nonIterableSpread$5(); +} +__name(_toConsumableArray$5, "_toConsumableArray$5"); +function _nonIterableSpread$5() { + throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); +} +__name(_nonIterableSpread$5, "_nonIterableSpread$5"); +function _unsupportedIterableToArray$7(r, a) { + if (r) { + if ("string" == typeof r) return _arrayLikeToArray$7(r, a); + var t = {}.toString.call(r).slice(8, -1); + return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray$7(r, a) : void 0; + } +} +__name(_unsupportedIterableToArray$7, "_unsupportedIterableToArray$7"); +function _iterableToArray$5(r) { + if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); +} +__name(_iterableToArray$5, "_iterableToArray$5"); +function _arrayWithoutHoles$5(r) { + if (Array.isArray(r)) return _arrayLikeToArray$7(r); +} +__name(_arrayWithoutHoles$5, "_arrayWithoutHoles$5"); +function _arrayLikeToArray$7(r, a) { + (null == a || a > r.length) && (a = r.length); + for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; + return n; +} +__name(_arrayLikeToArray$7, "_arrayLikeToArray$7"); +var script$g = { + name: "SelectButton", + "extends": script$1$d, + inheritAttrs: false, + emits: ["update:modelValue", "change"], + methods: { + getOptionLabel: /* @__PURE__ */ __name(function getOptionLabel2(option2) { + return this.optionLabel ? resolveFieldData(option2, this.optionLabel) : option2; + }, "getOptionLabel"), + getOptionValue: /* @__PURE__ */ __name(function getOptionValue2(option2) { + return this.optionValue ? resolveFieldData(option2, this.optionValue) : option2; + }, "getOptionValue"), + getOptionRenderKey: /* @__PURE__ */ __name(function getOptionRenderKey2(option2) { + return this.dataKey ? resolveFieldData(option2, this.dataKey) : this.getOptionLabel(option2); + }, "getOptionRenderKey"), + getPTOptions: /* @__PURE__ */ __name(function getPTOptions5(option2, key) { + return this.ptm(key, { + context: { + active: this.isSelected(option2), + disabled: this.isOptionDisabled(option2), + option: option2 + } + }); + }, "getPTOptions"), + isOptionDisabled: /* @__PURE__ */ __name(function isOptionDisabled2(option2) { + return this.optionDisabled ? resolveFieldData(option2, this.optionDisabled) : false; + }, "isOptionDisabled"), + onOptionSelect: /* @__PURE__ */ __name(function onOptionSelect2(event, option2, index2) { + var _this = this; + if (this.disabled || this.isOptionDisabled(option2)) { + return; + } + var selected2 = this.isSelected(option2); + if (selected2 && !this.allowEmpty) { + return; + } + var optionValue = this.getOptionValue(option2); + var newValue; + if (this.multiple) { + if (selected2) newValue = this.modelValue.filter(function(val) { + return !equals(val, optionValue, _this.equalityKey); + }); + else newValue = this.modelValue ? [].concat(_toConsumableArray$5(this.modelValue), [optionValue]) : [optionValue]; + } else { + newValue = selected2 ? null : optionValue; + } + this.focusedIndex = index2; + this.$emit("update:modelValue", newValue); + this.$emit("change", { + event, + value: newValue + }); + }, "onOptionSelect"), + isSelected: /* @__PURE__ */ __name(function isSelected2(option2) { + var selected2 = false; + var optionValue = this.getOptionValue(option2); + if (this.multiple) { + if (this.modelValue) { + var _iterator = _createForOfIteratorHelper$4(this.modelValue), _step; + try { + for (_iterator.s(); !(_step = _iterator.n()).done; ) { + var val = _step.value; + if (equals(val, optionValue, this.equalityKey)) { + selected2 = true; + break; + } + } + } catch (err) { + _iterator.e(err); + } finally { + _iterator.f(); + } + } + } else { + selected2 = equals(this.modelValue, optionValue, this.equalityKey); + } + return selected2; + }, "isSelected") + }, + computed: { + equalityKey: /* @__PURE__ */ __name(function equalityKey2() { + return this.optionValue ? null : this.dataKey; + }, "equalityKey") + }, + directives: { + ripple: Ripple + }, + components: { + ToggleButton: script$h + } +}; +var _hoisted_1$A = ["aria-labelledby"]; +function render$h(_ctx, _cache, $props, $setup, $data, $options) { + var _component_ToggleButton = resolveComponent("ToggleButton"); + return openBlock(), createElementBlock("div", mergeProps({ + "class": _ctx.cx("root"), + role: "group", + "aria-labelledby": _ctx.ariaLabelledby + }, _ctx.ptmi("root")), [(openBlock(true), createElementBlock(Fragment, null, renderList(_ctx.options, function(option2, index2) { + return openBlock(), createBlock(_component_ToggleButton, { + key: $options.getOptionRenderKey(option2), + modelValue: $options.isSelected(option2), + onLabel: $options.getOptionLabel(option2), + offLabel: $options.getOptionLabel(option2), + disabled: _ctx.disabled || $options.isOptionDisabled(option2), + unstyled: _ctx.unstyled, + onChange: /* @__PURE__ */ __name(function onChange3($event) { + return $options.onOptionSelect($event, option2, index2); + }, "onChange"), + pt: _ctx.ptm("pcButton") + }, createSlots({ + _: 2 + }, [_ctx.$slots.option ? { + name: "default", + fn: withCtx(function() { + return [renderSlot(_ctx.$slots, "option", { + option: option2, + index: index2 + }, function() { + return [createBaseVNode("span", mergeProps({ + ref_for: true + }, _ctx.ptm("pcButton")["label"]), toDisplayString($options.getOptionLabel(option2)), 17)]; + })]; + }), + key: "0" + } : void 0]), 1032, ["modelValue", "onLabel", "offLabel", "disabled", "unstyled", "onChange", "pt"]); + }), 128))], 16, _hoisted_1$A); +} +__name(render$h, "render$h"); +script$g.render = render$h; +const _withScopeId$j = /* @__PURE__ */ __name((n) => (pushScopeId("data-v-e7b35fd9"), n = n(), popScopeId(), n), "_withScopeId$j"); +const _hoisted_1$z = { class: "_content" }; +const _hoisted_2$r = { class: "_footer" }; +const _sfc_main$A = /* @__PURE__ */ defineComponent({ + __name: "NodeSearchFilter", + emits: ["addFilter"], + setup(__props, { emit: __emit }) { + const filters = computed(() => nodeDefStore.nodeSearchService.nodeFilters); + const selectedFilter = ref(); + const filterValues = computed(() => selectedFilter.value?.fuseSearch.data ?? []); + const selectedFilterValue = ref(""); + const nodeDefStore = useNodeDefStore(); + onMounted(() => { + selectedFilter.value = nodeDefStore.nodeSearchService.nodeFilters[0]; + updateSelectedFilterValue(); + }); + const emit = __emit; + const updateSelectedFilterValue = /* @__PURE__ */ __name(() => { + if (filterValues.value.includes(selectedFilterValue.value)) { + return; + } + selectedFilterValue.value = filterValues.value[0]; + }, "updateSelectedFilterValue"); + const submit = /* @__PURE__ */ __name(() => { + emit("addFilter", [ + selectedFilter.value, + selectedFilterValue.value + ]); + }, "submit"); + return (_ctx, _cache) => { + return openBlock(), createElementBlock(Fragment, null, [ + createBaseVNode("div", _hoisted_1$z, [ + createVNode(unref(script$g), { + class: "filter-type-select", + modelValue: selectedFilter.value, + "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => selectedFilter.value = $event), + options: filters.value, + allowEmpty: false, + optionLabel: "name", + onChange: updateSelectedFilterValue + }, null, 8, ["modelValue", "options"]), + createVNode(unref(script$v), { + class: "filter-value-select", + modelValue: selectedFilterValue.value, + "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => selectedFilterValue.value = $event), + options: filterValues.value, + filter: "" + }, null, 8, ["modelValue", "options"]) + ]), + createBaseVNode("div", _hoisted_2$r, [ + createVNode(unref(script$o), { + type: "button", + label: _ctx.$t("add"), + onClick: submit + }, null, 8, ["label"]) + ]) + ], 64); + }; + } +}); +const NodeSearchFilter = /* @__PURE__ */ _export_sfc(_sfc_main$A, [["__scopeId", "data-v-e7b35fd9"]]); +const BOOKMARK_SETTING_ID = "Comfy.NodeLibrary.Bookmarks.V2"; +const useNodeBookmarkStore = defineStore("nodeBookmark", () => { + const settingStore = useSettingStore(); + const nodeDefStore = useNodeDefStore(); + const migrateLegacyBookmarks = /* @__PURE__ */ __name(() => { + settingStore.get("Comfy.NodeLibrary.Bookmarks").forEach((bookmark) => { + if (bookmark.endsWith("/")) { + addBookmark(bookmark); + return; + } + const category = bookmark.split("/").slice(0, -1).join("/"); + const displayName = bookmark.split("/").pop(); + const nodeDef = nodeDefStore.nodeDefsByDisplayName[displayName]; + if (!nodeDef) return; + addBookmark(`${category === "" ? "" : category + "/"}${nodeDef.name}`); + }); + settingStore.set("Comfy.NodeLibrary.Bookmarks", []); + }, "migrateLegacyBookmarks"); + const bookmarks = computed( + () => settingStore.get(BOOKMARK_SETTING_ID) + ); + const bookmarksSet = computed(() => new Set(bookmarks.value)); + const bookmarkedRoot = computed( + () => buildBookmarkTree(bookmarks.value) + ); + const isBookmarked = /* @__PURE__ */ __name((node2) => bookmarksSet.value.has(node2.nodePath) || bookmarksSet.value.has(node2.name), "isBookmarked"); + const toggleBookmark = /* @__PURE__ */ __name((node2) => { + if (isBookmarked(node2)) { + deleteBookmark(node2.nodePath); + deleteBookmark(node2.name); + } else { + addBookmark(node2.name); + } + }, "toggleBookmark"); + const buildBookmarkTree = /* @__PURE__ */ __name((bookmarks2) => { + const bookmarkNodes = bookmarks2.map((bookmark) => { + if (bookmark.endsWith("/")) return createDummyFolderNodeDef(bookmark); + const parts = bookmark.split("/"); + const name = parts.pop(); + const category = parts.join("/"); + const srcNodeDef = nodeDefStore.nodeDefsByName[name]; + if (!srcNodeDef) { + return null; + } + const nodeDef = _.clone(srcNodeDef); + nodeDef.category = category; + return nodeDef; + }).filter((nodeDef) => nodeDef !== null); + return buildNodeDefTree(bookmarkNodes); + }, "buildBookmarkTree"); + const addBookmark = /* @__PURE__ */ __name((nodePath) => { + settingStore.set(BOOKMARK_SETTING_ID, [...bookmarks.value, nodePath]); + }, "addBookmark"); + const deleteBookmark = /* @__PURE__ */ __name((nodePath) => { + settingStore.set( + BOOKMARK_SETTING_ID, + bookmarks.value.filter((b) => b !== nodePath) + ); + }, "deleteBookmark"); + const addNewBookmarkFolder = /* @__PURE__ */ __name((parent) => { + const parentPath = parent ? parent.nodePath : ""; + let newFolderPath = parentPath + "New Folder/"; + let suffix = 1; + while (bookmarks.value.some((b) => b.startsWith(newFolderPath))) { + newFolderPath = parentPath + `New Folder ${suffix}/`; + suffix++; + } + addBookmark(newFolderPath); + return newFolderPath; + }, "addNewBookmarkFolder"); + const renameBookmarkFolder = /* @__PURE__ */ __name((folderNode, newName) => { + if (!folderNode.isDummyFolder) { + throw new Error("Cannot rename non-folder node"); + } + const newNodePath = folderNode.category.split("/").slice(0, -1).concat(newName).join("/") + "/"; + if (newNodePath === folderNode.nodePath) { + return; + } + if (bookmarks.value.some((b) => b.startsWith(newNodePath))) { + throw new Error(`Folder name "${newNodePath}" already exists`); + } + settingStore.set( + BOOKMARK_SETTING_ID, + bookmarks.value.map( + (b) => b.startsWith(folderNode.nodePath) ? b.replace(folderNode.nodePath, newNodePath) : b + ) + ); + renameBookmarkCustomization(folderNode.nodePath, newNodePath); + }, "renameBookmarkFolder"); + const deleteBookmarkFolder = /* @__PURE__ */ __name((folderNode) => { + if (!folderNode.isDummyFolder) { + throw new Error("Cannot delete non-folder node"); + } + settingStore.set( + BOOKMARK_SETTING_ID, + bookmarks.value.filter( + (b) => b !== folderNode.nodePath && !b.startsWith(folderNode.nodePath) + ) + ); + deleteBookmarkCustomization(folderNode.nodePath); + }, "deleteBookmarkFolder"); + const bookmarksCustomization = computed(() => settingStore.get("Comfy.NodeLibrary.BookmarksCustomization")); + const updateBookmarkCustomization = /* @__PURE__ */ __name((nodePath, customization) => { + const currentCustomization = bookmarksCustomization.value[nodePath] || {}; + const newCustomization = { ...currentCustomization, ...customization }; + if (newCustomization.icon === defaultBookmarkIcon) { + delete newCustomization.icon; + } + if (newCustomization.color === defaultBookmarkColor) { + delete newCustomization.color; + } + if (Object.keys(newCustomization).length === 0) { + deleteBookmarkCustomization(nodePath); + } else { + settingStore.set("Comfy.NodeLibrary.BookmarksCustomization", { + ...bookmarksCustomization.value, + [nodePath]: newCustomization + }); + } + }, "updateBookmarkCustomization"); + const deleteBookmarkCustomization = /* @__PURE__ */ __name((nodePath) => { + settingStore.set("Comfy.NodeLibrary.BookmarksCustomization", { + ...bookmarksCustomization.value, + [nodePath]: void 0 + }); + }, "deleteBookmarkCustomization"); + const renameBookmarkCustomization = /* @__PURE__ */ __name((oldNodePath, newNodePath) => { + const updatedCustomization = { ...bookmarksCustomization.value }; + if (updatedCustomization[oldNodePath]) { + updatedCustomization[newNodePath] = updatedCustomization[oldNodePath]; + delete updatedCustomization[oldNodePath]; + } + settingStore.set( + "Comfy.NodeLibrary.BookmarksCustomization", + updatedCustomization + ); + }, "renameBookmarkCustomization"); + const defaultBookmarkIcon = "pi-bookmark-fill"; + const defaultBookmarkColor = "#a1a1aa"; + return { + bookmarks, + bookmarkedRoot, + isBookmarked, + toggleBookmark, + addBookmark, + addNewBookmarkFolder, + renameBookmarkFolder, + deleteBookmarkFolder, + bookmarksCustomization, + updateBookmarkCustomization, + deleteBookmarkCustomization, + renameBookmarkCustomization, + defaultBookmarkIcon, + defaultBookmarkColor, + migrateLegacyBookmarks + }; +}); +const _withScopeId$i = /* @__PURE__ */ __name((n) => (pushScopeId("data-v-37f672ab"), n = n(), popScopeId(), n), "_withScopeId$i"); +const _hoisted_1$y = { class: "option-container flex justify-between items-center px-2 py-0 cursor-pointer overflow-hidden w-full" }; +const _hoisted_2$q = { class: "option-display-name font-semibold flex flex-col" }; +const _hoisted_3$k = { key: 0 }; +const _hoisted_4$d = /* @__PURE__ */ _withScopeId$i(() => /* @__PURE__ */ createBaseVNode("i", { class: "pi pi-bookmark-fill text-sm mr-1" }, null, -1)); +const _hoisted_5$9 = [ + _hoisted_4$d +]; +const _hoisted_6$7 = ["innerHTML"]; +const _hoisted_7$4 = /* @__PURE__ */ _withScopeId$i(() => /* @__PURE__ */ createBaseVNode("span", null, " ", -1)); +const _hoisted_8$3 = ["innerHTML"]; +const _hoisted_9$3 = { + key: 0, + class: "option-category font-light text-sm text-gray-400 overflow-hidden text-ellipsis whitespace-nowrap" +}; +const _hoisted_10$3 = { class: "option-badges" }; +const _sfc_main$z = /* @__PURE__ */ defineComponent({ + __name: "NodeSearchItem", + props: { + nodeDef: {}, + currentQuery: {} + }, + setup(__props) { + const settingStore = useSettingStore(); + const showCategory = computed( + () => settingStore.get("Comfy.NodeSearchBoxImpl.ShowCategory") + ); + const showIdName = computed( + () => settingStore.get("Comfy.NodeSearchBoxImpl.ShowIdName") + ); + const showNodeFrequency = computed( + () => settingStore.get("Comfy.NodeSearchBoxImpl.ShowNodeFrequency") + ); + const nodeFrequencyStore = useNodeFrequencyStore(); + const nodeFrequency = computed( + () => nodeFrequencyStore.getNodeFrequency(props.nodeDef) + ); + const nodeBookmarkStore = useNodeBookmarkStore(); + const isBookmarked = computed( + () => nodeBookmarkStore.isBookmarked(props.nodeDef) + ); + const props = __props; + return (_ctx, _cache) => { + return openBlock(), createElementBlock("div", _hoisted_1$y, [ + createBaseVNode("div", _hoisted_2$q, [ + createBaseVNode("div", null, [ + isBookmarked.value ? (openBlock(), createElementBlock("span", _hoisted_3$k, _hoisted_5$9)) : createCommentVNode("", true), + createBaseVNode("span", { + innerHTML: unref(highlightQuery)(_ctx.nodeDef.display_name, _ctx.currentQuery) + }, null, 8, _hoisted_6$7), + _hoisted_7$4, + showIdName.value ? (openBlock(), createBlock(unref(script$w), { + key: 1, + severity: "secondary" + }, { + default: withCtx(() => [ + createBaseVNode("span", { + innerHTML: unref(highlightQuery)(_ctx.nodeDef.name, _ctx.currentQuery) + }, null, 8, _hoisted_8$3) + ]), + _: 1 + })) : createCommentVNode("", true) + ]), + showCategory.value ? (openBlock(), createElementBlock("div", _hoisted_9$3, toDisplayString(_ctx.nodeDef.category.replaceAll("/", " > ")), 1)) : createCommentVNode("", true) + ]), + createBaseVNode("div", _hoisted_10$3, [ + _ctx.nodeDef.experimental ? (openBlock(), createBlock(unref(script$w), { + key: 0, + value: _ctx.$t("experimental"), + severity: "primary" + }, null, 8, ["value"])) : createCommentVNode("", true), + _ctx.nodeDef.deprecated ? (openBlock(), createBlock(unref(script$w), { + key: 1, + value: _ctx.$t("deprecated"), + severity: "danger" + }, null, 8, ["value"])) : createCommentVNode("", true), + showNodeFrequency.value && nodeFrequency.value > 0 ? (openBlock(), createBlock(unref(script$w), { + key: 2, + value: unref(formatNumberWithSuffix)(nodeFrequency.value, { roundToInt: true }), + severity: "secondary" + }, null, 8, ["value"])) : createCommentVNode("", true), + _ctx.nodeDef.nodeSource.type !== unref(NodeSourceType).Unknown ? (openBlock(), createBlock(unref(script$u), { + key: 3, + class: "text-sm font-light" + }, { + default: withCtx(() => [ + createTextVNode(toDisplayString(_ctx.nodeDef.nodeSource.displayText), 1) + ]), + _: 1 + })) : createCommentVNode("", true) + ]) + ]); + }; + } +}); +const NodeSearchItem = /* @__PURE__ */ _export_sfc(_sfc_main$z, [["__scopeId", "data-v-37f672ab"]]); +const _withScopeId$h = /* @__PURE__ */ __name((n) => (pushScopeId("data-v-ff07c900"), n = n(), popScopeId(), n), "_withScopeId$h"); +const _hoisted_1$x = { class: "_sb_node_preview" }; +const _hoisted_2$p = { class: "_sb_table" }; +const _hoisted_3$j = /* @__PURE__ */ _withScopeId$h(() => /* @__PURE__ */ createBaseVNode("div", { class: "_sb_dot headdot" }, null, -1)); +const _hoisted_4$c = /* @__PURE__ */ _withScopeId$h(() => /* @__PURE__ */ createBaseVNode("div", { class: "_sb_preview_badge" }, "PREVIEW", -1)); +const _hoisted_5$8 = { class: "_sb_col" }; +const _hoisted_6$6 = { class: "_sb_col" }; +const _hoisted_7$3 = /* @__PURE__ */ _withScopeId$h(() => /* @__PURE__ */ createBaseVNode("div", { class: "_sb_col middle-column" }, null, -1)); +const _hoisted_8$2 = { class: "_sb_col" }; +const _hoisted_9$2 = /* @__PURE__ */ _withScopeId$h(() => /* @__PURE__ */ createBaseVNode("div", { class: "_sb_col _sb_arrow" }, "◀", -1)); +const _hoisted_10$2 = /* @__PURE__ */ _withScopeId$h(() => /* @__PURE__ */ createBaseVNode("div", { class: "_sb_col middle-column" }, null, -1)); +const _hoisted_11$2 = /* @__PURE__ */ _withScopeId$h(() => /* @__PURE__ */ createBaseVNode("div", { class: "_sb_col _sb_arrow" }, "▶", -1)); +const _sfc_main$y = /* @__PURE__ */ defineComponent({ + __name: "NodePreview", + props: { + nodeDef: { + type: ComfyNodeDefImpl, + required: true + } + }, + setup(__props) { + const props = __props; + const colors = getColorPalette()?.colors?.litegraph_base; + const litegraphColors = colors ?? defaultColorPalette.colors.litegraph_base; + const nodeDefStore = useNodeDefStore(); + const nodeDef = props.nodeDef; + const allInputDefs = nodeDef.input.all; + const allOutputDefs = nodeDef.output.all; + const slotInputDefs = allInputDefs.filter( + (input) => !nodeDefStore.inputIsWidget(input) + ); + const widgetInputDefs = allInputDefs.filter( + (input) => nodeDefStore.inputIsWidget(input) + ); + const truncateDefaultValue = /* @__PURE__ */ __name((value, charLimit = 32) => { + let stringValue; + if (typeof value === "object" && value !== null) { + stringValue = JSON.stringify(value); + } else if (Array.isArray(value)) { + stringValue = JSON.stringify(value); + } else if (typeof value === "string") { + stringValue = value; + } else { + stringValue = String(value); + } + return _.truncate(stringValue, { length: charLimit }); + }, "truncateDefaultValue"); + return (_ctx, _cache) => { + return openBlock(), createElementBlock("div", _hoisted_1$x, [ + createBaseVNode("div", _hoisted_2$p, [ + createBaseVNode("div", { + class: "node_header", + style: normalizeStyle({ + backgroundColor: unref(litegraphColors).NODE_DEFAULT_COLOR, + color: unref(litegraphColors).NODE_TITLE_COLOR + }) + }, [ + _hoisted_3$j, + createTextVNode(" " + toDisplayString(unref(nodeDef).display_name), 1) + ], 4), + _hoisted_4$c, + (openBlock(true), createElementBlock(Fragment, null, renderList(unref(_).zip(unref(slotInputDefs), unref(allOutputDefs)), ([slotInput, slotOutput]) => { + return openBlock(), createElementBlock("div", { + class: "_sb_row slot_row", + key: (slotInput?.name || "") + (slotOutput?.index.toString() || "") + }, [ + createBaseVNode("div", _hoisted_5$8, [ + slotInput ? (openBlock(), createElementBlock("div", { + key: 0, + class: normalizeClass(["_sb_dot", slotInput.type]) + }, null, 2)) : createCommentVNode("", true) + ]), + createBaseVNode("div", _hoisted_6$6, toDisplayString(slotInput ? slotInput.name : ""), 1), + _hoisted_7$3, + createBaseVNode("div", { + class: "_sb_col _sb_inherit", + style: normalizeStyle({ + color: unref(litegraphColors).NODE_TEXT_COLOR + }) + }, toDisplayString(slotOutput ? slotOutput.name : ""), 5), + createBaseVNode("div", _hoisted_8$2, [ + slotOutput ? (openBlock(), createElementBlock("div", { + key: 0, + class: normalizeClass(["_sb_dot", slotOutput.type]) + }, null, 2)) : createCommentVNode("", true) + ]) + ]); + }), 128)), + (openBlock(true), createElementBlock(Fragment, null, renderList(unref(widgetInputDefs), (widgetInput) => { + return openBlock(), createElementBlock("div", { + class: "_sb_row _long_field", + key: widgetInput.name + }, [ + _hoisted_9$2, + createBaseVNode("div", { + class: "_sb_col", + style: normalizeStyle({ + color: unref(litegraphColors).WIDGET_SECONDARY_TEXT_COLOR + }) + }, toDisplayString(widgetInput.name), 5), + _hoisted_10$2, + createBaseVNode("div", { + class: "_sb_col _sb_inherit", + style: normalizeStyle({ color: unref(litegraphColors).WIDGET_TEXT_COLOR }) + }, toDisplayString(truncateDefaultValue(widgetInput.default)), 5), + _hoisted_11$2 + ]); + }), 128)) + ]), + unref(nodeDef).description ? (openBlock(), createElementBlock("div", { + key: 0, + class: "_sb_description", + style: normalizeStyle({ + color: unref(litegraphColors).WIDGET_SECONDARY_TEXT_COLOR, + backgroundColor: unref(litegraphColors).WIDGET_BGCOLOR + }) + }, toDisplayString(unref(nodeDef).description), 5)) : createCommentVNode("", true) + ]); + }; + } +}); +const NodePreview = /* @__PURE__ */ _export_sfc(_sfc_main$y, [["__scopeId", "data-v-ff07c900"]]); +const _withScopeId$g = /* @__PURE__ */ __name((n) => (pushScopeId("data-v-2d409367"), n = n(), popScopeId(), n), "_withScopeId$g"); +const _hoisted_1$w = { class: "comfy-vue-node-search-container" }; +const _hoisted_2$o = { + key: 0, + class: "comfy-vue-node-preview-container" +}; +const _hoisted_3$i = /* @__PURE__ */ _withScopeId$g(() => /* @__PURE__ */ createBaseVNode("h3", null, "Add node filter condition", -1)); +const _hoisted_4$b = { class: "_dialog-body" }; +const _sfc_main$x = /* @__PURE__ */ defineComponent({ + __name: "NodeSearchBox", + props: { + filters: {}, + searchLimit: { default: 64 } + }, + emits: ["addFilter", "removeFilter", "addNode"], + setup(__props, { emit: __emit }) { + const settingStore = useSettingStore(); + const { t } = useI18n(); + const enableNodePreview = computed( + () => settingStore.get("Comfy.NodeSearchBoxImpl.NodePreview") + ); + const props = __props; + const nodeSearchFilterVisible = ref(false); + const inputId = `comfy-vue-node-search-box-input-${Math.random()}`; + const suggestions2 = ref([]); + const hoveredSuggestion = ref(null); + const currentQuery = ref(""); + const placeholder = computed(() => { + return props.filters.length === 0 ? t("searchNodes") + "..." : ""; + }); + const nodeDefStore = useNodeDefStore(); + const nodeFrequencyStore = useNodeFrequencyStore(); + const search2 = /* @__PURE__ */ __name((query) => { + const queryIsEmpty = query === "" && props.filters.length === 0; + currentQuery.value = query; + suggestions2.value = queryIsEmpty ? nodeFrequencyStore.topNodeDefs : [ + ...nodeDefStore.nodeSearchService.searchNode(query, props.filters, { + limit: props.searchLimit + }) + ]; + }, "search"); + const emit = __emit; + const reFocusInput = /* @__PURE__ */ __name(() => { + const inputElement = document.getElementById(inputId); + if (inputElement) { + inputElement.blur(); + inputElement.focus(); + } + }, "reFocusInput"); + onMounted(reFocusInput); + const onAddFilter = /* @__PURE__ */ __name((filterAndValue) => { + nodeSearchFilterVisible.value = false; + emit("addFilter", filterAndValue); + reFocusInput(); + }, "onAddFilter"); + const onRemoveFilter = /* @__PURE__ */ __name((event, filterAndValue) => { + event.stopPropagation(); + event.preventDefault(); + emit("removeFilter", filterAndValue); + reFocusInput(); + }, "onRemoveFilter"); + const setHoverSuggestion = /* @__PURE__ */ __name((index2) => { + if (index2 === -1) { + hoveredSuggestion.value = null; + return; + } + const value = suggestions2.value[index2]; + hoveredSuggestion.value = value; + }, "setHoverSuggestion"); + return (_ctx, _cache) => { + return openBlock(), createElementBlock("div", _hoisted_1$w, [ + enableNodePreview.value ? (openBlock(), createElementBlock("div", _hoisted_2$o, [ + hoveredSuggestion.value ? (openBlock(), createBlock(NodePreview, { + nodeDef: hoveredSuggestion.value, + key: hoveredSuggestion.value?.name || "" + }, null, 8, ["nodeDef"])) : createCommentVNode("", true) + ])) : createCommentVNode("", true), + createVNode(unref(script$o), { + icon: "pi pi-filter", + severity: "secondary", + class: "_filter-button", + onClick: _cache[0] || (_cache[0] = ($event) => nodeSearchFilterVisible.value = true) + }), + createVNode(unref(script$x), { + visible: nodeSearchFilterVisible.value, + "onUpdate:visible": _cache[1] || (_cache[1] = ($event) => nodeSearchFilterVisible.value = $event), + class: "_dialog" + }, { + header: withCtx(() => [ + _hoisted_3$i + ]), + default: withCtx(() => [ + createBaseVNode("div", _hoisted_4$b, [ + createVNode(NodeSearchFilter, { onAddFilter }) + ]) + ]), + _: 1 + }, 8, ["visible"]), + createVNode(_sfc_main$B, { + "model-value": props.filters, + class: "comfy-vue-node-search-box", + scrollHeight: "40vh", + placeholder: placeholder.value, + "input-id": inputId, + "append-to": "self", + suggestions: suggestions2.value, + "min-length": 0, + delay: 100, + loading: !unref(nodeFrequencyStore).isLoaded, + onComplete: _cache[2] || (_cache[2] = ($event) => search2($event.query)), + onOptionSelect: _cache[3] || (_cache[3] = ($event) => emit("addNode", $event.value)), + onFocusedOptionChanged: _cache[4] || (_cache[4] = ($event) => setHoverSuggestion($event)), + "complete-on-focus": "", + "auto-option-focus": "", + "force-selection": "", + multiple: "", + optionLabel: "display_name" + }, { + option: withCtx(({ option: option2 }) => [ + createVNode(NodeSearchItem, { + nodeDef: option2, + currentQuery: currentQuery.value + }, null, 8, ["nodeDef", "currentQuery"]) + ]), + chip: withCtx(({ value }) => [ + createVNode(SearchFilterChip, { + onRemove: /* @__PURE__ */ __name(($event) => onRemoveFilter($event, value), "onRemove"), + text: value[1], + badge: value[0].invokeSequence.toUpperCase(), + "badge-class": value[0].invokeSequence + "-badge" + }, null, 8, ["onRemove", "text", "badge", "badge-class"]) + ]), + _: 1 + }, 8, ["model-value", "placeholder", "suggestions", "loading"]) + ]); + }; + } +}); +const NodeSearchBox = /* @__PURE__ */ _export_sfc(_sfc_main$x, [["__scopeId", "data-v-2d409367"]]); +class ConnectingLinkImpl { + static { + __name(this, "ConnectingLinkImpl"); + } + node; + slot; + input; + output; + pos; + constructor(node2, slot, input, output, pos) { + this.node = node2; + this.slot = slot; + this.input = input; + this.output = output; + this.pos = pos; + } + static createFromPlainObject(obj) { + return new ConnectingLinkImpl( + obj.node, + obj.slot, + obj.input, + obj.output, + obj.pos + ); + } + get type() { + const result = this.input ? this.input.type : this.output.type; + return result === -1 ? null : result; + } + /** + * Which slot type is release and need to be reconnected. + * - 'output' means we need a new node's outputs slot to connect with this link + */ + get releaseSlotType() { + return this.output ? "input" : "output"; + } + connectTo(newNode) { + const newNodeSlots = this.releaseSlotType === "output" ? newNode.outputs : newNode.inputs; + if (!newNodeSlots) return; + const newNodeSlot = newNodeSlots.findIndex( + (slot) => LiteGraph.isValidConnection(slot.type, this.type) + ); + if (newNodeSlot === -1) { + console.warn( + `Could not find slot with type ${this.type} on node ${newNode.title}. This should never happen` + ); + return; + } + if (this.releaseSlotType === "input") { + this.node.connect(this.slot, newNode, newNodeSlot); + } else { + newNode.connect(newNodeSlot, this.node, this.slot); + } + } +} +const _sfc_main$w = /* @__PURE__ */ defineComponent({ + __name: "NodeSearchBoxPopover", + setup(__props) { + const settingStore = useSettingStore(); + const visible = ref(false); + const dismissable = ref(true); + const triggerEvent = ref(null); + const getNewNodeLocation = /* @__PURE__ */ __name(() => { + if (triggerEvent.value === null) { + return [100, 100]; + } + const originalEvent = triggerEvent.value.detail.originalEvent; + return [originalEvent.canvasX, originalEvent.canvasY]; + }, "getNewNodeLocation"); + const nodeFilters = ref([]); + const addFilter = /* @__PURE__ */ __name((filter) => { + nodeFilters.value.push(filter); + }, "addFilter"); + const removeFilter = /* @__PURE__ */ __name((filter) => { + nodeFilters.value = nodeFilters.value.filter( + (f) => toRaw(f) !== toRaw(filter) + ); + }, "removeFilter"); + const clearFilters = /* @__PURE__ */ __name(() => { + nodeFilters.value = []; + }, "clearFilters"); + const closeDialog = /* @__PURE__ */ __name(() => { + visible.value = false; + }, "closeDialog"); + const addNode = /* @__PURE__ */ __name((nodeDef) => { + const node2 = app.addNodeOnGraph(nodeDef, { pos: getNewNodeLocation() }); + const eventDetail = triggerEvent.value.detail; + if (eventDetail.subType === "empty-release") { + eventDetail.linkReleaseContext.links.forEach((link) => { + ConnectingLinkImpl.createFromPlainObject(link).connectTo(node2); + }); + } + window.setTimeout(() => { + closeDialog(); + }, 100); + }, "addNode"); + const newSearchBoxEnabled = computed( + () => settingStore.get("Comfy.NodeSearchBoxImpl") === "default" + ); + const showSearchBox = /* @__PURE__ */ __name((e) => { + if (newSearchBoxEnabled.value) { + if (e.detail.originalEvent?.pointerType === "touch") { + setTimeout(() => { + showNewSearchBox(e); + }, 128); + } else { + showNewSearchBox(e); + } + } else { + canvasStore.canvas.showSearchBox(e.detail.originalEvent); + } + }, "showSearchBox"); + const nodeDefStore = useNodeDefStore(); + const showNewSearchBox = /* @__PURE__ */ __name((e) => { + if (e.detail.linkReleaseContext) { + const links = e.detail.linkReleaseContext.links; + if (links.length === 0) { + console.warn("Empty release with no links! This should never happen"); + return; + } + const firstLink = ConnectingLinkImpl.createFromPlainObject(links[0]); + const filter = nodeDefStore.nodeSearchService.getFilterById( + firstLink.releaseSlotType + ); + const dataType = firstLink.type; + addFilter([filter, dataType]); + } + visible.value = true; + triggerEvent.value = e; + dismissable.value = false; + setTimeout(() => { + dismissable.value = true; + }, 300); + }, "showNewSearchBox"); + const showContextMenu = /* @__PURE__ */ __name((e) => { + const links = e.detail.linkReleaseContext.links; + if (links.length === 0) { + console.warn("Empty release with no links! This should never happen"); + return; + } + const firstLink = ConnectingLinkImpl.createFromPlainObject(links[0]); + const mouseEvent = e.detail.originalEvent; + const commonOptions = { + e: mouseEvent, + allow_searchbox: true, + showSearchBox: /* @__PURE__ */ __name(() => showSearchBox(e), "showSearchBox") + }; + const connectionOptions = firstLink.output ? { nodeFrom: firstLink.node, slotFrom: firstLink.output } : { nodeTo: firstLink.node, slotTo: firstLink.input }; + canvasStore.canvas.showConnectionMenu({ + ...connectionOptions, + ...commonOptions + }); + }, "showContextMenu"); + const canvasStore = useCanvasStore(); + watchEffect(() => { + if (canvasStore.canvas) { + LiteGraph.release_link_on_empty_shows_menu = false; + canvasStore.canvas.allow_searchbox = false; + } + }); + const canvasEventHandler = /* @__PURE__ */ __name((e) => { + if (e.detail.subType === "empty-double-click") { + showSearchBox(e); + } else if (e.detail.subType === "empty-release") { + handleCanvasEmptyRelease(e); + } else if (e.detail.subType === "group-double-click") { + const group = e.detail.group; + const [x, y] = group.pos; + const relativeY = e.detail.originalEvent.canvasY - y; + if (relativeY > group.titleHeight) { + showSearchBox(e); + } + } + }, "canvasEventHandler"); + const linkReleaseAction = computed(() => { + return settingStore.get("Comfy.LinkRelease.Action"); + }); + const linkReleaseActionShift = computed(() => { + return settingStore.get("Comfy.LinkRelease.ActionShift"); + }); + const handleCanvasEmptyRelease = /* @__PURE__ */ __name((e) => { + const originalEvent = e.detail.originalEvent; + const shiftPressed = originalEvent.shiftKey; + const action = shiftPressed ? linkReleaseActionShift.value : linkReleaseAction.value; + switch (action) { + case LinkReleaseTriggerAction.SEARCH_BOX: + showSearchBox(e); + break; + case LinkReleaseTriggerAction.CONTEXT_MENU: + showContextMenu(e); + break; + case LinkReleaseTriggerAction.NO_ACTION: + default: + break; + } + }, "handleCanvasEmptyRelease"); + onMounted(() => { + document.addEventListener("litegraph:canvas", canvasEventHandler); + }); + onUnmounted(() => { + document.removeEventListener("litegraph:canvas", canvasEventHandler); + }); + return (_ctx, _cache) => { + return openBlock(), createElementBlock("div", null, [ + createVNode(unref(script$x), { + visible: visible.value, + "onUpdate:visible": _cache[0] || (_cache[0] = ($event) => visible.value = $event), + modal: "", + "dismissable-mask": dismissable.value, + onHide: clearFilters, + pt: { + root: { + class: "invisible-dialog-root", + role: "search" + }, + mask: { class: "node-search-box-dialog-mask" }, + transition: { + enterFromClass: "opacity-0 scale-75", + // 100ms is the duration of the transition in the dialog component + enterActiveClass: "transition-all duration-100 ease-out", + leaveActiveClass: "transition-all duration-100 ease-in", + leaveToClass: "opacity-0 scale-75" + } + } + }, { + container: withCtx(() => [ + createVNode(NodeSearchBox, { + filters: nodeFilters.value, + onAddFilter: addFilter, + onRemoveFilter: removeFilter, + onAddNode: addNode + }, null, 8, ["filters"]) + ]), + _: 1 + }, 8, ["visible", "dismissable-mask"]) + ]); + }; + } +}); +const _sfc_main$v = /* @__PURE__ */ defineComponent({ + __name: "NodeTooltip", + setup(__props) { + let idleTimeout; + const nodeDefStore = useNodeDefStore(); + const settingStore = useSettingStore(); + const tooltipRef = ref(); + const tooltipText = ref(""); + const left = ref(); + const top = ref(); + const getHoveredWidget = /* @__PURE__ */ __name(() => { + const node2 = app.canvas.node_over; + if (!node2.widgets) return; + const graphPos = app.canvas.graph_mouse; + const x = graphPos[0] - node2.pos[0]; + const y = graphPos[1] - node2.pos[1]; + for (const w of node2.widgets) { + let widgetWidth, widgetHeight; + if (w.computeSize) { + ; + [widgetWidth, widgetHeight] = w.computeSize(node2.size[0]); + } else { + widgetWidth = w.width || node2.size[0]; + widgetHeight = LiteGraph.NODE_WIDGET_HEIGHT; + } + if (w.last_y !== void 0 && x >= 6 && x <= widgetWidth - 12 && y >= w.last_y && y <= w.last_y + widgetHeight) { + return w; + } + } + }, "getHoveredWidget"); + const hideTooltip = /* @__PURE__ */ __name(() => tooltipText.value = null, "hideTooltip"); + const showTooltip = /* @__PURE__ */ __name(async (tooltip) => { + if (!tooltip) return; + left.value = app.canvas.mouse[0] + "px"; + top.value = app.canvas.mouse[1] + "px"; + tooltipText.value = tooltip; + await nextTick(); + const rect = tooltipRef.value.getBoundingClientRect(); + if (rect.right > window.innerWidth) { + left.value = app.canvas.mouse[0] - rect.width + "px"; + } + if (rect.top < 0) { + top.value = app.canvas.mouse[1] + rect.height + "px"; + } + }, "showTooltip"); + const onIdle = /* @__PURE__ */ __name(() => { + const { canvas } = app; + const node2 = canvas.node_over; + if (!node2) return; + const ctor = node2.constructor; + const nodeDef = nodeDefStore.nodeDefsByName[node2.type]; + if (ctor.title_mode !== LiteGraph.NO_TITLE && canvas.graph_mouse[1] < node2.pos[1]) { + return showTooltip(nodeDef.description); + } + if (node2.flags?.collapsed) return; + const inputSlot = canvas.isOverNodeInput( + node2, + canvas.graph_mouse[0], + canvas.graph_mouse[1], + [0, 0] + ); + if (inputSlot !== -1) { + const inputName = node2.inputs[inputSlot].name; + return showTooltip(nodeDef.input.getInput(inputName)?.tooltip); + } + const outputSlot = canvas.isOverNodeOutput( + node2, + canvas.graph_mouse[0], + canvas.graph_mouse[1], + [0, 0] + ); + if (outputSlot !== -1) { + return showTooltip(nodeDef.output.all?.[outputSlot]?.tooltip); + } + const widget = getHoveredWidget(); + if (widget && !widget.element) { + return showTooltip( + widget.tooltip ?? nodeDef.input.getInput(widget.name)?.tooltip + ); + } + }, "onIdle"); + const onMouseMove = /* @__PURE__ */ __name((e) => { + hideTooltip(); + clearTimeout(idleTimeout); + if (e.target.nodeName !== "CANVAS") return; + idleTimeout = window.setTimeout(onIdle, 500); + }, "onMouseMove"); + watch( + () => settingStore.get("Comfy.EnableTooltips"), + (enabled) => { + if (enabled) { + window.addEventListener("mousemove", onMouseMove); + window.addEventListener("click", hideTooltip); + } else { + window.removeEventListener("mousemove", onMouseMove); + window.removeEventListener("click", hideTooltip); + } + }, + { immediate: true } + ); + onBeforeUnmount(() => { + window.removeEventListener("mousemove", onMouseMove); + window.removeEventListener("click", hideTooltip); + }); + return (_ctx, _cache) => { + return tooltipText.value ? (openBlock(), createElementBlock("div", { + key: 0, + ref_key: "tooltipRef", + ref: tooltipRef, + class: "node-tooltip", + style: normalizeStyle({ left: left.value, top: top.value }) + }, toDisplayString(tooltipText.value), 5)) : createCommentVNode("", true); + }; + } +}); +const NodeTooltip = /* @__PURE__ */ _export_sfc(_sfc_main$v, [["__scopeId", "data-v-0a4402f9"]]); +function _arrayWithHoles(r) { + if (Array.isArray(r)) return r; +} +__name(_arrayWithHoles, "_arrayWithHoles"); +function _iterableToArrayLimit(r, l) { + var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; + if (null != t) { + var e, n, i, u, a = [], f = true, o = false; + try { + if (i = (t = t.call(r)).next, 0 === l) { + if (Object(t) !== t) return; + f = false; + } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = true) ; + } catch (r2) { + o = true, n = r2; + } finally { + try { + if (!f && null != t["return"] && (u = t["return"](), Object(u) !== u)) return; + } finally { + if (o) throw n; + } + } + return a; + } +} +__name(_iterableToArrayLimit, "_iterableToArrayLimit"); +function _arrayLikeToArray$6(r, a) { + (null == a || a > r.length) && (a = r.length); + for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; + return n; +} +__name(_arrayLikeToArray$6, "_arrayLikeToArray$6"); +function _unsupportedIterableToArray$6(r, a) { + if (r) { + if ("string" == typeof r) return _arrayLikeToArray$6(r, a); + var t = {}.toString.call(r).slice(8, -1); + return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray$6(r, a) : void 0; + } +} +__name(_unsupportedIterableToArray$6, "_unsupportedIterableToArray$6"); +function _nonIterableRest() { + throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); +} +__name(_nonIterableRest, "_nonIterableRest"); +function _slicedToArray(r, e) { + return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray$6(r, e) || _nonIterableRest(); +} +__name(_slicedToArray, "_slicedToArray"); +var dist = {}; +var bind$1 = {}; +"use strict"; +Object.defineProperty(bind$1, "__esModule", { value: true }); +var bind_2 = bind$1.bind = void 0; +function bind(target, _a) { + var type = _a.type, listener = _a.listener, options = _a.options; + target.addEventListener(type, listener, options); + return /* @__PURE__ */ __name(function unbind() { + target.removeEventListener(type, listener, options); + }, "unbind"); +} +__name(bind, "bind"); +bind_2 = bind$1.bind = bind; +var bindAll$1 = {}; +"use strict"; +var __assign = commonjsGlobal && commonjsGlobal.__assign || function() { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; +Object.defineProperty(bindAll$1, "__esModule", { value: true }); +var bindAll_2 = bindAll$1.bindAll = void 0; +var bind_1 = bind$1; +function toOptions(value) { + if (typeof value === "undefined") { + return void 0; + } + if (typeof value === "boolean") { + return { + capture: value + }; + } + return value; +} +__name(toOptions, "toOptions"); +function getBinding(original, sharedOptions) { + if (sharedOptions == null) { + return original; + } + var binding = __assign(__assign({}, original), { options: __assign(__assign({}, toOptions(sharedOptions)), toOptions(original.options)) }); + return binding; +} +__name(getBinding, "getBinding"); +function bindAll(target, bindings, sharedOptions) { + var unbinds = bindings.map(function(original) { + var binding = getBinding(original, sharedOptions); + return (0, bind_1.bind)(target, binding); + }); + return /* @__PURE__ */ __name(function unbindAll() { + unbinds.forEach(function(unbind) { + return unbind(); + }); + }, "unbindAll"); +} +__name(bindAll, "bindAll"); +bindAll_2 = bindAll$1.bindAll = bindAll; +(function(exports) { + "use strict"; + Object.defineProperty(exports, "__esModule", { value: true }); + exports.bindAll = exports.bind = void 0; + var bind_12 = bind$1; + Object.defineProperty(exports, "bind", { enumerable: true, get: /* @__PURE__ */ __name(function() { + return bind_12.bind; + }, "get") }); + var bind_all_1 = bindAll$1; + Object.defineProperty(exports, "bindAll", { enumerable: true, get: /* @__PURE__ */ __name(function() { + return bind_all_1.bindAll; + }, "get") }); +})(dist); +const index = /* @__PURE__ */ getDefaultExportFromCjs(dist); +var honeyPotDataAttribute = "data-pdnd-honey-pot"; +function isHoneyPotElement(target) { + return target instanceof Element && target.hasAttribute(honeyPotDataAttribute); +} +__name(isHoneyPotElement, "isHoneyPotElement"); +function getElementFromPointWithoutHoneypot(client) { + var _document$elementsFro = document.elementsFromPoint(client.x, client.y), _document$elementsFro2 = _slicedToArray(_document$elementsFro, 2), top = _document$elementsFro2[0], second = _document$elementsFro2[1]; + if (!top) { + return null; + } + if (isHoneyPotElement(top)) { + return second !== null && second !== void 0 ? second : null; + } + return top; +} +__name(getElementFromPointWithoutHoneypot, "getElementFromPointWithoutHoneypot"); +function _typeof$6(o) { + "@babel/helpers - typeof"; + return _typeof$6 = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(o2) { + return typeof o2; + } : function(o2) { + return o2 && "function" == typeof Symbol && o2.constructor === Symbol && o2 !== Symbol.prototype ? "symbol" : typeof o2; + }, _typeof$6(o); +} +__name(_typeof$6, "_typeof$6"); +function toPrimitive(t, r) { + if ("object" != _typeof$6(t) || !t) return t; + var e = t[Symbol.toPrimitive]; + if (void 0 !== e) { + var i = e.call(t, r || "default"); + if ("object" != _typeof$6(i)) return i; + throw new TypeError("@@toPrimitive must return a primitive value."); + } + return ("string" === r ? String : Number)(t); +} +__name(toPrimitive, "toPrimitive"); +function toPropertyKey(t) { + var i = toPrimitive(t, "string"); + return "symbol" == _typeof$6(i) ? i : i + ""; +} +__name(toPropertyKey, "toPropertyKey"); +function _defineProperty$6(e, r, t) { + return (r = toPropertyKey(r)) in e ? Object.defineProperty(e, r, { + value: t, + enumerable: true, + configurable: true, + writable: true + }) : e[r] = t, e; +} +__name(_defineProperty$6, "_defineProperty$6"); +var maxZIndex = 2147483647; +function ownKeys$7(e, r) { + var t = Object.keys(e); + if (Object.getOwnPropertySymbols) { + var o = Object.getOwnPropertySymbols(e); + r && (o = o.filter(function(r2) { + return Object.getOwnPropertyDescriptor(e, r2).enumerable; + })), t.push.apply(t, o); + } + return t; +} +__name(ownKeys$7, "ownKeys$7"); +function _objectSpread$7(e) { + for (var r = 1; r < arguments.length; r++) { + var t = null != arguments[r] ? arguments[r] : {}; + r % 2 ? ownKeys$7(Object(t), true).forEach(function(r2) { + _defineProperty$6(e, r2, t[r2]); + }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$7(Object(t)).forEach(function(r2) { + Object.defineProperty(e, r2, Object.getOwnPropertyDescriptor(t, r2)); + }); + } + return e; +} +__name(_objectSpread$7, "_objectSpread$7"); +var honeyPotSize = 2; +var halfHoneyPotSize = honeyPotSize / 2; +function floorToClosestPixel(point) { + return { + x: Math.floor(point.x), + y: Math.floor(point.y) + }; +} +__name(floorToClosestPixel, "floorToClosestPixel"); +function pullBackByHalfHoneyPotSize(point) { + return { + x: point.x - halfHoneyPotSize, + y: point.y - halfHoneyPotSize + }; +} +__name(pullBackByHalfHoneyPotSize, "pullBackByHalfHoneyPotSize"); +function preventGoingBackwardsOffScreen(point) { + return { + x: Math.max(point.x, 0), + y: Math.max(point.y, 0) + }; +} +__name(preventGoingBackwardsOffScreen, "preventGoingBackwardsOffScreen"); +function preventGoingForwardsOffScreen(point) { + return { + x: Math.min(point.x, window.innerWidth - honeyPotSize), + y: Math.min(point.y, window.innerHeight - honeyPotSize) + }; +} +__name(preventGoingForwardsOffScreen, "preventGoingForwardsOffScreen"); +function getHoneyPotRectFor(_ref) { + var client = _ref.client; + var point = preventGoingForwardsOffScreen(preventGoingBackwardsOffScreen(pullBackByHalfHoneyPotSize(floorToClosestPixel(client)))); + return DOMRect.fromRect({ + x: point.x, + y: point.y, + width: honeyPotSize, + height: honeyPotSize + }); +} +__name(getHoneyPotRectFor, "getHoneyPotRectFor"); +function getRectStyles(_ref2) { + var clientRect = _ref2.clientRect; + return { + left: "".concat(clientRect.left, "px"), + top: "".concat(clientRect.top, "px"), + width: "".concat(clientRect.width, "px"), + height: "".concat(clientRect.height, "px") + }; +} +__name(getRectStyles, "getRectStyles"); +function isWithin(_ref3) { + var client = _ref3.client, clientRect = _ref3.clientRect; + return ( + // is within horizontal bounds + client.x >= clientRect.x && client.x <= clientRect.x + clientRect.width && // is within vertical bounds + client.y >= clientRect.y && client.y <= clientRect.y + clientRect.height + ); +} +__name(isWithin, "isWithin"); +function mountHoneyPot(_ref4) { + var initial = _ref4.initial; + var element = document.createElement("div"); + element.setAttribute(honeyPotDataAttribute, "true"); + var clientRect = getHoneyPotRectFor({ + client: initial + }); + Object.assign(element.style, _objectSpread$7(_objectSpread$7({ + // Setting a background color explicitly to avoid any inherited styles. + // Looks like this could be `opacity: 0`, but worried that _might_ + // cause the element to be ignored on some platforms. + // When debugging, set backgroundColor to something like "red". + backgroundColor: "transparent", + position: "fixed", + // Being explicit to avoid inheriting styles + padding: 0, + margin: 0, + boxSizing: "border-box" + }, getRectStyles({ + clientRect + })), {}, { + // We want this element to absorb pointer events, + // it's kind of the whole point 😉 + pointerEvents: "auto", + // Want to make sure the honey pot is top of everything else. + // Don't need to worry about native drag previews, as they will + // have been rendered (and removed) before the honey pot is rendered + zIndex: maxZIndex + })); + document.body.appendChild(element); + var unbindPointerMove = dist.bind(window, { + type: "pointermove", + listener: /* @__PURE__ */ __name(function listener(event) { + var client = { + x: event.clientX, + y: event.clientY + }; + clientRect = getHoneyPotRectFor({ + client + }); + Object.assign(element.style, getRectStyles({ + clientRect + })); + }, "listener"), + // using capture so we are less likely to be impacted by event stopping + options: { + capture: true + } + }); + return /* @__PURE__ */ __name(function finish(_ref5) { + var current = _ref5.current; + unbindPointerMove(); + if (isWithin({ + client: current, + clientRect + })) { + element.remove(); + return; + } + function cleanup() { + unbindPostDragEvents(); + element.remove(); + } + __name(cleanup, "cleanup"); + var unbindPostDragEvents = dist.bindAll(window, [ + { + type: "pointerdown", + listener: cleanup + }, + { + type: "pointermove", + listener: cleanup + }, + { + type: "focusin", + listener: cleanup + }, + { + type: "focusout", + listener: cleanup + }, + // a 'pointerdown' should happen before 'dragstart', but just being super safe + { + type: "dragstart", + listener: cleanup + }, + // if the user has dragged something out of the window + // and then is dragging something back into the window + // the first events we will see are "dragenter" (and then "dragover"). + // So if we see any of these we need to clear the post drag fix. + { + type: "dragenter", + listener: cleanup + }, + { + type: "dragover", + listener: cleanup + } + // Not adding a "wheel" event listener, as "wheel" by itself does not + // resolve the bug. + ], { + // Using `capture` so less likely to be impacted by other code stopping events + capture: true + }); + }, "finish"); +} +__name(mountHoneyPot, "mountHoneyPot"); +function makeHoneyPotFix() { + var latestPointerMove = null; + function bindEvents() { + latestPointerMove = null; + return dist.bind(window, { + type: "pointermove", + listener: /* @__PURE__ */ __name(function listener(event) { + latestPointerMove = { + x: event.clientX, + y: event.clientY + }; + }, "listener"), + // listening for pointer move in capture phase + // so we are less likely to be impacted by events being stopped. + options: { + capture: true + } + }); + } + __name(bindEvents, "bindEvents"); + function getOnPostDispatch() { + var finish = null; + return /* @__PURE__ */ __name(function onPostEvent(_ref6) { + var eventName = _ref6.eventName, payload = _ref6.payload; + if (eventName === "onDragStart") { + var _latestPointerMove; + var input = payload.location.initial.input; + var initial = (_latestPointerMove = latestPointerMove) !== null && _latestPointerMove !== void 0 ? _latestPointerMove : { + x: input.clientX, + y: input.clientY + }; + finish = mountHoneyPot({ + initial + }); + } + if (eventName === "onDrop") { + var _finish; + var _input = payload.location.current.input; + (_finish = finish) === null || _finish === void 0 || _finish({ + current: { + x: _input.clientX, + y: _input.clientY + } + }); + finish = null; + latestPointerMove = null; + } + }, "onPostEvent"); + } + __name(getOnPostDispatch, "getOnPostDispatch"); + return { + bindEvents, + getOnPostDispatch + }; +} +__name(makeHoneyPotFix, "makeHoneyPotFix"); +function _arrayWithoutHoles$4(r) { + if (Array.isArray(r)) return _arrayLikeToArray$6(r); +} +__name(_arrayWithoutHoles$4, "_arrayWithoutHoles$4"); +function _iterableToArray$4(r) { + if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); +} +__name(_iterableToArray$4, "_iterableToArray$4"); +function _nonIterableSpread$4() { + throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); +} +__name(_nonIterableSpread$4, "_nonIterableSpread$4"); +function _toConsumableArray$4(r) { + return _arrayWithoutHoles$4(r) || _iterableToArray$4(r) || _unsupportedIterableToArray$6(r) || _nonIterableSpread$4(); +} +__name(_toConsumableArray$4, "_toConsumableArray$4"); +function once(fn) { + var cache = null; + return /* @__PURE__ */ __name(function wrapped() { + if (!cache) { + for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { + args[_key] = arguments[_key]; + } + var result = fn.apply(this, args); + cache = { + result + }; + } + return cache.result; + }, "wrapped"); +} +__name(once, "once"); +var isFirefox = once(/* @__PURE__ */ __name(function isFirefox2() { + if (false) { + return false; + } + return navigator.userAgent.includes("Firefox"); +}, "isFirefox2")); +var isSafari = once(/* @__PURE__ */ __name(function isSafari2() { + if (false) { + return false; + } + var _navigator = navigator, userAgent = _navigator.userAgent; + return userAgent.includes("AppleWebKit") && !userAgent.includes("Chrome"); +}, "isSafari2")); +var symbols = { + isLeavingWindow: Symbol("leaving"), + isEnteringWindow: Symbol("entering") +}; +function isEnteringWindowInSafari(_ref) { + var dragEnter = _ref.dragEnter; + if (!isSafari()) { + return false; + } + return dragEnter.hasOwnProperty(symbols.isEnteringWindow); +} +__name(isEnteringWindowInSafari, "isEnteringWindowInSafari"); +function isLeavingWindowInSafari(_ref2) { + var dragLeave = _ref2.dragLeave; + if (!isSafari()) { + return false; + } + return dragLeave.hasOwnProperty(symbols.isLeavingWindow); +} +__name(isLeavingWindowInSafari, "isLeavingWindowInSafari"); +(/* @__PURE__ */ __name(function fixSafari() { + if (typeof window === "undefined") { + return; + } + if (false) { + return; + } + if (!isSafari()) { + return; + } + function getInitialState() { + return { + enterCount: 0, + isOverWindow: false + }; + } + __name(getInitialState, "getInitialState"); + var state = getInitialState(); + function resetState() { + state = getInitialState(); + } + __name(resetState, "resetState"); + dist.bindAll( + window, + [{ + type: "dragstart", + listener: /* @__PURE__ */ __name(function listener() { + state.enterCount = 0; + state.isOverWindow = true; + }, "listener") + }, { + type: "drop", + listener: resetState + }, { + type: "dragend", + listener: resetState + }, { + type: "dragenter", + listener: /* @__PURE__ */ __name(function listener(event) { + if (!state.isOverWindow && state.enterCount === 0) { + event[symbols.isEnteringWindow] = true; + } + state.isOverWindow = true; + state.enterCount++; + }, "listener") + }, { + type: "dragleave", + listener: /* @__PURE__ */ __name(function listener(event) { + state.enterCount--; + if (state.isOverWindow && state.enterCount === 0) { + event[symbols.isLeavingWindow] = true; + state.isOverWindow = false; + } + }, "listener") + }], + // using `capture: true` so that adding event listeners + // in bubble phase will have the correct symbols + { + capture: true + } + ); +}, "fixSafari"))(); +function isNodeLike(target) { + return "nodeName" in target; +} +__name(isNodeLike, "isNodeLike"); +function isFromAnotherWindow(eventTarget) { + return isNodeLike(eventTarget) && eventTarget.ownerDocument !== document; +} +__name(isFromAnotherWindow, "isFromAnotherWindow"); +function isLeavingWindow(_ref) { + var dragLeave = _ref.dragLeave; + var type = dragLeave.type, relatedTarget = dragLeave.relatedTarget; + if (type !== "dragleave") { + return false; + } + if (isSafari()) { + return isLeavingWindowInSafari({ + dragLeave + }); + } + if (relatedTarget == null) { + return true; + } + if (isFirefox()) { + return isFromAnotherWindow(relatedTarget); + } + return relatedTarget instanceof HTMLIFrameElement; +} +__name(isLeavingWindow, "isLeavingWindow"); +function getBindingsForBrokenDrags(_ref) { + var onDragEnd2 = _ref.onDragEnd; + return [ + // ## Detecting drag ending for removed draggables + // + // If a draggable element is removed during a drag and the user drops: + // 1. if over a valid drop target: we get a "drop" event to know the drag is finished + // 2. if not over a valid drop target (or cancelled): we get nothing + // The "dragend" event will not fire on the source draggable if it has been + // removed from the DOM. + // So we need to figure out if a drag operation has finished by looking at other events + // We can do this by looking at other events + // ### First detection: "pointermove" events + // 1. "pointermove" events cannot fire during a drag and drop operation + // according to the spec. So if we get a "pointermove" it means that + // the drag and drop operations has finished. So if we get a "pointermove" + // we know that the drag is over + // 2. 🦊😤 Drag and drop operations are _supposed_ to suppress + // other pointer events. However, firefox will allow a few + // pointer event to get through after a drag starts. + // The most I've seen is 3 + { + type: "pointermove", + listener: /* @__PURE__ */ function() { + var callCount = 0; + return /* @__PURE__ */ __name(function listener() { + if (callCount < 20) { + callCount++; + return; + } + onDragEnd2(); + }, "listener"); + }() + }, + // ### Second detection: "pointerdown" events + // If we receive this event then we know that a drag operation has finished + // and potentially another one is about to start. + // Note: `pointerdown` fires on all browsers / platforms before "dragstart" + { + type: "pointerdown", + listener: onDragEnd2 + } + ]; +} +__name(getBindingsForBrokenDrags, "getBindingsForBrokenDrags"); +function getInput(event) { + return { + altKey: event.altKey, + button: event.button, + buttons: event.buttons, + ctrlKey: event.ctrlKey, + metaKey: event.metaKey, + shiftKey: event.shiftKey, + clientX: event.clientX, + clientY: event.clientY, + pageX: event.pageX, + pageY: event.pageY + }; +} +__name(getInput, "getInput"); +var rafSchd = /* @__PURE__ */ __name(function rafSchd2(fn) { + var lastArgs = []; + var frameId = null; + var wrapperFn = /* @__PURE__ */ __name(function wrapperFn2() { + for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { + args[_key] = arguments[_key]; + } + lastArgs = args; + if (frameId) { + return; + } + frameId = requestAnimationFrame(function() { + frameId = null; + fn.apply(void 0, lastArgs); + }); + }, "wrapperFn"); + wrapperFn.cancel = function() { + if (!frameId) { + return; + } + cancelAnimationFrame(frameId); + frameId = null; + }; + return wrapperFn; +}, "rafSchd"); +var scheduleOnDrag = rafSchd(function(fn) { + return fn(); +}); +var dragStart = /* @__PURE__ */ function() { + var scheduled = null; + function schedule(fn) { + var frameId = requestAnimationFrame(function() { + scheduled = null; + fn(); + }); + scheduled = { + frameId, + fn + }; + } + __name(schedule, "schedule"); + function flush() { + if (scheduled) { + cancelAnimationFrame(scheduled.frameId); + scheduled.fn(); + scheduled = null; + } + } + __name(flush, "flush"); + return { + schedule, + flush + }; +}(); +function makeDispatch(_ref) { + var source = _ref.source, initial = _ref.initial, dispatchEvent = _ref.dispatchEvent; + var previous = { + dropTargets: [] + }; + function safeDispatch(args) { + dispatchEvent(args); + previous = { + dropTargets: args.payload.location.current.dropTargets + }; + } + __name(safeDispatch, "safeDispatch"); + var dispatch = { + start: /* @__PURE__ */ __name(function start2(_ref2) { + var nativeSetDragImage = _ref2.nativeSetDragImage; + var location = { + current: initial, + previous, + initial + }; + safeDispatch({ + eventName: "onGenerateDragPreview", + payload: { + source, + location, + nativeSetDragImage + } + }); + dragStart.schedule(function() { + safeDispatch({ + eventName: "onDragStart", + payload: { + source, + location + } + }); + }); + }, "start"), + dragUpdate: /* @__PURE__ */ __name(function dragUpdate(_ref3) { + var current = _ref3.current; + dragStart.flush(); + scheduleOnDrag.cancel(); + safeDispatch({ + eventName: "onDropTargetChange", + payload: { + source, + location: { + initial, + previous, + current + } + } + }); + }, "dragUpdate"), + drag: /* @__PURE__ */ __name(function drag(_ref4) { + var current = _ref4.current; + scheduleOnDrag(function() { + dragStart.flush(); + var location = { + initial, + previous, + current + }; + safeDispatch({ + eventName: "onDrag", + payload: { + source, + location + } + }); + }); + }, "drag"), + drop: /* @__PURE__ */ __name(function drop(_ref5) { + var current = _ref5.current, updatedSourcePayload = _ref5.updatedSourcePayload; + dragStart.flush(); + scheduleOnDrag.cancel(); + safeDispatch({ + eventName: "onDrop", + payload: { + source: updatedSourcePayload !== null && updatedSourcePayload !== void 0 ? updatedSourcePayload : source, + location: { + current, + previous, + initial + } + } + }); + }, "drop") + }; + return dispatch; +} +__name(makeDispatch, "makeDispatch"); +var globalState = { + isActive: false +}; +function canStart() { + return !globalState.isActive; +} +__name(canStart, "canStart"); +function getNativeSetDragImage(event) { + if (event.dataTransfer) { + return event.dataTransfer.setDragImage.bind(event.dataTransfer); + } + return null; +} +__name(getNativeSetDragImage, "getNativeSetDragImage"); +function hasHierarchyChanged(_ref) { + var current = _ref.current, next2 = _ref.next; + if (current.length !== next2.length) { + return true; + } + for (var i = 0; i < current.length; i++) { + if (current[i].element !== next2[i].element) { + return true; + } + } + return false; +} +__name(hasHierarchyChanged, "hasHierarchyChanged"); +function start(_ref2) { + var event = _ref2.event, dragType = _ref2.dragType, getDropTargetsOver = _ref2.getDropTargetsOver, dispatchEvent = _ref2.dispatchEvent; + if (!canStart()) { + return; + } + var initial = getStartLocation({ + event, + dragType, + getDropTargetsOver + }); + globalState.isActive = true; + var state = { + current: initial + }; + setDropEffectOnEvent({ + event, + current: initial.dropTargets + }); + var dispatch = makeDispatch({ + source: dragType.payload, + dispatchEvent, + initial + }); + function updateState(next2) { + var hasChanged = hasHierarchyChanged({ + current: state.current.dropTargets, + next: next2.dropTargets + }); + state.current = next2; + if (hasChanged) { + dispatch.dragUpdate({ + current: state.current + }); + } + } + __name(updateState, "updateState"); + function onUpdateEvent(event2) { + var input = getInput(event2); + var target = isHoneyPotElement(event2.target) ? getElementFromPointWithoutHoneypot({ + x: input.clientX, + y: input.clientY + }) : event2.target; + var nextDropTargets = getDropTargetsOver({ + target, + input, + source: dragType.payload, + current: state.current.dropTargets + }); + if (nextDropTargets.length) { + event2.preventDefault(); + setDropEffectOnEvent({ + event: event2, + current: nextDropTargets + }); + } + updateState({ + dropTargets: nextDropTargets, + input + }); + } + __name(onUpdateEvent, "onUpdateEvent"); + function cancel() { + if (state.current.dropTargets.length) { + updateState({ + dropTargets: [], + input: state.current.input + }); + } + dispatch.drop({ + current: state.current, + updatedSourcePayload: null + }); + finish(); + } + __name(cancel, "cancel"); + function finish() { + globalState.isActive = false; + unbindEvents(); + } + __name(finish, "finish"); + var unbindEvents = dist.bindAll( + window, + [{ + // 👋 Note: we are repurposing the `dragover` event as our `drag` event + // this is because firefox does not publish pointer coordinates during + // a `drag` event, but does for every other type of drag event + // `dragover` fires on all elements that are being dragged over + // Because we are binding to `window` - our `dragover` is effectively the same as a `drag` + // 🦊😤 + type: "dragover", + listener: /* @__PURE__ */ __name(function listener(event2) { + onUpdateEvent(event2); + dispatch.drag({ + current: state.current + }); + }, "listener") + }, { + type: "dragenter", + listener: onUpdateEvent + }, { + type: "dragleave", + listener: /* @__PURE__ */ __name(function listener(event2) { + if (!isLeavingWindow({ + dragLeave: event2 + })) { + return; + } + updateState({ + input: state.current.input, + dropTargets: [] + }); + if (dragType.startedFrom === "external") { + cancel(); + } + }, "listener") + }, { + // A "drop" can only happen if the browser allowed the drop + type: "drop", + listener: /* @__PURE__ */ __name(function listener(event2) { + state.current = { + dropTargets: state.current.dropTargets, + input: getInput(event2) + }; + if (!state.current.dropTargets.length) { + cancel(); + return; + } + event2.preventDefault(); + setDropEffectOnEvent({ + event: event2, + current: state.current.dropTargets + }); + dispatch.drop({ + current: state.current, + // When dropping something native, we need to extract the latest + // `.items` from the "drop" event as it is now accessible + updatedSourcePayload: dragType.type === "external" ? dragType.getDropPayload(event2) : null + }); + finish(); + }, "listener") + }, { + // "dragend" fires when on the drag source (eg a draggable element) + // when the drag is finished. + // "dragend" will fire after "drop" (if there was a successful drop) + // "dragend" does not fire if the draggable source has been removed during the drag + // or for external drag sources (eg files) + // This "dragend" listener will not fire if there was a successful drop + // as we will have already removed the event listener + type: "dragend", + listener: /* @__PURE__ */ __name(function listener(event2) { + state.current = { + dropTargets: state.current.dropTargets, + input: getInput(event2) + }; + cancel(); + }, "listener") + }].concat(_toConsumableArray$4(getBindingsForBrokenDrags({ + onDragEnd: cancel + }))), + // Once we have started a managed drag operation it is important that we see / own all drag events + // We got one adoption bug pop up where some code was stopping (`event.stopPropagation()`) + // all "drop" events in the bubble phase on the `document.body`. + // This meant that we never saw the "drop" event. + { + capture: true + } + ); + dispatch.start({ + nativeSetDragImage: getNativeSetDragImage(event) + }); +} +__name(start, "start"); +function setDropEffectOnEvent(_ref3) { + var _current$; + var event = _ref3.event, current = _ref3.current; + var innerMost = (_current$ = current[0]) === null || _current$ === void 0 ? void 0 : _current$.dropEffect; + if (innerMost != null && event.dataTransfer) { + event.dataTransfer.dropEffect = innerMost; + } +} +__name(setDropEffectOnEvent, "setDropEffectOnEvent"); +function getStartLocation(_ref4) { + var event = _ref4.event, dragType = _ref4.dragType, getDropTargetsOver = _ref4.getDropTargetsOver; + var input = getInput(event); + if (dragType.startedFrom === "external") { + return { + input, + dropTargets: [] + }; + } + var dropTargets = getDropTargetsOver({ + input, + source: dragType.payload, + target: event.target, + current: [] + }); + return { + input, + dropTargets + }; +} +__name(getStartLocation, "getStartLocation"); +var lifecycle = { + canStart, + start +}; +var ledger = /* @__PURE__ */ new Map(); +function registerUsage(_ref) { + var typeKey = _ref.typeKey, mount2 = _ref.mount; + var entry = ledger.get(typeKey); + if (entry) { + entry.usageCount++; + return entry; + } + var initial = { + typeKey, + unmount: mount2(), + usageCount: 1 + }; + ledger.set(typeKey, initial); + return initial; +} +__name(registerUsage, "registerUsage"); +function register(args) { + var entry = registerUsage(args); + return /* @__PURE__ */ __name(function unregister() { + entry.usageCount--; + if (entry.usageCount > 0) { + return; + } + entry.unmount(); + ledger.delete(args.typeKey); + }, "unregister"); +} +__name(register, "register"); +function combine() { + for (var _len = arguments.length, fns = new Array(_len), _key = 0; _key < _len; _key++) { + fns[_key] = arguments[_key]; + } + return /* @__PURE__ */ __name(function cleanup() { + fns.forEach(function(fn) { + return fn(); + }); + }, "cleanup"); +} +__name(combine, "combine"); +function addAttribute(element, _ref) { + var attribute = _ref.attribute, value = _ref.value; + element.setAttribute(attribute, value); + return function() { + return element.removeAttribute(attribute); + }; +} +__name(addAttribute, "addAttribute"); +function ownKeys$6(e, r) { + var t = Object.keys(e); + if (Object.getOwnPropertySymbols) { + var o = Object.getOwnPropertySymbols(e); + r && (o = o.filter(function(r2) { + return Object.getOwnPropertyDescriptor(e, r2).enumerable; + })), t.push.apply(t, o); + } + return t; +} +__name(ownKeys$6, "ownKeys$6"); +function _objectSpread$6(e) { + for (var r = 1; r < arguments.length; r++) { + var t = null != arguments[r] ? arguments[r] : {}; + r % 2 ? ownKeys$6(Object(t), true).forEach(function(r2) { + _defineProperty$6(e, r2, t[r2]); + }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$6(Object(t)).forEach(function(r2) { + Object.defineProperty(e, r2, Object.getOwnPropertyDescriptor(t, r2)); + }); + } + return e; +} +__name(_objectSpread$6, "_objectSpread$6"); +function _createForOfIteratorHelper$3(o, allowArrayLike) { + var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; + if (!it) { + if (Array.isArray(o) || (it = _unsupportedIterableToArray$5(o)) || allowArrayLike && o && typeof o.length === "number") { + if (it) o = it; + var i = 0; + var F = /* @__PURE__ */ __name(function F2() { + }, "F2"); + return { s: F, n: /* @__PURE__ */ __name(function n() { + if (i >= o.length) return { done: true }; + return { done: false, value: o[i++] }; + }, "n"), e: /* @__PURE__ */ __name(function e(_e) { + throw _e; + }, "e"), f: F }; + } + throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); + } + var normalCompletion = true, didErr = false, err; + return { s: /* @__PURE__ */ __name(function s() { + it = it.call(o); + }, "s"), n: /* @__PURE__ */ __name(function n() { + var step2 = it.next(); + normalCompletion = step2.done; + return step2; + }, "n"), e: /* @__PURE__ */ __name(function e(_e2) { + didErr = true; + err = _e2; + }, "e"), f: /* @__PURE__ */ __name(function f() { + try { + if (!normalCompletion && it.return != null) it.return(); + } finally { + if (didErr) throw err; + } + }, "f") }; +} +__name(_createForOfIteratorHelper$3, "_createForOfIteratorHelper$3"); +function _unsupportedIterableToArray$5(o, minLen) { + if (!o) return; + if (typeof o === "string") return _arrayLikeToArray$5(o, minLen); + var n = Object.prototype.toString.call(o).slice(8, -1); + if (n === "Object" && o.constructor) n = o.constructor.name; + if (n === "Map" || n === "Set") return Array.from(o); + if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray$5(o, minLen); +} +__name(_unsupportedIterableToArray$5, "_unsupportedIterableToArray$5"); +function _arrayLikeToArray$5(arr, len) { + if (len == null || len > arr.length) len = arr.length; + for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; + return arr2; +} +__name(_arrayLikeToArray$5, "_arrayLikeToArray$5"); +function copyReverse(array) { + return array.slice(0).reverse(); +} +__name(copyReverse, "copyReverse"); +function makeDropTarget(_ref) { + var typeKey = _ref.typeKey, defaultDropEffect = _ref.defaultDropEffect; + var registry = /* @__PURE__ */ new WeakMap(); + var dropTargetDataAtt = "data-drop-target-for-".concat(typeKey); + var dropTargetSelector = "[".concat(dropTargetDataAtt, "]"); + function addToRegistry2(args) { + registry.set(args.element, args); + return function() { + return registry.delete(args.element); + }; + } + __name(addToRegistry2, "addToRegistry"); + function dropTargetForConsumers(args) { + if (false) { + var existing = registry.get(args.element); + if (existing) { + console.warn("You have already registered a [".concat(typeKey, "] dropTarget on the same element"), { + existing, + proposed: args + }); + } + if (args.element instanceof HTMLIFrameElement) { + console.warn("\n We recommend not registering