@scalar/api-client-react 2.0.37 → 2.0.39
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.
- package/CHANGELOG.md +4 -0
- package/dist/index.js.map +1 -1
- package/dist/style.css +1438 -304
- package/package.json +6 -6
package/CHANGELOG.md
CHANGED
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/lazy-load.ts","../src/use-api-client.ts"],"sourcesContent":["import type { ApiClientOptions } from '@scalar/api-client/modal'\n\n/**\n * Creates a lazy singleton getter: the factory runs at most once, caches the resulting promise,\n * and clears the cache on failure so the next call can retry.\n *\n * Optional args are forwarded to the factory on the first (cache-miss) call only.\n * Subsequent calls return the cached promise regardless of the args passed.\n */\nconst makeLazySingleton = <T, Args extends unknown[] = []>(\n factory: (...args: Args) => Promise<T>,\n): ((...args: Args) => Promise<T>) => {\n let cached: Promise<T> | undefined\n return (...args: Args) => {\n cached ??= factory(...args).catch((error) => {\n cached = undefined\n throw error\n })\n return cached\n }\n}\n\n/** Lazy load the client modal creator */\nexport const getClientModalCreator = makeLazySingleton(() =>\n import('@scalar/api-client/modal').then(({ createApiClientModal }) => createApiClientModal),\n)\n\n/** Module-scoped singleton workspace store (lazy-loaded on first use). */\nexport const getWorkspaceStoreSingleton = makeLazySingleton(() =>\n import('@scalar/workspace-store/client').then(({ createWorkspaceStore }) => createWorkspaceStore()),\n)\n\n/** Module-scoped singleton workspace event bus (lazy-loaded on first use). */\nexport const getWorkspaceEventBusSingleton = makeLazySingleton(() =>\n import('@scalar/workspace-store/events').then(({ createWorkspaceEventBus }) => createWorkspaceEventBus()),\n)\n\n/**\n * Lazily creates the singleton Vue app, mounts it as the last child of document.body,\n * and returns the controller. Subsequent calls return the same promise.\n *\n * Only modal-supported options are accepted here. Document-specific fields\n * (`url`, `content`) must be registered via `workspaceStore.addDocument` after the client\n * is ready — they are not part of the modal constructor.\n */\nexport const getOrCreateApiClient = makeLazySingleton(async (options: ApiClientOptions = {}) => {\n const el = document.createElement('div')\n el.className = 'scalar-app'\n document.body.appendChild(el)\n\n try {\n const [createModal, workspaceStore, eventBus] = await Promise.all([\n getClientModalCreator(),\n getWorkspaceStoreSingleton(),\n getWorkspaceEventBusSingleton(),\n ])\n\n const apiClient = createModal({\n el,\n eventBus,\n workspaceStore,\n options,\n // TODO: map plugins from configuration when available\n // plugins: mapConfigPlugins(options),\n })\n\n return { apiClient, workspaceStore }\n } catch (error) {\n el.remove()\n throw error\n }\n})\n","'use client'\n\nimport type { ApiClientModal, ApiClientOptions, RoutePayload } from '@scalar/api-client/modal'\nimport { generateHash } from '@scalar/helpers/string/generate-hash'\nimport { useEffect, useRef, useState } from 'react'\n\nimport './style.css'\n\nimport { isObjectEqual } from '@scalar/helpers/object/is-object-equal'\nimport type { WorkspaceStore } from '@scalar/workspace-store/client'\n\nimport { getOrCreateApiClient } from './lazy-load'\n\nglobalThis.__VUE_OPTIONS_API__ = true\nglobalThis.__VUE_PROD_HYDRATION_MISMATCH_DETAILS__ = true\nglobalThis.__VUE_PROD_DEVTOOLS__ = false\n\nexport type ApiClientConfigurationReact = ApiClientOptions &\n (\n | {\n content?: never\n url: string\n }\n | {\n content: Record<string, unknown>\n url?: never\n }\n )\n\nexport type UseApiClientModalProps = {\n /** Configuration for the Api Client (url or inline content) */\n configuration: ApiClientConfigurationReact\n}\n\n/** Tracks which documents are/have been loaded so we dont duplicate */\nconst documentSet = new Set<string>()\n\nconst getDocumentSlug = (configuration: ApiClientConfigurationReact) => {\n if (configuration.url !== undefined) {\n return configuration.url || 'default'\n }\n return generateHash(JSON.stringify(configuration.content))\n}\n\n/**\n * Returns the singleton Api Client\n *\n * On first call the Vue app is lazily created and appended to document.body where it\n * lives for the lifetime of the page — it is never unmounted, so it survives client-side\n * navigation without losing state.\n *\n * Subsequent calls from any component share the same instance of the client but can use the same\n * or different documents\n */\nexport const useApiClient = ({\n configuration,\n}: UseApiClientModalProps): (Omit<ApiClientModal, 'open'> & { open: (payload: RoutePayload) => void }) | undefined => {\n const [client, setClient] = useState<ApiClientModal | undefined>(undefined)\n const [workspaceStore, setWorkspaceStore] = useState<WorkspaceStore | undefined>(undefined)\n const documentSlugRef = useRef('')\n const previousModalOptionsRef = useRef<ApiClientOptions | undefined>(undefined)\n\n /** Small wrapper to set the documentSlug */\n const open = (payload: RoutePayload) => client?.open({ documentSlug: documentSlugRef.current, ...payload })\n\n useEffect(() => {\n let cancelled = false\n\n // Strip document-specific fields before passing to the modal constructor.\n const { url, content, ...modalOptions } = configuration\n\n const slug = getDocumentSlug(configuration)\n\n void getOrCreateApiClient(modalOptions)?.then((_client) => {\n if (cancelled || !_client) {\n return\n }\n\n // React always provides the complete modal option set for this hook instance,\n // so we overwrite to clear options removed by consumers.\n _client.apiClient.updateOptions(modalOptions, true)\n previousModalOptionsRef.current = modalOptions\n\n setClient(_client.apiClient)\n setWorkspaceStore(_client.workspaceStore)\n documentSlugRef.current = slug\n\n if (slug && !documentSet.has(slug)) {\n documentSet.add(slug)\n if (url !== undefined) {\n void _client.workspaceStore.addDocument({ name: slug, url })\n } else {\n void _client.workspaceStore.addDocument({ name: slug, document: content })\n }\n }\n })\n\n return () => {\n cancelled = true\n }\n\n // Only run once per mount\n }, [])\n\n // Register new document when we detect the url has changed\n useEffect(() => {\n if (!client || !workspaceStore) {\n return\n }\n\n const slug = getDocumentSlug(configuration)\n documentSlugRef.current = slug\n\n if (documentSet.has(slug)) {\n return\n }\n documentSet.add(slug)\n\n if (configuration.url !== undefined) {\n void workspaceStore.addDocument({ name: slug, url: configuration.url })\n } else {\n void workspaceStore.addDocument({ name: slug, document: configuration.content })\n }\n }, [client, configuration.url, configuration.content, workspaceStore])\n\n // Update the modal options when the configuration changes\n useEffect(() => {\n if (!client || !configuration) {\n return\n }\n\n const { url: _url, content: _content, ...modalOptions } = configuration\n if (isObjectEqual(previousModalOptionsRef.current, modalOptions)) {\n return\n }\n\n client.updateOptions(modalOptions, true)\n previousModalOptionsRef.current = modalOptions\n }, [client, configuration])\n\n return client\n ? {\n ...client,\n open,\n }\n : undefined\n}\n"],"mappings":";;;;;;;;;;;;AASA,IAAM,qBACJ,YACoC;CACpC,IAAI;
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/lazy-load.ts","../src/use-api-client.ts"],"sourcesContent":["import type { ApiClientOptions } from '@scalar/api-client/modal'\n\n/**\n * Creates a lazy singleton getter: the factory runs at most once, caches the resulting promise,\n * and clears the cache on failure so the next call can retry.\n *\n * Optional args are forwarded to the factory on the first (cache-miss) call only.\n * Subsequent calls return the cached promise regardless of the args passed.\n */\nconst makeLazySingleton = <T, Args extends unknown[] = []>(\n factory: (...args: Args) => Promise<T>,\n): ((...args: Args) => Promise<T>) => {\n let cached: Promise<T> | undefined\n return (...args: Args) => {\n cached ??= factory(...args).catch((error) => {\n cached = undefined\n throw error\n })\n return cached\n }\n}\n\n/** Lazy load the client modal creator */\nexport const getClientModalCreator = makeLazySingleton(() =>\n import('@scalar/api-client/modal').then(({ createApiClientModal }) => createApiClientModal),\n)\n\n/** Module-scoped singleton workspace store (lazy-loaded on first use). */\nexport const getWorkspaceStoreSingleton = makeLazySingleton(() =>\n import('@scalar/workspace-store/client').then(({ createWorkspaceStore }) => createWorkspaceStore()),\n)\n\n/** Module-scoped singleton workspace event bus (lazy-loaded on first use). */\nexport const getWorkspaceEventBusSingleton = makeLazySingleton(() =>\n import('@scalar/workspace-store/events').then(({ createWorkspaceEventBus }) => createWorkspaceEventBus()),\n)\n\n/**\n * Lazily creates the singleton Vue app, mounts it as the last child of document.body,\n * and returns the controller. Subsequent calls return the same promise.\n *\n * Only modal-supported options are accepted here. Document-specific fields\n * (`url`, `content`) must be registered via `workspaceStore.addDocument` after the client\n * is ready — they are not part of the modal constructor.\n */\nexport const getOrCreateApiClient = makeLazySingleton(async (options: ApiClientOptions = {}) => {\n const el = document.createElement('div')\n el.className = 'scalar-app'\n document.body.appendChild(el)\n\n try {\n const [createModal, workspaceStore, eventBus] = await Promise.all([\n getClientModalCreator(),\n getWorkspaceStoreSingleton(),\n getWorkspaceEventBusSingleton(),\n ])\n\n const apiClient = createModal({\n el,\n eventBus,\n workspaceStore,\n options,\n // TODO: map plugins from configuration when available\n // plugins: mapConfigPlugins(options),\n })\n\n return { apiClient, workspaceStore }\n } catch (error) {\n el.remove()\n throw error\n }\n})\n","'use client'\n\nimport type { ApiClientModal, ApiClientOptions, RoutePayload } from '@scalar/api-client/modal'\nimport { generateHash } from '@scalar/helpers/string/generate-hash'\nimport { useEffect, useRef, useState } from 'react'\n\nimport './style.css'\n\nimport { isObjectEqual } from '@scalar/helpers/object/is-object-equal'\nimport type { WorkspaceStore } from '@scalar/workspace-store/client'\n\nimport { getOrCreateApiClient } from './lazy-load'\n\nglobalThis.__VUE_OPTIONS_API__ = true\nglobalThis.__VUE_PROD_HYDRATION_MISMATCH_DETAILS__ = true\nglobalThis.__VUE_PROD_DEVTOOLS__ = false\n\nexport type ApiClientConfigurationReact = ApiClientOptions &\n (\n | {\n content?: never\n url: string\n }\n | {\n content: Record<string, unknown>\n url?: never\n }\n )\n\nexport type UseApiClientModalProps = {\n /** Configuration for the Api Client (url or inline content) */\n configuration: ApiClientConfigurationReact\n}\n\n/** Tracks which documents are/have been loaded so we dont duplicate */\nconst documentSet = new Set<string>()\n\nconst getDocumentSlug = (configuration: ApiClientConfigurationReact) => {\n if (configuration.url !== undefined) {\n return configuration.url || 'default'\n }\n return generateHash(JSON.stringify(configuration.content))\n}\n\n/**\n * Returns the singleton Api Client\n *\n * On first call the Vue app is lazily created and appended to document.body where it\n * lives for the lifetime of the page — it is never unmounted, so it survives client-side\n * navigation without losing state.\n *\n * Subsequent calls from any component share the same instance of the client but can use the same\n * or different documents\n */\nexport const useApiClient = ({\n configuration,\n}: UseApiClientModalProps): (Omit<ApiClientModal, 'open'> & { open: (payload: RoutePayload) => void }) | undefined => {\n const [client, setClient] = useState<ApiClientModal | undefined>(undefined)\n const [workspaceStore, setWorkspaceStore] = useState<WorkspaceStore | undefined>(undefined)\n const documentSlugRef = useRef('')\n const previousModalOptionsRef = useRef<ApiClientOptions | undefined>(undefined)\n\n /** Small wrapper to set the documentSlug */\n const open = (payload: RoutePayload) => client?.open({ documentSlug: documentSlugRef.current, ...payload })\n\n useEffect(() => {\n let cancelled = false\n\n // Strip document-specific fields before passing to the modal constructor.\n const { url, content, ...modalOptions } = configuration\n\n const slug = getDocumentSlug(configuration)\n\n void getOrCreateApiClient(modalOptions)?.then((_client) => {\n if (cancelled || !_client) {\n return\n }\n\n // React always provides the complete modal option set for this hook instance,\n // so we overwrite to clear options removed by consumers.\n _client.apiClient.updateOptions(modalOptions, true)\n previousModalOptionsRef.current = modalOptions\n\n setClient(_client.apiClient)\n setWorkspaceStore(_client.workspaceStore)\n documentSlugRef.current = slug\n\n if (slug && !documentSet.has(slug)) {\n documentSet.add(slug)\n if (url !== undefined) {\n void _client.workspaceStore.addDocument({ name: slug, url })\n } else {\n void _client.workspaceStore.addDocument({ name: slug, document: content })\n }\n }\n })\n\n return () => {\n cancelled = true\n }\n\n // Only run once per mount\n }, [])\n\n // Register new document when we detect the url has changed\n useEffect(() => {\n if (!client || !workspaceStore) {\n return\n }\n\n const slug = getDocumentSlug(configuration)\n documentSlugRef.current = slug\n\n if (documentSet.has(slug)) {\n return\n }\n documentSet.add(slug)\n\n if (configuration.url !== undefined) {\n void workspaceStore.addDocument({ name: slug, url: configuration.url })\n } else {\n void workspaceStore.addDocument({ name: slug, document: configuration.content })\n }\n }, [client, configuration.url, configuration.content, workspaceStore])\n\n // Update the modal options when the configuration changes\n useEffect(() => {\n if (!client || !configuration) {\n return\n }\n\n const { url: _url, content: _content, ...modalOptions } = configuration\n if (isObjectEqual(previousModalOptionsRef.current, modalOptions)) {\n return\n }\n\n client.updateOptions(modalOptions, true)\n previousModalOptionsRef.current = modalOptions\n }, [client, configuration])\n\n return client\n ? {\n ...client,\n open,\n }\n : undefined\n}\n"],"mappings":"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"}
|