@tldraw/editor 3.12.0-canary.d81bcb86d4e7 → 3.12.0-canary.e333011facbe
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 +40 -3
- package/dist-cjs/index.js +1 -1
- package/dist-cjs/lib/TldrawEditor.js +4 -0
- package/dist-cjs/lib/TldrawEditor.js.map +2 -2
- package/dist-cjs/lib/editor/Editor.js +24 -8
- package/dist-cjs/lib/editor/Editor.js.map +2 -2
- package/dist-cjs/lib/exports/StyleEmbedder.js +19 -5
- package/dist-cjs/lib/exports/StyleEmbedder.js.map +2 -2
- package/dist-cjs/lib/exports/cssRules.js +127 -0
- package/dist-cjs/lib/exports/cssRules.js.map +7 -0
- package/dist-cjs/lib/exports/parseCss.js +0 -69
- package/dist-cjs/lib/exports/parseCss.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 +40 -3
- package/dist-esm/index.mjs +1 -1
- package/dist-esm/lib/TldrawEditor.mjs +4 -0
- package/dist-esm/lib/TldrawEditor.mjs.map +2 -2
- package/dist-esm/lib/editor/Editor.mjs +24 -8
- package/dist-esm/lib/editor/Editor.mjs.map +2 -2
- package/dist-esm/lib/exports/StyleEmbedder.mjs +21 -12
- package/dist-esm/lib/exports/StyleEmbedder.mjs.map +2 -2
- package/dist-esm/lib/exports/cssRules.mjs +107 -0
- package/dist-esm/lib/exports/cssRules.mjs.map +7 -0
- package/dist-esm/lib/exports/parseCss.mjs +0 -69
- package/dist-esm/lib/exports/parseCss.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/lib/TldrawEditor.tsx +27 -1
- package/src/lib/editor/Editor.ts +52 -8
- package/src/lib/exports/StyleEmbedder.ts +25 -15
- package/src/lib/exports/cssRules.ts +126 -0
- package/src/lib/exports/parseCss.ts +0 -79
- package/src/version.ts +3 -3
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { assertExists, objectMapValues, uniqueId } from "@tldraw/utils";
|
|
1
|
+
import { assertExists, getOwnProperty, objectMapValues, uniqueId } from "@tldraw/utils";
|
|
2
2
|
import { FontEmbedder } from "./FontEmbedder.mjs";
|
|
3
|
+
import { cssRules } from "./cssRules.mjs";
|
|
3
4
|
import {
|
|
4
5
|
elementStyle,
|
|
5
6
|
getComputedStyle,
|
|
@@ -7,12 +8,7 @@ import {
|
|
|
7
8
|
getRenderedChildren
|
|
8
9
|
} from "./domUtils.mjs";
|
|
9
10
|
import { resourceToDataUrl } from "./fetchCache.mjs";
|
|
10
|
-
import {
|
|
11
|
-
isPropertyCoveredByCurrentColor,
|
|
12
|
-
isPropertyInherited,
|
|
13
|
-
parseCssValueUrls,
|
|
14
|
-
shouldIncludeCssProperty
|
|
15
|
-
} from "./parseCss.mjs";
|
|
11
|
+
import { parseCssValueUrls, shouldIncludeCssProperty } from "./parseCss.mjs";
|
|
16
12
|
const NO_STYLES = {};
|
|
17
13
|
class StyleEmbedder {
|
|
18
14
|
constructor(root) {
|
|
@@ -171,25 +167,38 @@ function styleFromPseudoElement(element, pseudo) {
|
|
|
171
167
|
}
|
|
172
168
|
function styleFromComputedStyleMap(style, { defaultStyles, parentStyles }) {
|
|
173
169
|
const styles = {};
|
|
170
|
+
const currentColor = style.get("color")?.toString() || "";
|
|
171
|
+
const ruleOptions = {
|
|
172
|
+
currentColor,
|
|
173
|
+
parentStyles,
|
|
174
|
+
defaultStyles,
|
|
175
|
+
getStyle: (property) => style.get(property)?.toString() ?? ""
|
|
176
|
+
};
|
|
174
177
|
for (const property of style.keys()) {
|
|
175
178
|
if (!shouldIncludeCssProperty(property)) continue;
|
|
176
179
|
const value = style.get(property).toString();
|
|
177
180
|
if (defaultStyles[property] === value) continue;
|
|
178
|
-
|
|
179
|
-
if (
|
|
180
|
-
continue;
|
|
181
|
+
const rule = getOwnProperty(cssRules, property);
|
|
182
|
+
if (rule && rule(value, property, ruleOptions)) continue;
|
|
181
183
|
styles[property] = value;
|
|
182
184
|
}
|
|
183
185
|
return styles;
|
|
184
186
|
}
|
|
185
187
|
function styleFromComputedStyle(style, { defaultStyles, parentStyles }) {
|
|
186
188
|
const styles = {};
|
|
189
|
+
const currentColor = style.color;
|
|
190
|
+
const ruleOptions = {
|
|
191
|
+
currentColor,
|
|
192
|
+
parentStyles,
|
|
193
|
+
defaultStyles,
|
|
194
|
+
getStyle: (property) => style.getPropertyValue(property)
|
|
195
|
+
};
|
|
187
196
|
for (const property in style) {
|
|
188
197
|
if (!shouldIncludeCssProperty(property)) continue;
|
|
189
198
|
const value = style.getPropertyValue(property);
|
|
190
199
|
if (defaultStyles[property] === value) continue;
|
|
191
|
-
|
|
192
|
-
if (
|
|
200
|
+
const rule = getOwnProperty(cssRules, property);
|
|
201
|
+
if (rule && rule(value, property, ruleOptions)) continue;
|
|
193
202
|
styles[property] = value;
|
|
194
203
|
}
|
|
195
204
|
return styles;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/lib/exports/StyleEmbedder.ts"],
|
|
4
|
-
"sourcesContent": ["import { assertExists, objectMapValues, uniqueId } from '@tldraw/utils'\nimport { FontEmbedder } from './FontEmbedder'\nimport {\n\telementStyle,\n\tgetComputedStyle,\n\tgetRenderedChildNodes,\n\tgetRenderedChildren,\n} from './domUtils'\nimport { resourceToDataUrl } from './fetchCache'\nimport {\n\tisPropertyCoveredByCurrentColor,\n\tisPropertyInherited,\n\tparseCssValueUrls,\n\tshouldIncludeCssProperty,\n} from './parseCss'\n\ntype Styles = { [K in string]?: string }\ntype ReadonlyStyles = { readonly [K in string]?: string }\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\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\t\tif (parentStyles[property] === value && isPropertyInherited(property)) continue\n\t\tif (isPropertyCoveredByCurrentColor(style.get('color')?.toString() || '', property, value))\n\t\t\tcontinue\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\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\t\tif (parentStyles[property] === value && isPropertyInherited(property)) continue\n\t\tif (isPropertyCoveredByCurrentColor(style.color, property, value)) 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,SAAS,cAAc,iBAAiB,gBAAgB;
|
|
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": "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",
|
|
6
6
|
"names": ["document"]
|
|
7
7
|
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
const isCoveredByCurrentColor = (value, property, { currentColor }) => {
|
|
2
|
+
return value === "currentColor" || value === currentColor;
|
|
3
|
+
};
|
|
4
|
+
const isInherited = (value, property, { parentStyles }) => {
|
|
5
|
+
return parentStyles[property] === value;
|
|
6
|
+
};
|
|
7
|
+
const isExcludedBorder = (borderDirection) => (value, property, { getStyle }) => {
|
|
8
|
+
const borderWidth = getStyle(`border-${borderDirection}-width`);
|
|
9
|
+
const borderStyle = getStyle(`border-${borderDirection}-style`);
|
|
10
|
+
if (borderWidth === "0px") return true;
|
|
11
|
+
if (borderStyle === "none") return true;
|
|
12
|
+
return false;
|
|
13
|
+
};
|
|
14
|
+
const cssRules = {
|
|
15
|
+
// currentColor properties:
|
|
16
|
+
"border-block-end-color": isCoveredByCurrentColor,
|
|
17
|
+
"border-block-start-color": isCoveredByCurrentColor,
|
|
18
|
+
"border-bottom-color": isCoveredByCurrentColor,
|
|
19
|
+
"border-inline-end-color": isCoveredByCurrentColor,
|
|
20
|
+
"border-inline-start-color": isCoveredByCurrentColor,
|
|
21
|
+
"border-left-color": isCoveredByCurrentColor,
|
|
22
|
+
"border-right-color": isCoveredByCurrentColor,
|
|
23
|
+
"border-top-color": isCoveredByCurrentColor,
|
|
24
|
+
"caret-color": isCoveredByCurrentColor,
|
|
25
|
+
"column-rule-color": isCoveredByCurrentColor,
|
|
26
|
+
"outline-color": isCoveredByCurrentColor,
|
|
27
|
+
"text-decoration": (value, property, { currentColor }) => {
|
|
28
|
+
return value === "none solid currentColor" || value === "none solid " + currentColor;
|
|
29
|
+
},
|
|
30
|
+
"text-decoration-color": isCoveredByCurrentColor,
|
|
31
|
+
"text-emphasis-color": isCoveredByCurrentColor,
|
|
32
|
+
// inherited properties:
|
|
33
|
+
"border-collapse": isInherited,
|
|
34
|
+
"border-spacing": isInherited,
|
|
35
|
+
"caption-side": isInherited,
|
|
36
|
+
// N.B. We shouldn't inherit 'color' because there's some UA styling, e.g. `mark` elements
|
|
37
|
+
// 'color': isInherited,
|
|
38
|
+
cursor: isInherited,
|
|
39
|
+
direction: isInherited,
|
|
40
|
+
"empty-cells": isInherited,
|
|
41
|
+
"font-family": isInherited,
|
|
42
|
+
"font-size": isInherited,
|
|
43
|
+
"font-style": isInherited,
|
|
44
|
+
"font-variant": isInherited,
|
|
45
|
+
"font-weight": isInherited,
|
|
46
|
+
"font-size-adjust": isInherited,
|
|
47
|
+
"font-stretch": isInherited,
|
|
48
|
+
font: isInherited,
|
|
49
|
+
"letter-spacing": isInherited,
|
|
50
|
+
"line-height": isInherited,
|
|
51
|
+
"list-style-image": isInherited,
|
|
52
|
+
"list-style-position": isInherited,
|
|
53
|
+
"list-style-type": isInherited,
|
|
54
|
+
"list-style": isInherited,
|
|
55
|
+
orphans: isInherited,
|
|
56
|
+
"overflow-wrap": isInherited,
|
|
57
|
+
quotes: isInherited,
|
|
58
|
+
"stroke-linecap": isInherited,
|
|
59
|
+
"stroke-linejoin": isInherited,
|
|
60
|
+
"tab-size": isInherited,
|
|
61
|
+
"text-align": isInherited,
|
|
62
|
+
"text-align-last": isInherited,
|
|
63
|
+
"text-indent": isInherited,
|
|
64
|
+
"text-justify": isInherited,
|
|
65
|
+
"text-shadow": isInherited,
|
|
66
|
+
"text-transform": isInherited,
|
|
67
|
+
visibility: isInherited,
|
|
68
|
+
"white-space": isInherited,
|
|
69
|
+
"white-space-collapse": isInherited,
|
|
70
|
+
widows: isInherited,
|
|
71
|
+
"word-break": isInherited,
|
|
72
|
+
"word-spacing": isInherited,
|
|
73
|
+
"word-wrap": isInherited,
|
|
74
|
+
// special border cases - we have a weird case (tailwind seems to trigger this) where all
|
|
75
|
+
// border-styles sometimes get set to 'solid', but the border-width is 0 so they don't render.
|
|
76
|
+
// but in SVGs, **sometimes**, the border-width defaults (i think from a UA style-sheet? but
|
|
77
|
+
// honestly can't tell) to 1.5px so the border displays. we work around this by only including
|
|
78
|
+
// border styles at all if both the border-width and border-style are set to something that
|
|
79
|
+
// would show a border.
|
|
80
|
+
"border-top": isExcludedBorder("top"),
|
|
81
|
+
"border-right": isExcludedBorder("right"),
|
|
82
|
+
"border-bottom": isExcludedBorder("bottom"),
|
|
83
|
+
"border-left": isExcludedBorder("left"),
|
|
84
|
+
"border-block-end": isExcludedBorder("block-end"),
|
|
85
|
+
"border-block-start": isExcludedBorder("block-start"),
|
|
86
|
+
"border-inline-end": isExcludedBorder("inline-end"),
|
|
87
|
+
"border-inline-start": isExcludedBorder("inline-start"),
|
|
88
|
+
"border-top-style": isExcludedBorder("top"),
|
|
89
|
+
"border-right-style": isExcludedBorder("right"),
|
|
90
|
+
"border-bottom-style": isExcludedBorder("bottom"),
|
|
91
|
+
"border-left-style": isExcludedBorder("left"),
|
|
92
|
+
"border-block-end-style": isExcludedBorder("block-end"),
|
|
93
|
+
"border-block-start-style": isExcludedBorder("block-start"),
|
|
94
|
+
"border-inline-end-style": isExcludedBorder("inline-end"),
|
|
95
|
+
"border-inline-start-style": isExcludedBorder("inline-start"),
|
|
96
|
+
"border-top-width": isExcludedBorder("top"),
|
|
97
|
+
"border-right-width": isExcludedBorder("right"),
|
|
98
|
+
"border-bottom-width": isExcludedBorder("bottom"),
|
|
99
|
+
"border-left-width": isExcludedBorder("left"),
|
|
100
|
+
"border-block-end-width": isExcludedBorder("block-end"),
|
|
101
|
+
"border-block-start-width": isExcludedBorder("block-start"),
|
|
102
|
+
"border-inline-end-width": isExcludedBorder("inline-end")
|
|
103
|
+
};
|
|
104
|
+
export {
|
|
105
|
+
cssRules
|
|
106
|
+
};
|
|
107
|
+
//# sourceMappingURL=cssRules.mjs.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/lib/exports/cssRules.ts"],
|
|
4
|
+
"sourcesContent": ["export type Styles = { [K in string]?: string }\nexport type ReadonlyStyles = { readonly [K in string]?: string }\n\ntype CanSkipRule = (\n\tvalue: string,\n\tproperty: string,\n\toptions: {\n\t\tgetStyle(property: string): string\n\t\tparentStyles: ReadonlyStyles\n\t\tdefaultStyles: ReadonlyStyles\n\t\tcurrentColor: string\n\t}\n) => boolean\n\nconst isCoveredByCurrentColor: CanSkipRule = (value, property, { currentColor }) => {\n\treturn value === 'currentColor' || value === currentColor\n}\n\nconst isInherited: CanSkipRule = (value, property, { parentStyles }) => {\n\treturn parentStyles[property] === value\n}\n\n// see comment below about why we exclude border styles\nconst isExcludedBorder =\n\t(borderDirection: string): CanSkipRule =>\n\t(value, property, { getStyle }) => {\n\t\tconst borderWidth = getStyle(`border-${borderDirection}-width`)\n\t\tconst borderStyle = getStyle(`border-${borderDirection}-style`)\n\n\t\tif (borderWidth === '0px') return true\n\t\tif (borderStyle === 'none') return true\n\t\treturn false\n\t}\n\nexport const cssRules = {\n\t// currentColor properties:\n\t'border-block-end-color': isCoveredByCurrentColor,\n\t'border-block-start-color': isCoveredByCurrentColor,\n\t'border-bottom-color': isCoveredByCurrentColor,\n\t'border-inline-end-color': isCoveredByCurrentColor,\n\t'border-inline-start-color': isCoveredByCurrentColor,\n\t'border-left-color': isCoveredByCurrentColor,\n\t'border-right-color': isCoveredByCurrentColor,\n\t'border-top-color': isCoveredByCurrentColor,\n\t'caret-color': isCoveredByCurrentColor,\n\t'column-rule-color': isCoveredByCurrentColor,\n\t'outline-color': isCoveredByCurrentColor,\n\t'text-decoration': (value, property, { currentColor }) => {\n\t\treturn value === 'none solid currentColor' || value === 'none solid ' + currentColor\n\t},\n\t'text-decoration-color': isCoveredByCurrentColor,\n\t'text-emphasis-color': isCoveredByCurrentColor,\n\n\t// inherited properties:\n\t'border-collapse': isInherited,\n\t'border-spacing': isInherited,\n\t'caption-side': isInherited,\n\t// N.B. We shouldn't inherit 'color' because there's some UA styling, e.g. `mark` elements\n\t// 'color': isInherited,\n\tcursor: isInherited,\n\tdirection: isInherited,\n\t'empty-cells': isInherited,\n\t'font-family': isInherited,\n\t'font-size': isInherited,\n\t'font-style': isInherited,\n\t'font-variant': isInherited,\n\t'font-weight': isInherited,\n\t'font-size-adjust': isInherited,\n\t'font-stretch': isInherited,\n\tfont: isInherited,\n\t'letter-spacing': isInherited,\n\t'line-height': isInherited,\n\t'list-style-image': isInherited,\n\t'list-style-position': isInherited,\n\t'list-style-type': isInherited,\n\t'list-style': isInherited,\n\torphans: isInherited,\n\t'overflow-wrap': isInherited,\n\tquotes: isInherited,\n\t'stroke-linecap': isInherited,\n\t'stroke-linejoin': isInherited,\n\t'tab-size': isInherited,\n\t'text-align': isInherited,\n\t'text-align-last': isInherited,\n\t'text-indent': isInherited,\n\t'text-justify': isInherited,\n\t'text-shadow': isInherited,\n\t'text-transform': isInherited,\n\tvisibility: isInherited,\n\t'white-space': isInherited,\n\t'white-space-collapse': isInherited,\n\twidows: isInherited,\n\t'word-break': isInherited,\n\t'word-spacing': isInherited,\n\t'word-wrap': isInherited,\n\n\t// special border cases - we have a weird case (tailwind seems to trigger this) where all\n\t// border-styles sometimes get set to 'solid', but the border-width is 0 so they don't render.\n\t// but in SVGs, **sometimes**, the border-width defaults (i think from a UA style-sheet? but\n\t// honestly can't tell) to 1.5px so the border displays. we work around this by only including\n\t// border styles at all if both the border-width and border-style are set to something that\n\t// would show a border.\n\t'border-top': isExcludedBorder('top'),\n\t'border-right': isExcludedBorder('right'),\n\t'border-bottom': isExcludedBorder('bottom'),\n\t'border-left': isExcludedBorder('left'),\n\t'border-block-end': isExcludedBorder('block-end'),\n\t'border-block-start': isExcludedBorder('block-start'),\n\t'border-inline-end': isExcludedBorder('inline-end'),\n\t'border-inline-start': isExcludedBorder('inline-start'),\n\t'border-top-style': isExcludedBorder('top'),\n\t'border-right-style': isExcludedBorder('right'),\n\t'border-bottom-style': isExcludedBorder('bottom'),\n\t'border-left-style': isExcludedBorder('left'),\n\t'border-block-end-style': isExcludedBorder('block-end'),\n\t'border-block-start-style': isExcludedBorder('block-start'),\n\t'border-inline-end-style': isExcludedBorder('inline-end'),\n\t'border-inline-start-style': isExcludedBorder('inline-start'),\n\t'border-top-width': isExcludedBorder('top'),\n\t'border-right-width': isExcludedBorder('right'),\n\t'border-bottom-width': isExcludedBorder('bottom'),\n\t'border-left-width': isExcludedBorder('left'),\n\t'border-block-end-width': isExcludedBorder('block-end'),\n\t'border-block-start-width': isExcludedBorder('block-start'),\n\t'border-inline-end-width': isExcludedBorder('inline-end'),\n} satisfies Record<string, CanSkipRule>\n"],
|
|
5
|
+
"mappings": "AAcA,MAAM,0BAAuC,CAAC,OAAO,UAAU,EAAE,aAAa,MAAM;AACnF,SAAO,UAAU,kBAAkB,UAAU;AAC9C;AAEA,MAAM,cAA2B,CAAC,OAAO,UAAU,EAAE,aAAa,MAAM;AACvE,SAAO,aAAa,QAAQ,MAAM;AACnC;AAGA,MAAM,mBACL,CAAC,oBACD,CAAC,OAAO,UAAU,EAAE,SAAS,MAAM;AAClC,QAAM,cAAc,SAAS,UAAU,eAAe,QAAQ;AAC9D,QAAM,cAAc,SAAS,UAAU,eAAe,QAAQ;AAE9D,MAAI,gBAAgB,MAAO,QAAO;AAClC,MAAI,gBAAgB,OAAQ,QAAO;AACnC,SAAO;AACR;AAEM,MAAM,WAAW;AAAA;AAAA,EAEvB,0BAA0B;AAAA,EAC1B,4BAA4B;AAAA,EAC5B,uBAAuB;AAAA,EACvB,2BAA2B;AAAA,EAC3B,6BAA6B;AAAA,EAC7B,qBAAqB;AAAA,EACrB,sBAAsB;AAAA,EACtB,oBAAoB;AAAA,EACpB,eAAe;AAAA,EACf,qBAAqB;AAAA,EACrB,iBAAiB;AAAA,EACjB,mBAAmB,CAAC,OAAO,UAAU,EAAE,aAAa,MAAM;AACzD,WAAO,UAAU,6BAA6B,UAAU,gBAAgB;AAAA,EACzE;AAAA,EACA,yBAAyB;AAAA,EACzB,uBAAuB;AAAA;AAAA,EAGvB,mBAAmB;AAAA,EACnB,kBAAkB;AAAA,EAClB,gBAAgB;AAAA;AAAA;AAAA,EAGhB,QAAQ;AAAA,EACR,WAAW;AAAA,EACX,eAAe;AAAA,EACf,eAAe;AAAA,EACf,aAAa;AAAA,EACb,cAAc;AAAA,EACd,gBAAgB;AAAA,EAChB,eAAe;AAAA,EACf,oBAAoB;AAAA,EACpB,gBAAgB;AAAA,EAChB,MAAM;AAAA,EACN,kBAAkB;AAAA,EAClB,eAAe;AAAA,EACf,oBAAoB;AAAA,EACpB,uBAAuB;AAAA,EACvB,mBAAmB;AAAA,EACnB,cAAc;AAAA,EACd,SAAS;AAAA,EACT,iBAAiB;AAAA,EACjB,QAAQ;AAAA,EACR,kBAAkB;AAAA,EAClB,mBAAmB;AAAA,EACnB,YAAY;AAAA,EACZ,cAAc;AAAA,EACd,mBAAmB;AAAA,EACnB,eAAe;AAAA,EACf,gBAAgB;AAAA,EAChB,eAAe;AAAA,EACf,kBAAkB;AAAA,EAClB,YAAY;AAAA,EACZ,eAAe;AAAA,EACf,wBAAwB;AAAA,EACxB,QAAQ;AAAA,EACR,cAAc;AAAA,EACd,gBAAgB;AAAA,EAChB,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQb,cAAc,iBAAiB,KAAK;AAAA,EACpC,gBAAgB,iBAAiB,OAAO;AAAA,EACxC,iBAAiB,iBAAiB,QAAQ;AAAA,EAC1C,eAAe,iBAAiB,MAAM;AAAA,EACtC,oBAAoB,iBAAiB,WAAW;AAAA,EAChD,sBAAsB,iBAAiB,aAAa;AAAA,EACpD,qBAAqB,iBAAiB,YAAY;AAAA,EAClD,uBAAuB,iBAAiB,cAAc;AAAA,EACtD,oBAAoB,iBAAiB,KAAK;AAAA,EAC1C,sBAAsB,iBAAiB,OAAO;AAAA,EAC9C,uBAAuB,iBAAiB,QAAQ;AAAA,EAChD,qBAAqB,iBAAiB,MAAM;AAAA,EAC5C,0BAA0B,iBAAiB,WAAW;AAAA,EACtD,4BAA4B,iBAAiB,aAAa;AAAA,EAC1D,2BAA2B,iBAAiB,YAAY;AAAA,EACxD,6BAA6B,iBAAiB,cAAc;AAAA,EAC5D,oBAAoB,iBAAiB,KAAK;AAAA,EAC1C,sBAAsB,iBAAiB,OAAO;AAAA,EAC9C,uBAAuB,iBAAiB,QAAQ;AAAA,EAChD,qBAAqB,iBAAiB,MAAM;AAAA,EAC5C,0BAA0B,iBAAiB,WAAW;AAAA,EACtD,4BAA4B,iBAAiB,aAAa;AAAA,EAC1D,2BAA2B,iBAAiB,YAAY;AACzD;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -67,76 +67,7 @@ function parseCssValueUrls(value) {
|
|
|
67
67
|
url: m[1] || m[2] || m[3]
|
|
68
68
|
}));
|
|
69
69
|
}
|
|
70
|
-
const currentColorProperties = /* @__PURE__ */ new Set([
|
|
71
|
-
"border-block-end-color",
|
|
72
|
-
"border-block-start-color",
|
|
73
|
-
"border-bottom-color",
|
|
74
|
-
"border-inline-end-color",
|
|
75
|
-
"border-inline-start-color",
|
|
76
|
-
"border-left-color",
|
|
77
|
-
"border-right-color",
|
|
78
|
-
"border-top-color",
|
|
79
|
-
"caret-color",
|
|
80
|
-
"column-rule-color",
|
|
81
|
-
"outline-color",
|
|
82
|
-
"text-decoration",
|
|
83
|
-
"text-decoration-color",
|
|
84
|
-
"text-emphasis-color"
|
|
85
|
-
]);
|
|
86
|
-
function isPropertyCoveredByCurrentColor(currentColor, property, value) {
|
|
87
|
-
if (currentColorProperties.has(property)) {
|
|
88
|
-
return value === "currentColor" || value === currentColor || property === "text-decoration" && value === `none solid ${currentColor}`;
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
const inheritedProperties = /* @__PURE__ */ new Set([
|
|
92
|
-
"border-collapse",
|
|
93
|
-
"border-spacing",
|
|
94
|
-
"caption-side",
|
|
95
|
-
// N.B. We shouldn't inherit 'color' because there's some UA styling, e.g. `mark` elements
|
|
96
|
-
// 'color',
|
|
97
|
-
"cursor",
|
|
98
|
-
"direction",
|
|
99
|
-
"empty-cells",
|
|
100
|
-
"font-family",
|
|
101
|
-
"font-size",
|
|
102
|
-
"font-style",
|
|
103
|
-
"font-variant",
|
|
104
|
-
"font-weight",
|
|
105
|
-
"font-size-adjust",
|
|
106
|
-
"font-stretch",
|
|
107
|
-
"font",
|
|
108
|
-
"letter-spacing",
|
|
109
|
-
"line-height",
|
|
110
|
-
"list-style-image",
|
|
111
|
-
"list-style-position",
|
|
112
|
-
"list-style-type",
|
|
113
|
-
"list-style",
|
|
114
|
-
"orphans",
|
|
115
|
-
"overflow-wrap",
|
|
116
|
-
"quotes",
|
|
117
|
-
"stroke-linecap",
|
|
118
|
-
"stroke-linejoin",
|
|
119
|
-
"tab-size",
|
|
120
|
-
"text-align",
|
|
121
|
-
"text-align-last",
|
|
122
|
-
"text-indent",
|
|
123
|
-
"text-justify",
|
|
124
|
-
"text-shadow",
|
|
125
|
-
"text-transform",
|
|
126
|
-
"visibility",
|
|
127
|
-
"white-space",
|
|
128
|
-
"white-space-collapse",
|
|
129
|
-
"widows",
|
|
130
|
-
"word-break",
|
|
131
|
-
"word-spacing",
|
|
132
|
-
"word-wrap"
|
|
133
|
-
]);
|
|
134
|
-
function isPropertyInherited(property) {
|
|
135
|
-
return inheritedProperties.has(property);
|
|
136
|
-
}
|
|
137
70
|
export {
|
|
138
|
-
isPropertyCoveredByCurrentColor,
|
|
139
|
-
isPropertyInherited,
|
|
140
71
|
parseCss,
|
|
141
72
|
parseCssFontFaces,
|
|
142
73
|
parseCssFontFamilyValue,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/lib/exports/parseCss.ts"],
|
|
4
|
-
"sourcesContent": ["import { safeParseUrl } from '@tldraw/utils'\n\nexport interface ParsedFontFace {\n\tfontFace: string\n\turls: { original: string; resolved: string | null; embedded?: Promise<string | null> }[]\n\tfontFamilies: Set<string>\n}\n\n// parsing CSS with regular expressions doesn't really work. There are almost certainly edge cases\n// in the regular expressions we're using here. They're based formal grammars of CSS, but aren't\n// perfect. These were written with https://regexper.com/ - give it a go if you're editing these.\n\n// The regexes themselves would be nicer to work with if we were using named capturing groups\n// (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Regular_expressions/Named_capturing_group).\n// We use a lot of disjunctions (the `|`) to cover different syntaxes though, and at the time of\n// writing, browser support for using named capturing groups across disjunctions is rough.\n\n// Parse @import declarations:\n// https://developer.mozilla.org/en-US/docs/Web/CSS/@import#formal_syntax\nconst importsRegex =\n\t/@import\\s+(?:\"([^\"]+)\"|'([^']+)'|url\\s*\\(\\s*(?:\"([^\"]+)\"|'([^']+)'|([^'\")]+))\\s*\\))([^;]+);/gi\n\n// Locate @font-face declarations:\nconst fontFaceRegex = /@font-face\\s*{([^}]+)}/gi\n\n// Parse url() calls within a CSS value:\n// https://developer.mozilla.org/en-US/docs/Web/CSS/url#syntax\nconst urlsRegex = /url\\s*\\(\\s*(?:\"([^\"]+)\"|'([^']+)'|([^'\")]+))\\s*\\)/gi\n\n// Locate and parse the value of `font-family` within a @font-face declaration:\n// https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-family#formal_syntax\nconst fontFamilyRegex =\n\t/(?:^|;)\\s*font-family\\s*:\\s*(?:([^'\"][^;\\n]+)|\"([^\"]+)\"|'([^']+)')\\s*(?:;|$)/gi\n\nexport function parseCssImports(css: string) {\n\treturn Array.from(css.matchAll(importsRegex), (m) => ({\n\t\turl: m[1] || m[2] || m[3] || m[4] || m[5],\n\t\textras: m[6],\n\t}))\n}\n\nexport function parseCssFontFaces(css: string, baseUrl: string) {\n\treturn Array.from(css.matchAll(fontFaceRegex), (m): ParsedFontFace => {\n\t\tconst fontFace = m[1]\n\t\tconst urls = Array.from(fontFace.matchAll(urlsRegex), (m) => {\n\t\t\tconst original = m[1] || m[2] || m[3]\n\t\t\treturn {\n\t\t\t\toriginal,\n\t\t\t\tresolved: safeParseUrl(original, baseUrl)?.href ?? null,\n\t\t\t}\n\t\t})\n\t\tconst fontFamilies = new Set(\n\t\t\tArray.from(fontFace.matchAll(fontFamilyRegex), (m) => (m[1] || m[2] || m[3]).toLowerCase())\n\t\t)\n\n\t\treturn { fontFace, urls, fontFamilies }\n\t})\n}\n\nexport function parseCssFontFamilyValue(value: string) {\n\t// https://developer.mozilla.org/en-US/docs/Web/CSS/font-family#formal_syntax\n\t// we use two regexes here to parse each value in a comma separated list of font families\n\tconst valueRegex = /\\s*(?:([^'\"][^;\\n\\s,]+)|\"([^\"]+)\"|'([^']+)')\\s*/gi\n\tconst separatorRegex = /\\s*,\\s*/gi\n\n\tconst fontFamilies = new Set<string>()\n\n\twhile (true) {\n\t\tconst valueMatch = valueRegex.exec(value)\n\t\tif (!valueMatch) {\n\t\t\tbreak\n\t\t}\n\n\t\tconst fontFamily = valueMatch[1] || valueMatch[2] || valueMatch[3]\n\t\tfontFamilies.add(fontFamily.toLowerCase())\n\n\t\tseparatorRegex.lastIndex = valueRegex.lastIndex\n\t\tconst separatorMatch = separatorRegex.exec(value)\n\t\tif (!separatorMatch) {\n\t\t\tbreak\n\t\t}\n\n\t\tvalueRegex.lastIndex = separatorRegex.lastIndex\n\t}\n\n\treturn fontFamilies\n}\n\nexport function shouldIncludeCssProperty(property: string) {\n\tif (property.startsWith('-')) return false\n\tif (property.startsWith('animation')) return false\n\tif (property.startsWith('transition')) return false\n\tif (property === 'cursor') return false\n\tif (property === 'pointer-events') return false\n\tif (property === 'user-select') return false\n\tif (property === 'touch-action') return false\n\treturn true\n}\n\nexport function parseCss(css: string, baseUrl: string) {\n\treturn {\n\t\timports: parseCssImports(css),\n\t\tfontFaces: parseCssFontFaces(css, baseUrl),\n\t}\n}\n\nexport function parseCssValueUrls(value: string) {\n\treturn Array.from(value.matchAll(urlsRegex), (m) => ({\n\t\toriginal: m[0],\n\t\turl: m[1] || m[2] || m[3],\n\t}))\n}\n
|
|
5
|
-
"mappings": "AAAA,SAAS,oBAAoB;AAmB7B,MAAM,eACL;AAGD,MAAM,gBAAgB;AAItB,MAAM,YAAY;AAIlB,MAAM,kBACL;AAEM,SAAS,gBAAgB,KAAa;AAC5C,SAAO,MAAM,KAAK,IAAI,SAAS,YAAY,GAAG,CAAC,OAAO;AAAA,IACrD,KAAK,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,CAAC;AAAA,IACxC,QAAQ,EAAE,CAAC;AAAA,EACZ,EAAE;AACH;AAEO,SAAS,kBAAkB,KAAa,SAAiB;AAC/D,SAAO,MAAM,KAAK,IAAI,SAAS,aAAa,GAAG,CAAC,MAAsB;AACrE,UAAM,WAAW,EAAE,CAAC;AACpB,UAAM,OAAO,MAAM,KAAK,SAAS,SAAS,SAAS,GAAG,CAACA,OAAM;AAC5D,YAAM,WAAWA,GAAE,CAAC,KAAKA,GAAE,CAAC,KAAKA,GAAE,CAAC;AACpC,aAAO;AAAA,QACN;AAAA,QACA,UAAU,aAAa,UAAU,OAAO,GAAG,QAAQ;AAAA,MACpD;AAAA,IACD,CAAC;AACD,UAAM,eAAe,IAAI;AAAA,MACxB,MAAM,KAAK,SAAS,SAAS,eAAe,GAAG,CAACA,QAAOA,GAAE,CAAC,KAAKA,GAAE,CAAC,KAAKA,GAAE,CAAC,GAAG,YAAY,CAAC;AAAA,IAC3F;AAEA,WAAO,EAAE,UAAU,MAAM,aAAa;AAAA,EACvC,CAAC;AACF;AAEO,SAAS,wBAAwB,OAAe;AAGtD,QAAM,aAAa;AACnB,QAAM,iBAAiB;AAEvB,QAAM,eAAe,oBAAI,IAAY;AAErC,SAAO,MAAM;AACZ,UAAM,aAAa,WAAW,KAAK,KAAK;AACxC,QAAI,CAAC,YAAY;AAChB;AAAA,IACD;AAEA,UAAM,aAAa,WAAW,CAAC,KAAK,WAAW,CAAC,KAAK,WAAW,CAAC;AACjE,iBAAa,IAAI,WAAW,YAAY,CAAC;AAEzC,mBAAe,YAAY,WAAW;AACtC,UAAM,iBAAiB,eAAe,KAAK,KAAK;AAChD,QAAI,CAAC,gBAAgB;AACpB;AAAA,IACD;AAEA,eAAW,YAAY,eAAe;AAAA,EACvC;AAEA,SAAO;AACR;AAEO,SAAS,yBAAyB,UAAkB;AAC1D,MAAI,SAAS,WAAW,GAAG,EAAG,QAAO;AACrC,MAAI,SAAS,WAAW,WAAW,EAAG,QAAO;AAC7C,MAAI,SAAS,WAAW,YAAY,EAAG,QAAO;AAC9C,MAAI,aAAa,SAAU,QAAO;AAClC,MAAI,aAAa,iBAAkB,QAAO;AAC1C,MAAI,aAAa,cAAe,QAAO;AACvC,MAAI,aAAa,eAAgB,QAAO;AACxC,SAAO;AACR;AAEO,SAAS,SAAS,KAAa,SAAiB;AACtD,SAAO;AAAA,IACN,SAAS,gBAAgB,GAAG;AAAA,IAC5B,WAAW,kBAAkB,KAAK,OAAO;AAAA,EAC1C;AACD;AAEO,SAAS,kBAAkB,OAAe;AAChD,SAAO,MAAM,KAAK,MAAM,SAAS,SAAS,GAAG,CAAC,OAAO;AAAA,IACpD,UAAU,EAAE,CAAC;AAAA,IACb,KAAK,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,CAAC;AAAA,EACzB,EAAE;AACH;
|
|
4
|
+
"sourcesContent": ["import { safeParseUrl } from '@tldraw/utils'\n\nexport interface ParsedFontFace {\n\tfontFace: string\n\turls: { original: string; resolved: string | null; embedded?: Promise<string | null> }[]\n\tfontFamilies: Set<string>\n}\n\n// parsing CSS with regular expressions doesn't really work. There are almost certainly edge cases\n// in the regular expressions we're using here. They're based formal grammars of CSS, but aren't\n// perfect. These were written with https://regexper.com/ - give it a go if you're editing these.\n\n// The regexes themselves would be nicer to work with if we were using named capturing groups\n// (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Regular_expressions/Named_capturing_group).\n// We use a lot of disjunctions (the `|`) to cover different syntaxes though, and at the time of\n// writing, browser support for using named capturing groups across disjunctions is rough.\n\n// Parse @import declarations:\n// https://developer.mozilla.org/en-US/docs/Web/CSS/@import#formal_syntax\nconst importsRegex =\n\t/@import\\s+(?:\"([^\"]+)\"|'([^']+)'|url\\s*\\(\\s*(?:\"([^\"]+)\"|'([^']+)'|([^'\")]+))\\s*\\))([^;]+);/gi\n\n// Locate @font-face declarations:\nconst fontFaceRegex = /@font-face\\s*{([^}]+)}/gi\n\n// Parse url() calls within a CSS value:\n// https://developer.mozilla.org/en-US/docs/Web/CSS/url#syntax\nconst urlsRegex = /url\\s*\\(\\s*(?:\"([^\"]+)\"|'([^']+)'|([^'\")]+))\\s*\\)/gi\n\n// Locate and parse the value of `font-family` within a @font-face declaration:\n// https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-family#formal_syntax\nconst fontFamilyRegex =\n\t/(?:^|;)\\s*font-family\\s*:\\s*(?:([^'\"][^;\\n]+)|\"([^\"]+)\"|'([^']+)')\\s*(?:;|$)/gi\n\nexport function parseCssImports(css: string) {\n\treturn Array.from(css.matchAll(importsRegex), (m) => ({\n\t\turl: m[1] || m[2] || m[3] || m[4] || m[5],\n\t\textras: m[6],\n\t}))\n}\n\nexport function parseCssFontFaces(css: string, baseUrl: string) {\n\treturn Array.from(css.matchAll(fontFaceRegex), (m): ParsedFontFace => {\n\t\tconst fontFace = m[1]\n\t\tconst urls = Array.from(fontFace.matchAll(urlsRegex), (m) => {\n\t\t\tconst original = m[1] || m[2] || m[3]\n\t\t\treturn {\n\t\t\t\toriginal,\n\t\t\t\tresolved: safeParseUrl(original, baseUrl)?.href ?? null,\n\t\t\t}\n\t\t})\n\t\tconst fontFamilies = new Set(\n\t\t\tArray.from(fontFace.matchAll(fontFamilyRegex), (m) => (m[1] || m[2] || m[3]).toLowerCase())\n\t\t)\n\n\t\treturn { fontFace, urls, fontFamilies }\n\t})\n}\n\nexport function parseCssFontFamilyValue(value: string) {\n\t// https://developer.mozilla.org/en-US/docs/Web/CSS/font-family#formal_syntax\n\t// we use two regexes here to parse each value in a comma separated list of font families\n\tconst valueRegex = /\\s*(?:([^'\"][^;\\n\\s,]+)|\"([^\"]+)\"|'([^']+)')\\s*/gi\n\tconst separatorRegex = /\\s*,\\s*/gi\n\n\tconst fontFamilies = new Set<string>()\n\n\twhile (true) {\n\t\tconst valueMatch = valueRegex.exec(value)\n\t\tif (!valueMatch) {\n\t\t\tbreak\n\t\t}\n\n\t\tconst fontFamily = valueMatch[1] || valueMatch[2] || valueMatch[3]\n\t\tfontFamilies.add(fontFamily.toLowerCase())\n\n\t\tseparatorRegex.lastIndex = valueRegex.lastIndex\n\t\tconst separatorMatch = separatorRegex.exec(value)\n\t\tif (!separatorMatch) {\n\t\t\tbreak\n\t\t}\n\n\t\tvalueRegex.lastIndex = separatorRegex.lastIndex\n\t}\n\n\treturn fontFamilies\n}\n\nexport function shouldIncludeCssProperty(property: string) {\n\tif (property.startsWith('-')) return false\n\tif (property.startsWith('animation')) return false\n\tif (property.startsWith('transition')) return false\n\tif (property === 'cursor') return false\n\tif (property === 'pointer-events') return false\n\tif (property === 'user-select') return false\n\tif (property === 'touch-action') return false\n\treturn true\n}\n\nexport function parseCss(css: string, baseUrl: string) {\n\treturn {\n\t\timports: parseCssImports(css),\n\t\tfontFaces: parseCssFontFaces(css, baseUrl),\n\t}\n}\n\nexport function parseCssValueUrls(value: string) {\n\treturn Array.from(value.matchAll(urlsRegex), (m) => ({\n\t\toriginal: m[0],\n\t\turl: m[1] || m[2] || m[3],\n\t}))\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,oBAAoB;AAmB7B,MAAM,eACL;AAGD,MAAM,gBAAgB;AAItB,MAAM,YAAY;AAIlB,MAAM,kBACL;AAEM,SAAS,gBAAgB,KAAa;AAC5C,SAAO,MAAM,KAAK,IAAI,SAAS,YAAY,GAAG,CAAC,OAAO;AAAA,IACrD,KAAK,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,CAAC;AAAA,IACxC,QAAQ,EAAE,CAAC;AAAA,EACZ,EAAE;AACH;AAEO,SAAS,kBAAkB,KAAa,SAAiB;AAC/D,SAAO,MAAM,KAAK,IAAI,SAAS,aAAa,GAAG,CAAC,MAAsB;AACrE,UAAM,WAAW,EAAE,CAAC;AACpB,UAAM,OAAO,MAAM,KAAK,SAAS,SAAS,SAAS,GAAG,CAACA,OAAM;AAC5D,YAAM,WAAWA,GAAE,CAAC,KAAKA,GAAE,CAAC,KAAKA,GAAE,CAAC;AACpC,aAAO;AAAA,QACN;AAAA,QACA,UAAU,aAAa,UAAU,OAAO,GAAG,QAAQ;AAAA,MACpD;AAAA,IACD,CAAC;AACD,UAAM,eAAe,IAAI;AAAA,MACxB,MAAM,KAAK,SAAS,SAAS,eAAe,GAAG,CAACA,QAAOA,GAAE,CAAC,KAAKA,GAAE,CAAC,KAAKA,GAAE,CAAC,GAAG,YAAY,CAAC;AAAA,IAC3F;AAEA,WAAO,EAAE,UAAU,MAAM,aAAa;AAAA,EACvC,CAAC;AACF;AAEO,SAAS,wBAAwB,OAAe;AAGtD,QAAM,aAAa;AACnB,QAAM,iBAAiB;AAEvB,QAAM,eAAe,oBAAI,IAAY;AAErC,SAAO,MAAM;AACZ,UAAM,aAAa,WAAW,KAAK,KAAK;AACxC,QAAI,CAAC,YAAY;AAChB;AAAA,IACD;AAEA,UAAM,aAAa,WAAW,CAAC,KAAK,WAAW,CAAC,KAAK,WAAW,CAAC;AACjE,iBAAa,IAAI,WAAW,YAAY,CAAC;AAEzC,mBAAe,YAAY,WAAW;AACtC,UAAM,iBAAiB,eAAe,KAAK,KAAK;AAChD,QAAI,CAAC,gBAAgB;AACpB;AAAA,IACD;AAEA,eAAW,YAAY,eAAe;AAAA,EACvC;AAEA,SAAO;AACR;AAEO,SAAS,yBAAyB,UAAkB;AAC1D,MAAI,SAAS,WAAW,GAAG,EAAG,QAAO;AACrC,MAAI,SAAS,WAAW,WAAW,EAAG,QAAO;AAC7C,MAAI,SAAS,WAAW,YAAY,EAAG,QAAO;AAC9C,MAAI,aAAa,SAAU,QAAO;AAClC,MAAI,aAAa,iBAAkB,QAAO;AAC1C,MAAI,aAAa,cAAe,QAAO;AACvC,MAAI,aAAa,eAAgB,QAAO;AACxC,SAAO;AACR;AAEO,SAAS,SAAS,KAAa,SAAiB;AACtD,SAAO;AAAA,IACN,SAAS,gBAAgB,GAAG;AAAA,IAC5B,WAAW,kBAAkB,KAAK,OAAO;AAAA,EAC1C;AACD;AAEO,SAAS,kBAAkB,OAAe;AAChD,SAAO,MAAM,KAAK,MAAM,SAAS,SAAS,GAAG,CAAC,OAAO;AAAA,IACpD,UAAU,EAAE,CAAC;AAAA,IACb,KAAK,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,CAAC;AAAA,EACzB,EAAE;AACH;",
|
|
6
6
|
"names": ["m"]
|
|
7
7
|
}
|
package/dist-esm/version.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
const version = "3.12.0-canary.
|
|
1
|
+
const version = "3.12.0-canary.e333011facbe";
|
|
2
2
|
const publishDates = {
|
|
3
3
|
major: "2024-09-13T14:36:29.063Z",
|
|
4
|
-
minor: "2025-04-
|
|
5
|
-
patch: "2025-04-
|
|
4
|
+
minor: "2025-04-03T09:52:50.298Z",
|
|
5
|
+
patch: "2025-04-03T09:52:50.298Z"
|
|
6
6
|
};
|
|
7
7
|
export {
|
|
8
8
|
publishDates,
|
package/dist-esm/version.mjs.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/version.ts"],
|
|
4
|
-
"sourcesContent": ["// This file is automatically generated by internal/scripts/refresh-assets.ts.\n// Do not edit manually. Or do, I'm a comment, not a cop.\n\nexport const version = '3.12.0-canary.
|
|
4
|
+
"sourcesContent": ["// This file is automatically generated by internal/scripts/refresh-assets.ts.\n// Do not edit manually. Or do, I'm a comment, not a cop.\n\nexport const version = '3.12.0-canary.e333011facbe'\nexport const publishDates = {\n\tmajor: '2024-09-13T14:36:29.063Z',\n\tminor: '2025-04-03T09:52:50.298Z',\n\tpatch: '2025-04-03T09:52:50.298Z',\n}\n"],
|
|
5
5
|
"mappings": "AAGO,MAAM,UAAU;AAChB,MAAM,eAAe;AAAA,EAC3B,OAAO;AAAA,EACP,OAAO;AAAA,EACP,OAAO;AACR;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tldraw/editor",
|
|
3
3
|
"description": "A tiny little drawing app (editor).",
|
|
4
|
-
"version": "3.12.0-canary.
|
|
4
|
+
"version": "3.12.0-canary.e333011facbe",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "tldraw Inc.",
|
|
7
7
|
"email": "hello@tldraw.com"
|
|
@@ -48,12 +48,12 @@
|
|
|
48
48
|
"@tiptap/core": "^2.9.1",
|
|
49
49
|
"@tiptap/pm": "^2.9.1",
|
|
50
50
|
"@tiptap/react": "^2.9.1",
|
|
51
|
-
"@tldraw/state": "3.12.0-canary.
|
|
52
|
-
"@tldraw/state-react": "3.12.0-canary.
|
|
53
|
-
"@tldraw/store": "3.12.0-canary.
|
|
54
|
-
"@tldraw/tlschema": "3.12.0-canary.
|
|
55
|
-
"@tldraw/utils": "3.12.0-canary.
|
|
56
|
-
"@tldraw/validate": "3.12.0-canary.
|
|
51
|
+
"@tldraw/state": "3.12.0-canary.e333011facbe",
|
|
52
|
+
"@tldraw/state-react": "3.12.0-canary.e333011facbe",
|
|
53
|
+
"@tldraw/store": "3.12.0-canary.e333011facbe",
|
|
54
|
+
"@tldraw/tlschema": "3.12.0-canary.e333011facbe",
|
|
55
|
+
"@tldraw/utils": "3.12.0-canary.e333011facbe",
|
|
56
|
+
"@tldraw/validate": "3.12.0-canary.e333011facbe",
|
|
57
57
|
"@types/core-js": "^2.5.8",
|
|
58
58
|
"@use-gesture/react": "^10.3.1",
|
|
59
59
|
"classnames": "^2.5.1",
|
package/src/lib/TldrawEditor.tsx
CHANGED
|
@@ -191,11 +191,33 @@ export interface TldrawEditorBaseProps {
|
|
|
191
191
|
/**
|
|
192
192
|
* Predicate for whether or not a shape should be hidden.
|
|
193
193
|
*
|
|
194
|
+
* @deprecated Use {@link TldrawEditorBaseProps#getShapeVisibility} instead.
|
|
195
|
+
*/
|
|
196
|
+
isShapeHidden?(shape: TLShape, editor: Editor): boolean
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Provides a way to hide shapes.
|
|
200
|
+
*
|
|
194
201
|
* Hidden shapes will not render in the editor, and they will not be eligible for hit test via
|
|
195
202
|
* {@link Editor#getShapeAtPoint} and {@link Editor#getShapesAtPoint}. But otherwise they will
|
|
196
203
|
* remain in the store and participate in all other operations.
|
|
204
|
+
*
|
|
205
|
+
* @example
|
|
206
|
+
* ```ts
|
|
207
|
+
* getShapeVisibility={(shape, editor) => shape.meta.hidden ? 'hidden' : 'inherit'}
|
|
208
|
+
* ```
|
|
209
|
+
*
|
|
210
|
+
* - `'inherit' | undefined` - (default) The shape will be visible unless its parent is hidden.
|
|
211
|
+
* - `'hidden'` - The shape will be hidden.
|
|
212
|
+
* - `'visible'` - The shape will be visible.
|
|
213
|
+
*
|
|
214
|
+
* @param shape - The shape to check.
|
|
215
|
+
* @param editor - The editor instance.
|
|
197
216
|
*/
|
|
198
|
-
|
|
217
|
+
getShapeVisibility?(
|
|
218
|
+
shape: TLShape,
|
|
219
|
+
editor: Editor
|
|
220
|
+
): 'visible' | 'hidden' | 'inherit' | null | undefined
|
|
199
221
|
|
|
200
222
|
/**
|
|
201
223
|
* The URLs for the fonts to use in the editor.
|
|
@@ -387,7 +409,9 @@ function TldrawEditorWithReadyStore({
|
|
|
387
409
|
options,
|
|
388
410
|
licenseKey,
|
|
389
411
|
deepLinks: _deepLinks,
|
|
412
|
+
// eslint-disable-next-line @typescript-eslint/no-deprecated
|
|
390
413
|
isShapeHidden,
|
|
414
|
+
getShapeVisibility,
|
|
391
415
|
assetUrls,
|
|
392
416
|
}: Required<
|
|
393
417
|
TldrawEditorProps & {
|
|
@@ -447,6 +471,7 @@ function TldrawEditorWithReadyStore({
|
|
|
447
471
|
options,
|
|
448
472
|
licenseKey,
|
|
449
473
|
isShapeHidden,
|
|
474
|
+
getShapeVisibility,
|
|
450
475
|
fontAssetUrls: assetUrls?.fonts,
|
|
451
476
|
})
|
|
452
477
|
|
|
@@ -482,6 +507,7 @@ function TldrawEditorWithReadyStore({
|
|
|
482
507
|
setEditor,
|
|
483
508
|
licenseKey,
|
|
484
509
|
isShapeHidden,
|
|
510
|
+
getShapeVisibility,
|
|
485
511
|
textOptions,
|
|
486
512
|
assetUrls,
|
|
487
513
|
]
|
package/src/lib/editor/Editor.ts
CHANGED
|
@@ -241,10 +241,33 @@ export interface TLEditorOptions {
|
|
|
241
241
|
fontAssetUrls?: { [key: string]: string | undefined }
|
|
242
242
|
/**
|
|
243
243
|
* A predicate that should return true if the given shape should be hidden.
|
|
244
|
+
*
|
|
245
|
+
* @deprecated Use {@link Editor#getShapeVisibility} instead.
|
|
246
|
+
*
|
|
244
247
|
* @param shape - The shape to check.
|
|
245
248
|
* @param editor - The editor instance.
|
|
246
249
|
*/
|
|
247
250
|
isShapeHidden?(shape: TLShape, editor: Editor): boolean
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Provides a way to hide shapes.
|
|
254
|
+
*
|
|
255
|
+
* @example
|
|
256
|
+
* ```ts
|
|
257
|
+
* getShapeVisibility={(shape, editor) => shape.meta.hidden ? 'hidden' : 'inherit'}
|
|
258
|
+
* ```
|
|
259
|
+
*
|
|
260
|
+
* - `'inherit' | undefined` - (default) The shape will be visible unless its parent is hidden.
|
|
261
|
+
* - `'hidden'` - The shape will be hidden.
|
|
262
|
+
* - `'visible'` - The shape will be visible.
|
|
263
|
+
*
|
|
264
|
+
* @param shape - The shape to check.
|
|
265
|
+
* @param editor - The editor instance.
|
|
266
|
+
*/
|
|
267
|
+
getShapeVisibility?(
|
|
268
|
+
shape: TLShape,
|
|
269
|
+
editor: Editor
|
|
270
|
+
): 'visible' | 'hidden' | 'inherit' | null | undefined
|
|
248
271
|
}
|
|
249
272
|
|
|
250
273
|
/**
|
|
@@ -281,12 +304,21 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
281
304
|
autoFocus,
|
|
282
305
|
inferDarkMode,
|
|
283
306
|
options,
|
|
307
|
+
// eslint-disable-next-line @typescript-eslint/no-deprecated
|
|
284
308
|
isShapeHidden,
|
|
309
|
+
getShapeVisibility,
|
|
285
310
|
fontAssetUrls,
|
|
286
311
|
}: TLEditorOptions) {
|
|
287
312
|
super()
|
|
313
|
+
assert(
|
|
314
|
+
!(isShapeHidden && getShapeVisibility),
|
|
315
|
+
'Cannot use both isShapeHidden and getShapeVisibility'
|
|
316
|
+
)
|
|
288
317
|
|
|
289
|
-
this.
|
|
318
|
+
this._getShapeVisibility = isShapeHidden
|
|
319
|
+
? // eslint-disable-next-line @typescript-eslint/no-deprecated
|
|
320
|
+
(shape: TLShape, editor: Editor) => (isShapeHidden(shape, editor) ? 'hidden' : 'inherit')
|
|
321
|
+
: getShapeVisibility
|
|
290
322
|
|
|
291
323
|
this.options = { ...defaultTldrawOptions, ...options }
|
|
292
324
|
|
|
@@ -773,18 +805,22 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
773
805
|
}
|
|
774
806
|
}
|
|
775
807
|
|
|
776
|
-
private readonly
|
|
808
|
+
private readonly _getShapeVisibility?: TLEditorOptions['getShapeVisibility']
|
|
777
809
|
@computed
|
|
778
810
|
private getIsShapeHiddenCache() {
|
|
779
|
-
if (!this.
|
|
811
|
+
if (!this._getShapeVisibility) return null
|
|
780
812
|
return this.store.createComputedCache<boolean, TLShape>('isShapeHidden', (shape: TLShape) => {
|
|
781
|
-
const
|
|
782
|
-
|
|
783
|
-
|
|
813
|
+
const visibility = this._getShapeVisibility!(shape, this)
|
|
814
|
+
const isParentHidden = PageRecordType.isId(shape.parentId)
|
|
815
|
+
? false
|
|
816
|
+
: this.isShapeHidden(shape.parentId)
|
|
817
|
+
|
|
818
|
+
if (isParentHidden) return visibility !== 'visible'
|
|
819
|
+
return visibility === 'hidden'
|
|
784
820
|
})
|
|
785
821
|
}
|
|
786
822
|
isShapeHidden(shapeOrId: TLShape | TLShapeId): boolean {
|
|
787
|
-
if (!this.
|
|
823
|
+
if (!this._getShapeVisibility) return false
|
|
788
824
|
return !!this.getIsShapeHiddenCache!()!.get(
|
|
789
825
|
typeof shapeOrId === 'string' ? shapeOrId : shapeOrId.id
|
|
790
826
|
)
|
|
@@ -3711,7 +3747,15 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
3711
3747
|
const addShapeById = (id: TLShapeId, opacity: number, isAncestorErasing: boolean) => {
|
|
3712
3748
|
const shape = this.getShape(id)
|
|
3713
3749
|
if (!shape) return
|
|
3714
|
-
|
|
3750
|
+
|
|
3751
|
+
if (this.isShapeHidden(shape)) {
|
|
3752
|
+
// process children just in case they are overriding the hidden state
|
|
3753
|
+
const isErasing = isAncestorErasing || erasingShapeIds.includes(id)
|
|
3754
|
+
for (const childId of this.getSortedChildIdsForParent(id)) {
|
|
3755
|
+
addShapeById(childId, opacity, isErasing)
|
|
3756
|
+
}
|
|
3757
|
+
return
|
|
3758
|
+
}
|
|
3715
3759
|
|
|
3716
3760
|
opacity *= shape.opacity
|
|
3717
3761
|
let isShapeErasing = false
|