@tldraw/editor 3.9.0 → 3.10.0-canary.12c0cb0549ca
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 +243 -5
- package/dist-cjs/index.js +9 -1
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/lib/TldrawEditor.js +32 -6
- package/dist-cjs/lib/TldrawEditor.js.map +2 -2
- package/dist-cjs/lib/components/LiveCollaborators.js +5 -0
- package/dist-cjs/lib/components/LiveCollaborators.js.map +2 -2
- package/dist-cjs/lib/components/Shape.js +7 -0
- package/dist-cjs/lib/components/Shape.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultBrush.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultCollaboratorHint.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultCursor.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultScribble.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultShapeIndicator.js.map +2 -2
- package/dist-cjs/lib/editor/Editor.js +69 -14
- package/dist-cjs/lib/editor/Editor.js.map +2 -2
- package/dist-cjs/lib/editor/managers/FontManager.js +166 -0
- package/dist-cjs/lib/editor/managers/FontManager.js.map +7 -0
- package/dist-cjs/lib/editor/managers/TextManager.js +23 -17
- package/dist-cjs/lib/editor/managers/TextManager.js.map +2 -2
- package/dist-cjs/lib/editor/shapes/ShapeUtil.js +11 -0
- package/dist-cjs/lib/editor/shapes/ShapeUtil.js.map +2 -2
- package/dist-cjs/lib/editor/types/emit-types.js.map +1 -1
- package/dist-cjs/lib/editor/types/external-content.js.map +1 -1
- package/dist-cjs/lib/exports/FontEmbedder.js +7 -2
- package/dist-cjs/lib/exports/FontEmbedder.js.map +2 -2
- package/dist-cjs/lib/exports/StyleEmbedder.js +1 -1
- package/dist-cjs/lib/exports/StyleEmbedder.js.map +2 -2
- package/dist-cjs/lib/exports/exportToSvg.js +3 -2
- package/dist-cjs/lib/exports/exportToSvg.js.map +2 -2
- package/dist-cjs/lib/exports/getSvgJsx.js +18 -1
- package/dist-cjs/lib/exports/getSvgJsx.js.map +2 -2
- package/dist-cjs/lib/exports/parseCss.js +1 -0
- package/dist-cjs/lib/exports/parseCss.js.map +2 -2
- package/dist-cjs/lib/hooks/useCanvasEvents.js +2 -2
- package/dist-cjs/lib/hooks/useCanvasEvents.js.map +2 -2
- package/dist-cjs/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.js +1 -1
- package/dist-cjs/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.js.map +2 -2
- package/dist-cjs/lib/hooks/usePassThroughMouseOverEvents.js +48 -0
- package/dist-cjs/lib/hooks/usePassThroughMouseOverEvents.js.map +7 -0
- package/dist-cjs/lib/hooks/usePassThroughWheelEvents.js.map +2 -2
- package/dist-cjs/lib/hooks/usePeerIds.js.map +1 -1
- package/dist-cjs/lib/hooks/usePresence.js.map +1 -1
- package/dist-cjs/lib/hooks/useViewportHeight.js +56 -0
- package/dist-cjs/lib/hooks/useViewportHeight.js.map +7 -0
- package/dist-cjs/lib/options.js +2 -1
- package/dist-cjs/lib/options.js.map +2 -2
- package/dist-cjs/lib/utils/browserCanvasMaxSize.js +5 -0
- package/dist-cjs/lib/utils/browserCanvasMaxSize.js.map +2 -2
- package/dist-cjs/lib/utils/dom.js +1 -1
- package/dist-cjs/lib/utils/dom.js.map +2 -2
- package/dist-cjs/lib/utils/richText.js +46 -0
- package/dist-cjs/lib/utils/richText.js.map +7 -0
- package/dist-cjs/version.js +3 -3
- package/dist-cjs/version.js.map +1 -1
- package/dist-esm/index.d.mts +243 -5
- package/dist-esm/index.mjs +13 -1
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/lib/TldrawEditor.mjs +33 -7
- package/dist-esm/lib/TldrawEditor.mjs.map +2 -2
- package/dist-esm/lib/components/LiveCollaborators.mjs +5 -0
- package/dist-esm/lib/components/LiveCollaborators.mjs.map +2 -2
- package/dist-esm/lib/components/Shape.mjs +8 -1
- package/dist-esm/lib/components/Shape.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultBrush.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultCollaboratorHint.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultCursor.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultScribble.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultShapeIndicator.mjs.map +2 -2
- package/dist-esm/lib/editor/Editor.mjs +72 -10
- package/dist-esm/lib/editor/Editor.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/FontManager.mjs +152 -0
- package/dist-esm/lib/editor/managers/FontManager.mjs.map +7 -0
- package/dist-esm/lib/editor/managers/TextManager.mjs +23 -17
- package/dist-esm/lib/editor/managers/TextManager.mjs.map +2 -2
- package/dist-esm/lib/editor/shapes/ShapeUtil.mjs +11 -0
- package/dist-esm/lib/editor/shapes/ShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/exports/FontEmbedder.mjs +7 -2
- package/dist-esm/lib/exports/FontEmbedder.mjs.map +2 -2
- package/dist-esm/lib/exports/StyleEmbedder.mjs +1 -1
- package/dist-esm/lib/exports/StyleEmbedder.mjs.map +2 -2
- package/dist-esm/lib/exports/exportToSvg.mjs +3 -2
- package/dist-esm/lib/exports/exportToSvg.mjs.map +2 -2
- package/dist-esm/lib/exports/getSvgJsx.mjs +19 -2
- package/dist-esm/lib/exports/getSvgJsx.mjs.map +2 -2
- package/dist-esm/lib/exports/parseCss.mjs +1 -0
- package/dist-esm/lib/exports/parseCss.mjs.map +2 -2
- package/dist-esm/lib/hooks/useCanvasEvents.mjs +2 -2
- package/dist-esm/lib/hooks/useCanvasEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.mjs +1 -1
- package/dist-esm/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/usePassThroughMouseOverEvents.mjs +28 -0
- package/dist-esm/lib/hooks/usePassThroughMouseOverEvents.mjs.map +7 -0
- package/dist-esm/lib/hooks/usePassThroughWheelEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/usePeerIds.mjs.map +1 -1
- package/dist-esm/lib/hooks/usePresence.mjs.map +1 -1
- package/dist-esm/lib/hooks/useViewportHeight.mjs +36 -0
- package/dist-esm/lib/hooks/useViewportHeight.mjs.map +7 -0
- package/dist-esm/lib/options.mjs +2 -1
- package/dist-esm/lib/options.mjs.map +2 -2
- package/dist-esm/lib/utils/browserCanvasMaxSize.mjs +5 -0
- package/dist-esm/lib/utils/browserCanvasMaxSize.mjs.map +2 -2
- package/dist-esm/lib/utils/dom.mjs +1 -1
- package/dist-esm/lib/utils/dom.mjs.map +2 -2
- package/dist-esm/lib/utils/richText.mjs +26 -0
- package/dist-esm/lib/utils/richText.mjs.map +7 -0
- package/dist-esm/version.mjs +3 -3
- package/dist-esm/version.mjs.map +1 -1
- package/editor.css +127 -13
- package/package.json +10 -7
- package/src/index.ts +15 -0
- package/src/lib/TldrawEditor.tsx +52 -4
- package/src/lib/components/LiveCollaborators.tsx +5 -0
- package/src/lib/components/Shape.tsx +9 -1
- package/src/lib/components/default-components/DefaultBrush.tsx +1 -0
- package/src/lib/components/default-components/DefaultCollaboratorHint.tsx +1 -0
- package/src/lib/components/default-components/DefaultCursor.tsx +1 -0
- package/src/lib/components/default-components/DefaultScribble.tsx +1 -0
- package/src/lib/components/default-components/DefaultShapeIndicator.tsx +1 -0
- package/src/lib/editor/Editor.ts +92 -8
- package/src/lib/editor/managers/FontManager.ts +251 -0
- package/src/lib/editor/managers/TextManager.ts +42 -17
- package/src/lib/editor/shapes/ShapeUtil.ts +13 -0
- package/src/lib/editor/types/emit-types.ts +1 -0
- package/src/lib/editor/types/external-content.ts +1 -0
- package/src/lib/exports/FontEmbedder.ts +13 -1
- package/src/lib/exports/StyleEmbedder.ts +1 -1
- package/src/lib/exports/exportToSvg.tsx +4 -3
- package/src/lib/exports/getSvgJsx.tsx +22 -2
- package/src/lib/exports/parseCss.ts +1 -0
- package/src/lib/hooks/useCanvasEvents.ts +2 -1
- package/src/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.ts +1 -0
- package/src/lib/hooks/usePassThroughMouseOverEvents.ts +29 -0
- package/src/lib/hooks/usePassThroughWheelEvents.ts +0 -1
- package/src/lib/hooks/usePeerIds.ts +1 -1
- package/src/lib/hooks/usePresence.ts +2 -2
- package/src/lib/hooks/useViewportHeight.ts +37 -0
- package/src/lib/options.ts +7 -0
- package/src/lib/utils/browserCanvasMaxSize.ts +5 -3
- package/src/lib/utils/dom.ts +1 -1
- package/src/lib/utils/richText.ts +72 -0
- package/src/version.ts +3 -3
|
@@ -2,6 +2,8 @@ import { assert, bind, compact } from '@tldraw/utils'
|
|
|
2
2
|
import { fetchCache, resourceToDataUrl } from './fetchCache'
|
|
3
3
|
import { ParsedFontFace, parseCss, parseCssFontFaces, parseCssFontFamilyValue } from './parseCss'
|
|
4
4
|
|
|
5
|
+
export const SVG_EXPORT_CLASSNAME = 'tldraw-svg-export'
|
|
6
|
+
|
|
5
7
|
/**
|
|
6
8
|
* Because SVGs cannot refer to external CSS/font resources, any web fonts used in the SVG must be
|
|
7
9
|
* embedded as data URLs in inlined @font-face declarations. This class is responsible for
|
|
@@ -81,7 +83,17 @@ export class FontEmbedder {
|
|
|
81
83
|
async function getCurrentDocumentFontFaces() {
|
|
82
84
|
const fontFaces: (ParsedFontFace[] | Promise<ParsedFontFace[] | null>)[] = []
|
|
83
85
|
|
|
84
|
-
|
|
86
|
+
// In exportToSvg we add the exported node to the DOM temporarily.
|
|
87
|
+
// Because of this, and because we do a setTimeout to delay removing that node from the
|
|
88
|
+
// DOM, when looking at document.styleSheets the number of nodes and stylesheets
|
|
89
|
+
// can grow unbounded (especially when using "Debug svg" and moving shapes around).
|
|
90
|
+
// To avoid this, we filter out the stylesheets that are part of the SVG export.
|
|
91
|
+
const styleSheetsWithoutSvgExports = Array.from(document.styleSheets).filter(
|
|
92
|
+
(styleSheet) =>
|
|
93
|
+
!(styleSheet.ownerNode as HTMLElement | null)?.closest(`.${SVG_EXPORT_CLASSNAME}`)
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
for (const styleSheet of styleSheetsWithoutSvgExports) {
|
|
85
97
|
let cssRules
|
|
86
98
|
try {
|
|
87
99
|
cssRules = styleSheet.cssRules
|
|
@@ -242,7 +242,7 @@ function styleFromComputedStyle(
|
|
|
242
242
|
{ defaultStyles, parentStyles }: ReadStyleOpts
|
|
243
243
|
) {
|
|
244
244
|
const styles: Record<string, string> = {}
|
|
245
|
-
for (const property of style) {
|
|
245
|
+
for (const [property, _] of Object.entries(style)) {
|
|
246
246
|
if (!shouldIncludeCssProperty(property)) continue
|
|
247
247
|
|
|
248
248
|
const value = style.getPropertyValue(property)
|
|
@@ -4,6 +4,7 @@ import { flushSync } from 'react-dom'
|
|
|
4
4
|
import { createRoot } from 'react-dom/client'
|
|
5
5
|
import { Editor } from '../editor/Editor'
|
|
6
6
|
import { TLSvgExportOptions } from '../editor/types/misc-types'
|
|
7
|
+
import { SVG_EXPORT_CLASSNAME } from './FontEmbedder'
|
|
7
8
|
import { StyleEmbedder } from './StyleEmbedder'
|
|
8
9
|
import { embedMedia } from './embedMedia'
|
|
9
10
|
import { getSvgJsx } from './getSvgJsx'
|
|
@@ -26,7 +27,7 @@ export async function exportToSvg(
|
|
|
26
27
|
// <foreignObject> elements have their styles and content inlined correctly.
|
|
27
28
|
const container = editor.getContainer()
|
|
28
29
|
const renderTarget = document.createElement('div')
|
|
29
|
-
renderTarget.className =
|
|
30
|
+
renderTarget.className = SVG_EXPORT_CLASSNAME
|
|
30
31
|
// we hide the element visually, but we don't want it to be focusable or interactive in any way either
|
|
31
32
|
renderTarget.inert = true
|
|
32
33
|
renderTarget.tabIndex = -1
|
|
@@ -83,9 +84,9 @@ export async function exportToSvg(
|
|
|
83
84
|
|
|
84
85
|
async function applyChangesToForeignObjects(svg: SVGSVGElement) {
|
|
85
86
|
// If any shapes have their own <foreignObject> elements, we don't want to mess with them. Our
|
|
86
|
-
// ones that we need to embed will have a class of `tl-
|
|
87
|
+
// ones that we need to embed will have a class of `tl-export-embed-styles`.
|
|
87
88
|
const foreignObjectChildren = [
|
|
88
|
-
...svg.querySelectorAll('foreignObject.tl-
|
|
89
|
+
...svg.querySelectorAll('foreignObject.tl-export-embed-styles > *'),
|
|
89
90
|
]
|
|
90
91
|
if (!foreignObjectChildren.length) return
|
|
91
92
|
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
TLShapeId,
|
|
7
7
|
getDefaultColorTheme,
|
|
8
8
|
} from '@tldraw/tlschema'
|
|
9
|
-
import { hasOwnProperty, promiseWithResolve } from '@tldraw/utils'
|
|
9
|
+
import { hasOwnProperty, promiseWithResolve, uniqueId } from '@tldraw/utils'
|
|
10
10
|
import {
|
|
11
11
|
ComponentType,
|
|
12
12
|
Fragment,
|
|
@@ -21,6 +21,7 @@ import { flushSync } from 'react-dom'
|
|
|
21
21
|
import { ErrorBoundary } from '../components/ErrorBoundary'
|
|
22
22
|
import { InnerShape, InnerShapeBackground } from '../components/Shape'
|
|
23
23
|
import { Editor, TLRenderingShape } from '../editor/Editor'
|
|
24
|
+
import { TLFontFace } from '../editor/managers/FontManager'
|
|
24
25
|
import { ShapeUtil } from '../editor/shapes/ShapeUtil'
|
|
25
26
|
import {
|
|
26
27
|
SvgExportContext,
|
|
@@ -340,6 +341,25 @@ function SvgExport({
|
|
|
340
341
|
})()
|
|
341
342
|
}, [bbox, editor, exportContext, masksId, renderingShapes, singleFrameShapeId, stateAtom])
|
|
342
343
|
|
|
344
|
+
useEffect(() => {
|
|
345
|
+
const fontsInUse = new Set<TLFontFace>()
|
|
346
|
+
for (const { id } of renderingShapes) {
|
|
347
|
+
for (const font of editor.fonts.getShapeFontFaces(id)) {
|
|
348
|
+
fontsInUse.add(font)
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
for (const font of fontsInUse) {
|
|
353
|
+
addExportDef({
|
|
354
|
+
key: uniqueId(),
|
|
355
|
+
getElement: async () => {
|
|
356
|
+
const declaration = await editor.fonts.toEmbeddedCssDeclaration(font)
|
|
357
|
+
return <style>{declaration}</style>
|
|
358
|
+
},
|
|
359
|
+
})
|
|
360
|
+
}
|
|
361
|
+
}, [editor, renderingShapes, addExportDef])
|
|
362
|
+
|
|
343
363
|
useEffect(() => {
|
|
344
364
|
if (shapeElements === null) return
|
|
345
365
|
onMount()
|
|
@@ -408,7 +428,7 @@ function ForeignObjectShape({
|
|
|
408
428
|
y={bbox.minY}
|
|
409
429
|
width={bbox.w}
|
|
410
430
|
height={bbox.h}
|
|
411
|
-
className="tl-shape-foreign-object"
|
|
431
|
+
className="tl-shape-foreign-object tl-export-embed-styles"
|
|
412
432
|
>
|
|
413
433
|
<div
|
|
414
434
|
className={className}
|
|
@@ -100,8 +100,9 @@ export function useCanvasEvents() {
|
|
|
100
100
|
if (
|
|
101
101
|
e.target.tagName !== 'A' &&
|
|
102
102
|
e.target.tagName !== 'TEXTAREA' &&
|
|
103
|
+
e.target.isContentEditable &&
|
|
103
104
|
// When in EditingShape state, we are actually clicking on a 'DIV'
|
|
104
|
-
// not A/TEXTAREA element yet. So, to preserve cursor position
|
|
105
|
+
// not A/TEXTAREA/contenteditable element yet. So, to preserve cursor position
|
|
105
106
|
// for edit mode on mobile we need to not preventDefault.
|
|
106
107
|
// TODO: Find out if we still need this preventDefault in general though.
|
|
107
108
|
!(editor.getEditingShape() && e.target.className.includes('tl-text-content'))
|
|
@@ -25,6 +25,7 @@ export function useFixSafariDoubleTapZoomPencilEvents(ref: React.RefObject<HTMLE
|
|
|
25
25
|
// Allow events to propagate if the app is editing a shape, or if the event is occurring in a text area or input
|
|
26
26
|
if (
|
|
27
27
|
IGNORED_TAGS.includes((target as Element).tagName?.toLocaleLowerCase()) ||
|
|
28
|
+
(target as HTMLElement).isContentEditable ||
|
|
28
29
|
editor.isIn('select.editing_shape')
|
|
29
30
|
) {
|
|
30
31
|
return
|
|
@@ -0,0 +1,29 @@
|
|
|
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
|
+
}
|
|
@@ -5,7 +5,6 @@ import { useContainer } from './useContainer'
|
|
|
5
5
|
/** @public */
|
|
6
6
|
export function usePassThroughWheelEvents(ref: RefObject<HTMLElement>) {
|
|
7
7
|
if (!ref) throw Error('usePassThroughWheelEvents must be passed a ref')
|
|
8
|
-
|
|
9
8
|
const container = useContainer()
|
|
10
9
|
|
|
11
10
|
useEffect(() => {
|
|
@@ -4,8 +4,8 @@ import { useEditor } from './useEditor'
|
|
|
4
4
|
|
|
5
5
|
// TODO: maybe move this to a computed property on the App class?
|
|
6
6
|
/**
|
|
7
|
-
* @returns The
|
|
8
|
-
* @
|
|
7
|
+
* @returns The latest presence of the user matching userId
|
|
8
|
+
* @public
|
|
9
9
|
*/
|
|
10
10
|
export function usePresence(userId: string): TLInstancePresence | null {
|
|
11
11
|
const editor = useEditor()
|
|
@@ -0,0 +1,37 @@
|
|
|
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
|
+
}
|
package/src/lib/options.ts
CHANGED
|
@@ -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
|
|
@@ -19,9 +19,11 @@ function getBrowserCanvasMaxSize(): CanvasMaxSize {
|
|
|
19
19
|
return maxCanvasSizes
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
/*!
|
|
23
|
+
* Extracted from https://github.com/jhildenbiddle/canvas-size
|
|
24
|
+
* MIT License: https://github.com/jhildenbiddle/canvas-size/blob/master/LICENSE
|
|
25
|
+
* Copyright (c) John Hildenbiddle
|
|
26
|
+
*/
|
|
25
27
|
|
|
26
28
|
const MAX_SAFE_CANVAS_DIMENSION = 8192
|
|
27
29
|
const MAX_SAFE_CANVAS_AREA = 4096 * 4096
|
package/src/lib/utils/dom.ts
CHANGED
|
@@ -98,7 +98,7 @@ export function activeElementShouldCaptureKeys() {
|
|
|
98
98
|
const { activeElement } = document
|
|
99
99
|
return !!(
|
|
100
100
|
activeElement &&
|
|
101
|
-
(activeElement.
|
|
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.
|
|
4
|
+
export const version = '3.10.0-canary.12c0cb0549ca'
|
|
5
5
|
export const publishDates = {
|
|
6
6
|
major: '2024-09-13T14:36:29.063Z',
|
|
7
|
-
minor: '2025-03-
|
|
8
|
-
patch: '2025-03-
|
|
7
|
+
minor: '2025-03-06T09:01:02.970Z',
|
|
8
|
+
patch: '2025-03-06T09:01:02.970Z',
|
|
9
9
|
}
|