@tldraw/editor 4.2.0-next.47462e908ff5 → 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 +56 -6
- package/dist-cjs/index.js +2 -1
- package/dist-cjs/index.js.map +2 -2
- 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 +31 -0
- 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/debug-flags.js +1 -0
- package/dist-cjs/lib/utils/debug-flags.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 +56 -6
- package/dist-esm/index.mjs +3 -1
- package/dist-esm/index.mjs.map +2 -2
- 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 +31 -0
- 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/debug-flags.mjs +1 -0
- package/dist-esm/lib/utils/debug-flags.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 +10 -10
- package/src/index.ts +1 -0
- 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 +33 -0
- package/src/lib/license/LicenseManager.ts +1 -0
- package/src/lib/license/Watermark.tsx +8 -5
- package/src/lib/utils/debug-flags.ts +5 -4
- 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
|
@@ -837,6 +837,39 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
837
837
|
*/
|
|
838
838
|
readonly root: StateNode
|
|
839
839
|
|
|
840
|
+
/**
|
|
841
|
+
* Set a tool. Useful if you need to add a tool to the state chart on demand,
|
|
842
|
+
* after the editor has already been initialized.
|
|
843
|
+
*
|
|
844
|
+
* @param Tool - The tool to set.
|
|
845
|
+
* @param parent - The parent state node to set the tool on.
|
|
846
|
+
*
|
|
847
|
+
* @public
|
|
848
|
+
*/
|
|
849
|
+
setTool(Tool: TLStateNodeConstructor, parent?: StateNode) {
|
|
850
|
+
parent ??= this.root
|
|
851
|
+
if (hasOwnProperty(parent.children!, Tool.id)) {
|
|
852
|
+
throw Error(`Can't override tool with id "${Tool.id}"`)
|
|
853
|
+
}
|
|
854
|
+
parent.children![Tool.id] = new Tool(this, parent)
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
/**
|
|
858
|
+
* Remove a tool. Useful if you need to remove a tool from the state chart on demand,
|
|
859
|
+
* after the editor has already been initialized.
|
|
860
|
+
*
|
|
861
|
+
* @param Tool - The tool to delete.
|
|
862
|
+
* @param parent - The parent state node to remove the tool from.
|
|
863
|
+
*
|
|
864
|
+
* @public
|
|
865
|
+
*/
|
|
866
|
+
removeTool(Tool: TLStateNodeConstructor, parent?: StateNode) {
|
|
867
|
+
parent ??= this.root
|
|
868
|
+
if (hasOwnProperty(parent.children!, Tool.id)) {
|
|
869
|
+
delete parent.children![Tool.id]
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
|
|
840
873
|
/**
|
|
841
874
|
* A set of functions to call when the app is disposed.
|
|
842
875
|
*
|
|
@@ -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>
|
|
@@ -92,7 +92,8 @@ if (typeof Element !== 'undefined') {
|
|
|
92
92
|
|
|
93
93
|
// --- IMPLEMENTATION ---
|
|
94
94
|
// you probably don't need to read this if you're just using the debug values system
|
|
95
|
-
|
|
95
|
+
/** @public */
|
|
96
|
+
export function createDebugValue<T>(
|
|
96
97
|
name: string,
|
|
97
98
|
{
|
|
98
99
|
defaults,
|
|
@@ -193,7 +194,7 @@ function getDefaultValue<T>(def: DebugFlagDef<T>): T {
|
|
|
193
194
|
}
|
|
194
195
|
}
|
|
195
196
|
|
|
196
|
-
/** @
|
|
197
|
+
/** @public */
|
|
197
198
|
export interface DebugFlagDefaults<T> {
|
|
198
199
|
development?: T
|
|
199
200
|
staging?: T
|
|
@@ -201,14 +202,14 @@ export interface DebugFlagDefaults<T> {
|
|
|
201
202
|
all: T
|
|
202
203
|
}
|
|
203
204
|
|
|
204
|
-
/** @
|
|
205
|
+
/** @public */
|
|
205
206
|
export interface DebugFlagDef<T> {
|
|
206
207
|
name: string
|
|
207
208
|
defaults: DebugFlagDefaults<T>
|
|
208
209
|
shouldStoreForSession: boolean
|
|
209
210
|
}
|
|
210
211
|
|
|
211
|
-
/** @
|
|
212
|
+
/** @public */
|
|
212
213
|
export interface DebugFlag<T> extends DebugFlagDef<T>, Atom<T> {
|
|
213
214
|
reset(): void
|
|
214
215
|
}
|
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
|
}
|