@meonode/canvas 1.5.0 → 1.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/canvas/grid.canvas.util.d.ts.map +1 -1
- package/dist/cjs/canvas/grid.canvas.util.js +14 -1
- package/dist/cjs/canvas/grid.canvas.util.js.map +1 -1
- package/dist/cjs/canvas/text.canvas.util.d.ts +6 -0
- package/dist/cjs/canvas/text.canvas.util.d.ts.map +1 -1
- package/dist/cjs/canvas/text.canvas.util.js +26 -13
- package/dist/cjs/canvas/text.canvas.util.js.map +1 -1
- package/dist/esm/canvas/grid.canvas.util.d.ts.map +1 -1
- package/dist/esm/canvas/grid.canvas.util.js +14 -1
- package/dist/esm/canvas/text.canvas.util.d.ts +6 -0
- package/dist/esm/canvas/text.canvas.util.d.ts.map +1 -1
- package/dist/esm/canvas/text.canvas.util.js +26 -13
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grid.canvas.util.d.ts","sourceRoot":"","sources":["../../../src/canvas/grid.canvas.util.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAiB,aAAa,EAAE,MAAM,yBAAyB,CAAA;AACtF,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,gCAAgC,CAAA;AAIjE;;;;GAIG;AACH,qBAAa,YAAa,SAAQ,OAAO;gBAC3B,KAAK,EAAE,aAAa;CAMjC;AAED;;GAEG;AACH,eAAO,MAAM,QAAQ,GAAI,OAAO,aAAa,iBAA4B,CAAA;AAEzE;;;GAGG;AACH,qBAAa,QAAS,SAAQ,OAAO;IACnC;;;OAGG;gBACS,KAAK,EAAE,SAAS;IAQ5B;;OAEG;IACH,OAAO,CAAC,UAAU;IAqBlB;;OAEG;IACH,OAAO,CAAC,YAAY;IAmBpB;;OAEG;cACgB,+BAA+B;
|
|
1
|
+
{"version":3,"file":"grid.canvas.util.d.ts","sourceRoot":"","sources":["../../../src/canvas/grid.canvas.util.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAiB,aAAa,EAAE,MAAM,yBAAyB,CAAA;AACtF,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,gCAAgC,CAAA;AAIjE;;;;GAIG;AACH,qBAAa,YAAa,SAAQ,OAAO;gBAC3B,KAAK,EAAE,aAAa;CAMjC;AAED;;GAEG;AACH,eAAO,MAAM,QAAQ,GAAI,OAAO,aAAa,iBAA4B,CAAA;AAEzE;;;GAGG;AACH,qBAAa,QAAS,SAAQ,OAAO;IACnC;;;OAGG;gBACS,KAAK,EAAE,SAAS;IAQ5B;;OAEG;IACH,OAAO,CAAC,UAAU;IAqBlB;;OAEG;IACH,OAAO,CAAC,YAAY;IAmBpB;;OAEG;cACgB,+BAA+B;IAsSlD;;OAEG;IACH,OAAO,CAAC,aAAa;CAkCtB;AAED;;GAEG;AACH,eAAO,MAAM,IAAI,GAAI,OAAO,SAAS,aAAwB,CAAA"}
|
|
@@ -70,7 +70,20 @@ class GridNode extends layout_canvas_util.RowNode {
|
|
|
70
70
|
*/
|
|
71
71
|
updateLayoutBasedOnComputedSize() {
|
|
72
72
|
// 1. Get Container Dimensions
|
|
73
|
-
|
|
73
|
+
let width = this.node.getComputedWidth();
|
|
74
|
+
// When parent has minWidth (percentage), the computed width may grow beyond
|
|
75
|
+
// the intended minWidth to fit content. Constrain to minWidth if it's a percentage.
|
|
76
|
+
const minWidth = this.node.getMinWidth();
|
|
77
|
+
if (minWidth.unit === common_const.Style.Unit.Percent && this.node.getParent()) {
|
|
78
|
+
const parentWidth = this.node.getParent().getComputedWidth();
|
|
79
|
+
if (!isNaN(parentWidth) && parentWidth > 0) {
|
|
80
|
+
const intendedMinWidth = (minWidth.value / 100) * parentWidth;
|
|
81
|
+
// Constrain width to the intended minWidth percentage
|
|
82
|
+
if (width > intendedMinWidth) {
|
|
83
|
+
width = intendedMinWidth;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
74
87
|
const paddingLeft = this.node.getComputedPadding(common_const.Style.Edge.Left);
|
|
75
88
|
const paddingRight = this.node.getComputedPadding(common_const.Style.Edge.Right);
|
|
76
89
|
const paddingTop = this.node.getComputedPadding(common_const.Style.Edge.Top);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grid.canvas.util.js","sources":["../../../../src/canvas/grid.canvas.util.ts"],"sourcesContent":["import type { GridProps, GridTrackSize, GridItemProps } from '@/canvas/canvas.type.js'\nimport { BoxNode, RowNode } from '@/canvas/layout.canvas.util.js'\nimport { Style } from '@/constant/common.const.js'\nimport { parsePercentage } from '@/canvas/canvas.helper.js'\n\n/**\n * GridItem Node. Theoretically just a BoxNode but typed differently in factory.\n * In runtime, it behaves almost like a BoxNode, but we can detect it if needed,\n * or simply rely on the props being present in the instance.\n */\nexport class GridItemNode extends BoxNode {\n constructor(props: GridItemProps) {\n super({\n ...props,\n name: 'GridItem',\n })\n }\n}\n\n/**\n * Factory for GridItem.\n */\nexport const GridItem = (props: GridItemProps) => new GridItemNode(props)\n\n/**\n * Grid layout node that arranges children in a 2D grid.\n * Implements a simplified version of the CSS Grid Layout algorithm.\n */\nexport class GridNode extends RowNode {\n /**\n * Creates a new grid layout node\n * @param props Grid configuration properties\n */\n constructor(props: GridProps) {\n super({\n ...props,\n name: props.name || 'Grid',\n flexWrap: Style.Wrap.Wrap,\n })\n }\n\n /**\n * Helper to parse a track size definition.\n */\n private parseTrack(track: GridTrackSize, availableSpace: number): { type: 'px' | '%' | 'fr' | 'auto'; value: number } {\n if (typeof track === 'number') {\n return { type: 'px', value: track }\n }\n if (track === 'auto') {\n return { type: 'auto', value: 0 }\n }\n if (typeof track === 'string') {\n if (track.endsWith('fr')) {\n return { type: 'fr', value: parseFloat(track) }\n }\n if (track.endsWith('%')) {\n return { type: '%', value: parsePercentage(track, availableSpace) }\n }\n // Try parsing as number (px) if just string \"100\"\n const num = parseFloat(track)\n if (!isNaN(num)) return { type: 'px', value: num }\n }\n return { type: 'auto', value: 0 }\n }\n\n /**\n * Parses the gap property into pixels.\n */\n private getGapPixels(gap: GridProps['gap'], width: number, height: number) {\n let rowGap = 0\n let colGap = 0\n\n if (typeof gap === 'number') {\n rowGap = colGap = gap\n } else if (typeof gap === 'string') {\n const val = parsePercentage(gap, width) // Use width as base for simplicity if %\n rowGap = colGap = val\n } else if (gap && typeof gap === 'object') {\n const colVal = gap.Column ?? gap.All ?? 0\n const rowVal = gap.Row ?? gap.All ?? 0\n colGap = parsePercentage(colVal as string | number, width)\n rowGap = parsePercentage(rowVal as string | number, height)\n }\n\n return { rowGap, colGap }\n }\n\n /**\n * Update layout calculations after the initial layout is computed.\n */\n protected override updateLayoutBasedOnComputedSize() {\n // 1. Get Container Dimensions\n const width = this.node.getComputedWidth()\n\n const paddingLeft = this.node.getComputedPadding(Style.Edge.Left)\n const paddingRight = this.node.getComputedPadding(Style.Edge.Right)\n const paddingTop = this.node.getComputedPadding(Style.Edge.Top)\n const paddingBottom = this.node.getComputedPadding(Style.Edge.Bottom)\n\n const contentWidth = Math.max(0, width - paddingLeft - paddingRight)\n const computedHeight = this.node.getComputedHeight()\n const contentHeight = Math.max(0, computedHeight - paddingTop - paddingBottom)\n\n const { templateColumns, templateRows, autoRows = 'auto', gap, columns } = this.props as GridProps\n\n // 2. Resolve Gaps\n const { rowGap, colGap } = this.getGapPixels(gap, contentWidth, contentHeight)\n\n // 3. Resolve Columns (Tracks)\n let explicitColTracks: GridTrackSize[] = templateColumns || []\n if (explicitColTracks.length === 0 && columns) {\n explicitColTracks = Array(columns).fill('1fr')\n }\n if (explicitColTracks.length === 0) explicitColTracks = ['1fr']\n\n const resolvedColTracks = this.resolveTracks(explicitColTracks, contentWidth, colGap)\n\n // Pre-calculate Col Offsets needed for placement/width\n const colOffsetsValues = [0]\n for (let i = 0; i < resolvedColTracks.length; i++) {\n colOffsetsValues.push(colOffsetsValues[i] + resolvedColTracks[i] + colGap)\n }\n\n // 4. Place Items & Resolve Explicit Row Tracks\n const explicitRowTracks = templateRows || []\n const resolvedExplicitRowTracks = this.resolveTracks(explicitRowTracks, contentHeight, rowGap)\n\n const cells: boolean[][] = [] // true if occupied\n const items: { node: BoxNode; rowStart: number; rowEnd: number; colStart: number; colEnd: number }[] = []\n\n const isOccupied = (r: number, c: number) => {\n if (!cells[r]) return false\n return cells[r][c] === true\n }\n const setOccupied = (r: number, c: number) => {\n if (!cells[r]) cells[r] = []\n cells[r][c] = true\n }\n\n let cursorRow = 0\n let cursorCol = 0\n\n for (const child of this.children) {\n const childProps = child.props as GridItemProps\n const { gridColumn, gridRow } = childProps\n\n let colStart: number | undefined\n let colEnd: number | undefined\n let colSpan = 1\n let rowStart: number | undefined\n let rowEnd: number | undefined\n let rowSpan = 1\n\n // ... Grid Placement Logic ...\n if (gridColumn) {\n const parts = gridColumn.split('/').map(s => s.trim())\n if (parts[0]) {\n if (parts[0].startsWith('span')) {\n colSpan = parseInt(parts[0].replace('span', '')) || 1\n } else {\n colStart = parseInt(parts[0]) - 1\n }\n }\n if (parts[1]) {\n if (parts[1].startsWith('span')) {\n const span = parseInt(parts[1].replace('span', '')) || 1\n if (colStart !== undefined) {\n colEnd = colStart + span\n colSpan = span\n } else {\n // If start is undefined but end is span? Unusual. Treat as span.\n colSpan = span\n }\n } else {\n colEnd = parseInt(parts[1]) - 1\n if (colStart !== undefined) {\n colSpan = colEnd - colStart\n }\n }\n }\n }\n\n if (gridRow) {\n const parts = gridRow.split('/').map(s => s.trim())\n if (parts[0]) {\n if (parts[0].startsWith('span')) {\n rowSpan = parseInt(parts[0].replace('span', '')) || 1\n } else {\n rowStart = parseInt(parts[0]) - 1\n }\n }\n if (parts[1]) {\n if (parts[1].startsWith('span')) {\n const span = parseInt(parts[1].replace('span', '')) || 1\n if (rowStart !== undefined) {\n rowEnd = rowStart + span\n rowSpan = span\n } else {\n rowSpan = span\n }\n } else {\n rowEnd = parseInt(parts[1]) - 1\n if (rowStart !== undefined) {\n rowSpan = rowEnd - rowStart\n }\n }\n }\n }\n\n if (colStart !== undefined && rowStart !== undefined) {\n // Fixed position: Check overlap in simpler V1? Or just place?\n // Just place.\n } else {\n // Auto placement\n let placed = false\n while (!placed) {\n if (!cells[cursorRow]) cells[cursorRow] = []\n\n if (colStart !== undefined) cursorCol = colStart\n\n let fits = true\n for (let r = 0; r < rowSpan; r++) {\n for (let c = 0; c < colSpan; c++) {\n if (isOccupied(cursorRow + r, cursorCol + c)) {\n fits = false\n break\n }\n }\n if (!fits) break\n }\n\n if (fits) {\n rowStart = cursorRow\n colStart = cursorCol\n placed = true\n } else {\n cursorCol++\n if (cursorCol + colSpan > resolvedColTracks.length) {\n cursorCol = 0\n cursorRow++\n }\n }\n }\n cursorCol += colSpan\n if (cursorCol >= resolvedColTracks.length) {\n cursorCol = 0\n cursorRow++\n }\n }\n\n rowEnd = (rowStart ?? 0) + rowSpan\n colEnd = (colStart ?? 0) + colSpan\n\n for (let r = rowStart!; r < rowEnd!; r++) {\n for (let c = colStart!; c < colEnd!; c++) {\n setOccupied(r, c)\n }\n }\n\n // CRITICAL FIX: Pre-set width on item to ensure height calculation is accurate later\n const itemColStart = colStart!\n const itemColEnd = colEnd!\n\n // Extend local offsets if needed for spanned columns beyond track count (rare but safe)\n while (colOffsetsValues.length <= itemColEnd) {\n colOffsetsValues.push(colOffsetsValues[colOffsetsValues.length - 1] + 0 + colGap)\n }\n\n const cs = Math.min(itemColStart, colOffsetsValues.length - 1)\n const ce = Math.min(itemColEnd, colOffsetsValues.length - 1)\n const targetWidth = Math.max(0, colOffsetsValues[ce] - colOffsetsValues[cs] - colGap)\n\n child.node.setWidth(targetWidth)\n child.node.calculateLayout(targetWidth, Number.NaN, Style.Direction.LTR)\n\n // Recursively finalize nested children (e.g. inner Grids) so their\n // computed heights are accurate before we measure row sizes.\n child.finalizeLayout()\n if (child.node.isDirty()) {\n child.node.calculateLayout(targetWidth, Number.NaN, Style.Direction.LTR)\n }\n\n items.push({ node: child, rowStart: rowStart!, rowEnd: rowEnd!, colStart: itemColStart, colEnd: itemColEnd })\n }\n\n // 6. Finalize Rows (Implicit)\n const totalRowsNeeded = Math.max(resolvedExplicitRowTracks.length, ...items.map(i => i.rowEnd))\n const resolvedRowTracks = [...resolvedExplicitRowTracks]\n\n // Fill implicit rows\n for (let r = resolvedExplicitRowTracks.length; r < totalRowsNeeded; r++) {\n let rowSize = 0\n\n // Better 'auto' handling:\n if (autoRows === 'auto') {\n const rowItems = items.filter(i => i.rowStart === r && i.rowEnd - i.rowStart === 1)\n for (const item of rowItems) {\n rowSize = Math.max(rowSize, item.node.node.getComputedHeight())\n }\n } else {\n const parsed = this.parseTrack(autoRows, contentHeight)\n rowSize = parsed.value\n }\n resolvedRowTracks.push(rowSize)\n }\n\n // 6. Calculate Offsets (Rows) & Final Layout Application\n const colOffsets = colOffsetsValues // Re-use\n const rowOffsets = [0]\n for (let i = 0; i < resolvedRowTracks.length; i++) {\n let size = resolvedRowTracks[i]\n // Re-check auto-sized explicit rows (value 0)\n if (size === 0) {\n const rowItems = items.filter(it => it.rowStart === i && it.rowEnd - it.rowStart === 1)\n for (const item of rowItems) {\n size = Math.max(size, item.node.node.getComputedHeight())\n }\n resolvedRowTracks[i] = size\n }\n rowOffsets.push(rowOffsets[i] + size + rowGap)\n }\n\n // 7. Apply Positions\n for (const item of items) {\n const x = colOffsets[item.colStart] + paddingLeft\n\n while (colOffsets.length <= item.colEnd) {\n colOffsets.push(colOffsets[colOffsets.length - 1] + 0 + colGap)\n }\n\n const widthStart = colOffsets[item.colStart]\n const widthEnd = colOffsets[item.colEnd]\n const totalWidth = Math.max(0, widthEnd - widthStart - colGap)\n\n const y = rowOffsets[item.rowStart] + paddingTop\n\n const heightStart = rowOffsets[item.rowStart]\n const heightEnd = rowOffsets[item.rowEnd]\n const totalHeight = Math.max(0, heightEnd - heightStart - rowGap)\n\n const childNode = item.node.node\n\n if (childNode.getPositionType() !== Style.PositionType.Absolute) {\n childNode.setPositionType(Style.PositionType.Absolute)\n }\n\n if (childNode.getPosition(Style.Edge.Left).value !== x) {\n childNode.setPosition(Style.Edge.Left, x)\n }\n if (childNode.getPosition(Style.Edge.Top).value !== y) {\n childNode.setPosition(Style.Edge.Top, y)\n }\n\n if (childNode.getWidth().unit !== Style.Unit.Point || Math.abs(childNode.getWidth().value - totalWidth) > 0.1) {\n childNode.setWidth(totalWidth)\n }\n if (childNode.getHeight().unit !== Style.Unit.Point || Math.abs(childNode.getHeight().value - totalHeight) > 0.1) {\n childNode.setHeight(totalHeight)\n }\n }\n\n // 9. Update Grid Height\n const totalGridHeight = Math.max(0, rowOffsets[rowOffsets.length - 1] - rowGap)\n const currentHeightStyle = this.node.getHeight()\n if (currentHeightStyle.unit === Style.Unit.Auto || currentHeightStyle.unit === Style.Unit.Undefined) {\n const targetTotalHeight = totalGridHeight + paddingTop + paddingBottom\n this.node.setHeight(targetTotalHeight)\n }\n }\n\n /**\n * Resolves track sizes to pixels.\n */\n private resolveTracks(tracks: GridTrackSize[], availableSpace: number, gap: number): number[] {\n const resolved: number[] = []\n let usedSpace = 0\n let totalFr = 0\n const frIndices: number[] = []\n\n tracks.forEach((t, i) => {\n const parsed = this.parseTrack(t, availableSpace)\n if (parsed.type === 'px' || parsed.type === '%') {\n resolved[i] = parsed.value\n usedSpace += parsed.value\n } else if (parsed.type === 'fr') {\n totalFr += parsed.value\n resolved[i] = 0\n frIndices.push(i)\n } else {\n resolved[i] = 0\n }\n })\n\n const totalGaps = Math.max(0, tracks.length - 1) * gap\n usedSpace += totalGaps\n\n const remainingSpace = Math.max(0, availableSpace - usedSpace)\n if (totalFr > 0) {\n frIndices.forEach(i => {\n const parsed = this.parseTrack(tracks[i], availableSpace)\n const share = (parsed.value / totalFr) * remainingSpace\n resolved[i] = share\n })\n }\n\n return resolved\n }\n}\n\n/**\n * Factory function to create a new GridNode instance.\n */\nexport const Grid = (props: GridProps) => new GridNode(props)\n"],"names":["RowNode","Style","parsePercentage"],"mappings":";;;;;;AAwBA;;;AAGG;AACG,MAAO,QAAS,SAAQA,0BAAO,CAAA;AACnC;;;AAGG;AACH,IAAA,WAAA,CAAY,KAAgB,EAAA;AAC1B,QAAA,KAAK,CAAC;AACJ,YAAA,GAAG,KAAK;AACR,YAAA,IAAI,EAAE,KAAK,CAAC,IAAI,IAAI,MAAM;AAC1B,YAAA,QAAQ,EAAEC,kBAAK,CAAC,IAAI,CAAC,IAAI;AAC1B,SAAA,CAAC;IACJ;AAEA;;AAEG;IACK,UAAU,CAAC,KAAoB,EAAE,cAAsB,EAAA;AAC7D,QAAA,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE;YAC7B,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE;QACrC;AACA,QAAA,IAAI,KAAK,KAAK,MAAM,EAAE;YACpB,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE;QACnC;AACA,QAAA,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE;AAC7B,YAAA,IAAI,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE;AACxB,gBAAA,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,UAAU,CAAC,KAAK,CAAC,EAAE;YACjD;AACA,YAAA,IAAI,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE;AACvB,gBAAA,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAEC,6BAAe,CAAC,KAAK,EAAE,cAAc,CAAC,EAAE;YACrE;;AAEA,YAAA,MAAM,GAAG,GAAG,UAAU,CAAC,KAAK,CAAC;AAC7B,YAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC;gBAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE;QACpD;QACA,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE;IACnC;AAEA;;AAEG;AACK,IAAA,YAAY,CAAC,GAAqB,EAAE,KAAa,EAAE,MAAc,EAAA;QACvE,IAAI,MAAM,GAAG,CAAC;QACd,IAAI,MAAM,GAAG,CAAC;AAEd,QAAA,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE;AAC3B,YAAA,MAAM,GAAG,MAAM,GAAG,GAAG;QACvB;AAAO,aAAA,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE;YAClC,MAAM,GAAG,GAAGA,6BAAe,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;AACvC,YAAA,MAAM,GAAG,MAAM,GAAG,GAAG;QACvB;AAAO,aAAA,IAAI,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE;YACzC,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,GAAG,IAAI,CAAC;YACzC,MAAM,MAAM,GAAG,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,IAAI,CAAC;AACtC,YAAA,MAAM,GAAGA,6BAAe,CAAC,MAAyB,EAAE,KAAK,CAAC;AAC1D,YAAA,MAAM,GAAGA,6BAAe,CAAC,MAAyB,EAAE,MAAM,CAAC;QAC7D;AAEA,QAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE;IAC3B;AAEA;;AAEG;IACgB,+BAA+B,GAAA;;QAEhD,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE;AAE1C,QAAA,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAACD,kBAAK,CAAC,IAAI,CAAC,IAAI,CAAC;AACjE,QAAA,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAACA,kBAAK,CAAC,IAAI,CAAC,KAAK,CAAC;AACnE,QAAA,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAACA,kBAAK,CAAC,IAAI,CAAC,GAAG,CAAC;AAC/D,QAAA,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAACA,kBAAK,CAAC,IAAI,CAAC,MAAM,CAAC;AAErE,QAAA,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,GAAG,WAAW,GAAG,YAAY,CAAC;QACpE,MAAM,cAAc,GAAG,IAAI,CAAC,IAAI,CAAC,iBAAiB,EAAE;AACpD,QAAA,MAAM,aAAa,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,cAAc,GAAG,UAAU,GAAG,aAAa,CAAC;AAE9E,QAAA,MAAM,EAAE,eAAe,EAAE,YAAY,EAAE,QAAQ,GAAG,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC,KAAkB;;AAGlG,QAAA,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC,YAAY,CAAC,GAAG,EAAE,YAAY,EAAE,aAAa,CAAC;;AAG9E,QAAA,IAAI,iBAAiB,GAAoB,eAAe,IAAI,EAAE;QAC9D,IAAI,iBAAiB,CAAC,MAAM,KAAK,CAAC,IAAI,OAAO,EAAE;YAC7C,iBAAiB,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC;QAChD;AACA,QAAA,IAAI,iBAAiB,CAAC,MAAM,KAAK,CAAC;AAAE,YAAA,iBAAiB,GAAG,CAAC,KAAK,CAAC;AAE/D,QAAA,MAAM,iBAAiB,GAAG,IAAI,CAAC,aAAa,CAAC,iBAAiB,EAAE,YAAY,EAAE,MAAM,CAAC;;AAGrF,QAAA,MAAM,gBAAgB,GAAG,CAAC,CAAC,CAAC;AAC5B,QAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,iBAAiB,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;AACjD,YAAA,gBAAgB,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,GAAG,iBAAiB,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC;QAC5E;;AAGA,QAAA,MAAM,iBAAiB,GAAG,YAAY,IAAI,EAAE;AAC5C,QAAA,MAAM,yBAAyB,GAAG,IAAI,CAAC,aAAa,CAAC,iBAAiB,EAAE,aAAa,EAAE,MAAM,CAAC;AAE9F,QAAA,MAAM,KAAK,GAAgB,EAAE,CAAA;QAC7B,MAAM,KAAK,GAA4F,EAAE;AAEzG,QAAA,MAAM,UAAU,GAAG,CAAC,CAAS,EAAE,CAAS,KAAI;AAC1C,YAAA,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;AAAE,gBAAA,OAAO,KAAK;YAC3B,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI;AAC7B,QAAA,CAAC;AACD,QAAA,MAAM,WAAW,GAAG,CAAC,CAAS,EAAE,CAAS,KAAI;AAC3C,YAAA,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;AAAE,gBAAA,KAAK,CAAC,CAAC,CAAC,GAAG,EAAE;YAC5B,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI;AACpB,QAAA,CAAC;QAED,IAAI,SAAS,GAAG,CAAC;QACjB,IAAI,SAAS,GAAG,CAAC;AAEjB,QAAA,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ,EAAE;AACjC,YAAA,MAAM,UAAU,GAAG,KAAK,CAAC,KAAsB;AAC/C,YAAA,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,GAAG,UAAU;AAE1C,YAAA,IAAI,QAA4B;AAChC,YAAA,IAAI,MAA0B;YAC9B,IAAI,OAAO,GAAG,CAAC;AACf,YAAA,IAAI,QAA4B;AAChC,YAAA,IAAI,MAA0B;YAC9B,IAAI,OAAO,GAAG,CAAC;;YAGf,IAAI,UAAU,EAAE;gBACd,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;AACtD,gBAAA,IAAI,KAAK,CAAC,CAAC,CAAC,EAAE;oBACZ,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE;AAC/B,wBAAA,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC;oBACvD;yBAAO;wBACL,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;oBACnC;gBACF;AACA,gBAAA,IAAI,KAAK,CAAC,CAAC,CAAC,EAAE;oBACZ,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE;AAC/B,wBAAA,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC;AACxD,wBAAA,IAAI,QAAQ,KAAK,SAAS,EAAE;AAC1B,4BAAA,MAAM,GAAG,QAAQ,GAAG,IAAI;4BACxB,OAAO,GAAG,IAAI;wBAChB;6BAAO;;4BAEL,OAAO,GAAG,IAAI;wBAChB;oBACF;yBAAO;wBACL,MAAM,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;AAC/B,wBAAA,IAAI,QAAQ,KAAK,SAAS,EAAE;AAC1B,4BAAA,OAAO,GAAG,MAAM,GAAG,QAAQ;wBAC7B;oBACF;gBACF;YACF;YAEA,IAAI,OAAO,EAAE;gBACX,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;AACnD,gBAAA,IAAI,KAAK,CAAC,CAAC,CAAC,EAAE;oBACZ,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE;AAC/B,wBAAA,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC;oBACvD;yBAAO;wBACL,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;oBACnC;gBACF;AACA,gBAAA,IAAI,KAAK,CAAC,CAAC,CAAC,EAAE;oBACZ,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE;AAC/B,wBAAA,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC;AACxD,wBAAA,IAAI,QAAQ,KAAK,SAAS,EAAE;AAC1B,4BAAA,MAAM,GAAG,QAAQ,GAAG,IAAI;4BACxB,OAAO,GAAG,IAAI;wBAChB;6BAAO;4BACL,OAAO,GAAG,IAAI;wBAChB;oBACF;yBAAO;wBACL,MAAM,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;AAC/B,wBAAA,IAAI,QAAQ,KAAK,SAAS,EAAE;AAC1B,4BAAA,OAAO,GAAG,MAAM,GAAG,QAAQ;wBAC7B;oBACF;gBACF;YACF;YAEA,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,KAAK,SAAS,EAAE;iBAG/C;;gBAEL,IAAI,MAAM,GAAG,KAAK;gBAClB,OAAO,CAAC,MAAM,EAAE;AACd,oBAAA,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC;AAAE,wBAAA,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE;oBAE5C,IAAI,QAAQ,KAAK,SAAS;wBAAE,SAAS,GAAG,QAAQ;oBAEhD,IAAI,IAAI,GAAG,IAAI;AACf,oBAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,EAAE,CAAC,EAAE,EAAE;AAChC,wBAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,EAAE,CAAC,EAAE,EAAE;4BAChC,IAAI,UAAU,CAAC,SAAS,GAAG,CAAC,EAAE,SAAS,GAAG,CAAC,CAAC,EAAE;gCAC5C,IAAI,GAAG,KAAK;gCACZ;4BACF;wBACF;AACA,wBAAA,IAAI,CAAC,IAAI;4BAAE;oBACb;oBAEA,IAAI,IAAI,EAAE;wBACR,QAAQ,GAAG,SAAS;wBACpB,QAAQ,GAAG,SAAS;wBACpB,MAAM,GAAG,IAAI;oBACf;yBAAO;AACL,wBAAA,SAAS,EAAE;wBACX,IAAI,SAAS,GAAG,OAAO,GAAG,iBAAiB,CAAC,MAAM,EAAE;4BAClD,SAAS,GAAG,CAAC;AACb,4BAAA,SAAS,EAAE;wBACb;oBACF;gBACF;gBACA,SAAS,IAAI,OAAO;AACpB,gBAAA,IAAI,SAAS,IAAI,iBAAiB,CAAC,MAAM,EAAE;oBACzC,SAAS,GAAG,CAAC;AACb,oBAAA,SAAS,EAAE;gBACb;YACF;YAEA,MAAM,GAAG,CAAC,QAAQ,IAAI,CAAC,IAAI,OAAO;YAClC,MAAM,GAAG,CAAC,QAAQ,IAAI,CAAC,IAAI,OAAO;AAElC,YAAA,KAAK,IAAI,CAAC,GAAG,QAAS,EAAE,CAAC,GAAG,MAAO,EAAE,CAAC,EAAE,EAAE;AACxC,gBAAA,KAAK,IAAI,CAAC,GAAG,QAAS,EAAE,CAAC,GAAG,MAAO,EAAE,CAAC,EAAE,EAAE;AACxC,oBAAA,WAAW,CAAC,CAAC,EAAE,CAAC,CAAC;gBACnB;YACF;;YAGA,MAAM,YAAY,GAAG,QAAS;YAC9B,MAAM,UAAU,GAAG,MAAO;;AAG1B,YAAA,OAAO,gBAAgB,CAAC,MAAM,IAAI,UAAU,EAAE;AAC5C,gBAAA,gBAAgB,CAAC,IAAI,CAAC,gBAAgB,CAAC,gBAAgB,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC;YACnF;AAEA,YAAA,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,gBAAgB,CAAC,MAAM,GAAG,CAAC,CAAC;AAC9D,YAAA,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,gBAAgB,CAAC,MAAM,GAAG,CAAC,CAAC;YAC5D,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,gBAAgB,CAAC,EAAE,CAAC,GAAG,gBAAgB,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC;AAErF,YAAA,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC;AAChC,YAAA,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,WAAW,EAAE,MAAM,CAAC,GAAG,EAAEA,kBAAK,CAAC,SAAS,CAAC,GAAG,CAAC;;;YAIxE,KAAK,CAAC,cAAc,EAAE;AACtB,YAAA,IAAI,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE;AACxB,gBAAA,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,WAAW,EAAE,MAAM,CAAC,GAAG,EAAEA,kBAAK,CAAC,SAAS,CAAC,GAAG,CAAC;YAC1E;YAEA,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAS,EAAE,MAAM,EAAE,MAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;QAC/G;;QAGA,MAAM,eAAe,GAAG,IAAI,CAAC,GAAG,CAAC,yBAAyB,CAAC,MAAM,EAAE,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC;AAC/F,QAAA,MAAM,iBAAiB,GAAG,CAAC,GAAG,yBAAyB,CAAC;;AAGxD,QAAA,KAAK,IAAI,CAAC,GAAG,yBAAyB,CAAC,MAAM,EAAE,CAAC,GAAG,eAAe,EAAE,CAAC,EAAE,EAAE;YACvE,IAAI,OAAO,GAAG,CAAC;;AAGf,YAAA,IAAI,QAAQ,KAAK,MAAM,EAAE;gBACvB,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC;AACnF,gBAAA,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE;AAC3B,oBAAA,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,iBAAiB,EAAE,CAAC;gBACjE;YACF;iBAAO;gBACL,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,QAAQ,EAAE,aAAa,CAAC;AACvD,gBAAA,OAAO,GAAG,MAAM,CAAC,KAAK;YACxB;AACA,YAAA,iBAAiB,CAAC,IAAI,CAAC,OAAO,CAAC;QACjC;;AAGA,QAAA,MAAM,UAAU,GAAG,gBAAgB,CAAA;AACnC,QAAA,MAAM,UAAU,GAAG,CAAC,CAAC,CAAC;AACtB,QAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,iBAAiB,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;AACjD,YAAA,IAAI,IAAI,GAAG,iBAAiB,CAAC,CAAC,CAAC;;AAE/B,YAAA,IAAI,IAAI,KAAK,CAAC,EAAE;gBACd,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,EAAE,CAAC,QAAQ,KAAK,CAAC,CAAC;AACvF,gBAAA,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE;AAC3B,oBAAA,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,iBAAiB,EAAE,CAAC;gBAC3D;AACA,gBAAA,iBAAiB,CAAC,CAAC,CAAC,GAAG,IAAI;YAC7B;AACA,YAAA,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,MAAM,CAAC;QAChD;;AAGA,QAAA,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE;YACxB,MAAM,CAAC,GAAG,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,WAAW;YAEjD,OAAO,UAAU,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,EAAE;AACvC,gBAAA,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC;YACjE;YAEA,MAAM,UAAU,GAAG,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC;YAC5C,MAAM,QAAQ,GAAG,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC;AACxC,YAAA,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,GAAG,UAAU,GAAG,MAAM,CAAC;YAE9D,MAAM,CAAC,GAAG,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,UAAU;YAEhD,MAAM,WAAW,GAAG,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC;YAC7C,MAAM,SAAS,GAAG,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC;AACzC,YAAA,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,GAAG,WAAW,GAAG,MAAM,CAAC;AAEjE,YAAA,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI;YAEhC,IAAI,SAAS,CAAC,eAAe,EAAE,KAAKA,kBAAK,CAAC,YAAY,CAAC,QAAQ,EAAE;gBAC/D,SAAS,CAAC,eAAe,CAACA,kBAAK,CAAC,YAAY,CAAC,QAAQ,CAAC;YACxD;AAEA,YAAA,IAAI,SAAS,CAAC,WAAW,CAACA,kBAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,KAAK,CAAC,EAAE;gBACtD,SAAS,CAAC,WAAW,CAACA,kBAAK,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;YAC3C;AACA,YAAA,IAAI,SAAS,CAAC,WAAW,CAACA,kBAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,KAAK,CAAC,EAAE;gBACrD,SAAS,CAAC,WAAW,CAACA,kBAAK,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;YAC1C;AAEA,YAAA,IAAI,SAAS,CAAC,QAAQ,EAAE,CAAC,IAAI,KAAKA,kBAAK,CAAC,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,QAAQ,EAAE,CAAC,KAAK,GAAG,UAAU,CAAC,GAAG,GAAG,EAAE;AAC7G,gBAAA,SAAS,CAAC,QAAQ,CAAC,UAAU,CAAC;YAChC;AACA,YAAA,IAAI,SAAS,CAAC,SAAS,EAAE,CAAC,IAAI,KAAKA,kBAAK,CAAC,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,SAAS,EAAE,CAAC,KAAK,GAAG,WAAW,CAAC,GAAG,GAAG,EAAE;AAChH,gBAAA,SAAS,CAAC,SAAS,CAAC,WAAW,CAAC;YAClC;QACF;;AAGA,QAAA,MAAM,eAAe,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,UAAU,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC;QAC/E,MAAM,kBAAkB,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE;QAChD,IAAI,kBAAkB,CAAC,IAAI,KAAKA,kBAAK,CAAC,IAAI,CAAC,IAAI,IAAI,kBAAkB,CAAC,IAAI,KAAKA,kBAAK,CAAC,IAAI,CAAC,SAAS,EAAE;AACnG,YAAA,MAAM,iBAAiB,GAAG,eAAe,GAAG,UAAU,GAAG,aAAa;AACtE,YAAA,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,iBAAiB,CAAC;QACxC;IACF;AAEA;;AAEG;AACK,IAAA,aAAa,CAAC,MAAuB,EAAE,cAAsB,EAAE,GAAW,EAAA;QAChF,MAAM,QAAQ,GAAa,EAAE;QAC7B,IAAI,SAAS,GAAG,CAAC;QACjB,IAAI,OAAO,GAAG,CAAC;QACf,MAAM,SAAS,GAAa,EAAE;QAE9B,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,KAAI;YACtB,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,EAAE,cAAc,CAAC;AACjD,YAAA,IAAI,MAAM,CAAC,IAAI,KAAK,IAAI,IAAI,MAAM,CAAC,IAAI,KAAK,GAAG,EAAE;AAC/C,gBAAA,QAAQ,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,KAAK;AAC1B,gBAAA,SAAS,IAAI,MAAM,CAAC,KAAK;YAC3B;AAAO,iBAAA,IAAI,MAAM,CAAC,IAAI,KAAK,IAAI,EAAE;AAC/B,gBAAA,OAAO,IAAI,MAAM,CAAC,KAAK;AACvB,gBAAA,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC;AACf,gBAAA,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;YACnB;iBAAO;AACL,gBAAA,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC;YACjB;AACF,QAAA,CAAC,CAAC;AAEF,QAAA,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,GAAG;QACtD,SAAS,IAAI,SAAS;AAEtB,QAAA,MAAM,cAAc,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,cAAc,GAAG,SAAS,CAAC;AAC9D,QAAA,IAAI,OAAO,GAAG,CAAC,EAAE;AACf,YAAA,SAAS,CAAC,OAAO,CAAC,CAAC,IAAG;AACpB,gBAAA,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,cAAc,CAAC;gBACzD,MAAM,KAAK,GAAG,CAAC,MAAM,CAAC,KAAK,GAAG,OAAO,IAAI,cAAc;AACvD,gBAAA,QAAQ,CAAC,CAAC,CAAC,GAAG,KAAK;AACrB,YAAA,CAAC,CAAC;QACJ;AAEA,QAAA,OAAO,QAAQ;IACjB;AACD;AAED;;AAEG;AACI,MAAM,IAAI,GAAG,CAAC,KAAgB,KAAK,IAAI,QAAQ,CAAC,KAAK;;;;;"}
|
|
1
|
+
{"version":3,"file":"grid.canvas.util.js","sources":["../../../../src/canvas/grid.canvas.util.ts"],"sourcesContent":["import type { GridProps, GridTrackSize, GridItemProps } from '@/canvas/canvas.type.js'\nimport { BoxNode, RowNode } from '@/canvas/layout.canvas.util.js'\nimport { Style } from '@/constant/common.const.js'\nimport { parsePercentage } from '@/canvas/canvas.helper.js'\n\n/**\n * GridItem Node. Theoretically just a BoxNode but typed differently in factory.\n * In runtime, it behaves almost like a BoxNode, but we can detect it if needed,\n * or simply rely on the props being present in the instance.\n */\nexport class GridItemNode extends BoxNode {\n constructor(props: GridItemProps) {\n super({\n ...props,\n name: 'GridItem',\n })\n }\n}\n\n/**\n * Factory for GridItem.\n */\nexport const GridItem = (props: GridItemProps) => new GridItemNode(props)\n\n/**\n * Grid layout node that arranges children in a 2D grid.\n * Implements a simplified version of the CSS Grid Layout algorithm.\n */\nexport class GridNode extends RowNode {\n /**\n * Creates a new grid layout node\n * @param props Grid configuration properties\n */\n constructor(props: GridProps) {\n super({\n ...props,\n name: props.name || 'Grid',\n flexWrap: Style.Wrap.Wrap,\n })\n }\n\n /**\n * Helper to parse a track size definition.\n */\n private parseTrack(track: GridTrackSize, availableSpace: number): { type: 'px' | '%' | 'fr' | 'auto'; value: number } {\n if (typeof track === 'number') {\n return { type: 'px', value: track }\n }\n if (track === 'auto') {\n return { type: 'auto', value: 0 }\n }\n if (typeof track === 'string') {\n if (track.endsWith('fr')) {\n return { type: 'fr', value: parseFloat(track) }\n }\n if (track.endsWith('%')) {\n return { type: '%', value: parsePercentage(track, availableSpace) }\n }\n // Try parsing as number (px) if just string \"100\"\n const num = parseFloat(track)\n if (!isNaN(num)) return { type: 'px', value: num }\n }\n return { type: 'auto', value: 0 }\n }\n\n /**\n * Parses the gap property into pixels.\n */\n private getGapPixels(gap: GridProps['gap'], width: number, height: number) {\n let rowGap = 0\n let colGap = 0\n\n if (typeof gap === 'number') {\n rowGap = colGap = gap\n } else if (typeof gap === 'string') {\n const val = parsePercentage(gap, width) // Use width as base for simplicity if %\n rowGap = colGap = val\n } else if (gap && typeof gap === 'object') {\n const colVal = gap.Column ?? gap.All ?? 0\n const rowVal = gap.Row ?? gap.All ?? 0\n colGap = parsePercentage(colVal as string | number, width)\n rowGap = parsePercentage(rowVal as string | number, height)\n }\n\n return { rowGap, colGap }\n }\n\n /**\n * Update layout calculations after the initial layout is computed.\n */\n protected override updateLayoutBasedOnComputedSize() {\n // 1. Get Container Dimensions\n let width = this.node.getComputedWidth()\n\n // When parent has minWidth (percentage), the computed width may grow beyond\n // the intended minWidth to fit content. Constrain to minWidth if it's a percentage.\n const minWidth = this.node.getMinWidth()\n if (minWidth.unit === Style.Unit.Percent && this.node.getParent()) {\n const parentWidth = this.node.getParent()!.getComputedWidth()\n if (!isNaN(parentWidth) && parentWidth > 0) {\n const intendedMinWidth = (minWidth.value / 100) * parentWidth\n // Constrain width to the intended minWidth percentage\n if (width > intendedMinWidth) {\n width = intendedMinWidth\n }\n }\n }\n\n const paddingLeft = this.node.getComputedPadding(Style.Edge.Left)\n const paddingRight = this.node.getComputedPadding(Style.Edge.Right)\n const paddingTop = this.node.getComputedPadding(Style.Edge.Top)\n const paddingBottom = this.node.getComputedPadding(Style.Edge.Bottom)\n\n const contentWidth = Math.max(0, width - paddingLeft - paddingRight)\n const computedHeight = this.node.getComputedHeight()\n const contentHeight = Math.max(0, computedHeight - paddingTop - paddingBottom)\n\n const { templateColumns, templateRows, autoRows = 'auto', gap, columns } = this.props as GridProps\n\n // 2. Resolve Gaps\n const { rowGap, colGap } = this.getGapPixels(gap, contentWidth, contentHeight)\n\n // 3. Resolve Columns (Tracks)\n let explicitColTracks: GridTrackSize[] = templateColumns || []\n if (explicitColTracks.length === 0 && columns) {\n explicitColTracks = Array(columns).fill('1fr')\n }\n if (explicitColTracks.length === 0) explicitColTracks = ['1fr']\n\n const resolvedColTracks = this.resolveTracks(explicitColTracks, contentWidth, colGap)\n\n // Pre-calculate Col Offsets needed for placement/width\n const colOffsetsValues = [0]\n for (let i = 0; i < resolvedColTracks.length; i++) {\n colOffsetsValues.push(colOffsetsValues[i] + resolvedColTracks[i] + colGap)\n }\n\n // 4. Place Items & Resolve Explicit Row Tracks\n const explicitRowTracks = templateRows || []\n const resolvedExplicitRowTracks = this.resolveTracks(explicitRowTracks, contentHeight, rowGap)\n\n const cells: boolean[][] = [] // true if occupied\n const items: { node: BoxNode; rowStart: number; rowEnd: number; colStart: number; colEnd: number }[] = []\n\n const isOccupied = (r: number, c: number) => {\n if (!cells[r]) return false\n return cells[r][c] === true\n }\n const setOccupied = (r: number, c: number) => {\n if (!cells[r]) cells[r] = []\n cells[r][c] = true\n }\n\n let cursorRow = 0\n let cursorCol = 0\n\n for (const child of this.children) {\n const childProps = child.props as GridItemProps\n const { gridColumn, gridRow } = childProps\n\n let colStart: number | undefined\n let colEnd: number | undefined\n let colSpan = 1\n let rowStart: number | undefined\n let rowEnd: number | undefined\n let rowSpan = 1\n\n // ... Grid Placement Logic ...\n if (gridColumn) {\n const parts = gridColumn.split('/').map(s => s.trim())\n if (parts[0]) {\n if (parts[0].startsWith('span')) {\n colSpan = parseInt(parts[0].replace('span', '')) || 1\n } else {\n colStart = parseInt(parts[0]) - 1\n }\n }\n if (parts[1]) {\n if (parts[1].startsWith('span')) {\n const span = parseInt(parts[1].replace('span', '')) || 1\n if (colStart !== undefined) {\n colEnd = colStart + span\n colSpan = span\n } else {\n // If start is undefined but end is span? Unusual. Treat as span.\n colSpan = span\n }\n } else {\n colEnd = parseInt(parts[1]) - 1\n if (colStart !== undefined) {\n colSpan = colEnd - colStart\n }\n }\n }\n }\n\n if (gridRow) {\n const parts = gridRow.split('/').map(s => s.trim())\n if (parts[0]) {\n if (parts[0].startsWith('span')) {\n rowSpan = parseInt(parts[0].replace('span', '')) || 1\n } else {\n rowStart = parseInt(parts[0]) - 1\n }\n }\n if (parts[1]) {\n if (parts[1].startsWith('span')) {\n const span = parseInt(parts[1].replace('span', '')) || 1\n if (rowStart !== undefined) {\n rowEnd = rowStart + span\n rowSpan = span\n } else {\n rowSpan = span\n }\n } else {\n rowEnd = parseInt(parts[1]) - 1\n if (rowStart !== undefined) {\n rowSpan = rowEnd - rowStart\n }\n }\n }\n }\n\n if (colStart !== undefined && rowStart !== undefined) {\n // Fixed position: Check overlap in simpler V1? Or just place?\n // Just place.\n } else {\n // Auto placement\n let placed = false\n while (!placed) {\n if (!cells[cursorRow]) cells[cursorRow] = []\n\n if (colStart !== undefined) cursorCol = colStart\n\n let fits = true\n for (let r = 0; r < rowSpan; r++) {\n for (let c = 0; c < colSpan; c++) {\n if (isOccupied(cursorRow + r, cursorCol + c)) {\n fits = false\n break\n }\n }\n if (!fits) break\n }\n\n if (fits) {\n rowStart = cursorRow\n colStart = cursorCol\n placed = true\n } else {\n cursorCol++\n if (cursorCol + colSpan > resolvedColTracks.length) {\n cursorCol = 0\n cursorRow++\n }\n }\n }\n cursorCol += colSpan\n if (cursorCol >= resolvedColTracks.length) {\n cursorCol = 0\n cursorRow++\n }\n }\n\n rowEnd = (rowStart ?? 0) + rowSpan\n colEnd = (colStart ?? 0) + colSpan\n\n for (let r = rowStart!; r < rowEnd!; r++) {\n for (let c = colStart!; c < colEnd!; c++) {\n setOccupied(r, c)\n }\n }\n\n // CRITICAL FIX: Pre-set width on item to ensure height calculation is accurate later\n const itemColStart = colStart!\n const itemColEnd = colEnd!\n\n // Extend local offsets if needed for spanned columns beyond track count (rare but safe)\n while (colOffsetsValues.length <= itemColEnd) {\n colOffsetsValues.push(colOffsetsValues[colOffsetsValues.length - 1] + 0 + colGap)\n }\n\n const cs = Math.min(itemColStart, colOffsetsValues.length - 1)\n const ce = Math.min(itemColEnd, colOffsetsValues.length - 1)\n const targetWidth = Math.max(0, colOffsetsValues[ce] - colOffsetsValues[cs] - colGap)\n\n child.node.setWidth(targetWidth)\n child.node.calculateLayout(targetWidth, Number.NaN, Style.Direction.LTR)\n\n // Recursively finalize nested children (e.g. inner Grids) so their\n // computed heights are accurate before we measure row sizes.\n child.finalizeLayout()\n if (child.node.isDirty()) {\n child.node.calculateLayout(targetWidth, Number.NaN, Style.Direction.LTR)\n }\n\n items.push({ node: child, rowStart: rowStart!, rowEnd: rowEnd!, colStart: itemColStart, colEnd: itemColEnd })\n }\n\n // 6. Finalize Rows (Implicit)\n const totalRowsNeeded = Math.max(resolvedExplicitRowTracks.length, ...items.map(i => i.rowEnd))\n const resolvedRowTracks = [...resolvedExplicitRowTracks]\n\n // Fill implicit rows\n for (let r = resolvedExplicitRowTracks.length; r < totalRowsNeeded; r++) {\n let rowSize = 0\n\n // Better 'auto' handling:\n if (autoRows === 'auto') {\n const rowItems = items.filter(i => i.rowStart === r && i.rowEnd - i.rowStart === 1)\n for (const item of rowItems) {\n rowSize = Math.max(rowSize, item.node.node.getComputedHeight())\n }\n } else {\n const parsed = this.parseTrack(autoRows, contentHeight)\n rowSize = parsed.value\n }\n resolvedRowTracks.push(rowSize)\n }\n\n // 6. Calculate Offsets (Rows) & Final Layout Application\n const colOffsets = colOffsetsValues // Re-use\n const rowOffsets = [0]\n for (let i = 0; i < resolvedRowTracks.length; i++) {\n let size = resolvedRowTracks[i]\n // Re-check auto-sized explicit rows (value 0)\n if (size === 0) {\n const rowItems = items.filter(it => it.rowStart === i && it.rowEnd - it.rowStart === 1)\n for (const item of rowItems) {\n size = Math.max(size, item.node.node.getComputedHeight())\n }\n resolvedRowTracks[i] = size\n }\n rowOffsets.push(rowOffsets[i] + size + rowGap)\n }\n\n // 7. Apply Positions\n for (const item of items) {\n const x = colOffsets[item.colStart] + paddingLeft\n\n while (colOffsets.length <= item.colEnd) {\n colOffsets.push(colOffsets[colOffsets.length - 1] + 0 + colGap)\n }\n\n const widthStart = colOffsets[item.colStart]\n const widthEnd = colOffsets[item.colEnd]\n const totalWidth = Math.max(0, widthEnd - widthStart - colGap)\n\n const y = rowOffsets[item.rowStart] + paddingTop\n\n const heightStart = rowOffsets[item.rowStart]\n const heightEnd = rowOffsets[item.rowEnd]\n const totalHeight = Math.max(0, heightEnd - heightStart - rowGap)\n\n const childNode = item.node.node\n\n if (childNode.getPositionType() !== Style.PositionType.Absolute) {\n childNode.setPositionType(Style.PositionType.Absolute)\n }\n\n if (childNode.getPosition(Style.Edge.Left).value !== x) {\n childNode.setPosition(Style.Edge.Left, x)\n }\n if (childNode.getPosition(Style.Edge.Top).value !== y) {\n childNode.setPosition(Style.Edge.Top, y)\n }\n\n if (childNode.getWidth().unit !== Style.Unit.Point || Math.abs(childNode.getWidth().value - totalWidth) > 0.1) {\n childNode.setWidth(totalWidth)\n }\n if (childNode.getHeight().unit !== Style.Unit.Point || Math.abs(childNode.getHeight().value - totalHeight) > 0.1) {\n childNode.setHeight(totalHeight)\n }\n }\n\n // 9. Update Grid Height\n const totalGridHeight = Math.max(0, rowOffsets[rowOffsets.length - 1] - rowGap)\n const currentHeightStyle = this.node.getHeight()\n if (currentHeightStyle.unit === Style.Unit.Auto || currentHeightStyle.unit === Style.Unit.Undefined) {\n const targetTotalHeight = totalGridHeight + paddingTop + paddingBottom\n this.node.setHeight(targetTotalHeight)\n }\n }\n\n /**\n * Resolves track sizes to pixels.\n */\n private resolveTracks(tracks: GridTrackSize[], availableSpace: number, gap: number): number[] {\n const resolved: number[] = []\n let usedSpace = 0\n let totalFr = 0\n const frIndices: number[] = []\n\n tracks.forEach((t, i) => {\n const parsed = this.parseTrack(t, availableSpace)\n if (parsed.type === 'px' || parsed.type === '%') {\n resolved[i] = parsed.value\n usedSpace += parsed.value\n } else if (parsed.type === 'fr') {\n totalFr += parsed.value\n resolved[i] = 0\n frIndices.push(i)\n } else {\n resolved[i] = 0\n }\n })\n\n const totalGaps = Math.max(0, tracks.length - 1) * gap\n usedSpace += totalGaps\n\n const remainingSpace = Math.max(0, availableSpace - usedSpace)\n if (totalFr > 0) {\n frIndices.forEach(i => {\n const parsed = this.parseTrack(tracks[i], availableSpace)\n const share = (parsed.value / totalFr) * remainingSpace\n resolved[i] = share\n })\n }\n\n return resolved\n }\n}\n\n/**\n * Factory function to create a new GridNode instance.\n */\nexport const Grid = (props: GridProps) => new GridNode(props)\n"],"names":["RowNode","Style","parsePercentage"],"mappings":"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"}
|
|
@@ -76,6 +76,12 @@ export declare class TextNode extends BoxNode {
|
|
|
76
76
|
private parseRichText;
|
|
77
77
|
private formatSpacing;
|
|
78
78
|
private parseSpacingToPx;
|
|
79
|
+
/**
|
|
80
|
+
* Adds manual letter spacing compensation to a measured text width.
|
|
81
|
+
* Needed because skia-canvas ctx.measureText() does not include letterSpacing in the returned width,
|
|
82
|
+
* even though letterSpacing IS applied during rendering (fillText/strokeText).
|
|
83
|
+
*/
|
|
84
|
+
private addLetterSpacingExtra;
|
|
79
85
|
/**
|
|
80
86
|
* Generates a CSS font string by combining base TextProps with optional TextSegment styling.
|
|
81
87
|
* Follows browser font string format: "font-style font-weight font-size font-family"
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"text.canvas.util.d.ts","sourceRoot":"","sources":["../../../src/canvas/text.canvas.util.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAe,MAAM,yBAAyB,CAAA;AACrE,OAAO,EAAU,KAAK,wBAAwB,EAA2B,MAAM,aAAa,CAAA;AAC5F,OAAO,EAAE,OAAO,EAAE,MAAM,gCAAgC,CAAA;AAGxD;;;GAGG;AACH,qBAAa,QAAS,SAAQ,OAAO;IACnC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAoB;IAC7C,OAAO,CAAC,KAAK,CAAsB;IACnC,OAAO,CAAC,MAAM,CAAC,kBAAkB,CAAwC;IACzE,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAU;IACxC,OAAO,CAAC,WAAW,CAAe;IAClC,OAAO,CAAC,WAAW,CAAe;IAClC,OAAO,CAAC,kBAAkB,CAAe;IAEjC,KAAK,EAAE,SAAS,GAAG;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAA;gBAElC,IAAI,GAAE,MAAM,GAAG,MAAW,EAAE,KAAK,GAAE,SAAc;IAuB7D;;;;;;;;OAQG;WACW,gBAAgB,CAC5B,GAAG,EAAE,wBAAwB,EAC7B,IAAI,EAAE,MAAM,EACZ,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,KAAK,GAAE;QACL,UAAU,CAAC,EAAE,MAAM,CAAA;QACnB,QAAQ,CAAC,EAAE,MAAM,CAAA;QACjB,UAAU,CAAC,EAAE,SAAS,CAAC,YAAY,CAAC,CAAA;QACpC,SAAS,CAAC,EAAE,SAAS,CAAC,WAAW,CAAC,CAAA;QAClC,KAAK,CAAC,EAAE,MAAM,CAAA;QACd,SAAS,CAAC,EAAE,wBAAwB,CAAC,WAAW,CAAC,CAAA;QACjD,YAAY,CAAC,EAAE,wBAAwB,CAAC,cAAc,CAAC,CAAA;KACnD;cAwBW,aAAa,IAAI,IAAI;IAoDxC;;;;;;;;;;;;;;;;;OAiBG;IACH,OAAO,CAAC,sBAAsB;IA8B9B;;;;;;;;;;;;;;;;;OAiBG;IACH,OAAO,CAAC,aAAa;IA+ErB,OAAO,CAAC,aAAa;IAKrB,OAAO,CAAC,gBAAgB;IAyBxB;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,aAAa;IAiCrB;;OAEG;IACH,OAAO,CAAC,yBAAyB;IAQjC;;;;;;;;;;;;;;OAcG;IACH,OAAO,CAAC,WAAW;
|
|
1
|
+
{"version":3,"file":"text.canvas.util.d.ts","sourceRoot":"","sources":["../../../src/canvas/text.canvas.util.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAe,MAAM,yBAAyB,CAAA;AACrE,OAAO,EAAU,KAAK,wBAAwB,EAA2B,MAAM,aAAa,CAAA;AAC5F,OAAO,EAAE,OAAO,EAAE,MAAM,gCAAgC,CAAA;AAGxD;;;GAGG;AACH,qBAAa,QAAS,SAAQ,OAAO;IACnC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAoB;IAC7C,OAAO,CAAC,KAAK,CAAsB;IACnC,OAAO,CAAC,MAAM,CAAC,kBAAkB,CAAwC;IACzE,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAU;IACxC,OAAO,CAAC,WAAW,CAAe;IAClC,OAAO,CAAC,WAAW,CAAe;IAClC,OAAO,CAAC,kBAAkB,CAAe;IAEjC,KAAK,EAAE,SAAS,GAAG;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAA;gBAElC,IAAI,GAAE,MAAM,GAAG,MAAW,EAAE,KAAK,GAAE,SAAc;IAuB7D;;;;;;;;OAQG;WACW,gBAAgB,CAC5B,GAAG,EAAE,wBAAwB,EAC7B,IAAI,EAAE,MAAM,EACZ,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,KAAK,GAAE;QACL,UAAU,CAAC,EAAE,MAAM,CAAA;QACnB,QAAQ,CAAC,EAAE,MAAM,CAAA;QACjB,UAAU,CAAC,EAAE,SAAS,CAAC,YAAY,CAAC,CAAA;QACpC,SAAS,CAAC,EAAE,SAAS,CAAC,WAAW,CAAC,CAAA;QAClC,KAAK,CAAC,EAAE,MAAM,CAAA;QACd,SAAS,CAAC,EAAE,wBAAwB,CAAC,WAAW,CAAC,CAAA;QACjD,YAAY,CAAC,EAAE,wBAAwB,CAAC,cAAc,CAAC,CAAA;KACnD;cAwBW,aAAa,IAAI,IAAI;IAoDxC;;;;;;;;;;;;;;;;;OAiBG;IACH,OAAO,CAAC,sBAAsB;IA8B9B;;;;;;;;;;;;;;;;;OAiBG;IACH,OAAO,CAAC,aAAa;IA+ErB,OAAO,CAAC,aAAa;IAKrB,OAAO,CAAC,gBAAgB;IAyBxB;;;;OAIG;IACH,OAAO,CAAC,qBAAqB;IAM7B;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,aAAa;IAiCrB;;OAEG;IACH,OAAO,CAAC,yBAAyB;IAQjC;;;;;;;;;;;;;;OAcG;IACH,OAAO,CAAC,WAAW;IA+NnB;;;;;;;;;OASG;IACH,OAAO,CAAC,YAAY;IA6KpB;;;;;;;OAOG;IACH,OAAO,CAAC,aAAa;IAmErB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAQzB;;;;;;;;;;;;;;;;OAgBG;cACgB,cAAc,CAAC,GAAG,EAAE,wBAAwB,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;CAkXrH;AAED;;GAEG;AACH,eAAO,MAAM,IAAI,GAAI,MAAM,MAAM,GAAG,MAAM,EAAE,QAAQ,SAAS,aAA8B,CAAA"}
|
|
@@ -262,6 +262,17 @@ class TextNode extends layout_canvas_util.BoxNode {
|
|
|
262
262
|
}
|
|
263
263
|
return 0; // Default fallback
|
|
264
264
|
}
|
|
265
|
+
/**
|
|
266
|
+
* Adds manual letter spacing compensation to a measured text width.
|
|
267
|
+
* Needed because skia-canvas ctx.measureText() does not include letterSpacing in the returned width,
|
|
268
|
+
* even though letterSpacing IS applied during rendering (fillText/strokeText).
|
|
269
|
+
*/
|
|
270
|
+
addLetterSpacingExtra(text, measuredWidth, letterSpacingPx) {
|
|
271
|
+
if (letterSpacingPx === 0 || text.length === 0)
|
|
272
|
+
return measuredWidth;
|
|
273
|
+
const charCount = [...text].length;
|
|
274
|
+
return measuredWidth + (charCount > 1 ? (charCount - 1) * letterSpacingPx : 0);
|
|
275
|
+
}
|
|
265
276
|
/**
|
|
266
277
|
* Generates a CSS font string by combining base TextProps with optional TextSegment styling.
|
|
267
278
|
* Follows browser font string format: "font-style font-weight font-size font-family"
|
|
@@ -340,6 +351,7 @@ class TextNode extends layout_canvas_util.BoxNode {
|
|
|
340
351
|
ctx.letterSpacing = this.formatSpacing(this.props.letterSpacing);
|
|
341
352
|
ctx.wordSpacing = 'normal'; // Handled manually via parsedWordSpacingPx
|
|
342
353
|
const parsedWordSpacingPx = this.parseSpacingToPx(this.props.wordSpacing, baseFontSize);
|
|
354
|
+
const parsedLetterSpacingPx = this.parseSpacingToPx(this.props.letterSpacing, baseFontSize);
|
|
343
355
|
// Pre-measure each text segment width with its specific styling
|
|
344
356
|
for (const segment of this.segments) {
|
|
345
357
|
ctx.font = this.getFontString(segment);
|
|
@@ -355,13 +367,13 @@ class TextNode extends layout_canvas_util.BoxNode {
|
|
|
355
367
|
if (ctx.fontVariant !== 'normal')
|
|
356
368
|
ctx.fontVariant = 'normal';
|
|
357
369
|
}
|
|
358
|
-
segment.width = ctx.measureText(segment.text).width;
|
|
370
|
+
segment.width = this.addLetterSpacingExtra(segment.text, ctx.measureText(segment.text).width, parsedLetterSpacingPx);
|
|
359
371
|
}
|
|
360
372
|
// Calculate available layout width
|
|
361
373
|
const availableWidthForContent = widthMode === common_const.Style.MeasureMode.Undefined ? Infinity : Math.max(0, widthConstraint);
|
|
362
374
|
const epsilon = 0.001; // Float precision compensation
|
|
363
375
|
// Wrap text into lines based on available width
|
|
364
|
-
this.lines = this.wrapTextRich(ctx, this.segments, availableWidthForContent + epsilon, parsedWordSpacingPx);
|
|
376
|
+
this.lines = this.wrapTextRich(ctx, this.segments, availableWidthForContent + epsilon, parsedWordSpacingPx, parsedLetterSpacingPx);
|
|
365
377
|
// Initialize line metrics arrays
|
|
366
378
|
this.lineHeights = []; // Final heights including leading
|
|
367
379
|
this.lineAscents = []; // Text ascent heights
|
|
@@ -481,7 +493,7 @@ class TextNode extends layout_canvas_util.BoxNode {
|
|
|
481
493
|
if (ctx.fontVariant !== 'normal')
|
|
482
494
|
ctx.fontVariant = 'normal';
|
|
483
495
|
}
|
|
484
|
-
const wordWidth = ctx.measureText(word).width;
|
|
496
|
+
const wordWidth = this.addLetterSpacingExtra(word, ctx.measureText(word).width, parsedLetterSpacingPx);
|
|
485
497
|
if (!firstWordInSingleLine) {
|
|
486
498
|
singleLineWidth += spaceWidth + parsedWordSpacingPx;
|
|
487
499
|
}
|
|
@@ -556,7 +568,7 @@ class TextNode extends layout_canvas_util.BoxNode {
|
|
|
556
568
|
* @param parsedWordSpacingPx Additional spacing to add between words in pixels
|
|
557
569
|
* @returns Array of lines, where each line contains styled text segments
|
|
558
570
|
*/
|
|
559
|
-
wrapTextRich(ctx, segments, maxWidth, parsedWordSpacingPx) {
|
|
571
|
+
wrapTextRich(ctx, segments, maxWidth, parsedWordSpacingPx, parsedLetterSpacingPx = 0) {
|
|
560
572
|
const lines = [];
|
|
561
573
|
if (segments.length === 0 || maxWidth <= 0)
|
|
562
574
|
return lines;
|
|
@@ -607,7 +619,7 @@ class TextNode extends layout_canvas_util.BoxNode {
|
|
|
607
619
|
ctx.font = this.getFontString(segmentStyle);
|
|
608
620
|
if (this.props.fontVariant)
|
|
609
621
|
ctx.fontVariant = this.props.fontVariant;
|
|
610
|
-
wordWidth = ctx.measureText(wordOrSpace).width;
|
|
622
|
+
wordWidth = this.addLetterSpacingExtra(wordOrSpace, ctx.measureText(wordOrSpace).width, parsedLetterSpacingPx);
|
|
611
623
|
wordSegment = { text: wordOrSpace, ...segmentStyle, width: wordWidth };
|
|
612
624
|
}
|
|
613
625
|
const needsSpace = currentLineSegments.length > 0 && !/^\s+$/.test(currentLineSegments[currentLineSegments.length - 1].text);
|
|
@@ -626,7 +638,7 @@ class TextNode extends layout_canvas_util.BoxNode {
|
|
|
626
638
|
}
|
|
627
639
|
if (!isSpace) {
|
|
628
640
|
if (wordWidth > maxWidth && maxWidth > 0) {
|
|
629
|
-
const brokenParts = this.breakWordRich(ctx, wordSegment, maxWidth);
|
|
641
|
+
const brokenParts = this.breakWordRich(ctx, wordSegment, maxWidth, parsedLetterSpacingPx);
|
|
630
642
|
if (brokenParts.length > 0) {
|
|
631
643
|
for (let k = 0; k < brokenParts.length - 1; k++) {
|
|
632
644
|
lines.push([brokenParts[k]]);
|
|
@@ -669,7 +681,7 @@ class TextNode extends layout_canvas_util.BoxNode {
|
|
|
669
681
|
ctx.font = this.getFontString(segmentStyle);
|
|
670
682
|
if (this.props.fontVariant)
|
|
671
683
|
ctx.fontVariant = this.props.fontVariant;
|
|
672
|
-
wordWidth = ctx.measureText(wordOrSpace).width;
|
|
684
|
+
wordWidth = this.addLetterSpacingExtra(wordOrSpace, ctx.measureText(wordOrSpace).width, parsedLetterSpacingPx);
|
|
673
685
|
wordSegment = { text: wordOrSpace, ...segmentStyle, width: wordWidth };
|
|
674
686
|
}
|
|
675
687
|
const needsSpace = currentLineSegments.length > 0 && !/^\s+$/.test(currentLineSegments[currentLineSegments.length - 1].text);
|
|
@@ -688,7 +700,7 @@ class TextNode extends layout_canvas_util.BoxNode {
|
|
|
688
700
|
}
|
|
689
701
|
if (!isSpace) {
|
|
690
702
|
if (wordWidth > maxWidth && maxWidth > 0) {
|
|
691
|
-
const brokenParts = this.breakWordRich(ctx, wordSegment, maxWidth);
|
|
703
|
+
const brokenParts = this.breakWordRich(ctx, wordSegment, maxWidth, parsedLetterSpacingPx);
|
|
692
704
|
if (brokenParts.length > 0) {
|
|
693
705
|
for (let k = 0; k < brokenParts.length - 1; k++) {
|
|
694
706
|
lines.push([brokenParts[k]]);
|
|
@@ -721,7 +733,7 @@ class TextNode extends layout_canvas_util.BoxNode {
|
|
|
721
733
|
* @param maxWidth Maximum width allowed for each resulting segment
|
|
722
734
|
* @returns Array of TextSegments, each fitting maxWidth, or original segment if no breaking needed
|
|
723
735
|
*/
|
|
724
|
-
breakWordRich(ctx, segmentToBreak, maxWidth) {
|
|
736
|
+
breakWordRich(ctx, segmentToBreak, maxWidth, parsedLetterSpacingPx = 0) {
|
|
725
737
|
const word = segmentToBreak.text;
|
|
726
738
|
// Copy all style properties to maintain consistent styling across broken segments
|
|
727
739
|
const style = {
|
|
@@ -742,14 +754,14 @@ class TextNode extends layout_canvas_util.BoxNode {
|
|
|
742
754
|
// Process word character by character to find valid break points
|
|
743
755
|
for (const char of word) {
|
|
744
756
|
const testPartText = currentPartText + char;
|
|
745
|
-
const testPartWidth = ctx.measureText(testPartText).width;
|
|
757
|
+
const testPartWidth = this.addLetterSpacingExtra(testPartText, ctx.measureText(testPartText).width, parsedLetterSpacingPx);
|
|
746
758
|
if (testPartWidth > maxWidth) {
|
|
747
759
|
// Current accumulated text exceeds width - create new segment
|
|
748
760
|
if (currentPartText) {
|
|
749
761
|
brokenSegments.push({
|
|
750
762
|
text: currentPartText,
|
|
751
763
|
...style,
|
|
752
|
-
width: ctx.measureText(currentPartText).width,
|
|
764
|
+
width: this.addLetterSpacingExtra(currentPartText, ctx.measureText(currentPartText).width, parsedLetterSpacingPx),
|
|
753
765
|
});
|
|
754
766
|
}
|
|
755
767
|
// Handle current character that caused overflow
|
|
@@ -775,7 +787,7 @@ class TextNode extends layout_canvas_util.BoxNode {
|
|
|
775
787
|
brokenSegments.push({
|
|
776
788
|
text: currentPartText,
|
|
777
789
|
...style,
|
|
778
|
-
width: ctx.measureText(currentPartText).width,
|
|
790
|
+
width: this.addLetterSpacingExtra(currentPartText, ctx.measureText(currentPartText).width, parsedLetterSpacingPx),
|
|
779
791
|
});
|
|
780
792
|
}
|
|
781
793
|
return brokenSegments.length > 0 ? brokenSegments : [segmentToBreak];
|
|
@@ -834,7 +846,8 @@ class TextNode extends layout_canvas_util.BoxNode {
|
|
|
834
846
|
const spaceWidth = this.measureSpaceWidth(ctx);
|
|
835
847
|
// Use a small epsilon for float precision issues
|
|
836
848
|
const epsilon = 0.01;
|
|
837
|
-
const
|
|
849
|
+
const parsedLetterSpacingPx = this.parseSpacingToPx(this.props.letterSpacing, baseFontSize);
|
|
850
|
+
const allLines = this.wrapTextRich(ctx, this.segments, contentWidth + epsilon, parsedWordSpacingPx, parsedLetterSpacingPx);
|
|
838
851
|
const needsEllipsis = this.props.ellipsis && this.props.maxLines !== undefined && allLines.length > this.props.maxLines;
|
|
839
852
|
// Apply maxLines constraint to get the visible lines
|
|
840
853
|
const visibleLines = this.props.maxLines !== undefined && this.props.maxLines > 0 ? allLines.slice(0, this.props.maxLines) : allLines;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"text.canvas.util.js","sources":["../../../../src/canvas/text.canvas.util.ts"],"sourcesContent":["// TODO: Add comprehensive unit tests for this file.\n\nimport type { TextProps, TextSegment } from '@/canvas/canvas.type.js'\nimport { Canvas, type CanvasRenderingContext2D, type FontVariantSetting } from 'skia-canvas'\nimport { BoxNode } from '@/canvas/layout.canvas.util.js'\nimport { Style, MeasureMode } from '@/constant/common.const.js'\n\n/**\n * Node for rendering text content with rich text styling support\n * Supports color and weight variations through HTML-like tags\n */\nexport class TextNode extends BoxNode {\n private readonly segments: TextSegment[] = []\n private lines: TextSegment[][] = []\n private static measurementContext: CanvasRenderingContext2D | null = null\n private readonly metricsString = 'Ag|``'\n private lineHeights: number[] = []\n private lineAscents: number[] = []\n private lineContentHeights: number[] = []\n\n declare props: TextProps & { lineGap: number }\n\n constructor(text: number | string = '', props: TextProps = {}) {\n const initialProps = {\n name: 'TextNode',\n flexShrink: 1,\n lineGap: 0,\n ...props,\n children: undefined,\n }\n super(initialProps)\n this.props = initialProps\n // Process escape sequences before parsing rich text\n const processedText = this.processEscapeSequences(String(text ?? ''))\n this.segments = this.parseRichText(processedText, {\n color: this.props.color,\n weight: this.props.fontWeight,\n size: this.props.fontSize,\n b: this.props.fontWeight === 'bold',\n i: this.props.fontStyle === 'italic',\n })\n this.node.setMeasureFunc(this.measureText.bind(this))\n this.applyDefaults()\n }\n\n /**\n * Renders a simple, single-line text string without complex layout calculations.\n * A lightweight, static utility for drawing text where layout is handled externally.\n * @param ctx The canvas rendering context.\n * @param text The string to render.\n * @param x The x-coordinate for rendering.\n * @param y The y-coordinate for rendering.\n * @param props Basic text styling properties.\n */\n public static renderSimpleText(\n ctx: CanvasRenderingContext2D,\n text: string,\n x: number,\n y: number,\n props: {\n fontFamily?: string\n fontSize?: number\n fontWeight?: TextProps['fontWeight']\n fontStyle?: TextProps['fontStyle']\n color?: string\n textAlign?: CanvasRenderingContext2D['textAlign']\n textBaseline?: CanvasRenderingContext2D['textBaseline']\n } = {},\n ) {\n ctx.save()\n\n const {\n fontFamily = 'sans-serif',\n fontSize = 12,\n fontWeight = 'normal',\n fontStyle = 'normal',\n color = '#333',\n textAlign = 'left',\n textBaseline = 'alphabetic',\n } = props\n\n ctx.font = `${fontStyle} ${fontWeight} ${fontSize}px ${fontFamily}`\n ctx.fillStyle = color\n ctx.textAlign = textAlign\n ctx.textBaseline = textBaseline\n\n ctx.fillText(text, x, y)\n\n ctx.restore()\n }\n\n protected override applyDefaults(): void {\n const textDefaults: Required<\n Pick<TextProps, 'fontSize' | 'fontFamily' | 'fontWeight' | 'fontStyle' | 'color' | 'textAlign' | 'verticalAlign' | 'ellipsis' | 'lineGap'>\n > & {\n lineHeight: undefined | number\n maxLines: undefined | number\n letterSpacing: undefined | number\n wordSpacing: undefined | number\n fontVariant: undefined | FontVariantSetting\n } = {\n fontSize: 16,\n fontFamily: 'sans-serif',\n fontWeight: 'normal',\n fontStyle: 'normal',\n color: 'black',\n textAlign: 'left',\n verticalAlign: 'top',\n fontVariant: undefined,\n lineHeight: undefined,\n lineGap: 0,\n maxLines: undefined,\n ellipsis: false,\n letterSpacing: undefined,\n wordSpacing: undefined,\n }\n\n let defaultsApplied = false\n for (const key of Object.keys(textDefaults) as (keyof typeof textDefaults)[]) {\n if (this.props[key] === undefined && textDefaults[key] !== undefined) {\n this.props[key as string] = textDefaults[key]\n defaultsApplied = true\n }\n }\n\n if (defaultsApplied && !this.node.isDirty()) {\n const affectsMeasurement = [\n 'fontSize',\n 'fontFamily',\n 'fontWeight',\n 'fontStyle',\n 'lineHeight',\n 'maxLines',\n 'lineGap',\n 'letterSpacing',\n 'wordSpacing',\n ].some(measureKey => this.props[measureKey] === textDefaults[measureKey])\n if (affectsMeasurement) {\n this.node.markDirty()\n }\n }\n }\n\n /**\n * Processes Unix-like escape sequences in text strings.\n * Converts escaped characters into their actual representations.\n *\n * Supported escape sequences:\n * - \\n - Newline (line feed)\n * - \\t - Tab (converted to 4 spaces)\n * - \\r - Carriage return (treated as newline)\n * - \\\\ - Literal backslash\n * - \\' - Single quote\n * - \\\" - Double quote\n * - \\0 - Null character (removed)\n * - \\b - Backspace (removed)\n * - \\f - Form feed (treated as newline)\n * - \\v - Vertical tab (treated as newline)\n * @param input Raw text string potentially containing escape sequences\n * @returns Processed string with escape sequences converted\n */\n private processEscapeSequences(input: string): string {\n return input.replace(/\\\\(.)/g, (match, char) => {\n switch (char) {\n case 'n':\n return '\\n' // Newline\n case 't':\n return ' ' // Tab as 4 spaces\n case 'r':\n return '\\n' // Carriage return treated as newline\n case '\\\\':\n return '\\\\' // Literal backslash\n case \"'\":\n return \"'\" // Single quote\n case '\"':\n return '\"' // Double quote\n case '0':\n return '' // Null character (remove)\n case 'b':\n return '' // Backspace (remove)\n case 'f':\n return '\\n' // Form feed as newline\n case 'v':\n return '\\n' // Vertical tab as newline\n default:\n // Unknown escape sequence - keep original\n return match\n }\n })\n }\n\n /**\n * Parses input text with HTML-style markup into styled text segments.\n *\n * Supported tags:\n * - <color=\"value\"> - Sets text color (hex code or CSS color name)\n * - <weight=\"value\"> - Sets font weight (100-900 or keywords like \"bold\")\n * - <size=\"value\"> - Sets font size in pixels\n * - <b> - Makes text bold (shorthand for weight=\"bold\")\n * - <i> - Makes text italic\n *\n * Tag values can use double quotes, single quotes, or no quotes:\n * <color=\"red\">, <color='red'>, <color=red>\n *\n * Tags can be nested and must be properly closed with </tag>\n * @param input Text string containing markup tags\n * @param baseStyle Default style properties to apply to all segments\n * @returns Array of styled text segments with consistent style properties\n */\n private parseRichText(input: string, baseStyle: Partial<TextSegment>): TextSegment[] {\n // Match opening/closing tags with optional quoted/unquoted values\n // Capture groups: (1) closing slash, (2) tag name, (3) double quoted value, (4) single quoted value, (5) unquoted value\n const tagRegex = /<(\\/?)(\\w+)(?:=(?:\"([^\"]*)\"|'([^']*)'|([^\\s>]+)))?>/g\n const stack: Partial<TextSegment>[] = []\n const segments: TextSegment[] = []\n let lastIndex = 0\n let currentStyle: Partial<TextSegment> = { ...baseStyle }\n\n // Helper to create a styled segment ensuring all style properties are included\n const applyStyle = (text: string) => {\n if (!text) return\n segments.push({\n text,\n color: currentStyle.color,\n weight: currentStyle.weight,\n size: currentStyle.size,\n b: currentStyle.b,\n i: currentStyle.i,\n })\n }\n\n let match: RegExpExecArray | null\n while ((match = tagRegex.exec(input))) {\n const [, closingSlash, tagNameStr, quotedVal1, quotedVal2, unquotedVal] = match\n const tagName = tagNameStr.toLowerCase()\n const value = quotedVal1 || quotedVal2 || unquotedVal\n\n // Process text content before the current tag\n applyStyle(input.slice(lastIndex, match.index))\n lastIndex = tagRegex.lastIndex\n\n if (!closingSlash) {\n // Opening tag: Save current style state and apply new style\n stack.push({ ...currentStyle })\n\n switch (tagName) {\n case 'color':\n // Support any valid CSS color value\n currentStyle.color = value as TextSegment['color']\n break\n\n case 'weight':\n // Support numeric weights (100-900) or keywords\n currentStyle.weight = value as TextSegment['weight']\n break\n\n case 'size':\n // Parse pixel size as number, revert to default if invalid\n currentStyle.size = value ? Number(value) : undefined\n if (isNaN(currentStyle.size as number)) {\n console.warn(`[TextNode ${this.key || ''}] Invalid numeric value for size tag: ${value}`)\n currentStyle.size = undefined\n }\n break\n\n case 'b':\n // Simple bold flag\n currentStyle.b = true\n break\n\n case 'i':\n // Simple italic flag\n currentStyle.i = true\n break\n }\n } else {\n // Closing tag: Restore previous style state\n currentStyle = stack.pop() || { ...baseStyle }\n }\n }\n\n // Process remaining text after last tag\n applyStyle(input.slice(lastIndex))\n\n // Don't filter out empty segments - they might represent empty lines\n return segments\n }\n\n private formatSpacing(value: TextProps['letterSpacing'] | TextProps['wordSpacing']) {\n if (typeof value === 'number') return `${value}px`\n return value || 'normal'\n }\n\n private parseSpacingToPx(spacingValue: number | string | undefined, fontSize: number): number {\n if (spacingValue === undefined || spacingValue === 'normal') {\n return 0\n }\n if (typeof spacingValue === 'number') {\n return spacingValue // Treat raw number as px\n }\n if (typeof spacingValue === 'string') {\n const trimmed = spacingValue.trim()\n if (trimmed.endsWith('px')) {\n return parseFloat(trimmed) || 0\n }\n if (trimmed.endsWith('em')) {\n // Convert em based on the current font size\n return (parseFloat(trimmed) || 0) * fontSize\n }\n // Attempt to parse as a raw number (pixels) if no unit\n const parsed = parseFloat(trimmed)\n if (!isNaN(parsed)) {\n return parsed\n }\n }\n return 0 // Default fallback\n }\n\n /**\n * Generates a CSS font string by combining base TextProps with optional TextSegment styling.\n * Follows browser font string format: \"font-style font-weight font-size font-family\"\n *\n * Priority for style properties:\n * - Weight: segment <weight> tag > segment <b> tag > base fontWeight prop\n * - Style: segment <i> > base fontStyle\n * - Size: segment size > base fontSize\n * - Family: base fontFamily\n * @param segmentStyle Optional TextSegment styling to override base props\n * @returns Formatted CSS font string for canvas context\n */\n private getFontString(segmentStyle?: Partial<TextSegment>): string {\n const baseStyle = this.props\n let effectiveWeight: TextSegment['weight'] | number | undefined\n\n // Determine italic style - segment <i> tag overrides base style\n const effectiveStyle = segmentStyle?.i ? 'italic' : baseStyle.fontStyle || 'normal'\n\n // Determine font weight with priority:\n // 1. Segment explicit weight (<weight> tag)\n // 2. Segment bold flag (<b> tag)\n // 3. Base font weight prop\n if (segmentStyle?.weight) {\n effectiveWeight = segmentStyle.weight\n } else if (segmentStyle?.b) {\n effectiveWeight = 'bold'\n } else {\n effectiveWeight = baseStyle.fontWeight || 'normal'\n }\n\n // Use segment size if specified, otherwise base size with 16px default\n const effectiveSize = segmentStyle?.size ? segmentStyle.size : baseStyle.fontSize || 16\n\n // Combine properties into CSS font string format\n const style = {\n fontStyle: effectiveStyle,\n fontWeight: effectiveWeight,\n fontSize: effectiveSize,\n fontFamily: baseStyle.fontFamily || 'sans-serif',\n }\n\n return `${style.fontStyle} ${style.fontWeight} ${style.fontSize}px ${style.fontFamily}`\n }\n\n /**\n * Gets lines to process respecting maxLines constraint\n */\n private getLinesToMeasureOrRender(): TextSegment[][] {\n const maxLines = this.props.maxLines\n if (maxLines !== undefined && maxLines > 0 && this.lines.length > maxLines) {\n return this.lines.slice(0, maxLines)\n }\n return this.lines\n }\n\n /**\n * Measures text dimensions and calculates layout metrics for the YogaLayout engine.\n * Handles text wrapping, line height calculations, and dynamic leading.\n *\n * Line heights are determined by:\n * 1. Using props.lineHeight as fixed pixel value if provided\n * 2. Otherwise calculating dynamic height based on largest font size per line\n * 3. Adding leading space above/below text content\n * 4. Including specified line gaps between lines\n * @param widthConstraint Maximum allowed width in pixels for text layout\n * @param widthMode YogaLayout mode determining how width constraint is applied\n * @returns Calculated minimum dimensions required to render text content\n * - width: Total width needed for text layout\n * - height: Total height including line heights and gaps\n */\n private measureText(widthConstraint: number, widthMode: MeasureMode): { width: number; height: number } {\n // Create measurement canvas if not exists\n if (!TextNode.measurementContext) {\n TextNode.measurementContext = new Canvas(1, 1).getContext('2d')\n }\n const baseFontSize = this.props.fontSize || 16\n const ctx = TextNode.measurementContext!\n ctx.save()\n\n // Setup text measurement context\n ctx.letterSpacing = this.formatSpacing(this.props.letterSpacing)\n ctx.wordSpacing = 'normal' // Handled manually via parsedWordSpacingPx\n const parsedWordSpacingPx = this.parseSpacingToPx(this.props.wordSpacing, baseFontSize)\n\n // Pre-measure each text segment width with its specific styling\n for (const segment of this.segments) {\n ctx.font = this.getFontString(segment)\n if (typeof this.props.fontVariant === 'string') {\n ctx.fontVariant = this.props.fontVariant\n } else if (this.props.fontVariant !== undefined) {\n console.warn(`[TextNode ${this.key || ''}] Invalid fontVariant prop type in measureText (segment width):`, this.props.fontVariant)\n if (ctx.fontVariant !== 'normal') ctx.fontVariant = 'normal'\n } else {\n if (ctx.fontVariant !== 'normal') ctx.fontVariant = 'normal'\n }\n segment.width = ctx.measureText(segment.text).width\n }\n\n // Calculate available layout width\n const availableWidthForContent = widthMode === Style.MeasureMode.Undefined ? Infinity : Math.max(0, widthConstraint)\n const epsilon = 0.001 // Float precision compensation\n\n // Wrap text into lines based on available width\n this.lines = this.wrapTextRich(ctx, this.segments, availableWidthForContent + epsilon, parsedWordSpacingPx)\n\n // Initialize line metrics arrays\n this.lineHeights = [] // Final heights including leading\n this.lineAscents = [] // Text ascent heights\n this.lineContentHeights = [] // Raw content heights (ascent + descent)\n\n let totalTextHeight = 0\n const linesToMeasure = this.getLinesToMeasureOrRender()\n const numLines = linesToMeasure.length\n const defaultLineHeightMultiplier = 1.2 // Base leading multiplier\n\n // Calculate metrics for each line\n for (const line of linesToMeasure) {\n let maxAscent = 0\n let maxDescent = 0\n let maxFontSizeOnLine = 0\n\n // Handle empty line metrics\n if (line.length === 0) {\n ctx.font = this.getFontString()\n if (typeof this.props.fontVariant === 'string') {\n ctx.fontVariant = this.props.fontVariant\n } else if (this.props.fontVariant !== undefined) {\n console.warn(`[TextNode ${this.key || ''}] Invalid fontVariant prop type in measureText (empty line):`, this.props.fontVariant)\n if (ctx.fontVariant !== 'normal') ctx.fontVariant = 'normal'\n } else {\n if (ctx.fontVariant !== 'normal') ctx.fontVariant = 'normal'\n }\n const metrics = ctx.measureText(this.metricsString)\n maxAscent = metrics.actualBoundingBoxAscent ?? baseFontSize * 0.8\n maxDescent = metrics.actualBoundingBoxDescent ?? baseFontSize * 0.2\n maxFontSizeOnLine = baseFontSize\n } else {\n // Calculate max metrics across all segments in line\n for (const segment of line) {\n if (/^\\s+$/.test(segment.text)) continue\n\n const segmentSize = segment.size || baseFontSize\n maxFontSizeOnLine = Math.max(maxFontSizeOnLine, segmentSize)\n\n ctx.font = this.getFontString(segment)\n if (typeof this.props.fontVariant === 'string') {\n ctx.fontVariant = this.props.fontVariant\n } else if (this.props.fontVariant !== undefined) {\n console.warn(`[TextNode ${this.key || ''}] Invalid fontVariant prop type in measureText (segment height):`, this.props.fontVariant)\n if (ctx.fontVariant !== 'normal') ctx.fontVariant = 'normal'\n } else {\n if (ctx.fontVariant !== 'normal') ctx.fontVariant = 'normal'\n }\n\n const metrics = ctx.measureText(this.metricsString)\n const ascent = metrics.actualBoundingBoxAscent ?? segmentSize * 0.8\n const descent = metrics.actualBoundingBoxDescent ?? segmentSize * 0.2\n\n maxAscent = Math.max(maxAscent, ascent)\n maxDescent = Math.max(maxDescent, descent)\n }\n }\n\n // Fallback metrics for lines with only whitespace\n if (maxAscent === 0 && maxDescent === 0 && line.length > 0) {\n ctx.font = this.getFontString()\n if (typeof this.props.fontVariant === 'string') {\n ctx.fontVariant = this.props.fontVariant\n } else if (this.props.fontVariant !== undefined) {\n console.warn(`[TextNode ${this.key || ''}] Invalid fontVariant prop type in measureText (fallback):`, this.props.fontVariant)\n if (ctx.fontVariant !== 'normal') ctx.fontVariant = 'normal'\n } else {\n if (ctx.fontVariant !== 'normal') ctx.fontVariant = 'normal'\n }\n const metrics = ctx.measureText(this.metricsString)\n maxAscent = metrics.actualBoundingBoxAscent ?? baseFontSize * 0.8\n maxDescent = metrics.actualBoundingBoxDescent ?? baseFontSize * 0.2\n maxFontSizeOnLine = maxFontSizeOnLine || baseFontSize\n }\n\n maxFontSizeOnLine = maxFontSizeOnLine || baseFontSize\n\n // Calculate total content height for line\n const actualContentHeight = maxAscent + maxDescent\n\n // Determine final line box height with leading\n const targetLineBoxHeight =\n typeof this.props.lineHeight === 'number' && this.props.lineHeight > 0 ? this.props.lineHeight : maxFontSizeOnLine * defaultLineHeightMultiplier\n\n // Use larger of target height or content height to prevent clipping\n const finalLineHeight = Math.max(actualContentHeight, targetLineBoxHeight)\n\n // Store line metrics for rendering\n this.lineHeights.push(finalLineHeight)\n this.lineAscents.push(maxAscent)\n this.lineContentHeights.push(actualContentHeight)\n\n totalTextHeight += finalLineHeight\n }\n\n // Add line gap spacing to total height\n const lineGapValue = this.props.lineGap\n const totalGapHeight = Math.max(0, (numLines - 1) * lineGapValue)\n const calculatedContentHeight = totalTextHeight + totalGapHeight\n\n // Calculate width required for text content\n const spaceWidth = this.measureSpaceWidth(ctx)\n let singleLineWidth = 0\n let firstWordInSingleLine = true\n for (const segment of this.segments) {\n const words = segment.text.split(/(\\s+)/).filter(Boolean)\n for (const word of words) {\n if (/^\\s+$/.test(word)) continue\n ctx.font = this.getFontString(segment)\n if (typeof this.props.fontVariant === 'string') {\n ctx.fontVariant = this.props.fontVariant\n } else if (this.props.fontVariant !== undefined) {\n console.warn(`[TextNode ${this.key || ''}] Invalid fontVariant prop type in measureText (single line width):`, this.props.fontVariant)\n if (ctx.fontVariant !== 'normal') ctx.fontVariant = 'normal'\n } else {\n if (ctx.fontVariant !== 'normal') ctx.fontVariant = 'normal'\n }\n const wordWidth = ctx.measureText(word).width\n if (!firstWordInSingleLine) {\n singleLineWidth += spaceWidth + parsedWordSpacingPx\n }\n singleLineWidth += wordWidth\n firstWordInSingleLine = false\n }\n }\n\n // Determine final content width based on wrapping\n let requiredContentWidth: number\n if (singleLineWidth <= availableWidthForContent) {\n requiredContentWidth = singleLineWidth\n if (linesToMeasure.length > 1 && this.props.maxLines !== 1 && !this.segments.some(s => s.text.includes('\\n'))) {\n console.warn(\n `[TextNode ${this.key || ''}] Rich text should fit (${singleLineWidth.toFixed(2)} <= ${availableWidthForContent.toFixed(2)}) but wrapTextRich produced ${linesToMeasure.length} lines. Width calculation might be slightly off due to complex spacing/kerning.`,\n )\n let maxWrappedLineWidth = 0\n for (const line of linesToMeasure) {\n let currentLineWidth = 0\n let firstWordOnWrappedLine = true\n for (const segment of line) {\n const segmentWidth = segment.width ?? 0\n const isSpaceSegment = /^\\s+$/.test(segment.text)\n if (!isSpaceSegment) {\n if (!firstWordOnWrappedLine) {\n currentLineWidth += spaceWidth + parsedWordSpacingPx\n }\n currentLineWidth += segmentWidth\n firstWordOnWrappedLine = false\n }\n }\n maxWrappedLineWidth = Math.max(maxWrappedLineWidth, currentLineWidth)\n }\n requiredContentWidth = Math.max(singleLineWidth, maxWrappedLineWidth)\n }\n } else {\n let maxWrappedLineWidth = 0\n for (const line of linesToMeasure) {\n let currentLineWidth = 0\n let firstWordOnWrappedLine = true\n for (const segment of line) {\n const segmentWidth = segment.width ?? 0\n const isSpaceSegment = /^\\s+$/.test(segment.text)\n if (!isSpaceSegment) {\n if (!firstWordOnWrappedLine) {\n currentLineWidth += spaceWidth + parsedWordSpacingPx\n }\n currentLineWidth += segmentWidth\n firstWordOnWrappedLine = false\n }\n }\n maxWrappedLineWidth = Math.max(maxWrappedLineWidth, currentLineWidth)\n }\n requiredContentWidth = maxWrappedLineWidth\n }\n\n // Constrain width if needed\n let finalContentWidth = requiredContentWidth\n if (availableWidthForContent !== Infinity) {\n finalContentWidth = Math.min(requiredContentWidth, availableWidthForContent)\n }\n\n ctx.restore()\n return {\n width: Math.max(0, finalContentWidth),\n height: Math.max(0, calculatedContentHeight),\n }\n }\n\n /**\n * Wraps text segments into multiple lines while respecting width constraints and preserving styling.\n * Handles rich text attributes (color, weight, size, bold, italic) and proper word wrapping.\n * Also respects explicit newline characters (\\n) for forced line breaks.\n * @param ctx Canvas rendering context used for text measurements\n * @param segments Array of text segments with styling information\n * @param maxWidth Maximum allowed width for each line in pixels\n * @param parsedWordSpacingPx Additional spacing to add between words in pixels\n * @returns Array of lines, where each line contains styled text segments\n */\n private wrapTextRich(ctx: CanvasRenderingContext2D, segments: TextSegment[], maxWidth: number, parsedWordSpacingPx: number): TextSegment[][] {\n const lines: TextSegment[][] = []\n\n if (segments.length === 0 || maxWidth <= 0) return lines\n\n let currentLineSegments: TextSegment[] = []\n let currentLineWidth = 0\n const spaceWidth = this.measureSpaceWidth(ctx)\n\n // Helper to finalize current line and start new one\n const finalizeLine = (forceEmpty = false) => {\n // Remove trailing whitespace segments unless we're forcing an empty line\n if (!forceEmpty) {\n while (currentLineSegments.length > 0 && /^\\s+$/.test(currentLineSegments[currentLineSegments.length - 1].text)) {\n currentLineSegments.pop()\n }\n }\n // Always push the line, even if empty (for \\n\\n cases)\n lines.push(currentLineSegments)\n currentLineSegments = []\n currentLineWidth = 0\n }\n\n for (const segment of segments) {\n // Preserve all style attributes for consistency\n const segmentStyle = {\n color: segment.color,\n weight: segment.weight,\n size: segment.size,\n b: segment.b,\n i: segment.i,\n }\n\n // Check if segment contains newline characters\n if (segment.text.includes('\\n')) {\n // Split by newlines and process each part\n const parts = segment.text.split('\\n')\n\n for (let i = 0; i < parts.length; i++) {\n const part = parts[i]\n const isLastPart = i === parts.length - 1\n\n if (part.length > 0) {\n // Process this part normally\n const wordsAndSpaces = part.split(/(\\s+)/).filter(Boolean)\n\n for (const wordOrSpace of wordsAndSpaces) {\n const isSpace = /^\\s+$/.test(wordOrSpace)\n let wordSegment: TextSegment\n let wordWidth: number\n\n if (isSpace) {\n wordSegment = { text: wordOrSpace, ...segmentStyle, width: 0 }\n wordWidth = 0\n } else {\n ctx.font = this.getFontString(segmentStyle)\n if (this.props.fontVariant) ctx.fontVariant = this.props.fontVariant\n wordWidth = ctx.measureText(wordOrSpace).width\n wordSegment = { text: wordOrSpace, ...segmentStyle, width: wordWidth }\n }\n\n const needsSpace = currentLineSegments.length > 0 && !/^\\s+$/.test(currentLineSegments[currentLineSegments.length - 1].text)\n const spaceToAdd = needsSpace ? spaceWidth + parsedWordSpacingPx : 0\n\n if (currentLineWidth + spaceToAdd + wordWidth <= maxWidth || currentLineSegments.length === 0) {\n if (needsSpace) {\n currentLineSegments.push({ text: ' ', ...segmentStyle, width: 0 })\n currentLineWidth += spaceToAdd\n }\n currentLineSegments.push(wordSegment)\n currentLineWidth += wordWidth\n } else {\n if (currentLineSegments.length > 0) {\n finalizeLine()\n }\n\n if (!isSpace) {\n if (wordWidth > maxWidth && maxWidth > 0) {\n const brokenParts = this.breakWordRich(ctx, wordSegment, maxWidth)\n\n if (brokenParts.length > 0) {\n for (let k = 0; k < brokenParts.length - 1; k++) {\n lines.push([brokenParts[k]])\n }\n currentLineSegments = [brokenParts[brokenParts.length - 1]]\n currentLineWidth = brokenParts[brokenParts.length - 1].width ?? 0\n } else {\n currentLineSegments = [wordSegment]\n currentLineWidth = wordWidth\n }\n } else {\n currentLineSegments = [wordSegment]\n currentLineWidth = wordWidth\n }\n }\n }\n }\n }\n\n // Force line break after each part except the last\n // If part is empty, this creates an empty line (like \\n\\n)\n if (!isLastPart) {\n finalizeLine(part.length === 0)\n }\n }\n } else {\n // No newlines - process normally\n const wordsAndSpaces = segment.text.split(/(\\s+)/).filter(Boolean)\n\n for (const wordOrSpace of wordsAndSpaces) {\n const isSpace = /^\\s+$/.test(wordOrSpace)\n let wordSegment: TextSegment\n let wordWidth: number\n\n if (isSpace) {\n wordSegment = { text: wordOrSpace, ...segmentStyle, width: 0 }\n wordWidth = 0\n } else {\n ctx.font = this.getFontString(segmentStyle)\n if (this.props.fontVariant) ctx.fontVariant = this.props.fontVariant\n wordWidth = ctx.measureText(wordOrSpace).width\n wordSegment = { text: wordOrSpace, ...segmentStyle, width: wordWidth }\n }\n\n const needsSpace = currentLineSegments.length > 0 && !/^\\s+$/.test(currentLineSegments[currentLineSegments.length - 1].text)\n const spaceToAdd = needsSpace ? spaceWidth + parsedWordSpacingPx : 0\n\n if (currentLineWidth + spaceToAdd + wordWidth <= maxWidth || currentLineSegments.length === 0) {\n if (needsSpace) {\n currentLineSegments.push({ text: ' ', ...segmentStyle, width: 0 })\n currentLineWidth += spaceToAdd\n }\n currentLineSegments.push(wordSegment)\n currentLineWidth += wordWidth\n } else {\n if (currentLineSegments.length > 0) {\n finalizeLine()\n }\n\n if (!isSpace) {\n if (wordWidth > maxWidth && maxWidth > 0) {\n const brokenParts = this.breakWordRich(ctx, wordSegment, maxWidth)\n\n if (brokenParts.length > 0) {\n for (let k = 0; k < brokenParts.length - 1; k++) {\n lines.push([brokenParts[k]])\n }\n currentLineSegments = [brokenParts[brokenParts.length - 1]]\n currentLineWidth = brokenParts[brokenParts.length - 1].width ?? 0\n } else {\n currentLineSegments = [wordSegment]\n currentLineWidth = wordWidth\n }\n } else {\n currentLineSegments = [wordSegment]\n currentLineWidth = wordWidth\n }\n }\n }\n }\n }\n }\n\n finalizeLine()\n return lines\n }\n\n /**\n * Breaks a word segment into multiple segments that each fit within the specified width constraint.\n * Maintains all styling properties (color, weight, size, bold, italic) across broken segments.\n * @param ctx Canvas rendering context used for text measurements\n * @param segmentToBreak Original text segment to split\n * @param maxWidth Maximum width allowed for each resulting segment\n * @returns Array of TextSegments, each fitting maxWidth, or original segment if no breaking needed\n */\n private breakWordRich(ctx: CanvasRenderingContext2D, segmentToBreak: TextSegment, maxWidth: number): TextSegment[] {\n const word = segmentToBreak.text\n\n // Copy all style properties to maintain consistent styling across broken segments\n const style = {\n color: segmentToBreak.color,\n weight: segmentToBreak.weight,\n size: segmentToBreak.size,\n b: segmentToBreak.b,\n i: segmentToBreak.i,\n }\n\n if (maxWidth <= 0) return [segmentToBreak]\n\n const brokenSegments: TextSegment[] = []\n let currentPartText = ''\n\n // Configure context with segment style for accurate measurements\n ctx.font = this.getFontString(style)\n if (this.props.fontVariant) ctx.fontVariant = this.props.fontVariant\n\n // Process word character by character to find valid break points\n for (const char of word) {\n const testPartText = currentPartText + char\n const testPartWidth = ctx.measureText(testPartText).width\n\n if (testPartWidth > maxWidth) {\n // Current accumulated text exceeds width - create new segment\n if (currentPartText) {\n brokenSegments.push({\n text: currentPartText,\n ...style,\n width: ctx.measureText(currentPartText).width,\n })\n }\n\n // Handle current character that caused overflow\n currentPartText = char\n const currentCharWidth = ctx.measureText(currentPartText).width\n\n if (currentCharWidth > maxWidth) {\n // Single character is too wide - force break after it\n brokenSegments.push({\n text: currentPartText,\n ...style,\n width: currentCharWidth,\n })\n currentPartText = ''\n }\n } else {\n // Character fits - add to current part\n currentPartText = testPartText\n }\n }\n\n // Handle any remaining text as final segment\n if (currentPartText) {\n brokenSegments.push({\n text: currentPartText,\n ...style,\n width: ctx.measureText(currentPartText).width,\n })\n }\n\n return brokenSegments.length > 0 ? brokenSegments : [segmentToBreak]\n }\n\n /**\n * Measures width of space character using base font\n */\n private measureSpaceWidth(ctx: CanvasRenderingContext2D): number {\n const originalFont = ctx.font\n ctx.font = this.getFontString()\n const width = ctx.measureText(' ').width\n ctx.font = originalFont\n return width > 0 ? width : (this.props.fontSize || 16) * 0.3\n }\n\n /**\n * Renders multi-line text content with rich text styling and layout features\n *\n * Core features:\n * - Dynamic line heights with leading/spacing controls\n * - Vertical text alignment (top/middle/bottom)\n * - Horizontal text alignment (left/center/right/justify)\n * - Text wrapping within bounds\n * - Ellipsis truncation\n * - Rich text styling per segment (color, weight, size, etc)\n * - Performance optimizations (clipping, visibility checks)\n * @param ctx Canvas rendering context\n * @param x Content box left position in pixels\n * @param y Content box top position in pixels\n * @param width Content box total width including padding\n * @param height Content box total height including padding\n */\n protected override _renderContent(ctx: CanvasRenderingContext2D, x: number, y: number, width: number, height: number) {\n super._renderContent(ctx, x, y, width, height)\n\n ctx.save()\n ctx.textBaseline = 'alphabetic'\n ctx.letterSpacing = this.formatSpacing(this.props.letterSpacing)\n ctx.wordSpacing = 'normal'\n\n const baseFontSize = this.props.fontSize || 16\n const parsedWordSpacingPx = this.parseSpacingToPx(this.props.wordSpacing, baseFontSize)\n\n // Calculate content box with padding\n const paddingLeft = this.node.getComputedPadding(Style.Edge.Left) ?? 0\n const paddingTop = this.node.getComputedPadding(Style.Edge.Top) ?? 0\n const paddingRight = this.node.getComputedPadding(Style.Edge.Right) ?? 0\n const paddingBottom = this.node.getComputedPadding(Style.Edge.Bottom) ?? 0\n const contentX = x + paddingLeft\n const contentY = y + paddingTop\n const contentWidth = Math.max(0, width - paddingLeft - paddingRight)\n const contentHeight = Math.max(0, height - paddingTop - paddingBottom)\n\n if (contentWidth <= 0 || contentHeight <= 0) {\n ctx.restore()\n return\n }\n\n // Re-calculate lines based on the actual render width to ensure consistency\n // This fixes issues where Yoga Layout might use a cached measurement from a different\n // width constraint (e.g., during a flex shrink pass) but final layout is wider.\n const spaceWidth = this.measureSpaceWidth(ctx)\n // Use a small epsilon for float precision issues\n const epsilon = 0.01\n const allLines = this.wrapTextRich(ctx, this.segments, contentWidth + epsilon, parsedWordSpacingPx)\n\n const needsEllipsis = this.props.ellipsis && this.props.maxLines !== undefined && allLines.length > this.props.maxLines\n\n // Apply maxLines constraint to get the visible lines\n const visibleLines = this.props.maxLines !== undefined && this.props.maxLines > 0 ? allLines.slice(0, this.props.maxLines) : allLines\n\n const numLinesToRender = visibleLines.length\n\n // Recalculate line metrics for the rendered lines\n // We cannot rely on this.lineHeights from measureText because it might correspond to different wrapping\n const lineHeights: number[] = []\n const lineAscents: number[] = []\n const lineContentHeights: number[] = []\n const defaultLineHeightMultiplier = 1.2\n let totalTextHeight = 0\n\n for (const line of visibleLines) {\n let maxAscent = 0\n let maxDescent = 0\n let maxFontSizeOnLine = 0\n\n if (line.length === 0) {\n ctx.font = this.getFontString()\n if (this.props.fontVariant) ctx.fontVariant = typeof this.props.fontVariant === 'string' ? this.props.fontVariant : 'normal'\n const metrics = ctx.measureText(this.metricsString)\n maxAscent = metrics.actualBoundingBoxAscent ?? baseFontSize * 0.8\n maxDescent = metrics.actualBoundingBoxDescent ?? baseFontSize * 0.2\n maxFontSizeOnLine = baseFontSize\n } else {\n for (const segment of line) {\n if (/^\\s+$/.test(segment.text)) continue\n const segmentSize = segment.size || baseFontSize\n maxFontSizeOnLine = Math.max(maxFontSizeOnLine, segmentSize)\n\n // Style context for accurate metrics\n ctx.font = this.getFontString(segment)\n if (this.props.fontVariant) ctx.fontVariant = typeof this.props.fontVariant === 'string' ? this.props.fontVariant : 'normal'\n\n const metrics = ctx.measureText(this.metricsString)\n const ascent = metrics.actualBoundingBoxAscent ?? segmentSize * 0.8\n const descent = metrics.actualBoundingBoxDescent ?? segmentSize * 0.2\n maxAscent = Math.max(maxAscent, ascent)\n maxDescent = Math.max(maxDescent, descent)\n }\n }\n if (maxAscent === 0 && maxDescent === 0 && line.length > 0) {\n // Fallback\n ctx.font = this.getFontString()\n if (this.props.fontVariant) ctx.fontVariant = typeof this.props.fontVariant === 'string' ? this.props.fontVariant : 'normal'\n const metrics = ctx.measureText(this.metricsString)\n maxAscent = metrics.actualBoundingBoxAscent ?? baseFontSize * 0.8\n maxDescent = metrics.actualBoundingBoxDescent ?? baseFontSize * 0.2\n maxFontSizeOnLine = maxFontSizeOnLine || baseFontSize\n }\n maxFontSizeOnLine = maxFontSizeOnLine || baseFontSize\n const actualContentHeight = maxAscent + maxDescent\n const targetLineBoxHeight =\n typeof this.props.lineHeight === 'number' && this.props.lineHeight > 0 ? this.props.lineHeight : maxFontSizeOnLine * defaultLineHeightMultiplier\n const finalLineHeight = Math.max(actualContentHeight, targetLineBoxHeight)\n\n lineHeights.push(finalLineHeight)\n lineAscents.push(maxAscent)\n lineContentHeights.push(actualContentHeight)\n totalTextHeight += finalLineHeight\n }\n\n if (numLinesToRender === 0) {\n ctx.restore()\n return\n }\n\n // Calculate vertical alignment offset\n const lineGapValue = this.props.lineGap\n const totalCalculatedTextHeight = totalTextHeight + Math.max(0, numLinesToRender - 1) * lineGapValue\n\n let blockStartY: number\n switch (this.props.verticalAlign) {\n case 'middle':\n blockStartY = contentY + (contentHeight - totalCalculatedTextHeight) / 2\n break\n case 'bottom':\n blockStartY = contentY + contentHeight - totalCalculatedTextHeight\n break\n case 'top':\n default:\n blockStartY = contentY\n }\n\n let currentLineTopY = blockStartY\n\n // Setup text content clipping region\n ctx.beginPath()\n ctx.rect(contentX, contentY, contentWidth, contentHeight)\n ctx.clip()\n\n // Configure ellipsis if needed\n const ellipsisChar = typeof this.props.ellipsis === 'string' ? this.props.ellipsis : '...'\n let ellipsisWidth = 0\n let ellipsisStyle: Partial<TextSegment> | undefined = undefined\n\n if (needsEllipsis) {\n const lastRenderedLine = visibleLines[visibleLines.length - 1]\n // ... ellipsis calculation ...\n const lastTextStyleSegment = [...lastRenderedLine].reverse().find(seg => !/^\\s+$/.test(seg.text))\n ellipsisStyle = lastTextStyleSegment\n ? {\n color: lastTextStyleSegment.color,\n weight: lastTextStyleSegment.weight,\n size: lastTextStyleSegment.size,\n b: lastTextStyleSegment.b,\n i: lastTextStyleSegment.i,\n }\n : undefined\n\n ctx.save()\n ctx.font = this.getFontString(ellipsisStyle)\n if (this.props.fontVariant) {\n ctx.fontVariant = typeof this.props.fontVariant === 'string' ? this.props.fontVariant : 'normal'\n }\n ellipsisWidth = ctx.measureText(ellipsisChar).width\n ctx.restore()\n }\n\n // Render text content line by line\n for (let i = 0; i < numLinesToRender; i++) {\n const lineSegments = visibleLines[i]\n const currentLineFinalHeight = lineHeights[i]\n const currentLineMaxAscent = lineAscents[i]\n const currentLineContentHeight = lineContentHeights[i]\n\n // Calculate line spacing metrics\n const currentLineLeading = currentLineFinalHeight - currentLineContentHeight\n const currentLineSpaceAbove = Math.max(0, currentLineLeading / 2)\n const lineY = currentLineTopY + currentLineSpaceAbove + currentLineMaxAscent\n\n // Visibility culling check\n const lineTop = currentLineTopY\n const lineBottom = currentLineTopY + currentLineFinalHeight\n\n // Don't skip empty lines - they're intentional (from \\n\\n)\n // Only skip if the line is completely outside the visible area\n if (lineBottom <= contentY || lineTop >= contentY + contentHeight) {\n currentLineTopY += currentLineFinalHeight + lineGapValue\n continue\n }\n\n const isLastRenderedLine = i === numLinesToRender - 1\n\n // Calculate line width metrics for alignment\n let totalLineWidth = 0\n let totalWordsWidth = 0\n let numWordGaps = 0\n let firstWordOnLine = true\n const noSpaceBeforePunctuation = /^[.,!?;:)\\]}]/\n\n for (const segment of lineSegments) {\n const segmentWidth = segment.width ?? 0\n const isSpaceSegment = /^\\s+$/.test(segment.text)\n\n if (!isSpaceSegment) {\n if (!firstWordOnLine) {\n totalLineWidth += spaceWidth + parsedWordSpacingPx\n if (!noSpaceBeforePunctuation.test(segment.text)) {\n numWordGaps++\n }\n }\n totalLineWidth += segmentWidth\n totalWordsWidth += segmentWidth\n firstWordOnLine = false\n }\n }\n\n // Calculate horizontal alignment position\n const isJustify = this.props.textAlign === 'justify' && !isLastRenderedLine\n const lineTextAlign = isJustify ? 'left' : this.props.textAlign || 'left'\n let currentX: number\n\n switch (lineTextAlign) {\n case 'center':\n currentX = contentX + (contentWidth - totalLineWidth) / 2\n break\n case 'right':\n case 'end':\n currentX = contentX + contentWidth - totalLineWidth\n break\n case 'left':\n case 'start':\n default:\n currentX = contentX\n }\n currentX = Math.max(contentX, currentX)\n\n // Calculate justification spacing\n let spacePerWordGapPlusSpacing = spaceWidth + parsedWordSpacingPx\n if (isJustify && numWordGaps > 0 && totalLineWidth < contentWidth) {\n const totalBaseSpacingWidth = numWordGaps * (spaceWidth + parsedWordSpacingPx)\n const remainingSpace = contentWidth - totalWordsWidth - totalBaseSpacingWidth\n if (remainingSpace > 0) {\n spacePerWordGapPlusSpacing += remainingSpace / numWordGaps\n }\n }\n\n // Render line segments (skip rendering for truly empty lines)\n if (lineSegments.length > 0 && !lineSegments.every(s => s.text.trim() === '')) {\n let accumulatedWidth = 0\n let ellipsisApplied = false\n let firstWordDrawn = false\n\n for (let j = 0; j < lineSegments.length; j++) {\n const segment = lineSegments[j]\n const segmentWidth = segment.width ?? 0\n const isLastSegmentOnLine = j === lineSegments.length - 1\n const isSpaceSegment = /^\\s+$/.test(segment.text)\n\n // Calculate word spacing\n let spaceToAddBefore = 0\n if (!isSpaceSegment && firstWordDrawn && !noSpaceBeforePunctuation.test(segment.text)) {\n spaceToAddBefore = isJustify ? spacePerWordGapPlusSpacing : spaceWidth + parsedWordSpacingPx\n }\n\n // Apply segment styles\n ctx.font = this.getFontString(segment)\n ctx.fillStyle = segment.color || this.props.color || 'black'\n\n if (typeof this.props.fontVariant === 'string') {\n ctx.fontVariant = this.props.fontVariant\n } else if (this.props.fontVariant !== undefined) {\n console.warn(`[TextNode ${this.key || ''}] Invalid fontVariant prop type in _renderContent (segment render):`, this.props.fontVariant)\n if (ctx.fontVariant !== 'normal') ctx.fontVariant = 'normal'\n } else {\n if (ctx.fontVariant !== 'normal') ctx.fontVariant = 'normal'\n }\n\n // Handle text truncation and ellipsis\n let textToDraw = segment.text\n let currentSegmentRenderWidth = segmentWidth\n let applyEllipsisAfter = false\n\n if (isLastRenderedLine && needsEllipsis && !isSpaceSegment) {\n const currentTotalWidth = accumulatedWidth + spaceToAddBefore + segmentWidth\n const spaceNeededAfter = isLastSegmentOnLine ? 0 : isJustify ? spacePerWordGapPlusSpacing : spaceWidth + parsedWordSpacingPx\n\n if (currentTotalWidth > contentWidth - spaceNeededAfter) {\n const availableWidthForSegment = contentWidth - accumulatedWidth - spaceToAddBefore - ellipsisWidth\n if (availableWidthForSegment > 0) {\n let truncatedText = ''\n for (const char of segment.text) {\n if (ctx.measureText(truncatedText + char).width <= availableWidthForSegment) {\n truncatedText += char\n } else {\n break\n }\n }\n textToDraw = truncatedText\n currentSegmentRenderWidth = ctx.measureText(textToDraw).width\n } else {\n textToDraw = ''\n currentSegmentRenderWidth = 0\n }\n applyEllipsisAfter = true\n ellipsisApplied = true\n } else if (isLastSegmentOnLine) {\n applyEllipsisAfter = true\n ellipsisApplied = true\n }\n }\n\n // Render text segment\n currentX += spaceToAddBefore\n accumulatedWidth += spaceToAddBefore\n\n const remainingRenderWidth = contentX + contentWidth - currentX\n if (currentSegmentRenderWidth > 0 && remainingRenderWidth > 0 && !isSpaceSegment) {\n ctx.textAlign = 'left'\n\n const shadows = this.props.textShadow ? (Array.isArray(this.props.textShadow) ? this.props.textShadow : [this.props.textShadow]) : []\n\n ctx.save()\n\n // Draw shadows\n for (const shadow of shadows) {\n ctx.shadowColor = shadow.color || 'transparent'\n ctx.shadowBlur = shadow.blur || 0\n ctx.shadowOffsetX = shadow.offsetX || 0\n ctx.shadowOffsetY = shadow.offsetY || 0\n ctx.fillText(textToDraw, currentX, lineY, Math.max(0, remainingRenderWidth + 1))\n }\n\n // Reset shadow to draw the main text\n ctx.shadowColor = 'transparent'\n ctx.shadowBlur = 0\n ctx.shadowOffsetX = 0\n ctx.shadowOffsetY = 0\n\n ctx.fillText(textToDraw, currentX, lineY, Math.max(0, remainingRenderWidth + 1))\n\n ctx.restore()\n\n firstWordDrawn = true\n }\n\n currentX += currentSegmentRenderWidth\n accumulatedWidth += currentSegmentRenderWidth\n\n // Render ellipsis\n if (applyEllipsisAfter) {\n const ellipsisRemainingWidth = contentX + contentWidth - currentX\n if (ellipsisRemainingWidth >= ellipsisWidth) {\n ctx.save()\n ctx.font = this.getFontString(ellipsisStyle)\n\n if (typeof this.props.fontVariant === 'string') {\n ctx.fontVariant = this.props.fontVariant\n } else if (this.props.fontVariant !== undefined) {\n console.warn(`[TextNode ${this.key || ''}] Invalid fontVariant prop type in _renderContent (ellipsis draw):`, this.props.fontVariant)\n if (ctx.fontVariant !== 'normal') ctx.fontVariant = 'normal'\n } else {\n if (ctx.fontVariant !== 'normal') ctx.fontVariant = 'normal'\n }\n\n ctx.fillStyle = ellipsisStyle?.color || this.props.color || 'black'\n ctx.fillText(ellipsisChar, currentX, lineY, Math.max(0, ellipsisRemainingWidth + 1))\n ctx.restore()\n }\n break\n }\n\n if (ellipsisApplied && currentX >= contentX + contentWidth) break\n }\n }\n\n currentLineTopY += currentLineFinalHeight + lineGapValue\n }\n\n ctx.restore()\n }\n}\n\n/**\n * Creates a new TextNode instance with rich text support\n */\nexport const Text = (text: number | string, props?: TextProps) => new TextNode(text, props)\n"],"names":["BoxNode","Canvas","Style"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"text.canvas.util.js","sources":["../../../../src/canvas/text.canvas.util.ts"],"sourcesContent":["// TODO: Add comprehensive unit tests for this file.\n\nimport type { TextProps, TextSegment } from '@/canvas/canvas.type.js'\nimport { Canvas, type CanvasRenderingContext2D, type FontVariantSetting } from 'skia-canvas'\nimport { BoxNode } from '@/canvas/layout.canvas.util.js'\nimport { Style, MeasureMode } from '@/constant/common.const.js'\n\n/**\n * Node for rendering text content with rich text styling support\n * Supports color and weight variations through HTML-like tags\n */\nexport class TextNode extends BoxNode {\n private readonly segments: TextSegment[] = []\n private lines: TextSegment[][] = []\n private static measurementContext: CanvasRenderingContext2D | null = null\n private readonly metricsString = 'Ag|``'\n private lineHeights: number[] = []\n private lineAscents: number[] = []\n private lineContentHeights: number[] = []\n\n declare props: TextProps & { lineGap: number }\n\n constructor(text: number | string = '', props: TextProps = {}) {\n const initialProps = {\n name: 'TextNode',\n flexShrink: 1,\n lineGap: 0,\n ...props,\n children: undefined,\n }\n super(initialProps)\n this.props = initialProps\n // Process escape sequences before parsing rich text\n const processedText = this.processEscapeSequences(String(text ?? ''))\n this.segments = this.parseRichText(processedText, {\n color: this.props.color,\n weight: this.props.fontWeight,\n size: this.props.fontSize,\n b: this.props.fontWeight === 'bold',\n i: this.props.fontStyle === 'italic',\n })\n this.node.setMeasureFunc(this.measureText.bind(this))\n this.applyDefaults()\n }\n\n /**\n * Renders a simple, single-line text string without complex layout calculations.\n * A lightweight, static utility for drawing text where layout is handled externally.\n * @param ctx The canvas rendering context.\n * @param text The string to render.\n * @param x The x-coordinate for rendering.\n * @param y The y-coordinate for rendering.\n * @param props Basic text styling properties.\n */\n public static renderSimpleText(\n ctx: CanvasRenderingContext2D,\n text: string,\n x: number,\n y: number,\n props: {\n fontFamily?: string\n fontSize?: number\n fontWeight?: TextProps['fontWeight']\n fontStyle?: TextProps['fontStyle']\n color?: string\n textAlign?: CanvasRenderingContext2D['textAlign']\n textBaseline?: CanvasRenderingContext2D['textBaseline']\n } = {},\n ) {\n ctx.save()\n\n const {\n fontFamily = 'sans-serif',\n fontSize = 12,\n fontWeight = 'normal',\n fontStyle = 'normal',\n color = '#333',\n textAlign = 'left',\n textBaseline = 'alphabetic',\n } = props\n\n ctx.font = `${fontStyle} ${fontWeight} ${fontSize}px ${fontFamily}`\n ctx.fillStyle = color\n ctx.textAlign = textAlign\n ctx.textBaseline = textBaseline\n\n ctx.fillText(text, x, y)\n\n ctx.restore()\n }\n\n protected override applyDefaults(): void {\n const textDefaults: Required<\n Pick<TextProps, 'fontSize' | 'fontFamily' | 'fontWeight' | 'fontStyle' | 'color' | 'textAlign' | 'verticalAlign' | 'ellipsis' | 'lineGap'>\n > & {\n lineHeight: undefined | number\n maxLines: undefined | number\n letterSpacing: undefined | number\n wordSpacing: undefined | number\n fontVariant: undefined | FontVariantSetting\n } = {\n fontSize: 16,\n fontFamily: 'sans-serif',\n fontWeight: 'normal',\n fontStyle: 'normal',\n color: 'black',\n textAlign: 'left',\n verticalAlign: 'top',\n fontVariant: undefined,\n lineHeight: undefined,\n lineGap: 0,\n maxLines: undefined,\n ellipsis: false,\n letterSpacing: undefined,\n wordSpacing: undefined,\n }\n\n let defaultsApplied = false\n for (const key of Object.keys(textDefaults) as (keyof typeof textDefaults)[]) {\n if (this.props[key] === undefined && textDefaults[key] !== undefined) {\n this.props[key as string] = textDefaults[key]\n defaultsApplied = true\n }\n }\n\n if (defaultsApplied && !this.node.isDirty()) {\n const affectsMeasurement = [\n 'fontSize',\n 'fontFamily',\n 'fontWeight',\n 'fontStyle',\n 'lineHeight',\n 'maxLines',\n 'lineGap',\n 'letterSpacing',\n 'wordSpacing',\n ].some(measureKey => this.props[measureKey] === textDefaults[measureKey])\n if (affectsMeasurement) {\n this.node.markDirty()\n }\n }\n }\n\n /**\n * Processes Unix-like escape sequences in text strings.\n * Converts escaped characters into their actual representations.\n *\n * Supported escape sequences:\n * - \\n - Newline (line feed)\n * - \\t - Tab (converted to 4 spaces)\n * - \\r - Carriage return (treated as newline)\n * - \\\\ - Literal backslash\n * - \\' - Single quote\n * - \\\" - Double quote\n * - \\0 - Null character (removed)\n * - \\b - Backspace (removed)\n * - \\f - Form feed (treated as newline)\n * - \\v - Vertical tab (treated as newline)\n * @param input Raw text string potentially containing escape sequences\n * @returns Processed string with escape sequences converted\n */\n private processEscapeSequences(input: string): string {\n return input.replace(/\\\\(.)/g, (match, char) => {\n switch (char) {\n case 'n':\n return '\\n' // Newline\n case 't':\n return ' ' // Tab as 4 spaces\n case 'r':\n return '\\n' // Carriage return treated as newline\n case '\\\\':\n return '\\\\' // Literal backslash\n case \"'\":\n return \"'\" // Single quote\n case '\"':\n return '\"' // Double quote\n case '0':\n return '' // Null character (remove)\n case 'b':\n return '' // Backspace (remove)\n case 'f':\n return '\\n' // Form feed as newline\n case 'v':\n return '\\n' // Vertical tab as newline\n default:\n // Unknown escape sequence - keep original\n return match\n }\n })\n }\n\n /**\n * Parses input text with HTML-style markup into styled text segments.\n *\n * Supported tags:\n * - <color=\"value\"> - Sets text color (hex code or CSS color name)\n * - <weight=\"value\"> - Sets font weight (100-900 or keywords like \"bold\")\n * - <size=\"value\"> - Sets font size in pixels\n * - <b> - Makes text bold (shorthand for weight=\"bold\")\n * - <i> - Makes text italic\n *\n * Tag values can use double quotes, single quotes, or no quotes:\n * <color=\"red\">, <color='red'>, <color=red>\n *\n * Tags can be nested and must be properly closed with </tag>\n * @param input Text string containing markup tags\n * @param baseStyle Default style properties to apply to all segments\n * @returns Array of styled text segments with consistent style properties\n */\n private parseRichText(input: string, baseStyle: Partial<TextSegment>): TextSegment[] {\n // Match opening/closing tags with optional quoted/unquoted values\n // Capture groups: (1) closing slash, (2) tag name, (3) double quoted value, (4) single quoted value, (5) unquoted value\n const tagRegex = /<(\\/?)(\\w+)(?:=(?:\"([^\"]*)\"|'([^']*)'|([^\\s>]+)))?>/g\n const stack: Partial<TextSegment>[] = []\n const segments: TextSegment[] = []\n let lastIndex = 0\n let currentStyle: Partial<TextSegment> = { ...baseStyle }\n\n // Helper to create a styled segment ensuring all style properties are included\n const applyStyle = (text: string) => {\n if (!text) return\n segments.push({\n text,\n color: currentStyle.color,\n weight: currentStyle.weight,\n size: currentStyle.size,\n b: currentStyle.b,\n i: currentStyle.i,\n })\n }\n\n let match: RegExpExecArray | null\n while ((match = tagRegex.exec(input))) {\n const [, closingSlash, tagNameStr, quotedVal1, quotedVal2, unquotedVal] = match\n const tagName = tagNameStr.toLowerCase()\n const value = quotedVal1 || quotedVal2 || unquotedVal\n\n // Process text content before the current tag\n applyStyle(input.slice(lastIndex, match.index))\n lastIndex = tagRegex.lastIndex\n\n if (!closingSlash) {\n // Opening tag: Save current style state and apply new style\n stack.push({ ...currentStyle })\n\n switch (tagName) {\n case 'color':\n // Support any valid CSS color value\n currentStyle.color = value as TextSegment['color']\n break\n\n case 'weight':\n // Support numeric weights (100-900) or keywords\n currentStyle.weight = value as TextSegment['weight']\n break\n\n case 'size':\n // Parse pixel size as number, revert to default if invalid\n currentStyle.size = value ? Number(value) : undefined\n if (isNaN(currentStyle.size as number)) {\n console.warn(`[TextNode ${this.key || ''}] Invalid numeric value for size tag: ${value}`)\n currentStyle.size = undefined\n }\n break\n\n case 'b':\n // Simple bold flag\n currentStyle.b = true\n break\n\n case 'i':\n // Simple italic flag\n currentStyle.i = true\n break\n }\n } else {\n // Closing tag: Restore previous style state\n currentStyle = stack.pop() || { ...baseStyle }\n }\n }\n\n // Process remaining text after last tag\n applyStyle(input.slice(lastIndex))\n\n // Don't filter out empty segments - they might represent empty lines\n return segments\n }\n\n private formatSpacing(value: TextProps['letterSpacing'] | TextProps['wordSpacing']) {\n if (typeof value === 'number') return `${value}px`\n return value || 'normal'\n }\n\n private parseSpacingToPx(spacingValue: number | string | undefined, fontSize: number): number {\n if (spacingValue === undefined || spacingValue === 'normal') {\n return 0\n }\n if (typeof spacingValue === 'number') {\n return spacingValue // Treat raw number as px\n }\n if (typeof spacingValue === 'string') {\n const trimmed = spacingValue.trim()\n if (trimmed.endsWith('px')) {\n return parseFloat(trimmed) || 0\n }\n if (trimmed.endsWith('em')) {\n // Convert em based on the current font size\n return (parseFloat(trimmed) || 0) * fontSize\n }\n // Attempt to parse as a raw number (pixels) if no unit\n const parsed = parseFloat(trimmed)\n if (!isNaN(parsed)) {\n return parsed\n }\n }\n return 0 // Default fallback\n }\n\n /**\n * Adds manual letter spacing compensation to a measured text width.\n * Needed because skia-canvas ctx.measureText() does not include letterSpacing in the returned width,\n * even though letterSpacing IS applied during rendering (fillText/strokeText).\n */\n private addLetterSpacingExtra(text: string, measuredWidth: number, letterSpacingPx: number): number {\n if (letterSpacingPx === 0 || text.length === 0) return measuredWidth\n const charCount = [...text].length\n return measuredWidth + (charCount > 1 ? (charCount - 1) * letterSpacingPx : 0)\n }\n\n /**\n * Generates a CSS font string by combining base TextProps with optional TextSegment styling.\n * Follows browser font string format: \"font-style font-weight font-size font-family\"\n *\n * Priority for style properties:\n * - Weight: segment <weight> tag > segment <b> tag > base fontWeight prop\n * - Style: segment <i> > base fontStyle\n * - Size: segment size > base fontSize\n * - Family: base fontFamily\n * @param segmentStyle Optional TextSegment styling to override base props\n * @returns Formatted CSS font string for canvas context\n */\n private getFontString(segmentStyle?: Partial<TextSegment>): string {\n const baseStyle = this.props\n let effectiveWeight: TextSegment['weight'] | number | undefined\n\n // Determine italic style - segment <i> tag overrides base style\n const effectiveStyle = segmentStyle?.i ? 'italic' : baseStyle.fontStyle || 'normal'\n\n // Determine font weight with priority:\n // 1. Segment explicit weight (<weight> tag)\n // 2. Segment bold flag (<b> tag)\n // 3. Base font weight prop\n if (segmentStyle?.weight) {\n effectiveWeight = segmentStyle.weight\n } else if (segmentStyle?.b) {\n effectiveWeight = 'bold'\n } else {\n effectiveWeight = baseStyle.fontWeight || 'normal'\n }\n\n // Use segment size if specified, otherwise base size with 16px default\n const effectiveSize = segmentStyle?.size ? segmentStyle.size : baseStyle.fontSize || 16\n\n // Combine properties into CSS font string format\n const style = {\n fontStyle: effectiveStyle,\n fontWeight: effectiveWeight,\n fontSize: effectiveSize,\n fontFamily: baseStyle.fontFamily || 'sans-serif',\n }\n\n return `${style.fontStyle} ${style.fontWeight} ${style.fontSize}px ${style.fontFamily}`\n }\n\n /**\n * Gets lines to process respecting maxLines constraint\n */\n private getLinesToMeasureOrRender(): TextSegment[][] {\n const maxLines = this.props.maxLines\n if (maxLines !== undefined && maxLines > 0 && this.lines.length > maxLines) {\n return this.lines.slice(0, maxLines)\n }\n return this.lines\n }\n\n /**\n * Measures text dimensions and calculates layout metrics for the YogaLayout engine.\n * Handles text wrapping, line height calculations, and dynamic leading.\n *\n * Line heights are determined by:\n * 1. Using props.lineHeight as fixed pixel value if provided\n * 2. Otherwise calculating dynamic height based on largest font size per line\n * 3. Adding leading space above/below text content\n * 4. Including specified line gaps between lines\n * @param widthConstraint Maximum allowed width in pixels for text layout\n * @param widthMode YogaLayout mode determining how width constraint is applied\n * @returns Calculated minimum dimensions required to render text content\n * - width: Total width needed for text layout\n * - height: Total height including line heights and gaps\n */\n private measureText(widthConstraint: number, widthMode: MeasureMode): { width: number; height: number } {\n // Create measurement canvas if not exists\n if (!TextNode.measurementContext) {\n TextNode.measurementContext = new Canvas(1, 1).getContext('2d')\n }\n const baseFontSize = this.props.fontSize || 16\n const ctx = TextNode.measurementContext!\n ctx.save()\n\n // Setup text measurement context\n ctx.letterSpacing = this.formatSpacing(this.props.letterSpacing)\n ctx.wordSpacing = 'normal' // Handled manually via parsedWordSpacingPx\n const parsedWordSpacingPx = this.parseSpacingToPx(this.props.wordSpacing, baseFontSize)\n const parsedLetterSpacingPx = this.parseSpacingToPx(this.props.letterSpacing, baseFontSize)\n\n // Pre-measure each text segment width with its specific styling\n for (const segment of this.segments) {\n ctx.font = this.getFontString(segment)\n if (typeof this.props.fontVariant === 'string') {\n ctx.fontVariant = this.props.fontVariant\n } else if (this.props.fontVariant !== undefined) {\n console.warn(`[TextNode ${this.key || ''}] Invalid fontVariant prop type in measureText (segment width):`, this.props.fontVariant)\n if (ctx.fontVariant !== 'normal') ctx.fontVariant = 'normal'\n } else {\n if (ctx.fontVariant !== 'normal') ctx.fontVariant = 'normal'\n }\n segment.width = this.addLetterSpacingExtra(segment.text, ctx.measureText(segment.text).width, parsedLetterSpacingPx)\n }\n\n // Calculate available layout width\n const availableWidthForContent = widthMode === Style.MeasureMode.Undefined ? Infinity : Math.max(0, widthConstraint)\n const epsilon = 0.001 // Float precision compensation\n\n // Wrap text into lines based on available width\n this.lines = this.wrapTextRich(ctx, this.segments, availableWidthForContent + epsilon, parsedWordSpacingPx, parsedLetterSpacingPx)\n\n // Initialize line metrics arrays\n this.lineHeights = [] // Final heights including leading\n this.lineAscents = [] // Text ascent heights\n this.lineContentHeights = [] // Raw content heights (ascent + descent)\n\n let totalTextHeight = 0\n const linesToMeasure = this.getLinesToMeasureOrRender()\n const numLines = linesToMeasure.length\n const defaultLineHeightMultiplier = 1.2 // Base leading multiplier\n\n // Calculate metrics for each line\n for (const line of linesToMeasure) {\n let maxAscent = 0\n let maxDescent = 0\n let maxFontSizeOnLine = 0\n\n // Handle empty line metrics\n if (line.length === 0) {\n ctx.font = this.getFontString()\n if (typeof this.props.fontVariant === 'string') {\n ctx.fontVariant = this.props.fontVariant\n } else if (this.props.fontVariant !== undefined) {\n console.warn(`[TextNode ${this.key || ''}] Invalid fontVariant prop type in measureText (empty line):`, this.props.fontVariant)\n if (ctx.fontVariant !== 'normal') ctx.fontVariant = 'normal'\n } else {\n if (ctx.fontVariant !== 'normal') ctx.fontVariant = 'normal'\n }\n const metrics = ctx.measureText(this.metricsString)\n maxAscent = metrics.actualBoundingBoxAscent ?? baseFontSize * 0.8\n maxDescent = metrics.actualBoundingBoxDescent ?? baseFontSize * 0.2\n maxFontSizeOnLine = baseFontSize\n } else {\n // Calculate max metrics across all segments in line\n for (const segment of line) {\n if (/^\\s+$/.test(segment.text)) continue\n\n const segmentSize = segment.size || baseFontSize\n maxFontSizeOnLine = Math.max(maxFontSizeOnLine, segmentSize)\n\n ctx.font = this.getFontString(segment)\n if (typeof this.props.fontVariant === 'string') {\n ctx.fontVariant = this.props.fontVariant\n } else if (this.props.fontVariant !== undefined) {\n console.warn(`[TextNode ${this.key || ''}] Invalid fontVariant prop type in measureText (segment height):`, this.props.fontVariant)\n if (ctx.fontVariant !== 'normal') ctx.fontVariant = 'normal'\n } else {\n if (ctx.fontVariant !== 'normal') ctx.fontVariant = 'normal'\n }\n\n const metrics = ctx.measureText(this.metricsString)\n const ascent = metrics.actualBoundingBoxAscent ?? segmentSize * 0.8\n const descent = metrics.actualBoundingBoxDescent ?? segmentSize * 0.2\n\n maxAscent = Math.max(maxAscent, ascent)\n maxDescent = Math.max(maxDescent, descent)\n }\n }\n\n // Fallback metrics for lines with only whitespace\n if (maxAscent === 0 && maxDescent === 0 && line.length > 0) {\n ctx.font = this.getFontString()\n if (typeof this.props.fontVariant === 'string') {\n ctx.fontVariant = this.props.fontVariant\n } else if (this.props.fontVariant !== undefined) {\n console.warn(`[TextNode ${this.key || ''}] Invalid fontVariant prop type in measureText (fallback):`, this.props.fontVariant)\n if (ctx.fontVariant !== 'normal') ctx.fontVariant = 'normal'\n } else {\n if (ctx.fontVariant !== 'normal') ctx.fontVariant = 'normal'\n }\n const metrics = ctx.measureText(this.metricsString)\n maxAscent = metrics.actualBoundingBoxAscent ?? baseFontSize * 0.8\n maxDescent = metrics.actualBoundingBoxDescent ?? baseFontSize * 0.2\n maxFontSizeOnLine = maxFontSizeOnLine || baseFontSize\n }\n\n maxFontSizeOnLine = maxFontSizeOnLine || baseFontSize\n\n // Calculate total content height for line\n const actualContentHeight = maxAscent + maxDescent\n\n // Determine final line box height with leading\n const targetLineBoxHeight =\n typeof this.props.lineHeight === 'number' && this.props.lineHeight > 0 ? this.props.lineHeight : maxFontSizeOnLine * defaultLineHeightMultiplier\n\n // Use larger of target height or content height to prevent clipping\n const finalLineHeight = Math.max(actualContentHeight, targetLineBoxHeight)\n\n // Store line metrics for rendering\n this.lineHeights.push(finalLineHeight)\n this.lineAscents.push(maxAscent)\n this.lineContentHeights.push(actualContentHeight)\n\n totalTextHeight += finalLineHeight\n }\n\n // Add line gap spacing to total height\n const lineGapValue = this.props.lineGap\n const totalGapHeight = Math.max(0, (numLines - 1) * lineGapValue)\n const calculatedContentHeight = totalTextHeight + totalGapHeight\n\n // Calculate width required for text content\n const spaceWidth = this.measureSpaceWidth(ctx)\n let singleLineWidth = 0\n let firstWordInSingleLine = true\n for (const segment of this.segments) {\n const words = segment.text.split(/(\\s+)/).filter(Boolean)\n for (const word of words) {\n if (/^\\s+$/.test(word)) continue\n ctx.font = this.getFontString(segment)\n if (typeof this.props.fontVariant === 'string') {\n ctx.fontVariant = this.props.fontVariant\n } else if (this.props.fontVariant !== undefined) {\n console.warn(`[TextNode ${this.key || ''}] Invalid fontVariant prop type in measureText (single line width):`, this.props.fontVariant)\n if (ctx.fontVariant !== 'normal') ctx.fontVariant = 'normal'\n } else {\n if (ctx.fontVariant !== 'normal') ctx.fontVariant = 'normal'\n }\n const wordWidth = this.addLetterSpacingExtra(word, ctx.measureText(word).width, parsedLetterSpacingPx)\n if (!firstWordInSingleLine) {\n singleLineWidth += spaceWidth + parsedWordSpacingPx\n }\n singleLineWidth += wordWidth\n firstWordInSingleLine = false\n }\n }\n\n // Determine final content width based on wrapping\n let requiredContentWidth: number\n if (singleLineWidth <= availableWidthForContent) {\n requiredContentWidth = singleLineWidth\n if (linesToMeasure.length > 1 && this.props.maxLines !== 1 && !this.segments.some(s => s.text.includes('\\n'))) {\n console.warn(\n `[TextNode ${this.key || ''}] Rich text should fit (${singleLineWidth.toFixed(2)} <= ${availableWidthForContent.toFixed(2)}) but wrapTextRich produced ${linesToMeasure.length} lines. Width calculation might be slightly off due to complex spacing/kerning.`,\n )\n let maxWrappedLineWidth = 0\n for (const line of linesToMeasure) {\n let currentLineWidth = 0\n let firstWordOnWrappedLine = true\n for (const segment of line) {\n const segmentWidth = segment.width ?? 0\n const isSpaceSegment = /^\\s+$/.test(segment.text)\n if (!isSpaceSegment) {\n if (!firstWordOnWrappedLine) {\n currentLineWidth += spaceWidth + parsedWordSpacingPx\n }\n currentLineWidth += segmentWidth\n firstWordOnWrappedLine = false\n }\n }\n maxWrappedLineWidth = Math.max(maxWrappedLineWidth, currentLineWidth)\n }\n requiredContentWidth = Math.max(singleLineWidth, maxWrappedLineWidth)\n }\n } else {\n let maxWrappedLineWidth = 0\n for (const line of linesToMeasure) {\n let currentLineWidth = 0\n let firstWordOnWrappedLine = true\n for (const segment of line) {\n const segmentWidth = segment.width ?? 0\n const isSpaceSegment = /^\\s+$/.test(segment.text)\n if (!isSpaceSegment) {\n if (!firstWordOnWrappedLine) {\n currentLineWidth += spaceWidth + parsedWordSpacingPx\n }\n currentLineWidth += segmentWidth\n firstWordOnWrappedLine = false\n }\n }\n maxWrappedLineWidth = Math.max(maxWrappedLineWidth, currentLineWidth)\n }\n requiredContentWidth = maxWrappedLineWidth\n }\n\n // Constrain width if needed\n let finalContentWidth = requiredContentWidth\n if (availableWidthForContent !== Infinity) {\n finalContentWidth = Math.min(requiredContentWidth, availableWidthForContent)\n }\n\n ctx.restore()\n return {\n width: Math.max(0, finalContentWidth),\n height: Math.max(0, calculatedContentHeight),\n }\n }\n\n /**\n * Wraps text segments into multiple lines while respecting width constraints and preserving styling.\n * Handles rich text attributes (color, weight, size, bold, italic) and proper word wrapping.\n * Also respects explicit newline characters (\\n) for forced line breaks.\n * @param ctx Canvas rendering context used for text measurements\n * @param segments Array of text segments with styling information\n * @param maxWidth Maximum allowed width for each line in pixels\n * @param parsedWordSpacingPx Additional spacing to add between words in pixels\n * @returns Array of lines, where each line contains styled text segments\n */\n private wrapTextRich(\n ctx: CanvasRenderingContext2D,\n segments: TextSegment[],\n maxWidth: number,\n parsedWordSpacingPx: number,\n parsedLetterSpacingPx: number = 0,\n ): TextSegment[][] {\n const lines: TextSegment[][] = []\n\n if (segments.length === 0 || maxWidth <= 0) return lines\n\n let currentLineSegments: TextSegment[] = []\n let currentLineWidth = 0\n const spaceWidth = this.measureSpaceWidth(ctx)\n\n // Helper to finalize current line and start new one\n const finalizeLine = (forceEmpty = false) => {\n // Remove trailing whitespace segments unless we're forcing an empty line\n if (!forceEmpty) {\n while (currentLineSegments.length > 0 && /^\\s+$/.test(currentLineSegments[currentLineSegments.length - 1].text)) {\n currentLineSegments.pop()\n }\n }\n // Always push the line, even if empty (for \\n\\n cases)\n lines.push(currentLineSegments)\n currentLineSegments = []\n currentLineWidth = 0\n }\n\n for (const segment of segments) {\n // Preserve all style attributes for consistency\n const segmentStyle = {\n color: segment.color,\n weight: segment.weight,\n size: segment.size,\n b: segment.b,\n i: segment.i,\n }\n\n // Check if segment contains newline characters\n if (segment.text.includes('\\n')) {\n // Split by newlines and process each part\n const parts = segment.text.split('\\n')\n\n for (let i = 0; i < parts.length; i++) {\n const part = parts[i]\n const isLastPart = i === parts.length - 1\n\n if (part.length > 0) {\n // Process this part normally\n const wordsAndSpaces = part.split(/(\\s+)/).filter(Boolean)\n\n for (const wordOrSpace of wordsAndSpaces) {\n const isSpace = /^\\s+$/.test(wordOrSpace)\n let wordSegment: TextSegment\n let wordWidth: number\n\n if (isSpace) {\n wordSegment = { text: wordOrSpace, ...segmentStyle, width: 0 }\n wordWidth = 0\n } else {\n ctx.font = this.getFontString(segmentStyle)\n if (this.props.fontVariant) ctx.fontVariant = this.props.fontVariant\n wordWidth = this.addLetterSpacingExtra(wordOrSpace, ctx.measureText(wordOrSpace).width, parsedLetterSpacingPx)\n wordSegment = { text: wordOrSpace, ...segmentStyle, width: wordWidth }\n }\n\n const needsSpace = currentLineSegments.length > 0 && !/^\\s+$/.test(currentLineSegments[currentLineSegments.length - 1].text)\n const spaceToAdd = needsSpace ? spaceWidth + parsedWordSpacingPx : 0\n\n if (currentLineWidth + spaceToAdd + wordWidth <= maxWidth || currentLineSegments.length === 0) {\n if (needsSpace) {\n currentLineSegments.push({ text: ' ', ...segmentStyle, width: 0 })\n currentLineWidth += spaceToAdd\n }\n currentLineSegments.push(wordSegment)\n currentLineWidth += wordWidth\n } else {\n if (currentLineSegments.length > 0) {\n finalizeLine()\n }\n\n if (!isSpace) {\n if (wordWidth > maxWidth && maxWidth > 0) {\n const brokenParts = this.breakWordRich(ctx, wordSegment, maxWidth, parsedLetterSpacingPx)\n\n if (brokenParts.length > 0) {\n for (let k = 0; k < brokenParts.length - 1; k++) {\n lines.push([brokenParts[k]])\n }\n currentLineSegments = [brokenParts[brokenParts.length - 1]]\n currentLineWidth = brokenParts[brokenParts.length - 1].width ?? 0\n } else {\n currentLineSegments = [wordSegment]\n currentLineWidth = wordWidth\n }\n } else {\n currentLineSegments = [wordSegment]\n currentLineWidth = wordWidth\n }\n }\n }\n }\n }\n\n // Force line break after each part except the last\n // If part is empty, this creates an empty line (like \\n\\n)\n if (!isLastPart) {\n finalizeLine(part.length === 0)\n }\n }\n } else {\n // No newlines - process normally\n const wordsAndSpaces = segment.text.split(/(\\s+)/).filter(Boolean)\n\n for (const wordOrSpace of wordsAndSpaces) {\n const isSpace = /^\\s+$/.test(wordOrSpace)\n let wordSegment: TextSegment\n let wordWidth: number\n\n if (isSpace) {\n wordSegment = { text: wordOrSpace, ...segmentStyle, width: 0 }\n wordWidth = 0\n } else {\n ctx.font = this.getFontString(segmentStyle)\n if (this.props.fontVariant) ctx.fontVariant = this.props.fontVariant\n wordWidth = this.addLetterSpacingExtra(wordOrSpace, ctx.measureText(wordOrSpace).width, parsedLetterSpacingPx)\n wordSegment = { text: wordOrSpace, ...segmentStyle, width: wordWidth }\n }\n\n const needsSpace = currentLineSegments.length > 0 && !/^\\s+$/.test(currentLineSegments[currentLineSegments.length - 1].text)\n const spaceToAdd = needsSpace ? spaceWidth + parsedWordSpacingPx : 0\n\n if (currentLineWidth + spaceToAdd + wordWidth <= maxWidth || currentLineSegments.length === 0) {\n if (needsSpace) {\n currentLineSegments.push({ text: ' ', ...segmentStyle, width: 0 })\n currentLineWidth += spaceToAdd\n }\n currentLineSegments.push(wordSegment)\n currentLineWidth += wordWidth\n } else {\n if (currentLineSegments.length > 0) {\n finalizeLine()\n }\n\n if (!isSpace) {\n if (wordWidth > maxWidth && maxWidth > 0) {\n const brokenParts = this.breakWordRich(ctx, wordSegment, maxWidth, parsedLetterSpacingPx)\n\n if (brokenParts.length > 0) {\n for (let k = 0; k < brokenParts.length - 1; k++) {\n lines.push([brokenParts[k]])\n }\n currentLineSegments = [brokenParts[brokenParts.length - 1]]\n currentLineWidth = brokenParts[brokenParts.length - 1].width ?? 0\n } else {\n currentLineSegments = [wordSegment]\n currentLineWidth = wordWidth\n }\n } else {\n currentLineSegments = [wordSegment]\n currentLineWidth = wordWidth\n }\n }\n }\n }\n }\n }\n\n finalizeLine()\n return lines\n }\n\n /**\n * Breaks a word segment into multiple segments that each fit within the specified width constraint.\n * Maintains all styling properties (color, weight, size, bold, italic) across broken segments.\n * @param ctx Canvas rendering context used for text measurements\n * @param segmentToBreak Original text segment to split\n * @param maxWidth Maximum width allowed for each resulting segment\n * @returns Array of TextSegments, each fitting maxWidth, or original segment if no breaking needed\n */\n private breakWordRich(ctx: CanvasRenderingContext2D, segmentToBreak: TextSegment, maxWidth: number, parsedLetterSpacingPx: number = 0): TextSegment[] {\n const word = segmentToBreak.text\n\n // Copy all style properties to maintain consistent styling across broken segments\n const style = {\n color: segmentToBreak.color,\n weight: segmentToBreak.weight,\n size: segmentToBreak.size,\n b: segmentToBreak.b,\n i: segmentToBreak.i,\n }\n\n if (maxWidth <= 0) return [segmentToBreak]\n\n const brokenSegments: TextSegment[] = []\n let currentPartText = ''\n\n // Configure context with segment style for accurate measurements\n ctx.font = this.getFontString(style)\n if (this.props.fontVariant) ctx.fontVariant = this.props.fontVariant\n\n // Process word character by character to find valid break points\n for (const char of word) {\n const testPartText = currentPartText + char\n const testPartWidth = this.addLetterSpacingExtra(testPartText, ctx.measureText(testPartText).width, parsedLetterSpacingPx)\n\n if (testPartWidth > maxWidth) {\n // Current accumulated text exceeds width - create new segment\n if (currentPartText) {\n brokenSegments.push({\n text: currentPartText,\n ...style,\n width: this.addLetterSpacingExtra(currentPartText, ctx.measureText(currentPartText).width, parsedLetterSpacingPx),\n })\n }\n\n // Handle current character that caused overflow\n currentPartText = char\n const currentCharWidth = ctx.measureText(currentPartText).width\n\n if (currentCharWidth > maxWidth) {\n // Single character is too wide - force break after it\n brokenSegments.push({\n text: currentPartText,\n ...style,\n width: currentCharWidth,\n })\n currentPartText = ''\n }\n } else {\n // Character fits - add to current part\n currentPartText = testPartText\n }\n }\n\n // Handle any remaining text as final segment\n if (currentPartText) {\n brokenSegments.push({\n text: currentPartText,\n ...style,\n width: this.addLetterSpacingExtra(currentPartText, ctx.measureText(currentPartText).width, parsedLetterSpacingPx),\n })\n }\n\n return brokenSegments.length > 0 ? brokenSegments : [segmentToBreak]\n }\n\n /**\n * Measures width of space character using base font\n */\n private measureSpaceWidth(ctx: CanvasRenderingContext2D): number {\n const originalFont = ctx.font\n ctx.font = this.getFontString()\n const width = ctx.measureText(' ').width\n ctx.font = originalFont\n return width > 0 ? width : (this.props.fontSize || 16) * 0.3\n }\n\n /**\n * Renders multi-line text content with rich text styling and layout features\n *\n * Core features:\n * - Dynamic line heights with leading/spacing controls\n * - Vertical text alignment (top/middle/bottom)\n * - Horizontal text alignment (left/center/right/justify)\n * - Text wrapping within bounds\n * - Ellipsis truncation\n * - Rich text styling per segment (color, weight, size, etc)\n * - Performance optimizations (clipping, visibility checks)\n * @param ctx Canvas rendering context\n * @param x Content box left position in pixels\n * @param y Content box top position in pixels\n * @param width Content box total width including padding\n * @param height Content box total height including padding\n */\n protected override _renderContent(ctx: CanvasRenderingContext2D, x: number, y: number, width: number, height: number) {\n super._renderContent(ctx, x, y, width, height)\n\n ctx.save()\n ctx.textBaseline = 'alphabetic'\n ctx.letterSpacing = this.formatSpacing(this.props.letterSpacing)\n ctx.wordSpacing = 'normal'\n\n const baseFontSize = this.props.fontSize || 16\n const parsedWordSpacingPx = this.parseSpacingToPx(this.props.wordSpacing, baseFontSize)\n\n // Calculate content box with padding\n const paddingLeft = this.node.getComputedPadding(Style.Edge.Left) ?? 0\n const paddingTop = this.node.getComputedPadding(Style.Edge.Top) ?? 0\n const paddingRight = this.node.getComputedPadding(Style.Edge.Right) ?? 0\n const paddingBottom = this.node.getComputedPadding(Style.Edge.Bottom) ?? 0\n const contentX = x + paddingLeft\n const contentY = y + paddingTop\n const contentWidth = Math.max(0, width - paddingLeft - paddingRight)\n const contentHeight = Math.max(0, height - paddingTop - paddingBottom)\n\n if (contentWidth <= 0 || contentHeight <= 0) {\n ctx.restore()\n return\n }\n\n // Re-calculate lines based on the actual render width to ensure consistency\n // This fixes issues where Yoga Layout might use a cached measurement from a different\n // width constraint (e.g., during a flex shrink pass) but final layout is wider.\n const spaceWidth = this.measureSpaceWidth(ctx)\n // Use a small epsilon for float precision issues\n const epsilon = 0.01\n const parsedLetterSpacingPx = this.parseSpacingToPx(this.props.letterSpacing, baseFontSize)\n const allLines = this.wrapTextRich(ctx, this.segments, contentWidth + epsilon, parsedWordSpacingPx, parsedLetterSpacingPx)\n\n const needsEllipsis = this.props.ellipsis && this.props.maxLines !== undefined && allLines.length > this.props.maxLines\n\n // Apply maxLines constraint to get the visible lines\n const visibleLines = this.props.maxLines !== undefined && this.props.maxLines > 0 ? allLines.slice(0, this.props.maxLines) : allLines\n\n const numLinesToRender = visibleLines.length\n\n // Recalculate line metrics for the rendered lines\n // We cannot rely on this.lineHeights from measureText because it might correspond to different wrapping\n const lineHeights: number[] = []\n const lineAscents: number[] = []\n const lineContentHeights: number[] = []\n const defaultLineHeightMultiplier = 1.2\n let totalTextHeight = 0\n\n for (const line of visibleLines) {\n let maxAscent = 0\n let maxDescent = 0\n let maxFontSizeOnLine = 0\n\n if (line.length === 0) {\n ctx.font = this.getFontString()\n if (this.props.fontVariant) ctx.fontVariant = typeof this.props.fontVariant === 'string' ? this.props.fontVariant : 'normal'\n const metrics = ctx.measureText(this.metricsString)\n maxAscent = metrics.actualBoundingBoxAscent ?? baseFontSize * 0.8\n maxDescent = metrics.actualBoundingBoxDescent ?? baseFontSize * 0.2\n maxFontSizeOnLine = baseFontSize\n } else {\n for (const segment of line) {\n if (/^\\s+$/.test(segment.text)) continue\n const segmentSize = segment.size || baseFontSize\n maxFontSizeOnLine = Math.max(maxFontSizeOnLine, segmentSize)\n\n // Style context for accurate metrics\n ctx.font = this.getFontString(segment)\n if (this.props.fontVariant) ctx.fontVariant = typeof this.props.fontVariant === 'string' ? this.props.fontVariant : 'normal'\n\n const metrics = ctx.measureText(this.metricsString)\n const ascent = metrics.actualBoundingBoxAscent ?? segmentSize * 0.8\n const descent = metrics.actualBoundingBoxDescent ?? segmentSize * 0.2\n maxAscent = Math.max(maxAscent, ascent)\n maxDescent = Math.max(maxDescent, descent)\n }\n }\n if (maxAscent === 0 && maxDescent === 0 && line.length > 0) {\n // Fallback\n ctx.font = this.getFontString()\n if (this.props.fontVariant) ctx.fontVariant = typeof this.props.fontVariant === 'string' ? this.props.fontVariant : 'normal'\n const metrics = ctx.measureText(this.metricsString)\n maxAscent = metrics.actualBoundingBoxAscent ?? baseFontSize * 0.8\n maxDescent = metrics.actualBoundingBoxDescent ?? baseFontSize * 0.2\n maxFontSizeOnLine = maxFontSizeOnLine || baseFontSize\n }\n maxFontSizeOnLine = maxFontSizeOnLine || baseFontSize\n const actualContentHeight = maxAscent + maxDescent\n const targetLineBoxHeight =\n typeof this.props.lineHeight === 'number' && this.props.lineHeight > 0 ? this.props.lineHeight : maxFontSizeOnLine * defaultLineHeightMultiplier\n const finalLineHeight = Math.max(actualContentHeight, targetLineBoxHeight)\n\n lineHeights.push(finalLineHeight)\n lineAscents.push(maxAscent)\n lineContentHeights.push(actualContentHeight)\n totalTextHeight += finalLineHeight\n }\n\n if (numLinesToRender === 0) {\n ctx.restore()\n return\n }\n\n // Calculate vertical alignment offset\n const lineGapValue = this.props.lineGap\n const totalCalculatedTextHeight = totalTextHeight + Math.max(0, numLinesToRender - 1) * lineGapValue\n\n let blockStartY: number\n switch (this.props.verticalAlign) {\n case 'middle':\n blockStartY = contentY + (contentHeight - totalCalculatedTextHeight) / 2\n break\n case 'bottom':\n blockStartY = contentY + contentHeight - totalCalculatedTextHeight\n break\n case 'top':\n default:\n blockStartY = contentY\n }\n\n let currentLineTopY = blockStartY\n\n // Setup text content clipping region\n ctx.beginPath()\n ctx.rect(contentX, contentY, contentWidth, contentHeight)\n ctx.clip()\n\n // Configure ellipsis if needed\n const ellipsisChar = typeof this.props.ellipsis === 'string' ? this.props.ellipsis : '...'\n let ellipsisWidth = 0\n let ellipsisStyle: Partial<TextSegment> | undefined = undefined\n\n if (needsEllipsis) {\n const lastRenderedLine = visibleLines[visibleLines.length - 1]\n // ... ellipsis calculation ...\n const lastTextStyleSegment = [...lastRenderedLine].reverse().find(seg => !/^\\s+$/.test(seg.text))\n ellipsisStyle = lastTextStyleSegment\n ? {\n color: lastTextStyleSegment.color,\n weight: lastTextStyleSegment.weight,\n size: lastTextStyleSegment.size,\n b: lastTextStyleSegment.b,\n i: lastTextStyleSegment.i,\n }\n : undefined\n\n ctx.save()\n ctx.font = this.getFontString(ellipsisStyle)\n if (this.props.fontVariant) {\n ctx.fontVariant = typeof this.props.fontVariant === 'string' ? this.props.fontVariant : 'normal'\n }\n ellipsisWidth = ctx.measureText(ellipsisChar).width\n ctx.restore()\n }\n\n // Render text content line by line\n for (let i = 0; i < numLinesToRender; i++) {\n const lineSegments = visibleLines[i]\n const currentLineFinalHeight = lineHeights[i]\n const currentLineMaxAscent = lineAscents[i]\n const currentLineContentHeight = lineContentHeights[i]\n\n // Calculate line spacing metrics\n const currentLineLeading = currentLineFinalHeight - currentLineContentHeight\n const currentLineSpaceAbove = Math.max(0, currentLineLeading / 2)\n const lineY = currentLineTopY + currentLineSpaceAbove + currentLineMaxAscent\n\n // Visibility culling check\n const lineTop = currentLineTopY\n const lineBottom = currentLineTopY + currentLineFinalHeight\n\n // Don't skip empty lines - they're intentional (from \\n\\n)\n // Only skip if the line is completely outside the visible area\n if (lineBottom <= contentY || lineTop >= contentY + contentHeight) {\n currentLineTopY += currentLineFinalHeight + lineGapValue\n continue\n }\n\n const isLastRenderedLine = i === numLinesToRender - 1\n\n // Calculate line width metrics for alignment\n let totalLineWidth = 0\n let totalWordsWidth = 0\n let numWordGaps = 0\n let firstWordOnLine = true\n const noSpaceBeforePunctuation = /^[.,!?;:)\\]}]/\n\n for (const segment of lineSegments) {\n const segmentWidth = segment.width ?? 0\n const isSpaceSegment = /^\\s+$/.test(segment.text)\n\n if (!isSpaceSegment) {\n if (!firstWordOnLine) {\n totalLineWidth += spaceWidth + parsedWordSpacingPx\n if (!noSpaceBeforePunctuation.test(segment.text)) {\n numWordGaps++\n }\n }\n totalLineWidth += segmentWidth\n totalWordsWidth += segmentWidth\n firstWordOnLine = false\n }\n }\n\n // Calculate horizontal alignment position\n const isJustify = this.props.textAlign === 'justify' && !isLastRenderedLine\n const lineTextAlign = isJustify ? 'left' : this.props.textAlign || 'left'\n let currentX: number\n\n switch (lineTextAlign) {\n case 'center':\n currentX = contentX + (contentWidth - totalLineWidth) / 2\n break\n case 'right':\n case 'end':\n currentX = contentX + contentWidth - totalLineWidth\n break\n case 'left':\n case 'start':\n default:\n currentX = contentX\n }\n currentX = Math.max(contentX, currentX)\n\n // Calculate justification spacing\n let spacePerWordGapPlusSpacing = spaceWidth + parsedWordSpacingPx\n if (isJustify && numWordGaps > 0 && totalLineWidth < contentWidth) {\n const totalBaseSpacingWidth = numWordGaps * (spaceWidth + parsedWordSpacingPx)\n const remainingSpace = contentWidth - totalWordsWidth - totalBaseSpacingWidth\n if (remainingSpace > 0) {\n spacePerWordGapPlusSpacing += remainingSpace / numWordGaps\n }\n }\n\n // Render line segments (skip rendering for truly empty lines)\n if (lineSegments.length > 0 && !lineSegments.every(s => s.text.trim() === '')) {\n let accumulatedWidth = 0\n let ellipsisApplied = false\n let firstWordDrawn = false\n\n for (let j = 0; j < lineSegments.length; j++) {\n const segment = lineSegments[j]\n const segmentWidth = segment.width ?? 0\n const isLastSegmentOnLine = j === lineSegments.length - 1\n const isSpaceSegment = /^\\s+$/.test(segment.text)\n\n // Calculate word spacing\n let spaceToAddBefore = 0\n if (!isSpaceSegment && firstWordDrawn && !noSpaceBeforePunctuation.test(segment.text)) {\n spaceToAddBefore = isJustify ? spacePerWordGapPlusSpacing : spaceWidth + parsedWordSpacingPx\n }\n\n // Apply segment styles\n ctx.font = this.getFontString(segment)\n ctx.fillStyle = segment.color || this.props.color || 'black'\n\n if (typeof this.props.fontVariant === 'string') {\n ctx.fontVariant = this.props.fontVariant\n } else if (this.props.fontVariant !== undefined) {\n console.warn(`[TextNode ${this.key || ''}] Invalid fontVariant prop type in _renderContent (segment render):`, this.props.fontVariant)\n if (ctx.fontVariant !== 'normal') ctx.fontVariant = 'normal'\n } else {\n if (ctx.fontVariant !== 'normal') ctx.fontVariant = 'normal'\n }\n\n // Handle text truncation and ellipsis\n let textToDraw = segment.text\n let currentSegmentRenderWidth = segmentWidth\n let applyEllipsisAfter = false\n\n if (isLastRenderedLine && needsEllipsis && !isSpaceSegment) {\n const currentTotalWidth = accumulatedWidth + spaceToAddBefore + segmentWidth\n const spaceNeededAfter = isLastSegmentOnLine ? 0 : isJustify ? spacePerWordGapPlusSpacing : spaceWidth + parsedWordSpacingPx\n\n if (currentTotalWidth > contentWidth - spaceNeededAfter) {\n const availableWidthForSegment = contentWidth - accumulatedWidth - spaceToAddBefore - ellipsisWidth\n if (availableWidthForSegment > 0) {\n let truncatedText = ''\n for (const char of segment.text) {\n if (ctx.measureText(truncatedText + char).width <= availableWidthForSegment) {\n truncatedText += char\n } else {\n break\n }\n }\n textToDraw = truncatedText\n currentSegmentRenderWidth = ctx.measureText(textToDraw).width\n } else {\n textToDraw = ''\n currentSegmentRenderWidth = 0\n }\n applyEllipsisAfter = true\n ellipsisApplied = true\n } else if (isLastSegmentOnLine) {\n applyEllipsisAfter = true\n ellipsisApplied = true\n }\n }\n\n // Render text segment\n currentX += spaceToAddBefore\n accumulatedWidth += spaceToAddBefore\n\n const remainingRenderWidth = contentX + contentWidth - currentX\n if (currentSegmentRenderWidth > 0 && remainingRenderWidth > 0 && !isSpaceSegment) {\n ctx.textAlign = 'left'\n\n const shadows = this.props.textShadow ? (Array.isArray(this.props.textShadow) ? this.props.textShadow : [this.props.textShadow]) : []\n\n ctx.save()\n\n // Draw shadows\n for (const shadow of shadows) {\n ctx.shadowColor = shadow.color || 'transparent'\n ctx.shadowBlur = shadow.blur || 0\n ctx.shadowOffsetX = shadow.offsetX || 0\n ctx.shadowOffsetY = shadow.offsetY || 0\n ctx.fillText(textToDraw, currentX, lineY, Math.max(0, remainingRenderWidth + 1))\n }\n\n // Reset shadow to draw the main text\n ctx.shadowColor = 'transparent'\n ctx.shadowBlur = 0\n ctx.shadowOffsetX = 0\n ctx.shadowOffsetY = 0\n\n ctx.fillText(textToDraw, currentX, lineY, Math.max(0, remainingRenderWidth + 1))\n\n ctx.restore()\n\n firstWordDrawn = true\n }\n\n currentX += currentSegmentRenderWidth\n accumulatedWidth += currentSegmentRenderWidth\n\n // Render ellipsis\n if (applyEllipsisAfter) {\n const ellipsisRemainingWidth = contentX + contentWidth - currentX\n if (ellipsisRemainingWidth >= ellipsisWidth) {\n ctx.save()\n ctx.font = this.getFontString(ellipsisStyle)\n\n if (typeof this.props.fontVariant === 'string') {\n ctx.fontVariant = this.props.fontVariant\n } else if (this.props.fontVariant !== undefined) {\n console.warn(`[TextNode ${this.key || ''}] Invalid fontVariant prop type in _renderContent (ellipsis draw):`, this.props.fontVariant)\n if (ctx.fontVariant !== 'normal') ctx.fontVariant = 'normal'\n } else {\n if (ctx.fontVariant !== 'normal') ctx.fontVariant = 'normal'\n }\n\n ctx.fillStyle = ellipsisStyle?.color || this.props.color || 'black'\n ctx.fillText(ellipsisChar, currentX, lineY, Math.max(0, ellipsisRemainingWidth + 1))\n ctx.restore()\n }\n break\n }\n\n if (ellipsisApplied && currentX >= contentX + contentWidth) break\n }\n }\n\n currentLineTopY += currentLineFinalHeight + lineGapValue\n }\n\n ctx.restore()\n }\n}\n\n/**\n * Creates a new TextNode instance with rich text support\n */\nexport const Text = (text: number | string, props?: TextProps) => new TextNode(text, props)\n"],"names":["BoxNode","Canvas","Style"],"mappings":";;;;;;AAAA;AAOA;;;AAGG;AACG,MAAO,QAAS,SAAQA,0BAAO,CAAA;IAClB,QAAQ,GAAkB,EAAE;IACrC,KAAK,GAAoB,EAAE;AAC3B,IAAA,OAAO,kBAAkB,GAAoC,IAAI;IACxD,aAAa,GAAG,OAAO;IAChC,WAAW,GAAa,EAAE;IAC1B,WAAW,GAAa,EAAE;IAC1B,kBAAkB,GAAa,EAAE;AAIzC,IAAA,WAAA,CAAY,IAAA,GAAwB,EAAE,EAAE,KAAA,GAAmB,EAAE,EAAA;AAC3D,QAAA,MAAM,YAAY,GAAG;AACnB,YAAA,IAAI,EAAE,UAAU;AAChB,YAAA,UAAU,EAAE,CAAC;AACb,YAAA,OAAO,EAAE,CAAC;AACV,YAAA,GAAG,KAAK;AACR,YAAA,QAAQ,EAAE,SAAS;SACpB;QACD,KAAK,CAAC,YAAY,CAAC;AACnB,QAAA,IAAI,CAAC,KAAK,GAAG,YAAY;;AAEzB,QAAA,MAAM,aAAa,GAAG,IAAI,CAAC,sBAAsB,CAAC,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;QACrE,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,aAAa,CAAC,aAAa,EAAE;AAChD,YAAA,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK;AACvB,YAAA,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,UAAU;AAC7B,YAAA,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,QAAQ;AACzB,YAAA,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,UAAU,KAAK,MAAM;AACnC,YAAA,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,SAAS,KAAK,QAAQ;AACrC,SAAA,CAAC;AACF,QAAA,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACrD,IAAI,CAAC,aAAa,EAAE;IACtB;AAEA;;;;;;;;AAQG;AACI,IAAA,OAAO,gBAAgB,CAC5B,GAA6B,EAC7B,IAAY,EACZ,CAAS,EACT,CAAS,EACT,KAAA,GAQI,EAAE,EAAA;QAEN,GAAG,CAAC,IAAI,EAAE;AAEV,QAAA,MAAM,EACJ,UAAU,GAAG,YAAY,EACzB,QAAQ,GAAG,EAAE,EACb,UAAU,GAAG,QAAQ,EACrB,SAAS,GAAG,QAAQ,EACpB,KAAK,GAAG,MAAM,EACd,SAAS,GAAG,MAAM,EAClB,YAAY,GAAG,YAAY,GAC5B,GAAG,KAAK;AAET,QAAA,GAAG,CAAC,IAAI,GAAG,CAAA,EAAG,SAAS,CAAA,CAAA,EAAI,UAAU,CAAA,CAAA,EAAI,QAAQ,CAAA,GAAA,EAAM,UAAU,CAAA,CAAE;AACnE,QAAA,GAAG,CAAC,SAAS,GAAG,KAAK;AACrB,QAAA,GAAG,CAAC,SAAS,GAAG,SAAS;AACzB,QAAA,GAAG,CAAC,YAAY,GAAG,YAAY;QAE/B,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;QAExB,GAAG,CAAC,OAAO,EAAE;IACf;IAEmB,aAAa,GAAA;AAC9B,QAAA,MAAM,YAAY,GAQd;AACF,YAAA,QAAQ,EAAE,EAAE;AACZ,YAAA,UAAU,EAAE,YAAY;AACxB,YAAA,UAAU,EAAE,QAAQ;AACpB,YAAA,SAAS,EAAE,QAAQ;AACnB,YAAA,KAAK,EAAE,OAAO;AACd,YAAA,SAAS,EAAE,MAAM;AACjB,YAAA,aAAa,EAAE,KAAK;AACpB,YAAA,WAAW,EAAE,SAAS;AACtB,YAAA,UAAU,EAAE,SAAS;AACrB,YAAA,OAAO,EAAE,CAAC;AACV,YAAA,QAAQ,EAAE,SAAS;AACnB,YAAA,QAAQ,EAAE,KAAK;AACf,YAAA,aAAa,EAAE,SAAS;AACxB,YAAA,WAAW,EAAE,SAAS;SACvB;QAED,IAAI,eAAe,GAAG,KAAK;QAC3B,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,YAAY,CAAkC,EAAE;AAC5E,YAAA,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,SAAS,IAAI,YAAY,CAAC,GAAG,CAAC,KAAK,SAAS,EAAE;gBACpE,IAAI,CAAC,KAAK,CAAC,GAAa,CAAC,GAAG,YAAY,CAAC,GAAG,CAAC;gBAC7C,eAAe,GAAG,IAAI;YACxB;QACF;QAEA,IAAI,eAAe,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE;AAC3C,YAAA,MAAM,kBAAkB,GAAG;gBACzB,UAAU;gBACV,YAAY;gBACZ,YAAY;gBACZ,WAAW;gBACX,YAAY;gBACZ,UAAU;gBACV,SAAS;gBACT,eAAe;gBACf,aAAa;AACd,aAAA,CAAC,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,KAAK,YAAY,CAAC,UAAU,CAAC,CAAC;YACzE,IAAI,kBAAkB,EAAE;AACtB,gBAAA,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE;YACvB;QACF;IACF;AAEA;;;;;;;;;;;;;;;;;AAiBG;AACK,IAAA,sBAAsB,CAAC,KAAa,EAAA;QAC1C,OAAO,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,IAAI,KAAI;YAC7C,QAAQ,IAAI;AACV,gBAAA,KAAK,GAAG;oBACN,OAAO,IAAI,CAAA;AACb,gBAAA,KAAK,GAAG;oBACN,OAAO,MAAM,CAAA;AACf,gBAAA,KAAK,GAAG;oBACN,OAAO,IAAI,CAAA;AACb,gBAAA,KAAK,IAAI;oBACP,OAAO,IAAI,CAAA;AACb,gBAAA,KAAK,GAAG;oBACN,OAAO,GAAG,CAAA;AACZ,gBAAA,KAAK,GAAG;oBACN,OAAO,GAAG,CAAA;AACZ,gBAAA,KAAK,GAAG;oBACN,OAAO,EAAE,CAAA;AACX,gBAAA,KAAK,GAAG;oBACN,OAAO,EAAE,CAAA;AACX,gBAAA,KAAK,GAAG;oBACN,OAAO,IAAI,CAAA;AACb,gBAAA,KAAK,GAAG;oBACN,OAAO,IAAI,CAAA;AACb,gBAAA;;AAEE,oBAAA,OAAO,KAAK;;AAElB,QAAA,CAAC,CAAC;IACJ;AAEA;;;;;;;;;;;;;;;;;AAiBG;IACK,aAAa,CAAC,KAAa,EAAE,SAA+B,EAAA;;;QAGlE,MAAM,QAAQ,GAAG,sDAAsD;QACvE,MAAM,KAAK,GAA2B,EAAE;QACxC,MAAM,QAAQ,GAAkB,EAAE;QAClC,IAAI,SAAS,GAAG,CAAC;AACjB,QAAA,IAAI,YAAY,GAAyB,EAAE,GAAG,SAAS,EAAE;;AAGzD,QAAA,MAAM,UAAU,GAAG,CAAC,IAAY,KAAI;AAClC,YAAA,IAAI,CAAC,IAAI;gBAAE;YACX,QAAQ,CAAC,IAAI,CAAC;gBACZ,IAAI;gBACJ,KAAK,EAAE,YAAY,CAAC,KAAK;gBACzB,MAAM,EAAE,YAAY,CAAC,MAAM;gBAC3B,IAAI,EAAE,YAAY,CAAC,IAAI;gBACvB,CAAC,EAAE,YAAY,CAAC,CAAC;gBACjB,CAAC,EAAE,YAAY,CAAC,CAAC;AAClB,aAAA,CAAC;AACJ,QAAA,CAAC;AAED,QAAA,IAAI,KAA6B;QACjC,QAAQ,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG;AACrC,YAAA,MAAM,GAAG,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,CAAC,GAAG,KAAK;AAC/E,YAAA,MAAM,OAAO,GAAG,UAAU,CAAC,WAAW,EAAE;AACxC,YAAA,MAAM,KAAK,GAAG,UAAU,IAAI,UAAU,IAAI,WAAW;;AAGrD,YAAA,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;AAC/C,YAAA,SAAS,GAAG,QAAQ,CAAC,SAAS;YAE9B,IAAI,CAAC,YAAY,EAAE;;gBAEjB,KAAK,CAAC,IAAI,CAAC,EAAE,GAAG,YAAY,EAAE,CAAC;gBAE/B,QAAQ,OAAO;AACb,oBAAA,KAAK,OAAO;;AAEV,wBAAA,YAAY,CAAC,KAAK,GAAG,KAA6B;wBAClD;AAEF,oBAAA,KAAK,QAAQ;;AAEX,wBAAA,YAAY,CAAC,MAAM,GAAG,KAA8B;wBACpD;AAEF,oBAAA,KAAK,MAAM;;AAET,wBAAA,YAAY,CAAC,IAAI,GAAG,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,SAAS;AACrD,wBAAA,IAAI,KAAK,CAAC,YAAY,CAAC,IAAc,CAAC,EAAE;AACtC,4BAAA,OAAO,CAAC,IAAI,CAAC,CAAA,UAAA,EAAa,IAAI,CAAC,GAAG,IAAI,EAAE,CAAA,sCAAA,EAAyC,KAAK,CAAA,CAAE,CAAC;AACzF,4BAAA,YAAY,CAAC,IAAI,GAAG,SAAS;wBAC/B;wBACA;AAEF,oBAAA,KAAK,GAAG;;AAEN,wBAAA,YAAY,CAAC,CAAC,GAAG,IAAI;wBACrB;AAEF,oBAAA,KAAK,GAAG;;AAEN,wBAAA,YAAY,CAAC,CAAC,GAAG,IAAI;wBACrB;;YAEN;iBAAO;;gBAEL,YAAY,GAAG,KAAK,CAAC,GAAG,EAAE,IAAI,EAAE,GAAG,SAAS,EAAE;YAChD;QACF;;QAGA,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;;AAGlC,QAAA,OAAO,QAAQ;IACjB;AAEQ,IAAA,aAAa,CAAC,KAA4D,EAAA;QAChF,IAAI,OAAO,KAAK,KAAK,QAAQ;YAAE,OAAO,CAAA,EAAG,KAAK,CAAA,EAAA,CAAI;QAClD,OAAO,KAAK,IAAI,QAAQ;IAC1B;IAEQ,gBAAgB,CAAC,YAAyC,EAAE,QAAgB,EAAA;QAClF,IAAI,YAAY,KAAK,SAAS,IAAI,YAAY,KAAK,QAAQ,EAAE;AAC3D,YAAA,OAAO,CAAC;QACV;AACA,QAAA,IAAI,OAAO,YAAY,KAAK,QAAQ,EAAE;YACpC,OAAO,YAAY,CAAA;QACrB;AACA,QAAA,IAAI,OAAO,YAAY,KAAK,QAAQ,EAAE;AACpC,YAAA,MAAM,OAAO,GAAG,YAAY,CAAC,IAAI,EAAE;AACnC,YAAA,IAAI,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE;AAC1B,gBAAA,OAAO,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC;YACjC;AACA,YAAA,IAAI,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE;;gBAE1B,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,QAAQ;YAC9C;;AAEA,YAAA,MAAM,MAAM,GAAG,UAAU,CAAC,OAAO,CAAC;AAClC,YAAA,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE;AAClB,gBAAA,OAAO,MAAM;YACf;QACF;QACA,OAAO,CAAC,CAAA;IACV;AAEA;;;;AAIG;AACK,IAAA,qBAAqB,CAAC,IAAY,EAAE,aAAqB,EAAE,eAAuB,EAAA;QACxF,IAAI,eAAe,KAAK,CAAC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;AAAE,YAAA,OAAO,aAAa;QACpE,MAAM,SAAS,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC,MAAM;QAClC,OAAO,aAAa,IAAI,SAAS,GAAG,CAAC,GAAG,CAAC,SAAS,GAAG,CAAC,IAAI,eAAe,GAAG,CAAC,CAAC;IAChF;AAEA;;;;;;;;;;;AAWG;AACK,IAAA,aAAa,CAAC,YAAmC,EAAA;AACvD,QAAA,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK;AAC5B,QAAA,IAAI,eAA2D;;AAG/D,QAAA,MAAM,cAAc,GAAG,YAAY,EAAE,CAAC,GAAG,QAAQ,GAAG,SAAS,CAAC,SAAS,IAAI,QAAQ;;;;;AAMnF,QAAA,IAAI,YAAY,EAAE,MAAM,EAAE;AACxB,YAAA,eAAe,GAAG,YAAY,CAAC,MAAM;QACvC;AAAO,aAAA,IAAI,YAAY,EAAE,CAAC,EAAE;YAC1B,eAAe,GAAG,MAAM;QAC1B;aAAO;AACL,YAAA,eAAe,GAAG,SAAS,CAAC,UAAU,IAAI,QAAQ;QACpD;;AAGA,QAAA,MAAM,aAAa,GAAG,YAAY,EAAE,IAAI,GAAG,YAAY,CAAC,IAAI,GAAG,SAAS,CAAC,QAAQ,IAAI,EAAE;;AAGvF,QAAA,MAAM,KAAK,GAAG;AACZ,YAAA,SAAS,EAAE,cAAc;AACzB,YAAA,UAAU,EAAE,eAAe;AAC3B,YAAA,QAAQ,EAAE,aAAa;AACvB,YAAA,UAAU,EAAE,SAAS,CAAC,UAAU,IAAI,YAAY;SACjD;AAED,QAAA,OAAO,GAAG,KAAK,CAAC,SAAS,CAAA,CAAA,EAAI,KAAK,CAAC,UAAU,CAAA,CAAA,EAAI,KAAK,CAAC,QAAQ,CAAA,GAAA,EAAM,KAAK,CAAC,UAAU,EAAE;IACzF;AAEA;;AAEG;IACK,yBAAyB,GAAA;AAC/B,QAAA,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ;AACpC,QAAA,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,GAAG,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,QAAQ,EAAE;YAC1E,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC;QACtC;QACA,OAAO,IAAI,CAAC,KAAK;IACnB;AAEA;;;;;;;;;;;;;;AAcG;IACK,WAAW,CAAC,eAAuB,EAAE,SAAsB,EAAA;;AAEjE,QAAA,IAAI,CAAC,QAAQ,CAAC,kBAAkB,EAAE;AAChC,YAAA,QAAQ,CAAC,kBAAkB,GAAG,IAAIC,iBAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC;QACjE;QACA,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,IAAI,EAAE;AAC9C,QAAA,MAAM,GAAG,GAAG,QAAQ,CAAC,kBAAmB;QACxC,GAAG,CAAC,IAAI,EAAE;;AAGV,QAAA,GAAG,CAAC,aAAa,GAAG,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC;AAChE,QAAA,GAAG,CAAC,WAAW,GAAG,QAAQ,CAAA;AAC1B,QAAA,MAAM,mBAAmB,GAAG,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,YAAY,CAAC;AACvF,QAAA,MAAM,qBAAqB,GAAG,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,aAAa,EAAE,YAAY,CAAC;;AAG3F,QAAA,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,QAAQ,EAAE;YACnC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC;YACtC,IAAI,OAAO,IAAI,CAAC,KAAK,CAAC,WAAW,KAAK,QAAQ,EAAE;gBAC9C,GAAG,CAAC,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW;YAC1C;iBAAO,IAAI,IAAI,CAAC,KAAK,CAAC,WAAW,KAAK,SAAS,EAAE;AAC/C,gBAAA,OAAO,CAAC,IAAI,CAAC,CAAA,UAAA,EAAa,IAAI,CAAC,GAAG,IAAI,EAAE,CAAA,+DAAA,CAAiE,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC;AAClI,gBAAA,IAAI,GAAG,CAAC,WAAW,KAAK,QAAQ;AAAE,oBAAA,GAAG,CAAC,WAAW,GAAG,QAAQ;YAC9D;iBAAO;AACL,gBAAA,IAAI,GAAG,CAAC,WAAW,KAAK,QAAQ;AAAE,oBAAA,GAAG,CAAC,WAAW,GAAG,QAAQ;YAC9D;YACA,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC,qBAAqB,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,qBAAqB,CAAC;QACtH;;QAGA,MAAM,wBAAwB,GAAG,SAAS,KAAKC,kBAAK,CAAC,WAAW,CAAC,SAAS,GAAG,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,eAAe,CAAC;AACpH,QAAA,MAAM,OAAO,GAAG,KAAK,CAAA;;QAGrB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,YAAY,CAAC,GAAG,EAAE,IAAI,CAAC,QAAQ,EAAE,wBAAwB,GAAG,OAAO,EAAE,mBAAmB,EAAE,qBAAqB,CAAC;;AAGlI,QAAA,IAAI,CAAC,WAAW,GAAG,EAAE,CAAA;AACrB,QAAA,IAAI,CAAC,WAAW,GAAG,EAAE,CAAA;AACrB,QAAA,IAAI,CAAC,kBAAkB,GAAG,EAAE,CAAA;QAE5B,IAAI,eAAe,GAAG,CAAC;AACvB,QAAA,MAAM,cAAc,GAAG,IAAI,CAAC,yBAAyB,EAAE;AACvD,QAAA,MAAM,QAAQ,GAAG,cAAc,CAAC,MAAM;AACtC,QAAA,MAAM,2BAA2B,GAAG,GAAG,CAAA;;AAGvC,QAAA,KAAK,MAAM,IAAI,IAAI,cAAc,EAAE;YACjC,IAAI,SAAS,GAAG,CAAC;YACjB,IAAI,UAAU,GAAG,CAAC;YAClB,IAAI,iBAAiB,GAAG,CAAC;;AAGzB,YAAA,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE;AACrB,gBAAA,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,aAAa,EAAE;gBAC/B,IAAI,OAAO,IAAI,CAAC,KAAK,CAAC,WAAW,KAAK,QAAQ,EAAE;oBAC9C,GAAG,CAAC,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW;gBAC1C;qBAAO,IAAI,IAAI,CAAC,KAAK,CAAC,WAAW,KAAK,SAAS,EAAE;AAC/C,oBAAA,OAAO,CAAC,IAAI,CAAC,CAAA,UAAA,EAAa,IAAI,CAAC,GAAG,IAAI,EAAE,CAAA,4DAAA,CAA8D,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC;AAC/H,oBAAA,IAAI,GAAG,CAAC,WAAW,KAAK,QAAQ;AAAE,wBAAA,GAAG,CAAC,WAAW,GAAG,QAAQ;gBAC9D;qBAAO;AACL,oBAAA,IAAI,GAAG,CAAC,WAAW,KAAK,QAAQ;AAAE,wBAAA,GAAG,CAAC,WAAW,GAAG,QAAQ;gBAC9D;gBACA,MAAM,OAAO,GAAG,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,aAAa,CAAC;gBACnD,SAAS,GAAG,OAAO,CAAC,uBAAuB,IAAI,YAAY,GAAG,GAAG;gBACjE,UAAU,GAAG,OAAO,CAAC,wBAAwB,IAAI,YAAY,GAAG,GAAG;gBACnE,iBAAiB,GAAG,YAAY;YAClC;iBAAO;;AAEL,gBAAA,KAAK,MAAM,OAAO,IAAI,IAAI,EAAE;AAC1B,oBAAA,IAAI,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;wBAAE;AAEhC,oBAAA,MAAM,WAAW,GAAG,OAAO,CAAC,IAAI,IAAI,YAAY;oBAChD,iBAAiB,GAAG,IAAI,CAAC,GAAG,CAAC,iBAAiB,EAAE,WAAW,CAAC;oBAE5D,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC;oBACtC,IAAI,OAAO,IAAI,CAAC,KAAK,CAAC,WAAW,KAAK,QAAQ,EAAE;wBAC9C,GAAG,CAAC,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW;oBAC1C;yBAAO,IAAI,IAAI,CAAC,KAAK,CAAC,WAAW,KAAK,SAAS,EAAE;AAC/C,wBAAA,OAAO,CAAC,IAAI,CAAC,CAAA,UAAA,EAAa,IAAI,CAAC,GAAG,IAAI,EAAE,CAAA,gEAAA,CAAkE,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC;AACnI,wBAAA,IAAI,GAAG,CAAC,WAAW,KAAK,QAAQ;AAAE,4BAAA,GAAG,CAAC,WAAW,GAAG,QAAQ;oBAC9D;yBAAO;AACL,wBAAA,IAAI,GAAG,CAAC,WAAW,KAAK,QAAQ;AAAE,4BAAA,GAAG,CAAC,WAAW,GAAG,QAAQ;oBAC9D;oBAEA,MAAM,OAAO,GAAG,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,aAAa,CAAC;oBACnD,MAAM,MAAM,GAAG,OAAO,CAAC,uBAAuB,IAAI,WAAW,GAAG,GAAG;oBACnE,MAAM,OAAO,GAAG,OAAO,CAAC,wBAAwB,IAAI,WAAW,GAAG,GAAG;oBAErE,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC;oBACvC,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,OAAO,CAAC;gBAC5C;YACF;;AAGA,YAAA,IAAI,SAAS,KAAK,CAAC,IAAI,UAAU,KAAK,CAAC,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE;AAC1D,gBAAA,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,aAAa,EAAE;gBAC/B,IAAI,OAAO,IAAI,CAAC,KAAK,CAAC,WAAW,KAAK,QAAQ,EAAE;oBAC9C,GAAG,CAAC,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW;gBAC1C;qBAAO,IAAI,IAAI,CAAC,KAAK,CAAC,WAAW,KAAK,SAAS,EAAE;AAC/C,oBAAA,OAAO,CAAC,IAAI,CAAC,CAAA,UAAA,EAAa,IAAI,CAAC,GAAG,IAAI,EAAE,CAAA,0DAAA,CAA4D,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC;AAC7H,oBAAA,IAAI,GAAG,CAAC,WAAW,KAAK,QAAQ;AAAE,wBAAA,GAAG,CAAC,WAAW,GAAG,QAAQ;gBAC9D;qBAAO;AACL,oBAAA,IAAI,GAAG,CAAC,WAAW,KAAK,QAAQ;AAAE,wBAAA,GAAG,CAAC,WAAW,GAAG,QAAQ;gBAC9D;gBACA,MAAM,OAAO,GAAG,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,aAAa,CAAC;gBACnD,SAAS,GAAG,OAAO,CAAC,uBAAuB,IAAI,YAAY,GAAG,GAAG;gBACjE,UAAU,GAAG,OAAO,CAAC,wBAAwB,IAAI,YAAY,GAAG,GAAG;AACnE,gBAAA,iBAAiB,GAAG,iBAAiB,IAAI,YAAY;YACvD;AAEA,YAAA,iBAAiB,GAAG,iBAAiB,IAAI,YAAY;;AAGrD,YAAA,MAAM,mBAAmB,GAAG,SAAS,GAAG,UAAU;;AAGlD,YAAA,MAAM,mBAAmB,GACvB,OAAO,IAAI,CAAC,KAAK,CAAC,UAAU,KAAK,QAAQ,IAAI,IAAI,CAAC,KAAK,CAAC,UAAU,GAAG,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,GAAG,iBAAiB,GAAG,2BAA2B;;YAGlJ,MAAM,eAAe,GAAG,IAAI,CAAC,GAAG,CAAC,mBAAmB,EAAE,mBAAmB,CAAC;;AAG1E,YAAA,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,eAAe,CAAC;AACtC,YAAA,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC;AAChC,YAAA,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,mBAAmB,CAAC;YAEjD,eAAe,IAAI,eAAe;QACpC;;AAGA,QAAA,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO;AACvC,QAAA,MAAM,cAAc,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,QAAQ,GAAG,CAAC,IAAI,YAAY,CAAC;AACjE,QAAA,MAAM,uBAAuB,GAAG,eAAe,GAAG,cAAc;;QAGhE,MAAM,UAAU,GAAG,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC;QAC9C,IAAI,eAAe,GAAG,CAAC;QACvB,IAAI,qBAAqB,GAAG,IAAI;AAChC,QAAA,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,QAAQ,EAAE;AACnC,YAAA,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC;AACzD,YAAA,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE;AACxB,gBAAA,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC;oBAAE;gBACxB,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC;gBACtC,IAAI,OAAO,IAAI,CAAC,KAAK,CAAC,WAAW,KAAK,QAAQ,EAAE;oBAC9C,GAAG,CAAC,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW;gBAC1C;qBAAO,IAAI,IAAI,CAAC,KAAK,CAAC,WAAW,KAAK,SAAS,EAAE;AAC/C,oBAAA,OAAO,CAAC,IAAI,CAAC,CAAA,UAAA,EAAa,IAAI,CAAC,GAAG,IAAI,EAAE,CAAA,mEAAA,CAAqE,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC;AACtI,oBAAA,IAAI,GAAG,CAAC,WAAW,KAAK,QAAQ;AAAE,wBAAA,GAAG,CAAC,WAAW,GAAG,QAAQ;gBAC9D;qBAAO;AACL,oBAAA,IAAI,GAAG,CAAC,WAAW,KAAK,QAAQ;AAAE,wBAAA,GAAG,CAAC,WAAW,GAAG,QAAQ;gBAC9D;AACA,gBAAA,MAAM,SAAS,GAAG,IAAI,CAAC,qBAAqB,CAAC,IAAI,EAAE,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,qBAAqB,CAAC;gBACtG,IAAI,CAAC,qBAAqB,EAAE;AAC1B,oBAAA,eAAe,IAAI,UAAU,GAAG,mBAAmB;gBACrD;gBACA,eAAe,IAAI,SAAS;gBAC5B,qBAAqB,GAAG,KAAK;YAC/B;QACF;;AAGA,QAAA,IAAI,oBAA4B;AAChC,QAAA,IAAI,eAAe,IAAI,wBAAwB,EAAE;YAC/C,oBAAoB,GAAG,eAAe;AACtC,YAAA,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,QAAQ,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE;AAC7G,gBAAA,OAAO,CAAC,IAAI,CACV,CAAA,UAAA,EAAa,IAAI,CAAC,GAAG,IAAI,EAAE,CAAA,wBAAA,EAA2B,eAAe,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA,IAAA,EAAO,wBAAwB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA,4BAAA,EAA+B,cAAc,CAAC,MAAM,CAAA,+EAAA,CAAiF,CAChQ;gBACD,IAAI,mBAAmB,GAAG,CAAC;AAC3B,gBAAA,KAAK,MAAM,IAAI,IAAI,cAAc,EAAE;oBACjC,IAAI,gBAAgB,GAAG,CAAC;oBACxB,IAAI,sBAAsB,GAAG,IAAI;AACjC,oBAAA,KAAK,MAAM,OAAO,IAAI,IAAI,EAAE;AAC1B,wBAAA,MAAM,YAAY,GAAG,OAAO,CAAC,KAAK,IAAI,CAAC;wBACvC,MAAM,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;wBACjD,IAAI,CAAC,cAAc,EAAE;4BACnB,IAAI,CAAC,sBAAsB,EAAE;AAC3B,gCAAA,gBAAgB,IAAI,UAAU,GAAG,mBAAmB;4BACtD;4BACA,gBAAgB,IAAI,YAAY;4BAChC,sBAAsB,GAAG,KAAK;wBAChC;oBACF;oBACA,mBAAmB,GAAG,IAAI,CAAC,GAAG,CAAC,mBAAmB,EAAE,gBAAgB,CAAC;gBACvE;gBACA,oBAAoB,GAAG,IAAI,CAAC,GAAG,CAAC,eAAe,EAAE,mBAAmB,CAAC;YACvE;QACF;aAAO;YACL,IAAI,mBAAmB,GAAG,CAAC;AAC3B,YAAA,KAAK,MAAM,IAAI,IAAI,cAAc,EAAE;gBACjC,IAAI,gBAAgB,GAAG,CAAC;gBACxB,IAAI,sBAAsB,GAAG,IAAI;AACjC,gBAAA,KAAK,MAAM,OAAO,IAAI,IAAI,EAAE;AAC1B,oBAAA,MAAM,YAAY,GAAG,OAAO,CAAC,KAAK,IAAI,CAAC;oBACvC,MAAM,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;oBACjD,IAAI,CAAC,cAAc,EAAE;wBACnB,IAAI,CAAC,sBAAsB,EAAE;AAC3B,4BAAA,gBAAgB,IAAI,UAAU,GAAG,mBAAmB;wBACtD;wBACA,gBAAgB,IAAI,YAAY;wBAChC,sBAAsB,GAAG,KAAK;oBAChC;gBACF;gBACA,mBAAmB,GAAG,IAAI,CAAC,GAAG,CAAC,mBAAmB,EAAE,gBAAgB,CAAC;YACvE;YACA,oBAAoB,GAAG,mBAAmB;QAC5C;;QAGA,IAAI,iBAAiB,GAAG,oBAAoB;AAC5C,QAAA,IAAI,wBAAwB,KAAK,QAAQ,EAAE;YACzC,iBAAiB,GAAG,IAAI,CAAC,GAAG,CAAC,oBAAoB,EAAE,wBAAwB,CAAC;QAC9E;QAEA,GAAG,CAAC,OAAO,EAAE;QACb,OAAO;YACL,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,iBAAiB,CAAC;YACrC,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,uBAAuB,CAAC;SAC7C;IACH;AAEA;;;;;;;;;AASG;IACK,YAAY,CAClB,GAA6B,EAC7B,QAAuB,EACvB,QAAgB,EAChB,mBAA2B,EAC3B,qBAAA,GAAgC,CAAC,EAAA;QAEjC,MAAM,KAAK,GAAoB,EAAE;QAEjC,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,IAAI,QAAQ,IAAI,CAAC;AAAE,YAAA,OAAO,KAAK;QAExD,IAAI,mBAAmB,GAAkB,EAAE;QAC3C,IAAI,gBAAgB,GAAG,CAAC;QACxB,MAAM,UAAU,GAAG,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC;;AAG9C,QAAA,MAAM,YAAY,GAAG,CAAC,UAAU,GAAG,KAAK,KAAI;;YAE1C,IAAI,CAAC,UAAU,EAAE;gBACf,OAAO,mBAAmB,CAAC,MAAM,GAAG,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,mBAAmB,CAAC,mBAAmB,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE;oBAC/G,mBAAmB,CAAC,GAAG,EAAE;gBAC3B;YACF;;AAEA,YAAA,KAAK,CAAC,IAAI,CAAC,mBAAmB,CAAC;YAC/B,mBAAmB,GAAG,EAAE;YACxB,gBAAgB,GAAG,CAAC;AACtB,QAAA,CAAC;AAED,QAAA,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE;;AAE9B,YAAA,MAAM,YAAY,GAAG;gBACnB,KAAK,EAAE,OAAO,CAAC,KAAK;gBACpB,MAAM,EAAE,OAAO,CAAC,MAAM;gBACtB,IAAI,EAAE,OAAO,CAAC,IAAI;gBAClB,CAAC,EAAE,OAAO,CAAC,CAAC;gBACZ,CAAC,EAAE,OAAO,CAAC,CAAC;aACb;;YAGD,IAAI,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE;;gBAE/B,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;AAEtC,gBAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;AACrC,oBAAA,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC;oBACrB,MAAM,UAAU,GAAG,CAAC,KAAK,KAAK,CAAC,MAAM,GAAG,CAAC;AAEzC,oBAAA,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE;;AAEnB,wBAAA,MAAM,cAAc,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC;AAE1D,wBAAA,KAAK,MAAM,WAAW,IAAI,cAAc,EAAE;4BACxC,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC;AACzC,4BAAA,IAAI,WAAwB;AAC5B,4BAAA,IAAI,SAAiB;4BAErB,IAAI,OAAO,EAAE;AACX,gCAAA,WAAW,GAAG,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,YAAY,EAAE,KAAK,EAAE,CAAC,EAAE;gCAC9D,SAAS,GAAG,CAAC;4BACf;iCAAO;gCACL,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,aAAa,CAAC,YAAY,CAAC;AAC3C,gCAAA,IAAI,IAAI,CAAC,KAAK,CAAC,WAAW;oCAAE,GAAG,CAAC,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW;AACpE,gCAAA,SAAS,GAAG,IAAI,CAAC,qBAAqB,CAAC,WAAW,EAAE,GAAG,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC,KAAK,EAAE,qBAAqB,CAAC;AAC9G,gCAAA,WAAW,GAAG,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,YAAY,EAAE,KAAK,EAAE,SAAS,EAAE;4BACxE;4BAEA,MAAM,UAAU,GAAG,mBAAmB,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,mBAAmB,CAAC,mBAAmB,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;AAC5H,4BAAA,MAAM,UAAU,GAAG,UAAU,GAAG,UAAU,GAAG,mBAAmB,GAAG,CAAC;AAEpE,4BAAA,IAAI,gBAAgB,GAAG,UAAU,GAAG,SAAS,IAAI,QAAQ,IAAI,mBAAmB,CAAC,MAAM,KAAK,CAAC,EAAE;gCAC7F,IAAI,UAAU,EAAE;AACd,oCAAA,mBAAmB,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,YAAY,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;oCAClE,gBAAgB,IAAI,UAAU;gCAChC;AACA,gCAAA,mBAAmB,CAAC,IAAI,CAAC,WAAW,CAAC;gCACrC,gBAAgB,IAAI,SAAS;4BAC/B;iCAAO;AACL,gCAAA,IAAI,mBAAmB,CAAC,MAAM,GAAG,CAAC,EAAE;AAClC,oCAAA,YAAY,EAAE;gCAChB;gCAEA,IAAI,CAAC,OAAO,EAAE;oCACZ,IAAI,SAAS,GAAG,QAAQ,IAAI,QAAQ,GAAG,CAAC,EAAE;AACxC,wCAAA,MAAM,WAAW,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,EAAE,WAAW,EAAE,QAAQ,EAAE,qBAAqB,CAAC;AAEzF,wCAAA,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE;AAC1B,4CAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE;gDAC/C,KAAK,CAAC,IAAI,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;4CAC9B;4CACA,mBAAmB,GAAG,CAAC,WAAW,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AAC3D,4CAAA,gBAAgB,GAAG,WAAW,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;wCACnE;6CAAO;AACL,4CAAA,mBAAmB,GAAG,CAAC,WAAW,CAAC;4CACnC,gBAAgB,GAAG,SAAS;wCAC9B;oCACF;yCAAO;AACL,wCAAA,mBAAmB,GAAG,CAAC,WAAW,CAAC;wCACnC,gBAAgB,GAAG,SAAS;oCAC9B;gCACF;4BACF;wBACF;oBACF;;;oBAIA,IAAI,CAAC,UAAU,EAAE;AACf,wBAAA,YAAY,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC;oBACjC;gBACF;YACF;iBAAO;;AAEL,gBAAA,MAAM,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC;AAElE,gBAAA,KAAK,MAAM,WAAW,IAAI,cAAc,EAAE;oBACxC,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC;AACzC,oBAAA,IAAI,WAAwB;AAC5B,oBAAA,IAAI,SAAiB;oBAErB,IAAI,OAAO,EAAE;AACX,wBAAA,WAAW,GAAG,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,YAAY,EAAE,KAAK,EAAE,CAAC,EAAE;wBAC9D,SAAS,GAAG,CAAC;oBACf;yBAAO;wBACL,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,aAAa,CAAC,YAAY,CAAC;AAC3C,wBAAA,IAAI,IAAI,CAAC,KAAK,CAAC,WAAW;4BAAE,GAAG,CAAC,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW;AACpE,wBAAA,SAAS,GAAG,IAAI,CAAC,qBAAqB,CAAC,WAAW,EAAE,GAAG,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC,KAAK,EAAE,qBAAqB,CAAC;AAC9G,wBAAA,WAAW,GAAG,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,YAAY,EAAE,KAAK,EAAE,SAAS,EAAE;oBACxE;oBAEA,MAAM,UAAU,GAAG,mBAAmB,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,mBAAmB,CAAC,mBAAmB,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;AAC5H,oBAAA,MAAM,UAAU,GAAG,UAAU,GAAG,UAAU,GAAG,mBAAmB,GAAG,CAAC;AAEpE,oBAAA,IAAI,gBAAgB,GAAG,UAAU,GAAG,SAAS,IAAI,QAAQ,IAAI,mBAAmB,CAAC,MAAM,KAAK,CAAC,EAAE;wBAC7F,IAAI,UAAU,EAAE;AACd,4BAAA,mBAAmB,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,YAAY,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;4BAClE,gBAAgB,IAAI,UAAU;wBAChC;AACA,wBAAA,mBAAmB,CAAC,IAAI,CAAC,WAAW,CAAC;wBACrC,gBAAgB,IAAI,SAAS;oBAC/B;yBAAO;AACL,wBAAA,IAAI,mBAAmB,CAAC,MAAM,GAAG,CAAC,EAAE;AAClC,4BAAA,YAAY,EAAE;wBAChB;wBAEA,IAAI,CAAC,OAAO,EAAE;4BACZ,IAAI,SAAS,GAAG,QAAQ,IAAI,QAAQ,GAAG,CAAC,EAAE;AACxC,gCAAA,MAAM,WAAW,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,EAAE,WAAW,EAAE,QAAQ,EAAE,qBAAqB,CAAC;AAEzF,gCAAA,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE;AAC1B,oCAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE;wCAC/C,KAAK,CAAC,IAAI,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;oCAC9B;oCACA,mBAAmB,GAAG,CAAC,WAAW,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AAC3D,oCAAA,gBAAgB,GAAG,WAAW,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;gCACnE;qCAAO;AACL,oCAAA,mBAAmB,GAAG,CAAC,WAAW,CAAC;oCACnC,gBAAgB,GAAG,SAAS;gCAC9B;4BACF;iCAAO;AACL,gCAAA,mBAAmB,GAAG,CAAC,WAAW,CAAC;gCACnC,gBAAgB,GAAG,SAAS;4BAC9B;wBACF;oBACF;gBACF;YACF;QACF;AAEA,QAAA,YAAY,EAAE;AACd,QAAA,OAAO,KAAK;IACd;AAEA;;;;;;;AAOG;IACK,aAAa,CAAC,GAA6B,EAAE,cAA2B,EAAE,QAAgB,EAAE,wBAAgC,CAAC,EAAA;AACnI,QAAA,MAAM,IAAI,GAAG,cAAc,CAAC,IAAI;;AAGhC,QAAA,MAAM,KAAK,GAAG;YACZ,KAAK,EAAE,cAAc,CAAC,KAAK;YAC3B,MAAM,EAAE,cAAc,CAAC,MAAM;YAC7B,IAAI,EAAE,cAAc,CAAC,IAAI;YACzB,CAAC,EAAE,cAAc,CAAC,CAAC;YACnB,CAAC,EAAE,cAAc,CAAC,CAAC;SACpB;QAED,IAAI,QAAQ,IAAI,CAAC;YAAE,OAAO,CAAC,cAAc,CAAC;QAE1C,MAAM,cAAc,GAAkB,EAAE;QACxC,IAAI,eAAe,GAAG,EAAE;;QAGxB,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC;AACpC,QAAA,IAAI,IAAI,CAAC,KAAK,CAAC,WAAW;YAAE,GAAG,CAAC,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW;;AAGpE,QAAA,KAAK,MAAM,IAAI,IAAI,IAAI,EAAE;AACvB,YAAA,MAAM,YAAY,GAAG,eAAe,GAAG,IAAI;AAC3C,YAAA,MAAM,aAAa,GAAG,IAAI,CAAC,qBAAqB,CAAC,YAAY,EAAE,GAAG,CAAC,WAAW,CAAC,YAAY,CAAC,CAAC,KAAK,EAAE,qBAAqB,CAAC;AAE1H,YAAA,IAAI,aAAa,GAAG,QAAQ,EAAE;;gBAE5B,IAAI,eAAe,EAAE;oBACnB,cAAc,CAAC,IAAI,CAAC;AAClB,wBAAA,IAAI,EAAE,eAAe;AACrB,wBAAA,GAAG,KAAK;AACR,wBAAA,KAAK,EAAE,IAAI,CAAC,qBAAqB,CAAC,eAAe,EAAE,GAAG,CAAC,WAAW,CAAC,eAAe,CAAC,CAAC,KAAK,EAAE,qBAAqB,CAAC;AAClH,qBAAA,CAAC;gBACJ;;gBAGA,eAAe,GAAG,IAAI;gBACtB,MAAM,gBAAgB,GAAG,GAAG,CAAC,WAAW,CAAC,eAAe,CAAC,CAAC,KAAK;AAE/D,gBAAA,IAAI,gBAAgB,GAAG,QAAQ,EAAE;;oBAE/B,cAAc,CAAC,IAAI,CAAC;AAClB,wBAAA,IAAI,EAAE,eAAe;AACrB,wBAAA,GAAG,KAAK;AACR,wBAAA,KAAK,EAAE,gBAAgB;AACxB,qBAAA,CAAC;oBACF,eAAe,GAAG,EAAE;gBACtB;YACF;iBAAO;;gBAEL,eAAe,GAAG,YAAY;YAChC;QACF;;QAGA,IAAI,eAAe,EAAE;YACnB,cAAc,CAAC,IAAI,CAAC;AAClB,gBAAA,IAAI,EAAE,eAAe;AACrB,gBAAA,GAAG,KAAK;AACR,gBAAA,KAAK,EAAE,IAAI,CAAC,qBAAqB,CAAC,eAAe,EAAE,GAAG,CAAC,WAAW,CAAC,eAAe,CAAC,CAAC,KAAK,EAAE,qBAAqB,CAAC;AAClH,aAAA,CAAC;QACJ;AAEA,QAAA,OAAO,cAAc,CAAC,MAAM,GAAG,CAAC,GAAG,cAAc,GAAG,CAAC,cAAc,CAAC;IACtE;AAEA;;AAEG;AACK,IAAA,iBAAiB,CAAC,GAA6B,EAAA;AACrD,QAAA,MAAM,YAAY,GAAG,GAAG,CAAC,IAAI;AAC7B,QAAA,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,aAAa,EAAE;QAC/B,MAAM,KAAK,GAAG,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,KAAK;AACxC,QAAA,GAAG,CAAC,IAAI,GAAG,YAAY;QACvB,OAAO,KAAK,GAAG,CAAC,GAAG,KAAK,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,IAAI,EAAE,IAAI,GAAG;IAC9D;AAEA;;;;;;;;;;;;;;;;AAgBG;IACgB,cAAc,CAAC,GAA6B,EAAE,CAAS,EAAE,CAAS,EAAE,KAAa,EAAE,MAAc,EAAA;AAClH,QAAA,KAAK,CAAC,cAAc,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC;QAE9C,GAAG,CAAC,IAAI,EAAE;AACV,QAAA,GAAG,CAAC,YAAY,GAAG,YAAY;AAC/B,QAAA,GAAG,CAAC,aAAa,GAAG,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC;AAChE,QAAA,GAAG,CAAC,WAAW,GAAG,QAAQ;QAE1B,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,IAAI,EAAE;AAC9C,QAAA,MAAM,mBAAmB,GAAG,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,YAAY,CAAC;;AAGvF,QAAA,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAACA,kBAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;AACtE,QAAA,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAACA,kBAAK,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;AACpE,QAAA,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAACA,kBAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;AACxE,QAAA,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAACA,kBAAK,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC;AAC1E,QAAA,MAAM,QAAQ,GAAG,CAAC,GAAG,WAAW;AAChC,QAAA,MAAM,QAAQ,GAAG,CAAC,GAAG,UAAU;AAC/B,QAAA,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,GAAG,WAAW,GAAG,YAAY,CAAC;AACpE,QAAA,MAAM,aAAa,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,GAAG,UAAU,GAAG,aAAa,CAAC;QAEtE,IAAI,YAAY,IAAI,CAAC,IAAI,aAAa,IAAI,CAAC,EAAE;YAC3C,GAAG,CAAC,OAAO,EAAE;YACb;QACF;;;;QAKA,MAAM,UAAU,GAAG,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC;;QAE9C,MAAM,OAAO,GAAG,IAAI;AACpB,QAAA,MAAM,qBAAqB,GAAG,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,aAAa,EAAE,YAAY,CAAC;QAC3F,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,CAAC,GAAG,EAAE,IAAI,CAAC,QAAQ,EAAE,YAAY,GAAG,OAAO,EAAE,mBAAmB,EAAE,qBAAqB,CAAC;QAE1H,MAAM,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,IAAI,IAAI,CAAC,KAAK,CAAC,QAAQ,KAAK,SAAS,IAAI,QAAQ,CAAC,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ;;AAGvH,QAAA,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,KAAK,SAAS,IAAI,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,QAAQ;AAErI,QAAA,MAAM,gBAAgB,GAAG,YAAY,CAAC,MAAM;;;QAI5C,MAAM,WAAW,GAAa,EAAE;QAChC,MAAM,WAAW,GAAa,EAAE;QAChC,MAAM,kBAAkB,GAAa,EAAE;QACvC,MAAM,2BAA2B,GAAG,GAAG;QACvC,IAAI,eAAe,GAAG,CAAC;AAEvB,QAAA,KAAK,MAAM,IAAI,IAAI,YAAY,EAAE;YAC/B,IAAI,SAAS,GAAG,CAAC;YACjB,IAAI,UAAU,GAAG,CAAC;YAClB,IAAI,iBAAiB,GAAG,CAAC;AAEzB,YAAA,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE;AACrB,gBAAA,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,aAAa,EAAE;AAC/B,gBAAA,IAAI,IAAI,CAAC,KAAK,CAAC,WAAW;oBAAE,GAAG,CAAC,WAAW,GAAG,OAAO,IAAI,CAAC,KAAK,CAAC,WAAW,KAAK,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,GAAG,QAAQ;gBAC5H,MAAM,OAAO,GAAG,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,aAAa,CAAC;gBACnD,SAAS,GAAG,OAAO,CAAC,uBAAuB,IAAI,YAAY,GAAG,GAAG;gBACjE,UAAU,GAAG,OAAO,CAAC,wBAAwB,IAAI,YAAY,GAAG,GAAG;gBACnE,iBAAiB,GAAG,YAAY;YAClC;iBAAO;AACL,gBAAA,KAAK,MAAM,OAAO,IAAI,IAAI,EAAE;AAC1B,oBAAA,IAAI,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;wBAAE;AAChC,oBAAA,MAAM,WAAW,GAAG,OAAO,CAAC,IAAI,IAAI,YAAY;oBAChD,iBAAiB,GAAG,IAAI,CAAC,GAAG,CAAC,iBAAiB,EAAE,WAAW,CAAC;;oBAG5D,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC;AACtC,oBAAA,IAAI,IAAI,CAAC,KAAK,CAAC,WAAW;wBAAE,GAAG,CAAC,WAAW,GAAG,OAAO,IAAI,CAAC,KAAK,CAAC,WAAW,KAAK,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,GAAG,QAAQ;oBAE5H,MAAM,OAAO,GAAG,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,aAAa,CAAC;oBACnD,MAAM,MAAM,GAAG,OAAO,CAAC,uBAAuB,IAAI,WAAW,GAAG,GAAG;oBACnE,MAAM,OAAO,GAAG,OAAO,CAAC,wBAAwB,IAAI,WAAW,GAAG,GAAG;oBACrE,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC;oBACvC,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,OAAO,CAAC;gBAC5C;YACF;AACA,YAAA,IAAI,SAAS,KAAK,CAAC,IAAI,UAAU,KAAK,CAAC,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE;;AAE1D,gBAAA,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,aAAa,EAAE;AAC/B,gBAAA,IAAI,IAAI,CAAC,KAAK,CAAC,WAAW;oBAAE,GAAG,CAAC,WAAW,GAAG,OAAO,IAAI,CAAC,KAAK,CAAC,WAAW,KAAK,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,GAAG,QAAQ;gBAC5H,MAAM,OAAO,GAAG,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,aAAa,CAAC;gBACnD,SAAS,GAAG,OAAO,CAAC,uBAAuB,IAAI,YAAY,GAAG,GAAG;gBACjE,UAAU,GAAG,OAAO,CAAC,wBAAwB,IAAI,YAAY,GAAG,GAAG;AACnE,gBAAA,iBAAiB,GAAG,iBAAiB,IAAI,YAAY;YACvD;AACA,YAAA,iBAAiB,GAAG,iBAAiB,IAAI,YAAY;AACrD,YAAA,MAAM,mBAAmB,GAAG,SAAS,GAAG,UAAU;AAClD,YAAA,MAAM,mBAAmB,GACvB,OAAO,IAAI,CAAC,KAAK,CAAC,UAAU,KAAK,QAAQ,IAAI,IAAI,CAAC,KAAK,CAAC,UAAU,GAAG,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,GAAG,iBAAiB,GAAG,2BAA2B;YAClJ,MAAM,eAAe,GAAG,IAAI,CAAC,GAAG,CAAC,mBAAmB,EAAE,mBAAmB,CAAC;AAE1E,YAAA,WAAW,CAAC,IAAI,CAAC,eAAe,CAAC;AACjC,YAAA,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC;AAC3B,YAAA,kBAAkB,CAAC,IAAI,CAAC,mBAAmB,CAAC;YAC5C,eAAe,IAAI,eAAe;QACpC;AAEA,QAAA,IAAI,gBAAgB,KAAK,CAAC,EAAE;YAC1B,GAAG,CAAC,OAAO,EAAE;YACb;QACF;;AAGA,QAAA,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO;AACvC,QAAA,MAAM,yBAAyB,GAAG,eAAe,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,gBAAgB,GAAG,CAAC,CAAC,GAAG,YAAY;AAEpG,QAAA,IAAI,WAAmB;AACvB,QAAA,QAAQ,IAAI,CAAC,KAAK,CAAC,aAAa;AAC9B,YAAA,KAAK,QAAQ;gBACX,WAAW,GAAG,QAAQ,GAAG,CAAC,aAAa,GAAG,yBAAyB,IAAI,CAAC;gBACxE;AACF,YAAA,KAAK,QAAQ;AACX,gBAAA,WAAW,GAAG,QAAQ,GAAG,aAAa,GAAG,yBAAyB;gBAClE;AACF,YAAA,KAAK,KAAK;AACV,YAAA;gBACE,WAAW,GAAG,QAAQ;;QAG1B,IAAI,eAAe,GAAG,WAAW;;QAGjC,GAAG,CAAC,SAAS,EAAE;QACf,GAAG,CAAC,IAAI,CAAC,QAAQ,EAAE,QAAQ,EAAE,YAAY,EAAE,aAAa,CAAC;QACzD,GAAG,CAAC,IAAI,EAAE;;QAGV,MAAM,YAAY,GAAG,OAAO,IAAI,CAAC,KAAK,CAAC,QAAQ,KAAK,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,KAAK;QAC1F,IAAI,aAAa,GAAG,CAAC;QACrB,IAAI,aAAa,GAAqC,SAAS;QAE/D,IAAI,aAAa,EAAE;YACjB,MAAM,gBAAgB,GAAG,YAAY,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC;;YAE9D,MAAM,oBAAoB,GAAG,CAAC,GAAG,gBAAgB,CAAC,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AACjG,YAAA,aAAa,GAAG;AACd,kBAAE;oBACE,KAAK,EAAE,oBAAoB,CAAC,KAAK;oBACjC,MAAM,EAAE,oBAAoB,CAAC,MAAM;oBACnC,IAAI,EAAE,oBAAoB,CAAC,IAAI;oBAC/B,CAAC,EAAE,oBAAoB,CAAC,CAAC;oBACzB,CAAC,EAAE,oBAAoB,CAAC,CAAC;AAC1B;kBACD,SAAS;YAEb,GAAG,CAAC,IAAI,EAAE;YACV,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,aAAa,CAAC,aAAa,CAAC;AAC5C,YAAA,IAAI,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE;gBAC1B,GAAG,CAAC,WAAW,GAAG,OAAO,IAAI,CAAC,KAAK,CAAC,WAAW,KAAK,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,GAAG,QAAQ;YAClG;YACA,aAAa,GAAG,GAAG,CAAC,WAAW,CAAC,YAAY,CAAC,CAAC,KAAK;YACnD,GAAG,CAAC,OAAO,EAAE;QACf;;AAGA,QAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,gBAAgB,EAAE,CAAC,EAAE,EAAE;AACzC,YAAA,MAAM,YAAY,GAAG,YAAY,CAAC,CAAC,CAAC;AACpC,YAAA,MAAM,sBAAsB,GAAG,WAAW,CAAC,CAAC,CAAC;AAC7C,YAAA,MAAM,oBAAoB,GAAG,WAAW,CAAC,CAAC,CAAC;AAC3C,YAAA,MAAM,wBAAwB,GAAG,kBAAkB,CAAC,CAAC,CAAC;;AAGtD,YAAA,MAAM,kBAAkB,GAAG,sBAAsB,GAAG,wBAAwB;AAC5E,YAAA,MAAM,qBAAqB,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,kBAAkB,GAAG,CAAC,CAAC;AACjE,YAAA,MAAM,KAAK,GAAG,eAAe,GAAG,qBAAqB,GAAG,oBAAoB;;YAG5E,MAAM,OAAO,GAAG,eAAe;AAC/B,YAAA,MAAM,UAAU,GAAG,eAAe,GAAG,sBAAsB;;;YAI3D,IAAI,UAAU,IAAI,QAAQ,IAAI,OAAO,IAAI,QAAQ,GAAG,aAAa,EAAE;AACjE,gBAAA,eAAe,IAAI,sBAAsB,GAAG,YAAY;gBACxD;YACF;AAEA,YAAA,MAAM,kBAAkB,GAAG,CAAC,KAAK,gBAAgB,GAAG,CAAC;;YAGrD,IAAI,cAAc,GAAG,CAAC;YACtB,IAAI,eAAe,GAAG,CAAC;YACvB,IAAI,WAAW,GAAG,CAAC;YACnB,IAAI,eAAe,GAAG,IAAI;YAC1B,MAAM,wBAAwB,GAAG,eAAe;AAEhD,YAAA,KAAK,MAAM,OAAO,IAAI,YAAY,EAAE;AAClC,gBAAA,MAAM,YAAY,GAAG,OAAO,CAAC,KAAK,IAAI,CAAC;gBACvC,MAAM,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;gBAEjD,IAAI,CAAC,cAAc,EAAE;oBACnB,IAAI,CAAC,eAAe,EAAE;AACpB,wBAAA,cAAc,IAAI,UAAU,GAAG,mBAAmB;wBAClD,IAAI,CAAC,wBAAwB,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE;AAChD,4BAAA,WAAW,EAAE;wBACf;oBACF;oBACA,cAAc,IAAI,YAAY;oBAC9B,eAAe,IAAI,YAAY;oBAC/B,eAAe,GAAG,KAAK;gBACzB;YACF;;AAGA,YAAA,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,KAAK,SAAS,IAAI,CAAC,kBAAkB;AAC3E,YAAA,MAAM,aAAa,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,IAAI,MAAM;AACzE,YAAA,IAAI,QAAgB;YAEpB,QAAQ,aAAa;AACnB,gBAAA,KAAK,QAAQ;oBACX,QAAQ,GAAG,QAAQ,GAAG,CAAC,YAAY,GAAG,cAAc,IAAI,CAAC;oBACzD;AACF,gBAAA,KAAK,OAAO;AACZ,gBAAA,KAAK,KAAK;AACR,oBAAA,QAAQ,GAAG,QAAQ,GAAG,YAAY,GAAG,cAAc;oBACnD;AACF,gBAAA,KAAK,MAAM;AACX,gBAAA,KAAK,OAAO;AACZ,gBAAA;oBACE,QAAQ,GAAG,QAAQ;;YAEvB,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,QAAQ,CAAC;;AAGvC,YAAA,IAAI,0BAA0B,GAAG,UAAU,GAAG,mBAAmB;YACjE,IAAI,SAAS,IAAI,WAAW,GAAG,CAAC,IAAI,cAAc,GAAG,YAAY,EAAE;gBACjE,MAAM,qBAAqB,GAAG,WAAW,IAAI,UAAU,GAAG,mBAAmB,CAAC;AAC9E,gBAAA,MAAM,cAAc,GAAG,YAAY,GAAG,eAAe,GAAG,qBAAqB;AAC7E,gBAAA,IAAI,cAAc,GAAG,CAAC,EAAE;AACtB,oBAAA,0BAA0B,IAAI,cAAc,GAAG,WAAW;gBAC5D;YACF;;YAGA,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE;gBAC7E,IAAI,gBAAgB,GAAG,CAAC;gBACxB,IAAI,eAAe,GAAG,KAAK;gBAC3B,IAAI,cAAc,GAAG,KAAK;AAE1B,gBAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,YAAY,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;AAC5C,oBAAA,MAAM,OAAO,GAAG,YAAY,CAAC,CAAC,CAAC;AAC/B,oBAAA,MAAM,YAAY,GAAG,OAAO,CAAC,KAAK,IAAI,CAAC;oBACvC,MAAM,mBAAmB,GAAG,CAAC,KAAK,YAAY,CAAC,MAAM,GAAG,CAAC;oBACzD,MAAM,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;;oBAGjD,IAAI,gBAAgB,GAAG,CAAC;AACxB,oBAAA,IAAI,CAAC,cAAc,IAAI,cAAc,IAAI,CAAC,wBAAwB,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE;AACrF,wBAAA,gBAAgB,GAAG,SAAS,GAAG,0BAA0B,GAAG,UAAU,GAAG,mBAAmB;oBAC9F;;oBAGA,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC;AACtC,oBAAA,GAAG,CAAC,SAAS,GAAG,OAAO,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,IAAI,OAAO;oBAE5D,IAAI,OAAO,IAAI,CAAC,KAAK,CAAC,WAAW,KAAK,QAAQ,EAAE;wBAC9C,GAAG,CAAC,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW;oBAC1C;yBAAO,IAAI,IAAI,CAAC,KAAK,CAAC,WAAW,KAAK,SAAS,EAAE;AAC/C,wBAAA,OAAO,CAAC,IAAI,CAAC,CAAA,UAAA,EAAa,IAAI,CAAC,GAAG,IAAI,EAAE,CAAA,mEAAA,CAAqE,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC;AACtI,wBAAA,IAAI,GAAG,CAAC,WAAW,KAAK,QAAQ;AAAE,4BAAA,GAAG,CAAC,WAAW,GAAG,QAAQ;oBAC9D;yBAAO;AACL,wBAAA,IAAI,GAAG,CAAC,WAAW,KAAK,QAAQ;AAAE,4BAAA,GAAG,CAAC,WAAW,GAAG,QAAQ;oBAC9D;;AAGA,oBAAA,IAAI,UAAU,GAAG,OAAO,CAAC,IAAI;oBAC7B,IAAI,yBAAyB,GAAG,YAAY;oBAC5C,IAAI,kBAAkB,GAAG,KAAK;AAE9B,oBAAA,IAAI,kBAAkB,IAAI,aAAa,IAAI,CAAC,cAAc,EAAE;AAC1D,wBAAA,MAAM,iBAAiB,GAAG,gBAAgB,GAAG,gBAAgB,GAAG,YAAY;wBAC5E,MAAM,gBAAgB,GAAG,mBAAmB,GAAG,CAAC,GAAG,SAAS,GAAG,0BAA0B,GAAG,UAAU,GAAG,mBAAmB;AAE5H,wBAAA,IAAI,iBAAiB,GAAG,YAAY,GAAG,gBAAgB,EAAE;4BACvD,MAAM,wBAAwB,GAAG,YAAY,GAAG,gBAAgB,GAAG,gBAAgB,GAAG,aAAa;AACnG,4BAAA,IAAI,wBAAwB,GAAG,CAAC,EAAE;gCAChC,IAAI,aAAa,GAAG,EAAE;AACtB,gCAAA,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,IAAI,EAAE;AAC/B,oCAAA,IAAI,GAAG,CAAC,WAAW,CAAC,aAAa,GAAG,IAAI,CAAC,CAAC,KAAK,IAAI,wBAAwB,EAAE;wCAC3E,aAAa,IAAI,IAAI;oCACvB;yCAAO;wCACL;oCACF;gCACF;gCACA,UAAU,GAAG,aAAa;gCAC1B,yBAAyB,GAAG,GAAG,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC,KAAK;4BAC/D;iCAAO;gCACL,UAAU,GAAG,EAAE;gCACf,yBAAyB,GAAG,CAAC;4BAC/B;4BACA,kBAAkB,GAAG,IAAI;4BACzB,eAAe,GAAG,IAAI;wBACxB;6BAAO,IAAI,mBAAmB,EAAE;4BAC9B,kBAAkB,GAAG,IAAI;4BACzB,eAAe,GAAG,IAAI;wBACxB;oBACF;;oBAGA,QAAQ,IAAI,gBAAgB;oBAC5B,gBAAgB,IAAI,gBAAgB;AAEpC,oBAAA,MAAM,oBAAoB,GAAG,QAAQ,GAAG,YAAY,GAAG,QAAQ;oBAC/D,IAAI,yBAAyB,GAAG,CAAC,IAAI,oBAAoB,GAAG,CAAC,IAAI,CAAC,cAAc,EAAE;AAChF,wBAAA,GAAG,CAAC,SAAS,GAAG,MAAM;wBAEtB,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,EAAE;wBAErI,GAAG,CAAC,IAAI,EAAE;;AAGV,wBAAA,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE;4BAC5B,GAAG,CAAC,WAAW,GAAG,MAAM,CAAC,KAAK,IAAI,aAAa;4BAC/C,GAAG,CAAC,UAAU,GAAG,MAAM,CAAC,IAAI,IAAI,CAAC;4BACjC,GAAG,CAAC,aAAa,GAAG,MAAM,CAAC,OAAO,IAAI,CAAC;4BACvC,GAAG,CAAC,aAAa,GAAG,MAAM,CAAC,OAAO,IAAI,CAAC;4BACvC,GAAG,CAAC,QAAQ,CAAC,UAAU,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,oBAAoB,GAAG,CAAC,CAAC,CAAC;wBAClF;;AAGA,wBAAA,GAAG,CAAC,WAAW,GAAG,aAAa;AAC/B,wBAAA,GAAG,CAAC,UAAU,GAAG,CAAC;AAClB,wBAAA,GAAG,CAAC,aAAa,GAAG,CAAC;AACrB,wBAAA,GAAG,CAAC,aAAa,GAAG,CAAC;wBAErB,GAAG,CAAC,QAAQ,CAAC,UAAU,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,oBAAoB,GAAG,CAAC,CAAC,CAAC;wBAEhF,GAAG,CAAC,OAAO,EAAE;wBAEb,cAAc,GAAG,IAAI;oBACvB;oBAEA,QAAQ,IAAI,yBAAyB;oBACrC,gBAAgB,IAAI,yBAAyB;;oBAG7C,IAAI,kBAAkB,EAAE;AACtB,wBAAA,MAAM,sBAAsB,GAAG,QAAQ,GAAG,YAAY,GAAG,QAAQ;AACjE,wBAAA,IAAI,sBAAsB,IAAI,aAAa,EAAE;4BAC3C,GAAG,CAAC,IAAI,EAAE;4BACV,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,aAAa,CAAC,aAAa,CAAC;4BAE5C,IAAI,OAAO,IAAI,CAAC,KAAK,CAAC,WAAW,KAAK,QAAQ,EAAE;gCAC9C,GAAG,CAAC,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW;4BAC1C;iCAAO,IAAI,IAAI,CAAC,KAAK,CAAC,WAAW,KAAK,SAAS,EAAE;AAC/C,gCAAA,OAAO,CAAC,IAAI,CAAC,CAAA,UAAA,EAAa,IAAI,CAAC,GAAG,IAAI,EAAE,CAAA,kEAAA,CAAoE,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC;AACrI,gCAAA,IAAI,GAAG,CAAC,WAAW,KAAK,QAAQ;AAAE,oCAAA,GAAG,CAAC,WAAW,GAAG,QAAQ;4BAC9D;iCAAO;AACL,gCAAA,IAAI,GAAG,CAAC,WAAW,KAAK,QAAQ;AAAE,oCAAA,GAAG,CAAC,WAAW,GAAG,QAAQ;4BAC9D;AAEA,4BAAA,GAAG,CAAC,SAAS,GAAG,aAAa,EAAE,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,IAAI,OAAO;4BACnE,GAAG,CAAC,QAAQ,CAAC,YAAY,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,sBAAsB,GAAG,CAAC,CAAC,CAAC;4BACpF,GAAG,CAAC,OAAO,EAAE;wBACf;wBACA;oBACF;AAEA,oBAAA,IAAI,eAAe,IAAI,QAAQ,IAAI,QAAQ,GAAG,YAAY;wBAAE;gBAC9D;YACF;AAEA,YAAA,eAAe,IAAI,sBAAsB,GAAG,YAAY;QAC1D;QAEA,GAAG,CAAC,OAAO,EAAE;IACf;;AAGF;;AAEG;AACI,MAAM,IAAI,GAAG,CAAC,IAAqB,EAAE,KAAiB,KAAK,IAAI,QAAQ,CAAC,IAAI,EAAE,KAAK;;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grid.canvas.util.d.ts","sourceRoot":"","sources":["../../../src/canvas/grid.canvas.util.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAiB,aAAa,EAAE,MAAM,yBAAyB,CAAA;AACtF,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,gCAAgC,CAAA;AAIjE;;;;GAIG;AACH,qBAAa,YAAa,SAAQ,OAAO;gBAC3B,KAAK,EAAE,aAAa;CAMjC;AAED;;GAEG;AACH,eAAO,MAAM,QAAQ,GAAI,OAAO,aAAa,iBAA4B,CAAA;AAEzE;;;GAGG;AACH,qBAAa,QAAS,SAAQ,OAAO;IACnC;;;OAGG;gBACS,KAAK,EAAE,SAAS;IAQ5B;;OAEG;IACH,OAAO,CAAC,UAAU;IAqBlB;;OAEG;IACH,OAAO,CAAC,YAAY;IAmBpB;;OAEG;cACgB,+BAA+B;
|
|
1
|
+
{"version":3,"file":"grid.canvas.util.d.ts","sourceRoot":"","sources":["../../../src/canvas/grid.canvas.util.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAiB,aAAa,EAAE,MAAM,yBAAyB,CAAA;AACtF,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,gCAAgC,CAAA;AAIjE;;;;GAIG;AACH,qBAAa,YAAa,SAAQ,OAAO;gBAC3B,KAAK,EAAE,aAAa;CAMjC;AAED;;GAEG;AACH,eAAO,MAAM,QAAQ,GAAI,OAAO,aAAa,iBAA4B,CAAA;AAEzE;;;GAGG;AACH,qBAAa,QAAS,SAAQ,OAAO;IACnC;;;OAGG;gBACS,KAAK,EAAE,SAAS;IAQ5B;;OAEG;IACH,OAAO,CAAC,UAAU;IAqBlB;;OAEG;IACH,OAAO,CAAC,YAAY;IAmBpB;;OAEG;cACgB,+BAA+B;IAsSlD;;OAEG;IACH,OAAO,CAAC,aAAa;CAkCtB;AAED;;GAEG;AACH,eAAO,MAAM,IAAI,GAAI,OAAO,SAAS,aAAwB,CAAA"}
|
|
@@ -68,7 +68,20 @@ class GridNode extends RowNode {
|
|
|
68
68
|
*/
|
|
69
69
|
updateLayoutBasedOnComputedSize() {
|
|
70
70
|
// 1. Get Container Dimensions
|
|
71
|
-
|
|
71
|
+
let width = this.node.getComputedWidth();
|
|
72
|
+
// When parent has minWidth (percentage), the computed width may grow beyond
|
|
73
|
+
// the intended minWidth to fit content. Constrain to minWidth if it's a percentage.
|
|
74
|
+
const minWidth = this.node.getMinWidth();
|
|
75
|
+
if (minWidth.unit === Style.Unit.Percent && this.node.getParent()) {
|
|
76
|
+
const parentWidth = this.node.getParent().getComputedWidth();
|
|
77
|
+
if (!isNaN(parentWidth) && parentWidth > 0) {
|
|
78
|
+
const intendedMinWidth = (minWidth.value / 100) * parentWidth;
|
|
79
|
+
// Constrain width to the intended minWidth percentage
|
|
80
|
+
if (width > intendedMinWidth) {
|
|
81
|
+
width = intendedMinWidth;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
72
85
|
const paddingLeft = this.node.getComputedPadding(Style.Edge.Left);
|
|
73
86
|
const paddingRight = this.node.getComputedPadding(Style.Edge.Right);
|
|
74
87
|
const paddingTop = this.node.getComputedPadding(Style.Edge.Top);
|
|
@@ -76,6 +76,12 @@ export declare class TextNode extends BoxNode {
|
|
|
76
76
|
private parseRichText;
|
|
77
77
|
private formatSpacing;
|
|
78
78
|
private parseSpacingToPx;
|
|
79
|
+
/**
|
|
80
|
+
* Adds manual letter spacing compensation to a measured text width.
|
|
81
|
+
* Needed because skia-canvas ctx.measureText() does not include letterSpacing in the returned width,
|
|
82
|
+
* even though letterSpacing IS applied during rendering (fillText/strokeText).
|
|
83
|
+
*/
|
|
84
|
+
private addLetterSpacingExtra;
|
|
79
85
|
/**
|
|
80
86
|
* Generates a CSS font string by combining base TextProps with optional TextSegment styling.
|
|
81
87
|
* Follows browser font string format: "font-style font-weight font-size font-family"
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"text.canvas.util.d.ts","sourceRoot":"","sources":["../../../src/canvas/text.canvas.util.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAe,MAAM,yBAAyB,CAAA;AACrE,OAAO,EAAU,KAAK,wBAAwB,EAA2B,MAAM,aAAa,CAAA;AAC5F,OAAO,EAAE,OAAO,EAAE,MAAM,gCAAgC,CAAA;AAGxD;;;GAGG;AACH,qBAAa,QAAS,SAAQ,OAAO;IACnC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAoB;IAC7C,OAAO,CAAC,KAAK,CAAsB;IACnC,OAAO,CAAC,MAAM,CAAC,kBAAkB,CAAwC;IACzE,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAU;IACxC,OAAO,CAAC,WAAW,CAAe;IAClC,OAAO,CAAC,WAAW,CAAe;IAClC,OAAO,CAAC,kBAAkB,CAAe;IAEjC,KAAK,EAAE,SAAS,GAAG;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAA;gBAElC,IAAI,GAAE,MAAM,GAAG,MAAW,EAAE,KAAK,GAAE,SAAc;IAuB7D;;;;;;;;OAQG;WACW,gBAAgB,CAC5B,GAAG,EAAE,wBAAwB,EAC7B,IAAI,EAAE,MAAM,EACZ,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,KAAK,GAAE;QACL,UAAU,CAAC,EAAE,MAAM,CAAA;QACnB,QAAQ,CAAC,EAAE,MAAM,CAAA;QACjB,UAAU,CAAC,EAAE,SAAS,CAAC,YAAY,CAAC,CAAA;QACpC,SAAS,CAAC,EAAE,SAAS,CAAC,WAAW,CAAC,CAAA;QAClC,KAAK,CAAC,EAAE,MAAM,CAAA;QACd,SAAS,CAAC,EAAE,wBAAwB,CAAC,WAAW,CAAC,CAAA;QACjD,YAAY,CAAC,EAAE,wBAAwB,CAAC,cAAc,CAAC,CAAA;KACnD;cAwBW,aAAa,IAAI,IAAI;IAoDxC;;;;;;;;;;;;;;;;;OAiBG;IACH,OAAO,CAAC,sBAAsB;IA8B9B;;;;;;;;;;;;;;;;;OAiBG;IACH,OAAO,CAAC,aAAa;IA+ErB,OAAO,CAAC,aAAa;IAKrB,OAAO,CAAC,gBAAgB;IAyBxB;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,aAAa;IAiCrB;;OAEG;IACH,OAAO,CAAC,yBAAyB;IAQjC;;;;;;;;;;;;;;OAcG;IACH,OAAO,CAAC,WAAW;
|
|
1
|
+
{"version":3,"file":"text.canvas.util.d.ts","sourceRoot":"","sources":["../../../src/canvas/text.canvas.util.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAe,MAAM,yBAAyB,CAAA;AACrE,OAAO,EAAU,KAAK,wBAAwB,EAA2B,MAAM,aAAa,CAAA;AAC5F,OAAO,EAAE,OAAO,EAAE,MAAM,gCAAgC,CAAA;AAGxD;;;GAGG;AACH,qBAAa,QAAS,SAAQ,OAAO;IACnC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAoB;IAC7C,OAAO,CAAC,KAAK,CAAsB;IACnC,OAAO,CAAC,MAAM,CAAC,kBAAkB,CAAwC;IACzE,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAU;IACxC,OAAO,CAAC,WAAW,CAAe;IAClC,OAAO,CAAC,WAAW,CAAe;IAClC,OAAO,CAAC,kBAAkB,CAAe;IAEjC,KAAK,EAAE,SAAS,GAAG;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAA;gBAElC,IAAI,GAAE,MAAM,GAAG,MAAW,EAAE,KAAK,GAAE,SAAc;IAuB7D;;;;;;;;OAQG;WACW,gBAAgB,CAC5B,GAAG,EAAE,wBAAwB,EAC7B,IAAI,EAAE,MAAM,EACZ,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,KAAK,GAAE;QACL,UAAU,CAAC,EAAE,MAAM,CAAA;QACnB,QAAQ,CAAC,EAAE,MAAM,CAAA;QACjB,UAAU,CAAC,EAAE,SAAS,CAAC,YAAY,CAAC,CAAA;QACpC,SAAS,CAAC,EAAE,SAAS,CAAC,WAAW,CAAC,CAAA;QAClC,KAAK,CAAC,EAAE,MAAM,CAAA;QACd,SAAS,CAAC,EAAE,wBAAwB,CAAC,WAAW,CAAC,CAAA;QACjD,YAAY,CAAC,EAAE,wBAAwB,CAAC,cAAc,CAAC,CAAA;KACnD;cAwBW,aAAa,IAAI,IAAI;IAoDxC;;;;;;;;;;;;;;;;;OAiBG;IACH,OAAO,CAAC,sBAAsB;IA8B9B;;;;;;;;;;;;;;;;;OAiBG;IACH,OAAO,CAAC,aAAa;IA+ErB,OAAO,CAAC,aAAa;IAKrB,OAAO,CAAC,gBAAgB;IAyBxB;;;;OAIG;IACH,OAAO,CAAC,qBAAqB;IAM7B;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,aAAa;IAiCrB;;OAEG;IACH,OAAO,CAAC,yBAAyB;IAQjC;;;;;;;;;;;;;;OAcG;IACH,OAAO,CAAC,WAAW;IA+NnB;;;;;;;;;OASG;IACH,OAAO,CAAC,YAAY;IA6KpB;;;;;;;OAOG;IACH,OAAO,CAAC,aAAa;IAmErB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAQzB;;;;;;;;;;;;;;;;OAgBG;cACgB,cAAc,CAAC,GAAG,EAAE,wBAAwB,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;CAkXrH;AAED;;GAEG;AACH,eAAO,MAAM,IAAI,GAAI,MAAM,MAAM,GAAG,MAAM,EAAE,QAAQ,SAAS,aAA8B,CAAA"}
|
|
@@ -260,6 +260,17 @@ class TextNode extends BoxNode {
|
|
|
260
260
|
}
|
|
261
261
|
return 0; // Default fallback
|
|
262
262
|
}
|
|
263
|
+
/**
|
|
264
|
+
* Adds manual letter spacing compensation to a measured text width.
|
|
265
|
+
* Needed because skia-canvas ctx.measureText() does not include letterSpacing in the returned width,
|
|
266
|
+
* even though letterSpacing IS applied during rendering (fillText/strokeText).
|
|
267
|
+
*/
|
|
268
|
+
addLetterSpacingExtra(text, measuredWidth, letterSpacingPx) {
|
|
269
|
+
if (letterSpacingPx === 0 || text.length === 0)
|
|
270
|
+
return measuredWidth;
|
|
271
|
+
const charCount = [...text].length;
|
|
272
|
+
return measuredWidth + (charCount > 1 ? (charCount - 1) * letterSpacingPx : 0);
|
|
273
|
+
}
|
|
263
274
|
/**
|
|
264
275
|
* Generates a CSS font string by combining base TextProps with optional TextSegment styling.
|
|
265
276
|
* Follows browser font string format: "font-style font-weight font-size font-family"
|
|
@@ -338,6 +349,7 @@ class TextNode extends BoxNode {
|
|
|
338
349
|
ctx.letterSpacing = this.formatSpacing(this.props.letterSpacing);
|
|
339
350
|
ctx.wordSpacing = 'normal'; // Handled manually via parsedWordSpacingPx
|
|
340
351
|
const parsedWordSpacingPx = this.parseSpacingToPx(this.props.wordSpacing, baseFontSize);
|
|
352
|
+
const parsedLetterSpacingPx = this.parseSpacingToPx(this.props.letterSpacing, baseFontSize);
|
|
341
353
|
// Pre-measure each text segment width with its specific styling
|
|
342
354
|
for (const segment of this.segments) {
|
|
343
355
|
ctx.font = this.getFontString(segment);
|
|
@@ -353,13 +365,13 @@ class TextNode extends BoxNode {
|
|
|
353
365
|
if (ctx.fontVariant !== 'normal')
|
|
354
366
|
ctx.fontVariant = 'normal';
|
|
355
367
|
}
|
|
356
|
-
segment.width = ctx.measureText(segment.text).width;
|
|
368
|
+
segment.width = this.addLetterSpacingExtra(segment.text, ctx.measureText(segment.text).width, parsedLetterSpacingPx);
|
|
357
369
|
}
|
|
358
370
|
// Calculate available layout width
|
|
359
371
|
const availableWidthForContent = widthMode === Style.MeasureMode.Undefined ? Infinity : Math.max(0, widthConstraint);
|
|
360
372
|
const epsilon = 0.001; // Float precision compensation
|
|
361
373
|
// Wrap text into lines based on available width
|
|
362
|
-
this.lines = this.wrapTextRich(ctx, this.segments, availableWidthForContent + epsilon, parsedWordSpacingPx);
|
|
374
|
+
this.lines = this.wrapTextRich(ctx, this.segments, availableWidthForContent + epsilon, parsedWordSpacingPx, parsedLetterSpacingPx);
|
|
363
375
|
// Initialize line metrics arrays
|
|
364
376
|
this.lineHeights = []; // Final heights including leading
|
|
365
377
|
this.lineAscents = []; // Text ascent heights
|
|
@@ -479,7 +491,7 @@ class TextNode extends BoxNode {
|
|
|
479
491
|
if (ctx.fontVariant !== 'normal')
|
|
480
492
|
ctx.fontVariant = 'normal';
|
|
481
493
|
}
|
|
482
|
-
const wordWidth = ctx.measureText(word).width;
|
|
494
|
+
const wordWidth = this.addLetterSpacingExtra(word, ctx.measureText(word).width, parsedLetterSpacingPx);
|
|
483
495
|
if (!firstWordInSingleLine) {
|
|
484
496
|
singleLineWidth += spaceWidth + parsedWordSpacingPx;
|
|
485
497
|
}
|
|
@@ -554,7 +566,7 @@ class TextNode extends BoxNode {
|
|
|
554
566
|
* @param parsedWordSpacingPx Additional spacing to add between words in pixels
|
|
555
567
|
* @returns Array of lines, where each line contains styled text segments
|
|
556
568
|
*/
|
|
557
|
-
wrapTextRich(ctx, segments, maxWidth, parsedWordSpacingPx) {
|
|
569
|
+
wrapTextRich(ctx, segments, maxWidth, parsedWordSpacingPx, parsedLetterSpacingPx = 0) {
|
|
558
570
|
const lines = [];
|
|
559
571
|
if (segments.length === 0 || maxWidth <= 0)
|
|
560
572
|
return lines;
|
|
@@ -605,7 +617,7 @@ class TextNode extends BoxNode {
|
|
|
605
617
|
ctx.font = this.getFontString(segmentStyle);
|
|
606
618
|
if (this.props.fontVariant)
|
|
607
619
|
ctx.fontVariant = this.props.fontVariant;
|
|
608
|
-
wordWidth = ctx.measureText(wordOrSpace).width;
|
|
620
|
+
wordWidth = this.addLetterSpacingExtra(wordOrSpace, ctx.measureText(wordOrSpace).width, parsedLetterSpacingPx);
|
|
609
621
|
wordSegment = { text: wordOrSpace, ...segmentStyle, width: wordWidth };
|
|
610
622
|
}
|
|
611
623
|
const needsSpace = currentLineSegments.length > 0 && !/^\s+$/.test(currentLineSegments[currentLineSegments.length - 1].text);
|
|
@@ -624,7 +636,7 @@ class TextNode extends BoxNode {
|
|
|
624
636
|
}
|
|
625
637
|
if (!isSpace) {
|
|
626
638
|
if (wordWidth > maxWidth && maxWidth > 0) {
|
|
627
|
-
const brokenParts = this.breakWordRich(ctx, wordSegment, maxWidth);
|
|
639
|
+
const brokenParts = this.breakWordRich(ctx, wordSegment, maxWidth, parsedLetterSpacingPx);
|
|
628
640
|
if (brokenParts.length > 0) {
|
|
629
641
|
for (let k = 0; k < brokenParts.length - 1; k++) {
|
|
630
642
|
lines.push([brokenParts[k]]);
|
|
@@ -667,7 +679,7 @@ class TextNode extends BoxNode {
|
|
|
667
679
|
ctx.font = this.getFontString(segmentStyle);
|
|
668
680
|
if (this.props.fontVariant)
|
|
669
681
|
ctx.fontVariant = this.props.fontVariant;
|
|
670
|
-
wordWidth = ctx.measureText(wordOrSpace).width;
|
|
682
|
+
wordWidth = this.addLetterSpacingExtra(wordOrSpace, ctx.measureText(wordOrSpace).width, parsedLetterSpacingPx);
|
|
671
683
|
wordSegment = { text: wordOrSpace, ...segmentStyle, width: wordWidth };
|
|
672
684
|
}
|
|
673
685
|
const needsSpace = currentLineSegments.length > 0 && !/^\s+$/.test(currentLineSegments[currentLineSegments.length - 1].text);
|
|
@@ -686,7 +698,7 @@ class TextNode extends BoxNode {
|
|
|
686
698
|
}
|
|
687
699
|
if (!isSpace) {
|
|
688
700
|
if (wordWidth > maxWidth && maxWidth > 0) {
|
|
689
|
-
const brokenParts = this.breakWordRich(ctx, wordSegment, maxWidth);
|
|
701
|
+
const brokenParts = this.breakWordRich(ctx, wordSegment, maxWidth, parsedLetterSpacingPx);
|
|
690
702
|
if (brokenParts.length > 0) {
|
|
691
703
|
for (let k = 0; k < brokenParts.length - 1; k++) {
|
|
692
704
|
lines.push([brokenParts[k]]);
|
|
@@ -719,7 +731,7 @@ class TextNode extends BoxNode {
|
|
|
719
731
|
* @param maxWidth Maximum width allowed for each resulting segment
|
|
720
732
|
* @returns Array of TextSegments, each fitting maxWidth, or original segment if no breaking needed
|
|
721
733
|
*/
|
|
722
|
-
breakWordRich(ctx, segmentToBreak, maxWidth) {
|
|
734
|
+
breakWordRich(ctx, segmentToBreak, maxWidth, parsedLetterSpacingPx = 0) {
|
|
723
735
|
const word = segmentToBreak.text;
|
|
724
736
|
// Copy all style properties to maintain consistent styling across broken segments
|
|
725
737
|
const style = {
|
|
@@ -740,14 +752,14 @@ class TextNode extends BoxNode {
|
|
|
740
752
|
// Process word character by character to find valid break points
|
|
741
753
|
for (const char of word) {
|
|
742
754
|
const testPartText = currentPartText + char;
|
|
743
|
-
const testPartWidth = ctx.measureText(testPartText).width;
|
|
755
|
+
const testPartWidth = this.addLetterSpacingExtra(testPartText, ctx.measureText(testPartText).width, parsedLetterSpacingPx);
|
|
744
756
|
if (testPartWidth > maxWidth) {
|
|
745
757
|
// Current accumulated text exceeds width - create new segment
|
|
746
758
|
if (currentPartText) {
|
|
747
759
|
brokenSegments.push({
|
|
748
760
|
text: currentPartText,
|
|
749
761
|
...style,
|
|
750
|
-
width: ctx.measureText(currentPartText).width,
|
|
762
|
+
width: this.addLetterSpacingExtra(currentPartText, ctx.measureText(currentPartText).width, parsedLetterSpacingPx),
|
|
751
763
|
});
|
|
752
764
|
}
|
|
753
765
|
// Handle current character that caused overflow
|
|
@@ -773,7 +785,7 @@ class TextNode extends BoxNode {
|
|
|
773
785
|
brokenSegments.push({
|
|
774
786
|
text: currentPartText,
|
|
775
787
|
...style,
|
|
776
|
-
width: ctx.measureText(currentPartText).width,
|
|
788
|
+
width: this.addLetterSpacingExtra(currentPartText, ctx.measureText(currentPartText).width, parsedLetterSpacingPx),
|
|
777
789
|
});
|
|
778
790
|
}
|
|
779
791
|
return brokenSegments.length > 0 ? brokenSegments : [segmentToBreak];
|
|
@@ -832,7 +844,8 @@ class TextNode extends BoxNode {
|
|
|
832
844
|
const spaceWidth = this.measureSpaceWidth(ctx);
|
|
833
845
|
// Use a small epsilon for float precision issues
|
|
834
846
|
const epsilon = 0.01;
|
|
835
|
-
const
|
|
847
|
+
const parsedLetterSpacingPx = this.parseSpacingToPx(this.props.letterSpacing, baseFontSize);
|
|
848
|
+
const allLines = this.wrapTextRich(ctx, this.segments, contentWidth + epsilon, parsedWordSpacingPx, parsedLetterSpacingPx);
|
|
836
849
|
const needsEllipsis = this.props.ellipsis && this.props.maxLines !== undefined && allLines.length > this.props.maxLines;
|
|
837
850
|
// Apply maxLines constraint to get the visible lines
|
|
838
851
|
const visibleLines = this.props.maxLines !== undefined && this.props.maxLines > 0 ? allLines.slice(0, this.props.maxLines) : allLines;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@meonode/canvas",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.2",
|
|
4
4
|
"description": "A declarative, component-based library for server-side canvas image generation. Write complex visuals with simple functions, similar to the composition style of @meonode/ui.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"canvas",
|