Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 28 additions & 6 deletions src/components/api-request.js
Original file line number Diff line number Diff line change
Expand Up @@ -575,7 +575,7 @@ export default class ApiRequest extends LitElement {

return html`
<div class='request-body-container' data-selected-request-body-type="${this.selectedRequestBodyType}">
<div class="table-title top-gap row">
<div class="table-title top-gap row" role="heading" aria-level="${this.renderStyle === 'focused' ? 4 : 5}" id="request-body-header">
${getI18nText('operations.request-body')} ${this.request_body.required ? html`<span class="mono-font" style='color:var(--red)'>*</span>` : ''}
<span style = "font-weight:normal; margin-left:5px"> ${this.selectedRequestBodyType}</span>
<span style="flex:1"></span>
Expand All @@ -586,12 +586,34 @@ export default class ApiRequest extends LitElement {
${reqBodySchemaHtml || reqBodyDefaultHtml
? html`
<div class="tab-panel col" style="border-width:0 0 1px 0;">
<div class="tab-buttons row" role="group" @click="${(e) => { if (e.target.tagName.toLowerCase() === 'button') { this.activeSchemaTab = e.target.dataset.tab; } }}">
<button class="tab-btn ${this.activeSchemaTab === 'model' ? 'active' : ''}" aria-current="${this.activeSchemaTab === 'model'}" data-tab="model" >${getI18nText('operations.model')}</button>
<button class="tab-btn ${this.activeSchemaTab !== 'model' ? 'active' : ''}" aria-current="${this.activeSchemaTab !== 'model'}" data-tab="body">${bodyTabNameUseBody ? getI18nText('operations.body') : getI18nText('operations.form')}</button>
<div class="tab-buttons row" role="tablist" aria-labelledby="request-body-header" @click="${(e) => { if (e.target.tagName.toLowerCase() === 'button') { this.activeSchemaTab = e.target.dataset.tab; } }}" @keydown="${(e) => {
const b = e.target;
if (b.tagName.toLowerCase() !== 'button') {return;}
const i = Array.from(b.parentNode.children).indexOf(b);
let newIndex = 0;
switch (e.key) {
case 'ArrowRight':
newIndex = (i + 1) % 2;
break;
case 'ArrowLeft':
newIndex = (i - 1 + 2) % 2;
break;
case 'Home':
newIndex = 0;
break;
case 'End':
newIndex = 1;
break;
default:
return;
}
e.target.parentElement.children[newIndex].focus();
}}">
<button class="tab-btn ${this.activeSchemaTab === 'model' ? 'active' : ''}" id="schema-model-button" aria-controls="schema-model-body" aria-selected="${this.activeSchemaTab === 'model'}" tabindex="${this.activeSchemaTab === 'model' ? 0 : '-1'}" data-tab="model" >${getI18nText('operations.model')}</button>
<button class="tab-btn ${this.activeSchemaTab !== 'model' ? 'active' : ''}" id="schema-body-button" aria-controls="schema-body-body" aria-selected="${this.activeSchemaTab !== 'model'}" tabindex="${this.activeSchemaTab !== 'model' ? 0 : '-1'}" data-tab="body">${bodyTabNameUseBody ? getI18nText('operations.body') : getI18nText('operations.form')}</button>
</div>
${html`<div class="tab-content col" style="display: ${this.activeSchemaTab === 'model' ? 'block' : 'none'}"> ${reqBodySchemaHtml}</div>`}
${html`<div class="tab-content col" style="display: ${this.activeSchemaTab === 'model' ? 'none' : 'block'}"> ${reqBodyDefaultHtml}</div>`}
${html`<div class="tab-content col" id="schema-model-body" tabindex="0" aria-labelledby="schema-model-button" role="tabpanel" style="display: ${this.activeSchemaTab === 'model' ? 'block' : 'none'}"> ${reqBodySchemaHtml}</div>`}
${html`<div class="tab-content col" id="schema-body-body" tabindex="0" aria-labelledby="schema-body-button" role="tabpanel" style="display: ${this.activeSchemaTab === 'model' ? 'none' : 'block'}"> ${reqBodyDefaultHtml}</div>`}
</div>`
: html`${reqBodyFileInputHtml}`
}
Expand Down
77 changes: 61 additions & 16 deletions src/components/api-response.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ export default class ApiResponse extends LitElement {
render() {
return html`
<div class="col regular-font response-panel ${this.renderStyle}-mode">
<div class=" ${this.callback === 'true' ? 'tiny-title' : 'req-res-title'} " role="heading" aria-level="${this.renderStyle === 'focused' ? 3 : 4}">
<div class=" ${this.callback === 'true' ? 'tiny-title' : 'req-res-title'} " role="heading" aria-level="${this.renderStyle === 'focused' ? 3 : 4}" id="response-title">
${this.callback === 'true' ? getI18nText('operations.callback-response') : getI18nText('operations.response')}
</div>
<div>
Expand Down Expand Up @@ -159,8 +159,8 @@ export default class ApiResponse extends LitElement {
this.headersForEachRespStatus[statusCode] = tempHeaders;
this.mimeResponsesForEachStatus[statusCode] = allMimeResp;
}
return html`<div class='row' style='flex-wrap:wrap' role="group">
${Object.keys(this.responses).map((respStatus) => html`
return html`<div class='row' style='flex-wrap:wrap' role="tablist" aria-labelledby="response-title">
${Object.keys(this.responses).map((respStatus, i) => html`
${respStatus === '$$ref' // Swagger-Client parser creates '$$ref' object if JSON references are used to create responses - this should be ignored
? ''
: html`
Expand All @@ -173,7 +173,32 @@ export default class ApiResponse extends LitElement {
this.selectedMimeType = undefined;
}
}}"
aria-current="${this.selectedStatus === respStatus}"
@keydown="${(e) => {
const keys = Object.keys(this.responses);
let newIndex = 0;
switch (e.key) {
case 'ArrowRight':
newIndex = (i + 1) % keys.length;
break;
case 'ArrowLeft':
newIndex = (i - 1 + keys.length) % keys.length;
break;
case 'Home':
newIndex = 0;
break;
case 'End':
newIndex = keys.length - 1;
break;
default:
return;
}
this.shadowRoot.getElementById(`button${keys[newIndex]}`).focus();
}}"
role="tab"
aria-selected="${this.selectedStatus === respStatus}"
aria-controls="status${respStatus}"
tabindex="${this.selectedStatus === respStatus ? '0' : '-1'}"
id="button${respStatus}"
class='m-btn small ${this.selectedStatus === respStatus ? 'primary' : ''}'
part="btn--resp ${this.selectedStatus === respStatus ? 'btn-fill--resp' : 'btn-outline--resp'} btn-response-status"
style='margin: 8px 4px 0 0; text-transform: capitalize'>
Expand All @@ -184,7 +209,7 @@ export default class ApiResponse extends LitElement {
</div>

${Object.keys(this.responses).map((status) => html`
<div style = 'display: ${status === this.selectedStatus ? 'block' : 'none'}' >
<div id="status${status}" role="tabpanel" aria-labelledby="button${status}" tabindex="0" style="display: ${status === this.selectedStatus ? 'block' : 'none'}">
<div class="top-gap">
<span class="resp-descr m-markdown ">${unsafeHTML(toMarkdown(this.responses[status] && this.responses[status].description || ''))}</span>
${(this.headersForEachRespStatus[status] && this.headersForEachRespStatus[status].length > 0)
Expand All @@ -196,23 +221,43 @@ export default class ApiResponse extends LitElement {
? ''
: html`
<div class="tab-panel col">
<div class="tab-buttons row" role="group" @click="${(e) => { if (e.target.tagName.toLowerCase() === 'button') { this.activeSchemaTab = e.target.dataset.tab; } }}" >
<button class="tab-btn ${this.activeSchemaTab === 'model' ? 'active' : ''}" aria-current="${this.activeSchemaTab === 'model'}" data-tab='model'>${getI18nText('operations.model')}</button>
<button class="tab-btn ${this.activeSchemaTab !== 'model' ? 'active' : ''}" aria-current="${this.activeSchemaTab !== 'model'}" data-tab='body'>${getI18nText('operations.example')}</button>
<div class="tab-buttons row" role="ta" @click="${(e) => { if (e.target.tagName.toLowerCase() === 'button') { this.activeSchemaTab = e.target.dataset.tab; } }}" @keydown="${(e) => {
const b = e.target;
if (b.tagName.toLowerCase() !== 'button') {return;}
const i = Array.from(b.parentNode.children).indexOf(b);
let newIndex = 0;
switch (e.key) {
case 'ArrowRight':
newIndex = (i + 1) % 2;
break;
case 'ArrowLeft':
newIndex = (i - 1 + 2) % 2;
break;
case 'Home':
newIndex = 0;
break;
case 'End':
newIndex = 1;
break;
default:
return;
}
e.target.parentElement.children[newIndex].focus();
}}">
<button class="tab-btn ${this.activeSchemaTab === 'model' ? 'active' : ''}" id="resp-model-button" aria-controls="resp-model-body" aria-selected="${this.activeSchemaTab === 'model'}" tabindex="${this.activeSchemaTab === 'model' ? 0 : '-1'}" data-tab='model'>${getI18nText('operations.model')}</button>
<button class="tab-btn ${this.activeSchemaTab !== 'model' ? 'active' : ''}" id="resp-body-button" aria-controls="resp-body-body" aria-selected="${this.activeSchemaTab !== 'model'}" tabindex="${this.activeSchemaTab !== 'model' ? 0 : '-1'}" data-tab='body'>${getI18nText('operations.example')}</button>
<div style="flex:1"></div>
${Object.keys(this.mimeResponsesForEachStatus[status]).length === 1
? html`<span class='small-font-size gray-text' style='align-self:center; margin-top:8px;'> ${Object.keys(this.mimeResponsesForEachStatus[status])[0]} </span>`
: html`${this.mimeTypeDropdownTemplate(Object.keys(this.mimeResponsesForEachStatus[status]))}`
}
</div>
${this.activeSchemaTab === 'body'
? html`<div class='tab-content col' style='flex:1;'>
${this.mimeExampleTemplate(this.mimeResponsesForEachStatus[status][this.selectedMimeType])}
</div>`
: html`<div class='tab-content col' style='flex:1;'>
${this.mimeSchemaTemplate(this.mimeResponsesForEachStatus[status][this.selectedMimeType])}
</div>`
}
${html`<div class='tab-content col' role="tabpanel" tabindex="0" id='resp-body-body' aria-labelledby='resp-body-button' style='flex:1; display: ${this.activeSchemaTab === 'body' ? 'block' : 'none'}'>
${this.mimeExampleTemplate(this.mimeResponsesForEachStatus[status][this.selectedMimeType])}}
</div>`}
${html`<div class='tab-content col' role="tabpanel" tabindex="0" id='resp-model-body' style='flex:1; display: ${this.activeSchemaTab === 'body' ? 'none' : 'block'}'>
${this.mimeSchemaTemplate(this.mimeResponsesForEachStatus[status][this.selectedMimeType])}
</div>`}
</div>
`
}`)
Expand Down
3 changes: 2 additions & 1 deletion src/styles/tab-styles.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ export default css`
color:var(--primary-color);
}

