fix: make samples accessible by keyboard (#1401)

* fix: make samples accessible by keyboard

* chore: set outline-width and padding to collapser
This commit is contained in:
Anna Stasiuk 2020-10-13 14:56:03 +03:00 committed by GitHub
parent 0c782ec51f
commit 146b38c9d0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 45 additions and 18 deletions

View File

@ -34,11 +34,11 @@ class Json extends React.PureComponent<JsonProps> {
<button onClick={this.collapseAll}> Collapse all </button> <button onClick={this.collapseAll}> Collapse all </button>
</SampleControls> </SampleControls>
<OptionsContext.Consumer> <OptionsContext.Consumer>
{options => ( {(options) => (
<PrismDiv <PrismDiv
className={this.props.className} className={this.props.className}
// tslint:disable-next-line // tslint:disable-next-line
ref={node => (this.node = node!)} ref={(node) => (this.node = node!)}
dangerouslySetInnerHTML={{ dangerouslySetInnerHTML={{
__html: jsonToHTML(this.props.data, options.jsonSampleExpandLevel), __html: jsonToHTML(this.props.data, options.jsonSampleExpandLevel),
}} }}
@ -65,9 +65,8 @@ class Json extends React.PureComponent<JsonProps> {
} }
}; };
clickListener = (event: MouseEvent) => { collapseElement = (target: HTMLElement) => {
let collapsed; let collapsed;
const target = event.target as HTMLElement;
if (target.className === 'collapser') { if (target.className === 'collapser') {
collapsed = target.parentElement!.getElementsByClassName('collapsible')[0]; collapsed = target.parentElement!.getElementsByClassName('collapsible')[0];
if (collapsed.parentElement.classList.contains('collapsed')) { if (collapsed.parentElement.classList.contains('collapsed')) {
@ -78,12 +77,24 @@ class Json extends React.PureComponent<JsonProps> {
} }
}; };
clickListener = (event: MouseEvent) => {
this.collapseElement(event.target as HTMLElement);
};
focusListener = (event: KeyboardEvent) => {
if (event.key === 'Enter') {
this.collapseElement(event.target as HTMLElement);
}
};
componentDidMount() { componentDidMount() {
this.node!.addEventListener('click', this.clickListener); this.node!.addEventListener('click', this.clickListener);
this.node!.addEventListener('focus', this.focusListener);
} }
componentWillUnmount() { componentWillUnmount() {
this.node!.removeEventListener('click', this.clickListener); this.node!.removeEventListener('click', this.clickListener);
this.node!.removeEventListener('focus', this.focusListener);
} }
} }

View File

@ -1,12 +1,13 @@
import { css } from '../../styled-components'; import { css } from '../../styled-components';
export const jsonStyles = css` export const jsonStyles = css`
.redoc-json > .collapser { .redoc-json code > .collapser {
display: none; display: none;
pointer-events: none;
} }
font-family: ${props => props.theme.typography.code.fontFamily}; font-family: ${(props) => props.theme.typography.code.fontFamily};
font-size: ${props => props.theme.typography.code.fontSize}; font-size: ${(props) => props.theme.typography.code.fontSize};
white-space: ${({ theme }) => (theme.typography.code.wrap ? 'pre-wrap' : 'pre')}; white-space: ${({ theme }) => (theme.typography.code.wrap ? 'pre-wrap' : 'pre')};
contain: content; contain: content;
@ -47,8 +48,32 @@ export const jsonStyles = css`
} }
.collapser { .collapser {
background-color: transparent;
border: 0;
color: #fff;
font-family: ${(props) => props.theme.typography.code.fontFamily};
font-size: ${(props) => props.theme.typography.code.fontSize};
padding-right: 6px; padding-right: 6px;
padding-left: 6px; padding-left: 6px;
padding-top: 0;
padding-bottom: 0;
display: flex;
align-items: center;
justify-content: center;
width: 15px;
height: 15px;
position: absolute;
top: 4px;
left: -1.5em;
cursor: default;
user-select: none;
-webkit-user-select: none;
padding: 2px;
&:focus {
outline-color: #fff;
outline-style: dotted;
outline-width: 1px;
}
} }
ul { ul {
@ -83,13 +108,4 @@ export const jsonStyles = css`
.collapsed > .ellipsis { .collapsed > .ellipsis {
display: inherit; display: inherit;
} }
.collapser {
position: absolute;
top: 1px;
left: -1.5em;
cursor: default;
user-select: none;
-webkit-user-select: none;
}
`; `;

View File

@ -73,7 +73,7 @@ function valueToHTML(value, maxExpandLevel: number) {
function arrayToHTML(json, maxExpandLevel: number) { function arrayToHTML(json, maxExpandLevel: number) {
const collapsed = level > maxExpandLevel ? 'collapsed' : ''; const collapsed = level > maxExpandLevel ? 'collapsed' : '';
let output = `<div class="collapser"></div>${punctuation( let output = `<button class="collapser"></button>${punctuation(
'[', '[',
)}<span class="ellipsis"></span><ul class="array collapsible">`; )}<span class="ellipsis"></span><ul class="array collapsible">`;
let hasContents = false; let hasContents = false;
@ -98,7 +98,7 @@ function objectToHTML(json, maxExpandLevel: number) {
const collapsed = level > maxExpandLevel ? 'collapsed' : ''; const collapsed = level > maxExpandLevel ? 'collapsed' : '';
const keys = Object.keys(json); const keys = Object.keys(json);
const length = keys.length; const length = keys.length;
let output = `<div class="collapser"></div>${punctuation( let output = `<button class="collapser"></button>${punctuation(
'{', '{',
)}<span class="ellipsis"></span><ul class="obj collapsible">`; )}<span class="ellipsis"></span><ul class="obj collapsible">`;
let hasContents = false; let hasContents = false;