Interactive
Summary: _typescript_ Reviewed By: passy Differential Revision: D16830548 fbshipit-source-id: d0530ef3491af95bece7fba610a4b1cf19c80bd1
This commit is contained in:
committed by
Facebook Github Bot
parent
e00db4f6d3
commit
28a295bcf1
@@ -5,31 +5,34 @@
|
|||||||
* @format
|
* @format
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type {Rect} from '../../utils/geometry.tsx';
|
import {Rect} from '../../utils/geometry';
|
||||||
import LowPassFilter from '../../utils/LowPassFilter.tsx';
|
import LowPassFilter from '../../utils/LowPassFilter';
|
||||||
import {
|
import {
|
||||||
getDistanceTo,
|
getDistanceTo,
|
||||||
maybeSnapLeft,
|
maybeSnapLeft,
|
||||||
maybeSnapTop,
|
maybeSnapTop,
|
||||||
SNAP_SIZE,
|
SNAP_SIZE,
|
||||||
} from '../../utils/snap.tsx';
|
} from '../../utils/snap';
|
||||||
import styled from '../styled/index.js';
|
import styled from 'react-emotion';
|
||||||
import invariant from 'invariant';
|
import invariant from 'invariant';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
const WINDOW_CURSOR_BOUNDARY = 5;
|
const WINDOW_CURSOR_BOUNDARY = 5;
|
||||||
|
|
||||||
type CursorState = {|
|
type CursorState = {
|
||||||
top: number,
|
top: number;
|
||||||
left: number,
|
left: number;
|
||||||
|};
|
};
|
||||||
|
|
||||||
type ResizingSides = ?{|
|
type ResizingSides =
|
||||||
left?: boolean,
|
| {
|
||||||
top?: boolean,
|
left?: boolean;
|
||||||
bottom?: boolean,
|
top?: boolean;
|
||||||
right?: boolean,
|
bottom?: boolean;
|
||||||
|};
|
right?: boolean;
|
||||||
|
}
|
||||||
|
| null
|
||||||
|
| undefined;
|
||||||
|
|
||||||
const ALL_RESIZABLE: ResizingSides = {
|
const ALL_RESIZABLE: ResizingSides = {
|
||||||
bottom: true,
|
bottom: true,
|
||||||
@@ -38,52 +41,52 @@ const ALL_RESIZABLE: ResizingSides = {
|
|||||||
top: true,
|
top: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
type InteractiveProps = {|
|
type InteractiveProps = {
|
||||||
isMovableAnchor?: (event: SyntheticMouseEvent<>) => boolean,
|
isMovableAnchor?: (event: React.MouseEvent) => boolean;
|
||||||
onMoveStart?: () => void,
|
onMoveStart?: () => void;
|
||||||
onMoveEnd?: () => void,
|
onMoveEnd?: () => void;
|
||||||
onMove?: (top: number, left: number, event: SyntheticMouseEvent<>) => void,
|
onMove?: (top: number, left: number, event: MouseEvent) => void;
|
||||||
id?: string,
|
id?: string;
|
||||||
movable?: boolean,
|
movable?: boolean;
|
||||||
hidden?: boolean,
|
hidden?: boolean;
|
||||||
moving?: boolean,
|
moving?: boolean;
|
||||||
grow?: boolean,
|
grow?: boolean;
|
||||||
siblings?: $Shape<{[key: string]: $Shape<Rect>}>,
|
siblings?: Partial<{[key: string]: Rect}>;
|
||||||
updateCursor?: (cursor: ?string) => void,
|
updateCursor?: (cursor?: string | null | undefined) => void;
|
||||||
zIndex?: number,
|
zIndex?: number;
|
||||||
top?: number,
|
top?: number;
|
||||||
left?: number,
|
left?: number;
|
||||||
minTop: number,
|
minTop?: number;
|
||||||
minLeft: number,
|
minLeft?: number;
|
||||||
width?: number | string,
|
width?: number | string;
|
||||||
height?: number | string,
|
height?: number | string;
|
||||||
minWidth: number,
|
minWidth: number;
|
||||||
minHeight: number,
|
minHeight: number;
|
||||||
maxWidth?: number,
|
maxWidth?: number;
|
||||||
maxHeight?: number,
|
maxHeight?: number;
|
||||||
onCanResize?: (sides: ResizingSides) => void,
|
onCanResize?: (sides: ResizingSides) => void;
|
||||||
onResizeStart?: () => void,
|
onResizeStart?: () => void;
|
||||||
onResizeEnd?: () => void,
|
onResizeEnd?: () => void;
|
||||||
onResize?: (width: number, height: number) => void,
|
onResize?: (width: number, height: number) => void;
|
||||||
resizing?: boolean,
|
resizing?: boolean;
|
||||||
resizable?: boolean | ResizingSides,
|
resizable?: boolean | ResizingSides;
|
||||||
innerRef?: (elem: HTMLElement) => void,
|
innerRef?: (elem: HTMLElement) => void;
|
||||||
style?: Object,
|
style?: Object;
|
||||||
className?: string,
|
className?: string;
|
||||||
children?: React$Element<*>,
|
children?: React.ReactNode;
|
||||||
|};
|
};
|
||||||
|
|
||||||
type InteractiveState = {|
|
type InteractiveState = {
|
||||||
moving: boolean,
|
moving: boolean;
|
||||||
movingInitialProps: ?InteractiveProps,
|
movingInitialProps: InteractiveProps | null | undefined;
|
||||||
movingInitialCursor: ?CursorState,
|
movingInitialCursor: CursorState | null | undefined;
|
||||||
cursor: ?string,
|
cursor: string | null | undefined;
|
||||||
resizingSides: ResizingSides,
|
resizingSides: ResizingSides;
|
||||||
couldResize: boolean,
|
couldResize: boolean;
|
||||||
resizing: boolean,
|
resizing: boolean;
|
||||||
resizingInitialRect: ?Rect,
|
resizingInitialRect: Rect | null | undefined;
|
||||||
resizingInitialCursor: ?CursorState,
|
resizingInitialCursor: CursorState | null | undefined;
|
||||||
|};
|
};
|
||||||
|
|
||||||
const InteractiveContainer = styled('div')({
|
const InteractiveContainer = styled('div')({
|
||||||
willChange: 'transform, height, width, z-index',
|
willChange: 'transform, height, width, z-index',
|
||||||
@@ -91,7 +94,7 @@ const InteractiveContainer = styled('div')({
|
|||||||
|
|
||||||
export default class Interactive extends React.Component<
|
export default class Interactive extends React.Component<
|
||||||
InteractiveProps,
|
InteractiveProps,
|
||||||
InteractiveState,
|
InteractiveState
|
||||||
> {
|
> {
|
||||||
constructor(props: InteractiveProps, context: Object) {
|
constructor(props: InteractiveProps, context: Object) {
|
||||||
super(props, context);
|
super(props, context);
|
||||||
@@ -114,9 +117,9 @@ export default class Interactive extends React.Component<
|
|||||||
globalMouse: boolean;
|
globalMouse: boolean;
|
||||||
ref: HTMLElement;
|
ref: HTMLElement;
|
||||||
|
|
||||||
nextTop: ?number;
|
nextTop: number | null | undefined;
|
||||||
nextLeft: ?number;
|
nextLeft: number | null | undefined;
|
||||||
nextEvent: ?SyntheticMouseEvent<>;
|
nextEvent: MouseEvent | null | undefined;
|
||||||
|
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
minHeight: 0,
|
minHeight: 0,
|
||||||
@@ -125,7 +128,7 @@ export default class Interactive extends React.Component<
|
|||||||
minWidth: 0,
|
minWidth: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
onMouseMove = (event: SyntheticMouseEvent<>) => {
|
onMouseMove = (event: MouseEvent) => {
|
||||||
if (this.state.moving) {
|
if (this.state.moving) {
|
||||||
this.calculateMove(event);
|
this.calculateMove(event);
|
||||||
} else if (this.state.resizing) {
|
} else if (this.state.resizing) {
|
||||||
@@ -135,7 +138,7 @@ export default class Interactive extends React.Component<
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
startAction = (event: SyntheticMouseEvent<>) => {
|
startAction = (event: React.MouseEvent) => {
|
||||||
this.globalMouse = true;
|
this.globalMouse = true;
|
||||||
window.addEventListener('pointerup', this.endAction, {passive: true});
|
window.addEventListener('pointerup', this.endAction, {passive: true});
|
||||||
window.addEventListener('pointermove', this.onMouseMove, {passive: true});
|
window.addEventListener('pointermove', this.onMouseMove, {passive: true});
|
||||||
@@ -148,7 +151,7 @@ export default class Interactive extends React.Component<
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
startTitleAction(event: SyntheticMouseEvent<>) {
|
startTitleAction(event: React.MouseEvent) {
|
||||||
if (this.state.couldResize) {
|
if (this.state.couldResize) {
|
||||||
this.startResizeAction(event);
|
this.startResizeAction(event);
|
||||||
} else if (this.props.movable === true) {
|
} else if (this.props.movable === true) {
|
||||||
@@ -156,7 +159,7 @@ export default class Interactive extends React.Component<
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
startMoving(event: SyntheticMouseEvent<>) {
|
startMoving(event: React.MouseEvent) {
|
||||||
const {onMoveStart} = this.props;
|
const {onMoveStart} = this.props;
|
||||||
if (onMoveStart) {
|
if (onMoveStart) {
|
||||||
onMoveStart();
|
onMoveStart();
|
||||||
@@ -229,13 +232,13 @@ export default class Interactive extends React.Component<
|
|||||||
return closeWindows;
|
return closeWindows;
|
||||||
}
|
}
|
||||||
|
|
||||||
startWindowAction(event: SyntheticMouseEvent<>) {
|
startWindowAction(event: React.MouseEvent) {
|
||||||
if (this.state.couldResize) {
|
if (this.state.couldResize) {
|
||||||
this.startResizeAction(event);
|
this.startResizeAction(event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
startResizeAction(event: SyntheticMouseEvent<>) {
|
startResizeAction(event: React.MouseEvent) {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
@@ -254,7 +257,10 @@ export default class Interactive extends React.Component<
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate(prevProps: InteractiveProps, prevState: InteractiveState) {
|
componentDidUpdate(
|
||||||
|
_prevProps: InteractiveProps,
|
||||||
|
prevState: InteractiveState,
|
||||||
|
) {
|
||||||
if (prevState.cursor !== this.state.cursor) {
|
if (prevState.cursor !== this.state.cursor) {
|
||||||
const {updateCursor} = this.props;
|
const {updateCursor} = this.props;
|
||||||
if (updateCursor) {
|
if (updateCursor) {
|
||||||
@@ -323,13 +329,13 @@ export default class Interactive extends React.Component<
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
onClick = (e: SyntheticMouseEvent<>) => {
|
onClick = (e: React.MouseEvent) => {
|
||||||
if (this.state.couldResize) {
|
if (this.state.couldResize) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
calculateMove(event: SyntheticMouseEvent<>) {
|
calculateMove(event: MouseEvent) {
|
||||||
const {movingInitialCursor, movingInitialProps} = this.state;
|
const {movingInitialCursor, movingInitialProps} = this.state;
|
||||||
|
|
||||||
invariant(movingInitialProps, 'TODO');
|
invariant(movingInitialProps, 'TODO');
|
||||||
@@ -380,7 +386,7 @@ export default class Interactive extends React.Component<
|
|||||||
onResize(width, height);
|
onResize(width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
move(top: number, left: number, event: SyntheticMouseEvent<>) {
|
move(top: number, left: number, event: MouseEvent) {
|
||||||
top = Math.max(this.props.minTop, top);
|
top = Math.max(this.props.minTop, top);
|
||||||
left = Math.max(this.props.minLeft, left);
|
left = Math.max(this.props.minLeft, left);
|
||||||
|
|
||||||
@@ -395,7 +401,7 @@ export default class Interactive extends React.Component<
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
calculateResize(event: SyntheticMouseEvent<>) {
|
calculateResize(event: MouseEvent) {
|
||||||
const {
|
const {
|
||||||
resizingInitialCursor,
|
resizingInitialCursor,
|
||||||
resizingInitialRect,
|
resizingInitialRect,
|
||||||
@@ -514,13 +520,15 @@ export default class Interactive extends React.Component<
|
|||||||
}
|
}
|
||||||
|
|
||||||
checkIfResizable(
|
checkIfResizable(
|
||||||
event: SyntheticMouseEvent<>,
|
event: MouseEvent,
|
||||||
): ?{|
|
):
|
||||||
left: boolean,
|
| {
|
||||||
right: boolean,
|
left: boolean;
|
||||||
top: boolean,
|
right: boolean;
|
||||||
bottom: boolean,
|
top: boolean;
|
||||||
|} {
|
bottom: boolean;
|
||||||
|
}
|
||||||
|
| undefined {
|
||||||
const canResize = this.getResizable();
|
const canResize = this.getResizable();
|
||||||
if (!canResize) {
|
if (!canResize) {
|
||||||
return;
|
return;
|
||||||
@@ -546,7 +554,7 @@ export default class Interactive extends React.Component<
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
calculateResizable(event: SyntheticMouseEvent<>) {
|
calculateResizable(event: MouseEvent) {
|
||||||
const resizing = this.checkIfResizable(event);
|
const resizing = this.checkIfResizable(event);
|
||||||
if (!resizing) {
|
if (!resizing) {
|
||||||
return;
|
return;
|
||||||
@@ -629,7 +637,7 @@ export default class Interactive extends React.Component<
|
|||||||
|
|
||||||
const {onCanResize} = this.props;
|
const {onCanResize} = this.props;
|
||||||
if (onCanResize) {
|
if (onCanResize) {
|
||||||
onCanResize();
|
onCanResize({});
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
@@ -648,16 +656,16 @@ export default class Interactive extends React.Component<
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
onLocalMouseMove = (event: SyntheticMouseEvent<>) => {
|
onLocalMouseMove = (event: React.MouseEvent) => {
|
||||||
if (!this.globalMouse) {
|
if (!this.globalMouse) {
|
||||||
this.onMouseMove(event);
|
this.onMouseMove(event.nativeEvent);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {grow, height, left, movable, top, width, zIndex} = this.props;
|
const {grow, height, left, movable, top, width, zIndex} = this.props;
|
||||||
|
|
||||||
const style: Object = {
|
const style: React.CSSProperties = {
|
||||||
cursor: this.state.cursor,
|
cursor: this.state.cursor,
|
||||||
zIndex: zIndex == null ? 'auto' : zIndex,
|
zIndex: zIndex == null ? 'auto' : zIndex,
|
||||||
};
|
};
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
* @format
|
* @format
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import Interactive from './Interactive.js';
|
import Interactive from './Interactive';
|
||||||
import FlexColumn from './FlexColumn.js';
|
import FlexColumn from './FlexColumn.js';
|
||||||
import {colors} from './colors';
|
import {colors} from './colors';
|
||||||
import {Component} from 'react';
|
import {Component} from 'react';
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import type {
|
|||||||
import {normaliseColumnWidth, isPercentage} from './utils.js';
|
import {normaliseColumnWidth, isPercentage} from './utils.js';
|
||||||
import {PureComponent} from 'react';
|
import {PureComponent} from 'react';
|
||||||
import ContextMenu from '../ContextMenu.js';
|
import ContextMenu from '../ContextMenu.js';
|
||||||
import Interactive from '../Interactive.js';
|
import Interactive from '../Interactive.tsx';
|
||||||
import styled from '../../styled/index.js';
|
import styled from '../../styled/index.js';
|
||||||
import {colors} from '../colors.tsx';
|
import {colors} from '../colors.tsx';
|
||||||
|
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ export {default as ErrorBoundary} from './components/ErrorBoundary.js';
|
|||||||
|
|
||||||
// interactive components
|
// interactive components
|
||||||
export type {OrderableOrder} from './components/Orderable.tsx';
|
export type {OrderableOrder} from './components/Orderable.tsx';
|
||||||
export {default as Interactive} from './components/Interactive.js';
|
export {default as Interactive} from './components/Interactive.tsx';
|
||||||
export {default as Orderable} from './components/Orderable.tsx';
|
export {default as Orderable} from './components/Orderable.tsx';
|
||||||
export {default as VirtualList} from './components/VirtualList.tsx';
|
export {default as VirtualList} from './components/VirtualList.tsx';
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user