rapidoc 9.3.7 → 10.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.
Files changed (69) hide show
  1. package/README.md +193 -61
  2. package/dist/rapidoc-min.js +279 -3912
  3. package/package.json +24 -47
  4. package/.babelrc.json +0 -42
  5. package/.eslintrc +0 -53
  6. package/.github/FUNDING.yml +0 -13
  7. package/.github/workflow/words.yaml +0 -22
  8. package/CONTRIBUTING.md +0 -35
  9. package/dist/index.html +0 -6
  10. package/dist/index.html.gz +0 -0
  11. package/dist/rapidoc-min.js.LICENSE.txt +0 -64
  12. package/dist/rapidoc-min.js.LICENSE.txt.gz +0 -0
  13. package/dist/rapidoc-min.js.gz +0 -0
  14. package/dist/rapidoc-min.js.map +0 -1
  15. package/dist/rapidoc-min.js.map.gz +0 -0
  16. package/dist/rapidoc.js +0 -21594
  17. package/dist/report.html +0 -39
  18. package/index-hashroute.html +0 -65
  19. package/index.html +0 -249
  20. package/index1.html +0 -244
  21. package/jsconfig.json +0 -11
  22. package/logo.png +0 -0
  23. package/performance.html +0 -31
  24. package/src/components/api-request.js +0 -1787
  25. package/src/components/api-response.js +0 -335
  26. package/src/components/dialog-box.js +0 -73
  27. package/src/components/json-tree.js +0 -145
  28. package/src/components/schema-table.js +0 -358
  29. package/src/components/schema-tree.js +0 -378
  30. package/src/components/tag-input.js +0 -135
  31. package/src/index.js +0 -7
  32. package/src/json-schema-viewer.js +0 -345
  33. package/src/oauth-receiver.js +0 -56
  34. package/src/rapidoc-mini.js +0 -380
  35. package/src/rapidoc.js +0 -1082
  36. package/src/styles/border-styles.js +0 -24
  37. package/src/styles/custom-styles.js +0 -10
  38. package/src/styles/dialog-box-styles.js +0 -75
  39. package/src/styles/endpoint-styles.js +0 -202
  40. package/src/styles/flex-styles.js +0 -15
  41. package/src/styles/font-styles.js +0 -268
  42. package/src/styles/info-styles.js +0 -21
  43. package/src/styles/input-styles.js +0 -202
  44. package/src/styles/nav-styles.js +0 -198
  45. package/src/styles/prism-styles.js +0 -105
  46. package/src/styles/schema-styles.js +0 -121
  47. package/src/styles/tab-styles.js +0 -47
  48. package/src/styles/table-styles.js +0 -58
  49. package/src/templates/advance-search-template.js +0 -72
  50. package/src/templates/callback-template.js +0 -73
  51. package/src/templates/code-samples-template.js +0 -34
  52. package/src/templates/components-template.js +0 -76
  53. package/src/templates/endpoint-template.js +0 -249
  54. package/src/templates/expanded-endpoint-template.js +0 -197
  55. package/src/templates/focused-endpoint-template.js +0 -110
  56. package/src/templates/header-template.js +0 -66
  57. package/src/templates/json-schema-viewer-template.js +0 -185
  58. package/src/templates/logo-template.js +0 -18
  59. package/src/templates/main-body-template.js +0 -121
  60. package/src/templates/navbar-template.js +0 -272
  61. package/src/templates/overview-template.js +0 -79
  62. package/src/templates/security-scheme-template.js +0 -610
  63. package/src/templates/server-template.js +0 -115
  64. package/src/utils/color-utils.js +0 -59
  65. package/src/utils/common-utils.js +0 -168
  66. package/src/utils/schema-utils.js +0 -1086
  67. package/src/utils/spec-parser.js +0 -462
  68. package/src/utils/theme.js +0 -288
  69. package/webpack.config.js +0 -142
