@scalar/api-client 3.10.2 → 3.10.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/dist/style.css +188 -96
  3. package/dist/v2/blocks/operation-code-sample/helpers/operation-to-har/process-security-schemes.d.ts.map +1 -1
  4. package/dist/v2/blocks/operation-code-sample/helpers/operation-to-har/process-security-schemes.js.map +1 -1
  5. package/dist/v2/blocks/operation-code-sample/index.d.ts +1 -1
  6. package/dist/v2/blocks/operation-code-sample/index.d.ts.map +1 -1
  7. package/dist/v2/blocks/operation-code-sample/index.js +2 -2
  8. package/dist/v2/blocks/request-block/components/RequestTable.vue.d.ts.map +1 -1
  9. package/dist/v2/blocks/request-block/components/RequestTable.vue.js +1 -1
  10. package/dist/v2/blocks/request-block/components/RequestTable.vue.js.map +1 -1
  11. package/dist/v2/blocks/request-block/components/RequestTable.vue.script.js.map +1 -1
  12. package/dist/v2/blocks/request-block/components/RequestTableRow.vue.d.ts.map +1 -1
  13. package/dist/v2/blocks/request-block/components/RequestTableRow.vue.js.map +1 -1
  14. package/dist/v2/blocks/request-block/components/RequestTableRow.vue.script.js +13 -28
  15. package/dist/v2/blocks/request-block/components/RequestTableRow.vue.script.js.map +1 -1
  16. package/dist/v2/blocks/scalar-address-bar-block/components/AddressBar.vue.d.ts.map +1 -1
  17. package/dist/v2/blocks/scalar-address-bar-block/components/AddressBar.vue.js +1 -1
  18. package/dist/v2/blocks/scalar-address-bar-block/components/AddressBar.vue.js.map +1 -1
  19. package/dist/v2/blocks/scalar-address-bar-block/components/AddressBar.vue.script.js.map +1 -1
  20. package/dist/v2/blocks/scalar-auth-selector-block/components/OAuth2.vue.d.ts +4 -1
  21. package/dist/v2/blocks/scalar-auth-selector-block/components/OAuth2.vue.d.ts.map +1 -1
  22. package/dist/v2/blocks/scalar-auth-selector-block/components/OAuth2.vue.js.map +1 -1
  23. package/dist/v2/blocks/scalar-auth-selector-block/components/OAuth2.vue.script.js +2 -2
  24. package/dist/v2/blocks/scalar-auth-selector-block/components/OAuth2.vue.script.js.map +1 -1
  25. package/dist/v2/blocks/scalar-auth-selector-block/components/OpenIDConnect.vue.d.ts +3 -0
  26. package/dist/v2/blocks/scalar-auth-selector-block/components/OpenIDConnect.vue.d.ts.map +1 -1
  27. package/dist/v2/blocks/scalar-auth-selector-block/components/OpenIDConnect.vue.js.map +1 -1
  28. package/dist/v2/blocks/scalar-auth-selector-block/components/OpenIDConnect.vue.script.js +3 -2
  29. package/dist/v2/blocks/scalar-auth-selector-block/components/OpenIDConnect.vue.script.js.map +1 -1
  30. package/dist/v2/blocks/scalar-auth-selector-block/components/RequestAuthDataTableInput.vue.d.ts.map +1 -1
  31. package/dist/v2/blocks/scalar-auth-selector-block/components/RequestAuthDataTableInput.vue.js.map +1 -1
  32. package/dist/v2/blocks/scalar-auth-selector-block/components/RequestAuthDataTableInput.vue.script.js +0 -1
  33. package/dist/v2/blocks/scalar-auth-selector-block/components/RequestAuthDataTableInput.vue.script.js.map +1 -1
  34. package/dist/v2/blocks/scalar-auth-selector-block/components/RequestAuthTab.vue.d.ts.map +1 -1
  35. package/dist/v2/blocks/scalar-auth-selector-block/components/RequestAuthTab.vue.js.map +1 -1
  36. package/dist/v2/blocks/scalar-auth-selector-block/components/RequestAuthTab.vue.script.js +2 -0
  37. package/dist/v2/blocks/scalar-auth-selector-block/components/RequestAuthTab.vue.script.js.map +1 -1
  38. package/dist/v2/blocks/scalar-auth-selector-block/helpers/fetch-openid-connect-discovery.d.ts +4 -1
  39. package/dist/v2/blocks/scalar-auth-selector-block/helpers/fetch-openid-connect-discovery.d.ts.map +1 -1
  40. package/dist/v2/blocks/scalar-auth-selector-block/helpers/fetch-openid-connect-discovery.js +4 -3
  41. package/dist/v2/blocks/scalar-auth-selector-block/helpers/fetch-openid-connect-discovery.js.map +1 -1
  42. package/dist/v2/blocks/scalar-auth-selector-block/helpers/oauth.d.ts +7 -2
  43. package/dist/v2/blocks/scalar-auth-selector-block/helpers/oauth.d.ts.map +1 -1
  44. package/dist/v2/blocks/scalar-auth-selector-block/helpers/oauth.js +11 -9
  45. package/dist/v2/blocks/scalar-auth-selector-block/helpers/oauth.js.map +1 -1
  46. package/dist/v2/components/code-input/CodeInput.vue.d.ts.map +1 -1
  47. package/dist/v2/components/code-input/CodeInput.vue.js +1 -1
  48. package/dist/v2/components/code-input/CodeInput.vue.js.map +1 -1
  49. package/dist/v2/components/code-input/CodeInput.vue.script.js +3 -2
  50. package/dist/v2/components/code-input/CodeInput.vue.script.js.map +1 -1
  51. package/dist/v2/components/code-input/CodeInputLite.vue.d.ts +124 -0
  52. package/dist/v2/components/code-input/CodeInputLite.vue.d.ts.map +1 -0
  53. package/dist/v2/components/code-input/CodeInputLite.vue.js +10 -0
  54. package/dist/v2/components/code-input/CodeInputLite.vue.js.map +1 -0
  55. package/dist/v2/components/code-input/CodeInputLite.vue.script.js +631 -0
  56. package/dist/v2/components/code-input/CodeInputLite.vue.script.js.map +1 -0
  57. package/dist/v2/components/code-input/PillTooltipHost.vue.d.ts +3 -0
  58. package/dist/v2/components/code-input/PillTooltipHost.vue.d.ts.map +1 -1
  59. package/dist/v2/components/code-input/PillTooltipHost.vue.js.map +1 -1
  60. package/dist/v2/components/code-input/PillTooltipHost.vue.script.js +23 -11
  61. package/dist/v2/components/code-input/PillTooltipHost.vue.script.js.map +1 -1
  62. package/dist/v2/components/code-input/code-variable-widget.d.ts.map +1 -1
  63. package/dist/v2/components/code-input/code-variable-widget.js +5 -2
  64. package/dist/v2/components/code-input/code-variable-widget.js.map +1 -1
  65. package/dist/v2/components/code-input/helpers/build-pill-context.d.ts +11 -0
  66. package/dist/v2/components/code-input/helpers/build-pill-context.d.ts.map +1 -0
  67. package/dist/v2/components/code-input/helpers/build-pill-context.js +28 -0
  68. package/dist/v2/components/code-input/helpers/build-pill-context.js.map +1 -0
  69. package/dist/v2/components/code-input/helpers/lookup-variable-value.d.ts +11 -0
  70. package/dist/v2/components/code-input/helpers/lookup-variable-value.d.ts.map +1 -0
  71. package/dist/v2/components/code-input/helpers/lookup-variable-value.js +18 -0
  72. package/dist/v2/components/code-input/helpers/lookup-variable-value.js.map +1 -0
  73. package/dist/v2/components/code-input/helpers/pill-signature.d.ts +13 -0
  74. package/dist/v2/components/code-input/helpers/pill-signature.d.ts.map +1 -0
  75. package/dist/v2/components/code-input/helpers/pill-signature.js +25 -0
  76. package/dist/v2/components/code-input/helpers/pill-signature.js.map +1 -0
  77. package/dist/v2/components/code-input/helpers/serialize-value.d.ts +10 -0
  78. package/dist/v2/components/code-input/helpers/serialize-value.d.ts.map +1 -0
  79. package/dist/v2/components/code-input/helpers/serialize-value.js +17 -0
  80. package/dist/v2/components/code-input/helpers/serialize-value.js.map +1 -0
  81. package/dist/v2/components/code-input/index.d.ts +1 -0
  82. package/dist/v2/components/code-input/index.d.ts.map +1 -1
  83. package/dist/v2/components/code-input/index.js +2 -1
  84. package/dist/v2/components/data-table/DataTableInput.vue.d.ts +0 -4
  85. package/dist/v2/components/data-table/DataTableInput.vue.d.ts.map +1 -1
  86. package/dist/v2/components/data-table/DataTableInput.vue.js +1 -1
  87. package/dist/v2/components/data-table/DataTableInput.vue.js.map +1 -1
  88. package/dist/v2/components/data-table/DataTableInput.vue.script.js +2 -19
  89. package/dist/v2/components/data-table/DataTableInput.vue.script.js.map +1 -1
  90. package/dist/v2/constants.js +1 -1
  91. package/dist/v2/features/environments/components/EnvironmentVariablesDropdown.vue.d.ts +9 -0
  92. package/dist/v2/features/environments/components/EnvironmentVariablesDropdown.vue.d.ts.map +1 -1
  93. package/dist/v2/features/environments/components/EnvironmentVariablesDropdown.vue.js.map +1 -1
  94. package/dist/v2/features/environments/components/EnvironmentVariablesDropdown.vue.script.js +59 -28
  95. package/dist/v2/features/environments/components/EnvironmentVariablesDropdown.vue.script.js.map +1 -1
  96. package/dist/v2/features/environments/components/EnvironmentVariablesTable.vue.d.ts.map +1 -1
  97. package/dist/v2/features/environments/components/EnvironmentVariablesTable.vue.js +1 -1
  98. package/dist/v2/features/environments/components/EnvironmentVariablesTable.vue.js.map +1 -1
  99. package/dist/v2/features/environments/components/EnvironmentVariablesTable.vue.script.js +3 -8
  100. package/dist/v2/features/environments/components/EnvironmentVariablesTable.vue.script.js.map +1 -1
  101. package/dist/v2/features/modal/helpers/create-api-client-modal.d.ts.map +1 -1
  102. package/dist/v2/features/modal/helpers/create-api-client-modal.js +12 -1
  103. package/dist/v2/features/modal/helpers/create-api-client-modal.js.map +1 -1
  104. package/dist/v2/features/modal/helpers/resolve-route-parameters.d.ts.map +1 -1
  105. package/dist/v2/features/modal/helpers/resolve-route-parameters.js +6 -1
  106. package/dist/v2/features/modal/helpers/resolve-route-parameters.js.map +1 -1
  107. package/dist/v2/features/search/helpers/create-search-index.d.ts.map +1 -1
  108. package/dist/v2/features/search/helpers/create-search-index.js +2 -1
  109. package/dist/v2/features/search/helpers/create-search-index.js.map +1 -1
  110. package/dist/vue-styles.css +141 -89
  111. package/package.json +11 -11
