rapidoc 11.0.1 → 12.0.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.
- package/README.md +46 -31
- package/dist/rapidoc-min.js +1424 -213
- package/dist/rapidoc-static-min.js +13542 -0
- package/package.json +47 -35
- package/src/components/api-request.ts +869 -0
- package/src/components/api-response.ts +509 -0
- package/src/components/json-tree.ts +171 -0
- package/src/components/schema-base-element.ts +315 -0
- package/src/components/schema-table.ts +430 -0
- package/src/components/schema-tree.ts +386 -0
- package/src/components/tag-input.ts +184 -0
- package/src/index.js +6 -0
- package/src/oauth-receiver.ts +29 -0
- package/src/rapidoc-mini.ts +582 -0
- package/src/rapidoc.ts +1808 -0
- package/src/static/index.d.ts +149 -0
- package/src/static/index.js +62 -0
- package/src/static/navigation.js +497 -0
- package/src/static/render.js +490 -0
- package/src/static/serializer.js +216 -0
- package/src/styles/auth-styles.js +318 -0
- package/src/styles/border-styles.js +24 -0
- package/src/styles/css-bundle.js +129 -0
- package/src/styles/custom-styles.js +8 -0
- package/src/styles/dialog-box-styles.js +102 -0
- package/src/styles/endpoint-styles.js +559 -0
- package/src/styles/flex-styles.js +16 -0
- package/src/styles/font-styles.js +432 -0
- package/src/styles/info-styles.js +36 -0
- package/src/styles/input-styles.js +555 -0
- package/src/styles/layout-styles.js +396 -0
- package/src/styles/microlighter-styles.js +99 -0
- package/src/styles/nav-styles.js +609 -0
- package/src/styles/param-list-styles.js +261 -0
- package/src/styles/schema-styles.js +288 -0
- package/src/styles/tab-styles.js +106 -0
- package/src/styles/theme-tokens.js +582 -0
- package/src/templates/advanced-search-dialog-template.js +94 -0
- package/src/templates/api-response-template.js +219 -0
- package/src/templates/callback-template.js +86 -0
- package/src/templates/code-samples-template.js +52 -0
- package/src/templates/components-template.js +86 -0
- package/src/templates/downloads-template.js +85 -0
- package/src/templates/endpoint-template.js +386 -0
- package/src/templates/expanded-endpoint-template.js +266 -0
- package/src/templates/focused-endpoint-template.js +145 -0
- package/src/templates/header-template.js +92 -0
- package/src/templates/logo-template.js +21 -0
- package/src/templates/main-body-template.js +102 -0
- package/src/templates/navbar-template.js +489 -0
- package/src/templates/overview-template.js +104 -0
- package/src/templates/request-body-template.js +651 -0
- package/src/templates/request-params-template.js +474 -0
- package/src/templates/security-scheme-template.js +1263 -0
- package/src/templates/server-template.js +152 -0
- package/src/utils/auto-color-scheme.js +99 -0
- package/src/utils/bind-navbar.js +175 -0
- package/src/utils/color-utils.js +59 -0
- package/src/utils/common-utils.js +191 -0
- package/src/utils/curl-utils.js +123 -0
- package/src/utils/highlighter.js +416 -0
- package/src/utils/markdown-utils.js +110 -0
- package/src/utils/mcp/common.js +467 -0
- package/src/utils/mcp/generators/csharp.js +242 -0
- package/src/utils/mcp/generators/go.js +298 -0
- package/src/utils/mcp/generators/java.js +330 -0
- package/src/utils/mcp/generators/python.js +248 -0
- package/src/utils/mcp/generators/rust.js +281 -0
- package/src/utils/mcp/generators/typescript.js +290 -0
- package/src/utils/mcp-generator.js +143 -0
- package/src/utils/mock-interceptor.js +508 -0
- package/src/utils/oauth-utils.js +87 -0
- package/src/utils/request-utils.js +203 -0
- package/src/utils/response-utils.js +203 -0
- package/src/utils/sanitize.js +57 -0
- package/src/utils/schema-utils.js +1927 -0
- package/src/utils/slugger.js +189 -0
- package/src/utils/spec-parser.js +915 -0
- package/src/utils/url-utils.js +211 -0
- package/src/utils/xml-utils.js +61 -0
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
import { html, css, nothing } from "lit";
|
|
2
|
+
import { customElement } from "lit/decorators.js";
|
|
3
|
+
import FontStyles from "../styles/font-styles.js";
|
|
4
|
+
import SchemaStyles from "../styles/schema-styles.js";
|
|
5
|
+
import BorderStyles from "../styles/border-styles.js";
|
|
6
|
+
import CustomStyles from "../styles/custom-styles.js";
|
|
7
|
+
import SchemaBaseElement from "./schema-base-element";
|
|
8
|
+
|
|
9
|
+
@customElement("schema-tree")
|
|
10
|
+
export default class SchemaTree extends SchemaBaseElement {
|
|
11
|
+
static get styles() {
|
|
12
|
+
return [
|
|
13
|
+
FontStyles,
|
|
14
|
+
SchemaStyles,
|
|
15
|
+
BorderStyles,
|
|
16
|
+
css`
|
|
17
|
+
.tree {
|
|
18
|
+
font-size: var(--font-size-small);
|
|
19
|
+
text-align: left;
|
|
20
|
+
direction: ltr;
|
|
21
|
+
line-height: calc(var(--font-size-small) + 6px);
|
|
22
|
+
|
|
23
|
+
& .tr:hover {
|
|
24
|
+
background-color: rgba(0, 0, 0, 0.15);
|
|
25
|
+
}
|
|
26
|
+
& .tr.expanded-descr {
|
|
27
|
+
max-height: none;
|
|
28
|
+
}
|
|
29
|
+
/* faint separators where descriptions wrap: every row in multiline mode, or around a row expanded by click */
|
|
30
|
+
&.expanded-all-descr .tr,
|
|
31
|
+
&.collapsed-all-descr .tr.expanded-descr {
|
|
32
|
+
border-bottom: 1px solid color-mix(in srgb, var(--border) 60%, transparent);
|
|
33
|
+
}
|
|
34
|
+
&.collapsed-all-descr .tr.expanded-descr {
|
|
35
|
+
box-shadow: 0 -1px 0 color-mix(in srgb, var(--border) 60%, transparent);
|
|
36
|
+
}
|
|
37
|
+
& .key {
|
|
38
|
+
max-width: 300px;
|
|
39
|
+
}
|
|
40
|
+
&.collapsed-all-descr .tr:not(.expanded-descr) {
|
|
41
|
+
overflow: hidden;
|
|
42
|
+
max-height: calc(var(--font-size-small) + 8px);
|
|
43
|
+
|
|
44
|
+
& .key {
|
|
45
|
+
white-space: nowrap;
|
|
46
|
+
text-overflow: ellipsis;
|
|
47
|
+
overflow: hidden;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.tr {
|
|
53
|
+
&.expanded {
|
|
54
|
+
&:hover {
|
|
55
|
+
& > .td.key > .open-bracket,
|
|
56
|
+
& + .inside-bracket + .close-bracket {
|
|
57
|
+
color: var(--primary);
|
|
58
|
+
}
|
|
59
|
+
& + .inside-bracket {
|
|
60
|
+
border-left: 1px solid var(--muted-foreground);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
& .open-bracket .open-bracket-collapsed {
|
|
64
|
+
display: none;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
&.collapsed {
|
|
68
|
+
& + .inside-bracket,
|
|
69
|
+
& + .inside-bracket + .close-bracket {
|
|
70
|
+
overflow: hidden;
|
|
71
|
+
display: none;
|
|
72
|
+
}
|
|
73
|
+
& .open-bracket .open-bracket-expanded {
|
|
74
|
+
display: none;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.inside-bracket {
|
|
80
|
+
&.xxx-of-option {
|
|
81
|
+
border-left: 1px solid transparent;
|
|
82
|
+
}
|
|
83
|
+
&.object,
|
|
84
|
+
&.array {
|
|
85
|
+
border-left: 1px dotted var(--border);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.open-bracket {
|
|
90
|
+
display: inline-block;
|
|
91
|
+
padding: 0 20px 0 0;
|
|
92
|
+
cursor: pointer;
|
|
93
|
+
border: 1px solid transparent;
|
|
94
|
+
border-radius: min(var(--radius), 0.5rem);
|
|
95
|
+
|
|
96
|
+
&:hover {
|
|
97
|
+
color: var(--primary);
|
|
98
|
+
border: 1px solid var(--border);
|
|
99
|
+
}
|
|
100
|
+
&:focus-visible {
|
|
101
|
+
outline: 2px solid var(--primary);
|
|
102
|
+
border-color: var(--primary);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.close-bracket {
|
|
107
|
+
display: inline-block;
|
|
108
|
+
font-family: var(--font-mono);
|
|
109
|
+
}
|
|
110
|
+
`,
|
|
111
|
+
CustomStyles,
|
|
112
|
+
];
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
render() {
|
|
116
|
+
if (!this.data) {
|
|
117
|
+
return html`
|
|
118
|
+
<div class="tree">
|
|
119
|
+
<span class="mono-font" style="color:var(--destructive)"> Schema not found </span>
|
|
120
|
+
</div>
|
|
121
|
+
`;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const rootType = this.data.kind === "primitive" ? this.data.type : this.data.kind || "";
|
|
125
|
+
const rootDescription = this.data.description || "";
|
|
126
|
+
|
|
127
|
+
return html` <div
|
|
128
|
+
class="tree ${this.schemaDescriptionExpanded === "true" ? "expanded-all-descr" : "collapsed-all-descr"}"
|
|
129
|
+
@click="${(e) => this.handleAllEvents(e)}"
|
|
130
|
+
@keydown="${(e) => this.handleKeyDown(e)}"
|
|
131
|
+
>
|
|
132
|
+
${this.renderToolbar(rootType)}
|
|
133
|
+
<span part="schema-description" class="m-markdown"> ${this.renderDescriptionHtml(rootDescription)}</span>
|
|
134
|
+
${this.renderAST(this.data)}
|
|
135
|
+
</div>`;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
renderAST(node, parentType = "", schemaLevel = 0, indentLevel = 0) {
|
|
139
|
+
if (this.isFieldHidden(node)) {
|
|
140
|
+
return "";
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const leftPadding = 12;
|
|
144
|
+
const minFieldColWidth = 400 - indentLevel * leftPadding;
|
|
145
|
+
const isExpanded = schemaLevel < this.schemaExpandLevel;
|
|
146
|
+
const readWriteBadge = this.getReadWriteBadge(node);
|
|
147
|
+
const readWriteTip = this.getReadWriteTip(node);
|
|
148
|
+
const nullMarker = node.nullable ? "null┃" : "";
|
|
149
|
+
const nullClass = node.nullable ? "nullable" : "";
|
|
150
|
+
const deprecatedIcon = this.renderDeprecatedIcon(node);
|
|
151
|
+
|
|
152
|
+
// 1. Array kind
|
|
153
|
+
if (node.kind === "array") {
|
|
154
|
+
const items = node.items;
|
|
155
|
+
if (!items) {
|
|
156
|
+
const fieldTitle = node.name
|
|
157
|
+
? `${node.name}${readWriteTip ? ` (${readWriteTip})` : ""}`
|
|
158
|
+
: "";
|
|
159
|
+
return html`
|
|
160
|
+
<div class="tr ${isExpanded ? "expanded" : "collapsed"} array ${nullClass}" title="${node.deprecated ? "Deprecated" : nothing}">
|
|
161
|
+
<div class="td key ${node.deprecated ? "deprecated" : ""}" style="min-width:${minFieldColWidth}px">
|
|
162
|
+
${deprecatedIcon}${node.name ? html`<span class="key-label" title="${fieldTitle}">${node.name}${node.required ? html`<span style="color:var(--destructive)">*</span>` : ""}${readWriteBadge}:</span>` : ""}
|
|
163
|
+
<span class="open-bracket array">${nullMarker}[ ]</span>
|
|
164
|
+
</div>
|
|
165
|
+
${this.renderDescrCell(node.description)}
|
|
166
|
+
</div>
|
|
167
|
+
`;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// If array of primitives
|
|
171
|
+
if (items.kind === "primitive") {
|
|
172
|
+
const itemType = items.format || items.contentMediaType || items.type || "string";
|
|
173
|
+
const dataTypeCss = this.getDataTypeCss(itemType);
|
|
174
|
+
const fieldTitle = node.name
|
|
175
|
+
? `${node.name}${readWriteTip ? ` (${readWriteTip})` : ""}`
|
|
176
|
+
: "";
|
|
177
|
+
|
|
178
|
+
return html`
|
|
179
|
+
<div class="tr primitive ${nullClass}" title="${node.deprecated || items.deprecated ? "Deprecated" : nothing}">
|
|
180
|
+
<div class="td key ${node.deprecated || items.deprecated ? "deprecated" : ""}" style="min-width:${minFieldColWidth}px">
|
|
181
|
+
${deprecatedIcon}${node.name ? html`<span class="key-label" title="${fieldTitle}">${node.name}${node.required ? html`<span style="color:var(--destructive)">*</span>` : ""}:</span>` : ""}
|
|
182
|
+
<span class="${dataTypeCss}" title="${readWriteTip || nothing}">${nullMarker}[${itemType}]${readWriteBadge}</span>
|
|
183
|
+
</div>
|
|
184
|
+
${this.renderDescrCell(node.description || items.description, items)}
|
|
185
|
+
</div>
|
|
186
|
+
`;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// If array of objects
|
|
190
|
+
if (items.kind === "object") {
|
|
191
|
+
const openBracket = html`<span
|
|
192
|
+
class="open-bracket array-of-object"
|
|
193
|
+
role="button"
|
|
194
|
+
tabindex="0"
|
|
195
|
+
aria-label="Toggle ${node.name || "object"}"
|
|
196
|
+
aria-expanded="${isExpanded ? "true" : "false"}"
|
|
197
|
+
>${nullMarker}<span class="open-bracket-expanded">[{</span><span class="open-bracket-collapsed">[{...}]</span></span
|
|
198
|
+
>`;
|
|
199
|
+
const closeBracket = "}]";
|
|
200
|
+
const fieldTitle = node.name
|
|
201
|
+
? `${node.name}${readWriteTip ? ` (${readWriteTip})` : ""}`
|
|
202
|
+
: "";
|
|
203
|
+
|
|
204
|
+
return html`
|
|
205
|
+
<div
|
|
206
|
+
class="tr ${isExpanded ? "expanded" : "collapsed"} object ${nullClass}"
|
|
207
|
+
title="${node.deprecated || items.deprecated ? "Deprecated" : nothing}"
|
|
208
|
+
>
|
|
209
|
+
<div class="td key ${node.deprecated || items.deprecated ? "deprecated" : ""}" style="min-width:${minFieldColWidth}px">
|
|
210
|
+
${deprecatedIcon}${node.name ? html`<span class="key-label" title="${fieldTitle}">${node.name}${node.required ? html`<span style="color:var(--destructive)">*</span>` : ""}${readWriteBadge}:</span>` : ""}
|
|
211
|
+
${openBracket}
|
|
212
|
+
</div>
|
|
213
|
+
${this.renderDescrCell(node.description || items.description)}
|
|
214
|
+
</div>
|
|
215
|
+
<div class="inside-bracket object" style="padding-left:${leftPadding}px;">
|
|
216
|
+
${items.properties?.map((p) => this.renderAST(p, "object", schemaLevel + 1, indentLevel + 1))}
|
|
217
|
+
${items.patternProperties?.map((p) => this.renderAST(p, "object", schemaLevel + 1, indentLevel + 1))}
|
|
218
|
+
${items.additionalProperties ? this.renderAST(items.additionalProperties, "object", schemaLevel + 1, indentLevel + 1) : ""}
|
|
219
|
+
${items.unions?.map((u) => this.renderAST(u, "object", schemaLevel + 1, indentLevel + 1))}
|
|
220
|
+
</div>
|
|
221
|
+
<div class="close-bracket">${closeBracket}</div>
|
|
222
|
+
`;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// If array of arrays
|
|
226
|
+
if (items.kind === "array") {
|
|
227
|
+
const arrType = node.arrayType !== "object" ? node.arrayType : "";
|
|
228
|
+
const openBracket = html`<span
|
|
229
|
+
class="open-bracket array-of-array"
|
|
230
|
+
data-array-type="${arrType}"
|
|
231
|
+
role="button"
|
|
232
|
+
tabindex="0"
|
|
233
|
+
aria-label="Toggle ${node.name || "array"}"
|
|
234
|
+
aria-expanded="${isExpanded ? "true" : "false"}"
|
|
235
|
+
>${nullMarker}<span class="open-bracket-expanded">[[ ${arrType} </span><span class="open-bracket-collapsed">[[...]]</span></span
|
|
236
|
+
>`;
|
|
237
|
+
const closeBracket = "]]";
|
|
238
|
+
const fieldTitle = node.name
|
|
239
|
+
? `${node.name}${readWriteTip ? ` (${readWriteTip})` : ""}`
|
|
240
|
+
: "";
|
|
241
|
+
|
|
242
|
+
return html`
|
|
243
|
+
<div class="tr ${isExpanded ? "expanded" : "collapsed"} array ${nullClass}" title="${node.deprecated ? "Deprecated" : nothing}">
|
|
244
|
+
<div class="td key ${node.deprecated ? "deprecated" : ""}" style="min-width:${minFieldColWidth}px">
|
|
245
|
+
${deprecatedIcon}${node.name ? html`<span class="key-label" title="${fieldTitle}">${node.name}${node.required ? html`<span style="color:var(--destructive)">*</span>` : ""}${readWriteBadge}:</span>` : ""}
|
|
246
|
+
${openBracket}
|
|
247
|
+
</div>
|
|
248
|
+
${this.renderDescrCell(node.description)}
|
|
249
|
+
</div>
|
|
250
|
+
<div class="inside-bracket array" style="padding-left:${leftPadding}px;">
|
|
251
|
+
${this.renderAST(items, "array", schemaLevel + 1, indentLevel + 1)}
|
|
252
|
+
</div>
|
|
253
|
+
<div class="close-bracket">${closeBracket}</div>
|
|
254
|
+
`;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// If array of unions or others
|
|
258
|
+
const fieldTitle = node.name ? `${node.name}${readWriteTip ? ` (${readWriteTip})` : ""}` : "";
|
|
259
|
+
return html`
|
|
260
|
+
<div class="tr ${isExpanded ? "expanded" : "collapsed"} array ${nullClass}" title="${node.deprecated ? "Deprecated" : nothing}">
|
|
261
|
+
<div class="td key ${node.deprecated ? "deprecated" : ""}" style="min-width:${minFieldColWidth}px">
|
|
262
|
+
${deprecatedIcon}${node.name ? html`<span class="key-label" title="${fieldTitle}">${node.name}${node.required ? html`<span style="color:var(--destructive)">*</span>` : ""}${readWriteBadge}:</span>` : ""}
|
|
263
|
+
<span
|
|
264
|
+
class="open-bracket array"
|
|
265
|
+
role="button"
|
|
266
|
+
tabindex="0"
|
|
267
|
+
aria-label="Toggle ${node.name || "array"}"
|
|
268
|
+
aria-expanded="${isExpanded ? "true" : "false"}"
|
|
269
|
+
>${nullMarker}<span class="open-bracket-expanded">[</span><span class="open-bracket-collapsed">[...]</span></span
|
|
270
|
+
>
|
|
271
|
+
</div>
|
|
272
|
+
${this.renderDescrCell(node.description)}
|
|
273
|
+
</div>
|
|
274
|
+
<div class="inside-bracket array" style="padding-left:${leftPadding}px;">
|
|
275
|
+
${this.renderAST(items, "array", schemaLevel + 1, indentLevel + 1)}
|
|
276
|
+
</div>
|
|
277
|
+
<div class="close-bracket">]</div>
|
|
278
|
+
`;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// 2. Object kind
|
|
282
|
+
if (node.kind === "object") {
|
|
283
|
+
const openBracket = html`<span
|
|
284
|
+
class="open-bracket object"
|
|
285
|
+
role="button"
|
|
286
|
+
tabindex="0"
|
|
287
|
+
aria-label="Toggle ${node.name || "object"}"
|
|
288
|
+
aria-expanded="${isExpanded ? "true" : "false"}"
|
|
289
|
+
>${nullMarker}<span class="open-bracket-expanded">{</span><span class="open-bracket-collapsed">{...}</span></span
|
|
290
|
+
>`;
|
|
291
|
+
const closeBracket = "}";
|
|
292
|
+
const fieldTitle = node.name ? `${node.name}${readWriteTip ? ` (${readWriteTip})` : ""}` : "";
|
|
293
|
+
|
|
294
|
+
return html`
|
|
295
|
+
<div class="tr ${isExpanded ? "expanded" : "collapsed"} object ${nullClass}" title="${node.deprecated ? "Deprecated" : nothing}">
|
|
296
|
+
<div class="td key ${node.deprecated ? "deprecated" : ""}" style="min-width:${minFieldColWidth}px">
|
|
297
|
+
${deprecatedIcon}${node.name ? html`<span class="key-label" title="${fieldTitle}">${node.name}${node.required ? html`<span style="color:var(--destructive)">*</span>` : ""}${readWriteBadge}:</span>` : ""}
|
|
298
|
+
${openBracket}
|
|
299
|
+
</div>
|
|
300
|
+
${this.renderDescrCell(node.description)}
|
|
301
|
+
</div>
|
|
302
|
+
<div class="inside-bracket object" style="padding-left:${leftPadding}px;">
|
|
303
|
+
${node.properties?.map((p) => this.renderAST(p, "object", schemaLevel + 1, indentLevel + 1))}
|
|
304
|
+
${node.patternProperties?.map((p) => this.renderAST(p, "object", schemaLevel + 1, indentLevel + 1))}
|
|
305
|
+
${node.additionalProperties ? this.renderAST(node.additionalProperties, "object", schemaLevel + 1, indentLevel + 1) : ""}
|
|
306
|
+
${node.unions?.map((u) => this.renderAST(u, "object", schemaLevel + 1, indentLevel + 1))}
|
|
307
|
+
</div>
|
|
308
|
+
<div class="close-bracket">${closeBracket}</div>
|
|
309
|
+
`;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
// 3. Union kind (oneOf / anyOf)
|
|
313
|
+
if (node.kind === "union") {
|
|
314
|
+
const opLabel =
|
|
315
|
+
(node.operator === "anyOf" ? "ANY OF" : "ONE OF") + (node.suffix ? ` ${node.suffix}` : "");
|
|
316
|
+
const newIndent = parentType === "xxx-of-option" ? indentLevel : indentLevel + 1;
|
|
317
|
+
// Options are already labelled by their OPT row, so only property names are shown
|
|
318
|
+
const showName = node.name && parentType !== "xxx-of-option";
|
|
319
|
+
// A named union puts its label and options one level inside the property row
|
|
320
|
+
const bodyFieldColWidth = showName ? minFieldColWidth - leftPadding : minFieldColWidth;
|
|
321
|
+
|
|
322
|
+
const unionBody = html`
|
|
323
|
+
<div class="tr expanded xxx-of-option">
|
|
324
|
+
<div class="td key" style="min-width:${bodyFieldColWidth}px">
|
|
325
|
+
<span class="key-label xxx-of-key">${opLabel}</span>
|
|
326
|
+
</div>
|
|
327
|
+
${showName ? "" : this.renderDescrCell(node.description)}
|
|
328
|
+
</div>
|
|
329
|
+
<div class="inside-bracket xxx-of-option" style="padding-left:0px;">
|
|
330
|
+
${node.options?.map(
|
|
331
|
+
(opt, i) => html`
|
|
332
|
+
<div>
|
|
333
|
+
<div class="tr expanded xxx-of-option">
|
|
334
|
+
<div class="td key" style="min-width:${bodyFieldColWidth}px">
|
|
335
|
+
<span class="key-label xxx-of-key">OPT ${opt.optionIndex || i + 1}</span>
|
|
336
|
+
${opt.optionTitle ? html`<span class="xxx-of-descr">${opt.optionTitle}</span>` : ""}
|
|
337
|
+
</div>
|
|
338
|
+
</div>
|
|
339
|
+
${this.renderAST(opt, "xxx-of-option", schemaLevel, newIndent)}
|
|
340
|
+
</div>
|
|
341
|
+
`,
|
|
342
|
+
)}
|
|
343
|
+
</div>
|
|
344
|
+
`;
|
|
345
|
+
|
|
346
|
+
return html`
|
|
347
|
+
${node.properties?.map((p) => this.renderAST(p, "object", schemaLevel, indentLevel))}
|
|
348
|
+
${
|
|
349
|
+
showName
|
|
350
|
+
? html`
|
|
351
|
+
<div class="tr expanded xxx-of-prop">
|
|
352
|
+
<div class="td key" style="min-width:${minFieldColWidth}px">
|
|
353
|
+
<span class="key-label" title="${node.name}"
|
|
354
|
+
>${node.name}${node.required ? html`<span style="color:var(--destructive)">*</span>` : ""}:</span
|
|
355
|
+
>
|
|
356
|
+
</div>
|
|
357
|
+
${this.renderDescrCell(node.description)}
|
|
358
|
+
</div>
|
|
359
|
+
<div class="inside-bracket xxx-of-option" style="padding-left:${leftPadding}px;">${unionBody}</div>
|
|
360
|
+
`
|
|
361
|
+
: unionBody
|
|
362
|
+
}
|
|
363
|
+
`;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// 4. Primitive kind
|
|
367
|
+
if (node.kind === "primitive") {
|
|
368
|
+
const dataTypeCss = this.getDataTypeCss(node.type);
|
|
369
|
+
const fieldTitle = node.name ? `${node.name}${readWriteTip ? ` (${readWriteTip})` : ""}` : "";
|
|
370
|
+
|
|
371
|
+
return html`
|
|
372
|
+
<div class="tr primitive" title="${node.deprecated ? "Deprecated" : nothing}">
|
|
373
|
+
<div class="td key ${node.deprecated ? "deprecated" : ""}" style="min-width:${minFieldColWidth}px">
|
|
374
|
+
${deprecatedIcon}${node.name ? html`<span class="key-label" title="${fieldTitle}">${node.name}${node.required ? html`<span style="color:var(--destructive);">*</span>` : ""}:</span>` : ""}
|
|
375
|
+
<span class="${dataTypeCss}" title="${readWriteTip || nothing}"
|
|
376
|
+
>${parentType === "array" ? `[${node.type}]` : node.type}${readWriteBadge}</span
|
|
377
|
+
>
|
|
378
|
+
</div>
|
|
379
|
+
${this.renderDescrCell(node.description, node, node.title)}
|
|
380
|
+
</div>
|
|
381
|
+
`;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
return "";
|
|
385
|
+
}
|
|
386
|
+
}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import { LitElement, html, css } from "lit";
|
|
2
|
+
import { customElement, property } from "lit/decorators.js";
|
|
3
|
+
|
|
4
|
+
@customElement("tag-input")
|
|
5
|
+
export default class TagInput extends LitElement {
|
|
6
|
+
@property({ type: String }) placeholder = "";
|
|
7
|
+
|
|
8
|
+
@property({
|
|
9
|
+
type: Array,
|
|
10
|
+
attribute: "value",
|
|
11
|
+
hasChanged(newVal, oldVal) {
|
|
12
|
+
if (newVal === oldVal) return false;
|
|
13
|
+
if (!Array.isArray(newVal) || !Array.isArray(oldVal)) return true;
|
|
14
|
+
if (newVal.length !== oldVal.length) return true;
|
|
15
|
+
return newVal.some((v, i) => v !== oldVal[i]);
|
|
16
|
+
},
|
|
17
|
+
})
|
|
18
|
+
value = [];
|
|
19
|
+
|
|
20
|
+
// For backwards compatibility with static properties inspection in tests
|
|
21
|
+
static get properties() {
|
|
22
|
+
return Object.fromEntries(this.elementProperties || []);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
render() {
|
|
26
|
+
let tagItemTmpl = "";
|
|
27
|
+
if (Array.isArray(this.value)) {
|
|
28
|
+
tagItemTmpl = html`${this.value
|
|
29
|
+
.filter((v) => v !== "" && v !== null && v !== undefined && String(v).trim() !== "")
|
|
30
|
+
.map((v) => html`<span class="tag">${v}</span>`)}`;
|
|
31
|
+
}
|
|
32
|
+
return html`<div class="tags" @click="${(e) => this.focusEditor(e)}">
|
|
33
|
+
${tagItemTmpl}
|
|
34
|
+
<input
|
|
35
|
+
type="text"
|
|
36
|
+
class="editor"
|
|
37
|
+
@paste="${(e) => this.afterPaste(e)}"
|
|
38
|
+
@keydown="${(e) => this.afterKeyDown(e)}"
|
|
39
|
+
@blur="${(e) => this.onBlur(e)}"
|
|
40
|
+
placeholder="${this.placeholder || ""}"
|
|
41
|
+
/>
|
|
42
|
+
</div>`;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
focusEditor(e) {
|
|
46
|
+
if (e.target.classList.contains("tags")) {
|
|
47
|
+
this.shadowRoot?.querySelector(".editor")?.focus();
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
attributeChangedCallback(name, oldVal, newVal) {
|
|
52
|
+
if (name === "value") {
|
|
53
|
+
if (newVal && oldVal !== newVal) {
|
|
54
|
+
this.value = newVal.split(",").filter((v) => v.trim() !== "");
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
super.attributeChangedCallback(name, oldVal, newVal);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
dispatchEvents() {
|
|
61
|
+
this.dispatchEvent(
|
|
62
|
+
new CustomEvent("change", { bubbles: true, composed: true, detail: { value: this.value } }),
|
|
63
|
+
);
|
|
64
|
+
this.dispatchEvent(
|
|
65
|
+
new CustomEvent("input", { bubbles: true, composed: true, detail: { value: this.value } }),
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
afterPaste(e) {
|
|
70
|
+
const clipboardData = e.clipboardData || window.clipboardData;
|
|
71
|
+
const pastedData = clipboardData.getData("Text");
|
|
72
|
+
const pastedArray = pastedData ? pastedData.split(",").filter((v) => v.trim() !== "") : "";
|
|
73
|
+
if (pastedArray) {
|
|
74
|
+
if (Array.isArray(this.value)) {
|
|
75
|
+
this.value = [...this.value, ...pastedArray];
|
|
76
|
+
} else {
|
|
77
|
+
this.value = pastedArray;
|
|
78
|
+
}
|
|
79
|
+
this.dispatchEvents();
|
|
80
|
+
}
|
|
81
|
+
e.preventDefault();
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
afterKeyDown(e) {
|
|
85
|
+
if (e.key === "Enter" || e.keyCode === 13) {
|
|
86
|
+
e.stopPropagation();
|
|
87
|
+
e.preventDefault();
|
|
88
|
+
const val = e.target.value ? e.target.value.trim() : "";
|
|
89
|
+
if (val) {
|
|
90
|
+
if (Array.isArray(this.value)) {
|
|
91
|
+
this.value = [...this.value, val];
|
|
92
|
+
} else {
|
|
93
|
+
this.value = [val];
|
|
94
|
+
}
|
|
95
|
+
e.target.value = "";
|
|
96
|
+
this.dispatchEvents();
|
|
97
|
+
}
|
|
98
|
+
} else if (e.key === "Backspace" || e.key === "Delete" || e.keyCode === 8 || e.keyCode === 46) {
|
|
99
|
+
if (!e.target.value || e.target.value.length === 0) {
|
|
100
|
+
if (Array.isArray(this.value) && this.value.length > 0) {
|
|
101
|
+
e.preventDefault();
|
|
102
|
+
this.value = this.value.slice(0, -1);
|
|
103
|
+
this.dispatchEvents();
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
onBlur(e) {
|
|
110
|
+
const val = e.target.value ? e.target.value.trim() : "";
|
|
111
|
+
if (val) {
|
|
112
|
+
if (Array.isArray(this.value)) {
|
|
113
|
+
this.value = [...this.value, val];
|
|
114
|
+
} else {
|
|
115
|
+
this.value = [val];
|
|
116
|
+
}
|
|
117
|
+
e.target.value = "";
|
|
118
|
+
this.dispatchEvents();
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
static get styles() {
|
|
123
|
+
return [
|
|
124
|
+
css`
|
|
125
|
+
.tags {
|
|
126
|
+
display: flex;
|
|
127
|
+
flex-wrap: wrap;
|
|
128
|
+
align-items: center;
|
|
129
|
+
box-sizing: border-box;
|
|
130
|
+
/* Same height as the text inputs in a parameter row (see param-list-styles.js) */
|
|
131
|
+
min-height: calc(2.75 * var(--font-size-small) + 2px);
|
|
132
|
+
outline: none;
|
|
133
|
+
padding: 0;
|
|
134
|
+
border-radius: var(--radius);
|
|
135
|
+
border: 1px solid var(--input);
|
|
136
|
+
cursor: text;
|
|
137
|
+
overflow: hidden;
|
|
138
|
+
background: var(--input-background);
|
|
139
|
+
transition:
|
|
140
|
+
border-color 0.2s ease,
|
|
141
|
+
box-shadow 0.2s ease;
|
|
142
|
+
|
|
143
|
+
/* Same focus ring as the text inputs */
|
|
144
|
+
&:focus-within {
|
|
145
|
+
border-color: var(--primary);
|
|
146
|
+
box-shadow: var(--focus-shadow);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
.tag,
|
|
150
|
+
.editor {
|
|
151
|
+
padding: 3px;
|
|
152
|
+
margin: 2px;
|
|
153
|
+
}
|
|
154
|
+
/* Chips: a muted fill with the form-field border, so each one stands apart on a white or dark field */
|
|
155
|
+
.tag {
|
|
156
|
+
border: 1px solid var(--input);
|
|
157
|
+
background: var(--muted);
|
|
158
|
+
color: var(--foreground);
|
|
159
|
+
border-radius: var(--radius);
|
|
160
|
+
word-break: break-all;
|
|
161
|
+
font-size: var(--font-size-small);
|
|
162
|
+
}
|
|
163
|
+
.tag:hover ~ #cursor {
|
|
164
|
+
display: block;
|
|
165
|
+
}
|
|
166
|
+
.editor {
|
|
167
|
+
flex: 1;
|
|
168
|
+
border: 1px solid transparent;
|
|
169
|
+
color: var(--foreground);
|
|
170
|
+
min-width: 60px;
|
|
171
|
+
outline: none;
|
|
172
|
+
line-height: inherit;
|
|
173
|
+
font-family: inherit;
|
|
174
|
+
background: transparent;
|
|
175
|
+
font-size: calc(var(--font-size-small) + 1px);
|
|
176
|
+
}
|
|
177
|
+
.editor::placeholder {
|
|
178
|
+
color: var(--muted-foreground);
|
|
179
|
+
opacity: 1;
|
|
180
|
+
}
|
|
181
|
+
`,
|
|
182
|
+
];
|
|
183
|
+
}
|
|
184
|
+
}
|
package/src/index.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { customElement } from "lit/decorators.js";
|
|
2
|
+
import { OAUTH_CHANNEL, readOAuthReply } from "~/utils/oauth-utils";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The OAuth return page's element: the provider sends the sign-in popup back here with a code (or, in the legacy
|
|
6
|
+
* implicit flow, a token). It hands the reply to the page that opened the popup, which checks it (origin, popup
|
|
7
|
+
* window, state) before using it, then removes it from the address bar and history.
|
|
8
|
+
*
|
|
9
|
+
* Two ways to reach the opener, both limited to this site's origin: `window.opener.postMessage`, and a
|
|
10
|
+
* BroadcastChannel for when the provider's page cut the link to the opener (Cross-Origin-Opener-Policy).
|
|
11
|
+
*/
|
|
12
|
+
@customElement("oauth-receiver")
|
|
13
|
+
export default class OauthReceiver extends HTMLElement {
|
|
14
|
+
connectedCallback() {
|
|
15
|
+
const reply = readOAuthReply(window.location);
|
|
16
|
+
if (!reply) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
window.history.replaceState(null, "", window.location.pathname);
|
|
20
|
+
if (window.opener) {
|
|
21
|
+
window.opener.postMessage(reply, window.location.origin);
|
|
22
|
+
}
|
|
23
|
+
if (typeof BroadcastChannel === "function") {
|
|
24
|
+
const channel = new BroadcastChannel(OAUTH_CHANNEL);
|
|
25
|
+
channel.postMessage(reply);
|
|
26
|
+
channel.close();
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|