Remove core example

This commit is contained in:
Steve Ruiz 2021-10-29 15:01:09 +01:00
parent b6f2e2940f
commit 742f9421d6
4 changed files with 0 additions and 450 deletions

View file

@ -1,138 +0,0 @@
/* eslint-disable @typescript-eslint/no-non-null-assertion */
/* refresh-reset */
import * as React from 'react'
import { TLShape, Utils, TLBounds, TLShapeUtil, HTMLContainer, SVGContainer } from '@tldraw/core'
// Define a custom shape
export interface BoxShape extends TLShape {
type: 'box'
size: number[]
text: string
}
export const boxShape: BoxShape = {
id: 'example1',
type: 'box',
parentId: 'page',
childIndex: 0,
name: 'Example Shape',
point: [0, 0],
size: [100, 100],
rotation: 0,
text: 'Hello world!',
}
// Create a "shape utility" class that interprets that shape
export class BoxUtil extends TLShapeUtil<BoxShape, HTMLDivElement> {
age = 100
Component = TLShapeUtil.Component<BoxShape, HTMLDivElement>(
({ shape, events, onShapeChange, isEditing, meta }, ref) => {
const color = meta.isDarkMode ? 'white' : 'black'
const rInput = React.useRef<HTMLDivElement>(null)
function updateShapeSize() {
const elm = rInput.current!
onShapeChange?.({
...shape,
text: elm.innerText,
size: [elm.offsetWidth + 44, elm.offsetHeight + 44],
})
}
React.useLayoutEffect(() => {
const elm = rInput.current!
const observer = new MutationObserver(updateShapeSize)
observer.observe(elm, {
attributes: true,
characterData: true,
subtree: true,
})
elm.innerText = shape.text
updateShapeSize()
return () => {
observer.disconnect()
}
}, [])
React.useEffect(() => {
if (isEditing) {
rInput.current!.focus()
}
}, [isEditing])
return (
<HTMLContainer ref={ref}>
<div
{...events}
style={{
pointerEvents: 'all',
width: shape.size[0],
height: shape.size[1],
display: 'flex',
fontSize: 20,
fontFamily: 'sans-serif',
alignItems: 'center',
justifyContent: 'center',
border: `2px solid ${color}`,
color,
}}
>
<div onPointerDown={(e) => isEditing && e.stopPropagation()}>
<div
ref={rInput}
style={{
whiteSpace: 'nowrap',
overflow: 'hidden',
textAlign: 'center',
outline: 'none',
userSelect: isEditing ? 'all' : 'none',
}}
contentEditable={isEditing}
/>
</div>
</div>
</HTMLContainer>
)
}
)
Indicator = TLShapeUtil.Indicator<BoxShape>(({ shape }) => {
return (
<SVGContainer>
<rect
fill="none"
stroke="blue"
strokeWidth={1}
width={shape.size[0]}
height={shape.size[1]}
pointerEvents="none"
/>
</SVGContainer>
)
})
getBounds = (shape: BoxShape) => {
const bounds = Utils.getFromCache(this.boundsCache, shape, () => {
const [width, height] = shape.size
return {
minX: 0,
maxX: width,
minY: 0,
maxY: height,
width,
height,
} as TLBounds
})
return Utils.translateBounds(bounds, shape.point)
}
}

View file

@ -1,35 +0,0 @@
import * as React from 'react'
import { Renderer, TLShapeUtilsMap } from '@tldraw/core'
import { BoxShape, BoxUtil } from './box'
import { LabelUtil, LabelShape } from './label'
import { appState } from './state'
const shapeUtils: TLShapeUtilsMap<BoxShape | LabelShape> = {
box: new BoxUtil(),
label: new LabelUtil(),
}
export default function Core() {
const page = appState.useStore((s) => s.page)
const pageState = appState.useStore((s) => s.pageState)
const meta = appState.useStore((s) => s.meta)
return (
<div className="tldraw">
<Renderer
shapeUtils={shapeUtils}
page={page}
pageState={pageState}
meta={meta}
onDoubleClickBounds={appState.onDoubleClickBounds}
onDoubleClickShape={appState.onDoubleClickShape}
onPointShape={appState.onPointShape}
onPointCanvas={appState.onPointCanvas}
onPointerDown={appState.onPointerDown}
onPointerMove={appState.onPointerMove}
onPointerUp={appState.onPointerUp}
onShapeChange={appState.onShapeChange}
/>
</div>
)
}

View file

