@tldraw/editor 3.9.0-canary.fae364b5aba5 → 3.9.0-internal.7f0e15f4f7d9

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.
Files changed (132) hide show
  1. package/dist-cjs/index.d.ts +228 -3
  2. package/dist-cjs/index.js +9 -1
  3. package/dist-cjs/index.js.map +2 -2
  4. package/dist-cjs/lib/TldrawEditor.js +33 -6
  5. package/dist-cjs/lib/TldrawEditor.js.map +2 -2
  6. package/dist-cjs/lib/components/Shape.js +7 -0
  7. package/dist-cjs/lib/components/Shape.js.map +2 -2
  8. package/dist-cjs/lib/editor/Editor.js +63 -8
  9. package/dist-cjs/lib/editor/Editor.js.map +2 -2
  10. package/dist-cjs/lib/editor/managers/FontManager.js +167 -0
  11. package/dist-cjs/lib/editor/managers/FontManager.js.map +7 -0
  12. package/dist-cjs/lib/editor/managers/TextManager.js +23 -17
  13. package/dist-cjs/lib/editor/managers/TextManager.js.map +2 -2
  14. package/dist-cjs/lib/editor/shapes/ShapeUtil.js +11 -0
  15. package/dist-cjs/lib/editor/shapes/ShapeUtil.js.map +2 -2
  16. package/dist-cjs/lib/editor/types/emit-types.js.map +1 -1
  17. package/dist-cjs/lib/editor/types/external-content.js.map +1 -1
  18. package/dist-cjs/lib/exports/FontEmbedder.js +7 -2
  19. package/dist-cjs/lib/exports/FontEmbedder.js.map +2 -2
  20. package/dist-cjs/lib/exports/StyleEmbedder.js +1 -1
  21. package/dist-cjs/lib/exports/StyleEmbedder.js.map +2 -2
  22. package/dist-cjs/lib/exports/exportToSvg.js +3 -2
  23. package/dist-cjs/lib/exports/exportToSvg.js.map +2 -2
  24. package/dist-cjs/lib/exports/getSvgAsImage.js +1 -1
  25. package/dist-cjs/lib/exports/getSvgAsImage.js.map +2 -2
  26. package/dist-cjs/lib/exports/getSvgJsx.js +18 -1
  27. package/dist-cjs/lib/exports/getSvgJsx.js.map +2 -2
  28. package/dist-cjs/lib/exports/parseCss.js +1 -0
  29. package/dist-cjs/lib/exports/parseCss.js.map +2 -2
  30. package/dist-cjs/lib/globals/environment.js +3 -1
  31. package/dist-cjs/lib/globals/environment.js.map +2 -2
  32. package/dist-cjs/lib/hooks/useCanvasEvents.js +2 -2
  33. package/dist-cjs/lib/hooks/useCanvasEvents.js.map +2 -2
  34. package/dist-cjs/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.js +1 -1
  35. package/dist-cjs/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.js.map +2 -2
  36. package/dist-cjs/lib/hooks/usePassThroughMouseOverEvents.js +48 -0
  37. package/dist-cjs/lib/hooks/usePassThroughMouseOverEvents.js.map +7 -0
  38. package/dist-cjs/lib/hooks/usePassThroughWheelEvents.js.map +2 -2
  39. package/dist-cjs/lib/hooks/useViewportHeight.js +56 -0
  40. package/dist-cjs/lib/hooks/useViewportHeight.js.map +7 -0
  41. package/dist-cjs/lib/license/LicenseManager.js +1 -1
  42. package/dist-cjs/lib/license/LicenseManager.js.map +2 -2
  43. package/dist-cjs/lib/options.js +2 -1
  44. package/dist-cjs/lib/options.js.map +2 -2
  45. package/dist-cjs/lib/utils/browserCanvasMaxSize.js +104 -28
  46. package/dist-cjs/lib/utils/browserCanvasMaxSize.js.map +3 -3
  47. package/dist-cjs/lib/utils/dom.js +1 -1
  48. package/dist-cjs/lib/utils/dom.js.map +2 -2
  49. package/dist-cjs/lib/utils/richText.js +46 -0
  50. package/dist-cjs/lib/utils/richText.js.map +7 -0
  51. package/dist-cjs/version.js +3 -3
  52. package/dist-cjs/version.js.map +1 -1
  53. package/dist-esm/index.d.mts +228 -3
  54. package/dist-esm/index.mjs +13 -1
  55. package/dist-esm/index.mjs.map +2 -2
  56. package/dist-esm/lib/TldrawEditor.mjs +34 -7
  57. package/dist-esm/lib/TldrawEditor.mjs.map +2 -2
  58. package/dist-esm/lib/components/Shape.mjs +8 -1
  59. package/dist-esm/lib/components/Shape.mjs.map +2 -2
  60. package/dist-esm/lib/editor/Editor.mjs +71 -9
  61. package/dist-esm/lib/editor/Editor.mjs.map +2 -2
  62. package/dist-esm/lib/editor/managers/FontManager.mjs +153 -0
  63. package/dist-esm/lib/editor/managers/FontManager.mjs.map +7 -0
  64. package/dist-esm/lib/editor/managers/TextManager.mjs +23 -17
  65. package/dist-esm/lib/editor/managers/TextManager.mjs.map +2 -2
  66. package/dist-esm/lib/editor/shapes/ShapeUtil.mjs +11 -0
  67. package/dist-esm/lib/editor/shapes/ShapeUtil.mjs.map +2 -2
  68. package/dist-esm/lib/exports/FontEmbedder.mjs +7 -2
  69. package/dist-esm/lib/exports/FontEmbedder.mjs.map +2 -2
  70. package/dist-esm/lib/exports/StyleEmbedder.mjs +1 -1
  71. package/dist-esm/lib/exports/StyleEmbedder.mjs.map +2 -2
  72. package/dist-esm/lib/exports/exportToSvg.mjs +3 -2
  73. package/dist-esm/lib/exports/exportToSvg.mjs.map +2 -2
  74. package/dist-esm/lib/exports/getSvgAsImage.mjs +1 -1
  75. package/dist-esm/lib/exports/getSvgAsImage.mjs.map +2 -2
  76. package/dist-esm/lib/exports/getSvgJsx.mjs +19 -2
  77. package/dist-esm/lib/exports/getSvgJsx.mjs.map +2 -2
  78. package/dist-esm/lib/exports/parseCss.mjs +1 -0
  79. package/dist-esm/lib/exports/parseCss.mjs.map +2 -2
  80. package/dist-esm/lib/globals/environment.mjs +3 -1
  81. package/dist-esm/lib/globals/environment.mjs.map +2 -2
  82. package/dist-esm/lib/hooks/useCanvasEvents.mjs +2 -2
  83. package/dist-esm/lib/hooks/useCanvasEvents.mjs.map +2 -2
  84. package/dist-esm/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.mjs +1 -1
  85. package/dist-esm/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.mjs.map +2 -2
  86. package/dist-esm/lib/hooks/usePassThroughMouseOverEvents.mjs +28 -0
  87. package/dist-esm/lib/hooks/usePassThroughMouseOverEvents.mjs.map +7 -0
  88. package/dist-esm/lib/hooks/usePassThroughWheelEvents.mjs.map +2 -2
  89. package/dist-esm/lib/hooks/useViewportHeight.mjs +36 -0
  90. package/dist-esm/lib/hooks/useViewportHeight.mjs.map +7 -0
  91. package/dist-esm/lib/license/LicenseManager.mjs +1 -1
  92. package/dist-esm/lib/license/LicenseManager.mjs.map +2 -2
  93. package/dist-esm/lib/options.mjs +2 -1
  94. package/dist-esm/lib/options.mjs.map +2 -2
  95. package/dist-esm/lib/utils/browserCanvasMaxSize.mjs +104 -18
  96. package/dist-esm/lib/utils/browserCanvasMaxSize.mjs.map +2 -2
  97. package/dist-esm/lib/utils/dom.mjs +1 -1
  98. package/dist-esm/lib/utils/dom.mjs.map +2 -2
  99. package/dist-esm/lib/utils/richText.mjs +26 -0
  100. package/dist-esm/lib/utils/richText.mjs.map +7 -0
  101. package/dist-esm/version.mjs +3 -3
  102. package/dist-esm/version.mjs.map +1 -1
  103. package/editor.css +127 -13
  104. package/package.json +10 -9
  105. package/src/index.ts +15 -0
  106. package/src/lib/TldrawEditor.tsx +52 -4
  107. package/src/lib/components/Shape.tsx +9 -1
  108. package/src/lib/editor/Editor.ts +91 -7
  109. package/src/lib/editor/managers/FontManager.ts +252 -0
  110. package/src/lib/editor/managers/TextManager.ts +42 -17
  111. package/src/lib/editor/shapes/ShapeUtil.ts +13 -0
  112. package/src/lib/editor/types/emit-types.ts +1 -0
  113. package/src/lib/editor/types/external-content.ts +1 -0
  114. package/src/lib/exports/FontEmbedder.ts +13 -1
  115. package/src/lib/exports/StyleEmbedder.ts +1 -1
  116. package/src/lib/exports/exportToSvg.tsx +4 -3
  117. package/src/lib/exports/getSvgAsImage.ts +1 -1
  118. package/src/lib/exports/getSvgJsx.tsx +22 -2
  119. package/src/lib/exports/parseCss.ts +1 -0
  120. package/src/lib/globals/environment.ts +3 -0
  121. package/src/lib/hooks/useCanvasEvents.ts +2 -1
  122. package/src/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.ts +1 -0
  123. package/src/lib/hooks/usePassThroughMouseOverEvents.ts +29 -0
  124. package/src/lib/hooks/usePassThroughWheelEvents.ts +0 -1
  125. package/src/lib/hooks/useViewportHeight.ts +37 -0
  126. package/src/lib/license/LicenseManager.test.ts +16 -13
  127. package/src/lib/license/LicenseManager.ts +2 -2
  128. package/src/lib/options.ts +7 -0
  129. package/src/lib/utils/browserCanvasMaxSize.ts +121 -21
  130. package/src/lib/utils/dom.ts +1 -1
  131. package/src/lib/utils/richText.ts +72 -0
  132. package/src/version.ts +3 -3
