@tldraw/editor 4.2.0-next.3abbdad51d2e → 4.2.0-next.54bc357bbff2
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 +17 -5
- package/dist-cjs/index.js +1 -1
- package/dist-cjs/lib/components/default-components/DefaultCanvas.js +11 -11
- package/dist-cjs/lib/components/default-components/DefaultCanvas.js.map +2 -2
- package/dist-cjs/lib/editor/Editor.js +10 -6
- package/dist-cjs/lib/editor/Editor.js.map +2 -2
- package/dist-cjs/lib/license/LicenseManager.js +1 -0
- package/dist-cjs/lib/license/LicenseManager.js.map +2 -2
- package/dist-cjs/lib/license/Watermark.js +8 -4
- package/dist-cjs/lib/license/Watermark.js.map +2 -2
- package/dist-cjs/lib/utils/runtime.js +2 -2
- package/dist-cjs/lib/utils/runtime.js.map +2 -2
- package/dist-cjs/lib/utils/window-open.js +2 -2
- package/dist-cjs/lib/utils/window-open.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 +17 -5
- package/dist-esm/index.mjs +1 -1
- package/dist-esm/lib/components/default-components/DefaultCanvas.mjs +11 -11
- package/dist-esm/lib/components/default-components/DefaultCanvas.mjs.map +2 -2
- package/dist-esm/lib/editor/Editor.mjs +10 -6
- package/dist-esm/lib/editor/Editor.mjs.map +2 -2
- package/dist-esm/lib/license/LicenseManager.mjs +1 -0
- package/dist-esm/lib/license/LicenseManager.mjs.map +2 -2
- package/dist-esm/lib/license/Watermark.mjs +8 -4
- package/dist-esm/lib/license/Watermark.mjs.map +2 -2
- package/dist-esm/lib/utils/runtime.mjs +2 -2
- package/dist-esm/lib/utils/runtime.mjs.map +2 -2
- package/dist-esm/lib/utils/window-open.mjs +2 -2
- package/dist-esm/lib/utils/window-open.mjs.map +2 -2
- package/dist-esm/version.mjs +3 -3
- package/dist-esm/version.mjs.map +1 -1
- package/package.json +7 -7
- package/src/lib/components/default-components/DefaultCanvas.tsx +9 -9
- package/src/lib/editor/Editor.test.ts +268 -0
- package/src/lib/editor/Editor.ts +10 -6
- package/src/lib/license/LicenseManager.ts +1 -0
- package/src/lib/license/Watermark.tsx +8 -5
- package/src/lib/utils/runtime.ts +3 -3
- package/src/lib/utils/window-open.ts +13 -3
- package/src/version.ts +3 -3
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
createTLStore,
|
|
12
12
|
} from '../..'
|
|
13
13
|
import { Editor } from './Editor'
|
|
14
|
+
import { StateNode } from './tools/StateNode'
|
|
14
15
|
|
|
15
16
|
type ICustomShape = TLBaseShape<
|
|
16
17
|
'my-custom-shape',
|
|
@@ -923,3 +924,270 @@ describe('replaceExternalContent', () => {
|
|
|
923
924
|
expect(mockHandler).toHaveBeenCalledWith(info)
|
|
924
925
|
})
|
|
925
926
|
})
|
|
927
|
+
|
|
928
|
+
describe('setTool', () => {
|
|
929
|
+
class CustomToolA extends StateNode {
|
|
930
|
+
static override id = 'custom-tool-a'
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
class CustomToolB extends StateNode {
|
|
934
|
+
static override id = 'custom-tool-b'
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
class CustomToolC extends StateNode {
|
|
938
|
+
static override id = 'custom-tool-c'
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
class ParentTool extends StateNode {
|
|
942
|
+
static override id = 'parent-tool'
|
|
943
|
+
static override initial = 'child-tool-1'
|
|
944
|
+
static override children() {
|
|
945
|
+
return [ChildTool1]
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
class ChildTool1 extends StateNode {
|
|
950
|
+
static override id = 'child-tool-1'
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
class ChildTool2 extends StateNode {
|
|
954
|
+
static override id = 'child-tool-2'
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
let toolEditor: Editor
|
|
958
|
+
|
|
959
|
+
beforeEach(() => {
|
|
960
|
+
toolEditor = new Editor({
|
|
961
|
+
shapeUtils: [],
|
|
962
|
+
bindingUtils: [],
|
|
963
|
+
tools: [CustomToolA, ParentTool],
|
|
964
|
+
store: createTLStore({ shapeUtils: [], bindingUtils: [] }),
|
|
965
|
+
getContainer: () => document.body,
|
|
966
|
+
})
|
|
967
|
+
})
|
|
968
|
+
|
|
969
|
+
it('should add a tool to the root state', () => {
|
|
970
|
+
// Initially CustomToolB should not exist
|
|
971
|
+
expect(toolEditor.root.children!['custom-tool-b']).toBeUndefined()
|
|
972
|
+
|
|
973
|
+
// Add CustomToolB
|
|
974
|
+
toolEditor.setTool(CustomToolB)
|
|
975
|
+
|
|
976
|
+
// CustomToolB should now exist in root
|
|
977
|
+
expect(toolEditor.root.children!['custom-tool-b']).toBeDefined()
|
|
978
|
+
expect(toolEditor.root.children!['custom-tool-b']).toBeInstanceOf(CustomToolB)
|
|
979
|
+
})
|
|
980
|
+
|
|
981
|
+
it('should add a tool to a specific parent state', () => {
|
|
982
|
+
const parentTool = toolEditor.root.children!['parent-tool'] as ParentTool
|
|
983
|
+
|
|
984
|
+
// Initially should only have child-tool-1
|
|
985
|
+
expect(Object.keys(parentTool.children!)).toHaveLength(1)
|
|
986
|
+
expect(parentTool.children!['child-tool-1']).toBeDefined()
|
|
987
|
+
expect(parentTool.children!['child-tool-2']).toBeUndefined()
|
|
988
|
+
|
|
989
|
+
// Add ChildTool2 to ParentTool
|
|
990
|
+
toolEditor.setTool(ChildTool2, parentTool)
|
|
991
|
+
|
|
992
|
+
// Should now have both children
|
|
993
|
+
expect(Object.keys(parentTool.children!)).toHaveLength(2)
|
|
994
|
+
expect(parentTool.children!['child-tool-1']).toBeDefined()
|
|
995
|
+
expect(parentTool.children!['child-tool-2']).toBeDefined()
|
|
996
|
+
expect(parentTool.children!['child-tool-2']).toBeInstanceOf(ChildTool2)
|
|
997
|
+
})
|
|
998
|
+
|
|
999
|
+
it('should throw an error when trying to override an existing tool', () => {
|
|
1000
|
+
// CustomToolA is already in the root (added in beforeEach)
|
|
1001
|
+
expect(toolEditor.root.children!['custom-tool-a']).toBeDefined()
|
|
1002
|
+
|
|
1003
|
+
// Should throw error when trying to add another tool with the same ID
|
|
1004
|
+
expect(() => {
|
|
1005
|
+
toolEditor.setTool(CustomToolA)
|
|
1006
|
+
}).toThrow('Can\'t override tool with id "custom-tool-a"')
|
|
1007
|
+
})
|
|
1008
|
+
|
|
1009
|
+
it('should allow transitioning to a newly added tool', () => {
|
|
1010
|
+
// Add CustomToolB
|
|
1011
|
+
toolEditor.setTool(CustomToolB)
|
|
1012
|
+
|
|
1013
|
+
// Should be able to transition to the new tool
|
|
1014
|
+
expect(() => {
|
|
1015
|
+
toolEditor.setCurrentTool('custom-tool-b')
|
|
1016
|
+
}).not.toThrow()
|
|
1017
|
+
|
|
1018
|
+
// Should now be on the new tool
|
|
1019
|
+
expect(toolEditor.getCurrentToolId()).toBe('custom-tool-b')
|
|
1020
|
+
})
|
|
1021
|
+
|
|
1022
|
+
it('should create the tool with the correct editor and parent', () => {
|
|
1023
|
+
// Add CustomToolB to root
|
|
1024
|
+
toolEditor.setTool(CustomToolB)
|
|
1025
|
+
|
|
1026
|
+
const customToolB = toolEditor.root.children!['custom-tool-b'] as CustomToolB
|
|
1027
|
+
|
|
1028
|
+
expect(customToolB.editor).toBe(toolEditor)
|
|
1029
|
+
expect(customToolB.parent).toBe(toolEditor.root)
|
|
1030
|
+
})
|
|
1031
|
+
|
|
1032
|
+
it('should maintain existing tools when adding new ones', () => {
|
|
1033
|
+
const originalTool = toolEditor.root.children!['custom-tool-a']
|
|
1034
|
+
|
|
1035
|
+
// Add CustomToolB
|
|
1036
|
+
toolEditor.setTool(CustomToolB)
|
|
1037
|
+
|
|
1038
|
+
// Original tool should still exist
|
|
1039
|
+
expect(toolEditor.root.children!['custom-tool-a']).toBe(originalTool)
|
|
1040
|
+
expect(toolEditor.root.children!['custom-tool-a']).toBeInstanceOf(CustomToolA)
|
|
1041
|
+
})
|
|
1042
|
+
|
|
1043
|
+
it('should allow adding multiple tools', () => {
|
|
1044
|
+
// Add multiple tools
|
|
1045
|
+
toolEditor.setTool(CustomToolB)
|
|
1046
|
+
toolEditor.setTool(CustomToolC)
|
|
1047
|
+
|
|
1048
|
+
// All tools should exist
|
|
1049
|
+
expect(toolEditor.root.children!['custom-tool-a']).toBeDefined()
|
|
1050
|
+
expect(toolEditor.root.children!['custom-tool-b']).toBeDefined()
|
|
1051
|
+
expect(toolEditor.root.children!['custom-tool-c']).toBeDefined()
|
|
1052
|
+
expect(toolEditor.root.children!['custom-tool-b']).toBeInstanceOf(CustomToolB)
|
|
1053
|
+
expect(toolEditor.root.children!['custom-tool-c']).toBeInstanceOf(CustomToolC)
|
|
1054
|
+
})
|
|
1055
|
+
})
|
|
1056
|
+
|
|
1057
|
+
describe('removeTool', () => {
|
|
1058
|
+
class CustomToolA extends StateNode {
|
|
1059
|
+
static override id = 'custom-tool-a'
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
class CustomToolB extends StateNode {
|
|
1063
|
+
static override id = 'custom-tool-b'
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
class CustomToolC extends StateNode {
|
|
1067
|
+
static override id = 'custom-tool-c'
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
class ParentTool extends StateNode {
|
|
1071
|
+
static override id = 'parent-tool'
|
|
1072
|
+
static override initial = 'child-tool-1'
|
|
1073
|
+
static override children() {
|
|
1074
|
+
return [ChildTool1, ChildTool2]
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
class ChildTool1 extends StateNode {
|
|
1079
|
+
static override id = 'child-tool-1'
|
|
1080
|
+
}
|
|
1081
|
+
|
|
1082
|
+
class ChildTool2 extends StateNode {
|
|
1083
|
+
static override id = 'child-tool-2'
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
let toolEditor: Editor
|
|
1087
|
+
|
|
1088
|
+
beforeEach(() => {
|
|
1089
|
+
toolEditor = new Editor({
|
|
1090
|
+
shapeUtils: [],
|
|
1091
|
+
bindingUtils: [],
|
|
1092
|
+
tools: [CustomToolA, CustomToolB, CustomToolC, ParentTool],
|
|
1093
|
+
store: createTLStore({ shapeUtils: [], bindingUtils: [] }),
|
|
1094
|
+
getContainer: () => document.body,
|
|
1095
|
+
})
|
|
1096
|
+
})
|
|
1097
|
+
|
|
1098
|
+
it('should remove a tool from the root state', () => {
|
|
1099
|
+
// CustomToolB should exist initially
|
|
1100
|
+
expect(toolEditor.root.children!['custom-tool-b']).toBeDefined()
|
|
1101
|
+
|
|
1102
|
+
// Remove CustomToolB
|
|
1103
|
+
toolEditor.removeTool(CustomToolB)
|
|
1104
|
+
|
|
1105
|
+
// CustomToolB should no longer exist
|
|
1106
|
+
expect(toolEditor.root.children!['custom-tool-b']).toBeUndefined()
|
|
1107
|
+
})
|
|
1108
|
+
|
|
1109
|
+
it('should remove a tool from a specific parent state', () => {
|
|
1110
|
+
const parentTool = toolEditor.root.children!['parent-tool'] as ParentTool
|
|
1111
|
+
|
|
1112
|
+
// Initially should have both children
|
|
1113
|
+
expect(Object.keys(parentTool.children!)).toHaveLength(2)
|
|
1114
|
+
expect(parentTool.children!['child-tool-1']).toBeDefined()
|
|
1115
|
+
expect(parentTool.children!['child-tool-2']).toBeDefined()
|
|
1116
|
+
|
|
1117
|
+
// Remove ChildTool2 from ParentTool
|
|
1118
|
+
toolEditor.removeTool(ChildTool2, parentTool)
|
|
1119
|
+
|
|
1120
|
+
// Should now only have child-tool-1
|
|
1121
|
+
expect(Object.keys(parentTool.children!)).toHaveLength(1)
|
|
1122
|
+
expect(parentTool.children!['child-tool-1']).toBeDefined()
|
|
1123
|
+
expect(parentTool.children!['child-tool-2']).toBeUndefined()
|
|
1124
|
+
})
|
|
1125
|
+
|
|
1126
|
+
it('should not throw an error when trying to remove a non-existent tool', () => {
|
|
1127
|
+
// First remove CustomToolB
|
|
1128
|
+
toolEditor.removeTool(CustomToolB)
|
|
1129
|
+
expect(toolEditor.root.children!['custom-tool-b']).toBeUndefined()
|
|
1130
|
+
|
|
1131
|
+
// Trying to remove it again should not throw
|
|
1132
|
+
expect(() => {
|
|
1133
|
+
toolEditor.removeTool(CustomToolB)
|
|
1134
|
+
}).not.toThrow()
|
|
1135
|
+
})
|
|
1136
|
+
|
|
1137
|
+
it('should maintain other tools when removing one', () => {
|
|
1138
|
+
const originalToolA = toolEditor.root.children!['custom-tool-a']
|
|
1139
|
+
const originalToolC = toolEditor.root.children!['custom-tool-c']
|
|
1140
|
+
|
|
1141
|
+
// Remove CustomToolB
|
|
1142
|
+
toolEditor.removeTool(CustomToolB)
|
|
1143
|
+
|
|
1144
|
+
// Other tools should still exist
|
|
1145
|
+
expect(toolEditor.root.children!['custom-tool-a']).toBe(originalToolA)
|
|
1146
|
+
expect(toolEditor.root.children!['custom-tool-c']).toBe(originalToolC)
|
|
1147
|
+
expect(toolEditor.root.children!['custom-tool-a']).toBeInstanceOf(CustomToolA)
|
|
1148
|
+
expect(toolEditor.root.children!['custom-tool-c']).toBeInstanceOf(CustomToolC)
|
|
1149
|
+
})
|
|
1150
|
+
|
|
1151
|
+
it('should not be able to transition to a removed tool', () => {
|
|
1152
|
+
// Remove CustomToolB
|
|
1153
|
+
toolEditor.removeTool(CustomToolB)
|
|
1154
|
+
|
|
1155
|
+
// Should throw when trying to transition to removed tool
|
|
1156
|
+
expect(() => {
|
|
1157
|
+
toolEditor.setCurrentTool('custom-tool-b')
|
|
1158
|
+
}).toThrow()
|
|
1159
|
+
})
|
|
1160
|
+
|
|
1161
|
+
it('should allow removing multiple tools', () => {
|
|
1162
|
+
// Remove multiple tools
|
|
1163
|
+
toolEditor.removeTool(CustomToolB)
|
|
1164
|
+
toolEditor.removeTool(CustomToolC)
|
|
1165
|
+
|
|
1166
|
+
// Removed tools should not exist
|
|
1167
|
+
expect(toolEditor.root.children!['custom-tool-b']).toBeUndefined()
|
|
1168
|
+
expect(toolEditor.root.children!['custom-tool-c']).toBeUndefined()
|
|
1169
|
+
|
|
1170
|
+
// Other tools should still exist
|
|
1171
|
+
expect(toolEditor.root.children!['custom-tool-a']).toBeDefined()
|
|
1172
|
+
expect(toolEditor.root.children!['parent-tool']).toBeDefined()
|
|
1173
|
+
})
|
|
1174
|
+
|
|
1175
|
+
it('should allow re-adding a tool after removing it', () => {
|
|
1176
|
+
// Remove CustomToolB
|
|
1177
|
+
toolEditor.removeTool(CustomToolB)
|
|
1178
|
+
expect(toolEditor.root.children!['custom-tool-b']).toBeUndefined()
|
|
1179
|
+
|
|
1180
|
+
// Re-add CustomToolB
|
|
1181
|
+
toolEditor.setTool(CustomToolB)
|
|
1182
|
+
|
|
1183
|
+
// CustomToolB should exist again
|
|
1184
|
+
expect(toolEditor.root.children!['custom-tool-b']).toBeDefined()
|
|
1185
|
+
expect(toolEditor.root.children!['custom-tool-b']).toBeInstanceOf(CustomToolB)
|
|
1186
|
+
|
|
1187
|
+
// Should be able to transition to it
|
|
1188
|
+
expect(() => {
|
|
1189
|
+
toolEditor.setCurrentTool('custom-tool-b')
|
|
1190
|
+
}).not.toThrow()
|
|
1191
|
+
expect(toolEditor.getCurrentToolId()).toBe('custom-tool-b')
|
|
1192
|
+
})
|
|
1193
|
+
})
|
package/src/lib/editor/Editor.ts
CHANGED
|
@@ -842,14 +842,16 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
842
842
|
* after the editor has already been initialized.
|
|
843
843
|
*
|
|
844
844
|
* @param Tool - The tool to set.
|
|
845
|
+
* @param parent - The parent state node to set the tool on.
|
|
845
846
|
*
|
|
846
847
|
* @public
|
|
847
848
|
*/
|
|
848
|
-
setTool(Tool: TLStateNodeConstructor) {
|
|
849
|
-
|
|
849
|
+
setTool(Tool: TLStateNodeConstructor, parent?: StateNode) {
|
|
850
|
+
parent ??= this.root
|
|
851
|
+
if (hasOwnProperty(parent.children!, Tool.id)) {
|
|
850
852
|
throw Error(`Can't override tool with id "${Tool.id}"`)
|
|
851
853
|
}
|
|
852
|
-
|
|
854
|
+
parent.children![Tool.id] = new Tool(this, parent)
|
|
853
855
|
}
|
|
854
856
|
|
|
855
857
|
/**
|
|
@@ -857,12 +859,14 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
857
859
|
* after the editor has already been initialized.
|
|
858
860
|
*
|
|
859
861
|
* @param Tool - The tool to delete.
|
|
862
|
+
* @param parent - The parent state node to remove the tool from.
|
|
860
863
|
*
|
|
861
864
|
* @public
|
|
862
865
|
*/
|
|
863
|
-
removeTool(Tool: TLStateNodeConstructor) {
|
|
864
|
-
|
|
865
|
-
|
|
866
|
+
removeTool(Tool: TLStateNodeConstructor, parent?: StateNode) {
|
|
867
|
+
parent ??= this.root
|
|
868
|
+
if (hasOwnProperty(parent.children!, Tool.id)) {
|
|
869
|
+
delete parent.children![Tool.id]
|
|
866
870
|
}
|
|
867
871
|
}
|
|
868
872
|
|
|
@@ -48,8 +48,7 @@ const UnlicensedWatermark = memo(function UnlicensedWatermark({
|
|
|
48
48
|
const ref = useRef<HTMLDivElement>(null)
|
|
49
49
|
usePassThroughWheelEvents(ref)
|
|
50
50
|
|
|
51
|
-
const url =
|
|
52
|
-
'https://tldraw.dev/pricing?utm_source=dotcom&utm_medium=organic&utm_campaign=watermark'
|
|
51
|
+
const url = 'https://tldraw.dev/pricing?utm_source=sdk&utm_medium=organic&utm_campaign=watermark'
|
|
53
52
|
|
|
54
53
|
return (
|
|
55
54
|
<div
|
|
@@ -70,7 +69,9 @@ const UnlicensedWatermark = memo(function UnlicensedWatermark({
|
|
|
70
69
|
preventDefault(e)
|
|
71
70
|
}}
|
|
72
71
|
title="The tldraw SDK requires a license key to work in production. You can get a free 100-day trial license at tldraw.dev/pricing."
|
|
73
|
-
onClick={() =>
|
|
72
|
+
onClick={() => {
|
|
73
|
+
runtime.openWindow(url, '_blank', true)
|
|
74
|
+
}} // allow referrer
|
|
74
75
|
>
|
|
75
76
|
Get a license for production
|
|
76
77
|
</button>
|
|
@@ -96,7 +97,7 @@ const WatermarkInner = memo(function WatermarkInner({
|
|
|
96
97
|
usePassThroughWheelEvents(ref)
|
|
97
98
|
|
|
98
99
|
const maskCss = `url('${src}') center 100% / 100% no-repeat`
|
|
99
|
-
const url = 'https://tldraw.dev/?utm_source=
|
|
100
|
+
const url = 'https://tldraw.dev/?utm_source=sdk&utm_medium=organic&utm_campaign=watermark'
|
|
100
101
|
|
|
101
102
|
if (isUnlicensed) {
|
|
102
103
|
return <UnlicensedWatermark isDebugMode={isDebugMode} isMobile={isMobile} />
|
|
@@ -120,7 +121,9 @@ const WatermarkInner = memo(function WatermarkInner({
|
|
|
120
121
|
preventDefault(e)
|
|
121
122
|
}}
|
|
122
123
|
title="Build infinite canvas applications with the tldraw SDK. Learn more at https://tldraw.dev."
|
|
123
|
-
onClick={() =>
|
|
124
|
+
onClick={() => {
|
|
125
|
+
runtime.openWindow(url, '_blank')
|
|
126
|
+
}}
|
|
124
127
|
style={{ mask: maskCss, WebkitMask: maskCss }}
|
|
125
128
|
/>
|
|
126
129
|
</div>
|
package/src/lib/utils/runtime.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/** @public */
|
|
2
2
|
export const runtime: {
|
|
3
|
-
openWindow(url: string, target: string): void
|
|
3
|
+
openWindow(url: string, target: string, allowReferrer?: boolean): void
|
|
4
4
|
refreshPage(): void
|
|
5
5
|
hardReset(): void
|
|
6
6
|
} = {
|
|
7
|
-
openWindow(url, target) {
|
|
8
|
-
window.open(url, target, 'noopener noreferrer')
|
|
7
|
+
openWindow(url, target, allowReferrer = false) {
|
|
8
|
+
return window.open(url, target, allowReferrer ? 'noopener' : 'noopener noreferrer')
|
|
9
9
|
},
|
|
10
10
|
refreshPage() {
|
|
11
11
|
window.location.reload()
|
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
import { runtime } from './runtime'
|
|
2
2
|
|
|
3
|
-
/**
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Open a new window with the given URL and target. Prefer this to the window.open function, as it
|
|
5
|
+
* will work more reliably in embedded scenarios, such as our VS Code extension. See the runtime
|
|
6
|
+
* object in tldraw/editor for more details.
|
|
7
|
+
*
|
|
8
|
+
* @param url - The URL to open.
|
|
9
|
+
* @param target - The target window to open the URL in.
|
|
10
|
+
* @param allowReferrer - Whether to allow the referrer to be sent to the new window.
|
|
11
|
+
* @returns The new window object.
|
|
12
|
+
* @public
|
|
13
|
+
*/
|
|
14
|
+
export function openWindow(url: string, target = '_blank', allowReferrer?: boolean) {
|
|
15
|
+
return runtime.openWindow(url, target, allowReferrer)
|
|
6
16
|
}
|
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 = '4.2.0-next.
|
|
4
|
+
export const version = '4.2.0-next.54bc357bbff2'
|
|
5
5
|
export const publishDates = {
|
|
6
6
|
major: '2025-09-18T14:39:22.803Z',
|
|
7
|
-
minor: '2025-
|
|
8
|
-
patch: '2025-
|
|
7
|
+
minor: '2025-11-19T10:31:43.651Z',
|
|
8
|
+
patch: '2025-11-19T10:31:43.651Z',
|
|
9
9
|
}
|