Replace Atom.value with Atom.get() (#2189)
This PR replaces the `.value` getter for the atom with `.get()` ### Change Type - [x] `major` — Breaking change --------- Co-authored-by: David Sheldrick <d.j.sheldrick@gmail.com>
This commit is contained in:
parent
260a31db81
commit
5db3c1553e
131 changed files with 1388 additions and 929 deletions
|
@ -10,4 +10,5 @@ fi
|
|||
|
||||
npx lazy run build-api
|
||||
git add packages/*/api-report.md
|
||||
git add packages/*/api/api.json
|
||||
npx lint-staged
|
||||
|
|
|
@ -1,247 +1,249 @@
|
|||
import test, { Page, expect } from '@playwright/test'
|
||||
import { Editor, TLShapeId, TLShapePartial } from '@tldraw/tldraw'
|
||||
import assert from 'assert'
|
||||
import { rename, writeFile } from 'fs/promises'
|
||||
import { setupPage } from '../shared-e2e'
|
||||
export {}
|
||||
|
||||
declare const editor: Editor
|
||||
// import test, { Page, expect } from '@playwright/test'
|
||||
// import { Editor, TLShapeId, TLShapePartial } from '@tldraw/tldraw'
|
||||
// import assert from 'assert'
|
||||
// import { rename, writeFile } from 'fs/promises'
|
||||
// import { setupPage } from '../shared-e2e'
|
||||
|
||||
test.describe('Export snapshots', () => {
|
||||
const snapshots = {
|
||||
'Exports geo text with leading line breaks': [
|
||||
{
|
||||
id: 'shape:testShape' as TLShapeId,
|
||||
type: 'geo',
|
||||
props: {
|
||||
w: 100,
|
||||
h: 30,
|
||||
text: '\n\n\n\n\n\ntext',
|
||||
},
|
||||
},
|
||||
],
|
||||
'Exports geo text with trailing line breaks': [
|
||||
{
|
||||
id: 'shape:testShape' as TLShapeId,
|
||||
type: 'geo',
|
||||
props: {
|
||||
w: 100,
|
||||
h: 30,
|
||||
text: 'text\n\n\n\n\n\n',
|
||||
},
|
||||
},
|
||||
],
|
||||
} as Record<string, TLShapePartial[]>
|
||||
// declare const editor: Editor
|
||||
|
||||
for (const fill of ['none', 'semi', 'solid', 'pattern']) {
|
||||
snapshots[`geo fill=${fill}`] = [
|
||||
{
|
||||
id: 'shape:testShape' as TLShapeId,
|
||||
type: 'geo',
|
||||
props: {
|
||||
fill,
|
||||
color: 'green',
|
||||
w: 100,
|
||||
h: 100,
|
||||
},
|
||||
},
|
||||
]
|
||||
// test.describe('Export snapshots', () => {
|
||||
// const snapshots = {
|
||||
// 'Exports geo text with leading line breaks': [
|
||||
// {
|
||||
// id: 'shape:testShape' as TLShapeId,
|
||||
// type: 'geo',
|
||||
// props: {
|
||||
// w: 100,
|
||||
// h: 30,
|
||||
// text: '\n\n\n\n\n\ntext',
|
||||
// },
|
||||
// },
|
||||
// ],
|
||||
// 'Exports geo text with trailing line breaks': [
|
||||
// {
|
||||
// id: 'shape:testShape' as TLShapeId,
|
||||
// type: 'geo',
|
||||
// props: {
|
||||
// w: 100,
|
||||
// h: 30,
|
||||
// text: 'text\n\n\n\n\n\n',
|
||||
// },
|
||||
// },
|
||||
// ],
|
||||
// } as Record<string, TLShapePartial[]>
|
||||
|
||||
snapshots[`arrow fill=${fill}`] = [
|
||||
{
|
||||
id: 'shape:testShape' as TLShapeId,
|
||||
type: 'arrow',
|
||||
props: {
|
||||
color: 'light-green',
|
||||
fill: fill,
|
||||
arrowheadStart: 'square',
|
||||
arrowheadEnd: 'dot',
|
||||
start: { type: 'point', x: 0, y: 0 },
|
||||
end: { type: 'point', x: 100, y: 100 },
|
||||
bend: 20,
|
||||
},
|
||||
},
|
||||
]
|
||||
// for (const fill of ['none', 'semi', 'solid', 'pattern']) {
|
||||
// snapshots[`geo fill=${fill}`] = [
|
||||
// {
|
||||
// id: 'shape:testShape' as TLShapeId,
|
||||
// type: 'geo',
|
||||
// props: {
|
||||
// fill,
|
||||
// color: 'green',
|
||||
// w: 100,
|
||||
// h: 100,
|
||||
// },
|
||||
// },
|
||||
// ]
|
||||
|
||||
snapshots[`draw fill=${fill}`] = [
|
||||
{
|
||||
id: 'shape:testShape' as TLShapeId,
|
||||
type: 'draw',
|
||||
props: {
|
||||
color: 'light-violet',
|
||||
fill: fill,
|
||||
segments: [
|
||||
{
|
||||
type: 'straight',
|
||||
points: [{ x: 0, y: 0 }],
|
||||
},
|
||||
{
|
||||
type: 'straight',
|
||||
points: [
|
||||
{ x: 0, y: 0 },
|
||||
{ x: 100, y: 0 },
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'straight',
|
||||
points: [
|
||||
{ x: 100, y: 0 },
|
||||
{ x: 0, y: 100 },
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'straight',
|
||||
points: [
|
||||
{ x: 0, y: 100 },
|
||||
{ x: 100, y: 100 },
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'straight',
|
||||
points: [
|
||||
{ x: 100, y: 100 },
|
||||
{ x: 0, y: 0 },
|
||||
],
|
||||
},
|
||||
],
|
||||
isClosed: true,
|
||||
isComplete: true,
|
||||
},
|
||||
},
|
||||
]
|
||||
}
|
||||
// snapshots[`arrow fill=${fill}`] = [
|
||||
// {
|
||||
// id: 'shape:testShape' as TLShapeId,
|
||||
// type: 'arrow',
|
||||
// props: {
|
||||
// color: 'light-green',
|
||||
// fill: fill,
|
||||
// arrowheadStart: 'square',
|
||||
// arrowheadEnd: 'dot',
|
||||
// start: { type: 'point', x: 0, y: 0 },
|
||||
// end: { type: 'point', x: 100, y: 100 },
|
||||
// bend: 20,
|
||||
// },
|
||||
// },
|
||||
// ]
|
||||
|
||||
for (const font of ['draw', 'sans', 'serif', 'mono']) {
|
||||
snapshots[`geo font=${font}`] = [
|
||||
{
|
||||
id: 'shape:testShape' as TLShapeId,
|
||||
type: 'geo',
|
||||
props: {
|
||||
text: 'test',
|
||||
color: 'blue',
|
||||
font,
|
||||
w: 100,
|
||||
h: 100,
|
||||
},
|
||||
},
|
||||
]
|
||||
// snapshots[`draw fill=${fill}`] = [
|
||||
// {
|
||||
// id: 'shape:testShape' as TLShapeId,
|
||||
// type: 'draw',
|
||||
// props: {
|
||||
// color: 'light-violet',
|
||||
// fill: fill,
|
||||
// segments: [
|
||||
// {
|
||||
// type: 'straight',
|
||||
// points: [{ x: 0, y: 0 }],
|
||||
// },
|
||||
// {
|
||||
// type: 'straight',
|
||||
// points: [
|
||||
// { x: 0, y: 0 },
|
||||
// { x: 100, y: 0 },
|
||||
// ],
|
||||
// },
|
||||
// {
|
||||
// type: 'straight',
|
||||
// points: [
|
||||
// { x: 100, y: 0 },
|
||||
// { x: 0, y: 100 },
|
||||
// ],
|
||||
// },
|
||||
// {
|
||||
// type: 'straight',
|
||||
// points: [
|
||||
// { x: 0, y: 100 },
|
||||
// { x: 100, y: 100 },
|
||||
// ],
|
||||
// },
|
||||
// {
|
||||
// type: 'straight',
|
||||
// points: [
|
||||
// { x: 100, y: 100 },
|
||||
// { x: 0, y: 0 },
|
||||
// ],
|
||||
// },
|
||||
// ],
|
||||
// isClosed: true,
|
||||
// isComplete: true,
|
||||
// },
|
||||
// },
|
||||
// ]
|
||||
// }
|
||||
|
||||
snapshots[`arrow font=${font}`] = [
|
||||
{
|
||||
id: 'shape:testShape' as TLShapeId,
|
||||
type: 'arrow',
|
||||
props: {
|
||||
color: 'blue',
|
||||
fill: 'solid',
|
||||
arrowheadStart: 'square',
|
||||
arrowheadEnd: 'arrow',
|
||||
font,
|
||||
start: { type: 'point', x: 0, y: 0 },
|
||||
end: { type: 'point', x: 100, y: 100 },
|
||||
bend: 20,
|
||||
text: 'test',
|
||||
},
|
||||
},
|
||||
]
|
||||
// for (const font of ['draw', 'sans', 'serif', 'mono']) {
|
||||
// snapshots[`geo font=${font}`] = [
|
||||
// {
|
||||
// id: 'shape:testShape' as TLShapeId,
|
||||
// type: 'geo',
|
||||
// props: {
|
||||
// text: 'test',
|
||||
// color: 'blue',
|
||||
// font,
|
||||
// w: 100,
|
||||
// h: 100,
|
||||
// },
|
||||
// },
|
||||
// ]
|
||||
|
||||
snapshots[`arrow font=${font}`] = [
|
||||
{
|
||||
id: 'shape:testShape' as TLShapeId,
|
||||
type: 'arrow',
|
||||
props: {
|
||||
color: 'blue',
|
||||
fill: 'solid',
|
||||
arrowheadStart: 'square',
|
||||
arrowheadEnd: 'arrow',
|
||||
font,
|
||||
start: { type: 'point', x: 0, y: 0 },
|
||||
end: { type: 'point', x: 100, y: 100 },
|
||||
bend: 20,
|
||||
text: 'test',
|
||||
},
|
||||
},
|
||||
]
|
||||
// snapshots[`arrow font=${font}`] = [
|
||||
// {
|
||||
// id: 'shape:testShape' as TLShapeId,
|
||||
// type: 'arrow',
|
||||
// props: {
|
||||
// color: 'blue',
|
||||
// fill: 'solid',
|
||||
// arrowheadStart: 'square',
|
||||
// arrowheadEnd: 'arrow',
|
||||
// font,
|
||||
// start: { type: 'point', x: 0, y: 0 },
|
||||
// end: { type: 'point', x: 100, y: 100 },
|
||||
// bend: 20,
|
||||
// text: 'test',
|
||||
// },
|
||||
// },
|
||||
// ]
|
||||
|
||||
snapshots[`note font=${font}`] = [
|
||||
{
|
||||
id: 'shape:testShape' as TLShapeId,
|
||||
type: 'note',
|
||||
props: {
|
||||
color: 'violet',
|
||||
font,
|
||||
text: 'test',
|
||||
},
|
||||
},
|
||||
]
|
||||
// snapshots[`arrow font=${font}`] = [
|
||||
// {
|
||||
// id: 'shape:testShape' as TLShapeId,
|
||||
// type: 'arrow',
|
||||
// props: {
|
||||
// color: 'blue',
|
||||
// fill: 'solid',
|
||||
// arrowheadStart: 'square',
|
||||
// arrowheadEnd: 'arrow',
|
||||
// font,
|
||||
// start: { type: 'point', x: 0, y: 0 },
|
||||
// end: { type: 'point', x: 100, y: 100 },
|
||||
// bend: 20,
|
||||
// text: 'test',
|
||||
// },
|
||||
// },
|
||||
// ]
|
||||
|
||||
snapshots[`text font=${font}`] = [
|
||||
{
|
||||
id: 'shape:testShape' as TLShapeId,
|
||||
type: 'text',
|
||||
props: {
|
||||
color: 'red',
|
||||
font,
|
||||
text: 'test',
|
||||
},
|
||||
},
|
||||
]
|
||||
}
|
||||
// snapshots[`note font=${font}`] = [
|
||||
// {
|
||||
// id: 'shape:testShape' as TLShapeId,
|
||||
// type: 'note',
|
||||
// props: {
|
||||
// color: 'violet',
|
||||
// font,
|
||||
// text: 'test',
|
||||
// },
|
||||
// },
|
||||
// ]
|
||||
|
||||
for (const [name, shapes] of Object.entries(snapshots)) {
|
||||
test(`Exports with ${name}`, async ({ browser }) => {
|
||||
const page = await browser.newPage()
|
||||
await setupPage(page)
|
||||
await page.evaluate((shapes) => {
|
||||
editor
|
||||
.updateInstanceState({ exportBackground: false })
|
||||
.selectAll()
|
||||
.deleteShapes(editor.selectedShapeIds)
|
||||
.createShapes(shapes)
|
||||
}, shapes as any)
|
||||
// snapshots[`text font=${font}`] = [
|
||||
// {
|
||||
// id: 'shape:testShape' as TLShapeId,
|
||||
// type: 'text',
|
||||
// props: {
|
||||
// color: 'red',
|
||||
// font,
|
||||
// text: 'test',
|
||||
// },
|
||||
// },
|
||||
// ]
|
||||
// }
|
||||
|
||||
await snapshotTest(page)
|
||||
})
|
||||
}
|
||||
// for (const [name, shapes] of Object.entries(snapshots)) {
|
||||
// test(`Exports with ${name}`, async ({ browser }) => {
|
||||
// const page = await browser.newPage()
|
||||
// await setupPage(page)
|
||||
// await page.evaluate((shapes) => {
|
||||
// editor
|
||||
// .updateInstanceState({ exportBackground: false })
|
||||
// .selectAll()
|
||||
// .deleteShapes(editor.selectedShapeIds)
|
||||
// .createShapes(shapes)
|
||||
// }, shapes as any)
|
||||
|
||||
for (const [name, shapes] of Object.entries(snapshots)) {
|
||||
test(`Exports with ${name} in dark mode`, async ({ browser }) => {
|
||||
const page = await browser.newPage()
|
||||
await setupPage(page)
|
||||
await page.evaluate((shapes) => {
|
||||
editor.user.updateUserPreferences({ isDarkMode: true })
|
||||
editor
|
||||
.updateInstanceState({ exportBackground: false })
|
||||
.selectAll()
|
||||
.deleteShapes(editor.selectedShapeIds)
|
||||
.createShapes(shapes)
|
||||
}, shapes as any)
|
||||
// await snapshotTest(page)
|
||||
// })
|
||||
// }
|
||||
|
||||
await snapshotTest(page)
|
||||
})
|
||||
}
|
||||
})
|
||||
// for (const [name, shapes] of Object.entries(snapshots)) {
|
||||
// test(`Exports with ${name} in dark mode`, async ({ browser }) => {
|
||||
// const page = await browser.newPage()
|
||||
// await setupPage(page)
|
||||
// await page.evaluate((shapes) => {
|
||||
// editor.user.updateUserPreferences({ isDarkMode: true })
|
||||
// editor
|
||||
// .updateInstanceState({ exportBackground: false })
|
||||
// .selectAll()
|
||||
// .deleteShapes(editor.selectedShapeIds)
|
||||
// .createShapes(shapes)
|
||||
// }, shapes as any)
|
||||
|
||||
async function snapshotTest(page: Page) {
|
||||
page.waitForEvent('download').then(async (download) => {
|
||||
const path = (await download.path()) as string
|
||||
assert(path)
|
||||
await rename(path, path + '.svg')
|
||||
await writeFile(
|
||||
path + '.html',
|
||||
`
|
||||
<!DOCTYPE html>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<img src="${path}.svg" />
|
||||
`,
|
||||
'utf-8'
|
||||
)
|
||||
// await snapshotTest(page)
|
||||
// })
|
||||
// }
|
||||
// })
|
||||
|
||||
await page.goto(`file://${path}.html`)
|
||||
const clip = await page.$eval('img', (img) => img.getBoundingClientRect())
|
||||
await expect(page).toHaveScreenshot({
|
||||
omitBackground: true,
|
||||
clip,
|
||||
})
|
||||
})
|
||||
await page.evaluate(() => (window as any)['tldraw-export']())
|
||||
}
|
||||
// async function snapshotTest(page: Page) {
|
||||
// page.waitForEvent('download').then(async (download) => {
|
||||
// const path = (await download.path()) as string
|
||||
// assert(path)
|
||||
// await rename(path, path + '.svg')
|
||||
// await writeFile(
|
||||
// path + '.html',
|
||||
// `
|
||||
// <!DOCTYPE html>
|
||||
// <meta charset="utf-8" />
|
||||
// <meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
// <img src="${path}.svg" />
|
||||
// `,
|
||||
// 'utf-8'
|
||||
// )
|
||||
|
||||
// await page.goto(`file://${path}.html`)
|
||||
// const clip = await page.$eval('img', (img) => img.getBoundingClientRect())
|
||||
// await expect(page).toHaveScreenshot({
|
||||
// omitBackground: true,
|
||||
// clip,
|
||||
// })
|
||||
// })
|
||||
// await page.evaluate(() => (window as any)['tldraw-export']())
|
||||
// }
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 2.1 KiB |
Binary file not shown.
After Width: | Height: | Size: 3.2 KiB |
Binary file not shown.
After Width: | Height: | Size: 2.1 KiB |
|
@ -43,9 +43,9 @@ test.describe('Focus', () => {
|
|||
({ id }) => {
|
||||
if (
|
||||
!(
|
||||
EDITOR_A.instanceState.isFocused === (id === 'A') &&
|
||||
EDITOR_B.instanceState.isFocused === (id === 'B') &&
|
||||
EDITOR_C.instanceState.isFocused === (id === 'C')
|
||||
EDITOR_A.getInstanceState().isFocused === (id === 'A') &&
|
||||
EDITOR_B.getInstanceState().isFocused === (id === 'B') &&
|
||||
EDITOR_C.getInstanceState().isFocused === (id === 'C')
|
||||
)
|
||||
) {
|
||||
throw Error('isFocused is not correct')
|
||||
|
|
|
@ -54,21 +54,21 @@ const CustomUi = track(() => {
|
|||
<div className="custom-toolbar">
|
||||
<button
|
||||
className="custom-button"
|
||||
data-isactive={editor.currentToolId === 'select'}
|
||||
data-isactive={editor.getCurrentToolId() === 'select'}
|
||||
onClick={() => editor.setCurrentTool('select')}
|
||||
>
|
||||
Select
|
||||
</button>
|
||||
<button
|
||||
className="custom-button"
|
||||
data-isactive={editor.currentToolId === 'draw'}
|
||||
data-isactive={editor.getCurrentToolId() === 'draw'}
|
||||
onClick={() => editor.setCurrentTool('draw')}
|
||||
>
|
||||
Pencil
|
||||
</button>
|
||||
<button
|
||||
className="custom-button"
|
||||
data-isactive={editor.currentToolId === 'eraser'}
|
||||
data-isactive={editor.getCurrentToolId() === 'eraser'}
|
||||
onClick={() => editor.setCurrentTool('eraser')}
|
||||
>
|
||||
Eraser
|
||||
|
|
|
@ -579,7 +579,9 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
get cameraState(): "idle" | "moving";
|
||||
cancel(): this;
|
||||
cancelDoubleClick(): void;
|
||||
// @deprecated (undocumented)
|
||||
get canRedo(): boolean;
|
||||
// @deprecated (undocumented)
|
||||
get canUndo(): boolean;
|
||||
// @internal (undocumented)
|
||||
capturedPointerId: null | number;
|
||||
|
@ -617,7 +619,9 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
get currentPageShapes(): TLShape[];
|
||||
get currentPageShapesSorted(): TLShape[];
|
||||
get currentPageState(): TLInstancePageState;
|
||||
// @deprecated (undocumented)
|
||||
get currentTool(): StateNode | undefined;
|
||||
// @deprecated (undocumented)
|
||||
get currentToolId(): string;
|
||||
deleteAssets(assets: TLAsset[] | TLAssetId[]): this;
|
||||
deleteOpenMenu(id: string): this;
|
||||
|
@ -633,6 +637,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
readonly disposables: Set<() => void>;
|
||||
dispose(): void;
|
||||
distributeShapes(shapes: TLShape[] | TLShapeId[], operation: 'horizontal' | 'vertical'): this;
|
||||
// @deprecated (undocumented)
|
||||
get documentSettings(): TLDocument;
|
||||
duplicatePage(page: TLPage | TLPageId, createId?: TLPageId): this;
|
||||
duplicateShapes(shapes: TLShape[] | TLShapeId[], offset?: VecLike): this;
|
||||
|
@ -670,11 +675,18 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
}[];
|
||||
getAsset(asset: TLAsset | TLAssetId): TLAsset | undefined;
|
||||
getAssetForExternalContent(info: TLExternalAssetContent): Promise<TLAsset | undefined>;
|
||||
getCanRedo(): boolean;
|
||||
getCanUndo(): boolean;
|
||||
getContainer: () => HTMLElement;
|
||||
getContentFromCurrentPage(shapes: TLShape[] | TLShapeId[]): TLContent | undefined;
|
||||
getCurrentTool(): StateNode | undefined;
|
||||
getCurrentToolId(): string;
|
||||
getDocumentSettings(): TLDocument;
|
||||
getDroppingOverShape(point: VecLike, droppingShapes?: TLShape[]): TLUnknownShape | undefined;
|
||||
getHighestIndexForParent(parent: TLPage | TLParentId | TLShape): string;
|
||||
getInitialMetaForShape(_shape: TLShape): JsonObject;
|
||||
getInstanceState(): TLInstance;
|
||||
getOpenMenus(): string[];
|
||||
getOutermostSelectableShape(shape: TLShape | TLShapeId, filter?: (shape: TLShape) => boolean): TLShape;
|
||||
getPage(page: TLPage | TLPageId): TLPage | undefined;
|
||||
getPageShapeIds(page: TLPage | TLPageId): Set<TLShapeId>;
|
||||
|
@ -752,6 +764,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
isPanning: boolean;
|
||||
pointerVelocity: Vec2d;
|
||||
};
|
||||
// @deprecated (undocumented)
|
||||
get instanceState(): TLInstance;
|
||||
interrupt(): this;
|
||||
isAncestorSelected(shape: TLShape | TLShapeId): boolean;
|
||||
|
@ -773,6 +786,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
moveShapesToPage(shapes: TLShape[] | TLShapeId[], pageId: TLPageId): this;
|
||||
nudgeShapes(shapes: TLShape[] | TLShapeId[], offset: VecLike, historyOptions?: TLCommandHistoryOptions): this;
|
||||
get onlySelectedShape(): null | TLShape;
|
||||
// @deprecated (undocumented)
|
||||
get openMenus(): string[];
|
||||
packShapes(shapes: TLShape[] | TLShapeId[], gap: number): this;
|
||||
get pages(): TLPage[];
|
||||
|
|
|
@ -7528,7 +7528,7 @@
|
|||
{
|
||||
"kind": "Property",
|
||||
"canonicalReference": "@tldraw/editor!Editor#canRedo:member",
|
||||
"docComment": "/**\n * Whether the app can redo.\n *\n * @public\n */\n",
|
||||
"docComment": "/**\n * @deprecated\n *\n * Use `getCanRedo` instead.\n */\n",
|
||||
"excerptTokens": [
|
||||
{
|
||||
"kind": "Content",
|
||||
|
@ -7558,7 +7558,7 @@
|
|||
{
|
||||
"kind": "Property",
|
||||
"canonicalReference": "@tldraw/editor!Editor#canUndo:member",
|
||||
"docComment": "/**\n * Whether the app can undo.\n *\n * @public\n */\n",
|
||||
"docComment": "/**\n * @deprecated\n *\n * Use `getCanUndo` instead.\n */\n",
|
||||
"excerptTokens": [
|
||||
{
|
||||
"kind": "Content",
|
||||
|
@ -8280,7 +8280,7 @@
|
|||
{
|
||||
"kind": "Property",
|
||||
"canonicalReference": "@tldraw/editor!Editor#currentTool:member",
|
||||
"docComment": "/**\n * The current selected tool.\n *\n * @public\n */\n",
|
||||
"docComment": "/**\n * @deprecated\n *\n * Use `getCurrentTool` instead.\n *\n * @public\n */\n",
|
||||
"excerptTokens": [
|
||||
{
|
||||
"kind": "Content",
|
||||
|
@ -8315,7 +8315,7 @@
|
|||
{
|
||||
"kind": "Property",
|
||||
"canonicalReference": "@tldraw/editor!Editor#currentToolId:member",
|
||||
"docComment": "/**\n * The id of the current selected tool.\n *\n * @public\n */\n",
|
||||
"docComment": "/**\n * @deprecated\n *\n * Use `getCurrentToolId` instead.\n */\n",
|
||||
"excerptTokens": [
|
||||
{
|
||||
"kind": "Content",
|
||||
|
@ -8962,7 +8962,7 @@
|
|||
{
|
||||
"kind": "Property",
|
||||
"canonicalReference": "@tldraw/editor!Editor#documentSettings:member",
|
||||
"docComment": "/**\n * The global document settings that apply to all users.\n *\n * @public\n */\n",
|
||||
"docComment": "/**\n * @deprecated\n *\n * Use `getDocumentSettings` instead.\n */\n",
|
||||
"excerptTokens": [
|
||||
{
|
||||
"kind": "Content",
|
||||
|
@ -9967,6 +9967,68 @@
|
|||
"isAbstract": false,
|
||||
"name": "getAssetForExternalContent"
|
||||
},
|
||||
{
|
||||
"kind": "Method",
|
||||
"canonicalReference": "@tldraw/editor!Editor#getCanRedo:member(1)",
|
||||
"docComment": "/**\n * Whether the app can redo.\n *\n * @public\n */\n",
|
||||
"excerptTokens": [
|
||||
{
|
||||
"kind": "Content",
|
||||
"text": "getCanRedo(): "
|
||||
},
|
||||
{
|
||||
"kind": "Content",
|
||||
"text": "boolean"
|
||||
},
|
||||
{
|
||||
"kind": "Content",
|
||||
"text": ";"
|
||||
}
|
||||
],
|
||||
"isStatic": false,
|
||||
"returnTypeTokenRange": {
|
||||
"startIndex": 1,
|
||||
"endIndex": 2
|
||||
},
|
||||
"releaseTag": "Public",
|
||||
"isProtected": false,
|
||||
"overloadIndex": 1,
|
||||
"parameters": [],
|
||||
"isOptional": false,
|
||||
"isAbstract": false,
|
||||
"name": "getCanRedo"
|
||||
},
|
||||
{
|
||||
"kind": "Method",
|
||||
"canonicalReference": "@tldraw/editor!Editor#getCanUndo:member(1)",
|
||||
"docComment": "/**\n * Whether the app can undo.\n *\n * @public\n */\n",
|
||||
"excerptTokens": [
|
||||
{
|
||||
"kind": "Content",
|
||||
"text": "getCanUndo(): "
|
||||
},
|
||||
{
|
||||
"kind": "Content",
|
||||
"text": "boolean"
|
||||
},
|
||||
{
|
||||
"kind": "Content",
|
||||
"text": ";"
|
||||
}
|
||||
],
|
||||
"isStatic": false,
|
||||
"returnTypeTokenRange": {
|
||||
"startIndex": 1,
|
||||
"endIndex": 2
|
||||
},
|
||||
"releaseTag": "Public",
|
||||
"isProtected": false,
|
||||
"overloadIndex": 1,
|
||||
"parameters": [],
|
||||
"isOptional": false,
|
||||
"isAbstract": false,
|
||||
"name": "getCanUndo"
|
||||
},
|
||||
{
|
||||
"kind": "Property",
|
||||
"canonicalReference": "@tldraw/editor!Editor#getContainer:member",
|
||||
|
@ -10069,6 +10131,105 @@
|
|||
"isAbstract": false,
|
||||
"name": "getContentFromCurrentPage"
|
||||
},
|
||||
{
|
||||
"kind": "Method",
|
||||
"canonicalReference": "@tldraw/editor!Editor#getCurrentTool:member(1)",
|
||||
"docComment": "/**\n * The current selected tool.\n *\n * @public\n */\n",
|
||||
"excerptTokens": [
|
||||
{
|
||||
"kind": "Content",
|
||||
"text": "getCurrentTool(): "
|
||||
},
|
||||
{
|
||||
"kind": "Reference",
|
||||
"text": "StateNode",
|
||||
"canonicalReference": "@tldraw/editor!StateNode:class"
|
||||
},
|
||||
{
|
||||
"kind": "Content",
|
||||
"text": " | undefined"
|
||||
},
|
||||
{
|
||||
"kind": "Content",
|
||||
"text": ";"
|
||||
}
|
||||
],
|
||||
"isStatic": false,
|
||||
"returnTypeTokenRange": {
|
||||
"startIndex": 1,
|
||||
"endIndex": 3
|
||||
},
|
||||
"releaseTag": "Public",
|
||||
"isProtected": false,
|
||||
"overloadIndex": 1,
|
||||
"parameters": [],
|
||||
"isOptional": false,
|
||||
"isAbstract": false,
|
||||
"name": "getCurrentTool"
|
||||
},
|
||||
{
|
||||
"kind": "Method",
|
||||
"canonicalReference": "@tldraw/editor!Editor#getCurrentToolId:member(1)",
|
||||
"docComment": "/**\n * The id of the current selected tool.\n *\n * @public\n */\n",
|
||||
"excerptTokens": [
|
||||
{
|
||||
"kind": "Content",
|
||||
"text": "getCurrentToolId(): "
|
||||
},
|
||||
{
|
||||
"kind": "Content",
|
||||
"text": "string"
|
||||
},
|
||||
{
|
||||
"kind": "Content",
|
||||
"text": ";"
|
||||
}
|
||||
],
|
||||
"isStatic": false,
|
||||
"returnTypeTokenRange": {
|
||||
"startIndex": 1,
|
||||
"endIndex": 2
|
||||
},
|
||||
"releaseTag": "Public",
|
||||
"isProtected": false,
|
||||
"overloadIndex": 1,
|
||||
"parameters": [],
|
||||
"isOptional": false,
|
||||
"isAbstract": false,
|
||||
"name": "getCurrentToolId"
|
||||
},
|
||||
{
|
||||
"kind": "Method",
|
||||
"canonicalReference": "@tldraw/editor!Editor#getDocumentSettings:member(1)",
|
||||
"docComment": "/**\n * The global document settings that apply to all users.\n *\n * @public\n */\n",
|
||||
"excerptTokens": [
|
||||
{
|
||||
"kind": "Content",
|
||||
"text": "getDocumentSettings(): "
|
||||
},
|
||||
{
|
||||
"kind": "Reference",
|
||||
"text": "TLDocument",
|
||||
"canonicalReference": "@tldraw/tlschema!TLDocument:interface"
|
||||
},
|
||||
{
|
||||
"kind": "Content",
|
||||
"text": ";"
|
||||
}
|
||||
],
|
||||
"isStatic": false,
|
||||
"returnTypeTokenRange": {
|
||||
"startIndex": 1,
|
||||
"endIndex": 2
|
||||
},
|
||||
"releaseTag": "Public",
|
||||
"isProtected": false,
|
||||
"overloadIndex": 1,
|
||||
"parameters": [],
|
||||
"isOptional": false,
|
||||
"isAbstract": false,
|
||||
"name": "getDocumentSettings"
|
||||
},
|
||||
{
|
||||
"kind": "Method",
|
||||
"canonicalReference": "@tldraw/editor!Editor#getDroppingOverShape:member(1)",
|
||||
|
@ -10261,6 +10422,69 @@
|
|||
"isAbstract": false,
|
||||
"name": "getInitialMetaForShape"
|
||||
},
|
||||
{
|
||||
"kind": "Method",
|
||||
"canonicalReference": "@tldraw/editor!Editor#getInstanceState:member(1)",
|
||||
"docComment": "/**\n * The current instance's state.\n *\n * @public\n */\n",
|
||||
"excerptTokens": [
|
||||
{
|
||||
"kind": "Content",
|
||||
"text": "getInstanceState(): "
|
||||
},
|
||||
{
|
||||
"kind": "Reference",
|
||||
"text": "TLInstance",
|
||||
"canonicalReference": "@tldraw/tlschema!TLInstance:interface"
|
||||
},
|
||||
{
|
||||
"kind": "Content",
|
||||
"text": ";"
|
||||
}
|
||||
],
|
||||
"isStatic": false,
|
||||
"returnTypeTokenRange": {
|
||||
"startIndex": 1,
|
||||
"endIndex": 2
|
||||
},
|
||||
"releaseTag": "Public",
|
||||
"isProtected": false,
|
||||
"overloadIndex": 1,
|
||||
"parameters": [],
|
||||
"isOptional": false,
|
||||
"isAbstract": false,
|
||||
"name": "getInstanceState"
|
||||
},
|
||||
{
|
||||
"kind": "Method",
|
||||
"canonicalReference": "@tldraw/editor!Editor#getOpenMenus:member(1)",
|
||||
"docComment": "/**\n * A set of strings representing any open menus. When menus are open, certain interactions will behave differently; for example, when a draw tool is selected and a menu is open, a pointer-down will not create a dot (because the user is probably trying to close the menu) however a pointer-down event followed by a drag will begin drawing a line (because the user is BOTH trying to close the menu AND start drawing a line).\n *\n * @public\n */\n",
|
||||
"excerptTokens": [
|
||||
{
|
||||
"kind": "Content",
|
||||
"text": "getOpenMenus(): "
|
||||
},
|
||||
{
|
||||
"kind": "Content",
|
||||
"text": "string[]"
|
||||
},
|
||||
{
|
||||
"kind": "Content",
|
||||
"text": ";"
|
||||
}
|
||||
],
|
||||
"isStatic": false,
|
||||
"returnTypeTokenRange": {
|
||||
"startIndex": 1,
|
||||
"endIndex": 2
|
||||
},
|
||||
"releaseTag": "Public",
|
||||
"isProtected": false,
|
||||
"overloadIndex": 1,
|
||||
"parameters": [],
|
||||
"isOptional": false,
|
||||
"isAbstract": false,
|
||||
"name": "getOpenMenus"
|
||||
},
|
||||
{
|
||||
"kind": "Method",
|
||||
"canonicalReference": "@tldraw/editor!Editor#getOutermostSelectableShape:member(1)",
|
||||
|
@ -12813,7 +13037,7 @@
|
|||
{
|
||||
"kind": "Property",
|
||||
"canonicalReference": "@tldraw/editor!Editor#instanceState:member",
|
||||
"docComment": "/**\n * The current instance's state.\n *\n * @public\n */\n",
|
||||
"docComment": "/**\n * @deprecated\n *\n * Use `getInstanceState` instead.\n */\n",
|
||||
"excerptTokens": [
|
||||
{
|
||||
"kind": "Content",
|
||||
|
@ -13801,7 +14025,7 @@
|
|||
{
|
||||
"kind": "Property",
|
||||
"canonicalReference": "@tldraw/editor!Editor#openMenus:member",
|
||||
"docComment": "/**\n * A set of strings representing any open menus. When menus are open, certain interactions will behave differently; for example, when a draw tool is selected and a menu is open, a pointer-down will not create a dot (because the user is probably trying to close the menu) however a pointer-down event followed by a drag will begin drawing a line (because the user is BOTH trying to close the menu AND start drawing a line).\n *\n * @public\n */\n",
|
||||
"docComment": "/**\n * @deprecated\n *\n * Use `getOpenMenus` instead.\n */\n",
|
||||
"excerptTokens": [
|
||||
{
|
||||
"kind": "Content",
|
||||
|
@ -33176,7 +33400,7 @@
|
|||
{
|
||||
"kind": "Property",
|
||||
"canonicalReference": "@tldraw/editor!StateNode#_currentToolIdMask:member",
|
||||
"docComment": "/**\n * This is a hack / escape hatch that will tell the editor to report a different state as active (in `currentToolId`) when this state is active. This is usually used when a tool transitions to a child of a different state for a certain interaction and then returns to the original tool when that interaction completes; and where we would want to show the original tool as active in the UI.\n *\n * @public\n */\n",
|
||||
"docComment": "/**\n * This is a hack / escape hatch that will tell the editor to report a different state as active (in `getCurrentToolId()`) when this state is active. This is usually used when a tool transitions to a child of a different state for a certain interaction and then returns to the original tool when that interaction completes; and where we would want to show the original tool as active in the UI.\n *\n * @public\n */\n",
|
||||
"excerptTokens": [
|
||||
{
|
||||
"kind": "Content",
|
||||
|
|
|
@ -221,11 +221,11 @@ const TldrawEditorWithLoadingStore = memo(function TldrawEditorBeforeLoading({
|
|||
const container = useContainer()
|
||||
|
||||
useLayoutEffect(() => {
|
||||
if (user.userPreferences.value.isDarkMode) {
|
||||
if (user.userPreferences.get().isDarkMode) {
|
||||
container.classList.remove('tl-theme__light')
|
||||
container.classList.add('tl-theme__dark')
|
||||
}
|
||||
}, [container, user.userPreferences.value.isDarkMode])
|
||||
}, [container, user])
|
||||
|
||||
switch (store.status) {
|
||||
case 'error': {
|
||||
|
|
|
@ -81,9 +81,9 @@ export function Canvas({ className }: { className?: string }) {
|
|||
[editor]
|
||||
)
|
||||
|
||||
const hideShapes = useValue('debug_shapes', () => debugFlags.hideShapes.value, [debugFlags])
|
||||
const debugSvg = useValue('debug_svg', () => debugFlags.debugSvg.value, [debugFlags])
|
||||
const debugGeometry = useValue('debug_geometry', () => debugFlags.debugGeometry.value, [
|
||||
const hideShapes = useValue('debug_shapes', () => debugFlags.hideShapes.get(), [debugFlags])
|
||||
const debugSvg = useValue('debug_svg', () => debugFlags.debugSvg.get(), [debugFlags])
|
||||
const debugGeometry = useValue('debug_geometry', () => debugFlags.debugGeometry.get(), [
|
||||
debugFlags,
|
||||
])
|
||||
|
||||
|
@ -135,9 +135,9 @@ export function Canvas({ className }: { className?: string }) {
|
|||
|
||||
function GridWrapper() {
|
||||
const editor = useEditor()
|
||||
const gridSize = useValue('gridSize', () => editor.documentSettings.gridSize, [editor])
|
||||
const gridSize = useValue('gridSize', () => editor.getDocumentSettings().gridSize, [editor])
|
||||
const { x, y, z } = useValue('camera', () => editor.camera, [editor])
|
||||
const isGridMode = useValue('isGridMode', () => editor.instanceState.isGridMode, [editor])
|
||||
const isGridMode = useValue('isGridMode', () => editor.getInstanceState().isGridMode, [editor])
|
||||
const { Grid } = useEditorComponents()
|
||||
|
||||
if (!(Grid && isGridMode)) return null
|
||||
|
@ -147,7 +147,7 @@ function GridWrapper() {
|
|||
|
||||
function ScribbleWrapper() {
|
||||
const editor = useEditor()
|
||||
const scribbles = useValue('scribbles', () => editor.instanceState.scribbles, [editor])
|
||||
const scribbles = useValue('scribbles', () => editor.getInstanceState().scribbles, [editor])
|
||||
const zoomLevel = useValue('zoomLevel', () => editor.zoomLevel, [editor])
|
||||
const { Scribble } = useEditorComponents()
|
||||
|
||||
|
@ -169,7 +169,7 @@ function ScribbleWrapper() {
|
|||
|
||||
function BrushWrapper() {
|
||||
const editor = useEditor()
|
||||
const brush = useValue('brush', () => editor.instanceState.brush, [editor])
|
||||
const brush = useValue('brush', () => editor.getInstanceState().brush, [editor])
|
||||
const { Brush } = useEditorComponents()
|
||||
|
||||
if (!(Brush && brush)) return null
|
||||
|
@ -179,7 +179,7 @@ function BrushWrapper() {
|
|||
|
||||
function ZoomBrushWrapper() {
|
||||
const editor = useEditor()
|
||||
const zoomBrush = useValue('zoomBrush', () => editor.instanceState.zoomBrush, [editor])
|
||||
const zoomBrush = useValue('zoomBrush', () => editor.getInstanceState().zoomBrush, [editor])
|
||||
const { ZoomBrush } = useEditorComponents()
|
||||
|
||||
if (!(ZoomBrush && zoomBrush)) return null
|
||||
|
@ -211,12 +211,18 @@ function HandlesWrapper() {
|
|||
const { Handles } = useEditorComponents()
|
||||
|
||||
const zoomLevel = useValue('zoomLevel', () => editor.zoomLevel, [editor])
|
||||
const isCoarse = useValue('coarse pointer', () => editor.instanceState.isCoarsePointer, [editor])
|
||||
const onlySelectedShape = useValue('onlySelectedShape', () => editor.onlySelectedShape, [editor])
|
||||
const isChangingStyle = useValue('isChangingStyle', () => editor.instanceState.isChangingStyle, [
|
||||
const isCoarse = useValue('coarse pointer', () => editor.getInstanceState().isCoarsePointer, [
|
||||
editor,
|
||||
])
|
||||
const onlySelectedShape = useValue('onlySelectedShape', () => editor.onlySelectedShape, [editor])
|
||||
const isChangingStyle = useValue(
|
||||
'isChangingStyle',
|
||||
() => editor.getInstanceState().isChangingStyle,
|
||||
[editor]
|
||||
)
|
||||
const isReadonly = useValue('isChangingStyle', () => editor.getInstanceState().isReadonly, [
|
||||
editor,
|
||||
])
|
||||
const isReadonly = useValue('isChangingStyle', () => editor.instanceState.isReadonly, [editor])
|
||||
const handles = useValue(
|
||||
'handles',
|
||||
() => (editor.onlySelectedShape ? editor.getShapeHandles(editor.onlySelectedShape) : undefined),
|
||||
|
@ -345,7 +351,7 @@ function SelectedIdIndicators() {
|
|||
'select.pointing_shape',
|
||||
'select.pointing_selection',
|
||||
'select.pointing_handle'
|
||||
) && !editor.instanceState.isChangingStyle
|
||||
) && !editor.getInstanceState().isChangingStyle
|
||||
)
|
||||
},
|
||||
[editor]
|
||||
|
@ -365,12 +371,14 @@ function SelectedIdIndicators() {
|
|||
const HoveredShapeIndicator = function HoveredShapeIndicator() {
|
||||
const editor = useEditor()
|
||||
const { HoveredShapeIndicator } = useEditorComponents()
|
||||
const isCoarsePointer = useValue('coarse pointer', () => editor.instanceState.isCoarsePointer, [
|
||||
editor,
|
||||
])
|
||||
const isCoarsePointer = useValue(
|
||||
'coarse pointer',
|
||||
() => editor.getInstanceState().isCoarsePointer,
|
||||
[editor]
|
||||
)
|
||||
const isHoveringCanvas = useValue(
|
||||
'hovering canvas',
|
||||
() => editor.instanceState.isHoveringCanvas,
|
||||
() => editor.getInstanceState().isHoveringCanvas,
|
||||
[editor]
|
||||
)
|
||||
const hoveredShapeId = useValue('hovered id', () => editor.currentPageState.hoveredShapeId, [
|
||||
|
@ -480,7 +488,7 @@ const DebugSvgCopy = track(function DupSvg({ id }: { id: TLShapeId }) {
|
|||
})
|
||||
|
||||
function UiLogger() {
|
||||
const uiLog = useValue('debugging ui log', () => debugFlags.logMessages.value, [debugFlags])
|
||||
const uiLog = useValue('debugging ui log', () => debugFlags.logMessages.get(), [debugFlags])
|
||||
|
||||
if (!uiLog.length) return null
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ const CollaboratorGuard = track(function CollaboratorGuard({
|
|||
|
||||
switch (collaboratorState) {
|
||||
case 'inactive': {
|
||||
const { followingUserId, highlightedUserIds } = editor.instanceState
|
||||
const { followingUserId, highlightedUserIds } = editor.getInstanceState()
|
||||
// If they're inactive and unless we're following them or they're highlighted, hide them
|
||||
if (!(followingUserId === presence.userId || highlightedUserIds.includes(presence.userId))) {
|
||||
return null
|
||||
|
@ -46,7 +46,7 @@ const CollaboratorGuard = track(function CollaboratorGuard({
|
|||
break
|
||||
}
|
||||
case 'idle': {
|
||||
const { highlightedUserIds } = editor.instanceState
|
||||
const { highlightedUserIds } = editor.getInstanceState()
|
||||
// If they're idle and following us and unless they have a chat message or are highlighted, hide them
|
||||
if (
|
||||
presence.followingUserId === editor.user.id &&
|
||||
|
|
|
@ -81,7 +81,7 @@ export const Shape = track(function Shape({
|
|||
if (!shape) return null
|
||||
|
||||
const bounds = editor.getShapeGeometry(shape).bounds
|
||||
const dpr = Math.floor(editor.instanceState.devicePixelRatio * 100) / 100
|
||||
const dpr = Math.floor(editor.getInstanceState().devicePixelRatio * 100) / 100
|
||||
// dprMultiple is the smallest number we can multiply dpr by to get an integer
|
||||
// it's usually 1, 2, or 4 (for e.g. dpr of 2, 2.5 and 2.25 respectively)
|
||||
const dprMultiple = nearestMultiple(dpr)
|
||||
|
|
|
@ -170,7 +170,7 @@ export function createSessionStateSnapshotSignal(
|
|||
const instanceState = store.get(TLINSTANCE_ID)
|
||||
if (!instanceState) return null
|
||||
|
||||
const allPageIds = [...$allPageIds.value]
|
||||
const allPageIds = [...$allPageIds.get()]
|
||||
return {
|
||||
version: CURRENT_SESSION_STATE_SNAPSHOT_VERSION,
|
||||
currentPageId: instanceState.currentPageId,
|
||||
|
|
|
@ -189,7 +189,7 @@ function storeUserPreferences() {
|
|||
USER_DATA_KEY,
|
||||
JSON.stringify({
|
||||
version: userMigrations.currentVersion,
|
||||
user: globalUserPreferences.value,
|
||||
user: globalUserPreferences.get(),
|
||||
})
|
||||
)
|
||||
}
|
||||
|
@ -225,7 +225,7 @@ function broadcastUserPreferencesChange() {
|
|||
type: broadcastEventKey,
|
||||
origin: broadcastOrigin,
|
||||
data: {
|
||||
user: globalUserPreferences.value,
|
||||
user: globalUserPreferences.get(),
|
||||
version: userMigrations.currentVersion,
|
||||
},
|
||||
} satisfies UserChangeBroadcastMessage)
|
||||
|
@ -233,5 +233,5 @@ function broadcastUserPreferencesChange() {
|
|||
|
||||
/** @public */
|
||||
export function getUserPreferences() {
|
||||
return globalUserPreferences.value
|
||||
return globalUserPreferences.get()
|
||||
}
|
||||
|
|
|
@ -454,7 +454,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
invalidParents.add(record.parentId)
|
||||
}
|
||||
// clean up any arrows bound to this shape
|
||||
const bindings = this._arrowBindingsIndex.value[record.id]
|
||||
const bindings = this._arrowBindingsIndex.get()[record.id]
|
||||
if (bindings?.length) {
|
||||
for (const { arrowId, handleId } of bindings) {
|
||||
const arrow = this.getShape<TLArrowShape>(arrowId)
|
||||
|
@ -476,11 +476,11 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
|
||||
this.sideEffects.registerBeforeDeleteHandler('page', (record) => {
|
||||
// page was deleted, need to check whether it's the current page and select another one if so
|
||||
if (this.instanceState.currentPageId !== record.id) return
|
||||
if (this.getInstanceState().currentPageId !== record.id) return
|
||||
|
||||
const backupPageId = this.pages.find((p) => p.id !== record.id)?.id
|
||||
if (!backupPageId) return
|
||||
this.store.put([{ ...this.instanceState, currentPageId: backupPageId }])
|
||||
this.store.put([{ ...this.getInstanceState(), currentPageId: backupPageId }])
|
||||
|
||||
// delete the camera and state for the page if necessary
|
||||
const cameraId = CameraRecordType.createId(record.id)
|
||||
|
@ -496,7 +496,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
// if the shape's parent changed and it is bound to an arrow, update the arrow's parent
|
||||
if (prev.parentId !== next.parentId) {
|
||||
const reparentBoundArrows = (id: TLShapeId) => {
|
||||
const boundArrows = this._arrowBindingsIndex.value[id]
|
||||
const boundArrows = this._arrowBindingsIndex.get()[id]
|
||||
if (boundArrows?.length) {
|
||||
for (const arrow of boundArrows) {
|
||||
reparentArrow(arrow.arrowId)
|
||||
|
@ -621,7 +621,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
|
||||
this.root.enter(undefined, 'initial')
|
||||
|
||||
if (this.instanceState.followingUserId) {
|
||||
if (this.getInstanceState().followingUserId) {
|
||||
this.stopFollowingUser()
|
||||
}
|
||||
|
||||
|
@ -792,10 +792,17 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
*
|
||||
* @public
|
||||
*/
|
||||
@computed get canUndo(): boolean {
|
||||
@computed getCanUndo(): boolean {
|
||||
return this.history.numUndos > 0
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use `getCanUndo` instead.
|
||||
*/
|
||||
get canUndo(): boolean {
|
||||
return this.getCanUndo()
|
||||
}
|
||||
|
||||
/**
|
||||
* Redo to the next mark.
|
||||
*
|
||||
|
@ -816,10 +823,17 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
*
|
||||
* @public
|
||||
*/
|
||||
@computed get canRedo(): boolean {
|
||||
@computed getCanRedo(): boolean {
|
||||
return this.history.numRedos > 0
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use `getCanRedo` instead.
|
||||
*/
|
||||
get canRedo(): boolean {
|
||||
return this.getCanRedo()
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new "mark", or stopping point, in the undo redo history. Creating a mark will clear
|
||||
* any redos.
|
||||
|
@ -910,7 +924,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
* @public
|
||||
*/
|
||||
getArrowsBoundTo(shapeId: TLShapeId) {
|
||||
return this._arrowBindingsIndex.value[shapeId] || EMPTY_ARRAY
|
||||
return this._arrowBindingsIndex.get()[shapeId] || EMPTY_ARRAY
|
||||
}
|
||||
|
||||
@computed
|
||||
|
@ -987,7 +1001,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
willCrashApp,
|
||||
},
|
||||
extras: {
|
||||
activeStateNode: this.root.path.value,
|
||||
activeStateNode: this.root.path.get(),
|
||||
selectedShapes: this.selectedShapes,
|
||||
editingShape: this.editingShapeId ? this.getShape(this.editingShapeId) : undefined,
|
||||
inputs: this.inputs,
|
||||
|
@ -1049,7 +1063,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
while (ids.length > 0) {
|
||||
const id = ids.pop()
|
||||
if (!id) return true
|
||||
const current = state.current.value
|
||||
const current = state.current.get()
|
||||
if (current?.id === id) {
|
||||
if (ids.length === 0) return true
|
||||
state = current
|
||||
|
@ -1097,8 +1111,16 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
*
|
||||
* @public
|
||||
*/
|
||||
@computed get currentTool(): StateNode | undefined {
|
||||
return this.root.current.value
|
||||
@computed getCurrentTool(): StateNode | undefined {
|
||||
return this.root.current.get()
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use `getCurrentTool` instead.
|
||||
* @public
|
||||
*/
|
||||
get currentTool() {
|
||||
return this.getCurrentTool()
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1106,12 +1128,19 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
*
|
||||
* @public
|
||||
*/
|
||||
@computed get currentToolId(): string {
|
||||
const { currentTool } = this
|
||||
@computed getCurrentToolId(): string {
|
||||
const currentTool = this.getCurrentTool()
|
||||
if (!currentTool) return ''
|
||||
return currentTool.currentToolIdMask ?? currentTool.id
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use `getCurrentToolId` instead.
|
||||
*/
|
||||
get currentToolId() {
|
||||
return this.getCurrentToolId()
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a descendant by its path.
|
||||
*
|
||||
|
@ -1145,17 +1174,24 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
*
|
||||
* @public
|
||||
**/
|
||||
@computed get documentSettings() {
|
||||
@computed getDocumentSettings() {
|
||||
return this.store.get(TLDOCUMENT_ID)!
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use `getDocumentSettings` instead.
|
||||
*/
|
||||
get documentSettings() {
|
||||
return this.getDocumentSettings()
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the global document settings that apply to all users.
|
||||
*
|
||||
* @public
|
||||
**/
|
||||
updateDocumentSettings(settings: Partial<TLDocument>): this {
|
||||
this.store.put([{ ...this.documentSettings, ...settings }])
|
||||
this.store.put([{ ...this.getDocumentSettings(), ...settings }])
|
||||
return this
|
||||
}
|
||||
|
||||
|
@ -1166,10 +1202,17 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
*
|
||||
* @public
|
||||
*/
|
||||
@computed get instanceState(): TLInstance {
|
||||
@computed getInstanceState(): TLInstance {
|
||||
return this.store.get(TLINSTANCE_ID)!
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use `getInstanceState` instead.
|
||||
*/
|
||||
get instanceState() {
|
||||
return this.getInstanceState()
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the instance's state.
|
||||
*
|
||||
|
@ -1204,7 +1247,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
partial: Partial<Omit<TLInstance, 'currentPageId'>>,
|
||||
historyOptions?: TLCommandHistoryOptions
|
||||
) => {
|
||||
const prev = this.store.get(this.instanceState.id)!
|
||||
const prev = this.store.get(this.getInstanceState().id)!
|
||||
const next = { ...prev, ...partial }
|
||||
|
||||
return {
|
||||
|
@ -1243,8 +1286,15 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
*
|
||||
* @public
|
||||
*/
|
||||
@computed get openMenus(): string[] {
|
||||
return this.instanceState.openMenus
|
||||
@computed getOpenMenus(): string[] {
|
||||
return this.getInstanceState().openMenus
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use `getOpenMenus` instead.
|
||||
*/
|
||||
get openMenus() {
|
||||
return this.getOpenMenus()
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1258,7 +1308,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
* @public
|
||||
*/
|
||||
addOpenMenu(id: string): this {
|
||||
const menus = new Set(this.openMenus)
|
||||
const menus = new Set(this.getOpenMenus())
|
||||
if (!menus.has(id)) {
|
||||
menus.add(id)
|
||||
this.updateInstanceState({ openMenus: [...menus] })
|
||||
|
@ -1277,7 +1327,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
* @public
|
||||
*/
|
||||
deleteOpenMenu(id: string): this {
|
||||
const menus = new Set(this.openMenus)
|
||||
const menus = new Set(this.getOpenMenus())
|
||||
if (menus.has(id)) {
|
||||
menus.delete(id)
|
||||
this.updateInstanceState({ openMenus: [...menus] })
|
||||
|
@ -1296,7 +1346,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
* @public
|
||||
*/
|
||||
@computed get isMenuOpen(): boolean {
|
||||
return this.openMenus.length > 0
|
||||
return this.getOpenMenus().length > 0
|
||||
}
|
||||
|
||||
/* --------------------- Cursor --------------------- */
|
||||
|
@ -1311,7 +1361,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
*/
|
||||
setCursor = (cursor: Partial<TLCursor>): this => {
|
||||
this.updateInstanceState(
|
||||
{ cursor: { ...this.instanceState.cursor, ...cursor } },
|
||||
{ cursor: { ...this.getInstanceState().cursor, ...cursor } },
|
||||
{ ephemeral: true }
|
||||
)
|
||||
return this
|
||||
|
@ -1325,7 +1375,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
* @public
|
||||
*/
|
||||
@computed get pageStates(): TLInstancePageState[] {
|
||||
return this._pageStates.value
|
||||
return this._pageStates.get()
|
||||
}
|
||||
/** @internal */
|
||||
@computed private get _pageStates() {
|
||||
|
@ -2058,7 +2108,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
altKey: this.inputs.altKey,
|
||||
shiftKey: this.inputs.shiftKey,
|
||||
button: 0,
|
||||
isPen: this.instanceState.isPenMode ?? false,
|
||||
isPen: this.getInstanceState().isPenMode ?? false,
|
||||
})
|
||||
|
||||
this._tickCameraState()
|
||||
|
@ -2091,7 +2141,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
this.stopCameraAnimation()
|
||||
|
||||
// Stop following any user
|
||||
if (this.instanceState.followingUserId) {
|
||||
if (this.getInstanceState().followingUserId) {
|
||||
this.stopFollowingUser()
|
||||
}
|
||||
|
||||
|
@ -2120,7 +2170,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
* @public
|
||||
*/
|
||||
centerOnPoint(point: VecLike, animation?: TLAnimationOptions): this {
|
||||
if (!this.instanceState.canMoveCamera) return this
|
||||
if (!this.getInstanceState().canMoveCamera) return this
|
||||
|
||||
const {
|
||||
viewportPageBounds: { width: pw, height: ph },
|
||||
|
@ -2168,7 +2218,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
* @public
|
||||
*/
|
||||
zoomToFit(animation?: TLAnimationOptions): this {
|
||||
if (!this.instanceState.canMoveCamera) return this
|
||||
if (!this.getInstanceState().canMoveCamera) return this
|
||||
|
||||
const ids = [...this.currentPageShapeIds]
|
||||
if (ids.length <= 0) return this
|
||||
|
@ -2194,7 +2244,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
* @public
|
||||
*/
|
||||
resetZoom(point = this.viewportScreenCenter, animation?: TLAnimationOptions): this {
|
||||
if (!this.instanceState.canMoveCamera) return this
|
||||
if (!this.getInstanceState().canMoveCamera) return this
|
||||
|
||||
const { x: cx, y: cy, z: cz } = this.camera
|
||||
const { x, y } = point
|
||||
|
@ -2221,7 +2271,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
* @public
|
||||
*/
|
||||
zoomIn(point = this.viewportScreenCenter, animation?: TLAnimationOptions): this {
|
||||
if (!this.instanceState.canMoveCamera) return this
|
||||
if (!this.getInstanceState().canMoveCamera) return this
|
||||
|
||||
const { x: cx, y: cy, z: cz } = this.camera
|
||||
|
||||
|
@ -2259,7 +2309,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
* @public
|
||||
*/
|
||||
zoomOut(point = this.viewportScreenCenter, animation?: TLAnimationOptions): this {
|
||||
if (!this.instanceState.canMoveCamera) return this
|
||||
if (!this.getInstanceState().canMoveCamera) return this
|
||||
|
||||
const { x: cx, y: cy, z: cz } = this.camera
|
||||
|
||||
|
@ -2300,7 +2350,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
* @public
|
||||
*/
|
||||
zoomToSelection(animation?: TLAnimationOptions): this {
|
||||
if (!this.instanceState.canMoveCamera) return this
|
||||
if (!this.getInstanceState().canMoveCamera) return this
|
||||
|
||||
const { selectionPageBounds } = this
|
||||
if (!selectionPageBounds) return this
|
||||
|
@ -2319,7 +2369,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
* @public
|
||||
*/
|
||||
panZoomIntoView(ids: TLShapeId[], animation?: TLAnimationOptions): this {
|
||||
if (!this.instanceState.canMoveCamera) return this
|
||||
if (!this.getInstanceState().canMoveCamera) return this
|
||||
|
||||
if (ids.length <= 0) return this
|
||||
const selectionBounds = Box2d.Common(compact(ids.map((id) => this.getShapePageBounds(id))))
|
||||
|
@ -2379,7 +2429,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
* @public
|
||||
*/
|
||||
zoomToBounds(bounds: Box2d, targetZoom?: number, animation?: TLAnimationOptions): this {
|
||||
if (!this.instanceState.canMoveCamera) return this
|
||||
if (!this.getInstanceState().canMoveCamera) return this
|
||||
|
||||
const { viewportScreenBounds } = this
|
||||
|
||||
|
@ -2423,7 +2473,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
* @param animation - The animation options.
|
||||
*/
|
||||
pan(offset: VecLike, animation?: TLAnimationOptions): this {
|
||||
if (!this.instanceState.canMoveCamera) return this
|
||||
if (!this.getInstanceState().canMoveCamera) return this
|
||||
const { x: cx, y: cy, z: cz } = this.camera
|
||||
this.setCamera({ x: cx + offset.x / cz, y: cy + offset.y / cz, z: cz }, animation)
|
||||
return this
|
||||
|
@ -2490,7 +2540,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
|
||||
// If we have an existing animation, then stop it; also stop following any user
|
||||
this.stopCameraAnimation()
|
||||
if (this.instanceState.followingUserId) {
|
||||
if (this.getInstanceState().followingUserId) {
|
||||
this.stopFollowingUser()
|
||||
}
|
||||
|
||||
|
@ -2532,7 +2582,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
speedThreshold?: number
|
||||
}
|
||||
): this {
|
||||
if (!this.instanceState.canMoveCamera) return this
|
||||
if (!this.getInstanceState().canMoveCamera) return this
|
||||
|
||||
this.stopCameraAnimation()
|
||||
|
||||
|
@ -2580,7 +2630,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
userId: { eq: userId },
|
||||
}))
|
||||
|
||||
const presence = [...presences.value]
|
||||
const presence = [...presences.get()]
|
||||
.sort((a, b) => {
|
||||
return a.lastActivityTimestamp - b.lastActivityTimestamp
|
||||
})
|
||||
|
@ -2590,7 +2640,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
|
||||
this.batch(() => {
|
||||
// If we're following someone, stop following them
|
||||
if (this.instanceState.followingUserId !== null) {
|
||||
if (this.getInstanceState().followingUserId !== null) {
|
||||
this.stopFollowingUser()
|
||||
}
|
||||
|
||||
|
@ -2606,12 +2656,12 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
this.centerOnPoint(presence.cursor, options)
|
||||
|
||||
// Highlight the user's cursor
|
||||
const { highlightedUserIds } = this.instanceState
|
||||
const { highlightedUserIds } = this.getInstanceState()
|
||||
this.updateInstanceState({ highlightedUserIds: [...highlightedUserIds, userId] })
|
||||
|
||||
// Unhighlight the user's cursor after a few seconds
|
||||
setTimeout(() => {
|
||||
const highlightedUserIds = [...this.instanceState.highlightedUserIds]
|
||||
const highlightedUserIds = [...this.getInstanceState().highlightedUserIds]
|
||||
const index = highlightedUserIds.indexOf(userId)
|
||||
if (index < 0) return
|
||||
highlightedUserIds.splice(index, 1)
|
||||
|
@ -2628,7 +2678,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
* @public
|
||||
*/
|
||||
animateToShape(shapeId: TLShapeId, opts: TLAnimationOptions = DEFAULT_ANIMATION_OPTIONS): this {
|
||||
if (!this.instanceState.canMoveCamera) return this
|
||||
if (!this.getInstanceState().canMoveCamera) return this
|
||||
|
||||
const activeArea = this.viewportScreenBounds.clone().expandBy(-32)
|
||||
const viewportAspectRatio = activeArea.width / activeArea.height
|
||||
|
@ -2703,7 +2753,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
{ squashing: true, ephemeral: true }
|
||||
)
|
||||
} else {
|
||||
if (center && !this.instanceState.followingUserId) {
|
||||
if (center && !this.getInstanceState().followingUserId) {
|
||||
// Get the page center before the change, make the change, and restore it
|
||||
const before = this.viewportPageCenter
|
||||
this.updateInstanceState(
|
||||
|
@ -2733,7 +2783,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
* @public
|
||||
*/
|
||||
@computed get viewportScreenBounds() {
|
||||
const { x, y, w, h } = this.instanceState.screenBounds
|
||||
const { x, y, w, h } = this.getInstanceState().screenBounds
|
||||
return new Box2d(x, y, w, h)
|
||||
}
|
||||
|
||||
|
@ -2832,7 +2882,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
}
|
||||
|
||||
// If the leader is following us, then we can't follow them
|
||||
if (leaderPresences.value.some((p) => p.followingUserId === thisUserId)) {
|
||||
if (leaderPresences.get().some((p) => p.followingUserId === thisUserId)) {
|
||||
return this
|
||||
}
|
||||
|
||||
|
@ -2851,7 +2901,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
|
||||
const moveTowardsUser = () => {
|
||||
// Stop following if we can't find the user
|
||||
const leaderPresence = [...leaderPresences.value]
|
||||
const leaderPresence = [...leaderPresences.get()]
|
||||
.sort((a, b) => {
|
||||
return a.lastActivityTimestamp - b.lastActivityTimestamp
|
||||
})
|
||||
|
@ -2959,7 +3009,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
* @public
|
||||
*/
|
||||
@computed get cameraState() {
|
||||
return this._cameraState.value
|
||||
return this._cameraState.get()
|
||||
}
|
||||
|
||||
// Camera state does two things: first, it allows us to subscribe to whether
|
||||
|
@ -3136,7 +3186,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
* @public
|
||||
*/
|
||||
@computed get renderingBounds() {
|
||||
return this._renderingBounds.value
|
||||
return this._renderingBounds.get()
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
|
@ -3149,7 +3199,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
* @public
|
||||
*/
|
||||
@computed get renderingBoundsExpanded() {
|
||||
return this._renderingBoundsExpanded.value
|
||||
return this._renderingBoundsExpanded.get()
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
|
@ -3203,7 +3253,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
* @public
|
||||
*/
|
||||
@computed get pages(): TLPage[] {
|
||||
return this._pages.value.sort(sortByIndex)
|
||||
return this._pages.get().sort(sortByIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -3222,7 +3272,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
* @public
|
||||
*/
|
||||
get currentPageId(): TLPageId {
|
||||
return this.instanceState.currentPageId
|
||||
return this.getInstanceState().currentPageId
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -3251,7 +3301,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
* @public
|
||||
*/
|
||||
get currentPageShapeIds() {
|
||||
return this._currentPageShapeIds.value
|
||||
return this._currentPageShapeIds.get()
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -3329,7 +3379,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
])
|
||||
}
|
||||
|
||||
this.store.put([{ ...this.instanceState, currentPageId: toId }])
|
||||
this.store.put([{ ...this.getInstanceState(), currentPageId: toId }])
|
||||
|
||||
this.updateRenderingBounds()
|
||||
},
|
||||
|
@ -3338,7 +3388,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
// in multiplayer contexts this page might have been deleted
|
||||
return
|
||||
}
|
||||
this.store.put([{ ...this.instanceState, currentPageId: fromId }])
|
||||
this.store.put([{ ...this.getInstanceState(), currentPageId: fromId }])
|
||||
|
||||
this.updateRenderingBounds()
|
||||
},
|
||||
|
@ -3370,7 +3420,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
private _updatePage = this.history.createCommand(
|
||||
'updatePage',
|
||||
(partial: RequiredKeys<TLPage, 'id'>, historyOptions?: TLCommandHistoryOptions) => {
|
||||
if (this.instanceState.isReadonly) return null
|
||||
if (this.getInstanceState().isReadonly) return null
|
||||
|
||||
const prev = this.getPage(partial.id)
|
||||
|
||||
|
@ -3415,7 +3465,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
private _createPage = this.history.createCommand(
|
||||
'createPage',
|
||||
(page: Partial<TLPage>) => {
|
||||
if (this.instanceState.isReadonly) return null
|
||||
if (this.getInstanceState().isReadonly) return null
|
||||
if (this.pages.length >= MAX_PAGES) return null
|
||||
const { pages } = this
|
||||
|
||||
|
@ -3486,7 +3536,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
private _deletePage = this.history.createCommand(
|
||||
'delete_page',
|
||||
(id: TLPageId) => {
|
||||
if (this.instanceState.isReadonly) return null
|
||||
if (this.getInstanceState().isReadonly) return null
|
||||
const { pages } = this
|
||||
if (pages.length === 1) return null
|
||||
|
||||
|
@ -3578,7 +3628,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
*/
|
||||
renamePage(page: TLPageId | TLPage, name: string, historyOptions?: TLCommandHistoryOptions) {
|
||||
const id = typeof page === 'string' ? page : page.id
|
||||
if (this.instanceState.isReadonly) return this
|
||||
if (this.getInstanceState().isReadonly) return this
|
||||
this.updatePage({ id, name }, historyOptions)
|
||||
return this
|
||||
}
|
||||
|
@ -3596,7 +3646,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
* @public
|
||||
*/
|
||||
get assets() {
|
||||
return this._assets.value
|
||||
return this._assets.get()
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -3619,7 +3669,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
private _createAssets = this.history.createCommand(
|
||||
'createAssets',
|
||||
(assets: TLAsset[]) => {
|
||||
if (this.instanceState.isReadonly) return null
|
||||
if (this.getInstanceState().isReadonly) return null
|
||||
if (assets.length <= 0) return null
|
||||
|
||||
return { data: { assets } }
|
||||
|
@ -3655,7 +3705,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
private _updateAssets = this.history.createCommand(
|
||||
'updateAssets',
|
||||
(assets: TLAssetPartial[]) => {
|
||||
if (this.instanceState.isReadonly) return
|
||||
if (this.getInstanceState().isReadonly) return
|
||||
if (assets.length <= 0) return
|
||||
|
||||
const snapshots: Record<string, TLAsset> = {}
|
||||
|
@ -3706,7 +3756,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
private _deleteAssets = this.history.createCommand(
|
||||
'deleteAssets',
|
||||
(ids: TLAssetId[]) => {
|
||||
if (this.instanceState.isReadonly) return
|
||||
if (this.getInstanceState().isReadonly) return
|
||||
if (ids.length <= 0) return
|
||||
|
||||
const prev = compact(ids.map((id) => this.store.get(id)))
|
||||
|
@ -4858,7 +4908,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
*/
|
||||
getHighestIndexForParent(parent: TLParentId | TLPage | TLShape): string {
|
||||
const parentId = typeof parent === 'string' ? parent : parent.id
|
||||
const children = this._parentIdsToChildIds.value[parentId]
|
||||
const children = this._parentIdsToChildIds.get()[parentId]
|
||||
|
||||
if (!children || children.length === 0) {
|
||||
return 'a1'
|
||||
|
@ -4888,7 +4938,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
*/
|
||||
getSortedChildIdsForParent(parent: TLParentId | TLPage | TLShape): TLShapeId[] {
|
||||
const parentId = typeof parent === 'string' ? parent : parent.id
|
||||
const ids = this._parentIdsToChildIds.value[parentId]
|
||||
const ids = this._parentIdsToChildIds.get()[parentId]
|
||||
if (!ids) return EMPTY_ARRAY
|
||||
return this._childIdsCache.get(ids, () => ids)
|
||||
}
|
||||
|
@ -5329,7 +5379,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
: (shapes as TLShape[]).map((s) => s.id)
|
||||
|
||||
if (ids.length === 0) return this
|
||||
if (this.instanceState.isReadonly) return this
|
||||
if (this.getInstanceState().isReadonly) return this
|
||||
|
||||
const { currentPageId } = this
|
||||
|
||||
|
@ -5392,7 +5442,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
? (shapes as TLShapeId[])
|
||||
: (shapes as TLShape[]).map((s) => s.id)
|
||||
|
||||
if (this.instanceState.isReadonly || ids.length === 0) return this
|
||||
if (this.getInstanceState().isReadonly || ids.length === 0) return this
|
||||
|
||||
let allLocked = true,
|
||||
allUnlocked = true
|
||||
|
@ -5540,7 +5590,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
? (shapes as TLShapeId[])
|
||||
: (shapes as TLShape[]).map((s) => s.id)
|
||||
|
||||
if (this.instanceState.isReadonly) return this
|
||||
if (this.getInstanceState().isReadonly) return this
|
||||
|
||||
let shapesToFlip = compact(ids.map((id) => this.getShape(id)))
|
||||
|
||||
|
@ -5609,7 +5659,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
typeof shapes[0] === 'string'
|
||||
? (shapes as TLShapeId[])
|
||||
: (shapes as TLShape[]).map((s) => s.id)
|
||||
if (this.instanceState.isReadonly) return this
|
||||
if (this.getInstanceState().isReadonly) return this
|
||||
|
||||
const shapesToStack = compact(
|
||||
ids
|
||||
|
@ -5754,7 +5804,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
? (shapes as TLShapeId[])
|
||||
: (shapes as TLShape[]).map((s) => s.id)
|
||||
|
||||
if (this.instanceState.isReadonly) return this
|
||||
if (this.getInstanceState().isReadonly) return this
|
||||
if (ids.length < 2) return this
|
||||
|
||||
const shapesToPack = compact(
|
||||
|
@ -5918,7 +5968,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
? (shapes as TLShapeId[])
|
||||
: (shapes as TLShape[]).map((s) => s.id)
|
||||
|
||||
if (this.instanceState.isReadonly) return this
|
||||
if (this.getInstanceState().isReadonly) return this
|
||||
if (ids.length < 2) return this
|
||||
|
||||
const shapesToAlign = compact(ids.map((id) => this.getShape(id))) // always fresh shapes
|
||||
|
@ -6009,7 +6059,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
? (shapes as TLShapeId[])
|
||||
: (shapes as TLShape[]).map((s) => s.id)
|
||||
|
||||
if (this.instanceState.isReadonly) return this
|
||||
if (this.getInstanceState().isReadonly) return this
|
||||
if (ids.length < 3) return this
|
||||
|
||||
const len = ids.length
|
||||
|
@ -6100,7 +6150,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
? (shapes as TLShapeId[])
|
||||
: (shapes as TLShape[]).map((s) => s.id)
|
||||
|
||||
if (this.instanceState.isReadonly) return this
|
||||
if (this.getInstanceState().isReadonly) return this
|
||||
if (ids.length < 2) return this
|
||||
|
||||
const shapesToStretch = compact(ids.map((id) => this.getShape(id))) // always fresh shapes
|
||||
|
@ -6176,7 +6226,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
options: TLResizeShapeOptions = {}
|
||||
): this {
|
||||
const id = typeof shape === 'string' ? shape : shape.id
|
||||
if (this.instanceState.isReadonly) return this
|
||||
if (this.getInstanceState().isReadonly) return this
|
||||
|
||||
if (!Number.isFinite(scale.x)) scale = new Vec2d(1, scale.y)
|
||||
if (!Number.isFinite(scale.y)) scale = new Vec2d(scale.x, 1)
|
||||
|
@ -6474,7 +6524,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
private _createShapes = this.history.createCommand(
|
||||
'createShapes',
|
||||
(partials: OptionalKeys<TLShapePartial, 'id'>[]) => {
|
||||
if (this.instanceState.isReadonly) return null
|
||||
if (this.getInstanceState().isReadonly) return null
|
||||
if (partials.length <= 0) return null
|
||||
|
||||
const { currentPageShapeIds } = this
|
||||
|
@ -6627,7 +6677,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
).create({
|
||||
...partial,
|
||||
index,
|
||||
opacity: partial.opacity ?? this.instanceState.opacityForNextShape,
|
||||
opacity: partial.opacity ?? this.getInstanceState().opacityForNextShape,
|
||||
parentId: partial.parentId ?? focusedGroupId,
|
||||
props: 'props' in partial ? { ...initialProps, ...partial.props } : initialProps,
|
||||
})
|
||||
|
@ -6800,7 +6850,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
if (!Array.isArray(shapes)) {
|
||||
throw Error('Editor.groupShapes: must provide an array of shapes or shape ids')
|
||||
}
|
||||
if (this.instanceState.isReadonly) return this
|
||||
if (this.getInstanceState().isReadonly) return this
|
||||
|
||||
const ids =
|
||||
typeof shapes[0] === 'string'
|
||||
|
@ -6818,7 +6868,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
const parentId = this.findCommonAncestor(shapesToGroup) ?? this.currentPageId
|
||||
|
||||
// Only group when the select tool is active
|
||||
if (this.currentToolId !== 'select') return this
|
||||
if (this.getCurrentToolId() !== 'select') return this
|
||||
|
||||
// If not already in idle, cancel the current interaction (get back to idle)
|
||||
if (!this.isIn('select.idle')) {
|
||||
|
@ -6864,11 +6914,11 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
ungroupShapes(_ids: TLShapeId[] | TLShape[]) {
|
||||
const ids =
|
||||
typeof _ids[0] === 'string' ? (_ids as TLShapeId[]) : (_ids as TLShape[]).map((s) => s.id)
|
||||
if (this.instanceState.isReadonly) return this
|
||||
if (this.getInstanceState().isReadonly) return this
|
||||
if (ids.length === 0) return this
|
||||
|
||||
// Only ungroup when the select tool is active
|
||||
if (this.currentToolId !== 'select') return this
|
||||
if (this.getCurrentToolId() !== 'select') return this
|
||||
|
||||
// If not already in idle, cancel the current interaction (get back to idle)
|
||||
if (!this.isIn('select.idle')) {
|
||||
|
@ -6979,7 +7029,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
_partials: (TLShapePartial | null | undefined)[],
|
||||
historyOptions?: TLCommandHistoryOptions
|
||||
) => {
|
||||
if (this.instanceState.isReadonly) return null
|
||||
if (this.getInstanceState().isReadonly) return null
|
||||
|
||||
const partials = compact(_partials)
|
||||
|
||||
|
@ -7129,7 +7179,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
private _deleteShapes = this.history.createCommand(
|
||||
'delete_shapes',
|
||||
(ids: TLShapeId[]) => {
|
||||
if (this.instanceState.isReadonly) return null
|
||||
if (this.getInstanceState().isReadonly) return null
|
||||
if (ids.length === 0) return null
|
||||
const prevSelectedShapeIds = [...this.currentPageState.selectedShapeIds]
|
||||
|
||||
|
@ -7142,7 +7192,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
}
|
||||
|
||||
const deletedIds = [...allIds]
|
||||
const arrowBindings = this._arrowBindingsIndex.value
|
||||
const arrowBindings = this._arrowBindingsIndex.get()
|
||||
const snapshots = compact(
|
||||
deletedIds.flatMap((id) => {
|
||||
const shape = this.getShape(id)
|
||||
|
@ -7190,7 +7240,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
// For groups, ignore the styles of the group shape and instead include the styles of the
|
||||
// group's children. These are the shapes that would have their styles changed if the
|
||||
// user called `setStyle` on the current selection.
|
||||
const childIds = this._parentIdsToChildIds.value[shape.id]
|
||||
const childIds = this._parentIdsToChildIds.get()[shape.id]
|
||||
if (!childIds) return
|
||||
|
||||
for (let i = 0, n = childIds.length; i < n; i++) {
|
||||
|
@ -7224,7 +7274,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
|
||||
/** @internal */
|
||||
getStyleForNextShape<T>(style: StyleProp<T>): T {
|
||||
const value = this.instanceState.stylesForNextShape[style.id]
|
||||
const value = this.getInstanceState().stylesForNextShape[style.id]
|
||||
return value === undefined ? style.defaultValue : (value as T)
|
||||
}
|
||||
|
||||
|
@ -7253,12 +7303,12 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
// If we're in selecting and if we have a selection, return the shared styles from the
|
||||
// current selection
|
||||
if (this.isIn('select') && this.selectedShapeIds.length > 0) {
|
||||
return this._selectionSharedStyles.value
|
||||
return this._selectionSharedStyles.get()
|
||||
}
|
||||
|
||||
// If the current tool is associated with a shape, return the styles for that shape.
|
||||
// Otherwise, just return an empty map.
|
||||
const currentTool = this.root.current.value!
|
||||
const currentTool = this.root.current.get()!
|
||||
const styles = new SharedStyleMap()
|
||||
if (currentTool.shapeType) {
|
||||
for (const style of this.styleProps[currentTool.shapeType].keys()) {
|
||||
|
@ -7308,7 +7358,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
|
||||
if (opacity !== null) return { type: 'shared', value: opacity }
|
||||
}
|
||||
return { type: 'shared', value: this.instanceState.opacityForNextShape }
|
||||
return { type: 'shared', value: this.getInstanceState().opacityForNextShape }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -7398,9 +7448,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
value: T,
|
||||
historyOptions?: TLCommandHistoryOptions
|
||||
): this {
|
||||
const {
|
||||
instanceState: { stylesForNextShape },
|
||||
} = this
|
||||
const stylesForNextShape = this.getInstanceState().stylesForNextShape
|
||||
|
||||
this.updateInstanceState(
|
||||
{ stylesForNextShape: { ...stylesForNextShape, [style.id]: value } },
|
||||
|
@ -7748,7 +7796,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
preserveIds?: boolean
|
||||
} = {}
|
||||
): this {
|
||||
if (this.instanceState.isReadonly) return this
|
||||
if (this.getInstanceState().isReadonly) return this
|
||||
|
||||
// todo: make this able to support putting content onto any page, not just the current page
|
||||
|
||||
|
@ -8591,7 +8639,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
|
||||
switch (type) {
|
||||
case 'pinch': {
|
||||
if (!this.instanceState.canMoveCamera) return
|
||||
if (!this.getInstanceState().canMoveCamera) return
|
||||
this._updateInputsFromEvent(info)
|
||||
|
||||
switch (info.name) {
|
||||
|
@ -8657,7 +8705,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
}
|
||||
}
|
||||
case 'wheel': {
|
||||
if (!this.instanceState.canMoveCamera) return
|
||||
if (!this.getInstanceState().canMoveCamera) return
|
||||
|
||||
this._updateInputsFromEvent(info)
|
||||
|
||||
|
@ -8693,7 +8741,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
!inputs.isDragging &&
|
||||
inputs.isPointing &&
|
||||
originPagePoint.dist(currentPagePoint) >
|
||||
(this.instanceState.isCoarsePointer ? COARSE_DRAG_DISTANCE : DRAG_DISTANCE) /
|
||||
(this.getInstanceState().isCoarsePointer ? COARSE_DRAG_DISTANCE : DRAG_DISTANCE) /
|
||||
this.zoomLevel
|
||||
) {
|
||||
inputs.isDragging = true
|
||||
|
@ -8725,7 +8773,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
inputs.isPointing = true
|
||||
inputs.isDragging = false
|
||||
|
||||
if (this.instanceState.isPenMode) {
|
||||
if (this.getInstanceState().isPenMode) {
|
||||
if (!isPen) {
|
||||
return
|
||||
}
|
||||
|
@ -8737,13 +8785,13 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
|
||||
if (info.button === 5) {
|
||||
// Eraser button activates eraser
|
||||
this._restoreToolId = this.currentToolId
|
||||
this._restoreToolId = this.getCurrentToolId()
|
||||
this.complete()
|
||||
this.setCurrentTool('eraser')
|
||||
} else if (info.button === 1) {
|
||||
// Middle mouse pan activates panning
|
||||
if (!this.inputs.isPanning) {
|
||||
this._prevCursor = this.instanceState.cursor.type
|
||||
this._prevCursor = this.getInstanceState().cursor.type
|
||||
}
|
||||
|
||||
this.inputs.isPanning = true
|
||||
|
@ -8766,7 +8814,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
}
|
||||
case 'pointer_move': {
|
||||
// If the user is in pen mode, but the pointer is not a pen, stop here.
|
||||
if (!isPen && this.instanceState.isPenMode) {
|
||||
if (!isPen && this.getInstanceState().isPenMode) {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -8781,7 +8829,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
!inputs.isDragging &&
|
||||
inputs.isPointing &&
|
||||
originPagePoint.dist(currentPagePoint) >
|
||||
(this.instanceState.isCoarsePointer ? COARSE_DRAG_DISTANCE : DRAG_DISTANCE) /
|
||||
(this.getInstanceState().isCoarsePointer ? COARSE_DRAG_DISTANCE : DRAG_DISTANCE) /
|
||||
this.zoomLevel
|
||||
) {
|
||||
inputs.isDragging = true
|
||||
|
@ -8800,7 +8848,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
return
|
||||
}
|
||||
|
||||
if (!isPen && this.instanceState.isPenMode) {
|
||||
if (!isPen && this.getInstanceState().isPenMode) {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -8879,7 +8927,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
// If the space key is pressed (but meta / control isn't!) activate panning
|
||||
if (!info.ctrlKey && info.code === 'Space') {
|
||||
if (!this.inputs.isPanning) {
|
||||
this._prevCursor = this.instanceState.cursor.type
|
||||
this._prevCursor = this.getInstanceState().cursor.type
|
||||
}
|
||||
|
||||
this.inputs.isPanning = true
|
||||
|
@ -8921,7 +8969,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
}
|
||||
|
||||
// If a pointer event, send the event to the click manager.
|
||||
if (info.isPen === this.instanceState.isPenMode) {
|
||||
if (info.isPen === this.getInstanceState().isPenMode) {
|
||||
switch (info.name) {
|
||||
case 'pointer_down': {
|
||||
const otherEvent = this._clickManager.transformPointerDownEvent(info)
|
||||
|
|
|
@ -12,7 +12,7 @@ export const arrowBindingsIndex = (editor: Editor): Computed<TLArrowBindingsInde
|
|||
const shapeHistory = store.query.filterHistory('shape')
|
||||
const arrowQuery = store.query.records('shape', () => ({ type: { eq: 'arrow' as const } }))
|
||||
function fromScratch() {
|
||||
const allArrows = arrowQuery.value as TLArrowShape[]
|
||||
const allArrows = arrowQuery.get() as TLArrowShape[]
|
||||
|
||||
const bindings2Arrows: TLArrowBindingsIndex = {}
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ export const parentsToChildren = (store: TLStore) => {
|
|||
|
||||
function fromScratch() {
|
||||
const result: Parents2Children = {}
|
||||
const shapeIds = shapeIdsQuery.value
|
||||
const shapeIds = shapeIdsQuery.get()
|
||||
const shapes = Array(shapeIds.size) as TLShape[]
|
||||
shapeIds.forEach((id) => shapes.push(store.get(id)!))
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ export const deriveShapeIdsInCurrentPage = (store: TLStore, getCurrentPageId: ()
|
|||
const currentPageId = getCurrentPageId()
|
||||
lastPageId = currentPageId
|
||||
return new Set(
|
||||
[...shapesIndex.value].filter((id) => isShapeInPage(store, currentPageId, store.get(id)!))
|
||||
[...shapesIndex.get()].filter((id) => isShapeInPage(store, currentPageId, store.get(id)!))
|
||||
)
|
||||
}
|
||||
return computed<Set<TLShapeId>>('_shapeIdsInCurrentPage', (prevValue, lastComputedEpoch) => {
|
||||
|
|
|
@ -227,7 +227,7 @@ export class ClickManager {
|
|||
this._clickState !== 'idle' &&
|
||||
this._clickScreenPoint &&
|
||||
this._clickScreenPoint.dist(this.editor.inputs.currentScreenPoint) >
|
||||
(this.editor.instanceState.isCoarsePointer ? COARSE_DRAG_DISTANCE : DRAG_DISTANCE)
|
||||
(this.editor.getInstanceState().isCoarsePointer ? COARSE_DRAG_DISTANCE : DRAG_DISTANCE)
|
||||
) {
|
||||
this.cancelDoubleClickTimeout()
|
||||
}
|
||||
|
|
|
@ -116,7 +116,7 @@ describe(HistoryManager, () => {
|
|||
editor.decrement()
|
||||
expect(editor.getCount()).toBe(3)
|
||||
|
||||
const undos = [...editor.history._undos.value]
|
||||
const undos = [...editor.history._undos.get()]
|
||||
const parsedUndos = JSON.parse(JSON.stringify(undos))
|
||||
editor.history._undos.set(stack(parsedUndos))
|
||||
|
||||
|
|
|
@ -34,11 +34,11 @@ export class HistoryManager<
|
|||
private _commands: Record<string, TLCommandHandler<any>> = {}
|
||||
|
||||
get numUndos() {
|
||||
return this._undos.value.length
|
||||
return this._undos.get().length
|
||||
}
|
||||
|
||||
get numRedos() {
|
||||
return this._redos.value.length
|
||||
return this._redos.get().length
|
||||
}
|
||||
|
||||
createCommand = <Name extends string, Constructor extends CommandFn<any>>(
|
||||
|
@ -72,7 +72,7 @@ export class HistoryManager<
|
|||
})
|
||||
|
||||
if (!ephemeral) {
|
||||
const prev = this._undos.value.head
|
||||
const prev = this._undos.get().head
|
||||
if (
|
||||
squashing &&
|
||||
prev &&
|
||||
|
@ -119,9 +119,9 @@ export class HistoryManager<
|
|||
this._batchDepth++
|
||||
if (this._batchDepth === 1) {
|
||||
transact(() => {
|
||||
const mostRecentActionId = this._undos.value.head?.id
|
||||
const mostRecentActionId = this._undos.get().head?.id
|
||||
fn()
|
||||
if (mostRecentActionId !== this._undos.value.head?.id) {
|
||||
if (mostRecentActionId !== this._undos.get().head?.id) {
|
||||
this.onBatchComplete()
|
||||
}
|
||||
})
|
||||
|
@ -144,8 +144,8 @@ export class HistoryManager<
|
|||
redos: Stack<TLHistoryEntry>
|
||||
) => { undos: Stack<TLHistoryEntry>; redos: Stack<TLHistoryEntry> }
|
||||
) => {
|
||||
let undos = this._undos.value
|
||||
let redos = this._redos.value
|
||||
let undos = this._undos.get()
|
||||
let redos = this._redos.get()
|
||||
|
||||
this._undos.set(stack())
|
||||
this._redos.set(stack())
|
||||
|
@ -286,7 +286,7 @@ export class HistoryManager<
|
|||
}
|
||||
|
||||
mark = (id = uniqueId(), onUndo = true, onRedo = true) => {
|
||||
const mostRecent = this._undos.value.head
|
||||
const mostRecent = this._undos.get().head
|
||||
// dedupe marks, why not
|
||||
if (mostRecent && mostRecent.type === 'STOP') {
|
||||
if (mostRecent.id === id && mostRecent.onUndo === onUndo && mostRecent.onRedo === onRedo) {
|
||||
|
|
|
@ -213,7 +213,7 @@ export class SnapManager {
|
|||
private _snapLines = atom<SnapLine[] | undefined>('snapLines', undefined)
|
||||
|
||||
get lines() {
|
||||
return this._snapLines.value ?? (EMPTY_ARRAY as SnapLine[])
|
||||
return this._snapLines.get() ?? (EMPTY_ARRAY as SnapLine[])
|
||||
}
|
||||
|
||||
clear() {
|
||||
|
|
|
@ -11,7 +11,7 @@ export class UserPreferencesManager {
|
|||
|
||||
updateUserPreferences = (userPreferences: Partial<TLUserPreferences>) => {
|
||||
this.user.setUserPreferences({
|
||||
...this.user.userPreferences.value,
|
||||
...this.user.userPreferences.get(),
|
||||
...userPreferences,
|
||||
})
|
||||
}
|
||||
|
@ -29,32 +29,32 @@ export class UserPreferencesManager {
|
|||
|
||||
@computed get isDarkMode() {
|
||||
return (
|
||||
this.user.userPreferences.value.isDarkMode ??
|
||||
this.user.userPreferences.get().isDarkMode ??
|
||||
(this.inferDarkMode ? userPrefersDarkUI() : false)
|
||||
)
|
||||
}
|
||||
|
||||
@computed get animationSpeed() {
|
||||
return this.user.userPreferences.value.animationSpeed ?? defaultUserPreferences.animationSpeed
|
||||
return this.user.userPreferences.get().animationSpeed ?? defaultUserPreferences.animationSpeed
|
||||
}
|
||||
|
||||
@computed get id() {
|
||||
return this.user.userPreferences.value.id
|
||||
return this.user.userPreferences.get().id
|
||||
}
|
||||
|
||||
@computed get name() {
|
||||
return this.user.userPreferences.value.name ?? defaultUserPreferences.name
|
||||
return this.user.userPreferences.get().name ?? defaultUserPreferences.name
|
||||
}
|
||||
|
||||
@computed get locale() {
|
||||
return this.user.userPreferences.value.locale ?? defaultUserPreferences.locale
|
||||
return this.user.userPreferences.get().locale ?? defaultUserPreferences.locale
|
||||
}
|
||||
|
||||
@computed get color() {
|
||||
return this.user.userPreferences.value.color ?? defaultUserPreferences.color
|
||||
return this.user.userPreferences.get().color ?? defaultUserPreferences.color
|
||||
}
|
||||
|
||||
@computed get isSnapMode() {
|
||||
return this.user.userPreferences.value.isSnapMode ?? defaultUserPreferences.isSnapMode
|
||||
return this.user.userPreferences.get().isSnapMode ?? defaultUserPreferences.isSnapMode
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ describe('atom manager', () => {
|
|||
expect(A.lastChangedEpoch).toBe(2)
|
||||
|
||||
manager.b
|
||||
expect(A.value).toMatchObject({ a: 2, b: 4, c: 3 })
|
||||
expect(A.get()).toMatchObject({ a: 2, b: 4, c: 3 })
|
||||
|
||||
expect(cb).toHaveBeenCalledTimes(2)
|
||||
})
|
||||
|
|
|
@ -5,18 +5,18 @@ export function getAtomManager<T extends { [key: string]: any }>(
|
|||
transform?: (prev: T, next: T) => T
|
||||
): T {
|
||||
const update = (value: Partial<T>) => {
|
||||
const curr = atom.value
|
||||
const curr = atom.get()
|
||||
const next = { ...curr, ...value }
|
||||
const final = transform?.(atom.value, atom.value) ?? next
|
||||
const final = transform?.(atom.get(), atom.get()) ?? next
|
||||
atom.set(final)
|
||||
}
|
||||
|
||||
return Object.defineProperties(
|
||||
{} as T,
|
||||
Object.keys(atom.value).reduce((acc, key) => {
|
||||
Object.keys(atom.get()).reduce((acc, key) => {
|
||||
acc[key as keyof T] = computed(atom, key, {
|
||||
get() {
|
||||
return atom.value[key as keyof T]
|
||||
return atom.get()[key as keyof T]
|
||||
},
|
||||
set(value: T[keyof T]) {
|
||||
update({ [key]: value } as any)
|
||||
|
|
|
@ -112,7 +112,7 @@ export class Pointing extends StateNode {
|
|||
|
||||
this.editor.setSelectedShapes([id])
|
||||
|
||||
if (this.editor.instanceState.isToolLocked) {
|
||||
if (this.editor.getInstanceState().isToolLocked) {
|
||||
this.parent.transition('idle', {})
|
||||
} else {
|
||||
this.editor.setCurrentTool('select.idle')
|
||||
|
|
|
@ -10,8 +10,8 @@ export class RootState extends StateNode {
|
|||
switch (info.code) {
|
||||
case 'KeyZ': {
|
||||
if (!(info.shiftKey || info.ctrlKey)) {
|
||||
const currentTool = this.current.value
|
||||
if (currentTool && currentTool.current.value?.id === 'idle') {
|
||||
const currentTool = this.current.get()
|
||||
if (currentTool && currentTool.current.get()?.id === 'idle') {
|
||||
if (this.children!['zoom']) {
|
||||
this.editor.setCurrentTool('zoom', { ...info, onInteractionEnd: currentTool.id })
|
||||
}
|
||||
|
|
|
@ -28,8 +28,8 @@ export abstract class StateNode implements Partial<TLEventHandlers> {
|
|||
this.current = atom<StateNode | undefined>('toolState' + this.id, undefined)
|
||||
|
||||
this.path = computed('toolPath' + this.id, () => {
|
||||
const current = this.current.value
|
||||
return this.id + (current ? `.${current.path.value}` : '')
|
||||
const current = this.current.get()
|
||||
return this.id + (current ? `.${current.path.get()}` : '')
|
||||
})
|
||||
|
||||
this.parent = parent ?? ({} as any)
|
||||
|
@ -81,7 +81,7 @@ export abstract class StateNode implements Partial<TLEventHandlers> {
|
|||
|
||||
for (let i = 0; i < path.length; i++) {
|
||||
const id = path[i]
|
||||
const prevChildState = currState.current.value
|
||||
const prevChildState = currState.current.get()
|
||||
const nextChildState = currState.children?.[id]
|
||||
|
||||
if (!nextChildState) {
|
||||
|
@ -103,9 +103,9 @@ export abstract class StateNode implements Partial<TLEventHandlers> {
|
|||
|
||||
handleEvent = (info: Exclude<TLEventInfo, TLPinchEventInfo>) => {
|
||||
const cbName = EVENT_NAME_MAP[info.name]
|
||||
const x = this.current.value
|
||||
const x = this.current.get()
|
||||
this[cbName]?.(info as any)
|
||||
if (this.current.value === x && this.isActive) {
|
||||
if (this.current.get() === x && this.isActive) {
|
||||
x?.handleEvent(info)
|
||||
}
|
||||
}
|
||||
|
@ -124,13 +124,13 @@ export abstract class StateNode implements Partial<TLEventHandlers> {
|
|||
this.isActive = false
|
||||
this.onExit?.(info, from)
|
||||
if (!this.isActive) {
|
||||
this.current.value?.exit(info, from)
|
||||
this.current.get()?.exit(info, from)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a hack / escape hatch that will tell the editor to
|
||||
* report a different state as active (in `currentToolId`) when
|
||||
* report a different state as active (in `getCurrentToolId()`) when
|
||||
* this state is active. This is usually used when a tool transitions
|
||||
* to a child of a different state for a certain interaction and then
|
||||
* returns to the original tool when that interaction completes; and
|
||||
|
@ -141,7 +141,7 @@ export abstract class StateNode implements Partial<TLEventHandlers> {
|
|||
_currentToolIdMask = atom('curent tool id mask', undefined as string | undefined)
|
||||
|
||||
@computed get currentToolIdMask() {
|
||||
return this._currentToolIdMask.value
|
||||
return this._currentToolIdMask.get()
|
||||
}
|
||||
|
||||
set currentToolIdMask(id: string | undefined) {
|
||||
|
|
|
@ -40,7 +40,7 @@ export function useCanvasEvents() {
|
|||
...getPointerInfo(e),
|
||||
})
|
||||
|
||||
if (editor.openMenus.length > 0) {
|
||||
if (editor.getOpenMenus().length > 0) {
|
||||
editor.updateInstanceState({
|
||||
openMenus: [],
|
||||
})
|
||||
|
@ -83,14 +83,14 @@ export function useCanvasEvents() {
|
|||
|
||||
function onPointerEnter(e: React.PointerEvent) {
|
||||
if ((e as any).isKilled) return
|
||||
if (editor.instanceState.isPenMode && e.pointerType !== 'pen') return
|
||||
if (editor.getInstanceState().isPenMode && e.pointerType !== 'pen') return
|
||||
const canHover = e.pointerType === 'mouse' || e.pointerType === 'pen'
|
||||
editor.updateInstanceState({ isHoveringCanvas: canHover ? true : null })
|
||||
}
|
||||
|
||||
function onPointerLeave(e: React.PointerEvent) {
|
||||
if ((e as any).isKilled) return
|
||||
if (editor.instanceState.isPenMode && e.pointerType !== 'pen') return
|
||||
if (editor.getInstanceState().isPenMode && e.pointerType !== 'pen') return
|
||||
const canHover = e.pointerType === 'mouse' || e.pointerType === 'pen'
|
||||
editor.updateInstanceState({ isHoveringCanvas: canHover ? false : null })
|
||||
}
|
||||
|
|
|
@ -78,7 +78,7 @@ export function useCursor() {
|
|||
useQuickReactor(
|
||||
'useCursor',
|
||||
() => {
|
||||
const { type, rotation } = editor.instanceState.cursor
|
||||
const { type, rotation } = editor.getInstanceState().cursor
|
||||
|
||||
if (STATIC_CURSORS.includes(type)) {
|
||||
container.style.setProperty('--tl-cursor', `var(--tl-cursor-${type})`)
|
||||
|
|
|
@ -23,7 +23,7 @@ export function useDPRMultiple() {
|
|||
|
||||
React.useEffect(() => {
|
||||
return react('useDPRMultiple', () => {
|
||||
const dpr = editor.instanceState.devicePixelRatio
|
||||
const dpr = editor.getInstanceState().devicePixelRatio
|
||||
container.style.setProperty('--tl-dpr-multiple', nearestMultiple(dpr).toString())
|
||||
})
|
||||
}, [editor, container])
|
||||
|
|
|
@ -9,7 +9,7 @@ export function useDocumentEvents() {
|
|||
const editor = useEditor()
|
||||
const container = useContainer()
|
||||
|
||||
const isAppFocused = useValue('isFocused', () => editor.instanceState.isFocused, [editor])
|
||||
const isAppFocused = useValue('isFocused', () => editor.getInstanceState().isFocused, [editor])
|
||||
|
||||
useEffect(() => {
|
||||
if (typeof matchMedia === undefined) return
|
||||
|
@ -55,7 +55,7 @@ export function useDocumentEvents() {
|
|||
if (
|
||||
e.altKey &&
|
||||
// todo: When should we allow the alt key to be used? Perhaps states should declare which keys matter to them?
|
||||
(editor.isIn('zoom') || !editor.root.path.value.endsWith('.idle')) &&
|
||||
(editor.isIn('zoom') || !editor.root.path.get().endsWith('.idle')) &&
|
||||
!isFocusingInput()
|
||||
) {
|
||||
// On windows the alt key opens the menu bar.
|
||||
|
@ -107,7 +107,7 @@ export function useDocumentEvents() {
|
|||
ctrlKey: e.metaKey || e.ctrlKey,
|
||||
pointerId: 0,
|
||||
button: 0,
|
||||
isPen: editor.instanceState.isPenMode,
|
||||
isPen: editor.getInstanceState().isPenMode,
|
||||
target: 'canvas',
|
||||
}
|
||||
|
||||
|
@ -131,7 +131,7 @@ export function useDocumentEvents() {
|
|||
}
|
||||
|
||||
// Don't do anything if we open menus open
|
||||
if (editor.openMenus.length > 0) return
|
||||
if (editor.getOpenMenus().length > 0) return
|
||||
|
||||
if (!editor.inputs.keys.has('Escape')) {
|
||||
editor.inputs.keys.add('Escape')
|
||||
|
@ -191,7 +191,7 @@ export function useDocumentEvents() {
|
|||
ctrlKey: e.metaKey || e.ctrlKey,
|
||||
pointerId: 0,
|
||||
button: 0,
|
||||
isPen: editor.instanceState.isPenMode,
|
||||
isPen: editor.getInstanceState().isPenMode,
|
||||
target: 'canvas',
|
||||
}
|
||||
editor.dispatch(info)
|
||||
|
|
|
@ -10,7 +10,7 @@ export function useFocusEvents(autoFocus: boolean) {
|
|||
if (autoFocus) {
|
||||
// When autoFocus is true, update the editor state to be focused
|
||||
// unless it's already focused
|
||||
if (!editor.instanceState.isFocused) {
|
||||
if (!editor.getInstanceState().isFocused) {
|
||||
editor.updateInstanceState({ isFocused: true })
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,7 @@ export function useFocusEvents(autoFocus: boolean) {
|
|||
} else {
|
||||
// When autoFocus is false, update the editor state to be not focused
|
||||
// unless it's already not focused
|
||||
if (editor.instanceState.isFocused) {
|
||||
if (editor.getInstanceState().isFocused) {
|
||||
editor.updateInstanceState({ isFocused: false })
|
||||
}
|
||||
}
|
||||
|
|
|
@ -81,7 +81,7 @@ export function useGestureEvents(ref: React.RefObject<HTMLDivElement>) {
|
|||
let pinchState = 'not sure' as 'not sure' | 'zooming' | 'panning'
|
||||
|
||||
const onWheel: Handler<'wheel', WheelEvent> = ({ event }) => {
|
||||
if (!editor.instanceState.isFocused) {
|
||||
if (!editor.getInstanceState().isFocused) {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ export function usePeerIds() {
|
|||
|
||||
const $userIds = useComputed(
|
||||
'userIds',
|
||||
() => uniq($presences.value.map((p) => p.userId)).sort(),
|
||||
() => uniq($presences.get().map((p) => p.userId)).sort(),
|
||||
{ isEqual: (a, b) => a.join(',') === b.join?.(',') },
|
||||
[$presences]
|
||||
)
|
||||
|
|
|
@ -20,7 +20,8 @@ export function usePresence(userId: string): TLInstancePresence | null {
|
|||
const latestPresence = useValue(
|
||||
`latestPresence:${userId}`,
|
||||
() => {
|
||||
return $presences.value
|
||||
return $presences
|
||||
.get()
|
||||
.slice()
|
||||
.sort((a, b) => b.lastActivityTimestamp - a.lastActivityTimestamp)[0]
|
||||
},
|
||||
|
|
|
@ -32,16 +32,16 @@ beforeEach(() => {
|
|||
|
||||
describe('current tool id mask', () => {
|
||||
it('starts with the correct tool id', () => {
|
||||
expect(editor.currentToolId).toBe('A')
|
||||
expect(editor.getCurrentToolId()).toBe('A')
|
||||
})
|
||||
|
||||
it('updates the current tool id', () => {
|
||||
editor.setCurrentTool('B')
|
||||
expect(editor.currentToolId).toBe('B')
|
||||
expect(editor.getCurrentToolId()).toBe('B')
|
||||
})
|
||||
|
||||
it('masks the current tool id', () => {
|
||||
editor.setCurrentTool('C')
|
||||
expect(editor.currentToolId).toBe('A')
|
||||
expect(editor.getCurrentToolId()).toBe('A')
|
||||
})
|
||||
})
|
||||
|
|
|
@ -62,7 +62,7 @@ declare global {
|
|||
|
||||
if (typeof window !== 'undefined') {
|
||||
window.tldrawLog = (message: any) => {
|
||||
debugFlags.logMessages.set(debugFlags.logMessages.value.concat(message))
|
||||
debugFlags.logMessages.set(debugFlags.logMessages.get().concat(message))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -82,7 +82,7 @@ if (typeof window !== 'undefined') {
|
|||
if (typeof Element !== 'undefined') {
|
||||
const nativeElementRemoveChild = Element.prototype.removeChild
|
||||
react('element removal logging', () => {
|
||||
if (debugFlags.elementRemovalLogging.value) {
|
||||
if (debugFlags.elementRemovalLogging.get()) {
|
||||
Element.prototype.removeChild = function <T extends Node>(this: any, child: Node): T {
|
||||
console.warn('[tldraw] removing child:', child)
|
||||
return nativeElementRemoveChild.call(this, child) as T
|
||||
|
@ -130,7 +130,7 @@ function createDebugValueBase<T>(def: DebugFlagDef<T>): DebugFlag<T> {
|
|||
if (typeof window !== 'undefined') {
|
||||
if (def.shouldStoreForSession) {
|
||||
react(`debug:${def.name}`, () => {
|
||||
const currentValue = valueAtom.value
|
||||
const currentValue = valueAtom.get()
|
||||
try {
|
||||
if (currentValue === defaultValue) {
|
||||
window.sessionStorage.removeItem(`tldraw_debug:${def.name}`)
|
||||
|
@ -145,7 +145,7 @@ function createDebugValueBase<T>(def: DebugFlagDef<T>): DebugFlag<T> {
|
|||
|
||||
Object.defineProperty(window, `tldraw${def.name.replace(/^[a-z]/, (l) => l.toUpperCase())}`, {
|
||||
get() {
|
||||
return valueAtom.value
|
||||
return valueAtom.get()
|
||||
},
|
||||
set(newValue) {
|
||||
valueAtom.set(newValue)
|
||||
|
|
|
@ -37,7 +37,7 @@ export function loopToHtmlElement(elm: Element): HTMLElement {
|
|||
*/
|
||||
export function preventDefault(event: React.BaseSyntheticEvent | Event) {
|
||||
event.preventDefault()
|
||||
if (debugFlags.preventDefaultLogging.value) {
|
||||
if (debugFlags.preventDefaultLogging.get()) {
|
||||
console.warn('preventDefault called on event:', event)
|
||||
}
|
||||
}
|
||||
|
@ -48,11 +48,11 @@ export function setPointerCapture(
|
|||
event: React.PointerEvent<Element> | PointerEvent
|
||||
) {
|
||||
element.setPointerCapture(event.pointerId)
|
||||
if (debugFlags.pointerCaptureTracking.value) {
|
||||
const trackingObj = debugFlags.pointerCaptureTrackingObject.value
|
||||
if (debugFlags.pointerCaptureTracking.get()) {
|
||||
const trackingObj = debugFlags.pointerCaptureTrackingObject.get()
|
||||
trackingObj.set(element, (trackingObj.get(element) ?? 0) + 1)
|
||||
}
|
||||
if (debugFlags.pointerCaptureLogging.value) {
|
||||
if (debugFlags.pointerCaptureLogging.get()) {
|
||||
console.warn('setPointerCapture called on element:', element, event)
|
||||
}
|
||||
}
|
||||
|
@ -67,8 +67,8 @@ export function releasePointerCapture(
|
|||
}
|
||||
|
||||
element.releasePointerCapture(event.pointerId)
|
||||
if (debugFlags.pointerCaptureTracking.value) {
|
||||
const trackingObj = debugFlags.pointerCaptureTrackingObject.value
|
||||
if (debugFlags.pointerCaptureTracking.get()) {
|
||||
const trackingObj = debugFlags.pointerCaptureTrackingObject.get()
|
||||
if (trackingObj.get(element) === 1) {
|
||||
trackingObj.delete(element)
|
||||
} else if (trackingObj.has(element)) {
|
||||
|
@ -77,7 +77,7 @@ export function releasePointerCapture(
|
|||
console.warn('Release without capture')
|
||||
}
|
||||
}
|
||||
if (debugFlags.pointerCaptureLogging.value) {
|
||||
if (debugFlags.pointerCaptureLogging.get()) {
|
||||
console.warn('releasePointerCapture called on element:', element, event)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -359,7 +359,7 @@ export class TLLocalSyncClient {
|
|||
snapshot: this.store.serialize(),
|
||||
didCancel: () => this.didDispose,
|
||||
sessionId: this.sessionId,
|
||||
sessionStateSnapshot: this.$sessionStateSnapshot.value,
|
||||
sessionStateSnapshot: this.$sessionStateSnapshot.get(),
|
||||
})
|
||||
} else {
|
||||
const diffs = squashRecordDiffs(
|
||||
|
@ -371,7 +371,7 @@ export class TLLocalSyncClient {
|
|||
schema: this.store.schema,
|
||||
didCancel: () => this.didDispose,
|
||||
sessionId: this.sessionId,
|
||||
sessionStateSnapshot: this.$sessionStateSnapshot.value,
|
||||
sessionStateSnapshot: this.$sessionStateSnapshot.get(),
|
||||
})
|
||||
}
|
||||
this.didLastWriteError = false
|
||||
|
|
|
@ -114,10 +114,12 @@ export interface Signal<Value, Diff = unknown> {
|
|||
__unsafe__getWithoutCapture(): Value;
|
||||
// @internal (undocumented)
|
||||
children: ArraySet<Child>;
|
||||
get(): Value;
|
||||
getDiffSince(epoch: number): Diff[] | RESET_VALUE;
|
||||
lastChangedEpoch: number;
|
||||
name: string;
|
||||
readonly value: Value;
|
||||
// @deprecated (undocumented)
|
||||
value: Value;
|
||||
}
|
||||
|
||||
// @public
|
||||
|
|
|
@ -2139,6 +2139,34 @@
|
|||
"parameters": [],
|
||||
"name": "__unsafe__getWithoutCapture"
|
||||
},
|
||||
{
|
||||
"kind": "MethodSignature",
|
||||
"canonicalReference": "@tldraw/state!Signal#get:member(1)",
|
||||
"docComment": "/**\n * The current value of the signal. This is a reactive value, and will update when the signal changes. Any computed signal that depends on this signal will be lazily recomputed if this signal changes. Any effect that depends on this signal will be rescheduled if this signal changes.\n */\n",
|
||||
"excerptTokens": [
|
||||
{
|
||||
"kind": "Content",
|
||||
"text": "get(): "
|
||||
},
|
||||
{
|
||||
"kind": "Content",
|
||||
"text": "Value"
|
||||
},
|
||||
{
|
||||
"kind": "Content",
|
||||
"text": ";"
|
||||
}
|
||||
],
|
||||
"isOptional": false,
|
||||
"returnTypeTokenRange": {
|
||||
"startIndex": 1,
|
||||
"endIndex": 2
|
||||
},
|
||||
"releaseTag": "Public",
|
||||
"overloadIndex": 1,
|
||||
"parameters": [],
|
||||
"name": "get"
|
||||
},
|
||||
{
|
||||
"kind": "MethodSignature",
|
||||
"canonicalReference": "@tldraw/state!Signal#getDiffSince:member(1)",
|
||||
|
@ -2246,11 +2274,11 @@
|
|||
{
|
||||
"kind": "PropertySignature",
|
||||
"canonicalReference": "@tldraw/state!Signal#value:member",
|
||||
"docComment": "/**\n * The current value of the signal. This is a reactive value, and will update when the signal changes. Any computed signal that depends on this signal will be lazily recomputed if this signal changes. Any effect that depends on this signal will be rescheduled if this signal changes.\n */\n",
|
||||
"docComment": "/**\n * @deprecated\n *\n * Use [[Signal.get]] instead.\n */\n",
|
||||
"excerptTokens": [
|
||||
{
|
||||
"kind": "Content",
|
||||
"text": "readonly value: "
|
||||
"text": "value: "
|
||||
},
|
||||
{
|
||||
"kind": "Content",
|
||||
|
@ -2261,7 +2289,7 @@
|
|||
"text": ";"
|
||||
}
|
||||
],
|
||||
"isReadonly": true,
|
||||
"isReadonly": false,
|
||||
"isOptional": false,
|
||||
"releaseTag": "Public",
|
||||
"name": "value",
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import { ArraySet } from './ArraySet'
|
||||
import { HistoryBuffer } from './HistoryBuffer'
|
||||
import { maybeCaptureParent } from './capture'
|
||||
import { EMPTY_ARRAY, equals } from './helpers'
|
||||
import { HistoryBuffer } from './HistoryBuffer'
|
||||
import { advanceGlobalEpoch, atomDidChange, globalEpoch } from './transactions'
|
||||
import { Child, ComputeDiff, RESET_VALUE, Signal } from './types'
|
||||
import { logDotValueWarning } from './warnings'
|
||||
|
||||
/**
|
||||
* The options to configure an atom, passed into the [[atom]] function.
|
||||
|
@ -99,11 +100,19 @@ export class _Atom<Value, Diff = unknown> implements Atom<Value, Diff> {
|
|||
return this.current
|
||||
}
|
||||
|
||||
get value() {
|
||||
get() {
|
||||
maybeCaptureParent(this)
|
||||
return this.current
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use [[Atom.get]] instead.
|
||||
*/
|
||||
get value() {
|
||||
logDotValueWarning()
|
||||
return this.get()
|
||||
}
|
||||
|
||||
set(value: Value, diff?: Diff): Value {
|
||||
// If the value has not changed, do nothing.
|
||||
if (this.isEqual?.(this.current, value) ?? equals(this.current, value)) {
|
||||
|
|
|
@ -6,6 +6,7 @@ import { GLOBAL_START_EPOCH } from './constants'
|
|||
import { EMPTY_ARRAY, equals, haveParentsChanged } from './helpers'
|
||||
import { globalEpoch } from './transactions'
|
||||
import { Child, ComputeDiff, RESET_VALUE, Signal } from './types'
|
||||
import { logComputedGetterWarning, logDotValueWarning } from './warnings'
|
||||
|
||||
const UNINITIALIZED = Symbol('UNINITIALIZED')
|
||||
/**
|
||||
|
@ -202,16 +203,24 @@ export class _Computed<Value, Diff = unknown> implements Computed<Value, Diff> {
|
|||
}
|
||||
}
|
||||
|
||||
get value(): Value {
|
||||
get(): Value {
|
||||
const value = this.__unsafe__getWithoutCapture()
|
||||
maybeCaptureParent(this)
|
||||
return value
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use [[get]] instead.
|
||||
*/
|
||||
get value() {
|
||||
logDotValueWarning()
|
||||
return this.get()
|
||||
}
|
||||
|
||||
getDiffSince(epoch: number): RESET_VALUE | Diff[] {
|
||||
// need to call .value to ensure both that this derivation is up to date
|
||||
// and that tracking happens correctly
|
||||
this.value
|
||||
this.get()
|
||||
|
||||
if (epoch >= this.lastChangedEpoch) {
|
||||
return EMPTY_ARRAY
|
||||
|
@ -221,11 +230,53 @@ export class _Computed<Value, Diff = unknown> implements Computed<Value, Diff> {
|
|||
}
|
||||
}
|
||||
|
||||
function computedMethodAnnotation(
|
||||
options: ComputedOptions<any, any> = {},
|
||||
_target: any,
|
||||
key: string,
|
||||
descriptor: PropertyDescriptor
|
||||
) {
|
||||
const originalMethod = descriptor.value
|
||||
const derivationKey = Symbol.for('__@tldraw/state__computed__' + key)
|
||||
|
||||
descriptor.value = function (this: any) {
|
||||
let d = this[derivationKey] as _Computed<any> | undefined
|
||||
|
||||
if (!d) {
|
||||
d = new _Computed(key, originalMethod!.bind(this) as any, options)
|
||||
Object.defineProperty(this, derivationKey, {
|
||||
enumerable: false,
|
||||
configurable: false,
|
||||
writable: false,
|
||||
value: d,
|
||||
})
|
||||
}
|
||||
return d.get()
|
||||
}
|
||||
descriptor.value[isComputedMethodKey] = true
|
||||
|
||||
return descriptor
|
||||
}
|
||||
|
||||
function computedAnnotation(
|
||||
options: ComputedOptions<any, any> = {},
|
||||
_target: any,
|
||||
key: string,
|
||||
descriptor: PropertyDescriptor
|
||||
) {
|
||||
if (descriptor.get) {
|
||||
logComputedGetterWarning()
|
||||
return computedGetterAnnotation(options, _target, key, descriptor)
|
||||
} else {
|
||||
return computedMethodAnnotation(options, _target, key, descriptor)
|
||||
}
|
||||
}
|
||||
|
||||
function computedGetterAnnotation(
|
||||
options: ComputedOptions<any, any> = {},
|
||||
_target: any,
|
||||
key: string,
|
||||
descriptor: PropertyDescriptor
|
||||
) {
|
||||
const originalMethod = descriptor.get
|
||||
const derivationKey = Symbol.for('__@tldraw/state__computed__' + key)
|
||||
|
@ -242,12 +293,14 @@ function computedAnnotation(
|
|||
value: d,
|
||||
})
|
||||
}
|
||||
return d.value
|
||||
return d.get()
|
||||
}
|
||||
|
||||
return descriptor
|
||||
}
|
||||
|
||||
const isComputedMethodKey = '@@__isComputedMethod__@@'
|
||||
|
||||
/**
|
||||
* Retrieves the underlying computed instance for a given property created with the [[computed]]
|
||||
* decorator.
|
||||
|
@ -278,12 +331,15 @@ export function getComputedInstance<Obj extends object, Prop extends keyof Obj>(
|
|||
obj: Obj,
|
||||
propertyName: Prop
|
||||
): Computed<Obj[Prop]> {
|
||||
// deref to make sure it exists first
|
||||
const key = Symbol.for('__@tldraw/state__computed__' + propertyName.toString())
|
||||
let inst = obj[key as keyof typeof obj] as _Computed<Obj[Prop]> | undefined
|
||||
if (!inst) {
|
||||
// deref to make sure it exists first
|
||||
obj[propertyName]
|
||||
const val = obj[propertyName]
|
||||
if (typeof val === 'function' && (val as any)[isComputedMethodKey]) {
|
||||
val.call(obj)
|
||||
}
|
||||
|
||||
inst = obj[key as keyof typeof obj] as _Computed<Obj[Prop]> | undefined
|
||||
}
|
||||
return inst as any
|
||||
|
|
|
@ -6,7 +6,7 @@ describe(EffectScheduler, () => {
|
|||
const a = atom('a', 1)
|
||||
let numReactions = 0
|
||||
const scheduler = new EffectScheduler('test', () => {
|
||||
a.value
|
||||
a.get()
|
||||
numReactions++
|
||||
})
|
||||
scheduler.attach()
|
||||
|
@ -26,7 +26,7 @@ describe(EffectScheduler, () => {
|
|||
const a = atom('a', 1)
|
||||
let numReactions = 0
|
||||
const scheduler = new EffectScheduler('test', () => {
|
||||
a.value
|
||||
a.get()
|
||||
numReactions++
|
||||
})
|
||||
scheduler.attach()
|
||||
|
@ -51,7 +51,7 @@ describe(EffectScheduler, () => {
|
|||
const scheduler = new EffectScheduler(
|
||||
'test',
|
||||
() => {
|
||||
a.value
|
||||
a.get()
|
||||
numReactions++
|
||||
},
|
||||
{
|
||||
|
|
|
@ -7,14 +7,14 @@ describe('atoms', () => {
|
|||
it('contain data', () => {
|
||||
const a = atom('', 1)
|
||||
|
||||
expect(a.value).toBe(1)
|
||||
expect(a.get()).toBe(1)
|
||||
})
|
||||
it('can be updated', () => {
|
||||
const a = atom('', 1)
|
||||
|
||||
a.set(2)
|
||||
|
||||
expect(a.value).toBe(2)
|
||||
expect(a.get()).toBe(2)
|
||||
})
|
||||
it('will not advance the global epoch on creation', () => {
|
||||
const startEpoch = globalEpoch
|
||||
|
@ -115,7 +115,7 @@ describe('atoms', () => {
|
|||
|
||||
a.update((value) => value + 1)
|
||||
|
||||
expect(a.value).toBe(2)
|
||||
expect(a.get()).toBe(2)
|
||||
expect(globalEpoch).toBe(startEpoch + 1)
|
||||
})
|
||||
it('supports passing diffs in .set', () => {
|
||||
|
@ -159,7 +159,7 @@ describe('reacting to atoms', () => {
|
|||
|
||||
let val = 0
|
||||
const r = reactor('', () => {
|
||||
val = a.value
|
||||
val = a.get()
|
||||
})
|
||||
|
||||
expect(val).toBe(0)
|
||||
|
@ -177,7 +177,7 @@ describe('reacting to atoms', () => {
|
|||
a.set(2342)
|
||||
|
||||
expect(val).toBe(939)
|
||||
expect(a.value).toBe(2342)
|
||||
expect(a.get()).toBe(2342)
|
||||
})
|
||||
})
|
||||
|
||||
|
@ -189,11 +189,11 @@ test('isEqual can provide custom equality checks', () => {
|
|||
|
||||
a.set(bar)
|
||||
|
||||
expect(a.value).toBe(bar)
|
||||
expect(a.get()).toBe(bar)
|
||||
|
||||
const b = atom('b', foo, { isEqual: (a, b) => a.hello === b.hello })
|
||||
|
||||
b.set(bar)
|
||||
|
||||
expect(b.value).toBe(foo)
|
||||
expect(b.get()).toBe(foo)
|
||||
})
|
||||
|
|
|
@ -172,7 +172,7 @@ describe(unsafe__withoutCapture, () => {
|
|||
const atomC = atom('c', 1)
|
||||
|
||||
const child = computed('', () => {
|
||||
return atomA.value + atomB.value + unsafe__withoutCapture(() => atomC.value)
|
||||
return atomA.get() + atomB.get() + unsafe__withoutCapture(() => atomC.get())
|
||||
})
|
||||
|
||||
let lastValue: number | undefined
|
||||
|
@ -180,7 +180,7 @@ describe(unsafe__withoutCapture, () => {
|
|||
|
||||
react('', () => {
|
||||
numReactions++
|
||||
lastValue = child.value
|
||||
lastValue = child.get()
|
||||
})
|
||||
|
||||
expect(lastValue).toBe(3)
|
||||
|
@ -213,7 +213,7 @@ describe(unsafe__withoutCapture, () => {
|
|||
|
||||
react('', () => {
|
||||
numReactions++
|
||||
lastValue = atomA.value + atomB.value + unsafe__withoutCapture(() => atomC.value)
|
||||
lastValue = atomA.get() + atomB.get() + unsafe__withoutCapture(() => atomC.get())
|
||||
})
|
||||
|
||||
expect(lastValue).toBe(3)
|
||||
|
|
|
@ -17,9 +17,9 @@ describe('derivations', () => {
|
|||
|
||||
expect(derive).toHaveBeenCalledTimes(0)
|
||||
|
||||
expect(derivation.value).toBe(1)
|
||||
expect(derivation.value).toBe(1)
|
||||
expect(derivation.value).toBe(1)
|
||||
expect(derivation.get()).toBe(1)
|
||||
expect(derivation.get()).toBe(1)
|
||||
expect(derivation.get()).toBe(1)
|
||||
|
||||
expect(derive).toHaveBeenCalledTimes(1)
|
||||
|
||||
|
@ -28,13 +28,13 @@ describe('derivations', () => {
|
|||
advanceGlobalEpoch()
|
||||
advanceGlobalEpoch()
|
||||
|
||||
expect(derivation.value).toBe(1)
|
||||
expect(derivation.value).toBe(1)
|
||||
expect(derivation.value).toBe(1)
|
||||
expect(derivation.get()).toBe(1)
|
||||
expect(derivation.get()).toBe(1)
|
||||
expect(derivation.get()).toBe(1)
|
||||
advanceGlobalEpoch()
|
||||
advanceGlobalEpoch()
|
||||
expect(derivation.value).toBe(1)
|
||||
expect(derivation.value).toBe(1)
|
||||
expect(derivation.get()).toBe(1)
|
||||
expect(derivation.get()).toBe(1)
|
||||
|
||||
expect(derive).toHaveBeenCalledTimes(1)
|
||||
|
||||
|
@ -45,18 +45,18 @@ describe('derivations', () => {
|
|||
|
||||
it('will update when parent atoms update', () => {
|
||||
const a = atom('', 1)
|
||||
const double = jest.fn(() => a.value * 2)
|
||||
const double = jest.fn(() => a.get() * 2)
|
||||
const derivation = computed('', double)
|
||||
const startEpoch = globalEpoch
|
||||
expect(double).toHaveBeenCalledTimes(0)
|
||||
|
||||
expect(derivation.value).toBe(2)
|
||||
expect(derivation.get()).toBe(2)
|
||||
expect(double).toHaveBeenCalledTimes(1)
|
||||
|
||||
expect(derivation.lastChangedEpoch).toBe(startEpoch)
|
||||
|
||||
expect(derivation.value).toBe(2)
|
||||
expect(derivation.value).toBe(2)
|
||||
expect(derivation.get()).toBe(2)
|
||||
expect(derivation.get()).toBe(2)
|
||||
expect(double).toHaveBeenCalledTimes(1)
|
||||
expect(derivation.lastChangedEpoch).toBe(startEpoch)
|
||||
|
||||
|
@ -66,12 +66,12 @@ describe('derivations', () => {
|
|||
|
||||
expect(double).toHaveBeenCalledTimes(1)
|
||||
expect(derivation.lastChangedEpoch).toBe(startEpoch)
|
||||
expect(derivation.value).toBe(4)
|
||||
expect(derivation.get()).toBe(4)
|
||||
|
||||
expect(double).toHaveBeenCalledTimes(2)
|
||||
expect(derivation.lastChangedEpoch).toBe(nextEpoch)
|
||||
|
||||
expect(derivation.value).toBe(4)
|
||||
expect(derivation.get()).toBe(4)
|
||||
expect(double).toHaveBeenCalledTimes(2)
|
||||
expect(derivation.lastChangedEpoch).toBe(nextEpoch)
|
||||
|
||||
|
@ -81,7 +81,7 @@ describe('derivations', () => {
|
|||
unrelatedAtom.set(3)
|
||||
unrelatedAtom.set(5)
|
||||
|
||||
expect(derivation.value).toBe(4)
|
||||
expect(derivation.get()).toBe(4)
|
||||
expect(double).toHaveBeenCalledTimes(2)
|
||||
expect(derivation.lastChangedEpoch).toBe(nextEpoch)
|
||||
})
|
||||
|
@ -90,14 +90,14 @@ describe('derivations', () => {
|
|||
const startEpoch = globalEpoch
|
||||
const a = atom('', 1)
|
||||
|
||||
const derivation = computed('', () => a.value * 2, {
|
||||
const derivation = computed('', () => a.get() * 2, {
|
||||
historyLength: 3,
|
||||
computeDiff: (a, b) => {
|
||||
return b - a
|
||||
},
|
||||
})
|
||||
|
||||
derivation.value
|
||||
derivation.get()
|
||||
|
||||
expect(derivation.getDiffSince(startEpoch)).toHaveLength(0)
|
||||
|
||||
|
@ -123,37 +123,37 @@ describe('derivations', () => {
|
|||
const a = atom('', 1)
|
||||
|
||||
const floor = jest.fn((n: number) => Math.floor(n))
|
||||
const derivation = computed('', () => floor(a.value), {
|
||||
const derivation = computed('', () => floor(a.get()), {
|
||||
historyLength: 3,
|
||||
computeDiff: (a, b) => {
|
||||
return b - a
|
||||
},
|
||||
})
|
||||
|
||||
expect(derivation.value).toBe(1)
|
||||
expect(derivation.get()).toBe(1)
|
||||
expect(derivation.getDiffSince(startEpoch)).toHaveLength(0)
|
||||
|
||||
a.set(1.2)
|
||||
|
||||
expect(derivation.value).toBe(1)
|
||||
expect(derivation.get()).toBe(1)
|
||||
expect(derivation.getDiffSince(startEpoch)).toHaveLength(0)
|
||||
expect(floor).toHaveBeenCalledTimes(2)
|
||||
|
||||
a.set(1.5)
|
||||
|
||||
expect(derivation.value).toBe(1)
|
||||
expect(derivation.get()).toBe(1)
|
||||
expect(derivation.getDiffSince(startEpoch)).toHaveLength(0)
|
||||
expect(floor).toHaveBeenCalledTimes(3)
|
||||
|
||||
a.set(1.9)
|
||||
|
||||
expect(derivation.value).toBe(1)
|
||||
expect(derivation.get()).toBe(1)
|
||||
expect(derivation.getDiffSince(startEpoch)).toHaveLength(0)
|
||||
expect(floor).toHaveBeenCalledTimes(4)
|
||||
|
||||
a.set(2.3)
|
||||
|
||||
expect(derivation.value).toBe(2)
|
||||
expect(derivation.get()).toBe(2)
|
||||
expect(derivation.getDiffSince(startEpoch)).toEqual([+1])
|
||||
expect(floor).toHaveBeenCalledTimes(5)
|
||||
})
|
||||
|
@ -162,15 +162,15 @@ describe('derivations', () => {
|
|||
const startEpoch = globalEpoch
|
||||
const a = atom('', 1)
|
||||
|
||||
const double = jest.fn(() => a.value * 2)
|
||||
const double = jest.fn(() => a.get() * 2)
|
||||
const derivation = computed('', double)
|
||||
|
||||
derivation.value
|
||||
derivation.get()
|
||||
|
||||
expect(getLastCheckedEpoch(derivation)).toEqual(startEpoch)
|
||||
|
||||
advanceGlobalEpoch()
|
||||
derivation.value
|
||||
derivation.get()
|
||||
|
||||
expect(getLastCheckedEpoch(derivation)).toBeGreaterThan(startEpoch)
|
||||
|
||||
|
@ -179,16 +179,16 @@ describe('derivations', () => {
|
|||
|
||||
it('receives UNINTIALIZED as the previousValue the first time it computes', () => {
|
||||
const a = atom('', 1)
|
||||
const double = jest.fn((_prevValue) => a.value * 2)
|
||||
const double = jest.fn((_prevValue) => a.get() * 2)
|
||||
const derivation = computed('', double)
|
||||
|
||||
expect(derivation.value).toBe(2)
|
||||
expect(derivation.get()).toBe(2)
|
||||
|
||||
expect(isUninitialized(double.mock.calls[0][0])).toBe(true)
|
||||
|
||||
a.set(2)
|
||||
|
||||
expect(derivation.value).toBe(4)
|
||||
expect(derivation.get()).toBe(4)
|
||||
expect(isUninitialized(double.mock.calls[1][0])).toBe(false)
|
||||
expect(double.mock.calls[1][0]).toBe(2)
|
||||
})
|
||||
|
@ -197,17 +197,17 @@ describe('derivations', () => {
|
|||
const a = atom('', 1)
|
||||
const double = jest.fn((_prevValue, lastChangedEpoch) => {
|
||||
expect(lastChangedEpoch).toBe(derivation.lastChangedEpoch)
|
||||
return a.value * 2
|
||||
return a.get() * 2
|
||||
})
|
||||
const derivation = computed('', double)
|
||||
|
||||
expect(derivation.value).toBe(2)
|
||||
expect(derivation.get()).toBe(2)
|
||||
|
||||
const startEpoch = globalEpoch
|
||||
|
||||
a.set(2)
|
||||
|
||||
expect(derivation.value).toBe(4)
|
||||
expect(derivation.get()).toBe(4)
|
||||
expect(derivation.lastChangedEpoch).toBeGreaterThan(startEpoch)
|
||||
|
||||
expect(double).toHaveBeenCalledTimes(2)
|
||||
|
@ -221,13 +221,13 @@ describe('derivations', () => {
|
|||
let numTimesComputed = 0
|
||||
const fullName = computed('', () => {
|
||||
numTimesComputed++
|
||||
return `${firstName.value} ${lastName.value}`
|
||||
return `${firstName.get()} ${lastName.get()}`
|
||||
})
|
||||
|
||||
let numTimesReacted = 0
|
||||
let name = ''
|
||||
const r = reactor('', () => {
|
||||
name = fullName.value
|
||||
name = fullName.get()
|
||||
numTimesReacted++
|
||||
})
|
||||
|
||||
|
@ -263,7 +263,7 @@ describe('derivations', () => {
|
|||
expect(numTimesComputed).toBe(2)
|
||||
expect(numTimesReacted).toBe(2)
|
||||
expect(name).toBe('Jane Doe')
|
||||
expect(fullName.value).toBe('Wilbur Jones')
|
||||
expect(fullName.get()).toBe('Wilbur Jones')
|
||||
|
||||
expect(numTimesComputed).toBe(3)
|
||||
expect(numTimesReacted).toBe(2)
|
||||
|
@ -279,23 +279,23 @@ describe('derivations', () => {
|
|||
const firstName = atom('', 'John')
|
||||
const lastName = atom('', 'Doe')
|
||||
|
||||
const fullName = computed('', () => `${firstName.value} ${lastName.value}`)
|
||||
const fullName = computed('', () => `${firstName.get()} ${lastName.get()}`)
|
||||
|
||||
transaction((rollback) => {
|
||||
firstName.set('Jane')
|
||||
lastName.set('Jones')
|
||||
expect(fullName.value).toBe('Jane Jones')
|
||||
expect(fullName.get()).toBe('Jane Jones')
|
||||
rollback()
|
||||
})
|
||||
|
||||
expect(fullName.value).toBe('John Doe')
|
||||
expect(fullName.get()).toBe('John Doe')
|
||||
})
|
||||
|
||||
it('will add history items if a transaction is aborted', () => {
|
||||
const a = atom('', 1)
|
||||
const b = atom('', 1)
|
||||
|
||||
const c = computed('', () => a.value + b.value, {
|
||||
const c = computed('', () => a.get() + b.get(), {
|
||||
historyLength: 3,
|
||||
computeDiff: (a, b) => b - a,
|
||||
})
|
||||
|
@ -317,7 +317,7 @@ describe('derivations', () => {
|
|||
const a = atom('', 1)
|
||||
const b = atom('', 1)
|
||||
|
||||
const c = computed('', () => a.value + b.value, {
|
||||
const c = computed('', () => a.get() + b.get(), {
|
||||
historyLength: 3,
|
||||
computeDiff: (a, b) => b - a,
|
||||
})
|
||||
|
@ -341,7 +341,7 @@ function getIncrementalRecordMapper<In, Out>(
|
|||
mapper: (t: In, k: string) => Out
|
||||
): Computed<Record<string, Out>> {
|
||||
function computeFromScratch() {
|
||||
const input = obj.value
|
||||
const input = obj.get()
|
||||
return Object.fromEntries(Object.entries(input).map(([k, v]) => [k, mapper(v, k)]))
|
||||
}
|
||||
return computed('', (previousValue, lastComputedEpoch) => {
|
||||
|
@ -356,7 +356,7 @@ function getIncrementalRecordMapper<In, Out>(
|
|||
return previousValue
|
||||
}
|
||||
|
||||
const newUpstream = obj.value
|
||||
const newUpstream = obj.get()
|
||||
|
||||
const result = { ...previousValue } as Record<string, Out>
|
||||
|
||||
|
@ -442,7 +442,7 @@ describe('incremental derivations', () => {
|
|||
|
||||
const doubledNodes = getIncrementalRecordMapper(nodes, mapper)
|
||||
|
||||
expect(doubledNodes.value).toEqual({
|
||||
expect(doubledNodes.get()).toEqual({
|
||||
a: 2,
|
||||
b: 4,
|
||||
c: 6,
|
||||
|
@ -453,7 +453,7 @@ describe('incremental derivations', () => {
|
|||
|
||||
nodes.update((ns) => ({ ...ns, a: 10 }))
|
||||
|
||||
expect(doubledNodes.value).toEqual({
|
||||
expect(doubledNodes.get()).toEqual({
|
||||
a: 20,
|
||||
b: 4,
|
||||
c: 6,
|
||||
|
@ -466,7 +466,7 @@ describe('incremental derivations', () => {
|
|||
// remove d
|
||||
nodes.update(({ d: _d, ...others }) => others)
|
||||
|
||||
expect(doubledNodes.value).toEqual({
|
||||
expect(doubledNodes.get()).toEqual({
|
||||
a: 20,
|
||||
b: 4,
|
||||
c: 6,
|
||||
|
@ -476,7 +476,7 @@ describe('incremental derivations', () => {
|
|||
|
||||
nodes.update((ns) => ({ ...ns, f: 50, g: 60 }))
|
||||
|
||||
expect(doubledNodes.value).toEqual({
|
||||
expect(doubledNodes.get()).toEqual({
|
||||
a: 20,
|
||||
b: 4,
|
||||
c: 6,
|
||||
|
@ -486,9 +486,9 @@ describe('incremental derivations', () => {
|
|||
})
|
||||
expect(mapper).toHaveBeenCalledTimes(8)
|
||||
|
||||
nodes.set({ ...nodes.value })
|
||||
nodes.set({ ...nodes.get() })
|
||||
// no changes so no new calls to mapper
|
||||
expect(doubledNodes.value).toEqual({
|
||||
expect(doubledNodes.get()).toEqual({
|
||||
a: 20,
|
||||
b: 4,
|
||||
c: 6,
|
||||
|
@ -510,7 +510,7 @@ describe('incremental derivations', () => {
|
|||
// nothing was called because we didn't deref yet
|
||||
expect(mapper).toHaveBeenCalledTimes(8)
|
||||
|
||||
expect(doubledNodes.value).toEqual({
|
||||
expect(doubledNodes.get()).toEqual({
|
||||
a: 8,
|
||||
b: 18,
|
||||
c: 34,
|
||||
|
@ -527,18 +527,18 @@ describe('computed as a decorator', () => {
|
|||
class Foo {
|
||||
a = atom('a', 1)
|
||||
@computed
|
||||
get b() {
|
||||
return this.a.value * 2
|
||||
getB() {
|
||||
return this.a.get() * 2
|
||||
}
|
||||
}
|
||||
|
||||
const foo = new Foo()
|
||||
|
||||
expect(foo.b).toBe(2)
|
||||
expect(foo.getB()).toBe(2)
|
||||
|
||||
foo.a.set(2)
|
||||
|
||||
expect(foo.b).toBe(4)
|
||||
expect(foo.getB()).toBe(4)
|
||||
})
|
||||
|
||||
it('can be used to decorate a class with custom properties', () => {
|
||||
|
@ -547,20 +547,20 @@ describe('computed as a decorator', () => {
|
|||
a = atom('a', 1)
|
||||
|
||||
@computed({ isEqual: (a, b) => a.b === b.b })
|
||||
get b() {
|
||||
getB() {
|
||||
numComputations++
|
||||
return { b: this.a.value * this.a.value }
|
||||
return { b: this.a.get() * this.a.get() }
|
||||
}
|
||||
}
|
||||
|
||||
const foo = new Foo()
|
||||
|
||||
const firstVal = foo.b
|
||||
const firstVal = foo.getB()
|
||||
expect(firstVal).toEqual({ b: 1 })
|
||||
|
||||
foo.a.set(-1)
|
||||
|
||||
const secondVal = foo.b
|
||||
const secondVal = foo.getB()
|
||||
expect(secondVal).toEqual({ b: 1 })
|
||||
|
||||
expect(firstVal).toBe(secondVal)
|
||||
|
@ -574,14 +574,14 @@ describe(getComputedInstance, () => {
|
|||
a = atom('a', 1)
|
||||
|
||||
@computed({ isEqual: (a, b) => a.b === b.b })
|
||||
get b() {
|
||||
return { b: this.a.value * this.a.value }
|
||||
getB() {
|
||||
return { b: this.a.get() * this.a.get() }
|
||||
}
|
||||
}
|
||||
|
||||
const foo = new Foo()
|
||||
|
||||
const bInst = getComputedInstance(foo, 'b')
|
||||
const bInst = getComputedInstance(foo, 'getB')
|
||||
|
||||
expect(bInst).toBeDefined()
|
||||
expect(bInst).toBeInstanceOf(_Computed)
|
||||
|
@ -593,18 +593,18 @@ describe('computed isEqual', () => {
|
|||
const isEqual = jest.fn((a, b) => a === b)
|
||||
|
||||
const a = atom('a', 1)
|
||||
const b = computed('b', () => a.value * 2, { isEqual })
|
||||
const b = computed('b', () => a.get() * 2, { isEqual })
|
||||
|
||||
expect(b.value).toBe(2)
|
||||
expect(b.get()).toBe(2)
|
||||
expect(isEqual).not.toHaveBeenCalled()
|
||||
expect(b.value).toBe(2)
|
||||
expect(b.get()).toBe(2)
|
||||
expect(isEqual).not.toHaveBeenCalled()
|
||||
|
||||
a.set(2)
|
||||
|
||||
expect(b.value).toBe(4)
|
||||
expect(b.get()).toBe(4)
|
||||
expect(isEqual).toHaveBeenCalledTimes(1)
|
||||
expect(b.value).toBe(4)
|
||||
expect(b.get()).toBe(4)
|
||||
expect(isEqual).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -67,7 +67,7 @@ type Letter = (typeof LETTERS)[number]
|
|||
|
||||
const unpack = (value: unknown): Letter => {
|
||||
if (isComputed(value) || isAtom(value)) {
|
||||
return unpack(value.value) as Letter
|
||||
return unpack(value.get()) as Letter
|
||||
}
|
||||
return value as Letter
|
||||
}
|
||||
|
@ -307,15 +307,15 @@ class Test {
|
|||
break
|
||||
}
|
||||
case 'deref_atom_in_derivation': {
|
||||
this.systemState.atomsInDerivations[op.id].value
|
||||
this.systemState.atomsInDerivations[op.id].get()
|
||||
break
|
||||
}
|
||||
case 'deref_derivation': {
|
||||
this.systemState.derivations[op.id].derivation.value
|
||||
this.systemState.derivations[op.id].derivation.get()
|
||||
break
|
||||
}
|
||||
case 'deref_derivation_in_derivation': {
|
||||
this.systemState.derivationsInDerivations[op.id].value
|
||||
this.systemState.derivationsInDerivations[op.id].get()
|
||||
break
|
||||
}
|
||||
case 'update_atom_in_atom': {
|
||||
|
|
|
@ -6,7 +6,7 @@ describe('reactors', () => {
|
|||
it('can be started and stopped ', () => {
|
||||
const a = atom('', 1)
|
||||
const r = reactor('', () => {
|
||||
a.value
|
||||
a.get()
|
||||
})
|
||||
expect(r.scheduler.isActivelyListening).toBe(false)
|
||||
r.start()
|
||||
|
@ -20,7 +20,7 @@ describe('reactors', () => {
|
|||
it('can not set atom values directly yet', () => {
|
||||
const a = atom('', 1)
|
||||
const r = reactor('', () => {
|
||||
if (a.value < +Infinity) {
|
||||
if (a.get() < +Infinity) {
|
||||
a.update((a) => a + 1)
|
||||
}
|
||||
})
|
||||
|
@ -34,8 +34,8 @@ describe('reactors', () => {
|
|||
const atomB = atom('', 1)
|
||||
|
||||
const react = jest.fn(() => {
|
||||
atomA.value
|
||||
atomB.value
|
||||
atomA.get()
|
||||
atomB.get()
|
||||
})
|
||||
const r = reactor('', react)
|
||||
|
||||
|
@ -53,7 +53,7 @@ describe('reactors', () => {
|
|||
it('will not react if stopped', () => {
|
||||
const a = atom('', 1)
|
||||
const react = jest.fn(() => {
|
||||
a.value
|
||||
a.get()
|
||||
})
|
||||
const r = reactor('', react)
|
||||
|
||||
|
@ -66,7 +66,7 @@ describe('reactors', () => {
|
|||
const a = atom('', 1)
|
||||
const react = jest
|
||||
.fn(() => {
|
||||
a.value
|
||||
a.get()
|
||||
})
|
||||
.mockName('react')
|
||||
const r = reactor('', react)
|
||||
|
@ -85,7 +85,7 @@ describe('stopping', () => {
|
|||
const a = atom('', 1)
|
||||
|
||||
const rfn = jest.fn(() => {
|
||||
a.value
|
||||
a.get()
|
||||
})
|
||||
const r = reactor('', rfn)
|
||||
|
||||
|
@ -120,7 +120,7 @@ test('.start() by default does not trigger a reaction if nothing has changed', (
|
|||
const a = atom('', 1)
|
||||
|
||||
const rfn = jest.fn(() => {
|
||||
a.value
|
||||
a.get()
|
||||
})
|
||||
|
||||
const r = reactor('', rfn)
|
||||
|
@ -139,7 +139,7 @@ test('.start({force: true}) will trigger a reaction even if nothing has changed'
|
|||
const a = atom('', 1)
|
||||
|
||||
const rfn = jest.fn(() => {
|
||||
a.value
|
||||
a.get()
|
||||
})
|
||||
|
||||
const r = reactor('', rfn)
|
||||
|
|
|
@ -11,14 +11,14 @@ describe('transactions', () => {
|
|||
let numTimesComputed = 0
|
||||
const fullName = computed('', () => {
|
||||
numTimesComputed++
|
||||
return `${firstName.value} ${lastName.value}`
|
||||
return `${firstName.get()} ${lastName.get()}`
|
||||
})
|
||||
|
||||
let numTimesReacted = 0
|
||||
let name = ''
|
||||
|
||||
react('', () => {
|
||||
name = fullName.value
|
||||
name = fullName.get()
|
||||
numTimesReacted++
|
||||
})
|
||||
|
||||
|
@ -35,7 +35,7 @@ describe('transactions', () => {
|
|||
expect(numTimesComputed).toBe(1)
|
||||
expect(numTimesReacted).toBe(1)
|
||||
expect(name).toBe('John Doe')
|
||||
expect(fullName.value).toBe('Wilbur Jones')
|
||||
expect(fullName.get()).toBe('Wilbur Jones')
|
||||
|
||||
expect(numTimesComputed).toBe(2)
|
||||
expect(numTimesReacted).toBe(1)
|
||||
|
@ -48,7 +48,7 @@ describe('transactions', () => {
|
|||
expect(numTimesComputed).toBe(3)
|
||||
expect(numTimesReacted).toBe(2)
|
||||
|
||||
expect(fullName.value).toBe('John Doe')
|
||||
expect(fullName.get()).toBe('John Doe')
|
||||
expect(name).toBe('John Doe')
|
||||
})
|
||||
|
||||
|
@ -72,8 +72,8 @@ describe('transactions', () => {
|
|||
rollback()
|
||||
})
|
||||
|
||||
expect(atomA.value).toBe(0)
|
||||
expect(atomB.value).toBe(0)
|
||||
expect(atomA.get()).toBe(0)
|
||||
expect(atomB.get()).toBe(0)
|
||||
|
||||
transaction((rollback) => {
|
||||
atomA.set(1)
|
||||
|
@ -90,8 +90,8 @@ describe('transactions', () => {
|
|||
rollback()
|
||||
})
|
||||
|
||||
expect(atomA.value).toBe(0)
|
||||
expect(atomB.value).toBe(0)
|
||||
expect(atomA.get()).toBe(0)
|
||||
expect(atomB.get()).toBe(0)
|
||||
|
||||
transaction((rollback) => {
|
||||
atomA.set(1)
|
||||
|
@ -107,8 +107,8 @@ describe('transactions', () => {
|
|||
rollback()
|
||||
})
|
||||
|
||||
expect(atomA.value).toBe(0)
|
||||
expect(atomB.value).toBe(0)
|
||||
expect(atomA.get()).toBe(0)
|
||||
expect(atomB.get()).toBe(0)
|
||||
|
||||
transaction(() => {
|
||||
atomA.set(1)
|
||||
|
@ -125,8 +125,8 @@ describe('transactions', () => {
|
|||
})
|
||||
})
|
||||
|
||||
expect(atomA.value).toBe(1)
|
||||
expect(atomB.value).toBe(-1)
|
||||
expect(atomA.get()).toBe(1)
|
||||
expect(atomB.get()).toBe(-1)
|
||||
|
||||
transaction(() => {
|
||||
atomA.set(1)
|
||||
|
@ -142,8 +142,8 @@ describe('transactions', () => {
|
|||
})
|
||||
})
|
||||
|
||||
expect(atomA.value).toBe(2)
|
||||
expect(atomB.value).toBe(-2)
|
||||
expect(atomA.get()).toBe(2)
|
||||
expect(atomB.get()).toBe(-2)
|
||||
})
|
||||
|
||||
it('should restore the original even if an inner commits', () => {
|
||||
|
@ -156,7 +156,7 @@ describe('transactions', () => {
|
|||
rollback()
|
||||
})
|
||||
|
||||
expect(a.value).toBe('a')
|
||||
expect(a.get()).toBe('a')
|
||||
})
|
||||
})
|
||||
|
||||
|
@ -173,7 +173,7 @@ describe('transact', () => {
|
|||
expect(e.message).toBe('blah')
|
||||
}
|
||||
|
||||
expect(a.value).toBe('a')
|
||||
expect(a.get()).toBe('a')
|
||||
|
||||
expect.assertions(2)
|
||||
})
|
||||
|
@ -192,10 +192,10 @@ describe('transact', () => {
|
|||
} catch (e: any) {
|
||||
expect(e.message).toBe('blah')
|
||||
}
|
||||
expect(a.value).toBe('c')
|
||||
expect(a.get()).toBe('c')
|
||||
})
|
||||
|
||||
expect(a.value).toBe('c')
|
||||
expect(a.get()).toBe('c')
|
||||
|
||||
expect.assertions(3)
|
||||
})
|
||||
|
|
|
@ -28,7 +28,11 @@ export interface Signal<Value, Diff = unknown> {
|
|||
* Any computed signal that depends on this signal will be lazily recomputed if this signal changes.
|
||||
* Any effect that depends on this signal will be rescheduled if this signal changes.
|
||||
*/
|
||||
readonly value: Value
|
||||
get(): Value
|
||||
/**
|
||||
* @deprecated Use [[Signal.get]] instead.
|
||||
*/
|
||||
value: Value
|
||||
/**
|
||||
* The epoch when this signal's value last changed. Note tha this is not the same as when the value was last computed.
|
||||
* A signal may recopmute it's value without changing it.
|
||||
|
|
41
packages/state/src/lib/core/warnings.ts
Normal file
41
packages/state/src/lib/core/warnings.ts
Normal file
|
@ -0,0 +1,41 @@
|
|||
let didWarnDotValue = false
|
||||
const isDev = typeof process !== 'undefined' && process.env?.NODE_ENV === 'development'
|
||||
const isProd = !isDev
|
||||
|
||||
// remove this once we've removed all getters from our app
|
||||
const ROLLOUT_OVERRIDE_REMOVE_ME = true
|
||||
|
||||
export function logDotValueWarning() {
|
||||
if (ROLLOUT_OVERRIDE_REMOVE_ME) return
|
||||
if (isProd) return
|
||||
if (didWarnDotValue) return
|
||||
didWarnDotValue = true
|
||||
console.warn(
|
||||
'Using Signal.value is deprecated and will be removed in the near future. Please use Signal.get() instead.'
|
||||
)
|
||||
}
|
||||
|
||||
let didWarnComputedGetter = false
|
||||
|
||||
export function logComputedGetterWarning() {
|
||||
if (ROLLOUT_OVERRIDE_REMOVE_ME) return
|
||||
if (isProd) return
|
||||
if (didWarnComputedGetter) return
|
||||
didWarnComputedGetter = true
|
||||
console.warn(
|
||||
`Using \`@computed\` as a decorator for getters is deprecated and will be removed in the near future. Please refactor to use \`@computed\` as a decorator for methods.
|
||||
|
||||
// Before
|
||||
@computed
|
||||
get foo() {
|
||||
return 'foo'
|
||||
}
|
||||
|
||||
// After
|
||||
@computed
|
||||
getFoo() {
|
||||
return 'foo'
|
||||
}
|
||||
`
|
||||
)
|
||||
}
|
|
@ -135,7 +135,7 @@ test('tracked components update when the state they refernce updates', async ()
|
|||
const a = atom('a', 1)
|
||||
|
||||
const C = track(function Component() {
|
||||
return <>{a.value}</>
|
||||
return <>{a.get()}</>
|
||||
})
|
||||
|
||||
let view: ReactTestRenderer
|
||||
|
@ -160,7 +160,7 @@ test('things referenced in effects do not trigger updates', async () => {
|
|||
const Component = track(function Component() {
|
||||
numRenders++
|
||||
useEffect(() => {
|
||||
a.value
|
||||
a.get()
|
||||
}, [])
|
||||
return <>hi</>
|
||||
})
|
||||
|
@ -185,7 +185,7 @@ test('things referenced in effects do not trigger updates', async () => {
|
|||
test("tracked zombie-children don't throw", async () => {
|
||||
const theAtom = atom<Record<string, number>>('map', { a: 1, b: 2, c: 3 })
|
||||
const Parent = track(function Parent() {
|
||||
const ids = Object.keys(theAtom.value)
|
||||
const ids = Object.keys(theAtom.get())
|
||||
return (
|
||||
<>
|
||||
{ids.map((id) => (
|
||||
|
@ -195,8 +195,8 @@ test("tracked zombie-children don't throw", async () => {
|
|||
)
|
||||
})
|
||||
const Child = track(function Child({ id }: { id: string }) {
|
||||
if (!(id in theAtom.value)) throw new Error('id not found!')
|
||||
const value = theAtom.value[id]
|
||||
if (!(id in theAtom.get())) throw new Error('id not found!')
|
||||
const value = theAtom.get()[id]
|
||||
return <>{value}</>
|
||||
})
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ test('useAtom returns an atom', async () => {
|
|||
})
|
||||
|
||||
expect(theAtom).not.toBeNull()
|
||||
expect(theAtom?.value).toBe('a')
|
||||
expect(theAtom?.get()).toBe('a')
|
||||
expect(theAtom?.name).toBe('useAtom(myAtom)')
|
||||
expect(view!.toJSON()).toMatchInlineSnapshot(`"a"`)
|
||||
|
||||
|
@ -44,7 +44,7 @@ test('useAtom supports taking an initializer', async () => {
|
|||
})
|
||||
|
||||
expect(theAtom).not.toBeNull()
|
||||
expect(theAtom?.value).toBe('a')
|
||||
expect(theAtom?.get()).toBe('a')
|
||||
|
||||
expect(theAtom?.name).toBe('useAtom(myAtom)')
|
||||
expect(view!.toJSON()).toMatchInlineSnapshot(`"a"`)
|
||||
|
|
|
@ -12,7 +12,7 @@ test('useComputed returns a computed value', async () => {
|
|||
function Component() {
|
||||
const a = useAtom('a', 1)
|
||||
theAtom = a
|
||||
const b = useComputed('a+1', () => a.value + 1, [])
|
||||
const b = useComputed('a+1', () => a.get() + 1, [])
|
||||
theComputed = b
|
||||
return <>{useValue(b)}</>
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ test('useComputed returns a computed value', async () => {
|
|||
})
|
||||
|
||||
expect(theComputed).not.toBeNull()
|
||||
expect(theComputed?.value).toBe(2)
|
||||
expect(theComputed?.get()).toBe(2)
|
||||
expect(theComputed?.name).toBe('useComputed(a+1)')
|
||||
expect(view!.toJSON()).toMatchInlineSnapshot(`"2"`)
|
||||
|
||||
|
@ -42,7 +42,7 @@ test('useComputed has a dependencies array that allows creating a new computed',
|
|||
setCount = _setCount
|
||||
const a = useAtom('a', 1)
|
||||
theAtom = a
|
||||
const b = useComputed('a+1', () => a.value + 1, [count])
|
||||
const b = useComputed('a+1', () => a.get() + 1, [count])
|
||||
theComputed = b
|
||||
return <>{useValue(b)}</>
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ test('useComputed has a dependencies array that allows creating a new computed',
|
|||
const initialComputed = theComputed
|
||||
|
||||
expect(theComputed).not.toBeNull()
|
||||
expect(theComputed?.value).toBe(2)
|
||||
expect(theComputed?.get()).toBe(2)
|
||||
expect(theComputed?.name).toBe('useComputed(a+1)')
|
||||
expect(view!.toJSON()).toMatchInlineSnapshot(`"2"`)
|
||||
|
||||
|
@ -83,7 +83,7 @@ test('useComputed allows optionally passing options', async () => {
|
|||
setCount = _setCount
|
||||
const a = useAtom('a', 1)
|
||||
theAtom = a
|
||||
const b = useComputed('a+1', () => a.value + 1, { isEqual }, [count])
|
||||
const b = useComputed('a+1', () => a.get() + 1, { isEqual }, [count])
|
||||
theComputed = b
|
||||
return <>{useValue(b)}</>
|
||||
}
|
||||
|
@ -96,7 +96,7 @@ test('useComputed allows optionally passing options', async () => {
|
|||
const initialComputed = theComputed
|
||||
|
||||
expect(theComputed).not.toBeNull()
|
||||
expect(theComputed?.value).toBe(2)
|
||||
expect(theComputed?.get()).toBe(2)
|
||||
expect(theComputed?.name).toBe('useComputed(a+1)')
|
||||
expect(view!.toJSON()).toMatchInlineSnapshot(`"2"`)
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ describe('useStateTracking', () => {
|
|||
|
||||
const Component = () => {
|
||||
const val = useStateTracking('', () => {
|
||||
return a.value
|
||||
return a.get()
|
||||
})
|
||||
return <>You are {val} years old</>
|
||||
}
|
||||
|
@ -48,7 +48,7 @@ describe('useStateTracking', () => {
|
|||
const age = useStateTracking('', () => {
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
;[height, setHeight] = React.useState(20)
|
||||
return _age.value
|
||||
return _age.get()
|
||||
})
|
||||
return (
|
||||
<>
|
||||
|
@ -110,12 +110,12 @@ describe('useStateTracking', () => {
|
|||
|
||||
const Component = () => {
|
||||
const val = useStateTracking('', () => {
|
||||
if (a.value === null) {
|
||||
if (a.get() === null) {
|
||||
throw new Promise<string>((r) => {
|
||||
resolve = r
|
||||
})
|
||||
}
|
||||
return a.value
|
||||
return a.get()
|
||||
})
|
||||
return <>You are {val} years old</>
|
||||
}
|
||||
|
@ -156,7 +156,7 @@ describe('useStateTracking', () => {
|
|||
const Component = () => {
|
||||
const val = useStateTracking('', () => {
|
||||
numRenders++
|
||||
return a.value
|
||||
return a.get()
|
||||
})
|
||||
return <>You are {val} years old</>
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ test('useValue returns a value from a computed', async () => {
|
|||
function Component() {
|
||||
const a = useAtom('a', 1)
|
||||
theAtom = a
|
||||
const b = useComputed('a+1', () => a.value + 1, [])
|
||||
const b = useComputed('a+1', () => a.get() + 1, [])
|
||||
theComputed = b
|
||||
return <>{useValue(b)}</>
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ test('useValue returns a value from a computed', async () => {
|
|||
})
|
||||
|
||||
expect(theComputed).not.toBeNull()
|
||||
expect(theComputed?.value).toBe(2)
|
||||
expect(theComputed?.get()).toBe(2)
|
||||
expect(theComputed?.name).toBe('useComputed(a+1)')
|
||||
expect(view!.toJSON()).toMatchInlineSnapshot(`"2"`)
|
||||
|
||||
|
@ -62,7 +62,7 @@ test('useValue returns a value from a compute function', async () => {
|
|||
const [b, _setB] = useState(1)
|
||||
setB = _setB
|
||||
theAtom = a
|
||||
const c = useValue('a+b', () => a.value + b, [b])
|
||||
const c = useValue('a+b', () => a.get() + b, [b])
|
||||
return <>{c}</>
|
||||
}
|
||||
|
||||
|
@ -87,7 +87,7 @@ test('useValue returns a value from a compute function', async () => {
|
|||
test("useValue doesn't throw when used in a zombie-child component", async () => {
|
||||
const theAtom = atom<Record<string, number>>('map', { a: 1, b: 2, c: 3 })
|
||||
function Parent() {
|
||||
const ids = useValue('ids', () => Object.keys(theAtom.value), [])
|
||||
const ids = useValue('ids', () => Object.keys(theAtom.get()), [])
|
||||
return (
|
||||
<>
|
||||
{ids.map((id) => (
|
||||
|
@ -100,8 +100,8 @@ test("useValue doesn't throw when used in a zombie-child component", async () =>
|
|||
const value = useValue(
|
||||
'value',
|
||||
() => {
|
||||
if (!(id in theAtom.value)) throw new Error('id not found!')
|
||||
return theAtom.value[id]
|
||||
if (!(id in theAtom.get())) throw new Error('id not found!')
|
||||
return theAtom.get()[id]
|
||||
},
|
||||
[id]
|
||||
)
|
||||
|
|
|
@ -82,11 +82,11 @@ export function useValue() {
|
|||
return {
|
||||
subscribe: (listen: () => void) => {
|
||||
return react(`useValue(${name})`, () => {
|
||||
$val.value
|
||||
$val.get()
|
||||
listen()
|
||||
})
|
||||
},
|
||||
getSnapshot: () => $val.value,
|
||||
getSnapshot: () => $val.get(),
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [$val])
|
||||
|
|
|
@ -197,7 +197,7 @@ export class Store<R extends UnknownRecord = UnknownRecord, Props = unknown> {
|
|||
'Store.historyReactor',
|
||||
() => {
|
||||
// deref to make sure we're subscribed regardless of whether we need to propagate
|
||||
this.history.value
|
||||
this.history.get()
|
||||
// If we have accumulated history, flush it and update listeners
|
||||
this._flushHistory()
|
||||
},
|
||||
|
@ -290,7 +290,7 @@ export class Store<R extends UnknownRecord = UnknownRecord, Props = unknown> {
|
|||
if (this.listeners.size === 0) {
|
||||
this.historyAccumulator.clear()
|
||||
}
|
||||
this.history.set(this.history.value + 1, changes)
|
||||
this.history.set(this.history.get() + 1, changes)
|
||||
}
|
||||
|
||||
validate(phase: 'initialize' | 'createRecord' | 'updateRecord' | 'tests') {
|
||||
|
@ -379,7 +379,7 @@ export class Store<R extends UnknownRecord = UnknownRecord, Props = unknown> {
|
|||
const recordAtom = (map ?? currentMap)[record.id as IdOf<R>]
|
||||
|
||||
if (recordAtom) {
|
||||
if (beforeUpdate) record = beforeUpdate(recordAtom.value, record, source)
|
||||
if (beforeUpdate) record = beforeUpdate(recordAtom.get(), record, source)
|
||||
|
||||
// If we already have an atom for this record, update its value.
|
||||
|
||||
|
@ -478,7 +478,7 @@ export class Store<R extends UnknownRecord = UnknownRecord, Props = unknown> {
|
|||
const atom = this.atoms.__unsafe__getWithoutCapture()[id]
|
||||
if (!atom) continue
|
||||
|
||||
if (this.onBeforeDelete(atom.value, source) === false) {
|
||||
if (this.onBeforeDelete(atom.get(), source) === false) {
|
||||
cancelled.push(id)
|
||||
}
|
||||
}
|
||||
|
@ -496,7 +496,7 @@ export class Store<R extends UnknownRecord = UnknownRecord, Props = unknown> {
|
|||
if (!result) result = { ...atoms }
|
||||
if (!removed) removed = {} as Record<IdOf<R>, R>
|
||||
delete result[id]
|
||||
removed[id] = atoms[id].value
|
||||
removed[id] = atoms[id].get()
|
||||
}
|
||||
|
||||
return result ?? atoms
|
||||
|
@ -526,7 +526,7 @@ export class Store<R extends UnknownRecord = UnknownRecord, Props = unknown> {
|
|||
* @public
|
||||
*/
|
||||
get = <K extends IdOf<R>>(id: K): RecFromId<K> | undefined => {
|
||||
return this.atoms.value[id]?.value as any
|
||||
return this.atoms.get()[id]?.get() as any
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -536,7 +536,7 @@ export class Store<R extends UnknownRecord = UnknownRecord, Props = unknown> {
|
|||
* @public
|
||||
*/
|
||||
unsafeGetWithoutCapture = <K extends IdOf<R>>(id: K): RecFromId<K> | undefined => {
|
||||
return this.atoms.value[id]?.__unsafe__getWithoutCapture() as any
|
||||
return this.atoms.get()[id]?.__unsafe__getWithoutCapture() as any
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -547,8 +547,8 @@ export class Store<R extends UnknownRecord = UnknownRecord, Props = unknown> {
|
|||
*/
|
||||
serialize = (scope: RecordScope | 'all' = 'document'): SerializedStore<R> => {
|
||||
const result = {} as SerializedStore<R>
|
||||
for (const [id, atom] of objectMapEntries(this.atoms.value)) {
|
||||
const record = atom.value
|
||||
for (const [id, atom] of objectMapEntries(this.atoms.get())) {
|
||||
const record = atom.get()
|
||||
if (scope === 'all' || this.scopedTypes[scope].has(record.typeName)) {
|
||||
result[id as IdOf<R>] = record
|
||||
}
|
||||
|
@ -631,7 +631,7 @@ export class Store<R extends UnknownRecord = UnknownRecord, Props = unknown> {
|
|||
* @public
|
||||
*/
|
||||
allRecords = (): R[] => {
|
||||
return objectMapValues(this.atoms.value).map((atom) => atom.value)
|
||||
return objectMapValues(this.atoms.get()).map((atom) => atom.get())
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -640,7 +640,7 @@ export class Store<R extends UnknownRecord = UnknownRecord, Props = unknown> {
|
|||
* @public
|
||||
*/
|
||||
clear = (): void => {
|
||||
this.remove(objectMapKeys(this.atoms.value))
|
||||
this.remove(objectMapKeys(this.atoms.get()))
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -651,7 +651,7 @@ export class Store<R extends UnknownRecord = UnknownRecord, Props = unknown> {
|
|||
* @param updater - A function that updates the record.
|
||||
*/
|
||||
update = <K extends IdOf<R>>(id: K, updater: (record: RecFromId<K>) => RecFromId<K>) => {
|
||||
const atom = this.atoms.value[id]
|
||||
const atom = this.atoms.get()[id]
|
||||
if (!atom) {
|
||||
console.error(`Record ${id} not found. This is probably an error`)
|
||||
return
|
||||
|
@ -667,7 +667,7 @@ export class Store<R extends UnknownRecord = UnknownRecord, Props = unknown> {
|
|||
* @public
|
||||
*/
|
||||
has = <K extends IdOf<R>>(id: K): boolean => {
|
||||
return !!this.atoms.value[id]
|
||||
return !!this.atoms.get()[id]
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -772,18 +772,20 @@ export class Store<R extends UnknownRecord = UnknownRecord, Props = unknown> {
|
|||
const cache = new Cache<Atom<any>, Computed<T | undefined>>()
|
||||
return {
|
||||
get: (id: IdOf<V>) => {
|
||||
const atom = this.atoms.value[id]
|
||||
const atom = this.atoms.get()[id]
|
||||
if (!atom) {
|
||||
return undefined
|
||||
}
|
||||
return cache.get(atom, () => {
|
||||
return cache
|
||||
.get(atom, () => {
|
||||
const recordSignal = isEqual
|
||||
? computed(atom.name + ':equals', () => atom.value, { isEqual })
|
||||
? computed(atom.name + ':equals', () => atom.get(), { isEqual })
|
||||
: atom
|
||||
return computed<T | undefined>(name + ':' + id, () => {
|
||||
return derive(recordSignal.value as V)
|
||||
return derive(recordSignal.get() as V)
|
||||
})
|
||||
}).value
|
||||
})
|
||||
.get()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -804,17 +806,17 @@ export class Store<R extends UnknownRecord = UnknownRecord, Props = unknown> {
|
|||
const cache = new Cache<Atom<any>, Computed<J | undefined>>()
|
||||
return {
|
||||
get: (id: IdOf<V>) => {
|
||||
const atom = this.atoms.value[id]
|
||||
const atom = this.atoms.get()[id]
|
||||
if (!atom) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
const d = computed<T | undefined>(name + ':' + id + ':selector', () =>
|
||||
selector(atom.value as V)
|
||||
selector(atom.get() as V)
|
||||
)
|
||||
return cache.get(atom, () =>
|
||||
computed<J | undefined>(name + ':' + id, () => derive(d.value as T))
|
||||
).value
|
||||
return cache
|
||||
.get(atom, () => computed<J | undefined>(name + ':' + id, () => derive(d.get() as T)))
|
||||
.get()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -74,11 +74,11 @@ export class StoreQueries<R extends UnknownRecord> {
|
|||
'filterHistory:' + typeName,
|
||||
(lastValue, lastComputedEpoch) => {
|
||||
if (isUninitialized(lastValue)) {
|
||||
return this.history.value
|
||||
return this.history.get()
|
||||
}
|
||||
|
||||
const diff = this.history.getDiffSince(lastComputedEpoch)
|
||||
if (diff === RESET_VALUE) return this.history.value
|
||||
if (diff === RESET_VALUE) return this.history.get()
|
||||
|
||||
const res = { added: {}, removed: {}, updated: {} } as RecordsDiff<S>
|
||||
let numAdded = 0
|
||||
|
@ -137,7 +137,7 @@ export class StoreQueries<R extends UnknownRecord> {
|
|||
}
|
||||
|
||||
if (numAdded || numRemoved || numUpdated) {
|
||||
return withDiff(this.history.value, res)
|
||||
return withDiff(this.history.get(), res)
|
||||
} else {
|
||||
return lastValue
|
||||
}
|
||||
|
@ -192,10 +192,10 @@ export class StoreQueries<R extends UnknownRecord> {
|
|||
const fromScratch = () => {
|
||||
// deref typeHistory early so that the first time the incremental version runs
|
||||
// it gets a diff to work with instead of having to bail to this from-scratch version
|
||||
typeHistory.value
|
||||
typeHistory.get()
|
||||
const res = new Map<S[Property], Set<IdOf<S>>>()
|
||||
for (const atom of objectMapValues(this.atoms.value)) {
|
||||
const record = atom.value
|
||||
for (const atom of objectMapValues(this.atoms.get())) {
|
||||
const record = atom.get()
|
||||
if (record.typeName === typeName) {
|
||||
const value = (record as S)[property]
|
||||
if (!res.has(value)) {
|
||||
|
@ -306,8 +306,8 @@ export class StoreQueries<R extends UnknownRecord> {
|
|||
const ids = this.ids(typeName, queryCreator, name)
|
||||
|
||||
return computed<S | undefined>(name, () => {
|
||||
for (const id of ids.value) {
|
||||
return this.atoms.value[id]?.value as S
|
||||
for (const id of ids.get()) {
|
||||
return this.atoms.get()[id]?.get() as S
|
||||
}
|
||||
return undefined
|
||||
})
|
||||
|
@ -329,12 +329,12 @@ export class StoreQueries<R extends UnknownRecord> {
|
|||
const ids = this.ids(typeName, queryCreator, 'ids:' + name)
|
||||
|
||||
return computed<S[]>(name, () => {
|
||||
return [...ids.value].map((id) => {
|
||||
const atom = this.atoms.value[id]
|
||||
return [...ids.get()].map((id) => {
|
||||
const atom = this.atoms.get()[id]
|
||||
if (!atom) {
|
||||
throw new Error('no atom found for record id: ' + id)
|
||||
}
|
||||
return atom.value as S
|
||||
return atom.get() as S
|
||||
})
|
||||
})
|
||||
}
|
||||
|
@ -360,12 +360,12 @@ export class StoreQueries<R extends UnknownRecord> {
|
|||
|
||||
const fromScratch = () => {
|
||||
// deref type history early to allow first incremental update to use diffs
|
||||
typeHistory.value
|
||||
typeHistory.get()
|
||||
const query: QueryExpression<S> = queryCreator()
|
||||
if (Object.keys(query).length === 0) {
|
||||
return new Set<IdOf<S>>(
|
||||
objectMapValues(this.atoms.value).flatMap((v) => {
|
||||
const r = v.value
|
||||
objectMapValues(this.atoms.get()).flatMap((v) => {
|
||||
const r = v.get()
|
||||
if (r.typeName === typeName) {
|
||||
return r.id
|
||||
} else {
|
||||
|
@ -394,7 +394,7 @@ export class StoreQueries<R extends UnknownRecord> {
|
|||
return computed(
|
||||
'query:' + name,
|
||||
(prevValue, lastComputedEpoch) => {
|
||||
const query = cachedQuery.value
|
||||
const query = cachedQuery.get()
|
||||
if (isUninitialized(prevValue)) {
|
||||
return fromScratch()
|
||||
}
|
||||
|
@ -455,7 +455,7 @@ export class StoreQueries<R extends UnknownRecord> {
|
|||
if (ids.size === 0) {
|
||||
return EMPTY_ARRAY
|
||||
}
|
||||
const atoms = this.atoms.value
|
||||
return [...ids].map((id) => atoms[id].value as Extract<R, { typeName: TypeName }>)
|
||||
const atoms = this.atoms.get()
|
||||
return [...ids].map((id) => atoms[id].get() as Extract<R, { typeName: TypeName }>)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ export function executeQuery<R extends UnknownRecord, TypeName extends R['typeNa
|
|||
for (const [k, matcher] of Object.entries(query)) {
|
||||
if ('eq' in matcher) {
|
||||
const index = store.index(typeName, k as any)
|
||||
const ids = index.value.get(matcher.eq)
|
||||
const ids = index.get().get(matcher.eq)
|
||||
if (ids) {
|
||||
for (const id of ids) {
|
||||
matchIds[k].add(id)
|
||||
|
@ -42,7 +42,7 @@ export function executeQuery<R extends UnknownRecord, TypeName extends R['typeNa
|
|||
}
|
||||
} else if ('neq' in matcher) {
|
||||
const index = store.index(typeName, k as any)
|
||||
for (const [value, ids] of index.value) {
|
||||
for (const [value, ids] of index.get()) {
|
||||
if (value !== matcher.neq) {
|
||||
for (const id of ids) {
|
||||
matchIds[k].add(id)
|
||||
|
@ -51,7 +51,7 @@ export function executeQuery<R extends UnknownRecord, TypeName extends R['typeNa
|
|||
}
|
||||
} else if ('gt' in matcher) {
|
||||
const index = store.index(typeName, k as any)
|
||||
for (const [value, ids] of index.value) {
|
||||
for (const [value, ids] of index.get()) {
|
||||
if (value > matcher.gt) {
|
||||
for (const id of ids) {
|
||||
matchIds[k].add(id)
|
||||
|
|
|
@ -66,7 +66,7 @@ describe('Store', () => {
|
|||
|
||||
it('allows records to be added', () => {
|
||||
store.put([Author.create({ name: 'J.R.R Tolkein', id: Author.createId('tolkein') })])
|
||||
expect(store.query.records('author').value).toEqual([
|
||||
expect(store.query.records('author').get()).toEqual([
|
||||
{ id: 'author:tolkein', typeName: 'author', name: 'J.R.R Tolkein', isPseudonym: false },
|
||||
])
|
||||
|
||||
|
@ -80,7 +80,7 @@ describe('Store', () => {
|
|||
},
|
||||
])
|
||||
|
||||
expect(store.query.records('book').value).toEqual([
|
||||
expect(store.query.records('book').get()).toEqual([
|
||||
{
|
||||
id: 'book:the-hobbit',
|
||||
typeName: 'book',
|
||||
|
@ -217,7 +217,7 @@ describe('Store', () => {
|
|||
expect(current).toEqual(
|
||||
Author.create({ name: 'J.R.R Tolkein', id: Author.createId('tolkein') })
|
||||
)
|
||||
expect([...store.query.ids('author').value]).toEqual([Author.createId('tolkein')])
|
||||
expect([...store.query.ids('author').get()]).toEqual([Author.createId('tolkein')])
|
||||
})
|
||||
store.put([Author.create({ name: 'J.R.R Tolkein', id: Author.createId('tolkein') })])
|
||||
|
||||
|
@ -257,10 +257,16 @@ describe('Store', () => {
|
|||
Author.create({ name: 'Cynan Jones', id: Author.createId('cj') }),
|
||||
Author.create({ name: 'David Foster Wallace', id: Author.createId('dfw') }),
|
||||
])
|
||||
const Js = store.query.records('author').value.filter((r) => r.name.startsWith('J'))
|
||||
const Js = store.query
|
||||
.records('author')
|
||||
.get()
|
||||
.filter((r) => r.name.startsWith('J'))
|
||||
expect(Js.map((j) => j.name).sort()).toEqual(['J.R.R Tolkein', 'James McAvoy'])
|
||||
|
||||
const david = store.query.records('author').value.find((r) => r.name.startsWith('David'))
|
||||
const david = store.query
|
||||
.records('author')
|
||||
.get()
|
||||
.find((r) => r.name.startsWith('David'))
|
||||
expect(david?.name).toBe('David Foster Wallace')
|
||||
})
|
||||
|
||||
|
|
|
@ -344,7 +344,7 @@ function runTest(seed: number) {
|
|||
})
|
||||
store.onBeforeDelete = (record) => {
|
||||
if (record.typeName === 'author') {
|
||||
const books = store.query.index('book', 'authorId').value.get(record.id)
|
||||
const books = store.query.index('book', 'authorId').get().get(record.id)
|
||||
if (books) store.remove([...books])
|
||||
}
|
||||
}
|
||||
|
@ -359,16 +359,16 @@ function runTest(seed: number) {
|
|||
const bookTitleQueryParam = atom('bookTitle', getRandomBookName(getRandomNumber))
|
||||
|
||||
const booksByAuthorQuery = store.query.records('book', () => ({
|
||||
authorId: { eq: authorIdQueryParam.value },
|
||||
authorId: { eq: authorIdQueryParam.get() },
|
||||
}))
|
||||
|
||||
const booksByTitleQuery = store.query.records('book', () => ({
|
||||
title: { eq: bookTitleQueryParam.value },
|
||||
title: { eq: bookTitleQueryParam.get() },
|
||||
}))
|
||||
|
||||
const authorNameQueryParam = atom('authorName', getRandomAuthorName(getRandomNumber))
|
||||
const authorIdsByNameQuery = store.query.ids('author', () => ({
|
||||
name: { neq: authorNameQueryParam.value },
|
||||
name: { neq: authorNameQueryParam.get() },
|
||||
}))
|
||||
|
||||
const ops = []
|
||||
|
@ -384,9 +384,9 @@ function runTest(seed: number) {
|
|||
const authorNameIndexDiff = authorNameIndex.getDiffSince(lastReactedEpoch)
|
||||
const authorIdIndexDiff = authorIdIndex.getDiffSince(lastReactedEpoch)
|
||||
const authorIdsByNameDiff = authorIdsByNameQuery.getDiffSince(lastReactedEpoch)
|
||||
latestBooksByAuthorQueryResult = booksByAuthorQuery.value
|
||||
latestBooksByTitleQueryResult = booksByTitleQuery.value
|
||||
latestAuthorIdsByNameQueryResult = authorIdsByNameQuery.value
|
||||
latestBooksByAuthorQueryResult = booksByAuthorQuery.get()
|
||||
latestBooksByTitleQueryResult = booksByTitleQuery.get()
|
||||
latestAuthorIdsByNameQueryResult = authorIdsByNameQuery.get()
|
||||
if (
|
||||
authorNameIndexDiff === RESET_VALUE ||
|
||||
authorIdIndexDiff === RESET_VALUE ||
|
||||
|
@ -419,7 +419,7 @@ function runTest(seed: number) {
|
|||
store.remove([op.id])
|
||||
|
||||
if (op.id === 'book:0.5525377229080933') {
|
||||
store.query.index('book', 'title').value
|
||||
store.query.index('book', 'title').get()
|
||||
}
|
||||
break
|
||||
}
|
||||
|
@ -440,16 +440,14 @@ function runTest(seed: number) {
|
|||
effect.execute()
|
||||
// these tests create a version of the index from scratch and check it against
|
||||
// the incrementally-updated version to make sure the logic matches.
|
||||
const authorNameIndexFromScratch = store.query.__uncached_createIndex(
|
||||
'author',
|
||||
'name'
|
||||
).value
|
||||
const authorIdIndexFromScratch = store.query.__uncached_createIndex(
|
||||
'book',
|
||||
'authorId'
|
||||
).value
|
||||
expect(authorNameIndex.value).toEqual(authorNameIndexFromScratch)
|
||||
expect(authorIdIndex.value).toEqual(authorIdIndexFromScratch)
|
||||
const authorNameIndexFromScratch = store.query
|
||||
.__uncached_createIndex('author', 'name')
|
||||
.get()
|
||||
const authorIdIndexFromScratch = store.query
|
||||
.__uncached_createIndex('book', 'authorId')
|
||||
.get()
|
||||
expect(authorNameIndex.get()).toEqual(authorNameIndexFromScratch)
|
||||
expect(authorIdIndex.get()).toEqual(authorIdIndexFromScratch)
|
||||
// these tests recreate the index from scratch based on the diffs so far and
|
||||
// check it against the gold standard version to make sure the diff logic matches.
|
||||
expect(recreateIndexFromDiffs(authorNameIndexDiffs)).toEqual(authorNameIndexFromScratch)
|
||||
|
@ -459,36 +457,36 @@ function runTest(seed: number) {
|
|||
store
|
||||
.allRecords()
|
||||
.filter(
|
||||
(r): r is Book => r.typeName === 'book' && r.authorId === authorIdQueryParam.value
|
||||
(r): r is Book => r.typeName === 'book' && r.authorId === authorIdQueryParam.get()
|
||||
)
|
||||
.sort(bookComparator)
|
||||
)
|
||||
expect(new Set(latestBooksByAuthorQueryResult.map((b) => b.id))).toEqual(
|
||||
executeQuery(store.query, 'book', { authorId: { eq: authorIdQueryParam.value } })
|
||||
executeQuery(store.query, 'book', { authorId: { eq: authorIdQueryParam.get() } })
|
||||
)
|
||||
expect(latestBooksByTitleQueryResult.sort(bookComparator)).toEqual(
|
||||
store
|
||||
.allRecords()
|
||||
.filter(
|
||||
(r): r is Book => r.typeName === 'book' && r.title === bookTitleQueryParam.value
|
||||
(r): r is Book => r.typeName === 'book' && r.title === bookTitleQueryParam.get()
|
||||
)
|
||||
.sort(bookComparator)
|
||||
)
|
||||
expect(new Set(latestBooksByTitleQueryResult.map((b) => b.id))).toEqual(
|
||||
executeQuery(store.query, 'book', { title: { eq: bookTitleQueryParam.value } })
|
||||
executeQuery(store.query, 'book', { title: { eq: bookTitleQueryParam.get() } })
|
||||
)
|
||||
expect(latestAuthorIdsByNameQueryResult).toEqual(
|
||||
new Set(
|
||||
store
|
||||
.allRecords()
|
||||
.filter(
|
||||
(r): r is Author => r.typeName === 'author' && r.name !== authorNameQueryParam.value
|
||||
(r): r is Author => r.typeName === 'author' && r.name !== authorNameQueryParam.get()
|
||||
)
|
||||
.map((r) => r.id)
|
||||
)
|
||||
)
|
||||
expect(latestAuthorIdsByNameQueryResult).toEqual(
|
||||
executeQuery(store.query, 'author', { name: { neq: authorNameQueryParam.value } })
|
||||
executeQuery(store.query, 'author', { name: { neq: authorNameQueryParam.get() } })
|
||||
)
|
||||
// this test checks that the authorIdsByName set matches what you get when you reassemble it from the diffs
|
||||
expect(reacreateSetFromDiffs(authorIdsByNameDiffs)).toEqual(
|
||||
|
|
|
@ -96,27 +96,27 @@ describe('indexes', () => {
|
|||
it('can be made on any property', () => {
|
||||
const authorNameIndex = store.query.index('author', 'name')
|
||||
|
||||
expect(authorNameIndex.value.get('J.R.R. Tolkein')).toEqual(new Set([authors.tolkein.id]))
|
||||
expect(authorNameIndex.value.get('David Mitchell')).toEqual(
|
||||
expect(authorNameIndex.get().get('J.R.R. Tolkein')).toEqual(new Set([authors.tolkein.id]))
|
||||
expect(authorNameIndex.get().get('David Mitchell')).toEqual(
|
||||
new Set([authors.davidMitchellFunny.id, authors.davidMitchellSerious.id])
|
||||
)
|
||||
|
||||
const bookTitleIndex = store.query.index('book', 'title')
|
||||
expect(bookTitleIndex.value.get('Cloud Atlas')).toEqual(new Set([books.cloudAtlas.id]))
|
||||
expect(bookTitleIndex.value.get('Lord of the Rings')).toEqual(new Set([books.lotr.id]))
|
||||
expect(bookTitleIndex.get().get('Cloud Atlas')).toEqual(new Set([books.cloudAtlas.id]))
|
||||
expect(bookTitleIndex.get().get('Lord of the Rings')).toEqual(new Set([books.lotr.id]))
|
||||
})
|
||||
|
||||
it('can have things added when records are added', () => {
|
||||
const authorNameIndex = store.query.index('author', 'name')
|
||||
// deref to make it compute once
|
||||
expect(authorNameIndex.value.get('J.R.R. Tolkein')).toEqual(new Set([authors.tolkein.id]))
|
||||
expect(authorNameIndex.get().get('J.R.R. Tolkein')).toEqual(new Set([authors.tolkein.id]))
|
||||
|
||||
let lastChangedEpoch = authorNameIndex.lastChangedEpoch
|
||||
const newAuthor = Author.create({ name: 'New Author' })
|
||||
|
||||
store.put([newAuthor])
|
||||
|
||||
expect(authorNameIndex.value.get('New Author')).toEqual(new Set([newAuthor.id]))
|
||||
expect(authorNameIndex.get().get('New Author')).toEqual(new Set([newAuthor.id]))
|
||||
|
||||
const diff = authorNameIndex.getDiffSince(lastChangedEpoch)
|
||||
if (diff === RESET_VALUE) throw new Error('should not be reset')
|
||||
|
@ -135,7 +135,7 @@ describe('indexes', () => {
|
|||
lastChangedEpoch = authorNameIndex.lastChangedEpoch
|
||||
store.put(moreNewAuthors)
|
||||
|
||||
expect(authorNameIndex.value.get('New Author')).toEqual(
|
||||
expect(authorNameIndex.get().get('New Author')).toEqual(
|
||||
new Set([newAuthor.id, ...moreNewAuthors.map((a) => a.id)])
|
||||
)
|
||||
|
||||
|
@ -150,13 +150,13 @@ describe('indexes', () => {
|
|||
it('can have things added when records are updated', () => {
|
||||
const authorNameIndex = store.query.index('author', 'name')
|
||||
|
||||
expect(authorNameIndex.value.get('J.R.R. Tolkein')).toEqual(new Set([authors.tolkein.id]))
|
||||
expect(authorNameIndex.get().get('J.R.R. Tolkein')).toEqual(new Set([authors.tolkein.id]))
|
||||
|
||||
let lastChangedEpoch = authorNameIndex.lastChangedEpoch
|
||||
|
||||
store.put([{ ...authors.bradbury, name: 'J.R.R. Tolkein' }])
|
||||
|
||||
expect(authorNameIndex.value.get('J.R.R. Tolkein')).toEqual(
|
||||
expect(authorNameIndex.get().get('J.R.R. Tolkein')).toEqual(
|
||||
new Set([authors.tolkein.id, authors.bradbury.id])
|
||||
)
|
||||
|
||||
|
@ -178,7 +178,7 @@ describe('indexes', () => {
|
|||
{ ...authors.davidMitchellSerious, name: 'J.R.R. Tolkein' },
|
||||
])
|
||||
|
||||
expect(authorNameIndex.value.get('J.R.R. Tolkein')).toEqual(
|
||||
expect(authorNameIndex.get().get('J.R.R. Tolkein')).toEqual(
|
||||
new Set([
|
||||
authors.tolkein.id,
|
||||
authors.bradbury.id,
|
||||
|
@ -206,13 +206,13 @@ describe('indexes', () => {
|
|||
it('can have things removed when records are removed', () => {
|
||||
const authorNameIndex = store.query.index('author', 'name')
|
||||
|
||||
expect(authorNameIndex.value.get('J.R.R. Tolkein')).toEqual(new Set([authors.tolkein.id]))
|
||||
expect(authorNameIndex.get().get('J.R.R. Tolkein')).toEqual(new Set([authors.tolkein.id]))
|
||||
|
||||
let lastChangedEpoch = authorNameIndex.lastChangedEpoch
|
||||
|
||||
store.remove([authors.tolkein.id])
|
||||
|
||||
expect(authorNameIndex.value.get('J.R.R. Tolkein')).toEqual(undefined)
|
||||
expect(authorNameIndex.get().get('J.R.R. Tolkein')).toEqual(undefined)
|
||||
|
||||
const diff = authorNameIndex.getDiffSince(lastChangedEpoch)
|
||||
if (diff === RESET_VALUE) throw new Error('should not be reset')
|
||||
|
@ -229,8 +229,8 @@ describe('indexes', () => {
|
|||
authors.davidMitchellSerious.id,
|
||||
])
|
||||
|
||||
expect(authorNameIndex.value.get('Ray Bradbury')).toEqual(undefined)
|
||||
expect(authorNameIndex.value.get('David Mitchell')).toEqual(undefined)
|
||||
expect(authorNameIndex.get().get('Ray Bradbury')).toEqual(undefined)
|
||||
expect(authorNameIndex.get().get('David Mitchell')).toEqual(undefined)
|
||||
|
||||
const diff2 = authorNameIndex.getDiffSince(lastChangedEpoch)
|
||||
|
||||
|
@ -250,16 +250,16 @@ describe('indexes', () => {
|
|||
|
||||
it('can have things removed when records are updated', () => {
|
||||
const authorNameIndex = store.query.index('author', 'name')
|
||||
expect(authorNameIndex.value.get('J.R.R. Tolkein')).toEqual(new Set([authors.tolkein.id]))
|
||||
expect(authorNameIndex.get().get('J.R.R. Tolkein')).toEqual(new Set([authors.tolkein.id]))
|
||||
|
||||
let lastChangedEpoch = authorNameIndex.lastChangedEpoch
|
||||
|
||||
store.put([{ ...authors.tolkein, name: 'Ray Bradbury' }])
|
||||
|
||||
expect(authorNameIndex.value.get('Ray Bradbury')).toEqual(
|
||||
expect(authorNameIndex.get().get('Ray Bradbury')).toEqual(
|
||||
new Set([authors.tolkein.id, authors.bradbury.id])
|
||||
)
|
||||
expect(authorNameIndex.value.get('J.R.R. Tolkein')).toEqual(undefined)
|
||||
expect(authorNameIndex.get().get('J.R.R. Tolkein')).toEqual(undefined)
|
||||
|
||||
const diff = authorNameIndex.getDiffSince(lastChangedEpoch)
|
||||
if (diff === RESET_VALUE) throw new Error('should not be reset')
|
||||
|
@ -279,7 +279,7 @@ describe('indexes', () => {
|
|||
{ ...authors.davidMitchellSerious, name: 'Ray Bradbury' },
|
||||
])
|
||||
|
||||
expect(authorNameIndex.value.get('Ray Bradbury')).toEqual(
|
||||
expect(authorNameIndex.get().get('Ray Bradbury')).toEqual(
|
||||
new Set([
|
||||
authors.tolkein.id,
|
||||
authors.bradbury.id,
|
||||
|
@ -287,7 +287,7 @@ describe('indexes', () => {
|
|||
authors.davidMitchellSerious.id,
|
||||
])
|
||||
)
|
||||
expect(authorNameIndex.value.get('David Mitchell')).toEqual(undefined)
|
||||
expect(authorNameIndex.get().get('David Mitchell')).toEqual(undefined)
|
||||
|
||||
const diff2 = authorNameIndex.getDiffSince(lastChangedEpoch)
|
||||
|
||||
|
@ -307,7 +307,7 @@ describe('indexes', () => {
|
|||
|
||||
it('handles things being removed and added for the same value at the same time', () => {
|
||||
const authorNameIndex = store.query.index('author', 'name')
|
||||
expect(authorNameIndex.value.get('J.R.R. Tolkein')).toEqual(new Set([authors.tolkein.id]))
|
||||
expect(authorNameIndex.get().get('J.R.R. Tolkein')).toEqual(new Set([authors.tolkein.id]))
|
||||
|
||||
let lastChangedEpoch = authorNameIndex.lastChangedEpoch
|
||||
|
||||
|
@ -316,7 +316,7 @@ describe('indexes', () => {
|
|||
const newAuthor = Author.create({ name: 'J.R.R. Tolkein' })
|
||||
store.put([newAuthor])
|
||||
|
||||
expect(authorNameIndex.value.get('J.R.R. Tolkein')).toEqual(new Set([newAuthor.id]))
|
||||
expect(authorNameIndex.get().get('J.R.R. Tolkein')).toEqual(new Set([newAuthor.id]))
|
||||
|
||||
const diff = authorNameIndex.getDiffSince(lastChangedEpoch)
|
||||
|
||||
|
@ -335,10 +335,10 @@ describe('indexes', () => {
|
|||
store.put([{ ...authors.davidMitchellFunny, name: 'Ray Bradbury' }])
|
||||
store.put([{ ...authors.bradbury, name: 'David Mitchell' }])
|
||||
|
||||
expect(authorNameIndex.value.get('Ray Bradbury')).toEqual(
|
||||
expect(authorNameIndex.get().get('Ray Bradbury')).toEqual(
|
||||
new Set([authors.davidMitchellFunny.id])
|
||||
)
|
||||
expect(authorNameIndex.value.get('David Mitchell')).toEqual(
|
||||
expect(authorNameIndex.get().get('David Mitchell')).toEqual(
|
||||
new Set([authors.bradbury.id, authors.davidMitchellSerious.id])
|
||||
)
|
||||
|
||||
|
@ -363,13 +363,13 @@ describe('indexes', () => {
|
|||
it('has the same value if nothing changed', () => {
|
||||
const authorNameIndex = store.query.index('author', 'name')
|
||||
|
||||
expect(authorNameIndex.value.get('J.R.R. Tolkein')).toEqual(new Set([authors.tolkein.id]))
|
||||
expect(authorNameIndex.get().get('J.R.R. Tolkein')).toEqual(new Set([authors.tolkein.id]))
|
||||
|
||||
const lastChangedEpoch = authorNameIndex.lastChangedEpoch
|
||||
|
||||
store.put([{ ...authors.tolkein, age: 23 }])
|
||||
|
||||
expect(authorNameIndex.value.get('J.R.R. Tolkein')).toEqual(new Set([authors.tolkein.id]))
|
||||
expect(authorNameIndex.get().get('J.R.R. Tolkein')).toEqual(new Set([authors.tolkein.id]))
|
||||
|
||||
expect(lastChangedEpoch).toBe(authorNameIndex.lastChangedEpoch)
|
||||
})
|
||||
|
@ -379,13 +379,13 @@ describe('queries for ids', () => {
|
|||
it('can query for all values of a given type', () => {
|
||||
const bookQuery = store.query.ids('book')
|
||||
|
||||
expect(bookQuery.value).toEqual(
|
||||
expect(bookQuery.get()).toEqual(
|
||||
new Set([books.cloudAtlas.id, books.farenheit.id, books.lotr.id, books.myLifeInComedy.id])
|
||||
)
|
||||
|
||||
const authorQuery = store.query.ids('author')
|
||||
|
||||
expect(authorQuery.value).toEqual(
|
||||
expect(authorQuery.get()).toEqual(
|
||||
new Set([
|
||||
authors.bradbury.id,
|
||||
authors.davidMitchellFunny.id,
|
||||
|
@ -398,7 +398,7 @@ describe('queries for ids', () => {
|
|||
const newBook = Book.create({ title: 'The Hobbit', authorId: newAuthor.id })
|
||||
store.put([newAuthor, newBook])
|
||||
|
||||
expect(bookQuery.value).toEqual(
|
||||
expect(bookQuery.get()).toEqual(
|
||||
new Set([
|
||||
books.cloudAtlas.id,
|
||||
books.farenheit.id,
|
||||
|
@ -408,7 +408,7 @@ describe('queries for ids', () => {
|
|||
])
|
||||
)
|
||||
|
||||
expect(authorQuery.value).toEqual(
|
||||
expect(authorQuery.get()).toEqual(
|
||||
new Set([
|
||||
authors.bradbury.id,
|
||||
authors.davidMitchellFunny.id,
|
||||
|
@ -424,13 +424,13 @@ describe('queries for ids', () => {
|
|||
name: { eq: 'J.R.R. Tolkein' },
|
||||
}))
|
||||
|
||||
expect(jrr.value).toEqual(new Set([authors.tolkein.id]))
|
||||
expect(jrr.get()).toEqual(new Set([authors.tolkein.id]))
|
||||
|
||||
const mitchell = store.query.ids('author', () => ({
|
||||
name: { eq: 'David Mitchell' },
|
||||
}))
|
||||
|
||||
expect(mitchell.value).toEqual(
|
||||
expect(mitchell.get()).toEqual(
|
||||
new Set([authors.davidMitchellFunny.id, authors.davidMitchellSerious.id])
|
||||
)
|
||||
})
|
||||
|
@ -443,7 +443,7 @@ describe('queries for ids', () => {
|
|||
age: { eq: 30 },
|
||||
}))
|
||||
|
||||
expect(mitchell30.value).toEqual(new Set([authors.davidMitchellFunny.id]))
|
||||
expect(mitchell30.get()).toEqual(new Set([authors.davidMitchellFunny.id]))
|
||||
})
|
||||
|
||||
it('can use a reactive query', () => {
|
||||
|
@ -453,16 +453,16 @@ describe('queries for ids', () => {
|
|||
const currentAge = atom('currentAge', 30)
|
||||
|
||||
const mitchell30 = store.query.ids('author', () => ({
|
||||
name: { eq: currentAuthor.value },
|
||||
age: { eq: currentAge.value },
|
||||
name: { eq: currentAuthor.get() },
|
||||
age: { eq: currentAge.get() },
|
||||
}))
|
||||
|
||||
expect(mitchell30.value).toEqual(new Set([authors.davidMitchellFunny.id]))
|
||||
expect(mitchell30.get()).toEqual(new Set([authors.davidMitchellFunny.id]))
|
||||
|
||||
let lastChangedEpoch = mitchell30.lastChangedEpoch
|
||||
currentAge.set(23)
|
||||
|
||||
expect(mitchell30.value).toEqual(new Set([authors.davidMitchellSerious.id]))
|
||||
expect(mitchell30.get()).toEqual(new Set([authors.davidMitchellSerious.id]))
|
||||
|
||||
const diff = mitchell30.getDiffSince(lastChangedEpoch)
|
||||
|
||||
|
@ -478,7 +478,7 @@ describe('queries for ids', () => {
|
|||
|
||||
lastChangedEpoch = mitchell30.lastChangedEpoch
|
||||
|
||||
expect(mitchell30.value).toEqual(new Set([authors.tolkein.id]))
|
||||
expect(mitchell30.get()).toEqual(new Set([authors.tolkein.id]))
|
||||
|
||||
const diff2 = mitchell30.getDiffSince(lastChangedEpoch)
|
||||
|
||||
|
@ -498,13 +498,13 @@ describe('queries for ids', () => {
|
|||
name: { neq: 'David Mitchell' },
|
||||
}))
|
||||
|
||||
expect(mitchell.value).toEqual(new Set([authors.tolkein.id, authors.bradbury.id]))
|
||||
expect(mitchell.get()).toEqual(new Set([authors.tolkein.id, authors.bradbury.id]))
|
||||
|
||||
const ageNot23 = store.query.ids('author', () => ({
|
||||
age: { neq: 23 },
|
||||
}))
|
||||
|
||||
expect(ageNot23.value).toEqual(new Set([authors.davidMitchellFunny.id]))
|
||||
expect(ageNot23.get()).toEqual(new Set([authors.davidMitchellFunny.id]))
|
||||
})
|
||||
|
||||
it('supports records being added', () => {
|
||||
|
@ -512,14 +512,14 @@ describe('queries for ids', () => {
|
|||
name: { eq: 'David Mitchell' },
|
||||
}))
|
||||
|
||||
expect(mitchell.value).toEqual(
|
||||
expect(mitchell.get()).toEqual(
|
||||
new Set([authors.davidMitchellFunny.id, authors.davidMitchellSerious.id])
|
||||
)
|
||||
|
||||
const newAuthor = Author.create({ name: 'David Mitchell' })
|
||||
store.put([newAuthor])
|
||||
|
||||
expect(mitchell.value).toEqual(
|
||||
expect(mitchell.get()).toEqual(
|
||||
new Set([authors.davidMitchellFunny.id, authors.davidMitchellSerious.id, newAuthor.id])
|
||||
)
|
||||
})
|
||||
|
@ -529,13 +529,13 @@ describe('queries for ids', () => {
|
|||
name: { eq: 'David Mitchell' },
|
||||
}))
|
||||
|
||||
expect(mitchell.value).toEqual(
|
||||
expect(mitchell.get()).toEqual(
|
||||
new Set([authors.davidMitchellFunny.id, authors.davidMitchellSerious.id])
|
||||
)
|
||||
|
||||
store.remove([authors.davidMitchellFunny.id])
|
||||
|
||||
expect(mitchell.value).toEqual(new Set([authors.davidMitchellSerious.id]))
|
||||
expect(mitchell.get()).toEqual(new Set([authors.davidMitchellSerious.id]))
|
||||
})
|
||||
|
||||
it('supports records being updated', () => {
|
||||
|
@ -544,17 +544,17 @@ describe('queries for ids', () => {
|
|||
age: { neq: 30 },
|
||||
}))
|
||||
|
||||
expect(mitchell.value).toEqual(
|
||||
expect(mitchell.get()).toEqual(
|
||||
new Set([authors.davidMitchellFunny.id, authors.davidMitchellSerious.id])
|
||||
)
|
||||
|
||||
store.put([{ ...authors.davidMitchellFunny, age: 30 }])
|
||||
|
||||
expect(mitchell.value).toEqual(new Set([authors.davidMitchellSerious.id]))
|
||||
expect(mitchell.get()).toEqual(new Set([authors.davidMitchellSerious.id]))
|
||||
|
||||
store.put([{ ...authors.davidMitchellFunny, age: 23 }])
|
||||
|
||||
expect(mitchell.value).toEqual(
|
||||
expect(mitchell.get()).toEqual(
|
||||
new Set([authors.davidMitchellSerious.id, authors.davidMitchellFunny.id])
|
||||
)
|
||||
})
|
||||
|
@ -564,7 +564,7 @@ describe('queries for ids', () => {
|
|||
name: { eq: 'David Mitchell' },
|
||||
}))
|
||||
|
||||
expect(mitchell.value).toEqual(
|
||||
expect(mitchell.get()).toEqual(
|
||||
new Set([authors.davidMitchellFunny.id, authors.davidMitchellSerious.id])
|
||||
)
|
||||
|
||||
|
@ -573,13 +573,13 @@ describe('queries for ids', () => {
|
|||
const newAuthor = Author.create({ name: 'William Shakespeare' })
|
||||
store.put([newAuthor])
|
||||
|
||||
mitchell.value
|
||||
mitchell.get()
|
||||
|
||||
expect(mitchell.lastChangedEpoch).toEqual(lastChangedEpoch)
|
||||
|
||||
store.remove([authors.tolkein.id])
|
||||
|
||||
mitchell.value
|
||||
mitchell.get()
|
||||
|
||||
expect(mitchell.lastChangedEpoch).toEqual(lastChangedEpoch)
|
||||
})
|
||||
|
@ -589,7 +589,7 @@ describe('queries for ids', () => {
|
|||
name: { eq: 'David Mitchell' },
|
||||
}))
|
||||
|
||||
expect(mitchell.value).toEqual(
|
||||
expect(mitchell.get()).toEqual(
|
||||
new Set([authors.davidMitchellFunny.id, authors.davidMitchellSerious.id])
|
||||
)
|
||||
|
||||
|
@ -597,14 +597,14 @@ describe('queries for ids', () => {
|
|||
|
||||
store.put([{ ...authors.davidMitchellFunny, age: 30 }])
|
||||
|
||||
mitchell.value
|
||||
mitchell.get()
|
||||
|
||||
expect(mitchell.lastChangedEpoch).toEqual(lastChangedEpoch)
|
||||
|
||||
// make a change that does affect the query just to check
|
||||
store.put([{ ...authors.davidMitchellFunny, name: 'steve' }])
|
||||
|
||||
mitchell.value
|
||||
mitchell.get()
|
||||
expect(mitchell.lastChangedEpoch).toBeGreaterThan(lastChangedEpoch)
|
||||
})
|
||||
|
||||
|
@ -613,7 +613,7 @@ describe('queries for ids', () => {
|
|||
name: { eq: 'David Mitchell' },
|
||||
}))
|
||||
|
||||
expect(mitchell.value).toEqual(
|
||||
expect(mitchell.get()).toEqual(
|
||||
new Set([authors.davidMitchellFunny.id, authors.davidMitchellSerious.id])
|
||||
)
|
||||
|
||||
|
@ -622,7 +622,7 @@ describe('queries for ids', () => {
|
|||
store.remove([authors.davidMitchellFunny.id])
|
||||
store.put([authors.davidMitchellFunny])
|
||||
|
||||
mitchell.value
|
||||
mitchell.get()
|
||||
|
||||
expect(mitchell.lastChangedEpoch).toEqual(lastChangedEpoch)
|
||||
})
|
||||
|
@ -632,7 +632,7 @@ describe('queries for ids', () => {
|
|||
name: { eq: 'David Mitchell' },
|
||||
}))
|
||||
|
||||
expect(mitchell.value).toEqual(
|
||||
expect(mitchell.get()).toEqual(
|
||||
new Set([authors.davidMitchellFunny.id, authors.davidMitchellSerious.id])
|
||||
)
|
||||
|
||||
|
@ -643,7 +643,7 @@ describe('queries for ids', () => {
|
|||
store.put([newMitchell])
|
||||
store.remove([newMitchell.id])
|
||||
|
||||
mitchell.value
|
||||
mitchell.get()
|
||||
|
||||
expect(mitchell.lastChangedEpoch).toEqual(lastChangedEpoch)
|
||||
})
|
||||
|
@ -655,7 +655,7 @@ describe('queries for records', () => {
|
|||
it('can query for all values of a given type', () => {
|
||||
const allBooks = store.query.records('book')
|
||||
|
||||
expect(allBooks.value.sort(bookComparator)).toEqual(
|
||||
expect(allBooks.get().sort(bookComparator)).toEqual(
|
||||
[books.cloudAtlas, books.farenheit, books.lotr, books.myLifeInComedy].sort(bookComparator)
|
||||
)
|
||||
|
||||
|
@ -663,7 +663,7 @@ describe('queries for records', () => {
|
|||
|
||||
store.put([newBook])
|
||||
|
||||
expect(allBooks.value.sort(bookComparator)).toEqual(
|
||||
expect(allBooks.get().sort(bookComparator)).toEqual(
|
||||
[books.cloudAtlas, books.farenheit, books.lotr, books.myLifeInComedy, newBook].sort(
|
||||
bookComparator
|
||||
)
|
||||
|
@ -675,7 +675,7 @@ describe('queries for records', () => {
|
|||
title: { eq: 'Farenheit 451' },
|
||||
}))
|
||||
|
||||
expect(farenheit.value).toEqual([books.farenheit])
|
||||
expect(farenheit.get()).toEqual([books.farenheit])
|
||||
})
|
||||
|
||||
it('can query for multiple values', () => {
|
||||
|
@ -688,7 +688,7 @@ describe('queries for records', () => {
|
|||
authorId: { eq: authors.davidMitchellFunny.id },
|
||||
}))
|
||||
|
||||
expect(mitchell.value.sort(bookComparator)).toEqual(
|
||||
expect(mitchell.get().sort(bookComparator)).toEqual(
|
||||
[books.myLifeInComedy, funnyGuide].sort(bookComparator)
|
||||
)
|
||||
})
|
||||
|
@ -696,14 +696,14 @@ describe('queries for records', () => {
|
|||
it('supports reactive queries', () => {
|
||||
const currentAuthor = atom('currentAuthor', authors.davidMitchellFunny.id)
|
||||
const booksQuery = store.query.records('book', () => ({
|
||||
authorId: { eq: currentAuthor.value },
|
||||
authorId: { eq: currentAuthor.get() },
|
||||
}))
|
||||
|
||||
expect(booksQuery.value).toEqual([books.myLifeInComedy])
|
||||
expect(booksQuery.get()).toEqual([books.myLifeInComedy])
|
||||
|
||||
currentAuthor.set(authors.tolkein.id)
|
||||
|
||||
expect(booksQuery.value).toEqual([books.lotr])
|
||||
expect(booksQuery.get()).toEqual([books.lotr])
|
||||
})
|
||||
})
|
||||
|
||||
|
@ -717,7 +717,7 @@ describe('filtering history', () => {
|
|||
it('allows filtering history', () => {
|
||||
const authorHistory = store.query.filterHistory('author')
|
||||
|
||||
authorHistory.value
|
||||
authorHistory.get()
|
||||
|
||||
let lastChangedEpoch = authorHistory.lastChangedEpoch
|
||||
|
||||
|
@ -726,7 +726,7 @@ describe('filtering history', () => {
|
|||
// updating an author should change the history
|
||||
store.put([{ ...authors.davidMitchellFunny, age: 30 }])
|
||||
|
||||
authorHistory.value
|
||||
authorHistory.get()
|
||||
|
||||
expect(lastChangedEpoch).toBeLessThan(authorHistory.lastChangedEpoch)
|
||||
|
||||
|
@ -742,7 +742,7 @@ describe('filtering history', () => {
|
|||
{ ...books.lotr, title: 'The Lord of the Rings Part I: The Fellowship of the Ring' },
|
||||
])
|
||||
|
||||
authorHistory.value
|
||||
authorHistory.get()
|
||||
|
||||
expect(authorHistory.lastChangedEpoch).toEqual(lastChangedEpoch)
|
||||
expect(authorHistory.getDiffSince(lastChangedEpoch)).toMatchObject([])
|
||||
|
@ -751,25 +751,25 @@ describe('filtering history', () => {
|
|||
it('should not update if changes in a window of time cancel each other out', () => {
|
||||
const authorHistory = store.query.filterHistory('author')
|
||||
|
||||
const epoch = authorHistory.value
|
||||
const epoch = authorHistory.get()
|
||||
const newAuthor = Author.create({ name: 'Stanley Briggs' })
|
||||
|
||||
store.put([newAuthor])
|
||||
store.put([{ ...newAuthor, age: 38 }])
|
||||
store.remove([newAuthor.id])
|
||||
|
||||
expect(authorHistory.value).toEqual(epoch)
|
||||
expect(authorHistory.get()).toEqual(epoch)
|
||||
|
||||
store.remove([authors.tolkein.id])
|
||||
store.put([authors.tolkein])
|
||||
|
||||
expect(authorHistory.value).toEqual(epoch)
|
||||
expect(authorHistory.get()).toEqual(epoch)
|
||||
})
|
||||
|
||||
it('removes update entries if a thing was deleted', () => {
|
||||
const authorHistory = store.query.filterHistory('author')
|
||||
|
||||
authorHistory.value
|
||||
authorHistory.get()
|
||||
|
||||
const lastChangedEpoch = authorHistory.lastChangedEpoch
|
||||
|
||||
|
@ -788,7 +788,7 @@ describe('filtering history', () => {
|
|||
it('collapses multiple updated entries into one', () => {
|
||||
const authorHistory = store.query.filterHistory('author')
|
||||
|
||||
authorHistory.value
|
||||
authorHistory.get()
|
||||
|
||||
const lastChangedEpoch = authorHistory.lastChangedEpoch
|
||||
|
||||
|
@ -805,7 +805,7 @@ describe('filtering history', () => {
|
|||
it('collapeses an add + update entry into just an add entry', () => {
|
||||
const authorHistory = store.query.filterHistory('author')
|
||||
|
||||
authorHistory.value
|
||||
authorHistory.get()
|
||||
|
||||
const lastChangedEpoch = authorHistory.lastChangedEpoch
|
||||
|
||||
|
|
|
@ -69,7 +69,7 @@ describe('Store with validation', () => {
|
|||
it('Accepts valid records and rejects invalid records', () => {
|
||||
store.put([Author.create({ name: 'J.R.R Tolkein', id: Author.createId('tolkein') })])
|
||||
|
||||
expect(store.query.records('author').value).toEqual([
|
||||
expect(store.query.records('author').get()).toEqual([
|
||||
{ id: 'author:tolkein', typeName: 'author', name: 'J.R.R Tolkein', isPseudonym: false },
|
||||
])
|
||||
|
||||
|
@ -85,7 +85,7 @@ describe('Store with validation', () => {
|
|||
])
|
||||
}).toThrow()
|
||||
|
||||
expect(store.query.records('book').value).toEqual([])
|
||||
expect(store.query.records('book').get()).toEqual([])
|
||||
})
|
||||
})
|
||||
|
||||
|
|
|
@ -33,8 +33,9 @@ export const TldrawSelectionForeground: TLSelectionForegroundComponent = track(
|
|||
const bottomRightEvents = useSelectionEvents('bottom_right')
|
||||
const bottomLeftEvents = useSelectionEvents('bottom_left')
|
||||
|
||||
const isDefaultCursor = !editor.isMenuOpen && editor.instanceState.cursor.type === 'default'
|
||||
const isCoarsePointer = editor.instanceState.isCoarsePointer
|
||||
const isDefaultCursor =
|
||||
!editor.isMenuOpen && editor.getInstanceState().cursor.type === 'default'
|
||||
const isCoarsePointer = editor.getInstanceState().isCoarsePointer
|
||||
|
||||
const shapes = editor.selectedShapes
|
||||
const onlyShape = editor.onlySelectedShape
|
||||
|
@ -54,7 +55,7 @@ export const TldrawSelectionForeground: TLSelectionForegroundComponent = track(
|
|||
bounds = bounds.clone().expandBy(expandOutlineBy).zeroFix()
|
||||
|
||||
const zoom = editor.zoomLevel
|
||||
const isChangingStyle = editor.instanceState.isChangingStyle
|
||||
const isChangingStyle = editor.getInstanceState().isChangingStyle
|
||||
|
||||
const width = bounds.width
|
||||
const height = bounds.height
|
||||
|
|
|
@ -33,7 +33,7 @@ beforeEach(() => {
|
|||
|
||||
it('enters the arrow state', () => {
|
||||
editor.setCurrentTool('arrow')
|
||||
expect(editor.currentToolId).toBe('arrow')
|
||||
expect(editor.getCurrentToolId()).toBe('arrow')
|
||||
editor.expectPathToBe('root.arrow.idle')
|
||||
})
|
||||
|
||||
|
|
|
@ -494,7 +494,7 @@ export class ArrowShapeUtil extends ShapeUtil<TLArrowShape> {
|
|||
'select.pointing_handle',
|
||||
'select.dragging_handle',
|
||||
'arrow.dragging'
|
||||
) && !this.editor.instanceState.isReadonly
|
||||
) && !this.editor.getInstanceState().isReadonly
|
||||
|
||||
const info = this.editor.getArrowInfo(shape)
|
||||
const bounds = Box2d.ZeroFix(this.editor.getShapeGeometry(shape).bounds)
|
||||
|
|
|
@ -17,7 +17,7 @@ export class Idle extends StateNode {
|
|||
|
||||
override onKeyUp: TLEventHandlers['onKeyUp'] = (info) => {
|
||||
if (info.key === 'Enter') {
|
||||
if (this.editor.instanceState.isReadonly) return null
|
||||
if (this.editor.getInstanceState().isReadonly) return null
|
||||
const { onlySelectedShape } = this.editor
|
||||
// If the only selected shape is editable, start editing it
|
||||
if (
|
||||
|
@ -26,7 +26,7 @@ export class Idle extends StateNode {
|
|||
) {
|
||||
this.editor.setCurrentTool('select')
|
||||
this.editor.setEditingShape(onlySelectedShape.id)
|
||||
this.editor.root.current.value!.transition('editing_shape', {
|
||||
this.editor.root.current.get()!.transition('editing_shape', {
|
||||
...info,
|
||||
target: 'shape',
|
||||
shape: onlySelectedShape,
|
||||
|
|
|
@ -13,7 +13,7 @@ export class Idle extends StateNode {
|
|||
|
||||
override onKeyUp: TLEventHandlers['onKeyUp'] = (info) => {
|
||||
if (info.key === 'Enter') {
|
||||
if (this.editor.instanceState.isReadonly) return null
|
||||
if (this.editor.getInstanceState().isReadonly) return null
|
||||
|
||||
const { onlySelectedShape } = this.editor
|
||||
// If the only selected shape is editable, start editing it
|
||||
|
@ -23,7 +23,7 @@ export class Idle extends StateNode {
|
|||
) {
|
||||
this.editor.setCurrentTool('select')
|
||||
this.editor.setEditingShape(onlySelectedShape.id)
|
||||
this.editor.root.current.value!.transition('editing_shape', {
|
||||
this.editor.root.current.get()!.transition('editing_shape', {
|
||||
...info,
|
||||
target: 'shape',
|
||||
shape: onlySelectedShape,
|
||||
|
|
|
@ -117,7 +117,7 @@ export class Pointing extends StateNode {
|
|||
},
|
||||
])
|
||||
|
||||
if (this.editor.instanceState.isToolLocked) {
|
||||
if (this.editor.getInstanceState().isToolLocked) {
|
||||
this.parent.transition('idle', {})
|
||||
} else {
|
||||
this.editor.setCurrentTool('select', {})
|
||||
|
|
|
@ -9,7 +9,7 @@ beforeEach(() => {
|
|||
|
||||
it('enters the line state', () => {
|
||||
editor.setCurrentTool('line')
|
||||
expect(editor.currentToolId).toBe('line')
|
||||
expect(editor.getCurrentToolId()).toBe('line')
|
||||
editor.expectPathToBe('root.line.idle')
|
||||
})
|
||||
|
||||
|
|
|
@ -62,7 +62,7 @@ export class Pointing extends StateNode {
|
|||
|
||||
private complete() {
|
||||
if (this.wasFocusedOnEnter) {
|
||||
if (this.editor.instanceState.isToolLocked) {
|
||||
if (this.editor.getInstanceState().isToolLocked) {
|
||||
this.parent.transition('idle', {})
|
||||
} else {
|
||||
this.editor.setEditingShape(this.shape.id)
|
||||
|
|
|
@ -137,7 +137,7 @@ const generateImage = (dpr: number, currentZoom: number, darkMode: boolean) => {
|
|||
ctx.stroke()
|
||||
|
||||
canvasEl.toBlob((blob) => {
|
||||
if (!blob || debugFlags.throwToBlob.value) {
|
||||
if (!blob || debugFlags.throwToBlob.get()) {
|
||||
reject()
|
||||
} else {
|
||||
resolve(blob)
|
||||
|
@ -184,7 +184,7 @@ const getDefaultPatterns = () => {
|
|||
|
||||
function usePattern() {
|
||||
const editor = useEditor()
|
||||
const dpr = editor.instanceState.devicePixelRatio
|
||||
const dpr = editor.getInstanceState().devicePixelRatio
|
||||
const [isReady, setIsReady] = useState(false)
|
||||
const defaultPatterns = useMemo(() => getDefaultPatterns(), [])
|
||||
const [backgroundUrls, setBackgroundUrls] = useState<PatternDef[]>(defaultPatterns)
|
||||
|
|
|
@ -23,7 +23,7 @@ export class Idle extends StateNode {
|
|||
|
||||
override onKeyDown: TLEventHandlers['onKeyDown'] = (info) => {
|
||||
if (info.key === 'Enter') {
|
||||
if (this.editor.instanceState.isReadonly) return null
|
||||
if (this.editor.getInstanceState().isReadonly) return null
|
||||
const { onlySelectedShape } = this.editor
|
||||
// If the only selected shape is editable, start editing it
|
||||
if (
|
||||
|
@ -32,7 +32,7 @@ export class Idle extends StateNode {
|
|||
) {
|
||||
this.editor.setCurrentTool('select')
|
||||
this.editor.setEditingShape(onlySelectedShape.id)
|
||||
this.editor.root.current.value!.transition('editing_shape', {
|
||||
this.editor.root.current.get()!.transition('editing_shape', {
|
||||
...info,
|
||||
target: 'shape',
|
||||
shape: onlySelectedShape,
|
||||
|
|
|
@ -90,7 +90,7 @@ export class Pointing extends StateNode {
|
|||
|
||||
this.editor.setEditingShape(id)
|
||||
this.editor.setCurrentTool('select')
|
||||
this.editor.root.current.value?.transition('editing_shape', {})
|
||||
this.editor.root.current.get()?.transition('editing_shape', {})
|
||||
}
|
||||
|
||||
private cancel() {
|
||||
|
|
|
@ -179,7 +179,7 @@ export class DraggingHandle extends StateNode {
|
|||
this.editor.snaps.clear()
|
||||
|
||||
const { onInteractionEnd } = this.info
|
||||
if (this.editor.instanceState.isToolLocked && onInteractionEnd) {
|
||||
if (this.editor.getInstanceState().isToolLocked && onInteractionEnd) {
|
||||
// Return to the tool that was active before this one,
|
||||
// but only if tool lock is turned on!
|
||||
this.editor.setCurrentTool(onInteractionEnd, { shapeId: this.shapeId })
|
||||
|
|
|
@ -98,7 +98,7 @@ export class Idle extends StateNode {
|
|||
break
|
||||
}
|
||||
case 'handle': {
|
||||
if (this.editor.instanceState.isReadonly) break
|
||||
if (this.editor.getInstanceState().isReadonly) break
|
||||
if (this.editor.inputs.altKey) {
|
||||
this.parent.transition('pointing_shape', info)
|
||||
} else {
|
||||
|
@ -222,7 +222,7 @@ export class Idle extends StateNode {
|
|||
break
|
||||
}
|
||||
case 'selection': {
|
||||
if (this.editor.instanceState.isReadonly) break
|
||||
if (this.editor.getInstanceState().isReadonly) break
|
||||
|
||||
const { onlySelectedShape } = this.editor
|
||||
|
||||
|
@ -271,7 +271,7 @@ export class Idle extends StateNode {
|
|||
if (
|
||||
shape.type !== 'video' &&
|
||||
shape.type !== 'embed' &&
|
||||
this.editor.instanceState.isReadonly
|
||||
this.editor.getInstanceState().isReadonly
|
||||
)
|
||||
break
|
||||
|
||||
|
@ -302,7 +302,7 @@ export class Idle extends StateNode {
|
|||
break
|
||||
}
|
||||
case 'handle': {
|
||||
if (this.editor.instanceState.isReadonly) break
|
||||
if (this.editor.getInstanceState().isReadonly) break
|
||||
const { shape, handle } = info
|
||||
|
||||
const util = this.editor.getShapeUtil(shape)
|
||||
|
@ -475,7 +475,7 @@ export class Idle extends StateNode {
|
|||
|
||||
handleDoubleClickOnCanvas(info: TLClickEventInfo) {
|
||||
// Create text shape and transition to editing_shape
|
||||
if (this.editor.instanceState.isReadonly) return
|
||||
if (this.editor.getInstanceState().isReadonly) return
|
||||
|
||||
this.editor.mark('creating text shape')
|
||||
|
||||
|
@ -500,7 +500,7 @@ export class Idle extends StateNode {
|
|||
if (!shape) return
|
||||
|
||||
const util = this.editor.getShapeUtil(shape)
|
||||
if (this.editor.instanceState.isReadonly) {
|
||||
if (this.editor.getInstanceState().isReadonly) {
|
||||
if (!util.canEditInReadOnly(shape)) {
|
||||
return
|
||||
}
|
||||
|
@ -534,9 +534,9 @@ export class Idle extends StateNode {
|
|||
|
||||
if (!ephemeral) this.editor.mark('nudge shapes')
|
||||
|
||||
const { gridSize } = this.editor.documentSettings
|
||||
const { gridSize } = this.editor.getDocumentSettings()
|
||||
|
||||
const step = this.editor.instanceState.isGridMode
|
||||
const step = this.editor.getInstanceState().isGridMode
|
||||
? shiftKey
|
||||
? gridSize * GRID_INCREMENT
|
||||
: gridSize
|
||||
|
@ -548,7 +548,7 @@ export class Idle extends StateNode {
|
|||
}
|
||||
|
||||
private canInteractWithShapeInReadOnly(shape: TLShape) {
|
||||
if (!this.editor.instanceState.isReadonly) return true
|
||||
if (!this.editor.getInstanceState().isReadonly) return true
|
||||
const util = this.editor.getShapeUtil(shape)
|
||||
if (util.canEditInReadOnly(shape)) return true
|
||||
return false
|
||||
|
|
|
@ -25,7 +25,7 @@ export class PointingSelection extends StateNode {
|
|||
|
||||
override onPointerMove: TLEventHandlers['onPointerMove'] = (info) => {
|
||||
if (this.editor.inputs.isDragging) {
|
||||
if (this.editor.instanceState.isReadonly) return
|
||||
if (this.editor.getInstanceState().isReadonly) return
|
||||
this.parent.transition('translating', info)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -151,7 +151,7 @@ export class PointingShape extends StateNode {
|
|||
this.editor.select(selectingShape.id)
|
||||
|
||||
const util = this.editor.getShapeUtil(selectingShape)
|
||||
if (this.editor.instanceState.isReadonly) {
|
||||
if (this.editor.getInstanceState().isReadonly) {
|
||||
if (!util.canEditInReadOnly(selectingShape)) {
|
||||
return
|
||||
}
|
||||
|
@ -195,7 +195,7 @@ export class PointingShape extends StateNode {
|
|||
|
||||
override onPointerMove: TLEventHandlers['onPointerMove'] = (info) => {
|
||||
if (this.editor.inputs.isDragging) {
|
||||
if (this.editor.instanceState.isReadonly) return
|
||||
if (this.editor.getInstanceState().isReadonly) return
|
||||
this.parent.transition('translating', info)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -113,7 +113,7 @@ export class Resizing extends StateNode {
|
|||
return
|
||||
}
|
||||
|
||||
if (this.editor.instanceState.isToolLocked && this.info.onInteractionEnd) {
|
||||
if (this.editor.getInstanceState().isToolLocked && this.info.onInteractionEnd) {
|
||||
this.editor.setCurrentTool(this.info.onInteractionEnd, {})
|
||||
return
|
||||
}
|
||||
|
@ -212,8 +212,8 @@ export class Resizing extends StateNode {
|
|||
.sub(this.creationCursorOffset)
|
||||
const originPagePoint = this.editor.inputs.originPagePoint.clone().sub(cursorHandleOffset)
|
||||
|
||||
if (this.editor.instanceState.isGridMode && !ctrlKey) {
|
||||
const { gridSize } = this.editor.documentSettings
|
||||
if (this.editor.getInstanceState().isGridMode && !ctrlKey) {
|
||||
const { gridSize } = this.editor.getDocumentSettings()
|
||||
currentPagePoint.snapToGrid(gridSize)
|
||||
}
|
||||
|
||||
|
@ -328,7 +328,7 @@ export class Resizing extends StateNode {
|
|||
isFlippedY: boolean
|
||||
rotation: number
|
||||
}) {
|
||||
const nextCursor = { ...this.editor.instanceState.cursor }
|
||||
const nextCursor = { ...this.editor.getInstanceState().cursor }
|
||||
|
||||
switch (dragHandle) {
|
||||
case 'top_left':
|
||||
|
|
|
@ -161,7 +161,7 @@ export class Rotating extends StateNode {
|
|||
} else if (snapToNearestDegree) {
|
||||
newSelectionRotation = Math.round(newSelectionRotation / EPSILON) * EPSILON
|
||||
|
||||
if (this.editor.instanceState.isCoarsePointer) {
|
||||
if (this.editor.getInstanceState().isCoarsePointer) {
|
||||
const snappedToRightAngle = snapAngle(newSelectionRotation, 4)
|
||||
const angleToRightAngle = angleDelta(newSelectionRotation, snappedToRightAngle)
|
||||
if (Math.abs(angleToRightAngle) < degreesToRadians(5)) {
|
||||
|
|
|
@ -162,7 +162,7 @@ export class Translating extends StateNode {
|
|||
this.dragAndDropManager.dropShapes(this.snapshot.movingShapes)
|
||||
this.handleEnd()
|
||||
|
||||
if (this.editor.instanceState.isToolLocked && this.info.onInteractionEnd) {
|
||||
if (this.editor.getInstanceState().isToolLocked && this.info.onInteractionEnd) {
|
||||
this.editor.setCurrentTool(this.info.onInteractionEnd)
|
||||
} else {
|
||||
if (this.editAfterComplete) {
|
||||
|
@ -345,11 +345,11 @@ export function moveShapesToPoint({
|
|||
initialSelectionPageBounds: Box2d
|
||||
initialSelectionSnapPoints: SnapPoint[]
|
||||
}) {
|
||||
const {
|
||||
inputs,
|
||||
instanceState: { isGridMode },
|
||||
documentSettings: { gridSize },
|
||||
} = editor
|
||||
const { inputs } = editor
|
||||
|
||||
const isGridMode = editor.getInstanceState().isGridMode
|
||||
|
||||
const gridSize = editor.getDocumentSettings().gridSize
|
||||
|
||||
const delta = Vec2d.Sub(inputs.currentPagePoint, inputs.originPagePoint)
|
||||
|
||||
|
|
|
@ -120,9 +120,11 @@ const TldrawUiContent = React.memo(function TldrawUI({
|
|||
const editor = useEditor()
|
||||
const msg = useTranslation()
|
||||
const breakpoint = useBreakpoint()
|
||||
const isReadonlyMode = useValue('isReadonlyMode', () => editor.instanceState.isReadonly, [editor])
|
||||
const isFocusMode = useValue('focus', () => editor.instanceState.isFocusMode, [editor])
|
||||
const isDebugMode = useValue('debug', () => editor.instanceState.isDebugMode, [editor])
|
||||
const isReadonlyMode = useValue('isReadonlyMode', () => editor.getInstanceState().isReadonly, [
|
||||
editor,
|
||||
])
|
||||
const isFocusMode = useValue('focus', () => editor.getInstanceState().isFocusMode, [editor])
|
||||
const isDebugMode = useValue('debug', () => editor.getInstanceState().isDebugMode, [editor])
|
||||
|
||||
useKeyboardShortcuts()
|
||||
useNativeClipboardEvents()
|
||||
|
|
|
@ -34,7 +34,7 @@ export const ContextMenu = function ContextMenu({ children }: { children: any })
|
|||
}
|
||||
} else {
|
||||
// Weird route: selecting locked shapes on long press
|
||||
if (editor.instanceState.isCoarsePointer) {
|
||||
if (editor.getInstanceState().isCoarsePointer) {
|
||||
const {
|
||||
selectedShapes,
|
||||
inputs: { currentPagePoint },
|
||||
|
@ -74,9 +74,11 @@ export const ContextMenu = function ContextMenu({ children }: { children: any })
|
|||
contextTLUiMenuSchema.length === 0 ||
|
||||
(isReadonly && contextTLUiMenuSchema.every((item) => !item.readonlyOk))
|
||||
|
||||
const selectToolActive = useValue('isSelectToolActive', () => editor.currentToolId === 'select', [
|
||||
editor,
|
||||
])
|
||||
const selectToolActive = useValue(
|
||||
'isSelectToolActive',
|
||||
() => editor.getCurrentToolId() === 'select',
|
||||
[editor]
|
||||
)
|
||||
|
||||
const disabled = !selectToolActive || noItemsToShow
|
||||
|
||||
|
|
|
@ -65,7 +65,7 @@ export const DebugPanel = React.memo(function DebugPanel({
|
|||
|
||||
const CurrentState = track(function CurrentState() {
|
||||
const editor = useEditor()
|
||||
return <div className="tlui-debug-panel__current-state">{editor.root.path.value}</div>
|
||||
return <div className="tlui-debug-panel__current-state">{editor.root.path.get()}</div>
|
||||
})
|
||||
|
||||
const ShapeCount = function ShapeCount() {
|
||||
|
@ -261,7 +261,7 @@ const DebugFlagToggle = track(function DebugFlagToggle({
|
|||
label={flag.name
|
||||
.replace(/([a-z0-9])([A-Z])/g, (m) => `${m[0]} ${m[1].toLowerCase()}`)
|
||||
.replace(/^[a-z]/, (m) => m.toUpperCase())}
|
||||
value={flag.value}
|
||||
value={flag.get()}
|
||||
onChange={(newValue) => {
|
||||
flag.set(newValue)
|
||||
onChange?.(newValue)
|
||||
|
|
|
@ -2,7 +2,9 @@ import { useEditor, usePresence, useValue } from '@tldraw/editor'
|
|||
|
||||
export function FollowingIndicator() {
|
||||
const editor = useEditor()
|
||||
const followingUserId = useValue('follow', () => editor.instanceState.followingUserId, [editor])
|
||||
const followingUserId = useValue('follow', () => editor.getInstanceState().followingUserId, [
|
||||
editor,
|
||||
])
|
||||
if (!followingUserId) return null
|
||||
return <FollowingIndicatorInner userId={followingUserId} />
|
||||
}
|
||||
|
|
|
@ -30,7 +30,9 @@ export function Minimap({ shapeFill, selectFill, viewportFill }: MinimapProps) {
|
|||
const rPointing = React.useRef(false)
|
||||
|
||||
const isDarkMode = useIsDarkMode()
|
||||
const devicePixelRatio = useComputed('dpr', () => editor.instanceState.devicePixelRatio, [editor])
|
||||
const devicePixelRatio = useComputed('dpr', () => editor.getInstanceState().devicePixelRatio, [
|
||||
editor,
|
||||
])
|
||||
const presences = React.useMemo(() => editor.store.query.records('instance_presence'), [editor])
|
||||
|
||||
const minimap = React.useMemo(() => new MinimapManager(editor), [editor])
|
||||
|
@ -135,7 +137,7 @@ export function Minimap({ shapeFill, selectFill, viewportFill }: MinimapProps) {
|
|||
name: 'pointer_move',
|
||||
...getPointerInfo(e),
|
||||
point: screenPoint,
|
||||
isPen: editor.instanceState.isPenMode,
|
||||
isPen: editor.getInstanceState().isPenMode,
|
||||
}
|
||||
|
||||
editor.dispatch(info)
|
||||
|
@ -164,7 +166,7 @@ export function Minimap({ shapeFill, selectFill, viewportFill }: MinimapProps) {
|
|||
useQuickReactor(
|
||||
'update when dpr changes',
|
||||
() => {
|
||||
const dpr = devicePixelRatio.value
|
||||
const dpr = devicePixelRatio.get()
|
||||
minimap.setDpr(dpr)
|
||||
|
||||
const canvas = rCanvas.current as HTMLCanvasElement
|
||||
|
@ -191,7 +193,7 @@ export function Minimap({ shapeFill, selectFill, viewportFill }: MinimapProps) {
|
|||
currentPageBounds: commonBoundsOfAllShapesOnCurrentPage,
|
||||
} = editor
|
||||
|
||||
const _dpr = devicePixelRatio.value // dereference
|
||||
const _dpr = devicePixelRatio.get() // dereference
|
||||
|
||||
minimap.contentPageBounds = commonBoundsOfAllShapesOnCurrentPage
|
||||
? Box2d.Expand(commonBoundsOfAllShapesOnCurrentPage, viewportPageBounds)
|
||||
|
@ -224,7 +226,7 @@ export function Minimap({ shapeFill, selectFill, viewportFill }: MinimapProps) {
|
|||
})
|
||||
|
||||
minimap.pageBounds = allShapeBounds
|
||||
minimap.collaborators = presences.value
|
||||
minimap.collaborators = presences.get()
|
||||
minimap.render()
|
||||
},
|
||||
[editor, minimap]
|
||||
|
|
|
@ -255,7 +255,7 @@ export class MinimapManager {
|
|||
|
||||
// Brush
|
||||
{
|
||||
const { brush } = editor.instanceState
|
||||
const { brush } = editor.getInstanceState()
|
||||
if (brush) {
|
||||
const { x, y, w, h } = brush
|
||||
ctx.beginPath()
|
||||
|
|
|
@ -46,9 +46,11 @@ export const PageMenu = function PageMenu() {
|
|||
[editor]
|
||||
)
|
||||
|
||||
const isCoarsePointer = useValue('isCoarsePointer', () => editor.instanceState.isCoarsePointer, [
|
||||
editor,
|
||||
])
|
||||
const isCoarsePointer = useValue(
|
||||
'isCoarsePointer',
|
||||
() => editor.getInstanceState().isCoarsePointer,
|
||||
[editor]
|
||||
)
|
||||
|
||||
// The component has an "editing state" that may be toggled to expose additional controls
|
||||
const [isEditing, setIsEditing] = useState(false)
|
||||
|
|
|
@ -5,7 +5,7 @@ import { Button } from './primitives/Button'
|
|||
export const ExitPenMode = track(function ExitPenMode() {
|
||||
const editor = useEditor()
|
||||
|
||||
const isPenMode = editor.instanceState.isPenMode
|
||||
const isPenMode = editor.getInstanceState().isPenMode
|
||||
|
||||
const actions = useActions()
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ export const StopFollowing = track(function ExitPenMode() {
|
|||
const editor = useEditor()
|
||||
const actions = useActions()
|
||||
|
||||
if (!editor.instanceState.followingUserId) {
|
||||
if (!editor.getInstanceState().followingUserId) {
|
||||
return null
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,9 @@ export function ToggleToolLockedButton({ activeToolId }: ToggleToolLockedButtonP
|
|||
const breakpoint = useBreakpoint()
|
||||
const msg = useTranslation()
|
||||
|
||||
const isToolLocked = useValue('is tool locked', () => editor.instanceState.isToolLocked, [editor])
|
||||
const isToolLocked = useValue('is tool locked', () => editor.getInstanceState().isToolLocked, [
|
||||
editor,
|
||||
])
|
||||
|
||||
if (!activeToolId || NOT_LOCKABLE_TOOLS.includes(activeToolId)) return null
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ export const Toolbar = memo(function Toolbar() {
|
|||
const toolbarItems = useToolbarSchema()
|
||||
const laserTool = toolbarItems.find((item) => item.toolItem.id === 'laser')
|
||||
|
||||
const activeToolId = useValue('current tool id', () => editor.currentToolId, [editor])
|
||||
const activeToolId = useValue('current tool id', () => editor.getCurrentToolId(), [editor])
|
||||
|
||||
const geoState = useValue('geo', () => editor.sharedStyles.getAsKnownValue(GeoShapeGeoStyle), [
|
||||
editor,
|
||||
|
|
|
@ -278,12 +278,12 @@ export function ActionsProvider({ overrides, children }: ActionsProviderProps) {
|
|||
readonlyOk: true,
|
||||
kbd: 'z',
|
||||
onSelect(source) {
|
||||
if (editor.root.current.value?.id === 'zoom') return
|
||||
if (editor.root.current.get()?.id === 'zoom') return
|
||||
|
||||
trackEvent('zoom-tool', { source })
|
||||
if (!(editor.inputs.shiftKey || editor.inputs.ctrlKey)) {
|
||||
const currentTool = editor.root.current.value
|
||||
if (currentTool && currentTool.current.value?.id === 'idle') {
|
||||
const currentTool = editor.root.current.get()
|
||||
if (currentTool && currentTool.current.get()?.id === 'idle') {
|
||||
editor.setCurrentTool('zoom', { onInteractionEnd: currentTool.id, maskAs: 'zoom' })
|
||||
}
|
||||
}
|
||||
|
@ -402,7 +402,7 @@ export function ActionsProvider({ overrides, children }: ActionsProviderProps) {
|
|||
trackEvent('duplicate-shapes', { source })
|
||||
const ids = editor.selectedShapeIds
|
||||
const commonBounds = Box2d.Common(compact(ids.map((id) => editor.getShapePageBounds(id))))
|
||||
const offset = editor.instanceState.canMoveCamera
|
||||
const offset = editor.getInstanceState().canMoveCamera
|
||||
? {
|
||||
x: commonBounds.width + 10,
|
||||
y: 0,
|
||||
|
@ -955,7 +955,7 @@ export function ActionsProvider({ overrides, children }: ActionsProviderProps) {
|
|||
trackEvent('toggle-transparent', { source })
|
||||
editor.updateInstanceState(
|
||||
{
|
||||
exportBackground: !editor.instanceState.exportBackground,
|
||||
exportBackground: !editor.getInstanceState().exportBackground,
|
||||
},
|
||||
{ ephemeral: true }
|
||||
)
|
||||
|
@ -970,7 +970,7 @@ export function ActionsProvider({ overrides, children }: ActionsProviderProps) {
|
|||
kbd: 'q',
|
||||
onSelect(source) {
|
||||
trackEvent('toggle-tool-lock', { source })
|
||||
editor.updateInstanceState({ isToolLocked: !editor.instanceState.isToolLocked })
|
||||
editor.updateInstanceState({ isToolLocked: !editor.getInstanceState().isToolLocked })
|
||||
},
|
||||
checkbox: true,
|
||||
},
|
||||
|
@ -1006,7 +1006,7 @@ export function ActionsProvider({ overrides, children }: ActionsProviderProps) {
|
|||
trackEvent('toggle-focus-mode', { source })
|
||||
clearDialogs()
|
||||
clearToasts()
|
||||
editor.updateInstanceState({ isFocusMode: !editor.instanceState.isFocusMode })
|
||||
editor.updateInstanceState({ isFocusMode: !editor.getInstanceState().isFocusMode })
|
||||
})
|
||||
})
|
||||
},
|
||||
|
@ -1019,7 +1019,7 @@ export function ActionsProvider({ overrides, children }: ActionsProviderProps) {
|
|||
kbd: "$'",
|
||||
onSelect(source) {
|
||||
trackEvent('toggle-grid-mode', { source })
|
||||
editor.updateInstanceState({ isGridMode: !editor.instanceState.isGridMode })
|
||||
editor.updateInstanceState({ isGridMode: !editor.getInstanceState().isGridMode })
|
||||
},
|
||||
checkbox: true,
|
||||
},
|
||||
|
@ -1031,7 +1031,7 @@ export function ActionsProvider({ overrides, children }: ActionsProviderProps) {
|
|||
onSelect(source) {
|
||||
trackEvent('toggle-debug-mode', { source })
|
||||
editor.updateInstanceState({
|
||||
isDebugMode: !editor.instanceState.isDebugMode,
|
||||
isDebugMode: !editor.getInstanceState().isDebugMode,
|
||||
})
|
||||
},
|
||||
checkbox: true,
|
||||
|
|
|
@ -3,5 +3,5 @@ import { useEditor, useValue } from '@tldraw/editor'
|
|||
/** @public */
|
||||
export function useCanRedo() {
|
||||
const editor = useEditor()
|
||||
return useValue('useCanRedo', () => editor.canRedo, [editor])
|
||||
return useValue('useCanRedo', () => editor.getCanRedo(), [editor])
|
||||
}
|
||||
|
|
|
@ -3,5 +3,5 @@ import { useEditor, useValue } from '@tldraw/editor'
|
|||
/** @public */
|
||||
export function useCanUndo() {
|
||||
const editor = useEditor()
|
||||
return useValue('useCanUndo', () => editor.canUndo, [editor])
|
||||
return useValue('useCanUndo', () => editor.getCanUndo(), [editor])
|
||||
}
|
||||
|
|
|
@ -625,7 +625,9 @@ export function useNativeClipboardEvents() {
|
|||
const editor = useEditor()
|
||||
const trackEvent = useUiEvents()
|
||||
|
||||
const appIsFocused = useValue('editor.isFocused', () => editor.instanceState.isFocused, [editor])
|
||||
const appIsFocused = useValue('editor.isFocused', () => editor.getInstanceState().isFocused, [
|
||||
editor,
|
||||
])
|
||||
|
||||
useEffect(() => {
|
||||
if (!appIsFocused) return
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue