Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use custom splitter component #4606

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,6 @@
"react-dom": "^18.2.0",
"react-intersection-observer": "^9.4.3",
"react-redux": "^8.0.5",
"react-splitter-layout": "^4.0.0",
"react-transition-group": "^4.4.5",
"redux": "^4.2.1",
"redux-logger": "^3.0.6",
Expand Down
15 changes: 12 additions & 3 deletions src/components/app/BottomBox.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,17 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

.bottom-box {
display: flex;
min-height: 0;
flex-flow: row nowrap;
}

.bottom-box-pane {
display: flex;
height: 100%; /* direct child of SplitterLayout */
overflow: hidden;
min-width: 0;
flex: 1;
flex-flow: column nowrap;
}

Expand All @@ -18,15 +26,15 @@
background: var(--grey-20);
}

.bottom-box .layout-splitter {
.bottom-box .resizableWithSplitterSplitter {
position: relative; /* containing block for absolute ::before */
width: 1px;
border: none;
background-color: var(--grey-30) !important;
}

/* Provide 3px extra grabbable surface on each side of the splitter */
.bottom-box .layout-splitter::before {
.bottom-box .resizableWithSplitterSplitter::before {
position: absolute;
z-index: 1;
display: block;
Expand All @@ -39,6 +47,7 @@
overflow: hidden;
height: 24px;
flex-flow: row;
flex-shrink: 0;
align-items: center;
justify-content: space-between;
border-bottom: 1px solid var(--grey-30);
Expand Down
67 changes: 36 additions & 31 deletions src/components/app/BottomBox.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
// @flow

import React from 'react';
import SplitterLayout from 'react-splitter-layout';
import classNames from 'classnames';

import { SourceView } from '../shared/SourceView';
import { AssemblyView } from '../shared/AssemblyView';
import { ResizableWithSplitter } from '../shared/ResizableWithSplitter';
import { AssemblyViewToggleButton } from './AssemblyViewToggleButton';
import { CodeLoadingOverlay } from './CodeLoadingOverlay';
import { CodeErrorOverlay } from './CodeErrorOverlay';
Expand Down Expand Up @@ -205,36 +205,41 @@ class BottomBoxImpl extends React.PureComponent<Props> {

return (
<div className="bottom-box">
<SplitterLayout customClassName="bottom-box" percentage>
<div className="bottom-box-pane">
<div className="bottom-box-bar">
<h3 className="bottom-box-title">{path ?? '(no source file)'}</h3>
{assemblyViewIsOpen ? null : trailingHeaderButtons}
</div>
<div className="bottom-sourceview-wrapper">
{sourceViewFile !== null ? (
<SourceView
disableOverscan={disableOverscan}
timings={globalLineTimings}
sourceCode={sourceCode}
filePath={path}
scrollToHotSpotGeneration={sourceViewScrollGeneration}
hotSpotTimings={selectedCallNodeLineTimings}
ref={this._sourceView}
/>
) : null}
{sourceViewCode !== undefined &&
sourceViewCode.type === 'LOADING' ? (
<CodeLoadingOverlay source={sourceViewCode.source} />
) : null}
{sourceViewCode !== undefined &&
sourceViewCode.type === 'ERROR' ? (
<SourceCodeErrorOverlay errors={sourceViewCode.errors} />
) : null}
</div>
<div className="bottom-box-pane">
<div className="bottom-box-bar">
<h3 className="bottom-box-title">{path ?? '(no source file)'}</h3>
{assemblyViewIsOpen ? null : trailingHeaderButtons}
</div>
<div className="bottom-sourceview-wrapper">
{sourceViewFile !== null ? (
<SourceView
disableOverscan={disableOverscan}
timings={globalLineTimings}
sourceCode={sourceCode}
filePath={path}
scrollToHotSpotGeneration={sourceViewScrollGeneration}
hotSpotTimings={selectedCallNodeLineTimings}
ref={this._sourceView}
/>
) : null}
{sourceViewCode !== undefined &&
sourceViewCode.type === 'LOADING' ? (
<CodeLoadingOverlay source={sourceViewCode.source} />
) : null}
{sourceViewCode !== undefined && sourceViewCode.type === 'ERROR' ? (
<SourceCodeErrorOverlay errors={sourceViewCode.errors} />
) : null}
</div>
</div>

{assemblyViewIsOpen ? (
{assemblyViewIsOpen ? (
<ResizableWithSplitter
splitterPosition="start"
controlledProperty="width"
className=""
percent={true}
initialSize="50%"
>
<div className="bottom-box-pane">
<div className="bottom-box-bar">
<h3 className="bottom-box-title">
Expand Down Expand Up @@ -268,8 +273,8 @@ class BottomBoxImpl extends React.PureComponent<Props> {
) : null}
</div>
</div>
) : null}
</SplitterLayout>
</ResizableWithSplitter>
) : null}
</div>
);
}
Expand Down
6 changes: 5 additions & 1 deletion src/components/app/Details.css
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
.Details {
display: flex;
flex: auto;

/* If .Details is squished to a very small size between the sidebar and/or bottom bar,
don't spill out our contents over those other elements. */
overflow: hidden;
flex: 1;
flex-direction: column;
}

Expand Down
27 changes: 15 additions & 12 deletions src/components/app/DetailsContainer.css
Original file line number Diff line number Diff line change
@@ -1,26 +1,29 @@
.DetailsContainer .layout-pane > * {
width: 100%;
height: 100%;
.DetailsContainer {
position: relative;
z-index: 0;
display: flex;
box-sizing: border-box;
flex: 1;
flex-flow: row nowrap;
contain: size;
}

.DetailsContainer .layout-pane:not(.layout-pane-primary) {
max-width: 600px;
.DetailsContainer .resizableWithSplitterInner > * {
min-width: 0;
flex: 1;
}

/* overriding defaults from splitter-layout */
.DetailsContainer {
/* SplitterLayout injects position: absolute, this conflicts with our using
* Flex Layout. */
position: unset;
.DetailsContainerResizableSidebarWrapper {
max-width: 600px;
}

.DetailsContainer .layout-splitter {
/* overriding defaults from ResizableWithSplitter.css */
.DetailsContainer .resizableWithSplitterSplitter {
border-top: 1px solid var(--grey-30);
border-left: 1px solid var(--grey-30);
background: var(--grey-10); /* Same background as sidebars */
}

.DetailsContainer .layout-splitter:hover {
.DetailsContainer .resizableWithSplitterSplitter:hover {
background: var(--grey-30); /* same as the border above */
}
29 changes: 15 additions & 14 deletions src/components/app/DetailsContainer.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
// @flow

import React from 'react';
import SplitterLayout from 'react-splitter-layout';

import { Details } from './Details';
import { ResizableWithSplitter } from 'firefox-profiler/components/shared/ResizableWithSplitter';
import { selectSidebar } from 'firefox-profiler/components/sidebar';

import { invalidatePanelLayout } from 'firefox-profiler/actions/app';
Expand All @@ -30,23 +30,24 @@ type DispatchProps = {|

type Props = ConnectedProps<{||}, StateProps, DispatchProps>;

function DetailsContainerImpl({
selectedTab,
isSidebarOpen,
invalidatePanelLayout,
}: Props) {
function DetailsContainerImpl({ selectedTab, isSidebarOpen }: Props) {
const Sidebar = selectSidebar(selectedTab);

return (
<SplitterLayout
customClassName="DetailsContainer"
percentage
secondaryInitialSize={20}
onDragEnd={invalidatePanelLayout}
>
<div className="DetailsContainer">
<Details />
{Sidebar && isSidebarOpen ? <Sidebar /> : null}
</SplitterLayout>
{Sidebar && isSidebarOpen ? (
<ResizableWithSplitter
className="DetailsContainerResizableSidebarWrapper"
percent={false}
splitterPosition="start"
controlledProperty="width"
initialSize="300px"
>
<Sidebar />
</ResizableWithSplitter>
) : null}
</div>
);
}

Expand Down
19 changes: 4 additions & 15 deletions src/components/app/ProfileViewer.css
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@
}

.profileViewer {
/* Create a stacking context, so that the KeyboardShortcut can overlay the profile
viewer. */
position: relative;
z-index: 0;
display: flex;
min-width: 0; /* This allows Flexible Layout to shrink this further than its min-content */
flex: 1;
Expand Down Expand Up @@ -89,21 +93,6 @@
border-color: #000;
}

.profileViewerSplitter {
/* Create a stacking context, so that the KeyboardShortcut can overlay the profile
viewer. In addition, the built-in class uses position: absolute, which is not
appropriate here. */
position: relative;
z-index: 0;
}

.profileViewerSplitter > .layout-pane:not(.layout-pane-primary) {
display: flex;
overflow: hidden;
max-height: var(--profile-viewer-splitter-max-height);
flex-direction: column;
}

.profileViewerTopBar {
display: flex;
height: 24px;
Expand Down
42 changes: 19 additions & 23 deletions src/components/app/ProfileViewer.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import React, { PureComponent } from 'react';
import explicitConnect from 'firefox-profiler/utils/connect';

import { ResizableWithSplitter } from 'firefox-profiler/components/shared/ResizableWithSplitter';
import { DetailsContainer } from './DetailsContainer';
import { SourceCodeFetcher } from './SourceCodeFetcher';
import { AssemblyCodeFetcher } from './AssemblyCodeFetcher';
Expand All @@ -22,7 +23,6 @@ import { KeyboardShortcut } from './KeyboardShortcut';
import { returnToZipFileList } from 'firefox-profiler/actions/zipped-profiles';
import { Timeline } from 'firefox-profiler/components/timeline';
import { getHasZipFile } from 'firefox-profiler/selectors/zipped-profiles';
import SplitterLayout from 'react-splitter-layout';
import { invalidatePanelLayout } from 'firefox-profiler/actions/app';
import { getTimelineHeight } from 'firefox-profiler/selectors/app';
import { getIsBottomBoxOpen } from 'firefox-profiler/selectors/url-state';
Expand Down Expand Up @@ -66,7 +66,6 @@ class ProfileViewerImpl extends PureComponent<Props> {
const {
hasZipFile,
returnToZipFileList,
invalidatePanelLayout,
timelineHeight,
isUploading,
uploadProgress,
Expand Down Expand Up @@ -130,30 +129,27 @@ class ProfileViewerImpl extends PureComponent<Props> {
/>
) : null}
</div>
<SplitterLayout
customClassName="profileViewerSplitter"
vertical
percentage={false}
// The DetailsContainer is primary.
primaryIndex={1}
// The Timeline is secondary.
secondaryInitialSize={270}
onDragEnd={invalidatePanelLayout}
<ResizableWithSplitter
className=""
splitterPosition="end"
controlledProperty="max-height"
percent={false}
initialSize="270px"
>
<Timeline />
<SplitterLayout
vertical
percentage={true}
// The DetailsContainer is primary.
primaryIndex={0}
// The BottomBox is secondary.
secondaryInitialSize={40}
onDragEnd={invalidatePanelLayout}
</ResizableWithSplitter>
<DetailsContainer />
{isBottomBoxOpen ? (
<ResizableWithSplitter
className=""
splitterPosition="start"
controlledProperty="height"
percent={true}
initialSize="40%"
>
<DetailsContainer />
{isBottomBoxOpen ? <BottomBox /> : null}
</SplitterLayout>
</SplitterLayout>
<BottomBox />
</ResizableWithSplitter>
) : null}
<SymbolicationStatusOverlay />
<BeforeUnloadManager />
<DebugWarning />
Expand Down
15 changes: 7 additions & 8 deletions src/components/shared/Draggable.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,17 @@
// @flow

import * as React from 'react';
import type { Milliseconds } from 'firefox-profiler/types';

export type OnMove = (
originalValue: { +selectionEnd: Milliseconds, +selectionStart: Milliseconds },
export type OnMove<T> = (
originalValue: T,
dx: number,
dy: number,
isModifying: boolean
) => void;

type Props = {
value: { +selectionStart: Milliseconds, +selectionEnd: Milliseconds },
onMove: OnMove,
type Props<T> = {
getInitialValue: () => T,
onMove: OnMove<T>,
className: string,
children?: React.Node,
};
Expand All @@ -33,7 +32,7 @@ type State = {
* x and y deltas compared to the mouse position at mousedown.
* During the drag, the additional className 'dragging' is set on the element.
*/
export class Draggable extends React.PureComponent<Props, State> {
export class Draggable<T> extends React.PureComponent<Props<T>, State> {
_container: HTMLDivElement | null = null;
_handlers: {
mouseMoveHandler: (MouseEvent) => void,
Expand All @@ -58,7 +57,7 @@ export class Draggable extends React.PureComponent<Props, State> {

const mouseDownX = e.pageX;
const mouseDownY = e.pageY;
const startValue = this.props.value;
const startValue = this.props.getInitialValue();

const mouseMoveHandler = (e) => {
this.props.onMove(
Expand Down
Loading