Interactive

Summary: _typescript_

Reviewed By: passy

Differential Revision: D16830548

fbshipit-source-id: d0530ef3491af95bece7fba610a4b1cf19c80bd1
This commit is contained in:
Daniel Büchele
2019-08-20 03:18:32 -07:00
committed by Facebook Github Bot
parent e00db4f6d3
commit 28a295bcf1
4 changed files with 97 additions and 89 deletions

View File

@@ -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,
}; };

View File

@@ -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';

View File

@@ -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';

View File

@@ -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';