tldraw/packages/tlschema/api-report.md

1264 lines
38 KiB
Markdown
Raw Normal View History

2023-04-25 11:01:25 +00:00
## API Report File for "@tldraw/tlschema"
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
```ts
import { BaseRecord } from '@tldraw/store';
import { Expand } from '@tldraw/utils';
import { JsonObject } from '@tldraw/utils';
import { Migrations } from '@tldraw/store';
import { RecordId } from '@tldraw/store';
import { RecordType } from '@tldraw/store';
import { SerializedStore } from '@tldraw/store';
import { Signal } from '@tldraw/state';
import { Store } from '@tldraw/store';
import { StoreSchema } from '@tldraw/store';
import { StoreSnapshot } from '@tldraw/store';
import { T } from '@tldraw/validate';
import { UnknownRecord } from '@tldraw/store';
2023-04-25 11:01:25 +00:00
// @public (undocumented)
export const ArrowShapeArrowheadEndStyle: EnumStyleProp<"arrow" | "bar" | "diamond" | "dot" | "inverted" | "none" | "pipe" | "square" | "triangle">;
// @public (undocumented)
export const ArrowShapeArrowheadStartStyle: EnumStyleProp<"arrow" | "bar" | "diamond" | "dot" | "inverted" | "none" | "pipe" | "square" | "triangle">;
2023-04-25 11:01:25 +00:00
// @internal (undocumented)
export const arrowShapeMigrations: Migrations;
// @public (undocumented)
export const arrowShapeProps: {
labelColor: EnumStyleProp<"black" | "blue" | "green" | "grey" | "light-blue" | "light-green" | "light-red" | "light-violet" | "orange" | "red" | "violet" | "yellow">;
color: EnumStyleProp<"black" | "blue" | "green" | "grey" | "light-blue" | "light-green" | "light-red" | "light-violet" | "orange" | "red" | "violet" | "yellow">;
fill: EnumStyleProp<"none" | "pattern" | "semi" | "solid">;
dash: EnumStyleProp<"dashed" | "dotted" | "draw" | "solid">;
size: EnumStyleProp<"l" | "m" | "s" | "xl">;
arrowheadStart: EnumStyleProp<"arrow" | "bar" | "diamond" | "dot" | "inverted" | "none" | "pipe" | "square" | "triangle">;
arrowheadEnd: EnumStyleProp<"arrow" | "bar" | "diamond" | "dot" | "inverted" | "none" | "pipe" | "square" | "triangle">;
font: EnumStyleProp<"draw" | "mono" | "sans" | "serif">;
start: T.UnionValidator<"type", {
binding: T.ObjectValidator<{
type: "binding";
boundShapeId: TLShapeId;
normalizedAnchor: VecModel;
isExact: boolean;
[improvements] arrows x enclosing shapes x precision. (#2265) This PR makes several improvements to the behavior of arrows as they relate to precision and container relationships. - an arrow's terminals are always "true" and are never snapped to { x: .5, y: .5 } as they were previously when not precise - instead, a new `isPrecise` boolean is added to the arrow terminal - when an arrow terminal renders "imprecisely" it will be placed to the center of the bound shape - when an arrow terminal renders "precisely" it will be placed at the normalized location within the bound shape ![Kapture 2023-11-29 at 23 12 12](https://github.com/tldraw/tldraw/assets/23072548/e94e1594-75fa-4c94-86f3-7d911bf25f7f) The logic now is... - if the user has indicated precision by "pausing" while drawing the arrow, it will be precise - otherwise... - if both of an arrow's terminals are bound to the same shape, both will be precise - if a terminal is bound to a shape that contains the shape that its opposite terminal is bound to, it will be precise - if a terminal is bound to a shape that contains the shape that its opposite terminal is bound to, it will be precise - or else it will be imprecise If the spatial relationships change, the precision may change as well. Fixes https://github.com/tldraw/tldraw/issues/2204 Note: a previous version of this PR was based around ancestry but that's not actually important. ### Change Type - [x] `minor` — New feature ### Test Plan 1. Draw an arrow between a frame and its descendant 2. Draw an arrow inside of a shape to another shape contained within the bounds of the big shape 3. Vis versa 4. Vis versa - [x] Unit Tests ### Release Notes - Improves the logic about when to draw "precise" arrows between the center of bound shapes.
2023-12-01 21:34:12 +00:00
isPrecise: boolean;
}>;
point: T.ObjectValidator<{
type: "point";
x: number;
y: number;
}>;
}, never>;
end: T.UnionValidator<"type", {
binding: T.ObjectValidator<{
type: "binding";
boundShapeId: TLShapeId;
normalizedAnchor: VecModel;
isExact: boolean;
[improvements] arrows x enclosing shapes x precision. (#2265) This PR makes several improvements to the behavior of arrows as they relate to precision and container relationships. - an arrow's terminals are always "true" and are never snapped to { x: .5, y: .5 } as they were previously when not precise - instead, a new `isPrecise` boolean is added to the arrow terminal - when an arrow terminal renders "imprecisely" it will be placed to the center of the bound shape - when an arrow terminal renders "precisely" it will be placed at the normalized location within the bound shape ![Kapture 2023-11-29 at 23 12 12](https://github.com/tldraw/tldraw/assets/23072548/e94e1594-75fa-4c94-86f3-7d911bf25f7f) The logic now is... - if the user has indicated precision by "pausing" while drawing the arrow, it will be precise - otherwise... - if both of an arrow's terminals are bound to the same shape, both will be precise - if a terminal is bound to a shape that contains the shape that its opposite terminal is bound to, it will be precise - if a terminal is bound to a shape that contains the shape that its opposite terminal is bound to, it will be precise - or else it will be imprecise If the spatial relationships change, the precision may change as well. Fixes https://github.com/tldraw/tldraw/issues/2204 Note: a previous version of this PR was based around ancestry but that's not actually important. ### Change Type - [x] `minor` — New feature ### Test Plan 1. Draw an arrow between a frame and its descendant 2. Draw an arrow inside of a shape to another shape contained within the bounds of the big shape 3. Vis versa 4. Vis versa - [x] Unit Tests ### Release Notes - Improves the logic about when to draw "precise" arrows between the center of bound shapes.
2023-12-01 21:34:12 +00:00
isPrecise: boolean;
}>;
point: T.ObjectValidator<{
type: "point";
x: number;
y: number;
}>;
}, never>;
bend: T.Validator<number>;
text: T.Validator<string>;
};
// @public
export const assetIdValidator: T.Validator<TLAssetId>;
2023-04-25 11:01:25 +00:00
// @internal (undocumented)
export const assetMigrations: Migrations;
2023-04-25 11:01:25 +00:00
// @public (undocumented)
export const AssetRecordType: RecordType<TLAsset, "props" | "type">;
// @internal (undocumented)
export const assetValidator: T.Validator<TLAsset>;
2023-04-25 11:01:25 +00:00
// @internal (undocumented)
export const bookmarkShapeMigrations: Migrations;
// @public (undocumented)
export const bookmarkShapeProps: {
w: T.Validator<number>;
h: T.Validator<number>;
assetId: T.Validator<TLAssetId | null>;
url: T.Validator<string>;
};
// @public
export interface BoxModel {
2023-04-25 11:01:25 +00:00
// (undocumented)
h: number;
// (undocumented)
w: number;
// (undocumented)
x: number;
// (undocumented)
y: number;
}
// @public (undocumented)
export const boxModelValidator: T.Validator<BoxModel>;
// @public (undocumented)
export const CameraRecordType: RecordType<TLCamera, never>;
// @public
export const canvasUiColorTypeValidator: T.Validator<"accent" | "black" | "laser" | "muted-1" | "selection-fill" | "selection-stroke" | "white">;
// @public
export function createAssetValidator<Type extends string, Props extends JsonObject>(type: Type, props: T.Validator<Props>): T.ObjectValidator<{
2023-04-25 11:01:25 +00:00
id: TLAssetId;
typeName: 'asset';
type: Type;
props: Props;
meta: JsonObject;
2023-04-25 11:01:25 +00:00
}>;
// @public (undocumented)
export const createPresenceStateDerivation: ($user: Signal<{
id: string;
color: string;
name: string;
}>, instanceId?: TLInstancePresence['id']) => (store: TLStore) => Signal<null | TLInstancePresence>;
2023-04-25 11:01:25 +00:00
// @public (undocumented)
export function createShapeId(id?: string): TLShapeId;
2023-04-25 11:01:25 +00:00
// @public (undocumented)
export function createShapeValidator<Type extends string, Props extends JsonObject, Meta extends JsonObject>(type: Type, props?: {
[K in keyof Props]: T.Validatable<Props[K]>;
}, meta?: {
[K in keyof Meta]: T.Validatable<Meta[K]>;
}): T.ObjectValidator<TLBaseShape<Type, Props>>;
2023-04-25 11:01:25 +00:00
// @public
export function createTLSchema({ shapes }: {
shapes: Record<string, SchemaShapeInfo>;
}): TLSchema;
// @public (undocumented)
export const DefaultColorStyle: EnumStyleProp<"black" | "blue" | "green" | "grey" | "light-blue" | "light-green" | "light-red" | "light-violet" | "orange" | "red" | "violet" | "yellow">;
// @public (undocumented)
export const DefaultColorThemePalette: {
lightMode: TLDefaultColorTheme;
darkMode: TLDefaultColorTheme;
};
// @public (undocumented)
export const DefaultDashStyle: EnumStyleProp<"dashed" | "dotted" | "draw" | "solid">;
// @public (undocumented)
export const DefaultFillStyle: EnumStyleProp<"none" | "pattern" | "semi" | "solid">;
// @public (undocumented)
export const DefaultFontFamilies: {
draw: string;
sans: string;
serif: string;
mono: string;
};
// @public (undocumented)
export const DefaultFontStyle: EnumStyleProp<"draw" | "mono" | "sans" | "serif">;
// @public (undocumented)
export const DefaultHorizontalAlignStyle: EnumStyleProp<"end-legacy" | "end" | "middle-legacy" | "middle" | "start-legacy" | "start">;
// @public (undocumented)
export const DefaultSizeStyle: EnumStyleProp<"l" | "m" | "s" | "xl">;
// @public (undocumented)
export const DefaultVerticalAlignStyle: EnumStyleProp<"end" | "middle" | "start">;
2023-04-25 11:01:25 +00:00
// @public (undocumented)
export const DocumentRecordType: RecordType<TLDocument, never>;
// @internal (undocumented)
export const drawShapeMigrations: Migrations;
// @public (undocumented)
export const drawShapeProps: {
color: EnumStyleProp<"black" | "blue" | "green" | "grey" | "light-blue" | "light-green" | "light-red" | "light-violet" | "orange" | "red" | "violet" | "yellow">;
fill: EnumStyleProp<"none" | "pattern" | "semi" | "solid">;
dash: EnumStyleProp<"dashed" | "dotted" | "draw" | "solid">;
size: EnumStyleProp<"l" | "m" | "s" | "xl">;
segments: T.ArrayOfValidator<{
type: "free" | "straight";
points: VecModel[];
}>;
isComplete: T.Validator<boolean>;
isClosed: T.Validator<boolean>;
isPen: T.Validator<boolean>;
};
2023-04-25 11:01:25 +00:00
// @public (undocumented)
export const EMBED_DEFINITIONS: readonly [{
readonly type: "tldraw";
readonly title: "tldraw";
readonly hostnames: readonly ["beta.tldraw.com", "tldraw.com"];
2023-04-25 11:01:25 +00:00
readonly minWidth: 300;
readonly minHeight: 300;
readonly width: 720;
readonly height: 500;
readonly doesResize: true;
readonly canUnmount: true;
2023-04-25 11:01:25 +00:00
readonly toEmbedUrl: (url: string) => string | undefined;
readonly fromEmbedUrl: (url: string) => string | undefined;
}, {
readonly type: "figma";
readonly title: "Figma";
readonly hostnames: readonly ["figma.com"];
readonly width: 720;
readonly height: 500;
readonly doesResize: true;
readonly canUnmount: true;
readonly toEmbedUrl: (url: string) => string | undefined;
readonly fromEmbedUrl: (url: string) => string | undefined;
}, {
readonly type: "google_maps";
readonly title: "Google Maps";
readonly hostnames: readonly ["google.*"];
readonly width: 720;
readonly height: 500;
readonly doesResize: true;
readonly canUnmount: false;
readonly toEmbedUrl: (url: string) => string | undefined;
readonly fromEmbedUrl: (url: string) => string | undefined;
}, {
readonly type: "val_town";
readonly title: "Val Town";
readonly hostnames: readonly ["val.town"];
readonly minWidth: 260;
readonly minHeight: 100;
readonly width: 720;
readonly height: 500;
readonly doesResize: true;
readonly canUnmount: false;
readonly toEmbedUrl: (url: string) => string | undefined;
readonly fromEmbedUrl: (url: string) => string | undefined;
2023-04-25 11:01:25 +00:00
}, {
readonly type: "codesandbox";
readonly title: "CodeSandbox";
readonly hostnames: readonly ["codesandbox.io"];
readonly minWidth: 300;
readonly minHeight: 300;
readonly width: 720;
readonly height: 500;
readonly doesResize: true;
readonly canUnmount: false;
2023-04-25 11:01:25 +00:00
readonly toEmbedUrl: (url: string) => string | undefined;
readonly fromEmbedUrl: (url: string) => string | undefined;
}, {
readonly type: "codepen";
readonly title: "Codepen";
readonly hostnames: readonly ["codepen.io"];
readonly minWidth: 300;
readonly minHeight: 300;
readonly width: 520;
readonly height: 400;
readonly doesResize: true;
readonly canUnmount: false;
2023-04-25 11:01:25 +00:00
readonly toEmbedUrl: (url: string) => string | undefined;
readonly fromEmbedUrl: (url: string) => string | undefined;
}, {
readonly type: "scratch";
readonly title: "Scratch";
readonly hostnames: readonly ["scratch.mit.edu"];
readonly width: 520;
readonly height: 400;
readonly doesResize: false;
readonly canUnmount: false;
2023-04-25 11:01:25 +00:00
readonly toEmbedUrl: (url: string) => string | undefined;
readonly fromEmbedUrl: (url: string) => string | undefined;
}, {
readonly type: "youtube";
readonly title: "YouTube";
readonly hostnames: readonly ["*.youtube.com", "youtube.com", "youtu.be"];
readonly width: 800;
readonly height: 450;
readonly doesResize: true;
readonly canUnmount: false;
2023-04-25 11:01:25 +00:00
readonly overridePermissions: {
readonly 'allow-presentation': true;
};
readonly isAspectRatioLocked: true;
readonly toEmbedUrl: (url: string) => string | undefined;
readonly fromEmbedUrl: (url: string) => string | undefined;
}, {
readonly type: "google_calendar";
readonly title: "Google Calendar";
readonly hostnames: readonly ["calendar.google.*"];
readonly width: 720;
readonly height: 500;
readonly minWidth: 460;
readonly minHeight: 360;
readonly doesResize: true;
readonly canUnmount: false;
2023-04-25 11:01:25 +00:00
readonly instructionLink: "https://support.google.com/calendar/answer/41207?hl=en";
readonly toEmbedUrl: (url: string) => string | undefined;
readonly fromEmbedUrl: (url: string) => string | undefined;
}, {
readonly type: "google_slides";
readonly title: "Google Slides";
readonly hostnames: readonly ["docs.google.*"];
readonly width: 720;
readonly height: 500;
readonly minWidth: 460;
readonly minHeight: 360;
readonly doesResize: true;
readonly canUnmount: false;
2023-04-25 11:01:25 +00:00
readonly toEmbedUrl: (url: string) => string | undefined;
readonly fromEmbedUrl: (url: string) => string | undefined;
}, {
readonly type: "github_gist";
readonly title: "GitHub Gist";
readonly hostnames: readonly ["gist.github.com"];
readonly width: 720;
readonly height: 500;
readonly doesResize: true;
readonly canUnmount: true;
2023-04-25 11:01:25 +00:00
readonly toEmbedUrl: (url: string) => string | undefined;
readonly fromEmbedUrl: (url: string) => string | undefined;
}, {
readonly type: "replit";
readonly title: "Replit";
readonly hostnames: readonly ["replit.com"];
readonly width: 720;
readonly height: 500;
readonly doesResize: true;
readonly canUnmount: false;
2023-04-25 11:01:25 +00:00
readonly toEmbedUrl: (url: string) => string | undefined;
readonly fromEmbedUrl: (url: string) => string | undefined;
}, {
readonly type: "felt";
readonly title: "Felt";
readonly hostnames: readonly ["felt.com"];
readonly width: 720;
readonly height: 500;
readonly doesResize: true;
readonly canUnmount: false;
2023-04-25 11:01:25 +00:00
readonly toEmbedUrl: (url: string) => string | undefined;
readonly fromEmbedUrl: (url: string) => string | undefined;
}, {
readonly type: "spotify";
readonly title: "Spotify";
readonly hostnames: readonly ["open.spotify.com"];
readonly width: 720;
readonly height: 500;
readonly minHeight: 500;
readonly overrideOutlineRadius: 12;
readonly doesResize: true;
readonly canUnmount: false;
2023-04-25 11:01:25 +00:00
readonly toEmbedUrl: (url: string) => string | undefined;
readonly fromEmbedUrl: (url: string) => string | undefined;
}, {
readonly type: "vimeo";
readonly title: "Vimeo";
readonly hostnames: readonly ["vimeo.com", "player.vimeo.com"];
readonly width: 640;
readonly height: 360;
readonly doesResize: true;
readonly canUnmount: false;
2023-04-25 11:01:25 +00:00
readonly isAspectRatioLocked: true;
readonly toEmbedUrl: (url: string) => string | undefined;
readonly fromEmbedUrl: (url: string) => string | undefined;
}, {
readonly type: "excalidraw";
readonly title: "Excalidraw";
readonly hostnames: readonly ["excalidraw.com"];
readonly width: 720;
readonly height: 500;
readonly doesResize: true;
readonly canUnmount: false;
2023-04-25 11:01:25 +00:00
readonly isAspectRatioLocked: true;
readonly toEmbedUrl: (url: string) => string | undefined;
readonly fromEmbedUrl: (url: string) => string | undefined;
}, {
readonly type: "observable";
readonly title: "Observable";
readonly hostnames: readonly ["observablehq.com"];
readonly width: 720;
readonly height: 500;
readonly doesResize: true;
readonly canUnmount: false;
2023-04-25 11:01:25 +00:00
readonly isAspectRatioLocked: false;
readonly backgroundColor: "#fff";
readonly toEmbedUrl: (url: string) => string | undefined;
readonly fromEmbedUrl: (url: string) => string | undefined;
}];
// @public (undocumented)
export type EmbedDefinition = {
readonly type: string;
readonly title: string;
readonly hostnames: readonly string[];
readonly minWidth?: number;
readonly minHeight?: number;
readonly width: number;
readonly height: number;
readonly doesResize: boolean;
readonly canUnmount: boolean;
2023-04-25 11:01:25 +00:00
readonly isAspectRatioLocked?: boolean;
readonly overridePermissions?: TLEmbedShapePermissions;
readonly instructionLink?: string;
readonly backgroundColor?: string;
readonly overrideOutlineRadius?: number;
readonly toEmbedUrl: (url: string) => string | undefined;
readonly fromEmbedUrl: (url: string) => string | undefined;
};
// @internal (undocumented)
export const embedShapeMigrations: Migrations;
// @public
export const embedShapePermissionDefaults: {
readonly 'allow-downloads-without-user-activation': false;
readonly 'allow-downloads': false;
readonly 'allow-modals': false;
readonly 'allow-orientation-lock': false;
readonly 'allow-pointer-lock': false;
readonly 'allow-popups': true;
readonly 'allow-popups-to-escape-sandbox': false;
readonly 'allow-presentation': false;
readonly 'allow-storage-access-by-user-activation': false;
readonly 'allow-top-navigation': false;
readonly 'allow-top-navigation-by-user-activation': false;
readonly 'allow-scripts': true;
readonly 'allow-same-origin': true;
readonly 'allow-forms': true;
};
2023-04-25 11:01:25 +00:00
// @public (undocumented)
export const embedShapeProps: {
w: T.Validator<number>;
h: T.Validator<number>;
url: T.Validator<string>;
};
// @public
export class EnumStyleProp<T> extends StyleProp<T> {
// @internal
constructor(id: string, defaultValue: T, values: readonly T[]);
// (undocumented)
readonly values: readonly T[];
}
2023-04-25 11:01:25 +00:00
// @internal (undocumented)
export const frameShapeMigrations: Migrations;
// @public (undocumented)
export const frameShapeProps: {
w: T.Validator<number>;
h: T.Validator<number>;
name: T.Validator<string>;
};
// @public (undocumented)
export const GeoShapeGeoStyle: EnumStyleProp<"arrow-down" | "arrow-left" | "arrow-right" | "arrow-up" | "check-box" | "cloud" | "diamond" | "ellipse" | "hexagon" | "octagon" | "oval" | "pentagon" | "rectangle" | "rhombus-2" | "rhombus" | "star" | "trapezoid" | "triangle" | "x-box">;
// @internal (undocumented)
export const geoShapeMigrations: Migrations;
// @public (undocumented)
export const geoShapeProps: {
geo: EnumStyleProp<"arrow-down" | "arrow-left" | "arrow-right" | "arrow-up" | "check-box" | "cloud" | "diamond" | "ellipse" | "hexagon" | "octagon" | "oval" | "pentagon" | "rectangle" | "rhombus-2" | "rhombus" | "star" | "trapezoid" | "triangle" | "x-box">;
labelColor: EnumStyleProp<"black" | "blue" | "green" | "grey" | "light-blue" | "light-green" | "light-red" | "light-violet" | "orange" | "red" | "violet" | "yellow">;
color: EnumStyleProp<"black" | "blue" | "green" | "grey" | "light-blue" | "light-green" | "light-red" | "light-violet" | "orange" | "red" | "violet" | "yellow">;
fill: EnumStyleProp<"none" | "pattern" | "semi" | "solid">;
dash: EnumStyleProp<"dashed" | "dotted" | "draw" | "solid">;
size: EnumStyleProp<"l" | "m" | "s" | "xl">;
font: EnumStyleProp<"draw" | "mono" | "sans" | "serif">;
align: EnumStyleProp<"end-legacy" | "end" | "middle-legacy" | "middle" | "start-legacy" | "start">;
verticalAlign: EnumStyleProp<"end" | "middle" | "start">;
url: T.Validator<string>;
w: T.Validator<number>;
h: T.Validator<number>;
growY: T.Validator<number>;
text: T.Validator<string>;
};
2023-04-25 11:01:25 +00:00
// @public (undocumented)
export function getDefaultColorTheme(opts: {
isDarkMode: boolean;
}): TLDefaultColorTheme;
// @public (undocumented)
export function getDefaultTranslationLocale(): TLLanguage['locale'];
2023-04-25 11:01:25 +00:00
// @internal (undocumented)
export function getShapePropKeysByStyle(props: Record<string, T.Validatable<any>>): Map<StyleProp<unknown>, string>;
// @internal (undocumented)
export const groupShapeMigrations: Migrations;
// @internal (undocumented)
export const groupShapeProps: ShapeProps<TLGroupShape>;
// @internal (undocumented)
export const highlightShapeMigrations: Migrations;
// @public (undocumented)
export const highlightShapeProps: {
color: EnumStyleProp<"black" | "blue" | "green" | "grey" | "light-blue" | "light-green" | "light-red" | "light-violet" | "orange" | "red" | "violet" | "yellow">;
size: EnumStyleProp<"l" | "m" | "s" | "xl">;
segments: T.ArrayOfValidator<{
type: "free" | "straight";
points: VecModel[];
}>;
isComplete: T.Validator<boolean>;
isPen: T.Validator<boolean>;
};
2023-04-25 11:01:25 +00:00
// @internal (undocumented)
export function idValidator<Id extends RecordId<UnknownRecord>>(prefix: Id['__type__']['typeName']): T.Validator<Id>;
2023-04-25 11:01:25 +00:00
// @internal (undocumented)
export const imageShapeMigrations: Migrations;
// @public (undocumented)
export const imageShapeProps: {
w: T.Validator<number>;
h: T.Validator<number>;
playing: T.Validator<boolean>;
url: T.Validator<string>;
assetId: T.Validator<TLAssetId | null>;
crop: T.Validator<{
topLeft: VecModel;
bottomRight: VecModel;
} | null>;
};
// @public (undocumented)
Independent instance state persistence (#1493) This PR - Removes UserDocumentRecordType - moving isSnapMode to user preferences - moving isGridMode and isPenMode to InstanceRecordType - deleting the other properties which are no longer needed. - Creates a separate pipeline for persisting instance state. Previously the instance state records were stored alongside the document state records, and in order to load the state for a particular instance (in our case, a particular tab) you needed to pass the 'instanceId' prop. This prop ended up totally pervading the public API and people ran into all kinds of issues with it, e.g. using the same instance id in multiple editor instances. There was also an issue whereby it was hard for us to clean up old instance state so the idb table ended up bloating over time. This PR makes it so that rather than passing an instanceId, you load the instance state yourself while creating the store. It provides tools to make that easy. - Undoes the assumption that we might have more than one instance's state in the store. - Like `document`, `instance` now has a singleton id `instance:instance`. - Page state ids and camera ids are no longer random, but rather derive from the page they belong to. This is like having a foreign primary key in SQL databases. It's something i'd love to support fully as part of the RecordType/Store api. Tests to do - [x] Test Migrations - [x] Test Store.listen filtering - [x] Make type sets in Store public and readonly - [x] Test RecordType.createId - [x] Test Instance state snapshot loading/exporting - [x] Manual test File I/O - [x] Manual test Vscode extension with multiple tabs - [x] Audit usages of store.query - [x] Audit usages of changed types: InstanceRecordType, 'instance', InstancePageStateRecordType, 'instance_page_state', 'user_document', 'camera', CameraRecordType, InstancePresenceRecordType, 'instance_presence' - [x] Test user preferences - [x] Manual test isSnapMode and isGridMode and isPenMode - [ ] Test indexedDb functions - [x] Add instanceId stuff back ### Change Type - [x] `major` — Breaking Change ### Test Plan 1. Add a step-by-step description of how to test your PR here. 2. - [ ] Unit Tests - [ ] Webdriver tests ### Release Notes - Add a brief release note for your PR here.
2023-06-05 14:11:07 +00:00
export const InstancePageStateRecordType: RecordType<TLInstancePageState, "pageId">;
// @public (undocumented)
Independent instance state persistence (#1493) This PR - Removes UserDocumentRecordType - moving isSnapMode to user preferences - moving isGridMode and isPenMode to InstanceRecordType - deleting the other properties which are no longer needed. - Creates a separate pipeline for persisting instance state. Previously the instance state records were stored alongside the document state records, and in order to load the state for a particular instance (in our case, a particular tab) you needed to pass the 'instanceId' prop. This prop ended up totally pervading the public API and people ran into all kinds of issues with it, e.g. using the same instance id in multiple editor instances. There was also an issue whereby it was hard for us to clean up old instance state so the idb table ended up bloating over time. This PR makes it so that rather than passing an instanceId, you load the instance state yourself while creating the store. It provides tools to make that easy. - Undoes the assumption that we might have more than one instance's state in the store. - Like `document`, `instance` now has a singleton id `instance:instance`. - Page state ids and camera ids are no longer random, but rather derive from the page they belong to. This is like having a foreign primary key in SQL databases. It's something i'd love to support fully as part of the RecordType/Store api. Tests to do - [x] Test Migrations - [x] Test Store.listen filtering - [x] Make type sets in Store public and readonly - [x] Test RecordType.createId - [x] Test Instance state snapshot loading/exporting - [x] Manual test File I/O - [x] Manual test Vscode extension with multiple tabs - [x] Audit usages of store.query - [x] Audit usages of changed types: InstanceRecordType, 'instance', InstancePageStateRecordType, 'instance_page_state', 'user_document', 'camera', CameraRecordType, InstancePresenceRecordType, 'instance_presence' - [x] Test user preferences - [x] Manual test isSnapMode and isGridMode and isPenMode - [ ] Test indexedDb functions - [x] Add instanceId stuff back ### Change Type - [x] `major` — Breaking Change ### Test Plan 1. Add a step-by-step description of how to test your PR here. 2. - [ ] Unit Tests - [ ] Webdriver tests ### Release Notes - Add a brief release note for your PR here.
2023-06-05 14:11:07 +00:00
export const InstancePresenceRecordType: RecordType<TLInstancePresence, "currentPageId" | "userId" | "userName">;
// @public (undocumented)
export function isPageId(id: string): id is TLPageId;
2023-04-25 11:01:25 +00:00
// @public (undocumented)
export function isShape(record?: UnknownRecord): record is TLShape;
2023-04-25 11:01:25 +00:00
// @public (undocumented)
export function isShapeId(id?: string): id is TLShapeId;
// @public (undocumented)
export const LANGUAGES: readonly [{
readonly locale: "ar";
readonly label: "عربي";
}, {
readonly locale: "ca";
readonly label: "Català";
}, {
readonly locale: "cs";
readonly label: "Čeština";
}, {
readonly locale: "da";
readonly label: "Danish";
}, {
readonly locale: "de";
readonly label: "Deutsch";
}, {
readonly locale: "en";
readonly label: "English";
}, {
readonly locale: "es";
readonly label: "Español";
}, {
readonly locale: "fa";
readonly label: "فارسی";
}, {
readonly locale: "fi";
readonly label: "Suomi";
}, {
readonly locale: "fr";
readonly label: "Français";
}, {
readonly locale: "gl";
readonly label: "Galego";
}, {
readonly locale: "he";
readonly label: "עברית";
}, {
readonly locale: "it";
readonly label: "Italiano";
}, {
readonly locale: "ja";
readonly label: "日本語";
}, {
readonly locale: "ko-kr";
readonly label: "한국어";
}, {
readonly locale: "ku";
readonly label: "کوردی";
}, {
readonly locale: "hi-in";
readonly label: "हिन्दी";
}, {
readonly locale: "hu";
readonly label: "Magyar";
}, {
readonly locale: "my";
readonly label: "မြန်မာစာ";
}, {
readonly locale: "ne";
readonly label: "नेपाली";
}, {
readonly locale: "no";
readonly label: "Norwegian";
}, {
readonly locale: "pl";
readonly label: "Polski";
}, {
readonly locale: "pt-br";
readonly label: "Português - Brasil";
}, {
readonly locale: "pt-pt";
readonly label: "Português - Europeu";
}, {
readonly locale: "ro";
readonly label: "Română";
}, {
readonly locale: "ru";
readonly label: "Russian";
}, {
readonly locale: "sv";
readonly label: "Svenska";
}, {
readonly locale: "te";
readonly label: "తెలుగు";
}, {
readonly locale: "th";
readonly label: "ภาษาไทย";
}, {
readonly locale: "tr";
readonly label: "Türkçe";
}, {
readonly locale: "uk";
readonly label: "Ukrainian";
}, {
readonly locale: "vi";
readonly label: "Tiếng Việt";
}, {
readonly locale: "zh-cn";
readonly label: "简体中文";
}, {
readonly locale: "zh-tw";
readonly label: "繁體中文 (台灣)";
}];
2023-04-25 11:01:25 +00:00
// @internal (undocumented)
export const lineShapeMigrations: Migrations;
// @public (undocumented)
export const lineShapeProps: {
color: EnumStyleProp<"black" | "blue" | "green" | "grey" | "light-blue" | "light-green" | "light-red" | "light-violet" | "orange" | "red" | "violet" | "yellow">;
dash: EnumStyleProp<"dashed" | "dotted" | "draw" | "solid">;
size: EnumStyleProp<"l" | "m" | "s" | "xl">;
spline: EnumStyleProp<"cubic" | "line">;
handles: T.DictValidator<string, TLHandle>;
};
// @public (undocumented)
export const LineShapeSplineStyle: EnumStyleProp<"cubic" | "line">;
// @internal (undocumented)
export const noteShapeMigrations: Migrations;
// @public (undocumented)
export const noteShapeProps: {
color: EnumStyleProp<"black" | "blue" | "green" | "grey" | "light-blue" | "light-green" | "light-red" | "light-violet" | "orange" | "red" | "violet" | "yellow">;
size: EnumStyleProp<"l" | "m" | "s" | "xl">;
font: EnumStyleProp<"draw" | "mono" | "sans" | "serif">;
align: EnumStyleProp<"end-legacy" | "end" | "middle-legacy" | "middle" | "start-legacy" | "start">;
verticalAlign: EnumStyleProp<"end" | "middle" | "start">;
growY: T.Validator<number>;
url: T.Validator<string>;
text: T.Validator<string>;
};
2023-04-25 11:01:25 +00:00
// @internal (undocumented)
export const opacityValidator: T.Validator<number>;
2023-04-25 11:01:25 +00:00
Independent instance state persistence (#1493) This PR - Removes UserDocumentRecordType - moving isSnapMode to user preferences - moving isGridMode and isPenMode to InstanceRecordType - deleting the other properties which are no longer needed. - Creates a separate pipeline for persisting instance state. Previously the instance state records were stored alongside the document state records, and in order to load the state for a particular instance (in our case, a particular tab) you needed to pass the 'instanceId' prop. This prop ended up totally pervading the public API and people ran into all kinds of issues with it, e.g. using the same instance id in multiple editor instances. There was also an issue whereby it was hard for us to clean up old instance state so the idb table ended up bloating over time. This PR makes it so that rather than passing an instanceId, you load the instance state yourself while creating the store. It provides tools to make that easy. - Undoes the assumption that we might have more than one instance's state in the store. - Like `document`, `instance` now has a singleton id `instance:instance`. - Page state ids and camera ids are no longer random, but rather derive from the page they belong to. This is like having a foreign primary key in SQL databases. It's something i'd love to support fully as part of the RecordType/Store api. Tests to do - [x] Test Migrations - [x] Test Store.listen filtering - [x] Make type sets in Store public and readonly - [x] Test RecordType.createId - [x] Test Instance state snapshot loading/exporting - [x] Manual test File I/O - [x] Manual test Vscode extension with multiple tabs - [x] Audit usages of store.query - [x] Audit usages of changed types: InstanceRecordType, 'instance', InstancePageStateRecordType, 'instance_page_state', 'user_document', 'camera', CameraRecordType, InstancePresenceRecordType, 'instance_presence' - [x] Test user preferences - [x] Manual test isSnapMode and isGridMode and isPenMode - [ ] Test indexedDb functions - [x] Add instanceId stuff back ### Change Type - [x] `major` — Breaking Change ### Test Plan 1. Add a step-by-step description of how to test your PR here. 2. - [ ] Unit Tests - [ ] Webdriver tests ### Release Notes - Add a brief release note for your PR here.
2023-06-05 14:11:07 +00:00
// @internal (undocumented)
export const pageIdValidator: T.Validator<TLPageId>;
// @public (undocumented)
export const PageRecordType: RecordType<TLPage, "index" | "name">;
2023-04-25 11:01:25 +00:00
// @public (undocumented)
export const parentIdValidator: T.Validator<TLParentId>;
// @public (undocumented)
export const PointerRecordType: RecordType<TLPointer, never>;
2023-04-25 11:01:25 +00:00
// @internal (undocumented)
export const rootShapeMigrations: Migrations;
[refactor] User-facing APIs (#1478) This PR updates our user-facing APIs for the Tldraw and TldrawEditor components, as well as the Editor (App). It mainly incorporates surface changes from #1450 without any changes to validators or migrators, incorporating feedback / discussion with @SomeHats and @ds300. Here we: - remove the TldrawEditorConfig - bring back a loose version of shape definitions - make a separation between "core" shapes and "default" shapes - do not allow custom shapes, migrators or validators to overwrite core shapes - but _do_ allow new shapes ## `<Tldraw>` component In this PR, the `Tldraw` component wraps both the `TldrawEditor` component and our `TldrawUi` component. It accepts a union of props for both components. Previously, this component also added local syncing via a `useLocalSyncClient` hook call, however that has been pushed down to the `TldrawEditor` component. ## `<TldrawEditor>` component The `TldrawEditor` component now more neatly wraps up the different ways that the editor can be configured. ## The store prop (`TldrawEditorProps.store`) There are three main ways for the `TldrawEditor` component to be run: 1. with an externally defined store 2. with an externally defined syncing store (local or remote) 3. with an internally defined store 4. with an internally defined locally syncing store The `store` prop allows for these configurations. If the `store` prop is defined, it may be defined either as a `TLStore` or as a `SyncedStore`. If the store is a `TLStore`, then the Editor will assume that the store is ready to go; if it is defined as a SyncedStore, then the component will display the loading / error screens as needed, or the final editor once the store's status is "synced". When the store is left undefined, then the `TldrawEditor` will create its own internal store using the optional `instanceId`, `initialData`, or `shapes` props to define the store / store schema. If the `persistenceKey` prop is left undefined, then the store will not be synced. If the `persistenceKey` is defined, then the store will be synced locally. In the future, we may also here accept the API key / roomId / etc for creating a remotely synced store. The `SyncedStore` type has been expanded to also include types used for remote syncing, e.g. with `ConnectionStatus`. ## Tools By default, the App has two "baked-in" tools: the select tool and the zoom tool. These cannot (for now) be replaced or removed. The default tools are used by default, but may be replaced by other tools if provided. ## Shapes By default, the App has a set of "core" shapes: - group - embed - bookmark - image - video - text That cannot by overwritten because they're created by the app at different moments, such as when double clicking on the canvas or via a copy and paste event. In follow up PRs, we'll split these out so that users can replace parts of the code where these shapes are created. ### Change Type - [x] `major` — Breaking Change ### Test Plan - [x] Unit Tests
2023-06-01 15:47:34 +00:00
// @public (undocumented)
export type SchemaShapeInfo = {
migrations?: Migrations;
props?: Record<string, {
validate: (prop: any) => any;
}>;
meta?: Record<string, {
validate: (prop: any) => any;
}>;
};
// @internal (undocumented)
export const scribbleValidator: T.Validator<TLScribble>;
2023-04-25 11:01:25 +00:00
// @public (undocumented)
export const shapeIdValidator: T.Validator<TLShapeId>;
// @public (undocumented)
export type ShapeProps<Shape extends TLBaseShape<any, any>> = {
[K in keyof Shape['props']]: T.Validatable<Shape['props'][K]>;
};
// @public
export class StyleProp<Type> implements T.Validatable<Type> {
// @internal
protected constructor(id: string, defaultValue: Type, type: T.Validatable<Type>);
// (undocumented)
readonly defaultValue: Type;
static define<Type>(uniqueId: string, options: {
defaultValue: Type;
type?: T.Validatable<Type>;
}): StyleProp<Type>;
static defineEnum<const Values extends readonly unknown[]>(uniqueId: string, options: {
defaultValue: Values[number];
values: Values;
}): EnumStyleProp<Values[number]>;
2023-04-25 11:01:25 +00:00
// (undocumented)
readonly id: string;
2023-04-25 11:01:25 +00:00
// (undocumented)
readonly type: T.Validatable<Type>;
2023-04-25 11:01:25 +00:00
// (undocumented)
validate(value: unknown): Type;
2023-04-25 11:01:25 +00:00
}
// @internal (undocumented)
export const textShapeMigrations: Migrations;
2023-04-25 11:01:25 +00:00
// @public (undocumented)
export const textShapeProps: {
color: EnumStyleProp<"black" | "blue" | "green" | "grey" | "light-blue" | "light-green" | "light-red" | "light-violet" | "orange" | "red" | "violet" | "yellow">;
size: EnumStyleProp<"l" | "m" | "s" | "xl">;
font: EnumStyleProp<"draw" | "mono" | "sans" | "serif">;
align: EnumStyleProp<"end-legacy" | "end" | "middle-legacy" | "middle" | "start-legacy" | "start">;
w: T.Validator<number>;
text: T.Validator<string>;
scale: T.Validator<number>;
autoSize: T.Validator<boolean>;
};
// @public
export const TL_CANVAS_UI_COLOR_TYPES: Set<"accent" | "black" | "laser" | "muted-1" | "selection-fill" | "selection-stroke" | "white">;
2023-04-25 11:01:25 +00:00
// @public (undocumented)
export type TLArrowShape = TLBaseShape<'arrow', TLArrowShapeProps>;
// @public (undocumented)
export type TLArrowShapeArrowheadStyle = T.TypeOf<typeof ArrowShapeArrowheadStartStyle>;
2023-04-25 11:01:25 +00:00
// @public (undocumented)
export type TLArrowShapeProps = ShapePropsType<typeof arrowShapeProps>;
2023-04-25 11:01:25 +00:00
// @public (undocumented)
export type TLArrowShapeTerminal = T.TypeOf<typeof ArrowShapeTerminal>;
2023-04-25 11:01:25 +00:00
// @public (undocumented)
export type TLAsset = TLBookmarkAsset | TLImageAsset | TLVideoAsset;
// @public (undocumented)
export type TLAssetId = RecordId<TLBaseAsset<any, any>>;
2023-04-25 11:01:25 +00:00
// @public (undocumented)
export type TLAssetPartial<T extends TLAsset = TLAsset> = T extends T ? {
id: TLAssetId;
type: T['type'];
props?: Partial<T['props']>;
meta?: Partial<T['meta']>;
} & Partial<Omit<T, 'id' | 'meta' | 'props' | 'type'>> : never;
2023-04-25 11:01:25 +00:00
// @public (undocumented)
export type TLAssetShape = Extract<TLShape, {
props: {
assetId: TLAssetId;
};
}>;
// @public (undocumented)
export interface TLBaseAsset<Type extends string, Props> extends BaseRecord<'asset', TLAssetId> {
// (undocumented)
meta: JsonObject;
2023-04-25 11:01:25 +00:00
// (undocumented)
props: Props;
// (undocumented)
type: Type;
}
// @public (undocumented)
export interface TLBaseShape<Type extends string, Props extends object> extends BaseRecord<'shape', TLShapeId> {
2023-04-25 11:01:25 +00:00
// (undocumented)
index: string;
// (undocumented)
isLocked: boolean;
// (undocumented)
meta: JsonObject;
// (undocumented)
opacity: TLOpacityType;
// (undocumented)
2023-04-25 11:01:25 +00:00
parentId: TLParentId;
// (undocumented)
props: Props;
// (undocumented)
rotation: number;
// (undocumented)
type: Type;
// (undocumented)
x: number;
// (undocumented)
y: number;
}
// @public
2023-04-25 11:01:25 +00:00
export type TLBookmarkAsset = TLBaseAsset<'bookmark', {
title: string;
description: string;
image: string;
src: null | string;
}>;
// @public (undocumented)
export type TLBookmarkShape = TLBaseShape<'bookmark', TLBookmarkShapeProps>;
// @public
export interface TLCamera extends BaseRecord<'camera', TLCameraId> {
// (undocumented)
meta: JsonObject;
2023-04-25 11:01:25 +00:00
// (undocumented)
x: number;
// (undocumented)
y: number;
// (undocumented)
z: number;
}
// @public
export type TLCameraId = RecordId<TLCamera>;
// @public
export type TLCanvasUiColor = SetValue<typeof TL_CANVAS_UI_COLOR_TYPES>;
2023-04-25 11:01:25 +00:00
// @public
2023-04-25 11:01:25 +00:00
export interface TLCursor {
// (undocumented)
rotation: number;
// (undocumented)
type: TLCursorType;
}
// @public
2023-04-25 11:01:25 +00:00
export type TLCursorType = SetValue<typeof TL_CURSOR_TYPES>;
// @public (undocumented)
export type TLDefaultColorStyle = T.TypeOf<typeof DefaultColorStyle>;
// @public (undocumented)
export type TLDefaultColorTheme = Expand<{
id: 'dark' | 'light';
text: string;
background: string;
solid: string;
} & Record<(typeof colors)[number], TLDefaultColorThemeColor>>;
// @public (undocumented)
export type TLDefaultColorThemeColor = {
solid: string;
semi: string;
pattern: string;
highlight: {
srgb: string;
p3: string;
};
};
// @public (undocumented)
export type TLDefaultDashStyle = T.TypeOf<typeof DefaultDashStyle>;
2023-04-25 11:01:25 +00:00
// @public (undocumented)
export type TLDefaultFillStyle = T.TypeOf<typeof DefaultFillStyle>;
// @public (undocumented)
export type TLDefaultFontStyle = T.TypeOf<typeof DefaultFontStyle>;
// @public (undocumented)
export type TLDefaultHorizontalAlignStyle = T.TypeOf<typeof DefaultHorizontalAlignStyle>;
2023-04-25 11:01:25 +00:00
// @public
export type TLDefaultShape = TLArrowShape | TLBookmarkShape | TLDrawShape | TLEmbedShape | TLFrameShape | TLGeoShape | TLGroupShape | TLHighlightShape | TLImageShape | TLLineShape | TLNoteShape | TLTextShape | TLVideoShape;
// @public (undocumented)
export type TLDefaultSizeStyle = T.TypeOf<typeof DefaultSizeStyle>;
// @public (undocumented)
export type TLDefaultVerticalAlignStyle = T.TypeOf<typeof DefaultVerticalAlignStyle>;
2023-04-25 11:01:25 +00:00
// @public
export interface TLDocument extends BaseRecord<'document', RecordId<TLDocument>> {
2023-04-25 11:01:25 +00:00
// (undocumented)
gridSize: number;
Add support for project names (#1340) This PR adds some things that we need for the Project Name feature on tldraw.com. It should be reviewed alongside https://github.com/tldraw/tldraw-lite/pull/1814 ## Name Property This PR adds a `name` property to `TLDocument`. We use this to store a project's name. <img width="454" alt="Screenshot 2023-05-09 at 15 47 26" src="https://github.com/tldraw/tldraw/assets/15892272/f3be438e-aa0f-4dec-8f51-8dfd9f9d0ced"> ## Top Zone This PR adds a `topZone` area of the UI that we can add stuff to, similar to how `shareZone` works. It also adds an example to show where the `topZone` and `shareZone` are: <img width="1511" alt="Screenshot 2023-05-12 at 10 57 40" src="https://github.com/tldraw/tldraw/assets/15892272/f5e1cd33-017e-4aaf-bfee-4d85119e2974"> ## Breakpoints This PR change's the UI's breakpoints a little bit. It moves the action bar to the bottom a little bit earlier. (This gives us more space at the top for the project name). ![2023-05-12 at 11 08 26 - Fuchsia Bison](https://github.com/tldraw/tldraw/assets/15892272/34563cea-b1d1-47be-ac5e-5650ee0ba02d) ![2023-05-12 at 13 45 04 - Tan Mole](https://github.com/tldraw/tldraw/assets/15892272/ab190bd3-51d4-4a8b-88de-c72ab14bcba6) ## Input Blur This PR adds an `onBlur` parameter to `Input`. This was needed because 'clicking off' the input wasn't firing `onComplete` or `onCancel`. <img width="620" alt="Screenshot 2023-05-09 at 16 12 58" src="https://github.com/tldraw/tldraw/assets/15892272/3b28da74-0a74-4063-8053-e59e47027caf"> ## Create Project Name This PR adds an internal `createProjectName` property to `TldrawEditorConfig`. Similar to `derivePresenceState`, you can pass a custom function to it. It lets you control what gets used as the default project name. We use it to set different names in our local projects compared to shared projects. In the future, when we add more advanced project features, we could handle this better within the UI. <img width="454" alt="Screenshot 2023-05-09 at 15 47 26" src="https://github.com/tldraw/tldraw/assets/15892272/da9a4699-ac32-40d9-a97c-6c682acfac41"> ### Test Plan 1. Gradually reduce the width of the browser window. 2. Check that the actions menu jumps to the bottom before the style panel moves to the bottom. --- 1. In the examples app, open the `/zones` example. 2. Check that there's a 'top zone' at the top. - [ ] Unit Tests - [ ] Webdriver tests ### Release Note - [dev] Added a `topZone` area where you can put stuff. - [dev] Added a `name` property to `TLDocument` - and `app` methods for it. - [dev] Added an internal `createProjectName` config property for controlling the default project name. - [dev] Added an `onBlur` parameter to `Input`. - Moved the actions bar to the bottom on medium-sized screens. --------- Co-authored-by: Steve Ruiz <steveruizok@gmail.com>
2023-06-01 18:46:26 +00:00
// (undocumented)
meta: JsonObject;
// (undocumented)
Add support for project names (#1340) This PR adds some things that we need for the Project Name feature on tldraw.com. It should be reviewed alongside https://github.com/tldraw/tldraw-lite/pull/1814 ## Name Property This PR adds a `name` property to `TLDocument`. We use this to store a project's name. <img width="454" alt="Screenshot 2023-05-09 at 15 47 26" src="https://github.com/tldraw/tldraw/assets/15892272/f3be438e-aa0f-4dec-8f51-8dfd9f9d0ced"> ## Top Zone This PR adds a `topZone` area of the UI that we can add stuff to, similar to how `shareZone` works. It also adds an example to show where the `topZone` and `shareZone` are: <img width="1511" alt="Screenshot 2023-05-12 at 10 57 40" src="https://github.com/tldraw/tldraw/assets/15892272/f5e1cd33-017e-4aaf-bfee-4d85119e2974"> ## Breakpoints This PR change's the UI's breakpoints a little bit. It moves the action bar to the bottom a little bit earlier. (This gives us more space at the top for the project name). ![2023-05-12 at 11 08 26 - Fuchsia Bison](https://github.com/tldraw/tldraw/assets/15892272/34563cea-b1d1-47be-ac5e-5650ee0ba02d) ![2023-05-12 at 13 45 04 - Tan Mole](https://github.com/tldraw/tldraw/assets/15892272/ab190bd3-51d4-4a8b-88de-c72ab14bcba6) ## Input Blur This PR adds an `onBlur` parameter to `Input`. This was needed because 'clicking off' the input wasn't firing `onComplete` or `onCancel`. <img width="620" alt="Screenshot 2023-05-09 at 16 12 58" src="https://github.com/tldraw/tldraw/assets/15892272/3b28da74-0a74-4063-8053-e59e47027caf"> ## Create Project Name This PR adds an internal `createProjectName` property to `TldrawEditorConfig`. Similar to `derivePresenceState`, you can pass a custom function to it. It lets you control what gets used as the default project name. We use it to set different names in our local projects compared to shared projects. In the future, when we add more advanced project features, we could handle this better within the UI. <img width="454" alt="Screenshot 2023-05-09 at 15 47 26" src="https://github.com/tldraw/tldraw/assets/15892272/da9a4699-ac32-40d9-a97c-6c682acfac41"> ### Test Plan 1. Gradually reduce the width of the browser window. 2. Check that the actions menu jumps to the bottom before the style panel moves to the bottom. --- 1. In the examples app, open the `/zones` example. 2. Check that there's a 'top zone' at the top. - [ ] Unit Tests - [ ] Webdriver tests ### Release Note - [dev] Added a `topZone` area where you can put stuff. - [dev] Added a `name` property to `TLDocument` - and `app` methods for it. - [dev] Added an internal `createProjectName` config property for controlling the default project name. - [dev] Added an `onBlur` parameter to `Input`. - Moved the actions bar to the bottom on medium-sized screens. --------- Co-authored-by: Steve Ruiz <steveruizok@gmail.com>
2023-06-01 18:46:26 +00:00
name: string;
2023-04-25 11:01:25 +00:00
}
// @public (undocumented)
export const TLDOCUMENT_ID: RecordId<TLDocument>;
2023-04-25 11:01:25 +00:00
// @public (undocumented)
export type TLDrawShape = TLBaseShape<'draw', TLDrawShapeProps>;
// @public (undocumented)
export type TLDrawShapeSegment = T.TypeOf<typeof DrawShapeSegment>;
2023-04-25 11:01:25 +00:00
// @public (undocumented)
export type TLEmbedShape = TLBaseShape<'embed', TLEmbedShapeProps>;
// @public (undocumented)
export type TLEmbedShapePermissions = {
[K in keyof typeof embedShapePermissionDefaults]?: boolean;
2023-04-25 11:01:25 +00:00
};
// @public (undocumented)
export type TLFrameShape = TLBaseShape<'frame', TLFrameShapeProps>;
// @public (undocumented)
export type TLGeoShape = TLBaseShape<'geo', TLGeoShapeProps>;
// @public (undocumented)
export type TLGroupShape = TLBaseShape<'group', TLGroupShapeProps>;
// @public
export interface TLHandle {
// (undocumented)
canBind?: boolean;
// (undocumented)
canSnap?: boolean;
2023-04-25 11:01:25 +00:00
id: string;
// (undocumented)
index: string;
// (undocumented)
type: TLHandleType;
// (undocumented)
x: number;
// (undocumented)
y: number;
}
// @public
export type TLHandleType = SetValue<typeof TL_HANDLE_TYPES>;
// @public (undocumented)
export type TLHighlightShape = TLBaseShape<'highlight', TLHighlightShapeProps>;
// @public
2023-04-25 11:01:25 +00:00
export type TLImageAsset = TLBaseAsset<'image', {
w: number;
h: number;
name: string;
isAnimated: boolean;
mimeType: null | string;
src: null | string;
}>;
// @public (undocumented)
export type TLImageShape = TLBaseShape<'image', TLImageShapeProps>;
2023-04-25 11:01:25 +00:00
// @public (undocumented)
export type TLImageShapeCrop = T.TypeOf<typeof ImageShapeCrop>;
2023-04-25 11:01:25 +00:00
// @public (undocumented)
export type TLImageShapeProps = ShapePropsType<typeof imageShapeProps>;
2023-04-25 11:01:25 +00:00
// @public
export interface TLInstance extends BaseRecord<'instance', TLInstanceId> {
2023-04-25 11:01:25 +00:00
// (undocumented)
brush: BoxModel | null;
2023-04-25 11:01:25 +00:00
// (undocumented)
Remove helpers / extraneous API methods. (#1745) This PR removes several extraneous computed values from the editor. It adds some silly instance state onto the instance state record and unifies a few methods which were inconsistent. This is fit and finish work 🧽 ## Computed Values In general, where once we had a getter and setter for `isBlahMode`, which really masked either an `_isBlahMode` atom on the editor or `instanceState.isBlahMode`, these are merged into `instanceState`; they can be accessed / updated via `editor.instanceState` / `editor.updateInstanceState`. ## tldraw select tool specific things This PR also removes some tldraw specific state checks and creates new component overrides to allow us to include them in tldraw/tldraw. ### Change Type - [x] `major` — Breaking change ### Test Plan - [x] Unit Tests - [x] End to end tests ### Release Notes - [tldraw] rename `useReadonly` to `useReadOnly` - [editor] remove `Editor.isDarkMode` - [editor] remove `Editor.isChangingStyle` - [editor] remove `Editor.isCoarsePointer` - [editor] remove `Editor.isDarkMode` - [editor] remove `Editor.isFocused` - [editor] remove `Editor.isGridMode` - [editor] remove `Editor.isPenMode` - [editor] remove `Editor.isReadOnly` - [editor] remove `Editor.isSnapMode` - [editor] remove `Editor.isToolLocked` - [editor] remove `Editor.locale` - [editor] rename `Editor.pageState` to `Editor.currentPageState` - [editor] add `Editor.pageStates` - [editor] add `Editor.setErasingIds` - [editor] add `Editor.setEditingId` - [editor] add several new component overrides
2023-07-18 21:50:23 +00:00
canMoveCamera: boolean;
// (undocumented)
(1/2) Cursor Chat - Presence (#1487) This PR adds support for seeing **another user**'s chat messages. It's part 1 of two PRs relating to Cursor Chat. And it's needed for the much bigger part 2: https://github.com/tldraw/brivate/pull/1981 # Presence You can see another person's chat messages! ![2023-06-02 at 17 42 33 - Blush Capybara](https://github.com/tldraw/tldraw/assets/15892272/8f3efb5f-9c05-459c-aa7e-24842be75e58) If they have a name, it gets popped on top. ![2023-06-02 at 17 45 34 - Sapphire Meerkat](https://github.com/tldraw/tldraw/assets/15892272/749bd924-c1f5-419b-a028-1fafe1b61292) That's it! With this PR, there's no way of actually *typing* your chat messages. That comes with the [next one](https://github.com/tldraw/brivate/pull/1981)! # Admin ### To-do - [x] Store chat message - [x] Allow overflowing chat - [x] Presence for chat message - [x] Display chat message to others ### Change Type - [x] `minor` — New Feature ### Test Plan To test this, I recommend checking out both `lu/cursor-chat` branches, and opening two browser sessions in the same shared project. 1. In one session, type some cursor chat by pressing the Enter key while on the canvas (and typing). 2. On the other session, check that you can see the chat message appear. 3. Repeat this while being both named, and unnamed. I recommend just focusing on the visible presense in this PR. The [other PR](https://github.com/tldraw/brivate/pull/1981) is where we can focus about how we _input_ the cursor chat. ### Release Notes - [dev] Added support for cursor chat presence. --------- Co-authored-by: Steve Ruiz <steveruizok@gmail.com>
2023-06-15 15:10:08 +00:00
chatMessage: string;
// (undocumented)
2023-04-25 11:01:25 +00:00
currentPageId: TLPageId;
// (undocumented)
cursor: TLCursor;
// (undocumented)
Remove helpers / extraneous API methods. (#1745) This PR removes several extraneous computed values from the editor. It adds some silly instance state onto the instance state record and unifies a few methods which were inconsistent. This is fit and finish work 🧽 ## Computed Values In general, where once we had a getter and setter for `isBlahMode`, which really masked either an `_isBlahMode` atom on the editor or `instanceState.isBlahMode`, these are merged into `instanceState`; they can be accessed / updated via `editor.instanceState` / `editor.updateInstanceState`. ## tldraw select tool specific things This PR also removes some tldraw specific state checks and creates new component overrides to allow us to include them in tldraw/tldraw. ### Change Type - [x] `major` — Breaking change ### Test Plan - [x] Unit Tests - [x] End to end tests ### Release Notes - [tldraw] rename `useReadonly` to `useReadOnly` - [editor] remove `Editor.isDarkMode` - [editor] remove `Editor.isChangingStyle` - [editor] remove `Editor.isCoarsePointer` - [editor] remove `Editor.isDarkMode` - [editor] remove `Editor.isFocused` - [editor] remove `Editor.isGridMode` - [editor] remove `Editor.isPenMode` - [editor] remove `Editor.isReadOnly` - [editor] remove `Editor.isSnapMode` - [editor] remove `Editor.isToolLocked` - [editor] remove `Editor.locale` - [editor] rename `Editor.pageState` to `Editor.currentPageState` - [editor] add `Editor.pageStates` - [editor] add `Editor.setErasingIds` - [editor] add `Editor.setEditingId` - [editor] add several new component overrides
2023-07-18 21:50:23 +00:00
devicePixelRatio: number;
// (undocumented)
2023-04-25 11:01:25 +00:00
exportBackground: boolean;
// (undocumented)
followingUserId: null | string;
2023-04-25 11:01:25 +00:00
// (undocumented)
highlightedUserIds: string[];
// (undocumented)
[improvement] account for coarse pointers / insets in edge scrolling (#2401) This PR: - shrinks the distance for edge scrolling and insets the distance for coarse pointers - adds edge inset tracking ## Scroll distances Rather than increasing the distance, we move the "zero" in from the edges, so that the middle of a honkin' fat finger would be at "zero" when the edge of the finger is touching the edge of the screen. This is a bit more reliable than looking at just the component size. ## Inset tracking We now track whether a shape's edges are identical to the edges of the document body. When an edge is inset, we extend the edge scrolling distance outside of the component, so that dragging PAST the edge of the component will scroll. When an edge is NOT inset, we bring that distance into the component's bounds, so that dragging NEAR TO the edge will begin to scroll. ![image](https://github.com/tldraw/tldraw/assets/23072548/bb216c98-3dd0-4e2e-a635-4c4f339d5117) ![image](https://github.com/tldraw/tldraw/assets/23072548/75e83c81-1ca9-40a9-8edc-72851d3b1411) ![image](https://github.com/tldraw/tldraw/assets/23072548/6cda7bda-2935-4ded-821c-e7bf78833a1c) ### Change Type - [x] `minor` — New feature ### Test Plan 1. Use edge scrolling on mobile 2. Use edge scrolling on desktop 3. Use edge scrolling in the "scrolling example" - [x] Unit Tests ### Release Notes - Add `instanceState.insets` to track which edges of the component are inset from the edges of the document body. - Improve behavior around edge scrolling
2024-01-10 14:29:32 +00:00
insets: boolean[];
// (undocumented)
Remove helpers / extraneous API methods. (#1745) This PR removes several extraneous computed values from the editor. It adds some silly instance state onto the instance state record and unifies a few methods which were inconsistent. This is fit and finish work 🧽 ## Computed Values In general, where once we had a getter and setter for `isBlahMode`, which really masked either an `_isBlahMode` atom on the editor or `instanceState.isBlahMode`, these are merged into `instanceState`; they can be accessed / updated via `editor.instanceState` / `editor.updateInstanceState`. ## tldraw select tool specific things This PR also removes some tldraw specific state checks and creates new component overrides to allow us to include them in tldraw/tldraw. ### Change Type - [x] `major` — Breaking change ### Test Plan - [x] Unit Tests - [x] End to end tests ### Release Notes - [tldraw] rename `useReadonly` to `useReadOnly` - [editor] remove `Editor.isDarkMode` - [editor] remove `Editor.isChangingStyle` - [editor] remove `Editor.isCoarsePointer` - [editor] remove `Editor.isDarkMode` - [editor] remove `Editor.isFocused` - [editor] remove `Editor.isGridMode` - [editor] remove `Editor.isPenMode` - [editor] remove `Editor.isReadOnly` - [editor] remove `Editor.isSnapMode` - [editor] remove `Editor.isToolLocked` - [editor] remove `Editor.locale` - [editor] rename `Editor.pageState` to `Editor.currentPageState` - [editor] add `Editor.pageStates` - [editor] add `Editor.setErasingIds` - [editor] add `Editor.setEditingId` - [editor] add several new component overrides
2023-07-18 21:50:23 +00:00
isChangingStyle: boolean;
// (undocumented)
(1/2) Cursor Chat - Presence (#1487) This PR adds support for seeing **another user**'s chat messages. It's part 1 of two PRs relating to Cursor Chat. And it's needed for the much bigger part 2: https://github.com/tldraw/brivate/pull/1981 # Presence You can see another person's chat messages! ![2023-06-02 at 17 42 33 - Blush Capybara](https://github.com/tldraw/tldraw/assets/15892272/8f3efb5f-9c05-459c-aa7e-24842be75e58) If they have a name, it gets popped on top. ![2023-06-02 at 17 45 34 - Sapphire Meerkat](https://github.com/tldraw/tldraw/assets/15892272/749bd924-c1f5-419b-a028-1fafe1b61292) That's it! With this PR, there's no way of actually *typing* your chat messages. That comes with the [next one](https://github.com/tldraw/brivate/pull/1981)! # Admin ### To-do - [x] Store chat message - [x] Allow overflowing chat - [x] Presence for chat message - [x] Display chat message to others ### Change Type - [x] `minor` — New Feature ### Test Plan To test this, I recommend checking out both `lu/cursor-chat` branches, and opening two browser sessions in the same shared project. 1. In one session, type some cursor chat by pressing the Enter key while on the canvas (and typing). 2. On the other session, check that you can see the chat message appear. 3. Repeat this while being both named, and unnamed. I recommend just focusing on the visible presense in this PR. The [other PR](https://github.com/tldraw/brivate/pull/1981) is where we can focus about how we _input_ the cursor chat. ### Release Notes - [dev] Added support for cursor chat presence. --------- Co-authored-by: Steve Ruiz <steveruizok@gmail.com>
2023-06-15 15:10:08 +00:00
isChatting: boolean;
// (undocumented)
Remove helpers / extraneous API methods. (#1745) This PR removes several extraneous computed values from the editor. It adds some silly instance state onto the instance state record and unifies a few methods which were inconsistent. This is fit and finish work 🧽 ## Computed Values In general, where once we had a getter and setter for `isBlahMode`, which really masked either an `_isBlahMode` atom on the editor or `instanceState.isBlahMode`, these are merged into `instanceState`; they can be accessed / updated via `editor.instanceState` / `editor.updateInstanceState`. ## tldraw select tool specific things This PR also removes some tldraw specific state checks and creates new component overrides to allow us to include them in tldraw/tldraw. ### Change Type - [x] `major` — Breaking change ### Test Plan - [x] Unit Tests - [x] End to end tests ### Release Notes - [tldraw] rename `useReadonly` to `useReadOnly` - [editor] remove `Editor.isDarkMode` - [editor] remove `Editor.isChangingStyle` - [editor] remove `Editor.isCoarsePointer` - [editor] remove `Editor.isDarkMode` - [editor] remove `Editor.isFocused` - [editor] remove `Editor.isGridMode` - [editor] remove `Editor.isPenMode` - [editor] remove `Editor.isReadOnly` - [editor] remove `Editor.isSnapMode` - [editor] remove `Editor.isToolLocked` - [editor] remove `Editor.locale` - [editor] rename `Editor.pageState` to `Editor.currentPageState` - [editor] add `Editor.pageStates` - [editor] add `Editor.setErasingIds` - [editor] add `Editor.setEditingId` - [editor] add several new component overrides
2023-07-18 21:50:23 +00:00
isCoarsePointer: boolean;
// (undocumented)
2023-04-25 11:01:25 +00:00
isDebugMode: boolean;
// (undocumented)
Remove helpers / extraneous API methods. (#1745) This PR removes several extraneous computed values from the editor. It adds some silly instance state onto the instance state record and unifies a few methods which were inconsistent. This is fit and finish work 🧽 ## Computed Values In general, where once we had a getter and setter for `isBlahMode`, which really masked either an `_isBlahMode` atom on the editor or `instanceState.isBlahMode`, these are merged into `instanceState`; they can be accessed / updated via `editor.instanceState` / `editor.updateInstanceState`. ## tldraw select tool specific things This PR also removes some tldraw specific state checks and creates new component overrides to allow us to include them in tldraw/tldraw. ### Change Type - [x] `major` — Breaking change ### Test Plan - [x] Unit Tests - [x] End to end tests ### Release Notes - [tldraw] rename `useReadonly` to `useReadOnly` - [editor] remove `Editor.isDarkMode` - [editor] remove `Editor.isChangingStyle` - [editor] remove `Editor.isCoarsePointer` - [editor] remove `Editor.isDarkMode` - [editor] remove `Editor.isFocused` - [editor] remove `Editor.isGridMode` - [editor] remove `Editor.isPenMode` - [editor] remove `Editor.isReadOnly` - [editor] remove `Editor.isSnapMode` - [editor] remove `Editor.isToolLocked` - [editor] remove `Editor.locale` - [editor] rename `Editor.pageState` to `Editor.currentPageState` - [editor] add `Editor.pageStates` - [editor] add `Editor.setErasingIds` - [editor] add `Editor.setEditingId` - [editor] add several new component overrides
2023-07-18 21:50:23 +00:00
isFocused: boolean;
// (undocumented)
2023-04-25 11:01:25 +00:00
isFocusMode: boolean;
// (undocumented)
Independent instance state persistence (#1493) This PR - Removes UserDocumentRecordType - moving isSnapMode to user preferences - moving isGridMode and isPenMode to InstanceRecordType - deleting the other properties which are no longer needed. - Creates a separate pipeline for persisting instance state. Previously the instance state records were stored alongside the document state records, and in order to load the state for a particular instance (in our case, a particular tab) you needed to pass the 'instanceId' prop. This prop ended up totally pervading the public API and people ran into all kinds of issues with it, e.g. using the same instance id in multiple editor instances. There was also an issue whereby it was hard for us to clean up old instance state so the idb table ended up bloating over time. This PR makes it so that rather than passing an instanceId, you load the instance state yourself while creating the store. It provides tools to make that easy. - Undoes the assumption that we might have more than one instance's state in the store. - Like `document`, `instance` now has a singleton id `instance:instance`. - Page state ids and camera ids are no longer random, but rather derive from the page they belong to. This is like having a foreign primary key in SQL databases. It's something i'd love to support fully as part of the RecordType/Store api. Tests to do - [x] Test Migrations - [x] Test Store.listen filtering - [x] Make type sets in Store public and readonly - [x] Test RecordType.createId - [x] Test Instance state snapshot loading/exporting - [x] Manual test File I/O - [x] Manual test Vscode extension with multiple tabs - [x] Audit usages of store.query - [x] Audit usages of changed types: InstanceRecordType, 'instance', InstancePageStateRecordType, 'instance_page_state', 'user_document', 'camera', CameraRecordType, InstancePresenceRecordType, 'instance_presence' - [x] Test user preferences - [x] Manual test isSnapMode and isGridMode and isPenMode - [ ] Test indexedDb functions - [x] Add instanceId stuff back ### Change Type - [x] `major` — Breaking Change ### Test Plan 1. Add a step-by-step description of how to test your PR here. 2. - [ ] Unit Tests - [ ] Webdriver tests ### Release Notes - Add a brief release note for your PR here.
2023-06-05 14:11:07 +00:00
isGridMode: boolean;
isHoveringCanvas: boolean | null;
Independent instance state persistence (#1493) This PR - Removes UserDocumentRecordType - moving isSnapMode to user preferences - moving isGridMode and isPenMode to InstanceRecordType - deleting the other properties which are no longer needed. - Creates a separate pipeline for persisting instance state. Previously the instance state records were stored alongside the document state records, and in order to load the state for a particular instance (in our case, a particular tab) you needed to pass the 'instanceId' prop. This prop ended up totally pervading the public API and people ran into all kinds of issues with it, e.g. using the same instance id in multiple editor instances. There was also an issue whereby it was hard for us to clean up old instance state so the idb table ended up bloating over time. This PR makes it so that rather than passing an instanceId, you load the instance state yourself while creating the store. It provides tools to make that easy. - Undoes the assumption that we might have more than one instance's state in the store. - Like `document`, `instance` now has a singleton id `instance:instance`. - Page state ids and camera ids are no longer random, but rather derive from the page they belong to. This is like having a foreign primary key in SQL databases. It's something i'd love to support fully as part of the RecordType/Store api. Tests to do - [x] Test Migrations - [x] Test Store.listen filtering - [x] Make type sets in Store public and readonly - [x] Test RecordType.createId - [x] Test Instance state snapshot loading/exporting - [x] Manual test File I/O - [x] Manual test Vscode extension with multiple tabs - [x] Audit usages of store.query - [x] Audit usages of changed types: InstanceRecordType, 'instance', InstancePageStateRecordType, 'instance_page_state', 'user_document', 'camera', CameraRecordType, InstancePresenceRecordType, 'instance_presence' - [x] Test user preferences - [x] Manual test isSnapMode and isGridMode and isPenMode - [ ] Test indexedDb functions - [x] Add instanceId stuff back ### Change Type - [x] `major` — Breaking Change ### Test Plan 1. Add a step-by-step description of how to test your PR here. 2. - [ ] Unit Tests - [ ] Webdriver tests ### Release Notes - Add a brief release note for your PR here.
2023-06-05 14:11:07 +00:00
// (undocumented)
isPenMode: boolean;
// (undocumented)
isReadonly: boolean;
Remove helpers / extraneous API methods. (#1745) This PR removes several extraneous computed values from the editor. It adds some silly instance state onto the instance state record and unifies a few methods which were inconsistent. This is fit and finish work 🧽 ## Computed Values In general, where once we had a getter and setter for `isBlahMode`, which really masked either an `_isBlahMode` atom on the editor or `instanceState.isBlahMode`, these are merged into `instanceState`; they can be accessed / updated via `editor.instanceState` / `editor.updateInstanceState`. ## tldraw select tool specific things This PR also removes some tldraw specific state checks and creates new component overrides to allow us to include them in tldraw/tldraw. ### Change Type - [x] `major` — Breaking change ### Test Plan - [x] Unit Tests - [x] End to end tests ### Release Notes - [tldraw] rename `useReadonly` to `useReadOnly` - [editor] remove `Editor.isDarkMode` - [editor] remove `Editor.isChangingStyle` - [editor] remove `Editor.isCoarsePointer` - [editor] remove `Editor.isDarkMode` - [editor] remove `Editor.isFocused` - [editor] remove `Editor.isGridMode` - [editor] remove `Editor.isPenMode` - [editor] remove `Editor.isReadOnly` - [editor] remove `Editor.isSnapMode` - [editor] remove `Editor.isToolLocked` - [editor] remove `Editor.locale` - [editor] rename `Editor.pageState` to `Editor.currentPageState` - [editor] add `Editor.pageStates` - [editor] add `Editor.setErasingIds` - [editor] add `Editor.setEditingId` - [editor] add several new component overrides
2023-07-18 21:50:23 +00:00
// (undocumented)
2023-04-25 11:01:25 +00:00
isToolLocked: boolean;
// (undocumented)
meta: JsonObject;
// (undocumented)
opacityForNextShape: TLOpacityType;
// (undocumented)
Remove helpers / extraneous API methods. (#1745) This PR removes several extraneous computed values from the editor. It adds some silly instance state onto the instance state record and unifies a few methods which were inconsistent. This is fit and finish work 🧽 ## Computed Values In general, where once we had a getter and setter for `isBlahMode`, which really masked either an `_isBlahMode` atom on the editor or `instanceState.isBlahMode`, these are merged into `instanceState`; they can be accessed / updated via `editor.instanceState` / `editor.updateInstanceState`. ## tldraw select tool specific things This PR also removes some tldraw specific state checks and creates new component overrides to allow us to include them in tldraw/tldraw. ### Change Type - [x] `major` — Breaking change ### Test Plan - [x] Unit Tests - [x] End to end tests ### Release Notes - [tldraw] rename `useReadonly` to `useReadOnly` - [editor] remove `Editor.isDarkMode` - [editor] remove `Editor.isChangingStyle` - [editor] remove `Editor.isCoarsePointer` - [editor] remove `Editor.isDarkMode` - [editor] remove `Editor.isFocused` - [editor] remove `Editor.isGridMode` - [editor] remove `Editor.isPenMode` - [editor] remove `Editor.isReadOnly` - [editor] remove `Editor.isSnapMode` - [editor] remove `Editor.isToolLocked` - [editor] remove `Editor.locale` - [editor] rename `Editor.pageState` to `Editor.currentPageState` - [editor] add `Editor.pageStates` - [editor] add `Editor.setErasingIds` - [editor] add `Editor.setEditingId` - [editor] add several new component overrides
2023-07-18 21:50:23 +00:00
openMenus: string[];
// (undocumented)
screenBounds: BoxModel;
2023-04-25 11:01:25 +00:00
// (undocumented)
scribbles: TLScribble[];
2023-04-25 11:01:25 +00:00
// (undocumented)
stylesForNextShape: Record<string, unknown>;
// (undocumented)
zoomBrush: BoxModel | null;
2023-04-25 11:01:25 +00:00
}
Independent instance state persistence (#1493) This PR - Removes UserDocumentRecordType - moving isSnapMode to user preferences - moving isGridMode and isPenMode to InstanceRecordType - deleting the other properties which are no longer needed. - Creates a separate pipeline for persisting instance state. Previously the instance state records were stored alongside the document state records, and in order to load the state for a particular instance (in our case, a particular tab) you needed to pass the 'instanceId' prop. This prop ended up totally pervading the public API and people ran into all kinds of issues with it, e.g. using the same instance id in multiple editor instances. There was also an issue whereby it was hard for us to clean up old instance state so the idb table ended up bloating over time. This PR makes it so that rather than passing an instanceId, you load the instance state yourself while creating the store. It provides tools to make that easy. - Undoes the assumption that we might have more than one instance's state in the store. - Like `document`, `instance` now has a singleton id `instance:instance`. - Page state ids and camera ids are no longer random, but rather derive from the page they belong to. This is like having a foreign primary key in SQL databases. It's something i'd love to support fully as part of the RecordType/Store api. Tests to do - [x] Test Migrations - [x] Test Store.listen filtering - [x] Make type sets in Store public and readonly - [x] Test RecordType.createId - [x] Test Instance state snapshot loading/exporting - [x] Manual test File I/O - [x] Manual test Vscode extension with multiple tabs - [x] Audit usages of store.query - [x] Audit usages of changed types: InstanceRecordType, 'instance', InstancePageStateRecordType, 'instance_page_state', 'user_document', 'camera', CameraRecordType, InstancePresenceRecordType, 'instance_presence' - [x] Test user preferences - [x] Manual test isSnapMode and isGridMode and isPenMode - [ ] Test indexedDb functions - [x] Add instanceId stuff back ### Change Type - [x] `major` — Breaking Change ### Test Plan 1. Add a step-by-step description of how to test your PR here. 2. - [ ] Unit Tests - [ ] Webdriver tests ### Release Notes - Add a brief release note for your PR here.
2023-06-05 14:11:07 +00:00
// @public (undocumented)
export const TLINSTANCE_ID: TLInstanceId;
2023-04-25 11:01:25 +00:00
// @public (undocumented)
export type TLInstanceId = RecordId<TLInstance>;
2023-04-25 11:01:25 +00:00
// @public
export interface TLInstancePageState extends BaseRecord<'instance_page_state', TLInstancePageStateId> {
2023-04-25 11:01:25 +00:00
// (undocumented)
`ShapeUtil.getGeometry`, selection rewrite (#1751) This PR is a significant rewrite of our selection / hit testing logic. It - replaces our current geometric helpers (`getBounds`, `getOutline`, `hitTestPoint`, and `hitTestLineSegment`) with a new geometry API - moves our hit testing entirely to JS using geometry - improves selection logic, especially around editing shapes, groups and frames - fixes many minor selection bugs (e.g. shapes behind frames) - removes hit-testing DOM elements from ShapeFill etc. - adds many new tests around selection - adds new tests around selection - makes several superficial changes to surface editor APIs This PR is hard to evaluate. The `selection-omnibus` test suite is intended to describe all of the selection behavior, however all existing tests are also either here preserved and passing or (in a few cases around editing shapes) are modified to reflect the new behavior. ## Geometry All `ShapeUtils` implement `getGeometry`, which returns a single geometry primitive (`Geometry2d`). For example: ```ts class BoxyShapeUtil { getGeometry(shape: BoxyShape) { return new Rectangle2d({ width: shape.props.width, height: shape.props.height, isFilled: true, margin: shape.props.strokeWidth }) } } ``` This geometric primitive is used for all bounds calculation, hit testing, intersection with arrows, etc. There are several geometric primitives that extend `Geometry2d`: - `Arc2d` - `Circle2d` - `CubicBezier2d` - `CubicSpline2d` - `Edge2d` - `Ellipse2d` - `Group2d` - `Polygon2d` - `Rectangle2d` - `Stadium2d` For shapes that have more complicated geometric representations, such as an arrow with a label, the `Group2d` can accept other primitives as its children. ## Hit testing Previously, we did all hit testing via events set on shapes and other elements. In this PR, I've replaced those hit tests with our own calculation for hit tests in JavaScript. This removed the need for many DOM elements, such as hit test area borders and fills which only existed to trigger pointer events. ## Selection We now support selecting "hollow" shapes by clicking inside of them. This involves a lot of new logic but it should work intuitively. See `Editor.getShapeAtPoint` for the (thoroughly commented) implementation. ![Kapture 2023-07-23 at 23 27 27](https://github.com/tldraw/tldraw/assets/23072548/a743275c-acdb-42d9-a3fe-b3e20dce86b6) every sunset is actually the sun hiding in fear and respect of tldraw's quality of interactions This PR also fixes several bugs with scribble selection, in particular around the shift key modifier. ![Kapture 2023-07-24 at 23 34 07](https://github.com/tldraw/tldraw/assets/23072548/871d67d0-8d06-42ae-a2b2-021effba37c5) ...as well as issues with labels and editing. There are **over 100 new tests** for selection covering groups, frames, brushing, scribbling, hovering, and editing. I'll add a few more before I feel comfortable merging this PR. ## Arrow binding Using the same "hollow shape" logic as selection, arrow binding is significantly improved. ![Kapture 2023-07-22 at 07 46 25](https://github.com/tldraw/tldraw/assets/23072548/5aa724b3-b57d-4fb7-92d0-80e34246753c) a thousand wise men could not improve on this ## Moving focus between editing shapes Previously, this was handled in the `editing_shapes` state. This is moved to `useEditableText`, and should generally be considered an advanced implementation detail on a shape-by-shape basis. This addresses a bug that I'd never noticed before, but which can be reproduced by selecting an shape—but not focusing its input—while editing a different shape. Previously, the new shape became the editing shape but its input did not focus. ![Kapture 2023-07-23 at 23 19 09](https://github.com/tldraw/tldraw/assets/23072548/a5e157fb-24a8-42bd-a692-04ce769b1a9c) In this PR, you can select a shape by clicking on its edge or body, or select its input to transfer editing / focus. ![Kapture 2023-07-23 at 23 22 21](https://github.com/tldraw/tldraw/assets/23072548/7384e7ea-9777-4e1a-8f63-15de2166a53a) tldraw, glorious tldraw ### Change Type - [x] `major` — Breaking change ### Test Plan 1. Erase shapes 2. Select shapes 3. Calculate their bounding boxes - [ ] Unit Tests // todo - [ ] End to end tests // todo ### Release Notes - [editor] Remove `ShapeUtil.getBounds`, `ShapeUtil.getOutline`, `ShapeUtil.hitTestPoint`, `ShapeUtil.hitTestLineSegment` - [editor] Add `ShapeUtil.getGeometry` - [editor] Add `Editor.getShapeGeometry`
2023-07-25 16:10:15 +00:00
croppingShapeId: null | TLShapeId;
2023-04-25 11:01:25 +00:00
// (undocumented)
`ShapeUtil.getGeometry`, selection rewrite (#1751) This PR is a significant rewrite of our selection / hit testing logic. It - replaces our current geometric helpers (`getBounds`, `getOutline`, `hitTestPoint`, and `hitTestLineSegment`) with a new geometry API - moves our hit testing entirely to JS using geometry - improves selection logic, especially around editing shapes, groups and frames - fixes many minor selection bugs (e.g. shapes behind frames) - removes hit-testing DOM elements from ShapeFill etc. - adds many new tests around selection - adds new tests around selection - makes several superficial changes to surface editor APIs This PR is hard to evaluate. The `selection-omnibus` test suite is intended to describe all of the selection behavior, however all existing tests are also either here preserved and passing or (in a few cases around editing shapes) are modified to reflect the new behavior. ## Geometry All `ShapeUtils` implement `getGeometry`, which returns a single geometry primitive (`Geometry2d`). For example: ```ts class BoxyShapeUtil { getGeometry(shape: BoxyShape) { return new Rectangle2d({ width: shape.props.width, height: shape.props.height, isFilled: true, margin: shape.props.strokeWidth }) } } ``` This geometric primitive is used for all bounds calculation, hit testing, intersection with arrows, etc. There are several geometric primitives that extend `Geometry2d`: - `Arc2d` - `Circle2d` - `CubicBezier2d` - `CubicSpline2d` - `Edge2d` - `Ellipse2d` - `Group2d` - `Polygon2d` - `Rectangle2d` - `Stadium2d` For shapes that have more complicated geometric representations, such as an arrow with a label, the `Group2d` can accept other primitives as its children. ## Hit testing Previously, we did all hit testing via events set on shapes and other elements. In this PR, I've replaced those hit tests with our own calculation for hit tests in JavaScript. This removed the need for many DOM elements, such as hit test area borders and fills which only existed to trigger pointer events. ## Selection We now support selecting "hollow" shapes by clicking inside of them. This involves a lot of new logic but it should work intuitively. See `Editor.getShapeAtPoint` for the (thoroughly commented) implementation. ![Kapture 2023-07-23 at 23 27 27](https://github.com/tldraw/tldraw/assets/23072548/a743275c-acdb-42d9-a3fe-b3e20dce86b6) every sunset is actually the sun hiding in fear and respect of tldraw's quality of interactions This PR also fixes several bugs with scribble selection, in particular around the shift key modifier. ![Kapture 2023-07-24 at 23 34 07](https://github.com/tldraw/tldraw/assets/23072548/871d67d0-8d06-42ae-a2b2-021effba37c5) ...as well as issues with labels and editing. There are **over 100 new tests** for selection covering groups, frames, brushing, scribbling, hovering, and editing. I'll add a few more before I feel comfortable merging this PR. ## Arrow binding Using the same "hollow shape" logic as selection, arrow binding is significantly improved. ![Kapture 2023-07-22 at 07 46 25](https://github.com/tldraw/tldraw/assets/23072548/5aa724b3-b57d-4fb7-92d0-80e34246753c) a thousand wise men could not improve on this ## Moving focus between editing shapes Previously, this was handled in the `editing_shapes` state. This is moved to `useEditableText`, and should generally be considered an advanced implementation detail on a shape-by-shape basis. This addresses a bug that I'd never noticed before, but which can be reproduced by selecting an shape—but not focusing its input—while editing a different shape. Previously, the new shape became the editing shape but its input did not focus. ![Kapture 2023-07-23 at 23 19 09](https://github.com/tldraw/tldraw/assets/23072548/a5e157fb-24a8-42bd-a692-04ce769b1a9c) In this PR, you can select a shape by clicking on its edge or body, or select its input to transfer editing / focus. ![Kapture 2023-07-23 at 23 22 21](https://github.com/tldraw/tldraw/assets/23072548/7384e7ea-9777-4e1a-8f63-15de2166a53a) tldraw, glorious tldraw ### Change Type - [x] `major` — Breaking change ### Test Plan 1. Erase shapes 2. Select shapes 3. Calculate their bounding boxes - [ ] Unit Tests // todo - [ ] End to end tests // todo ### Release Notes - [editor] Remove `ShapeUtil.getBounds`, `ShapeUtil.getOutline`, `ShapeUtil.hitTestPoint`, `ShapeUtil.hitTestLineSegment` - [editor] Add `ShapeUtil.getGeometry` - [editor] Add `Editor.getShapeGeometry`
2023-07-25 16:10:15 +00:00
editingShapeId: null | TLShapeId;
2023-04-25 11:01:25 +00:00
// (undocumented)
`ShapeUtil.getGeometry`, selection rewrite (#1751) This PR is a significant rewrite of our selection / hit testing logic. It - replaces our current geometric helpers (`getBounds`, `getOutline`, `hitTestPoint`, and `hitTestLineSegment`) with a new geometry API - moves our hit testing entirely to JS using geometry - improves selection logic, especially around editing shapes, groups and frames - fixes many minor selection bugs (e.g. shapes behind frames) - removes hit-testing DOM elements from ShapeFill etc. - adds many new tests around selection - adds new tests around selection - makes several superficial changes to surface editor APIs This PR is hard to evaluate. The `selection-omnibus` test suite is intended to describe all of the selection behavior, however all existing tests are also either here preserved and passing or (in a few cases around editing shapes) are modified to reflect the new behavior. ## Geometry All `ShapeUtils` implement `getGeometry`, which returns a single geometry primitive (`Geometry2d`). For example: ```ts class BoxyShapeUtil { getGeometry(shape: BoxyShape) { return new Rectangle2d({ width: shape.props.width, height: shape.props.height, isFilled: true, margin: shape.props.strokeWidth }) } } ``` This geometric primitive is used for all bounds calculation, hit testing, intersection with arrows, etc. There are several geometric primitives that extend `Geometry2d`: - `Arc2d` - `Circle2d` - `CubicBezier2d` - `CubicSpline2d` - `Edge2d` - `Ellipse2d` - `Group2d` - `Polygon2d` - `Rectangle2d` - `Stadium2d` For shapes that have more complicated geometric representations, such as an arrow with a label, the `Group2d` can accept other primitives as its children. ## Hit testing Previously, we did all hit testing via events set on shapes and other elements. In this PR, I've replaced those hit tests with our own calculation for hit tests in JavaScript. This removed the need for many DOM elements, such as hit test area borders and fills which only existed to trigger pointer events. ## Selection We now support selecting "hollow" shapes by clicking inside of them. This involves a lot of new logic but it should work intuitively. See `Editor.getShapeAtPoint` for the (thoroughly commented) implementation. ![Kapture 2023-07-23 at 23 27 27](https://github.com/tldraw/tldraw/assets/23072548/a743275c-acdb-42d9-a3fe-b3e20dce86b6) every sunset is actually the sun hiding in fear and respect of tldraw's quality of interactions This PR also fixes several bugs with scribble selection, in particular around the shift key modifier. ![Kapture 2023-07-24 at 23 34 07](https://github.com/tldraw/tldraw/assets/23072548/871d67d0-8d06-42ae-a2b2-021effba37c5) ...as well as issues with labels and editing. There are **over 100 new tests** for selection covering groups, frames, brushing, scribbling, hovering, and editing. I'll add a few more before I feel comfortable merging this PR. ## Arrow binding Using the same "hollow shape" logic as selection, arrow binding is significantly improved. ![Kapture 2023-07-22 at 07 46 25](https://github.com/tldraw/tldraw/assets/23072548/5aa724b3-b57d-4fb7-92d0-80e34246753c) a thousand wise men could not improve on this ## Moving focus between editing shapes Previously, this was handled in the `editing_shapes` state. This is moved to `useEditableText`, and should generally be considered an advanced implementation detail on a shape-by-shape basis. This addresses a bug that I'd never noticed before, but which can be reproduced by selecting an shape—but not focusing its input—while editing a different shape. Previously, the new shape became the editing shape but its input did not focus. ![Kapture 2023-07-23 at 23 19 09](https://github.com/tldraw/tldraw/assets/23072548/a5e157fb-24a8-42bd-a692-04ce769b1a9c) In this PR, you can select a shape by clicking on its edge or body, or select its input to transfer editing / focus. ![Kapture 2023-07-23 at 23 22 21](https://github.com/tldraw/tldraw/assets/23072548/7384e7ea-9777-4e1a-8f63-15de2166a53a) tldraw, glorious tldraw ### Change Type - [x] `major` — Breaking change ### Test Plan 1. Erase shapes 2. Select shapes 3. Calculate their bounding boxes - [ ] Unit Tests // todo - [ ] End to end tests // todo ### Release Notes - [editor] Remove `ShapeUtil.getBounds`, `ShapeUtil.getOutline`, `ShapeUtil.hitTestPoint`, `ShapeUtil.hitTestLineSegment` - [editor] Add `ShapeUtil.getGeometry` - [editor] Add `Editor.getShapeGeometry`
2023-07-25 16:10:15 +00:00
erasingShapeIds: TLShapeId[];
2023-04-25 11:01:25 +00:00
// (undocumented)
`ShapeUtil.getGeometry`, selection rewrite (#1751) This PR is a significant rewrite of our selection / hit testing logic. It - replaces our current geometric helpers (`getBounds`, `getOutline`, `hitTestPoint`, and `hitTestLineSegment`) with a new geometry API - moves our hit testing entirely to JS using geometry - improves selection logic, especially around editing shapes, groups and frames - fixes many minor selection bugs (e.g. shapes behind frames) - removes hit-testing DOM elements from ShapeFill etc. - adds many new tests around selection - adds new tests around selection - makes several superficial changes to surface editor APIs This PR is hard to evaluate. The `selection-omnibus` test suite is intended to describe all of the selection behavior, however all existing tests are also either here preserved and passing or (in a few cases around editing shapes) are modified to reflect the new behavior. ## Geometry All `ShapeUtils` implement `getGeometry`, which returns a single geometry primitive (`Geometry2d`). For example: ```ts class BoxyShapeUtil { getGeometry(shape: BoxyShape) { return new Rectangle2d({ width: shape.props.width, height: shape.props.height, isFilled: true, margin: shape.props.strokeWidth }) } } ``` This geometric primitive is used for all bounds calculation, hit testing, intersection with arrows, etc. There are several geometric primitives that extend `Geometry2d`: - `Arc2d` - `Circle2d` - `CubicBezier2d` - `CubicSpline2d` - `Edge2d` - `Ellipse2d` - `Group2d` - `Polygon2d` - `Rectangle2d` - `Stadium2d` For shapes that have more complicated geometric representations, such as an arrow with a label, the `Group2d` can accept other primitives as its children. ## Hit testing Previously, we did all hit testing via events set on shapes and other elements. In this PR, I've replaced those hit tests with our own calculation for hit tests in JavaScript. This removed the need for many DOM elements, such as hit test area borders and fills which only existed to trigger pointer events. ## Selection We now support selecting "hollow" shapes by clicking inside of them. This involves a lot of new logic but it should work intuitively. See `Editor.getShapeAtPoint` for the (thoroughly commented) implementation. ![Kapture 2023-07-23 at 23 27 27](https://github.com/tldraw/tldraw/assets/23072548/a743275c-acdb-42d9-a3fe-b3e20dce86b6) every sunset is actually the sun hiding in fear and respect of tldraw's quality of interactions This PR also fixes several bugs with scribble selection, in particular around the shift key modifier. ![Kapture 2023-07-24 at 23 34 07](https://github.com/tldraw/tldraw/assets/23072548/871d67d0-8d06-42ae-a2b2-021effba37c5) ...as well as issues with labels and editing. There are **over 100 new tests** for selection covering groups, frames, brushing, scribbling, hovering, and editing. I'll add a few more before I feel comfortable merging this PR. ## Arrow binding Using the same "hollow shape" logic as selection, arrow binding is significantly improved. ![Kapture 2023-07-22 at 07 46 25](https://github.com/tldraw/tldraw/assets/23072548/5aa724b3-b57d-4fb7-92d0-80e34246753c) a thousand wise men could not improve on this ## Moving focus between editing shapes Previously, this was handled in the `editing_shapes` state. This is moved to `useEditableText`, and should generally be considered an advanced implementation detail on a shape-by-shape basis. This addresses a bug that I'd never noticed before, but which can be reproduced by selecting an shape—but not focusing its input—while editing a different shape. Previously, the new shape became the editing shape but its input did not focus. ![Kapture 2023-07-23 at 23 19 09](https://github.com/tldraw/tldraw/assets/23072548/a5e157fb-24a8-42bd-a692-04ce769b1a9c) In this PR, you can select a shape by clicking on its edge or body, or select its input to transfer editing / focus. ![Kapture 2023-07-23 at 23 22 21](https://github.com/tldraw/tldraw/assets/23072548/7384e7ea-9777-4e1a-8f63-15de2166a53a) tldraw, glorious tldraw ### Change Type - [x] `major` — Breaking change ### Test Plan 1. Erase shapes 2. Select shapes 3. Calculate their bounding boxes - [ ] Unit Tests // todo - [ ] End to end tests // todo ### Release Notes - [editor] Remove `ShapeUtil.getBounds`, `ShapeUtil.getOutline`, `ShapeUtil.hitTestPoint`, `ShapeUtil.hitTestLineSegment` - [editor] Add `ShapeUtil.getGeometry` - [editor] Add `Editor.getShapeGeometry`
2023-07-25 16:10:15 +00:00
focusedGroupId: null | TLShapeId;
2023-04-25 11:01:25 +00:00
// (undocumented)
`ShapeUtil.getGeometry`, selection rewrite (#1751) This PR is a significant rewrite of our selection / hit testing logic. It - replaces our current geometric helpers (`getBounds`, `getOutline`, `hitTestPoint`, and `hitTestLineSegment`) with a new geometry API - moves our hit testing entirely to JS using geometry - improves selection logic, especially around editing shapes, groups and frames - fixes many minor selection bugs (e.g. shapes behind frames) - removes hit-testing DOM elements from ShapeFill etc. - adds many new tests around selection - adds new tests around selection - makes several superficial changes to surface editor APIs This PR is hard to evaluate. The `selection-omnibus` test suite is intended to describe all of the selection behavior, however all existing tests are also either here preserved and passing or (in a few cases around editing shapes) are modified to reflect the new behavior. ## Geometry All `ShapeUtils` implement `getGeometry`, which returns a single geometry primitive (`Geometry2d`). For example: ```ts class BoxyShapeUtil { getGeometry(shape: BoxyShape) { return new Rectangle2d({ width: shape.props.width, height: shape.props.height, isFilled: true, margin: shape.props.strokeWidth }) } } ``` This geometric primitive is used for all bounds calculation, hit testing, intersection with arrows, etc. There are several geometric primitives that extend `Geometry2d`: - `Arc2d` - `Circle2d` - `CubicBezier2d` - `CubicSpline2d` - `Edge2d` - `Ellipse2d` - `Group2d` - `Polygon2d` - `Rectangle2d` - `Stadium2d` For shapes that have more complicated geometric representations, such as an arrow with a label, the `Group2d` can accept other primitives as its children. ## Hit testing Previously, we did all hit testing via events set on shapes and other elements. In this PR, I've replaced those hit tests with our own calculation for hit tests in JavaScript. This removed the need for many DOM elements, such as hit test area borders and fills which only existed to trigger pointer events. ## Selection We now support selecting "hollow" shapes by clicking inside of them. This involves a lot of new logic but it should work intuitively. See `Editor.getShapeAtPoint` for the (thoroughly commented) implementation. ![Kapture 2023-07-23 at 23 27 27](https://github.com/tldraw/tldraw/assets/23072548/a743275c-acdb-42d9-a3fe-b3e20dce86b6) every sunset is actually the sun hiding in fear and respect of tldraw's quality of interactions This PR also fixes several bugs with scribble selection, in particular around the shift key modifier. ![Kapture 2023-07-24 at 23 34 07](https://github.com/tldraw/tldraw/assets/23072548/871d67d0-8d06-42ae-a2b2-021effba37c5) ...as well as issues with labels and editing. There are **over 100 new tests** for selection covering groups, frames, brushing, scribbling, hovering, and editing. I'll add a few more before I feel comfortable merging this PR. ## Arrow binding Using the same "hollow shape" logic as selection, arrow binding is significantly improved. ![Kapture 2023-07-22 at 07 46 25](https://github.com/tldraw/tldraw/assets/23072548/5aa724b3-b57d-4fb7-92d0-80e34246753c) a thousand wise men could not improve on this ## Moving focus between editing shapes Previously, this was handled in the `editing_shapes` state. This is moved to `useEditableText`, and should generally be considered an advanced implementation detail on a shape-by-shape basis. This addresses a bug that I'd never noticed before, but which can be reproduced by selecting an shape—but not focusing its input—while editing a different shape. Previously, the new shape became the editing shape but its input did not focus. ![Kapture 2023-07-23 at 23 19 09](https://github.com/tldraw/tldraw/assets/23072548/a5e157fb-24a8-42bd-a692-04ce769b1a9c) In this PR, you can select a shape by clicking on its edge or body, or select its input to transfer editing / focus. ![Kapture 2023-07-23 at 23 22 21](https://github.com/tldraw/tldraw/assets/23072548/7384e7ea-9777-4e1a-8f63-15de2166a53a) tldraw, glorious tldraw ### Change Type - [x] `major` — Breaking change ### Test Plan 1. Erase shapes 2. Select shapes 3. Calculate their bounding boxes - [ ] Unit Tests // todo - [ ] End to end tests // todo ### Release Notes - [editor] Remove `ShapeUtil.getBounds`, `ShapeUtil.getOutline`, `ShapeUtil.hitTestPoint`, `ShapeUtil.hitTestLineSegment` - [editor] Add `ShapeUtil.getGeometry` - [editor] Add `Editor.getShapeGeometry`
2023-07-25 16:10:15 +00:00
hintingShapeIds: TLShapeId[];
2023-04-25 11:01:25 +00:00
// (undocumented)
`ShapeUtil.getGeometry`, selection rewrite (#1751) This PR is a significant rewrite of our selection / hit testing logic. It - replaces our current geometric helpers (`getBounds`, `getOutline`, `hitTestPoint`, and `hitTestLineSegment`) with a new geometry API - moves our hit testing entirely to JS using geometry - improves selection logic, especially around editing shapes, groups and frames - fixes many minor selection bugs (e.g. shapes behind frames) - removes hit-testing DOM elements from ShapeFill etc. - adds many new tests around selection - adds new tests around selection - makes several superficial changes to surface editor APIs This PR is hard to evaluate. The `selection-omnibus` test suite is intended to describe all of the selection behavior, however all existing tests are also either here preserved and passing or (in a few cases around editing shapes) are modified to reflect the new behavior. ## Geometry All `ShapeUtils` implement `getGeometry`, which returns a single geometry primitive (`Geometry2d`). For example: ```ts class BoxyShapeUtil { getGeometry(shape: BoxyShape) { return new Rectangle2d({ width: shape.props.width, height: shape.props.height, isFilled: true, margin: shape.props.strokeWidth }) } } ``` This geometric primitive is used for all bounds calculation, hit testing, intersection with arrows, etc. There are several geometric primitives that extend `Geometry2d`: - `Arc2d` - `Circle2d` - `CubicBezier2d` - `CubicSpline2d` - `Edge2d` - `Ellipse2d` - `Group2d` - `Polygon2d` - `Rectangle2d` - `Stadium2d` For shapes that have more complicated geometric representations, such as an arrow with a label, the `Group2d` can accept other primitives as its children. ## Hit testing Previously, we did all hit testing via events set on shapes and other elements. In this PR, I've replaced those hit tests with our own calculation for hit tests in JavaScript. This removed the need for many DOM elements, such as hit test area borders and fills which only existed to trigger pointer events. ## Selection We now support selecting "hollow" shapes by clicking inside of them. This involves a lot of new logic but it should work intuitively. See `Editor.getShapeAtPoint` for the (thoroughly commented) implementation. ![Kapture 2023-07-23 at 23 27 27](https://github.com/tldraw/tldraw/assets/23072548/a743275c-acdb-42d9-a3fe-b3e20dce86b6) every sunset is actually the sun hiding in fear and respect of tldraw's quality of interactions This PR also fixes several bugs with scribble selection, in particular around the shift key modifier. ![Kapture 2023-07-24 at 23 34 07](https://github.com/tldraw/tldraw/assets/23072548/871d67d0-8d06-42ae-a2b2-021effba37c5) ...as well as issues with labels and editing. There are **over 100 new tests** for selection covering groups, frames, brushing, scribbling, hovering, and editing. I'll add a few more before I feel comfortable merging this PR. ## Arrow binding Using the same "hollow shape" logic as selection, arrow binding is significantly improved. ![Kapture 2023-07-22 at 07 46 25](https://github.com/tldraw/tldraw/assets/23072548/5aa724b3-b57d-4fb7-92d0-80e34246753c) a thousand wise men could not improve on this ## Moving focus between editing shapes Previously, this was handled in the `editing_shapes` state. This is moved to `useEditableText`, and should generally be considered an advanced implementation detail on a shape-by-shape basis. This addresses a bug that I'd never noticed before, but which can be reproduced by selecting an shape—but not focusing its input—while editing a different shape. Previously, the new shape became the editing shape but its input did not focus. ![Kapture 2023-07-23 at 23 19 09](https://github.com/tldraw/tldraw/assets/23072548/a5e157fb-24a8-42bd-a692-04ce769b1a9c) In this PR, you can select a shape by clicking on its edge or body, or select its input to transfer editing / focus. ![Kapture 2023-07-23 at 23 22 21](https://github.com/tldraw/tldraw/assets/23072548/7384e7ea-9777-4e1a-8f63-15de2166a53a) tldraw, glorious tldraw ### Change Type - [x] `major` — Breaking change ### Test Plan 1. Erase shapes 2. Select shapes 3. Calculate their bounding boxes - [ ] Unit Tests // todo - [ ] End to end tests // todo ### Release Notes - [editor] Remove `ShapeUtil.getBounds`, `ShapeUtil.getOutline`, `ShapeUtil.hitTestPoint`, `ShapeUtil.hitTestLineSegment` - [editor] Add `ShapeUtil.getGeometry` - [editor] Add `Editor.getShapeGeometry`
2023-07-25 16:10:15 +00:00
hoveredShapeId: null | TLShapeId;
2023-04-25 11:01:25 +00:00
// (undocumented)
meta: JsonObject;
// (undocumented)
pageId: RecordId<TLPage>;
2023-04-25 11:01:25 +00:00
// (undocumented)
`ShapeUtil.getGeometry`, selection rewrite (#1751) This PR is a significant rewrite of our selection / hit testing logic. It - replaces our current geometric helpers (`getBounds`, `getOutline`, `hitTestPoint`, and `hitTestLineSegment`) with a new geometry API - moves our hit testing entirely to JS using geometry - improves selection logic, especially around editing shapes, groups and frames - fixes many minor selection bugs (e.g. shapes behind frames) - removes hit-testing DOM elements from ShapeFill etc. - adds many new tests around selection - adds new tests around selection - makes several superficial changes to surface editor APIs This PR is hard to evaluate. The `selection-omnibus` test suite is intended to describe all of the selection behavior, however all existing tests are also either here preserved and passing or (in a few cases around editing shapes) are modified to reflect the new behavior. ## Geometry All `ShapeUtils` implement `getGeometry`, which returns a single geometry primitive (`Geometry2d`). For example: ```ts class BoxyShapeUtil { getGeometry(shape: BoxyShape) { return new Rectangle2d({ width: shape.props.width, height: shape.props.height, isFilled: true, margin: shape.props.strokeWidth }) } } ``` This geometric primitive is used for all bounds calculation, hit testing, intersection with arrows, etc. There are several geometric primitives that extend `Geometry2d`: - `Arc2d` - `Circle2d` - `CubicBezier2d` - `CubicSpline2d` - `Edge2d` - `Ellipse2d` - `Group2d` - `Polygon2d` - `Rectangle2d` - `Stadium2d` For shapes that have more complicated geometric representations, such as an arrow with a label, the `Group2d` can accept other primitives as its children. ## Hit testing Previously, we did all hit testing via events set on shapes and other elements. In this PR, I've replaced those hit tests with our own calculation for hit tests in JavaScript. This removed the need for many DOM elements, such as hit test area borders and fills which only existed to trigger pointer events. ## Selection We now support selecting "hollow" shapes by clicking inside of them. This involves a lot of new logic but it should work intuitively. See `Editor.getShapeAtPoint` for the (thoroughly commented) implementation. ![Kapture 2023-07-23 at 23 27 27](https://github.com/tldraw/tldraw/assets/23072548/a743275c-acdb-42d9-a3fe-b3e20dce86b6) every sunset is actually the sun hiding in fear and respect of tldraw's quality of interactions This PR also fixes several bugs with scribble selection, in particular around the shift key modifier. ![Kapture 2023-07-24 at 23 34 07](https://github.com/tldraw/tldraw/assets/23072548/871d67d0-8d06-42ae-a2b2-021effba37c5) ...as well as issues with labels and editing. There are **over 100 new tests** for selection covering groups, frames, brushing, scribbling, hovering, and editing. I'll add a few more before I feel comfortable merging this PR. ## Arrow binding Using the same "hollow shape" logic as selection, arrow binding is significantly improved. ![Kapture 2023-07-22 at 07 46 25](https://github.com/tldraw/tldraw/assets/23072548/5aa724b3-b57d-4fb7-92d0-80e34246753c) a thousand wise men could not improve on this ## Moving focus between editing shapes Previously, this was handled in the `editing_shapes` state. This is moved to `useEditableText`, and should generally be considered an advanced implementation detail on a shape-by-shape basis. This addresses a bug that I'd never noticed before, but which can be reproduced by selecting an shape—but not focusing its input—while editing a different shape. Previously, the new shape became the editing shape but its input did not focus. ![Kapture 2023-07-23 at 23 19 09](https://github.com/tldraw/tldraw/assets/23072548/a5e157fb-24a8-42bd-a692-04ce769b1a9c) In this PR, you can select a shape by clicking on its edge or body, or select its input to transfer editing / focus. ![Kapture 2023-07-23 at 23 22 21](https://github.com/tldraw/tldraw/assets/23072548/7384e7ea-9777-4e1a-8f63-15de2166a53a) tldraw, glorious tldraw ### Change Type - [x] `major` — Breaking change ### Test Plan 1. Erase shapes 2. Select shapes 3. Calculate their bounding boxes - [ ] Unit Tests // todo - [ ] End to end tests // todo ### Release Notes - [editor] Remove `ShapeUtil.getBounds`, `ShapeUtil.getOutline`, `ShapeUtil.hitTestPoint`, `ShapeUtil.hitTestLineSegment` - [editor] Add `ShapeUtil.getGeometry` - [editor] Add `Editor.getShapeGeometry`
2023-07-25 16:10:15 +00:00
selectedShapeIds: TLShapeId[];
2023-04-25 11:01:25 +00:00
}
derived presence state (#1204) This PR adds - A new `TLInstancePresence` record type, to collect info about the presence state in a particular instance of the editor. This will eventually be used to sync presence data instead of sending instance-only state across the wire. - **Record Scopes** `RecordType` now has a `scope` property which can be one of three things: - `document`: the record belongs to the document and should be synced and persisted freely. Currently: `TLDocument`, `TLPage`, `TLShape`, and `TLAsset` - `instance`: the record belongs to a single instance of the store and should not be synced at all. It should not be persisted directly in most cases, but rather compiled into a kind of 'instance configuration' to store alongside the local document data so that when reopening the associated document it can remember some of the previous instance state. Currently: `TLInstance`, `TLInstancePageState`, `TLCamera`, `TLUser`, `TLUserDocument`, `TLUserPresence` - `presence`: the record belongs to a single instance of the store and should not be persisted, but may be synced using the special presence sync protocol. Currently just `TLInstancePresence` This sets us up for the following changes, which are gonna be pretty high-impact in terms of integrating tldraw into existing systems: - Removing `instanceId` as a config option. Each instance gets a randomly generated ID. - We'd replace it with an `instanceConfig` option that has stuff like selectedIds, camera positions, and so on. Then it's up to library users to get and reinstate the instance config at persistence boundaries. - Removing `userId` as config option, and removing the `TLUser` type altogether. - We might need to revisit when doing auth-enabled features like locking shapes, but I suspect that will be separate.
2023-04-27 18:03:19 +00:00
// @public (undocumented)
export interface TLInstancePresence extends BaseRecord<'instance_presence', TLInstancePresenceID> {
derived presence state (#1204) This PR adds - A new `TLInstancePresence` record type, to collect info about the presence state in a particular instance of the editor. This will eventually be used to sync presence data instead of sending instance-only state across the wire. - **Record Scopes** `RecordType` now has a `scope` property which can be one of three things: - `document`: the record belongs to the document and should be synced and persisted freely. Currently: `TLDocument`, `TLPage`, `TLShape`, and `TLAsset` - `instance`: the record belongs to a single instance of the store and should not be synced at all. It should not be persisted directly in most cases, but rather compiled into a kind of 'instance configuration' to store alongside the local document data so that when reopening the associated document it can remember some of the previous instance state. Currently: `TLInstance`, `TLInstancePageState`, `TLCamera`, `TLUser`, `TLUserDocument`, `TLUserPresence` - `presence`: the record belongs to a single instance of the store and should not be persisted, but may be synced using the special presence sync protocol. Currently just `TLInstancePresence` This sets us up for the following changes, which are gonna be pretty high-impact in terms of integrating tldraw into existing systems: - Removing `instanceId` as a config option. Each instance gets a randomly generated ID. - We'd replace it with an `instanceConfig` option that has stuff like selectedIds, camera positions, and so on. Then it's up to library users to get and reinstate the instance config at persistence boundaries. - Removing `userId` as config option, and removing the `TLUser` type altogether. - We might need to revisit when doing auth-enabled features like locking shapes, but I suspect that will be separate.
2023-04-27 18:03:19 +00:00
// (undocumented)
brush: BoxModel | null;
derived presence state (#1204) This PR adds - A new `TLInstancePresence` record type, to collect info about the presence state in a particular instance of the editor. This will eventually be used to sync presence data instead of sending instance-only state across the wire. - **Record Scopes** `RecordType` now has a `scope` property which can be one of three things: - `document`: the record belongs to the document and should be synced and persisted freely. Currently: `TLDocument`, `TLPage`, `TLShape`, and `TLAsset` - `instance`: the record belongs to a single instance of the store and should not be synced at all. It should not be persisted directly in most cases, but rather compiled into a kind of 'instance configuration' to store alongside the local document data so that when reopening the associated document it can remember some of the previous instance state. Currently: `TLInstance`, `TLInstancePageState`, `TLCamera`, `TLUser`, `TLUserDocument`, `TLUserPresence` - `presence`: the record belongs to a single instance of the store and should not be persisted, but may be synced using the special presence sync protocol. Currently just `TLInstancePresence` This sets us up for the following changes, which are gonna be pretty high-impact in terms of integrating tldraw into existing systems: - Removing `instanceId` as a config option. Each instance gets a randomly generated ID. - We'd replace it with an `instanceConfig` option that has stuff like selectedIds, camera positions, and so on. Then it's up to library users to get and reinstate the instance config at persistence boundaries. - Removing `userId` as config option, and removing the `TLUser` type altogether. - We might need to revisit when doing auth-enabled features like locking shapes, but I suspect that will be separate.
2023-04-27 18:03:19 +00:00
// (undocumented)
camera: {
x: number;
y: number;
z: number;
};
// (undocumented)
(1/2) Cursor Chat - Presence (#1487) This PR adds support for seeing **another user**'s chat messages. It's part 1 of two PRs relating to Cursor Chat. And it's needed for the much bigger part 2: https://github.com/tldraw/brivate/pull/1981 # Presence You can see another person's chat messages! ![2023-06-02 at 17 42 33 - Blush Capybara](https://github.com/tldraw/tldraw/assets/15892272/8f3efb5f-9c05-459c-aa7e-24842be75e58) If they have a name, it gets popped on top. ![2023-06-02 at 17 45 34 - Sapphire Meerkat](https://github.com/tldraw/tldraw/assets/15892272/749bd924-c1f5-419b-a028-1fafe1b61292) That's it! With this PR, there's no way of actually *typing* your chat messages. That comes with the [next one](https://github.com/tldraw/brivate/pull/1981)! # Admin ### To-do - [x] Store chat message - [x] Allow overflowing chat - [x] Presence for chat message - [x] Display chat message to others ### Change Type - [x] `minor` — New Feature ### Test Plan To test this, I recommend checking out both `lu/cursor-chat` branches, and opening two browser sessions in the same shared project. 1. In one session, type some cursor chat by pressing the Enter key while on the canvas (and typing). 2. On the other session, check that you can see the chat message appear. 3. Repeat this while being both named, and unnamed. I recommend just focusing on the visible presense in this PR. The [other PR](https://github.com/tldraw/brivate/pull/1981) is where we can focus about how we _input_ the cursor chat. ### Release Notes - [dev] Added support for cursor chat presence. --------- Co-authored-by: Steve Ruiz <steveruizok@gmail.com>
2023-06-15 15:10:08 +00:00
chatMessage: string;
// (undocumented)
derived presence state (#1204) This PR adds - A new `TLInstancePresence` record type, to collect info about the presence state in a particular instance of the editor. This will eventually be used to sync presence data instead of sending instance-only state across the wire. - **Record Scopes** `RecordType` now has a `scope` property which can be one of three things: - `document`: the record belongs to the document and should be synced and persisted freely. Currently: `TLDocument`, `TLPage`, `TLShape`, and `TLAsset` - `instance`: the record belongs to a single instance of the store and should not be synced at all. It should not be persisted directly in most cases, but rather compiled into a kind of 'instance configuration' to store alongside the local document data so that when reopening the associated document it can remember some of the previous instance state. Currently: `TLInstance`, `TLInstancePageState`, `TLCamera`, `TLUser`, `TLUserDocument`, `TLUserPresence` - `presence`: the record belongs to a single instance of the store and should not be persisted, but may be synced using the special presence sync protocol. Currently just `TLInstancePresence` This sets us up for the following changes, which are gonna be pretty high-impact in terms of integrating tldraw into existing systems: - Removing `instanceId` as a config option. Each instance gets a randomly generated ID. - We'd replace it with an `instanceConfig` option that has stuff like selectedIds, camera positions, and so on. Then it's up to library users to get and reinstate the instance config at persistence boundaries. - Removing `userId` as config option, and removing the `TLUser` type altogether. - We might need to revisit when doing auth-enabled features like locking shapes, but I suspect that will be separate.
2023-04-27 18:03:19 +00:00
color: string;
// (undocumented)
currentPageId: TLPageId;
// (undocumented)
cursor: {
x: number;
y: number;
type: TLCursor['type'];
rotation: number;
};
// (undocumented)
followingUserId: null | string;
derived presence state (#1204) This PR adds - A new `TLInstancePresence` record type, to collect info about the presence state in a particular instance of the editor. This will eventually be used to sync presence data instead of sending instance-only state across the wire. - **Record Scopes** `RecordType` now has a `scope` property which can be one of three things: - `document`: the record belongs to the document and should be synced and persisted freely. Currently: `TLDocument`, `TLPage`, `TLShape`, and `TLAsset` - `instance`: the record belongs to a single instance of the store and should not be synced at all. It should not be persisted directly in most cases, but rather compiled into a kind of 'instance configuration' to store alongside the local document data so that when reopening the associated document it can remember some of the previous instance state. Currently: `TLInstance`, `TLInstancePageState`, `TLCamera`, `TLUser`, `TLUserDocument`, `TLUserPresence` - `presence`: the record belongs to a single instance of the store and should not be persisted, but may be synced using the special presence sync protocol. Currently just `TLInstancePresence` This sets us up for the following changes, which are gonna be pretty high-impact in terms of integrating tldraw into existing systems: - Removing `instanceId` as a config option. Each instance gets a randomly generated ID. - We'd replace it with an `instanceConfig` option that has stuff like selectedIds, camera positions, and so on. Then it's up to library users to get and reinstate the instance config at persistence boundaries. - Removing `userId` as config option, and removing the `TLUser` type altogether. - We might need to revisit when doing auth-enabled features like locking shapes, but I suspect that will be separate.
2023-04-27 18:03:19 +00:00
// (undocumented)
lastActivityTimestamp: number;
// (undocumented)
meta: JsonObject;
// (undocumented)
screenBounds: BoxModel;
derived presence state (#1204) This PR adds - A new `TLInstancePresence` record type, to collect info about the presence state in a particular instance of the editor. This will eventually be used to sync presence data instead of sending instance-only state across the wire. - **Record Scopes** `RecordType` now has a `scope` property which can be one of three things: - `document`: the record belongs to the document and should be synced and persisted freely. Currently: `TLDocument`, `TLPage`, `TLShape`, and `TLAsset` - `instance`: the record belongs to a single instance of the store and should not be synced at all. It should not be persisted directly in most cases, but rather compiled into a kind of 'instance configuration' to store alongside the local document data so that when reopening the associated document it can remember some of the previous instance state. Currently: `TLInstance`, `TLInstancePageState`, `TLCamera`, `TLUser`, `TLUserDocument`, `TLUserPresence` - `presence`: the record belongs to a single instance of the store and should not be persisted, but may be synced using the special presence sync protocol. Currently just `TLInstancePresence` This sets us up for the following changes, which are gonna be pretty high-impact in terms of integrating tldraw into existing systems: - Removing `instanceId` as a config option. Each instance gets a randomly generated ID. - We'd replace it with an `instanceConfig` option that has stuff like selectedIds, camera positions, and so on. Then it's up to library users to get and reinstate the instance config at persistence boundaries. - Removing `userId` as config option, and removing the `TLUser` type altogether. - We might need to revisit when doing auth-enabled features like locking shapes, but I suspect that will be separate.
2023-04-27 18:03:19 +00:00
// (undocumented)
scribbles: TLScribble[];
derived presence state (#1204) This PR adds - A new `TLInstancePresence` record type, to collect info about the presence state in a particular instance of the editor. This will eventually be used to sync presence data instead of sending instance-only state across the wire. - **Record Scopes** `RecordType` now has a `scope` property which can be one of three things: - `document`: the record belongs to the document and should be synced and persisted freely. Currently: `TLDocument`, `TLPage`, `TLShape`, and `TLAsset` - `instance`: the record belongs to a single instance of the store and should not be synced at all. It should not be persisted directly in most cases, but rather compiled into a kind of 'instance configuration' to store alongside the local document data so that when reopening the associated document it can remember some of the previous instance state. Currently: `TLInstance`, `TLInstancePageState`, `TLCamera`, `TLUser`, `TLUserDocument`, `TLUserPresence` - `presence`: the record belongs to a single instance of the store and should not be persisted, but may be synced using the special presence sync protocol. Currently just `TLInstancePresence` This sets us up for the following changes, which are gonna be pretty high-impact in terms of integrating tldraw into existing systems: - Removing `instanceId` as a config option. Each instance gets a randomly generated ID. - We'd replace it with an `instanceConfig` option that has stuff like selectedIds, camera positions, and so on. Then it's up to library users to get and reinstate the instance config at persistence boundaries. - Removing `userId` as config option, and removing the `TLUser` type altogether. - We might need to revisit when doing auth-enabled features like locking shapes, but I suspect that will be separate.
2023-04-27 18:03:19 +00:00
// (undocumented)
`ShapeUtil.getGeometry`, selection rewrite (#1751) This PR is a significant rewrite of our selection / hit testing logic. It - replaces our current geometric helpers (`getBounds`, `getOutline`, `hitTestPoint`, and `hitTestLineSegment`) with a new geometry API - moves our hit testing entirely to JS using geometry - improves selection logic, especially around editing shapes, groups and frames - fixes many minor selection bugs (e.g. shapes behind frames) - removes hit-testing DOM elements from ShapeFill etc. - adds many new tests around selection - adds new tests around selection - makes several superficial changes to surface editor APIs This PR is hard to evaluate. The `selection-omnibus` test suite is intended to describe all of the selection behavior, however all existing tests are also either here preserved and passing or (in a few cases around editing shapes) are modified to reflect the new behavior. ## Geometry All `ShapeUtils` implement `getGeometry`, which returns a single geometry primitive (`Geometry2d`). For example: ```ts class BoxyShapeUtil { getGeometry(shape: BoxyShape) { return new Rectangle2d({ width: shape.props.width, height: shape.props.height, isFilled: true, margin: shape.props.strokeWidth }) } } ``` This geometric primitive is used for all bounds calculation, hit testing, intersection with arrows, etc. There are several geometric primitives that extend `Geometry2d`: - `Arc2d` - `Circle2d` - `CubicBezier2d` - `CubicSpline2d` - `Edge2d` - `Ellipse2d` - `Group2d` - `Polygon2d` - `Rectangle2d` - `Stadium2d` For shapes that have more complicated geometric representations, such as an arrow with a label, the `Group2d` can accept other primitives as its children. ## Hit testing Previously, we did all hit testing via events set on shapes and other elements. In this PR, I've replaced those hit tests with our own calculation for hit tests in JavaScript. This removed the need for many DOM elements, such as hit test area borders and fills which only existed to trigger pointer events. ## Selection We now support selecting "hollow" shapes by clicking inside of them. This involves a lot of new logic but it should work intuitively. See `Editor.getShapeAtPoint` for the (thoroughly commented) implementation. ![Kapture 2023-07-23 at 23 27 27](https://github.com/tldraw/tldraw/assets/23072548/a743275c-acdb-42d9-a3fe-b3e20dce86b6) every sunset is actually the sun hiding in fear and respect of tldraw's quality of interactions This PR also fixes several bugs with scribble selection, in particular around the shift key modifier. ![Kapture 2023-07-24 at 23 34 07](https://github.com/tldraw/tldraw/assets/23072548/871d67d0-8d06-42ae-a2b2-021effba37c5) ...as well as issues with labels and editing. There are **over 100 new tests** for selection covering groups, frames, brushing, scribbling, hovering, and editing. I'll add a few more before I feel comfortable merging this PR. ## Arrow binding Using the same "hollow shape" logic as selection, arrow binding is significantly improved. ![Kapture 2023-07-22 at 07 46 25](https://github.com/tldraw/tldraw/assets/23072548/5aa724b3-b57d-4fb7-92d0-80e34246753c) a thousand wise men could not improve on this ## Moving focus between editing shapes Previously, this was handled in the `editing_shapes` state. This is moved to `useEditableText`, and should generally be considered an advanced implementation detail on a shape-by-shape basis. This addresses a bug that I'd never noticed before, but which can be reproduced by selecting an shape—but not focusing its input—while editing a different shape. Previously, the new shape became the editing shape but its input did not focus. ![Kapture 2023-07-23 at 23 19 09](https://github.com/tldraw/tldraw/assets/23072548/a5e157fb-24a8-42bd-a692-04ce769b1a9c) In this PR, you can select a shape by clicking on its edge or body, or select its input to transfer editing / focus. ![Kapture 2023-07-23 at 23 22 21](https://github.com/tldraw/tldraw/assets/23072548/7384e7ea-9777-4e1a-8f63-15de2166a53a) tldraw, glorious tldraw ### Change Type - [x] `major` — Breaking change ### Test Plan 1. Erase shapes 2. Select shapes 3. Calculate their bounding boxes - [ ] Unit Tests // todo - [ ] End to end tests // todo ### Release Notes - [editor] Remove `ShapeUtil.getBounds`, `ShapeUtil.getOutline`, `ShapeUtil.hitTestPoint`, `ShapeUtil.hitTestLineSegment` - [editor] Add `ShapeUtil.getGeometry` - [editor] Add `Editor.getShapeGeometry`
2023-07-25 16:10:15 +00:00
selectedShapeIds: TLShapeId[];
derived presence state (#1204) This PR adds - A new `TLInstancePresence` record type, to collect info about the presence state in a particular instance of the editor. This will eventually be used to sync presence data instead of sending instance-only state across the wire. - **Record Scopes** `RecordType` now has a `scope` property which can be one of three things: - `document`: the record belongs to the document and should be synced and persisted freely. Currently: `TLDocument`, `TLPage`, `TLShape`, and `TLAsset` - `instance`: the record belongs to a single instance of the store and should not be synced at all. It should not be persisted directly in most cases, but rather compiled into a kind of 'instance configuration' to store alongside the local document data so that when reopening the associated document it can remember some of the previous instance state. Currently: `TLInstance`, `TLInstancePageState`, `TLCamera`, `TLUser`, `TLUserDocument`, `TLUserPresence` - `presence`: the record belongs to a single instance of the store and should not be persisted, but may be synced using the special presence sync protocol. Currently just `TLInstancePresence` This sets us up for the following changes, which are gonna be pretty high-impact in terms of integrating tldraw into existing systems: - Removing `instanceId` as a config option. Each instance gets a randomly generated ID. - We'd replace it with an `instanceConfig` option that has stuff like selectedIds, camera positions, and so on. Then it's up to library users to get and reinstate the instance config at persistence boundaries. - Removing `userId` as config option, and removing the `TLUser` type altogether. - We might need to revisit when doing auth-enabled features like locking shapes, but I suspect that will be separate.
2023-04-27 18:03:19 +00:00
// (undocumented)
userId: string;
derived presence state (#1204) This PR adds - A new `TLInstancePresence` record type, to collect info about the presence state in a particular instance of the editor. This will eventually be used to sync presence data instead of sending instance-only state across the wire. - **Record Scopes** `RecordType` now has a `scope` property which can be one of three things: - `document`: the record belongs to the document and should be synced and persisted freely. Currently: `TLDocument`, `TLPage`, `TLShape`, and `TLAsset` - `instance`: the record belongs to a single instance of the store and should not be synced at all. It should not be persisted directly in most cases, but rather compiled into a kind of 'instance configuration' to store alongside the local document data so that when reopening the associated document it can remember some of the previous instance state. Currently: `TLInstance`, `TLInstancePageState`, `TLCamera`, `TLUser`, `TLUserDocument`, `TLUserPresence` - `presence`: the record belongs to a single instance of the store and should not be persisted, but may be synced using the special presence sync protocol. Currently just `TLInstancePresence` This sets us up for the following changes, which are gonna be pretty high-impact in terms of integrating tldraw into existing systems: - Removing `instanceId` as a config option. Each instance gets a randomly generated ID. - We'd replace it with an `instanceConfig` option that has stuff like selectedIds, camera positions, and so on. Then it's up to library users to get and reinstate the instance config at persistence boundaries. - Removing `userId` as config option, and removing the `TLUser` type altogether. - We might need to revisit when doing auth-enabled features like locking shapes, but I suspect that will be separate.
2023-04-27 18:03:19 +00:00
// (undocumented)
userName: string;
}
2023-04-25 11:01:25 +00:00
// @public (undocumented)
export type TLLanguage = (typeof LANGUAGES)[number];
2023-04-25 11:01:25 +00:00
// @public (undocumented)
export type TLLineShape = TLBaseShape<'line', TLLineShapeProps>;
2023-04-25 11:01:25 +00:00
// @public (undocumented)
export type TLNoteShape = TLBaseShape<'note', TLNoteShapeProps>;
// @public (undocumented)
export type TLOpacityType = number;
2023-04-25 11:01:25 +00:00
// @public
export interface TLPage extends BaseRecord<'page', TLPageId> {
2023-04-25 11:01:25 +00:00
// (undocumented)
index: string;
// (undocumented)
meta: JsonObject;
// (undocumented)
2023-04-25 11:01:25 +00:00
name: string;
}
// @public (undocumented)
export type TLPageId = RecordId<TLPage>;
2023-04-25 11:01:25 +00:00
// @public (undocumented)
export type TLParentId = TLPageId | TLShapeId;
// @public (undocumented)
export const TLPOINTER_ID: TLPointerId;
2023-04-25 11:01:25 +00:00
// @public (undocumented)
Independent instance state persistence (#1493) This PR - Removes UserDocumentRecordType - moving isSnapMode to user preferences - moving isGridMode and isPenMode to InstanceRecordType - deleting the other properties which are no longer needed. - Creates a separate pipeline for persisting instance state. Previously the instance state records were stored alongside the document state records, and in order to load the state for a particular instance (in our case, a particular tab) you needed to pass the 'instanceId' prop. This prop ended up totally pervading the public API and people ran into all kinds of issues with it, e.g. using the same instance id in multiple editor instances. There was also an issue whereby it was hard for us to clean up old instance state so the idb table ended up bloating over time. This PR makes it so that rather than passing an instanceId, you load the instance state yourself while creating the store. It provides tools to make that easy. - Undoes the assumption that we might have more than one instance's state in the store. - Like `document`, `instance` now has a singleton id `instance:instance`. - Page state ids and camera ids are no longer random, but rather derive from the page they belong to. This is like having a foreign primary key in SQL databases. It's something i'd love to support fully as part of the RecordType/Store api. Tests to do - [x] Test Migrations - [x] Test Store.listen filtering - [x] Make type sets in Store public and readonly - [x] Test RecordType.createId - [x] Test Instance state snapshot loading/exporting - [x] Manual test File I/O - [x] Manual test Vscode extension with multiple tabs - [x] Audit usages of store.query - [x] Audit usages of changed types: InstanceRecordType, 'instance', InstancePageStateRecordType, 'instance_page_state', 'user_document', 'camera', CameraRecordType, InstancePresenceRecordType, 'instance_presence' - [x] Test user preferences - [x] Manual test isSnapMode and isGridMode and isPenMode - [ ] Test indexedDb functions - [x] Add instanceId stuff back ### Change Type - [x] `major` — Breaking Change ### Test Plan 1. Add a step-by-step description of how to test your PR here. 2. - [ ] Unit Tests - [ ] Webdriver tests ### Release Notes - Add a brief release note for your PR here.
2023-06-05 14:11:07 +00:00
export type TLRecord = TLAsset | TLCamera | TLDocument | TLInstance | TLInstancePageState | TLInstancePresence | TLPage | TLPointer | TLShape;
2023-04-25 11:01:25 +00:00
// @public (undocumented)
export type TLSchema = StoreSchema<TLRecord, TLStoreProps>;
// @public
2023-04-25 11:01:25 +00:00
export type TLScribble = {
id: string;
points: VecModel[];
2023-04-25 11:01:25 +00:00
size: number;
color: TLCanvasUiColor;
2023-04-25 11:01:25 +00:00
opacity: number;
state: SetValue<typeof TL_SCRIBBLE_STATES>;
delay: number;
shrink: number;
taper: boolean;
2023-04-25 11:01:25 +00:00
};
// @public (undocumented)
export type TLSerializedStore = SerializedStore<TLRecord>;
2023-04-25 11:01:25 +00:00
// @public
export type TLShape = TLDefaultShape | TLUnknownShape;
2023-04-25 11:01:25 +00:00
// @public (undocumented)
export type TLShapeId = RecordId<TLUnknownShape>;
2023-04-25 11:01:25 +00:00
// @public (undocumented)
export type TLShapePartial<T extends TLShape = TLShape> = T extends T ? {
id: TLShapeId;
type: T['type'];
props?: Partial<T['props']>;
meta?: Partial<T['meta']>;
} & Partial<Omit<T, 'id' | 'meta' | 'props' | 'type'>> : never;
2023-04-25 11:01:25 +00:00
// @public (undocumented)
export type TLShapeProp = keyof TLShapeProps;
// @public (undocumented)
export type TLShapeProps = Identity<UnionToIntersection<TLDefaultShape['props']>>;
2023-04-25 11:01:25 +00:00
// @public (undocumented)
export type TLStore = Store<TLRecord, TLStoreProps>;
// @public (undocumented)
export type TLStoreProps = {
Add support for project names (#1340) This PR adds some things that we need for the Project Name feature on tldraw.com. It should be reviewed alongside https://github.com/tldraw/tldraw-lite/pull/1814 ## Name Property This PR adds a `name` property to `TLDocument`. We use this to store a project's name. <img width="454" alt="Screenshot 2023-05-09 at 15 47 26" src="https://github.com/tldraw/tldraw/assets/15892272/f3be438e-aa0f-4dec-8f51-8dfd9f9d0ced"> ## Top Zone This PR adds a `topZone` area of the UI that we can add stuff to, similar to how `shareZone` works. It also adds an example to show where the `topZone` and `shareZone` are: <img width="1511" alt="Screenshot 2023-05-12 at 10 57 40" src="https://github.com/tldraw/tldraw/assets/15892272/f5e1cd33-017e-4aaf-bfee-4d85119e2974"> ## Breakpoints This PR change's the UI's breakpoints a little bit. It moves the action bar to the bottom a little bit earlier. (This gives us more space at the top for the project name). ![2023-05-12 at 11 08 26 - Fuchsia Bison](https://github.com/tldraw/tldraw/assets/15892272/34563cea-b1d1-47be-ac5e-5650ee0ba02d) ![2023-05-12 at 13 45 04 - Tan Mole](https://github.com/tldraw/tldraw/assets/15892272/ab190bd3-51d4-4a8b-88de-c72ab14bcba6) ## Input Blur This PR adds an `onBlur` parameter to `Input`. This was needed because 'clicking off' the input wasn't firing `onComplete` or `onCancel`. <img width="620" alt="Screenshot 2023-05-09 at 16 12 58" src="https://github.com/tldraw/tldraw/assets/15892272/3b28da74-0a74-4063-8053-e59e47027caf"> ## Create Project Name This PR adds an internal `createProjectName` property to `TldrawEditorConfig`. Similar to `derivePresenceState`, you can pass a custom function to it. It lets you control what gets used as the default project name. We use it to set different names in our local projects compared to shared projects. In the future, when we add more advanced project features, we could handle this better within the UI. <img width="454" alt="Screenshot 2023-05-09 at 15 47 26" src="https://github.com/tldraw/tldraw/assets/15892272/da9a4699-ac32-40d9-a97c-6c682acfac41"> ### Test Plan 1. Gradually reduce the width of the browser window. 2. Check that the actions menu jumps to the bottom before the style panel moves to the bottom. --- 1. In the examples app, open the `/zones` example. 2. Check that there's a 'top zone' at the top. - [ ] Unit Tests - [ ] Webdriver tests ### Release Note - [dev] Added a `topZone` area where you can put stuff. - [dev] Added a `name` property to `TLDocument` - and `app` methods for it. - [dev] Added an internal `createProjectName` config property for controlling the default project name. - [dev] Added an `onBlur` parameter to `Input`. - Moved the actions bar to the bottom on medium-sized screens. --------- Co-authored-by: Steve Ruiz <steveruizok@gmail.com>
2023-06-01 18:46:26 +00:00
defaultName: string;
2023-04-25 11:01:25 +00:00
};
// @public (undocumented)
export type TLStoreSchema = StoreSchema<TLRecord, TLStoreProps>;
// @public (undocumented)
export type TLStoreSnapshot = StoreSnapshot<TLRecord>;
2023-04-25 11:01:25 +00:00
// @public (undocumented)
export type TLTextShape = TLBaseShape<'text', TLTextShapeProps>;
// @public (undocumented)
export type TLTextShapeProps = ShapePropsType<typeof textShapeProps>;
2023-04-25 11:01:25 +00:00
// @public
2023-04-25 11:01:25 +00:00
export type TLUnknownShape = TLBaseShape<string, object>;
// @public
2023-04-25 11:01:25 +00:00
export type TLVideoAsset = TLBaseAsset<'video', {
w: number;
h: number;
name: string;
isAnimated: boolean;
mimeType: null | string;
src: null | string;
}>;
// @public (undocumented)
export type TLVideoShape = TLBaseShape<'video', TLVideoShapeProps>;
// @public
export interface VecModel {
2023-04-25 11:01:25 +00:00
// (undocumented)
x: number;
// (undocumented)
y: number;
// (undocumented)
z?: number;
}
// @public (undocumented)
export const vecModelValidator: T.Validator<VecModel>;
2023-04-25 11:01:25 +00:00
// @internal (undocumented)
export const videoShapeMigrations: Migrations;
// @public (undocumented)
export const videoShapeProps: {
w: T.Validator<number>;
h: T.Validator<number>;
time: T.Validator<number>;
playing: T.Validator<boolean>;
url: T.Validator<string>;
assetId: T.Validator<TLAssetId | null>;
};
2023-04-25 11:01:25 +00:00
// (No @packageDocumentation comment for this package)
```