@tldraw/editor 3.11.0-canary.ef35d1e7bc8d → 3.11.0-canary.f0072703bfd4
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.js +1 -1
- package/dist-cjs/lib/components/default-components/DefaultShapeIndicators.js +8 -12
- package/dist-cjs/lib/components/default-components/DefaultShapeIndicators.js.map +2 -2
- package/dist-cjs/lib/exports/StyleEmbedder.js +16 -1
- package/dist-cjs/lib/exports/StyleEmbedder.js.map +2 -2
- package/dist-cjs/lib/exports/parseCss.js +27 -2
- 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.mjs +1 -1
- package/dist-esm/lib/components/default-components/DefaultShapeIndicators.mjs +8 -12
- package/dist-esm/lib/components/default-components/DefaultShapeIndicators.mjs.map +2 -2
- package/dist-esm/lib/exports/StyleEmbedder.mjs +22 -2
- package/dist-esm/lib/exports/StyleEmbedder.mjs.map +2 -2
- package/dist-esm/lib/exports/parseCss.mjs +27 -2
- 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 +10 -7
- package/src/lib/components/default-components/DefaultShapeIndicators.tsx +12 -14
- package/src/lib/exports/StyleEmbedder.ts +23 -4
- package/src/lib/exports/parseCss.ts +36 -2
- package/src/version.ts +3 -3
package/dist-cjs/index.js
CHANGED
|
@@ -39,30 +39,26 @@ const DefaultShapeIndicators = (0, import_react.memo)(function DefaultShapeIndic
|
|
|
39
39
|
() => {
|
|
40
40
|
const prev = rPreviousSelectedShapeIds.current;
|
|
41
41
|
const next = /* @__PURE__ */ new Set();
|
|
42
|
-
const
|
|
42
|
+
const instanceState = editor.getInstanceState();
|
|
43
|
+
const isChangingStyle = instanceState.isChangingStyle;
|
|
44
|
+
const isIdleOrEditing = editor.isInAny("select.idle", "select.editing_shape");
|
|
43
45
|
const isInSelectState = editor.isInAny(
|
|
44
|
-
"select.idle",
|
|
45
46
|
"select.brushing",
|
|
46
47
|
"select.scribble_brushing",
|
|
47
|
-
"select.editing_shape",
|
|
48
48
|
"select.pointing_shape",
|
|
49
49
|
"select.pointing_selection",
|
|
50
50
|
"select.pointing_handle"
|
|
51
51
|
);
|
|
52
|
-
if (isChangingStyle || !isInSelectState) {
|
|
52
|
+
if (isChangingStyle || !(isIdleOrEditing || isInSelectState)) {
|
|
53
53
|
rPreviousSelectedShapeIds.current = next;
|
|
54
54
|
return next;
|
|
55
55
|
}
|
|
56
|
-
const
|
|
57
|
-
for (const id of selected) {
|
|
56
|
+
for (const id of editor.getSelectedShapeIds()) {
|
|
58
57
|
next.add(id);
|
|
59
58
|
}
|
|
60
|
-
if (
|
|
61
|
-
const
|
|
62
|
-
if (
|
|
63
|
-
const hovered = editor.getHoveredShapeId();
|
|
64
|
-
if (hovered) next.add(hovered);
|
|
65
|
-
}
|
|
59
|
+
if (isIdleOrEditing && instanceState.isHoveringCanvas && !instanceState.isCoarsePointer) {
|
|
60
|
+
const hovered = editor.getHoveredShapeId();
|
|
61
|
+
if (hovered) next.add(hovered);
|
|
66
62
|
}
|
|
67
63
|
if (prev.size !== next.size) {
|
|
68
64
|
rPreviousSelectedShapeIds.current = next;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/lib/components/default-components/DefaultShapeIndicators.tsx"],
|
|
4
|
-
"sourcesContent": ["import { useValue } from '@tldraw/state-react'\nimport { TLShapeId } from '@tldraw/tlschema'\nimport { memo, useRef } from 'react'\nimport { useEditor } from '../../hooks/useEditor'\nimport { useEditorComponents } from '../../hooks/useEditorComponents'\n\n/** @public */\nexport interface TLShapeIndicatorsProps {\n\t/** Whether to hide all of the indicators */\n\thideAll?: boolean\n\t/** Whether to show all of the indicators */\n\tshowAll?: boolean\n}\n\n/** @public @react */\nexport const DefaultShapeIndicators = memo(function DefaultShapeIndicators({\n\thideAll,\n\tshowAll,\n}: TLShapeIndicatorsProps) {\n\tconst editor = useEditor()\n\n\tif (hideAll && showAll)\n\t\tthrow Error('You cannot set both hideAll and showAll props to true, cmon now')\n\n\tconst rPreviousSelectedShapeIds = useRef<Set<TLShapeId>>(new Set())\n\n\tconst idsToDisplay = useValue(\n\t\t'should display selected ids',\n\t\t() => {\n\t\t\tconst prev = rPreviousSelectedShapeIds.current\n\t\t\tconst next = new Set<TLShapeId>()\n\n\t\t\tconst
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;
|
|
4
|
+
"sourcesContent": ["import { useValue } from '@tldraw/state-react'\nimport { TLShapeId } from '@tldraw/tlschema'\nimport { memo, useRef } from 'react'\nimport { useEditor } from '../../hooks/useEditor'\nimport { useEditorComponents } from '../../hooks/useEditorComponents'\n\n/** @public */\nexport interface TLShapeIndicatorsProps {\n\t/** Whether to hide all of the indicators */\n\thideAll?: boolean\n\t/** Whether to show all of the indicators */\n\tshowAll?: boolean\n}\n\n/** @public @react */\nexport const DefaultShapeIndicators = memo(function DefaultShapeIndicators({\n\thideAll,\n\tshowAll,\n}: TLShapeIndicatorsProps) {\n\tconst editor = useEditor()\n\n\tif (hideAll && showAll)\n\t\tthrow Error('You cannot set both hideAll and showAll props to true, cmon now')\n\n\tconst rPreviousSelectedShapeIds = useRef<Set<TLShapeId>>(new Set())\n\n\tconst idsToDisplay = useValue(\n\t\t'should display selected ids',\n\t\t() => {\n\t\t\tconst prev = rPreviousSelectedShapeIds.current\n\t\t\tconst next = new Set<TLShapeId>()\n\n\t\t\tconst instanceState = editor.getInstanceState()\n\n\t\t\tconst isChangingStyle = instanceState.isChangingStyle\n\n\t\t\t// todo: this is tldraw specific and is duplicated at the tldraw layer. What should we do here instead?\n\n\t\t\tconst isIdleOrEditing = editor.isInAny('select.idle', 'select.editing_shape')\n\n\t\t\tconst isInSelectState = editor.isInAny(\n\t\t\t\t'select.brushing',\n\t\t\t\t'select.scribble_brushing',\n\t\t\t\t'select.pointing_shape',\n\t\t\t\t'select.pointing_selection',\n\t\t\t\t'select.pointing_handle'\n\t\t\t)\n\n\t\t\t// We hide all indicators if we're changing style or in certain interactions\n\t\t\t// todo: move this to some kind of Tool.hideIndicators property\n\t\t\tif (isChangingStyle || !(isIdleOrEditing || isInSelectState)) {\n\t\t\t\trPreviousSelectedShapeIds.current = next\n\t\t\t\treturn next\n\t\t\t}\n\n\t\t\t// We always want to show indicators for the selected shapes, if any\n\t\t\tfor (const id of editor.getSelectedShapeIds()) {\n\t\t\t\tnext.add(id)\n\t\t\t}\n\n\t\t\t// If we're idle or editing a shape, we want to also show an indicator for the hovered shape, if any\n\t\t\tif (isIdleOrEditing && instanceState.isHoveringCanvas && !instanceState.isCoarsePointer) {\n\t\t\t\tconst hovered = editor.getHoveredShapeId()\n\t\t\t\tif (hovered) next.add(hovered)\n\t\t\t}\n\n\t\t\t// Ok, has anything changed?\n\n\t\t\t// If the number of items in the set is different, then the selection has changed. This catches most changes.\n\t\t\tif (prev.size !== next.size) {\n\t\t\t\trPreviousSelectedShapeIds.current = next\n\t\t\t\treturn next\n\t\t\t}\n\n\t\t\t// Set difference check\n\t\t\tfor (const id of next) {\n\t\t\t\tif (!prev.has(id)) {\n\t\t\t\t\trPreviousSelectedShapeIds.current = next\n\t\t\t\t\treturn next\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn prev\n\t\t},\n\t\t[editor]\n\t)\n\n\t// Show indicators only for the shapes that are currently being rendered (ie that are on screen)\n\tconst renderingShapes = useValue('rendering shapes', () => editor.getRenderingShapes(), [editor])\n\n\tconst { ShapeIndicator } = useEditorComponents()\n\tif (!ShapeIndicator) return null\n\n\treturn renderingShapes.map(({ id }) => (\n\t\t<ShapeIndicator\n\t\t\tkey={id + '_indicator'}\n\t\t\tshapeId={id}\n\t\t\thidden={!showAll && (hideAll || !idsToDisplay.has(id))}\n\t\t/>\n\t))\n})\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA8FE;AA9FF,yBAAyB;AAEzB,mBAA6B;AAC7B,uBAA0B;AAC1B,iCAAoC;AAW7B,MAAM,6BAAyB,mBAAK,SAASA,wBAAuB;AAAA,EAC1E;AAAA,EACA;AACD,GAA2B;AAC1B,QAAM,aAAS,4BAAU;AAEzB,MAAI,WAAW;AACd,UAAM,MAAM,iEAAiE;AAE9E,QAAM,gCAA4B,qBAAuB,oBAAI,IAAI,CAAC;AAElE,QAAM,mBAAe;AAAA,IACpB;AAAA,IACA,MAAM;AACL,YAAM,OAAO,0BAA0B;AACvC,YAAM,OAAO,oBAAI,IAAe;AAEhC,YAAM,gBAAgB,OAAO,iBAAiB;AAE9C,YAAM,kBAAkB,cAAc;AAItC,YAAM,kBAAkB,OAAO,QAAQ,eAAe,sBAAsB;AAE5E,YAAM,kBAAkB,OAAO;AAAA,QAC9B;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACD;AAIA,UAAI,mBAAmB,EAAE,mBAAmB,kBAAkB;AAC7D,kCAA0B,UAAU;AACpC,eAAO;AAAA,MACR;AAGA,iBAAW,MAAM,OAAO,oBAAoB,GAAG;AAC9C,aAAK,IAAI,EAAE;AAAA,MACZ;AAGA,UAAI,mBAAmB,cAAc,oBAAoB,CAAC,cAAc,iBAAiB;AACxF,cAAM,UAAU,OAAO,kBAAkB;AACzC,YAAI,QAAS,MAAK,IAAI,OAAO;AAAA,MAC9B;AAKA,UAAI,KAAK,SAAS,KAAK,MAAM;AAC5B,kCAA0B,UAAU;AACpC,eAAO;AAAA,MACR;AAGA,iBAAW,MAAM,MAAM;AACtB,YAAI,CAAC,KAAK,IAAI,EAAE,GAAG;AAClB,oCAA0B,UAAU;AACpC,iBAAO;AAAA,QACR;AAAA,MACD;AAEA,aAAO;AAAA,IACR;AAAA,IACA,CAAC,MAAM;AAAA,EACR;AAGA,QAAM,sBAAkB,6BAAS,oBAAoB,MAAM,OAAO,mBAAmB,GAAG,CAAC,MAAM,CAAC;AAEhG,QAAM,EAAE,eAAe,QAAI,gDAAoB;AAC/C,MAAI,CAAC,eAAgB,QAAO;AAE5B,SAAO,gBAAgB,IAAI,CAAC,EAAE,GAAG,MAChC;AAAA,IAAC;AAAA;AAAA,MAEA,SAAS;AAAA,MACT,QAAQ,CAAC,YAAY,WAAW,CAAC,aAAa,IAAI,EAAE;AAAA;AAAA,IAF/C,KAAK;AAAA,EAGX,CACA;AACF,CAAC;",
|
|
6
6
|
"names": ["DefaultShapeIndicators"]
|
|
7
7
|
}
|
|
@@ -50,7 +50,19 @@ class StyleEmbedder {
|
|
|
50
50
|
}
|
|
51
51
|
readElementStyles(element, { shouldRespectDefaults = true, shouldSkipInheritedParentStyles = true }) {
|
|
52
52
|
const defaultStyles = shouldRespectDefaults ? getDefaultStylesForTagName(element.tagName.toLowerCase()) : NO_STYLES;
|
|
53
|
-
const parentStyles =
|
|
53
|
+
const parentStyles = Object.assign({}, NO_STYLES);
|
|
54
|
+
if (shouldSkipInheritedParentStyles) {
|
|
55
|
+
let el = element.parentElement;
|
|
56
|
+
while (el) {
|
|
57
|
+
const currentStyles = this.styles.get(el)?.self;
|
|
58
|
+
for (const style in currentStyles) {
|
|
59
|
+
if (!parentStyles[style]) {
|
|
60
|
+
parentStyles[style] = currentStyles[style];
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
el = el.parentElement;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
54
66
|
const info = {
|
|
55
67
|
self: styleFromElement(element, { defaultStyles, parentStyles }),
|
|
56
68
|
before: styleFromPseudoElement(element, "::before"),
|
|
@@ -177,6 +189,8 @@ function styleFromComputedStyleMap(style, { defaultStyles, parentStyles }) {
|
|
|
177
189
|
const value = style.get(property).toString();
|
|
178
190
|
if (defaultStyles[property] === value) continue;
|
|
179
191
|
if (parentStyles[property] === value && (0, import_parseCss.isPropertyInherited)(property)) continue;
|
|
192
|
+
if ((0, import_parseCss.isPropertyCoveredByCurrentColor)(style.get("color")?.toString() || "", property, value))
|
|
193
|
+
continue;
|
|
180
194
|
styles[property] = value;
|
|
181
195
|
}
|
|
182
196
|
return styles;
|
|
@@ -188,6 +202,7 @@ function styleFromComputedStyle(style, { defaultStyles, parentStyles }) {
|
|
|
188
202
|
const value = style.getPropertyValue(property);
|
|
189
203
|
if (defaultStyles[property] === value) continue;
|
|
190
204
|
if (parentStyles[property] === value && (0, import_parseCss.isPropertyInherited)(property)) continue;
|
|
205
|
+
if ((0, import_parseCss.isPropertyCoveredByCurrentColor)(style.color, property, value)) continue;
|
|
191
206
|
styles[property] = value;
|
|
192
207
|
}
|
|
193
208
|
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 { isPropertyInherited, parseCssValueUrls, shouldIncludeCssProperty } 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 = shouldSkipInheritedParentStyles\n\t\t\t? (this.styles.get(element.parentElement as Element)?.self ?? NO_STYLES)\n\t\t\t: NO_STYLES\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\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\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,mBAAwD;AACxD,0BAA6B;AAC7B,sBAKO;AACP,wBAAkC;AAClC,
|
|
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": "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",
|
|
6
6
|
"names": ["document"]
|
|
7
7
|
}
|
|
@@ -18,6 +18,7 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
18
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
19
|
var parseCss_exports = {};
|
|
20
20
|
__export(parseCss_exports, {
|
|
21
|
+
isPropertyCoveredByCurrentColor: () => isPropertyCoveredByCurrentColor,
|
|
21
22
|
isPropertyInherited: () => isPropertyInherited,
|
|
22
23
|
parseCss: () => parseCss,
|
|
23
24
|
parseCssFontFaces: () => parseCssFontFaces,
|
|
@@ -96,11 +97,33 @@ function parseCssValueUrls(value) {
|
|
|
96
97
|
url: m[1] || m[2] || m[3]
|
|
97
98
|
}));
|
|
98
99
|
}
|
|
100
|
+
const currentColorProperties = /* @__PURE__ */ new Set([
|
|
101
|
+
"border-block-end-color",
|
|
102
|
+
"border-block-start-color",
|
|
103
|
+
"border-bottom-color",
|
|
104
|
+
"border-inline-end-color",
|
|
105
|
+
"border-inline-start-color",
|
|
106
|
+
"border-left-color",
|
|
107
|
+
"border-right-color",
|
|
108
|
+
"border-top-color",
|
|
109
|
+
"caret-color",
|
|
110
|
+
"column-rule-color",
|
|
111
|
+
"outline-color",
|
|
112
|
+
"text-decoration",
|
|
113
|
+
"text-decoration-color",
|
|
114
|
+
"text-emphasis-color"
|
|
115
|
+
]);
|
|
116
|
+
function isPropertyCoveredByCurrentColor(currentColor, property, value) {
|
|
117
|
+
if (currentColorProperties.has(property)) {
|
|
118
|
+
return value === "currentColor" || value === currentColor || property === "text-decoration" && value === `none solid ${currentColor}`;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
99
121
|
const inheritedProperties = /* @__PURE__ */ new Set([
|
|
100
122
|
"border-collapse",
|
|
101
123
|
"border-spacing",
|
|
102
124
|
"caption-side",
|
|
103
|
-
|
|
125
|
+
// N.B. We shouldn't inherit 'color' because there's some UA styling, e.g. `mark` elements
|
|
126
|
+
// 'color',
|
|
104
127
|
"cursor",
|
|
105
128
|
"direction",
|
|
106
129
|
"empty-cells",
|
|
@@ -121,16 +144,18 @@ const inheritedProperties = /* @__PURE__ */ new Set([
|
|
|
121
144
|
"orphans",
|
|
122
145
|
"overflow-wrap",
|
|
123
146
|
"quotes",
|
|
147
|
+
"stroke-linecap",
|
|
148
|
+
"stroke-linejoin",
|
|
124
149
|
"tab-size",
|
|
125
150
|
"text-align",
|
|
126
151
|
"text-align-last",
|
|
127
|
-
"text-decoration-color",
|
|
128
152
|
"text-indent",
|
|
129
153
|
"text-justify",
|
|
130
154
|
"text-shadow",
|
|
131
155
|
"text-transform",
|
|
132
156
|
"visibility",
|
|
133
157
|
"white-space",
|
|
158
|
+
"white-space-collapse",
|
|
134
159
|
"widows",
|
|
135
160
|
"word-break",
|
|
136
161
|
"word-spacing",
|
|
@@ -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\nconst inheritedProperties = new Set([\n\t'border-collapse',\n\t'border-spacing',\n\t'caption-side',\n\t'color',\n\t'cursor',\n\t'direction',\n\t'empty-cells',\n\t'font-family',\n\t'font-size',\n\t'font-style',\n\t'font-variant',\n\t'font-weight',\n\t'font-size-adjust',\n\t'font-stretch',\n\t'font',\n\t'letter-spacing',\n\t'line-height',\n\t'list-style-image',\n\t'list-style-position',\n\t'list-style-type',\n\t'list-style',\n\t'orphans',\n\t'overflow-wrap',\n\t'quotes',\n\t'
|
|
5
|
-
"mappings": "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",
|
|
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\nconst currentColorProperties = new Set([\n\t'border-block-end-color',\n\t'border-block-start-color',\n\t'border-bottom-color',\n\t'border-inline-end-color',\n\t'border-inline-start-color',\n\t'border-left-color',\n\t'border-right-color',\n\t'border-top-color',\n\t'caret-color',\n\t'column-rule-color',\n\t'outline-color',\n\t'text-decoration',\n\t'text-decoration-color',\n\t'text-emphasis-color',\n])\n\nexport function isPropertyCoveredByCurrentColor(\n\tcurrentColor: string,\n\tproperty: string,\n\tvalue: string\n) {\n\tif (currentColorProperties.has(property)) {\n\t\treturn (\n\t\t\tvalue === 'currentColor' ||\n\t\t\tvalue === currentColor ||\n\t\t\t(property === 'text-decoration' && value === `none solid ${currentColor}`)\n\t\t)\n\t}\n}\n\nconst inheritedProperties = new Set([\n\t'border-collapse',\n\t'border-spacing',\n\t'caption-side',\n\t// N.B. We shouldn't inherit 'color' because there's some UA styling, e.g. `mark` elements\n\t// 'color',\n\t'cursor',\n\t'direction',\n\t'empty-cells',\n\t'font-family',\n\t'font-size',\n\t'font-style',\n\t'font-variant',\n\t'font-weight',\n\t'font-size-adjust',\n\t'font-stretch',\n\t'font',\n\t'letter-spacing',\n\t'line-height',\n\t'list-style-image',\n\t'list-style-position',\n\t'list-style-type',\n\t'list-style',\n\t'orphans',\n\t'overflow-wrap',\n\t'quotes',\n\t'stroke-linecap',\n\t'stroke-linejoin',\n\t'tab-size',\n\t'text-align',\n\t'text-align-last',\n\t'text-indent',\n\t'text-justify',\n\t'text-shadow',\n\t'text-transform',\n\t'visibility',\n\t'white-space',\n\t'white-space-collapse',\n\t'widows',\n\t'word-break',\n\t'word-spacing',\n\t'word-wrap',\n])\n\nexport function isPropertyInherited(property: string) {\n\treturn inheritedProperties.has(property)\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["m"]
|
|
7
7
|
}
|
package/dist-cjs/version.js
CHANGED
|
@@ -22,10 +22,10 @@ __export(version_exports, {
|
|
|
22
22
|
version: () => version
|
|
23
23
|
});
|
|
24
24
|
module.exports = __toCommonJS(version_exports);
|
|
25
|
-
const version = "3.11.0-canary.
|
|
25
|
+
const version = "3.11.0-canary.f0072703bfd4";
|
|
26
26
|
const publishDates = {
|
|
27
27
|
major: "2024-09-13T14:36:29.063Z",
|
|
28
|
-
minor: "2025-03-
|
|
29
|
-
patch: "2025-03-
|
|
28
|
+
minor: "2025-03-19T13:05:59.554Z",
|
|
29
|
+
patch: "2025-03-19T13:05:59.554Z"
|
|
30
30
|
};
|
|
31
31
|
//# sourceMappingURL=version.js.map
|
package/dist-cjs/version.js.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.11.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.11.0-canary.f0072703bfd4'\nexport const publishDates = {\n\tmajor: '2024-09-13T14:36:29.063Z',\n\tminor: '2025-03-19T13:05:59.554Z',\n\tpatch: '2025-03-19T13:05:59.554Z',\n}\n"],
|
|
5
5
|
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGO,MAAM,UAAU;AAChB,MAAM,eAAe;AAAA,EAC3B,OAAO;AAAA,EACP,OAAO;AAAA,EACP,OAAO;AACR;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist-esm/index.mjs
CHANGED
|
@@ -16,30 +16,26 @@ const DefaultShapeIndicators = memo(function DefaultShapeIndicators2({
|
|
|
16
16
|
() => {
|
|
17
17
|
const prev = rPreviousSelectedShapeIds.current;
|
|
18
18
|
const next = /* @__PURE__ */ new Set();
|
|
19
|
-
const
|
|
19
|
+
const instanceState = editor.getInstanceState();
|
|
20
|
+
const isChangingStyle = instanceState.isChangingStyle;
|
|
21
|
+
const isIdleOrEditing = editor.isInAny("select.idle", "select.editing_shape");
|
|
20
22
|
const isInSelectState = editor.isInAny(
|
|
21
|
-
"select.idle",
|
|
22
23
|
"select.brushing",
|
|
23
24
|
"select.scribble_brushing",
|
|
24
|
-
"select.editing_shape",
|
|
25
25
|
"select.pointing_shape",
|
|
26
26
|
"select.pointing_selection",
|
|
27
27
|
"select.pointing_handle"
|
|
28
28
|
);
|
|
29
|
-
if (isChangingStyle || !isInSelectState) {
|
|
29
|
+
if (isChangingStyle || !(isIdleOrEditing || isInSelectState)) {
|
|
30
30
|
rPreviousSelectedShapeIds.current = next;
|
|
31
31
|
return next;
|
|
32
32
|
}
|
|
33
|
-
const
|
|
34
|
-
for (const id of selected) {
|
|
33
|
+
for (const id of editor.getSelectedShapeIds()) {
|
|
35
34
|
next.add(id);
|
|
36
35
|
}
|
|
37
|
-
if (
|
|
38
|
-
const
|
|
39
|
-
if (
|
|
40
|
-
const hovered = editor.getHoveredShapeId();
|
|
41
|
-
if (hovered) next.add(hovered);
|
|
42
|
-
}
|
|
36
|
+
if (isIdleOrEditing && instanceState.isHoveringCanvas && !instanceState.isCoarsePointer) {
|
|
37
|
+
const hovered = editor.getHoveredShapeId();
|
|
38
|
+
if (hovered) next.add(hovered);
|
|
43
39
|
}
|
|
44
40
|
if (prev.size !== next.size) {
|
|
45
41
|
rPreviousSelectedShapeIds.current = next;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/lib/components/default-components/DefaultShapeIndicators.tsx"],
|
|
4
|
-
"sourcesContent": ["import { useValue } from '@tldraw/state-react'\nimport { TLShapeId } from '@tldraw/tlschema'\nimport { memo, useRef } from 'react'\nimport { useEditor } from '../../hooks/useEditor'\nimport { useEditorComponents } from '../../hooks/useEditorComponents'\n\n/** @public */\nexport interface TLShapeIndicatorsProps {\n\t/** Whether to hide all of the indicators */\n\thideAll?: boolean\n\t/** Whether to show all of the indicators */\n\tshowAll?: boolean\n}\n\n/** @public @react */\nexport const DefaultShapeIndicators = memo(function DefaultShapeIndicators({\n\thideAll,\n\tshowAll,\n}: TLShapeIndicatorsProps) {\n\tconst editor = useEditor()\n\n\tif (hideAll && showAll)\n\t\tthrow Error('You cannot set both hideAll and showAll props to true, cmon now')\n\n\tconst rPreviousSelectedShapeIds = useRef<Set<TLShapeId>>(new Set())\n\n\tconst idsToDisplay = useValue(\n\t\t'should display selected ids',\n\t\t() => {\n\t\t\tconst prev = rPreviousSelectedShapeIds.current\n\t\t\tconst next = new Set<TLShapeId>()\n\n\t\t\tconst
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["import { useValue } from '@tldraw/state-react'\nimport { TLShapeId } from '@tldraw/tlschema'\nimport { memo, useRef } from 'react'\nimport { useEditor } from '../../hooks/useEditor'\nimport { useEditorComponents } from '../../hooks/useEditorComponents'\n\n/** @public */\nexport interface TLShapeIndicatorsProps {\n\t/** Whether to hide all of the indicators */\n\thideAll?: boolean\n\t/** Whether to show all of the indicators */\n\tshowAll?: boolean\n}\n\n/** @public @react */\nexport const DefaultShapeIndicators = memo(function DefaultShapeIndicators({\n\thideAll,\n\tshowAll,\n}: TLShapeIndicatorsProps) {\n\tconst editor = useEditor()\n\n\tif (hideAll && showAll)\n\t\tthrow Error('You cannot set both hideAll and showAll props to true, cmon now')\n\n\tconst rPreviousSelectedShapeIds = useRef<Set<TLShapeId>>(new Set())\n\n\tconst idsToDisplay = useValue(\n\t\t'should display selected ids',\n\t\t() => {\n\t\t\tconst prev = rPreviousSelectedShapeIds.current\n\t\t\tconst next = new Set<TLShapeId>()\n\n\t\t\tconst instanceState = editor.getInstanceState()\n\n\t\t\tconst isChangingStyle = instanceState.isChangingStyle\n\n\t\t\t// todo: this is tldraw specific and is duplicated at the tldraw layer. What should we do here instead?\n\n\t\t\tconst isIdleOrEditing = editor.isInAny('select.idle', 'select.editing_shape')\n\n\t\t\tconst isInSelectState = editor.isInAny(\n\t\t\t\t'select.brushing',\n\t\t\t\t'select.scribble_brushing',\n\t\t\t\t'select.pointing_shape',\n\t\t\t\t'select.pointing_selection',\n\t\t\t\t'select.pointing_handle'\n\t\t\t)\n\n\t\t\t// We hide all indicators if we're changing style or in certain interactions\n\t\t\t// todo: move this to some kind of Tool.hideIndicators property\n\t\t\tif (isChangingStyle || !(isIdleOrEditing || isInSelectState)) {\n\t\t\t\trPreviousSelectedShapeIds.current = next\n\t\t\t\treturn next\n\t\t\t}\n\n\t\t\t// We always want to show indicators for the selected shapes, if any\n\t\t\tfor (const id of editor.getSelectedShapeIds()) {\n\t\t\t\tnext.add(id)\n\t\t\t}\n\n\t\t\t// If we're idle or editing a shape, we want to also show an indicator for the hovered shape, if any\n\t\t\tif (isIdleOrEditing && instanceState.isHoveringCanvas && !instanceState.isCoarsePointer) {\n\t\t\t\tconst hovered = editor.getHoveredShapeId()\n\t\t\t\tif (hovered) next.add(hovered)\n\t\t\t}\n\n\t\t\t// Ok, has anything changed?\n\n\t\t\t// If the number of items in the set is different, then the selection has changed. This catches most changes.\n\t\t\tif (prev.size !== next.size) {\n\t\t\t\trPreviousSelectedShapeIds.current = next\n\t\t\t\treturn next\n\t\t\t}\n\n\t\t\t// Set difference check\n\t\t\tfor (const id of next) {\n\t\t\t\tif (!prev.has(id)) {\n\t\t\t\t\trPreviousSelectedShapeIds.current = next\n\t\t\t\t\treturn next\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn prev\n\t\t},\n\t\t[editor]\n\t)\n\n\t// Show indicators only for the shapes that are currently being rendered (ie that are on screen)\n\tconst renderingShapes = useValue('rendering shapes', () => editor.getRenderingShapes(), [editor])\n\n\tconst { ShapeIndicator } = useEditorComponents()\n\tif (!ShapeIndicator) return null\n\n\treturn renderingShapes.map(({ id }) => (\n\t\t<ShapeIndicator\n\t\t\tkey={id + '_indicator'}\n\t\t\tshapeId={id}\n\t\t\thidden={!showAll && (hideAll || !idsToDisplay.has(id))}\n\t\t/>\n\t))\n})\n"],
|
|
5
|
+
"mappings": "AA8FE;AA9FF,SAAS,gBAAgB;AAEzB,SAAS,MAAM,cAAc;AAC7B,SAAS,iBAAiB;AAC1B,SAAS,2BAA2B;AAW7B,MAAM,yBAAyB,KAAK,SAASA,wBAAuB;AAAA,EAC1E;AAAA,EACA;AACD,GAA2B;AAC1B,QAAM,SAAS,UAAU;AAEzB,MAAI,WAAW;AACd,UAAM,MAAM,iEAAiE;AAE9E,QAAM,4BAA4B,OAAuB,oBAAI,IAAI,CAAC;AAElE,QAAM,eAAe;AAAA,IACpB;AAAA,IACA,MAAM;AACL,YAAM,OAAO,0BAA0B;AACvC,YAAM,OAAO,oBAAI,IAAe;AAEhC,YAAM,gBAAgB,OAAO,iBAAiB;AAE9C,YAAM,kBAAkB,cAAc;AAItC,YAAM,kBAAkB,OAAO,QAAQ,eAAe,sBAAsB;AAE5E,YAAM,kBAAkB,OAAO;AAAA,QAC9B;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACD;AAIA,UAAI,mBAAmB,EAAE,mBAAmB,kBAAkB;AAC7D,kCAA0B,UAAU;AACpC,eAAO;AAAA,MACR;AAGA,iBAAW,MAAM,OAAO,oBAAoB,GAAG;AAC9C,aAAK,IAAI,EAAE;AAAA,MACZ;AAGA,UAAI,mBAAmB,cAAc,oBAAoB,CAAC,cAAc,iBAAiB;AACxF,cAAM,UAAU,OAAO,kBAAkB;AACzC,YAAI,QAAS,MAAK,IAAI,OAAO;AAAA,MAC9B;AAKA,UAAI,KAAK,SAAS,KAAK,MAAM;AAC5B,kCAA0B,UAAU;AACpC,eAAO;AAAA,MACR;AAGA,iBAAW,MAAM,MAAM;AACtB,YAAI,CAAC,KAAK,IAAI,EAAE,GAAG;AAClB,oCAA0B,UAAU;AACpC,iBAAO;AAAA,QACR;AAAA,MACD;AAEA,aAAO;AAAA,IACR;AAAA,IACA,CAAC,MAAM;AAAA,EACR;AAGA,QAAM,kBAAkB,SAAS,oBAAoB,MAAM,OAAO,mBAAmB,GAAG,CAAC,MAAM,CAAC;AAEhG,QAAM,EAAE,eAAe,IAAI,oBAAoB;AAC/C,MAAI,CAAC,eAAgB,QAAO;AAE5B,SAAO,gBAAgB,IAAI,CAAC,EAAE,GAAG,MAChC;AAAA,IAAC;AAAA;AAAA,MAEA,SAAS;AAAA,MACT,QAAQ,CAAC,YAAY,WAAW,CAAC,aAAa,IAAI,EAAE;AAAA;AAAA,IAF/C,KAAK;AAAA,EAGX,CACA;AACF,CAAC;",
|
|
6
6
|
"names": ["DefaultShapeIndicators"]
|
|
7
7
|
}
|
|
@@ -7,7 +7,12 @@ import {
|
|
|
7
7
|
getRenderedChildren
|
|
8
8
|
} from "./domUtils.mjs";
|
|
9
9
|
import { resourceToDataUrl } from "./fetchCache.mjs";
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
isPropertyCoveredByCurrentColor,
|
|
12
|
+
isPropertyInherited,
|
|
13
|
+
parseCssValueUrls,
|
|
14
|
+
shouldIncludeCssProperty
|
|
15
|
+
} from "./parseCss.mjs";
|
|
11
16
|
const NO_STYLES = {};
|
|
12
17
|
class StyleEmbedder {
|
|
13
18
|
constructor(root) {
|
|
@@ -32,7 +37,19 @@ class StyleEmbedder {
|
|
|
32
37
|
}
|
|
33
38
|
readElementStyles(element, { shouldRespectDefaults = true, shouldSkipInheritedParentStyles = true }) {
|
|
34
39
|
const defaultStyles = shouldRespectDefaults ? getDefaultStylesForTagName(element.tagName.toLowerCase()) : NO_STYLES;
|
|
35
|
-
const parentStyles =
|
|
40
|
+
const parentStyles = Object.assign({}, NO_STYLES);
|
|
41
|
+
if (shouldSkipInheritedParentStyles) {
|
|
42
|
+
let el = element.parentElement;
|
|
43
|
+
while (el) {
|
|
44
|
+
const currentStyles = this.styles.get(el)?.self;
|
|
45
|
+
for (const style in currentStyles) {
|
|
46
|
+
if (!parentStyles[style]) {
|
|
47
|
+
parentStyles[style] = currentStyles[style];
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
el = el.parentElement;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
36
53
|
const info = {
|
|
37
54
|
self: styleFromElement(element, { defaultStyles, parentStyles }),
|
|
38
55
|
before: styleFromPseudoElement(element, "::before"),
|
|
@@ -159,6 +176,8 @@ function styleFromComputedStyleMap(style, { defaultStyles, parentStyles }) {
|
|
|
159
176
|
const value = style.get(property).toString();
|
|
160
177
|
if (defaultStyles[property] === value) continue;
|
|
161
178
|
if (parentStyles[property] === value && isPropertyInherited(property)) continue;
|
|
179
|
+
if (isPropertyCoveredByCurrentColor(style.get("color")?.toString() || "", property, value))
|
|
180
|
+
continue;
|
|
162
181
|
styles[property] = value;
|
|
163
182
|
}
|
|
164
183
|
return styles;
|
|
@@ -170,6 +189,7 @@ function styleFromComputedStyle(style, { defaultStyles, parentStyles }) {
|
|
|
170
189
|
const value = style.getPropertyValue(property);
|
|
171
190
|
if (defaultStyles[property] === value) continue;
|
|
172
191
|
if (parentStyles[property] === value && isPropertyInherited(property)) continue;
|
|
192
|
+
if (isPropertyCoveredByCurrentColor(style.color, property, value)) continue;
|
|
173
193
|
styles[property] = value;
|
|
174
194
|
}
|
|
175
195
|
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 { isPropertyInherited, parseCssValueUrls, shouldIncludeCssProperty } 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 = shouldSkipInheritedParentStyles\n\t\t\t? (this.styles.get(element.parentElement as Element)?.self ?? NO_STYLES)\n\t\t\t: NO_STYLES\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\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\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;AACxD,SAAS,oBAAoB;AAC7B;AAAA,EACC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACM;AACP,SAAS,yBAAyB;AAClC,
|
|
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": "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",
|
|
6
6
|
"names": ["document"]
|
|
7
7
|
}
|
|
@@ -67,11 +67,33 @@ 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
|
+
}
|
|
70
91
|
const inheritedProperties = /* @__PURE__ */ new Set([
|
|
71
92
|
"border-collapse",
|
|
72
93
|
"border-spacing",
|
|
73
94
|
"caption-side",
|
|
74
|
-
|
|
95
|
+
// N.B. We shouldn't inherit 'color' because there's some UA styling, e.g. `mark` elements
|
|
96
|
+
// 'color',
|
|
75
97
|
"cursor",
|
|
76
98
|
"direction",
|
|
77
99
|
"empty-cells",
|
|
@@ -92,16 +114,18 @@ const inheritedProperties = /* @__PURE__ */ new Set([
|
|
|
92
114
|
"orphans",
|
|
93
115
|
"overflow-wrap",
|
|
94
116
|
"quotes",
|
|
117
|
+
"stroke-linecap",
|
|
118
|
+
"stroke-linejoin",
|
|
95
119
|
"tab-size",
|
|
96
120
|
"text-align",
|
|
97
121
|
"text-align-last",
|
|
98
|
-
"text-decoration-color",
|
|
99
122
|
"text-indent",
|
|
100
123
|
"text-justify",
|
|
101
124
|
"text-shadow",
|
|
102
125
|
"text-transform",
|
|
103
126
|
"visibility",
|
|
104
127
|
"white-space",
|
|
128
|
+
"white-space-collapse",
|
|
105
129
|
"widows",
|
|
106
130
|
"word-break",
|
|
107
131
|
"word-spacing",
|
|
@@ -111,6 +135,7 @@ function isPropertyInherited(property) {
|
|
|
111
135
|
return inheritedProperties.has(property);
|
|
112
136
|
}
|
|
113
137
|
export {
|
|
138
|
+
isPropertyCoveredByCurrentColor,
|
|
114
139
|
isPropertyInherited,
|
|
115
140
|
parseCss,
|
|
116
141
|
parseCssFontFaces,
|
|
@@ -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\nconst inheritedProperties = new Set([\n\t'border-collapse',\n\t'border-spacing',\n\t'caption-side',\n\t'color',\n\t'cursor',\n\t'direction',\n\t'empty-cells',\n\t'font-family',\n\t'font-size',\n\t'font-style',\n\t'font-variant',\n\t'font-weight',\n\t'font-size-adjust',\n\t'font-stretch',\n\t'font',\n\t'letter-spacing',\n\t'line-height',\n\t'list-style-image',\n\t'list-style-position',\n\t'list-style-type',\n\t'list-style',\n\t'orphans',\n\t'overflow-wrap',\n\t'quotes',\n\t'
|
|
5
|
-
"mappings": "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",
|
|
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\nconst currentColorProperties = new Set([\n\t'border-block-end-color',\n\t'border-block-start-color',\n\t'border-bottom-color',\n\t'border-inline-end-color',\n\t'border-inline-start-color',\n\t'border-left-color',\n\t'border-right-color',\n\t'border-top-color',\n\t'caret-color',\n\t'column-rule-color',\n\t'outline-color',\n\t'text-decoration',\n\t'text-decoration-color',\n\t'text-emphasis-color',\n])\n\nexport function isPropertyCoveredByCurrentColor(\n\tcurrentColor: string,\n\tproperty: string,\n\tvalue: string\n) {\n\tif (currentColorProperties.has(property)) {\n\t\treturn (\n\t\t\tvalue === 'currentColor' ||\n\t\t\tvalue === currentColor ||\n\t\t\t(property === 'text-decoration' && value === `none solid ${currentColor}`)\n\t\t)\n\t}\n}\n\nconst inheritedProperties = new Set([\n\t'border-collapse',\n\t'border-spacing',\n\t'caption-side',\n\t// N.B. We shouldn't inherit 'color' because there's some UA styling, e.g. `mark` elements\n\t// 'color',\n\t'cursor',\n\t'direction',\n\t'empty-cells',\n\t'font-family',\n\t'font-size',\n\t'font-style',\n\t'font-variant',\n\t'font-weight',\n\t'font-size-adjust',\n\t'font-stretch',\n\t'font',\n\t'letter-spacing',\n\t'line-height',\n\t'list-style-image',\n\t'list-style-position',\n\t'list-style-type',\n\t'list-style',\n\t'orphans',\n\t'overflow-wrap',\n\t'quotes',\n\t'stroke-linecap',\n\t'stroke-linejoin',\n\t'tab-size',\n\t'text-align',\n\t'text-align-last',\n\t'text-indent',\n\t'text-justify',\n\t'text-shadow',\n\t'text-transform',\n\t'visibility',\n\t'white-space',\n\t'white-space-collapse',\n\t'widows',\n\t'word-break',\n\t'word-spacing',\n\t'word-wrap',\n])\n\nexport function isPropertyInherited(property: string) {\n\treturn inheritedProperties.has(property)\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["m"]
|
|
7
7
|
}
|
package/dist-esm/version.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
const version = "3.11.0-canary.
|
|
1
|
+
const version = "3.11.0-canary.f0072703bfd4";
|
|
2
2
|
const publishDates = {
|
|
3
3
|
major: "2024-09-13T14:36:29.063Z",
|
|
4
|
-
minor: "2025-03-
|
|
5
|
-
patch: "2025-03-
|
|
4
|
+
minor: "2025-03-19T13:05:59.554Z",
|
|
5
|
+
patch: "2025-03-19T13:05:59.554Z"
|
|
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.11.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.11.0-canary.f0072703bfd4'\nexport const publishDates = {\n\tmajor: '2024-09-13T14:36:29.063Z',\n\tminor: '2025-03-19T13:05:59.554Z',\n\tpatch: '2025-03-19T13:05:59.554Z',\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.11.0-canary.
|
|
4
|
+
"version": "3.11.0-canary.f0072703bfd4",
|
|
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.11.0-canary.
|
|
52
|
-
"@tldraw/state-react": "3.11.0-canary.
|
|
53
|
-
"@tldraw/store": "3.11.0-canary.
|
|
54
|
-
"@tldraw/tlschema": "3.11.0-canary.
|
|
55
|
-
"@tldraw/utils": "3.11.0-canary.
|
|
56
|
-
"@tldraw/validate": "3.11.0-canary.
|
|
51
|
+
"@tldraw/state": "3.11.0-canary.f0072703bfd4",
|
|
52
|
+
"@tldraw/state-react": "3.11.0-canary.f0072703bfd4",
|
|
53
|
+
"@tldraw/store": "3.11.0-canary.f0072703bfd4",
|
|
54
|
+
"@tldraw/tlschema": "3.11.0-canary.f0072703bfd4",
|
|
55
|
+
"@tldraw/utils": "3.11.0-canary.f0072703bfd4",
|
|
56
|
+
"@tldraw/validate": "3.11.0-canary.f0072703bfd4",
|
|
57
57
|
"@types/core-js": "^2.5.8",
|
|
58
58
|
"@use-gesture/react": "^10.3.1",
|
|
59
59
|
"classnames": "^2.5.1",
|
|
@@ -72,12 +72,15 @@
|
|
|
72
72
|
"@testing-library/jest-dom": "^5.17.0",
|
|
73
73
|
"@testing-library/react": "^15.0.7",
|
|
74
74
|
"@types/benchmark": "^2.1.5",
|
|
75
|
+
"@types/react": "^18.3.18",
|
|
75
76
|
"@types/wicg-file-system-access": "^2020.9.8",
|
|
76
77
|
"benchmark": "^2.1.4",
|
|
77
78
|
"fake-indexeddb": "^4.0.2",
|
|
78
79
|
"jest-canvas-mock": "^2.5.2",
|
|
79
80
|
"jest-environment-jsdom": "^29.7.0",
|
|
80
81
|
"lazyrepo": "0.0.0-alpha.27",
|
|
82
|
+
"react": "^18.3.1",
|
|
83
|
+
"react-dom": "^18.3.1",
|
|
81
84
|
"resize-observer-polyfill": "^1.5.1"
|
|
82
85
|
},
|
|
83
86
|
"jest": {
|
|
@@ -30,14 +30,17 @@ export const DefaultShapeIndicators = memo(function DefaultShapeIndicators({
|
|
|
30
30
|
const prev = rPreviousSelectedShapeIds.current
|
|
31
31
|
const next = new Set<TLShapeId>()
|
|
32
32
|
|
|
33
|
-
const
|
|
33
|
+
const instanceState = editor.getInstanceState()
|
|
34
|
+
|
|
35
|
+
const isChangingStyle = instanceState.isChangingStyle
|
|
34
36
|
|
|
35
37
|
// todo: this is tldraw specific and is duplicated at the tldraw layer. What should we do here instead?
|
|
38
|
+
|
|
39
|
+
const isIdleOrEditing = editor.isInAny('select.idle', 'select.editing_shape')
|
|
40
|
+
|
|
36
41
|
const isInSelectState = editor.isInAny(
|
|
37
|
-
'select.idle',
|
|
38
42
|
'select.brushing',
|
|
39
43
|
'select.scribble_brushing',
|
|
40
|
-
'select.editing_shape',
|
|
41
44
|
'select.pointing_shape',
|
|
42
45
|
'select.pointing_selection',
|
|
43
46
|
'select.pointing_handle'
|
|
@@ -45,24 +48,20 @@ export const DefaultShapeIndicators = memo(function DefaultShapeIndicators({
|
|
|
45
48
|
|
|
46
49
|
// We hide all indicators if we're changing style or in certain interactions
|
|
47
50
|
// todo: move this to some kind of Tool.hideIndicators property
|
|
48
|
-
if (isChangingStyle || !isInSelectState) {
|
|
51
|
+
if (isChangingStyle || !(isIdleOrEditing || isInSelectState)) {
|
|
49
52
|
rPreviousSelectedShapeIds.current = next
|
|
50
53
|
return next
|
|
51
54
|
}
|
|
52
55
|
|
|
53
56
|
// We always want to show indicators for the selected shapes, if any
|
|
54
|
-
const
|
|
55
|
-
for (const id of selected) {
|
|
57
|
+
for (const id of editor.getSelectedShapeIds()) {
|
|
56
58
|
next.add(id)
|
|
57
59
|
}
|
|
58
60
|
|
|
59
61
|
// If we're idle or editing a shape, we want to also show an indicator for the hovered shape, if any
|
|
60
|
-
if (
|
|
61
|
-
const
|
|
62
|
-
if (
|
|
63
|
-
const hovered = editor.getHoveredShapeId()
|
|
64
|
-
if (hovered) next.add(hovered)
|
|
65
|
-
}
|
|
62
|
+
if (isIdleOrEditing && instanceState.isHoveringCanvas && !instanceState.isCoarsePointer) {
|
|
63
|
+
const hovered = editor.getHoveredShapeId()
|
|
64
|
+
if (hovered) next.add(hovered)
|
|
66
65
|
}
|
|
67
66
|
|
|
68
67
|
// Ok, has anything changed?
|
|
@@ -73,7 +72,7 @@ export const DefaultShapeIndicators = memo(function DefaultShapeIndicators({
|
|
|
73
72
|
return next
|
|
74
73
|
}
|
|
75
74
|
|
|
76
|
-
//
|
|
75
|
+
// Set difference check
|
|
77
76
|
for (const id of next) {
|
|
78
77
|
if (!prev.has(id)) {
|
|
79
78
|
rPreviousSelectedShapeIds.current = next
|
|
@@ -81,7 +80,6 @@ export const DefaultShapeIndicators = memo(function DefaultShapeIndicators({
|
|
|
81
80
|
}
|
|
82
81
|
}
|
|
83
82
|
|
|
84
|
-
// If nothing has changed, then return the previous value
|
|
85
83
|
return prev
|
|
86
84
|
},
|
|
87
85
|
[editor]
|
|
@@ -7,7 +7,12 @@ import {
|
|
|
7
7
|
getRenderedChildren,
|
|
8
8
|
} from './domUtils'
|
|
9
9
|
import { resourceToDataUrl } from './fetchCache'
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
isPropertyCoveredByCurrentColor,
|
|
12
|
+
isPropertyInherited,
|
|
13
|
+
parseCssValueUrls,
|
|
14
|
+
shouldIncludeCssProperty,
|
|
15
|
+
} from './parseCss'
|
|
11
16
|
|
|
12
17
|
type Styles = { [K in string]?: string }
|
|
13
18
|
type ReadonlyStyles = { readonly [K in string]?: string }
|
|
@@ -53,9 +58,20 @@ export class StyleEmbedder {
|
|
|
53
58
|
? getDefaultStylesForTagName(element.tagName.toLowerCase())
|
|
54
59
|
: NO_STYLES
|
|
55
60
|
|
|
56
|
-
const parentStyles =
|
|
57
|
-
|
|
58
|
-
|
|
61
|
+
const parentStyles = Object.assign({}, NO_STYLES) as Styles
|
|
62
|
+
if (shouldSkipInheritedParentStyles) {
|
|
63
|
+
let el = element.parentElement
|
|
64
|
+
// Keep going up the tree to find all the relevant styles
|
|
65
|
+
while (el) {
|
|
66
|
+
const currentStyles = this.styles.get(el)?.self
|
|
67
|
+
for (const style in currentStyles) {
|
|
68
|
+
if (!parentStyles[style]) {
|
|
69
|
+
parentStyles[style] = currentStyles[style]
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
el = el.parentElement
|
|
73
|
+
}
|
|
74
|
+
}
|
|
59
75
|
|
|
60
76
|
const info: ElementStyleInfo = {
|
|
61
77
|
self: styleFromElement(element, { defaultStyles, parentStyles }),
|
|
@@ -230,6 +246,8 @@ function styleFromComputedStyleMap(
|
|
|
230
246
|
|
|
231
247
|
if (defaultStyles[property] === value) continue
|
|
232
248
|
if (parentStyles[property] === value && isPropertyInherited(property)) continue
|
|
249
|
+
if (isPropertyCoveredByCurrentColor(style.get('color')?.toString() || '', property, value))
|
|
250
|
+
continue
|
|
233
251
|
|
|
234
252
|
styles[property] = value
|
|
235
253
|
}
|
|
@@ -249,6 +267,7 @@ function styleFromComputedStyle(
|
|
|
249
267
|
|
|
250
268
|
if (defaultStyles[property] === value) continue
|
|
251
269
|
if (parentStyles[property] === value && isPropertyInherited(property)) continue
|
|
270
|
+
if (isPropertyCoveredByCurrentColor(style.color, property, value)) continue
|
|
252
271
|
|
|
253
272
|
styles[property] = value
|
|
254
273
|
}
|
|
@@ -111,11 +111,43 @@ export function parseCssValueUrls(value: string) {
|
|
|
111
111
|
}))
|
|
112
112
|
}
|
|
113
113
|
|
|
114
|
+
const currentColorProperties = new Set([
|
|
115
|
+
'border-block-end-color',
|
|
116
|
+
'border-block-start-color',
|
|
117
|
+
'border-bottom-color',
|
|
118
|
+
'border-inline-end-color',
|
|
119
|
+
'border-inline-start-color',
|
|
120
|
+
'border-left-color',
|
|
121
|
+
'border-right-color',
|
|
122
|
+
'border-top-color',
|
|
123
|
+
'caret-color',
|
|
124
|
+
'column-rule-color',
|
|
125
|
+
'outline-color',
|
|
126
|
+
'text-decoration',
|
|
127
|
+
'text-decoration-color',
|
|
128
|
+
'text-emphasis-color',
|
|
129
|
+
])
|
|
130
|
+
|
|
131
|
+
export function isPropertyCoveredByCurrentColor(
|
|
132
|
+
currentColor: string,
|
|
133
|
+
property: string,
|
|
134
|
+
value: string
|
|
135
|
+
) {
|
|
136
|
+
if (currentColorProperties.has(property)) {
|
|
137
|
+
return (
|
|
138
|
+
value === 'currentColor' ||
|
|
139
|
+
value === currentColor ||
|
|
140
|
+
(property === 'text-decoration' && value === `none solid ${currentColor}`)
|
|
141
|
+
)
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
114
145
|
const inheritedProperties = new Set([
|
|
115
146
|
'border-collapse',
|
|
116
147
|
'border-spacing',
|
|
117
148
|
'caption-side',
|
|
118
|
-
'color',
|
|
149
|
+
// N.B. We shouldn't inherit 'color' because there's some UA styling, e.g. `mark` elements
|
|
150
|
+
// 'color',
|
|
119
151
|
'cursor',
|
|
120
152
|
'direction',
|
|
121
153
|
'empty-cells',
|
|
@@ -136,16 +168,18 @@ const inheritedProperties = new Set([
|
|
|
136
168
|
'orphans',
|
|
137
169
|
'overflow-wrap',
|
|
138
170
|
'quotes',
|
|
171
|
+
'stroke-linecap',
|
|
172
|
+
'stroke-linejoin',
|
|
139
173
|
'tab-size',
|
|
140
174
|
'text-align',
|
|
141
175
|
'text-align-last',
|
|
142
|
-
'text-decoration-color',
|
|
143
176
|
'text-indent',
|
|
144
177
|
'text-justify',
|
|
145
178
|
'text-shadow',
|
|
146
179
|
'text-transform',
|
|
147
180
|
'visibility',
|
|
148
181
|
'white-space',
|
|
182
|
+
'white-space-collapse',
|
|
149
183
|
'widows',
|
|
150
184
|
'word-break',
|
|
151
185
|
'word-spacing',
|
package/src/version.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// This file is automatically generated by internal/scripts/refresh-assets.ts.
|
|
2
2
|
// Do not edit manually. Or do, I'm a comment, not a cop.
|
|
3
3
|
|
|
4
|
-
export const version = '3.11.0-canary.
|
|
4
|
+
export const version = '3.11.0-canary.f0072703bfd4'
|
|
5
5
|
export const publishDates = {
|
|
6
6
|
major: '2024-09-13T14:36:29.063Z',
|
|
7
|
-
minor: '2025-03-
|
|
8
|
-
patch: '2025-03-
|
|
7
|
+
minor: '2025-03-19T13:05:59.554Z',
|
|
8
|
+
patch: '2025-03-19T13:05:59.554Z',
|
|
9
9
|
}
|