jamdesk 1.1.90 → 1.1.92
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/package.json +1 -1
- package/vendored/app/api/r2/[project]/[...path]/route.ts +14 -9
- package/vendored/app/layout.tsx +2 -2
- package/vendored/components/HtmlLangSync.tsx +3 -2
- package/vendored/components/mdx/Accordion.tsx +1 -1
- package/vendored/components/mdx/Card.tsx +1 -1
- package/vendored/components/mdx/CodeGroup.tsx +18 -23
- package/vendored/components/mdx/Color.tsx +0 -1
- package/vendored/components/mdx/Icon.tsx +1 -1
- package/vendored/components/mdx/MDXComponents.tsx +92 -66
- package/vendored/components/mdx/OpenApiEndpoint.tsx +0 -1
- package/vendored/components/mdx/ParamField.tsx +0 -1
- package/vendored/components/mdx/RequestExample.tsx +0 -1
- package/vendored/components/mdx/ResponseExample.tsx +0 -1
- package/vendored/components/mdx/Steps.tsx +12 -3
- package/vendored/components/mdx/Table.tsx +8 -2
- package/vendored/components/mdx/Tabs.tsx +1 -1
- package/vendored/components/mdx/Tree.tsx +6 -4
- package/vendored/components/navigation/Header.tsx +7 -5
- package/vendored/components/navigation/LanguageSelector.tsx +37 -10
- package/vendored/components/navigation/TableOfContents.tsx +1 -1
- package/vendored/components/navigation/TabsNav.tsx +17 -5
- package/vendored/components/search/SearchModal.tsx +41 -36
- package/vendored/components/ui/CodePanel.tsx +2 -2
- package/vendored/hooks/useChat.ts +1 -1
- package/vendored/hooks/useShikiHighlight.ts +7 -1
- package/vendored/lib/code-utils.ts +6 -2
- package/vendored/lib/health-checks.ts +2 -2
- package/vendored/lib/language-utils.ts +87 -15
- package/vendored/lib/layout-helpers.tsx +2 -1
- package/vendored/lib/mdx-inline-components.ts +1 -1
- package/vendored/lib/navigation-resolver.ts +0 -69
- package/vendored/lib/normalize-config.ts +1 -1
- package/vendored/lib/openapi/generator.ts +3 -3
- package/vendored/lib/openapi/parser.ts +14 -6
- package/vendored/lib/openapi/validator.ts +2 -2
- package/vendored/lib/openapi-isr.ts +4 -1
- package/vendored/lib/public-paths-resolver.ts +7 -6
- package/vendored/lib/redis.ts +2 -2
- package/vendored/lib/rehype-code-meta.ts +2 -2
- package/vendored/lib/render-doc-page.tsx +2 -2
- package/vendored/lib/seo.ts +22 -7
- package/vendored/lib/shiki-highlighter.ts +1 -1
- package/vendored/lib/snippet-loader-isr.ts +1 -1
- package/vendored/lib/static-artifacts.ts +37 -6
- package/vendored/lib/validate-config.ts +1 -0
- package/vendored/workspace-package-lock.json +10 -10
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jamdesk",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.92",
|
|
4
4
|
"description": "CLI for Jamdesk — build, preview, and deploy documentation sites from MDX. Dev server with hot reload, 50+ components, OpenAPI support, AI search, and Mintlify migration",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"jamdesk",
|
|
@@ -78,20 +78,25 @@ export async function GET(
|
|
|
78
78
|
|
|
79
79
|
if (!stream) {
|
|
80
80
|
const notFoundPage = await getFileFromR2(project, '/404.html');
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
81
|
+
// R2 SDK ReadableStream may not exactly match the DOM ReadableStream<Uint8Array>
|
|
82
|
+
// expected by BodyInit, but it satisfies the underlying contract at runtime.
|
|
83
|
+
return new NextResponse(
|
|
84
|
+
(notFoundPage as ReadableStream<Uint8Array> | null) ?? get404Html(project),
|
|
85
|
+
{
|
|
86
|
+
status: 404,
|
|
87
|
+
headers: {
|
|
88
|
+
'Content-Type': 'text/html; charset=utf-8',
|
|
89
|
+
'Cache-Control': 'no-cache',
|
|
90
|
+
},
|
|
91
|
+
}
|
|
92
|
+
);
|
|
88
93
|
}
|
|
89
94
|
|
|
90
95
|
// Raw MDX source: prevent indexing and embedding
|
|
91
96
|
const isMdx = filePath.endsWith('.mdx');
|
|
92
97
|
const vercelCdnCache = getVercelCdnCacheControl(filePath);
|
|
93
98
|
|
|
94
|
-
return new NextResponse(stream as
|
|
99
|
+
return new NextResponse(stream as ReadableStream<Uint8Array>, {
|
|
95
100
|
status: 200,
|
|
96
101
|
headers: {
|
|
97
102
|
'Content-Type': getContentType(filePath),
|
|
@@ -122,7 +127,7 @@ export async function GET(
|
|
|
122
127
|
const JAMDESK_FAVICON = "data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32' fill='none'><rect x='3' y='7' width='14' height='19' rx='2.5' fill='%23C4B5FD' fill-opacity='0.9'/><rect x='8' y='4' width='14' height='19' rx='2.5' fill='%23A78BFA' fill-opacity='0.85'/><rect x='13' y='9' width='14' height='19' rx='2.5' fill='%238B5CF6' fill-opacity='0.9'/></svg>";
|
|
123
128
|
|
|
124
129
|
// Simple fallback 404 page if project's 404.html doesn't exist
|
|
125
|
-
function get404Html(
|
|
130
|
+
function get404Html(_project: string): string {
|
|
126
131
|
return `<!DOCTYPE html>
|
|
127
132
|
<html>
|
|
128
133
|
<head>
|
package/vendored/app/layout.tsx
CHANGED
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
getHostAtDocs,
|
|
18
18
|
getLanguageFromRequest,
|
|
19
19
|
} from '@/lib/page-isr-helpers';
|
|
20
|
-
import { isRTLLanguage, resolveLanguageWithFallback } from '@/lib/language-utils';
|
|
20
|
+
import { isRTLLanguage, resolveLanguageWithFallback, toHreflang } from '@/lib/language-utils';
|
|
21
21
|
import type { DocsConfig } from '@/lib/docs-types';
|
|
22
22
|
import { buildSiteTitle, getFaviconPath, FALLBACK_METADATA } from '@/lib/seo';
|
|
23
23
|
import { withR2OpsContext, emitR2OpsSummary } from '@/lib/r2-content';
|
|
@@ -114,7 +114,7 @@ async function rootLayoutImpl({
|
|
|
114
114
|
);
|
|
115
115
|
const unlockDir = isRTLLanguage(unlockLang) ? 'rtl' : undefined;
|
|
116
116
|
return (
|
|
117
|
-
<html lang={unlockLang} dir={unlockDir} suppressHydrationWarning>
|
|
117
|
+
<html lang={toHreflang(unlockLang)} dir={unlockDir} suppressHydrationWarning>
|
|
118
118
|
<head>
|
|
119
119
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
120
120
|
<meta name="robots" content="noindex, nofollow" />
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { useEffect } from 'react';
|
|
4
4
|
import { usePathname } from 'next/navigation';
|
|
5
|
-
import { extractLanguageFromPath, isRTLLanguage } from '@/lib/language-utils';
|
|
5
|
+
import { extractLanguageFromPath, isRTLLanguage, toHreflang } from '@/lib/language-utils';
|
|
6
6
|
import type { LanguageCode } from '@/lib/docs-types';
|
|
7
7
|
|
|
8
8
|
interface HtmlLangSyncProps {
|
|
@@ -24,8 +24,9 @@ export function HtmlLangSync({ defaultLanguage }: HtmlLangSyncProps) {
|
|
|
24
24
|
|
|
25
25
|
useEffect(() => {
|
|
26
26
|
const lang = extractLanguageFromPath(pathname || '/') ?? defaultLanguage;
|
|
27
|
+
const htmlLang = toHreflang(lang);
|
|
27
28
|
const html = document.documentElement;
|
|
28
|
-
if (html.lang !==
|
|
29
|
+
if (html.lang !== htmlLang) html.lang = htmlLang;
|
|
29
30
|
|
|
30
31
|
if (isRTLLanguage(lang)) {
|
|
31
32
|
if (html.dir !== 'rtl') html.dir = 'rtl';
|
|
@@ -206,7 +206,7 @@ export const Card = memo(function Card({ title, icon, img, href, children, horiz
|
|
|
206
206
|
role={href ? 'link' : undefined}
|
|
207
207
|
aria-label={href ? (ariaLabel || (title ? `Learn about ${title}` : undefined)) : undefined}
|
|
208
208
|
tabIndex={href ? 0 : undefined}
|
|
209
|
-
onKeyDown={href ? (e) => { if (e.key === 'Enter' || e.key === ' ') handleClick(e as
|
|
209
|
+
onKeyDown={href ? (e) => { if (e.key === 'Enter' || e.key === ' ') handleClick(e as unknown as React.MouseEvent<HTMLDivElement>); } : undefined}
|
|
210
210
|
>
|
|
211
211
|
{cardContent}
|
|
212
212
|
</div>
|
|
@@ -3,12 +3,23 @@
|
|
|
3
3
|
import { ReactNode, Children, isValidElement, memo } from 'react';
|
|
4
4
|
import { CodePanel, CodePanelTab } from '../ui/CodePanel';
|
|
5
5
|
import { formatLanguage } from '@/lib/code-utils';
|
|
6
|
-
import { getLanguageIcon } from '@/lib/language-icons';
|
|
7
6
|
|
|
8
7
|
interface CodeGroupProps {
|
|
9
8
|
children: ReactNode;
|
|
10
9
|
}
|
|
11
10
|
|
|
11
|
+
// Loose shape of `pre`/`code` props from MDX/Shiki — only the fields we read.
|
|
12
|
+
type PreProps = {
|
|
13
|
+
'data-language'?: string;
|
|
14
|
+
children?: ReactNode;
|
|
15
|
+
};
|
|
16
|
+
type CodeProps = {
|
|
17
|
+
className?: string;
|
|
18
|
+
'data-title'?: string;
|
|
19
|
+
'data-meta'?: string;
|
|
20
|
+
meta?: string;
|
|
21
|
+
};
|
|
22
|
+
|
|
12
23
|
/**
|
|
13
24
|
* Extract raw language identifier from a pre element
|
|
14
25
|
* Priority: data-language > className language-*
|
|
@@ -16,7 +27,7 @@ interface CodeGroupProps {
|
|
|
16
27
|
function getRawLanguage(child: ReactNode): string | undefined {
|
|
17
28
|
if (!isValidElement(child)) return undefined;
|
|
18
29
|
|
|
19
|
-
const childProps = child.props as
|
|
30
|
+
const childProps = child.props as PreProps;
|
|
20
31
|
|
|
21
32
|
// Check for data-language on the pre element (added by Shiki transformer)
|
|
22
33
|
const preLanguage = childProps['data-language'];
|
|
@@ -25,7 +36,7 @@ function getRawLanguage(child: ReactNode): string | undefined {
|
|
|
25
36
|
const codeElement = childProps?.children;
|
|
26
37
|
if (!isValidElement(codeElement)) return undefined;
|
|
27
38
|
|
|
28
|
-
const codeProps = codeElement.props as
|
|
39
|
+
const codeProps = codeElement.props as CodeProps;
|
|
29
40
|
|
|
30
41
|
// Fall back to language from className (pre-Shiki format)
|
|
31
42
|
const className = codeProps?.className || '';
|
|
@@ -35,22 +46,6 @@ function getRawLanguage(child: ReactNode): string | undefined {
|
|
|
35
46
|
return undefined;
|
|
36
47
|
}
|
|
37
48
|
|
|
38
|
-
/**
|
|
39
|
-
* Extract custom icon from a pre element's code child
|
|
40
|
-
* Returns data-icon attribute if present
|
|
41
|
-
*/
|
|
42
|
-
function getCustomIcon(child: ReactNode): string | undefined {
|
|
43
|
-
if (!isValidElement(child)) return undefined;
|
|
44
|
-
|
|
45
|
-
const childProps = child.props as any;
|
|
46
|
-
const codeElement = childProps?.children;
|
|
47
|
-
|
|
48
|
-
if (!isValidElement(codeElement)) return undefined;
|
|
49
|
-
|
|
50
|
-
const codeProps = codeElement.props as any;
|
|
51
|
-
return codeProps['data-icon'];
|
|
52
|
-
}
|
|
53
|
-
|
|
54
49
|
/**
|
|
55
50
|
* Extract title from a pre element's code child
|
|
56
51
|
* Returns data-title attribute if present (e.g., title="utils.js")
|
|
@@ -58,12 +53,12 @@ function getCustomIcon(child: ReactNode): string | undefined {
|
|
|
58
53
|
function getTitle(child: ReactNode): string | undefined {
|
|
59
54
|
if (!isValidElement(child)) return undefined;
|
|
60
55
|
|
|
61
|
-
const childProps = child.props as
|
|
56
|
+
const childProps = child.props as PreProps;
|
|
62
57
|
const codeElement = childProps?.children;
|
|
63
58
|
|
|
64
59
|
if (!isValidElement(codeElement)) return undefined;
|
|
65
60
|
|
|
66
|
-
const codeProps = codeElement.props as
|
|
61
|
+
const codeProps = codeElement.props as CodeProps;
|
|
67
62
|
return codeProps['data-title'];
|
|
68
63
|
}
|
|
69
64
|
|
|
@@ -74,7 +69,7 @@ function getTitle(child: ReactNode): string | undefined {
|
|
|
74
69
|
function getTabLabel(child: ReactNode): string {
|
|
75
70
|
if (!isValidElement(child)) return 'Code';
|
|
76
71
|
|
|
77
|
-
const childProps = child.props as
|
|
72
|
+
const childProps = child.props as PreProps;
|
|
78
73
|
|
|
79
74
|
// Check for data-language on the pre element (added by Shiki transformer)
|
|
80
75
|
const preLanguage = childProps['data-language'];
|
|
@@ -85,7 +80,7 @@ function getTabLabel(child: ReactNode): string {
|
|
|
85
80
|
const codeElement = childProps?.children;
|
|
86
81
|
if (!isValidElement(codeElement)) return 'Code';
|
|
87
82
|
|
|
88
|
-
const codeProps = codeElement.props as
|
|
83
|
+
const codeProps = codeElement.props as CodeProps;
|
|
89
84
|
|
|
90
85
|
// Check for title in data-meta or meta props (e.g., "Success Response")
|
|
91
86
|
const metaString = codeProps['data-meta'] || codeProps.meta || '';
|
|
@@ -113,7 +113,6 @@ export function ColorItem({ name, value }: ColorItemProps) {
|
|
|
113
113
|
|
|
114
114
|
const swatchColor = isThemeAware ? 'var(--color-swatch-light)' : value;
|
|
115
115
|
const lightTextOnLight = isThemeAware ? shouldUseLightText(value.light) : shouldUseLightText(value as string);
|
|
116
|
-
const lightTextOnDark = isThemeAware ? shouldUseLightText(value.dark) : lightTextOnLight;
|
|
117
116
|
|
|
118
117
|
if (variant === 'table') {
|
|
119
118
|
return (
|
|
@@ -77,7 +77,7 @@ function getColorStyle(color?: string): { style?: React.CSSProperties; className
|
|
|
77
77
|
* <Icon icon={<svg viewBox="0 0 24 24"><path d="..."/></svg>} />
|
|
78
78
|
*
|
|
79
79
|
*/
|
|
80
|
-
export function Icon({ icon, iconType = 'solid', color, size = 16, className }: IconProps) {
|
|
80
|
+
export function Icon({ icon, iconType: _iconType = 'solid', color, size = 16, className }: IconProps) {
|
|
81
81
|
const { style: colorStyle, className: colorClass } = getColorStyle(color);
|
|
82
82
|
const combinedClassName = `inline-block ${colorClass || ''} ${className || ''}`.trim();
|
|
83
83
|
const sizeStyle = { width: size, height: size };
|
|
@@ -1,4 +1,15 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
isValidElement,
|
|
3
|
+
type AnchorHTMLAttributes,
|
|
4
|
+
type BlockquoteHTMLAttributes,
|
|
5
|
+
type HTMLAttributes,
|
|
6
|
+
type ImgHTMLAttributes,
|
|
7
|
+
type OlHTMLAttributes,
|
|
8
|
+
type ReactNode,
|
|
9
|
+
type TableHTMLAttributes,
|
|
10
|
+
type TdHTMLAttributes,
|
|
11
|
+
type ThHTMLAttributes,
|
|
12
|
+
} from 'react';
|
|
2
13
|
import { Card } from './Card';
|
|
3
14
|
import { Note, Info, Warning, Tip, Check, Danger, Callout } from './Callouts';
|
|
4
15
|
import { Accordion, AccordionGroup } from './Accordion';
|
|
@@ -41,14 +52,20 @@ import { Visibility } from './Visibility';
|
|
|
41
52
|
* 2. language-* class on code element (standard markdown)
|
|
42
53
|
* 3. language-* class on pre element (fallback for edge cases)
|
|
43
54
|
*/
|
|
44
|
-
|
|
55
|
+
type PreLikeProps = {
|
|
56
|
+
'data-language'?: string;
|
|
57
|
+
className?: string;
|
|
58
|
+
};
|
|
59
|
+
type CodeLikeProps = { className?: string };
|
|
60
|
+
|
|
61
|
+
function getCodeLanguage(preProps: PreLikeProps, children: ReactNode): string {
|
|
45
62
|
// Check data-language on pre element (added by Shiki transformer)
|
|
46
63
|
if (preProps['data-language']) {
|
|
47
64
|
return preProps['data-language'];
|
|
48
65
|
}
|
|
49
66
|
// Check code element's className for language-* class
|
|
50
67
|
if (isValidElement(children)) {
|
|
51
|
-
const codeProps = children.props as
|
|
68
|
+
const codeProps = children.props as CodeLikeProps;
|
|
52
69
|
const className = codeProps?.className || '';
|
|
53
70
|
const match = className.match(/language-(\w+)/);
|
|
54
71
|
if (match) return match[1];
|
|
@@ -70,7 +87,7 @@ function extractTextFromChildren(children: ReactNode): string {
|
|
|
70
87
|
if (!children) return '';
|
|
71
88
|
|
|
72
89
|
if (isValidElement(children)) {
|
|
73
|
-
const props = children.props as
|
|
90
|
+
const props = children.props as { children?: ReactNode };
|
|
74
91
|
return extractTextFromChildren(props?.children);
|
|
75
92
|
}
|
|
76
93
|
|
|
@@ -239,9 +256,9 @@ export const MDXComponents = {
|
|
|
239
256
|
// Sized images from preprocess-mdx ( syntax).
|
|
240
257
|
// These are output as <SizedImage> JSX so they go through component mapping
|
|
241
258
|
// (raw <img> JSX in MDX bypasses the components provider).
|
|
242
|
-
SizedImage: ({ src, alt, width, height, className, ...
|
|
259
|
+
SizedImage: ({ src, alt, width, height, className, ..._rest }: Omit<ImgHTMLAttributes<HTMLImageElement>, 'src'> & { src?: string }) => (
|
|
243
260
|
<ZoomableImage
|
|
244
|
-
src={src}
|
|
261
|
+
src={src ?? ''}
|
|
245
262
|
alt={alt || ''}
|
|
246
263
|
width={width}
|
|
247
264
|
height={height}
|
|
@@ -269,11 +286,20 @@ export const MDXComponents = {
|
|
|
269
286
|
noStyle, // Explicitly destructure to prevent React warning about unknown DOM prop
|
|
270
287
|
nostyle, // Also handle lowercase version from HTML parsing
|
|
271
288
|
// Destructure and ignore any other props to prevent them from being passed to DOM
|
|
272
|
-
...
|
|
273
|
-
}:
|
|
289
|
+
..._rest
|
|
290
|
+
}: Omit<ImgHTMLAttributes<HTMLImageElement>, 'src'> & {
|
|
291
|
+
src?: string;
|
|
292
|
+
class?: string;
|
|
293
|
+
'data-no-zoom'?: string | boolean;
|
|
294
|
+
'data-no-style'?: string | boolean;
|
|
295
|
+
noZoom?: string | boolean;
|
|
296
|
+
nozoom?: string | boolean;
|
|
297
|
+
noStyle?: string | boolean;
|
|
298
|
+
nostyle?: string | boolean;
|
|
299
|
+
}) => {
|
|
274
300
|
// Check if this is a video file — render <Video> instead of <ZoomableImage>
|
|
275
301
|
if (isVideoUrl(src)) {
|
|
276
|
-
return <Video src={src} title={alt || undefined} />;
|
|
302
|
+
return <Video src={src ?? ''} title={alt || undefined} />;
|
|
277
303
|
}
|
|
278
304
|
|
|
279
305
|
// Check for data-no-zoom attribute or noZoom prop (handle both camelCase and lowercase)
|
|
@@ -295,7 +321,7 @@ export const MDXComponents = {
|
|
|
295
321
|
|
|
296
322
|
return (
|
|
297
323
|
<ZoomableImage
|
|
298
|
-
src={src}
|
|
324
|
+
src={src ?? ''}
|
|
299
325
|
alt={alt || ''}
|
|
300
326
|
width={width}
|
|
301
327
|
height={height}
|
|
@@ -308,64 +334,64 @@ export const MDXComponents = {
|
|
|
308
334
|
/>
|
|
309
335
|
);
|
|
310
336
|
},
|
|
311
|
-
h1: (props:
|
|
312
|
-
<h1
|
|
313
|
-
className="text-3xl font-bold text-theme-text-primary mt-8 mb-4 tracking-tight"
|
|
314
|
-
{...props}
|
|
337
|
+
h1: (props: HTMLAttributes<HTMLHeadingElement>) => (
|
|
338
|
+
<h1
|
|
339
|
+
className="text-3xl font-bold text-theme-text-primary mt-8 mb-4 tracking-tight"
|
|
340
|
+
{...props}
|
|
315
341
|
/>
|
|
316
342
|
),
|
|
317
|
-
h2: (props:
|
|
318
|
-
<h2
|
|
319
|
-
className="text-2xl font-semibold text-theme-text-primary mt-10 mb-4 tracking-tight scroll-mt-20"
|
|
320
|
-
{...props}
|
|
343
|
+
h2: (props: HTMLAttributes<HTMLHeadingElement>) => (
|
|
344
|
+
<h2
|
|
345
|
+
className="text-2xl font-semibold text-theme-text-primary mt-10 mb-4 tracking-tight scroll-mt-20"
|
|
346
|
+
{...props}
|
|
321
347
|
/>
|
|
322
348
|
),
|
|
323
|
-
h3: (props:
|
|
324
|
-
<h3
|
|
325
|
-
className="text-xl font-semibold text-theme-text-primary mt-8 mb-3 scroll-mt-20"
|
|
326
|
-
{...props}
|
|
349
|
+
h3: (props: HTMLAttributes<HTMLHeadingElement>) => (
|
|
350
|
+
<h3
|
|
351
|
+
className="text-xl font-semibold text-theme-text-primary mt-8 mb-3 scroll-mt-20"
|
|
352
|
+
{...props}
|
|
327
353
|
/>
|
|
328
354
|
),
|
|
329
|
-
h4: (props:
|
|
330
|
-
<h4
|
|
331
|
-
className="text-lg font-semibold text-theme-text-primary mt-6 mb-2 scroll-mt-20"
|
|
332
|
-
{...props}
|
|
355
|
+
h4: (props: HTMLAttributes<HTMLHeadingElement>) => (
|
|
356
|
+
<h4
|
|
357
|
+
className="text-lg font-semibold text-theme-text-primary mt-6 mb-2 scroll-mt-20"
|
|
358
|
+
{...props}
|
|
333
359
|
/>
|
|
334
360
|
),
|
|
335
|
-
p: (props:
|
|
336
|
-
<p
|
|
337
|
-
className="text-theme-text-secondary leading-7 mb-4"
|
|
338
|
-
{...props}
|
|
361
|
+
p: (props: HTMLAttributes<HTMLParagraphElement>) => (
|
|
362
|
+
<p
|
|
363
|
+
className="text-theme-text-secondary leading-7 mb-4"
|
|
364
|
+
{...props}
|
|
339
365
|
/>
|
|
340
366
|
),
|
|
341
|
-
ul: ({ class: htmlClass, className, ...props }:
|
|
342
|
-
<ul
|
|
343
|
-
className={`list-disc list-inside text-theme-text-secondary space-y-2 mb-4 ml-4 ${htmlClass || ''} ${className || ''}`.trim()}
|
|
344
|
-
{...props}
|
|
367
|
+
ul: ({ class: htmlClass, className, ...props }: HTMLAttributes<HTMLUListElement> & { class?: string }) => (
|
|
368
|
+
<ul
|
|
369
|
+
className={`list-disc list-inside text-theme-text-secondary space-y-2 mb-4 ml-4 ${htmlClass || ''} ${className || ''}`.trim()}
|
|
370
|
+
{...props}
|
|
345
371
|
/>
|
|
346
372
|
),
|
|
347
|
-
ol: ({ class: htmlClass, className, ...props }:
|
|
348
|
-
<ol
|
|
349
|
-
className={`list-decimal list-inside text-theme-text-secondary space-y-2 mb-4 ml-4 ${htmlClass || ''} ${className || ''}`.trim()}
|
|
350
|
-
{...props}
|
|
373
|
+
ol: ({ class: htmlClass, className, ...props }: OlHTMLAttributes<HTMLOListElement> & { class?: string }) => (
|
|
374
|
+
<ol
|
|
375
|
+
className={`list-decimal list-inside text-theme-text-secondary space-y-2 mb-4 ml-4 ${htmlClass || ''} ${className || ''}`.trim()}
|
|
376
|
+
{...props}
|
|
351
377
|
/>
|
|
352
378
|
),
|
|
353
|
-
li: (props:
|
|
354
|
-
<li
|
|
355
|
-
className="text-theme-text-secondary marker:text-theme-marker"
|
|
356
|
-
{...props}
|
|
379
|
+
li: (props: HTMLAttributes<HTMLLIElement>) => (
|
|
380
|
+
<li
|
|
381
|
+
className="text-theme-text-secondary marker:text-theme-marker"
|
|
382
|
+
{...props}
|
|
357
383
|
/>
|
|
358
384
|
),
|
|
359
385
|
// NOTE: page.tsx overrides this for hostAtDocs sites to auto-prefix links.
|
|
360
386
|
// If you change styling here, update the override in app/[[...slug]]/page.tsx too.
|
|
361
|
-
a: ({ ariaLabel, ...props }:
|
|
387
|
+
a: ({ ariaLabel, ...props }: AnchorHTMLAttributes<HTMLAnchorElement> & { ariaLabel?: string }) => (
|
|
362
388
|
<a
|
|
363
389
|
className="text-theme-accent hover:text-theme-accent-hover transition-colors"
|
|
364
390
|
aria-label={ariaLabel}
|
|
365
391
|
{...props}
|
|
366
392
|
/>
|
|
367
393
|
),
|
|
368
|
-
blockquote: (props:
|
|
394
|
+
blockquote: (props: BlockquoteHTMLAttributes<HTMLQuoteElement>) => (
|
|
369
395
|
<blockquote
|
|
370
396
|
className="border-l-4 pl-4 text-theme-text-tertiary my-6 not-italic"
|
|
371
397
|
style={{ borderColor: 'var(--color-border)' }}
|
|
@@ -373,7 +399,7 @@ export const MDXComponents = {
|
|
|
373
399
|
/>
|
|
374
400
|
),
|
|
375
401
|
// Custom pre component to wrap code blocks with titles in CodePanel
|
|
376
|
-
pre: ({ children, 'data-title': dataTitle, ...props }:
|
|
402
|
+
pre: ({ children, 'data-title': dataTitle, ...props }: HTMLAttributes<HTMLPreElement> & { 'data-title'?: string }) => {
|
|
377
403
|
const language = getCodeLanguage(props, children);
|
|
378
404
|
|
|
379
405
|
// Check for mermaid diagrams - render with Mermaid component
|
|
@@ -411,41 +437,41 @@ export const MDXComponents = {
|
|
|
411
437
|
);
|
|
412
438
|
},
|
|
413
439
|
// Inline code styling is done via CSS in base.css (.prose :not(pre) > code)
|
|
414
|
-
table: (props:
|
|
440
|
+
table: (props: TableHTMLAttributes<HTMLTableElement>) => (
|
|
415
441
|
<div className="overflow-x-auto my-6">
|
|
416
|
-
<table
|
|
417
|
-
className="w-full text-sm border-collapse"
|
|
418
|
-
{...props}
|
|
442
|
+
<table
|
|
443
|
+
className="w-full text-sm border-collapse"
|
|
444
|
+
{...props}
|
|
419
445
|
/>
|
|
420
446
|
</div>
|
|
421
447
|
),
|
|
422
|
-
th: (props:
|
|
423
|
-
<th
|
|
424
|
-
className="text-left font-semibold text-theme-text-primary p-3 border-b-2 border-theme-border bg-theme-bg-secondary"
|
|
425
|
-
{...props}
|
|
448
|
+
th: (props: ThHTMLAttributes<HTMLTableHeaderCellElement>) => (
|
|
449
|
+
<th
|
|
450
|
+
className="text-left font-semibold text-theme-text-primary p-3 border-b-2 border-theme-border bg-theme-bg-secondary"
|
|
451
|
+
{...props}
|
|
426
452
|
/>
|
|
427
453
|
),
|
|
428
|
-
td: (props:
|
|
429
|
-
<td
|
|
430
|
-
className="p-3 border-b border-theme-border text-theme-text-secondary"
|
|
431
|
-
{...props}
|
|
454
|
+
td: (props: TdHTMLAttributes<HTMLTableDataCellElement>) => (
|
|
455
|
+
<td
|
|
456
|
+
className="p-3 border-b border-theme-border text-theme-text-secondary"
|
|
457
|
+
{...props}
|
|
432
458
|
/>
|
|
433
459
|
),
|
|
434
|
-
hr: (props:
|
|
435
|
-
<hr
|
|
436
|
-
className="border-theme-border my-8"
|
|
437
|
-
{...props}
|
|
460
|
+
hr: (props: HTMLAttributes<HTMLHRElement>) => (
|
|
461
|
+
<hr
|
|
462
|
+
className="border-theme-border my-8"
|
|
463
|
+
{...props}
|
|
438
464
|
/>
|
|
439
465
|
),
|
|
440
466
|
// Generic div handler to convert class to className
|
|
441
|
-
div: ({ class: htmlClass, className, ...props }:
|
|
442
|
-
<div
|
|
443
|
-
className={`${htmlClass || ''} ${className || ''}`.trim() || undefined}
|
|
444
|
-
{...props}
|
|
467
|
+
div: ({ class: htmlClass, className, ...props }: HTMLAttributes<HTMLDivElement> & { class?: string }) => (
|
|
468
|
+
<div
|
|
469
|
+
className={`${htmlClass || ''} ${className || ''}`.trim() || undefined}
|
|
470
|
+
{...props}
|
|
445
471
|
/>
|
|
446
472
|
),
|
|
447
473
|
// Generic span handler to convert class to className
|
|
448
|
-
span: ({ class: htmlClass, className, ...props }:
|
|
474
|
+
span: ({ class: htmlClass, className, ...props }: HTMLAttributes<HTMLSpanElement> & { class?: string }) => (
|
|
449
475
|
<span
|
|
450
476
|
className={`${htmlClass || ''} ${className || ''}`.trim() || undefined}
|
|
451
477
|
{...props}
|
|
@@ -77,7 +77,6 @@ function renderSchemaType(schema: JsonSchema): string {
|
|
|
77
77
|
// Shiki HTML comes from server-side highlighting of trusted code strings;
|
|
78
78
|
// sanitization is unnecessary and would break the syntax-color spans.
|
|
79
79
|
function renderHighlightedHtml(html: string) {
|
|
80
|
-
// eslint-disable-next-line react/no-danger
|
|
81
80
|
return <div dangerouslySetInnerHTML={{ __html: html }} />;
|
|
82
81
|
}
|
|
83
82
|
|
|
@@ -30,7 +30,6 @@ export function ParamField({
|
|
|
30
30
|
}: ParamFieldProps) {
|
|
31
31
|
// Determine the parameter name from the prop
|
|
32
32
|
const paramName = body || header || query || path || '';
|
|
33
|
-
const location = body ? 'body' : header ? 'header' : query ? 'query' : path ? 'path' : '';
|
|
34
33
|
|
|
35
34
|
return (
|
|
36
35
|
<div className="group param-divider py-2.5 first:pt-0 not-prose">
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
import { ReactNode, Children, isValidElement } from 'react';
|
|
4
4
|
import { CodePanel, CodePanelTab } from '../ui/CodePanel';
|
|
5
5
|
import { formatLanguage, getElementProps } from '@/lib/code-utils';
|
|
6
|
-
import { getLanguageIcon } from '@/lib/language-icons';
|
|
7
6
|
|
|
8
7
|
interface RequestExampleProps {
|
|
9
8
|
children: ReactNode;
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
import { ReactNode, Children, isValidElement } from 'react';
|
|
4
4
|
import { CodePanel, CodePanelTab } from '../ui/CodePanel';
|
|
5
5
|
import { getElementProps } from '@/lib/code-utils';
|
|
6
|
-
import { getLanguageIcon } from '@/lib/language-icons';
|
|
7
6
|
|
|
8
7
|
interface ResponseExampleProps {
|
|
9
8
|
children: ReactNode;
|
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
ReactNode,
|
|
5
|
+
Children,
|
|
6
|
+
Fragment,
|
|
7
|
+
cloneElement,
|
|
8
|
+
isValidElement,
|
|
9
|
+
memo,
|
|
10
|
+
type ReactElement,
|
|
11
|
+
} from 'react';
|
|
4
12
|
import { getIconClass } from '@/lib/icon-utils';
|
|
5
13
|
import { useStepSlug } from './StepSlugContext';
|
|
6
14
|
|
|
@@ -56,10 +64,11 @@ export const Steps = memo(function Steps({ children, titleSize = 'p' }: StepsPro
|
|
|
56
64
|
<div className="relative my-8 space-y-0 not-prose">
|
|
57
65
|
{childrenArray.map((child) => {
|
|
58
66
|
if (isStepComponent(child)) {
|
|
59
|
-
const
|
|
67
|
+
const stepEl = child as ReactElement<StepProps>;
|
|
68
|
+
const childProps = stepEl.props;
|
|
60
69
|
const currentStepIndex = stepIndex;
|
|
61
70
|
stepIndex++;
|
|
62
|
-
return cloneElement(
|
|
71
|
+
return cloneElement(stepEl, {
|
|
63
72
|
...childProps,
|
|
64
73
|
stepNumber: childProps.stepNumber ?? currentStepIndex + 1,
|
|
65
74
|
isLast: currentStepIndex === totalSteps - 1,
|
|
@@ -170,7 +170,10 @@ export function Table({
|
|
|
170
170
|
<tbody>
|
|
171
171
|
{sortedBodyRows.map((row, index) => {
|
|
172
172
|
if (isValidElement(row)) {
|
|
173
|
-
return cloneElement(
|
|
173
|
+
return cloneElement(
|
|
174
|
+
row as React.ReactElement<InternalRowProps>,
|
|
175
|
+
{ key: row.key ?? index, _rowIndex: index }
|
|
176
|
+
);
|
|
174
177
|
}
|
|
175
178
|
return row;
|
|
176
179
|
})}
|
|
@@ -223,7 +226,10 @@ export function Row({
|
|
|
223
226
|
<tr className={classes.join(' ')}>
|
|
224
227
|
{Children.map(children, (child, index) => {
|
|
225
228
|
if (isValidElement(child)) {
|
|
226
|
-
return cloneElement(
|
|
229
|
+
return cloneElement(
|
|
230
|
+
child as React.ReactElement<InternalCellProps>,
|
|
231
|
+
{ _isHeaderRow: header, _columnIndex: index }
|
|
232
|
+
);
|
|
227
233
|
}
|
|
228
234
|
return child;
|
|
229
235
|
})}
|
|
@@ -34,7 +34,7 @@ interface TabProps {
|
|
|
34
34
|
* Tab component - represents a single tab panel
|
|
35
35
|
* Must be used inside a Tabs component
|
|
36
36
|
*/
|
|
37
|
-
export const Tab = memo(function Tab({ title, icon, iconType, children }: TabProps) {
|
|
37
|
+
export const Tab = memo(function Tab({ title: _title, icon: _icon, iconType: _iconType, children }: TabProps) {
|
|
38
38
|
// This component is rendered by Tabs, not directly
|
|
39
39
|
// The props are extracted by Tabs to build the tab bar
|
|
40
40
|
return <>{children}</>;
|
|
@@ -10,8 +10,6 @@ import {
|
|
|
10
10
|
useMemo,
|
|
11
11
|
useId,
|
|
12
12
|
ReactNode,
|
|
13
|
-
Children,
|
|
14
|
-
isValidElement,
|
|
15
13
|
} from 'react';
|
|
16
14
|
|
|
17
15
|
// =============================================================================
|
|
@@ -158,7 +156,11 @@ function TreeRoot({ children }: TreeProps) {
|
|
|
158
156
|
|
|
159
157
|
traverse(null);
|
|
160
158
|
return items;
|
|
161
|
-
|
|
159
|
+
// itemsRef.current.size is intentional — refs don't trigger re-renders, but
|
|
160
|
+
// size changes correlate with register/unregister so this is the best
|
|
161
|
+
// available recompute signal without lifting items into state.
|
|
162
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
163
|
+
}, [expandedIds, itemsRef.current.size]);
|
|
162
164
|
|
|
163
165
|
// Initialize expanded state from defaultOpen props
|
|
164
166
|
useEffect(() => {
|
|
@@ -174,7 +176,7 @@ function TreeRoot({ children }: TreeProps) {
|
|
|
174
176
|
}
|
|
175
177
|
setInitialized(true);
|
|
176
178
|
}
|
|
177
|
-
}, [initialized, itemsRef.current.size]);
|
|
179
|
+
}, [initialized, itemsRef.current.size]);
|
|
178
180
|
|
|
179
181
|
// Type-ahead search handler
|
|
180
182
|
const handleTypeAhead = useCallback(
|