Add definitions for React DnD

Adding React DnD type definitions for React DnD v1.1.4, which is the latest
version.

Paired with @vsiao on parts of this
This commit is contained in:
Eric Pelz
2015-07-29 17:48:37 -07:00
parent dd4d30bbc3
commit d8dc5313d8
2 changed files with 432 additions and 0 deletions
+260
View File
@@ -0,0 +1,260 @@
///<reference path="react-dnd.d.ts" />
"use strict";
// Test adapted from the ReactDnD chess game tutorial:
// http://gaearon.github.io/react-dnd/docs-tutorial.html
import React = require("react");
import ReactDnd = require("react-dnd");
var r = React.DOM;
import DragSource = ReactDnd.DragSource;
import DropTarget = ReactDnd.DropTarget;
import DragDropContext = ReactDnd.DragDropContext;
import HTML5Backend = require('react-dnd/modules/backends/HTML5');
// Game Component
// ----------------------------------------------------------------------
module Game {
var knightPosition = [0, 0];
var observer: any = null;
function emitChange() {
observer(knightPosition);
}
export function observe(o: any) {
if (observer) {
throw new Error("Multiple observers not implemented.");
}
observer = o;
emitChange();
}
export function moveKnight(toX: number, toY: number) {
knightPosition = [toX, toY];
emitChange();
}
export function canMoveKnight(toX: number, toY: number) {
const x = knightPosition[0];
const y = knightPosition[1];
const dx = toX - x;
const dy = toY - y;
return (Math.abs(dx) === 2 && Math.abs(dy) === 1) ||
(Math.abs(dx) === 1 && Math.abs(dy) === 2);
}
}
var ItemTypes = {
KNIGHT: "knight"
};
// Knight Component
// ----------------------------------------------------------------------
module Knight {
interface KnightP extends React.Props<Knight> {
connectDragSource: ReactDnd.ConnectDragSource;
connectDragPreview: ReactDnd.ConnectDragPreview;
isDragging: boolean;
}
var knightSource: ReactDnd.DragSourceSpec<KnightP> = {
beginDrag: (props) => {
return {};
}
};
function knightCollect(connect: ReactDnd.DragSourceConnector, monitor: ReactDnd.DragSourceMonitor) {
return {
connectDragSource: connect.dragSource(),
connectDragPreview: connect.dragPreview(),
isDragging: monitor.isDragging()
};
}
export class Knight extends React.Component<KnightP, {}> {
static create = React.createFactory(Knight);
componentDidMount() {
var img = HTML5Backend.getEmptyImage();
img.onload = () => this.props.connectDragPreview(img);
}
render() {
return this.props.connectDragSource(
r.div({
style: {
opacity: this.props.isDragging ? 0.5 : 1,
fontSize: 25,
fontWeight: 'bold',
cursor: 'move'
}
}, "♘")
);
}
}
export var DndKnight = DragSource(ItemTypes.KNIGHT, knightSource, knightCollect)(Knight);
export var create = React.createFactory(DndKnight);
}
// Square Component
// ----------------------------------------------------------------------
module Square {
interface SquareP extends React.Props<Square> {
black: boolean;
}
export class Square extends React.Component<SquareP, {}> {
render() {
var fill = this.props.black ? 'black' : 'white';
return r.div({
style: {
backgroundColor: fill
}
})
}
}
export var create = React.createFactory(Square);
}
// BoardSquare Component
// ----------------------------------------------------------------------
module BoardSquare {
interface BoardSquareP extends React.Props<BoardSquare> {
x: number;
y: number;
connectDropTarget?: ReactDnd.ConnectDropTarget;
isOver?: boolean;
canDrop?: boolean;
}
var boardSquareTarget: ReactDnd.DropTargetSpec<BoardSquareP> = {
canDrop: (props) => Game.canMoveKnight(props.x, props.y),
drop: (props) => Game.moveKnight(props.x, props.y)
};
function boardSquareCollect(connect: ReactDnd.DropTargetConnector, monitor: ReactDnd.DropTargetMonitor) {
return {
connectDropTarget: connect.dropTarget(),
isOver: monitor.isOver(),
canDrop: monitor.canDrop()
};
}
export class BoardSquare extends React.Component<BoardSquareP, {}> {
private _renderOverlay = (color: string) => {
return r.div({
style: {
position: 'absolute',
top: 0,
left: 0,
height: '100%',
width: '100%',
zIndex: 1,
opacity: 0.5,
backgroundColor: color
}
});
};
render() {
var black = (this.props.x + this.props.y) % 2 === 1;
var isOver = this.props.isOver;
var canDrop = this.props.canDrop;
return this.props.connectDropTarget(
r.div({
style: {
position: 'relative',
width: '100%',
height: '100%'
},
children: [
Square.create({
black: black
}),
isOver && !canDrop ? this._renderOverlay('red') : null,
!isOver && canDrop ? this._renderOverlay('yellow') : null,
isOver && canDrop ? this._renderOverlay('green') : null
]
})
);
}
}
export var DndBoardSquare = DropTarget(ItemTypes.KNIGHT, boardSquareTarget, boardSquareCollect)(BoardSquare);
export var create = React.createFactory(DndBoardSquare);
}
// Board Component
// ----------------------------------------------------------------------
module Board {
interface BoardP extends React.Props<Board> {
knightPosition: number[];
}
export class Board extends React.Component<BoardP, {}> {
private _renderPiece = (x: number, y: number) => {
var knightX = this.props.knightPosition[0];
var knightY = this.props.knightPosition[1];
return x === knightX && y === knightY ?
Knight.create() :
null;
};
private _renderSquare = (i: number) => {
var x = i % 8;
var y = Math.floor(i / 8);
return r.div({
key: i,
style: {
width: '12.5%',
height: '12.5%'
}
}, BoardSquare.create({
x: x,
y: y
}, this._renderPiece(x, y)));
};
render() {
var squares: React.DOMElement<React.HTMLAttributes>[] = [];
for (let i = 0; i < 64; i++) {
squares.push(this._renderSquare(i));
}
return r.div({
style: {
width: '100%',
height: '100%',
display: 'flex',
flexWrap: 'wrap'
},
children: squares
});
}
}
var DndBoard = DragDropContext(HTML5Backend)(Board);
export var create = React.createFactory(DndBoard);
}
// Render the Board Component
// ----------------------------------------------------------------------
Board.create({
knightPosition: [0, 0]
});
+172
View File
@@ -0,0 +1,172 @@
// Type definitions for React DnD v1.1.4
// Project: https://github.com/gaearon/react-dnd
// Definitions by: Asana <https://asana.com>
// Definitions: https://github.com/borisyankov/DefinitelyTyped
///<reference path='../react/react.d.ts' />
declare module __ReactDnd {
import React = __React;
// Decorated React Components
// ----------------------------------------------------------------------
class ContextComponent<P, S> extends React.Component<P, S> {
getDecoratedComponentInstance(): React.Component<P, S>;
// Note: getManager is not yet documented on the React DnD docs.
getManager(): any;
}
class DndComponent<P, S> extends React.Component<P, S> {
getDecoratedComponentInstance(): React.Component<P, S>;
getHandlerId(): Identifier;
}
interface ContextComponentClass<P> extends React.ComponentClass<P> {
new(props?: P, context?: any): ContextComponent<P, any>;
DecoratedComponent: React.ComponentClass<P>;
}
interface DndComponentClass<P> extends React.ComponentClass<P> {
new(props?: P, context?: any): DndComponent<P, any>;
DecoratedComponent: React.ComponentClass<P>;
}
// Top-level API
// ----------------------------------------------------------------------
export function DragSource<P>(
type: Identifier | ((props: P) => Identifier),
spec: DragSourceSpec<P>,
collect: (connect: DragSourceConnector, monitor: DragSourceMonitor) => Object,
options?: DndOptions<P>
): (componentClass: React.ComponentClass<P>) => DndComponentClass<P>;
export function DropTarget<P>(
types: Identifier | Identifier[] | ((props: P) => Identifier | Identifier[]),
spec: DropTargetSpec<P>,
collect: (connect: DropTargetConnector, monitor: DropTargetMonitor) => Object,
options?: DndOptions<P>
): (componentClass: React.ComponentClass<P>) => DndComponentClass<P>;
export function DragDropContext<P>(
backend: Backend
): (componentClass: React.ComponentClass<P>) => ContextComponentClass<P>;
// TODO: Add exported function for DragLayer.
// The React DnD docs say that this is an advanced feature that is only
// necessary when performing custom rendering or when using a custom
// backend.
// Shared
// ----------------------------------------------------------------------
// The React DnD docs say that this can also be the ES6 Symbol.
type Identifier = string;
interface ClientOffset {
x: number;
y: number;
}
interface DndOptions<P> {
arePropsEqual?(props: P, otherProps: P): boolean;
}
// DragSource
// ----------------------------------------------------------------------
interface DragSourceSpec<P> {
beginDrag(props: P, monitor?: DragSourceMonitor, component?: React.Component<P, any>): Object;
endDrag?(props: P, monitor?: DragSourceMonitor, component?: React.Component<P, any>): void;
canDrag?(props: P, monitor?: DragSourceMonitor): boolean;
isDragging?(props: P, monitor?: DragSourceMonitor): boolean;
}
class DragSourceMonitor {
canDrag(): boolean;
isDragging(): boolean;
getItemType(): Identifier;
getItem(): Object;
getDropResult(): Object;
didDrop(): boolean;
getInitialClientOffset(): ClientOffset;
getInitialSourceClientOffset(): ClientOffset;
getClientOffset(): ClientOffset;
getDifferenceFromInitialOffset(): ClientOffset;
getSourceClientOffset(): ClientOffset;
}
class DragSourceConnector {
dragSource(): ConnectDragSource;
dragPreview(): ConnectDragPreview;
}
interface DragElementWrapper<O> {
<P>(elementOrNode: React.ReactElement<P>, options?: O): React.ReactElement<P>;
}
interface DragSourceOptions {
dropEffect?: string;
}
interface DragPreviewOptions {
captureDraggingState?: boolean;
anchorX?: number;
anchorY?: number;
}
type ConnectDragSource = DragElementWrapper<DragSourceOptions>;
type ConnectDragPreview = DragElementWrapper<DragPreviewOptions>;
/// DropTarget
// ----------------------------------------------------------------------
interface DropTargetSpec<P> {
drop?(props: P, monitor?: DropTargetMonitor, component?: React.Component<P, any>): Object|void;
hover?(props: P, monitor?: DropTargetMonitor, component?: React.Component<P, any>): void;
canDrop?(props: P, monitor?: DropTargetMonitor): boolean;
}
class DropTargetMonitor {
canDrop(): boolean;
isOver(options?: { shallow: boolean }): boolean;
getItemType(): Identifier;
getItem(): Object;
getDropResult(): Object;
didDrop(): boolean;
getInitialClientOffset(): ClientOffset;
getInitialSourceClientOffset(): ClientOffset;
getClientOffset(): ClientOffset;
getDifferenceFromInitialOffset(): ClientOffset;
getSourceClientOffset(): ClientOffset;
}
class DropTargetConnector {
dropTarget(): ConnectDropTarget;
}
type ConnectDropTarget = <P>(elementOrNode: React.ReactElement<P>) => React.ReactElement<P>;
/// Backend
/// ---------------------------------------------------------------------
// TODO: Fill in the Backend interface.
// The React DnD docs do not cover this, and this is only needed for
// creating custom backends (i.e. not using the built-in HTML5Backend).
interface Backend {}
}
declare module "react-dnd" {
export = __ReactDnd;
}
declare module "react-dnd/modules/backends/HTML5" {
enum _NativeTypes { FILE, URL, TEXT }
class HTML5Backend implements __ReactDnd.Backend {
static getEmptyImage(): any; // Image
static NativeTypes: _NativeTypes;
}
export = HTML5Backend;
}