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

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 (118) hide show
  1. package/CHANGELOG.md +90 -0
  2. package/README.md +1 -1
  3. package/dist-cjs/index.d.ts +36 -229
  4. package/dist-cjs/index.js +1 -9
  5. package/dist-cjs/index.js.map +2 -2
  6. package/dist-cjs/lib/TldrawEditor.js +6 -33
  7. package/dist-cjs/lib/TldrawEditor.js.map +2 -2
  8. package/dist-cjs/lib/components/Shape.js +0 -7
  9. package/dist-cjs/lib/components/Shape.js.map +2 -2
  10. package/dist-cjs/lib/components/default-components/DefaultErrorFallback.js +1 -1
  11. package/dist-cjs/lib/components/default-components/DefaultErrorFallback.js.map +2 -2
  12. package/dist-cjs/lib/editor/Editor.js +435 -308
  13. package/dist-cjs/lib/editor/Editor.js.map +3 -3
  14. package/dist-cjs/lib/editor/managers/TextManager.js +17 -23
  15. package/dist-cjs/lib/editor/managers/TextManager.js.map +2 -2
  16. package/dist-cjs/lib/editor/shapes/ShapeUtil.js +7 -13
  17. package/dist-cjs/lib/editor/shapes/ShapeUtil.js.map +2 -2
  18. package/dist-cjs/lib/editor/types/emit-types.js.map +1 -1
  19. package/dist-cjs/lib/editor/types/external-content.js.map +1 -1
  20. package/dist-cjs/lib/exports/FontEmbedder.js +2 -7
  21. package/dist-cjs/lib/exports/FontEmbedder.js.map +2 -2
  22. package/dist-cjs/lib/exports/StyleEmbedder.js +1 -1
  23. package/dist-cjs/lib/exports/StyleEmbedder.js.map +2 -2
  24. package/dist-cjs/lib/exports/exportToSvg.js +2 -3
  25. package/dist-cjs/lib/exports/exportToSvg.js.map +2 -2
  26. package/dist-cjs/lib/exports/getSvgJsx.js +1 -18
  27. package/dist-cjs/lib/exports/getSvgJsx.js.map +2 -2
  28. package/dist-cjs/lib/exports/parseCss.js +0 -1
  29. package/dist-cjs/lib/exports/parseCss.js.map +2 -2
  30. package/dist-cjs/lib/hooks/useCanvasEvents.js +2 -2
  31. package/dist-cjs/lib/hooks/useCanvasEvents.js.map +2 -2
  32. package/dist-cjs/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.js +1 -1
  33. package/dist-cjs/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.js.map +2 -2
  34. package/dist-cjs/lib/hooks/usePassThroughWheelEvents.js.map +2 -2
  35. package/dist-cjs/lib/options.js +1 -2
  36. package/dist-cjs/lib/options.js.map +2 -2
  37. package/dist-cjs/lib/utils/dom.js +1 -1
  38. package/dist-cjs/lib/utils/dom.js.map +2 -2
  39. package/dist-cjs/version.js +3 -3
  40. package/dist-cjs/version.js.map +1 -1
  41. package/dist-esm/index.d.mts +36 -229
  42. package/dist-esm/index.mjs +1 -13
  43. package/dist-esm/index.mjs.map +2 -2
  44. package/dist-esm/lib/TldrawEditor.mjs +7 -34
  45. package/dist-esm/lib/TldrawEditor.mjs.map +2 -2
  46. package/dist-esm/lib/components/Shape.mjs +1 -8
  47. package/dist-esm/lib/components/Shape.mjs.map +2 -2
  48. package/dist-esm/lib/components/default-components/DefaultErrorFallback.mjs +1 -1
  49. package/dist-esm/lib/components/default-components/DefaultErrorFallback.mjs.map +2 -2
  50. package/dist-esm/lib/editor/Editor.mjs +432 -312
  51. package/dist-esm/lib/editor/Editor.mjs.map +3 -3
  52. package/dist-esm/lib/editor/managers/TextManager.mjs +17 -23
  53. package/dist-esm/lib/editor/managers/TextManager.mjs.map +2 -2
  54. package/dist-esm/lib/editor/shapes/ShapeUtil.mjs +7 -13
  55. package/dist-esm/lib/editor/shapes/ShapeUtil.mjs.map +2 -2
  56. package/dist-esm/lib/exports/FontEmbedder.mjs +2 -7
  57. package/dist-esm/lib/exports/FontEmbedder.mjs.map +2 -2
  58. package/dist-esm/lib/exports/StyleEmbedder.mjs +1 -1
  59. package/dist-esm/lib/exports/StyleEmbedder.mjs.map +2 -2
  60. package/dist-esm/lib/exports/exportToSvg.mjs +2 -3
  61. package/dist-esm/lib/exports/exportToSvg.mjs.map +2 -2
  62. package/dist-esm/lib/exports/getSvgJsx.mjs +2 -19
  63. package/dist-esm/lib/exports/getSvgJsx.mjs.map +2 -2
  64. package/dist-esm/lib/exports/parseCss.mjs +0 -1
  65. package/dist-esm/lib/exports/parseCss.mjs.map +2 -2
  66. package/dist-esm/lib/hooks/useCanvasEvents.mjs +2 -2
  67. package/dist-esm/lib/hooks/useCanvasEvents.mjs.map +2 -2
  68. package/dist-esm/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.mjs +1 -1
  69. package/dist-esm/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.mjs.map +2 -2
  70. package/dist-esm/lib/hooks/usePassThroughWheelEvents.mjs.map +2 -2
  71. package/dist-esm/lib/options.mjs +1 -2
  72. package/dist-esm/lib/options.mjs.map +2 -2
  73. package/dist-esm/lib/utils/dom.mjs +1 -1
  74. package/dist-esm/lib/utils/dom.mjs.map +2 -2
  75. package/dist-esm/version.mjs +3 -3
  76. package/dist-esm/version.mjs.map +1 -1
  77. package/editor.css +13 -127
  78. package/package.json +7 -10
  79. package/src/index.ts +2 -15
  80. package/src/lib/TldrawEditor.tsx +4 -52
  81. package/src/lib/components/Shape.tsx +1 -9
  82. package/src/lib/components/default-components/DefaultErrorFallback.tsx +5 -3
  83. package/src/lib/editor/Editor.ts +561 -362
  84. package/src/lib/editor/managers/TextManager.ts +17 -42
  85. package/src/lib/editor/shapes/ShapeUtil.ts +32 -18
  86. package/src/lib/editor/types/emit-types.ts +0 -1
  87. package/src/lib/editor/types/external-content.ts +0 -1
  88. package/src/lib/exports/FontEmbedder.ts +1 -13
  89. package/src/lib/exports/StyleEmbedder.ts +1 -1
  90. package/src/lib/exports/exportToSvg.tsx +3 -4
  91. package/src/lib/exports/getSvgJsx.tsx +3 -22
  92. package/src/lib/exports/parseCss.ts +0 -1
  93. package/src/lib/hooks/useCanvasEvents.ts +1 -2
  94. package/src/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.ts +0 -1
  95. package/src/lib/hooks/usePassThroughWheelEvents.ts +1 -0
  96. package/src/lib/options.ts +0 -7
  97. package/src/lib/utils/dom.ts +1 -1
  98. package/src/version.ts +3 -3
  99. package/dist-cjs/lib/editor/managers/FontManager.js +0 -167
  100. package/dist-cjs/lib/editor/managers/FontManager.js.map +0 -7
  101. package/dist-cjs/lib/hooks/usePassThroughMouseOverEvents.js +0 -48
  102. package/dist-cjs/lib/hooks/usePassThroughMouseOverEvents.js.map +0 -7
  103. package/dist-cjs/lib/hooks/useViewportHeight.js +0 -56
  104. package/dist-cjs/lib/hooks/useViewportHeight.js.map +0 -7
  105. package/dist-cjs/lib/utils/richText.js +0 -46
  106. package/dist-cjs/lib/utils/richText.js.map +0 -7
  107. package/dist-esm/lib/editor/managers/FontManager.mjs +0 -153
  108. package/dist-esm/lib/editor/managers/FontManager.mjs.map +0 -7
  109. package/dist-esm/lib/hooks/usePassThroughMouseOverEvents.mjs +0 -28
  110. package/dist-esm/lib/hooks/usePassThroughMouseOverEvents.mjs.map +0 -7
  111. package/dist-esm/lib/hooks/useViewportHeight.mjs +0 -36
  112. package/dist-esm/lib/hooks/useViewportHeight.mjs.map +0 -7
  113. package/dist-esm/lib/utils/richText.mjs +0 -26
  114. package/dist-esm/lib/utils/richText.mjs.map +0 -7
  115. package/src/lib/editor/managers/FontManager.ts +0 -252
  116. package/src/lib/hooks/usePassThroughMouseOverEvents.ts +0 -29
  117. package/src/lib/hooks/useViewportHeight.ts +0 -37
  118. package/src/lib/utils/richText.ts +0 -72
