@tldraw/editor 4.5.3 → 4.6.0-canary.0bcbb3ed5bcb
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 +37 -6
- package/dist-cjs/index.js +6 -1
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/lib/TldrawEditor.js +7 -5
- package/dist-cjs/lib/TldrawEditor.js.map +3 -3
- package/dist-cjs/lib/components/default-components/CanvasShapeIndicators.js +3 -2
- package/dist-cjs/lib/components/default-components/CanvasShapeIndicators.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultCanvas.js +1 -1
- package/dist-cjs/lib/components/default-components/DefaultCanvas.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultErrorFallback.js +8 -5
- package/dist-cjs/lib/components/default-components/DefaultErrorFallback.js.map +2 -2
- package/dist-cjs/lib/config/TLSessionStateSnapshot.js +8 -5
- package/dist-cjs/lib/config/TLSessionStateSnapshot.js.map +2 -2
- package/dist-cjs/lib/config/TLUserPreferences.js +3 -2
- package/dist-cjs/lib/config/TLUserPreferences.js.map +2 -2
- package/dist-cjs/lib/config/createTLStore.js +1 -0
- package/dist-cjs/lib/config/createTLStore.js.map +2 -2
- package/dist-cjs/lib/editor/Editor.js +52 -16
- package/dist-cjs/lib/editor/Editor.js.map +2 -2
- package/dist-cjs/lib/editor/managers/FocusManager/FocusManager.js +62 -6
- package/dist-cjs/lib/editor/managers/FocusManager/FocusManager.js.map +2 -2
- package/dist-cjs/lib/editor/managers/FontManager/FontManager.js +4 -3
- package/dist-cjs/lib/editor/managers/FontManager/FontManager.js.map +2 -2
- package/dist-cjs/lib/editor/managers/HistoryManager/HistoryManager.js +5 -0
- package/dist-cjs/lib/editor/managers/HistoryManager/HistoryManager.js.map +2 -2
- package/dist-cjs/lib/editor/managers/TextManager/TextManager.js +2 -2
- package/dist-cjs/lib/editor/managers/TextManager/TextManager.js.map +2 -2
- package/dist-cjs/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.js +3 -2
- package/dist-cjs/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.js.map +2 -2
- package/dist-cjs/lib/editor/types/misc-types.js.map +1 -1
- package/dist-cjs/lib/exports/FontEmbedder.js +9 -8
- package/dist-cjs/lib/exports/FontEmbedder.js.map +2 -2
- package/dist-cjs/lib/exports/StyleEmbedder.js +27 -15
- package/dist-cjs/lib/exports/StyleEmbedder.js.map +3 -3
- package/dist-cjs/lib/exports/domUtils.js +15 -0
- package/dist-cjs/lib/exports/domUtils.js.map +2 -2
- package/dist-cjs/lib/exports/embedMedia.js +15 -12
- package/dist-cjs/lib/exports/embedMedia.js.map +2 -2
- package/dist-cjs/lib/exports/exportToSvg.js +8 -7
- package/dist-cjs/lib/exports/exportToSvg.js.map +2 -2
- package/dist-cjs/lib/exports/getSvgAsImage.js +181 -29
- package/dist-cjs/lib/exports/getSvgAsImage.js.map +3 -3
- package/dist-cjs/lib/exports/getSvgJsx.js +21 -9
- package/dist-cjs/lib/exports/getSvgJsx.js.map +2 -2
- package/dist-cjs/lib/globals/environment.js +4 -3
- package/dist-cjs/lib/globals/environment.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/useDocumentEvents.js +13 -11
- package/dist-cjs/lib/hooks/useDocumentEvents.js.map +2 -2
- package/dist-cjs/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.js +3 -2
- package/dist-cjs/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.js.map +2 -2
- package/dist-cjs/lib/hooks/useScreenBounds.js +10 -6
- package/dist-cjs/lib/hooks/useScreenBounds.js.map +2 -2
- package/dist-cjs/lib/hooks/useViewportHeight.js +13 -11
- package/dist-cjs/lib/hooks/useViewportHeight.js.map +3 -3
- package/dist-cjs/lib/license/Watermark.js +10 -0
- package/dist-cjs/lib/license/Watermark.js.map +2 -2
- package/dist-cjs/lib/primitives/Vec.js +35 -22
- package/dist-cjs/lib/primitives/Vec.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Arc2d.js +6 -13
- package/dist-cjs/lib/primitives/geometry/Arc2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Circle2d.js +31 -2
- package/dist-cjs/lib/primitives/geometry/Circle2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/CubicBezier2d.js +9 -0
- package/dist-cjs/lib/primitives/geometry/CubicBezier2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/CubicSpline2d.js +9 -0
- package/dist-cjs/lib/primitives/geometry/CubicSpline2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Edge2d.js +32 -18
- package/dist-cjs/lib/primitives/geometry/Edge2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Ellipse2d.js +12 -0
- package/dist-cjs/lib/primitives/geometry/Ellipse2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Polyline2d.js +51 -12
- package/dist-cjs/lib/primitives/geometry/Polyline2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Stadium2d.js +12 -0
- package/dist-cjs/lib/primitives/geometry/Stadium2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/geometry.bench.js +133 -0
- package/dist-cjs/lib/primitives/geometry/geometry.bench.js.map +7 -0
- package/dist-cjs/lib/primitives/intersect.js +16 -15
- package/dist-cjs/lib/primitives/intersect.js.map +2 -2
- package/dist-cjs/lib/primitives/utils.js +0 -1
- package/dist-cjs/lib/primitives/utils.js.map +2 -2
- package/dist-cjs/lib/utils/browserCanvasMaxSize.js +3 -2
- package/dist-cjs/lib/utils/browserCanvasMaxSize.js.map +2 -2
- package/dist-cjs/lib/utils/dom.js +15 -2
- package/dist-cjs/lib/utils/dom.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 +37 -6
- package/dist-esm/index.mjs +8 -1
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/lib/TldrawEditor.mjs +7 -5
- package/dist-esm/lib/TldrawEditor.mjs.map +3 -3
- package/dist-esm/lib/components/default-components/CanvasShapeIndicators.mjs +2 -1
- package/dist-esm/lib/components/default-components/CanvasShapeIndicators.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultCanvas.mjs +1 -1
- package/dist-esm/lib/components/default-components/DefaultCanvas.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultErrorFallback.mjs +8 -5
- package/dist-esm/lib/components/default-components/DefaultErrorFallback.mjs.map +2 -2
- package/dist-esm/lib/config/TLSessionStateSnapshot.mjs +8 -5
- package/dist-esm/lib/config/TLSessionStateSnapshot.mjs.map +2 -2
- package/dist-esm/lib/config/TLUserPreferences.mjs +3 -2
- package/dist-esm/lib/config/TLUserPreferences.mjs.map +2 -2
- package/dist-esm/lib/config/createTLStore.mjs +1 -0
- package/dist-esm/lib/config/createTLStore.mjs.map +2 -2
- package/dist-esm/lib/editor/Editor.mjs +53 -17
- package/dist-esm/lib/editor/Editor.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/FocusManager/FocusManager.mjs +64 -6
- package/dist-esm/lib/editor/managers/FocusManager/FocusManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/FontManager/FontManager.mjs +4 -3
- package/dist-esm/lib/editor/managers/FontManager/FontManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/HistoryManager/HistoryManager.mjs +5 -0
- package/dist-esm/lib/editor/managers/HistoryManager/HistoryManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/TextManager/TextManager.mjs +2 -2
- package/dist-esm/lib/editor/managers/TextManager/TextManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.mjs +3 -2
- package/dist-esm/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.mjs.map +2 -2
- package/dist-esm/lib/exports/FontEmbedder.mjs +9 -8
- package/dist-esm/lib/exports/FontEmbedder.mjs.map +2 -2
- package/dist-esm/lib/exports/StyleEmbedder.mjs +29 -16
- package/dist-esm/lib/exports/StyleEmbedder.mjs.map +3 -3
- package/dist-esm/lib/exports/domUtils.mjs +15 -0
- package/dist-esm/lib/exports/domUtils.mjs.map +2 -2
- package/dist-esm/lib/exports/embedMedia.mjs +16 -13
- package/dist-esm/lib/exports/embedMedia.mjs.map +2 -2
- package/dist-esm/lib/exports/exportToSvg.mjs +8 -7
- package/dist-esm/lib/exports/exportToSvg.mjs.map +2 -2
- package/dist-esm/lib/exports/getSvgAsImage.mjs +181 -29
- package/dist-esm/lib/exports/getSvgAsImage.mjs.map +3 -3
- package/dist-esm/lib/exports/getSvgJsx.mjs +21 -9
- package/dist-esm/lib/exports/getSvgJsx.mjs.map +2 -2
- package/dist-esm/lib/globals/environment.mjs +4 -3
- package/dist-esm/lib/globals/environment.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/useDocumentEvents.mjs +13 -11
- package/dist-esm/lib/hooks/useDocumentEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.mjs +3 -2
- package/dist-esm/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/useScreenBounds.mjs +10 -6
- package/dist-esm/lib/hooks/useScreenBounds.mjs.map +2 -2
- package/dist-esm/lib/hooks/useViewportHeight.mjs +13 -11
- package/dist-esm/lib/hooks/useViewportHeight.mjs.map +3 -3
- package/dist-esm/lib/license/Watermark.mjs +10 -0
- package/dist-esm/lib/license/Watermark.mjs.map +2 -2
- package/dist-esm/lib/primitives/Vec.mjs +35 -22
- package/dist-esm/lib/primitives/Vec.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Arc2d.mjs +6 -13
- package/dist-esm/lib/primitives/geometry/Arc2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Circle2d.mjs +31 -2
- package/dist-esm/lib/primitives/geometry/Circle2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/CubicBezier2d.mjs +9 -0
- package/dist-esm/lib/primitives/geometry/CubicBezier2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/CubicSpline2d.mjs +9 -0
- package/dist-esm/lib/primitives/geometry/CubicSpline2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Edge2d.mjs +32 -18
- package/dist-esm/lib/primitives/geometry/Edge2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Ellipse2d.mjs +13 -1
- package/dist-esm/lib/primitives/geometry/Ellipse2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Polyline2d.mjs +51 -12
- package/dist-esm/lib/primitives/geometry/Polyline2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Stadium2d.mjs +13 -1
- package/dist-esm/lib/primitives/geometry/Stadium2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/geometry.bench.mjs +132 -0
- package/dist-esm/lib/primitives/geometry/geometry.bench.mjs.map +7 -0
- package/dist-esm/lib/primitives/intersect.mjs +17 -16
- package/dist-esm/lib/primitives/intersect.mjs.map +2 -2
- package/dist-esm/lib/primitives/utils.mjs +0 -1
- package/dist-esm/lib/primitives/utils.mjs.map +2 -2
- package/dist-esm/lib/utils/browserCanvasMaxSize.mjs +3 -2
- package/dist-esm/lib/utils/browserCanvasMaxSize.mjs.map +2 -2
- package/dist-esm/lib/utils/dom.mjs +15 -2
- package/dist-esm/lib/utils/dom.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/index.ts +3 -0
- package/src/lib/TldrawEditor.tsx +7 -5
- package/src/lib/components/default-components/CanvasShapeIndicators.tsx +2 -1
- package/src/lib/components/default-components/DefaultCanvas.tsx +1 -1
- package/src/lib/components/default-components/DefaultErrorFallback.tsx +8 -5
- package/src/lib/config/TLSessionStateSnapshot.ts +8 -5
- package/src/lib/config/TLUserPreferences.ts +3 -2
- package/src/lib/config/createTLStore.ts +3 -0
- package/src/lib/editor/Editor.ts +53 -15
- package/src/lib/editor/managers/FocusManager/FocusManager.test.ts +7 -6
- package/src/lib/editor/managers/FocusManager/FocusManager.ts +10 -7
- package/src/lib/editor/managers/FontManager/FontManager.test.ts +1 -0
- package/src/lib/editor/managers/FontManager/FontManager.ts +4 -3
- package/src/lib/editor/managers/HistoryManager/HistoryManager.test.ts +16 -0
- package/src/lib/editor/managers/HistoryManager/HistoryManager.ts +7 -2
- package/src/lib/editor/managers/TextManager/TextManager.test.ts +4 -5
- package/src/lib/editor/managers/TextManager/TextManager.ts +2 -2
- package/src/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.ts +3 -2
- package/src/lib/editor/types/misc-types.ts +8 -2
- package/src/lib/exports/FontEmbedder.ts +10 -9
- package/src/lib/exports/StyleEmbedder.ts +33 -15
- package/src/lib/exports/domUtils.ts +20 -0
- package/src/lib/exports/embedMedia.ts +23 -17
- package/src/lib/exports/exportToSvg.tsx +8 -7
- package/src/lib/exports/getSvgAsImage.ts +292 -32
- package/src/lib/exports/getSvgJsx.test.ts +103 -101
- package/src/lib/exports/getSvgJsx.tsx +33 -10
- package/src/lib/globals/environment.ts +4 -3
- package/src/lib/hooks/useCanvasEvents.ts +2 -3
- package/src/lib/hooks/useDocumentEvents.ts +16 -11
- package/src/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.ts +3 -3
- package/src/lib/hooks/useScreenBounds.ts +10 -6
- package/src/lib/hooks/useViewportHeight.ts +13 -11
- package/src/lib/license/Watermark.tsx +10 -0
- package/src/lib/primitives/Vec.ts +51 -24
- package/src/lib/primitives/geometry/Arc2d.ts +10 -15
- package/src/lib/primitives/geometry/Circle2d.ts +40 -2
- package/src/lib/primitives/geometry/CubicBezier2d.ts +10 -0
- package/src/lib/primitives/geometry/CubicSpline2d.ts +10 -0
- package/src/lib/primitives/geometry/Edge2d.ts +41 -18
- package/src/lib/primitives/geometry/Ellipse2d.ts +14 -1
- package/src/lib/primitives/geometry/Polyline2d.ts +60 -12
- package/src/lib/primitives/geometry/Stadium2d.ts +14 -1
- package/src/lib/primitives/geometry/geometry.bench.ts +179 -0
- package/src/lib/primitives/intersect.ts +27 -27
- package/src/lib/primitives/utils.ts +4 -4
- package/src/lib/test/TestEditor.ts +1 -0
- package/src/lib/utils/browserCanvasMaxSize.ts +4 -2
- package/src/lib/utils/dom.ts +34 -2
- package/src/version.ts +3 -3
|
@@ -82,9 +82,9 @@ class FontEmbedder {
|
|
|
82
82
|
__publicField(this, "fontFacesToEmbed", /* @__PURE__ */ new Set());
|
|
83
83
|
__publicField(this, "pendingPromises", []);
|
|
84
84
|
}
|
|
85
|
-
|
|
85
|
+
startFindingDocumentFontFaces(doc) {
|
|
86
86
|
(0, import_utils.assert)(!this.fontFacesPromise, "FontEmbedder already started");
|
|
87
|
-
this.fontFacesPromise =
|
|
87
|
+
this.fontFacesPromise = getDocumentFontFaces(doc);
|
|
88
88
|
}
|
|
89
89
|
onFontFamilyValue(fontFamilyValue) {
|
|
90
90
|
(0, import_utils.assert)(this.fontFacesPromise, "FontEmbedder not started");
|
|
@@ -126,9 +126,10 @@ class FontEmbedder {
|
|
|
126
126
|
_init = __decoratorStart(null);
|
|
127
127
|
__decorateElement(_init, 1, "onFontFamilyValue", _onFontFamilyValue_dec, FontEmbedder);
|
|
128
128
|
__decoratorMetadata(_init, FontEmbedder);
|
|
129
|
-
async function
|
|
129
|
+
async function getDocumentFontFaces(doc) {
|
|
130
|
+
const win = doc.defaultView ?? globalThis;
|
|
130
131
|
const fontFaces = [];
|
|
131
|
-
const styleSheetsWithoutSvgExports = Array.from(
|
|
132
|
+
const styleSheetsWithoutSvgExports = Array.from(doc.styleSheets).filter(
|
|
132
133
|
(styleSheet) => !styleSheet.ownerNode?.closest(`.${SVG_EXPORT_CLASSNAME}`)
|
|
133
134
|
);
|
|
134
135
|
for (const styleSheet of styleSheetsWithoutSvgExports) {
|
|
@@ -139,10 +140,10 @@ async function getCurrentDocumentFontFaces() {
|
|
|
139
140
|
}
|
|
140
141
|
if (cssRules) {
|
|
141
142
|
for (const rule of styleSheet.cssRules) {
|
|
142
|
-
if (rule instanceof CSSFontFaceRule) {
|
|
143
|
-
fontFaces.push((0, import_parseCss.parseCssFontFaces)(rule.cssText, styleSheet.href ??
|
|
144
|
-
} else if (rule instanceof CSSImportRule) {
|
|
145
|
-
const absoluteUrl = new URL(rule.href, rule.parentStyleSheet?.href ??
|
|
143
|
+
if (rule instanceof win.CSSFontFaceRule) {
|
|
144
|
+
fontFaces.push((0, import_parseCss.parseCssFontFaces)(rule.cssText, styleSheet.href ?? doc.baseURI));
|
|
145
|
+
} else if (rule instanceof win.CSSImportRule) {
|
|
146
|
+
const absoluteUrl = new URL(rule.href, rule.parentStyleSheet?.href ?? doc.baseURI);
|
|
146
147
|
fontFaces.push(fetchCssFontFaces(absoluteUrl.href));
|
|
147
148
|
}
|
|
148
149
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/lib/exports/FontEmbedder.ts"],
|
|
4
|
-
"sourcesContent": ["import { assert, bind, compact } from '@tldraw/utils'\nimport { fetchCache, resourceToDataUrl } from './fetchCache'\nimport { ParsedFontFace, parseCss, parseCssFontFaces, parseCssFontFamilyValue } from './parseCss'\n\nexport const SVG_EXPORT_CLASSNAME = 'tldraw-svg-export'\n\n/**\n * Because SVGs cannot refer to external CSS/font resources, any web fonts used in the SVG must be\n * embedded as data URLs in inlined @font-face declarations. This class is responsible for\n * collecting used font faces and creating a CSS string with embedded fonts that can be used in the\n * SVG.\n *\n * It works in three steps:\n * 1. `
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAAsC;AACtC,wBAA8C;AAC9C,sBAAqF;AAFrF;AAIO,MAAM,uBAAuB;AA6BnC,0BAAC;AAXK,MAAM,aAAa;AAAA,EAAnB;AAAA;AACN,wBAAQ,oBAAqD;AAC7D,wBAAiB,kBAAiB,oBAAI,IAAY;AAClD,wBAAiB,oBAAmB,oBAAI,IAAoB;AAC5D,wBAAiB,mBAAmC,CAAC;AAAA;AAAA,EAErD,
|
|
4
|
+
"sourcesContent": ["import { assert, bind, compact } from '@tldraw/utils'\nimport { fetchCache, resourceToDataUrl } from './fetchCache'\nimport { ParsedFontFace, parseCss, parseCssFontFaces, parseCssFontFamilyValue } from './parseCss'\n\nexport const SVG_EXPORT_CLASSNAME = 'tldraw-svg-export'\n\n/**\n * Because SVGs cannot refer to external CSS/font resources, any web fonts used in the SVG must be\n * embedded as data URLs in inlined @font-face declarations. This class is responsible for\n * collecting used font faces and creating a CSS string with embedded fonts that can be used in the\n * SVG.\n *\n * It works in three steps:\n * 1. `startFindingDocumentFontFaces` - this traverses the given document, finding all the\n * stylesheets in use (including those imported via `@import` rules etc) and extracting the\n * @font-face declarations from them.\n * 2. `onFontFamilyValue` - as `StyleEmbedder` traverses the SVG, it will call this method with the\n * value of the `font-family` property for each element. We parse out the font names in use, and\n * mark them as needing to be embedded.\n * 3. `createCss` - once all the font families have been collected, this method will return a CSS\n * string with embedded fonts.\n */\nexport class FontEmbedder {\n\tprivate fontFacesPromise: Promise<ParsedFontFace[]> | null = null\n\tprivate readonly foundFontNames = new Set<string>()\n\tprivate readonly fontFacesToEmbed = new Set<ParsedFontFace>()\n\tprivate readonly pendingPromises: Promise<void>[] = []\n\n\tstartFindingDocumentFontFaces(doc: Document) {\n\t\tassert(!this.fontFacesPromise, 'FontEmbedder already started')\n\t\tthis.fontFacesPromise = getDocumentFontFaces(doc)\n\t}\n\n\t@bind onFontFamilyValue(fontFamilyValue: string) {\n\t\tassert(this.fontFacesPromise, 'FontEmbedder not started')\n\n\t\tconst fonts = parseCssFontFamilyValue(fontFamilyValue)\n\t\tfor (const font of fonts) {\n\t\t\tif (this.foundFontNames.has(font)) return\n\t\t\tthis.foundFontNames.add(font)\n\n\t\t\tthis.pendingPromises.push(\n\t\t\t\tthis.fontFacesPromise.then((fontFaces) => {\n\t\t\t\t\tconst relevantFontFaces = fontFaces.filter((fontFace) => fontFace.fontFamilies.has(font))\n\t\t\t\t\tfor (const fontFace of relevantFontFaces) {\n\t\t\t\t\t\tif (this.fontFacesToEmbed.has(fontFace)) continue\n\n\t\t\t\t\t\tthis.fontFacesToEmbed.add(fontFace)\n\t\t\t\t\t\tfor (const url of fontFace.urls) {\n\t\t\t\t\t\t\tif (!url.resolved || url.embedded) continue\n\t\t\t\t\t\t\t// kick off fetching this font\n\t\t\t\t\t\t\turl.embedded = resourceToDataUrl(url.resolved)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t)\n\t\t}\n\t}\n\n\tasync createCss() {\n\t\tawait Promise.all(this.pendingPromises)\n\n\t\tlet css = ''\n\n\t\tfor (const fontFace of this.fontFacesToEmbed) {\n\t\t\tlet fontFaceString = `@font-face {${fontFace.fontFace}}`\n\n\t\t\tfor (const url of fontFace.urls) {\n\t\t\t\tif (!url.embedded) continue\n\t\t\t\tconst dataUrl = await url.embedded\n\t\t\t\tif (!dataUrl) continue\n\n\t\t\t\tfontFaceString = fontFaceString.replace(url.original, dataUrl)\n\t\t\t}\n\n\t\t\tcss += fontFaceString\n\t\t}\n\n\t\treturn css\n\t}\n}\n\nasync function getDocumentFontFaces(doc: Document) {\n\tconst win = doc.defaultView ?? globalThis\n\tconst fontFaces: (ParsedFontFace[] | Promise<ParsedFontFace[] | null>)[] = []\n\n\t// In exportToSvg we add the exported node to the DOM temporarily.\n\t// Because of this, and because we do a setTimeout to delay removing that node from the\n\t// DOM, when looking at document.styleSheets the number of nodes and stylesheets\n\t// can grow unbounded (especially when using \"Debug svg\" and moving shapes around).\n\t// To avoid this, we filter out the stylesheets that are part of the SVG export.\n\tconst styleSheetsWithoutSvgExports = Array.from(doc.styleSheets).filter(\n\t\t(styleSheet) =>\n\t\t\t!(styleSheet.ownerNode as HTMLElement | null)?.closest(`.${SVG_EXPORT_CLASSNAME}`)\n\t)\n\n\tfor (const styleSheet of styleSheetsWithoutSvgExports) {\n\t\tlet cssRules\n\t\ttry {\n\t\t\tcssRules = styleSheet.cssRules\n\t\t} catch {\n\t\t\t// some stylesheets don't allow access through the DOM. We'll try to fetch them instead.\n\t\t}\n\n\t\tif (cssRules) {\n\t\t\tfor (const rule of styleSheet.cssRules) {\n\t\t\t\tif (rule instanceof win.CSSFontFaceRule) {\n\t\t\t\t\tfontFaces.push(parseCssFontFaces(rule.cssText, styleSheet.href ?? doc.baseURI))\n\t\t\t\t} else if (rule instanceof win.CSSImportRule) {\n\t\t\t\t\tconst absoluteUrl = new URL(rule.href, rule.parentStyleSheet?.href ?? doc.baseURI)\n\t\t\t\t\tfontFaces.push(fetchCssFontFaces(absoluteUrl.href))\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (styleSheet.href) {\n\t\t\tfontFaces.push(fetchCssFontFaces(styleSheet.href))\n\t\t}\n\t}\n\n\treturn compact(await Promise.all(fontFaces)).flat()\n}\n\nconst fetchCssFontFaces = fetchCache(async (response: Response): Promise<ParsedFontFace[]> => {\n\tconst parsed = parseCss(await response.text(), response.url)\n\n\tconst importedFontFaces = await Promise.all(\n\t\tparsed.imports.map(({ url }) => fetchCssFontFaces(new URL(url, response.url).href))\n\t)\n\n\treturn [...parsed.fontFaces, ...compact(importedFontFaces).flat()]\n})\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAAsC;AACtC,wBAA8C;AAC9C,sBAAqF;AAFrF;AAIO,MAAM,uBAAuB;AA6BnC,0BAAC;AAXK,MAAM,aAAa;AAAA,EAAnB;AAAA;AACN,wBAAQ,oBAAqD;AAC7D,wBAAiB,kBAAiB,oBAAI,IAAY;AAClD,wBAAiB,oBAAmB,oBAAI,IAAoB;AAC5D,wBAAiB,mBAAmC,CAAC;AAAA;AAAA,EAErD,8BAA8B,KAAe;AAC5C,6BAAO,CAAC,KAAK,kBAAkB,8BAA8B;AAC7D,SAAK,mBAAmB,qBAAqB,GAAG;AAAA,EACjD;AAAA,EAEM,kBAAkB,iBAAyB;AAChD,6BAAO,KAAK,kBAAkB,0BAA0B;AAExD,UAAM,YAAQ,yCAAwB,eAAe;AACrD,eAAW,QAAQ,OAAO;AACzB,UAAI,KAAK,eAAe,IAAI,IAAI,EAAG;AACnC,WAAK,eAAe,IAAI,IAAI;AAE5B,WAAK,gBAAgB;AAAA,QACpB,KAAK,iBAAiB,KAAK,CAAC,cAAc;AACzC,gBAAM,oBAAoB,UAAU,OAAO,CAAC,aAAa,SAAS,aAAa,IAAI,IAAI,CAAC;AACxF,qBAAW,YAAY,mBAAmB;AACzC,gBAAI,KAAK,iBAAiB,IAAI,QAAQ,EAAG;AAEzC,iBAAK,iBAAiB,IAAI,QAAQ;AAClC,uBAAW,OAAO,SAAS,MAAM;AAChC,kBAAI,CAAC,IAAI,YAAY,IAAI,SAAU;AAEnC,kBAAI,eAAW,qCAAkB,IAAI,QAAQ;AAAA,YAC9C;AAAA,UACD;AAAA,QACD,CAAC;AAAA,MACF;AAAA,IACD;AAAA,EACD;AAAA,EAEA,MAAM,YAAY;AACjB,UAAM,QAAQ,IAAI,KAAK,eAAe;AAEtC,QAAI,MAAM;AAEV,eAAW,YAAY,KAAK,kBAAkB;AAC7C,UAAI,iBAAiB,eAAe,SAAS,QAAQ;AAErD,iBAAW,OAAO,SAAS,MAAM;AAChC,YAAI,CAAC,IAAI,SAAU;AACnB,cAAM,UAAU,MAAM,IAAI;AAC1B,YAAI,CAAC,QAAS;AAEd,yBAAiB,eAAe,QAAQ,IAAI,UAAU,OAAO;AAAA,MAC9D;AAEA,aAAO;AAAA,IACR;AAEA,WAAO;AAAA,EACR;AACD;AA1DO;AAWA,iDAAN,wBAXY;AAAN,2BAAM;AA4Db,eAAe,qBAAqB,KAAe;AAClD,QAAM,MAAM,IAAI,eAAe;AAC/B,QAAM,YAAqE,CAAC;AAO5E,QAAM,+BAA+B,MAAM,KAAK,IAAI,WAAW,EAAE;AAAA,IAChE,CAAC,eACA,CAAE,WAAW,WAAkC,QAAQ,IAAI,oBAAoB,EAAE;AAAA,EACnF;AAEA,aAAW,cAAc,8BAA8B;AACtD,QAAI;AACJ,QAAI;AACH,iBAAW,WAAW;AAAA,IACvB,QAAQ;AAAA,IAER;AAEA,QAAI,UAAU;AACb,iBAAW,QAAQ,WAAW,UAAU;AACvC,YAAI,gBAAgB,IAAI,iBAAiB;AACxC,oBAAU,SAAK,mCAAkB,KAAK,SAAS,WAAW,QAAQ,IAAI,OAAO,CAAC;AAAA,QAC/E,WAAW,gBAAgB,IAAI,eAAe;AAC7C,gBAAM,cAAc,IAAI,IAAI,KAAK,MAAM,KAAK,kBAAkB,QAAQ,IAAI,OAAO;AACjF,oBAAU,KAAK,kBAAkB,YAAY,IAAI,CAAC;AAAA,QACnD;AAAA,MACD;AAAA,IACD,WAAW,WAAW,MAAM;AAC3B,gBAAU,KAAK,kBAAkB,WAAW,IAAI,CAAC;AAAA,IAClD;AAAA,EACD;AAEA,aAAO,sBAAQ,MAAM,QAAQ,IAAI,SAAS,CAAC,EAAE,KAAK;AACnD;AAEA,MAAM,wBAAoB,8BAAW,OAAO,aAAkD;AAC7F,QAAM,aAAS,0BAAS,MAAM,SAAS,KAAK,GAAG,SAAS,GAAG;AAE3D,QAAM,oBAAoB,MAAM,QAAQ;AAAA,IACvC,OAAO,QAAQ,IAAI,CAAC,EAAE,IAAI,MAAM,kBAAkB,IAAI,IAAI,KAAK,SAAS,GAAG,EAAE,IAAI,CAAC;AAAA,EACnF;AAEA,SAAO,CAAC,GAAG,OAAO,WAAW,OAAG,sBAAQ,iBAAiB,EAAE,KAAK,CAAC;AAClE,CAAC;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -50,7 +50,7 @@ class StyleEmbedder {
|
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
52
|
readElementStyles(element, { shouldRespectDefaults = true, shouldSkipInheritedParentStyles = true }) {
|
|
53
|
-
const defaultStyles = shouldRespectDefaults ? getDefaultStylesForTagName(element.tagName.toLowerCase()) : NO_STYLES;
|
|
53
|
+
const defaultStyles = shouldRespectDefaults ? getDefaultStylesForTagName(element.ownerDocument, element.tagName.toLowerCase()) : NO_STYLES;
|
|
54
54
|
const parentStyles = Object.assign({}, NO_STYLES);
|
|
55
55
|
if (shouldSkipInheritedParentStyles) {
|
|
56
56
|
let el = element.parentElement;
|
|
@@ -104,12 +104,12 @@ class StyleEmbedder {
|
|
|
104
104
|
visited.add(element);
|
|
105
105
|
const shadowRoot = element.shadowRoot;
|
|
106
106
|
if (shadowRoot) {
|
|
107
|
-
const clonedCustomEl =
|
|
107
|
+
const clonedCustomEl = element.ownerDocument.createElement("div");
|
|
108
108
|
this.styles.set(clonedCustomEl, this.styles.get(element));
|
|
109
109
|
clonedCustomEl.setAttribute("data-tl-custom-element", element.tagName);
|
|
110
110
|
(clonedParent ?? element.parentElement).appendChild(clonedCustomEl);
|
|
111
111
|
for (const child of shadowRoot.childNodes) {
|
|
112
|
-
if (
|
|
112
|
+
if ((0, import_domUtils.isElement)(child)) {
|
|
113
113
|
visit(child, clonedCustomEl);
|
|
114
114
|
} else {
|
|
115
115
|
clonedCustomEl.appendChild(child.cloneNode(true));
|
|
@@ -124,7 +124,7 @@ class StyleEmbedder {
|
|
|
124
124
|
this.styles.set(clonedEl, this.styles.get(element));
|
|
125
125
|
clonedParent.appendChild(clonedEl);
|
|
126
126
|
for (const child of (0, import_domUtils.getRenderedChildNodes)(element)) {
|
|
127
|
-
if (
|
|
127
|
+
if ((0, import_domUtils.isElement)(child)) {
|
|
128
128
|
visit(child, clonedEl);
|
|
129
129
|
} else {
|
|
130
130
|
clonedEl.appendChild(child.cloneNode(true));
|
|
@@ -230,32 +230,44 @@ function formatCss(style) {
|
|
|
230
230
|
}
|
|
231
231
|
let defaultStyleFrame;
|
|
232
232
|
const defaultStylesByTagName = {};
|
|
233
|
-
function getDefaultStyleFrame() {
|
|
234
|
-
if (!defaultStyleFrame) {
|
|
235
|
-
|
|
233
|
+
function getDefaultStyleFrame(ownerDoc) {
|
|
234
|
+
if (!defaultStyleFrame || defaultStyleFrame.ownerDocument !== ownerDoc) {
|
|
235
|
+
destroyDefaultStyleFrame();
|
|
236
|
+
const frame = ownerDoc.createElement("iframe");
|
|
236
237
|
frame.style.display = "none";
|
|
237
|
-
|
|
238
|
+
ownerDoc.body.appendChild(frame);
|
|
238
239
|
const frameDocument = (0, import_utils.assertExists)(frame.contentDocument, "frame must have a document");
|
|
239
|
-
const svg =
|
|
240
|
-
const foreignObject =
|
|
240
|
+
const svg = frameDocument.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
241
|
+
const foreignObject = frameDocument.createElementNS(
|
|
242
|
+
"http://www.w3.org/2000/svg",
|
|
243
|
+
"foreignObject"
|
|
244
|
+
);
|
|
241
245
|
svg.appendChild(foreignObject);
|
|
242
246
|
frameDocument.body.appendChild(svg);
|
|
243
|
-
defaultStyleFrame = {
|
|
247
|
+
defaultStyleFrame = {
|
|
248
|
+
iframe: frame,
|
|
249
|
+
foreignObject,
|
|
250
|
+
document: frameDocument,
|
|
251
|
+
ownerDocument: ownerDoc
|
|
252
|
+
};
|
|
244
253
|
}
|
|
245
254
|
return defaultStyleFrame;
|
|
246
255
|
}
|
|
247
256
|
function destroyDefaultStyleFrame() {
|
|
248
257
|
if (defaultStyleFrame) {
|
|
249
|
-
|
|
258
|
+
defaultStyleFrame.iframe.remove();
|
|
250
259
|
defaultStyleFrame = void 0;
|
|
251
260
|
}
|
|
261
|
+
for (const tagName in defaultStylesByTagName) {
|
|
262
|
+
delete defaultStylesByTagName[tagName];
|
|
263
|
+
}
|
|
252
264
|
}
|
|
253
265
|
const defaultStyleReadOptions = { defaultStyles: NO_STYLES, parentStyles: NO_STYLES };
|
|
254
|
-
function getDefaultStylesForTagName(tagName) {
|
|
266
|
+
function getDefaultStylesForTagName(ownerDoc, tagName) {
|
|
255
267
|
let existing = defaultStylesByTagName[tagName];
|
|
256
268
|
if (!existing) {
|
|
257
|
-
const { foreignObject, document
|
|
258
|
-
const element =
|
|
269
|
+
const { foreignObject, document } = getDefaultStyleFrame(ownerDoc);
|
|
270
|
+
const element = document.createElement(tagName);
|
|
259
271
|
foreignObject.appendChild(element);
|
|
260
272
|
existing = element.computedStyleMap ? styleFromComputedStyleMap(element.computedStyleMap(), defaultStyleReadOptions) : styleFromComputedStyle((0, import_domUtils.getComputedStyle)(element), defaultStyleReadOptions);
|
|
261
273
|
foreignObject.removeChild(element);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/lib/exports/StyleEmbedder.ts"],
|
|
4
|
-
"sourcesContent": ["import { assertExists, getOwnProperty, objectMapValues, uniqueId } from '@tldraw/utils'\nimport { FontEmbedder } from './FontEmbedder'\nimport { ReadonlyStyles, Styles, cssRules } from './cssRules'\nimport {\n\telementStyle,\n\tgetComputedStyle,\n\tgetRenderedChildNodes,\n\tgetRenderedChildren,\n} from './domUtils'\nimport { resourceToDataUrl } from './fetchCache'\nimport { parseCssValueUrls, shouldIncludeCssProperty } from './parseCss'\n\nconst NO_STYLES = {} as const\n\ninterface ElementStyleInfo {\n\tself: Styles\n\tbefore: Styles | undefined\n\tafter: Styles | undefined\n}\n\nexport class StyleEmbedder {\n\tconstructor(private readonly root: Element) {}\n\tprivate readonly styles = new Map<Element, ElementStyleInfo>()\n\treadonly fonts = new FontEmbedder()\n\n\treadRootElementStyles(rootElement: Element) {\n\t\t// when reading a root, we always apply _all_ the styles, even if they match the defaults\n\t\tthis.readElementStyles(rootElement, {\n\t\t\tshouldRespectDefaults: false,\n\t\t\tshouldSkipInheritedParentStyles: false,\n\t\t})\n\n\t\tconst children = Array.from(getRenderedChildren(rootElement))\n\t\twhile (children.length) {\n\t\t\tconst child = children.pop()!\n\t\t\tchildren.push(...getRenderedChildren(child))\n\n\t\t\t// when reading children, we don't apply styles that match the defaults for that\n\t\t\t// element, or that would be inherited from the parent\n\t\t\tthis.readElementStyles(child, {\n\t\t\t\tshouldRespectDefaults: true,\n\t\t\t\tshouldSkipInheritedParentStyles: true,\n\t\t\t})\n\t\t}\n\t}\n\n\tprivate readElementStyles(\n\t\telement: Element,\n\t\t{ shouldRespectDefaults = true, shouldSkipInheritedParentStyles = true }\n\t) {\n\t\tconst defaultStyles = shouldRespectDefaults\n\t\t\t? getDefaultStylesForTagName(element.tagName.toLowerCase())\n\t\t\t: NO_STYLES\n\n\t\tconst parentStyles = Object.assign({}, NO_STYLES) as Styles\n\t\tif (shouldSkipInheritedParentStyles) {\n\t\t\tlet el = element.parentElement\n\t\t\t// Keep going up the tree to find all the relevant styles\n\t\t\twhile (el) {\n\t\t\t\tconst currentStyles = this.styles.get(el)?.self\n\t\t\t\tfor (const style in currentStyles) {\n\t\t\t\t\tif (!parentStyles[style]) {\n\t\t\t\t\t\tparentStyles[style] = currentStyles[style]\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tel = el.parentElement\n\t\t\t}\n\t\t}\n\n\t\tconst info: ElementStyleInfo = {\n\t\t\tself: styleFromElement(element, { defaultStyles, parentStyles }),\n\t\t\tbefore: styleFromPseudoElement(element, '::before'),\n\t\t\tafter: styleFromPseudoElement(element, '::after'),\n\t\t}\n\t\tthis.styles.set(element, info)\n\t}\n\n\tfetchResources() {\n\t\tconst promises: Promise<void>[] = []\n\n\t\tfor (const info of this.styles.values()) {\n\t\t\tfor (const styles of objectMapValues(info)) {\n\t\t\t\tif (!styles) continue\n\t\t\t\tfor (const [property, value] of Object.entries(styles)) {\n\t\t\t\t\tif (!value) continue\n\t\t\t\t\tif (property === 'font-family') {\n\t\t\t\t\t\tthis.fonts.onFontFamilyValue(value)\n\t\t\t\t\t}\n\n\t\t\t\t\tconst urlMatches = parseCssValueUrls(value)\n\t\t\t\t\tif (urlMatches.length === 0) continue\n\n\t\t\t\t\tpromises.push(\n\t\t\t\t\t\t...urlMatches.map(async ({ url, original }) => {\n\t\t\t\t\t\t\tconst dataUrl = (await resourceToDataUrl(url)) ?? 'data:'\n\t\t\t\t\t\t\tstyles[property] = value.replace(original, `url(\"${dataUrl}\")`)\n\t\t\t\t\t\t})\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn Promise.all(promises)\n\t}\n\n\t// custom elements are tricky. if we serialize the dom as-is, the custom elements wont have\n\t// their shadow-dom contents serialized. after we've read all the styles, we need to unwrap the\n\t// contents of each custom elements shadow dom directly into the parent element itself.\n\tunwrapCustomElements() {\n\t\tconst visited = new Set<Node>()\n\n\t\tconst visit = (element: Element, clonedParent: Element | null) => {\n\t\t\tif (visited.has(element)) return\n\t\t\tvisited.add(element)\n\n\t\t\tconst shadowRoot = element.shadowRoot\n\n\t\t\tif (shadowRoot) {\n\t\t\t\tconst clonedCustomEl = document.createElement('div')\n\t\t\t\tthis.styles.set(clonedCustomEl, this.styles.get(element)!)\n\n\t\t\t\tclonedCustomEl.setAttribute('data-tl-custom-element', element.tagName)\n\t\t\t\t;(clonedParent ?? element.parentElement!).appendChild(clonedCustomEl)\n\n\t\t\t\tfor (const child of shadowRoot.childNodes) {\n\t\t\t\t\tif (child instanceof Element) {\n\t\t\t\t\t\tvisit(child, clonedCustomEl)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tclonedCustomEl.appendChild(child.cloneNode(true))\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\telement.remove()\n\t\t\t} else if (clonedParent) {\n\t\t\t\tif (element.tagName.toLowerCase() === 'style') {\n\t\t\t\t\t// we don't clone style tags at that would break the style scoping. instead we\n\t\t\t\t\t// rely on the computed styles we've already read\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tconst clonedEl = element.cloneNode(false) as Element\n\t\t\t\tthis.styles.set(clonedEl, this.styles.get(element)!)\n\n\t\t\t\tclonedParent.appendChild(clonedEl)\n\n\t\t\t\tfor (const child of getRenderedChildNodes(element)) {\n\t\t\t\t\tif (child instanceof Element) {\n\t\t\t\t\t\tvisit(child, clonedEl)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tclonedEl.appendChild(child.cloneNode(true))\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfor (const element of this.styles.keys()) {\n\t\t\tvisit(element, null)\n\t\t}\n\t}\n\n\tembedStyles(): string {\n\t\tlet css = ''\n\n\t\tfor (const [element, info] of this.styles) {\n\t\t\tif (info.after || info.before) {\n\t\t\t\tconst className = `pseudo-${uniqueId()}`\n\t\t\t\telement.classList.add(className)\n\n\t\t\t\tif (info.before) {\n\t\t\t\t\tcss += `.${className}::before {${formatCss(info.before)}}\\n`\n\t\t\t\t}\n\t\t\t\tif (info.after) {\n\t\t\t\t\tcss += `.${className}::after {${formatCss(info.after)}}\\n`\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst style = elementStyle(element)\n\t\t\tfor (const [property, value] of Object.entries(info.self)) {\n\t\t\t\tif (!value) continue\n\t\t\t\tstyle.setProperty(property, value)\n\t\t\t}\n\n\t\t\t// in HTML, font-kerning: auto is equivalent to font-kerning: normal. But in SVG, it's\n\t\t\t// none. We set it to normal here to match the HTML behavior, as otherwise this can\n\t\t\t// cause rendering differences.\n\t\t\tif (style.fontKerning === 'auto') {\n\t\t\t\tstyle.fontKerning = 'normal'\n\t\t\t}\n\t\t}\n\n\t\treturn css\n\t}\n\n\tasync getFontFaceCss() {\n\t\treturn await this.fonts.createCss()\n\t}\n\n\tdispose() {\n\t\tdestroyDefaultStyleFrame()\n\t}\n}\n\ninterface ReadStyleOpts {\n\tdefaultStyles: ReadonlyStyles\n\tparentStyles: ReadonlyStyles\n}\n\nfunction styleFromElement(element: Element, { defaultStyles, parentStyles }: ReadStyleOpts) {\n\t// `computedStyleMap` produces a more accurate representation of the styles, but it's not\n\t// supported in firefox at the time of writing. So we fall back to `getComputedStyle` if it's\n\t// not available.\n\tif (element.computedStyleMap) {\n\t\treturn styleFromComputedStyleMap(element.computedStyleMap(), { defaultStyles, parentStyles })\n\t}\n\treturn styleFromComputedStyle(getComputedStyle(element), { defaultStyles, parentStyles })\n}\n\nfunction styleFromPseudoElement(element: Element, pseudo: string) {\n\t// the equivalent of `computedStyleMap` for pseudo-elements isn't even fully specced out yet, so\n\t// for those we have to use `getComputedStyle` in all browsers.\n\tconst style = getComputedStyle(element, pseudo)\n\n\tconst content = style.getPropertyValue('content')\n\tif (content === '' || content === 'none') {\n\t\treturn undefined\n\t}\n\n\treturn styleFromComputedStyle(style, { defaultStyles: NO_STYLES, parentStyles: NO_STYLES })\n}\n\nfunction styleFromComputedStyleMap(\n\tstyle: StylePropertyMapReadOnly,\n\t{ defaultStyles, parentStyles }: ReadStyleOpts\n) {\n\tconst styles: Record<string, string> = {}\n\tconst currentColor = style.get('color')?.toString() || ''\n\tconst ruleOptions = {\n\t\tcurrentColor,\n\t\tparentStyles,\n\t\tdefaultStyles,\n\t\tgetStyle: (property: string) => style.get(property)?.toString() ?? '',\n\t}\n\tfor (const property of style.keys()) {\n\t\tif (!shouldIncludeCssProperty(property)) continue\n\n\t\tconst value = style.get(property)!.toString()\n\n\t\tif (defaultStyles[property] === value) continue\n\n\t\tconst rule = getOwnProperty(cssRules, property)\n\t\tif (rule && rule(value, property, ruleOptions)) continue\n\n\t\tstyles[property] = value\n\t}\n\n\treturn styles\n}\n\nfunction styleFromComputedStyle(\n\tstyle: CSSStyleDeclaration,\n\t{ defaultStyles, parentStyles }: ReadStyleOpts\n) {\n\tconst styles: Record<string, string> = {}\n\tconst currentColor = style.color\n\tconst ruleOptions = {\n\t\tcurrentColor,\n\t\tparentStyles,\n\t\tdefaultStyles,\n\t\tgetStyle: (property: string) => style.getPropertyValue(property),\n\t}\n\n\tfor (const property in style) {\n\t\tif (!shouldIncludeCssProperty(property)) continue\n\n\t\tconst value = style.getPropertyValue(property)\n\n\t\tif (defaultStyles[property] === value) continue\n\n\t\tconst rule = getOwnProperty(cssRules, property)\n\t\tif (rule && rule(value, property, ruleOptions)) continue\n\n\t\tstyles[property] = value\n\t}\n\treturn styles\n}\n\nfunction formatCss(style: ReadonlyStyles) {\n\tlet cssText = ''\n\tfor (const [property, value] of Object.entries(style)) {\n\t\tcssText += `${property}: ${value};`\n\t}\n\treturn cssText\n}\n\n// when we're figuring out the default values for a tag, we need read them from a separate document\n// so they're not affected by the current document's styles\nlet defaultStyleFrame:\n\t| { iframe: HTMLIFrameElement; foreignObject: SVGForeignObjectElement; document: Document }\n\t| undefined\nconst defaultStylesByTagName: Record<string, ReadonlyStyles> = {}\nfunction getDefaultStyleFrame() {\n\tif (!defaultStyleFrame) {\n\t\tconst frame = document.createElement('iframe')\n\t\tframe.style.display = 'none'\n\t\tdocument.body.appendChild(frame)\n\t\tconst frameDocument = assertExists(frame.contentDocument, 'frame must have a document')\n\t\tconst svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg')\n\t\tconst foreignObject = document.createElementNS('http://www.w3.org/2000/svg', 'foreignObject')\n\t\tsvg.appendChild(foreignObject)\n\t\tframeDocument.body.appendChild(svg)\n\t\tdefaultStyleFrame = { iframe: frame, foreignObject, document: frameDocument }\n\t}\n\treturn defaultStyleFrame\n}\n\nfunction destroyDefaultStyleFrame() {\n\tif (defaultStyleFrame) {\n\t\tdocument.body.removeChild(defaultStyleFrame.iframe)\n\t\tdefaultStyleFrame = undefined\n\t}\n}\n\nconst defaultStyleReadOptions: ReadStyleOpts = { defaultStyles: NO_STYLES, parentStyles: NO_STYLES }\nfunction getDefaultStylesForTagName(tagName: string) {\n\tlet existing = defaultStylesByTagName[tagName]\n\tif (!existing) {\n\t\tconst { foreignObject, document } = getDefaultStyleFrame()\n\t\tconst element = document.createElement(tagName)\n\t\tforeignObject.appendChild(element)\n\t\texisting = element.computedStyleMap\n\t\t\t? styleFromComputedStyleMap(element.computedStyleMap(), defaultStyleReadOptions)\n\t\t\t: styleFromComputedStyle(getComputedStyle(element), defaultStyleReadOptions)\n\t\tforeignObject.removeChild(element)\n\t\tdefaultStylesByTagName[tagName] = existing\n\t}\n\treturn existing\n}\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAAwE;AACxE,0BAA6B;AAC7B,sBAAiD;AACjD,
|
|
6
|
-
"names": [
|
|
4
|
+
"sourcesContent": ["import { assertExists, getOwnProperty, objectMapValues, uniqueId } from '@tldraw/utils'\nimport { FontEmbedder } from './FontEmbedder'\nimport { ReadonlyStyles, Styles, cssRules } from './cssRules'\nimport {\n\telementStyle,\n\tgetComputedStyle,\n\tgetRenderedChildNodes,\n\tgetRenderedChildren,\n\tisElement,\n} from './domUtils'\nimport { resourceToDataUrl } from './fetchCache'\nimport { parseCssValueUrls, shouldIncludeCssProperty } from './parseCss'\n\nconst NO_STYLES = {} as const\n\ninterface ElementStyleInfo {\n\tself: Styles\n\tbefore: Styles | undefined\n\tafter: Styles | undefined\n}\n\nexport class StyleEmbedder {\n\tconstructor(private readonly root: Element) {}\n\tprivate readonly styles = new Map<Element, ElementStyleInfo>()\n\treadonly fonts = new FontEmbedder()\n\n\treadRootElementStyles(rootElement: Element) {\n\t\t// when reading a root, we always apply _all_ the styles, even if they match the defaults\n\t\tthis.readElementStyles(rootElement, {\n\t\t\tshouldRespectDefaults: false,\n\t\t\tshouldSkipInheritedParentStyles: false,\n\t\t})\n\n\t\tconst children = Array.from(getRenderedChildren(rootElement))\n\t\twhile (children.length) {\n\t\t\tconst child = children.pop()!\n\t\t\tchildren.push(...getRenderedChildren(child))\n\n\t\t\t// when reading children, we don't apply styles that match the defaults for that\n\t\t\t// element, or that would be inherited from the parent\n\t\t\tthis.readElementStyles(child, {\n\t\t\t\tshouldRespectDefaults: true,\n\t\t\t\tshouldSkipInheritedParentStyles: true,\n\t\t\t})\n\t\t}\n\t}\n\n\tprivate readElementStyles(\n\t\telement: Element,\n\t\t{ shouldRespectDefaults = true, shouldSkipInheritedParentStyles = true }\n\t) {\n\t\tconst defaultStyles = shouldRespectDefaults\n\t\t\t? getDefaultStylesForTagName(element.ownerDocument, element.tagName.toLowerCase())\n\t\t\t: NO_STYLES\n\n\t\tconst parentStyles = Object.assign({}, NO_STYLES) as Styles\n\t\tif (shouldSkipInheritedParentStyles) {\n\t\t\tlet el = element.parentElement\n\t\t\t// Keep going up the tree to find all the relevant styles\n\t\t\twhile (el) {\n\t\t\t\tconst currentStyles = this.styles.get(el)?.self\n\t\t\t\tfor (const style in currentStyles) {\n\t\t\t\t\tif (!parentStyles[style]) {\n\t\t\t\t\t\tparentStyles[style] = currentStyles[style]\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tel = el.parentElement\n\t\t\t}\n\t\t}\n\n\t\tconst info: ElementStyleInfo = {\n\t\t\tself: styleFromElement(element, { defaultStyles, parentStyles }),\n\t\t\tbefore: styleFromPseudoElement(element, '::before'),\n\t\t\tafter: styleFromPseudoElement(element, '::after'),\n\t\t}\n\t\tthis.styles.set(element, info)\n\t}\n\n\tfetchResources() {\n\t\tconst promises: Promise<void>[] = []\n\n\t\tfor (const info of this.styles.values()) {\n\t\t\tfor (const styles of objectMapValues(info)) {\n\t\t\t\tif (!styles) continue\n\t\t\t\tfor (const [property, value] of Object.entries(styles)) {\n\t\t\t\t\tif (!value) continue\n\t\t\t\t\tif (property === 'font-family') {\n\t\t\t\t\t\tthis.fonts.onFontFamilyValue(value)\n\t\t\t\t\t}\n\n\t\t\t\t\tconst urlMatches = parseCssValueUrls(value)\n\t\t\t\t\tif (urlMatches.length === 0) continue\n\n\t\t\t\t\tpromises.push(\n\t\t\t\t\t\t...urlMatches.map(async ({ url, original }) => {\n\t\t\t\t\t\t\tconst dataUrl = (await resourceToDataUrl(url)) ?? 'data:'\n\t\t\t\t\t\t\tstyles[property] = value.replace(original, `url(\"${dataUrl}\")`)\n\t\t\t\t\t\t})\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn Promise.all(promises)\n\t}\n\n\t// custom elements are tricky. if we serialize the dom as-is, the custom elements wont have\n\t// their shadow-dom contents serialized. after we've read all the styles, we need to unwrap the\n\t// contents of each custom elements shadow dom directly into the parent element itself.\n\tunwrapCustomElements() {\n\t\tconst visited = new Set<Node>()\n\n\t\tconst visit = (element: Element, clonedParent: Element | null) => {\n\t\t\tif (visited.has(element)) return\n\t\t\tvisited.add(element)\n\n\t\t\tconst shadowRoot = element.shadowRoot\n\n\t\t\tif (shadowRoot) {\n\t\t\t\tconst clonedCustomEl = element.ownerDocument.createElement('div')\n\t\t\t\tthis.styles.set(clonedCustomEl, this.styles.get(element)!)\n\n\t\t\t\tclonedCustomEl.setAttribute('data-tl-custom-element', element.tagName)\n\t\t\t\t;(clonedParent ?? element.parentElement!).appendChild(clonedCustomEl)\n\n\t\t\t\tfor (const child of shadowRoot.childNodes) {\n\t\t\t\t\tif (isElement(child)) {\n\t\t\t\t\t\tvisit(child, clonedCustomEl)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tclonedCustomEl.appendChild(child.cloneNode(true))\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\telement.remove()\n\t\t\t} else if (clonedParent) {\n\t\t\t\tif (element.tagName.toLowerCase() === 'style') {\n\t\t\t\t\t// we don't clone style tags at that would break the style scoping. instead we\n\t\t\t\t\t// rely on the computed styles we've already read\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tconst clonedEl = element.cloneNode(false) as Element\n\t\t\t\tthis.styles.set(clonedEl, this.styles.get(element)!)\n\n\t\t\t\tclonedParent.appendChild(clonedEl)\n\n\t\t\t\tfor (const child of getRenderedChildNodes(element)) {\n\t\t\t\t\tif (isElement(child)) {\n\t\t\t\t\t\tvisit(child, clonedEl)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tclonedEl.appendChild(child.cloneNode(true))\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfor (const element of this.styles.keys()) {\n\t\t\tvisit(element, null)\n\t\t}\n\t}\n\n\tembedStyles(): string {\n\t\tlet css = ''\n\n\t\tfor (const [element, info] of this.styles) {\n\t\t\tif (info.after || info.before) {\n\t\t\t\tconst className = `pseudo-${uniqueId()}`\n\t\t\t\telement.classList.add(className)\n\n\t\t\t\tif (info.before) {\n\t\t\t\t\tcss += `.${className}::before {${formatCss(info.before)}}\\n`\n\t\t\t\t}\n\t\t\t\tif (info.after) {\n\t\t\t\t\tcss += `.${className}::after {${formatCss(info.after)}}\\n`\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst style = elementStyle(element)\n\t\t\tfor (const [property, value] of Object.entries(info.self)) {\n\t\t\t\tif (!value) continue\n\t\t\t\tstyle.setProperty(property, value)\n\t\t\t}\n\n\t\t\t// in HTML, font-kerning: auto is equivalent to font-kerning: normal. But in SVG, it's\n\t\t\t// none. We set it to normal here to match the HTML behavior, as otherwise this can\n\t\t\t// cause rendering differences.\n\t\t\tif (style.fontKerning === 'auto') {\n\t\t\t\tstyle.fontKerning = 'normal'\n\t\t\t}\n\t\t}\n\n\t\treturn css\n\t}\n\n\tasync getFontFaceCss() {\n\t\treturn await this.fonts.createCss()\n\t}\n\n\tdispose() {\n\t\tdestroyDefaultStyleFrame()\n\t}\n}\n\ninterface ReadStyleOpts {\n\tdefaultStyles: ReadonlyStyles\n\tparentStyles: ReadonlyStyles\n}\n\nfunction styleFromElement(element: Element, { defaultStyles, parentStyles }: ReadStyleOpts) {\n\t// `computedStyleMap` produces a more accurate representation of the styles, but it's not\n\t// supported in firefox at the time of writing. So we fall back to `getComputedStyle` if it's\n\t// not available.\n\tif (element.computedStyleMap) {\n\t\treturn styleFromComputedStyleMap(element.computedStyleMap(), { defaultStyles, parentStyles })\n\t}\n\treturn styleFromComputedStyle(getComputedStyle(element), { defaultStyles, parentStyles })\n}\n\nfunction styleFromPseudoElement(element: Element, pseudo: string) {\n\t// the equivalent of `computedStyleMap` for pseudo-elements isn't even fully specced out yet, so\n\t// for those we have to use `getComputedStyle` in all browsers.\n\tconst style = getComputedStyle(element, pseudo)\n\n\tconst content = style.getPropertyValue('content')\n\tif (content === '' || content === 'none') {\n\t\treturn undefined\n\t}\n\n\treturn styleFromComputedStyle(style, { defaultStyles: NO_STYLES, parentStyles: NO_STYLES })\n}\n\nfunction styleFromComputedStyleMap(\n\tstyle: StylePropertyMapReadOnly,\n\t{ defaultStyles, parentStyles }: ReadStyleOpts\n) {\n\tconst styles: Record<string, string> = {}\n\tconst currentColor = style.get('color')?.toString() || ''\n\tconst ruleOptions = {\n\t\tcurrentColor,\n\t\tparentStyles,\n\t\tdefaultStyles,\n\t\tgetStyle: (property: string) => style.get(property)?.toString() ?? '',\n\t}\n\tfor (const property of style.keys()) {\n\t\tif (!shouldIncludeCssProperty(property)) continue\n\n\t\tconst value = style.get(property)!.toString()\n\n\t\tif (defaultStyles[property] === value) continue\n\n\t\tconst rule = getOwnProperty(cssRules, property)\n\t\tif (rule && rule(value, property, ruleOptions)) continue\n\n\t\tstyles[property] = value\n\t}\n\n\treturn styles\n}\n\nfunction styleFromComputedStyle(\n\tstyle: CSSStyleDeclaration,\n\t{ defaultStyles, parentStyles }: ReadStyleOpts\n) {\n\tconst styles: Record<string, string> = {}\n\tconst currentColor = style.color\n\tconst ruleOptions = {\n\t\tcurrentColor,\n\t\tparentStyles,\n\t\tdefaultStyles,\n\t\tgetStyle: (property: string) => style.getPropertyValue(property),\n\t}\n\n\tfor (const property in style) {\n\t\tif (!shouldIncludeCssProperty(property)) continue\n\n\t\tconst value = style.getPropertyValue(property)\n\n\t\tif (defaultStyles[property] === value) continue\n\n\t\tconst rule = getOwnProperty(cssRules, property)\n\t\tif (rule && rule(value, property, ruleOptions)) continue\n\n\t\tstyles[property] = value\n\t}\n\treturn styles\n}\n\nfunction formatCss(style: ReadonlyStyles) {\n\tlet cssText = ''\n\tfor (const [property, value] of Object.entries(style)) {\n\t\tcssText += `${property}: ${value};`\n\t}\n\treturn cssText\n}\n\n// when we're figuring out the default values for a tag, we need read them from a separate document\n// so they're not affected by the current document's styles\nlet defaultStyleFrame:\n\t| {\n\t\t\tiframe: HTMLIFrameElement\n\t\t\tforeignObject: SVGForeignObjectElement\n\t\t\tdocument: Document\n\t\t\townerDocument: Document\n\t }\n\t| undefined\nconst defaultStylesByTagName: Record<string, ReadonlyStyles> = {}\nfunction getDefaultStyleFrame(ownerDoc: Document) {\n\tif (!defaultStyleFrame || defaultStyleFrame.ownerDocument !== ownerDoc) {\n\t\tdestroyDefaultStyleFrame()\n\t\tconst frame = ownerDoc.createElement('iframe')\n\t\tframe.style.display = 'none'\n\t\townerDoc.body.appendChild(frame)\n\t\tconst frameDocument = assertExists(frame.contentDocument, 'frame must have a document')\n\t\tconst svg = frameDocument.createElementNS('http://www.w3.org/2000/svg', 'svg')\n\t\tconst foreignObject = frameDocument.createElementNS(\n\t\t\t'http://www.w3.org/2000/svg',\n\t\t\t'foreignObject'\n\t\t)\n\t\tsvg.appendChild(foreignObject)\n\t\tframeDocument.body.appendChild(svg)\n\t\tdefaultStyleFrame = {\n\t\t\tiframe: frame,\n\t\t\tforeignObject,\n\t\t\tdocument: frameDocument,\n\t\t\townerDocument: ownerDoc,\n\t\t}\n\t}\n\treturn defaultStyleFrame\n}\n\nfunction destroyDefaultStyleFrame() {\n\tif (defaultStyleFrame) {\n\t\tdefaultStyleFrame.iframe.remove()\n\t\tdefaultStyleFrame = undefined\n\t}\n\tfor (const tagName in defaultStylesByTagName) {\n\t\tdelete defaultStylesByTagName[tagName]\n\t}\n}\n\nconst defaultStyleReadOptions: ReadStyleOpts = { defaultStyles: NO_STYLES, parentStyles: NO_STYLES }\nfunction getDefaultStylesForTagName(ownerDoc: Document, tagName: string) {\n\tlet existing = defaultStylesByTagName[tagName]\n\tif (!existing) {\n\t\tconst { foreignObject, document } = getDefaultStyleFrame(ownerDoc)\n\t\tconst element = document.createElement(tagName)\n\t\tforeignObject.appendChild(element)\n\t\texisting = element.computedStyleMap\n\t\t\t? styleFromComputedStyleMap(element.computedStyleMap(), defaultStyleReadOptions)\n\t\t\t: styleFromComputedStyle(getComputedStyle(element), defaultStyleReadOptions)\n\t\tforeignObject.removeChild(element)\n\t\tdefaultStylesByTagName[tagName] = existing\n\t}\n\treturn existing\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
7
|
}
|
|
@@ -20,6 +20,8 @@ var domUtils_exports = {};
|
|
|
20
20
|
__export(domUtils_exports, {
|
|
21
21
|
elementStyle: () => elementStyle,
|
|
22
22
|
getComputedStyle: () => getComputedStyle,
|
|
23
|
+
getOwnerDocument: () => getOwnerDocument,
|
|
24
|
+
getOwnerWindow: () => getOwnerWindow,
|
|
23
25
|
getRenderedChildNodes: () => getRenderedChildNodes,
|
|
24
26
|
getRenderedChildren: () => getRenderedChildren,
|
|
25
27
|
isElement: () => isElement
|
|
@@ -42,6 +44,19 @@ function* getRenderedChildren(node) {
|
|
|
42
44
|
if (isElement(child)) yield child;
|
|
43
45
|
}
|
|
44
46
|
}
|
|
47
|
+
function getOwnerWindow(nodeOrDocument) {
|
|
48
|
+
if (!nodeOrDocument) return globalThis;
|
|
49
|
+
const doc = isDocument(nodeOrDocument) ? nodeOrDocument : nodeOrDocument.ownerDocument;
|
|
50
|
+
return doc?.defaultView ?? globalThis;
|
|
51
|
+
}
|
|
52
|
+
function getOwnerDocument(nodeOrDocument) {
|
|
53
|
+
if (!nodeOrDocument) return globalThis.document;
|
|
54
|
+
if (isDocument(nodeOrDocument)) return nodeOrDocument;
|
|
55
|
+
return nodeOrDocument.ownerDocument ?? globalThis.document;
|
|
56
|
+
}
|
|
57
|
+
function isDocument(node) {
|
|
58
|
+
return node.nodeType === Node.DOCUMENT_NODE;
|
|
59
|
+
}
|
|
45
60
|
function getWindow(node) {
|
|
46
61
|
return node.ownerDocument?.defaultView ?? globalThis;
|
|
47
62
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/lib/exports/domUtils.ts"],
|
|
4
|
-
"sourcesContent": ["export function getRenderedChildNodes(node: Element): Iterable<Node> {\n\tif (node.shadowRoot) {\n\t\t// if this is a custom element with a shadow root, then it's the shadow root's children that\n\t\t// are visible in the DOM. This is only accessible if they created the shadow root with\n\t\t// `mode: 'open'` though.\n\t\treturn node.shadowRoot.childNodes\n\t}\n\tif (isShadowSlotElement(node)) {\n\t\t// if this is a `<slot>` within a shadow root, we should render the nodes that are being\n\t\t// templated into the slot instead of the slot children itself.\n\t\tconst assignedNodes = node.assignedNodes()\n\t\tif (assignedNodes?.length) {\n\t\t\treturn assignedNodes\n\t\t}\n\t}\n\treturn node.childNodes\n}\n\nexport function* getRenderedChildren(node: Element) {\n\tfor (const child of getRenderedChildNodes(node)) {\n\t\tif (isElement(child)) yield child\n\t}\n}\n\nfunction getWindow(node: Node) {\n\treturn node.ownerDocument?.defaultView ?? globalThis\n}\n\nexport function isElement(node: Node): node is Element {\n\treturn node instanceof getWindow(node).Element\n}\n\nfunction isShadowRoot(node: Node): node is ShadowRoot {\n\treturn node instanceof getWindow(node).ShadowRoot\n}\n\nfunction isInShadowRoot(node: Node) {\n\treturn 'getRootNode' in node && isShadowRoot(node.getRootNode())\n}\n\nfunction isShadowSlotElement(node: Node): node is HTMLSlotElement {\n\treturn isInShadowRoot(node) && node instanceof getWindow(node).HTMLSlotElement\n}\n\nexport function elementStyle(element: Element) {\n\treturn (element as HTMLElement | SVGElement).style\n}\n\nexport function getComputedStyle(element: Element, pseudoElement?: string) {\n\treturn getWindow(element).getComputedStyle(element, pseudoElement)\n}\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAO,SAAS,sBAAsB,MAA+B;AACpE,MAAI,KAAK,YAAY;AAIpB,WAAO,KAAK,WAAW;AAAA,EACxB;AACA,MAAI,oBAAoB,IAAI,GAAG;AAG9B,UAAM,gBAAgB,KAAK,cAAc;AACzC,QAAI,eAAe,QAAQ;AAC1B,aAAO;AAAA,IACR;AAAA,EACD;AACA,SAAO,KAAK;AACb;AAEO,UAAU,oBAAoB,MAAe;AACnD,aAAW,SAAS,sBAAsB,IAAI,GAAG;AAChD,QAAI,UAAU,KAAK,EAAG,OAAM;AAAA,EAC7B;AACD;AAEA,SAAS,UAAU,MAAY;AAC9B,SAAO,KAAK,eAAe,eAAe;AAC3C;AAEO,SAAS,UAAU,MAA6B;AACtD,SAAO,gBAAgB,UAAU,IAAI,EAAE;AACxC;AAEA,SAAS,aAAa,MAAgC;AACrD,SAAO,gBAAgB,UAAU,IAAI,EAAE;AACxC;AAEA,SAAS,eAAe,MAAY;AACnC,SAAO,iBAAiB,QAAQ,aAAa,KAAK,YAAY,CAAC;AAChE;AAEA,SAAS,oBAAoB,MAAqC;AACjE,SAAO,eAAe,IAAI,KAAK,gBAAgB,UAAU,IAAI,EAAE;AAChE;AAEO,SAAS,aAAa,SAAkB;AAC9C,SAAQ,QAAqC;AAC9C;AAEO,SAAS,iBAAiB,SAAkB,eAAwB;AAC1E,SAAO,UAAU,OAAO,EAAE,iBAAiB,SAAS,aAAa;AAClE;",
|
|
4
|
+
"sourcesContent": ["export function getRenderedChildNodes(node: Element): Iterable<Node> {\n\tif (node.shadowRoot) {\n\t\t// if this is a custom element with a shadow root, then it's the shadow root's children that\n\t\t// are visible in the DOM. This is only accessible if they created the shadow root with\n\t\t// `mode: 'open'` though.\n\t\treturn node.shadowRoot.childNodes\n\t}\n\tif (isShadowSlotElement(node)) {\n\t\t// if this is a `<slot>` within a shadow root, we should render the nodes that are being\n\t\t// templated into the slot instead of the slot children itself.\n\t\tconst assignedNodes = node.assignedNodes()\n\t\tif (assignedNodes?.length) {\n\t\t\treturn assignedNodes\n\t\t}\n\t}\n\treturn node.childNodes\n}\n\nexport function* getRenderedChildren(node: Element) {\n\tfor (const child of getRenderedChildNodes(node)) {\n\t\tif (isElement(child)) yield child\n\t}\n}\n\n/** @internal */\nexport function getOwnerWindow(\n\tnodeOrDocument: Node | Document | null | undefined\n): Window & typeof globalThis {\n\tif (!nodeOrDocument) return globalThis as Window & typeof globalThis\n\tconst doc = isDocument(nodeOrDocument) ? nodeOrDocument : nodeOrDocument.ownerDocument\n\treturn (doc?.defaultView ?? globalThis) as Window & typeof globalThis\n}\n\n/** @internal */\nexport function getOwnerDocument(nodeOrDocument: Node | Document | null | undefined): Document {\n\tif (!nodeOrDocument) return globalThis.document\n\tif (isDocument(nodeOrDocument)) return nodeOrDocument\n\treturn nodeOrDocument.ownerDocument ?? globalThis.document\n}\n\nfunction isDocument(node: Node | Document): node is Document {\n\treturn node.nodeType === Node.DOCUMENT_NODE\n}\n\nfunction getWindow(node: Node) {\n\treturn node.ownerDocument?.defaultView ?? globalThis\n}\n\nexport function isElement(node: Node): node is Element {\n\treturn node instanceof getWindow(node).Element\n}\n\nfunction isShadowRoot(node: Node): node is ShadowRoot {\n\treturn node instanceof getWindow(node).ShadowRoot\n}\n\nfunction isInShadowRoot(node: Node) {\n\treturn 'getRootNode' in node && isShadowRoot(node.getRootNode())\n}\n\nfunction isShadowSlotElement(node: Node): node is HTMLSlotElement {\n\treturn isInShadowRoot(node) && node instanceof getWindow(node).HTMLSlotElement\n}\n\nexport function elementStyle(element: Element) {\n\treturn (element as HTMLElement | SVGElement).style\n}\n\nexport function getComputedStyle(element: Element, pseudoElement?: string) {\n\treturn getWindow(element).getComputedStyle(element, pseudoElement)\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAO,SAAS,sBAAsB,MAA+B;AACpE,MAAI,KAAK,YAAY;AAIpB,WAAO,KAAK,WAAW;AAAA,EACxB;AACA,MAAI,oBAAoB,IAAI,GAAG;AAG9B,UAAM,gBAAgB,KAAK,cAAc;AACzC,QAAI,eAAe,QAAQ;AAC1B,aAAO;AAAA,IACR;AAAA,EACD;AACA,SAAO,KAAK;AACb;AAEO,UAAU,oBAAoB,MAAe;AACnD,aAAW,SAAS,sBAAsB,IAAI,GAAG;AAChD,QAAI,UAAU,KAAK,EAAG,OAAM;AAAA,EAC7B;AACD;AAGO,SAAS,eACf,gBAC6B;AAC7B,MAAI,CAAC,eAAgB,QAAO;AAC5B,QAAM,MAAM,WAAW,cAAc,IAAI,iBAAiB,eAAe;AACzE,SAAQ,KAAK,eAAe;AAC7B;AAGO,SAAS,iBAAiB,gBAA8D;AAC9F,MAAI,CAAC,eAAgB,QAAO,WAAW;AACvC,MAAI,WAAW,cAAc,EAAG,QAAO;AACvC,SAAO,eAAe,iBAAiB,WAAW;AACnD;AAEA,SAAS,WAAW,MAAyC;AAC5D,SAAO,KAAK,aAAa,KAAK;AAC/B;AAEA,SAAS,UAAU,MAAY;AAC9B,SAAO,KAAK,eAAe,eAAe;AAC3C;AAEO,SAAS,UAAU,MAA6B;AACtD,SAAO,gBAAgB,UAAU,IAAI,EAAE;AACxC;AAEA,SAAS,aAAa,MAAgC;AACrD,SAAO,gBAAgB,UAAU,IAAI,EAAE;AACxC;AAEA,SAAS,eAAe,MAAY;AACnC,SAAO,iBAAiB,QAAQ,aAAa,KAAK,YAAY,CAAC;AAChE;AAEA,SAAS,oBAAoB,MAAqC;AACjE,SAAO,eAAe,IAAI,KAAK,gBAAgB,UAAU,IAAI,EAAE;AAChE;AAEO,SAAS,aAAa,SAAkB;AAC9C,SAAQ,QAAqC;AAC9C;AAEO,SAAS,iBAAiB,SAAkB,eAAwB;AAC1E,SAAO,UAAU,OAAO,EAAE,iBAAiB,SAAS,aAAa;AAClE;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -34,8 +34,8 @@ function replace(original, replacement) {
|
|
|
34
34
|
original.replaceWith(replacement);
|
|
35
35
|
return replacement;
|
|
36
36
|
}
|
|
37
|
-
async function createImage(dataUrl, cloneAttributesFrom) {
|
|
38
|
-
const image =
|
|
37
|
+
async function createImage(doc, dataUrl, cloneAttributesFrom) {
|
|
38
|
+
const image = doc.createElement("img");
|
|
39
39
|
if (cloneAttributesFrom) {
|
|
40
40
|
copyAttrs(cloneAttributesFrom, image);
|
|
41
41
|
}
|
|
@@ -49,32 +49,35 @@ async function createImage(dataUrl, cloneAttributesFrom) {
|
|
|
49
49
|
return image;
|
|
50
50
|
}
|
|
51
51
|
async function getCanvasReplacement(canvas) {
|
|
52
|
+
const doc = canvas.ownerDocument;
|
|
52
53
|
try {
|
|
53
54
|
const dataURL = canvas.toDataURL();
|
|
54
|
-
return await createImage(dataURL, canvas);
|
|
55
|
+
return await createImage(doc, dataURL, canvas);
|
|
55
56
|
} catch {
|
|
56
|
-
return await createImage(null, canvas);
|
|
57
|
+
return await createImage(doc, null, canvas);
|
|
57
58
|
}
|
|
58
59
|
}
|
|
59
60
|
async function getVideoReplacement(video) {
|
|
61
|
+
const doc = video.ownerDocument;
|
|
60
62
|
try {
|
|
61
63
|
const dataUrl = await import_utils.MediaHelpers.getVideoFrameAsDataUrl(video);
|
|
62
|
-
return createImage(dataUrl, video);
|
|
64
|
+
return createImage(doc, dataUrl, video);
|
|
63
65
|
} catch (err) {
|
|
64
66
|
console.error("Could not get video frame", err);
|
|
65
67
|
}
|
|
66
68
|
if (video.poster) {
|
|
67
69
|
const dataUrl = await (0, import_fetchCache.resourceToDataUrl)(video.poster);
|
|
68
|
-
return createImage(dataUrl, video);
|
|
70
|
+
return createImage(doc, dataUrl, video);
|
|
69
71
|
}
|
|
70
|
-
return createImage(null, video);
|
|
72
|
+
return createImage(doc, null, video);
|
|
71
73
|
}
|
|
72
74
|
async function embedMedia(node) {
|
|
73
|
-
|
|
75
|
+
const win = (0, import_domUtils.getOwnerWindow)(node);
|
|
76
|
+
if (node instanceof win.HTMLCanvasElement) {
|
|
74
77
|
return replace(node, await getCanvasReplacement(node));
|
|
75
|
-
} else if (node instanceof HTMLVideoElement) {
|
|
78
|
+
} else if (node instanceof win.HTMLVideoElement) {
|
|
76
79
|
return replace(node, await getVideoReplacement(node));
|
|
77
|
-
} else if (node instanceof HTMLImageElement) {
|
|
80
|
+
} else if (node instanceof win.HTMLImageElement) {
|
|
78
81
|
const src = node.currentSrc || node.src;
|
|
79
82
|
const dataUrl = await (0, import_fetchCache.resourceToDataUrl)(src);
|
|
80
83
|
node.setAttribute("src", dataUrl ?? "data:");
|
|
@@ -85,9 +88,9 @@ async function embedMedia(node) {
|
|
|
85
88
|
} catch {
|
|
86
89
|
}
|
|
87
90
|
return node;
|
|
88
|
-
} else if (node instanceof HTMLInputElement) {
|
|
91
|
+
} else if (node instanceof win.HTMLInputElement) {
|
|
89
92
|
node.setAttribute("value", node.value);
|
|
90
|
-
} else if (node instanceof HTMLTextAreaElement) {
|
|
93
|
+
} else if (node instanceof win.HTMLTextAreaElement) {
|
|
91
94
|
node.textContent = node.value;
|
|
92
95
|
}
|
|
93
96
|
await Promise.all(
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/lib/exports/embedMedia.ts"],
|
|
4
|
-
"sourcesContent": ["import { MediaHelpers } from '@tldraw/utils'\nimport { getRenderedChildren } from './domUtils'\nimport { resourceToDataUrl } from './fetchCache'\n\nfunction copyAttrs(source: Element, target: Element) {\n\tconst attrs = Array.from(source.attributes)\n\tattrs.forEach((attr) => {\n\t\ttarget.setAttribute(attr.name, attr.value)\n\t})\n}\n\nfunction replace(original: HTMLElement, replacement: HTMLElement) {\n\toriginal.replaceWith(replacement)\n\treturn replacement\n}\n\nasync function createImage(
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAA6B;AAC7B,
|
|
4
|
+
"sourcesContent": ["import { MediaHelpers } from '@tldraw/utils'\nimport { getOwnerWindow, getRenderedChildren } from './domUtils'\nimport { resourceToDataUrl } from './fetchCache'\n\nfunction copyAttrs(source: Element, target: Element) {\n\tconst attrs = Array.from(source.attributes)\n\tattrs.forEach((attr) => {\n\t\ttarget.setAttribute(attr.name, attr.value)\n\t})\n}\n\nfunction replace(original: HTMLElement, replacement: HTMLElement) {\n\toriginal.replaceWith(replacement)\n\treturn replacement\n}\n\nasync function createImage(\n\tdoc: Document,\n\tdataUrl: string | null,\n\tcloneAttributesFrom?: HTMLElement\n) {\n\tconst image = doc.createElement('img')\n\n\tif (cloneAttributesFrom) {\n\t\tcopyAttrs(cloneAttributesFrom, image)\n\t}\n\n\timage.setAttribute('src', dataUrl ?? 'data:')\n\timage.setAttribute('decoding', 'sync')\n\timage.setAttribute('loading', 'eager')\n\n\ttry {\n\t\tawait image.decode()\n\t} catch {\n\t\t// this is fine\n\t}\n\treturn image\n}\n\nasync function getCanvasReplacement(canvas: HTMLCanvasElement) {\n\tconst doc = canvas.ownerDocument\n\ttry {\n\t\tconst dataURL = canvas.toDataURL()\n\t\treturn await createImage(doc, dataURL, canvas)\n\t} catch {\n\t\treturn await createImage(doc, null, canvas)\n\t}\n}\n\nasync function getVideoReplacement(video: HTMLVideoElement) {\n\tconst doc = video.ownerDocument\n\ttry {\n\t\tconst dataUrl = await MediaHelpers.getVideoFrameAsDataUrl(video)\n\t\treturn createImage(doc, dataUrl, video)\n\t} catch (err) {\n\t\tconsole.error('Could not get video frame', err)\n\t}\n\n\tif (video.poster) {\n\t\tconst dataUrl = await resourceToDataUrl(video.poster)\n\t\treturn createImage(doc, dataUrl, video)\n\t}\n\n\treturn createImage(doc, null, video)\n}\n\nexport async function embedMedia(node: HTMLElement) {\n\tconst win = getOwnerWindow(node)\n\tif (node instanceof win.HTMLCanvasElement) {\n\t\treturn replace(node, await getCanvasReplacement(node))\n\t} else if (node instanceof win.HTMLVideoElement) {\n\t\treturn replace(node, await getVideoReplacement(node))\n\t} else if (node instanceof win.HTMLImageElement) {\n\t\tconst src = node.currentSrc || node.src\n\t\tconst dataUrl = await resourceToDataUrl(src)\n\t\tnode.setAttribute('src', dataUrl ?? 'data:')\n\t\tnode.setAttribute('decoding', 'sync')\n\t\tnode.setAttribute('loading', 'eager')\n\t\ttry {\n\t\t\tawait (node as HTMLImageElement).decode()\n\t\t} catch {\n\t\t\t// this is fine\n\t\t}\n\t\treturn node\n\t} else if (node instanceof win.HTMLInputElement) {\n\t\tnode.setAttribute('value', (node as HTMLInputElement).value)\n\t} else if (node instanceof win.HTMLTextAreaElement) {\n\t\tnode.textContent = (node as HTMLTextAreaElement).value\n\t}\n\n\tawait Promise.all(\n\t\tArray.from(getRenderedChildren(node), (child) => embedMedia(child as HTMLElement))\n\t)\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAA6B;AAC7B,sBAAoD;AACpD,wBAAkC;AAElC,SAAS,UAAU,QAAiB,QAAiB;AACpD,QAAM,QAAQ,MAAM,KAAK,OAAO,UAAU;AAC1C,QAAM,QAAQ,CAAC,SAAS;AACvB,WAAO,aAAa,KAAK,MAAM,KAAK,KAAK;AAAA,EAC1C,CAAC;AACF;AAEA,SAAS,QAAQ,UAAuB,aAA0B;AACjE,WAAS,YAAY,WAAW;AAChC,SAAO;AACR;AAEA,eAAe,YACd,KACA,SACA,qBACC;AACD,QAAM,QAAQ,IAAI,cAAc,KAAK;AAErC,MAAI,qBAAqB;AACxB,cAAU,qBAAqB,KAAK;AAAA,EACrC;AAEA,QAAM,aAAa,OAAO,WAAW,OAAO;AAC5C,QAAM,aAAa,YAAY,MAAM;AACrC,QAAM,aAAa,WAAW,OAAO;AAErC,MAAI;AACH,UAAM,MAAM,OAAO;AAAA,EACpB,QAAQ;AAAA,EAER;AACA,SAAO;AACR;AAEA,eAAe,qBAAqB,QAA2B;AAC9D,QAAM,MAAM,OAAO;AACnB,MAAI;AACH,UAAM,UAAU,OAAO,UAAU;AACjC,WAAO,MAAM,YAAY,KAAK,SAAS,MAAM;AAAA,EAC9C,QAAQ;AACP,WAAO,MAAM,YAAY,KAAK,MAAM,MAAM;AAAA,EAC3C;AACD;AAEA,eAAe,oBAAoB,OAAyB;AAC3D,QAAM,MAAM,MAAM;AAClB,MAAI;AACH,UAAM,UAAU,MAAM,0BAAa,uBAAuB,KAAK;AAC/D,WAAO,YAAY,KAAK,SAAS,KAAK;AAAA,EACvC,SAAS,KAAK;AACb,YAAQ,MAAM,6BAA6B,GAAG;AAAA,EAC/C;AAEA,MAAI,MAAM,QAAQ;AACjB,UAAM,UAAU,UAAM,qCAAkB,MAAM,MAAM;AACpD,WAAO,YAAY,KAAK,SAAS,KAAK;AAAA,EACvC;AAEA,SAAO,YAAY,KAAK,MAAM,KAAK;AACpC;AAEA,eAAsB,WAAW,MAAmB;AACnD,QAAM,UAAM,gCAAe,IAAI;AAC/B,MAAI,gBAAgB,IAAI,mBAAmB;AAC1C,WAAO,QAAQ,MAAM,MAAM,qBAAqB,IAAI,CAAC;AAAA,EACtD,WAAW,gBAAgB,IAAI,kBAAkB;AAChD,WAAO,QAAQ,MAAM,MAAM,oBAAoB,IAAI,CAAC;AAAA,EACrD,WAAW,gBAAgB,IAAI,kBAAkB;AAChD,UAAM,MAAM,KAAK,cAAc,KAAK;AACpC,UAAM,UAAU,UAAM,qCAAkB,GAAG;AAC3C,SAAK,aAAa,OAAO,WAAW,OAAO;AAC3C,SAAK,aAAa,YAAY,MAAM;AACpC,SAAK,aAAa,WAAW,OAAO;AACpC,QAAI;AACH,YAAO,KAA0B,OAAO;AAAA,IACzC,QAAQ;AAAA,IAER;AACA,WAAO;AAAA,EACR,WAAW,gBAAgB,IAAI,kBAAkB;AAChD,SAAK,aAAa,SAAU,KAA0B,KAAK;AAAA,EAC5D,WAAW,gBAAgB,IAAI,qBAAqB;AACnD,SAAK,cAAe,KAA6B;AAAA,EAClD;AAEA,QAAM,QAAQ;AAAA,IACb,MAAM,SAAK,qCAAoB,IAAI,GAAG,CAAC,UAAU,WAAW,KAAoB,CAAC;AAAA,EAClF;AACD;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -24,16 +24,17 @@ module.exports = __toCommonJS(exportToSvg_exports);
|
|
|
24
24
|
var import_utils = require("@tldraw/utils");
|
|
25
25
|
var import_react_dom = require("react-dom");
|
|
26
26
|
var import_client = require("react-dom/client");
|
|
27
|
-
var
|
|
28
|
-
var import_StyleEmbedder = require("./StyleEmbedder");
|
|
27
|
+
var import_domUtils = require("./domUtils");
|
|
29
28
|
var import_embedMedia = require("./embedMedia");
|
|
29
|
+
var import_FontEmbedder = require("./FontEmbedder");
|
|
30
30
|
var import_getSvgJsx = require("./getSvgJsx");
|
|
31
|
+
var import_StyleEmbedder = require("./StyleEmbedder");
|
|
31
32
|
let idCounter = 1;
|
|
32
33
|
async function exportToSvg(editor, shapeIds, opts = {}) {
|
|
33
34
|
const result = (0, import_getSvgJsx.getSvgJsx)(editor, shapeIds, opts);
|
|
34
35
|
if (!result) return void 0;
|
|
35
36
|
const container = editor.getContainer();
|
|
36
|
-
const renderTarget =
|
|
37
|
+
const renderTarget = container.ownerDocument.createElement("div");
|
|
37
38
|
renderTarget.className = import_FontEmbedder.SVG_EXPORT_CLASSNAME;
|
|
38
39
|
renderTarget.inert = true;
|
|
39
40
|
renderTarget.tabIndex = -1;
|
|
@@ -55,9 +56,9 @@ async function exportToSvg(editor, shapeIds, opts = {}) {
|
|
|
55
56
|
});
|
|
56
57
|
await result.exportDelay.resolve();
|
|
57
58
|
const svg = renderTarget.firstElementChild;
|
|
58
|
-
(0, import_utils.assert)(svg instanceof SVGSVGElement, "Expected an SVG element");
|
|
59
|
+
(0, import_utils.assert)(svg instanceof (0, import_domUtils.getOwnerWindow)(container).SVGSVGElement, "Expected an SVG element");
|
|
59
60
|
await applyChangesToForeignObjects(svg);
|
|
60
|
-
return { svg, width: result.width, height: result.height };
|
|
61
|
+
return { svg, width: result.width, height: result.height, trimPadding: result.trimPadding };
|
|
61
62
|
} finally {
|
|
62
63
|
setTimeout(() => {
|
|
63
64
|
root.unmount();
|
|
@@ -72,7 +73,7 @@ async function applyChangesToForeignObjects(svg) {
|
|
|
72
73
|
if (!foreignObjectChildren.length) return;
|
|
73
74
|
const styleEmbedder = new import_StyleEmbedder.StyleEmbedder(svg);
|
|
74
75
|
try {
|
|
75
|
-
styleEmbedder.fonts.
|
|
76
|
+
styleEmbedder.fonts.startFindingDocumentFontFaces(svg.ownerDocument);
|
|
76
77
|
await Promise.all(foreignObjectChildren.map((el) => (0, import_embedMedia.embedMedia)(el)));
|
|
77
78
|
for (const el of foreignObjectChildren) {
|
|
78
79
|
styleEmbedder.readRootElementStyles(el);
|
|
@@ -82,7 +83,7 @@ async function applyChangesToForeignObjects(svg) {
|
|
|
82
83
|
styleEmbedder.unwrapCustomElements();
|
|
83
84
|
const pseudoCss = styleEmbedder.embedStyles();
|
|
84
85
|
if (fontCss || pseudoCss) {
|
|
85
|
-
const style =
|
|
86
|
+
const style = svg.ownerDocument.createElementNS("http://www.w3.org/2000/svg", "style");
|
|
86
87
|
style.textContent = `${fontCss}
|
|
87
88
|
${pseudoCss}`;
|
|
88
89
|
svg.prepend(style);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/lib/exports/exportToSvg.tsx"],
|
|
4
|
-
"sourcesContent": ["import { TLShapeId } from '@tldraw/tlschema'\nimport { assert } from '@tldraw/utils'\nimport { flushSync } from 'react-dom'\nimport { createRoot } from 'react-dom/client'\nimport type { Editor } from '../editor/Editor'\nimport { TLSvgExportOptions } from '../editor/types/misc-types'\nimport {
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,mBAAuB;AACvB,uBAA0B;AAC1B,oBAA2B;AAG3B,
|
|
4
|
+
"sourcesContent": ["import { TLShapeId } from '@tldraw/tlschema'\nimport { assert } from '@tldraw/utils'\nimport { flushSync } from 'react-dom'\nimport { createRoot } from 'react-dom/client'\nimport type { Editor } from '../editor/Editor'\nimport { TLSvgExportOptions } from '../editor/types/misc-types'\nimport { getOwnerWindow } from './domUtils'\nimport { embedMedia } from './embedMedia'\nimport { SVG_EXPORT_CLASSNAME } from './FontEmbedder'\nimport { getSvgJsx } from './getSvgJsx'\nimport { StyleEmbedder } from './StyleEmbedder'\n\nlet idCounter = 1\n\nexport async function exportToSvg(\n\teditor: Editor,\n\tshapeIds: TLShapeId[],\n\topts: TLSvgExportOptions = {}\n) {\n\t// when rendering to SVG, we start by creating a JSX representation of the SVG that we can\n\t// render with react. Hopefully elements will have a `toSvg` method that renders them to SVG,\n\t// but if they don't we'll render their normal HTML content into an svg <foreignObject> element.\n\tconst result = getSvgJsx(editor, shapeIds, opts)\n\tif (!result) return undefined\n\n\t// we need to render that SVG into a real DOM element that's actually laid out in the document.\n\t// without this CSS and layout aren't computed correctly, which we need to make sure any\n\t// <foreignObject> elements have their styles and content inlined correctly.\n\tconst container = editor.getContainer()\n\tconst renderTarget = container.ownerDocument.createElement('div')\n\trenderTarget.className = SVG_EXPORT_CLASSNAME\n\t// we hide the element visually, but we don't want it to be focusable or interactive in any way either\n\trenderTarget.inert = true\n\trenderTarget.tabIndex = -1\n\tObject.assign(renderTarget.style, {\n\t\tposition: 'absolute',\n\t\ttop: '0px',\n\t\tleft: '0px',\n\t\twidth: result.width + 'px',\n\t\theight: result.height + 'px',\n\t\tpointerEvents: 'none',\n\t\topacity: 0,\n\t})\n\t// we have to add the element to the document as otherwise styles won't be computed correctly.\n\tcontainer.appendChild(renderTarget)\n\n\t// create a react root...\n\tconst root = createRoot(renderTarget, { identifierPrefix: `export_${idCounter++}_` })\n\ttry {\n\t\t// ...wait for a tick so we know we're not in e.g. a react lifecycle method...\n\t\tawait Promise.resolve()\n\n\t\t// ...and render the SVG into it.\n\t\tflushSync(() => {\n\t\t\troot.render(result.jsx)\n\t\t})\n\n\t\t// Some operations take a while - for example, waiting for an asset to load in. We give\n\t\t// shape authors a way to delay snap-shotting the export until they're ready.\n\t\tawait result.exportDelay.resolve()\n\n\t\t// Extract the rendered SVG element from the react root\n\t\tconst svg = renderTarget.firstElementChild\n\t\tassert(svg instanceof getOwnerWindow(container).SVGSVGElement, 'Expected an SVG element')\n\n\t\t// And apply any changes to <foreignObject> elements that we need to make. while we're in\n\t\t// the document, these elements work exactly as we'd expect from other dom elements - they\n\t\t// can load external resources, and any stylesheets in the document apply to them as we\n\t\t// would expect them to. But when we pull the SVG into its own file or draw it to a canvas\n\t\t// though, it has to be completely self-contained. We embed any external resources, and\n\t\t// apply any styles directly to the elements themselves.\n\t\tawait applyChangesToForeignObjects(svg)\n\n\t\treturn { svg, width: result.width, height: result.height, trimPadding: result.trimPadding }\n\t} finally {\n\t\t// eslint-disable-next-line no-restricted-globals\n\t\tsetTimeout(() => {\n\t\t\t// we wait for a cycle of the event loop to allow the svg to be cloned etc. before\n\t\t\t// unmounting\n\t\t\troot.unmount()\n\t\t\tcontainer.removeChild(renderTarget)\n\t\t}, 0)\n\t}\n}\n\nasync function applyChangesToForeignObjects(svg: SVGSVGElement) {\n\t// If any shapes have their own <foreignObject> elements, we don't want to mess with them. Our\n\t// ones that we need to embed will have a class of `tl-export-embed-styles`.\n\tconst foreignObjectChildren = [\n\t\t...svg.querySelectorAll('foreignObject.tl-export-embed-styles > *'),\n\t]\n\tif (!foreignObjectChildren.length) return\n\n\t// StyleEmbedder embeds any CSS - including resources like fonts and images.\n\tconst styleEmbedder = new StyleEmbedder(svg)\n\n\ttry {\n\t\t// begin traversing stylesheets to find @font-face declarations we might need to embed\n\t\tstyleEmbedder.fonts.startFindingDocumentFontFaces(svg.ownerDocument)\n\n\t\t// embed any media elements in the foreignObject children. images will get converted to data\n\t\t// urls, and things like videos will be converted to images.\n\t\tawait Promise.all(foreignObjectChildren.map((el) => embedMedia(el as HTMLElement)))\n\n\t\t// read the computed styles of every element (+ it's children & pseudo-elements) in the\n\t\t// document. we do this in a single pass before we start embedding any CSS stuff to avoid\n\t\t// constantly forcing the browser to recompute styles & layout.\n\t\tfor (const el of foreignObjectChildren) {\n\t\t\tstyleEmbedder.readRootElementStyles(el as HTMLElement)\n\t\t}\n\n\t\t// fetch any resources that we need to embed in the CSS, like background images.\n\t\tawait styleEmbedder.fetchResources()\n\t\tconst fontCss = await styleEmbedder.getFontFaceCss()\n\n\t\t// custom elements that make use of the shadow dom won't be serialized correctly by default:\n\t\t// the contents of the shadow dom will be ignored. once we've read the styles from the\n\t\t// document, we go through and replace any custom elements with plain `<div>`s. as we do so,\n\t\t// we traverse the shadow dom and clone it into the new plain div. any scoped stylesheets\n\t\t// are removed, as we've already read all the computed styles above.\n\t\tstyleEmbedder.unwrapCustomElements()\n\n\t\t// apply the computed styles (with their embedded resources) directly to the elements with\n\t\t// their `style` attribute. Anything that can't be done this way (pseudo-elements) will be\n\t\t// returned as a string of CSS.\n\t\tconst pseudoCss = styleEmbedder.embedStyles()\n\n\t\t// add the CSS to the SVG\n\t\tif (fontCss || pseudoCss) {\n\t\t\tconst style = svg.ownerDocument.createElementNS('http://www.w3.org/2000/svg', 'style')\n\t\t\tstyle.textContent = `${fontCss}\\n${pseudoCss}`\n\t\t\tsvg.prepend(style)\n\t\t}\n\t} finally {\n\t\tstyleEmbedder.dispose()\n\t}\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,mBAAuB;AACvB,uBAA0B;AAC1B,oBAA2B;AAG3B,sBAA+B;AAC/B,wBAA2B;AAC3B,0BAAqC;AACrC,uBAA0B;AAC1B,2BAA8B;AAE9B,IAAI,YAAY;AAEhB,eAAsB,YACrB,QACA,UACA,OAA2B,CAAC,GAC3B;AAID,QAAM,aAAS,4BAAU,QAAQ,UAAU,IAAI;AAC/C,MAAI,CAAC,OAAQ,QAAO;AAKpB,QAAM,YAAY,OAAO,aAAa;AACtC,QAAM,eAAe,UAAU,cAAc,cAAc,KAAK;AAChE,eAAa,YAAY;AAEzB,eAAa,QAAQ;AACrB,eAAa,WAAW;AACxB,SAAO,OAAO,aAAa,OAAO;AAAA,IACjC,UAAU;AAAA,IACV,KAAK;AAAA,IACL,MAAM;AAAA,IACN,OAAO,OAAO,QAAQ;AAAA,IACtB,QAAQ,OAAO,SAAS;AAAA,IACxB,eAAe;AAAA,IACf,SAAS;AAAA,EACV,CAAC;AAED,YAAU,YAAY,YAAY;AAGlC,QAAM,WAAO,0BAAW,cAAc,EAAE,kBAAkB,UAAU,WAAW,IAAI,CAAC;AACpF,MAAI;AAEH,UAAM,QAAQ,QAAQ;AAGtB,oCAAU,MAAM;AACf,WAAK,OAAO,OAAO,GAAG;AAAA,IACvB,CAAC;AAID,UAAM,OAAO,YAAY,QAAQ;AAGjC,UAAM,MAAM,aAAa;AACzB,6BAAO,mBAAe,gCAAe,SAAS,EAAE,eAAe,yBAAyB;AAQxF,UAAM,6BAA6B,GAAG;AAEtC,WAAO,EAAE,KAAK,OAAO,OAAO,OAAO,QAAQ,OAAO,QAAQ,aAAa,OAAO,YAAY;AAAA,EAC3F,UAAE;AAED,eAAW,MAAM;AAGhB,WAAK,QAAQ;AACb,gBAAU,YAAY,YAAY;AAAA,IACnC,GAAG,CAAC;AAAA,EACL;AACD;AAEA,eAAe,6BAA6B,KAAoB;AAG/D,QAAM,wBAAwB;AAAA,IAC7B,GAAG,IAAI,iBAAiB,0CAA0C;AAAA,EACnE;AACA,MAAI,CAAC,sBAAsB,OAAQ;AAGnC,QAAM,gBAAgB,IAAI,mCAAc,GAAG;AAE3C,MAAI;AAEH,kBAAc,MAAM,8BAA8B,IAAI,aAAa;AAInE,UAAM,QAAQ,IAAI,sBAAsB,IAAI,CAAC,WAAO,8BAAW,EAAiB,CAAC,CAAC;AAKlF,eAAW,MAAM,uBAAuB;AACvC,oBAAc,sBAAsB,EAAiB;AAAA,IACtD;AAGA,UAAM,cAAc,eAAe;AACnC,UAAM,UAAU,MAAM,cAAc,eAAe;AAOnD,kBAAc,qBAAqB;AAKnC,UAAM,YAAY,cAAc,YAAY;AAG5C,QAAI,WAAW,WAAW;AACzB,YAAM,QAAQ,IAAI,cAAc,gBAAgB,8BAA8B,OAAO;AACrF,YAAM,cAAc,GAAG,OAAO;AAAA,EAAK,SAAS;AAC5C,UAAI,QAAQ,KAAK;AAAA,IAClB;AAAA,EACD,UAAE;AACD,kBAAc,QAAQ;AAAA,EACvB;AACD;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|