Skip to content

Commit

Permalink
Merge pull request #5419 from pat270/clay-5348
Browse files Browse the repository at this point in the history
feat(@clayui/core): Vertical Bar adds resizing to VerticalBar.Panel
  • Loading branch information
matuzalemsteles committed Mar 22, 2023
2 parents 3aeba2f + e2842c0 commit 1044c81
Show file tree
Hide file tree
Showing 17 changed files with 355 additions and 5 deletions.
28 changes: 26 additions & 2 deletions packages/clay-core/src/vertical-bar/Panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import React, {useContext, useEffect, useRef} from 'react';
import {CSSTransition} from 'react-transition-group';

import {ContentContext} from './Content';
import {Resizer} from './Resizer';
import {VerticalBarContext} from './context';

function useIsFirstRender(): boolean {
Expand Down Expand Up @@ -41,11 +42,14 @@ type Props = {
};

export function Panel({children, keyValue, tabIndex}: Props) {
const {activePanel, id} = useContext(VerticalBarContext);
const {activePanel, id, panelWidth, panelWidthMax, panelWidthMin, resize} =
useContext(VerticalBarContext);
const {displayType} = useContext(ContentContext);

const isFirst = useIsFirstRender();

const nodeRef = useRef<HTMLDivElement | null>(null);

const previousActivePanelRef = useRef<React.Key | null>(null);

useEffect(() => {
Expand All @@ -68,6 +72,7 @@ export function Panel({children, keyValue, tabIndex}: Props) {
}}
id={`${id}-tabpanel-${keyValue}`}
in={activePanel === keyValue}
nodeRef={nodeRef}
role="tabpanel"
tabIndex={tabIndex}
timeout={
Expand All @@ -80,7 +85,26 @@ export function Panel({children, keyValue, tabIndex}: Props) {
}
unmountOnExit
>
<div>{children}</div>
<div
ref={nodeRef}
style={{
width: panelWidth,
}}
>
{children}

{resize && (
<Resizer
aria-controls={`${id}-tabpanel-${keyValue}`}
aria-orientation="vertical"
aria-valuemax={panelWidthMax}
aria-valuemin={panelWidthMin}
aria-valuenow={panelWidth}
className="c-horizontal-resizer"
nodeRef={nodeRef}
/>
)}
</div>
</CSSTransition>
);
}
141 changes: 141 additions & 0 deletions packages/clay-core/src/vertical-bar/Resizer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
/**
* SPDX-FileCopyrightText: © 2023 Liferay, Inc. <https://liferay.com>
* SPDX-License-Identifier: BSD-3-Clause
*/

import {Keys} from '@clayui/shared';
import React, {useContext} from 'react';

import {VerticalBarContext} from './context';

type Props = {
/**
* Sets the CSS className for the component.
*/
className?: string;

/**
* Reference to Panel
*/
nodeRef?: React.RefObject<HTMLDivElement>;
};

const MAIN_MOUSE_BUTTON = 0;

let keyDownCounter = 0;

export function Resizer({nodeRef, ...otherProps}: Props) {
const {onPanelWidthChange, panelWidthMax, panelWidthMin, position} =
useContext(VerticalBarContext);

const positionLeft = position === 'left';

const getStartWidth = () => {
return nodeRef?.current?.offsetWidth || 320;
};

const decreasePanelWidth = (delta = 1, startWidth = getStartWidth()) => {
const width = Math.round(startWidth - delta);

if (width > panelWidthMin - 100 && width < panelWidthMin) {
onPanelWidthChange(panelWidthMin);
} else if (width > panelWidthMin) {
onPanelWidthChange(width);
}
};

const increasePanelWidth = (delta = 1, startWidth = getStartWidth()) => {
const width = Math.round(startWidth + delta);

if (width > panelWidthMax && width < panelWidthMax + 100) {
onPanelWidthChange(panelWidthMax);
} else if (width < panelWidthMax) {
onPanelWidthChange(width);
}
};

return (
<div
{...otherProps}
onKeyDown={(event: React.KeyboardEvent<HTMLDivElement>) => {
const delta = keyDownCounter > 7 ? 10 : 1;

keyDownCounter++;

switch (event.key) {
case Keys.Down: {
decreasePanelWidth(delta);

break;
}
case Keys.Left: {
if (positionLeft) {
decreasePanelWidth(delta);
} else {
increasePanelWidth(delta);
}

break;
}
case Keys.Right: {
if (positionLeft) {
increasePanelWidth(delta);
} else {
decreasePanelWidth(delta);
}

break;
}
case Keys.Up: {
increasePanelWidth(delta);

break;
}
default: {
break;
}
}
}}
onKeyUp={() => {
keyDownCounter = 0;
}}
onPointerDown={(event) => {
const startWidth = getStartWidth();
const startXPos = event.pageX;

function onResizerMove(event: any) {
const delta = Math.abs(event.pageX - startXPos);

if (
(event.pageX >= startXPos && positionLeft) ||
(event.pageX < startXPos && !positionLeft)
) {
increasePanelWidth(delta, startWidth);
} else if (
(event.pageX < startXPos && positionLeft) ||
(event.pageX >= startXPos && !positionLeft)
) {
decreasePanelWidth(delta, startWidth);
}
}

function removeResizerEvents() {
document.removeEventListener('pointermove', onResizerMove);

document.removeEventListener(
'pointerup',
removeResizerEvents
);
}

if (event.button === MAIN_MOUSE_BUTTON) {
document.addEventListener('pointermove', onResizerMove);

document.addEventListener('pointerup', removeResizerEvents);
}
}}
role="separator"
tabIndex={0}
/>
);
}
51 changes: 51 additions & 0 deletions packages/clay-core/src/vertical-bar/VerticalBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ type Props = {
*/
className?: string;

/**
* Panel width initial value (uncontrolled).
*/
defaultPanelWidth?: number;

/**
* Sets the position of the vertical bar.
*/
Expand All @@ -58,6 +63,31 @@ type Props = {
* Callback is called when the active state changes (controlled).
*/
onActiveChange?: InternalDispatch<React.Key | null>;

/**
* Callback called when panel width changes (controlled).
*/
onPanelWidthChange?: InternalDispatch<number>;

/**
* Sets a custom width on the sidebar panel (controlled).
*/
panelWidth?: number;

/**
* Sets a maximum width on the sidebar panel.
*/
panelWidthMax?: number;

/**
* Sets a minimum width on the sidebar panel.
*/
panelWidthMin?: number;

/**
* Flag to enable resizing the sidebar panel.
*/
resize?: boolean;
};

export function VerticalBar(props: Props): JSX.Element & {
Expand All @@ -74,8 +104,14 @@ export function VerticalBar({
children,
className,
defaultActive = null,
defaultPanelWidth = 320,
onActiveChange,
onPanelWidthChange,
panelWidth: externalPanelWidth,
panelWidthMax = 500,
panelWidthMin = 280,
position = 'right',
resize = false,
}: Props) {
const [activePanel, setActivePanel] = useInternalState<React.Key | null>({
defaultName: 'defaultItems',
Expand All @@ -88,6 +124,15 @@ export function VerticalBar({

const id = useId();

const [panelWidth, setPanelWidth] = useInternalState({
defaultName: 'defaultPanelWidth',
defaultValue: defaultPanelWidth,
handleName: 'onPanelWidthChange',
name: 'panelWidth',
onChange: onPanelWidthChange,
value: externalPanelWidth,
});

return (
<div
className={classNames('c-slideout c-slideout-shown', className, {
Expand All @@ -103,6 +148,12 @@ export function VerticalBar({
activePanel,
id: `${id}-verticalbar`,
onActivePanel: setActivePanel,
onPanelWidthChange: setPanelWidth,
panelWidth,
panelWidthMax,
panelWidthMin,
position,
resize,
}}
>
{children}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,7 @@ exports[`VerticalBar basic rendering renders the component with the active panel
class="sidebar c-slideout-show sidebar-light"
id="clay-id-6-verticalbar-tabpanel-$.0"
role="tabpanel"
style="width: 320px;"
>
Tag
</div>
Expand Down
6 changes: 6 additions & 0 deletions packages/clay-core/src/vertical-bar/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ type Context = {
activePanel: Key | null;
id: string;
onActivePanel: InternalDispatch<React.Key | null>;
onPanelWidthChange: InternalDispatch<number>;
panelWidth: number;
panelWidthMax: number;
panelWidthMin: number;
position: string;
resize: boolean;
};

export const VerticalBarContext = createContext<Context>({} as Context);
16 changes: 14 additions & 2 deletions packages/clay-core/stories/VerticalBar.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ export default {
control: {type: 'select'},
options: [null, 'light', 'dark'],
},
enableResize: {
control: {type: 'select'},
options: [true, false],
},
},
component: VerticalBar,
title: 'Design System/Components/VerticalBar',
Expand All @@ -31,7 +35,11 @@ export default {
export const Default = (args: any) => {
return (
<>
<VerticalBar activation={args.activation} position="left">
<VerticalBar
activation={args.activation}
position="left"
resize={args.enableResize}
>
<VerticalBar.Bar displayType={args.barDisplayType}>
<VerticalBar.Item>
<Button aria-label="Tag tab" displayType={null}>
Expand Down Expand Up @@ -75,7 +83,11 @@ export const Default = (args: any) => {
</VerticalBar.Content>
</VerticalBar>

<VerticalBar activation={args.activation} position="right">
<VerticalBar
activation={args.activation}
position="right"
resize={args.enableResize}
>
<VerticalBar.Content displayType={args.contentDisplayType}>
<VerticalBar.Panel tabIndex={0}>
<div className="sidebar-header">
Expand Down
1 change: 1 addition & 0 deletions packages/clay-css/src/scss/_components.scss
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

@import 'components/_aspect-ratio';
@import 'components/_buttons';
@import 'components/_resizer';
@import 'components/_transitions';

@import 'components/_grid';
Expand Down
1 change: 1 addition & 0 deletions packages/clay-css/src/scss/_variables.scss
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
@import 'variables/_spinners';

@import 'variables/_buttons';
@import 'variables/_resizer';

@import 'variables/_alerts';
@import 'variables/_badges';
Expand Down
1 change: 1 addition & 0 deletions packages/clay-css/src/scss/cadmin.scss
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ html#{$cadmin-selector} {

@import 'cadmin/components/_aspect-ratio';
@import 'cadmin/components/_buttons';
@import 'cadmin/components/_resizer';
@import 'cadmin/components/_transitions';

@import 'cadmin/components/_grid';
Expand Down
1 change: 1 addition & 0 deletions packages/clay-css/src/scss/cadmin/_variables.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
@import 'variables/_images';

@import 'variables/_buttons';
@import 'variables/_resizer';

@import 'variables/_alerts';
@import 'variables/_badges';
Expand Down
11 changes: 11 additions & 0 deletions packages/clay-css/src/scss/cadmin/components/_resizer.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
.c-horizontal-resizer {
@include clay-css($cadmin-c-horizontal-resizer);

&:hover {
@include clay-css(map-get($cadmin-c-horizontal-resizer, hover));
}

&:focus {
@include clay-css(map-get($cadmin-c-horizontal-resizer, focus));
}
}

0 comments on commit 1044c81

Please sign in to comment.