Skip to content

Commit

Permalink
Support the "as" prop to change the wrapper (#614)
Browse files Browse the repository at this point in the history
* Support the "as" prop to change the wrapper

* Add wrapper story

* Better as prop type

* Add as prop test case

* Replace HTMLDivElement with HTMLElement
  • Loading branch information
youknowriad authored May 13, 2020
1 parent da6284a commit 698aba1
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 8 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,10 @@ Calls when resizable component resize start.

The `scale` property is used in the scenario where the resizable element is a descendent of an element using css scaling (e.g. - `transform: scale(0.5)`).

#### `as?: string | React.ComponentType`;

By default the `Resizable` component will render a `div` as a wrapper. The `as` property is used to change the element used.

### Basic

`ResizeCallback` type is below.
Expand Down
9 changes: 9 additions & 0 deletions src/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,15 @@ test.serial('Should custom class name be applied to box', async t => {
t.is(divs[0].className, 'custom-class-name');
});

test.serial('Should use a custom wrapper element', async t => {
const resizable = TestUtils.renderIntoDocument<Element>(<Resizable as="header" />);
if (!resizable || resizable instanceof Element) {
return t.fail();
}
const headers = TestUtils.scryRenderedDOMComponentsWithTag(resizable, 'header');
t.is(headers.length, 1);
});

test.serial('Should custom class name be applied to resizer', async t => {
const resizable = TestUtils.renderIntoDocument<Element>(
<Resizable handleClasses={{ right: 'right-handle-class' }} />,
Expand Down
21 changes: 13 additions & 8 deletions src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,17 +66,18 @@ export interface HandleComponent {
export type ResizeCallback = (
event: MouseEvent | TouchEvent,
direction: Direction,
elementRef: HTMLDivElement,
elementRef: HTMLElement,
delta: NumberSize,
) => void;

export type ResizeStartCallback = (
e: React.MouseEvent<HTMLDivElement> | React.TouchEvent<HTMLDivElement>,
e: React.MouseEvent<HTMLElement> | React.TouchEvent<HTMLElement>,
dir: Direction,
elementRef: HTMLDivElement,
elementRef: HTMLElement,
) => void | boolean;

export interface ResizableProps {
as: string | React.ComponentType<any>;
style?: React.CSSProperties;
className?: string;
grid?: [number, number];
Expand Down Expand Up @@ -217,6 +218,7 @@ const calculateNewMax = memoize(
);

const definedProps = [
'as',
'style',
'className',
'grid',
Expand Down Expand Up @@ -348,6 +350,7 @@ export class Resizable extends React.PureComponent<ResizableProps, State> {
}

public static defaultProps = {
as: 'div',
onResizeStart: () => {},
onResize: () => {},
onResizeStop: () => {},
Expand All @@ -371,7 +374,7 @@ export class Resizable extends React.PureComponent<ResizableProps, State> {
snapGap: 0,
};
ratio = 1;
resizable: HTMLDivElement | null = null;
resizable: HTMLElement | null = null;
// For parent boundary
parentLeft = 0;
parentTop = 0;
Expand Down Expand Up @@ -645,7 +648,7 @@ export class Resizable extends React.PureComponent<ResizableProps, State> {
}
}

onResizeStart(event: React.MouseEvent<HTMLDivElement> | React.TouchEvent<HTMLDivElement>, direction: Direction) {
onResizeStart(event: React.MouseEvent<HTMLElement> | React.TouchEvent<HTMLElement>, direction: Direction) {
if (!this.resizable || !this.window) {
return;
}
Expand Down Expand Up @@ -879,7 +882,7 @@ export class Resizable extends React.PureComponent<ResizableProps, State> {
);
}

ref = (c: HTMLDivElement | null) => {
ref = (c: HTMLElement | null) => {
if (c) {
this.resizable = c;
}
Expand Down Expand Up @@ -911,12 +914,14 @@ export class Resizable extends React.PureComponent<ResizableProps, State> {
style.flexBasis = this.state.flexBasis;
}

const Wrapper = this.props.as;

return (
<div ref={this.ref} style={style} className={this.props.className} {...extendsProps}>
<Wrapper ref={this.ref} style={style} className={this.props.className} {...extendsProps}>
{this.state.isResizing && <div style={this.state.backgroundStyle} />}
{this.props.children}
{this.renderResizer()}
</div>
</Wrapper>
);
}
}
18 changes: 18 additions & 0 deletions stories/wrapper.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import * as React from 'react';
import { Resizable } from '../src';
import { storiesOf } from '@storybook/react';
import { style } from './style';

storiesOf('wrapper', module).add('default', () => (
<Resizable
as="header"
style={style}
defaultSize={{
width: 200,
height: 300,
}}
lockAspectRatio
>
This is a "header" element
</Resizable>
));

0 comments on commit 698aba1

Please sign in to comment.