UNPKG

tldraw

Version:

A tiny little drawing editor.

8 lines (7 loc) • 13.4 kB
{ "version": 3, "sources": ["../../../../src/lib/shapes/shared/defaultStyleDefs.tsx"], "sourcesContent": ["import {\n\tDefaultColorThemePalette,\n\tDefaultFontStyle,\n\tSvgExportDef,\n\tTLDefaultColorTheme,\n\tTLDefaultFillStyle,\n\tTLShapeUtilCanvasSvgDef,\n\tdebugFlags,\n\tlast,\n\tsuffixSafeId,\n\ttlenv,\n\tuseEditor,\n\tuseSharedSafeId,\n\tuseUniqueSafeId,\n\tuseValue,\n} from '@tldraw/editor'\nimport { useCallback, useEffect, useRef, useState } from 'react'\nimport { useDefaultColorTheme } from './useDefaultColorTheme'\n\n/** @public */\nexport function getFillDefForExport(fill: TLDefaultFillStyle): SvgExportDef {\n\treturn {\n\t\tkey: `${DefaultFontStyle.id}:${fill}`,\n\t\tasync getElement() {\n\t\t\tif (fill !== 'pattern') return null\n\n\t\t\treturn <HashPatternForExport />\n\t\t},\n\t}\n}\n\nfunction HashPatternForExport() {\n\tconst getHashPatternZoomName = useGetHashPatternZoomName()\n\tconst maskId = useUniqueSafeId()\n\tconst theme = useDefaultColorTheme()\n\tconst t = 8 / 12\n\treturn (\n\t\t<>\n\t\t\t<mask id={maskId}>\n\t\t\t\t<rect x=\"0\" y=\"0\" width=\"8\" height=\"8\" fill=\"white\" />\n\t\t\t\t<g strokeLinecap=\"round\" stroke=\"black\">\n\t\t\t\t\t<line x1={t * 1} y1={t * 3} x2={t * 3} y2={t * 1} />\n\t\t\t\t\t<line x1={t * 5} y1={t * 7} x2={t * 7} y2={t * 5} />\n\t\t\t\t\t<line x1={t * 9} y1={t * 11} x2={t * 11} y2={t * 9} />\n\t\t\t\t</g>\n\t\t\t</mask>\n\t\t\t<pattern\n\t\t\t\tid={getHashPatternZoomName(1, theme.id)}\n\t\t\t\twidth=\"8\"\n\t\t\t\theight=\"8\"\n\t\t\t\tpatternUnits=\"userSpaceOnUse\"\n\t\t\t>\n\t\t\t\t<rect x=\"0\" y=\"0\" width=\"8\" height=\"8\" fill={theme.solid} mask={`url(#${maskId})`} />\n\t\t\t</pattern>\n\t\t</>\n\t)\n}\n\nexport function getFillDefForCanvas(): TLShapeUtilCanvasSvgDef {\n\treturn {\n\t\tkey: `${DefaultFontStyle.id}:pattern`,\n\t\tcomponent: PatternFillDefForCanvas,\n\t}\n}\nconst TILE_PATTERN_SIZE = 8\n\nconst generateImage = (dpr: number, currentZoom: number, darkMode: boolean) => {\n\treturn new Promise<Blob>((resolve, reject) => {\n\t\tconst size = TILE_PATTERN_SIZE * currentZoom * dpr\n\n\t\tconst canvasEl = document.createElement('canvas')\n\t\tcanvasEl.width = size\n\t\tcanvasEl.height = size\n\n\t\tconst ctx = canvasEl.getContext('2d')\n\t\tif (!ctx) return\n\n\t\tctx.fillStyle = darkMode\n\t\t\t? DefaultColorThemePalette.darkMode.solid\n\t\t\t: DefaultColorThemePalette.lightMode.solid\n\t\tctx.fillRect(0, 0, size, size)\n\n\t\t// This essentially generates an inverse of the pattern we're drawing.\n\t\tctx.globalCompositeOperation = 'destination-out'\n\n\t\tctx.lineCap = 'round'\n\t\tctx.lineWidth = 1.25 * currentZoom * dpr\n\n\t\tconst t = 8 / 12\n\t\tconst s = (v: number) => v * currentZoom * dpr\n\n\t\tctx.beginPath()\n\t\tctx.moveTo(s(t * 1), s(t * 3))\n\t\tctx.lineTo(s(t * 3), s(t * 1))\n\n\t\tctx.moveTo(s(t * 5), s(t * 7))\n\t\tctx.lineTo(s(t * 7), s(t * 5))\n\n\t\tctx.moveTo(s(t * 9), s(t * 11))\n\t\tctx.lineTo(s(t * 11), s(t * 9))\n\t\tctx.stroke()\n\n\t\tcanvasEl.toBlob((blob) => {\n\t\t\tif (!blob || debugFlags.throwToBlob.get()) {\n\t\t\t\treject()\n\t\t\t} else {\n\t\t\t\tresolve(blob)\n\t\t\t}\n\t\t})\n\t})\n}\n\nconst canvasBlob = (size: [number, number], fn: (ctx: CanvasRenderingContext2D) => void) => {\n\tconst canvas = document.createElement('canvas')\n\tcanvas.width = size[0]\n\tcanvas.height = size[1]\n\tconst ctx = canvas.getContext('2d')\n\tif (!ctx) return ''\n\tfn(ctx)\n\treturn canvas.toDataURL()\n}\ninterface PatternDef {\n\tzoom: number\n\turl: string\n\ttheme: 'light' | 'dark'\n}\n\nlet defaultPixels: { white: string; black: string } | null = null\nfunction getDefaultPixels() {\n\tif (!defaultPixels) {\n\t\tdefaultPixels = {\n\t\t\twhite: canvasBlob([1, 1], (ctx) => {\n\t\t\t\tctx.fillStyle = '#f8f9fa'\n\t\t\t\tctx.fillRect(0, 0, 1, 1)\n\t\t\t}),\n\t\t\tblack: canvasBlob([1, 1], (ctx) => {\n\t\t\t\tctx.fillStyle = '#212529'\n\t\t\t\tctx.fillRect(0, 0, 1, 1)\n\t\t\t}),\n\t\t}\n\t}\n\treturn defaultPixels\n}\n\nfunction getPatternLodForZoomLevel(zoom: number) {\n\treturn Math.ceil(Math.log2(Math.max(1, zoom)))\n}\n\nexport function useGetHashPatternZoomName() {\n\tconst id = useSharedSafeId('hash_pattern')\n\treturn useCallback(\n\t\t(zoom: number, theme: TLDefaultColorTheme['id']) => {\n\t\t\tconst lod = getPatternLodForZoomLevel(zoom)\n\t\t\treturn suffixSafeId(id, `${theme}_${lod}`)\n\t\t},\n\t\t[id]\n\t)\n}\n\nfunction getPatternLodsToGenerate(maxZoom: number) {\n\tconst levels = []\n\tconst minLod = 0\n\tconst maxLod = getPatternLodForZoomLevel(maxZoom)\n\tfor (let i = minLod; i <= maxLod; i++) {\n\t\tlevels.push(Math.pow(2, i))\n\t}\n\treturn levels\n}\n\nfunction getDefaultPatterns(maxZoom: number): PatternDef[] {\n\tconst defaultPixels = getDefaultPixels()\n\treturn getPatternLodsToGenerate(maxZoom).flatMap((zoom) => [\n\t\t{ zoom, url: defaultPixels.white, theme: 'light' },\n\t\t{ zoom, url: defaultPixels.black, theme: 'dark' },\n\t])\n}\n\nfunction usePattern() {\n\tconst editor = useEditor()\n\tconst dpr = useValue('devicePixelRatio', () => editor.getInstanceState().devicePixelRatio, [\n\t\teditor,\n\t])\n\tconst maxZoom = useValue('maxZoom', () => Math.ceil(last(editor.getCameraOptions().zoomSteps)!), [\n\t\teditor,\n\t])\n\tconst [isReady, setIsReady] = useState(false)\n\tconst [backgroundUrls, setBackgroundUrls] = useState<PatternDef[]>(() =>\n\t\tgetDefaultPatterns(maxZoom)\n\t)\n\tconst getHashPatternZoomName = useGetHashPatternZoomName()\n\n\tuseEffect(() => {\n\t\tif (process.env.NODE_ENV === 'test') {\n\t\t\tsetIsReady(true)\n\t\t\treturn\n\t\t}\n\n\t\tconst promise = Promise.all(\n\t\t\tgetPatternLodsToGenerate(maxZoom).flatMap<Promise<PatternDef>>((zoom) => [\n\t\t\t\tgenerateImage(dpr, zoom, false).then((blob) => ({\n\t\t\t\t\tzoom,\n\t\t\t\t\ttheme: 'light',\n\t\t\t\t\turl: URL.createObjectURL(blob),\n\t\t\t\t})),\n\t\t\t\tgenerateImage(dpr, zoom, true).then((blob) => ({\n\t\t\t\t\tzoom,\n\t\t\t\t\ttheme: 'dark',\n\t\t\t\t\turl: URL.createObjectURL(blob),\n\t\t\t\t})),\n\t\t\t])\n\t\t)\n\n\t\tlet isCancelled = false\n\t\tpromise.then((urls) => {\n\t\t\tif (isCancelled) return\n\t\t\tsetBackgroundUrls(urls)\n\t\t\tsetIsReady(true)\n\t\t})\n\t\treturn () => {\n\t\t\tisCancelled = true\n\t\t\tsetIsReady(false)\n\t\t\tpromise.then((patterns) => {\n\t\t\t\tfor (const { url } of patterns) {\n\t\t\t\t\tURL.revokeObjectURL(url)\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\t}, [dpr, maxZoom])\n\n\tconst defs = (\n\t\t<>\n\t\t\t{backgroundUrls.map((item) => {\n\t\t\t\tconst id = getHashPatternZoomName(item.zoom, item.theme)\n\t\t\t\treturn (\n\t\t\t\t\t<pattern\n\t\t\t\t\t\tkey={id}\n\t\t\t\t\t\tid={id}\n\t\t\t\t\t\twidth={TILE_PATTERN_SIZE}\n\t\t\t\t\t\theight={TILE_PATTERN_SIZE}\n\t\t\t\t\t\tpatternUnits=\"userSpaceOnUse\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<image href={item.url} width={TILE_PATTERN_SIZE} height={TILE_PATTERN_SIZE} />\n\t\t\t\t\t</pattern>\n\t\t\t\t)\n\t\t\t})}\n\t\t</>\n\t)\n\n\treturn { defs, isReady }\n}\n\nfunction PatternFillDefForCanvas() {\n\tconst editor = useEditor()\n\tconst containerRef = useRef<SVGGElement>(null)\n\tconst { defs, isReady } = usePattern()\n\n\tuseEffect(() => {\n\t\tif (isReady && tlenv.isSafari) {\n\t\t\tconst htmlLayer = findHtmlLayerParent(containerRef.current!)\n\t\t\tif (htmlLayer) {\n\t\t\t\t// Wait for `patternContext` to be picked up\n\t\t\t\teditor.timers.requestAnimationFrame(() => {\n\t\t\t\t\thtmlLayer.style.display = 'none'\n\n\t\t\t\t\t// Wait for 'display = \"none\"' to take effect\n\t\t\t\t\teditor.timers.requestAnimationFrame(() => {\n\t\t\t\t\t\thtmlLayer.style.display = ''\n\t\t\t\t\t})\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t}, [editor, isReady])\n\n\treturn (\n\t\t<g ref={containerRef} data-testid={isReady ? 'ready-pattern-fill-defs' : undefined}>\n\t\t\t{defs}\n\t\t</g>\n\t)\n}\n\nfunction findHtmlLayerParent(element: Element): HTMLElement | null {\n\tif (element.classList.contains('tl-html-layer')) return element as HTMLElement\n\tif (element.parentElement) return findHtmlLayerParent(element.parentElement)\n\treturn null\n}\n"], "mappings": "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", "names": ["defaultPixels"] }