gesso-core 0.6.30 → 0.7.0

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/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { $ as isImeKey, $a as hasVisualState, $i as densityFactors, $n as CharacterCountTextMeasurer, $r as parseTransform, $t as clearFontStacks, A as withOverrideSource, Aa as darkColors, Ai as UiInsetRegistry, An as pointerEventsOf, Ar as findPropertyDefinition, At as wordRangeIn, B as FlexDirection, Ba as rgba, Bi as themesEqual, Bn as EDITOR_PROP, Br as UI_SEMANTIC_STATES, Bt as applyCanvasTextStyle, C as SCROLLBAR_LINGER_MS, Ca as spanAtOffset, Ci as borderRadiusIsZero, Cn as isNodeFocusable, Cr as DEFAULT_LINE_HEIGHT_FACTOR, Ct as scrollsFromRight, D as formatExplanation, Da as textSpansEqual, Di as defineProperty, Dn as isNodeTabStop, Dr as resolvePropertyByName, Dt as paragraphGeometry, E as formatConstraints, Ea as textContentOf, Ei as uniformBorderRadius, En as isNodeSelectable, Er as resolveProperty, Et as offsetAtPointIn, F as clampSize, Fa as colorValuesEqual, Fi as bandOf, Fn as linkOf, Fr as propertyIsInherited, Ft as editingGroupOf, G as CrossAxisAlignment, Ga as DirtyNodeSet, Gi as noThemeExtensions, Gn as isMultiline, Gr as validateRole, Gt as layoutTextLines, H as placeGridItems, Ha as findEnvironmentKey, Hi as withDensity, Hn as editorFor, Hr as isUiSemanticState, Ht as createCanvasTextStyle, I as constraintsEqual, Ia as colorsEqual, Ii as containerBands, In as linkRunAtPointIn, Ir as propertyNarrowers, It as commandForKey, J as parseCrossAxisAlignment, Ja as resetOverrideWarnings, Ji as withThemeExtension, Jn as nextCaretToggle, Jr as validateSubgrid, Jt as spanOf, K as MainAxisAlignment, Ka as clearOverrideProperty, Ki as themeExtension, Kn as isReadOnly, Kr as validateStates, Kt as runCanvasStyleInto, L as tightenConstraints, La as normalizeColor, Li as unknownContainerSize, Ln as setLinkHover, Lr as propertyValuesEqualByName, Lt as detectEditingPlatform, M as contentOffset, Ma as UiBasicColors, Mi as noInsets, Mn as clearLinkHover, Mr as inheritedPropertyFlags, Mt as adjacentField, N as LayoutRecord, Na as colorToHex, Ni as observeViewportInsets, Nn as hasTextLinks, Nr as inheritedPropertyNames, Nt as comparePositions, O as formatNumber, Oa as textStylesEqual, Oi as propertyValuesEqual, On as isPressable, Or as resolveString, Ot as paragraphGeometryFrom, P as Constraints, Pa as colorToRgba, Pi as UiContainerSizeSource, Pn as linkHoverOf, Pr as propertyEffects, Pt as edgeField, Q as capturePointer, Qa as defaultVisualState, Qi as relativeLuminance, Qn as videoFrameSize, Qr as UiTransforms, Qt as bumpFontStack, R as MAX_MEASURES_PER_CHILD, Ra as parseColor, Ri as darkTheme, Rn as CARET_BLINK_MS, Rr as UiProperties, Rt as isPrintable, S as SCROLLBAR_FADE_MS, Sa as resolvedSpansOf, Si as borderRadiusEqual, Sn as setSelectionRange, Sr as UiGraph, St as scrollbarZoneAt, T as describeOverrides, Ta as spansDifferOnlyInPaint, Ti as normalizeBorderRadius, Tn as isNodeInert, Tr as resolveNumber, Tt as hasDrawnText, U as sizeGridTracks, Ua as UiEnvironment, Ui as defineThemeExtension, Un as editorOf, Ur as normalizeStates, Ut as drawText, V as parseFlexDirection, Va as createEnvironmentKey, Vi as withContrast, Vn as caretVisibleAt, Vr as isUiRole, Vt as buildFontString, W as AlignContent, Wa as UiNode, Wi as hasThemeExtension, Wn as isEditableNode, Wr as statesEqual, Wt as fillTextRects, X as CanvasPlatformSurface, Xa as writeOverrideProperty, Xi as highContrastColors, Xn as resolveColorValue, Xr as paintValuesEqual, Xt as textRunBackgrounds, Y as parseMainAxisAlignment, Ya as writeDeclaredProperty, Yi as contrastRatio, Yn as syncEditorValue, Yr as inputsEqual, Yt as textMeasureRequest, Z as UiPlatformAdapter, Za as UiVisualState, Zi as raiseContrast, Zn as isVideoSurface, Zr as pathValuesEqual, Zt as textRunDecorations, _ as LABEL_PADDING_X, _a as typographyEqual, _i as repeat, _n as TEXT_SELECTION_PROP, _o as noKeyModifiers, _r as nextGraphemeEnd, _t as scrollBounds, a as PaintPictureCache, aa as shadowsEqual, ai as gradientsEqual, an as DEFAULT_TEXT_COLOR, ao as UiEventType, ar as caretRectFor, at as UiGestureRecognizer, b as snapScroll, ba as flattenTextSpans, bi as borderRadius, bn as selectableTextOf, bo as DirtyFlags, br as previousWordStart, bt as scrollbarThumb, c as EMPTY_RECORDING, ca as boxShadowArraysEqual, ci as validateGradient, cn as createPaintState, co as UiInputEvent, cr as lineLimit, ct as isScrollContainer, d as tracePathData, da as boxShadowsEqual, di as isAutoLength, dn as normalizeVerticalAlign, do as UiPinchEvent, dr as offsetForVerticalMove, dt as UiFocusManager, ea as defaultSpacing, ei as transform, en as fontStackFor, eo as visualState, er as ParagraphTextMeasurer, et as pointerDeviceOf, f as ScaledImageCache, fa as defaultShapes, fi as isFrLength, fn as resolvePaintState, fo as UiPointerEvent, fr as selectionRects, ft as UiHitTester, g as paintsAfterChildren, ga as isTypographyRole, gi as percent, gn as setMatchRanges, go as UiWheelEvent, gr as lineStartAt, gt as SCROLLBAR_THICKNESS, h as hasDecorationPhase, ha as defaultTypography, hi as minmax, hn as matchRangesOf, ho as UiWheelDeltaMode, hr as lineEndAt, ht as SCROLLBAR_MIN_THUMB, i as traceRoundedRect, ia as defaultShadows, ii as gradientPaint, in as DEFAULT_FONT_WEIGHT, io as UiCompositionEvent, ir as proportionalFontMetrics, it as UiTouchScroller, j as accumulatedOffsetTo, ja as lightColors, ji as insetsEqual, jn as resolveCursor, jr as getPropertyNames, jt as textInputOf, k as labelNode, ka as colorsEqualPalette, ki as UiEnvironmentKeys, kn as isSubtreeInert, kr as closestPropertyName, kt as selectionRectsIn, l as PaintRecorder, la as boxShadowRadius, li as auto, ln as isPaintVisible, lo as UiKeyboardEvent, lr as offsetAtPoint, lt as UiKeyboardController, m as decorationRect, ma as shapesEqual, mi as isPercentLength, mn as clearMatchRanges, mo as UiTextChangeEvent, mr as graphemeBoundaries, mt as SCROLLBAR_INSET, n as createCanvasSurface, na as spacingEqual, ni as transformsEqual, nn as DEFAULT_FONT_FAMILY, no as MOUSE_POINTER, nr as ELLIPSIS, nt as touchActionFor, o as paintPictures, oa as BOX_SHADOW_BLUR_REACH, oi as linearGradient, on as colorToCss, oo as UiFocusEvent, or as lineIndexAtY, ot as UiPinchRecognizer, p as decorationColor, pa as isShapeName, pi as isMinMaxTrack, pn as TEXT_MATCHES_PROP, po as UiSelectionChangeEvent, pr as EditableTextModel, pt as SCROLLBAR_HOVER_ZONE, q as parseAlignContent, qa as overrideSources, qi as themeExtensionsEqual, qn as maskText, qr as UI_SUBGRID_AXES, qt as runFontString, r as Canvas2DRenderer, ra as spacingSteps, ri as MAX_GRADIENT_STOPS, rn as DEFAULT_FONT_SIZE, ro as UiBeforeInputEvent, rr as layoutParagraph, rt as UiEditingController, s as PaintTarget, sa as boxShadow, si as radialGradient, sn as computeObjectFitRect, so as UiGestureEvent, sr as lineIndexForOffset, st as UiWheelController, t as CanvasSurface, ta as scaleSpacing, ti as transformIsIdentity, tn as registerFontStack, to as visualStatesEqual, tr as spannedRunsFor, tt as prepareInputSurface, u as replayPaint, ua as boxShadowReach, ui as fr, un as normalizeTextAlign, uo as UiPasteEvent, ur as offsetAtX, ut as UiPointerController, v as drawOverlayShapes, va as defaultTextStyle, vi as resolveLength, vn as clearSelectionRange, vo as wheelDeltaYOf, vr as nextWordEnd, vt as scrollLeaderOf, w as describeLength, wa as spannedTextOf, wi as borderRadiusValuesEqual, wn as isNodeHitTestable, wr as resolveBoolean, wt as UiInputDispatcher, x as LayoutEngine, xa as hiddenRangesOf, xi as borderRadiusCorners, xn as selectionRangeOf, xo as UiBinding, xr as wordRangeAt, xt as scrollbarThumbs, y as labelOrigin, ya as editableSpansOf, yi as UiBorderRadiuses, yn as selectableTextNodes, yo as UiNodeType, yr as previousGraphemeStart, yt as scrollRange, z as isLayoutProtocol, za as rgb8, zi as lightTheme, zn as CARET_WIDTH, zr as UI_ROLES, zt as EditableLayout } from "./CanvasSurface-CspYfnND.js";
1
+ import { $ as UiPlatformAdapter, $a as UiNode, $i as themeExtension, $n as isVideoSurface, $r as pathValuesEqual, $t as textRunDecorations, A as formatNumber, Aa as hiddenRangesOf, Ai as propertyValuesEqual, An as isPressable, Ao as UiBinding, Ar as resolveString, At as paragraphGeometryFrom, B as MAX_MEASURES_PER_CHILD, Ba as lightColors, Bi as containerBands, Bn as CARET_BLINK_MS, Br as UiProperties, Bt as isPrintable, C as LayoutEngine, Ca as shapesEqual, Ci as borderRadiusCorners, Cn as selectionRangeOf, Co as UiTextChangeEvent, Cr as wordRangeAt, Ct as scrollbarThumbs, D as describeOverrides, Da as defaultTextStyle, Di as normalizeBorderRadius, Dn as isNodeInert, Do as wheelDeltaYOf, Dr as resolveNumber, Dt as hasDrawnText, E as describeLength, Ea as typographyEqual, Ei as borderRadiusValuesEqual, En as isNodeHitTestable, Eo as noKeyModifiers, Er as resolveBoolean, Et as UiInputDispatcher, F as LayoutRecord, Fa as textContentOf, Fi as insetsEqual, Fn as hasTextLinks, Fr as inheritedPropertyNames, Ft as comparePositions, G as sizeGridTracks, Ga as colorsEqual, Gi as withContrast, Gn as editorOf, Gr as normalizeStates, Gt as drawText, H as FlexDirection, Ha as colorToHex, Hi as darkTheme, Hn as EDITOR_PROP, Hr as UI_SEMANTIC_STATES, Ht as applyCanvasTextStyle, I as Constraints, Ia as textSpansEqual, Ii as noInsets, In as linkHoverOf, Ir as propertyEffects, It as edgeField, J as MainAxisAlignment, Ja as rgb8, Ji as lengths, Jn as isReadOnly, Jr as validateStates, Jt as runCanvasStyleInto, K as AlignContent, Ka as normalizeColor, Ki as withDensity, Kn as isEditableNode, Kr as statesEqual, Kt as fillTextRects, L as clampSize, La as textStylesEqual, Li as observeViewportInsets, Ln as linkOf, Lr as propertyIsInherited, Lt as editingGroupOf, M as withOverrideSource, Ma as spanAtOffset, Mi as withPointer, Mn as pointerEventsOf, Mr as findPropertyDefinition, Mt as wordRangeIn, N as accumulatedOffsetTo, Na as spannedTextOf, Ni as UiEnvironmentKeys, Nn as resolveCursor, Nr as getPropertyNames, Nt as textInputOf, O as formatConstraints, Oa as editableSpansOf, Oi as uniformBorderRadius, On as isNodeSelectable, Oo as UiNodeType, Or as resolveProperty, Ot as offsetAtPointIn, P as contentOffset, Pa as spansDifferOnlyInPaint, Pi as UiInsetRegistry, Pn as clearLinkHover, Pr as inheritedPropertyFlags, Pt as adjacentField, Q as CanvasPlatformSurface, Qa as UiEnvironment, Qi as noThemeExtensions, Qn as resolveColorValue, Qr as paintValuesEqual, Qt as textRunBackgrounds, R as constraintsEqual, Ra as colorsEqualPalette, Ri as UiContainerSizeSource, Rn as linkRunAtPointIn, Rr as propertyNarrowers, Rt as commandForKey, S as tracePathData, Sa as isShapeName, Si as borderRadius, Sn as selectableTextOf, So as UiSelectionChangeEvent, Sr as previousWordStart, St as scrollbarThumb, T as SCROLLBAR_LINGER_MS, Ta as isTypographyRole, Ti as borderRadiusIsZero, Tn as isNodeFocusable, To as UiWheelEvent, Tr as DEFAULT_LINE_HEIGHT_FACTOR, Tt as scrollsFromRight, U as parseFlexDirection, Ua as colorToRgba, Ui as lightTheme, Un as caretVisibleAt, Ur as isUiRole, Ut as buildFontString, V as isLayoutProtocol, Va as UiBasicColors, Vi as unknownContainerSize, Vn as CARET_WIDTH, Vr as UI_ROLES, Vt as EditableLayout, W as placeGridItems, Wa as colorValuesEqual, Wi as themesEqual, Wn as editorFor, Wr as isUiSemanticState, Wt as createCanvasTextStyle, X as parseCrossAxisAlignment, Xa as createEnvironmentKey, Xi as defineThemeExtension, Xn as nextCaretToggle, Xr as validateSubgrid, Xt as spanOf, Y as parseAlignContent, Ya as rgba, Yi as unitsEqual, Yn as maskText, Yr as UI_SUBGRID_AXES, Yt as runFontString, Z as parseMainAxisAlignment, Za as findEnvironmentKey, Zi as hasThemeExtension, Zn as syncEditorValue, Zr as inputsEqual, Zt as textMeasureRequest, _ as paintsAfterChildren, _a as boxShadowReach, _i as minmax, _n as matchRangesOf, _o as UiInputEvent, _r as lineEndAt, _t as SCROLLBAR_MIN_THUMB, a as layerRegion, aa as relativeLuminance, ai as MAX_GRADIENT_STOPS, an as DEFAULT_FONT_SIZE, ao as writeOverrideProperty, ar as layoutParagraph, at as UiEditingController, b as labelOrigin, ba as shadowsOf, bi as resolveLength, bn as clearSelectionRange, bo as UiPinchEvent, br as nextWordEnd, bt as scrollLeaderOf, c as paintPictures, ca as scaleSpacing, ci as linearGradient, cn as colorToCss, co as hasVisualState, cr as lineIndexAtY, ct as UiPinchRecognizer, d as PaintRecorder, da as defaultShadows, di as auto, dn as isPaintVisible, do as MOUSE_POINTER, dr as offsetAtPoint, dt as UiKeyboardController, ea as themeExtensionsEqual, ei as UiTransforms, en as bumpFontStack, eo as DirtyNodeSet, er as videoFrameSize, et as capturePointer, f as replayPaint, fa as shadowsEqual, fi as fr, fn as normalizeTextAlign, fo as UiBeforeInputEvent, fr as offsetAtX, ft as UiPointerController, g as hasDecorationPhase, ga as boxShadowRadius, gi as isPercentLength, gn as clearMatchRanges, go as UiGestureEvent, gr as graphemeBoundaries, gt as SCROLLBAR_INSET, h as decorationRect, ha as boxShadowArraysEqual, hi as isMinMaxTrack, hn as TEXT_MATCHES_PROP, ho as UiFocusEvent, hr as EditableTextModel, ht as SCROLLBAR_HOVER_ZONE, i as traceRoundedRect, ia as raiseContrast, ii as transformsEqual, in as DEFAULT_FONT_FAMILY, io as writeDeclaredProperty, ir as ELLIPSIS, it as touchActionFor, j as labelNode, ja as resolvedSpansOf, ji as TOUCH_TARGET, jn as isSubtreeInert, jr as closestPropertyName, jt as selectionRectsIn, k as formatExplanation, ka as flattenTextSpans, ki as defineProperty, kn as isNodeTabStop, ko as DirtyFlags, kr as resolvePropertyByName, kt as paragraphGeometry, l as PaintTarget, la as spacingEqual, li as radialGradient, ln as computeObjectFitRect, lo as visualState, lr as lineIndexForOffset, lt as UiWheelController, m as decorationColor, ma as boxShadow, mi as isFrLength, mn as resolvePaintState, mo as UiEventType, mr as selectionRects, mt as UiHitTester, n as createCanvasSurface, na as contrastRatio, ni as transform, nn as fontStackFor, no as overrideSources, nr as ParagraphTextMeasurer, nt as pointerDeviceOf, o as opacityNeedsLayer, oa as densityFactors, oi as gradientPaint, on as DEFAULT_FONT_WEIGHT, oo as UiVisualState, or as proportionalFontMetrics, ot as UiTouchScroller, p as ScaledImageCache, pa as BOX_SHADOW_BLUR_REACH, pi as isAutoLength, pn as normalizeVerticalAlign, po as UiCompositionEvent, pr as offsetForVerticalMove, pt as UiFocusManager, q as CrossAxisAlignment, qa as parseColor, qi as defaultUnits, qn as isMultiline, qr as validateRole, qt as layoutTextLines, r as Canvas2DRenderer, ra as highContrastColors, ri as transformIsIdentity, rn as registerFontStack, ro as resetOverrideWarnings, rr as spannedRunsFor, rt as prepareInputSurface, s as PaintPictureCache, sa as defaultSpacing, si as gradientsEqual, sn as DEFAULT_TEXT_COLOR, so as defaultVisualState, sr as caretRectFor, st as UiGestureRecognizer, t as CanvasSurface, ta as withThemeExtension, ti as parseTransform, tn as clearFontStacks, to as clearOverrideProperty, tr as CharacterCountTextMeasurer, tt as isImeKey, u as EMPTY_RECORDING, ua as spacingSteps, ui as validateGradient, un as createPaintState, uo as visualStatesEqual, ur as lineLimit, ut as isScrollContainer, v as LABEL_PADDING_X, va as boxShadowValuesEqual, vi as percent, vn as setMatchRanges, vo as UiKeyboardEvent, vr as lineStartAt, vt as SCROLLBAR_THICKNESS, w as SCROLLBAR_FADE_MS, wa as defaultTypography, wi as borderRadiusEqual, wn as setSelectionRange, wo as UiWheelDeltaMode, wr as UiGraph, wt as scrollbarZoneAt, x as snapScroll, xa as defaultShapes, xi as UiBorderRadiuses, xn as selectableTextNodes, xo as UiPointerEvent, xr as previousGraphemeStart, xt as scrollRange, y as drawOverlayShapes, ya as boxShadowsEqual, yi as repeat, yn as TEXT_SELECTION_PROP, yo as UiPasteEvent, yr as nextGraphemeEnd, yt as scrollBounds, z as tightenConstraints, za as darkColors, zi as bandOf, zn as setLinkHover, zr as propertyValuesEqualByName, zt as detectEditingPlatform } from "./CanvasSurface-BpgbOku2.js";
2
2
  import { BehaviorSubject, EMPTY, Subject, combineLatest, distinctUntilChanged, isObservable as isObservable$1, map, of } from "rxjs";
