@tldraw/editor 3.8.0-canary.fa7c40c0a965 → 3.8.0-canary.fc0f484388e4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-cjs/index.d.ts +146 -47
- package/dist-cjs/index.js +10 -8
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultCanvas.js +1 -1
- package/dist-cjs/lib/components/default-components/DefaultCanvas.js.map +2 -2
- package/dist-cjs/lib/config/TLSessionStateSnapshot.js.map +2 -2
- package/dist-cjs/lib/config/createTLStore.js +3 -1
- package/dist-cjs/lib/config/createTLStore.js.map +2 -2
- package/dist-cjs/lib/editor/Editor.js +26 -15
- package/dist-cjs/lib/editor/Editor.js.map +2 -2
- package/dist-cjs/lib/editor/managers/SnapManager/BoundsSnaps.js.map +2 -2
- package/dist-cjs/lib/editor/managers/TextManager.js +1 -0
- package/dist-cjs/lib/editor/managers/TextManager.js.map +2 -2
- package/dist-cjs/lib/editor/shapes/ShapeUtil.js.map +2 -2
- package/dist-cjs/lib/editor/shapes/shared/resizeScaled.js +66 -0
- package/dist-cjs/lib/editor/shapes/shared/resizeScaled.js.map +7 -0
- package/dist-cjs/lib/editor/types/emit-types.js.map +1 -1
- package/dist-cjs/lib/editor/types/external-content.js.map +1 -1
- package/dist-cjs/lib/exports/StyleEmbedder.js.map +2 -2
- package/dist-cjs/lib/hooks/useLocalStore.js +1 -1
- package/dist-cjs/lib/hooks/useLocalStore.js.map +2 -2
- package/dist-cjs/lib/options.js +2 -1
- package/dist-cjs/lib/options.js.map +2 -2
- package/dist-cjs/version.js +3 -3
- package/dist-cjs/version.js.map +1 -1
- package/dist-esm/index.d.mts +146 -47
- package/dist-esm/index.mjs +3 -1
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultCanvas.mjs +1 -1
- package/dist-esm/lib/components/default-components/DefaultCanvas.mjs.map +2 -2
- package/dist-esm/lib/config/TLSessionStateSnapshot.mjs.map +2 -2
- package/dist-esm/lib/config/createTLStore.mjs +3 -1
- package/dist-esm/lib/config/createTLStore.mjs.map +2 -2
- package/dist-esm/lib/editor/Editor.mjs +26 -15
- package/dist-esm/lib/editor/Editor.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/SnapManager/BoundsSnaps.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/TextManager.mjs +1 -0
- package/dist-esm/lib/editor/managers/TextManager.mjs.map +2 -2
- package/dist-esm/lib/editor/shapes/ShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/editor/shapes/shared/resizeScaled.mjs +46 -0
- package/dist-esm/lib/editor/shapes/shared/resizeScaled.mjs.map +7 -0
- package/dist-esm/lib/exports/StyleEmbedder.mjs.map +2 -2
- package/dist-esm/lib/hooks/useLocalStore.mjs +1 -1
- package/dist-esm/lib/hooks/useLocalStore.mjs.map +2 -2
- package/dist-esm/lib/options.mjs +2 -1
- package/dist-esm/lib/options.mjs.map +2 -2
- package/dist-esm/version.mjs +3 -3
- package/dist-esm/version.mjs.map +1 -1
- package/editor.css +2 -1
- package/package.json +20 -20
- package/src/index.ts +15 -1
- package/src/lib/components/default-components/DefaultCanvas.tsx +1 -1
- package/src/lib/config/TLSessionStateSnapshot.ts +3 -1
- package/src/lib/config/createTLStore.ts +3 -1
- package/src/lib/editor/Editor.ts +64 -33
- package/src/lib/editor/managers/SnapManager/BoundsSnaps.ts +4 -4
- package/src/lib/editor/managers/TextManager.ts +1 -0
- package/src/lib/editor/shapes/ShapeUtil.ts +30 -1
- package/src/lib/editor/shapes/shared/resizeScaled.ts +61 -0
- package/src/lib/editor/types/emit-types.ts +1 -0
- package/src/lib/editor/types/external-content.ts +90 -50
- package/src/lib/exports/StyleEmbedder.ts +1 -1
- package/src/lib/hooks/useLocalStore.ts +1 -1
- package/src/lib/options.ts +6 -0
- package/src/version.ts +3 -3
|
@@ -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 of 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,SAAS,qBAAqB,mBAAmB,gCAAgC;AAIjF,MAAM,YAAY,CAAC;AAQZ,MAAM,cAAc;AAAA,EAC1B,YAA6B,MAAe;AAAf;AAAA,EAAgB;AAAA,EAC5B,SAAS,oBAAI,IAA+B;AAAA,EACpD,QAAQ,IAAI,aAAa;AAAA,EAElC,sBAAsB,aAAsB;AAE3C,SAAK,kBAAkB,aAAa;AAAA,MACnC,uBAAuB;AAAA,MACvB,iCAAiC;AAAA,IAClC,CAAC;AAED,UAAM,WAAW,MAAM,KAAK,oBAAoB,WAAW,CAAC;AAC5D,WAAO,SAAS,QAAQ;AACvB,YAAM,QAAQ,SAAS,IAAI;AAC3B,eAAS,KAAK,GAAG,oBAAoB,KAAK,CAAC;AAI3C,WAAK,kBAAkB,OAAO;AAAA,QAC7B,uBAAuB;AAAA,QACvB,iCAAiC;AAAA,MAClC,CAAC;AAAA,IACF;AAAA,EACD;AAAA,EAEQ,kBACP,SACA,EAAE,wBAAwB,MAAM,kCAAkC,KAAK,GACtE;AACD,UAAM,gBAAgB,wBACnB,2BAA2B,QAAQ,QAAQ,YAAY,CAAC,IACxD;AAEH,UAAM,eAAe,
|
|
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 of 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": "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",
|
|
6
6
|
"names": ["document"]
|
|
7
7
|
}
|
|
@@ -21,7 +21,7 @@ function useLocalStore(options) {
|
|
|
21
21
|
const assets = {
|
|
22
22
|
upload: async (asset, file) => {
|
|
23
23
|
await client.db.storeAsset(asset.id, file);
|
|
24
|
-
return asset.id;
|
|
24
|
+
return { src: asset.id };
|
|
25
25
|
},
|
|
26
26
|
resolve: async (asset) => {
|
|
27
27
|
if (!asset.props.src) return null;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/lib/hooks/useLocalStore.ts"],
|
|
4
|
-
"sourcesContent": ["import { TLAsset, TLAssetStore, TLStoreSnapshot } from '@tldraw/tlschema'\nimport { WeakCache } from '@tldraw/utils'\nimport { useEffect } from 'react'\nimport { TLEditorSnapshot } from '../config/TLEditorSnapshot'\nimport { TLStoreOptions, createTLStore } from '../config/createTLStore'\nimport { TLStoreWithStatus } from '../utils/sync/StoreWithStatus'\nimport { TLLocalSyncClient } from '../utils/sync/TLLocalSyncClient'\nimport { useShallowObjectIdentity } from './useIdentity'\nimport { useRefState } from './useRefState'\n\n/** @internal */\nexport function useLocalStore(\n\toptions: {\n\t\tpersistenceKey?: string\n\t\tsessionId?: string\n\t\tsnapshot?: TLEditorSnapshot | TLStoreSnapshot\n\t} & TLStoreOptions\n): TLStoreWithStatus {\n\tconst [state, setState] = useRefState<TLStoreWithStatus>({ status: 'loading' })\n\n\toptions = useShallowObjectIdentity(options)\n\n\tuseEffect(() => {\n\t\tconst { persistenceKey, sessionId, ...rest } = options\n\n\t\tif (!persistenceKey) {\n\t\t\tsetState({\n\t\t\t\tstatus: 'not-synced',\n\t\t\t\tstore: createTLStore(rest),\n\t\t\t})\n\t\t\treturn\n\t\t}\n\n\t\tsetState({ status: 'loading' })\n\n\t\tconst objectURLCache = new WeakCache<TLAsset, Promise<string | null>>()\n\t\tconst assets: TLAssetStore = {\n\t\t\tupload: async (asset, file) => {\n\t\t\t\tawait client.db.storeAsset(asset.id, file)\n\t\t\t\treturn asset.id\n\t\t\t},\n\t\t\tresolve: async (asset) => {\n\t\t\t\tif (!asset.props.src) return null\n\n\t\t\t\tif (asset.props.src.startsWith('asset:')) {\n\t\t\t\t\treturn await objectURLCache.get(asset, async () => {\n\t\t\t\t\t\tconst blob = await client.db.getAsset(asset.id)\n\t\t\t\t\t\tif (!blob) return null\n\t\t\t\t\t\treturn URL.createObjectURL(blob)\n\t\t\t\t\t})\n\t\t\t\t}\n\n\t\t\t\treturn asset.props.src\n\t\t\t},\n\t\t\t...rest.assets,\n\t\t}\n\n\t\tconst store = createTLStore({ ...rest, assets })\n\n\t\tlet isClosed = false\n\n\t\tconst client = new TLLocalSyncClient(store, {\n\t\t\tsessionId,\n\t\t\tpersistenceKey,\n\t\t\tonLoad() {\n\t\t\t\tif (isClosed) return\n\t\t\t\tsetState({ store, status: 'synced-local' })\n\t\t\t},\n\t\t\tonLoadError(err: any) {\n\t\t\t\tif (isClosed) return\n\t\t\t\tsetState({ status: 'error', error: err })\n\t\t\t},\n\t\t})\n\n\t\treturn () => {\n\t\t\tisClosed = true\n\t\t\tclient.close()\n\t\t}\n\t}, [options, setState])\n\n\treturn state\n}\n"],
|
|
5
|
-
"mappings": "AACA,SAAS,iBAAiB;AAC1B,SAAS,iBAAiB;AAE1B,SAAyB,qBAAqB;AAE9C,SAAS,yBAAyB;AAClC,SAAS,gCAAgC;AACzC,SAAS,mBAAmB;AAGrB,SAAS,cACf,SAKoB;AACpB,QAAM,CAAC,OAAO,QAAQ,IAAI,YAA+B,EAAE,QAAQ,UAAU,CAAC;AAE9E,YAAU,yBAAyB,OAAO;AAE1C,YAAU,MAAM;AACf,UAAM,EAAE,gBAAgB,WAAW,GAAG,KAAK,IAAI;AAE/C,QAAI,CAAC,gBAAgB;AACpB,eAAS;AAAA,QACR,QAAQ;AAAA,QACR,OAAO,cAAc,IAAI;AAAA,MAC1B,CAAC;AACD;AAAA,IACD;AAEA,aAAS,EAAE,QAAQ,UAAU,CAAC;AAE9B,UAAM,iBAAiB,IAAI,UAA2C;AACtE,UAAM,SAAuB;AAAA,MAC5B,QAAQ,OAAO,OAAO,SAAS;AAC9B,cAAM,OAAO,GAAG,WAAW,MAAM,IAAI,IAAI;AACzC,eAAO,MAAM;AAAA,
|
|
4
|
+
"sourcesContent": ["import { TLAsset, TLAssetStore, TLStoreSnapshot } from '@tldraw/tlschema'\nimport { WeakCache } from '@tldraw/utils'\nimport { useEffect } from 'react'\nimport { TLEditorSnapshot } from '../config/TLEditorSnapshot'\nimport { TLStoreOptions, createTLStore } from '../config/createTLStore'\nimport { TLStoreWithStatus } from '../utils/sync/StoreWithStatus'\nimport { TLLocalSyncClient } from '../utils/sync/TLLocalSyncClient'\nimport { useShallowObjectIdentity } from './useIdentity'\nimport { useRefState } from './useRefState'\n\n/** @internal */\nexport function useLocalStore(\n\toptions: {\n\t\tpersistenceKey?: string\n\t\tsessionId?: string\n\t\tsnapshot?: TLEditorSnapshot | TLStoreSnapshot\n\t} & TLStoreOptions\n): TLStoreWithStatus {\n\tconst [state, setState] = useRefState<TLStoreWithStatus>({ status: 'loading' })\n\n\toptions = useShallowObjectIdentity(options)\n\n\tuseEffect(() => {\n\t\tconst { persistenceKey, sessionId, ...rest } = options\n\n\t\tif (!persistenceKey) {\n\t\t\tsetState({\n\t\t\t\tstatus: 'not-synced',\n\t\t\t\tstore: createTLStore(rest),\n\t\t\t})\n\t\t\treturn\n\t\t}\n\n\t\tsetState({ status: 'loading' })\n\n\t\tconst objectURLCache = new WeakCache<TLAsset, Promise<string | null>>()\n\t\tconst assets: TLAssetStore = {\n\t\t\tupload: async (asset, file) => {\n\t\t\t\tawait client.db.storeAsset(asset.id, file)\n\t\t\t\treturn { src: asset.id }\n\t\t\t},\n\t\t\tresolve: async (asset) => {\n\t\t\t\tif (!asset.props.src) return null\n\n\t\t\t\tif (asset.props.src.startsWith('asset:')) {\n\t\t\t\t\treturn await objectURLCache.get(asset, async () => {\n\t\t\t\t\t\tconst blob = await client.db.getAsset(asset.id)\n\t\t\t\t\t\tif (!blob) return null\n\t\t\t\t\t\treturn URL.createObjectURL(blob)\n\t\t\t\t\t})\n\t\t\t\t}\n\n\t\t\t\treturn asset.props.src\n\t\t\t},\n\t\t\t...rest.assets,\n\t\t}\n\n\t\tconst store = createTLStore({ ...rest, assets })\n\n\t\tlet isClosed = false\n\n\t\tconst client = new TLLocalSyncClient(store, {\n\t\t\tsessionId,\n\t\t\tpersistenceKey,\n\t\t\tonLoad() {\n\t\t\t\tif (isClosed) return\n\t\t\t\tsetState({ store, status: 'synced-local' })\n\t\t\t},\n\t\t\tonLoadError(err: any) {\n\t\t\t\tif (isClosed) return\n\t\t\t\tsetState({ status: 'error', error: err })\n\t\t\t},\n\t\t})\n\n\t\treturn () => {\n\t\t\tisClosed = true\n\t\t\tclient.close()\n\t\t}\n\t}, [options, setState])\n\n\treturn state\n}\n"],
|
|
5
|
+
"mappings": "AACA,SAAS,iBAAiB;AAC1B,SAAS,iBAAiB;AAE1B,SAAyB,qBAAqB;AAE9C,SAAS,yBAAyB;AAClC,SAAS,gCAAgC;AACzC,SAAS,mBAAmB;AAGrB,SAAS,cACf,SAKoB;AACpB,QAAM,CAAC,OAAO,QAAQ,IAAI,YAA+B,EAAE,QAAQ,UAAU,CAAC;AAE9E,YAAU,yBAAyB,OAAO;AAE1C,YAAU,MAAM;AACf,UAAM,EAAE,gBAAgB,WAAW,GAAG,KAAK,IAAI;AAE/C,QAAI,CAAC,gBAAgB;AACpB,eAAS;AAAA,QACR,QAAQ;AAAA,QACR,OAAO,cAAc,IAAI;AAAA,MAC1B,CAAC;AACD;AAAA,IACD;AAEA,aAAS,EAAE,QAAQ,UAAU,CAAC;AAE9B,UAAM,iBAAiB,IAAI,UAA2C;AACtE,UAAM,SAAuB;AAAA,MAC5B,QAAQ,OAAO,OAAO,SAAS;AAC9B,cAAM,OAAO,GAAG,WAAW,MAAM,IAAI,IAAI;AACzC,eAAO,EAAE,KAAK,MAAM,GAAG;AAAA,MACxB;AAAA,MACA,SAAS,OAAO,UAAU;AACzB,YAAI,CAAC,MAAM,MAAM,IAAK,QAAO;AAE7B,YAAI,MAAM,MAAM,IAAI,WAAW,QAAQ,GAAG;AACzC,iBAAO,MAAM,eAAe,IAAI,OAAO,YAAY;AAClD,kBAAM,OAAO,MAAM,OAAO,GAAG,SAAS,MAAM,EAAE;AAC9C,gBAAI,CAAC,KAAM,QAAO;AAClB,mBAAO,IAAI,gBAAgB,IAAI;AAAA,UAChC,CAAC;AAAA,QACF;AAEA,eAAO,MAAM,MAAM;AAAA,MACpB;AAAA,MACA,GAAG,KAAK;AAAA,IACT;AAEA,UAAM,QAAQ,cAAc,EAAE,GAAG,MAAM,OAAO,CAAC;AAE/C,QAAI,WAAW;AAEf,UAAM,SAAS,IAAI,kBAAkB,OAAO;AAAA,MAC3C;AAAA,MACA;AAAA,MACA,SAAS;AACR,YAAI,SAAU;AACd,iBAAS,EAAE,OAAO,QAAQ,eAAe,CAAC;AAAA,MAC3C;AAAA,MACA,YAAY,KAAU;AACrB,YAAI,SAAU;AACd,iBAAS,EAAE,QAAQ,SAAS,OAAO,IAAI,CAAC;AAAA,MACzC;AAAA,IACD,CAAC;AAED,WAAO,MAAM;AACZ,iBAAW;AACX,aAAO,MAAM;AAAA,IACd;AAAA,EACD,GAAG,CAAC,SAAS,QAAQ,CAAC;AAEtB,SAAO;AACR;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist-esm/lib/options.mjs
CHANGED
|
@@ -42,7 +42,8 @@ const defaultTldrawOptions = {
|
|
|
42
42
|
temporaryAssetPreviewLifetimeMs: 18e4,
|
|
43
43
|
actionShortcutsLocation: "swap",
|
|
44
44
|
createTextOnCanvasDoubleClick: true,
|
|
45
|
-
exportProvider: Fragment
|
|
45
|
+
exportProvider: Fragment,
|
|
46
|
+
noteShapeResizeMode: "none"
|
|
46
47
|
};
|
|
47
48
|
export {
|
|
48
49
|
defaultTldrawOptions
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/lib/options.ts"],
|
|
4
|
-
"sourcesContent": ["import { ComponentType, Fragment } from 'react'\n\n/**\n * Options for configuring tldraw. For defaults, see {@link defaultTldrawOptions}.\n *\n * @example\n * ```tsx\n * const options: Partial<TldrawOptions> = {\n * maxPages: 3,\n * maxShapesPerPage: 1000,\n * }\n *\n * function MyTldrawComponent() {\n * return <Tldraw options={options} />\n * }\n * ```\n *\n * @public\n */\nexport interface TldrawOptions {\n\treadonly maxShapesPerPage: number\n\treadonly maxFilesAtOnce: number\n\treadonly maxPages: number\n\treadonly animationMediumMs: number\n\treadonly followChaseViewportSnap: number\n\treadonly doubleClickDurationMs: number\n\treadonly multiClickDurationMs: number\n\treadonly coarseDragDistanceSquared: number\n\treadonly dragDistanceSquared: number\n\treadonly defaultSvgPadding: number\n\treadonly cameraSlideFriction: number\n\treadonly maxPointsPerDrawShape: number\n\treadonly gridSteps: readonly {\n\t\treadonly min: number\n\t\treadonly mid: number\n\t\treadonly step: number\n\t}[]\n\treadonly collaboratorInactiveTimeoutMs: number\n\treadonly collaboratorIdleTimeoutMs: number\n\treadonly collaboratorCheckIntervalMs: number\n\treadonly cameraMovingTimeoutMs: number\n\treadonly hitTestMargin: number\n\treadonly edgeScrollDelay: number\n\treadonly edgeScrollEaseDuration: number\n\treadonly edgeScrollSpeed: number\n\treadonly edgeScrollDistance: number\n\treadonly coarsePointerWidth: number\n\treadonly coarseHandleRadius: number\n\treadonly handleRadius: number\n\treadonly longPressDurationMs: number\n\treadonly textShadowLod: number\n\treadonly adjacentShapeMargin: number\n\treadonly flattenImageBoundsExpand: number\n\treadonly flattenImageBoundsPadding: number\n\treadonly laserDelayMs: number\n\treadonly maxExportDelayMs: number\n\t/**\n\t * How long should previews created by {@link Editor.createTemporaryAssetPreview} last before\n\t * they expire? Defaults to 3 minutes.\n\t */\n\treadonly temporaryAssetPreviewLifetimeMs: number\n\treadonly actionShortcutsLocation: 'menu' | 'toolbar' | 'swap'\n\treadonly createTextOnCanvasDoubleClick: boolean\n\t/**\n\t * The react provider to use when exporting an image. This is useful if your shapes depend on\n\t * external context providers. By default, this is `React.Fragment`.\n\t */\n\treadonly exportProvider: ComponentType<{ children: React.ReactNode }>\n}\n\n/** @public */\nexport const defaultTldrawOptions = {\n\tmaxShapesPerPage: 4000,\n\tmaxFilesAtOnce: 100,\n\tmaxPages: 40,\n\tanimationMediumMs: 320,\n\tfollowChaseViewportSnap: 2,\n\tdoubleClickDurationMs: 450,\n\tmultiClickDurationMs: 200,\n\tcoarseDragDistanceSquared: 36, // 6 squared\n\tdragDistanceSquared: 16, // 4 squared\n\tdefaultSvgPadding: 32,\n\tcameraSlideFriction: 0.09,\n\tmaxPointsPerDrawShape: 500,\n\tgridSteps: [\n\t\t{ min: -1, mid: 0.15, step: 64 },\n\t\t{ min: 0.05, mid: 0.375, step: 16 },\n\t\t{ min: 0.15, mid: 1, step: 4 },\n\t\t{ min: 0.7, mid: 2.5, step: 1 },\n\t],\n\tcollaboratorInactiveTimeoutMs: 60000,\n\tcollaboratorIdleTimeoutMs: 3000,\n\tcollaboratorCheckIntervalMs: 1200,\n\tcameraMovingTimeoutMs: 64,\n\thitTestMargin: 8,\n\tedgeScrollDelay: 200,\n\tedgeScrollEaseDuration: 200,\n\tedgeScrollSpeed: 25,\n\tedgeScrollDistance: 8,\n\tcoarsePointerWidth: 12,\n\tcoarseHandleRadius: 20,\n\thandleRadius: 12,\n\tlongPressDurationMs: 500,\n\ttextShadowLod: 0.35,\n\tadjacentShapeMargin: 10,\n\tflattenImageBoundsExpand: 64,\n\tflattenImageBoundsPadding: 16,\n\tlaserDelayMs: 1200,\n\tmaxExportDelayMs: 5000,\n\ttemporaryAssetPreviewLifetimeMs: 180000,\n\tactionShortcutsLocation: 'swap',\n\tcreateTextOnCanvasDoubleClick: true,\n\texportProvider: Fragment,\n} as const satisfies TldrawOptions\n"],
|
|
5
|
-
"mappings": "AAAA,SAAwB,gBAAgB;
|
|
4
|
+
"sourcesContent": ["import { ComponentType, Fragment } from 'react'\n\n/**\n * Options for configuring tldraw. For defaults, see {@link defaultTldrawOptions}.\n *\n * @example\n * ```tsx\n * const options: Partial<TldrawOptions> = {\n * maxPages: 3,\n * maxShapesPerPage: 1000,\n * }\n *\n * function MyTldrawComponent() {\n * return <Tldraw options={options} />\n * }\n * ```\n *\n * @public\n */\nexport interface TldrawOptions {\n\treadonly maxShapesPerPage: number\n\treadonly maxFilesAtOnce: number\n\treadonly maxPages: number\n\treadonly animationMediumMs: number\n\treadonly followChaseViewportSnap: number\n\treadonly doubleClickDurationMs: number\n\treadonly multiClickDurationMs: number\n\treadonly coarseDragDistanceSquared: number\n\treadonly dragDistanceSquared: number\n\treadonly defaultSvgPadding: number\n\treadonly cameraSlideFriction: number\n\treadonly maxPointsPerDrawShape: number\n\treadonly gridSteps: readonly {\n\t\treadonly min: number\n\t\treadonly mid: number\n\t\treadonly step: number\n\t}[]\n\treadonly collaboratorInactiveTimeoutMs: number\n\treadonly collaboratorIdleTimeoutMs: number\n\treadonly collaboratorCheckIntervalMs: number\n\treadonly cameraMovingTimeoutMs: number\n\treadonly hitTestMargin: number\n\treadonly edgeScrollDelay: number\n\treadonly edgeScrollEaseDuration: number\n\treadonly edgeScrollSpeed: number\n\treadonly edgeScrollDistance: number\n\treadonly coarsePointerWidth: number\n\treadonly coarseHandleRadius: number\n\treadonly handleRadius: number\n\treadonly longPressDurationMs: number\n\treadonly textShadowLod: number\n\treadonly adjacentShapeMargin: number\n\treadonly flattenImageBoundsExpand: number\n\treadonly flattenImageBoundsPadding: number\n\treadonly laserDelayMs: number\n\treadonly maxExportDelayMs: number\n\t/**\n\t * How long should previews created by {@link Editor.createTemporaryAssetPreview} last before\n\t * they expire? Defaults to 3 minutes.\n\t */\n\treadonly temporaryAssetPreviewLifetimeMs: number\n\treadonly actionShortcutsLocation: 'menu' | 'toolbar' | 'swap'\n\treadonly createTextOnCanvasDoubleClick: boolean\n\t/**\n\t * The react provider to use when exporting an image. This is useful if your shapes depend on\n\t * external context providers. By default, this is `React.Fragment`.\n\t */\n\treadonly exportProvider: ComponentType<{ children: React.ReactNode }>\n\t/**\n\t * How should the note shape resize? By default it does not resize (except automatically based on its text content),\n\t * but you can set it to be user-resizable using scale.\n\t */\n\treadonly noteShapeResizeMode: 'none' | 'scale'\n}\n\n/** @public */\nexport const defaultTldrawOptions = {\n\tmaxShapesPerPage: 4000,\n\tmaxFilesAtOnce: 100,\n\tmaxPages: 40,\n\tanimationMediumMs: 320,\n\tfollowChaseViewportSnap: 2,\n\tdoubleClickDurationMs: 450,\n\tmultiClickDurationMs: 200,\n\tcoarseDragDistanceSquared: 36, // 6 squared\n\tdragDistanceSquared: 16, // 4 squared\n\tdefaultSvgPadding: 32,\n\tcameraSlideFriction: 0.09,\n\tmaxPointsPerDrawShape: 500,\n\tgridSteps: [\n\t\t{ min: -1, mid: 0.15, step: 64 },\n\t\t{ min: 0.05, mid: 0.375, step: 16 },\n\t\t{ min: 0.15, mid: 1, step: 4 },\n\t\t{ min: 0.7, mid: 2.5, step: 1 },\n\t],\n\tcollaboratorInactiveTimeoutMs: 60000,\n\tcollaboratorIdleTimeoutMs: 3000,\n\tcollaboratorCheckIntervalMs: 1200,\n\tcameraMovingTimeoutMs: 64,\n\thitTestMargin: 8,\n\tedgeScrollDelay: 200,\n\tedgeScrollEaseDuration: 200,\n\tedgeScrollSpeed: 25,\n\tedgeScrollDistance: 8,\n\tcoarsePointerWidth: 12,\n\tcoarseHandleRadius: 20,\n\thandleRadius: 12,\n\tlongPressDurationMs: 500,\n\ttextShadowLod: 0.35,\n\tadjacentShapeMargin: 10,\n\tflattenImageBoundsExpand: 64,\n\tflattenImageBoundsPadding: 16,\n\tlaserDelayMs: 1200,\n\tmaxExportDelayMs: 5000,\n\ttemporaryAssetPreviewLifetimeMs: 180000,\n\tactionShortcutsLocation: 'swap',\n\tcreateTextOnCanvasDoubleClick: true,\n\texportProvider: Fragment,\n\tnoteShapeResizeMode: 'none',\n} as const satisfies TldrawOptions\n"],
|
|
5
|
+
"mappings": "AAAA,SAAwB,gBAAgB;AA4EjC,MAAM,uBAAuB;AAAA,EACnC,kBAAkB;AAAA,EAClB,gBAAgB;AAAA,EAChB,UAAU;AAAA,EACV,mBAAmB;AAAA,EACnB,yBAAyB;AAAA,EACzB,uBAAuB;AAAA,EACvB,sBAAsB;AAAA,EACtB,2BAA2B;AAAA;AAAA,EAC3B,qBAAqB;AAAA;AAAA,EACrB,mBAAmB;AAAA,EACnB,qBAAqB;AAAA,EACrB,uBAAuB;AAAA,EACvB,WAAW;AAAA,IACV,EAAE,KAAK,IAAI,KAAK,MAAM,MAAM,GAAG;AAAA,IAC/B,EAAE,KAAK,MAAM,KAAK,OAAO,MAAM,GAAG;AAAA,IAClC,EAAE,KAAK,MAAM,KAAK,GAAG,MAAM,EAAE;AAAA,IAC7B,EAAE,KAAK,KAAK,KAAK,KAAK,MAAM,EAAE;AAAA,EAC/B;AAAA,EACA,+BAA+B;AAAA,EAC/B,2BAA2B;AAAA,EAC3B,6BAA6B;AAAA,EAC7B,uBAAuB;AAAA,EACvB,eAAe;AAAA,EACf,iBAAiB;AAAA,EACjB,wBAAwB;AAAA,EACxB,iBAAiB;AAAA,EACjB,oBAAoB;AAAA,EACpB,oBAAoB;AAAA,EACpB,oBAAoB;AAAA,EACpB,cAAc;AAAA,EACd,qBAAqB;AAAA,EACrB,eAAe;AAAA,EACf,qBAAqB;AAAA,EACrB,0BAA0B;AAAA,EAC1B,2BAA2B;AAAA,EAC3B,cAAc;AAAA,EACd,kBAAkB;AAAA,EAClB,iCAAiC;AAAA,EACjC,yBAAyB;AAAA,EACzB,+BAA+B;AAAA,EAC/B,gBAAgB;AAAA,EAChB,qBAAqB;AACtB;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist-esm/version.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
const version = "3.8.0-canary.
|
|
1
|
+
const version = "3.8.0-canary.fc0f484388e4";
|
|
2
2
|
const publishDates = {
|
|
3
3
|
major: "2024-09-13T14:36:29.063Z",
|
|
4
|
-
minor: "2025-01-
|
|
5
|
-
patch: "2025-01-
|
|
4
|
+
minor: "2025-01-30T15:44:39.992Z",
|
|
5
|
+
patch: "2025-01-30T15:44:39.992Z"
|
|
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.8.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.8.0-canary.fc0f484388e4'\nexport const publishDates = {\n\tmajor: '2024-09-13T14:36:29.063Z',\n\tminor: '2025-01-30T15:44:39.992Z',\n\tpatch: '2025-01-30T15:44:39.992Z',\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/editor.css
CHANGED
|
@@ -39,9 +39,10 @@
|
|
|
39
39
|
--layer-overlays-user-brush: 50;
|
|
40
40
|
--layer-overlays-user-indicator-selected: 60;
|
|
41
41
|
--layer-overlays-user-indicator-hovered: 70;
|
|
42
|
-
--layer-overlays-user-handles: 80;
|
|
43
42
|
--layer-overlays-user-snapline: 90;
|
|
44
43
|
--layer-overlays-selection-fg: 100;
|
|
44
|
+
/* User handles need to be above selection edges / corners, matters for sticky note clone handles */
|
|
45
|
+
--layer-overlays-user-handles: 105;
|
|
45
46
|
--layer-overlays-user-indicator-hint: 110;
|
|
46
47
|
--layer-overlays-collaborator-cursor-hint: 120;
|
|
47
48
|
--layer-overlays-collaborator-cursor: 130;
|
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.8.0-canary.
|
|
4
|
+
"version": "3.8.0-canary.fc0f484388e4",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "tldraw Inc.",
|
|
7
7
|
"email": "hello@tldraw.com"
|
|
@@ -45,37 +45,37 @@
|
|
|
45
45
|
"lint": "yarn run -T tsx ../../internal/scripts/lint.ts"
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"@tldraw/state": "3.8.0-canary.
|
|
49
|
-
"@tldraw/state-react": "3.8.0-canary.
|
|
50
|
-
"@tldraw/store": "3.8.0-canary.
|
|
51
|
-
"@tldraw/tlschema": "3.8.0-canary.
|
|
52
|
-
"@tldraw/utils": "3.8.0-canary.
|
|
53
|
-
"@tldraw/validate": "3.8.0-canary.
|
|
54
|
-
"@types/core-js": "^2.5.
|
|
55
|
-
"@use-gesture/react": "^10.
|
|
48
|
+
"@tldraw/state": "3.8.0-canary.fc0f484388e4",
|
|
49
|
+
"@tldraw/state-react": "3.8.0-canary.fc0f484388e4",
|
|
50
|
+
"@tldraw/store": "3.8.0-canary.fc0f484388e4",
|
|
51
|
+
"@tldraw/tlschema": "3.8.0-canary.fc0f484388e4",
|
|
52
|
+
"@tldraw/utils": "3.8.0-canary.fc0f484388e4",
|
|
53
|
+
"@tldraw/validate": "3.8.0-canary.fc0f484388e4",
|
|
54
|
+
"@types/core-js": "^2.5.8",
|
|
55
|
+
"@use-gesture/react": "^10.3.1",
|
|
56
56
|
"canvas-size": "~2.0.0",
|
|
57
|
-
"classnames": "^2.
|
|
58
|
-
"core-js": "^3.
|
|
57
|
+
"classnames": "^2.5.1",
|
|
58
|
+
"core-js": "^3.40.0",
|
|
59
59
|
"eventemitter3": "^4.0.7",
|
|
60
60
|
"idb": "^7.1.1",
|
|
61
61
|
"is-plain-object": "^5.0.0",
|
|
62
62
|
"lodash.isequal": "^4.5.0"
|
|
63
63
|
},
|
|
64
64
|
"peerDependencies": {
|
|
65
|
-
"react": "^18.2.0",
|
|
66
|
-
"react-dom": "^18.2.0"
|
|
65
|
+
"react": "^18.2.0 || ^19.0.0",
|
|
66
|
+
"react-dom": "^18.2.0 || ^19.0.0"
|
|
67
67
|
},
|
|
68
68
|
"devDependencies": {
|
|
69
|
-
"@peculiar/webcrypto": "^1.
|
|
70
|
-
"@testing-library/jest-dom": "^5.
|
|
71
|
-
"@testing-library/react": "^15.0.
|
|
72
|
-
"@types/benchmark": "^2.1.
|
|
69
|
+
"@peculiar/webcrypto": "^1.5.0",
|
|
70
|
+
"@testing-library/jest-dom": "^5.17.0",
|
|
71
|
+
"@testing-library/react": "^15.0.7",
|
|
72
|
+
"@types/benchmark": "^2.1.5",
|
|
73
73
|
"@types/canvas-size": "^1.2.2",
|
|
74
|
-
"@types/wicg-file-system-access": "^2020.9.
|
|
74
|
+
"@types/wicg-file-system-access": "^2020.9.8",
|
|
75
75
|
"benchmark": "^2.1.4",
|
|
76
|
-
"fake-indexeddb": "^4.0.
|
|
76
|
+
"fake-indexeddb": "^4.0.2",
|
|
77
77
|
"jest-canvas-mock": "^2.5.2",
|
|
78
|
-
"jest-environment-jsdom": "^29.
|
|
78
|
+
"jest-environment-jsdom": "^29.7.0",
|
|
79
79
|
"lazyrepo": "0.0.0-alpha.27",
|
|
80
80
|
"resize-observer-polyfill": "^1.5.1"
|
|
81
81
|
},
|
package/src/index.ts
CHANGED
|
@@ -25,6 +25,7 @@ export {
|
|
|
25
25
|
useStateTracking,
|
|
26
26
|
useValue,
|
|
27
27
|
} from '@tldraw/state-react'
|
|
28
|
+
export { resizeScaled } from './lib/editor/shapes/shared/resizeScaled'
|
|
28
29
|
export { LocalIndexedDb, Table, type StoreName } from './lib/utils/sync/LocalIndexedDb'
|
|
29
30
|
// eslint-disable-next-line local/no-export-star
|
|
30
31
|
export * from '@tldraw/store'
|
|
@@ -182,6 +183,7 @@ export { UserPreferencesManager } from './lib/editor/managers/UserPreferencesMan
|
|
|
182
183
|
export { BaseBoxShapeUtil, type TLBaseBoxShape } from './lib/editor/shapes/BaseBoxShapeUtil'
|
|
183
184
|
export {
|
|
184
185
|
ShapeUtil,
|
|
186
|
+
type TLCropInfo,
|
|
185
187
|
type TLHandleDragInfo,
|
|
186
188
|
type TLResizeInfo,
|
|
187
189
|
type TLResizeMode,
|
|
@@ -238,9 +240,21 @@ export {
|
|
|
238
240
|
type UiEventType,
|
|
239
241
|
} from './lib/editor/types/event-types'
|
|
240
242
|
export {
|
|
241
|
-
type
|
|
243
|
+
type TLBaseExternalContent,
|
|
244
|
+
type TLEmbedExternalContent,
|
|
245
|
+
type TLErrorExternalContentSource,
|
|
246
|
+
type TLExcalidrawExternalContentSource,
|
|
247
|
+
type TLExternalAsset,
|
|
242
248
|
type TLExternalContent,
|
|
243
249
|
type TLExternalContentSource,
|
|
250
|
+
type TLFileExternalAsset,
|
|
251
|
+
type TLFilesExternalContent,
|
|
252
|
+
type TLSvgTextExternalContent,
|
|
253
|
+
type TLTextExternalContent,
|
|
254
|
+
type TLTextExternalContentSource,
|
|
255
|
+
type TLTldrawExternalContentSource,
|
|
256
|
+
type TLUrlExternalAsset,
|
|
257
|
+
type TLUrlExternalContent,
|
|
244
258
|
} from './lib/editor/types/external-content'
|
|
245
259
|
export {
|
|
246
260
|
type TLHistoryBatchOptions,
|
|
@@ -160,7 +160,6 @@ export function DefaultCanvas({ className }: TLCanvasComponentProps) {
|
|
|
160
160
|
<div className="tl-overlays">
|
|
161
161
|
<div ref={rHtmlLayer2} className="tl-html-layer">
|
|
162
162
|
{debugGeometry ? <GeometryDebuggingView /> : null}
|
|
163
|
-
<HandlesWrapper />
|
|
164
163
|
<BrushWrapper />
|
|
165
164
|
<ScribbleWrapper />
|
|
166
165
|
<ZoomBrushWrapper />
|
|
@@ -168,6 +167,7 @@ export function DefaultCanvas({ className }: TLCanvasComponentProps) {
|
|
|
168
167
|
<HintedShapeIndicator />
|
|
169
168
|
<SnapIndicatorWrapper />
|
|
170
169
|
<SelectionForegroundWrapper />
|
|
170
|
+
<HandlesWrapper />
|
|
171
171
|
<LiveCollaborators />
|
|
172
172
|
</div>
|
|
173
173
|
</div>
|
|
@@ -50,7 +50,9 @@ function iOS() {
|
|
|
50
50
|
* @public
|
|
51
51
|
*/
|
|
52
52
|
export const TAB_ID: string = window
|
|
53
|
-
? window[tabIdKey] ??
|
|
53
|
+
? (window[tabIdKey] ??
|
|
54
|
+
getFromSessionStorage(tabIdKey) ??
|
|
55
|
+
`TLDRAW_INSTANCE_STATE_V1_` + uniqueId())
|
|
54
56
|
: '<error>'
|
|
55
57
|
if (window) {
|
|
56
58
|
window[tabIdKey] = TAB_ID
|
|
@@ -61,7 +61,9 @@ const defaultAssetResolve: NonNullable<TLAssetStore['resolve']> = (asset) => ass
|
|
|
61
61
|
|
|
62
62
|
/** @public */
|
|
63
63
|
export const inlineBase64AssetStore: TLAssetStore = {
|
|
64
|
-
upload: (_, file) =>
|
|
64
|
+
upload: async (_, file) => {
|
|
65
|
+
return { src: await FileHelpers.blobToDataUrl(file) }
|
|
66
|
+
},
|
|
65
67
|
}
|
|
66
68
|
|
|
67
69
|
/**
|
package/src/lib/editor/Editor.ts
CHANGED
|
@@ -155,7 +155,7 @@ import {
|
|
|
155
155
|
TLPointerEventInfo,
|
|
156
156
|
TLWheelEventInfo,
|
|
157
157
|
} from './types/event-types'
|
|
158
|
-
import {
|
|
158
|
+
import { TLExternalAsset, TLExternalContent } from './types/external-content'
|
|
159
159
|
import { TLHistoryBatchOptions } from './types/history-types'
|
|
160
160
|
import {
|
|
161
161
|
OptionalKeys,
|
|
@@ -929,6 +929,21 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
929
929
|
return shapeUtil
|
|
930
930
|
}
|
|
931
931
|
|
|
932
|
+
/**
|
|
933
|
+
* Returns true if the editor has a shape util for the given shape / shape type.
|
|
934
|
+
*
|
|
935
|
+
* @param shape - A shape, shape partial, or shape type.
|
|
936
|
+
*/
|
|
937
|
+
hasShapeUtil<S extends TLUnknownShape>(shape: S | TLShapePartial<S>): boolean
|
|
938
|
+
hasShapeUtil<S extends TLUnknownShape>(type: S['type']): boolean
|
|
939
|
+
hasShapeUtil<T extends ShapeUtil>(
|
|
940
|
+
type: T extends ShapeUtil<infer R> ? R['type'] : string
|
|
941
|
+
): boolean
|
|
942
|
+
hasShapeUtil(arg: string | { type: string }): boolean {
|
|
943
|
+
const type = typeof arg === 'string' ? arg : arg.type
|
|
944
|
+
return hasOwnProperty(this.shapeUtils, type)
|
|
945
|
+
}
|
|
946
|
+
|
|
932
947
|
/* ------------------- Binding Utils ------------------ */
|
|
933
948
|
/**
|
|
934
949
|
* A map of shape utility classes (TLShapeUtils) by shape type.
|
|
@@ -1460,10 +1475,10 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
1460
1475
|
if (partial.isChangingStyle !== undefined) {
|
|
1461
1476
|
clearTimeout(this._isChangingStyleTimeout)
|
|
1462
1477
|
if (partial.isChangingStyle === true) {
|
|
1463
|
-
// If we've set to true, set a new reset timeout to change the value back to false after
|
|
1478
|
+
// If we've set to true, set a new reset timeout to change the value back to false after 1 seconds
|
|
1464
1479
|
this._isChangingStyleTimeout = this.timers.setTimeout(() => {
|
|
1465
1480
|
this._updateInstanceState({ isChangingStyle: false }, { history: 'ignore' })
|
|
1466
|
-
},
|
|
1481
|
+
}, 1000)
|
|
1467
1482
|
}
|
|
1468
1483
|
}
|
|
1469
1484
|
|
|
@@ -1666,7 +1681,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
1666
1681
|
* @public
|
|
1667
1682
|
*/
|
|
1668
1683
|
isAncestorSelected(shape: TLShape | TLShapeId): boolean {
|
|
1669
|
-
const id = typeof shape === 'string' ? shape : shape?.id ?? null
|
|
1684
|
+
const id = typeof shape === 'string' ? shape : (shape?.id ?? null)
|
|
1670
1685
|
const _shape = this.getShape(id)
|
|
1671
1686
|
if (!_shape) return false
|
|
1672
1687
|
const selectedShapeIds = this.getSelectedShapeIds()
|
|
@@ -1923,7 +1938,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
1923
1938
|
* @public
|
|
1924
1939
|
*/
|
|
1925
1940
|
setFocusedGroup(shape: TLShapeId | TLGroupShape | null): this {
|
|
1926
|
-
const id = typeof shape === 'string' ? shape : shape?.id ?? null
|
|
1941
|
+
const id = typeof shape === 'string' ? shape : (shape?.id ?? null)
|
|
1927
1942
|
|
|
1928
1943
|
if (id !== null) {
|
|
1929
1944
|
const shape = this.getShape(id)
|
|
@@ -2006,7 +2021,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
2006
2021
|
* @public
|
|
2007
2022
|
*/
|
|
2008
2023
|
setEditingShape(shape: TLShapeId | TLShape | null): this {
|
|
2009
|
-
const id = typeof shape === 'string' ? shape : shape?.id ?? null
|
|
2024
|
+
const id = typeof shape === 'string' ? shape : (shape?.id ?? null)
|
|
2010
2025
|
if (id !== this.getEditingShapeId()) {
|
|
2011
2026
|
if (id) {
|
|
2012
2027
|
const shape = this.getShape(id)
|
|
@@ -2067,7 +2082,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
2067
2082
|
* @public
|
|
2068
2083
|
*/
|
|
2069
2084
|
setHoveredShape(shape: TLShapeId | TLShape | null): this {
|
|
2070
|
-
const id = typeof shape === 'string' ? shape : shape?.id ?? null
|
|
2085
|
+
const id = typeof shape === 'string' ? shape : (shape?.id ?? null)
|
|
2071
2086
|
if (id === this.getHoveredShapeId()) return this
|
|
2072
2087
|
this.run(
|
|
2073
2088
|
() => {
|
|
@@ -2216,7 +2231,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
2216
2231
|
* @public
|
|
2217
2232
|
*/
|
|
2218
2233
|
setCroppingShape(shape: TLShapeId | TLShape | null): this {
|
|
2219
|
-
const id = typeof shape === 'string' ? shape : shape?.id ?? null
|
|
2234
|
+
const id = typeof shape === 'string' ? shape : (shape?.id ?? null)
|
|
2220
2235
|
if (id !== this.getCroppingShapeId()) {
|
|
2221
2236
|
this.run(
|
|
2222
2237
|
() => {
|
|
@@ -4178,7 +4193,11 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
4178
4193
|
* Upload an asset to the store's asset service, returning a URL that can be used to resolve the
|
|
4179
4194
|
* asset.
|
|
4180
4195
|
*/
|
|
4181
|
-
async uploadAsset(
|
|
4196
|
+
async uploadAsset(
|
|
4197
|
+
asset: TLAsset,
|
|
4198
|
+
file: File,
|
|
4199
|
+
abortSignal?: AbortSignal
|
|
4200
|
+
): Promise<{ src: string; meta?: JsonObject }> {
|
|
4182
4201
|
return await this.store.props.assets.upload(asset, file, abortSignal)
|
|
4183
4202
|
}
|
|
4184
4203
|
|
|
@@ -6756,6 +6775,8 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
6756
6775
|
}
|
|
6757
6776
|
}
|
|
6758
6777
|
|
|
6778
|
+
let didResize = false
|
|
6779
|
+
|
|
6759
6780
|
if (util.onResize && util.canResize(initialShape)) {
|
|
6760
6781
|
// get the model changes from the shape util
|
|
6761
6782
|
const newPagePoint = this._scalePagePoint(
|
|
@@ -6794,24 +6815,30 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
6794
6815
|
)
|
|
6795
6816
|
}
|
|
6796
6817
|
|
|
6818
|
+
const resizedShape = util.onResize(
|
|
6819
|
+
{ ...initialShape, x, y },
|
|
6820
|
+
{
|
|
6821
|
+
newPoint: newLocalPoint,
|
|
6822
|
+
handle: opts.dragHandle ?? 'bottom_right',
|
|
6823
|
+
// don't set isSingle to true for children
|
|
6824
|
+
mode: opts.mode ?? 'scale_shape',
|
|
6825
|
+
scaleX: myScale.x,
|
|
6826
|
+
scaleY: myScale.y,
|
|
6827
|
+
initialBounds,
|
|
6828
|
+
initialShape,
|
|
6829
|
+
}
|
|
6830
|
+
)
|
|
6831
|
+
|
|
6832
|
+
if (resizedShape) {
|
|
6833
|
+
didResize = true
|
|
6834
|
+
}
|
|
6835
|
+
|
|
6797
6836
|
workingShape = applyPartialToRecordWithProps(workingShape, {
|
|
6798
6837
|
id,
|
|
6799
6838
|
type: initialShape.type as any,
|
|
6800
6839
|
x: newLocalPoint.x,
|
|
6801
6840
|
y: newLocalPoint.y,
|
|
6802
|
-
...
|
|
6803
|
-
{ ...initialShape, x, y },
|
|
6804
|
-
{
|
|
6805
|
-
newPoint: newLocalPoint,
|
|
6806
|
-
handle: opts.dragHandle ?? 'bottom_right',
|
|
6807
|
-
// don't set isSingle to true for children
|
|
6808
|
-
mode: opts.mode ?? 'scale_shape',
|
|
6809
|
-
scaleX: myScale.x,
|
|
6810
|
-
scaleY: myScale.y,
|
|
6811
|
-
initialBounds,
|
|
6812
|
-
initialShape,
|
|
6813
|
-
}
|
|
6814
|
-
),
|
|
6841
|
+
...resizedShape,
|
|
6815
6842
|
})
|
|
6816
6843
|
|
|
6817
6844
|
if (!opts.skipStartAndEndCallbacks) {
|
|
@@ -6822,7 +6849,11 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
6822
6849
|
}
|
|
6823
6850
|
|
|
6824
6851
|
this.updateShapes([workingShape])
|
|
6825
|
-
}
|
|
6852
|
+
}
|
|
6853
|
+
|
|
6854
|
+
if (!didResize) {
|
|
6855
|
+
// reposition shape (rather than resizing it) based on where its resized center would be
|
|
6856
|
+
|
|
6826
6857
|
const initialPageCenter = Mat.applyToPoint(pageTransform, initialBounds.center)
|
|
6827
6858
|
// get the model changes from the shape util
|
|
6828
6859
|
const newPageCenter = this._scalePagePoint(
|
|
@@ -7944,10 +7975,8 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
7944
7975
|
|
|
7945
7976
|
/** @internal */
|
|
7946
7977
|
externalAssetContentHandlers: {
|
|
7947
|
-
[K in
|
|
7948
|
-
[Key in K]:
|
|
7949
|
-
| null
|
|
7950
|
-
| ((info: TLExternalAssetContent & { type: Key }) => Promise<TLAsset | undefined>)
|
|
7978
|
+
[K in TLExternalAsset['type']]: {
|
|
7979
|
+
[Key in K]: null | ((info: TLExternalAsset & { type: Key }) => Promise<TLAsset | undefined>)
|
|
7951
7980
|
}[K]
|
|
7952
7981
|
} = {
|
|
7953
7982
|
file: null,
|
|
@@ -7976,9 +8005,9 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
7976
8005
|
*
|
|
7977
8006
|
* @public
|
|
7978
8007
|
*/
|
|
7979
|
-
registerExternalAssetHandler<T extends
|
|
8008
|
+
registerExternalAssetHandler<T extends TLExternalAsset['type']>(
|
|
7980
8009
|
type: T,
|
|
7981
|
-
handler: null | ((info:
|
|
8010
|
+
handler: null | ((info: TLExternalAsset & { type: T }) => Promise<TLAsset>)
|
|
7982
8011
|
): this {
|
|
7983
8012
|
this.externalAssetContentHandlers[type] = handler as any
|
|
7984
8013
|
return this
|
|
@@ -8046,11 +8075,11 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
8046
8075
|
* @param info - Info about the external content.
|
|
8047
8076
|
* @returns The asset.
|
|
8048
8077
|
*/
|
|
8049
|
-
async getAssetForExternalContent(info:
|
|
8078
|
+
async getAssetForExternalContent(info: TLExternalAsset): Promise<TLAsset | undefined> {
|
|
8050
8079
|
return await this.externalAssetContentHandlers[info.type]?.(info as any)
|
|
8051
8080
|
}
|
|
8052
8081
|
|
|
8053
|
-
hasExternalAssetHandler(type:
|
|
8082
|
+
hasExternalAssetHandler(type: TLExternalAsset['type']): boolean {
|
|
8054
8083
|
return !!this.externalAssetContentHandlers[type]
|
|
8055
8084
|
}
|
|
8056
8085
|
|
|
@@ -8772,8 +8801,8 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
8772
8801
|
// If our pointer moved only because we're following some other user, then don't
|
|
8773
8802
|
// update our last activity timestamp; otherwise, update it to the current timestamp.
|
|
8774
8803
|
info.type === 'pointer' && info.pointerId === INTERNAL_POINTER_IDS.CAMERA_MOVE
|
|
8775
|
-
? this.store.unsafeGetWithoutCapture(TLPOINTER_ID)?.lastActivityTimestamp ??
|
|
8776
|
-
this._tickManager.now
|
|
8804
|
+
? (this.store.unsafeGetWithoutCapture(TLPOINTER_ID)?.lastActivityTimestamp ??
|
|
8805
|
+
this._tickManager.now)
|
|
8777
8806
|
: this._tickManager.now,
|
|
8778
8807
|
meta: {},
|
|
8779
8808
|
},
|
|
@@ -9338,6 +9367,8 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
9338
9367
|
// todo: replace with new readonly mode?
|
|
9339
9368
|
if (this.getCrashingError()) return this
|
|
9340
9369
|
|
|
9370
|
+
this.emit('before-event', info)
|
|
9371
|
+
|
|
9341
9372
|
const { inputs } = this
|
|
9342
9373
|
const { type } = info
|
|
9343
9374
|
|
|
@@ -390,8 +390,8 @@ export class BoundsSnaps {
|
|
|
390
390
|
|
|
391
391
|
// at the same time, calculate how far we need to nudge the shape to 'snap' to the target point(s)
|
|
392
392
|
const nudge = new Vec(
|
|
393
|
-
lockedAxis === 'x' ? 0 : nearestSnapsX[0]?.nudge ?? 0,
|
|
394
|
-
lockedAxis === 'y' ? 0 : nearestSnapsY[0]?.nudge ?? 0
|
|
393
|
+
lockedAxis === 'x' ? 0 : (nearestSnapsX[0]?.nudge ?? 0),
|
|
394
|
+
lockedAxis === 'y' ? 0 : (nearestSnapsY[0]?.nudge ?? 0)
|
|
395
395
|
)
|
|
396
396
|
|
|
397
397
|
// ok we've figured out how much the box should be nudged, now let's find all the snap points
|
|
@@ -504,8 +504,8 @@ export class BoundsSnaps {
|
|
|
504
504
|
|
|
505
505
|
// at the same time, calculate how far we need to nudge the shape to 'snap' to the target point(s)
|
|
506
506
|
const nudge = new Vec(
|
|
507
|
-
isXLocked ? 0 : nearestSnapsX[0]?.nudge ?? 0,
|
|
508
|
-
isYLocked ? 0 : nearestSnapsY[0]?.nudge ?? 0
|
|
507
|
+
isXLocked ? 0 : (nearestSnapsX[0]?.nudge ?? 0),
|
|
508
|
+
isYLocked ? 0 : (nearestSnapsY[0]?.nudge ?? 0)
|
|
509
509
|
)
|
|
510
510
|
|
|
511
511
|
if (isAspectRatioLocked && isSelectionCorner(handle) && nudge.len() !== 0) {
|
|
@@ -230,6 +230,7 @@ export class TextManager {
|
|
|
230
230
|
elm.style.setProperty('font-weight', opts.fontWeight)
|
|
231
231
|
elm.style.setProperty('line-height', `${opts.lineHeight * opts.fontSize}px`)
|
|
232
232
|
elm.style.setProperty('text-align', textAlignmentsForLtr[opts.textAlign])
|
|
233
|
+
elm.style.setProperty('font-style', opts.fontStyle)
|
|
233
234
|
|
|
234
235
|
const shouldTruncateToFirstLine =
|
|
235
236
|
opts.overflow === 'truncate-ellipsis' || opts.overflow === 'truncate-clip'
|