@@ -1,335 +0,0 @@
1
- import { LitElement, html, css } from 'lit';
2
- import { unsafeHTML } from 'lit/directives/unsafe-html.js'; // eslint-disable-line import/extensions
3
- import { marked } from 'marked';
4
- import { schemaInObjectNotation, generateExample, standardizeExample } from '~/utils/schema-utils';
5
- import FontStyles from '~/styles/font-styles';
6
- import FlexStyles from '~/styles/flex-styles';
7
- import TableStyles from '~/styles/table-styles';
8
- import InputStyles from '~/styles/input-styles';
9
- import TabStyles from '~/styles/tab-styles';
10
- import BorderStyles from '~/styles/border-styles';
11
- import CustomStyles from '~/styles/custom-styles';
12
- import '~/components/json-tree';
13
- import '~/components/schema-tree';
14
- import '~/components/schema-table';
15
-
16
- export default class ApiResponse extends LitElement {
17
- constructor() {
18
- super();
19
- this.selectedStatus = '';
20
- this.headersForEachRespStatus = {};
21
- this.mimeResponsesForEachStatus = {};
22
- this.activeSchemaTab = 'schema';
23
- }
24
-
25
- static get properties() {
26
- return {
27
- callback: { type: String },
28
- webhook: { type: String },
29
- responses: { type: Object },
30
- parser: { type: Object },
31
- schemaStyle: { type: String, attribute: 'schema-style' },
32
- renderStyle: { type: String, attribute: 'render-style' },
33
- selectedStatus: { type: String, attribute: 'selected-status' },
34
- selectedMimeType: { type: String, attribute: 'selected-mime-type' },
35
- activeSchemaTab: { type: String, attribute: 'active-schema-tab' },
36
- schemaExpandLevel: { type: Number, attribute: 'schema-expand-level' },
37
- schemaDescriptionExpanded: { type: String, attribute: 'schema-description-expanded' },
38
- allowSchemaDescriptionExpandToggle: { type: String, attribute: 'allow-schema-description-expand-toggle' },
39
- schemaHideReadOnly: { type: String, attribute: 'schema-hide-read-only' },
40
- schemaHideWriteOnly: { type: String, attribute: 'schema-hide-write-only' },
41
- };
42
- }
43
-
44
- static get styles() {
45
- return [
46
- FontStyles,
47
- FlexStyles,
48
- TabStyles,
49
- TableStyles,
50
- InputStyles,
51
- BorderStyles,
52
- css`
53
- :where(button, input[type="checkbox"], [tabindex="0"]):focus-visible { box-shadow: var(--focus-shadow); }
54
- :where(input[type="text"], input[type="password"], select, textarea):focus-visible { border-color: var(--primary-color); }
55
- .resp-head{
56
- vertical-align: middle;
57
- padding:16px 0 8px;
58
- }
59
- .resp-head.divider{
60
- border-top: 1px solid var(--border-color);
61
- margin-top:10px;
62
- }
63
- .resp-status{
64
- font-weight:bold;
65
- font-size:calc(var(--font-size-small) + 1px);
66
- }
67
- .resp-descr{
68
- font-size:calc(var(--font-size-small) + 1px);
69
- color:var(--light-fg);
70
- text-align:left;
71
- }
72
- .top-gap{margin-top:16px;}
73
- .example-panel{
74
- font-size:var(--font-size-small);
75
- margin:0;
76
- }
77
- .focused-mode,
78
- .read-mode {
79
- padding-top:24px;
80
- margin-top:12px;
81
- border-top: 1px dashed var(--border-color);
82
- }`,
83
- CustomStyles,
84
- ];
85
- }
86
-
87
- render() {
88
- return html`
89
- <div class="col regular-font response-panel ${this.renderStyle}-mode">
90
- <div class=" ${this.callback === 'true' ? 'tiny-title' : 'req-res-title'} ">
91
- ${this.callback === 'true' ? 'CALLBACK RESPONSE' : 'RESPONSE'}
92
- </div>
93
- <div>
94
- ${this.responseTemplate()}
95
- </div>
96
- </div>
97
- `;
98
- }
99
-
100
- resetSelection() {
101
- this.selectedStatus = '';
102
- this.selectedMimeType = '';
103
- }
104
-
105
- /* eslint-disable indent */
106
- responseTemplate() {
107
- if (!this.responses) { return ''; }
108
- for (const statusCode in this.responses) {
109
- if (!this.selectedStatus) {
110
- this.selectedStatus = statusCode;
111
- }
112
- const allMimeResp = {};
113
- for (const mimeResp in this.responses[statusCode]?.content) {
114
- const mimeRespObj = this.responses[statusCode].content[mimeResp];
115
- if (!this.selectedMimeType) {
116
- this.selectedMimeType = mimeResp;
117
- }
118
- // Generate Schema
119
- const schemaTree = schemaInObjectNotation(mimeRespObj.schema, {});
120
- // Generate Example
121
- const respExamples = generateExample(
122
- mimeRespObj.schema,
123
- mimeResp,
124
- standardizeExample(mimeRespObj.examples),
125
- standardizeExample(mimeRespObj.example),
126
- this.callback === 'true' || this.webhook === 'true' ? false : true, // eslint-disable-line no-unneeded-ternary
127
- this.callback === 'true' || this.webhook === 'true' ? true : false, // eslint-disable-line no-unneeded-ternary
128
- mimeResp.includes('json') ? 'json' : 'text',
129
- );
130
- allMimeResp[mimeResp] = {
131
- description: this.responses[statusCode].description,
132
- examples: respExamples,
133
- selectedExample: respExamples[0]?.exampleId || '',
134
- schemaTree,
135
- };
136
- }
137
- // Headers for each response status
138
- const tempHeaders = [];
139
- for (const key in this.responses[statusCode]?.headers) {
140
- tempHeaders.push({ name: key, ...this.responses[statusCode].headers[key] });
141
- }
142
- this.headersForEachRespStatus[statusCode] = tempHeaders;
143
- this.mimeResponsesForEachStatus[statusCode] = allMimeResp;
144
- }
145
- return html`
146
- ${Object.keys(this.responses).length > 1
147
- ? html`<div class='row' style='flex-wrap:wrap'>
148
- ${Object.keys(this.responses).map((respStatus) => html`
149
- ${respStatus === '$$ref' // Swagger-Client parser creates '$$ref' object if JSON references are used to create responses - this should be ignored
150
- ? ''
151
- : html`
152
- <button
153
- @click="${() => {
154
- this.selectedStatus = respStatus;
155
- if (this.responses[respStatus].content && Object.keys(this.responses[respStatus].content)[0]) {
156
- this.selectedMimeType = Object.keys(this.responses[respStatus].content)[0]; // eslint-disable-line prefer-destructuring
157
- } else {
158
- this.selectedMimeType = undefined;
159
- }
160
- }}"
161
- class='m-btn small ${this.selectedStatus === respStatus ? 'primary' : ''}'
162
- part="btn ${this.selectedStatus === respStatus ? 'btn-response-status btn-selected-response-status' : ' btn-response-status'}"
163
- style='margin: 8px 4px 0 0'
164
- >
165
- ${respStatus}
166
- </button>`
167
- }`)
168
- }</div>`
169
- : html`<span>${Object.keys(this.responses)[0]}</span>`
170
- }
171
-
172
- ${Object.keys(this.responses).map((status) => html`
173
- <div style = 'display: ${status === this.selectedStatus ? 'block' : 'none'}' >
174
- <div class="top-gap">
175
- <span class="resp-descr m-markdown ">${unsafeHTML(marked(this.responses[status]?.description || ''))}</span>
176
- ${(this.headersForEachRespStatus[status] && this.headersForEachRespStatus[status]?.length > 0)
177
- ? html`${this.responseHeaderListTemplate(this.headersForEachRespStatus[status])}`
178
- : ''
179
- }
180
- </div>
181
- ${Object.keys(this.mimeResponsesForEachStatus[status]).length === 0
182
- ? ''
183
- : html`
184
- <div class="tab-panel col">
185
- <div class="tab-buttons row" @click="${(e) => { if (e.target.tagName.toLowerCase() === 'button') { this.activeSchemaTab = e.target.dataset.tab; } }}" >
186
- <button class="tab-btn ${this.activeSchemaTab === 'example' ? 'active' : ''}" data-tab = 'example'>EXAMPLE </button>
187
- <button class="tab-btn ${this.activeSchemaTab !== 'example' ? 'active' : ''}" data-tab = 'schema' >SCHEMA</button>
188
- <div style="flex:1"></div>
189
- ${Object.keys(this.mimeResponsesForEachStatus[status]).length === 1
190
- ? html`<span class='small-font-size gray-text' style='align-self:center; margin-top:8px;'> ${Object.keys(this.mimeResponsesForEachStatus[status])[0]} </span>`
191
- : html`${this.mimeTypeDropdownTemplate(Object.keys(this.mimeResponsesForEachStatus[status]))}`
192
- }
193
- </div>
194
- ${this.activeSchemaTab === 'example'
195
- ? html`<div class ='tab-content col' style = 'flex:1;'>
196
- ${this.mimeExampleTemplate(this.mimeResponsesForEachStatus[status][this.selectedMimeType])}
197
- </div>`
198
- : html`<div class ='tab-content col' style = 'flex:1;'>
199
- ${this.mimeSchemaTemplate(this.mimeResponsesForEachStatus[status][this.selectedMimeType])}
200
- </div>`
201
- }
202
- </div>
203
- `
204
- }</div>`)
205
- }
206
- `;
207
- }
208
-
209
- responseHeaderListTemplate(respHeaders) {
210
- return html`
211
- <div style="padding:16px 0 8px 0" class="resp-headers small-font-size bold-text">RESPONSE HEADERS</div>
212
- <table role="presentation" style="border-collapse: collapse; margin-bottom:16px; border:1px solid var(--border-color); border-radius: var(--border-radius)" class="small-font-size mono-font">
213
- ${respHeaders.map((v) => html`
214
- <tr>
215
- <td style="padding:8px; vertical-align: baseline; min-width:120px; border-top: 1px solid var(--light-border-color); text-overflow: ellipsis;">
216
- ${v.name || ''}
217
- </td>
218
- <td style="padding:4px; vertical-align: baseline; padding:0 5px; border-top: 1px solid var(--light-border-color); text-overflow: ellipsis;">
219
- ${v.schema?.type || ''}
220
- </td>
221
- <td style="padding:8px; vertical-align: baseline; border-top: 1px solid var(--light-border-color);text-overflow: ellipsis;">
222
- <div class="m-markdown-small regular-font" >${unsafeHTML(marked(v.description || ''))}</div>
223
- </td>
224
- <td style="padding:8px; vertical-align: baseline; border-top: 1px solid var(--light-border-color); text-overflow: ellipsis;">
225
- ${v.schema?.example || ''}
226
- </td>
227
- </tr>
228
- `)}
229
- </table>`;
230
- }
231
-
232
- mimeTypeDropdownTemplate(mimeTypes) {
233
- return html`
234
- <select aria-label='mime types' @change="${(e) => { this.selectedMimeType = e.target.value; }}" style='margin-bottom: -1px; z-index:1'>
235
- ${mimeTypes.map((mimeType) => html`<option value='${mimeType}' ?selected = '${mimeType === this.selectedMimeType}'> ${mimeType} </option>`)}
236
- </select>`;
237
- }
238
-
239
- onSelectExample(e) {
240
- const exampleContainerEl = e.target.closest('.example-panel');
241
- const exampleEls = [...exampleContainerEl.querySelectorAll('.example')];
242
-
243
- exampleEls.forEach((v) => {
244
- v.style.display = v.dataset.example === e.target.value ? 'block' : 'none';
245
- });
246
- }
247
-
248
- mimeExampleTemplate(mimeRespDetails) {
249
- if (!mimeRespDetails) {
250
- return html`
251
- <pre style='color:var(--red)' class = '${this.renderStyle === 'read' ? 'read example-panel border pad-8-16' : 'example-panel border-top'}'> No example provided </pre>
252
- `;
253
- }
254
- return html`
255
- ${mimeRespDetails.examples.length === 1
256
- ? html`
257
- ${mimeRespDetails.examples[0].exampleFormat === 'json'
258
- ? html`
259
- ${mimeRespDetails.examples[0].exampleSummary && mimeRespDetails.examples[0].exampleSummary.length > 80 ? html`<div style="padding: 4px 0"> ${mimeRespDetails.examples[0].exampleSummary} </div>` : ''}
260
- ${mimeRespDetails.examples[0].exampleDescription ? html`<div class="m-markdown-small" style="padding: 4px 0"> ${unsafeHTML(marked(mimeRespDetails.examples[0].exampleDescription || ''))} </div>` : ''}
261
- <json-tree
262
- render-style = '${this.renderStyle}'
263
- .data="${mimeRespDetails.examples[0].exampleValue}"
264
- class = 'example-panel ${this.renderStyle === 'read' ? 'border pad-8-16' : 'border-top pad-top-8'}'
265
- exportparts = "btn:btn, btn-fill:btn-fill, btn-copy:btn-copy"
266
- ></json-tree>`
267
- : html`
268
- ${mimeRespDetails.examples[0].exampleSummary && mimeRespDetails.examples[0].exampleSummary.length > 80 ? html`<div style="padding: 4px 0"> ${mimeRespDetails.examples[0].exampleSummary} </div>` : ''}
269
- ${mimeRespDetails.examples[0].exampleDescription ? html`<div class="m-markdown-small" style="padding: 4px 0"> ${unsafeHTML(marked(mimeRespDetails.examples[0].exampleDescription || ''))} </div>` : ''}
270
- <pre class = 'example-panel ${this.renderStyle === 'read' ? 'border pad-8-16' : 'border-top pad-top-8'}'>${mimeRespDetails.examples[0].exampleValue}</pre>
271
- `
272
- }`
273
- : html`
274
- <span class = 'example-panel ${this.renderStyle === 'read' ? 'border pad-8-16' : 'border-top pad-top-8'}'>
275
- <select aria-label='response examples' style="min-width:100px; max-width:100%" @change='${(e) => this.onSelectExample(e)}'>
276
- ${mimeRespDetails.examples.map((v) => html`<option value="${v.exampleId}" ?selected=${v.exampleId === mimeRespDetails.selectedExample} >
277
- ${v.exampleSummary.length > 80 ? v.exampleId : v.exampleSummary}
278
- </option>`)}
279
- </select>
280
- ${mimeRespDetails.examples.map((v) => html`
281
- <div class="example" data-example = '${v.exampleId}' style = "display: ${v.exampleId === mimeRespDetails.selectedExample ? 'block' : 'none'}">
282
- ${v.exampleSummary && v.exampleSummary.length > 80 ? html`<div style="padding: 4px 0"> ${v.exampleSummary} </div>` : ''}
283
- ${v.exampleDescription ? html`<div class="m-markdown-small" style="padding: 4px 0"> ${unsafeHTML(marked(v.exampleDescription || ''))} </div>` : ''}
284
- ${v.exampleFormat === 'json'
285
- ? html`
286
- <json-tree
287
- render-style = '${this.renderStyle}'
288
- .data = '${v.exampleValue}'
289
- exportparts = "btn:btn, btn-fill:btn-fill, btn-copy:btn-copy"
290
- ></json-tree>`
291
- : html`<pre>${v.exampleValue}</pre>`
292
- }
293
- </div>
294
- `)}
295
- </span>
296
- `
297
- }
298
- `;
299
- }
300
-
301
- mimeSchemaTemplate(mimeRespDetails) {
302
- if (!mimeRespDetails) {
303
- return html`
304
- <pre style='color:var(--red)' class = '${this.renderStyle === 'read' ? 'border pad-8-16' : 'border-top'}'> Schema not found</pre>
305
- `;
306
- }
307
- return html`
308
- ${this.schemaStyle === 'table'
309
- ? html`
310
- <schema-table
311
- .data = "${mimeRespDetails.schemaTree}"
312
- schema-expand-level = "${this.schemaExpandLevel}"
313
- schema-description-expanded = "${this.schemaDescriptionExpanded}"
314
- allow-schema-description-expand-toggle = "${this.allowSchemaDescriptionExpandToggle}"
315
- schema-hide-read-only = "${this.schemaHideReadOnly}"
316
- schema-hide-write-only = "${this.schemaHideWriteOnly}"
317
- exportparts = "schema-description:schema-description, schema-multiline-toggle:schema-multiline-toggle"
318
- > </schema-table> `
319
- : html`
320
- <schema-tree
321
- .data = '${mimeRespDetails.schemaTree}'
322
- schema-expand-level = "${this.schemaExpandLevel}"
323
- schema-description-expanded = "${this.schemaDescriptionExpanded}"
324
- allow-schema-description-expand-toggle = "${this.allowSchemaDescriptionExpandToggle}"
325
- schema-hide-read-only = "${this.schemaHideReadOnly}"
326
- schema-hide-write-only = "${this.schemaHideWriteOnly}"
327
- exportparts = "schema-description:schema-description, schema-multiline-toggle:schema-multiline-toggle"
328
- > </schema-tree>`
329
- }`;
330
- }
331
- /* eslint-enable indent */
332
- }
333
-
334
- // Register the element with the browser
335
- customElements.define('api-response', ApiResponse);
@@ -1,73 +0,0 @@
1
- import { LitElement, html } from 'lit';
2
- import DialogBoxStyles from '~/styles/dialog-box-styles';
3
-
4
- export default class DialogBox extends LitElement {
5
- static get properties() {
6
- return {
7
- heading: { type: String, attribute: 'heading' },
8
- show: { type: String, attribute: 'show' },
9
- };
10
- }
11
-
12
- static get styles() {
13
- return [DialogBoxStyles];
14
- }
15
-
16
- connectedCallback() {
17
- super.connectedCallback();
18
- document.addEventListener('keydown', (e) => {
19
- if (e.code === 'Escape') {
20
- this.onClose();
21
- }
22
- });
23
- }
24
-
25
- attributeChangedCallback(name, oldVal, newVal) {
26
- if (oldVal !== newVal) {
27
- if (name === 'heading') {
28
- this.heading = newVal;
29
- }
30
- if (name === 'show') {
31
- this.show = newVal;
32
- if (newVal === 'true') {
33
- document.dispatchEvent(new CustomEvent('open', {
34
- bubbles: true,
35
- composed: true,
36
- detail: this,
37
- }));
38
- }
39
- }
40
- }
41
- super.attributeChangedCallback(name, oldVal, newVal);
42
- }
43
-
44
- /* eslint-disable indent */
45
- render() {
46
- return html`
47
- ${this.show === 'true'
48
- ? html`
49
- <div class="dialog-box-overlay">
50
- <div class="dialog-box">
51
- <header class="dialog-box-header">
52
- <span class="dialog-box-title">${this.heading}</span>
53
- <button type="button" @click="${this.onClose}">&times;</button>
54
- </header>
55
- <div class="dialog-box-content">
56
- <slot></slot>
57
- </div>
58
- </div>
59
- </div>`
60
- : ''
61
- }`;
62
- }
63
- /* eslint-enable indent */
64
-
65
- onClose() {
66
- document.dispatchEvent(new CustomEvent('close', {
67
- bubbles: true,
68
- composed: true,
69
- }));
70
- }
71
- }
72
-
73
- customElements.define('dialog-box', DialogBox);
@@ -1,145 +0,0 @@
1
- import { LitElement, html, css } from 'lit';
2
- import { copyToClipboard } from '~/utils/common-utils';
3
- import FontStyles from '~/styles/font-styles';
4
- import BorderStyles from '~/styles/border-styles';
5
- import InputStyles from '~/styles/input-styles';
6
- import CustomStyles from '~/styles/custom-styles';
7
-
8
- export default class JsonTree extends LitElement {
9
- static get properties() {
10
- return {
11
- data: { type: Object },
12
- renderStyle: { type: String, attribute: 'render-style' },
13
- };
14
- }
15
-
16
- static get styles() {
17
- return [
18
- FontStyles,
19
- BorderStyles,
20
- InputStyles,
21
- css`
22
- :host{
23
- display:flex;
24
- }
25
- :where(button, input[type="checkbox"], [tabindex="0"]):focus-visible { box-shadow: var(--focus-shadow); }
26
- :where(input[type="text"], input[type="password"], select, textarea):focus-visible { border-color: var(--primary-color); }
27
- .json-tree {
28
- position: relative;
29
- font-family: var(--font-mono);
30
- font-size: var(--font-size-small);
31
- display:inline-block;
32
- overflow:hidden;
33
- word-break: break-all;
34
- flex:1;
35
- line-height: calc(var(--font-size-small) + 6px);
36
- min-height: 40px;
37
- direction: ltr;
38
- text-align: left;
39
- }
40
-
41
- .open-bracket {
42
- display:inline-block;
43
- padding: 0 20px 0 0;
44
- cursor:pointer;
45
- border: 1px solid transparent;
46
- border-radius:3px;
47
- }
48
- .close-bracket {
49
- border: 1px solid transparent;
50
- border-radius:3px;
51
- display:inline-block;
52
- }
53
- .open-bracket:hover {
54
- color:var(--primary-color);
55
- background-color:var(--hover-color);
56
- border: 1px solid var(--border-color);
57
- }
58
- .open-bracket.expanded:hover ~ .inside-bracket {
59
- border-left: 1px solid var(--fg3);
60
- }
61
- .open-bracket.expanded:hover ~ .close-bracket {
62
- color:var(--primary-color);
63
- }
64
- .inside-bracket {
65
- padding-left:12px;
66
- overflow: hidden;
67
- border-left:1px dotted var(--border-color);
68
- }
69
- .open-bracket.collapsed + .inside-bracket,
70
- .open-bracket.collapsed + .inside-bracket + .close-bracket {
71
- display:none;
72
- }
73
-
74
- .string{color:var(--green);}
75
- .number{color:var(--blue);}
76
- .null{color:var(--red);}
77
- .boolean{color:var(--purple);}
78
- .object{color:var(--fg)}
79
- .toolbar {
80
- position: absolute;
81
- top:5px;
82
- right:6px;
83
- display:flex;
84
- padding:2px;
85
- align-items: center;
86
- }`,
87
- CustomStyles,
88
- ];
89
- }
90
-
91
- /* eslint-disable indent */
92
- render() {
93
- return html`
94
- <div class = "json-tree" @click='${(e) => { if (e.target.classList.contains('btn-copy')) { copyToClipboard(JSON.stringify(this.data, null, 2), e); } else { this.toggleExpand(e); } }}'>
95
- <div class='toolbar'>
96
- <button class="toolbar-btn btn-copy" part="btn btn-fill btn-copy"> Copy </button>
97
- </div>
98
- ${this.generateTree(this.data, true)}
99
- </div>
100
- `;
101
- }
102
-
103
- generateTree(data, isLast = false) {
104
- if (data === null) {
105
- return html`<div class="null" style="display:inline;">null</div>`;
106
- }
107
- if (typeof data === 'object' && (data instanceof Date === false)) {
108
- const detailType = Array.isArray(data) ? 'array' : 'pure_object';
109
- if (Object.keys(data).length === 0) {
110
- return html`${(Array.isArray(data) ? '[ ],' : '{ },')}`;
111
- }
112
- return html`
113
- <div class="open-bracket expanded ${detailType === 'array' ? 'array' : 'object'}" > ${detailType === 'array' ? '[' : '{'}</div>
114
- <div class="inside-bracket">
115
- ${Object.keys(data).map((key, i, a) => html`
116
- <div class="item">
117
- ${detailType === 'pure_object' ? html`"${key}":` : ''}
118
- ${this.generateTree(data[key], i === (a.length - 1))}
119
- </div>`)
120
- }
121
- </div>
122
- <div class="close-bracket">${detailType === 'array' ? ']' : '}'}${isLast ? '' : ','}</div>
123
- `;
124
- }
125
- return (typeof data === 'string' || data instanceof Date)
126
- ? html`<span class="${typeof data}">"${data}"</span>${isLast ? '' : ','}`
127
- : html`<span class="${typeof data}">${data}</span>${isLast ? '' : ','}`;
128
- }
129
- /* eslint-enable indent */
130
-
131
- toggleExpand(e) {
132
- const openBracketEl = e.target;
133
- if (e.target.classList.contains('open-bracket')) {
134
- if (openBracketEl.classList.contains('expanded')) {
135
- openBracketEl.classList.replace('expanded', 'collapsed');
136
- e.target.innerHTML = e.target.classList.contains('array') ? '[...]' : '{...}';
137
- } else {
138
- openBracketEl.classList.replace('collapsed', 'expanded');
139
- e.target.innerHTML = e.target.classList.contains('array') ? '[' : '{';
140
- }
141
- }
142
- }
143
- }
144
- // Register the element with the browser
145
- customElements.define('json-tree', JsonTree);