@ -1,124 +0,0 @@
/* eslint-disable @typescript-eslint/no-non-null-assertion */
/* refresh-reset */
import * as React from 'react'
import {
TLShape,
Utils,
TLBounds,
HTMLContainer,
TLComponent,
TLShapeUtil,
TLIndicator,
} from '@tldraw/core'
import { appState } from './state'
// Define a custom shape
export interface LabelShape extends TLShape {
type: 'label'
text: string
}
// Create a "shape utility" class that interprets that shape
export class LabelUtil extends TLShapeUtil<LabelShape, HTMLDivElement> {
type = 'label' as const
isStateful = true
Component: TLComponent<LabelShape, HTMLDivElement> = (
{ shape, events, isSelected, onShapeChange, meta },
ref
) => {
const color = meta.isDarkMode ? 'white' : 'black'
const bounds = this.getBounds(shape)
const rInput = React.useRef<HTMLDivElement>(null)
function updateShapeSize() {
const elm = rInput.current!
appState.changeShapeText(shape.id, elm.innerText)
onShapeChange?.({
id: shape.id,
text: elm.innerText,
})
}
React.useLayoutEffect(() => {
const elm = rInput.current!
elm.innerText = shape.text
updateShapeSize()
const observer = new MutationObserver(updateShapeSize)
observer.observe(elm, {
attributes: true,
characterData: true,
subtree: true,
})
}, [])
return (
<HTMLContainer>
<div
{...events}
style={{
width: bounds.width,
height: bounds.height,
pointerEvents: 'all',
display: 'flex',
fontSize: 20,
fontFamily: 'sans-serif',
alignItems: 'center',
justifyContent: 'center',
border: `2px solid ${color}`,
color,
}}
>
<div ref={ref} onPointerDown={(e) => isSelected && e.stopPropagation()}>
<div
ref={rInput}
style={{
whiteSpace: 'nowrap',
overflow: 'hidden',
textAlign: 'center',
outline: 'none',
userSelect: isSelected ? 'all' : 'none',
}}
contentEditable={isSelected}
/>
</div>
</div>
</HTMLContainer>
)
}
Indicator: TLIndicator<LabelShape> = ({ shape }) => {
const bounds = this.getBounds(shape)
return (
<rect
fill="none"
stroke="blue"
strokeWidth={1}
width={bounds.width}
height={bounds.height}
pointerEvents="none"
/>
)
}
getBounds = (shape: LabelShape) => {
const bounds = Utils.getFromCache(this.boundsCache, shape, () => {
const ref = this.getRef(shape)
const width = ref.current?.offsetWidth || 0
const height = ref.current?.offsetHeight || 0
return {
minX: 0,
maxX: width,
minY: 0,
maxY: height,
width,
height,
} as TLBounds
})
return Utils.translateBounds(bounds, shape.point)
}
}

View file

@ -1,153 +0,0 @@
import type {
TLBinding,
TLPage,
TLPageState,
TLPointerEventHandler,
TLShapeChangeHandler,
} from '@tldraw/core'
import type { BoxShape } from './box'
import type { LabelShape } from './label'
import { StateManager } from 'rko'
type Shapes = BoxShape | LabelShape
interface State {
page: TLPage<Shapes, TLBinding>
pageState: TLPageState
meta: {
isDarkMode: boolean
}
}
class AppState extends StateManager<State> {
/* ----------------------- API ---------------------- */
selectShape(shapeId: string) {
this.patchState({
pageState: {
selectedIds: [shapeId],
},
})
}
deselect() {
this.patchState({
pageState: {
selectedIds: [],
editingId: undefined,
},
})
}
startEditingShape(shapeId: string) {
this.patchState({
pageState: {
selectedIds: [shapeId],
editingId: shapeId,
},
})
}
changeShapeText = (id: string, text: string) => {
this.patchState({
page: {
shapes: {
[id]: { text },
},
},
})
}
/* --------------------- Events --------------------- */
onPointCanvas: TLPointerEventHandler = (info) => {
this.deselect()
}
onPointShape: TLPointerEventHandler = (info) => {
this.selectShape(info.target)
}
onDoubleClickShape: TLPointerEventHandler = (info) => {
this.startEditingShape(info.target)
}
onDoubleClickBounds: TLPointerEventHandler = (info) => {
// Todo
}
onPointerDown: TLPointerEventHandler = (info) => {
// Todo
}
onPointerUp: TLPointerEventHandler = (info) => {
// Todo
}
onPointerMove: TLPointerEventHandler = (info) => {
// Todo
}
onShapeChange: TLShapeChangeHandler<Shapes> = (shape) => {
if (shape.type === 'box' && shape.size) {
this.patchState({
page: {
shapes: {
[shape.id]: { ...shape, size: [...shape.size] },
},
},
})
}
}
}
export const appState = new AppState({
page: {
id: 'page1',
shapes: {
rect1: {
id: 'rect1',
parentId: 'page1',
name: 'Rectangle',
childIndex: 1,
type: 'box',
point: [0, 0],
rotation: 0,
size: [100, 100],
text: 'Hello world!',
},
label1: {
id: 'label1',
parentId: 'page1',
name: 'Label',
childIndex: 2,
type: 'label',
point: [-200, -200],
rotation: 0,
text: 'My shape is stateful, I should still render while off screen!',
},
label2: {
id: 'label2',
parentId: 'page1',
name: 'Label',
childIndex: 2,
type: 'label',
point: [200, 200],
rotation: 0,
text: 'Hello world!',
},
},
bindings: {},
},
pageState: {
id: 'page1',
selectedIds: [],
camera: {
point: [0, 0],
zoom: 1,
},
},
meta: {
isDarkMode: false,
},
})