satori 0.0.20 → 0.0.21

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/satori.ts","../../src/yoga/yoga-prebuilt.wasm.ts","../../src/yoga/index.ts","../../src/utils.ts","../../src/handler/presets.ts","../../src/handler/inheritable.ts","../../src/handler/expand.ts","../../src/vendor/parse-css-dimension/index.js","../../src/transform-origin.ts","../../src/handler/index.ts","../../src/builder/transform.ts","../../src/builder/text.ts","../../src/builder/shadow.ts","../../src/builder/text-decoration.ts","../../src/text.ts","../../src/vendor/gradient-parser/index.js","../../src/builder/background-image.ts","../../src/builder/border-radius.ts","../../src/builder/overflow.ts","../../src/builder/rect.ts","../../src/builder/image.ts","../../src/layout.ts","../../src/font.ts","../../src/builder/svg.ts"],"sourcesContent":["import type { ReactNode } from 'react'\n\nimport { guessLanguage } from 'guesslanguage'\n\nimport getYoga, { init } from './yoga'\nimport layout from './layout'\nimport FontLoader, { FontOptions } from './font'\nimport svg from './builder/svg'\nimport { segment } from './utils'\n\n// We don't need to initialize the opentype instances every time.\nconst fontCache = new WeakMap()\n\nexport interface SatoriOptions {\n width: number\n height: number\n fonts: FontOptions[]\n embedFont?: boolean\n debug?: boolean\n graphemeImages?: Record<string, string>\n // Can be used to dynamically load missing fonts or image for a given segment.\n loadAdditionalAsset?: (\n code: string,\n segment: string\n ) => Promise<FontOptions | string | undefined>\n}\n\nexport { init }\n\nexport default async function satori(\n element: ReactNode,\n options: SatoriOptions\n): Promise<string> {\n const Yoga = getYoga()\n if (!Yoga) throw new Error('Satori is not initialized.')\n\n let font: FontLoader\n if (fontCache.has(options.fonts)) {\n font = fontCache.get(options.fonts)\n } else {\n fontCache.set(options.fonts, (font = new FontLoader(options.fonts)))\n }\n\n const root = Yoga.Node.create()\n root.setWidth(options.width)\n root.setHeight(options.height)\n root.setFlexDirection(Yoga.FLEX_DIRECTION_ROW)\n root.setFlexWrap(Yoga.WRAP_WRAP)\n root.setAlignContent(Yoga.ALIGN_AUTO)\n root.setAlignItems(Yoga.ALIGN_FLEX_START)\n root.setJustifyContent(Yoga.JUSTIFY_FLEX_START)\n root.setOverflow(Yoga.OVERFLOW_HIDDEN)\n\n const graphemeImages = { ...options.graphemeImages }\n\n const handler = layout(element, {\n id: 'id',\n parentStyle: {},\n inheritedStyle: {\n fontSize: 16,\n fontWeight: 'normal',\n fontFamily: 'serif',\n fontStyle: 'normal',\n lineHeight: 1.2,\n color: 'black',\n opacity: 1,\n whiteSpace: 'normal',\n\n // Special style properties:\n _viewportWidth: options.width,\n _viewportHeight: options.height,\n },\n parent: root,\n font,\n embedFont: options.embedFont,\n debug: options.debug,\n graphemeImages,\n canLoadAdditionalAssets: !!options.loadAdditionalAsset,\n })\n\n let segmentsMissingFont = handler.next().value as string[]\n\n if (options.loadAdditionalAsset) {\n if (segmentsMissingFont.length) {\n // Potentially CJK fonts are missing.\n segmentsMissingFont = Array.from(\n new Set(segment(segmentsMissingFont.join(''), 'grapheme'))\n )\n\n const langaugeCodes: Record<string, string[]> = {}\n segmentsMissingFont.forEach((seg) =>\n guessLanguage.detect(seg, (code) => {\n langaugeCodes[code] = langaugeCodes[code] || []\n if (code === 'unknown') {\n langaugeCodes[code].push(seg)\n } else {\n langaugeCodes[code][0] = (langaugeCodes[code][0] || '') + seg\n }\n })\n )\n\n const fonts: FontOptions[] = []\n const images: Record<string, string> = {}\n\n await Promise.all(\n Object.entries(langaugeCodes).flatMap(([code, segments]) =>\n segments.map((segment) =>\n options.loadAdditionalAsset(code, segment).then((asset) => {\n if (typeof asset === 'string') {\n images[segment] = asset\n } else if (asset) {\n fonts.push(asset)\n }\n })\n )\n )\n )\n\n // Directly mutate the font provider and the grapheme map.\n font.addFonts(fonts)\n Object.assign(graphemeImages, images)\n }\n }\n\n handler.next()\n root.calculateLayout(options.width, options.height, Yoga.DIRECTION_LTR)\n\n const content = handler.next([0, 0]).value as string\n\n root.freeRecursive()\n\n return svg({ width: options.width, height: options.height, content })\n}\n","// For WASM build, we don't include the prebuilt version of Yoga but let the\n// user specify the module manually with e.g.:\n// https://github.com/shuding/yoga-wasm-web.\nexport default {}\n","let Yoga: typeof import('yoga-layout')\n\nimport YogaMod from '@yoga'\n\n// @ts-ignore\nYoga = YogaMod.default\n\nexport function init(yoga: typeof Yoga) {\n Yoga = yoga\n}\n\nexport default function getYoga(): typeof Yoga {\n return Yoga\n}\n","import type { ReactNode, ReactElement } from 'react'\n\nimport { LineBreaker } from 'css-line-break'\nimport { splitGraphemes } from 'text-segmentation'\n\nexport function isReactElement(node: ReactNode): node is ReactElement {\n const type = typeof node\n if (\n type === 'number' ||\n type === 'bigint' ||\n type === 'string' ||\n type === 'boolean'\n ) {\n return false\n }\n return true\n}\n\nexport function isClass(f: Function) {\n return /^class\\s/.test(Function.prototype.toString.call(f))\n}\n\n// Multiplies two 2d transform matrices.\nexport function multiply(m1: number[], m2: number[]) {\n return [\n m1[0] * m2[0] + m1[2] * m2[1],\n m1[1] * m2[0] + m1[3] * m2[1],\n m1[0] * m2[2] + m1[2] * m2[3],\n m1[1] * m2[2] + m1[3] * m2[3],\n m1[0] * m2[4] + m1[2] * m2[5] + m1[4],\n m1[1] * m2[4] + m1[3] * m2[5] + m1[5],\n ]\n}\n\nexport function v(\n field: string | number,\n map: Record<string, any>,\n fallback: any\n) {\n const value = map[field]\n return typeof value === 'undefined' ? fallback : value\n}\n\n// @TODO: Support \"lang\" attribute to modify the locale\nconst locale = undefined\n\nconst INTL_SEGMENTER_SUPPORTED =\n typeof Intl !== 'undefined' &&\n 'Segmenter' in Intl &&\n process.env.NODE_ENV !== 'test'\n\nconst wordSegmenter = INTL_SEGMENTER_SUPPORTED\n ? new (Intl as any).Segmenter(locale, { granularity: 'word' })\n : null\nconst graphemeSegmenter = INTL_SEGMENTER_SUPPORTED\n ? new (Intl as any).Segmenter(locale, {\n granularity: 'grapheme',\n })\n : null\n\n// Implementation modified from\n// https://github.com/niklasvh/html2canvas/blob/6521a487d78172f7179f7c973c1a3af40eb92009/src/css/layout/text.ts\n// https://drafts.csswg.org/css-text/#word-separator\nexport const wordSeparators = [\n 0x0020, 0x00a0, 0x1361, 0x10100, 0x10101, 0x1039, 0x1091, 0xa,\n].map((point) => String.fromCodePoint(point))\n\nconst breakWords = (str: string): string[] => {\n const breaker = LineBreaker(str, {\n lineBreak: 'strict',\n wordBreak: 'normal',\n })\n\n const words = []\n let bk\n\n while (!(bk = breaker.next()).done) {\n if (bk.value) {\n const value = bk.value.slice()\n let word = ''\n for (let i = 0; i < value.length; i++) {\n const char = value[i]\n if (!wordSeparators.includes(char)) {\n word += char\n } else {\n if (word.length) {\n words.push(word)\n }\n words.push(char)\n word = ''\n }\n }\n\n if (word.length) {\n words.push(word)\n }\n }\n }\n\n return words\n}\n\nexport function segment(\n content: string,\n granularity: 'word' | 'grapheme'\n): string[] {\n if (INTL_SEGMENTER_SUPPORTED) {\n return granularity === 'word'\n ? [...wordSegmenter.segment(content)].map((seg) => seg.segment)\n : [...graphemeSegmenter.segment(content)].map((seg) => seg.segment)\n }\n\n if (granularity === 'word') {\n return breakWords(content)\n } else {\n return splitGraphemes(content)\n }\n}\n\nexport function buildXMLString(\n type: string,\n attrs: Record<string, any>,\n children?: string\n) {\n let attrString = ''\n\n for (const [k, v] of Object.entries(attrs)) {\n if (typeof v !== 'undefined') {\n attrString += ` ${k}=\"${v}\"`\n }\n }\n\n if (children) {\n return `<${type}${attrString}>${children}</${type}>`\n }\n return `<${type}${attrString}/>`\n}\n","/**\n * Pre-defined styles for elements. Here we hand pick some from Chromium's\n * default styles:\n * https://chromium.googlesource.com/chromium/blink/+/master/Source/core/css/html.css\n *\n * We try to only include commonly used, styling elements rather than senmantic elements.\n */\n\nexport default {\n // Generic block-level elements\n p: {\n display: 'block',\n marginTop: '1em',\n marginBottom: '1em',\n },\n div: {\n display: 'block',\n },\n blockquote: {\n display: 'block',\n marginTop: '1em',\n marginBottom: '1em',\n marginLeft: 40,\n marginRight: 40,\n },\n center: {\n display: 'block',\n textAlign: 'center',\n },\n hr: {\n display: 'block',\n marginTop: '0.5em',\n marginBottom: '0.5em',\n marginLeft: 'auto',\n marginRight: 'auto',\n borderWidth: 1,\n borderStyle: 'inset',\n },\n // Heading elements\n h1: {\n display: 'block',\n fontSize: '2em',\n marginTop: '0.67em',\n marginBottom: '0.67em',\n marginLeft: 0,\n marginRight: 0,\n fontWeight: 'bold',\n },\n h2: {\n display: 'block',\n fontSize: '1.5em',\n marginTop: '0.83em',\n marginBottom: '0.83em',\n marginLeft: 0,\n marginRight: 0,\n fontWeight: 'bold',\n },\n h3: {\n display: 'block',\n fontSize: '1.17em',\n marginTop: '1em',\n marginBottom: '1em',\n marginLeft: 0,\n marginRight: 0,\n fontWeight: 'bold',\n },\n h4: {\n display: 'block',\n marginTop: '1.33em',\n marginBottom: '1.33em',\n marginLeft: 0,\n marginRight: 0,\n fontWeight: 'bold',\n },\n h5: {\n display: 'block',\n fontSize: '0.83em',\n marginTop: '1.67em',\n marginBottom: '1.67em',\n marginLeft: 0,\n marginRight: 0,\n fontWeight: 'bold',\n },\n h6: {\n display: 'block',\n fontSize: '0.67em',\n marginTop: '2.33em',\n marginBottom: '2.33em',\n marginLeft: 0,\n marginRight: 0,\n fontWeight: 'bold',\n },\n // Tables\n // Lists\n // Form elements\n // Inline elements\n u: {\n textDecoration: 'underline',\n },\n strong: {\n fontWeight: 'bold',\n },\n b: {\n fontWeight: 'bold',\n },\n i: {\n fontStyle: 'italic',\n },\n em: {\n fontStyle: 'italic',\n },\n code: {\n fontFamily: 'monospace',\n },\n kbd: {\n fontFamily: 'monospace',\n },\n pre: {\n display: 'block',\n fontFamily: 'monospace',\n whiteSpace: 'pre',\n marginTop: '1em',\n marginBottom: '1em',\n },\n mark: {\n backgroundColor: 'yellow',\n color: 'black',\n },\n big: {\n fontSize: 'larger',\n },\n small: {\n fontSize: 'smaller',\n },\n s: {\n textDecoration: 'line-through',\n },\n}\n","const list = new Set([\n 'color',\n 'font',\n 'fontFamily',\n 'fontSize',\n 'fontStyle',\n 'fontWeight',\n 'letterSpacing',\n 'lineHeight',\n 'textAlign',\n 'textTransform',\n 'textShadowOffset',\n 'textShadowColor',\n 'textShadowRadius',\n 'textDecorationLine',\n 'textDecorationStyle',\n 'textDecorationColor',\n 'whiteSpace',\n 'transform',\n 'wordBreak',\n\n // Special case: SVG doesn't apply these to children elements so we need to\n // make it inheritable here.\n 'opacity',\n 'filter',\n\n // Special properties of Satori:\n '_viewportWidth',\n '_viewportHeight',\n '_inheritedClipPathId',\n '_inheritedBackgroundClipTextPath',\n])\n\nexport default function inheritable(style: Record<string, any>) {\n const inheritedStyle: Record<string, any> = {}\n for (const prop in style) {\n if (list.has(prop)) {\n inheritedStyle[prop] = style[prop]\n }\n }\n return inheritedStyle\n}\n","/**\n * This module expands the CSS properties to get rid of shorthands, as well as\n * cleaning up some properties.\n */\n\nimport { getPropertyName, getStylesForProperty } from 'css-to-react-native'\nimport { parseElementStyle } from 'css-background-parser'\n\nimport CssDimension from '../vendor/parse-css-dimension'\nimport parseTransformOrigin from '../transform-origin'\nimport { multiply } from '../utils'\n\n// https://react-cn.github.io/react/tips/style-props-value-px.html\nconst optOutPx = new Set([\n 'flex',\n 'flexGrow',\n 'flexShrink',\n 'flexBasis',\n 'fontWeight',\n 'lineHeight',\n 'opacity',\n 'scale',\n 'scaleX',\n 'scaleY',\n])\nconst keepNumber = new Set(['lineHeight'])\n\nconst baseMatrix = [1, 0, 0, 1, 0, 0]\n\n/**\n * A trick to fix `border: 1px solid` to not use `black` but the inherited\n * `color` value. This is necessary because css-to-react-native automatically\n * fallbacks to default color values.\n */\nfunction handleFallbackColor(\n prop: string,\n parsed: Record<string, string>,\n rawInput: string,\n color: string\n) {\n if (prop === 'border' && !rawInput.includes(parsed.borderColor)) {\n parsed.borderColor = color\n } else if (\n prop === 'textDecoration' &&\n !rawInput.includes(parsed.textDecorationColor)\n ) {\n parsed.textDecorationColor = color\n }\n return parsed\n}\n\nfunction purify(name: string, value?: string | number) {\n if (typeof value === 'number') {\n if (!optOutPx.has(name)) return value + 'px'\n if (keepNumber.has(name)) return value\n return String(value)\n }\n // @TODO: For `transform`, we need to convert relative values to absolute\n // values here.\n return value\n}\n\nfunction handleSpecialCase(name: string, value: string | number) {\n if (name === 'lineHeight') return { lineHeight: purify(name, value) }\n if (name === 'fontFamily')\n return {\n fontFamily: (value as string).split(',').map((v) => {\n return v\n .trim()\n .replace(/(^['\"])|(['\"]$)/g, '')\n .toLocaleLowerCase()\n }),\n }\n return null\n}\n\nfunction lengthToNumber(\n length: string | number,\n baseFontSize: number,\n inheritedStyle: Record<string, string | number>,\n { percentage }: { percentage: boolean } = { percentage: false }\n): number | undefined {\n if (typeof length === 'number') return length\n\n // Convert em and rem values to number (px), convert rad to deg.\n try {\n const parsed = new CssDimension(length)\n if (parsed.type === 'length') {\n switch (parsed.unit) {\n case 'em':\n return parsed.value * baseFontSize\n case 'rem':\n return parsed.value * 16\n case 'vw':\n return ~~(\n (parsed.value * (inheritedStyle._viewportWidth as number)) /\n 100\n )\n case 'vh':\n return ~~(\n (parsed.value * (inheritedStyle._viewportHeight as number)) /\n 100\n )\n default:\n return parsed.value\n }\n } else if (parsed.type === 'angle') {\n switch (parsed.unit) {\n case 'deg':\n return parsed.value\n case 'rad':\n return (parsed.value * 180) / Math.PI\n default:\n return parsed.value\n }\n } else if (parsed.type === 'percentage') {\n if (percentage) {\n return (parsed.value / 100) * baseFontSize\n }\n }\n } catch (err) {}\n}\n\nexport default function expand(\n style: Record<string, string | number>,\n inheritedStyle: Record<string, string | number>\n): Record<string, string | number> {\n const transformedStyle = {} as any\n for (const prop in style) {\n // Internal properties.\n if (prop.startsWith('_')) {\n transformedStyle[prop] = style[prop]\n continue\n }\n\n const name = getPropertyName(prop)\n Object.assign(\n transformedStyle,\n handleSpecialCase(name, style[prop]) ||\n handleFallbackColor(\n name,\n getStylesForProperty(name, purify(name, style[prop]), true),\n style[prop] as string,\n (style.color || inheritedStyle.color) as string\n )\n )\n }\n\n // Parse background images.\n if (transformedStyle.backgroundImage) {\n const { backgrounds } = parseElementStyle(transformedStyle)\n transformedStyle.backgroundImage = backgrounds\n }\n\n // Calculate the base font size.\n let baseFontSize: number =\n transformedStyle.fontSize || inheritedStyle.fontSize\n if (typeof baseFontSize === 'string') {\n try {\n const parsed = new CssDimension(baseFontSize)\n switch (parsed.unit) {\n case 'em':\n baseFontSize = parsed.value * (inheritedStyle.fontSize as number)\n break\n case 'rem':\n baseFontSize = parsed.value * 16\n break\n }\n } catch (err) {\n baseFontSize = 16\n }\n }\n if (typeof transformedStyle.fontSize !== 'undefined') {\n transformedStyle.fontSize = baseFontSize\n }\n\n if (transformedStyle.transformOrigin) {\n transformedStyle.transformOrigin = parseTransformOrigin(\n transformedStyle.transformOrigin,\n baseFontSize\n )\n }\n\n for (const prop in transformedStyle) {\n let value = transformedStyle[prop]\n\n // Line height needs to be relative.\n if (prop === 'lineHeight') {\n if (typeof value === 'string') {\n value = transformedStyle[prop] =\n lengthToNumber(value, baseFontSize, inheritedStyle, {\n percentage: true,\n }) / baseFontSize\n }\n } else {\n // Convert em and rem values to px (number).\n if (typeof value === 'string') {\n const len = lengthToNumber(value, baseFontSize, inheritedStyle)\n if (typeof len !== 'undefined') transformedStyle[prop] = len\n value = transformedStyle[prop]\n }\n }\n\n // Inherit the opacity.\n if (prop === 'opacity') {\n value = transformedStyle[prop] =\n value * (inheritedStyle.opacity as number)\n }\n\n // Handle CSS transforms To make it easier, we convert different transform\n // types directly to a matrix and apply it recursively to all its children.\n // @TODO: We need to convert relative values (50%) to absolute values. This\n // is pretty tricky to support as we need an extra pass to handle them after\n // the full layout pass.\n if (prop === 'transform') {\n let matrix = [...baseMatrix]\n const transforms = value as { [type: string]: number | string }[]\n\n // Transforms are applied from right to left.\n for (const transform of transforms) {\n const type = Object.keys(transform)[0]\n const v = transform[type]\n const len =\n typeof v === 'string'\n ? lengthToNumber(v, baseFontSize, inheritedStyle)\n : v\n\n const transformMatrix = [...baseMatrix]\n switch (type) {\n case 'translateX':\n transformMatrix[4] = len\n break\n case 'translateY':\n transformMatrix[5] = len\n break\n case 'scale':\n transformMatrix[0] = len\n transformMatrix[3] = len\n break\n case 'scaleX':\n transformMatrix[0] = len\n break\n case 'scaleY':\n transformMatrix[3] = len\n break\n case 'rotate':\n const rad = (len * Math.PI) / 180\n const c = Math.cos(rad)\n const s = Math.sin(rad)\n transformMatrix[0] = c\n transformMatrix[1] = s\n transformMatrix[2] = -s\n transformMatrix[3] = c\n break\n case 'skewX':\n transformMatrix[2] = Math.tan((len * Math.PI) / 180)\n break\n case 'skewY':\n transformMatrix[1] = Math.tan((len * Math.PI) / 180)\n break\n }\n matrix = multiply(transformMatrix, matrix)\n }\n\n transformedStyle.transform = matrix\n }\n }\n\n return transformedStyle\n}\n","var e=(t,r)=>()=>(r||t((r={exports:{}}).exports,r),r.exports);var u=e((k,g)=>{g.exports=[\"em\",\"ex\",\"ch\",\"rem\",\"vh\",\"vw\",\"vmin\",\"vmax\",\"px\",\"mm\",\"cm\",\"in\",\"pt\",\"pc\",\"mozmm\"]});var a=e((z,v)=>{v.exports=[\"deg\",\"grad\",\"rad\",\"turn\"]});var c=e((L,w)=>{w.exports=[\"dpi\",\"dpcm\",\"dppx\"]});var h=e(($,y)=>{y.exports=[\"Hz\",\"kHz\"]});var m=e((j,b)=>{b.exports=[\"s\",\"ms\"]});var q=u(),f=a(),p=c(),l=h(),d=m();function s(t){if(/\\.\\D?$/.test(t))throw new Error(\"The dot should be followed by a number\");if(/^[+-]{2}/.test(t))throw new Error(\"Only one leading +/- is allowed\");if(x(t)>1)throw new Error(\"Only one dot is allowed\");if(/%$/.test(t)){this.type=\"percentage\",this.value=o(t),this.unit=\"%\";return}var r=O(t);if(!r){this.type=\"number\",this.value=o(t);return}this.type=F(r),this.value=o(t.substr(0,t.length-r.length)),this.unit=r}s.prototype.valueOf=function(){return this.value};s.prototype.toString=function(){return this.value+(this.unit||\"\")};function U(t){return new s(t)}function x(t){var r=t.match(/\\./g);return r?r.length:0}function o(t){var r=parseFloat(t);if(isNaN(r))throw new Error(\"Invalid number: \"+t);return r}var E=[].concat(f,l,q,p,d);function O(t){var r=t.match(/\\D+$/),n=r&&r[0];if(n&&E.indexOf(n)===-1)throw new Error(\"Invalid unit: \"+n);return n}var D=Object.assign(i(f,\"angle\"),i(l,\"frequency\"),i(p,\"resolution\"),i(d,\"time\"));function i(t,r){return Object.fromEntries(t.map(n=>[n,r]))}function F(t){return D[t]||\"length\"}export{U as default};\n","import valueParser from 'postcss-value-parser'\n\nimport CssDimension from './vendor/parse-css-dimension'\n\n/**\n * If key for each direction is missing, assume default (50%)\n */\nexport interface ParsedTransformOrigin {\n /** Relative horizontal transform origin in % */\n xRelative?: number\n /** Relative vertical transform origin in % */\n yRelative?: number\n /** Absolute horizontal transform origin in pixels */\n xAbsolute?: number\n /** Absolute horizontal transform origin in pixels */\n yAbsolute?: number\n}\n\ninterface ParsedUnit {\n /** Relative unit in % */\n relative?: number\n /** Absolute unit in pixels */\n absolute?: number\n}\n\nfunction parseUnit(word: string, baseFontSize: number): ParsedUnit {\n try {\n const parsed = new CssDimension(word)\n switch (parsed.unit) {\n case 'px':\n return { absolute: parsed.value }\n case 'em':\n return { absolute: parsed.value * baseFontSize }\n case 'rem':\n return { absolute: parsed.value * 16 }\n case '%':\n return { relative: parsed.value }\n default:\n return {}\n }\n } catch (e) {\n return {}\n }\n}\n\nfunction handleWord(\n word: string,\n baseFontSize: number,\n unitIsHorizontal: boolean\n) {\n switch (word) {\n case 'top':\n return { yRelative: 0 }\n case 'left':\n return { xRelative: 0 }\n case 'right':\n return { xRelative: 100 }\n case 'bottom':\n return { yRelative: 100 }\n case 'center':\n return {}\n default:\n const parsedUnit = parseUnit(word, baseFontSize)\n return parsedUnit.absolute\n ? {\n [unitIsHorizontal ? 'xAbsolute' : 'yAbsolute']: parsedUnit.absolute,\n }\n : parsedUnit.relative\n ? {\n [unitIsHorizontal ? 'xRelative' : 'yRelative']: parsedUnit.relative,\n }\n : {}\n }\n}\n\nexport default function parseTranformOrigin(\n value: string | number,\n baseFontSize: number\n): ParsedTransformOrigin {\n // If it's a single value and a number, then it's horizontal\n if (typeof value === 'number') {\n return { xAbsolute: value }\n }\n let words: string[]\n try {\n words = valueParser(value)\n .nodes.filter((node) => node.type === 'word')\n .map((node) => node.value)\n } catch (e) {\n return {}\n }\n\n if (words.length === 1) {\n // If it's a single value and a number, then it's horizontal, so\n // pass `true` to `unitIsHorizontal`\n return handleWord(words[0], baseFontSize, true)\n } else if (words.length === 2) {\n // Make words to be [horizontal, vertical]\n if (\n words[0] === 'top' ||\n words[0] === 'bottom' ||\n words[1] === 'left' ||\n words[1] === 'right'\n ) {\n words.reverse()\n }\n\n return {\n ...handleWord(words[0], baseFontSize, true),\n ...handleWord(words[1], baseFontSize, false),\n }\n } else {\n return {}\n }\n}\n","/**\n * Handler to update the Yoga node properties with the given element type and\n * style. Each supported element has its own preset styles, so this function\n * also returns the inherited style for children of the element.\n */\n\nimport type { YogaNode } from 'yoga-layout'\n\nimport getYoga from '../yoga'\nimport presets from './presets'\nimport inheritable from './inheritable'\nimport expand from './expand'\nimport { v } from '../utils'\n\ntype SatoriElement = keyof typeof presets\n\nexport default function handler(\n node: YogaNode,\n type: SatoriElement | string,\n inheritedStyle: Record<string, string | number>,\n definedStyle: Record<string, string | number>,\n props: Record<string, any>\n): [Record<string, string | number>, Record<string, string | number>] {\n const Yoga = getYoga()\n\n // Extend the default style with defined and inherited styles.\n const style = {\n ...inheritedStyle,\n ...expand(presets[type], inheritedStyle),\n ...expand(definedStyle, inheritedStyle),\n }\n\n if (type === 'img') {\n const width = parseInt(props.width)\n const height = parseInt(props.height)\n const r = height / width\n if (!style.width) style.width = width\n if (!style.height) style.height = r * (style.width as number)\n }\n\n // Set properties for Yoga.\n node.setDisplay(\n v(\n style.display,\n {\n flex: Yoga.DISPLAY_FLEX,\n none: Yoga.DISPLAY_NONE,\n },\n Yoga.DISPLAY_FLEX\n )\n )\n\n node.setAlignContent(\n v(\n style.alignContent,\n {\n stretch: Yoga.ALIGN_STRETCH,\n center: Yoga.ALIGN_CENTER,\n 'flex-start': Yoga.ALIGN_FLEX_START,\n 'flex-end': Yoga.ALIGN_FLEX_END,\n 'space-between': Yoga.ALIGN_SPACE_BETWEEN,\n 'space-around': Yoga.ALIGN_SPACE_AROUND,\n baseline: Yoga.ALIGN_BASELINE,\n normal: Yoga.ALIGN_AUTO,\n },\n Yoga.ALIGN_AUTO\n )\n )\n\n node.setAlignItems(\n v(\n style.alignItems,\n {\n stretch: Yoga.ALIGN_STRETCH,\n center: Yoga.ALIGN_CENTER,\n 'flex-start': Yoga.ALIGN_FLEX_START,\n 'flex-end': Yoga.ALIGN_FLEX_END,\n baseline: Yoga.ALIGN_BASELINE,\n normal: Yoga.ALIGN_AUTO,\n },\n Yoga.ALIGN_FLEX_START\n )\n )\n node.setAlignSelf(\n v(\n style.alignSelf,\n {\n stretch: Yoga.ALIGN_STRETCH,\n center: Yoga.ALIGN_CENTER,\n 'flex-start': Yoga.ALIGN_FLEX_START,\n 'flex-end': Yoga.ALIGN_FLEX_END,\n baseline: Yoga.ALIGN_BASELINE,\n normal: Yoga.ALIGN_AUTO,\n },\n Yoga.ALIGN_AUTO\n )\n )\n node.setJustifyContent(\n v(\n style.justifyContent,\n {\n center: Yoga.JUSTIFY_CENTER,\n 'flex-start': Yoga.JUSTIFY_FLEX_START,\n 'flex-end': Yoga.JUSTIFY_FLEX_END,\n 'space-between': Yoga.JUSTIFY_SPACE_BETWEEN,\n 'space-around': Yoga.JUSTIFY_SPACE_AROUND,\n },\n Yoga.JUSTIFY_FLEX_START\n )\n )\n // @TODO: node.setAspectRatio\n\n node.setFlexDirection(\n v(\n style.flexDirection,\n {\n row: Yoga.FLEX_DIRECTION_ROW,\n column: Yoga.FLEX_DIRECTION_COLUMN,\n 'row-reverse': Yoga.FLEX_DIRECTION_ROW_REVERSE,\n 'column-reverse': Yoga.FLEX_DIRECTION_COLUMN_REVERSE,\n },\n Yoga.FLEX_DIRECTION_ROW\n )\n )\n node.setFlexWrap(\n v(\n style.flexWrap,\n {\n wrap: Yoga.WRAP_WRAP,\n nowrap: Yoga.WRAP_NO_WRAP,\n 'wrap-reverse': Yoga.WRAP_WRAP_REVERSE,\n },\n Yoga.WRAP_WRAP\n )\n )\n\n // @TODO: node.setFlex\n\n if (typeof style.flexBasis !== 'undefined') {\n // We can't use `auto` here due to this:\n // https://github.com/facebook/yoga/pull/1112\n // @TODO: We need a fork to add this API.\n node.setFlexBasis(style.flexBasis)\n }\n node.setFlexGrow(\n typeof style.flexGrow === 'undefined' ? 0 : (style.flexGrow as number)\n )\n node.setFlexShrink(\n typeof style.flexShrink === 'undefined' ? 0 : (style.flexShrink as number)\n )\n\n if (typeof style.maxHeight !== 'undefined') {\n node.setMaxHeight(style.maxHeight)\n }\n if (typeof style.maxWidth !== 'undefined') {\n node.setMaxWidth(style.maxWidth)\n }\n if (typeof style.minHeight !== 'undefined') {\n node.setMinHeight(style.minHeight)\n }\n if (typeof style.minWidth !== 'undefined') {\n node.setMinWidth(style.minWidth)\n }\n\n node.setOverflow(\n v(\n style.overflow,\n {\n visible: Yoga.OVERFLOW_VISIBLE,\n hidden: Yoga.OVERFLOW_HIDDEN,\n },\n Yoga.OVERFLOW_VISIBLE\n )\n )\n\n node.setMargin(Yoga.EDGE_TOP, (style.marginTop as number) || 0)\n node.setMargin(Yoga.EDGE_BOTTOM, (style.marginBottom as number) || 0)\n node.setMargin(Yoga.EDGE_LEFT, (style.marginLeft as number) || 0)\n node.setMargin(Yoga.EDGE_RIGHT, (style.marginRight as number) || 0)\n\n // @TODO: Add directional border support.\n node.setBorder(Yoga.EDGE_TOP, (style.borderWidth as number) || 0)\n node.setBorder(Yoga.EDGE_BOTTOM, (style.borderWidth as number) || 0)\n node.setBorder(Yoga.EDGE_LEFT, (style.borderWidth as number) || 0)\n node.setBorder(Yoga.EDGE_RIGHT, (style.borderWidth as number) || 0)\n\n node.setPadding(Yoga.EDGE_TOP, style.paddingTop || 0)\n node.setPadding(Yoga.EDGE_BOTTOM, style.paddingBottom || 0)\n node.setPadding(Yoga.EDGE_LEFT, style.paddingLeft || 0)\n node.setPadding(Yoga.EDGE_RIGHT, style.paddingRight || 0)\n\n node.setPositionType(\n v(\n style.position,\n {\n absolute: Yoga.POSITION_TYPE_ABSOLUTE,\n relative: Yoga.POSITION_TYPE_RELATIVE,\n },\n Yoga.POSITION_TYPE_RELATIVE\n )\n )\n\n if (typeof style.top !== 'undefined') {\n node.setPosition(Yoga.EDGE_TOP, style.top)\n }\n if (typeof style.bottom !== 'undefined') {\n node.setPosition(Yoga.EDGE_BOTTOM, style.bottom)\n }\n if (typeof style.left !== 'undefined') {\n node.setPosition(Yoga.EDGE_LEFT, style.left)\n }\n if (typeof style.right !== 'undefined') {\n node.setPosition(Yoga.EDGE_RIGHT, style.right)\n }\n\n if (typeof style.height !== 'undefined') {\n node.setHeight(style.height)\n } else {\n node.setHeightAuto()\n }\n if (typeof style.width !== 'undefined') {\n node.setWidth(style.width)\n } else {\n node.setWidthAuto()\n }\n\n return [style, inheritable(style)]\n}\n","import { multiply } from '../utils'\nimport type { ParsedTransformOrigin } from '../transform-origin'\n\nexport default function transform(\n {\n left,\n top,\n width,\n height,\n }: {\n left: number\n top: number\n width: number\n height: number\n },\n matrix: number[],\n isInheritingTransform: boolean,\n transformOrigin?: ParsedTransformOrigin\n) {\n let result: number[]\n\n // Calculate the transform origin.\n if (isInheritingTransform) {\n result = matrix\n } else {\n const xOrigin =\n transformOrigin?.xAbsolute ??\n ((transformOrigin?.xRelative ?? 50) * width) / 100\n const yOrigin =\n transformOrigin?.yAbsolute ??\n ((transformOrigin?.yRelative ?? 50) * height) / 100\n\n // If this element is the transform target, we attach the origin coordinates\n // to this matrix.\n const x = left + xOrigin\n const y = top + yOrigin\n\n // Due to the different coordinate systems, we need to move the shape to the\n // origin first, then apply the matrix, then move it back.\n result = multiply(\n [1, 0, 0, 1, x, y],\n multiply(matrix, [1, 0, 0, 1, -x, -y])\n )\n\n // And we need to apply its parent transform if it has one.\n if ((matrix as any).__parent) {\n result = multiply((matrix as any).__parent, result)\n }\n\n // Mutate self.\n matrix.splice(0, 6, ...result)\n }\n\n return `matrix(${result.map((v) => v.toFixed(2)).join(',')})`\n}\n","import type { ParsedTransformOrigin } from '../transform-origin'\nimport transform from './transform'\nimport { buildXMLString } from '../utils'\n\nexport function container(\n {\n left,\n top,\n width,\n height,\n isInheritingTransform,\n }: {\n left: number\n top: number\n width: number\n height: number\n isInheritingTransform: boolean\n },\n style: Record<string, number | string>\n) {\n let matrix = ''\n let opacity = 1\n\n if (style.transform) {\n matrix = transform(\n {\n left,\n top,\n width,\n height,\n },\n style.transform as unknown as number[],\n isInheritingTransform,\n style.transformOrigin as ParsedTransformOrigin | undefined\n )\n }\n\n if (style.opacity) {\n opacity = +style.opacity\n }\n\n return { matrix, opacity }\n}\n\nexport default function text(\n {\n id,\n content,\n filter,\n left,\n top,\n width,\n height,\n matrix,\n opacity,\n image,\n clipPathId,\n debug,\n shape,\n decorationShape,\n }: {\n content: string\n filter: string\n id: string\n left: number\n top: number\n width: number\n height: number\n matrix: string\n opacity: number\n image: string | null\n clipPathId?: string\n debug?: boolean\n shape?: boolean\n decorationShape?: string\n },\n style: Record<string, number | string>\n) {\n let extra = ''\n if (debug) {\n extra = buildXMLString('rect', {\n x: left,\n y: top - height,\n width,\n height,\n fill: 'transparent',\n stroke: '#575eff',\n 'stroke-width': 1,\n transform: matrix || undefined,\n 'clip-path': clipPathId ? `url(#${clipPathId})` : undefined,\n })\n }\n\n // This grapheme should be rendered as an image.\n if (image) {\n const shapeProps = {\n href: image,\n x: left,\n y: top,\n width,\n height,\n transform: matrix || undefined,\n 'clip-path': clipPathId ? `url(#${clipPathId})` : undefined,\n style: style.filter ? `filter:${style.filter}` : undefined,\n }\n return [\n (filter ? `${filter}<g filter=\"url(#satori_s-${id})\">` : '') +\n buildXMLString('image', {\n ...shapeProps,\n opacity: opacity !== 1 ? opacity : undefined,\n }) +\n (decorationShape || '') +\n (filter ? '</g>' : '') +\n extra,\n // SVG doesn't support `<image>` as the shape.\n '',\n ]\n }\n\n // Do not embed the font, use <text> with the raw content instead.\n const shapeProps = {\n x: left,\n y: top,\n width,\n height,\n 'font-weight': style.fontWeight,\n 'font-style': style.fontStyle,\n 'font-size': style.fontSize,\n 'font-family': style.fontFamily,\n 'letter-spacing': style.letterSpacing || undefined,\n transform: matrix || undefined,\n 'clip-path': clipPathId ? `url(#${clipPathId})` : undefined,\n style: style.filter ? `filter:${style.filter}` : undefined,\n }\n return [\n (filter ? `${filter}<g filter=\"url(#satori_s-${id})\">` : '') +\n buildXMLString(\n 'text',\n {\n ...shapeProps,\n fill: style.color,\n opacity: opacity !== 1 ? opacity : undefined,\n },\n content\n ) +\n (decorationShape || '') +\n (filter ? '</g>' : '') +\n extra,\n shape ? buildXMLString('text', shapeProps, content) : '',\n ]\n}\n","// @TODO: It seems that SVG filters are pretty expensive for resvg, PNG\n// generation time 10x'd when adding this filter (WASM in browser).\n// https://drafts.fxtf.org/filter-effects/#feGaussianBlurElement\n\nexport default function shadow(\n { id, width, height }: { id: string; width: number; height: number },\n style: Record<string, any>\n) {\n if (\n !style.shadowColor ||\n !style.shadowOffset ||\n typeof style.shadowRadius === 'undefined'\n ) {\n return ''\n }\n\n // Expand the area for the filter to prevent it from cutting off.\n const grow = (style.shadowRadius * style.shadowRadius) / 4\n\n const left = Math.min(style.shadowOffset.width - grow, 0)\n const right = Math.max(style.shadowOffset.width + grow + width, width)\n const top = Math.min(style.shadowOffset.height - grow, 0)\n const bottom = Math.max(style.shadowOffset.height + grow + height, height)\n\n return `<defs><filter id=\"satori_s-${id}\" x=\"${(left / width) * 100}%\" y=\"${\n (top / height) * 100\n }%\" width=\"${((right - left) / width) * 100}%\" height=\"${\n ((bottom - top) / height) * 100\n }%\"><feDropShadow dx=\"${style.shadowOffset.width}\" dy=\"${\n style.shadowOffset.height\n }\" stdDeviation=\"${\n // According to the spec, we use the half of the blur radius as the standard\n // deviation for the filter.\n // > the image that would be generated by applying to the shadow a Gaussian\n // > blur with a standard deviation equal to half the blur radius\n // > https://www.w3.org/TR/css-backgrounds-3/#shadow-blur\n style.shadowRadius / 2\n }\" flood-color=\"${style.shadowColor}\" flood-opacity=\"1\"/></filter></defs>`\n}\n","import { buildXMLString } from '../utils'\n\nexport default function decoration(\n {\n width,\n left,\n top,\n ascender,\n clipPathId,\n }: {\n width: number\n left: number\n top: number\n ascender: number\n clipPathId?: string\n },\n style: Record<string, any>\n) {\n const {\n textDecorationColor,\n textDecorationStyle,\n textDecorationLine,\n fontSize,\n } = style\n if (!textDecorationLine || textDecorationLine === 'none') return ''\n\n // The UA should use such font-based information when choosing auto line thicknesses wherever appropriate.\n // https://drafts.csswg.org/css-text-decor-4/#text-decoration-thickness\n const height = Math.max(1, fontSize * 0.1)\n\n const y =\n textDecorationLine === 'line-through'\n ? top + ascender * 0.5\n : textDecorationLine === 'underline'\n ? top + ascender * 1.1\n : top\n\n const dasharray =\n textDecorationStyle === 'dashed'\n ? `${height * 1.2} ${height * 2}`\n : textDecorationStyle === 'dotted'\n ? `0 ${height * 2}`\n : undefined\n\n return buildXMLString('line', {\n x1: left,\n y1: y,\n x2: left + width,\n y2: y,\n stroke: textDecorationColor,\n 'stroke-width': height,\n 'stroke-dasharray': dasharray,\n 'stroke-linecap': textDecorationStyle === 'dotted' ? 'round' : 'square',\n 'clip-path': clipPathId ? `url(#${clipPathId})` : undefined,\n })\n}\n","/**\n * This module calculates the layout of a text string. Currently the only\n * supported inline node is text. All other nodes are using block layout.\n */\nimport type { LayoutContext } from './layout'\n\nimport getYoga from './yoga'\nimport { v, segment, wordSeparators, buildXMLString } from './utils'\nimport text, { container } from './builder/text'\nimport shadow from './builder/shadow'\nimport decoration from './builder/text-decoration'\n\n// @TODO: Support \"lang\" attribute to modify the locale\nconst locale = undefined\n\nexport default function* buildTextNodes(\n content: string,\n context: LayoutContext\n) {\n const Yoga = getYoga()\n\n const {\n parentStyle,\n inheritedStyle,\n parent,\n font,\n id,\n isInheritingTransform,\n debug,\n embedFont,\n graphemeImages,\n canLoadAdditionalAssets,\n } = context\n\n if (parentStyle.textTransform === 'uppercase') {\n content = content.toLocaleUpperCase(locale)\n } else if (parentStyle.textTransform === 'lowercase') {\n content = content.toLocaleLowerCase(locale)\n } else if (parentStyle.textTransform === 'capitalize') {\n content = segment(content, 'word')\n // For each word...\n .map((word) => {\n // ...split into graphemes...\n return segment(word, 'grapheme')\n .map((grapheme, index) => {\n // ...and make the first grapheme uppercase\n return index === 0 ? grapheme.toLocaleUpperCase(locale) : grapheme\n })\n .join('')\n })\n .join('')\n }\n\n const segmenter = v(\n parentStyle.wordBreak,\n {\n normal: 'word',\n 'break-all': 'grapheme',\n 'break-word': 'grapheme',\n 'keep-all': 'word',\n },\n 'word'\n )\n\n const words = segment(content, segmenter)\n\n // Create a container node for this text fragment.\n const textContainer = Yoga.Node.create()\n textContainer.setAlignItems(Yoga.ALIGN_BASELINE)\n if (parentStyle.textAlign === 'left') {\n textContainer.setJustifyContent(Yoga.JUSTIFY_FLEX_START)\n } else if (parentStyle.textAlign === 'center') {\n textContainer.setJustifyContent(Yoga.JUSTIFY_CENTER)\n } else if (parentStyle.textAlign === 'right') {\n textContainer.setJustifyContent(Yoga.JUSTIFY_FLEX_END)\n } else if (parentStyle.textAlign === 'justify') {\n textContainer.setJustifyContent(Yoga.JUSTIFY_SPACE_BETWEEN)\n }\n parent.insertChild(textContainer, parent.getChildCount())\n\n const {\n textAlign,\n textOverflow,\n whiteSpace,\n lineHeight,\n filter: cssFilter,\n _inheritedBackgroundClipTextPath,\n } = parentStyle\n\n const baseFontSize = parentStyle.fontSize as number\n\n // Get the correct font according to the container style.\n // https://www.w3.org/TR/CSS2/visudet.html\n let engine = font.getEngine(\n baseFontSize,\n lineHeight as number,\n parentStyle as any\n )\n\n // Yield segments that are missing a font.\n const wordsMissingFont = canLoadAdditionalAssets\n ? words.filter((word) => !engine.resolve(word))\n : []\n yield wordsMissingFont\n if (wordsMissingFont.length) {\n // Reload the engine with additional fonts.\n engine = font.getEngine(\n baseFontSize,\n lineHeight as number,\n parentStyle as any\n )\n }\n\n // Compute the layout.\n // @TODO: Use segments instead of words to properly support kerning.\n let lineWidths = []\n let baselines = []\n let lineSegmentNumber = []\n let wordsInLayout: (null | {\n x: number\n y: number\n width: number\n line: number\n lineIndex: number\n })[] = []\n\n // We can cache the measured width of each word as the measure function will be\n // called multiple times.\n const wordWidthCache = new Map<string, number>()\n const measureWithCache = (segments: string[]) => {\n let total = 0\n for (const s of segments) {\n if (wordWidthCache.has(s)) {\n total += wordWidthCache.get(s)\n continue\n }\n const width = engine.measure(s, parentStyle as any)\n wordWidthCache.set(s, width)\n total += width\n }\n return total\n }\n\n // Calculate the minimal possible width of the parent container so it don't\n // shrink below the content.\n let minWidth = 0\n let remainingSegment = []\n let extraWidth = 0\n for (const word of words) {\n let breakSegment = false\n const isImage = graphemeImages && graphemeImages[word]\n\n if (whiteSpace === 'pre') {\n // For `pre`, only break the line for `\\n`.\n breakSegment = word[0] === '\\n'\n } else if (whiteSpace !== 'nowrap') {\n // For `normal`, `pre-wrap`, we can wrap with any word separators or\n // images.\n if (isImage || wordSeparators.includes(word[0])) {\n breakSegment = true\n }\n }\n\n if (!breakSegment) {\n if (!wordSeparators.includes(word[0]) || !remainingSegment.length) {\n remainingSegment.push(word === '\\n' ? ' ' : word)\n }\n } else {\n if (whiteSpace === 'nowrap') {\n extraWidth +=\n measureWithCache(remainingSegment) + (parentStyle.fontSize as number)\n } else {\n minWidth = Math.max(minWidth, measureWithCache(remainingSegment))\n if (isImage) {\n minWidth = Math.max(minWidth, parentStyle.fontSize as number)\n }\n }\n remainingSegment = []\n }\n }\n minWidth = Math.max(minWidth, measureWithCache(remainingSegment) + extraWidth)\n const currentMinWidth = parent.getMinWidth()\n const currentMaxWidth = parent.getMaxWidth()\n const currentWidth = parent.getWidth()\n if (\n isNaN(currentWidth.value) &&\n (isNaN(currentMinWidth.value) ||\n (currentMinWidth.unit === 1 && currentMinWidth.value > minWidth))\n ) {\n // minWidth cannot be larger than maxWidth\n if (!isNaN(currentMaxWidth.value)) {\n if (currentMaxWidth.unit === 1) {\n minWidth = Math.min(minWidth, currentMaxWidth.value)\n } else {\n // @TODO: Support percentage units.\n }\n }\n parent.setMinWidth(minWidth)\n }\n if (typeof parentStyle.flexShrink === 'undefined') {\n parent.setFlexShrink(1)\n }\n\n const shouldAlwaysBreakLine =\n whiteSpace === 'pre-wrap' || whiteSpace === 'pre'\n\n textContainer.setMeasureFunc((width) => {\n let lines = 0\n let remainingSpace = ''\n let remainingSpaceWidth = 0\n let currentWidth = 0\n let maxWidth = 0\n let lineIndex = -1\n let height = 0\n let currentLineHeight = 0\n let currentBaselineOffset = 0\n\n lineWidths = []\n lineSegmentNumber = [0]\n\n // We naively implement the width calculation without proper kerning.\n // @TODO: Support different writing modes.\n // @TODO: Support RTL languages.\n for (let i = 0; i < words.length; i++) {\n const word = words[i]\n\n // A character is a word separator if `white-space` is not `pre`.\n if (\n !shouldAlwaysBreakLine &&\n wordSeparators.includes(\n // It's possible that the segment contains multiple separate words such\n // as ` `. We can just use the first character to detect.\n word[0]\n )\n ) {\n // Since `white-space` is not `pre`, multiple whitespaces are considered\n // as one.\n if (!remainingSpace) {\n remainingSpace = ' '\n }\n remainingSpaceWidth = measureWithCache([remainingSpace])\n wordsInLayout[i] = null\n } else {\n const forceBreak = shouldAlwaysBreakLine && word === '\\n'\n const w = forceBreak\n ? 0\n : graphemeImages && graphemeImages[word]\n ? (parentStyle.fontSize as number)\n : measureWithCache([word])\n\n // This is the start of the line, we can ignore all spaces here.\n if (!currentWidth) {\n remainingSpace = ''\n remainingSpaceWidth = 0\n }\n\n const allowedToPutAtBeginning =\n remainingSpaceWidth || ',.!?:-@)>]}%#'.indexOf(word[0]) < 0\n const allowedToJustify = !currentWidth || !!remainingSpaceWidth\n\n if (\n forceBreak ||\n (i &&\n allowedToPutAtBeginning &&\n currentWidth + remainingSpaceWidth + w > width &&\n whiteSpace !== 'nowrap' &&\n whiteSpace !== 'pre')\n ) {\n // Start a new line, spaces can be ignored.\n lineWidths.push(currentWidth)\n baselines.push(currentBaselineOffset)\n lines++\n height += currentLineHeight\n currentWidth = w\n currentLineHeight = w ? engine.glyphHeight(word) : 0\n currentBaselineOffset = w ? engine.baseline(word) : 0\n lineSegmentNumber.push(1)\n lineIndex = -1\n\n // If it's neturally breaked, we update the max width.\n // Since if there are multiple lines, the width should fit the\n // container.\n if (!forceBreak) {\n maxWidth = Math.max(maxWidth, width)\n }\n } else {\n // It fits into the current line.\n currentWidth += remainingSpaceWidth + w\n const glyphHeight = engine.glyphHeight(word)\n if (glyphHeight > currentLineHeight) {\n // Use the baseline of the heighest segment as the baseline of the line.\n currentLineHeight = glyphHeight\n currentBaselineOffset = engine.baseline(word)\n }\n if (allowedToJustify) {\n lineSegmentNumber[lineSegmentNumber.length - 1]++\n }\n }\n\n remainingSpace = ''\n remainingSpaceWidth = 0\n\n if (allowedToJustify) {\n lineIndex++\n }\n\n maxWidth = Math.max(maxWidth, currentWidth)\n wordsInLayout[i] = {\n y: height,\n x: currentWidth - w,\n width: w,\n line: lines,\n lineIndex,\n }\n }\n }\n if (currentWidth) {\n lines++\n lineWidths.push(currentWidth)\n baselines.push(currentBaselineOffset)\n height += currentLineHeight\n }\n\n // @TODO: Support `line-height`.\n return { width: maxWidth, height }\n })\n\n const [x, y] = yield\n\n let result = ''\n let backgroundClipDef = ''\n\n const clipPathId = inheritedStyle._inheritedClipPathId as string | undefined\n const {\n left: containerLeft,\n top: containerTop,\n width: containerWidth,\n height: containerHeight,\n } = textContainer.getComputedLayout()\n const parentContainerInnerWidth =\n parent.getComputedWidth() -\n parent.getComputedPadding(Yoga.EDGE_LEFT) -\n parent.getComputedPadding(Yoga.EDGE_RIGHT) -\n parent.getComputedBorder(Yoga.EDGE_LEFT) -\n parent.getComputedBorder(Yoga.EDGE_RIGHT)\n\n // Attach offset to the current node.\n const left = x + containerLeft\n const top = y + containerTop\n\n const { matrix, opacity } = container(\n {\n left: containerLeft,\n top: containerTop,\n width: containerWidth,\n height: containerHeight,\n isInheritingTransform,\n },\n parentStyle\n )\n\n let filter = ''\n if (parentStyle.textShadowOffset) {\n filter = shadow(\n {\n width: containerWidth,\n height: containerHeight,\n id,\n },\n {\n shadowColor: parentStyle.textShadowColor,\n shadowOffset: parentStyle.textShadowOffset,\n shadowRadius: parentStyle.textShadowRadius,\n }\n )\n }\n\n let decorationShape = ''\n let mergedPath = ''\n let extra = ''\n let skippedLine = -1\n let ellipsisWidth = textOverflow === 'ellipsis' ? measureWithCache(['…']) : 0\n let spaceWidth = textOverflow === 'ellipsis' ? measureWithCache([' ']) : 0\n let decorationLines: Record<number, null | number[]> = {}\n\n for (let i = 0; i < words.length; i++) {\n // Skip whitespace.\n if (!wordsInLayout[i]) continue\n const layout = wordsInLayout[i]\n\n let word = words[i]\n let path: string | null = null\n\n const image = graphemeImages ? graphemeImages[word] : null\n\n let topOffset = layout.y\n let leftOffset = layout.x\n const width = layout.width\n const line = layout.line\n\n if (line === skippedLine) {\n continue\n }\n\n // When `text-align` is `justify`, the width of the line will be adjusted.\n let extendedWidth = false\n\n if (lineWidths.length > 1) {\n // Calculate alignment. Note that for flexbox, there is only text\n // alignment when the container is multi-line.\n const remainingWidth = containerWidth - lineWidths[line]\n if (textAlign === 'right' || textAlign === 'end') {\n leftOffset += remainingWidth\n } else if (textAlign === 'center') {\n leftOffset += remainingWidth / 2\n } else if (textAlign === 'justify') {\n // Don't justify the last line.\n if (line < lineWidths.length - 1) {\n const segments = lineSegmentNumber[line]\n const gutter = segments > 1 ? remainingWidth / (segments - 1) : 0\n leftOffset += gutter * layout.lineIndex\n extendedWidth = true\n }\n }\n }\n\n if (!decorationLines[line]) {\n decorationLines[line] = [\n leftOffset,\n extendedWidth ? containerWidth : lineWidths[line],\n ]\n }\n\n if (textOverflow === 'ellipsis') {\n if (lineWidths[line] > parentContainerInnerWidth) {\n if (\n layout.x + width + ellipsisWidth + spaceWidth >\n parentContainerInnerWidth\n ) {\n const chars = segment(word, 'grapheme')\n let subset = ''\n let resolvedWidth = 0\n for (const char of chars) {\n const w = layout.x + measureWithCache([subset + char])\n if (\n // Keep at least one character:\n // > The first character or atomic inline-level element on a line\n // must be clipped rather than ellipsed.\n // https://drafts.csswg.org/css-overflow/#text-overflow\n subset &&\n w + ellipsisWidth > parentContainerInnerWidth\n ) {\n break\n }\n subset += char\n resolvedWidth = w\n }\n word = subset + '…'\n skippedLine = line\n decorationLines[line][1] = resolvedWidth\n }\n }\n }\n\n const baselineOfLine = baselines[line]\n const baselineOfWord = engine.baseline(word)\n const heightOfWord = engine.glyphHeight(word)\n const baselineDelta = baselineOfLine - baselineOfWord\n\n if (image) {\n // For images, we remove the baseline offset.\n topOffset += 0\n } else if (embedFont) {\n path = engine.getSVG(word, {\n ...parentStyle,\n left: left + leftOffset,\n // Since we need to pass the baseline position, add the ascender to the top.\n top: top + topOffset + baselineOfWord + baselineDelta,\n letterSpacing: parentStyle.letterSpacing,\n } as any)\n\n if (debug) {\n extra +=\n buildXMLString('rect', {\n x: left + leftOffset,\n y: top + topOffset + baselineDelta,\n width: layout.width,\n height: heightOfWord,\n fill: 'transparent',\n stroke: '#575eff',\n 'stroke-width': 1,\n transform: matrix ? matrix : undefined,\n 'clip-path': clipPathId ? `url(#${clipPathId})` : undefined,\n }) +\n // Baseline\n buildXMLString('line', {\n x1: left + leftOffset,\n x2: left + leftOffset + layout.width,\n y1: top + topOffset + baselineDelta + baselineOfWord,\n y2: top + topOffset + baselineDelta + baselineOfWord,\n stroke: '#14c000',\n 'stroke-width': 1,\n transform: matrix ? matrix : undefined,\n 'clip-path': clipPathId ? `url(#${clipPathId})` : undefined,\n })\n }\n } else {\n // We need manually add the font ascender height to ensure it starts\n // at the baseline because <text>'s alignment baseline is set to `hanging`\n // by default and supported to change in SVG 1.1.\n topOffset += baselineOfWord + baselineDelta\n }\n\n // Get the decoration shape.\n if (parentStyle.textDecorationLine) {\n // If it's the last word in the current line.\n if (line !== wordsInLayout[i + 1]?.line || skippedLine === line) {\n const deco = decorationLines[line]\n if (deco && !deco[2]) {\n decorationShape += decoration(\n {\n left: left + deco[0],\n top: top + heightOfWord * +line,\n width: deco[1],\n ascender: engine.baseline(word),\n clipPathId,\n },\n parentStyle\n )\n deco[2] = 1\n }\n }\n }\n\n if (path !== null) {\n mergedPath += path + ' '\n } else {\n const [t, shape] = text(\n {\n content: word,\n filter,\n id,\n left: left + leftOffset,\n top: top + topOffset,\n width,\n height: heightOfWord,\n matrix,\n opacity,\n image,\n clipPathId,\n debug,\n shape: !!_inheritedBackgroundClipTextPath,\n decorationShape,\n },\n parentStyle\n )\n result += t\n backgroundClipDef += shape\n decorationShape = ''\n }\n }\n\n // Embed the font as path.\n if (mergedPath) {\n const p =\n parentStyle.color !== 'transparent' && opacity !== 0\n ? buildXMLString('path', {\n fill: parentStyle.color,\n d: mergedPath,\n transform: matrix ? matrix : undefined,\n opacity: opacity !== 1 ? opacity : undefined,\n 'clip-path': clipPathId ? `url(#${clipPathId})` : undefined,\n\n style: cssFilter ? `filter:${cssFilter}` : undefined,\n })\n : ''\n\n if (!!_inheritedBackgroundClipTextPath) {\n backgroundClipDef = buildXMLString('path', {\n d: mergedPath,\n transform: matrix ? matrix : undefined,\n })\n }\n\n result +=\n (filter ? `${filter}<g filter=\"url(#satori_s-${id})\">` : '') +\n p +\n decorationShape +\n (filter ? '</g>' : '') +\n extra\n }\n\n // Attach information to the parent node.\n if (backgroundClipDef) {\n ;(parentStyle._inheritedBackgroundClipTextPath as any).value +=\n backgroundClipDef\n }\n\n return result\n}\n","// Copyright (c) 2014 Rafael Caricio. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nvar GradientParser = GradientParser || {}\n\nGradientParser.parse = (function () {\n var tokens = {\n linearGradient: /^(\\-(webkit|o|ms|moz)\\-)?(linear\\-gradient)/i,\n repeatingLinearGradient:\n /^(\\-(webkit|o|ms|moz)\\-)?(repeating\\-linear\\-gradient)/i,\n radialGradient: /^(\\-(webkit|o|ms|moz)\\-)?(radial\\-gradient)/i,\n repeatingRadialGradient:\n /^(\\-(webkit|o|ms|moz)\\-)?(repeating\\-radial\\-gradient)/i,\n sideOrCorner:\n /^to (left (top|bottom)|right (top|bottom)|top (left|right)|bottom (left|right)|left|right|top|bottom)/i,\n extentKeywords:\n /^(closest\\-side|closest\\-corner|farthest\\-side|farthest\\-corner|contain|cover)/,\n positionKeywords: /^(left|center|right|top|bottom)/i,\n pixelValue: /^(-?(([0-9]*\\.[0-9]+)|([0-9]+\\.?)))px/,\n percentageValue: /^(-?(([0-9]*\\.[0-9]+)|([0-9]+\\.?)))\\%/,\n emValue: /^(-?(([0-9]*\\.[0-9]+)|([0-9]+\\.?)))em/,\n angleValue: /^(-?(([0-9]*\\.[0-9]+)|([0-9]+\\.?)))deg/,\n startCall: /^\\(/,\n endCall: /^\\)/,\n comma: /^,/,\n hexColor: /^\\#([0-9a-fA-F]+)/,\n literalColor: /^([a-zA-Z]+)/,\n rgbColor: /^rgb/i,\n rgbaColor: /^rgba/i,\n number: /^(([0-9]*\\.[0-9]+)|([0-9]+\\.?))/,\n }\n\n var input = ''\n\n function error(msg) {\n var err = new Error(input + ': ' + msg)\n err.source = input\n throw err\n }\n\n function getAST() {\n var ast = matchListDefinitions()\n\n if (input.length > 0) {\n error('Invalid input not EOF')\n }\n\n return ast\n }\n\n function matchListDefinitions() {\n return matchListing(matchDefinition)\n }\n\n function matchDefinition() {\n return (\n matchGradient(\n 'linear-gradient',\n tokens.linearGradient,\n matchLinearOrientation\n ) ||\n matchGradient(\n 'repeating-linear-gradient',\n tokens.repeatingLinearGradient,\n matchLinearOrientation\n ) ||\n matchGradient(\n 'radial-gradient',\n tokens.radialGradient,\n matchListRadialOrientations\n ) ||\n matchGradient(\n 'repeating-radial-gradient',\n tokens.repeatingRadialGradient,\n matchListRadialOrientations\n )\n )\n }\n\n function matchGradient(gradientType, pattern, orientationMatcher) {\n return matchCall(pattern, function (captures) {\n var orientation = orientationMatcher()\n if (orientation) {\n if (!scan(tokens.comma)) {\n error('Missing comma before color stops')\n }\n }\n\n return {\n type: gradientType,\n orientation: orientation,\n colorStops: matchListing(matchColorStop),\n }\n })\n }\n\n function matchCall(pattern, callback) {\n var captures = scan(pattern)\n\n if (captures) {\n if (!scan(tokens.startCall)) {\n error('Missing (')\n }\n\n var result = callback(captures)\n\n if (!scan(tokens.endCall)) {\n error('Missing )')\n }\n\n return result\n }\n }\n\n function matchLinearOrientation() {\n return matchSideOrCorner() || matchAngle()\n }\n\n function matchSideOrCorner() {\n return match('directional', tokens.sideOrCorner, 1)\n }\n\n function matchAngle() {\n return match('angular', tokens.angleValue, 1)\n }\n\n function matchListRadialOrientations() {\n var radialOrientations,\n radialOrientation = matchRadialOrientation(),\n lookaheadCache\n\n if (radialOrientation) {\n radialOrientations = []\n radialOrientations.push(radialOrientation)\n\n lookaheadCache = input\n if (scan(tokens.comma)) {\n radialOrientation = matchRadialOrientation()\n if (radialOrientation) {\n radialOrientations.push(radialOrientation)\n } else {\n input = lookaheadCache\n }\n }\n }\n\n return radialOrientations\n }\n\n function matchRadialOrientation() {\n var radialType = matchCircle() || matchEllipse()\n\n if (radialType) {\n radialType.at = matchAtPosition()\n } else {\n var extent = matchExtentKeyword()\n if (extent) {\n radialType = extent\n var positionAt = matchAtPosition()\n if (positionAt) {\n radialType.at = positionAt\n }\n } else {\n var defaultPosition = matchPositioning()\n if (defaultPosition) {\n radialType = {\n type: 'default-radial',\n at: defaultPosition,\n }\n }\n }\n }\n\n return radialType\n }\n\n function matchCircle() {\n var circle = match('shape', /^(circle)/i, 0)\n\n if (circle) {\n circle.style = matchLength() || matchExtentKeyword()\n }\n\n return circle\n }\n\n function matchEllipse() {\n var ellipse = match('shape', /^(ellipse)/i, 0)\n\n if (ellipse) {\n ellipse.style = matchDistance() || matchExtentKeyword()\n }\n\n return ellipse\n }\n\n function matchExtentKeyword() {\n return match('extent-keyword', tokens.extentKeywords, 1)\n }\n\n function matchAtPosition() {\n if (match('position', /^at/, 0)) {\n var positioning = matchPositioning()\n\n if (!positioning) {\n error('Missing positioning value')\n }\n\n return positioning\n }\n }\n\n function matchPositioning() {\n var location = matchCoordinates()\n\n if (location.x || location.y) {\n return {\n type: 'position',\n value: location,\n }\n }\n }\n\n function matchCoordinates() {\n return {\n x: matchDistance(),\n y: matchDistance(),\n }\n }\n\n function matchListing(matcher) {\n var captures = matcher(),\n result = []\n\n if (captures) {\n result.push(captures)\n while (scan(tokens.comma)) {\n captures = matcher()\n if (captures) {\n result.push(captures)\n } else {\n error('One extra comma')\n }\n }\n }\n\n return result\n }\n\n function matchColorStop() {\n var color = matchColor()\n\n if (!color) {\n error('Expected color definition')\n }\n\n color.length = matchDistance()\n return color\n }\n\n function matchColor() {\n return (\n matchHexColor() ||\n matchRGBAColor() ||\n matchRGBColor() ||\n matchLiteralColor()\n )\n }\n\n function matchLiteralColor() {\n return match('literal', tokens.literalColor, 0)\n }\n\n function matchHexColor() {\n return match('hex', tokens.hexColor, 1)\n }\n\n function matchRGBColor() {\n return matchCall(tokens.rgbColor, function () {\n return {\n type: 'rgb',\n value: matchListing(matchNumber),\n }\n })\n }\n\n function matchRGBAColor() {\n return matchCall(tokens.rgbaColor, function () {\n return {\n type: 'rgba',\n value: matchListing(matchNumber),\n }\n })\n }\n\n function matchNumber() {\n return scan(tokens.number)[1]\n }\n\n function matchDistance() {\n return (\n match('%', tokens.percentageValue, 1) ||\n matchPositionKeyword() ||\n matchLength()\n )\n }\n\n function matchPositionKeyword() {\n return match('position-keyword', tokens.positionKeywords, 1)\n }\n\n function matchLength() {\n return match('px', tokens.pixelValue, 1) || match('em', tokens.emValue, 1)\n }\n\n function match(type, pattern, captureIndex) {\n var captures = scan(pattern)\n if (captures) {\n return {\n type: type,\n value: captures[captureIndex],\n }\n }\n }\n\n function scan(regexp) {\n var captures, blankCaptures\n\n blankCaptures = /^[\\n\\r\\t\\s]+/.exec(input)\n if (blankCaptures) {\n consume(blankCaptures[0].length)\n }\n\n captures = regexp.exec(input)\n if (captures) {\n consume(captures[0].length)\n }\n\n return captures\n }\n\n function consume(size) {\n input = input.substr(size)\n }\n\n return function (code) {\n input = code.toString()\n return getAST()\n }\n})()\n\nexport default GradientParser\n","import CssDimension from '../vendor/parse-css-dimension'\nimport { buildXMLString } from '../utils'\n\nimport gradient from '../vendor/gradient-parser'\n\ninterface Background {\n attachment: string\n color?: string\n clip: string\n image: string\n origin: string\n position: string\n size: string\n repeat: string\n}\n\nfunction resolveColorFromStop(stop) {\n if (stop.type === 'literal') return stop.value\n if (stop.type === 'hex') return `#${stop.value}`\n if (stop.type === 'rgb') return `rgb(${stop.value.join(',')})`\n if (stop.type === 'rgba') return `rgba(${stop.value.join(',')})`\n return 'transparent'\n}\n\nfunction toAbsoluteValue(v: string | number, base: number) {\n if (typeof v === 'string' && v.endsWith('%')) {\n return (base * parseFloat(v)) / 100\n }\n return +v\n}\n\nfunction parseLengthPairs(\n str: string,\n {\n x,\n y,\n defaultX,\n defaultY,\n }: {\n x: number\n y: number\n defaultX: number | string\n defaultY: number | string\n }\n) {\n return (\n str\n ? str\n .split(' ')\n .map((value) => {\n try {\n const parsed = new CssDimension(value)\n return parsed.type === 'length' || parsed.type === 'number'\n ? parsed.value\n : parsed.value + parsed.unit\n } catch (e) {\n return null\n }\n })\n .filter((v) => v !== null)\n : [defaultX, defaultY]\n ).map((v, index) => toAbsoluteValue(v, [x, y][index]))\n}\n\nfunction normalizeStops(totalLength: number, colorStops: any[]) {\n // Resolve the color stops based on the spec:\n // https://drafts.csswg.org/css-images/#color-stop-syntax\n const stops = []\n for (const stop of colorStops) {\n const color = resolveColorFromStop(stop)\n if (!stops.length) {\n // First stop, ensure it's at the start.\n stops.push({\n offset: 0,\n color,\n })\n\n if (typeof stop.length === 'undefined') continue\n if (stop.length.value === '0') continue\n }\n\n // All offsets are relative values (0-1) in SVG.\n const offset =\n typeof stop.length === 'undefined'\n ? undefined\n : stop.length.type === '%'\n ? stop.length.value / 100\n : stop.length.value / totalLength\n\n stops.push({\n offset,\n color,\n })\n }\n if (!stops.length) {\n stops.push({\n offset: 0,\n color: 'transparent',\n })\n }\n // Last stop, ensure it's at the end.\n const lastStop = stops[stops.length - 1]\n if (lastStop.offset !== 1) {\n if (typeof lastStop.offset === 'undefined') {\n lastStop.offset = 1\n } else {\n stops.push({\n offset: 1,\n color: lastStop.color,\n })\n }\n }\n\n let previousStop = 0\n let nextStop = 1\n // Evenly distribute the missing stop offsets.\n for (let i = 0; i < stops.length; i++) {\n if (typeof stops[i].offset === 'undefined') {\n // Find the next stop that has an offset.\n if (nextStop < i) nextStop = i\n while (typeof stops[nextStop].offset === 'undefined') nextStop++\n\n stops[i].offset =\n ((stops[nextStop].offset - stops[previousStop].offset) /\n (nextStop - previousStop)) *\n (i - previousStop) +\n stops[previousStop].offset\n } else {\n previousStop = i\n }\n }\n\n return stops\n}\n\nexport default function backgroundImage(\n { id, width, height }: { id: string; width: number; height: number },\n { image, size, position, repeat }: Background\n): string[] {\n // Default to `repeat`.\n repeat = repeat || 'repeat'\n\n const repeatX = repeat === 'repeat-x' || repeat === 'repeat'\n const repeatY = repeat === 'repeat-y' || repeat === 'repeat'\n\n const dimensions = parseLengthPairs(size, {\n x: width,\n y: height,\n defaultX: width,\n defaultY: height,\n })\n const offsets = parseLengthPairs(position, {\n x: width,\n y: height,\n defaultX: 0,\n defaultY: 0,\n })\n\n if (image.startsWith('linear-gradient(')) {\n const parsed = gradient.parse(image)[0]\n\n // Calculate the direction.\n let x1, y1, x2, y2\n if (parsed.orientation.type === 'directional') {\n ;[x1, y1, x2, y2] = {\n top: [0, 1, 0, 0],\n bottom: [0, 0, 0, 1],\n left: [1, 0, 0, 0],\n right: [0, 0, 1, 0],\n }[parsed.orientation.value]\n } else if (parsed.orientation.type === 'angular') {\n const angle = (+parsed.orientation.value / 180) * Math.PI - Math.PI / 2\n const c = Math.cos(angle)\n const s = Math.sin(angle)\n\n x1 = 0\n y1 = 0\n x2 = c\n y2 = s\n if (x2 < 0) {\n x1 -= x2\n x2 = 0\n }\n if (y2 < 0) {\n y1 -= y2\n y2 = 0\n }\n }\n\n const stops = normalizeStops(width, parsed.colorStops)\n\n return [\n `satori_bi${id}`,\n `<linearGradient id=\"satori_bi${id}\" x1=\"${x1}\" y1=\"${y1}\" x2=\"${x2}\" y2=\"${y2}\">${stops\n .map(\n (stop) =>\n `<stop offset=\"${stop.offset * 100}%\" stop-color=\"${stop.color}\"/>`\n )\n .join('')}</linearGradient>`,\n ]\n }\n\n if (image.startsWith('radial-gradient(')) {\n const parsed = gradient.parse(image)[0]\n const orientation = parsed.orientation[0]\n const [xDelta, yDelta] = dimensions\n\n let shape = 'circle'\n let cx: number = xDelta / 2\n let cy: number = yDelta / 2\n\n if (orientation.type === 'shape') {\n shape = orientation.value\n if (!orientation.at) {\n // Defaults to center.\n } else if (orientation.at.type === 'position') {\n cx = orientation.at.value.x.value\n cy = orientation.at.value.y.value\n } else {\n throw new Error(\n 'orientation.at.type not implemented: ' + orientation.at.type\n )\n }\n } else {\n throw new Error('orientation.type not implemented: ' + orientation.type)\n }\n\n const stops = normalizeStops(width, parsed.colorStops)\n\n const gradientId = `satori_radial_${id}`\n const patternId = `satori_pattern_${id}`\n\n // We currently only support `farthest-corner`:\n // https://developer.mozilla.org/en-US/docs/Web/CSS/gradient/radial-gradient()#values\n const spread: Record<string, number> = {}\n\n // Farest corner.\n const fx = Math.max(Math.abs(xDelta - cx), Math.abs(cx))\n const fy = Math.max(Math.abs(yDelta - cy), Math.abs(cy))\n if (shape === 'circle') {\n spread.r = Math.sqrt(fx * fx + fy * fy)\n } else if (shape === 'ellipse') {\n // Spec: https://drafts.csswg.org/css-images/#typedef-size\n // Get the aspect ratio of the closest-side size.\n const ratio = fy !== 0 ? fx / fy : 1\n\n // fx^2/a^2 + fy^2/b^2 = 1\n // fx^2/(b*ratio)^2 + fy^2/b^2 = 1\n // (fx^2+fy^2*ratio^2) = (b*ratio)^2\n // b = sqrt(fx^2+fy^2*ratio^2)/ratio\n spread.ry = Math.sqrt(fx * fx + fy * fy * ratio * ratio) / ratio\n spread.rx = spread.ry * ratio\n }\n\n // TODO: check for repeat-x/repeat-y\n const defs = buildXMLString(\n 'pattern',\n {\n id: patternId,\n x: offsets[0],\n y: offsets[1],\n width: repeatX ? xDelta : '100%',\n height: repeatY ? yDelta : '100%',\n patternUnits: 'userSpaceOnUse',\n },\n buildXMLString(\n 'radialGradient',\n {\n id: gradientId,\n },\n stops\n .map((stop) =>\n buildXMLString('stop', {\n offset: stop.offset,\n 'stop-color': stop.color,\n })\n )\n .join('')\n ) +\n buildXMLString(shape, {\n cx: cx,\n cy: cy,\n width: xDelta,\n height: yDelta,\n ...spread,\n fill: `url(#${gradientId})`,\n })\n )\n\n const result = [patternId, defs]\n return result\n }\n\n if (image.startsWith('url(')) {\n const src = image.slice(4, -1)\n return [\n `satori_bi${id}`,\n buildXMLString(\n 'pattern',\n {\n id: `satori_bi${id}`,\n patternContentUnits: 'userSpaceOnUse',\n patternUnits: 'userSpaceOnUse',\n x: offsets[0],\n y: offsets[1],\n width: repeatX ? dimensions[0] : '100%',\n height: repeatY ? dimensions[1] : '100%',\n },\n buildXMLString('image', {\n x: 0,\n y: 0,\n width: dimensions[0],\n height: dimensions[1],\n href: src,\n })\n ),\n ]\n }\n}\n","/**\n * CSS border radius to SVG path.\n */\n\nfunction resolveSize(a: number, b: number, limit: number) {\n if (limit < a + b) {\n if (limit / 2 < a && limit / 2 < b) {\n a = b = limit / 2\n } else if (limit / 2 < a) {\n a = limit - b\n } else if (limit / 2 < b) {\n b = limit - a\n }\n }\n return [a, b]\n}\n\nexport default function radius(\n {\n left,\n top,\n width,\n height,\n }: {\n left: number\n top: number\n width: number\n height: number\n },\n style: Record<string, number>\n) {\n let {\n borderTopLeftRadius,\n borderTopRightRadius,\n borderBottomLeftRadius,\n borderBottomRightRadius,\n } = style\n\n borderTopLeftRadius = Math.min(borderTopLeftRadius || 0, width, height)\n borderTopRightRadius = Math.min(borderTopRightRadius || 0, width, height)\n borderBottomLeftRadius = Math.min(borderBottomLeftRadius || 0, width, height)\n borderBottomRightRadius = Math.min(\n borderBottomRightRadius || 0,\n width,\n height\n )\n\n if (\n !borderTopLeftRadius &&\n !borderTopRightRadius &&\n !borderBottomLeftRadius &&\n !borderBottomRightRadius\n ) {\n return ''\n }\n\n // Limit the radius size.\n ;[borderTopLeftRadius, borderTopRightRadius] = resolveSize(\n borderTopLeftRadius,\n borderTopRightRadius,\n width\n )\n ;[borderTopLeftRadius, borderBottomLeftRadius] = resolveSize(\n borderTopLeftRadius,\n borderBottomLeftRadius,\n height\n )\n ;[borderTopRightRadius, borderBottomRightRadius] = resolveSize(\n borderTopRightRadius,\n borderBottomRightRadius,\n height\n )\n ;[borderBottomLeftRadius, borderBottomRightRadius] = resolveSize(\n borderBottomLeftRadius,\n borderBottomRightRadius,\n width\n )\n\n // Generate the path (GitHub Copilot wrote these for me).\n return `M${left + borderTopLeftRadius},${top} h${\n width - borderTopLeftRadius - borderTopRightRadius\n } a${borderTopRightRadius},${borderTopRightRadius} 0 0 1 ${borderTopRightRadius},${borderTopRightRadius} v${\n height - borderTopRightRadius - borderBottomRightRadius\n } a${borderBottomRightRadius},${borderBottomRightRadius} 0 0 1 ${-borderBottomRightRadius},${borderBottomRightRadius} h${\n borderBottomRightRadius + borderBottomLeftRadius - width\n } a${borderBottomLeftRadius},${borderBottomLeftRadius} 0 0 1 ${-borderBottomLeftRadius},${-borderBottomLeftRadius} v${\n borderBottomLeftRadius + borderTopLeftRadius - height\n } a${borderTopLeftRadius},${borderTopLeftRadius} 0 0 1 ${borderTopLeftRadius},${-borderTopLeftRadius}`\n}\n","/**\n * Generate clip path for the given element.\n */\n\nimport { buildXMLString } from '../utils'\n\nexport default function overflow(\n {\n left,\n top,\n width,\n height,\n path,\n id,\n }: {\n left: number\n top: number\n width: number\n height: number\n path: string\n id: string\n },\n style: Record<string, string | number>\n) {\n if (style.overflow !== 'hidden') {\n return ''\n }\n\n if (path) {\n // <clipPath id=\"myClip\"><circle cx=\"40\" cy=\"35\" r=\"35\" /></clipPath>\n return buildXMLString(\n 'clipPath',\n {\n id: `satori_cp-${id}`,\n 'clip-path': style._inheritedClipPathId\n ? `url(#${style._inheritedClipPathId})`\n : undefined,\n },\n buildXMLString('path', {\n x: left,\n y: top,\n width,\n height,\n d: path,\n })\n )\n }\n return buildXMLString(\n 'clipPath',\n {\n id: `satori_cp-${id}`,\n 'clip-path': style._inheritedClipPathId\n ? `url(#${style._inheritedClipPathId})`\n : undefined,\n },\n buildXMLString('rect', {\n x: left,\n y: top,\n width,\n height,\n })\n )\n}\n","import type { ParsedTransformOrigin } from '../transform-origin'\n\nimport backgroundImage from './background-image'\nimport radius from './border-radius'\nimport shadow from './shadow'\nimport transform from './transform'\nimport overflow from './overflow'\nimport { buildXMLString } from '../utils'\n\nexport default function rect(\n {\n id,\n left,\n top,\n width,\n height,\n isInheritingTransform,\n debug,\n }: {\n id: string\n left: number\n top: number\n width: number\n height: number\n isInheritingTransform: boolean\n debug?: boolean\n },\n style: Record<string, number | string>\n) {\n if (style.display === 'none') return ''\n\n let type = 'rect'\n let stroke = 'transparent'\n let strokeWidth = 0\n let matrix = ''\n let defs = ''\n let fills: string[] = []\n let opacity = 1\n let extra = ''\n\n if (style.backgroundColor) {\n fills.push(style.backgroundColor as string)\n }\n\n if (style.borderWidth) {\n strokeWidth = style.borderWidth as number\n stroke = style.borderColor as string\n }\n\n if (style.opacity) {\n opacity = +style.opacity\n }\n\n if (style.transform) {\n matrix = transform(\n {\n left,\n top,\n width,\n height,\n },\n style.transform as unknown as number[],\n isInheritingTransform,\n style.transformOrigin as ParsedTransformOrigin | undefined\n )\n }\n\n let backgroundShapes = ''\n if (style.backgroundImage) {\n const backgrounds: string[] = (style.backgroundImage as any)\n .map((background, index) =>\n backgroundImage({ id: id + '_' + index, width, height }, background)\n )\n .filter(Boolean)\n for (const background of backgrounds) {\n fills.push(`url(#${background[0]})`)\n defs += background[1]\n if (background[2]) {\n backgroundShapes += background[2]\n }\n }\n }\n\n const path = radius(\n { left, top, width, height },\n style as Record<string, number>\n )\n if (path) {\n type = 'path'\n }\n\n const clip = overflow(\n { left, top, width, height, path, id },\n style as Record<string, number>\n )\n const clipPathId = style._inheritedClipPathId as number | undefined\n\n const filter = shadow({ width, height, id }, style)\n\n if (debug) {\n extra = buildXMLString('rect', {\n x: left,\n y: top,\n width,\n height,\n fill: 'transparent',\n stroke: '#ff5757',\n 'stroke-width': 1,\n transform: matrix || undefined,\n 'clip-path': clipPathId ? `url(#${clipPathId})` : undefined,\n })\n }\n\n if (!fills.length) fills.push('transparent')\n\n const { backgroundClip, filter: cssFilter } = style\n\n // Each background generates a new rectangle.\n // @TODO: Not sure if this is the best way to do it, maybe <pattern> with\n // multiple <image>s is better.\n let shape = fills\n .map((fill, i) => {\n if (fill === 'transparent' && !(i === fills.length - 1 && strokeWidth)) {\n return ''\n }\n\n const hasStroke =\n i === fills.length - 1 && strokeWidth && backgroundClip !== 'text'\n return buildXMLString(type, {\n x: left,\n y: top,\n width,\n height,\n fill,\n stroke: hasStroke ? stroke : undefined,\n 'stroke-width': hasStroke ? strokeWidth : undefined,\n d: path ? path : undefined,\n transform: matrix ? matrix : undefined,\n 'clip-path':\n backgroundClip === 'text'\n ? `url(#satori_bct-${id})`\n : clipPathId\n ? `url(#${clipPathId})`\n : undefined,\n style: cssFilter ? `filter:${cssFilter}` : undefined,\n })\n })\n .join('')\n\n // When using `background-clip: text`, we need to draw the extra border.\n if (backgroundClip === 'text' && strokeWidth) {\n shape =\n buildXMLString(type, {\n x: left,\n y: top,\n width,\n height,\n fill: 'transparent',\n stroke,\n 'stroke-width': strokeWidth,\n d: path ? path : undefined,\n transform: matrix ? matrix : undefined,\n 'clip-path': clipPathId ? `url(#${clipPathId})` : undefined,\n }) + shape\n }\n\n return (\n (defs ? `<defs>${defs}</defs>` : '') +\n clip +\n (filter ? `${filter}<g filter=\"url(#satori_s-${id})\">` : '') +\n (opacity !== 1 ? `<g opacity=\"${opacity}\">` : '') +\n (backgroundShapes || shape) +\n (opacity !== 1 ? `</g>` : '') +\n (filter ? '</g>' : '') +\n extra\n )\n}\n","import type { ParsedTransformOrigin } from '../transform-origin'\n\nimport { buildXMLString } from '../utils'\nimport radius from './border-radius'\nimport shadow from './shadow'\nimport transform from './transform'\n\nexport default function image(\n {\n id,\n left,\n top,\n width,\n height,\n src,\n debug,\n isInheritingTransform,\n }: {\n id: string\n left: number\n top: number\n width: number\n height: number\n src: string\n isInheritingTransform: boolean\n debug?: boolean\n },\n style: Record<string, number | string>\n) {\n if (style.display === 'none') return ''\n\n let clip = ''\n let opacity = 1\n let matrix = ''\n\n const preserveAspectRatio =\n style.objectFit === 'contain'\n ? 'xMidYMid'\n : style.objectFit === 'cover'\n ? 'xMidYMid slice'\n : 'none'\n\n const path = radius(\n { left, top, width, height },\n style as Record<string, number>\n )\n\n const clipPathId = style._inheritedClipPathId as number | undefined\n if (path) {\n clip = buildXMLString(\n 'clipPath',\n {\n id: `satori_c-${id}`,\n 'clip-path': clipPathId ? `url(#${clipPathId})` : undefined,\n },\n buildXMLString('path', {\n x: left,\n y: top,\n width,\n height,\n d: path,\n })\n )\n }\n\n if (style.opacity) {\n opacity = +style.opacity\n }\n\n const filter = shadow({ width, height, id }, style)\n\n if (style.transform) {\n matrix = transform(\n {\n left,\n top,\n width,\n height,\n },\n style.transform as unknown as number[],\n isInheritingTransform,\n style.transformOrigin as ParsedTransformOrigin | undefined\n )\n }\n\n return (\n filter +\n (filter ? `<g filter=\"url(#satori_s-${id})\">` : '') +\n clip +\n buildXMLString('image', {\n x: left,\n y: top,\n width,\n height,\n href: src,\n preserveAspectRatio,\n transform: matrix ? matrix : undefined,\n 'clip-path': clip\n ? `url(#satori_c-${id})`\n : clipPathId\n ? `url(#${clipPathId})`\n : undefined,\n }) +\n (filter ? `</g>` : '')\n )\n}\n","/**\n * This module is used to calculate the layout of the current sub-tree.\n */\n\nimport type { ReactNode } from 'react'\nimport type { YogaNode } from 'yoga-layout'\n\nimport getYoga from './yoga'\nimport { isReactElement, isClass, buildXMLString } from './utils'\nimport handler from './handler'\nimport FontLoader from './font'\nimport layoutText from './text'\nimport rect from './builder/rect'\nimport image from './builder/image'\n\nexport interface LayoutContext {\n id: string\n parentStyle: Record<string, number | string>\n inheritedStyle: Record<string, number | string>\n isInheritingTransform?: boolean\n parent: YogaNode\n font: FontLoader\n embedFont: boolean\n debug?: boolean\n graphemeImages?: Record<string, string>\n canLoadAdditionalAssets: boolean\n}\n\nexport default function* layout(\n element: ReactNode,\n context: LayoutContext\n): Generator<string[], string, [number, number]> {\n const Yoga = getYoga()\n const {\n id,\n inheritedStyle,\n parent,\n font,\n debug,\n embedFont = true,\n graphemeImages,\n canLoadAdditionalAssets,\n } = context\n\n // 1. Pre-process the node.\n if (element === null || typeof element === 'undefined') {\n yield\n yield\n return ''\n }\n\n // Not a normal element.\n if (!isReactElement(element) || typeof element.type === 'function') {\n let iter: ReturnType<typeof layout>\n\n if (!isReactElement(element)) {\n // Process as text node.\n iter = layoutText(String(element), context)\n yield iter.next().value as string[]\n } else {\n if (isClass(element.type as Function)) {\n throw new Error('Class component is not supported.')\n }\n // If it's a custom component, Satori strictly requires it to be pure,\n // stateless, and not relying on any React APIs such as hooks or suspense.\n // So we can safely evaluate it to render. Otherwise, an error will be\n // thrown by React.\n iter = layout((element.type as Function)(element.props), context)\n yield iter.next().value as string[]\n }\n\n iter.next()\n const offset = yield\n return iter.next(offset).value as string\n }\n\n // Process as element.\n const { type, props } = element\n const { style, children } = props\n\n const node = Yoga.Node.create()\n parent.insertChild(node, parent.getChildCount())\n\n const [computedStyle, newInheritableStyle] = handler(\n node,\n type,\n inheritedStyle,\n style,\n props\n )\n\n // Post-process styles to attach inheritable properties for Satori.\n\n // If the element is inheriting the parent `transform`, or applying its own.\n // This affects the coordinate system.\n const isInheritingTransform =\n computedStyle.transform === inheritedStyle.transform\n if (!isInheritingTransform) {\n ;(computedStyle.transform as any).__parent = inheritedStyle.transform\n }\n\n // If the element has `overflow` set to `hidden`, we need to create a clip\n // path and use it in all its children.\n if (computedStyle.overflow === 'hidden') {\n newInheritableStyle._inheritedClipPathId = `satori_cp-${id}`\n }\n\n // If the element has `background-clip: text` set, we need to create a clip\n // path and use it in all its children.\n if (computedStyle.backgroundClip === 'text') {\n const mutateRefValue = { value: '' } as any\n newInheritableStyle._inheritedBackgroundClipTextPath = mutateRefValue\n computedStyle._inheritedBackgroundClipTextPath = mutateRefValue\n }\n\n // 2. Do layout recursively for its children.\n const normalizedChildren =\n typeof children === 'undefined' ? [] : [].concat(children)\n const iterators: ReturnType<typeof layout>[] = []\n\n let i = 0\n const segmentsMissingFont: string[] = []\n for (const child of normalizedChildren) {\n const iter = layout(child, {\n id: id + '-' + i++,\n parentStyle: computedStyle,\n inheritedStyle: newInheritableStyle,\n isInheritingTransform: true,\n parent: node,\n font,\n embedFont,\n debug,\n graphemeImages,\n canLoadAdditionalAssets,\n })\n if (canLoadAdditionalAssets) {\n segmentsMissingFont.push(...((iter.next().value as any) || []))\n } else {\n iter.next()\n }\n iterators.push(iter)\n }\n yield segmentsMissingFont\n for (const iter of iterators) iter.next()\n\n // 3. Post-process the node.\n const [x, y] = yield\n\n if (computedStyle.position === 'absolute') {\n node.calculateLayout()\n }\n\n let { left, top, width, height } = node.getComputedLayout()\n\n // Attach offset to the current node.\n left += x\n top += y\n\n let childrenRenderResult = ''\n let baseRenderResult = ''\n let depsRenderResult = ''\n\n // Generate the rendered markup for the current node.\n if (type === 'img') {\n baseRenderResult = image(\n {\n id,\n left,\n top,\n width,\n height,\n src: props.src,\n isInheritingTransform,\n debug,\n },\n computedStyle\n )\n } else {\n baseRenderResult = rect(\n { id, left, top, width, height, isInheritingTransform, debug },\n computedStyle\n )\n }\n\n // Generate the rendered markup for the children.\n for (const iter of iterators) {\n childrenRenderResult += iter.next([left, top]).value\n }\n\n // An extra pass to generate the special background-clip shape collected from\n // children.\n if (computedStyle._inheritedBackgroundClipTextPath) {\n depsRenderResult += buildXMLString(\n 'clipPath',\n {\n id: `satori_bct-${id}`,\n 'clip-path': computedStyle._inheritedClipPathId\n ? `url(#${computedStyle._inheritedClipPathId})`\n : undefined,\n },\n (computedStyle._inheritedBackgroundClipTextPath as any).value\n )\n }\n\n return depsRenderResult + baseRenderResult + childrenRenderResult\n}\n","/**\n * This class handles everything related to fonts.\n */\nimport opentype from '@shuding/opentype.js'\n\nimport { segment } from './utils'\n\ntype Weight = 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900\ntype WeigthName = 'normal' | 'bold'\ntype Style = 'normal' | 'italic'\n\nexport interface FontOptions {\n data: Buffer | ArrayBuffer\n name: string\n weight?: Weight\n style?: Style\n}\n\nfunction compareFont(weight, style, [weight1, style1], [weight2, style2]) {\n if (weight1 !== weight2) {\n // Put the defined weight first.\n if (!weight1) return 1\n if (!weight2) return -1\n\n // Exact match.\n if (weight1 === weight) return -1\n if (weight2 === weight) return 1\n\n // 400 and 500.\n if (weight === 400 && weight1 === 500) return -1\n if (weight === 500 && weight1 === 400) return -1\n if (weight === 400 && weight2 === 500) return 1\n if (weight === 500 && weight2 === 400) return 1\n\n // Less than 400.\n if (weight < 400) {\n if (weight1 < weight && weight2 < weight) return weight2 - weight1\n if (weight1 < weight) return -1\n if (weight2 < weight) return 1\n return weight1 - weight2\n }\n\n // Greater than 500.\n if (weight < weight1 && weight < weight2) return weight1 - weight2\n if (weight < weight1) return -1\n if (weight < weight2) return 1\n return weight2 - weight1\n }\n\n if (style1 !== style2) {\n // Exact match.\n if (style1 === style) return -1\n if (style2 === style) return 1\n }\n\n return -1\n}\n\nexport default class FontLoader {\n defaultFont: opentype.Font\n fonts = new Map<string, [opentype.Font, Weight?, Style?][]>()\n constructor(fontOptions: FontOptions[]) {\n this.addFonts(fontOptions)\n }\n\n // Get font by name and weight.\n private get({\n name,\n weight,\n style,\n }: {\n name: string\n weight: Weight | WeigthName\n style: Style\n }) {\n if (!this.fonts.has(name)) {\n return null\n }\n\n if (weight === 'normal') weight = 400\n if (weight === 'bold') weight = 700\n\n const fonts = [...this.fonts.get(name)]\n\n let matchedFont = fonts[0]\n\n // Fallback to the closest weight and style according to the strategy here:\n // https://developer.mozilla.org/en-US/docs/Web/CSS/font-weight#fallback_weights\n for (let i = 1; i < fonts.length; i++) {\n const [, weight1, style1] = matchedFont\n const [, weight2, style2] = fonts[i]\n if (\n compareFont(weight, style, [weight1, style1], [weight2, style2]) > 0\n ) {\n matchedFont = fonts[i]\n }\n }\n\n return matchedFont[0]\n }\n\n public addFonts(fontOptions: FontOptions[]) {\n for (const fontOption of fontOptions) {\n const data = fontOption.data\n const font = opentype.parse(\n // Buffer to ArrayBuffer.\n 'buffer' in data\n ? data.buffer.slice(\n data.byteOffset,\n data.byteOffset + data.byteLength\n )\n : data,\n // @ts-ignore\n { lowMemory: true }\n )\n\n // We use the first font as the default font fallback.\n if (!this.defaultFont) this.defaultFont = font\n\n const name = fontOption.name.toLowerCase()\n if (!this.fonts.has(name)) {\n this.fonts.set(name, [])\n }\n this.fonts.get(name).push([font, fontOption.weight, fontOption.style])\n }\n }\n\n public getEngine(\n fontSize = 16,\n lineHeight = 1.2,\n {\n fontFamily,\n fontWeight = 400,\n fontStyle = 'normal',\n }: {\n fontFamily: string | string[]\n fontWeight?: Weight | WeigthName\n fontStyle?: Style\n }\n ) {\n fontFamily = Array.isArray(fontFamily) ? fontFamily : [fontFamily]\n const fonts = fontFamily\n .map((face) =>\n this.get({\n name: face,\n weight: fontWeight,\n style: fontStyle,\n })\n )\n .filter(Boolean)\n\n // Add additional fonts as the fallback.\n for (const name of this.fonts.keys()) {\n if (fontFamily.includes(name)) continue\n fonts.push(\n this.get({\n name,\n weight: fontWeight,\n style: fontStyle,\n })\n )\n }\n\n const cachedFontResolver = new Map<number, opentype.Font | undefined>()\n const resolveFont = (word: string, fallback = true) => {\n const code = word.charCodeAt(0)\n if (cachedFontResolver.has(code)) return cachedFontResolver.get(code)\n\n const font = fonts.find((font, index) => {\n return (\n !!font.charToGlyphIndex(word) ||\n (fallback && index === fonts.length - 1)\n )\n })\n\n if (font) {\n cachedFontResolver.set(code, font)\n }\n return font\n }\n\n const ascender = (resolvedFont: opentype.Font, useOS2Table = false) => {\n const ascender =\n (useOS2Table ? resolvedFont.tables?.os2?.sTypoAscender : 0) ||\n resolvedFont.ascender\n return (ascender / resolvedFont.unitsPerEm) * fontSize\n }\n const descender = (resolvedFont: opentype.Font, useOS2Table = false) => {\n const descender =\n (useOS2Table ? resolvedFont.tables?.os2?.sTypoDescender : 0) ||\n resolvedFont.descender\n return (descender / resolvedFont.unitsPerEm) * fontSize\n }\n\n const engine = {\n resolve: (s: string) => {\n return resolveFont(s, false)\n },\n baseline: (\n s?: string,\n resolvedFont = typeof s === 'undefined' ? fonts[0] : resolveFont(s)\n ) => {\n // https://www.w3.org/TR/CSS2/visudet.html#leading\n // Note. It is recommended that implementations that use OpenType or\n // TrueType fonts use the metrics \"sTypoAscender\" and \"sTypoDescender\"\n // from the font's OS/2 table for A and D (after scaling to the current\n // element's font size). In the absence of these metrics, the \"Ascent\"\n // and \"Descent\" metrics from the HHEA table should be used.\n const A = ascender(resolvedFont, true)\n const D = descender(resolvedFont, true)\n const sGlyphHeight = A - D\n const glyphHeight = engine.glyphHeight(s, resolvedFont)\n const sTypoOffset = (glyphHeight - sGlyphHeight) / 2\n const { yMax, yMin } = resolvedFont.tables.head\n const baseline = yMax / (yMax - yMin)\n\n return sTypoOffset + baseline * glyphHeight\n },\n glyphHeight: (\n s?: string,\n resolvedFont = typeof s === 'undefined' ? fonts[0] : resolveFont(s)\n ) => {\n return (\n ((ascender(resolvedFont) - descender(resolvedFont)) * lineHeight) /\n 1.2\n )\n },\n measure: (s: string, style: any) => {\n // Find the first font that supports rendering this segment, or fallback\n // to use the last one.\n const resolvedFont = resolveFont(s)\n return this.measure(resolvedFont, s, style)\n },\n getSVG: (s: string, style: any) => {\n const resolvedFont = resolveFont(s)\n return this.getSVG(resolvedFont, s, style)\n },\n }\n\n return engine\n }\n\n public measure(\n font: opentype.Font,\n content: string,\n {\n fontSize,\n letterSpacing = 0,\n }: {\n fontSize: number\n letterSpacing: number\n }\n ) {\n return font.getAdvanceWidth(content, fontSize, {\n letterSpacing: letterSpacing / fontSize,\n })\n }\n\n public getSVG(\n font: opentype.Font,\n content: string,\n {\n fontSize,\n top,\n left,\n letterSpacing = 0,\n }: {\n fontSize: number\n top: number\n left: number\n letterSpacing: number\n }\n ) {\n return font\n .getPath(content, left, top, fontSize, {\n letterSpacing: letterSpacing / fontSize,\n })\n .toPathData(1)\n }\n}\n","import { buildXMLString } from '../utils'\n\nexport default function svg({\n width,\n height,\n content,\n}: {\n width: number\n height: number\n content: string\n}) {\n return buildXMLString(\n 'svg',\n {\n width,\n height,\n viewBox: `0 0 ${width} ${height}`,\n xmlns: 'http://www.w3.org/2000/svg',\n },\n content\n )\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/satori.ts","../../src/yoga/yoga-prebuilt.wasm.ts","../../src/yoga/index.ts","../../src/utils.ts","../../src/handler/presets.ts","../../src/handler/inheritable.ts","../../src/handler/expand.ts","../../src/vendor/parse-css-dimension/index.js","../../src/transform-origin.ts","../../src/handler/index.ts","../../src/builder/transform.ts","../../src/builder/text.ts","../../src/builder/shadow.ts","../../src/builder/text-decoration.ts","../../src/text.ts","../../src/vendor/gradient-parser/index.js","../../src/builder/background-image.ts","../../src/builder/border-radius.ts","../../src/builder/overflow.ts","../../src/builder/rect.ts","../../src/builder/image.ts","../../src/layout.ts","../../src/font.ts","../../src/builder/svg.ts","../../src/emoji.ts"],"sourcesContent":["import type { ReactNode } from 'react'\n\nimport { guessLanguage } from 'guesslanguage'\n\nimport getYoga, { init } from './yoga'\nimport layout from './layout'\nimport FontLoader, { FontOptions } from './font'\nimport svg from './builder/svg'\nimport { segment } from './utils'\nimport { isEmoji } from './emoji'\n\n// We don't need to initialize the opentype instances every time.\nconst fontCache = new WeakMap()\n\nexport interface SatoriOptions {\n width: number\n height: number\n fonts: FontOptions[]\n embedFont?: boolean\n debug?: boolean\n graphemeImages?: Record<string, string>\n // Can be used to dynamically load missing fonts or image for a given segment.\n detectLanguage?: (segment: string) => Promise<string> | string\n loadAdditionalAsset?: (\n languageCode: string,\n segment: string\n ) => Promise<FontOptions | string | undefined>\n}\n\nexport { init }\n\nexport default async function satori(\n element: ReactNode,\n options: SatoriOptions\n): Promise<string> {\n const Yoga = getYoga()\n if (!Yoga) throw new Error('Satori is not initialized.')\n\n let font: FontLoader\n if (fontCache.has(options.fonts)) {\n font = fontCache.get(options.fonts)\n } else {\n fontCache.set(options.fonts, (font = new FontLoader(options.fonts)))\n }\n\n const root = Yoga.Node.create()\n root.setWidth(options.width)\n root.setHeight(options.height)\n root.setFlexDirection(Yoga.FLEX_DIRECTION_ROW)\n root.setFlexWrap(Yoga.WRAP_WRAP)\n root.setAlignContent(Yoga.ALIGN_AUTO)\n root.setAlignItems(Yoga.ALIGN_FLEX_START)\n root.setJustifyContent(Yoga.JUSTIFY_FLEX_START)\n root.setOverflow(Yoga.OVERFLOW_HIDDEN)\n\n const graphemeImages = { ...options.graphemeImages }\n\n const handler = layout(element, {\n id: 'id',\n parentStyle: {},\n inheritedStyle: {\n fontSize: 16,\n fontWeight: 'normal',\n fontFamily: 'serif',\n fontStyle: 'normal',\n lineHeight: 1.2,\n color: 'black',\n opacity: 1,\n whiteSpace: 'normal',\n\n // Special style properties:\n _viewportWidth: options.width,\n _viewportHeight: options.height,\n },\n parent: root,\n font,\n embedFont: options.embedFont,\n debug: options.debug,\n graphemeImages,\n canLoadAdditionalAssets: !!options.loadAdditionalAsset,\n })\n\n let segmentsMissingFont = handler.next().value as string[]\n\n if (options.loadAdditionalAsset) {\n if (segmentsMissingFont.length) {\n // Potentially CJK fonts are missing.\n segmentsMissingFont = Array.from(\n new Set(segment(segmentsMissingFont.join(''), 'grapheme'))\n )\n\n const langaugeCodes: Record<string, string[]> = {}\n segmentsMissingFont.forEach((seg) =>\n guessLanguage.detect(seg, (code) => {\n if (code === 'unknown' && isEmoji(seg)) code = 'emoji'\n\n langaugeCodes[code] = langaugeCodes[code] || []\n if (code === 'emoji') {\n langaugeCodes[code].push(seg)\n } else {\n langaugeCodes[code][0] = (langaugeCodes[code][0] || '') + seg\n }\n })\n )\n\n const fonts: FontOptions[] = []\n const images: Record<string, string> = {}\n\n await Promise.all(\n Object.entries(langaugeCodes).flatMap(([code, segments]) =>\n segments.map((segment) =>\n options.loadAdditionalAsset(code, segment).then((asset) => {\n if (typeof asset === 'string') {\n images[segment] = asset\n } else if (asset) {\n fonts.push(asset)\n }\n })\n )\n )\n )\n\n // Directly mutate the font provider and the grapheme map.\n font.addFonts(fonts)\n Object.assign(graphemeImages, images)\n }\n }\n\n handler.next()\n root.calculateLayout(options.width, options.height, Yoga.DIRECTION_LTR)\n\n const content = handler.next([0, 0]).value as string\n\n root.freeRecursive()\n\n return svg({ width: options.width, height: options.height, content })\n}\n","// For WASM build, we don't include the prebuilt version of Yoga but let the\n// user specify the module manually with e.g.:\n// https://github.com/shuding/yoga-wasm-web.\nexport default {}\n","let Yoga: typeof import('yoga-layout')\n\nimport YogaMod from '@yoga'\n\n// @ts-ignore\nYoga = YogaMod.default\n\nexport function init(yoga: typeof Yoga) {\n Yoga = yoga\n}\n\nexport default function getYoga(): typeof Yoga {\n return Yoga\n}\n","import type { ReactNode, ReactElement } from 'react'\n\nimport { LineBreaker } from 'css-line-break'\nimport { splitGraphemes } from 'text-segmentation'\n\nexport function isReactElement(node: ReactNode): node is ReactElement {\n const type = typeof node\n if (\n type === 'number' ||\n type === 'bigint' ||\n type === 'string' ||\n type === 'boolean'\n ) {\n return false\n }\n return true\n}\n\nexport function isClass(f: Function) {\n return /^class\\s/.test(Function.prototype.toString.call(f))\n}\n\n// Multiplies two 2d transform matrices.\nexport function multiply(m1: number[], m2: number[]) {\n return [\n m1[0] * m2[0] + m1[2] * m2[1],\n m1[1] * m2[0] + m1[3] * m2[1],\n m1[0] * m2[2] + m1[2] * m2[3],\n m1[1] * m2[2] + m1[3] * m2[3],\n m1[0] * m2[4] + m1[2] * m2[5] + m1[4],\n m1[1] * m2[4] + m1[3] * m2[5] + m1[5],\n ]\n}\n\nexport function v(\n field: string | number,\n map: Record<string, any>,\n fallback: any\n) {\n const value = map[field]\n return typeof value === 'undefined' ? fallback : value\n}\n\n// @TODO: Support \"lang\" attribute to modify the locale\nconst locale = undefined\n\nconst INTL_SEGMENTER_SUPPORTED =\n typeof Intl !== 'undefined' &&\n 'Segmenter' in Intl &&\n process.env.NODE_ENV !== 'test'\n\nconst wordSegmenter = INTL_SEGMENTER_SUPPORTED\n ? new (Intl as any).Segmenter(locale, { granularity: 'word' })\n : null\nconst graphemeSegmenter = INTL_SEGMENTER_SUPPORTED\n ? new (Intl as any).Segmenter(locale, {\n granularity: 'grapheme',\n })\n : null\n\n// Implementation modified from\n// https://github.com/niklasvh/html2canvas/blob/6521a487d78172f7179f7c973c1a3af40eb92009/src/css/layout/text.ts\n// https://drafts.csswg.org/css-text/#word-separator\nexport const wordSeparators = [\n 0x0020, 0x00a0, 0x1361, 0x10100, 0x10101, 0x1039, 0x1091, 0xa,\n].map((point) => String.fromCodePoint(point))\n\nconst breakWords = (str: string): string[] => {\n const breaker = LineBreaker(str, {\n lineBreak: 'strict',\n wordBreak: 'normal',\n })\n\n const words = []\n let bk\n\n while (!(bk = breaker.next()).done) {\n if (bk.value) {\n const value = bk.value.slice()\n let word = ''\n for (let i = 0; i < value.length; i++) {\n const char = value[i]\n if (!wordSeparators.includes(char)) {\n word += char\n } else {\n if (word.length) {\n words.push(word)\n }\n words.push(char)\n word = ''\n }\n }\n\n if (word.length) {\n words.push(word)\n }\n }\n }\n\n return words\n}\n\nexport function segment(\n content: string,\n granularity: 'word' | 'grapheme'\n): string[] {\n if (INTL_SEGMENTER_SUPPORTED) {\n return granularity === 'word'\n ? [...wordSegmenter.segment(content)].map((seg) => seg.segment)\n : [...graphemeSegmenter.segment(content)].map((seg) => seg.segment)\n }\n\n if (granularity === 'word') {\n return breakWords(content)\n } else {\n return splitGraphemes(content)\n }\n}\n\nexport function buildXMLString(\n type: string,\n attrs: Record<string, any>,\n children?: string\n) {\n let attrString = ''\n\n for (const [k, v] of Object.entries(attrs)) {\n if (typeof v !== 'undefined') {\n attrString += ` ${k}=\"${v}\"`\n }\n }\n\n if (children) {\n return `<${type}${attrString}>${children}</${type}>`\n }\n return `<${type}${attrString}/>`\n}\n","/**\n * Pre-defined styles for elements. Here we hand pick some from Chromium's\n * default styles:\n * https://chromium.googlesource.com/chromium/blink/+/master/Source/core/css/html.css\n *\n * We try to only include commonly used, styling elements rather than senmantic elements.\n */\n\nexport default {\n // Generic block-level elements\n p: {\n display: 'block',\n marginTop: '1em',\n marginBottom: '1em',\n },\n div: {\n display: 'block',\n },\n blockquote: {\n display: 'block',\n marginTop: '1em',\n marginBottom: '1em',\n marginLeft: 40,\n marginRight: 40,\n },\n center: {\n display: 'block',\n textAlign: 'center',\n },\n hr: {\n display: 'block',\n marginTop: '0.5em',\n marginBottom: '0.5em',\n marginLeft: 'auto',\n marginRight: 'auto',\n borderWidth: 1,\n borderStyle: 'inset',\n },\n // Heading elements\n h1: {\n display: 'block',\n fontSize: '2em',\n marginTop: '0.67em',\n marginBottom: '0.67em',\n marginLeft: 0,\n marginRight: 0,\n fontWeight: 'bold',\n },\n h2: {\n display: 'block',\n fontSize: '1.5em',\n marginTop: '0.83em',\n marginBottom: '0.83em',\n marginLeft: 0,\n marginRight: 0,\n fontWeight: 'bold',\n },\n h3: {\n display: 'block',\n fontSize: '1.17em',\n marginTop: '1em',\n marginBottom: '1em',\n marginLeft: 0,\n marginRight: 0,\n fontWeight: 'bold',\n },\n h4: {\n display: 'block',\n marginTop: '1.33em',\n marginBottom: '1.33em',\n marginLeft: 0,\n marginRight: 0,\n fontWeight: 'bold',\n },\n h5: {\n display: 'block',\n fontSize: '0.83em',\n marginTop: '1.67em',\n marginBottom: '1.67em',\n marginLeft: 0,\n marginRight: 0,\n fontWeight: 'bold',\n },\n h6: {\n display: 'block',\n fontSize: '0.67em',\n marginTop: '2.33em',\n marginBottom: '2.33em',\n marginLeft: 0,\n marginRight: 0,\n fontWeight: 'bold',\n },\n // Tables\n // Lists\n // Form elements\n // Inline elements\n u: {\n textDecoration: 'underline',\n },\n strong: {\n fontWeight: 'bold',\n },\n b: {\n fontWeight: 'bold',\n },\n i: {\n fontStyle: 'italic',\n },\n em: {\n fontStyle: 'italic',\n },\n code: {\n fontFamily: 'monospace',\n },\n kbd: {\n fontFamily: 'monospace',\n },\n pre: {\n display: 'block',\n fontFamily: 'monospace',\n whiteSpace: 'pre',\n marginTop: '1em',\n marginBottom: '1em',\n },\n mark: {\n backgroundColor: 'yellow',\n color: 'black',\n },\n big: {\n fontSize: 'larger',\n },\n small: {\n fontSize: 'smaller',\n },\n s: {\n textDecoration: 'line-through',\n },\n}\n","const list = new Set([\n 'color',\n 'font',\n 'fontFamily',\n 'fontSize',\n 'fontStyle',\n 'fontWeight',\n 'letterSpacing',\n 'lineHeight',\n 'textAlign',\n 'textTransform',\n 'textShadowOffset',\n 'textShadowColor',\n 'textShadowRadius',\n 'textDecorationLine',\n 'textDecorationStyle',\n 'textDecorationColor',\n 'whiteSpace',\n 'transform',\n 'wordBreak',\n\n // Special case: SVG doesn't apply these to children elements so we need to\n // make it inheritable here.\n 'opacity',\n 'filter',\n\n // Special properties of Satori:\n '_viewportWidth',\n '_viewportHeight',\n '_inheritedClipPathId',\n '_inheritedBackgroundClipTextPath',\n])\n\nexport default function inheritable(style: Record<string, any>) {\n const inheritedStyle: Record<string, any> = {}\n for (const prop in style) {\n if (list.has(prop)) {\n inheritedStyle[prop] = style[prop]\n }\n }\n return inheritedStyle\n}\n","/**\n * This module expands the CSS properties to get rid of shorthands, as well as\n * cleaning up some properties.\n */\n\nimport { getPropertyName, getStylesForProperty } from 'css-to-react-native'\nimport { parseElementStyle } from 'css-background-parser'\n\nimport CssDimension from '../vendor/parse-css-dimension'\nimport parseTransformOrigin from '../transform-origin'\nimport { multiply } from '../utils'\n\n// https://react-cn.github.io/react/tips/style-props-value-px.html\nconst optOutPx = new Set([\n 'flex',\n 'flexGrow',\n 'flexShrink',\n 'flexBasis',\n 'fontWeight',\n 'lineHeight',\n 'opacity',\n 'scale',\n 'scaleX',\n 'scaleY',\n])\nconst keepNumber = new Set(['lineHeight'])\n\nconst baseMatrix = [1, 0, 0, 1, 0, 0]\n\n/**\n * A trick to fix `border: 1px solid` to not use `black` but the inherited\n * `color` value. This is necessary because css-to-react-native automatically\n * fallbacks to default color values.\n */\nfunction handleFallbackColor(\n prop: string,\n parsed: Record<string, string>,\n rawInput: string,\n color: string\n) {\n if (prop === 'border' && !rawInput.includes(parsed.borderColor)) {\n parsed.borderColor = color\n } else if (\n prop === 'textDecoration' &&\n !rawInput.includes(parsed.textDecorationColor)\n ) {\n parsed.textDecorationColor = color\n }\n return parsed\n}\n\nfunction purify(name: string, value?: string | number) {\n if (typeof value === 'number') {\n if (!optOutPx.has(name)) return value + 'px'\n if (keepNumber.has(name)) return value\n return String(value)\n }\n // @TODO: For `transform`, we need to convert relative values to absolute\n // values here.\n return value\n}\n\nfunction handleSpecialCase(name: string, value: string | number) {\n if (name === 'lineHeight') return { lineHeight: purify(name, value) }\n if (name === 'fontFamily')\n return {\n fontFamily: (value as string).split(',').map((v) => {\n return v\n .trim()\n .replace(/(^['\"])|(['\"]$)/g, '')\n .toLocaleLowerCase()\n }),\n }\n return null\n}\n\nfunction lengthToNumber(\n length: string | number,\n baseFontSize: number,\n inheritedStyle: Record<string, string | number>,\n { percentage }: { percentage: boolean } = { percentage: false }\n): number | undefined {\n if (typeof length === 'number') return length\n\n // Convert em and rem values to number (px), convert rad to deg.\n try {\n const parsed = new CssDimension(length)\n if (parsed.type === 'length') {\n switch (parsed.unit) {\n case 'em':\n return parsed.value * baseFontSize\n case 'rem':\n return parsed.value * 16\n case 'vw':\n return ~~(\n (parsed.value * (inheritedStyle._viewportWidth as number)) /\n 100\n )\n case 'vh':\n return ~~(\n (parsed.value * (inheritedStyle._viewportHeight as number)) /\n 100\n )\n default:\n return parsed.value\n }\n } else if (parsed.type === 'angle') {\n switch (parsed.unit) {\n case 'deg':\n return parsed.value\n case 'rad':\n return (parsed.value * 180) / Math.PI\n default:\n return parsed.value\n }\n } else if (parsed.type === 'percentage') {\n if (percentage) {\n return (parsed.value / 100) * baseFontSize\n }\n }\n } catch (err) {}\n}\n\nexport default function expand(\n style: Record<string, string | number>,\n inheritedStyle: Record<string, string | number>\n): Record<string, string | number> {\n const transformedStyle = {} as any\n for (const prop in style) {\n // Internal properties.\n if (prop.startsWith('_')) {\n transformedStyle[prop] = style[prop]\n continue\n }\n\n const name = getPropertyName(prop)\n Object.assign(\n transformedStyle,\n handleSpecialCase(name, style[prop]) ||\n handleFallbackColor(\n name,\n getStylesForProperty(name, purify(name, style[prop]), true),\n style[prop] as string,\n (style.color || inheritedStyle.color) as string\n )\n )\n }\n\n // Parse background images.\n if (transformedStyle.backgroundImage) {\n const { backgrounds } = parseElementStyle(transformedStyle)\n transformedStyle.backgroundImage = backgrounds\n }\n\n // Calculate the base font size.\n let baseFontSize: number =\n transformedStyle.fontSize || inheritedStyle.fontSize\n if (typeof baseFontSize === 'string') {\n try {\n const parsed = new CssDimension(baseFontSize)\n switch (parsed.unit) {\n case 'em':\n baseFontSize = parsed.value * (inheritedStyle.fontSize as number)\n break\n case 'rem':\n baseFontSize = parsed.value * 16\n break\n }\n } catch (err) {\n baseFontSize = 16\n }\n }\n if (typeof transformedStyle.fontSize !== 'undefined') {\n transformedStyle.fontSize = baseFontSize\n }\n\n if (transformedStyle.transformOrigin) {\n transformedStyle.transformOrigin = parseTransformOrigin(\n transformedStyle.transformOrigin,\n baseFontSize\n )\n }\n\n for (const prop in transformedStyle) {\n let value = transformedStyle[prop]\n\n // Line height needs to be relative.\n if (prop === 'lineHeight') {\n if (typeof value === 'string') {\n value = transformedStyle[prop] =\n lengthToNumber(value, baseFontSize, inheritedStyle, {\n percentage: true,\n }) / baseFontSize\n }\n } else {\n // Convert em and rem values to px (number).\n if (typeof value === 'string') {\n const len = lengthToNumber(value, baseFontSize, inheritedStyle)\n if (typeof len !== 'undefined') transformedStyle[prop] = len\n value = transformedStyle[prop]\n }\n }\n\n // Inherit the opacity.\n if (prop === 'opacity') {\n value = transformedStyle[prop] =\n value * (inheritedStyle.opacity as number)\n }\n\n // Handle CSS transforms To make it easier, we convert different transform\n // types directly to a matrix and apply it recursively to all its children.\n // @TODO: We need to convert relative values (50%) to absolute values. This\n // is pretty tricky to support as we need an extra pass to handle them after\n // the full layout pass.\n if (prop === 'transform') {\n let matrix = [...baseMatrix]\n const transforms = value as { [type: string]: number | string }[]\n\n // Transforms are applied from right to left.\n for (const transform of transforms) {\n const type = Object.keys(transform)[0]\n const v = transform[type]\n const len =\n typeof v === 'string'\n ? lengthToNumber(v, baseFontSize, inheritedStyle)\n : v\n\n const transformMatrix = [...baseMatrix]\n switch (type) {\n case 'translateX':\n transformMatrix[4] = len\n break\n case 'translateY':\n transformMatrix[5] = len\n break\n case 'scale':\n transformMatrix[0] = len\n transformMatrix[3] = len\n break\n case 'scaleX':\n transformMatrix[0] = len\n break\n case 'scaleY':\n transformMatrix[3] = len\n break\n case 'rotate':\n const rad = (len * Math.PI) / 180\n const c = Math.cos(rad)\n const s = Math.sin(rad)\n transformMatrix[0] = c\n transformMatrix[1] = s\n transformMatrix[2] = -s\n transformMatrix[3] = c\n break\n case 'skewX':\n transformMatrix[2] = Math.tan((len * Math.PI) / 180)\n break\n case 'skewY':\n transformMatrix[1] = Math.tan((len * Math.PI) / 180)\n break\n }\n matrix = multiply(transformMatrix, matrix)\n }\n\n transformedStyle.transform = matrix\n }\n }\n\n return transformedStyle\n}\n","var e=(t,r)=>()=>(r||t((r={exports:{}}).exports,r),r.exports);var u=e((k,g)=>{g.exports=[\"em\",\"ex\",\"ch\",\"rem\",\"vh\",\"vw\",\"vmin\",\"vmax\",\"px\",\"mm\",\"cm\",\"in\",\"pt\",\"pc\",\"mozmm\"]});var a=e((z,v)=>{v.exports=[\"deg\",\"grad\",\"rad\",\"turn\"]});var c=e((L,w)=>{w.exports=[\"dpi\",\"dpcm\",\"dppx\"]});var h=e(($,y)=>{y.exports=[\"Hz\",\"kHz\"]});var m=e((j,b)=>{b.exports=[\"s\",\"ms\"]});var q=u(),f=a(),p=c(),l=h(),d=m();function s(t){if(/\\.\\D?$/.test(t))throw new Error(\"The dot should be followed by a number\");if(/^[+-]{2}/.test(t))throw new Error(\"Only one leading +/- is allowed\");if(x(t)>1)throw new Error(\"Only one dot is allowed\");if(/%$/.test(t)){this.type=\"percentage\",this.value=o(t),this.unit=\"%\";return}var r=O(t);if(!r){this.type=\"number\",this.value=o(t);return}this.type=F(r),this.value=o(t.substr(0,t.length-r.length)),this.unit=r}s.prototype.valueOf=function(){return this.value};s.prototype.toString=function(){return this.value+(this.unit||\"\")};function U(t){return new s(t)}function x(t){var r=t.match(/\\./g);return r?r.length:0}function o(t){var r=parseFloat(t);if(isNaN(r))throw new Error(\"Invalid number: \"+t);return r}var E=[].concat(f,l,q,p,d);function O(t){var r=t.match(/\\D+$/),n=r&&r[0];if(n&&E.indexOf(n)===-1)throw new Error(\"Invalid unit: \"+n);return n}var D=Object.assign(i(f,\"angle\"),i(l,\"frequency\"),i(p,\"resolution\"),i(d,\"time\"));function i(t,r){return Object.fromEntries(t.map(n=>[n,r]))}function F(t){return D[t]||\"length\"}export{U as default};\n","import valueParser from 'postcss-value-parser'\n\nimport CssDimension from './vendor/parse-css-dimension'\n\n/**\n * If key for each direction is missing, assume default (50%)\n */\nexport interface ParsedTransformOrigin {\n /** Relative horizontal transform origin in % */\n xRelative?: number\n /** Relative vertical transform origin in % */\n yRelative?: number\n /** Absolute horizontal transform origin in pixels */\n xAbsolute?: number\n /** Absolute horizontal transform origin in pixels */\n yAbsolute?: number\n}\n\ninterface ParsedUnit {\n /** Relative unit in % */\n relative?: number\n /** Absolute unit in pixels */\n absolute?: number\n}\n\nfunction parseUnit(word: string, baseFontSize: number): ParsedUnit {\n try {\n const parsed = new CssDimension(word)\n switch (parsed.unit) {\n case 'px':\n return { absolute: parsed.value }\n case 'em':\n return { absolute: parsed.value * baseFontSize }\n case 'rem':\n return { absolute: parsed.value * 16 }\n case '%':\n return { relative: parsed.value }\n default:\n return {}\n }\n } catch (e) {\n return {}\n }\n}\n\nfunction handleWord(\n word: string,\n baseFontSize: number,\n unitIsHorizontal: boolean\n) {\n switch (word) {\n case 'top':\n return { yRelative: 0 }\n case 'left':\n return { xRelative: 0 }\n case 'right':\n return { xRelative: 100 }\n case 'bottom':\n return { yRelative: 100 }\n case 'center':\n return {}\n default:\n const parsedUnit = parseUnit(word, baseFontSize)\n return parsedUnit.absolute\n ? {\n [unitIsHorizontal ? 'xAbsolute' : 'yAbsolute']: parsedUnit.absolute,\n }\n : parsedUnit.relative\n ? {\n [unitIsHorizontal ? 'xRelative' : 'yRelative']: parsedUnit.relative,\n }\n : {}\n }\n}\n\nexport default function parseTranformOrigin(\n value: string | number,\n baseFontSize: number\n): ParsedTransformOrigin {\n // If it's a single value and a number, then it's horizontal\n if (typeof value === 'number') {\n return { xAbsolute: value }\n }\n let words: string[]\n try {\n words = valueParser(value)\n .nodes.filter((node) => node.type === 'word')\n .map((node) => node.value)\n } catch (e) {\n return {}\n }\n\n if (words.length === 1) {\n // If it's a single value and a number, then it's horizontal, so\n // pass `true` to `unitIsHorizontal`\n return handleWord(words[0], baseFontSize, true)\n } else if (words.length === 2) {\n // Make words to be [horizontal, vertical]\n if (\n words[0] === 'top' ||\n words[0] === 'bottom' ||\n words[1] === 'left' ||\n words[1] === 'right'\n ) {\n words.reverse()\n }\n\n return {\n ...handleWord(words[0], baseFontSize, true),\n ...handleWord(words[1], baseFontSize, false),\n }\n } else {\n return {}\n }\n}\n","/**\n * Handler to update the Yoga node properties with the given element type and\n * style. Each supported element has its own preset styles, so this function\n * also returns the inherited style for children of the element.\n */\n\nimport type { YogaNode } from 'yoga-layout'\n\nimport getYoga from '../yoga'\nimport presets from './presets'\nimport inheritable from './inheritable'\nimport expand from './expand'\nimport { v } from '../utils'\n\ntype SatoriElement = keyof typeof presets\n\nexport default function handler(\n node: YogaNode,\n type: SatoriElement | string,\n inheritedStyle: Record<string, string | number>,\n definedStyle: Record<string, string | number>,\n props: Record<string, any>\n): [Record<string, string | number>, Record<string, string | number>] {\n const Yoga = getYoga()\n\n // Extend the default style with defined and inherited styles.\n const style = {\n ...inheritedStyle,\n ...expand(presets[type], inheritedStyle),\n ...expand(definedStyle, inheritedStyle),\n }\n\n if (type === 'img') {\n const width = parseInt(props.width)\n const height = parseInt(props.height)\n const r = height / width\n if (!style.width) style.width = width\n if (!style.height) style.height = r * (style.width as number)\n }\n\n // Set properties for Yoga.\n node.setDisplay(\n v(\n style.display,\n {\n flex: Yoga.DISPLAY_FLEX,\n none: Yoga.DISPLAY_NONE,\n },\n Yoga.DISPLAY_FLEX\n )\n )\n\n node.setAlignContent(\n v(\n style.alignContent,\n {\n stretch: Yoga.ALIGN_STRETCH,\n center: Yoga.ALIGN_CENTER,\n 'flex-start': Yoga.ALIGN_FLEX_START,\n 'flex-end': Yoga.ALIGN_FLEX_END,\n 'space-between': Yoga.ALIGN_SPACE_BETWEEN,\n 'space-around': Yoga.ALIGN_SPACE_AROUND,\n baseline: Yoga.ALIGN_BASELINE,\n normal: Yoga.ALIGN_AUTO,\n },\n Yoga.ALIGN_AUTO\n )\n )\n\n node.setAlignItems(\n v(\n style.alignItems,\n {\n stretch: Yoga.ALIGN_STRETCH,\n center: Yoga.ALIGN_CENTER,\n 'flex-start': Yoga.ALIGN_FLEX_START,\n 'flex-end': Yoga.ALIGN_FLEX_END,\n baseline: Yoga.ALIGN_BASELINE,\n normal: Yoga.ALIGN_AUTO,\n },\n Yoga.ALIGN_FLEX_START\n )\n )\n node.setAlignSelf(\n v(\n style.alignSelf,\n {\n stretch: Yoga.ALIGN_STRETCH,\n center: Yoga.ALIGN_CENTER,\n 'flex-start': Yoga.ALIGN_FLEX_START,\n 'flex-end': Yoga.ALIGN_FLEX_END,\n baseline: Yoga.ALIGN_BASELINE,\n normal: Yoga.ALIGN_AUTO,\n },\n Yoga.ALIGN_AUTO\n )\n )\n node.setJustifyContent(\n v(\n style.justifyContent,\n {\n center: Yoga.JUSTIFY_CENTER,\n 'flex-start': Yoga.JUSTIFY_FLEX_START,\n 'flex-end': Yoga.JUSTIFY_FLEX_END,\n 'space-between': Yoga.JUSTIFY_SPACE_BETWEEN,\n 'space-around': Yoga.JUSTIFY_SPACE_AROUND,\n },\n Yoga.JUSTIFY_FLEX_START\n )\n )\n // @TODO: node.setAspectRatio\n\n node.setFlexDirection(\n v(\n style.flexDirection,\n {\n row: Yoga.FLEX_DIRECTION_ROW,\n column: Yoga.FLEX_DIRECTION_COLUMN,\n 'row-reverse': Yoga.FLEX_DIRECTION_ROW_REVERSE,\n 'column-reverse': Yoga.FLEX_DIRECTION_COLUMN_REVERSE,\n },\n Yoga.FLEX_DIRECTION_ROW\n )\n )\n node.setFlexWrap(\n v(\n style.flexWrap,\n {\n wrap: Yoga.WRAP_WRAP,\n nowrap: Yoga.WRAP_NO_WRAP,\n 'wrap-reverse': Yoga.WRAP_WRAP_REVERSE,\n },\n Yoga.WRAP_WRAP\n )\n )\n\n // @TODO: node.setFlex\n\n if (typeof style.flexBasis !== 'undefined') {\n // We can't use `auto` here due to this:\n // https://github.com/facebook/yoga/pull/1112\n // @TODO: We need a fork to add this API.\n node.setFlexBasis(style.flexBasis)\n }\n node.setFlexGrow(\n typeof style.flexGrow === 'undefined' ? 0 : (style.flexGrow as number)\n )\n node.setFlexShrink(\n typeof style.flexShrink === 'undefined' ? 0 : (style.flexShrink as number)\n )\n\n if (typeof style.maxHeight !== 'undefined') {\n node.setMaxHeight(style.maxHeight)\n }\n if (typeof style.maxWidth !== 'undefined') {\n node.setMaxWidth(style.maxWidth)\n }\n if (typeof style.minHeight !== 'undefined') {\n node.setMinHeight(style.minHeight)\n }\n if (typeof style.minWidth !== 'undefined') {\n node.setMinWidth(style.minWidth)\n }\n\n node.setOverflow(\n v(\n style.overflow,\n {\n visible: Yoga.OVERFLOW_VISIBLE,\n hidden: Yoga.OVERFLOW_HIDDEN,\n },\n Yoga.OVERFLOW_VISIBLE\n )\n )\n\n node.setMargin(Yoga.EDGE_TOP, (style.marginTop as number) || 0)\n node.setMargin(Yoga.EDGE_BOTTOM, (style.marginBottom as number) || 0)\n node.setMargin(Yoga.EDGE_LEFT, (style.marginLeft as number) || 0)\n node.setMargin(Yoga.EDGE_RIGHT, (style.marginRight as number) || 0)\n\n // @TODO: Add directional border support.\n node.setBorder(Yoga.EDGE_TOP, (style.borderWidth as number) || 0)\n node.setBorder(Yoga.EDGE_BOTTOM, (style.borderWidth as number) || 0)\n node.setBorder(Yoga.EDGE_LEFT, (style.borderWidth as number) || 0)\n node.setBorder(Yoga.EDGE_RIGHT, (style.borderWidth as number) || 0)\n\n node.setPadding(Yoga.EDGE_TOP, style.paddingTop || 0)\n node.setPadding(Yoga.EDGE_BOTTOM, style.paddingBottom || 0)\n node.setPadding(Yoga.EDGE_LEFT, style.paddingLeft || 0)\n node.setPadding(Yoga.EDGE_RIGHT, style.paddingRight || 0)\n\n node.setPositionType(\n v(\n style.position,\n {\n absolute: Yoga.POSITION_TYPE_ABSOLUTE,\n relative: Yoga.POSITION_TYPE_RELATIVE,\n },\n Yoga.POSITION_TYPE_RELATIVE\n )\n )\n\n if (typeof style.top !== 'undefined') {\n node.setPosition(Yoga.EDGE_TOP, style.top)\n }\n if (typeof style.bottom !== 'undefined') {\n node.setPosition(Yoga.EDGE_BOTTOM, style.bottom)\n }\n if (typeof style.left !== 'undefined') {\n node.setPosition(Yoga.EDGE_LEFT, style.left)\n }\n if (typeof style.right !== 'undefined') {\n node.setPosition(Yoga.EDGE_RIGHT, style.right)\n }\n\n if (typeof style.height !== 'undefined') {\n node.setHeight(style.height)\n } else {\n node.setHeightAuto()\n }\n if (typeof style.width !== 'undefined') {\n node.setWidth(style.width)\n } else {\n node.setWidthAuto()\n }\n\n return [style, inheritable(style)]\n}\n","import { multiply } from '../utils'\nimport type { ParsedTransformOrigin } from '../transform-origin'\n\nexport default function transform(\n {\n left,\n top,\n width,\n height,\n }: {\n left: number\n top: number\n width: number\n height: number\n },\n matrix: number[],\n isInheritingTransform: boolean,\n transformOrigin?: ParsedTransformOrigin\n) {\n let result: number[]\n\n // Calculate the transform origin.\n if (isInheritingTransform) {\n result = matrix\n } else {\n const xOrigin =\n transformOrigin?.xAbsolute ??\n ((transformOrigin?.xRelative ?? 50) * width) / 100\n const yOrigin =\n transformOrigin?.yAbsolute ??\n ((transformOrigin?.yRelative ?? 50) * height) / 100\n\n // If this element is the transform target, we attach the origin coordinates\n // to this matrix.\n const x = left + xOrigin\n const y = top + yOrigin\n\n // Due to the different coordinate systems, we need to move the shape to the\n // origin first, then apply the matrix, then move it back.\n result = multiply(\n [1, 0, 0, 1, x, y],\n multiply(matrix, [1, 0, 0, 1, -x, -y])\n )\n\n // And we need to apply its parent transform if it has one.\n if ((matrix as any).__parent) {\n result = multiply((matrix as any).__parent, result)\n }\n\n // Mutate self.\n matrix.splice(0, 6, ...result)\n }\n\n return `matrix(${result.map((v) => v.toFixed(2)).join(',')})`\n}\n","import type { ParsedTransformOrigin } from '../transform-origin'\nimport transform from './transform'\nimport { buildXMLString } from '../utils'\n\nexport function container(\n {\n left,\n top,\n width,\n height,\n isInheritingTransform,\n }: {\n left: number\n top: number\n width: number\n height: number\n isInheritingTransform: boolean\n },\n style: Record<string, number | string>\n) {\n let matrix = ''\n let opacity = 1\n\n if (style.transform) {\n matrix = transform(\n {\n left,\n top,\n width,\n height,\n },\n style.transform as unknown as number[],\n isInheritingTransform,\n style.transformOrigin as ParsedTransformOrigin | undefined\n )\n }\n\n if (style.opacity) {\n opacity = +style.opacity\n }\n\n return { matrix, opacity }\n}\n\nexport default function text(\n {\n id,\n content,\n filter,\n left,\n top,\n width,\n height,\n matrix,\n opacity,\n image,\n clipPathId,\n debug,\n shape,\n decorationShape,\n }: {\n content: string\n filter: string\n id: string\n left: number\n top: number\n width: number\n height: number\n matrix: string\n opacity: number\n image: string | null\n clipPathId?: string\n debug?: boolean\n shape?: boolean\n decorationShape?: string\n },\n style: Record<string, number | string>\n) {\n let extra = ''\n if (debug) {\n extra = buildXMLString('rect', {\n x: left,\n y: top - height,\n width,\n height,\n fill: 'transparent',\n stroke: '#575eff',\n 'stroke-width': 1,\n transform: matrix || undefined,\n 'clip-path': clipPathId ? `url(#${clipPathId})` : undefined,\n })\n }\n\n // This grapheme should be rendered as an image.\n if (image) {\n const shapeProps = {\n href: image,\n x: left,\n y: top,\n width,\n height,\n transform: matrix || undefined,\n 'clip-path': clipPathId ? `url(#${clipPathId})` : undefined,\n style: style.filter ? `filter:${style.filter}` : undefined,\n }\n return [\n (filter ? `${filter}<g filter=\"url(#satori_s-${id})\">` : '') +\n buildXMLString('image', {\n ...shapeProps,\n opacity: opacity !== 1 ? opacity : undefined,\n }) +\n (decorationShape || '') +\n (filter ? '</g>' : '') +\n extra,\n // SVG doesn't support `<image>` as the shape.\n '',\n ]\n }\n\n // Do not embed the font, use <text> with the raw content instead.\n const shapeProps = {\n x: left,\n y: top,\n width,\n height,\n 'font-weight': style.fontWeight,\n 'font-style': style.fontStyle,\n 'font-size': style.fontSize,\n 'font-family': style.fontFamily,\n 'letter-spacing': style.letterSpacing || undefined,\n transform: matrix || undefined,\n 'clip-path': clipPathId ? `url(#${clipPathId})` : undefined,\n style: style.filter ? `filter:${style.filter}` : undefined,\n }\n return [\n (filter ? `${filter}<g filter=\"url(#satori_s-${id})\">` : '') +\n buildXMLString(\n 'text',\n {\n ...shapeProps,\n fill: style.color,\n opacity: opacity !== 1 ? opacity : undefined,\n },\n content\n ) +\n (decorationShape || '') +\n (filter ? '</g>' : '') +\n extra,\n shape ? buildXMLString('text', shapeProps, content) : '',\n ]\n}\n","// @TODO: It seems that SVG filters are pretty expensive for resvg, PNG\n// generation time 10x'd when adding this filter (WASM in browser).\n// https://drafts.fxtf.org/filter-effects/#feGaussianBlurElement\n\nexport default function shadow(\n { id, width, height }: { id: string; width: number; height: number },\n style: Record<string, any>\n) {\n if (\n !style.shadowColor ||\n !style.shadowOffset ||\n typeof style.shadowRadius === 'undefined'\n ) {\n return ''\n }\n\n // Expand the area for the filter to prevent it from cutting off.\n const grow = (style.shadowRadius * style.shadowRadius) / 4\n\n const left = Math.min(style.shadowOffset.width - grow, 0)\n const right = Math.max(style.shadowOffset.width + grow + width, width)\n const top = Math.min(style.shadowOffset.height - grow, 0)\n const bottom = Math.max(style.shadowOffset.height + grow + height, height)\n\n return `<defs><filter id=\"satori_s-${id}\" x=\"${(left / width) * 100}%\" y=\"${\n (top / height) * 100\n }%\" width=\"${((right - left) / width) * 100}%\" height=\"${\n ((bottom - top) / height) * 100\n }%\"><feDropShadow dx=\"${style.shadowOffset.width}\" dy=\"${\n style.shadowOffset.height\n }\" stdDeviation=\"${\n // According to the spec, we use the half of the blur radius as the standard\n // deviation for the filter.\n // > the image that would be generated by applying to the shadow a Gaussian\n // > blur with a standard deviation equal to half the blur radius\n // > https://www.w3.org/TR/css-backgrounds-3/#shadow-blur\n style.shadowRadius / 2\n }\" flood-color=\"${style.shadowColor}\" flood-opacity=\"1\"/></filter></defs>`\n}\n","import { buildXMLString } from '../utils'\n\nexport default function decoration(\n {\n width,\n left,\n top,\n ascender,\n clipPathId,\n }: {\n width: number\n left: number\n top: number\n ascender: number\n clipPathId?: string\n },\n style: Record<string, any>\n) {\n const {\n textDecorationColor,\n textDecorationStyle,\n textDecorationLine,\n fontSize,\n } = style\n if (!textDecorationLine || textDecorationLine === 'none') return ''\n\n // The UA should use such font-based information when choosing auto line thicknesses wherever appropriate.\n // https://drafts.csswg.org/css-text-decor-4/#text-decoration-thickness\n const height = Math.max(1, fontSize * 0.1)\n\n const y =\n textDecorationLine === 'line-through'\n ? top + ascender * 0.5\n : textDecorationLine === 'underline'\n ? top + ascender * 1.1\n : top\n\n const dasharray =\n textDecorationStyle === 'dashed'\n ? `${height * 1.2} ${height * 2}`\n : textDecorationStyle === 'dotted'\n ? `0 ${height * 2}`\n : undefined\n\n return buildXMLString('line', {\n x1: left,\n y1: y,\n x2: left + width,\n y2: y,\n stroke: textDecorationColor,\n 'stroke-width': height,\n 'stroke-dasharray': dasharray,\n 'stroke-linecap': textDecorationStyle === 'dotted' ? 'round' : 'square',\n 'clip-path': clipPathId ? `url(#${clipPathId})` : undefined,\n })\n}\n","/**\n * This module calculates the layout of a text string. Currently the only\n * supported inline node is text. All other nodes are using block layout.\n */\nimport type { LayoutContext } from './layout'\n\nimport getYoga from './yoga'\nimport { v, segment, wordSeparators, buildXMLString } from './utils'\nimport text, { container } from './builder/text'\nimport shadow from './builder/shadow'\nimport decoration from './builder/text-decoration'\n\n// @TODO: Support \"lang\" attribute to modify the locale\nconst locale = undefined\n\nexport default function* buildTextNodes(\n content: string,\n context: LayoutContext\n) {\n const Yoga = getYoga()\n\n const {\n parentStyle,\n inheritedStyle,\n parent,\n font,\n id,\n isInheritingTransform,\n debug,\n embedFont,\n graphemeImages,\n canLoadAdditionalAssets,\n } = context\n\n if (parentStyle.textTransform === 'uppercase') {\n content = content.toLocaleUpperCase(locale)\n } else if (parentStyle.textTransform === 'lowercase') {\n content = content.toLocaleLowerCase(locale)\n } else if (parentStyle.textTransform === 'capitalize') {\n content = segment(content, 'word')\n // For each word...\n .map((word) => {\n // ...split into graphemes...\n return segment(word, 'grapheme')\n .map((grapheme, index) => {\n // ...and make the first grapheme uppercase\n return index === 0 ? grapheme.toLocaleUpperCase(locale) : grapheme\n })\n .join('')\n })\n .join('')\n }\n\n const segmenter = v(\n parentStyle.wordBreak,\n {\n normal: 'word',\n 'break-all': 'grapheme',\n 'break-word': 'grapheme',\n 'keep-all': 'word',\n },\n 'word'\n )\n\n const words = segment(content, segmenter)\n\n // Create a container node for this text fragment.\n const textContainer = Yoga.Node.create()\n textContainer.setAlignItems(Yoga.ALIGN_BASELINE)\n if (parentStyle.textAlign === 'left') {\n textContainer.setJustifyContent(Yoga.JUSTIFY_FLEX_START)\n } else if (parentStyle.textAlign === 'center') {\n textContainer.setJustifyContent(Yoga.JUSTIFY_CENTER)\n } else if (parentStyle.textAlign === 'right') {\n textContainer.setJustifyContent(Yoga.JUSTIFY_FLEX_END)\n } else if (parentStyle.textAlign === 'justify') {\n textContainer.setJustifyContent(Yoga.JUSTIFY_SPACE_BETWEEN)\n }\n parent.insertChild(textContainer, parent.getChildCount())\n\n const {\n textAlign,\n textOverflow,\n whiteSpace,\n lineHeight,\n filter: cssFilter,\n _inheritedBackgroundClipTextPath,\n } = parentStyle\n\n const baseFontSize = parentStyle.fontSize as number\n\n // Get the correct font according to the container style.\n // https://www.w3.org/TR/CSS2/visudet.html\n let engine = font.getEngine(\n baseFontSize,\n lineHeight as number,\n parentStyle as any\n )\n\n // Yield segments that are missing a font.\n const wordsMissingFont = canLoadAdditionalAssets\n ? words.filter((word) => !engine.check(word))\n : []\n yield wordsMissingFont\n if (wordsMissingFont.length) {\n // Reload the engine with additional fonts.\n engine = font.getEngine(\n baseFontSize,\n lineHeight as number,\n parentStyle as any\n )\n }\n\n // Compute the layout.\n // @TODO: Use segments instead of words to properly support kerning.\n let lineWidths = []\n let baselines = []\n let lineSegmentNumber = []\n let wordsInLayout: (null | {\n x: number\n y: number\n width: number\n line: number\n lineIndex: number\n })[] = []\n\n // We can cache the measured width of each word as the measure function will be\n // called multiple times.\n const wordWidthCache = new Map<string, number>()\n const measureWithCache = (segments: string[]) => {\n let total = 0\n for (const s of segments) {\n if (wordWidthCache.has(s)) {\n total += wordWidthCache.get(s)\n continue\n }\n const width = engine.measure(s, parentStyle as any)\n wordWidthCache.set(s, width)\n total += width\n }\n return total\n }\n\n // Calculate the minimal possible width of the parent container so it don't\n // shrink below the content.\n let minWidth = 0\n let remainingSegment = []\n let extraWidth = 0\n for (const word of words) {\n let breakSegment = false\n const isImage = graphemeImages && graphemeImages[word]\n\n if (whiteSpace === 'pre') {\n // For `pre`, only break the line for `\\n`.\n breakSegment = word[0] === '\\n'\n } else if (whiteSpace !== 'nowrap') {\n // For `normal`, `pre-wrap`, we can wrap with any word separators or\n // images.\n if (isImage || wordSeparators.includes(word[0])) {\n breakSegment = true\n }\n }\n\n if (!breakSegment) {\n if (!wordSeparators.includes(word[0]) || !remainingSegment.length) {\n remainingSegment.push(word === '\\n' ? ' ' : word)\n }\n } else {\n if (whiteSpace === 'nowrap') {\n extraWidth +=\n measureWithCache(remainingSegment) + (parentStyle.fontSize as number)\n } else {\n minWidth = Math.max(minWidth, measureWithCache(remainingSegment))\n if (isImage) {\n minWidth = Math.max(minWidth, parentStyle.fontSize as number)\n }\n }\n remainingSegment = []\n }\n }\n minWidth = Math.max(minWidth, measureWithCache(remainingSegment) + extraWidth)\n const currentMinWidth = parent.getMinWidth()\n const currentMaxWidth = parent.getMaxWidth()\n const currentWidth = parent.getWidth()\n if (\n isNaN(currentWidth.value) &&\n (isNaN(currentMinWidth.value) ||\n (currentMinWidth.unit === 1 && currentMinWidth.value > minWidth))\n ) {\n // minWidth cannot be larger than maxWidth\n if (!isNaN(currentMaxWidth.value)) {\n if (currentMaxWidth.unit === 1) {\n minWidth = Math.min(minWidth, currentMaxWidth.value)\n } else {\n // @TODO: Support percentage units.\n }\n }\n parent.setMinWidth(minWidth)\n }\n if (typeof parentStyle.flexShrink === 'undefined') {\n parent.setFlexShrink(1)\n }\n\n const shouldAlwaysBreakLine =\n whiteSpace === 'pre-wrap' || whiteSpace === 'pre'\n\n textContainer.setMeasureFunc((width) => {\n let lines = 0\n let remainingSpace = ''\n let remainingSpaceWidth = 0\n let currentWidth = 0\n let maxWidth = 0\n let lineIndex = -1\n let height = 0\n let currentLineHeight = 0\n let currentBaselineOffset = 0\n\n lineWidths = []\n lineSegmentNumber = [0]\n\n // We naively implement the width calculation without proper kerning.\n // @TODO: Support different writing modes.\n // @TODO: Support RTL languages.\n for (let i = 0; i < words.length; i++) {\n const word = words[i]\n\n // A character is a word separator if `white-space` is not `pre`.\n if (\n !shouldAlwaysBreakLine &&\n wordSeparators.includes(\n // It's possible that the segment contains multiple separate words such\n // as ` `. We can just use the first character to detect.\n word[0]\n )\n ) {\n // Since `white-space` is not `pre`, multiple whitespaces are considered\n // as one.\n if (!remainingSpace) {\n remainingSpace = ' '\n }\n remainingSpaceWidth = measureWithCache([remainingSpace])\n wordsInLayout[i] = null\n } else {\n const forceBreak = shouldAlwaysBreakLine && word === '\\n'\n const w = forceBreak\n ? 0\n : graphemeImages && graphemeImages[word]\n ? (parentStyle.fontSize as number)\n : measureWithCache([word])\n\n // This is the start of the line, we can ignore all spaces here.\n if (!currentWidth) {\n remainingSpace = ''\n remainingSpaceWidth = 0\n }\n\n const allowedToPutAtBeginning =\n remainingSpaceWidth || ',.!?:-@)>]}%#'.indexOf(word[0]) < 0\n const allowedToJustify = !currentWidth || !!remainingSpaceWidth\n\n if (\n forceBreak ||\n (i &&\n allowedToPutAtBeginning &&\n currentWidth + remainingSpaceWidth + w > width &&\n whiteSpace !== 'nowrap' &&\n whiteSpace !== 'pre')\n ) {\n // Start a new line, spaces can be ignored.\n lineWidths.push(currentWidth)\n baselines.push(currentBaselineOffset)\n lines++\n height += currentLineHeight\n currentWidth = w\n currentLineHeight = w ? engine.glyphHeight(word) : 0\n currentBaselineOffset = w ? engine.baseline(word) : 0\n lineSegmentNumber.push(1)\n lineIndex = -1\n\n // If it's neturally breaked, we update the max width.\n // Since if there are multiple lines, the width should fit the\n // container.\n if (!forceBreak) {\n maxWidth = Math.max(maxWidth, width)\n }\n } else {\n // It fits into the current line.\n currentWidth += remainingSpaceWidth + w\n const glyphHeight = engine.glyphHeight(word)\n if (glyphHeight > currentLineHeight) {\n // Use the baseline of the heighest segment as the baseline of the line.\n currentLineHeight = glyphHeight\n currentBaselineOffset = engine.baseline(word)\n }\n if (allowedToJustify) {\n lineSegmentNumber[lineSegmentNumber.length - 1]++\n }\n }\n\n remainingSpace = ''\n remainingSpaceWidth = 0\n\n if (allowedToJustify) {\n lineIndex++\n }\n\n maxWidth = Math.max(maxWidth, currentWidth)\n wordsInLayout[i] = {\n y: height,\n x: currentWidth - w,\n width: w,\n line: lines,\n lineIndex,\n }\n }\n }\n if (currentWidth) {\n lines++\n lineWidths.push(currentWidth)\n baselines.push(currentBaselineOffset)\n height += currentLineHeight\n }\n\n // @TODO: Support `line-height`.\n return { width: maxWidth, height }\n })\n\n const [x, y] = yield\n\n let result = ''\n let backgroundClipDef = ''\n\n const clipPathId = inheritedStyle._inheritedClipPathId as string | undefined\n const {\n left: containerLeft,\n top: containerTop,\n width: containerWidth,\n height: containerHeight,\n } = textContainer.getComputedLayout()\n const parentContainerInnerWidth =\n parent.getComputedWidth() -\n parent.getComputedPadding(Yoga.EDGE_LEFT) -\n parent.getComputedPadding(Yoga.EDGE_RIGHT) -\n parent.getComputedBorder(Yoga.EDGE_LEFT) -\n parent.getComputedBorder(Yoga.EDGE_RIGHT)\n\n // Attach offset to the current node.\n const left = x + containerLeft\n const top = y + containerTop\n\n const { matrix, opacity } = container(\n {\n left: containerLeft,\n top: containerTop,\n width: containerWidth,\n height: containerHeight,\n isInheritingTransform,\n },\n parentStyle\n )\n\n let filter = ''\n if (parentStyle.textShadowOffset) {\n filter = shadow(\n {\n width: containerWidth,\n height: containerHeight,\n id,\n },\n {\n shadowColor: parentStyle.textShadowColor,\n shadowOffset: parentStyle.textShadowOffset,\n shadowRadius: parentStyle.textShadowRadius,\n }\n )\n }\n\n let decorationShape = ''\n let mergedPath = ''\n let extra = ''\n let skippedLine = -1\n let ellipsisWidth = textOverflow === 'ellipsis' ? measureWithCache(['…']) : 0\n let spaceWidth = textOverflow === 'ellipsis' ? measureWithCache([' ']) : 0\n let decorationLines: Record<number, null | number[]> = {}\n\n for (let i = 0; i < words.length; i++) {\n // Skip whitespace.\n if (!wordsInLayout[i]) continue\n const layout = wordsInLayout[i]\n\n let word = words[i]\n let path: string | null = null\n\n const image = graphemeImages ? graphemeImages[word] : null\n\n let topOffset = layout.y\n let leftOffset = layout.x\n const width = layout.width\n const line = layout.line\n\n if (line === skippedLine) {\n continue\n }\n\n // When `text-align` is `justify`, the width of the line will be adjusted.\n let extendedWidth = false\n\n if (lineWidths.length > 1) {\n // Calculate alignment. Note that for flexbox, there is only text\n // alignment when the container is multi-line.\n const remainingWidth = containerWidth - lineWidths[line]\n if (textAlign === 'right' || textAlign === 'end') {\n leftOffset += remainingWidth\n } else if (textAlign === 'center') {\n leftOffset += remainingWidth / 2\n } else if (textAlign === 'justify') {\n // Don't justify the last line.\n if (line < lineWidths.length - 1) {\n const segments = lineSegmentNumber[line]\n const gutter = segments > 1 ? remainingWidth / (segments - 1) : 0\n leftOffset += gutter * layout.lineIndex\n extendedWidth = true\n }\n }\n }\n\n if (!decorationLines[line]) {\n decorationLines[line] = [\n leftOffset,\n extendedWidth ? containerWidth : lineWidths[line],\n ]\n }\n\n if (textOverflow === 'ellipsis') {\n if (lineWidths[line] > parentContainerInnerWidth) {\n if (\n layout.x + width + ellipsisWidth + spaceWidth >\n parentContainerInnerWidth\n ) {\n const chars = segment(word, 'grapheme')\n let subset = ''\n let resolvedWidth = 0\n for (const char of chars) {\n const w = layout.x + measureWithCache([subset + char])\n if (\n // Keep at least one character:\n // > The first character or atomic inline-level element on a line\n // must be clipped rather than ellipsed.\n // https://drafts.csswg.org/css-overflow/#text-overflow\n subset &&\n w + ellipsisWidth > parentContainerInnerWidth\n ) {\n break\n }\n subset += char\n resolvedWidth = w\n }\n word = subset + '…'\n skippedLine = line\n decorationLines[line][1] = resolvedWidth\n }\n }\n }\n\n const baselineOfLine = baselines[line]\n const baselineOfWord = engine.baseline(word)\n const heightOfWord = engine.glyphHeight(word)\n const baselineDelta = baselineOfLine - baselineOfWord\n\n if (image) {\n // For images, we remove the baseline offset.\n topOffset += 0\n } else if (embedFont) {\n path = engine.getSVG(word, {\n ...parentStyle,\n left: left + leftOffset,\n // Since we need to pass the baseline position, add the ascender to the top.\n top: top + topOffset + baselineOfWord + baselineDelta,\n letterSpacing: parentStyle.letterSpacing,\n } as any)\n\n if (debug) {\n extra +=\n buildXMLString('rect', {\n x: left + leftOffset,\n y: top + topOffset + baselineDelta,\n width: layout.width,\n height: heightOfWord,\n fill: 'transparent',\n stroke: '#575eff',\n 'stroke-width': 1,\n transform: matrix ? matrix : undefined,\n 'clip-path': clipPathId ? `url(#${clipPathId})` : undefined,\n }) +\n // Baseline\n buildXMLString('line', {\n x1: left + leftOffset,\n x2: left + leftOffset + layout.width,\n y1: top + topOffset + baselineDelta + baselineOfWord,\n y2: top + topOffset + baselineDelta + baselineOfWord,\n stroke: '#14c000',\n 'stroke-width': 1,\n transform: matrix ? matrix : undefined,\n 'clip-path': clipPathId ? `url(#${clipPathId})` : undefined,\n })\n }\n } else {\n // We need manually add the font ascender height to ensure it starts\n // at the baseline because <text>'s alignment baseline is set to `hanging`\n // by default and supported to change in SVG 1.1.\n topOffset += baselineOfWord + baselineDelta\n }\n\n // Get the decoration shape.\n if (parentStyle.textDecorationLine) {\n // If it's the last word in the current line.\n if (line !== wordsInLayout[i + 1]?.line || skippedLine === line) {\n const deco = decorationLines[line]\n if (deco && !deco[2]) {\n decorationShape += decoration(\n {\n left: left + deco[0],\n top: top + heightOfWord * +line,\n width: deco[1],\n ascender: engine.baseline(word),\n clipPathId,\n },\n parentStyle\n )\n deco[2] = 1\n }\n }\n }\n\n if (path !== null) {\n mergedPath += path + ' '\n } else {\n const [t, shape] = text(\n {\n content: word,\n filter,\n id,\n left: left + leftOffset,\n top: top + topOffset,\n width,\n height: heightOfWord,\n matrix,\n opacity,\n image,\n clipPathId,\n debug,\n shape: !!_inheritedBackgroundClipTextPath,\n decorationShape,\n },\n parentStyle\n )\n result += t\n backgroundClipDef += shape\n decorationShape = ''\n }\n }\n\n // Embed the font as path.\n if (mergedPath) {\n const p =\n parentStyle.color !== 'transparent' && opacity !== 0\n ? buildXMLString('path', {\n fill: parentStyle.color,\n d: mergedPath,\n transform: matrix ? matrix : undefined,\n opacity: opacity !== 1 ? opacity : undefined,\n 'clip-path': clipPathId ? `url(#${clipPathId})` : undefined,\n\n style: cssFilter ? `filter:${cssFilter}` : undefined,\n })\n : ''\n\n if (!!_inheritedBackgroundClipTextPath) {\n backgroundClipDef = buildXMLString('path', {\n d: mergedPath,\n transform: matrix ? matrix : undefined,\n })\n }\n\n result +=\n (filter ? `${filter}<g filter=\"url(#satori_s-${id})\">` : '') +\n p +\n decorationShape +\n (filter ? '</g>' : '') +\n extra\n }\n\n // Attach information to the parent node.\n if (backgroundClipDef) {\n ;(parentStyle._inheritedBackgroundClipTextPath as any).value +=\n backgroundClipDef\n }\n\n return result\n}\n","// Copyright (c) 2014 Rafael Caricio. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nvar GradientParser = GradientParser || {}\n\nGradientParser.parse = (function () {\n var tokens = {\n linearGradient: /^(\\-(webkit|o|ms|moz)\\-)?(linear\\-gradient)/i,\n repeatingLinearGradient:\n /^(\\-(webkit|o|ms|moz)\\-)?(repeating\\-linear\\-gradient)/i,\n radialGradient: /^(\\-(webkit|o|ms|moz)\\-)?(radial\\-gradient)/i,\n repeatingRadialGradient:\n /^(\\-(webkit|o|ms|moz)\\-)?(repeating\\-radial\\-gradient)/i,\n sideOrCorner:\n /^to (left (top|bottom)|right (top|bottom)|top (left|right)|bottom (left|right)|left|right|top|bottom)/i,\n extentKeywords:\n /^(closest\\-side|closest\\-corner|farthest\\-side|farthest\\-corner|contain|cover)/,\n positionKeywords: /^(left|center|right|top|bottom)/i,\n pixelValue: /^(-?(([0-9]*\\.[0-9]+)|([0-9]+\\.?)))px/,\n percentageValue: /^(-?(([0-9]*\\.[0-9]+)|([0-9]+\\.?)))\\%/,\n emValue: /^(-?(([0-9]*\\.[0-9]+)|([0-9]+\\.?)))em/,\n angleValue: /^(-?(([0-9]*\\.[0-9]+)|([0-9]+\\.?)))deg/,\n startCall: /^\\(/,\n endCall: /^\\)/,\n comma: /^,/,\n hexColor: /^\\#([0-9a-fA-F]+)/,\n literalColor: /^([a-zA-Z]+)/,\n rgbColor: /^rgb/i,\n rgbaColor: /^rgba/i,\n number: /^(([0-9]*\\.[0-9]+)|([0-9]+\\.?))/,\n }\n\n var input = ''\n\n function error(msg) {\n var err = new Error(input + ': ' + msg)\n err.source = input\n throw err\n }\n\n function getAST() {\n var ast = matchListDefinitions()\n\n if (input.length > 0) {\n error('Invalid input not EOF')\n }\n\n return ast\n }\n\n function matchListDefinitions() {\n return matchListing(matchDefinition)\n }\n\n function matchDefinition() {\n return (\n matchGradient(\n 'linear-gradient',\n tokens.linearGradient,\n matchLinearOrientation\n ) ||\n matchGradient(\n 'repeating-linear-gradient',\n tokens.repeatingLinearGradient,\n matchLinearOrientation\n ) ||\n matchGradient(\n 'radial-gradient',\n tokens.radialGradient,\n matchListRadialOrientations\n ) ||\n matchGradient(\n 'repeating-radial-gradient',\n tokens.repeatingRadialGradient,\n matchListRadialOrientations\n )\n )\n }\n\n function matchGradient(gradientType, pattern, orientationMatcher) {\n return matchCall(pattern, function (captures) {\n var orientation = orientationMatcher()\n if (orientation) {\n if (!scan(tokens.comma)) {\n error('Missing comma before color stops')\n }\n }\n\n return {\n type: gradientType,\n orientation: orientation,\n colorStops: matchListing(matchColorStop),\n }\n })\n }\n\n function matchCall(pattern, callback) {\n var captures = scan(pattern)\n\n if (captures) {\n if (!scan(tokens.startCall)) {\n error('Missing (')\n }\n\n var result = callback(captures)\n\n if (!scan(tokens.endCall)) {\n error('Missing )')\n }\n\n return result\n }\n }\n\n function matchLinearOrientation() {\n return matchSideOrCorner() || matchAngle()\n }\n\n function matchSideOrCorner() {\n return match('directional', tokens.sideOrCorner, 1)\n }\n\n function matchAngle() {\n return match('angular', tokens.angleValue, 1)\n }\n\n function matchListRadialOrientations() {\n var radialOrientations,\n radialOrientation = matchRadialOrientation(),\n lookaheadCache\n\n if (radialOrientation) {\n radialOrientations = []\n radialOrientations.push(radialOrientation)\n\n lookaheadCache = input\n if (scan(tokens.comma)) {\n radialOrientation = matchRadialOrientation()\n if (radialOrientation) {\n radialOrientations.push(radialOrientation)\n } else {\n input = lookaheadCache\n }\n }\n }\n\n return radialOrientations\n }\n\n function matchRadialOrientation() {\n var radialType = matchCircle() || matchEllipse()\n\n if (radialType) {\n radialType.at = matchAtPosition()\n } else {\n var extent = matchExtentKeyword()\n if (extent) {\n radialType = extent\n var positionAt = matchAtPosition()\n if (positionAt) {\n radialType.at = positionAt\n }\n } else {\n var defaultPosition = matchPositioning()\n if (defaultPosition) {\n radialType = {\n type: 'default-radial',\n at: defaultPosition,\n }\n }\n }\n }\n\n return radialType\n }\n\n function matchCircle() {\n var circle = match('shape', /^(circle)/i, 0)\n\n if (circle) {\n circle.style = matchLength() || matchExtentKeyword()\n }\n\n return circle\n }\n\n function matchEllipse() {\n var ellipse = match('shape', /^(ellipse)/i, 0)\n\n if (ellipse) {\n ellipse.style = matchDistance() || matchExtentKeyword()\n }\n\n return ellipse\n }\n\n function matchExtentKeyword() {\n return match('extent-keyword', tokens.extentKeywords, 1)\n }\n\n function matchAtPosition() {\n if (match('position', /^at/, 0)) {\n var positioning = matchPositioning()\n\n if (!positioning) {\n error('Missing positioning value')\n }\n\n return positioning\n }\n }\n\n function matchPositioning() {\n var location = matchCoordinates()\n\n if (location.x || location.y) {\n return {\n type: 'position',\n value: location,\n }\n }\n }\n\n function matchCoordinates() {\n return {\n x: matchDistance(),\n y: matchDistance(),\n }\n }\n\n function matchListing(matcher) {\n var captures = matcher(),\n result = []\n\n if (captures) {\n result.push(captures)\n while (scan(tokens.comma)) {\n captures = matcher()\n if (captures) {\n result.push(captures)\n } else {\n error('One extra comma')\n }\n }\n }\n\n return result\n }\n\n function matchColorStop() {\n var color = matchColor()\n\n if (!color) {\n error('Expected color definition')\n }\n\n color.length = matchDistance()\n return color\n }\n\n function matchColor() {\n return (\n matchHexColor() ||\n matchRGBAColor() ||\n matchRGBColor() ||\n matchLiteralColor()\n )\n }\n\n function matchLiteralColor() {\n return match('literal', tokens.literalColor, 0)\n }\n\n function matchHexColor() {\n return match('hex', tokens.hexColor, 1)\n }\n\n function matchRGBColor() {\n return matchCall(tokens.rgbColor, function () {\n return {\n type: 'rgb',\n value: matchListing(matchNumber),\n }\n })\n }\n\n function matchRGBAColor() {\n return matchCall(tokens.rgbaColor, function () {\n return {\n type: 'rgba',\n value: matchListing(matchNumber),\n }\n })\n }\n\n function matchNumber() {\n return scan(tokens.number)[1]\n }\n\n function matchDistance() {\n return (\n match('%', tokens.percentageValue, 1) ||\n matchPositionKeyword() ||\n matchLength()\n )\n }\n\n function matchPositionKeyword() {\n return match('position-keyword', tokens.positionKeywords, 1)\n }\n\n function matchLength() {\n return match('px', tokens.pixelValue, 1) || match('em', tokens.emValue, 1)\n }\n\n function match(type, pattern, captureIndex) {\n var captures = scan(pattern)\n if (captures) {\n return {\n type: type,\n value: captures[captureIndex],\n }\n }\n }\n\n function scan(regexp) {\n var captures, blankCaptures\n\n blankCaptures = /^[\\n\\r\\t\\s]+/.exec(input)\n if (blankCaptures) {\n consume(blankCaptures[0].length)\n }\n\n captures = regexp.exec(input)\n if (captures) {\n consume(captures[0].length)\n }\n\n return captures\n }\n\n function consume(size) {\n input = input.substr(size)\n }\n\n return function (code) {\n input = code.toString()\n return getAST()\n }\n})()\n\nexport default GradientParser\n","import CssDimension from '../vendor/parse-css-dimension'\nimport { buildXMLString } from '../utils'\n\nimport gradient from '../vendor/gradient-parser'\n\ninterface Background {\n attachment: string\n color?: string\n clip: string\n image: string\n origin: string\n position: string\n size: string\n repeat: string\n}\n\nfunction resolveColorFromStop(stop) {\n if (stop.type === 'literal') return stop.value\n if (stop.type === 'hex') return `#${stop.value}`\n if (stop.type === 'rgb') return `rgb(${stop.value.join(',')})`\n if (stop.type === 'rgba') return `rgba(${stop.value.join(',')})`\n return 'transparent'\n}\n\nfunction toAbsoluteValue(v: string | number, base: number) {\n if (typeof v === 'string' && v.endsWith('%')) {\n return (base * parseFloat(v)) / 100\n }\n return +v\n}\n\nfunction parseLengthPairs(\n str: string,\n {\n x,\n y,\n defaultX,\n defaultY,\n }: {\n x: number\n y: number\n defaultX: number | string\n defaultY: number | string\n }\n) {\n return (\n str\n ? str\n .split(' ')\n .map((value) => {\n try {\n const parsed = new CssDimension(value)\n return parsed.type === 'length' || parsed.type === 'number'\n ? parsed.value\n : parsed.value + parsed.unit\n } catch (e) {\n return null\n }\n })\n .filter((v) => v !== null)\n : [defaultX, defaultY]\n ).map((v, index) => toAbsoluteValue(v, [x, y][index]))\n}\n\nfunction normalizeStops(totalLength: number, colorStops: any[]) {\n // Resolve the color stops based on the spec:\n // https://drafts.csswg.org/css-images/#color-stop-syntax\n const stops = []\n for (const stop of colorStops) {\n const color = resolveColorFromStop(stop)\n if (!stops.length) {\n // First stop, ensure it's at the start.\n stops.push({\n offset: 0,\n color,\n })\n\n if (typeof stop.length === 'undefined') continue\n if (stop.length.value === '0') continue\n }\n\n // All offsets are relative values (0-1) in SVG.\n const offset =\n typeof stop.length === 'undefined'\n ? undefined\n : stop.length.type === '%'\n ? stop.length.value / 100\n : stop.length.value / totalLength\n\n stops.push({\n offset,\n color,\n })\n }\n if (!stops.length) {\n stops.push({\n offset: 0,\n color: 'transparent',\n })\n }\n // Last stop, ensure it's at the end.\n const lastStop = stops[stops.length - 1]\n if (lastStop.offset !== 1) {\n if (typeof lastStop.offset === 'undefined') {\n lastStop.offset = 1\n } else {\n stops.push({\n offset: 1,\n color: lastStop.color,\n })\n }\n }\n\n let previousStop = 0\n let nextStop = 1\n // Evenly distribute the missing stop offsets.\n for (let i = 0; i < stops.length; i++) {\n if (typeof stops[i].offset === 'undefined') {\n // Find the next stop that has an offset.\n if (nextStop < i) nextStop = i\n while (typeof stops[nextStop].offset === 'undefined') nextStop++\n\n stops[i].offset =\n ((stops[nextStop].offset - stops[previousStop].offset) /\n (nextStop - previousStop)) *\n (i - previousStop) +\n stops[previousStop].offset\n } else {\n previousStop = i\n }\n }\n\n return stops\n}\n\nexport default function backgroundImage(\n { id, width, height }: { id: string; width: number; height: number },\n { image, size, position, repeat }: Background\n): string[] {\n // Default to `repeat`.\n repeat = repeat || 'repeat'\n\n const repeatX = repeat === 'repeat-x' || repeat === 'repeat'\n const repeatY = repeat === 'repeat-y' || repeat === 'repeat'\n\n const dimensions = parseLengthPairs(size, {\n x: width,\n y: height,\n defaultX: width,\n defaultY: height,\n })\n const offsets = parseLengthPairs(position, {\n x: width,\n y: height,\n defaultX: 0,\n defaultY: 0,\n })\n\n if (image.startsWith('linear-gradient(')) {\n const parsed = gradient.parse(image)[0]\n\n // Calculate the direction.\n let x1, y1, x2, y2\n if (parsed.orientation.type === 'directional') {\n ;[x1, y1, x2, y2] = {\n top: [0, 1, 0, 0],\n bottom: [0, 0, 0, 1],\n left: [1, 0, 0, 0],\n right: [0, 0, 1, 0],\n }[parsed.orientation.value]\n } else if (parsed.orientation.type === 'angular') {\n const angle = (+parsed.orientation.value / 180) * Math.PI - Math.PI / 2\n const c = Math.cos(angle)\n const s = Math.sin(angle)\n\n x1 = 0\n y1 = 0\n x2 = c\n y2 = s\n if (x2 < 0) {\n x1 -= x2\n x2 = 0\n }\n if (y2 < 0) {\n y1 -= y2\n y2 = 0\n }\n }\n\n const stops = normalizeStops(width, parsed.colorStops)\n\n return [\n `satori_bi${id}`,\n `<linearGradient id=\"satori_bi${id}\" x1=\"${x1}\" y1=\"${y1}\" x2=\"${x2}\" y2=\"${y2}\">${stops\n .map(\n (stop) =>\n `<stop offset=\"${stop.offset * 100}%\" stop-color=\"${stop.color}\"/>`\n )\n .join('')}</linearGradient>`,\n ]\n }\n\n if (image.startsWith('radial-gradient(')) {\n const parsed = gradient.parse(image)[0]\n const orientation = parsed.orientation[0]\n const [xDelta, yDelta] = dimensions\n\n let shape = 'circle'\n let cx: number = xDelta / 2\n let cy: number = yDelta / 2\n\n if (orientation.type === 'shape') {\n shape = orientation.value\n if (!orientation.at) {\n // Defaults to center.\n } else if (orientation.at.type === 'position') {\n cx = orientation.at.value.x.value\n cy = orientation.at.value.y.value\n } else {\n throw new Error(\n 'orientation.at.type not implemented: ' + orientation.at.type\n )\n }\n } else {\n throw new Error('orientation.type not implemented: ' + orientation.type)\n }\n\n const stops = normalizeStops(width, parsed.colorStops)\n\n const gradientId = `satori_radial_${id}`\n const patternId = `satori_pattern_${id}`\n\n // We currently only support `farthest-corner`:\n // https://developer.mozilla.org/en-US/docs/Web/CSS/gradient/radial-gradient()#values\n const spread: Record<string, number> = {}\n\n // Farest corner.\n const fx = Math.max(Math.abs(xDelta - cx), Math.abs(cx))\n const fy = Math.max(Math.abs(yDelta - cy), Math.abs(cy))\n if (shape === 'circle') {\n spread.r = Math.sqrt(fx * fx + fy * fy)\n } else if (shape === 'ellipse') {\n // Spec: https://drafts.csswg.org/css-images/#typedef-size\n // Get the aspect ratio of the closest-side size.\n const ratio = fy !== 0 ? fx / fy : 1\n\n // fx^2/a^2 + fy^2/b^2 = 1\n // fx^2/(b*ratio)^2 + fy^2/b^2 = 1\n // (fx^2+fy^2*ratio^2) = (b*ratio)^2\n // b = sqrt(fx^2+fy^2*ratio^2)/ratio\n spread.ry = Math.sqrt(fx * fx + fy * fy * ratio * ratio) / ratio\n spread.rx = spread.ry * ratio\n }\n\n // TODO: check for repeat-x/repeat-y\n const defs = buildXMLString(\n 'pattern',\n {\n id: patternId,\n x: offsets[0],\n y: offsets[1],\n width: repeatX ? xDelta : '100%',\n height: repeatY ? yDelta : '100%',\n patternUnits: 'userSpaceOnUse',\n },\n buildXMLString(\n 'radialGradient',\n {\n id: gradientId,\n },\n stops\n .map((stop) =>\n buildXMLString('stop', {\n offset: stop.offset,\n 'stop-color': stop.color,\n })\n )\n .join('')\n ) +\n buildXMLString(shape, {\n cx: cx,\n cy: cy,\n width: xDelta,\n height: yDelta,\n ...spread,\n fill: `url(#${gradientId})`,\n })\n )\n\n const result = [patternId, defs]\n return result\n }\n\n if (image.startsWith('url(')) {\n const src = image.slice(4, -1)\n return [\n `satori_bi${id}`,\n buildXMLString(\n 'pattern',\n {\n id: `satori_bi${id}`,\n patternContentUnits: 'userSpaceOnUse',\n patternUnits: 'userSpaceOnUse',\n x: offsets[0],\n y: offsets[1],\n width: repeatX ? dimensions[0] : '100%',\n height: repeatY ? dimensions[1] : '100%',\n },\n buildXMLString('image', {\n x: 0,\n y: 0,\n width: dimensions[0],\n height: dimensions[1],\n href: src,\n })\n ),\n ]\n }\n}\n","/**\n * CSS border radius to SVG path.\n */\n\nfunction resolveSize(a: number, b: number, limit: number) {\n if (limit < a + b) {\n if (limit / 2 < a && limit / 2 < b) {\n a = b = limit / 2\n } else if (limit / 2 < a) {\n a = limit - b\n } else if (limit / 2 < b) {\n b = limit - a\n }\n }\n return [a, b]\n}\n\nexport default function radius(\n {\n left,\n top,\n width,\n height,\n }: {\n left: number\n top: number\n width: number\n height: number\n },\n style: Record<string, number>\n) {\n let {\n borderTopLeftRadius,\n borderTopRightRadius,\n borderBottomLeftRadius,\n borderBottomRightRadius,\n } = style\n\n borderTopLeftRadius = Math.min(borderTopLeftRadius || 0, width, height)\n borderTopRightRadius = Math.min(borderTopRightRadius || 0, width, height)\n borderBottomLeftRadius = Math.min(borderBottomLeftRadius || 0, width, height)\n borderBottomRightRadius = Math.min(\n borderBottomRightRadius || 0,\n width,\n height\n )\n\n if (\n !borderTopLeftRadius &&\n !borderTopRightRadius &&\n !borderBottomLeftRadius &&\n !borderBottomRightRadius\n ) {\n return ''\n }\n\n // Limit the radius size.\n ;[borderTopLeftRadius, borderTopRightRadius] = resolveSize(\n borderTopLeftRadius,\n borderTopRightRadius,\n width\n )\n ;[borderTopLeftRadius, borderBottomLeftRadius] = resolveSize(\n borderTopLeftRadius,\n borderBottomLeftRadius,\n height\n )\n ;[borderTopRightRadius, borderBottomRightRadius] = resolveSize(\n borderTopRightRadius,\n borderBottomRightRadius,\n height\n )\n ;[borderBottomLeftRadius, borderBottomRightRadius] = resolveSize(\n borderBottomLeftRadius,\n borderBottomRightRadius,\n width\n )\n\n // Generate the path (GitHub Copilot wrote these for me).\n return `M${left + borderTopLeftRadius},${top} h${\n width - borderTopLeftRadius - borderTopRightRadius\n } a${borderTopRightRadius},${borderTopRightRadius} 0 0 1 ${borderTopRightRadius},${borderTopRightRadius} v${\n height - borderTopRightRadius - borderBottomRightRadius\n } a${borderBottomRightRadius},${borderBottomRightRadius} 0 0 1 ${-borderBottomRightRadius},${borderBottomRightRadius} h${\n borderBottomRightRadius + borderBottomLeftRadius - width\n } a${borderBottomLeftRadius},${borderBottomLeftRadius} 0 0 1 ${-borderBottomLeftRadius},${-borderBottomLeftRadius} v${\n borderBottomLeftRadius + borderTopLeftRadius - height\n } a${borderTopLeftRadius},${borderTopLeftRadius} 0 0 1 ${borderTopLeftRadius},${-borderTopLeftRadius}`\n}\n","/**\n * Generate clip path for the given element.\n */\n\nimport { buildXMLString } from '../utils'\n\nexport default function overflow(\n {\n left,\n top,\n width,\n height,\n path,\n id,\n }: {\n left: number\n top: number\n width: number\n height: number\n path: string\n id: string\n },\n style: Record<string, string | number>\n) {\n if (style.overflow !== 'hidden') {\n return ''\n }\n\n if (path) {\n // <clipPath id=\"myClip\"><circle cx=\"40\" cy=\"35\" r=\"35\" /></clipPath>\n return buildXMLString(\n 'clipPath',\n {\n id: `satori_cp-${id}`,\n 'clip-path': style._inheritedClipPathId\n ? `url(#${style._inheritedClipPathId})`\n : undefined,\n },\n buildXMLString('path', {\n x: left,\n y: top,\n width,\n height,\n d: path,\n })\n )\n }\n return buildXMLString(\n 'clipPath',\n {\n id: `satori_cp-${id}`,\n 'clip-path': style._inheritedClipPathId\n ? `url(#${style._inheritedClipPathId})`\n : undefined,\n },\n buildXMLString('rect', {\n x: left,\n y: top,\n width,\n height,\n })\n )\n}\n","import type { ParsedTransformOrigin } from '../transform-origin'\n\nimport backgroundImage from './background-image'\nimport radius from './border-radius'\nimport shadow from './shadow'\nimport transform from './transform'\nimport overflow from './overflow'\nimport { buildXMLString } from '../utils'\n\nexport default function rect(\n {\n id,\n left,\n top,\n width,\n height,\n isInheritingTransform,\n debug,\n }: {\n id: string\n left: number\n top: number\n width: number\n height: number\n isInheritingTransform: boolean\n debug?: boolean\n },\n style: Record<string, number | string>\n) {\n if (style.display === 'none') return ''\n\n let type = 'rect'\n let stroke = 'transparent'\n let strokeWidth = 0\n let matrix = ''\n let defs = ''\n let fills: string[] = []\n let opacity = 1\n let extra = ''\n\n if (style.backgroundColor) {\n fills.push(style.backgroundColor as string)\n }\n\n if (style.borderWidth) {\n strokeWidth = style.borderWidth as number\n stroke = style.borderColor as string\n }\n\n if (style.opacity) {\n opacity = +style.opacity\n }\n\n if (style.transform) {\n matrix = transform(\n {\n left,\n top,\n width,\n height,\n },\n style.transform as unknown as number[],\n isInheritingTransform,\n style.transformOrigin as ParsedTransformOrigin | undefined\n )\n }\n\n let backgroundShapes = ''\n if (style.backgroundImage) {\n const backgrounds: string[] = (style.backgroundImage as any)\n .map((background, index) =>\n backgroundImage({ id: id + '_' + index, width, height }, background)\n )\n .filter(Boolean)\n for (const background of backgrounds) {\n fills.push(`url(#${background[0]})`)\n defs += background[1]\n if (background[2]) {\n backgroundShapes += background[2]\n }\n }\n }\n\n const path = radius(\n { left, top, width, height },\n style as Record<string, number>\n )\n if (path) {\n type = 'path'\n }\n\n const clip = overflow(\n { left, top, width, height, path, id },\n style as Record<string, number>\n )\n const clipPathId = style._inheritedClipPathId as number | undefined\n\n const filter = shadow({ width, height, id }, style)\n\n if (debug) {\n extra = buildXMLString('rect', {\n x: left,\n y: top,\n width,\n height,\n fill: 'transparent',\n stroke: '#ff5757',\n 'stroke-width': 1,\n transform: matrix || undefined,\n 'clip-path': clipPathId ? `url(#${clipPathId})` : undefined,\n })\n }\n\n if (!fills.length) fills.push('transparent')\n\n const { backgroundClip, filter: cssFilter } = style\n\n // Each background generates a new rectangle.\n // @TODO: Not sure if this is the best way to do it, maybe <pattern> with\n // multiple <image>s is better.\n let shape = fills\n .map((fill, i) => {\n if (fill === 'transparent' && !(i === fills.length - 1 && strokeWidth)) {\n return ''\n }\n\n const hasStroke =\n i === fills.length - 1 && strokeWidth && backgroundClip !== 'text'\n return buildXMLString(type, {\n x: left,\n y: top,\n width,\n height,\n fill,\n stroke: hasStroke ? stroke : undefined,\n 'stroke-width': hasStroke ? strokeWidth : undefined,\n d: path ? path : undefined,\n transform: matrix ? matrix : undefined,\n 'clip-path':\n backgroundClip === 'text'\n ? `url(#satori_bct-${id})`\n : clipPathId\n ? `url(#${clipPathId})`\n : undefined,\n style: cssFilter ? `filter:${cssFilter}` : undefined,\n })\n })\n .join('')\n\n // When using `background-clip: text`, we need to draw the extra border.\n if (backgroundClip === 'text' && strokeWidth) {\n shape =\n buildXMLString(type, {\n x: left,\n y: top,\n width,\n height,\n fill: 'transparent',\n stroke,\n 'stroke-width': strokeWidth,\n d: path ? path : undefined,\n transform: matrix ? matrix : undefined,\n 'clip-path': clipPathId ? `url(#${clipPathId})` : undefined,\n }) + shape\n }\n\n return (\n (defs ? `<defs>${defs}</defs>` : '') +\n clip +\n (filter ? `${filter}<g filter=\"url(#satori_s-${id})\">` : '') +\n (opacity !== 1 ? `<g opacity=\"${opacity}\">` : '') +\n (backgroundShapes || shape) +\n (opacity !== 1 ? `</g>` : '') +\n (filter ? '</g>' : '') +\n extra\n )\n}\n","import type { ParsedTransformOrigin } from '../transform-origin'\n\nimport { buildXMLString } from '../utils'\nimport radius from './border-radius'\nimport shadow from './shadow'\nimport transform from './transform'\n\nexport default function image(\n {\n id,\n left,\n top,\n width,\n height,\n src,\n debug,\n isInheritingTransform,\n }: {\n id: string\n left: number\n top: number\n width: number\n height: number\n src: string\n isInheritingTransform: boolean\n debug?: boolean\n },\n style: Record<string, number | string>\n) {\n if (style.display === 'none') return ''\n\n let clip = ''\n let opacity = 1\n let matrix = ''\n\n const preserveAspectRatio =\n style.objectFit === 'contain'\n ? 'xMidYMid'\n : style.objectFit === 'cover'\n ? 'xMidYMid slice'\n : 'none'\n\n const path = radius(\n { left, top, width, height },\n style as Record<string, number>\n )\n\n const clipPathId = style._inheritedClipPathId as number | undefined\n if (path) {\n clip = buildXMLString(\n 'clipPath',\n {\n id: `satori_c-${id}`,\n 'clip-path': clipPathId ? `url(#${clipPathId})` : undefined,\n },\n buildXMLString('path', {\n x: left,\n y: top,\n width,\n height,\n d: path,\n })\n )\n }\n\n if (style.opacity) {\n opacity = +style.opacity\n }\n\n const filter = shadow({ width, height, id }, style)\n\n if (style.transform) {\n matrix = transform(\n {\n left,\n top,\n width,\n height,\n },\n style.transform as unknown as number[],\n isInheritingTransform,\n style.transformOrigin as ParsedTransformOrigin | undefined\n )\n }\n\n return (\n filter +\n (filter ? `<g filter=\"url(#satori_s-${id})\">` : '') +\n clip +\n buildXMLString('image', {\n x: left,\n y: top,\n width,\n height,\n href: src,\n preserveAspectRatio,\n transform: matrix ? matrix : undefined,\n 'clip-path': clip\n ? `url(#satori_c-${id})`\n : clipPathId\n ? `url(#${clipPathId})`\n : undefined,\n }) +\n (filter ? `</g>` : '')\n )\n}\n","/**\n * This module is used to calculate the layout of the current sub-tree.\n */\n\nimport type { ReactNode } from 'react'\nimport type { YogaNode } from 'yoga-layout'\n\nimport getYoga from './yoga'\nimport { isReactElement, isClass, buildXMLString } from './utils'\nimport handler from './handler'\nimport FontLoader from './font'\nimport layoutText from './text'\nimport rect from './builder/rect'\nimport image from './builder/image'\n\nexport interface LayoutContext {\n id: string\n parentStyle: Record<string, number | string>\n inheritedStyle: Record<string, number | string>\n isInheritingTransform?: boolean\n parent: YogaNode\n font: FontLoader\n embedFont: boolean\n debug?: boolean\n graphemeImages?: Record<string, string>\n canLoadAdditionalAssets: boolean\n}\n\nexport default function* layout(\n element: ReactNode,\n context: LayoutContext\n): Generator<string[], string, [number, number]> {\n const Yoga = getYoga()\n const {\n id,\n inheritedStyle,\n parent,\n font,\n debug,\n embedFont = true,\n graphemeImages,\n canLoadAdditionalAssets,\n } = context\n\n // 1. Pre-process the node.\n if (element === null || typeof element === 'undefined') {\n yield\n yield\n return ''\n }\n\n // Not a normal element.\n if (!isReactElement(element) || typeof element.type === 'function') {\n let iter: ReturnType<typeof layout>\n\n if (!isReactElement(element)) {\n // Process as text node.\n iter = layoutText(String(element), context)\n yield iter.next().value as string[]\n } else {\n if (isClass(element.type as Function)) {\n throw new Error('Class component is not supported.')\n }\n // If it's a custom component, Satori strictly requires it to be pure,\n // stateless, and not relying on any React APIs such as hooks or suspense.\n // So we can safely evaluate it to render. Otherwise, an error will be\n // thrown by React.\n iter = layout((element.type as Function)(element.props), context)\n yield iter.next().value as string[]\n }\n\n iter.next()\n const offset = yield\n return iter.next(offset).value as string\n }\n\n // Process as element.\n const { type, props } = element\n const { style, children } = props\n\n const node = Yoga.Node.create()\n parent.insertChild(node, parent.getChildCount())\n\n const [computedStyle, newInheritableStyle] = handler(\n node,\n type,\n inheritedStyle,\n style,\n props\n )\n\n // Post-process styles to attach inheritable properties for Satori.\n\n // If the element is inheriting the parent `transform`, or applying its own.\n // This affects the coordinate system.\n const isInheritingTransform =\n computedStyle.transform === inheritedStyle.transform\n if (!isInheritingTransform) {\n ;(computedStyle.transform as any).__parent = inheritedStyle.transform\n }\n\n // If the element has `overflow` set to `hidden`, we need to create a clip\n // path and use it in all its children.\n if (computedStyle.overflow === 'hidden') {\n newInheritableStyle._inheritedClipPathId = `satori_cp-${id}`\n }\n\n // If the element has `background-clip: text` set, we need to create a clip\n // path and use it in all its children.\n if (computedStyle.backgroundClip === 'text') {\n const mutateRefValue = { value: '' } as any\n newInheritableStyle._inheritedBackgroundClipTextPath = mutateRefValue\n computedStyle._inheritedBackgroundClipTextPath = mutateRefValue\n }\n\n // 2. Do layout recursively for its children.\n const normalizedChildren =\n typeof children === 'undefined' ? [] : [].concat(children)\n const iterators: ReturnType<typeof layout>[] = []\n\n let i = 0\n const segmentsMissingFont: string[] = []\n for (const child of normalizedChildren) {\n const iter = layout(child, {\n id: id + '-' + i++,\n parentStyle: computedStyle,\n inheritedStyle: newInheritableStyle,\n isInheritingTransform: true,\n parent: node,\n font,\n embedFont,\n debug,\n graphemeImages,\n canLoadAdditionalAssets,\n })\n if (canLoadAdditionalAssets) {\n segmentsMissingFont.push(...((iter.next().value as any) || []))\n } else {\n iter.next()\n }\n iterators.push(iter)\n }\n yield segmentsMissingFont\n for (const iter of iterators) iter.next()\n\n // 3. Post-process the node.\n const [x, y] = yield\n\n if (computedStyle.position === 'absolute') {\n node.calculateLayout()\n }\n\n let { left, top, width, height } = node.getComputedLayout()\n\n // Attach offset to the current node.\n left += x\n top += y\n\n let childrenRenderResult = ''\n let baseRenderResult = ''\n let depsRenderResult = ''\n\n // Generate the rendered markup for the current node.\n if (type === 'img') {\n baseRenderResult = image(\n {\n id,\n left,\n top,\n width,\n height,\n src: props.src,\n isInheritingTransform,\n debug,\n },\n computedStyle\n )\n } else {\n baseRenderResult = rect(\n { id, left, top, width, height, isInheritingTransform, debug },\n computedStyle\n )\n }\n\n // Generate the rendered markup for the children.\n for (const iter of iterators) {\n childrenRenderResult += iter.next([left, top]).value\n }\n\n // An extra pass to generate the special background-clip shape collected from\n // children.\n if (computedStyle._inheritedBackgroundClipTextPath) {\n depsRenderResult += buildXMLString(\n 'clipPath',\n {\n id: `satori_bct-${id}`,\n 'clip-path': computedStyle._inheritedClipPathId\n ? `url(#${computedStyle._inheritedClipPathId})`\n : undefined,\n },\n (computedStyle._inheritedBackgroundClipTextPath as any).value\n )\n }\n\n return depsRenderResult + baseRenderResult + childrenRenderResult\n}\n","/**\n * This class handles everything related to fonts.\n */\nimport opentype from '@shuding/opentype.js'\n\nimport { segment } from './utils'\n\ntype Weight = 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900\ntype WeigthName = 'normal' | 'bold'\ntype Style = 'normal' | 'italic'\n\nexport interface FontOptions {\n data: Buffer | ArrayBuffer\n name: string\n weight?: Weight\n style?: Style\n}\n\nfunction compareFont(weight, style, [weight1, style1], [weight2, style2]) {\n if (weight1 !== weight2) {\n // Put the defined weight first.\n if (!weight1) return 1\n if (!weight2) return -1\n\n // Exact match.\n if (weight1 === weight) return -1\n if (weight2 === weight) return 1\n\n // 400 and 500.\n if (weight === 400 && weight1 === 500) return -1\n if (weight === 500 && weight1 === 400) return -1\n if (weight === 400 && weight2 === 500) return 1\n if (weight === 500 && weight2 === 400) return 1\n\n // Less than 400.\n if (weight < 400) {\n if (weight1 < weight && weight2 < weight) return weight2 - weight1\n if (weight1 < weight) return -1\n if (weight2 < weight) return 1\n return weight1 - weight2\n }\n\n // Greater than 500.\n if (weight < weight1 && weight < weight2) return weight1 - weight2\n if (weight < weight1) return -1\n if (weight < weight2) return 1\n return weight2 - weight1\n }\n\n if (style1 !== style2) {\n // Exact match.\n if (style1 === style) return -1\n if (style2 === style) return 1\n }\n\n return -1\n}\n\nexport default class FontLoader {\n defaultFont: opentype.Font\n fonts = new Map<string, [opentype.Font, Weight?, Style?][]>()\n constructor(fontOptions: FontOptions[]) {\n this.addFonts(fontOptions)\n }\n\n // Get font by name and weight.\n private get({\n name,\n weight,\n style,\n }: {\n name: string\n weight: Weight | WeigthName\n style: Style\n }) {\n if (!this.fonts.has(name)) {\n return null\n }\n\n if (weight === 'normal') weight = 400\n if (weight === 'bold') weight = 700\n\n const fonts = [...this.fonts.get(name)]\n\n let matchedFont = fonts[0]\n\n // Fallback to the closest weight and style according to the strategy here:\n // https://developer.mozilla.org/en-US/docs/Web/CSS/font-weight#fallback_weights\n for (let i = 1; i < fonts.length; i++) {\n const [, weight1, style1] = matchedFont\n const [, weight2, style2] = fonts[i]\n if (\n compareFont(weight, style, [weight1, style1], [weight2, style2]) > 0\n ) {\n matchedFont = fonts[i]\n }\n }\n\n return matchedFont[0]\n }\n\n public addFonts(fontOptions: FontOptions[]) {\n for (const fontOption of fontOptions) {\n const data = fontOption.data\n const font = opentype.parse(\n // Buffer to ArrayBuffer.\n 'buffer' in data\n ? data.buffer.slice(\n data.byteOffset,\n data.byteOffset + data.byteLength\n )\n : data,\n // @ts-ignore\n { lowMemory: true }\n )\n\n // Modify the `charToGlyphIndex` method, so we can know which char is\n // being mapped to which glyph.\n const originalCharToGlyphIndex = font.charToGlyphIndex\n font.charToGlyphIndex = (char) => {\n const index = originalCharToGlyphIndex.call(font, char)\n if (index === 0) {\n // The current requested char is missing a glyph.\n if ((font as any)._trackBrokenChars) {\n ;(font as any)._trackBrokenChars.push(char)\n }\n }\n return index\n }\n\n // We use the first font as the default font fallback.\n if (!this.defaultFont) this.defaultFont = font\n\n const name = fontOption.name.toLowerCase()\n if (!this.fonts.has(name)) {\n this.fonts.set(name, [])\n }\n this.fonts.get(name).push([font, fontOption.weight, fontOption.style])\n }\n }\n\n public getEngine(\n fontSize = 16,\n lineHeight = 1.2,\n {\n fontFamily,\n fontWeight = 400,\n fontStyle = 'normal',\n }: {\n fontFamily: string | string[]\n fontWeight?: Weight | WeigthName\n fontStyle?: Style\n }\n ) {\n fontFamily = Array.isArray(fontFamily) ? fontFamily : [fontFamily]\n const fonts = fontFamily\n .map((face) =>\n this.get({\n name: face,\n weight: fontWeight,\n style: fontStyle,\n })\n )\n .filter(Boolean)\n\n // Add additional fonts as the fallback.\n const keys = Array.from(this.fonts.keys())\n for (const name of keys) {\n if (fontFamily.includes(name)) continue\n fonts.push(\n this.get({\n name,\n weight: fontWeight,\n style: fontStyle,\n })\n )\n }\n\n const cachedFontResolver = new Map<number, opentype.Font | undefined>()\n const resolveFont = (word: string, fallback = true) => {\n const code = word.charCodeAt(0)\n if (cachedFontResolver.has(code)) return cachedFontResolver.get(code)\n\n const font = fonts.find((font, index) => {\n return (\n !!font.charToGlyphIndex(word) ||\n (fallback && index === fonts.length - 1)\n )\n })\n\n if (font) {\n cachedFontResolver.set(code, font)\n }\n return font\n }\n\n const ascender = (resolvedFont: opentype.Font, useOS2Table = false) => {\n const ascender =\n (useOS2Table ? resolvedFont.tables?.os2?.sTypoAscender : 0) ||\n resolvedFont.ascender\n return (ascender / resolvedFont.unitsPerEm) * fontSize\n }\n const descender = (resolvedFont: opentype.Font, useOS2Table = false) => {\n const descender =\n (useOS2Table ? resolvedFont.tables?.os2?.sTypoDescender : 0) ||\n resolvedFont.descender\n return (descender / resolvedFont.unitsPerEm) * fontSize\n }\n\n const resolve = (s: string) => {\n return resolveFont(s, false)\n }\n\n const engine = {\n check: (s: string) => {\n const font = resolve(s)\n if (!font) return false\n ;(font as any)._trackBrokenChars = []\n font.stringToGlyphs(s)\n if (!(font as any)._trackBrokenChars.length) return true\n ;(font as any)._trackBrokenChars = undefined\n return false\n },\n baseline: (\n s?: string,\n resolvedFont = typeof s === 'undefined' ? fonts[0] : resolveFont(s)\n ) => {\n // https://www.w3.org/TR/CSS2/visudet.html#leading\n // Note. It is recommended that implementations that use OpenType or\n // TrueType fonts use the metrics \"sTypoAscender\" and \"sTypoDescender\"\n // from the font's OS/2 table for A and D (after scaling to the current\n // element's font size). In the absence of these metrics, the \"Ascent\"\n // and \"Descent\" metrics from the HHEA table should be used.\n const A = ascender(resolvedFont, true)\n const D = descender(resolvedFont, true)\n const sGlyphHeight = A - D\n const glyphHeight = engine.glyphHeight(s, resolvedFont)\n const sTypoOffset = (glyphHeight - sGlyphHeight) / 2\n const { yMax, yMin } = resolvedFont.tables.head\n const baseline = yMax / (yMax - yMin)\n\n return sTypoOffset + baseline * glyphHeight\n },\n glyphHeight: (\n s?: string,\n resolvedFont = typeof s === 'undefined' ? fonts[0] : resolveFont(s)\n ) => {\n return (\n ((ascender(resolvedFont) - descender(resolvedFont)) * lineHeight) /\n 1.2\n )\n },\n measure: (s: string, style: any) => {\n return this.measure(resolveFont, s, style)\n },\n getSVG: (s: string, style: any) => {\n return this.getSVG(resolveFont, s, style)\n },\n }\n\n return engine\n }\n\n private patchFontFallbackResolver(\n font: opentype.Font,\n resolveFont: (word: string, fallback?: boolean) => opentype.Font\n ) {\n const brokenChars = []\n ;(font as any)._trackBrokenChars = brokenChars\n\n const originalStringToGlyphs = font.stringToGlyphs\n font.stringToGlyphs = (s: string, ...args: any) => {\n const glyphs = originalStringToGlyphs.call(font, s, ...args)\n\n for (let i = 0; i < glyphs.length; i++) {\n // Hitting an undefined glyph. We have to try to resolve it from other\n // fonts.\n // @TODO: This affects the kerning resolution but should be fine for now.\n if (glyphs[i].unicode === undefined) {\n const char = brokenChars.shift()\n const anotherFont = resolveFont(char)\n if (anotherFont !== font) {\n glyphs[i] = anotherFont.charToGlyph(char)\n }\n }\n }\n\n return glyphs\n }\n\n return () => {\n font.stringToGlyphs = originalStringToGlyphs\n ;(font as any)._trackBrokenChars = undefined\n }\n }\n\n private measure(\n resolveFont: (word: string, fallback?: boolean) => opentype.Font,\n content: string,\n {\n fontSize,\n letterSpacing = 0,\n }: {\n fontSize: number\n letterSpacing: number\n }\n ) {\n const font = resolveFont(content)\n const unpatch = this.patchFontFallbackResolver(font, resolveFont)\n\n try {\n return font.getAdvanceWidth(content, fontSize, {\n letterSpacing: letterSpacing / fontSize,\n })\n } finally {\n unpatch()\n }\n }\n\n private getSVG(\n resolveFont: (word: string, fallback?: boolean) => opentype.Font,\n content: string,\n {\n fontSize,\n top,\n left,\n letterSpacing = 0,\n }: {\n fontSize: number\n top: number\n left: number\n letterSpacing: number\n }\n ) {\n const font = resolveFont(content)\n const unpatch = this.patchFontFallbackResolver(font, resolveFont)\n\n try {\n return font\n .getPath(content, left, top, fontSize, {\n letterSpacing: letterSpacing / fontSize,\n })\n .toPathData(1)\n } finally {\n unpatch()\n }\n }\n}\n","import { buildXMLString } from '../utils'\n\nexport default function svg({\n width,\n height,\n content,\n}: {\n width: number\n height: number\n content: string\n}) {\n return buildXMLString(\n 'svg',\n {\n width,\n height,\n viewBox: `0 0 ${width} ${height}`,\n xmlns: 'http://www.w3.org/2000/svg',\n },\n content\n )\n}\n","/**\n * Modified version of https://unpkg.com/twemoji@13.1.0/dist/twemoji.esm.js.\n */\n\n/*! Copyright Twitter Inc. and other contributors. Licensed under MIT */\n\nconst re =\n /(?:\\ud83d\\udc68\\ud83c\\udffb\\u200d\\u2764\\ufe0f\\u200d\\ud83d\\udc8b\\u200d\\ud83d\\udc68\\ud83c[\\udffb-\\udfff]|\\ud83d\\udc68\\ud83c\\udffc\\u200d\\u2764\\ufe0f\\u200d\\ud83d\\udc8b\\u200d\\ud83d\\udc68\\ud83c[\\udffb-\\udfff]|\\ud83d\\udc68\\ud83c\\udffd\\u200d\\u2764\\ufe0f\\u200d\\ud83d\\udc8b\\u200d\\ud83d\\udc68\\ud83c[\\udffb-\\udfff]|\\ud83d\\udc68\\ud83c\\udffe\\u200d\\u2764\\ufe0f\\u200d\\ud83d\\udc8b\\u200d\\ud83d\\udc68\\ud83c[\\udffb-\\udfff]|\\ud83d\\udc68\\ud83c\\udfff\\u200d\\u2764\\ufe0f\\u200d\\ud83d\\udc8b\\u200d\\ud83d\\udc68\\ud83c[\\udffb-\\udfff]|\\ud83d\\udc69\\ud83c\\udffb\\u200d\\u2764\\ufe0f\\u200d\\ud83d\\udc8b\\u200d\\ud83d\\udc68\\ud83c[\\udffb-\\udfff]|\\ud83d\\udc69\\ud83c\\udffb\\u200d\\u2764\\ufe0f\\u200d\\ud83d\\udc8b\\u200d\\ud83d\\udc69\\ud83c[\\udffb-\\udfff]|\\ud83d\\udc69\\ud83c\\udffc\\u200d\\u2764\\ufe0f\\u200d\\ud83d\\udc8b\\u200d\\ud83d\\udc68\\ud83c[\\udffb-\\udfff]|\\ud83d\\udc69\\ud83c\\udffc\\u200d\\u2764\\ufe0f\\u200d\\ud83d\\udc8b\\u200d\\ud83d\\udc69\\ud83c[\\udffb-\\udfff]|\\ud83d\\udc69\\ud83c\\udffd\\u200d\\u2764\\ufe0f\\u200d\\ud83d\\udc8b\\u200d\\ud83d\\udc68\\ud83c[\\udffb-\\udfff]|\\ud83d\\udc69\\ud83c\\udffd\\u200d\\u2764\\ufe0f\\u200d\\ud83d\\udc8b\\u200d\\ud83d\\udc69\\ud83c[\\udffb-\\udfff]|\\ud83d\\udc69\\ud83c\\udffe\\u200d\\u2764\\ufe0f\\u200d\\ud83d\\udc8b\\u200d\\ud83d\\udc68\\ud83c[\\udffb-\\udfff]|\\ud83d\\udc69\\ud83c\\udffe\\u200d\\u2764\\ufe0f\\u200d\\ud83d\\udc8b\\u200d\\ud83d\\udc69\\ud83c[\\udffb-\\udfff]|\\ud83d\\udc69\\ud83c\\udfff\\u200d\\u2764\\ufe0f\\u200d\\ud83d\\udc8b\\u200d\\ud83d\\udc68\\ud83c[\\udffb-\\udfff]|\\ud83d\\udc69\\ud83c\\udfff\\u200d\\u2764\\ufe0f\\u200d\\ud83d\\udc8b\\u200d\\ud83d\\udc69\\ud83c[\\udffb-\\udfff]|\\ud83e\\uddd1\\ud83c\\udffb\\u200d\\u2764\\ufe0f\\u200d\\ud83d\\udc8b\\u200d\\ud83e\\uddd1\\ud83c[\\udffc-\\udfff]|\\ud83e\\uddd1\\ud83c\\udffc\\u200d\\u2764\\ufe0f\\u200d\\ud83d\\udc8b\\u200d\\ud83e\\uddd1\\ud83c[\\udffb\\udffd-\\udfff]|\\ud83e\\uddd1\\ud83c\\udffd\\u200d\\u2764\\ufe0f\\u200d\\ud83d\\udc8b\\u200d\\ud83e\\uddd1\\ud83c[\\udffb\\udffc\\udffe\\udfff]|\\ud83e\\uddd1\\ud83c\\udffe\\u200d\\u2764\\ufe0f\\u200d\\ud83d\\udc8b\\u200d\\ud83e\\uddd1\\ud83c[\\udffb-\\udffd\\udfff]|\\ud83e\\uddd1\\ud83c\\udfff\\u200d\\u2764\\ufe0f\\u200d\\ud83d\\udc8b\\u200d\\ud83e\\uddd1\\ud83c[\\udffb-\\udffe]|\\ud83d\\udc68\\ud83c\\udffb\\u200d\\u2764\\ufe0f\\u200d\\ud83d\\udc68\\ud83c[\\udffb-\\udfff]|\\ud83d\\udc68\\ud83c\\udffb\\u200d\\ud83e\\udd1d\\u200d\\ud83d\\udc68\\ud83c[\\udffc-\\udfff]|\\ud83d\\udc68\\ud83c\\udffc\\u200d\\u2764\\ufe0f\\u200d\\ud83d\\udc68\\ud83c[\\udffb-\\udfff]|\\ud83d\\udc68\\ud83c\\udffc\\u200d\\ud83e\\udd1d\\u200d\\ud83d\\udc68\\ud83c[\\udffb\\udffd-\\udfff]|\\ud83d\\udc68\\ud83c\\udffd\\u200d\\u2764\\ufe0f\\u200d\\ud83d\\udc68\\ud83c[\\udffb-\\udfff]|\\ud83d\\udc68\\ud83c\\udffd\\u200d\\ud83e\\udd1d\\u200d\\ud83d\\udc68\\ud83c[\\udffb\\udffc\\udffe\\udfff]|\\ud83d\\udc68\\ud83c\\udffe\\u200d\\u2764\\ufe0f\\u200d\\ud83d\\udc68\\ud83c[\\udffb-\\udfff]|\\ud83d\\udc68\\ud83c\\udffe\\u200d\\ud83e\\udd1d\\u200d\\ud83d\\udc68\\ud83c[\\udffb-\\udffd\\udfff]|\\ud83d\\udc68\\ud83c\\udfff\\u200d\\u2764\\ufe0f\\u200d\\ud83d\\udc68\\ud83c[\\udffb-\\udfff]|\\ud83d\\udc68\\ud83c\\udfff\\u200d\\ud83e\\udd1d\\u200d\\ud83d\\udc68\\ud83c[\\udffb-\\udffe]|\\ud83d\\udc69\\ud83c\\udffb\\u200d\\u2764\\ufe0f\\u200d\\ud83d\\udc68\\ud83c[\\udffb-\\udfff]|\\ud83d\\udc69\\ud83c\\udffb\\u200d\\u2764\\ufe0f\\u200d\\ud83d\\udc69\\ud83c[\\udffb-\\udfff]|\\ud83d\\udc69\\ud83c\\udffb\\u200d\\ud83e\\udd1d\\u200d\\ud83d\\udc68\\ud83c[\\udffc-\\udfff]|\\ud83d\\udc69\\ud83c\\udffb\\u200d\\ud83e\\udd1d\\u200d\\ud83d\\udc69\\ud83c[\\udffc-\\udfff]|\\ud83d\\udc69\\ud83c\\udffc\\u200d\\u2764\\ufe0f\\u200d\\ud83d\\udc68\\ud83c[\\udffb-\\udfff]|\\ud83d\\udc69\\ud83c\\udffc\\u200d\\u2764\\ufe0f\\u200d\\ud83d\\udc69\\ud83c[\\udffb-\\udfff]|\\ud83d\\udc69\\ud83c\\udffc\\u200d\\ud83e\\udd1d\\u200d\\ud83d\\udc68\\ud83c[\\udffb\\udffd-\\udfff]|\\ud83d\\udc69\\ud83c\\udffc\\u200d\\ud83e\\udd1d\\u200d\\ud83d\\udc69\\ud83c[\\udffb\\udffd-\\udfff]|\\ud83d\\udc69\\ud83c\\udffd\\u200d\\u2764\\ufe0f\\u200d\\ud83d\\udc68\\ud83c[\\udffb-\\udfff]|\\ud83d\\udc69\\ud83c\\udffd\\u200d\\u2764\\ufe0f\\u200d\\ud83d\\udc69\\ud83c[\\udffb-\\udfff]|\\ud83d\\udc69\\ud83c\\udffd\\u200d\\ud83e\\udd1d\\u200d\\ud83d\\udc68\\ud83c[\\udffb\\udffc\\udffe\\udfff]|\\ud83d\\udc69\\ud83c\\udffd\\u200d\\ud83e\\udd1d\\u200d\\ud83d\\udc69\\ud83c[\\udffb\\udffc\\udffe\\udfff]|\\ud83d\\udc69\\ud83c\\udffe\\u200d\\u2764\\ufe0f\\u200d\\ud83d\\udc68\\ud83c[\\udffb-\\udfff]|\\ud83d\\udc69\\ud83c\\udffe\\u200d\\u2764\\ufe0f\\u200d\\ud83d\\udc69\\ud83c[\\udffb-\\udfff]|\\ud83d\\udc69\\ud83c\\udffe\\u200d\\ud83e\\udd1d\\u200d\\ud83d\\udc68\\ud83c[\\udffb-\\udffd\\udfff]|\\ud83d\\udc69\\ud83c\\udffe\\u200d\\ud83e\\udd1d\\u200d\\ud83d\\udc69\\ud83c[\\udffb-\\udffd\\udfff]|\\ud83d\\udc69\\ud83c\\udfff\\u200d\\u2764\\ufe0f\\u200d\\ud83d\\udc68\\ud83c[\\udffb-\\udfff]|\\ud83d\\udc69\\ud83c\\udfff\\u200d\\u2764\\ufe0f\\u200d\\ud83d\\udc69\\ud83c[\\udffb-\\udfff]|\\ud83d\\udc69\\ud83c\\udfff\\u200d\\ud83e\\udd1d\\u200d\\ud83d\\udc68\\ud83c[\\udffb-\\udffe]|\\ud83d\\udc69\\ud83c\\udfff\\u200d\\ud83e\\udd1d\\u200d\\ud83d\\udc69\\ud83c[\\udffb-\\udffe]|\\ud83e\\uddd1\\ud83c\\udffb\\u200d\\u2764\\ufe0f\\u200d\\ud83e\\uddd1\\ud83c[\\udffc-\\udfff]|\\ud83e\\uddd1\\ud83c\\udffb\\u200d\\ud83e\\udd1d\\u200d\\ud83e\\uddd1\\ud83c[\\udffb-\\udfff]|\\ud83e\\uddd1\\ud83c\\udffc\\u200d\\u2764\\ufe0f\\u200d\\ud83e\\uddd1\\ud83c[\\udffb\\udffd-\\udfff]|\\ud83e\\uddd1\\ud83c\\udffc\\u200d\\ud83e\\udd1d\\u200d\\ud83e\\uddd1\\ud83c[\\udffb-\\udfff]|\\ud83e\\uddd1\\ud83c\\udffd\\u200d\\u2764\\ufe0f\\u200d\\ud83e\\uddd1\\ud83c[\\udffb\\udffc\\udffe\\udfff]|\\ud83e\\uddd1\\ud83c\\udffd\\u200d\\ud83e\\udd1d\\u200d\\ud83e\\uddd1\\ud83c[\\udffb-\\udfff]|\\ud83e\\uddd1\\ud83c\\udffe\\u200d\\u2764\\ufe0f\\u200d\\ud83e\\uddd1\\ud83c[\\udffb-\\udffd\\udfff]|\\ud83e\\uddd1\\ud83c\\udffe\\u200d\\ud83e\\udd1d\\u200d\\ud83e\\uddd1\\ud83c[\\udffb-\\udfff]|\\ud83e\\uddd1\\ud83c\\udfff\\u200d\\u2764\\ufe0f\\u200d\\ud83e\\uddd1\\ud83c[\\udffb-\\udffe]|\\ud83e\\uddd1\\ud83c\\udfff\\u200d\\ud83e\\udd1d\\u200d\\ud83e\\uddd1\\ud83c[\\udffb-\\udfff]|\\ud83d\\udc68\\u200d\\u2764\\ufe0f\\u200d\\ud83d\\udc8b\\u200d\\ud83d\\udc68|\\ud83d\\udc69\\u200d\\u2764\\ufe0f\\u200d\\ud83d\\udc8b\\u200d\\ud83d[\\udc68\\udc69]|\\ud83d\\udc68\\u200d\\u2764\\ufe0f\\u200d\\ud83d\\udc68|\\ud83d\\udc69\\u200d\\u2764\\ufe0f\\u200d\\ud83d[\\udc68\\udc69]|\\ud83e\\uddd1\\u200d\\ud83e\\udd1d\\u200d\\ud83e\\uddd1|\\ud83d\\udc6b\\ud83c[\\udffb-\\udfff]|\\ud83d\\udc6c\\ud83c[\\udffb-\\udfff]|\\ud83d\\udc6d\\ud83c[\\udffb-\\udfff]|\\ud83d\\udc8f\\ud83c[\\udffb-\\udfff]|\\ud83d\\udc91\\ud83c[\\udffb-\\udfff]|\\ud83d[\\udc6b-\\udc6d\\udc8f\\udc91])|(?:\\ud83d[\\udc68\\udc69]|\\ud83e\\uddd1)(?:\\ud83c[\\udffb-\\udfff])?\\u200d(?:\\u2695\\ufe0f|\\u2696\\ufe0f|\\u2708\\ufe0f|\\ud83c[\\udf3e\\udf73\\udf7c\\udf84\\udf93\\udfa4\\udfa8\\udfeb\\udfed]|\\ud83d[\\udcbb\\udcbc\\udd27\\udd2c\\ude80\\ude92]|\\ud83e[\\uddaf-\\uddb3\\uddbc\\uddbd])|(?:\\ud83c[\\udfcb\\udfcc]|\\ud83d[\\udd74\\udd75]|\\u26f9)((?:\\ud83c[\\udffb-\\udfff]|\\ufe0f)\\u200d[\\u2640\\u2642]\\ufe0f)|(?:\\ud83c[\\udfc3\\udfc4\\udfca]|\\ud83d[\\udc6e\\udc70\\udc71\\udc73\\udc77\\udc81\\udc82\\udc86\\udc87\\ude45-\\ude47\\ude4b\\ude4d\\ude4e\\udea3\\udeb4-\\udeb6]|\\ud83e[\\udd26\\udd35\\udd37-\\udd39\\udd3d\\udd3e\\uddb8\\uddb9\\uddcd-\\uddcf\\uddd4\\uddd6-\\udddd])(?:\\ud83c[\\udffb-\\udfff])?\\u200d[\\u2640\\u2642]\\ufe0f|(?:\\ud83d\\udc68\\u200d\\ud83d\\udc68\\u200d\\ud83d\\udc66\\u200d\\ud83d\\udc66|\\ud83d\\udc68\\u200d\\ud83d\\udc68\\u200d\\ud83d\\udc67\\u200d\\ud83d[\\udc66\\udc67]|\\ud83d\\udc68\\u200d\\ud83d\\udc69\\u200d\\ud83d\\udc66\\u200d\\ud83d\\udc66|\\ud83d\\udc68\\u200d\\ud83d\\udc69\\u200d\\ud83d\\udc67\\u200d\\ud83d[\\udc66\\udc67]|\\ud83d\\udc69\\u200d\\ud83d\\udc69\\u200d\\ud83d\\udc66\\u200d\\ud83d\\udc66|\\ud83d\\udc69\\u200d\\ud83d\\udc69\\u200d\\ud83d\\udc67\\u200d\\ud83d[\\udc66\\udc67]|\\ud83d\\udc68\\u200d\\ud83d\\udc66\\u200d\\ud83d\\udc66|\\ud83d\\udc68\\u200d\\ud83d\\udc67\\u200d\\ud83d[\\udc66\\udc67]|\\ud83d\\udc68\\u200d\\ud83d\\udc68\\u200d\\ud83d[\\udc66\\udc67]|\\ud83d\\udc68\\u200d\\ud83d\\udc69\\u200d\\ud83d[\\udc66\\udc67]|\\ud83d\\udc69\\u200d\\ud83d\\udc66\\u200d\\ud83d\\udc66|\\ud83d\\udc69\\u200d\\ud83d\\udc67\\u200d\\ud83d[\\udc66\\udc67]|\\ud83d\\udc69\\u200d\\ud83d\\udc69\\u200d\\ud83d[\\udc66\\udc67]|\\ud83c\\udff3\\ufe0f\\u200d\\u26a7\\ufe0f|\\ud83c\\udff3\\ufe0f\\u200d\\ud83c\\udf08|\\ud83d\\ude36\\u200d\\ud83c\\udf2b\\ufe0f|\\u2764\\ufe0f\\u200d\\ud83d\\udd25|\\u2764\\ufe0f\\u200d\\ud83e\\ude79|\\ud83c\\udff4\\u200d\\u2620\\ufe0f|\\ud83d\\udc15\\u200d\\ud83e\\uddba|\\ud83d\\udc3b\\u200d\\u2744\\ufe0f|\\ud83d\\udc41\\u200d\\ud83d\\udde8|\\ud83d\\udc68\\u200d\\ud83d[\\udc66\\udc67]|\\ud83d\\udc69\\u200d\\ud83d[\\udc66\\udc67]|\\ud83d\\udc6f\\u200d\\u2640\\ufe0f|\\ud83d\\udc6f\\u200d\\u2642\\ufe0f|\\ud83d\\ude2e\\u200d\\ud83d\\udca8|\\ud83d\\ude35\\u200d\\ud83d\\udcab|\\ud83e\\udd3c\\u200d\\u2640\\ufe0f|\\ud83e\\udd3c\\u200d\\u2642\\ufe0f|\\ud83e\\uddde\\u200d\\u2640\\ufe0f|\\ud83e\\uddde\\u200d\\u2642\\ufe0f|\\ud83e\\udddf\\u200d\\u2640\\ufe0f|\\ud83e\\udddf\\u200d\\u2642\\ufe0f|\\ud83d\\udc08\\u200d\\u2b1b)|[#*0-9]\\ufe0f?\\u20e3|(?:[©®\\u2122\\u265f]\\ufe0f)|(?:\\ud83c[\\udc04\\udd70\\udd71\\udd7e\\udd7f\\ude02\\ude1a\\ude2f\\ude37\\udf21\\udf24-\\udf2c\\udf36\\udf7d\\udf96\\udf97\\udf99-\\udf9b\\udf9e\\udf9f\\udfcd\\udfce\\udfd4-\\udfdf\\udff3\\udff5\\udff7]|\\ud83d[\\udc3f\\udc41\\udcfd\\udd49\\udd4a\\udd6f\\udd70\\udd73\\udd76-\\udd79\\udd87\\udd8a-\\udd8d\\udda5\\udda8\\uddb1\\uddb2\\uddbc\\uddc2-\\uddc4\\uddd1-\\uddd3\\udddc-\\uddde\\udde1\\udde3\\udde8\\uddef\\uddf3\\uddfa\\udecb\\udecd-\\udecf\\udee0-\\udee5\\udee9\\udef0\\udef3]|[\\u203c\\u2049\\u2139\\u2194-\\u2199\\u21a9\\u21aa\\u231a\\u231b\\u2328\\u23cf\\u23ed-\\u23ef\\u23f1\\u23f2\\u23f8-\\u23fa\\u24c2\\u25aa\\u25ab\\u25b6\\u25c0\\u25fb-\\u25fe\\u2600-\\u2604\\u260e\\u2611\\u2614\\u2615\\u2618\\u2620\\u2622\\u2623\\u2626\\u262a\\u262e\\u262f\\u2638-\\u263a\\u2640\\u2642\\u2648-\\u2653\\u2660\\u2663\\u2665\\u2666\\u2668\\u267b\\u267f\\u2692-\\u2697\\u2699\\u269b\\u269c\\u26a0\\u26a1\\u26a7\\u26aa\\u26ab\\u26b0\\u26b1\\u26bd\\u26be\\u26c4\\u26c5\\u26c8\\u26cf\\u26d1\\u26d3\\u26d4\\u26e9\\u26ea\\u26f0-\\u26f5\\u26f8\\u26fa\\u26fd\\u2702\\u2708\\u2709\\u270f\\u2712\\u2714\\u2716\\u271d\\u2721\\u2733\\u2734\\u2744\\u2747\\u2757\\u2763\\u2764\\u27a1\\u2934\\u2935\\u2b05-\\u2b07\\u2b1b\\u2b1c\\u2b50\\u2b55\\u3030\\u303d\\u3297\\u3299])(?:\\ufe0f|(?!\\ufe0e))|(?:(?:\\ud83c[\\udfcb\\udfcc]|\\ud83d[\\udd74\\udd75\\udd90]|[\\u261d\\u26f7\\u26f9\\u270c\\u270d])(?:\\ufe0f|(?!\\ufe0e))|(?:\\ud83c[\\udf85\\udfc2-\\udfc4\\udfc7\\udfca]|\\ud83d[\\udc42\\udc43\\udc46-\\udc50\\udc66-\\udc69\\udc6e\\udc70-\\udc78\\udc7c\\udc81-\\udc83\\udc85-\\udc87\\udcaa\\udd7a\\udd95\\udd96\\ude45-\\ude47\\ude4b-\\ude4f\\udea3\\udeb4-\\udeb6\\udec0\\udecc]|\\ud83e[\\udd0c\\udd0f\\udd18-\\udd1c\\udd1e\\udd1f\\udd26\\udd30-\\udd39\\udd3d\\udd3e\\udd77\\uddb5\\uddb6\\uddb8\\uddb9\\uddbb\\uddcd-\\uddcf\\uddd1-\\udddd]|[\\u270a\\u270b]))(?:\\ud83c[\\udffb-\\udfff])?|(?:\\ud83c\\udff4\\udb40\\udc67\\udb40\\udc62\\udb40\\udc65\\udb40\\udc6e\\udb40\\udc67\\udb40\\udc7f|\\ud83c\\udff4\\udb40\\udc67\\udb40\\udc62\\udb40\\udc73\\udb40\\udc63\\udb40\\udc74\\udb40\\udc7f|\\ud83c\\udff4\\udb40\\udc67\\udb40\\udc62\\udb40\\udc77\\udb40\\udc6c\\udb40\\udc73\\udb40\\udc7f|\\ud83c\\udde6\\ud83c[\\udde8-\\uddec\\uddee\\uddf1\\uddf2\\uddf4\\uddf6-\\uddfa\\uddfc\\uddfd\\uddff]|\\ud83c\\udde7\\ud83c[\\udde6\\udde7\\udde9-\\uddef\\uddf1-\\uddf4\\uddf6-\\uddf9\\uddfb\\uddfc\\uddfe\\uddff]|\\ud83c\\udde8\\ud83c[\\udde6\\udde8\\udde9\\uddeb-\\uddee\\uddf0-\\uddf5\\uddf7\\uddfa-\\uddff]|\\ud83c\\udde9\\ud83c[\\uddea\\uddec\\uddef\\uddf0\\uddf2\\uddf4\\uddff]|\\ud83c\\uddea\\ud83c[\\udde6\\udde8\\uddea\\uddec\\udded\\uddf7-\\uddfa]|\\ud83c\\uddeb\\ud83c[\\uddee-\\uddf0\\uddf2\\uddf4\\uddf7]|\\ud83c\\uddec\\ud83c[\\udde6\\udde7\\udde9-\\uddee\\uddf1-\\uddf3\\uddf5-\\uddfa\\uddfc\\uddfe]|\\ud83c\\udded\\ud83c[\\uddf0\\uddf2\\uddf3\\uddf7\\uddf9\\uddfa]|\\ud83c\\uddee\\ud83c[\\udde8-\\uddea\\uddf1-\\uddf4\\uddf6-\\uddf9]|\\ud83c\\uddef\\ud83c[\\uddea\\uddf2\\uddf4\\uddf5]|\\ud83c\\uddf0\\ud83c[\\uddea\\uddec-\\uddee\\uddf2\\uddf3\\uddf5\\uddf7\\uddfc\\uddfe\\uddff]|\\ud83c\\uddf1\\ud83c[\\udde6-\\udde8\\uddee\\uddf0\\uddf7-\\uddfb\\uddfe]|\\ud83c\\uddf2\\ud83c[\\udde6\\udde8-\\udded\\uddf0-\\uddff]|\\ud83c\\uddf3\\ud83c[\\udde6\\udde8\\uddea-\\uddec\\uddee\\uddf1\\uddf4\\uddf5\\uddf7\\uddfa\\uddff]|\\ud83c\\uddf4\\ud83c\\uddf2|\\ud83c\\uddf5\\ud83c[\\udde6\\uddea-\\udded\\uddf0-\\uddf3\\uddf7-\\uddf9\\uddfc\\uddfe]|\\ud83c\\uddf6\\ud83c\\udde6|\\ud83c\\uddf7\\ud83c[\\uddea\\uddf4\\uddf8\\uddfa\\uddfc]|\\ud83c\\uddf8\\ud83c[\\udde6-\\uddea\\uddec-\\uddf4\\uddf7-\\uddf9\\uddfb\\uddfd-\\uddff]|\\ud83c\\uddf9\\ud83c[\\udde6\\udde8\\udde9\\uddeb-\\udded\\uddef-\\uddf4\\uddf7\\uddf9\\uddfb\\uddfc\\uddff]|\\ud83c\\uddfa\\ud83c[\\udde6\\uddec\\uddf2\\uddf3\\uddf8\\uddfe\\uddff]|\\ud83c\\uddfb\\ud83c[\\udde6\\udde8\\uddea\\uddec\\uddee\\uddf3\\uddfa]|\\ud83c\\uddfc\\ud83c[\\uddeb\\uddf8]|\\ud83c\\uddfd\\ud83c\\uddf0|\\ud83c\\uddfe\\ud83c[\\uddea\\uddf9]|\\ud83c\\uddff\\ud83c[\\udde6\\uddf2\\uddfc]|\\ud83c[\\udccf\\udd8e\\udd91-\\udd9a\\udde6-\\uddff\\ude01\\ude32-\\ude36\\ude38-\\ude3a\\ude50\\ude51\\udf00-\\udf20\\udf2d-\\udf35\\udf37-\\udf7c\\udf7e-\\udf84\\udf86-\\udf93\\udfa0-\\udfc1\\udfc5\\udfc6\\udfc8\\udfc9\\udfcf-\\udfd3\\udfe0-\\udff0\\udff4\\udff8-\\udfff]|\\ud83d[\\udc00-\\udc3e\\udc40\\udc44\\udc45\\udc51-\\udc65\\udc6a\\udc6f\\udc79-\\udc7b\\udc7d-\\udc80\\udc84\\udc88-\\udc8e\\udc90\\udc92-\\udca9\\udcab-\\udcfc\\udcff-\\udd3d\\udd4b-\\udd4e\\udd50-\\udd67\\udda4\\uddfb-\\ude44\\ude48-\\ude4a\\ude80-\\udea2\\udea4-\\udeb3\\udeb7-\\udebf\\udec1-\\udec5\\uded0-\\uded2\\uded5-\\uded7\\udeeb\\udeec\\udef4-\\udefc\\udfe0-\\udfeb]|\\ud83e[\\udd0d\\udd0e\\udd10-\\udd17\\udd1d\\udd20-\\udd25\\udd27-\\udd2f\\udd3a\\udd3c\\udd3f-\\udd45\\udd47-\\udd76\\udd78\\udd7a-\\uddb4\\uddb7\\uddba\\uddbc-\\uddcb\\uddd0\\uddde-\\uddff\\ude70-\\ude74\\ude78-\\ude7a\\ude80-\\ude86\\ude90-\\udea8\\udeb0-\\udeb6\\udec0-\\udec2\\uded0-\\uded6]|[\\u23e9-\\u23ec\\u23f0\\u23f3\\u267e\\u26ce\\u2705\\u2728\\u274c\\u274e\\u2753-\\u2755\\u2795-\\u2797\\u27b0\\u27bf\\ue50a])|\\ufe0f/g\n\nexport function isEmoji(char: string) {\n return char.match(re)\n}\n"],"mappings":"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","names":[]}