From f93ac26ecefc12370475b5a6b80985cac89dbc77 Mon Sep 17 00:00:00 2001 From: Acko Date: Thu, 28 Feb 2019 17:57:01 +0100 Subject: [PATCH 1/5] Added `reverse` prop to Drawer component to enable rendering on reverse side (if vertical then on the top instead of the bottom, otherwise on the left instead of the right side). Fixes #3360 --- packages/core/src/common/classes.ts | 1 + .../core/src/components/drawer/_drawer.scss | 114 ++++++++++++------ .../core/src/components/drawer/drawer.tsx | 14 ++- packages/core/test/drawer/drawerTests.tsx | 9 ++ .../examples/core-examples/drawerExample.tsx | 4 + 5 files changed, 106 insertions(+), 36 deletions(-) diff --git a/packages/core/src/common/classes.ts b/packages/core/src/common/classes.ts index a81a4de246..eb9f91e477 100644 --- a/packages/core/src/common/classes.ts +++ b/packages/core/src/common/classes.ts @@ -28,6 +28,7 @@ export const MULTILINE = `${NS}-multiline`; export const ROUND = `${NS}-round`; export const SMALL = `${NS}-small`; export const VERTICAL = `${NS}-vertical`; +export const REVERSED = `${NS}-reversed`; export const ELEVATION_0 = elevationClass(Elevation.ZERO); export const ELEVATION_1 = elevationClass(Elevation.ONE); diff --git a/packages/core/src/components/drawer/_drawer.scss b/packages/core/src/components/drawer/_drawer.scss index 627535e006..7416f3b573 100644 --- a/packages/core/src/components/drawer/_drawer.scss +++ b/packages/core/src/components/drawer/_drawer.scss @@ -24,49 +24,95 @@ $drawer-default-size: 50%; } &:not(.#{$ns}-vertical) { - @include react-transition-phase( - "#{$ns}-overlay", - "enter", - (transform: (translateX(100%), translateX(0))), - $pt-transition-duration * 2, - $pt-transition-ease, - $before: "&" - ); - @include react-transition-phase( - "#{$ns}-overlay", - "exit", - (transform: (translateX(100%), translateX(0))), - $pt-transition-duration, - $before: "&" - ); - top: 0; - right: 0; bottom: 0; width: $drawer-default-size; + + &:not(.#{$ns}-reversed) { + @include react-transition-phase( + "#{$ns}-overlay", + "enter", + (transform: (translateX(100%), translateX(0))), + $pt-transition-duration * 2, + $pt-transition-ease, + $before: "&" + ); + @include react-transition-phase( + "#{$ns}-overlay", + "exit", + (transform: (translateX(100%), translateX(0))), + $pt-transition-duration, + $before: "&" + ); + + right: 0; + } + + &.#{$ns}-reversed { + @include react-transition-phase( + "#{$ns}-overlay", + "enter", + (transform: (translateX(-100%), translateX(0))), + $pt-transition-duration * 2, + $pt-transition-ease, + $before: "&" + ); + @include react-transition-phase( + "#{$ns}-overlay", + "exit", + (transform: (translateX(-100%), translateX(0))), + $pt-transition-duration, + $before: "&" + ); + + left: 0; + } } &.#{$ns}-vertical { - @include react-transition-phase( - "#{$ns}-overlay", - "enter", - (transform: (translateY(100%), translateY(0))), - $pt-transition-duration * 2, - $pt-transition-ease, - $before: "&" - ); - @include react-transition-phase( - "#{$ns}-overlay", - "exit", - (transform: (translateY(100%), translateY(0))), - $pt-transition-duration, - $before: "&" - ); - right: 0; - bottom: 0; left: 0; height: $drawer-default-size; + + &:not(.#{$ns}-reversed) { + @include react-transition-phase( + "#{$ns}-overlay", + "enter", + (transform: (translateY(100%), translateY(0))), + $pt-transition-duration * 2, + $pt-transition-ease, + $before: "&" + ); + @include react-transition-phase( + "#{$ns}-overlay", + "exit", + (transform: (translateY(100%), translateY(0))), + $pt-transition-duration, + $before: "&" + ); + + bottom: 0; + } + + &.#{$ns}-reversed { + @include react-transition-phase( + "#{$ns}-overlay", + "enter", + (transform: (translateY(-100%), translateY(0))), + $pt-transition-duration * 2, + $pt-transition-ease, + $before: "&" + ); + @include react-transition-phase( + "#{$ns}-overlay", + "exit", + (transform: (translateY(-100%), translateY(0))), + $pt-transition-duration, + $before: "&" + ); + + top: 0; + } } &.#{$ns}-dark, diff --git a/packages/core/src/components/drawer/drawer.tsx b/packages/core/src/components/drawer/drawer.tsx index 0593be97b3..7bd0a7344a 100644 --- a/packages/core/src/components/drawer/drawer.tsx +++ b/packages/core/src/components/drawer/drawer.tsx @@ -37,6 +37,14 @@ export interface IDrawerProps extends IOverlayableProps, IBackdropProps, IProps */ isOpen: boolean; + /** + * Whether the drawer should appear on the reversed side. + * Depending on the `vertical` prop, it will show on the left side (instead of the left), + * or on the top (instead of the bottom) + * @default false + */ + reversed?: boolean; + /** * CSS size of the drawer. This sets `width` if `vertical={false}` (default) * and `height` otherwise. @@ -80,6 +88,7 @@ export class Drawer extends AbstractPureComponent { public static defaultProps: IDrawerProps = { canOutsideClickClose: true, isOpen: false, + reversed: false, style: {}, vertical: false, }; @@ -89,8 +98,9 @@ export class Drawer extends AbstractPureComponent { public static readonly SIZE_LARGE = "90%"; public render() { - const { size, style, vertical } = this.props; - const classes = classNames(Classes.DRAWER, { [Classes.VERTICAL]: vertical }, this.props.className); + const { size, style, vertical, reversed } = this.props; + const additionalClasses = { [Classes.VERTICAL]: vertical, [Classes.REVERSED]: reversed }; + const classes = classNames(Classes.DRAWER, additionalClasses, this.props.className); const styleProp = size == null ? style : { ...style, [vertical ? "height" : "width"]: size }; return ( diff --git a/packages/core/test/drawer/drawerTests.tsx b/packages/core/test/drawer/drawerTests.tsx index 86f64836f7..451c25b405 100644 --- a/packages/core/test/drawer/drawerTests.tsx +++ b/packages/core/test/drawer/drawerTests.tsx @@ -51,6 +51,15 @@ describe("", () => { assert.isTrue(drawer.find(`.${Classes.VERTICAL}`).exists()); }); + it("reversed adds class", () => { + const drawer = mount( + + {createDrawerContents()} + , + ); + assert.isTrue(drawer.find(`.${Classes.REVERSED}`).exists()); + }); + it("portalClassName appears on Portal", () => { const TEST_CLASS = "test-class"; const drawer = mount( diff --git a/packages/docs-app/src/examples/core-examples/drawerExample.tsx b/packages/docs-app/src/examples/core-examples/drawerExample.tsx index 5ce0f56e07..b727dc82f6 100644 --- a/packages/docs-app/src/examples/core-examples/drawerExample.tsx +++ b/packages/docs-app/src/examples/core-examples/drawerExample.tsx @@ -17,6 +17,7 @@ export interface IDrawerExampleState { enforceFocus: boolean; hasBackdrop: boolean; isOpen: boolean; + reversed: boolean; size: string; usePortal: boolean; vertical: boolean; @@ -29,6 +30,7 @@ export class DrawerExample extends React.PureComponent this.setState({ canEscapeKeyClose })); private handleUsePortalChange = handleBooleanChange(usePortal => this.setState({ usePortal })); private handleOutsideClickChange = handleBooleanChange(val => this.setState({ canOutsideClickClose: val })); + private handleReversedChange = handleBooleanChange(reversed => this.setState({ reversed })); private handleVerticalChange = handleBooleanChange(vertical => this.setState({ vertical })); private handleSizeChange = handleStringChange(size => this.setState({ size })); @@ -100,6 +103,7 @@ export class DrawerExample extends React.PureComponent + From b7c238f10a1c28d1da8969f67e43feddff931baa Mon Sep 17 00:00:00 2001 From: Acko Date: Thu, 28 Feb 2019 18:53:40 +0100 Subject: [PATCH 2/5] Updated comment on `reverse` prop (`Drawer` component) --- packages/core/src/components/drawer/drawer.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/src/components/drawer/drawer.tsx b/packages/core/src/components/drawer/drawer.tsx index 7bd0a7344a..2753cf4f50 100644 --- a/packages/core/src/components/drawer/drawer.tsx +++ b/packages/core/src/components/drawer/drawer.tsx @@ -39,7 +39,7 @@ export interface IDrawerProps extends IOverlayableProps, IBackdropProps, IProps /** * Whether the drawer should appear on the reversed side. - * Depending on the `vertical` prop, it will show on the left side (instead of the left), + * Depending on the `vertical` prop, it will show on the left side (instead of the right), * or on the top (instead of the bottom) * @default false */ From f001a381f68b336710ddf84f4308ae03b714472c Mon Sep 17 00:00:00 2001 From: Acko Date: Wed, 20 Mar 2019 15:07:54 +0100 Subject: [PATCH 3/5] Changed `reversed` into `reverse` prop on `Drawer`, and small code style fixes --- packages/core/src/common/classes.ts | 2 +- .../core/src/components/drawer/_drawer.scss | 8 ++++---- packages/core/src/components/drawer/drawer.tsx | 18 ++++++++++++------ packages/core/test/drawer/drawerTests.tsx | 6 +++--- .../examples/core-examples/drawerExample.tsx | 8 ++++---- 5 files changed, 24 insertions(+), 18 deletions(-) diff --git a/packages/core/src/common/classes.ts b/packages/core/src/common/classes.ts index eb9f91e477..33162cbf46 100644 --- a/packages/core/src/common/classes.ts +++ b/packages/core/src/common/classes.ts @@ -28,7 +28,7 @@ export const MULTILINE = `${NS}-multiline`; export const ROUND = `${NS}-round`; export const SMALL = `${NS}-small`; export const VERTICAL = `${NS}-vertical`; -export const REVERSED = `${NS}-reversed`; +export const REVERSE = `${NS}-reverse`; export const ELEVATION_0 = elevationClass(Elevation.ZERO); export const ELEVATION_1 = elevationClass(Elevation.ONE); diff --git a/packages/core/src/components/drawer/_drawer.scss b/packages/core/src/components/drawer/_drawer.scss index 7416f3b573..af1640db23 100644 --- a/packages/core/src/components/drawer/_drawer.scss +++ b/packages/core/src/components/drawer/_drawer.scss @@ -28,7 +28,7 @@ $drawer-default-size: 50%; bottom: 0; width: $drawer-default-size; - &:not(.#{$ns}-reversed) { + &:not(.#{$ns}-reverse) { @include react-transition-phase( "#{$ns}-overlay", "enter", @@ -48,7 +48,7 @@ $drawer-default-size: 50%; right: 0; } - &.#{$ns}-reversed { + &.#{$ns}-reverse { @include react-transition-phase( "#{$ns}-overlay", "enter", @@ -74,7 +74,7 @@ $drawer-default-size: 50%; left: 0; height: $drawer-default-size; - &:not(.#{$ns}-reversed) { + &:not(.#{$ns}-reverse) { @include react-transition-phase( "#{$ns}-overlay", "enter", @@ -94,7 +94,7 @@ $drawer-default-size: 50%; bottom: 0; } - &.#{$ns}-reversed { + &.#{$ns}-reverse { @include react-transition-phase( "#{$ns}-overlay", "enter", diff --git a/packages/core/src/components/drawer/drawer.tsx b/packages/core/src/components/drawer/drawer.tsx index 2753cf4f50..73ff6850a7 100644 --- a/packages/core/src/components/drawer/drawer.tsx +++ b/packages/core/src/components/drawer/drawer.tsx @@ -40,10 +40,10 @@ export interface IDrawerProps extends IOverlayableProps, IBackdropProps, IProps /** * Whether the drawer should appear on the reversed side. * Depending on the `vertical` prop, it will show on the left side (instead of the right), - * or on the top (instead of the bottom) + * or on the top (instead of the bottom). * @default false */ - reversed?: boolean; + reverse?: boolean; /** * CSS size of the drawer. This sets `width` if `vertical={false}` (default) @@ -88,7 +88,7 @@ export class Drawer extends AbstractPureComponent { public static defaultProps: IDrawerProps = { canOutsideClickClose: true, isOpen: false, - reversed: false, + reverse: false, style: {}, vertical: false, }; @@ -98,9 +98,15 @@ export class Drawer extends AbstractPureComponent { public static readonly SIZE_LARGE = "90%"; public render() { - const { size, style, vertical, reversed } = this.props; - const additionalClasses = { [Classes.VERTICAL]: vertical, [Classes.REVERSED]: reversed }; - const classes = classNames(Classes.DRAWER, additionalClasses, this.props.className); + const { size, style, vertical, reverse } = this.props; + const classes = classNames( + Classes.DRAWER, + { + [Classes.VERTICAL]: vertical, + [Classes.REVERSE]: reverse, + }, + this.props.className, + ); const styleProp = size == null ? style : { ...style, [vertical ? "height" : "width"]: size }; return ( diff --git a/packages/core/test/drawer/drawerTests.tsx b/packages/core/test/drawer/drawerTests.tsx index 451c25b405..2c949caeb3 100644 --- a/packages/core/test/drawer/drawerTests.tsx +++ b/packages/core/test/drawer/drawerTests.tsx @@ -51,13 +51,13 @@ describe("", () => { assert.isTrue(drawer.find(`.${Classes.VERTICAL}`).exists()); }); - it("reversed adds class", () => { + it("reverse adds class", () => { const drawer = mount( - + {createDrawerContents()} , ); - assert.isTrue(drawer.find(`.${Classes.REVERSED}`).exists()); + assert.isTrue(drawer.find(`.${Classes.REVERSE}`).exists()); }); it("portalClassName appears on Portal", () => { diff --git a/packages/docs-app/src/examples/core-examples/drawerExample.tsx b/packages/docs-app/src/examples/core-examples/drawerExample.tsx index b727dc82f6..ba20eed315 100644 --- a/packages/docs-app/src/examples/core-examples/drawerExample.tsx +++ b/packages/docs-app/src/examples/core-examples/drawerExample.tsx @@ -17,7 +17,7 @@ export interface IDrawerExampleState { enforceFocus: boolean; hasBackdrop: boolean; isOpen: boolean; - reversed: boolean; + reverse: boolean; size: string; usePortal: boolean; vertical: boolean; @@ -30,7 +30,7 @@ export class DrawerExample extends React.PureComponent this.setState({ canEscapeKeyClose })); private handleUsePortalChange = handleBooleanChange(usePortal => this.setState({ usePortal })); private handleOutsideClickChange = handleBooleanChange(val => this.setState({ canOutsideClickClose: val })); - private handleReversedChange = handleBooleanChange(reversed => this.setState({ reversed })); + private handleReverseChange = handleBooleanChange(reverse => this.setState({ reverse })); private handleVerticalChange = handleBooleanChange(vertical => this.setState({ vertical })); private handleSizeChange = handleStringChange(size => this.setState({ size })); @@ -103,7 +103,7 @@ export class DrawerExample extends React.PureComponent - + From 496a3a90975f92cd0812b19869940d1f329f8fe6 Mon Sep 17 00:00:00 2001 From: Acko Date: Fri, 22 Mar 2019 00:02:07 +0100 Subject: [PATCH 4/5] Updated `Drawer` reverse logic to use `Position`, and `vertical` deprecated --- packages/core/src/common/errors.ts | 4 + packages/core/src/common/position.ts | 24 +++ .../core/src/components/drawer/drawer.tsx | 33 +++- packages/core/test/drawer/drawerTests.tsx | 183 ++++++++++++++++-- .../examples/core-examples/drawerExample.tsx | 33 +++- 5 files changed, 250 insertions(+), 27 deletions(-) diff --git a/packages/core/src/common/errors.ts b/packages/core/src/common/errors.ts index 0f59460be6..047df85e78 100644 --- a/packages/core/src/common/errors.ts +++ b/packages/core/src/common/errors.ts @@ -80,3 +80,7 @@ export const TOASTER_WARN_INLINE = ns + ` Toaster.create() ignores inline prop a export const DIALOG_WARN_NO_HEADER_ICON = ns + ` iconName is ignored if title is omitted.`; export const DIALOG_WARN_NO_HEADER_CLOSE_BUTTON = ns + ` isCloseButtonShown prop is ignored if title is omitted.`; + +export const DRAWER_VERTICAL_IS_IGNORED = ns + ` vertical is ignored if position is defined`; +export const DRAWER_ANGLE_POSITIONS_ARE_CASTED = + ns + ` all angle positions are casted into pure position (TOP, BOTTOM, LEFT or RIGHT)`; diff --git a/packages/core/src/common/position.ts b/packages/core/src/common/position.ts index 2178efa96c..8070c11bc5 100644 --- a/packages/core/src/common/position.ts +++ b/packages/core/src/common/position.ts @@ -43,3 +43,27 @@ export function isPositionVertical(position: Position) { position === Position.RIGHT_BOTTOM ); } + +export function getPositionIgnoreAngles(position: Position) { + if ( + position === Position.TOP || + position === Position.TOP_LEFT || + position === Position.TOP_RIGHT + ) { + return Position.TOP; + } else if ( + position === Position.BOTTOM || + position === Position.BOTTOM_LEFT || + position === Position.BOTTOM_RIGHT + ) { + return Position.BOTTOM; + } else if ( + position === Position.LEFT || + position === Position.LEFT_TOP || + position === Position.LEFT_BOTTOM + ) { + return Position.LEFT; + } else { + return Position.RIGHT; + } +} diff --git a/packages/core/src/components/drawer/drawer.tsx b/packages/core/src/components/drawer/drawer.tsx index 73ff6850a7..3a7f20b0c5 100644 --- a/packages/core/src/components/drawer/drawer.tsx +++ b/packages/core/src/components/drawer/drawer.tsx @@ -10,6 +10,7 @@ import * as React from "react"; import { AbstractPureComponent } from "../../common/abstractPureComponent"; import * as Classes from "../../common/classes"; import * as Errors from "../../common/errors"; +import { getPositionIgnoreAngles, isPositionHorizontal, Position } from "../../common/position"; import { DISPLAYNAME_PREFIX, IProps, MaybeElement } from "../../common/props"; import { Button } from "../button/buttons"; import { H4 } from "../html/html"; @@ -38,12 +39,11 @@ export interface IDrawerProps extends IOverlayableProps, IBackdropProps, IProps isOpen: boolean; /** - * Whether the drawer should appear on the reversed side. - * Depending on the `vertical` prop, it will show on the left side (instead of the right), - * or on the top (instead of the bottom). - * @default false + * Position of a drawer. All angled positions will be casted into pure positions + * (TOP, BOTTOM, LEFT or RIGHT). + * @default Position.RIGHT */ - reverse?: boolean; + position?: Position; /** * CSS size of the drawer. This sets `width` if `vertical={false}` (default) @@ -78,7 +78,9 @@ export interface IDrawerProps extends IOverlayableProps, IBackdropProps, IProps /** * Whether the drawer should appear with vertical styling. + * It will be ignored if `position` prop is set * @default false + * @deprecated */ vertical?: boolean; } @@ -88,7 +90,7 @@ export class Drawer extends AbstractPureComponent { public static defaultProps: IDrawerProps = { canOutsideClickClose: true, isOpen: false, - reverse: false, + position: null, style: {}, vertical: false, }; @@ -98,16 +100,19 @@ export class Drawer extends AbstractPureComponent { public static readonly SIZE_LARGE = "90%"; public render() { - const { size, style, vertical, reverse } = this.props; + const { size, style, position, vertical } = this.props; + const realPosition = getPositionIgnoreAngles(position || (vertical ? Position.BOTTOM : Position.RIGHT)); + const classes = classNames( Classes.DRAWER, { - [Classes.VERTICAL]: vertical, - [Classes.REVERSE]: reverse, + [Classes.VERTICAL]: isPositionHorizontal(realPosition), + [Classes.REVERSE]: realPosition === Position.TOP || realPosition === Position.LEFT, }, this.props.className, ); - const styleProp = size == null ? style : { ...style, [vertical ? "height" : "width"]: size }; + const styleProp = + size == null ? style : { ...style, [isPositionHorizontal(realPosition) ? "height" : "width"]: size }; return (
@@ -127,6 +132,14 @@ export class Drawer extends AbstractPureComponent { console.warn(Errors.DIALOG_WARN_NO_HEADER_CLOSE_BUTTON); } } + if (props.position != null) { + if (props.vertical) { + console.warn(Errors.DRAWER_VERTICAL_IS_IGNORED); + } + if (props.position !== getPositionIgnoreAngles(props.position)) { + console.warn(Errors.DRAWER_ANGLE_POSITIONS_ARE_CASTED); + } + } } private maybeRenderCloseButton() { diff --git a/packages/core/test/drawer/drawerTests.tsx b/packages/core/test/drawer/drawerTests.tsx index 2c949caeb3..b806f1d979 100644 --- a/packages/core/test/drawer/drawerTests.tsx +++ b/packages/core/test/drawer/drawerTests.tsx @@ -7,10 +7,11 @@ import { assert } from "chai"; import { mount } from "enzyme"; import * as React from "react"; -import { spy } from "sinon"; +import { spy, stub } from "sinon"; +import { DRAWER_ANGLE_POSITIONS_ARE_CASTED, DRAWER_VERTICAL_IS_IGNORED } from "../../src/common/errors"; import * as Keys from "../../src/common/keys"; -import { Button, Classes, Drawer } from "../../src/index"; +import { Button, Classes, Drawer, Position } from "../../src/index"; describe("", () => { it("renders its content correctly", () => { @@ -24,6 +25,175 @@ describe("", () => { }); }); + describe("position", () => { + it("casts angle positions into pure positions (with console warning)", () => { + const warnSpy = stub(console, "warn"); + + const drawerTop = mount( + + {createDrawerContents()} + , + ); + const drawerLeft = mount( + + {createDrawerContents()} + , + ); + const drawerTopRight = mount( + + {createDrawerContents()} + , + ); + const drawerTopLeft = mount( + + {createDrawerContents()} + , + ); + const drawerLeftTop = mount( + + {createDrawerContents()} + , + ); + + assert.isTrue( + drawerTop.find(`.${Classes.DRAWER}`).equals(drawerTopRight.find(`.${Classes.DRAWER}`).getElement()), + ); + assert.isTrue( + drawerTop.find(`.${Classes.DRAWER}`).equals(drawerTopLeft.find(`.${Classes.DRAWER}`).getElement()), + ); + assert.isFalse( + drawerTop.find(`.${Classes.DRAWER}`).equals(drawerLeftTop.find(`.${Classes.DRAWER}`).getElement()), + ); + assert.isTrue( + drawerLeft.find(`.${Classes.DRAWER}`).equals(drawerLeftTop.find(`.${Classes.DRAWER}`).getElement()), + ); + + assert.isTrue(warnSpy.alwaysCalledWith(DRAWER_ANGLE_POSITIONS_ARE_CASTED)); + warnSpy.restore(); + }); + + it("overrides vertical (with console warning)", () => { + const warnSpy = stub(console, "warn"); + + const drawerLeft = mount( + + {createDrawerContents()} + , + ); + + // vertical size becomes height (opposite test) + assert.equal(drawerLeft.find(`.${Classes.DRAWER}`).prop("style").width, 100); + // vertical adds class (opposite test) + assert.isFalse(drawerLeft.find(`.${Classes.VERTICAL}`).exists()); + + assert.isTrue(warnSpy.alwaysCalledWith(DRAWER_VERTICAL_IS_IGNORED)); + warnSpy.restore(); + }); + + describe("RIGHT", () => { + it("position right is default", () => { + const drawerDefault = mount( + + {createDrawerContents()} + , + ); + const drawerRight = mount( + + {createDrawerContents()} + , + ); + + assert.isTrue( + drawerDefault + .find(`.${Classes.DRAWER}`) + .equals(drawerRight.find(`.${Classes.DRAWER}`).getElement()), + ); + }); + + it("position right, size becomes width", () => { + const drawer = mount( + + {createDrawerContents()} + , + ); + assert.equal(drawer.find(`.${Classes.DRAWER}`).prop("style").width, 100); + }); + + it("position right, adds appropriate classes (default behavior)", () => { + const drawer = mount( + + {createDrawerContents()} + , + ); + assert.isFalse(drawer.find(`.${Classes.VERTICAL}`).exists()); + assert.isFalse(drawer.find(`.${Classes.REVERSE}`).exists()); + }); + }); + + describe("TOP", () => { + it("position top, size becomes height", () => { + const drawer = mount( + + {createDrawerContents()} + , + ); + assert.equal(drawer.find(`.${Classes.DRAWER}`).prop("style").height, 100); + }); + + it("position top, adds appropriate classes (vertical, reverse)", () => { + const drawer = mount( + + {createDrawerContents()} + , + ); + assert.isTrue(drawer.find(`.${Classes.VERTICAL}`).exists()); + assert.isTrue(drawer.find(`.${Classes.REVERSE}`).exists()); + }); + }); + + describe("BOTTOM", () => { + it("position bottom, size becomes height", () => { + const drawer = mount( + + {createDrawerContents()} + , + ); + assert.equal(drawer.find(`.${Classes.DRAWER}`).prop("style").height, 100); + }); + + it("position bottom, adds appropriate classes (vertical)", () => { + const drawer = mount( + + {createDrawerContents()} + , + ); + assert.isTrue(drawer.find(`.${Classes.VERTICAL}`).exists()); + assert.isFalse(drawer.find(`.${Classes.REVERSE}`).exists()); + }); + }); + + describe("LEFT", () => { + it("position left, size becomes width", () => { + const drawer = mount( + + {createDrawerContents()} + , + ); + assert.equal(drawer.find(`.${Classes.DRAWER}`).prop("style").width, 100); + }); + + it("position left, adds appropriate classes (reverse)", () => { + const drawer = mount( + + {createDrawerContents()} + , + ); + assert.isFalse(drawer.find(`.${Classes.VERTICAL}`).exists()); + assert.isTrue(drawer.find(`.${Classes.REVERSE}`).exists()); + }); + }); + }); + it("size becomes width", () => { const drawer = mount( @@ -51,15 +221,6 @@ describe("", () => { assert.isTrue(drawer.find(`.${Classes.VERTICAL}`).exists()); }); - it("reverse adds class", () => { - const drawer = mount( - - {createDrawerContents()} - , - ); - assert.isTrue(drawer.find(`.${Classes.REVERSE}`).exists()); - }); - it("portalClassName appears on Portal", () => { const TEST_CLASS = "test-class"; const drawer = mount( diff --git a/packages/docs-app/src/examples/core-examples/drawerExample.tsx b/packages/docs-app/src/examples/core-examples/drawerExample.tsx index ba20eed315..9775bba5f3 100644 --- a/packages/docs-app/src/examples/core-examples/drawerExample.tsx +++ b/packages/docs-app/src/examples/core-examples/drawerExample.tsx @@ -6,7 +6,19 @@ import * as React from "react"; -import { Button, Classes, Code, Divider, Drawer, H5, HTMLSelect, IOptionProps, Label, Switch } from "@blueprintjs/core"; +import { + Button, + Classes, + Code, + Divider, + Drawer, + H5, + HTMLSelect, + IOptionProps, + Label, + Position, + Switch, +} from "@blueprintjs/core"; import { Example, handleBooleanChange, handleStringChange, IExampleProps } from "@blueprintjs/docs-theme"; import { IBlueprintExampleData } from "../../tags/reactExamples"; @@ -17,7 +29,7 @@ export interface IDrawerExampleState { enforceFocus: boolean; hasBackdrop: boolean; isOpen: boolean; - reverse: boolean; + position?: Position; size: string; usePortal: boolean; vertical: boolean; @@ -30,7 +42,7 @@ export class DrawerExample extends React.PureComponent this.setState({ enforceFocus })); private handleEscapeKeyChange = handleBooleanChange(canEscapeKeyClose => this.setState({ canEscapeKeyClose })); private handleUsePortalChange = handleBooleanChange(usePortal => this.setState({ usePortal })); + private handlePositionChange = handleStringChange((position: Position) => this.setState({ position })); private handleOutsideClickChange = handleBooleanChange(val => this.setState({ canOutsideClickClose: val })); - private handleReverseChange = handleBooleanChange(reverse => this.setState({ reverse })); private handleVerticalChange = handleBooleanChange(vertical => this.setState({ vertical })); private handleSizeChange = handleStringChange(size => this.setState({ size })); @@ -98,12 +110,19 @@ export class DrawerExample extends React.PureComponent
Props
+ - - + @@ -133,3 +152,5 @@ const SIZES: Array = [ "72%", "560px", ]; + +const VALID_POSITIONS: Position[] = [Position.TOP, Position.RIGHT, Position.BOTTOM, Position.LEFT]; From 54b55129ff9243d20443884f1c19be87e40a7ba0 Mon Sep 17 00:00:00 2001 From: Acko Date: Fri, 22 Mar 2019 22:44:33 +0100 Subject: [PATCH 5/5] Updated `Drawer` reverse logic to use `{ns}-position-` classes instead of `{ns}-vertical`/`{ns}-reverse` pair --- packages/core/src/common/classes.ts | 13 +- .../core/src/components/drawer/_drawer.scss | 147 ++++++++++++------ .../core/src/components/drawer/drawer.tsx | 16 +- packages/core/test/drawer/drawerTests.tsx | 24 ++- .../examples/core-examples/drawerExample.tsx | 4 - 5 files changed, 132 insertions(+), 72 deletions(-) diff --git a/packages/core/src/common/classes.ts b/packages/core/src/common/classes.ts index 33162cbf46..730aff545d 100644 --- a/packages/core/src/common/classes.ts +++ b/packages/core/src/common/classes.ts @@ -7,6 +7,7 @@ import { Alignment } from "./alignment"; import { Elevation } from "./elevation"; import { Intent } from "./intent"; +import { Position } from "./position"; const NS = process.env.BLUEPRINT_NAMESPACE || "bp3"; @@ -28,7 +29,10 @@ export const MULTILINE = `${NS}-multiline`; export const ROUND = `${NS}-round`; export const SMALL = `${NS}-small`; export const VERTICAL = `${NS}-vertical`; -export const REVERSE = `${NS}-reverse`; +export const POSITION_TOP = positionClass(Position.TOP); +export const POSITION_BOTTOM = positionClass(Position.BOTTOM); +export const POSITION_LEFT = positionClass(Position.LEFT); +export const POSITION_RIGHT = positionClass(Position.RIGHT); export const ELEVATION_0 = elevationClass(Elevation.ZERO); export const ELEVATION_1 = elevationClass(Elevation.ONE); @@ -305,3 +309,10 @@ export function intentClass(intent?: Intent) { } return `${NS}-intent-${intent.toLowerCase()}`; } + +export function positionClass(position: Position) { + if (position == null) { + return undefined; + } + return `${NS}-position-${position}`; +} diff --git a/packages/core/src/components/drawer/_drawer.scss b/packages/core/src/components/drawer/_drawer.scss index af1640db23..90745eeac4 100644 --- a/packages/core/src/components/drawer/_drawer.scss +++ b/packages/core/src/components/drawer/_drawer.scss @@ -23,62 +23,105 @@ $drawer-default-size: 50%; outline: 0; } - &:not(.#{$ns}-vertical) { + &.#{$ns}-position-top { + @include react-transition-phase( + "#{$ns}-overlay", + "enter", + (transform: (translateY(-100%), translateY(0))), + $pt-transition-duration * 2, + $pt-transition-ease, + $before: "&" + ); + @include react-transition-phase( + "#{$ns}-overlay", + "exit", + (transform: (translateY(-100%), translateY(0))), + $pt-transition-duration, + $before: "&" + ); + top: 0; - bottom: 0; - width: $drawer-default-size; + right: 0; + left: 0; + height: $drawer-default-size; + } - &:not(.#{$ns}-reverse) { - @include react-transition-phase( - "#{$ns}-overlay", - "enter", - (transform: (translateX(100%), translateX(0))), - $pt-transition-duration * 2, - $pt-transition-ease, - $before: "&" - ); - @include react-transition-phase( - "#{$ns}-overlay", - "exit", - (transform: (translateX(100%), translateX(0))), - $pt-transition-duration, - $before: "&" - ); + &.#{$ns}-position-bottom { + @include react-transition-phase( + "#{$ns}-overlay", + "enter", + (transform: (translateY(100%), translateY(0))), + $pt-transition-duration * 2, + $pt-transition-ease, + $before: "&" + ); + @include react-transition-phase( + "#{$ns}-overlay", + "exit", + (transform: (translateY(100%), translateY(0))), + $pt-transition-duration, + $before: "&" + ); - right: 0; - } + right: 0; + bottom: 0; + left: 0; + height: $drawer-default-size; + } - &.#{$ns}-reverse { - @include react-transition-phase( - "#{$ns}-overlay", - "enter", - (transform: (translateX(-100%), translateX(0))), - $pt-transition-duration * 2, - $pt-transition-ease, - $before: "&" - ); - @include react-transition-phase( - "#{$ns}-overlay", - "exit", - (transform: (translateX(-100%), translateX(0))), - $pt-transition-duration, - $before: "&" - ); + &.#{$ns}-position-left { + @include react-transition-phase( + "#{$ns}-overlay", + "enter", + (transform: (translateX(-100%), translateX(0))), + $pt-transition-duration * 2, + $pt-transition-ease, + $before: "&" + ); + @include react-transition-phase( + "#{$ns}-overlay", + "exit", + (transform: (translateX(-100%), translateX(0))), + $pt-transition-duration, + $before: "&" + ); - left: 0; - } + top: 0; + bottom: 0; + left: 0; + width: $drawer-default-size; } - &.#{$ns}-vertical { + &.#{$ns}-position-right { + @include react-transition-phase( + "#{$ns}-overlay", + "enter", + (transform: (translateX(100%), translateX(0))), + $pt-transition-duration * 2, + $pt-transition-ease, + $before: "&" + ); + @include react-transition-phase( + "#{$ns}-overlay", + "exit", + (transform: (translateX(100%), translateX(0))), + $pt-transition-duration, + $before: "&" + ); + + top: 0; right: 0; - left: 0; - height: $drawer-default-size; + bottom: 0; + width: $drawer-default-size; + } - &:not(.#{$ns}-reverse) { + &:not(.#{$ns}-position-top):not(.#{$ns}-position-bottom):not(.#{$ns}-position-left):not( + .#{$ns}-position-right) { + &:not(.#{$ns}-vertical) { @include react-transition-phase( "#{$ns}-overlay", "enter", - (transform: (translateY(100%), translateY(0))), + (transform: (translateX(100%), translateX(0))), $pt-transition-duration * 2, $pt-transition-ease, $before: "&" @@ -86,19 +129,22 @@ $drawer-default-size: 50%; @include react-transition-phase( "#{$ns}-overlay", "exit", - (transform: (translateY(100%), translateY(0))), + (transform: (translateX(100%), translateX(0))), $pt-transition-duration, $before: "&" ); + top: 0; + right: 0; bottom: 0; + width: $drawer-default-size; } - &.#{$ns}-reverse { + &.#{$ns}-vertical { @include react-transition-phase( "#{$ns}-overlay", "enter", - (transform: (translateY(-100%), translateY(0))), + (transform: (translateY(100%), translateY(0))), $pt-transition-duration * 2, $pt-transition-ease, $before: "&" @@ -106,12 +152,15 @@ $drawer-default-size: 50%; @include react-transition-phase( "#{$ns}-overlay", "exit", - (transform: (translateY(-100%), translateY(0))), + (transform: (translateY(100%), translateY(0))), $pt-transition-duration, $before: "&" ); - top: 0; + right: 0; + bottom: 0; + left: 0; + height: $drawer-default-size; } } diff --git a/packages/core/src/components/drawer/drawer.tsx b/packages/core/src/components/drawer/drawer.tsx index 3a7f20b0c5..1a1664ad0d 100644 --- a/packages/core/src/components/drawer/drawer.tsx +++ b/packages/core/src/components/drawer/drawer.tsx @@ -80,7 +80,7 @@ export interface IDrawerProps extends IOverlayableProps, IBackdropProps, IProps * Whether the drawer should appear with vertical styling. * It will be ignored if `position` prop is set * @default false - * @deprecated + * @deprecated use `position` instead */ vertical?: boolean; } @@ -101,18 +101,24 @@ export class Drawer extends AbstractPureComponent { public render() { const { size, style, position, vertical } = this.props; - const realPosition = getPositionIgnoreAngles(position || (vertical ? Position.BOTTOM : Position.RIGHT)); + const realPosition = position ? getPositionIgnoreAngles(position) : null; const classes = classNames( Classes.DRAWER, { - [Classes.VERTICAL]: isPositionHorizontal(realPosition), - [Classes.REVERSE]: realPosition === Position.TOP || realPosition === Position.LEFT, + [Classes.VERTICAL]: !realPosition && vertical, + [realPosition ? Classes.positionClass(realPosition) : ""]: true, }, this.props.className, ); + const styleProp = - size == null ? style : { ...style, [isPositionHorizontal(realPosition) ? "height" : "width"]: size }; + size == null + ? style + : { + ...style, + [(realPosition ? isPositionHorizontal(realPosition) : vertical) ? "height" : "width"]: size, + }; return (
diff --git a/packages/core/test/drawer/drawerTests.tsx b/packages/core/test/drawer/drawerTests.tsx index b806f1d979..54b46e515d 100644 --- a/packages/core/test/drawer/drawerTests.tsx +++ b/packages/core/test/drawer/drawerTests.tsx @@ -102,11 +102,13 @@ describe("", () => { {createDrawerContents()} , ); - - assert.isTrue( - drawerDefault - .find(`.${Classes.DRAWER}`) - .equals(drawerRight.find(`.${Classes.DRAWER}`).getElement()), + assert.equal( + drawerDefault.find(`.${Classes.DRAWER}`).prop("style").width, + drawerRight.find(`.${Classes.DRAWER}`).prop("style").width, + ); + assert.equal( + drawerDefault.find(`.${Classes.DRAWER}`).prop("style").height, + drawerRight.find(`.${Classes.DRAWER}`).prop("style").height, ); }); @@ -125,8 +127,7 @@ describe("", () => { {createDrawerContents()} , ); - assert.isFalse(drawer.find(`.${Classes.VERTICAL}`).exists()); - assert.isFalse(drawer.find(`.${Classes.REVERSE}`).exists()); + assert.isTrue(drawer.find(`.${Classes.POSITION_RIGHT}`).exists()); }); }); @@ -146,8 +147,7 @@ describe("", () => { {createDrawerContents()} , ); - assert.isTrue(drawer.find(`.${Classes.VERTICAL}`).exists()); - assert.isTrue(drawer.find(`.${Classes.REVERSE}`).exists()); + assert.isTrue(drawer.find(`.${Classes.POSITION_TOP}`).exists()); }); }); @@ -167,8 +167,7 @@ describe("", () => { {createDrawerContents()} , ); - assert.isTrue(drawer.find(`.${Classes.VERTICAL}`).exists()); - assert.isFalse(drawer.find(`.${Classes.REVERSE}`).exists()); + assert.isTrue(drawer.find(`.${Classes.POSITION_BOTTOM}`).exists()); }); }); @@ -188,8 +187,7 @@ describe("", () => { {createDrawerContents()} , ); - assert.isFalse(drawer.find(`.${Classes.VERTICAL}`).exists()); - assert.isTrue(drawer.find(`.${Classes.REVERSE}`).exists()); + assert.isTrue(drawer.find(`.${Classes.POSITION_LEFT}`).exists()); }); }); }); diff --git a/packages/docs-app/src/examples/core-examples/drawerExample.tsx b/packages/docs-app/src/examples/core-examples/drawerExample.tsx index 9775bba5f3..1cf3010c2c 100644 --- a/packages/docs-app/src/examples/core-examples/drawerExample.tsx +++ b/packages/docs-app/src/examples/core-examples/drawerExample.tsx @@ -32,7 +32,6 @@ export interface IDrawerExampleState { position?: Position; size: string; usePortal: boolean; - vertical: boolean; } export class DrawerExample extends React.PureComponent, IDrawerExampleState> { public state: IDrawerExampleState = { @@ -45,7 +44,6 @@ export class DrawerExample extends React.PureComponent this.setState({ autoFocus })); @@ -55,7 +53,6 @@ export class DrawerExample extends React.PureComponent this.setState({ usePortal })); private handlePositionChange = handleStringChange((position: Position) => this.setState({ position })); private handleOutsideClickChange = handleBooleanChange(val => this.setState({ canOutsideClickClose: val })); - private handleVerticalChange = handleBooleanChange(vertical => this.setState({ vertical })); private handleSizeChange = handleStringChange(size => this.setState({ size })); public render() { @@ -122,7 +119,6 @@ export class DrawerExample extends React.PureComponent -