tldraw 4.1.0-canary.0818d090f5e3 → 4.1.0-canary.21c9ed69dd72
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 +19 -0
- package/dist-cjs/index.js +1 -1
- package/dist-cjs/lib/defaultEmbedDefinitions.js +24 -6
- package/dist-cjs/lib/defaultEmbedDefinitions.js.map +2 -2
- package/dist-cjs/lib/defaultExternalContentHandlers.js +1 -1
- package/dist-cjs/lib/defaultExternalContentHandlers.js.map +2 -2
- package/dist-cjs/lib/tools/SelectTool/childStates/Crop/children/Idle.js +1 -1
- package/dist-cjs/lib/tools/SelectTool/childStates/Crop/children/Idle.js.map +2 -2
- package/dist-cjs/lib/tools/SelectTool/childStates/Idle.js +1 -1
- package/dist-cjs/lib/tools/SelectTool/childStates/Idle.js.map +2 -2
- package/dist-cjs/lib/ui/version.js +3 -3
- package/dist-cjs/lib/ui/version.js.map +1 -1
- package/dist-esm/index.d.mts +19 -0
- package/dist-esm/index.mjs +1 -1
- package/dist-esm/lib/defaultEmbedDefinitions.mjs +24 -6
- package/dist-esm/lib/defaultEmbedDefinitions.mjs.map +2 -2
- package/dist-esm/lib/defaultExternalContentHandlers.mjs +1 -1
- package/dist-esm/lib/defaultExternalContentHandlers.mjs.map +2 -2
- package/dist-esm/lib/tools/SelectTool/childStates/Crop/children/Idle.mjs +1 -1
- package/dist-esm/lib/tools/SelectTool/childStates/Crop/children/Idle.mjs.map +2 -2
- package/dist-esm/lib/tools/SelectTool/childStates/Idle.mjs +1 -1
- package/dist-esm/lib/tools/SelectTool/childStates/Idle.mjs.map +2 -2
- package/dist-esm/lib/ui/version.mjs +3 -3
- package/dist-esm/lib/ui/version.mjs.map +1 -1
- package/package.json +3 -3
- package/src/lib/defaultEmbedDefinitions.ts +19 -0
- package/src/lib/defaultExternalContentHandlers.ts +1 -1
- package/src/lib/shapes/text/TextShapeTool.test.ts +74 -0
- package/src/lib/tools/SelectTool/childStates/Crop/children/Idle.ts +1 -1
- package/src/lib/tools/SelectTool/childStates/Idle.ts +1 -1
- package/src/lib/ui/version.ts +3 -3
|
@@ -35,6 +35,7 @@ export const DEFAULT_EMBED_DEFINITIONS = [
|
|
|
35
35
|
}
|
|
36
36
|
return
|
|
37
37
|
},
|
|
38
|
+
embedOnPaste: false,
|
|
38
39
|
},
|
|
39
40
|
{
|
|
40
41
|
type: 'figma',
|
|
@@ -65,6 +66,7 @@ export const DEFAULT_EMBED_DEFINITIONS = [
|
|
|
65
66
|
}
|
|
66
67
|
return
|
|
67
68
|
},
|
|
69
|
+
embedOnPaste: true,
|
|
68
70
|
},
|
|
69
71
|
{
|
|
70
72
|
type: 'google_maps',
|
|
@@ -116,6 +118,7 @@ export const DEFAULT_EMBED_DEFINITIONS = [
|
|
|
116
118
|
}
|
|
117
119
|
return
|
|
118
120
|
},
|
|
121
|
+
embedOnPaste: true,
|
|
119
122
|
},
|
|
120
123
|
{
|
|
121
124
|
type: 'val_town',
|
|
@@ -144,6 +147,7 @@ export const DEFAULT_EMBED_DEFINITIONS = [
|
|
|
144
147
|
}
|
|
145
148
|
return
|
|
146
149
|
},
|
|
150
|
+
embedOnPaste: true,
|
|
147
151
|
},
|
|
148
152
|
{
|
|
149
153
|
type: 'codesandbox',
|
|
@@ -170,6 +174,7 @@ export const DEFAULT_EMBED_DEFINITIONS = [
|
|
|
170
174
|
}
|
|
171
175
|
return
|
|
172
176
|
},
|
|
177
|
+
embedOnPaste: true,
|
|
173
178
|
},
|
|
174
179
|
{
|
|
175
180
|
type: 'codepen',
|
|
@@ -198,6 +203,7 @@ export const DEFAULT_EMBED_DEFINITIONS = [
|
|
|
198
203
|
}
|
|
199
204
|
return
|
|
200
205
|
},
|
|
206
|
+
embedOnPaste: true,
|
|
201
207
|
},
|
|
202
208
|
{
|
|
203
209
|
type: 'scratch',
|
|
@@ -206,6 +212,7 @@ export const DEFAULT_EMBED_DEFINITIONS = [
|
|
|
206
212
|
width: 520,
|
|
207
213
|
height: 400,
|
|
208
214
|
doesResize: false,
|
|
215
|
+
embedOnPaste: true,
|
|
209
216
|
toEmbedUrl: (url) => {
|
|
210
217
|
const SCRATCH_URL_REGEXP = /https?:\/\/scratch.mit.edu\/projects\/([^/]+)/
|
|
211
218
|
const matches = url.match(SCRATCH_URL_REGEXP)
|
|
@@ -237,6 +244,7 @@ export const DEFAULT_EMBED_DEFINITIONS = [
|
|
|
237
244
|
'allow-popups-to-escape-sandbox': true,
|
|
238
245
|
},
|
|
239
246
|
isAspectRatioLocked: true,
|
|
247
|
+
embedOnPaste: true,
|
|
240
248
|
toEmbedUrl: (url) => {
|
|
241
249
|
const urlObj = safeParseUrl(url)
|
|
242
250
|
if (!urlObj) return
|
|
@@ -303,6 +311,7 @@ export const DEFAULT_EMBED_DEFINITIONS = [
|
|
|
303
311
|
overridePermissions: {
|
|
304
312
|
'allow-popups-to-escape-sandbox': true,
|
|
305
313
|
},
|
|
314
|
+
embedOnPaste: true,
|
|
306
315
|
toEmbedUrl: (url) => {
|
|
307
316
|
const urlObj = safeParseUrl(url)
|
|
308
317
|
const cidQs = urlObj?.searchParams.get('cid')
|
|
@@ -347,6 +356,7 @@ export const DEFAULT_EMBED_DEFINITIONS = [
|
|
|
347
356
|
overridePermissions: {
|
|
348
357
|
'allow-popups-to-escape-sandbox': true,
|
|
349
358
|
},
|
|
359
|
+
embedOnPaste: true,
|
|
350
360
|
toEmbedUrl: (url) => {
|
|
351
361
|
const urlObj = safeParseUrl(url)
|
|
352
362
|
|
|
@@ -381,6 +391,7 @@ export const DEFAULT_EMBED_DEFINITIONS = [
|
|
|
381
391
|
width: 720,
|
|
382
392
|
height: 500,
|
|
383
393
|
doesResize: true,
|
|
394
|
+
embedOnPaste: true,
|
|
384
395
|
// Security warning:
|
|
385
396
|
// Gists allow adding .json extensions to the URL which return JSONP.
|
|
386
397
|
// Furthermore, the JSONP can include callbacks that execute arbitrary JavaScript.
|
|
@@ -413,6 +424,7 @@ export const DEFAULT_EMBED_DEFINITIONS = [
|
|
|
413
424
|
width: 720,
|
|
414
425
|
height: 500,
|
|
415
426
|
doesResize: true,
|
|
427
|
+
embedOnPaste: true,
|
|
416
428
|
toEmbedUrl: (url) => {
|
|
417
429
|
const urlObj = safeParseUrl(url)
|
|
418
430
|
if (urlObj && urlObj.pathname.match(/\/@([^/]+)\/([^/]+)/)) {
|
|
@@ -440,6 +452,7 @@ export const DEFAULT_EMBED_DEFINITIONS = [
|
|
|
440
452
|
width: 720,
|
|
441
453
|
height: 500,
|
|
442
454
|
doesResize: true,
|
|
455
|
+
embedOnPaste: true,
|
|
443
456
|
toEmbedUrl: (url) => {
|
|
444
457
|
const urlObj = safeParseUrl(url)
|
|
445
458
|
if (urlObj && urlObj.pathname.match(/^\/map\//)) {
|
|
@@ -465,6 +478,7 @@ export const DEFAULT_EMBED_DEFINITIONS = [
|
|
|
465
478
|
minHeight: 500,
|
|
466
479
|
overrideOutlineRadius: 12,
|
|
467
480
|
doesResize: true,
|
|
481
|
+
embedOnPaste: true,
|
|
468
482
|
toEmbedUrl: (url) => {
|
|
469
483
|
const urlObj = safeParseUrl(url)
|
|
470
484
|
if (urlObj && urlObj.pathname.match(/^\/(artist|album)\//)) {
|
|
@@ -488,6 +502,7 @@ export const DEFAULT_EMBED_DEFINITIONS = [
|
|
|
488
502
|
height: 360,
|
|
489
503
|
doesResize: true,
|
|
490
504
|
isAspectRatioLocked: true,
|
|
505
|
+
embedOnPaste: true,
|
|
491
506
|
toEmbedUrl: (url) => {
|
|
492
507
|
const urlObj = safeParseUrl(url)
|
|
493
508
|
if (urlObj && urlObj.hostname === 'vimeo.com') {
|
|
@@ -518,6 +533,7 @@ export const DEFAULT_EMBED_DEFINITIONS = [
|
|
|
518
533
|
height: 500,
|
|
519
534
|
doesResize: true,
|
|
520
535
|
isAspectRatioLocked: true,
|
|
536
|
+
embedOnPaste: true,
|
|
521
537
|
toEmbedUrl: (url) => {
|
|
522
538
|
const urlObj = safeParseUrl(url)
|
|
523
539
|
if (urlObj && urlObj.hash.match(/#room=/)) {
|
|
@@ -542,6 +558,7 @@ export const DEFAULT_EMBED_DEFINITIONS = [
|
|
|
542
558
|
doesResize: true,
|
|
543
559
|
isAspectRatioLocked: false,
|
|
544
560
|
backgroundColor: '#fff',
|
|
561
|
+
embedOnPaste: true,
|
|
545
562
|
toEmbedUrl: (url) => {
|
|
546
563
|
const urlObj = safeParseUrl(url)
|
|
547
564
|
if (urlObj && urlObj.pathname.match(/^\/@([^/]+)\/([^/]+)\/?$/)) {
|
|
@@ -573,6 +590,7 @@ export const DEFAULT_EMBED_DEFINITIONS = [
|
|
|
573
590
|
width: 700,
|
|
574
591
|
height: 450,
|
|
575
592
|
doesResize: true,
|
|
593
|
+
embedOnPaste: true,
|
|
576
594
|
toEmbedUrl: (url) => {
|
|
577
595
|
const urlObj = safeParseUrl(url)
|
|
578
596
|
if (
|
|
@@ -673,6 +691,7 @@ export interface EmbedDefinition {
|
|
|
673
691
|
readonly overridePermissions?: TLEmbedShapePermissions
|
|
674
692
|
readonly instructionLink?: string
|
|
675
693
|
readonly backgroundColor?: string
|
|
694
|
+
readonly embedOnPaste?: boolean
|
|
676
695
|
// TODO: FIXME this is ugly be required because some embeds have their own border radius for example spotify embeds
|
|
677
696
|
readonly overrideOutlineRadius?: number
|
|
678
697
|
// eslint-disable-next-line @typescript-eslint/method-signature-style
|
|
@@ -557,7 +557,7 @@ export async function defaultHandleExternalUrlContent(
|
|
|
557
557
|
const embedUtil = editor.getShapeUtil('embed') as EmbedShapeUtil | undefined
|
|
558
558
|
const embedInfo = embedUtil?.getEmbedDefinition(url)
|
|
559
559
|
|
|
560
|
-
if (embedInfo) {
|
|
560
|
+
if (embedInfo && embedInfo.definition.embedOnPaste) {
|
|
561
561
|
return editor.putExternalContent({
|
|
562
562
|
type: 'embed',
|
|
563
563
|
url: embedInfo.url,
|
|
@@ -86,6 +86,80 @@ describe('When in idle state', () => {
|
|
|
86
86
|
editor.cancel()
|
|
87
87
|
editor.expectToBeIn('select.idle')
|
|
88
88
|
})
|
|
89
|
+
|
|
90
|
+
it('starts editing selected text shape on Enter key', () => {
|
|
91
|
+
// Create a text shape using the same method as other tests
|
|
92
|
+
expect(editor.getCurrentPageShapes().length).toBe(0)
|
|
93
|
+
editor.setCurrentTool('text')
|
|
94
|
+
editor.pointerDown(0, 0)
|
|
95
|
+
editor.pointerUp()
|
|
96
|
+
editor.expectToBeIn('select.editing_shape')
|
|
97
|
+
|
|
98
|
+
// Update the text shape with some content
|
|
99
|
+
editor.updateShapes<TLTextShape>([
|
|
100
|
+
{
|
|
101
|
+
...editor.getCurrentPageShapes()[0]!,
|
|
102
|
+
type: 'text',
|
|
103
|
+
props: { richText: toRichText('Hello') },
|
|
104
|
+
},
|
|
105
|
+
])
|
|
106
|
+
|
|
107
|
+
// Exit editing mode
|
|
108
|
+
editor.cancel()
|
|
109
|
+
editor.expectToBeIn('select.idle')
|
|
110
|
+
|
|
111
|
+
// Verify the text shape exists and is selected
|
|
112
|
+
expect(editor.getCurrentPageShapes().length).toBe(1)
|
|
113
|
+
const textShape = editor.getCurrentPageShapes()[0]
|
|
114
|
+
expect(textShape.type).toBe('text')
|
|
115
|
+
editor.setSelectedShapes([textShape])
|
|
116
|
+
|
|
117
|
+
// Switch to text tool and press Enter
|
|
118
|
+
editor.setCurrentTool('text')
|
|
119
|
+
editor.expectToBeIn('text.idle')
|
|
120
|
+
editor.keyDown('Enter')
|
|
121
|
+
|
|
122
|
+
// Should transition to editing the selected text shape
|
|
123
|
+
editor.expectToBeIn('select.editing_shape')
|
|
124
|
+
expect(editor.getEditingShapeId()).toBe(textShape.id)
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
it('starts editing selected text shape on numpad Enter key', () => {
|
|
128
|
+
// Create a text shape using the same method as other tests
|
|
129
|
+
expect(editor.getCurrentPageShapes().length).toBe(0)
|
|
130
|
+
editor.setCurrentTool('text')
|
|
131
|
+
editor.pointerDown(0, 0)
|
|
132
|
+
editor.pointerUp()
|
|
133
|
+
editor.expectToBeIn('select.editing_shape')
|
|
134
|
+
|
|
135
|
+
// Update the text shape with some content
|
|
136
|
+
editor.updateShapes<TLTextShape>([
|
|
137
|
+
{
|
|
138
|
+
...editor.getCurrentPageShapes()[0]!,
|
|
139
|
+
type: 'text',
|
|
140
|
+
props: { richText: toRichText('Hello') },
|
|
141
|
+
},
|
|
142
|
+
])
|
|
143
|
+
|
|
144
|
+
// Exit editing mode
|
|
145
|
+
editor.cancel()
|
|
146
|
+
editor.expectToBeIn('select.idle')
|
|
147
|
+
|
|
148
|
+
// Verify the text shape exists and is selected
|
|
149
|
+
expect(editor.getCurrentPageShapes().length).toBe(1)
|
|
150
|
+
const textShape = editor.getCurrentPageShapes()[0]
|
|
151
|
+
expect(textShape.type).toBe('text')
|
|
152
|
+
editor.setSelectedShapes([textShape])
|
|
153
|
+
|
|
154
|
+
// Switch to text tool and press numpad Enter
|
|
155
|
+
editor.setCurrentTool('text')
|
|
156
|
+
editor.expectToBeIn('text.idle')
|
|
157
|
+
editor.keyDown('Enter', { code: 'NumpadEnter' })
|
|
158
|
+
|
|
159
|
+
// Should transition to editing the selected text shape
|
|
160
|
+
editor.expectToBeIn('select.editing_shape')
|
|
161
|
+
expect(editor.getEditingShapeId()).toBe(textShape.id)
|
|
162
|
+
})
|
|
89
163
|
})
|
|
90
164
|
|
|
91
165
|
describe('When in the pointing state', () => {
|
|
@@ -143,7 +143,7 @@ export class Idle extends StateNode {
|
|
|
143
143
|
}
|
|
144
144
|
|
|
145
145
|
override onKeyUp(info: TLKeyboardEventInfo) {
|
|
146
|
-
switch (info.
|
|
146
|
+
switch (info.key) {
|
|
147
147
|
case 'Enter': {
|
|
148
148
|
this.editor.setCroppingShape(null)
|
|
149
149
|
this.editor.setCurrentTool('select.idle', {})
|
|
@@ -516,7 +516,7 @@ export class Idle extends StateNode {
|
|
|
516
516
|
}
|
|
517
517
|
|
|
518
518
|
override onKeyUp(info: TLKeyboardEventInfo) {
|
|
519
|
-
switch (info.
|
|
519
|
+
switch (info.key) {
|
|
520
520
|
case 'Enter': {
|
|
521
521
|
// Because Enter onKeyDown can happen outside the canvas (but then focus the canvas potentially),
|
|
522
522
|
// we need to check if the canvas was initially selecting something before continuing.
|
package/src/lib/ui/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 = '4.1.0-canary.
|
|
4
|
+
export const version = '4.1.0-canary.21c9ed69dd72'
|
|
5
5
|
export const publishDates = {
|
|
6
6
|
major: '2025-09-18T14:39:22.803Z',
|
|
7
|
-
minor: '2025-
|
|
8
|
-
patch: '2025-
|
|
7
|
+
minor: '2025-10-02T13:15:36.823Z',
|
|
8
|
+
patch: '2025-10-02T13:15:36.823Z',
|
|
9
9
|
}
|