@@ -110,8 +110,8 @@ export class LicenseManager {
110
110
  if (testEnvironment === 'development') return true
111
111
  if (testEnvironment === 'production') return false
112
112
 
113
- // If we are using https we assume it's a production env and a development one otherwise
114
- return window.location.protocol !== 'https:'
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 window.location.protocol !== 'https:' || window.location.hostname === 'localhost'
115
115
  }
116
116
 
117
117
  private async extractLicenseKey(licenseKey: string): Promise<LicenseInfo> {
@@ -69,6 +69,12 @@ export interface TldrawOptions {
69
69
  * By default, the toolbar items are accessible via number shortcuts according to their order. To disable this, set this option to false.
70
70
  */
71
71
  readonly enableToolbarKeyboardShortcuts: boolean
72
+ /**
73
+ * The maximum number of fonts that will be loaded while blocking the main rendering of the
74
+ * canvas. If there are more than this number of fonts needed, we'll just show the canvas right
75
+ * away and let the fonts load in in the background.
76
+ */
77
+ readonly maxFontsToLoadBeforeRender: number
72
78
  }
73
79
 
74
80
  /** @public */
@@ -114,4 +120,5 @@ export const defaultTldrawOptions = {
114
120
  createTextOnCanvasDoubleClick: true,
115
121
  exportProvider: Fragment,
116
122
  enableToolbarKeyboardShortcuts: true,
123
+ maxFontsToLoadBeforeRender: Infinity,
117
124
  } as const satisfies TldrawOptions
@@ -1,5 +1,3 @@
1
- import canvasSize from 'canvas-size'
2
-
3
1
  /** @internal */
4
2
  export interface CanvasMaxSize {
5
3
  maxWidth: number
@@ -7,33 +5,135 @@ export interface CanvasMaxSize {
7
5
  maxArea: number
8
6
  }
9
7
 
10
- let maxSizePromise: Promise<CanvasMaxSize> | null = null
8
+ // Cache this, only want to do this once per browser session
9
+ let maxCanvasSizes: CanvasMaxSize | null = null
11
10
 
12
- function getBrowserCanvasMaxSize() {
13
- if (!maxSizePromise) {
14
- maxSizePromise = calculateBrowserCanvasMaxSize()
11
+ function getBrowserCanvasMaxSize(): CanvasMaxSize {
12
+ if (!maxCanvasSizes) {
13
+ maxCanvasSizes = {
14
+ maxWidth: getCanvasSize('width'), // test very wide but 1 pixel tall canvases
15
+ maxHeight: getCanvasSize('height'), // test very tall but 1 pixel wide canvases
16
+ maxArea: getCanvasSize('area'), // test square canvases
17
+ }
15
18
  }
16
-
17
- return maxSizePromise
19
+ return maxCanvasSizes
18
20
  }
19
21
 
20
- async function calculateBrowserCanvasMaxSize(): Promise<CanvasMaxSize> {
21
- const maxWidth = await canvasSize.maxWidth({ usePromise: true })
22
- const maxHeight = await canvasSize.maxHeight({ usePromise: true })
23
- const maxArea = await canvasSize.maxArea({ usePromise: true })
24
- return {
25
- maxWidth: maxWidth.width,
26
- maxHeight: maxHeight.height,
27
- maxArea: maxArea.width * maxArea.height,
28
- }
29
- }
22
+ // Extracted from https://github.com/jhildenbiddle/canvas-size
23
+ // MIT License: https://github.com/jhildenbiddle/canvas-size/blob/master/LICENSE
24
+ // Copyright (c) John Hildenbiddle
30
25
 
31
- // https://github.com/jhildenbiddle/canvas-size?tab=readme-ov-file#test-results
32
26
  const MAX_SAFE_CANVAS_DIMENSION = 8192
33
27
  const MAX_SAFE_CANVAS_AREA = 4096 * 4096
34
28
 
29
+ const TEST_SIZES = {
30
+ area: [
31
+ // Chrome 70 (Mac, Win)
32
+ // Chrome 68 (Android 4.4)
33
+ // Edge 17 (Win)
34
+ // Safari 7-12 (Mac)
35
+ 16384,
36
+ // Chrome 68 (Android 7.1-9)
37
+ 14188,
38
+ // Chrome 68 (Android 5)
39
+ 11402,
40
+ // Firefox 63 (Mac, Win)
41
+ 11180,
42
+ // Chrome 68 (Android 6)
43
+ 10836,
44
+ // IE 9-11 (Win)
45
+ 8192,
46
+ // IE Mobile (Windows Phone 8.x)
47
+ // Safari (iOS 9 - 12)
48
+ 4096,
49
+ ],
50
+ height: [
51
+ // Safari 7-12 (Mac)
52
+ // Safari (iOS 9-12)
53
+ 8388607,
54
+ // Chrome 83 (Mac, Win)
55
+ 65535,
56
+ // Chrome 70 (Mac, Win)
57
+ // Chrome 68 (Android 4.4-9)
58
+ // Firefox 63 (Mac, Win)
59
+ 32767,
60
+ // Edge 17 (Win)
61
+ // IE11 (Win)
62
+ 16384,
63
+ // IE 9-10 (Win)
64
+ 8192,
65
+ // IE Mobile (Windows Phone 8.x)
66
+ 4096,
67
+ ],
68
+ width: [
69
+ // Safari 7-12 (Mac)
70
+ // Safari (iOS 9-12)
71
+ 4194303,
72
+ // Chrome 83 (Mac, Win)
73
+ 65535,
74
+ // Chrome 70 (Mac, Win)
75
+ // Chrome 68 (Android 4.4-9)
76
+ // Firefox 63 (Mac, Win)
77
+ 32767,
78
+ // Edge 17 (Win)
79
+ // IE11 (Win)
80
+ 16384,
81
+ // IE 9-10 (Win)
82
+ 8192,
83
+ // IE Mobile (Windows Phone 8.x)
84
+ 4096,
85
+ ],
86
+ } as const
87
+
88
+ /**
89
+ * Tests ability to read pixel data from canvas elements of various dimensions
90
+ * by decreasing canvas height and/or width until a test succeeds.
91
+ */
92
+ export function getCanvasSize(dimension: 'width' | 'height' | 'area') {
93
+ const cropCvs = document.createElement('canvas')
94
+ cropCvs.width = 1
95
+ cropCvs.height = 1
96
+ const cropCtx = cropCvs.getContext('2d')!
97
+
98
+ for (const size of TEST_SIZES[dimension]) {
99
+ const w = dimension === 'height' ? 1 : size
100
+ const h = dimension === 'width' ? 1 : size
101
+
102
+ const testCvs = document.createElement('canvas')
103
+ testCvs.width = w
104
+ testCvs.height = h
105
+ const testCtx = testCvs.getContext('2d')!
106
+
107
+ testCtx.fillRect(w - 1, h - 1, 1, 1)
108
+ cropCtx.drawImage(testCvs, w - 1, h - 1, 1, 1, 0, 0, 1, 1)
109
+
110
+ const isTestPassed = cropCtx.getImageData(0, 0, 1, 1).data[3] !== 0
111
+ // release memory
112
+ testCvs.width = 0
113
+ testCvs.height = 0
114
+
115
+ if (isTestPassed) {
116
+ // release memory
117
+ cropCvs.width = 0
118
+ cropCvs.height = 0
119
+
120
+ if (dimension === 'area') {
121
+ return size * size
122
+ } else {
123
+ return size
124
+ }
125
+ }
126
+ }
127
+
128
+ // didn't find a good size, release memory and error
129
+ cropCvs.width = 0
130
+ cropCvs.height = 0
131
+
132
+ throw Error('Failed to determine maximum canvas dimension')
133
+ }
134
+
35
135
  /** @internal */
36
- export async function clampToBrowserMaxCanvasSize(width: number, height: number) {
136
+ export function clampToBrowserMaxCanvasSize(width: number, height: number) {
37
137
  if (
38
138
  width <= MAX_SAFE_CANVAS_DIMENSION &&
39
139
  height <= MAX_SAFE_CANVAS_DIMENSION &&
@@ -42,7 +142,7 @@ export async function clampToBrowserMaxCanvasSize(width: number, height: number)
42
142
  return [width, height]
43
143
  }
44
144
 
45
- const { maxWidth, maxHeight, maxArea } = await getBrowserCanvasMaxSize()
145
+ const { maxWidth, maxHeight, maxArea } = getBrowserCanvasMaxSize()
46
146
  const aspectRatio = width / height
47
147
 
48
148
  if (width > maxWidth) {
@@ -98,7 +98,7 @@ export function activeElementShouldCaptureKeys() {
98
98
  const { activeElement } = document
99
99
  return !!(
100
100
  activeElement &&
101
- (activeElement.getAttribute('contenteditable') ||
101
+ ((activeElement as HTMLElement).isContentEditable ||
102
102
  INPUTS.indexOf(activeElement.tagName.toLowerCase()) > -1)
103
103
  )
104
104
  }
@@ -0,0 +1,72 @@
1
+ import { getSchema, JSONContent, Editor as TTEditor } from '@tiptap/core'
2
+ import { Node } from '@tiptap/pm/model'
3
+ import { EditorProviderProps } from '@tiptap/react'
4
+ import { TLRichText } from '@tldraw/tlschema'
5
+ import { assert } from '@tldraw/utils'
6
+ import { Editor } from '../editor/Editor'
7
+ import { TLFontFace } from '../editor/managers/FontManager'
8
+
9
+ /**
10
+ * This is the TipTap editor! Docs are {@link https://tiptap.dev/docs}.
11
+ *
12
+ * @public
13
+ */
14
+ export type TiptapEditor = TTEditor
15
+
16
+ /**
17
+ * A TipTap node. See {@link https://tiptap.dev/docs}.
18
+ * @public
19
+ */
20
+ export type TiptapNode = Node
21
+
22
+ /** @public */
23
+ export interface TLTextOptions {
24
+ tipTapConfig?: EditorProviderProps
25
+ addFontsFromNode?: RichTextFontVisitor
26
+ }
27
+
28
+ /** @public */
29
+ export interface RichTextFontVisitorState {
30
+ readonly family: string
31
+ readonly weight: string
32
+ readonly style: string
33
+ }
34
+
35
+ /** @public */
36
+ export type RichTextFontVisitor = (
37
+ node: TiptapNode,
38
+ state: RichTextFontVisitorState,
39
+ addFont: (font: TLFontFace) => void
40
+ ) => RichTextFontVisitorState
41
+
42
+ /** @public */
43
+ export function getFontsFromRichText(
44
+ editor: Editor,
45
+ richText: TLRichText,
46
+ initialState: RichTextFontVisitorState
47
+ ) {
48
+ const { tipTapConfig, addFontsFromNode } = editor.getTextOptions()
49
+ assert(tipTapConfig, 'textOptions.tipTapConfig must be set to use rich text')
50
+ assert(addFontsFromNode, 'textOptions.addFontsFromNode must be set to use rich text')
51
+
52
+ const schema = getSchema(tipTapConfig.extensions ?? [])
53
+ const rootNode = Node.fromJSON(schema, richText as JSONContent)
54
+
55
+ const fonts = new Set<TLFontFace>()
56
+
57
+ function addFont(font: TLFontFace) {
58
+ fonts.add(font)
59
+ }
60
+
61
+ function visit(node: TiptapNode, state: RichTextFontVisitorState) {
62
+ state = addFontsFromNode!(node, state, addFont)
63
+
64
+ for (const child of node.children) {
65
+ visit(child, state)
66
+ }
67
+ }
68
+
69
+ visit(rootNode, initialState)
70
+
71
+ return Array.from(fonts)
72
+ }
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.9.0-canary.fae364b5aba5'
4
+ export const version = '3.9.0-internal.7f0e15f4f7d9'
5
5
  export const publishDates = {
6
6
  major: '2024-09-13T14:36:29.063Z',
7
- minor: '2025-02-21T10:19:16.590Z',
8
- patch: '2025-02-21T10:19:16.590Z',
7
+ minor: '2025-02-25T14:10:40.799Z',
8
+ patch: '2025-02-25T14:10:40.799Z',
9
9
  }