Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
82d4ba2
fix: add aria label to select element for content types
ediiotero Mar 11, 2021
7eb1f1d
Merging upstream changes
Mar 17, 2021
e038821
fix: add aria label to select element for content types
gileswells Mar 18, 2021
559fb68
fix: add aria label prop to contentType component
ediiotero Mar 22, 2021
407424b
fix: conflicts
ediiotero Mar 22, 2021
fa3a94c
Remove changes to dist folder
gileswells Mar 24, 2021
eb3ac73
Merge branch 'upstream-main' of github.com:department-of-veterans-aff…
gileswells Mar 24, 2021
d785aad
Merge pull request #1 from department-of-veterans-affairs/bug/add-ari…
gileswells Mar 29, 2021
a78b4a0
Merge pull request #3 from swagger-api/master
gileswells Mar 29, 2021
762ac60
Merge branch 'master' into master
gileswells Mar 30, 2021
f2037e6
Merge branch 'master' into master
gileswells Mar 30, 2021
88c01f1
Merge branch 'master' into master
gileswells Mar 31, 2021
dec8ade
feat: adds a11y for ContentType & Responses region
Apr 8, 2021
5ac104c
feat: adds a11y to expandable/collapsible elements
Apr 8, 2021
9a5d9f2
Merge pull request #4 from department-of-veterans-affairs/ft/a11y-cur…
Apr 12, 2021
50285e4
fix: failing test and missing className
Apr 12, 2021
9d6918c
Merge pull request #5 from department-of-veterans-affairs/ft/a11y-upd…
Apr 14, 2021
c25fa03
Merge branch 'master' of github.com:swagger-api/swagger-ui into master
gileswells Apr 27, 2021
dc7893c
Change optag to h3 for better tag heirarchy
gileswells Apr 27, 2021
a16a91e
Remove unneeded additional import
gileswells Apr 27, 2021
9ccdfb8
Merge pull request #6 from department-of-veterans-affairs/fix-optag-h…
gileswells Apr 28, 2021
003bfcd
Merge branch 'master' of github.com:swagger-api/swagger-ui into master
gileswells Apr 29, 2021
2aac46c
Merge branch 'master' into master
gileswells Apr 29, 2021
f6a00d3
Merge branch 'master' into master
gileswells May 4, 2021
1738900
Merge branch 'master' into master
gileswells May 6, 2021
e4458cc
Merge branch 'master' into master
gileswells May 10, 2021
98eac9b
Merge branch 'master' into master
gileswells May 11, 2021
26872bd
Merge branch 'master' into master
gileswells May 12, 2021
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
6 changes: 4 additions & 2 deletions src/core/components/content-type.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ const noop = ()=>{}
export default class ContentType extends React.Component {

static propTypes = {
ariaControls: PropTypes.string,
contentTypes: PropTypes.oneOfType([ImPropTypes.list, ImPropTypes.set, ImPropTypes.seq]),
controlId: PropTypes.string,
value: PropTypes.string,
onChange: PropTypes.func,
className: PropTypes.string,
Expand Down Expand Up @@ -41,14 +43,14 @@ export default class ContentType extends React.Component {
onChangeWrapper = e => this.props.onChange(e.target.value)

render() {
let { contentTypes, className, value, ariaLabel } = this.props
let { ariaControls, ariaLabel, className, contentTypes, controlId, value } = this.props

if ( !contentTypes || !contentTypes.size )
return null

return (
<div className={ "content-type-wrapper " + ( className || "" ) }>
<select className="content-type" aria-label={ariaLabel} value={value || ""} onChange={this.onChangeWrapper} >
<select aria-controls={ariaControls} aria-label={ariaLabel} className="content-type" id={controlId} onChange={this.onChangeWrapper} value={value || ""} >
{ contentTypes.map( (val) => {
return <option key={ val } value={ val }>{ val }</option>
}).toArray()}
Expand Down
14 changes: 6 additions & 8 deletions src/core/components/model-collapse.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -86,15 +86,13 @@ export default class ModelCollapse extends Component {

return (
<span className={classes || ""} ref={this.onLoad}>
{ title && <span onClick={this.toggleCollapsed} className="pointer">{title}</span> }
<span onClick={ this.toggleCollapsed } className="pointer">
<button aria-expanded={this.state.expanded} className="model-box-control" onClick={this.toggleCollapsed}>
{ title && <span className="pointer">{title}</span> }
<span className={ "model-toggle" + ( this.state.expanded ? "" : " collapsed" ) }></span>
</span>
{
this.state.expanded
? this.props.children
: <span onClick={this.toggleCollapsed} className="pointer">{this.state.collapsedContent}</span>
}
{ !this.state.expanded && <span>{this.state.collapsedContent}</span> }
</button>

{ this.state.expanded && this.props.children }
</span>
)
}
Expand Down
16 changes: 11 additions & 5 deletions src/core/components/models.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,17 @@ export default class Models extends Component {
const JumpToPath = getComponent("JumpToPath")

return <section className={ showModels ? "models is-open" : "models"} ref={this.onLoadModels}>
<h4 onClick={() => layoutActions.show(specPathBase, !showModels)}>
<span>{isOAS3 ? "Schemas" : "Models" }</span>
<svg width="20" height="20">
<use xlinkHref={showModels ? "#large-arrow-down" : "#large-arrow"} />
</svg>
<h4>
<button
aria-expanded={showModels}
className="models-control"
onClick={() => layoutActions.show(specPathBase, !showModels)}
>
<span>{isOAS3 ? "Schemas" : "Models"}</span>
<svg width="20" height="20" aria-hidden="true" focusable="false">
<use xlinkHref={showModels ? "#large-arrow-up" : "#large-arrow-down"} />
</svg>
</button>
</h4>
<Collapse isOpened={showModels}>
{
Expand Down
34 changes: 24 additions & 10 deletions src/core/components/operation-summary.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export default class OperationSummary extends PureComponent {
static propTypes = {
specPath: ImPropTypes.list.isRequired,
operationProps: PropTypes.instanceOf(Iterable).isRequired,
isShown: PropTypes.bool.isRequired,
toggleShown: PropTypes.func.isRequired,
getComponent: PropTypes.func.isRequired,
getConfigs: PropTypes.func.isRequired,
Expand All @@ -26,6 +27,7 @@ export default class OperationSummary extends PureComponent {
render() {

let {
isShown,
toggleShown,
getComponent,
authActions,
Expand All @@ -40,6 +42,7 @@ export default class OperationSummary extends PureComponent {
method,
op,
showSummary,
path,
operationId,
originalOperationId,
displayOperationId,
Expand All @@ -60,17 +63,28 @@ export default class OperationSummary extends PureComponent {
const securityIsOptional = hasSecurity && security.size === 1 && security.first().isEmpty()
const allowAnonymous = !hasSecurity || securityIsOptional
return (
<div className={`opblock-summary opblock-summary-${method}`} onClick={toggleShown} >
<OperationSummaryMethod method={method} />
<OperationSummaryPath getComponent={getComponent} operationProps={operationProps} specPath={specPath} />

{!showSummary ? null :
<div className="opblock-summary-description">
{toString(resolvedSummary || summary)}
</div>
}
<div className={`opblock-summary opblock-summary-${method}`} >
<button
aria-label={`${method} ${path.replace(/\//g, "\u200b/")}`}
aria-expanded={isShown}
className="opblock-summary-control"
onClick={toggleShown}
>
<OperationSummaryMethod method={method} />
<OperationSummaryPath getComponent={getComponent} operationProps={operationProps} specPath={specPath} />

{!showSummary ? null :
<div className="opblock-summary-description">
{toString(resolvedSummary || summary)}
</div>
}

{displayOperationId && (originalOperationId || operationId) ? <span className="opblock-summary-operation-id">{originalOperationId || operationId}</span> : null}

{displayOperationId && (originalOperationId || operationId) ? <span className="opblock-summary-operation-id">{originalOperationId || operationId}</span> : null}
<svg className="arrow" width="20" height="20" aria-hidden="true" focusable="false">
<use href={isShown ? "#large-arrow-up" : "#large-arrow-down"} xlinkHref={isShown ? "#large-arrow-up" : "#large-arrow-down"} />
</svg>
</button>

{
allowAnonymous ? null :
Expand Down
9 changes: 5 additions & 4 deletions src/core/components/operation-tag.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export default class OperationTag extends React.Component {
return (
<div className={showTag ? "opblock-tag-section is-open" : "opblock-tag-section"} >

<h4
<h3
onClick={() => layoutActions.show(isShownKey, !showTag)}
className={!tagDescription ? "opblock-tag no-desc" : "opblock-tag" }
id={isShownKey.map(v => escapeDeepLinkPath(v)).join("-")}
Expand Down Expand Up @@ -105,15 +105,16 @@ export default class OperationTag extends React.Component {
</div>

<button
aria-expanded={showTag}
className="expand-operation"
title={showTag ? "Collapse operation": "Expand operation"}
onClick={() => layoutActions.show(isShownKey, !showTag)}>

<svg className="arrow" width="20" height="20">
<use href={showTag ? "#large-arrow-down" : "#large-arrow"} xlinkHref={showTag ? "#large-arrow-down" : "#large-arrow"} />
<svg className="arrow" width="20" height="20" aria-hidden="true" focusable="false">
<use href={showTag ? "#large-arrow-up" : "#large-arrow-down"} xlinkHref={showTag ? "#large-arrow-up" : "#large-arrow-down"} />
</svg>
</button>
</h4>
</h3>

<Collapse isOpened={showTag}>
{children}
Expand Down
2 changes: 1 addition & 1 deletion src/core/components/operation.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ export default class Operation extends PureComponent {

return (
<div className={deprecated ? "opblock opblock-deprecated" : isShown ? `opblock opblock-${method} is-open` : `opblock opblock-${method}`} id={escapeDeepLinkPath(isShownKey.join("-"))} >
<OperationSummary operationProps={operationProps} toggleShown={toggleShown} getComponent={getComponent} authActions={authActions} authSelectors={authSelectors} specPath={specPath} />
<OperationSummary operationProps={operationProps} isShown={isShown} toggleShown={toggleShown} getComponent={getComponent} authActions={authActions} authSelectors={authSelectors} specPath={specPath} />
<Collapse isOpened={isShown}>
<div className="opblock-body">
{ (operation && operation.size) || operation === null ? null :
Expand Down
16 changes: 11 additions & 5 deletions src/core/components/responses.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { fromJS, Iterable } from "immutable"
import PropTypes from "prop-types"
import ImPropTypes from "react-immutable-proptypes"
import { defaultStatusCode, getAcceptControllingResponse } from "core/utils"
import createHtmlReadyId from "../../helpers/create-html-ready-id"

export default class Responses extends React.Component {
static propTypes = {
Expand Down Expand Up @@ -86,17 +87,22 @@ export default class Responses extends React.Component {
const acceptControllingResponse = isSpecOAS3 ?
getAcceptControllingResponse(responses) : null

const regionId = createHtmlReadyId(`${method}${path}_responses`)
const controlId = `${regionId}_select`

return (
<div className="responses-wrapper">
<div className="opblock-section-header">
<h4>Responses</h4>
{ specSelectors.isOAS3() ? null : <label>
{ specSelectors.isOAS3() ? null : <label htmlFor={controlId}>
<span>Response content type</span>
<ContentType value={producesValue}
onChange={this.onChangeProducesWrapper}
contentTypes={produces}
ariaControls={regionId}
ariaLabel="Response content type"
className="execute-content-type"
ariaLabel="Response content type" />
contentTypes={produces}
controlId={controlId}
onChange={this.onChangeProducesWrapper} />
</label> }
</div>
<div className="responses-inner">
Expand All @@ -115,7 +121,7 @@ export default class Responses extends React.Component {

}

<table className="responses-table">
<table aria-live="polite" className="responses-table" id={regionId} role="region">
<thead>
<tr className="responses-header">
<td className="col_header response-col_status">Code</td>
Expand Down
3 changes: 3 additions & 0 deletions src/core/components/svg-assets.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ const SvgAssets = () =>
<path d="M17.418 6.109c.272-.268.709-.268.979 0s.271.701 0 .969l-7.908 7.83c-.27.268-.707.268-.979 0l-7.908-7.83c-.27-.268-.27-.701 0-.969.271-.268.709-.268.979 0L10 13.25l7.418-7.141z"/>
</symbol>

<symbol viewBox="0 0 20 20" id="large-arrow-up">
<path d="M 17.418 14.908 C 17.69 15.176 18.127 15.176 18.397 14.908 C 18.667 14.64 18.668 14.207 18.397 13.939 L 10.489 6.109 C 10.219 5.841 9.782 5.841 9.51 6.109 L 1.602 13.939 C 1.332 14.207 1.332 14.64 1.602 14.908 C 1.873 15.176 2.311 15.176 2.581 14.908 L 10 7.767 L 17.418 14.908 Z"/>
</symbol>

<symbol viewBox="0 0 24 24" id="jump-to">
<path d="M19 7v4H5.83l3.58-3.59L8 6l-6 6 6 6 1.41-1.41L5.83 13H21V7z"/>
Expand Down
10 changes: 10 additions & 0 deletions src/helpers/create-html-ready-id.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/**
* Replace invalid characters from a string to create an html-ready ID
*
* @param {string} id A string that may contain invalid characters for the HTML ID attribute
* @param {string} [replacement=_] The string to replace invalid characters with; "_" by default
* @return {string} Information about the parameter schema
*/
export default function createHtmlReadyId(id, replacement = "_") {
return id.replace(/[^\w-]/g, replacement)
}
17 changes: 15 additions & 2 deletions src/style/_buttons.scss
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,21 @@
}
}

.opblock-summary-control,
.models-control,
.model-box-control
{
all: inherit;
flex: 1;
border-bottom: 0;
padding: 0;
cursor: pointer;

&:focus {
outline: auto;
}
}

.expand-methods,
.expand-operation
{
Expand Down Expand Up @@ -143,11 +158,9 @@
}
}


button
{
cursor: pointer;
outline: none;

&.invalid
{
Expand Down
25 changes: 6 additions & 19 deletions test/e2e-cypress/tests/features/model-collapse.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,45 +18,32 @@ function ModelCollapseTest(baseUrl, urlFragment) {
.get("#model-Pet")
.should("exist")
})

it("Models section should collapse and expand when toggled", () => {
cy.visit(baseUrl)
.get(".models h4")
.get(".models h4 .models-control")
.click()
.get(".models")
.should("not.have.class", "is-open")
.get("#model-Order")
.should("not.exist")
.get(".models h4")
.get(".models h4 .models-control")
.click()
.get(".models")
.should("have.class", "is-open")
.get("#model-Order")
.should("exist")
})

it("Model should collapse and expand when toggled clicking title", () => {
it("Model should collapse and expand when toggled clicking button", () => {
cy.visit(baseUrl)
.get("#model-User .model-box .pointer:nth-child(1)")
.get("#model-User .model-box .model-box-control")
.click()
.get("#model-User .model-box .model .inner-object")
.should("exist")
.get("#model-User .model-box .pointer:nth-child(1)")
.click()
.get("#model-User .model-box .model .inner-object")
.should("not.exist")
})

it("Model should collapse and expand when toggled clicking arrow", () => {
cy.visit(baseUrl)
.get("#model-User .model-box .pointer:nth-child(2)")
.click()
.get("#model-User .model-box .model .inner-object")
.should("exist")
.get("#model-User .model-box .pointer:nth-child(2)")
.get("#model-User .model-box .model-box-control")
.click()
.get("#model-User .model-box .model .inner-object")
.should("not.exist")
})
}

1 change: 1 addition & 0 deletions test/unit/components/operation-tag.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ describe("<OperationTag/>", function(){

const opblockTag = wrapper.find(".opblock-tag")
expect(opblockTag.length).toEqual(1)
expect(opblockTag.getNode().type).toEqual("h3")

const renderedLink = wrapper.find("Link")
expect(renderedLink.length).toEqual(1)
Expand Down