rapidoc 11.0.1 → 12.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. package/README.md +171 -54
  2. package/dist/rapidoc-flow-min.js +580 -0
  3. package/dist/rapidoc-flow-min.js.LICENSE.txt +171 -0
  4. package/dist/rapidoc-min.js +645 -202
  5. package/dist/rapidoc-min.js.LICENSE.txt +381 -0
  6. package/package.json +57 -42
  7. package/src/README.md +150 -0
  8. package/src/components/README.md +91 -0
  9. package/src/components/api-request.ts +912 -0
  10. package/src/components/api-response.ts +514 -0
  11. package/src/components/json-tree.ts +171 -0
  12. package/src/components/schema-base-element.ts +329 -0
  13. package/src/components/schema-table.ts +475 -0
  14. package/src/components/schema-tree.ts +393 -0
  15. package/src/components/tag-input.ts +180 -0
  16. package/src/flow.js +3 -0
  17. package/src/index.js +6 -0
  18. package/src/oauth-receiver.ts +29 -0
  19. package/src/rapi-flow.ts +1178 -0
  20. package/src/rapidoc-mini.ts +603 -0
  21. package/src/rapidoc.ts +1854 -0
  22. package/src/styles/README.md +96 -0
  23. package/src/styles/auth-styles.js +318 -0
  24. package/src/styles/border-styles.js +24 -0
  25. package/src/styles/css-bundle.js +129 -0
  26. package/src/styles/custom-styles.js +8 -0
  27. package/src/styles/dialog-box-styles.js +102 -0
  28. package/src/styles/endpoint-styles.js +564 -0
  29. package/src/styles/flex-styles.js +16 -0
  30. package/src/styles/flow-styles.js +248 -0
  31. package/src/styles/font-styles.js +432 -0
  32. package/src/styles/info-styles.js +36 -0
  33. package/src/styles/input-styles.js +555 -0
  34. package/src/styles/layout-styles.js +396 -0
  35. package/src/styles/microlighter-styles.js +99 -0
  36. package/src/styles/nav-styles.js +633 -0
  37. package/src/styles/param-list-styles.js +261 -0
  38. package/src/styles/schema-styles.js +296 -0
  39. package/src/styles/tab-styles.js +106 -0
  40. package/src/styles/theme-tokens.js +582 -0
  41. package/src/templates/README.md +89 -0
  42. package/src/templates/advanced-search-dialog-template.js +94 -0
  43. package/src/templates/api-response-template.js +223 -0
  44. package/src/templates/callback-template.js +86 -0
  45. package/src/templates/code-samples-template.js +52 -0
  46. package/src/templates/components-template.js +86 -0
  47. package/src/templates/downloads-template.js +70 -0
  48. package/src/templates/endpoint-template.js +377 -0
  49. package/src/templates/expanded-endpoint-template.js +270 -0
  50. package/src/templates/focused-endpoint-template.js +146 -0
  51. package/src/templates/header-template.js +92 -0
  52. package/src/templates/logo-template.js +21 -0
  53. package/src/templates/main-body-template.js +102 -0
  54. package/src/templates/navbar-template.js +498 -0
  55. package/src/templates/overview-template.js +104 -0
  56. package/src/templates/request-body-template.js +673 -0
  57. package/src/templates/request-params-template.js +485 -0
  58. package/src/templates/security-scheme-template.js +1272 -0
  59. package/src/templates/server-template.js +153 -0
  60. package/src/utils/README.md +146 -0
  61. package/src/utils/arazzo/README.md +119 -0
  62. package/src/utils/arazzo/components.js +15 -0
  63. package/src/utils/arazzo/graph.js +269 -0
  64. package/src/utils/arazzo/index.js +52 -0
  65. package/src/utils/arazzo/operations.js +106 -0
  66. package/src/utils/arazzo/parse.js +196 -0
  67. package/src/utils/arazzo/refs.js +40 -0
  68. package/src/utils/arazzo/svg.js +707 -0
  69. package/src/utils/auto-color-scheme.js +99 -0
  70. package/src/utils/bind-navbar.js +175 -0
  71. package/src/utils/color-utils.js +59 -0
  72. package/src/utils/common-utils.js +191 -0
  73. package/src/utils/curl-utils.js +126 -0
  74. package/src/utils/highlighter.js +419 -0
  75. package/src/utils/markdown-utils.js +110 -0
  76. package/src/utils/mcp/README.md +155 -0
  77. package/src/utils/mcp/common.js +166 -0
  78. package/src/utils/mcp/manifest.js +382 -0
  79. package/src/utils/mcp/project/server.ts +53 -0
  80. package/src/utils/mcp/project.js +88 -0
  81. package/src/utils/mcp/runtime.js +289 -0
  82. package/src/utils/mcp/schema.js +98 -0
  83. package/src/utils/mcp/workflow-runtime.js +374 -0
  84. package/src/utils/mcp/workflows.js +240 -0
  85. package/src/utils/mcp/zip.js +102 -0
  86. package/src/utils/mcp-generator.js +47 -0
  87. package/src/utils/mock-interceptor.js +557 -0
  88. package/src/utils/oauth-utils.js +87 -0
  89. package/src/utils/request-utils.js +264 -0
  90. package/src/utils/response-utils.js +203 -0
  91. package/src/utils/sanitize.js +57 -0
  92. package/src/utils/schema-utils.js +1954 -0
  93. package/src/utils/slugger.js +187 -0
  94. package/src/utils/spec-parser.js +941 -0
  95. package/src/utils/url-utils.js +246 -0
  96. package/src/utils/xml-utils.js +61 -0
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Renders the modal search dialog for full-text search across paths, operation summaries, descriptions, and tags.
3
+ */
4
+ import { html } from "lit";
5
+ export default function advancedSearchDialogTemplate() {
6
+ return html`<dialog id="advanced-search-dialog" class="dialog-box">
7
+ <header class="dialog-box-header">
8
+ <span class="dialog-box-title">Search</span>
9
+ <button type="button" @click="${(e) => this.onAdvancedSearchClose(e)}">&times;</button>
10
+ </header>
11
+ <div class="dialog-box-content">
12
+ <div class="advanced-search-options">
13
+ <input
14
+ id="input-advanced-search-dialog"
15
+ style="width:100%; padding-right:20px;"
16
+ type="text"
17
+ part="textbox textbox-search-dialog"
18
+ placeholder="search text..."
19
+ spellcheck="false"
20
+ @keyup="${(e) => this.onAdvancedSearch(e, 400)}"
21
+ />
22
+ <div class="search-options-row">
23
+ <label class="search-option-label" for="search-api-path">
24
+ <input
25
+ type="checkbox"
26
+ part="checkbox checkbox-search-dialog"
27
+ id="search-api-path"
28
+ checked
29
+ @change="${(e) => this.onAdvancedSearch(e, 0)}"
30
+ />
31
+ API Path
32
+ </label>
33
+ <label class="search-option-label" for="search-api-descr">
34
+ <input
35
+ type="checkbox"
36
+ part="checkbox checkbox-search-dialog"
37
+ id="search-api-descr"
38
+ checked
39
+ @change="${(e) => this.onAdvancedSearch(e, 0)}"
40
+ />
41
+ API Description
42
+ </label>
43
+ <label class="search-option-label" for="search-api-params">
44
+ <input
45
+ type="checkbox"
46
+ part="checkbox checkbox-search-dialog"
47
+ id="search-api-params"
48
+ @change="${(e) => this.onAdvancedSearch(e, 0)}"
49
+ />
50
+ API Parameters
51
+ </label>
52
+ <label class="search-option-label" for="search-api-request-body">
53
+ <input
54
+ type="checkbox"
55
+ part="checkbox checkbox-search-dialog"
56
+ id="search-api-request-body"
57
+ @change="${(e) => this.onAdvancedSearch(e, 0)}"
58
+ />
59
+ Request Body Parameters
60
+ </label>
61
+ <label class="search-option-label" for="search-api-resp-descr">
62
+ <input
63
+ type="checkbox"
64
+ part="checkbox checkbox-search-dialog"
65
+ id="search-api-resp-descr"
66
+ @change="${(e) => this.onAdvancedSearch(e, 0)}"
67
+ />
68
+ Response Description
69
+ </label>
70
+ </div>
71
+ </div>
72
+ ${this.advancedSearchMatches?.map(
73
+ (path) => html`
74
+ <div
75
+ class="mono-font small-font-size hover-bg search-match-row"
76
+ style="${path.deprecated ? "filter:opacity(0.5);" : ""}"
77
+ data-content-id="${path.elementId}"
78
+ tabindex="0"
79
+ @click="${(e) => {
80
+ this.searchVal = ""; // clear quick filter if applied
81
+ this.shadowRoot.getElementById("advanced-search-dialog").close();
82
+ this.requestUpdate();
83
+ this.scrollToEventTarget(e, true);
84
+ }}"
85
+ >
86
+ <span class="upper bold-text method-fg ${path.method}">${path.method}</span>
87
+ <span>${path.path}</span>
88
+ <span class="regular-font gray-text">${path.summary}</span>
89
+ </div>
90
+ `,
91
+ )}
92
+ </div>
93
+ </dialog>`;
94
+ }
@@ -0,0 +1,223 @@
1
+ /**
2
+ * Renders the interactive API response panel (status, headers, body, blob actions),
3
+ * live cURL preview/copy, and the execute/Try action controls for <api-request>.
4
+ */
5
+ import { html } from "lit";
6
+ import { ifDefined } from "lit/directives/if-defined.js";
7
+ import { copyToClipboard, downloadResource, viewResource } from "~/utils/common-utils";
8
+
9
+ export function curlSyntaxTemplate(display = "flex") {
10
+ return html`
11
+ <div class="col m-markdown" style="flex:1; display:${display}; position:relative; max-width: 100%;">
12
+ <button
13
+ class="btn btn-sm btn-outline toolbar-btn"
14
+ style="position:absolute; top:12px; right:8px"
15
+ @click="${(e) => {
16
+ copyToClipboard(this.curlSyntax.trim().replace(/\\$/, ""), e);
17
+ }}"
18
+ part="btn btn-outline btn-copy"
19
+ >
20
+ Copy
21
+ </button>
22
+ <pre style="white-space:pre"><code class="language-shell">${this.curlSyntax.trim().replace(/\\$/, "")}</code></pre>
23
+ </div>
24
+ `;
25
+ }
26
+
27
+ export function apiResponseTabTemplate() {
28
+ let responseFormat = "";
29
+ let responseContent = "";
30
+ if (!this.responseIsBlob) {
31
+ if (
32
+ this.responseHeaders.includes("application/x-ndjson") ||
33
+ this.responseHeaders.includes("json")
34
+ ) {
35
+ responseFormat = "json";
36
+ } else if (this.responseHeaders.includes("html") || this.responseHeaders.includes("xml")) {
37
+ responseFormat = "html";
38
+ } else {
39
+ responseFormat = "text";
40
+ }
41
+ responseContent = html`<code class="language-${responseFormat}">${this.responseText}</code>`;
42
+ }
43
+ return html` <div class="row" style="font-size:var(--font-size-small); margin:5px 0; justify-content:space-between; align-items:center;">
44
+ <div class="response-message ${this.responseStatus}">Response Status: ${this.responseMessage}</div>
45
+ <button class="btn btn-outline" part="btn btn-outline btn-clear-response" @click="${this.clearResponseData}">CLEAR RESPONSE</button>
46
+ </div>
47
+ <div part="tab-panel" class="tab-panel col">
48
+ <div
49
+ id="tab_buttons"
50
+ part="tab-btn-row"
51
+ class="tab-buttons row"
52
+ @click="${(e) => {
53
+ if (
54
+ e.target.classList.contains("tab-btn") === false &&
55
+ e.target.classList.contains("tab") === false
56
+ ) {
57
+ return;
58
+ }
59
+ this.activeResponseTab = e.target.dataset.tab;
60
+ }}"
61
+ >
62
+ <button part="tab-btn" class="tab-btn ${this.activeResponseTab === "response" ? "active" : ""}" data-tab="response">
63
+ RESPONSE
64
+ </button>
65
+ <button part="tab-btn" class="tab-btn ${this.activeResponseTab === "headers" ? "active" : ""}" data-tab="headers">
66
+ RESPONSE HEADERS
67
+ </button>
68
+ ${
69
+ this.showCurlBeforeTry === "true"
70
+ ? ""
71
+ : html`<button part="tab-btn" class="tab-btn ${this.activeResponseTab === "curl" ? "active" : ""}" data-tab="curl">
72
+ CURL
73
+ </button>`
74
+ }
75
+ </div>
76
+ ${
77
+ this.responseIsBlob
78
+ ? html`<div
79
+ part="tab-content"
80
+ class="tab-content col"
81
+ style="flex:1; display:${this.activeResponseTab === "response" ? "flex" : "none"};"
82
+ >
83
+ ${
84
+ this.responseBlobType === "image"
85
+ ? html`<img style="max-height:var(--resp-area-height); object-fit:contain;" class="mar-top-8" src="${ifDefined(this.responseBlobUrl)}"></img>`
86
+ : ""
87
+ }
88
+ <button
89
+ class="btn btn-outline mar-top-8"
90
+ style="width:135px"
91
+ @click="${() => {
92
+ downloadResource(this.responseBlobUrl, this.respContentDisposition);
93
+ }}"
94
+ part="btn btn-outline"
95
+ >
96
+ DOWNLOAD
97
+ </button>
98
+ ${
99
+ this.responseBlobType === "view" || this.responseBlobType === "image"
100
+ ? html`<button
101
+ class="btn btn-outline mar-top-8"
102
+ style="width:135px"
103
+ @click="${() => {
104
+ viewResource(this.responseBlobUrl);
105
+ }}"
106
+ part="btn btn-outline"
107
+ >
108
+ VIEW (NEW TAB)
109
+ </button>`
110
+ : ""
111
+ }
112
+ </div>`
113
+ : html`<div
114
+ part="tab-content"
115
+ class="tab-content col m-markdown"
116
+ style="flex:1; display:${this.activeResponseTab === "response" ? "flex" : "none"};"
117
+ >
118
+ <button
119
+ class="btn btn-sm btn-outline toolbar-btn"
120
+ @click="${(e) => {
121
+ copyToClipboard(this.responseText, e);
122
+ }}"
123
+ part="btn btn-outline btn-copy"
124
+ >
125
+ Copy
126
+ </button>
127
+ <pre style="white-space:pre; min-height:50px; height:var(--resp-area-height); resize:vertical; overflow:auto">
128
+ ${responseContent}</pre>
129
+ </div>`
130
+ }
131
+ <div
132
+ part="tab-content"
133
+ class="tab-content col m-markdown"
134
+ style="flex:1; display:${this.activeResponseTab === "headers" ? "flex" : "none"};"
135
+ >
136
+ <button
137
+ class="btn btn-sm btn-outline toolbar-btn"
138
+ @click="${(e) => {
139
+ copyToClipboard(this.responseHeaders, e);
140
+ }}"
141
+ part="btn btn-outline btn-copy"
142
+ >
143
+ Copy
144
+ </button>
145
+ <pre style="white-space:pre"><code class="language-css">${this.responseHeaders}</code></pre>
146
+ </div>
147
+ ${this.showCurlBeforeTry === "true" ? "" : curlSyntaxTemplate.call(this, this.activeResponseTab === "curl" ? "flex" : "none")}
148
+ </div>`;
149
+ }
150
+
151
+ export function apiCallTemplate() {
152
+ let authHtml;
153
+ if (this.security?.length > 0 && !this.security.every((s) => !s || Object.keys(s).length === 0)) {
154
+ if (this.api_keys.length > 0) {
155
+ authHtml = html`<span class="blue-text">
156
+ ${this.api_keys.length === 1 ? `${this.api_keys[0]?.typeDisplay} in ${this.api_keys[0].in}` : `${this.api_keys.length} API keys applied`}
157
+ </span>`;
158
+ } else if (this.security.some((s) => !s || Object.keys(s).length === 0)) {
159
+ authHtml = html`Optional (None Applied)`;
160
+ } else {
161
+ authHtml = html`Required <span class="red-text">(None Applied)</span>`;
162
+ }
163
+ } else {
164
+ authHtml = html`Not Required`;
165
+ }
166
+
167
+ return html`<div class="try-bar" part="wrap-request-btn">
168
+ <div class="try-layout">
169
+ <dl class="try-info">
170
+ ${
171
+ this.serverUrl
172
+ ? html`<dt>API Server</dt>
173
+ <dd class="try-server-url">${this.serverUrl}</dd>`
174
+ : ""
175
+ }
176
+ <dt>Authentication</dt>
177
+ <dd>${authHtml}</dd>
178
+ </dl>
179
+ <div class="try-actions">
180
+ ${
181
+ this.parameters.length > 0 || this.request_body
182
+ ? html`${
183
+ this.hasExampleToFill
184
+ ? html`<button
185
+ class="btn btn-outline"
186
+ part="btn btn-outline btn-fill btn-fill-example"
187
+ ?disabled="${this.loading}"
188
+ @click="${this.onFillRequestData}"
189
+ title="Fills the request fields with their examples"
190
+ >
191
+ FILL EXAMPLE
192
+ </button>`
193
+ : ""
194
+ }
195
+ <button
196
+ class="btn btn-outline"
197
+ part="btn btn-outline btn-clear"
198
+ ?disabled="${this.loading || !this.hasValueToClear}"
199
+ @click="${this.onClearRequestData}"
200
+ >
201
+ CLEAR
202
+ </button>`
203
+ : ""
204
+ }
205
+ <button
206
+ class="btn btn-primary"
207
+ part="btn btn-try"
208
+ ?disabled="${this.loading}"
209
+ aria-busy="${this.loading}"
210
+ @click="${this.onTryClick}"
211
+ >
212
+ ${this.loading ? "TRYING..." : "TRY"}
213
+ </button>
214
+ </div>
215
+ </div>
216
+ </div>
217
+ <div class="row" style="font-size:var(--font-size-small); margin:5px 0">
218
+ ${this.showCurlBeforeTry === "true" ? curlSyntaxTemplate.call(this) : ""}
219
+ </div>
220
+ ${this.responseMessage === "" ? "" : apiResponseTabTemplate.call(this)} `;
221
+ }
222
+
223
+ export default apiCallTemplate;
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Renders OpenAPI callback requests and nested response definitions within an endpoint.
3
+ */
4
+ import { html } from "lit";
5
+
6
+ export default function callbackTemplate(callbacks) {
7
+ return html`
8
+ <h4 class="rapidoc-heading label-heading req-res-title" part="heading heading-4">Callbacks</h4>
9
+ ${Object.entries(callbacks).map(
10
+ (kv) => html`
11
+ <div class="tiny-title" style="padding: 12px; border:1px solid var(--border)">
12
+ <h5 class="rapidoc-heading callback-name" part="heading heading-5">${kv[0]}</h5>
13
+ ${Object.entries(kv[1]).map(
14
+ (pathObj) => html`
15
+ <div class="callback-operation-list mono-font small-font-size">
16
+ ${Object.entries(pathObj[1]).map(
17
+ (method) => html`
18
+ <div class="callback-operation-item">
19
+ <div class="callback-operation-header">
20
+ <div class="method method-fg ${method[0]} callback-method">
21
+ <span style="font-size:20px;"> &#x2944; </span>
22
+ ${method[0]}
23
+ </div>
24
+ <span style="line-height:20px; vertical-align: baseline;">${pathObj[0]}</span>
25
+ </div>
26
+ <div class="expanded-req-resp-container">
27
+ <api-request
28
+ .config="${this.config}"
29
+ class="${this.renderStyle}-mode callback"
30
+ style="width:100%;"
31
+ callback="true"
32
+ method="${method[0] || ""}"
33
+ path="${pathObj[0] || ""}"
34
+ .parameters="${method[1]?.parameters || ""}"
35
+ .request_body="${method[1]?.requestBody || ""}"
36
+ fill-request-fields-with-example="${this.fillRequestFieldsWithExample}"
37
+ allow-try="false"
38
+ render-style="${this.renderStyle}"
39
+ schema-style="${this.schemaStyle}"
40
+ active-schema-tab="${this.defaultSchemaTab}"
41
+ schema-expand-level="${this.schemaExpandLevel}"
42
+ schema-description-expanded="${this.schemaDescriptionExpanded}"
43
+ allow-schema-description-expand-toggle="${this.allowSchemaDescriptionExpandToggle}"
44
+ schema-hide-read-only="false"
45
+ schema-hide-write-only="${this.schemaHideWriteOnly === "never" ? "false" : "true"}"
46
+ fetch-credentials="${this.fetchCredentials}"
47
+ exportparts="section-request-title:section-request-title, heading:heading, heading-4:heading-4, heading-5:heading-5, heading-6:heading-6,
48
+ wrap-request-btn:wrap-request-btn, btn:btn, btn-fill:btn-fill, btn-outline:btn-outline, btn-try:btn-try, btn-clear:btn-clear, btn-fill-example:btn-fill-example, btn-clear-resp:btn-clear-resp,
49
+ tab-panel:tab-panel, tab-btn:tab-btn, tab-btn-row:tab-btn-row, tab-content:tab-content,
50
+ file-input:file-input, textbox:textbox, textbox-param:textbox-param, textarea:textarea, textarea-param:textarea-param,
51
+ anchor:anchor, anchor-param-example:anchor-param-example, anchor-param-constraint:anchor-param-constraint, param-list:param-list, param:param, param-label:param-label, param-name:param-name, param-type:param-type, param-input:param-input, param-constraint:param-constraint, param-constraint-label:param-constraint-label, param-details:param-details, param-example-list:param-example-list, value-list:value-list, value-list-label:value-list-label, value-list-items:value-list-items, schema-description:schema-description, schema-multiline-toggle:schema-multiline-toggle"
52
+ >
53
+ </api-request>
54
+
55
+ <api-response
56
+ .config="${this.config}"
57
+ style="width:100%;"
58
+ class="${this.renderStyle}-mode"
59
+ callback="true"
60
+ .responses="${method[1]?.responses}"
61
+ render-style="${this.renderStyle}"
62
+ schema-style="${this.schemaStyle}"
63
+ active-schema-tab="${this.defaultSchemaTab}"
64
+ schema-expand-level="${this.schemaExpandLevel}"
65
+ schema-description-expanded="${this.schemaDescriptionExpanded}"
66
+ allow-schema-description-expand-toggle="${this.allowSchemaDescriptionExpandToggle}"
67
+ schema-hide-read-only="${this.schemaHideReadOnly === "never" ? "false" : "true"}"
68
+ schema-hide-write-only="false"
69
+ exportparts="section-response-title:section-response-title, heading:heading, heading-4:heading-4, heading-5:heading-5, heading-6:heading-6,
70
+ btn:btn, btn-response-status:btn-response-status, btn-selected-response-status:btn-selected-response-status, btn-fill:btn-fill, btn-outline:btn-outline, btn-copy:btn-copy,
71
+ tab-panel:tab-panel, tab-btn:tab-btn, tab-btn-row:tab-btn-row, tab-content:tab-content,
72
+ schema-description:schema-description, schema-multiline-toggle:schema-multiline-toggle, param-list:param-list, param:param, param-label:param-label, param-name:param-name, param-type:param-type, param-constraint:param-constraint, param-constraint-label:param-constraint-label, param-details:param-details, param-example-list:param-example-list, value-list:value-list, value-list-label:value-list-label, value-list-items:value-list-items"
73
+ >
74
+ </api-response>
75
+ </div>
76
+ </div>
77
+ `,
78
+ )}
79
+ </div>
80
+ `,
81
+ )}
82
+ </div>
83
+ `,
84
+ )}
85
+ `;
86
+ }
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Renders multi-language code snippets and custom x-codeSamples / x-code-samples tab panels.
3
+ */
4
+ import { html } from "lit";
5
+
6
+ import { copyToClipboard } from "~/utils/common-utils";
7
+ import { scheduleHighlight } from "~/utils/highlighter";
8
+
9
+ export default function codeSamplesTemplate(xCodeSamples) {
10
+ return html` <div class="code-samples-container">
11
+ <h4 class="rapidoc-heading label-heading table-title top-gap" part="heading heading-4">Code samples</h4>
12
+ <div
13
+ part="tab-panel"
14
+ class="tab-panel col"
15
+ @click="${(e) => {
16
+ if (!e.target.classList.contains("tab-btn")) {
17
+ return;
18
+ }
19
+ const clickedTab = e.target.dataset.tab;
20
+
21
+ const tabButtons = [...e.currentTarget.querySelectorAll(".tab-btn")];
22
+ const tabContents = [...e.currentTarget.querySelectorAll(".tab-content")];
23
+ tabButtons.forEach((tabBtnEl) =>
24
+ tabBtnEl.classList[tabBtnEl.dataset.tab === clickedTab ? "add" : "remove"]("active"),
25
+ );
26
+ tabContents.forEach((tabBodyEl) => {
27
+ tabBodyEl.style.display = tabBodyEl.dataset.tab === clickedTab ? "block" : "none";
28
+ });
29
+ scheduleHighlight(e.currentTarget.getRootNode()?.host?.shadowRoot || e.currentTarget);
30
+ }}"
31
+ >
32
+ <div part="tab-btn-row" class="tab-buttons row" style="width:100%; overflow:auto;">
33
+ ${xCodeSamples.map((v, i) => html`<button part="tab-btn" class="tab-btn ${i === 0 ? "active" : ""}" data-tab="${v.lang}${i}">${v.label || v.lang}</button>`)}
34
+ </div>
35
+ ${xCodeSamples.map(
36
+ (v, i) =>
37
+ html`<div class="tab-content m-markdown" style="display:${i === 0 ? "block" : "none"}" data-tab="${v.lang}${i}">
38
+ <button
39
+ class="btn btn-sm btn-outline toolbar-btn"
40
+ part="btn btn-outline btn-copy"
41
+ @click="${(e) => {
42
+ copyToClipboard(v.source, e);
43
+ }}"
44
+ >
45
+ Copy
46
+ </button>
47
+ <pre><code class="language-${v.lang?.toLowerCase()}">${v.source}</code></pre>
48
+ </div>`,
49
+ )}
50
+ </div>
51
+ </div>`;
52
+ }
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Renders reusable OpenAPI component definitions (schemas, models) in the document.
3
+ */
4
+ import { html } from "lit";
5
+ import { unsafeHTML } from "lit/directives/unsafe-html.js";
6
+ import { sanitizeHTML } from "../utils/sanitize.js";
7
+ import { marked } from "marked";
8
+ import { schemaToAST } from "~/utils/schema-utils";
9
+ import "~/components/json-tree";
10
+ import "~/components/schema-tree";
11
+ import "~/components/schema-table";
12
+
13
+ function schemaBodyTemplate(sComponent) {
14
+ return html` <div class="expanded-endpoint-body observe-me ${sComponent.name}" id="cmp--${sComponent.id}">
15
+ <h3 class="rapidoc-heading component-title" part="heading heading-3">
16
+ ${sComponent.name} <span style="color:var(--muted-foreground); font-size:var(--font-size-small); font-weight:400;"> Schema </span>
17
+ </h3>
18
+ ${
19
+ this.schemaStyle === "table"
20
+ ? html` <schema-table
21
+ .data="${schemaToAST(sComponent.component)}"
22
+ schema-expand-level="${this.schemaExpandLevel}"
23
+ schema-description-expanded="${this.schemaDescriptionExpanded}"
24
+ allow-schema-description-expand-toggle="${this.allowSchemaDescriptionExpandToggle}"
25
+ schema-hide-read-only="false"
26
+ schema-hide-write-only="${this.schemaHideWriteOnly}"
27
+ exportparts="schema-description:schema-description, schema-multiline-toggle:schema-multiline-toggle"
28
+ >
29
+ </schema-table>`
30
+ : html`<schema-tree
31
+ .data="${schemaToAST(sComponent.component)}"
32
+ schema-expand-level="${this.schemaExpandLevel}"
33
+ schema-description-expanded="${this.schemaDescriptionExpanded}"
34
+ allow-schema-description-expand-toggle="${this.allowSchemaDescriptionExpandToggle}"
35
+ schema-hide-read-only="false"
36
+ schema-hide-write-only="${this.schemaHideWriteOnly}"
37
+ exportparts="schema-description:schema-description, schema-multiline-toggle:schema-multiline-toggle"
38
+ >
39
+ </schema-tree>`
40
+ }
41
+ </div>`;
42
+ }
43
+
44
+ function componentBodyTemplate(sComponent, componentType) {
45
+ if (sComponent.id.indexOf("schemas-") !== -1) {
46
+ return schemaBodyTemplate.call(this, sComponent);
47
+ }
48
+ return html`
49
+ <div class="expanded-endpoint-body observe-me ${sComponent.name}" id="cmp--${sComponent.id}">
50
+ ${html`
51
+ <h3 class="rapidoc-heading component-title" part="heading heading-3">
52
+ ${sComponent.name}
53
+ <span style="color:var(--muted-foreground); font-size:var(--font-size-small); font-weight:400"> ${componentType} </span>
54
+ </h3>
55
+ ${
56
+ sComponent.component
57
+ ? html`<div class="mono-font regular-font-size" style="padding: 8px 0; color:var(--card-foreground)">
58
+ <json-tree class="border tree" render-style="${this.renderStyle}" .data="${sComponent.component}"> </json-tree>
59
+ </div>`
60
+ : ""
61
+ }
62
+ `}
63
+ </div>
64
+ `;
65
+ }
66
+
67
+ export default function componentsTemplate() {
68
+ if (!this.resolvedSpec) {
69
+ return "";
70
+ }
71
+ return html`
72
+ ${this.resolvedSpec.components.map(
73
+ (component) => html`
74
+ <div id="cmp--${component.name.toLowerCase()}" class="regular-font section-gap--read-mode observe-me read-mode-tag">
75
+ <h2 class="rapidoc-heading title tag" part="heading heading-2">${component.name}</h2>
76
+ ${unsafeHTML(`<div class='m-markdown regular-font'>${sanitizeHTML(marked(component.description || ""))}</div>`)}
77
+ </div>
78
+ <div class="regular-font section-gap--read-mode">
79
+ ${component.subComponents
80
+ .filter((c) => c.expanded !== false)
81
+ .map((sComponent) => componentBodyTemplate.call(this, sComponent, component.name))}
82
+ </div>
83
+ `,
84
+ )}
85
+ `;
86
+ }
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Dedicated Download & Export Action Bar for OpenAPI specs and curated MCP servers.
3
+ * Rendered independently of show-info to guarantee accessibility across all render modes.
4
+ */
5
+ import { html } from "lit";
6
+ import { downloadResource, viewResource } from "~/utils/common-utils";
7
+ import { parseMcpEnabled } from "~/utils/mcp-generator";
8
+
9
+ export default function downloadsTemplate() {
10
+ const showSpecDownload = this.specUrl && this.allowSpecFileDownload === "true";
11
+ const showMcpExport = parseMcpEnabled(this.mcp);
12
+
13
+ if (!showSpecDownload && !showMcpExport) {
14
+ return "";
15
+ }
16
+
17
+ let sectionClass = "section-gap";
18
+ if (this.renderStyle === "focused") {
19
+ sectionClass = "section-gap--focused-mode";
20
+ } else if (this.renderStyle === "read") {
21
+ sectionClass = "section-gap--read-mode";
22
+ }
23
+
24
+ return html`
25
+ <section id="downloads" part="section-downloads" class="downloads-bar observe-me ${sectionClass}">
26
+ ${
27
+ showSpecDownload
28
+ ? html`
29
+ <button
30
+ class="btn btn-outline download-btn"
31
+ part="btn btn-outline"
32
+ @click="${() => {
33
+ downloadResource(this.specUrl, "openapi-spec");
34
+ }}"
35
+ >
36
+ Download OpenAPI spec
37
+ </button>
38
+ ${
39
+ this.specUrl?.trim().toLowerCase().endsWith("json")
40
+ ? html`<button
41
+ class="btn btn-outline download-btn view-spec"
42
+ part="btn btn-outline"
43
+ @click="${() => {
44
+ viewResource(this.specUrl);
45
+ }}"
46
+ >
47
+ View OpenAPI spec (New Tab)
48
+ </button>`
49
+ : ""
50
+ }
51
+ `
52
+ : ""
53
+ }
54
+ ${
55
+ showMcpExport
56
+ ? html`<button
57
+ class="btn btn-outline download-btn"
58
+ part="btn btn-outline btn-mcp-export"
59
+ title="Download an MCP server project (manifest, runtime and stdio server) as a zip"
60
+ @click="${() => {
61
+ this.downloadMcpServer();
62
+ }}"
63
+ >
64
+ Export MCP Server
65
+ </button>`
66
+ : ""
67
+ }
68
+ </section>
69
+ `;
70
+ }