Skip to content

Commit

Permalink
feat: update default handle to include central button element
Browse files Browse the repository at this point in the history
  • Loading branch information
nerdyman committed Dec 13, 2020
1 parent 9ea26fd commit a1bfc6f
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 54 deletions.
39 changes: 34 additions & 5 deletions src/ReactCompareSlider.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
import React, { useEffect, useCallback, useRef, useState } from 'react';
import React, { forwardRef, useEffect, useCallback, useRef, useState } from 'react';

import {
ReactCompareSliderHandle,
ReactCompareSliderHandleContainer,
} from './ReactCompareSliderHandle';
import { ReactCompareSliderHandle } from './ReactCompareSliderHandle';
import { ReactCompareSliderClipContainer } from './ReactCompareSliderClipContainer';
import { ReactCompareSliderCommonProps, ReactCompareSliderPropPosition } from './types';

Expand All @@ -14,6 +11,38 @@ import {
useResizeObserver,
} from './utils';

/** Handle container to control position. */
const ReactCompareSliderHandleContainer = forwardRef<
HTMLDivElement,
React.HTMLProps<HTMLDivElement> & Pick<ReactCompareSliderCommonProps, 'portrait'>
>(
({ children, portrait }, ref): React.ReactElement => {
const style: React.CSSProperties = {
position: 'absolute',
top: 0,
width: '100%',
height: '100%',
pointerEvents: 'none',
};

const innerStyle: React.CSSProperties = {
position: 'absolute',
width: portrait ? '100%' : undefined,
height: portrait ? undefined : '100%',
transform: portrait ? 'translateY(-50%)' : 'translateX(-50%)',
pointerEvents: 'all',
};

return (
<div style={style} data-rcs="handle-container" ref={ref}>
<div style={innerStyle}>{children}</div>
</div>
);
}
);

ReactCompareSliderHandleContainer.displayName = 'ReactCompareSliderHandleContainer';

/** Comparison slider properties. */
export interface ReactCompareSliderProps extends Partial<ReactCompareSliderCommonProps> {
/** Padding to limit the slideable bounds in pixels on the X-axis (landscape) or Y-axis (portrait). */
Expand Down
110 changes: 69 additions & 41 deletions src/ReactCompareSliderHandle.tsx
Original file line number Diff line number Diff line change
@@ -1,62 +1,90 @@
import React, { forwardRef } from 'react';
import React from 'react';

import { ReactCompareSliderCommonProps } from './types';

/** Handle container to control position. */
export const ReactCompareSliderHandleContainer = forwardRef<
HTMLDivElement,
React.HTMLProps<HTMLDivElement> & Pick<ReactCompareSliderCommonProps, 'portrait'>
>(
({ children, portrait }, ref): React.ReactElement => {
const style: React.CSSProperties = {
position: 'absolute',
top: 0,
width: '100%',
height: '100%',
pointerEvents: 'none',
};

const innerStyle: React.CSSProperties = {
position: 'absolute',
width: portrait ? '100%' : undefined,
height: portrait ? undefined : '100%',
transform: portrait ? 'translateY(-50%)' : 'translateX(-50%)',
pointerEvents: 'all',
};

return (
<div style={style} data-rcs="handle-container" ref={ref}>
<div style={innerStyle}>{children}</div>
</div>
);
}
);
interface ThisArrowProps {
flip?: boolean;
}

ReactCompareSliderHandleContainer.displayName = 'ReactCompareSliderHandleContainer';
const ThisArrow: React.FC<ThisArrowProps> = ({ flip }) => {
const style: React.CSSProperties = {
width: 0,
height: 0,
borderTop: '8px solid transparent',
borderRight: '10px solid',
borderBottom: '8px solid transparent',
transform: flip ? 'rotate(180deg)' : undefined,
};

return <div style={style} />;
};

/** Props for `ReactCompareSliderHandle`. */
export interface ReactCompareSliderHandleProps
extends Pick<ReactCompareSliderCommonProps, 'portrait'> {
/** Optional styles for handle button. */
innerStyle?: React.CSSProperties;
/** Optional styles for handle root. */
/** Optional styles for handle the button. */
buttonStyle?: React.CSSProperties;
/** Optional styles for lines either side of the handle button. */
lineStyle?: React.CSSProperties;
/** Optional styles for the handle root. */
style?: React.CSSProperties;
}

/** Overridable handle. */
/** Default `handle`. */
export const ReactCompareSliderHandle: React.FC<ReactCompareSliderHandleProps> = ({
portrait,
buttonStyle,
lineStyle,
style,
...props
}): React.ReactElement => {
const rootStyle: React.CSSProperties = {
height: portrait ? 4 : '100%',
width: portrait ? '100%' : 4,
backgroundColor: '#fff',
boxShadow: '0 0 .2rem #000',
const _style: React.CSSProperties = {
display: 'flex',
flexDirection: portrait ? 'row' : 'column',
placeItems: 'center',
height: '100%',
cursor: portrait ? 'ns-resize' : 'ew-resize',
pointerEvents: 'none',
color: '#fff',
...style,
};

return <div {...props} style={rootStyle} data-rcs="handle-inner" />;
const _lineStyle: React.CSSProperties = {
flexGrow: 1,
height: portrait ? 2 : '100%',
width: portrait ? '100%' : 2,
backgroundColor: 'currentColor',
pointerEvents: 'auto',
boxShadow: '0 0 7px rgba(0,0,0,.35)',
...lineStyle,
};

const _buttonStyle: React.CSSProperties = {
display: 'grid',
gridAutoFlow: 'column',
gap: 8,
placeContent: 'center',
flexShrink: 0,
width: 56,
height: 56,
borderRadius: '50%',
borderStyle: 'solid',
borderWidth: 2,
pointerEvents: 'auto',
backdropFilter: 'blur(7px)',
boxShadow: '0 0 7px rgba(0,0,0,.35)',
transform: portrait ? 'rotate(90deg)' : undefined,
...buttonStyle,
};

return (
<div className="__rcs-handle-root" {...props} style={_style}>
<div className="__rcs-handle-line" style={_lineStyle} />
<div className="__rcs-handle-button" style={_buttonStyle}>
<ThisArrow />
<ThisArrow flip />
</div>
<div className="__rcs-handle-line" style={_lineStyle} />
</div>
);
};
12 changes: 4 additions & 8 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,5 @@
import { RefObject, useEffect, useRef, useLayoutEffect, useCallback } from 'react';

/** Whether runtime is client-side. */
const isClient = !!(
typeof window !== 'undefined' &&
window.document &&
window.document.createElement
);

/**
* Stand-alone CSS utility to make replaced elements (`img`, `video`, etc.) fit their
* container.
Expand Down Expand Up @@ -76,7 +69,10 @@ export const useEventListener = (
* Conditionally use `useLayoutEffect` for client *or* `useEffect` for SSR.
* @see https://github.com/reduxjs/react-redux/blob/c581d480dd675f2645851fb006bef91aeb6ac24d/src/utils/useIsomorphicLayoutEffect.js
*/
const useIsomorphicLayoutEffect = isClient ? useLayoutEffect : useEffect;
const useIsomorphicLayoutEffect =
typeof window !== 'undefined' && window.document && window.document.createElement
? useLayoutEffect
: useEffect;

/** Params passed to `useResizeObserver` `handler` function. */
export type UseResizeObserverHandlerParams = DOMRect;
Expand Down

0 comments on commit a1bfc6f

Please sign in to comment.