.tab-btn:focus-visible {
.tab-btn:focus-visible,
.tab-btn.active:focus-visible {
color:var(--secondary-color);
}

Expand Down
31 changes: 27 additions & 4 deletions src/templates/code-samples-template.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,40 @@ export default function codeSamplesTemplate(xCodeSamples) {
tabContents.forEach((tabBodyEl) => { tabBodyEl.style.display = (tabBodyEl.dataset.tab === clickedTab ? 'block' : 'none'); });
}
}">
<div class="tab-buttons row" role="group" style="width:100; overflow">
${xCodeSamples.map((v, i) => html`<button class="tab-btn ${i === 0 ? 'active' : ''}" aria-current='${i === 0}' data-tab = '${v.lang}${i}'> ${v.label || v.lang} </button>`)}
<div class="tab-buttons row" role="tablist" style="width:100; overflow">
${xCodeSamples.map((v, i) => html`<button class="tab-btn ${i === 0 ? 'active' : ''}" role="tab" id="codesample${i}-button" aria-controls="codesample${i}" aria-selected='${i === 0}' tabindex="${i === 0 ? 0 : '-1'}'" data-tab = '${v.lang}${i}' @keydown="${(e) => {
const samps = xCodeSamples;
let newIndex = 0;
switch (e.key) {
case 'ArrowRight':
newIndex = (i + 1) % samps.length;
break;
case 'ArrowLeft':
newIndex = (i - 1 + samps.length) % samps.length;
break;
case 'Home':
newIndex = 0;
break;
case 'End':
newIndex = samps.length - 1;
break;
default:
return;
}
const button = this.shadowRoot.getElementById(`codesample${newIndex}-button`);
Array.from(button.parentElement.children).forEach((b) => b.tabIndex = '-1');
button.tabIndex = 0;
button.focus();
}}"> ${v.label || v.lang} </button>`)}
</div>
${xCodeSamples.map((v, i) => {
// We skip the first line because it could be there is no padding there, but padding on the next lines which needs to be removed
const paddingToRemove = Math.min(...v.source.split('\n').slice(1).map(l => l.match(/^(\s*).*$/m)?.[1].length).filter(l => typeof l !== 'undefined'));
const sanitizedSource = v.source.split('\n').map(s => s.substring(0, paddingToRemove).match(/^\s+$/) ? s.substring(paddingToRemove) : s);
const fullSource = sanitizedSource.join('\n');
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 class="tab-content m-markdown code-sample-wrapper" id="codesample${i}" role="tabpanel" aria-labelledby="codesample${i}-button" tabindex="0" style= "display:${i === 0 ? 'block' : 'none'}" data-tab = '${v.lang}${i}'>
<syntax-highlighter language="${v.lang}" .content="${fullSource}" aria-label="Code sample"/>
</div>`;
})
}
Expand Down
Loading