Skip to content

Commit

Permalink
Fix #5849: Splitter improve ARIA accessibility
Browse files Browse the repository at this point in the history
  • Loading branch information
melloware committed Jan 29, 2024
1 parent fe2312e commit c680482
Show file tree
Hide file tree
Showing 4 changed files with 156 additions and 27 deletions.
18 changes: 18 additions & 0 deletions components/doc/splitter/accessibilitydoc.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,24 @@ export function AccessibilityDoc() {
</td>
<td>Moves a vertical splitter to the right.</td>
</tr>
<tr>
<td>
<i>home</i>
</td>
<td>Maximizes the primary panel.</td>
</tr>
<tr>
<td>
<i>end</i>
</td>
<td>Minimizes the primary panel.</td>
</tr>
<tr>
<td>
<i>enter</i>
</td>
<td>Toggles the primary panel between minimum and maximum sizes.</td>
</tr>
</tbody>
</table>
</div>
Expand Down
82 changes: 67 additions & 15 deletions components/lib/splitter/Splitter.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import * as React from 'react';
import { PrimeReactContext } from '../api/Api';
import { useHandleStyle } from '../componentbase/ComponentBase';
import { useEventListener, useMergeProps } from '../hooks/Hooks';
import { DomHandler, ObjectUtils, classNames } from '../utils/Utils';
import { useEventListener, useMergeProps, useMountEffect } from '../hooks/Hooks';
import { DomHandler, ObjectUtils, UniqueComponentId, classNames } from '../utils/Utils';
import { SplitterBase, SplitterPanelBase } from './SplitterBase';

export const SplitterPanel = () => {};
Expand All @@ -13,6 +13,7 @@ export const Splitter = React.memo(
const context = React.useContext(PrimeReactContext);
const props = SplitterBase.getProps(inProps, context);

const idState = React.useRef('');
const elementRef = React.useRef(null);
const gutterRef = React.useRef();
const gutterRefs = React.useRef({});
Expand Down Expand Up @@ -183,13 +184,7 @@ export const Splitter = React.memo(
newNextPanelSize = nextPanelSize.current - newPos;
}

if (validateResize(newPrevPanelSize, newNextPanelSize)) {
prevPanelSizeNew.current = newPrevPanelSize;
nextPanelSizeNew.current = newNextPanelSize;
prevPanelElement.current.style.flexBasis = 'calc(' + newPrevPanelSize + '% - ' + (props.children.length - 1) * props.gutterSize + 'px)';
nextPanelElement.current.style.flexBasis = 'calc(' + newNextPanelSize + '% - ' + (props.children.length - 1) * props.gutterSize + 'px)';
prevSize.current = parseFloat(newPrevPanelSize).toFixed(4);
}
resizePanel(prevPanelIndex.current, newPrevPanelSize, newNextPanelSize);
};

const onResizeEnd = (event) => {
Expand Down Expand Up @@ -225,6 +220,8 @@ export const Splitter = React.memo(
};

const onGutterKeyDown = (event, index) => {
const minSize = (props.children[index].props && props.children[index].props.minSize) || 0;

switch (event.code) {
case 'ArrowLeft': {
if (props.layout === 'horizontal') {
Expand Down Expand Up @@ -262,12 +259,53 @@ export const Splitter = React.memo(
break;
}

case 'Home': {
resizePanel(index, 100, minSize);

event.preventDefault();
break;
}

case 'End': {
resizePanel(index, minSize, 100);

event.preventDefault();
break;
}

case 'Enter': {
if (prevSize.current > 99) {
resizePanel(index, minSize, 100);
} else {
resizePanel(index, 100, minSize);
}

event.preventDefault();
break;
}

default:
//no op
break;
}
};

const resizePanel = (index, newPrevPanelSize, newNextPanelSize) => {
prevPanelIndex.current = index;
gutterRef.current = gutterRefs.current[index];
size.current = horizontal ? DomHandler.getWidth(elementRef.current) : DomHandler.getHeight(elementRef.current);
prevPanelElement.current = gutterRef.current.previousElementSibling;
nextPanelElement.current = gutterRef.current.nextElementSibling;

if (validateResize(newPrevPanelSize, newNextPanelSize)) {
prevPanelSizeNew.current = newPrevPanelSize;
nextPanelSizeNew.current = newNextPanelSize;
prevPanelElement.current.style.flexBasis = 'calc(' + newPrevPanelSize + '% - ' + (props.children.length - 1) * props.gutterSize + 'px)';
nextPanelElement.current.style.flexBasis = 'calc(' + newNextPanelSize + '% - ' + (props.children.length - 1) * props.gutterSize + 'px)';
prevSize.current = parseFloat(newPrevPanelSize).toFixed(4);
}
};

const repeat = (event, index, step) => {
onResizeStart(event, index, true);
onResize(event, step, true);
Expand Down Expand Up @@ -313,6 +351,12 @@ export const Splitter = React.memo(
getElement: () => elementRef.current
}));

useMountEffect(() => {
if (elementRef.current) {
idState.current = UniqueComponentId();
}
});

React.useEffect(() => {
const panelElements = [...elementRef.current.children].filter((child) => DomHandler.getAttribute(child, 'data-pc-section') === 'splitterpanel.root');

Expand All @@ -333,6 +377,7 @@ export const Splitter = React.memo(
}, [restoreState, isStateful]);

const createPanel = (panel, index) => {
const panelId = getPanelProp(panel, 'id') || `${idState.current}_${index}`;
const panelClassName = classNames(getPanelProp(panel, 'className'), cx('panel.root'));

const gutterProps = mergeProps(
Expand All @@ -346,17 +391,24 @@ export const Splitter = React.memo(
onTouchStart: (event) => onGutterTouchStart(event, index),
onTouchMove: (event) => onGutterTouchMove(event),
onTouchEnd: (event) => onGutterTouchEnd(event),
'data-p-splitter-gutter-resizing': false
'data-p-splitter-gutter-resizing': false,
role: 'splitter'
},
ptm('gutter')
);

const gutterHandlerProps = mergeProps(
{
tabIndex: 0,
tabIndex: getPanelProp(panel, 'tabIndex') || 0,
className: cx('gutterHandler'),
'aria-orientation': props.layout,
'aria-valuenow': prevSize.current
'aria-orientation': props.layout === 'horizontal' ? 'vertical' : 'horizontal',
'aria-controls': panelId,
'aria-label': getPanelProp(panel, 'aria-label'),
'aria-labelledby': getPanelProp(panel, 'aria-labelledby'),
'aria-valuenow': prevSize.current,
'aria-valuetext': parseFloat(prevSize.current).toFixed(0) + '%',
'aria-valuemin': getPanelProp(panel, 'minSize') || '0',
'aria-valuemax': '100'
},
ptm('gutterHandler')
);
Expand All @@ -371,8 +423,8 @@ export const Splitter = React.memo(

const rootProps = mergeProps(
{
key: index,
id: getPanelProp(panel, 'id'),
key: panelId,
id: panelId,
className: panelClassName,
style: { ...getPanelProp(panel, 'style'), flexBasis },
role: 'presentation',
Expand Down
Loading

0 comments on commit c680482

Please sign in to comment.