@@ -1,252 +0,0 @@
1
- import { atom, Atom, EMPTY_ARRAY, transact } from '@tldraw/state'
2
- import { TLShape, TLShapeId } from '@tldraw/tlschema'
3
- import {
4
- areArraysShallowEqual,
5
- compact,
6
- FileHelpers,
7
- mapObjectMapValues,
8
- objectMapEntries,
9
- } from '@tldraw/utils'
10
- import { Editor } from '../Editor'
11
-
12
- /**
13
- * Represents the `src` property of a {@link TLFontFace}.
14
- * See {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/src | `src`} for details of the properties here.
15
- * @public
16
- */
17
- export interface TLFontFaceSource {
18
- /**
19
- * A URL from which to load the font. If the value here is a key in
20
- * {@link tldraw#TLEditorAssetUrls.fonts}, the value from there will be used instead.
21
- */
22
- url: string
23
- format?: string
24
- tech?: string
25
- }
26
-
27
- /**
28
- * A font face that can be used in the editor. The properties of this are largely the same as the
29
- * ones in the
30
- * {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face | css `@font-face` rule}.
31
- * @public
32
- */
33
- export interface TLFontFace {
34
- /**
35
- * How this font can be referred to in CSS.
36
- * See {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-family | `font-family`}.
37
- */
38
- readonly family: string
39
- /**
40
- * The source of the font. This
41
- * See {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/src | `src`}.
42
- */
43
- readonly src: TLFontFaceSource
44
- /**
45
- * See {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/ascent-override | `ascent-override`}.
46
- */
47
- readonly ascentOverride?: string
48
- /**
49
- * See {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/descent-override | `descent-override`}.
50
- */
51
- readonly descentOverride?: string
52
- /**
53
- * See {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-stretch | `font-stretch`}.
54
- */
55
- readonly stretch?: string
56
- /**
57
- * See {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-style | `font-style`}.
58
- */
59
- readonly style?: string
60
- /**
61
- * See {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-weight | `font-weight`}.
62
- */
63
- readonly weight?: string
64
- /**
65
- * See {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-feature-settings | `font-feature-settings`}.
66
- */
67
- readonly featureSettings?: string
68
- /**
69
- * See {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/line-gap-override | `line-gap-override`}.
70
- */
71
- readonly lineGapOverride?: string
72
- /**
73
- * See {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/unicode-range | `unicode-range`}.
74
- */
75
- readonly unicodeRange?: string
76
- }
77
-
78
- interface FontState {
79
- readonly state: 'loading' | 'ready' | 'error'
80
- readonly instance: FontFace
81
- readonly loadingPromise: Promise<void>
82
- }
83
-
84
- /** @public */
85
- export class FontManager {
86
- constructor(
87
- private readonly editor: Editor,
88
- private readonly assetUrls?: { [key: string]: string | undefined }
89
- ) {
90
- this.shapeFontFacesCache = editor.store.createComputedCache(
91
- 'shape font faces',
92
- (shape: TLShape) => {
93
- const shapeUtil = this.editor.getShapeUtil(shape)
94
- return shapeUtil.getFontFaces(shape)
95
- },
96
- { areResultsEqual: areArraysShallowEqual }
97
- )
98
-
99
- this.shapeFontLoadStateCache = editor.store.createComputedCache(
100
- 'shape font load state',
101
- (shape: TLShape) => {
102
- const states = this.getShapeFontFaces(shape).map((face) => this.getFontState(face))
103
- return states
104
- },
105
- { areResultsEqual: areArraysShallowEqual }
106
- )
107
- }
108
-
109
- private readonly shapeFontFacesCache
110
- private readonly shapeFontLoadStateCache
111
-
112
- getShapeFontFaces(shape: TLShape | TLShapeId): TLFontFace[] {
113
- const shapeId = typeof shape === 'string' ? shape : shape.id
114
- return this.shapeFontFacesCache.get(shapeId) ?? EMPTY_ARRAY
115
- }
116
-
117
- trackFontsForShape(shape: TLShape | TLShapeId) {
118
- const shapeId = typeof shape === 'string' ? shape : shape.id
119
- this.shapeFontLoadStateCache.get(shapeId)
120
- }
121
-
122
- async loadRequiredFontsForCurrentPage(limit = Infinity) {
123
- const neededFonts = new Set<TLFontFace>()
124
- for (const shapeId of this.editor.getCurrentPageShapeIds()) {
125
- for (const font of this.getShapeFontFaces(this.editor.getShape(shapeId)!)) {
126
- neededFonts.add(font)
127
- }
128
- }
129
-
130
- if (neededFonts.size > limit) {
131
- return
132
- }
133
-
134
- const promises = Array.from(neededFonts, (font) => this.ensureFontIsLoaded(font))
135
- await Promise.all(promises)
136
- }
137
-
138
- private readonly fontStates = atom<ReadonlyMap<TLFontFace, Atom<FontState>>>(
139
- 'font states',
140
- new Map()
141
- )
142
- private getFontState(font: TLFontFace): FontState | null {
143
- return this.fontStates.get().get(font)?.get() ?? null
144
- }
145
-
146
- ensureFontIsLoaded(font: TLFontFace): Promise<void> {
147
- const state = this.getFontState(font)
148
- if (state) return state.loadingPromise
149
-
150
- const instance = this.findOrCreateFontFace(font)
151
- const stateAtom = atom<FontState>('font state', {
152
- state: 'loading',
153
- instance,
154
- loadingPromise: instance
155
- .load()
156
- .then(() => {
157
- document.fonts.add(instance)
158
- stateAtom.update((s) => ({ ...s, state: 'ready' }))
159
- })
160
- .catch((err) => {
161
- console.error(err)
162
- stateAtom.update((s) => ({ ...s, state: 'error' }))
163
- }),
164
- })
165
- this.fontStates.update((map) => {
166
- const newMap = new Map(map)
167
- newMap.set(font, stateAtom)
168
- return newMap
169
- })
170
-
171
- return stateAtom.get().loadingPromise
172
- }
173
-
174
- private fontsToLoad = new Set<TLFontFace>()
175
- requestFonts(fonts: TLFontFace[]) {
176
- if (!this.fontsToLoad.size) {
177
- queueMicrotask(() => {
178
- if (this.editor.isDisposed) return
179
- const toLoad = this.fontsToLoad
180
- this.fontsToLoad = new Set()
181
- transact(() => {
182
- for (const font of toLoad) {
183
- this.ensureFontIsLoaded(font)
184
- }
185
- })
186
- })
187
- }
188
- for (const font of fonts) {
189
- this.fontsToLoad.add(font)
190
- }
191
- }
192
-
193
- private findOrCreateFontFace(font: TLFontFace) {
194
- for (const existing of document.fonts) {
195
- if (
196
- existing.family === font.family &&
197
- objectMapEntries(defaultFontFaceDescriptors).every(
198
- ([key, defaultValue]) => existing[key] === (font[key] ?? defaultValue)
199
- )
200
- ) {
201
- return existing
202
- }
203
- }
204
-
205
- const url = this.assetUrls?.[font.src.url] ?? font.src.url
206
- const instance = new FontFace(font.family, `url(${JSON.stringify(url)})`, {
207
- ...mapObjectMapValues(defaultFontFaceDescriptors, (key) => font[key]),
208
- display: 'swap',
209
- })
210
-
211
- document.fonts.add(instance)
212
-
213
- return instance
214
- }
215
-
216
- async toEmbeddedCssDeclaration(font: TLFontFace) {
217
- const url = this.assetUrls?.[font.src.url] ?? font.src.url
218
- const dataUrl = await FileHelpers.urlToDataUrl(url)
219
-
220
- const src = compact([
221
- `url("${dataUrl}")`,
222
- font.src.format ? `format(${font.src.format})` : null,
223
- font.src.tech ? `tech(${font.src.tech})` : null,
224
- ]).join(' ')
225
- return compact([
226
- `@font-face {`,
227
- ` font-family: ${font.family};`,
228
- ` src: ${src};`,
229
- font.ascentOverride ? ` ascent-override: ${font.ascentOverride};` : null,
230
- font.descentOverride ? ` descent-override: ${font.descentOverride};` : null,
231
- font.stretch ? ` font-stretch: ${font.stretch};` : null,
232
- font.style ? ` font-style: ${font.style};` : null,
233
- font.weight ? ` font-weight: ${font.weight};` : null,
234
- font.featureSettings ? ` font-feature-settings: ${font.featureSettings};` : null,
235
- font.lineGapOverride ? ` line-gap-override: ${font.lineGapOverride};` : null,
236
- font.unicodeRange ? ` unicode-range: ${font.unicodeRange};` : null,
237
- `}`,
238
- ]).join('\n')
239
- }
240
- }
241
-
242
- // From https://drafts.csswg.org/css-font-loading/#fontface-interface
243
- const defaultFontFaceDescriptors = {
244
- style: 'normal',
245
- weight: 'normal',
246
- stretch: 'normal',
247
- unicodeRange: 'U+0-10FFFF',
248
- featureSettings: 'normal',
249
- ascentOverride: 'normal',
250
- descentOverride: 'normal',
251
- lineGapOverride: 'normal',
252
- }
@@ -1,29 +0,0 @@
1
- import { RefObject, useEffect } from 'react'
2
- import { preventDefault } from '../utils/dom'
3
- import { useContainer } from './useContainer'
4
-
5
- /** @public */
6
- export function usePassThroughMouseOverEvents(ref: RefObject<HTMLElement>) {
7
- if (!ref) throw Error('usePassThroughWheelEvents must be passed a ref')
8
- const container = useContainer()
9
-
10
- useEffect(() => {
11
- function onMouseOver(e: MouseEvent) {
12
- if ((e as any).isSpecialRedispatchedEvent) return
13
- preventDefault(e)
14
- const cvs = container.querySelector('.tl-canvas')
15
- if (!cvs) return
16
- const newEvent = new PointerEvent(e.type, e as any)
17
- ;(newEvent as any).isSpecialRedispatchedEvent = true
18
- cvs.dispatchEvent(newEvent)
19
- }
20
-
21
- const elm = ref.current
22
- if (!elm) return
23
-
24
- elm.addEventListener('mouseover', onMouseOver, { passive: false })
25
- return () => {
26
- elm.removeEventListener('mouseover', onMouseOver)
27
- }
28
- }, [container, ref])
29
- }
@@ -1,37 +0,0 @@
1
- import { useLayoutEffect, useState } from 'react'
2
-
3
- /*!
4
- * BSD License: https://github.com/outline/rich-markdown-editor/blob/main/LICENSE
5
- * Copyright (c) 2020 General Outline, Inc (https://www.getoutline.com/) and individual contributors.
6
- *
7
- * Returns the height of the viewport.
8
- * This is mainly to account for virtual keyboards on mobile devices.
9
- *
10
- * N.B. On iOS, you have to take into account the offsetTop as well so that you get an accurate position
11
- * while using the virtual keyboard.
12
- */
13
- /** @public */
14
- export function useViewportHeight(): number {
15
- const visualViewport = window.visualViewport
16
- const [height, setHeight] = useState<number>(() =>
17
- visualViewport ? visualViewport.height + visualViewport.offsetTop : window.innerHeight
18
- )
19
-
20
- useLayoutEffect(() => {
21
- const handleResize = () => {
22
- const visualViewport = window.visualViewport
23
- setHeight(() =>
24
- visualViewport ? visualViewport.height + visualViewport.offsetTop : window.innerHeight
25
- )
26
- }
27
-
28
- window.visualViewport?.addEventListener('resize', handleResize)
29
- window.visualViewport?.addEventListener('scroll', handleResize)
30
-
31
- return () => {
32
- window.visualViewport?.removeEventListener('resize', handleResize)
33
- window.visualViewport?.removeEventListener('scroll', handleResize)
34
- }
35
- }, [])
36
- return height
37
- }
@@ -1,72 +0,0 @@
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
- }