import { n as formatMs } from "./formatters-DOGXZq9R.js";
import { t as _plugin_vue_export_helper_default } from "./_plugin-vue_export-helper-BmmBcIzD.js";
import { t as HttpMethod_default } from "./HttpMethod-rnWEgC3T.js";
import { t as getResolvedUrl } from "./get-resolved-url-BUCwrBzc.js";
import { t as CodeInput_default } from "./code-input-iq-moLxi.js";
import { t as ValueEmitter_default } from "./ValueEmitter-QYkZ9Hdc.js";
import { t as ServerDropdown_default } from "./server-tcI-OCyx.js";
import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createSlots, createTextVNode, createVNode, defineComponent, normalizeClass, normalizeStyle, onBeforeUnmount, onMounted, openBlock, ref, renderList, toDisplayString, unref, useId, useTemplateRef, withCtx } from "vue";
import { ScalarButton, ScalarFloating, ScalarFloatingBackdrop, ScalarIcon, ScalarWrappingText } from "@scalar/components";
import { useClipboard } from "@scalar/use-hooks/useClipboard";
import { httpStatusCodes } from "@scalar/oas-utils/helpers";
import { Menu, MenuButton, MenuItem, MenuItems } from "@headlessui/vue";
import { REQUEST_METHODS } from "@scalar/helpers/http/http-info";
import { ScalarIconCopy, ScalarIconWarningCircle } from "@scalar/icons";
//#region src/v2/blocks/scalar-address-bar-block/hooks/use-loading-animation.ts
/**
* Constants for the loading animation behavior.
* These control how the progress bar animates during and after requests.
*/
var TICK_INTERVAL_MS = 20;
var MAX_PERCENTAGE = 100;
var MIN_PERCENTAGE = 0;
var ASYMPTOTIC_LIMIT = 15;
var ASYMPTOTIC_DIVISOR = 60;
var FINISH_ANIMATION_STEPS = 400 / TICK_INTERVAL_MS;
/**
* Manages the loading animation for the address bar.
*
* The animation has two phases:
* 1. While requesting: Animates asymptotically toward 85% to indicate ongoing work
* 2. After request completes: Animates linearly to 100% over 400ms for smooth completion
*
* This creates a natural feel where the bar does not instantly jump to 100%,
* making the loading experience more predictable and less jarring.
*
* @returns An object with methods to control the loading animation and the current percentage
*/
var useLoadingAnimation = () => {
	/** The current loading percentage from 100 (not started) to 0 (complete) */
	const percentage = ref(MAX_PERCENTAGE);
	/** Tracks how much percentage was remaining when the request completed */
	const remaining = ref(0);
	/** Indicates whether a request is currently in progress */
	const isRequesting = ref(false);
	/** The interval timer that drives the animation */
	const interval = ref();
	/**
	* Resets the animation state to initial values.
	* This is called when the animation completes.
	*/
	const resetAnimation = () => {
		clearInterval(interval.value);
		interval.value = void 0;
		percentage.value = MAX_PERCENTAGE;
		isRequesting.value = false;
	};
	/**
	* Advances the loading animation by one tick.
	* Uses different animation strategies based on whether a request is active.
	*/
	const load = () => {
		if (isRequesting.value) percentage.value -= (percentage.value - ASYMPTOTIC_LIMIT) / ASYMPTOTIC_DIVISOR;
		else percentage.value -= remaining.value / FINISH_ANIMATION_STEPS;
		if (percentage.value <= MIN_PERCENTAGE) resetAnimation();
	};
	/**
	* Starts the loading animation.
	* If called while the finishing animation is running, it switches back to requesting mode.
	* This handles the case where a new request starts before the previous animation completes.
	*/
	const startLoading = () => {
		if (interval.value) {
			isRequesting.value = true;
			return;
		}
		isRequesting.value = true;
		interval.value = setInterval(load, TICK_INTERVAL_MS);
	};
	/**
	* Marks the request as complete and begins the finish animation.
	* The animation will continue until it reaches 100% to provide visual feedback.
	*/
	const stopLoading = () => {
		remaining.value = percentage.value;
		isRequesting.value = false;
	};
	return {
		startLoading,
		stopLoading,
		percentage,
		isLoading: isRequesting
	};
};
//#endregion
//#region src/v2/blocks/scalar-address-bar-block/components/httpStatusCodeColors.ts
var STATUS_CODES_COLORS = {
	100: { color: "text-yellow" },
	200: { color: "text-green" },
	202: { color: "text-green" },
	300: { color: "text-blue" },
	304: { color: "text-blue" },
	400: { color: "text-red" },
	401: { color: "text-orange" },
	422: { color: "text-yellow" },
	423: { color: "text-purple" },
	505: { color: "text-orange" }
};
var getStatusCodeColor = (statusCode) => {
	return STATUS_CODES_COLORS[statusCode] || { color: "text-grey" };
};
//#endregion
//#region src/v2/blocks/scalar-address-bar-block/components/AddressBarHistory.vue?vue&type=script&setup=true&lang.ts
var _hoisted_1$1 = { class: "min-w-0" };
var _hoisted_2$1 = { class: "text-c-1 min-w-0 truncate" };
//#endregion
//#region src/v2/blocks/scalar-address-bar-block/components/AddressBarHistory.vue
var AddressBarHistory_default = /* @__PURE__ */ _plugin_vue_export_helper_default(/* @__PURE__ */ defineComponent({
	__name: "AddressBarHistory",
	props: {
		target: {},
		history: {}
	},
	emits: ["select:history:item", "update:open"],
	setup(__props, { emit: __emit }) {
		const emits = __emit;
		return (_ctx, _cache) => {
			return openBlock(), createBlock(unref(Menu), { as: "div" }, {
				default: withCtx(({ open }) => [createVNode(ValueEmitter_default, {
					value: open,
					onChange: _cache[0] || (_cache[0] = (value) => emits("update:open", value)),
					onUnmount: _cache[1] || (_cache[1] = ($event) => emits("update:open", false))
				}, null, 8, ["value"]), createVNode(unref(ScalarFloating), {
					offset: 0,
					resize: "",
					target: __props.target
				}, createSlots({
					default: withCtx(() => [__props.history.length ? (openBlock(), createBlock(unref(MenuButton), {
						key: 0,
						class: "address-bar-history-button text-c-3 focus:text-c-1 relative mr-1 rounded-lg p-1.5"
					}, {
						default: withCtx(() => [createVNode(unref(ScalarIcon), {
							icon: "History",
							size: "sm",
							thickness: "2.25"
						}), _cache[2] || (_cache[2] = createElementVNode("span", { class: "sr-only" }, "Request History", -1))]),
						_: 1
					})) : createCommentVNode("", true)]),
					_: 2
				}, [open ? {
					name: "floating",
					fn: withCtx(({ width }) => [createVNode(unref(MenuItems), {
						class: "custom-scroll grid max-h-[inherit] grid-cols-[44px_1fr_repeat(3,auto)] items-center p-0.75",
						static: "",
						style: normalizeStyle({ width })
					}, {
						default: withCtx(() => [(openBlock(true), createElementBlock(Fragment, null, renderList(__props.history, (entry, index) => {
							return openBlock(), createBlock(unref(MenuItem), {
								key: index,
								as: "button",
								class: "font-code ui-active:*:bg-b-2 text-c-2 contents text-sm font-medium *:flex *:h-8 *:cursor-pointer *:items-center *:rounded-none *:px-1.5 *:first:rounded-l *:last:rounded-r",
								value: index,
								onClick: ($event) => emits("select:history:item", { index })
							}, {
								default: withCtx(() => [
									createVNode(unref(HttpMethod_default), {
										class: "text-[11px]",
										method: entry.method
									}, null, 8, ["method"]),
									createElementVNode("div", _hoisted_1$1, [createElementVNode("div", _hoisted_2$1, toDisplayString(entry.path), 1)]),
									createElementVNode("div", null, toDisplayString(unref(formatMs)(entry.duration)), 1),
									createElementVNode("div", { class: normalizeClass([unref(getStatusCodeColor)(entry.status).color]) }, toDisplayString(entry.status), 3),
									createElementVNode("div", null, toDisplayString(unref(httpStatusCodes)[entry.status]?.name), 1)
								]),
								_: 2
							}, 1032, ["value", "onClick"]);
						}), 128))]),
						_: 1
					}, 8, ["style"]), createVNode(unref(ScalarFloatingBackdrop), { class: "inset-x-px rounded-none rounded-b-lg" })]),
					key: "0"
				} : void 0]), 1032, ["target"])]),
				_: 1
			});
		};
	}
}), [["__scopeId", "data-v-c15c6573"]]);
//#endregion
//#region src/v2/blocks/scalar-address-bar-block/components/AddressBar.vue?vue&type=script&setup=true&lang.ts
var _hoisted_1 = ["id"];
var _hoisted_2 = { class: "flex gap-1" };
var _hoisted_3 = { class: "scroll-timeline-x scroll-timeline-x-hidden relative flex w-full bg-blend-normal" };
var _hoisted_4 = {
	key: 0,
	class: "absolute inset-x-0 top-[calc(100%+4px)] flex flex-col items-center rounded px-6"
};
var _hoisted_5 = { class: "text-c-danger bg-b-danger border-c-danger flex items-center gap-1 rounded border p-1" };
var _hoisted_6 = { class: "min-w-0 flex-1" };
var _hoisted_7 = {
	"aria-hidden": "true",
	class: "inline-flex items-center gap-1"
};
var _hoisted_8 = { class: "sr-only" };
//#endregion
//#region src/v2/blocks/scalar-address-bar-block/components/AddressBar.vue
var AddressBar_default = /* @__PURE__ */ _plugin_vue_export_helper_default(/* @__PURE__ */ defineComponent({
	name: "AddressBar",
	props: {
		path: {},
		method: {},
		server: {},
		servers: {},
		history: {},
		layout: {},
		eventBus: {},
		environment: {},
		serverMeta: {}
	},
	emits: ["execute", "select:history:item"],
	setup(__props, { expose: __expose, emit: __emit }) {
		const emit = __emit;
		const id = useId();
		const { percentage, startLoading, stopLoading, isLoading } = useLoadingAnimation();
		/** Calculate the style for the address bar */
		const style = computed(() => ({
			backgroundColor: `color-mix(in srgb, transparent 90%, ${REQUEST_METHODS[__props.method].colorVar})`,
			transform: `translate3d(-${percentage.value}%,0,0)`
		}));
		const pathConflict = ref(null);
		const methodConflict = ref(null);
		/** Whether there is a path or method conflict */
		const hasConflict = computed(() => methodConflict.value || pathConflict.value);
		/** Emit the path/method update event with conflict handling */
		const emitPathMethodUpdate = (targetMethod, targetPath, emitOptions) => {
			const position = addressBarRef.value?.cursorPosition();
			__props.eventBus.emit("operation:update:pathMethod", {
				meta: {
					method: __props.method,
					path: __props.path
				},
				payload: {
					method: targetMethod,
					path: targetPath
				},
				callback: (status) => {
					if (status === "success" || status === "no-change") {
						methodConflict.value = null;
						pathConflict.value = null;
					}
					if (status === "success") __props.eventBus.emit("ui:focus:address-bar", { position });
					else if (status === "conflict") {
						if (targetMethod !== __props.method) methodConflict.value = targetMethod;
						if (targetPath !== __props.path) pathConflict.value = targetPath;
					}
				}
			}, emitOptions);
		};
		/** Update the operation's HTTP method, handling conflicts */
		const handleMethodChange = (newMethod) => emitPathMethodUpdate(newMethod, pathConflict.value ?? __props.path);
		/** Update the operation's path, handling conflicts */
		const handlePathChange = (newPath) => {
			const normalizedPath = newPath.startsWith("/") ? newPath : `/${newPath}`;
			emitPathMethodUpdate(methodConflict.value ?? __props.method, normalizedPath, { debounceKey: `operation:update:pathMethod-${__props.path}-${__props.method}` });
		};
		/** Handle focus events */
		const sendButtonRef = useTemplateRef("sendButtonRef");
		const addressBarRef = useTemplateRef("addressBarRef");
		const handleFocusSendButton = () => sendButtonRef.value?.$el?.focus();
		const handleFocusAddressBar = (payload) => {
			if (addressBarRef.value?.isFocused && __props.layout !== "desktop") return;
			const position = payload && "position" in payload ? payload.position : "end";
			addressBarRef.value?.focus(position);
			if (payload && "event" in payload) payload.event.preventDefault();
		};
		onMounted(() => {
			__props.eventBus.on("ui:focus:address-bar", handleFocusAddressBar);
			__props.eventBus.on("ui:focus:send-button", handleFocusSendButton);
			__props.eventBus.on("hooks:on:request:sent", startLoading);
			__props.eventBus.on("hooks:on:request:complete", stopLoading);
		});
		onBeforeUnmount(() => {
			__props.eventBus.off("ui:focus:address-bar", handleFocusAddressBar);
			__props.eventBus.off("ui:focus:send-button", handleFocusSendButton);
			__props.eventBus.off("hooks:on:request:sent", startLoading);
			__props.eventBus.off("hooks:on:request:complete", stopLoading);
			stopLoading();
		});
		const { copyToClipboard } = useClipboard();
		const copyUrl = async () => {
			await copyToClipboard(getResolvedUrl({
				environment: __props.environment,
				server: __props.server,
				path: __props.path,
				pathVariables: {}
			}));
		};
		const isServerDropdownOpen = ref(false);
		const isHistoryDropdownOpen = ref(false);
		/** Whether either dropdown is open */
		const isDropdownOpen = computed(() => isServerDropdownOpen.value || isHistoryDropdownOpen.value);
		const navigateToServersPage = () => {
			if (__props.serverMeta.type === "operation") return __props.eventBus.emit("ui:navigate", {
				page: "operation",
				path: "servers",
				operationPath: __props.serverMeta.path,
				method: __props.serverMeta.method
			});
			return __props.eventBus.emit("ui:navigate", {
				page: "document",
				path: "servers"
			});
		};
		__expose({
			methodConflict,
			pathConflict
		});
		return (_ctx, _cache) => {
			return openBlock(), createElementBlock("div", {
				id: unref(id),
				class: "scalar-address-bar order-last flex h-(--scalar-address-bar-height) w-full [--scalar-address-bar-height:32px] lg:order-0 lg:w-auto"
			}, [createElementVNode("div", { class: normalizeClass(["address-bar-bg-states text-xxs group relative order-last flex w-full max-w-[calc(100dvw-24px)] flex-1 flex-row items-stretch rounded-lg p-0.75 lg:order-none lg:max-w-[580px] lg:min-w-[580px] xl:max-w-[720px] xl:min-w-[720px]", {
				"outline-c-danger outline": hasConflict.value,
				"rounded-b-none": isDropdownOpen.value
			}]) }, [
				createElementVNode("div", { class: normalizeClass(["pointer-events-none absolute top-0 left-0 block h-full w-full overflow-hidden rounded-lg border", { "rounded-b-none": isDropdownOpen.value }]) }, [createElementVNode("div", {
					class: "absolute top-0 left-0 h-full w-full",
					style: normalizeStyle(style.value)
				}, null, 4)], 2),
				createElementVNode("div", _hoisted_2, [createVNode(unref(HttpMethod_default), {
					isEditable: __props.layout !== "modal",
					isSquare: "",
					method: methodConflict.value ?? __props.method,
					teleport: "",
					onChange: handleMethodChange
				}, null, 8, ["isEditable", "method"])]),
				createElementVNode("div", _hoisted_3, [
					__props.servers.length ? (openBlock(), createBlock(unref(ServerDropdown_default), {
						key: 0,
						layout: __props.layout,
						meta: __props.serverMeta,
						server: __props.server,
						servers: __props.servers,
						target: unref(id),
						"onUpdate:open": _cache[0] || (_cache[0] = (value) => isServerDropdownOpen.value = value),
						"onUpdate:selectedServer": _cache[1] || (_cache[1] = (payload) => __props.eventBus.emit("server:update:selected", payload)),
						"onUpdate:servers": navigateToServersPage,
						"onUpdate:variable": _cache[2] || (_cache[2] = (payload) => __props.eventBus.emit("server:update:variables", payload))
					}, null, 8, [
						"layout",
						"meta",
						"server",
						"servers",
						"target"
					])) : createCommentVNode("", true),
					_cache[7] || (_cache[7] = createElementVNode("div", { class: "fade-left" }, null, -1)),
					createVNode(unref(CodeInput_default), {
						ref_key: "addressBarRef",
						ref: addressBarRef,
						alwaysEmitChange: "",
						"aria-label": "Path",
						class: "min-w-fit outline-none",
						disableCloseBrackets: "",
						disabled: __props.layout === "modal",
						disableEnter: "",
						disableTabIndent: "",
						emitOnBlur: false,
						environment: __props.environment,
						importCurl: "",
						layout: __props.layout,
						modelValue: __props.path,
						placeholder: __props.server ? "" : "Enter a URL",
						server: "",
						onSubmit: _cache[3] || (_cache[3] = ($event) => emit("execute")),
						"onUpdate:modelValue": handlePathChange
					}, null, 8, [
						"disabled",
						"environment",
						"layout",
						"modelValue",
						"placeholder"
					]),
					_cache[8] || (_cache[8] = createElementVNode("div", { class: "fade-right" }, null, -1))
				]),
				createVNode(unref(ScalarButton), {
					class: "hover:bg-b-3 mx-1",
					size: "xs",
					variant: "ghost",
					onClick: copyUrl
				}, {
					default: withCtx(() => [createVNode(unref(ScalarIconCopy)), _cache[9] || (_cache[9] = createElementVNode("span", { class: "sr-only" }, "Copy URL", -1))]),
					_: 1
				}),
				createVNode(AddressBarHistory_default, {
					history: __props.history,
					target: unref(id),
					"onSelect:history:item": _cache[4] || (_cache[4] = (payload) => emit("select:history:item", payload)),
					"onUpdate:open": _cache[5] || (_cache[5] = (value) => isHistoryDropdownOpen.value = value)
				}, null, 8, ["history", "target"]),
				hasConflict.value ? (openBlock(), createElementBlock("div", _hoisted_4, [createElementVNode("div", _hoisted_5, [createVNode(unref(ScalarIconWarningCircle), { size: "sm" }), createElementVNode("div", _hoisted_6, [
					_cache[10] || (_cache[10] = createTextVNode(" A ", -1)),
					createElementVNode("em", null, toDisplayString(methodConflict.value?.toUpperCase() ?? __props.method.toUpperCase()), 1),
					_cache[11] || (_cache[11] = createTextVNode(" request to ", -1)),
					createVNode(unref(ScalarWrappingText), { text: pathConflict.value ?? __props.path }, null, 8, ["text"]),
					_cache[12] || (_cache[12] = createTextVNode(" already exists in this document ", -1))
				])])])) : createCommentVNode("", true),
				createVNode(unref(ScalarButton), {
					ref_key: "sendButtonRef",
					ref: sendButtonRef,
					class: "relative h-auto shrink-0 overflow-hidden py-1 pr-2.5 pl-2 font-bold",
					disabled: unref(isLoading),
					onClick: _cache[6] || (_cache[6] = ($event) => emit("execute"))
				}, {
					default: withCtx(() => [createElementVNode("span", _hoisted_7, [createVNode(unref(ScalarIcon), {
						class: "relative shrink-0 fill-current",
						icon: "Play",
						size: "xs"
					}), _cache[13] || (_cache[13] = createElementVNode("span", { class: "text-xxs hidden lg:flex" }, "Send", -1))]), createElementVNode("span", _hoisted_8, " Send " + toDisplayString(__props.method) + " request to " + toDisplayString(__props.server?.url ?? "") + toDisplayString(__props.path), 1)]),
					_: 1
				}, 8, ["disabled"])
			], 2)], 8, _hoisted_1);
		};
	}
}), [["__scopeId", "data-v-f5565642"]]);
//#endregion
export { AddressBar_default as t };

//# sourceMappingURL=scalar-address-bar-block--Vs6IBU1.js.map