Skip to content

Commit

Permalink
#2137 Resize Right Flyout using drag (#2224)
Browse files Browse the repository at this point in the history
Signed-off-by: srikant <[email protected]>
  • Loading branch information
srikant-ch5 authored Nov 26, 2024
1 parent 940e0ae commit f89a7fd
Show file tree
Hide file tree
Showing 19 changed files with 294 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ describe("CommonCanvas renders correctly", () => {
const config = {};
const canvasParams = { showRightFlyout: false };
const wrapper = createCommonCanvas(config, canvasController, canvasParams);
expect(wrapper.find(CommonCanvasRightFlyout)).to.have.length(1);
// When showRightFlyout is false then Right Flyout should not be visible
expect(wrapper.find(CommonCanvasRightFlyout)).to.have.length(0);
expect(canvasController.isRightFlyoutOpen() === false).to.be.true;
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1618,6 +1618,18 @@ export default class CanvasController {
this.objectModel.setBottomPanelHeight(ht);
}

isLeftFlyoutOpen() {
return this.objectModel.isLeftFlyoutOpen();
}

setRightFlyoutWidth(wd) {
this.objectModel.setRightFlyoutWidth(wd);
}

isRightFlyoutOpen() {
return this.objectModel.isRightFlyoutOpen();
}

isTopPanelOpen() {
return this.getObjectModel().isTopPanelOpen();
}
Expand Down Expand Up @@ -1672,14 +1684,6 @@ export default class CanvasController {
this.objectModel.toggleNotificationPanel();
}

isLeftFlyoutOpen() {
return this.objectModel.isLeftFlyoutOpen();
}

isRightFlyoutOpen() {
return this.objectModel.isRightFlyoutOpen();
}

isDisplayingFullPageSubFlow() {
const breadcrumbs = this.objectModel.getBreadcrumbs();
return breadcrumbs.length > 1;
Expand Down
18 changes: 15 additions & 3 deletions canvas_modules/common-canvas/src/common-canvas/cc-panels.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ class CommonCanvasPanels extends React.Component {
// indicated by setting the config field enablePaletteLayout to
// "None" and providing some JSX in the leftFlyoutContent field
// of <CommonCanvas>.
isLeftPanelOpen() {
isLeftFlyoutOpen() {
if (this.props.enablePaletteLayout === PALETTE_LAYOUT_DIALOG) {
return false;
}
Expand All @@ -114,6 +114,11 @@ class CommonCanvasPanels extends React.Component {
return false;
}

// Returns true if the right flyout should be displayed.
isRightFlyoutOpen() {
return this.props.rightFlyoutIsOpen;
}

// Returns a JSX object for the contents of the left panel. If the application
// sets enablePaletteLayout to None this indicates the app wamts its own content
// to go into the left panel provided by leftFlyoutContent provided to <CommonCanvas>
Expand All @@ -129,6 +134,11 @@ class CommonCanvasPanels extends React.Component {
return null;
}

// Returns a JSX object for the contents of the right panel.
generateRightFlyout() {
return (<CommonCanvasRightFlyout containingDivId={this.props.containingDivId} canvasController={this.props.canvasController} />);
}

render() {
this.logger.log("render");

Expand All @@ -138,8 +148,9 @@ class CommonCanvasPanels extends React.Component {
containingDivId={this.props.containingDivId}
/>
);
const rightFlyout = (<CommonCanvasRightFlyout />);
const leftFlyoutIsOpen = this.isLeftPanelOpen();
const rightFlyoutIsOpen = this.isRightFlyoutOpen();
const rightFlyout = rightFlyoutIsOpen ? this.generateRightFlyout() : null;
const leftFlyoutIsOpen = this.isLeftFlyoutOpen();
const leftFlyout = leftFlyoutIsOpen ? this.generateLeftFlyout() : null;

const topCenterBottom = this.generateTopCenterBottom();
Expand Down Expand Up @@ -288,6 +299,7 @@ const mapStateToProps = (state, ownProps) => ({
enableNarrowPalette: state.canvasconfig.enableNarrowPalette,
enableLeftFlyoutUnderToolbar: state.canvasconfig.enableLeftFlyoutUnderToolbar,
enableRightFlyoutUnderToolbar: state.canvasconfig.enableRightFlyoutUnderToolbar,
enableRightFlyoutDragToResize: state.canvasconfig.enableRightFlyoutDragToResize,
toolbarIsOpen: (state.canvasconfig.enableToolbarLayout !== PALETTE_LAYOUT_NONE),
paletteIsOpen: state.palette.isOpen,
topPanelIsOpen: state.toppanel.isOpen,
Expand Down
121 changes: 117 additions & 4 deletions canvas_modules/common-canvas/src/common-canvas/cc-right-flyout.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,24 +19,129 @@ import { connect } from "react-redux";
import PropTypes from "prop-types";
import Logger from "../logging/canvas-logger.js";

// Should cover at most 70% of available width.
const MAX_WIDTH_EXTEND_PERCENT = 0.7;
// Should have a minimum width of 0 to hide flyout if there is no content.
const MIN_WIDTH = 0;
// If flyout content width is not set occupy entire width to strecth content.
const DEFAULT_WIDTH = "100%";
class CommonCanvasRightFlyout extends React.Component {
constructor(props) {
super(props);

// Intial width of the flyout when opened to track resize.
this.initialWidth = MIN_WIDTH;

this.logger = new Logger("CC-RightFlyout");

this.rightFlyoutRef = React.createRef();

this.onMouseUp = this.onMouseUp.bind(this);
this.onMouseDown = this.onMouseDown.bind(this);
this.onMouseMoveX = this.onMouseMoveX.bind(this);
this.getCurrentWidth = this.getCurrentWidth.bind(this);

this.getRightFlyoutResizeContent = this.getRightFlyoutResizeContent.bind(this);
}

componentDidMount() {
// Since flyout content width can be dynamic set the initial width as per width of the content
const currentWidth = this.getCurrentWidth();
this.initialWidth = currentWidth;
}

componentWillUnmount() {
// Reset the flyout width to adjust as per content width in next render
this.props.canvasController.setRightFlyoutWidth(0);
}

onMouseDown(e) {
// Set width as soon as resize is detected to accurately move the flyout with the drag.
const currentWidth = this.getCurrentWidth();
this.props.canvasController.setRightFlyoutWidth(this.limitWidth(currentWidth));

if (e.button === 0) {
document.addEventListener("mousemove", this.onMouseMoveX, true);
document.addEventListener("mouseup", this.onMouseUp, true);
this.posX = e.clientX;
// Prevent panel contents being dragged in the test harness (which can
// happen even though draggable is false for the contents!)
e.preventDefault();
}
}

onMouseUp() {
document.removeEventListener("mousemove", this.onMouseMoveX, true);
document.removeEventListener("mouseup", this.onMouseUp, true);
}

onMouseMoveX(e) {
if (e.clientX) {
const diff = e.clientX - this.posX;
const wth = this.props.panelWidth - diff;
this.props.canvasController.setRightFlyoutWidth(this.limitWidth(wth));
this.posX = e.clientX;
}
}

// Returns content to enable/disable resize based on feature flag.
getRightFlyoutResizeContent() {
let resizeContent = null;

if (this.props.enableRightFlyoutDragToResize) {
resizeContent = (<div className="right-flyout-drag" onMouseDown={this.onMouseDown} />);
}

return resizeContent;
}

// Returns present width of the flyout.
getCurrentWidth() {
let currentWidth = MIN_WIDTH;
const el = this.rightFlyoutRef?.current;
if (el) {
currentWidth = el?.offsetWidth;
}
return currentWidth;
}

// Returns a new width for right panel limited by the need to enforce
// a minimum and maximum width
limitWidth(wd) {
const canvasContainer = document.getElementById(this.props.containingDivId);
let width = wd;

if (canvasContainer) {
// Max Width should be 70% of the total available width (canvas + rightflyout)
const canvasWidth = canvasContainer.getBoundingClientRect().width;
const maxWidth = (canvasWidth + this.props.panelWidth) * MAX_WIDTH_EXTEND_PERCENT;
width = Math.min(Math.max(width, this.initialWidth), maxWidth);
}

return width;
}

render() {
this.logger.log("render");

let rightFlyout = <div />; // For no content, return empty <div> so grid siziing for parent <div> work correctly.
const rightFlyoutDragContent = this.getRightFlyoutResizeContent();

if (this.props.content && this.props.isOpen) {
let widthPx = this.limitWidth(this.props.panelWidth) + "px";
// Apply 100% width if content has no width to occupy flyout.
if (this.props.panelWidth === MIN_WIDTH) {
widthPx = DEFAULT_WIDTH;
}
const rfClass = this.props.enableRightFlyoutUnderToolbar
? "right-flyout-panel under-toolbar"
: "right-flyout-panel";
rightFlyout = (
<div className={rfClass}>
{this.props.content}
<div className="right-flyout-container" style={{ width: widthPx }} >
{rightFlyoutDragContent}
<div className={rfClass} ref={this.rightFlyoutRef}>
{this.props.content}
</div>
</div>
);
}
Expand All @@ -46,16 +151,24 @@ class CommonCanvasRightFlyout extends React.Component {
}

CommonCanvasRightFlyout.propTypes = {
// Provided by Common Canvas
canvasController: PropTypes.object,
containingDivId: PropTypes.string,

// Provided by Redux
isOpen: PropTypes.bool,
content: PropTypes.object,
enableRightFlyoutUnderToolbar: PropTypes.bool
enableRightFlyoutUnderToolbar: PropTypes.bool,
enableRightFlyoutDragToResize: PropTypes.bool,
panelWidth: PropTypes.number
};

const mapStateToProps = (state, ownProps) => ({
isOpen: state.rightflyout.isOpen,
content: state.rightflyout.content,
enableRightFlyoutUnderToolbar: state.canvasconfig.enableRightFlyoutUnderToolbar
enableRightFlyoutUnderToolbar: state.canvasconfig.enableRightFlyoutUnderToolbar,
enableRightFlyoutDragToResize: state.canvasconfig.enableRightFlyoutDragToResize,
panelWidth: state.rightflyout.panelWidth
});

export default connect(mapStateToProps)(CommonCanvasRightFlyout);
25 changes: 25 additions & 0 deletions canvas_modules/common-canvas/src/common-canvas/common-canvas.scss
Original file line number Diff line number Diff line change
Expand Up @@ -44,18 +44,43 @@ $panel-border-color: $border-subtle-01;
position: relative; // This allows the State Tag to have positio: absolute
}

.right-flyout-container {
display: flex;
border-left: $panel-border-width solid $panel-border-color;
min-height: fit-content;
min-width: fit-content;
}

.left-flyout-panel,
.right-flyout-panel {
// This combination of height and min-height enable scrolling in the child panel,
// I believe this is because it sets a specific height on the CSS grid cell,
// so the contents of the panel can adjust themselves to the height accordingly.
height: 0;
min-height: 100%;
}

// Allow content in child to expand on drag using flex
.right-flyout-panel {
min-width: fit-content;
display: flex;
flex: 1;
user-select: none; /* Prevent elements from being selectable */
background-color: $layer-01;
}

.right-flyout-drag {
border-left: $panel-border-color;
cursor: col-resize;
flex: 0 0 $spacing-01;
border-left-width: 1px;
background: $layer-01;
transition: all 0.2s ease-in;
&:hover {
background: $button-tertiary;
}
}

.bottom-panel {
display: flex;
flex-direction: column;
Expand Down
Loading

0 comments on commit f89a7fd

Please sign in to comment.