Improves types and imports!

pull/67/head
Steve Ruiz 2021-08-13 10:28:09 +01:00
rodzic edc29dfbcf
commit 8c02e0df84
147 zmienionych plików z 1268 dodań i 1800 usunięć

Wyświetl plik

@ -18,7 +18,7 @@
"main": "./dist/cjs/index.js",
"types": "./dist/types/index.d.ts",
"scripts": {
"dev": "node scripts/dev & tsc --watch --incremental --emitDeclarationOnly --outDir dist/types",
"dev": "node scripts/dev & tsc --watch --incremental --emitDeclarationOnly --declarationMap --outDir dist/types",
"build": "yarn clean && node scripts/build && tsc --emitDeclarationOnly --outDir dist/types",
"lint": "eslint src/ --ext .ts,.tsx",
"clean": "rm -rf dist",
@ -26,6 +26,7 @@
"docs": "typedoc --entryPoints src/index.ts"
},
"devDependencies": {
"@types/jest": "^27.0.1",
"@types/node": "^15.0.1",
"@types/react": "^17.0.16",
"@types/react-dom": "^17.0.9",

Wyświetl plik

@ -1,4 +1,4 @@
import type { TLBinding } from '@tldraw/core/src/types'
import type { TLBinding } from '~types'
interface BindingProps {
point: number[]

Wyświetl plik

@ -1,7 +1,7 @@
import * as React from 'react'
import type { TLBounds } from '../../../types'
import { Utils } from '../../../utils'
import { useBoundsEvents } from '../../hooks/useBoundsEvents'
import type { TLBounds } from '~types'
import { Utils } from '~utils'
import { useBoundsEvents } from '~hooks'
interface BoundsBgProps {
bounds: TLBounds

Wyświetl plik

@ -1,6 +1,6 @@
import * as React from 'react'
import { TLBoundsEdge, TLBoundsCorner, TLBounds } from '../../../types'
import { Utils } from '../../../utils'
import { TLBoundsEdge, TLBoundsCorner, TLBounds } from '~types'
import { Utils } from '~utils'
import { CenterHandle } from './center-handle'
import { RotateHandle } from './rotate-handle'
import { CornerHandle } from './corner-handle'

Wyświetl plik

@ -0,0 +1,20 @@
import * as React from 'react'
import type { TLBounds } from '~types'
export interface CenterHandleProps {
bounds: TLBounds
isLocked: boolean
}
export const CenterHandle = React.memo(({ bounds, isLocked }: CenterHandleProps): JSX.Element => {
return (
<rect
className={isLocked ? 'tl-bounds-center tl-dashed' : 'tl-bounds-center'}
x={-1}
y={-1}
width={bounds.width + 2}
height={bounds.height + 2}
pointerEvents="none"
/>
)
})

Wyświetl plik

@ -1,6 +1,6 @@
import * as React from 'react'
import { useBoundsHandleEvents } from '../../hooks'
import { TLBoundsCorner, TLBounds } from '../../../types'
import { useBoundsHandleEvents } from '~hooks'
import { TLBoundsCorner, TLBounds } from '~types'
const cornerBgClassnames = {
[TLBoundsCorner.TopLeft]: 'tl-transparent tl-cursor-nwse',

Wyświetl plik

@ -1,6 +1,6 @@
import * as React from 'react'
import { useBoundsHandleEvents } from '../../hooks'
import { TLBoundsEdge, TLBounds } from '../../../types'
import { useBoundsHandleEvents } from '~hooks'
import { TLBoundsEdge, TLBounds } from '~types'
const edgeClassnames = {
[TLBoundsEdge.Top]: 'tl-transparent tl-cursor-ns',

Wyświetl plik

@ -1,6 +1,6 @@
import * as React from 'react'
import { useBoundsHandleEvents } from '../../hooks'
import type { TLBounds } from '../../../types'
import { useBoundsHandleEvents } from '~hooks'
import type { TLBounds } from '~types'
export const RotateHandle = React.memo(
({ bounds, size }: { bounds: TLBounds; size: number }): JSX.Element => {

Wyświetl plik

@ -1,5 +1,5 @@
import * as React from 'react'
import type { TLBounds } from '../../../types'
import type { TLBounds } from '~types'
export class BrushUpdater {
ref = React.createRef<SVGRectElement>()

Wyświetl plik

@ -1,5 +1,4 @@
import * as React from 'react'
import { TLBounds } from '../../../types'
import { BrushUpdater } from './BrushUpdater'
export const brushUpdater = new BrushUpdater()

Wyświetl plik

@ -1,13 +1,17 @@
import * as React from 'react'
import { ErrorBoundary } from 'react-error-boundary'
import { useZoomEvents, useSafariFocusOutFix, useCanvasEvents, useCameraCss } from '../hooks'
import {
usePreventNavigation,
useZoomEvents,
useSafariFocusOutFix,
useCanvasEvents,
useCameraCss,
} from '~hooks'
import type { TLBinding, TLPage, TLPageState, TLShape } from '~types'
import { ErrorFallback } from './error-fallback'
import type { TLBinding, TLPage, TLPageState, TLShape } from '../../types'
import { Brush } from './brush'
import { Defs } from './defs'
import { Page } from './page'
import { usePreventNavigation } from '../hooks/usePreventNavigation'
function resetError() {
void null

Wyświetl plik

@ -1,5 +1,5 @@
import * as React from 'react'
import { useHandleEvents } from '../../hooks'
import { useHandleEvents } from '~hooks'
interface HandleProps {
id: string

Wyświetl plik

@ -0,0 +1,35 @@
import * as React from 'react'
import { Vec } from '~utils'
import type { TLShape } from '~types'
import { useTLContext } from '~hooks'
import { Handle } from './handle'
interface HandlesProps {
shape: TLShape
zoom: number
}
const toAngle = 180 / Math.PI
export const Handles = React.memo(({ shape, zoom }: HandlesProps): JSX.Element | null => {
const { shapeUtils } = useTLContext()
const center = shapeUtils[shape.type].getCenter(shape)
if (shape.handles === undefined) {
return null
}
return (
<g transform={`rotate(${(shape.rotation || 0) * toAngle},${center})`}>
{Object.values(shape.handles).map((handle) => (
<Handle
key={shape.id + '_' + handle.id}
id={handle.id}
point={Vec.add(handle.point, shape.point)}
zoom={zoom}
/>
))}
</g>
)
})

Wyświetl plik

@ -0,0 +1,2 @@
export * from './renderer'
export { brushUpdater } from './brush'

Wyświetl plik

@ -1,8 +1,7 @@
import * as React from 'react'
import { useShapeTree } from '../hooks/useShapeTree'
import type { IShapeTreeNode, TLBinding, TLPage, TLPageState, TLShape } from '../../types'
import type { IShapeTreeNode, TLBinding, TLPage, TLPageState, TLShape } from '~types'
import { Shape as ShapeComponent } from './shape'
import { useHandles, useRenderOnResize, useTLContext } from '../hooks'
import { useShapeTree, useHandles, useRenderOnResize, useTLContext } from '../hooks'
import { Bounds } from './bounds'
import { BoundsBg } from './bounds/bounds-bg'
import { useSelection } from '../hooks'

Wyświetl plik

@ -10,9 +10,8 @@ import type {
TLBounds,
TLBinding,
} from '../types'
import { Canvas } from './components/canvas'
import { useTLTheme } from './hooks/useStyle'
import { TLContext } from './hooks/useTLContext'
import { Canvas } from '../components/canvas'
import { useTLTheme, TLContext } from '../hooks'
export interface RendererProps<T extends TLShape>
extends Partial<TLSettings>,

Wyświetl plik

@ -1,6 +1,6 @@
import { useTLContext } from '../../hooks'
import { useTLContext } from '~hooks'
import * as React from 'react'
import type { TLShapeUtil, TLRenderInfo, TLShape } from '../../../types'
import type { TLShapeUtil, TLRenderInfo, TLShape } from '~types'
interface EditingShapeProps<T extends TLShape> extends TLRenderInfo {
shape: T
@ -16,13 +16,7 @@ export function EditingTextShape({
isCurrentParent,
}: EditingShapeProps<TLShape>) {
const {
callbacks: {
onTextChange,
onTextBlur,
onTextFocus,
onTextKeyDown,
onTextKeyUp,
},
callbacks: { onTextChange, onTextBlur, onTextFocus, onTextKeyDown, onTextKeyUp },
} = useTLContext()
const ref = React.useRef<HTMLElement>(null)

Wyświetl plik

@ -1,5 +1,5 @@
import * as React from 'react'
import type { TLShapeUtil, TLRenderInfo, TLShape } from '../../../types'
import type { TLShapeUtil, TLRenderInfo, TLShape } from '~types'
interface RenderedShapeProps<T extends TLShape> extends TLRenderInfo {
shape: T

Wyświetl plik

@ -1,17 +1,11 @@
import * as React from 'react'
import { useShapeEvents, useTLContext } from '../../hooks'
import type { IShapeTreeNode } from '../../../types'
import { useShapeEvents, useTLContext } from '~hooks'
import type { IShapeTreeNode } from '~types'
import { RenderedShape } from './rendered-shape'
import { EditingTextShape } from './editing-text-shape'
export const Shape = React.memo(
({
shape,
isEditing,
isBinding,
isDarkMode,
isCurrentParent,
}: IShapeTreeNode) => {
({ shape, isEditing, isBinding, isDarkMode, isCurrentParent }: IShapeTreeNode) => {
const { shapeUtils } = useTLContext()
const events = useShapeEvents(shape.id, isCurrentParent)
const utils = shapeUtils[shape.type]
@ -22,11 +16,7 @@ export const Shape = React.memo(
return (
<g
className={
isCurrentParent
? 'tl-shape-group tl-current-parent'
: 'tl-shape-group'
}
className={isCurrentParent ? 'tl-shape-group tl-current-parent' : 'tl-shape-group'}
id={shape.id}
transform={transform}
{...events}

Wyświetl plik

@ -12,3 +12,5 @@ export * from './useRenderOnResize'
export * from './useSelection'
export * from './useHandleEvents'
export * from './useHandles'
export * from './usePreventNavigation'
export * from './useBoundsEvents'

Wyświetl plik

@ -1,5 +1,5 @@
import * as React from 'react'
import { inputs } from '../../inputs'
import { inputs } from '~inputs'
import { useTLContext } from './useTLContext'
export function useBoundsEvents() {

Wyświetl plik

@ -1,11 +1,9 @@
import * as React from 'react'
import { inputs } from '../../inputs'
import type { TLBoundsEdge, TLBoundsCorner } from '../../types'
import { inputs } from '~inputs'
import type { TLBoundsEdge, TLBoundsCorner } from '~types'
import { useTLContext } from './useTLContext'
export function useBoundsHandleEvents(
id: TLBoundsCorner | TLBoundsEdge | 'rotate'
) {
export function useBoundsHandleEvents(id: TLBoundsCorner | TLBoundsEdge | 'rotate') {
const { callbacks } = useTLContext()
const onPointerDown = React.useCallback(

Wyświetl plik

@ -1,15 +1,12 @@
import * as React from 'react'
import type { TLPageState } from '../../types'
import type { TLPageState } from '~types'
export function useCameraCss(pageState: TLPageState) {
const rGroup = React.useRef<SVGGElement>(null)
// Update the tl-zoom CSS variable when the zoom changes
React.useEffect(() => {
document.documentElement.style.setProperty(
'--tl-zoom',
pageState.camera.zoom.toString()
)
document.documentElement.style.setProperty('--tl-zoom', pageState.camera.zoom.toString())
}, [pageState.camera.zoom])
// Update the group's position when the camera moves or zooms
@ -18,10 +15,7 @@ export function useCameraCss(pageState: TLPageState) {
zoom,
point: [x = 0, y = 0],
} = pageState.camera
rGroup.current?.setAttribute(
'transform',
`scale(${zoom}) translate(${x} ${y})`
)
rGroup.current?.setAttribute('transform', `scale(${zoom}) translate(${x} ${y})`)
}, [pageState.camera])
return rGroup

Wyświetl plik

@ -1,6 +1,6 @@
import * as React from 'react'
import { useTLContext } from './useTLContext'
import { inputs } from '../../inputs'
import { inputs } from '~inputs'
export function useCanvasEvents() {
const { callbacks } = useTLContext()

Wyświetl plik

@ -1,5 +1,5 @@
import * as React from 'react'
import { inputs } from '../../inputs'
import { inputs } from '~inputs'
import { useTLContext } from './useTLContext'
export function useHandleEvents(id: string) {

Wyświetl plik

@ -1,4 +1,4 @@
import type { TLBinding, TLPage, TLPageState, TLShape } from '../../types'
import type { TLBinding, TLPage, TLPageState, TLShape } from '~types'
export function useHandles<T extends TLShape>(page: TLPage<T, TLBinding>, pageState: TLPageState) {
const { selectedIds } = pageState

Wyświetl plik

@ -1,8 +1,8 @@
import * as React from 'react'
import Utils from '../../utils'
import Utils from '~utils'
export function useRenderOnResize() {
const forceUpdate = React.useReducer(x => x + 1, 0)[1]
const forceUpdate = React.useReducer((x) => x + 1, 0)[1]
React.useEffect(() => {
const debouncedUpdate = Utils.debounce(forceUpdate, 96)

Wyświetl plik

@ -1,5 +1,5 @@
import Utils from '../../utils'
import { useEffect } from 'react'
import Utils from '~utils'
import { useTLContext } from './useTLContext'
// Send event on iOS when a user presses the "Done" key while editing a text element.

Wyświetl plik

@ -1,6 +1,6 @@
import type { TLPage, TLPageState, TLShape, TLBounds, TLShapeUtils, TLBinding } from '../../types'
import Utils from '../../utils'
import { useTLContext } from '../hooks/useTLContext'
import type { TLPage, TLPageState, TLShape, TLBounds, TLShapeUtils, TLBinding } from '~types'
import Utils from '~utils'
import { useTLContext } from '~hooks'
function canvasToScreen(point: number[], camera: TLPageState['camera']): number[] {
return [(point[0] + camera.point[0]) * camera.zoom, (point[1] + camera.point[1]) * camera.zoom]

Wyświetl plik

@ -1,7 +1,7 @@
import * as React from 'react'
import { inputs } from '../../inputs'
import { inputs } from '~inputs'
import { useTLContext } from './useTLContext'
import { Utils } from '../../utils'
import { Utils } from '~utils'
export function useShapeEvents(id: string, disable = false) {
const { rPageState, rScreenBounds, callbacks } = useTLContext()

Wyświetl plik

@ -7,8 +7,8 @@ import type {
TLShapeUtils,
TLCallbacks,
TLBinding,
} from '../../types'
import Utils, { Vec } from '../../utils'
} from '~types'
import { Utils, Vec } from '~utils'
function addToShapeTree<T extends TLShape>(
shape: TLShape,

Wyświetl plik

@ -1,5 +1,5 @@
import * as React from 'react'
import type { TLTheme } from '../../types'
import type { TLTheme } from '~types'
const styles = new Map<string, HTMLStyleElement>()

Wyświetl plik

@ -1,11 +1,5 @@
import * as React from 'react'
import type {
TLCallbacks,
TLShape,
TLBounds,
TLPageState,
TLShapeUtils,
} from '../../types'
import type { TLCallbacks, TLShape, TLBounds, TLPageState, TLShapeUtils } from '~types'
export interface TLContextType {
callbacks: Partial<TLCallbacks>

Wyświetl plik

@ -1,9 +1,9 @@
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
import { useRef } from 'react'
import { useTLContext } from './useTLContext'
import { Vec } from '../../utils'
import { Vec } from '~utils'
import { useWheel, usePinch } from 'react-use-gesture'
import { inputs } from '../../inputs'
import { inputs } from '~inputs'
// Capture zoom gestures (pinches, wheels and pans)
export function useZoomEvents() {
@ -54,8 +54,10 @@ export function useZoomEvents() {
rOriginPoint.current = origin
}
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const [distanceDelta] = Vec.sub(rPinchDa.current!, da)
if (!rPinchDa.current) throw Error('No pinch direction!')
if (!rOriginPoint.current) throw Error('No origin point!')
const [distanceDelta] = Vec.sub(rPinchDa.current, da)
const info = inputs.pinch(rPinchPoint.current, origin)
@ -63,7 +65,7 @@ export function useZoomEvents() {
{
...info,
point: origin,
origin: rOriginPoint.current!,
origin: rOriginPoint.current,
delta: [...info.delta, distanceDelta],
},
e as React.WheelEvent<Element> | WheelEvent | React.TouchEvent<Element> | TouchEvent

Wyświetl plik

@ -1,4 +1,4 @@
export * from './renderer'
export * from './components'
export * from './types'
export * from './utils'
export * from './inputs'

Wyświetl plik

@ -11,10 +11,7 @@ class Inputs {
pointerUpTime = 0
touchStart<T extends string>(
e: TouchEvent | React.TouchEvent,
target: T
): TLPointerInfo<T> {
touchStart<T extends string>(e: TouchEvent | React.TouchEvent, target: T): TLPointerInfo<T> {
const { shiftKey, ctrlKey, metaKey, altKey } = e
e.preventDefault()
@ -38,10 +35,7 @@ class Inputs {
return info
}
touchMove<T extends string>(
e: TouchEvent | React.TouchEvent,
target: T
): TLPointerInfo<T> {
touchMove<T extends string>(e: TouchEvent | React.TouchEvent, target: T): TLPointerInfo<T> {
const { shiftKey, ctrlKey, metaKey, altKey } = e
e.preventDefault()
@ -72,10 +66,7 @@ class Inputs {
return info
}
pointerDown<T extends string>(
e: PointerEvent | React.PointerEvent,
target: T
): TLPointerInfo<T> {
pointerDown<T extends string>(e: PointerEvent | React.PointerEvent, target: T): TLPointerInfo<T> {
const { shiftKey, ctrlKey, metaKey, altKey } = e
const point = Inputs.getPoint(e)
@ -124,10 +115,7 @@ class Inputs {
return info
}
pointerMove<T extends string>(
e: PointerEvent | React.PointerEvent,
target: T
): TLPointerInfo<T> {
pointerMove<T extends string>(e: PointerEvent | React.PointerEvent, target: T): TLPointerInfo<T> {
const { shiftKey, ctrlKey, metaKey, altKey } = e
const prev = this.pointer
@ -155,10 +143,7 @@ class Inputs {
return info
}
pointerUp<T extends string>(
e: PointerEvent | React.PointerEvent,
target: T
): TLPointerInfo<T> {
pointerUp<T extends string>(e: PointerEvent | React.PointerEvent, target: T): TLPointerInfo<T> {
const { shiftKey, ctrlKey, metaKey, altKey } = e
const prev = this.pointer
@ -236,22 +221,12 @@ class Inputs {
return info
}
canAccept = (_pointerId: PointerEvent['pointerId']): boolean => {
return true
// return (
// this.activePointerId === undefined || this.activePointerId === pointerId
// )
}
isDoubleClick() {
if (!this.pointer) return false
const { origin, point } = this.pointer
return (
Date.now() - this.pointerUpTime < DOUBLE_CLICK_DURATION &&
Vec.dist(origin, point) < 4
)
return Date.now() - this.pointerUpTime < DOUBLE_CLICK_DURATION && Vec.dist(origin, point) < 4
}
clear() {
@ -334,9 +309,7 @@ class Inputs {
return [Number(e.clientX.toPrecision(5)), Number(e.clientY.toPrecision(5))]
}
static getPressure(
e: PointerEvent | React.PointerEvent | Touch | React.Touch | WheelEvent
) {
static getPressure(e: PointerEvent | React.PointerEvent | Touch | React.Touch | WheelEvent) {
return 'pressure' in e ? Number(e.pressure.toPrecision(5)) || 0.5 : 0.5
}

Wyświetl plik

@ -1,22 +0,0 @@
import * as React from 'react'
import type { TLBounds } from '../../../types'
export interface CenterHandleProps {
bounds: TLBounds
isLocked: boolean
}
export const CenterHandle = React.memo(
({ bounds, isLocked }: CenterHandleProps): JSX.Element => {
return (
<rect
className={isLocked ? 'tl-bounds-center tl-dashed' : 'tl-bounds-center'}
x={-1}
y={-1}
width={bounds.width + 2}
height={bounds.height + 2}
pointerEvents="none"
/>
)
}
)

Wyświetl plik

@ -1,37 +0,0 @@
import * as React from 'react'
import { Vec } from '../../../utils'
import type { TLShape } from '../../../types'
import { useTLContext } from '../../hooks'
import { Handle } from './handle'
interface HandlesProps {
shape: TLShape
zoom: number
}
const toAngle = 180 / Math.PI
export const Handles = React.memo(
({ shape, zoom }: HandlesProps): JSX.Element | null => {
const { shapeUtils } = useTLContext()
const center = shapeUtils[shape.type].getCenter(shape)
if (shape.handles === undefined) {
return null
}
return (
<g transform={`rotate(${(shape.rotation || 0) * toAngle},${center})`}>
{Object.values(shape.handles).map((handle) => (
<Handle
key={shape.id + '_' + handle.id}
id={handle.id}
point={Vec.add(handle.point, shape.point)}
zoom={zoom}
/>
))}
</g>
)
}
)

Wyświetl plik

@ -1,2 +0,0 @@
export * from './renderer'
export { brushUpdater } from './components/brush'

Wyświetl plik

@ -1,12 +1,7 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import * as React from 'react'
import {
TLShapeUtil,
TLShape,
TLBounds,
TLRenderInfo,
TLTransformInfo,
} from '../types'
import Utils, { Intersect } from '../utils'
import { TLShapeUtil, TLShape, TLBounds, TLRenderInfo, TLTransformInfo } from '~types'
import Utils, { Intersect } from '~utils'
export class ExampleShape extends TLShapeUtil<TLShape> {
type = 'shape-type'
@ -49,9 +44,7 @@ export class ExampleShape extends TLShapeUtil<TLShape> {
}
getRotatedBounds(shape: TLShape) {
return Utils.getBoundsFromPoints(
Utils.getRotatedCorners(this.getBounds(shape), shape.rotation)
)
return Utils.getBoundsFromPoints(Utils.getRotatedCorners(this.getBounds(shape), shape.rotation))
}
getCenter(shape: TLShape): number[] {
@ -63,10 +56,7 @@ export class ExampleShape extends TLShapeUtil<TLShape> {
}
hitTestBounds(shape: TLShape, bounds: TLBounds) {
const rotatedCorners = Utils.getRotatedCorners(
this.getBounds(shape),
shape.rotation
)
const rotatedCorners = Utils.getRotatedCorners(this.getBounds(shape), shape.rotation)
return (
rotatedCorners.every((point) => Utils.pointInBounds(point, bounds)) ||
@ -74,19 +64,11 @@ export class ExampleShape extends TLShapeUtil<TLShape> {
)
}
transform(
shape: TLShape,
bounds: TLBounds,
_info: TLTransformInfo<TLShape>
): TLShape {
transform(shape: TLShape, bounds: TLBounds, _info: TLTransformInfo<TLShape>): TLShape {
return { ...shape, point: [bounds.minX, bounds.minY] }
}
transformSingle(
shape: TLShape,
bounds: TLBounds,
info: TLTransformInfo<TLShape>
): TLShape {
transformSingle(shape: TLShape, bounds: TLBounds, info: TLTransformInfo<TLShape>): TLShape {
return this.transform(shape, bounds, info)
}
}

Wyświetl plik

@ -1,257 +0,0 @@
/// <reference types="react" />
export interface TLPage<T extends TLShape> {
id: string;
name?: string;
childIndex?: number;
shapes: Record<string, T>;
bindings: Record<string, TLBinding>;
backgroundColor?: string;
}
export interface TLPageState {
id: string;
brush?: TLBounds;
pointedId?: string;
hoveredId?: string;
editingId?: string;
bindingId?: string;
boundsRotation?: number;
currentParentId?: string;
selectedIds: string[];
camera: {
point: number[];
zoom: number;
};
}
export interface TLHandle {
id: string;
index: number;
point: number[];
canBind?: boolean;
bindingId?: string;
}
export interface TLShape {
id: string;
type: string;
parentId: string;
childIndex: number;
name: string;
point: number[];
rotation?: number;
children?: string[];
handles?: Record<string, TLHandle>;
isLocked?: boolean;
isHidden?: boolean;
isEditing?: boolean;
isGenerated?: boolean;
isAspectRatioLocked?: boolean;
}
export declare type TLShapeUtils<T extends TLShape> = Record<string, TLShapeUtil<T>>;
export interface TLRenderInfo<T extends SVGElement | HTMLElement = any> {
isEditing: boolean;
isBinding: boolean;
isDarkMode: boolean;
isCurrentParent: boolean;
ref?: React.RefObject<T>;
onTextChange?: TLCallbacks['onTextChange'];
onTextBlur?: TLCallbacks['onTextBlur'];
onTextFocus?: TLCallbacks['onTextFocus'];
onTextKeyDown?: TLCallbacks['onTextKeyDown'];
onTextKeyUp?: TLCallbacks['onTextKeyUp'];
}
export interface TLTool {
id: string;
name: string;
}
export interface TLBinding {
id: string;
type: string;
toId: string;
fromId: string;
}
export interface TLSettings {
isDebugMode: boolean;
isDarkMode: boolean;
isPenMode: boolean;
}
export interface TLTheme {
brushFill?: string;
brushStroke?: string;
selectFill?: string;
selectStroke?: string;
background?: string;
foreground?: string;
}
export declare type TLWheelEventHandler = (info: TLPointerInfo<string>, e: React.WheelEvent<Element> | WheelEvent) => void;
export declare type TLPinchEventHandler = (info: TLPointerInfo<string>, e: React.WheelEvent<Element> | WheelEvent | React.TouchEvent<Element> | TouchEvent) => void;
export declare type TLPointerEventHandler = (info: TLPointerInfo<string>, e: React.PointerEvent) => void;
export declare type TLCanvasEventHandler = (info: TLPointerInfo<'canvas'>, e: React.PointerEvent) => void;
export declare type TLBoundsEventHandler = (info: TLPointerInfo<'bounds'>, e: React.PointerEvent) => void;
export declare type TLBoundsHandleEventHandler = (info: TLPointerInfo<TLBoundsCorner | TLBoundsEdge | 'rotate'>, e: React.PointerEvent) => void;
export interface TLCallbacks {
onChange: (ids: string[]) => void;
onPinchStart: TLPinchEventHandler;
onPinchEnd: TLPinchEventHandler;
onPinch: TLPinchEventHandler;
onPan: TLWheelEventHandler;
onZoom: TLWheelEventHandler;
onPointerMove: TLPointerEventHandler;
onPointerUp: TLPointerEventHandler;
onPointerDown: TLPointerEventHandler;
onPointCanvas: TLCanvasEventHandler;
onDoubleClickCanvas: TLCanvasEventHandler;
onRightPointCanvas: TLCanvasEventHandler;
onDragCanvas: TLCanvasEventHandler;
onReleaseCanvas: TLCanvasEventHandler;
onPointShape: TLPointerEventHandler;
onDoubleClickShape: TLPointerEventHandler;
onRightPointShape: TLPointerEventHandler;
onDragShape: TLPointerEventHandler;
onHoverShape: TLPointerEventHandler;
onUnhoverShape: TLPointerEventHandler;
onReleaseShape: TLPointerEventHandler;
onPointBounds: TLBoundsEventHandler;
onDoubleClickBounds: TLBoundsEventHandler;
onRightPointBounds: TLBoundsEventHandler;
onDragBounds: TLBoundsEventHandler;
onHoverBounds: TLBoundsEventHandler;
onUnhoverBounds: TLBoundsEventHandler;
onReleaseBounds: TLBoundsEventHandler;
onPointBoundsHandle: TLBoundsHandleEventHandler;
onDoubleClickBoundsHandle: TLBoundsHandleEventHandler;
onRightPointBoundsHandle: TLBoundsHandleEventHandler;
onDragBoundsHandle: TLBoundsHandleEventHandler;
onHoverBoundsHandle: TLBoundsHandleEventHandler;
onUnhoverBoundsHandle: TLBoundsHandleEventHandler;
onReleaseBoundsHandle: TLBoundsHandleEventHandler;
onPointHandle: TLPointerEventHandler;
onDoubleClickHandle: TLPointerEventHandler;
onRightPointHandle: TLPointerEventHandler;
onDragHandle: TLPointerEventHandler;
onHoverHandle: TLPointerEventHandler;
onUnhoverHandle: TLPointerEventHandler;
onReleaseHandle: TLPointerEventHandler;
onTextChange: (id: string, text: string) => void;
onTextBlur: (id: string) => void;
onTextFocus: (id: string) => void;
onTextKeyDown: (id: string, key: string) => void;
onTextKeyUp: (id: string, key: string) => void;
onBlurEditingShape: () => void;
onError: (error: Error) => void;
}
export interface TLBounds {
minX: number;
minY: number;
maxX: number;
maxY: number;
width: number;
height: number;
rotation?: number;
}
export declare type TLIntersection = {
didIntersect: boolean;
message: string;
points: number[][];
};
export declare enum TLBoundsEdge {
Top = "top_edge",
Right = "right_edge",
Bottom = "bottom_edge",
Left = "left_edge"
}
export declare enum TLBoundsCorner {
TopLeft = "top_left_corner",
TopRight = "top_right_corner",
BottomRight = "bottom_right_corner",
BottomLeft = "bottom_left_corner"
}
export interface TLPointerInfo<T extends string = string> {
target: T;
pointerId: number;
origin: number[];
point: number[];
delta: number[];
pressure: number;
shiftKey: boolean;
ctrlKey: boolean;
metaKey: boolean;
altKey: boolean;
}
export interface TLKeyboardInfo {
origin: number[];
point: number[];
key: string;
keys: string[];
shiftKey: boolean;
ctrlKey: boolean;
metaKey: boolean;
altKey: boolean;
}
export interface TLTransformInfo<T extends TLShape> {
type: TLBoundsEdge | TLBoundsCorner;
initialShape: T;
scaleX: number;
scaleY: number;
transformOrigin: number[];
}
export interface TLBezierCurveSegment {
start: number[];
tangentStart: number[];
normalStart: number[];
pressureStart: number;
end: number[];
tangentEnd: number[];
normalEnd: number[];
pressureEnd: number;
}
export declare abstract class TLShapeUtil<T extends TLShape> {
boundsCache: WeakMap<TLShape, TLBounds>;
isEditableText: boolean;
isAspectRatioLocked: boolean;
canEdit: boolean;
canBind: boolean;
abstract type: T['type'];
abstract defaultProps: T;
abstract render(shape: T, info: TLRenderInfo): JSX.Element;
abstract renderIndicator(shape: T): JSX.Element | null;
abstract getBounds(shape: T): TLBounds;
abstract getRotatedBounds(shape: T): TLBounds;
abstract hitTest(shape: T, point: number[]): boolean;
abstract hitTestBounds(shape: T, bounds: TLBounds): boolean;
abstract transform(shape: T, bounds: TLBounds, info: TLTransformInfo<T>): Partial<T>;
transformSingle(shape: T, bounds: TLBounds, info: TLTransformInfo<T>): Partial<T>;
shouldRender(_prev: T, _next: T): boolean;
shouldDelete(_shape: T): boolean;
getCenter(shape: T): number[];
getBindingPoint(shape: T, point: number[], origin: number[], direction: number[], padding: number, anywhere: boolean): {
point: number[];
distance: number;
} | undefined;
create(props: Partial<T>): T;
mutate(shape: T, props: Partial<T>): T;
updateChildren<K extends TLShape>(_shape: T, _children: K[]): Partial<K>[] | void;
onChildrenChange(_shape: T, _children: TLShape[]): Partial<T> | void;
onBindingChange(_shape: T, _binding: TLBinding, _target: TLShape, _targetBounds: TLBounds, _center: number[]): Partial<T> | void;
onHandleChange(_shape: T, _handle: Partial<T['handles']>, _info: Partial<TLPointerInfo>): Partial<T> | void;
onRightPointHandle(_shape: T, _handle: Partial<T['handles']>, _info: Partial<TLPointerInfo>): Partial<T> | void;
onDoubleClickHandle(_shape: T, _handle: Partial<T['handles']>, _info: Partial<TLPointerInfo>): Partial<T> | void;
onSessionComplete(_shape: T): Partial<T> | void;
onBoundsReset(_shape: T): Partial<T> | void;
onStyleChange(_shape: T): Partial<T> | void;
}
export interface IShapeTreeNode {
shape: TLShape;
children?: IShapeTreeNode[];
isEditing: boolean;
isBinding: boolean;
isDarkMode: boolean;
isCurrentParent: boolean;
}
export declare type MappedByType<T extends {
type: string;
}> = {
[P in T['type']]: T extends any ? (P extends T['type'] ? T : never) : never;
};
export declare type RequiredKeys<T> = {
[K in keyof T]-?: Record<string, unknown> extends Pick<T, K> ? never : K;
}[keyof T];
export {};

Wyświetl plik

@ -1,3 +1,5 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
/* eslint-disable @typescript-eslint/no-explicit-any */
/* --------------------- Primary -------------------- */
export interface TLPage<T extends TLShape, B extends TLBinding> {
@ -316,57 +318,57 @@ export abstract class TLShapeUtil<T extends TLShape> {
return { ...shape, ...props }
}
updateChildren<K extends TLShape>(_shape: T, _children: K[]): Partial<K>[] | void {
updateChildren<K extends TLShape>(shape: T, children: K[]): Partial<K>[] | void {
return
}
onChildrenChange(_shape: T, _children: TLShape[]): Partial<T> | void {
onChildrenChange(shape: T, children: TLShape[]): Partial<T> | void {
return
}
onBindingChange(
_shape: T,
_binding: TLBinding,
_target: TLShape,
_targetBounds: TLBounds,
_center: number[]
shape: T,
binding: TLBinding,
target: TLShape,
targetBounds: TLBounds,
center: number[]
): Partial<T> | void {
return undefined
}
onHandleChange(
_shape: T,
_handle: Partial<T['handles']>,
_info: Partial<TLPointerInfo>
shape: T,
handle: Partial<T['handles']>,
info: Partial<TLPointerInfo>
): Partial<T> | void {
return
}
onRightPointHandle(
_shape: T,
_handle: Partial<T['handles']>,
_info: Partial<TLPointerInfo>
shape: T,
handle: Partial<T['handles']>,
info: Partial<TLPointerInfo>
): Partial<T> | void {
return
}
onDoubleClickHandle(
_shape: T,
_handle: Partial<T['handles']>,
_info: Partial<TLPointerInfo>
shape: T,
handle: Partial<T['handles']>,
info: Partial<TLPointerInfo>
): Partial<T> | void {
return
}
onSessionComplete(_shape: T): Partial<T> | void {
onSessionComplete(shape: T): Partial<T> | void {
return
}
onBoundsReset(_shape: T): Partial<T> | void {
onBoundsReset(shape: T): Partial<T> | void {
return
}
onStyleChange(_shape: T): Partial<T> | void {
onStyleChange(shape: T): Partial<T> | void {
return
}
}
@ -394,5 +396,3 @@ export type MappedByType<T extends { type: string }> = {
export type RequiredKeys<T> = {
[K in keyof T]-?: Record<string, unknown> extends Pick<T, K> ? never : K
}[keyof T]
export {}

Wyświetl plik

@ -1,5 +1,4 @@
import { Utils } from './utils'
export { Intersect } from './intersect'
export { Utils } from './utils'
export { Svg } from './svg'

Wyświetl plik

@ -559,13 +559,21 @@ export class Intersect {
// Get an intersection between an ellipse and a second ellipse.
// Adapted from https://gist.github.com/drawable/92792f59b6ff8869d8b1
ellipse(
// eslint-disable-next-line @typescript-eslint/no-unused-vars
_c1: number[],
// eslint-disable-next-line @typescript-eslint/no-unused-vars
_rx1: number,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
_ry1: number,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
_r1: number,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
_c2: number[],
// eslint-disable-next-line @typescript-eslint/no-unused-vars
_rx2: number,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
_ry2: number,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
_r2: number
): TLIntersection {
// TODO

Wyświetl plik

@ -9,7 +9,7 @@
*/
if (!String.prototype.replaceAll) {
// @ts-ignore
String.prototype.replaceAll = function(str: string, newStr: string) {
String.prototype.replaceAll = function (str: string, newStr: string) {
// If a regex pattern
if (Object.prototype.toString.call(str).toLowerCase() === '[object regexp]') {
return this.replace(str, newStr)
@ -19,5 +19,3 @@ if (!String.prototype.replaceAll) {
return this.replace(new RegExp(str, 'g'), newStr)
}
}
export {}

Wyświetl plik

@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-extra-semi */
/* eslint-disable @typescript-eslint/ban-types */
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable no-redeclare */
@ -1634,16 +1635,13 @@ left past the initial left edge) then swap points on that axis.
let inThrottle: boolean
let lastResult: ReturnType<T>
return function (this: any): ReturnType<T> {
const args = arguments
const context = this
return function (this: any, ...args: any[]): ReturnType<T> {
if (!inThrottle) {
inThrottle = true
setTimeout(() => (inThrottle = false), limit)
lastResult = func.apply(context, args as any)
lastResult = func.apply(this, ...args)
}
return lastResult

Wyświetl plik

@ -1,12 +1,42 @@
{
"extends": "../../tsconfig.json",
"include": ["src"],
"exclude": ["node_modules", "**/*.test.ts", "dist"],
"compilerOptions": {
"baseUrl": "src",
"allowSyntheticDefaultImports": true,
"declaration": true,
"esModuleInterop": true,
"experimentalDecorators": true,
"forceConsistentCasingInFileNames": true,
"importsNotUsedAsValues": "error",
"incremental": true,
"importHelpers": true,
"moduleResolution": "node",
"noEmit": false,
"noFallthroughCasesInSwitch": true /* Report errors for fallthrough cases in switch statement. */,
"noImplicitAny": true /* Raise error on expressions and declarations with an implied 'any' type. */,
"noImplicitReturns": true /* Report error when not all code paths in function return a value. */,
"noUnusedLocals": false /* Report errors on unused locals. */,
"noUnusedParameters": false /* Report errors on unused parameters. */,
"skipLibCheck": true,
"sourceMap": true,
"strict": false,
"strictFunctionTypes": true /* Enable strict checking of function types. */,
"strictNullChecks": true /* Enable strict null checks. */,
"target": "es5",
"typeRoots": ["node_modules/@types", "node_modules/jest"],
"types": ["node", "jest"],
//
"rootDir": "src",
"jsx": "preserve",
"lib": ["dom", "esnext"],
"module": "esnext",
"outDir": "./dist/types"
"outDir": "./dist/types",
"baseUrl": "src",
"paths": {
"~utils": ["./utils/index.ts"],
"~types": ["./types.ts"],
"~inputs": ["./inputs.ts"],
"~hooks": ["./hooks/index.ts"]
}
}
}

Wyświetl plik

@ -1,6 +1,13 @@
import * as React from 'react'
import { ColorStyle, DashStyle, SizeStyle, TLDrawShapeType, TLDrawState } from '@tldraw/tldraw'
import { TLDraw, TLDrawDocument } from '@tldraw/tldraw'
import {
TLDraw,
TLDrawDocument,
ColorStyle,
DashStyle,
SizeStyle,
TLDrawShapeType,
TLDrawState,
} from '@tldraw/tldraw'
import { usePersistence } from '../hooks/usePersistence'
const initialDoc: TLDrawDocument = {

Wyświetl plik

@ -19,7 +19,7 @@
"types": "./dist/types/index.d.ts",
"typings": "./dist/types/index.d.ts",
"scripts": {
"dev": "node scripts/dev & tsc --watch --incremental --emitDeclarationOnly --outDir dist/types",
"dev": "node scripts/dev & tsc --watch --incremental --emitDeclarationOnly --declarationMap --outDir dist/types",
"build": "yarn clean && node scripts/build && tsc --emitDeclarationOnly --outDir dist/types",
"lint": "eslint src/ --ext .ts,.tsx",
"clean": "rm -rf dist",
@ -28,6 +28,7 @@
},
"devDependencies": {
"@tldraw/core": "*",
"@types/jest": "^27.0.1",
"@types/node": "^15.0.1",
"@types/react": "^17.0.16",
"@types/react-dom": "^17.0.9",

Wyświetl plik

@ -1,9 +1,9 @@
import * as React from 'react'
import { Utils } from '@tldraw/core'
import * as RadixContextMenu from '@radix-ui/react-context-menu'
import styled from '../../styles'
import { useTLDrawContext } from '../../hooks'
import type { Data } from '../../state/state-types'
import styled from '~styles'
import { useTLDrawContext } from '~hooks'
import type { Data } from '~types'
import { Kbd } from '../kbd'
import {
IconWrapper,
@ -17,7 +17,7 @@ import {
ContextMenuRoot,
MenuContent,
} from '../shared'
import { AlignType, DistributeType, StretchType } from '../../types'
import { AlignType, DistributeType, StretchType } from '~types'
import {
ChevronRightIcon,
AlignBottomIcon,
@ -47,176 +47,169 @@ const isDebugModeSelector = (s: Data) => {
}
const hasGroupSelectedSelector = (s: Data) => {
return s.pageState.selectedIds.some(
(id) => s.page.shapes[id].children !== undefined
)
return s.pageState.selectedIds.some((id) => s.page.shapes[id].children !== undefined)
}
interface ContextMenuProps {
children: React.ReactNode
}
export const ContextMenu = React.memo(
({ children }: ContextMenuProps): JSX.Element => {
const { tlstate, useSelector } = useTLDrawContext()
const hasSelection = useSelector(has1SelectedIdsSelector)
const hasTwoOrMore = useSelector(has2SelectedIdsSelector)
const hasThreeOrMore = useSelector(has3SelectedIdsSelector)
const isDebugMode = useSelector(isDebugModeSelector)
const hasGroupSelected = useSelector(hasGroupSelectedSelector)
export const ContextMenu = React.memo(({ children }: ContextMenuProps): JSX.Element => {
const { tlstate, useSelector } = useTLDrawContext()
const hasSelection = useSelector(has1SelectedIdsSelector)
const hasTwoOrMore = useSelector(has2SelectedIdsSelector)
const hasThreeOrMore = useSelector(has3SelectedIdsSelector)
const isDebugMode = useSelector(isDebugModeSelector)
const hasGroupSelected = useSelector(hasGroupSelectedSelector)
const rContent = React.useRef<HTMLDivElement>(null)
const rContent = React.useRef<HTMLDivElement>(null)
const handleFlipHorizontal = React.useCallback(() => {
tlstate.flipHorizontal()
}, [tlstate])
const handleFlipHorizontal = React.useCallback(() => {
tlstate.flipHorizontal()
}, [tlstate])
const handleFlipVertical = React.useCallback(() => {
tlstate.flipVertical()
}, [tlstate])
const handleFlipVertical = React.useCallback(() => {
tlstate.flipVertical()
}, [tlstate])
const handleDuplicate = React.useCallback(() => {
tlstate.duplicate()
}, [tlstate])
const handleDuplicate = React.useCallback(() => {
tlstate.duplicate()
}, [tlstate])
const handleGroup = React.useCallback(() => {
tlstate.group()
}, [tlstate])
const handleGroup = React.useCallback(() => {
tlstate.group()
}, [tlstate])
const handleMoveToBack = React.useCallback(() => {
tlstate.moveToBack()
}, [tlstate])
const handleMoveToBack = React.useCallback(() => {
tlstate.moveToBack()
}, [tlstate])
const handleMoveBackward = React.useCallback(() => {
tlstate.moveBackward()
}, [tlstate])
const handleMoveBackward = React.useCallback(() => {
tlstate.moveBackward()
}, [tlstate])
const handleMoveForward = React.useCallback(() => {
tlstate.moveForward()
}, [tlstate])
const handleMoveForward = React.useCallback(() => {
tlstate.moveForward()
}, [tlstate])
const handleMoveToFront = React.useCallback(() => {
tlstate.moveToFront()
}, [tlstate])
const handleMoveToFront = React.useCallback(() => {
tlstate.moveToFront()
}, [tlstate])
const handleDelete = React.useCallback(() => {
tlstate.delete()
}, [tlstate])
const handleDelete = React.useCallback(() => {
tlstate.delete()
}, [tlstate])
const handleCopyAsJson = React.useCallback(() => {
tlstate.copyAsJson()
}, [tlstate])
const handleCopyAsJson = React.useCallback(() => {
tlstate.copyAsJson()
}, [tlstate])
const handleCopyAsSvg = React.useCallback(() => {
tlstate.copyAsSvg()
}, [tlstate])
const handleCopyAsSvg = React.useCallback(() => {
tlstate.copyAsSvg()
}, [tlstate])
const handleUndo = React.useCallback(() => {
tlstate.undo()
}, [tlstate])
const handleUndo = React.useCallback(() => {
tlstate.undo()
}, [tlstate])
const handleRedo = React.useCallback(() => {
tlstate.redo()
}, [tlstate])
const handleRedo = React.useCallback(() => {
tlstate.redo()
}, [tlstate])
if (Utils.isMobile()) {
return <>{children}</>
}
if (Utils.isMobile()) {
return <>{children}</>
}
return (
<ContextMenuRoot>
<RadixContextMenu.Trigger>{children}</RadixContextMenu.Trigger>
<MenuContent as={RadixContextMenu.Content} ref={rContent}>
{hasSelection ? (
<>
<ContextMenuButton onSelect={handleFlipHorizontal}>
<span>Flip Horizontal</span>
<Kbd variant="menu">H</Kbd>
return (
<ContextMenuRoot>
<RadixContextMenu.Trigger>{children}</RadixContextMenu.Trigger>
<MenuContent as={RadixContextMenu.Content} ref={rContent}>
{hasSelection ? (
<>
<ContextMenuButton onSelect={handleFlipHorizontal}>
<span>Flip Horizontal</span>
<Kbd variant="menu">H</Kbd>
</ContextMenuButton>
<ContextMenuButton onSelect={handleFlipVertical}>
<span>Flip Vertical</span>
<Kbd variant="menu">V</Kbd>
</ContextMenuButton>
<ContextMenuButton onSelect={handleDuplicate}>
<span>Duplicate</span>
<Kbd variant="menu">#D</Kbd>
</ContextMenuButton>
<ContextMenuDivider />
{hasGroupSelected ||
(hasTwoOrMore && (
<>
{hasGroupSelected && (
<ContextMenuButton onSelect={handleGroup}>
<span>Ungroup</span>
<Kbd variant="menu">#G</Kbd>
</ContextMenuButton>
)}
{hasTwoOrMore && (
<ContextMenuButton onSelect={handleGroup}>
<span>Group</span>
<Kbd variant="menu">#G</Kbd>
</ContextMenuButton>
)}
</>
))}
<ContextMenuSubMenu label="Move">
<ContextMenuButton onSelect={handleMoveToFront}>
<span>To Front</span>
<Kbd variant="menu"># ]</Kbd>
</ContextMenuButton>
<ContextMenuButton onSelect={handleFlipVertical}>
<span>Flip Vertical</span>
<Kbd variant="menu">V</Kbd>
<ContextMenuButton onSelect={handleMoveForward}>
<span>Forward</span>
<Kbd variant="menu"># ]</Kbd>
</ContextMenuButton>
<ContextMenuButton onSelect={handleDuplicate}>
<span>Duplicate</span>
<Kbd variant="menu">#D</Kbd>
<ContextMenuButton onSelect={handleMoveBackward}>
<span>Backward</span>
<Kbd variant="menu"># [</Kbd>
</ContextMenuButton>
<ContextMenuDivider />
{hasGroupSelected ||
(hasTwoOrMore && (
<>
{hasGroupSelected && (
<ContextMenuButton onSelect={handleGroup}>
<span>Ungroup</span>
<Kbd variant="menu">#G</Kbd>
</ContextMenuButton>
)}
{hasTwoOrMore && (
<ContextMenuButton onSelect={handleGroup}>
<span>Group</span>
<Kbd variant="menu">#G</Kbd>
</ContextMenuButton>
)}
</>
))}
<ContextMenuSubMenu label="Move">
<ContextMenuButton onSelect={handleMoveToFront}>
<span>To Front</span>
<Kbd variant="menu"># ]</Kbd>
</ContextMenuButton>
<ContextMenuButton onSelect={handleMoveForward}>
<span>Forward</span>
<Kbd variant="menu"># ]</Kbd>
</ContextMenuButton>
<ContextMenuButton onSelect={handleMoveBackward}>
<span>Backward</span>
<Kbd variant="menu"># [</Kbd>
</ContextMenuButton>
<ContextMenuButton onSelect={handleMoveToBack}>
<span>To Back</span>
<Kbd variant="menu"># [</Kbd>
</ContextMenuButton>
</ContextMenuSubMenu>
{hasTwoOrMore && (
<AlignDistributeSubMenu
hasTwoOrMore={hasTwoOrMore}
hasThreeOrMore={hasThreeOrMore}
/>
)}
{/* <MoveToPageMenu /> */}
{isDebugMode && (
<ContextMenuButton onSelect={handleCopyAsJson}>
<span>Copy Data</span>
<Kbd variant="menu"># C</Kbd>
</ContextMenuButton>
)}
<ContextMenuButton onSelect={handleCopyAsSvg}>
<span>Copy to SVG</span>
<ContextMenuButton onSelect={handleMoveToBack}>
<span>To Back</span>
<Kbd variant="menu"># [</Kbd>
</ContextMenuButton>
</ContextMenuSubMenu>
{hasTwoOrMore && (
<AlignDistributeSubMenu hasTwoOrMore={hasTwoOrMore} hasThreeOrMore={hasThreeOrMore} />
)}
{/* <MoveToPageMenu /> */}
{isDebugMode && (
<ContextMenuButton onSelect={handleCopyAsJson}>
<span>Copy Data</span>
<Kbd variant="menu"># C</Kbd>
</ContextMenuButton>
<ContextMenuDivider />
<ContextMenuButton onSelect={handleDelete}>
<span>Delete</span>
<Kbd variant="menu"></Kbd>
</ContextMenuButton>
</>
) : (
<>
<ContextMenuButton onSelect={handleUndo}>
<span>Undo</span>
<Kbd variant="menu"># Z</Kbd>
</ContextMenuButton>
<ContextMenuButton onSelect={handleRedo}>
<span>Redo</span>
<Kbd variant="menu"># Z</Kbd>
</ContextMenuButton>
</>
)}
</MenuContent>
</ContextMenuRoot>
)
}
)
)}
<ContextMenuButton onSelect={handleCopyAsSvg}>
<span>Copy to SVG</span>
<Kbd variant="menu"># C</Kbd>
</ContextMenuButton>
<ContextMenuDivider />
<ContextMenuButton onSelect={handleDelete}>
<span>Delete</span>
<Kbd variant="menu"></Kbd>
</ContextMenuButton>
</>
) : (
<>
<ContextMenuButton onSelect={handleUndo}>
<span>Undo</span>
<Kbd variant="menu"># Z</Kbd>
</ContextMenuButton>
<ContextMenuButton onSelect={handleRedo}>
<span>Redo</span>
<Kbd variant="menu"># Z</Kbd>
</ContextMenuButton>
</>
)}
</MenuContent>
</ContextMenuRoot>
)
})
function AlignDistributeSubMenu({
hasThreeOrMore,

Wyświetl plik

@ -1,4 +0,0 @@
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M12.5 2.49538C12.2239 2.49538 12 2.71923 12 2.99538V5.49559H9.49979C9.22364 5.49559 8.99979 5.71945 8.99979 5.99559C8.99979 6.27173 9.22364 6.49559 9.49979 6.49559H12.5C12.7761 6.49559 13 6.27173 13 5.99559V2.99538C13 2.71923 12.7761 2.49538 12.5 2.49538Z" fill="black"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.69698 2.04877C6.62345 1.89773 5.52991 2.09968 4.58113 2.62417C3.63236 3.14867 2.87973 3.9673 2.43667 4.95673C1.99361 5.94616 1.8841 7.05278 2.12465 8.10985C2.3652 9.16693 2.94278 10.1172 3.77036 10.8175C4.59794 11.5177 5.63069 11.9301 6.713 11.9924C7.79531 12.0547 8.86855 11.7635 9.77101 11.1628C10.6735 10.5621 11.3563 9.68441 11.7165 8.66191C11.8083 8.40146 11.6715 8.11593 11.4111 8.02417C11.1506 7.93241 10.8651 8.06916 10.7733 8.32961C10.4851 9.14762 9.93888 9.84981 9.21691 10.3304C8.49493 10.811 7.63632 11.0439 6.77046 10.994C5.9046 10.9442 5.07839 10.6143 4.41631 10.0541C3.75424 9.49386 3.29217 8.73363 3.09972 7.88796C2.90728 7.04229 2.99488 6.15698 3.34934 5.36542C3.7038 4.57387 4.30591 3.91895 5.06494 3.49935C5.82398 3.07974 6.69882 2.91819 7.55765 3.03902C8.41649 3.15985 9.21279 3.55653 9.82658 4.16928L9.83745 4.17981L12.1576 6.35996C12.3588 6.54906 12.6753 6.53921 12.8644 6.33797C13.0535 6.13673 13.0436 5.8203 12.8424 5.63121L10.5276 3.4561C9.76111 2.69329 8.76794 2.19945 7.69698 2.04877Z" fill="black"/>
</svg>

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 1.5 KiB

Wyświetl plik

@ -1,6 +0,0 @@
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M2 4.65555C2 4.37941 2.22386 4.15555 2.5 4.15555H12.2C12.4761 4.15555 12.7 4.37941 12.7 4.65555C12.7 4.93169 12.4761 5.15555 12.2 5.15555H2.5C2.22386 5.15555 2 4.93169 2 4.65555Z" fill="black"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M6.27208 3C6.11885 3 5.97189 3.06087 5.86353 3.16923C5.75518 3.27758 5.6943 3.42454 5.6943 3.57778V4.15556H9.00542V3.57778C9.00542 3.42454 8.94454 3.27758 8.83619 3.16923C8.72783 3.06087 8.58087 3 8.42764 3H6.27208ZM10.0054 4.15556V3.57778C10.0054 3.15933 9.83919 2.75801 9.54329 2.46212C9.2474 2.16623 8.84609 2 8.42764 2H6.27208C5.85363 2 5.45232 2.16623 5.15642 2.46212C4.86053 2.75801 4.6943 3.15933 4.6943 3.57778V4.15556H3.57764C3.30149 4.15556 3.07764 4.37941 3.07764 4.65556V12.2C3.07764 12.6185 3.24387 13.0198 3.53976 13.3157C3.83565 13.6115 4.23696 13.7778 4.65541 13.7778H10.0443C10.4628 13.7778 10.8641 13.6115 11.16 13.3157C11.4559 13.0198 11.6221 12.6185 11.6221 12.2V4.65556C11.6221 4.37941 11.3982 4.15556 11.1221 4.15556H10.0054ZM4.07764 5.15556V12.2C4.07764 12.3532 4.13851 12.5002 4.24686 12.6086C4.35522 12.7169 4.50218 12.7778 4.65541 12.7778H10.0443C10.1975 12.7778 10.3445 12.7169 10.4529 12.6086C10.5612 12.5002 10.6221 12.3532 10.6221 12.2V5.15556H4.07764Z" fill="black"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M6.27246 6.85001C6.5486 6.85001 6.77246 7.07386 6.77246 7.35001V10.5833C6.77246 10.8595 6.5486 11.0833 6.27246 11.0833C5.99632 11.0833 5.77246 10.8595 5.77246 10.5833V7.35001C5.77246 7.07386 5.99632 6.85001 6.27246 6.85001Z" fill="black"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.42773 6.85001C8.70388 6.85001 8.92773 7.07386 8.92773 7.35001V10.5833C8.92773 10.8595 8.70388 11.0833 8.42773 11.0833C8.15159 11.0833 7.92773 10.8595 7.92773 10.5833V7.35001C7.92773 7.07386 8.15159 6.85001 8.42773 6.85001Z" fill="black"/>
</svg>

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 1.9 KiB

Wyświetl plik

@ -1,4 +0,0 @@
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M2.5 2.49538C2.77614 2.49538 3 2.71923 3 2.99538V5.49559H5.50021C5.77636 5.49559 6.00021 5.71945 6.00021 5.99559C6.00021 6.27173 5.77636 6.49559 5.50021 6.49559H2.5C2.22386 6.49559 2 6.27173 2 5.99559V2.99538C2 2.71923 2.22386 2.49538 2.5 2.49538Z" fill="black"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.30302 2.04877C8.37655 1.89773 9.47009 2.09968 10.4189 2.62417C11.3676 3.14867 12.1203 3.9673 12.5633 4.95673C13.0064 5.94616 13.1159 7.05278 12.8753 8.10985C12.6348 9.16693 12.0572 10.1172 11.2296 10.8175C10.4021 11.5177 9.36931 11.9301 8.287 11.9924C7.20469 12.0547 6.13145 11.7635 5.22899 11.1628C4.32653 10.5621 3.64374 9.68441 3.2835 8.66191C3.19174 8.40146 3.32849 8.11593 3.58894 8.02417C3.84939 7.93241 4.13492 8.06916 4.22668 8.32961C4.51488 9.14762 5.06112 9.84981 5.78309 10.3304C6.50507 10.811 7.36368 11.0439 8.22954 10.994C9.0954 10.9442 9.92161 10.6143 10.5837 10.0541C11.2458 9.49386 11.7078 8.73363 11.9003 7.88796C12.0927 7.04229 12.0051 6.15698 11.6507 5.36542C11.2962 4.57387 10.6941 3.91895 9.93506 3.49935C9.17602 3.07974 8.30118 2.91819 7.44235 3.03902C6.58351 3.15985 5.78721 3.55653 5.17342 4.16928L5.16255 4.17981L2.84239 6.35996C2.64115 6.54906 2.32472 6.53921 2.13562 6.33797C1.94653 6.13673 1.95637 5.8203 2.15761 5.63121L4.47241 3.4561C5.23889 2.69329 6.23206 2.19945 7.30302 2.04877Z" fill="black"/>
</svg>

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 1.5 KiB

Wyświetl plik

@ -1,5 +1,5 @@
import * as React from 'react'
import styled from '../styles'
import styled from '~styles'
import { Utils } from '@tldraw/core'
export function commandKey(): string {

Wyświetl plik

@ -24,7 +24,7 @@ import {
} from '@radix-ui/react-dropdown-menu'
import { Root as RGRoot } from '@radix-ui/react-radio-group'
import { CheckIcon, ChevronRightIcon } from '@radix-ui/react-icons'
import styled from '../styles'
import styled from '~styles'
export const breakpoints: any = { '@initial': 'mobile', '@sm': 'small' }
@ -408,12 +408,7 @@ export function MenuButton({
children: React.ReactNode
}): JSX.Element {
return (
<RowButton
bp={breakpoints}
disabled={disabled}
warn={warn}
onSelect={onSelect}
>
<RowButton bp={breakpoints} disabled={disabled} warn={warn} onSelect={onSelect}>
{children}
</RowButton>
)
@ -499,12 +494,7 @@ export function DropdownMenuButton({
children: React.ReactNode
}): JSX.Element {
return (
<DMItem
as={RowButton}
bp={breakpoints}
disabled={disabled}
onSelect={onSelect}
>
<DMItem as={RowButton} bp={breakpoints} disabled={disabled} onSelect={onSelect}>
{children}
</DMItem>
)
@ -522,12 +512,7 @@ export function DropdownMenuIconButton({
disabled = false,
}: DropdownMenuIconButtonProps): JSX.Element {
return (
<DMItem
as={IconButton}
bp={breakpoints}
disabled={disabled}
onSelect={onSelect}
>
<DMItem as={IconButton} bp={breakpoints} disabled={disabled} onSelect={onSelect}>
{children}
</DMItem>
)
@ -646,12 +631,7 @@ export function ContextMenuButton({
children: React.ReactNode
}): JSX.Element {
return (
<RowButton
as={CMItem}
bp={breakpoints}
disabled={disabled}
onSelect={onSelect}
>
<RowButton as={CMItem} bp={breakpoints} disabled={disabled} onSelect={onSelect}>
{children}
</RowButton>
)
@ -667,12 +647,7 @@ export function ContextMenuIconButton({
children: React.ReactNode
}): JSX.Element {
return (
<CMItem
as={IconButton}
bp={breakpoints}
disabled={disabled}
onSelect={onSelect}
>
<CMItem as={IconButton} bp={breakpoints} disabled={disabled} onSelect={onSelect}>
{children}
</CMItem>
)

Wyświetl plik

@ -11,9 +11,9 @@ import {
StretchHorizontallyIcon,
StretchVerticallyIcon,
} from '@radix-ui/react-icons'
import { AlignType, DistributeType, StretchType } from '../../types'
import { AlignType, DistributeType, StretchType } from '~types'
import { useTLDrawContext } from '~hooks'
import { breakpoints, ButtonsRow, IconButton } from '../shared'
import { useTLDrawContext } from '../../hooks'
export interface AlignDistributeProps {
hasTwoOrMore: boolean

Wyświetl plik

@ -2,56 +2,50 @@ import * as React from 'react'
import * as DropdownMenu from '@radix-ui/react-dropdown-menu'
import { BoxIcon, StyleDropdownItem, StyleDropdownContent } from './shared'
import { DropdownMenuIconTriggerButton } from '../shared'
import { ColorStyle, strokes } from '../../shape'
import { useTheme } from '../../hooks/useTheme'
import { useTLDrawContext } from '../../hooks'
import type { Data } from '../../state'
import { strokes } from '~shape'
import { useTheme, useTLDrawContext } from '~hooks'
import type { Data, ColorStyle } from '~types'
const selectColor = (data: Data) => data.appState.selectedStyle.color
export const QuickColorSelect = React.memo(
(): JSX.Element => {
const { theme } = useTheme()
const { tlstate, useSelector } = useTLDrawContext()
const color = useSelector(selectColor)
export const QuickColorSelect = React.memo((): JSX.Element => {
const { theme } = useTheme()
const { tlstate, useSelector } = useTLDrawContext()
const color = useSelector(selectColor)
const handleColorChange = React.useCallback(
(color) => {
tlstate.style({ color: color as ColorStyle })
},
[tlstate]
)
const handleColorChange = React.useCallback(
(color) => {
tlstate.style({ color: color as ColorStyle })
},
[tlstate]
)
return (
<DropdownMenu.Root dir="ltr">
<DropdownMenuIconTriggerButton label="Color">
<BoxIcon
fill={strokes[theme][color]}
stroke={strokes[theme][color]}
/>
</DropdownMenuIconTriggerButton>
<DropdownMenu.Content sideOffset={8}>
<DropdownMenu.DropdownMenuRadioGroup
value={color as string}
onValueChange={handleColorChange}
as={StyleDropdownContent}
>
{Object.keys(strokes[theme]).map((colorStyle: string) => (
<DropdownMenu.DropdownMenuRadioItem
as={StyleDropdownItem}
key={colorStyle}
title={colorStyle}
value={colorStyle}
>
<BoxIcon
fill={strokes[theme][colorStyle as ColorStyle]}
stroke={strokes[theme][colorStyle as ColorStyle]}
/>
</DropdownMenu.DropdownMenuRadioItem>
))}
</DropdownMenu.DropdownMenuRadioGroup>
</DropdownMenu.Content>
</DropdownMenu.Root>
)
}
)
return (
<DropdownMenu.Root dir="ltr">
<DropdownMenuIconTriggerButton label="Color">
<BoxIcon fill={strokes[theme][color]} stroke={strokes[theme][color]} />
</DropdownMenuIconTriggerButton>
<DropdownMenu.Content sideOffset={8}>
<DropdownMenu.DropdownMenuRadioGroup
value={color as string}
onValueChange={handleColorChange}
as={StyleDropdownContent}
>
{Object.keys(strokes[theme]).map((colorStyle: string) => (
<DropdownMenu.DropdownMenuRadioItem
as={StyleDropdownItem}
key={colorStyle}
title={colorStyle}
value={colorStyle}
>
<BoxIcon
fill={strokes[theme][colorStyle as ColorStyle]}
stroke={strokes[theme][colorStyle as ColorStyle]}
/>
</DropdownMenu.DropdownMenuRadioItem>
))}
</DropdownMenu.DropdownMenuRadioGroup>
</DropdownMenu.Content>
</DropdownMenu.Root>
)
})

Wyświetl plik

@ -9,9 +9,8 @@ import {
StyleDropdownContent,
StyleDropdownItem,
} from './shared'
import { DashStyle } from '../../shape'
import { useTLDrawContext } from '../../hooks'
import type { Data } from '../../state'
import { useTLDrawContext } from '~hooks'
import { DashStyle, Data } from '~types'
const dashes = {
[DashStyle.Draw]: <DashDrawIcon />,
@ -22,43 +21,39 @@ const dashes = {
const selectDash = (data: Data) => data.appState.selectedStyle.dash
export const QuickDashSelect = React.memo(
(): JSX.Element => {
const { tlstate, useSelector } = useTLDrawContext()
const dash = useSelector(selectDash)
export const QuickDashSelect = React.memo((): JSX.Element => {
const { tlstate, useSelector } = useTLDrawContext()
const dash = useSelector(selectDash)
const changeDashStyle = React.useCallback(
(dash) => {
tlstate.style({ dash: dash as DashStyle })
},
[tlstate]
)
const changeDashStyle = React.useCallback(
(dash) => {
tlstate.style({ dash: dash as DashStyle })
},
[tlstate]
)
return (
<DropdownMenu.Root dir="ltr">
<DropdownMenuIconTriggerButton label="Dash">
{dashes[dash]}
</DropdownMenuIconTriggerButton>
<DropdownMenu.Content sideOffset={8}>
<DropdownMenu.DropdownMenuRadioGroup
as={StyleDropdownContent}
direction="vertical"
value={dash}
onValueChange={changeDashStyle}
>
{Object.keys(DashStyle).map((dashStyle: string) => (
<DropdownMenu.DropdownMenuRadioItem
as={StyleDropdownItem}
key={dashStyle}
isActive={dash === dashStyle}
value={dashStyle}
>
{dashes[dashStyle as DashStyle]}
</DropdownMenu.DropdownMenuRadioItem>
))}
</DropdownMenu.DropdownMenuRadioGroup>
</DropdownMenu.Content>
</DropdownMenu.Root>
)
}
)
return (
<DropdownMenu.Root dir="ltr">
<DropdownMenuIconTriggerButton label="Dash">{dashes[dash]}</DropdownMenuIconTriggerButton>
<DropdownMenu.Content sideOffset={8}>
<DropdownMenu.DropdownMenuRadioGroup
as={StyleDropdownContent}
direction="vertical"
value={dash}
onValueChange={changeDashStyle}
>
{Object.keys(DashStyle).map((dashStyle: string) => (
<DropdownMenu.DropdownMenuRadioItem
as={StyleDropdownItem}
key={dashStyle}
isActive={dash === dashStyle}
value={dashStyle}
>
{dashes[dashStyle as DashStyle]}
</DropdownMenu.DropdownMenuRadioItem>
))}
</DropdownMenu.DropdownMenuRadioGroup>
</DropdownMenu.Content>
</DropdownMenu.Root>
)
})

Wyświetl plik

@ -3,41 +3,39 @@ import * as Checkbox from '@radix-ui/react-checkbox'
import { breakpoints, IconButton, IconWrapper } from '../shared'
import { BoxIcon, IsFilledFillIcon } from './shared'
import { Tooltip } from '../tooltip'
import { useTLDrawContext } from '../../hooks'
import type { Data } from '../../state'
import { useTLDrawContext } from '~hooks'
import type { Data } from '~types'
const isFilledSelector = (data: Data) => data.appState.selectedStyle.isFilled
export const QuickFillSelect = React.memo(
(): JSX.Element => {
const { tlstate, useSelector } = useTLDrawContext()
export const QuickFillSelect = React.memo((): JSX.Element => {
const { tlstate, useSelector } = useTLDrawContext()
const isFilled = useSelector(isFilledSelector)
const isFilled = useSelector(isFilledSelector)
const handleIsFilledChange = React.useCallback(
(isFilled: boolean) => {
tlstate.style({ isFilled })
},
[tlstate]
)
const handleIsFilledChange = React.useCallback(
(isFilled: boolean) => {
tlstate.style({ isFilled })
},
[tlstate]
)
return (
<Checkbox.Root
dir="ltr"
as={IconButton}
bp={breakpoints}
checked={isFilled}
onCheckedChange={handleIsFilledChange}
>
<Tooltip label="Fill">
<IconWrapper>
<BoxIcon />
<Checkbox.Indicator>
<IsFilledFillIcon />
</Checkbox.Indicator>
</IconWrapper>
</Tooltip>
</Checkbox.Root>
)
}
)
return (
<Checkbox.Root
dir="ltr"
as={IconButton}
bp={breakpoints}
checked={isFilled}
onCheckedChange={handleIsFilledChange}
>
<Tooltip label="Fill">
<IconWrapper>
<BoxIcon />
<Checkbox.Indicator>
<IsFilledFillIcon />
</Checkbox.Indicator>
</IconWrapper>
</Tooltip>
</Checkbox.Root>
)
})

Wyświetl plik

@ -2,9 +2,8 @@ import * as React from 'react'
import * as DropdownMenu from '@radix-ui/react-dropdown-menu'
import { DropdownMenuIconTriggerButton, CircleIcon } from '../shared'
import { StyleDropdownContent, StyleDropdownItem } from './shared'
import { SizeStyle } from '../../shape'
import type { Data } from '../../state'
import { useTLDrawContext } from '../../hooks'
import { Data, SizeStyle } from '~types'
import { useTLDrawContext } from '~hooks'
const sizes = {
[SizeStyle.Small]: 6,
@ -14,44 +13,42 @@ const sizes = {
const selectSize = (data: Data) => data.appState.selectedStyle.size
export const QuickSizeSelect = React.memo(
(): JSX.Element => {
const { tlstate, useSelector } = useTLDrawContext()
export const QuickSizeSelect = React.memo((): JSX.Element => {
const { tlstate, useSelector } = useTLDrawContext()
const size = useSelector(selectSize)
const size = useSelector(selectSize)
const changeSizeStyle = React.useCallback(
(size: string) => {
tlstate.style({ size: size as SizeStyle })
},
[tlstate]
)
const changeSizeStyle = React.useCallback(
(size: string) => {
tlstate.style({ size: size as SizeStyle })
},
[tlstate]
)
return (
<DropdownMenu.Root dir="ltr">
<DropdownMenuIconTriggerButton label="Size">
<CircleIcon size={sizes[size]} stroke="none" fill="currentColor" />
</DropdownMenuIconTriggerButton>
<DropdownMenu.Content sideOffset={8}>
<DropdownMenu.DropdownMenuRadioGroup
as={StyleDropdownContent}
direction="vertical"
value={size}
onValueChange={changeSizeStyle}
>
{Object.keys(SizeStyle).map((sizeStyle: string) => (
<DropdownMenu.DropdownMenuRadioItem
key={sizeStyle}
as={StyleDropdownItem}
isActive={size === sizeStyle}
value={sizeStyle}
>
<CircleIcon size={sizes[sizeStyle as SizeStyle]} />
</DropdownMenu.DropdownMenuRadioItem>
))}
</DropdownMenu.DropdownMenuRadioGroup>
</DropdownMenu.Content>
</DropdownMenu.Root>
)
}
)
return (
<DropdownMenu.Root dir="ltr">
<DropdownMenuIconTriggerButton label="Size">
<CircleIcon size={sizes[size]} stroke="none" fill="currentColor" />
</DropdownMenuIconTriggerButton>
<DropdownMenu.Content sideOffset={8}>
<DropdownMenu.DropdownMenuRadioGroup
as={StyleDropdownContent}
direction="vertical"
value={size}
onValueChange={changeSizeStyle}
>
{Object.keys(SizeStyle).map((sizeStyle: string) => (
<DropdownMenu.DropdownMenuRadioItem
key={sizeStyle}
as={StyleDropdownItem}
isActive={size === sizeStyle}
value={sizeStyle}
>
<CircleIcon size={sizes[sizeStyle as SizeStyle]} />
</DropdownMenu.DropdownMenuRadioItem>
))}
</DropdownMenu.DropdownMenuRadioGroup>
</DropdownMenu.Content>
</DropdownMenu.Root>
)
})

Wyświetl plik

@ -14,8 +14,8 @@ import {
PinTopIcon,
RotateCounterClockwiseIcon,
} from '@radix-ui/react-icons'
import { useTLDrawContext } from '../../hooks'
import type { Data } from '../../state'
import { useTLDrawContext } from '~hooks'
import type { Data } from '~types'
const isAllLockedSelector = (s: Data) => {
const { selectedIds } = s.pageState
@ -39,8 +39,7 @@ const isAllGroupedSelector = (s: Data) => {
const hasSelectionSelector = (s: Data) => s.pageState.selectedIds.length > 0
const hasMultipleSelectionSelector = (s: Data) =>
s.pageState.selectedIds.length > 1
const hasMultipleSelectionSelector = (s: Data) => s.pageState.selectedIds.length > 1
export const ShapesFunctions = React.memo(() => {
const { tlstate, useSelector } = useTLDrawContext()
@ -109,11 +108,7 @@ export const ShapesFunctions = React.memo(() => {
</Tooltip>
</IconButton>
<IconButton
disabled={!hasSelection}
size="small"
onClick={handleRotate}
>
<IconButton disabled={!hasSelection} size="small" onClick={handleRotate}>
<Tooltip label="Rotate">
<RotateCounterClockwiseIcon />
</Tooltip>
@ -197,12 +192,7 @@ export const ShapesFunctions = React.memo(() => {
</Tooltip>
</IconButton>
<IconButton
bp={breakpoints}
disabled={!hasSelection}
size="small"
onClick={handleDelete}
>
<IconButton bp={breakpoints} disabled={!hasSelection} size="small" onClick={handleDelete}>
<Tooltip label="Delete" kbd="⌫">
<Trash />
</Tooltip>

Wyświetl plik

@ -1,5 +1,5 @@
import * as React from 'react'
import styled from '../../styles'
import styled from '~styles'
export const StyleDropdownContent = styled('div', {
display: 'grid',

Wyświetl plik

@ -1,4 +1,15 @@
import * as React from 'react'
import { Utils } from '@tldraw/core'
import { DotsHorizontalIcon, Cross2Icon } from '@radix-ui/react-icons'
import { useTLDrawContext } from '~hooks'
import type { Data } from '~types'
import { ShapesFunctions } from './shapes-functions'
import { AlignDistribute } from './align-distribute'
import { QuickColorSelect } from './quick-color-select'
import { QuickSizeSelect } from './quick-size-select'
import { QuickDashSelect } from './quick-dash-select'
import { QuickFillSelect } from './quick-fill-select'
import { Tooltip } from '../tooltip'
import { Kbd } from '../kbd'
import {
IconButton,
@ -9,18 +20,6 @@ import {
Divider,
} from '../shared'
import type { Data } from '../../state'
import { ShapesFunctions } from './shapes-functions'
import { AlignDistribute } from './align-distribute'
import { QuickColorSelect } from './quick-color-select'
import { QuickSizeSelect } from './quick-size-select'
import { QuickDashSelect } from './quick-dash-select'
import { QuickFillSelect } from './quick-fill-select'
import { Tooltip } from '../tooltip'
import { DotsHorizontalIcon, Cross2Icon } from '@radix-ui/react-icons'
import { Utils } from '@tldraw/core'
import { useTLDrawContext } from '../../hooks'
const isStyleOpenSelector = (s: Data) => s.appState.isStyleOpen
export function StylePanel(): JSX.Element {
@ -79,11 +78,7 @@ function SelectedShapeContent(): JSX.Element {
hasThreeOrMore={selectedShapesCount > 2}
/>
<Divider />
<RowButton
bp={breakpoints}
disabled={selectedShapesCount === 0}
onClick={handleCopy}
>
<RowButton bp={breakpoints} disabled={selectedShapesCount === 0} onClick={handleCopy}>
<span>Copy</span>
{showKbds && <Kbd variant="menu">#C</Kbd>}
</RowButton>

Wyświetl plik

@ -1,15 +1,14 @@
import * as React from 'react'
import { IdProvider } from '@radix-ui/react-id'
import { Renderer } from '@tldraw/core'
import styled from '~styles'
import type { Data, TLDrawDocument } from '~types'
import { TLDrawState } from '~state'
import { useKeyboardShortcuts, TLDrawContext } from '~hooks'
import { tldrawShapeUtils } from '../shape'
import type { TLDrawDocument } from '../types'
import { useKeyboardShortcuts } from '../hooks'
import styled from '../styles'
import { ContextMenu } from './context-menu'
import { StylePanel } from './style-panel'
import { ToolsPanel } from './tools-panel'
import { Data, TLDrawState } from '../state'
import { TLDrawContext } from '../hooks'
export interface TLDrawProps {
document?: TLDrawDocument

Wyświetl plik

@ -1,8 +1,8 @@
import * as React from 'react'
import { FloatingContainer, RowButton } from '../shared'
import styled from '../../styles'
import type { Data } from '../../state'
import { useTLDrawContext } from '../../hooks'
import styled from '~styles'
import type { Data } from '~types'
import { useTLDrawContext } from '~hooks'
const isEmptyCanvasSelector = (s: Data) =>
Object.keys(s.page.shapes).length > 0 && s.appState.isEmptyCanvas

Wyświetl plik

@ -1,7 +1,7 @@
import * as React from 'react'
import { FloatingContainer } from '../shared'
import { Tooltip } from '../tooltip'
import styled from '../../styles'
import styled from '~styles'
export const ToolButton = styled('button', {
position: 'relative',

Wyświetl plik

@ -1,7 +1,7 @@
import * as React from 'react'
import { useTLDrawContext } from '../../hooks'
import type { Data } from '../../state'
import styled from '../../styles'
import { useTLDrawContext } from '~hooks'
import type { Data } from '~types'
import styled from '~styles'
const activeToolSelector = (s: Data) => s.appState.activeTool

Wyświetl plik

@ -1,3 +1,4 @@
import * as React from 'react'
import {
ArrowTopRightIcon,
CircleIcon,
@ -8,17 +9,15 @@ import {
SquareIcon,
TextIcon,
} from '@radix-ui/react-icons'
import * as React from 'react'
import styled from '~styles'
import { Data, TLDrawShapeType } from '~types'
import { useTLDrawContext } from '~hooks'
import { StatusBar } from './status-bar'
import { FloatingContainer } from '../shared'
import { PrimaryButton, SecondaryButton } from './shared'
import styled from '../../styles'
import { UndoRedo } from './undo-redo'
import { Zoom } from './zoom'
import { BackToContent } from './back-to-content'
import { TLDrawShapeType } from '../../shape'
import { useTLDrawContext } from '../../hooks'
import type { Data } from '../../state'
const activeToolSelector = (s: Data) => s.appState.activeTool
const isToolLockedSelector = (s: Data) => s.appState.isToolLocked
@ -130,9 +129,11 @@ export const ToolsPanel = React.memo((): JSX.Element => {
</FloatingContainer>
<UndoRedo />
</RightWrap>
<StatusWrap>
<StatusBar />
</StatusWrap>
{isDebugMode && (
<StatusWrap>
<StatusBar />
</StatusWrap>
)}
</ToolsPanelContainer>
)
})

Wyświetl plik

@ -1,32 +1,30 @@
import * as React from 'react'
import { useTLDrawContext } from '~hooks'
import { TertiaryButton, TertiaryButtonsContainer } from './shared'
import { Undo, Redo, Trash } from '../icons'
import { useTLDrawContext } from '../../hooks'
export const UndoRedo = React.memo(
(): JSX.Element => {
const { tlstate } = useTLDrawContext()
export const UndoRedo = React.memo((): JSX.Element => {
const { tlstate } = useTLDrawContext()
const handleDelete = React.useCallback(() => {
tlstate.delete()
}, [tlstate])
const handleDelete = React.useCallback(() => {
tlstate.delete()
}, [tlstate])
const handleClear = React.useCallback(() => {
tlstate.clear()
}, [tlstate])
const handleClear = React.useCallback(() => {
tlstate.clear()
}, [tlstate])
return (
<TertiaryButtonsContainer bp={{ '@initial': 'mobile', '@sm': 'small' }}>
<TertiaryButton label="Undo" kbd="#Z" onClick={tlstate.undo}>
<Undo />
</TertiaryButton>
<TertiaryButton label="Redo" kbd="#⇧" onClick={tlstate.redo}>
<Redo />
</TertiaryButton>
<TertiaryButton label="Delete" kbd="⌫" onClick={handleDelete} onDoubleClick={handleClear}>
<Trash />
</TertiaryButton>
</TertiaryButtonsContainer>
)
}
)
return (
<TertiaryButtonsContainer bp={{ '@initial': 'mobile', '@sm': 'small' }}>
<TertiaryButton label="Undo" kbd="#Z" onClick={tlstate.undo}>
<Undo />
</TertiaryButton>
<TertiaryButton label="Redo" kbd="#⇧" onClick={tlstate.redo}>
<Redo />
</TertiaryButton>
<TertiaryButton label="Delete" kbd="⌫" onClick={handleDelete} onDoubleClick={handleClear}>
<Trash />
</TertiaryButton>
</TertiaryButtonsContainer>
)
})

Wyświetl plik

@ -1,26 +1,24 @@
import * as React from 'react'
import { ZoomInIcon, ZoomOutIcon } from '@radix-ui/react-icons'
import { TertiaryButton, TertiaryButtonsContainer } from './shared'
import { useTLDrawContext } from '../../hooks'
import type { Data } from '../../state'
import { useTLDrawContext } from '~hooks'
import type { Data } from '~types'
export const Zoom = React.memo(
(): JSX.Element => {
const { tlstate } = useTLDrawContext()
export const Zoom = React.memo((): JSX.Element => {
const { tlstate } = useTLDrawContext()
return (
<TertiaryButtonsContainer bp={{ '@initial': 'mobile', '@sm': 'small' }}>
<TertiaryButton label="Zoom Out" kbd={`#`} onClick={tlstate.zoomOut}>
<ZoomOutIcon />
</TertiaryButton>
<TertiaryButton label="Zoom In" kbd={`#+`} onClick={tlstate.zoomIn}>
<ZoomInIcon />
</TertiaryButton>
<ZoomCounter />
</TertiaryButtonsContainer>
)
}
)
return (
<TertiaryButtonsContainer bp={{ '@initial': 'mobile', '@sm': 'small' }}>
<TertiaryButton label="Zoom Out" kbd={`#`} onClick={tlstate.zoomOut}>
<ZoomOutIcon />
</TertiaryButton>
<TertiaryButton label="Zoom In" kbd={`#+`} onClick={tlstate.zoomIn}>
<ZoomInIcon />
</TertiaryButton>
<ZoomCounter />
</TertiaryButtonsContainer>
)
})
const zoomSelector = (s: Data) => s.pageState.camera.zoom

Wyświetl plik

@ -1,6 +1,6 @@
import * as RadixTooltip from '@radix-ui/react-tooltip'
import * as React from 'react'
import styled from '../styles'
import styled from '~styles'
import { Kbd } from './kbd'
interface TooltipProps {
@ -10,12 +10,7 @@ interface TooltipProps {
side?: 'bottom' | 'left' | 'right' | 'top'
}
export function Tooltip({
children,
label,
kbd,
side = 'top',
}: TooltipProps): JSX.Element {
export function Tooltip({ children, label, kbd, side = 'top' }: TooltipProps): JSX.Element {
return (
<RadixTooltip.Root>
<RadixTooltip.Trigger as="span">{children}</RadixTooltip.Trigger>

Wyświetl plik

@ -1,8 +1,8 @@
import * as React from 'react'
import { inputs } from '@tldraw/core'
import { useHotkeys } from 'react-hotkeys-hook'
import { TLDrawShapeType } from '../shape'
import type { TLDrawState } from '../state'
import { TLDrawShapeType } from '~types'
import type { TLDrawState } from '~state'
export function useKeyboardShortcuts(tlstate: TLDrawState) {
React.useEffect(() => {

Wyświetl plik

@ -1,16 +1,14 @@
import * as React from 'react'
import type { Data } from '../state/state-types'
import type { Data } from '~types'
import type { UseStore } from 'zustand'
import type { TLDrawState } from '../state'
import type { TLDrawState } from '~state'
export interface TLDrawContextType {
tlstate: TLDrawState
useSelector: UseStore<Data>
}
export const TLDrawContext = React.createContext<TLDrawContextType>(
{} as TLDrawContextType
)
export const TLDrawContext = React.createContext<TLDrawContextType>({} as TLDrawContextType)
export function useTLDrawContext() {
const context = React.useContext(TLDrawContext)

Wyświetl plik

@ -1,4 +1,4 @@
import type { Theme } from '../shape'
import type { Theme } from '~types'
export function useTheme() {
return {

Wyświetl plik

@ -1,3 +1,2 @@
export * from './shape-utils'
export * from './shape-types'
export * from './shape-styles'

Wyświetl plik

@ -1,5 +1,5 @@
import { Utils } from '@tldraw/core'
import { Theme, ColorStyle, DashStyle, ShapeStyles, SizeStyle } from './shape-types'
import { Theme, ColorStyle, DashStyle, ShapeStyles, SizeStyle } from '~types'
const canvasLight = '#fafafa'

Wyświetl plik

@ -1,160 +0,0 @@
import type { TLBinding } from '@tldraw/core'
import { TLShape, TLShapeUtil, TLHandle } from '@tldraw/core'
export enum TLDrawToolType {
Draw = 'draw',
Bounds = 'bounds',
Point = 'point',
Handle = 'handle',
Points = 'points',
Text = 'text',
}
export enum TLDrawShapeType {
Ellipse = 'ellipse',
Rectangle = 'rectangle',
Draw = 'draw',
Arrow = 'arrow',
Text = 'text',
}
export enum Decoration {
Arrow = 'Arrow',
}
export interface TLDrawBaseShape extends TLShape {
style: ShapeStyles
type: TLDrawShapeType
}
export interface DrawShape extends TLDrawBaseShape {
type: TLDrawShapeType.Draw
points: number[][]
}
export interface ArrowShape extends TLDrawBaseShape {
type: TLDrawShapeType.Arrow
bend: number
handles: {
start: TLHandle
bend: TLHandle
end: TLHandle
}
decorations?: {
start?: Decoration
end?: Decoration
middle?: Decoration
}
}
export interface EllipseShape extends TLDrawBaseShape {
type: TLDrawShapeType.Ellipse
radius: number[]
}
export interface RectangleShape extends TLDrawBaseShape {
type: TLDrawShapeType.Rectangle
size: number[]
}
export interface TextShape extends TLDrawBaseShape {
type: TLDrawShapeType.Text
text: string
}
export type TLDrawShape = RectangleShape | EllipseShape | DrawShape | ArrowShape | TextShape
export abstract class TLDrawShapeUtil<T extends TLDrawShape> extends TLShapeUtil<T> {
abstract toolType: TLDrawToolType
}
export type TLDrawShapeUtils = Record<TLDrawShapeType, TLDrawShapeUtil<TLDrawShape>>
export interface ArrowBinding extends TLBinding {
type: 'arrow'
handleId: keyof ArrowShape['handles']
distance: number
point: number[]
}
export type TLDrawBinding = ArrowBinding
export enum ColorStyle {
White = 'White',
LightGray = 'LightGray',
Gray = 'Gray',
Black = 'Black',
Green = 'Green',
Cyan = 'Cyan',
Blue = 'Blue',
Indigo = 'Indigo',
Violet = 'Violet',
Red = 'Red',
Orange = 'Orange',
Yellow = 'Yellow',
}
export enum SizeStyle {
Small = 'Small',
Medium = 'Medium',
Large = 'Large',
}
export enum DashStyle {
Draw = 'Draw',
Solid = 'Solid',
Dashed = 'Dashed',
Dotted = 'Dotted',
}
export enum FontSize {
Small = 'Small',
Medium = 'Medium',
Large = 'Large',
ExtraLarge = 'ExtraLarge',
}
export type ShapeStyles = {
color: ColorStyle
size: SizeStyle
dash: DashStyle
isFilled?: boolean
scale?: number
}
export type PropsOfType<U> = {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
[K in keyof TLDrawShape]: TLDrawShape[K] extends any
? TLDrawShape[K] extends U
? K
: never
: never
}[keyof TLDrawShape]
export type Theme = 'dark' | 'light'
export type Difference<A, B, C = A> = A extends B ? never : C
export type Intersection<A, B, C = A> = A extends B ? C : never
export type FilteredKeys<T, U> = {
[P in keyof T]: T[P] extends U ? P : never
}[keyof T]
export type RequiredKeys<T> = {
[K in keyof T]-?: Difference<Record<string, unknown>, Pick<T, K>, K>
}[keyof T]
export type MembersWithRequiredKey<T, U> = {
[P in keyof T]: Intersection<U, RequiredKeys<T[P]>, T[P]>
}[keyof T]
export type MappedByType<U extends string, T extends { type: U }> = {
[P in T['type']]: T extends any ? (P extends T['type'] ? T : never) : never
}
export type ShapesWithProp<U> = MembersWithRequiredKey<
MappedByType<TLDrawShapeType, TLDrawShape>,
U
>
export {}

Wyświetl plik

@ -1,5 +1,5 @@
import { Rectangle, Ellipse, Arrow, Draw, Text } from './shapes'
import { TLDrawShapeType, TLDrawShape, TLDrawShapeUtil, TLDrawShapeUtils } from './shape-types'
import { TLDrawShapeType, TLDrawShape, TLDrawShapeUtil, TLDrawShapeUtils } from '~types'
export const tldrawShapeUtils: TLDrawShapeUtils = {
[TLDrawShapeType.Rectangle]: new Rectangle(),

Wyświetl plik

@ -8,11 +8,9 @@ import {
Intersect,
TLHandle,
TLPointerInfo,
TLBinding,
TLShapeUtil,
} from '@tldraw/core'
import getStroke from 'perfect-freehand'
import { defaultStyle, getPerfectDashProps, getShapeStyle } from '../../shape-styles'
import { defaultStyle, getPerfectDashProps, getShapeStyle } from '~shape'
import {
ArrowShape,
Decoration,
@ -22,7 +20,7 @@ import {
DashStyle,
TLDrawShape,
ArrowBinding,
} from '../../shape-types'
} from '~types'
export class Arrow extends TLDrawShapeUtil<ArrowShape> {
type = TLDrawShapeType.Arrow as const
@ -122,6 +120,7 @@ export class Arrow extends TLDrawShapeUtil<ArrowShape> {
strokeDashoffset="none"
strokeLinecap="round"
strokeLinejoin="round"
pointerEvents="stroke"
/>
<path
d={path}
@ -132,6 +131,7 @@ export class Arrow extends TLDrawShapeUtil<ArrowShape> {
strokeDashoffset={strokeDashoffset}
strokeLinecap="round"
strokeLinejoin="round"
pointerEvents="stroke"
/>
</>
)
@ -181,6 +181,7 @@ export class Arrow extends TLDrawShapeUtil<ArrowShape> {
strokeDashoffset="none"
strokeLinecap="round"
strokeLinejoin="round"
pointerEvents="stroke"
/>
<path
d={path}
@ -191,6 +192,7 @@ export class Arrow extends TLDrawShapeUtil<ArrowShape> {
strokeDashoffset={strokeDashoffset}
strokeLinecap="round"
strokeLinejoin="round"
pointerEvents="stroke"
/>
</>
)
@ -199,7 +201,7 @@ export class Arrow extends TLDrawShapeUtil<ArrowShape> {
const sw = strokeWidth * 1.618
return (
<g pointerEvents="all">
<g pointerEvents="none">
{shaftPath}
{shape.decorations?.start === Decoration.Arrow && (
<path
@ -586,6 +588,9 @@ export class Arrow extends TLDrawShapeUtil<ArrowShape> {
},
}
// Zero out the handles to prevent handles with negative points. If a handle's x or y
// is below zero, we need to move the shape left or up to make it zero.
const bounds = Utils.getBoundsFromPoints(
Object.values(nextShape.handles).map((handle) => handle.point)
)

Wyświetl plik

@ -1,14 +1,8 @@
import * as React from 'react'
import { TLBounds, Utils, Vec, TLTransformInfo, TLRenderInfo, Intersect } from '@tldraw/core'
import getStroke, { getStrokePoints } from 'perfect-freehand'
import { defaultStyle, getShapeStyle } from '../../shape-styles'
import {
DrawShape,
DashStyle,
TLDrawShapeUtil,
TLDrawShapeType,
TLDrawToolType,
} from '../../shape-types'
import { defaultStyle, getShapeStyle } from '~shape'
import { DrawShape, DashStyle, TLDrawShapeUtil, TLDrawShapeType, TLDrawToolType } from '~types'
export class Draw extends TLDrawShapeUtil<DrawShape> {
type = TLDrawShapeType.Draw as const

Wyświetl plik

@ -1,13 +1,7 @@
import * as React from 'react'
import { Utils, TLTransformInfo, TLBounds, Intersect, Vec, TLRenderInfo } from '@tldraw/core'
import {
DashStyle,
EllipseShape,
TLDrawShapeType,
TLDrawShapeUtil,
TLDrawToolType,
} from '../../shape-types'
import { defaultStyle, getPerfectDashProps, getShapeStyle } from '../../shape-styles'
import { DashStyle, EllipseShape, TLDrawShapeType, TLDrawShapeUtil, TLDrawToolType } from '~types'
import { defaultStyle, getPerfectDashProps, getShapeStyle } from '~shape'
import getStroke from 'perfect-freehand'
export class Ellipse extends TLDrawShapeUtil<EllipseShape> {

Wyświetl plik

@ -1,14 +1,8 @@
import * as React from 'react'
import { TLBounds, Utils, Vec, TLTransformInfo, TLRenderInfo, Intersect } from '@tldraw/core'
import getStroke from 'perfect-freehand'
import { getPerfectDashProps, defaultStyle, getShapeStyle } from '../../shape-styles'
import {
RectangleShape,
DashStyle,
TLDrawShapeUtil,
TLDrawShapeType,
TLDrawToolType,
} from '../../shape-types'
import { getPerfectDashProps, defaultStyle, getShapeStyle } from '~shape'
import { RectangleShape, DashStyle, TLDrawShapeUtil, TLDrawShapeType, TLDrawToolType } from '~types'
export class Rectangle extends TLDrawShapeUtil<RectangleShape> {
type = TLDrawShapeType.Rectangle as const
@ -308,7 +302,7 @@ export class Rectangle extends TLDrawShapeUtil<RectangleShape> {
}
}
transformSingle(shape: RectangleShape, bounds: TLBounds, info: TLTransformInfo<RectangleShape>) {
transformSingle(shape: RectangleShape, bounds: TLBounds) {
return {
size: Vec.round([bounds.width, bounds.height]),
point: Vec.round([bounds.minX, bounds.minY]),

Wyświetl plik

@ -1,8 +1,8 @@
import * as React from 'react'
import { TLBounds, Utils, Vec, TLTransformInfo, TLRenderInfo, Intersect } from '@tldraw/core'
import { defaultStyle, getShapeStyle, getFontSize, getFontStyle } from '../../shape-styles'
import { TextShape, TLDrawShapeUtil, TLDrawShapeType, TLDrawToolType } from '../../shape-types'
import styled from '../../../styles'
import { defaultStyle, getShapeStyle, getFontSize, getFontStyle } from '~shape'
import { TextShape, TLDrawShapeUtil, TLDrawShapeType, TLDrawToolType } from '~types'
import styled from '~styles'
import TextAreaUtils from './text-utils'
function normalizeText(text: string) {

Wyświetl plik

@ -1,6 +1,6 @@
import { TLDrawState } from '../../tlstate'
import { mockDocument } from '../../test-helpers'
import { AlignType } from '../../../types'
import { TLDrawState } from '~state'
import { mockDocument } from '~state/test-helpers'
import { AlignType } from '~types'
describe('Align command', () => {
const tlstate = new TLDrawState()

Wyświetl plik

@ -1,7 +1,7 @@
import { Utils } from '@tldraw/core'
import { AlignType } from '../../../types'
import type { Data, Command } from '../../state-types'
import { TLDR } from '../../tldr'
import { AlignType } from '~types'
import type { Data, Command } from '~types'
import { TLDR } from '~state/tldr'
export function align(data: Data, ids: string[], type: AlignType): Command {
const initialShapes = ids.map((id) => TLDR.getShape(data, id))
@ -14,9 +14,7 @@ export function align(data: Data, ids: string[], type: AlignType): Command {
}
})
const commonBounds = Utils.getCommonBounds(
boundsForShapes.map(({ bounds }) => bounds)
)
const commonBounds = Utils.getCommonBounds(boundsForShapes.map(({ bounds }) => bounds))
const midX = commonBounds.minX + commonBounds.width / 2
const midY = commonBounds.minY + commonBounds.height / 2

Wyświetl plik

@ -1,5 +1,5 @@
import { TLDrawState } from '../../tlstate'
import { mockDocument } from '../../test-helpers'
import { TLDrawState } from '~state'
import { mockDocument } from '~state/test-helpers'
describe('Create command', () => {
const tlstate = new TLDrawState()

Wyświetl plik

@ -1,5 +1,4 @@
import type { TLDrawShape } from '../../../shape'
import type { Data, Command } from '../../state-types'
import type { TLDrawShape, Data, Command } from '~types'
export function create(data: Data, shapes: TLDrawShape[]): Command {
return {

Wyświetl plik

@ -1,7 +1,7 @@
import { TLDR } from './../../tldr'
import { TLDrawState } from '../../tlstate'
import { mockDocument } from '../../test-helpers'
import type { TLDrawShape } from '../../../shape'
import { TLDR } from '~state/tldr'
import { TLDrawState } from '~state'
import { mockDocument } from '~state/test-helpers'
import type { TLDrawShape } from '~types'
describe('Delete command', () => {
const tlstate = new TLDrawState()

Wyświetl plik

@ -1,4 +1,4 @@
import type { Data, Command, PagePartial } from '../../state-types'
import type { Data, Command, PagePartial } from '~types'
// - [x] Delete shapes
// - [x] Delete bindings too

Wyświetl plik

@ -1,6 +1,6 @@
import { TLDrawState } from '../../tlstate'
import { mockDocument } from '../../test-helpers'
import { DistributeType } from '../../../types'
import { TLDrawState } from '~state'
import { mockDocument } from '~state/test-helpers'
import { DistributeType } from '~types'
describe('Distribute command', () => {
const tlstate = new TLDrawState()

Wyświetl plik

@ -1,18 +1,10 @@
import { Utils } from '@tldraw/core'
import type { TLDrawShape } from '../../../shape'
import { DistributeType } from '../../../types'
import type { Data, Command } from '../../state-types'
import { TLDR } from '../../tldr'
import { DistributeType, TLDrawShape, Data, Command } from '~types'
import { TLDR } from '~state/tldr'
export function distribute(
data: Data,
ids: string[],
type: DistributeType
): Command {
export function distribute(data: Data, ids: string[], type: DistributeType): Command {
const initialShapes = ids.map((id) => data.page.shapes[id])
const deltaMap = Object.fromEntries(
getDistributions(initialShapes, type).map((d) => [d.id, d])
)
const deltaMap = Object.fromEntries(getDistributions(initialShapes, type).map((d) => [d.id, d]))
const { before, after } = TLDR.mutateShapes(data, ids, (shape) => {
if (!deltaMap[shape.id]) return shape
@ -50,9 +42,7 @@ function getDistributions(initialShapes: TLDrawShape[], type: DistributeType) {
})
const len = entries.length
const commonBounds = Utils.getCommonBounds(
entries.map(({ bounds }) => bounds)
)
const commonBounds = Utils.getCommonBounds(entries.map(({ bounds }) => bounds))
const results: { id: string; prev: number[]; next: number[] }[] = []
@ -86,7 +76,7 @@ function getDistributions(initialShapes: TLDrawShape[], type: DistributeType) {
let x = commonBounds.minX
const step = (commonBounds.width - span) / (len - 1)
entriesToMove.forEach(({ id, point, bounds }, i) => {
entriesToMove.forEach(({ id, point, bounds }) => {
results.push({ id, prev: point, next: [x, bounds.minY] })
x += bounds.width + step
})
@ -122,7 +112,7 @@ function getDistributions(initialShapes: TLDrawShape[], type: DistributeType) {
let y = commonBounds.minY
const step = (commonBounds.height - span) / (len - 1)
entriesToMove.forEach(({ id, point, bounds }, i) => {
entriesToMove.forEach(({ id, point, bounds }) => {
results.push({ id, prev: point, next: [bounds.minX, y] })
y += bounds.height + step
})

Wyświetl plik

@ -1,5 +1,5 @@
import { TLDrawState } from '../../tlstate'
import { mockDocument } from '../../test-helpers'
import { TLDrawState } from '~state'
import { mockDocument } from '~state/test-helpers'
describe('Duplicate command', () => {
const tlstate = new TLDrawState()

Some files were not shown because too many files have changed in this diff Show More