Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 3 additions & 21 deletions packages/grid/src/elements/pane/components/Splitter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,10 @@
* found at http://www.apache.org/licenses/LICENSE-2.0.
*/

import React, {
useContext,
useEffect,
forwardRef,
useMemo,
useState,
useRef,
HTMLAttributes
} from 'react';
import React, { useContext, useEffect, forwardRef, useMemo, useRef, HTMLAttributes } from 'react';
import mergeRefs from 'react-merge-refs';
import PropTypes from 'prop-types';
import { ThemeContext } from 'styled-components';
import { composeEventHandlers } from '@zendeskgarden/container-utilities';
import { useSplitter } from '@zendeskgarden/container-splitter';
import { usePaneProviderContextData } from '../../../utils/usePaneProviderContext';
import usePaneContext from '../../../utils/usePaneContext';
Expand All @@ -43,6 +34,7 @@ const orientationToDimension: Record<string, 'columns' | 'rows'> = {
const SplitterComponent = forwardRef<HTMLDivElement, ISplitterProps>(
(
{
children,
providerId,
layoutKey,
min,
Expand All @@ -61,7 +53,6 @@ const SplitterComponent = forwardRef<HTMLDivElement, ISplitterProps>(
const paneContext = usePaneContext();
const themeContext = useContext(ThemeContext);
const environment = useDocument(themeContext);
const [isHovered, setIsHovered] = useState(false);
const isRow = orientationToDimension[orientation!] === 'rows';
const separatorRef = useRef<HTMLDivElement>(null);

Expand Down Expand Up @@ -131,14 +122,6 @@ const SplitterComponent = forwardRef<HTMLDivElement, ISplitterProps>(

const size = isRow ? separatorRef.current?.clientWidth : separatorRef.current?.clientHeight;

const onMouseOver = useMemo(
() =>
composeEventHandlers(props.onMouseOver, (event: MouseEvent) =>
setIsHovered(event.target === separatorRef.current)
),
[props.onMouseOver, separatorRef]
);

return (
<PaneSplitterContext.Provider
value={useMemo(
Expand All @@ -147,14 +130,13 @@ const SplitterComponent = forwardRef<HTMLDivElement, ISplitterProps>(
)}
>
<StyledPaneSplitter
isHovered={isHovered}
isFixed={isFixed}
orientation={orientation}
{...separatorProps}
{...props}
onMouseOver={onMouseOver}
ref={mergeRefs([separatorRef, ref])}
/>
{children /* Splitter.Button is the only valid child */}
</PaneSplitterContext.Provider>
);
}
Expand Down
39 changes: 24 additions & 15 deletions packages/grid/src/elements/pane/components/SplitterButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import React, { forwardRef, useCallback } from 'react';
import { Tooltip } from '@zendeskgarden/react-tooltips';
import { composeEventHandlers } from '@zendeskgarden/container-utilities';
import { StyledPaneSplitterButton } from '../../../styled';
import { StyledPaneSplitterButton, StyledPaneSplitterButtonContainer } from '../../../styled';
import { ISplitterButtonProps } from '../../../types';
import usePaneSplitterContext from '../../../utils/usePaneSplitterContext';
import { usePaneProviderContextData } from '../../../utils/usePaneProviderContext';
Expand Down Expand Up @@ -62,20 +62,29 @@ const SplitterButtonComponent = forwardRef<HTMLButtonElement, ISplitterButtonPro
);

return (
<Tooltip content={label} style={{ cursor: 'default' }} onMouseDown={e => e.stopPropagation()}>
<StyledPaneSplitterButton
aria-label={label}
{...props}
placement={placement!}
orientation={orientation!}
isRotated={isMin}
splitterSize={size || 0}
ref={ref}
onClick={onClick}
onKeyDown={onKeyDown}
onMouseDown={onMouseDown}
/>
</Tooltip>
<StyledPaneSplitterButtonContainer
orientation={orientation!}
placement={placement!}
splitterSize={size || 0}
>
<Tooltip
content={label}
zIndex={2}
style={{ cursor: 'default' }}
onMouseDown={e => e.stopPropagation()}
>
<StyledPaneSplitterButton
aria-label={label}
{...props}
orientation={orientation!}
isRotated={isMin}
ref={ref}
onClick={onClick}
onKeyDown={onKeyDown}
onMouseDown={onMouseDown}
/>
</Tooltip>
</StyledPaneSplitterButtonContainer>
);
}
);
Expand Down
1 change: 1 addition & 0 deletions packages/grid/src/styled/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ export * from './pane/StyledPane';
export * from './pane/StyledPaneContent';
export * from './pane/StyledPaneSplitter';
export * from './pane/StyledPaneSplitterButton';
export * from './pane/StyledPaneSplitterButtonContainer';
7 changes: 3 additions & 4 deletions packages/grid/src/styled/pane/StyledPaneSplitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import { Orientation } from '../../types';
const COMPONENT_ID = 'pane.splitter';

interface IStyledPaneSplitterProps {
isHovered: boolean;
orientation?: Orientation;
isFixed?: boolean;
}
Expand All @@ -35,7 +34,7 @@ const colorStyles = (props: IStyledPaneSplitterProps & ThemeProps<DefaultTheme>)
}

&:hover::before {
background-color: ${props.isHovered && hoverColor};
background-color: ${hoverColor};
}

${focusStyles({
Expand All @@ -48,7 +47,7 @@ const colorStyles = (props: IStyledPaneSplitterProps & ThemeProps<DefaultTheme>)
})}

&:active::before {
background-color: ${props.isHovered && activeColor};
background-color: ${activeColor};
}
`;
};
Expand Down Expand Up @@ -140,7 +139,7 @@ const sizeStyles = (props: IStyledPaneSplitterProps & ThemeProps<DefaultTheme>)
}

&:hover::before {
${dimensionProperty}: ${props.isHovered && separatorSize};
${dimensionProperty}: ${separatorSize};
}

&:focus::before,
Expand Down
121 changes: 16 additions & 105 deletions packages/grid/src/styled/pane/StyledPaneSplitterButton.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,29 @@
*/

import styled, { css, ThemeProps, DefaultTheme } from 'styled-components';
import { math, stripUnit } from 'polished';
import {
retrieveComponentStyles,
DEFAULT_THEME,
getColorV8,
focusStyles,
SELECTOR_FOCUS_VISIBLE
} from '@zendeskgarden/react-theming';
import { ISplitterButtonProps, Orientation, PLACEMENT } from '../../types';
import { retrieveComponentStyles, DEFAULT_THEME } from '@zendeskgarden/react-theming';
import { ChevronButton } from '@zendeskgarden/react-buttons';
import { StyledPaneSplitter } from './StyledPaneSplitter';
import { Orientation } from '../../types';

const COMPONENT_ID = 'pane.splitter_button';

interface IStyledSplitterButtonProps extends ISplitterButtonProps {
interface IStyledSplitterButtonProps {
orientation: Orientation;
placement: (typeof PLACEMENT)[number];
isRotated: boolean;
splitterSize: number;
}

export const getSize = (theme: DefaultTheme) => theme.space.base * 6;

const sizeStyles = ({ theme }: ThemeProps<DefaultTheme>) => {
const size = `${getSize(theme)}px`;

return css`
width: ${size};
min-width: ${size};
height: ${size};
`;
};

const transformStyles = (props: IStyledSplitterButtonProps & ThemeProps<DefaultTheme>) => {
let degrees = 0;

Expand All @@ -49,107 +51,16 @@ const transformStyles = (props: IStyledSplitterButtonProps & ThemeProps<DefaultT
`;
};

const colorStyles = ({ theme }: IStyledSplitterButtonProps & ThemeProps<DefaultTheme>) => {
const boxShadow = theme.shadows.lg(
`${theme.space.base}px`,
`${theme.space.base * 2}px`,
getColorV8('chromeHue', 600, theme, 0.15)!
);

return css`
box-shadow: ${boxShadow};

${focusStyles({
theme,
boxShadow
})}
`;
};

const sizeStyles = (props: IStyledSplitterButtonProps & ThemeProps<DefaultTheme>) => {
const size = `${props.theme.space.base * 6}px`;
const display =
props.splitterSize <=
(stripUnit(math(`${props.theme.shadowWidths.md} * 2 + ${size}`)) as number) && 'none';
const isVertical = props.orientation === 'start' || props.orientation === 'end';
let top;
let left;
let right;
let bottom;

if (props.splitterSize >= (stripUnit(math(`${size} * 3`)) as number)) {
if (props.placement === 'start') {
if (isVertical) {
top = size;
} else if (props.theme.rtl) {
right = size;
} else {
left = size;
}
} else if (props.placement === 'end') {
if (isVertical) {
bottom = size;
} else if (props.theme.rtl) {
left = size;
} else {
right = size;
}
}
}

return css`
display: ${display};
/* stylelint-disable declaration-block-no-redundant-longhand-properties */
top: ${top};
right: ${right};
bottom: ${bottom};
left: ${left};
width: ${size};
min-width: ${size};
height: ${size};
`;
};

/**
* 1. Opaque "dish" behind transparent button
*/
export const StyledPaneSplitterButton = styled(ChevronButton).attrs<IStyledSplitterButtonProps>({
'data-garden-id': COMPONENT_ID,
'data-garden-version': PACKAGE_VERSION,
isBasic: true,
isPill: true,
size: 'small'
})<IStyledSplitterButtonProps>`
position: absolute;
/* prettier-ignore */
transition:
box-shadow 0.1s ease-in-out,
background-color 0.25s ease-in-out,
opacity 0.25s ease-in-out 0.1s;
opacity: 0;

${sizeStyles};
${transformStyles};

/* [1] */
&::before {
position: absolute;
z-index: -1;
background-color: ${props => getColorV8('background', 600 /* default shade */, props.theme)};
width: 100%;
height: 100%;
content: '';
}

${colorStyles};

/* stylelint-disable selector-no-qualifying-type */
${StyledPaneSplitter}:hover &,
${StyledPaneSplitter}:focus-visible &,
${StyledPaneSplitter}[data-garden-focus-visible] &,
${SELECTOR_FOCUS_VISIBLE} {
opacity: 1;
}
${transformStyles};

${props => retrieveComponentStyles(COMPONENT_ID, props)};
`;
Expand Down
Loading