@tldraw/editor 3.13.0-canary.ae83a75c91b6 → 3.13.0-canary.b133066477f2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-cjs/index.d.ts +18 -13
- package/dist-cjs/index.js +1 -1
- package/dist-cjs/lib/TldrawEditor.js +2 -1
- package/dist-cjs/lib/TldrawEditor.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultCanvas.js +6 -0
- package/dist-cjs/lib/components/default-components/DefaultCanvas.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultErrorFallback.js +14 -12
- package/dist-cjs/lib/components/default-components/DefaultErrorFallback.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultSpinner.js +1 -1
- package/dist-cjs/lib/components/default-components/DefaultSpinner.js.map +2 -2
- package/dist-cjs/lib/hooks/useDocumentEvents.js +3 -2
- package/dist-cjs/lib/hooks/useDocumentEvents.js.map +2 -2
- package/dist-cjs/lib/hooks/useEditorComponents.js +16 -15
- package/dist-cjs/lib/hooks/useEditorComponents.js.map +2 -2
- package/dist-cjs/lib/license/LicenseManager.js +8 -1
- package/dist-cjs/lib/license/LicenseManager.js.map +2 -2
- package/dist-cjs/lib/options.js.map +2 -2
- package/dist-cjs/lib/utils/dom.js +3 -3
- package/dist-cjs/lib/utils/dom.js.map +2 -2
- package/dist-cjs/lib/utils/rotation.js +5 -5
- package/dist-cjs/lib/utils/rotation.js.map +2 -2
- package/dist-cjs/version.js +3 -3
- package/dist-cjs/version.js.map +1 -1
- package/dist-esm/index.d.mts +18 -13
- package/dist-esm/index.mjs +1 -1
- package/dist-esm/lib/TldrawEditor.mjs +2 -1
- package/dist-esm/lib/TldrawEditor.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultCanvas.mjs +6 -0
- package/dist-esm/lib/components/default-components/DefaultCanvas.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultErrorFallback.mjs +14 -12
- package/dist-esm/lib/components/default-components/DefaultErrorFallback.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultSpinner.mjs +1 -1
- package/dist-esm/lib/components/default-components/DefaultSpinner.mjs.map +2 -2
- package/dist-esm/lib/hooks/useDocumentEvents.mjs +3 -2
- package/dist-esm/lib/hooks/useDocumentEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/useEditorComponents.mjs +16 -15
- package/dist-esm/lib/hooks/useEditorComponents.mjs.map +2 -2
- package/dist-esm/lib/license/LicenseManager.mjs +8 -1
- package/dist-esm/lib/license/LicenseManager.mjs.map +2 -2
- package/dist-esm/lib/options.mjs.map +2 -2
- package/dist-esm/lib/utils/dom.mjs +3 -3
- package/dist-esm/lib/utils/dom.mjs.map +2 -2
- package/dist-esm/lib/utils/rotation.mjs +5 -5
- package/dist-esm/lib/utils/rotation.mjs.map +2 -2
- package/dist-esm/version.mjs +3 -3
- package/dist-esm/version.mjs.map +1 -1
- package/editor.css +11 -0
- package/package.json +7 -7
- package/src/lib/TldrawEditor.tsx +6 -1
- package/src/lib/components/default-components/DefaultCanvas.tsx +11 -0
- package/src/lib/components/default-components/DefaultErrorFallback.tsx +25 -14
- package/src/lib/components/default-components/DefaultSpinner.tsx +1 -1
- package/src/lib/hooks/useDocumentEvents.ts +7 -2
- package/src/lib/hooks/useEditorComponents.tsx +32 -28
- package/src/lib/license/LicenseManager.test.ts +40 -0
- package/src/lib/license/LicenseManager.ts +13 -1
- package/src/lib/options.ts +4 -0
- package/src/lib/utils/dom.ts +4 -4
- package/src/lib/utils/rotation.ts +8 -6
- package/src/version.ts +3 -3
|
@@ -157,8 +157,10 @@ My browser: ${navigator.userAgent}`
|
|
|
157
157
|
<h2>Are you sure?</h2>
|
|
158
158
|
<p>Resetting your data will delete your drawing and cannot be undone.</p>
|
|
159
159
|
<div className="tl-error-boundary__content__actions">
|
|
160
|
-
<button onClick={() => setShouldShowResetConfirmation(false)}>
|
|
161
|
-
|
|
160
|
+
<button className="tlui-button" onClick={() => setShouldShowResetConfirmation(false)}>
|
|
161
|
+
Cancel
|
|
162
|
+
</button>
|
|
163
|
+
<button className="tlui-button tl-error-boundary__reset" onClick={resetLocalState}>
|
|
162
164
|
Reset data
|
|
163
165
|
</button>
|
|
164
166
|
</div>
|
|
@@ -166,16 +168,23 @@ My browser: ${navigator.userAgent}`
|
|
|
166
168
|
) : (
|
|
167
169
|
<>
|
|
168
170
|
<h2>Something went wrong</h2>
|
|
169
|
-
<p>Please refresh
|
|
171
|
+
<p>Please refresh your browser.</p>
|
|
172
|
+
<p>
|
|
173
|
+
If the issue continues after refreshing, you may need to reset the tldraw data stored
|
|
174
|
+
on your device.
|
|
175
|
+
</p>
|
|
170
176
|
<p>
|
|
171
|
-
|
|
172
|
-
<a href={url.toString()}>GitHub issue</a> or ask for help on{' '}
|
|
173
|
-
<a href="https://discord.tldraw.com/?utm_source=sdk&utm_medium=organic&utm_campaign=error-screen">
|
|
174
|
-
Discord
|
|
175
|
-
</a>
|
|
176
|
-
. If you are still stuck, you can reset the tldraw data on your machine. This may
|
|
177
|
-
erase the project you were working on, so try to get help first.
|
|
177
|
+
<strong>Note:</strong> Resetting will erase your current project and any unsaved work.
|
|
178
178
|
</p>
|
|
179
|
+
{process.env.NODE_ENV !== 'production' && (
|
|
180
|
+
<p>
|
|
181
|
+
If you're developing with the SDK and need help, join us on{' '}
|
|
182
|
+
<a href="https://discord.tldraw.com/?utm_source=sdk&utm_medium=organic&utm_campaign=error-screen">
|
|
183
|
+
Discord
|
|
184
|
+
</a>
|
|
185
|
+
.
|
|
186
|
+
</p>
|
|
187
|
+
)}
|
|
179
188
|
{shouldShowError && (
|
|
180
189
|
<>
|
|
181
190
|
Message:
|
|
@@ -187,22 +196,24 @@ My browser: ${navigator.userAgent}`
|
|
|
187
196
|
<pre>
|
|
188
197
|
<code>{errorStack ?? errorMessage}</code>
|
|
189
198
|
</pre>
|
|
190
|
-
<button onClick={copyError}>
|
|
199
|
+
<button className="tlui-button" onClick={copyError}>
|
|
200
|
+
{didCopy ? 'Copied!' : 'Copy'}
|
|
201
|
+
</button>
|
|
191
202
|
</div>
|
|
192
203
|
</>
|
|
193
204
|
)}
|
|
194
205
|
<div className="tl-error-boundary__content__actions">
|
|
195
|
-
<button onClick={() => setShouldShowError(!shouldShowError)}>
|
|
206
|
+
<button className="tlui-button" onClick={() => setShouldShowError(!shouldShowError)}>
|
|
196
207
|
{shouldShowError ? 'Hide details' : 'Show details'}
|
|
197
208
|
</button>
|
|
198
209
|
<div className="tl-error-boundary__content__actions__group">
|
|
199
210
|
<button
|
|
200
|
-
className="tl-error-boundary__reset"
|
|
211
|
+
className="tlui-button tl-error-boundary__reset"
|
|
201
212
|
onClick={() => setShouldShowResetConfirmation(true)}
|
|
202
213
|
>
|
|
203
214
|
Reset data
|
|
204
215
|
</button>
|
|
205
|
-
<button className="tl-error-boundary__refresh" onClick={refresh}>
|
|
216
|
+
<button className="tlui-button tl-error-boundary__refresh" onClick={refresh}>
|
|
206
217
|
Refresh Page
|
|
207
218
|
</button>
|
|
208
219
|
</div>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** @public @react */
|
|
2
2
|
export function DefaultSpinner() {
|
|
3
3
|
return (
|
|
4
|
-
<svg width={16} height={16} viewBox="0 0 16 16">
|
|
4
|
+
<svg width={16} height={16} viewBox="0 0 16 16" aria-hidden="false">
|
|
5
5
|
<g strokeWidth={2} fill="none" fillRule="evenodd">
|
|
6
6
|
<circle strokeOpacity={0.25} cx={8} cy={8} r={7} stroke="currentColor" />
|
|
7
7
|
<path strokeLinecap="round" d="M15 8c0-4.5-4.5-7-7-7" stroke="currentColor">
|
|
@@ -11,6 +11,7 @@ export function useDocumentEvents() {
|
|
|
11
11
|
const editor = useEditor()
|
|
12
12
|
const container = useContainer()
|
|
13
13
|
|
|
14
|
+
const isEditing = useValue('isEditing', () => editor.getEditingShapeId(), [editor])
|
|
14
15
|
const isAppFocused = useValue('isFocused', () => editor.getIsFocused(), [editor])
|
|
15
16
|
|
|
16
17
|
// Prevent the browser's default drag and drop behavior on our container (UI, etc)
|
|
@@ -125,7 +126,11 @@ export function useDocumentEvents() {
|
|
|
125
126
|
if (areShortcutsDisabled(editor)) {
|
|
126
127
|
return
|
|
127
128
|
}
|
|
128
|
-
|
|
129
|
+
// isEditing here sounds like it's about text editing
|
|
130
|
+
// but more specifically, this is so you can tab into an
|
|
131
|
+
// embed that's being 'edited'. In our world,
|
|
132
|
+
// editing an embed, means it's interactive.
|
|
133
|
+
if (hasSelectedShapes && !isEditing) {
|
|
129
134
|
// This is used in tandem with shape navigation.
|
|
130
135
|
preventDefault(e)
|
|
131
136
|
}
|
|
@@ -289,7 +294,7 @@ export function useDocumentEvents() {
|
|
|
289
294
|
container.removeEventListener('keydown', handleKeyDown)
|
|
290
295
|
container.removeEventListener('keyup', handleKeyUp)
|
|
291
296
|
}
|
|
292
|
-
}, [editor, container, isAppFocused])
|
|
297
|
+
}, [editor, container, isAppFocused, isEditing])
|
|
293
298
|
}
|
|
294
299
|
|
|
295
300
|
function areShortcutsDisabled(editor: Editor) {
|
|
@@ -51,29 +51,30 @@ import { useShallowObjectIdentity } from './useIdentity'
|
|
|
51
51
|
/** @public */
|
|
52
52
|
export interface TLEditorComponents {
|
|
53
53
|
Background?: ComponentType | null
|
|
54
|
-
SvgDefs?: ComponentType | null
|
|
55
54
|
Brush?: ComponentType<TLBrushProps> | null
|
|
56
|
-
ZoomBrush?: ComponentType<TLBrushProps> | null
|
|
57
|
-
ShapeIndicators?: ComponentType | null
|
|
58
|
-
ShapeIndicator?: ComponentType<TLShapeIndicatorProps> | null
|
|
59
|
-
Cursor?: ComponentType<TLCursorProps> | null
|
|
60
55
|
Canvas?: ComponentType<TLCanvasComponentProps> | null
|
|
61
56
|
CollaboratorBrush?: ComponentType<TLBrushProps> | null
|
|
62
57
|
CollaboratorCursor?: ComponentType<TLCursorProps> | null
|
|
63
58
|
CollaboratorHint?: ComponentType<TLCollaboratorHintProps> | null
|
|
59
|
+
CollaboratorScribble?: ComponentType<TLScribbleProps> | null
|
|
64
60
|
CollaboratorShapeIndicator?: ComponentType<TLShapeIndicatorProps> | null
|
|
61
|
+
Cursor?: ComponentType<TLCursorProps> | null
|
|
65
62
|
Grid?: ComponentType<TLGridProps> | null
|
|
66
|
-
Scribble?: ComponentType<TLScribbleProps> | null
|
|
67
|
-
CollaboratorScribble?: ComponentType<TLScribbleProps> | null
|
|
68
|
-
SnapIndicator?: ComponentType<TLSnapIndicatorProps> | null
|
|
69
|
-
Handles?: ComponentType<TLHandlesProps> | null
|
|
70
63
|
Handle?: ComponentType<TLHandleProps> | null
|
|
71
|
-
|
|
72
|
-
SelectionForeground?: ComponentType<TLSelectionForegroundProps> | null
|
|
73
|
-
SelectionBackground?: ComponentType<TLSelectionBackgroundProps> | null
|
|
74
|
-
OnTheCanvas?: ComponentType | null
|
|
64
|
+
Handles?: ComponentType<TLHandlesProps> | null
|
|
75
65
|
InFrontOfTheCanvas?: ComponentType | null
|
|
76
66
|
LoadingScreen?: ComponentType | null
|
|
67
|
+
OnTheCanvas?: ComponentType | null
|
|
68
|
+
Overlays?: ComponentType | null
|
|
69
|
+
Scribble?: ComponentType<TLScribbleProps> | null
|
|
70
|
+
SelectionBackground?: ComponentType<TLSelectionBackgroundProps> | null
|
|
71
|
+
SelectionForeground?: ComponentType<TLSelectionForegroundProps> | null
|
|
72
|
+
ShapeIndicator?: ComponentType<TLShapeIndicatorProps> | null
|
|
73
|
+
ShapeIndicators?: ComponentType | null
|
|
74
|
+
SnapIndicator?: ComponentType<TLSnapIndicatorProps> | null
|
|
75
|
+
Spinner?: ComponentType | null
|
|
76
|
+
SvgDefs?: ComponentType | null
|
|
77
|
+
ZoomBrush?: ComponentType<TLBrushProps> | null
|
|
77
78
|
|
|
78
79
|
// These will always have defaults
|
|
79
80
|
ErrorFallback?: TLErrorFallbackComponent
|
|
@@ -96,32 +97,35 @@ export function EditorComponentsProvider({
|
|
|
96
97
|
const value = useMemo(
|
|
97
98
|
(): Required<TLEditorComponents> => ({
|
|
98
99
|
Background: DefaultBackground,
|
|
99
|
-
SvgDefs: DefaultSvgDefs,
|
|
100
100
|
Brush: DefaultBrush,
|
|
101
|
-
|
|
101
|
+
Canvas: DefaultCanvas,
|
|
102
102
|
CollaboratorBrush: DefaultBrush,
|
|
103
|
-
Cursor: DefaultCursor,
|
|
104
103
|
CollaboratorCursor: DefaultCursor,
|
|
105
104
|
CollaboratorHint: DefaultCollaboratorHint,
|
|
105
|
+
CollaboratorScribble: DefaultScribble,
|
|
106
106
|
CollaboratorShapeIndicator: DefaultShapeIndicator,
|
|
107
|
+
Cursor: DefaultCursor,
|
|
107
108
|
Grid: DefaultGrid,
|
|
109
|
+
Handle: DefaultHandle,
|
|
110
|
+
Handles: DefaultHandles,
|
|
111
|
+
InFrontOfTheCanvas: null,
|
|
112
|
+
LoadingScreen: DefaultLoadingScreen,
|
|
113
|
+
OnTheCanvas: null,
|
|
114
|
+
Overlays: null,
|
|
108
115
|
Scribble: DefaultScribble,
|
|
116
|
+
SelectionBackground: DefaultSelectionBackground,
|
|
117
|
+
SelectionForeground: DefaultSelectionForeground,
|
|
118
|
+
ShapeIndicator: DefaultShapeIndicator,
|
|
119
|
+
ShapeIndicators: DefaultShapeIndicators,
|
|
109
120
|
SnapIndicator: DefaultSnapIndicator,
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
121
|
+
Spinner: DefaultSpinner,
|
|
122
|
+
SvgDefs: DefaultSvgDefs,
|
|
123
|
+
ZoomBrush: DefaultBrush,
|
|
124
|
+
|
|
113
125
|
ErrorFallback: DefaultErrorFallback,
|
|
114
126
|
ShapeErrorFallback: DefaultShapeErrorFallback,
|
|
115
127
|
ShapeIndicatorErrorFallback: DefaultShapeIndicatorErrorFallback,
|
|
116
|
-
|
|
117
|
-
SelectionBackground: DefaultSelectionBackground,
|
|
118
|
-
SelectionForeground: DefaultSelectionForeground,
|
|
119
|
-
ShapeIndicators: DefaultShapeIndicators,
|
|
120
|
-
ShapeIndicator: DefaultShapeIndicator,
|
|
121
|
-
OnTheCanvas: null,
|
|
122
|
-
InFrontOfTheCanvas: null,
|
|
123
|
-
Canvas: DefaultCanvas,
|
|
124
|
-
LoadingScreen: DefaultLoadingScreen,
|
|
128
|
+
|
|
125
129
|
..._overrides,
|
|
126
130
|
}),
|
|
127
131
|
[_overrides]
|
|
@@ -317,6 +317,46 @@ describe('LicenseManager', () => {
|
|
|
317
317
|
expect(result.isDomainValid).toBe(false)
|
|
318
318
|
})
|
|
319
319
|
|
|
320
|
+
it('Succeeds if it is a vscode extension', async () => {
|
|
321
|
+
// @ts-ignore
|
|
322
|
+
delete window.location
|
|
323
|
+
// @ts-ignore
|
|
324
|
+
window.location = new URL(
|
|
325
|
+
'vscode-webview:vscode-webview://1ipd8pun8ud7nd7hv9d112g7evi7m10vak9vviuvia66ou6aibp3/index.html?id=6ec2dc7a-afe9-45d9-bd71-1749f9568d28&origin=955b256f-37e1-4a72-a2f4-ad633e88239c&swVersion=4&extensionId=tldraw-org.tldraw-vscode&platform=electron&vscode-resource-base-authority=vscode-resource.vscode-cdn.net&parentOrigin=vscode-file%3A%2F%2Fvscode-app'
|
|
326
|
+
)
|
|
327
|
+
|
|
328
|
+
const permissiveHostsInfo = JSON.parse(STANDARD_LICENSE_INFO)
|
|
329
|
+
permissiveHostsInfo[PROPERTIES.HOSTS] = ['tldraw-org.tldraw-vscode']
|
|
330
|
+
const permissiveLicenseKey = await generateLicenseKey(
|
|
331
|
+
JSON.stringify(permissiveHostsInfo),
|
|
332
|
+
keyPair
|
|
333
|
+
)
|
|
334
|
+
const result = (await licenseManager.getLicenseFromKey(
|
|
335
|
+
permissiveLicenseKey
|
|
336
|
+
)) as ValidLicenseKeyResult
|
|
337
|
+
expect(result.isDomainValid).toBe(true)
|
|
338
|
+
})
|
|
339
|
+
|
|
340
|
+
it('Fails if it is a vscode extension with the wrong id', async () => {
|
|
341
|
+
// @ts-ignore
|
|
342
|
+
delete window.location
|
|
343
|
+
// @ts-ignore
|
|
344
|
+
window.location = new URL(
|
|
345
|
+
'vscode-webview:vscode-webview://1ipd8pun8ud7nd7hv9d112g7evi7m10vak9vviuvia66ou6aibp3/index.html?id=6ec2dc7a-afe9-45d9-bd71-1749f9568d28&origin=955b256f-37e1-4a72-a2f4-ad633e88239c&swVersion=4&extensionId=tldraw-org.tldraw-vscode&platform=electron&vscode-resource-base-authority=vscode-resource.vscode-cdn.net&parentOrigin=vscode-file%3A%2F%2Fvscode-app'
|
|
346
|
+
)
|
|
347
|
+
|
|
348
|
+
const permissiveHostsInfo = JSON.parse(STANDARD_LICENSE_INFO)
|
|
349
|
+
permissiveHostsInfo[PROPERTIES.HOSTS] = ['blah-org.blah-vscode']
|
|
350
|
+
const permissiveLicenseKey = await generateLicenseKey(
|
|
351
|
+
JSON.stringify(permissiveHostsInfo),
|
|
352
|
+
keyPair
|
|
353
|
+
)
|
|
354
|
+
const result = (await licenseManager.getLicenseFromKey(
|
|
355
|
+
permissiveLicenseKey
|
|
356
|
+
)) as ValidLicenseKeyResult
|
|
357
|
+
expect(result.isDomainValid).toBe(false)
|
|
358
|
+
})
|
|
359
|
+
|
|
320
360
|
it('Checks for internal license', async () => {
|
|
321
361
|
const internalLicenseInfo = JSON.parse(STANDARD_LICENSE_INFO)
|
|
322
362
|
internalLicenseInfo[PROPERTIES.FLAGS] = FLAGS.INTERNAL_LICENSE
|
|
@@ -111,7 +111,10 @@ export class LicenseManager {
|
|
|
111
111
|
if (testEnvironment === 'production') return false
|
|
112
112
|
|
|
113
113
|
// If we are using https on a non-localhost domain we assume it's a production env and a development one otherwise
|
|
114
|
-
return
|
|
114
|
+
return (
|
|
115
|
+
!['https:', 'vscode-webview:'].includes(window.location.protocol) ||
|
|
116
|
+
window.location.hostname === 'localhost'
|
|
117
|
+
)
|
|
115
118
|
}
|
|
116
119
|
|
|
117
120
|
private async extractLicenseKey(licenseKey: string): Promise<LicenseInfo> {
|
|
@@ -250,6 +253,15 @@ export class LicenseManager {
|
|
|
250
253
|
return globToRegex.test(currentHostname) || globToRegex.test(`www.${currentHostname}`)
|
|
251
254
|
}
|
|
252
255
|
|
|
256
|
+
// VSCode support
|
|
257
|
+
if (window.location.protocol === 'vscode-webview:') {
|
|
258
|
+
const currentUrl = new URL(window.location.href)
|
|
259
|
+
const extensionId = currentUrl.searchParams.get('extensionId')
|
|
260
|
+
if (normalizedHost === extensionId) {
|
|
261
|
+
return true
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
253
265
|
return false
|
|
254
266
|
})
|
|
255
267
|
}
|
package/src/lib/options.ts
CHANGED
|
@@ -80,6 +80,10 @@ export interface TldrawOptions {
|
|
|
80
80
|
* nonce to use in the editor's styles.
|
|
81
81
|
*/
|
|
82
82
|
readonly nonce: string | undefined
|
|
83
|
+
/**
|
|
84
|
+
* Branding name of the app, currently only used for adding aria-label for the application.
|
|
85
|
+
*/
|
|
86
|
+
readonly branding?: string
|
|
83
87
|
}
|
|
84
88
|
|
|
85
89
|
/** @public */
|
package/src/lib/utils/dom.ts
CHANGED
|
@@ -91,14 +91,14 @@ export const setStyleProperty = (
|
|
|
91
91
|
elm.style.setProperty(property, value as string)
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
-
const INPUTS = ['input', 'select', 'button', 'textarea']
|
|
95
|
-
|
|
96
94
|
/** @internal */
|
|
97
|
-
export function activeElementShouldCaptureKeys() {
|
|
95
|
+
export function activeElementShouldCaptureKeys(allowButtons = false) {
|
|
98
96
|
const { activeElement } = document
|
|
97
|
+
const elements = allowButtons ? ['input', 'textarea'] : ['input', 'select', 'button', 'textarea']
|
|
99
98
|
return !!(
|
|
100
99
|
activeElement &&
|
|
101
100
|
((activeElement as HTMLElement).isContentEditable ||
|
|
102
|
-
|
|
101
|
+
elements.indexOf(activeElement.tagName.toLowerCase()) > -1 ||
|
|
102
|
+
activeElement.classList.contains('tlui-slider__thumb'))
|
|
103
103
|
)
|
|
104
104
|
}
|
|
@@ -26,11 +26,13 @@ export function getRotationSnapshot({
|
|
|
26
26
|
return null
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
const
|
|
29
|
+
const initialPageCenter = rotatedPageBounds.center
|
|
30
|
+
.clone()
|
|
31
|
+
.rotWith(rotatedPageBounds.point, rotation)
|
|
30
32
|
|
|
31
33
|
return {
|
|
32
|
-
|
|
33
|
-
initialCursorAngle:
|
|
34
|
+
initialPageCenter,
|
|
35
|
+
initialCursorAngle: initialPageCenter.angle(editor.inputs.originPagePoint),
|
|
34
36
|
initialShapesRotation: rotation,
|
|
35
37
|
shapeSnapshots: shapes.map((shape) => ({
|
|
36
38
|
shape,
|
|
@@ -43,7 +45,7 @@ export function getRotationSnapshot({
|
|
|
43
45
|
* @internal
|
|
44
46
|
**/
|
|
45
47
|
export interface TLRotationSnapshot {
|
|
46
|
-
|
|
48
|
+
initialPageCenter: Vec
|
|
47
49
|
initialCursorAngle: number
|
|
48
50
|
initialShapesRotation: number
|
|
49
51
|
shapeSnapshots: {
|
|
@@ -66,7 +68,7 @@ export function applyRotationToSnapshotShapes({
|
|
|
66
68
|
stage: 'start' | 'update' | 'end' | 'one-off'
|
|
67
69
|
centerOverride?: VecLike
|
|
68
70
|
}) {
|
|
69
|
-
const {
|
|
71
|
+
const { initialPageCenter, shapeSnapshots } = snapshot
|
|
70
72
|
|
|
71
73
|
editor.updateShapes(
|
|
72
74
|
shapeSnapshots.map(({ shape, initialPagePoint }) => {
|
|
@@ -77,7 +79,7 @@ export function applyRotationToSnapshotShapes({
|
|
|
77
79
|
? editor.getShapePageTransform(shape.parentId)!
|
|
78
80
|
: Mat.Identity()
|
|
79
81
|
|
|
80
|
-
const newPagePoint = Vec.RotWith(initialPagePoint, centerOverride ??
|
|
82
|
+
const newPagePoint = Vec.RotWith(initialPagePoint, centerOverride ?? initialPageCenter, delta)
|
|
81
83
|
|
|
82
84
|
const newLocalPoint = Mat.applyToPoint(
|
|
83
85
|
// use the current parent transform in case it has moved/resized since the start
|
package/src/version.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// This file is automatically generated by internal/scripts/refresh-assets.ts.
|
|
2
2
|
// Do not edit manually. Or do, I'm a comment, not a cop.
|
|
3
3
|
|
|
4
|
-
export const version = '3.13.0-canary.
|
|
4
|
+
export const version = '3.13.0-canary.b133066477f2'
|
|
5
5
|
export const publishDates = {
|
|
6
6
|
major: '2024-09-13T14:36:29.063Z',
|
|
7
|
-
minor: '2025-04-
|
|
8
|
-
patch: '2025-04-
|
|
7
|
+
minor: '2025-04-29T17:22:49.319Z',
|
|
8
|
+
patch: '2025-04-29T17:22:49.319Z',
|
|
9
9
|
}
|