import "../../../HttpMethod-rnWEgC3T.js";
import { t as ModalClientContainer_default } from "../../../ModalClientContainer-qHsZi4wQ.js";
import "../../../CodeInput-C-igR77V.js";
import "../../../Server-DnA_BzPS.js";
import "../../../AddressBar-B4xnl66I.js";
import "../../../components-ChixwQhN.js";
import "../../../Sidebar-C6AdX6-N.js";
import "../../../DataTableInput-yaU5g-kP.js";
import { i as mapHiddenClientsConfig, n as Operation_default } from "../../../operation-block-BnMIKAOh.js";
import "../../../operation-code-sample-ZUTueV3v.js";
import "../../../request-block-DwsGy64Q.js";
import "../../../SectionFilter-hrtoRLwj.js";
import "../../../code-input-iq-moLxi.js";
import "../../../data-table-PL7e8NRO.js";
import { t as mergeSecurity } from "../../../scalar-auth-selector-block-DI3DLag9.js";
import "../../../response-block-DmkaDZYs.js";
import "../../../ScalarAsciiArt-BjuSnj8e.js";
import "../../../scalar-address-bar-block--Vs6IBU1.js";
import "../../../server-tcI-OCyx.js";
import "../../../resize-D2IYvVdh.js";
import { n as Sidebar_default, t as SidebarToggle_default } from "../../../sidebar-ceSbYmnt.js";
import { t as getActiveEnvironment } from "../../../get-active-environment-CkxyQ1dM.js";
import { n as initializeWorkspaceEventHandlers, t as useGlobalHotKeys } from "../../../use-global-hot-keys-D8Ai8Qbm.js";
import { computed, createApp, createBlock, createElementBlock, createElementVNode, createVNode, defineComponent, onBeforeUnmount, openBlock, reactive, ref, toValue, unref, vShow, watch, withCtx, withDirectives } from "vue";
import { useModal } from "@scalar/components";
import { ScalarToasts } from "@scalar/use-toasts";
import { isDefined } from "@scalar/helpers/array/is-defined";
import { createWorkspaceEventBus } from "@scalar/workspace-store/events";
import { unpackProxyObject } from "@scalar/workspace-store/helpers/unpack-proxy";
import { createSidebarState, generateReverseIndex, getChildEntry } from "@scalar/sidebar";
import { getOperationEntries, getParentEntry } from "@scalar/workspace-store/navigation";
import { isHttpMethod } from "@scalar/helpers/http/is-http-method";
//#region src/v2/features/modal/helpers/resolve-route-parameters.ts
/** Type guard to check if an entry is an example. */
var isExample = (entry) => entry.type === "example";
/**
* Gets the document from the workspace store.
* Returns undefined if the document slug is not provided or the document does not exist.
*/
var getDocument = (ctx) => ctx.store.workspace.documents[ctx.documentSlug ?? ""];
/**
* Resolves the document slug from a raw input value.
*
* When "default" is specified and no document exists with that slug,
* we fall back to the active document or the first available document.
* This ensures a valid document is selected even when the caller does not know which documents exist.
*/
var resolveDocumentSlug = (store, slug) => {
	if (slug !== "default" || store.workspace.documents[slug] !== void 0) return slug;
	return store.workspace["x-scalar-active-document"] || Object.keys(store.workspace.documents)[0];
};
/**
* Resolves the path from a raw input value.
*
* When "default" is specified, returns the first available path in the document.
* This is useful for initial navigation when no specific path is requested.
*/
var resolvePath = (ctx, path) => {
	const document = getDocument(ctx);
	if (!document) return;
	if (path === "default") return Object.keys(document.paths ?? {})[0];
	return path;
};
/**
* Resolves the HTTP method from a raw input value.
*
* When "default" is specified, returns the first valid HTTP method for the given path.
* This ensures we select a real method rather than metadata keys like "parameters" or "summary".
*/
var resolveMethod = (ctx, path, method) => {
	const document = getDocument(ctx);
	if (!document || !path) return;
	if (method === "default") return Object.keys(document.paths?.[path] ?? {}).find(isHttpMethod);
	return isHttpMethod(method) ? method : void 0;
};
/**
* Resolves the example name from a raw input value.
*
* When "default" is specified, returns the first available example name.
* Falls back to "default" when no examples exist, which signals to use the default request body.
*/
var resolveExampleName = (ctx, operation, exampleKey) => {
	if (!getDocument(ctx) || operation?.type !== "operation") return "default";
	const examples = operation.children?.filter(isExample) ?? [];
	const matchingExample = examples.find((child) => child.name === exampleKey);
	if (matchingExample) return matchingExample.name;
	if (exampleKey === "default") return examples[0]?.name ?? "default";
	return "default";
};
/**
* Resolves all route parameters from raw input values to their actual values.
*
* This function handles "default" placeholders by looking up actual values from the workspace store.
* It ensures the modal can be opened even when the caller does not know specific paths, methods, or examples.
*/
var resolveRouteParameters = (store, params) => {
	const documentSlug = resolveDocumentSlug(store, params.documentSlug);
	const ctx = {
		store,
		documentSlug
	};
	const path = resolvePath(ctx, params.path);
	const method = resolveMethod(ctx, path, params.method);
	const traversedDocument = getDocument(ctx)?.["x-scalar-navigation"];
	if (!traversedDocument) return {
		documentSlug,
		path,
		method,
		example: "default"
	};
	const operation = getOperationEntries(traversedDocument).get(`${path}|${method}`)?.find((entry) => entry.type === "operation");
	return {
		documentSlug,
		path,
		method,
		example: resolveExampleName(ctx, operation, params.example)
	};
};
//#endregion
//#region src/v2/features/modal/helpers/restore-workspace-state.ts
/**
* Restores the state of a workspace document by reverting its state
* to the specified import, while preserving certain live properties
* such as servers, security schemes, and selected server.
*/
var restoreWorkspaceState = ({ workspaceStore, workspaceState, name }) => {
	if (!workspaceStore) return {
		ok: false,
		error: "Workspace store is not available"
	};
	const currentDocument = unpackProxyObject(workspaceStore.workspace.documents[name]);
	if (!currentDocument) return {
		ok: false,
		error: "Current document not found in workspace store"
	};
	const importingDocument = workspaceState.documents[name];
	if (!importingDocument) return {
		ok: false,
		error: "Importing document not found in workspace state"
	};
	const persistedProperties = {
		selectedServer: currentDocument["x-scalar-selected-server"],
		securitySchemes: currentDocument.components?.securitySchemes,
		servers: currentDocument.servers
	};
	workspaceStore.loadWorkspace({
		meta: {},
		documents: { [name]: importingDocument },
		intermediateDocuments: {},
		originalDocuments: {},
		overrides: {},
		history: {},
		auth: {}
	});
	const newDocument = unpackProxyObject(workspaceStore.workspace.documents[name]);
	if (!newDocument) return {
		ok: false,
		error: "New document not found in workspace store"
	};
	newDocument["x-scalar-selected-server"] = persistedProperties.selectedServer;
	newDocument.servers = persistedProperties.servers;
	newDocument.components ??= {};
	newDocument.components.securitySchemes = persistedProperties.securitySchemes;
	return { ok: true };
};
//#endregion
//#region src/v2/helpers/generate-location-id.ts
/**
* Generates a unique string ID for an API location, based on the document, path, method, and example.
* Filters out undefined values and serializes the composite array into a stable string.
*
* @param params - An object containing document, path, method, and optional example name.
* @returns A stringified array representing the unique location identifier.
*
* Example:
*   generateLocationId({ document: 'mydoc', path: '/users', method: 'get', example: 'default' })
*   // => '["mydoc","/users","get","default"]'
*/
var generateLocationId = ({ document, path, method, example }) => {
	return JSON.stringify([
		document,
		path,
		method,
		example
	].filter(isDefined));
};
//#endregion
//#region src/v2/features/modal/hooks/use-modal-sidebar.ts
/**
* useSidebarState - Custom hook to manage the sidebar state and navigation logic in the Scalar API client
*
* This composable manages the sidebar structure, synchronizes selection state
* with the current route, and provides a handler for selecting sidebar items.
*
* Example usage:
*
* const { handleSelectItem, sidebarState } = useSidebarState({
*   workspaceStore,
*   workspaceSlug,
*   documentSlug,
*   path,
*   method,
*   exampleName,
* })
*/
var useModalSidebar = ({ workspaceStore, documentSlug, path, method, exampleName, route }) => {
	const entries = computed(() => workspaceStore?.workspace.documents[toValue(documentSlug) ?? ""]?.["x-scalar-navigation"]?.children ?? []);
	const state = createSidebarState(entries);
	/**
	* Computed index for fast lookup of sidebar nodes by their unique API location.
	*
	* - Only indexes nodes of type 'operation', or 'example'.
	* - The lookup key is a serialized array of: [operationPath, operationMethod, exampleName?].
	* - Supports precise resolution of sidebar entries given an API "location".
	*/
	const locationIndex = computed(() => generateReverseIndex({
		items: entries.value,
		nestedKey: "children",
		filter: (node) => node.type === "operation" || node.type === "example",
		getId: (node) => {
			const operation = getParentEntry("operation", node);
			return generateLocationId({
				document: toValue(documentSlug) ?? "",
				path: operation?.path,
				method: operation?.method,
				example: node.type === "example" ? node.name : void 0
			});
		}
	}));
	/**
	* Looks up a sidebar entry by its unique API location.
	* - First tries to find an entry matching all provided properties (including example).
	* - If not found, falls back to matching only the operation (ignores example field).
	* This allows resolving either examples, operations, or documents as appropriate.
	*
	* @param location - Object specifying the document name, path, method, and optional example name.
	* @returns The matching sidebar entry, or undefined if none found.
	*
	* Example:
	*   const entry = getEntryByLocation({
	*     document: 'pets',
	*     path: '/pets',
	*     method: 'get',
	*     example: 'default',
	*   })
	*/
	const getEntryByLocation = (location) => {
		const entryWithExample = locationIndex.value.get(generateLocationId({
			document: location.document,
			path: location.path,
			method: location.method,
			example: location.example
		}));
		if (entryWithExample) return entryWithExample;
		return locationIndex.value.get(generateLocationId({
			document: location.document,
			path: location.path,
			method: location.method
		}));
	};
	/**
	* Handles item selection from the sidebar and routes navigation accordingly.
	*
	* Example:
	*   handleSelectItem('id-of-entry')
	*/
	const handleSelectItem = (id) => {
		const entry = state.getEntryById(id);
		if (!entry) {
			console.warn(`Could not find sidebar entry with id ${id} to select`);
			return;
		}
		if (entry.type === "operation" || entry.type === "example") {
			if (state.isSelected(id)) {
				state.setExpanded(id, !state.isExpanded(id));
				return;
			}
			const operation = getParentEntry("operation", entry);
			const example = getChildEntry("example", entry);
			if (example) {
				state.setSelected(example.id);
				state.setExpanded(example.id, true);
			} else state.setSelected(id);
			if (!operation) return;
			return route({
				documentSlug: toValue(documentSlug),
				path: operation.path,
				method: operation.method,
				example: example?.name ?? "default"
			});
		}
		state.setExpanded(id, !state.isExpanded(id));
	};
	/** Keep the sidebar state in sync with the modal parameters */
	watch([
		documentSlug,
		path,
		method,
		exampleName
	], ([newDocument, newPath, newMethod, newExample]) => {
		if (!newDocument) {
			state.setSelected(null);
			return;
		}
		const entry = getEntryByLocation({
			document: newDocument,
			path: newPath,
			method: newMethod,
			example: newExample
		});
		if (entry) {
			state.setSelected(entry.id);
			state.setExpanded(entry.id, true);
		}
	}, { immediate: true });
	return {
		handleSelectItem,
		state,
		getEntryByLocation
	};
};
//#endregion
//#region src/v2/features/modal/modal-events.ts
function initializeModalEvents({ eventBus, isSidebarOpen, sidebarState, modalState, store }) {
	/** Initialize workspace event handlers */
	initializeWorkspaceEventHandlers({
		eventBus,
		store: ref(store),
		hooks: {}
	});
	eventBus.on("scroll-to:nav-item", ({ id }) => sidebarState.handleSelectItem(id));
	eventBus.on("ui:toggle:sidebar", () => isSidebarOpen.value = !isSidebarOpen.value);
	eventBus.on("ui:close:client-modal", () => modalState.hide());
	eventBus.on("ui:open:client-modal", (payload) => {
		if (!payload) {
			modalState.show();
			return;
		}
		if ("id" in payload && payload.id) {
			let targetId = payload.id;
			if ("exampleName" in payload && payload.exampleName) {
				const operationEntry = sidebarState.state.getEntryById(payload.id);
				if (operationEntry && "children" in operationEntry && operationEntry.children) {
					const exampleEntry = operationEntry.children.find((child) => child.type === "example" && child.name === payload.exampleName);
					if (exampleEntry) targetId = exampleEntry.id;
				}
			}
			sidebarState.handleSelectItem(targetId);
		} else if ("method" in payload && "path" in payload) sidebarState.handleSelectItem(sidebarState.getEntryByLocation({
			document: store.workspace.activeDocument?.["x-scalar-navigation"]?.id ?? "",
			path: payload.path,
			method: payload.method,
			example: payload.exampleName
		})?.id ?? "");
		modalState.show();
	});
}
//#endregion
//#region src/v2/hooks/use-scroll-lock.ts
/**
* useScrollLock - A Vue composition function to lock and unlock scrolling on a specific element.
*
* This hook provides a computed ref that allows you to enable or disable scrolling on a given HTMLElement.
* Locking sets the element's `overflow` style to `'hidden'`.
* Unlocking restores the original `overflow` value.
*
* The lock state will be automatically cleaned up (unlocked) when the component is unmounted.
*
* @param element - MaybeRefOrGetter for the HTMLElement to lock scrolling on. Can be a ref or a function.
* @returns A computed ref: assign `true` to lock, `false` to unlock, read for current state.
*
* @example
* ```ts
* // In your setup():
* const container = ref<HTMLElement | null>(null)
* const scrollLock = useScrollLock(container)
*
* // To lock scrolling:
* scrollLock.value = true
*
* // To unlock scrolling:
* scrollLock.value = false
* ```
*/
var useScrollLock = (element) => {
	const initialValue = ref("");
	const isLocked = ref(false);
	const lock = () => {
		const el = toValue(element);
		if (!el) return;
		initialValue.value = el.style.overflow;
		el.style.overflow = "hidden";
	};
	const unlock = () => {
		const el = toValue(element);
		if (!el) return;
		if (initialValue.value !== "") el.style.overflow = initialValue.value;
		else el.style.removeProperty("overflow");
	};
	const state = computed({
		get: () => isLocked.value,
		set: (value) => {
			isLocked.value = value;
			value ? lock() : unlock();
		}
	});
	onBeforeUnmount(() => {
		if (isLocked.value) unlock();
	});
	return state;
};
//#endregion
//#region src/v2/features/modal/Modal.vue?vue&type=script&setup=true&lang.ts
var _hoisted_1 = {
	key: 0,
	class: "relative flex h-full min-h-0 w-full flex-1"
};
var _hoisted_2 = {
	key: 1,
	class: "flex h-full w-full items-center justify-center"
};
//#endregion
//#region src/v2/features/modal/Modal.vue
var Modal_default = /* @__PURE__ */ defineComponent({
	__name: "Modal",
	props: {
		workspaceStore: {},
		document: {},
		path: {},
		eventBus: {},
		method: {},
		exampleName: {},
		modalState: {},
		sidebarState: {},
		plugins: {},
		options: {}
	},
	setup(__props, { expose: __expose }) {
		const activeWorkspace = {
			label: "default",
			id: "default"
		};
		/** Controls the visibility of the sidebar. */
		const isSidebarOpen = ref(false);
		/** Initialize modal events */
		initializeModalEvents({
			eventBus: __props.eventBus,
			isSidebarOpen,
			sidebarState: __props.sidebarState,
			modalState: __props.modalState,
			store: __props.workspaceStore
		});
		/** Register global hotkeys for the app, passing the workspace event bus and layout state */
		useGlobalHotKeys(__props.eventBus, "modal", () => !__props.modalState.open);
		/** Clean up on close */
		const cleanUp = () => {
			__props.eventBus.emit("operation:cancel:request");
		};
		const isLocked = useScrollLock(() => {
			if (typeof window !== "undefined") return window.document.body;
			return null;
		});
		watch(() => __props.modalState.open, (open) => {
			isLocked.value = open;
			if (!open) cleanUp();
		});
		onBeforeUnmount(() => cleanUp());
		/** Default sidebar width in pixels. */
		const DEFAULT_SIDEBAR_WIDTH = 288;
		/** Width of the sidebar, with fallback to default. */
		const sidebarWidth = computed(() => __props.workspaceStore?.workspace?.["x-scalar-sidebar-width"] ?? DEFAULT_SIDEBAR_WIDTH);
		/** Handler for sidebar width changes. */
		const handleSidebarWidthUpdate = (width) => __props.workspaceStore?.update("x-scalar-sidebar-width", width);
		/**
		* Merged environment variables from workspace and document levels.
		* Variables from both sources are combined, with document variables
		* taking precedence in case of naming conflicts.
		*/
		const environment = computed(() => getActiveEnvironment(__props.workspaceStore, __props.document.value));
		/** Merge authentication config with the document security schemes */
		const securitySchemes = computed(() => mergeSecurity(__props.document.value?.components?.securitySchemes, toValue(__props.options)?.authentication?.securitySchemes, __props.workspaceStore.auth, __props.document.value?.["x-scalar-navigation"]?.name ?? ""));
		__expose({
			sidebarWidth,
			environment
		});
		return (_ctx, _cache) => {
			return openBlock(), createBlock(ModalClientContainer_default, { modalState: __props.modalState }, {
				default: withCtx(() => [createVNode(unref(ScalarToasts)), __props.document.value && __props.path?.value && __props.method?.value ? (openBlock(), createElementBlock("main", _hoisted_1, [
					createVNode(unref(SidebarToggle_default), {
						modelValue: isSidebarOpen.value,
						"onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => isSidebarOpen.value = $event),
						class: "absolute top-2 left-3 z-2"
					}, null, 8, ["modelValue"]),
					withDirectives(createVNode(unref(Sidebar_default), {
						sidebarWidth: sidebarWidth.value,
						"onUpdate:sidebarWidth": [_cache[1] || (_cache[1] = ($event) => sidebarWidth.value = $event), handleSidebarWidthUpdate],
						activeWorkspace,
						class: "h-full max-md:absolute! max-md:w-full!",
						documents: [__props.document.value],
						eventBus: __props.eventBus,
						isDroppable: () => false,
						layout: "modal",
						sidebarState: __props.sidebarState.state,
						workspaces: [],
						onSelectItem: __props.sidebarState.handleSelectItem
					}, null, 8, [
						"sidebarWidth",
						"documents",
						"eventBus",
						"sidebarState",
						"onSelectItem"
					]), [[vShow, isSidebarOpen.value]]),
					createVNode(Operation_default, {
						activeWorkspace,
						class: "flex-1",
						document: __props.document.value,
						documentSlug: __props.document.value["x-scalar-navigation"]?.id ?? "",
						environment: environment.value,
						eventBus: __props.eventBus,
						exampleName: __props.exampleName?.value,
						layout: "modal",
						method: __props.method?.value,
						options: __props.options,
						path: __props.path?.value,
						plugins: __props.plugins,
						securitySchemes: securitySchemes.value,
						workspaceStore: __props.workspaceStore
					}, null, 8, [
						"document",
						"documentSlug",
						"environment",
						"eventBus",
						"exampleName",
						"method",
						"options",
						"path",
						"plugins",
						"securitySchemes",
						"workspaceStore"
					])
				])) : (openBlock(), createElementBlock("div", _hoisted_2, [..._cache[2] || (_cache[2] = [createElementVNode("span", { class: "text-c-3" }, "No document selected", -1)])]))]),
				_: 1
			}, 8, ["modalState"]);
		};
	}
});
//#endregion
//#region src/v2/features/modal/helpers/create-api-client-modal.ts
/**
* Creates the API Client Modal.
*
* The modal does not require a router. Instead, navigation is handled by setting
* active entities directly through the returned `route` function.
*/
var createApiClientModal = ({ el, eventBus = createWorkspaceEventBus({ debug: false }), mountOnInitialize = true, plugins = [], workspaceStore, options = {} }) => {
	const defaultEntities = {
		path: "default",
		method: "default",
		example: "default",
		documentSlug: workspaceStore.workspace["x-scalar-active-document"] || "default"
	};
	const workspaceStoreSnapshot = ref(null);
	const parameters = reactive({ ...defaultEntities });
	/** Navigate to the specified path, method, and example. */
	const route = (payload) => {
		Object.assign(parameters, defaultEntities, payload);
	};
	/** Resolved parameters from the workspace store. */
	const resolvedParameters = computed(() => resolveRouteParameters(workspaceStore, parameters));
	const documentSlug = computed(() => resolvedParameters.value.documentSlug);
	const path = computed(() => resolvedParameters.value.path);
	const method = computed(() => resolvedParameters.value.method);
	const exampleName = computed(() => resolvedParameters.value.example);
	/** The document from the workspace store. */
	const document = computed(() => workspaceStore.workspace.documents[documentSlug.value ?? ""] ?? null);
	/** Sidebar state and selection handling. */
	const sidebarState = useModalSidebar({
		workspaceStore,
		documentSlug,
		path,
		method,
		exampleName,
		route
	});
	const modalState = useModal();
	const app = createApp(Modal_default, {
		document,
		eventBus,
		exampleName,
		method,
		modalState,
		path,
		plugins,
		sidebarState,
		workspaceStore,
		options
	});
	/** Snapshot the workspace store when the modal is opened. */
	const handleModalOpen = () => {
		workspaceStoreSnapshot.value = window.structuredClone(workspaceStore.exportWorkspace());
	};
	/** Restore the workspace store when the modal is closed. */
	const handleModalClose = () => {
		if (!workspaceStoreSnapshot.value) {
			console.warn("No workspace store snapshot to restore");
			return;
		}
		const result = restoreWorkspaceState({
			workspaceStore,
			workspaceState: workspaceStoreSnapshot.value,
			name: documentSlug.value ?? ""
		});
		if (!result.ok) console.error("Failed to restore workspace state", result.error);
	};
	watch(() => modalState.open, (open) => open ? handleModalOpen() : handleModalClose());
	app.config.idPrefix = "scalar-client";
	/** Mount the modal to a given element. */
	const mount = (mountingEl = el) => {
		if (!mountingEl) {
			console.error("[@scalar/api-client] Could not create the API client Modal.", "Invalid HTML element provided.", "Read more: https://github.com/scalar/scalar/tree/main/packages/api-client");
			return;
		}
		app.mount(mountingEl);
	};
	if (mountOnInitialize) mount();
	return {
		app,
		open: (payload) => {
			modalState.open = true;
			if (payload) route(payload);
		},
		mount,
		route,
		modalState
	};
};
//#endregion
export { createApiClientModal, initializeModalEvents, mapHiddenClientsConfig };

//# sourceMappingURL=index.js.map