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

Add experimental hook-based examples #1256

Merged
merged 16 commits into from
Mar 8, 2019
Merged
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: 1 addition & 0 deletions packages/documentation/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"react": "link:../react-dnd/node_modules/react",
"react-dnd": "^7.2.1",
"react-dnd-documentation-examples": "^7.2.1",
"react-dnd-documentation-examples-hooks": "^7.2.1",
"react-dnd-html5-backend": "^7.2.0",
"react-dnd-test-backend": "^7.2.0",
"react-dom": "link:../react-dnd/node_modules/react-dom",
Expand Down
29 changes: 22 additions & 7 deletions packages/documentation/src/components/header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,32 @@ import NavBar from './navbar'

export interface HeaderProps {
debugMode?: boolean
experimentalMode?: boolean
}

const DebugModeFlag = () => (
<a className="github-fork-ribbon" data-ribbon="Debug Mode" title="Debug Mode">
Debug Mode
</a>
)
const DebugModeFlag = ({ debugMode, experimentalMode }: any) => {
if (!debugMode && !experimentalMode) {
return null
}

let text = ''
if (debugMode && experimentalMode) {
text = 'Dbg Experimental.'
} else if (debugMode) {
text = 'Debug'
} else if (experimentalMode) {
text = 'Experimental'
}
return (
<a className="github-fork-ribbon" data-ribbon={text} title={text}>
{text}
</a>
)
}

