@zendeskgarden/react-grid
Version:
Components relating to layout grids in the Garden Design System
129 lines (126 loc) • 4.45 kB
JavaScript
/**
* Copyright Zendesk, Inc.
*
* Use of this source code is governed under the Apache License, Version 2.0
* found at http://www.apache.org/licenses/LICENSE-2.0.
*/
import React, { forwardRef, useContext, useRef, useEffect, useMemo } from 'react';
import { mergeRefs } from 'react-merge-refs';
import PropTypes from 'prop-types';
import { ThemeContext } from 'styled-components';
import { useSplitter } from '@zendeskgarden/container-splitter';
import { usePaneProviderContextData } from '../../../utils/usePaneProviderContext.js';
import usePaneContext from '../../../utils/usePaneContext.js';
import { ORIENTATION } from '../../../types/index.js';
import '../../../styled/StyledCol.js';
import '../../../styled/StyledGrid.js';
import '../../../styled/StyledRow.js';
import '../../../styled/pane/StyledPane.js';
import '../../../styled/pane/StyledPaneContent.js';
import { StyledPaneSplitter } from '../../../styled/pane/StyledPaneSplitter.js';
import '../../../styled/pane/StyledPaneSplitterButton.js';
import '../../../styled/pane/StyledPaneSplitterButtonContainer.js';
import { PaneSplitterContext } from '../../../utils/usePaneSplitterContext.js';
import { useDocument, useText } from '@zendeskgarden/react-theming';
const paneToSplitterOrientation = {
start: 'vertical',
end: 'vertical',
top: 'horizontal',
bottom: 'horizontal'
};
const orientationToDimension = {
start: 'columns',
end: 'columns',
top: 'rows',
bottom: 'rows'
};
const SplitterComponent = forwardRef((_ref, ref) => {
let {
children,
providerId,
layoutKey,
min,
max,
orientation,
isFixed,
onMouseDown,
onTouchStart,
onKeyDown,
onClick,
...props
} = _ref;
const paneProviderContext = usePaneProviderContextData(providerId);
const paneContext = usePaneContext();
const themeContext = useContext(ThemeContext);
const environment = useDocument(themeContext);
const isRow = orientationToDimension[orientation] === 'rows';
const separatorRef = useRef(null);
const splitterOrientation = paneToSplitterOrientation[orientation || 'end'];
const pixelsPerFr = paneProviderContext ? paneProviderContext.pixelsPerFr[orientationToDimension[orientation]] : 0;
const value = isRow ? paneProviderContext?.getRowValue(layoutKey, true) : paneProviderContext?.getColumnValue(layoutKey, true);
const valueInFr = isRow ? paneProviderContext?.getRowValue(layoutKey) : paneProviderContext?.getColumnValue(layoutKey);
const {
getSeparatorProps,
getPrimaryPaneProps
} = useSplitter({
orientation: splitterOrientation,
isLeading: orientation === 'start' || orientation === 'top',
min: min * pixelsPerFr,
max: max * pixelsPerFr,
rtl: themeContext.rtl,
isFixed,
environment,
onChange: valueNow => {
if (isRow) {
return paneProviderContext?.setRowValue(orientation === 'top', layoutKey, valueNow / pixelsPerFr);
}
return paneProviderContext?.setColumnValue(orientation === 'start', layoutKey, valueNow / pixelsPerFr);
},
valueNow: value,
separatorRef
});
useEffect(() => {
if (!paneContext.id) {
paneContext.setId(getPrimaryPaneProps().id);
}
}, [paneContext, getPrimaryPaneProps]);
const ariaLabel = useText(SplitterComponent, props, 'aria-label', `${splitterOrientation} splitter`);
const separatorProps = getSeparatorProps({
'aria-controls': paneContext.id,
'aria-label': ariaLabel,
onMouseDown,
onTouchStart,
onKeyDown,
onClick
});
const size = isRow ? separatorRef.current?.clientWidth : separatorRef.current?.clientHeight;
return React.createElement(PaneSplitterContext.Provider, {
value: useMemo(() => ({
orientation,
layoutKey,
min,
max,
valueNow: valueInFr,
size,
isRow
}), [orientation, layoutKey, min, max, valueInFr, size, isRow])
}, React.createElement(StyledPaneSplitter, Object.assign({
$isFixed: isFixed,
$orientation: orientation
}, separatorProps, props, {
ref: mergeRefs([separatorRef, ref])
})), children );
});
SplitterComponent.displayName = 'Pane.Splitter';
SplitterComponent.propTypes = {
layoutKey: PropTypes.string.isRequired,
min: PropTypes.number.isRequired,
max: PropTypes.number.isRequired,
orientation: PropTypes.oneOf(ORIENTATION),
isFixed: PropTypes.bool
};
SplitterComponent.defaultProps = {
orientation: 'end'
};
const Splitter = SplitterComponent;
export { Splitter };