[refactor] ShapeUtils (#206)

* Starts refactor

* tests passing, got it

* Fix next
This commit is contained in:
Steve Ruiz 2021-10-27 16:15:01 +01:00 committed by GitHub
parent 8d6fe119a5
commit 2e6c33342d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
87 changed files with 1517 additions and 1554 deletions

View file

@ -1,9 +1,10 @@
import * as React from 'react' import * as React from 'react'
import { mockUtils, renderWithContext } from '+test' import { renderWithContext } from '+test'
import { Handles } from './handles' import { Handles } from './handles'
import { boxShape } from '+shape-utils/TLShapeUtil.spec'
describe('handles', () => { describe('handles', () => {
test('mounts component without crashing', () => { test('mounts component without crashing', () => {
renderWithContext(<Handles shape={mockUtils.box.create({ id: 'box' })} zoom={1} />) renderWithContext(<Handles shape={boxShape} zoom={1} />)
}) })
}) })

View file

@ -1,12 +1,13 @@
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
import * as React from 'react' import * as React from 'react'
import type { TLBinding, TLPage, TLPageState, TLShape, TLShapeUtil } from '+types' import type { TLBinding, TLPage, TLPageState, TLShape } from '+types'
import { useSelection, useShapeTree, useTLContext } from '+hooks' import { useSelection, useShapeTree, useTLContext } from '+hooks'
import { Bounds } from '+components/bounds' import { Bounds } from '+components/bounds'
import { BoundsBg } from '+components/bounds/bounds-bg' import { BoundsBg } from '+components/bounds/bounds-bg'
import { Handles } from '+components/handles' import { Handles } from '+components/handles'
import { ShapeNode } from '+components/shape' import { ShapeNode } from '+components/shape'
import { ShapeIndicator } from '+components/shape-indicator' import { ShapeIndicator } from '+components/shape-indicator'
import type { TLShapeUtil } from '+shape-utils'
interface PageProps<T extends TLShape, M extends Record<string, unknown>> { interface PageProps<T extends TLShape, M extends Record<string, unknown>> {
page: TLPage<T, TLBinding> page: TLPage<T, TLBinding>

View file

@ -12,10 +12,10 @@ import type {
import { Canvas } from '../canvas' import { Canvas } from '../canvas'
import { Inputs } from '../../inputs' import { Inputs } from '../../inputs'
import { useTLTheme, TLContext, TLContextType } from '../../hooks' import { useTLTheme, TLContext, TLContextType } from '../../hooks'
import type { TLShapeUtil, TLSnapLine, TLUsers } from '+index' import type { TLSnapLine, TLUsers } from '+index'
import type { TLShapeUtilsMap } from '+shape-utils'
export interface RendererProps<T extends TLShape, E extends Element = any, M = any> export interface RendererProps<T extends TLShape, M = any> extends Partial<TLCallbacks<T>> {
extends Partial<TLCallbacks<T>> {
/** /**
* (optional) A unique id to be applied to the renderer element, used to scope styles. * (optional) A unique id to be applied to the renderer element, used to scope styles.
*/ */
@ -27,7 +27,7 @@ export interface RendererProps<T extends TLShape, E extends Element = any, M = a
/** /**
* An object containing instances of your shape classes. * An object containing instances of your shape classes.
*/ */
shapeUtils: Record<T['type'], TLShapeUtil<T, E, M>> shapeUtils: TLShapeUtilsMap<T>
/** /**
* The current page, containing shapes and bindings. * The current page, containing shapes and bindings.
*/ */
@ -104,7 +104,7 @@ export interface RendererProps<T extends TLShape, E extends Element = any, M = a
* @param props * @param props
* @returns * @returns
*/ */
export function Renderer<T extends TLShape, E extends Element, M extends Record<string, unknown>>({ export function Renderer<T extends TLShape, M extends Record<string, unknown>>({
id = 'tl', id = 'tl',
shapeUtils, shapeUtils,
page, page,
@ -123,7 +123,7 @@ export function Renderer<T extends TLShape, E extends Element, M extends Record<
hideBounds = false, hideBounds = false,
onMount, onMount,
...rest ...rest
}: RendererProps<T, E, M>): JSX.Element { }: RendererProps<T, M>): JSX.Element {
useTLTheme(theme, '#' + id) useTLTheme(theme, '#' + id)
const rSelectionBounds = React.useRef<TLBounds>(null) const rSelectionBounds = React.useRef<TLBounds>(null)
@ -134,7 +134,7 @@ export function Renderer<T extends TLShape, E extends Element, M extends Record<
rPageState.current = pageState rPageState.current = pageState
}, [pageState]) }, [pageState])
const [context] = React.useState<TLContextType<T, E, M>>(() => ({ const [context] = React.useState<TLContextType<T>>(() => ({
callbacks: rest, callbacks: rest,
shapeUtils, shapeUtils,
rSelectionBounds, rSelectionBounds,
@ -147,7 +147,7 @@ export function Renderer<T extends TLShape, E extends Element, M extends Record<
}, [context]) }, [context])
return ( return (
<TLContext.Provider value={context as unknown as TLContextType<TLShape, Element>}> <TLContext.Provider value={context as unknown as TLContextType<TLShape>}>
<Canvas <Canvas
id={id} id={id}
page={page} page={page}

View file

@ -1,16 +1,12 @@
import * as React from 'react' import * as React from 'react'
import { mockUtils, renderWithSvg } from '+test' import { renderWithSvg } from '+test'
import { ShapeIndicator } from './shape-indicator' import { ShapeIndicator } from './shape-indicator'
import { boxShape } from '+shape-utils/TLShapeUtil.spec'
describe('shape indicator', () => { describe('shape indicator', () => {
test('mounts component without crashing', () => { test('mounts component without crashing', () => {
renderWithSvg( renderWithSvg(
<ShapeIndicator <ShapeIndicator shape={boxShape} isSelected={true} isHovered={false} meta={undefined} />
shape={mockUtils.box.create({ id: 'box1' })}
isSelected={true}
isHovered={false}
meta={undefined}
/>
) )
}) })
}) })

View file

@ -13,8 +13,8 @@ interface IndicatorProps<T extends TLShape, M = any> {
export const ShapeIndicator = React.memo( export const ShapeIndicator = React.memo(
<T extends TLShape, M = any>({ <T extends TLShape, M = any>({
isHovered, isHovered = false,
isSelected, isSelected = false,
shape, shape,
color, color,
meta, meta,

View file

@ -1,9 +1,10 @@
/* eslint-disable @typescript-eslint/no-non-null-assertion */ /* eslint-disable @typescript-eslint/no-non-null-assertion */
import * as React from 'react' import * as React from 'react'
import type { TLShapeUtil, TLRenderInfo, TLShape } from '+types' import type { TLComponentProps, TLShape } from '+types'
import type { TLShapeUtil } from '+shape-utils'
interface RenderedShapeProps<T extends TLShape, E extends Element, M> interface RenderedShapeProps<T extends TLShape, E extends Element, M>
extends TLRenderInfo<T, E, M> { extends TLComponentProps<T, E, M> {
shape: T shape: T
utils: TLShapeUtil<T, E, M> utils: TLShapeUtil<T, E, M>
} }

View file

@ -1,13 +1,14 @@
import * as React from 'react' import * as React from 'react'
import type { IShapeTreeNode, TLShape, TLShapeUtils } from '+types' import type { IShapeTreeNode, TLShape } from '+types'
import { Shape } from './shape' import { Shape } from './shape'
import type { TLShapeUtilsMap } from '+shape-utils'
interface ShapeNodeProps<T extends TLShape, E extends Element> extends IShapeTreeNode<T> { interface ShapeNodeProps<T extends TLShape> extends IShapeTreeNode<T> {
utils: TLShapeUtils<T, E> utils: TLShapeUtilsMap<TLShape>
} }
export const ShapeNode = React.memo( export const ShapeNode = React.memo(
<T extends TLShape, E extends Element>({ <T extends TLShape>({
shape, shape,
utils, utils,
children, children,
@ -17,7 +18,7 @@ export const ShapeNode = React.memo(
isSelected, isSelected,
isCurrentParent, isCurrentParent,
meta, meta,
}: ShapeNodeProps<T, E>) => { }: ShapeNodeProps<T>) => {
return ( return (
<> <>
<Shape <Shape
@ -27,7 +28,7 @@ export const ShapeNode = React.memo(
isHovered={isHovered} isHovered={isHovered}
isSelected={isSelected} isSelected={isSelected}
isCurrentParent={isCurrentParent} isCurrentParent={isCurrentParent}
utils={utils[shape.type]} utils={utils[shape.type as T['type']]}
meta={meta} meta={meta}
/> />
{children && {children &&

View file

@ -1,13 +1,16 @@
import * as React from 'react' import * as React from 'react'
import { mockUtils, renderWithContext } from '+test' import { renderWithContext } from '+test'
import { Shape } from './shape' import { Shape } from './shape'
import { BoxUtil, boxShape } from '+shape-utils/TLShapeUtil.spec'
import type { TLShapeUtil } from '+shape-utils'
import type { TLShape } from '+types'
describe('shape', () => { describe('shape', () => {
test('mounts component without crashing', () => { test('mounts component without crashing', () => {
renderWithContext( renderWithContext(
<Shape <Shape
shape={mockUtils.box.create({ id: 'box' })} shape={boxShape}
utils={mockUtils[mockUtils.box.type]} utils={new BoxUtil() as unknown as TLShapeUtil<TLShape>}
isEditing={false} isEditing={false}
isBinding={false} isBinding={false}
isHovered={false} isHovered={false}
@ -18,5 +21,5 @@ describe('shape', () => {
}) })
}) })
// { shape: TLShape; ref: ForwardedRef<Element>; } & TLRenderInfo<any, any> & RefAttributes<Element> // { shape: TLShape; ref: ForwardedRef<Element>; } & TLComponentProps<any, any> & RefAttributes<Element>
// { shape: BoxShape; ref: ForwardedRef<any>; } & TLRenderInfo<any, any> & RefAttributes<any>' // { shape: BoxShape; ref: ForwardedRef<any>; } & TLComponentProps<any, any> & RefAttributes<any>'

View file

@ -2,18 +2,19 @@
/* eslint-disable @typescript-eslint/no-non-null-assertion */ /* eslint-disable @typescript-eslint/no-non-null-assertion */
import * as React from 'react' import * as React from 'react'
import { useShapeEvents } from '+hooks' import { useShapeEvents } from '+hooks'
import type { IShapeTreeNode, TLShape, TLShapeUtil } from '+types' import type { IShapeTreeNode, TLShape } from '+types'
import { RenderedShape } from './rendered-shape' import { RenderedShape } from './rendered-shape'
import { Container } from '+components/container' import { Container } from '+components/container'
import { useTLContext } from '+hooks' import { useTLContext } from '+hooks'
import { useForceUpdate } from '+hooks/useForceUpdate' import { useForceUpdate } from '+hooks/useForceUpdate'
import type { TLShapeUtil } from '+shape-utils'
interface ShapeProps<T extends TLShape, E extends Element, M> extends IShapeTreeNode<T, M> { interface ShapeProps<T extends TLShape, M> extends IShapeTreeNode<T, M> {
utils: TLShapeUtil<T, E, M> utils: TLShapeUtil<T>
} }
export const Shape = React.memo( export const Shape = React.memo(
<T extends TLShape, E extends Element, M>({ <T extends TLShape, M>({
shape, shape,
utils, utils,
isEditing, isEditing,
@ -22,7 +23,7 @@ export const Shape = React.memo(
isSelected, isSelected,
isCurrentParent, isCurrentParent,
meta, meta,
}: ShapeProps<T, E, M>) => { }: ShapeProps<T, M>) => {
const { callbacks } = useTLContext() const { callbacks } = useTLContext()
const bounds = utils.getBounds(shape) const bounds = utils.getBounds(shape)
const events = useShapeEvents(shape.id, isCurrentParent) const events = useShapeEvents(shape.id, isCurrentParent)

View file

@ -1,16 +1,21 @@
import * as React from 'react' import * as React from 'react'
import type { TLPage, TLPageState, TLShape, TLBounds, TLShapeUtils, TLBinding } from '+types' import type { TLPage, TLPageState, TLShape, TLBounds, TLBinding } from '+types'
import Utils from '+utils' import Utils from '+utils'
import { useTLContext } from '+hooks' import { useTLContext } from '+hooks'
import type { TLShapeUtil, TLShapeUtilsMap } from '+shape-utils'
function canvasToScreen(point: number[], camera: TLPageState['camera']): number[] { function canvasToScreen(point: number[], camera: TLPageState['camera']): number[] {
return [(point[0] + camera.point[0]) * camera.zoom, (point[1] + camera.point[1]) * camera.zoom] return [(point[0] + camera.point[0]) * camera.zoom, (point[1] + camera.point[1]) * camera.zoom]
} }
export function useSelection<T extends TLShape, E extends Element>( function getShapeUtils<T extends TLShape>(shapeUtils: TLShapeUtilsMap<T>, shape: T) {
return shapeUtils[shape.type as T['type']] as unknown as TLShapeUtil<T>
}
export function useSelection<T extends TLShape>(
page: TLPage<T, TLBinding>, page: TLPage<T, TLBinding>,
pageState: TLPageState, pageState: TLPageState,
shapeUtils: TLShapeUtils<T, E> shapeUtils: TLShapeUtilsMap<T>
) { ) {
const { rSelectionBounds } = useTLContext() const { rSelectionBounds } = useTLContext()
const { selectedIds } = pageState const { selectedIds } = pageState
@ -30,7 +35,7 @@ export function useSelection<T extends TLShape, E extends Element>(
isLocked = shape.isLocked || false isLocked = shape.isLocked || false
bounds = shapeUtils[shape.type as T['type']].getBounds(shape) bounds = getShapeUtils(shapeUtils, shape).getBounds(shape)
} else if (selectedIds.length > 1) { } else if (selectedIds.length > 1) {
const selectedShapes = selectedIds.map((id) => page.shapes[id]) const selectedShapes = selectedIds.map((id) => page.shapes[id])
@ -40,12 +45,9 @@ export function useSelection<T extends TLShape, E extends Element>(
bounds = selectedShapes.reduce((acc, shape, i) => { bounds = selectedShapes.reduce((acc, shape, i) => {
if (i === 0) { if (i === 0) {
return shapeUtils[shape.type as T['type']].getRotatedBounds(shape) return getShapeUtils(shapeUtils, shape).getRotatedBounds(shape)
} }
return Utils.getExpandedBounds( return Utils.getExpandedBounds(acc, getShapeUtils(shapeUtils, shape).getRotatedBounds(shape))
acc,
shapeUtils[shape.type as T['type']].getRotatedBounds(shape)
)
}, {} as TLBounds) }, {} as TLBounds)
} }

View file

@ -6,14 +6,13 @@ import type {
TLPage, TLPage,
TLPageState, TLPageState,
TLShape, TLShape,
TLShapeUtils,
TLCallbacks, TLCallbacks,
TLBinding, TLBinding,
TLBounds, TLBounds,
TLShapeUtil,
} from '+types' } from '+types'
import { Utils } from '+utils' import { Utils } from '+utils'
import { Vec } from '@tldraw/vec' import { Vec } from '@tldraw/vec'
import type { TLShapeUtilsMap } from '+shape-utils'
function addToShapeTree<T extends TLShape, M extends Record<string, unknown>>( function addToShapeTree<T extends TLShape, M extends Record<string, unknown>>(
shape: T, shape: T,
@ -70,21 +69,10 @@ function shapeIsInViewport(bounds: TLBounds, viewport: TLBounds) {
return Utils.boundsContain(viewport, bounds) || Utils.boundsCollide(viewport, bounds) return Utils.boundsContain(viewport, bounds) || Utils.boundsCollide(viewport, bounds)
} }
function getShapeUtils<T extends TLShape, E extends Element>( export function useShapeTree<T extends TLShape, M extends Record<string, unknown>>(
shape: T,
shapeUtils: TLShapeUtils<T, E>
) {
return shapeUtils[shape.type] as TLShapeUtil<T, E>
}
export function useShapeTree<
T extends TLShape,
E extends Element,
M extends Record<string, unknown>
>(
page: TLPage<T, TLBinding>, page: TLPage<T, TLBinding>,
pageState: TLPageState, pageState: TLPageState,
shapeUtils: TLShapeUtils<T, E>, shapeUtils: TLShapeUtilsMap<T>,
size: number[], size: number[],
meta?: M, meta?: M,
onRenderCountChange?: TLCallbacks<T>['onRenderCountChange'] onRenderCountChange?: TLCallbacks<T>['onRenderCountChange']
@ -122,11 +110,11 @@ export function useShapeTree<
.filter( .filter(
(shape) => (shape) =>
// Always render shapes that are flagged as stateful // Always render shapes that are flagged as stateful
getShapeUtils(shape, shapeUtils).isStateful || shapeUtils[shape.type as T['type']].isStateful ||
// Always render selected shapes (this preserves certain drag interactions) // Always render selected shapes (this preserves certain drag interactions)
selectedIds.includes(shape.id) || selectedIds.includes(shape.id) ||
// Otherwise, only render shapes that are in view // Otherwise, only render shapes that are in view
shapeIsInViewport(shapeUtils[shape.type as T['type']].getBounds(shape), viewport) shapeIsInViewport(shapeUtils[shape.type as T['type']].getBounds(shape as any), viewport)
) )
.sort((a, b) => a.childIndex - b.childIndex) .sort((a, b) => a.childIndex - b.childIndex)
.forEach((shape) => { .forEach((shape) => {

View file

@ -1,18 +1,19 @@
import * as React from 'react' import * as React from 'react'
import type { Inputs } from '+inputs' import type { Inputs } from '+inputs'
import type { TLCallbacks, TLShape, TLBounds, TLPageState, TLShapeUtils } from '+types' import type { TLCallbacks, TLShape, TLBounds, TLPageState } from '+types'
import type { TLShapeUtilsMap } from '+shape-utils'
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
export interface TLContextType<T extends TLShape, E extends Element, M = any> { export interface TLContextType<T extends TLShape> {
id?: string id?: string
callbacks: Partial<TLCallbacks<T>> callbacks: Partial<TLCallbacks<T>>
shapeUtils: TLShapeUtils<T, E, M> shapeUtils: TLShapeUtilsMap<T>
rPageState: React.MutableRefObject<TLPageState> rPageState: React.MutableRefObject<TLPageState>
rSelectionBounds: React.MutableRefObject<TLBounds | null> rSelectionBounds: React.MutableRefObject<TLBounds | null>
inputs: Inputs inputs: Inputs
} }
export const TLContext = React.createContext({} as TLContextType<TLShape, Element>) export const TLContext = React.createContext({} as TLContextType<TLShape>)
export function useTLContext() { export function useTLContext() {
const context = React.useContext(TLContext) const context = React.useContext(TLContext)

View file

@ -2,4 +2,4 @@ export * from './components'
export * from './types' export * from './types'
export * from './utils' export * from './utils'
export * from './inputs' export * from './inputs'
export * from './shapes' export * from './shape-utils'

View file

@ -0,0 +1,230 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import * as React from 'react'
/* eslint-disable @typescript-eslint/no-unused-vars */
import type { TLShape, TLBounds } from '+types'
import { TLShapeUtil } from './TLShapeUtil'
import { render } from '@testing-library/react'
import { SVGContainer } from '+components'
import Utils from '+utils'
import type { TLComponent, TLIndicator } from '+shape-utils'
export interface BoxShape extends TLShape {
type: 'box'
size: number[]
}
const meta = { legs: 93 }
type Meta = typeof meta
export const boxShape: BoxShape = {
id: 'example1',
type: 'box',
parentId: 'page',
childIndex: 0,
name: 'Example Shape',
point: [0, 0],
size: [100, 100],
rotation: 0,
}
export class BoxUtil extends TLShapeUtil<BoxShape, SVGSVGElement, Meta> {
age = 100
Component: TLComponent<BoxShape, SVGSVGElement, Meta> = ({ shape, events, meta }, ref) => {
type T = typeof meta.legs
type C = T['toFixed']
return (
<SVGContainer ref={ref}>
<g {...events}>
<rect width={shape.size[0]} height={shape.size[1]} fill="none" stroke="black" />
</g>
</SVGContainer>
)
}
Indicator: TLIndicator<BoxShape, SVGSVGElement, Meta> = ({ shape }) => {
return (
<SVGContainer>
<rect width={shape.size[0]} height={shape.size[1]} fill="none" stroke="black" />
</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)
}
}
describe('When creating a minimal ShapeUtil', () => {
const Box = new BoxUtil()
it('creates a shape utils', () => {
expect(Box).toBeTruthy()
})
test('accesses this in an override method', () => {
expect(Box.shouldRender(boxShape, { ...boxShape, point: [1, 1] })).toBe(true)
})
test('mounts component without crashing', () => {
const ref = React.createRef<SVGSVGElement>()
const ref2 = React.createRef<HTMLDivElement>()
const H = React.forwardRef<HTMLDivElement, { message: string }>((props, ref) => {
return <div ref={ref2}>{props.message}</div>
})
render(<H message="Hello" />)
render(
<Box._Component
ref={ref}
shape={boxShape}
isEditing={false}
isBinding={false}
isHovered={false}
isSelected={false}
isCurrentParent={false}
meta={{} as any}
events={{} as any}
/>
)
})
})
abstract class TLRealisticShapeUtil<
T extends TLShape,
E extends Element = any,
M = any
> extends TLShapeUtil<T, E, M> {
abstract type: T['type']
abstract getShape: (props: Partial<T>) => T
create = (props: { id: string } & Partial<T>) => {
this.refMap.set(props.id, React.createRef())
return this.getShape(props)
}
}
describe('When creating a realistic API around TLShapeUtil', () => {
class ExtendedBoxUtil extends TLRealisticShapeUtil<BoxShape, SVGSVGElement, Meta> {
type = 'box' as const
age = 100
Component: TLComponent<BoxShape, SVGSVGElement, Meta> = ({ shape, events, meta }, ref) => {
type T = typeof meta.legs
type C = T['toFixed']
return (
<SVGContainer ref={ref}>
<g {...events}>
<rect width={shape.size[0]} height={shape.size[1]} fill="none" stroke="black" />
</g>
</SVGContainer>
)
}
Indicator: TLIndicator<BoxShape, SVGSVGElement, Meta> = ({ shape }) => {
return (
<SVGContainer>
<rect width={shape.size[0]} height={shape.size[1]} fill="none" stroke="black" />
</SVGContainer>
)
}
getShape = (props: Partial<BoxShape>): BoxShape => ({
id: 'example1',
type: 'box',
parentId: 'page',
childIndex: 0,
name: 'Example Shape',
point: [0, 0],
size: [100, 100],
rotation: 0,
...props,
})
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)
}
}
const Box = new ExtendedBoxUtil()
it('creates a shape utils', () => {
expect(Box).toBeTruthy()
})
it('creates a shape utils with extended properties', () => {
expect(Box.age).toBe(100)
})
it('creates a shape', () => {
expect(Box.create({ id: 'box1' })).toStrictEqual({
...boxShape,
id: 'box1',
})
})
test('accesses this in an override method', () => {
expect(Box.shouldRender(boxShape, { ...boxShape, point: [1, 1] })).toBe(true)
})
test('mounts component without crashing', () => {
const box = Box.create({ id: 'box1' })
const ref = React.createRef<SVGSVGElement>()
const ref2 = React.createRef<HTMLDivElement>()
const H = React.forwardRef<HTMLDivElement, { message: string }>((props, ref) => {
return <div ref={ref2}>{props.message}</div>
})
render(<H message="Hello" />)
render(
<Box._Component
ref={ref}
shape={box}
isEditing={false}
isBinding={false}
isHovered={false}
isSelected={false}
isCurrentParent={false}
meta={meta}
events={{} as any}
/>
)
})
})

View file

@ -0,0 +1,90 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import * as React from 'react'
import Utils from '+utils'
import { intersectPolylineBounds } from '@tldraw/intersect'
import type { TLBounds, TLForwardedRef, TLComponentProps, TLShape } from 'types'
export interface TLComponent<T extends TLShape, E extends Element = any, M = any> {
(
this: TLShapeUtil<T, E, M>,
props: TLComponentProps<T, E, M>,
ref: TLForwardedRef<E>
): React.ReactElement<TLComponentProps<T, E, M>, E['tagName']> | null
}
export interface TLIndicator<T extends TLShape, E extends Element = any, M = any> {
(
this: TLShapeUtil<T, E, M>,
props: { shape: T; meta: M; isHovered: boolean; isSelected: boolean }
): React.ReactElement | null
}
export abstract class TLShapeUtil<T extends TLShape, E extends Element = any, M = any> {
_Component: React.ForwardRefExoticComponent<any>
constructor() {
this._Component = React.forwardRef(this.Component)
}
refMap = new Map<string, React.RefObject<E>>()
boundsCache = new WeakMap<TLShape, TLBounds>()
canEdit = false
canBind = false
canClone = false
showBounds = true
isStateful = false
isAspectRatioLocked = false
Component: TLComponent<T, E, M> = () => null
Indicator: TLIndicator<T, E, M> = () => null
shouldRender: (prev: T, next: T) => boolean = () => true
getRef = (shape: T): React.RefObject<E> => {
if (!this.refMap.has(shape.id)) {
this.refMap.set(shape.id, React.createRef<E>())
}
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
return this.refMap.get(shape.id)!
}
hitTest = (shape: T, point: number[]): boolean => {
const bounds = this.getBounds(shape)
return shape.rotation
? Utils.pointInPolygon(point, Utils.getRotatedCorners(bounds, shape.rotation))
: Utils.pointInBounds(point, bounds)
}
hitTestBounds = (shape: T, bounds: TLBounds) => {
const shapeBounds = this.getBounds(shape)
if (!shape.rotation) {
return (
Utils.boundsContain(bounds, shapeBounds) ||
Utils.boundsContain(shapeBounds, bounds) ||
Utils.boundsCollide(shapeBounds, bounds)
)
}
const corners = Utils.getRotatedCorners(shapeBounds, shape.rotation)
return (
corners.every((point) => Utils.pointInBounds(point, bounds)) ||
intersectPolylineBounds(corners, bounds).length > 0
)
}
abstract getBounds: (shape: T) => TLBounds
getRotatedBounds: (shape: T) => TLBounds = (shape) => {
return Utils.getBoundsFromPoints(Utils.getRotatedCorners(this.getBounds(shape), shape.rotation))
}
}

View file

@ -0,0 +1,8 @@
import type { TLShape } from '+types'
import type { TLShapeUtil } from './TLShapeUtil'
export type TLShapeUtilsMap<T extends TLShape> = {
[K in T['type']]: TLShapeUtil<Extract<T, { type: K }>>
}
export * from './TLShapeUtil'

View file

@ -1,147 +0,0 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import * as React from 'react'
/* eslint-disable @typescript-eslint/no-unused-vars */
import type { TLShape, TLBounds } from '+types'
import { ShapeUtil } from './createShape'
import { render } from '@testing-library/react'
import { SVGContainer } from '+components'
import Utils from '+utils'
export interface BoxShape extends TLShape {
size: number[]
}
export const Box = new ShapeUtil<BoxShape, SVGSVGElement, null, { age: number }>(() => {
return {
age: 100,
type: 'box',
defaultProps: {
id: 'example1',
type: 'box',
parentId: 'page',
childIndex: 0,
name: 'Example Shape',
point: [0, 0],
size: [100, 100],
rotation: 0,
},
Component({ shape, events, meta }, ref) {
return (
<SVGContainer ref={ref}>
<g {...events}>
<rect width={shape.size[0]} height={shape.size[1]} fill="none" stroke="black" />
</g>
</SVGContainer>
)
},
Indicator({ shape }) {
return (
<SVGContainer>
<rect width={shape.size[0]} height={shape.size[1]} fill="none" stroke="black" />
</SVGContainer>
)
},
getBounds(shape) {
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)
},
getRotatedBounds(shape) {
return {
minX: 0,
minY: 0,
maxX: 100,
maxY: 100,
width: 100,
height: 100,
}
},
shouldRender(prev, next) {
return prev.point !== next.point
},
}
})
const boxShape = {
id: 'example1',
type: 'box',
parentId: 'page',
childIndex: 0,
name: 'Example Shape',
point: [0, 0],
size: [100, 100],
rotation: 0,
}
const box = Box.create({ id: 'box1' })
describe('shape utils', () => {
it('creates a shape utils', () => {
expect(Box).toBeTruthy()
})
it('creates a shape utils with extended properties', () => {
expect(Box.age).toBe(100)
})
it('creates a shape', () => {
expect(Box.create({ id: 'box1' })).toStrictEqual({
...boxShape,
id: 'box1',
})
})
it('sets config', () => {
const bounds = Box.getRotatedBounds(box)
expect(bounds).toStrictEqual({
minX: 0,
minY: 0,
maxX: 100,
maxY: 100,
width: 100,
height: 100,
})
})
test('accesses this in an override method', () => {
expect(Box.shouldRender(box, { ...box, point: [1, 1] })).toBeTruthy()
})
test('mounts component without crashing', () => {
const box = Box.create({ id: 'box1' })
const ref = React.createRef<SVGSVGElement>()
const ref2 = React.createRef<HTMLDivElement>()
const H = React.forwardRef<HTMLDivElement, { message: string }>((props, ref) => {
return <div ref={ref2}>{props.message}</div>
})
render(<H message="Hello" />)
render(
<Box._Component
ref={ref}
shape={box}
isEditing={false}
isBinding={false}
isHovered={false}
isSelected={false}
isCurrentParent={false}
meta={{} as any}
events={{} as any}
/>
)
})
})

View file

@ -1,232 +0,0 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import * as React from 'react'
import { Vec } from '@tldraw/vec'
import type { TLShape, TLShapeUtil } from '+types'
import Utils from '+utils'
import { intersectPolylineBounds, intersectRayBounds } from '@tldraw/intersect'
export const ShapeUtil = function <T extends TLShape, E extends Element, M = any, K = unknown>(
this: TLShapeUtil<T, E, M> & K,
fn: (
this: TLShapeUtil<T, E, M> & K
) => Partial<TLShapeUtil<T, E, M>> &
Pick<TLShapeUtil<T, E, M>, 'type' | 'defaultProps' | 'Component' | 'Indicator' | 'getBounds'> &
K
): TLShapeUtil<T, E, M> & ReturnType<typeof fn> {
const defaults: Partial<TLShapeUtil<T, E, M>> = {
refMap: new Map(),
boundsCache: new WeakMap(),
canEdit: false,
canBind: false,
showBounds: true,
isStateful: false,
canClone: false,
isAspectRatioLocked: false,
create: (props) => {
this.refMap.set(props.id, React.createRef())
const defaults = this.defaultProps
return { ...defaults, ...props }
},
getRef: (shape) => {
if (!this.refMap.has(shape.id)) {
this.refMap.set(shape.id, React.createRef<E>())
}
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
return this.refMap.get(shape.id)!
},
mutate: (shape, props) => {
return { ...shape, ...props }
},
transform: (shape, bounds) => {
return { ...shape, point: [bounds.minX, bounds.minY] }
},
transformSingle: (shape, bounds, info) => {
return this.transform(shape, bounds, info)
},
shouldRender: () => {
return true
},
getRotatedBounds: (shape) => {
return Utils.getBoundsFromPoints(
Utils.getRotatedCorners(this.getBounds(shape), shape.rotation)
)
},
getCenter: (shape) => {
return Utils.getBoundsCenter(this.getBounds(shape))
},
hitTest: (shape, point) => {
return Utils.pointInBounds(point, this.getBounds(shape))
},
hitTestBounds: (shape, bounds) => {
const { minX, minY, maxX, maxY, width, height } = this.getBounds(shape)
const center = [minX + width / 2, minY + height / 2]
const corners = [
[minX, minY],
[maxX, minY],
[maxX, maxY],
[minX, maxY],
].map((point) => Vec.rotWith(point, center, shape.rotation || 0))
return (
corners.every(
(point) =>
!(
point[0] < bounds.minX ||
point[0] > bounds.maxX ||
point[1] < bounds.minY ||
point[1] > bounds.maxY
)
) || intersectPolylineBounds(corners, bounds).length > 0
)
},
getBindingPoint: (shape, fromShape, point, origin, direction, padding, bindAnywhere) => {
// Algorithm time! We need to find the binding point (a normalized point inside of the shape, or around the shape, where the arrow will point to) and the distance from the binding shape to the anchor.
let bindingPoint: number[]
let distance: number
const bounds = this.getBounds(shape)
const expandedBounds = Utils.expandBounds(bounds, padding)
// The point must be inside of the expanded bounding box
if (!Utils.pointInBounds(point, expandedBounds)) return
// The point is inside of the shape, so we'll assume the user is indicating a specific point inside of the shape.
if (bindAnywhere) {
if (Vec.dist(point, this.getCenter(shape)) < 12) {
bindingPoint = [0.5, 0.5]
} else {
bindingPoint = Vec.divV(Vec.sub(point, [expandedBounds.minX, expandedBounds.minY]), [
expandedBounds.width,
expandedBounds.height,
])
}
distance = 0
} else {
// (1) Binding point
// Find furthest intersection between ray from origin through point and expanded bounds. TODO: What if the shape has a curve? In that case, should we intersect the circle-from-three-points instead?
const intersection = intersectRayBounds(origin, direction, expandedBounds)
.filter((int) => int.didIntersect)
.map((int) => int.points[0])
.sort((a, b) => Vec.dist(b, origin) - Vec.dist(a, origin))[0]
// The anchor is a point between the handle and the intersection
const anchor = Vec.med(point, intersection)
// If we're close to the center, snap to the center, or else calculate a normalized point based on the anchor and the expanded bounds.
if (Vec.distanceToLineSegment(point, anchor, this.getCenter(shape)) < 12) {
bindingPoint = [0.5, 0.5]
} else {
//
bindingPoint = Vec.divV(Vec.sub(anchor, [expandedBounds.minX, expandedBounds.minY]), [
expandedBounds.width,
expandedBounds.height,
])
}
// (3) Distance
// If the point is inside of the bounds, set the distance to a fixed value.
if (Utils.pointInBounds(point, bounds)) {
distance = 16
} else {
// If the binding point was close to the shape's center, snap to to the center. Find the distance between the point and the real bounds of the shape
distance = Math.max(
16,
Utils.getBoundsSides(bounds)
.map((side) => Vec.distanceToLineSegment(side[1][0], side[1][1], point))
.sort((a, b) => a - b)[0]
)
}
}
return {
point: Vec.clampV(bindingPoint, 0, 1),
distance,
}
},
onDoubleClickBoundsHandle() {
return
},
onDoubleClickHandle() {
return
},
onHandleChange() {
return
},
onRightPointHandle() {
return
},
onSessionComplete() {
return
},
onBindingChange() {
return
},
onChildrenChange() {
return
},
updateChildren() {
return
},
}
Object.assign(this, defaults)
Object.assign(this, fn.call(this))
Object.assign(this, fn.call(this))
// Make sure all functions are bound to this
for (const entry of Object.entries(this)) {
if (entry[1] instanceof Function) {
this[entry[0] as keyof typeof this] = this[entry[0]].bind(this)
}
}
this._Component = React.forwardRef(this.Component)
return this
} as unknown as {
new <T extends TLShape, E extends Element, M = any, K = unknown>(
fn: (
this: TLShapeUtil<T, E, M>
) => Partial<TLShapeUtil<T, E, M>> &
Pick<
TLShapeUtil<T, E, M>,
'type' | 'defaultProps' | 'Component' | 'Indicator' | 'getBounds'
> &
K
): TLShapeUtil<T, E, M> & ReturnType<typeof fn>
}

View file

@ -1 +0,0 @@
export * from './createShape'

View file

@ -1,8 +1,5 @@
import type { TLBinding, TLPage, TLPageState, TLShape } from '+types' import type { BoxShape } from '+shape-utils/TLShapeUtil.spec'
import type { TLBinding, TLPage, TLPageState } from '+types'
interface BoxShape extends TLShape {
size: number[]
}
export const mockDocument: { page: TLPage<BoxShape, TLBinding>; pageState: TLPageState } = { export const mockDocument: { page: TLPage<BoxShape, TLBinding>; pageState: TLPageState } = {
page: { page: {

View file

@ -1,6 +1,5 @@
import type { TLShapeUtils } from '+types' import { BoxUtil } from '+shape-utils/TLShapeUtil.spec'
import { Box } from '../shapes/createShape.spec'
export const mockUtils: TLShapeUtils = { export const mockUtils = {
box: Box, box: new BoxUtil(),
} }

View file

@ -6,7 +6,10 @@ import type React from 'react'
export type Patch<T> = Partial<{ [P in keyof T]: T | Partial<T> | Patch<T[P]> }> export type Patch<T> = Partial<{ [P in keyof T]: T | Partial<T> | Patch<T[P]> }>
type ForwardedRef<T> = ((instance: T | null) => void) | React.MutableRefObject<T | null> | null export type TLForwardedRef<T> =
| ((instance: T | null) => void)
| React.MutableRefObject<T | null>
| null
export interface TLPage<T extends TLShape, B extends TLBinding> { export interface TLPage<T extends TLShape, B extends TLBinding> {
id: string id: string
@ -68,14 +71,7 @@ export interface TLShape {
isAspectRatioLocked?: boolean isAspectRatioLocked?: boolean
} }
export type TLShapeUtils< export interface TLComponentProps<T extends TLShape, E = any, M = any> {
T extends TLShape = any,
E extends Element = any,
M = any,
K = any
> = Record<string, TLShapeUtil<T, E, M, K>>
export interface TLRenderInfo<T extends TLShape, E = any, M = any> {
shape: T shape: T
isEditing: boolean isEditing: boolean
isBinding: boolean isBinding: boolean
@ -94,8 +90,9 @@ export interface TLRenderInfo<T extends TLShape, E = any, M = any> {
} }
} }
export interface TLShapeProps<T extends TLShape, E = any, M = any> extends TLRenderInfo<T, E, M> { export interface TLShapeProps<T extends TLShape, E = any, M = any>
ref: ForwardedRef<E> extends TLComponentProps<T, E, M> {
ref: TLForwardedRef<E>
shape: T shape: T
} }
@ -336,148 +333,6 @@ export type Snap =
distance: number distance: number
} }
/* -------------------------------------------------- */
/* Shape Utility */
/* -------------------------------------------------- */
export type TLShapeUtil<
T extends TLShape,
E extends Element,
M = any,
K = { [key: string]: any }
> = K & {
type: T['type']
defaultProps: T
Component(
this: TLShapeUtil<T, E, M>,
props: TLRenderInfo<T, E, M>,
ref: ForwardedRef<E>
): React.ReactElement<TLRenderInfo<T, E, M>, E['tagName']>
Indicator(
this: TLShapeUtil<T, E, M>,
props: { shape: T; meta: M; isHovered: boolean; isSelected: boolean }
): React.ReactElement | null
getBounds(this: TLShapeUtil<T, E, M>, shape: T): TLBounds
refMap: Map<string, React.RefObject<E>>
boundsCache: WeakMap<TLShape, TLBounds>
isAspectRatioLocked: boolean
canEdit: boolean
canClone: boolean
canBind: boolean
isStateful: boolean
showBounds: boolean
getRotatedBounds(this: TLShapeUtil<T, E, M>, shape: T): TLBounds
hitTest(this: TLShapeUtil<T, E, M>, shape: T, point: number[]): boolean
hitTestBounds(this: TLShapeUtil<T, E, M>, shape: T, bounds: TLBounds): boolean
shouldRender(this: TLShapeUtil<T, E, M>, prev: T, next: T): boolean
getCenter(this: TLShapeUtil<T, E, M>, shape: T): number[]
getRef(this: TLShapeUtil<T, E, M>, shape: T): React.RefObject<E>
getBindingPoint<K extends TLShape>(
this: TLShapeUtil<T, E, M>,
shape: T,
fromShape: K,
point: number[],
origin: number[],
direction: number[],
padding: number,
bindAnywhere: boolean
): { point: number[]; distance: number } | undefined
create: (this: TLShapeUtil<T, E, M>, props: { id: string } & Partial<T>) => T
mutate: (this: TLShapeUtil<T, E, M>, shape: T, props: Partial<T>) => Partial<T>
transform: (
this: TLShapeUtil<T, E, M>,
shape: T,
bounds: TLBounds,
info: TLTransformInfo<T>
) => Partial<T> | void
transformSingle: (
this: TLShapeUtil<T, E, M>,
shape: T,
bounds: TLBounds,
info: TLTransformInfo<T>
) => Partial<T> | void
updateChildren: <K extends TLShape>(
this: TLShapeUtil<T, E, M>,
shape: T,
children: K[]
) => Partial<K>[] | void
onChildrenChange: (this: TLShapeUtil<T, E, M>, shape: T, children: TLShape[]) => Partial<T> | void
onBindingChange: (
this: TLShapeUtil<T, E, M>,
shape: T,
binding: TLBinding,
target: TLShape,
targetBounds: TLBounds,
center: number[]
) => Partial<T> | void
onHandleChange: (
this: TLShapeUtil<T, E, M>,
shape: T,
handle: Partial<T['handles']>,
info: Partial<TLPointerInfo>
) => Partial<T> | void
onRightPointHandle: (
this: TLShapeUtil<T, E, M>,
shape: T,
handle: Partial<T['handles']>,
info: Partial<TLPointerInfo>
) => Partial<T> | void
onDoubleClickHandle: (
this: TLShapeUtil<T, E, M>,
shape: T,
handle: Partial<T['handles']>,
info: Partial<TLPointerInfo>
) => Partial<T> | void
onDoubleClickBoundsHandle: (this: TLShapeUtil<T, E, M>, shape: T) => Partial<T> | void
onSessionComplete: (this: TLShapeUtil<T, E, M>, shape: T) => Partial<T> | void
_Component: React.ForwardRefExoticComponent<any>
}
// export interface TLShapeUtil<T extends TLShape, E extends Element, M = any>
// extends TLShapeUtilRequired<T, E, M>,
// Required<TLShapeUtilDefaults<T, E>> {
// _Component: React.ForwardRefExoticComponent<any> & {
// defaultProps: any
// propTypes: any
// }
// }
// export interface TLShapeUtilConfig<T extends TLShape, E extends Element, M = any>
// extends TLShapeUtilRequired<T, E, M>,
// Partial<TLShapeUtilDefaults<T, E>> {}
/* -------------------- Internal -------------------- */ /* -------------------- Internal -------------------- */
export interface IShapeTreeNode<T extends TLShape, M = any> { export interface IShapeTreeNode<T extends TLShape, M = any> {

View file

@ -2,7 +2,7 @@ import * as React from 'react'
import * as DropdownMenu from '@radix-ui/react-dropdown-menu' import * as DropdownMenu from '@radix-ui/react-dropdown-menu'
import { BoxIcon, dropdownItem, dropdownContent } from './styled' import { BoxIcon, dropdownItem, dropdownContent } from './styled'
import { DropdownMenuIconTriggerButton } from '../shared' import { DropdownMenuIconTriggerButton } from '../shared'
import { strokes } from '~shape' import { strokes } from '~shape-utils'
import { useTheme, useTLDrawContext } from '~hooks' import { useTheme, useTLDrawContext } from '~hooks'
import type { Data, ColorStyle } from '~types' import type { Data, ColorStyle } from '~types'

View file

@ -5,7 +5,7 @@ import css, { dark } from '~styles'
import { Data, TLDrawDocument, TLDrawStatus, TLDrawUser } from '~types' import { Data, TLDrawDocument, TLDrawStatus, TLDrawUser } from '~types'
import { TLDrawState } from '~state' import { TLDrawState } from '~state'
import { TLDrawContext, useCustomFonts, useKeyboardShortcuts, useTLDrawContext } from '~hooks' import { TLDrawContext, useCustomFonts, useKeyboardShortcuts, useTLDrawContext } from '~hooks'
import { tldrawShapeUtils } from '~shape' import { shapeUtils } from '~shape-utils'
import { StylePanel } from '~components/style-panel' import { StylePanel } from '~components/style-panel'
import { ToolsPanel } from '~components/tools-panel' import { ToolsPanel } from '~components/tools-panel'
import { PagePanel } from '~components/page-panel' import { PagePanel } from '~components/page-panel'
@ -14,7 +14,6 @@ import { breakpoints, iconButton } from '~components'
import { DotFilledIcon } from '@radix-ui/react-icons' import { DotFilledIcon } from '@radix-ui/react-icons'
import { TLDR } from '~state/tldr' import { TLDR } from '~state/tldr'
import { ContextMenu } from '~components/context-menu' import { ContextMenu } from '~components/context-menu'
import { EMPTY_ARRAY } from '~state/constants'
// Selectors // Selectors
const isInSelectSelector = (s: Data) => s.appState.activeTool === 'select' const isInSelectSelector = (s: Data) => s.appState.activeTool === 'select'
@ -225,7 +224,7 @@ function InnerTldraw({
snapLines={snapLines} snapLines={snapLines}
users={users} users={users}
userId={tlstate.state.room?.userId} userId={tlstate.state.room?.userId}
shapeUtils={tldrawShapeUtils} shapeUtils={shapeUtils}
theme={theme} theme={theme}
meta={meta} meta={meta}
hideBounds={hideBounds} hideBounds={hideBounds}

View file

@ -1,2 +1,78 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
export const BINDING_DISTANCE = 24 export const BINDING_DISTANCE = 24
export const CLONING_DISTANCE = 32 export const CLONING_DISTANCE = 32
export const FIT_TO_SCREEN_PADDING = 128
export const SNAP_DISTANCE = 5
export const EMPTY_ARRAY = [] as any[]
export const SLOW_SPEED = 10
export const VERY_SLOW_SPEED = 2.5
import type { Easing } from '~types'
export const PI2 = Math.PI * 2
export const EASINGS: Record<Easing, (t: number) => number> = {
linear: (t) => t,
easeInQuad: (t) => t * t,
easeOutQuad: (t) => t * (2 - t),
easeInOutQuad: (t) => (t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t),
easeInCubic: (t) => t * t * t,
easeOutCubic: (t) => --t * t * t + 1,
easeInOutCubic: (t) => (t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1),
easeInQuart: (t) => t * t * t * t,
easeOutQuart: (t) => 1 - --t * t * t * t,
easeInOutQuart: (t) => (t < 0.5 ? 8 * t * t * t * t : 1 - 8 * --t * t * t * t),
easeInQuint: (t) => t * t * t * t * t,
easeOutQuint: (t) => 1 + --t * t * t * t * t,
easeInOutQuint: (t) => (t < 0.5 ? 16 * t * t * t * t * t : 1 + 16 * --t * t * t * t * t),
easeInSine: (t) => 1 - Math.cos((t * Math.PI) / 2),
easeOutSine: (t) => Math.sin((t * Math.PI) / 2),
easeInOutSine: (t) => -(Math.cos(Math.PI * t) - 1) / 2,
easeInExpo: (t) => (t <= 0 ? 0 : Math.pow(2, 10 * t - 10)),
easeOutExpo: (t) => (t >= 1 ? 1 : 1 - Math.pow(2, -10 * t)),
easeInOutExpo: (t) =>
t <= 0
? 0
: t >= 1
? 1
: t < 0.5
? Math.pow(2, 20 * t - 10) / 2
: (2 - Math.pow(2, -20 * t + 10)) / 2,
}
export const EASING_STRINGS: Record<Easing, string> = {
linear: `(t) => t`,
easeInQuad: `(t) => t * t`,
easeOutQuad: `(t) => t * (2 - t)`,
easeInOutQuad: `(t) => (t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t)`,
easeInCubic: `(t) => t * t * t`,
easeOutCubic: `(t) => --t * t * t + 1`,
easeInOutCubic: `(t) => t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1`,
easeInQuart: `(t) => t * t * t * t`,
easeOutQuart: `(t) => 1 - --t * t * t * t`,
easeInOutQuart: `(t) => t < 0.5 ? 8 * t * t * t * t : 1 - 8 * --t * t * t * t`,
easeInQuint: `(t) => t * t * t * t * t`,
easeOutQuint: `(t) => 1 + --t * t * t * t * t`,
easeInOutQuint: `(t) => t < 0.5 ? 16 * t * t * t * t * t : 1 + 16 * --t * t * t * t * t`,
easeInSine: `(t) => 1 - Math.cos((t * Math.PI) / 2)`,
easeOutSine: `(t) => Math.sin((t * Math.PI) / 2)`,
easeInOutSine: `(t) => -(Math.cos(Math.PI * t) - 1) / 2`,
easeInExpo: `(t) => (t <= 0 ? 0 : Math.pow(2, 10 * t - 10))`,
easeOutExpo: `(t) => (t >= 1 ? 1 : 1 - Math.pow(2, -10 * t))`,
easeInOutExpo: `(t) => t <= 0 ? 0 : t >= 1 ? 1 : t < 0.5 ? Math.pow(2, 20 * t - 10) / 2 : (2 - Math.pow(2, -20 * t + 10)) / 2`,
}
export const USER_COLORS = [
'#EC5E41',
'#F2555A',
'#F04F88',
'#E34BA9',
'#BD54C6',
'#9D5BD2',
'#7B66DC',
'#02B1CC',
'#11B3A3',
'#39B178',
'#55B467',
'#FF802B',
]

View file

@ -1,4 +1,4 @@
export * from './components/tldraw' export * from './components/tldraw'
export * from './types' export * from './types'
export * from './shape' export * from './shape-utils'
export { TLDrawState } from './state' export { TLDrawState } from './state'

View file

@ -0,0 +1,157 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable @typescript-eslint/no-unused-vars */
import { Utils, TLShapeUtil } from '@tldraw/core'
import type { TLPointerInfo, TLBinding, TLBounds } from '@tldraw/core'
import { intersectRayBounds } from '@tldraw/intersect'
import { Vec } from '@tldraw/vec'
import type { TLDrawMeta, TLDrawShape, TLDrawTransformInfo } from '~types'
import * as React from 'react'
export abstract class TLDrawShapeUtil<
T extends TLDrawShape,
E extends Element = any
> extends TLShapeUtil<T, E, TLDrawMeta> {
abstract type: T['type']
abstract getShape: (props: Partial<T>) => T
create = (props: { id: string } & Partial<T>) => {
this.refMap.set(props.id, React.createRef())
return this.getShape(props)
}
getCenter = (shape: T) => {
return Utils.getBoundsCenter(this.getBounds(shape))
}
getBindingPoint = <K extends TLDrawShape>(
shape: T,
fromShape: K,
point: number[],
origin: number[],
direction: number[],
padding: number,
bindAnywhere: boolean
) => {
// Algorithm time! We need to find the binding point (a normalized point inside of the shape, or around the shape, where the arrow will point to) and the distance from the binding shape to the anchor.
let bindingPoint: number[]
let distance: number
const bounds = this.getBounds(shape)
const expandedBounds = Utils.expandBounds(bounds, padding)
// The point must be inside of the expanded bounding box
if (!Utils.pointInBounds(point, expandedBounds)) return
// The point is inside of the shape, so we'll assume the user is indicating a specific point inside of the shape.
if (bindAnywhere) {
if (Vec.dist(point, this.getCenter(shape)) < 12) {
bindingPoint = [0.5, 0.5]
} else {
bindingPoint = Vec.divV(Vec.sub(point, [expandedBounds.minX, expandedBounds.minY]), [
expandedBounds.width,
expandedBounds.height,
])
}
distance = 0
} else {
// (1) Binding point
// Find furthest intersection between ray from origin through point and expanded bounds. TODO: What if the shape has a curve? In that case, should we intersect the circle-from-three-points instead?
const intersection = intersectRayBounds(origin, direction, expandedBounds)
.filter((int) => int.didIntersect)
.map((int) => int.points[0])
.sort((a, b) => Vec.dist(b, origin) - Vec.dist(a, origin))[0]
// The anchor is a point between the handle and the intersection
const anchor = Vec.med(point, intersection)
// If we're close to the center, snap to the center, or else calculate a normalized point based on the anchor and the expanded bounds.
if (Vec.distanceToLineSegment(point, anchor, this.getCenter(shape)) < 12) {
bindingPoint = [0.5, 0.5]
} else {
//
bindingPoint = Vec.divV(Vec.sub(anchor, [expandedBounds.minX, expandedBounds.minY]), [
expandedBounds.width,
expandedBounds.height,
])
}
// (3) Distance
// If the point is inside of the bounds, set the distance to a fixed value.
if (Utils.pointInBounds(point, bounds)) {
distance = 16
} else {
// If the binding point was close to the shape's center, snap to to the center. Find the distance between the point and the real bounds of the shape
distance = Math.max(
16,
Utils.getBoundsSides(bounds)
.map((side) => Vec.distanceToLineSegment(side[1][0], side[1][1], point))
.sort((a, b) => a - b)[0]
)
}
}
return {
point: Vec.clampV(bindingPoint, 0, 1),
distance,
}
}
mutate = (shape: T, props: Partial<T>): Partial<T> => {
return props
}
transform = (shape: T, bounds: TLBounds, info: TLDrawTransformInfo<T>): Partial<T> => {
return { ...shape, point: [bounds.minX, bounds.minY] }
}
transformSingle = (
shape: T,
bounds: TLBounds,
info: TLDrawTransformInfo<T>
): Partial<T> | void => {
return this.transform(shape, bounds, info)
}
updateChildren?: <K extends TLDrawShape>(shape: T, children: K[]) => Partial<K>[] | void
onChildrenChange?: (shape: T, children: TLDrawShape[]) => Partial<T> | void
onBindingChange?: (
shape: T,
binding: TLBinding,
target: TLDrawShape,
targetBounds: TLBounds,
center: number[]
) => Partial<T> | void
onHandleChange?: (
shape: T,
handles: Partial<T['handles']>,
info: Partial<TLPointerInfo>
) => Partial<T> | void
onRightPointHandle?: (
shape: T,
handles: Partial<T['handles']>,
info: Partial<TLPointerInfo>
) => Partial<T> | void
onDoubleClickHandle?: (
shape: T,
handles: Partial<T['handles']>,
info: Partial<TLPointerInfo>
) => Partial<T> | void
onDoubleClickBoundsHandle?: (shape: T) => Partial<T> | void
onSessionComplete?: (shape: T) => Partial<T> | void
}

View file

@ -0,0 +1 @@
# Shape Utils

View file

@ -1,4 +1,4 @@
import { Arrow } from './arrow' import { Arrow } from '../'
describe('Arrow shape', () => { describe('Arrow shape', () => {
it('Creates a shape', () => { it('Creates a shape', () => {

View file

@ -1,17 +1,27 @@
import * as React from 'react' import * as React from 'react'
import { ShapeUtil, SVGContainer, TLBounds, Utils, TLHandle } from '@tldraw/core' import {
Utils,
TLHandle,
SVGContainer,
TLBinding,
TLBounds,
TLIndicator,
TLComponent,
TLPointerInfo,
} from '@tldraw/core'
import { Vec } from '@tldraw/vec' import { Vec } from '@tldraw/vec'
import getStroke from 'perfect-freehand' import getStroke from 'perfect-freehand'
import { defaultStyle, getShapeStyle } from '~shape/shape-styles' import { defaultStyle, getShapeStyle } from '../shape-styles'
import { import {
ArrowShape, ArrowShape,
DashStyle,
TLDrawTransformInfo,
Decoration, Decoration,
TLDrawShapeType, TLDrawShapeType,
DashStyle, TLDrawShape,
ArrowBinding,
TLDrawMeta,
EllipseShape, EllipseShape,
} from '~types' } from '~types'
import { TLDrawShapeUtil } from '../TLDrawShapeUtil'
import { import {
intersectArcBounds, intersectArcBounds,
intersectCircleCircle, intersectCircleCircle,
@ -20,56 +30,63 @@ import {
intersectRayBounds, intersectRayBounds,
intersectRayEllipse, intersectRayEllipse,
} from '@tldraw/intersect' } from '@tldraw/intersect'
import { EASINGS } from '~state/utils' import { EASINGS, BINDING_DISTANCE } from '~constants'
import { BINDING_DISTANCE } from '~constants'
export const Arrow = new ShapeUtil<ArrowShape, SVGSVGElement, TLDrawMeta>(() => ({ type T = ArrowShape
type: TLDrawShapeType.Arrow, type E = SVGSVGElement
canStyleFill: false, export class ArrowUtil extends TLDrawShapeUtil<T, E> {
type = TLDrawShapeType.Arrow as const
showBounds: false, canStyleFill = false
pathCache: new WeakMap<ArrowShape, string>(), showBounds = false
defaultProps: { pathCache = new WeakMap<T, string>()
id: 'id',
type: TLDrawShapeType.Arrow, getShape = (props: Partial<T>): T => {
name: 'Arrow', return Utils.deepMerge<T>(
parentId: 'page', {
childIndex: 1, id: 'id',
point: [0, 0], type: TLDrawShapeType.Arrow,
rotation: 0, name: 'Arrow',
bend: 0, parentId: 'page',
handles: { childIndex: 1,
start: {
id: 'start',
index: 0,
point: [0, 0], point: [0, 0],
canBind: true, rotation: 0,
bend: 0,
handles: {
start: {
id: 'start',
index: 0,
point: [0, 0],
canBind: true,
},
end: {
id: 'end',
index: 1,
point: [1, 1],
canBind: true,
},
bend: {
id: 'bend',
index: 2,
point: [0.5, 0.5],
},
},
decorations: {
end: Decoration.Arrow,
},
style: {
...defaultStyle,
isFilled: false,
},
}, },
end: { props
id: 'end', )
index: 1, }
point: [1, 1],
canBind: true,
},
bend: {
id: 'bend',
index: 2,
point: [0.5, 0.5],
},
},
decorations: {
end: Decoration.Arrow,
},
style: {
...defaultStyle,
isFilled: false,
},
},
Component({ shape, meta, events }, ref) { Component: TLComponent<T, E> = ({ shape, meta, events }, ref) => {
const { const {
handles: { start, bend, end }, handles: { start, bend, end },
decorations = {}, decorations = {},
@ -245,32 +262,24 @@ export const Arrow = new ShapeUtil<ArrowShape, SVGSVGElement, TLDrawMeta>(() =>
</g> </g>
</SVGContainer> </SVGContainer>
) )
}, }
Indicator({ shape }) { Indicator: TLIndicator<T> = ({ shape }) => {
const path = getArrowPath(shape) const path = getArrowPath(shape)
return <path d={path} /> return <path d={path} />
}, }
shouldRender(prev, next) { getBounds = (shape: T) => {
return (
next.decorations !== prev.decorations ||
next.handles !== prev.handles ||
next.style !== prev.style
)
},
getBounds(shape) {
const bounds = Utils.getFromCache(this.boundsCache, shape, () => { const bounds = Utils.getFromCache(this.boundsCache, shape, () => {
const points = getArcPoints(shape) const points = getArcPoints(shape)
return Utils.getBoundsFromPoints(points) return Utils.getBoundsFromPoints(points)
}) })
return Utils.translateBounds(bounds, shape.point) return Utils.translateBounds(bounds, shape.point)
}, }
getRotatedBounds(shape) { getRotatedBounds = (shape: T) => {
let points = getArcPoints(shape) let points = getArcPoints(shape)
const { minX, minY, maxX, maxY } = Utils.getBoundsFromPoints(points) const { minX, minY, maxX, maxY } = Utils.getBoundsFromPoints(points)
@ -282,39 +291,51 @@ export const Arrow = new ShapeUtil<ArrowShape, SVGSVGElement, TLDrawMeta>(() =>
} }
return Utils.translateBounds(Utils.getBoundsFromPoints(points), shape.point) return Utils.translateBounds(Utils.getBoundsFromPoints(points), shape.point)
}, }
getCenter(shape) { getCenter = (shape: T) => {
const { start, end } = shape.handles const { start, end } = shape.handles
return Vec.add(shape.point, Vec.med(start.point, end.point)) return Vec.add(shape.point, Vec.med(start.point, end.point))
}, }
hitTestBounds(shape, brushBounds: TLBounds) { shouldRender = (prev: T, next: T) => {
return (
next.decorations !== prev.decorations ||
next.handles !== prev.handles ||
next.style !== prev.style
)
}
hitTestBounds = (shape: T, bounds: TLBounds) => {
const { start, end, bend } = shape.handles const { start, end, bend } = shape.handles
const sp = Vec.add(shape.point, start.point) const sp = Vec.add(shape.point, start.point)
const ep = Vec.add(shape.point, end.point) const ep = Vec.add(shape.point, end.point)
if (Utils.pointInBounds(sp, brushBounds) || Utils.pointInBounds(ep, brushBounds)) { if (Utils.pointInBounds(sp, bounds) || Utils.pointInBounds(ep, bounds)) {
return true return true
} }
if (Vec.isEqual(Vec.med(start.point, end.point), bend.point)) { if (Vec.isEqual(Vec.med(start.point, end.point), bend.point)) {
return intersectLineSegmentBounds(sp, ep, brushBounds).length > 0 return intersectLineSegmentBounds(sp, ep, bounds).length > 0
} else { } else {
const [cx, cy, r] = getCtp(shape) const [cx, cy, r] = getCtp(shape)
const cp = Vec.add(shape.point, [cx, cy]) const cp = Vec.add(shape.point, [cx, cy])
return intersectArcBounds(cp, r, sp, ep, brushBounds).length > 0 return intersectArcBounds(cp, r, sp, ep, bounds).length > 0
} }
}, }
transform(_shape, bounds, { initialShape, scaleX, scaleY }) { transform = (
shape: T,
bounds: TLBounds,
{ initialShape, scaleX, scaleY }: TLDrawTransformInfo<T>
): Partial<T> => {
const initialShapeBounds = this.getBounds(initialShape) const initialShapeBounds = this.getBounds(initialShape)
const handles: (keyof ArrowShape['handles'])[] = ['start', 'end'] const handles: (keyof T['handles'])[] = ['start', 'end']
const nextHandles = { ...initialShape.handles } const nextHandles = { ...initialShape.handles }
@ -355,9 +376,9 @@ export const Arrow = new ShapeUtil<ArrowShape, SVGSVGElement, TLDrawMeta>(() =>
point: Vec.round([bounds.minX, bounds.minY]), point: Vec.round([bounds.minX, bounds.minY]),
handles: nextHandles, handles: nextHandles,
} }
}, }
onDoubleClickHandle(shape, handle) { onDoubleClickHandle = (shape: T, handle: Partial<T['handles']>): Partial<T> | void => {
switch (handle) { switch (handle) {
case 'bend': { case 'bend': {
return { return {
@ -390,9 +411,15 @@ export const Arrow = new ShapeUtil<ArrowShape, SVGSVGElement, TLDrawMeta>(() =>
} }
return this return this
}, }
onBindingChange(shape, binding: ArrowBinding, target, targetBounds, center) { onBindingChange = (
shape: T,
binding: TLBinding,
target: TLDrawShape,
targetBounds: TLBounds,
center: number[]
): Partial<T> | void => {
const handle = shape.handles[binding.meta.handleId as keyof ArrowShape['handles']] const handle = shape.handles[binding.meta.handleId as keyof ArrowShape['handles']]
const expandedBounds = Utils.expandBounds(targetBounds, BINDING_DISTANCE) const expandedBounds = Utils.expandBounds(targetBounds, BINDING_DISTANCE)
@ -467,9 +494,13 @@ export const Arrow = new ShapeUtil<ArrowShape, SVGSVGElement, TLDrawMeta>(() =>
}, },
{ shiftKey: false } { shiftKey: false }
) )
}, }
onHandleChange(shape, handles, { shiftKey }) { onHandleChange = (
shape: T,
handles: Partial<T['handles']>,
{ shiftKey }: Partial<TLPointerInfo>
): Partial<T> | void => {
let nextHandles = Utils.deepMerge<ArrowShape['handles']>(shape.handles, handles) let nextHandles = Utils.deepMerge<ArrowShape['handles']>(shape.handles, handles)
let nextBend = shape.bend let nextBend = shape.bend
@ -575,8 +606,8 @@ export const Arrow = new ShapeUtil<ArrowShape, SVGSVGElement, TLDrawMeta>(() =>
} }
return nextShape return nextShape
}, }
})) }
/* -------------------------------------------------- */ /* -------------------------------------------------- */
/* Helpers */ /* Helpers */

View file

@ -1,4 +1,4 @@
import { Draw } from './draw' import { Draw } from '../'
describe('Draw shape', () => { describe('Draw shape', () => {
it('Creates a shape', () => { it('Creates a shape', () => {

View file

@ -1,33 +1,45 @@
import * as React from 'react' import * as React from 'react'
import { SVGContainer, TLBounds, Utils, TLTransformInfo, ShapeUtil } from '@tldraw/core' import { Utils, SVGContainer, TLBounds, TLIndicator, TLComponent } from '@tldraw/core'
import { Vec } from '@tldraw/vec' import { Vec } from '@tldraw/vec'
import { intersectBoundsBounds, intersectBoundsPolyline } from '@tldraw/intersect'
import { getStrokeOutlinePoints, getStrokePoints, StrokeOptions } from 'perfect-freehand' import { getStrokeOutlinePoints, getStrokePoints, StrokeOptions } from 'perfect-freehand'
import { defaultStyle, getShapeStyle } from '~shape/shape-styles' import { defaultStyle, getShapeStyle } from '../shape-styles'
import { DrawShape, DashStyle, TLDrawShapeType, TLDrawMeta } from '~types' import { DrawShape, DashStyle, TLDrawShapeType, TLDrawTransformInfo } from '~types'
import { TLDrawShapeUtil } from '../TLDrawShapeUtil'
import { intersectBoundsBounds, intersectBoundsPolyline } from '@tldraw/intersect'
const pointsBoundsCache = new WeakMap<DrawShape['points'], TLBounds>([]) type T = DrawShape
const shapeBoundsCache = new Map<string, TLBounds>() type E = SVGSVGElement
const rotatedCache = new WeakMap<DrawShape, number[][]>([])
const pointCache: Record<string, number[]> = {}
export const Draw = new ShapeUtil<DrawShape, SVGSVGElement, TLDrawMeta>(() => ({ export class DrawUtil extends TLDrawShapeUtil<T, E> {
type: TLDrawShapeType.Draw, type = TLDrawShapeType.Draw as const
defaultProps: { pointsBoundsCache = new WeakMap<T['points'], TLBounds>([])
id: 'id',
type: TLDrawShapeType.Draw,
name: 'Draw',
parentId: 'page',
childIndex: 1,
point: [0, 0],
rotation: 0,
style: defaultStyle,
points: [],
isComplete: false,
},
Component({ shape, meta, events }, ref) { shapeBoundsCache = new Map<string, TLBounds>()
rotatedCache = new WeakMap<T, number[][]>([])
pointCache: Record<string, number[]> = {}
getShape = (props: Partial<T>): T => {
return Utils.deepMerge<T>(
{
id: 'id',
type: TLDrawShapeType.Draw,
name: 'Draw',
parentId: 'page',
childIndex: 1,
point: [0, 0],
rotation: 0,
style: defaultStyle,
points: [],
isComplete: false,
},
props
)
}
Component: TLComponent<T, E> = ({ shape, meta, events }, ref) => {
const { points, style, isComplete } = shape const { points, style, isComplete } = shape
const polygonPathData = React.useMemo(() => { const polygonPathData = React.useMemo(() => {
@ -132,9 +144,9 @@ export const Draw = new ShapeUtil<DrawShape, SVGSVGElement, TLDrawMeta>(() => ({
/> />
</SVGContainer> </SVGContainer>
) )
}, }
Indicator({ shape }) { Indicator: TLIndicator<T> = ({ shape }) => {
const { points } = shape const { points } = shape
const pathData = React.useMemo(() => { const pathData = React.useMemo(() => {
@ -150,85 +162,12 @@ export const Draw = new ShapeUtil<DrawShape, SVGSVGElement, TLDrawMeta>(() => ({
} }
return <path d={pathData} /> return <path d={pathData} />
}, }
transform = (
getBounds(shape: DrawShape): TLBounds { shape: T,
// return Utils.translateBounds(Utils.getBoundsFromPoints(shape.points), shape.point)
// The goal here is to avoid recalculating the bounds from the
// points array, which is expensive. However, we still need a
// new bounds if the point has changed, but we will reuse the
// previous bounds-from-points result if we can.
const pointsHaveChanged = !pointsBoundsCache.has(shape.points)
const pointHasChanged = !(pointCache[shape.id] === shape.point)
if (pointsHaveChanged) {
// If the points have changed, then bust the points cache
const bounds = Utils.getBoundsFromPoints(shape.points)
pointsBoundsCache.set(shape.points, bounds)
shapeBoundsCache.set(shape.id, Utils.translateBounds(bounds, shape.point))
pointCache[shape.id] = shape.point
} else if (pointHasChanged && !pointsHaveChanged) {
// If the point have has changed, then bust the point cache
pointCache[shape.id] = shape.point
shapeBoundsCache.set(
shape.id,
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
Utils.translateBounds(pointsBoundsCache.get(shape.points)!, shape.point)
)
}
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
return shapeBoundsCache.get(shape.id)!
},
shouldRender(prev: DrawShape, next: DrawShape): boolean {
return (
next.points !== prev.points ||
next.style !== prev.style ||
next.isComplete !== prev.isComplete
)
},
hitTestBounds(shape: DrawShape, brushBounds: TLBounds): boolean {
// Test axis-aligned shape
if (!shape.rotation) {
const bounds = this.getBounds(shape)
return (
Utils.boundsContain(brushBounds, bounds) ||
((Utils.boundsContain(bounds, brushBounds) ||
intersectBoundsBounds(bounds, brushBounds).length > 0) &&
intersectBoundsPolyline(
Utils.translateBounds(brushBounds, Vec.neg(shape.point)),
shape.points
).length > 0)
)
}
// Test rotated shape
const rBounds = this.getRotatedBounds(shape)
const rotatedBounds = Utils.getFromCache(rotatedCache, shape, () => {
const c = Utils.getBoundsCenter(Utils.getBoundsFromPoints(shape.points))
return shape.points.map((pt) => Vec.rotWith(pt, c, shape.rotation || 0))
})
return (
Utils.boundsContain(brushBounds, rBounds) ||
intersectBoundsPolyline(
Utils.translateBounds(brushBounds, Vec.neg(shape.point)),
rotatedBounds
).length > 0
)
},
transform(
shape: DrawShape,
bounds: TLBounds, bounds: TLBounds,
{ initialShape, scaleX, scaleY }: TLTransformInfo<DrawShape> { initialShape, scaleX, scaleY }: TLDrawTransformInfo<T>
): Partial<DrawShape> { ): Partial<T> => {
const initialShapeBounds = Utils.getFromCache(this.boundsCache, initialShape, () => const initialShapeBounds = Utils.getFromCache(this.boundsCache, initialShape, () =>
Utils.getBoundsFromPoints(initialShape.points) Utils.getBoundsFromPoints(initialShape.points)
) )
@ -255,8 +194,74 @@ export const Draw = new ShapeUtil<DrawShape, SVGSVGElement, TLDrawMeta>(() => ({
points, points,
point, point,
} }
}, }
}))
getBounds = (shape: T) => {
// The goal here is to avoid recalculating the bounds from the
// points array, which is expensive. However, we still need a
// new bounds if the point has changed, but we will reuse the
// previous bounds-from-points result if we can.
const pointsHaveChanged = !this.pointsBoundsCache.has(shape.points)
const pointHasChanged = !(this.pointCache[shape.id] === shape.point)
if (pointsHaveChanged) {
// If the points have changed, then bust the points cache
const bounds = Utils.getBoundsFromPoints(shape.points)
this.pointsBoundsCache.set(shape.points, bounds)
this.shapeBoundsCache.set(shape.id, Utils.translateBounds(bounds, shape.point))
this.pointCache[shape.id] = shape.point
} else if (pointHasChanged && !pointsHaveChanged) {
// If the point have has changed, then bust the point cache
this.pointCache[shape.id] = shape.point
this.shapeBoundsCache.set(
shape.id,
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
Utils.translateBounds(this.pointsBoundsCache.get(shape.points)!, shape.point)
)
}
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
return this.shapeBoundsCache.get(shape.id)!
}
shouldRender = (prev: T, next: T) => {
return (
next.points !== prev.points ||
next.style !== prev.style ||
next.isComplete !== prev.isComplete
)
}
hitTestBounds = (shape: T, bounds: TLBounds) => {
// Test axis-aligned shape
if (!shape.rotation) {
const shapeBounds = this.getBounds(shape)
return (
Utils.boundsContain(bounds, shapeBounds) ||
((Utils.boundsContain(shapeBounds, bounds) ||
intersectBoundsBounds(shapeBounds, bounds).length > 0) &&
intersectBoundsPolyline(Utils.translateBounds(bounds, Vec.neg(shape.point)), shape.points)
.length > 0)
)
}
// Test rotated shape
const rBounds = this.getRotatedBounds(shape)
const rotatedBounds = Utils.getFromCache(this.rotatedCache, shape, () => {
const c = Utils.getBoundsCenter(Utils.getBoundsFromPoints(shape.points))
return shape.points.map((pt) => Vec.rotWith(pt, c, shape.rotation || 0))
})
return (
Utils.boundsContain(bounds, rBounds) ||
intersectBoundsPolyline(Utils.translateBounds(bounds, Vec.neg(shape.point)), rotatedBounds)
.length > 0
)
}
}
/* -------------------------------------------------- */ /* -------------------------------------------------- */
/* Helpers */ /* Helpers */
@ -272,7 +277,7 @@ const realPressureSettings: StrokeOptions = {
simulatePressure: false, simulatePressure: false,
} }
function getOptions(shape: DrawShape) { function getOptions(shape: T) {
const styles = getShapeStyle(shape.style) const styles = getShapeStyle(shape.style)
const options: StrokeOptions = { const options: StrokeOptions = {
@ -287,7 +292,7 @@ function getOptions(shape: DrawShape) {
return options return options
} }
function getFillPath(shape: DrawShape) { function getFillPath(shape: T) {
if (shape.points.length < 2) return '' if (shape.points.length < 2) return ''
return Utils.getSvgPathFromStroke( return Utils.getSvgPathFromStroke(
@ -295,14 +300,14 @@ function getFillPath(shape: DrawShape) {
) )
} }
function getDrawStrokePoints(shape: DrawShape, options: StrokeOptions) { function getDrawStrokePoints(shape: T, options: StrokeOptions) {
return getStrokePoints(shape.points, options) return getStrokePoints(shape.points, options)
} }
/** /**
* Get path data for a stroke with the DashStyle.Draw dash style. * Get path data for a stroke with the DashStyle.Draw dash style.
*/ */
function getDrawStrokePathData(shape: DrawShape) { function getDrawStrokePathData(shape: T) {
if (shape.points.length < 2) return '' if (shape.points.length < 2) return ''
const options = getOptions(shape) const options = getOptions(shape)
@ -319,7 +324,7 @@ function getDrawStrokePathData(shape: DrawShape) {
/** /**
* Get SVG path data for a shape that has a DashStyle other than DashStyles.Draw. * Get SVG path data for a shape that has a DashStyle other than DashStyles.Draw.
*/ */
function getSolidStrokePathData(shape: DrawShape) { function getSolidStrokePathData(shape: T) {
const { points } = shape const { points } = shape
if (points.length < 2) return 'M 0 0 L 0 0' if (points.length < 2) return 'M 0 0 L 0 0'

View file

@ -1,4 +1,4 @@
import { Ellipse } from './ellipse' import { Ellipse } from '../'
describe('Ellipse shape', () => { describe('Ellipse shape', () => {
it('Creates a shape', () => { it('Creates a shape', () => {

View file

@ -1,37 +1,39 @@
import * as React from 'react' import * as React from 'react'
import { SVGContainer, Utils, ShapeUtil, TLTransformInfo, TLBounds } from '@tldraw/core' import { Utils, SVGContainer, TLIndicator, TLComponent, TLBounds } from '@tldraw/core'
import { Vec } from '@tldraw/vec' import { Vec } from '@tldraw/vec'
import { DashStyle, EllipseShape, TLDrawShapeType, TLDrawMeta } from '~types'
import { defaultStyle, getShapeStyle } from '~shape/shape-styles'
import { getStrokeOutlinePoints, getStrokePoints } from 'perfect-freehand' import { getStrokeOutlinePoints, getStrokePoints } from 'perfect-freehand'
import { import { defaultStyle, getShapeStyle } from '../shape-styles'
intersectBoundsEllipse, import { EllipseShape, DashStyle, TLDrawShapeType, TLDrawShape, TLDrawTransformInfo } from '~types'
intersectLineSegmentEllipse, import { EASINGS, BINDING_DISTANCE } from '~constants'
intersectRayEllipse, import { TLDrawShapeUtil } from '../TLDrawShapeUtil'
} from '@tldraw/intersect' import { intersectLineSegmentEllipse, intersectRayEllipse } from '@tldraw/intersect'
import { EASINGS } from '~state/utils'
import { BINDING_DISTANCE } from '~constants'
export const Ellipse = new ShapeUtil<EllipseShape, SVGSVGElement, TLDrawMeta>(() => ({ type T = EllipseShape
type: TLDrawShapeType.Ellipse, type E = SVGSVGElement
pathCache: new WeakMap<EllipseShape, string>([]), export class EllipseUtil extends TLDrawShapeUtil<T, E> {
type = TLDrawShapeType.Ellipse as const
canBind: true, canBind = true
defaultProps: { getShape = (props: Partial<T>): T => {
id: 'id', return Utils.deepMerge<T>(
type: TLDrawShapeType.Ellipse, {
name: 'Ellipse', id: 'id',
parentId: 'page', type: TLDrawShapeType.Ellipse,
childIndex: 1, name: 'Ellipse',
point: [0, 0], parentId: 'page',
radius: [1, 1], childIndex: 1,
rotation: 0, point: [0, 0],
style: defaultStyle, radius: [1, 1],
}, rotation: 0,
style: defaultStyle,
},
props
)
}
Component({ shape, meta, isBinding, events }, ref) { Component: TLComponent<T, E> = ({ shape, isBinding, meta, events }, ref) => {
const { const {
radius: [radiusX, radiusY], radius: [radiusX, radiusY],
style, style,
@ -117,17 +119,13 @@ export const Ellipse = new ShapeUtil<EllipseShape, SVGSVGElement, TLDrawMeta>(()
/> />
</SVGContainer> </SVGContainer>
) )
}, }
Indicator({ shape }) { Indicator: TLIndicator<T> = ({ shape }) => {
return <path d={getEllipseIndicatorPathData(shape, this.getCenter(shape))} /> return <path d={getEllipseIndicatorPathData(shape, this.getCenter(shape))} />
}, }
shouldRender(prev, next) { getBounds = (shape: T) => {
return next.radius !== prev.radius || next.style !== prev.style
},
getBounds(shape) {
return Utils.getFromCache(this.boundsCache, shape, () => { return Utils.getFromCache(this.boundsCache, shape, () => {
return Utils.getRotatedEllipseBounds( return Utils.getRotatedEllipseBounds(
shape.point[0], shape.point[0],
@ -137,9 +135,9 @@ export const Ellipse = new ShapeUtil<EllipseShape, SVGSVGElement, TLDrawMeta>(()
0 0
) )
}) })
}, }
getRotatedBounds(shape) { getRotatedBounds = (shape: T): TLBounds => {
return Utils.getRotatedEllipseBounds( return Utils.getRotatedEllipseBounds(
shape.point[0], shape.point[0],
shape.point[1], shape.point[1],
@ -147,36 +145,25 @@ export const Ellipse = new ShapeUtil<EllipseShape, SVGSVGElement, TLDrawMeta>(()
shape.radius[1], shape.radius[1],
shape.rotation shape.rotation
) )
}, }
getCenter(shape): number[] { shouldRender = (prev: T, next: T): boolean => {
return next.radius !== prev.radius || next.style !== prev.style
}
getCenter = (shape: T): number[] => {
return [shape.point[0] + shape.radius[0], shape.point[1] + shape.radius[1]] return [shape.point[0] + shape.radius[0], shape.point[1] + shape.radius[1]]
}, }
hitTest(shape, point: number[]) { getBindingPoint = <K extends TLDrawShape>(
return Utils.pointInEllipse( shape: T,
point, fromShape: K,
this.getCenter(shape), point: number[],
shape.radius[0], origin: number[],
shape.radius[1], direction: number[],
shape.rotation padding: number,
) bindAnywhere: boolean
}, ) => {
hitTestBounds(shape, bounds) {
return (
Utils.boundsContain(bounds, this.getBounds(shape)) ||
intersectBoundsEllipse(
bounds,
this.getCenter(shape),
shape.radius[0],
shape.radius[1],
shape.rotation
).length > 0
)
},
getBindingPoint(shape, fromShape, point, origin, direction, padding, anywhere) {
{ {
const bounds = this.getBounds(shape) const bounds = this.getBounds(shape)
@ -197,7 +184,7 @@ export const Ellipse = new ShapeUtil<EllipseShape, SVGSVGElement, TLDrawMeta>(()
) )
return return
if (anywhere) { if (bindAnywhere) {
if (Vec.dist(point, this.getCenter(shape)) < 12) { if (Vec.dist(point, this.getCenter(shape)) < 12) {
bindingPoint = [0.5, 0.5] bindingPoint = [0.5, 0.5]
} else { } else {
@ -272,13 +259,13 @@ export const Ellipse = new ShapeUtil<EllipseShape, SVGSVGElement, TLDrawMeta>(()
distance, distance,
} }
} }
}, }
transform( transform = (
_shape, shape: T,
bounds: TLBounds, bounds: TLBounds,
{ scaleX, scaleY, initialShape }: TLTransformInfo<EllipseShape> { scaleX, scaleY, initialShape }: TLDrawTransformInfo<T>
) { ): Partial<T> => {
const { rotation = 0 } = initialShape const { rotation = 0 } = initialShape
return { return {
@ -289,15 +276,15 @@ export const Ellipse = new ShapeUtil<EllipseShape, SVGSVGElement, TLDrawMeta>(()
? -(rotation || 0) ? -(rotation || 0)
: rotation || 0, : rotation || 0,
} }
}, }
transformSingle(shape, bounds: TLBounds) { transformSingle = (shape: T, bounds: TLBounds): Partial<T> => {
return { return {
point: Vec.round([bounds.minX, bounds.minY]), point: Vec.round([bounds.minX, bounds.minY]),
radius: Vec.div([bounds.width, bounds.height], 2), radius: Vec.div([bounds.width, bounds.height], 2),
} }
}, }
})) }
/* -------------------------------------------------- */ /* -------------------------------------------------- */
/* Helpers */ /* Helpers */

View file

@ -1,4 +1,4 @@
import { Group } from './group' import { Group } from '../'
describe('Group shape', () => { describe('Group shape', () => {
it('Creates a shape', () => { it('Creates a shape', () => {

View file

@ -1,30 +1,39 @@
import * as React from 'react' import * as React from 'react'
import { SVGContainer, ShapeUtil } from '@tldraw/core' import { Utils, SVGContainer, TLIndicator, TLComponent } from '@tldraw/core'
import { defaultStyle } from '~shape/shape-styles' import { defaultStyle } from '../shape-styles'
import { GroupShape, TLDrawShapeType, ColorStyle, TLDrawMeta } from '~types' import { TLDrawShapeType, GroupShape, ColorStyle } from '~types'
import { getBoundsRectangle } from '../shared' import { getBoundsRectangle } from '../shared'
import css from '~styles'
import { BINDING_DISTANCE } from '~constants' import { BINDING_DISTANCE } from '~constants'
import { TLDrawShapeUtil } from '../TLDrawShapeUtil'
import css from '~styles'
export const Group = new ShapeUtil<GroupShape, SVGSVGElement, TLDrawMeta>(() => ({ type T = GroupShape
type: TLDrawShapeType.Group, type E = SVGSVGElement
canBind: true, export class GroupUtil extends TLDrawShapeUtil<T, E> {
type = TLDrawShapeType.Group as const
defaultProps: { canBind = true
id: 'id',
type: TLDrawShapeType.Group,
name: 'Group',
parentId: 'page',
childIndex: 1,
point: [0, 0],
size: [100, 100],
rotation: 0,
children: [],
style: defaultStyle,
},
Component({ shape, isBinding, isHovered, isSelected, events }, ref) { getShape = (props: Partial<T>): T => {
return Utils.deepMerge<T>(
{
id: 'id',
type: TLDrawShapeType.Group,
name: 'Group',
parentId: 'page',
childIndex: 1,
point: [0, 0],
size: [100, 100],
rotation: 0,
children: [],
style: defaultStyle,
},
props
)
}
Component: TLComponent<T, E> = ({ shape, isBinding, isHovered, isSelected, events }, ref) => {
const { id, size } = shape const { id, size } = shape
const sw = 2 const sw = 2
@ -65,9 +74,9 @@ export const Group = new ShapeUtil<GroupShape, SVGSVGElement, TLDrawMeta>(() =>
</g> </g>
</SVGContainer> </SVGContainer>
) )
}, }
Indicator({ shape }) { Indicator: TLIndicator<T> = ({ shape }) => {
const { id, size } = shape const { id, size } = shape
const sw = 2 const sw = 2
@ -90,16 +99,16 @@ export const Group = new ShapeUtil<GroupShape, SVGSVGElement, TLDrawMeta>(() =>
{paths} {paths}
</g> </g>
) )
}, }
shouldRender(prev, next) { getBounds = (shape: T) => {
return next.size !== prev.size || next.style !== prev.style
},
getBounds(shape) {
return getBoundsRectangle(shape, this.boundsCache) return getBoundsRectangle(shape, this.boundsCache)
}, }
}))
shouldRender = (prev: T, next: T) => {
return next.size !== prev.size || next.style !== prev.style
}
}
const scaledLines = css({ const scaledLines = css({
strokeWidth: 'calc(1.5px * var(--tl-scale))', strokeWidth: 'calc(1.5px * var(--tl-scale))',

View file

@ -0,0 +1,51 @@
import type { TLDrawShapeUtil } from './TLDrawShapeUtil'
import { RectangleUtil } from './rectangle'
import { EllipseUtil } from './ellipse'
import { ArrowUtil } from './arrow'
import { GroupUtil } from './group'
import { StickyUtil } from './sticky'
import { TextUtil } from './text'
import { DrawUtil } from './draw'
import { TLDrawShape, TLDrawShapeType } from '~types'
import type { TLShapeUtilsMap } from '@tldraw/core'
export * from './shape-styles'
export * from './TLDrawShapeUtil'
export const Rectangle = new RectangleUtil()
export const Ellipse = new EllipseUtil()
export const Draw = new DrawUtil()
export const Arrow = new ArrowUtil()
export const Text = new TextUtil()
export const Group = new GroupUtil()
export const Sticky = new StickyUtil()
// type Utils = RectangleUtil | EllipseUtil | DrawUtil | ArrowUtil | TextUtil | GroupUtil | StickyUtil
// type MappedByKey<U extends string | number, K extends string | number, T extends Record<K, U>> = {
// [P in T[K]]: T extends any ? (P extends T[K] ? T : never) : never
// }
// export type ShapeUtilsMap = MappedByKey<Utils['type'], 'type', Utils>
// export const getShapeUtils = <T extends Utils['type']>(
// type: T | Extract<TLDrawShape, { type: T }>
// ): ShapeUtilsMap[T] => {
// if (typeof type === 'string') return shapeUtils[type]
// return shapeUtils[type.type]
// }
export const shapeUtils = {
[TLDrawShapeType.Rectangle]: Rectangle,
[TLDrawShapeType.Ellipse]: Ellipse,
[TLDrawShapeType.Draw]: Draw,
[TLDrawShapeType.Arrow]: Arrow,
[TLDrawShapeType.Text]: Text,
[TLDrawShapeType.Group]: Group,
[TLDrawShapeType.Sticky]: Sticky,
}
export const getShapeUtils = <T extends TLDrawShape>(shape: T | T['type']) => {
if (typeof shape === 'string') return shapeUtils[shape] as unknown as TLDrawShapeUtil<T>
return shapeUtils[shape.type] as unknown as TLDrawShapeUtil<T>
}

View file

@ -1,4 +1,4 @@
import { Rectangle } from './rectangle' import { Rectangle } from '../'
describe('Rectangle shape', () => { describe('Rectangle shape', () => {
it('Creates a shape', () => { it('Creates a shape', () => {

View file

@ -1,34 +1,39 @@
import * as React from 'react' import * as React from 'react'
import { Utils, SVGContainer, ShapeUtil } from '@tldraw/core' import { Utils, SVGContainer, TLIndicator, TLComponent } from '@tldraw/core'
import { Vec } from '@tldraw/vec' import { Vec } from '@tldraw/vec'
import getStroke, { getStrokePoints } from 'perfect-freehand' import { getStroke, getStrokePoints } from 'perfect-freehand'
import { defaultStyle, getShapeStyle } from '~shape/shape-styles' import { defaultStyle, getShapeStyle } from '../shape-styles'
import { RectangleShape, DashStyle, TLDrawShapeType, TLDrawMeta } from '~types' import { RectangleShape, DashStyle, TLDrawShapeType } from '~types'
import { getBoundsRectangle, transformRectangle, transformSingleRectangle } from '../shared' import { getBoundsRectangle, transformRectangle, transformSingleRectangle } from '../shared'
import { BINDING_DISTANCE } from '~constants' import { BINDING_DISTANCE } from '~constants'
import { TLDrawShapeUtil } from '../TLDrawShapeUtil'
export const Rectangle = new ShapeUtil<RectangleShape, SVGSVGElement, TLDrawMeta>(() => ({ type T = RectangleShape
type: TLDrawShapeType.Rectangle, type E = SVGSVGElement
canBind: true, export class RectangleUtil extends TLDrawShapeUtil<T, E> {
type = TLDrawShapeType.Rectangle as const
defaultProps: { canBind = true
id: 'id',
type: TLDrawShapeType.Rectangle,
name: 'Rectangle',
parentId: 'page',
childIndex: 1,
point: [0, 0],
size: [1, 1],
rotation: 0,
style: defaultStyle,
},
shouldRender(prev, next) { getShape = (props: Partial<T>): T => {
return next.size !== prev.size || next.style !== prev.style return Utils.deepMerge<T>(
}, {
id: 'id',
type: TLDrawShapeType.Rectangle,
name: 'Rectangle',
parentId: 'page',
childIndex: 1,
point: [0, 0],
size: [1, 1],
rotation: 0,
style: defaultStyle,
},
props
)
}
Component({ shape, isBinding, meta, events }, ref) { Component: TLComponent<T, E> = ({ shape, isBinding, meta, events }, ref) => {
const { id, size, style } = shape const { id, size, style } = shape
const styles = getShapeStyle(style, meta.isDarkMode) const styles = getShapeStyle(style, meta.isDarkMode)
const strokeWidth = +styles.strokeWidth const strokeWidth = +styles.strokeWidth
@ -124,9 +129,9 @@ export const Rectangle = new ShapeUtil<RectangleShape, SVGSVGElement, TLDrawMeta
<g pointerEvents="stroke">{paths}</g> <g pointerEvents="stroke">{paths}</g>
</SVGContainer> </SVGContainer>
) )
}, }
Indicator({ shape }) { Indicator: TLIndicator<T> = ({ shape }) => {
const { const {
style, style,
size: [width, height], size: [width, height],
@ -151,16 +156,20 @@ export const Rectangle = new ShapeUtil<RectangleShape, SVGSVGElement, TLDrawMeta
height={Math.max(1, height - sw * 2)} height={Math.max(1, height - sw * 2)}
/> />
) )
}, }
getBounds(shape) { getBounds = (shape: T) => {
return getBoundsRectangle(shape, this.boundsCache) return getBoundsRectangle(shape, this.boundsCache)
}, }
transform: transformRectangle, shouldRender = (prev: T, next: T) => {
return next.size !== prev.size || next.style !== prev.style
}
transformSingle: transformSingleRectangle, transform = transformRectangle
}))
transformSingle = transformSingleRectangle
}
/* -------------------------------------------------- */ /* -------------------------------------------------- */
/* Helpers */ /* Helpers */

View file

@ -1,4 +1,4 @@
import { Sticky } from './sticky' import { Sticky } from '../'
describe('Post-It shape', () => { describe('Post-It shape', () => {
it('Creates a shape', () => { it('Creates a shape', () => {

View file

@ -1,54 +1,44 @@
/* eslint-disable @typescript-eslint/no-non-null-assertion */ /* eslint-disable @typescript-eslint/no-non-null-assertion */
import * as React from 'react' import * as React from 'react'
import { css } from '@stitches/core' import { Utils, HTMLContainer, TLBounds, TLIndicator, TLComponent } from '@tldraw/core'
import { HTMLContainer, ShapeUtil } from '@tldraw/core' import { defaultStyle } from '../shape-styles'
import { defaultStyle } from '~shape/shape-styles' import { StickyShape, TLDrawShapeType, TLDrawTransformInfo } from '~types'
import { StickyShape, TLDrawMeta, TLDrawShapeType } from '~types' import { getBoundsRectangle, TextAreaUtils } from '../shared'
import { getBoundsRectangle } from '../shared' import { TLDrawShapeUtil } from '../TLDrawShapeUtil'
import { getStickyFontStyle, getStickyShapeStyle } from '~shape' import { getStickyFontStyle, getStickyShapeStyle } from '../shape-styles'
import { TextAreaUtils } from '../shared' import css from '~styles'
import Vec from '@tldraw/vec' import Vec from '@tldraw/vec'
const PADDING = 16 type T = StickyShape
const MIN_CONTAINER_HEIGHT = 200 type E = HTMLDivElement
function normalizeText(text: string) { export class StickyUtil extends TLDrawShapeUtil<T, E> {
return text.replace(/\r?\n|\r/g, '\n') type = TLDrawShapeType.Sticky as const
}
export const Sticky = new ShapeUtil<StickyShape, HTMLDivElement, TLDrawMeta>(() => ({ canBind = true
type: TLDrawShapeType.Sticky,
showBounds: false, getShape = (props: Partial<T>): T => {
return Utils.deepMerge<T>(
{
id: 'id',
type: TLDrawShapeType.Sticky,
name: 'Sticky',
parentId: 'page',
childIndex: 1,
point: [0, 0],
size: [200, 200],
text: '',
rotation: 0,
style: defaultStyle,
},
props
)
}
isStateful: false, Component: TLComponent<T, E> = (
{ shape, meta, events, isEditing, onShapeBlur, onShapeChange },
canBind: true, ref
) => {
canEdit: true,
canClone: true,
pathCache: new WeakMap<number[], string>([]),
defaultProps: {
id: 'id',
type: TLDrawShapeType.Sticky,
name: 'Sticky',
parentId: 'page',
childIndex: 1,
point: [0, 0],
size: [200, 200],
text: '',
rotation: 0,
style: defaultStyle,
},
shouldRender(prev, next) {
return next.size !== prev.size || next.style !== prev.style || next.text !== prev.text
},
Component({ events, shape, isEditing, onShapeBlur, onShapeChange, meta }, ref) {
const font = getStickyFontStyle(shape.style) const font = getStickyFontStyle(shape.style)
const { color, fill } = getStickyShapeStyle(shape.style, meta.isDarkMode) const { color, fill } = getStickyShapeStyle(shape.style, meta.isDarkMode)
@ -202,9 +192,9 @@ export const Sticky = new ShapeUtil<StickyShape, HTMLDivElement, TLDrawMeta>(()
</div> </div>
</HTMLContainer> </HTMLContainer>
) )
}, }
Indicator({ shape }) { Indicator: TLIndicator<T> = ({ shape }) => {
const { const {
size: [width, height], size: [width, height],
} = shape } = shape
@ -212,13 +202,21 @@ export const Sticky = new ShapeUtil<StickyShape, HTMLDivElement, TLDrawMeta>(()
return ( return (
<rect x={0} y={0} rx={3} ry={3} width={Math.max(1, width)} height={Math.max(1, height)} /> <rect x={0} y={0} rx={3} ry={3} width={Math.max(1, width)} height={Math.max(1, height)} />
) )
}, }
getBounds(shape) { getBounds = (shape: T) => {
return getBoundsRectangle(shape, this.boundsCache) return getBoundsRectangle(shape, this.boundsCache)
}, }
transform(shape, bounds, { transformOrigin, scaleX, scaleY }) { shouldRender = (prev: T, next: T) => {
return next.size !== prev.size || next.style !== prev.style || next.text !== prev.text
}
transform = (
shape: T,
bounds: TLBounds,
{ scaleX, scaleY, transformOrigin }: TLDrawTransformInfo<T>
): Partial<T> => {
const point = Vec.round([ const point = Vec.round([
bounds.minX + bounds.minX +
(bounds.width - shape.size[0]) * (scaleX < 0 ? 1 - transformOrigin[0] : transformOrigin[0]), (bounds.width - shape.size[0]) * (scaleX < 0 ? 1 - transformOrigin[0] : transformOrigin[0]),
@ -230,12 +228,23 @@ export const Sticky = new ShapeUtil<StickyShape, HTMLDivElement, TLDrawMeta>(()
return { return {
point, point,
} }
}, }
transformSingle(shape) { transformSingle = (shape: T): Partial<T> => {
return shape return shape
}, }
})) }
/* -------------------------------------------------- */
/* Helpers */
/* -------------------------------------------------- */
const PADDING = 16
const MIN_CONTAINER_HEIGHT = 200
function normalizeText(text: string) {
return text.replace(/\r?\n|\r/g, '\n')
}
const styledStickyContainer = css({ const styledStickyContainer = css({
pointerEvents: 'all', pointerEvents: 'all',

View file

@ -1,4 +1,4 @@
import { Text } from './text' import { Text } from '../'
describe('Text shape', () => { describe('Text shape', () => {
it('Creates a shape', () => { it('Creates a shape', () => {

View file

@ -1,85 +1,47 @@
/* eslint-disable @typescript-eslint/no-non-null-assertion */ /* eslint-disable @typescript-eslint/no-non-null-assertion */
import * as React from 'react' import * as React from 'react'
import { HTMLContainer, TLBounds, Utils, ShapeUtil } from '@tldraw/core' import { Utils, HTMLContainer, TLIndicator, TLComponent, TLBounds } from '@tldraw/core'
import { Vec } from '@tldraw/vec' import { defaultStyle, getShapeStyle, getFontStyle } from '../shape-styles'
import { getShapeStyle, getFontStyle, defaultStyle } from '~shape/shape-styles' import { TextShape, TLDrawShapeType, TLDrawTransformInfo } from '~types'
import { TextShape, TLDrawShapeType, TLDrawMeta } from '~types'
import css from '~styles'
import { TextAreaUtils } from '../shared' import { TextAreaUtils } from '../shared'
import { BINDING_DISTANCE } from '~constants' import { BINDING_DISTANCE } from '~constants'
import { TLDrawShapeUtil } from '../TLDrawShapeUtil'
import css from '~styles'
import Vec from '@tldraw/vec'
const LETTER_SPACING = -1.5 type T = TextShape
type E = HTMLDivElement
function normalizeText(text: string) { export class TextUtil extends TLDrawShapeUtil<T, E> {
return text.replace(/\r?\n|\r/g, '\n') type = TLDrawShapeType.Text as const
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any isAspectRatioLocked = true
let melm: any
function getMeasurementDiv() { canEdit = true
// A div used for measurement
document.getElementById('__textMeasure')?.remove()
const pre = document.createElement('pre') canBind = true
pre.id = '__textMeasure'
Object.assign(pre.style, { getShape = (props: Partial<T>): T => {
whiteSpace: 'pre', return Utils.deepMerge<T>(
width: 'auto', {
border: '1px solid red', id: 'id',
padding: '4px', type: TLDrawShapeType.Text,
margin: '0px', name: 'Text',
letterSpacing: `${LETTER_SPACING}px`, parentId: 'page',
opacity: '0', childIndex: 1,
position: 'absolute', point: [0, 0],
top: '-500px', rotation: 0,
left: '0px', text: ' ',
zIndex: '9999', style: defaultStyle,
pointerEvents: 'none', },
userSelect: 'none', props
alignmentBaseline: 'mathematical',
dominantBaseline: 'mathematical',
})
pre.tabIndex = -1
document.body.appendChild(pre)
return pre
}
if (typeof window !== 'undefined') {
melm = getMeasurementDiv()
}
export const Text = new ShapeUtil<TextShape, HTMLDivElement, TLDrawMeta>(() => ({
type: TLDrawShapeType.Text,
isAspectRatioLocked: true,
canEdit: true,
canBind: true,
defaultProps: {
id: 'id',
type: TLDrawShapeType.Text,
name: 'Text',
parentId: 'page',
childIndex: 1,
point: [0, 0],
rotation: 0,
text: ' ',
style: defaultStyle,
},
shouldRender(prev, next): boolean {
return (
next.text !== prev.text || next.style.scale !== prev.style.scale || next.style !== prev.style
) )
}, }
Component({ shape, meta, isEditing, isBinding, onShapeChange, onShapeBlur, events }, ref) { Component: TLComponent<T, E> = (
{ shape, isBinding, isEditing, onShapeBlur, onShapeChange, meta, events },
ref
) => {
const rInput = React.useRef<HTMLTextAreaElement>(null) const rInput = React.useRef<HTMLTextAreaElement>(null)
const { text, style } = shape const { text, style } = shape
const styles = getShapeStyle(style, meta.isDarkMode) const styles = getShapeStyle(style, meta.isDarkMode)
@ -217,14 +179,14 @@ export const Text = new ShapeUtil<TextShape, HTMLDivElement, TLDrawMeta>(() => (
</div> </div>
</HTMLContainer> </HTMLContainer>
) )
}, }
Indicator({ shape }) { Indicator: TLIndicator<T> = ({ shape }) => {
const { width, height } = this.getBounds(shape) const { width, height } = this.getBounds(shape)
return <rect x={0} y={0} width={width} height={height} /> return <rect x={0} y={0} width={width} height={height} />
}, }
getBounds(shape): TLBounds { getBounds = (shape: T) => {
const bounds = Utils.getFromCache(this.boundsCache, shape, () => { const bounds = Utils.getFromCache(this.boundsCache, shape, () => {
if (!melm) { if (!melm) {
// We're in SSR // We're in SSR
@ -249,9 +211,19 @@ export const Text = new ShapeUtil<TextShape, HTMLDivElement, TLDrawMeta>(() => (
}) })
return Utils.translateBounds(bounds, shape.point) return Utils.translateBounds(bounds, shape.point)
}, }
transform(_shape, bounds, { initialShape, scaleX, scaleY }) { shouldRender = (prev: T, next: T): boolean => {
return (
next.text !== prev.text || next.style.scale !== prev.style.scale || next.style !== prev.style
)
}
transform = (
shape: T,
bounds: TLBounds,
{ initialShape, scaleX, scaleY }: TLDrawTransformInfo<T>
): Partial<T> => {
const { const {
rotation = 0, rotation = 0,
style: { scale = 1 }, style: { scale = 1 },
@ -268,9 +240,13 @@ export const Text = new ShapeUtil<TextShape, HTMLDivElement, TLDrawMeta>(() => (
scale: nextScale, scale: nextScale,
}, },
} }
}, }
transformSingle(_shape, bounds, { initialShape, scaleX, scaleY }) { transformSingle = (
shape: T,
bounds: TLBounds,
{ initialShape, scaleX, scaleY }: TLDrawTransformInfo<T>
): Partial<T> | void => {
const { const {
style: { scale = 1 }, style: { scale = 1 },
} = initialShape } = initialShape
@ -282,9 +258,9 @@ export const Text = new ShapeUtil<TextShape, HTMLDivElement, TLDrawMeta>(() => (
scale: scale * Math.max(Math.abs(scaleY), Math.abs(scaleX)), scale: scale * Math.max(Math.abs(scaleY), Math.abs(scaleX)),
}, },
} }
}, }
onDoubleClickBoundsHandle(shape) { onDoubleClickBoundsHandle = (shape: T) => {
const center = this.getCenter(shape) const center = this.getCenter(shape)
const newCenter = this.getCenter({ const newCenter = this.getCenter({
@ -302,13 +278,57 @@ export const Text = new ShapeUtil<TextShape, HTMLDivElement, TLDrawMeta>(() => (
}, },
point: Vec.round(Vec.add(shape.point, Vec.sub(center, newCenter))), point: Vec.round(Vec.add(shape.point, Vec.sub(center, newCenter))),
} }
}, }
})) }
/* -------------------------------------------------- */ /* -------------------------------------------------- */
/* Helpers */ /* Helpers */
/* -------------------------------------------------- */ /* -------------------------------------------------- */
const LETTER_SPACING = -1.5
function normalizeText(text: string) {
return text.replace(/\r?\n|\r/g, '\n')
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let melm: any
function getMeasurementDiv() {
// A div used for measurement
document.getElementById('__textMeasure')?.remove()
const pre = document.createElement('pre')
pre.id = '__textMeasure'
Object.assign(pre.style, {
whiteSpace: 'pre',
width: 'auto',
border: '1px solid red',
padding: '4px',
margin: '0px',
letterSpacing: `${LETTER_SPACING}px`,
opacity: '0',
position: 'absolute',
top: '-500px',
left: '0px',
zIndex: '9999',
pointerEvents: 'none',
userSelect: 'none',
alignmentBaseline: 'mathematical',
dominantBaseline: 'mathematical',
})
pre.tabIndex = -1
document.body.appendChild(pre)
return pre
}
if (typeof window !== 'undefined') {
melm = getMeasurementDiv()
}
const wrapper = css({ const wrapper = css({
width: '100%', width: '100%',
height: '100%', height: '100%',

View file

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

View file

@ -1,19 +0,0 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { Rectangle, Ellipse, Arrow, Draw, Text, Group, Sticky } from './shapes'
import { TLDrawShapeType, TLDrawShape, TLDrawShapeUtil } from '~types'
// This is a bad "any", but the "this" context stuff we're doing doesn't allow us to union the types
export const tldrawShapeUtils: Record<TLDrawShapeType, any> = {
[TLDrawShapeType.Rectangle]: Rectangle,
[TLDrawShapeType.Ellipse]: Ellipse,
[TLDrawShapeType.Draw]: Draw,
[TLDrawShapeType.Arrow]: Arrow,
[TLDrawShapeType.Text]: Text,
[TLDrawShapeType.Group]: Group,
[TLDrawShapeType.Sticky]: Sticky,
}
export function getShapeUtils<T extends TLDrawShape>(type: T['type']) {
if (!tldrawShapeUtils[type]) throw Error(`Could not find a util of type ${type}`)
return tldrawShapeUtils[type] as TLDrawShapeUtil<T>
}

View file

@ -1,7 +0,0 @@
export * from './draw'
export * from './arrow'
export * from './rectangle'
export * from './ellipse'
export * from './text'
export * from './group'
export * from './sticky'

View file

@ -7,7 +7,7 @@ export function resetBounds(data: Data, ids: string[], pageId: string): TLDrawCo
const { before, after } = TLDR.mutateShapes( const { before, after } = TLDR.mutateShapes(
data, data,
ids, ids,
(shape) => TLDR.getShapeUtils(shape).onDoubleClickBoundsHandle(shape), (shape) => TLDR.getShapeUtils(shape).onDoubleClickBoundsHandle?.(shape),
pageId pageId
) )

View file

@ -1,5 +1 @@
export const FIT_TO_SCREEN_PADDING = 128 /* eslint-disable @typescript-eslint/no-explicit-any */
export const SNAP_DISTANCE = 5
export const EMPTY_ARRAY = [] as any[]
export const SLOW_SPEED = 10
export const VERY_SLOW_SPEED = 2.5

View file

@ -7,11 +7,13 @@ import {
Session, Session,
TLDrawStatus, TLDrawStatus,
SessionType, SessionType,
TLDrawShapeType,
} from '~types' } from '~types'
import { Vec } from '@tldraw/vec' import { Vec } from '@tldraw/vec'
import { Utils, TLBounds } from '@tldraw/core' import { Utils, TLBounds } from '@tldraw/core'
import { TLDR } from '~state/tldr' import { TLDR } from '~state/tldr'
import { BINDING_DISTANCE } from '~constants' import { BINDING_DISTANCE } from '~constants'
import { shapeUtils } from '~shape-utils'
export class ArrowSession extends Session { export class ArrowSession extends Session {
static type = SessionType.Arrow static type = SessionType.Arrow
@ -108,9 +110,9 @@ export class ArrowSession extends Session {
bindingId: undefined, bindingId: undefined,
} }
const utils = TLDR.getShapeUtils<ArrowShape>(shape.type) const utils = shapeUtils[TLDrawShapeType.Arrow]
const change = utils.onHandleChange( const change = utils.onHandleChange?.(
shape, shape,
{ {
[handleId]: handle, [handleId]: handle,
@ -181,7 +183,7 @@ export class ArrowSession extends Session {
const targetUtils = TLDR.getShapeUtils(target) const targetUtils = TLDR.getShapeUtils(target)
const arrowChange = TLDR.getShapeUtils<ArrowShape>(next.shape.type).onBindingChange( const arrowChange = TLDR.getShapeUtils<ArrowShape>(next.shape.type).onBindingChange?.(
next.shape, next.shape,
startBinding, startBinding,
target, target,
@ -257,7 +259,9 @@ export class ArrowSession extends Session {
const targetUtils = TLDR.getShapeUtils(target) const targetUtils = TLDR.getShapeUtils(target)
const arrowChange = TLDR.getShapeUtils<ArrowShape>(next.shape.type).onBindingChange( const utils = shapeUtils[TLDrawShapeType.Arrow]
const arrowChange = utils.onBindingChange(
next.shape, next.shape,
draggedBinding, draggedBinding,
target, target,

View file

@ -20,8 +20,8 @@ export class BrushSession extends Session {
update = ( update = (
data: Data, data: Data,
point: number[], point: number[],
shiftKey = false, _shiftKey = false,
altKey = false, _altKey = false,
metaKey = false metaKey = false
): TLDrawPatch => { ): TLDrawPatch => {
const { snapshot, origin } = this const { snapshot, origin } = this

View file

@ -54,7 +54,7 @@ export class HandleSession extends Session {
// First update the handle's next point // First update the handle's next point
const change = TLDR.getShapeUtils(shape).onHandleChange( const change = TLDR.getShapeUtils(shape).onHandleChange?.(
shape, shape,
{ {
[handleId]: handle, [handleId]: handle,

View file

@ -11,7 +11,7 @@ import { SessionType, TLDrawShape, TLDrawStatus } from '~types'
import { Session } from '~types' import { Session } from '~types'
import type { Data } from '~types' import type { Data } from '~types'
import { TLDR } from '~state/tldr' import { TLDR } from '~state/tldr'
import { SLOW_SPEED, SNAP_DISTANCE } from '~state/constants' import { SLOW_SPEED, SNAP_DISTANCE } from '~constants'
type SnapInfo = type SnapInfo =
| { | {
@ -54,7 +54,7 @@ export class TransformSingleSession extends Session {
return void null return void null
} }
update = (data: Data, point: number[], shiftKey = false, altKey = false, metaKey = false) => { update = (data: Data, point: number[], shiftKey = false, _altKey = false, metaKey = false) => {
const { transformType } = this const { transformType } = this
const { currentPageId, initialShapeBounds, initialShape, id } = this.snapshot const { currentPageId, initialShapeBounds, initialShape, id } = this.snapshot

View file

@ -5,7 +5,7 @@ import { Session, SessionType, TLDrawShape, TLDrawStatus } from '~types'
import type { Data } from '~types' import type { Data } from '~types'
import { TLDR } from '~state/tldr' import { TLDR } from '~state/tldr'
import type { Command } from 'rko' import type { Command } from 'rko'
import { SLOW_SPEED, SNAP_DISTANCE } from '~state/constants' import { SLOW_SPEED, SNAP_DISTANCE } from '~constants'
type SnapInfo = type SnapInfo =
| { | {

View file

@ -14,7 +14,7 @@ import {
ArrowBinding, ArrowBinding,
TLDrawShapeType, TLDrawShapeType,
} from '~types' } from '~types'
import { SLOW_SPEED, SNAP_DISTANCE } from '~state/constants' import { SLOW_SPEED, SNAP_DISTANCE } from '~constants'
import { TLDR } from '~state/tldr' import { TLDR } from '~state/tldr'
import type { Patch } from 'rko' import type { Patch } from 'rko'

View file

@ -1,5 +1,5 @@
import { TLBounds, TLTransformInfo, Utils, TLPageState } from '@tldraw/core' import { TLBounds, TLTransformInfo, Utils, TLPageState } from '@tldraw/core'
import { getShapeUtils } from '~shape' import { getShapeUtils, TLDrawShapeUtil } from '~shape-utils'
import { import {
Data, Data,
ShapeStyles, ShapeStyles,
@ -9,7 +9,6 @@ import {
TLDrawPage, TLDrawPage,
TLDrawCommand, TLDrawCommand,
TLDrawPatch, TLDrawPatch,
TLDrawShapeUtil,
TLDrawShapeType, TLDrawShapeType,
ArrowShape, ArrowShape,
} from '~types' } from '~types'
@ -21,7 +20,7 @@ export class TLDR {
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
static getShapeUtils<T extends TLDrawShape>(shape: T): TLDrawShapeUtil<T> static getShapeUtils<T extends TLDrawShape>(shape: T): TLDrawShapeUtil<T>
static getShapeUtils<T extends TLDrawShape>(shape: T | T['type']) { static getShapeUtils<T extends TLDrawShape>(shape: T | T['type']) {
return getShapeUtils<T>(typeof shape === 'string' ? shape : shape.type) return getShapeUtils<T>(shape)
} }
static getSelectedShapes(data: Data, pageId: string) { static getSelectedShapes(data: Data, pageId: string) {
@ -607,7 +606,7 @@ export class TLDR {
} }
static onSessionComplete<T extends TLDrawShape>(shape: T) { static onSessionComplete<T extends TLDrawShape>(shape: T) {
const delta = TLDR.getShapeUtils(shape).onSessionComplete(shape) const delta = TLDR.getShapeUtils(shape).onSessionComplete?.(shape)
if (!delta) return shape if (!delta) return shape
return { ...shape, ...delta } return { ...shape, ...delta }
} }
@ -615,7 +614,7 @@ export class TLDR {
static onChildrenChange<T extends TLDrawShape>(data: Data, shape: T, pageId: string) { static onChildrenChange<T extends TLDrawShape>(data: Data, shape: T, pageId: string) {
if (!shape.children) return if (!shape.children) return
const delta = TLDR.getShapeUtils(shape).onChildrenChange( const delta = TLDR.getShapeUtils(shape).onChildrenChange?.(
shape, shape,
shape.children.map((id) => TLDR.getShape(data, id, pageId)) shape.children.map((id) => TLDR.getShape(data, id, pageId))
) )
@ -630,7 +629,7 @@ export class TLDR {
binding: TLDrawBinding, binding: TLDrawBinding,
otherShape: TLDrawShape otherShape: TLDrawShape
) { ) {
const delta = TLDR.getShapeUtils(shape).onBindingChange( const delta = TLDR.getShapeUtils(shape).onBindingChange?.(
shape, shape,
binding, binding,
otherShape, otherShape,
@ -684,7 +683,7 @@ export class TLDR {
// of rotating the shape. Shapes with handles should never be rotated, // of rotating the shape. Shapes with handles should never be rotated,
// because that makes a lot of other things incredible difficult. // because that makes a lot of other things incredible difficult.
if (shape.handles !== undefined) { if (shape.handles !== undefined) {
const change = this.getShapeUtils(shape).onHandleChange( const change = this.getShapeUtils(shape).onHandleChange?.(
// Base the change on a shape with the next point // Base the change on a shape with the next point
{ ...shape, point: nextPoint }, { ...shape, point: nextPoint },
Object.fromEntries( Object.fromEntries(

View file

@ -2,7 +2,6 @@
import { TLDrawState } from './tlstate' import { TLDrawState } from './tlstate'
import { mockDocument, TLStateUtils } from '~test' import { mockDocument, TLStateUtils } from '~test'
import { ArrowShape, ColorStyle, SessionType, TLDrawShapeType } from '~types' import { ArrowShape, ColorStyle, SessionType, TLDrawShapeType } from '~types'
import * as idb from 'idb-keyval'
import type { SelectTool } from './tool/SelectTool' import type { SelectTool } from './tool/SelectTool'
describe('TLDrawState', () => { describe('TLDrawState', () => {

View file

@ -39,13 +39,13 @@ import {
ExceptFirstTwo, ExceptFirstTwo,
} from '~types' } from '~types'
import { TLDR } from './tldr' import { TLDR } from './tldr'
import { defaultStyle, tldrawShapeUtils } from '~shape' import { defaultStyle, shapeUtils } from '~shape-utils'
import * as Commands from './command' import * as Commands from './command'
import { ArgsOfType, getSession } from './session' import { ArgsOfType, getSession } from './session'
import { sample, USER_COLORS } from './utils' import { sample } from './utils'
import { createTools, ToolType } from './tool' import { createTools, ToolType } from './tool'
import type { BaseTool } from './tool/BaseTool' import type { BaseTool } from './tool/BaseTool'
import * as constants from './constants' import { USER_COLORS, FIT_TO_SCREEN_PADDING } from '~constants'
const uuid = Utils.uniqueId() const uuid = Utils.uniqueId()
@ -218,7 +218,7 @@ export class TLDrawState extends StateManager<Data> {
const fromUtils = TLDR.getShapeUtils(fromShape) const fromUtils = TLDR.getShapeUtils(fromShape)
// We only need to update the binding's "from" shape // We only need to update the binding's "from" shape
const fromDelta = fromUtils.onBindingChange( const fromDelta = fromUtils.onBindingChange?.(
fromShape, fromShape,
binding, binding,
toShape, toShape,
@ -1428,8 +1428,8 @@ export class TLDrawState extends StateManager<Data> {
let zoom = TLDR.getCameraZoom( let zoom = TLDR.getCameraZoom(
Math.min( Math.min(
(this.bounds.width - constants.FIT_TO_SCREEN_PADDING) / bounds.width, (this.bounds.width - FIT_TO_SCREEN_PADDING) / bounds.width,
(this.bounds.height - constants.FIT_TO_SCREEN_PADDING) / bounds.height (this.bounds.height - FIT_TO_SCREEN_PADDING) / bounds.height
) )
) )
@ -1458,8 +1458,8 @@ export class TLDrawState extends StateManager<Data> {
let zoom = TLDR.getCameraZoom( let zoom = TLDR.getCameraZoom(
Math.min( Math.min(
(this.bounds.width - constants.FIT_TO_SCREEN_PADDING) / bounds.width, (this.bounds.width - FIT_TO_SCREEN_PADDING) / bounds.width,
(this.bounds.height - constants.FIT_TO_SCREEN_PADDING) / bounds.height (this.bounds.height - FIT_TO_SCREEN_PADDING) / bounds.height
) )
) )
@ -1901,7 +1901,7 @@ export class TLDrawState extends StateManager<Data> {
const id = Utils.uniqueId() const id = Utils.uniqueId()
const Text = tldrawShapeUtils.text const Text = shapeUtils[TLDrawShapeType.Text]
const newShape = Text.create({ const newShape = Text.create({
id, id,

View file

@ -1,6 +1,6 @@
import Vec from '@tldraw/vec' import Vec from '@tldraw/vec'
import { Utils, TLPointerEventHandler } from '@tldraw/core' import { Utils, TLPointerEventHandler } from '@tldraw/core'
import { Arrow } from '~shape/shapes' import { Arrow } from '~shape-utils'
import { SessionType, TLDrawShapeType } from '~types' import { SessionType, TLDrawShapeType } from '~types'
import { BaseTool, Status } from '../BaseTool' import { BaseTool, Status } from '../BaseTool'

View file

@ -1,6 +1,6 @@
import Vec from '@tldraw/vec' import Vec from '@tldraw/vec'
import { Utils, TLPointerEventHandler } from '@tldraw/core' import { Utils, TLPointerEventHandler } from '@tldraw/core'
import { Draw } from '~shape/shapes' import { Draw } from '~shape-utils'
import { SessionType, TLDrawShapeType } from '~types' import { SessionType, TLDrawShapeType } from '~types'
import { BaseTool, Status } from '../BaseTool' import { BaseTool, Status } from '../BaseTool'

View file

@ -1,6 +1,6 @@
import Vec from '@tldraw/vec' import Vec from '@tldraw/vec'
import { Utils, TLPointerEventHandler, TLBoundsCorner } from '@tldraw/core' import { Utils, TLPointerEventHandler, TLBoundsCorner } from '@tldraw/core'
import { Ellipse } from '~shape/shapes' import { Ellipse } from '~shape-utils'
import { SessionType, TLDrawShapeType } from '~types' import { SessionType, TLDrawShapeType } from '~types'
import { BaseTool, Status } from '../BaseTool' import { BaseTool, Status } from '../BaseTool'

View file

@ -1,6 +1,6 @@
import Vec from '@tldraw/vec' import Vec from '@tldraw/vec'
import { Utils, TLPointerEventHandler, TLBoundsCorner } from '@tldraw/core' import { Utils, TLPointerEventHandler, TLBoundsCorner } from '@tldraw/core'
import { Rectangle } from '~shape/shapes' import { Rectangle } from '~shape-utils'
import { SessionType, TLDrawShapeType } from '~types' import { SessionType, TLDrawShapeType } from '~types'
import { BaseTool, Status } from '../BaseTool' import { BaseTool, Status } from '../BaseTool'

View file

@ -1,7 +1,7 @@
import Vec from '@tldraw/vec' import Vec from '@tldraw/vec'
import type { TLPointerEventHandler } from '@tldraw/core' import type { TLPointerEventHandler } from '@tldraw/core'
import { Utils } from '@tldraw/core' import { Utils } from '@tldraw/core'
import { Sticky } from '~shape/shapes' import { Sticky } from '~shape-utils'
import { SessionType, TLDrawShapeType } from '~types' import { SessionType, TLDrawShapeType } from '~types'
import { BaseTool, Status } from '../BaseTool' import { BaseTool, Status } from '../BaseTool'

View file

@ -1,71 +1 @@
import type { Easing } from '~types'
export const PI2 = Math.PI * 2
export const EASINGS: Record<Easing, (t: number) => number> = {
linear: (t) => t,
easeInQuad: (t) => t * t,
easeOutQuad: (t) => t * (2 - t),
easeInOutQuad: (t) => (t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t),
easeInCubic: (t) => t * t * t,
easeOutCubic: (t) => --t * t * t + 1,
easeInOutCubic: (t) => (t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1),
easeInQuart: (t) => t * t * t * t,
easeOutQuart: (t) => 1 - --t * t * t * t,
easeInOutQuart: (t) => (t < 0.5 ? 8 * t * t * t * t : 1 - 8 * --t * t * t * t),
easeInQuint: (t) => t * t * t * t * t,
easeOutQuint: (t) => 1 + --t * t * t * t * t,
easeInOutQuint: (t) => (t < 0.5 ? 16 * t * t * t * t * t : 1 + 16 * --t * t * t * t * t),
easeInSine: (t) => 1 - Math.cos((t * Math.PI) / 2),
easeOutSine: (t) => Math.sin((t * Math.PI) / 2),
easeInOutSine: (t) => -(Math.cos(Math.PI * t) - 1) / 2,
easeInExpo: (t) => (t <= 0 ? 0 : Math.pow(2, 10 * t - 10)),
easeOutExpo: (t) => (t >= 1 ? 1 : 1 - Math.pow(2, -10 * t)),
easeInOutExpo: (t) =>
t <= 0
? 0
: t >= 1
? 1
: t < 0.5
? Math.pow(2, 20 * t - 10) / 2
: (2 - Math.pow(2, -20 * t + 10)) / 2,
}
export const EASING_STRINGS: Record<Easing, string> = {
linear: `(t) => t`,
easeInQuad: `(t) => t * t`,
easeOutQuad: `(t) => t * (2 - t)`,
easeInOutQuad: `(t) => (t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t)`,
easeInCubic: `(t) => t * t * t`,
easeOutCubic: `(t) => --t * t * t + 1`,
easeInOutCubic: `(t) => t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1`,
easeInQuart: `(t) => t * t * t * t`,
easeOutQuart: `(t) => 1 - --t * t * t * t`,
easeInOutQuart: `(t) => t < 0.5 ? 8 * t * t * t * t : 1 - 8 * --t * t * t * t`,
easeInQuint: `(t) => t * t * t * t * t`,
easeOutQuint: `(t) => 1 + --t * t * t * t * t`,
easeInOutQuint: `(t) => t < 0.5 ? 16 * t * t * t * t * t : 1 + 16 * --t * t * t * t * t`,
easeInSine: `(t) => 1 - Math.cos((t * Math.PI) / 2)`,
easeOutSine: `(t) => Math.sin((t * Math.PI) / 2)`,
easeInOutSine: `(t) => -(Math.cos(Math.PI * t) - 1) / 2`,
easeInExpo: `(t) => (t <= 0 ? 0 : Math.pow(2, 10 * t - 10))`,
easeOutExpo: `(t) => (t >= 1 ? 1 : 1 - Math.pow(2, -10 * t))`,
easeInOutExpo: `(t) => t <= 0 ? 0 : t >= 1 ? 1 : t < 0.5 ? Math.pow(2, 20 * t - 10) / 2 : (2 - Math.pow(2, -20 * t + 10)) / 2`,
}
export const USER_COLORS = [
'#EC5E41',
'#F2555A',
'#F04F88',
'#E34BA9',
'#BD54C6',
'#9D5BD2',
'#7B66DC',
'#02B1CC',
'#11B3A3',
'#39B178',
'#55B467',
'#FF802B',
]
export const sample = (arr: any[]) => arr[Math.floor(Math.random() * arr.length)] export const sample = (arr: any[]) => arr[Math.floor(Math.random() * arr.length)]

View file

@ -1,11 +1,28 @@
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable @typescript-eslint/ban-types */ /* eslint-disable @typescript-eslint/ban-types */
import type { TLBinding, TLShapeProps, TLBounds, TLSnapLine } from '@tldraw/core' import type {
import type { TLShape, TLShapeUtil, TLHandle } from '@tldraw/core' TLBinding,
TLBoundsCorner,
TLBoundsEdge,
TLShapeProps,
TLShape,
TLHandle,
TLBounds,
TLSnapLine,
} from '@tldraw/core'
import type { TLPage, TLUser, TLPageState } from '@tldraw/core' import type { TLPage, TLUser, TLPageState } from '@tldraw/core'
import type { StoreApi } from 'zustand' import type { StoreApi } from 'zustand'
import type { Command, Patch } from 'rko' import type { Command, Patch } from 'rko'
export interface TLDrawTransformInfo<T extends TLShape> {
type: TLBoundsEdge | TLBoundsCorner
initialShape: T
scaleX: number
scaleY: number
transformOrigin: number[]
}
// old
export type TLStore = StoreApi<Data> export type TLStore = StoreApi<Data>
export type TLChange = Data export type TLChange = Data
@ -257,8 +274,6 @@ export type TLDrawShape =
| GroupShape | GroupShape
| StickyShape | StickyShape
export type TLDrawShapeUtil<T extends TLDrawShape> = TLShapeUtil<T, any, TLDrawMeta>
export type ArrowBinding = TLBinding<{ export type ArrowBinding = TLBinding<{
handleId: keyof ArrowShape['handles'] handleId: keyof ArrowShape['handles']
distance: number distance: number

View file

@ -264,7 +264,7 @@ export class Vec {
* @param A * @param A
* @param r rotation in radians * @param r rotation in radians
*/ */
static rot = (A: number[], r: number): number[] => { static rot = (A: number[], r = 0): number[] => {
return [A[0] * Math.cos(r) - A[1] * Math.sin(r), A[0] * Math.sin(r) + A[1] * Math.cos(r)] return [A[0] * Math.cos(r) - A[1] * Math.sin(r), A[0] * Math.sin(r) + A[1] * Math.cos(r)]
} }
@ -274,7 +274,7 @@ export class Vec {
* @param C center * @param C center
* @param r rotation in radians * @param r rotation in radians
*/ */
static rotWith = (A: number[], C: number[], r: number): number[] => { static rotWith = (A: number[], C: number[], r = 0): number[] => {
if (r === 0) return A if (r === 0) return A
const s = Math.sin(r) const s = Math.sin(r)

View file

@ -1,6 +1,5 @@
/* eslint-disable @typescript-eslint/no-non-null-assertion */ /* eslint-disable @typescript-eslint/no-non-null-assertion */
import { TLDraw, TLDrawState, Data, TLDrawDocument, TLDrawUser } from '@tldraw/tldraw' import { TLDraw, TLDrawState, Data, TLDrawDocument, TLDrawUser } from '@tldraw/tldraw'
import * as gtag from '-utils/gtag'
import * as React from 'react' import * as React from 'react'
import { createClient, Presence } from '@liveblocks/client' import { createClient, Presence } from '@liveblocks/client'
import { LiveblocksProvider, RoomProvider, useObject, useErrorListener } from '@liveblocks/react' import { LiveblocksProvider, RoomProvider, useObject, useErrorListener } from '@liveblocks/react'
@ -59,15 +58,18 @@ function Editor({ id }: { id: string }) {
}) })
// Put the tlstate into the window, for debugging. // Put the tlstate into the window, for debugging.
const handleMount = React.useCallback((tlstate: TLDrawState) => { const handleMount = React.useCallback(
// eslint-disable-next-line @typescript-eslint/ban-ts-comment (tlstate: TLDrawState) => {
// @ts-ignore // eslint-disable-next-line @typescript-eslint/ban-ts-comment
window.tlstate = tlstate // @ts-ignore
window.tlstate = tlstate
tlstate.loadRoom(id) tlstate.loadRoom(id)
setTlstate(tlstate) setTlstate(tlstate)
}, []) },
[id]
)
const handleChange = React.useCallback( const handleChange = React.useCallback(
(_tlstate: TLDrawState, state: Data, reason: string) => { (_tlstate: TLDrawState, state: Data, reason: string) => {

View file

@ -24,11 +24,12 @@
"@sentry/tracing": "^6.13.2", "@sentry/tracing": "^6.13.2",
"@stitches/react": "^1.0.0", "@stitches/react": "^1.0.0",
"@tldraw/tldraw": "^0.0.128", "@tldraw/tldraw": "^0.0.128",
"next": "^11.1.2", "@types/next-auth": "^3.15.0",
"next": "^12.0.1",
"next-auth": "^3.29.0", "next-auth": "^3.29.0",
"next-pwa": "^5.2.23", "next-pwa": "^5.4.0",
"next-themes": "^0.0.15", "next-themes": "^0.0.15",
"next-transpile-modules": "^8.0.0", "next-transpile-modules": "^9.0.0",
"react": "17.0.2", "react": "17.0.2",
"react-dom": "17.0.2" "react-dom": "17.0.2"
}, },

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -2,7 +2,11 @@
"compilerOptions": { "compilerOptions": {
"composite": true, "composite": true,
"target": "es5", "target": "es5",
"lib": ["dom", "dom.iterable", "esnext"], "lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true, "allowJs": true,
"skipLibCheck": true, "skipLibCheck": true,
"strict": false, "strict": false,
@ -17,11 +21,29 @@
"baseUrl": ".", "baseUrl": ".",
"rootDir": ".", "rootDir": ".",
"paths": { "paths": {
"-*": ["./*"], "-*": [
"@tldraw/tldraw": ["../tldraw"] "./*"
} ],
"@tldraw/tldraw": [
"../tldraw"
]
},
"incremental": true
}, },
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], "include": [
"exclude": ["node_modules"], "next-env.d.ts",
"references": [{ "path": "../tldraw" }, { "path": "../core" }] "**/*.ts",
"**/*.tsx"
],
"exclude": [
"node_modules"
],
"references": [
{
"path": "../tldraw"
},
{
"path": "../core"
}
]
} }

497
yarn.lock
View file

@ -881,14 +881,7 @@
core-js-pure "^3.16.0" core-js-pure "^3.16.0"
regenerator-runtime "^0.13.4" regenerator-runtime "^0.13.4"
"@babel/runtime@7.15.3": "@babel/runtime@7.15.4", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.14.0", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2":
version "7.15.3"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.15.3.tgz#2e1c2880ca118e5b2f9988322bd8a7656a32502b"
integrity sha512-OvwMLqNXkCXSz1kSm58sEsNuhqOx/fKpnUnKnFB5v8uDda5bLNEHNgKPvhDN6IU0LDcnHQ90LlJ0Q6jnyBSIBA==
dependencies:
regenerator-runtime "^0.13.4"
"@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.14.0", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2":
version "7.15.4" version "7.15.4"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.15.4.tgz#fd17d16bfdf878e6dd02d19753a39fa8a8d9c84a" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.15.4.tgz#fd17d16bfdf878e6dd02d19753a39fa8a8d9c84a"
integrity sha512-99catp6bHCaxr4sJ/DbTGgHS4+Rs2RVd2g7iOap6SLGPDknRK9ztKNsE/Fg6QhSeh1FGE5f6gHGQmvvn3I3xhw== integrity sha512-99catp6bHCaxr4sJ/DbTGgHS4+Rs2RVd2g7iOap6SLGPDknRK9ztKNsE/Fg6QhSeh1FGE5f6gHGQmvvn3I3xhw==
@ -2673,10 +2666,10 @@
require_optional "^1.0.1" require_optional "^1.0.1"
typeorm "^0.2.30" typeorm "^0.2.30"
"@next/env@11.1.2": "@next/env@12.0.1":
version "11.1.2" version "12.0.1"
resolved "https://registry.yarnpkg.com/@next/env/-/env-11.1.2.tgz#27996efbbc54c5f949f5e8c0a156e3aa48369b99" resolved "https://registry.yarnpkg.com/@next/env/-/env-12.0.1.tgz#d57141ef1fe844f6f7c18cdaf29a712788c18ca4"
integrity sha512-+fteyVdQ7C/OoulfcF6vd1Yk0FEli4453gr8kSFbU8sKseNSizYq6df5MKz/AjwLptsxrUeIkgBdAzbziyJ3mA== integrity sha512-+eJ8mQbAcV/ZILRAgIx9xwDg6hrqm6m/7QLfEvsf2BPnsh+fwU4Xf1zgcbyqD2V4ja4OTWG6ow+Hiukgap3mZQ==
"@next/eslint-plugin-next@11.1.2": "@next/eslint-plugin-next@11.1.2":
version "11.1.2" version "11.1.2"
@ -2685,15 +2678,15 @@
dependencies: dependencies:
glob "7.1.7" glob "7.1.7"
"@next/polyfill-module@11.1.2": "@next/polyfill-module@12.0.1":
version "11.1.2" version "12.0.1"
resolved "https://registry.yarnpkg.com/@next/polyfill-module/-/polyfill-module-11.1.2.tgz#1fe92c364fdc81add775a16c678f5057c6aace98" resolved "https://registry.yarnpkg.com/@next/polyfill-module/-/polyfill-module-12.0.1.tgz#d20abf06f686ee7a8bd0d9056accfd0662f19e87"
integrity sha512-xZmixqADM3xxtqBV0TpAwSFzWJP0MOQzRfzItHXf1LdQHWb0yofHHC+7eOrPFic8+ZGz5y7BdPkkgR1S25OymA== integrity sha512-fTrndwGuvrQO+4myVGcPtsYI4/tmZBhHHJId7MSHWz+9gW4NFgsmDlr8OI9Th2ZXpqk5WHLsTYQ+dLiQp1zV4g==
"@next/react-dev-overlay@11.1.2": "@next/react-dev-overlay@12.0.1":
version "11.1.2" version "12.0.1"
resolved "https://registry.yarnpkg.com/@next/react-dev-overlay/-/react-dev-overlay-11.1.2.tgz#73795dc5454b7af168bac93df7099965ebb603be" resolved "https://registry.yarnpkg.com/@next/react-dev-overlay/-/react-dev-overlay-12.0.1.tgz#134299ae44fad5a59448d5e671518074f37cba95"
integrity sha512-rDF/mGY2NC69mMg2vDqzVpCOlWqnwPUXB2zkARhvknUHyS6QJphPYv9ozoPJuoT/QBs49JJd9KWaAzVBvq920A== integrity sha512-dLv1to40bvadbr0VO8pBsbr9ddgktCLilfejOpEFQkOOrdQBUuIfegqqEDiCL9THkAO3QGYY4t/ZPfv9wrxLZQ==
dependencies: dependencies:
"@babel/code-frame" "7.12.11" "@babel/code-frame" "7.12.11"
anser "1.4.9" anser "1.4.9"
@ -2705,32 +2698,67 @@
shell-quote "1.7.2" shell-quote "1.7.2"
source-map "0.8.0-beta.0" source-map "0.8.0-beta.0"
stacktrace-parser "0.1.10" stacktrace-parser "0.1.10"
strip-ansi "6.0.0" strip-ansi "6.0.1"
"@next/react-refresh-utils@11.1.2": "@next/react-refresh-utils@12.0.1":
version "11.1.2" version "12.0.1"
resolved "https://registry.yarnpkg.com/@next/react-refresh-utils/-/react-refresh-utils-11.1.2.tgz#44ea40d8e773e4b77bad85e24f6ac041d5e4b4a5" resolved "https://registry.yarnpkg.com/@next/react-refresh-utils/-/react-refresh-utils-12.0.1.tgz#219be7a81696a7bd1e2d4ee397ca100eb8262f23"
integrity sha512-hsoJmPfhVqjZ8w4IFzoo8SyECVnN+8WMnImTbTKrRUHOVJcYMmKLL7xf7T0ft00tWwAl/3f3Q3poWIN2Ueql/Q== integrity sha512-CjTBR9a6ai+2fUT8KFya9AiTaCnfDY34H6pDmtdJdkD+vY08AwtPpv10kzsgNEhsL06210yVzH59IsEQLBIllA==
"@next/swc-darwin-arm64@11.1.2": "@next/swc-android-arm64@12.0.1":
version "11.1.2" version "12.0.1"
resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-11.1.2.tgz#93226c38db488c4b62b30a53b530e87c969b8251" resolved "https://registry.yarnpkg.com/@next/swc-android-arm64/-/swc-android-arm64-12.0.1.tgz#c776853e0911c12fcc69a69cd7ab111dff29f8d2"
integrity sha512-hZuwOlGOwBZADA8EyDYyjx3+4JGIGjSHDHWrmpI7g5rFmQNltjlbaefAbiU5Kk7j3BUSDwt30quJRFv3nyJQ0w== integrity sha512-zI/6zsZuO2igknzHzfaQep0PeD3d4/qdjXUcQLwLHJQtGdhPvZFMke1z3BBWZqePHVsR1JPjE4QTii7udF5qsQ==
"@next/swc-darwin-x64@11.1.2": "@next/swc-darwin-arm64@12.0.1":
version "11.1.2" version "12.0.1"
resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-11.1.2.tgz#792003989f560c00677b5daeff360b35b510db83" resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.0.1.tgz#bee9c5932511c993ab384ef9aedb86c02532d41e"
integrity sha512-PGOp0E1GisU+EJJlsmJVGE+aPYD0Uh7zqgsrpD3F/Y3766Ptfbe1lEPPWnRDl+OzSSrSrX1lkyM/Jlmh5OwNvA== integrity sha512-vRfHz7rEt9+TTfwi3uY9ObUSLhzMmgVZ96b+yOSmZ6Kxs/V46IXHOLawCnoldXylpskZ/+HTWcrB1D3aimGeZA==
"@next/swc-linux-x64-gnu@11.1.2": "@next/swc-darwin-x64@12.0.1":
version "11.1.2" version "12.0.1"
resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-11.1.2.tgz#8216b2ae1f21f0112958735c39dd861088108f37" resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-12.0.1.tgz#a0bdcbcf11b8b62190ec8e0406cecbbcc810b7fc"
integrity sha512-YcDHTJjn/8RqvyJVB6pvEKXihDcdrOwga3GfMv/QtVeLphTouY4BIcEUfrG5+26Nf37MP1ywN3RRl1TxpurAsQ== integrity sha512-mM7QLIqRUqR8I74gbZ4Uq+dY8k3Whrs98wK+vPurmDTBhXhaVnAYblEkEwe0DJGqlmjD4w6faYfCydmFI69jqw==
"@next/swc-win32-x64-msvc@11.1.2": "@next/swc-linux-arm-gnueabihf@12.0.1":
version "11.1.2" version "12.0.1"
resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-11.1.2.tgz#e15824405df137129918205e43cb5e9339589745" resolved "https://registry.yarnpkg.com/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-12.0.1.tgz#d0132637288f452ad5c6a6161e42aebcd4355f82"
integrity sha512-e/pIKVdB+tGQYa1cW3sAeHm8gzEri/HYLZHT4WZojrUxgWXqx8pk7S7Xs47uBcFTqBDRvK3EcQpPLf3XdVsDdg== integrity sha512-QF5LVyAWTah5i1p/yG4a8nTGRXerHoDkS3kWYCdjcwlALOiAJ9m0GUTks/O47izNokBAbZnL7URUdvtGFjP0Ng==
"@next/swc-linux-arm64-gnu@12.0.1":
version "12.0.1"
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.0.1.tgz#6b310344b9bac7700eaff8f4c536540b1226e378"
integrity sha512-ETFUh373WsjUJJr32GHSDlVSgwFwS+EJUJuSH40Pr4xB6250YxuRk8ccF6QR5LHqTL4tbbVEEfCD8sZVnccP8w==
"@next/swc-linux-arm64-musl@12.0.1":
version "12.0.1"
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.0.1.tgz#8ab1fc81d18bbb70bb15bcc4250382257bba6298"
integrity sha512-pfnXNjKywXyp2DJsjFhkfOlvcNu9xa8HgEhCUKXm1OZ4pGnpeb1+UD4t5Pn9b9ggiWPzauZK1abR/9nShvbSzw==
"@next/swc-linux-x64-gnu@12.0.1":
version "12.0.1"
resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.0.1.tgz#a664268aedec402da5df34efac1b337d9b0e492e"
integrity sha512-d9cXS27Ar7TTtA3BJ8gxosDDdVNSFy4MQiwsszKlEiqfGrnINeXKdVgeiOa+xxq+JxNvPzonp4sbX6k8InIocg==
"@next/swc-linux-x64-musl@12.0.1":
version "12.0.1"
resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-12.0.1.tgz#4b7e5fee5a62adb6d9c9aad1a4aa00a6a09b53dc"
integrity sha512-4SAmi7riavU6TFGX7wQFioFi/vx8uJ2/Cx7ZfrYiZzzKmmuu2eM8onW1kcKu+aQD777x/kvzW4+2pWkM2gyPOA==
"@next/swc-win32-arm64-msvc@12.0.1":
version "12.0.1"
resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.0.1.tgz#9ff0c2a2f00f41d40bd44d6da195bdf649d807c6"
integrity sha512-JRad3QyXvs5zDkeEmc6z5tEvm/ZZnjnsBY921zWw7OIcIZR5wAs+1AnRVjIxHTEHSExxOvBgPyEMpgVkB8OyxQ==
"@next/swc-win32-ia32-msvc@12.0.1":
version "12.0.1"
resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.0.1.tgz#5a927ec832b184ce2e35f8ec668daa34175e47d0"
integrity sha512-ierQmzVWPi6a7PqrdgfI6nrQ/SWJ9W5jllByyQeFIOKhOzZiz030Tw+U6V7NqE3gGNeRwpj56Iya8nUb3hlM1g==
"@next/swc-win32-x64-msvc@12.0.1":
version "12.0.1"
resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.0.1.tgz#fe145cf7baf79564159a87a545e430f96c835578"
integrity sha512-li3CCXpdMX0+wJlQpy0xZmHCgHMebaBf5X2BIAJrv8cQXYc6dejeojttXLFNCF0dNAo3UzlbP6h7N+8p6Wbakw==
"@node-rs/helper@1.2.1", "@node-rs/helper@^1.0.0": "@node-rs/helper@1.2.1", "@node-rs/helper@^1.0.0":
version "1.2.1" version "1.2.1"
@ -3837,6 +3865,13 @@
resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.2.tgz#ee771e2ba4b3dc5b372935d549fd9617bf345b8c" resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.2.tgz#ee771e2ba4b3dc5b372935d549fd9617bf345b8c"
integrity sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ== integrity sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==
"@types/next-auth@^3.15.0":
version "3.15.0"
resolved "https://registry.yarnpkg.com/@types/next-auth/-/next-auth-3.15.0.tgz#b602f4689b35fff3d2af09500c79ab11c4745bca"
integrity sha512-ZVfejlu81YiIRX1m0iKAfvZ3nK7K9EyZWhNARNKsFop8kNAgEvMnlKpTpwN59xkK2OhyWLagPuiDAVBYSO9jSA==
dependencies:
next-auth "*"
"@types/node@*", "@types/node@>= 8", "@types/node@^16.7.10": "@types/node@*", "@types/node@>= 8", "@types/node@^16.7.10":
version "16.9.4" version "16.9.4"
resolved "https://registry.yarnpkg.com/@types/node/-/node-16.9.4.tgz#a12f0ee7847cf17a97f6fdf1093cb7a9af23cca4" resolved "https://registry.yarnpkg.com/@types/node/-/node-16.9.4.tgz#a12f0ee7847cf17a97f6fdf1093cb7a9af23cca4"
@ -3933,21 +3968,11 @@
resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39" resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39"
integrity sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew== integrity sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==
"@types/source-list-map@*":
version "0.1.2"
resolved "https://registry.yarnpkg.com/@types/source-list-map/-/source-list-map-0.1.2.tgz#0078836063ffaf17412349bba364087e0ac02ec9"
integrity sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA==
"@types/stack-utils@^2.0.0": "@types/stack-utils@^2.0.0":
version "2.0.1" version "2.0.1"
resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c" resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c"
integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw== integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==
"@types/tapable@^1":
version "1.0.8"
resolved "https://registry.yarnpkg.com/@types/tapable/-/tapable-1.0.8.tgz#b94a4391c85666c7b73299fd3ad79d4faa435310"
integrity sha512-ipixuVrh2OdNmauvtT51o3d8z12p6LtFW9in7U79der/kwejjdNchQC5UMn5u/KxNoM7VHHOs/l8KS8uHxhODQ==
"@types/testing-library__jest-dom@^5.9.1": "@types/testing-library__jest-dom@^5.9.1":
version "5.14.1" version "5.14.1"
resolved "https://registry.yarnpkg.com/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.14.1.tgz#014162a5cee6571819d48e999980694e2f657c3c" resolved "https://registry.yarnpkg.com/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.14.1.tgz#014162a5cee6571819d48e999980694e2f657c3c"
@ -3960,34 +3985,6 @@
resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-2.0.2.tgz#fc25ad9943bcac11cceb8168db4f275e0e72e756" resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-2.0.2.tgz#fc25ad9943bcac11cceb8168db4f275e0e72e756"
integrity sha512-F5DIZ36YVLE+PN+Zwws4kJogq47hNgX3Nx6WyDJ3kcplxyke3XIzB8uK5n/Lpm1HBsbGzd6nmGehL8cPekP+Tg== integrity sha512-F5DIZ36YVLE+PN+Zwws4kJogq47hNgX3Nx6WyDJ3kcplxyke3XIzB8uK5n/Lpm1HBsbGzd6nmGehL8cPekP+Tg==
"@types/uglify-js@*":
version "3.13.1"
resolved "https://registry.yarnpkg.com/@types/uglify-js/-/uglify-js-3.13.1.tgz#5e889e9e81e94245c75b6450600e1c5ea2878aea"
integrity sha512-O3MmRAk6ZuAKa9CHgg0Pr0+lUOqoMLpc9AS4R8ano2auvsg7IE8syF3Xh/NPr26TWklxYcqoEEFdzLLs1fV9PQ==
dependencies:
source-map "^0.6.1"
"@types/webpack-sources@*":
version "3.2.0"
resolved "https://registry.yarnpkg.com/@types/webpack-sources/-/webpack-sources-3.2.0.tgz#16d759ba096c289034b26553d2df1bf45248d38b"
integrity sha512-Ft7YH3lEVRQ6ls8k4Ff1oB4jN6oy/XmU6tQISKdhfh+1mR+viZFphS6WL0IrtDOzvefmJg5a0s7ZQoRXwqTEFg==
dependencies:
"@types/node" "*"
"@types/source-list-map" "*"
source-map "^0.7.3"
"@types/webpack@^4.4.31":
version "4.41.31"
resolved "https://registry.yarnpkg.com/@types/webpack/-/webpack-4.41.31.tgz#c35f252a3559ddf9c85c0d8b0b42019025e581aa"
integrity sha512-/i0J7sepXFIp1ZT7FjUGi1eXMCg8HCCzLJEQkKsOtbJFontsJLolBcDC+3qxn5pPwiCt1G0ZdRmYRzNBtvpuGQ==
dependencies:
"@types/node" "*"
"@types/tapable" "^1"
"@types/uglify-js" "*"
"@types/webpack-sources" "*"
anymatch "^3.0.0"
source-map "^0.6.0"
"@types/yargs-parser@*": "@types/yargs-parser@*":
version "20.2.1" version "20.2.1"
resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-20.2.1.tgz#3b9ce2489919d9e4fea439b76916abc34b2df129" resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-20.2.1.tgz#3b9ce2489919d9e4fea439b76916abc34b2df129"
@ -4136,16 +4133,21 @@ acorn-walk@^8.1.1:
resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1"
integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==
acorn@8.5.0, acorn@^8.2.4, acorn@^8.4.1:
version "8.5.0"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.5.0.tgz#4512ccb99b3698c752591e9bb4472e38ad43cee2"
integrity sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q==
acorn@^6.2.1:
version "6.4.2"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.2.tgz#35866fd710528e92de10cf06016498e47e39e1e6"
integrity sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==
acorn@^7.1.1, acorn@^7.4.0: acorn@^7.1.1, acorn@^7.4.0:
version "7.4.1" version "7.4.1"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa"
integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==
acorn@^8.2.4, acorn@^8.4.1:
version "8.5.0"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.5.0.tgz#4512ccb99b3698c752591e9bb4472e38ad43cee2"
integrity sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q==
add-stream@^1.0.0: add-stream@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/add-stream/-/add-stream-1.0.0.tgz#6a7990437ca736d5e1288db92bd3266d5f5cb2aa" resolved "https://registry.yarnpkg.com/add-stream/-/add-stream-1.0.0.tgz#6a7990437ca736d5e1288db92bd3266d5f5cb2aa"
@ -4258,7 +4260,7 @@ ansi-regex@^4.1.0:
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997"
integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==
ansi-regex@^5.0.0: ansi-regex@^5.0.0, ansi-regex@^5.0.1:
version "5.0.1" version "5.0.1"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304"
integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==
@ -4292,7 +4294,7 @@ any-promise@^1.0.0:
resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f"
integrity sha1-q8av7tzqUugJzcA3au0845Y10X8= integrity sha1-q8av7tzqUugJzcA3au0845Y10X8=
anymatch@^3.0.0, anymatch@^3.0.3, anymatch@~3.1.1: anymatch@^3.0.3, anymatch@~3.1.1:
version "3.1.2" version "3.1.2"
resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716"
integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==
@ -4489,14 +4491,6 @@ assert@2.0.0:
object-is "^1.0.1" object-is "^1.0.1"
util "^0.12.0" util "^0.12.0"
assert@^1.1.1:
version "1.5.0"
resolved "https://registry.yarnpkg.com/assert/-/assert-1.5.0.tgz#55c109aaf6e0aefdb3dc4b71240c70bf574b18eb"
integrity sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==
dependencies:
object-assign "^4.1.1"
util "0.10.3"
assign-symbols@^1.0.0: assign-symbols@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367"
@ -4507,11 +4501,6 @@ ast-types-flow@^0.0.7:
resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.7.tgz#f70b735c6bca1a5c9c22d982c3e39e7feba3bdad" resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.7.tgz#f70b735c6bca1a5c9c22d982c3e39e7feba3bdad"
integrity sha1-9wtzXGvKGlycItmCw+Oef+ujva0= integrity sha1-9wtzXGvKGlycItmCw+Oef+ujva0=
ast-types@0.13.2:
version "0.13.2"
resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.13.2.tgz#df39b677a911a83f3a049644fb74fdded23cea48"
integrity sha512-uWMHxJxtfj/1oZClOxDEV1sQ1HCDkA4MG8Gr69KKeBjEVH0R84WlejZ0y2DcwyBlpAEMltmVYkVgqfLFb2oyiA==
astral-regex@^2.0.0: astral-regex@^2.0.0:
version "2.0.0" version "2.0.0"
resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31"
@ -4824,7 +4813,7 @@ browserify-sign@^4.0.0:
readable-stream "^3.6.0" readable-stream "^3.6.0"
safe-buffer "^5.2.0" safe-buffer "^5.2.0"
browserify-zlib@0.2.0, browserify-zlib@^0.2.0: browserify-zlib@0.2.0:
version "0.2.0" version "0.2.0"
resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.2.0.tgz#2869459d9aa3be245fe8fe2ca1f46e2e7f54d73f" resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.2.0.tgz#2869459d9aa3be245fe8fe2ca1f46e2e7f54d73f"
integrity sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA== integrity sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==
@ -4888,15 +4877,6 @@ buffer@5.6.0:
base64-js "^1.0.2" base64-js "^1.0.2"
ieee754 "^1.1.4" ieee754 "^1.1.4"
buffer@^4.3.0:
version "4.9.2"
resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.2.tgz#230ead344002988644841ab0244af8c44bbe3ef8"
integrity sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==
dependencies:
base64-js "^1.0.2"
ieee754 "^1.1.4"
isarray "^1.0.0"
buffer@^6.0.3: buffer@^6.0.3:
version "6.0.3" version "6.0.3"
resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6"
@ -5215,12 +5195,11 @@ clean-stack@^2.0.0:
resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b"
integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==
clean-webpack-plugin@^3.0.0: clean-webpack-plugin@^4.0.0:
version "3.0.0" version "4.0.0"
resolved "https://registry.yarnpkg.com/clean-webpack-plugin/-/clean-webpack-plugin-3.0.0.tgz#a99d8ec34c1c628a4541567aa7b457446460c62b" resolved "https://registry.yarnpkg.com/clean-webpack-plugin/-/clean-webpack-plugin-4.0.0.tgz#72947d4403d452f38ed61a9ff0ada8122aacd729"
integrity sha512-MciirUH5r+cYLGCOL5JX/ZLzOZbVr1ot3Fw+KcvbhUb6PM+yycqd9ZhIlcigQ5gl+XhppNmw3bEFuaaMNyLj3A== integrity sha512-WuWE1nyTNAyW5T7oNyys2EN0cfP2fdRxhxnIQWiAp0bMabPdHhoGxM8A6YL2GhqwgrPnnaemVE7nv5XJ2Fhh2w==
dependencies: dependencies:
"@types/webpack" "^4.4.31"
del "^4.1.1" del "^4.1.1"
cli-cursor@^2.1.0: cli-cursor@^2.1.0:
@ -5446,17 +5425,12 @@ config-chain@^1.1.11, config-chain@^1.1.12:
ini "^1.3.4" ini "^1.3.4"
proto-list "~1.2.1" proto-list "~1.2.1"
console-browserify@^1.1.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.2.0.tgz#67063cef57ceb6cf4993a2ab3a55840ae8c49336"
integrity sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==
console-control-strings@^1.0.0, console-control-strings@~1.1.0: console-control-strings@^1.0.0, console-control-strings@~1.1.0:
version "1.1.0" version "1.1.0"
resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=
constants-browserify@1.0.0, constants-browserify@^1.0.0: constants-browserify@1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75"
integrity sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U= integrity sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=
@ -5738,7 +5712,7 @@ cross-spawn@^7.0.2, cross-spawn@^7.0.3:
shebang-command "^2.0.0" shebang-command "^2.0.0"
which "^2.0.1" which "^2.0.1"
crypto-browserify@3.12.0, crypto-browserify@^3.11.0: crypto-browserify@3.12.0:
version "3.12.0" version "3.12.0"
resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec"
integrity sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg== integrity sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==
@ -6103,11 +6077,6 @@ domain-browser@4.19.0:
resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-4.19.0.tgz#1093e17c0a17dbd521182fe90d49ac1370054af1" resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-4.19.0.tgz#1093e17c0a17dbd521182fe90d49ac1370054af1"
integrity sha512-fRA+BaAWOR/yr/t7T9E9GJztHPeFjj8U35ajyAjCDtAAnTn1Rc1f6W6VGPJrO1tkQv9zWu+JRof7z6oQtiYVFQ== integrity sha512-fRA+BaAWOR/yr/t7T9E9GJztHPeFjj8U35ajyAjCDtAAnTn1Rc1f6W6VGPJrO1tkQv9zWu+JRof7z6oQtiYVFQ==
domain-browser@^1.1.1:
version "1.2.0"
resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda"
integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==
domexception@^1.0.1: domexception@^1.0.1:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/domexception/-/domexception-1.0.1.tgz#937442644ca6a31261ef36e3ec677fe805582c90" resolved "https://registry.yarnpkg.com/domexception/-/domexception-1.0.1.tgz#937442644ca6a31261ef36e3ec677fe805582c90"
@ -6722,7 +6691,7 @@ eventemitter3@^4.0.4:
resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f"
integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==
events@^3.0.0: events@3.3.0:
version "3.3.0" version "3.3.0"
resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400"
integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==
@ -7683,7 +7652,7 @@ http-signature@~1.2.0:
jsprim "^1.2.2" jsprim "^1.2.2"
sshpk "^1.7.0" sshpk "^1.7.0"
https-browserify@1.0.0, https-browserify@^1.0.0: https-browserify@1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73"
integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM= integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=
@ -7853,21 +7822,11 @@ inflight@^1.0.4:
once "^1.3.0" once "^1.3.0"
wrappy "1" wrappy "1"
inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3, inherits@~2.0.4: inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3, inherits@~2.0.4:
version "2.0.4" version "2.0.4"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
inherits@2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1"
integrity sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=
inherits@2.0.3:
version "2.0.3"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
ini@^1.3.2, ini@^1.3.4: ini@^1.3.2, ini@^1.3.4:
version "1.3.8" version "1.3.8"
resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c"
@ -8328,7 +8287,7 @@ isarray@0.0.1:
resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf"
integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=
isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: isarray@1.0.0, isarray@~1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
@ -9955,13 +9914,6 @@ nanomatch@^1.2.9:
snapdragon "^0.8.1" snapdragon "^0.8.1"
to-regex "^3.0.1" to-regex "^3.0.1"
native-url@0.3.4:
version "0.3.4"
resolved "https://registry.yarnpkg.com/native-url/-/native-url-0.3.4.tgz#29c943172aed86c63cee62c8c04db7f5756661f8"
integrity sha512-6iM8R99ze45ivyH8vybJ7X0yekIcPf5GgLV5K0ENCbmRcaRIDoj37BC8iLEmaaBfqqb8enuZ5p0uhY+lVAbAcA==
dependencies:
querystring "^0.2.0"
natural-compare@^1.4.0: natural-compare@^1.4.0:
version "1.4.0" version "1.4.0"
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
@ -9972,12 +9924,12 @@ negotiator@^0.6.2:
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb"
integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==
neo-async@^2.6.0: neo-async@^2.6.0, neo-async@^2.6.1:
version "2.6.2" version "2.6.2"
resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f"
integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==
next-auth@^3.29.0: next-auth@*, next-auth@^3.29.0:
version "3.29.0" version "3.29.0"
resolved "https://registry.yarnpkg.com/next-auth/-/next-auth-3.29.0.tgz#60ddbfc7ed8ae7d43ebb02c16dc58eebf5dcb337" resolved "https://registry.yarnpkg.com/next-auth/-/next-auth-3.29.0.tgz#60ddbfc7ed8ae7d43ebb02c16dc58eebf5dcb337"
integrity sha512-B//4QTv/1Of0D+roZ82URmI6L2JSbkKgeaKI7Mdrioq8lAzp9ff8NdmouvZL/7zwrPe2cUyM6MLYlasfuI3ZIQ== integrity sha512-B//4QTv/1Of0D+roZ82URmI6L2JSbkKgeaKI7Mdrioq8lAzp9ff8NdmouvZL/7zwrPe2cUyM6MLYlasfuI3ZIQ==
@ -9995,45 +9947,45 @@ next-auth@^3.29.0:
preact-render-to-string "^5.1.14" preact-render-to-string "^5.1.14"
querystring "^0.2.0" querystring "^0.2.0"
next-pwa@^5.2.23: next-pwa@^5.4.0:
version "5.3.1" version "5.4.0"
resolved "https://registry.yarnpkg.com/next-pwa/-/next-pwa-5.3.1.tgz#5bcd854422a452fd1fd56500d1c483664d9733d9" resolved "https://registry.yarnpkg.com/next-pwa/-/next-pwa-5.4.0.tgz#61587d0d5fc3c5304f23dd4f187888c1c717ec5e"
integrity sha512-Os6bf/lEYoztvsILYkAhDjiYfLNTprqEumxuv5DjhoFh4OpIzO7U0GKRI6MZluH4SfAoe0IdHz9knnZxybSnag== integrity sha512-0tTgZsGGFAd2L151Y8Tv8gB8Q6NdWA0aHZRGRm4mHPnq06ZeVXAucVNpHcAcqALKcdp54J2puV+BQAY72tShSA==
dependencies: dependencies:
babel-loader "^8.2.2" babel-loader "^8.2.2"
clean-webpack-plugin "^3.0.0" clean-webpack-plugin "^4.0.0"
globby "^11.0.4" globby "^11.0.4"
terser-webpack-plugin "^5.1.4" terser-webpack-plugin "^5.2.4"
workbox-webpack-plugin "^6.2.4" workbox-webpack-plugin "^6.3.0"
workbox-window "^6.2.4" workbox-window "^6.3.0"
next-themes@^0.0.15: next-themes@^0.0.15:
version "0.0.15" version "0.0.15"
resolved "https://registry.yarnpkg.com/next-themes/-/next-themes-0.0.15.tgz#ab0cee69cd763b77d41211f631e108beab39bf7d" resolved "https://registry.yarnpkg.com/next-themes/-/next-themes-0.0.15.tgz#ab0cee69cd763b77d41211f631e108beab39bf7d"
integrity sha512-LTmtqYi03c4gMTJmWwVK9XkHL7h0/+XrtR970Ujvtu3s0kZNeJN24aJsi4rkZOI8i19+qq6f8j+8Duwy5jqcrQ== integrity sha512-LTmtqYi03c4gMTJmWwVK9XkHL7h0/+XrtR970Ujvtu3s0kZNeJN24aJsi4rkZOI8i19+qq6f8j+8Duwy5jqcrQ==
next-transpile-modules@^8.0.0: next-transpile-modules@^9.0.0:
version "8.0.0" version "9.0.0"
resolved "https://registry.yarnpkg.com/next-transpile-modules/-/next-transpile-modules-8.0.0.tgz#56375cdc25ae5d23a834195f277fc2737b26cb97" resolved "https://registry.yarnpkg.com/next-transpile-modules/-/next-transpile-modules-9.0.0.tgz#133b1742af082e61cc76b02a0f12ffd40ce2bf90"
integrity sha512-Q2f2yB0zMJ8KJbIYAeZoIxG6cSfVk813zr6B5HzsLMBVcJ3FaF8lKr7WG66n0KlHCwjLSmf/6EkgI6QQVWHrDw== integrity sha512-VCNFOazIAnXn1hvgYYSTYMnoWgKgwlYh4lm1pKbSfiB3kj5ZYLcKVhfh3jkPOg1cnd9DP+pte9yCUocdPEUBTQ==
dependencies: dependencies:
enhanced-resolve "^5.7.0" enhanced-resolve "^5.7.0"
escalade "^3.1.1" escalade "^3.1.1"
next@^11.1.2: next@^12.0.1:
version "11.1.2" version "12.0.1"
resolved "https://registry.yarnpkg.com/next/-/next-11.1.2.tgz#527475787a9a362f1bc916962b0c0655cc05bc91" resolved "https://registry.yarnpkg.com/next/-/next-12.0.1.tgz#7b82a73bc185bfda7372e7e8309f9b38e6be9cb0"
integrity sha512-azEYL0L+wFjv8lstLru3bgvrzPvK0P7/bz6B/4EJ9sYkXeW8r5Bjh78D/Ol7VOg0EIPz0CXoe72hzAlSAXo9hw== integrity sha512-4MNXAbD9+Tmtejg0TOKbaP52Cgu4mIn2ejKMLHWV0acxWGkkcE7QvdZwvg5pkg3fQBMrgucOxxtmw4D7yWaZvg==
dependencies: dependencies:
"@babel/runtime" "7.15.3" "@babel/runtime" "7.15.4"
"@hapi/accept" "5.0.2" "@hapi/accept" "5.0.2"
"@next/env" "11.1.2" "@next/env" "12.0.1"
"@next/polyfill-module" "11.1.2" "@next/polyfill-module" "12.0.1"
"@next/react-dev-overlay" "11.1.2" "@next/react-dev-overlay" "12.0.1"
"@next/react-refresh-utils" "11.1.2" "@next/react-refresh-utils" "12.0.1"
"@node-rs/helper" "1.2.1" "@node-rs/helper" "1.2.1"
acorn "8.5.0"
assert "2.0.0" assert "2.0.0"
ast-types "0.13.2"
browserify-zlib "0.2.0" browserify-zlib "0.2.0"
browserslist "4.16.6" browserslist "4.16.6"
buffer "5.6.0" buffer "5.6.0"
@ -10046,40 +9998,48 @@ next@^11.1.2:
domain-browser "4.19.0" domain-browser "4.19.0"
encoding "0.1.13" encoding "0.1.13"
etag "1.8.1" etag "1.8.1"
events "3.3.0"
find-cache-dir "3.3.1" find-cache-dir "3.3.1"
get-orientation "1.1.2" get-orientation "1.1.2"
https-browserify "1.0.0" https-browserify "1.0.0"
image-size "1.0.0" image-size "1.0.0"
jest-worker "27.0.0-next.5" jest-worker "27.0.0-next.5"
native-url "0.3.4"
node-fetch "2.6.1" node-fetch "2.6.1"
node-html-parser "1.4.9" node-html-parser "1.4.9"
node-libs-browser "^2.2.1"
os-browserify "0.3.0" os-browserify "0.3.0"
p-limit "3.1.0" p-limit "3.1.0"
path-browserify "1.0.1" path-browserify "1.0.1"
pnp-webpack-plugin "1.6.4"
postcss "8.2.15" postcss "8.2.15"
process "0.11.10" process "0.11.10"
querystring-es3 "0.2.1" querystring-es3 "0.2.1"
raw-body "2.4.1" raw-body "2.4.1"
react-is "17.0.2" react-is "17.0.2"
react-refresh "0.8.3" react-refresh "0.8.3"
react-server-dom-webpack "0.0.0-experimental-3c4c1c470-20211021"
regenerator-runtime "0.13.4"
stream-browserify "3.0.0" stream-browserify "3.0.0"
stream-http "3.1.1" stream-http "3.1.1"
string_decoder "1.3.0" string_decoder "1.3.0"
styled-jsx "4.0.1" styled-jsx "5.0.0-beta.3"
timers-browserify "2.0.12" timers-browserify "2.0.12"
tty-browserify "0.0.1" tty-browserify "0.0.1"
use-subscription "1.5.1" use-subscription "1.5.1"
util "0.12.4" util "0.12.4"
vm-browserify "1.1.2" vm-browserify "1.1.2"
watchpack "2.1.1" watchpack "2.1.1"
web-streams-polyfill "3.0.3"
optionalDependencies: optionalDependencies:
"@next/swc-darwin-arm64" "11.1.2" "@next/swc-android-arm64" "12.0.1"
"@next/swc-darwin-x64" "11.1.2" "@next/swc-darwin-arm64" "12.0.1"
"@next/swc-linux-x64-gnu" "11.1.2" "@next/swc-darwin-x64" "12.0.1"
"@next/swc-win32-x64-msvc" "11.1.2" "@next/swc-linux-arm-gnueabihf" "12.0.1"
"@next/swc-linux-arm64-gnu" "12.0.1"
"@next/swc-linux-arm64-musl" "12.0.1"
"@next/swc-linux-x64-gnu" "12.0.1"
"@next/swc-linux-x64-musl" "12.0.1"
"@next/swc-win32-arm64-msvc" "12.0.1"
"@next/swc-win32-ia32-msvc" "12.0.1"
"@next/swc-win32-x64-msvc" "12.0.1"
nice-try@^1.0.4: nice-try@^1.0.4:
version "1.0.5" version "1.0.5"
@ -10157,35 +10117,6 @@ node-int64@^0.4.0:
resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b"
integrity sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs= integrity sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=
node-libs-browser@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.2.1.tgz#b64f513d18338625f90346d27b0d235e631f6425"
integrity sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==
dependencies:
assert "^1.1.1"
browserify-zlib "^0.2.0"
buffer "^4.3.0"
console-browserify "^1.1.0"
constants-browserify "^1.0.0"
crypto-browserify "^3.11.0"
domain-browser "^1.1.1"
events "^3.0.0"
https-browserify "^1.0.0"
os-browserify "^0.3.0"
path-browserify "0.0.1"
process "^0.11.10"
punycode "^1.2.4"
querystring-es3 "^0.2.0"
readable-stream "^2.3.3"
stream-browserify "^2.0.1"
stream-http "^2.7.2"
string_decoder "^1.0.0"
timers-browserify "^2.0.4"
tty-browserify "0.0.0"
url "^0.11.0"
util "^0.11.0"
vm-browserify "^1.0.1"
node-modules-regexp@^1.0.0: node-modules-regexp@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz#8d9dbe28964a4ac5712e9131642107c71e90ec40" resolved "https://registry.yarnpkg.com/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz#8d9dbe28964a4ac5712e9131642107c71e90ec40"
@ -10556,7 +10487,7 @@ optionator@^0.9.1:
type-check "^0.4.0" type-check "^0.4.0"
word-wrap "^1.2.3" word-wrap "^1.2.3"
os-browserify@0.3.0, os-browserify@^0.3.0: os-browserify@0.3.0:
version "0.3.0" version "0.3.0"
resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27"
integrity sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc= integrity sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=
@ -10863,11 +10794,6 @@ pascalcase@^0.1.1:
resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14"
integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=
path-browserify@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.1.tgz#e6c4ddd7ed3aa27c68a20cc4e50e1a4ee83bbc4a"
integrity sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==
path-browserify@1.0.1: path-browserify@1.0.1:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-1.0.1.tgz#d98454a9c3753d5790860f16f68867b9e46be1fd" resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-1.0.1.tgz#d98454a9c3753d5790860f16f68867b9e46be1fd"
@ -11051,13 +10977,6 @@ platform@1.3.6:
resolved "https://registry.yarnpkg.com/platform/-/platform-1.3.6.tgz#48b4ce983164b209c2d45a107adb31f473a6e7a7" resolved "https://registry.yarnpkg.com/platform/-/platform-1.3.6.tgz#48b4ce983164b209c2d45a107adb31f473a6e7a7"
integrity sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg== integrity sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==
pnp-webpack-plugin@1.6.4:
version "1.6.4"
resolved "https://registry.yarnpkg.com/pnp-webpack-plugin/-/pnp-webpack-plugin-1.6.4.tgz#c9711ac4dc48a685dabafc86f8b6dd9f8df84149"
integrity sha512-7Wjy+9E3WwLOEL30D+m8TSTF7qJJUJLONBnwQp0518siuMxUQUbgZwssaFX+QKlZkjHZcw/IpZCt/H0srrntSg==
dependencies:
ts-pnp "^1.1.6"
posix-character-classes@^0.1.0: posix-character-classes@^0.1.0:
version "0.1.1" version "0.1.1"
resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab"
@ -11119,7 +11038,7 @@ process-nextick-args@~2.0.0:
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==
process@0.11.10, process@^0.11.10: process@0.11.10:
version "0.11.10" version "0.11.10"
resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182"
integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI=
@ -11238,16 +11157,6 @@ pumpify@^1.3.3:
inherits "^2.0.3" inherits "^2.0.3"
pump "^2.0.0" pump "^2.0.0"
punycode@1.3.2:
version "1.3.2"
resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d"
integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=
punycode@^1.2.4:
version "1.4.1"
resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
integrity sha1-wNWmOycYgArY4esPpSachN1BhF4=
punycode@^2.1.0, punycode@^2.1.1: punycode@^2.1.0, punycode@^2.1.1:
version "2.1.1" version "2.1.1"
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
@ -11280,16 +11189,11 @@ query-string@^6.13.8:
split-on-first "^1.0.0" split-on-first "^1.0.0"
strict-uri-encode "^2.0.0" strict-uri-encode "^2.0.0"
querystring-es3@0.2.1, querystring-es3@^0.2.0: querystring-es3@0.2.1:
version "0.2.1" version "0.2.1"
resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73"
integrity sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM= integrity sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=
querystring@0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620"
integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=
querystring@^0.2.0: querystring@^0.2.0:
version "0.2.1" version "0.2.1"
resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.1.tgz#40d77615bb09d16902a85c3e38aa8b5ed761c2dd" resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.1.tgz#40d77615bb09d16902a85c3e38aa8b5ed761c2dd"
@ -11421,6 +11325,16 @@ react-router@5.2.1, react-router@^5.2.1:
tiny-invariant "^1.0.2" tiny-invariant "^1.0.2"
tiny-warning "^1.0.0" tiny-warning "^1.0.0"
react-server-dom-webpack@0.0.0-experimental-3c4c1c470-20211021:
version "0.0.0-experimental-3c4c1c470-20211021"
resolved "https://registry.yarnpkg.com/react-server-dom-webpack/-/react-server-dom-webpack-0.0.0-experimental-3c4c1c470-20211021.tgz#cdcaa2f19c8d820c1f4d31252319fb05e2de0e88"
integrity sha512-YyRlED5kR0C2aQ3IJ/8BR2TELt51RcDZhnUDKz+m/HU+Gb/qak0CZkG0A8Zxffom9VI6HFkUj1dRFZqm0Lh9Pg==
dependencies:
acorn "^6.2.1"
loose-envify "^1.1.0"
neo-async "^2.6.1"
object-assign "^4.1.1"
react-style-singleton@^2.1.0: react-style-singleton@^2.1.0:
version "2.1.1" version "2.1.1"
resolved "https://registry.yarnpkg.com/react-style-singleton/-/react-style-singleton-2.1.1.tgz#ce7f90b67618be2b6b94902a30aaea152ce52e66" resolved "https://registry.yarnpkg.com/react-style-singleton/-/react-style-singleton-2.1.1.tgz#ce7f90b67618be2b6b94902a30aaea152ce52e66"
@ -11557,7 +11471,7 @@ read@1, read@~1.0.1:
dependencies: dependencies:
mute-stream "~0.0.4" mute-stream "~0.0.4"
"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.6: "readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.6, readable-stream@~2.3.6:
version "2.3.7" version "2.3.7"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57"
integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==
@ -11647,6 +11561,11 @@ regenerate@^1.4.2:
resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a" resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a"
integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A== integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==
regenerator-runtime@0.13.4:
version "0.13.4"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.4.tgz#e96bf612a3362d12bb69f7e8f74ffeab25c7ac91"
integrity sha512-plpwicqEzfEyTQohIKktWigcLzmNStMGwbOUbykx51/29Z3JOGYldaaNGK7ngNXV+UcoqvIMmloZ48Sr74sd+g==
regenerator-runtime@^0.13.4: regenerator-runtime@^0.13.4:
version "0.13.9" version "0.13.9"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52"
@ -12454,14 +12373,6 @@ stream-browserify@3.0.0:
inherits "~2.0.4" inherits "~2.0.4"
readable-stream "^3.5.0" readable-stream "^3.5.0"
stream-browserify@^2.0.1:
version "2.0.2"
resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.2.tgz#87521d38a44aa7ee91ce1cd2a47df0cb49dd660b"
integrity sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==
dependencies:
inherits "~2.0.1"
readable-stream "^2.0.2"
stream-each@^1.1.0: stream-each@^1.1.0:
version "1.2.3" version "1.2.3"
resolved "https://registry.yarnpkg.com/stream-each/-/stream-each-1.2.3.tgz#ebe27a0c389b04fbcc233642952e10731afa9bae" resolved "https://registry.yarnpkg.com/stream-each/-/stream-each-1.2.3.tgz#ebe27a0c389b04fbcc233642952e10731afa9bae"
@ -12480,17 +12391,6 @@ stream-http@3.1.1:
readable-stream "^3.6.0" readable-stream "^3.6.0"
xtend "^4.0.2" xtend "^4.0.2"
stream-http@^2.7.2:
version "2.8.3"
resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.3.tgz#b2d242469288a5a27ec4fe8933acf623de6514fc"
integrity sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==
dependencies:
builtin-status-codes "^3.0.0"
inherits "^2.0.1"
readable-stream "^2.3.6"
to-arraybuffer "^1.0.0"
xtend "^4.0.0"
stream-parser@^0.3.1: stream-parser@^0.3.1:
version "0.3.1" version "0.3.1"
resolved "https://registry.yarnpkg.com/stream-parser/-/stream-parser-0.3.1.tgz#1618548694420021a1182ff0af1911c129761773" resolved "https://registry.yarnpkg.com/stream-parser/-/stream-parser-0.3.1.tgz#1618548694420021a1182ff0af1911c129761773"
@ -12586,7 +12486,7 @@ string.prototype.trimstart@^1.0.4:
call-bind "^1.0.2" call-bind "^1.0.2"
define-properties "^1.1.3" define-properties "^1.1.3"
string_decoder@1.3.0, string_decoder@^1.0.0, string_decoder@^1.1.1: string_decoder@1.3.0, string_decoder@^1.1.1:
version "1.3.0" version "1.3.0"
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e"
integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==
@ -12609,12 +12509,12 @@ stringify-object@^3.3.0:
is-obj "^1.0.1" is-obj "^1.0.1"
is-regexp "^1.0.0" is-regexp "^1.0.0"
strip-ansi@6.0.0, strip-ansi@^6.0.0: strip-ansi@6.0.1:
version "6.0.0" version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w== integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
dependencies: dependencies:
ansi-regex "^5.0.0" ansi-regex "^5.0.1"
strip-ansi@^3.0.0, strip-ansi@^3.0.1: strip-ansi@^3.0.0, strip-ansi@^3.0.1:
version "3.0.1" version "3.0.1"
@ -12637,6 +12537,13 @@ strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0:
dependencies: dependencies:
ansi-regex "^4.1.0" ansi-regex "^4.1.0"
strip-ansi@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532"
integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==
dependencies:
ansi-regex "^5.0.0"
strip-bom@^2.0.0: strip-bom@^2.0.0:
version "2.0.0" version "2.0.0"
resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e"
@ -12702,10 +12609,10 @@ strong-log-transformer@^2.0.0, strong-log-transformer@^2.1.0:
minimist "^1.2.0" minimist "^1.2.0"
through "^2.3.4" through "^2.3.4"
styled-jsx@4.0.1: styled-jsx@5.0.0-beta.3:
version "4.0.1" version "5.0.0-beta.3"
resolved "https://registry.yarnpkg.com/styled-jsx/-/styled-jsx-4.0.1.tgz#ae3f716eacc0792f7050389de88add6d5245b9e9" resolved "https://registry.yarnpkg.com/styled-jsx/-/styled-jsx-5.0.0-beta.3.tgz#400d16179b5dff10d5954ab8be27a9a1b7780dd2"
integrity sha512-Gcb49/dRB1k8B4hdK8vhW27Rlb2zujCk1fISrizCcToIs+55B4vmUM0N9Gi4nnVfFZWe55jRdWpAqH1ldAKWvQ== integrity sha512-HtDDGSFPvmjHIqWf9n8Oo54tAoY/DTplvlyOH2+YOtD80Sp31Ap8ffSmxhgk5EkUoJ7xepdXMGT650mSffWuRA==
dependencies: dependencies:
"@babel/plugin-syntax-jsx" "7.14.5" "@babel/plugin-syntax-jsx" "7.14.5"
"@babel/types" "7.15.0" "@babel/types" "7.15.0"
@ -12858,7 +12765,7 @@ terminal-link@^2.0.0:
ansi-escapes "^4.2.1" ansi-escapes "^4.2.1"
supports-hyperlinks "^2.0.0" supports-hyperlinks "^2.0.0"
terser-webpack-plugin@^5.1.4: terser-webpack-plugin@^5.2.4:
version "5.2.4" version "5.2.4"
resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.2.4.tgz#ad1be7639b1cbe3ea49fab995cbe7224b31747a1" resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.2.4.tgz#ad1be7639b1cbe3ea49fab995cbe7224b31747a1"
integrity sha512-E2CkNMN+1cho04YpdANyRrn8CyN4yMy+WdFKZIySFZrGXZxJwJP6PMNGGc/Mcr6qygQHUUqRxnAPmi0M9f00XA== integrity sha512-E2CkNMN+1cho04YpdANyRrn8CyN4yMy+WdFKZIySFZrGXZxJwJP6PMNGGc/Mcr6qygQHUUqRxnAPmi0M9f00XA==
@ -12945,7 +12852,7 @@ through@2, "through@>=2.2.7 <3", through@^2.3.4, through@^2.3.6:
resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=
timers-browserify@2.0.12, timers-browserify@^2.0.4: timers-browserify@2.0.12:
version "2.0.12" version "2.0.12"
resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.12.tgz#44a45c11fbf407f34f97bccd1577c652361b00ee" resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.12.tgz#44a45c11fbf407f34f97bccd1577c652361b00ee"
integrity sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ== integrity sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==
@ -12974,11 +12881,6 @@ tmpl@1.0.x:
resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc"
integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==
to-arraybuffer@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43"
integrity sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=
to-fast-properties@^2.0.0: to-fast-properties@^2.0.0:
version "2.0.0" version "2.0.0"
resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e"
@ -13095,11 +12997,6 @@ ts-node@^10.2.1:
make-error "^1.1.1" make-error "^1.1.1"
yn "3.1.1" yn "3.1.1"
ts-pnp@^1.1.6:
version "1.2.0"
resolved "https://registry.yarnpkg.com/ts-pnp/-/ts-pnp-1.2.0.tgz#a500ad084b0798f1c3071af391e65912c86bca92"
integrity sha512-csd+vJOb/gkzvcCHgTGSChYpy5f1/XKNsmvBGO4JXS+z1v2HobugDz4s1IeFXM3wZB44uczs+eazB5Q/ccdhQw==
tsconfig-paths@^3.11.0, tsconfig-paths@^3.9.0: tsconfig-paths@^3.11.0, tsconfig-paths@^3.9.0:
version "3.11.0" version "3.11.0"
resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.11.0.tgz#954c1fe973da6339c78e06b03ce2e48810b65f36" resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.11.0.tgz#954c1fe973da6339c78e06b03ce2e48810b65f36"
@ -13135,11 +13032,6 @@ tsutils@^3.21.0:
dependencies: dependencies:
tslib "^1.8.1" tslib "^1.8.1"
tty-browserify@0.0.0:
version "0.0.0"
resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6"
integrity sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=
tty-browserify@0.0.1: tty-browserify@0.0.1:
version "0.0.1" version "0.0.1"
resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.1.tgz#3f05251ee17904dfd0677546670db9651682b811" resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.1.tgz#3f05251ee17904dfd0677546670db9651682b811"
@ -13427,14 +13319,6 @@ urix@^0.1.0:
resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72"
integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=
url@^0.11.0:
version "0.11.0"
resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1"
integrity sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=
dependencies:
punycode "1.3.2"
querystring "0.2.0"
use-callback-ref@^1.2.3: use-callback-ref@^1.2.3:
version "1.2.5" version "1.2.5"
resolved "https://registry.yarnpkg.com/use-callback-ref/-/use-callback-ref-1.2.5.tgz#6115ed242cfbaed5915499c0a9842ca2912f38a5" resolved "https://registry.yarnpkg.com/use-callback-ref/-/use-callback-ref-1.2.5.tgz#6115ed242cfbaed5915499c0a9842ca2912f38a5"
@ -13472,13 +13356,6 @@ util-promisify@^2.1.0:
dependencies: dependencies:
object.getownpropertydescriptors "^2.0.3" object.getownpropertydescriptors "^2.0.3"
util@0.10.3:
version "0.10.3"
resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9"
integrity sha1-evsa/lCAUkZInj23/g7TeTNqwPk=
dependencies:
inherits "2.0.1"
util@0.12.4, util@^0.12.0: util@0.12.4, util@^0.12.0:
version "0.12.4" version "0.12.4"
resolved "https://registry.yarnpkg.com/util/-/util-0.12.4.tgz#66121a31420df8f01ca0c464be15dfa1d1850253" resolved "https://registry.yarnpkg.com/util/-/util-0.12.4.tgz#66121a31420df8f01ca0c464be15dfa1d1850253"
@ -13491,13 +13368,6 @@ util@0.12.4, util@^0.12.0:
safe-buffer "^5.1.2" safe-buffer "^5.1.2"
which-typed-array "^1.1.2" which-typed-array "^1.1.2"
util@^0.11.0:
version "0.11.1"
resolved "https://registry.yarnpkg.com/util/-/util-0.11.1.tgz#3236733720ec64bb27f6e26f421aaa2e1b588d61"
integrity sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==
dependencies:
inherits "2.0.3"
uuid@^3.0.1, uuid@^3.3.2: uuid@^3.0.1, uuid@^3.3.2:
version "3.4.0" version "3.4.0"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
@ -13546,7 +13416,7 @@ verror@1.10.0:
core-util-is "1.0.2" core-util-is "1.0.2"
extsprintf "^1.2.0" extsprintf "^1.2.0"
vm-browserify@1.1.2, vm-browserify@^1.0.1: vm-browserify@1.1.2:
version "1.1.2" version "1.1.2"
resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0" resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0"
integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ== integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==
@ -13592,6 +13462,11 @@ wcwidth@^1.0.0:
dependencies: dependencies:
defaults "^1.0.3" defaults "^1.0.3"
web-streams-polyfill@3.0.3:
version "3.0.3"
resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.0.3.tgz#f49e487eedeca47a207c1aee41ee5578f884b42f"
integrity sha512-d2H/t0eqRNM4w2WvmTdoeIvzAUSpK7JmATB8Nr2lb7nQ9BTIJVjbQ/TRFVEh2gUH1HwclPdoPtfMoFfetXaZnA==
webidl-conversions@^3.0.0: webidl-conversions@^3.0.0:
version "3.0.1" version "3.0.1"
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"
@ -13875,7 +13750,7 @@ workbox-sw@6.3.0:
resolved "https://registry.yarnpkg.com/workbox-sw/-/workbox-sw-6.3.0.tgz#8b805a3ac5339e8df0e6ba36c491d9cd01aa9f3f" resolved "https://registry.yarnpkg.com/workbox-sw/-/workbox-sw-6.3.0.tgz#8b805a3ac5339e8df0e6ba36c491d9cd01aa9f3f"
integrity sha512-xwrXRBzw5jwJ7VdAQkTSNTbNZ4S6VhXtbZZ0vY6XKNQARO5nuGphNdif+hJFIejHUgtV6ESpQnixPj5hYB2jKQ== integrity sha512-xwrXRBzw5jwJ7VdAQkTSNTbNZ4S6VhXtbZZ0vY6XKNQARO5nuGphNdif+hJFIejHUgtV6ESpQnixPj5hYB2jKQ==
workbox-webpack-plugin@^6.2.4: workbox-webpack-plugin@^6.3.0:
version "6.3.0" version "6.3.0"
resolved "https://registry.yarnpkg.com/workbox-webpack-plugin/-/workbox-webpack-plugin-6.3.0.tgz#86c6c6fcb5fc151e6b4ccd8d7041d3da6a4a4271" resolved "https://registry.yarnpkg.com/workbox-webpack-plugin/-/workbox-webpack-plugin-6.3.0.tgz#86c6c6fcb5fc151e6b4ccd8d7041d3da6a4a4271"
integrity sha512-3l5H8h7O2eUgTAISQoglDe4VJDDYTZaDnkRY0FY2+eFOXA+fZoWuDSmLiMnA0uYqPC4NWVTZwP549E0dWgiWjw== integrity sha512-3l5H8h7O2eUgTAISQoglDe4VJDDYTZaDnkRY0FY2+eFOXA+fZoWuDSmLiMnA0uYqPC4NWVTZwP549E0dWgiWjw==
@ -13887,7 +13762,7 @@ workbox-webpack-plugin@^6.2.4:
webpack-sources "^1.4.3" webpack-sources "^1.4.3"
workbox-build "6.3.0" workbox-build "6.3.0"
workbox-window@6.3.0, workbox-window@^6.2.4: workbox-window@6.3.0, workbox-window@^6.3.0:
version "6.3.0" version "6.3.0"
resolved "https://registry.yarnpkg.com/workbox-window/-/workbox-window-6.3.0.tgz#f669a0715363c35e519d1b6d919e04da7ce369ea" resolved "https://registry.yarnpkg.com/workbox-window/-/workbox-window-6.3.0.tgz#f669a0715363c35e519d1b6d919e04da7ce369ea"
integrity sha512-CFP84assX9srH/TOx4OD8z4EBPO/Cq4WKdV2YLcJIFJmVTS/cB63XKeidKl2KJk8qOOLVIKnaO7BLmb0MxGFtA== integrity sha512-CFP84assX9srH/TOx4OD8z4EBPO/Cq4WKdV2YLcJIFJmVTS/cB63XKeidKl2KJk8qOOLVIKnaO7BLmb0MxGFtA==
@ -14018,7 +13893,7 @@ xmlchars@^2.2.0:
resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb"
integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==
xtend@^4.0.0, xtend@^4.0.2, xtend@~4.0.1: xtend@^4.0.2, xtend@~4.0.1:
version "4.0.2" version "4.0.2"
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==