openapi-explorer 2.4.801 → 2.4.820

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.
@@ -455,7 +455,7 @@ export default class ApiRequest extends LitElement {
455
455
  return;
456
456
  }
457
457
  this.activeResponseTab = e.target.dataset.tab;
458
- }}"> <br> <div style="width:100%"> <button class="tab-btn ${!hasResponse || this.activeResponseTab === 'curl' ? 'active' : ''}" data-tab="curl">${getI18nText('operations.request')}</button> ${!hasResponse ? '' : html` <button class="tab-btn ${this.activeResponseTab === 'response' ? 'active' : ''}" data-tab="response">${getI18nText('operations.response')}</button> <button class="tab-btn ${this.activeResponseTab === 'headers' ? 'active' : ''}" data-tab="headers">${getI18nText('operations.response-headers')}</button>`} </div> </div> ${this.responseIsBlob ? html` <div class="tab-content col" style="flex:1;display:${this.activeResponseTab === 'response' ? 'flex' : 'none'}"> ${this.responseBlobType === 'image' ? html`<img style="max-height:var(--resp-area-height,300px);object-fit:contain" class="mar-top-8" src="${this.responseBlobUrl}">` : ''} <div style="display:flex;justify-content:center"> <div> <button class="m-btn thin-border mar-top-8" style="width:135px" @click="${this.downloadResponseBlob}" part="btn btn-outline">DOWNLOAD</button> ${this.responseBlobType === 'view' || this.responseBlobType === 'image' ? html`<button class="m-btn thin-border mar-top-8" style="width:135px" @click="${this.viewResponseBlob}" part="btn btn-outline">VIEW (NEW TAB)</button>` : ''} </div> </div> </div>` : html` <div class="tab-content col m-markdown" style="flex:1;display:${this.activeResponseTab === 'response' ? 'flex' : 'none'}"> <syntax-highlighter style="min-height:60px" mime-type="${this.responseContentType}" .content="${this.responseText}"> </div>`} <div class="tab-content col m-markdown" style="flex:1;display:${this.activeResponseTab === 'headers' ? 'flex' : 'none'}"> <syntax-highlighter style="min-height:60px" language="http" .content="${this.responseHeaders}"> </div> <div class="tab-content m-markdown col" style="flex:1;display:${this.activeResponseTab === 'curl' ? 'flex' : 'none'}"> <syntax-highlighter style="min-height:60px" language="shell" .content="${curlSyntax.trim()}"> </div> </div>`;
458
+ }}"> <br> <div style="width:100%"> <button class="tab-btn ${!hasResponse || this.activeResponseTab === 'curl' ? 'active' : ''}" data-tab="curl">${getI18nText('operations.request')}</button> ${!hasResponse ? '' : html` <button class="tab-btn ${this.activeResponseTab === 'response' ? 'active' : ''}" data-tab="response">${getI18nText('operations.response')}</button> <button class="tab-btn ${this.activeResponseTab === 'headers' ? 'active' : ''}" data-tab="headers">${getI18nText('operations.response-headers')}</button>`} </div> </div> ${this.responseIsBlob ? html` <div class="tab-content col" style="flex:1;display:${this.activeResponseTab === 'response' ? 'flex' : 'none'}"> ${this.responseBlobType === 'image' ? html`<img style="max-height:var(--resp-area-height,300px);object-fit:contain" class="mar-top-8" src="${this.responseBlobUrl}">` : ''} <div style="display:flex;justify-content:center"> <div> <button class="m-btn thin-border mar-top-8" style="width:135px" @click="${this.downloadResponseBlob}" part="btn btn-outline">DOWNLOAD</button> ${this.responseBlobType === 'view' || this.responseBlobType === 'image' ? html`<button class="m-btn thin-border mar-top-8" style="width:135px" @click="${this.viewResponseBlob}" part="btn btn-outline">VIEW (NEW TAB)</button>` : ''} </div> </div> </div>` : html` <div class="tab-content col m-markdown" style="flex:1;display:${this.activeResponseTab === 'response' ? 'flex' : 'none'}"> <syntax-highlighter style="min-height:60px" mime-type="${this.responseContentType}" .content="${this.responseText}" .label="${getI18nText('operations.response')}"> </div>`} <div class="tab-content col m-markdown" style="flex:1;display:${this.activeResponseTab === 'headers' ? 'flex' : 'none'}"> <syntax-highlighter style="min-height:60px" language="http" .content="${this.responseHeaders}" .label="${getI18nText('operations.response-headers')}"> </div> <div class="tab-content m-markdown col" style="flex:1;display:${this.activeResponseTab === 'curl' ? 'flex' : 'none'}"> <syntax-highlighter style="min-height:60px" language="shell" .content="${curlSyntax.trim()}" .label="${getI18nText('operations.request')}"> </div> </div>`;
459
459
  }