3
3
  //#region src/animation/UiEasing.ts
4
4
  /** Progress equals time. What a spinner and a sweep want. */
@@ -2307,8 +2307,9 @@ var UiGraphBuilder = class {
2307
2307
  * the fragment's children on each emission.
2308
2308
  */
2309
2309
  reconcileChildren(parent, definitions) {
2310
+ const present = definitions.some(isNothing) ? definitions.filter((each) => !isNothing(each)) : definitions;
2310
2311
  if (this.reconciling.has(parent)) {
2311
- this.deferredChildren.set(parent, definitions);
2312
+ this.deferredChildren.set(parent, present);
2312
2313
  return {
2313
2314
  nodes: this.collectChildren(parent),
2314
2315
  changed: false
@@ -2318,7 +2319,7 @@ var UiGraphBuilder = class {
2318
2319
  this.reconcileDepth++;
2319
2320
  let result;
2320
2321
  try {
2321
- result = this.reconcile(parent, definitions);
2322
+ result = this.reconcile(parent, present);
2322
2323
  } finally {
2323
2324
  this.reconcileDepth--;
2324
2325
  this.reconciling.delete(parent);
@@ -2524,7 +2525,7 @@ var UiGraphBuilder = class {
2524
2525
  matchNode(parent, definition, unkeyed, matched) {
2525
2526
  const key = this.elementKey(definition);
2526
2527
  if (key !== void 0) {
2527
- const candidate = this.graph.getNode(`${parent.id}:${key}`);
2528
+ const candidate = this.graph.getNode(`${parent.id}:${idSegment(key)}`);
2528
2529
  if (candidate === void 0 || candidate.parent !== parent || candidate.type !== definition.type) return;
2529
2530
  if (matched.has(candidate)) throw new Error(`Duplicate key '${key}' in parent '${parent.id}'.`);
2530
2531
  return candidate;
@@ -2552,8 +2553,13 @@ var UiGraphBuilder = class {
2552
2553
  createNode(parent, definition, index) {
2553
2554
  const id = this.createNodeId(parent, definition, index);
2554
2555
  const node = this.graph.createNode(id, definition.type);
2555
- this.reconcileProps(node, definition.props, parent);
2556
- this.reconcileChildren(node, definition.children);
2556
+ try {
2557
+ this.reconcileProps(node, definition.props, parent);
2558
+ this.reconcileChildren(node, definition.children);
2559
+ } catch (error) {
2560
+ this.removeSubtree(node);
2561
+ throw error;
2562
+ }
2557
2563
  return node;
2558
2564
  }
2559
2565
  /**
@@ -2583,7 +2589,7 @@ var UiGraphBuilder = class {
2583
2589
  if (isObservable(definition) || isComponentLikeElement(definition)) continue;
2584
2590
  const key = this.elementKey(definition);
2585
2591
  if (key === void 0) continue;
2586
- const candidate = this.graph.getNode(`${parent.id}:${key}`);
2592
+ const candidate = this.graph.getNode(`${parent.id}:${idSegment(key)}`);
2587
2593
  const position = candidate === void 0 ? void 0 : at.get(candidate);
2588
2594
  if (candidate === void 0 || position === void 0 || candidate.type !== definition.type) continue;
2589
2595
  nodes.push(candidate);
@@ -2731,6 +2737,19 @@ var UiGraphBuilder = class {
2731
2737
  return this.modifiers.get(node);
2732
2738
  }
2733
2739
  /**
2740
+ * Where the element a node was last reconciled from was written, for
2741
+ * the inspector and for tools that edit the source. For a component's
2742
+ * anchor it is where the component was used, so walking up from a
2743
+ * node gives the line that made it and then each place it was used.
2744
+ *
2745
+ * Read off the definition the builder already keeps for each node
2746
+ * rather than stored on the node, so it costs a tree nothing when no
2747
+ * element carries one, which is every element in production.
2748
+ */
2749
+ sourceOf(node) {
2750
+ return this.reconciledFrom.get(node)?.source;
2751
+ }
2752
+ /**
2734
2753
  * Rejects a prop nothing will ever read.
2735
2754
  *
2736
2755
  * Every property layout, paint, input or the environment consults is
@@ -2834,7 +2853,7 @@ var UiGraphBuilder = class {
2834
2853
  */
2835
2854
  createNodeId(parent, definition, index) {
2836
2855
  const key = this.elementKey(definition);
2837
- if (key !== void 0) return `${parent.id}:${key}`;
2856
+ if (key !== void 0) return `${parent.id}:${idSegment(key)}`;
2838
2857
  return `${parent.id}:${index}`;
2839
2858
  }
2840
2859
  /**
@@ -2853,7 +2872,7 @@ var UiGraphBuilder = class {
2853
2872
  */
2854
2873
  createComponentAnchorId(parent, element, index) {
2855
2874
  const key = element.key === void 0 || element.key === null ? index : element.key;
2856
- return `${parent.id}:component:${String(key)}`;
2875
+ return `${parent.id}:component:${idSegment(String(key))}`;
2857
2876
  }
2858
2877
  };
2859
2878
  const NO_NODES = /* @__PURE__ */ new Set();
@@ -2882,6 +2901,24 @@ function longestIncreasing(values) {
2882
2901
  for (let index = tops.length > 0 ? tops[tops.length - 1] : -1; index !== -1; index = previous[index]) run.push(index);
2883
2902
  return run.reverse();
2884
2903
  }
2904
+ /**
2905
+ * A key as one segment of a node id, which joins segments with colons.
2906
+ *
2907
+ * A key holding a colon would otherwise read as more than one segment,
2908
+ * and could spell another node's id: a row keyed `a:0` beside a row
2909
+ * keyed `a` whose first child is `a:0` again, which threw "already used
2910
+ * outside parent" for a list keyed by ids (a layers panel's). Escaped,
2911
+ * a key is one segment whatever it holds, and a key with no colon in it
2912
+ * is unchanged.
2913
+ */
2914
+ function idSegment(key) {
2915
+ const text = String(key);
2916
+ return text.includes(":") || text.includes("%") ? text.replace(/%/g, "%25").replace(/:/g, "%3A") : text;
2917
+ }
2918
+ /** A child that draws nothing: null, undefined or a boolean, from plain script. */
2919
+ function isNothing(child) {
2920
+ return child === null || child === void 0 || typeof child === "boolean";
2921
+ }
2885
2922
  //#endregion
2886
2923
  //#region src/composition/UiVirtualWindow.ts
2887
2924
  /** Marks an item wrapper with its index so the host can measure it. */
@@ -4828,14 +4865,17 @@ var UiShortcutRegistry = class {
4828
4865
  * `preventDefault()` so the keyboard controller's own defaults (Tab
4829
4866
  * navigation, Enter on a button, an editable's typing) do not also
4830
4867
  * act on a key that has already been spent.
4868
+ *
4869
+ * `code` is the physical key, which a digit written with Shift
4870
+ * matches on (see `sameStep`).
4831
4871
  */
4832
- handleKey(key, modifiers, focused) {
4872
+ handleKey(key, modifiers, focused, code) {
4833
4873
  if (MODIFIER_KEYS.has(key)) return false;
4834
4874
  if (focused !== null && isTypingInto(focused) && this.isEditingKey(key, modifiers)) {
4835
4875
  this.pending = [];
4836
4876
  return false;
4837
4877
  }
4838
- const step = stepFor(key, modifiers);
4878
+ const step = stepFor(key, modifiers, code);
4839
4879
  const at = this.now();
4840
4880
  if (this.pending.length > 0 && at - this.pendingAt > this.chordTimeout) this.pending = [];
4841
4881
  const sequence = [...this.pending, step];
@@ -5009,7 +5049,7 @@ function matchesPrefix(steps, sequence) {
5009
5049
  return sequence.every((step, index) => sameStep(steps[index], step));
5010
5050
  }
5011
5051
  function sameStep(want, got) {
5012
- if (want.key !== got.key) return false;
5052
+ if (want.key !== got.key && !shiftedDigit(want, got)) return false;
5013
5053
  if (isSymbol(want.key)) {
5014
5054
  if (isBare(want) && got.alt && !got.meta) return true;
5015
5055
  } else if (want.shift !== got.shift) return false;
@@ -5018,6 +5058,15 @@ function sameStep(want, got) {
5018
5058
  return want.ctrl === got.ctrl && want.meta === got.meta;
5019
5059
  }
5020
5060
  /**
5061
+ * A digit written with Shift, pressed: `Shift+1`, as a design tool's
5062
+ * "zoom to fit" is written, is the 1 key with Shift held, whatever
5063
+ * character that types. On a US keyboard it types `!`, on a French one
5064
+ * `1` itself, so the character cannot say; the physical key can.
5065
+ */
5066
+ function shiftedDigit(want, got) {
5067
+ return want.shift && got.shift && /^[0-9]$/.test(want.key) && got.code === `Digit${want.key}`;
5068
+ }
5069
+ /**
5021
5070
  * Whether a key is a character that isn't a letter: punctuation, a digit
5022
5071
  * or a symbol, which different layouts put under different keys and
5023
5072
  * reach with or without Shift. A letter keeps its Shift, which is what
@@ -5027,14 +5076,15 @@ function isSymbol(key) {
5027
5076
  return key.length === 1 && key !== " " && key.toLowerCase() === key.toUpperCase();
5028
5077
  }
5029
5078
  /** The press the person actually made. */
5030
- function stepFor(key, modifiers) {
5079
+ function stepFor(key, modifiers, code) {
5031
5080
  return {
5032
5081
  key: normalizeKey(key),
5033
5082
  mod: false,
5034
5083
  ctrl: modifiers.ctrl,
5035
5084
  meta: modifiers.meta,
5036
5085
  shift: modifiers.shift,
5037
- alt: modifiers.alt
5086
+ alt: modifiers.alt,
5087
+ ...code === void 0 ? {} : { code }
5038
5088
  };
5039
5089
  }
5040
5090
  /**
@@ -6526,7 +6576,7 @@ var Pinchable = class {
6526
6576
  if (box === null) return;
6527
6577
  const clamped = Math.min(Math.max(scale, this.options.minScale ?? 1), this.options.maxScale ?? 8);
6528
6578
  const [unrotatedX, unrotatedY] = unapply(anchorX - box.x - this.translateX, anchorY - box.y - this.translateY, this.scale, this.rotation);
6529
- const [reappliedX, reappliedY] = apply(unrotatedX, unrotatedY, clamped, rotation);
6579
+ const [reappliedX, reappliedY] = apply$1(unrotatedX, unrotatedY, clamped, rotation);
6530
6580
  this.scale = clamped;
6531
6581
  this.rotation = rotation;
6532
6582
  this.translateX = anchorX + panX - box.x - reappliedX;
@@ -6547,7 +6597,7 @@ var Pinchable = class {
6547
6597
  }
6548
6598
  };
6549
6599
  /** Rotates and scales a node-local point, the way the renderers do. */
6550
- function apply(x, y, scale, degrees) {
6600
+ function apply$1(x, y, scale, degrees) {
6551
6601
  const radians = degrees * Math.PI / 180;
6552
6602
  const cos = Math.cos(radians);
6553
6603
  const sin = Math.sin(radians);
@@ -6596,7 +6646,7 @@ const shortcutsKind = defineModifier({
6596
6646
  host.onRoot("keydown", (event) => {
6597
6647
  if (event.defaultPrevented) return;
6598
6648
  const key = event;
6599
- if (registry.handleKey(key.key, key.modifiers, key.target)) {
6649
+ if (registry.handleKey(key.key, key.modifiers, key.target, key.code)) {
6600
6650
  event.preventDefault();
6601
6651
  event.stopPropagation();
6602
6652
  }
@@ -6861,6 +6911,1129 @@ function numberOr(value, fallback) {
6861
6911
  return typeof value === "number" && Number.isFinite(value) ? value : fallback;
6862
6912
  }
6863
6913
  //#endregion
6914
+ //#region src/rendering/svg/SvgXml.ts
6915
+ /**
6916
+ * The document's outermost element, or null when there is none.
6917
+ */
6918
+ function parseSvgXml(source) {
6919
+ const stack = [];
6920
+ let root = null;
6921
+ let index = 0;
6922
+ const close = () => {
6923
+ const element = stack.pop();
6924
+ const parent = stack.at(-1);
6925
+ if (parent === void 0) root ??= element;
6926
+ else parent.children.push(element);
6927
+ };
6928
+ while (index < source.length) {
6929
+ const open = source.indexOf("<", index);
6930
+ if (open === -1) break;
6931
+ if (open > index && stack.length > 0) stack.at(-1).text += decodeEntities(source.slice(index, open));
6932
+ if (source.startsWith("<!--", open)) {
6933
+ const end = source.indexOf("-->", open + 4);
6934
+ index = end === -1 ? source.length : end + 3;
6935
+ continue;
6936
+ }
6937
+ if (source.startsWith("<![CDATA[", open)) {
6938
+ const end = source.indexOf("]]>", open + 9);
6939
+ const text = source.slice(open + 9, end === -1 ? source.length : end);
6940
+ if (stack.length > 0) stack.at(-1).text += text;
6941
+ index = end === -1 ? source.length : end + 3;
6942
+ continue;
6943
+ }
6944
+ if (source[open + 1] === "?" || source[open + 1] === "!") {
6945
+ index = skipDeclaration(source, open);
6946
+ continue;
6947
+ }
6948
+ if (source[open + 1] === "/") {
6949
+ const end = source.indexOf(">", open);
6950
+ const name = source.slice(open + 2, end === -1 ? source.length : end).trim();
6951
+ const at = stack.map((element) => element.name).lastIndexOf(name);
6952
+ if (at !== -1) while (stack.length > at) close();
6953
+ index = end === -1 ? source.length : end + 1;
6954
+ continue;
6955
+ }
6956
+ const tag = readTag(source, open);
6957
+ stack.push({
6958
+ name: tag.name,
6959
+ attributes: tag.attributes,
6960
+ children: [],
6961
+ text: ""
6962
+ });
6963
+ if (tag.selfClosing) close();
6964
+ index = tag.end;
6965
+ }
6966
+ while (stack.length > 0) close();
6967
+ return root;
6968
+ }
6969
+ /** Past a `<?…?>` or a `<!…>`, minding a doctype's bracketed subset. */
6970
+ function skipDeclaration(source, open) {
6971
+ let depth = 0;
6972
+ for (let i = open + 1; i < source.length; i++) {
6973
+ const char = source[i];
6974
+ if (char === "[") depth++;
6975
+ else if (char === "]") depth--;
6976
+ else if (char === ">" && depth <= 0) return i + 1;
6977
+ }
6978
+ return source.length;
6979
+ }
6980
+ function readTag(source, open) {
6981
+ let i = open + 1;
6982
+ const nameStart = i;
6983
+ while (i < source.length && !/[\s/>]/.test(source[i])) i++;
6984
+ const name = source.slice(nameStart, i);
6985
+ const attributes = {};
6986
+ for (;;) {
6987
+ while (i < source.length && /\s/.test(source[i])) i++;
6988
+ if (i >= source.length) return {
6989
+ name,
6990
+ attributes,
6991
+ selfClosing: false,
6992
+ end: i
6993
+ };
6994
+ if (source[i] === ">") return {
6995
+ name,
6996
+ attributes,
6997
+ selfClosing: false,
6998
+ end: i + 1
6999
+ };
7000
+ if (source[i] === "/") {
7001
+ const end = source.indexOf(">", i);
7002
+ return {
7003
+ name,
7004
+ attributes,
7005
+ selfClosing: true,
7006
+ end: end === -1 ? source.length : end + 1
7007
+ };
7008
+ }
7009
+ const keyStart = i;
7010
+ while (i < source.length && !/[\s=/>]/.test(source[i])) i++;
7011
+ const key = source.slice(keyStart, i);
7012
+ while (i < source.length && /\s/.test(source[i])) i++;
7013
+ if (source[i] !== "=") {
7014
+ if (key !== "") attributes[key] = "";
7015
+ else i++;
7016
+ continue;
7017
+ }
7018
+ i++;
7019
+ while (i < source.length && /\s/.test(source[i])) i++;
7020
+ const quote = source[i];
7021
+ if (quote === "\"" || quote === "'") {
7022
+ const end = source.indexOf(quote, i + 1);
7023
+ attributes[key] = decodeEntities(source.slice(i + 1, end === -1 ? source.length : end));
7024
+ i = end === -1 ? source.length : end + 1;
7025
+ } else {
7026
+ const valueStart = i;
7027
+ while (i < source.length && !/[\s>]/.test(source[i])) i++;
7028
+ attributes[key] = decodeEntities(source.slice(valueStart, i));
7029
+ }
7030
+ }
7031
+ }
7032
+ const NAMED_ENTITIES = {
7033
+ amp: "&",
7034
+ lt: "<",
7035
+ gt: ">",
7036
+ quot: "\"",
7037
+ apos: "'"
7038
+ };
7039
+ function decodeEntities(text) {
7040
+ if (!text.includes("&")) return text;
7041
+ return text.replace(/&(#x[0-9a-f]+|#\d+|[a-z]+);/gi, (whole, entity) => {
7042
+ if (entity[0] === "#") {
7043
+ const code = entity[1] === "x" || entity[1] === "X" ? parseInt(entity.slice(2), 16) : parseInt(entity.slice(1), 10);
7044
+ return Number.isFinite(code) ? String.fromCodePoint(code) : whole;
7045
+ }
7046
+ return NAMED_ENTITIES[entity] ?? whole;
7047
+ });
7048
+ }
7049
+ //#endregion
7050
+ //#region src/rendering/svg/SvgDocument.ts
7051
+ /** Elements drawn as nothing, because nothing here draws them yet. */
7052
+ const UNSUPPORTED_ELEMENTS = /* @__PURE__ */ new Set([
7053
+ "text",
7054
+ "image",
7055
+ "foreignObject",
7056
+ "mask",
7057
+ "filter",
7058
+ "pattern",
7059
+ "marker"
7060
+ ]);
7061
+ /** Attributes that point at one of those. */
7062
+ const UNSUPPORTED_ATTRIBUTES = {
7063
+ mask: "mask",
7064
+ filter: "filter",
7065
+ "marker-start": "marker",
7066
+ "marker-mid": "marker",
7067
+ "marker-end": "marker"
7068
+ };
7069
+ /**
7070
+ * Reads an SVG file. Throws when it holds no `<svg>` element, since
7071
+ * there is then nothing to draw and the caller should fall back.
7072
+ */
7073
+ function parseSvg(source) {
7074
+ const root = parseSvgXml(source);
7075
+ if (root === null || localName(root.name) !== "svg") throw new Error("This is not an SVG file: it has no <svg> element.");
7076
+ const ids = /* @__PURE__ */ new Map();
7077
+ const rules = [];
7078
+ const unsupported = /* @__PURE__ */ new Set();
7079
+ const visit = (element) => {
7080
+ const name = localName(element.name);
7081
+ const id = element.attributes.id;
7082
+ if (id !== void 0 && !ids.has(id)) ids.set(id, element);
7083
+ if (name === "style") rules.push(...parseStyleSheet(element.text));
7084
+ if (UNSUPPORTED_ELEMENTS.has(name)) unsupported.add(name);
7085
+ for (const [attribute, feature] of Object.entries(UNSUPPORTED_ATTRIBUTES)) if (element.attributes[attribute] !== void 0 && element.attributes[attribute] !== "none") unsupported.add(feature);
7086
+ element.children.forEach(visit);
7087
+ };
7088
+ visit(root);
7089
+ const viewBox = parseViewBox(root.attributes.viewBox);
7090
+ const width = absoluteLength(root.attributes.width) ?? viewBox?.width ?? 300;
7091
+ const height = absoluteLength(root.attributes.height) ?? viewBox?.height ?? 150;
7092
+ return {
7093
+ root,
7094
+ width,
7095
+ height,
7096
+ viewBox: viewBox ?? {
7097
+ x: 0,
7098
+ y: 0,
7099
+ width,
7100
+ height
7101
+ },
7102
+ ids,
7103
+ rules,
7104
+ unsupported: [...unsupported]
7105
+ };
7106
+ }
7107
+ /** An element's name without its namespace prefix: `svg:path` is `path`. */
7108
+ function localName(name) {
7109
+ const colon = name.indexOf(":");
7110
+ return colon === -1 ? name : name.slice(colon + 1);
7111
+ }
7112
+ /** A `viewBox`, or undefined when it is absent or describes nothing. */
7113
+ function parseViewBox(value) {
7114
+ if (value === void 0) return;
7115
+ const [x, y, width, height] = numbersIn(value);
7116
+ if (x === void 0 || y === void 0 || width === void 0 || height === void 0 || width <= 0 || height <= 0) return;
7117
+ return {
7118
+ x,
7119
+ y,
7120
+ width,
7121
+ height
7122
+ };
7123
+ }
7124
+ /** Every number in a list separated by commas and spaces. */
7125
+ function numbersIn(value) {
7126
+ return (value.match(/[-+]?(?:\d+\.?\d*|\.\d+)(?:e[-+]?\d+)?/gi) ?? []).map(Number);
7127
+ }
7128
+ /** A length in pixels, or undefined for a percentage or anything that is not one. */
7129
+ function absoluteLength(value) {
7130
+ if (value === void 0 || value.trim().endsWith("%")) return;
7131
+ const number = parseFloat(value);
7132
+ if (!Number.isFinite(number) || number <= 0) return;
7133
+ const unit = value.trim().replace(/^[-+\d.e]+/i, "");
7134
+ return number * (UNIT_PIXELS[unit] ?? 1);
7135
+ }
7136
+ /** CSS's absolute units in pixels, 96 to the inch. */
7137
+ const UNIT_PIXELS = {
7138
+ "": 1,
7139
+ px: 1,
7140
+ pt: 96 / 72,
7141
+ pc: 16,
7142
+ in: 96,
7143
+ cm: 96 / 2.54,
7144
+ mm: 96 / 25.4
7145
+ };
7146
+ /** The declarations of an inline `style` attribute or a rule's block. */
7147
+ function parseDeclarations(text) {
7148
+ const declarations = {};
7149
+ for (const part of text.split(";")) {
7150
+ const colon = part.indexOf(":");
7151
+ if (colon === -1) continue;
7152
+ const property = part.slice(0, colon).trim().toLowerCase();
7153
+ const value = part.slice(colon + 1).replace(/!important/i, "").trim();
7154
+ if (property !== "" && value !== "") declarations[property] = value;
7155
+ }
7156
+ return declarations;
7157
+ }
7158
+ /**
7159
+ * A `<style>`'s rules. Only compound selectors are understood, which is
7160
+ * what an exporter writes (`.st0{fill:#fff}`); a rule whose selector
7161
+ * has a combinator or a pseudo-class is skipped rather than misapplied.
7162
+ */
7163
+ function parseStyleSheet(text) {
7164
+ const rules = [];
7165
+ const source = text.replace(/\/\*[\s\S]*?\*\//g, "");
7166
+ for (const match of source.matchAll(/([^{}]+)\{([^}]*)\}/g)) {
7167
+ const declarations = parseDeclarations(match[2]);
7168
+ for (const raw of match[1].split(",")) {
7169
+ const selector = parseSelector(raw.trim());
7170
+ if (selector !== null) {
7171
+ const specificity = (selector.id === void 0 ? 0 : 100) + selector.classes.length * 10 + (selector.name === void 0 ? 0 : 1);
7172
+ rules.push({
7173
+ selector,
7174
+ declarations,
7175
+ specificity
7176
+ });
7177
+ }
7178
+ }
7179
+ }
7180
+ return rules;
7181
+ }
7182
+ function parseSelector(text) {
7183
+ if (text === "" || /[\s>+~:[\]*]/.test(text)) return null;
7184
+ const parts = text.match(/[.#]?[^.#]+/g) ?? [];
7185
+ let name;
7186
+ let id;
7187
+ const classes = [];
7188
+ for (const part of parts) if (part.startsWith("#")) id = part.slice(1);
7189
+ else if (part.startsWith(".")) classes.push(part.slice(1));
7190
+ else name = part;
7191
+ return {
7192
+ ...name === void 0 ? {} : { name },
7193
+ ...id === void 0 ? {} : { id },
7194
+ classes
7195
+ };
7196
+ }
7197
+ /** Whether a rule's selector matches an element. */
7198
+ function selectorMatches(selector, element) {
7199
+ if (selector.name !== void 0 && localName(element.name) !== selector.name) return false;
7200
+ if (selector.id !== void 0 && element.attributes.id !== selector.id) return false;
7201
+ if (selector.classes.length > 0) {
7202
+ const classes = (element.attributes.class ?? "").split(/\s+/);
7203
+ return selector.classes.every((name) => classes.includes(name));
7204
+ }
7205
+ return true;
7206
+ }
7207
+ //#endregion
7208
+ //#region src/rendering/svg/SvgDraw.ts
7209
+ /**
7210
+ * Draws a read SVG file into a box, through the surface every painted
7211
+ * node draws through, so it is vectors on either renderer and is drawn
7212
+ * again at whatever size the box is laid out at.
7213
+ */
7214
+ function drawSvg(document, surface, box, options = {}) {
7215
+ const { viewBox } = document;
7216
+ const fit = options.fit ?? "contain";
7217
+ let scaleX = box.width / viewBox.width;
7218
+ let scaleY = box.height / viewBox.height;
7219
+ if (fit !== "fill") {
7220
+ const contain = Math.min(scaleX, scaleY);
7221
+ const natural = document.width / viewBox.width;
7222
+ const uniform = fit === "cover" ? Math.max(scaleX, scaleY) : fit === "none" ? natural : fit === "scale-down" ? Math.min(contain, natural) : contain;
7223
+ scaleX = uniform;
7224
+ scaleY = uniform;
7225
+ }
7226
+ surface.save();
7227
+ if (fit === "cover" || fit === "none") {
7228
+ surface.beginPath();
7229
+ surface.rect(0, 0, box.width, box.height);
7230
+ surface.clip();
7231
+ }
7232
+ surface.translate((box.width - viewBox.width * scaleX) / 2, (box.height - viewBox.height * scaleY) / 2);
7233
+ surface.scale(scaleX, scaleY);
7234
+ surface.translate(-viewBox.x, -viewBox.y);
7235
+ const context = {
7236
+ document,
7237
+ surface,
7238
+ currentColor: options.color ?? "currentColor",
7239
+ using: /* @__PURE__ */ new Set()
7240
+ };
7241
+ drawChildren(document.root, cascade(INITIAL_STYLE, declarationsOf(document.root, document), context), viewBox, context);
7242
+ surface.restore();
7243
+ }
7244
+ const paints = /* @__PURE__ */ new WeakMap();
7245
+ /**
7246
+ * A read SVG file as a node's `paint`: drawn to fill the node, and the
7247
+ * file's own size as the node's when the layout gives it none.
7248
+ *
7249
+ * The same object for the same file and options, so a node given it
7250
+ * again is not drawn again; see `paintValuesEqual`.
7251
+ */
7252
+ function svgPaint(document, options = {}) {
7253
+ let byOptions = paints.get(document);
7254
+ if (byOptions === void 0) {
7255
+ byOptions = /* @__PURE__ */ new Map();
7256
+ paints.set(document, byOptions);
7257
+ }
7258
+ const key = JSON.stringify([options.fit ?? "contain", options.color ?? "currentColor"]);
7259
+ let paint = byOptions.get(key);
7260
+ if (paint === void 0) {
7261
+ paint = {
7262
+ draw: (surface, box) => drawSvg(document, surface, box, options),
7263
+ inputs: [document, key],
7264
+ intrinsicWidth: document.width,
7265
+ intrinsicHeight: document.height
7266
+ };
7267
+ byOptions.set(key, paint);
7268
+ }
7269
+ return paint;
7270
+ }
7271
+ const BLACK = {
7272
+ kind: "color",
7273
+ color: {
7274
+ r: 0,
7275
+ g: 0,
7276
+ b: 0,
7277
+ a: 1
7278
+ }
7279
+ };
7280
+ const NONE = { kind: "none" };
7281
+ const INITIAL_STYLE = {
7282
+ fill: BLACK,
7283
+ fillOpacity: 1,
7284
+ fillRule: "nonzero",
7285
+ stroke: NONE,
7286
+ strokeOpacity: 1,
7287
+ strokeWidth: 1,
7288
+ lineCap: "butt",
7289
+ lineJoin: "miter",
7290
+ miterLimit: 4,
7291
+ dash: [],
7292
+ dashOffset: 0,
7293
+ clipRule: "nonzero",
7294
+ color: null,
7295
+ visible: true
7296
+ };
7297
+ /** Drawn only when something points at them, or not at all. */
7298
+ const NOT_DRAWN = /* @__PURE__ */ new Set([
7299
+ "defs",
7300
+ "clipPath",
7301
+ "linearGradient",
7302
+ "radialGradient",
7303
+ "symbol",
7304
+ "style",
7305
+ "title",
7306
+ "desc",
7307
+ "metadata",
7308
+ "mask",
7309
+ "filter",
7310
+ "pattern",
7311
+ "marker",
7312
+ "text",
7313
+ "image",
7314
+ "foreignObject"
7315
+ ]);
7316
+ function drawChildren(element, style, viewport, context) {
7317
+ for (const child of element.children) drawElement(child, style, viewport, context);
7318
+ }
7319
+ function drawElement(element, inherited, viewport, context) {
7320
+ const name = localName(element.name);
7321
+ if (NOT_DRAWN.has(name)) return;
7322
+ const declared = declarationsOf(element, context.document);
7323
+ if (declared.display === "none") return;
7324
+ const style = cascade(inherited, declared, context);
7325
+ const { surface } = context;
7326
+ surface.save();
7327
+ if (declared.transform !== void 0) applyTransform$1(surface, declared.transform);
7328
+ const opacity = unit(declared.opacity);
7329
+ if (opacity < 1) surface.alpha(opacity);
7330
+ if (declared["clip-path"] !== void 0) clipTo(declared["clip-path"], viewport, context);
7331
+ switch (name) {
7332
+ case "g":
7333
+ case "a":
7334
+ case "switch":
7335
+ drawChildren(element, style, viewport, context);
7336
+ break;
7337
+ case "svg":
7338
+ drawNested(element, style, viewport, context);
7339
+ break;
7340
+ case "use":
7341
+ drawUse(element, style, viewport, context);
7342
+ break;
7343
+ default: {
7344
+ const shape = shapeOf(element, name, viewport);
7345
+ if (shape !== null && style.visible) paintShape(shape, style, viewport, context);
7346
+ }
7347
+ }
7348
+ surface.restore();
7349
+ }
7350
+ /** A nested `<svg>`: a viewport of its own, at its x and y. */
7351
+ function drawNested(element, style, viewport, context) {
7352
+ const { surface } = context;
7353
+ const x = length(element.attributes.x, viewport.width);
7354
+ const y = length(element.attributes.y, viewport.height);
7355
+ const width = length(element.attributes.width ?? "100%", viewport.width);
7356
+ const height = length(element.attributes.height ?? "100%", viewport.height);
7357
+ const viewBox = parseViewBox(element.attributes.viewBox);
7358
+ surface.translate(x, y);
7359
+ if (viewBox !== void 0) {
7360
+ const scale = Math.min(width / viewBox.width, height / viewBox.height);
7361
+ surface.translate((width - viewBox.width * scale) / 2, (height - viewBox.height * scale) / 2);
7362
+ surface.scale(scale, scale);
7363
+ surface.translate(-viewBox.x, -viewBox.y);
7364
+ }
7365
+ drawChildren(element, style, viewBox ?? {
7366
+ x: 0,
7367
+ y: 0,
7368
+ width,
7369
+ height
7370
+ }, context);
7371
+ }
7372
+ /** A `<use>`: the element it names, drawn at its x and y, inheriting from the `<use>`. */
7373
+ function drawUse(element, style, viewport, context) {
7374
+ const target = referenced(element, context.document);
7375
+ if (target === void 0 || context.using.has(element)) return;
7376
+ const { surface } = context;
7377
+ surface.translate(length(element.attributes.x, viewport.width), length(element.attributes.y, viewport.height));
7378
+ context.using.add(element);
7379
+ if (localName(target.name) === "symbol") drawNested(target, style, viewport, context);
7380
+ else {
7381
+ const name = localName(target.name);
7382
+ if (name === "g" || name === "svg" || name === "use" || !NOT_DRAWN.has(name)) drawElement(target, style, viewport, context);
7383
+ }
7384
+ context.using.delete(element);
7385
+ }
7386
+ function referenced(element, document) {
7387
+ const href = element.attributes.href ?? element.attributes["xlink:href"];
7388
+ return href?.startsWith("#") ? document.ids.get(href.slice(1)) : void 0;
7389
+ }
7390
+ function shapeOf(element, name, viewport) {
7391
+ const a = element.attributes;
7392
+ const w = viewport.width;
7393
+ const h = viewport.height;
7394
+ const diagonal = Math.sqrt((w * w + h * h) / 2);
7395
+ switch (name) {
7396
+ case "path": {
7397
+ const d = a.d;
7398
+ return d === void 0 || d.trim() === "" ? null : { trace: (surface) => surface.path(d) };
7399
+ }
7400
+ case "rect": {
7401
+ const x = length(a.x, w);
7402
+ const y = length(a.y, h);
7403
+ const width = length(a.width, w);
7404
+ const height = length(a.height, h);
7405
+ if (width <= 0 || height <= 0) return null;
7406
+ const rx = a.rx === void 0 ? void 0 : length(a.rx, w);
7407
+ const ry = a.ry === void 0 ? void 0 : length(a.ry, h);
7408
+ const radius = Math.min(rx ?? ry ?? 0, ry ?? rx ?? 0);
7409
+ return { trace: (surface) => radius > 0 ? surface.roundRect(x, y, width, height, radius) : surface.rect(x, y, width, height) };
7410
+ }
7411
+ case "circle": return ellipse(length(a.cx, w), length(a.cy, h), length(a.r, diagonal), length(a.r, diagonal));
7412
+ case "ellipse": return ellipse(length(a.cx, w), length(a.cy, h), length(a.rx, w), length(a.ry, h));
7413
+ case "line": {
7414
+ const [x1, y1, x2, y2] = [
7415
+ length(a.x1, w),
7416
+ length(a.y1, h),
7417
+ length(a.x2, w),
7418
+ length(a.y2, h)
7419
+ ];
7420
+ return { trace: (surface) => {
7421
+ surface.moveTo(x1, y1);
7422
+ surface.lineTo(x2, y2);
7423
+ } };
7424
+ }
7425
+ case "polyline":
7426
+ case "polygon": {
7427
+ const points = numbersIn(a.points ?? "");
7428
+ if (points.length < 4) return null;
7429
+ return { trace: (surface) => {
7430
+ surface.moveTo(points[0], points[1]);
7431
+ for (let i = 2; i + 1 < points.length; i += 2) surface.lineTo(points[i], points[i + 1]);
7432
+ if (name === "polygon") surface.closePath();
7433
+ } };
7434
+ }
7435
+ default: return null;
7436
+ }
7437
+ }
7438
+ /** An ellipse as two arcs of path data, which the surface turns into curves. */
7439
+ function ellipse(cx, cy, rx, ry) {
7440
+ if (rx <= 0 || ry <= 0) return null;
7441
+ const d = `M${cx - rx} ${cy}A${rx} ${ry} 0 1 0 ${cx + rx} ${cy}A${rx} ${ry} 0 1 0 ${cx - rx} ${cy}Z`;
7442
+ return { trace: (surface) => surface.path(d) };
7443
+ }
7444
+ function paintShape(shape, style, viewport, context) {
7445
+ const { surface } = context;
7446
+ surface.beginPath();
7447
+ shape.trace(surface);
7448
+ if (style.fill.kind !== "none" && style.fillOpacity > 0) {
7449
+ surface.save();
7450
+ if (style.fillOpacity < 1) surface.alpha(style.fillOpacity);
7451
+ if (setPaint(style.fill, "fill", shape, style, viewport, context)) surface.fill(style.fillRule);
7452
+ surface.restore();
7453
+ }
7454
+ if (style.stroke.kind !== "none" && style.strokeOpacity > 0 && style.strokeWidth > 0) {
7455
+ surface.save();
7456
+ if (style.strokeOpacity < 1) surface.alpha(style.strokeOpacity);
7457
+ if (setPaint(style.stroke, "stroke", shape, style, viewport, context)) {
7458
+ surface.lineWidth(style.strokeWidth);
7459
+ surface.lineCap(style.lineCap);
7460
+ surface.lineJoin(style.lineJoin);
7461
+ surface.miterLimit(style.miterLimit);
7462
+ if (style.dash.length > 0) surface.lineDash(style.dash, style.dashOffset);
7463
+ surface.stroke();
7464
+ }
7465
+ surface.restore();
7466
+ }
7467
+ }
7468
+ /**
7469
+ * Sets a fill or a stroke on the surface. False when there is nothing
7470
+ * to draw with: a gradient with no stops, or a reference to nothing and
7471
+ * no fallback.
7472
+ *
7473
+ * A gradient stroke is drawn in its last stop's colour, because the
7474
+ * surface strokes only in a colour.
7475
+ */
7476
+ function setPaint(paint, role, shape, style, viewport, context) {
7477
+ if (paint.kind === "none") return false;
7478
+ if (paint.kind === "color") {
7479
+ if (role === "fill") context.surface.fillColor(paint.color);
7480
+ else context.surface.strokeColor(paint.color);
7481
+ return true;
7482
+ }
7483
+ const target = context.document.ids.get(paint.id);
7484
+ const gradient = target === void 0 ? void 0 : gradientOf(target, shape, style, viewport, context);
7485
+ if (gradient === void 0) return setPaint(paint.fallback, role, shape, style, viewport, context);
7486
+ if (gradient.stops.length === 0) return false;
7487
+ if (role === "stroke" || gradient.stops.length === 1) {
7488
+ const color = gradient.stops.at(-1).color;
7489
+ if (role === "fill") context.surface.fillColor(color);
7490
+ else context.surface.strokeColor(color);
7491
+ return true;
7492
+ }
7493
+ context.surface.fillGradient(gradient.paint, gradient.rect.x, gradient.rect.y, gradient.rect.width, gradient.rect.height);
7494
+ return true;
7495
+ }
7496
+ /**
7497
+ * An SVG gradient as Gesso's, and the rectangle to place it in.
7498
+ *
7499
+ * SVG gives a linear gradient as the two ends of its line and Gesso as
7500
+ * an angle across a rectangle, CSS's way, so the rectangle is chosen to
7501
+ * make the two agree: a square about the line's midpoint whose
7502
+ * gradient line, at that angle, is exactly as long as the SVG's. A
7503
+ * radial one is its centre and radius in pixels, placed at the origin.
7504
+ */
7505
+ function gradientOf(element, shape, style, viewport, context) {
7506
+ const name = localName(element.name);
7507
+ if (name !== "linearGradient" && name !== "radialGradient") return;
7508
+ const attributes = gradientAttributes(element, context.document);
7509
+ const stops = gradientStops(element, style, context);
7510
+ const userSpace = attributes.gradientUnits === "userSpaceOnUse";
7511
+ const box = userSpace ? viewport : boundsOf(shape);
7512
+ const matrix = attributes.gradientTransform === void 0 ? IDENTITY$1 : parseTransform$1(attributes.gradientTransform);
7513
+ /** A point in the gradient's units, in the drawing's. */
7514
+ const place = (x, y, fallbackX, fallbackY) => {
7515
+ const u = gradientLength(x ?? fallbackX, userSpace, viewport.width);
7516
+ const v = gradientLength(y ?? fallbackY, userSpace, viewport.height);
7517
+ const [tx, ty] = apply(matrix, u, v);
7518
+ return userSpace ? [tx, ty] : [box.x + tx * box.width, box.y + ty * box.height];
7519
+ };
7520
+ if (name === "linearGradient") {
7521
+ const [x1, y1] = place(attributes.x1, attributes.y1, "0%", "0%");
7522
+ const [x2, y2] = place(attributes.x2, attributes.y2, "100%", "0%");
7523
+ const dx = x2 - x1;
7524
+ const dy = y2 - y1;
7525
+ const span = Math.hypot(dx, dy);
7526
+ if (span === 0) return {
7527
+ paint: {
7528
+ kind: "linear",
7529
+ angle: 0,
7530
+ stops: stops.slice(-1)
7531
+ },
7532
+ stops: stops.slice(-1),
7533
+ rect: box
7534
+ };
7535
+ const angle = Math.atan2(dx, -dy);
7536
+ const side = span / (Math.abs(Math.sin(angle)) + Math.abs(Math.cos(angle)));
7537
+ return {
7538
+ paint: {
7539
+ kind: "linear",
7540
+ angle,
7541
+ stops
7542
+ },
7543
+ stops,
7544
+ rect: {
7545
+ x: (x1 + x2) / 2 - side / 2,
7546
+ y: (y1 + y2) / 2 - side / 2,
7547
+ width: side,
7548
+ height: side
7549
+ }
7550
+ };
7551
+ }
7552
+ const [cx, cy] = place(attributes.cx, attributes.cy, "50%", "50%");
7553
+ const radius = gradientLength(attributes.r ?? "50%", userSpace, Math.sqrt((viewport.width ** 2 + viewport.height ** 2) / 2)) * Math.sqrt(Math.abs(matrix[0] * matrix[3] - matrix[1] * matrix[2])) * (userSpace ? 1 : (box.width + box.height) / 2);
7554
+ if (radius <= 0) return {
7555
+ paint: {
7556
+ kind: "radial",
7557
+ stops: stops.slice(-1)
7558
+ },
7559
+ stops: stops.slice(-1),
7560
+ rect: box
7561
+ };
7562
+ return {
7563
+ paint: {
7564
+ kind: "radial",
7565
+ centerX: cx,
7566
+ centerY: cy,
7567
+ radius,
7568
+ stops
7569
+ },
7570
+ stops,
7571
+ rect: {
7572
+ x: 0,
7573
+ y: 0,
7574
+ width: 1,
7575
+ height: 1
7576
+ }
7577
+ };
7578
+ }
7579
+ /** A gradient's attributes, with the ones it inherits through `href` from the gradient it names. */
7580
+ function gradientAttributes(element, document) {
7581
+ const chain = [];
7582
+ for (let at = element; at !== void 0 && !chain.includes(at); at = referenced(at, document)) chain.push(at);
7583
+ return Object.assign({}, ...chain.reverse().map((link) => link.attributes));
7584
+ }
7585
+ /** Its stops, or those of the gradient it names when it has none. */
7586
+ function gradientStops(element, style, context) {
7587
+ const seen = [];
7588
+ let at = element;
7589
+ while (at !== void 0 && !seen.includes(at)) {
7590
+ seen.push(at);
7591
+ const stops = at.children.filter((child) => localName(child.name) === "stop");
7592
+ if (stops.length > 0) {
7593
+ let last = 0;
7594
+ return stops.map((stop) => {
7595
+ const declared = declarationsOf(stop, context.document);
7596
+ const raw = declared.offset ?? "0";
7597
+ const offset = Math.max(last, Math.min(1, raw.trim().endsWith("%") ? parseFloat(raw) / 100 : parseFloat(raw) || 0));
7598
+ last = offset;
7599
+ const color = colorValue(declared["stop-color"] ?? "black", style, context) ?? BLACK_COLOR;
7600
+ return {
7601
+ offset: percent(offset * 100),
7602
+ color: withOpacity(color, unit(declared["stop-opacity"]))
7603
+ };
7604
+ });
7605
+ }
7606
+ at = referenced(at, context.document);
7607
+ }
7608
+ return [];
7609
+ }
7610
+ const BLACK_COLOR = {
7611
+ r: 0,
7612
+ g: 0,
7613
+ b: 0,
7614
+ a: 1
7615
+ };
7616
+ function withOpacity(color, opacity) {
7617
+ if (opacity >= 1 || typeof color === "string") return color;
7618
+ return {
7619
+ ...color,
7620
+ a: color.a * opacity
7621
+ };
7622
+ }
7623
+ /** A gradient coordinate: a fraction of the box, or pixels in user space. */
7624
+ function gradientLength(value, userSpace, extent) {
7625
+ const trimmed = value.trim();
7626
+ if (trimmed.endsWith("%")) {
7627
+ const fraction = parseFloat(trimmed) / 100;
7628
+ return userSpace ? fraction * extent : fraction;
7629
+ }
7630
+ return parseFloat(trimmed) || 0;
7631
+ }
7632
+ /** The box a shape's outline and control points lie in, for a gradient sized to it. */
7633
+ function boundsOf(shape) {
7634
+ const bounds = new BoundsSurface();
7635
+ shape.trace(bounds);
7636
+ return bounds.bounds();
7637
+ }
7638
+ /** A surface that only notes where a path goes. */
7639
+ var BoundsSurface = class {
7640
+ minX = Infinity;
7641
+ minY = Infinity;
7642
+ maxX = -Infinity;
7643
+ maxY = -Infinity;
7644
+ note(x, y) {
7645
+ this.minX = Math.min(this.minX, x);
7646
+ this.minY = Math.min(this.minY, y);
7647
+ this.maxX = Math.max(this.maxX, x);
7648
+ this.maxY = Math.max(this.maxY, y);
7649
+ }
7650
+ bounds() {
7651
+ if (this.minX > this.maxX) return {
7652
+ x: 0,
7653
+ y: 0,
7654
+ width: 0,
7655
+ height: 0
7656
+ };
7657
+ return {
7658
+ x: this.minX,
7659
+ y: this.minY,
7660
+ width: this.maxX - this.minX,
7661
+ height: this.maxY - this.minY
7662
+ };
7663
+ }
7664
+ moveTo(x, y) {
7665
+ this.note(x, y);
7666
+ }
7667
+ lineTo(x, y) {
7668
+ this.note(x, y);
7669
+ }
7670
+ quadraticCurveTo(cx, cy, x, y) {
7671
+ this.note(cx, cy);
7672
+ this.note(x, y);
7673
+ }
7674
+ bezierCurveTo(c1x, c1y, c2x, c2y, x, y) {
7675
+ this.note(c1x, c1y);
7676
+ this.note(c2x, c2y);
7677
+ this.note(x, y);
7678
+ }
7679
+ arc(x, y, radius) {
7680
+ this.note(x - radius, y - radius);
7681
+ this.note(x + radius, y + radius);
7682
+ }
7683
+ rect(x, y, width, height) {
7684
+ this.note(x, y);
7685
+ this.note(x + width, y + height);
7686
+ }
7687
+ roundRect(x, y, width, height) {
7688
+ this.rect(x, y, width, height);
7689
+ }
7690
+ closePath() {}
7691
+ path(d) {
7692
+ tracePathData(this, d);
7693
+ }
7694
+ };
7695
+ /** Intersects the clip with a `<clipPath>`'s shapes, in the drawing's own coordinates. */
7696
+ function clipTo(value, viewport, context) {
7697
+ const id = /url\(\s*['"]?#([^'")]+)['"]?\s*\)/.exec(value)?.[1];
7698
+ const clip = id === void 0 ? void 0 : context.document.ids.get(id);
7699
+ if (clip === void 0 || localName(clip.name) !== "clipPath") return;
7700
+ const { surface } = context;
7701
+ surface.beginPath();
7702
+ let rule = "nonzero";
7703
+ const add = (element) => {
7704
+ const name = localName(element.name);
7705
+ const declared = declarationsOf(element, context.document);
7706
+ if (name === "use") {
7707
+ const target = referenced(element, context.document);
7708
+ if (target !== void 0 && localName(target.name) !== "use") add(target);
7709
+ return;
7710
+ }
7711
+ if (name === "g") {
7712
+ element.children.forEach(add);
7713
+ return;
7714
+ }
7715
+ const shape = shapeOf(element, name, viewport);
7716
+ if (shape === null) return;
7717
+ if (declared["clip-rule"] === "evenodd") rule = "evenodd";
7718
+ if (declared.transform !== void 0) {
7719
+ const matrix = parseTransform$1(declared.transform);
7720
+ shape.trace(new TransformedSurface(surface, matrix));
7721
+ } else shape.trace(surface);
7722
+ };
7723
+ clip.children.forEach(add);
7724
+ surface.clip(rule);
7725
+ }
7726
+ /** Forwards path calls with every point through a matrix. */
7727
+ var TransformedSurface = class {
7728
+ target;
7729
+ matrix;
7730
+ constructor(target, matrix) {
7731
+ this.target = target;
7732
+ this.matrix = matrix;
7733
+ }
7734
+ at(x, y) {
7735
+ return apply(this.matrix, x, y);
7736
+ }
7737
+ moveTo(x, y) {
7738
+ this.target.moveTo(...this.at(x, y));
7739
+ }
7740
+ lineTo(x, y) {
7741
+ this.target.lineTo(...this.at(x, y));
7742
+ }
7743
+ quadraticCurveTo(cx, cy, x, y) {
7744
+ this.target.quadraticCurveTo(...this.at(cx, cy), ...this.at(x, y));
7745
+ }
7746
+ bezierCurveTo(c1x, c1y, c2x, c2y, x, y) {
7747
+ this.target.bezierCurveTo(...this.at(c1x, c1y), ...this.at(c2x, c2y), ...this.at(x, y));
7748
+ }
7749
+ rect(x, y, width, height) {
7750
+ this.moveTo(x, y);
7751
+ this.lineTo(x + width, y);
7752
+ this.lineTo(x + width, y + height);
7753
+ this.lineTo(x, y + height);
7754
+ this.closePath();
7755
+ }
7756
+ roundRect(x, y, width, height) {
7757
+ this.rect(x, y, width, height);
7758
+ }
7759
+ closePath() {
7760
+ this.target.closePath();
7761
+ }
7762
+ path(d) {
7763
+ tracePathData(this, d);
7764
+ }
7765
+ };
7766
+ /**
7767
+ * What an element declares, in the cascade's order: its presentation
7768
+ * attributes, then the `<style>` rules that match it by specificity,
7769
+ * then its own `style` attribute.
7770
+ */
7771
+ function declarationsOf(element, document) {
7772
+ const declared = { ...element.attributes };
7773
+ if (document.rules.length > 0) {
7774
+ const matching = document.rules.map((rule, order) => ({
7775
+ rule,
7776
+ order
7777
+ })).filter(({ rule }) => selectorMatches(rule.selector, element)).sort((a, b) => a.rule.specificity - b.rule.specificity || a.order - b.order);
7778
+ for (const { rule } of matching) Object.assign(declared, rule.declarations);
7779
+ }
7780
+ if (element.attributes.style !== void 0) Object.assign(declared, parseDeclarations(element.attributes.style));
7781
+ return declared;
7782
+ }
7783
+ /** The inherited style at an element, from its parent's and what it declares. */
7784
+ function cascade(parent, declared, context) {
7785
+ const color = declared.color === void 0 || declared.color === "inherit" ? parent.color : colorValue(declared.color, parent, context) ?? parent.color;
7786
+ const here = {
7787
+ ...parent,
7788
+ color
7789
+ };
7790
+ const pick = (key, property, read) => {
7791
+ const value = declared[property];
7792
+ return value === void 0 || value === "inherit" ? here[key] : read(value) ?? here[key];
7793
+ };
7794
+ const number = (value) => {
7795
+ const parsed = parseFloat(value);
7796
+ return Number.isFinite(parsed) ? parsed : void 0;
7797
+ };
7798
+ return {
7799
+ ...here,
7800
+ fill: pick("fill", "fill", (value) => paintValue(value, here, context)),
7801
+ fillOpacity: pick("fillOpacity", "fill-opacity", (value) => unit(value)),
7802
+ fillRule: pick("fillRule", "fill-rule", (value) => value === "evenodd" ? "evenodd" : "nonzero"),
7803
+ stroke: pick("stroke", "stroke", (value) => paintValue(value, here, context)),
7804
+ strokeOpacity: pick("strokeOpacity", "stroke-opacity", (value) => unit(value)),
7805
+ strokeWidth: pick("strokeWidth", "stroke-width", number),
7806
+ lineCap: pick("lineCap", "stroke-linecap", (value) => value === "round" || value === "square" || value === "butt" ? value : void 0),
7807
+ lineJoin: pick("lineJoin", "stroke-linejoin", (value) => value === "round" || value === "bevel" || value === "miter" ? value : value === "arcs" || value === "miter-clip" ? "miter" : void 0),
7808
+ miterLimit: pick("miterLimit", "stroke-miterlimit", number),
7809
+ dash: pick("dash", "stroke-dasharray", (value) => {
7810
+ if (value === "none") return [];
7811
+ const segments = numbersIn(value);
7812
+ if (segments.some((segment) => segment < 0) || segments.every((segment) => segment === 0)) return [];
7813
+ return segments.length % 2 === 1 ? [...segments, ...segments] : segments;
7814
+ }),
7815
+ dashOffset: pick("dashOffset", "stroke-dashoffset", number),
7816
+ clipRule: pick("clipRule", "clip-rule", (value) => value === "evenodd" ? "evenodd" : "nonzero"),
7817
+ visible: pick("visible", "visibility", (value) => value === "visible" || value === "inherit" ? true : value === "hidden" || value === "collapse" ? false : void 0)
7818
+ };
7819
+ }
7820
+ function paintValue(value, style, context) {
7821
+ const trimmed = value.trim();
7822
+ if (trimmed === "none" || trimmed === "transparent") return NONE;
7823
+ const reference = /^url\(\s*['"]?#([^'")]+)['"]?\s*\)\s*(.*)$/.exec(trimmed);
7824
+ if (reference !== null) {
7825
+ const fallback = reference[2] === "" || reference[2] === void 0 ? NONE : paintValue(reference[2], style, context) ?? NONE;
7826
+ return {
7827
+ kind: "ref",
7828
+ id: reference[1],
7829
+ fallback
7830
+ };
7831
+ }
7832
+ const color = colorValue(trimmed, style, context);
7833
+ return color === void 0 ? void 0 : {
7834
+ kind: "color",
7835
+ color
7836
+ };
7837
+ }
7838
+ /** A colour, with `currentColor` resolved to whatever it is here. */
7839
+ function colorValue(value, style, context) {
7840
+ const trimmed = value.trim();
7841
+ if (trimmed.toLowerCase() === "currentcolor") return style.color ?? context.currentColor;
7842
+ return parseColor(trimmed);
7843
+ }
7844
+ /** An opacity: a number or a percentage, clamped to 0..1, and 1 when absent. */
7845
+ function unit(value) {
7846
+ if (value === void 0) return 1;
7847
+ const trimmed = value.trim();
7848
+ const parsed = trimmed.endsWith("%") ? parseFloat(trimmed) / 100 : parseFloat(trimmed);
7849
+ return Number.isFinite(parsed) ? Math.max(0, Math.min(1, parsed)) : 1;
7850
+ }
7851
+ /** A length in the drawing's units, a percentage being of `extent`. */
7852
+ function length(value, extent) {
7853
+ if (value === void 0) return 0;
7854
+ const trimmed = value.trim();
7855
+ if (trimmed.endsWith("%")) return parseFloat(trimmed) / 100 * extent;
7856
+ const parsed = parseFloat(trimmed);
7857
+ return Number.isFinite(parsed) ? parsed : 0;
7858
+ }
7859
+ const IDENTITY$1 = [
7860
+ 1,
7861
+ 0,
7862
+ 0,
7863
+ 1,
7864
+ 0,
7865
+ 0
7866
+ ];
7867
+ function multiply(m, n) {
7868
+ return [
7869
+ m[0] * n[0] + m[2] * n[1],
7870
+ m[1] * n[0] + m[3] * n[1],
7871
+ m[0] * n[2] + m[2] * n[3],
7872
+ m[1] * n[2] + m[3] * n[3],
7873
+ m[0] * n[4] + m[2] * n[5] + m[4],
7874
+ m[1] * n[4] + m[3] * n[5] + m[5]
7875
+ ];
7876
+ }
7877
+ function apply(m, x, y) {
7878
+ return [m[0] * x + m[2] * y + m[4], m[1] * x + m[3] * y + m[5]];
7879
+ }
7880
+ /** A `transform` list as one matrix, its functions applied left to right as SVG says. */
7881
+ function parseTransform$1(value) {
7882
+ let matrix = IDENTITY$1;
7883
+ for (const match of value.matchAll(/(matrix|translate|scale|rotate|skewX|skewY)\s*\(([^)]*)\)/g)) {
7884
+ const args = numbersIn(match[2]);
7885
+ let step = IDENTITY$1;
7886
+ switch (match[1]) {
7887
+ case "matrix":
7888
+ if (args.length >= 6) step = [
7889
+ args[0],
7890
+ args[1],
7891
+ args[2],
7892
+ args[3],
7893
+ args[4],
7894
+ args[5]
7895
+ ];
7896
+ break;
7897
+ case "translate":
7898
+ step = [
7899
+ 1,
7900
+ 0,
7901
+ 0,
7902
+ 1,
7903
+ args[0] ?? 0,
7904
+ args[1] ?? 0
7905
+ ];
7906
+ break;
7907
+ case "scale":
7908
+ step = [
7909
+ args[0] ?? 1,
7910
+ 0,
7911
+ 0,
7912
+ args[1] ?? args[0] ?? 1,
7913
+ 0,
7914
+ 0
7915
+ ];
7916
+ break;
7917
+ case "rotate": {
7918
+ const angle = (args[0] ?? 0) * Math.PI / 180;
7919
+ const cos = Math.cos(angle);
7920
+ const sin = Math.sin(angle);
7921
+ const [cx, cy] = [args[1] ?? 0, args[2] ?? 0];
7922
+ step = multiply(multiply([
7923
+ 1,
7924
+ 0,
7925
+ 0,
7926
+ 1,
7927
+ cx,
7928
+ cy
7929
+ ], [
7930
+ cos,
7931
+ sin,
7932
+ -sin,
7933
+ cos,
7934
+ 0,
7935
+ 0
7936
+ ]), [
7937
+ 1,
7938
+ 0,
7939
+ 0,
7940
+ 1,
7941
+ -cx,
7942
+ -cy
7943
+ ]);
7944
+ break;
7945
+ }
7946
+ case "skewX":
7947
+ step = [
7948
+ 1,
7949
+ 0,
7950
+ Math.tan((args[0] ?? 0) * Math.PI / 180),
7951
+ 1,
7952
+ 0,
7953
+ 0
7954
+ ];
7955
+ break;
7956
+ case "skewY": step = [
7957
+ 1,
7958
+ Math.tan((args[0] ?? 0) * Math.PI / 180),
7959
+ 0,
7960
+ 1,
7961
+ 0,
7962
+ 0
7963
+ ];
7964
+ }
7965
+ matrix = multiply(matrix, step);
7966
+ }
7967
+ return matrix;
7968
+ }
7969
+ function applyTransform$1(surface, value) {
7970
+ const [a, b, c, d, e, f] = parseTransform$1(value);
7971
+ surface.transform(a, b, c, d, e, f);
7972
+ }
7973
+ //#endregion
7974
+ //#region src/rendering/svg/SvgResolver.ts
7975
+ /**
7976
+ * Whether a source is an SVG file, from its name or its data URL's
7977
+ * type: what `Image` asks before it decodes, since the platform
7978
+ * decoder refuses SVG and this one draws it.
7979
+ */
7980
+ function isSvgSource(source) {
7981
+ if (/^data:image\/svg\+xml[;,]/i.test(source)) return true;
7982
+ const path = source.split(/[?#]/)[0] ?? "";
7983
+ return /\.svgz?$/i.test(path);
7984
+ }
7985
+ const DEFAULT_CAPACITY$3 = 64;
7986
+ /**
7987
+ * Fetch, read, keep.
7988
+ *
7989
+ * Kept by recency and never closed, unlike a bitmap: a read file holds
7990
+ * no decoded pixels, so there is nothing to release promptly, and a
7991
+ * file a screen shows a hundred times (an icon in every row) is read
7992
+ * once. A failed fetch is not kept, so the next node tries again.
7993
+ */
7994
+ var DefaultSvgResolver = class {
7995
+ entries = /* @__PURE__ */ new Map();
7996
+ settled = /* @__PURE__ */ new Map();
7997
+ capacity;
7998
+ fetchText;
7999
+ constructor(options = {}) {
8000
+ this.capacity = options.capacity ?? DEFAULT_CAPACITY$3;
8001
+ this.fetchText = options.fetch ?? defaultFetch$2;
8002
+ }
8003
+ resolve(source) {
8004
+ const existing = this.entries.get(source);
8005
+ if (existing !== void 0) {
8006
+ this.entries.delete(source);
8007
+ this.entries.set(source, existing);
8008
+ return existing;
8009
+ }
8010
+ const entry = this.fetchText(source).then((text) => {
8011
+ const document = parseSvg(text);
8012
+ if (this.entries.get(source) === entry) this.settled.set(source, document);
8013
+ return document;
8014
+ }).catch((error) => {
8015
+ if (this.entries.get(source) === entry) this.entries.delete(source);
8016
+ throw error;
8017
+ });
8018
+ entry.catch(() => {});
8019
+ this.entries.set(source, entry);
8020
+ while (this.entries.size > this.capacity) {
8021
+ const oldest = this.entries.keys().next().value;
8022
+ this.entries.delete(oldest);
8023
+ this.settled.delete(oldest);
8024
+ }
8025
+ return entry;
8026
+ }
8027
+ peek(source) {
8028
+ return this.settled.get(source) ?? null;
8029
+ }
8030
+ };
8031
+ async function defaultFetch$2(source) {
8032
+ const response = await fetch(source);
8033
+ if (!response.ok) throw new Error(`Fetching the SVG '${source}' failed with ${response.status} ${response.statusText}.`);
8034
+ return response.text();
8035
+ }
8036
+ //#endregion
6864
8037
  //#region src/modifiers/media.ts
6865
8038
  /**
6866
8039
  * A value or an Observable of one, as one Observable. The media
@@ -6870,6 +8043,29 @@ function numberOr(value, fallback) {
6870
8043
  function follow(value) {
6871
8044
  return isObservable$1(value) ? value : of(value);
6872
8045
  }
8046
+ /** Pictures this thread's media modifiers are fetching or decoding now. */
8047
+ let inFlight = 0;
8048
+ /**
8049
+ * How many pictures the media modifiers in this thread are still
8050
+ * fetching or decoding: an `Image`'s bitmap or its SVG.
8051
+ *
8052
+ * A tree waiting on a picture asks for no frames while it waits, so a
8053
+ * caller that judges a tree finished by its quiet (`renderFrame`, which
8054
+ * draws a mock once, off screen) would draw it without the picture.
8055
+ * This is the other half of finished: nothing still on its way.
8056
+ */
8057
+ function mediaLoadsInFlight() {
8058
+ return inFlight;
8059
+ }
8060
+ /** Counts a load from its start until it settles, either way. */
8061
+ function counted(loading) {
8062
+ inFlight++;
8063
+ const done = () => {
8064
+ inFlight--;
8065
+ };
8066
+ loading.then(done, done);
8067
+ return loading;
8068
+ }
6873
8069
  /**
6874
8070
  * Resolves a source to a bitmap and writes it onto the node's `image`.
6875
8071
  *
@@ -6905,6 +8101,8 @@ function load$1(host, args, sources) {
6905
8101
  let held = null;
6906
8102
  args.onState?.("loading");
6907
8103
  host.clear("image");
8104
+ host.clear("paint");
8105
+ host.clear("src");
6908
8106
  const attempt = (index, lastError) => {
6909
8107
  if (!live) return;
6910
8108
  const source = sources[index];
@@ -6912,16 +8110,22 @@ function load$1(host, args, sources) {
6912
8110
  args.onState?.("failed", lastError ?? /* @__PURE__ */ new Error("No image source was given."));
6913
8111
  return;
6914
8112
  }
8113
+ if (args.vectors !== void 0 && isSvgSource(source)) {
8114
+ drawVector(host, args, args.vectors, source, () => live, (error) => attempt(index + 1, error));
8115
+ return;
8116
+ }
6915
8117
  held = source;
6916
8118
  const ready = args.resolver.peek?.(source) ?? null;
6917
8119
  if (ready !== null) {
6918
8120
  host.set("image", ready);
8121
+ host.set("src", source);
6919
8122
  args.onState?.("loaded");
6920
8123
  return;
6921
8124
  }
6922
- args.resolver.resolve(source).then((bitmap) => {
8125
+ counted(args.resolver.resolve(source)).then((bitmap) => {
6923
8126
  if (!live) return;
6924
8127
  host.set("image", bitmap);
8128
+ host.set("src", source);
6925
8129
  args.onState?.("loaded");
6926
8130
  }).catch((error) => {
6927
8131
  if (held === source) held = null;
@@ -6937,6 +8141,36 @@ function load$1(host, args, sources) {
6937
8141
  }
6938
8142
  };
6939
8143
  }
8144
+ /** SVG sources already warned about, so a file shown in every row says what it lacks once. */
8145
+ const warnedSvg = /* @__PURE__ */ new Set();
8146
+ /**
8147
+ * An SVG source, read and set as the node's `paint`: vectors, drawn at
8148
+ * whatever size the node is laid out at, with `currentColor` the
8149
+ * node's inherited text colour. Nothing is held, because a read file
8150
+ * holds no pixels to release.
8151
+ */
8152
+ function drawVector(host, args, vectors, source, live, fail) {
8153
+ const show = (document) => {
8154
+ const fit = host.node.getProperty("objectFit") ?? "contain";
8155
+ host.set("paint", svgPaint(document, { fit }));
8156
+ host.set("src", source);
8157
+ if (document.unsupported.length > 0 && !warnedSvg.has(source)) {
8158
+ warnedSvg.add(source);
8159
+ console.warn(`[gesso] ${source.slice(0, 80)} uses ${document.unsupported.join(", ")}, which Gesso does not draw yet; the rest of it is drawn.`);
8160
+ }
8161
+ args.onState?.("loaded");
8162
+ };
8163
+ const ready = vectors.peek?.(source) ?? null;
8164
+ if (ready !== null) {
8165
+ show(ready);
8166
+ return;
8167
+ }
8168
+ counted(vectors.resolve(source)).then((document) => {
8169
+ if (live()) show(document);
8170
+ }, (error) => {
8171
+ if (live()) fail(error);
8172
+ });
8173
+ }
6940
8174
  function sameSources(a, b) {
6941
8175
  if (typeof a === "string" || typeof b === "string") return a === b;
6942
8176
  return a.length === b.length && a.every((url, index) => url === b[index]);
@@ -8630,11 +9864,9 @@ const DEFAULT_CAPACITY$2 = 32;
8630
9864
  *
8631
9865
  * **What it cannot decode.** `createImageBitmap` takes a `Blob`, and
8632
9866
  * Chrome refuses an SVG one — "The source image could not be decoded".
8633
- * So an `Image` pointed at an `.svg` fails on a browser where the same
8634
- * file in an `<img>` would work, and a vector glyph belongs in `Icon`,
8635
- * which draws a path rather than decoding a document. Found by
8636
- * pointing the playground's Media card at an SVG data URL and getting
8637
- * a placeholder.
9867
+ * Found by pointing the playground's Media card at an SVG data URL and
9868
+ * getting a placeholder. So an `Image` never sends one here: an SVG
9869
+ * source is read by `SvgResolver` and drawn as vectors (`svg/`).
8638
9870
  *
8639
9871
  * **Eviction.** Reference counting first, LRU second. A bitmap
8640
9872
  * something on screen is holding is never evicted, however long the
@@ -9282,6 +10514,19 @@ fn fs(in: VertexOutput) -> @location(0) vec4f {
9282
10514
  let color = textureSample(tTexture, tSampler, in.uv);
9283
10515
  return vec4f(color.rgb, color.a * in.opacity * alpha);
9284
10516
  }
10517
+
10518
+ // An opacity group's layer, blended onto what holds it. The layer was
10519
+ // drawn into with the same blend as the frame, so it holds premultiplied
10520
+ // colour, and is scaled whole — colour and alpha alike — by the group's
10521
+ // opacity and the clip's coverage.
10522
+ @fragment
10523
+ fn fsLayer(in: VertexOutput) -> @location(0) vec4f {
10524
+ let alpha = clipCoverage(in.position.xy, uView.z, in.clipIndex);
10525
+ if (alpha <= 0.0) {
10526
+ discard;
10527
+ }
10528
+ return textureSample(tTexture, tSampler, in.uv) * (in.opacity * alpha);
10529
+ }
9285
10530
  `;
9286
10531
  //#endregion
9287
10532
  //#region src/rendering/webgpu/WebGPUGlyphAtlas.ts
@@ -10109,6 +11354,13 @@ let CommandKind = /* @__PURE__ */ function(CommandKind) {
10109
11354
  CommandKind[CommandKind["Glyphs"] = 1] = "Glyphs";
10110
11355
  /** One textured instance drawn with an image. */
10111
11356
  CommandKind[CommandKind["Image"] = 2] = "Image";
11357
+ /**
11358
+ * Everything until the matching `EndLayer` is drawn into a cleared
11359
+ * layer of its own, the start of an opacity group (`GroupOpacity.ts`).
11360
+ */
11361
+ CommandKind[CommandKind["BeginLayer"] = 3] = "BeginLayer";
11362
+ /** The layer is done, and is blended onto what holds it at the group's opacity. */
11363
+ CommandKind[CommandKind["EndLayer"] = 4] = "EndLayer";
10112
11364
  return CommandKind;
10113
11365
  }({});
10114
11366
  const IDENTITY = [
@@ -10223,8 +11475,21 @@ function buildRenderList(root, layout, measurer, logicalWidth, logicalHeight, dp
10223
11475
  height: logicalHeight
10224
11476
  }
10225
11477
  };
10226
- /** The nodes asking for `lift`, met on the walk and drawn after it. */
11478
+ /**
11479
+ * The nodes asking for `lift`, met on the walk and drawn after it,
11480
+ * with their opacity as a product of everything above them: inside a
11481
+ * layer `state.opacity` counts from the layer, and a lifted node is
11482
+ * drawn outside the layers it was met in.
11483
+ */
10227
11484
  const liftedPass = [];
11485
+ /**
11486
+ * The opacity each open layer will be blended at, multiplied out from
11487
+ * the frame: the last entry is what `state.opacity` is relative to.
11488
+ * One entry, 1, while no layer is open.
11489
+ */
11490
+ const layerOpacities = [1];
11491
+ const physicalWidth = toPhysicalPixels(logicalWidth, dpr);
11492
+ const physicalHeight = toPhysicalPixels(logicalHeight, dpr);
10228
11493
  function closePrimitives() {
10229
11494
  const end = instanceData.length / 24;
10230
11495
  if (end > openStart) commands.push({
@@ -10344,7 +11609,7 @@ function buildRenderList(root, layout, measurer, logicalWidth, logicalHeight, dp
10344
11609
  if (rec.lifted && !lifted) {
10345
11610
  liftedPass.push({
10346
11611
  node,
10347
- opacity: state.opacity,
11612
+ opacity: state.opacity * layerOpacities[layerOpacities.length - 1],
10348
11613
  ctm: state.ctm
10349
11614
  });
10350
11615
  return;
@@ -10352,9 +11617,33 @@ function buildRenderList(root, layout, measurer, logicalWidth, logicalHeight, dp
10352
11617
  const sticky = rec.stickyOffsetX !== 0 || rec.stickyOffsetY !== 0;
10353
11618
  if (state.cull !== null && !intersectsCull(state.cull, rec.extentMinX + rec.stickyOffsetX, rec.extentMinY + rec.stickyOffsetY, rec.extentMaxX - rec.extentMinX, rec.extentMaxY - rec.extentMinY)) return;
10354
11619
  const paint = resolvePaintState(node, paintScratch);
10355
- const effectiveOpacity = state.opacity * paint.opacity;
11620
+ const layered = paint.opacity < 1 && opacityNeedsLayer(node, rec, paint, layout);
11621
+ const opacity = paint.opacity;
11622
+ const outerOpacity = state.opacity;
11623
+ const outerClip = state.clip;
11624
+ const outerRounded = state.rounded;
11625
+ const effectiveOpacity = layered ? 1 : state.opacity * paint.opacity;
10356
11626
  const baseCtm = sticky ? translateTransform(state.ctm, rec.stickyOffsetX, rec.stickyOffsetY) : state.ctm;
10357
11627
  const nodeCtm = paint.hasTransform ? multiplyTransform(baseCtm, buildOwnTransform(rec, paint.transform)) : baseCtm;
11628
+ const region = layered ? layerRegion(node, rec, {
11629
+ a: nodeCtm[0] * dpr,
11630
+ b: nodeCtm[1] * dpr,
11631
+ c: nodeCtm[2] * dpr,
11632
+ d: nodeCtm[3] * dpr,
11633
+ e: nodeCtm[4] * dpr,
11634
+ f: nodeCtm[5] * dpr
11635
+ }, layout, physicalWidth, physicalHeight, dpr) : null;
11636
+ if (layered) {
11637
+ closePrimitives();
11638
+ commands.push({
11639
+ kind: 3,
11640
+ scissor: null
11641
+ });
11642
+ layerOpacities.push(layerOpacities[layerOpacities.length - 1] * outerOpacity * opacity);
11643
+ state.opacity = 1;
11644
+ state.clip = null;
11645
+ state.rounded = -1;
11646
+ }
10358
11647
  const ownScissor = state.clip;
10359
11648
  const ownRounded = state.rounded;
10360
11649
  let nextClip = state.clip;
@@ -10624,6 +11913,24 @@ function buildRenderList(root, layout, measurer, logicalWidth, logicalHeight, dp
10624
11913
  beginPrimitives(ownScissor);
10625
11914
  pushScrollbars(instanceData, rec, effectiveOpacity, nodeCtm, ownRounded, now);
10626
11915
  }
11916
+ if (region !== null) {
11917
+ closePrimitives();
11918
+ layerOpacities.pop();
11919
+ state.opacity = outerOpacity;
11920
+ state.clip = outerClip;
11921
+ state.rounded = outerRounded;
11922
+ const instance = region.width > 0 && region.height > 0 ? pushTextured(texturedData, region.x / dpr, region.y / dpr, region.width / dpr, region.height / dpr, outerOpacity * opacity, IDENTITY, outerRounded, {
11923
+ u: region.x / physicalWidth,
11924
+ v: region.y / physicalHeight,
11925
+ uw: region.width / physicalWidth,
11926
+ vh: region.height / physicalHeight
11927
+ }) : null;
11928
+ commands.push({
11929
+ kind: 4,
11930
+ instance,
11931
+ scissor: outerClip
11932
+ });
11933
+ }
10627
11934
  }
10628
11935
  /**
10629
11936
  * The top layer, drawn once the tree is done: no clip, no scissor,
@@ -10643,7 +11950,7 @@ function buildRenderList(root, layout, measurer, logicalWidth, logicalHeight, dp
10643
11950
  };
10644
11951
  for (let i = from; i < liftedPass.length; i++) {
10645
11952
  const entry = liftedPass[i];
10646
- state.opacity = entry.opacity;
11953
+ state.opacity = entry.opacity / layerOpacities[layerOpacities.length - 1];
10647
11954
  state.ctm = entry.ctm;
10648
11955
  state.clip = clip;
10649
11956
  state.rounded = rounded;
@@ -11125,6 +12432,19 @@ const STRAIGHT_ALPHA_BLEND = {
11125
12432
  operation: "add"
11126
12433
  }
11127
12434
  };
12435
+ /** Source-over for a premultiplied source: an opacity group's layer. */
12436
+ const PREMULTIPLIED_BLEND = {
12437
+ color: {
12438
+ srcFactor: "one",
12439
+ dstFactor: "one-minus-src-alpha",
12440
+ operation: "add"
12441
+ },
12442
+ alpha: {
12443
+ srcFactor: "one",
12444
+ dstFactor: "one-minus-src-alpha",
12445
+ operation: "add"
12446
+ }
12447
+ };
11128
12448
  /**
11129
12449
  * Creates the primitive pipeline: rounded fills and borders.
11130
12450
  *
@@ -11204,8 +12524,9 @@ function createTexturedPipeline(device, format, frameLayout) {
11204
12524
  texture: {}
11205
12525
  }
11206
12526
  ] });
12527
+ const layout = device.createPipelineLayout({ bindGroupLayouts: [bindGroupLayout, frameLayout] });
11207
12528
  const pipeline = device.createRenderPipeline({
11208
- layout: device.createPipelineLayout({ bindGroupLayouts: [bindGroupLayout, frameLayout] }),
12529
+ layout,
11209
12530
  vertex: {
11210
12531
  module,
11211
12532
  entryPoint: "vs",
@@ -11224,7 +12545,27 @@ function createTexturedPipeline(device, format, frameLayout) {
11224
12545
  cullMode: "none"
11225
12546
  }
11226
12547
  });
11227
- if (pipeline === void 0) throw new WebGPUError("Failed to create textured render pipeline.", "pipeline");
12548
+ const layerPipeline = device.createRenderPipeline({
12549
+ layout,
12550
+ vertex: {
12551
+ module,
12552
+ entryPoint: "vs",
12553
+ buffers: [quadVertexLayout(), texturedInstanceLayout()]
12554
+ },
12555
+ fragment: {
12556
+ module,
12557
+ entryPoint: "fsLayer",
12558
+ targets: [{
12559
+ format,
12560
+ blend: PREMULTIPLIED_BLEND
12561
+ }]
12562
+ },
12563
+ primitive: {
12564
+ topology: "triangle-list",
12565
+ cullMode: "none"
12566
+ }
12567
+ });
12568
+ if (pipeline === void 0 || layerPipeline === void 0) throw new WebGPUError("Failed to create textured render pipeline.", "pipeline");
11228
12569
  const { vertexBuffer, indexBuffer } = createQuad(device);
11229
12570
  const uniformBuffer = device.createBuffer({
11230
12571
  size: 16,
@@ -11244,7 +12585,8 @@ function createTexturedPipeline(device, format, frameLayout) {
11244
12585
  imageSampler: device.createSampler({
11245
12586
  magFilter: "linear",
11246
12587
  minFilter: "linear"
11247
- })
12588
+ }),
12589
+ layerPipeline
11248
12590
  };
11249
12591
  }
11250
12592
  function createQuad(device) {
@@ -11673,6 +13015,7 @@ function createCanvas(width, height) {
11673
13015
  const vertexBufferUsage = typeof GPUBufferUsage !== "undefined" ? GPUBufferUsage.VERTEX : 32;
11674
13016
  const storageBufferUsage = typeof GPUBufferUsage !== "undefined" ? GPUBufferUsage.STORAGE : 128;
11675
13017
  const copyDstBufferUsage = typeof GPUBufferUsage !== "undefined" ? GPUBufferUsage.COPY_DST : 8;
13018
+ const layerTextureUsage = (typeof GPUTextureUsage !== "undefined" ? GPUTextureUsage.RENDER_ATTACHMENT : 16) | (typeof GPUTextureUsage !== "undefined" ? GPUTextureUsage.TEXTURE_BINDING : 4);
11676
13019
  const copyDstUsage = typeof GPUBufferUsage !== "undefined" ? GPUBufferUsage.COPY_DST : 8;
11677
13020
  const mapReadUsage = typeof GPUBufferUsage !== "undefined" ? GPUBufferUsage.MAP_READ : 1;
11678
13021
  const mapModeRead = typeof GPUMapMode !== "undefined" ? GPUMapMode.READ : 1;
@@ -11705,6 +13048,12 @@ var WebGPURenderer = class {
11705
13048
  frameLayout = null;
11706
13049
  frameBindGroup = null;
11707
13050
  cachedInstanceData = null;
13051
+ /**
13052
+ * The textures opacity groups are drawn in, one per depth of nesting,
13053
+ * so a group inside a group never clears what holds it. Made the first
13054
+ * time a frame reaches that depth and again when the surface resizes.
13055
+ */
13056
+ groupLayers = [];
11708
13057
  /** Draw calls of the most recent frame. */
11709
13058
  lastDraws = {
11710
13059
  primitiveDraws: 0,
@@ -11847,8 +13196,9 @@ var WebGPURenderer = class {
11847
13196
  const encodeStart = this.hooks.onEncodeStart !== void 0 || this.hooks.onEncodeEnd !== void 0 ? performance.now() : 0;
11848
13197
  const commandEncoder = device.createCommandEncoder();
11849
13198
  const texture = this.surface.getCurrentTexture();
11850
- const pass = commandEncoder.beginRenderPass({ colorAttachments: [{
11851
- view: texture.createView(),
13199
+ const targets = [texture.createView()];
13200
+ let pass = commandEncoder.beginRenderPass({ colorAttachments: [{
13201
+ view: targets[0],
11852
13202
  clearValue: {
11853
13203
  r: 0,
11854
13204
  g: 0,
@@ -11868,6 +13218,49 @@ var WebGPURenderer = class {
11868
13218
  const commands = list.commands;
11869
13219
  for (let i = 0; i < commands.length; i++) {
11870
13220
  const command = commands[i];
13221
+ if (command.kind === 3 || command.kind === 4) {
13222
+ pass.end();
13223
+ const depth = targets.length - 1;
13224
+ let layer;
13225
+ if (command.kind === 3) {
13226
+ layer = this.groupLayer(device, depth, texture.width, texture.height);
13227
+ targets.push(layer.view);
13228
+ } else {
13229
+ layer = this.groupLayers[depth - 1];
13230
+ targets.pop();
13231
+ }
13232
+ pass = commandEncoder.beginRenderPass({ colorAttachments: [command.kind === 3 ? {
13233
+ view: layer.view,
13234
+ clearValue: {
13235
+ r: 0,
13236
+ g: 0,
13237
+ b: 0,
13238
+ a: 0
13239
+ },
13240
+ loadOp: "clear",
13241
+ storeOp: "store"
13242
+ } : {
13243
+ view: targets[targets.length - 1],
13244
+ loadOp: "load",
13245
+ storeOp: "store"
13246
+ }] });
13247
+ pass.setBindGroup(1, this.frameBindGroup);
13248
+ currentScissor = null;
13249
+ currentKind = null;
13250
+ if (command.kind === 3) continue;
13251
+ const blendScissor = command.scissor ?? viewport;
13252
+ if (command.instance === null || blendScissor.width <= 0 || blendScissor.height <= 0) continue;
13253
+ pass.setPipeline(textured.layerPipeline);
13254
+ pass.setVertexBuffer(0, textured.vertexBuffer);
13255
+ pass.setVertexBuffer(1, this.texturedBuffer);
13256
+ pass.setIndexBuffer(textured.indexBuffer, "uint16");
13257
+ pass.setBindGroup(0, layer.bindGroup);
13258
+ currentScissor = setScissor(pass, currentScissor, blendScissor);
13259
+ pass.drawIndexed(textured.indexCount, 1, 0, 0, command.instance);
13260
+ this.lastDraws.texturedDraws++;
13261
+ this.lastDraws.texturedInstances++;
13262
+ continue;
13263
+ }
11871
13264
  const scissor = command.scissor ?? viewport;
11872
13265
  if (scissor.width <= 0 || scissor.height <= 0) continue;
11873
13266
  if (command.kind === 0) {
@@ -11909,6 +13302,24 @@ var WebGPURenderer = class {
11909
13302
  capture?.();
11910
13303
  if (this.hooks.onEncodeEnd !== void 0) this.hooks.onEncodeEnd(performance.now() - encodeStart);
11911
13304
  }
13305
+ /** The layer for an opacity group at `depth`, made or remade at the surface's size. */
13306
+ groupLayer(device, depth, width, height) {
13307
+ const existing = this.groupLayers[depth];
13308
+ if (existing !== void 0 && existing.texture.width === width && existing.texture.height === height) return existing;
13309
+ existing?.texture.destroy();
13310
+ const texture = device.createTexture({
13311
+ size: [width, height],
13312
+ format: this.format,
13313
+ usage: layerTextureUsage
13314
+ });
13315
+ const layer = {
13316
+ texture,
13317
+ view: texture.createView(),
13318
+ bindGroup: createTexturedBindGroup(device, this.textured, texture, this.textured.textSampler)
13319
+ };
13320
+ this.groupLayers[depth] = layer;
13321
+ return layer;
13322
+ }
11912
13323
  /**
11913
13324
  * When a capture is pending, encodes a copy of the frame into a
11914
13325
  * mappable buffer and returns the step that maps it after submit.
@@ -12034,6 +13445,8 @@ var WebGPURenderer = class {
12034
13445
  this.clipBuffer = null;
12035
13446
  this.gradientBuffer?.destroy();
12036
13447
  this.gradientBuffer = null;
13448
+ for (const layer of this.groupLayers) layer.texture.destroy();
13449
+ this.groupLayers = [];
12037
13450
  this.frameBindGroup = null;
12038
13451
  this.frameLayout = null;
12039
13452
  this.primitives = null;
@@ -14723,6 +16136,14 @@ const NEW_DISPLAY = .15;
14723
16136
  const BEAT_PASSES = 3;
14724
16137
  /** Refreshes apart the two an interval is read between must be, at least. */
14725
16138
  const MIN_BEAT_SPAN = 6;
16139
+ /**
16140
+ * The most refreshes a frame waits for a tick that has not sat in this
16141
+ * thread's queue (see `tick`): a frame is drawn on a stale one after
16142
+ * that, so a thread that is always behind still draws.
16143
+ */
16144
+ const MAX_QUEUED_REFRESHES = 8;
16145
+ /** How long, at least, between timing this thread's refreshes again once they were given up; see `retryLocal`. */
16146
+ const RETRY_LOCAL_MS = 2e3;
14726
16147
  /** The most refreshes a frame is given: two, sixty at 120 Hz; slower than that is no smoother. */
14727
16148
  const MAX_STRIDE = 2;
14728
16149
  function localAnimationFrame() {
@@ -14776,6 +16197,8 @@ var UiHostFrameClock = class {
14776
16197
  /** Gaps between this thread's own refreshes while frames ran back to back. */
14777
16198
  localIntervals = [];
14778
16199
  lastLocalTime = null;
16200
+ /** How long the frame drawn at `lastLocalTime` took, which says whether the gap after it was the refresh's or the frame's. */
16201
+ lastLocalCost = 0;
14779
16202
  /** The display's interval and the host's time origin, once the host has said. */
14780
16203
  display = null;
14781
16204
  /**
@@ -14784,6 +16207,11 @@ var UiHostFrameClock = class {
14784
16207
  * show (see \`displayInterval\`).
14785
16208
  */
14786
16209
  locked = false;
16210
+ /** This thread's own `requestAnimationFrame` once given up, kept to see whether it keeps time after all. */
16211
+ givenUp = null;
16212
+ /** When this thread's refreshes were last timed again, and their times while they are being. */
16213
+ lastRetry = -Infinity;
16214
+ retrying = null;
14787
16215
  /** The host's recent refresh times, which give the beat its phase. */
14788
16216
  refreshes = [];
14789
16217
  /** Host refreshes since the last frame drawn on the beat. */
@@ -14818,7 +16246,11 @@ var UiHostFrameClock = class {
14818
16246
  if (this.localHandle === null) this.localHandle = this.local((time) => {
14819
16247
  this.localHandle = null;
14820
16248
  this.recordLocal(time);
14821
- if (this.pending) this.deliver(time);
16249
+ if (this.pending) {
16250
+ const started = this.now();
16251
+ this.deliver(time);
16252
+ this.lastLocalCost = this.now() - started;
16253
+ } else this.lastLocalCost = 0;
14822
16254
  });
14823
16255
  return;
14824
16256
  }
@@ -14873,7 +16305,7 @@ var UiHostFrameClock = class {
14873
16305
  this.lastLocalTime = time;
14874
16306
  if (previous !== null && this.pending) {
14875
16307
  const interval = time - previous;
14876
- if (interval > 0 && interval < MAX_CADENCE_MS) {
16308
+ if (interval > 0 && interval < MAX_CADENCE_MS && this.lastLocalCost < interval / 2) {
14877
16309
  this.localIntervals.push(interval);
14878
16310
  if (this.localIntervals.length > LOCAL_SAMPLES) this.localIntervals.shift();
14879
16311
  }
@@ -14891,9 +16323,59 @@ var UiHostFrameClock = class {
14891
16323
  if (this.local === null || this.display === null || this.localIntervals.length < LOCAL_SAMPLES) return;
14892
16324
  const sorted = [...this.localIntervals].sort((a, b) => a - b);
14893
16325
  if (sorted[Math.floor(sorted.length / 2)] / this.display.interval <= 1.06) return;
16326
+ this.givenUp = this.local;
14894
16327
  this.local = null;
14895
16328
  this.locked = true;
14896
16329
  }
16330
+ /**
16331
+ * Times this thread's own refreshes again, now and then, once they were
16332
+ * given up, and takes them back if they keep the display's time.
16333
+ *
16334
+ * Given up for good, a worker's refreshes stayed given up whatever had
16335
+ * made them slow. A Chrome worker busy between its frames, opening a
16336
+ * large file or scrolling through lines it has never drawn, refreshes
16337
+ * late and unevenly, which no measure of the gaps alone told from
16338
+ * WebKit's timer: 5.5, 25.5, 10.9, 25 ms on a 165 Hz display one time,
16339
+ * 12.1, 6.1, 12.2, 24.2 the next. Its frames then went through the
16340
+ * host's ticks for as long as the page was open, a message and a hop
16341
+ * through the page's thread each. Timed again while frames are cheap,
16342
+ * they come a refresh apart and are taken back; WebKit's come 15 ms
16343
+ * apart on a 120 Hz display however idle the thread is, and stay given
16344
+ * up. Nine refreshes every two seconds or more, while frames come cheap.
16345
+ */
16346
+ retryLocal(interval) {
16347
+ if (this.givenUp === null || this.hidden || this.costs.length < SLOW_SAMPLES) return;
16348
+ const now = this.now();
16349
+ if (now - this.lastRetry < RETRY_LOCAL_MS) return;
16350
+ const sorted = [...this.costs].sort((a, b) => a - b);
16351
+ if (sorted[Math.floor(sorted.length / 2)] > interval * FAST_FRAME) return;
16352
+ this.lastRetry = now;
16353
+ const local = this.givenUp;
16354
+ const times = [];
16355
+ this.retrying = times;
16356
+ const step = (time) => {
16357
+ if (this.retrying !== times) return;
16358
+ times.push(time);
16359
+ if (times.length <= LOCAL_SAMPLES) {
16360
+ local(step);
16361
+ return;
16362
+ }
16363
+ this.retrying = null;
16364
+ const gaps = times.slice(1).map((value, index) => value - times[index]).sort((a, b) => a - b);
16365
+ if (this.givenUp === null || this.display === null || gaps[Math.floor(gaps.length / 2)] / this.display.interval > 1.06) return;
16366
+ this.local = this.givenUp;
16367
+ this.givenUp = null;
16368
+ this.locked = false;
16369
+ this.localIntervals.length = 0;
16370
+ this.lastLocalTime = null;
16371
+ this.costs.length = 0;
16372
+ this.stride = 1;
16373
+ this.clearFallback();
16374
+ this.setActive(false);
16375
+ if (this.pending) this.requestFrame();
16376
+ };
16377
+ local(step);
16378
+ }
14897
16379
  /** A time on the host's clock, on this thread's. */
14898
16380
  toLocal(host) {
14899
16381
  return this.display === null ? host : host - this.timeOrigin + this.display.origin;
@@ -14959,6 +16441,7 @@ var UiHostFrameClock = class {
14959
16441
  const started = this.now();
14960
16442
  this.deliver(this.toLocal(refresh));
14961
16443
  this.recordCost(this.now() - started, beat.interval);
16444
+ this.retryLocal(beat.interval);
14962
16445
  }
14963
16446
  /**
14964
16447
  * Keeps the stride to what frames cost: every refresh while the typical
@@ -15120,7 +16603,8 @@ var UiHostFrameClock = class {
15120
16603
  if (this.pending) {
15121
16604
  this.clearFallback();
15122
16605
  this.idleTicks = 0;
15123
- if (this.refreshesSinceFrame >= this.stride) this.deliverOnBeat(time);
16606
+ const queued = this.now() - this.toLocal(time) > this.display.interval;
16607
+ if (this.refreshesSinceFrame >= this.stride && (!queued || this.refreshesSinceFrame >= MAX_QUEUED_REFRESHES)) this.deliverOnBeat(time);
15124
16608
  return;
15125
16609
  }
15126
16610
  }
@@ -16114,6 +17598,6 @@ function recordsEqual(a, b) {
16114
17598
  return true;
16115
17599
  }
16116
17600
  //#endregion
16117
- export { AlignContent, AnimationDriver, BOX_SHADOW_BLUR_REACH, BUTTON_INTERACTION, Box, Button, CARET_BLINK_MS, CARET_WIDTH, CLIP_STRIDE_BYTES, CLIP_STRIDE_FLOATS, Canvas2DRenderer, CanvasPlatformSurface, CanvasSurface, CanvasTextMeasurer, CharacterCountTextMeasurer, Column, CommandKind, Constraints, CrossAxisAlignment, DEFAULT_BLOCK_SIZE, DEFAULT_FONT_FAMILY, DEFAULT_FONT_SIZE, DEFAULT_FONT_WEIGHT, DEFAULT_LINE_HEIGHT_FACTOR, DEFAULT_TEXT_COLOR, DefaultImageResolver, DefaultVideoResolver, DirtyFlags, DirtyNodeSet, EDITOR_PROP, ELLIPSIS, EMPTY_RECORDING, EXTERNAL_FILES, EditableLayout, EditableText, EditableTextModel, EnvironmentNotifier, FlexDirection, FocusNotifier, GLYPH_SUBPIXEL_PHASES, GlyphShaper, Grid, INSPECTOR_HEAT_MS, INSTANCE_STRIDE_BYTES, INSTANCE_STRIDE_FLOATS, IconRasterizer, LABEL_PADDING_X, LayoutEngine, LayoutInspector, LayoutNotifier, LayoutRecord, LazyColumn, LazyGrid, LazyRow, LazySheet, MARK_PREFIX, MAX_GRADIENT_STOPS, MAX_MEASURES_PER_CHILD, MOTION_CHANNELS, MOTION_REST, MOUSE_POINTER, MainAxisAlignment, Mp3Frames, NO_CLIP_INDEX, NodeTransitions, Paint, PaintPictureCache, PaintRecorder, PaintTarget, ParagraphTextMeasurer, PrimitiveKind, Responsive, Row, SCROLLBAR_FADE_MS, SCROLLBAR_HOVER_ZONE, SCROLLBAR_INSET, SCROLLBAR_LINGER_MS, SCROLLBAR_MIN_THUMB, SCROLLBAR_THICKNESS, ScrollView, Stack, TEXTURED_STRIDE_BYTES, TEXTURED_STRIDE_FLOATS, TEXT_MATCHES_PROP, TEXT_RUN_ID_SEPARATOR, TEXT_SELECTION_PROP, Text, UI_ROLES, UI_SEMANTIC_STATES, UI_SUBGRID_AXES, UiAnimation, UiAnimationFrameClock, UiBasicColors, UiBeforeInputEvent, UiBinding, UiBorderRadiuses, UiChildrenBinding, UiCompositionEvent, UiContainerSizeSource, UiDragSession, UiEditingController, UiEnvironment, UiEnvironmentKeys, UiEventBinding, UiEventType, UiFindController, UiFocusEvent, UiFocusManager, UiFrame, UiGestureEvent, UiGestureRecognizer, UiGraph, UiGraphBuilder, UiHitTester, UiHostFrameClock, UiInputDispatcher, UiInputEvent, UiInsetRegistry, UiKeyboardController, UiKeyboardEvent, UiManualFrameClock, UiModifierSet, UiNode, UiNodeType, UiPasteEvent, UiPinchEvent, UiPinchRecognizer, UiPlatformAdapter, UiPointerController, UiPointerEvent, UiProperties, UiScheduler, UiSelectionChangeEvent, UiSelectionController, UiSharedElements, UiShortcutRegistry, UiSpring, UiTextChangeEvent, UiTimerFrameClock, UiTouchScroller, UiTransforms, UiTween, UiUnknownModifierPropertyError, UiVirtualSheet, UiVirtualWindow, UiVisualState, UiWheelController, UiWheelDeltaMode, UiWheelEvent, VIRTUAL_INDEX_PROP, VIRTUAL_LEAD_PROP, VIRTUAL_SHEET_PROP, VIRTUAL_WINDOW_PROP, WebGPUError, WebGPUGlyphAtlas, WebGPUGlyphPages, WebGPURenderer, WebGPUSurface, WebGPUTextureCache, accumulatedOffsetTo, adjacentField, animateLayout, applyCanvasTextStyle, assertModifierList, assertTransitionMap, auto, autoFocus, bandOf, borderRadius, borderRadiusCorners, borderRadiusEqual, borderRadiusIsZero, borderRadiusValuesEqual, borderShapes, borders, boxShadow, boxShadowArraysEqual, boxShadowRadius, boxShadowReach, boxShadowsEqual, breakpoint, bufferSource, buildFontString, buildRenderList, buildSemanticsSubtree, buildSemanticsTree, bumpFontStack, bundle, canDecodeVideo, capturePointer, caretRectFor, caretVisibleAt, clampSize, clearFontStacks, clearLinkHover, clearMatchRanges, clearOverrideProperty, clearSelectionRange, clickOutside, closestPropertyName, colorToCss, colorToHex, colorToRgba, colorValuesEqual, colorsEqual, colorsEqualPalette, commandForKey, comparePositions, computeObjectFitRect, constraintsEqual, containerBands, contentOffset, contextMenu, contrastRatio, createCanvasSurface, createCanvasTextStyle, createElement, createEnvironmentKey, createPaintState, createTextCache, createTween, createWebGPUSurface, cubicBezier, cueAt, darkColors, darkTheme, decorated, decorationColor, decorationRect, defaultMotion, defaultShadows, defaultShapes, defaultSpacing, defaultTextStyle, defaultTypography, defaultVisualState, defineModifier, defineProperty, defineThemeExtension, demuxMp4Audio, demuxMp4Video, densityFactors, describeLength, describeOverrides, describeShortcut, detectEditingPlatform, diffSemantics, dragSessionFor, dragSource, draggable, drawOverlayShapes, drawText, dropIndexShifts, dropTarget, easings, edgeField, editableSpansOf, editingGroupOf, editorFor, editorOf, fade, fillTextRects, findEnvironmentKey, findMatchesIn, findPropertyDefinition, flattenTextSpans, focusRing, fontStackFor, formatConstraints, formatExplanation, formatShortcut, fr, getPropertyNames, glyphCount, gradientPaint, gradientsEqual, graphemeBoundaries, hasDecorationPhase, hasDrawnText, hasTextLinks, hasThemeExtension, hasVisualState, hiddenRangesOf, highContrastColors, hoverable, iconKey, iconSource, imageSource, inheritedPropertyFlags, inheritedPropertyNames, initializeWebGPU, inputsEqual, insetPadding, insetsEqual, interactive, interpolateColor, interpolateNumber, interpolateTransform, interpolatorFor, isAutoLength, isComponentLikeElement, isEditableNode, isFrLength, isImeKey, isLayoutProtocol, isMinMaxTrack, isMotionRest, isMultiline, isNodeFocusable, isNodeHitTestable, isNodeInert, isNodeSelectable, isNodeTabStop, isObservable, isPaintVisible, isPercentLength, isPrintable, isReadOnly, isScrollContainer, isShapeName, isSubtreeInert, isTypographyRole, isUiChild, isUiElement, isUiModifier, isUiRole, isUiSemanticState, isVideoSurface, isWebGPUAvailable, labelNode, labelOrigin, layoutParagraph, layoutTextLines, lazySource, lightColors, lightTheme, lineEndAt, lineIndexAtY, lineIndexForOffset, lineLimit, lineStartAt, linear, linearGradient, linkHoverOf, linkOf, linkRunAtPointIn, markInstant, markNow, matchRangesOf, measure, measureFlow, measureSpan, minmax, motion, nextCaretToggle, nextGraphemeEnd, nextWordEnd, noInsets, noKeyModifiers, noModifiers, noThemeExtensions, normalizeBorderRadius, normalizeColor, normalizeStates, normalizeTextAlign, normalizeTransition, normalizeVerticalAlign, observeViewportInsets, offsetAtPoint, offsetAtPointIn, offsetAtX, offsetForVerticalMove, overrideSources, paintPictures, paintValuesEqual, paintsAfterChildren, paragraphGeometry, paragraphGeometryFrom, parseAlignContent, parseColor, parseCrossAxisAlignment, parseFlexDirection, parseMainAxisAlignment, parseShortcut, parseTransform, parseWebVtt, pathValuesEqual, percent, performanceMarksEnabled, pinchable, placeGridItems, pointerDeviceOf, pointerEventsOf, pop, prepareInputSurface, pressable, previousGraphemeStart, previousWordStart, propertyEffects, propertyIsInherited, propertyNarrowers, propertyValuesEqual, propertyValuesEqualByName, proportionalFontMetrics, provideEnvironment, publishInset, radialGradient, raiseContrast, rangeSource, readMp3Header, recordsEqual, registerFontStack, relativeLuminance, reorderable, repeat, replayPaint, resetOverrideWarnings, resetTransitionWarnings, resolveBoolean, resolveCursor, resolveLength, resolveMotionState, resolveNumber, resolvePaintState, resolveProperty, resolvePropertyByName, resolveString, resolvedSpansOf, rewalkSemantics, rgb8, rgba, rotateFrom, runCanvasStyleInto, runFontString, sameArgs, scaleFrom, scaleSpacing, scrollBounds, scrollLeaderOf, scrollPosition, scrollRange, scrollbarThumb, scrollbarThumbs, scrollbarZoneAt, scrollsFromRight, selectableTextNodes, selectableTextOf, selectionRangeOf, selectionRects, selectionRectsIn, semanticsInertAbove, semanticsMemory, setLinkHover, setMatchRanges, setPerformanceMarks, setSelectionRange, shadowsEqual, shapesEqual, sharedElement, sheetSource, shortcut, shortcutKeyCaps, shortcuts, sizeContainer, sizeGridTracks, slideDown, slideFrom, slideUp, spacingEqual, spacingSteps, spanAtOffset, spannedRunsFor, spannedTextOf, spansDifferOnlyInPaint, splitMp3Frames, spring, statesEqual, steps, syncEditorValue, textContentOf, textInputOf, textRunBackgrounds, textRunDecorations, textRunOfRecordId, textRuns, textSpansEqual, textStylesEqual, themeExtension, themeExtensionsEqual, themeTokens, themesEqual, tightenConstraints, touchActionFor, tracePathData, traceRoundedRect, transform, transformIsIdentity, transformsEqual, tween, typographyEqual, uniformBorderRadius, unknownContainerSize, validateGradient, validateRole, validateStates, validateSubgrid, videoFrameSize, videoSource, visualState, visualStatesEqual, wheelDeltaYOf, withContrast, withDensity, withOverrideSource, withThemeExtension, wordRangeAt, wordRangeIn, writeDeclaredProperty, writeOverrideProperty };
17601
+ export { AlignContent, AnimationDriver, BOX_SHADOW_BLUR_REACH, BUTTON_INTERACTION, Box, Button, CARET_BLINK_MS, CARET_WIDTH, CLIP_STRIDE_BYTES, CLIP_STRIDE_FLOATS, Canvas2DRenderer, CanvasPlatformSurface, CanvasSurface, CanvasTextMeasurer, CharacterCountTextMeasurer, Column, CommandKind, Constraints, CrossAxisAlignment, DEFAULT_BLOCK_SIZE, DEFAULT_FONT_FAMILY, DEFAULT_FONT_SIZE, DEFAULT_FONT_WEIGHT, DEFAULT_LINE_HEIGHT_FACTOR, DEFAULT_TEXT_COLOR, DefaultImageResolver, DefaultSvgResolver, DefaultVideoResolver, DirtyFlags, DirtyNodeSet, EDITOR_PROP, ELLIPSIS, EMPTY_RECORDING, EXTERNAL_FILES, EditableLayout, EditableText, EditableTextModel, EnvironmentNotifier, FlexDirection, FocusNotifier, GLYPH_SUBPIXEL_PHASES, GlyphShaper, Grid, INSPECTOR_HEAT_MS, INSTANCE_STRIDE_BYTES, INSTANCE_STRIDE_FLOATS, IconRasterizer, LABEL_PADDING_X, LayoutEngine, LayoutInspector, LayoutNotifier, LayoutRecord, LazyColumn, LazyGrid, LazyRow, LazySheet, MARK_PREFIX, MAX_GRADIENT_STOPS, MAX_MEASURES_PER_CHILD, MOTION_CHANNELS, MOTION_REST, MOUSE_POINTER, MainAxisAlignment, Mp3Frames, NO_CLIP_INDEX, NodeTransitions, Paint, PaintPictureCache, PaintRecorder, PaintTarget, ParagraphTextMeasurer, PrimitiveKind, Responsive, Row, SCROLLBAR_FADE_MS, SCROLLBAR_HOVER_ZONE, SCROLLBAR_INSET, SCROLLBAR_LINGER_MS, SCROLLBAR_MIN_THUMB, SCROLLBAR_THICKNESS, ScrollView, Stack, TEXTURED_STRIDE_BYTES, TEXTURED_STRIDE_FLOATS, TEXT_MATCHES_PROP, TEXT_RUN_ID_SEPARATOR, TEXT_SELECTION_PROP, TOUCH_TARGET, Text, UI_ROLES, UI_SEMANTIC_STATES, UI_SUBGRID_AXES, UiAnimation, UiAnimationFrameClock, UiBasicColors, UiBeforeInputEvent, UiBinding, UiBorderRadiuses, UiChildrenBinding, UiCompositionEvent, UiContainerSizeSource, UiDragSession, UiEditingController, UiEnvironment, UiEnvironmentKeys, UiEventBinding, UiEventType, UiFindController, UiFocusEvent, UiFocusManager, UiFrame, UiGestureEvent, UiGestureRecognizer, UiGraph, UiGraphBuilder, UiHitTester, UiHostFrameClock, UiInputDispatcher, UiInputEvent, UiInsetRegistry, UiKeyboardController, UiKeyboardEvent, UiManualFrameClock, UiModifierSet, UiNode, UiNodeType, UiPasteEvent, UiPinchEvent, UiPinchRecognizer, UiPlatformAdapter, UiPointerController, UiPointerEvent, UiProperties, UiScheduler, UiSelectionChangeEvent, UiSelectionController, UiSharedElements, UiShortcutRegistry, UiSpring, UiTextChangeEvent, UiTimerFrameClock, UiTouchScroller, UiTransforms, UiTween, UiUnknownModifierPropertyError, UiVirtualSheet, UiVirtualWindow, UiVisualState, UiWheelController, UiWheelDeltaMode, UiWheelEvent, VIRTUAL_INDEX_PROP, VIRTUAL_LEAD_PROP, VIRTUAL_SHEET_PROP, VIRTUAL_WINDOW_PROP, WebGPUError, WebGPUGlyphAtlas, WebGPUGlyphPages, WebGPURenderer, WebGPUSurface, WebGPUTextureCache, accumulatedOffsetTo, adjacentField, animateLayout, applyCanvasTextStyle, assertModifierList, assertTransitionMap, auto, autoFocus, bandOf, borderRadius, borderRadiusCorners, borderRadiusEqual, borderRadiusIsZero, borderRadiusValuesEqual, borderShapes, borders, boxShadow, boxShadowArraysEqual, boxShadowRadius, boxShadowReach, boxShadowValuesEqual, boxShadowsEqual, breakpoint, bufferSource, buildFontString, buildRenderList, buildSemanticsSubtree, buildSemanticsTree, bumpFontStack, bundle, canDecodeVideo, capturePointer, caretRectFor, caretVisibleAt, clampSize, clearFontStacks, clearLinkHover, clearMatchRanges, clearOverrideProperty, clearSelectionRange, clickOutside, closestPropertyName, colorToCss, colorToHex, colorToRgba, colorValuesEqual, colorsEqual, colorsEqualPalette, commandForKey, comparePositions, computeObjectFitRect, constraintsEqual, containerBands, contentOffset, contextMenu, contrastRatio, createCanvasSurface, createCanvasTextStyle, createElement, createEnvironmentKey, createPaintState, createTextCache, createTween, createWebGPUSurface, cubicBezier, cueAt, darkColors, darkTheme, decorated, decorationColor, decorationRect, defaultMotion, defaultShadows, defaultShapes, defaultSpacing, defaultTextStyle, defaultTypography, defaultUnits, defaultVisualState, defineModifier, defineProperty, defineThemeExtension, demuxMp4Audio, demuxMp4Video, densityFactors, describeLength, describeOverrides, describeShortcut, detectEditingPlatform, diffSemantics, dragSessionFor, dragSource, draggable, drawOverlayShapes, drawSvg, drawText, dropIndexShifts, dropTarget, easings, edgeField, editableSpansOf, editingGroupOf, editorFor, editorOf, fade, fillTextRects, findEnvironmentKey, findMatchesIn, findPropertyDefinition, flattenTextSpans, focusRing, fontStackFor, formatConstraints, formatExplanation, formatShortcut, fr, getPropertyNames, glyphCount, gradientPaint, gradientsEqual, graphemeBoundaries, hasDecorationPhase, hasDrawnText, hasTextLinks, hasThemeExtension, hasVisualState, hiddenRangesOf, highContrastColors, hoverable, iconKey, iconSource, imageSource, inheritedPropertyFlags, inheritedPropertyNames, initializeWebGPU, inputsEqual, insetPadding, insetsEqual, interactive, interpolateColor, interpolateNumber, interpolateTransform, interpolatorFor, isAutoLength, isComponentLikeElement, isEditableNode, isFrLength, isImeKey, isLayoutProtocol, isMinMaxTrack, isMotionRest, isMultiline, isNodeFocusable, isNodeHitTestable, isNodeInert, isNodeSelectable, isNodeTabStop, isObservable, isPaintVisible, isPercentLength, isPrintable, isReadOnly, isScrollContainer, isShapeName, isSubtreeInert, isSvgSource, isTypographyRole, isUiChild, isUiElement, isUiModifier, isUiRole, isUiSemanticState, isVideoSurface, isWebGPUAvailable, labelNode, labelOrigin, layoutParagraph, layoutTextLines, lazySource, lengths, lightColors, lightTheme, lineEndAt, lineIndexAtY, lineIndexForOffset, lineLimit, lineStartAt, linear, linearGradient, linkHoverOf, linkOf, linkRunAtPointIn, markInstant, markNow, matchRangesOf, measure, measureFlow, measureSpan, mediaLoadsInFlight, minmax, motion, nextCaretToggle, nextGraphemeEnd, nextWordEnd, noInsets, noKeyModifiers, noModifiers, noThemeExtensions, normalizeBorderRadius, normalizeColor, normalizeStates, normalizeTextAlign, normalizeTransition, normalizeVerticalAlign, observeViewportInsets, offsetAtPoint, offsetAtPointIn, offsetAtX, offsetForVerticalMove, overrideSources, paintPictures, paintValuesEqual, paintsAfterChildren, paragraphGeometry, paragraphGeometryFrom, parseAlignContent, parseColor, parseCrossAxisAlignment, parseFlexDirection, parseMainAxisAlignment, parseShortcut, parseSvg, parseTransform, parseWebVtt, pathValuesEqual, percent, performanceMarksEnabled, pinchable, placeGridItems, pointerDeviceOf, pointerEventsOf, pop, prepareInputSurface, pressable, previousGraphemeStart, previousWordStart, propertyEffects, propertyIsInherited, propertyNarrowers, propertyValuesEqual, propertyValuesEqualByName, proportionalFontMetrics, provideEnvironment, publishInset, radialGradient, raiseContrast, rangeSource, readMp3Header, recordsEqual, registerFontStack, relativeLuminance, reorderable, repeat, replayPaint, resetOverrideWarnings, resetTransitionWarnings, resolveBoolean, resolveCursor, resolveLength, resolveMotionState, resolveNumber, resolvePaintState, resolveProperty, resolvePropertyByName, resolveString, resolvedSpansOf, rewalkSemantics, rgb8, rgba, rotateFrom, runCanvasStyleInto, runFontString, sameArgs, scaleFrom, scaleSpacing, scrollBounds, scrollLeaderOf, scrollPosition, scrollRange, scrollbarThumb, scrollbarThumbs, scrollbarZoneAt, scrollsFromRight, selectableTextNodes, selectableTextOf, selectionRangeOf, selectionRects, selectionRectsIn, semanticsInertAbove, semanticsMemory, setLinkHover, setMatchRanges, setPerformanceMarks, setSelectionRange, shadowsEqual, shadowsOf, shapesEqual, sharedElement, sheetSource, shortcut, shortcutKeyCaps, shortcuts, sizeContainer, sizeGridTracks, slideDown, slideFrom, slideUp, spacingEqual, spacingSteps, spanAtOffset, spannedRunsFor, spannedTextOf, spansDifferOnlyInPaint, splitMp3Frames, spring, statesEqual, steps, svgPaint, syncEditorValue, textContentOf, textInputOf, textRunBackgrounds, textRunDecorations, textRunOfRecordId, textRuns, textSpansEqual, textStylesEqual, themeExtension, themeExtensionsEqual, themeTokens, themesEqual, tightenConstraints, touchActionFor, tracePathData, traceRoundedRect, transform, transformIsIdentity, transformsEqual, tween, typographyEqual, uniformBorderRadius, unitsEqual, unknownContainerSize, validateGradient, validateRole, validateStates, validateSubgrid, videoFrameSize, videoSource, visualState, visualStatesEqual, wheelDeltaYOf, withContrast, withDensity, withOverrideSource, withPointer, withThemeExtension, wordRangeAt, wordRangeIn, writeDeclaredProperty, writeOverrideProperty };
16118
17602
 
16119
17603
  //# sourceMappingURL=index.js.map