diff --git a/src/components/Resizer/helpers.tsx b/src/components/Resizer/helpers.tsx new file mode 100644 index 0000000..3b074dd --- /dev/null +++ b/src/components/Resizer/helpers.tsx @@ -0,0 +1,66 @@ +import React from 'react'; +import styled, { css } from 'styled-components'; +import { Fade, Grow, Zoom } from '@material-ui/core'; +import { TransitionType, ResizerCollapseButtonProps } from '.'; + +type OrientationProps = { + isVertical: boolean; +}; +export const topBottomCss = css` + top: 0; + bottom: 0; +`; +const leftRightCss = css` + right: 0; + left: 0; +`; + +export const ButtonWrapper = styled.div` + cursor: pointer; + position: absolute; +`; + +type ButtonContainerProps = OrientationProps & { grabberSize: string }; +export const ButtonContainer = styled.div` + position: absolute; + ${props => (props.isVertical ? topBottomCss : leftRightCss)} + ${props => (props.isVertical ? 'width: 6rem' : 'height: 6rem')}; + transform: ${props => + props.isVertical + ? `translateX(-50%) translateX(calc(${props.grabberSize} / 2))` + : `translateY(-50%) translateY(calc(${props.grabberSize} / 2))`}; + display: flex; + align-items: center; + justify-content: center; +`; + +export const ResizeGrabber = styled.div` + position: absolute; + ${props => (props.isVertical ? topBottomCss : leftRightCss)} + z-index: 3; + transform: ${props => + props.isVertical ? 'translateX(-50%)' : 'translateY(-50%)'}; + cursor: ${props => (props.isVertical ? 'col-resize' : 'row-resize')}; +`; + +export const ResizePresentation = styled.div<{ isVertical: boolean }>` + z-index: 2; + position: absolute; + ${props => (props.isVertical ? topBottomCss : leftRightCss)} +`; + +type TransitionComponent = typeof Fade | typeof Grow | typeof Zoom; +const transitionComponentMap: { + [key in TransitionType]: TransitionComponent; +} = { + fade: Fade, + grow: Grow, + zoom: Zoom, +}; + +export const getTransition = ( + details: ResizerCollapseButtonProps | undefined +): TransitionComponent => transitionComponentMap[details?.transition ?? 'fade']; + +export const getSizeWithUnit = (size: string | number): string => + isNaN(size as number) ? size.toString() : `${size}px`; diff --git a/src/components/Resizer.tsx b/src/components/Resizer/index.tsx similarity index 51% rename from src/components/Resizer.tsx rename to src/components/Resizer/index.tsx index 976d6c5..14f8dd6 100644 --- a/src/components/Resizer.tsx +++ b/src/components/Resizer/index.tsx @@ -1,69 +1,17 @@ -import React, { useState, useCallback } from 'react'; -import styled, { css } from 'styled-components'; -import { Fade, Grow, Zoom } from '@material-ui/core'; -import { ClientPosition } from 'components/hooks/useDragStateHandlers'; +import React, { useState, useCallback, useMemo } from 'react'; +import { Fade } from '@material-ui/core'; +import { ClientPosition } from '../hooks/useDragStateHandlers'; +import { getTransition, getSizeWithUnit } from '../Resizer/helpers'; +import { mergeClasses } from '../SplitPane/helpers'; +import { + ButtonContainer, + ButtonWrapper, + ResizeGrabber, + ResizePresentation, +} from './helpers'; + +export type TransitionType = 'fade' | 'grow' | 'zoom'; -type OrientationProps = { - isVertical: boolean; -}; - -const ButtonWrapper = styled.div` - cursor: pointer; - z-index: 3; -`; - -const ButtonContainer = styled.div` - ${props => - props.isVertical - ? css` - width: 6rem; - height: 100%; - ` - : css` - height: 6rem; - width: 100%; - `} - transform: ${props => - props.isVertical - ? `translateX(-50%) translateX(calc(${props.grabberSize} / 2))` - : `translateY(-50%) translateY(calc(${props.grabberSize} / 2))`}; - display: flex; - align-items: center; - justify-content: center; -`; - -const topBottomCss = css` - top: 0; - bottom: 0; -`; -const leftRightCss = css` - right: 0; - left: 0; -`; - -const ResizeGrabber = styled.div` - position: absolute; - ${props => (props.isVertical ? topBottomCss : leftRightCss)} - z-index: 3; - transform: ${props => - props.isVertical ? 'translateX(-50%)' : 'translateY(-50%)'}; - cursor: ${props => (props.isVertical ? 'col-resize' : 'row-resize')}; -`; - -const ResizePresentation = styled.div<{ isVertical: boolean }>` - z-index: 2; - position: absolute; - ${props => (props.isVertical ? topBottomCss : leftRightCss)} -`; - -type TransitionType = 'fade' | 'grow' | 'zoom'; -const transitionComponentMap: { - [key in TransitionType]: typeof Fade | typeof Grow | typeof Zoom; -} = { - fade: Fade, - grow: Grow, - zoom: Zoom, -}; export interface ResizerCollapseButtonProps { button?: React.ReactElement; transition?: TransitionType; @@ -79,6 +27,7 @@ export interface ResizerProps { resizerHoverCss?: React.CSSProperties; grabberSize?: string | number; onDragStarted: (index: number, pos: ClientPosition) => void; + onCollapseToggle: () => void; } export const Resizer = React.memo( @@ -91,11 +40,13 @@ export const Resizer = React.memo( resizerCss = { backgroundColor: 'silver' }, resizerHoverCss = { backgroundColor: 'grey' }, collapseButtonDetails, + onCollapseToggle, }: ResizerProps) => { + const [isHovered, setIsHovered] = useState(false); + const handleMouseDown = useCallback( (event: React.MouseEvent) => { event.preventDefault(); - onDragStarted(index, event); }, [index, onDragStarted] @@ -104,7 +55,6 @@ export const Resizer = React.memo( const handleTouchStart = useCallback( (event: React.TouchEvent) => { event.preventDefault(); - onDragStarted(index, event.touches[0]); }, [index, onDragStarted] @@ -112,30 +62,33 @@ export const Resizer = React.memo( const handleButtonClick = useCallback((event: React.MouseEvent) => { event.stopPropagation(); - console.log('button clicked'); + onCollapseToggle(); }, []); const handleButtonMousedown = useCallback((event: React.MouseEvent) => { event.stopPropagation(); }, []); - const classes = ['Resizer', split, className].join(' '); - const [isHovered, setIsHovered] = useState(false); + const classes = useMemo(() => mergeClasses(['Resizer', split, className]), [ + split, + className, + ]); const isVertical = split === 'vertical'; - const widthOrHeightSize = (size: string | number) => + const getWidthOrHeight = (size: string | number) => isVertical ? { width: size } : { height: size }; + const grabberSizeWithUnit = useMemo(() => getSizeWithUnit(grabberSize), [ + grabberSize, + ]); + + const Transition = useMemo(() => getTransition(collapseButtonDetails), [ + collapseButtonDetails, + ]); - const Transition = - transitionComponentMap[collapseButtonDetails?.transition ?? 'fade']; - const button = collapseButtonDetails ? ( + const collapseButton = collapseButtonDetails ? ( ) : null; - const handleMouseEnter = () => { + const handleMouseEnterGrabber = () => { setIsHovered(true); }; - const handleMouseLeave = () => { + const handleMouseLeaveGrabber = () => { setIsHovered(false); }; @@ -160,26 +113,26 @@ export const Resizer = React.memo(
- {button} + {collapseButton}
diff --git a/src/components/SplitPane/index.tsx b/src/components/SplitPane/index.tsx index 98cd62a..6020b28 100644 --- a/src/components/SplitPane/index.tsx +++ b/src/components/SplitPane/index.tsx @@ -1,4 +1,4 @@ -import * as React from 'react'; +import React, { useMemo, useState } from 'react'; import { Pane } from '../Pane'; import { Resizer, ResizerCollapseButtonProps } from '../Resizer'; @@ -70,13 +70,24 @@ export const SplitPane = React.memo((props: SplitPaneProps) => { options ); - const classes = mergeClasses(['SplitPane', split, className]); - const dragLayerClasses = mergeClasses([ - 'DragLayer', + const classes = useMemo(() => mergeClasses(['SplitPane', split, className]), [ split, - resizeState ? 'resizing' : '', className, ]); + const dragLayerClasses = useMemo( + () => + mergeClasses([ + 'DragLayer', + split, + resizeState ? 'resizing' : '', + className, + ]), + [split, resizeState, className] + ); + + const onCollapse = () => { + console.log('clicked collapse!'); + }; const entries: React.ReactNode[] = []; @@ -94,6 +105,7 @@ export const SplitPane = React.memo((props: SplitPaneProps) => { resizerHoverCss={props.resizerHoverCss} collapseButtonDetails={props.collapseButtonDetails} onDragStarted={handleDragStart} + onCollapseToggle={onCollapse} /> ); } diff --git a/stories/Thing.stories.tsx b/stories/Thing.stories.tsx index ed6614a..b7ac57d 100644 --- a/stories/Thing.stories.tsx +++ b/stories/Thing.stories.tsx @@ -44,7 +44,8 @@ export const VerticalSplitWithButton = () => ( grabberSize="1rem" >
This is a div
-
This is a div
+
This is a second div
+
This is a third div
); diff --git a/tsconfig.json b/tsconfig.json index 71606db..dabcf87 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -14,10 +14,10 @@ "noFallthroughCasesInSwitch": true, "moduleResolution": "node", "baseUrl": "./", - "paths": { - "@": ["./"], - "*": ["src/*", "node_modules/*"] - }, + // "paths": { + // "@": ["./"], + // "*": ["src/*", "node_modules/*"] + // }, "jsx": "react", "esModuleInterop": true }