make sure everything marked @public gets documented (#3892)

Previously, we had the `ae-forgotten-export` rule from api-extractor
disabled. This rule makes sure that everything that's referred to in the
public API is actually exported. There are more details on the rule
[here](https://api-extractor.com/pages/messages/ae-forgotten-export/),
but not exporting public API entires is bad because they're hard to
document and can't be typed/called from consumer code. For us, the big
effect is that they don't appear in our docs at all.

This diff re-enables that rule. Now, if you introduce something new to
the public API but don't export it, your build will fail.

### Change Type

- [x] `docs` — Changes to the documentation, examples, or templates.
- [x] `improvement` — Improving existing features
This commit is contained in:
alex 2024-06-10 14:50:03 +01:00 committed by GitHub
parent f5a6ed7b91
commit fb0dd1d2fe
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
87 changed files with 2378 additions and 1014 deletions

View file

@ -1,17 +1,11 @@
import { import { TLV1Document, TldrawUiButton, TldrawUiButtonLabel, useEditor, useValue } from 'tldraw'
LegacyTldrawDocument,
TldrawUiButton,
TldrawUiButtonLabel,
useEditor,
useValue,
} from 'tldraw'
export function MigrationAnnouncement({ export function MigrationAnnouncement({
onClose, onClose,
originalFile, originalFile,
}: { }: {
onClose: () => void onClose: () => void
originalFile: { name: string; document: LegacyTldrawDocument } originalFile: { name: string; document: TLV1Document }
}) { }) {
const editor = useEditor() const editor = useEditor()
const isDarkMode = useValue('is dark mode', () => editor.user.getIsDarkMode(), [editor]) const isDarkMode = useValue('is dark mode', () => editor.user.getIsDarkMode(), [editor])

View file

@ -1,5 +1,5 @@
import { openDB } from 'idb' import { openDB } from 'idb'
import { Editor, LegacyTldrawDocument, buildFromV1Document } from 'tldraw' import { Editor, TLV1Document, buildFromV1Document } from 'tldraw'
export function isEditorEmpty(editor: Editor) { export function isEditorEmpty(editor: Editor) {
const hasAnyShapes = editor.store.allRecords().some((r) => r.typeName === 'shape') const hasAnyShapes = editor.store.allRecords().some((r) => r.typeName === 'shape')
@ -7,7 +7,7 @@ export function isEditorEmpty(editor: Editor) {
} }
export async function findV1ContentFromIdb(): Promise<{ export async function findV1ContentFromIdb(): Promise<{
document: LegacyTldrawDocument document: TLV1Document
clear: () => Promise<void> clear: () => Promise<void>
} | null> { } | null> {
try { try {
@ -28,7 +28,7 @@ export async function findV1ContentFromIdb(): Promise<{
typeof home.document.version === 'number' typeof home.document.version === 'number'
) { ) {
return { return {
document: home.document as LegacyTldrawDocument, document: home.document as TLV1Document,
clear: async () => { clear: async () => {
try { try {
const tx = db.transaction('keyval', 'readwrite') const tx = db.transaction('keyval', 'readwrite')
@ -52,7 +52,7 @@ export async function findV1ContentFromIdb(): Promise<{
export async function importFromV1LocalRoom( export async function importFromV1LocalRoom(
editor: Editor, editor: Editor,
didCancel: () => boolean didCancel: () => boolean
): Promise<{ didImport: false } | { didImport: true; document: LegacyTldrawDocument }> { ): Promise<{ didImport: false } | { didImport: true; document: TLV1Document }> {
const v1Doc = await findV1ContentFromIdb() const v1Doc = await findV1ContentFromIdb()
if (didCancel() || !v1Doc) return { didImport: false } if (didCancel() || !v1Doc) return { didImport: false }
@ -75,7 +75,7 @@ export async function importFromV1MultiplayerRoom(
editor: Editor, editor: Editor,
roomSlug: string, roomSlug: string,
didCancel: () => boolean didCancel: () => boolean
): Promise<{ didImport: false } | { didImport: true; document: LegacyTldrawDocument }> { ): Promise<{ didImport: false } | { didImport: true; document: TLV1Document }> {
const response = await fetch(`/api/static-legacy-multiplayer?roomSlug=${roomSlug}`) const response = await fetch(`/api/static-legacy-multiplayer?roomSlug=${roomSlug}`)
if (!response.ok || didCancel()) { if (!response.ok || didCancel()) {
return { didImport: false } return { didImport: false }
@ -89,7 +89,7 @@ export async function importFromV1MultiplayerRoom(
// TODO: handle weird data formats (TLD-1605) & v1 migrations (TLD-1638) // TODO: handle weird data formats (TLD-1605) & v1 migrations (TLD-1638)
const { assets, bindings, shapes, version } = data.room.storage.data const { assets, bindings, shapes, version } = data.room.storage.data
const PAGE_ID = 'page' const PAGE_ID = 'page'
const document: LegacyTldrawDocument = { const document: TLV1Document = {
id: 'doc', id: 'doc',
name: roomSlug, name: roomSlug,
version, version,

View file

@ -370,7 +370,7 @@
"addToApiReportFile": false "addToApiReportFile": false
}, },
"ae-forgotten-export": { "ae-forgotten-export": {
"logLevel": "none", "logLevel": "error",
"addToApiReportFile": false "addToApiReportFile": false
} }
// "ae-extra-release-tag": { // "ae-extra-release-tag": {

View file

@ -154,7 +154,7 @@ export function average(A: VecLike, B: VecLike): string;
// @public (undocumented) // @public (undocumented)
export abstract class BaseBoxShapeTool extends StateNode { export abstract class BaseBoxShapeTool extends StateNode {
// (undocumented) // (undocumented)
static children: () => (typeof Idle | typeof Pointing)[]; static children: () => TLStateNodeConstructor[];
// (undocumented) // (undocumented)
static id: string; static id: string;
// (undocumented) // (undocumented)
@ -253,6 +253,32 @@ export interface BoundsSnapPoint {
y: number; y: number;
} }
// @public (undocumented)
export class BoundsSnaps {
constructor(manager: SnapManager);
// (undocumented)
readonly editor: Editor;
// (undocumented)
getSnapPoints(shapeId: TLShapeId): BoundsSnapPoint[];
// (undocumented)
readonly manager: SnapManager;
// (undocumented)
snapResizeShapes({ initialSelectionPageBounds, dragDelta, handle: originalHandle, isAspectRatioLocked, isResizingFromCenter, }: {
dragDelta: Vec;
handle: SelectionCorner | SelectionEdge;
initialSelectionPageBounds: Box;
isAspectRatioLocked: boolean;
isResizingFromCenter: boolean;
}): SnapData;
// (undocumented)
snapTranslateShapes({ lockedAxis, initialSelectionPageBounds, initialSelectionSnapPoints, dragDelta, }: {
dragDelta: Vec;
initialSelectionPageBounds: Box;
initialSelectionSnapPoints: BoundsSnapPoint[];
lockedAxis: 'x' | 'y' | null;
}): SnapData;
}
// @public (undocumented) // @public (undocumented)
export class Box { export class Box {
constructor(x?: number, y?: number, w?: number, h?: number); constructor(x?: number, y?: number, w?: number, h?: number);
@ -425,6 +451,20 @@ export function clamp(n: number, min: number, max: number): number;
// @public // @public
export function clampRadians(r: number): number; export function clampRadians(r: number): number;
// @public (undocumented)
export class ClickManager {
constructor(editor: Editor);
// @internal
cancelDoubleClickTimeout: () => void;
get clickState(): TLClickState | undefined;
// (undocumented)
editor: Editor;
// (undocumented)
handlePointerEvent: (info: TLPointerEventInfo) => TLClickEventInfo | TLPointerEventInfo;
// (undocumented)
lastPointerInfo: TLPointerEventInfo;
}
// @public // @public
export function clockwiseAngleDist(a0: number, a1: number): number; export function clockwiseAngleDist(a0: number, a1: number): number;
@ -514,6 +554,28 @@ export function dataUrlToFile(url: string, filename: string, mimeType: string):
// @internal (undocumented) // @internal (undocumented)
export type DebugFlag<T> = DebugFlagDef<T> & Atom<T>; export type DebugFlag<T> = DebugFlagDef<T> & Atom<T>;
// @internal (undocumented)
export interface DebugFlagDef<T> {
// (undocumented)
defaults: DebugFlagDefaults<T>;
// (undocumented)
name: string;
// (undocumented)
shouldStoreForSession: boolean;
}
// @internal (undocumented)
export interface DebugFlagDefaults<T> {
// (undocumented)
all: T;
// (undocumented)
development?: T;
// (undocumented)
production?: T;
// (undocumented)
staging?: T;
}
// @internal (undocumented) // @internal (undocumented)
export const debugFlags: { export const debugFlags: {
readonly debugCursors: DebugFlag<boolean>; readonly debugCursors: DebugFlag<boolean>;
@ -1051,7 +1113,7 @@ export class Editor extends EventEmitter<TLEventMap> {
reparentShapes(shapes: TLShape[] | TLShapeId[], parentId: TLParentId, insertIndex?: IndexKey): this; reparentShapes(shapes: TLShape[] | TLShapeId[], parentId: TLParentId, insertIndex?: IndexKey): this;
resetZoom(point?: Vec, opts?: TLCameraMoveOptions): this; resetZoom(point?: Vec, opts?: TLCameraMoveOptions): this;
resizeShape(shape: TLShape | TLShapeId, scale: VecLike, options?: TLResizeShapeOptions): this; resizeShape(shape: TLShape | TLShapeId, scale: VecLike, options?: TLResizeShapeOptions): this;
readonly root: RootState; readonly root: StateNode;
rotateShapesBy(shapes: TLShape[] | TLShapeId[], delta: number): this; rotateShapesBy(shapes: TLShape[] | TLShapeId[], delta: number): this;
screenToPage(point: VecLike): Vec; screenToPage(point: VecLike): Vec;
readonly scribbles: ScribbleManager; readonly scribbles: ScribbleManager;
@ -1172,7 +1234,21 @@ export class Ellipse2d extends Geometry2d {
export { EMPTY_ARRAY } export { EMPTY_ARRAY }
// @public (undocumented) // @public (undocumented)
export class ErrorBoundary extends React_3.Component<React_3.PropsWithRef<React_3.PropsWithChildren<TLErrorBoundaryProps>>, TLErrorBoundaryState> { export class EnvironmentManager {
constructor(editor: Editor);
// (undocumented)
editor: Editor;
readonly isAndroid: boolean;
readonly isChromeForIos: boolean;
readonly isFirefox: boolean;
readonly isIos: boolean;
readonly isSafari: boolean;
}
// @public (undocumented)
export class ErrorBoundary extends React_3.Component<React_3.PropsWithRef<React_3.PropsWithChildren<TLErrorBoundaryProps>>, {
error: Error | null;
}> {
// (undocumented) // (undocumented)
componentDidCatch(error: unknown): void; componentDidCatch(error: unknown): void;
// (undocumented) // (undocumented)
@ -1182,7 +1258,9 @@ export class ErrorBoundary extends React_3.Component<React_3.PropsWithRef<React_
// (undocumented) // (undocumented)
render(): boolean | JSX_2.Element | Iterable<React_3.ReactNode> | null | number | string | undefined; render(): boolean | JSX_2.Element | Iterable<React_3.ReactNode> | null | number | string | undefined;
// (undocumented) // (undocumented)
state: TLErrorBoundaryState; state: {
error: null;
};
} }
// @public (undocumented) // @public (undocumented)
@ -1265,6 +1343,20 @@ export abstract class Geometry2d {
get vertices(): Vec[]; get vertices(): Vec[];
} }
// @public (undocumented)
export interface Geometry2dOptions {
// (undocumented)
debugColor?: string;
// (undocumented)
ignore?: boolean;
// (undocumented)
isClosed: boolean;
// (undocumented)
isFilled: boolean;
// (undocumented)
isLabel?: boolean;
}
// @public // @public
export function getArcMeasure(A: number, B: number, sweepFlag: number, largeArcFlag: number): number; export function getArcMeasure(A: number, B: number, sweepFlag: number, largeArcFlag: number): number;
@ -1382,6 +1474,20 @@ export interface HandleSnapGeometry {
points?: VecModel[]; points?: VecModel[];
} }
// @public (undocumented)
export class HandleSnaps {
constructor(manager: SnapManager);
// (undocumented)
readonly editor: Editor;
// (undocumented)
readonly manager: SnapManager;
// (undocumented)
snapHandle({ currentShapeId, handle, }: {
currentShapeId: TLShapeId;
handle: TLHandle;
}): null | SnapData;
}
// @public // @public
export function hardReset({ shouldReload }?: { export function hardReset({ shouldReload }?: {
shouldReload?: boolean | undefined; shouldReload?: boolean | undefined;
@ -1411,7 +1517,7 @@ export class HistoryManager<R extends UnknownRecord> {
isEmpty: boolean; isEmpty: boolean;
}; };
redos: (NonNullable<TLHistoryEntry<R>> | undefined)[]; redos: (NonNullable<TLHistoryEntry<R>> | undefined)[];
state: HistoryRecorderState; state: string;
undos: (NonNullable<TLHistoryEntry<R>> | undefined)[]; undos: (NonNullable<TLHistoryEntry<R>> | undefined)[];
}; };
// (undocumented) // (undocumented)
@ -1430,11 +1536,6 @@ export class HistoryManager<R extends UnknownRecord> {
onBatchComplete: () => void; onBatchComplete: () => void;
// (undocumented) // (undocumented)
redo: () => this | undefined; redo: () => this | undefined;
// @internal (undocumented)
stacks: Atom< {
redos: Stack<TLHistoryEntry<R>>;
undos: Stack<TLHistoryEntry<R>>;
}, unknown>;
// (undocumented) // (undocumented)
undo: () => this; undo: () => this;
} }
@ -1637,6 +1738,9 @@ export function OptionalErrorBoundary({ children, fallback, ...props }: Omit<TLE
fallback: TLErrorFallbackComponent; fallback: TLErrorFallbackComponent;
}): JSX_2.Element; }): JSX_2.Element;
// @public (undocumented)
export type OptionalKeys<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
// @public // @public
export function perimeterOfEllipse(rx: number, ry: number): number; export function perimeterOfEllipse(rx: number, ry: number): number;
@ -1834,6 +1938,38 @@ export const runtime: {
refreshPage: () => void; refreshPage: () => void;
}; };
// @public (undocumented)
export interface ScribbleItem {
// (undocumented)
delayRemaining: number;
// (undocumented)
id: string;
// (undocumented)
next: null | VecModel;
// (undocumented)
prev: null | VecModel;
// (undocumented)
scribble: TLScribble;
// (undocumented)
timeoutMs: number;
}
// @public (undocumented)
export class ScribbleManager {
constructor(editor: Editor);
addPoint: (id: ScribbleItem['id'], x: number, y: number) => ScribbleItem;
// (undocumented)
addScribble: (scribble: Partial<TLScribble>, id?: string) => ScribbleItem;
// (undocumented)
reset(): void;
// (undocumented)
scribbleItems: Map<string, ScribbleItem>;
// (undocumented)
state: "paused" | "running";
stop: (id: ScribbleItem['id']) => ScribbleItem;
tick: (elapsed: number) => void;
}
// @public (undocumented) // @public (undocumented)
export type SelectionCorner = 'bottom_left' | 'bottom_right' | 'top_left' | 'top_right'; export type SelectionCorner = 'bottom_left' | 'bottom_right' | 'top_left' | 'top_right';
@ -1948,6 +2084,12 @@ export const SIN: (x: number) => number;
// @public // @public
export function snapAngle(r: number, segments: number): number; export function snapAngle(r: number, segments: number): number;
// @public (undocumented)
export interface SnapData {
// (undocumented)
nudge: Vec;
}
// @public (undocumented) // @public (undocumented)
export type SnapIndicator = GapsSnapIndicator | PointsSnapIndicator; export type SnapIndicator = GapsSnapIndicator | PointsSnapIndicator;
@ -2090,7 +2232,7 @@ export abstract class StateNode implements Partial<TLEventHandlers> {
shapeType?: string; shapeType?: string;
transition: (id: string, info?: any) => this; transition: (id: string, info?: any) => this;
// (undocumented) // (undocumented)
type: TLStateNodeType; type: 'branch' | 'leaf' | 'root';
} }
// @public (undocumented) // @public (undocumented)
@ -2119,6 +2261,42 @@ export interface SvgExportDef {
// @public // @public
export const TAB_ID: string; export const TAB_ID: string;
// @public (undocumented)
export class TextManager {
constructor(editor: Editor);
// (undocumented)
baseElm: HTMLDivElement;
// (undocumented)
editor: Editor;
measureElementTextNodeSpans(element: HTMLElement, { shouldTruncateToFirstLine }?: {
shouldTruncateToFirstLine?: boolean;
}): {
didTruncate: boolean;
spans: {
box: BoxModel;
text: string;
}[];
};
// (undocumented)
measureText: (textToMeasure: string, opts: {
maxWidth: null | number;
disableOverflowWrapBreaking?: boolean;
fontFamily: string;
fontSize: number;
fontStyle: string;
fontWeight: string;
lineHeight: number;
minWidth?: null | number;
padding: string;
}) => BoxModel & {
scrollWidth: number;
};
measureTextSpans(textToMeasure: string, opts: TLMeasureTextSpanOpts): {
box: BoxModel;
text: string;
}[];
}
// @public (undocumented) // @public (undocumented)
export type TLAnyBindingUtilConstructor = TLBindingUtilConstructor<any>; export type TLAnyBindingUtilConstructor = TLBindingUtilConstructor<any>;
@ -2210,6 +2388,12 @@ export interface TLCancelEventInfo {
type: 'misc'; type: 'misc';
} }
// @public (undocumented)
export interface TLCanvasComponentProps {
// (undocumented)
className?: string;
}
// @public (undocumented) // @public (undocumented)
export type TLClickEvent = (info: TLClickEventInfo) => void; export type TLClickEvent = (info: TLClickEventInfo) => void;
@ -2226,6 +2410,9 @@ export type TLClickEventInfo = TLBaseEventInfo & {
// @public (undocumented) // @public (undocumented)
export type TLCLickEventName = 'double_click' | 'quadruple_click' | 'triple_click'; export type TLCLickEventName = 'double_click' | 'quadruple_click' | 'triple_click';
// @public (undocumented)
export type TLClickState = 'idle' | 'overflow' | 'pendingDouble' | 'pendingOverflow' | 'pendingQuadruple' | 'pendingTriple';
// @public (undocumented) // @public (undocumented)
export interface TLCollaboratorHintProps { export interface TLCollaboratorHintProps {
// (undocumented) // (undocumented)
@ -2375,9 +2562,60 @@ export interface TldrawOptions {
} }
// @public (undocumented) // @public (undocumented)
export type TLEditorComponents = Partial<{ export interface TLEditorComponents {
[K in keyof BaseEditorComponents]: BaseEditorComponents[K] | null; // (undocumented)
} & ErrorComponents>; Background?: ComponentType | null;
// (undocumented)
Brush?: ComponentType<TLBrushProps> | null;
// (undocumented)
Canvas?: ComponentType<TLCanvasComponentProps> | null;
// (undocumented)
CollaboratorBrush?: ComponentType<TLBrushProps> | null;
// (undocumented)
CollaboratorCursor?: ComponentType<TLCursorProps> | null;
// (undocumented)
CollaboratorHint?: ComponentType<TLCollaboratorHintProps> | null;
// (undocumented)
CollaboratorScribble?: ComponentType<TLScribbleProps> | null;
// (undocumented)
CollaboratorShapeIndicator?: ComponentType<TLShapeIndicatorProps> | null;
// (undocumented)
Cursor?: ComponentType<TLCursorProps> | null;
// (undocumented)
ErrorFallback?: TLErrorFallbackComponent;
// (undocumented)
Grid?: ComponentType<TLGridProps> | null;
// (undocumented)
Handle?: ComponentType<TLHandleProps> | null;
// (undocumented)
Handles?: ComponentType<TLHandlesProps> | null;
// (undocumented)
InFrontOfTheCanvas?: ComponentType | null;
// (undocumented)
LoadingScreen?: ComponentType | null;
// (undocumented)
OnTheCanvas?: ComponentType | null;
// (undocumented)
Scribble?: ComponentType<TLScribbleProps> | null;
// (undocumented)
SelectionBackground?: ComponentType<TLSelectionBackgroundProps> | null;
// (undocumented)
SelectionForeground?: ComponentType<TLSelectionForegroundProps> | null;
// (undocumented)
ShapeErrorFallback?: TLShapeErrorFallbackComponent;
// (undocumented)
ShapeIndicator?: ComponentType<TLShapeIndicatorProps> | null;
// (undocumented)
ShapeIndicatorErrorFallback?: TLShapeIndicatorErrorFallbackComponent;
// (undocumented)
SnapIndicator?: ComponentType<TLSnapIndicatorProps> | null;
// (undocumented)
Spinner?: ComponentType | null;
// (undocumented)
SvgDefs?: ComponentType | null;
// (undocumented)
ZoomBrush?: ComponentType<TLBrushProps> | null;
}
// @public (undocumented) // @public (undocumented)
export interface TLEditorOptions { export interface TLEditorOptions {
@ -2416,6 +2654,12 @@ export interface TLErrorBoundaryProps {
onError?: ((error: unknown) => void) | null; onError?: ((error: unknown) => void) | null;
} }
// @public (undocumented)
export type TLErrorFallbackComponent = ComponentType<{
editor?: Editor;
error: unknown;
}>;
// @public (undocumented) // @public (undocumented)
export interface TLEventHandlers { export interface TLEventHandlers {
// (undocumented) // (undocumented)
@ -2581,6 +2825,30 @@ export interface TLHandlesProps {
children: ReactNode; children: ReactNode;
} }
// @public (undocumented)
export interface TLHistoryBatchOptions {
history?: 'ignore' | 'record-preserveRedoStack' | 'record';
}
// @public (undocumented)
export interface TLHistoryDiff<R extends UnknownRecord> {
// (undocumented)
diff: RecordsDiff<R>;
// (undocumented)
type: 'diff';
}
// @public (undocumented)
export type TLHistoryEntry<R extends UnknownRecord> = TLHistoryDiff<R> | TLHistoryMark;
// @public (undocumented)
export interface TLHistoryMark {
// (undocumented)
id: string;
// (undocumented)
type: 'stop';
}
// @public (undocumented) // @public (undocumented)
export type TLInterruptEvent = (info: TLInterruptEventInfo) => void; export type TLInterruptEvent = (info: TLInterruptEventInfo) => void;
@ -2606,6 +2874,30 @@ export type TLKeyboardEventInfo = TLBaseEventInfo & {
// @public (undocumented) // @public (undocumented)
export type TLKeyboardEventName = 'key_down' | 'key_repeat' | 'key_up'; export type TLKeyboardEventName = 'key_down' | 'key_repeat' | 'key_up';
// @public (undocumented)
export interface TLMeasureTextSpanOpts {
// (undocumented)
fontFamily: string;
// (undocumented)
fontSize: number;
// (undocumented)
fontStyle: string;
// (undocumented)
fontWeight: string;
// (undocumented)
height: number;
// (undocumented)
lineHeight: number;
// (undocumented)
overflow: 'truncate-clip' | 'truncate-ellipsis' | 'wrap';
// (undocumented)
padding: number;
// (undocumented)
textAlign: TLDefaultHorizontalAlignStyle;
// (undocumented)
width: number;
}
// @public (undocumented) // @public (undocumented)
export type TLOnBeforeCreateHandler<T extends TLShape> = (next: T) => T | void; export type TLOnBeforeCreateHandler<T extends TLShape> = (next: T) => T | void;
@ -2644,31 +2936,31 @@ export type TLOnHandleDragHandler<T extends TLShape> = (shape: T, info: {
export type TLOnMountHandler = (editor: Editor) => (() => undefined | void) | undefined | void; export type TLOnMountHandler = (editor: Editor) => (() => undefined | void) | undefined | void;
// @public (undocumented) // @public (undocumented)
export type TLOnResizeEndHandler<T extends TLShape> = TLEventChangeHandler<T>; export type TLOnResizeEndHandler<T extends TLShape> = (initial: T, current: T) => TLShapePartial<T> | void;
// @public (undocumented) // @public (undocumented)
export type TLOnResizeHandler<T extends TLShape> = (shape: T, info: TLResizeInfo<T>) => Omit<TLShapePartial<T>, 'id' | 'type'> | undefined | void; export type TLOnResizeHandler<T extends TLShape> = (shape: T, info: TLResizeInfo<T>) => Omit<TLShapePartial<T>, 'id' | 'type'> | undefined | void;
// @public (undocumented) // @public (undocumented)
export type TLOnResizeStartHandler<T extends TLShape> = TLEventStartHandler<T>; export type TLOnResizeStartHandler<T extends TLShape> = (shape: T) => TLShapePartial<T> | void;
// @public (undocumented) // @public (undocumented)
export type TLOnRotateEndHandler<T extends TLShape> = TLEventChangeHandler<T>; export type TLOnRotateEndHandler<T extends TLShape> = (initial: T, current: T) => TLShapePartial<T> | void;
// @public (undocumented) // @public (undocumented)
export type TLOnRotateHandler<T extends TLShape> = TLEventChangeHandler<T>; export type TLOnRotateHandler<T extends TLShape> = (initial: T, current: T) => TLShapePartial<T> | void;
// @public (undocumented) // @public (undocumented)
export type TLOnRotateStartHandler<T extends TLShape> = TLEventStartHandler<T>; export type TLOnRotateStartHandler<T extends TLShape> = (shape: T) => TLShapePartial<T> | void;
// @public (undocumented) // @public (undocumented)
export type TLOnTranslateEndHandler<T extends TLShape> = TLEventChangeHandler<T>; export type TLOnTranslateEndHandler<T extends TLShape> = (initial: T, current: T) => TLShapePartial<T> | void;
// @public (undocumented) // @public (undocumented)
export type TLOnTranslateHandler<T extends TLShape> = TLEventChangeHandler<T>; export type TLOnTranslateHandler<T extends TLShape> = (initial: T, current: T) => TLShapePartial<T> | void;
// @public (undocumented) // @public (undocumented)
export type TLOnTranslateStartHandler<T extends TLShape> = TLEventStartHandler<T>; export type TLOnTranslateStartHandler<T extends TLShape> = (shape: T) => TLShapePartial<T> | void;
// @public (undocumented) // @public (undocumented)
export type TLPinchEvent = (info: TLPinchEventInfo) => void; export type TLPinchEvent = (info: TLPinchEventInfo) => void;
@ -2831,6 +3123,16 @@ export interface TLSessionStateSnapshot {
version: number; version: number;
} }
// @public (undocumented)
export type TLShapeErrorFallbackComponent = ComponentType<{
error: any;
}>;
// @public (undocumented)
export type TLShapeIndicatorErrorFallbackComponent = ComponentType<{
error: unknown;
}>;
// @public (undocumented) // @public (undocumented)
export interface TLShapeIndicatorProps { export interface TLShapeIndicatorProps {
// (undocumented) // (undocumented)
@ -2956,6 +3258,26 @@ export interface TLSvgOptions {
// @public (undocumented) // @public (undocumented)
export type TLTickEvent = (info: TLTickEventInfo) => void; export type TLTickEvent = (info: TLTickEventInfo) => void;
// @public (undocumented)
export interface TLTickEventInfo {
// (undocumented)
elapsed: number;
// (undocumented)
name: 'tick';
// (undocumented)
type: 'misc';
}
// @public (undocumented)
export interface TLUser {
// (undocumented)
readonly derivePresenceState: (store: TLStore) => Signal<null | TLInstancePresence>;
// (undocumented)
readonly setUserPreferences: (userPreferences: TLUserPreferences) => void;
// (undocumented)
readonly userPreferences: Signal<TLUserPreferences>;
}
// @public // @public
export interface TLUserPreferences { export interface TLUserPreferences {
// (undocumented) // (undocumented)
@ -3028,31 +3350,7 @@ export function useContainer(): HTMLDivElement;
export function useEditor(): Editor; export function useEditor(): Editor;
// @public (undocumented) // @public (undocumented)
export function useEditorComponents(): Partial<{ export function useEditorComponents(): Required<TLEditorComponents>;
Background: ComponentType | null;
Brush: ComponentType<TLBrushProps> | null;
Canvas: ComponentType<TLCanvasComponentProps> | null;
CollaboratorBrush: ComponentType<TLBrushProps> | null;
CollaboratorCursor: ComponentType<TLCursorProps> | null;
CollaboratorHint: ComponentType<TLCollaboratorHintProps> | null;
CollaboratorScribble: ComponentType<TLScribbleProps> | null;
CollaboratorShapeIndicator: ComponentType<TLShapeIndicatorProps> | null;
Cursor: ComponentType<TLCursorProps> | null;
Grid: ComponentType<TLGridProps> | null;
Handle: ComponentType<TLHandleProps> | null;
Handles: ComponentType<TLHandlesProps> | null;
InFrontOfTheCanvas: ComponentType | null;
LoadingScreen: ComponentType | null;
OnTheCanvas: ComponentType | null;
Scribble: ComponentType<TLScribbleProps> | null;
SelectionBackground: ComponentType<TLSelectionBackgroundProps> | null;
SelectionForeground: ComponentType<TLSelectionForegroundProps> | null;
ShapeIndicator: ComponentType<TLShapeIndicatorProps> | null;
SnapIndicator: ComponentType<TLSnapIndicatorProps> | null;
Spinner: ComponentType | null;
SvgDefs: ComponentType | null;
ZoomBrush: ComponentType<TLBrushProps> | null;
} & ErrorComponents> & ErrorComponents;
// @internal // @internal
export function useEvent<Args extends Array<unknown>, Result>(handler: (...args: Args) => Result): (...args: Args) => Result; export function useEvent<Args extends Array<unknown>, Result>(handler: (...args: Args) => Result): (...args: Args) => Result;
@ -3086,6 +3384,41 @@ export const USER_COLORS: readonly ["#FF802B", "#EC5E41", "#F2555A", "#F04F88",
export { useReactor } export { useReactor }
// @public (undocumented)
export class UserPreferencesManager {
constructor(user: TLUser, inferDarkMode: boolean);
// (undocumented)
getAnimationSpeed(): number;
// (undocumented)
getColor(): string;
getEdgeScrollSpeed(): number;
// (undocumented)
getId(): string;
// (undocumented)
getIsDarkMode(): boolean;
// (undocumented)
getIsSnapMode(): boolean;
// (undocumented)
getIsWrapMode(): boolean;
// (undocumented)
getLocale(): string;
// (undocumented)
getName(): string;
// (undocumented)
getUserPreferences(): {
animationSpeed: number;
color: string;
id: string;
isDarkMode: boolean;
isSnapMode: boolean;
isWrapMode: boolean;
locale: string;
name: string;
};
// (undocumented)
updateUserPreferences: (userPreferences: Partial<TLUserPreferences>) => void;
}
// @internal // @internal
export function useSafeId(): string; export function useSafeId(): string;
@ -3100,7 +3433,7 @@ export function useSelectionEvents(handle: TLSelectionHandle): {
export function useShallowArrayIdentity<T>(arr: readonly T[]): readonly T[]; export function useShallowArrayIdentity<T>(arr: readonly T[]): readonly T[];
// @internal (undocumented) // @internal (undocumented)
export function useShallowObjectIdentity<T extends Record<string, unknown>>(arr: T): T; export function useShallowObjectIdentity<T extends object>(arr: T): T;
// @public // @public
export function useSvgExportContext(): { export function useSvgExportContext(): {

View file

@ -1,6 +1,21 @@
// Important! don't move this tlschema re-export to lib/index.ts, doing so causes esbuild to produce // Important! don't move this tlschema re-export to lib/index.ts, doing so causes esbuild to produce
// incorrect output. https://github.com/evanw/esbuild/issues/1737 // incorrect output. https://github.com/evanw/esbuild/issues/1737
import 'core-js/stable/array/at.js'
import 'core-js/stable/array/flat-map.js'
import 'core-js/stable/array/flat.js'
import 'core-js/stable/string/at.js'
import 'core-js/stable/string/replace-all.js'
// eslint-disable-next-line local/no-export-star
export * from '@tldraw/store'
// eslint-disable-next-line local/no-export-star
export * from '@tldraw/tlschema'
// eslint-disable-next-line local/no-export-star
export * from '@tldraw/utils'
// eslint-disable-next-line local/no-export-star
export * from '@tldraw/validate'
export { export {
EMPTY_ARRAY, EMPTY_ARRAY,
atom, atom,
@ -17,14 +32,6 @@ export {
type Atom, type Atom,
type Signal, type Signal,
} from '@tldraw/state' } from '@tldraw/state'
// eslint-disable-next-line local/no-export-star
export * from '@tldraw/store'
// eslint-disable-next-line local/no-export-star
export * from '@tldraw/tlschema'
// eslint-disable-next-line local/no-export-star
export * from '@tldraw/utils'
// eslint-disable-next-line local/no-export-star
export * from '@tldraw/validate'
export { export {
ErrorScreen, ErrorScreen,
LoadingScreen, LoadingScreen,
@ -42,7 +49,10 @@ export { HTMLContainer, type HTMLContainerProps } from './lib/components/HTMLCon
export { SVGContainer, type SVGContainerProps } from './lib/components/SVGContainer' export { SVGContainer, type SVGContainerProps } from './lib/components/SVGContainer'
export { DefaultBackground } from './lib/components/default-components/DefaultBackground' export { DefaultBackground } from './lib/components/default-components/DefaultBackground'
export { DefaultBrush, type TLBrushProps } from './lib/components/default-components/DefaultBrush' export { DefaultBrush, type TLBrushProps } from './lib/components/default-components/DefaultBrush'
export { DefaultCanvas } from './lib/components/default-components/DefaultCanvas' export {
DefaultCanvas,
type TLCanvasComponentProps,
} from './lib/components/default-components/DefaultCanvas'
export { export {
DefaultCollaboratorHint, DefaultCollaboratorHint,
type TLCollaboratorHintProps, type TLCollaboratorHintProps,
@ -51,7 +61,10 @@ export {
DefaultCursor, DefaultCursor,
type TLCursorProps, type TLCursorProps,
} from './lib/components/default-components/DefaultCursor' } from './lib/components/default-components/DefaultCursor'
export { DefaultErrorFallback } from './lib/components/default-components/DefaultErrorFallback' export {
DefaultErrorFallback,
type TLErrorFallbackComponent,
} from './lib/components/default-components/DefaultErrorFallback'
export { DefaultGrid, type TLGridProps } from './lib/components/default-components/DefaultGrid' export { DefaultGrid, type TLGridProps } from './lib/components/default-components/DefaultGrid'
export { export {
DefaultHandle, DefaultHandle,
@ -73,10 +86,12 @@ export {
DefaultSelectionForeground, DefaultSelectionForeground,
type TLSelectionForegroundProps, type TLSelectionForegroundProps,
} from './lib/components/default-components/DefaultSelectionForeground' } from './lib/components/default-components/DefaultSelectionForeground'
export { type TLShapeErrorFallbackComponent } from './lib/components/default-components/DefaultShapeErrorFallback'
export { export {
DefaultShapeIndicator, DefaultShapeIndicator,
type TLShapeIndicatorProps, type TLShapeIndicatorProps,
} from './lib/components/default-components/DefaultShapeIndicator' } from './lib/components/default-components/DefaultShapeIndicator'
export { type TLShapeIndicatorErrorFallbackComponent } from './lib/components/default-components/DefaultShapeIndicatorErrorFallback'
export { export {
DefaultSnapIndicator, DefaultSnapIndicator,
type TLSnapIndicatorProps, type TLSnapIndicatorProps,
@ -104,7 +119,7 @@ export {
type TLStoreEventInfo, type TLStoreEventInfo,
type TLStoreOptions, type TLStoreOptions,
} from './lib/config/createTLStore' } from './lib/config/createTLStore'
export { createTLUser } from './lib/config/createTLUser' export { createTLUser, type TLUser } from './lib/config/createTLUser'
export { type TLAnyBindingUtilConstructor } from './lib/config/defaultBindings' export { type TLAnyBindingUtilConstructor } from './lib/config/defaultBindings'
export { coreShapes, type TLAnyShapeUtilConstructor } from './lib/config/defaultShapes' export { coreShapes, type TLAnyShapeUtilConstructor } from './lib/config/defaultShapes'
export { DEFAULT_ANIMATION_OPTIONS, DEFAULT_CAMERA_OPTIONS, SIDES } from './lib/constants' export { DEFAULT_ANIMATION_OPTIONS, DEFAULT_CAMERA_OPTIONS, SIDES } from './lib/constants'
@ -119,18 +134,25 @@ export {
type BindingOnShapeIsolateOptions, type BindingOnShapeIsolateOptions,
type TLBindingUtilConstructor, type TLBindingUtilConstructor,
} from './lib/editor/bindings/BindingUtil' } from './lib/editor/bindings/BindingUtil'
export { ClickManager, type TLClickState } from './lib/editor/managers/ClickManager'
export { EnvironmentManager } from './lib/editor/managers/EnvironmentManager'
export { HistoryManager } from './lib/editor/managers/HistoryManager' export { HistoryManager } from './lib/editor/managers/HistoryManager'
export { ScribbleManager, type ScribbleItem } from './lib/editor/managers/ScribbleManager'
export { export {
BoundsSnaps,
type BoundsSnapGeometry, type BoundsSnapGeometry,
type BoundsSnapPoint, type BoundsSnapPoint,
} from './lib/editor/managers/SnapManager/BoundsSnaps' } from './lib/editor/managers/SnapManager/BoundsSnaps'
export { type HandleSnapGeometry } from './lib/editor/managers/SnapManager/HandleSnaps' export { HandleSnaps, type HandleSnapGeometry } from './lib/editor/managers/SnapManager/HandleSnaps'
export { export {
SnapManager, SnapManager,
type GapsSnapIndicator, type GapsSnapIndicator,
type PointsSnapIndicator, type PointsSnapIndicator,
type SnapData,
type SnapIndicator, type SnapIndicator,
} from './lib/editor/managers/SnapManager/SnapManager' } from './lib/editor/managers/SnapManager/SnapManager'
export { TextManager, type TLMeasureTextSpanOpts } from './lib/editor/managers/TextManager'
export { UserPreferencesManager } from './lib/editor/managers/UserPreferencesManager'
export { BaseBoxShapeUtil, type TLBaseBoxShape } from './lib/editor/shapes/BaseBoxShapeUtil' export { BaseBoxShapeUtil, type TLBaseBoxShape } from './lib/editor/shapes/BaseBoxShapeUtil'
export { export {
ShapeUtil, ShapeUtil,
@ -199,6 +221,7 @@ export {
type TLPointerEventName, type TLPointerEventName,
type TLPointerEventTarget, type TLPointerEventTarget,
type TLTickEvent, type TLTickEvent,
type TLTickEventInfo,
type TLWheelEvent, type TLWheelEvent,
type TLWheelEventInfo, type TLWheelEventInfo,
type UiEvent, type UiEvent,
@ -210,6 +233,13 @@ export {
type TLExternalContentSource, type TLExternalContentSource,
} from './lib/editor/types/external-content' } from './lib/editor/types/external-content'
export { export {
type TLHistoryBatchOptions,
type TLHistoryDiff,
type TLHistoryEntry,
type TLHistoryMark,
} from './lib/editor/types/history-types'
export {
type OptionalKeys,
type RequiredKeys, type RequiredKeys,
type TLCameraConstraints, type TLCameraConstraints,
type TLCameraMoveOptions, type TLCameraMoveOptions,
@ -254,7 +284,7 @@ export { CubicBezier2d } from './lib/primitives/geometry/CubicBezier2d'
export { CubicSpline2d } from './lib/primitives/geometry/CubicSpline2d' export { CubicSpline2d } from './lib/primitives/geometry/CubicSpline2d'
export { Edge2d } from './lib/primitives/geometry/Edge2d' export { Edge2d } from './lib/primitives/geometry/Edge2d'
export { Ellipse2d } from './lib/primitives/geometry/Ellipse2d' export { Ellipse2d } from './lib/primitives/geometry/Ellipse2d'
export { Geometry2d } from './lib/primitives/geometry/Geometry2d' export { Geometry2d, type Geometry2dOptions } from './lib/primitives/geometry/Geometry2d'
export { Group2d } from './lib/primitives/geometry/Group2d' export { Group2d } from './lib/primitives/geometry/Group2d'
export { Point2d } from './lib/primitives/geometry/Point2d' export { Point2d } from './lib/primitives/geometry/Point2d'
export { Polygon2d } from './lib/primitives/geometry/Polygon2d' export { Polygon2d } from './lib/primitives/geometry/Polygon2d'
@ -314,7 +344,13 @@ export {
type SharedStyle, type SharedStyle,
} from './lib/utils/SharedStylesMap' } from './lib/utils/SharedStylesMap'
export { dataUrlToFile } from './lib/utils/assets' export { dataUrlToFile } from './lib/utils/assets'
export { debugFlags, featureFlags, type DebugFlag } from './lib/utils/debug-flags' export {
debugFlags,
featureFlags,
type DebugFlag,
type DebugFlagDef,
type DebugFlagDefaults,
} from './lib/utils/debug-flags'
export { export {
loopToHtmlElement, loopToHtmlElement,
preventDefault, preventDefault,
@ -340,11 +376,3 @@ export { hardReset } from './lib/utils/sync/hardReset'
export { uniq } from './lib/utils/uniq' export { uniq } from './lib/utils/uniq'
export { uniqueId } from './lib/utils/uniqueId' export { uniqueId } from './lib/utils/uniqueId'
export { openWindow } from './lib/utils/window-open' export { openWindow } from './lib/utils/window-open'
/** @polyfills */
import 'core-js/stable/array/at.js'
import 'core-js/stable/array/flat-map.js'
import 'core-js/stable/array/flat.js'
import 'core-js/stable/string/at.js'
import 'core-js/stable/string/replace-all.js'

View file

@ -8,16 +8,12 @@ export interface TLErrorBoundaryProps {
fallback: TLErrorFallbackComponent fallback: TLErrorFallbackComponent
} }
interface TLErrorBoundaryState { const initialState = { error: null }
error: Error | null
}
const initialState: TLErrorBoundaryState = { error: null }
/** @public */ /** @public */
export class ErrorBoundary extends React.Component< export class ErrorBoundary extends React.Component<
React.PropsWithRef<React.PropsWithChildren<TLErrorBoundaryProps>>, React.PropsWithRef<React.PropsWithChildren<TLErrorBoundaryProps>>,
TLErrorBoundaryState { error: Error | null }
> { > {
static getDerivedStateFromError(error: Error) { static getDerivedStateFromError(error: Error) {
return { error } return { error }

View file

@ -1,4 +1,5 @@
import { useValue } from '@tldraw/state' import { useValue } from '@tldraw/state'
import { noop } from '@tldraw/utils'
import classNames from 'classnames' import classNames from 'classnames'
import { ComponentType, useEffect, useLayoutEffect, useRef, useState } from 'react' import { ComponentType, useEffect, useLayoutEffect, useRef, useState } from 'react'
import { Editor } from '../../editor/Editor' import { Editor } from '../../editor/Editor'
@ -10,9 +11,6 @@ import { ErrorBoundary } from '../ErrorBoundary'
const BASE_ERROR_URL = 'https://github.com/tldraw/tldraw/issues/new' const BASE_ERROR_URL = 'https://github.com/tldraw/tldraw/issues/new'
// eslint-disable-next-line @typescript-eslint/no-empty-function
function noop() {}
/** @public */ /** @public */
export type TLErrorFallbackComponent = ComponentType<{ error: unknown; editor?: Editor }> export type TLErrorFallbackComponent = ComponentType<{ error: unknown; editor?: Editor }>

View file

@ -707,7 +707,7 @@ export class Editor extends EventEmitter<TLEventMap> {
* *
* @public * @public
*/ */
readonly root: RootState readonly root: StateNode
/** /**
* A set of functions to call when the app is disposed. * A set of functions to call when the app is disposed.

View file

@ -3,7 +3,8 @@ import { uniqueId } from '../../utils/uniqueId'
import type { Editor } from '../Editor' import type { Editor } from '../Editor'
import { TLClickEventInfo, TLPointerEventInfo } from '../types/event-types' import { TLClickEventInfo, TLPointerEventInfo } from '../types/event-types'
type TLClickState = /** @public */
export type TLClickState =
| 'idle' | 'idle'
| 'pendingDouble' | 'pendingDouble'
| 'pendingTriple' | 'pendingTriple'
@ -13,6 +14,7 @@ type TLClickState =
const MAX_CLICK_DISTANCE = 40 const MAX_CLICK_DISTANCE = 40
/** @public */
export class ClickManager { export class ClickManager {
constructor(public editor: Editor) {} constructor(public editor: Editor) {}

View file

@ -1,5 +1,6 @@
import { Editor } from '../Editor' import { Editor } from '../Editor'
/** @public */
export class EnvironmentManager { export class EnvironmentManager {
constructor(public editor: Editor) { constructor(public editor: Editor) {
if (typeof window !== 'undefined' && 'navigator' in window) { if (typeof window !== 'undefined' && 'navigator' in window) {

View file

@ -1,7 +1,6 @@
import { BaseRecord, RecordId, Store, StoreSchema, createRecordType } from '@tldraw/store' import { BaseRecord, RecordId, Store, StoreSchema, createRecordType } from '@tldraw/store'
import { TLHistoryBatchOptions } from '../types/history-types' import { TLHistoryBatchOptions } from '../types/history-types'
import { HistoryManager } from './HistoryManager' import { HistoryManager } from './HistoryManager'
import { stack } from './Stack'
interface TestRecord extends BaseRecord<'test', TestRecordId> { interface TestRecord extends BaseRecord<'test', TestRecordId> {
value: number | string value: number | string
@ -99,9 +98,9 @@ describe(HistoryManager, () => {
editor.decrement() editor.decrement()
expect(editor.getCount()).toBe(3) expect(editor.getCount()).toBe(3)
const undos = [...editor.history.stacks.get().undos] const undos = editor.history.debug().undos
const parsedUndos = JSON.parse(JSON.stringify(undos)) const parsedUndos = JSON.parse(JSON.stringify(undos))
editor.history.stacks.update(({ redos }) => ({ undos: stack(parsedUndos), redos })) expect(parsedUndos).toEqual(undos)
editor.history.undo() editor.history.undo()

View file

@ -27,8 +27,7 @@ export class HistoryManager<R extends UnknownRecord> {
private state: HistoryRecorderState = HistoryRecorderState.Recording private state: HistoryRecorderState = HistoryRecorderState.Recording
private readonly pendingDiff = new PendingDiff<R>() private readonly pendingDiff = new PendingDiff<R>()
/** @internal */ private stacks = atom(
stacks = atom(
'HistoryManager.stacks', 'HistoryManager.stacks',
{ {
undos: stack<TLHistoryEntry<R>>(), undos: stack<TLHistoryEntry<R>>(),
@ -274,7 +273,7 @@ export class HistoryManager<R extends UnknownRecord> {
undos: undos.toArray(), undos: undos.toArray(),
redos: redos.toArray(), redos: redos.toArray(),
pendingDiff: this.pendingDiff.debug(), pendingDiff: this.pendingDiff.debug(),
state: this.state, state: this.state as string,
} }
} }
} }

View file

@ -3,7 +3,8 @@ import { Vec } from '../../primitives/Vec'
import { uniqueId } from '../../utils/uniqueId' import { uniqueId } from '../../utils/uniqueId'
import { Editor } from '../Editor' import { Editor } from '../Editor'
interface ScribbleItem { /** @public */
export interface ScribbleItem {
id: string id: string
scribble: TLScribble scribble: TLScribble
timeoutMs: number timeoutMs: number

View file

@ -196,6 +196,7 @@ function dedupeGapSnaps(snaps: Array<Extract<SnapIndicator, { type: 'gaps' }>>)
} }
} }
/** @public */
export class BoundsSnaps { export class BoundsSnaps {
readonly editor: Editor readonly editor: Editor
constructor(readonly manager: SnapManager) { constructor(readonly manager: SnapManager) {

View file

@ -47,6 +47,7 @@ export interface HandleSnapGeometry {
const defaultGetSelfSnapOutline = () => null const defaultGetSelfSnapOutline = () => null
const defaultGetSelfSnapPoints = () => [] const defaultGetSelfSnapPoints = () => []
/** @public */
export class HandleSnaps { export class HandleSnaps {
readonly editor: Editor readonly editor: Editor
constructor(readonly manager: SnapManager) { constructor(readonly manager: SnapManager) {

View file

@ -20,9 +20,9 @@ const textAlignmentsForLtr = {
'end-legacy': 'right', 'end-legacy': 'right',
} }
type TLOverflowMode = 'wrap' | 'truncate-ellipsis' | 'truncate-clip' /** @public */
interface TLMeasureTextSpanOpts { export interface TLMeasureTextSpanOpts {
overflow: TLOverflowMode overflow: 'wrap' | 'truncate-ellipsis' | 'truncate-clip'
width: number width: number
height: number height: number
padding: number padding: number
@ -36,6 +36,7 @@ interface TLMeasureTextSpanOpts {
const spaceCharacterRegex = /\s/ const spaceCharacterRegex = /\s/
/** @public */
export class TextManager { export class TextManager {
baseElm: HTMLDivElement baseElm: HTMLDivElement

View file

@ -6,6 +6,7 @@ import {
} from '../../config/TLUserPreferences' } from '../../config/TLUserPreferences'
import { TLUser } from '../../config/createTLUser' import { TLUser } from '../../config/createTLUser'
/** @public */
export class UserPreferencesManager { export class UserPreferencesManager {
constructor( constructor(
private readonly user: TLUser, private readonly user: TLUser,

View file

@ -542,17 +542,29 @@ export type TLOnBeforeCreateHandler<T extends TLShape> = (next: T) => T | void
/** @public */ /** @public */
export type TLOnBeforeUpdateHandler<T extends TLShape> = (prev: T, next: T) => T | void export type TLOnBeforeUpdateHandler<T extends TLShape> = (prev: T, next: T) => T | void
/** @public */ /** @public */
export type TLOnTranslateStartHandler<T extends TLShape> = TLEventStartHandler<T> export type TLOnTranslateStartHandler<T extends TLShape> = (shape: T) => TLShapePartial<T> | void
/** @public */ /** @public */
export type TLOnTranslateHandler<T extends TLShape> = TLEventChangeHandler<T> export type TLOnTranslateHandler<T extends TLShape> = (
initial: T,
current: T
) => TLShapePartial<T> | void
/** @public */ /** @public */
export type TLOnTranslateEndHandler<T extends TLShape> = TLEventChangeHandler<T> export type TLOnTranslateEndHandler<T extends TLShape> = (
initial: T,
current: T
) => TLShapePartial<T> | void
/** @public */ /** @public */
export type TLOnRotateStartHandler<T extends TLShape> = TLEventStartHandler<T> export type TLOnRotateStartHandler<T extends TLShape> = (shape: T) => TLShapePartial<T> | void
/** @public */ /** @public */
export type TLOnRotateHandler<T extends TLShape> = TLEventChangeHandler<T> export type TLOnRotateHandler<T extends TLShape> = (
initial: T,
current: T
) => TLShapePartial<T> | void
/** @public */ /** @public */
export type TLOnRotateEndHandler<T extends TLShape> = TLEventChangeHandler<T> export type TLOnRotateEndHandler<T extends TLShape> = (
initial: T,
current: T
) => TLShapePartial<T> | void
/** /**
* The type of resize. * The type of resize.
@ -595,10 +607,13 @@ export type TLOnResizeHandler<T extends TLShape> = (
) => Omit<TLShapePartial<T>, 'id' | 'type'> | undefined | void ) => Omit<TLShapePartial<T>, 'id' | 'type'> | undefined | void
/** @public */ /** @public */
export type TLOnResizeStartHandler<T extends TLShape> = TLEventStartHandler<T> export type TLOnResizeStartHandler<T extends TLShape> = (shape: T) => TLShapePartial<T> | void
/** @public */ /** @public */
export type TLOnResizeEndHandler<T extends TLShape> = TLEventChangeHandler<T> export type TLOnResizeEndHandler<T extends TLShape> = (
initial: T,
current: T
) => TLShapePartial<T> | void
/* -------------------- Dragging -------------------- */ /* -------------------- Dragging -------------------- */
@ -632,6 +647,3 @@ export type TLOnDoubleClickHandleHandler<T extends TLShape> = (
shape: T, shape: T,
handle: TLHandle handle: TLHandle
) => TLShapePartial<T> | void ) => TLShapePartial<T> | void
type TLEventStartHandler<T extends TLShape> = (shape: T) => TLShapePartial<T> | void
type TLEventChangeHandler<T extends TLShape> = (initial: T, current: T) => TLShapePartial<T> | void

View file

@ -1,5 +1,5 @@
import { TLShape } from '@tldraw/tlschema' import { TLShape } from '@tldraw/tlschema'
import { StateNode } from '../StateNode' import { StateNode, TLStateNodeConstructor } from '../StateNode'
import { Idle } from './children/Idle' import { Idle } from './children/Idle'
import { Pointing } from './children/Pointing' import { Pointing } from './children/Pointing'
@ -7,7 +7,7 @@ import { Pointing } from './children/Pointing'
export abstract class BaseBoxShapeTool extends StateNode { export abstract class BaseBoxShapeTool extends StateNode {
static override id = 'box' static override id = 'box'
static override initial = 'idle' static override initial = 'idle'
static override children = () => [Idle, Pointing] static override children = (): TLStateNodeConstructor[] => [Idle, Pointing]
abstract override shapeType: string abstract override shapeType: string

View file

@ -11,7 +11,6 @@ import {
TLPinchEventInfo, TLPinchEventInfo,
} from '../types/event-types' } from '../types/event-types'
type TLStateNodeType = 'branch' | 'leaf' | 'root'
const STATE_NODES_TO_MEASURE = [ const STATE_NODES_TO_MEASURE = [
'brushing', 'brushing',
'cropping', 'cropping',
@ -84,7 +83,7 @@ export abstract class StateNode implements Partial<TLEventHandlers> {
static children?: () => TLStateNodeConstructor[] static children?: () => TLStateNodeConstructor[]
id: string id: string
type: TLStateNodeType type: 'branch' | 'leaf' | 'root'
shapeType?: string shapeType?: string
initial?: string initial?: string
children?: Record<string, StateNode> children?: Record<string, StateNode>

View file

@ -17,6 +17,7 @@ import {
import { DefaultGrid, TLGridProps } from '../components/default-components/DefaultGrid' import { DefaultGrid, TLGridProps } from '../components/default-components/DefaultGrid'
import { DefaultHandle, TLHandleProps } from '../components/default-components/DefaultHandle' import { DefaultHandle, TLHandleProps } from '../components/default-components/DefaultHandle'
import { DefaultHandles, TLHandlesProps } from '../components/default-components/DefaultHandles' import { DefaultHandles, TLHandlesProps } from '../components/default-components/DefaultHandles'
import { DefaultLoadingScreen } from '../components/default-components/DefaultLoadingScreen'
import { DefaultScribble, TLScribbleProps } from '../components/default-components/DefaultScribble' import { DefaultScribble, TLScribbleProps } from '../components/default-components/DefaultScribble'
import { import {
DefaultSelectionBackground, DefaultSelectionBackground,
@ -46,47 +47,39 @@ import { DefaultSpinner } from '../components/default-components/DefaultSpinner'
import { DefaultSvgDefs } from '../components/default-components/DefaultSvgDefs' import { DefaultSvgDefs } from '../components/default-components/DefaultSvgDefs'
import { useShallowObjectIdentity } from './useIdentity' import { useShallowObjectIdentity } from './useIdentity'
export interface BaseEditorComponents {
Background: ComponentType
SvgDefs: ComponentType
Brush: ComponentType<TLBrushProps>
ZoomBrush: ComponentType<TLBrushProps>
ShapeIndicator: ComponentType<TLShapeIndicatorProps>
Cursor: ComponentType<TLCursorProps>
Canvas: ComponentType<TLCanvasComponentProps>
CollaboratorBrush: ComponentType<TLBrushProps>
CollaboratorCursor: ComponentType<TLCursorProps>
CollaboratorHint: ComponentType<TLCollaboratorHintProps>
CollaboratorShapeIndicator: ComponentType<TLShapeIndicatorProps>
Grid: ComponentType<TLGridProps>
Scribble: ComponentType<TLScribbleProps>
CollaboratorScribble: ComponentType<TLScribbleProps>
SnapIndicator: ComponentType<TLSnapIndicatorProps>
Handles: ComponentType<TLHandlesProps>
Handle: ComponentType<TLHandleProps>
Spinner: ComponentType
SelectionForeground: ComponentType<TLSelectionForegroundProps>
SelectionBackground: ComponentType<TLSelectionBackgroundProps>
OnTheCanvas: ComponentType
InFrontOfTheCanvas: ComponentType
LoadingScreen: ComponentType
}
// These will always have defaults
interface ErrorComponents {
ErrorFallback: TLErrorFallbackComponent
ShapeErrorFallback: TLShapeErrorFallbackComponent
ShapeIndicatorErrorFallback: TLShapeIndicatorErrorFallbackComponent
}
/** @public */ /** @public */
export type TLEditorComponents = Partial< export interface TLEditorComponents {
{ Background?: ComponentType | null
[K in keyof BaseEditorComponents]: BaseEditorComponents[K] | null SvgDefs?: ComponentType | null
} & ErrorComponents Brush?: ComponentType<TLBrushProps> | null
> ZoomBrush?: ComponentType<TLBrushProps> | null
ShapeIndicator?: ComponentType<TLShapeIndicatorProps> | null
Cursor?: ComponentType<TLCursorProps> | null
Canvas?: ComponentType<TLCanvasComponentProps> | null
CollaboratorBrush?: ComponentType<TLBrushProps> | null
CollaboratorCursor?: ComponentType<TLCursorProps> | null
CollaboratorHint?: ComponentType<TLCollaboratorHintProps> | null
CollaboratorShapeIndicator?: ComponentType<TLShapeIndicatorProps> | null
Grid?: ComponentType<TLGridProps> | null
Scribble?: ComponentType<TLScribbleProps> | null
CollaboratorScribble?: ComponentType<TLScribbleProps> | null
SnapIndicator?: ComponentType<TLSnapIndicatorProps> | null
Handles?: ComponentType<TLHandlesProps> | null
Handle?: ComponentType<TLHandleProps> | null
Spinner?: ComponentType | null
SelectionForeground?: ComponentType<TLSelectionForegroundProps> | null
SelectionBackground?: ComponentType<TLSelectionBackgroundProps> | null
OnTheCanvas?: ComponentType | null
InFrontOfTheCanvas?: ComponentType | null
LoadingScreen?: ComponentType | null
const EditorComponentsContext = createContext<null | (TLEditorComponents & ErrorComponents)>(null) // These will always have defaults
ErrorFallback?: TLErrorFallbackComponent
ShapeErrorFallback?: TLShapeErrorFallbackComponent
ShapeIndicatorErrorFallback?: TLShapeIndicatorErrorFallbackComponent
}
const EditorComponentsContext = createContext<null | Required<TLEditorComponents>>(null)
interface ComponentsContextProviderProps { interface ComponentsContextProviderProps {
overrides?: TLEditorComponents overrides?: TLEditorComponents
@ -101,12 +94,11 @@ export function EditorComponentsProvider({
return ( return (
<EditorComponentsContext.Provider <EditorComponentsContext.Provider
value={useMemo( value={useMemo(
() => ({ (): Required<TLEditorComponents> => ({
Background: DefaultBackground, Background: DefaultBackground,
SvgDefs: DefaultSvgDefs, SvgDefs: DefaultSvgDefs,
Brush: DefaultBrush, Brush: DefaultBrush,
ZoomBrush: DefaultBrush, ZoomBrush: DefaultBrush,
ScreenshotBrush: DefaultBrush,
CollaboratorBrush: DefaultBrush, CollaboratorBrush: DefaultBrush,
Cursor: DefaultCursor, Cursor: DefaultCursor,
CollaboratorCursor: DefaultCursor, CollaboratorCursor: DefaultCursor,
@ -128,6 +120,7 @@ export function EditorComponentsProvider({
OnTheCanvas: null, OnTheCanvas: null,
InFrontOfTheCanvas: null, InFrontOfTheCanvas: null,
Canvas: DefaultCanvas, Canvas: DefaultCanvas,
LoadingScreen: DefaultLoadingScreen,
..._overrides, ..._overrides,
}), }),
[_overrides] [_overrides]

View file

@ -16,6 +16,6 @@ export function useShallowArrayIdentity<T>(arr: readonly T[]): readonly T[] {
} }
/** @internal */ /** @internal */
export function useShallowObjectIdentity<T extends Record<string, unknown>>(arr: T): T { export function useShallowObjectIdentity<T extends object>(arr: T): T {
return useIdentity(arr, areObjectsShallowEqual) return useIdentity(arr, areObjectsShallowEqual)
} }

View file

@ -2,6 +2,7 @@ import { Box } from '../Box'
import { Vec } from '../Vec' import { Vec } from '../Vec'
import { pointInPolygon } from '../utils' import { pointInPolygon } from '../utils'
/** @public */
export interface Geometry2dOptions { export interface Geometry2dOptions {
isFilled: boolean isFilled: boolean
isClosed: boolean isClosed: boolean

View file

@ -97,7 +97,7 @@ function createDebugValue<T>(
{ {
defaults, defaults,
shouldStoreForSession = true, shouldStoreForSession = true,
}: { defaults: Defaults<T>; shouldStoreForSession?: boolean } }: { defaults: DebugFlagDefaults<T>; shouldStoreForSession?: boolean }
) { ) {
return createDebugValueBase({ return createDebugValueBase({
name, name,
@ -188,16 +188,18 @@ function getDefaultValue<T>(def: DebugFlagDef<T>): T {
} }
} }
interface Defaults<T> { /** @internal */
export interface DebugFlagDefaults<T> {
development?: T development?: T
staging?: T staging?: T
production?: T production?: T
all: T all: T
} }
interface DebugFlagDef<T> { /** @internal */
export interface DebugFlagDef<T> {
name: string name: string
defaults: Defaults<T> defaults: DebugFlagDefaults<T>
shouldStoreForSession: boolean shouldStoreForSession: boolean
} }

View file

@ -7,6 +7,20 @@
import { FunctionComponent } from 'react'; import { FunctionComponent } from 'react';
import { default as React_2 } from 'react'; import { default as React_2 } from 'react';
// @internal
export class ArraySet<T> {
add(elem: T): boolean;
// (undocumented)
clear(): void;
// (undocumented)
has(elem: T): boolean;
get isEmpty(): boolean;
remove(elem: T): boolean;
// (undocumented)
size(): number;
visit(visitor: (item: T) => void): void;
}
// @public // @public
export interface Atom<Value, Diff = unknown> extends Signal<Value, Diff> { export interface Atom<Value, Diff = unknown> extends Signal<Value, Diff> {
set(value: Value, diff?: Diff): Value; set(value: Value, diff?: Diff): Value;
@ -26,6 +40,20 @@ export interface AtomOptions<Value, Diff> {
isEqual?: (a: any, b: any) => boolean; isEqual?: (a: any, b: any) => boolean;
} }
// @internal (undocumented)
export interface Child {
// (undocumented)
isActivelyListening: boolean;
// (undocumented)
lastTraversedEpoch: number;
// (undocumented)
readonly parentEpochs: number[];
// (undocumented)
readonly parents: Signal<any, any>[];
// (undocumented)
readonly parentSet: ArraySet<Signal<any, any>>;
}
// @public // @public
export interface Computed<Value, Diff = unknown> extends Signal<Value, Diff> { export interface Computed<Value, Diff = unknown> extends Signal<Value, Diff> {
readonly isActivelyListening: boolean; readonly isActivelyListening: boolean;
@ -46,6 +74,9 @@ export function computed(target: any, key: string, descriptor: PropertyDescripto
// @public (undocumented) // @public (undocumented)
export function computed<Value, Diff = unknown>(options?: ComputedOptions<Value, Diff>): (target: any, key: string, descriptor: PropertyDescriptor) => PropertyDescriptor; export function computed<Value, Diff = unknown>(options?: ComputedOptions<Value, Diff>): (target: any, key: string, descriptor: PropertyDescriptor) => PropertyDescriptor;
// @public
export type ComputeDiff<Value, Diff> = (previousValue: Value, currentValue: Value, lastComputedEpoch: number, currentEpoch: number) => Diff | RESET_VALUE;
// @public // @public
export interface ComputedOptions<Value, Diff> { export interface ComputedOptions<Value, Diff> {
computeDiff?: ComputeDiff<Value, Diff>; computeDiff?: ComputeDiff<Value, Diff>;
@ -54,10 +85,35 @@ export interface ComputedOptions<Value, Diff> {
} }
// @public // @public
export const EffectScheduler: typeof __EffectScheduler__; export const EffectScheduler: new <Result>(name: string, runEffect: (lastReactedEpoch: number) => Result, options?: EffectSchedulerOptions) => EffectScheduler<Result>;
// @public (undocumented) // @public (undocumented)
export type EffectScheduler<Result> = __EffectScheduler__<Result>; export interface EffectScheduler<Result> {
attach(): void;
detach(): void;
execute(): Result;
readonly isActivelyListening: boolean;
// @internal (undocumented)
readonly lastTraversedEpoch: number;
// @internal (undocumented)
maybeExecute(): void;
// @internal (undocumented)
maybeScheduleEffect(): void;
// @internal (undocumented)
readonly parentEpochs: number[];
// @internal (undocumented)
readonly parents: Signal<any, any>[];
// @internal (undocumented)
readonly parentSet: ArraySet<Signal<any, any>>;
readonly scheduleCount: number;
// @internal (undocumented)
scheduleEffect(): void;
}
// @public (undocumented)
export interface EffectSchedulerOptions {
scheduleEffect?: (execute: () => void) => void;
}
// @public (undocumented) // @public (undocumented)
export const EMPTY_ARRAY: []; export const EMPTY_ARRAY: [];
@ -115,6 +171,12 @@ export function transact<T>(fn: () => T): T;
// @public // @public
export function transaction<T>(fn: (rollback: () => void) => T): T; export function transaction<T>(fn: (rollback: () => void) => T): T;
// @public (undocumented)
export const UNINITIALIZED: unique symbol;
// @public
export type UNINITIALIZED = typeof UNINITIALIZED;
// @public // @public
export function unsafe__withoutCapture<T>(fn: () => T): T; export function unsafe__withoutCapture<T>(fn: () => T): T;
@ -148,6 +210,22 @@ export function useValue<Value>(name: string, fn: () => Value, deps: unknown[]):
// @public // @public
export function whyAmIRunning(): void; export function whyAmIRunning(): void;
// @public (undocumented)
export const WithDiff: {
new <Value, Diff>(value: Value, diff: Diff): {
diff: Diff;
value: Value;
};
};
// @public (undocumented)
export interface WithDiff<Value, Diff> {
// (undocumented)
diff: Diff;
// (undocumented)
value: Value;
}
// @public // @public
export function withDiff<Value, Diff>(value: Value, diff: Diff): WithDiff<Value, Diff>; export function withDiff<Value, Diff>(value: Value, diff: Diff): WithDiff<Value, Diff>;

View file

@ -43,6 +43,7 @@ export const isUninitialized = (value: any): value is UNINITIALIZED => {
return value === UNINITIALIZED return value === UNINITIALIZED
} }
/** @public */
export const WithDiff = singleton( export const WithDiff = singleton(
'WithDiff', 'WithDiff',
() => () =>
@ -53,6 +54,8 @@ export const WithDiff = singleton(
) {} ) {}
} }
) )
/** @public */
export interface WithDiff<Value, Diff> { export interface WithDiff<Value, Diff> {
value: Value value: Value
diff: Diff diff: Diff

View file

@ -5,7 +5,8 @@ import { attach, detach, haveParentsChanged, singleton } from './helpers'
import { getGlobalEpoch } from './transactions' import { getGlobalEpoch } from './transactions'
import { Signal } from './types' import { Signal } from './types'
interface EffectSchedulerOptions { /** @public */
export interface EffectSchedulerOptions {
/** /**
* scheduleEffect is a function that will be called when the effect is scheduled. * scheduleEffect is a function that will be called when the effect is scheduled.
* *
@ -38,7 +39,7 @@ interface EffectSchedulerOptions {
scheduleEffect?: (execute: () => void) => void scheduleEffect?: (execute: () => void) => void
} }
class __EffectScheduler__<Result> { class __EffectScheduler__<Result> implements EffectScheduler<Result> {
private _isActivelyListening = false private _isActivelyListening = false
/** /**
* Whether this scheduler is attached and actively listening to its parents. * Whether this scheduler is attached and actively listening to its parents.
@ -174,9 +175,71 @@ class __EffectScheduler__<Result> {
* *
* @public * @public
*/ */
export const EffectScheduler = singleton('EffectScheduler', () => __EffectScheduler__) export const EffectScheduler = singleton(
'EffectScheduler',
(): {
new <Result>(
name: string,
runEffect: (lastReactedEpoch: number) => Result,
options?: EffectSchedulerOptions
): EffectScheduler<Result>
} => __EffectScheduler__
)
/** @public */ /** @public */
export type EffectScheduler<Result> = __EffectScheduler__<Result> export interface EffectScheduler<Result> {
/**
* Whether this scheduler is attached and actively listening to its parents.
* @public
*/
readonly isActivelyListening: boolean
/** @internal */
readonly lastTraversedEpoch: number
/**
* The number of times this effect has been scheduled.
* @public
*/
readonly scheduleCount: number
/** @internal */
readonly parentSet: ArraySet<Signal<any, any>>
/** @internal */
readonly parentEpochs: number[]
/** @internal */
readonly parents: Signal<any, any>[]
/** @internal */
maybeScheduleEffect(): void
/** @internal */
scheduleEffect(): void
/** @internal */
maybeExecute(): void
/**
* Makes this scheduler become 'actively listening' to its parents.
* If it has been executed before it will immediately become eligible to receive 'maybeScheduleEffect' calls.
* If it has not executed before it will need to be manually executed once to become eligible for scheduling, i.e. by calling [[EffectScheduler.execute]].
* @public
*/
attach(): void
/**
* Makes this scheduler stop 'actively listening' to its parents.
* It will no longer be eligible to receive 'maybeScheduleEffect' calls until [[EffectScheduler.attach]] is called again.
*/
detach(): void
/**
* Executes the effect immediately and returns the result.
* @returns The result of the effect.
*/
execute(): Result
}
/** /**
* Starts a new effect scheduler, scheduling the effect immediately. * Starts a new effect scheduler, scheduling the effect immediately.

View file

@ -1,17 +1,18 @@
import { singleton } from './helpers' import { singleton } from './helpers'
export { ArraySet } from './ArraySet'
export { atom, isAtom } from './Atom' export { atom, isAtom } from './Atom'
export type { Atom, AtomOptions } from './Atom' export type { Atom, AtomOptions } from './Atom'
export { computed, getComputedInstance, isUninitialized, withDiff } from './Computed' export { UNINITIALIZED, computed, getComputedInstance, isUninitialized, withDiff } from './Computed'
export type { Computed, ComputedOptions } from './Computed' export type { Computed, ComputedOptions, WithDiff } from './Computed'
export { EffectScheduler, react, reactor } from './EffectScheduler' export { EffectScheduler, react, reactor } from './EffectScheduler'
export type { Reactor } from './EffectScheduler' export type { EffectSchedulerOptions, Reactor } from './EffectScheduler'
export { unsafe__withoutCapture, whyAmIRunning } from './capture' export { unsafe__withoutCapture, whyAmIRunning } from './capture'
export { EMPTY_ARRAY } from './helpers' export { EMPTY_ARRAY } from './helpers'
export { isSignal } from './isSignal' export { isSignal } from './isSignal'
export { transact, transaction } from './transactions' export { transact, transaction } from './transactions'
export { RESET_VALUE } from './types' export { RESET_VALUE } from './types'
export type { Signal } from './types' export type { Child, ComputeDiff, Signal } from './types'
// This should be incremented any time an API change is made. i.e. for additions or removals. // This should be incremented any time an API change is made. i.e. for additions or removals.
// Bugfixes need not increment this. // Bugfixes need not increment this.

View file

@ -333,14 +333,6 @@ type AuthorRecord extends BaseRecord<"author"> {
} }
``` ```
### `AllRecords`
A helper to get the type of all records in a record store.
```ts
type AllAuthorRecords = AllRecords<RecordStore<Author>>
```
### `RecordsDiff` ### `RecordsDiff`
A diff describing the changes to a record. A diff describing the changes to a record.

View file

@ -8,9 +8,6 @@ import { Atom } from '@tldraw/state';
import { Computed } from '@tldraw/state'; import { Computed } from '@tldraw/state';
import { Result } from '@tldraw/utils'; import { Result } from '@tldraw/utils';
// @public
export type AllRecords<T extends Store<any>> = ExtractR<ExtractRecordType<T>>;
// @public // @public
export function assertIdType<R extends UnknownRecord>(id: string | undefined, type: RecordType<R, any>): asserts id is IdOf<R>; export function assertIdType<R extends UnknownRecord>(id: string | undefined, type: RecordType<R, any>): asserts id is IdOf<R>;
@ -22,6 +19,9 @@ export interface BaseRecord<TypeName extends string, Id extends RecordId<Unknown
readonly typeName: TypeName; readonly typeName: TypeName;
} }
// @public (undocumented)
export type ChangeSource = 'remote' | 'user';
// @public // @public
export interface CollectionDiff<T> { export interface CollectionDiff<T> {
// (undocumented) // (undocumented)
@ -37,7 +37,7 @@ export interface ComputedCache<Data, R extends UnknownRecord> {
} }
// @public // @public
export function createComputedCache<Context extends StoreContext<any>, Result, Record extends ContextRecordType<Context> = ContextRecordType<Context>>(name: string, derive: (context: Context, record: Record) => Result | undefined, isEqual?: (a: Record, b: Record) => boolean): { export function createComputedCache<Context extends StoreObject<any>, Result, Record extends StoreObjectRecordType<Context> = StoreObjectRecordType<Context>>(name: string, derive: (context: Context, record: Record) => Result | undefined, isEqual?: (a: Record, b: Record) => boolean): {
get(context: Context, id: IdOf<Record>): Result | undefined; get(context: Context, id: IdOf<Record>): Result | undefined;
}; };
@ -117,6 +117,18 @@ export class IncrementalSetConstructor<T> {
// @internal // @internal
export function isRecordsDiffEmpty<T extends UnknownRecord>(diff: RecordsDiff<T>): boolean; export function isRecordsDiffEmpty<T extends UnknownRecord>(diff: RecordsDiff<T>): boolean;
// @public (undocumented)
export interface LegacyBaseMigrationsInfo {
// (undocumented)
currentVersion: number;
// (undocumented)
firstVersion: number;
// (undocumented)
migrators: {
[version: number]: LegacyMigration;
};
}
// @public (undocumented) // @public (undocumented)
export interface LegacyMigration<Before = any, After = any> { export interface LegacyMigration<Before = any, After = any> {
// (undocumented) // (undocumented)
@ -191,11 +203,31 @@ export function parseMigrationId(id: MigrationId): {
version: number; version: number;
}; };
// @public (undocumented)
export type QueryExpression<R extends object> = {
[k in keyof R & string]?: QueryValueMatcher<R[k]>;
};
// @public (undocumented)
export type QueryValueMatcher<T> = {
eq: T;
} | {
gt: number;
} | {
neq: T;
};
// @public (undocumented)
export type RecordFromId<K extends RecordId<UnknownRecord>> = K extends RecordId<infer R> ? R : never;
// @public (undocumented) // @public (undocumented)
export type RecordId<R extends UnknownRecord> = string & { export type RecordId<R extends UnknownRecord> = string & {
__type__: R; __type__: R;
}; };
// @public
export type RecordScope = 'document' | 'presence' | 'session';
// @public // @public
export interface RecordsDiff<R extends UnknownRecord> { export interface RecordsDiff<R extends UnknownRecord> {
// (undocumented) // (undocumented)
@ -210,7 +242,7 @@ export interface RecordsDiff<R extends UnknownRecord> {
export class RecordType<R extends UnknownRecord, RequiredProperties extends keyof Omit<R, 'id' | 'typeName'>> { export class RecordType<R extends UnknownRecord, RequiredProperties extends keyof Omit<R, 'id' | 'typeName'>> {
constructor( constructor(
typeName: R['typeName'], config: { typeName: R['typeName'], config: {
readonly createDefaultProperties: () => Exclude<OmitMeta<R>, RequiredProperties>; readonly createDefaultProperties: () => Exclude<Omit<R, 'id' | 'typeName'>, RequiredProperties>;
readonly ephemeralKeys?: { readonly ephemeralKeys?: {
readonly [K in Exclude<keyof R, 'id' | 'typeName'>]: boolean; readonly [K in Exclude<keyof R, 'id' | 'typeName'>]: boolean;
}; };
@ -222,7 +254,7 @@ export class RecordType<R extends UnknownRecord, RequiredProperties extends keyo
// @deprecated // @deprecated
createCustomId(id: string): IdOf<R>; createCustomId(id: string): IdOf<R>;
// (undocumented) // (undocumented)
readonly createDefaultProperties: () => Exclude<OmitMeta<R>, RequiredProperties>; readonly createDefaultProperties: () => Exclude<Omit<R, 'id' | 'typeName'>, RequiredProperties>;
createId(customUniquePart?: string): IdOf<R>; createId(customUniquePart?: string): IdOf<R>;
// (undocumented) // (undocumented)
readonly ephemeralKeys?: { readonly ephemeralKeys?: {
@ -245,6 +277,15 @@ export class RecordType<R extends UnknownRecord, RequiredProperties extends keyo
// @public (undocumented) // @public (undocumented)
export function reverseRecordsDiff(diff: RecordsDiff<any>): RecordsDiff<any>; export function reverseRecordsDiff(diff: RecordsDiff<any>): RecordsDiff<any>;
// @public (undocumented)
export type RSIndex<R extends UnknownRecord, Property extends string & keyof R = string & keyof R> = Computed<RSIndexMap<R, Property>, RSIndexDiff<R, Property>>;
// @public (undocumented)
export type RSIndexDiff<R extends UnknownRecord, Property extends string & keyof R = string & keyof R> = Map<R[Property], CollectionDiff<IdOf<R>>>;
// @public (undocumented)
export type RSIndexMap<R extends UnknownRecord, Property extends string & keyof R = string & keyof R> = Map<R[Property], Set<IdOf<R>>>;
// @public (undocumented) // @public (undocumented)
export type SerializedSchema = SerializedSchemaV1 | SerializedSchemaV2; export type SerializedSchema = SerializedSchemaV1 | SerializedSchemaV2;
@ -317,7 +358,7 @@ export class Store<R extends UnknownRecord = UnknownRecord, Props = unknown> {
} | null; } | null;
// (undocumented) // (undocumented)
_flushHistory(): void; _flushHistory(): void;
get: <K extends IdOf<R>>(id: K) => RecFromId<K> | undefined; get: <K extends IdOf<R>>(id: K) => RecordFromId<K> | undefined;
// @deprecated (undocumented) // @deprecated (undocumented)
getSnapshot(scope?: 'all' | RecordScope): StoreSnapshot<R>; getSnapshot(scope?: 'all' | RecordScope): StoreSnapshot<R>;
getStoreSnapshot(scope?: 'all' | RecordScope): StoreSnapshot<R>; getStoreSnapshot(scope?: 'all' | RecordScope): StoreSnapshot<R>;
@ -348,8 +389,8 @@ export class Store<R extends UnknownRecord = UnknownRecord, Props = unknown> {
serialize: (scope?: 'all' | RecordScope) => SerializedStore<R>; serialize: (scope?: 'all' | RecordScope) => SerializedStore<R>;
// (undocumented) // (undocumented)
readonly sideEffects: StoreSideEffects<R>; readonly sideEffects: StoreSideEffects<R>;
unsafeGetWithoutCapture: <K extends IdOf<R>>(id: K) => RecFromId<K> | undefined; unsafeGetWithoutCapture: <K extends IdOf<R>>(id: K) => RecordFromId<K> | undefined;
update: <K extends IdOf<R>>(id: K, updater: (record: RecFromId<K>) => RecFromId<K>) => void; update: <K extends IdOf<R>>(id: K, updater: (record: RecordFromId<K>) => RecordFromId<K>) => void;
// (undocumented) // (undocumented)
validate(phase: 'createRecord' | 'initialize' | 'tests' | 'updateRecord'): void; validate(phase: 'createRecord' | 'initialize' | 'tests' | 'updateRecord'): void;
} }
@ -389,9 +430,69 @@ export interface StoreError {
// @public // @public
export type StoreListener<R extends UnknownRecord> = (entry: HistoryEntry<R>) => void; export type StoreListener<R extends UnknownRecord> = (entry: HistoryEntry<R>) => void;
// @public (undocumented)
export interface StoreListenerFilters {
// (undocumented)
scope: 'all' | RecordScope;
// (undocumented)
source: 'all' | ChangeSource;
}
// @public (undocumented)
export type StoreObject<R extends UnknownRecord> = {
store: Store<R>;
} | Store<R>;
// @public (undocumented)
export type StoreObjectRecordType<Context extends StoreObject<any>> = Context extends Store<infer R> ? R : Context extends {
store: Store<infer R>;
} ? R : never;
// @public (undocumented) // @public (undocumented)
export type StoreOperationCompleteHandler = (source: 'remote' | 'user') => void; export type StoreOperationCompleteHandler = (source: 'remote' | 'user') => void;
// @public
export class StoreQueries<R extends UnknownRecord> {
constructor(atoms: Atom<Record<IdOf<R>, Atom<R>>>, history: Atom<number, RecordsDiff<R>>);
// @internal
__uncached_createIndex<TypeName extends R['typeName'], Property extends string & keyof Extract<R, {
typeName: TypeName;
}>>(typeName: TypeName, property: Property): RSIndex<Extract<R, {
typeName: TypeName;
}>, Property>;
// (undocumented)
exec<TypeName extends R['typeName']>(typeName: TypeName, query: QueryExpression<Extract<R, {
typeName: TypeName;
}>>): Array<Extract<R, {
typeName: TypeName;
}>>;
filterHistory<TypeName extends R['typeName']>(typeName: TypeName): Computed<number, RecordsDiff<Extract<R, {
typeName: TypeName;
}>>>;
ids<TypeName extends R['typeName']>(typeName: TypeName, queryCreator?: () => QueryExpression<Extract<R, {
typeName: TypeName;
}>>, name?: string): Computed<Set<IdOf<Extract<R, {
typeName: TypeName;
}>>>, CollectionDiff<IdOf<Extract<R, {
typeName: TypeName;
}>>>>;
index<TypeName extends R['typeName'], Property extends string & keyof Extract<R, {
typeName: TypeName;
}>>(typeName: TypeName, property: Property): RSIndex<Extract<R, {
typeName: TypeName;
}>, Property>;
record<TypeName extends R['typeName']>(typeName: TypeName, queryCreator?: () => QueryExpression<Extract<R, {
typeName: TypeName;
}>>, name?: string): Computed<Extract<R, {
typeName: TypeName;
}> | undefined>;
records<TypeName extends R['typeName']>(typeName: TypeName, queryCreator?: () => QueryExpression<Extract<R, {
typeName: TypeName;
}>>, name?: string): Computed<Array<Extract<R, {
typeName: TypeName;
}>>>;
}
// @public (undocumented) // @public (undocumented)
export class StoreSchema<R extends UnknownRecord, P = unknown> { export class StoreSchema<R extends UnknownRecord, P = unknown> {
// (undocumented) // (undocumented)

View file

@ -1,6 +1,6 @@
export type { BaseRecord, IdOf, RecordId, UnknownRecord } from './lib/BaseRecord' export type { BaseRecord, IdOf, RecordId, UnknownRecord } from './lib/BaseRecord'
export { IncrementalSetConstructor } from './lib/IncrementalSetConstructor' export { IncrementalSetConstructor } from './lib/IncrementalSetConstructor'
export { RecordType, assertIdType, createRecordType } from './lib/RecordType' export { RecordType, assertIdType, createRecordType, type RecordScope } from './lib/RecordType'
export { export {
createEmptyRecordsDiff, createEmptyRecordsDiff,
isRecordsDiffEmpty, isRecordsDiffEmpty,
@ -9,7 +9,15 @@ export {
squashRecordDiffsMutable, squashRecordDiffsMutable,
type RecordsDiff, type RecordsDiff,
} from './lib/RecordsDiff' } from './lib/RecordsDiff'
export { Store, createComputedCache } from './lib/Store' export {
Store,
createComputedCache,
type ChangeSource,
type RecordFromId,
type StoreListenerFilters,
type StoreObject,
type StoreObjectRecordType,
} from './lib/Store'
export type { export type {
CollectionDiff, CollectionDiff,
ComputedCache, ComputedCache,
@ -21,6 +29,7 @@ export type {
StoreValidator, StoreValidator,
StoreValidators, StoreValidators,
} from './lib/Store' } from './lib/Store'
export { StoreQueries, type RSIndex, type RSIndexDiff, type RSIndexMap } from './lib/StoreQueries'
export { StoreSchema } from './lib/StoreSchema' export { StoreSchema } from './lib/StoreSchema'
export type { export type {
SerializedSchema, SerializedSchema,
@ -39,6 +48,7 @@ export {
type StoreOperationCompleteHandler, type StoreOperationCompleteHandler,
} from './lib/StoreSideEffects' } from './lib/StoreSideEffects'
export { devFreeze } from './lib/devFreeze' export { devFreeze } from './lib/devFreeze'
export { type QueryExpression, type QueryValueMatcher } from './lib/executeQuery'
export { export {
MigrationFailureReason, MigrationFailureReason,
createMigrationIds, createMigrationIds,
@ -47,6 +57,7 @@ export {
// eslint-disable-next-line deprecation/deprecation // eslint-disable-next-line deprecation/deprecation
defineMigrations, defineMigrations,
parseMigrationId, parseMigrationId,
type LegacyBaseMigrationsInfo,
type LegacyMigration, type LegacyMigration,
type LegacyMigrations, type LegacyMigrations,
type Migration, type Migration,
@ -55,4 +66,3 @@ export {
type MigrationSequence, type MigrationSequence,
type StandaloneDependsOn, type StandaloneDependsOn,
} from './lib/migrate' } from './lib/migrate'
export type { AllRecords } from './lib/type-utils'

View file

@ -17,8 +17,6 @@ export interface BaseRecord<TypeName extends string, Id extends RecordId<Unknown
/** @public */ /** @public */
export type UnknownRecord = BaseRecord<string, RecordId<UnknownRecord>> export type UnknownRecord = BaseRecord<string, RecordId<UnknownRecord>>
export type OmitMeta<R extends UnknownRecord> = R extends R ? Omit<R, 'id' | 'typeName'> : R
export function isRecord(record: unknown): record is UnknownRecord { export function isRecord(record: unknown): record is UnknownRecord {
return typeof record === 'object' && record !== null && 'id' in record && 'typeName' in record return typeof record === 'object' && record !== null && 'id' in record && 'typeName' in record
} }

View file

@ -1,6 +1,6 @@
import { objectMapEntries, structuredClone } from '@tldraw/utils' import { objectMapEntries, structuredClone } from '@tldraw/utils'
import { nanoid } from 'nanoid' import { nanoid } from 'nanoid'
import { IdOf, OmitMeta, UnknownRecord } from './BaseRecord' import { IdOf, UnknownRecord } from './BaseRecord'
import { StoreValidator } from './Store' import { StoreValidator } from './Store'
export type RecordTypeRecord<R extends RecordType<any, any>> = ReturnType<R['create']> export type RecordTypeRecord<R extends RecordType<any, any>> = ReturnType<R['create']>
@ -26,7 +26,7 @@ export class RecordType<
R extends UnknownRecord, R extends UnknownRecord,
RequiredProperties extends keyof Omit<R, 'id' | 'typeName'>, RequiredProperties extends keyof Omit<R, 'id' | 'typeName'>,
> { > {
readonly createDefaultProperties: () => Exclude<OmitMeta<R>, RequiredProperties> readonly createDefaultProperties: () => Exclude<Omit<R, 'id' | 'typeName'>, RequiredProperties>
readonly validator: StoreValidator<R> readonly validator: StoreValidator<R>
readonly ephemeralKeys?: { readonly [K in Exclude<keyof R, 'id' | 'typeName'>]: boolean } readonly ephemeralKeys?: { readonly [K in Exclude<keyof R, 'id' | 'typeName'>]: boolean }
readonly ephemeralKeySet: ReadonlySet<string> readonly ephemeralKeySet: ReadonlySet<string>
@ -41,7 +41,10 @@ export class RecordType<
*/ */
public readonly typeName: R['typeName'], public readonly typeName: R['typeName'],
config: { config: {
readonly createDefaultProperties: () => Exclude<OmitMeta<R>, RequiredProperties> readonly createDefaultProperties: () => Exclude<
Omit<R, 'id' | 'typeName'>,
RequiredProperties
>
readonly validator?: StoreValidator<R> readonly validator?: StoreValidator<R>
readonly scope?: RecordScope readonly scope?: RecordScope
readonly ephemeralKeys?: { readonly [K in Exclude<keyof R, 'id' | 'typeName'>]: boolean } readonly ephemeralKeys?: { readonly [K in Exclude<keyof R, 'id' | 'typeName'>]: boolean }

View file

@ -19,7 +19,9 @@ import { SerializedSchema, StoreSchema } from './StoreSchema'
import { StoreSideEffects } from './StoreSideEffects' import { StoreSideEffects } from './StoreSideEffects'
import { devFreeze } from './devFreeze' import { devFreeze } from './devFreeze'
type RecFromId<K extends RecordId<UnknownRecord>> = K extends RecordId<infer R> ? R : never /** @public */
export type RecordFromId<K extends RecordId<UnknownRecord>> =
K extends RecordId<infer R> ? R : never
/** /**
* A diff describing the changes to a collection. * A diff describing the changes to a collection.
@ -31,8 +33,10 @@ export interface CollectionDiff<T> {
removed?: Set<T> removed?: Set<T>
} }
/** @public */
export type ChangeSource = 'user' | 'remote' export type ChangeSource = 'user' | 'remote'
/** @public */
export interface StoreListenerFilters { export interface StoreListenerFilters {
source: ChangeSource | 'all' source: ChangeSource | 'all'
scope: RecordScope | 'all' scope: RecordScope | 'all'
@ -450,7 +454,7 @@ export class Store<R extends UnknownRecord = UnknownRecord, Props = unknown> {
* @param id - The id of the record to get. * @param id - The id of the record to get.
* @public * @public
*/ */
get = <K extends IdOf<R>>(id: K): RecFromId<K> | undefined => { get = <K extends IdOf<R>>(id: K): RecordFromId<K> | undefined => {
return this.atoms.get()[id]?.get() as any return this.atoms.get()[id]?.get() as any
} }
@ -460,7 +464,7 @@ export class Store<R extends UnknownRecord = UnknownRecord, Props = unknown> {
* @param id - The id of the record to get. * @param id - The id of the record to get.
* @public * @public
*/ */
unsafeGetWithoutCapture = <K extends IdOf<R>>(id: K): RecFromId<K> | undefined => { unsafeGetWithoutCapture = <K extends IdOf<R>>(id: K): RecordFromId<K> | undefined => {
return this.atoms.get()[id]?.__unsafe__getWithoutCapture() as any return this.atoms.get()[id]?.__unsafe__getWithoutCapture() as any
} }
@ -602,14 +606,14 @@ export class Store<R extends UnknownRecord = UnknownRecord, Props = unknown> {
* @param id - The id of the record to update. * @param id - The id of the record to update.
* @param updater - A function that updates the record. * @param updater - A function that updates the record.
*/ */
update = <K extends IdOf<R>>(id: K, updater: (record: RecFromId<K>) => RecFromId<K>) => { update = <K extends IdOf<R>>(id: K, updater: (record: RecordFromId<K>) => RecordFromId<K>) => {
const atom = this.atoms.get()[id] const atom = this.atoms.get()[id]
if (!atom) { if (!atom) {
console.error(`Record ${id} not found. This is probably an error`) console.error(`Record ${id} not found. This is probably an error`)
return return
} }
this.put([updater(atom.__unsafe__getWithoutCapture() as any as RecFromId<K>) as any]) this.put([updater(atom.__unsafe__getWithoutCapture() as any as RecordFromId<K>) as any])
} }
/** /**
@ -973,8 +977,10 @@ class HistoryAccumulator<T extends UnknownRecord> {
} }
} }
type StoreContext<R extends UnknownRecord> = Store<R> | { store: Store<R> } /** @public */
type ContextRecordType<Context extends StoreContext<any>> = export type StoreObject<R extends UnknownRecord> = Store<R> | { store: Store<R> }
/** @public */
export type StoreObjectRecordType<Context extends StoreObject<any>> =
Context extends Store<infer R> ? R : Context extends { store: Store<infer R> } ? R : never Context extends Store<infer R> ? R : Context extends { store: Store<infer R> } ? R : never
/** /**
@ -992,9 +998,9 @@ type ContextRecordType<Context extends StoreContext<any>> =
* @public * @public
*/ */
export function createComputedCache< export function createComputedCache<
Context extends StoreContext<any>, Context extends StoreObject<any>,
Result, Result,
Record extends ContextRecordType<Context> = ContextRecordType<Context>, Record extends StoreObjectRecordType<Context> = StoreObjectRecordType<Context>,
>( >(
name: string, name: string,
derive: (context: Context, record: Record) => Result | undefined, derive: (context: Context, record: Record) => Result | undefined,

View file

@ -16,24 +16,28 @@ import { RecordsDiff } from './RecordsDiff'
import { diffSets } from './setUtils' import { diffSets } from './setUtils'
import { CollectionDiff } from './Store' import { CollectionDiff } from './Store'
/** @public */
export type RSIndexDiff< export type RSIndexDiff<
R extends UnknownRecord, R extends UnknownRecord,
Property extends string & keyof R = string & keyof R, Property extends string & keyof R = string & keyof R,
> = Map<R[Property], CollectionDiff<IdOf<R>>> > = Map<R[Property], CollectionDiff<IdOf<R>>>
/** @public */
export type RSIndexMap< export type RSIndexMap<
R extends UnknownRecord, R extends UnknownRecord,
Property extends string & keyof R = string & keyof R, Property extends string & keyof R = string & keyof R,
> = Map<R[Property], Set<IdOf<R>>> > = Map<R[Property], Set<IdOf<R>>>
/** @public */
export type RSIndex< export type RSIndex<
R extends UnknownRecord, R extends UnknownRecord,
Property extends string & keyof R = string & keyof R, Property extends string & keyof R = string & keyof R,
> = Computed<Map<R[Property], Set<IdOf<R>>>, RSIndexDiff<R, Property>> > = Computed<RSIndexMap<R, Property>, RSIndexDiff<R, Property>>
/** /**
* A class that provides a 'namespace' for the various kinds of indexes one may wish to derive from * A class that provides a 'namespace' for the various kinds of indexes one may wish to derive from
* the record store. * the record store.
* @public
*/ */
export class StoreQueries<R extends UnknownRecord> { export class StoreQueries<R extends UnknownRecord> {
constructor( constructor(

View file

@ -2,17 +2,19 @@ import { IdOf, UnknownRecord } from './BaseRecord'
import { intersectSets } from './setUtils' import { intersectSets } from './setUtils'
import { StoreQueries } from './StoreQueries' import { StoreQueries } from './StoreQueries'
export type ValueMatcher<T> = { eq: T } | { neq: T } | { gt: number } /** @public */
export type QueryValueMatcher<T> = { eq: T } | { neq: T } | { gt: number }
/** @public */
export type QueryExpression<R extends object> = { export type QueryExpression<R extends object> = {
[k in keyof R & string]?: ValueMatcher<R[k]> [k in keyof R & string]?: QueryValueMatcher<R[k]>
// todo: handle nesting // todo: handle nesting
// | (R[k] extends object ? { match: QueryExpression<R[k]> } : never) // | (R[k] extends object ? { match: QueryExpression<R[k]> } : never)
} }
export function objectMatchesQuery<T extends object>(query: QueryExpression<T>, object: T) { export function objectMatchesQuery<T extends object>(query: QueryExpression<T>, object: T) {
for (const [key, _matcher] of Object.entries(query)) { for (const [key, _matcher] of Object.entries(query)) {
const matcher = _matcher as ValueMatcher<T> const matcher = _matcher as QueryValueMatcher<T>
const value = object[key as keyof T] const value = object[key as keyof T]
// if you add matching logic here, make sure you also update executeQuery, // if you add matching logic here, make sure you also update executeQuery,
// where initial data is pulled out of the indexes, since that requires different // where initial data is pulled out of the indexes, since that requires different

View file

@ -163,7 +163,8 @@ export type Migration = {
} }
) )
interface LegacyBaseMigrationsInfo { /** @public */
export interface LegacyBaseMigrationsInfo {
firstVersion: number firstVersion: number
currentVersion: number currentVersion: number
migrators: { [version: number]: LegacyMigration } migrators: { [version: number]: LegacyMigration }

View file

@ -1,13 +0,0 @@
import { RecordType } from './RecordType'
import { Store } from './Store'
type ExtractRecordType<T extends Store<any>> = T extends Store<infer R> ? R : never
type ExtractR<T extends RecordType<any, any>> = T extends RecordType<infer S, any> ? S : never
/**
* Get the type of all records in a record store.
*
* @public
*/
export type AllRecords<T extends Store<any>> = ExtractR<ExtractRecordType<T>>

File diff suppressed because one or more lines are too long

View file

@ -1,18 +1,16 @@
/// <reference types="react" /> /// <reference types="react" />
export { preloadFont } from './lib/utils/assets/preload-font'
export { useCanRedo, useCanUndo } from './lib/ui/hooks/menu-hooks'
// eslint-disable-next-line local/no-export-star // eslint-disable-next-line local/no-export-star
export * from '@tldraw/editor' export * from '@tldraw/editor'
export { Tldraw, type TldrawProps } from './lib/Tldraw'
export { Tldraw, type TLComponents, type TldrawProps } from './lib/Tldraw'
export { TldrawImage, type TldrawImageProps } from './lib/TldrawImage' export { TldrawImage, type TldrawImageProps } from './lib/TldrawImage'
export { TldrawHandles } from './lib/canvas/TldrawHandles' export { TldrawHandles } from './lib/canvas/TldrawHandles'
export { TldrawScribble } from './lib/canvas/TldrawScribble' export { TldrawScribble } from './lib/canvas/TldrawScribble'
export { TldrawSelectionBackground } from './lib/canvas/TldrawSelectionBackground' export { TldrawSelectionBackground } from './lib/canvas/TldrawSelectionBackground'
export { TldrawSelectionForeground } from './lib/canvas/TldrawSelectionForeground' export { TldrawSelectionForeground } from './lib/canvas/TldrawSelectionForeground'
export { defaultBindingUtils } from './lib/defaultBindingUtils' export { defaultBindingUtils } from './lib/defaultBindingUtils'
export { type TLExternalContentProps } from './lib/defaultExternalContentHandlers'
export { defaultShapeTools } from './lib/defaultShapeTools' export { defaultShapeTools } from './lib/defaultShapeTools'
export { defaultShapeUtils } from './lib/defaultShapeUtils' export { defaultShapeUtils } from './lib/defaultShapeUtils'
export { defaultTools } from './lib/defaultTools' export { defaultTools } from './lib/defaultTools'
@ -40,139 +38,30 @@ export { LineShapeUtil } from './lib/shapes/line/LineShapeUtil'
export { NoteShapeTool } from './lib/shapes/note/NoteShapeTool' export { NoteShapeTool } from './lib/shapes/note/NoteShapeTool'
export { NoteShapeUtil } from './lib/shapes/note/NoteShapeUtil' export { NoteShapeUtil } from './lib/shapes/note/NoteShapeUtil'
export { useDefaultColorTheme } from './lib/shapes/shared/ShapeFill' export { useDefaultColorTheme } from './lib/shapes/shared/ShapeFill'
export { TextLabel } from './lib/shapes/shared/TextLabel' export { TextLabel, type TextLabelProps } from './lib/shapes/shared/TextLabel'
export {
FONT_FAMILIES,
LABEL_FONT_SIZES,
TEXT_PROPS,
} from './lib/shapes/shared/default-shape-constants'
export { getPerfectDashProps } from './lib/shapes/shared/getPerfectDashProps' export { getPerfectDashProps } from './lib/shapes/shared/getPerfectDashProps'
export { useEditableText } from './lib/shapes/shared/useEditableText'
export { TextShapeTool } from './lib/shapes/text/TextShapeTool' export { TextShapeTool } from './lib/shapes/text/TextShapeTool'
export { TextShapeUtil } from './lib/shapes/text/TextShapeUtil' export { TextShapeUtil } from './lib/shapes/text/TextShapeUtil'
export { VideoShapeUtil } from './lib/shapes/video/VideoShapeUtil' export { VideoShapeUtil } from './lib/shapes/video/VideoShapeUtil'
export { type StyleValuesForUi } from './lib/styles'
export { EraserTool } from './lib/tools/EraserTool/EraserTool' export { EraserTool } from './lib/tools/EraserTool/EraserTool'
export { HandTool } from './lib/tools/HandTool/HandTool' export { HandTool } from './lib/tools/HandTool/HandTool'
export { LaserTool } from './lib/tools/LaserTool/LaserTool' export { LaserTool } from './lib/tools/LaserTool/LaserTool'
export { SelectTool } from './lib/tools/SelectTool/SelectTool' export { SelectTool } from './lib/tools/SelectTool/SelectTool'
export { getOccludedChildren, kickoutOccludedShapes } from './lib/tools/SelectTool/selectHelpers' export { getOccludedChildren, kickoutOccludedShapes } from './lib/tools/SelectTool/selectHelpers'
export { ZoomTool } from './lib/tools/ZoomTool/ZoomTool' export { ZoomTool } from './lib/tools/ZoomTool/ZoomTool'
// UI
export { useEditableText } from './lib/shapes/shared/useEditableText'
export { TldrawUi, type TldrawUiBaseProps, type TldrawUiProps } from './lib/ui/TldrawUi' export { TldrawUi, type TldrawUiBaseProps, type TldrawUiProps } from './lib/ui/TldrawUi'
export { setDefaultUiAssetUrls, type TLUiAssetUrlOverrides } from './lib/ui/assetUrls'
export { OfflineIndicator } from './lib/ui/components/OfflineIndicator/OfflineIndicator'
export { Spinner } from './lib/ui/components/Spinner'
export { PORTRAIT_BREAKPOINT } from './lib/ui/constants'
export { export {
TldrawUiContextProvider, setDefaultUiAssetUrls,
type TldrawUiContextProviderProps, type TLUiAssetUrlOverrides,
} from './lib/ui/context/TldrawUiContextProvider' type TLUiAssetUrls,
export { } from './lib/ui/assetUrls'
useActions,
type TLUiActionItem,
type TLUiActionsContextType,
} from './lib/ui/context/actions'
export { AssetUrlsProvider, useAssetUrls } from './lib/ui/context/asset-urls'
export { BreakPointProvider, useBreakpoint } from './lib/ui/context/breakpoints'
export {
useDialogs,
type TLUiDialog,
type TLUiDialogProps,
type TLUiDialogsContextType,
} from './lib/ui/context/dialogs'
export {
UiEventsProvider,
useUiEvents,
type EventsProviderProps,
type TLUiEventContextType,
type TLUiEventHandler,
type TLUiEventMap,
type TLUiEventSource,
} from './lib/ui/context/events'
export {
useToasts,
type AlertSeverity,
type TLUiToast,
type TLUiToastAction,
type TLUiToastsContextType,
} from './lib/ui/context/toasts'
export { useMenuClipboardEvents, useNativeClipboardEvents } from './lib/ui/hooks/useClipboardEvents'
export { useCopyAs } from './lib/ui/hooks/useCopyAs'
export { useExportAs } from './lib/ui/hooks/useExportAs'
export { useKeyboardShortcuts } from './lib/ui/hooks/useKeyboardShortcuts'
export { useLocalStorageState } from './lib/ui/hooks/useLocalStorageState'
export { useMenuIsOpen } from './lib/ui/hooks/useMenuIsOpen'
export { usePreloadAssets } from './lib/ui/hooks/usePreloadAssets'
export { useReadonly } from './lib/ui/hooks/useReadonly'
export { useRelevantStyles } from './lib/ui/hooks/useRelevantStyles'
export {
useTools,
type TLUiToolItem,
type TLUiToolsContextType,
type TLUiToolsProviderProps,
} from './lib/ui/hooks/useTools'
export { type TLUiTranslationKey } from './lib/ui/hooks/useTranslation/TLUiTranslationKey'
export { type TLUiTranslation } from './lib/ui/hooks/useTranslation/translations'
export {
useCurrentTranslation,
useTranslation,
type TLUiTranslationContextType,
} from './lib/ui/hooks/useTranslation/useTranslation'
export { type TLUiIconType } from './lib/ui/icon-types'
export { useDefaultHelpers, type TLUiOverrides } from './lib/ui/overrides'
export { containBoxSize, downsizeImage } from './lib/utils/assets/assets'
export { getEmbedInfo } from './lib/utils/embeds/embeds'
export { copyAs } from './lib/utils/export/copyAs'
export { exportToBlob, getSvgAsImage } from './lib/utils/export/export'
export { exportAs, type TLExportType } from './lib/utils/export/exportAs'
export { fitFrameToContent, removeFrame } from './lib/utils/frames/frames'
export {
defaultEditorAssetUrls,
setDefaultEditorAssetUrls,
} from './lib/utils/static-assets/assetUrls'
export { truncateStringWithEllipsis } from './lib/utils/text/text'
export {
buildFromV1Document,
type LegacyTldrawDocument,
} from './lib/utils/tldr/buildFromV1Document'
export {
TLDRAW_FILE_EXTENSION,
parseAndLoadDocument,
parseTldrawJsonFile,
serializeTldrawJson,
serializeTldrawJsonBlob,
type TldrawFile,
} from './lib/utils/tldr/file'
// Minimap default component
export { DefaultMinimap } from './lib/ui/components/Minimap/DefaultMinimap'
// Helper to unwrap label from action items
export { unwrapLabel } from './lib/ui/context/actions'
export {
TldrawUiComponentsProvider,
useTldrawUiComponents,
type TLUiComponents,
type TLUiComponentsProviderProps,
} from './lib/ui/context/components'
export { DefaultPageMenu } from './lib/ui/components/PageMenu/DefaultPageMenu'
export { PageItemInput } from './lib/ui/components/PageMenu/PageItemInput'
export { PageItemSubmenu } from './lib/ui/components/PageMenu/PageItemSubmenu'
export { DefaultNavigationPanel } from './lib/ui/components/NavigationPanel/DefaultNavigationPanel'
export {
DefaultStylePanel,
type TLUiStylePanelProps,
} from './lib/ui/components/StylePanel/DefaultStylePanel'
export {
ArrowheadStylePickerSet,
CommonStylePickerSet,
DefaultStylePanelContent,
GeoStylePickerSet,
OpacitySlider,
SplineStylePickerSet,
TextStylePickerSet,
type TLUiStylePanelContentProps,
} from './lib/ui/components/StylePanel/DefaultStylePanelContent'
export { export {
DefaultActionsMenu, DefaultActionsMenu,
type TLUiActionsMenuProps, type TLUiActionsMenuProps,
@ -187,14 +76,22 @@ export {
StackMenuItems, StackMenuItems,
ZoomOrRotateMenuItem, ZoomOrRotateMenuItem,
} from './lib/ui/components/ActionsMenu/DefaultActionsMenuContent' } from './lib/ui/components/ActionsMenu/DefaultActionsMenuContent'
export { export {
DefaultContextMenu as ContextMenu, DefaultContextMenu as ContextMenu,
DefaultContextMenu, DefaultContextMenu,
type TLUiContextMenuProps, type TLUiContextMenuProps,
} from './lib/ui/components/ContextMenu/DefaultContextMenu' } from './lib/ui/components/ContextMenu/DefaultContextMenu'
export { DefaultContextMenuContent } from './lib/ui/components/ContextMenu/DefaultContextMenuContent' export { DefaultContextMenuContent } from './lib/ui/components/ContextMenu/DefaultContextMenuContent'
export {
DefaultDebugMenu,
type TLUiDebugMenuProps,
} from './lib/ui/components/DebugMenu/DefaultDebugMenu'
export {
DebugFlags,
DefaultDebugMenuContent,
ExampleDialog,
FeatureFlags,
} from './lib/ui/components/DebugMenu/DefaultDebugMenuContent'
export { export {
DefaultHelpMenu, DefaultHelpMenu,
type TLUiHelpMenuProps, type TLUiHelpMenuProps,
@ -203,8 +100,99 @@ export {
DefaultHelpMenuContent, DefaultHelpMenuContent,
KeyboardShortcutsMenuItem, KeyboardShortcutsMenuItem,
} from './lib/ui/components/HelpMenu/DefaultHelpMenuContent' } from './lib/ui/components/HelpMenu/DefaultHelpMenuContent'
export {
DefaultHelperButtons,
type TLUiHelperButtonsProps,
} from './lib/ui/components/HelperButtons/DefaultHelperButtons'
export { DefaultHelperButtonsContent } from './lib/ui/components/HelperButtons/DefaultHelperButtonsContent'
export {
DefaultKeyboardShortcutsDialog,
type TLUiKeyboardShortcutsDialogProps,
} from './lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialog'
export { DefaultKeyboardShortcutsDialogContent } from './lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent'
export { LanguageMenu } from './lib/ui/components/LanguageMenu' export { LanguageMenu } from './lib/ui/components/LanguageMenu'
export {
DefaultMainMenu,
type TLUiMainMenuProps,
} from './lib/ui/components/MainMenu/DefaultMainMenu'
export {
DefaultMainMenuContent,
EditSubmenu,
ExportFileContentSubMenu,
ExtrasGroup,
MiscMenuGroup,
PreferencesGroup,
UndoRedoGroup,
ViewSubmenu,
} from './lib/ui/components/MainMenu/DefaultMainMenuContent'
export { DefaultMinimap } from './lib/ui/components/Minimap/DefaultMinimap'
export { DefaultNavigationPanel } from './lib/ui/components/NavigationPanel/DefaultNavigationPanel'
export { OfflineIndicator } from './lib/ui/components/OfflineIndicator/OfflineIndicator'
export { DefaultPageMenu } from './lib/ui/components/PageMenu/DefaultPageMenu'
export { PageItemInput } from './lib/ui/components/PageMenu/PageItemInput'
export {
PageItemSubmenu,
type PageItemSubmenuProps,
} from './lib/ui/components/PageMenu/PageItemSubmenu'
export {
DefaultQuickActions,
type TLUiQuickActionsProps,
} from './lib/ui/components/QuickActions/DefaultQuickActions'
export { DefaultQuickActionsContent } from './lib/ui/components/QuickActions/DefaultQuickActionsContent'
export { Spinner } from './lib/ui/components/Spinner'
export {
DefaultStylePanel,
type TLUiStylePanelProps,
} from './lib/ui/components/StylePanel/DefaultStylePanel'
export {
ArrowheadStylePickerSet,
CommonStylePickerSet,
DefaultStylePanelContent,
GeoStylePickerSet,
OpacitySlider,
SplineStylePickerSet,
TextStylePickerSet,
type TLUiStylePanelContentProps,
} from './lib/ui/components/StylePanel/DefaultStylePanelContent'
export { DefaultToolbar } from './lib/ui/components/Toolbar/DefaultToolbar'
export {
ArrowDownToolbarItem,
ArrowLeftToolbarItem,
ArrowRightToolbarItem,
ArrowToolbarItem,
ArrowUpToolbarItem,
AssetToolbarItem,
CheckBoxToolbarItem,
CloudToolbarItem,
DefaultToolbarContent,
DiamondToolbarItem,
DrawToolbarItem,
EllipseToolbarItem,
EraserToolbarItem,
FrameToolbarItem,
HandToolbarItem,
HexagonToolbarItem,
HighlightToolbarItem,
LaserToolbarItem,
LineToolbarItem,
NoteToolbarItem,
OvalToolbarItem,
RectangleToolbarItem,
RhombusToolbarItem,
SelectToolbarItem,
StarToolbarItem,
TextToolbarItem,
ToolbarItem,
TrapezoidToolbarItem,
TriangleToolbarItem,
XBoxToolbarItem,
useIsToolSelected,
} from './lib/ui/components/Toolbar/DefaultToolbarContent'
export {
DefaultZoomMenu,
type TLUiZoomMenuProps,
} from './lib/ui/components/ZoomMenu/DefaultZoomMenu'
export { DefaultZoomMenuContent } from './lib/ui/components/ZoomMenu/DefaultZoomMenuContent'
export { export {
ArrangeMenuSubmenu, ArrangeMenuSubmenu,
ClipboardMenuGroup, ClipboardMenuGroup,
@ -243,62 +231,6 @@ export {
ZoomToFitMenuItem, ZoomToFitMenuItem,
ZoomToSelectionMenuItem, ZoomToSelectionMenuItem,
} from './lib/ui/components/menu-items' } from './lib/ui/components/menu-items'
export {
DefaultMainMenu,
type TLUiMainMenuProps,
} from './lib/ui/components/MainMenu/DefaultMainMenu'
export {
DefaultMainMenuContent,
EditSubmenu,
ExportFileContentSubMenu,
ExtrasGroup,
MiscMenuGroup,
PreferencesGroup,
UndoRedoGroup,
ViewSubmenu,
} from './lib/ui/components/MainMenu/DefaultMainMenuContent'
export {
DefaultQuickActions,
type TLUiQuickActionsProps,
} from './lib/ui/components/QuickActions/DefaultQuickActions'
export { DefaultQuickActionsContent } from './lib/ui/components/QuickActions/DefaultQuickActionsContent'
export {
DefaultZoomMenu,
type TLUiZoomMenuProps,
} from './lib/ui/components/ZoomMenu/DefaultZoomMenu'
export { DefaultZoomMenuContent } from './lib/ui/components/ZoomMenu/DefaultZoomMenuContent'
export {
DefaultHelperButtons,
type TLUiHelperButtonsProps,
} from './lib/ui/components/HelperButtons/DefaultHelperButtons'
export { DefaultHelperButtonsContent } from './lib/ui/components/HelperButtons/DefaultHelperButtonsContent'
export {
DefaultKeyboardShortcutsDialog,
type TLUiKeyboardShortcutsDialogProps,
} from './lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialog'
export { DefaultKeyboardShortcutsDialogContent } from './lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent'
export {
DefaultDebugMenu,
type TLUiDebugMenuProps,
} from './lib/ui/components/DebugMenu/DefaultDebugMenu'
export {
DebugFlags,
DefaultDebugMenuContent,
ExampleDialog,
FeatureFlags,
} from './lib/ui/components/DebugMenu/DefaultDebugMenuContent'
export { type TLComponents } from './lib/Tldraw'
/* ------------------- Primitives ------------------- */
// Button
export { export {
TldrawUiButton, TldrawUiButton,
type TLUiButtonProps, type TLUiButtonProps,
@ -315,14 +247,10 @@ export {
TldrawUiButtonLabel, TldrawUiButtonLabel,
type TLUiButtonLabelProps, type TLUiButtonLabelProps,
} from './lib/ui/components/primitives/Button/TldrawUiButtonLabel' } from './lib/ui/components/primitives/Button/TldrawUiButtonLabel'
// Button picker
export { export {
TldrawUiButtonPicker, TldrawUiButtonPicker,
type TLUiButtonPickerProps, type TLUiButtonPickerProps,
} from './lib/ui/components/primitives/TldrawUiButtonPicker' } from './lib/ui/components/primitives/TldrawUiButtonPicker'
// Dialog
export { export {
TldrawUiDialogBody, TldrawUiDialogBody,
TldrawUiDialogCloseButton, TldrawUiDialogCloseButton,
@ -334,8 +262,6 @@ export {
type TLUiDialogHeaderProps, type TLUiDialogHeaderProps,
type TLUiDialogTitleProps, type TLUiDialogTitleProps,
} from './lib/ui/components/primitives/TldrawUiDialog' } from './lib/ui/components/primitives/TldrawUiDialog'
// Dropdown Menu
export { export {
TldrawUiDropdownMenuCheckboxItem, TldrawUiDropdownMenuCheckboxItem,
TldrawUiDropdownMenuContent, TldrawUiDropdownMenuContent,
@ -355,17 +281,9 @@ export {
type TLUiDropdownMenuSubTriggerProps, type TLUiDropdownMenuSubTriggerProps,
type TLUiDropdownMenuTriggerProps, type TLUiDropdownMenuTriggerProps,
} from './lib/ui/components/primitives/TldrawUiDropdownMenu' } from './lib/ui/components/primitives/TldrawUiDropdownMenu'
// Icon
export { TldrawUiIcon, type TLUiIconProps } from './lib/ui/components/primitives/TldrawUiIcon' export { TldrawUiIcon, type TLUiIconProps } from './lib/ui/components/primitives/TldrawUiIcon'
// Input
export { TldrawUiInput, type TLUiInputProps } from './lib/ui/components/primitives/TldrawUiInput' export { TldrawUiInput, type TLUiInputProps } from './lib/ui/components/primitives/TldrawUiInput'
// Kbd
export { TldrawUiKbd, type TLUiKbdProps } from './lib/ui/components/primitives/TldrawUiKbd' export { TldrawUiKbd, type TLUiKbdProps } from './lib/ui/components/primitives/TldrawUiKbd'
// Popover
export { export {
TldrawUiPopover, TldrawUiPopover,
TldrawUiPopoverContent, TldrawUiPopoverContent,
@ -374,49 +292,7 @@ export {
type TLUiPopoverProps, type TLUiPopoverProps,
type TLUiPopoverTriggerProps, type TLUiPopoverTriggerProps,
} from './lib/ui/components/primitives/TldrawUiPopover' } from './lib/ui/components/primitives/TldrawUiPopover'
// Slider
export { TldrawUiSlider, type TLUiSliderProps } from './lib/ui/components/primitives/TldrawUiSlider' export { TldrawUiSlider, type TLUiSliderProps } from './lib/ui/components/primitives/TldrawUiSlider'
// Toolbar
export { DefaultToolbar } from './lib/ui/components/Toolbar/DefaultToolbar'
export {
ArrowDownToolbarItem,
ArrowLeftToolbarItem,
ArrowRightToolbarItem,
ArrowToolbarItem,
ArrowUpToolbarItem,
AssetToolbarItem,
CheckBoxToolbarItem,
CloudToolbarItem,
DefaultToolbarContent,
DiamondToolbarItem,
DrawToolbarItem,
EllipseToolbarItem,
EraserToolbarItem,
FrameToolbarItem,
HandToolbarItem,
HexagonToolbarItem,
HighlightToolbarItem,
LaserToolbarItem,
LineToolbarItem,
NoteToolbarItem,
OvalToolbarItem,
RectangleToolbarItem,
RhombusToolbarItem,
SelectToolbarItem,
StarToolbarItem,
TextToolbarItem,
ToolbarItem,
TrapezoidToolbarItem,
TriangleToolbarItem,
XBoxToolbarItem,
useIsToolSelected,
} from './lib/ui/components/Toolbar/DefaultToolbarContent'
/* ----------------- Menu Primitives ---------------- */
// General UI components for building menus
export { export {
TldrawUiMenuCheckboxItem, TldrawUiMenuCheckboxItem,
type TLUiMenuCheckboxItemProps, type TLUiMenuCheckboxItemProps,
@ -424,6 +300,7 @@ export {
export { export {
TldrawUiMenuContextProvider, TldrawUiMenuContextProvider,
type TLUiMenuContextProviderProps, type TLUiMenuContextProviderProps,
type TldrawUiMenuContextType,
} from './lib/ui/components/primitives/menus/TldrawUiMenuContext' } from './lib/ui/components/primitives/menus/TldrawUiMenuContext'
export { export {
TldrawUiMenuGroup, TldrawUiMenuGroup,
@ -437,11 +314,130 @@ export {
TldrawUiMenuSubmenu, TldrawUiMenuSubmenu,
type TLUiMenuSubmenuProps, type TLUiMenuSubmenuProps,
} from './lib/ui/components/primitives/menus/TldrawUiMenuSubmenu' } from './lib/ui/components/primitives/menus/TldrawUiMenuSubmenu'
export { PORTRAIT_BREAKPOINT } from './lib/ui/constants'
/* ----------------- Constants ---------------- */
export { export {
FONT_FAMILIES, TldrawUiContextProvider,
LABEL_FONT_SIZES, type TldrawUiContextProviderProps,
TEXT_PROPS, } from './lib/ui/context/TldrawUiContextProvider'
} from './lib/shapes/shared/default-shape-constants' export {
unwrapLabel,
useActions,
type ActionsProviderProps,
type TLUiActionItem,
type TLUiActionsContextType,
} from './lib/ui/context/actions'
export { AssetUrlsProvider, useAssetUrls } from './lib/ui/context/asset-urls'
export { BreakPointProvider, useBreakpoint } from './lib/ui/context/breakpoints'
export {
TldrawUiComponentsProvider,
useTldrawUiComponents,
type TLUiComponents,
type TLUiComponentsProviderProps,
} from './lib/ui/context/components'
export {
useDialogs,
type TLUiDialog,
type TLUiDialogProps,
type TLUiDialogsContextType,
} from './lib/ui/context/dialogs'
export {
UiEventsProvider,
useUiEvents,
type EventsProviderProps,
type TLUiEventContextType,
type TLUiEventData,
type TLUiEventHandler,
type TLUiEventMap,
type TLUiEventSource,
} from './lib/ui/context/events'
export {
useToasts,
type AlertSeverity,
type TLUiToast,
type TLUiToastAction,
type TLUiToastsContextType,
} from './lib/ui/context/toasts'
export { useCanRedo, useCanUndo } from './lib/ui/hooks/menu-hooks'
export { useMenuClipboardEvents, useNativeClipboardEvents } from './lib/ui/hooks/useClipboardEvents'
export { useCopyAs } from './lib/ui/hooks/useCopyAs'
export { useExportAs } from './lib/ui/hooks/useExportAs'
export { useKeyboardShortcuts } from './lib/ui/hooks/useKeyboardShortcuts'
export { useLocalStorageState } from './lib/ui/hooks/useLocalStorageState'
export { useMenuIsOpen } from './lib/ui/hooks/useMenuIsOpen'
export { usePreloadAssets } from './lib/ui/hooks/usePreloadAssets'
export { useReadonly } from './lib/ui/hooks/useReadonly'
export { useRelevantStyles } from './lib/ui/hooks/useRelevantStyles'
export {
useTools,
type TLUiToolItem,
type TLUiToolsContextType,
type TLUiToolsProviderProps,
} from './lib/ui/hooks/useTools'
export { type TLUiTranslationKey } from './lib/ui/hooks/useTranslation/TLUiTranslationKey'
export { type TLUiTranslation } from './lib/ui/hooks/useTranslation/translations'
export {
useCurrentTranslation,
useTranslation,
type TLUiTranslationContextType,
type TLUiTranslationProviderProps,
} from './lib/ui/hooks/useTranslation/useTranslation'
export { type TLUiIconType } from './lib/ui/icon-types'
export { useDefaultHelpers, type TLUiOverrideHelpers, type TLUiOverrides } from './lib/ui/overrides'
export { containBoxSize, downsizeImage, type BoxWidthHeight } from './lib/utils/assets/assets'
export { preloadFont, type TLTypeFace } from './lib/utils/assets/preload-font'
export { getEmbedInfo, type TLEmbedResult } from './lib/utils/embeds/embeds'
export { copyAs, type TLCopyType } from './lib/utils/export/copyAs'
export { exportToBlob, getSvgAsImage } from './lib/utils/export/export'
export { exportAs, type TLExportType } from './lib/utils/export/exportAs'
export { fitFrameToContent, removeFrame } from './lib/utils/frames/frames'
export {
defaultEditorAssetUrls,
setDefaultEditorAssetUrls,
type TLEditorAssetUrls,
} from './lib/utils/static-assets/assetUrls'
export { truncateStringWithEllipsis } from './lib/utils/text/text'
export {
TLV1AlignStyle,
TLV1AssetType,
TLV1ColorStyle,
TLV1DashStyle,
TLV1Decoration,
TLV1FontStyle,
TLV1ShapeType,
TLV1SizeStyle,
buildFromV1Document,
type TLV1ArrowBinding,
type TLV1ArrowShape,
type TLV1Asset,
type TLV1BaseAsset,
type TLV1BaseBinding,
type TLV1BaseShape,
type TLV1Binding,
type TLV1Bounds,
type TLV1Document,
type TLV1DrawShape,
type TLV1EllipseShape,
type TLV1GroupShape,
type TLV1Handle,
type TLV1ImageAsset,
type TLV1ImageShape,
type TLV1Page,
type TLV1PageState,
type TLV1RectangleShape,
type TLV1Shape,
type TLV1ShapeStyles,
type TLV1StickyShape,
type TLV1TextShape,
type TLV1TriangleShape,
type TLV1VideoAsset,
type TLV1VideoShape,
} from './lib/utils/tldr/buildFromV1Document'
export {
TLDRAW_FILE_EXTENSION,
parseAndLoadDocument,
parseTldrawJsonFile,
serializeTldrawJson,
serializeTldrawJsonBlob,
type TldrawFile,
type TldrawFileParseError,
} from './lib/utils/tldr/file'

View file

@ -1,4 +1,4 @@
import { StateNode } from '@tldraw/editor' import { StateNode, TLStateNodeConstructor } from '@tldraw/editor'
import { Idle } from './toolStates/Idle' import { Idle } from './toolStates/Idle'
import { Pointing } from './toolStates/Pointing' import { Pointing } from './toolStates/Pointing'
@ -6,7 +6,7 @@ import { Pointing } from './toolStates/Pointing'
export class ArrowShapeTool extends StateNode { export class ArrowShapeTool extends StateNode {
static override id = 'arrow' static override id = 'arrow'
static override initial = 'idle' static override initial = 'idle'
static override children = () => [Idle, Pointing] static override children = (): TLStateNodeConstructor[] => [Idle, Pointing]
override shapeType = 'arrow' override shapeType = 'arrow'
} }

View file

@ -1,4 +1,4 @@
import { StateNode } from '@tldraw/editor' import { StateNode, TLStateNodeConstructor } from '@tldraw/editor'
import { Drawing } from './toolStates/Drawing' import { Drawing } from './toolStates/Drawing'
import { Idle } from './toolStates/Idle' import { Idle } from './toolStates/Idle'
@ -6,7 +6,7 @@ import { Idle } from './toolStates/Idle'
export class DrawShapeTool extends StateNode { export class DrawShapeTool extends StateNode {
static override id = 'draw' static override id = 'draw'
static override initial = 'idle' static override initial = 'idle'
static override children = () => [Idle, Drawing] static override children = (): TLStateNodeConstructor[] => [Idle, Drawing]
override shapeType = 'draw' override shapeType = 'draw'

View file

@ -1,4 +1,4 @@
import { StateNode } from '@tldraw/editor' import { StateNode, TLStateNodeConstructor } from '@tldraw/editor'
import { Idle } from './toolStates/Idle' import { Idle } from './toolStates/Idle'
import { Pointing } from './toolStates/Pointing' import { Pointing } from './toolStates/Pointing'
@ -6,6 +6,6 @@ import { Pointing } from './toolStates/Pointing'
export class GeoShapeTool extends StateNode { export class GeoShapeTool extends StateNode {
static override id = 'geo' static override id = 'geo'
static override initial = 'idle' static override initial = 'idle'
static override children = () => [Idle, Pointing] static override children = (): TLStateNodeConstructor[] => [Idle, Pointing]
override shapeType = 'geo' override shapeType = 'geo'
} }

View file

@ -1,5 +1,5 @@
// shared custody // shared custody
import { StateNode } from '@tldraw/editor' import { StateNode, TLStateNodeConstructor } from '@tldraw/editor'
import { Drawing } from '../draw/toolStates/Drawing' import { Drawing } from '../draw/toolStates/Drawing'
import { Idle } from '../draw/toolStates/Idle' import { Idle } from '../draw/toolStates/Idle'
@ -7,7 +7,7 @@ import { Idle } from '../draw/toolStates/Idle'
export class HighlightShapeTool extends StateNode { export class HighlightShapeTool extends StateNode {
static override id = 'highlight' static override id = 'highlight'
static override initial = 'idle' static override initial = 'idle'
static override children = () => [Idle, Drawing] static override children = (): TLStateNodeConstructor[] => [Idle, Drawing]
override shapeType = 'highlight' override shapeType = 'highlight'
override onExit = () => { override onExit = () => {

View file

@ -1,4 +1,4 @@
import { StateNode } from '@tldraw/editor' import { StateNode, TLStateNodeConstructor } from '@tldraw/editor'
import { Idle } from './toolStates/Idle' import { Idle } from './toolStates/Idle'
import { Pointing } from './toolStates/Pointing' import { Pointing } from './toolStates/Pointing'
@ -6,7 +6,7 @@ import { Pointing } from './toolStates/Pointing'
export class LineShapeTool extends StateNode { export class LineShapeTool extends StateNode {
static override id = 'line' static override id = 'line'
static override initial = 'idle' static override initial = 'idle'
static override children = () => [Idle, Pointing] static override children = (): TLStateNodeConstructor[] => [Idle, Pointing]
override shapeType = 'line' override shapeType = 'line'
} }

View file

@ -1,4 +1,4 @@
import { StateNode } from '@tldraw/editor' import { StateNode, TLStateNodeConstructor } from '@tldraw/editor'
import { Idle } from './toolStates/Idle' import { Idle } from './toolStates/Idle'
import { Pointing } from './toolStates/Pointing' import { Pointing } from './toolStates/Pointing'
@ -6,6 +6,6 @@ import { Pointing } from './toolStates/Pointing'
export class NoteShapeTool extends StateNode { export class NoteShapeTool extends StateNode {
static override id = 'note' static override id = 'note'
static override initial = 'idle' static override initial = 'idle'
static override children = () => [Idle, Pointing] static override children = (): TLStateNodeConstructor[] => [Idle, Pointing]
override shapeType = 'note' override shapeType = 'note'
} }

View file

@ -12,7 +12,8 @@ import { TextHelpers } from './TextHelpers'
import { isLegacyAlign } from './legacyProps' import { isLegacyAlign } from './legacyProps'
import { useEditableText } from './useEditableText' import { useEditableText } from './useEditableText'
interface TextLabelProps { /** @public */
export interface TextLabelProps {
id: TLShapeId id: TLShapeId
type: string type: string
font: TLDefaultFontStyle font: TLDefaultFontStyle

View file

@ -2,6 +2,7 @@ import {
TLShapeId, TLShapeId,
TLUnknownShape, TLUnknownShape,
getPointerInfo, getPointerInfo,
noop,
stopEventPropagation, stopEventPropagation,
useEditor, useEditor,
useValue, useValue,
@ -133,7 +134,3 @@ export function useEditableText(id: TLShapeId, type: string, text: string) {
isEditingAnything, isEditingAnything,
} }
} }
function noop() {
return
}

View file

@ -1,4 +1,4 @@
import { StateNode } from '@tldraw/editor' import { StateNode, TLStateNodeConstructor } from '@tldraw/editor'
import { Idle } from './toolStates/Idle' import { Idle } from './toolStates/Idle'
import { Pointing } from './toolStates/Pointing' import { Pointing } from './toolStates/Pointing'
@ -6,6 +6,6 @@ import { Pointing } from './toolStates/Pointing'
export class TextShapeTool extends StateNode { export class TextShapeTool extends StateNode {
static override id = 'text' static override id = 'text'
static override initial = 'idle' static override initial = 'idle'
static override children = () => [Idle, Pointing] static override children = (): TLStateNodeConstructor[] => [Idle, Pointing]
override shapeType = 'text' override shapeType = 'text'
} }

View file

@ -1,3 +1,4 @@
/** @public */
export type StyleValuesForUi<T> = readonly { export type StyleValuesForUi<T> = readonly {
readonly value: T readonly value: T
readonly icon: string readonly icon: string

View file

@ -1,4 +1,4 @@
import { StateNode } from '@tldraw/editor' import { StateNode, TLStateNodeConstructor } from '@tldraw/editor'
import { Erasing } from './childStates/Erasing' import { Erasing } from './childStates/Erasing'
import { Idle } from './childStates/Idle' import { Idle } from './childStates/Idle'
import { Pointing } from './childStates/Pointing' import { Pointing } from './childStates/Pointing'
@ -7,7 +7,7 @@ import { Pointing } from './childStates/Pointing'
export class EraserTool extends StateNode { export class EraserTool extends StateNode {
static override id = 'eraser' static override id = 'eraser'
static override initial = 'idle' static override initial = 'idle'
static override children = () => [Idle, Pointing, Erasing] static override children = (): TLStateNodeConstructor[] => [Idle, Pointing, Erasing]
override onEnter = () => { override onEnter = () => {
this.editor.setCursor({ type: 'cross', rotation: 0 }) this.editor.setCursor({ type: 'cross', rotation: 0 })

View file

@ -1,4 +1,4 @@
import { EASINGS, StateNode, TLClickEvent } from '@tldraw/editor' import { EASINGS, StateNode, TLClickEvent, TLStateNodeConstructor } from '@tldraw/editor'
import { Dragging } from './childStates/Dragging' import { Dragging } from './childStates/Dragging'
import { Idle } from './childStates/Idle' import { Idle } from './childStates/Idle'
import { Pointing } from './childStates/Pointing' import { Pointing } from './childStates/Pointing'
@ -7,7 +7,7 @@ import { Pointing } from './childStates/Pointing'
export class HandTool extends StateNode { export class HandTool extends StateNode {
static override id = 'hand' static override id = 'hand'
static override initial = 'idle' static override initial = 'idle'
static override children = () => [Idle, Pointing, Dragging] static override children = (): TLStateNodeConstructor[] => [Idle, Pointing, Dragging]
override onDoubleClick: TLClickEvent = (info) => { override onDoubleClick: TLClickEvent = (info) => {
if (info.phase === 'settle') { if (info.phase === 'settle') {

View file

@ -1,4 +1,4 @@
import { StateNode } from '@tldraw/editor' import { StateNode, TLStateNodeConstructor } from '@tldraw/editor'
import { Idle } from './childStates/Idle' import { Idle } from './childStates/Idle'
import { Lasering } from './childStates/Lasering' import { Lasering } from './childStates/Lasering'
@ -6,7 +6,7 @@ import { Lasering } from './childStates/Lasering'
export class LaserTool extends StateNode { export class LaserTool extends StateNode {
static override id = 'laser' static override id = 'laser'
static override initial = 'idle' static override initial = 'idle'
static override children = () => [Idle, Lasering] static override children = (): TLStateNodeConstructor[] => [Idle, Lasering]
override onEnter = () => { override onEnter = () => {
this.editor.setCursor({ type: 'cross', rotation: 0 }) this.editor.setCursor({ type: 'cross', rotation: 0 })

View file

@ -1,4 +1,4 @@
import { StateNode, react } from '@tldraw/editor' import { StateNode, TLStateNodeConstructor, react } from '@tldraw/editor'
import { Brushing } from './childStates/Brushing' import { Brushing } from './childStates/Brushing'
import { Crop } from './childStates/Crop/Crop' import { Crop } from './childStates/Crop/Crop'
import { Cropping } from './childStates/Cropping' import { Cropping } from './childStates/Cropping'
@ -24,7 +24,7 @@ export class SelectTool extends StateNode {
static override initial = 'idle' static override initial = 'idle'
reactor: undefined | (() => void) = undefined reactor: undefined | (() => void) = undefined
static override children = () => [ static override children = (): TLStateNodeConstructor[] => [
Crop, Crop,
Cropping, Cropping,
Idle, Idle,

View file

@ -1,4 +1,10 @@
import { StateNode, TLInterruptEvent, TLKeyboardEvent, TLPointerEventInfo } from '@tldraw/editor' import {
StateNode,
TLInterruptEvent,
TLKeyboardEvent,
TLPointerEventInfo,
TLStateNodeConstructor,
} from '@tldraw/editor'
import { Idle } from './childStates/Idle' import { Idle } from './childStates/Idle'
import { Pointing } from './childStates/Pointing' import { Pointing } from './childStates/Pointing'
import { ZoomBrushing } from './childStates/ZoomBrushing' import { ZoomBrushing } from './childStates/ZoomBrushing'
@ -7,7 +13,7 @@ import { ZoomBrushing } from './childStates/ZoomBrushing'
export class ZoomTool extends StateNode { export class ZoomTool extends StateNode {
static override id = 'zoom' static override id = 'zoom'
static override initial = 'idle' static override initial = 'idle'
static override children = () => [Idle, ZoomBrushing, Pointing] static override children = (): TLStateNodeConstructor[] => [Idle, ZoomBrushing, Pointing]
info = {} as TLPointerEventInfo & { onInteractionEnd?: string } info = {} as TLPointerEventInfo & { onInteractionEnd?: string }

View file

@ -3,6 +3,7 @@ import { version } from '../ui/version'
import { TLEditorAssetUrls, defaultEditorAssetUrls } from '../utils/static-assets/assetUrls' import { TLEditorAssetUrls, defaultEditorAssetUrls } from '../utils/static-assets/assetUrls'
import { TLUiIconType, iconTypes } from './icon-types' import { TLUiIconType, iconTypes } from './icon-types'
/** @public */
export type TLUiAssetUrls = TLEditorAssetUrls & { export type TLUiAssetUrls = TLEditorAssetUrls & {
icons: Record<TLUiIconType | Exclude<string, TLUiIconType>, string> icons: Record<TLUiIconType | Exclude<string, TLUiIconType>, string>
translations: Record<(typeof LANGUAGES)[number]['locale'], string> translations: Record<(typeof LANGUAGES)[number]['locale'], string>

View file

@ -7,7 +7,7 @@ import {
useEditor, useEditor,
} from '@tldraw/editor' } from '@tldraw/editor'
import classNames from 'classnames' import classNames from 'classnames'
import { memo, useMemo, useRef } from 'react' import { ReactElement, memo, useMemo, useRef } from 'react'
import { StyleValuesForUi } from '../../../styles' import { StyleValuesForUi } from '../../../styles'
import { TLUiTranslationKey } from '../../hooks/useTranslation/TLUiTranslationKey' import { TLUiTranslationKey } from '../../hooks/useTranslation/TLUiTranslationKey'
import { useTranslation } from '../../hooks/useTranslation/useTranslation' import { useTranslation } from '../../hooks/useTranslation/useTranslation'
@ -25,7 +25,10 @@ export interface TLUiButtonPickerProps<T extends string> {
onValueChange: (style: StyleProp<T>, value: T) => void onValueChange: (style: StyleProp<T>, value: T) => void
} }
function _TldrawUiButtonPicker<T extends string>(props: TLUiButtonPickerProps<T>) { /** @public */
export const TldrawUiButtonPicker = memo(function TldrawUiButtonPicker<T extends string>(
props: TLUiButtonPickerProps<T>
) {
const { const {
uiType, uiType,
items, items,
@ -130,6 +133,4 @@ function _TldrawUiButtonPicker<T extends string>(props: TLUiButtonPickerProps<T>
))} ))}
</div> </div>
) )
} }) as <T extends string>(props: TLUiButtonPickerProps<T>) => ReactElement
/** @public */
export const TldrawUiButtonPicker = memo(_TldrawUiButtonPicker) as typeof _TldrawUiButtonPicker

View file

@ -32,31 +32,27 @@ import { DefaultStylePanel, TLUiStylePanelProps } from '../components/StylePanel
import { DefaultToolbar } from '../components/Toolbar/DefaultToolbar' import { DefaultToolbar } from '../components/Toolbar/DefaultToolbar'
import { DefaultZoomMenu, TLUiZoomMenuProps } from '../components/ZoomMenu/DefaultZoomMenu' import { DefaultZoomMenu, TLUiZoomMenuProps } from '../components/ZoomMenu/DefaultZoomMenu'
export interface BaseTLUiComponents {
ContextMenu: ComponentType<TLUiContextMenuProps>
ActionsMenu: ComponentType<TLUiActionsMenuProps>
HelpMenu: ComponentType<TLUiHelpMenuProps>
ZoomMenu: ComponentType<TLUiZoomMenuProps>
MainMenu: ComponentType<TLUiMainMenuProps>
Minimap: ComponentType
StylePanel: ComponentType<TLUiStylePanelProps>
PageMenu: ComponentType
NavigationPanel: ComponentType
Toolbar: ComponentType
KeyboardShortcutsDialog: ComponentType<TLUiKeyboardShortcutsDialogProps>
QuickActions: ComponentType<TLUiQuickActionsProps>
HelperButtons: ComponentType<TLUiHelperButtonsProps>
DebugPanel: ComponentType
DebugMenu: ComponentType
MenuPanel: ComponentType
TopPanel: ComponentType
SharePanel: ComponentType
}
/** @public */ /** @public */
export type TLUiComponents = Partial<{ export interface TLUiComponents {
[K in keyof BaseTLUiComponents]: BaseTLUiComponents[K] | null ContextMenu?: ComponentType<TLUiContextMenuProps> | null
}> ActionsMenu?: ComponentType<TLUiActionsMenuProps> | null
HelpMenu?: ComponentType<TLUiHelpMenuProps> | null
ZoomMenu?: ComponentType<TLUiZoomMenuProps> | null
MainMenu?: ComponentType<TLUiMainMenuProps> | null
Minimap?: ComponentType | null
StylePanel?: ComponentType<TLUiStylePanelProps> | null
PageMenu?: ComponentType | null
NavigationPanel?: ComponentType | null
Toolbar?: ComponentType | null
KeyboardShortcutsDialog?: ComponentType<TLUiKeyboardShortcutsDialogProps> | null
QuickActions?: ComponentType<TLUiQuickActionsProps> | null
HelperButtons?: ComponentType<TLUiHelperButtonsProps> | null
DebugPanel?: ComponentType | null
DebugMenu?: ComponentType | null
MenuPanel?: ComponentType | null
TopPanel?: ComponentType | null
SharePanel?: ComponentType | null
}
const TldrawUiComponentsContext = createContext<TLUiComponents | null>(null) const TldrawUiComponentsContext = createContext<TLUiComponents | null>(null)

View file

@ -98,14 +98,15 @@ export interface TLUiEventMap {
'unlock-all': null 'unlock-all': null
} }
type Join<T, K> = K extends null /** @public */
? { [R in keyof T]: T[R] } export type TLUiEventData<K> = K extends null
: { [R in keyof T]: T[R] } & { [R in keyof K]: K[R] } ? { source: TLUiEventSource }
: { source: TLUiEventSource } & K
/** @public */ /** @public */
export type TLUiEventHandler<T extends keyof TLUiEventMap = keyof TLUiEventMap> = ( export type TLUiEventHandler<T extends keyof TLUiEventMap = keyof TLUiEventMap> = (
name: T, name: T,
data: Join<{ source: TLUiEventSource }, TLUiEventMap[T]> data: TLUiEventData<TLUiEventMap[T]>
) => void ) => void
/** @internal */ /** @internal */

View file

@ -1,11 +1,11 @@
import { Editor, objectMapEntries } from '@tldraw/editor' import { Editor, objectMapEntries } from '@tldraw/editor'
import { useMemo } from 'react' import { useMemo } from 'react'
import { PORTRAIT_BREAKPOINT } from './constants' import { PORTRAIT_BREAKPOINT } from './constants'
import { ActionsProviderProps } from './context/actions' import { ActionsProviderProps, TLUiActionsContextType } from './context/actions'
import { useBreakpoint } from './context/breakpoints' import { useBreakpoint } from './context/breakpoints'
import { useDialogs } from './context/dialogs' import { useDialogs } from './context/dialogs'
import { useToasts } from './context/toasts' import { useToasts } from './context/toasts'
import { TLUiToolsProviderProps } from './hooks/useTools' import { TLUiToolsContextType, TLUiToolsProviderProps } from './hooks/useTools'
import { TLUiTranslationProviderProps, useTranslation } from './hooks/useTranslation/useTranslation' import { TLUiTranslationProviderProps, useTranslation } from './hooks/useTranslation/useTranslation'
/** @public */ /** @public */
@ -41,19 +41,21 @@ export function useDefaultHelpers() {
) )
} }
type DefaultHelpers = ReturnType<typeof useDefaultHelpers> /** @public */
export type TLUiOverrideHelpers = ReturnType<typeof useDefaultHelpers>
export type TLUiOverride<Type, Helpers> = (editor: Editor, schema: Type, helpers: Helpers) => Type
type WithDefaultHelpers<T extends TLUiOverride<any, any>> =
T extends TLUiOverride<infer Type, infer Helpers>
? TLUiOverride<Type, Helpers extends undefined ? DefaultHelpers : Helpers & DefaultHelpers>
: never
/** @public */ /** @public */
export type TLUiOverrides = Partial<{ export type TLUiOverrides = Partial<{
actions: WithDefaultHelpers<NonNullable<ActionsProviderProps['overrides']>> actions: (
tools: WithDefaultHelpers<NonNullable<TLUiToolsProviderProps['overrides']>> editor: Editor,
actions: TLUiActionsContextType,
helpers: TLUiOverrideHelpers
) => TLUiActionsContextType
tools: (
editor: Editor,
tools: TLUiToolsContextType,
helpers: { insertMedia: () => void } & TLUiOverrideHelpers
) => TLUiToolsContextType
translations: TLUiTranslationProviderProps['overrides'] translations: TLUiTranslationProviderProps['overrides']
}> }>
@ -65,7 +67,7 @@ export type TLUiOverridesWithoutDefaults = Partial<{
export function mergeOverrides( export function mergeOverrides(
overrides: TLUiOverrides[], overrides: TLUiOverrides[],
defaultHelpers: DefaultHelpers defaultHelpers: TLUiOverrideHelpers
): TLUiOverridesWithoutDefaults { ): TLUiOverridesWithoutDefaults {
const mergedTranslations: TLUiTranslationProviderProps['overrides'] = {} const mergedTranslations: TLUiTranslationProviderProps['overrides'] = {}
for (const override of overrides) { for (const override of overrides) {

View file

@ -1,7 +1,8 @@
import { MediaHelpers, assertExists } from '@tldraw/editor' import { MediaHelpers, assertExists } from '@tldraw/editor'
import { clampToBrowserMaxCanvasSize } from '../../shapes/shared/getBrowserCanvasMaxSize' import { clampToBrowserMaxCanvasSize } from '../../shapes/shared/getBrowserCanvasMaxSize'
interface BoxWidthHeight { /** @public */
export interface BoxWidthHeight {
w: number w: number
h: number h: number
} }

View file

@ -31,7 +31,8 @@ import { getArrowBindings } from '../../shapes/arrow/shared'
const TLDRAW_V1_VERSION = 15.5 const TLDRAW_V1_VERSION = 15.5
/** @internal */ /** @internal */
export function buildFromV1Document(editor: Editor, document: LegacyTldrawDocument) { export function buildFromV1Document(editor: Editor, _document: unknown) {
let document = _document as TLV1Document
editor.batch(() => { editor.batch(() => {
document = migrate(document, TLDRAW_V1_VERSION) document = migrate(document, TLDRAW_V1_VERSION)
// Cancel any interactions / states // Cancel any interactions / states
@ -56,7 +57,7 @@ export function buildFromV1Document(editor: Editor, document: LegacyTldrawDocume
Object.values(document.assets ?? {}).forEach((v1Asset) => { Object.values(document.assets ?? {}).forEach((v1Asset) => {
switch (v1Asset.type) { switch (v1Asset.type) {
case TDAssetType.Image: { case TLV1AssetType.Image: {
const assetId: TLAssetId = AssetRecordType.createId() const assetId: TLAssetId = AssetRecordType.createId()
v1AssetIdsToV2AssetIds.set(v1Asset.id, assetId) v1AssetIdsToV2AssetIds.set(v1Asset.id, assetId)
const placeholderAsset: TLAsset = { const placeholderAsset: TLAsset = {
@ -77,7 +78,7 @@ export function buildFromV1Document(editor: Editor, document: LegacyTldrawDocume
tryMigrateAsset(editor, placeholderAsset) tryMigrateAsset(editor, placeholderAsset)
break break
} }
case TDAssetType.Video: case TLV1AssetType.Video:
{ {
const assetId: TLAssetId = AssetRecordType.createId() const assetId: TLAssetId = AssetRecordType.createId()
v1AssetIdsToV2AssetIds.set(v1Asset.id, assetId) v1AssetIdsToV2AssetIds.set(v1Asset.id, assetId)
@ -133,14 +134,14 @@ export function buildFromV1Document(editor: Editor, document: LegacyTldrawDocume
// Groups only // Groups only
v1Shapes.forEach((v1Shape) => { v1Shapes.forEach((v1Shape) => {
if (v1Shape.type !== TDShapeType.Group) return if (v1Shape.type !== TLV1ShapeType.Group) return
const shapeId = createShapeId() const shapeId = createShapeId()
v1ShapeIdsToV2ShapeIds.set(v1Shape.id, shapeId) v1ShapeIdsToV2ShapeIds.set(v1Shape.id, shapeId)
v1GroupShapeIdsToV1ChildIds.set(v1Shape.id, []) v1GroupShapeIdsToV1ChildIds.set(v1Shape.id, [])
}) })
function decideNotToCreateShape(v1Shape: TDShape) { function decideNotToCreateShape(v1Shape: TLV1Shape) {
v1ShapeIdsToV2ShapeIds.delete(v1Shape.id) v1ShapeIdsToV2ShapeIds.delete(v1Shape.id)
const v1GroupParent = v1GroupShapeIdsToV1ChildIds.has(v1Shape.parentId) const v1GroupParent = v1GroupShapeIdsToV1ChildIds.has(v1Shape.parentId)
if (v1GroupParent) { if (v1GroupParent) {
@ -154,7 +155,7 @@ export function buildFromV1Document(editor: Editor, document: LegacyTldrawDocume
// Non-groups only // Non-groups only
v1Shapes.forEach((v1Shape) => { v1Shapes.forEach((v1Shape) => {
// Skip groups for now, we'll create groups via the app's API // Skip groups for now, we'll create groups via the app's API
if (v1Shape.type === TDShapeType.Group) { if (v1Shape.type === TLV1ShapeType.Group) {
return return
} }
@ -183,7 +184,7 @@ export function buildFromV1Document(editor: Editor, document: LegacyTldrawDocume
} }
switch (v1Shape.type) { switch (v1Shape.type) {
case TDShapeType.Sticky: { case TLV1ShapeType.Sticky: {
editor.createShapes<TLNoteShape>([ editor.createShapes<TLNoteShape>([
{ {
...inCommon, ...inCommon,
@ -199,7 +200,7 @@ export function buildFromV1Document(editor: Editor, document: LegacyTldrawDocume
]) ])
break break
} }
case TDShapeType.Rectangle: { case TLV1ShapeType.Rectangle: {
editor.createShapes<TLGeoShape>([ editor.createShapes<TLGeoShape>([
{ {
...inCommon, ...inCommon,
@ -255,7 +256,7 @@ export function buildFromV1Document(editor: Editor, document: LegacyTldrawDocume
} }
break break
} }
case TDShapeType.Triangle: { case TLV1ShapeType.Triangle: {
editor.createShapes<TLGeoShape>([ editor.createShapes<TLGeoShape>([
{ {
...inCommon, ...inCommon,
@ -310,7 +311,7 @@ export function buildFromV1Document(editor: Editor, document: LegacyTldrawDocume
} }
break break
} }
case TDShapeType.Ellipse: { case TLV1ShapeType.Ellipse: {
editor.createShapes<TLGeoShape>([ editor.createShapes<TLGeoShape>([
{ {
...inCommon, ...inCommon,
@ -366,7 +367,7 @@ export function buildFromV1Document(editor: Editor, document: LegacyTldrawDocume
break break
} }
case TDShapeType.Draw: { case TLV1ShapeType.Draw: {
if (v1Shape.points.length === 0) { if (v1Shape.points.length === 0) {
decideNotToCreateShape(v1Shape) decideNotToCreateShape(v1Shape)
break break
@ -389,7 +390,7 @@ export function buildFromV1Document(editor: Editor, document: LegacyTldrawDocume
]) ])
break break
} }
case TDShapeType.Arrow: { case TLV1ShapeType.Arrow: {
const v1Bend = coerceNumber(v1Shape.bend) const v1Bend = coerceNumber(v1Shape.bend)
const v1Start = getV2Point(v1Shape.handles.start.point) const v1Start = getV2Point(v1Shape.handles.start.point)
const v1End = getV2Point(v1Shape.handles.end.point) const v1End = getV2Point(v1Shape.handles.end.point)
@ -425,7 +426,7 @@ export function buildFromV1Document(editor: Editor, document: LegacyTldrawDocume
break break
} }
case TDShapeType.Text: { case TLV1ShapeType.Text: {
editor.createShapes<TLTextShape>([ editor.createShapes<TLTextShape>([
{ {
...inCommon, ...inCommon,
@ -442,7 +443,7 @@ export function buildFromV1Document(editor: Editor, document: LegacyTldrawDocume
]) ])
break break
} }
case TDShapeType.Image: { case TLV1ShapeType.Image: {
const assetId = v1AssetIdsToV2AssetIds.get(v1Shape.assetId) const assetId = v1AssetIdsToV2AssetIds.get(v1Shape.assetId)
if (!assetId) { if (!assetId) {
@ -463,7 +464,7 @@ export function buildFromV1Document(editor: Editor, document: LegacyTldrawDocume
]) ])
break break
} }
case TDShapeType.Video: { case TLV1ShapeType.Video: {
const assetId = v1AssetIdsToV2AssetIds.get(v1Shape.assetId) const assetId = v1AssetIdsToV2AssetIds.get(v1Shape.assetId)
if (!assetId) { if (!assetId) {
@ -512,7 +513,7 @@ export function buildFromV1Document(editor: Editor, document: LegacyTldrawDocume
// Bind arrows to shapes // Bind arrows to shapes
v1Shapes.forEach((v1Shape) => { v1Shapes.forEach((v1Shape) => {
if (v1Shape.type !== TDShapeType.Arrow) { if (v1Shape.type !== TLV1ShapeType.Arrow) {
return return
} }
@ -651,7 +652,7 @@ async function tryMigrateAsset(editor: Editor, placeholderAsset: TLAsset) {
} }
} }
function migrate(document: LegacyTldrawDocument, newVersion: number): LegacyTldrawDocument { function migrate(document: TLV1Document, newVersion: number): TLV1Document {
const { version = 0 } = document const { version = 0 } = document
if (!document.assets) { if (!document.assets) {
@ -675,7 +676,7 @@ function migrate(document: LegacyTldrawDocument, newVersion: number): LegacyTldr
shape.parentId = page.id shape.parentId = page.id
} }
if (shape.type === TDShapeType.Group && children) { if (shape.type === TLV1ShapeType.Group && children) {
children.forEach((childId) => { children.forEach((childId) => {
if (!page.shapes[childId]) { if (!page.shapes[childId]) {
console.warn('Encountered a parent with a missing child!', shape.id, childId) console.warn('Encountered a parent with a missing child!', shape.id, childId)
@ -698,10 +699,10 @@ function migrate(document: LegacyTldrawDocument, newVersion: number): LegacyTldr
if (version < 14) { if (version < 14) {
Object.values(document.pages).forEach((page) => { Object.values(document.pages).forEach((page) => {
Object.values(page.shapes) Object.values(page.shapes)
.filter((shape) => shape.type === TDShapeType.Text) .filter((shape) => shape.type === TLV1ShapeType.Text)
.forEach((shape) => { .forEach((shape) => {
if ((shape as TextShape).style.font === undefined) { if ((shape as TLV1TextShape).style.font === undefined) {
;(shape as TextShape).style.font === FontStyle.Script ;(shape as TLV1TextShape).style.font === TLV1FontStyle.Script
} }
}) })
}) })
@ -722,13 +723,13 @@ function migrate(document: LegacyTldrawDocument, newVersion: number): LegacyTldr
} }
}) })
if (shape.type === TDShapeType.Arrow) { if (shape.type === TLV1ShapeType.Arrow) {
if (shape.decorations) { if (shape.decorations) {
Object.entries(shape.decorations).forEach(([id, decoration]) => { Object.entries(shape.decorations).forEach(([id, decoration]) => {
if ((decoration as unknown) === 'Arrow') { if ((decoration as unknown) === 'Arrow') {
shape.decorations = { shape.decorations = {
...shape.decorations, ...shape.decorations,
[id]: Decoration.Arrow, [id]: TLV1Decoration.Arrow,
} }
} }
}) })
@ -751,7 +752,7 @@ function migrate(document: LegacyTldrawDocument, newVersion: number): LegacyTldr
Object.values(page.shapes).forEach((shape) => { Object.values(page.shapes).forEach((shape) => {
if (version < 15.2) { if (version < 15.2) {
if ( if (
(shape.type === TDShapeType.Image || shape.type === TDShapeType.Video) && (shape.type === TLV1ShapeType.Image || shape.type === TLV1ShapeType.Video) &&
shape.style.isFilled == null shape.style.isFilled == null
) { ) {
shape.style.isFilled = true shape.style.isFilled = true
@ -760,10 +761,10 @@ function migrate(document: LegacyTldrawDocument, newVersion: number): LegacyTldr
if (version < 15.3) { if (version < 15.3) {
if ( if (
shape.type === TDShapeType.Rectangle || shape.type === TLV1ShapeType.Rectangle ||
shape.type === TDShapeType.Triangle || shape.type === TLV1ShapeType.Triangle ||
shape.type === TDShapeType.Ellipse || shape.type === TLV1ShapeType.Ellipse ||
shape.type === TDShapeType.Arrow shape.type === TLV1ShapeType.Arrow
) { ) {
if ('text' in shape && typeof shape.text === 'string') { if ('text' in shape && typeof shape.text === 'string') {
shape.label = shape.text shape.label = shape.text
@ -798,37 +799,24 @@ function migrate(document: LegacyTldrawDocument, newVersion: number): LegacyTldr
/* -------------------- TLV1 Types -------------------- */ /* -------------------- TLV1 Types -------------------- */
interface TLV1Handle { /** @internal */
export interface TLV1Handle {
id: string id: string
index: number index: number
point: number[] point: number[]
canBind?: boolean
bindingId?: string
} }
interface TLV1Binding { /** @internal */
export interface TLV1BaseBinding {
id: string id: string
toId: string toId: string
fromId: string fromId: string
} }
interface TLV1Shape { /** @internal */
id: string export enum TLV1ShapeType {
type: string
parentId: string
childIndex: number
name: string
point: number[]
assetId?: string
rotation?: number
children?: string[]
handles?: Record<string, TLV1Handle>
isGhost?: boolean
isHidden?: boolean
isLocked?: boolean
isGenerated?: boolean
isAspectRatioLocked?: boolean
}
enum TDShapeType {
Sticky = 'sticky', Sticky = 'sticky',
Ellipse = 'ellipse', Ellipse = 'ellipse',
Rectangle = 'rectangle', Rectangle = 'rectangle',
@ -841,7 +829,8 @@ enum TDShapeType {
Video = 'video', Video = 'video',
} }
enum ColorStyle { /** @internal */
export enum TLV1ColorStyle {
White = 'white', White = 'white',
LightGray = 'lightGray', LightGray = 'lightGray',
Gray = 'gray', Gray = 'gray',
@ -856,121 +845,144 @@ enum ColorStyle {
Yellow = 'yellow', Yellow = 'yellow',
} }
enum SizeStyle { /** @internal */
export enum TLV1SizeStyle {
Small = 'small', Small = 'small',
Medium = 'medium', Medium = 'medium',
Large = 'large', Large = 'large',
} }
enum DashStyle { /** @internal */
export enum TLV1DashStyle {
Draw = 'draw', Draw = 'draw',
Solid = 'solid', Solid = 'solid',
Dashed = 'dashed', Dashed = 'dashed',
Dotted = 'dotted', Dotted = 'dotted',
} }
enum AlignStyle { /** @internal */
export enum TLV1AlignStyle {
Start = 'start', Start = 'start',
Middle = 'middle', Middle = 'middle',
End = 'end', End = 'end',
Justify = 'justify', Justify = 'justify',
} }
enum FontStyle { /** @internal */
export enum TLV1FontStyle {
Script = 'script', Script = 'script',
Sans = 'sans', Sans = 'sans',
Serif = 'serif', Serif = 'serif',
Mono = 'mono', Mono = 'mono',
} }
interface ShapeStyles { /** @internal */
color: ColorStyle export interface TLV1ShapeStyles {
size: SizeStyle color: TLV1ColorStyle
dash: DashStyle size: TLV1SizeStyle
font?: FontStyle dash: TLV1DashStyle
textAlign?: AlignStyle font?: TLV1FontStyle
textAlign?: TLV1AlignStyle
isFilled?: boolean isFilled?: boolean
scale?: number scale?: number
} }
interface TDBaseShape extends TLV1Shape { /** @internal */
style: ShapeStyles export interface TLV1BaseShape {
type: TDShapeType id: string
parentId: string
childIndex: number
name: string
point: number[]
assetId?: string
rotation?: number
children?: string[]
isGhost?: boolean
isHidden?: boolean
isLocked?: boolean
isGenerated?: boolean
isAspectRatioLocked?: boolean
style: TLV1ShapeStyles
type: TLV1ShapeType
label?: string label?: string
handles?: Record<string, TDHandle> handles?: Record<string, TLV1Handle>
} }
interface DrawShape extends TDBaseShape { /** @internal */
type: TDShapeType.Draw export interface TLV1DrawShape extends TLV1BaseShape {
type: TLV1ShapeType.Draw
points: number[][] points: number[][]
isComplete: boolean isComplete: boolean
} }
// The extended handle (used for arrows) /** @internal */
interface TDHandle extends TLV1Handle { export interface TLV1RectangleShape extends TLV1BaseShape {
canBind?: boolean type: TLV1ShapeType.Rectangle
bindingId?: string
}
interface RectangleShape extends TDBaseShape {
type: TDShapeType.Rectangle
size: number[] size: number[]
label?: string label?: string
labelPoint?: number[] labelPoint?: number[]
} }
interface EllipseShape extends TDBaseShape { /** @internal */
type: TDShapeType.Ellipse export interface TLV1EllipseShape extends TLV1BaseShape {
type: TLV1ShapeType.Ellipse
radius: number[] radius: number[]
label?: string label?: string
labelPoint?: number[] labelPoint?: number[]
} }
interface TriangleShape extends TDBaseShape { /** @internal */
type: TDShapeType.Triangle export interface TLV1TriangleShape extends TLV1BaseShape {
type: TLV1ShapeType.Triangle
size: number[] size: number[]
label?: string label?: string
labelPoint?: number[] labelPoint?: number[]
} }
enum Decoration { /** @internal */
export enum TLV1Decoration {
Arrow = 'arrow', Arrow = 'arrow',
} }
// The shape created with the arrow tool // The shape created with the arrow tool
interface ArrowShape extends TDBaseShape { /** @internal */
type: TDShapeType.Arrow export interface TLV1ArrowShape extends TLV1BaseShape {
type: TLV1ShapeType.Arrow
bend: number bend: number
handles: { handles: {
start: TDHandle start: TLV1Handle
bend: TDHandle bend: TLV1Handle
end: TDHandle end: TLV1Handle
} }
decorations?: { decorations?: {
start?: Decoration start?: TLV1Decoration
end?: Decoration end?: TLV1Decoration
middle?: Decoration middle?: TLV1Decoration
} }
label?: string label?: string
labelPoint?: number[] labelPoint?: number[]
} }
interface ArrowBinding extends TLV1Binding { /** @internal */
handleId: keyof ArrowShape['handles'] export interface TLV1ArrowBinding extends TLV1BaseBinding {
handleId: keyof TLV1ArrowShape['handles']
distance: number distance: number
point: number[] point: number[]
} }
type TDBinding = ArrowBinding /** @internal */
export type TLV1Binding = TLV1ArrowBinding
interface ImageShape extends TDBaseShape { /** @internal */
type: TDShapeType.Image export interface TLV1ImageShape extends TLV1BaseShape {
type: TLV1ShapeType.Image
size: number[] size: number[]
assetId: string assetId: string
} }
interface VideoShape extends TDBaseShape { /** @internal */
type: TDShapeType.Video export interface TLV1VideoShape extends TLV1BaseShape {
type: TLV1ShapeType.Video
size: number[] size: number[]
assetId: string assetId: string
isPlaying: boolean isPlaying: boolean
@ -978,46 +990,52 @@ interface VideoShape extends TDBaseShape {
} }
// The shape created by the text tool // The shape created by the text tool
interface TextShape extends TDBaseShape { /** @internal */
type: TDShapeType.Text export interface TLV1TextShape extends TLV1BaseShape {
type: TLV1ShapeType.Text
text: string text: string
} }
// The shape created by the sticky tool // The shape created by the sticky tool
interface StickyShape extends TDBaseShape { /** @internal */
type: TDShapeType.Sticky export interface TLV1StickyShape extends TLV1BaseShape {
type: TLV1ShapeType.Sticky
size: number[] size: number[]
text: string text: string
} }
// The shape created when multiple shapes are grouped // The shape created when multiple shapes are grouped
interface GroupShape extends TDBaseShape { /** @internal */
type: TDShapeType.Group export interface TLV1GroupShape extends TLV1BaseShape {
type: TLV1ShapeType.Group
size: number[] size: number[]
children: string[] children: string[]
} }
type TDShape = /** @internal */
| RectangleShape export type TLV1Shape =
| EllipseShape | TLV1RectangleShape
| TriangleShape | TLV1EllipseShape
| DrawShape | TLV1TriangleShape
| ArrowShape | TLV1DrawShape
| TextShape | TLV1ArrowShape
| GroupShape | TLV1TextShape
| StickyShape | TLV1GroupShape
| ImageShape | TLV1StickyShape
| VideoShape | TLV1ImageShape
| TLV1VideoShape
interface TDPage { /** @internal */
export interface TLV1Page {
id: string id: string
name?: string name?: string
childIndex?: number childIndex?: number
shapes: Record<string, TDShape> shapes: Record<string, TLV1Shape>
bindings: Record<string, TDBinding> bindings: Record<string, TLV1Binding>
} }
interface TLV1Bounds { /** @internal */
export interface TLV1Bounds {
minX: number minX: number
minY: number minY: number
maxX: number maxX: number
@ -1027,7 +1045,8 @@ interface TLV1Bounds {
rotation?: number rotation?: number
} }
interface TLV1PageState { /** @internal */
export interface TLV1PageState {
id: string id: string
selectedIds: string[] selectedIds: string[]
camera: { camera: {
@ -1041,126 +1060,129 @@ interface TLV1PageState {
bindingId?: string | null bindingId?: string | null
} }
enum TDAssetType { /** @internal */
export enum TLV1AssetType {
Image = 'image', Image = 'image',
Video = 'video', Video = 'video',
} }
interface TDImageAsset extends TLV1Asset { /** @internal */
type: TDAssetType.Image export interface TLV1ImageAsset extends TLV1BaseAsset {
type: TLV1AssetType.Image
fileName: string fileName: string
src: string src: string
size: number[] size: number[]
} }
interface TDVideoAsset extends TLV1Asset { /** @internal */
type: TDAssetType.Video export interface TLV1VideoAsset extends TLV1BaseAsset {
type: TLV1AssetType.Video
fileName: string fileName: string
src: string src: string
size: number[] size: number[]
} }
interface TLV1Asset { /** @internal */
export interface TLV1BaseAsset {
id: string id: string
type: string type: string
} }
type TDAsset = TDImageAsset | TDVideoAsset /** @internal */
export type TLV1Asset = TLV1ImageAsset | TLV1VideoAsset
type TDAssets = Record<string, TDAsset>
/** @internal */ /** @internal */
export interface LegacyTldrawDocument { export interface TLV1Document {
id: string id: string
name: string name: string
version: number version: number
pages: Record<string, TDPage> pages: Record<string, TLV1Page>
pageStates: Record<string, TLV1PageState> pageStates: Record<string, TLV1PageState>
assets: TDAssets assets: Record<string, TLV1Asset>
} }
/* ------------------ Translations ------------------ */ /* ------------------ Translations ------------------ */
const v1ColorsToV2Colors: Record<ColorStyle, TLDefaultColorStyle> = { const v1ColorsToV2Colors: Record<TLV1ColorStyle, TLDefaultColorStyle> = {
[ColorStyle.White]: 'black', [TLV1ColorStyle.White]: 'black',
[ColorStyle.Black]: 'black', [TLV1ColorStyle.Black]: 'black',
[ColorStyle.LightGray]: 'grey', [TLV1ColorStyle.LightGray]: 'grey',
[ColorStyle.Gray]: 'grey', [TLV1ColorStyle.Gray]: 'grey',
[ColorStyle.Green]: 'light-green', [TLV1ColorStyle.Green]: 'light-green',
[ColorStyle.Cyan]: 'green', [TLV1ColorStyle.Cyan]: 'green',
[ColorStyle.Blue]: 'light-blue', [TLV1ColorStyle.Blue]: 'light-blue',
[ColorStyle.Indigo]: 'blue', [TLV1ColorStyle.Indigo]: 'blue',
[ColorStyle.Orange]: 'orange', [TLV1ColorStyle.Orange]: 'orange',
[ColorStyle.Yellow]: 'yellow', [TLV1ColorStyle.Yellow]: 'yellow',
[ColorStyle.Red]: 'red', [TLV1ColorStyle.Red]: 'red',
[ColorStyle.Violet]: 'light-violet', [TLV1ColorStyle.Violet]: 'light-violet',
} }
const v1FontsToV2Fonts: Record<FontStyle, TLDefaultFontStyle> = { const v1FontsToV2Fonts: Record<TLV1FontStyle, TLDefaultFontStyle> = {
[FontStyle.Mono]: 'mono', [TLV1FontStyle.Mono]: 'mono',
[FontStyle.Sans]: 'sans', [TLV1FontStyle.Sans]: 'sans',
[FontStyle.Script]: 'draw', [TLV1FontStyle.Script]: 'draw',
[FontStyle.Serif]: 'serif', [TLV1FontStyle.Serif]: 'serif',
} }
const v1AlignsToV2Aligns: Record<AlignStyle, TLDefaultHorizontalAlignStyle> = { const v1AlignsToV2Aligns: Record<TLV1AlignStyle, TLDefaultHorizontalAlignStyle> = {
[AlignStyle.Start]: 'start', [TLV1AlignStyle.Start]: 'start',
[AlignStyle.Middle]: 'middle', [TLV1AlignStyle.Middle]: 'middle',
[AlignStyle.End]: 'end', [TLV1AlignStyle.End]: 'end',
[AlignStyle.Justify]: 'start', [TLV1AlignStyle.Justify]: 'start',
} }
const v1TextAlignsToV2TextAligns: Record<AlignStyle, TLDefaultTextAlignStyle> = { const v1TextAlignsToV2TextAligns: Record<TLV1AlignStyle, TLDefaultTextAlignStyle> = {
[AlignStyle.Start]: 'start', [TLV1AlignStyle.Start]: 'start',
[AlignStyle.Middle]: 'middle', [TLV1AlignStyle.Middle]: 'middle',
[AlignStyle.End]: 'end', [TLV1AlignStyle.End]: 'end',
[AlignStyle.Justify]: 'start', [TLV1AlignStyle.Justify]: 'start',
} }
const v1TextSizesToV2TextSizes: Record<SizeStyle, TLDefaultSizeStyle> = { const v1TextSizesToV2TextSizes: Record<TLV1SizeStyle, TLDefaultSizeStyle> = {
[SizeStyle.Small]: 's', [TLV1SizeStyle.Small]: 's',
[SizeStyle.Medium]: 'l', [TLV1SizeStyle.Medium]: 'l',
[SizeStyle.Large]: 'xl', [TLV1SizeStyle.Large]: 'xl',
} }
const v1SizesToV2Sizes: Record<SizeStyle, TLDefaultSizeStyle> = { const v1SizesToV2Sizes: Record<TLV1SizeStyle, TLDefaultSizeStyle> = {
[SizeStyle.Small]: 'm', [TLV1SizeStyle.Small]: 'm',
[SizeStyle.Medium]: 'l', [TLV1SizeStyle.Medium]: 'l',
[SizeStyle.Large]: 'xl', [TLV1SizeStyle.Large]: 'xl',
} }
const v1DashesToV2Dashes: Record<DashStyle, TLDefaultDashStyle> = { const v1DashesToV2Dashes: Record<TLV1DashStyle, TLDefaultDashStyle> = {
[DashStyle.Solid]: 'solid', [TLV1DashStyle.Solid]: 'solid',
[DashStyle.Dashed]: 'dashed', [TLV1DashStyle.Dashed]: 'dashed',
[DashStyle.Dotted]: 'dotted', [TLV1DashStyle.Dotted]: 'dotted',
[DashStyle.Draw]: 'draw', [TLV1DashStyle.Draw]: 'draw',
} }
function getV2Color(color: ColorStyle | undefined): TLDefaultColorStyle { function getV2Color(color: TLV1ColorStyle | undefined): TLDefaultColorStyle {
return color ? v1ColorsToV2Colors[color] ?? 'black' : 'black' return color ? v1ColorsToV2Colors[color] ?? 'black' : 'black'
} }
function getV2Font(font: FontStyle | undefined): TLDefaultFontStyle { function getV2Font(font: TLV1FontStyle | undefined): TLDefaultFontStyle {
return font ? v1FontsToV2Fonts[font] ?? 'draw' : 'draw' return font ? v1FontsToV2Fonts[font] ?? 'draw' : 'draw'
} }
function getV2Align(align: AlignStyle | undefined): TLDefaultHorizontalAlignStyle { function getV2Align(align: TLV1AlignStyle | undefined): TLDefaultHorizontalAlignStyle {
return align ? v1AlignsToV2Aligns[align] ?? 'middle' : 'middle' return align ? v1AlignsToV2Aligns[align] ?? 'middle' : 'middle'
} }
function getV2TextAlign(align: AlignStyle | undefined): TLDefaultTextAlignStyle { function getV2TextAlign(align: TLV1AlignStyle | undefined): TLDefaultTextAlignStyle {
return align ? v1TextAlignsToV2TextAligns[align] ?? 'middle' : 'middle' return align ? v1TextAlignsToV2TextAligns[align] ?? 'middle' : 'middle'
} }
function getV2TextSize(size: SizeStyle | undefined): TLDefaultSizeStyle { function getV2TextSize(size: TLV1SizeStyle | undefined): TLDefaultSizeStyle {
return size ? v1TextSizesToV2TextSizes[size] ?? 'm' : 'm' return size ? v1TextSizesToV2TextSizes[size] ?? 'm' : 'm'
} }
function getV2Size(size: SizeStyle | undefined): TLDefaultSizeStyle { function getV2Size(size: TLV1SizeStyle | undefined): TLDefaultSizeStyle {
return size ? v1SizesToV2Sizes[size] ?? 'l' : 'l' return size ? v1SizesToV2Sizes[size] ?? 'l' : 'l'
} }
function getV2Dash(dash: DashStyle | undefined): TLDefaultDashStyle { function getV2Dash(dash: TLV1DashStyle | undefined): TLDefaultDashStyle {
return dash ? v1DashesToV2Dashes[dash] ?? 'draw' : 'draw' return dash ? v1DashesToV2Dashes[dash] ?? 'draw' : 'draw'
} }
@ -1172,13 +1194,13 @@ function getV2Point(point: number[]): VecModel {
} }
} }
function getV2Arrowhead(decoration: Decoration | undefined): TLArrowShapeArrowheadStyle { function getV2Arrowhead(decoration: TLV1Decoration | undefined): TLArrowShapeArrowheadStyle {
return decoration === Decoration.Arrow ? 'arrow' : 'none' return decoration === TLV1Decoration.Arrow ? 'arrow' : 'none'
} }
function getV2Fill(isFilled: boolean | undefined, color: ColorStyle) { function getV2Fill(isFilled: boolean | undefined, color: TLV1ColorStyle) {
return isFilled return isFilled
? color === ColorStyle.Black || color === ColorStyle.White ? color === TLV1ColorStyle.Black || color === TLV1ColorStyle.White
? 'semi' ? 'semi'
: 'solid' : 'solid'
: 'none' : 'none'

View file

@ -19,6 +19,7 @@ import { StandaloneDependsOn } from '@tldraw/store';
import { Store } from '@tldraw/store'; import { Store } from '@tldraw/store';
import { StoreSchema } from '@tldraw/store'; import { StoreSchema } from '@tldraw/store';
import { StoreSnapshot } from '@tldraw/store'; import { StoreSnapshot } from '@tldraw/store';
import { StoreValidator } from '@tldraw/store';
import { T } from '@tldraw/validate'; import { T } from '@tldraw/validate';
import { UnknownRecord } from '@tldraw/store'; import { UnknownRecord } from '@tldraw/store';
@ -102,13 +103,25 @@ export const CameraRecordType: RecordType<TLCamera, never>;
export const canvasUiColorTypeValidator: T.Validator<"accent" | "black" | "laser" | "muted-1" | "selection-fill" | "selection-stroke" | "white">; export const canvasUiColorTypeValidator: T.Validator<"accent" | "black" | "laser" | "muted-1" | "selection-fill" | "selection-stroke" | "white">;
// @public // @public
export function createAssetValidator<Type extends string, Props extends JsonObject>(type: Type, props: T.Validator<Props>): T.ObjectValidator<{ [P in "id" | "meta" | "typeName" | (undefined extends Props ? never : "props") | (undefined extends Type ? never : "type")]: { export function createAssetValidator<Type extends string, Props extends JsonObject>(type: Type, props: T.Validator<Props>): T.ObjectValidator<{ [P in T.ExtractRequiredKeys<{
id: TLAssetId; id: TLAssetId;
meta: JsonObject; meta: JsonObject;
props: Props; props: Props;
type: Type; type: Type;
typeName: 'asset'; typeName: 'asset';
}[P]; } & { [P_1 in (undefined extends Props ? "props" : never) | (undefined extends Type ? "type" : never)]?: { }>]: {
id: TLAssetId;
meta: JsonObject;
props: Props;
type: Type;
typeName: 'asset';
}[P]; } & { [P_1 in T.ExtractOptionalKeys<{
id: TLAssetId;
meta: JsonObject;
props: Props;
type: Type;
typeName: 'asset';
}>]?: {
id: TLAssetId; id: TLAssetId;
meta: JsonObject; meta: JsonObject;
props: Props; props: Props;
@ -132,7 +145,7 @@ export function createBindingValidator<Type extends string, Props extends JsonOb
[K in keyof Props]: T.Validatable<Props[K]>; [K in keyof Props]: T.Validatable<Props[K]>;
}, meta?: { }, meta?: {
[K in keyof Meta]: T.Validatable<Meta[K]>; [K in keyof Meta]: T.Validatable<Meta[K]>;
}): T.ObjectValidator<{ [P in "fromId" | "id" | "meta" | "toId" | "typeName" | (undefined extends Props ? never : "props") | (undefined extends Type ? never : "type")]: TLBaseBinding<Type, Props>[P]; } & { [P_1 in (undefined extends Props ? "props" : never) | (undefined extends Type ? "type" : never)]?: TLBaseBinding<Type, Props>[P_1] | undefined; }>; }): T.ObjectValidator<{ [P in T.ExtractRequiredKeys<TLBaseBinding<Type, Props>>]: TLBaseBinding<Type, Props>[P]; } & { [P_1 in T.ExtractOptionalKeys<TLBaseBinding<Type, Props>>]?: TLBaseBinding<Type, Props>[P_1] | undefined; }>;
// @public // @public
export const createPresenceStateDerivation: ($user: Signal<{ export const createPresenceStateDerivation: ($user: Signal<{
@ -157,7 +170,7 @@ export function createShapeValidator<Type extends string, Props extends JsonObje
[K in keyof Props]: T.Validatable<Props[K]>; [K in keyof Props]: T.Validatable<Props[K]>;
}, meta?: { }, meta?: {
[K in keyof Meta]: T.Validatable<Meta[K]>; [K in keyof Meta]: T.Validatable<Meta[K]>;
}): T.ObjectValidator<{ [P in "id" | "index" | "isLocked" | "meta" | "opacity" | "parentId" | "rotation" | "typeName" | "x" | "y" | (undefined extends Props ? never : "props") | (undefined extends Type ? never : "type")]: TLBaseShape<Type, Props>[P]; } & { [P_1 in (undefined extends Props ? "props" : never) | (undefined extends Type ? "type" : never)]?: TLBaseShape<Type, Props>[P_1] | undefined; }>; }): T.ObjectValidator<{ [P in T.ExtractRequiredKeys<TLBaseShape<Type, Props>>]: TLBaseShape<Type, Props>[P]; } & { [P_1 in T.ExtractOptionalKeys<TLBaseShape<Type, Props>>]?: TLBaseShape<Type, Props>[P_1] | undefined; }>;
// @public // @public
export function createTLSchema({ shapes, bindings, migrations, }?: { export function createTLSchema({ shapes, bindings, migrations, }?: {
@ -166,6 +179,9 @@ export function createTLSchema({ shapes, bindings, migrations, }?: {
shapes?: Record<string, SchemaPropsInfo>; shapes?: Record<string, SchemaPropsInfo>;
}): TLSchema; }): TLSchema;
// @public (undocumented)
export const defaultColorNames: readonly ["black", "grey", "light-violet", "violet", "blue", "light-blue", "yellow", "orange", "green", "light-green", "light-red", "red", "white"];
// @public (undocumented) // @public (undocumented)
export const DefaultColorStyle: EnumStyleProp<"black" | "blue" | "green" | "grey" | "light-blue" | "light-green" | "light-red" | "light-violet" | "orange" | "red" | "violet" | "white" | "yellow">; export const DefaultColorStyle: EnumStyleProp<"black" | "blue" | "green" | "grey" | "light-blue" | "light-green" | "light-red" | "light-violet" | "orange" | "red" | "violet" | "white" | "yellow">;
@ -223,10 +239,7 @@ export const drawShapeProps: {
isClosed: T.Validator<boolean>; isClosed: T.Validator<boolean>;
isComplete: T.Validator<boolean>; isComplete: T.Validator<boolean>;
isPen: T.Validator<boolean>; isPen: T.Validator<boolean>;
segments: T.ArrayOfValidator<{ segments: T.ArrayOfValidator<TLDrawShapeSegment>;
points: VecModel[];
type: "free" | "straight";
} & {}>;
size: EnumStyleProp<"l" | "m" | "s" | "xl">; size: EnumStyleProp<"l" | "m" | "s" | "xl">;
}; };
@ -560,16 +573,19 @@ export const highlightShapeProps: {
color: EnumStyleProp<"black" | "blue" | "green" | "grey" | "light-blue" | "light-green" | "light-red" | "light-violet" | "orange" | "red" | "violet" | "white" | "yellow">; color: EnumStyleProp<"black" | "blue" | "green" | "grey" | "light-blue" | "light-green" | "light-red" | "light-violet" | "orange" | "red" | "violet" | "white" | "yellow">;
isComplete: T.Validator<boolean>; isComplete: T.Validator<boolean>;
isPen: T.Validator<boolean>; isPen: T.Validator<boolean>;
segments: T.ArrayOfValidator<{ segments: T.ArrayOfValidator<TLDrawShapeSegment>;
points: VecModel[];
type: "free" | "straight";
} & {}>;
size: EnumStyleProp<"l" | "m" | "s" | "xl">; size: EnumStyleProp<"l" | "m" | "s" | "xl">;
}; };
// @public (undocumented) // @public (undocumented)
export function idValidator<Id extends RecordId<UnknownRecord>>(prefix: Id['__type__']['typeName']): T.Validator<Id>; export function idValidator<Id extends RecordId<UnknownRecord>>(prefix: Id['__type__']['typeName']): T.Validator<Id>;
// @public (undocumented)
export const ImageShapeCrop: T.ObjectValidator<{
bottomRight: VecModel;
topLeft: VecModel;
} & {}>;
// @public (undocumented) // @public (undocumented)
export const imageShapeMigrations: TLPropsMigrations; export const imageShapeMigrations: TLPropsMigrations;
@ -796,16 +812,19 @@ export const rootShapeMigrations: MigrationSequence;
// @public (undocumented) // @public (undocumented)
export interface SchemaPropsInfo { export interface SchemaPropsInfo {
// (undocumented) // (undocumented)
meta?: Record<string, AnyValidator>; meta?: Record<string, StoreValidator<any>>;
// (undocumented) // (undocumented)
migrations?: LegacyMigrations | MigrationSequence | TLPropsMigrations; migrations?: LegacyMigrations | MigrationSequence | TLPropsMigrations;
// (undocumented) // (undocumented)
props?: Record<string, AnyValidator>; props?: Record<string, StoreValidator<any>>;
} }
// @public (undocumented) // @public (undocumented)
export const scribbleValidator: T.Validator<TLScribble>; export const scribbleValidator: T.Validator<TLScribble>;
// @public (undocumented)
export type SetValue<T extends Set<any>> = T extends Set<infer U> ? U : never;
// @public (undocumented) // @public (undocumented)
export const shapeIdValidator: T.Validator<TLShapeId>; export const shapeIdValidator: T.Validator<TLShapeId>;
@ -854,6 +873,15 @@ export const textShapeProps: {
// @public // @public
export const TL_CANVAS_UI_COLOR_TYPES: Set<"accent" | "black" | "laser" | "muted-1" | "selection-fill" | "selection-stroke" | "white">; export const TL_CANVAS_UI_COLOR_TYPES: Set<"accent" | "black" | "laser" | "muted-1" | "selection-fill" | "selection-stroke" | "white">;
// @public
export const TL_CURSOR_TYPES: Set<string>;
// @public
export const TL_HANDLE_TYPES: Set<"clone" | "create" | "vertex" | "virtual">;
// @public
export const TL_SCRIBBLE_STATES: Set<"active" | "paused" | "starting" | "stopping">;
// @public (undocumented) // @public (undocumented)
export type TLArrowBinding = TLBaseBinding<'arrow', TLArrowBindingProps>; export type TLArrowBinding = TLBaseBinding<'arrow', TLArrowBindingProps>;
@ -985,6 +1013,9 @@ export type TLBookmarkAsset = TLBaseAsset<'bookmark', {
// @public (undocumented) // @public (undocumented)
export type TLBookmarkShape = TLBaseShape<'bookmark', TLBookmarkShapeProps>; export type TLBookmarkShape = TLBaseShape<'bookmark', TLBookmarkShapeProps>;
// @public (undocumented)
export type TLBookmarkShapeProps = RecordPropsType<typeof bookmarkShapeProps>;
// @public // @public
export interface TLCamera extends BaseRecord<'camera', TLCameraId> { export interface TLCamera extends BaseRecord<'camera', TLCameraId> {
// (undocumented) // (undocumented)
@ -1026,7 +1057,7 @@ export type TLDefaultColorTheme = Expand<{
id: 'dark' | 'light'; id: 'dark' | 'light';
solid: string; solid: string;
text: string; text: string;
} & Record<(typeof colors)[number], TLDefaultColorThemeColor>>; } & Record<(typeof defaultColorNames)[number], TLDefaultColorThemeColor>>;
// @public (undocumented) // @public (undocumented)
export interface TLDefaultColorThemeColor { export interface TLDefaultColorThemeColor {
@ -1089,7 +1120,15 @@ export const TLDOCUMENT_ID: RecordId<TLDocument>;
export type TLDrawShape = TLBaseShape<'draw', TLDrawShapeProps>; export type TLDrawShape = TLBaseShape<'draw', TLDrawShapeProps>;
// @public (undocumented) // @public (undocumented)
export type TLDrawShapeSegment = T.TypeOf<typeof DrawShapeSegment>; export type TLDrawShapeProps = RecordPropsType<typeof drawShapeProps>;
// @public (undocumented)
export interface TLDrawShapeSegment {
// (undocumented)
points: VecModel[];
// (undocumented)
type: 'free' | 'straight';
}
// @public (undocumented) // @public (undocumented)
export type TLEmbedShape = TLBaseShape<'embed', TLEmbedShapeProps>; export type TLEmbedShape = TLBaseShape<'embed', TLEmbedShapeProps>;
@ -1099,15 +1138,29 @@ export type TLEmbedShapePermissions = {
[K in keyof typeof embedShapePermissionDefaults]?: boolean; [K in keyof typeof embedShapePermissionDefaults]?: boolean;
}; };
// @public (undocumented)
export type TLEmbedShapeProps = RecordPropsType<typeof embedShapeProps>;
// @public (undocumented) // @public (undocumented)
export type TLFrameShape = TLBaseShape<'frame', TLFrameShapeProps>; export type TLFrameShape = TLBaseShape<'frame', TLFrameShapeProps>;
// @public (undocumented)
export type TLFrameShapeProps = RecordPropsType<typeof frameShapeProps>;
// @public (undocumented) // @public (undocumented)
export type TLGeoShape = TLBaseShape<'geo', TLGeoShapeProps>; export type TLGeoShape = TLBaseShape<'geo', TLGeoShapeProps>;
// @public (undocumented)
export type TLGeoShapeProps = RecordPropsType<typeof geoShapeProps>;
// @public (undocumented) // @public (undocumented)
export type TLGroupShape = TLBaseShape<'group', TLGroupShapeProps>; export type TLGroupShape = TLBaseShape<'group', TLGroupShapeProps>;
// @public (undocumented)
export type TLGroupShapeProps = {
[key in never]: undefined;
};
// @public // @public
export interface TLHandle { export interface TLHandle {
// (undocumented) // (undocumented)
@ -1129,6 +1182,9 @@ export type TLHandleType = SetValue<typeof TL_HANDLE_TYPES>;
// @public (undocumented) // @public (undocumented)
export type TLHighlightShape = TLBaseShape<'highlight', TLHighlightShapeProps>; export type TLHighlightShape = TLBaseShape<'highlight', TLHighlightShapeProps>;
// @public (undocumented)
export type TLHighlightShapeProps = RecordPropsType<typeof highlightShapeProps>;
// @public // @public
export type TLImageAsset = TLBaseAsset<'image', { export type TLImageAsset = TLBaseAsset<'image', {
h: number; h: number;
@ -1240,6 +1296,9 @@ export interface TLInstancePageState extends BaseRecord<'instance_page_state', T
selectedShapeIds: TLShapeId[]; selectedShapeIds: TLShapeId[];
} }
// @public (undocumented)
export type TLInstancePageStateId = RecordId<TLInstancePageState>;
// @public (undocumented) // @public (undocumented)
export interface TLInstancePresence extends BaseRecord<'instance_presence', TLInstancePresenceID> { export interface TLInstancePresence extends BaseRecord<'instance_presence', TLInstancePresenceID> {
// (undocumented) // (undocumented)
@ -1281,15 +1340,24 @@ export interface TLInstancePresence extends BaseRecord<'instance_presence', TLIn
userName: string; userName: string;
} }
// @public (undocumented)
export type TLInstancePresenceID = RecordId<TLInstancePresence>;
// @public (undocumented) // @public (undocumented)
export type TLLanguage = (typeof LANGUAGES)[number]; export type TLLanguage = (typeof LANGUAGES)[number];
// @public (undocumented) // @public (undocumented)
export type TLLineShape = TLBaseShape<'line', TLLineShapeProps>; export type TLLineShape = TLBaseShape<'line', TLLineShapeProps>;
// @public (undocumented)
export type TLLineShapeProps = RecordPropsType<typeof lineShapeProps>;
// @public (undocumented) // @public (undocumented)
export type TLNoteShape = TLBaseShape<'note', TLNoteShapeProps>; export type TLNoteShape = TLBaseShape<'note', TLNoteShapeProps>;
// @public (undocumented)
export type TLNoteShapeProps = RecordPropsType<typeof noteShapeProps>;
// @public (undocumented) // @public (undocumented)
export type TLOpacityType = number; export type TLOpacityType = number;
@ -1309,15 +1377,29 @@ export type TLPageId = RecordId<TLPage>;
// @public (undocumented) // @public (undocumented)
export type TLParentId = TLPageId | TLShapeId; export type TLParentId = TLPageId | TLShapeId;
// @public
export interface TLPointer extends BaseRecord<'pointer', TLPointerId> {
// (undocumented)
lastActivityTimestamp: number;
// (undocumented)
meta: JsonObject;
// (undocumented)
x: number;
// (undocumented)
y: number;
}
// @public (undocumented) // @public (undocumented)
export const TLPOINTER_ID: TLPointerId; export const TLPOINTER_ID: TLPointerId;
// @public (undocumented)
export type TLPointerId = RecordId<TLPointer>;
// @public (undocumented) // @public (undocumented)
export interface TLPropsMigration { export interface TLPropsMigration {
// (undocumented) // (undocumented)
readonly dependsOn?: MigrationId[]; readonly dependsOn?: MigrationId[];
// (undocumented) readonly down?: 'none' | 'retired' | ((props: any) => any);
readonly down?: ((props: any) => any) | typeof NO_DOWN_MIGRATION | typeof RETIRED_DOWN_MIGRATION;
// (undocumented) // (undocumented)
readonly id: MigrationId; readonly id: MigrationId;
// (undocumented) // (undocumented)
@ -1415,6 +1497,9 @@ export type TLVideoAsset = TLBaseAsset<'video', {
// @public (undocumented) // @public (undocumented)
export type TLVideoShape = TLBaseShape<'video', TLVideoShapeProps>; export type TLVideoShape = TLBaseShape<'video', TLVideoShapeProps>;
// @public (undocumented)
export type TLVideoShapeProps = RecordPropsType<typeof videoShapeProps>;
// @public // @public
export interface VecModel { export interface VecModel {
// (undocumented) // (undocumented)

View file

@ -1,4 +1,4 @@
import { LegacyMigrations, MigrationSequence, StoreSchema } from '@tldraw/store' import { LegacyMigrations, MigrationSequence, StoreSchema, StoreValidator } from '@tldraw/store'
import { objectMapValues } from '@tldraw/utils' import { objectMapValues } from '@tldraw/utils'
import { TLStoreProps, createIntegrityChecker, onValidationFailure } from './TLStore' import { TLStoreProps, createIntegrityChecker, onValidationFailure } from './TLStore'
import { bookmarkAssetMigrations } from './assets/TLBookmarkAsset' import { bookmarkAssetMigrations } from './assets/TLBookmarkAsset'
@ -39,16 +39,11 @@ import { videoShapeMigrations, videoShapeProps } from './shapes/TLVideoShape'
import { storeMigrations } from './store-migrations' import { storeMigrations } from './store-migrations'
import { StyleProp } from './styles/StyleProp' import { StyleProp } from './styles/StyleProp'
interface AnyValidator {
validate: (prop: any) => any
validateUsingKnownGoodVersion?: (prevVersion: any, newVersion: any) => any
}
/** @public */ /** @public */
export interface SchemaPropsInfo { export interface SchemaPropsInfo {
migrations?: LegacyMigrations | TLPropsMigrations | MigrationSequence migrations?: LegacyMigrations | TLPropsMigrations | MigrationSequence
props?: Record<string, AnyValidator> props?: Record<string, StoreValidator<any>>
meta?: Record<string, AnyValidator> meta?: Record<string, StoreValidator<any>>
} }
/** @public */ /** @public */

View file

@ -32,10 +32,10 @@ export {
canvasUiColorTypeValidator, canvasUiColorTypeValidator,
type TLCanvasUiColor, type TLCanvasUiColor,
} from './misc/TLColor' } from './misc/TLColor'
export { type TLCursor, type TLCursorType } from './misc/TLCursor' export { TL_CURSOR_TYPES, type TLCursor, type TLCursorType } from './misc/TLCursor'
export { type TLHandle, type TLHandleType } from './misc/TLHandle' export { TL_HANDLE_TYPES, type TLHandle, type TLHandleType } from './misc/TLHandle'
export { opacityValidator, type TLOpacityType } from './misc/TLOpacity' export { opacityValidator, type TLOpacityType } from './misc/TLOpacity'
export { scribbleValidator, type TLScribble } from './misc/TLScribble' export { TL_SCRIBBLE_STATES, scribbleValidator, type TLScribble } from './misc/TLScribble'
export { export {
boxModelValidator, boxModelValidator,
vecModelValidator, vecModelValidator,
@ -81,9 +81,22 @@ export {
type TLPage, type TLPage,
type TLPageId, type TLPageId,
} from './records/TLPage' } from './records/TLPage'
export { InstancePageStateRecordType, type TLInstancePageState } from './records/TLPageState' export {
export { PointerRecordType, TLPOINTER_ID } from './records/TLPointer' InstancePageStateRecordType,
export { InstancePresenceRecordType, type TLInstancePresence } from './records/TLPresence' type TLInstancePageState,
type TLInstancePageStateId,
} from './records/TLPageState'
export {
PointerRecordType,
TLPOINTER_ID,
type TLPointer,
type TLPointerId,
} from './records/TLPointer'
export {
InstancePresenceRecordType,
type TLInstancePresence,
type TLInstancePresenceID,
} from './records/TLPresence'
export { type TLRecord } from './records/TLRecord' export { type TLRecord } from './records/TLRecord'
export { export {
createShapeId, createShapeId,
@ -125,11 +138,13 @@ export {
bookmarkShapeMigrations, bookmarkShapeMigrations,
bookmarkShapeProps, bookmarkShapeProps,
type TLBookmarkShape, type TLBookmarkShape,
type TLBookmarkShapeProps,
} from './shapes/TLBookmarkShape' } from './shapes/TLBookmarkShape'
export { export {
drawShapeMigrations, drawShapeMigrations,
drawShapeProps, drawShapeProps,
type TLDrawShape, type TLDrawShape,
type TLDrawShapeProps,
type TLDrawShapeSegment, type TLDrawShapeSegment,
} from './shapes/TLDrawShape' } from './shapes/TLDrawShape'
export { export {
@ -140,21 +155,35 @@ export {
type EmbedDefinition, type EmbedDefinition,
type TLEmbedShape, type TLEmbedShape,
type TLEmbedShapePermissions, type TLEmbedShapePermissions,
type TLEmbedShapeProps,
} from './shapes/TLEmbedShape' } from './shapes/TLEmbedShape'
export { frameShapeMigrations, frameShapeProps, type TLFrameShape } from './shapes/TLFrameShape' export {
frameShapeMigrations,
frameShapeProps,
type TLFrameShape,
type TLFrameShapeProps,
} from './shapes/TLFrameShape'
export { export {
GeoShapeGeoStyle, GeoShapeGeoStyle,
geoShapeMigrations, geoShapeMigrations,
geoShapeProps, geoShapeProps,
type TLGeoShape, type TLGeoShape,
type TLGeoShapeProps,
} from './shapes/TLGeoShape' } from './shapes/TLGeoShape'
export { groupShapeMigrations, groupShapeProps, type TLGroupShape } from './shapes/TLGroupShape' export {
groupShapeMigrations,
groupShapeProps,
type TLGroupShape,
type TLGroupShapeProps,
} from './shapes/TLGroupShape'
export { export {
highlightShapeMigrations, highlightShapeMigrations,
highlightShapeProps, highlightShapeProps,
type TLHighlightShape, type TLHighlightShape,
type TLHighlightShapeProps,
} from './shapes/TLHighlightShape' } from './shapes/TLHighlightShape'
export { export {
ImageShapeCrop,
imageShapeMigrations, imageShapeMigrations,
imageShapeProps, imageShapeProps,
type TLImageShape, type TLImageShape,
@ -166,19 +195,31 @@ export {
lineShapeMigrations, lineShapeMigrations,
lineShapeProps, lineShapeProps,
type TLLineShape, type TLLineShape,
type TLLineShapeProps,
} from './shapes/TLLineShape' } from './shapes/TLLineShape'
export { noteShapeMigrations, noteShapeProps, type TLNoteShape } from './shapes/TLNoteShape' export {
noteShapeMigrations,
noteShapeProps,
type TLNoteShape,
type TLNoteShapeProps,
} from './shapes/TLNoteShape'
export { export {
textShapeMigrations, textShapeMigrations,
textShapeProps, textShapeProps,
type TLTextShape, type TLTextShape,
type TLTextShapeProps, type TLTextShapeProps,
} from './shapes/TLTextShape' } from './shapes/TLTextShape'
export { videoShapeMigrations, videoShapeProps, type TLVideoShape } from './shapes/TLVideoShape' export {
videoShapeMigrations,
videoShapeProps,
type TLVideoShape,
type TLVideoShapeProps,
} from './shapes/TLVideoShape'
export { EnumStyleProp, StyleProp, type StylePropValue } from './styles/StyleProp' export { EnumStyleProp, StyleProp, type StylePropValue } from './styles/StyleProp'
export { export {
DefaultColorStyle, DefaultColorStyle,
DefaultColorThemePalette, DefaultColorThemePalette,
defaultColorNames,
getDefaultColorTheme, getDefaultColorTheme,
type TLDefaultColorStyle, type TLDefaultColorStyle,
type TLDefaultColorTheme, type TLDefaultColorTheme,
@ -206,3 +247,4 @@ export {
getDefaultTranslationLocale, getDefaultTranslationLocale,
type TLLanguage, type TLLanguage,
} from './translations/translations' } from './translations/translations'
export { type SetValue } from './util-types'

View file

@ -21,17 +21,6 @@ export type RecordPropsType<Config extends Record<string, T.Validatable<any>>> =
[K in keyof Config]: T.TypeOf<Config[K]> [K in keyof Config]: T.TypeOf<Config[K]>
}> }>
export const NO_DOWN_MIGRATION = 'none' as const
/**
* If a down migration was deployed more than a couple of months ago it should be safe to retire it.
* We only really need them to smooth over the transition between versions, and some folks do keep
* browser tabs open for months without refreshing, but at a certain point that kind of behavior is
* on them. Plus anyway recently chrome has started to actually kill tabs that are open for too long
* rather than just suspending them, so if other browsers follow suit maybe it's less of a concern.
*/
export const RETIRED_DOWN_MIGRATION = 'retired' as const
/** /**
* @public * @public
*/ */
@ -39,7 +28,16 @@ export interface TLPropsMigration {
readonly id: MigrationId readonly id: MigrationId
readonly dependsOn?: MigrationId[] readonly dependsOn?: MigrationId[]
readonly up: (props: any) => any readonly up: (props: any) => any
readonly down?: typeof NO_DOWN_MIGRATION | typeof RETIRED_DOWN_MIGRATION | ((props: any) => any) /**
* If a down migration was deployed more than a couple of months ago it should be safe to retire it.
* We only really need them to smooth over the transition between versions, and some folks do keep
* browser tabs open for months without refreshing, but at a certain point that kind of behavior is
* on them. Plus anyway recently chrome has started to actually kill tabs that are open for too long
* rather than just suspending them, so if other browsers follow suit maybe it's less of a concern.
*
* @public
*/
readonly down?: 'none' | 'retired' | ((props: any) => any)
} }
/** /**

View file

@ -4,12 +4,7 @@ import { TLArrowBinding } from '../bindings/TLArrowBinding'
import { VecModel, vecModelValidator } from '../misc/geometry-types' import { VecModel, vecModelValidator } from '../misc/geometry-types'
import { createBindingId } from '../records/TLBinding' import { createBindingId } from '../records/TLBinding'
import { TLShapeId, createShapePropsMigrationIds } from '../records/TLShape' import { TLShapeId, createShapePropsMigrationIds } from '../records/TLShape'
import { import { RecordPropsType, TLPropsMigration, createPropsMigration } from '../recordsWithProps'
RETIRED_DOWN_MIGRATION,
RecordPropsType,
TLPropsMigration,
createPropsMigration,
} from '../recordsWithProps'
import { StyleProp } from '../styles/StyleProp' import { StyleProp } from '../styles/StyleProp'
import { DefaultColorStyle, DefaultLabelColorStyle } from '../styles/TLColorStyle' import { DefaultColorStyle, DefaultLabelColorStyle } from '../styles/TLColorStyle'
import { DefaultDashStyle } from '../styles/TLDashStyle' import { DefaultDashStyle } from '../styles/TLDashStyle'
@ -88,7 +83,7 @@ export const arrowShapeMigrations = createMigrationSequence({
up: (props) => { up: (props) => {
props.labelColor = 'black' props.labelColor = 'black'
}, },
down: RETIRED_DOWN_MIGRATION, down: 'retired',
}), }),
propsMigration({ propsMigration({

View file

@ -1,7 +1,7 @@
import { T } from '@tldraw/validate' import { T } from '@tldraw/validate'
import { assetIdValidator } from '../assets/TLBaseAsset' import { assetIdValidator } from '../assets/TLBaseAsset'
import { createShapePropsMigrationIds, createShapePropsMigrationSequence } from '../records/TLShape' import { createShapePropsMigrationIds, createShapePropsMigrationSequence } from '../records/TLShape'
import { RETIRED_DOWN_MIGRATION, RecordPropsType } from '../recordsWithProps' import { RecordPropsType } from '../recordsWithProps'
import { TLBaseShape } from './TLBaseShape' import { TLBaseShape } from './TLBaseShape'
/** @public */ /** @public */
@ -35,7 +35,7 @@ export const bookmarkShapeMigrations = createShapePropsMigrationSequence({
props.assetId = null props.assetId = null
} }
}, },
down: RETIRED_DOWN_MIGRATION, down: 'retired',
}, },
{ {
id: Versions.MakeUrlsValid, id: Versions.MakeUrlsValid,

View file

@ -1,21 +1,24 @@
import { T } from '@tldraw/validate' import { T } from '@tldraw/validate'
import { vecModelValidator } from '../misc/geometry-types' import { VecModel, vecModelValidator } from '../misc/geometry-types'
import { createShapePropsMigrationIds, createShapePropsMigrationSequence } from '../records/TLShape' import { createShapePropsMigrationIds, createShapePropsMigrationSequence } from '../records/TLShape'
import { RETIRED_DOWN_MIGRATION, RecordPropsType } from '../recordsWithProps' import { RecordPropsType } from '../recordsWithProps'
import { DefaultColorStyle } from '../styles/TLColorStyle' import { DefaultColorStyle } from '../styles/TLColorStyle'
import { DefaultDashStyle } from '../styles/TLDashStyle' import { DefaultDashStyle } from '../styles/TLDashStyle'
import { DefaultFillStyle } from '../styles/TLFillStyle' import { DefaultFillStyle } from '../styles/TLFillStyle'
import { DefaultSizeStyle } from '../styles/TLSizeStyle' import { DefaultSizeStyle } from '../styles/TLSizeStyle'
import { TLBaseShape } from './TLBaseShape' import { TLBaseShape } from './TLBaseShape'
export const DrawShapeSegment = T.object({ /** @public */
export interface TLDrawShapeSegment {
type: 'free' | 'straight'
points: VecModel[]
}
export const DrawShapeSegment: T.Validator<TLDrawShapeSegment> = T.object<TLDrawShapeSegment>({
type: T.literalEnum('free', 'straight'), type: T.literalEnum('free', 'straight'),
points: T.arrayOf(vecModelValidator), points: T.arrayOf(vecModelValidator),
}) })
/** @public */
export type TLDrawShapeSegment = T.TypeOf<typeof DrawShapeSegment>
/** @public */ /** @public */
export const drawShapeProps = { export const drawShapeProps = {
color: DefaultColorStyle, color: DefaultColorStyle,
@ -66,7 +69,7 @@ export const drawShapeMigrations = createShapePropsMigrationSequence({
} }
props.isPen = isPen props.isPen = isPen
}, },
down: RETIRED_DOWN_MIGRATION, down: 'retired',
}, },
], ],
}) })

View file

@ -1,6 +1,6 @@
import { T } from '@tldraw/validate' import { T } from '@tldraw/validate'
import { createShapePropsMigrationIds, createShapePropsMigrationSequence } from '../records/TLShape' import { createShapePropsMigrationIds, createShapePropsMigrationSequence } from '../records/TLShape'
import { RETIRED_DOWN_MIGRATION, RecordPropsType } from '../recordsWithProps' import { RecordPropsType } from '../recordsWithProps'
import { TLBaseShape } from './TLBaseShape' import { TLBaseShape } from './TLBaseShape'
// Only allow multiplayer embeds. If we add additional routes later for example '/help' this won't match // Only allow multiplayer embeds. If we add additional routes later for example '/help' this won't match
@ -694,28 +694,28 @@ export const embedShapeMigrations = createShapePropsMigrationSequence({
props.tmpOldUrl = props.url props.tmpOldUrl = props.url
} }
}, },
down: RETIRED_DOWN_MIGRATION, down: 'retired',
}, },
{ {
id: Versions.RemoveDoesResize, id: Versions.RemoveDoesResize,
up: (props) => { up: (props) => {
delete props.doesResize delete props.doesResize
}, },
down: RETIRED_DOWN_MIGRATION, down: 'retired',
}, },
{ {
id: Versions.RemoveTmpOldUrl, id: Versions.RemoveTmpOldUrl,
up: (props) => { up: (props) => {
delete props.tmpOldUrl delete props.tmpOldUrl
}, },
down: RETIRED_DOWN_MIGRATION, down: 'retired',
}, },
{ {
id: Versions.RemovePermissionOverrides, id: Versions.RemovePermissionOverrides,
up: (props) => { up: (props) => {
delete props.overridePermissions delete props.overridePermissions
}, },
down: RETIRED_DOWN_MIGRATION, down: 'retired',
}, },
], ],
}) })

View file

@ -10,7 +10,8 @@ export const frameShapeProps = {
name: T.string, name: T.string,
} }
type TLFrameShapeProps = RecordPropsType<typeof frameShapeProps> /** @public */
export type TLFrameShapeProps = RecordPropsType<typeof frameShapeProps>
/** @public */ /** @public */
export type TLFrameShape = TLBaseShape<'frame', TLFrameShapeProps> export type TLFrameShape = TLBaseShape<'frame', TLFrameShapeProps>

View file

@ -1,6 +1,6 @@
import { T } from '@tldraw/validate' import { T } from '@tldraw/validate'
import { createShapePropsMigrationIds, createShapePropsMigrationSequence } from '../records/TLShape' import { createShapePropsMigrationIds, createShapePropsMigrationSequence } from '../records/TLShape'
import { RETIRED_DOWN_MIGRATION, RecordPropsType } from '../recordsWithProps' import { RecordPropsType } from '../recordsWithProps'
import { StyleProp } from '../styles/StyleProp' import { StyleProp } from '../styles/StyleProp'
import { DefaultColorStyle, DefaultLabelColorStyle } from '../styles/TLColorStyle' import { DefaultColorStyle, DefaultLabelColorStyle } from '../styles/TLColorStyle'
import { DefaultDashStyle } from '../styles/TLDashStyle' import { DefaultDashStyle } from '../styles/TLDashStyle'
@ -89,14 +89,14 @@ export const geoShapeMigrations = createShapePropsMigrationSequence({
up: (props) => { up: (props) => {
props.url = '' props.url = ''
}, },
down: RETIRED_DOWN_MIGRATION, down: 'retired',
}, },
{ {
id: geoShapeVersions.AddLabelColor, id: geoShapeVersions.AddLabelColor,
up: (props) => { up: (props) => {
props.labelColor = 'black' props.labelColor = 'black'
}, },
down: RETIRED_DOWN_MIGRATION, down: 'retired',
}, },
{ {
id: geoShapeVersions.RemoveJustify, id: geoShapeVersions.RemoveJustify,
@ -105,21 +105,21 @@ export const geoShapeMigrations = createShapePropsMigrationSequence({
props.align = 'start' props.align = 'start'
} }
}, },
down: RETIRED_DOWN_MIGRATION, down: 'retired',
}, },
{ {
id: geoShapeVersions.AddCheckBox, id: geoShapeVersions.AddCheckBox,
up: (_props) => { up: (_props) => {
// noop // noop
}, },
down: RETIRED_DOWN_MIGRATION, down: 'retired',
}, },
{ {
id: geoShapeVersions.AddVerticalAlign, id: geoShapeVersions.AddVerticalAlign,
up: (props) => { up: (props) => {
props.verticalAlign = 'middle' props.verticalAlign = 'middle'
}, },
down: RETIRED_DOWN_MIGRATION, down: 'retired',
}, },
{ {
id: geoShapeVersions.MigrateLegacyAlign, id: geoShapeVersions.MigrateLegacyAlign,
@ -138,14 +138,14 @@ export const geoShapeMigrations = createShapePropsMigrationSequence({
} }
props.align = newAlign props.align = newAlign
}, },
down: RETIRED_DOWN_MIGRATION, down: 'retired',
}, },
{ {
id: geoShapeVersions.AddCloud, id: geoShapeVersions.AddCloud,
up: (_props) => { up: (_props) => {
// noop // noop
}, },
down: RETIRED_DOWN_MIGRATION, down: 'retired',
}, },
{ {
id: geoShapeVersions.MakeUrlsValid, id: geoShapeVersions.MakeUrlsValid,

View file

@ -2,7 +2,7 @@ import { T } from '@tldraw/validate'
import { assetIdValidator } from '../assets/TLBaseAsset' import { assetIdValidator } from '../assets/TLBaseAsset'
import { vecModelValidator } from '../misc/geometry-types' import { vecModelValidator } from '../misc/geometry-types'
import { createShapePropsMigrationIds, createShapePropsMigrationSequence } from '../records/TLShape' import { createShapePropsMigrationIds, createShapePropsMigrationSequence } from '../records/TLShape'
import { RETIRED_DOWN_MIGRATION, RecordPropsType } from '../recordsWithProps' import { RecordPropsType } from '../recordsWithProps'
import { TLBaseShape } from './TLBaseShape' import { TLBaseShape } from './TLBaseShape'
/** @public */ /** @public */
@ -45,7 +45,7 @@ export const imageShapeMigrations = createShapePropsMigrationSequence({
up: (props) => { up: (props) => {
props.url = '' props.url = ''
}, },
down: RETIRED_DOWN_MIGRATION, down: 'retired',
}, },
{ {
id: Versions.AddCropProp, id: Versions.AddCropProp,

View file

@ -1,7 +1,7 @@
import { IndexKey, getIndices, objectMapFromEntries, sortByIndex } from '@tldraw/utils' import { IndexKey, getIndices, objectMapFromEntries, sortByIndex } from '@tldraw/utils'
import { T } from '@tldraw/validate' import { T } from '@tldraw/validate'
import { createShapePropsMigrationIds, createShapePropsMigrationSequence } from '../records/TLShape' import { createShapePropsMigrationIds, createShapePropsMigrationSequence } from '../records/TLShape'
import { RETIRED_DOWN_MIGRATION, RecordPropsType } from '../recordsWithProps' import { RecordPropsType } from '../recordsWithProps'
import { StyleProp } from '../styles/StyleProp' import { StyleProp } from '../styles/StyleProp'
import { DefaultColorStyle } from '../styles/TLColorStyle' import { DefaultColorStyle } from '../styles/TLColorStyle'
import { DefaultDashStyle } from '../styles/TLDashStyle' import { DefaultDashStyle } from '../styles/TLDashStyle'
@ -57,7 +57,7 @@ export const lineShapeMigrations = createShapePropsMigrationSequence({
;(handle as any).canSnap = true ;(handle as any).canSnap = true
} }
}, },
down: RETIRED_DOWN_MIGRATION, down: 'retired',
}, },
{ {
id: lineShapeVersions.RemoveExtraHandleProps, id: lineShapeVersions.RemoveExtraHandleProps,

View file

@ -1,6 +1,6 @@
import { T } from '@tldraw/validate' import { T } from '@tldraw/validate'
import { createShapePropsMigrationIds, createShapePropsMigrationSequence } from '../records/TLShape' import { createShapePropsMigrationIds, createShapePropsMigrationSequence } from '../records/TLShape'
import { RETIRED_DOWN_MIGRATION, RecordPropsType } from '../recordsWithProps' import { RecordPropsType } from '../recordsWithProps'
import { DefaultColorStyle } from '../styles/TLColorStyle' import { DefaultColorStyle } from '../styles/TLColorStyle'
import { DefaultFontStyle } from '../styles/TLFontStyle' import { DefaultFontStyle } from '../styles/TLFontStyle'
import { DefaultHorizontalAlignStyle } from '../styles/TLHorizontalAlignStyle' import { DefaultHorizontalAlignStyle } from '../styles/TLHorizontalAlignStyle'
@ -46,7 +46,7 @@ export const noteShapeMigrations = createShapePropsMigrationSequence({
up: (props) => { up: (props) => {
props.url = '' props.url = ''
}, },
down: RETIRED_DOWN_MIGRATION, down: 'retired',
}, },
{ {
id: Versions.RemoveJustify, id: Versions.RemoveJustify,
@ -55,7 +55,7 @@ export const noteShapeMigrations = createShapePropsMigrationSequence({
props.align = 'start' props.align = 'start'
} }
}, },
down: RETIRED_DOWN_MIGRATION, down: 'retired',
}, },
{ {
id: Versions.MigrateLegacyAlign, id: Versions.MigrateLegacyAlign,
@ -72,14 +72,14 @@ export const noteShapeMigrations = createShapePropsMigrationSequence({
return return
} }
}, },
down: RETIRED_DOWN_MIGRATION, down: 'retired',
}, },
{ {
id: Versions.AddVerticalAlign, id: Versions.AddVerticalAlign,
up: (props) => { up: (props) => {
props.verticalAlign = 'middle' props.verticalAlign = 'middle'
}, },
down: RETIRED_DOWN_MIGRATION, down: 'retired',
}, },
{ {
id: Versions.MakeUrlsValid, id: Versions.MakeUrlsValid,

View file

@ -1,6 +1,6 @@
import { T } from '@tldraw/validate' import { T } from '@tldraw/validate'
import { createShapePropsMigrationIds, createShapePropsMigrationSequence } from '../records/TLShape' import { createShapePropsMigrationIds, createShapePropsMigrationSequence } from '../records/TLShape'
import { RETIRED_DOWN_MIGRATION, RecordPropsType } from '../recordsWithProps' import { RecordPropsType } from '../recordsWithProps'
import { DefaultColorStyle } from '../styles/TLColorStyle' import { DefaultColorStyle } from '../styles/TLColorStyle'
import { DefaultFontStyle } from '../styles/TLFontStyle' import { DefaultFontStyle } from '../styles/TLFontStyle'
import { DefaultSizeStyle } from '../styles/TLSizeStyle' import { DefaultSizeStyle } from '../styles/TLSizeStyle'
@ -42,7 +42,7 @@ export const textShapeMigrations = createShapePropsMigrationSequence({
props.align = 'start' props.align = 'start'
} }
}, },
down: RETIRED_DOWN_MIGRATION, down: 'retired',
}, },
{ {
id: Versions.AddTextAlign, id: Versions.AddTextAlign,

View file

@ -1,7 +1,7 @@
import { T } from '@tldraw/validate' import { T } from '@tldraw/validate'
import { assetIdValidator } from '../assets/TLBaseAsset' import { assetIdValidator } from '../assets/TLBaseAsset'
import { createShapePropsMigrationIds, createShapePropsMigrationSequence } from '../records/TLShape' import { createShapePropsMigrationIds, createShapePropsMigrationSequence } from '../records/TLShape'
import { RETIRED_DOWN_MIGRATION, RecordPropsType } from '../recordsWithProps' import { RecordPropsType } from '../recordsWithProps'
import { TLBaseShape } from './TLBaseShape' import { TLBaseShape } from './TLBaseShape'
/** @public */ /** @public */
@ -35,7 +35,7 @@ export const videoShapeMigrations = createShapePropsMigrationSequence({
up: (props) => { up: (props) => {
props.url = '' props.url = ''
}, },
down: RETIRED_DOWN_MIGRATION, down: 'retired',
}, },
{ {
id: Versions.MakeUrlsValid, id: Versions.MakeUrlsValid,

View file

@ -2,7 +2,8 @@ import { Expand } from '@tldraw/utils'
import { T } from '@tldraw/validate' import { T } from '@tldraw/validate'
import { StyleProp } from './StyleProp' import { StyleProp } from './StyleProp'
const colors = [ /** @public */
export const defaultColorNames = [
'black', 'black',
'grey', 'grey',
'light-violet', 'light-violet',
@ -40,7 +41,7 @@ export type TLDefaultColorTheme = Expand<
text: string text: string
background: string background: string
solid: string solid: string
} & Record<(typeof colors)[number], TLDefaultColorThemeColor> } & Record<(typeof defaultColorNames)[number], TLDefaultColorThemeColor>
> >
/** @public */ /** @public */
@ -409,13 +410,13 @@ export function getDefaultColorTheme(opts: { isDarkMode: boolean }): TLDefaultCo
/** @public */ /** @public */
export const DefaultColorStyle = StyleProp.defineEnum('tldraw:color', { export const DefaultColorStyle = StyleProp.defineEnum('tldraw:color', {
defaultValue: 'black', defaultValue: 'black',
values: colors, values: defaultColorNames,
}) })
/** @public */ /** @public */
export const DefaultLabelColorStyle = StyleProp.defineEnum('tldraw:labelColor', { export const DefaultLabelColorStyle = StyleProp.defineEnum('tldraw:labelColor', {
defaultValue: 'black', defaultValue: 'black',
values: colors, values: defaultColorNames,
}) })
/** @public */ /** @public */

View file

@ -11,7 +11,7 @@ export function annotateError(error: unknown, annotations: Partial<ErrorAnnotati
export function areArraysShallowEqual<T>(arr1: readonly T[], arr2: readonly T[]): boolean; export function areArraysShallowEqual<T>(arr1: readonly T[], arr2: readonly T[]): boolean;
// @internal (undocumented) // @internal (undocumented)
export function areObjectsShallowEqual<T extends Record<string, unknown>>(obj1: T, obj2: T): boolean; export function areObjectsShallowEqual<T extends object>(obj1: T, obj2: T): boolean;
// @internal (undocumented) // @internal (undocumented)
export const assert: (value: unknown, message?: string) => asserts value; export const assert: (value: unknown, message?: string) => asserts value;
@ -52,6 +52,14 @@ export function deleteFromLocalStorage(key: string): void;
// @internal // @internal
export function deleteFromSessionStorage(key: string): void; export function deleteFromSessionStorage(key: string): void;
// @public (undocumented)
export interface ErrorAnnotations {
// (undocumented)
extras: Record<string, unknown>;
// (undocumented)
tags: Record<string, bigint | boolean | null | number | string | symbol | undefined>;
}
// @public (undocumented) // @public (undocumented)
export interface ErrorResult<E> { export interface ErrorResult<E> {
// (undocumented) // (undocumented)
@ -228,7 +236,7 @@ export function minBy<T>(arr: readonly T[], fn: (item: T) => number): T | undefi
export function modulate(value: number, rangeA: number[], rangeB: number[], clamp?: boolean): number; export function modulate(value: number, rangeA: number[], rangeB: number[], clamp?: boolean): number;
// @internal // @internal
export function noop(): void; export const noop: () => void;
// @internal // @internal
export function objectMapEntries<Key extends string, Value>(object: { export function objectMapEntries<Key extends string, Value>(object: {
@ -316,7 +324,9 @@ export type RecursivePartial<T> = {
}; };
// @internal (undocumented) // @internal (undocumented)
type Required_2<T, K extends keyof T> = Expand<Omit<T, K> & _Required<Pick<T, K>>>; type Required_2<T, K extends keyof T> = Expand<Omit<T, K> & {
[P in K]-?: T[P];
}>;
export { Required_2 as Required } export { Required_2 as Required }
// @public (undocumented) // @public (undocumented)

View file

@ -19,7 +19,7 @@ export {
type OkResult, type OkResult,
} from './lib/control' } from './lib/control'
export { debounce } from './lib/debounce' export { debounce } from './lib/debounce'
export { annotateError, getErrorAnnotations } from './lib/error' export { annotateError, getErrorAnnotations, type ErrorAnnotations } from './lib/error'
export { FileHelpers } from './lib/file' export { FileHelpers } from './lib/file'
export { noop, omitFromStackTrace, throttle } from './lib/function' export { noop, omitFromStackTrace, throttle } from './lib/function'
export { getHashForBuffer, getHashForObject, getHashForString, lns } from './lib/hash' export { getHashForBuffer, getHashForObject, getHashForString, lns } from './lib/hash'

View file

@ -1,4 +1,5 @@
interface ErrorAnnotations { /** @public */
export interface ErrorAnnotations {
tags: Record<string, number | string | boolean | bigint | symbol | null | undefined> tags: Record<string, number | string | boolean | bigint | symbol | null | undefined>
extras: Record<string, unknown> extras: Record<string, unknown>
} }

View file

@ -58,4 +58,4 @@ export function omitFromStackTrace<Args extends Array<unknown>, Return>(
* @internal * @internal
*/ */
// eslint-disable-next-line @typescript-eslint/no-empty-function // eslint-disable-next-line @typescript-eslint/no-empty-function
export function noop(): void {} export const noop: () => void = () => {}

View file

@ -105,17 +105,14 @@ export function mapObjectMapValues<Key extends string, ValueBefore, ValueAfter>(
} }
/** @internal */ /** @internal */
export function areObjectsShallowEqual<T extends Record<string, unknown>>( export function areObjectsShallowEqual<T extends object>(obj1: T, obj2: T): boolean {
obj1: T,
obj2: T
): boolean {
if (obj1 === obj2) return true if (obj1 === obj2) return true
const keys1 = new Set(Object.keys(obj1)) const keys1 = new Set(Object.keys(obj1))
const keys2 = new Set(Object.keys(obj2)) const keys2 = new Set(Object.keys(obj2))
if (keys1.size !== keys2.size) return false if (keys1.size !== keys2.size) return false
for (const key of keys1) { for (const key of keys1) {
if (!keys2.has(key)) return false if (!keys2.has(key)) return false
if (!Object.is(obj1[key], obj2[key])) return false if (!Object.is((obj1 as any)[key], (obj2 as any)[key])) return false
} }
return true return true
} }

View file

@ -6,7 +6,5 @@ export type RecursivePartial<T> = {
/** @public */ /** @public */
export type Expand<T> = T extends infer O ? { [K in keyof O]: O[K] } : never export type Expand<T> = T extends infer O ? { [K in keyof O]: O[K] } : never
type _Required<T> = { [K in keyof T]-?: T[K] }
/** @internal */ /** @internal */
export type Required<T, K extends keyof T> = Expand<Omit<T, K> & _Required<Pick<T, K>>> export type Required<T, K extends keyof T> = Expand<Omit<T, K> & { [P in K]-?: T[P] }>

View file

@ -45,6 +45,16 @@ export class DictValidator<Key extends string, Value> extends Validator<Record<K
readonly valueValidator: Validatable<Value>; readonly valueValidator: Validatable<Value>;
} }
// @public (undocumented)
export type ExtractOptionalKeys<T extends object> = {
[K in keyof T]: undefined extends T[K] ? K : never;
}[keyof T];
// @public (undocumented)
export type ExtractRequiredKeys<T extends object> = {
[K in keyof T]: undefined extends T[K] ? never : K;
}[keyof T];
// @public // @public
const indexKey: Validator<IndexKey>; const indexKey: Validator<IndexKey>;
@ -151,6 +161,7 @@ declare namespace T {
Validator, Validator,
ArrayOfValidator, ArrayOfValidator,
ObjectValidator, ObjectValidator,
UnionValidatorConfig,
UnionValidator, UnionValidator,
DictValidator, DictValidator,
unknown, unknown,
@ -166,6 +177,8 @@ declare namespace T {
bigint, bigint,
array, array,
unknownObject, unknownObject,
ExtractRequiredKeys,
ExtractOptionalKeys,
jsonValue, jsonValue,
linkUrl, linkUrl,
srcUrl, srcUrl,
@ -187,6 +200,15 @@ export class UnionValidator<Key extends string, Config extends UnionValidatorCon
validateUnknownVariants<Unknown>(unknownValueValidation: (value: object, variant: string) => Unknown): UnionValidator<Key, Config, Unknown>; validateUnknownVariants<Unknown>(unknownValueValidation: (value: object, variant: string) => Unknown): UnionValidator<Key, Config, Unknown>;
} }
// @public (undocumented)
export type UnionValidatorConfig<Key extends string, Config> = {
readonly [Variant in keyof Config]: Validatable<any> & {
validate: (input: any) => {
readonly [K in Key]: Variant;
};
};
};
// @public // @public
const unknown: Validator<unknown>; const unknown: Validator<unknown>;

View file

@ -6,5 +6,8 @@ export {
ObjectValidator, ObjectValidator,
UnionValidator, UnionValidator,
Validator, Validator,
type ExtractOptionalKeys,
type ExtractRequiredKeys,
type UnionValidatorConfig,
} from './lib/validation' } from './lib/validation'
export { T } export { T }

View file

@ -380,7 +380,8 @@ export class ObjectValidator<Shape extends object> extends Validator<Shape> {
} }
// pass this into itself e.g. Config extends UnionObjectSchemaConfig<Key, Config> // pass this into itself e.g. Config extends UnionObjectSchemaConfig<Key, Config>
type UnionValidatorConfig<Key extends string, Config> = { /** @public */
export type UnionValidatorConfig<Key extends string, Config> = {
readonly [Variant in keyof Config]: Validatable<any> & { readonly [Variant in keyof Config]: Validatable<any> & {
validate: (input: any) => { readonly [K in Key]: Variant } validate: (input: any) => { readonly [K in Key]: Variant }
} }
@ -677,11 +678,13 @@ export const unknownObject = new Validator<Record<string, unknown>>((value) => {
return value as Record<string, unknown> return value as Record<string, unknown>
}) })
type ExtractRequiredKeys<T extends object> = { /** @public */
export type ExtractRequiredKeys<T extends object> = {
[K in keyof T]: undefined extends T[K] ? never : K [K in keyof T]: undefined extends T[K] ? never : K
}[keyof T] }[keyof T]
type ExtractOptionalKeys<T extends object> = { /** @public */
export type ExtractOptionalKeys<T extends object> = {
[K in keyof T]: undefined extends T[K] ? K : never [K in keyof T]: undefined extends T[K] ? K : never
}[keyof T] }[keyof T]