tldraw 3.15.0-next.c85303fd51c8 → 3.15.0-next.e136ad205948
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-cjs/index.d.ts +5 -0
- package/dist-cjs/index.js +2 -1
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/lib/canvas/TldrawCropHandles.js +1 -1
- package/dist-cjs/lib/canvas/TldrawCropHandles.js.map +2 -2
- package/dist-cjs/lib/canvas/TldrawHandles.js +1 -1
- package/dist-cjs/lib/canvas/TldrawHandles.js.map +2 -2
- package/dist-cjs/lib/canvas/TldrawOverlays.js +1 -1
- package/dist-cjs/lib/canvas/TldrawOverlays.js.map +2 -2
- package/dist-cjs/lib/canvas/TldrawSelectionForeground.js +279 -271
- package/dist-cjs/lib/canvas/TldrawSelectionForeground.js.map +2 -2
- package/dist-cjs/lib/shapes/shared/PathBuilder.js +21 -3
- package/dist-cjs/lib/shapes/shared/PathBuilder.js.map +2 -2
- package/dist-cjs/lib/shapes/shared/PlainTextLabel.js +1 -0
- package/dist-cjs/lib/shapes/shared/PlainTextLabel.js.map +2 -2
- package/dist-cjs/lib/shapes/shared/RichTextLabel.js +1 -0
- package/dist-cjs/lib/shapes/shared/RichTextLabel.js.map +2 -2
- package/dist-cjs/lib/ui/components/NavigationPanel/DefaultNavigationPanel.js +3 -4
- package/dist-cjs/lib/ui/components/NavigationPanel/DefaultNavigationPanel.js.map +2 -2
- package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanelContent.js +2 -1
- package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanelContent.js.map +2 -2
- package/dist-cjs/lib/ui/components/primitives/TldrawUiDialog.js +1 -1
- package/dist-cjs/lib/ui/components/primitives/TldrawUiDialog.js.map +2 -2
- package/dist-cjs/lib/ui/components/primitives/TldrawUiSlider.js +5 -2
- package/dist-cjs/lib/ui/components/primitives/TldrawUiSlider.js.map +2 -2
- package/dist-cjs/lib/ui/components/primitives/TldrawUiToolbar.js +1 -0
- package/dist-cjs/lib/ui/components/primitives/TldrawUiToolbar.js.map +2 -2
- package/dist-cjs/lib/ui/version.js +3 -3
- package/dist-cjs/lib/ui/version.js.map +1 -1
- package/dist-esm/index.d.mts +5 -0
- package/dist-esm/index.mjs +3 -1
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/lib/canvas/TldrawCropHandles.mjs +1 -1
- package/dist-esm/lib/canvas/TldrawCropHandles.mjs.map +2 -2
- package/dist-esm/lib/canvas/TldrawHandles.mjs +1 -1
- package/dist-esm/lib/canvas/TldrawHandles.mjs.map +2 -2
- package/dist-esm/lib/canvas/TldrawOverlays.mjs +1 -1
- package/dist-esm/lib/canvas/TldrawOverlays.mjs.map +2 -2
- package/dist-esm/lib/canvas/TldrawSelectionForeground.mjs +279 -271
- package/dist-esm/lib/canvas/TldrawSelectionForeground.mjs.map +2 -2
- package/dist-esm/lib/shapes/shared/PathBuilder.mjs +22 -3
- package/dist-esm/lib/shapes/shared/PathBuilder.mjs.map +2 -2
- package/dist-esm/lib/shapes/shared/PlainTextLabel.mjs +1 -0
- package/dist-esm/lib/shapes/shared/PlainTextLabel.mjs.map +2 -2
- package/dist-esm/lib/shapes/shared/RichTextLabel.mjs +1 -0
- package/dist-esm/lib/shapes/shared/RichTextLabel.mjs.map +2 -2
- package/dist-esm/lib/ui/components/NavigationPanel/DefaultNavigationPanel.mjs +3 -4
- package/dist-esm/lib/ui/components/NavigationPanel/DefaultNavigationPanel.mjs.map +2 -2
- package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanelContent.mjs +2 -1
- package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanelContent.mjs.map +2 -2
- package/dist-esm/lib/ui/components/primitives/TldrawUiDialog.mjs +1 -1
- package/dist-esm/lib/ui/components/primitives/TldrawUiDialog.mjs.map +2 -2
- package/dist-esm/lib/ui/components/primitives/TldrawUiSlider.mjs +5 -2
- package/dist-esm/lib/ui/components/primitives/TldrawUiSlider.mjs.map +2 -2
- package/dist-esm/lib/ui/components/primitives/TldrawUiToolbar.mjs +1 -0
- package/dist-esm/lib/ui/components/primitives/TldrawUiToolbar.mjs.map +2 -2
- package/dist-esm/lib/ui/version.mjs +3 -3
- package/dist-esm/lib/ui/version.mjs.map +1 -1
- package/package.json +4 -3
- package/src/index.ts +1 -0
- package/src/lib/canvas/TldrawCropHandles.tsx +1 -1
- package/src/lib/canvas/TldrawHandles.tsx +5 -1
- package/src/lib/canvas/TldrawOverlays.tsx +1 -1
- package/src/lib/canvas/TldrawSelectionForeground.tsx +5 -1
- package/src/lib/shapes/shared/PathBuilder.test.tsx +1 -1
- package/src/lib/shapes/shared/PathBuilder.tsx +35 -1
- package/src/lib/shapes/shared/PlainTextLabel.tsx +1 -0
- package/src/lib/shapes/shared/RichTextLabel.tsx +1 -0
- package/src/lib/ui/components/NavigationPanel/DefaultNavigationPanel.tsx +3 -4
- package/src/lib/ui/components/StylePanel/DefaultStylePanelContent.tsx +1 -0
- package/src/lib/ui/components/primitives/TldrawUiDialog.tsx +1 -1
- package/src/lib/ui/components/primitives/TldrawUiSlider.tsx +5 -1
- package/src/lib/ui/components/primitives/TldrawUiToolbar.tsx +4 -0
- package/src/lib/ui/version.ts +3 -3
- package/src/lib/ui.css +0 -14
- package/src/test/navigation.test.ts +254 -0
- package/tldraw.css +2 -16
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/lib/canvas/TldrawSelectionForeground.tsx"],
|
|
4
|
-
"sourcesContent": ["import {\n\tBox,\n\tRotateCorner,\n\tTLEmbedShape,\n\tTLSelectionForegroundProps,\n\tTLTextShape,\n\tgetCursor,\n\ttlenv,\n\ttoDomPrecision,\n\ttrack,\n\tuseEditor,\n\tuseSelectionEvents,\n\tuseTransform,\n\tuseValue,\n} from '@tldraw/editor'\nimport classNames from 'classnames'\nimport { PointerEventHandler, useRef } from 'react'\nimport { useReadonly } from '../ui/hooks/useReadonly'\nimport { useTranslation } from '../ui/hooks/useTranslation/useTranslation'\nimport { TldrawCropHandles } from './TldrawCropHandles'\n\n/** @public */\nexport const TldrawSelectionForeground = track(function TldrawSelectionForeground({\n\tbounds,\n\trotation,\n}: TLSelectionForegroundProps) {\n\tconst editor = useEditor()\n\tconst msg = useTranslation()\n\tconst rSvg = useRef<SVGSVGElement>(null)\n\n\tconst isReadonlyMode = useReadonly()\n\tconst topEvents = useSelectionEvents('top')\n\tconst rightEvents = useSelectionEvents('right')\n\tconst bottomEvents = useSelectionEvents('bottom')\n\tconst leftEvents = useSelectionEvents('left')\n\tconst topLeftEvents = useSelectionEvents('top_left')\n\tconst topRightEvents = useSelectionEvents('top_right')\n\tconst bottomRightEvents = useSelectionEvents('bottom_right')\n\tconst bottomLeftEvents = useSelectionEvents('bottom_left')\n\n\tconst isDefaultCursor = editor.getInstanceState().cursor.type === 'default'\n\tconst isCoarsePointer = editor.getInstanceState().isCoarsePointer\n\n\tconst onlyShape = editor.getOnlySelectedShape()\n\tconst isLockedShape = onlyShape && editor.isShapeOrAncestorLocked(onlyShape)\n\n\t// if all shapes have an expandBy for the selection outline, we can expand by the l\n\tconst expandOutlineBy = onlyShape\n\t\t? editor.getShapeUtil(onlyShape).expandSelectionOutlinePx(onlyShape)\n\t\t: 0\n\n\tconst expandedBounds =\n\t\texpandOutlineBy instanceof Box\n\t\t\t? bounds.clone().expand(expandOutlineBy).zeroFix()\n\t\t\t: bounds.clone().expandBy(expandOutlineBy).zeroFix()\n\n\tuseTransform(rSvg, bounds?.x, bounds?.y, 1, editor.getSelectionRotation(), {\n\t\tx: expandedBounds.x - bounds.x,\n\t\ty: expandedBounds.y - bounds.y,\n\t})\n\n\tif (onlyShape && editor.isShapeHidden(onlyShape)) return null\n\n\tconst zoom = editor.getZoomLevel()\n\tconst isChangingStyle = editor.getInstanceState().isChangingStyle\n\n\tconst width = expandedBounds.width\n\tconst height = expandedBounds.height\n\n\tconst size = 8 / zoom\n\tconst isTinyX = width < size * 2\n\tconst isTinyY = height < size * 2\n\n\tconst isSmallX = width < size * 4\n\tconst isSmallY = height < size * 4\n\tconst isSmallCropX = width < size * 5\n\tconst isSmallCropY = height < size * 5\n\n\tconst mobileHandleMultiplier = isCoarsePointer ? 1.75 : 1\n\tconst targetSize = (6 / zoom) * mobileHandleMultiplier\n\n\tconst targetSizeX = (isSmallX ? targetSize / 2 : targetSize) * (mobileHandleMultiplier * 0.75)\n\tconst targetSizeY = (isSmallY ? targetSize / 2 : targetSize) * (mobileHandleMultiplier * 0.75)\n\n\tconst showSelectionBounds =\n\t\t(onlyShape ? !editor.getShapeUtil(onlyShape).hideSelectionBoundsFg(onlyShape) : true) &&\n\t\t!isChangingStyle\n\n\tlet shouldDisplayBox =\n\t\t(showSelectionBounds &&\n\t\t\teditor.isInAny(\n\t\t\t\t'select.idle',\n\t\t\t\t'select.brushing',\n\t\t\t\t'select.scribble_brushing',\n\t\t\t\t'select.pointing_canvas',\n\t\t\t\t'select.pointing_selection',\n\t\t\t\t'select.pointing_shape',\n\t\t\t\t'select.crop.idle',\n\t\t\t\t'select.crop.pointing_crop',\n\t\t\t\t'select.crop.pointing_crop_handle',\n\t\t\t\t'select.pointing_resize_handle'\n\t\t\t)) ||\n\t\t(showSelectionBounds &&\n\t\t\teditor.isIn('select.resizing') &&\n\t\t\tonlyShape &&\n\t\t\teditor.isShapeOfType<TLTextShape>(onlyShape, 'text'))\n\n\tif (onlyShape && shouldDisplayBox) {\n\t\tif (tlenv.isFirefox && editor.isShapeOfType<TLEmbedShape>(onlyShape, 'embed')) {\n\t\t\tshouldDisplayBox = false\n\t\t}\n\t}\n\n\tconst showCropHandles =\n\t\teditor.isInAny(\n\t\t\t'select.crop.idle',\n\t\t\t'select.crop.pointing_crop',\n\t\t\t'select.crop.pointing_crop_handle'\n\t\t) &&\n\t\t!isChangingStyle &&\n\t\t!isReadonlyMode\n\n\tconst shouldDisplayControls =\n\t\teditor.isInAny(\n\t\t\t'select.idle',\n\t\t\t'select.pointing_selection',\n\t\t\t'select.pointing_shape',\n\t\t\t'select.crop.idle'\n\t\t) &&\n\t\t!isChangingStyle &&\n\t\t!isReadonlyMode\n\n\tconst showCornerRotateHandles =\n\t\t!isCoarsePointer &&\n\t\t!(isTinyX || isTinyY) &&\n\t\t(shouldDisplayControls || showCropHandles) &&\n\t\t(onlyShape ? !editor.getShapeUtil(onlyShape).hideRotateHandle(onlyShape) : true) &&\n\t\t!isLockedShape\n\n\tconst showMobileRotateHandle =\n\t\tisCoarsePointer &&\n\t\t(!isSmallX || !isSmallY) &&\n\t\t(shouldDisplayControls || showCropHandles) &&\n\t\t(onlyShape ? !editor.getShapeUtil(onlyShape).hideRotateHandle(onlyShape) : true) &&\n\t\t!isLockedShape\n\n\tconst showResizeHandles =\n\t\tshouldDisplayControls &&\n\t\t(onlyShape\n\t\t\t? editor.getShapeUtil(onlyShape).canResize(onlyShape) &&\n\t\t\t\t!editor.getShapeUtil(onlyShape).hideResizeHandles(onlyShape)\n\t\t\t: true) &&\n\t\t!showCropHandles &&\n\t\t!isLockedShape\n\n\tconst hideAlternateCornerHandles = isTinyX || isTinyY\n\tconst showOnlyOneHandle = isTinyX && isTinyY\n\tconst hideAlternateCropHandles = isSmallCropX || isSmallCropY\n\n\tconst showHandles = showResizeHandles || showCropHandles\n\tconst hideRotateCornerHandles = !showCornerRotateHandles\n\tconst hideMobileRotateHandle = !shouldDisplayControls || !showMobileRotateHandle\n\tconst hideTopLeftCorner = !shouldDisplayControls || !showHandles\n\tconst hideTopRightCorner = !shouldDisplayControls || !showHandles || hideAlternateCornerHandles\n\tconst hideBottomLeftCorner = !shouldDisplayControls || !showHandles || hideAlternateCornerHandles\n\tconst hideBottomRightCorner =\n\t\t!shouldDisplayControls || !showHandles || (showOnlyOneHandle && !showCropHandles)\n\n\t// If we're showing crop handles, then show the edges too.\n\t// If we're showing resize handles, then show the edges only\n\t// if we're not hiding them for some other reason.\n\tlet hideVerticalEdgeTargets = true\n\t// The same logic above applies here, except another nuance is that\n\t// we enable resizing for text on mobile (coarse).\n\tlet hideHorizontalEdgeTargets = true\n\n\tif (showCropHandles) {\n\t\thideVerticalEdgeTargets = hideAlternateCropHandles\n\t\thideHorizontalEdgeTargets = hideAlternateCropHandles\n\t} else if (showResizeHandles) {\n\t\thideVerticalEdgeTargets = hideAlternateCornerHandles || showOnlyOneHandle || isCoarsePointer\n\t\tconst isMobileAndTextShape = isCoarsePointer && onlyShape && onlyShape.type === 'text'\n\t\thideHorizontalEdgeTargets = hideVerticalEdgeTargets && !isMobileAndTextShape\n\t}\n\n\tconst textHandleHeight = Math.min(24 / zoom, height - targetSizeY * 3)\n\tconst showTextResizeHandles =\n\t\tshouldDisplayControls &&\n\t\tisCoarsePointer &&\n\t\tonlyShape &&\n\t\teditor.isShapeOfType<TLTextShape>(onlyShape, 'text') &&\n\t\ttextHandleHeight * zoom >= 4\n\n\treturn (\n\t\t<svg className=\"tl-overlays__item tl-selection__fg\" data-testid=\"selection-foreground\">\n\t\t\t<g ref={rSvg}>\n\t\t\t\t{shouldDisplayBox && (\n\t\t\t\t\t<rect\n\t\t\t\t\t\tclassName=\"tl-selection__fg__outline\"\n\t\t\t\t\t\twidth={toDomPrecision(width)}\n\t\t\t\t\t\theight={toDomPrecision(height)}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\t\t\t\t<RotateCornerHandle\n\t\t\t\t\tdata-testid=\"selection.rotate.top-left\"\n\t\t\t\t\tcx={0}\n\t\t\t\t\tcy={0}\n\t\t\t\t\ttargetSize={targetSize}\n\t\t\t\t\tcorner=\"top_left_rotate\"\n\t\t\t\t\tcursor={isDefaultCursor ? getCursor('nwse-rotate', rotation) : undefined}\n\t\t\t\t\tisHidden={hideRotateCornerHandles}\n\t\t\t\t/>\n\t\t\t\t<RotateCornerHandle\n\t\t\t\t\tdata-testid=\"selection.rotate.top-right\"\n\t\t\t\t\tcx={width + targetSize * 3}\n\t\t\t\t\tcy={0}\n\t\t\t\t\ttargetSize={targetSize}\n\t\t\t\t\tcorner=\"top_right_rotate\"\n\t\t\t\t\tcursor={isDefaultCursor ? getCursor('nesw-rotate', rotation) : undefined}\n\t\t\t\t\tisHidden={hideRotateCornerHandles}\n\t\t\t\t/>\n\t\t\t\t<RotateCornerHandle\n\t\t\t\t\tdata-testid=\"selection.rotate.bottom-left\"\n\t\t\t\t\tcx={0}\n\t\t\t\t\tcy={height + targetSize * 3}\n\t\t\t\t\ttargetSize={targetSize}\n\t\t\t\t\tcorner=\"bottom_left_rotate\"\n\t\t\t\t\tcursor={isDefaultCursor ? getCursor('swne-rotate', rotation) : undefined}\n\t\t\t\t\tisHidden={hideRotateCornerHandles}\n\t\t\t\t/>\n\t\t\t\t<RotateCornerHandle\n\t\t\t\t\tdata-testid=\"selection.rotate.bottom-right\"\n\t\t\t\t\tcx={width + targetSize * 3}\n\t\t\t\t\tcy={height + targetSize * 3}\n\t\t\t\t\ttargetSize={targetSize}\n\t\t\t\t\tcorner=\"bottom_right_rotate\"\n\t\t\t\t\tcursor={isDefaultCursor ? getCursor('senw-rotate', rotation) : undefined}\n\t\t\t\t\tisHidden={hideRotateCornerHandles}\n\t\t\t\t/>\n\t\t\t\t<MobileRotateHandle\n\t\t\t\t\tdata-testid=\"selection.rotate.mobile\"\n\t\t\t\t\tcx={isSmallX ? -targetSize * 1.5 : width / 2}\n\t\t\t\t\tcy={isSmallX ? height / 2 : -targetSize * 1.5}\n\t\t\t\t\tsize={size}\n\t\t\t\t\tisHidden={hideMobileRotateHandle}\n\t\t\t\t/>\n\t\t\t\t{/* Targets */}\n\t\t\t\t<ResizeHandle\n\t\t\t\t\thide={hideVerticalEdgeTargets}\n\t\t\t\t\tdataTestId=\"selection.resize.top\"\n\t\t\t\t\tariaLabel={msg('handle.resize-top')}\n\t\t\t\t\tx={0}\n\t\t\t\t\ty={toDomPrecision(0 - (isSmallY ? targetSizeY * 2 : targetSizeY))}\n\t\t\t\t\twidth={toDomPrecision(width)}\n\t\t\t\t\theight={toDomPrecision(Math.max(1, targetSizeY * 2))}\n\t\t\t\t\tcursor={isDefaultCursor ? getCursor('ns-resize', rotation) : undefined}\n\t\t\t\t\tevents={topEvents}\n\t\t\t\t/>\n\t\t\t\t<ResizeHandle\n\t\t\t\t\thide={hideHorizontalEdgeTargets}\n\t\t\t\t\tdataTestId=\"selection.resize.right\"\n\t\t\t\t\tariaLabel={msg('handle.resize-right')}\n\t\t\t\t\tx={toDomPrecision(width - (isSmallX ? 0 : targetSizeX))}\n\t\t\t\t\ty={0}\n\t\t\t\t\theight={toDomPrecision(height)}\n\t\t\t\t\twidth={toDomPrecision(Math.max(1, targetSizeX * 2))}\n\t\t\t\t\tcursor={isDefaultCursor ? getCursor('ew-resize', rotation) : undefined}\n\t\t\t\t\tevents={rightEvents}\n\t\t\t\t/>\n\t\t\t\t<ResizeHandle\n\t\t\t\t\thide={hideVerticalEdgeTargets}\n\t\t\t\t\tdataTestId=\"selection.resize.bottom\"\n\t\t\t\t\tariaLabel={msg('handle.resize-bottom')}\n\t\t\t\t\tx={0}\n\t\t\t\t\ty={toDomPrecision(height - (isSmallY ? 0 : targetSizeY))}\n\t\t\t\t\twidth={toDomPrecision(width)}\n\t\t\t\t\theight={toDomPrecision(Math.max(1, targetSizeY * 2))}\n\t\t\t\t\tcursor={isDefaultCursor ? getCursor('ns-resize', rotation) : undefined}\n\t\t\t\t\tevents={bottomEvents}\n\t\t\t\t/>\n\t\t\t\t<ResizeHandle\n\t\t\t\t\thide={hideHorizontalEdgeTargets}\n\t\t\t\t\tdataTestId=\"selection.resize.left\"\n\t\t\t\t\tariaLabel={msg('handle.resize-left')}\n\t\t\t\t\tx={toDomPrecision(0 - (isSmallX ? targetSizeX * 2 : targetSizeX))}\n\t\t\t\t\ty={0}\n\t\t\t\t\theight={toDomPrecision(height)}\n\t\t\t\t\twidth={toDomPrecision(Math.max(1, targetSizeX * 2))}\n\t\t\t\t\tcursor={isDefaultCursor ? getCursor('ew-resize', rotation) : undefined}\n\t\t\t\t\tevents={leftEvents}\n\t\t\t\t/>\n\t\t\t\t{/* Corner Targets */}\n\t\t\t\t<ResizeHandle\n\t\t\t\t\thide={hideTopLeftCorner}\n\t\t\t\t\tdataTestId=\"selection.target.top-left\"\n\t\t\t\t\tariaLabel={msg('handle.resize-top-left')}\n\t\t\t\t\tx={toDomPrecision(0 - (isSmallX ? targetSizeX * 2 : targetSizeX * 1.5))}\n\t\t\t\t\ty={toDomPrecision(0 - (isSmallY ? targetSizeY * 2 : targetSizeY * 1.5))}\n\t\t\t\t\twidth={toDomPrecision(targetSizeX * 3)}\n\t\t\t\t\theight={toDomPrecision(targetSizeY * 3)}\n\t\t\t\t\tcursor={isDefaultCursor ? getCursor('nwse-resize', rotation) : undefined}\n\t\t\t\t\tevents={topLeftEvents}\n\t\t\t\t/>\n\t\t\t\t<ResizeHandle\n\t\t\t\t\thide={hideTopRightCorner}\n\t\t\t\t\tdataTestId=\"selection.target.top-right\"\n\t\t\t\t\tariaLabel={msg('handle.resize-top-right')}\n\t\t\t\t\tx={toDomPrecision(width - (isSmallX ? 0 : targetSizeX * 1.5))}\n\t\t\t\t\ty={toDomPrecision(0 - (isSmallY ? targetSizeY * 2 : targetSizeY * 1.5))}\n\t\t\t\t\twidth={toDomPrecision(targetSizeX * 3)}\n\t\t\t\t\theight={toDomPrecision(targetSizeY * 3)}\n\t\t\t\t\tcursor={isDefaultCursor ? getCursor('nesw-resize', rotation) : undefined}\n\t\t\t\t\tevents={topRightEvents}\n\t\t\t\t/>\n\t\t\t\t<ResizeHandle\n\t\t\t\t\thide={hideBottomRightCorner}\n\t\t\t\t\tdataTestId=\"selection.target.bottom-right\"\n\t\t\t\t\tariaLabel={msg('handle.resize-bottom-right')}\n\t\t\t\t\tx={toDomPrecision(width - (isSmallX ? targetSizeX : targetSizeX * 1.5))}\n\t\t\t\t\ty={toDomPrecision(height - (isSmallY ? targetSizeY : targetSizeY * 1.5))}\n\t\t\t\t\twidth={toDomPrecision(targetSizeX * 3)}\n\t\t\t\t\theight={toDomPrecision(targetSizeY * 3)}\n\t\t\t\t\tcursor={isDefaultCursor ? getCursor('nwse-resize', rotation) : undefined}\n\t\t\t\t\tevents={bottomRightEvents}\n\t\t\t\t/>\n\t\t\t\t<ResizeHandle\n\t\t\t\t\thide={hideBottomLeftCorner}\n\t\t\t\t\tdataTestId=\"selection.target.bottom-left\"\n\t\t\t\t\tariaLabel={msg('handle.resize-bottom-left')}\n\t\t\t\t\tx={toDomPrecision(0 - (isSmallX ? targetSizeX * 3 : targetSizeX * 1.5))}\n\t\t\t\t\ty={toDomPrecision(height - (isSmallY ? 0 : targetSizeY * 1.5))}\n\t\t\t\t\twidth={toDomPrecision(targetSizeX * 3)}\n\t\t\t\t\theight={toDomPrecision(targetSizeY * 3)}\n\t\t\t\t\tcursor={isDefaultCursor ? getCursor('nesw-resize', rotation) : undefined}\n\t\t\t\t\tevents={bottomLeftEvents}\n\t\t\t\t/>\n\t\t\t\t{/* Resize Handles */}\n\t\t\t\t{showResizeHandles && (\n\t\t\t\t\t<>\n\t\t\t\t\t\t<rect\n\t\t\t\t\t\t\tdata-testid=\"selection.resize.top-left\"\n\t\t\t\t\t\t\tclassName={classNames('tl-corner-handle', {\n\t\t\t\t\t\t\t\t'tl-hidden': hideTopLeftCorner,\n\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t\tx={toDomPrecision(0 - size / 2)}\n\t\t\t\t\t\t\ty={toDomPrecision(0 - size / 2)}\n\t\t\t\t\t\t\twidth={toDomPrecision(size)}\n\t\t\t\t\t\t\theight={toDomPrecision(size)}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<rect\n\t\t\t\t\t\t\tdata-testid=\"selection.resize.top-right\"\n\t\t\t\t\t\t\tclassName={classNames('tl-corner-handle', {\n\t\t\t\t\t\t\t\t'tl-hidden': hideTopRightCorner,\n\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t\tx={toDomPrecision(width - size / 2)}\n\t\t\t\t\t\t\ty={toDomPrecision(0 - size / 2)}\n\t\t\t\t\t\t\twidth={toDomPrecision(size)}\n\t\t\t\t\t\t\theight={toDomPrecision(size)}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<rect\n\t\t\t\t\t\t\tdata-testid=\"selection.resize.bottom-right\"\n\t\t\t\t\t\t\tclassName={classNames('tl-corner-handle', {\n\t\t\t\t\t\t\t\t'tl-hidden': hideBottomRightCorner,\n\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t\tx={toDomPrecision(width - size / 2)}\n\t\t\t\t\t\t\ty={toDomPrecision(height - size / 2)}\n\t\t\t\t\t\t\twidth={toDomPrecision(size)}\n\t\t\t\t\t\t\theight={toDomPrecision(size)}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<rect\n\t\t\t\t\t\t\tdata-testid=\"selection.resize.bottom-left\"\n\t\t\t\t\t\t\tclassName={classNames('tl-corner-handle', {\n\t\t\t\t\t\t\t\t'tl-hidden': hideBottomLeftCorner,\n\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t\tx={toDomPrecision(0 - size / 2)}\n\t\t\t\t\t\t\ty={toDomPrecision(height - size / 2)}\n\t\t\t\t\t\t\twidth={toDomPrecision(size)}\n\t\t\t\t\t\t\theight={toDomPrecision(size)}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</>\n\t\t\t\t)}\n\t\t\t\t{showTextResizeHandles && (\n\t\t\t\t\t<>\n\t\t\t\t\t\t<rect\n\t\t\t\t\t\t\tdata-testid=\"selection.text-resize.left.handle\"\n\t\t\t\t\t\t\tclassName=\"tl-text-handle\"\n\t\t\t\t\t\t\tx={toDomPrecision(0 - size / 4)}\n\t\t\t\t\t\t\ty={toDomPrecision(height / 2 - textHandleHeight / 2)}\n\t\t\t\t\t\t\trx={size / 4}\n\t\t\t\t\t\t\twidth={toDomPrecision(size / 2)}\n\t\t\t\t\t\t\theight={toDomPrecision(textHandleHeight)}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<rect\n\t\t\t\t\t\t\tdata-testid=\"selection.text-resize.right.handle\"\n\t\t\t\t\t\t\tclassName=\"tl-text-handle\"\n\t\t\t\t\t\t\trx={size / 4}\n\t\t\t\t\t\t\tx={toDomPrecision(width - size / 4)}\n\t\t\t\t\t\t\ty={toDomPrecision(height / 2 - textHandleHeight / 2)}\n\t\t\t\t\t\t\twidth={toDomPrecision(size / 2)}\n\t\t\t\t\t\t\theight={toDomPrecision(textHandleHeight)}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</>\n\t\t\t\t)}\n\t\t\t\t{/* Crop Handles */}\n\t\t\t\t{showCropHandles && (\n\t\t\t\t\t<TldrawCropHandles\n\t\t\t\t\t\t{...{\n\t\t\t\t\t\t\tsize,\n\t\t\t\t\t\t\twidth,\n\t\t\t\t\t\t\theight,\n\t\t\t\t\t\t\thideAlternateHandles: hideAlternateCropHandles,\n\t\t\t\t\t\t}}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\t\t\t</g>\n\t\t</svg>\n\t)\n})\n\nexport const ResizeHandle = function ResizeHandle({\n\thide,\n\tdataTestId,\n\tariaLabel,\n\tx,\n\ty,\n\twidth,\n\theight,\n\tcursor,\n\tevents,\n}: {\n\thide: boolean\n\tdataTestId: string\n\tariaLabel: string\n\tx: number\n\ty: number\n\twidth: number\n\theight: number\n\tcursor?: string\n\tevents: {\n\t\tonPointerUp: PointerEventHandler<Element>\n\t\tonPointerMove(e: React.PointerEvent<Element>): void\n\t\tonPointerDown: PointerEventHandler<Element>\n\t}\n}) {\n\treturn (\n\t\t<rect\n\t\t\tclassName={classNames('tl-resize-handle', 'tl-transparent', {\n\t\t\t\t'tl-hidden': hide,\n\t\t\t})}\n\t\t\tdata-testid={dataTestId}\n\t\t\trole=\"button\"\n\t\t\taria-label={ariaLabel}\n\t\t\tpointerEvents=\"all\"\n\t\t\tx={x}\n\t\t\ty={y}\n\t\t\twidth={width}\n\t\t\theight={height}\n\t\t\tcursor={cursor}\n\t\t\t{...events}\n\t\t/>\n\t)\n}\n\nexport const RotateCornerHandle = function RotateCornerHandle({\n\tcx,\n\tcy,\n\ttargetSize,\n\tcorner,\n\tcursor,\n\tisHidden,\n\t'data-testid': testId,\n}: {\n\tcx: number\n\tcy: number\n\ttargetSize: number\n\tcorner: RotateCorner\n\tcursor?: string\n\tisHidden: boolean\n\t'data-testid'?: string\n}) {\n\tconst events = useSelectionEvents(corner)\n\tconst msg = useTranslation()\n\tconst label = msg(`handle.rotate.${corner}`)\n\n\treturn (\n\t\t<rect\n\t\t\tclassName={classNames('tl-transparent', 'tl-rotate-corner', { 'tl-hidden': isHidden })}\n\t\t\tdata-testid={testId}\n\t\t\trole=\"button\"\n\t\t\taria-label={label}\n\t\t\tpointerEvents=\"all\"\n\t\t\tx={toDomPrecision(cx - targetSize * 3)}\n\t\t\ty={toDomPrecision(cy - targetSize * 3)}\n\t\t\twidth={toDomPrecision(Math.max(1, targetSize * 3))}\n\t\t\theight={toDomPrecision(Math.max(1, targetSize * 3))}\n\t\t\tcursor={cursor}\n\t\t\t{...events}\n\t\t/>\n\t)\n}\n\nconst SQUARE_ROOT_PI = Math.sqrt(Math.PI)\n\nexport const MobileRotateHandle = function RotateHandle({\n\tcx,\n\tcy,\n\tsize,\n\tisHidden,\n\t'data-testid': testId,\n}: {\n\tcx: number\n\tcy: number\n\tsize: number\n\tisHidden: boolean\n\t'data-testid'?: string\n}) {\n\tconst events = useSelectionEvents('mobile_rotate')\n\n\tconst editor = useEditor()\n\tconst zoom = useValue('zoom level', () => editor.getZoomLevel(), [editor])\n\tconst bgRadius = Math.max(14 * (1 / zoom), 20 / Math.max(1, zoom))\n\tconst msg = useTranslation()\n\treturn (\n\t\t<g role=\"button\" aria-label={msg('handle.rotate.mobile_rotate')}>\n\t\t\t<circle\n\t\t\t\tdata-testid={testId}\n\t\t\t\tpointerEvents=\"all\"\n\t\t\t\tclassName={classNames('tl-transparent', 'tl-mobile-rotate__bg', { 'tl-hidden': isHidden })}\n\t\t\t\tcx={cx}\n\t\t\t\tcy={cy}\n\t\t\t\tr={bgRadius}\n\t\t\t\t{...events}\n\t\t\t/>\n\t\t\t<circle\n\t\t\t\tclassName={classNames('tl-mobile-rotate__fg', { 'tl-hidden': isHidden })}\n\t\t\t\tcx={cx}\n\t\t\t\tcy={cy}\n\t\t\t\tr={size / SQUARE_ROOT_PI}\n\t\t\t/>\n\t\t</g>\n\t)\n}\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;
|
|
4
|
+
"sourcesContent": ["import {\n\tBox,\n\tRotateCorner,\n\tTLEmbedShape,\n\tTLSelectionForegroundProps,\n\tTLTextShape,\n\tgetCursor,\n\ttlenv,\n\ttoDomPrecision,\n\ttrack,\n\tuseEditor,\n\tuseSelectionEvents,\n\tuseTransform,\n\tuseValue,\n} from '@tldraw/editor'\nimport classNames from 'classnames'\nimport { PointerEventHandler, useRef } from 'react'\nimport { useReadonly } from '../ui/hooks/useReadonly'\nimport { useTranslation } from '../ui/hooks/useTranslation/useTranslation'\nimport { TldrawCropHandles } from './TldrawCropHandles'\n\n/** @public */\nexport const TldrawSelectionForeground = track(function TldrawSelectionForeground({\n\tbounds,\n\trotation,\n}: TLSelectionForegroundProps) {\n\tconst editor = useEditor()\n\tconst msg = useTranslation()\n\tconst rSvg = useRef<SVGSVGElement>(null)\n\n\tconst isReadonlyMode = useReadonly()\n\tconst topEvents = useSelectionEvents('top')\n\tconst rightEvents = useSelectionEvents('right')\n\tconst bottomEvents = useSelectionEvents('bottom')\n\tconst leftEvents = useSelectionEvents('left')\n\tconst topLeftEvents = useSelectionEvents('top_left')\n\tconst topRightEvents = useSelectionEvents('top_right')\n\tconst bottomRightEvents = useSelectionEvents('bottom_right')\n\tconst bottomLeftEvents = useSelectionEvents('bottom_left')\n\n\tconst isDefaultCursor = editor.getInstanceState().cursor.type === 'default'\n\tconst isCoarsePointer = editor.getInstanceState().isCoarsePointer\n\n\tconst onlyShape = editor.getOnlySelectedShape()\n\tconst isLockedShape = onlyShape && editor.isShapeOrAncestorLocked(onlyShape)\n\n\t// if all shapes have an expandBy for the selection outline, we can expand by the l\n\tconst expandOutlineBy = onlyShape\n\t\t? editor.getShapeUtil(onlyShape).expandSelectionOutlinePx(onlyShape)\n\t\t: 0\n\n\tconst expandedBounds =\n\t\texpandOutlineBy instanceof Box\n\t\t\t? bounds.clone().expand(expandOutlineBy).zeroFix()\n\t\t\t: bounds.clone().expandBy(expandOutlineBy).zeroFix()\n\n\tuseTransform(rSvg, bounds?.x, bounds?.y, 1, editor.getSelectionRotation(), {\n\t\tx: expandedBounds.x - bounds.x,\n\t\ty: expandedBounds.y - bounds.y,\n\t})\n\n\tif (onlyShape && editor.isShapeHidden(onlyShape)) return null\n\n\tconst zoom = editor.getZoomLevel()\n\tconst isChangingStyle = editor.getInstanceState().isChangingStyle\n\n\tconst width = expandedBounds.width\n\tconst height = expandedBounds.height\n\n\tconst size = 8 / zoom\n\tconst isTinyX = width < size * 2\n\tconst isTinyY = height < size * 2\n\n\tconst isSmallX = width < size * 4\n\tconst isSmallY = height < size * 4\n\tconst isSmallCropX = width < size * 5\n\tconst isSmallCropY = height < size * 5\n\n\tconst mobileHandleMultiplier = isCoarsePointer ? 1.75 : 1\n\tconst targetSize = (6 / zoom) * mobileHandleMultiplier\n\n\tconst targetSizeX = (isSmallX ? targetSize / 2 : targetSize) * (mobileHandleMultiplier * 0.75)\n\tconst targetSizeY = (isSmallY ? targetSize / 2 : targetSize) * (mobileHandleMultiplier * 0.75)\n\n\tconst showSelectionBounds =\n\t\t(onlyShape ? !editor.getShapeUtil(onlyShape).hideSelectionBoundsFg(onlyShape) : true) &&\n\t\t!isChangingStyle\n\n\tlet shouldDisplayBox =\n\t\t(showSelectionBounds &&\n\t\t\teditor.isInAny(\n\t\t\t\t'select.idle',\n\t\t\t\t'select.brushing',\n\t\t\t\t'select.scribble_brushing',\n\t\t\t\t'select.pointing_canvas',\n\t\t\t\t'select.pointing_selection',\n\t\t\t\t'select.pointing_shape',\n\t\t\t\t'select.crop.idle',\n\t\t\t\t'select.crop.pointing_crop',\n\t\t\t\t'select.crop.pointing_crop_handle',\n\t\t\t\t'select.pointing_resize_handle'\n\t\t\t)) ||\n\t\t(showSelectionBounds &&\n\t\t\teditor.isIn('select.resizing') &&\n\t\t\tonlyShape &&\n\t\t\teditor.isShapeOfType<TLTextShape>(onlyShape, 'text'))\n\n\tif (onlyShape && shouldDisplayBox) {\n\t\tif (tlenv.isFirefox && editor.isShapeOfType<TLEmbedShape>(onlyShape, 'embed')) {\n\t\t\tshouldDisplayBox = false\n\t\t}\n\t}\n\n\tconst showCropHandles =\n\t\teditor.isInAny(\n\t\t\t'select.crop.idle',\n\t\t\t'select.crop.pointing_crop',\n\t\t\t'select.crop.pointing_crop_handle'\n\t\t) &&\n\t\t!isChangingStyle &&\n\t\t!isReadonlyMode\n\n\tconst shouldDisplayControls =\n\t\teditor.isInAny(\n\t\t\t'select.idle',\n\t\t\t'select.pointing_selection',\n\t\t\t'select.pointing_shape',\n\t\t\t'select.crop.idle'\n\t\t) &&\n\t\t!isChangingStyle &&\n\t\t!isReadonlyMode\n\n\tconst showCornerRotateHandles =\n\t\t!isCoarsePointer &&\n\t\t!(isTinyX || isTinyY) &&\n\t\t(shouldDisplayControls || showCropHandles) &&\n\t\t(onlyShape ? !editor.getShapeUtil(onlyShape).hideRotateHandle(onlyShape) : true) &&\n\t\t!isLockedShape\n\n\tconst showMobileRotateHandle =\n\t\tisCoarsePointer &&\n\t\t(!isSmallX || !isSmallY) &&\n\t\t(shouldDisplayControls || showCropHandles) &&\n\t\t(onlyShape ? !editor.getShapeUtil(onlyShape).hideRotateHandle(onlyShape) : true) &&\n\t\t!isLockedShape\n\n\tconst showResizeHandles =\n\t\tshouldDisplayControls &&\n\t\t(onlyShape\n\t\t\t? editor.getShapeUtil(onlyShape).canResize(onlyShape) &&\n\t\t\t\t!editor.getShapeUtil(onlyShape).hideResizeHandles(onlyShape)\n\t\t\t: true) &&\n\t\t!showCropHandles &&\n\t\t!isLockedShape\n\n\tconst hideAlternateCornerHandles = isTinyX || isTinyY\n\tconst showOnlyOneHandle = isTinyX && isTinyY\n\tconst hideAlternateCropHandles = isSmallCropX || isSmallCropY\n\n\tconst showHandles = showResizeHandles || showCropHandles\n\tconst hideRotateCornerHandles = !showCornerRotateHandles\n\tconst hideMobileRotateHandle = !shouldDisplayControls || !showMobileRotateHandle\n\tconst hideTopLeftCorner = !shouldDisplayControls || !showHandles\n\tconst hideTopRightCorner = !shouldDisplayControls || !showHandles || hideAlternateCornerHandles\n\tconst hideBottomLeftCorner = !shouldDisplayControls || !showHandles || hideAlternateCornerHandles\n\tconst hideBottomRightCorner =\n\t\t!shouldDisplayControls || !showHandles || (showOnlyOneHandle && !showCropHandles)\n\n\t// If we're showing crop handles, then show the edges too.\n\t// If we're showing resize handles, then show the edges only\n\t// if we're not hiding them for some other reason.\n\tlet hideVerticalEdgeTargets = true\n\t// The same logic above applies here, except another nuance is that\n\t// we enable resizing for text on mobile (coarse).\n\tlet hideHorizontalEdgeTargets = true\n\n\tif (showCropHandles) {\n\t\thideVerticalEdgeTargets = hideAlternateCropHandles\n\t\thideHorizontalEdgeTargets = hideAlternateCropHandles\n\t} else if (showResizeHandles) {\n\t\thideVerticalEdgeTargets = hideAlternateCornerHandles || showOnlyOneHandle || isCoarsePointer\n\t\tconst isMobileAndTextShape = isCoarsePointer && onlyShape && onlyShape.type === 'text'\n\t\thideHorizontalEdgeTargets = hideVerticalEdgeTargets && !isMobileAndTextShape\n\t}\n\n\tconst textHandleHeight = Math.min(24 / zoom, height - targetSizeY * 3)\n\tconst showTextResizeHandles =\n\t\tshouldDisplayControls &&\n\t\tisCoarsePointer &&\n\t\tonlyShape &&\n\t\teditor.isShapeOfType<TLTextShape>(onlyShape, 'text') &&\n\t\ttextHandleHeight * zoom >= 4\n\n\treturn (\n\t\t<svg\n\t\t\tclassName=\"tl-overlays__item tl-selection__fg\"\n\t\t\tdata-testid=\"selection-foreground\"\n\t\t\taria-hidden=\"true\"\n\t\t>\n\t\t\t<g ref={rSvg}>\n\t\t\t\t{shouldDisplayBox && (\n\t\t\t\t\t<rect\n\t\t\t\t\t\tclassName=\"tl-selection__fg__outline\"\n\t\t\t\t\t\twidth={toDomPrecision(width)}\n\t\t\t\t\t\theight={toDomPrecision(height)}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\t\t\t\t<RotateCornerHandle\n\t\t\t\t\tdata-testid=\"selection.rotate.top-left\"\n\t\t\t\t\tcx={0}\n\t\t\t\t\tcy={0}\n\t\t\t\t\ttargetSize={targetSize}\n\t\t\t\t\tcorner=\"top_left_rotate\"\n\t\t\t\t\tcursor={isDefaultCursor ? getCursor('nwse-rotate', rotation) : undefined}\n\t\t\t\t\tisHidden={hideRotateCornerHandles}\n\t\t\t\t/>\n\t\t\t\t<RotateCornerHandle\n\t\t\t\t\tdata-testid=\"selection.rotate.top-right\"\n\t\t\t\t\tcx={width + targetSize * 3}\n\t\t\t\t\tcy={0}\n\t\t\t\t\ttargetSize={targetSize}\n\t\t\t\t\tcorner=\"top_right_rotate\"\n\t\t\t\t\tcursor={isDefaultCursor ? getCursor('nesw-rotate', rotation) : undefined}\n\t\t\t\t\tisHidden={hideRotateCornerHandles}\n\t\t\t\t/>\n\t\t\t\t<RotateCornerHandle\n\t\t\t\t\tdata-testid=\"selection.rotate.bottom-left\"\n\t\t\t\t\tcx={0}\n\t\t\t\t\tcy={height + targetSize * 3}\n\t\t\t\t\ttargetSize={targetSize}\n\t\t\t\t\tcorner=\"bottom_left_rotate\"\n\t\t\t\t\tcursor={isDefaultCursor ? getCursor('swne-rotate', rotation) : undefined}\n\t\t\t\t\tisHidden={hideRotateCornerHandles}\n\t\t\t\t/>\n\t\t\t\t<RotateCornerHandle\n\t\t\t\t\tdata-testid=\"selection.rotate.bottom-right\"\n\t\t\t\t\tcx={width + targetSize * 3}\n\t\t\t\t\tcy={height + targetSize * 3}\n\t\t\t\t\ttargetSize={targetSize}\n\t\t\t\t\tcorner=\"bottom_right_rotate\"\n\t\t\t\t\tcursor={isDefaultCursor ? getCursor('senw-rotate', rotation) : undefined}\n\t\t\t\t\tisHidden={hideRotateCornerHandles}\n\t\t\t\t/>\n\t\t\t\t<MobileRotateHandle\n\t\t\t\t\tdata-testid=\"selection.rotate.mobile\"\n\t\t\t\t\tcx={isSmallX ? -targetSize * 1.5 : width / 2}\n\t\t\t\t\tcy={isSmallX ? height / 2 : -targetSize * 1.5}\n\t\t\t\t\tsize={size}\n\t\t\t\t\tisHidden={hideMobileRotateHandle}\n\t\t\t\t/>\n\t\t\t\t{/* Targets */}\n\t\t\t\t<ResizeHandle\n\t\t\t\t\thide={hideVerticalEdgeTargets}\n\t\t\t\t\tdataTestId=\"selection.resize.top\"\n\t\t\t\t\tariaLabel={msg('handle.resize-top')}\n\t\t\t\t\tx={0}\n\t\t\t\t\ty={toDomPrecision(0 - (isSmallY ? targetSizeY * 2 : targetSizeY))}\n\t\t\t\t\twidth={toDomPrecision(width)}\n\t\t\t\t\theight={toDomPrecision(Math.max(1, targetSizeY * 2))}\n\t\t\t\t\tcursor={isDefaultCursor ? getCursor('ns-resize', rotation) : undefined}\n\t\t\t\t\tevents={topEvents}\n\t\t\t\t/>\n\t\t\t\t<ResizeHandle\n\t\t\t\t\thide={hideHorizontalEdgeTargets}\n\t\t\t\t\tdataTestId=\"selection.resize.right\"\n\t\t\t\t\tariaLabel={msg('handle.resize-right')}\n\t\t\t\t\tx={toDomPrecision(width - (isSmallX ? 0 : targetSizeX))}\n\t\t\t\t\ty={0}\n\t\t\t\t\theight={toDomPrecision(height)}\n\t\t\t\t\twidth={toDomPrecision(Math.max(1, targetSizeX * 2))}\n\t\t\t\t\tcursor={isDefaultCursor ? getCursor('ew-resize', rotation) : undefined}\n\t\t\t\t\tevents={rightEvents}\n\t\t\t\t/>\n\t\t\t\t<ResizeHandle\n\t\t\t\t\thide={hideVerticalEdgeTargets}\n\t\t\t\t\tdataTestId=\"selection.resize.bottom\"\n\t\t\t\t\tariaLabel={msg('handle.resize-bottom')}\n\t\t\t\t\tx={0}\n\t\t\t\t\ty={toDomPrecision(height - (isSmallY ? 0 : targetSizeY))}\n\t\t\t\t\twidth={toDomPrecision(width)}\n\t\t\t\t\theight={toDomPrecision(Math.max(1, targetSizeY * 2))}\n\t\t\t\t\tcursor={isDefaultCursor ? getCursor('ns-resize', rotation) : undefined}\n\t\t\t\t\tevents={bottomEvents}\n\t\t\t\t/>\n\t\t\t\t<ResizeHandle\n\t\t\t\t\thide={hideHorizontalEdgeTargets}\n\t\t\t\t\tdataTestId=\"selection.resize.left\"\n\t\t\t\t\tariaLabel={msg('handle.resize-left')}\n\t\t\t\t\tx={toDomPrecision(0 - (isSmallX ? targetSizeX * 2 : targetSizeX))}\n\t\t\t\t\ty={0}\n\t\t\t\t\theight={toDomPrecision(height)}\n\t\t\t\t\twidth={toDomPrecision(Math.max(1, targetSizeX * 2))}\n\t\t\t\t\tcursor={isDefaultCursor ? getCursor('ew-resize', rotation) : undefined}\n\t\t\t\t\tevents={leftEvents}\n\t\t\t\t/>\n\t\t\t\t{/* Corner Targets */}\n\t\t\t\t<ResizeHandle\n\t\t\t\t\thide={hideTopLeftCorner}\n\t\t\t\t\tdataTestId=\"selection.target.top-left\"\n\t\t\t\t\tariaLabel={msg('handle.resize-top-left')}\n\t\t\t\t\tx={toDomPrecision(0 - (isSmallX ? targetSizeX * 2 : targetSizeX * 1.5))}\n\t\t\t\t\ty={toDomPrecision(0 - (isSmallY ? targetSizeY * 2 : targetSizeY * 1.5))}\n\t\t\t\t\twidth={toDomPrecision(targetSizeX * 3)}\n\t\t\t\t\theight={toDomPrecision(targetSizeY * 3)}\n\t\t\t\t\tcursor={isDefaultCursor ? getCursor('nwse-resize', rotation) : undefined}\n\t\t\t\t\tevents={topLeftEvents}\n\t\t\t\t/>\n\t\t\t\t<ResizeHandle\n\t\t\t\t\thide={hideTopRightCorner}\n\t\t\t\t\tdataTestId=\"selection.target.top-right\"\n\t\t\t\t\tariaLabel={msg('handle.resize-top-right')}\n\t\t\t\t\tx={toDomPrecision(width - (isSmallX ? 0 : targetSizeX * 1.5))}\n\t\t\t\t\ty={toDomPrecision(0 - (isSmallY ? targetSizeY * 2 : targetSizeY * 1.5))}\n\t\t\t\t\twidth={toDomPrecision(targetSizeX * 3)}\n\t\t\t\t\theight={toDomPrecision(targetSizeY * 3)}\n\t\t\t\t\tcursor={isDefaultCursor ? getCursor('nesw-resize', rotation) : undefined}\n\t\t\t\t\tevents={topRightEvents}\n\t\t\t\t/>\n\t\t\t\t<ResizeHandle\n\t\t\t\t\thide={hideBottomRightCorner}\n\t\t\t\t\tdataTestId=\"selection.target.bottom-right\"\n\t\t\t\t\tariaLabel={msg('handle.resize-bottom-right')}\n\t\t\t\t\tx={toDomPrecision(width - (isSmallX ? targetSizeX : targetSizeX * 1.5))}\n\t\t\t\t\ty={toDomPrecision(height - (isSmallY ? targetSizeY : targetSizeY * 1.5))}\n\t\t\t\t\twidth={toDomPrecision(targetSizeX * 3)}\n\t\t\t\t\theight={toDomPrecision(targetSizeY * 3)}\n\t\t\t\t\tcursor={isDefaultCursor ? getCursor('nwse-resize', rotation) : undefined}\n\t\t\t\t\tevents={bottomRightEvents}\n\t\t\t\t/>\n\t\t\t\t<ResizeHandle\n\t\t\t\t\thide={hideBottomLeftCorner}\n\t\t\t\t\tdataTestId=\"selection.target.bottom-left\"\n\t\t\t\t\tariaLabel={msg('handle.resize-bottom-left')}\n\t\t\t\t\tx={toDomPrecision(0 - (isSmallX ? targetSizeX * 3 : targetSizeX * 1.5))}\n\t\t\t\t\ty={toDomPrecision(height - (isSmallY ? 0 : targetSizeY * 1.5))}\n\t\t\t\t\twidth={toDomPrecision(targetSizeX * 3)}\n\t\t\t\t\theight={toDomPrecision(targetSizeY * 3)}\n\t\t\t\t\tcursor={isDefaultCursor ? getCursor('nesw-resize', rotation) : undefined}\n\t\t\t\t\tevents={bottomLeftEvents}\n\t\t\t\t/>\n\t\t\t\t{/* Resize Handles */}\n\t\t\t\t{showResizeHandles && (\n\t\t\t\t\t<>\n\t\t\t\t\t\t<rect\n\t\t\t\t\t\t\tdata-testid=\"selection.resize.top-left\"\n\t\t\t\t\t\t\tclassName={classNames('tl-corner-handle', {\n\t\t\t\t\t\t\t\t'tl-hidden': hideTopLeftCorner,\n\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t\tx={toDomPrecision(0 - size / 2)}\n\t\t\t\t\t\t\ty={toDomPrecision(0 - size / 2)}\n\t\t\t\t\t\t\twidth={toDomPrecision(size)}\n\t\t\t\t\t\t\theight={toDomPrecision(size)}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<rect\n\t\t\t\t\t\t\tdata-testid=\"selection.resize.top-right\"\n\t\t\t\t\t\t\tclassName={classNames('tl-corner-handle', {\n\t\t\t\t\t\t\t\t'tl-hidden': hideTopRightCorner,\n\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t\tx={toDomPrecision(width - size / 2)}\n\t\t\t\t\t\t\ty={toDomPrecision(0 - size / 2)}\n\t\t\t\t\t\t\twidth={toDomPrecision(size)}\n\t\t\t\t\t\t\theight={toDomPrecision(size)}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<rect\n\t\t\t\t\t\t\tdata-testid=\"selection.resize.bottom-right\"\n\t\t\t\t\t\t\tclassName={classNames('tl-corner-handle', {\n\t\t\t\t\t\t\t\t'tl-hidden': hideBottomRightCorner,\n\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t\tx={toDomPrecision(width - size / 2)}\n\t\t\t\t\t\t\ty={toDomPrecision(height - size / 2)}\n\t\t\t\t\t\t\twidth={toDomPrecision(size)}\n\t\t\t\t\t\t\theight={toDomPrecision(size)}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<rect\n\t\t\t\t\t\t\tdata-testid=\"selection.resize.bottom-left\"\n\t\t\t\t\t\t\tclassName={classNames('tl-corner-handle', {\n\t\t\t\t\t\t\t\t'tl-hidden': hideBottomLeftCorner,\n\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t\tx={toDomPrecision(0 - size / 2)}\n\t\t\t\t\t\t\ty={toDomPrecision(height - size / 2)}\n\t\t\t\t\t\t\twidth={toDomPrecision(size)}\n\t\t\t\t\t\t\theight={toDomPrecision(size)}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</>\n\t\t\t\t)}\n\t\t\t\t{showTextResizeHandles && (\n\t\t\t\t\t<>\n\t\t\t\t\t\t<rect\n\t\t\t\t\t\t\tdata-testid=\"selection.text-resize.left.handle\"\n\t\t\t\t\t\t\tclassName=\"tl-text-handle\"\n\t\t\t\t\t\t\tx={toDomPrecision(0 - size / 4)}\n\t\t\t\t\t\t\ty={toDomPrecision(height / 2 - textHandleHeight / 2)}\n\t\t\t\t\t\t\trx={size / 4}\n\t\t\t\t\t\t\twidth={toDomPrecision(size / 2)}\n\t\t\t\t\t\t\theight={toDomPrecision(textHandleHeight)}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<rect\n\t\t\t\t\t\t\tdata-testid=\"selection.text-resize.right.handle\"\n\t\t\t\t\t\t\tclassName=\"tl-text-handle\"\n\t\t\t\t\t\t\trx={size / 4}\n\t\t\t\t\t\t\tx={toDomPrecision(width - size / 4)}\n\t\t\t\t\t\t\ty={toDomPrecision(height / 2 - textHandleHeight / 2)}\n\t\t\t\t\t\t\twidth={toDomPrecision(size / 2)}\n\t\t\t\t\t\t\theight={toDomPrecision(textHandleHeight)}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</>\n\t\t\t\t)}\n\t\t\t\t{/* Crop Handles */}\n\t\t\t\t{showCropHandles && (\n\t\t\t\t\t<TldrawCropHandles\n\t\t\t\t\t\t{...{\n\t\t\t\t\t\t\tsize,\n\t\t\t\t\t\t\twidth,\n\t\t\t\t\t\t\theight,\n\t\t\t\t\t\t\thideAlternateHandles: hideAlternateCropHandles,\n\t\t\t\t\t\t}}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\t\t\t</g>\n\t\t</svg>\n\t)\n})\n\nexport const ResizeHandle = function ResizeHandle({\n\thide,\n\tdataTestId,\n\tariaLabel,\n\tx,\n\ty,\n\twidth,\n\theight,\n\tcursor,\n\tevents,\n}: {\n\thide: boolean\n\tdataTestId: string\n\tariaLabel: string\n\tx: number\n\ty: number\n\twidth: number\n\theight: number\n\tcursor?: string\n\tevents: {\n\t\tonPointerUp: PointerEventHandler<Element>\n\t\tonPointerMove(e: React.PointerEvent<Element>): void\n\t\tonPointerDown: PointerEventHandler<Element>\n\t}\n}) {\n\treturn (\n\t\t<rect\n\t\t\tclassName={classNames('tl-resize-handle', 'tl-transparent', {\n\t\t\t\t'tl-hidden': hide,\n\t\t\t})}\n\t\t\tdata-testid={dataTestId}\n\t\t\trole=\"button\"\n\t\t\taria-label={ariaLabel}\n\t\t\tpointerEvents=\"all\"\n\t\t\tx={x}\n\t\t\ty={y}\n\t\t\twidth={width}\n\t\t\theight={height}\n\t\t\tcursor={cursor}\n\t\t\t{...events}\n\t\t/>\n\t)\n}\n\nexport const RotateCornerHandle = function RotateCornerHandle({\n\tcx,\n\tcy,\n\ttargetSize,\n\tcorner,\n\tcursor,\n\tisHidden,\n\t'data-testid': testId,\n}: {\n\tcx: number\n\tcy: number\n\ttargetSize: number\n\tcorner: RotateCorner\n\tcursor?: string\n\tisHidden: boolean\n\t'data-testid'?: string\n}) {\n\tconst events = useSelectionEvents(corner)\n\tconst msg = useTranslation()\n\tconst label = msg(`handle.rotate.${corner}`)\n\n\treturn (\n\t\t<rect\n\t\t\tclassName={classNames('tl-transparent', 'tl-rotate-corner', { 'tl-hidden': isHidden })}\n\t\t\tdata-testid={testId}\n\t\t\trole=\"button\"\n\t\t\taria-label={label}\n\t\t\tpointerEvents=\"all\"\n\t\t\tx={toDomPrecision(cx - targetSize * 3)}\n\t\t\ty={toDomPrecision(cy - targetSize * 3)}\n\t\t\twidth={toDomPrecision(Math.max(1, targetSize * 3))}\n\t\t\theight={toDomPrecision(Math.max(1, targetSize * 3))}\n\t\t\tcursor={cursor}\n\t\t\t{...events}\n\t\t/>\n\t)\n}\n\nconst SQUARE_ROOT_PI = Math.sqrt(Math.PI)\n\nexport const MobileRotateHandle = function RotateHandle({\n\tcx,\n\tcy,\n\tsize,\n\tisHidden,\n\t'data-testid': testId,\n}: {\n\tcx: number\n\tcy: number\n\tsize: number\n\tisHidden: boolean\n\t'data-testid'?: string\n}) {\n\tconst events = useSelectionEvents('mobile_rotate')\n\n\tconst editor = useEditor()\n\tconst zoom = useValue('zoom level', () => editor.getZoomLevel(), [editor])\n\tconst bgRadius = Math.max(14 * (1 / zoom), 20 / Math.max(1, zoom))\n\tconst msg = useTranslation()\n\treturn (\n\t\t<g role=\"button\" aria-label={msg('handle.rotate.mobile_rotate')}>\n\t\t\t<circle\n\t\t\t\tdata-testid={testId}\n\t\t\t\tpointerEvents=\"all\"\n\t\t\t\tclassName={classNames('tl-transparent', 'tl-mobile-rotate__bg', { 'tl-hidden': isHidden })}\n\t\t\t\tcx={cx}\n\t\t\t\tcy={cy}\n\t\t\t\tr={bgRadius}\n\t\t\t\t{...events}\n\t\t\t/>\n\t\t\t<circle\n\t\t\t\tclassName={classNames('tl-mobile-rotate__fg', { 'tl-hidden': isHidden })}\n\t\t\t\tcx={cx}\n\t\t\t\tcy={cy}\n\t\t\t\tr={size / SQUARE_ROOT_PI}\n\t\t\t/>\n\t\t</g>\n\t)\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["TldrawSelectionForeground", "classNames", "ResizeHandle", "RotateCornerHandle"]
|
|
7
7
|
}
|
|
@@ -135,7 +135,11 @@ class PathBuilder {
|
|
|
135
135
|
endAngle += 2 * Math.PI;
|
|
136
136
|
}
|
|
137
137
|
const sweepAngle = endAngle - startAngle;
|
|
138
|
+
const approximateArcLength = Math.max(rx1, ry1) * Math.abs(sweepAngle);
|
|
138
139
|
const numSegments = Math.min(4, Math.ceil(Math.abs(sweepAngle) / (Math.PI / 2)));
|
|
140
|
+
const resolutionPerSegment = Math.ceil(
|
|
141
|
+
(0, import_editor.getVerticesCountForArcLength)(approximateArcLength) / numSegments
|
|
142
|
+
);
|
|
139
143
|
const anglePerSegment = sweepAngle / numSegments;
|
|
140
144
|
const ellipsePoint = (angle) => {
|
|
141
145
|
return {
|
|
@@ -163,11 +167,23 @@ class PathBuilder {
|
|
|
163
167
|
const cp2x = end.x - handleScale * d2.x;
|
|
164
168
|
const cp2y = end.y - handleScale * d2.y;
|
|
165
169
|
const bezierOpts = i === 0 ? opts : { ...opts, mergeWithPrevious: true };
|
|
166
|
-
this.
|
|
170
|
+
this.cubicBezierToWithResolution(
|
|
171
|
+
end.x,
|
|
172
|
+
end.y,
|
|
173
|
+
cp1x,
|
|
174
|
+
cp1y,
|
|
175
|
+
cp2x,
|
|
176
|
+
cp2y,
|
|
177
|
+
bezierOpts,
|
|
178
|
+
resolutionPerSegment
|
|
179
|
+
);
|
|
167
180
|
}
|
|
168
181
|
return this;
|
|
169
182
|
}
|
|
170
183
|
cubicBezierTo(x, y, cp1X, cp1Y, cp2X, cp2Y, opts) {
|
|
184
|
+
return this.cubicBezierToWithResolution(x, y, cp1X, cp1Y, cp2X, cp2Y, opts);
|
|
185
|
+
}
|
|
186
|
+
cubicBezierToWithResolution(x, y, cp1X, cp1Y, cp2X, cp2Y, opts, resolution) {
|
|
171
187
|
this.assertHasMoveTo();
|
|
172
188
|
this.commands.push({
|
|
173
189
|
type: "cubic",
|
|
@@ -176,7 +192,8 @@ class PathBuilder {
|
|
|
176
192
|
cp1: { x: cp1X, y: cp1Y },
|
|
177
193
|
cp2: { x: cp2X, y: cp2Y },
|
|
178
194
|
isClose: false,
|
|
179
|
-
opts
|
|
195
|
+
opts,
|
|
196
|
+
resolution
|
|
180
197
|
});
|
|
181
198
|
return this;
|
|
182
199
|
}
|
|
@@ -639,7 +656,8 @@ class PathBuilderGeometry2d extends import_editor.Geometry2d {
|
|
|
639
656
|
start: import_editor.Vec.From(last),
|
|
640
657
|
cp1: import_editor.Vec.From(command.cp1),
|
|
641
658
|
cp2: import_editor.Vec.From(command.cp2),
|
|
642
|
-
end: import_editor.Vec.From(command)
|
|
659
|
+
end: import_editor.Vec.From(command),
|
|
660
|
+
resolution: command.resolution
|
|
643
661
|
})
|
|
644
662
|
);
|
|
645
663
|
break;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/lib/shapes/shared/PathBuilder.tsx"],
|
|
4
|
-
"sourcesContent": ["import {\n\tapproximately,\n\tassert,\n\tassertExists,\n\tclamp,\n\tCubicBezier2d,\n\tEdge2d,\n\texhaustiveSwitchError,\n\tGeometry2d,\n\tGeometry2dFilters,\n\tGeometry2dOptions,\n\tgetPerfectDashProps,\n\tGroup2d,\n\tmodulate,\n\tPerfectDashTerminal,\n\trng,\n\ttoDomPrecision,\n\tVec,\n\tVecLike,\n\tVecModel,\n} from '@tldraw/editor'\nimport { ReactNode, SVGProps } from 'react'\n\n/** @public */\nexport interface BasePathBuilderOpts {\n\tstrokeWidth: number\n\tforceSolid?: boolean\n\tonlyFilled?: boolean\n\tprops?: SVGProps<SVGPathElement & SVGGElement>\n}\n\n/** @public */\nexport interface SolidPathBuilderOpts extends BasePathBuilderOpts {\n\tstyle: 'solid'\n}\n\n/** @public */\nexport interface DashedPathBuilderOpts extends BasePathBuilderOpts {\n\tstyle: 'dashed' | 'dotted'\n\tsnap?: number\n\tend?: PerfectDashTerminal\n\tstart?: PerfectDashTerminal\n\tlengthRatio?: number\n}\n\n/** @public */\nexport interface DrawPathBuilderDOpts {\n\tstrokeWidth: number\n\trandomSeed: string\n\toffset?: number\n\troundness?: number\n\tpasses?: number\n\tonlyFilled?: boolean\n}\n\n/** @public */\nexport interface DrawPathBuilderOpts extends BasePathBuilderOpts, DrawPathBuilderDOpts {\n\tstyle: 'draw'\n}\n\n/** @public */\nexport type PathBuilderOpts = SolidPathBuilderOpts | DashedPathBuilderOpts | DrawPathBuilderOpts\n\n/** @public */\nexport interface PathBuilderCommandOpts {\n\t/**\n\t * When converting to a draw-style line, how much offset from the original point should be\n\t * applied?\n\t */\n\toffset?: number\n\t/**\n\t * When converting to a draw-style line, how much roundness should be applied to the end of this\n\t * line?\n\t */\n\troundness?: number\n\t/**\n\t * When converting to a dash- or dot-style line, should the current segment be merged with the\n\t * previous segment when calculating the dash pattern? This is false by default, meaning each\n\t * command will start/end on a dash/dot boundary.\n\t */\n\tmergeWithPrevious?: boolean\n}\n\n/** @internal */\nexport interface PathBuilderCommandInfo {\n\ttangentStart: VecModel\n\ttangentEnd: VecModel\n\tlength: number\n}\n\n/** @internal */\nexport interface PathBuilderCommandBase {\n\topts?: PathBuilderCommandOpts\n\tx: number\n\ty: number\n\tisClose: boolean\n\t_info?: PathBuilderCommandInfo\n}\n\n/** @public */\nexport interface PathBuilderLineOpts extends PathBuilderCommandOpts {\n\tgeometry?: Omit<Geometry2dOptions, 'isClosed'> | false\n\tdashStart?: PerfectDashTerminal\n\tdashEnd?: PerfectDashTerminal\n}\n\n/** @internal */\nexport interface MoveToPathBuilderCommand extends PathBuilderCommandBase {\n\ttype: 'move'\n\tcloseIdx: number | null\n\topts?: PathBuilderLineOpts\n}\n\n/** @internal */\nexport interface LineToPathBuilderCommand extends PathBuilderCommandBase {\n\ttype: 'line'\n}\n\n/** @internal */\nexport interface CubicBezierToPathBuilderCommand extends PathBuilderCommandBase {\n\ttype: 'cubic'\n\tcp1: VecModel\n\tcp2: VecModel\n}\n\n/** @internal */\nexport type PathBuilderCommand =\n\t| MoveToPathBuilderCommand\n\t| LineToPathBuilderCommand\n\t| CubicBezierToPathBuilderCommand\n\n/** @public */\nexport interface PathBuilderToDOpts {\n\tstartIdx?: number\n\tendIdx?: number\n\tonlyFilled?: boolean\n}\n\n/** @public */\nexport class PathBuilder {\n\tstatic lineThroughPoints(\n\t\tpoints: VecLike[],\n\t\topts?: PathBuilderLineOpts & { endOffsets?: number }\n\t) {\n\t\tconst path = new PathBuilder()\n\t\tpath.moveTo(points[0].x, points[0].y, { ...opts, offset: opts?.endOffsets ?? opts?.offset })\n\t\tfor (let i = 1; i < points.length; i++) {\n\t\t\tconst isLast = i === points.length - 1\n\t\t\tpath.lineTo(points[i].x, points[i].y, isLast ? { offset: opts?.endOffsets } : undefined)\n\t\t}\n\t\treturn path\n\t}\n\n\tstatic cubicSplineThroughPoints(\n\t\tpoints: VecLike[],\n\t\topts?: PathBuilderLineOpts & { endOffsets?: number }\n\t) {\n\t\tconst path = new PathBuilder()\n\t\tconst len = points.length\n\t\tconst last = len - 2\n\t\tconst k = 1.25\n\n\t\tpath.moveTo(points[0].x, points[0].y, { ...opts, offset: opts?.endOffsets ?? opts?.offset })\n\n\t\tfor (let i = 0; i < len - 1; i++) {\n\t\t\tconst p0 = i === 0 ? points[0] : points[i - 1]\n\t\t\tconst p1 = points[i]\n\t\t\tconst p2 = points[i + 1]\n\t\t\tconst p3 = i === last ? p2 : points[i + 2]\n\n\t\t\tlet cp1x, cp1y, cp2x, cp2y\n\t\t\tif (i === 0) {\n\t\t\t\tcp1x = p0.x\n\t\t\t\tcp1y = p0.y\n\t\t\t} else {\n\t\t\t\tcp1x = p1.x + ((p2.x - p0.x) / 6) * k\n\t\t\t\tcp1y = p1.y + ((p2.y - p0.y) / 6) * k\n\t\t\t}\n\n\t\t\tlet pointOpts = undefined\n\t\t\tif (i === last) {\n\t\t\t\tcp2x = p2.x\n\t\t\t\tcp2y = p2.y\n\t\t\t\tpointOpts = { offset: opts?.endOffsets }\n\t\t\t} else {\n\t\t\t\tcp2x = p2.x - ((p3.x - p1.x) / 6) * k\n\t\t\t\tcp2y = p2.y - ((p3.y - p1.y) / 6) * k\n\t\t\t}\n\n\t\t\tpath.cubicBezierTo(p2.x, p2.y, cp1x, cp1y, cp2x, cp2y, pointOpts)\n\t\t}\n\n\t\treturn path\n\t}\n\n\tconstructor() {}\n\n\t/** @internal */\n\tcommands: PathBuilderCommand[] = []\n\n\tprivate lastMoveTo: MoveToPathBuilderCommand | null = null\n\tprivate assertHasMoveTo() {\n\t\tassert(this.lastMoveTo, 'Start an SVGPathBuilder with `.moveTo()`')\n\t\treturn this.lastMoveTo\n\t}\n\n\tmoveTo(x: number, y: number, opts?: PathBuilderLineOpts) {\n\t\tthis.lastMoveTo = { type: 'move', x, y, closeIdx: null, isClose: false, opts }\n\t\tthis.commands.push(this.lastMoveTo)\n\t\treturn this\n\t}\n\n\tlineTo(x: number, y: number, opts?: PathBuilderCommandOpts) {\n\t\tthis.assertHasMoveTo()\n\t\tthis.commands.push({ type: 'line', x, y, isClose: false, opts })\n\t\treturn this\n\t}\n\n\tcircularArcTo(\n\t\tradius: number,\n\t\tlargeArcFlag: boolean,\n\t\tsweepFlag: boolean,\n\t\tx2: number,\n\t\ty2: number,\n\t\topts?: PathBuilderCommandOpts\n\t) {\n\t\treturn this.arcTo(radius, radius, largeArcFlag, sweepFlag, 0, x2, y2, opts)\n\t}\n\n\tarcTo(\n\t\trx: number,\n\t\try: number,\n\t\tlargeArcFlag: boolean,\n\t\tsweepFlag: boolean,\n\t\txAxisRotationRadians: number,\n\t\tx2: number,\n\t\ty2: number,\n\t\topts?: PathBuilderCommandOpts\n\t) {\n\t\t// As arc flags make them very sensitive to offsets when we render them in draw mode, we\n\t\t// approximate arcs by converting them to up to 4 (1 per 90\u00B0 segment) cubic bezier curves.\n\t\t// This algorithm is a Claude special:\n\t\t// https://claude.ai/public/artifacts/5ea0bf18-4afb-4b3d-948d-31b8a77ef1e2\n\n\t\tthis.assertHasMoveTo()\n\n\t\tconst x1 = this.commands[this.commands.length - 1].x\n\t\tconst y1 = this.commands[this.commands.length - 1].y\n\n\t\t// If the endpoints are identical, don't add a command\n\t\tif (x1 === x2 && y1 === y2) {\n\t\t\treturn this\n\t\t}\n\n\t\t// If rx or ry is 0, return a straight line\n\t\tif (rx === 0 || ry === 0) {\n\t\t\treturn this.lineTo(x2, y2, opts)\n\t\t}\n\n\t\t// Convert angle from degrees to radians\n\t\tconst phi = xAxisRotationRadians\n\t\tconst sinPhi = Math.sin(phi)\n\t\tconst cosPhi = Math.cos(phi)\n\n\t\t// Ensure rx and ry are positive\n\t\tlet rx1 = Math.abs(rx)\n\t\tlet ry1 = Math.abs(ry)\n\n\t\t// Step 1: Compute (x1', y1') - transform from ellipse coordinate system to unit circle\n\t\tconst dx = (x1 - x2) / 2\n\t\tconst dy = (y1 - y2) / 2\n\t\tconst x1p = cosPhi * dx + sinPhi * dy\n\t\tconst y1p = -sinPhi * dx + cosPhi * dy\n\n\t\t// Correction of out-of-range radii\n\t\tconst lambda = (x1p * x1p) / (rx1 * rx1) + (y1p * y1p) / (ry1 * ry1)\n\t\tif (lambda > 1) {\n\t\t\tconst sqrtLambda = Math.sqrt(lambda)\n\t\t\trx1 *= sqrtLambda\n\t\t\try1 *= sqrtLambda\n\t\t}\n\n\t\t// Step 2: Compute (cx', cy') - center of ellipse in transformed system\n\t\tconst sign = largeArcFlag !== sweepFlag ? 1 : -1\n\n\t\tconst term = rx1 * rx1 * ry1 * ry1 - rx1 * rx1 * y1p * y1p - ry1 * ry1 * x1p * x1p\n\t\tconst numerator = rx1 * rx1 * y1p * y1p + ry1 * ry1 * x1p * x1p\n\n\t\tlet radicand = term / numerator\n\t\tradicand = radicand < 0 ? 0 : radicand\n\n\t\tconst coef = sign * Math.sqrt(radicand)\n\n\t\tconst cxp = coef * ((rx1 * y1p) / ry1)\n\t\tconst cyp = coef * (-(ry1 * x1p) / rx1)\n\n\t\t// Step 3: Compute (cx, cy) from (cx', cy') - transform back to original coordinate system\n\t\tconst cx = cosPhi * cxp - sinPhi * cyp + (x1 + x2) / 2\n\t\tconst cy = sinPhi * cxp + cosPhi * cyp + (y1 + y2) / 2\n\n\t\t// Step 4: Compute the start and end angles\n\t\tconst ux = (x1p - cxp) / rx1\n\t\tconst uy = (y1p - cyp) / ry1\n\t\tconst vx = (-x1p - cxp) / rx1\n\t\tconst vy = (-y1p - cyp) / ry1\n\n\t\tconst startAngle = Math.atan2(uy, ux)\n\t\tlet endAngle = Math.atan2(vy, vx)\n\n\t\t// Ensure correct sweep direction\n\t\tif (!sweepFlag && endAngle > startAngle) {\n\t\t\tendAngle -= 2 * Math.PI\n\t\t} else if (sweepFlag && endAngle < startAngle) {\n\t\t\tendAngle += 2 * Math.PI\n\t\t}\n\n\t\t// Calculate the sweep angle\n\t\tconst sweepAngle = endAngle - startAngle\n\n\t\t// Approximate the arc using cubic bezier curves\n\t\tconst numSegments = Math.min(4, Math.ceil(Math.abs(sweepAngle) / (Math.PI / 2)))\n\t\tconst anglePerSegment = sweepAngle / numSegments\n\n\t\t// Helper function to compute point on ellipse\n\t\tconst ellipsePoint = (angle: number) => {\n\t\t\treturn {\n\t\t\t\tx: cx + rx1 * Math.cos(angle) * cosPhi - ry1 * Math.sin(angle) * sinPhi,\n\t\t\t\ty: cy + rx1 * Math.cos(angle) * sinPhi + ry1 * Math.sin(angle) * cosPhi,\n\t\t\t}\n\t\t}\n\n\t\t// Helper function to compute derivative (tangent vector) at a point on the ellipse\n\t\tconst ellipseDerivative = (angle: number) => {\n\t\t\treturn {\n\t\t\t\tx: -rx1 * Math.sin(angle) * cosPhi - ry1 * Math.cos(angle) * sinPhi,\n\t\t\t\ty: -rx1 * Math.sin(angle) * sinPhi + ry1 * Math.cos(angle) * cosPhi,\n\t\t\t}\n\t\t}\n\n\t\t// Generate cubic bezier approximations\n\t\tfor (let i = 0; i < numSegments; i++) {\n\t\t\tconst theta1 = startAngle + i * anglePerSegment\n\t\t\tconst theta2 = startAngle + (i + 1) * anglePerSegment\n\t\t\tconst deltaTheta = theta2 - theta1\n\n\t\t\tconst start = ellipsePoint(theta1)\n\t\t\tconst end = ellipsePoint(theta2)\n\n\t\t\t// Get the derivative at the start and end points\n\t\t\tconst d1 = ellipseDerivative(theta1)\n\t\t\tconst d2 = ellipseDerivative(theta2)\n\n\t\t\t// Calculate the length of the tangent handles\n\t\t\t// This is a key factor for the accuracy of the approximation\n\t\t\t// For a 90\u00B0 arc, the handle length should be 4/3 * tan(\u03C0/8) * r\n\t\t\t// For smaller arcs, we scale this value by the angle ratio\n\t\t\tconst handleScale = (4 / 3) * Math.tan(deltaTheta / 4)\n\n\t\t\t// Create control points that are tangent to the ellipse at the endpoints\n\t\t\tconst cp1x = start.x + handleScale * d1.x\n\t\t\tconst cp1y = start.y + handleScale * d1.y\n\n\t\t\tconst cp2x = end.x - handleScale * d2.x\n\t\t\tconst cp2y = end.y - handleScale * d2.y\n\n\t\t\tconst bezierOpts = i === 0 ? opts : { ...opts, mergeWithPrevious: true }\n\t\t\tthis.cubicBezierTo(end.x, end.y, cp1x, cp1y, cp2x, cp2y, bezierOpts)\n\t\t}\n\n\t\treturn this\n\t}\n\n\tcubicBezierTo(\n\t\tx: number,\n\t\ty: number,\n\t\tcp1X: number,\n\t\tcp1Y: number,\n\t\tcp2X: number,\n\t\tcp2Y: number,\n\t\topts?: PathBuilderCommandOpts\n\t) {\n\t\tthis.assertHasMoveTo()\n\t\tthis.commands.push({\n\t\t\ttype: 'cubic',\n\t\t\tx,\n\t\t\ty,\n\t\t\tcp1: { x: cp1X, y: cp1Y },\n\t\t\tcp2: { x: cp2X, y: cp2Y },\n\t\t\tisClose: false,\n\t\t\topts,\n\t\t})\n\t\treturn this\n\t}\n\n\tclose() {\n\t\tconst lastMoveTo = this.assertHasMoveTo()\n\t\tconst lastCommand = this.commands[this.commands.length - 1]\n\n\t\tif (approximately(lastMoveTo.x, lastCommand.x) && approximately(lastMoveTo.y, lastCommand.y)) {\n\t\t\tlastCommand.isClose = true\n\t\t} else {\n\t\t\tthis.commands.push({\n\t\t\t\ttype: 'line',\n\t\t\t\tx: lastMoveTo.x,\n\t\t\t\ty: lastMoveTo.y,\n\t\t\t\tisClose: true,\n\t\t\t})\n\t\t}\n\n\t\tlastMoveTo.closeIdx = this.commands.length - 1\n\t\tthis.lastMoveTo = null\n\t\treturn this\n\t}\n\n\ttoD(opts: PathBuilderToDOpts = {}) {\n\t\tconst { startIdx = 0, endIdx = this.commands.length, onlyFilled = false } = opts\n\t\tconst parts = []\n\n\t\tlet isSkippingCurrentLine = false\n\n\t\tlet didAddMove = false\n\t\tlet didAddNaturalMove = false\n\n\t\tconst addMoveIfNeeded = (i: number) => {\n\t\t\tif (didAddMove || i === 0) return\n\t\t\tdidAddMove = true\n\t\t\tconst command = this.commands[i - 1]\n\t\t\tparts.push('M', toDomPrecision(command.x), toDomPrecision(command.y))\n\t\t}\n\n\t\tfor (let i = startIdx; i < endIdx; i++) {\n\t\t\tconst command = this.commands[i]\n\t\t\tswitch (command.type) {\n\t\t\t\tcase 'move': {\n\t\t\t\t\tconst isFilled =\n\t\t\t\t\t\tcommand.opts?.geometry === false ? false : (command.opts?.geometry?.isFilled ?? false)\n\t\t\t\t\tif (onlyFilled && !isFilled) {\n\t\t\t\t\t\tisSkippingCurrentLine = true\n\t\t\t\t\t} else {\n\t\t\t\t\t\tisSkippingCurrentLine = false\n\t\t\t\t\t\tdidAddMove = true\n\t\t\t\t\t\tdidAddNaturalMove = true\n\t\t\t\t\t\tparts.push('M', toDomPrecision(command.x), toDomPrecision(command.y))\n\t\t\t\t\t}\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tcase 'line':\n\t\t\t\t\tif (isSkippingCurrentLine) break\n\t\t\t\t\taddMoveIfNeeded(i)\n\t\t\t\t\tif (command.isClose && didAddNaturalMove) {\n\t\t\t\t\t\tparts.push('Z')\n\t\t\t\t\t} else {\n\t\t\t\t\t\tparts.push('L', toDomPrecision(command.x), toDomPrecision(command.y))\n\t\t\t\t\t}\n\t\t\t\t\tbreak\n\t\t\t\tcase 'cubic':\n\t\t\t\t\tif (isSkippingCurrentLine) break\n\t\t\t\t\taddMoveIfNeeded(i)\n\t\t\t\t\tparts.push(\n\t\t\t\t\t\t'C',\n\t\t\t\t\t\ttoDomPrecision(command.cp1.x),\n\t\t\t\t\t\ttoDomPrecision(command.cp1.y),\n\t\t\t\t\t\ttoDomPrecision(command.cp2.x),\n\t\t\t\t\t\ttoDomPrecision(command.cp2.y),\n\t\t\t\t\t\ttoDomPrecision(command.x),\n\t\t\t\t\t\ttoDomPrecision(command.y)\n\t\t\t\t\t)\n\t\t\t\t\tbreak\n\t\t\t\tdefault:\n\t\t\t\t\texhaustiveSwitchError(command, 'type')\n\t\t\t}\n\t\t}\n\t\treturn parts.join(' ')\n\t}\n\n\ttoSvg(opts: PathBuilderOpts) {\n\t\tif (opts.forceSolid) {\n\t\t\treturn this.toSolidSvg(opts)\n\t\t}\n\t\tswitch (opts.style) {\n\t\t\tcase 'solid':\n\t\t\t\treturn this.toSolidSvg(opts)\n\t\t\tcase 'dashed':\n\t\t\tcase 'dotted':\n\t\t\t\treturn this.toDashedSvg(opts)\n\t\t\tcase 'draw': {\n\t\t\t\tconst d = this.toDrawSvg(opts)\n\t\t\t\treturn d\n\t\t\t}\n\t\t\tdefault:\n\t\t\t\texhaustiveSwitchError(opts, 'style')\n\t\t}\n\t}\n\n\ttoGeometry(): PathBuilderGeometry2d | Group2d {\n\t\tconst geometries = []\n\n\t\tlet current: null | {\n\t\t\tstartIdx: number\n\t\t\tmoveCommand: MoveToPathBuilderCommand\n\t\t\tisClosed: boolean\n\t\t\topts?: PathBuilderLineOpts\n\t\t} = null\n\t\tfor (let i = 0; i < this.commands.length; i++) {\n\t\t\tconst command = this.commands[i]\n\n\t\t\tif (command.type === 'move') {\n\t\t\t\tif (current && current.opts?.geometry !== false) {\n\t\t\t\t\tgeometries.push(\n\t\t\t\t\t\tnew PathBuilderGeometry2d(this, current.startIdx, i, {\n\t\t\t\t\t\t\t...current.opts?.geometry,\n\t\t\t\t\t\t\tisFilled: current.opts?.geometry?.isFilled ?? false,\n\t\t\t\t\t\t\tisClosed: current.moveCommand.closeIdx !== null,\n\t\t\t\t\t\t})\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t\tcurrent = { startIdx: i, moveCommand: command, opts: command.opts, isClosed: false }\n\t\t\t}\n\n\t\t\tif (command.isClose) {\n\t\t\t\tassert(current, 'No current move command')\n\t\t\t\tcurrent.isClosed = true\n\t\t\t}\n\t\t}\n\n\t\tif (current && current.opts?.geometry !== false) {\n\t\t\tgeometries.push(\n\t\t\t\tnew PathBuilderGeometry2d(this, current.startIdx, this.commands.length, {\n\t\t\t\t\t...current.opts?.geometry,\n\t\t\t\t\tisFilled: current.opts?.geometry?.isFilled ?? false,\n\t\t\t\t\tisClosed: current.moveCommand.closeIdx !== null,\n\t\t\t\t})\n\t\t\t)\n\t\t}\n\n\t\tassert(geometries.length > 0)\n\t\tif (geometries.length === 1) return geometries[0]\n\t\treturn new Group2d({ children: geometries })\n\t}\n\n\tprivate toSolidSvg(opts: PathBuilderOpts) {\n\t\tconst { strokeWidth, props } = opts\n\n\t\treturn (\n\t\t\t<path strokeWidth={strokeWidth} d={this.toD({ onlyFilled: opts.onlyFilled })} {...props} />\n\t\t)\n\t}\n\n\tprivate toDashedSvg(opts: DashedPathBuilderOpts) {\n\t\tconst {\n\t\t\tstyle,\n\t\t\tstrokeWidth,\n\t\t\tsnap,\n\t\t\tlengthRatio,\n\t\t\tprops: { markerStart, markerEnd, ...props } = {},\n\t\t} = opts\n\n\t\tconst parts: ReactNode[] = []\n\n\t\tlet isCurrentPathClosed = false\n\t\tlet isSkippingCurrentLine = false\n\t\tlet currentLineOpts: PathBuilderLineOpts | undefined = undefined\n\n\t\tlet currentRun: {\n\t\t\tstartIdx: number\n\t\t\tendIdx: number\n\t\t\tisFirst: boolean\n\t\t\tisLast: boolean\n\t\t\tlength: number\n\t\t\tlineOpts: PathBuilderLineOpts | undefined\n\t\t\tpathIsClosed: boolean\n\t\t} | null = null\n\n\t\tconst addCurrentRun = () => {\n\t\t\tif (!currentRun) return\n\t\t\tconst { startIdx, endIdx, isFirst, isLast, length, lineOpts, pathIsClosed } = currentRun\n\t\t\tcurrentRun = null\n\n\t\t\tif (startIdx === endIdx && this.commands[startIdx].type === 'move') return\n\n\t\t\tconst start = lineOpts?.dashStart ?? opts.start\n\t\t\tconst end = lineOpts?.dashEnd ?? opts.end\n\t\t\tconst { strokeDasharray, strokeDashoffset } = getPerfectDashProps(length, strokeWidth, {\n\t\t\t\tstyle,\n\t\t\t\tsnap,\n\t\t\t\tlengthRatio,\n\t\t\t\tstart: isFirst ? (start ?? (pathIsClosed ? 'outset' : 'none')) : 'outset',\n\t\t\t\tend: isLast ? (end ?? (pathIsClosed ? 'outset' : 'none')) : 'outset',\n\t\t\t})\n\n\t\t\tconst d = this.toD({ startIdx, endIdx: endIdx + 1 })\n\t\t\tparts.push(\n\t\t\t\t<path\n\t\t\t\t\tkey={parts.length}\n\t\t\t\t\td={d}\n\t\t\t\t\tstrokeDasharray={strokeDasharray}\n\t\t\t\t\tstrokeDashoffset={strokeDashoffset}\n\t\t\t\t\tmarkerStart={isFirst ? markerStart : undefined}\n\t\t\t\t\tmarkerEnd={isLast ? markerEnd : undefined}\n\t\t\t\t/>\n\t\t\t)\n\t\t}\n\n\t\tfor (let i = 0; i < this.commands.length; i++) {\n\t\t\tconst command = this.commands[i]\n\t\t\tconst lastCommand = this.commands[i - 1]\n\t\t\tif (command.type === 'move') {\n\t\t\t\tisCurrentPathClosed = command.closeIdx !== null\n\t\t\t\tconst isFilled =\n\t\t\t\t\tcommand.opts?.geometry === false ? false : (command.opts?.geometry?.isFilled ?? false)\n\t\t\t\tif (opts.onlyFilled && !isFilled) {\n\t\t\t\t\tisSkippingCurrentLine = true\n\t\t\t\t} else {\n\t\t\t\t\tisSkippingCurrentLine = false\n\t\t\t\t\tcurrentLineOpts = command.opts\n\t\t\t\t}\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif (isSkippingCurrentLine) continue\n\n\t\t\tconst segmentLength = this.calculateSegmentLength(lastCommand, command)\n\t\t\tconst isFirst = lastCommand.type === 'move'\n\t\t\tconst isLast =\n\t\t\t\tcommand.isClose || i === this.commands.length - 1 || this.commands[i + 1]?.type === 'move'\n\n\t\t\tif (currentRun && command.opts?.mergeWithPrevious) {\n\t\t\t\tcurrentRun.length += segmentLength\n\t\t\t\tcurrentRun.endIdx = i\n\t\t\t\tcurrentRun.isLast = isLast\n\t\t\t} else {\n\t\t\t\taddCurrentRun()\n\t\t\t\tcurrentRun = {\n\t\t\t\t\tstartIdx: i,\n\t\t\t\t\tendIdx: i,\n\t\t\t\t\tisFirst,\n\t\t\t\t\tisLast,\n\t\t\t\t\tlength: segmentLength,\n\t\t\t\t\tlineOpts: currentLineOpts,\n\t\t\t\t\tpathIsClosed: isCurrentPathClosed,\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\taddCurrentRun()\n\n\t\treturn (\n\t\t\t<g strokeWidth={strokeWidth} {...props}>\n\t\t\t\t{parts}\n\t\t\t</g>\n\t\t)\n\t}\n\n\tprivate toDrawSvg(opts: DrawPathBuilderOpts) {\n\t\treturn <path strokeWidth={opts.strokeWidth} d={this.toDrawD(opts)} {...opts.props} />\n\t}\n\n\ttoDrawD(opts: DrawPathBuilderDOpts) {\n\t\tconst {\n\t\t\tstrokeWidth,\n\t\t\trandomSeed,\n\t\t\toffset: defaultOffset = strokeWidth / 3,\n\t\t\troundness: defaultRoundness = strokeWidth * 2,\n\t\t\tpasses = 2,\n\t\t\tonlyFilled = false,\n\t\t} = opts\n\n\t\tconst parts = []\n\n\t\tconst commandInfo = this.getCommandInfo()\n\n\t\t// for each command, we draw the line for the command, plus the corner to the next command.\n\t\tconst drawCommands = []\n\t\tlet lastMoveCommandIdx = null\n\t\tfor (let i = 0; i < this.commands.length; i++) {\n\t\t\tconst command = this.commands[i]\n\t\t\tconst offset = command.opts?.offset ?? defaultOffset\n\t\t\tconst roundness = command.opts?.roundness ?? defaultRoundness\n\n\t\t\tif (command.type === 'move') {\n\t\t\t\tlastMoveCommandIdx = i\n\t\t\t}\n\n\t\t\tconst nextIdx = command.isClose\n\t\t\t\t? assertExists(lastMoveCommandIdx) + 1\n\t\t\t\t: !this.commands[i + 1] || this.commands[i + 1].type === 'move'\n\t\t\t\t\t? undefined\n\t\t\t\t\t: i + 1\n\n\t\t\tconst nextInfo =\n\t\t\t\tnextIdx !== undefined && this.commands[nextIdx] && this.commands[nextIdx]?.type !== 'move'\n\t\t\t\t\t? commandInfo[nextIdx]\n\t\t\t\t\t: undefined\n\n\t\t\tconst currentSupportsRoundness = commandsSupportingRoundness[command.type]\n\t\t\tconst nextSupportsRoundness =\n\t\t\t\tnextIdx !== undefined ? commandsSupportingRoundness[this.commands[nextIdx].type] : false\n\n\t\t\tconst currentInfo = commandInfo[i]\n\n\t\t\tconst tangentToPrev = currentInfo?.tangentEnd\n\t\t\tconst tangentToNext = nextInfo?.tangentStart\n\n\t\t\tconst roundnessClampedForAngle =\n\t\t\t\tcurrentSupportsRoundness &&\n\t\t\t\tnextSupportsRoundness &&\n\t\t\t\ttangentToPrev &&\n\t\t\t\ttangentToNext &&\n\t\t\t\tVec.Len2(tangentToPrev) > 0.01 &&\n\t\t\t\tVec.Len2(tangentToNext) > 0.01\n\t\t\t\t\t? modulate(\n\t\t\t\t\t\t\tMath.abs(Vec.AngleBetween(tangentToPrev, tangentToNext)),\n\t\t\t\t\t\t\t[Math.PI / 2, Math.PI],\n\t\t\t\t\t\t\t[roundness, 0],\n\t\t\t\t\t\t\ttrue\n\t\t\t\t\t\t)\n\t\t\t\t\t: 0\n\n\t\t\tconst shortestDistance = Math.min(\n\t\t\t\tcurrentInfo?.length ?? Infinity,\n\t\t\t\tnextInfo?.length ?? Infinity\n\t\t\t)\n\t\t\tconst offsetLimit = shortestDistance - roundnessClampedForAngle * 2\n\n\t\t\tconst offsetAmount = clamp(offset, 0, offsetLimit / 4)\n\n\t\t\tconst roundnessBeforeClampedForLength = Math.min(\n\t\t\t\troundnessClampedForAngle,\n\t\t\t\t(currentInfo?.length ?? Infinity) / 4\n\t\t\t)\n\t\t\tconst roundnessAfterClampedForLength = Math.min(\n\t\t\t\troundnessClampedForAngle,\n\t\t\t\t(nextInfo?.length ?? Infinity) / 4\n\t\t\t)\n\n\t\t\tconst drawCommand = {\n\t\t\t\tcommand,\n\t\t\t\toffsetAmount,\n\t\t\t\troundnessBefore: roundnessBeforeClampedForLength,\n\t\t\t\troundnessAfter: roundnessAfterClampedForLength,\n\t\t\t\ttangentToPrev: commandInfo[i]?.tangentEnd,\n\t\t\t\ttangentToNext: nextInfo?.tangentStart,\n\t\t\t\tmoveDidClose: false,\n\t\t\t}\n\n\t\t\tdrawCommands.push(drawCommand)\n\n\t\t\tif (command.isClose && lastMoveCommandIdx !== null) {\n\t\t\t\tconst lastMoveCommand = drawCommands[lastMoveCommandIdx]\n\t\t\t\tlastMoveCommand.moveDidClose = true\n\t\t\t\tlastMoveCommand.roundnessAfter = roundnessAfterClampedForLength\n\t\t\t} else if (command.type === 'move') {\n\t\t\t\tlastMoveCommandIdx = i\n\t\t\t}\n\t\t}\n\n\t\tfor (let pass = 0; pass < passes; pass++) {\n\t\t\tconst random = rng(randomSeed + pass)\n\n\t\t\tlet lastMoveToOffset = { x: 0, y: 0 }\n\t\t\tlet isSkippingCurrentLine = false\n\t\t\tfor (const {\n\t\t\t\tcommand,\n\t\t\t\toffsetAmount,\n\t\t\t\troundnessBefore,\n\t\t\t\troundnessAfter,\n\t\t\t\ttangentToNext,\n\t\t\t\ttangentToPrev,\n\t\t\t} of drawCommands) {\n\t\t\t\tconst offset = command.isClose\n\t\t\t\t\t? lastMoveToOffset\n\t\t\t\t\t: { x: random() * offsetAmount, y: random() * offsetAmount }\n\n\t\t\t\tif (command.type === 'move') {\n\t\t\t\t\tlastMoveToOffset = offset\n\t\t\t\t\tconst isFilled =\n\t\t\t\t\t\tcommand.opts?.geometry === false ? false : (command.opts?.geometry?.isFilled ?? false)\n\t\t\t\t\tif (onlyFilled && !isFilled) {\n\t\t\t\t\t\tisSkippingCurrentLine = true\n\t\t\t\t\t} else {\n\t\t\t\t\t\tisSkippingCurrentLine = false\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (isSkippingCurrentLine) continue\n\n\t\t\t\tconst offsetPoint = Vec.Add(command, offset)\n\n\t\t\t\tconst endPoint =\n\t\t\t\t\ttangentToNext && roundnessAfter > 0\n\t\t\t\t\t\t? Vec.Mul(tangentToNext, -roundnessAfter).add(offsetPoint)\n\t\t\t\t\t\t: offsetPoint\n\n\t\t\t\tconst startPoint =\n\t\t\t\t\ttangentToPrev && roundnessBefore > 0\n\t\t\t\t\t\t? Vec.Mul(tangentToPrev, roundnessBefore).add(offsetPoint)\n\t\t\t\t\t\t: offsetPoint\n\n\t\t\t\tif (endPoint === offsetPoint || startPoint === offsetPoint) {\n\t\t\t\t\tswitch (command.type) {\n\t\t\t\t\t\tcase 'move':\n\t\t\t\t\t\t\tparts.push('M', toDomPrecision(endPoint.x), toDomPrecision(endPoint.y))\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\tcase 'line':\n\t\t\t\t\t\t\tparts.push('L', toDomPrecision(endPoint.x), toDomPrecision(endPoint.y))\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\tcase 'cubic': {\n\t\t\t\t\t\t\tconst offsetCp1 = Vec.Add(command.cp1, offset)\n\t\t\t\t\t\t\tconst offsetCp2 = Vec.Add(command.cp2, offset)\n\t\t\t\t\t\t\tparts.push(\n\t\t\t\t\t\t\t\t'C',\n\t\t\t\t\t\t\t\ttoDomPrecision(offsetCp1.x),\n\t\t\t\t\t\t\t\ttoDomPrecision(offsetCp1.y),\n\t\t\t\t\t\t\t\ttoDomPrecision(offsetCp2.x),\n\t\t\t\t\t\t\t\ttoDomPrecision(offsetCp2.y),\n\t\t\t\t\t\t\t\ttoDomPrecision(endPoint.x),\n\t\t\t\t\t\t\t\ttoDomPrecision(endPoint.y)\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\texhaustiveSwitchError(command, 'type')\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tswitch (command.type) {\n\t\t\t\t\t\tcase 'move':\n\t\t\t\t\t\t\tparts.push('M', toDomPrecision(endPoint.x), toDomPrecision(endPoint.y))\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\tcase 'line':\n\t\t\t\t\t\t\tparts.push(\n\t\t\t\t\t\t\t\t'L',\n\t\t\t\t\t\t\t\ttoDomPrecision(startPoint.x),\n\t\t\t\t\t\t\t\ttoDomPrecision(startPoint.y),\n\n\t\t\t\t\t\t\t\t'Q',\n\t\t\t\t\t\t\t\ttoDomPrecision(offsetPoint.x),\n\t\t\t\t\t\t\t\ttoDomPrecision(offsetPoint.y),\n\t\t\t\t\t\t\t\ttoDomPrecision(endPoint.x),\n\t\t\t\t\t\t\t\ttoDomPrecision(endPoint.y)\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\tcase 'cubic': {\n\t\t\t\t\t\t\tconst offsetCp1 = Vec.Add(command.cp1, offset)\n\t\t\t\t\t\t\tconst offsetCp2 = Vec.Add(command.cp2, offset)\n\t\t\t\t\t\t\tparts.push(\n\t\t\t\t\t\t\t\t'C',\n\t\t\t\t\t\t\t\ttoDomPrecision(offsetCp1.x),\n\t\t\t\t\t\t\t\ttoDomPrecision(offsetCp1.y),\n\t\t\t\t\t\t\t\ttoDomPrecision(offsetCp2.x),\n\t\t\t\t\t\t\t\ttoDomPrecision(offsetCp2.y),\n\t\t\t\t\t\t\t\ttoDomPrecision(offsetPoint.x),\n\t\t\t\t\t\t\t\ttoDomPrecision(offsetPoint.y)\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\texhaustiveSwitchError(command, 'type')\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn parts.join(' ')\n\t}\n\n\tprivate calculateSegmentLength(lastPoint: VecLike, command: PathBuilderCommand) {\n\t\tswitch (command.type) {\n\t\t\tcase 'move':\n\t\t\t\treturn 0\n\t\t\tcase 'line':\n\t\t\t\treturn Vec.Dist(lastPoint, command)\n\t\t\tcase 'cubic':\n\t\t\t\treturn CubicBezier.length(\n\t\t\t\t\tlastPoint.x,\n\t\t\t\t\tlastPoint.y,\n\t\t\t\t\tcommand.cp1.x,\n\t\t\t\t\tcommand.cp1.y,\n\t\t\t\t\tcommand.cp2.x,\n\t\t\t\t\tcommand.cp2.y,\n\t\t\t\t\tcommand.x,\n\t\t\t\t\tcommand.y\n\t\t\t\t)\n\t\t\tdefault:\n\t\t\t\texhaustiveSwitchError(command, 'type')\n\t\t}\n\t}\n\n\t/** @internal */\n\tgetCommands(): readonly PathBuilderCommand[] {\n\t\treturn this.commands\n\t}\n\n\t/** @internal */\n\tgetCommandInfo() {\n\t\tconst commandInfo: Array<undefined | PathBuilderCommandInfo> = []\n\t\tfor (let i = 1; i < this.commands.length; i++) {\n\t\t\tconst previous = this.commands[i - 1]\n\t\t\tconst current = this.commands[i]\n\n\t\t\tif (current._info) {\n\t\t\t\tcommandInfo[i] = current._info\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif (current.type === 'move') {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tlet tangentStart, tangentEnd\n\t\t\tswitch (current.type) {\n\t\t\t\tcase 'line':\n\t\t\t\t\ttangentStart = tangentEnd = Vec.Sub(previous, current).uni()\n\t\t\t\t\tbreak\n\t\t\t\tcase 'cubic': {\n\t\t\t\t\ttangentStart = Vec.Sub(current.cp1, previous).uni()\n\t\t\t\t\ttangentEnd = Vec.Sub(current.cp2, current).uni()\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t\texhaustiveSwitchError(current, 'type')\n\t\t\t}\n\n\t\t\tcurrent._info = {\n\t\t\t\ttangentStart,\n\t\t\t\ttangentEnd,\n\t\t\t\tlength: this.calculateSegmentLength(previous, current),\n\t\t\t}\n\t\t\tcommandInfo[i] = current._info\n\t\t}\n\n\t\treturn commandInfo\n\t}\n}\n\nconst commandsSupportingRoundness = {\n\tline: true,\n\tmove: true,\n\tcubic: false,\n} as const satisfies Record<PathBuilderCommand['type'], boolean>\n\n/** @public */\nexport class PathBuilderGeometry2d extends Geometry2d {\n\tconstructor(\n\t\tprivate readonly path: PathBuilder,\n\t\tprivate readonly startIdx: number,\n\t\tprivate readonly endIdx: number,\n\t\toptions: Geometry2dOptions\n\t) {\n\t\tsuper(options)\n\t}\n\n\tprivate _segments: Geometry2d[] | null = null\n\tgetSegments() {\n\t\tif (this._segments) return this._segments\n\n\t\tthis._segments = []\n\t\tlet last = this.path.commands[this.startIdx]\n\t\tassert(last.type === 'move')\n\n\t\tfor (let i = this.startIdx + 1; i < this.endIdx; i++) {\n\t\t\tconst command = this.path.commands[i]\n\t\t\tassert(command.type !== 'move')\n\n\t\t\tswitch (command.type) {\n\t\t\t\tcase 'line':\n\t\t\t\t\tthis._segments.push(new Edge2d({ start: Vec.From(last), end: Vec.From(command) }))\n\t\t\t\t\tbreak\n\t\t\t\tcase 'cubic': {\n\t\t\t\t\tthis._segments.push(\n\t\t\t\t\t\tnew CubicBezier2d({\n\t\t\t\t\t\t\tstart: Vec.From(last),\n\t\t\t\t\t\t\tcp1: Vec.From(command.cp1),\n\t\t\t\t\t\t\tcp2: Vec.From(command.cp2),\n\t\t\t\t\t\t\tend: Vec.From(command),\n\t\t\t\t\t\t})\n\t\t\t\t\t)\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t\texhaustiveSwitchError(command, 'type')\n\t\t\t}\n\n\t\t\tlast = command\n\t\t}\n\n\t\treturn this._segments\n\t}\n\n\toverride getVertices(filters: Geometry2dFilters): Vec[] {\n\t\tconst vs = this.getSegments()\n\t\t\t.flatMap((s) => s.getVertices(filters))\n\t\t\t.filter((vertex, i, vertices) => {\n\t\t\t\tconst prev = vertices[i - 1]\n\t\t\t\tif (!prev) return true\n\t\t\t\treturn !Vec.Equals(prev, vertex)\n\t\t\t})\n\n\t\tif (this.isClosed) {\n\t\t\tconst last = vs[vs.length - 1]\n\t\t\tconst first = vs[0]\n\t\t\tif (!Vec.Equals(last, first)) {\n\t\t\t\tvs.push(first)\n\t\t\t}\n\t\t}\n\n\t\treturn vs\n\t}\n\n\toverride nearestPoint(point: VecLike, _filters?: Geometry2dFilters): Vec {\n\t\tlet nearest: Vec | null = null\n\t\tlet nearestDistance = Infinity\n\n\t\tfor (const segment of this.getSegments()) {\n\t\t\tconst candidate = segment.nearestPoint(point)\n\t\t\tconst distance = Vec.Dist2(point, candidate)\n\t\t\tif (distance < nearestDistance) {\n\t\t\t\tnearestDistance = distance\n\t\t\t\tnearest = candidate\n\t\t\t}\n\t\t}\n\n\t\tassert(nearest, 'No nearest point found')\n\t\treturn nearest\n\t}\n\n\toverride hitTestLineSegment(\n\t\tA: VecLike,\n\t\tB: VecLike,\n\t\tdistance = 0,\n\t\tfilters?: Geometry2dFilters\n\t): boolean {\n\t\treturn super.hitTestLineSegment(A, B, distance, filters)\n\t}\n\toverride getSvgPathData(): string {\n\t\treturn this.path.toD({ startIdx: this.startIdx, endIdx: this.endIdx })\n\t}\n}\n\n/*!\n * Adapted from https://github.com/adobe-webplatform/Snap.svg/tree/master\n * Apache License: https://github.com/adobe-webplatform/Snap.svg/blob/master/LICENSE\n * https://github.com/adobe-webplatform/Snap.svg/blob/c8e483c9694517e24b282f8f59f985629f4994ce/dist/snap.svg.js#L5786\n */\nconst CubicBezier = {\n\tbase3(t: number, p1: number, p2: number, p3: number, p4: number) {\n\t\tconst t1 = -3 * p1 + 9 * p2 - 9 * p3 + 3 * p4\n\t\tconst t2 = t * t1 + 6 * p1 - 12 * p2 + 6 * p3\n\t\treturn t * t2 - 3 * p1 + 3 * p2\n\t},\n\t/**\n\t * Calculate the approximate length of a cubic bezier curve from (x1, y1) to (x4, y4) with\n\t * control points (x2, y2) and (x3, y3).\n\t */\n\tlength(\n\t\tx1: number,\n\t\ty1: number,\n\t\tx2: number,\n\t\ty2: number,\n\t\tx3: number,\n\t\ty3: number,\n\t\tx4: number,\n\t\ty4: number,\n\t\tz = 1\n\t) {\n\t\tz = z > 1 ? 1 : z < 0 ? 0 : z\n\t\tconst z2 = z / 2\n\t\tconst n = 12\n\n\t\tlet sum = 0\n\t\tsum = 0\n\t\tfor (let i = 0; i < n; i++) {\n\t\t\tconst ct = z2 * CubicBezier.Tvalues[i] + z2\n\t\t\tconst xbase = CubicBezier.base3(ct, x1, x2, x3, x4)\n\t\t\tconst ybase = CubicBezier.base3(ct, y1, y2, y3, y4)\n\t\t\tconst comb = xbase * xbase + ybase * ybase\n\t\t\tsum += CubicBezier.Cvalues[i] * Math.sqrt(comb)\n\t\t}\n\t\treturn z2 * sum\n\t},\n\tTvalues: [\n\t\t-0.1252, 0.1252, -0.3678, 0.3678, -0.5873, 0.5873, -0.7699, 0.7699, -0.9041, 0.9041, -0.9816,\n\t\t0.9816,\n\t],\n\tCvalues: [\n\t\t0.2491, 0.2491, 0.2335, 0.2335, 0.2032, 0.2032, 0.1601, 0.1601, 0.1069, 0.1069, 0.0472, 0.0472,\n\t],\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import {\n\tapproximately,\n\tassert,\n\tassertExists,\n\tclamp,\n\tCubicBezier2d,\n\tEdge2d,\n\texhaustiveSwitchError,\n\tGeometry2d,\n\tGeometry2dFilters,\n\tGeometry2dOptions,\n\tgetPerfectDashProps,\n\tgetVerticesCountForArcLength,\n\tGroup2d,\n\tmodulate,\n\tPerfectDashTerminal,\n\trng,\n\ttoDomPrecision,\n\tVec,\n\tVecLike,\n\tVecModel,\n} from '@tldraw/editor'\nimport { ReactNode, SVGProps } from 'react'\n\n/** @public */\nexport interface BasePathBuilderOpts {\n\tstrokeWidth: number\n\tforceSolid?: boolean\n\tonlyFilled?: boolean\n\tprops?: SVGProps<SVGPathElement & SVGGElement>\n}\n\n/** @public */\nexport interface SolidPathBuilderOpts extends BasePathBuilderOpts {\n\tstyle: 'solid'\n}\n\n/** @public */\nexport interface DashedPathBuilderOpts extends BasePathBuilderOpts {\n\tstyle: 'dashed' | 'dotted'\n\tsnap?: number\n\tend?: PerfectDashTerminal\n\tstart?: PerfectDashTerminal\n\tlengthRatio?: number\n}\n\n/** @public */\nexport interface DrawPathBuilderDOpts {\n\tstrokeWidth: number\n\trandomSeed: string\n\toffset?: number\n\troundness?: number\n\tpasses?: number\n\tonlyFilled?: boolean\n}\n\n/** @public */\nexport interface DrawPathBuilderOpts extends BasePathBuilderOpts, DrawPathBuilderDOpts {\n\tstyle: 'draw'\n}\n\n/** @public */\nexport type PathBuilderOpts = SolidPathBuilderOpts | DashedPathBuilderOpts | DrawPathBuilderOpts\n\n/** @public */\nexport interface PathBuilderCommandOpts {\n\t/**\n\t * When converting to a draw-style line, how much offset from the original point should be\n\t * applied?\n\t */\n\toffset?: number\n\t/**\n\t * When converting to a draw-style line, how much roundness should be applied to the end of this\n\t * line?\n\t */\n\troundness?: number\n\t/**\n\t * When converting to a dash- or dot-style line, should the current segment be merged with the\n\t * previous segment when calculating the dash pattern? This is false by default, meaning each\n\t * command will start/end on a dash/dot boundary.\n\t */\n\tmergeWithPrevious?: boolean\n}\n\n/** @internal */\nexport interface PathBuilderCommandInfo {\n\ttangentStart: VecModel\n\ttangentEnd: VecModel\n\tlength: number\n}\n\n/** @internal */\nexport interface PathBuilderCommandBase {\n\topts?: PathBuilderCommandOpts\n\tx: number\n\ty: number\n\tisClose: boolean\n\t_info?: PathBuilderCommandInfo\n}\n\n/** @public */\nexport interface PathBuilderLineOpts extends PathBuilderCommandOpts {\n\tgeometry?: Omit<Geometry2dOptions, 'isClosed'> | false\n\tdashStart?: PerfectDashTerminal\n\tdashEnd?: PerfectDashTerminal\n}\n\n/** @internal */\nexport interface MoveToPathBuilderCommand extends PathBuilderCommandBase {\n\ttype: 'move'\n\tcloseIdx: number | null\n\topts?: PathBuilderLineOpts\n}\n\n/** @internal */\nexport interface LineToPathBuilderCommand extends PathBuilderCommandBase {\n\ttype: 'line'\n}\n\n/** @internal */\nexport interface CubicBezierToPathBuilderCommand extends PathBuilderCommandBase {\n\ttype: 'cubic'\n\tcp1: VecModel\n\tcp2: VecModel\n\tresolution?: number\n}\n\n/** @internal */\nexport type PathBuilderCommand =\n\t| MoveToPathBuilderCommand\n\t| LineToPathBuilderCommand\n\t| CubicBezierToPathBuilderCommand\n\n/** @public */\nexport interface PathBuilderToDOpts {\n\tstartIdx?: number\n\tendIdx?: number\n\tonlyFilled?: boolean\n}\n\n/** @public */\nexport class PathBuilder {\n\tstatic lineThroughPoints(\n\t\tpoints: VecLike[],\n\t\topts?: PathBuilderLineOpts & { endOffsets?: number }\n\t) {\n\t\tconst path = new PathBuilder()\n\t\tpath.moveTo(points[0].x, points[0].y, { ...opts, offset: opts?.endOffsets ?? opts?.offset })\n\t\tfor (let i = 1; i < points.length; i++) {\n\t\t\tconst isLast = i === points.length - 1\n\t\t\tpath.lineTo(points[i].x, points[i].y, isLast ? { offset: opts?.endOffsets } : undefined)\n\t\t}\n\t\treturn path\n\t}\n\n\tstatic cubicSplineThroughPoints(\n\t\tpoints: VecLike[],\n\t\topts?: PathBuilderLineOpts & { endOffsets?: number }\n\t) {\n\t\tconst path = new PathBuilder()\n\t\tconst len = points.length\n\t\tconst last = len - 2\n\t\tconst k = 1.25\n\n\t\tpath.moveTo(points[0].x, points[0].y, { ...opts, offset: opts?.endOffsets ?? opts?.offset })\n\n\t\tfor (let i = 0; i < len - 1; i++) {\n\t\t\tconst p0 = i === 0 ? points[0] : points[i - 1]\n\t\t\tconst p1 = points[i]\n\t\t\tconst p2 = points[i + 1]\n\t\t\tconst p3 = i === last ? p2 : points[i + 2]\n\n\t\t\tlet cp1x, cp1y, cp2x, cp2y\n\t\t\tif (i === 0) {\n\t\t\t\tcp1x = p0.x\n\t\t\t\tcp1y = p0.y\n\t\t\t} else {\n\t\t\t\tcp1x = p1.x + ((p2.x - p0.x) / 6) * k\n\t\t\t\tcp1y = p1.y + ((p2.y - p0.y) / 6) * k\n\t\t\t}\n\n\t\t\tlet pointOpts = undefined\n\t\t\tif (i === last) {\n\t\t\t\tcp2x = p2.x\n\t\t\t\tcp2y = p2.y\n\t\t\t\tpointOpts = { offset: opts?.endOffsets }\n\t\t\t} else {\n\t\t\t\tcp2x = p2.x - ((p3.x - p1.x) / 6) * k\n\t\t\t\tcp2y = p2.y - ((p3.y - p1.y) / 6) * k\n\t\t\t}\n\n\t\t\tpath.cubicBezierTo(p2.x, p2.y, cp1x, cp1y, cp2x, cp2y, pointOpts)\n\t\t}\n\n\t\treturn path\n\t}\n\n\tconstructor() {}\n\n\t/** @internal */\n\tcommands: PathBuilderCommand[] = []\n\n\tprivate lastMoveTo: MoveToPathBuilderCommand | null = null\n\tprivate assertHasMoveTo() {\n\t\tassert(this.lastMoveTo, 'Start an SVGPathBuilder with `.moveTo()`')\n\t\treturn this.lastMoveTo\n\t}\n\n\tmoveTo(x: number, y: number, opts?: PathBuilderLineOpts) {\n\t\tthis.lastMoveTo = { type: 'move', x, y, closeIdx: null, isClose: false, opts }\n\t\tthis.commands.push(this.lastMoveTo)\n\t\treturn this\n\t}\n\n\tlineTo(x: number, y: number, opts?: PathBuilderCommandOpts) {\n\t\tthis.assertHasMoveTo()\n\t\tthis.commands.push({ type: 'line', x, y, isClose: false, opts })\n\t\treturn this\n\t}\n\n\tcircularArcTo(\n\t\tradius: number,\n\t\tlargeArcFlag: boolean,\n\t\tsweepFlag: boolean,\n\t\tx2: number,\n\t\ty2: number,\n\t\topts?: PathBuilderCommandOpts\n\t) {\n\t\treturn this.arcTo(radius, radius, largeArcFlag, sweepFlag, 0, x2, y2, opts)\n\t}\n\n\tarcTo(\n\t\trx: number,\n\t\try: number,\n\t\tlargeArcFlag: boolean,\n\t\tsweepFlag: boolean,\n\t\txAxisRotationRadians: number,\n\t\tx2: number,\n\t\ty2: number,\n\t\topts?: PathBuilderCommandOpts\n\t) {\n\t\t// As arc flags make them very sensitive to offsets when we render them in draw mode, we\n\t\t// approximate arcs by converting them to up to 4 (1 per 90\u00B0 segment) cubic bezier curves.\n\t\t// This algorithm is a Claude special:\n\t\t// https://claude.ai/public/artifacts/5ea0bf18-4afb-4b3d-948d-31b8a77ef1e2\n\n\t\tthis.assertHasMoveTo()\n\n\t\tconst x1 = this.commands[this.commands.length - 1].x\n\t\tconst y1 = this.commands[this.commands.length - 1].y\n\n\t\t// If the endpoints are identical, don't add a command\n\t\tif (x1 === x2 && y1 === y2) {\n\t\t\treturn this\n\t\t}\n\n\t\t// If rx or ry is 0, return a straight line\n\t\tif (rx === 0 || ry === 0) {\n\t\t\treturn this.lineTo(x2, y2, opts)\n\t\t}\n\n\t\t// Convert angle from degrees to radians\n\t\tconst phi = xAxisRotationRadians\n\t\tconst sinPhi = Math.sin(phi)\n\t\tconst cosPhi = Math.cos(phi)\n\n\t\t// Ensure rx and ry are positive\n\t\tlet rx1 = Math.abs(rx)\n\t\tlet ry1 = Math.abs(ry)\n\n\t\t// Step 1: Compute (x1', y1') - transform from ellipse coordinate system to unit circle\n\t\tconst dx = (x1 - x2) / 2\n\t\tconst dy = (y1 - y2) / 2\n\t\tconst x1p = cosPhi * dx + sinPhi * dy\n\t\tconst y1p = -sinPhi * dx + cosPhi * dy\n\n\t\t// Correction of out-of-range radii\n\t\tconst lambda = (x1p * x1p) / (rx1 * rx1) + (y1p * y1p) / (ry1 * ry1)\n\t\tif (lambda > 1) {\n\t\t\tconst sqrtLambda = Math.sqrt(lambda)\n\t\t\trx1 *= sqrtLambda\n\t\t\try1 *= sqrtLambda\n\t\t}\n\n\t\t// Step 2: Compute (cx', cy') - center of ellipse in transformed system\n\t\tconst sign = largeArcFlag !== sweepFlag ? 1 : -1\n\n\t\tconst term = rx1 * rx1 * ry1 * ry1 - rx1 * rx1 * y1p * y1p - ry1 * ry1 * x1p * x1p\n\t\tconst numerator = rx1 * rx1 * y1p * y1p + ry1 * ry1 * x1p * x1p\n\n\t\tlet radicand = term / numerator\n\t\tradicand = radicand < 0 ? 0 : radicand\n\n\t\tconst coef = sign * Math.sqrt(radicand)\n\n\t\tconst cxp = coef * ((rx1 * y1p) / ry1)\n\t\tconst cyp = coef * (-(ry1 * x1p) / rx1)\n\n\t\t// Step 3: Compute (cx, cy) from (cx', cy') - transform back to original coordinate system\n\t\tconst cx = cosPhi * cxp - sinPhi * cyp + (x1 + x2) / 2\n\t\tconst cy = sinPhi * cxp + cosPhi * cyp + (y1 + y2) / 2\n\n\t\t// Step 4: Compute the start and end angles\n\t\tconst ux = (x1p - cxp) / rx1\n\t\tconst uy = (y1p - cyp) / ry1\n\t\tconst vx = (-x1p - cxp) / rx1\n\t\tconst vy = (-y1p - cyp) / ry1\n\n\t\tconst startAngle = Math.atan2(uy, ux)\n\t\tlet endAngle = Math.atan2(vy, vx)\n\n\t\t// Ensure correct sweep direction\n\t\tif (!sweepFlag && endAngle > startAngle) {\n\t\t\tendAngle -= 2 * Math.PI\n\t\t} else if (sweepFlag && endAngle < startAngle) {\n\t\t\tendAngle += 2 * Math.PI\n\t\t}\n\n\t\t// Calculate the sweep angle\n\t\tconst sweepAngle = endAngle - startAngle\n\n\t\t// Calculate the approximate arc length. General ellipse arc length is expensive - there's\n\t\t// no closed form solution, so we have to do iterative numerical approximation. As we only\n\t\t// use this to control the resolution of later approximations, let's cheat and just use the\n\t\t// circular arc length with the largest radius:\n\t\tconst approximateArcLength = Math.max(rx1, ry1) * Math.abs(sweepAngle)\n\n\t\t// Approximate the arc using cubic bezier curves\n\t\tconst numSegments = Math.min(4, Math.ceil(Math.abs(sweepAngle) / (Math.PI / 2)))\n\t\tconst resolutionPerSegment = Math.ceil(\n\t\t\tgetVerticesCountForArcLength(approximateArcLength) / numSegments\n\t\t)\n\t\tconst anglePerSegment = sweepAngle / numSegments\n\n\t\t// Helper function to compute point on ellipse\n\t\tconst ellipsePoint = (angle: number) => {\n\t\t\treturn {\n\t\t\t\tx: cx + rx1 * Math.cos(angle) * cosPhi - ry1 * Math.sin(angle) * sinPhi,\n\t\t\t\ty: cy + rx1 * Math.cos(angle) * sinPhi + ry1 * Math.sin(angle) * cosPhi,\n\t\t\t}\n\t\t}\n\n\t\t// Helper function to compute derivative (tangent vector) at a point on the ellipse\n\t\tconst ellipseDerivative = (angle: number) => {\n\t\t\treturn {\n\t\t\t\tx: -rx1 * Math.sin(angle) * cosPhi - ry1 * Math.cos(angle) * sinPhi,\n\t\t\t\ty: -rx1 * Math.sin(angle) * sinPhi + ry1 * Math.cos(angle) * cosPhi,\n\t\t\t}\n\t\t}\n\n\t\t// Generate cubic bezier approximations\n\t\tfor (let i = 0; i < numSegments; i++) {\n\t\t\tconst theta1 = startAngle + i * anglePerSegment\n\t\t\tconst theta2 = startAngle + (i + 1) * anglePerSegment\n\t\t\tconst deltaTheta = theta2 - theta1\n\n\t\t\tconst start = ellipsePoint(theta1)\n\t\t\tconst end = ellipsePoint(theta2)\n\n\t\t\t// Get the derivative at the start and end points\n\t\t\tconst d1 = ellipseDerivative(theta1)\n\t\t\tconst d2 = ellipseDerivative(theta2)\n\n\t\t\t// Calculate the length of the tangent handles\n\t\t\t// This is a key factor for the accuracy of the approximation\n\t\t\t// For a 90\u00B0 arc, the handle length should be 4/3 * tan(\u03C0/8) * r\n\t\t\t// For smaller arcs, we scale this value by the angle ratio\n\t\t\tconst handleScale = (4 / 3) * Math.tan(deltaTheta / 4)\n\n\t\t\t// Create control points that are tangent to the ellipse at the endpoints\n\t\t\tconst cp1x = start.x + handleScale * d1.x\n\t\t\tconst cp1y = start.y + handleScale * d1.y\n\n\t\t\tconst cp2x = end.x - handleScale * d2.x\n\t\t\tconst cp2y = end.y - handleScale * d2.y\n\n\t\t\tconst bezierOpts = i === 0 ? opts : { ...opts, mergeWithPrevious: true }\n\t\t\tthis.cubicBezierToWithResolution(\n\t\t\t\tend.x,\n\t\t\t\tend.y,\n\t\t\t\tcp1x,\n\t\t\t\tcp1y,\n\t\t\t\tcp2x,\n\t\t\t\tcp2y,\n\t\t\t\tbezierOpts,\n\t\t\t\tresolutionPerSegment\n\t\t\t)\n\t\t}\n\n\t\treturn this\n\t}\n\n\tcubicBezierTo(\n\t\tx: number,\n\t\ty: number,\n\t\tcp1X: number,\n\t\tcp1Y: number,\n\t\tcp2X: number,\n\t\tcp2Y: number,\n\t\topts?: PathBuilderCommandOpts\n\t) {\n\t\treturn this.cubicBezierToWithResolution(x, y, cp1X, cp1Y, cp2X, cp2Y, opts)\n\t}\n\tprivate cubicBezierToWithResolution(\n\t\tx: number,\n\t\ty: number,\n\t\tcp1X: number,\n\t\tcp1Y: number,\n\t\tcp2X: number,\n\t\tcp2Y: number,\n\t\topts?: PathBuilderCommandOpts,\n\t\tresolution?: number\n\t) {\n\t\tthis.assertHasMoveTo()\n\t\tthis.commands.push({\n\t\t\ttype: 'cubic',\n\t\t\tx,\n\t\t\ty,\n\t\t\tcp1: { x: cp1X, y: cp1Y },\n\t\t\tcp2: { x: cp2X, y: cp2Y },\n\t\t\tisClose: false,\n\t\t\topts,\n\t\t\tresolution,\n\t\t})\n\t\treturn this\n\t}\n\n\tclose() {\n\t\tconst lastMoveTo = this.assertHasMoveTo()\n\t\tconst lastCommand = this.commands[this.commands.length - 1]\n\n\t\tif (approximately(lastMoveTo.x, lastCommand.x) && approximately(lastMoveTo.y, lastCommand.y)) {\n\t\t\tlastCommand.isClose = true\n\t\t} else {\n\t\t\tthis.commands.push({\n\t\t\t\ttype: 'line',\n\t\t\t\tx: lastMoveTo.x,\n\t\t\t\ty: lastMoveTo.y,\n\t\t\t\tisClose: true,\n\t\t\t})\n\t\t}\n\n\t\tlastMoveTo.closeIdx = this.commands.length - 1\n\t\tthis.lastMoveTo = null\n\t\treturn this\n\t}\n\n\ttoD(opts: PathBuilderToDOpts = {}) {\n\t\tconst { startIdx = 0, endIdx = this.commands.length, onlyFilled = false } = opts\n\t\tconst parts = []\n\n\t\tlet isSkippingCurrentLine = false\n\n\t\tlet didAddMove = false\n\t\tlet didAddNaturalMove = false\n\n\t\tconst addMoveIfNeeded = (i: number) => {\n\t\t\tif (didAddMove || i === 0) return\n\t\t\tdidAddMove = true\n\t\t\tconst command = this.commands[i - 1]\n\t\t\tparts.push('M', toDomPrecision(command.x), toDomPrecision(command.y))\n\t\t}\n\n\t\tfor (let i = startIdx; i < endIdx; i++) {\n\t\t\tconst command = this.commands[i]\n\t\t\tswitch (command.type) {\n\t\t\t\tcase 'move': {\n\t\t\t\t\tconst isFilled =\n\t\t\t\t\t\tcommand.opts?.geometry === false ? false : (command.opts?.geometry?.isFilled ?? false)\n\t\t\t\t\tif (onlyFilled && !isFilled) {\n\t\t\t\t\t\tisSkippingCurrentLine = true\n\t\t\t\t\t} else {\n\t\t\t\t\t\tisSkippingCurrentLine = false\n\t\t\t\t\t\tdidAddMove = true\n\t\t\t\t\t\tdidAddNaturalMove = true\n\t\t\t\t\t\tparts.push('M', toDomPrecision(command.x), toDomPrecision(command.y))\n\t\t\t\t\t}\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tcase 'line':\n\t\t\t\t\tif (isSkippingCurrentLine) break\n\t\t\t\t\taddMoveIfNeeded(i)\n\t\t\t\t\tif (command.isClose && didAddNaturalMove) {\n\t\t\t\t\t\tparts.push('Z')\n\t\t\t\t\t} else {\n\t\t\t\t\t\tparts.push('L', toDomPrecision(command.x), toDomPrecision(command.y))\n\t\t\t\t\t}\n\t\t\t\t\tbreak\n\t\t\t\tcase 'cubic':\n\t\t\t\t\tif (isSkippingCurrentLine) break\n\t\t\t\t\taddMoveIfNeeded(i)\n\t\t\t\t\tparts.push(\n\t\t\t\t\t\t'C',\n\t\t\t\t\t\ttoDomPrecision(command.cp1.x),\n\t\t\t\t\t\ttoDomPrecision(command.cp1.y),\n\t\t\t\t\t\ttoDomPrecision(command.cp2.x),\n\t\t\t\t\t\ttoDomPrecision(command.cp2.y),\n\t\t\t\t\t\ttoDomPrecision(command.x),\n\t\t\t\t\t\ttoDomPrecision(command.y)\n\t\t\t\t\t)\n\t\t\t\t\tbreak\n\t\t\t\tdefault:\n\t\t\t\t\texhaustiveSwitchError(command, 'type')\n\t\t\t}\n\t\t}\n\t\treturn parts.join(' ')\n\t}\n\n\ttoSvg(opts: PathBuilderOpts) {\n\t\tif (opts.forceSolid) {\n\t\t\treturn this.toSolidSvg(opts)\n\t\t}\n\t\tswitch (opts.style) {\n\t\t\tcase 'solid':\n\t\t\t\treturn this.toSolidSvg(opts)\n\t\t\tcase 'dashed':\n\t\t\tcase 'dotted':\n\t\t\t\treturn this.toDashedSvg(opts)\n\t\t\tcase 'draw': {\n\t\t\t\tconst d = this.toDrawSvg(opts)\n\t\t\t\treturn d\n\t\t\t}\n\t\t\tdefault:\n\t\t\t\texhaustiveSwitchError(opts, 'style')\n\t\t}\n\t}\n\n\ttoGeometry(): PathBuilderGeometry2d | Group2d {\n\t\tconst geometries = []\n\n\t\tlet current: null | {\n\t\t\tstartIdx: number\n\t\t\tmoveCommand: MoveToPathBuilderCommand\n\t\t\tisClosed: boolean\n\t\t\topts?: PathBuilderLineOpts\n\t\t} = null\n\t\tfor (let i = 0; i < this.commands.length; i++) {\n\t\t\tconst command = this.commands[i]\n\n\t\t\tif (command.type === 'move') {\n\t\t\t\tif (current && current.opts?.geometry !== false) {\n\t\t\t\t\tgeometries.push(\n\t\t\t\t\t\tnew PathBuilderGeometry2d(this, current.startIdx, i, {\n\t\t\t\t\t\t\t...current.opts?.geometry,\n\t\t\t\t\t\t\tisFilled: current.opts?.geometry?.isFilled ?? false,\n\t\t\t\t\t\t\tisClosed: current.moveCommand.closeIdx !== null,\n\t\t\t\t\t\t})\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t\tcurrent = { startIdx: i, moveCommand: command, opts: command.opts, isClosed: false }\n\t\t\t}\n\n\t\t\tif (command.isClose) {\n\t\t\t\tassert(current, 'No current move command')\n\t\t\t\tcurrent.isClosed = true\n\t\t\t}\n\t\t}\n\n\t\tif (current && current.opts?.geometry !== false) {\n\t\t\tgeometries.push(\n\t\t\t\tnew PathBuilderGeometry2d(this, current.startIdx, this.commands.length, {\n\t\t\t\t\t...current.opts?.geometry,\n\t\t\t\t\tisFilled: current.opts?.geometry?.isFilled ?? false,\n\t\t\t\t\tisClosed: current.moveCommand.closeIdx !== null,\n\t\t\t\t})\n\t\t\t)\n\t\t}\n\n\t\tassert(geometries.length > 0)\n\t\tif (geometries.length === 1) return geometries[0]\n\t\treturn new Group2d({ children: geometries })\n\t}\n\n\tprivate toSolidSvg(opts: PathBuilderOpts) {\n\t\tconst { strokeWidth, props } = opts\n\n\t\treturn (\n\t\t\t<path strokeWidth={strokeWidth} d={this.toD({ onlyFilled: opts.onlyFilled })} {...props} />\n\t\t)\n\t}\n\n\tprivate toDashedSvg(opts: DashedPathBuilderOpts) {\n\t\tconst {\n\t\t\tstyle,\n\t\t\tstrokeWidth,\n\t\t\tsnap,\n\t\t\tlengthRatio,\n\t\t\tprops: { markerStart, markerEnd, ...props } = {},\n\t\t} = opts\n\n\t\tconst parts: ReactNode[] = []\n\n\t\tlet isCurrentPathClosed = false\n\t\tlet isSkippingCurrentLine = false\n\t\tlet currentLineOpts: PathBuilderLineOpts | undefined = undefined\n\n\t\tlet currentRun: {\n\t\t\tstartIdx: number\n\t\t\tendIdx: number\n\t\t\tisFirst: boolean\n\t\t\tisLast: boolean\n\t\t\tlength: number\n\t\t\tlineOpts: PathBuilderLineOpts | undefined\n\t\t\tpathIsClosed: boolean\n\t\t} | null = null\n\n\t\tconst addCurrentRun = () => {\n\t\t\tif (!currentRun) return\n\t\t\tconst { startIdx, endIdx, isFirst, isLast, length, lineOpts, pathIsClosed } = currentRun\n\t\t\tcurrentRun = null\n\n\t\t\tif (startIdx === endIdx && this.commands[startIdx].type === 'move') return\n\n\t\t\tconst start = lineOpts?.dashStart ?? opts.start\n\t\t\tconst end = lineOpts?.dashEnd ?? opts.end\n\t\t\tconst { strokeDasharray, strokeDashoffset } = getPerfectDashProps(length, strokeWidth, {\n\t\t\t\tstyle,\n\t\t\t\tsnap,\n\t\t\t\tlengthRatio,\n\t\t\t\tstart: isFirst ? (start ?? (pathIsClosed ? 'outset' : 'none')) : 'outset',\n\t\t\t\tend: isLast ? (end ?? (pathIsClosed ? 'outset' : 'none')) : 'outset',\n\t\t\t})\n\n\t\t\tconst d = this.toD({ startIdx, endIdx: endIdx + 1 })\n\t\t\tparts.push(\n\t\t\t\t<path\n\t\t\t\t\tkey={parts.length}\n\t\t\t\t\td={d}\n\t\t\t\t\tstrokeDasharray={strokeDasharray}\n\t\t\t\t\tstrokeDashoffset={strokeDashoffset}\n\t\t\t\t\tmarkerStart={isFirst ? markerStart : undefined}\n\t\t\t\t\tmarkerEnd={isLast ? markerEnd : undefined}\n\t\t\t\t/>\n\t\t\t)\n\t\t}\n\n\t\tfor (let i = 0; i < this.commands.length; i++) {\n\t\t\tconst command = this.commands[i]\n\t\t\tconst lastCommand = this.commands[i - 1]\n\t\t\tif (command.type === 'move') {\n\t\t\t\tisCurrentPathClosed = command.closeIdx !== null\n\t\t\t\tconst isFilled =\n\t\t\t\t\tcommand.opts?.geometry === false ? false : (command.opts?.geometry?.isFilled ?? false)\n\t\t\t\tif (opts.onlyFilled && !isFilled) {\n\t\t\t\t\tisSkippingCurrentLine = true\n\t\t\t\t} else {\n\t\t\t\t\tisSkippingCurrentLine = false\n\t\t\t\t\tcurrentLineOpts = command.opts\n\t\t\t\t}\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif (isSkippingCurrentLine) continue\n\n\t\t\tconst segmentLength = this.calculateSegmentLength(lastCommand, command)\n\t\t\tconst isFirst = lastCommand.type === 'move'\n\t\t\tconst isLast =\n\t\t\t\tcommand.isClose || i === this.commands.length - 1 || this.commands[i + 1]?.type === 'move'\n\n\t\t\tif (currentRun && command.opts?.mergeWithPrevious) {\n\t\t\t\tcurrentRun.length += segmentLength\n\t\t\t\tcurrentRun.endIdx = i\n\t\t\t\tcurrentRun.isLast = isLast\n\t\t\t} else {\n\t\t\t\taddCurrentRun()\n\t\t\t\tcurrentRun = {\n\t\t\t\t\tstartIdx: i,\n\t\t\t\t\tendIdx: i,\n\t\t\t\t\tisFirst,\n\t\t\t\t\tisLast,\n\t\t\t\t\tlength: segmentLength,\n\t\t\t\t\tlineOpts: currentLineOpts,\n\t\t\t\t\tpathIsClosed: isCurrentPathClosed,\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\taddCurrentRun()\n\n\t\treturn (\n\t\t\t<g strokeWidth={strokeWidth} {...props}>\n\t\t\t\t{parts}\n\t\t\t</g>\n\t\t)\n\t}\n\n\tprivate toDrawSvg(opts: DrawPathBuilderOpts) {\n\t\treturn <path strokeWidth={opts.strokeWidth} d={this.toDrawD(opts)} {...opts.props} />\n\t}\n\n\ttoDrawD(opts: DrawPathBuilderDOpts) {\n\t\tconst {\n\t\t\tstrokeWidth,\n\t\t\trandomSeed,\n\t\t\toffset: defaultOffset = strokeWidth / 3,\n\t\t\troundness: defaultRoundness = strokeWidth * 2,\n\t\t\tpasses = 2,\n\t\t\tonlyFilled = false,\n\t\t} = opts\n\n\t\tconst parts = []\n\n\t\tconst commandInfo = this.getCommandInfo()\n\n\t\t// for each command, we draw the line for the command, plus the corner to the next command.\n\t\tconst drawCommands = []\n\t\tlet lastMoveCommandIdx = null\n\t\tfor (let i = 0; i < this.commands.length; i++) {\n\t\t\tconst command = this.commands[i]\n\t\t\tconst offset = command.opts?.offset ?? defaultOffset\n\t\t\tconst roundness = command.opts?.roundness ?? defaultRoundness\n\n\t\t\tif (command.type === 'move') {\n\t\t\t\tlastMoveCommandIdx = i\n\t\t\t}\n\n\t\t\tconst nextIdx = command.isClose\n\t\t\t\t? assertExists(lastMoveCommandIdx) + 1\n\t\t\t\t: !this.commands[i + 1] || this.commands[i + 1].type === 'move'\n\t\t\t\t\t? undefined\n\t\t\t\t\t: i + 1\n\n\t\t\tconst nextInfo =\n\t\t\t\tnextIdx !== undefined && this.commands[nextIdx] && this.commands[nextIdx]?.type !== 'move'\n\t\t\t\t\t? commandInfo[nextIdx]\n\t\t\t\t\t: undefined\n\n\t\t\tconst currentSupportsRoundness = commandsSupportingRoundness[command.type]\n\t\t\tconst nextSupportsRoundness =\n\t\t\t\tnextIdx !== undefined ? commandsSupportingRoundness[this.commands[nextIdx].type] : false\n\n\t\t\tconst currentInfo = commandInfo[i]\n\n\t\t\tconst tangentToPrev = currentInfo?.tangentEnd\n\t\t\tconst tangentToNext = nextInfo?.tangentStart\n\n\t\t\tconst roundnessClampedForAngle =\n\t\t\t\tcurrentSupportsRoundness &&\n\t\t\t\tnextSupportsRoundness &&\n\t\t\t\ttangentToPrev &&\n\t\t\t\ttangentToNext &&\n\t\t\t\tVec.Len2(tangentToPrev) > 0.01 &&\n\t\t\t\tVec.Len2(tangentToNext) > 0.01\n\t\t\t\t\t? modulate(\n\t\t\t\t\t\t\tMath.abs(Vec.AngleBetween(tangentToPrev, tangentToNext)),\n\t\t\t\t\t\t\t[Math.PI / 2, Math.PI],\n\t\t\t\t\t\t\t[roundness, 0],\n\t\t\t\t\t\t\ttrue\n\t\t\t\t\t\t)\n\t\t\t\t\t: 0\n\n\t\t\tconst shortestDistance = Math.min(\n\t\t\t\tcurrentInfo?.length ?? Infinity,\n\t\t\t\tnextInfo?.length ?? Infinity\n\t\t\t)\n\t\t\tconst offsetLimit = shortestDistance - roundnessClampedForAngle * 2\n\n\t\t\tconst offsetAmount = clamp(offset, 0, offsetLimit / 4)\n\n\t\t\tconst roundnessBeforeClampedForLength = Math.min(\n\t\t\t\troundnessClampedForAngle,\n\t\t\t\t(currentInfo?.length ?? Infinity) / 4\n\t\t\t)\n\t\t\tconst roundnessAfterClampedForLength = Math.min(\n\t\t\t\troundnessClampedForAngle,\n\t\t\t\t(nextInfo?.length ?? Infinity) / 4\n\t\t\t)\n\n\t\t\tconst drawCommand = {\n\t\t\t\tcommand,\n\t\t\t\toffsetAmount,\n\t\t\t\troundnessBefore: roundnessBeforeClampedForLength,\n\t\t\t\troundnessAfter: roundnessAfterClampedForLength,\n\t\t\t\ttangentToPrev: commandInfo[i]?.tangentEnd,\n\t\t\t\ttangentToNext: nextInfo?.tangentStart,\n\t\t\t\tmoveDidClose: false,\n\t\t\t}\n\n\t\t\tdrawCommands.push(drawCommand)\n\n\t\t\tif (command.isClose && lastMoveCommandIdx !== null) {\n\t\t\t\tconst lastMoveCommand = drawCommands[lastMoveCommandIdx]\n\t\t\t\tlastMoveCommand.moveDidClose = true\n\t\t\t\tlastMoveCommand.roundnessAfter = roundnessAfterClampedForLength\n\t\t\t} else if (command.type === 'move') {\n\t\t\t\tlastMoveCommandIdx = i\n\t\t\t}\n\t\t}\n\n\t\tfor (let pass = 0; pass < passes; pass++) {\n\t\t\tconst random = rng(randomSeed + pass)\n\n\t\t\tlet lastMoveToOffset = { x: 0, y: 0 }\n\t\t\tlet isSkippingCurrentLine = false\n\t\t\tfor (const {\n\t\t\t\tcommand,\n\t\t\t\toffsetAmount,\n\t\t\t\troundnessBefore,\n\t\t\t\troundnessAfter,\n\t\t\t\ttangentToNext,\n\t\t\t\ttangentToPrev,\n\t\t\t} of drawCommands) {\n\t\t\t\tconst offset = command.isClose\n\t\t\t\t\t? lastMoveToOffset\n\t\t\t\t\t: { x: random() * offsetAmount, y: random() * offsetAmount }\n\n\t\t\t\tif (command.type === 'move') {\n\t\t\t\t\tlastMoveToOffset = offset\n\t\t\t\t\tconst isFilled =\n\t\t\t\t\t\tcommand.opts?.geometry === false ? false : (command.opts?.geometry?.isFilled ?? false)\n\t\t\t\t\tif (onlyFilled && !isFilled) {\n\t\t\t\t\t\tisSkippingCurrentLine = true\n\t\t\t\t\t} else {\n\t\t\t\t\t\tisSkippingCurrentLine = false\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (isSkippingCurrentLine) continue\n\n\t\t\t\tconst offsetPoint = Vec.Add(command, offset)\n\n\t\t\t\tconst endPoint =\n\t\t\t\t\ttangentToNext && roundnessAfter > 0\n\t\t\t\t\t\t? Vec.Mul(tangentToNext, -roundnessAfter).add(offsetPoint)\n\t\t\t\t\t\t: offsetPoint\n\n\t\t\t\tconst startPoint =\n\t\t\t\t\ttangentToPrev && roundnessBefore > 0\n\t\t\t\t\t\t? Vec.Mul(tangentToPrev, roundnessBefore).add(offsetPoint)\n\t\t\t\t\t\t: offsetPoint\n\n\t\t\t\tif (endPoint === offsetPoint || startPoint === offsetPoint) {\n\t\t\t\t\tswitch (command.type) {\n\t\t\t\t\t\tcase 'move':\n\t\t\t\t\t\t\tparts.push('M', toDomPrecision(endPoint.x), toDomPrecision(endPoint.y))\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\tcase 'line':\n\t\t\t\t\t\t\tparts.push('L', toDomPrecision(endPoint.x), toDomPrecision(endPoint.y))\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\tcase 'cubic': {\n\t\t\t\t\t\t\tconst offsetCp1 = Vec.Add(command.cp1, offset)\n\t\t\t\t\t\t\tconst offsetCp2 = Vec.Add(command.cp2, offset)\n\t\t\t\t\t\t\tparts.push(\n\t\t\t\t\t\t\t\t'C',\n\t\t\t\t\t\t\t\ttoDomPrecision(offsetCp1.x),\n\t\t\t\t\t\t\t\ttoDomPrecision(offsetCp1.y),\n\t\t\t\t\t\t\t\ttoDomPrecision(offsetCp2.x),\n\t\t\t\t\t\t\t\ttoDomPrecision(offsetCp2.y),\n\t\t\t\t\t\t\t\ttoDomPrecision(endPoint.x),\n\t\t\t\t\t\t\t\ttoDomPrecision(endPoint.y)\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\texhaustiveSwitchError(command, 'type')\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tswitch (command.type) {\n\t\t\t\t\t\tcase 'move':\n\t\t\t\t\t\t\tparts.push('M', toDomPrecision(endPoint.x), toDomPrecision(endPoint.y))\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\tcase 'line':\n\t\t\t\t\t\t\tparts.push(\n\t\t\t\t\t\t\t\t'L',\n\t\t\t\t\t\t\t\ttoDomPrecision(startPoint.x),\n\t\t\t\t\t\t\t\ttoDomPrecision(startPoint.y),\n\n\t\t\t\t\t\t\t\t'Q',\n\t\t\t\t\t\t\t\ttoDomPrecision(offsetPoint.x),\n\t\t\t\t\t\t\t\ttoDomPrecision(offsetPoint.y),\n\t\t\t\t\t\t\t\ttoDomPrecision(endPoint.x),\n\t\t\t\t\t\t\t\ttoDomPrecision(endPoint.y)\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\tcase 'cubic': {\n\t\t\t\t\t\t\tconst offsetCp1 = Vec.Add(command.cp1, offset)\n\t\t\t\t\t\t\tconst offsetCp2 = Vec.Add(command.cp2, offset)\n\t\t\t\t\t\t\tparts.push(\n\t\t\t\t\t\t\t\t'C',\n\t\t\t\t\t\t\t\ttoDomPrecision(offsetCp1.x),\n\t\t\t\t\t\t\t\ttoDomPrecision(offsetCp1.y),\n\t\t\t\t\t\t\t\ttoDomPrecision(offsetCp2.x),\n\t\t\t\t\t\t\t\ttoDomPrecision(offsetCp2.y),\n\t\t\t\t\t\t\t\ttoDomPrecision(offsetPoint.x),\n\t\t\t\t\t\t\t\ttoDomPrecision(offsetPoint.y)\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\texhaustiveSwitchError(command, 'type')\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn parts.join(' ')\n\t}\n\n\tprivate calculateSegmentLength(lastPoint: VecLike, command: PathBuilderCommand) {\n\t\tswitch (command.type) {\n\t\t\tcase 'move':\n\t\t\t\treturn 0\n\t\t\tcase 'line':\n\t\t\t\treturn Vec.Dist(lastPoint, command)\n\t\t\tcase 'cubic':\n\t\t\t\treturn CubicBezier.length(\n\t\t\t\t\tlastPoint.x,\n\t\t\t\t\tlastPoint.y,\n\t\t\t\t\tcommand.cp1.x,\n\t\t\t\t\tcommand.cp1.y,\n\t\t\t\t\tcommand.cp2.x,\n\t\t\t\t\tcommand.cp2.y,\n\t\t\t\t\tcommand.x,\n\t\t\t\t\tcommand.y\n\t\t\t\t)\n\t\t\tdefault:\n\t\t\t\texhaustiveSwitchError(command, 'type')\n\t\t}\n\t}\n\n\t/** @internal */\n\tgetCommands(): readonly PathBuilderCommand[] {\n\t\treturn this.commands\n\t}\n\n\t/** @internal */\n\tgetCommandInfo() {\n\t\tconst commandInfo: Array<undefined | PathBuilderCommandInfo> = []\n\t\tfor (let i = 1; i < this.commands.length; i++) {\n\t\t\tconst previous = this.commands[i - 1]\n\t\t\tconst current = this.commands[i]\n\n\t\t\tif (current._info) {\n\t\t\t\tcommandInfo[i] = current._info\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif (current.type === 'move') {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tlet tangentStart, tangentEnd\n\t\t\tswitch (current.type) {\n\t\t\t\tcase 'line':\n\t\t\t\t\ttangentStart = tangentEnd = Vec.Sub(previous, current).uni()\n\t\t\t\t\tbreak\n\t\t\t\tcase 'cubic': {\n\t\t\t\t\ttangentStart = Vec.Sub(current.cp1, previous).uni()\n\t\t\t\t\ttangentEnd = Vec.Sub(current.cp2, current).uni()\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t\texhaustiveSwitchError(current, 'type')\n\t\t\t}\n\n\t\t\tcurrent._info = {\n\t\t\t\ttangentStart,\n\t\t\t\ttangentEnd,\n\t\t\t\tlength: this.calculateSegmentLength(previous, current),\n\t\t\t}\n\t\t\tcommandInfo[i] = current._info\n\t\t}\n\n\t\treturn commandInfo\n\t}\n}\n\nconst commandsSupportingRoundness = {\n\tline: true,\n\tmove: true,\n\tcubic: false,\n} as const satisfies Record<PathBuilderCommand['type'], boolean>\n\n/** @public */\nexport class PathBuilderGeometry2d extends Geometry2d {\n\tconstructor(\n\t\tprivate readonly path: PathBuilder,\n\t\tprivate readonly startIdx: number,\n\t\tprivate readonly endIdx: number,\n\t\toptions: Geometry2dOptions\n\t) {\n\t\tsuper(options)\n\t}\n\n\tprivate _segments: Geometry2d[] | null = null\n\tgetSegments() {\n\t\tif (this._segments) return this._segments\n\n\t\tthis._segments = []\n\t\tlet last = this.path.commands[this.startIdx]\n\t\tassert(last.type === 'move')\n\n\t\tfor (let i = this.startIdx + 1; i < this.endIdx; i++) {\n\t\t\tconst command = this.path.commands[i]\n\t\t\tassert(command.type !== 'move')\n\n\t\t\tswitch (command.type) {\n\t\t\t\tcase 'line':\n\t\t\t\t\tthis._segments.push(new Edge2d({ start: Vec.From(last), end: Vec.From(command) }))\n\t\t\t\t\tbreak\n\t\t\t\tcase 'cubic': {\n\t\t\t\t\tthis._segments.push(\n\t\t\t\t\t\tnew CubicBezier2d({\n\t\t\t\t\t\t\tstart: Vec.From(last),\n\t\t\t\t\t\t\tcp1: Vec.From(command.cp1),\n\t\t\t\t\t\t\tcp2: Vec.From(command.cp2),\n\t\t\t\t\t\t\tend: Vec.From(command),\n\t\t\t\t\t\t\tresolution: command.resolution,\n\t\t\t\t\t\t})\n\t\t\t\t\t)\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t\texhaustiveSwitchError(command, 'type')\n\t\t\t}\n\n\t\t\tlast = command\n\t\t}\n\n\t\treturn this._segments\n\t}\n\n\toverride getVertices(filters: Geometry2dFilters): Vec[] {\n\t\tconst vs = this.getSegments()\n\t\t\t.flatMap((s) => s.getVertices(filters))\n\t\t\t.filter((vertex, i, vertices) => {\n\t\t\t\tconst prev = vertices[i - 1]\n\t\t\t\tif (!prev) return true\n\t\t\t\treturn !Vec.Equals(prev, vertex)\n\t\t\t})\n\n\t\tif (this.isClosed) {\n\t\t\tconst last = vs[vs.length - 1]\n\t\t\tconst first = vs[0]\n\t\t\tif (!Vec.Equals(last, first)) {\n\t\t\t\tvs.push(first)\n\t\t\t}\n\t\t}\n\n\t\treturn vs\n\t}\n\n\toverride nearestPoint(point: VecLike, _filters?: Geometry2dFilters): Vec {\n\t\tlet nearest: Vec | null = null\n\t\tlet nearestDistance = Infinity\n\n\t\tfor (const segment of this.getSegments()) {\n\t\t\tconst candidate = segment.nearestPoint(point)\n\t\t\tconst distance = Vec.Dist2(point, candidate)\n\t\t\tif (distance < nearestDistance) {\n\t\t\t\tnearestDistance = distance\n\t\t\t\tnearest = candidate\n\t\t\t}\n\t\t}\n\n\t\tassert(nearest, 'No nearest point found')\n\t\treturn nearest\n\t}\n\n\toverride hitTestLineSegment(\n\t\tA: VecLike,\n\t\tB: VecLike,\n\t\tdistance = 0,\n\t\tfilters?: Geometry2dFilters\n\t): boolean {\n\t\treturn super.hitTestLineSegment(A, B, distance, filters)\n\t}\n\toverride getSvgPathData(): string {\n\t\treturn this.path.toD({ startIdx: this.startIdx, endIdx: this.endIdx })\n\t}\n}\n\n/*!\n * Adapted from https://github.com/adobe-webplatform/Snap.svg/tree/master\n * Apache License: https://github.com/adobe-webplatform/Snap.svg/blob/master/LICENSE\n * https://github.com/adobe-webplatform/Snap.svg/blob/c8e483c9694517e24b282f8f59f985629f4994ce/dist/snap.svg.js#L5786\n */\nconst CubicBezier = {\n\tbase3(t: number, p1: number, p2: number, p3: number, p4: number) {\n\t\tconst t1 = -3 * p1 + 9 * p2 - 9 * p3 + 3 * p4\n\t\tconst t2 = t * t1 + 6 * p1 - 12 * p2 + 6 * p3\n\t\treturn t * t2 - 3 * p1 + 3 * p2\n\t},\n\t/**\n\t * Calculate the approximate length of a cubic bezier curve from (x1, y1) to (x4, y4) with\n\t * control points (x2, y2) and (x3, y3).\n\t */\n\tlength(\n\t\tx1: number,\n\t\ty1: number,\n\t\tx2: number,\n\t\ty2: number,\n\t\tx3: number,\n\t\ty3: number,\n\t\tx4: number,\n\t\ty4: number,\n\t\tz = 1\n\t) {\n\t\tz = z > 1 ? 1 : z < 0 ? 0 : z\n\t\tconst z2 = z / 2\n\t\tconst n = 12\n\n\t\tlet sum = 0\n\t\tsum = 0\n\t\tfor (let i = 0; i < n; i++) {\n\t\t\tconst ct = z2 * CubicBezier.Tvalues[i] + z2\n\t\t\tconst xbase = CubicBezier.base3(ct, x1, x2, x3, x4)\n\t\t\tconst ybase = CubicBezier.base3(ct, y1, y2, y3, y4)\n\t\t\tconst comb = xbase * xbase + ybase * ybase\n\t\t\tsum += CubicBezier.Cvalues[i] * Math.sqrt(comb)\n\t\t}\n\t\treturn z2 * sum\n\t},\n\tTvalues: [\n\t\t-0.1252, 0.1252, -0.3678, 0.3678, -0.5873, 0.5873, -0.7699, 0.7699, -0.9041, 0.9041, -0.9816,\n\t\t0.9816,\n\t],\n\tCvalues: [\n\t\t0.2491, 0.2491, 0.2335, 0.2335, 0.2032, 0.2032, 0.1601, 0.1601, 0.1069, 0.1069, 0.0472, 0.0472,\n\t],\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAikBG;AAjkBH,oBAqBO;AAwHA,MAAM,YAAY;AAAA,EACxB,OAAO,kBACN,QACA,MACC;AACD,UAAM,OAAO,IAAI,YAAY;AAC7B,SAAK,OAAO,OAAO,CAAC,EAAE,GAAG,OAAO,CAAC,EAAE,GAAG,EAAE,GAAG,MAAM,QAAQ,MAAM,cAAc,MAAM,OAAO,CAAC;AAC3F,aAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACvC,YAAM,SAAS,MAAM,OAAO,SAAS;AACrC,WAAK,OAAO,OAAO,CAAC,EAAE,GAAG,OAAO,CAAC,EAAE,GAAG,SAAS,EAAE,QAAQ,MAAM,WAAW,IAAI,MAAS;AAAA,IACxF;AACA,WAAO;AAAA,EACR;AAAA,EAEA,OAAO,yBACN,QACA,MACC;AACD,UAAM,OAAO,IAAI,YAAY;AAC7B,UAAM,MAAM,OAAO;AACnB,UAAM,OAAO,MAAM;AACnB,UAAM,IAAI;AAEV,SAAK,OAAO,OAAO,CAAC,EAAE,GAAG,OAAO,CAAC,EAAE,GAAG,EAAE,GAAG,MAAM,QAAQ,MAAM,cAAc,MAAM,OAAO,CAAC;AAE3F,aAAS,IAAI,GAAG,IAAI,MAAM,GAAG,KAAK;AACjC,YAAM,KAAK,MAAM,IAAI,OAAO,CAAC,IAAI,OAAO,IAAI,CAAC;AAC7C,YAAM,KAAK,OAAO,CAAC;AACnB,YAAM,KAAK,OAAO,IAAI,CAAC;AACvB,YAAM,KAAK,MAAM,OAAO,KAAK,OAAO,IAAI,CAAC;AAEzC,UAAI,MAAM,MAAM,MAAM;AACtB,UAAI,MAAM,GAAG;AACZ,eAAO,GAAG;AACV,eAAO,GAAG;AAAA,MACX,OAAO;AACN,eAAO,GAAG,KAAM,GAAG,IAAI,GAAG,KAAK,IAAK;AACpC,eAAO,GAAG,KAAM,GAAG,IAAI,GAAG,KAAK,IAAK;AAAA,MACrC;AAEA,UAAI,YAAY;AAChB,UAAI,MAAM,MAAM;AACf,eAAO,GAAG;AACV,eAAO,GAAG;AACV,oBAAY,EAAE,QAAQ,MAAM,WAAW;AAAA,MACxC,OAAO;AACN,eAAO,GAAG,KAAM,GAAG,IAAI,GAAG,KAAK,IAAK;AACpC,eAAO,GAAG,KAAM,GAAG,IAAI,GAAG,KAAK,IAAK;AAAA,MACrC;AAEA,WAAK,cAAc,GAAG,GAAG,GAAG,GAAG,MAAM,MAAM,MAAM,MAAM,SAAS;AAAA,IACjE;AAEA,WAAO;AAAA,EACR;AAAA,EAEA,cAAc;AAAA,EAAC;AAAA;AAAA,EAGf,WAAiC,CAAC;AAAA,EAE1B,aAA8C;AAAA,EAC9C,kBAAkB;AACzB,8BAAO,KAAK,YAAY,0CAA0C;AAClE,WAAO,KAAK;AAAA,EACb;AAAA,EAEA,OAAO,GAAW,GAAW,MAA4B;AACxD,SAAK,aAAa,EAAE,MAAM,QAAQ,GAAG,GAAG,UAAU,MAAM,SAAS,OAAO,KAAK;AAC7E,SAAK,SAAS,KAAK,KAAK,UAAU;AAClC,WAAO;AAAA,EACR;AAAA,EAEA,OAAO,GAAW,GAAW,MAA+B;AAC3D,SAAK,gBAAgB;AACrB,SAAK,SAAS,KAAK,EAAE,MAAM,QAAQ,GAAG,GAAG,SAAS,OAAO,KAAK,CAAC;AAC/D,WAAO;AAAA,EACR;AAAA,EAEA,cACC,QACA,cACA,WACA,IACA,IACA,MACC;AACD,WAAO,KAAK,MAAM,QAAQ,QAAQ,cAAc,WAAW,GAAG,IAAI,IAAI,IAAI;AAAA,EAC3E;AAAA,EAEA,MACC,IACA,IACA,cACA,WACA,sBACA,IACA,IACA,MACC;AAMD,SAAK,gBAAgB;AAErB,UAAM,KAAK,KAAK,SAAS,KAAK,SAAS,SAAS,CAAC,EAAE;AACnD,UAAM,KAAK,KAAK,SAAS,KAAK,SAAS,SAAS,CAAC,EAAE;AAGnD,QAAI,OAAO,MAAM,OAAO,IAAI;AAC3B,aAAO;AAAA,IACR;AAGA,QAAI,OAAO,KAAK,OAAO,GAAG;AACzB,aAAO,KAAK,OAAO,IAAI,IAAI,IAAI;AAAA,IAChC;AAGA,UAAM,MAAM;AACZ,UAAM,SAAS,KAAK,IAAI,GAAG;AAC3B,UAAM,SAAS,KAAK,IAAI,GAAG;AAG3B,QAAI,MAAM,KAAK,IAAI,EAAE;AACrB,QAAI,MAAM,KAAK,IAAI,EAAE;AAGrB,UAAM,MAAM,KAAK,MAAM;AACvB,UAAM,MAAM,KAAK,MAAM;AACvB,UAAM,MAAM,SAAS,KAAK,SAAS;AACnC,UAAM,MAAM,CAAC,SAAS,KAAK,SAAS;AAGpC,UAAM,SAAU,MAAM,OAAQ,MAAM,OAAQ,MAAM,OAAQ,MAAM;AAChE,QAAI,SAAS,GAAG;AACf,YAAM,aAAa,KAAK,KAAK,MAAM;AACnC,aAAO;AACP,aAAO;AAAA,IACR;AAGA,UAAM,OAAO,iBAAiB,YAAY,IAAI;AAE9C,UAAM,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM;AAC/E,UAAM,YAAY,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM;AAE5D,QAAI,WAAW,OAAO;AACtB,eAAW,WAAW,IAAI,IAAI;AAE9B,UAAM,OAAO,OAAO,KAAK,KAAK,QAAQ;AAEtC,UAAM,MAAM,QAAS,MAAM,MAAO;AAClC,UAAM,MAAM,QAAQ,EAAE,MAAM,OAAO;AAGnC,UAAM,KAAK,SAAS,MAAM,SAAS,OAAO,KAAK,MAAM;AACrD,UAAM,KAAK,SAAS,MAAM,SAAS,OAAO,KAAK,MAAM;AAGrD,UAAM,MAAM,MAAM,OAAO;AACzB,UAAM,MAAM,MAAM,OAAO;AACzB,UAAM,MAAM,CAAC,MAAM,OAAO;AAC1B,UAAM,MAAM,CAAC,MAAM,OAAO;AAE1B,UAAM,aAAa,KAAK,MAAM,IAAI,EAAE;AACpC,QAAI,WAAW,KAAK,MAAM,IAAI,EAAE;AAGhC,QAAI,CAAC,aAAa,WAAW,YAAY;AACxC,kBAAY,IAAI,KAAK;AAAA,IACtB,WAAW,aAAa,WAAW,YAAY;AAC9C,kBAAY,IAAI,KAAK;AAAA,IACtB;AAGA,UAAM,aAAa,WAAW;AAM9B,UAAM,uBAAuB,KAAK,IAAI,KAAK,GAAG,IAAI,KAAK,IAAI,UAAU;AAGrE,UAAM,cAAc,KAAK,IAAI,GAAG,KAAK,KAAK,KAAK,IAAI,UAAU,KAAK,KAAK,KAAK,EAAE,CAAC;AAC/E,UAAM,uBAAuB,KAAK;AAAA,UACjC,4CAA6B,oBAAoB,IAAI;AAAA,IACtD;AACA,UAAM,kBAAkB,aAAa;AAGrC,UAAM,eAAe,CAAC,UAAkB;AACvC,aAAO;AAAA,QACN,GAAG,KAAK,MAAM,KAAK,IAAI,KAAK,IAAI,SAAS,MAAM,KAAK,IAAI,KAAK,IAAI;AAAA,QACjE,GAAG,KAAK,MAAM,KAAK,IAAI,KAAK,IAAI,SAAS,MAAM,KAAK,IAAI,KAAK,IAAI;AAAA,MAClE;AAAA,IACD;AAGA,UAAM,oBAAoB,CAAC,UAAkB;AAC5C,aAAO;AAAA,QACN,GAAG,CAAC,MAAM,KAAK,IAAI,KAAK,IAAI,SAAS,MAAM,KAAK,IAAI,KAAK,IAAI;AAAA,QAC7D,GAAG,CAAC,MAAM,KAAK,IAAI,KAAK,IAAI,SAAS,MAAM,KAAK,IAAI,KAAK,IAAI;AAAA,MAC9D;AAAA,IACD;AAGA,aAAS,IAAI,GAAG,IAAI,aAAa,KAAK;AACrC,YAAM,SAAS,aAAa,IAAI;AAChC,YAAM,SAAS,cAAc,IAAI,KAAK;AACtC,YAAM,aAAa,SAAS;AAE5B,YAAM,QAAQ,aAAa,MAAM;AACjC,YAAM,MAAM,aAAa,MAAM;AAG/B,YAAM,KAAK,kBAAkB,MAAM;AACnC,YAAM,KAAK,kBAAkB,MAAM;AAMnC,YAAM,cAAe,IAAI,IAAK,KAAK,IAAI,aAAa,CAAC;AAGrD,YAAM,OAAO,MAAM,IAAI,cAAc,GAAG;AACxC,YAAM,OAAO,MAAM,IAAI,cAAc,GAAG;AAExC,YAAM,OAAO,IAAI,IAAI,cAAc,GAAG;AACtC,YAAM,OAAO,IAAI,IAAI,cAAc,GAAG;AAEtC,YAAM,aAAa,MAAM,IAAI,OAAO,EAAE,GAAG,MAAM,mBAAmB,KAAK;AACvE,WAAK;AAAA,QACJ,IAAI;AAAA,QACJ,IAAI;AAAA,QACJ;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACD;AAAA,IACD;AAEA,WAAO;AAAA,EACR;AAAA,EAEA,cACC,GACA,GACA,MACA,MACA,MACA,MACA,MACC;AACD,WAAO,KAAK,4BAA4B,GAAG,GAAG,MAAM,MAAM,MAAM,MAAM,IAAI;AAAA,EAC3E;AAAA,EACQ,4BACP,GACA,GACA,MACA,MACA,MACA,MACA,MACA,YACC;AACD,SAAK,gBAAgB;AACrB,SAAK,SAAS,KAAK;AAAA,MAClB,MAAM;AAAA,MACN;AAAA,MACA;AAAA,MACA,KAAK,EAAE,GAAG,MAAM,GAAG,KAAK;AAAA,MACxB,KAAK,EAAE,GAAG,MAAM,GAAG,KAAK;AAAA,MACxB,SAAS;AAAA,MACT;AAAA,MACA;AAAA,IACD,CAAC;AACD,WAAO;AAAA,EACR;AAAA,EAEA,QAAQ;AACP,UAAM,aAAa,KAAK,gBAAgB;AACxC,UAAM,cAAc,KAAK,SAAS,KAAK,SAAS,SAAS,CAAC;AAE1D,YAAI,6BAAc,WAAW,GAAG,YAAY,CAAC,SAAK,6BAAc,WAAW,GAAG,YAAY,CAAC,GAAG;AAC7F,kBAAY,UAAU;AAAA,IACvB,OAAO;AACN,WAAK,SAAS,KAAK;AAAA,QAClB,MAAM;AAAA,QACN,GAAG,WAAW;AAAA,QACd,GAAG,WAAW;AAAA,QACd,SAAS;AAAA,MACV,CAAC;AAAA,IACF;AAEA,eAAW,WAAW,KAAK,SAAS,SAAS;AAC7C,SAAK,aAAa;AAClB,WAAO;AAAA,EACR;AAAA,EAEA,IAAI,OAA2B,CAAC,GAAG;AAClC,UAAM,EAAE,WAAW,GAAG,SAAS,KAAK,SAAS,QAAQ,aAAa,MAAM,IAAI;AAC5E,UAAM,QAAQ,CAAC;AAEf,QAAI,wBAAwB;AAE5B,QAAI,aAAa;AACjB,QAAI,oBAAoB;AAExB,UAAM,kBAAkB,CAAC,MAAc;AACtC,UAAI,cAAc,MAAM,EAAG;AAC3B,mBAAa;AACb,YAAM,UAAU,KAAK,SAAS,IAAI,CAAC;AACnC,YAAM,KAAK,SAAK,8BAAe,QAAQ,CAAC,OAAG,8BAAe,QAAQ,CAAC,CAAC;AAAA,IACrE;AAEA,aAAS,IAAI,UAAU,IAAI,QAAQ,KAAK;AACvC,YAAM,UAAU,KAAK,SAAS,CAAC;AAC/B,cAAQ,QAAQ,MAAM;AAAA,QACrB,KAAK,QAAQ;AACZ,gBAAM,WACL,QAAQ,MAAM,aAAa,QAAQ,QAAS,QAAQ,MAAM,UAAU,YAAY;AACjF,cAAI,cAAc,CAAC,UAAU;AAC5B,oCAAwB;AAAA,UACzB,OAAO;AACN,oCAAwB;AACxB,yBAAa;AACb,gCAAoB;AACpB,kBAAM,KAAK,SAAK,8BAAe,QAAQ,CAAC,OAAG,8BAAe,QAAQ,CAAC,CAAC;AAAA,UACrE;AACA;AAAA,QACD;AAAA,QACA,KAAK;AACJ,cAAI,sBAAuB;AAC3B,0BAAgB,CAAC;AACjB,cAAI,QAAQ,WAAW,mBAAmB;AACzC,kBAAM,KAAK,GAAG;AAAA,UACf,OAAO;AACN,kBAAM,KAAK,SAAK,8BAAe,QAAQ,CAAC,OAAG,8BAAe,QAAQ,CAAC,CAAC;AAAA,UACrE;AACA;AAAA,QACD,KAAK;AACJ,cAAI,sBAAuB;AAC3B,0BAAgB,CAAC;AACjB,gBAAM;AAAA,YACL;AAAA,gBACA,8BAAe,QAAQ,IAAI,CAAC;AAAA,gBAC5B,8BAAe,QAAQ,IAAI,CAAC;AAAA,gBAC5B,8BAAe,QAAQ,IAAI,CAAC;AAAA,gBAC5B,8BAAe,QAAQ,IAAI,CAAC;AAAA,gBAC5B,8BAAe,QAAQ,CAAC;AAAA,gBACxB,8BAAe,QAAQ,CAAC;AAAA,UACzB;AACA;AAAA,QACD;AACC,mDAAsB,SAAS,MAAM;AAAA,MACvC;AAAA,IACD;AACA,WAAO,MAAM,KAAK,GAAG;AAAA,EACtB;AAAA,EAEA,MAAM,MAAuB;AAC5B,QAAI,KAAK,YAAY;AACpB,aAAO,KAAK,WAAW,IAAI;AAAA,IAC5B;AACA,YAAQ,KAAK,OAAO;AAAA,MACnB,KAAK;AACJ,eAAO,KAAK,WAAW,IAAI;AAAA,MAC5B,KAAK;AAAA,MACL,KAAK;AACJ,eAAO,KAAK,YAAY,IAAI;AAAA,MAC7B,KAAK,QAAQ;AACZ,cAAM,IAAI,KAAK,UAAU,IAAI;AAC7B,eAAO;AAAA,MACR;AAAA,MACA;AACC,iDAAsB,MAAM,OAAO;AAAA,IACrC;AAAA,EACD;AAAA,EAEA,aAA8C;AAC7C,UAAM,aAAa,CAAC;AAEpB,QAAI,UAKA;AACJ,aAAS,IAAI,GAAG,IAAI,KAAK,SAAS,QAAQ,KAAK;AAC9C,YAAM,UAAU,KAAK,SAAS,CAAC;AAE/B,UAAI,QAAQ,SAAS,QAAQ;AAC5B,YAAI,WAAW,QAAQ,MAAM,aAAa,OAAO;AAChD,qBAAW;AAAA,YACV,IAAI,sBAAsB,MAAM,QAAQ,UAAU,GAAG;AAAA,cACpD,GAAG,QAAQ,MAAM;AAAA,cACjB,UAAU,QAAQ,MAAM,UAAU,YAAY;AAAA,cAC9C,UAAU,QAAQ,YAAY,aAAa;AAAA,YAC5C,CAAC;AAAA,UACF;AAAA,QACD;AACA,kBAAU,EAAE,UAAU,GAAG,aAAa,SAAS,MAAM,QAAQ,MAAM,UAAU,MAAM;AAAA,MACpF;AAEA,UAAI,QAAQ,SAAS;AACpB,kCAAO,SAAS,yBAAyB;AACzC,gBAAQ,WAAW;AAAA,MACpB;AAAA,IACD;AAEA,QAAI,WAAW,QAAQ,MAAM,aAAa,OAAO;AAChD,iBAAW;AAAA,QACV,IAAI,sBAAsB,MAAM,QAAQ,UAAU,KAAK,SAAS,QAAQ;AAAA,UACvE,GAAG,QAAQ,MAAM;AAAA,UACjB,UAAU,QAAQ,MAAM,UAAU,YAAY;AAAA,UAC9C,UAAU,QAAQ,YAAY,aAAa;AAAA,QAC5C,CAAC;AAAA,MACF;AAAA,IACD;AAEA,8BAAO,WAAW,SAAS,CAAC;AAC5B,QAAI,WAAW,WAAW,EAAG,QAAO,WAAW,CAAC;AAChD,WAAO,IAAI,sBAAQ,EAAE,UAAU,WAAW,CAAC;AAAA,EAC5C;AAAA,EAEQ,WAAW,MAAuB;AACzC,UAAM,EAAE,aAAa,MAAM,IAAI;AAE/B,WACC,4CAAC,UAAK,aAA0B,GAAG,KAAK,IAAI,EAAE,YAAY,KAAK,WAAW,CAAC,GAAI,GAAG,OAAO;AAAA,EAE3F;AAAA,EAEQ,YAAY,MAA6B;AAChD,UAAM;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,OAAO,EAAE,aAAa,WAAW,GAAG,MAAM,IAAI,CAAC;AAAA,IAChD,IAAI;AAEJ,UAAM,QAAqB,CAAC;AAE5B,QAAI,sBAAsB;AAC1B,QAAI,wBAAwB;AAC5B,QAAI,kBAAmD;AAEvD,QAAI,aAQO;AAEX,UAAM,gBAAgB,MAAM;AAC3B,UAAI,CAAC,WAAY;AACjB,YAAM,EAAE,UAAU,QAAQ,SAAS,QAAQ,QAAQ,UAAU,aAAa,IAAI;AAC9E,mBAAa;AAEb,UAAI,aAAa,UAAU,KAAK,SAAS,QAAQ,EAAE,SAAS,OAAQ;AAEpE,YAAM,QAAQ,UAAU,aAAa,KAAK;AAC1C,YAAM,MAAM,UAAU,WAAW,KAAK;AACtC,YAAM,EAAE,iBAAiB,iBAAiB,QAAI,mCAAoB,QAAQ,aAAa;AAAA,QACtF;AAAA,QACA;AAAA,QACA;AAAA,QACA,OAAO,UAAW,UAAU,eAAe,WAAW,UAAW;AAAA,QACjE,KAAK,SAAU,QAAQ,eAAe,WAAW,UAAW;AAAA,MAC7D,CAAC;AAED,YAAM,IAAI,KAAK,IAAI,EAAE,UAAU,QAAQ,SAAS,EAAE,CAAC;AACnD,YAAM;AAAA,QACL;AAAA,UAAC;AAAA;AAAA,YAEA;AAAA,YACA;AAAA,YACA;AAAA,YACA,aAAa,UAAU,cAAc;AAAA,YACrC,WAAW,SAAS,YAAY;AAAA;AAAA,UAL3B,MAAM;AAAA,QAMZ;AAAA,MACD;AAAA,IACD;AAEA,aAAS,IAAI,GAAG,IAAI,KAAK,SAAS,QAAQ,KAAK;AAC9C,YAAM,UAAU,KAAK,SAAS,CAAC;AAC/B,YAAM,cAAc,KAAK,SAAS,IAAI,CAAC;AACvC,UAAI,QAAQ,SAAS,QAAQ;AAC5B,8BAAsB,QAAQ,aAAa;AAC3C,cAAM,WACL,QAAQ,MAAM,aAAa,QAAQ,QAAS,QAAQ,MAAM,UAAU,YAAY;AACjF,YAAI,KAAK,cAAc,CAAC,UAAU;AACjC,kCAAwB;AAAA,QACzB,OAAO;AACN,kCAAwB;AACxB,4BAAkB,QAAQ;AAAA,QAC3B;AACA;AAAA,MACD;AAEA,UAAI,sBAAuB;AAE3B,YAAM,gBAAgB,KAAK,uBAAuB,aAAa,OAAO;AACtE,YAAM,UAAU,YAAY,SAAS;AACrC,YAAM,SACL,QAAQ,WAAW,MAAM,KAAK,SAAS,SAAS,KAAK,KAAK,SAAS,IAAI,CAAC,GAAG,SAAS;AAErF,UAAI,cAAc,QAAQ,MAAM,mBAAmB;AAClD,mBAAW,UAAU;AACrB,mBAAW,SAAS;AACpB,mBAAW,SAAS;AAAA,MACrB,OAAO;AACN,sBAAc;AACd,qBAAa;AAAA,UACZ,UAAU;AAAA,UACV,QAAQ;AAAA,UACR;AAAA,UACA;AAAA,UACA,QAAQ;AAAA,UACR,UAAU;AAAA,UACV,cAAc;AAAA,QACf;AAAA,MACD;AAAA,IACD;AAEA,kBAAc;AAEd,WACC,4CAAC,OAAE,aAA2B,GAAG,OAC/B,iBACF;AAAA,EAEF;AAAA,EAEQ,UAAU,MAA2B;AAC5C,WAAO,4CAAC,UAAK,aAAa,KAAK,aAAa,GAAG,KAAK,QAAQ,IAAI,GAAI,GAAG,KAAK,OAAO;AAAA,EACpF;AAAA,EAEA,QAAQ,MAA4B;AACnC,UAAM;AAAA,MACL;AAAA,MACA;AAAA,MACA,QAAQ,gBAAgB,cAAc;AAAA,MACtC,WAAW,mBAAmB,cAAc;AAAA,MAC5C,SAAS;AAAA,MACT,aAAa;AAAA,IACd,IAAI;AAEJ,UAAM,QAAQ,CAAC;AAEf,UAAM,cAAc,KAAK,eAAe;AAGxC,UAAM,eAAe,CAAC;AACtB,QAAI,qBAAqB;AACzB,aAAS,IAAI,GAAG,IAAI,KAAK,SAAS,QAAQ,KAAK;AAC9C,YAAM,UAAU,KAAK,SAAS,CAAC;AAC/B,YAAM,SAAS,QAAQ,MAAM,UAAU;AACvC,YAAM,YAAY,QAAQ,MAAM,aAAa;AAE7C,UAAI,QAAQ,SAAS,QAAQ;AAC5B,6BAAqB;AAAA,MACtB;AAEA,YAAM,UAAU,QAAQ,cACrB,4BAAa,kBAAkB,IAAI,IACnC,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,KAAK,SAAS,IAAI,CAAC,EAAE,SAAS,SACtD,SACA,IAAI;AAER,YAAM,WACL,YAAY,UAAa,KAAK,SAAS,OAAO,KAAK,KAAK,SAAS,OAAO,GAAG,SAAS,SACjF,YAAY,OAAO,IACnB;AAEJ,YAAM,2BAA2B,4BAA4B,QAAQ,IAAI;AACzE,YAAM,wBACL,YAAY,SAAY,4BAA4B,KAAK,SAAS,OAAO,EAAE,IAAI,IAAI;AAEpF,YAAM,cAAc,YAAY,CAAC;AAEjC,YAAM,gBAAgB,aAAa;AACnC,YAAM,gBAAgB,UAAU;AAEhC,YAAM,2BACL,4BACA,yBACA,iBACA,iBACA,kBAAI,KAAK,aAAa,IAAI,QAC1B,kBAAI,KAAK,aAAa,IAAI,WACvB;AAAA,QACA,KAAK,IAAI,kBAAI,aAAa,eAAe,aAAa,CAAC;AAAA,QACvD,CAAC,KAAK,KAAK,GAAG,KAAK,EAAE;AAAA,QACrB,CAAC,WAAW,CAAC;AAAA,QACb;AAAA,MACD,IACC;AAEJ,YAAM,mBAAmB,KAAK;AAAA,QAC7B,aAAa,UAAU;AAAA,QACvB,UAAU,UAAU;AAAA,MACrB;AACA,YAAM,cAAc,mBAAmB,2BAA2B;AAElE,YAAM,mBAAe,qBAAM,QAAQ,GAAG,cAAc,CAAC;AAErD,YAAM,kCAAkC,KAAK;AAAA,QAC5C;AAAA,SACC,aAAa,UAAU,YAAY;AAAA,MACrC;AACA,YAAM,iCAAiC,KAAK;AAAA,QAC3C;AAAA,SACC,UAAU,UAAU,YAAY;AAAA,MAClC;AAEA,YAAM,cAAc;AAAA,QACnB;AAAA,QACA;AAAA,QACA,iBAAiB;AAAA,QACjB,gBAAgB;AAAA,QAChB,eAAe,YAAY,CAAC,GAAG;AAAA,QAC/B,eAAe,UAAU;AAAA,QACzB,cAAc;AAAA,MACf;AAEA,mBAAa,KAAK,WAAW;AAE7B,UAAI,QAAQ,WAAW,uBAAuB,MAAM;AACnD,cAAM,kBAAkB,aAAa,kBAAkB;AACvD,wBAAgB,eAAe;AAC/B,wBAAgB,iBAAiB;AAAA,MAClC,WAAW,QAAQ,SAAS,QAAQ;AACnC,6BAAqB;AAAA,MACtB;AAAA,IACD;AAEA,aAAS,OAAO,GAAG,OAAO,QAAQ,QAAQ;AACzC,YAAM,aAAS,mBAAI,aAAa,IAAI;AAEpC,UAAI,mBAAmB,EAAE,GAAG,GAAG,GAAG,EAAE;AACpC,UAAI,wBAAwB;AAC5B,iBAAW;AAAA,QACV;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACD,KAAK,cAAc;AAClB,cAAM,SAAS,QAAQ,UACpB,mBACA,EAAE,GAAG,OAAO,IAAI,cAAc,GAAG,OAAO,IAAI,aAAa;AAE5D,YAAI,QAAQ,SAAS,QAAQ;AAC5B,6BAAmB;AACnB,gBAAM,WACL,QAAQ,MAAM,aAAa,QAAQ,QAAS,QAAQ,MAAM,UAAU,YAAY;AACjF,cAAI,cAAc,CAAC,UAAU;AAC5B,oCAAwB;AAAA,UACzB,OAAO;AACN,oCAAwB;AAAA,UACzB;AAAA,QACD;AAEA,YAAI,sBAAuB;AAE3B,cAAM,cAAc,kBAAI,IAAI,SAAS,MAAM;AAE3C,cAAM,WACL,iBAAiB,iBAAiB,IAC/B,kBAAI,IAAI,eAAe,CAAC,cAAc,EAAE,IAAI,WAAW,IACvD;AAEJ,cAAM,aACL,iBAAiB,kBAAkB,IAChC,kBAAI,IAAI,eAAe,eAAe,EAAE,IAAI,WAAW,IACvD;AAEJ,YAAI,aAAa,eAAe,eAAe,aAAa;AAC3D,kBAAQ,QAAQ,MAAM;AAAA,YACrB,KAAK;AACJ,oBAAM,KAAK,SAAK,8BAAe,SAAS,CAAC,OAAG,8BAAe,SAAS,CAAC,CAAC;AACtE;AAAA,YACD,KAAK;AACJ,oBAAM,KAAK,SAAK,8BAAe,SAAS,CAAC,OAAG,8BAAe,SAAS,CAAC,CAAC;AACtE;AAAA,YACD,KAAK,SAAS;AACb,oBAAM,YAAY,kBAAI,IAAI,QAAQ,KAAK,MAAM;AAC7C,oBAAM,YAAY,kBAAI,IAAI,QAAQ,KAAK,MAAM;AAC7C,oBAAM;AAAA,gBACL;AAAA,oBACA,8BAAe,UAAU,CAAC;AAAA,oBAC1B,8BAAe,UAAU,CAAC;AAAA,oBAC1B,8BAAe,UAAU,CAAC;AAAA,oBAC1B,8BAAe,UAAU,CAAC;AAAA,oBAC1B,8BAAe,SAAS,CAAC;AAAA,oBACzB,8BAAe,SAAS,CAAC;AAAA,cAC1B;AACA;AAAA,YACD;AAAA,YACA;AACC,uDAAsB,SAAS,MAAM;AAAA,UACvC;AAAA,QACD,OAAO;AACN,kBAAQ,QAAQ,MAAM;AAAA,YACrB,KAAK;AACJ,oBAAM,KAAK,SAAK,8BAAe,SAAS,CAAC,OAAG,8BAAe,SAAS,CAAC,CAAC;AACtE;AAAA,YACD,KAAK;AACJ,oBAAM;AAAA,gBACL;AAAA,oBACA,8BAAe,WAAW,CAAC;AAAA,oBAC3B,8BAAe,WAAW,CAAC;AAAA,gBAE3B;AAAA,oBACA,8BAAe,YAAY,CAAC;AAAA,oBAC5B,8BAAe,YAAY,CAAC;AAAA,oBAC5B,8BAAe,SAAS,CAAC;AAAA,oBACzB,8BAAe,SAAS,CAAC;AAAA,cAC1B;AACA;AAAA,YACD,KAAK,SAAS;AACb,oBAAM,YAAY,kBAAI,IAAI,QAAQ,KAAK,MAAM;AAC7C,oBAAM,YAAY,kBAAI,IAAI,QAAQ,KAAK,MAAM;AAC7C,oBAAM;AAAA,gBACL;AAAA,oBACA,8BAAe,UAAU,CAAC;AAAA,oBAC1B,8BAAe,UAAU,CAAC;AAAA,oBAC1B,8BAAe,UAAU,CAAC;AAAA,oBAC1B,8BAAe,UAAU,CAAC;AAAA,oBAC1B,8BAAe,YAAY,CAAC;AAAA,oBAC5B,8BAAe,YAAY,CAAC;AAAA,cAC7B;AACA;AAAA,YACD;AAAA,YACA;AACC,uDAAsB,SAAS,MAAM;AAAA,UACvC;AAAA,QACD;AAAA,MACD;AAAA,IACD;AAEA,WAAO,MAAM,KAAK,GAAG;AAAA,EACtB;AAAA,EAEQ,uBAAuB,WAAoB,SAA6B;AAC/E,YAAQ,QAAQ,MAAM;AAAA,MACrB,KAAK;AACJ,eAAO;AAAA,MACR,KAAK;AACJ,eAAO,kBAAI,KAAK,WAAW,OAAO;AAAA,MACnC,KAAK;AACJ,eAAO,YAAY;AAAA,UAClB,UAAU;AAAA,UACV,UAAU;AAAA,UACV,QAAQ,IAAI;AAAA,UACZ,QAAQ,IAAI;AAAA,UACZ,QAAQ,IAAI;AAAA,UACZ,QAAQ,IAAI;AAAA,UACZ,QAAQ;AAAA,UACR,QAAQ;AAAA,QACT;AAAA,MACD;AACC,iDAAsB,SAAS,MAAM;AAAA,IACvC;AAAA,EACD;AAAA;AAAA,EAGA,cAA6C;AAC5C,WAAO,KAAK;AAAA,EACb;AAAA;AAAA,EAGA,iBAAiB;AAChB,UAAM,cAAyD,CAAC;AAChE,aAAS,IAAI,GAAG,IAAI,KAAK,SAAS,QAAQ,KAAK;AAC9C,YAAM,WAAW,KAAK,SAAS,IAAI,CAAC;AACpC,YAAM,UAAU,KAAK,SAAS,CAAC;AAE/B,UAAI,QAAQ,OAAO;AAClB,oBAAY,CAAC,IAAI,QAAQ;AACzB;AAAA,MACD;AAEA,UAAI,QAAQ,SAAS,QAAQ;AAC5B;AAAA,MACD;AAEA,UAAI,cAAc;AAClB,cAAQ,QAAQ,MAAM;AAAA,QACrB,KAAK;AACJ,yBAAe,aAAa,kBAAI,IAAI,UAAU,OAAO,EAAE,IAAI;AAC3D;AAAA,QACD,KAAK,SAAS;AACb,yBAAe,kBAAI,IAAI,QAAQ,KAAK,QAAQ,EAAE,IAAI;AAClD,uBAAa,kBAAI,IAAI,QAAQ,KAAK,OAAO,EAAE,IAAI;AAC/C;AAAA,QACD;AAAA,QACA;AACC,mDAAsB,SAAS,MAAM;AAAA,MACvC;AAEA,cAAQ,QAAQ;AAAA,QACf;AAAA,QACA;AAAA,QACA,QAAQ,KAAK,uBAAuB,UAAU,OAAO;AAAA,MACtD;AACA,kBAAY,CAAC,IAAI,QAAQ;AAAA,IAC1B;AAEA,WAAO;AAAA,EACR;AACD;AAEA,MAAM,8BAA8B;AAAA,EACnC,MAAM;AAAA,EACN,MAAM;AAAA,EACN,OAAO;AACR;AAGO,MAAM,8BAA8B,yBAAW;AAAA,EACrD,YACkB,MACA,UACA,QACjB,SACC;AACD,UAAM,OAAO;AALI;AACA;AACA;AAAA,EAIlB;AAAA,EAEQ,YAAiC;AAAA,EACzC,cAAc;AACb,QAAI,KAAK,UAAW,QAAO,KAAK;AAEhC,SAAK,YAAY,CAAC;AAClB,QAAI,OAAO,KAAK,KAAK,SAAS,KAAK,QAAQ;AAC3C,8BAAO,KAAK,SAAS,MAAM;AAE3B,aAAS,IAAI,KAAK,WAAW,GAAG,IAAI,KAAK,QAAQ,KAAK;AACrD,YAAM,UAAU,KAAK,KAAK,SAAS,CAAC;AACpC,gCAAO,QAAQ,SAAS,MAAM;AAE9B,cAAQ,QAAQ,MAAM;AAAA,QACrB,KAAK;AACJ,eAAK,UAAU,KAAK,IAAI,qBAAO,EAAE,OAAO,kBAAI,KAAK,IAAI,GAAG,KAAK,kBAAI,KAAK,OAAO,EAAE,CAAC,CAAC;AACjF;AAAA,QACD,KAAK,SAAS;AACb,eAAK,UAAU;AAAA,YACd,IAAI,4BAAc;AAAA,cACjB,OAAO,kBAAI,KAAK,IAAI;AAAA,cACpB,KAAK,kBAAI,KAAK,QAAQ,GAAG;AAAA,cACzB,KAAK,kBAAI,KAAK,QAAQ,GAAG;AAAA,cACzB,KAAK,kBAAI,KAAK,OAAO;AAAA,cACrB,YAAY,QAAQ;AAAA,YACrB,CAAC;AAAA,UACF;AACA;AAAA,QACD;AAAA,QACA;AACC,mDAAsB,SAAS,MAAM;AAAA,MACvC;AAEA,aAAO;AAAA,IACR;AAEA,WAAO,KAAK;AAAA,EACb;AAAA,EAES,YAAY,SAAmC;AACvD,UAAM,KAAK,KAAK,YAAY,EAC1B,QAAQ,CAAC,MAAM,EAAE,YAAY,OAAO,CAAC,EACrC,OAAO,CAAC,QAAQ,GAAG,aAAa;AAChC,YAAM,OAAO,SAAS,IAAI,CAAC;AAC3B,UAAI,CAAC,KAAM,QAAO;AAClB,aAAO,CAAC,kBAAI,OAAO,MAAM,MAAM;AAAA,IAChC,CAAC;AAEF,QAAI,KAAK,UAAU;AAClB,YAAM,OAAO,GAAG,GAAG,SAAS,CAAC;AAC7B,YAAM,QAAQ,GAAG,CAAC;AAClB,UAAI,CAAC,kBAAI,OAAO,MAAM,KAAK,GAAG;AAC7B,WAAG,KAAK,KAAK;AAAA,MACd;AAAA,IACD;AAEA,WAAO;AAAA,EACR;AAAA,EAES,aAAa,OAAgB,UAAmC;AACxE,QAAI,UAAsB;AAC1B,QAAI,kBAAkB;AAEtB,eAAW,WAAW,KAAK,YAAY,GAAG;AACzC,YAAM,YAAY,QAAQ,aAAa,KAAK;AAC5C,YAAM,WAAW,kBAAI,MAAM,OAAO,SAAS;AAC3C,UAAI,WAAW,iBAAiB;AAC/B,0BAAkB;AAClB,kBAAU;AAAA,MACX;AAAA,IACD;AAEA,8BAAO,SAAS,wBAAwB;AACxC,WAAO;AAAA,EACR;AAAA,EAES,mBACR,GACA,GACA,WAAW,GACX,SACU;AACV,WAAO,MAAM,mBAAmB,GAAG,GAAG,UAAU,OAAO;AAAA,EACxD;AAAA,EACS,iBAAyB;AACjC,WAAO,KAAK,KAAK,IAAI,EAAE,UAAU,KAAK,UAAU,QAAQ,KAAK,OAAO,CAAC;AAAA,EACtE;AACD;AAEA;AAAA;AAAA;AAAA;AAAA;AAKA,MAAM,cAAc;AAAA,EACnB,MAAM,GAAW,IAAY,IAAY,IAAY,IAAY;AAChE,UAAM,KAAK,KAAK,KAAK,IAAI,KAAK,IAAI,KAAK,IAAI;AAC3C,UAAM,KAAK,IAAI,KAAK,IAAI,KAAK,KAAK,KAAK,IAAI;AAC3C,WAAO,IAAI,KAAK,IAAI,KAAK,IAAI;AAAA,EAC9B;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA,OACC,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IAAI,GACH;AACD,QAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI;AAC5B,UAAM,KAAK,IAAI;AACf,UAAM,IAAI;AAEV,QAAI,MAAM;AACV,UAAM;AACN,aAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC3B,YAAM,KAAK,KAAK,YAAY,QAAQ,CAAC,IAAI;AACzC,YAAM,QAAQ,YAAY,MAAM,IAAI,IAAI,IAAI,IAAI,EAAE;AAClD,YAAM,QAAQ,YAAY,MAAM,IAAI,IAAI,IAAI,IAAI,EAAE;AAClD,YAAM,OAAO,QAAQ,QAAQ,QAAQ;AACrC,aAAO,YAAY,QAAQ,CAAC,IAAI,KAAK,KAAK,IAAI;AAAA,IAC/C;AACA,WAAO,KAAK;AAAA,EACb;AAAA,EACA,SAAS;AAAA,IACR;AAAA,IAAS;AAAA,IAAQ;AAAA,IAAS;AAAA,IAAQ;AAAA,IAAS;AAAA,IAAQ;AAAA,IAAS;AAAA,IAAQ;AAAA,IAAS;AAAA,IAAQ;AAAA,IACrF;AAAA,EACD;AAAA,EACA,SAAS;AAAA,IACR;AAAA,IAAQ;AAAA,IAAQ;AAAA,IAAQ;AAAA,IAAQ;AAAA,IAAQ;AAAA,IAAQ;AAAA,IAAQ;AAAA,IAAQ;AAAA,IAAQ;AAAA,IAAQ;AAAA,IAAQ;AAAA,EACzF;AACD;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -69,6 +69,7 @@ const PlainTextLabel = import_react.default.memo(function PlainTextLabel2({
|
|
|
69
69
|
"div",
|
|
70
70
|
{
|
|
71
71
|
className: `${cssPrefix}-label tl-text-wrapper tl-plain-text-wrapper`,
|
|
72
|
+
"aria-hidden": "true",
|
|
72
73
|
"data-font": font,
|
|
73
74
|
"data-align": align,
|
|
74
75
|
"data-hastext": !isEmpty,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/lib/shapes/shared/PlainTextLabel.tsx"],
|
|
4
|
-
"sourcesContent": ["import {\n\tBox,\n\tTLDefaultFillStyle,\n\tTLDefaultFontStyle,\n\tTLDefaultHorizontalAlignStyle,\n\tTLDefaultVerticalAlignStyle,\n\tTLShapeId,\n} from '@tldraw/editor'\nimport React from 'react'\nimport { PlainTextArea } from '../text/PlainTextArea'\nimport { TextHelpers } from './TextHelpers'\nimport { isLegacyAlign } from './legacyProps'\nimport { useEditablePlainText } from './useEditablePlainText'\n\n/** @public */\nexport interface PlainTextLabelProps {\n\tshapeId: TLShapeId\n\ttype: string\n\tfont: TLDefaultFontStyle\n\tfontSize: number\n\tlineHeight: number\n\tfill?: TLDefaultFillStyle\n\talign: TLDefaultHorizontalAlignStyle\n\tverticalAlign: TLDefaultVerticalAlignStyle\n\twrap?: boolean\n\ttext?: string\n\tlabelColor: string\n\tbounds?: Box\n\tisSelected: boolean\n\tonKeyDown?(e: KeyboardEvent): void\n\tclassNamePrefix?: string\n\tstyle?: React.CSSProperties\n\ttextWidth?: number\n\ttextHeight?: number\n\tpadding?: number\n}\n\n/**\n * Renders a text label that can be used inside of shapes.\n * The component has the ability to be edited in place and furthermore\n * supports rich text editing.\n *\n * @public @react\n */\nexport const PlainTextLabel = React.memo(function PlainTextLabel({\n\tshapeId,\n\ttype,\n\ttext: plaintext,\n\tlabelColor,\n\tfont,\n\tfontSize,\n\tlineHeight,\n\talign,\n\tverticalAlign,\n\twrap,\n\tisSelected,\n\tpadding = 0,\n\tonKeyDown: handleKeyDownCustom,\n\tclassNamePrefix,\n\tstyle,\n\ttextWidth,\n\ttextHeight,\n}: PlainTextLabelProps) {\n\tconst { rInput, isEmpty, isEditing, isReadyForEditing, ...editableTextRest } =\n\t\tuseEditablePlainText(shapeId, type, plaintext)\n\n\tconst finalPlainText = TextHelpers.normalizeTextForDom(plaintext || '')\n\tconst hasText = finalPlainText.length > 0\n\n\tconst legacyAlign = isLegacyAlign(align)\n\n\tif (!isEditing && !hasText) {\n\t\treturn null\n\t}\n\n\t// TODO: probably combine tl-text and tl-arrow eventually\n\t// In case you're grepping for this, it breaks down as follows:\n\t// tl-text-label, tl-text-label__inner, tl-text-shape-label, tl-text\n\t// tl-arrow-label, tl-arrow-label__inner, tl-arrow\n\tconst cssPrefix = classNamePrefix || 'tl-text'\n\treturn (\n\t\t<div\n\t\t\tclassName={`${cssPrefix}-label tl-text-wrapper tl-plain-text-wrapper`}\n\t\t\tdata-font={font}\n\t\t\tdata-align={align}\n\t\t\tdata-hastext={!isEmpty}\n\t\t\tdata-isediting={isEditing}\n\t\t\tdata-is-ready-for-editing={isReadyForEditing}\n\t\t\tdata-textwrap={!!wrap}\n\t\t\tdata-isselected={isSelected}\n\t\t\tstyle={{\n\t\t\t\tjustifyContent: align === 'middle' || legacyAlign ? 'center' : align,\n\t\t\t\talignItems: verticalAlign === 'middle' ? 'center' : verticalAlign,\n\t\t\t\tpadding,\n\t\t\t\t...style,\n\t\t\t}}\n\t\t>\n\t\t\t<div\n\t\t\t\tclassName={`${cssPrefix}-label__inner tl-text-content__wrapper`}\n\t\t\t\tstyle={{\n\t\t\t\t\tfontSize,\n\t\t\t\t\tlineHeight: lineHeight.toString(),\n\t\t\t\t\tminHeight: Math.floor(fontSize * lineHeight) + 'px',\n\t\t\t\t\tminWidth: Math.ceil(textWidth || 0),\n\t\t\t\t\tcolor: labelColor,\n\t\t\t\t\twidth: textWidth ? Math.ceil(textWidth) : undefined,\n\t\t\t\t\theight: textHeight ? Math.ceil(textHeight) : undefined,\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t<div className={`${cssPrefix} tl-text tl-text-content`} dir=\"auto\">\n\t\t\t\t\t{finalPlainText.split('\\n').map((lineOfText, index) => (\n\t\t\t\t\t\t<div key={index} dir=\"auto\">\n\t\t\t\t\t\t\t{lineOfText}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t))}\n\t\t\t\t</div>\n\t\t\t\t{(isReadyForEditing || isSelected) && (\n\t\t\t\t\t<PlainTextArea\n\t\t\t\t\t\t// Fudge the ref type because we're using forwardRef and it's not typed correctly.\n\t\t\t\t\t\tref={rInput as any}\n\t\t\t\t\t\ttext={plaintext}\n\t\t\t\t\t\tisEditing={isEditing}\n\t\t\t\t\t\tshapeId={shapeId}\n\t\t\t\t\t\t{...editableTextRest}\n\t\t\t\t\t\thandleKeyDown={handleKeyDownCustom ?? editableTextRest.handleKeyDown}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\t\t\t</div>\n\t\t</div>\n\t)\n})\n\n/**\n * @deprecated Use `PlainTextLabel` instead.\n * @public\n */\nexport const TextLabel = PlainTextLabel\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;
|
|
4
|
+
"sourcesContent": ["import {\n\tBox,\n\tTLDefaultFillStyle,\n\tTLDefaultFontStyle,\n\tTLDefaultHorizontalAlignStyle,\n\tTLDefaultVerticalAlignStyle,\n\tTLShapeId,\n} from '@tldraw/editor'\nimport React from 'react'\nimport { PlainTextArea } from '../text/PlainTextArea'\nimport { TextHelpers } from './TextHelpers'\nimport { isLegacyAlign } from './legacyProps'\nimport { useEditablePlainText } from './useEditablePlainText'\n\n/** @public */\nexport interface PlainTextLabelProps {\n\tshapeId: TLShapeId\n\ttype: string\n\tfont: TLDefaultFontStyle\n\tfontSize: number\n\tlineHeight: number\n\tfill?: TLDefaultFillStyle\n\talign: TLDefaultHorizontalAlignStyle\n\tverticalAlign: TLDefaultVerticalAlignStyle\n\twrap?: boolean\n\ttext?: string\n\tlabelColor: string\n\tbounds?: Box\n\tisSelected: boolean\n\tonKeyDown?(e: KeyboardEvent): void\n\tclassNamePrefix?: string\n\tstyle?: React.CSSProperties\n\ttextWidth?: number\n\ttextHeight?: number\n\tpadding?: number\n}\n\n/**\n * Renders a text label that can be used inside of shapes.\n * The component has the ability to be edited in place and furthermore\n * supports rich text editing.\n *\n * @public @react\n */\nexport const PlainTextLabel = React.memo(function PlainTextLabel({\n\tshapeId,\n\ttype,\n\ttext: plaintext,\n\tlabelColor,\n\tfont,\n\tfontSize,\n\tlineHeight,\n\talign,\n\tverticalAlign,\n\twrap,\n\tisSelected,\n\tpadding = 0,\n\tonKeyDown: handleKeyDownCustom,\n\tclassNamePrefix,\n\tstyle,\n\ttextWidth,\n\ttextHeight,\n}: PlainTextLabelProps) {\n\tconst { rInput, isEmpty, isEditing, isReadyForEditing, ...editableTextRest } =\n\t\tuseEditablePlainText(shapeId, type, plaintext)\n\n\tconst finalPlainText = TextHelpers.normalizeTextForDom(plaintext || '')\n\tconst hasText = finalPlainText.length > 0\n\n\tconst legacyAlign = isLegacyAlign(align)\n\n\tif (!isEditing && !hasText) {\n\t\treturn null\n\t}\n\n\t// TODO: probably combine tl-text and tl-arrow eventually\n\t// In case you're grepping for this, it breaks down as follows:\n\t// tl-text-label, tl-text-label__inner, tl-text-shape-label, tl-text\n\t// tl-arrow-label, tl-arrow-label__inner, tl-arrow\n\tconst cssPrefix = classNamePrefix || 'tl-text'\n\treturn (\n\t\t<div\n\t\t\tclassName={`${cssPrefix}-label tl-text-wrapper tl-plain-text-wrapper`}\n\t\t\taria-hidden=\"true\"\n\t\t\tdata-font={font}\n\t\t\tdata-align={align}\n\t\t\tdata-hastext={!isEmpty}\n\t\t\tdata-isediting={isEditing}\n\t\t\tdata-is-ready-for-editing={isReadyForEditing}\n\t\t\tdata-textwrap={!!wrap}\n\t\t\tdata-isselected={isSelected}\n\t\t\tstyle={{\n\t\t\t\tjustifyContent: align === 'middle' || legacyAlign ? 'center' : align,\n\t\t\t\talignItems: verticalAlign === 'middle' ? 'center' : verticalAlign,\n\t\t\t\tpadding,\n\t\t\t\t...style,\n\t\t\t}}\n\t\t>\n\t\t\t<div\n\t\t\t\tclassName={`${cssPrefix}-label__inner tl-text-content__wrapper`}\n\t\t\t\tstyle={{\n\t\t\t\t\tfontSize,\n\t\t\t\t\tlineHeight: lineHeight.toString(),\n\t\t\t\t\tminHeight: Math.floor(fontSize * lineHeight) + 'px',\n\t\t\t\t\tminWidth: Math.ceil(textWidth || 0),\n\t\t\t\t\tcolor: labelColor,\n\t\t\t\t\twidth: textWidth ? Math.ceil(textWidth) : undefined,\n\t\t\t\t\theight: textHeight ? Math.ceil(textHeight) : undefined,\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t<div className={`${cssPrefix} tl-text tl-text-content`} dir=\"auto\">\n\t\t\t\t\t{finalPlainText.split('\\n').map((lineOfText, index) => (\n\t\t\t\t\t\t<div key={index} dir=\"auto\">\n\t\t\t\t\t\t\t{lineOfText}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t))}\n\t\t\t\t</div>\n\t\t\t\t{(isReadyForEditing || isSelected) && (\n\t\t\t\t\t<PlainTextArea\n\t\t\t\t\t\t// Fudge the ref type because we're using forwardRef and it's not typed correctly.\n\t\t\t\t\t\tref={rInput as any}\n\t\t\t\t\t\ttext={plaintext}\n\t\t\t\t\t\tisEditing={isEditing}\n\t\t\t\t\t\tshapeId={shapeId}\n\t\t\t\t\t\t{...editableTextRest}\n\t\t\t\t\t\thandleKeyDown={handleKeyDownCustom ?? editableTextRest.handleKeyDown}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\t\t\t</div>\n\t\t</div>\n\t)\n})\n\n/**\n * @deprecated Use `PlainTextLabel` instead.\n * @public\n */\nexport const TextLabel = PlainTextLabel\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAkGG;AA1FH,mBAAkB;AAClB,2BAA8B;AAC9B,yBAA4B;AAC5B,yBAA8B;AAC9B,kCAAqC;AAgC9B,MAAM,iBAAiB,aAAAA,QAAM,KAAK,SAASC,gBAAe;AAAA,EAChE;AAAA,EACA;AAAA,EACA,MAAM;AAAA,EACN;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,UAAU;AAAA,EACV,WAAW;AAAA,EACX;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD,GAAwB;AACvB,QAAM,EAAE,QAAQ,SAAS,WAAW,mBAAmB,GAAG,iBAAiB,QAC1E,kDAAqB,SAAS,MAAM,SAAS;AAE9C,QAAM,iBAAiB,+BAAY,oBAAoB,aAAa,EAAE;AACtE,QAAM,UAAU,eAAe,SAAS;AAExC,QAAM,kBAAc,kCAAc,KAAK;AAEvC,MAAI,CAAC,aAAa,CAAC,SAAS;AAC3B,WAAO;AAAA,EACR;AAMA,QAAM,YAAY,mBAAmB;AACrC,SACC;AAAA,IAAC;AAAA;AAAA,MACA,WAAW,GAAG,SAAS;AAAA,MACvB,eAAY;AAAA,MACZ,aAAW;AAAA,MACX,cAAY;AAAA,MACZ,gBAAc,CAAC;AAAA,MACf,kBAAgB;AAAA,MAChB,6BAA2B;AAAA,MAC3B,iBAAe,CAAC,CAAC;AAAA,MACjB,mBAAiB;AAAA,MACjB,OAAO;AAAA,QACN,gBAAgB,UAAU,YAAY,cAAc,WAAW;AAAA,QAC/D,YAAY,kBAAkB,WAAW,WAAW;AAAA,QACpD;AAAA,QACA,GAAG;AAAA,MACJ;AAAA,MAEA;AAAA,QAAC;AAAA;AAAA,UACA,WAAW,GAAG,SAAS;AAAA,UACvB,OAAO;AAAA,YACN;AAAA,YACA,YAAY,WAAW,SAAS;AAAA,YAChC,WAAW,KAAK,MAAM,WAAW,UAAU,IAAI;AAAA,YAC/C,UAAU,KAAK,KAAK,aAAa,CAAC;AAAA,YAClC,OAAO;AAAA,YACP,OAAO,YAAY,KAAK,KAAK,SAAS,IAAI;AAAA,YAC1C,QAAQ,aAAa,KAAK,KAAK,UAAU,IAAI;AAAA,UAC9C;AAAA,UAEA;AAAA,wDAAC,SAAI,WAAW,GAAG,SAAS,4BAA4B,KAAI,QAC1D,yBAAe,MAAM,IAAI,EAAE,IAAI,CAAC,YAAY,UAC5C,4CAAC,SAAgB,KAAI,QACnB,wBADQ,KAEV,CACA,GACF;AAAA,aACE,qBAAqB,eACtB;AAAA,cAAC;AAAA;AAAA,gBAEA,KAAK;AAAA,gBACL,MAAM;AAAA,gBACN;AAAA,gBACA;AAAA,gBACC,GAAG;AAAA,gBACJ,eAAe,uBAAuB,iBAAiB;AAAA;AAAA,YACxD;AAAA;AAAA;AAAA,MAEF;AAAA;AAAA,EACD;AAEF,CAAC;AAMM,MAAM,YAAY;",
|
|
6
6
|
"names": ["React", "PlainTextLabel"]
|
|
7
7
|
}
|
|
@@ -103,6 +103,7 @@ const RichTextLabel = import_react.default.memo(function RichTextLabel2({
|
|
|
103
103
|
"div",
|
|
104
104
|
{
|
|
105
105
|
className: `${cssPrefix}-label tl-text-wrapper tl-rich-text-wrapper`,
|
|
106
|
+
"aria-hidden": "true",
|
|
106
107
|
"data-font": font,
|
|
107
108
|
"data-align": align,
|
|
108
109
|
"data-hastext": !isEmpty,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/lib/shapes/shared/RichTextLabel.tsx"],
|
|
4
|
-
"sourcesContent": ["import {\n\tBox,\n\tDefaultFontFamilies,\n\tTLDefaultFillStyle,\n\tTLDefaultFontStyle,\n\tTLDefaultHorizontalAlignStyle,\n\tTLDefaultVerticalAlignStyle,\n\tTLEventInfo,\n\tTLRichText,\n\tTLShapeId,\n\tpreventDefault,\n\tuseEditor,\n\tuseReactor,\n\tuseValue,\n} from '@tldraw/editor'\nimport React, { useMemo } from 'react'\nimport { renderHtmlFromRichText } from '../../utils/text/richText'\nimport { RichTextArea } from '../text/RichTextArea'\nimport { TEXT_PROPS } from './default-shape-constants'\nimport { isLegacyAlign } from './legacyProps'\nimport { useEditableRichText } from './useEditableRichText'\n\n/** @public */\nexport interface RichTextLabelProps {\n\tshapeId: TLShapeId\n\ttype: string\n\tfont: TLDefaultFontStyle\n\tfontSize: number\n\tlineHeight: number\n\tfill?: TLDefaultFillStyle\n\talign: TLDefaultHorizontalAlignStyle\n\tverticalAlign: TLDefaultVerticalAlignStyle\n\twrap?: boolean\n\trichText?: TLRichText\n\tlabelColor: string\n\tbounds?: Box\n\tisSelected: boolean\n\tonKeyDown?(e: KeyboardEvent): void\n\tclassNamePrefix?: string\n\tstyle?: React.CSSProperties\n\ttextWidth?: number\n\ttextHeight?: number\n\tpadding?: number\n\thasCustomTabBehavior?: boolean\n}\n\n/**\n * Renders a text label that can be used inside of shapes.\n * The component has the ability to be edited in place and furthermore\n * supports rich text editing.\n *\n * @public @react\n */\nexport const RichTextLabel = React.memo(function RichTextLabel({\n\tshapeId,\n\ttype,\n\trichText,\n\tlabelColor,\n\tfont,\n\tfontSize,\n\tlineHeight,\n\talign,\n\tverticalAlign,\n\twrap,\n\tisSelected,\n\tpadding = 0,\n\tonKeyDown: handleKeyDownCustom,\n\tclassNamePrefix,\n\tstyle,\n\ttextWidth,\n\ttextHeight,\n\thasCustomTabBehavior,\n}: RichTextLabelProps) {\n\tconst editor = useEditor()\n\tconst isDragging = React.useRef(false)\n\tconst { rInput, isEmpty, isEditing, isReadyForEditing, ...editableTextRest } =\n\t\tuseEditableRichText(shapeId, type, richText)\n\n\tconst html = useMemo(() => {\n\t\tif (richText) {\n\t\t\treturn renderHtmlFromRichText(editor, richText)\n\t\t}\n\t}, [editor, richText])\n\n\tconst selectToolActive = useValue(\n\t\t'isSelectToolActive',\n\t\t() => editor.getCurrentToolId() === 'select',\n\t\t[editor]\n\t)\n\n\tuseReactor(\n\t\t'isDragging',\n\t\t() => {\n\t\t\teditor.getInstanceState()\n\t\t\tisDragging.current = editor.inputs.isDragging\n\t\t},\n\t\t[editor]\n\t)\n\n\tconst legacyAlign = isLegacyAlign(align)\n\n\tconst handlePointerDown = (e: React.MouseEvent<HTMLDivElement>) => {\n\t\tif (e.target instanceof HTMLElement && (e.target.tagName === 'A' || e.target.closest('a'))) {\n\t\t\t// This mousedown prevent default is to let dragging when over a link work.\n\t\t\tpreventDefault(e)\n\n\t\t\tif (!selectToolActive) return\n\t\t\tconst link = e.target.closest('a')?.getAttribute('href') ?? ''\n\t\t\t// We don't get the mouseup event later because we preventDefault\n\t\t\t// so we have to do it manually.\n\t\t\tconst handlePointerUp = (e: TLEventInfo) => {\n\t\t\t\tif (e.name !== 'pointer_up') return\n\n\t\t\t\tif (!isDragging.current) {\n\t\t\t\t\twindow.open(link, '_blank', 'noopener, noreferrer')\n\t\t\t\t}\n\t\t\t\teditor.off('event', handlePointerUp)\n\t\t\t}\n\t\t\teditor.on('event', handlePointerUp)\n\t\t}\n\t}\n\n\t// Should be guarded higher up so that this doesn't render... but repeated here. This should never be true.\n\tif (!isEditing && isEmpty) return null\n\n\t// TODO: probably combine tl-text and tl-arrow eventually\n\tconst cssPrefix = classNamePrefix || 'tl-text'\n\treturn (\n\t\t<div\n\t\t\tclassName={`${cssPrefix}-label tl-text-wrapper tl-rich-text-wrapper`}\n\t\t\tdata-font={font}\n\t\t\tdata-align={align}\n\t\t\tdata-hastext={!isEmpty}\n\t\t\tdata-isediting={isEditing}\n\t\t\tdata-textwrap={!!wrap}\n\t\t\tdata-isselected={isSelected}\n\t\t\tstyle={{\n\t\t\t\tjustifyContent: align === 'middle' || legacyAlign ? 'center' : align,\n\t\t\t\talignItems: verticalAlign === 'middle' ? 'center' : verticalAlign,\n\t\t\t\tpadding,\n\t\t\t\t...style,\n\t\t\t}}\n\t\t>\n\t\t\t<div\n\t\t\t\tclassName={`${cssPrefix}-label__inner tl-text-content__wrapper`}\n\t\t\t\tstyle={{\n\t\t\t\t\tfontSize,\n\t\t\t\t\tlineHeight: lineHeight.toString(),\n\t\t\t\t\tminHeight: Math.floor(fontSize * lineHeight) + 'px',\n\t\t\t\t\tminWidth: Math.ceil(textWidth || 0),\n\t\t\t\t\tcolor: labelColor,\n\t\t\t\t\twidth: textWidth ? Math.ceil(textWidth) : undefined,\n\t\t\t\t\theight: textHeight ? Math.ceil(textHeight) : undefined,\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t<div className={`${cssPrefix} tl-text tl-text-content`} dir=\"auto\">\n\t\t\t\t\t{richText && (\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t\tclassName=\"tl-rich-text\"\n\t\t\t\t\t\t\tdata-is-select-tool-active={selectToolActive}\n\t\t\t\t\t\t\t// todo: see if I can abuse this\n\t\t\t\t\t\t\tdangerouslySetInnerHTML={{ __html: html || '' }}\n\t\t\t\t\t\t\tonPointerDown={handlePointerDown}\n\t\t\t\t\t\t\tdata-is-ready-for-editing={isReadyForEditing}\n\t\t\t\t\t\t/>\n\t\t\t\t\t)}\n\t\t\t\t</div>\n\t\t\t\t{(isReadyForEditing || isSelected) && (\n\t\t\t\t\t<RichTextArea\n\t\t\t\t\t\t// Fudge the ref type because we're using forwardRef and it's not typed correctly.\n\t\t\t\t\t\tref={rInput as any}\n\t\t\t\t\t\trichText={richText}\n\t\t\t\t\t\tisEditing={isEditing}\n\t\t\t\t\t\tshapeId={shapeId}\n\t\t\t\t\t\t{...editableTextRest}\n\t\t\t\t\t\thasCustomTabBehavior={hasCustomTabBehavior}\n\t\t\t\t\t\thandleKeyDown={handleKeyDownCustom ?? editableTextRest.handleKeyDown}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\t\t\t</div>\n\t\t</div>\n\t)\n})\n\n/** @public */\nexport interface RichTextSVGProps {\n\tbounds: Box\n\trichText: TLRichText\n\tfontSize: number\n\tfont: TLDefaultFontStyle\n\talign: TLDefaultHorizontalAlignStyle\n\tverticalAlign: TLDefaultVerticalAlignStyle\n\twrap?: boolean\n\tlabelColor: string\n\tpadding: number\n\tshowTextOutline?: boolean\n}\n\n/**\n * Renders a rich text string as SVG given bounds and text properties.\n *\n * @public @react\n */\nexport function RichTextSVG({\n\tbounds,\n\trichText,\n\tfontSize,\n\tfont,\n\talign,\n\tverticalAlign,\n\twrap,\n\tlabelColor,\n\tpadding,\n\tshowTextOutline = true,\n}: RichTextSVGProps) {\n\tconst editor = useEditor()\n\tconst html = renderHtmlFromRichText(editor, richText)\n\tconst textAlign =\n\t\talign === 'middle'\n\t\t\t? ('center' as const)\n\t\t\t: align === 'start'\n\t\t\t\t? ('start' as const)\n\t\t\t\t: ('end' as const)\n\tconst justifyContent =\n\t\talign === 'middle'\n\t\t\t? ('center' as const)\n\t\t\t: align === 'start'\n\t\t\t\t? ('flex-start' as const)\n\t\t\t\t: ('flex-end' as const)\n\tconst alignItems =\n\t\tverticalAlign === 'middle' ? 'center' : verticalAlign === 'start' ? 'flex-start' : 'flex-end'\n\tconst wrapperStyle = {\n\t\tdisplay: 'flex',\n\t\tfontFamily: DefaultFontFamilies[font],\n\t\theight: `100%`,\n\t\tjustifyContent,\n\t\talignItems,\n\t\tpadding: `${padding}px`,\n\t}\n\tconst style = {\n\t\tfontSize: `${fontSize}px`,\n\t\twrap: wrap ? 'wrap' : 'nowrap',\n\t\tcolor: labelColor,\n\t\tlineHeight: TEXT_PROPS.lineHeight,\n\t\ttextAlign,\n\t\twidth: '100%',\n\t\twordWrap: 'break-word' as const,\n\t\toverflowWrap: 'break-word' as const,\n\t\twhiteSpace: 'pre-wrap',\n\t\ttextShadow: showTextOutline ? 'var(--tl-text-outline)' : 'none',\n\t}\n\n\treturn (\n\t\t<foreignObject\n\t\t\tx={bounds.minX}\n\t\t\ty={bounds.minY}\n\t\t\twidth={bounds.w}\n\t\t\theight={bounds.h}\n\t\t\tclassName=\"tl-export-embed-styles tl-rich-text tl-rich-text-svg\"\n\t\t>\n\t\t\t<div style={wrapperStyle}>\n\t\t\t\t<div dangerouslySetInnerHTML={{ __html: html }} style={style} />\n\t\t\t</div>\n\t\t</foreignObject>\n\t)\n}\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;
|
|
4
|
+
"sourcesContent": ["import {\n\tBox,\n\tDefaultFontFamilies,\n\tTLDefaultFillStyle,\n\tTLDefaultFontStyle,\n\tTLDefaultHorizontalAlignStyle,\n\tTLDefaultVerticalAlignStyle,\n\tTLEventInfo,\n\tTLRichText,\n\tTLShapeId,\n\tpreventDefault,\n\tuseEditor,\n\tuseReactor,\n\tuseValue,\n} from '@tldraw/editor'\nimport React, { useMemo } from 'react'\nimport { renderHtmlFromRichText } from '../../utils/text/richText'\nimport { RichTextArea } from '../text/RichTextArea'\nimport { TEXT_PROPS } from './default-shape-constants'\nimport { isLegacyAlign } from './legacyProps'\nimport { useEditableRichText } from './useEditableRichText'\n\n/** @public */\nexport interface RichTextLabelProps {\n\tshapeId: TLShapeId\n\ttype: string\n\tfont: TLDefaultFontStyle\n\tfontSize: number\n\tlineHeight: number\n\tfill?: TLDefaultFillStyle\n\talign: TLDefaultHorizontalAlignStyle\n\tverticalAlign: TLDefaultVerticalAlignStyle\n\twrap?: boolean\n\trichText?: TLRichText\n\tlabelColor: string\n\tbounds?: Box\n\tisSelected: boolean\n\tonKeyDown?(e: KeyboardEvent): void\n\tclassNamePrefix?: string\n\tstyle?: React.CSSProperties\n\ttextWidth?: number\n\ttextHeight?: number\n\tpadding?: number\n\thasCustomTabBehavior?: boolean\n}\n\n/**\n * Renders a text label that can be used inside of shapes.\n * The component has the ability to be edited in place and furthermore\n * supports rich text editing.\n *\n * @public @react\n */\nexport const RichTextLabel = React.memo(function RichTextLabel({\n\tshapeId,\n\ttype,\n\trichText,\n\tlabelColor,\n\tfont,\n\tfontSize,\n\tlineHeight,\n\talign,\n\tverticalAlign,\n\twrap,\n\tisSelected,\n\tpadding = 0,\n\tonKeyDown: handleKeyDownCustom,\n\tclassNamePrefix,\n\tstyle,\n\ttextWidth,\n\ttextHeight,\n\thasCustomTabBehavior,\n}: RichTextLabelProps) {\n\tconst editor = useEditor()\n\tconst isDragging = React.useRef(false)\n\tconst { rInput, isEmpty, isEditing, isReadyForEditing, ...editableTextRest } =\n\t\tuseEditableRichText(shapeId, type, richText)\n\n\tconst html = useMemo(() => {\n\t\tif (richText) {\n\t\t\treturn renderHtmlFromRichText(editor, richText)\n\t\t}\n\t}, [editor, richText])\n\n\tconst selectToolActive = useValue(\n\t\t'isSelectToolActive',\n\t\t() => editor.getCurrentToolId() === 'select',\n\t\t[editor]\n\t)\n\n\tuseReactor(\n\t\t'isDragging',\n\t\t() => {\n\t\t\teditor.getInstanceState()\n\t\t\tisDragging.current = editor.inputs.isDragging\n\t\t},\n\t\t[editor]\n\t)\n\n\tconst legacyAlign = isLegacyAlign(align)\n\n\tconst handlePointerDown = (e: React.MouseEvent<HTMLDivElement>) => {\n\t\tif (e.target instanceof HTMLElement && (e.target.tagName === 'A' || e.target.closest('a'))) {\n\t\t\t// This mousedown prevent default is to let dragging when over a link work.\n\t\t\tpreventDefault(e)\n\n\t\t\tif (!selectToolActive) return\n\t\t\tconst link = e.target.closest('a')?.getAttribute('href') ?? ''\n\t\t\t// We don't get the mouseup event later because we preventDefault\n\t\t\t// so we have to do it manually.\n\t\t\tconst handlePointerUp = (e: TLEventInfo) => {\n\t\t\t\tif (e.name !== 'pointer_up') return\n\n\t\t\t\tif (!isDragging.current) {\n\t\t\t\t\twindow.open(link, '_blank', 'noopener, noreferrer')\n\t\t\t\t}\n\t\t\t\teditor.off('event', handlePointerUp)\n\t\t\t}\n\t\t\teditor.on('event', handlePointerUp)\n\t\t}\n\t}\n\n\t// Should be guarded higher up so that this doesn't render... but repeated here. This should never be true.\n\tif (!isEditing && isEmpty) return null\n\n\t// TODO: probably combine tl-text and tl-arrow eventually\n\tconst cssPrefix = classNamePrefix || 'tl-text'\n\treturn (\n\t\t<div\n\t\t\tclassName={`${cssPrefix}-label tl-text-wrapper tl-rich-text-wrapper`}\n\t\t\taria-hidden=\"true\"\n\t\t\tdata-font={font}\n\t\t\tdata-align={align}\n\t\t\tdata-hastext={!isEmpty}\n\t\t\tdata-isediting={isEditing}\n\t\t\tdata-textwrap={!!wrap}\n\t\t\tdata-isselected={isSelected}\n\t\t\tstyle={{\n\t\t\t\tjustifyContent: align === 'middle' || legacyAlign ? 'center' : align,\n\t\t\t\talignItems: verticalAlign === 'middle' ? 'center' : verticalAlign,\n\t\t\t\tpadding,\n\t\t\t\t...style,\n\t\t\t}}\n\t\t>\n\t\t\t<div\n\t\t\t\tclassName={`${cssPrefix}-label__inner tl-text-content__wrapper`}\n\t\t\t\tstyle={{\n\t\t\t\t\tfontSize,\n\t\t\t\t\tlineHeight: lineHeight.toString(),\n\t\t\t\t\tminHeight: Math.floor(fontSize * lineHeight) + 'px',\n\t\t\t\t\tminWidth: Math.ceil(textWidth || 0),\n\t\t\t\t\tcolor: labelColor,\n\t\t\t\t\twidth: textWidth ? Math.ceil(textWidth) : undefined,\n\t\t\t\t\theight: textHeight ? Math.ceil(textHeight) : undefined,\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t<div className={`${cssPrefix} tl-text tl-text-content`} dir=\"auto\">\n\t\t\t\t\t{richText && (\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t\tclassName=\"tl-rich-text\"\n\t\t\t\t\t\t\tdata-is-select-tool-active={selectToolActive}\n\t\t\t\t\t\t\t// todo: see if I can abuse this\n\t\t\t\t\t\t\tdangerouslySetInnerHTML={{ __html: html || '' }}\n\t\t\t\t\t\t\tonPointerDown={handlePointerDown}\n\t\t\t\t\t\t\tdata-is-ready-for-editing={isReadyForEditing}\n\t\t\t\t\t\t/>\n\t\t\t\t\t)}\n\t\t\t\t</div>\n\t\t\t\t{(isReadyForEditing || isSelected) && (\n\t\t\t\t\t<RichTextArea\n\t\t\t\t\t\t// Fudge the ref type because we're using forwardRef and it's not typed correctly.\n\t\t\t\t\t\tref={rInput as any}\n\t\t\t\t\t\trichText={richText}\n\t\t\t\t\t\tisEditing={isEditing}\n\t\t\t\t\t\tshapeId={shapeId}\n\t\t\t\t\t\t{...editableTextRest}\n\t\t\t\t\t\thasCustomTabBehavior={hasCustomTabBehavior}\n\t\t\t\t\t\thandleKeyDown={handleKeyDownCustom ?? editableTextRest.handleKeyDown}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\t\t\t</div>\n\t\t</div>\n\t)\n})\n\n/** @public */\nexport interface RichTextSVGProps {\n\tbounds: Box\n\trichText: TLRichText\n\tfontSize: number\n\tfont: TLDefaultFontStyle\n\talign: TLDefaultHorizontalAlignStyle\n\tverticalAlign: TLDefaultVerticalAlignStyle\n\twrap?: boolean\n\tlabelColor: string\n\tpadding: number\n\tshowTextOutline?: boolean\n}\n\n/**\n * Renders a rich text string as SVG given bounds and text properties.\n *\n * @public @react\n */\nexport function RichTextSVG({\n\tbounds,\n\trichText,\n\tfontSize,\n\tfont,\n\talign,\n\tverticalAlign,\n\twrap,\n\tlabelColor,\n\tpadding,\n\tshowTextOutline = true,\n}: RichTextSVGProps) {\n\tconst editor = useEditor()\n\tconst html = renderHtmlFromRichText(editor, richText)\n\tconst textAlign =\n\t\talign === 'middle'\n\t\t\t? ('center' as const)\n\t\t\t: align === 'start'\n\t\t\t\t? ('start' as const)\n\t\t\t\t: ('end' as const)\n\tconst justifyContent =\n\t\talign === 'middle'\n\t\t\t? ('center' as const)\n\t\t\t: align === 'start'\n\t\t\t\t? ('flex-start' as const)\n\t\t\t\t: ('flex-end' as const)\n\tconst alignItems =\n\t\tverticalAlign === 'middle' ? 'center' : verticalAlign === 'start' ? 'flex-start' : 'flex-end'\n\tconst wrapperStyle = {\n\t\tdisplay: 'flex',\n\t\tfontFamily: DefaultFontFamilies[font],\n\t\theight: `100%`,\n\t\tjustifyContent,\n\t\talignItems,\n\t\tpadding: `${padding}px`,\n\t}\n\tconst style = {\n\t\tfontSize: `${fontSize}px`,\n\t\twrap: wrap ? 'wrap' : 'nowrap',\n\t\tcolor: labelColor,\n\t\tlineHeight: TEXT_PROPS.lineHeight,\n\t\ttextAlign,\n\t\twidth: '100%',\n\t\twordWrap: 'break-word' as const,\n\t\toverflowWrap: 'break-word' as const,\n\t\twhiteSpace: 'pre-wrap',\n\t\ttextShadow: showTextOutline ? 'var(--tl-text-outline)' : 'none',\n\t}\n\n\treturn (\n\t\t<foreignObject\n\t\t\tx={bounds.minX}\n\t\t\ty={bounds.minY}\n\t\t\twidth={bounds.w}\n\t\t\theight={bounds.h}\n\t\t\tclassName=\"tl-export-embed-styles tl-rich-text tl-rich-text-svg\"\n\t\t>\n\t\t\t<div style={wrapperStyle}>\n\t\t\t\t<div dangerouslySetInnerHTML={{ __html: html }} style={style} />\n\t\t\t</div>\n\t\t</foreignObject>\n\t)\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAgJG;AAhJH,oBAcO;AACP,mBAA+B;AAC/B,sBAAuC;AACvC,0BAA6B;AAC7B,qCAA2B;AAC3B,yBAA8B;AAC9B,iCAAoC;AAiC7B,MAAM,gBAAgB,aAAAA,QAAM,KAAK,SAASC,eAAc;AAAA,EAC9D;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,UAAU;AAAA,EACV,WAAW;AAAA,EACX;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD,GAAuB;AACtB,QAAM,aAAS,yBAAU;AACzB,QAAM,aAAa,aAAAD,QAAM,OAAO,KAAK;AACrC,QAAM,EAAE,QAAQ,SAAS,WAAW,mBAAmB,GAAG,iBAAiB,QAC1E,gDAAoB,SAAS,MAAM,QAAQ;AAE5C,QAAM,WAAO,sBAAQ,MAAM;AAC1B,QAAI,UAAU;AACb,iBAAO,wCAAuB,QAAQ,QAAQ;AAAA,IAC/C;AAAA,EACD,GAAG,CAAC,QAAQ,QAAQ,CAAC;AAErB,QAAM,uBAAmB;AAAA,IACxB;AAAA,IACA,MAAM,OAAO,iBAAiB,MAAM;AAAA,IACpC,CAAC,MAAM;AAAA,EACR;AAEA;AAAA,IACC;AAAA,IACA,MAAM;AACL,aAAO,iBAAiB;AACxB,iBAAW,UAAU,OAAO,OAAO;AAAA,IACpC;AAAA,IACA,CAAC,MAAM;AAAA,EACR;AAEA,QAAM,kBAAc,kCAAc,KAAK;AAEvC,QAAM,oBAAoB,CAAC,MAAwC;AAClE,QAAI,EAAE,kBAAkB,gBAAgB,EAAE,OAAO,YAAY,OAAO,EAAE,OAAO,QAAQ,GAAG,IAAI;AAE3F,wCAAe,CAAC;AAEhB,UAAI,CAAC,iBAAkB;AACvB,YAAM,OAAO,EAAE,OAAO,QAAQ,GAAG,GAAG,aAAa,MAAM,KAAK;AAG5D,YAAM,kBAAkB,CAACE,OAAmB;AAC3C,YAAIA,GAAE,SAAS,aAAc;AAE7B,YAAI,CAAC,WAAW,SAAS;AACxB,iBAAO,KAAK,MAAM,UAAU,sBAAsB;AAAA,QACnD;AACA,eAAO,IAAI,SAAS,eAAe;AAAA,MACpC;AACA,aAAO,GAAG,SAAS,eAAe;AAAA,IACnC;AAAA,EACD;AAGA,MAAI,CAAC,aAAa,QAAS,QAAO;AAGlC,QAAM,YAAY,mBAAmB;AACrC,SACC;AAAA,IAAC;AAAA;AAAA,MACA,WAAW,GAAG,SAAS;AAAA,MACvB,eAAY;AAAA,MACZ,aAAW;AAAA,MACX,cAAY;AAAA,MACZ,gBAAc,CAAC;AAAA,MACf,kBAAgB;AAAA,MAChB,iBAAe,CAAC,CAAC;AAAA,MACjB,mBAAiB;AAAA,MACjB,OAAO;AAAA,QACN,gBAAgB,UAAU,YAAY,cAAc,WAAW;AAAA,QAC/D,YAAY,kBAAkB,WAAW,WAAW;AAAA,QACpD;AAAA,QACA,GAAG;AAAA,MACJ;AAAA,MAEA;AAAA,QAAC;AAAA;AAAA,UACA,WAAW,GAAG,SAAS;AAAA,UACvB,OAAO;AAAA,YACN;AAAA,YACA,YAAY,WAAW,SAAS;AAAA,YAChC,WAAW,KAAK,MAAM,WAAW,UAAU,IAAI;AAAA,YAC/C,UAAU,KAAK,KAAK,aAAa,CAAC;AAAA,YAClC,OAAO;AAAA,YACP,OAAO,YAAY,KAAK,KAAK,SAAS,IAAI;AAAA,YAC1C,QAAQ,aAAa,KAAK,KAAK,UAAU,IAAI;AAAA,UAC9C;AAAA,UAEA;AAAA,wDAAC,SAAI,WAAW,GAAG,SAAS,4BAA4B,KAAI,QAC1D,sBACA;AAAA,cAAC;AAAA;AAAA,gBACA,WAAU;AAAA,gBACV,8BAA4B;AAAA,gBAE5B,yBAAyB,EAAE,QAAQ,QAAQ,GAAG;AAAA,gBAC9C,eAAe;AAAA,gBACf,6BAA2B;AAAA;AAAA,YAC5B,GAEF;AAAA,aACE,qBAAqB,eACtB;AAAA,cAAC;AAAA;AAAA,gBAEA,KAAK;AAAA,gBACL;AAAA,gBACA;AAAA,gBACA;AAAA,gBACC,GAAG;AAAA,gBACJ;AAAA,gBACA,eAAe,uBAAuB,iBAAiB;AAAA;AAAA,YACxD;AAAA;AAAA;AAAA,MAEF;AAAA;AAAA,EACD;AAEF,CAAC;AAqBM,SAAS,YAAY;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,kBAAkB;AACnB,GAAqB;AACpB,QAAM,aAAS,yBAAU;AACzB,QAAM,WAAO,wCAAuB,QAAQ,QAAQ;AACpD,QAAM,YACL,UAAU,WACN,WACD,UAAU,UACR,UACA;AACN,QAAM,iBACL,UAAU,WACN,WACD,UAAU,UACR,eACA;AACN,QAAM,aACL,kBAAkB,WAAW,WAAW,kBAAkB,UAAU,eAAe;AACpF,QAAM,eAAe;AAAA,IACpB,SAAS;AAAA,IACT,YAAY,kCAAoB,IAAI;AAAA,IACpC,QAAQ;AAAA,IACR;AAAA,IACA;AAAA,IACA,SAAS,GAAG,OAAO;AAAA,EACpB;AACA,QAAM,QAAQ;AAAA,IACb,UAAU,GAAG,QAAQ;AAAA,IACrB,MAAM,OAAO,SAAS;AAAA,IACtB,OAAO;AAAA,IACP,YAAY,0CAAW;AAAA,IACvB;AAAA,IACA,OAAO;AAAA,IACP,UAAU;AAAA,IACV,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,YAAY,kBAAkB,2BAA2B;AAAA,EAC1D;AAEA,SACC;AAAA,IAAC;AAAA;AAAA,MACA,GAAG,OAAO;AAAA,MACV,GAAG,OAAO;AAAA,MACV,OAAO,OAAO;AAAA,MACd,QAAQ,OAAO;AAAA,MACf,WAAU;AAAA,MAEV,sDAAC,SAAI,OAAO,cACX,sDAAC,SAAI,yBAAyB,EAAE,QAAQ,KAAK,GAAG,OAAc,GAC/D;AAAA;AAAA,EACD;AAEF;",
|
|
6
6
|
"names": ["React", "RichTextLabel", "e"]
|
|
7
7
|
}
|