@stainless-api/docs 0.1.0-beta.13 → 0.1.0-beta.130
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 +1102 -0
- package/ambient.d.ts +6 -0
- package/eslint-suppressions.json +90 -0
- package/{eslint.config.js → eslint.config.ts} +0 -2
- package/locals.d.ts +17 -0
- package/package.json +62 -44
- package/playground-virtual-modules.d.ts +96 -0
- package/plugin/assets/languages/cli.svg +14 -0
- package/plugin/assets/languages/csharp.svg +1 -0
- package/plugin/assets/languages/php.svg +4 -0
- package/plugin/buildAlgoliaIndex.ts +40 -39
- package/plugin/components/MethodDescription.tsx +54 -0
- package/plugin/components/RequestBuilder/ParamEditor.tsx +55 -0
- package/plugin/components/RequestBuilder/SnippetStainlessIsland.tsx +107 -0
- package/plugin/components/RequestBuilder/index.tsx +40 -0
- package/plugin/components/RequestBuilder/props.ts +9 -0
- package/plugin/components/RequestBuilder/spec-helpers.ts +47 -0
- package/plugin/components/RequestBuilder/styles.css +67 -0
- package/plugin/components/SDKSelect.astro +18 -111
- package/plugin/components/SnippetCode.tsx +112 -70
- package/plugin/components/StainlessIslands.tsx +126 -0
- package/plugin/components/search/SearchAlgolia.astro +46 -29
- package/plugin/components/search/SearchIsland.tsx +61 -37
- package/plugin/generateAPIReferenceLink.ts +0 -40
- package/plugin/globalJs/ai-dropdown-options.ts +248 -0
- package/plugin/globalJs/code-snippets.ts +45 -16
- package/plugin/globalJs/copy.ts +115 -27
- package/plugin/globalJs/create-playground.shim.ts +3 -0
- package/plugin/globalJs/method-descriptions.ts +33 -0
- package/plugin/globalJs/navigation.ts +24 -44
- package/plugin/globalJs/playground-data.shim.ts +1 -0
- package/plugin/globalJs/playground-data.ts +14 -0
- package/plugin/globalJs/summary-selection-tweak.ts +29 -0
- package/plugin/helpers/generateDocsRoutes.ts +59 -0
- package/plugin/helpers/multiSpec.ts +8 -0
- package/plugin/index.ts +317 -141
- package/plugin/languages.ts +8 -2
- package/plugin/loadPluginConfig.ts +284 -109
- package/plugin/markdown/highlighter.ts +100 -0
- package/plugin/markdown/index.ts +39 -0
- package/plugin/middlewareBuilder/stainlessMiddleware.d.ts +3 -1
- package/plugin/react/Routing.tsx +98 -263
- package/plugin/referencePlaceholderUtils.ts +17 -14
- package/plugin/replaceSidebarPlaceholderMiddleware.ts +39 -35
- package/plugin/routes/Docs.astro +72 -111
- package/plugin/routes/DocsStatic.astro +6 -5
- package/plugin/routes/Overview.astro +46 -22
- package/plugin/routes/llms.ts +186 -0
- package/plugin/routes/markdown.ts +13 -12
- package/plugin/{cms → sidebar-utils}/sidebar-builder.ts +84 -69
- package/plugin/specs/FileCache.ts +99 -0
- package/plugin/specs/fetchSpecSSR.ts +27 -0
- package/plugin/specs/generateSpec.ts +112 -0
- package/plugin/specs/index.ts +132 -0
- package/plugin/specs/inputResolver.ts +148 -0
- package/plugin/{cms → specs}/worker.ts +82 -5
- package/plugin/vendor/preview.worker.docs.js +27121 -16890
- package/plugin/vendor/templates/cli.md +1 -0
- package/plugin/vendor/templates/go.md +4 -2
- package/plugin/vendor/templates/java.md +5 -1
- package/plugin/vendor/templates/kotlin.md +5 -1
- package/plugin/vendor/templates/node.md +4 -2
- package/plugin/vendor/templates/python.md +4 -2
- package/plugin/vendor/templates/ruby.md +4 -2
- package/plugin/vendor/templates/terraform.md +1 -1
- package/plugin/vendor/templates/typescript.md +3 -1
- package/resolveSrcFile.ts +10 -0
- package/scripts/vendor_deps.ts +5 -5
- package/shared/conditionalIntegration.ts +28 -0
- package/shared/getProsePages.ts +41 -0
- package/shared/getSharedLogger.ts +15 -0
- package/shared/terminalUtils.ts +3 -0
- package/shared/virtualModule.ts +46 -1
- package/src/content.config.ts +9 -0
- package/stl-docs/aiChatExamples.ts +95 -0
- package/stl-docs/chat/docs-chat-handler.ts +18 -0
- package/stl-docs/chat/hook.ts +215 -0
- package/stl-docs/chat/schemas.ts +70 -0
- package/stl-docs/chat/stainless-handler/index.ts +126 -0
- package/stl-docs/chat/stream-util.ts +16 -0
- package/stl-docs/chat/ui/AiChat.module.css +591 -0
- package/stl-docs/chat/ui/AiChat.tsx +188 -0
- package/stl-docs/chat/ui/Trigger.tsx +154 -0
- package/stl-docs/chat/ui/components/ChatControls.tsx +51 -0
- package/stl-docs/chat/ui/components/ChatEmpty.tsx +42 -0
- package/stl-docs/chat/ui/components/ChatLog.tsx +96 -0
- package/stl-docs/chat/ui/components/ChatMessage.tsx +47 -0
- package/stl-docs/chat/ui/components/CodeBlock.tsx +33 -0
- package/stl-docs/chat/ui/components/MessageFeedback.tsx +109 -0
- package/stl-docs/chat/ui/components/Table.tsx +15 -0
- package/stl-docs/chat/ui/components/ToolCall.tsx +34 -0
- package/stl-docs/chat/ui/components/hljs-github.css +81 -0
- package/stl-docs/chat/ui/scroll-manager.ts +86 -0
- package/stl-docs/chat/ui/types.ts +45 -0
- package/stl-docs/components/AIDropdown.tsx +63 -0
- package/stl-docs/components/AiChatIsland.tsx +16 -0
- package/stl-docs/components/{content-panel/ContentBreadcrumbs.tsx → ContentBreadcrumbs.tsx} +2 -2
- package/stl-docs/components/ContentPanel.astro +9 -0
- package/stl-docs/components/Footer.astro +89 -0
- package/stl-docs/components/Head.astro +20 -0
- package/stl-docs/components/Header.astro +3 -9
- package/stl-docs/components/PageFrame.astro +37 -0
- package/stl-docs/components/PageSidebar.astro +11 -0
- package/stl-docs/components/PageTitle.astro +82 -0
- package/stl-docs/components/StainlessLogo.svg +4 -0
- package/stl-docs/components/ThemeProvider.astro +36 -0
- package/stl-docs/components/ThemeSelect.astro +84 -146
- package/stl-docs/components/TwoColumnContent.astro +2 -0
- package/stl-docs/components/headers/DefaultHeader.astro +6 -8
- package/stl-docs/components/headers/StackedHeader.astro +10 -53
- package/stl-docs/components/icons/chat-gpt.tsx +2 -2
- package/stl-docs/components/icons/cursor.tsx +10 -0
- package/stl-docs/components/icons/gemini.tsx +19 -0
- package/stl-docs/components/icons/markdown.tsx +1 -1
- package/stl-docs/components/index.ts +1 -0
- package/stl-docs/components/mintlify-compat/Accordion.astro +2 -2
- package/stl-docs/components/mintlify-compat/AccordionGroup.astro +0 -4
- package/stl-docs/components/mintlify-compat/Columns.astro +2 -2
- package/stl-docs/components/mintlify-compat/Frame.astro +6 -6
- package/stl-docs/components/mintlify-compat/Tab.astro +2 -2
- package/stl-docs/components/mintlify-compat/callouts/Callout.astro +2 -2
- package/stl-docs/components/mintlify-compat/callouts/Check.astro +0 -4
- package/stl-docs/components/mintlify-compat/callouts/Danger.astro +0 -4
- package/stl-docs/components/mintlify-compat/callouts/Info.astro +0 -4
- package/stl-docs/components/mintlify-compat/callouts/Note.astro +0 -4
- package/stl-docs/components/mintlify-compat/callouts/Tip.astro +0 -4
- package/stl-docs/components/mintlify-compat/callouts/Warning.astro +0 -4
- package/stl-docs/components/mintlify-compat/card.css +4 -4
- package/stl-docs/components/mintlify-compat/index.ts +2 -4
- package/stl-docs/components/nav-tabs/NavDropdown.astro +38 -77
- package/stl-docs/components/nav-tabs/NavTabs.astro +81 -81
- package/stl-docs/components/nav-tabs/SecondaryNavTabs.astro +1 -2
- package/stl-docs/components/nav-tabs/buildNavLinks.ts +5 -2
- package/stl-docs/components/pagination/HomeLink.astro +10 -0
- package/stl-docs/components/pagination/Pagination.astro +177 -0
- package/stl-docs/components/pagination/PaginationLinkEmphasized.astro +22 -0
- package/stl-docs/components/pagination/PaginationLinkQuiet.astro +13 -0
- package/stl-docs/components/pagination/util.ts +71 -0
- package/stl-docs/components/scripts.ts +1 -0
- package/stl-docs/components/sidebars/BaseSidebar.astro +80 -2
- package/stl-docs/components/sidebars/SidebarWithComponents.tsx +10 -0
- package/stl-docs/components/sidebars/convertAstroSidebarToStl.tsx +62 -0
- package/stl-docs/disableCalloutSyntax.ts +36 -0
- package/stl-docs/fonts.ts +186 -0
- package/stl-docs/index.ts +176 -58
- package/stl-docs/loadStlDocsConfig.ts +73 -8
- package/stl-docs/proseDocSync.test.ts +74 -0
- package/stl-docs/proseDocSync.ts +344 -0
- package/stl-docs/proseMarkdown/proseMarkdownIntegration.ts +53 -0
- package/stl-docs/proseMarkdown/proseMarkdownMiddleware.ts +41 -0
- package/stl-docs/proseMarkdown/toMarkdown.ts +158 -0
- package/stl-docs/proseSearchIndexing.ts +218 -0
- package/stl-docs/tabsMiddleware.ts +14 -5
- package/styles/code.css +53 -49
- package/styles/links.css +2 -37
- package/styles/method-descriptions.css +36 -0
- package/styles/overrides.css +28 -46
- package/styles/page.css +228 -38
- package/styles/sdk_select.css +9 -6
- package/styles/search.css +11 -21
- package/styles/sidebar.css +28 -215
- package/styles/{variables.css → sl-variables.css} +4 -8
- package/styles/stldocs-variables.css +6 -0
- package/styles/toc.css +19 -8
- package/theme.css +11 -9
- package/tsconfig.json +1 -4
- package/virtual-module.d.ts +66 -8
- package/components/variables.css +0 -112
- package/plugin/cms/client.ts +0 -62
- package/plugin/cms/server.ts +0 -268
- package/plugin/globalJs/ai-dropdown.ts +0 -57
- package/stl-docs/components/APIReferenceAIDropdown.tsx +0 -58
- package/stl-docs/components/ClientRouterHead.astro +0 -41
- package/stl-docs/components/content-panel/ContentPanel.astro +0 -69
- package/stl-docs/components/content-panel/ProseAIDropdown.tsx +0 -55
- package/stl-docs/components/headers/SplashMobileMenuToggle.astro +0 -49
- package/stl-docs/components/mintlify-compat/Step.astro +0 -56
- package/stl-docs/components/mintlify-compat/Steps.astro +0 -15
- package/styles/fonts.css +0 -68
- /package/{plugin/assets → assets}/fonts/geist/OFL.txt +0 -0
- /package/{plugin/assets → assets}/fonts/geist/geist-italic-latin-ext.woff2 +0 -0
- /package/{plugin/assets → assets}/fonts/geist/geist-italic-latin.woff2 +0 -0
- /package/{plugin/assets → assets}/fonts/geist/geist-latin-ext.woff2 +0 -0
- /package/{plugin/assets → assets}/fonts/geist/geist-latin.woff2 +0 -0
- /package/{plugin/assets → assets}/fonts/geist/geist-mono-italic-latin-ext.woff2 +0 -0
- /package/{plugin/assets → assets}/fonts/geist/geist-mono-italic-latin.woff2 +0 -0
- /package/{plugin/assets → assets}/fonts/geist/geist-mono-latin-ext.woff2 +0 -0
- /package/{plugin/assets → assets}/fonts/geist/geist-mono-latin.woff2 +0 -0
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { useState, useMemo, useEffect, useId, useSyncExternalStore, Activity, Fragment } from 'react';
|
|
2
|
+
import { createPortal } from 'react-dom';
|
|
3
|
+
import { Button } from '@stainless-api/ui-primitives';
|
|
4
|
+
import { PlayIcon, RotateCcw } from 'lucide-react';
|
|
5
|
+
import { SnippetStainlessIslandPropsSchema } from './props';
|
|
6
|
+
import { ParamEditor } from './ParamEditor';
|
|
7
|
+
import './styles.css';
|
|
8
|
+
|
|
9
|
+
function useRequiredChild<T extends Element = Element>(
|
|
10
|
+
parent: Element | null,
|
|
11
|
+
selector: string,
|
|
12
|
+
): React.RefObject<T> {
|
|
13
|
+
const elementRef = useMemo(() => {
|
|
14
|
+
const el = parent?.querySelector<T>(selector);
|
|
15
|
+
return el ? { current: el } : null;
|
|
16
|
+
}, [parent, selector]);
|
|
17
|
+
if (!elementRef) throw new Error(`Required child not found: ${selector}`);
|
|
18
|
+
return elementRef;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function useSetVisibility(elementRef: React.RefObject<HTMLElement>, visible: boolean) {
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
elementRef.current.style.display = visible ? '' : 'none';
|
|
24
|
+
}, [elementRef, visible]);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export default function SnippetStainlessIsland({ parent }: { parent: HTMLElement }) {
|
|
28
|
+
const [expanded, setExpanded] = useState(false);
|
|
29
|
+
|
|
30
|
+
const trigger = useRequiredChild<HTMLButtonElement>(parent, '.try-it-footer .try-it-button');
|
|
31
|
+
const codeContainer = useRequiredChild<HTMLElement>(parent, '.stldocs-snippet-code');
|
|
32
|
+
const exampleContainer = useRequiredChild<HTMLElement>(parent, '.stldocs-snippet-multi-response');
|
|
33
|
+
useSetVisibility(codeContainer, !expanded);
|
|
34
|
+
useSetVisibility(exampleContainer, !expanded);
|
|
35
|
+
useSetVisibility(trigger, !expanded);
|
|
36
|
+
// Attach click handler to trigger
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
if (!trigger.current) return;
|
|
39
|
+
const ac = new AbortController();
|
|
40
|
+
trigger.current.addEventListener('click', () => setExpanded(true), { signal: ac.signal });
|
|
41
|
+
return () => ac.abort();
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
const requestBuilderContainer = useRequiredChild<HTMLElement>(parent, '.request-builder-container');
|
|
45
|
+
const requestBuilderFooter = useRequiredChild<HTMLElement>(parent, '.request-builder-footer');
|
|
46
|
+
const requestBuilderResponse = useRequiredChild<HTMLElement>(parent, '.request-builder-response');
|
|
47
|
+
const requestBuilderProps = useRequiredChild<HTMLTemplateElement>(parent, '.request-builder-props').current;
|
|
48
|
+
const serializedProps = useSyncExternalStore(
|
|
49
|
+
(cb) => {
|
|
50
|
+
const mutationObserver = new MutationObserver(() => cb());
|
|
51
|
+
mutationObserver.observe(requestBuilderProps, { childList: true });
|
|
52
|
+
return () => mutationObserver.disconnect();
|
|
53
|
+
},
|
|
54
|
+
() => requestBuilderProps.content.textContent,
|
|
55
|
+
);
|
|
56
|
+
const deserializedProps = SnippetStainlessIslandPropsSchema.parse(JSON.parse(serializedProps));
|
|
57
|
+
const groupedParams = Map.groupBy(deserializedProps.params, (p) => p.location);
|
|
58
|
+
|
|
59
|
+
const formId = `request-builder-form-${useId()}`;
|
|
60
|
+
|
|
61
|
+
return (
|
|
62
|
+
<>
|
|
63
|
+
{createPortal(
|
|
64
|
+
<Activity mode={expanded ? 'visible' : 'hidden'}>
|
|
65
|
+
<form
|
|
66
|
+
onSubmit={(e) => {
|
|
67
|
+
alert('TODO: Submit button clicked');
|
|
68
|
+
e.preventDefault();
|
|
69
|
+
}}
|
|
70
|
+
id={formId}
|
|
71
|
+
>
|
|
72
|
+
{[...groupedParams.entries()].map(([location, params]) => (
|
|
73
|
+
<Fragment key={location}>
|
|
74
|
+
<h4>{location} parameters</h4>
|
|
75
|
+
{params.map((e) => (
|
|
76
|
+
<ParamEditor param={e} key={e.location + e.key} />
|
|
77
|
+
))}
|
|
78
|
+
</Fragment>
|
|
79
|
+
))}
|
|
80
|
+
</form>
|
|
81
|
+
</Activity>,
|
|
82
|
+
requestBuilderContainer.current,
|
|
83
|
+
)}
|
|
84
|
+
|
|
85
|
+
{createPortal(
|
|
86
|
+
<Activity mode={expanded ? 'visible' : 'hidden'}>
|
|
87
|
+
<Button variant="ghost" border={true} onClick={() => setExpanded(false)}>
|
|
88
|
+
<Button.Icon icon={RotateCcw} />
|
|
89
|
+
</Button>
|
|
90
|
+
|
|
91
|
+
<Button variant="success" className="send-button" type="submit" form={formId}>
|
|
92
|
+
<Button.Label>Send</Button.Label>
|
|
93
|
+
<Button.Icon icon={PlayIcon} />
|
|
94
|
+
</Button>
|
|
95
|
+
</Activity>,
|
|
96
|
+
requestBuilderFooter.current,
|
|
97
|
+
)}
|
|
98
|
+
|
|
99
|
+
{createPortal(
|
|
100
|
+
<Activity mode={expanded ? 'visible' : 'hidden'}>
|
|
101
|
+
<div>{/* TODO */}</div>
|
|
102
|
+
</Activity>,
|
|
103
|
+
requestBuilderResponse.current,
|
|
104
|
+
)}
|
|
105
|
+
</>
|
|
106
|
+
);
|
|
107
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import * as SDKJSON from '@stainless/sdk-json';
|
|
3
|
+
import { useSpec } from '@stainless-api/docs-ui/contexts';
|
|
4
|
+
import { extractParams, Param } from './spec-helpers';
|
|
5
|
+
import type { SnippetStainlessIslandProps } from './props';
|
|
6
|
+
|
|
7
|
+
/** Load and process the spec on the server side to avoid inflating client bundle */
|
|
8
|
+
export function RequestBuilder({
|
|
9
|
+
className,
|
|
10
|
+
children,
|
|
11
|
+
method,
|
|
12
|
+
}: {
|
|
13
|
+
className: string;
|
|
14
|
+
children: ReactNode;
|
|
15
|
+
method: SDKJSON.Method;
|
|
16
|
+
}) {
|
|
17
|
+
let params: Param[];
|
|
18
|
+
const spec = useSpec();
|
|
19
|
+
// https://github.com/Rel1cx/eslint-react/issues/1617
|
|
20
|
+
/* eslint-disable @eslint-react/error-boundaries */
|
|
21
|
+
try {
|
|
22
|
+
if (!spec) throw new Error('Spec is required for RequestBuilder');
|
|
23
|
+
params = spec && extractParams(spec, method);
|
|
24
|
+
} catch (e) {
|
|
25
|
+
console.warn(e);
|
|
26
|
+
return <div className={className}>{children}</div>;
|
|
27
|
+
}
|
|
28
|
+
/* eslint-enable */
|
|
29
|
+
const [httpMethod, path] = method.endpoint.split(' ') as [string, string];
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<stl-island component="SnippetStainlessIsland" className={className}>
|
|
33
|
+
{/* Pass state down to the client component. TODO: we need a better solution for this */}
|
|
34
|
+
<template className="request-builder-props">
|
|
35
|
+
{JSON.stringify({ method: httpMethod, path, params } satisfies SnippetStainlessIslandProps)}
|
|
36
|
+
</template>
|
|
37
|
+
{children}
|
|
38
|
+
</stl-island>
|
|
39
|
+
);
|
|
40
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import z from 'zod';
|
|
2
|
+
import { ParamSchema } from './spec-helpers';
|
|
3
|
+
|
|
4
|
+
export const SnippetStainlessIslandPropsSchema = z.object({
|
|
5
|
+
method: z.string(),
|
|
6
|
+
path: z.string(),
|
|
7
|
+
params: z.array(ParamSchema),
|
|
8
|
+
});
|
|
9
|
+
export type SnippetStainlessIslandProps = z.infer<typeof SnippetStainlessIslandPropsSchema>;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type * as SDKJSON from '@stainless/sdk-json';
|
|
2
|
+
import { printer } from '@stainless-api/docs-ui/markdown';
|
|
3
|
+
import z from 'zod';
|
|
4
|
+
import { getBodyParams } from '@stainless-api/docs-ui/utils';
|
|
5
|
+
|
|
6
|
+
export const ParamSchema = z.object({
|
|
7
|
+
stainlessPath: z.string(),
|
|
8
|
+
location: z.string(),
|
|
9
|
+
key: z.string(),
|
|
10
|
+
type: z.string(),
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
export type Param = z.infer<typeof ParamSchema>;
|
|
14
|
+
|
|
15
|
+
export function extractParams(spec: SDKJSON.Spec | undefined, method: SDKJSON.Method): Param[] {
|
|
16
|
+
const httpDecls = spec?.decls?.http;
|
|
17
|
+
if (!httpDecls) throw new Error('expected http language to be present in SDKJSON');
|
|
18
|
+
const decl = httpDecls?.[method.stainlessPath];
|
|
19
|
+
if (decl?.kind !== 'HttpDeclFunction') {
|
|
20
|
+
throw new Error(
|
|
21
|
+
'expected HttpDeclFunction at stainlessPath "' + method.stainlessPath + '", got ' + decl?.kind,
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
const bodyParams = getBodyParams(decl);
|
|
25
|
+
const params = [
|
|
26
|
+
...Object.entries(decl.paramsChildren ?? {}).map(([location, children]) => ({ location, children })),
|
|
27
|
+
...(bodyParams ? [{ location: 'body', children: bodyParams.params }] : []),
|
|
28
|
+
]
|
|
29
|
+
.filter((e) => e.children.length)
|
|
30
|
+
.flatMap(({ location, children }) =>
|
|
31
|
+
children.map((child) => {
|
|
32
|
+
const resolved = httpDecls[child];
|
|
33
|
+
if (resolved?.kind !== 'HttpDeclProperty') {
|
|
34
|
+
throw new Error(
|
|
35
|
+
'expected HttpDeclProperty at stainlessPath "' + child + '", got ' + resolved?.kind,
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
return {
|
|
39
|
+
stainlessPath: resolved.stainlessPath,
|
|
40
|
+
location,
|
|
41
|
+
key: resolved.key,
|
|
42
|
+
type: (resolved.optional ? 'optional ' : '') + printer.type('http', resolved.type),
|
|
43
|
+
};
|
|
44
|
+
}),
|
|
45
|
+
);
|
|
46
|
+
return params;
|
|
47
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
.request-builder-container form {
|
|
2
|
+
display: grid;
|
|
3
|
+
|
|
4
|
+
/* prettier-ignore */
|
|
5
|
+
grid-template-columns: /*info button*/max-content /*label*/max-content /*colon*/max-content /*input*/1fr;
|
|
6
|
+
font-family: var(--stl-typography-font);
|
|
7
|
+
font-size: var(--stl-typography-text-body-sm);
|
|
8
|
+
color: var(--stl-color-foreground);
|
|
9
|
+
|
|
10
|
+
& > * {
|
|
11
|
+
padding-inline-start: 12px;
|
|
12
|
+
padding-inline-end: 8px;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
& > h4 {
|
|
16
|
+
grid-column: 1 / -1;
|
|
17
|
+
text-transform: capitalize;
|
|
18
|
+
font-size: var(--stl-typography-scale-sm);
|
|
19
|
+
margin-top: 0;
|
|
20
|
+
margin-bottom: 0.25em;
|
|
21
|
+
color: var(--stl-color-foreground-muted);
|
|
22
|
+
padding-top: 0.75rem;
|
|
23
|
+
|
|
24
|
+
&:not(:first-child) {
|
|
25
|
+
border-top: 1px solid var(--stl-color-border);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.request-builder-param {
|
|
30
|
+
grid-column: 1 / -1;
|
|
31
|
+
display: grid;
|
|
32
|
+
grid-template-columns: subgrid;
|
|
33
|
+
align-items: center;
|
|
34
|
+
column-gap: 0.5rem;
|
|
35
|
+
padding-block: 0.35rem;
|
|
36
|
+
|
|
37
|
+
.request-builder-param-info-button {
|
|
38
|
+
color: var(--stl-color-foreground-muted);
|
|
39
|
+
margin-inline: -4px;
|
|
40
|
+
padding: 0;
|
|
41
|
+
}
|
|
42
|
+
.request-builder-param-label {
|
|
43
|
+
font-family: var(--stl-typography-font-mono);
|
|
44
|
+
}
|
|
45
|
+
.request-builder-param-colon {
|
|
46
|
+
font-family: var(--stl-typography-font-mono);
|
|
47
|
+
color: var(--stl-color-foreground-muted);
|
|
48
|
+
}
|
|
49
|
+
/* TODO: new input component that is better stylable */
|
|
50
|
+
.request-builder-param-value {
|
|
51
|
+
input {
|
|
52
|
+
margin: 6px 8px;
|
|
53
|
+
font-size: inherit;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
&:has(+ h4),
|
|
58
|
+
&:last-child {
|
|
59
|
+
padding-bottom: 0.75rem;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.request-builder-footer .stl-ui-button--ghost .stl-ui-button__icon {
|
|
65
|
+
color: var(--stl-color-foreground);
|
|
66
|
+
opacity: var(--stl-opacity-level-040);
|
|
67
|
+
}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
---
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import { cmsClient } from '../cms/client';
|
|
5
|
-
import { BASE_PATH, DEFAULT_LANGUAGE, EXCLUDE_LANGUAGES } from 'virtual:stl-starlight-virtual-module';
|
|
2
|
+
import { parseRoute } from '@stainless-api/docs-ui/routing';
|
|
3
|
+
import { DEFAULT_LANGUAGE } from 'virtual:stl-starlight-virtual-module';
|
|
6
4
|
import { Languages } from '../languages';
|
|
7
5
|
import { SDKSelectReactComponent } from '../react/Routing';
|
|
6
|
+
import { getDocsLanguages } from '../helpers/multiSpec';
|
|
7
|
+
import { API_REFERENCE_BASE_PATH } from 'virtual:stl-docs-virtual-module';
|
|
8
8
|
|
|
9
9
|
const slug = `/${Astro.locals.starlightRoute.id}`;
|
|
10
10
|
|
|
11
|
-
const basePath =
|
|
11
|
+
const basePath = API_REFERENCE_BASE_PATH;
|
|
12
12
|
const defaultLanguage = DEFAULT_LANGUAGE;
|
|
13
13
|
const { language, stainlessPath } = parseRoute(basePath, slug);
|
|
14
14
|
|
|
@@ -19,28 +19,15 @@ const data = {
|
|
|
19
19
|
defaultLanguage,
|
|
20
20
|
};
|
|
21
21
|
|
|
22
|
-
const
|
|
22
|
+
const options = getDocsLanguages().map((value) => ({
|
|
23
|
+
value,
|
|
24
|
+
label: Languages[value].name,
|
|
25
|
+
selected: data.language === value,
|
|
26
|
+
}));
|
|
23
27
|
|
|
24
|
-
|
|
25
|
-
const languages: DocsLanguage[] = spec.docs!.languages ?? ['http'];
|
|
26
|
-
const options = languages
|
|
27
|
-
.filter((language) => language !== 'terraform')
|
|
28
|
-
.filter((language) => !EXCLUDE_LANGUAGES.includes(language))
|
|
29
|
-
.map((value) => ({
|
|
30
|
-
value,
|
|
31
|
-
label: Languages[value].name,
|
|
32
|
-
selected: data.language === value,
|
|
33
|
-
}));
|
|
34
|
-
|
|
35
|
-
const readmeSlug = language === 'http' ? BASE_PATH : `${BASE_PATH}/${language}`;
|
|
28
|
+
const readmeSlug = language === 'http' ? API_REFERENCE_BASE_PATH : `${API_REFERENCE_BASE_PATH}/${language}`;
|
|
36
29
|
---
|
|
37
30
|
|
|
38
|
-
<span
|
|
39
|
-
hidden
|
|
40
|
-
id="stldocs-data"
|
|
41
|
-
data-stldocs-basepath={data.basePath}
|
|
42
|
-
data-stldocs-defaultLanguage={data.defaultLanguage}></span>
|
|
43
|
-
|
|
44
31
|
{
|
|
45
32
|
(data.stainlessPath || slug === readmeSlug) && (
|
|
46
33
|
<div class="stldocs-root stl-sdk-select">
|
|
@@ -53,101 +40,21 @@ const readmeSlug = language === 'http' ? BASE_PATH : `${BASE_PATH}/${language}`;
|
|
|
53
40
|
)
|
|
54
41
|
}
|
|
55
42
|
|
|
56
|
-
<style>
|
|
57
|
-
@layer starlight.core {
|
|
58
|
-
label {
|
|
59
|
-
--sl-label-icon-size: 16px;
|
|
60
|
-
--sl-caret-size: 1.25rem;
|
|
61
|
-
--sl-inline-padding: 0.5rem;
|
|
62
|
-
position: relative;
|
|
63
|
-
display: flex;
|
|
64
|
-
align-items: center;
|
|
65
|
-
gap: 0.25rem;
|
|
66
|
-
color: var(--sl-color-gray-1);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
label:hover {
|
|
70
|
-
color: var(--sl-color-gray-2);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
.icon {
|
|
74
|
-
position: absolute;
|
|
75
|
-
top: 50%;
|
|
76
|
-
transform: translateY(-50%);
|
|
77
|
-
pointer-events: none;
|
|
78
|
-
width: 16px;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
select {
|
|
82
|
-
padding-block: 0.3rem;
|
|
83
|
-
padding-inline: calc(var(--sl-label-icon-size) + var(--sl-inline-padding) + 0.5rem)
|
|
84
|
-
calc(var(--sl-caret-size) + var(--sl-inline-padding) + 0.25rem);
|
|
85
|
-
margin-inline: calc(var(--sl-inline-padding) * -1);
|
|
86
|
-
width: calc(var(--sl-select-width) + var(--sl-inline-padding) * 2);
|
|
87
|
-
text-overflow: ellipsis;
|
|
88
|
-
color: inherit;
|
|
89
|
-
cursor: pointer;
|
|
90
|
-
appearance: none;
|
|
91
|
-
font-weight: 600;
|
|
92
|
-
text-transform: capitalize;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
select:active {
|
|
96
|
-
font-weight: inherit;
|
|
97
|
-
/* font-family: sans-serif;
|
|
98
|
-
font-weight: 400; */
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
option {
|
|
102
|
-
background-color: var(--sl-color-bg-nav);
|
|
103
|
-
color: var(--sl-color-gray-1);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
@media (min-width: 50rem) {
|
|
107
|
-
select {
|
|
108
|
-
font-size: var(--sl-text-sm);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
@layer starlight.components {
|
|
114
|
-
.label-icon {
|
|
115
|
-
font-size: var(--sl-label-icon-size);
|
|
116
|
-
inset-inline-start: 0;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
.caret {
|
|
120
|
-
font-size: var(--sl-caret-size);
|
|
121
|
-
inset-inline-end: 0;
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
.custom-select-wrapper {
|
|
126
|
-
--sl-inline-padding: 0.5rem;
|
|
127
|
-
position: relative;
|
|
128
|
-
display: inline-block;
|
|
129
|
-
/* These match the padding on the sidebar menu */
|
|
130
|
-
padding-left: var(--sl-inline-padding);
|
|
131
|
-
padding-right: var(--sl-inline-padding);
|
|
132
|
-
|
|
133
|
-
.icon.http path {
|
|
134
|
-
fill: var(--sl-color-text);
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
</style>
|
|
138
43
|
<script>
|
|
139
44
|
import { navigate } from 'astro:transitions/client';
|
|
140
45
|
import { updateSelectedLanguage } from '../languages';
|
|
141
|
-
import { initDropdown } from '@stainless-api/docs
|
|
142
|
-
import {
|
|
46
|
+
import { initDropdown } from '@stainless-api/docs/components/scripts';
|
|
47
|
+
import { RESOLVED_API_REFERENCE_PATH } from 'virtual:stl-starlight-virtual-module';
|
|
143
48
|
import { getPageLoadEvent } from '../helpers/getPageLoadEvent';
|
|
144
49
|
|
|
145
50
|
document.addEventListener(getPageLoadEvent(), () => {
|
|
51
|
+
const sdkSelect = document.getElementById('sidebar-sdk-select');
|
|
52
|
+
if (!sdkSelect) return;
|
|
146
53
|
initDropdown({
|
|
147
|
-
|
|
54
|
+
root: sdkSelect,
|
|
148
55
|
onSelect: (value) => {
|
|
149
|
-
const originalLanguage =
|
|
150
|
-
navigate(updateSelectedLanguage(
|
|
56
|
+
const originalLanguage = sdkSelect.dataset.currentValue;
|
|
57
|
+
navigate(updateSelectedLanguage(RESOLVED_API_REFERENCE_PATH, originalLanguage, value));
|
|
151
58
|
},
|
|
152
59
|
});
|
|
153
60
|
});
|
|
@@ -1,14 +1,43 @@
|
|
|
1
|
-
import
|
|
2
|
-
SnippetCodeProps,
|
|
3
|
-
SnippetContainerProps,
|
|
4
|
-
|
|
5
|
-
} from '@stainless-api/docs-ui/
|
|
6
|
-
import { useHighlight, useLanguage } from '@stainless-api/docs-ui/
|
|
7
|
-
import style from '@stainless-api/docs-ui/
|
|
1
|
+
import {
|
|
2
|
+
type SnippetCodeProps,
|
|
3
|
+
type SnippetContainerProps,
|
|
4
|
+
SnippetResponse as DocsUiSnippetResponse,
|
|
5
|
+
} from '@stainless-api/docs-ui/components';
|
|
6
|
+
import { useHighlight, useLanguage } from '@stainless-api/docs-ui/contexts';
|
|
7
|
+
import style from '@stainless-api/docs-ui/style';
|
|
8
8
|
import * as cheerio from 'cheerio/slim';
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
EXPERIMENTAL_COLLAPSIBLE_SNIPPETS,
|
|
11
|
+
EXPERIMENTAL_PLAYGROUNDS,
|
|
12
|
+
EXPERIMENTAL_REQUEST_BUILDER,
|
|
13
|
+
} from 'virtual:stl-starlight-virtual-module';
|
|
10
14
|
import clsx from 'clsx';
|
|
11
15
|
import { Button } from '@stainless-api/ui-primitives';
|
|
16
|
+
import { CopyIcon, PlayIcon } from 'lucide-react';
|
|
17
|
+
import React from 'react';
|
|
18
|
+
import { RequestBuilder } from './RequestBuilder';
|
|
19
|
+
import { Method } from '@stainless/sdk-json';
|
|
20
|
+
|
|
21
|
+
function PlaygroundIcon() {
|
|
22
|
+
return (
|
|
23
|
+
<svg
|
|
24
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
25
|
+
width={16}
|
|
26
|
+
height={16}
|
|
27
|
+
viewBox="0 0 24 24"
|
|
28
|
+
fill="none"
|
|
29
|
+
stroke="currentColor"
|
|
30
|
+
strokeWidth={2}
|
|
31
|
+
strokeLinecap="round"
|
|
32
|
+
strokeLinejoin="round"
|
|
33
|
+
className={'lucide ' + style.Icon}
|
|
34
|
+
aria-hidden="true"
|
|
35
|
+
>
|
|
36
|
+
<path d="m 1,2 h 1 a 4,4 0 0 1 4,4 v 1 m 5,15 H 10 A 4,4 0 0 1 6,18 V 6 a 4,4 0 0 1 4,-4 h 1 M 1,22 H 2 A 4,4 0 0 0 6,18 V 17 M 14.029059,8.147837 A 1.2853426,1.2853426 0 0 1 15.978924,7.0437277 L 22.40178,10.8959 a 1.2853426,1.2853426 0 0 1 0,2.208219 l -6.422856,3.852172 a 1.2853426,1.2853426 0 0 1 -1.949865,-1.105395 z" />
|
|
37
|
+
</svg>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
12
41
|
/*
|
|
13
42
|
* This may be replaced by additional data from the sdk.
|
|
14
43
|
* Without information from the sdk, we use simple heuristics per language.
|
|
@@ -20,7 +49,7 @@ function getCollapsedRanges(content: string, language: string, signature?: strin
|
|
|
20
49
|
const sigIdx = raw.findIndex((l) => l.includes(signature));
|
|
21
50
|
if (sigIdx < 0) return [];
|
|
22
51
|
|
|
23
|
-
let finalIndex
|
|
52
|
+
let finalIndex;
|
|
24
53
|
if (language === 'kotlin' || language === 'java') {
|
|
25
54
|
finalIndex = raw.findIndex((l, i) => i > sigIdx && l.trim() === '}');
|
|
26
55
|
} else if (language === 'python') {
|
|
@@ -54,7 +83,7 @@ function wrapFirstNSpaces($line: cheerio.Cheerio<any>, n: number) {
|
|
|
54
83
|
const m = inner.match(new RegExp(`^( {1,${n}})`));
|
|
55
84
|
if (!m) return;
|
|
56
85
|
|
|
57
|
-
const lead = m[1]
|
|
86
|
+
const lead = m[1]!;
|
|
58
87
|
$firstSpan.html(`<span class="leading-ws">${lead}</span>${inner.slice(lead.length)}`);
|
|
59
88
|
}
|
|
60
89
|
|
|
@@ -111,7 +140,7 @@ function condensedShikiHtmlFull(docHtml: string, language: string, ranges: [numb
|
|
|
111
140
|
out.push('<span class="line ellipsis">…\n</span>');
|
|
112
141
|
didPushEllipsis = true;
|
|
113
142
|
}
|
|
114
|
-
out.push($.html(lineEl)
|
|
143
|
+
out.push($.html(lineEl));
|
|
115
144
|
});
|
|
116
145
|
|
|
117
146
|
$code.html(out.join(''));
|
|
@@ -124,63 +153,40 @@ function useIsCollapsible({ signature }: { signature?: string }): boolean {
|
|
|
124
153
|
return Boolean(EXPERIMENTAL_COLLAPSIBLE_SNIPPETS && signature && language);
|
|
125
154
|
}
|
|
126
155
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
return (
|
|
131
|
-
<div className="stl-snippet-request-container">
|
|
132
|
-
{children}
|
|
133
|
-
{signature && isCollapsible && (
|
|
134
|
-
<Button
|
|
135
|
-
className={'stl-snippet-expand-button'}
|
|
136
|
-
id="stl-snippet-expand-button"
|
|
137
|
-
size="sm"
|
|
138
|
-
variant="outline"
|
|
139
|
-
>
|
|
140
|
-
Show more
|
|
141
|
-
</Button>
|
|
142
|
-
)}
|
|
143
|
-
</div>
|
|
144
|
-
);
|
|
156
|
+
function isActualMethod(value: object): value is Method {
|
|
157
|
+
return 'kind' in value && value.kind === 'http_method';
|
|
145
158
|
}
|
|
146
159
|
|
|
147
|
-
export function SnippetContainer({ children, signature }: SnippetContainerProps) {
|
|
160
|
+
export function SnippetContainer({ children, signature, method }: SnippetContainerProps) {
|
|
148
161
|
const isCollapsible = useIsCollapsible({ signature });
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
)}
|
|
156
|
-
>
|
|
162
|
+
const className = clsx(
|
|
163
|
+
style.Snippet,
|
|
164
|
+
isCollapsible ? 'stl-snippet-collapsible' : 'stl-snippet-non-collapsible',
|
|
165
|
+
);
|
|
166
|
+
return EXPERIMENTAL_REQUEST_BUILDER && isActualMethod(method) ? (
|
|
167
|
+
<RequestBuilder className={className} method={method}>
|
|
157
168
|
{children}
|
|
158
|
-
</
|
|
169
|
+
</RequestBuilder>
|
|
170
|
+
) : (
|
|
171
|
+
<div className={className}>{children}</div>
|
|
159
172
|
);
|
|
160
173
|
}
|
|
161
174
|
|
|
162
|
-
export function
|
|
163
|
-
content
|
|
164
|
-
language
|
|
165
|
-
signature,
|
|
166
|
-
highlighted,
|
|
167
|
-
}: SnippetCodeProps & { signature: string; highlighted: string; language: string }) {
|
|
168
|
-
const ranges = getCollapsedRanges(content, language, signature);
|
|
169
|
-
const html = condensedShikiHtmlFull(highlighted, language, ranges);
|
|
170
|
-
const offset = getCounterOffset(ranges);
|
|
171
|
-
|
|
175
|
+
export function SnippetButtons({ content }: { content: string }) {
|
|
176
|
+
void content;
|
|
177
|
+
const language = useLanguage();
|
|
172
178
|
return (
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
179
|
+
<>
|
|
180
|
+
<Button variant="outline" data-stldocs-snippet-copy>
|
|
181
|
+
<CopyIcon size={16} className={style.Icon} />
|
|
182
|
+
</Button>
|
|
183
|
+
{EXPERIMENTAL_PLAYGROUNDS &&
|
|
184
|
+
(language === 'python' || language === 'typescript' || language === 'http') && (
|
|
185
|
+
<Button data-stldocs-snippet-play variant="muted" border title="Play">
|
|
186
|
+
<PlaygroundIcon />
|
|
187
|
+
</Button>
|
|
188
|
+
)}
|
|
189
|
+
</>
|
|
184
190
|
);
|
|
185
191
|
}
|
|
186
192
|
|
|
@@ -200,16 +206,52 @@ export function SnippetCode({ content, signature, language: forcedLanguage }: Sn
|
|
|
200
206
|
}
|
|
201
207
|
|
|
202
208
|
return (
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
209
|
+
<>
|
|
210
|
+
<div
|
|
211
|
+
className={clsx(style.SnippetCode, isCollapsible && 'stl-snippet-code-is-collapsed')}
|
|
212
|
+
data-snippet-expanded-offset={offset}
|
|
213
|
+
data-stldocs-copy-content
|
|
214
|
+
dangerouslySetInnerHTML={{ __html: highlighted }}
|
|
215
|
+
/>
|
|
216
|
+
{signature && isCollapsible && (
|
|
217
|
+
<Button
|
|
218
|
+
className={'stl-snippet-expand-button'}
|
|
219
|
+
id="stl-snippet-expand-button"
|
|
220
|
+
size="sm"
|
|
221
|
+
variant="outline"
|
|
222
|
+
>
|
|
223
|
+
Show more
|
|
224
|
+
</Button>
|
|
225
|
+
)}
|
|
226
|
+
{EXPERIMENTAL_REQUEST_BUILDER && (
|
|
227
|
+
<div className="request-builder-container" style={{ display: 'contents' }}></div>
|
|
228
|
+
)}
|
|
229
|
+
</>
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
export function SnippetFooter() {
|
|
234
|
+
if (!EXPERIMENTAL_REQUEST_BUILDER) return null;
|
|
235
|
+
return (
|
|
236
|
+
<div className={clsx(style.SnippetFooter, 'try-it-footer')}>
|
|
237
|
+
{EXPERIMENTAL_REQUEST_BUILDER && (
|
|
238
|
+
<div className="request-builder-footer" style={{ display: 'contents' }}></div>
|
|
239
|
+
)}
|
|
240
|
+
<Button variant="accent" className="try-it-button">
|
|
241
|
+
<Button.Label>Try it</Button.Label>
|
|
242
|
+
<Button.Icon icon={PlayIcon} />
|
|
243
|
+
</Button>
|
|
213
244
|
</div>
|
|
214
245
|
);
|
|
215
246
|
}
|
|
247
|
+
|
|
248
|
+
export function SnippetResponse({ ...props }: React.ComponentProps<typeof DocsUiSnippetResponse>) {
|
|
249
|
+
return (
|
|
250
|
+
<>
|
|
251
|
+
<DocsUiSnippetResponse {...props} />
|
|
252
|
+
{EXPERIMENTAL_REQUEST_BUILDER && (
|
|
253
|
+
<div className="request-builder-response" style={{ display: 'contents' }} />
|
|
254
|
+
)}
|
|
255
|
+
</>
|
|
256
|
+
);
|
|
257
|
+
}
|