const Header: React.FC<HeaderProps> = ({ debugMode }) => (
const Header: React.FC<HeaderProps> = ({ debugMode, experimentalMode }) => (
<Container>
{debugMode ? <DebugModeFlag /> : null}
<DebugModeFlag debugMode={debugMode} experimentalMode={experimentalMode} />
<NavBar />
</Container>
)
Expand Down
4 changes: 3 additions & 1 deletion packages/documentation/src/components/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { PageGroup } from '../constants'
import { APIPages, ExamplePages } from '../constants'
import Header from './header'
import './layout.css'
import { isExperimentalApiMode } from '../util/renderHtmlAst'
require('prismjs/themes/prism.css')
const favicon = require('../favicon.png')

Expand All @@ -31,6 +32,7 @@ const Layout: React.FC<LayoutProps> = props => {
const sidebarItems: PageGroup[] = isExampleUrl ? ExamplePages : APIPages
const hideSidebar = props.hideSidebar || sitepath === '/about'
const debugMode = isDebugMode()
const experimentalMode = isExperimentalApiMode()
return (
<>
<Helmet
Expand All @@ -47,7 +49,7 @@ const Layout: React.FC<LayoutProps> = props => {
href="https://cdnjs.cloudflare.com/ajax/libs/github-fork-ribbon-css/0.2.2/gh-fork-ribbon.min.css"
/>
</Helmet>
<Header debugMode={debugMode} />
<Header debugMode={debugMode} experimentalMode={experimentalMode} />
<DragDropContextProvider backend={HTML5Backend} debugMode={debugMode}>
<ContentContainer>
<PageBody hasSidebar={sitepath !== '/about'}>
Expand Down
15 changes: 14 additions & 1 deletion packages/documentation/src/util/renderHtmlAst.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,27 @@
declare var require: any
import { createElement } from 'react'
import { componentIndex } from 'react-dnd-documentation-examples/lib/esm/index'
import { componentIndex as hookComponentIndex } from 'react-dnd-documentation-examples-hooks/lib/esm/index'
import { parse } from 'query-string'
import processImages from './processImagesInMarkdownAst'
const log = require('debug')('site:renderHtmlAst')
const rehypeReact = require('rehype-react')

export function isExperimentalApiMode() {
if (typeof window !== 'undefined') {
const queryObject = parse(window.location.search)
return queryObject.experimental !== undefined
} else {
return false
}
}

// Registers the examples as custom components
const renderAst = new rehypeReact({
createElement,
components: componentIndex,
components: {
...(isExperimentalApiMode() ? hookComponentIndex : componentIndex),
},
}).Compiler

export default function renderHtmlAst(node: any) {
Expand Down
2 changes: 1 addition & 1 deletion packages/examples-hooks/src/00 Chessboard/Board.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react'
import * as React from 'react'
import { BoardSquare } from './BoardSquare'
import { Knight } from './Knight'

Expand Down
4 changes: 2 additions & 2 deletions packages/examples-hooks/src/00 Chessboard/BoardSquare.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useRef } from 'react'
import * as React from 'react'
import { __EXPERIMENTAL_DND_HOOKS_THAT_MAY_CHANGE_AND_BREAK_MY_BUILD__ } from 'react-dnd'
import { Square } from './Square'
import { canMoveKnight, moveKnight } from './Game'
Expand All @@ -17,7 +17,7 @@ export interface BoardSquareProps {
export const BoardSquare: React.FC<BoardSquareProps> = (
props: BoardSquareProps,
) => {
const ref = useRef(null)
const ref = React.useRef(null)
const { isOver, canDrop } = useDrop({
ref,
type: ItemTypes.KNIGHT,
Expand Down
9 changes: 4 additions & 5 deletions packages/examples-hooks/src/00 Chessboard/Knight.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useRef, useMemo } from 'react'
import * as React from 'react'
import { __EXPERIMENTAL_DND_HOOKS_THAT_MAY_CHANGE_AND_BREAK_MY_BUILD__ } from 'react-dnd'
import ItemTypes from './ItemTypes'
import knightImage from './knightImage'
Expand All @@ -23,13 +23,12 @@ function createKnightImage() {
}

export const Knight: React.FC = () => {
const ref = useRef(null)
const dragPreview = useMemo(createKnightImage, [])
const ref = React.useRef(null)
const dragPreview = React.useMemo(createKnightImage, [])
const { isDragging } = useDrag({
ref,
type: ItemTypes.KNIGHT,
begin: () => ({}),
dragPreview,
preview: dragPreview,
collect: mon => ({
isDragging: !!mon.isDragging(),
}),
Expand Down
2 changes: 1 addition & 1 deletion packages/examples-hooks/src/00 Chessboard/Overlay.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react'
import * as React from 'react'

export interface OverlayProps {
color: string
Expand Down
2 changes: 1 addition & 1 deletion packages/examples-hooks/src/00 Chessboard/Square.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react'
import * as React from 'react'

export interface SquareProps {
black: boolean
Expand Down
15 changes: 10 additions & 5 deletions packages/examples-hooks/src/00 Chessboard/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useEffect, useState } from 'react'
import * as React from 'react'
import Board from './Board'
import { observe } from './Game'

Expand All @@ -16,13 +16,18 @@ const containerStyle: React.CSSProperties = {
* The Chessboard Tutorial Application
*/
const ChessboardTutorialApp: React.FC = () => {
const [knightPos, setKnightPos] = useState<[number, number]>([1, 7])
const [knightPos, setKnightPos] = React.useState<[number, number]>([1, 7])

// the observe function will return an unsubscribe callback
useEffect(() => observe((newPos: [number, number]) => setKnightPos(newPos)))
React.useEffect(() =>
observe((newPos: [number, number]) => setKnightPos(newPos)),
)
return (
<div style={containerStyle}>
<Board knightPosition={knightPos} />
<div>
<h1>EXPERIMENTAL API</h1>
<div style={containerStyle}>
<Board knightPosition={knightPos} />
</div>
</div>
)
}
Expand Down
106 changes: 46 additions & 60 deletions packages/examples-hooks/src/01 Dustbin/Copy or Move/Box.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import React from 'react'
import {
DragSource,
ConnectDragSource,
DragSourceConnector,
DragSourceMonitor,
} from 'react-dnd'
import * as React from 'react'
import ItemTypes from '../Single Target/ItemTypes'
import { __EXPERIMENTAL_DND_HOOKS_THAT_MAY_CHANGE_AND_BREAK_MY_BUILD__ } from 'react-dnd'
const {
useDrag,
} = __EXPERIMENTAL_DND_HOOKS_THAT_MAY_CHANGE_AND_BREAK_MY_BUILD__

const style: React.CSSProperties = {
border: '1px dashed gray',
Expand All @@ -16,61 +14,49 @@ const style: React.CSSProperties = {
float: 'left',
}

const boxSource = {
beginDrag(props: BoxProps) {
return {
name: props.name,
}
},

endDrag(props: BoxProps, monitor: DragSourceMonitor) {
const item = monitor.getItem()
const dropResult = monitor.getDropResult()

if (dropResult) {
let alertMessage = ''
const isDropAllowed =
dropResult.allowedDropEffect === 'any' ||
dropResult.allowedDropEffect === dropResult.dropEffect

if (isDropAllowed) {
const isCopyAction = dropResult.dropEffect === 'copy'
const actionName = isCopyAction ? 'copied' : 'moved'
alertMessage = `You ${actionName} ${item.name} into ${dropResult.name}!`
} else {
alertMessage = `You cannot ${dropResult.dropEffect} an item into the ${
dropResult.name
}`
}
alert(alertMessage)
}
},
}

export interface BoxProps {
name: string
}

interface BoxCollectedProps {
isDragging: boolean
connectDragSource: ConnectDragSource
}

class Box extends React.Component<BoxProps & BoxCollectedProps> {
public render() {
const { isDragging, connectDragSource } = this.props
const { name } = this.props
const opacity = isDragging ? 0.4 : 1

return connectDragSource(<div style={{ ...style, opacity }}>{name}</div>)
}
const Box: React.FC<BoxProps> = ({ name }) => {
const ref = React.useRef(null)
const { opacity } = useDrag({
ref,
type: ItemTypes.BOX,
begin: () => ({ name }),
end(monitor) {
const item = monitor.getItem()
const dropResult = monitor.getDropResult()

if (dropResult) {
let alertMessage = ''
const isDropAllowed =
dropResult.allowedDropEffect === 'any' ||
dropResult.allowedDropEffect === dropResult.dropEffect

if (isDropAllowed) {
const isCopyAction = dropResult.dropEffect === 'copy'
const actionName = isCopyAction ? 'copied' : 'moved'
alertMessage = `You ${actionName} ${item.name} into ${
dropResult.name
}!`
} else {
alertMessage = `You cannot ${
dropResult.dropEffect
} an item into the ${dropResult.name}`
}
alert(alertMessage)
}
},
collect: monitor => ({
opacity: monitor.isDragging() ? 0.4 : 1,
}),
})

return (
<div ref={ref} style={{ ...style, opacity }}>
{name}
</div>
)
}

export default DragSource(
ItemTypes.BOX,
boxSource,
(connect: DragSourceConnector, monitor: DragSourceMonitor) => ({
connectDragSource: connect.dragSource(),
isDragging: monitor.isDragging(),
}),
)(Box)
export default Box
Loading