460
460
  apiCallTemplate() {
461
461
  return html` <div style="display:flex;align-items:flex-end;margin:16px 0;font-size:var(--font-size-small)"> ${this.parameters.length > 0 || this.request_body ? html` <button class="m-btn thin-border" part="btn btn-outline" style="margin-right:5px" @click="${this.onClearRequestData}"> ${getI18nText('operations.clear')} </button>` : ''} <button class="m-btn primary btn-execute thin-border" part="btn btn-fill btn-try" @click="${this.onTryClick}">${getI18nText('operations.execute')}</button> </div> ${this.apiResponseTabTemplate()} `;
@@ -160,7 +160,7 @@ export default class ApiResponse extends LitElement {
160
160
  if (!mimeRespDetails) {
161
161
  return html` <pre style="color:var(--red)" class="example-panel border-top"> No example provided </pre> `;
162
162
  }
163
- return html` ${mimeRespDetails.examples.length === 1 ? html` ${mimeRespDetails.examples[0].exampleSummary && mimeRespDetails.examples[0].exampleSummary.length > 80 ? html`<div style="padding:4px 0"> ${mimeRespDetails.examples[0].exampleSummary} </div>` : ''} ${mimeRespDetails.examples[0].exampleDescription ? html`<div class="m-markdown-small" style="padding:4px 0"> ${unsafeHTML(toMarkdown(mimeRespDetails.examples[0].exampleDescription || ''))} </div>` : ''} <syntax-highlighter class="example-panel generic-tree pad-top-8" mime-type="${mimeRespDetails.examples[0].exampleType}" .content="${mimeRespDetails.examples[0].exampleValue}">` : html` <span class="example-panel generic-tree ${this.renderStyle === 'read' ? 'border pad-8-16' : 'border-top pad-top-8'}"> <select aria-label="response body example" @change="${e => this.onSelectExample(e)}"> ${mimeRespDetails.examples.map(v => html`<option value="${v.exampleId}" ?selected="${v.exampleId === mimeRespDetails.selectedExample}"> ${!v.exampleSummary || v.exampleSummary.length > 80 ? v.exampleId : v.exampleSummary} </option>`)} </select> ${mimeRespDetails.examples.map(v => html` <div class="example" data-example="${v.exampleId}" style="display:${v.exampleId === mimeRespDetails.selectedExample ? 'block' : 'none'}"> ${v.exampleSummary && v.exampleSummary.length > 80 ? html`<div style="padding:4px 0"> ${v.exampleSummary} </div>` : ''} ${v.exampleDescription && v.exampleDescription !== v.exampleSummary ? html`<div class="m-markdown-small" style="padding:4px 0"> ${unsafeHTML(toMarkdown(v.exampleDescription || ''))} </div>` : ''} <syntax-highlighter mime-type="${v.exampleType}" .content="${v.exampleValue}"> </div> `)} </span> `} `;
163
+ return html` ${mimeRespDetails.examples.length === 1 ? html` ${mimeRespDetails.examples[0].exampleSummary && mimeRespDetails.examples[0].exampleSummary.length > 80 ? html`<div style="padding:4px 0"> ${mimeRespDetails.examples[0].exampleSummary} </div>` : ''} ${mimeRespDetails.examples[0].exampleDescription ? html`<div class="m-markdown-small" style="padding:4px 0"> ${unsafeHTML(toMarkdown(mimeRespDetails.examples[0].exampleDescription || ''))} </div>` : ''} <syntax-highlighter class="example-panel generic-tree pad-top-8" mime-type="${mimeRespDetails.examples[0].exampleType}" .content="${mimeRespDetails.examples[0].exampleValue}" .label="${getI18nText('operations.response')}">` : html` <span class="example-panel generic-tree ${this.renderStyle === 'read' ? 'border pad-8-16' : 'border-top pad-top-8'}"> <select aria-label="response body example" @change="${e => this.onSelectExample(e)}"> ${mimeRespDetails.examples.map(v => html`<option value="${v.exampleId}" ?selected="${v.exampleId === mimeRespDetails.selectedExample}"> ${!v.exampleSummary || v.exampleSummary.length > 80 ? v.exampleId : v.exampleSummary} </option>`)} </select> ${mimeRespDetails.examples.map(v => html` <div class="example" data-example="${v.exampleId}" style="display:${v.exampleId === mimeRespDetails.selectedExample ? 'block' : 'none'}"> ${v.exampleSummary && v.exampleSummary.length > 80 ? html`<div style="padding:4px 0"> ${v.exampleSummary} </div>` : ''} ${v.exampleDescription && v.exampleDescription !== v.exampleSummary ? html`<div class="m-markdown-small" style="padding:4px 0"> ${unsafeHTML(toMarkdown(v.exampleDescription || ''))} </div>` : ''} <syntax-highlighter mime-type="${v.exampleType}" .content="${v.exampleValue}" .label="${getI18nText('operations.response')}"> </div> `)} </span> `} `;
164
164
  }
165
165
  mimeSchemaTemplate(mimeRespDetails) {
166
166
  if (!mimeRespDetails) {
@@ -42,6 +42,9 @@ class SyntaxHighlighter extends LitElement {
42
42
  content: {
43
43
  type: Object
44
44
  },
45
+ label: {
46
+ type: String
47
+ },
45
48
  language: {
46
49
  type: String,
47
50
  attribute: 'language'
@@ -53,7 +56,7 @@ class SyntaxHighlighter extends LitElement {
53
56
  };
54
57
  }
55
58
  static finalizeStyles() {
56
- return [PrismStyles, FontStyle, InputStyle, css`:host{font-weight:400}div{position:relative;display:flex;flex-direction:column}.toolbar-copy-btn{position:absolute;top:0;right:0;margin-right:8px}.toolbar-copy-btn+pre{white-space:pre;max-height:400px;overflow:auto;display:flex;padding-right:70px}`];
59
+ return [PrismStyles, FontStyle, InputStyle, css`:host{font-weight:400}div{position:relative;display:flex;flex-direction:column}.toolbar-copy-btn{position:absolute;top:0;right:0;margin-right:8px}.toolbar-copy-btn+pre{white-space:pre;max-height:400px;overflow:auto;display:flex;padding-right:70px}.toolbar-copy-btn~.sr-only{clip:rect(0 0 0 0);clip-path:inset(50%);height:1px;width:1px;overflow:hidden;position:absolute;white-space:nowrap}`];
57
60
  }
58
61
 
59
62
  /**
@@ -73,7 +76,7 @@ class SyntaxHighlighter extends LitElement {
73
76
  return null;
74
77
  }
75
78
  render() {
76
- return this.renderCopyWrapper(this.renderHighlight());
79
+ return this.renderCopyWrapper(this.renderHighlight(), this.label.toLowerCase());
77
80
  }
78
81
 
79
82
  /**
@@ -89,7 +92,7 @@ class SyntaxHighlighter extends LitElement {
89
92
  }
90
93
  const stringContent = ((_this$content = this.content) === null || _this$content === void 0 ? void 0 : _this$content.toString()) || '';
91
94
  const increasedSpaceContent = lang !== 'python' && lang !== 'yaml' && lang !== 'toml' ? stringContent.split('\n').map(line => line.replace(/^\s{2}/g, ' ')).join('\n') : stringContent;
92
- return grammar ? html`<pre><code>${unsafeHTML(Prism.highlight(increasedSpaceContent, grammar, lang))}</code></pre>` : html`<pre>${increasedSpaceContent}</pre>`;
95
+ return grammar ? html`<pre tabindex="0" role="region" aria-label="${this.label}"><code>${unsafeHTML(Prism.highlight(increasedSpaceContent, grammar, lang))}</code></pre>` : html`<pre tabindex="0" role="region" aria-label="${this.label}">${increasedSpaceContent}</pre>`;
93
96
  }
94
97
 
95
98
  /**
@@ -97,8 +100,8 @@ class SyntaxHighlighter extends LitElement {
97
100
  * @param {*} content Content
98
101
  * @returns Content
99
102
  */
100
- renderCopyWrapper(content) {
101
- return html`<div class="fs-exclude ph-no-capture" data-hj-suppress data-sl="mask" style="min-height:2rem"> <button class="m-btn outline-primary toolbar-copy-btn" @click="${this.copyToClipboard}" part="btn btn-fill btn-copy">${getI18nText('operations.copy')}</button> ${content} </div>`;
103
+ renderCopyWrapper(content, label) {
104
+ return html`<div class="fs-exclude ph-no-capture" data-hj-suppress data-sl="mask" style="min-height:2rem"> <button class="m-btn outline-primary toolbar-copy-btn" @click="${this.copyToClipboard}" aria-label="${getI18nText('operations.copy')} ${label}" part="btn btn-fill btn-copy">${getI18nText('operations.copy')}</button> ${content} <div class="sr-only" aria-live="polite" role="status"></div> </div>`;
102
105
  }
103
106
 
104
107
  /**
@@ -491,6 +491,7 @@ export default class OpenApiExplorer extends LitElement {
491
491
  behavior: 'auto',
492
492
  block: 'start'
493
493
  });
494
+ gotoEl.focus();
494
495
  replaceState(tmpElementId);
495
496
  }
496
497
  }, isExpandingNeeded ? 150 : 0);
@@ -532,6 +533,7 @@ export default class OpenApiExplorer extends LitElement {
532
533
  behavior: 'auto',
533
534
  block: 'start'
534
535
  });
536
+ gotoEl.focus();
535
537
  }
536
538
  }
537
539
  }
@@ -668,6 +670,7 @@ export default class OpenApiExplorer extends LitElement {
668
670
  behavior: 'auto',
669
671
  block: 'start'
670
672
  });
673
+ contentEl.focus();
671
674
 
672
675
  // Update Location Hash
673
676
  replaceState(elementId);
@@ -677,6 +680,7 @@ export default class OpenApiExplorer extends LitElement {
677
680
  behavior: 'auto',
678
681
  block: 'start'
679
682
  });
683
+ contentEl.focus();
680
684
 
681
685
  // Update Location Hash
682
686
  replaceState(elementId);
@@ -686,7 +690,7 @@ export default class OpenApiExplorer extends LitElement {
686
690
  behavior: 'auto',
687
691
  block: 'start'
688
692
  });
689
-
693
+ this.shadowRoot.getElementById('operations-root').focus();
690
694
  // Update Location Hash
691
695
  replaceState(elementId);
692
696
  newNavEl = this.shadowRoot.getElementById(`link-${elementId}`);
@@ -718,6 +722,7 @@ export default class OpenApiExplorer extends LitElement {
718
722
  block: 'center'
719
723
  }), 600);
720
724
  }
725
+ newNavEl.focus();
721
726
  }
722
727
  await sleep(0);
723
728
  const oldNavEl = this.shadowRoot.querySelector('.nav-bar-tag.active, .nav-bar-path.active, .nav-bar-info.active, .nav-bar-h1.active, .nav-bar-h2.active');
@@ -22,7 +22,7 @@ export default function codeSamplesTemplate(xCodeSamples) {
22
22
  }).filter(l => typeof l !== 'undefined'));
23
23
  const sanitizedSource = v.source.split('\n').map(s => s.substring(0, paddingToRemove).match(/^\s+$/) ? s.substring(paddingToRemove) : s);
24
24
  const fullSource = sanitizedSource.join('\n');
25
- return html` <div class="tab-content m-markdown code-sample-wrapper" style="display:${i === 0 ? 'block' : 'none'}" data-tab="${v.lang}${i}"> <syntax-highlighter language="${v.lang}" .content="${fullSource}"> </div>`;
25
+ return html` <div class="tab-content m-markdown code-sample-wrapper" style="display:${i === 0 ? 'block' : 'none'}" data-tab="${v.lang}${i}"> <syntax-highlighter language="${v.lang}" .content="${fullSource}" .label="${getI18nText('parameters.samples')}"> </div>`;
26
26
  })} </div></section>`;
27
27
  }
28
28
  /* eslint-enable indent */
@@ -17,7 +17,8 @@ export const invalidCharsRegEx = new RegExp(/[\s#:?&={}-]+/, 'g'); // used for g
17
17
  export function sleep(ms) {
18
18
  return new Promise(resolve => setTimeout(resolve, ms));
19
19
  }
20
- export function copyToClipboard(copyData, eventTarget) {
20
+ export async function copyToClipboard(copyData, eventTarget) {
21
+ const btnEl = eventTarget === null || eventTarget === void 0 ? void 0 : eventTarget.target;
21
22
  // In lots of places we have more than a couple of spaces for <pre> display purposes, we remove those extra spaces here.
22
23
  let data = copyData === null || copyData === void 0 ? void 0 : copyData.trim().replace(/\s{8}/g, ' ');
23
24
  try {
@@ -29,25 +30,19 @@ export function copyToClipboard(copyData, eventTarget) {
29
30
  } catch (error) {
30
31
  // Ignore non JSON text;
31
32
  }
32
- const textArea = document.createElement('textarea');
33
- textArea.value = data;
34
- textArea.style.position = 'fixed'; // avoid scrolling to bottom
35
- document.body.appendChild(textArea);
36
- textArea.focus();
37
- textArea.select();
38
33
  try {
39
- document.execCommand('copy');
40
- const btnEl = eventTarget === null || eventTarget === void 0 ? void 0 : eventTarget.target;
34
+ await window.navigator.clipboard.writeText(data);
41
35
  if (btnEl) {
42
36
  btnEl.innerText = getI18nText('operations.copied');
37
+ btnEl.parentElement.querySelector('.sr-only').innerText = getI18nText('operations.copied');
43
38
  setTimeout(() => {
44
39
  btnEl.innerText = getI18nText('operations.copy');
40
+ btnEl.parentElement.querySelector('.sr-only').innerText = '';
45
41
  }, 5000);
46
42
  }
47
43
  } catch (err) {
48
44
  console.error('Unable to copy', err); // eslint-disable-line no-console
49
45
  }
50
- document.body.removeChild(textArea);
51
46
  }
52
47
  export function getBaseUrlFromUrl(url) {
53
48
  const pathArray = url.split('/');
@@ -460,7 +460,7 @@ class ApiRequest extends _lit.LitElement {
460
460
  return;
461
461
  }
462
462
  this.activeResponseTab = e.target.dataset.tab;
463
- }}"> <br> <div style="width:100%"> <button class="tab-btn ${!hasResponse || this.activeResponseTab === 'curl' ? 'active' : ''}" data-tab="curl">${(0, _index.getI18nText)('operations.request')}</button> ${!hasResponse ? '' : (0, _lit.html)` <button class="tab-btn ${this.activeResponseTab === 'response' ? 'active' : ''}" data-tab="response">${(0, _index.getI18nText)('operations.response')}</button> <button class="tab-btn ${this.activeResponseTab === 'headers' ? 'active' : ''}" data-tab="headers">${(0, _index.getI18nText)('operations.response-headers')}</button>`} </div> </div> ${this.responseIsBlob ? (0, _lit.html)` <div class="tab-content col" style="flex:1;display:${this.activeResponseTab === 'response' ? 'flex' : 'none'}"> ${this.responseBlobType === 'image' ? (0, _lit.html)`<img style="max-height:var(--resp-area-height,300px);object-fit:contain" class="mar-top-8" src="${this.responseBlobUrl}">` : ''} <div style="display:flex;justify-content:center"> <div> <button class="m-btn thin-border mar-top-8" style="width:135px" @click="${this.downloadResponseBlob}" part="btn btn-outline">DOWNLOAD</button> ${this.responseBlobType === 'view' || this.responseBlobType === 'image' ? (0, _lit.html)`<button class="m-btn thin-border mar-top-8" style="width:135px" @click="${this.viewResponseBlob}" part="btn btn-outline">VIEW (NEW TAB)</button>` : ''} </div> </div> </div>` : (0, _lit.html)` <div class="tab-content col m-markdown" style="flex:1;display:${this.activeResponseTab === 'response' ? 'flex' : 'none'}"> <syntax-highlighter style="min-height:60px" mime-type="${this.responseContentType}" .content="${this.responseText}"> </div>`} <div class="tab-content col m-markdown" style="flex:1;display:${this.activeResponseTab === 'headers' ? 'flex' : 'none'}"> <syntax-highlighter style="min-height:60px" language="http" .content="${this.responseHeaders}"> </div> <div class="tab-content m-markdown col" style="flex:1;display:${this.activeResponseTab === 'curl' ? 'flex' : 'none'}"> <syntax-highlighter style="min-height:60px" language="shell" .content="${curlSyntax.trim()}"> </div> </div>`;
463
+ }}"> <br> <div style="width:100%"> <button class="tab-btn ${!hasResponse || this.activeResponseTab === 'curl' ? 'active' : ''}" data-tab="curl">${(0, _index.getI18nText)('operations.request')}</button> ${!hasResponse ? '' : (0, _lit.html)` <button class="tab-btn ${this.activeResponseTab === 'response' ? 'active' : ''}" data-tab="response">${(0, _index.getI18nText)('operations.response')}</button> <button class="tab-btn ${this.activeResponseTab === 'headers' ? 'active' : ''}" data-tab="headers">${(0, _index.getI18nText)('operations.response-headers')}</button>`} </div> </div> ${this.responseIsBlob ? (0, _lit.html)` <div class="tab-content col" style="flex:1;display:${this.activeResponseTab === 'response' ? 'flex' : 'none'}"> ${this.responseBlobType === 'image' ? (0, _lit.html)`<img style="max-height:var(--resp-area-height,300px);object-fit:contain" class="mar-top-8" src="${this.responseBlobUrl}">` : ''} <div style="display:flex;justify-content:center"> <div> <button class="m-btn thin-border mar-top-8" style="width:135px" @click="${this.downloadResponseBlob}" part="btn btn-outline">DOWNLOAD</button> ${this.responseBlobType === 'view' || this.responseBlobType === 'image' ? (0, _lit.html)`<button class="m-btn thin-border mar-top-8" style="width:135px" @click="${this.viewResponseBlob}" part="btn btn-outline">VIEW (NEW TAB)</button>` : ''} </div> </div> </div>` : (0, _lit.html)` <div class="tab-content col m-markdown" style="flex:1;display:${this.activeResponseTab === 'response' ? 'flex' : 'none'}"> <syntax-highlighter style="min-height:60px" mime-type="${this.responseContentType}" .content="${this.responseText}" .label="${(0, _index.getI18nText)('operations.response')}"> </div>`} <div class="tab-content col m-markdown" style="flex:1;display:${this.activeResponseTab === 'headers' ? 'flex' : 'none'}"> <syntax-highlighter style="min-height:60px" language="http" .content="${this.responseHeaders}" .label="${(0, _index.getI18nText)('operations.response-headers')}"> </div> <div class="tab-content m-markdown col" style="flex:1;display:${this.activeResponseTab === 'curl' ? 'flex' : 'none'}"> <syntax-highlighter style="min-height:60px" language="shell" .content="${curlSyntax.trim()}" .label="${(0, _index.getI18nText)('operations.request')}"> </div> </div>`;
464
464
  }
465
465
  apiCallTemplate() {
466
466
  return (0, _lit.html)` <div style="display:flex;align-items:flex-end;margin:16px 0;font-size:var(--font-size-small)"> ${this.parameters.length > 0 || this.request_body ? (0, _lit.html)` <button class="m-btn thin-border" part="btn btn-outline" style="margin-right:5px" @click="${this.onClearRequestData}"> ${(0, _index.getI18nText)('operations.clear')} </button>` : ''} <button class="m-btn primary btn-execute thin-border" part="btn btn-fill btn-try" @click="${this.onTryClick}">${(0, _index.getI18nText)('operations.execute')}</button> </div> ${this.apiResponseTabTemplate()} `;
@@ -165,7 +165,7 @@ class ApiResponse extends _lit.LitElement {
165
165
  if (!mimeRespDetails) {
166
166
  return (0, _lit.html)` <pre style="color:var(--red)" class="example-panel border-top"> No example provided </pre> `;
167
167
  }
168
- return (0, _lit.html)` ${mimeRespDetails.examples.length === 1 ? (0, _lit.html)` ${mimeRespDetails.examples[0].exampleSummary && mimeRespDetails.examples[0].exampleSummary.length > 80 ? (0, _lit.html)`<div style="padding:4px 0"> ${mimeRespDetails.examples[0].exampleSummary} </div>` : ''} ${mimeRespDetails.examples[0].exampleDescription ? (0, _lit.html)`<div class="m-markdown-small" style="padding:4px 0"> ${(0, _unsafeHtml.unsafeHTML)((0, _commonUtils.toMarkdown)(mimeRespDetails.examples[0].exampleDescription || ''))} </div>` : ''} <syntax-highlighter class="example-panel generic-tree pad-top-8" mime-type="${mimeRespDetails.examples[0].exampleType}" .content="${mimeRespDetails.examples[0].exampleValue}">` : (0, _lit.html)` <span class="example-panel generic-tree ${this.renderStyle === 'read' ? 'border pad-8-16' : 'border-top pad-top-8'}"> <select aria-label="response body example" @change="${e => this.onSelectExample(e)}"> ${mimeRespDetails.examples.map(v => (0, _lit.html)`<option value="${v.exampleId}" ?selected="${v.exampleId === mimeRespDetails.selectedExample}"> ${!v.exampleSummary || v.exampleSummary.length > 80 ? v.exampleId : v.exampleSummary} </option>`)} </select> ${mimeRespDetails.examples.map(v => (0, _lit.html)` <div class="example" data-example="${v.exampleId}" style="display:${v.exampleId === mimeRespDetails.selectedExample ? 'block' : 'none'}"> ${v.exampleSummary && v.exampleSummary.length > 80 ? (0, _lit.html)`<div style="padding:4px 0"> ${v.exampleSummary} </div>` : ''} ${v.exampleDescription && v.exampleDescription !== v.exampleSummary ? (0, _lit.html)`<div class="m-markdown-small" style="padding:4px 0"> ${(0, _unsafeHtml.unsafeHTML)((0, _commonUtils.toMarkdown)(v.exampleDescription || ''))} </div>` : ''} <syntax-highlighter mime-type="${v.exampleType}" .content="${v.exampleValue}"> </div> `)} </span> `} `;
168
+ return (0, _lit.html)` ${mimeRespDetails.examples.length === 1 ? (0, _lit.html)` ${mimeRespDetails.examples[0].exampleSummary && mimeRespDetails.examples[0].exampleSummary.length > 80 ? (0, _lit.html)`<div style="padding:4px 0"> ${mimeRespDetails.examples[0].exampleSummary} </div>` : ''} ${mimeRespDetails.examples[0].exampleDescription ? (0, _lit.html)`<div class="m-markdown-small" style="padding:4px 0"> ${(0, _unsafeHtml.unsafeHTML)((0, _commonUtils.toMarkdown)(mimeRespDetails.examples[0].exampleDescription || ''))} </div>` : ''} <syntax-highlighter class="example-panel generic-tree pad-top-8" mime-type="${mimeRespDetails.examples[0].exampleType}" .content="${mimeRespDetails.examples[0].exampleValue}" .label="${(0, _index.getI18nText)('operations.response')}">` : (0, _lit.html)` <span class="example-panel generic-tree ${this.renderStyle === 'read' ? 'border pad-8-16' : 'border-top pad-top-8'}"> <select aria-label="response body example" @change="${e => this.onSelectExample(e)}"> ${mimeRespDetails.examples.map(v => (0, _lit.html)`<option value="${v.exampleId}" ?selected="${v.exampleId === mimeRespDetails.selectedExample}"> ${!v.exampleSummary || v.exampleSummary.length > 80 ? v.exampleId : v.exampleSummary} </option>`)} </select> ${mimeRespDetails.examples.map(v => (0, _lit.html)` <div class="example" data-example="${v.exampleId}" style="display:${v.exampleId === mimeRespDetails.selectedExample ? 'block' : 'none'}"> ${v.exampleSummary && v.exampleSummary.length > 80 ? (0, _lit.html)`<div style="padding:4px 0"> ${v.exampleSummary} </div>` : ''} ${v.exampleDescription && v.exampleDescription !== v.exampleSummary ? (0, _lit.html)`<div class="m-markdown-small" style="padding:4px 0"> ${(0, _unsafeHtml.unsafeHTML)((0, _commonUtils.toMarkdown)(v.exampleDescription || ''))} </div>` : ''} <syntax-highlighter mime-type="${v.exampleType}" .content="${v.exampleValue}" .label="${(0, _index.getI18nText)('operations.response')}"> </div> `)} </span> `} `;
169
169
  }
170
170
  mimeSchemaTemplate(mimeRespDetails) {
171
171
  if (!mimeRespDetails) {
@@ -44,6 +44,9 @@ class SyntaxHighlighter extends _lit.LitElement {
44
44
  content: {
45
45
  type: Object
46
46
  },
47
+ label: {
48
+ type: String
49
+ },
47
50
  language: {
48
51
  type: String,
49
52
  attribute: 'language'
@@ -55,7 +58,7 @@ class SyntaxHighlighter extends _lit.LitElement {
55
58
  };
56
59
  }
57
60
  static finalizeStyles() {
58
- return [_prismStyles.default, _fontStyles.default, _inputStyles.default, (0, _lit.css)`:host{font-weight:400}div{position:relative;display:flex;flex-direction:column}.toolbar-copy-btn{position:absolute;top:0;right:0;margin-right:8px}.toolbar-copy-btn+pre{white-space:pre;max-height:400px;overflow:auto;display:flex;padding-right:70px}`];
61
+ return [_prismStyles.default, _fontStyles.default, _inputStyles.default, (0, _lit.css)`:host{font-weight:400}div{position:relative;display:flex;flex-direction:column}.toolbar-copy-btn{position:absolute;top:0;right:0;margin-right:8px}.toolbar-copy-btn+pre{white-space:pre;max-height:400px;overflow:auto;display:flex;padding-right:70px}.toolbar-copy-btn~.sr-only{clip:rect(0 0 0 0);clip-path:inset(50%);height:1px;width:1px;overflow:hidden;position:absolute;white-space:nowrap}`];
59
62
  }
60
63
 
61
64
  /**
@@ -75,7 +78,7 @@ class SyntaxHighlighter extends _lit.LitElement {
75
78
  return null;
76
79
  }
77
80
  render() {
78
- return this.renderCopyWrapper(this.renderHighlight());
81
+ return this.renderCopyWrapper(this.renderHighlight(), this.label.toLowerCase());
79
82
  }
80
83
 
81
84
  /**
@@ -91,7 +94,7 @@ class SyntaxHighlighter extends _lit.LitElement {
91
94
  }
92
95
  const stringContent = ((_this$content = this.content) === null || _this$content === void 0 ? void 0 : _this$content.toString()) || '';
93
96
  const increasedSpaceContent = lang !== 'python' && lang !== 'yaml' && lang !== 'toml' ? stringContent.split('\n').map(line => line.replace(/^\s{2}/g, ' ')).join('\n') : stringContent;
94
- return grammar ? (0, _lit.html)`<pre><code>${(0, _unsafeHtml.unsafeHTML)(_prismjs.default.highlight(increasedSpaceContent, grammar, lang))}</code></pre>` : (0, _lit.html)`<pre>${increasedSpaceContent}</pre>`;
97
+ return grammar ? (0, _lit.html)`<pre tabindex="0" role="region" aria-label="${this.label}"><code>${(0, _unsafeHtml.unsafeHTML)(_prismjs.default.highlight(increasedSpaceContent, grammar, lang))}</code></pre>` : (0, _lit.html)`<pre tabindex="0" role="region" aria-label="${this.label}">${increasedSpaceContent}</pre>`;
95
98
  }
96
99
 
97
100
  /**
@@ -99,8 +102,8 @@ class SyntaxHighlighter extends _lit.LitElement {
99
102
  * @param {*} content Content
100
103
  * @returns Content
101
104
  */
102
- renderCopyWrapper(content) {
103
- return (0, _lit.html)`<div class="fs-exclude ph-no-capture" data-hj-suppress data-sl="mask" style="min-height:2rem"> <button class="m-btn outline-primary toolbar-copy-btn" @click="${this.copyToClipboard}" part="btn btn-fill btn-copy">${(0, _index.getI18nText)('operations.copy')}</button> ${content} </div>`;
105
+ renderCopyWrapper(content, label) {
106
+ return (0, _lit.html)`<div class="fs-exclude ph-no-capture" data-hj-suppress data-sl="mask" style="min-height:2rem"> <button class="m-btn outline-primary toolbar-copy-btn" @click="${this.copyToClipboard}" aria-label="${(0, _index.getI18nText)('operations.copy')} ${label}" part="btn btn-fill btn-copy">${(0, _index.getI18nText)('operations.copy')}</button> ${content} <div class="sr-only" aria-live="polite" role="status"></div> </div>`;
104
107
  }
105
108
 
106
109
  /**
@@ -497,6 +497,7 @@ class OpenApiExplorer extends _lit.LitElement {
497
497
  behavior: 'auto',
498
498
  block: 'start'
499
499
  });
500
+ gotoEl.focus();
500
501
  (0, _commonUtils.replaceState)(tmpElementId);
501
502
  }
502
503
  }, isExpandingNeeded ? 150 : 0);
@@ -538,6 +539,7 @@ class OpenApiExplorer extends _lit.LitElement {
538
539
  behavior: 'auto',
539
540
  block: 'start'
540
541
  });
542
+ gotoEl.focus();
541
543
  }
542
544
  }
543
545
  }
@@ -674,6 +676,7 @@ class OpenApiExplorer extends _lit.LitElement {
674
676
  behavior: 'auto',
675
677
  block: 'start'
676
678
  });
679
+ contentEl.focus();
677
680
 
678
681
  // Update Location Hash
679
682
  (0, _commonUtils.replaceState)(elementId);
@@ -683,6 +686,7 @@ class OpenApiExplorer extends _lit.LitElement {
683
686
  behavior: 'auto',
684
687
  block: 'start'
685
688
  });
689
+ contentEl.focus();
686
690
 
687
691
  // Update Location Hash
688
692
  (0, _commonUtils.replaceState)(elementId);
@@ -692,7 +696,7 @@ class OpenApiExplorer extends _lit.LitElement {
692
696
  behavior: 'auto',
693
697
  block: 'start'
694
698
  });
695
-
699
+ this.shadowRoot.getElementById('operations-root').focus();
696
700
  // Update Location Hash
697
701
  (0, _commonUtils.replaceState)(elementId);
698
702
  newNavEl = this.shadowRoot.getElementById(`link-${elementId}`);
@@ -724,6 +728,7 @@ class OpenApiExplorer extends _lit.LitElement {
724
728
  block: 'center'
725
729
  }), 600);
726
730
  }
731
+ newNavEl.focus();
727
732
  }
728
733
  await (0, _commonUtils.sleep)(0);
729
734
  const oldNavEl = this.shadowRoot.querySelector('.nav-bar-tag.active, .nav-bar-path.active, .nav-bar-info.active, .nav-bar-h1.active, .nav-bar-h2.active');
@@ -25,7 +25,7 @@ function codeSamplesTemplate(xCodeSamples) {
25
25
  }).filter(l => typeof l !== 'undefined'));
26
26
  const sanitizedSource = v.source.split('\n').map(s => s.substring(0, paddingToRemove).match(/^\s+$/) ? s.substring(paddingToRemove) : s);
27
27
  const fullSource = sanitizedSource.join('\n');
28
- return (0, _lit.html)` <div class="tab-content m-markdown code-sample-wrapper" style="display:${i === 0 ? 'block' : 'none'}" data-tab="${v.lang}${i}"> <syntax-highlighter language="${v.lang}" .content="${fullSource}"> </div>`;
28
+ return (0, _lit.html)` <div class="tab-content m-markdown code-sample-wrapper" style="display:${i === 0 ? 'block' : 'none'}" data-tab="${v.lang}${i}"> <syntax-highlighter language="${v.lang}" .content="${fullSource}" .label="${(0, _index.getI18nText)('parameters.samples')}"> </div>`;
29
29
  })} </div></section>`;
30
30
  }
31
31
  /* eslint-enable indent */
@@ -32,7 +32,8 @@ const invalidCharsRegEx = exports.invalidCharsRegEx = new RegExp(/[\s#:?&={}-]+/
32
32
  function sleep(ms) {
33
33
  return new Promise(resolve => setTimeout(resolve, ms));
34
34
  }
35
- function copyToClipboard(copyData, eventTarget) {
35
+ async function copyToClipboard(copyData, eventTarget) {
36
+ const btnEl = eventTarget === null || eventTarget === void 0 ? void 0 : eventTarget.target;
36
37
  // In lots of places we have more than a couple of spaces for <pre> display purposes, we remove those extra spaces here.
37
38
  let data = copyData === null || copyData === void 0 ? void 0 : copyData.trim().replace(/\s{8}/g, ' ');
38
39
  try {
@@ -44,25 +45,19 @@ function copyToClipboard(copyData, eventTarget) {
44
45
  } catch (error) {
45
46
  // Ignore non JSON text;
46
47
  }
47
- const textArea = document.createElement('textarea');
48
- textArea.value = data;
49
- textArea.style.position = 'fixed'; // avoid scrolling to bottom
50
- document.body.appendChild(textArea);
51
- textArea.focus();
52
- textArea.select();
53
48
  try {
54
- document.execCommand('copy');
55
- const btnEl = eventTarget === null || eventTarget === void 0 ? void 0 : eventTarget.target;
49
+ await window.navigator.clipboard.writeText(data);
56
50
  if (btnEl) {
57
51
  btnEl.innerText = (0, _index.getI18nText)('operations.copied');
52
+ btnEl.parentElement.querySelector('.sr-only').innerText = (0, _index.getI18nText)('operations.copied');
58
53
  setTimeout(() => {
59
54
  btnEl.innerText = (0, _index.getI18nText)('operations.copy');
55
+ btnEl.parentElement.querySelector('.sr-only').innerText = '';
60
56
  }, 5000);
61
57
  }
62
58
  } catch (err) {
63
59
  console.error('Unable to copy', err); // eslint-disable-line no-console
64
60
  }
65
- document.body.removeChild(textArea);
66
61
  }
67
62
  function getBaseUrlFromUrl(url) {
68
63
  const pathArray = url.split('/');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openapi-explorer",
3
- "version": "2.4.801",
3
+ "version": "2.4.820",
4
4
  "description": "OpenAPI Explorer - API viewer with dynamically generated components, documentation, and interaction console",
5
5
  "author": "Authress Developers <developers@authress.io>",
6
6
  "type": "module",