@djangocfg/ui-tools 2.1.287 → 2.1.290
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/README.md +14 -3
- package/dist/DocsLayout-IKH7BLSU.cjs +3464 -0
- package/dist/DocsLayout-IKH7BLSU.cjs.map +1 -0
- package/dist/DocsLayout-JPXFUKAR.mjs +3457 -0
- package/dist/DocsLayout-JPXFUKAR.mjs.map +1 -0
- package/dist/{PrettyCode.client-5GABIN2I.cjs → PrettyCode.client-RPDIE5CH.cjs} +104 -3
- package/dist/PrettyCode.client-RPDIE5CH.cjs.map +1 -0
- package/dist/{PrettyCode.client-IZTXXYHG.mjs → PrettyCode.client-SPMTQEG4.mjs} +106 -5
- package/dist/PrettyCode.client-SPMTQEG4.mjs.map +1 -0
- package/dist/{chunk-IULI4XII.cjs → chunk-5Q4UMSWB.cjs} +355 -9
- package/dist/chunk-5Q4UMSWB.cjs.map +1 -0
- package/dist/{chunk-VZGQC3NG.mjs → chunk-EFWOJPA6.mjs} +349 -9
- package/dist/chunk-EFWOJPA6.mjs.map +1 -0
- package/dist/index.cjs +10 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +34 -0
- package/dist/index.d.ts +34 -0
- package/dist/index.mjs +5 -5
- package/dist/index.mjs.map +1 -1
- package/package.json +21 -14
- package/src/components/markdown/MarkdownMessage.tsx +46 -0
- package/src/tools/OpenapiViewer/OpenapiViewer.story.tsx +93 -157
- package/src/tools/OpenapiViewer/README.md +114 -6
- package/src/tools/OpenapiViewer/components/DocsLayout/ApiIntroSection.tsx +20 -6
- package/src/tools/OpenapiViewer/components/DocsLayout/DocsView.tsx +331 -53
- package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/CodeSamples/LanguageTabs.tsx +36 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/CodeSamples/index.tsx +56 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/CodeSamples/useCodeSnippet.ts +77 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/Header/MetaActions.tsx +146 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/Header/MethodBadge.tsx +6 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/Header/PathDisplay.tsx +26 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/Header/index.tsx +87 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/Parameters/ParamGroup.tsx +30 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/Parameters/ParamRow.tsx +36 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/Parameters/index.tsx +22 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/RequestBody/index.tsx +33 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/Responses/ResponseBody.tsx +76 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/Responses/ResponseRow.tsx +80 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/Responses/StatusTag.tsx +32 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/Responses/index.tsx +21 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/SchemaFields/FieldRow.tsx +106 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/SchemaFields/buildTree.ts +127 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/SchemaFields/index.tsx +31 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/SchemaFields/types.ts +28 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/Section/SectionHeader.tsx +87 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/Section/defaults.ts +27 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/Section/index.tsx +45 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/context.tsx +56 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/hooks/useSectionHash.ts +63 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/index.tsx +96 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/store/index.ts +133 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/store/selectors.ts +40 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/types.ts +17 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/SchemaCopyMenu.tsx +40 -11
- package/src/tools/OpenapiViewer/components/DocsLayout/Sidebar/BrandHeader.tsx +48 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/Sidebar/CategoryBlock.tsx +33 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/Sidebar/EndpointRow.tsx +73 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/Sidebar/MethodChips.tsx +43 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/Sidebar/SchemaSection.tsx +27 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/Sidebar/SearchInput.tsx +45 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/Sidebar/SidebarBody.tsx +50 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/Sidebar/Toolbar.tsx +64 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/Sidebar/buildVM.ts +126 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/Sidebar/index.tsx +112 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/Sidebar/types.ts +42 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/Sidebar/useDebouncedValue.ts +14 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/SlideInPlayground.tsx +10 -7
- package/src/tools/OpenapiViewer/components/DocsLayout/TryItSheet.tsx +9 -6
- package/src/tools/OpenapiViewer/components/DocsLayout/anchor.ts +19 -2
- package/src/tools/OpenapiViewer/components/DocsLayout/grouping.ts +38 -21
- package/src/tools/OpenapiViewer/components/DocsLayout/index.tsx +168 -50
- package/src/tools/OpenapiViewer/components/shared/ResponsePanel/PrettyView.tsx +55 -0
- package/src/tools/OpenapiViewer/components/shared/ResponsePanel/PreviewView.tsx +115 -0
- package/src/tools/OpenapiViewer/components/shared/ResponsePanel/RawView.tsx +24 -0
- package/src/tools/OpenapiViewer/components/shared/ResponsePanel/StatusBar.tsx +63 -0
- package/src/tools/OpenapiViewer/components/shared/ResponsePanel/ViewTabs.tsx +45 -0
- package/src/tools/OpenapiViewer/components/shared/ResponsePanel/detectContent.ts +97 -0
- package/src/tools/OpenapiViewer/components/shared/ResponsePanel/index.tsx +93 -0
- package/src/tools/OpenapiViewer/components/shared/ResponsePanel/types.ts +26 -0
- package/src/tools/OpenapiViewer/components/shared/ResponsePanel/useResponseView.ts +62 -0
- package/src/tools/OpenapiViewer/hooks/index.ts +3 -1
- package/src/tools/OpenapiViewer/hooks/useDocsUrlSync.ts +119 -0
- package/src/tools/OpenapiViewer/hooks/useOpenApiSchema.ts +164 -74
- package/src/tools/OpenapiViewer/types.ts +46 -1
- package/src/tools/OpenapiViewer/utils/codeSamples.ts +287 -0
- package/src/tools/OpenapiViewer/utils/index.ts +3 -0
- package/src/tools/OpenapiViewer/utils/operationToHar.ts +119 -0
- package/src/tools/OpenapiViewer/utils/sampler.ts +72 -0
- package/src/tools/OpenapiViewer/utils/scrollParent.ts +68 -0
- package/src/tools/PrettyCode/PrettyCode.client.tsx +88 -1
- package/src/tools/PrettyCode/PrettyCode.story.tsx +114 -361
- package/src/tools/PrettyCode/index.tsx +13 -0
- package/src/tools/PrettyCode/lazy.tsx +5 -0
- package/src/tools/PrettyCode/registerPrismLanguages.ts +111 -0
- package/dist/DocsLayout-BCVU6TTX.cjs +0 -2027
- package/dist/DocsLayout-BCVU6TTX.cjs.map +0 -1
- package/dist/DocsLayout-ERETJLLV.mjs +0 -2020
- package/dist/DocsLayout-ERETJLLV.mjs.map +0 -1
- package/dist/PrettyCode.client-5GABIN2I.cjs.map +0 -1
- package/dist/PrettyCode.client-IZTXXYHG.mjs.map +0 -1
- package/dist/chunk-IULI4XII.cjs.map +0 -1
- package/dist/chunk-VZGQC3NG.mjs.map +0 -1
- package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc.tsx +0 -268
- package/src/tools/OpenapiViewer/components/DocsLayout/Sidebar.tsx +0 -211
- package/src/tools/OpenapiViewer/components/shared/ResponsePanel.tsx +0 -127
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@djangocfg/ui-tools",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.290",
|
|
4
4
|
"description": "Heavy React tools with lazy loading - for Electron, Vite, CRA, Next.js apps",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ui-tools",
|
|
@@ -90,9 +90,10 @@
|
|
|
90
90
|
"check": "tsc --noEmit"
|
|
91
91
|
},
|
|
92
92
|
"peerDependencies": {
|
|
93
|
-
"@djangocfg/i18n": "^2.1.
|
|
94
|
-
"@djangocfg/ui-core": "^2.1.
|
|
93
|
+
"@djangocfg/i18n": "^2.1.290",
|
|
94
|
+
"@djangocfg/ui-core": "^2.1.290",
|
|
95
95
|
"consola": "^3.4.2",
|
|
96
|
+
"lodash-es": "^4.18.1",
|
|
96
97
|
"lucide-react": "^0.545.0",
|
|
97
98
|
"react": "^19.1.0",
|
|
98
99
|
"react-dom": "^19.1.0",
|
|
@@ -100,30 +101,34 @@
|
|
|
100
101
|
"zustand": "^5.0.0"
|
|
101
102
|
},
|
|
102
103
|
"dependencies": {
|
|
103
|
-
"@tiptap/core": "^3.20.1",
|
|
104
|
-
"@tiptap/react": "^3.20.1",
|
|
105
|
-
"@tiptap/starter-kit": "^3.20.1",
|
|
106
|
-
"@tiptap/extension-placeholder": "^3.20.1",
|
|
107
|
-
"@tiptap/extension-mention": "^3.20.1",
|
|
108
|
-
"@tiptap/suggestion": "^3.20.1",
|
|
109
|
-
"@tiptap/markdown": "^3.20.1",
|
|
110
|
-
"@tiptap/pm": "^3.20.1",
|
|
111
104
|
"@rjsf/core": "^6.1.2",
|
|
112
105
|
"@rjsf/utils": "^6.1.2",
|
|
113
106
|
"@rjsf/validator-ajv8": "^6.1.2",
|
|
114
107
|
"@rpldy/uploady": "^1.8.5",
|
|
108
|
+
"@tiptap/core": "^3.20.1",
|
|
109
|
+
"@tiptap/extension-mention": "^3.20.1",
|
|
110
|
+
"@tiptap/extension-placeholder": "^3.20.1",
|
|
111
|
+
"@tiptap/markdown": "^3.20.1",
|
|
112
|
+
"@tiptap/pm": "^3.20.1",
|
|
113
|
+
"@tiptap/react": "^3.20.1",
|
|
114
|
+
"@tiptap/starter-kit": "^3.20.1",
|
|
115
|
+
"@tiptap/suggestion": "^3.20.1",
|
|
115
116
|
"@vidstack/react": "next",
|
|
116
117
|
"@wavesurfer/react": "^1.0.12",
|
|
117
118
|
"maplibre-gl": "^4.7.1",
|
|
118
119
|
"media-icons": "next",
|
|
119
120
|
"mermaid": "^11.12.0",
|
|
120
121
|
"monaco-editor": "^0.55.1",
|
|
122
|
+
"openapi-sampler": "^1.7.2",
|
|
121
123
|
"prism-react-renderer": "^2.4.1",
|
|
124
|
+
"prismjs": "^1.30.0",
|
|
122
125
|
"react-json-tree": "^0.20.0",
|
|
123
126
|
"react-lottie-player": "^2.1.0",
|
|
124
127
|
"react-map-gl": "^8.1.0",
|
|
125
128
|
"react-markdown": "10.1.0",
|
|
126
129
|
"react-zoom-pan-pinch": "^3.7.0",
|
|
130
|
+
"rehype-raw": "^7.0.0",
|
|
131
|
+
"rehype-sanitize": "^6.0.0",
|
|
127
132
|
"remark-gfm": "4.0.1",
|
|
128
133
|
"vidstack": "next",
|
|
129
134
|
"wavesurfer.js": "^7.12.1"
|
|
@@ -133,14 +138,16 @@
|
|
|
133
138
|
"@maplibre/maplibre-gl-geocoder": "^1.7.0"
|
|
134
139
|
},
|
|
135
140
|
"devDependencies": {
|
|
136
|
-
"@djangocfg/i18n": "^2.1.
|
|
141
|
+
"@djangocfg/i18n": "^2.1.290",
|
|
137
142
|
"@djangocfg/playground": "workspace:*",
|
|
138
|
-
"@djangocfg/typescript-config": "^2.1.
|
|
139
|
-
"@djangocfg/ui-core": "^2.1.
|
|
143
|
+
"@djangocfg/typescript-config": "^2.1.290",
|
|
144
|
+
"@djangocfg/ui-core": "^2.1.290",
|
|
145
|
+
"@types/lodash-es": "^4.17.12",
|
|
140
146
|
"@types/mapbox__mapbox-gl-draw": "^1.4.8",
|
|
141
147
|
"@types/node": "^24.7.2",
|
|
142
148
|
"@types/react": "^19.1.0",
|
|
143
149
|
"@types/react-dom": "^19.1.0",
|
|
150
|
+
"lodash-es": "^4.18.1",
|
|
144
151
|
"lucide-react": "^0.545.0",
|
|
145
152
|
"react": "^19.1.0",
|
|
146
153
|
"react-dom": "^19.1.0",
|
|
@@ -2,8 +2,37 @@
|
|
|
2
2
|
|
|
3
3
|
import React from 'react';
|
|
4
4
|
import ReactMarkdown from 'react-markdown';
|
|
5
|
+
import rehypeRaw from 'rehype-raw';
|
|
6
|
+
import rehypeSanitize, { defaultSchema } from 'rehype-sanitize';
|
|
5
7
|
import remarkGfm from 'remark-gfm';
|
|
6
8
|
|
|
9
|
+
// Allow-list HTML that OpenAPI descriptions commonly use — we want
|
|
10
|
+
// ``<b>``/``<code>``/``<br>`` to render, not to appear as literal text.
|
|
11
|
+
// Built on top of ``rehype-sanitize``'s default schema so we keep the
|
|
12
|
+
// XSS protection (no ``<script>``, no ``on*`` handlers, no ``javascript:``
|
|
13
|
+
// URLs); we just extend the tag allow-list with safe presentational
|
|
14
|
+
// elements that are in wide use in API docs.
|
|
15
|
+
const HTML_SCHEMA = {
|
|
16
|
+
...defaultSchema,
|
|
17
|
+
tagNames: [
|
|
18
|
+
...(defaultSchema.tagNames ?? []),
|
|
19
|
+
'br',
|
|
20
|
+
'b',
|
|
21
|
+
'i',
|
|
22
|
+
'u',
|
|
23
|
+
's',
|
|
24
|
+
'sub',
|
|
25
|
+
'sup',
|
|
26
|
+
'small',
|
|
27
|
+
'mark',
|
|
28
|
+
'kbd',
|
|
29
|
+
'code',
|
|
30
|
+
'pre',
|
|
31
|
+
'details',
|
|
32
|
+
'summary',
|
|
33
|
+
],
|
|
34
|
+
};
|
|
35
|
+
|
|
7
36
|
import { CopyButton } from '@djangocfg/ui-core/components';
|
|
8
37
|
import { useResolvedTheme } from '@djangocfg/ui-core/hooks';
|
|
9
38
|
|
|
@@ -331,6 +360,16 @@ const hasMarkdownSyntax = (text: string): boolean => {
|
|
|
331
360
|
return true;
|
|
332
361
|
}
|
|
333
362
|
|
|
363
|
+
// Inline HTML tags (``<br>``, ``<b>``, ``<code>``, …) — used widely
|
|
364
|
+
// in OpenAPI descriptions. Without this branch the plain-text fast
|
|
365
|
+
// path would escape them and the user sees literal angle brackets.
|
|
366
|
+
// The regex matches opening, closing, and self-closing tags without
|
|
367
|
+
// being too clever about malformed HTML; it's an affordance test,
|
|
368
|
+
// not a validator.
|
|
369
|
+
if (/<\/?[a-zA-Z][a-zA-Z0-9-]*(\s[^>]*)?\/?>/.test(text)) {
|
|
370
|
+
return true;
|
|
371
|
+
}
|
|
372
|
+
|
|
334
373
|
// Common markdown patterns
|
|
335
374
|
const markdownPatterns = [
|
|
336
375
|
/^#{1,6}\s/m, // Headers
|
|
@@ -549,6 +588,13 @@ export const MarkdownMessage: React.FC<MarkdownMessageProps> = ({
|
|
|
549
588
|
>
|
|
550
589
|
<ReactMarkdown
|
|
551
590
|
remarkPlugins={[remarkGfm]}
|
|
591
|
+
// ``rehype-raw`` parses inline HTML in the source (OpenAPI
|
|
592
|
+
// ``description`` fields often contain ``<br>`` / ``<b>`` /
|
|
593
|
+
// ``<code>``). ``rehype-sanitize`` with our extended schema
|
|
594
|
+
// runs after it so the allowed tags pass through while
|
|
595
|
+
// anything risky (scripts, event handlers, javascript: urls)
|
|
596
|
+
// is stripped.
|
|
597
|
+
rehypePlugins={[rehypeRaw, [rehypeSanitize, HTML_SCHEMA]]}
|
|
552
598
|
components={components}
|
|
553
599
|
>
|
|
554
600
|
{displayContent}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { defineStory, useSelect, useValue } from '@djangocfg/playground';
|
|
1
|
+
import { defineStory, useSelect, useValue, useBoolean } from '@djangocfg/playground';
|
|
2
2
|
import { Playground } from './index';
|
|
3
3
|
import { LazyOpenapiViewer } from './lazy';
|
|
4
4
|
import type { PlaygroundConfig } from './types';
|
|
@@ -11,13 +11,18 @@ export default defineStory({
|
|
|
11
11
|
});
|
|
12
12
|
|
|
13
13
|
// ============================================================================
|
|
14
|
-
// Schema
|
|
14
|
+
// Schema fixtures
|
|
15
15
|
// ============================================================================
|
|
16
16
|
|
|
17
|
+
// Petstore's own ``servers[0].url`` is just ``/api/v3`` (relative),
|
|
18
|
+
// which makes code samples look like they target ``localhost`` when
|
|
19
|
+
// viewed from the playground. Override with the canonical public host
|
|
20
|
+
// so the generated curl/fetch/etc snippets are runnable as-is.
|
|
17
21
|
const PETSTORE_SCHEMA = {
|
|
18
22
|
id: 'petstore',
|
|
19
23
|
name: 'Petstore API',
|
|
20
24
|
url: 'https://petstore3.swagger.io/api/v3/openapi.json',
|
|
25
|
+
baseUrl: 'https://petstore3.swagger.io/api/v3',
|
|
21
26
|
} as const;
|
|
22
27
|
|
|
23
28
|
const HTTPBIN_SCHEMA = {
|
|
@@ -28,15 +33,18 @@ const HTTPBIN_SCHEMA = {
|
|
|
28
33
|
|
|
29
34
|
const MULTI_SCHEMAS = [PETSTORE_SCHEMA, HTTPBIN_SCHEMA] as const;
|
|
30
35
|
|
|
31
|
-
// Simulates a real multi-group setup (like cmdop with 5+ API groups)
|
|
36
|
+
// Simulates a real multi-group setup (like cmdop with 5+ API groups).
|
|
37
|
+
// All clones share the canonical Petstore host so code samples
|
|
38
|
+
// render with a real runnable URL.
|
|
39
|
+
const PETSTORE_BASE = 'https://petstore3.swagger.io/api/v3';
|
|
32
40
|
const MANY_SCHEMAS = [
|
|
33
41
|
PETSTORE_SCHEMA,
|
|
34
42
|
HTTPBIN_SCHEMA,
|
|
35
|
-
{ id: 'machines', name: 'Machines API', url: 'https://petstore3.swagger.io/api/v3/openapi.json' },
|
|
36
|
-
{ id: 'terminal', name: 'Terminal API', url: 'https://petstore3.swagger.io/api/v3/openapi.json' },
|
|
37
|
-
{ id: 'skills', name: 'Skills API', url: 'https://petstore3.swagger.io/api/v3/openapi.json' },
|
|
38
|
-
{ id: 'system', name: 'System API', url: 'https://petstore3.swagger.io/api/v3/openapi.json' },
|
|
39
|
-
{ id: 'site', name: 'Site API', url: 'https://petstore3.swagger.io/api/v3/openapi.json' },
|
|
43
|
+
{ id: 'machines', name: 'Machines API', url: 'https://petstore3.swagger.io/api/v3/openapi.json', baseUrl: PETSTORE_BASE },
|
|
44
|
+
{ id: 'terminal', name: 'Terminal API', url: 'https://petstore3.swagger.io/api/v3/openapi.json', baseUrl: PETSTORE_BASE },
|
|
45
|
+
{ id: 'skills', name: 'Skills API', url: 'https://petstore3.swagger.io/api/v3/openapi.json', baseUrl: PETSTORE_BASE },
|
|
46
|
+
{ id: 'system', name: 'System API', url: 'https://petstore3.swagger.io/api/v3/openapi.json', baseUrl: PETSTORE_BASE },
|
|
47
|
+
{ id: 'site', name: 'Site API', url: 'https://petstore3.swagger.io/api/v3/openapi.json', baseUrl: PETSTORE_BASE },
|
|
40
48
|
] as const;
|
|
41
49
|
|
|
42
50
|
// ============================================================================
|
|
@@ -44,60 +52,34 @@ const MANY_SCHEMAS = [
|
|
|
44
52
|
// ============================================================================
|
|
45
53
|
|
|
46
54
|
/**
|
|
47
|
-
*
|
|
55
|
+
* Default — single-schema mode with the most common configuration knobs
|
|
56
|
+
* exposed as toggles. Replaces the earlier Interactive / SingleSchema /
|
|
57
|
+
* WithBaseUrl / NoDefault / CustomUrl stories, which were all "this
|
|
58
|
+
* component with different props" variations.
|
|
48
59
|
*/
|
|
49
|
-
export const
|
|
50
|
-
const [
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
description: 'Which schema to load first',
|
|
60
|
+
export const Default = () => {
|
|
61
|
+
const [schemaUrl] = useValue('schemaUrl', {
|
|
62
|
+
defaultValue: PETSTORE_SCHEMA.url,
|
|
63
|
+
label: 'Schema URL',
|
|
64
|
+
description: 'Any OpenAPI 3.x JSON endpoint',
|
|
55
65
|
});
|
|
56
66
|
|
|
57
|
-
const config: PlaygroundConfig = {
|
|
58
|
-
schemas: [...MULTI_SCHEMAS],
|
|
59
|
-
defaultSchemaId: defaultSchema,
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
return (
|
|
63
|
-
<div className="min-h-[600px]">
|
|
64
|
-
<Playground config={config} />
|
|
65
|
-
</div>
|
|
66
|
-
);
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* With baseUrl override — forces a specific request host, ignoring
|
|
71
|
-
* `schema.servers[0].url`. Useful when docs are hosted on a different
|
|
72
|
-
* origin than the API, or when the schema has no servers entry.
|
|
73
|
-
*/
|
|
74
|
-
export const WithBaseUrl = () => {
|
|
75
67
|
const [baseUrl] = useValue('baseUrl', {
|
|
76
|
-
defaultValue: '
|
|
77
|
-
label: 'Base URL',
|
|
78
|
-
description: '
|
|
68
|
+
defaultValue: '',
|
|
69
|
+
label: 'Base URL override',
|
|
70
|
+
description: 'Empty = use servers[0].url from the schema',
|
|
79
71
|
});
|
|
80
72
|
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
return (
|
|
88
|
-
<div className="min-h-[600px]">
|
|
89
|
-
<Playground config={config} />
|
|
90
|
-
</div>
|
|
91
|
-
);
|
|
92
|
-
};
|
|
73
|
+
const [autoSelect] = useBoolean('autoSelectDefault', {
|
|
74
|
+
defaultValue: true,
|
|
75
|
+
label: 'Auto-select default schema',
|
|
76
|
+
description: 'When off, tests the "no defaultSchemaId" code path',
|
|
77
|
+
});
|
|
93
78
|
|
|
94
|
-
/**
|
|
95
|
-
* Single schema — no Combobox switcher shown (schemas.length === 1).
|
|
96
|
-
*/
|
|
97
|
-
export const SingleSchema = () => {
|
|
98
79
|
const config: PlaygroundConfig = {
|
|
99
|
-
schemas: [
|
|
100
|
-
defaultSchemaId: '
|
|
80
|
+
schemas: [{ id: 'custom', name: 'Schema', url: schemaUrl }],
|
|
81
|
+
defaultSchemaId: autoSelect ? 'custom' : undefined,
|
|
82
|
+
baseUrl: baseUrl || undefined,
|
|
101
83
|
};
|
|
102
84
|
|
|
103
85
|
return (
|
|
@@ -108,29 +90,20 @@ export const SingleSchema = () => {
|
|
|
108
90
|
};
|
|
109
91
|
|
|
110
92
|
/**
|
|
111
|
-
*
|
|
112
|
-
*
|
|
93
|
+
* MultiSchema — multiple schemas with the Combobox switcher. Count
|
|
94
|
+
* is adjustable to exercise both the short-list layout and the
|
|
95
|
+
* long-list behaviour (cmdop-style setups with 7+ APIs).
|
|
113
96
|
*/
|
|
114
|
-
export const
|
|
115
|
-
const
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
<div className="min-h-[600px]">
|
|
122
|
-
<Playground config={config} />
|
|
123
|
-
</div>
|
|
124
|
-
);
|
|
125
|
-
};
|
|
97
|
+
export const MultiSchema = () => {
|
|
98
|
+
const [count] = useSelect('count', {
|
|
99
|
+
options: ['2', '7'] as const,
|
|
100
|
+
defaultValue: '2',
|
|
101
|
+
label: 'Schema count',
|
|
102
|
+
description: '2 uses Petstore+HTTPBin; 7 stress-tests the Combobox',
|
|
103
|
+
});
|
|
126
104
|
|
|
127
|
-
/**
|
|
128
|
-
* Many schemas (7+) — tests Combobox with a long list.
|
|
129
|
-
* Simulates a real setup like cmdop with machines, terminal, skills, etc.
|
|
130
|
-
*/
|
|
131
|
-
export const ManySchemas = () => {
|
|
132
105
|
const config: PlaygroundConfig = {
|
|
133
|
-
schemas: [...MANY_SCHEMAS],
|
|
106
|
+
schemas: count === '2' ? [...MULTI_SCHEMAS] : [...MANY_SCHEMAS],
|
|
134
107
|
defaultSchemaId: 'petstore',
|
|
135
108
|
};
|
|
136
109
|
|
|
@@ -142,58 +115,23 @@ export const ManySchemas = () => {
|
|
|
142
115
|
};
|
|
143
116
|
|
|
144
117
|
/**
|
|
145
|
-
*
|
|
118
|
+
* SectionsGrouping — alternate layout: every schema's endpoints get
|
|
119
|
+
* rendered on the same page as top-level sections, with a sidebar
|
|
120
|
+
* that stacks them. URL hash sync writes ``#<schemaId>/<anchor>``
|
|
121
|
+
* as the user scrolls so deep-linking keeps working.
|
|
146
122
|
*/
|
|
147
|
-
export const
|
|
148
|
-
const
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
<div className="min-h-[600px]">
|
|
154
|
-
<Playground config={config} />
|
|
155
|
-
</div>
|
|
156
|
-
);
|
|
157
|
-
};
|
|
123
|
+
export const SectionsGrouping = () => {
|
|
124
|
+
const [urlSync] = useBoolean('urlSync', {
|
|
125
|
+
defaultValue: true,
|
|
126
|
+
label: 'URL hash sync',
|
|
127
|
+
description: 'Writes #<schemaId>/<anchor> as you scroll',
|
|
128
|
+
});
|
|
158
129
|
|
|
159
|
-
/**
|
|
160
|
-
* Error state — invalid schema URL that will fail to fetch.
|
|
161
|
-
* Tests error handling and UI feedback.
|
|
162
|
-
*/
|
|
163
|
-
export const ErrorState = () => {
|
|
164
130
|
const config: PlaygroundConfig = {
|
|
165
|
-
schemas: [
|
|
166
|
-
{
|
|
167
|
-
id: 'broken',
|
|
168
|
-
name: 'Broken API',
|
|
169
|
-
url: 'https://httpbin.org/status/404',
|
|
170
|
-
},
|
|
171
|
-
],
|
|
172
|
-
defaultSchemaId: 'broken',
|
|
173
|
-
};
|
|
174
|
-
|
|
175
|
-
return (
|
|
176
|
-
<div className="min-h-[600px]">
|
|
177
|
-
<Playground config={config} />
|
|
178
|
-
</div>
|
|
179
|
-
);
|
|
180
|
-
};
|
|
181
|
-
|
|
182
|
-
/**
|
|
183
|
-
* Mixed valid + broken — one schema works, one fails.
|
|
184
|
-
* Tests switching between working and broken schemas.
|
|
185
|
-
*/
|
|
186
|
-
export const MixedValidBroken = () => {
|
|
187
|
-
const config: PlaygroundConfig = {
|
|
188
|
-
schemas: [
|
|
189
|
-
PETSTORE_SCHEMA,
|
|
190
|
-
{
|
|
191
|
-
id: 'broken',
|
|
192
|
-
name: 'Broken API (404)',
|
|
193
|
-
url: 'https://httpbin.org/status/404',
|
|
194
|
-
},
|
|
195
|
-
],
|
|
131
|
+
schemas: [...MULTI_SCHEMAS],
|
|
196
132
|
defaultSchemaId: 'petstore',
|
|
133
|
+
schemaGrouping: 'sections',
|
|
134
|
+
urlSync,
|
|
197
135
|
};
|
|
198
136
|
|
|
199
137
|
return (
|
|
@@ -204,12 +142,37 @@ export const MixedValidBroken = () => {
|
|
|
204
142
|
};
|
|
205
143
|
|
|
206
144
|
/**
|
|
207
|
-
*
|
|
145
|
+
* Errors — consolidated failure paths. Pick a scenario via the toggle:
|
|
146
|
+
* - ``broken``: single schema that 404s → full-panel error state.
|
|
147
|
+
* - ``mixed``: valid + broken side-by-side → tests switching between.
|
|
148
|
+
* - ``empty``: no schemas configured at all → empty-state UI.
|
|
208
149
|
*/
|
|
209
|
-
export const
|
|
210
|
-
const
|
|
211
|
-
|
|
212
|
-
|
|
150
|
+
export const Errors = () => {
|
|
151
|
+
const [scenario] = useSelect('scenario', {
|
|
152
|
+
options: ['broken', 'mixed', 'empty'] as const,
|
|
153
|
+
defaultValue: 'broken',
|
|
154
|
+
label: 'Failure scenario',
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
const config: PlaygroundConfig = (() => {
|
|
158
|
+
switch (scenario) {
|
|
159
|
+
case 'broken':
|
|
160
|
+
return {
|
|
161
|
+
schemas: [{ id: 'broken', name: 'Broken API', url: 'https://httpbin.org/status/404' }],
|
|
162
|
+
defaultSchemaId: 'broken',
|
|
163
|
+
};
|
|
164
|
+
case 'mixed':
|
|
165
|
+
return {
|
|
166
|
+
schemas: [
|
|
167
|
+
PETSTORE_SCHEMA,
|
|
168
|
+
{ id: 'broken', name: 'Broken API (404)', url: 'https://httpbin.org/status/404' },
|
|
169
|
+
],
|
|
170
|
+
defaultSchemaId: 'petstore',
|
|
171
|
+
};
|
|
172
|
+
case 'empty':
|
|
173
|
+
return { schemas: [] };
|
|
174
|
+
}
|
|
175
|
+
})();
|
|
213
176
|
|
|
214
177
|
return (
|
|
215
178
|
<div className="min-h-[600px]">
|
|
@@ -219,8 +182,9 @@ export const EmptySchemas = () => {
|
|
|
219
182
|
};
|
|
220
183
|
|
|
221
184
|
/**
|
|
222
|
-
*
|
|
223
|
-
*
|
|
185
|
+
* Lazy — production lazy-loaded variant. Shows the loading spinner
|
|
186
|
+
* while the ~400 KB OpenAPI viewer chunk is fetched. Only path you
|
|
187
|
+
* should use in an actual app bundle.
|
|
224
188
|
*/
|
|
225
189
|
export const Lazy = () => {
|
|
226
190
|
const config: PlaygroundConfig = {
|
|
@@ -234,31 +198,3 @@ export const Lazy = () => {
|
|
|
234
198
|
</div>
|
|
235
199
|
);
|
|
236
200
|
};
|
|
237
|
-
|
|
238
|
-
/**
|
|
239
|
-
* Custom schema URL — paste any OpenAPI 3.x schema URL to test.
|
|
240
|
-
*/
|
|
241
|
-
export const CustomUrl = () => {
|
|
242
|
-
const [url] = useValue('schemaUrl', {
|
|
243
|
-
defaultValue: 'https://petstore3.swagger.io/api/v3/openapi.json',
|
|
244
|
-
label: 'Schema URL',
|
|
245
|
-
description: 'Full URL to an OpenAPI 3.x JSON schema',
|
|
246
|
-
});
|
|
247
|
-
|
|
248
|
-
const config: PlaygroundConfig = {
|
|
249
|
-
schemas: [
|
|
250
|
-
{
|
|
251
|
-
id: 'custom',
|
|
252
|
-
name: 'Custom Schema',
|
|
253
|
-
url,
|
|
254
|
-
},
|
|
255
|
-
],
|
|
256
|
-
defaultSchemaId: 'custom',
|
|
257
|
-
};
|
|
258
|
-
|
|
259
|
-
return (
|
|
260
|
-
<div className="min-h-[600px]">
|
|
261
|
-
<Playground config={config} />
|
|
262
|
-
</div>
|
|
263
|
-
);
|
|
264
|
-
};
|
|
@@ -101,6 +101,9 @@ OpenapiViewer/
|
|
|
101
101
|
├── utils/
|
|
102
102
|
│ ├── url.ts # UrlBuilder + path/query/baseUrl helpers
|
|
103
103
|
│ ├── schemaExport.ts # Dereferenced/compact/markdown export for LLMs
|
|
104
|
+
│ ├── sampler.ts # Schema → example value (openapi-sampler wrap)
|
|
105
|
+
│ ├── operationToHar.ts # ApiEndpoint → HAR request shape
|
|
106
|
+
│ ├── codeSamples.ts # HAR → curl / fetch / python / … renderers
|
|
104
107
|
│ ├── formatters.ts # HTTP status / method helpers, JSON validation
|
|
105
108
|
│ ├── versionManager.ts
|
|
106
109
|
│ ├── apiKeyManager.ts
|
|
@@ -110,28 +113,126 @@ OpenapiViewer/
|
|
|
110
113
|
├── index.ts # Re-exports DocsLayout
|
|
111
114
|
├── DocsLayout/ # Default (only) layout
|
|
112
115
|
│ ├── index.tsx # Root: sidebar + docs + slide-in playground
|
|
113
|
-
│ ├── Sidebar.tsx # Grouped endpoint list, scrollspy highlight
|
|
114
116
|
│ ├── DocsView.tsx # Longread scroll container + scrollspy
|
|
115
|
-
│ ├── EndpointDoc.tsx # One endpoint as a prose section + fields table
|
|
116
117
|
│ ├── ApiIntroSection.tsx # Top intro + Copy-for-AI dropdown
|
|
117
118
|
│ ├── SchemaCopyMenu.tsx # Per-schema copy flavours
|
|
118
119
|
│ ├── SlideInPlayground.tsx# Right slide-in overlay
|
|
119
120
|
│ ├── TryItSheet.tsx # Mobile/tablet fallback via ResponsiveSheet
|
|
120
121
|
│ ├── anchor.ts # Stable section anchors for deep-linking
|
|
121
122
|
│ ├── grouping.ts # Shared group+sort used by sidebar and docs
|
|
122
|
-
│ ├── schemaFields.ts # JSON Schema → flat field rows
|
|
123
|
-
│
|
|
123
|
+
│ ├── schemaFields.ts # JSON Schema → flat field rows (legacy helper)
|
|
124
|
+
│ ├── sidebarLabel.ts # Common-prefix strip + tooltip helpers
|
|
125
|
+
│ │
|
|
126
|
+
│ ├── Sidebar/ # Grouped endpoint list + toolbar
|
|
127
|
+
│ │ ├── index.tsx # Orchestrator
|
|
128
|
+
│ │ ├── types.ts # VM types + METHOD_FILTERS
|
|
129
|
+
│ │ ├── buildVM.ts # Pure view-model builders (flat + sections)
|
|
130
|
+
│ │ ├── useDebouncedValue.ts
|
|
131
|
+
│ │ ├── BrandHeader.tsx # Title + version + Copy-for-AI
|
|
132
|
+
│ │ ├── Toolbar.tsx # Schema combobox + search + method chips
|
|
133
|
+
│ │ ├── SearchInput.tsx
|
|
134
|
+
│ │ ├── MethodChips.tsx
|
|
135
|
+
│ │ ├── SidebarBody.tsx # flat vs sections switch
|
|
136
|
+
│ │ ├── SchemaSection.tsx
|
|
137
|
+
│ │ ├── CategoryBlock.tsx
|
|
138
|
+
│ │ └── EndpointRow.tsx
|
|
139
|
+
│ │
|
|
140
|
+
│ └── EndpointDoc/ # One endpoint as a prose card
|
|
141
|
+
│ ├── index.tsx # Orchestrator: header + sections
|
|
142
|
+
│ ├── types.ts # SectionId union
|
|
143
|
+
│ ├── context.tsx # Identity context (endpointId + method)
|
|
144
|
+
│ │
|
|
145
|
+
│ ├── store/ # Zustand — open sections + active code tab
|
|
146
|
+
│ │ ├── index.ts # create() + sessionStorage persist
|
|
147
|
+
│ │ └── selectors.ts
|
|
148
|
+
│ │
|
|
149
|
+
│ ├── hooks/
|
|
150
|
+
│ │ └── useSectionHash.ts # #section=<id>.<sec> deep-link router
|
|
151
|
+
│ │
|
|
152
|
+
│ ├── Header/ # Meta row (badge + actions + Try it) + path
|
|
153
|
+
│ │ ├── index.tsx
|
|
154
|
+
│ │ ├── MetaActions.tsx # Copy link / markdown / expand all
|
|
155
|
+
│ │ ├── MethodBadge.tsx
|
|
156
|
+
│ │ └── PathDisplay.tsx
|
|
157
|
+
│ │
|
|
158
|
+
│ ├── Section/ # Collapsible section wrapper
|
|
159
|
+
│ │ ├── index.tsx
|
|
160
|
+
│ │ ├── SectionHeader.tsx # Chevron + title + badge + anchor
|
|
161
|
+
│ │ └── defaults.ts # Per-method open-by-default rules
|
|
162
|
+
│ │
|
|
163
|
+
│ ├── Parameters/ # Path + Query parameters block
|
|
164
|
+
│ │ ├── index.tsx
|
|
165
|
+
│ │ ├── ParamGroup.tsx
|
|
166
|
+
│ │ └── ParamRow.tsx
|
|
167
|
+
│ │
|
|
168
|
+
│ ├── RequestBody/ # Body preview
|
|
169
|
+
│ │ └── index.tsx
|
|
170
|
+
│ │
|
|
171
|
+
│ ├── SchemaFields/ # Tree-view of JSON Schema properties
|
|
172
|
+
│ │ ├── index.tsx
|
|
173
|
+
│ │ ├── FieldRow.tsx
|
|
174
|
+
│ │ ├── buildTree.ts
|
|
175
|
+
│ │ └── types.ts
|
|
176
|
+
│ │
|
|
177
|
+
│ ├── Responses/ # Status-code rows + example body
|
|
178
|
+
│ │ ├── index.tsx
|
|
179
|
+
│ │ ├── ResponseRow.tsx
|
|
180
|
+
│ │ ├── ResponseBody.tsx
|
|
181
|
+
│ │ └── StatusTag.tsx
|
|
182
|
+
│ │
|
|
183
|
+
│ └── CodeSamples/ # Language tabs + generated snippet
|
|
184
|
+
│ ├── index.tsx
|
|
185
|
+
│ ├── LanguageTabs.tsx
|
|
186
|
+
│ └── useCodeSnippet.ts
|
|
124
187
|
│
|
|
125
188
|
└── shared/ # Panels reused by SlideInPlayground + TryItSheet
|
|
126
189
|
├── RequestPanel.tsx
|
|
127
|
-
├── ResponsePanel.tsx
|
|
128
190
|
├── SendButton.tsx
|
|
129
191
|
├── BodyFormEditor.tsx # Recursive JSON-Schema form renderer
|
|
130
192
|
├── EndpointDraftSync.tsx# Headless draft ↔ context sync
|
|
131
193
|
├── EndpointResetButton.tsx
|
|
132
|
-
|
|
194
|
+
├── ui.tsx # MethodBadge, StatusBadge, Panel, atoms
|
|
195
|
+
│
|
|
196
|
+
└── ResponsePanel/ # Response viewer with Pretty / Raw / Preview tabs
|
|
197
|
+
├── index.tsx # Orchestrator + mode state + guards
|
|
198
|
+
├── types.ts # ViewMode + ContentKind
|
|
199
|
+
├── detectContent.ts # Content-Type → Prism language inference
|
|
200
|
+
├── useResponseView.ts
|
|
201
|
+
├── StatusBar.tsx # Status / size / duration / Copy
|
|
202
|
+
├── ViewTabs.tsx
|
|
203
|
+
├── PrettyView.tsx # JsonTree or syntax-highlighted code
|
|
204
|
+
├── RawView.tsx # Plain <pre>
|
|
205
|
+
└── PreviewView.tsx # Sandboxed iframe for HTML responses
|
|
133
206
|
```
|
|
134
207
|
|
|
208
|
+
## Endpoint doc — sections & deep-linking
|
|
209
|
+
|
|
210
|
+
Each endpoint card splits into four collapsible sections: **Parameters**,
|
|
211
|
+
**Request body**, **Code samples**, **Responses**. Defaults are
|
|
212
|
+
method-aware — GET opens Parameters + Responses, POST/PUT/PATCH opens
|
|
213
|
+
Request body + Responses, etc. User overrides are persisted per
|
|
214
|
+
endpoint in `sessionStorage` (zustand `persist` middleware) so a tab you
|
|
215
|
+
opened once stays open as you scroll.
|
|
216
|
+
|
|
217
|
+
A hover-revealed anchor button on each section header copies a shareable
|
|
218
|
+
URL like `…#section=ep-get-api-v3-pet-findbystatus.responses` —
|
|
219
|
+
following that link lands on the endpoint, expands the referenced
|
|
220
|
+
section, and scrolls it into view.
|
|
221
|
+
|
|
222
|
+
## Response panel — Pretty / Raw / Preview
|
|
223
|
+
|
|
224
|
+
The response panel picks a default view based on `Content-Type`:
|
|
225
|
+
|
|
226
|
+
- **JSON** → `Pretty` (interactive JsonTree)
|
|
227
|
+
- **HTML** → `Preview` (sandboxed iframe, scripts disabled) with `Pretty`
|
|
228
|
+
as the syntax-highlighted source fallback
|
|
229
|
+
- **XML / CSS / JS / text** → `Pretty` using Prism
|
|
230
|
+
- Everything has a **Raw** tab for a literal `<pre>` dump
|
|
231
|
+
|
|
232
|
+
The HTML preview detects single-page-app shells (empty `<body>` + mount
|
|
233
|
+
div + `<script>`) and shows an explanatory empty-state instead of a
|
|
234
|
+
blank iframe, since scripts can't run in the sandbox.
|
|
235
|
+
|
|
135
236
|
## Config Reference
|
|
136
237
|
|
|
137
238
|
```ts
|
|
@@ -145,6 +246,13 @@ interface PlaygroundConfig {
|
|
|
145
246
|
/** Optional API keys for the X-API-Key picker. */
|
|
146
247
|
apiKeys?: ApiKey[];
|
|
147
248
|
apiKeysLoading?: boolean;
|
|
249
|
+
/** Layout mode. ``'selector'`` (default) shows one schema at a time,
|
|
250
|
+
* picked via a Combobox. ``'sections'`` flattens every schema into
|
|
251
|
+
* the longread as top-level sections. */
|
|
252
|
+
schemaGrouping?: 'selector' | 'sections';
|
|
253
|
+
/** Sync the active endpoint anchor to ``window.location.hash`` as
|
|
254
|
+
* the user scrolls (sections mode). Default: off. */
|
|
255
|
+
urlSync?: boolean;
|
|
148
256
|
}
|
|
149
257
|
|
|
150
258
|
interface SchemaSource {
|