diff --git a/components/doc/splitter/accessibilitydoc.js b/components/doc/splitter/accessibilitydoc.js
index 9ddcc6f417..3d2d11e50c 100644
--- a/components/doc/splitter/accessibilitydoc.js
+++ b/components/doc/splitter/accessibilitydoc.js
@@ -50,6 +50,24 @@ export function AccessibilityDoc() {
Moves a vertical splitter to the right. |
+
+
+ home
+ |
+ Maximizes the primary panel. |
+
+
+
+ end
+ |
+ Minimizes the primary panel. |
+
+
+
+ enter
+ |
+ Toggles the primary panel between minimum and maximum sizes. |
+
diff --git a/components/lib/splitter/Splitter.js b/components/lib/splitter/Splitter.js
index 628463512d..b0c9bc84aa 100644
--- a/components/lib/splitter/Splitter.js
+++ b/components/lib/splitter/Splitter.js
@@ -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 = () => {};
@@ -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({});
@@ -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) => {
@@ -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') {
@@ -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);
@@ -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');
@@ -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(
@@ -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')
);
@@ -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',
diff --git a/components/lib/splitter/__snapshots__/Splitter.spec.js.snap b/components/lib/splitter/__snapshots__/Splitter.spec.js.snap
index 44920578f0..11b2a206c5 100644
--- a/components/lib/splitter/__snapshots__/Splitter.spec.js.snap
+++ b/components/lib/splitter/__snapshots__/Splitter.spec.js.snap
@@ -13,6 +13,7 @@ exports[`Splitter Nested 1`] = `
class="flex align-items-center justify-content-center p-splitter-panel"
data-p-splitter-panel-nested="false"
data-pc-section="splitterpanel.root"
+ id="pr_id_5_0"
role="presentation"
style="flex-basis: calc(20% - 4px);"
>
@@ -22,20 +23,26 @@ exports[`Splitter Nested 1`] = `
class="p-splitter-gutter"
data-p-splitter-gutter-resizing="false"
data-pc-section="gutter"
+ role="splitter"
style="width: 4px;"
>
@@ -49,6 +56,7 @@ exports[`Splitter Nested 1`] = `
class="flex align-items-center justify-content-center p-splitter-panel"
data-p-splitter-panel-nested="false"
data-pc-section="splitterpanel.root"
+ id="pr_id_7_0"
role="presentation"
style="flex-basis: calc(15% - 4px);"
>
@@ -58,20 +66,26 @@ exports[`Splitter Nested 1`] = `
class="p-splitter-gutter"
data-p-splitter-gutter-resizing="false"
data-pc-section="gutter"
+ role="splitter"
style="height: 4px;"
>
@@ -85,6 +99,7 @@ exports[`Splitter Nested 1`] = `
class="flex align-items-center justify-content-center p-splitter-panel"
data-p-splitter-panel-nested="false"
data-pc-section="splitterpanel.root"
+ id="pr_id_8_0"
role="presentation"
style="flex-basis: calc(20% - 4px);"
>
@@ -94,11 +109,16 @@ exports[`Splitter Nested 1`] = `
class="p-splitter-gutter"
data-p-splitter-gutter-resizing="false"
data-pc-section="gutter"
+ role="splitter"
style="width: 4px;"
>
@@ -134,6 +155,7 @@ exports[`Splitter Single Panel with size 1`] = `
class="p-splitter-panel"
data-p-splitter-panel-nested="false"
data-pc-section="splitterpanel.root"
+ id="pr_id_9_0"
role="presentation"
style="flex-basis: calc(5% - 0px);"
>
@@ -143,11 +165,16 @@ exports[`Splitter Single Panel with size 1`] = `
class="p-splitter-gutter"
data-p-splitter-gutter-resizing="false"
data-pc-section="gutter"
+ role="splitter"
style="height: 4px;"
>
@@ -179,11 +207,16 @@ exports[`Splitter Single Panel without size 1`] = `
class="p-splitter-gutter"
data-p-splitter-gutter-resizing="false"
data-pc-section="gutter"
+ role="splitter"
style="height: 4px;"
>
@@ -215,11 +249,16 @@ exports[`Splitter Splitter requires two SplitterPanel components to wrap. 1`] =
class="p-splitter-gutter"
data-p-splitter-gutter-resizing="false"
data-pc-section="gutter"
+ role="splitter"
style="width: 4px;"
>
@@ -251,6 +291,7 @@ exports[`Splitter Vertical layout 1`] = `
class="p-splitter-panel"
data-p-splitter-panel-nested="false"
data-pc-section="splitterpanel.root"
+ id="pr_id_2_0"
role="presentation"
style="flex-basis: calc(50% - 4px);"
>
@@ -260,11 +301,16 @@ exports[`Splitter Vertical layout 1`] = `
class="p-splitter-gutter"
data-p-splitter-gutter-resizing="false"
data-pc-section="gutter"
+ role="splitter"
style="height: 4px;"
>
diff --git a/components/lib/splitter/splitter.d.ts b/components/lib/splitter/splitter.d.ts
index 38747e0d11..d69f2f45db 100644
--- a/components/lib/splitter/splitter.d.ts
+++ b/components/lib/splitter/splitter.d.ts
@@ -105,7 +105,19 @@ export interface SplitterPassThroughOptions {
* Defines valid properties in SplitterPanel component.
* @group Properties
*/
-interface SplitterPanelProps {
+interface SplitterPanelProps extends Omit, HTMLDivElement>, 'ref'> {
+ /**
+ * Returns the value of element's id content attribute. Can be set to change it.
+ */
+ id?: string;
+ /**
+ * Establishes relationships between the splitter and panel label element IDs.
+ */
+ 'aria-labelledby'?: string | undefined;
+ /**
+ * Splitter handle ARIA label for screenreader support.
+ */
+ 'aria-label'?: string | undefined;
/**
* Size of the element relative to 100%.
*/