@@ -1 +1 @@
1
- {"version":3,"file":"create-api-client-modal.js","names":[],"sources":["../../../../../src/v2/features/modal/helpers/create-api-client-modal.ts"],"sourcesContent":["import { type ModalState, useModal } from '@scalar/components/modal'\nimport { type ClientPlugin, subscribePluginEvents } from '@scalar/oas-utils/helpers'\nimport type { WorkspaceStore } from '@scalar/workspace-store/client'\nimport { type WorkspaceEventBus, createWorkspaceEventBus } from '@scalar/workspace-store/events'\nimport { isOpenApiDocument } from '@scalar/workspace-store/schemas/type-guards'\nimport { type App, type MaybeRefOrGetter, computed, createApp, isRef, reactive, ref, toValue, watch } from 'vue'\n\nimport {\n type DefaultEntities,\n type RoutePayload,\n resolveRouteParameters,\n} from '@/v2/features/modal/helpers/resolve-route-parameters'\nimport { useModalSidebar } from '@/v2/features/modal/hooks/use-modal-sidebar'\nimport Modal, { type ModalProps } from '@/v2/features/modal/Modal.vue'\nimport type { ApiClientOptions, ApiClientOptionsRef } from '@/v2/types/options'\n\ntype CreateApiClientOptions = {\n /** Element to mount the client modal to. */\n el: HTMLElement | null\n /**\n * Will attempt to mount the references immediately.\n * For SSR this may need to be disabled and handled manually on the client side.\n */\n mountOnInitialize?: boolean\n /** You can pass in an event bus if you have one already, or we will create one */\n eventBus?: WorkspaceEventBus\n /** The workspace store must be initialized and passed in. */\n workspaceStore: WorkspaceStore\n /** Api client plugins to include in the modal */\n plugins?: ClientPlugin[]\n /** Subset of the configuration options for the modal, if you want it to be reactive ensure its a ref */\n options?: MaybeRefOrGetter<ApiClientOptions>\n}\n\nexport type ApiClientModal = {\n app: App\n open: (payload?: RoutePayload) => void\n mount: (mountingEl: HTMLElement | null) => void\n route: (payload: RoutePayload) => void\n updateOptions: (nextOptions: ApiClientOptions, overwrite?: boolean) => void\n modalState: ModalState\n}\n\n/**\n * Creates the API Client Modal.\n *\n * The modal does not require a router. Instead, navigation is handled by setting\n * active entities directly through the returned `route` function.\n */\nexport const createApiClientModal = ({\n el,\n eventBus = createWorkspaceEventBus({\n debug: import.meta.env.DEV,\n }),\n mountOnInitialize = true,\n plugins = [],\n workspaceStore,\n options = {},\n}: CreateApiClientOptions): ApiClientModal => {\n const requestBodyCompositionSelection = ref<Record<string, number>>({})\n\n /** This is to ensure that the options are a ref if they are not already, useful for react */\n const optionsRef = (isRef(options) ? options : ref(toValue(options))) as ApiClientOptionsRef\n\n const defaultEntities: DefaultEntities = {\n path: 'default',\n method: 'default',\n example: 'default',\n documentSlug: workspaceStore.workspace['x-scalar-active-document'] || 'default',\n }\n\n const parameters = reactive<DefaultEntities>({ ...defaultEntities })\n\n /** Navigate to the specified path, method, and example. */\n const route = (payload: RoutePayload): void => {\n Object.assign(parameters, defaultEntities, payload)\n }\n\n /** Resolved parameters from the workspace store. */\n const resolvedParameters = computed(() => resolveRouteParameters(workspaceStore, parameters))\n const documentSlug = computed(() => resolvedParameters.value.documentSlug)\n const path = computed(() => resolvedParameters.value.path)\n const method = computed(() => resolvedParameters.value.method)\n const exampleName = computed(() => resolvedParameters.value.example)\n /** The document from the workspace store. Modal is OpenAPI-only; AsyncAPI docs surface as null. */\n const document = computed(() => {\n const doc = workspaceStore.workspace.documents[documentSlug.value ?? '']\n return isOpenApiDocument(doc) ? doc : null\n })\n\n /** Sidebar state and selection handling. */\n const sidebarState = useModalSidebar({\n workspaceStore,\n documentSlug: documentSlug,\n path: path,\n method: method,\n exampleName: exampleName,\n route,\n })\n\n const modalState = useModal()\n\n const app = createApp(Modal, {\n document,\n eventBus,\n exampleName,\n method,\n modalState,\n path,\n plugins,\n requestBodyCompositionSelection,\n sidebarState,\n workspaceStore,\n options: optionsRef,\n } satisfies ModalProps)\n\n /** Restore the workspace store when the modal is closed. */\n const handleModalClose = () => {\n requestBodyCompositionSelection.value = {}\n }\n\n /** Initialize plugins and subscribe to event bus events */\n const pluginUnsubscribes: (() => void)[] = []\n for (const plugin of plugins) {\n plugin.lifecycle?.onInit?.()\n\n pluginUnsubscribes.push(subscribePluginEvents(eventBus, plugin))\n }\n\n /** Clean up plugin lifecycle and event bus subscriptions when the app is unmounted */\n app.onUnmount(() => {\n for (const unsub of pluginUnsubscribes) {\n unsub()\n }\n for (const plugin of plugins) {\n plugin.lifecycle?.onDestroy?.()\n }\n })\n\n watch(\n () => modalState.open,\n (open) => (open ? null : handleModalClose()),\n )\n\n // Update the active proxy when the proxyUrl changes\n watch(\n () => toValue(optionsRef).proxyUrl,\n (newProxyUrl) => workspaceStore.update('x-scalar-active-proxy', newProxyUrl),\n { immediate: true },\n )\n\n // Use a unique id prefix to prevent collisions with other Vue apps on the page\n app.config.idPrefix = 'scalar-client'\n\n /** Mount the modal to a given element. */\n const mount = (mountingEl: HTMLElement | null = el): void => {\n if (!mountingEl) {\n console.error(\n '[@scalar/api-client] Could not create the API client Modal.',\n 'Invalid HTML element provided.',\n 'Read more: https://github.com/scalar/scalar/tree/main/packages/api-client',\n )\n return\n }\n app.mount(mountingEl)\n }\n\n if (mountOnInitialize) {\n mount()\n }\n\n return {\n /** The Vue app instance for the modal. Use with caution. */\n app,\n /** Open the modal and optionally navigate to a specific route. */\n open: (payload?: RoutePayload): void => {\n modalState.open = true\n if (payload) {\n route(payload)\n }\n },\n /** Mount the modal to a given element. */\n mount,\n /** Navigate to the specified path, method, and example. */\n route,\n /** Controls the visibility of the modal. */\n modalState,\n /**\n * Merge new options into the current modal options.\n *\n * @param newOptions - The new options to merge into the current modal options.\n * @param overwrite - Whether to overwrite the current modal options with the new options. If false, the new options will be merged with the current options.\n */\n updateOptions: (newOptions: ApiClientOptions, overwrite = false): void => {\n optionsRef.value = overwrite\n ? newOptions\n : {\n ...optionsRef.value,\n ...newOptions,\n }\n },\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;AAiDA,IAAa,wBAAwB,EACnC,IACA,WAAW,wBAAwB,EACjC,OAAA,OACD,CAAC,EACF,oBAAoB,MACpB,UAAU,EAAE,EACZ,gBACA,UAAU,EAAE,OACgC;CAC5C,MAAM,kCAAkC,IAA4B,EAAE,CAAC;;CAGvE,MAAM,aAAc,MAAM,QAAQ,GAAG,UAAU,IAAI,QAAQ,QAAQ,CAAC;CAEpE,MAAM,kBAAmC;EACvC,MAAM;EACN,QAAQ;EACR,SAAS;EACT,cAAc,eAAe,UAAU,+BAA+B;EACvE;CAED,MAAM,aAAa,SAA0B,EAAE,GAAG,iBAAiB,CAAC;;CAGpE,MAAM,SAAS,YAAgC;AAC7C,SAAO,OAAO,YAAY,iBAAiB,QAAQ;;;CAIrD,MAAM,qBAAqB,eAAe,uBAAuB,gBAAgB,WAAW,CAAC;CAC7F,MAAM,eAAe,eAAe,mBAAmB,MAAM,aAAa;CAC1E,MAAM,OAAO,eAAe,mBAAmB,MAAM,KAAK;CAC1D,MAAM,SAAS,eAAe,mBAAmB,MAAM,OAAO;CAC9D,MAAM,cAAc,eAAe,mBAAmB,MAAM,QAAQ;;CAEpE,MAAM,WAAW,eAAe;EAC9B,MAAM,MAAM,eAAe,UAAU,UAAU,aAAa,SAAS;AACrE,SAAO,kBAAkB,IAAI,GAAG,MAAM;GACtC;;CAGF,MAAM,eAAe,gBAAgB;EACnC;EACc;EACR;EACE;EACK;EACb;EACD,CAAC;CAEF,MAAM,aAAa,UAAU;CAE7B,MAAM,MAAM,UAAU,eAAO;EAC3B;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,SAAS;EACV,CAAsB;;CAGvB,MAAM,yBAAyB;AAC7B,kCAAgC,QAAQ,EAAE;;;CAI5C,MAAM,qBAAqC,EAAE;AAC7C,MAAK,MAAM,UAAU,SAAS;AAC5B,SAAO,WAAW,UAAU;AAE5B,qBAAmB,KAAK,sBAAsB,UAAU,OAAO,CAAC;;;AAIlE,KAAI,gBAAgB;AAClB,OAAK,MAAM,SAAS,mBAClB,QAAO;AAET,OAAK,MAAM,UAAU,QACnB,QAAO,WAAW,aAAa;GAEjC;AAEF,aACQ,WAAW,OAChB,SAAU,OAAO,OAAO,kBAAkB,CAC5C;AAGD,aACQ,QAAQ,WAAW,CAAC,WACzB,gBAAgB,eAAe,OAAO,yBAAyB,YAAY,EAC5E,EAAE,WAAW,MAAM,CACpB;AAGD,KAAI,OAAO,WAAW;;CAGtB,MAAM,SAAS,aAAiC,OAAa;AAC3D,MAAI,CAAC,YAAY;AACf,WAAQ,MACN,+DACA,kCACA,4EACD;AACD;;AAEF,MAAI,MAAM,WAAW;;AAGvB,KAAI,kBACF,QAAO;AAGT,QAAO;EAEL;EAEA,OAAO,YAAiC;AACtC,cAAW,OAAO;AAClB,OAAI,QACF,OAAM,QAAQ;;EAIlB;EAEA;EAEA;EAOA,gBAAgB,YAA8B,YAAY,UAAgB;AACxE,cAAW,QAAQ,YACf,aACA;IACE,GAAG,WAAW;IACd,GAAG;IACJ;;EAER"}
1
+ {"version":3,"file":"create-api-client-modal.js","names":[],"sources":["../../../../../src/v2/features/modal/helpers/create-api-client-modal.ts"],"sourcesContent":["import { type ModalState, useModal } from '@scalar/components/modal'\nimport { type ClientPlugin, subscribePluginEvents } from '@scalar/oas-utils/helpers'\nimport type { WorkspaceStore } from '@scalar/workspace-store/client'\nimport { type WorkspaceEventBus, createWorkspaceEventBus } from '@scalar/workspace-store/events'\nimport { isOpenApiDocument } from '@scalar/workspace-store/schemas/type-guards'\nimport { type App, type MaybeRefOrGetter, computed, createApp, isRef, reactive, ref, toValue, watch } from 'vue'\n\nimport {\n type DefaultEntities,\n type RoutePayload,\n resolveRouteParameters,\n} from '@/v2/features/modal/helpers/resolve-route-parameters'\nimport { useModalSidebar } from '@/v2/features/modal/hooks/use-modal-sidebar'\nimport Modal, { type ModalProps } from '@/v2/features/modal/Modal.vue'\nimport type { ApiClientOptions, ApiClientOptionsRef } from '@/v2/types/options'\n\ntype CreateApiClientOptions = {\n /** Element to mount the client modal to. */\n el: HTMLElement | null\n /**\n * Will attempt to mount the references immediately.\n * For SSR this may need to be disabled and handled manually on the client side.\n */\n mountOnInitialize?: boolean\n /** You can pass in an event bus if you have one already, or we will create one */\n eventBus?: WorkspaceEventBus\n /** The workspace store must be initialized and passed in. */\n workspaceStore: WorkspaceStore\n /** Api client plugins to include in the modal */\n plugins?: ClientPlugin[]\n /** Subset of the configuration options for the modal, if you want it to be reactive ensure its a ref */\n options?: MaybeRefOrGetter<ApiClientOptions>\n}\n\nexport type ApiClientModal = {\n app: App\n open: (payload?: RoutePayload) => void\n mount: (mountingEl: HTMLElement | null) => void\n route: (payload: RoutePayload) => void\n updateOptions: (nextOptions: ApiClientOptions, overwrite?: boolean) => void\n modalState: ModalState\n}\n\n/**\n * Monotonic counter used to give every modal Vue app a unique `idPrefix`.\n *\n * Vue derives `useId()` values (and therefore our teleport target ids) from the app's\n * `idPrefix`. When more than one client app mounts on the same page — for example, the\n * API reference embeds this modal alongside another client instance — a shared prefix\n * makes both apps emit identical ids. A teleported popover then resolves to the first\n * matching target in the DOM, which can be a hidden app, so the popover never appears.\n * A per-app suffix keeps the ids unique across instances.\n */\nlet modalAppCount = 0\n\n/**\n * Creates the API Client Modal.\n *\n * The modal does not require a router. Instead, navigation is handled by setting\n * active entities directly through the returned `route` function.\n */\nexport const createApiClientModal = ({\n el,\n eventBus = createWorkspaceEventBus({\n debug: import.meta.env.DEV,\n }),\n mountOnInitialize = true,\n plugins = [],\n workspaceStore,\n options = {},\n}: CreateApiClientOptions): ApiClientModal => {\n const requestBodyCompositionSelection = ref<Record<string, number>>({})\n\n /** This is to ensure that the options are a ref if they are not already, useful for react */\n const optionsRef = (isRef(options) ? options : ref(toValue(options))) as ApiClientOptionsRef\n\n const defaultEntities: DefaultEntities = {\n path: 'default',\n method: 'default',\n example: 'default',\n documentSlug: workspaceStore.workspace['x-scalar-active-document'] || 'default',\n }\n\n const parameters = reactive<DefaultEntities>({ ...defaultEntities })\n\n /** Navigate to the specified path, method, and example. */\n const route = (payload: RoutePayload): void => {\n Object.assign(parameters, defaultEntities, payload)\n }\n\n /** Resolved parameters from the workspace store. */\n const resolvedParameters = computed(() => resolveRouteParameters(workspaceStore, parameters))\n const documentSlug = computed(() => resolvedParameters.value.documentSlug)\n const path = computed(() => resolvedParameters.value.path)\n const method = computed(() => resolvedParameters.value.method)\n const exampleName = computed(() => resolvedParameters.value.example)\n /** The document from the workspace store. Modal is OpenAPI-only; AsyncAPI docs surface as null. */\n const document = computed(() => {\n const doc = workspaceStore.workspace.documents[documentSlug.value ?? '']\n return isOpenApiDocument(doc) ? doc : null\n })\n\n /** Sidebar state and selection handling. */\n const sidebarState = useModalSidebar({\n workspaceStore,\n documentSlug: documentSlug,\n path: path,\n method: method,\n exampleName: exampleName,\n route,\n })\n\n const modalState = useModal()\n\n const app = createApp(Modal, {\n document,\n eventBus,\n exampleName,\n method,\n modalState,\n path,\n plugins,\n requestBodyCompositionSelection,\n sidebarState,\n workspaceStore,\n options: optionsRef,\n } satisfies ModalProps)\n\n /** Restore the workspace store when the modal is closed. */\n const handleModalClose = () => {\n requestBodyCompositionSelection.value = {}\n }\n\n /** Initialize plugins and subscribe to event bus events */\n const pluginUnsubscribes: (() => void)[] = []\n for (const plugin of plugins) {\n plugin.lifecycle?.onInit?.()\n\n pluginUnsubscribes.push(subscribePluginEvents(eventBus, plugin))\n }\n\n /** Clean up plugin lifecycle and event bus subscriptions when the app is unmounted */\n app.onUnmount(() => {\n for (const unsub of pluginUnsubscribes) {\n unsub()\n }\n for (const plugin of plugins) {\n plugin.lifecycle?.onDestroy?.()\n }\n })\n\n watch(\n () => modalState.open,\n (open) => (open ? null : handleModalClose()),\n )\n\n // Update the active proxy when the proxyUrl changes\n watch(\n () => toValue(optionsRef).proxyUrl,\n (newProxyUrl) => workspaceStore.update('x-scalar-active-proxy', newProxyUrl),\n { immediate: true },\n )\n\n // Use a unique id prefix to prevent collisions with other Vue apps on the page.\n // The suffix keeps the prefix unique even when several client apps mount together.\n app.config.idPrefix = `scalar-client-${modalAppCount++}`\n\n /** Mount the modal to a given element. */\n const mount = (mountingEl: HTMLElement | null = el): void => {\n if (!mountingEl) {\n console.error(\n '[@scalar/api-client] Could not create the API client Modal.',\n 'Invalid HTML element provided.',\n 'Read more: https://github.com/scalar/scalar/tree/main/packages/api-client',\n )\n return\n }\n app.mount(mountingEl)\n }\n\n if (mountOnInitialize) {\n mount()\n }\n\n return {\n /** The Vue app instance for the modal. Use with caution. */\n app,\n /** Open the modal and optionally navigate to a specific route. */\n open: (payload?: RoutePayload): void => {\n modalState.open = true\n if (payload) {\n route(payload)\n }\n },\n /** Mount the modal to a given element. */\n mount,\n /** Navigate to the specified path, method, and example. */\n route,\n /** Controls the visibility of the modal. */\n modalState,\n /**\n * Merge new options into the current modal options.\n *\n * @param newOptions - The new options to merge into the current modal options.\n * @param overwrite - Whether to overwrite the current modal options with the new options. If false, the new options will be merged with the current options.\n */\n updateOptions: (newOptions: ApiClientOptions, overwrite = false): void => {\n optionsRef.value = overwrite\n ? newOptions\n : {\n ...optionsRef.value,\n ...newOptions,\n }\n },\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAqDA,IAAI,gBAAgB;;;;;;;AAQpB,IAAa,wBAAwB,EACnC,IACA,WAAW,wBAAwB,EACjC,OAAA,OACD,CAAC,EACF,oBAAoB,MACpB,UAAU,EAAE,EACZ,gBACA,UAAU,EAAE,OACgC;CAC5C,MAAM,kCAAkC,IAA4B,EAAE,CAAC;;CAGvE,MAAM,aAAc,MAAM,QAAQ,GAAG,UAAU,IAAI,QAAQ,QAAQ,CAAC;CAEpE,MAAM,kBAAmC;EACvC,MAAM;EACN,QAAQ;EACR,SAAS;EACT,cAAc,eAAe,UAAU,+BAA+B;EACvE;CAED,MAAM,aAAa,SAA0B,EAAE,GAAG,iBAAiB,CAAC;;CAGpE,MAAM,SAAS,YAAgC;AAC7C,SAAO,OAAO,YAAY,iBAAiB,QAAQ;;;CAIrD,MAAM,qBAAqB,eAAe,uBAAuB,gBAAgB,WAAW,CAAC;CAC7F,MAAM,eAAe,eAAe,mBAAmB,MAAM,aAAa;CAC1E,MAAM,OAAO,eAAe,mBAAmB,MAAM,KAAK;CAC1D,MAAM,SAAS,eAAe,mBAAmB,MAAM,OAAO;CAC9D,MAAM,cAAc,eAAe,mBAAmB,MAAM,QAAQ;;CAEpE,MAAM,WAAW,eAAe;EAC9B,MAAM,MAAM,eAAe,UAAU,UAAU,aAAa,SAAS;AACrE,SAAO,kBAAkB,IAAI,GAAG,MAAM;GACtC;;CAGF,MAAM,eAAe,gBAAgB;EACnC;EACc;EACR;EACE;EACK;EACb;EACD,CAAC;CAEF,MAAM,aAAa,UAAU;CAE7B,MAAM,MAAM,UAAU,eAAO;EAC3B;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,SAAS;EACV,CAAsB;;CAGvB,MAAM,yBAAyB;AAC7B,kCAAgC,QAAQ,EAAE;;;CAI5C,MAAM,qBAAqC,EAAE;AAC7C,MAAK,MAAM,UAAU,SAAS;AAC5B,SAAO,WAAW,UAAU;AAE5B,qBAAmB,KAAK,sBAAsB,UAAU,OAAO,CAAC;;;AAIlE,KAAI,gBAAgB;AAClB,OAAK,MAAM,SAAS,mBAClB,QAAO;AAET,OAAK,MAAM,UAAU,QACnB,QAAO,WAAW,aAAa;GAEjC;AAEF,aACQ,WAAW,OAChB,SAAU,OAAO,OAAO,kBAAkB,CAC5C;AAGD,aACQ,QAAQ,WAAW,CAAC,WACzB,gBAAgB,eAAe,OAAO,yBAAyB,YAAY,EAC5E,EAAE,WAAW,MAAM,CACpB;AAID,KAAI,OAAO,WAAW,iBAAiB;;CAGvC,MAAM,SAAS,aAAiC,OAAa;AAC3D,MAAI,CAAC,YAAY;AACf,WAAQ,MACN,+DACA,kCACA,4EACD;AACD;;AAEF,MAAI,MAAM,WAAW;;AAGvB,KAAI,kBACF,QAAO;AAGT,QAAO;EAEL;EAEA,OAAO,YAAiC;AACtC,cAAW,OAAO;AAClB,OAAI,QACF,OAAM,QAAQ;;EAIlB;EAEA;EAEA;EAOA,gBAAgB,YAA8B,YAAY,UAAgB;AACxE,cAAW,QAAQ,YACf,aACA;IACE,GAAG,WAAW;IACd,GAAG;IACJ;;EAER"}
@@ -1 +1 @@
1
- {"version":3,"file":"resolve-route-parameters.d.ts","sourceRoot":"","sources":["../../../../../src/v2/features/modal/helpers/resolve-route-parameters.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mCAAmC,CAAA;AAEnE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAA;AAEpE,OAAO,KAAK,EAAE,cAAc,EAAoB,MAAM,4CAA4C,CAAA;AAGlG,4DAA4D;AAC5D,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,UAAU,CAAA;IAClB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB,CAAA;AAED,gEAAgE;AAChE,MAAM,MAAM,eAAe,GAAG,MAAM,CAAC,MAAM,YAAY,EAAE,MAAM,CAAC,CAAA;AAEhE,uEAAuE;AACvE,KAAK,eAAe,GAAG;IACrB,KAAK,EAAE,cAAc,CAAA;IACrB,YAAY,EAAE,MAAM,GAAG,SAAS,CAAA;CACjC,CAAA;AAeD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,mBAAmB,GAAI,OAAO,cAAc,EAAE,MAAM,MAAM,GAAG,SAAS,KAAG,MAAM,GAAG,SAe9F,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,WAAW,GAAI,KAAK,eAAe,EAAE,MAAM,MAAM,GAAG,SAAS,KAAG,MAAM,GAAG,SAYrF,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,aAAa,GACxB,KAAK,eAAe,EACpB,MAAM,MAAM,GAAG,SAAS,EACxB,QAAQ,MAAM,GAAG,SAAS,KACzB,UAAU,GAAG,SAaf,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,GAC7B,KAAK,eAAe,EACpB,WAAW,cAAc,GAAG,SAAS,EACrC,YAAY,MAAM,GAAG,SAAS,KAC7B,MAmBF,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,GAAI,OAAO,cAAc,EAAE,QAAQ,eAAe,KAAG,OAAO,CAAC,YAAY,CAkB3G,CAAA"}
1
+ {"version":3,"file":"resolve-route-parameters.d.ts","sourceRoot":"","sources":["../../../../../src/v2/features/modal/helpers/resolve-route-parameters.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mCAAmC,CAAA;AAEnE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAA;AAGpE,OAAO,KAAK,EAAE,cAAc,EAAoB,MAAM,4CAA4C,CAAA;AAGlG,4DAA4D;AAC5D,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,UAAU,CAAA;IAClB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB,CAAA;AAED,gEAAgE;AAChE,MAAM,MAAM,eAAe,GAAG,MAAM,CAAC,MAAM,YAAY,EAAE,MAAM,CAAC,CAAA;AAEhE,uEAAuE;AACvE,KAAK,eAAe,GAAG;IACrB,KAAK,EAAE,cAAc,CAAA;IACrB,YAAY,EAAE,MAAM,GAAG,SAAS,CAAA;CACjC,CAAA;AAeD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,mBAAmB,GAAI,OAAO,cAAc,EAAE,MAAM,MAAM,GAAG,SAAS,KAAG,MAAM,GAAG,SAe9F,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,WAAW,GAAI,KAAK,eAAe,EAAE,MAAM,MAAM,GAAG,SAAS,KAAG,MAAM,GAAG,SAYrF,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,aAAa,GACxB,KAAK,eAAe,EACpB,MAAM,MAAM,GAAG,SAAS,EACxB,QAAQ,MAAM,GAAG,SAAS,KACzB,UAAU,GAAG,SAiBf,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,GAC7B,KAAK,eAAe,EACpB,WAAW,cAAc,GAAG,SAAS,EACrC,YAAY,MAAM,GAAG,SAAS,KAC7B,MAmBF,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,GAAI,OAAO,cAAc,EAAE,QAAQ,eAAe,KAAG,OAAO,CAAC,YAAY,CAkB3G,CAAA"}
@@ -1,4 +1,5 @@
1
1
  import { isOpenApiDocument } from "@scalar/workspace-store/schemas/type-guards";
2
+ import { getResolvedPathItem } from "@scalar/workspace-store/helpers/for-each-path-item-operation";
2
3
  import { isHttpMethod } from "@scalar/helpers/http/is-http-method";
3
4
  import { getOperationEntries } from "@scalar/workspace-store/navigation";
4
5
  //#region src/v2/features/modal/helpers/resolve-route-parameters.ts
@@ -51,7 +52,11 @@ var resolvePath = (ctx, path) => {
51
52
  var resolveMethod = (ctx, path, method) => {
52
53
  const document = getDocument(ctx);
53
54
  if (!document || !path) return;
54
- if (method === "default") return Object.keys(document.paths?.[path] ?? {}).find(isHttpMethod);
55
+ if (method === "default") {
56
+ const pathItem = getResolvedPathItem(document.paths?.[path]);
57
+ if (!pathItem) return;
58
+ return Object.keys(pathItem).filter(isHttpMethod)[0];
59
+ }
55
60
  return isHttpMethod(method) ? method : void 0;
56
61
  };
57
62
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"resolve-route-parameters.js","names":[],"sources":["../../../../../src/v2/features/modal/helpers/resolve-route-parameters.ts"],"sourcesContent":["import type { HttpMethod } from '@scalar/helpers/http/http-methods'\nimport { isHttpMethod } from '@scalar/helpers/http/is-http-method'\nimport type { WorkspaceStore } from '@scalar/workspace-store/client'\nimport { getOperationEntries } from '@scalar/workspace-store/navigation'\nimport type { TraversedEntry, TraversedExample } from '@scalar/workspace-store/schemas/navigation'\nimport { isOpenApiDocument } from '@scalar/workspace-store/schemas/type-guards'\n\n/** Payload for routing and opening the API client modal. */\nexport type RoutePayload = {\n path: string\n method: HttpMethod\n example?: string\n documentSlug?: string\n}\n\n/** Raw input values that may contain \"default\" placeholders. */\nexport type DefaultEntities = Record<keyof RoutePayload, string>\n\n/** Context for resolving route parameters from the workspace store. */\ntype ResolverContext = {\n store: WorkspaceStore\n documentSlug: string | undefined\n}\n\n/** Type guard to check if an entry is an example. */\nconst isExample = (entry: TraversedEntry): entry is TraversedExample => entry.type === 'example'\n\n/**\n * Gets the document from the workspace store.\n * Returns undefined if the document slug is not provided or the document does not exist.\n * Modal routing is OpenAPI-only — AsyncAPI docs surface as undefined here.\n */\nconst getDocument = (ctx: ResolverContext) => {\n const doc = ctx.store.workspace.documents[ctx.documentSlug ?? '']\n return isOpenApiDocument(doc) ? doc : undefined\n}\n\n/**\n * Resolves the document slug from a raw input value.\n *\n * When \"default\" is specified and no document exists with that slug,\n * we fall back to the active document or the first available document.\n * Modal routing is OpenAPI-only, so the fallback skips AsyncAPI documents —\n * otherwise opening the modal with default params on a workspace that has\n * an AsyncAPI active or first document would hand a slug back that\n * `getDocument` then resolves to undefined, rendering the modal with\n * `document: null` even when OpenAPI documents exist.\n */\nexport const resolveDocumentSlug = (store: WorkspaceStore, slug: string | undefined): string | undefined => {\n const hasMatchingDocument = slug !== 'default' || store.workspace.documents[slug] !== undefined\n\n if (hasMatchingDocument) {\n return slug\n }\n\n // Prefer the active document when it is OpenAPI; otherwise pick the first\n // OpenAPI document in the workspace.\n const activeSlug = store.workspace['x-scalar-active-document']\n if (activeSlug && isOpenApiDocument(store.workspace.documents[activeSlug])) {\n return activeSlug\n }\n\n return Object.entries(store.workspace.documents).find(([, document]) => isOpenApiDocument(document))?.[0]\n}\n\n/**\n * Resolves the path from a raw input value.\n *\n * When \"default\" is specified, returns the first available path in the document.\n * This is useful for initial navigation when no specific path is requested.\n */\nexport const resolvePath = (ctx: ResolverContext, path: string | undefined): string | undefined => {\n const document = getDocument(ctx)\n\n if (!document) {\n return undefined\n }\n\n if (path === 'default') {\n return Object.keys(document.paths ?? {})[0]\n }\n\n return path\n}\n\n/**\n * Resolves the HTTP method from a raw input value.\n *\n * When \"default\" is specified, returns the first valid HTTP method for the given path.\n * This ensures we select a real method rather than metadata keys like \"parameters\" or \"summary\".\n */\nexport const resolveMethod = (\n ctx: ResolverContext,\n path: string | undefined,\n method: string | undefined,\n): HttpMethod | undefined => {\n const document = getDocument(ctx)\n\n if (!document || !path) {\n return undefined\n }\n\n if (method === 'default') {\n const pathMethods = Object.keys(document.paths?.[path] ?? {})\n return pathMethods.find(isHttpMethod)\n }\n\n return isHttpMethod(method) ? method : undefined\n}\n\n/**\n * Resolves the example name from a raw input value.\n *\n * When \"default\" is specified, returns the first available example name.\n * Falls back to \"default\" when no examples exist, which signals to use the default request body.\n */\nexport const resolveExampleName = (\n ctx: ResolverContext,\n operation: TraversedEntry | undefined,\n exampleKey: string | undefined,\n): string => {\n const document = getDocument(ctx)\n\n if (!document || operation?.type !== 'operation') {\n return 'default'\n }\n\n const examples = operation.children?.filter(isExample) ?? []\n const matchingExample = examples.find((child) => child.name === exampleKey)\n\n if (matchingExample) {\n return matchingExample.name\n }\n\n if (exampleKey === 'default') {\n return examples[0]?.name ?? 'default'\n }\n\n return 'default'\n}\n\n/**\n * Resolves all route parameters from raw input values to their actual values.\n *\n * This function handles \"default\" placeholders by looking up actual values from the workspace store.\n * It ensures the modal can be opened even when the caller does not know specific paths, methods, or examples.\n */\nexport const resolveRouteParameters = (store: WorkspaceStore, params: DefaultEntities): Partial<RoutePayload> => {\n const documentSlug = resolveDocumentSlug(store, params.documentSlug)\n const ctx: ResolverContext = { store, documentSlug }\n\n const path = resolvePath(ctx, params.path)\n const method = resolveMethod(ctx, path, params.method)\n\n const traversedDocument = getDocument(ctx)?.['x-scalar-navigation']\n\n if (!traversedDocument) {\n return { documentSlug, path, method, example: 'default' }\n }\n\n const operations = getOperationEntries(traversedDocument)\n const operation = operations.get(`${path}|${method}`)?.find((entry) => entry.type === 'operation')\n const example = resolveExampleName(ctx, operation, params.example)\n\n return { documentSlug, path, method, example }\n}\n"],"mappings":";;;;;AAyBA,IAAM,aAAa,UAAqD,MAAM,SAAS;;;;;;AAOvF,IAAM,eAAe,QAAyB;CAC5C,MAAM,MAAM,IAAI,MAAM,UAAU,UAAU,IAAI,gBAAgB;AAC9D,QAAO,kBAAkB,IAAI,GAAG,MAAM,KAAA;;;;;;;;;;;;;AAcxC,IAAa,uBAAuB,OAAuB,SAAiD;AAG1G,KAF4B,SAAS,aAAa,MAAM,UAAU,UAAU,UAAU,KAAA,EAGpF,QAAO;CAKT,MAAM,aAAa,MAAM,UAAU;AACnC,KAAI,cAAc,kBAAkB,MAAM,UAAU,UAAU,YAAY,CACxE,QAAO;AAGT,QAAO,OAAO,QAAQ,MAAM,UAAU,UAAU,CAAC,MAAM,GAAG,cAAc,kBAAkB,SAAS,CAAC,GAAG;;;;;;;;AASzG,IAAa,eAAe,KAAsB,SAAiD;CACjG,MAAM,WAAW,YAAY,IAAI;AAEjC,KAAI,CAAC,SACH;AAGF,KAAI,SAAS,UACX,QAAO,OAAO,KAAK,SAAS,SAAS,EAAE,CAAC,CAAC;AAG3C,QAAO;;;;;;;;AAST,IAAa,iBACX,KACA,MACA,WAC2B;CAC3B,MAAM,WAAW,YAAY,IAAI;AAEjC,KAAI,CAAC,YAAY,CAAC,KAChB;AAGF,KAAI,WAAW,UAEb,QADoB,OAAO,KAAK,SAAS,QAAQ,SAAS,EAAE,CAAC,CAC1C,KAAK,aAAa;AAGvC,QAAO,aAAa,OAAO,GAAG,SAAS,KAAA;;;;;;;;AASzC,IAAa,sBACX,KACA,WACA,eACW;AAGX,KAAI,CAFa,YAAY,IAAI,IAEhB,WAAW,SAAS,YACnC,QAAO;CAGT,MAAM,WAAW,UAAU,UAAU,OAAO,UAAU,IAAI,EAAE;CAC5D,MAAM,kBAAkB,SAAS,MAAM,UAAU,MAAM,SAAS,WAAW;AAE3E,KAAI,gBACF,QAAO,gBAAgB;AAGzB,KAAI,eAAe,UACjB,QAAO,SAAS,IAAI,QAAQ;AAG9B,QAAO;;;;;;;;AAST,IAAa,0BAA0B,OAAuB,WAAmD;CAC/G,MAAM,eAAe,oBAAoB,OAAO,OAAO,aAAa;CACpE,MAAM,MAAuB;EAAE;EAAO;EAAc;CAEpD,MAAM,OAAO,YAAY,KAAK,OAAO,KAAK;CAC1C,MAAM,SAAS,cAAc,KAAK,MAAM,OAAO,OAAO;CAEtD,MAAM,oBAAoB,YAAY,IAAI,GAAG;AAE7C,KAAI,CAAC,kBACH,QAAO;EAAE;EAAc;EAAM;EAAQ,SAAS;EAAW;CAI3D,MAAM,YADa,oBAAoB,kBAAkB,CAC5B,IAAI,GAAG,KAAK,GAAG,SAAS,EAAE,MAAM,UAAU,MAAM,SAAS,YAAY;AAGlG,QAAO;EAAE;EAAc;EAAM;EAAQ,SAFrB,mBAAmB,KAAK,WAAW,OAAO,QAAQ;EAEpB"}
1
+ {"version":3,"file":"resolve-route-parameters.js","names":[],"sources":["../../../../../src/v2/features/modal/helpers/resolve-route-parameters.ts"],"sourcesContent":["import type { HttpMethod } from '@scalar/helpers/http/http-methods'\nimport { isHttpMethod } from '@scalar/helpers/http/is-http-method'\nimport type { WorkspaceStore } from '@scalar/workspace-store/client'\nimport { getResolvedPathItem } from '@scalar/workspace-store/helpers/for-each-path-item-operation'\nimport { getOperationEntries } from '@scalar/workspace-store/navigation'\nimport type { TraversedEntry, TraversedExample } from '@scalar/workspace-store/schemas/navigation'\nimport { isOpenApiDocument } from '@scalar/workspace-store/schemas/type-guards'\n\n/** Payload for routing and opening the API client modal. */\nexport type RoutePayload = {\n path: string\n method: HttpMethod\n example?: string\n documentSlug?: string\n}\n\n/** Raw input values that may contain \"default\" placeholders. */\nexport type DefaultEntities = Record<keyof RoutePayload, string>\n\n/** Context for resolving route parameters from the workspace store. */\ntype ResolverContext = {\n store: WorkspaceStore\n documentSlug: string | undefined\n}\n\n/** Type guard to check if an entry is an example. */\nconst isExample = (entry: TraversedEntry): entry is TraversedExample => entry.type === 'example'\n\n/**\n * Gets the document from the workspace store.\n * Returns undefined if the document slug is not provided or the document does not exist.\n * Modal routing is OpenAPI-only — AsyncAPI docs surface as undefined here.\n */\nconst getDocument = (ctx: ResolverContext) => {\n const doc = ctx.store.workspace.documents[ctx.documentSlug ?? '']\n return isOpenApiDocument(doc) ? doc : undefined\n}\n\n/**\n * Resolves the document slug from a raw input value.\n *\n * When \"default\" is specified and no document exists with that slug,\n * we fall back to the active document or the first available document.\n * Modal routing is OpenAPI-only, so the fallback skips AsyncAPI documents —\n * otherwise opening the modal with default params on a workspace that has\n * an AsyncAPI active or first document would hand a slug back that\n * `getDocument` then resolves to undefined, rendering the modal with\n * `document: null` even when OpenAPI documents exist.\n */\nexport const resolveDocumentSlug = (store: WorkspaceStore, slug: string | undefined): string | undefined => {\n const hasMatchingDocument = slug !== 'default' || store.workspace.documents[slug] !== undefined\n\n if (hasMatchingDocument) {\n return slug\n }\n\n // Prefer the active document when it is OpenAPI; otherwise pick the first\n // OpenAPI document in the workspace.\n const activeSlug = store.workspace['x-scalar-active-document']\n if (activeSlug && isOpenApiDocument(store.workspace.documents[activeSlug])) {\n return activeSlug\n }\n\n return Object.entries(store.workspace.documents).find(([, document]) => isOpenApiDocument(document))?.[0]\n}\n\n/**\n * Resolves the path from a raw input value.\n *\n * When \"default\" is specified, returns the first available path in the document.\n * This is useful for initial navigation when no specific path is requested.\n */\nexport const resolvePath = (ctx: ResolverContext, path: string | undefined): string | undefined => {\n const document = getDocument(ctx)\n\n if (!document) {\n return undefined\n }\n\n if (path === 'default') {\n return Object.keys(document.paths ?? {})[0]\n }\n\n return path\n}\n\n/**\n * Resolves the HTTP method from a raw input value.\n *\n * When \"default\" is specified, returns the first valid HTTP method for the given path.\n * This ensures we select a real method rather than metadata keys like \"parameters\" or \"summary\".\n */\nexport const resolveMethod = (\n ctx: ResolverContext,\n path: string | undefined,\n method: string | undefined,\n): HttpMethod | undefined => {\n const document = getDocument(ctx)\n\n if (!document || !path) {\n return undefined\n }\n\n if (method === 'default') {\n const pathItem = getResolvedPathItem(document.paths?.[path])\n if (!pathItem) {\n return undefined\n }\n const pathMethods = Object.keys(pathItem).filter(isHttpMethod)\n return pathMethods[0]\n }\n\n return isHttpMethod(method) ? method : undefined\n}\n\n/**\n * Resolves the example name from a raw input value.\n *\n * When \"default\" is specified, returns the first available example name.\n * Falls back to \"default\" when no examples exist, which signals to use the default request body.\n */\nexport const resolveExampleName = (\n ctx: ResolverContext,\n operation: TraversedEntry | undefined,\n exampleKey: string | undefined,\n): string => {\n const document = getDocument(ctx)\n\n if (!document || operation?.type !== 'operation') {\n return 'default'\n }\n\n const examples = operation.children?.filter(isExample) ?? []\n const matchingExample = examples.find((child) => child.name === exampleKey)\n\n if (matchingExample) {\n return matchingExample.name\n }\n\n if (exampleKey === 'default') {\n return examples[0]?.name ?? 'default'\n }\n\n return 'default'\n}\n\n/**\n * Resolves all route parameters from raw input values to their actual values.\n *\n * This function handles \"default\" placeholders by looking up actual values from the workspace store.\n * It ensures the modal can be opened even when the caller does not know specific paths, methods, or examples.\n */\nexport const resolveRouteParameters = (store: WorkspaceStore, params: DefaultEntities): Partial<RoutePayload> => {\n const documentSlug = resolveDocumentSlug(store, params.documentSlug)\n const ctx: ResolverContext = { store, documentSlug }\n\n const path = resolvePath(ctx, params.path)\n const method = resolveMethod(ctx, path, params.method)\n\n const traversedDocument = getDocument(ctx)?.['x-scalar-navigation']\n\n if (!traversedDocument) {\n return { documentSlug, path, method, example: 'default' }\n }\n\n const operations = getOperationEntries(traversedDocument)\n const operation = operations.get(`${path}|${method}`)?.find((entry) => entry.type === 'operation')\n const example = resolveExampleName(ctx, operation, params.example)\n\n return { documentSlug, path, method, example }\n}\n"],"mappings":";;;;;;AA0BA,IAAM,aAAa,UAAqD,MAAM,SAAS;;;;;;AAOvF,IAAM,eAAe,QAAyB;CAC5C,MAAM,MAAM,IAAI,MAAM,UAAU,UAAU,IAAI,gBAAgB;AAC9D,QAAO,kBAAkB,IAAI,GAAG,MAAM,KAAA;;;;;;;;;;;;;AAcxC,IAAa,uBAAuB,OAAuB,SAAiD;AAG1G,KAF4B,SAAS,aAAa,MAAM,UAAU,UAAU,UAAU,KAAA,EAGpF,QAAO;CAKT,MAAM,aAAa,MAAM,UAAU;AACnC,KAAI,cAAc,kBAAkB,MAAM,UAAU,UAAU,YAAY,CACxE,QAAO;AAGT,QAAO,OAAO,QAAQ,MAAM,UAAU,UAAU,CAAC,MAAM,GAAG,cAAc,kBAAkB,SAAS,CAAC,GAAG;;;;;;;;AASzG,IAAa,eAAe,KAAsB,SAAiD;CACjG,MAAM,WAAW,YAAY,IAAI;AAEjC,KAAI,CAAC,SACH;AAGF,KAAI,SAAS,UACX,QAAO,OAAO,KAAK,SAAS,SAAS,EAAE,CAAC,CAAC;AAG3C,QAAO;;;;;;;;AAST,IAAa,iBACX,KACA,MACA,WAC2B;CAC3B,MAAM,WAAW,YAAY,IAAI;AAEjC,KAAI,CAAC,YAAY,CAAC,KAChB;AAGF,KAAI,WAAW,WAAW;EACxB,MAAM,WAAW,oBAAoB,SAAS,QAAQ,MAAM;AAC5D,MAAI,CAAC,SACH;AAGF,SADoB,OAAO,KAAK,SAAS,CAAC,OAAO,aAAa,CAC3C;;AAGrB,QAAO,aAAa,OAAO,GAAG,SAAS,KAAA;;;;;;;;AASzC,IAAa,sBACX,KACA,WACA,eACW;AAGX,KAAI,CAFa,YAAY,IAAI,IAEhB,WAAW,SAAS,YACnC,QAAO;CAGT,MAAM,WAAW,UAAU,UAAU,OAAO,UAAU,IAAI,EAAE;CAC5D,MAAM,kBAAkB,SAAS,MAAM,UAAU,MAAM,SAAS,WAAW;AAE3E,KAAI,gBACF,QAAO,gBAAgB;AAGzB,KAAI,eAAe,UACjB,QAAO,SAAS,IAAI,QAAQ;AAG9B,QAAO;;;;;;;;AAST,IAAa,0BAA0B,OAAuB,WAAmD;CAC/G,MAAM,eAAe,oBAAoB,OAAO,OAAO,aAAa;CACpE,MAAM,MAAuB;EAAE;EAAO;EAAc;CAEpD,MAAM,OAAO,YAAY,KAAK,OAAO,KAAK;CAC1C,MAAM,SAAS,cAAc,KAAK,MAAM,OAAO,OAAO;CAEtD,MAAM,oBAAoB,YAAY,IAAI,GAAG;AAE7C,KAAI,CAAC,kBACH,QAAO;EAAE;EAAc;EAAM;EAAQ,SAAS;EAAW;CAI3D,MAAM,YADa,oBAAoB,kBAAkB,CAC5B,IAAI,GAAG,KAAK,GAAG,SAAS,EAAE,MAAM,UAAU,MAAM,SAAS,YAAY;AAGlG,QAAO;EAAE;EAAc;EAAM;EAAQ,SAFrB,mBAAmB,KAAK,WAAW,OAAO,QAAQ;EAEpB"}
@@ -1 +1 @@
1
- {"version":3,"file":"create-search-index.d.ts","sourceRoot":"","sources":["../../../../../src/v2/features/search/helpers/create-search-index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8DAA8D,CAAA;AAEnG,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAA;AAE1D;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,eAAe,EAAE,GAAG,QAAQ,EAAE,CAoB1E"}
1
+ {"version":3,"file":"create-search-index.d.ts","sourceRoot":"","sources":["../../../../../src/v2/features/search/helpers/create-search-index.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8DAA8D,CAAA;AAEnG,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAA;AAE1D;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,eAAe,EAAE,GAAG,QAAQ,EAAE,CAoB1E"}
@@ -1,4 +1,5 @@
1
1
  import { getResolvedRef } from "@scalar/workspace-store/helpers/get-resolved-ref";
2
+ import { getPathItemOperation } from "@scalar/workspace-store/helpers/for-each-path-item-operation";
2
3
  //#region src/v2/features/search/helpers/create-search-index.ts
3
4
  /**
4
5
  * Create a search index from a list of entries.
@@ -22,7 +23,7 @@ function createSearchIndex(documents) {
22
23
  */
23
24
  function addEntryToIndex(entry, index, document) {
24
25
  if (entry.type === "operation") {
25
- const operation = getResolvedRef(document?.paths?.[entry.path]?.[entry.method]) ?? {};
26
+ const operation = getResolvedRef(getPathItemOperation(document?.paths?.[entry.path], entry.method)) ?? {};
26
27
  index.push({
27
28
  type: "operation",
28
29
  title: entry.title,
@@ -1 +1 @@
1
- {"version":3,"file":"create-search-index.js","names":[],"sources":["../../../../../src/v2/features/search/helpers/create-search-index.ts"],"sourcesContent":["import { getResolvedRef } from '@scalar/workspace-store/helpers/get-resolved-ref'\nimport type { TraversedEntry } from '@scalar/workspace-store/schemas/navigation'\nimport type { OpenApiDocument } from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\n\nimport type { FuseData } from '@/v2/features/search/types'\n\n/**\n * Create a search index from a list of entries.\n */\nexport function createSearchIndex(documents: OpenApiDocument[]): FuseData[] {\n const index: FuseData[] = []\n\n /**\n * Recursively processes entries and their children to build the search index.\n */\n function processEntries(entriesToProcess: TraversedEntry[], document?: OpenApiDocument): void {\n entriesToProcess.forEach((entry) => {\n addEntryToIndex(entry, index, document)\n\n // Recursively process children if they exist\n if ('children' in entry && entry.children) {\n processEntries(entry.children, document)\n }\n })\n }\n\n documents?.forEach((document) => processEntries(document['x-scalar-navigation']?.children ?? [], document))\n\n return index\n}\n\n/**\n * Adds a single entry to the search index, handling all entry types recursively.\n */\nfunction addEntryToIndex(entry: TraversedEntry, index: FuseData[], document?: OpenApiDocument): void {\n // Operation\n if (entry.type === 'operation') {\n const operation = getResolvedRef(document?.paths?.[entry.path]?.[entry.method]) ?? {}\n\n index.push({\n type: 'operation',\n title: entry.title,\n id: entry.id,\n description: operation.description || '',\n method: entry.method,\n path: entry.path,\n operationId: operation.operationId,\n entry,\n documentName: document?.info.title ?? '',\n })\n\n return\n }\n\n if (entry.type === 'tag' && entry.isGroup === false) {\n index.push({\n id: entry.id,\n title: entry.title,\n description: entry.description || '',\n type: 'tag',\n entry,\n documentName: document?.info.title ?? '',\n })\n\n return\n }\n\n // Tag group\n if (entry.type === 'tag' && entry.isGroup === true) {\n index.push({\n id: entry.id,\n title: entry.title,\n description: 'Tag Group',\n type: 'tag',\n entry,\n documentName: document?.info.title ?? '',\n })\n\n return\n }\n\n // Headings from info.description\n if (entry.type === 'text') {\n index.push({\n id: entry.id,\n type: 'heading',\n title: entry.title ?? '',\n description: 'Heading',\n entry,\n documentName: document?.info.title ?? '',\n })\n\n return\n }\n}\n"],"mappings":";;;;;AASA,SAAgB,kBAAkB,WAA0C;CAC1E,MAAM,QAAoB,EAAE;;;;CAK5B,SAAS,eAAe,kBAAoC,UAAkC;AAC5F,mBAAiB,SAAS,UAAU;AAClC,mBAAgB,OAAO,OAAO,SAAS;AAGvC,OAAI,cAAc,SAAS,MAAM,SAC/B,gBAAe,MAAM,UAAU,SAAS;IAE1C;;AAGJ,YAAW,SAAS,aAAa,eAAe,SAAS,wBAAwB,YAAY,EAAE,EAAE,SAAS,CAAC;AAE3G,QAAO;;;;;AAMT,SAAS,gBAAgB,OAAuB,OAAmB,UAAkC;AAEnG,KAAI,MAAM,SAAS,aAAa;EAC9B,MAAM,YAAY,eAAe,UAAU,QAAQ,MAAM,QAAQ,MAAM,QAAQ,IAAI,EAAE;AAErF,QAAM,KAAK;GACT,MAAM;GACN,OAAO,MAAM;GACb,IAAI,MAAM;GACV,aAAa,UAAU,eAAe;GACtC,QAAQ,MAAM;GACd,MAAM,MAAM;GACZ,aAAa,UAAU;GACvB;GACA,cAAc,UAAU,KAAK,SAAS;GACvC,CAAC;AAEF;;AAGF,KAAI,MAAM,SAAS,SAAS,MAAM,YAAY,OAAO;AACnD,QAAM,KAAK;GACT,IAAI,MAAM;GACV,OAAO,MAAM;GACb,aAAa,MAAM,eAAe;GAClC,MAAM;GACN;GACA,cAAc,UAAU,KAAK,SAAS;GACvC,CAAC;AAEF;;AAIF,KAAI,MAAM,SAAS,SAAS,MAAM,YAAY,MAAM;AAClD,QAAM,KAAK;GACT,IAAI,MAAM;GACV,OAAO,MAAM;GACb,aAAa;GACb,MAAM;GACN;GACA,cAAc,UAAU,KAAK,SAAS;GACvC,CAAC;AAEF;;AAIF,KAAI,MAAM,SAAS,QAAQ;AACzB,QAAM,KAAK;GACT,IAAI,MAAM;GACV,MAAM;GACN,OAAO,MAAM,SAAS;GACtB,aAAa;GACb;GACA,cAAc,UAAU,KAAK,SAAS;GACvC,CAAC;AAEF"}
1
+ {"version":3,"file":"create-search-index.js","names":[],"sources":["../../../../../src/v2/features/search/helpers/create-search-index.ts"],"sourcesContent":["import { getPathItemOperation } from '@scalar/workspace-store/helpers/for-each-path-item-operation'\nimport { getResolvedRef } from '@scalar/workspace-store/helpers/get-resolved-ref'\nimport type { TraversedEntry } from '@scalar/workspace-store/schemas/navigation'\nimport type { OpenApiDocument } from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\n\nimport type { FuseData } from '@/v2/features/search/types'\n\n/**\n * Create a search index from a list of entries.\n */\nexport function createSearchIndex(documents: OpenApiDocument[]): FuseData[] {\n const index: FuseData[] = []\n\n /**\n * Recursively processes entries and their children to build the search index.\n */\n function processEntries(entriesToProcess: TraversedEntry[], document?: OpenApiDocument): void {\n entriesToProcess.forEach((entry) => {\n addEntryToIndex(entry, index, document)\n\n // Recursively process children if they exist\n if ('children' in entry && entry.children) {\n processEntries(entry.children, document)\n }\n })\n }\n\n documents?.forEach((document) => processEntries(document['x-scalar-navigation']?.children ?? [], document))\n\n return index\n}\n\n/**\n * Adds a single entry to the search index, handling all entry types recursively.\n */\nfunction addEntryToIndex(entry: TraversedEntry, index: FuseData[], document?: OpenApiDocument): void {\n // Operation\n if (entry.type === 'operation') {\n const operation = getResolvedRef(getPathItemOperation(document?.paths?.[entry.path], entry.method)) ?? {}\n\n index.push({\n type: 'operation',\n title: entry.title,\n id: entry.id,\n description: operation.description || '',\n method: entry.method,\n path: entry.path,\n operationId: operation.operationId,\n entry,\n documentName: document?.info.title ?? '',\n })\n\n return\n }\n\n if (entry.type === 'tag' && entry.isGroup === false) {\n index.push({\n id: entry.id,\n title: entry.title,\n description: entry.description || '',\n type: 'tag',\n entry,\n documentName: document?.info.title ?? '',\n })\n\n return\n }\n\n // Tag group\n if (entry.type === 'tag' && entry.isGroup === true) {\n index.push({\n id: entry.id,\n title: entry.title,\n description: 'Tag Group',\n type: 'tag',\n entry,\n documentName: document?.info.title ?? '',\n })\n\n return\n }\n\n // Headings from info.description\n if (entry.type === 'text') {\n index.push({\n id: entry.id,\n type: 'heading',\n title: entry.title ?? '',\n description: 'Heading',\n entry,\n documentName: document?.info.title ?? '',\n })\n\n return\n }\n}\n"],"mappings":";;;;;;AAUA,SAAgB,kBAAkB,WAA0C;CAC1E,MAAM,QAAoB,EAAE;;;;CAK5B,SAAS,eAAe,kBAAoC,UAAkC;AAC5F,mBAAiB,SAAS,UAAU;AAClC,mBAAgB,OAAO,OAAO,SAAS;AAGvC,OAAI,cAAc,SAAS,MAAM,SAC/B,gBAAe,MAAM,UAAU,SAAS;IAE1C;;AAGJ,YAAW,SAAS,aAAa,eAAe,SAAS,wBAAwB,YAAY,EAAE,EAAE,SAAS,CAAC;AAE3G,QAAO;;;;;AAMT,SAAS,gBAAgB,OAAuB,OAAmB,UAAkC;AAEnG,KAAI,MAAM,SAAS,aAAa;EAC9B,MAAM,YAAY,eAAe,qBAAqB,UAAU,QAAQ,MAAM,OAAO,MAAM,OAAO,CAAC,IAAI,EAAE;AAEzG,QAAM,KAAK;GACT,MAAM;GACN,OAAO,MAAM;GACb,IAAI,MAAM;GACV,aAAa,UAAU,eAAe;GACtC,QAAQ,MAAM;GACd,MAAM,MAAM;GACZ,aAAa,UAAU;GACvB;GACA,cAAc,UAAU,KAAK,SAAS;GACvC,CAAC;AAEF;;AAGF,KAAI,MAAM,SAAS,SAAS,MAAM,YAAY,OAAO;AACnD,QAAM,KAAK;GACT,IAAI,MAAM;GACV,OAAO,MAAM;GACb,aAAa,MAAM,eAAe;GAClC,MAAM;GACN;GACA,cAAc,UAAU,KAAK,SAAS;GACvC,CAAC;AAEF;;AAIF,KAAI,MAAM,SAAS,SAAS,MAAM,YAAY,MAAM;AAClD,QAAM,KAAK;GACT,IAAI,MAAM;GACV,OAAO,MAAM;GACb,aAAa;GACb,MAAM;GACN;GACA,cAAc,UAAU,KAAK,SAAS;GACvC,CAAC;AAEF;;AAIF,KAAI,MAAM,SAAS,QAAQ;AACzB,QAAM,KAAK;GACT,IAAI,MAAM;GACV,MAAM;GACN,OAAO,MAAM,SAAS;GACtB,aAAa;GACb;GACA,cAAc,UAAU,KAAK,SAAS;GACvC,CAAC;AAEF"}
@@ -70,23 +70,23 @@ to {
70
70
  /*
71
71
  Deep styling for customizing Codemirror
72
72
  */
73
- [data-v-3118bf46] .cm-editor {
73
+ [data-v-d6fb2049] .cm-editor {
74
74
  height: 100%;
75
75
  outline: none;
76
76
  padding: 0;
77
77
  background: transparent;
78
78
  }
79
- [data-v-3118bf46] .cm-placeholder {
79
+ [data-v-d6fb2049] .cm-placeholder {
80
80
  color: var(--scalar-color-3);
81
81
  }
82
- [data-v-3118bf46] .cm-content {
82
+ [data-v-d6fb2049] .cm-content {
83
83
  font-family: var(--scalar-font-code);
84
84
  font-size: var(--scalar-small);
85
85
  max-height: 20px;
86
86
  padding: 8px 0;
87
87
  }
88
88
  /* Tooltip helper */
89
- [data-v-3118bf46] .cm-tooltip {
89
+ [data-v-d6fb2049] .cm-tooltip {
90
90
  background: transparent !important;
91
91
  filter: brightness(var(--scalar-lifted-brightness));
92
92
  border-radius: var(--scalar-radius);
@@ -95,43 +95,43 @@ to {
95
95
  outline: none !important;
96
96
  overflow: hidden !important;
97
97
  }
98
- [data-v-3118bf46] .cm-tooltip-autocomplete ul li {
98
+ [data-v-d6fb2049] .cm-tooltip-autocomplete ul li {
99
99
  padding: 3px 6px !important;
100
100
  }
101
- [data-v-3118bf46] .cm-completionIcon-type:after {
101
+ [data-v-d6fb2049] .cm-completionIcon-type:after {
102
102
  color: var(--scalar-color-3) !important;
103
103
  }
104
- [data-v-3118bf46] .cm-tooltip-autocomplete ul li[aria-selected] {
104
+ [data-v-d6fb2049] .cm-tooltip-autocomplete ul li[aria-selected] {
105
105
  background: var(--scalar-background-2) !important;
106
106
  color: var(--scalar-color-1) !important;
107
107
  }
108
- [data-v-3118bf46] .cm-tooltip-autocomplete ul {
108
+ [data-v-d6fb2049] .cm-tooltip-autocomplete ul {
109
109
  padding: 6px !important;
110
110
  position: relative;
111
111
  }
112
- [data-v-3118bf46] .cm-tooltip-autocomplete ul li:hover {
112
+ [data-v-d6fb2049] .cm-tooltip-autocomplete ul li:hover {
113
113
  border-radius: 3px;
114
114
  color: var(--scalar-color-1) !important;
115
115
  background: var(--scalar-background-3) !important;
116
116
  }
117
117
  /* Disable active line highlighting */
118
- [data-v-3118bf46] .cm-activeLine,[data-v-3118bf46] .cm-activeLineGutter {
118
+ [data-v-d6fb2049] .cm-activeLine,[data-v-d6fb2049] .cm-activeLineGutter {
119
119
  background-color: transparent;
120
120
  }
121
121
  /* Color selection matching */
122
- [data-v-3118bf46] .cm-selectionMatch,[data-v-3118bf46] .cm-matchingBracket {
122
+ [data-v-d6fb2049] .cm-selectionMatch,[data-v-d6fb2049] .cm-matchingBracket {
123
123
  border-radius: var(--scalar-radius);
124
124
  background: var(--scalar-background-4) !important;
125
125
  }
126
126
  /* Color Picker Swatches */
127
- [data-v-3118bf46] .cm-css-color-picker-wrapper {
127
+ [data-v-d6fb2049] .cm-css-color-picker-wrapper {
128
128
  display: inline-flex;
129
129
  outline: 1px solid var(--scalar-background-3);
130
130
  border-radius: 3px;
131
131
  overflow: hidden;
132
132
  }
133
133
  /* Number gutter */
134
- [data-v-3118bf46] .cm-gutters {
134
+ [data-v-d6fb2049] .cm-gutters {
135
135
  background-color: transparent;
136
136
  border-right: none;
137
137
  color: var(--scalar-color-3);
@@ -139,7 +139,7 @@ to {
139
139
  line-height: 22px;
140
140
  border-radius: 0 0 0 3px;
141
141
  }
142
- [data-v-3118bf46] .cm-gutters:before {
142
+ [data-v-d6fb2049] .cm-gutters:before {
143
143
  content: '';
144
144
  position: absolute;
145
145
  top: 2px;
@@ -149,7 +149,7 @@ to {
149
149
  border-radius: var(--scalar-radius) 0 0 var(--scalar-radius);
150
150
  background-color: var(--scalar-background-1);
151
151
  }
152
- [data-v-3118bf46] .cm-gutterElement {
152
+ [data-v-d6fb2049] .cm-gutterElement {
153
153
  font-family: var(--scalar-font-code) !important;
154
154
  padding-left: 0px !important;
155
155
  padding-right: 6px !important;
@@ -158,16 +158,16 @@ to {
158
158
  justify-content: flex-end;
159
159
  position: relative;
160
160
  }
161
- [data-v-3118bf46] .cm-lineNumbers .cm-gutterElement {
161
+ [data-v-d6fb2049] .cm-lineNumbers .cm-gutterElement {
162
162
  min-width: fit-content;
163
163
  }
164
- [data-v-3118bf46] .cm-gutter + .cm-gutter :not(.cm-foldGutter) .cm-gutterElement {
164
+ [data-v-d6fb2049] .cm-gutter + .cm-gutter :not(.cm-foldGutter) .cm-gutterElement {
165
165
  padding-left: 0 !important;
166
166
  }
167
- [data-v-3118bf46] .cm-scroller {
167
+ [data-v-d6fb2049] .cm-scroller {
168
168
  overflow: auto;
169
169
  }
170
- .line-wrapping[data-v-3118bf46]:focus-within .cm-content {
170
+ .line-wrapping[data-v-d6fb2049]:focus-within .cm-content {
171
171
  display: inline-table;
172
172
  min-height: fit-content;
173
173
  padding: 3px 6px;
@@ -243,21 +243,21 @@ to {
243
243
  margin-top: 0;
244
244
  }
245
245
 
246
- [data-v-372238a6] .cm-editor {
246
+ [data-v-d37cbfcc] .cm-editor {
247
247
  height: 100%;
248
248
  outline: none;
249
249
  width: 100%;
250
250
  }
251
- [data-v-372238a6] .cm-line {
251
+ [data-v-d37cbfcc] .cm-line {
252
252
  padding: 0;
253
253
  }
254
- [data-v-372238a6] .cm-content {
254
+ [data-v-d37cbfcc] .cm-content {
255
255
  padding: 0;
256
256
  display: flex;
257
257
  align-items: center;
258
258
  font-size: var(--scalar-small);
259
259
  }
260
- .scroll-timeline-x[data-v-372238a6] {
260
+ .scroll-timeline-x[data-v-d37cbfcc] {
261
261
  -ms-overflow-style: none;
262
262
  /* Fade the URL at the viewport edges. Mask lives on the scrollport (this
263
263
  element) rather than on `.cm-scroller`, whose width follows the URL's
@@ -270,31 +270,31 @@ to {
270
270
  transparent 100%
271
271
  );
272
272
  }
273
- .scroll-timeline-x-hidden[data-v-372238a6] {
273
+ .scroll-timeline-x-hidden[data-v-d37cbfcc] {
274
274
  overflow-x: auto;
275
275
  }
276
- .scroll-timeline-x-hidden[data-v-372238a6] .cm-scroller {
276
+ .scroll-timeline-x-hidden[data-v-d37cbfcc] .cm-scroller {
277
277
  scrollbar-width: none;
278
278
  -ms-overflow-style: none;
279
279
  padding-right: 20px;
280
280
  overflow: auto;
281
281
  }
282
- .scroll-timeline-x-hidden[data-v-372238a6]::-webkit-scrollbar {
282
+ .scroll-timeline-x-hidden[data-v-d37cbfcc]::-webkit-scrollbar {
283
283
  width: 0;
284
284
  height: 0;
285
285
  display: none;
286
286
  }
287
- .scroll-timeline-x-hidden[data-v-372238a6] .cm-scroller::-webkit-scrollbar {
287
+ .scroll-timeline-x-hidden[data-v-d37cbfcc] .cm-scroller::-webkit-scrollbar {
288
288
  width: 0;
289
289
  height: 0;
290
290
  display: none;
291
291
  }
292
- .scroll-timeline-x-address[data-v-372238a6] {
292
+ .scroll-timeline-x-address[data-v-d37cbfcc] {
293
293
  line-height: 27px;
294
294
  scrollbar-width: none; /* Firefox */
295
295
  }
296
296
  /* make clickable are to left of send button */
297
- .scroll-timeline-x-address[data-v-372238a6]:after {
297
+ .scroll-timeline-x-address[data-v-d37cbfcc]:after {
298
298
  content: '';
299
299
  position: absolute;
300
300
  height: 100%;
@@ -302,12 +302,12 @@ to {
302
302
  right: 0;
303
303
  cursor: text;
304
304
  }
305
- .scroll-timeline-x-address[data-v-372238a6]:empty:before {
305
+ .scroll-timeline-x-address[data-v-d37cbfcc]:empty:before {
306
306
  content: 'Enter URL or cURL request';
307
307
  color: var(--scalar-color-3);
308
308
  pointer-events: none;
309
309
  }
310
- .address-bar-bg-states[data-v-372238a6] {
310
+ .address-bar-bg-states[data-v-d37cbfcc] {
311
311
  --scalar-address-bar-bg: color-mix(
312
312
  in srgb,
313
313
  var(--scalar-background-1),
@@ -315,12 +315,16 @@ to {
315
315
  );
316
316
  background: var(--scalar-address-bar-bg);
317
317
  }
318
- .address-bar-bg-states[data-v-372238a6]:has(.cm-focused) {
318
+ .address-bar-bg-states[data-v-d37cbfcc]:has(.cm-focused) {
319
319
  --scalar-address-bar-bg: var(--scalar-background-1);
320
320
  border-color: var(--scalar-border-color);
321
321
  outline-width: 1px;
322
322
  outline-style: solid;
323
323
  }
324
+ .address-bar-bg-states:has(.cm-focused) .fade-left[data-v-d37cbfcc],
325
+ .address-bar-bg-states:has(.cm-focused) .fade-right[data-v-d37cbfcc] {
326
+ --scalar-address-bar-bg: var(--scalar-background-1);
327
+ }
324
328
 
325
329
  .app-exit-button[data-v-42c563b3] {
326
330
  color: white;
@@ -419,33 +423,110 @@ to {
419
423
  display: none;
420
424
  }
421
425
 
422
- [data-v-36811e28] .cm-editor {
423
- padding: 0;
426
+ .code-input-lite[data-v-1974e80d] {
427
+ /* Flex so the editor centres vertically in whatever height the cell gives us.
428
+ Font properties inherit so we adopt the surrounding typography. */
429
+ display: flex;
430
+ align-items: center;
431
+ }
432
+ .code-input-lite__editor[data-v-1974e80d] {
433
+ /* Everything font-related inherits from the surrounding context. */
434
+ font: inherit;
435
+ letter-spacing: inherit;
436
+ flex: 1;
437
+ min-width: 0;
438
+ background: transparent;
439
+ outline: none;
440
+ color: var(--scalar-color-1);
441
+ caret-color: var(--scalar-color-1);
442
+ /* Single-line: horizontal scroll keeps the caret visible for long values;
443
+ the scrollbar itself is hidden (would be noisy inside a table cell). */
444
+ white-space: pre;
445
+ overflow-x: auto;
446
+ overflow-y: hidden;
447
+ scrollbar-width: none;
448
+ padding: 0 0.5em;
449
+ box-sizing: border-box;
450
+ line-height: 1.44;
451
+ /* Positioning context for the absolutely positioned placeholder. */
452
+ position: relative;
424
453
  }
425
- [data-v-36811e28] .cm-content {
454
+ .code-input-lite__editor[data-v-1974e80d]::-webkit-scrollbar {
455
+ display: none;
456
+ }
457
+
458
+ /* Absolute so the placeholder does not occupy flow space inside the
459
+ contenteditable; otherwise the caret would land after it on focus.
460
+ `pointer-events: none` lets clicks fall through to focus the editor.
461
+ Hidden on focus so it never renders on top of the text caret. */
462
+ .code-input-lite--empty .code-input-lite__editor[data-v-1974e80d]:not(:focus)::before {
463
+ content: attr(data-placeholder);
464
+ color: var(--scalar-color-3);
465
+ pointer-events: none;
466
+ position: absolute;
467
+ top: 0;
468
+ bottom: 0;
469
+ left: 0.5em;
470
+ display: flex;
426
471
  align-items: center;
472
+ }
473
+ .code-input-lite--error .code-input-lite__editor[data-v-1974e80d] {
474
+ outline: 1px solid var(--scalar-color-red);
475
+ }
476
+
477
+ /* Pill styling. Each pill is `<span contenteditable="false">name</span>` —
478
+ an atomic widget; the caret lands before or after it, never inside. */
479
+ .scalar-pill {
480
+ color: var(--scalar-color-2);
481
+ border-radius: 30px;
482
+ display: inline-block;
483
+ font-family: var(--scalar-font-code);
484
+ font-size: 0.9em;
485
+ line-height: 1.4;
486
+ vertical-align: baseline;
487
+ background: var(--scalar-background-3);
488
+ padding: 0.125em 0.6em;
489
+ margin-right: 0.35em;
490
+ cursor: text;
491
+ /* Single click selects the whole pill — chip/mention model, deletes in one go. */
492
+ user-select: all;
493
+ -webkit-user-select: all;
494
+ }
495
+ .dark-mode .scalar-pill {
496
+ background: color-mix(
497
+ in srgb,
498
+ var(--tw-bg-base, var(--scalar-color-1)),
499
+ transparent 90%
500
+ );
501
+ }
502
+ .light-mode .scalar-pill {
503
+ background: var(--scalar-background-3);
504
+ }
505
+ .scalar-pill--context-fn {
506
+ /* Inset box-shadow as a border so the layout box stays identical to plain pills. */
507
+ box-shadow: 0 0 0 1px
508
+ color-mix(in srgb, var(--scalar-color-3), transparent 35%) inset;
509
+ }
510
+ .dark-mode .scalar-pill--context-fn {
511
+ background: color-mix(in srgb, var(--scalar-background-3), transparent 55%);
512
+ }
513
+ .light-mode .scalar-pill--context-fn {
514
+ background: color-mix(in srgb, var(--scalar-background-3), transparent 40%);
515
+ }
516
+
517
+ [data-v-e83eb7d0] .code-input-lite__editor {
427
518
  background-color: transparent;
428
- display: flex;
429
519
  font-family: var(--scalar-font);
430
520
  font-size: var(--scalar-small);
431
521
  padding: 5px 8px;
432
- width: 100%;
433
522
  }
434
- [data-v-36811e28] .cm-content:has(.cm-pill) {
435
- padding: 5px 8px;
436
- }
437
- [data-v-36811e28] .cm-content .cm-pill:not(:last-of-type) {
438
- margin-right: 0.5px;
523
+ [data-v-e83eb7d0] .scalar-pill:not(:last-of-type) {
524
+ margin-right: 0.15em;
439
525
  }
440
- [data-v-36811e28] .cm-content .cm-pill:not(:first-of-type) {
526
+ [data-v-e83eb7d0] .scalar-pill:not(:first-of-type) {
441
527
  margin-left: 0.5px;
442
528
  }
443
- [data-v-36811e28] .cm-line {
444
- overflow: hidden;
445
- padding: 0;
446
- text-overflow: ellipsis;
447
- }
448
- .filemask[data-v-36811e28] {
529
+ .filemask[data-v-e83eb7d0] {
449
530
  mask-image: linear-gradient(
450
531
  to right,
451
532
  transparent 0,
@@ -479,42 +560,27 @@ to {
479
560
  scrollbar-width: none;
480
561
  }
481
562
 
482
- [data-v-1ee3c31d] .cm-editor {
483
- padding: 0;
484
- }
485
- [data-v-1ee3c31d] .cm-content {
486
- align-items: center;
563
+ [data-v-a6f4752a] .code-input-lite__editor {
487
564
  background-color: transparent;
488
- display: flex;
489
565
  font-family: var(--scalar-font);
490
566
  font-size: var(--scalar-small);
491
567
  padding: 5px 8px;
492
- width: 100%;
493
568
  }
494
- [data-v-1ee3c31d] .cm-content:has(.cm-pill) {
495
- padding: 5px 8px;
569
+ [data-v-a6f4752a] .scalar-pill:not(:last-of-type) {
570
+ margin-right: 0.15em;
496
571
  }
497
- [data-v-1ee3c31d] .cm-content .cm-pill:not(:last-of-type) {
498
- margin-right: 0.5px;
499
- }
500
- [data-v-1ee3c31d] .cm-content .cm-pill:not(:first-of-type) {
572
+ [data-v-a6f4752a] .scalar-pill:not(:first-of-type) {
501
573
  margin-left: 0.5px;
502
574
  }
503
- [data-v-1ee3c31d] .cm-line {
504
- overflow: hidden;
505
- padding: 0;
506
- text-overflow: ellipsis;
507
- word-break: break-word;
508
- }
509
- .required[data-v-1ee3c31d]::after {
575
+ .required[data-v-a6f4752a]::after {
510
576
  content: 'Required';
511
577
  }
512
578
  /* Tailwind placeholder is busted */
513
- input[data-v-1ee3c31d]::placeholder {
579
+ input[data-v-a6f4752a]::placeholder {
514
580
  color: var(--scalar-color-3);
515
581
  }
516
582
  /* we want our inputs to look like a password input but not be one */
517
- .scalar-password-input[data-v-1ee3c31d] {
583
+ .scalar-password-input[data-v-a6f4752a] {
518
584
  text-security: disc;
519
585
  -webkit-text-security: disc;
520
586
  -moz-text-security: disc;
@@ -722,32 +788,18 @@ to {
722
788
  bottom: 0;
723
789
  }
724
790
 
725
- [data-v-69be2d6c] .cm-editor {
726
- padding: 0;
727
- }
728
- [data-v-69be2d6c] .cm-content {
729
- align-items: center;
791
+ [data-v-5b336842] .code-input-lite__editor {
730
792
  background-color: transparent;
731
- display: flex;
732
793
  font-family: var(--scalar-font);
733
794
  font-size: var(--scalar-small);
734
795
  padding: 5px 8px;
735
- width: 100%;
736
- }
737
- [data-v-69be2d6c] .cm-content:has(.cm-pill) {
738
- padding: 5px 8px;
739
796
  }
740
- [data-v-69be2d6c] .cm-content .cm-pill:not(:last-of-type) {
741
- margin-right: 0.5px;
797
+ [data-v-5b336842] .scalar-pill:not(:last-of-type) {
798
+ margin-right: 0.15em;
742
799
  }
743
- [data-v-69be2d6c] .cm-content .cm-pill:not(:first-of-type) {
800
+ [data-v-5b336842] .scalar-pill:not(:first-of-type) {
744
801
  margin-left: 0.5px;
745
802
  }
746
- [data-v-69be2d6c] .cm-line {
747
- overflow: hidden;
748
- padding: 0;
749
- text-overflow: ellipsis;
750
- }
751
803
  /*! tailwindcss v4.2.1 | MIT License | https://tailwindcss.com */
752
804
  .scalar .scalar-app-layout[data-v-77897d1c] {
753
805
  background: var(--scalar-background-1);
package/package.json CHANGED
@@ -18,7 +18,7 @@
18
18
  "rest",
19
19
  "testing"
20
20
  ],
21
- "version": "3.10.2",
21
+ "version": "3.10.4",
22
22
  "engines": {
23
23
  "node": ">=22"
24
24
  },
@@ -320,20 +320,20 @@
320
320
  "vue": "^3.5.30",
321
321
  "yaml": "^2.8.3",
322
322
  "zod": "^4.3.5",
323
- "@scalar/components": "0.27.1",
324
- "@scalar/icons": "0.7.3",
323
+ "@scalar/components": "0.27.2",
325
324
  "@scalar/helpers": "0.8.2",
326
325
  "@scalar/json-magic": "0.12.16",
327
- "@scalar/oas-utils": "0.18.3",
328
326
  "@scalar/openapi-types": "0.9.1",
327
+ "@scalar/oas-utils": "0.18.5",
328
+ "@scalar/icons": "0.7.3",
329
+ "@scalar/sidebar": "0.9.23",
330
+ "@scalar/snippetz": "0.9.17",
329
331
  "@scalar/themes": "0.16.0",
330
- "@scalar/sidebar": "0.9.21",
331
- "@scalar/types": "0.13.2",
332
- "@scalar/snippetz": "0.9.15",
333
- "@scalar/use-codemirror": "0.14.11",
334
- "@scalar/use-hooks": "0.4.6",
335
- "@scalar/workspace-store": "0.54.2",
336
- "@scalar/use-toasts": "0.10.2"
332
+ "@scalar/types": "0.14.0",
333
+ "@scalar/use-toasts": "0.10.2",
334
+ "@scalar/use-hooks": "0.4.7",
335
+ "@scalar/use-codemirror": "0.14.12",
336
+ "@scalar/workspace-store": "0.54.4"
337
337
  },
338
338
  "devDependencies": {
339
339
  "@tailwindcss/cli": "^4.2.4",