mirror of
https://github.com/reduxjs/redux-devtools.git
synced 2025-06-29 17:33:08 +03:00
Initial Basic Accessibility Added
This commit is contained in:
parent
c5aef77b85
commit
e8b07a9c11
|
@ -1,6 +1,6 @@
|
||||||
import React, { useCallback, useState } from 'react';
|
import React, { useCallback, useState } from 'react';
|
||||||
import JSONArrow from './JSONArrow.js';
|
import JSONArrow from './JSONArrow.js';
|
||||||
import type { CircularCache, CommonInternalProps } from './types.js';
|
import type { CircularCache, CommonInternalProps, KeyPath } from './types.js';
|
||||||
|
|
||||||
interface Props extends CommonInternalProps {
|
interface Props extends CommonInternalProps {
|
||||||
data: unknown;
|
data: unknown;
|
||||||
|
@ -10,6 +10,7 @@ interface Props extends CommonInternalProps {
|
||||||
renderChildNodes: (props: Props, from: number, to: number) => React.ReactNode;
|
renderChildNodes: (props: Props, from: number, to: number) => React.ReactNode;
|
||||||
circularCache: CircularCache;
|
circularCache: CircularCache;
|
||||||
level: number;
|
level: number;
|
||||||
|
keyPath: KeyPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function ItemRange(props: Props) {
|
export default function ItemRange(props: Props) {
|
||||||
|
@ -32,6 +33,7 @@ export default function ItemRange(props: Props) {
|
||||||
expanded={false}
|
expanded={false}
|
||||||
onClick={handleClick}
|
onClick={handleClick}
|
||||||
arrowStyle="double"
|
arrowStyle="double"
|
||||||
|
ariaLabel={`Expand Array from ${from} to ${to}`}
|
||||||
/>
|
/>
|
||||||
{`${from} ... ${to}`}
|
{`${from} ... ${to}`}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -6,7 +6,9 @@ interface Props {
|
||||||
arrowStyle?: 'single' | 'double';
|
arrowStyle?: 'single' | 'double';
|
||||||
expanded: boolean;
|
expanded: boolean;
|
||||||
nodeType: string;
|
nodeType: string;
|
||||||
onClick: React.MouseEventHandler<HTMLDivElement>;
|
onClick: React.MouseEventHandler<HTMLButtonElement>;
|
||||||
|
ariaControls?: string;
|
||||||
|
ariaLabel?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function JSONArrow({
|
export default function JSONArrow({
|
||||||
|
@ -15,15 +17,17 @@ export default function JSONArrow({
|
||||||
expanded,
|
expanded,
|
||||||
nodeType,
|
nodeType,
|
||||||
onClick,
|
onClick,
|
||||||
|
ariaControls,
|
||||||
|
ariaLabel
|
||||||
}: Props) {
|
}: Props) {
|
||||||
return (
|
return (
|
||||||
<div {...styling('arrowContainer', arrowStyle)} onClick={onClick}>
|
<button {...styling('arrowContainer', arrowStyle)} aria-label={ariaLabel} aria-expanded={expanded} aria-controls={ariaControls} onClick={onClick}>
|
||||||
<div {...styling(['arrow', 'arrowSign'], nodeType, expanded, arrowStyle)}>
|
<div {...styling(['arrow', 'arrowSign'], nodeType, expanded, arrowStyle)}>
|
||||||
{'\u25B6'}
|
{'\u25B6'}
|
||||||
{arrowStyle === 'double' && (
|
{arrowStyle === 'double' && (
|
||||||
<div {...styling(['arrowSign', 'arrowSignInner'])}>{'\u25B6'}</div>
|
<div {...styling(['arrowSign', 'arrowSignInner'])}>{'\u25B6'}</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</button>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import getCollectionEntries from './getCollectionEntries.js';
|
||||||
import JSONNode from './JSONNode.js';
|
import JSONNode from './JSONNode.js';
|
||||||
import ItemRange from './ItemRange.js';
|
import ItemRange from './ItemRange.js';
|
||||||
import type { CircularCache, CommonInternalProps } from './types.js';
|
import type { CircularCache, CommonInternalProps } from './types.js';
|
||||||
|
import getAriaPropsFromKeyPath from './getAriaPropsFromKeyPath.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Renders nested values (eg. objects, arrays, lists, etc.)
|
* Renders nested values (eg. objects, arrays, lists, etc.)
|
||||||
|
@ -62,6 +63,7 @@ function renderChildNodes(
|
||||||
from={entry.from}
|
from={entry.from}
|
||||||
to={entry.to}
|
to={entry.to}
|
||||||
renderChildNodes={renderChildNodes}
|
renderChildNodes={renderChildNodes}
|
||||||
|
keyPath={[entry.from, ...keyPath]}
|
||||||
/>,
|
/>,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
@ -141,6 +143,8 @@ export default function JSONNestedNode(props: Props) {
|
||||||
);
|
);
|
||||||
const stylingArgs = [keyPath, nodeType, expanded, expandable] as const;
|
const stylingArgs = [keyPath, nodeType, expanded, expandable] as const;
|
||||||
|
|
||||||
|
const {ariaControls, ariaLabel} = getAriaPropsFromKeyPath(keyPath)
|
||||||
|
|
||||||
return hideRoot ? (
|
return hideRoot ? (
|
||||||
<li {...styling('rootNode', ...stylingArgs)}>
|
<li {...styling('rootNode', ...stylingArgs)}>
|
||||||
<ul {...styling('rootNodeChildren', ...stylingArgs)}>
|
<ul {...styling('rootNodeChildren', ...stylingArgs)}>
|
||||||
|
@ -155,6 +159,8 @@ export default function JSONNestedNode(props: Props) {
|
||||||
nodeType={nodeType}
|
nodeType={nodeType}
|
||||||
expanded={expanded}
|
expanded={expanded}
|
||||||
onClick={handleClick}
|
onClick={handleClick}
|
||||||
|
ariaControls={ariaControls}
|
||||||
|
ariaLabel={ariaLabel}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<label
|
<label
|
||||||
|
@ -169,7 +175,7 @@ export default function JSONNestedNode(props: Props) {
|
||||||
>
|
>
|
||||||
{renderedItemString}
|
{renderedItemString}
|
||||||
</span>
|
</span>
|
||||||
<ul {...styling('nestedNodeChildren', ...stylingArgs)}>
|
<ul {...styling('nestedNodeChildren', ...stylingArgs)} id={expandable ? ariaControls : undefined}>
|
||||||
{renderedChildren}
|
{renderedChildren}
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -122,6 +122,11 @@ const getDefaultThemeStyling = (theme: Base16Theme): StylingConfig => {
|
||||||
arrowContainer: ({ style }, arrowStyle) => ({
|
arrowContainer: ({ style }, arrowStyle) => ({
|
||||||
style: {
|
style: {
|
||||||
...style,
|
...style,
|
||||||
|
background: 'none',
|
||||||
|
color: 'inherit',
|
||||||
|
border: 'none',
|
||||||
|
padding: 0,
|
||||||
|
font: 'inherit',
|
||||||
display: 'inline-block',
|
display: 'inline-block',
|
||||||
paddingRight: '0.5em',
|
paddingRight: '0.5em',
|
||||||
paddingLeft: arrowStyle === 'double' ? '1em' : 0,
|
paddingLeft: arrowStyle === 'double' ? '1em' : 0,
|
||||||
|
|
21
packages/react-json-tree/src/getAriaPropsFromKeyPath.ts
Normal file
21
packages/react-json-tree/src/getAriaPropsFromKeyPath.ts
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
import { KeyPath } from "./types.js";
|
||||||
|
|
||||||
|
const replaceSpacesRegex = / /g;
|
||||||
|
|
||||||
|
const getAriaPropsFromKeyPath = (
|
||||||
|
keyPath: KeyPath
|
||||||
|
) => {
|
||||||
|
let ariaControls = '';
|
||||||
|
let ariaLabel = 'JSON Tree Node: ';
|
||||||
|
for(let i = keyPath.length - 1; i >= 0; i--) {
|
||||||
|
const key = keyPath[i];
|
||||||
|
ariaControls += `${key}`.replace(replaceSpacesRegex, '-');
|
||||||
|
ariaLabel += `${key} `;
|
||||||
|
}
|
||||||
|
|
||||||
|
ariaLabel = ariaLabel.trim();
|
||||||
|
|
||||||
|
return { ariaControls, ariaLabel };
|
||||||
|
}
|
||||||
|
|
||||||
|
export default getAriaPropsFromKeyPath;
|
Loading…
Reference in New Issue
Block a user