gesso-core 0.2.0 → 0.3.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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CanvasSurface-ifHkg0-g.js","names":["editDistance","textStyle","defaultClock"],"sources":["../src/bindings/UiBinding.ts","../src/graph/DirtyFlags.ts","../src/graph/UiNodeType.ts","../src/input/UiInputEvent.ts","../src/properties/UiVisualState.ts","../src/graph/UiPropertyOverrides.ts","../src/graph/DirtyNodeSet.ts","../src/graph/UiNode.ts","../src/environment/UiEnvironment.ts","../src/environment/UiEnvironmentKey.ts","../src/properties/UiColor.ts","../src/environment/UiColors.ts","../src/properties/UiTextStyle.ts","../src/environment/UiTypography.ts","../src/environment/UiShapes.ts","../src/properties/UiBoxShadow.ts","../src/environment/UiShadows.ts","../src/environment/UiSpacing.ts","../src/environment/UiDensity.ts","../src/environment/UiContrast.ts","../src/environment/UiThemeExtension.ts","../src/environment/UiTheme.ts","../src/environment/UiContainerSize.ts","../src/environment/UiInsets.ts","../src/environment/UiEnvironmentKeys.ts","../src/properties/UiPropertyDefinition.ts","../src/properties/UiBorderRadius.ts","../src/layout/UiLength.ts","../src/properties/UiGradient.ts","../src/properties/UiTransform.ts","../src/rendering/PaintSurface.ts","../src/properties/UiPropertyValues.ts","../src/properties/UiSemantics.ts","../src/properties/UiProperty.ts","../src/properties/UiPropertyRegistry.ts","../src/graph/UiGraph.ts","../src/properties/UiPropertyResolver.ts","../src/editing/TextBoundaries.ts","../src/editing/EditableTextModel.ts","../src/editing/TextGeometry.ts","../src/properties/UiThemeShape.ts","../src/properties/UiVideo.ts","../src/properties/UiThemeColor.ts","../src/editing/UiEditable.ts","../src/selection/UiTextLinks.ts","../src/input/UiInteraction.ts","../src/selection/UiSelectable.ts","../src/find/UiTextMatches.ts","../src/properties/UiTextFont.ts","../src/rendering/PaintState.ts","../src/rendering/FontStacks.ts","../src/rendering/TextRenderer.ts","../src/editing/EditableLayout.ts","../src/editing/EditingKeymap.ts","../src/layout/LineBreaks.ts","../src/layout/ParagraphLayout.ts","../src/layout/TextMeasurer.ts","../src/selection/TextSelectionGeometry.ts","../src/input/UiInputDispatcher.ts","../src/layout/Scrollbars.ts","../src/input/UiHitTester.ts","../src/input/UiFocusManager.ts","../src/input/UiPointerController.ts","../src/input/UiKeyboardController.ts","../src/input/UiWheelController.ts","../src/input/UiPinchRecognizer.ts","../src/input/UiGestureRecognizer.ts","../src/input/UiTouchScroller.ts","../src/input/UiEditingController.ts","../src/input/UiPlatformAdapter.ts","../src/layout/Alignment.ts","../src/layout/GridLayout.ts","../src/layout/FlexDirection.ts","../src/layout/CustomLayout.ts","../src/layout/LayoutTypes.ts","../src/layout/LayoutRecord.ts","../src/layout/SubtreeBounds.ts","../src/layout/LayoutTransform.ts","../src/layout/LayoutExplanation.ts","../src/layout/LayoutEngine.ts","../src/rendering/OverlayShapes.ts","../src/rendering/Decorations.ts","../src/rendering/ScaledImageCache.ts","../src/rendering/PaintPathData.ts","../src/rendering/PaintRecording.ts","../src/rendering/PaintTarget.ts","../src/rendering/PaintPicture.ts","../src/rendering/canvas2d/Canvas2DRenderer.ts","../src/rendering/canvas2d/CanvasSurface.ts"],"sourcesContent":["import { Observable, Subscription } from 'rxjs';\nimport type { DirtyFlags } from '../graph/DirtyFlags';\nimport type { NodeId, NodeProperty, UiNode } from '../graph/UiNode';\nimport type { UiGraph } from '../graph/UiGraph';\n\nexport type BindingId = number;\n\nexport class UiBinding<T> {\n constructor(\n public readonly id: BindingId,\n public readonly node: UiNode,\n public readonly property: NodeProperty,\n public readonly observable: Observable<T>,\n private readonly graph: UiGraph,\n private readonly dirtyFlags: DirtyFlags\n ) {}\n\n /**\n * The bound node's id.\n *\n * The binding holds the node itself so that an emission writes the\n * property without going back through the graph's id index — that\n * index is keyed by a concatenated path, and this runs on every\n * value a bound observable produces.\n */\n get nodeId(): NodeId {\n return this.node.id;\n }\n\n private subscription: Subscription | null = null;\n\n private currentValue!: T;\n\n /**\n * How many values the source has produced since this binding\n * connected, and when the last one arrived.\n *\n * Kept unconditionally rather than behind a devtools switch, because\n * the question they answer — \"is this prop bound, to what, and is it\n * still emitting\" — is asked *after* something has already gone\n * wrong, and a counter that only starts when the panel opens would\n * answer it about a different run. The cost is an increment and one\n * `performance.now()` per emission, against a write that already\n * walks the override cascade and marks a node dirty.\n *\n * `emittedAt` is on the emitting thread's clock, which is why the\n * node report sends an age rather than the reading itself: a panel\n * on another thread cannot subtract it from its own.\n */\n private emissions = 0;\n private lastEmittedAt = 0;\n\n /**\n * Start listening to the Observable.\n */\n connect(): void {\n if (this.subscription !== null) {\n throw new Error(`Binding ${this.id} is already connected.`);\n }\n this.subscription = this.observable.subscribe({\n next: value => {\n this.currentValue = value;\n this.emissions++;\n this.lastEmittedAt = now();\n this.graph.updateNodeProperty(this.node, this.property, value, this.dirtyFlags);\n },\n error: error => {\n this.graph.handleBindingError(this, error);\n this.disconnect();\n }\n });\n }\n\n /**\n * Stop listening to the Observable.\n */\n disconnect(): void {\n this.subscription?.unsubscribe();\n this.subscription = null;\n }\n\n /**\n * Whether this binding is currently subscribed.\n */\n connected(): boolean {\n return this.subscription !== null;\n }\n\n /**\n * Most recently emitted value.\n */\n value(): T {\n return this.currentValue;\n }\n\n /** How many values the source has produced since `connect`. */\n emissionCount(): number {\n return this.emissions;\n }\n\n /**\n * When the last value arrived, on the clock of the thread that owns\n * the graph, or null before the first one.\n */\n emittedAt(): number | null {\n return this.emissions === 0 ? null : this.lastEmittedAt;\n }\n}\n\nfunction now(): number {\n return typeof performance === 'undefined' ? Date.now() : performance.now();\n}\n","export enum DirtyFlags {\n None = 0,\n Content = 1 << 0,\n Paint = 1 << 1,\n Layout = 1 << 2,\n SubtreeLayout = 1 << 3,\n Children = 1 << 4,\n Transform = 1 << 5,\n Properties = 1 << 6,\n Environment = 1 << 7,\n Semantics = 1 << 8\n}\n","export enum UiNodeType {\n Root = 'root',\n Column = 'column',\n Row = 'row',\n Box = 'box',\n Text = 'text',\n /** Text the user types into; see `UiEditable`. */\n EditableText = 'editable-text',\n Button = 'button',\n /**\n * A node an application draws itself, through `paint` or `path`.\n * A leaf with a box, like `Box`; see `rendering/PaintSurface.ts`.\n */\n Paint = 'paint',\n ScrollView = 'scroll-view',\n Grid = 'grid',\n Fragment = 'fragment'\n}\n","import type { UiNode } from '../graph/UiNode';\n\n/**\n * Framework-level input event types.\n *\n * These deliberately are NOT browser event types: browser events\n * are converted by the platform adapter, and only these reach\n * application code. Gesture events (click/longPress/drag/pan) are\n * synthesized by the gesture layer and flow through the same\n * dispatcher as raw input, so there is exactly one event model.\n */\nexport enum UiEventType {\n PointerDown = 'pointerdown',\n PointerUp = 'pointerup',\n PointerMove = 'pointermove',\n PointerCancel = 'pointercancel',\n PointerEnter = 'pointerenter',\n PointerLeave = 'pointerleave',\n Wheel = 'wheel',\n KeyDown = 'keydown',\n KeyUp = 'keyup',\n Focus = 'focus',\n Blur = 'blur',\n /** An edit is about to be applied to an editable; preventDefault() drops it. */\n BeforeInput = 'beforeinput',\n /** An editable's text changed. */\n Input = 'input',\n /**\n * An editable's selection moved, whether or not its text changed.\n *\n * Separate from `Input` because the caret moves without the text on\n * every arrow key, every click into the text and every\n * select-all — and something has to be able to follow it. A formula\n * editor that colours the bracket beside the caret has no other way\n * to know it moved.\n *\n * Fires *after* `Input` when a change did both, so a listener that\n * reads the text sees the new one. It is skipped entirely when the\n * selection did not actually move, so holding a key that is already\n * at the end of the text is silent.\n */\n SelectionChange = 'selectionchange',\n /**\n * Text arrived from the system clipboard with nothing editable\n * focused.\n *\n * A paste with a caret in it belongs to the text and never reaches\n * here. This is the other case: a surface that owns a selection of\n * its own — a grid with a rectangle of cells picked out — and is the\n * only thing that knows what a block of text means to it.\n * `preventDefault()` says it was taken.\n */\n Paste = 'paste',\n Click = 'click',\n LongPress = 'longpress',\n DragStart = 'dragstart',\n DragMove = 'dragmove',\n DragEnd = 'dragend',\n PanStart = 'panstart',\n PanMove = 'panmove',\n PanEnd = 'panend',\n /**\n * A request for the commands that apply to something: the secondary\n * mouse button, or a finger held on it.\n *\n * A gesture like any other, so the component that shows the menu\n * listens for an event rather than reaching for a browser API it\n * cannot see from a worker.\n */\n ContextMenu = 'contextmenu',\n PinchStart = 'pinchstart',\n PinchMove = 'pinchmove',\n PinchEnd = 'pinchend'\n}\n\n/**\n * Keyboard modifier state attached to events that carry one.\n *\n * Named `UiKeyModifiers`, not `UiModifiers`: a modifier in\n * A modifier is a behaviour attached to an element, and one\n * word meaning two things in one package is a permanent tax.\n */\nexport interface UiKeyModifiers {\n ctrl: boolean;\n shift: boolean;\n alt: boolean;\n meta: boolean;\n}\n\nexport function noKeyModifiers(): UiKeyModifiers {\n return { ctrl: false, shift: false, alt: false, meta: false };\n}\n\n/**\n * What is touching the surface, mirroring the DOM's `pointerType`.\n *\n * The runtime needs this because a finger is not a small mouse. It\n * has no hover to leave behind, it covers the point it is aiming at,\n * and it cannot land on a six-pixel scrollbar. Every one of those is\n * a behaviour decision the framework has to take on its own, and\n * `'touch'` is the only evidence it gets.\n */\nexport type UiPointerKind = 'mouse' | 'pen' | 'touch';\n\n/**\n * The device behind a pointer event.\n *\n * `id` is the DOM's `pointerId`: it separates simultaneous contacts,\n * so a second finger landing mid-press can be told from the first one\n * moving. The pointer controller is single-press and uses it to\n * *ignore* the second finger; a pinch recognizer would use it to\n * follow both.\n */\nexport interface UiPointerDevice {\n readonly id: number;\n readonly kind: UiPointerKind;\n}\n\n/**\n * The device assumed when a caller names none.\n *\n * A mouse, deliberately: every touch-specific behaviour is opt-in on\n * `kind === 'touch'`, so a shell, a test or an app that predates this\n * field keeps exactly the behaviour it had. The id matches what\n * browsers give a mouse, and the object is frozen because it is\n * shared by every event that does not name a device.\n */\nexport const MOUSE_POINTER: UiPointerDevice = Object.freeze({ id: 1, kind: 'mouse' as const });\n\n/**\n * Base class for every framework input event.\n *\n * Instances are small, flat and reused across the whole runtime.\n * `target` is the node the event was routed to; `currentTarget` is\n * the node currently processing it during dispatch. Both are set by\n * the dispatcher.\n *\n * Cancellation semantics (canvas-specific, documented):\n * stopPropagation() — stop the event travelling further.\n * stopImmediatePropagation() — stop further listeners AND travel.\n * preventDefault() — advisory flag that cancels the\n * framework-level default behaviour for the event kind:\n * pointerdown → no click synthesis, no focus-on-press\n * pointermove → no drag/pan gesture interpretation\n * wheel → no automatic scroll consumption\n * keydown Tab → no tab navigation\n * It never mirrors browser preventDefault exactly; each consumer\n * defines what \"the default\" is.\n */\nexport class UiInputEvent {\n readonly type: UiEventType;\n\n target: UiNode | null = null;\n currentTarget: UiNode | null = null;\n\n private propagationStoppedFlag = false;\n private immediateStoppedFlag = false;\n private defaultPreventedFlag = false;\n\n constructor(type: UiEventType) {\n this.type = type;\n }\n\n stopPropagation(): void {\n this.propagationStoppedFlag = true;\n }\n\n stopImmediatePropagation(): void {\n this.propagationStoppedFlag = true;\n this.immediateStoppedFlag = true;\n }\n\n preventDefault(): void {\n this.defaultPreventedFlag = true;\n }\n\n get defaultPrevented(): boolean {\n return this.defaultPreventedFlag;\n }\n\n get propagationStopped(): boolean {\n return this.propagationStoppedFlag;\n }\n\n get immediateStopped(): boolean {\n return this.immediateStoppedFlag;\n }\n\n /** Resets the mutable flags so pooled instances can be reused. */\n reset(): void {\n this.target = null;\n this.currentTarget = null;\n this.propagationStoppedFlag = false;\n this.immediateStoppedFlag = false;\n this.defaultPreventedFlag = false;\n }\n}\n\n/**\n * Focus/blur transition event.\n *\n * Focus transitions are target-only (they do not bubble), mirroring\n * DOM focus/blur rather than focusin/focusout. `relatedNode` is the\n * node the focus is moving to (for Blur) or away from (for Focus).\n */\nexport class UiFocusEvent extends UiInputEvent {\n readonly relatedNode: UiNode | null;\n\n constructor(type: UiEventType.Focus | UiEventType.Blur, relatedNode: UiNode | null) {\n super(type);\n this.relatedNode = relatedNode;\n }\n}\n\n/**\n * Pointer input event.\n *\n * Carries the canvas-space position (`x`/`y`), the pressed-button\n * bitmask, the keyboard modifiers present when the event was produced\n * and the device that produced it. Used for every raw Pointer* event\n * and for the Click gesture, so listeners never need a\n * browser-specific event shape.\n */\nexport class UiPointerEvent extends UiInputEvent {\n constructor(\n type: UiEventType,\n readonly x: number,\n readonly y: number,\n readonly buttons: number = 0,\n readonly modifiers: UiKeyModifiers = noKeyModifiers(),\n /**\n * The device that produced the event, for a listener that has to\n * treat a finger differently — sizing its own hit target, or\n * skipping a hover affordance nothing will ever hover.\n */\n readonly pointer: UiPointerDevice = MOUSE_POINTER\n ) {\n super(type);\n }\n}\n\n/**\n * A synthesized single-contact gesture, with the speed it ended at.\n *\n * Every Pan and Drag event is one of these, so a listener never has to\n * ask which kind of pointer event it was handed. The velocity is zero\n * everywhere except on `PanEnd` and `DragEnd`, where it is the speed\n * the contact was travelling at when it left the surface, measured\n * over the last moments of the gesture rather than over the whole of\n * it: a long slow drag that ends in a flick averages out to nothing.\n *\n * **Pixels per second**, which is what `UiSpringOptions.velocity` is\n * in. That is the whole point of carrying it: a card thrown across the\n * screen and released should go on travelling at the speed it was\n * thrown, and a spring handed a velocity of zero stops dead under the\n * finger instead. `UiTouchScroller` measures in pixels per millisecond\n * for its own projection and is not this; the unit is named here so\n * the two are never confused.\n */\nexport class UiGestureEvent extends UiPointerEvent {\n constructor(\n type: UiEventType,\n x: number,\n y: number,\n buttons: number = 0,\n modifiers: UiKeyModifiers = noKeyModifiers(),\n pointer: UiPointerDevice = MOUSE_POINTER,\n readonly velocityX: number = 0,\n readonly velocityY: number = 0\n ) {\n super(type, x, y, buttons, modifiers, pointer);\n }\n}\n\n/**\n * Two contacts moving relative to each other.\n *\n * `scale` and `rotation` are cumulative from the moment the second\n * contact landed, so a listener that writes them straight onto a\n * transform gets the gesture rather than a difference it has to\n * integrate itself; the `*Delta` pair is the change since the previous\n * event, for a listener that is integrating something of its own.\n * `x`/`y` are the midpoint between the contacts, which is the point a\n * zoom should hold still, and `translateX`/`translateY` are how far\n * that midpoint moved since the previous event, so a two-finger pan\n * and a pinch are one gesture rather than two that fight.\n *\n * Rotation is in degrees, matching the `rotation` field of the\n * transform property, so neither end of the handoff converts.\n */\nexport class UiPinchEvent extends UiInputEvent {\n constructor(\n type: UiEventType.PinchStart | UiEventType.PinchMove | UiEventType.PinchEnd,\n readonly x: number,\n readonly y: number,\n readonly scale: number,\n readonly rotation: number,\n readonly scaleDelta: number,\n readonly rotationDelta: number,\n readonly translateX: number,\n readonly translateY: number,\n readonly modifiers: UiKeyModifiers = noKeyModifiers()\n ) {\n super(type);\n }\n}\n\n/**\n * Keyboard input event.\n *\n * `key` is a logical key name (\"Enter\", \"Tab\", \"ArrowUp\", \"a\", ...)\n * produced by the platform adapter, so listeners never see\n * browser-specific key values.\n */\nexport class UiKeyboardEvent extends UiInputEvent {\n constructor(\n type: UiEventType.KeyDown | UiEventType.KeyUp,\n readonly key: string,\n readonly modifiers: UiKeyModifiers = noKeyModifiers()\n ) {\n super(type);\n }\n}\n\n/**\n * An edit about to reach an editable node's text.\n *\n * `inputType` follows the DOM Input Events vocabulary\n * (`insertText`, `insertLineBreak`, `insertFromPaste`,\n * `deleteContentBackward`, `deleteWordForward`, …) whether the edit\n * came from a shell's `beforeinput`, a key the runtime resolved itself,\n * or a paste. `data` is the text an insertion carries, else null.\n * preventDefault() cancels the edit — the way a numeric field rejects\n * letters.\n */\nexport class UiBeforeInputEvent extends UiInputEvent {\n constructor(\n readonly inputType: string,\n readonly data: string | null\n ) {\n super(UiEventType.BeforeInput);\n }\n}\n\n/**\n * An editable node's text changed: the new value and the selection\n * after the change. Bubbles, so a form can watch all its fields.\n */\n/**\n * Text from the system clipboard, offered to whatever holds focus.\n *\n * Carries the text rather than a clipboard handle, because a render\n * worker has neither a clipboard nor a window: the shell reads it and\n * sends it across, which is the same path `ShellService.copyText`\n * takes in the other direction.\n */\nexport class UiPasteEvent extends UiInputEvent {\n constructor(readonly text: string) {\n super(UiEventType.Paste);\n }\n}\n\nexport class UiTextChangeEvent extends UiInputEvent {\n constructor(\n readonly value: string,\n readonly selectionStart: number,\n readonly selectionEnd: number\n ) {\n super(UiEventType.Input);\n }\n}\n\n/**\n * An editable's selection moved.\n *\n * Carries the text as well as the offsets, because every use of this\n * is \"what is under the caret\" and the answer needs both — and\n * reading the text back off the model afterwards is a second source\n * of truth that can disagree by a frame.\n *\n * `start` and `end` are ordered; `anchor` and `focus` are where the\n * selection was begun and where the caret now is, which is the pair\n * that says which way it was dragged.\n */\nexport class UiSelectionChangeEvent extends UiInputEvent {\n constructor(\n readonly value: string,\n readonly start: number,\n readonly end: number,\n readonly anchor: number,\n readonly focus: number\n ) {\n super(UiEventType.SelectionChange);\n }\n\n get collapsed(): boolean {\n return this.start === this.end;\n }\n}\n\n/**\n * Wheel scroll input event.\n *\n * `deltaX`/`deltaY` are the scroll deltas in canvas pixels produced\n * by the platform adapter (browser wheel events are normalized\n * there). preventDefault() on a Wheel cancels the automatic scroll\n * consumption of the nearest scroll container.\n */\n/**\n * The unit a wheel's deltas are in, matching the DOM's `deltaMode`.\n *\n * The numbers are the DOM's own, so a shell can forward\n * `event.deltaMode` unchanged and nothing has to translate.\n */\nexport enum UiWheelDeltaMode {\n Pixel = 0,\n Line = 1,\n Page = 2\n}\n\n/**\n * Reads the legacy `wheelDeltaY` off a DOM wheel event.\n *\n * Not on `WheelEvent` in TypeScript's lib, because it was never\n * standardised — but every engine still reports it, and it is the only\n * field that distinguishes a detented wheel (multiples of 120) from a\n * precision device. Read defensively rather than cast, so an engine\n * that has genuinely dropped it reports nothing instead of `NaN`.\n */\nexport function wheelDeltaYOf(event: object): number | undefined {\n const value = (event as { wheelDeltaY?: unknown }).wheelDeltaY;\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined;\n}\n\nexport class UiWheelEvent extends UiInputEvent {\n private consumedFlag = false;\n\n constructor(\n type: UiEventType.Wheel,\n readonly x: number,\n readonly y: number,\n readonly deltaX: number,\n readonly deltaY: number,\n readonly modifiers: UiKeyModifiers = noKeyModifiers(),\n /**\n * What the deltas are measured in.\n *\n * Mirrors the DOM, deliberately: `deltaX`/`deltaY` are a distance\n * in pixels only when this is `Pixel`, and a handler that reads\n * them without checking is the bug this field was added to fix.\n * Chrome reports pixels and Firefox reports lines, so a delta\n * taken at face value moves the view three pixels per notch there.\n * The wheel controller converts before it scrolls anything; an\n * application handler that consumes the delta itself has to do the\n * same.\n */\n readonly deltaMode: UiWheelDeltaMode = UiWheelDeltaMode.Pixel,\n /**\n * The legacy `wheelDeltaY`, forwarded for one reason: a detented\n * wheel reports it in multiples of 120 and a precision device does\n * not, and there is no other evidence in a `WheelEvent` that tells\n * the two apart. See `isNotchedWheel`.\n */\n readonly wheelDeltaY?: number\n ) {\n super(type);\n }\n\n /**\n * Records that the runtime moved something with this delta.\n *\n * Called by the wheel controller, not by application code — an app\n * handler that takes a wheel for itself says so with\n * `preventDefault()`, and a shell treats the two the same.\n */\n markConsumed(): void {\n this.consumedFlag = true;\n }\n\n /**\n * Whether the runtime actually scrolled something.\n *\n * This is the answer a shell needs and the DOM cannot work out for\n * itself: whether to call `preventDefault()` on the browser's wheel\n * event. Preventing unconditionally makes the canvas a scroll trap\n * on a page it is embedded in — the wheel dies over a canvas with\n * nothing to scroll — and never preventing lets a scroll the\n * runtime already consumed move the page as well. Neither is\n * knowable without asking whether a container took the delta, which\n * is what this reports.\n *\n * False at the end of a chain that found no room, unless something\n * along it asked to keep the overscroll with\n * `overscrollBehavior=\"contain\"`.\n */\n get consumed(): boolean {\n return this.consumedFlag;\n }\n\n override reset(): void {\n super.reset();\n this.consumedFlag = false;\n }\n}\n","/**\n * A small, explicit set of interactive visual states.\n *\n * This is intentionally not a CSS pseudo-class system. Components\n * can resolve properties against the current state set, and the\n * reactive pipeline can drive state changes through Observables.\n */\nexport enum UiVisualState {\n Normal = 'normal',\n Hovered = 'hovered',\n Pressed = 'pressed',\n Focused = 'focused',\n Disabled = 'disabled',\n Selected = 'selected',\n Dragged = 'dragged'\n}\n\n/**\n * A set of active visual states.\n */\nexport type UiVisualStateSet = ReadonlySet<UiVisualState>;\n\n/**\n * Creates a state set from zero or more states.\n */\nexport function visualState(...states: UiVisualState[]): UiVisualStateSet {\n return new Set(states);\n}\n\n/**\n * The default visual state set containing only Normal.\n */\nexport const defaultVisualState: UiVisualStateSet = visualState(UiVisualState.Normal);\n\n/**\n * Returns true when the supplied state is active in the set.\n */\nexport function hasVisualState(states: UiVisualStateSet, state: UiVisualState): boolean {\n return states.has(state);\n}\n\n/**\n * Compares two visual state sets for equality.\n */\nexport function visualStatesEqual(a: UiVisualStateSet, b: UiVisualStateSet): boolean {\n if (a.size !== b.size) {\n return false;\n }\n for (const state of a) {\n if (!b.has(state)) {\n return false;\n }\n }\n return true;\n}\n","import type { DirtyFlags } from './DirtyFlags';\nimport type { UiGraph } from './UiGraph';\nimport type { NodeProperty, UiNode, UiPropertyOverride, UiPropertyOverrides } from './UiNode';\n\n/**\n * The cascade a modifier writes into.\n *\n * effective(property) = the last override in modifier order,\n * else what the element declared\n *\n * Keeping the element's own value rather than replacing it is what\n * makes a modifier safe to detach: dragging can write `transform` and\n * `opacity` for as long as the drag lasts, and dropping restores\n * exactly what the element asked for — including \"nothing\", which\n * restores inheritance from the environment rather than a default.\n *\n * Everything here funnels into `graph.applyResolvedProperty`, so\n * layout, paint, input and the environment read what they always read.\n */\n\n/**\n * A write from the element: a plain prop, or an emission from a bound\n * Observable. It updates the declared value; whether it reaches the\n * node depends on whether a modifier is currently overriding it.\n */\nexport function writeDeclaredProperty(\n graph: UiGraph,\n node: UiNode,\n property: NodeProperty,\n value: unknown,\n flags: DirtyFlags\n): boolean {\n const overrides = node.overrides?.get(property);\n if (overrides === undefined) {\n return graph.applyResolvedProperty(node, property, true, value, flags);\n }\n overrides.declared = { present: true, value };\n return applyEffective(graph, node, property, overrides, flags);\n}\n\n/**\n * A write from a modifier. Replaces that modifier's own entry, or adds\n * one in its position in the list.\n */\nexport function writeOverrideProperty(\n graph: UiGraph,\n node: UiNode,\n property: NodeProperty,\n override: Omit<UiPropertyOverride, 'value'> & { value: unknown },\n flags: DirtyFlags\n): boolean {\n const overrides = overridesFor(node, property);\n const existing = overrides.entries.find(entry => entry.source === override.source);\n if (existing !== undefined) {\n existing.value = override.value;\n existing.order = override.order;\n } else {\n warnOnConflict(node, property, overrides.entries, override);\n overrides.entries.push({ ...override });\n }\n overrides.entries.sort((a, b) => a.order - b.order);\n return applyEffective(graph, node, property, overrides, flags);\n}\n\n/** Removes one modifier's write, restoring whatever was under it. */\nexport function clearOverrideProperty(\n graph: UiGraph,\n node: UiNode,\n property: NodeProperty,\n source: symbol,\n flags: DirtyFlags\n): boolean {\n const overrides = node.overrides?.get(property);\n if (overrides === undefined) {\n return false;\n }\n const index = overrides.entries.findIndex(entry => entry.source === source);\n if (index === -1) {\n return false;\n }\n overrides.entries.splice(index, 1);\n const changed = applyEffective(graph, node, property, overrides, flags);\n if (overrides.entries.length === 0) {\n // Nothing is overriding it any more: drop the record so the write\n // path goes back to being a single field read.\n node.overrides?.delete(property);\n if (node.overrides?.size === 0) {\n node.overrides = null;\n }\n }\n return changed;\n}\n\n/** The names of the modifiers overriding a property, in order. */\nexport function overrideSources(node: UiNode, property: NodeProperty): string[] {\n return (node.overrides?.get(property)?.entries ?? []).map(entry => entry.name);\n}\n\nfunction applyEffective(\n graph: UiGraph,\n node: UiNode,\n property: NodeProperty,\n overrides: UiPropertyOverrides,\n flags: DirtyFlags\n): boolean {\n const last = overrides.entries[overrides.entries.length - 1];\n if (last !== undefined) {\n return graph.applyResolvedProperty(node, property, true, last.value, flags);\n }\n return graph.applyResolvedProperty(node, property, overrides.declared.present, overrides.declared.value, flags);\n}\n\nfunction overridesFor(node: UiNode, property: NodeProperty): UiPropertyOverrides {\n if (node.overrides === null) {\n node.overrides = new Map();\n }\n let overrides = node.overrides.get(property);\n if (overrides === undefined) {\n // First override of this property: remember what the element had,\n // including that it had nothing.\n const present = node.properties.has(property);\n overrides = { declared: { present, value: present ? node.properties.get(property) : undefined }, entries: [] };\n node.overrides.set(property, overrides);\n }\n return overrides;\n}\n\n/** Warned about once per node and property; two writers is usually a bug. */\nconst warned = new Set<string>();\n\nfunction warnOnConflict(\n node: UiNode,\n property: NodeProperty,\n entries: readonly UiPropertyOverride[],\n incoming: Omit<UiPropertyOverride, 'value'>\n): void {\n if (entries.length === 0) {\n return;\n }\n const key = `${node.id}:${property}`;\n if (warned.has(key)) {\n return;\n }\n warned.add(key);\n console.warn(\n `Modifiers '${entries.map(entry => entry.name).join(\"', '\")}' and '${incoming.name}' both write ` +\n `'${property}' on node '${node.id}'. The one later in the list wins.`\n );\n}\n\n/** Test hook: forgets which conflicts have been reported. */\nexport function resetOverrideWarnings(): void {\n warned.clear();\n}\n","import type { UiNode } from './UiNode';\n\n/**\n * The set of nodes invalidated since the last frame.\n *\n * Each node is stored once and drained in insertion order.\n * Dirty flags live on the UiNode itself; this set only tracks\n * membership.\n */\nexport class DirtyNodeSet {\n private readonly nodes = new Set<UiNode>();\n\n /**\n * Adds a node and reports whether it was newly added.\n */\n mark(node: UiNode): boolean {\n const size = this.nodes.size;\n this.nodes.add(node);\n return this.nodes.size > size;\n }\n\n has(node: UiNode): boolean {\n return this.nodes.has(node);\n }\n\n delete(node: UiNode): boolean {\n return this.nodes.delete(node);\n }\n\n get size(): number {\n return this.nodes.size;\n }\n\n isEmpty(): boolean {\n return this.nodes.size === 0;\n }\n\n /**\n * Drains the set, returning the nodes in insertion order.\n */\n take(): UiNode[] {\n const nodes = [...this.nodes];\n this.nodes.clear();\n return nodes;\n }\n\n /**\n * Drains the set into an existing array, in insertion order.\n *\n * The frame loop drains on every tick, so it keeps one buffer for\n * the life of the scheduler rather than allocating an array per\n * frame. The buffer is overwritten, not appended to, and its new\n * length is returned for callers that keep it around.\n */\n drainInto(buffer: UiNode[]): number {\n let count = 0;\n for (const node of this.nodes) {\n buffer[count++] = node;\n }\n buffer.length = count;\n this.nodes.clear();\n return count;\n }\n\n clear(): void {\n this.nodes.clear();\n }\n}\n","import { DirtyFlags } from './DirtyFlags';\nimport { type UiNodeType } from './UiNodeType';\nimport type { UiEnvironment } from '../environment/UiEnvironment';\nimport type { DecorationShape } from '../rendering/Decorations';\n\nexport type NodeId = string;\nexport type NodeProperty = string;\n\n/** One modifier's write of one property. `order` is its position in the list. */\nexport interface UiPropertyOverride {\n readonly source: symbol;\n /** The modifier kind's name, for the conflict warning and the inspector. */\n readonly name: string;\n order: number;\n value: unknown;\n}\n\n/**\n * The cascade for one overridden property: the element's own value,\n * and the modifier writes stacked on top of it in list order.\n */\nexport interface UiPropertyOverrides {\n /** What the element declared. Absent means it declared nothing. */\n declared: { present: boolean; value: unknown };\n /** Ordered by `order`; the last one wins. */\n entries: UiPropertyOverride[];\n}\n\n/**\n * The transitions an element declared, as the graph sees them.\n *\n * Structural rather than the class itself so that `UiNode` — which\n * every part of the engine imports — does not pull in the animation\n * module. `UiPropertyTransitions.ts` holds the implementation and the\n * argument for where it sits.\n */\nexport interface UiNodeTransitions {\n /** Takes over a write by animating towards it, or declines it. */\n write(property: NodeProperty, value: unknown, flags: DirtyFlags): boolean;\n /** Cancels everything, for a node leaving the tree. */\n release(): void;\n}\n\nexport class UiNode {\n constructor(\n public readonly id: NodeId,\n public readonly type: UiNodeType\n ) {}\n\n public parent: UiNode | null = null;\n\n public firstChild: UiNode | null = null;\n public lastChild: UiNode | null = null;\n\n /**\n * Bumped whenever this node's children are inserted, moved or\n * removed — never when a child merely changes size.\n *\n * It is the difference between \"this node reordered\" and \"the node\n * above it grew\", which look identical to anything watching boxes\n * and want opposite behaviour from a layout animation. Every change\n * to the child list goes through `appendChild`, `insertBefore` or\n * `detachNode`, so one counter here is exact and costs a comparison\n * rather than a walk of the sibling list.\n */\n public childOrderVersion = 0;\n\n public previousSibling: UiNode | null = null;\n public nextSibling: UiNode | null = null;\n\n public dirtyFlags: DirtyFlags = DirtyFlags.None;\n\n /**\n * Runtime values for this node.\n * Examples:\n * text → \"Hello\"\n * opacity → 0.5\n * visible → true\n * width → 200\n */\n public readonly properties = new Map<NodeProperty, unknown>();\n\n /**\n * Values a modifier has written over the element's own.\n *\n * Null until the first modifier writes, so a tree without modifiers\n * pays one field read per property write and nothing else. See\n * `UiPropertyOverrides.ts` for how the effective value is resolved.\n */\n public overrides: Map<NodeProperty, UiPropertyOverrides> | null = null;\n\n /**\n * The scoped environment this node reads inherited values from.\n *\n * Null means the node uses the default environment values. The\n * environment is assigned by the graph builder when a node or an\n * ancestor provides environment values.\n */\n public environment: UiEnvironment | null = null;\n\n /**\n * Shapes the node's modifiers put in its own paint pass, merged in\n * modifier order.\n *\n * Null until a modifier decorates, so the cost to an undecorated\n * node is the one null check each renderer already makes per node,\n * and a tree of ten thousand plain boxes pays nothing. Written only\n * through `UiModifierHost.decorate`; see `rendering/Decorations.ts`\n * for what a shape means and where it lands.\n */\n public decorations: readonly DecorationShape[] | null = null;\n\n /**\n * How this node's properties get from one value to the next.\n *\n * Null until the element declares a `transition`, so the cost to a\n * tree without one is a field read on the property write path — the\n * same shape, and the same argument, as `overrides` above.\n */\n public transitions: UiNodeTransitions | null = null;\n\n hasChildren(): boolean {\n return this.firstChild !== null;\n }\n\n isDirty(): boolean {\n return this.dirtyFlags !== DirtyFlags.None;\n }\n\n getProperty<T>(property: NodeProperty): T | undefined {\n return this.properties.get(property) as T | undefined;\n }\n\n setProperty<T>(property: NodeProperty, value: T): void {\n this.properties.set(property, value);\n }\n}\n","import type { UiEnvironmentKey } from './UiEnvironmentKey';\n\n/**\n * A scoped environment snapshot.\n *\n * Environments form a parent chain. Lookup walks up the chain and\n * returns the value from the nearest ancestor that provides the\n * requested key. If no ancestor provides it, the key's default\n * value is returned.\n *\n * Environments are immutable snapshots. When a provider changes an\n * environment value, a new environment instance is created and\n * attached to the affected subtree. This makes the environment\n * chain safe to cache on nodes and to reason about in tests.\n */\nexport class UiEnvironment {\n constructor(\n public readonly parent: UiEnvironment | null,\n private readonly values: ReadonlyMap<string, unknown> = new Map()\n ) {}\n\n /**\n * Returns a new environment identical to this one but with the\n * supplied key set to the supplied value.\n */\n set<T>(key: UiEnvironmentKey<T>, value: T): UiEnvironment {\n const next = new Map(this.values);\n next.set(key.name, value);\n return new UiEnvironment(this.parent, next);\n }\n\n /**\n * Returns a new environment identical to this one but with the\n * supplied key removed, exposing the parent value (or the key's\n * default) to consumers of the new environment.\n */\n delete<T>(key: UiEnvironmentKey<T>): UiEnvironment {\n const next = new Map(this.values);\n next.delete(key.name);\n return new UiEnvironment(this.parent, next);\n }\n\n /**\n * Looks up the nearest value for a key.\n */\n get<T>(key: UiEnvironmentKey<T>): T {\n if (this.values.has(key.name)) {\n return this.values.get(key.name) as T;\n }\n return this.parent !== null ? this.parent.get(key) : key.defaultValue;\n }\n\n /**\n * Returns true when this environment or an ancestor provides a\n * value for the key.\n */\n has<T>(key: UiEnvironmentKey<T>): boolean {\n if (this.values.has(key.name)) {\n return true;\n }\n return this.parent !== null ? this.parent.has(key) : false;\n }\n\n /**\n * The keys explicitly provided by this environment (not inherited\n * from parents).\n */\n providedKeys(): Iterable<string> {\n return this.values.keys();\n }\n\n /**\n * How many keys this environment provides itself.\n *\n * Comparing two environments starts here: differing counts settle it\n * without looking at a single value.\n */\n get providedSize(): number {\n return this.values.size;\n }\n\n /**\n * This environment's own value for a name, without consulting the\n * parent chain.\n *\n * Comparison needs the value a given environment provides rather\n * than the one it resolves, and needs it by name — the key object is\n * looked up separately, so probing through `get()` would mean\n * allocating a throwaway key per name per node.\n */\n getOwn(name: string): unknown {\n return this.values.get(name);\n }\n\n /**\n * Whether this environment provides a name itself, ignoring the\n * parent chain.\n */\n providesOwn(name: string): boolean {\n return this.values.has(name);\n }\n}\n","/**\n * A typed key for a value in the scoped UI environment.\n *\n * Environment keys are similar to Jetpack Compose's\n * CompositionLocal keys: they are static identifiers that carry\n * type information and a default value. A provider node can\n * override the value; descendants resolve the nearest override.\n */\nexport interface UiEnvironmentKey<T> {\n readonly name: string;\n readonly defaultValue: T;\n readonly compare?: (a: T, b: T) => boolean;\n}\n\n/**\n * Every key ever created, by name.\n *\n * Comparing two environments means going from the name an environment\n * stores back to the key that knows how to compare its values. That\n * lookup runs once per provided key per node across a propagated\n * subtree, so it has to be O(1) and allocation-free; scanning the\n * built-in key table would also miss keys declared elsewhere.\n */\nconst keysByName = new Map<string, UiEnvironmentKey<unknown>>();\n\n/**\n * Creates an environment key.\n *\n * Re-declaring a name replaces the registered key rather than\n * failing, so that a module re-executed by dev-server hot reload\n * leaves the registry pointing at the keys currently in use.\n */\nexport function createEnvironmentKey<T>(options: {\n name: string;\n defaultValue: T;\n compare?: (a: T, b: T) => boolean;\n}): UiEnvironmentKey<T> {\n const key: UiEnvironmentKey<T> = {\n name: options.name,\n defaultValue: options.defaultValue,\n compare: options.compare\n };\n keysByName.set(options.name, key as UiEnvironmentKey<unknown>);\n return key;\n}\n\n/**\n * The key declared under a name, or undefined when the name was never\n * declared as a key.\n */\nexport function findEnvironmentKey(name: string): UiEnvironmentKey<unknown> | undefined {\n return keysByName.get(name);\n}\n","/**\n * Renderer-independent color representation.\n *\n * Channels are stored as floats in the [0, 1] range. This value\n * type is intentionally free of CSS strings, Canvas2D fillStyle\n * semantics, or GPU formats; conversion to a renderer's native\n * color format belongs to the renderer.\n */\nexport interface UiColor {\n readonly r: number;\n readonly g: number;\n readonly b: number;\n readonly a: number;\n}\n\nexport const UiBasicColors = {\n transparent: { r: 0, g: 0, b: 0, a: 0 },\n black: { r: 0, g: 0, b: 0, a: 1 },\n white: { r: 1, g: 1, b: 1, a: 1 },\n red: { r: 1, g: 0, b: 0, a: 1 },\n green: { r: 0, g: 1, b: 0, a: 1 },\n blue: { r: 0, g: 0, b: 1, a: 1 }\n} as const;\n\n/**\n * Creates a color from RGBA float components.\n */\nexport function rgba(r: number, g: number, b: number, a = 1): UiColor {\n return { r, g, b, a };\n}\n\n/**\n * Creates a color from 8-bit RGBA integer components.\n */\nexport function rgb8(r: number, g: number, b: number, a = 255): UiColor {\n return {\n r: r / 255,\n g: g / 255,\n b: b / 255,\n a: a / 255\n };\n}\n\n/**\n * Compares two colors for equality.\n *\n * Uses a small epsilon for the float channels so that colors\n * produced by different computations (e.g. 1/3 vs 0.333333) are\n * considered equal when visually indistinguishable.\n */\nexport function colorsEqual(a: UiColor, b: UiColor): boolean {\n const epsilon = 0.0001;\n return (\n Math.abs(a.r - b.r) < epsilon &&\n Math.abs(a.g - b.g) < epsilon &&\n Math.abs(a.b - b.b) < epsilon &&\n Math.abs(a.a - b.a) < epsilon\n );\n}\n\n/**\n * Formatting caches, keyed on the identity of the color object.\n *\n * A UiColor is an immutable record, so once a given instance has been\n * turned into a string that string stays correct for the life of the\n * instance. Nothing in the repository writes to a color's channels;\n * the interface declares them readonly and every derived color is\n * built as a fresh object, so identity is a safe key here.\n *\n * These caches only pay for themselves because parseColor memoizes\n * too. The colors a renderer formats every frame come either from a\n * theme palette, whose objects are module constants, or from a parsed\n * CSS string. Without the parse cache below, every frame would hand\n * these maps a brand new object and every lookup would miss, so the\n * two caches have to be kept together: removing the parse cache turns\n * these into pure overhead.\n *\n * A WeakMap needs no size bound, because an entry cannot outlive the\n * color that keys it.\n */\nconst hexCache = new WeakMap<UiColor, string>();\nconst rgbaCache = new WeakMap<UiColor, string>();\n\n/**\n * Converts a UiColor to a CSS-compatible hex string.\n *\n * This is a renderer convenience only; the canonical representation\n * remains the float object.\n */\nexport function colorToHex(color: UiColor): string {\n const cached = hexCache.get(color);\n if (cached !== undefined) {\n return cached;\n }\n const formatted = formatHex(color);\n hexCache.set(color, formatted);\n return formatted;\n}\n\nfunction formatHex(color: UiColor): string {\n const r = Math.round(color.r * 255);\n const g = Math.round(color.g * 255);\n const b = Math.round(color.b * 255);\n const a = Math.round(color.a * 255);\n const channels = [r, g, b, a];\n const hex = channels.map(c => c.toString(16).padStart(2, '0')).join('');\n const shortenable = channels.every(c => c >> 4 === (c & 0x0f));\n if (shortenable) {\n if (a === 255) {\n return `#${hex[0]}${hex[2]}${hex[4]}`;\n }\n return `#${hex[0]}${hex[2]}${hex[4]}${hex[6]}`;\n }\n if (a === 255) {\n return `#${hex.slice(0, 6)}`;\n }\n return `#${hex}`;\n}\n\n/**\n * Converts a UiColor to a CSS rgba() string.\n */\nexport function colorToRgba(color: UiColor): string {\n const cached = rgbaCache.get(color);\n if (cached !== undefined) {\n return cached;\n }\n const r = Math.round(color.r * 255);\n const g = Math.round(color.g * 255);\n const b = Math.round(color.b * 255);\n const formatted = `rgba(${r}, ${g}, ${b}, ${color.a})`;\n rgbaCache.set(color, formatted);\n return formatted;\n}\n\nconst NAMED_COLORS: Record<string, UiColor> = {\n transparent: { r: 0, g: 0, b: 0, a: 0 },\n black: { r: 0, g: 0, b: 0, a: 1 },\n white: { r: 1, g: 1, b: 1, a: 1 },\n red: { r: 1, g: 0, b: 0, a: 1 },\n green: { r: 0, g: 0.5, b: 0, a: 1 },\n blue: { r: 0, g: 0, b: 1, a: 1 },\n yellow: { r: 1, g: 1, b: 0, a: 1 },\n cyan: { r: 0, g: 1, b: 1, a: 1 },\n magenta: { r: 1, g: 0, b: 1, a: 1 },\n orange: { r: 1, g: 0.65, b: 0, a: 1 },\n gray: { r: 0.5, g: 0.5, b: 0.5, a: 1 },\n grey: { r: 0.5, g: 0.5, b: 0.5, a: 1 }\n};\n\nfunction clamp01(v: number): number {\n return Math.min(Math.max(v, 0), 1);\n}\n\nfunction parseHexColor(hex: string): UiColor | undefined {\n let raw = hex.slice(1);\n if (raw.length === 3 || raw.length === 4) {\n raw = raw\n .split('')\n .map(c => c + c)\n .join('');\n }\n if (raw.length !== 6 && raw.length !== 8) {\n return undefined;\n }\n const num = Number.parseInt(raw, 16);\n if (!Number.isFinite(num)) {\n return undefined;\n }\n if (raw.length === 8) {\n const r = (num >> 24) & 0xff;\n const g = (num >> 16) & 0xff;\n const b = (num >> 8) & 0xff;\n const a = num & 0xff;\n return { r: r / 255, g: g / 255, b: b / 255, a: a / 255 };\n }\n const r = (num >> 16) & 0xff;\n const g = (num >> 8) & 0xff;\n const b = num & 0xff;\n return { r: r / 255, g: g / 255, b: b / 255, a: 1 };\n}\n\nfunction parseRgbColor(source: string): UiColor | undefined {\n const open = source.indexOf('(');\n const close = source.indexOf(')');\n if (open < 0 || close < 0) {\n return undefined;\n }\n const parts = source\n .slice(open + 1, close)\n .split(',')\n .map(s => s.trim());\n if (parts.length < 3) {\n return undefined;\n }\n const values: number[] = [];\n for (let i = 0; i < parts.length; i++) {\n const part = parts[i];\n const num = Number(part.replace('%', ''));\n if (!Number.isFinite(num)) {\n return undefined;\n }\n if (part.includes('%')) {\n values.push(num / 100);\n } else if (i === 3) {\n values.push(num);\n } else {\n values.push(num / 255);\n }\n }\n const [r, g, b, a = 1] = values;\n return {\n r: clamp01(r),\n g: clamp01(g),\n b: clamp01(b),\n a: clamp01(a)\n };\n}\n\n/**\n * Marks a string that has already been found unparseable.\n *\n * \"Unsupported\" is a real answer worth caching, and a bare undefined\n * in the map could not be told apart from a miss without a second\n * lookup through has(). A sentinel object keeps the hot path to one\n * map read.\n */\nconst UNSUPPORTED: UiColor = { r: 0, g: 0, b: 0, a: 0 };\n\n/**\n * How many distinct color strings the parse cache will hold.\n *\n * An application's colors come from a small fixed set, usually a\n * theme palette and a handful of literals, so a few hundred entries\n * covers the working set several times over. But a color can also\n * arrive through a binding, and an animated rgba() produces a fresh\n * string on every frame; caching those without a bound would be a\n * leak that grows for as long as the application runs.\n *\n * When the cache fills it is cleared wholesale rather than evicted\n * entry by entry. That is the right trade here precisely because the\n * real working set is tiny: rebuilding it costs one parse per\n * distinct color, which is a single frame's worth of work at most,\n * and it buys us a cache with no bookkeeping of recency at all.\n */\nconst PARSE_CACHE_LIMIT = 256;\n\nconst parseCache = new Map<string, UiColor>();\n\n/**\n * Parses a CSS color string into a UiColor.\n *\n * Supports hex (#rgb, #rgba, #rrggbb, #rrggbbaa), rgb()/rgba(),\n * and a small set of named colors. Returns undefined for unsupported\n * values.\n *\n * The result is memoized on the raw input string, which matters for\n * more than the parse itself: resolving a node's paint state parses\n * the same handful of constant strings on every node of every frame,\n * and returning the same instance each time is what lets colorToHex\n * and colorToRgba cache their output by identity. Callers must treat\n * the returned color as immutable, as the interface's readonly\n * channels already require, because they are very likely holding the\n * same object as everyone else who asked for that color.\n */\nexport function parseColor(value: string): UiColor | undefined {\n const cached = parseCache.get(value);\n if (cached !== undefined) {\n return cached === UNSUPPORTED ? undefined : cached;\n }\n const parsed = parseColorUncached(value);\n if (parseCache.size >= PARSE_CACHE_LIMIT) {\n parseCache.clear();\n }\n parseCache.set(value, parsed ?? UNSUPPORTED);\n return parsed;\n}\n\nfunction parseColorUncached(value: string): UiColor | undefined {\n const trimmed = value.trim().toLowerCase();\n if (trimmed.length === 0) {\n return undefined;\n }\n const named = NAMED_COLORS[trimmed];\n if (named !== undefined) {\n return named;\n }\n if (trimmed.startsWith('#')) {\n return parseHexColor(trimmed);\n }\n if (trimmed.startsWith('rgb')) {\n return parseRgbColor(trimmed);\n }\n return undefined;\n}\n\n/**\n * Normalizes a color value to a UiColor.\n *\n * UiColor objects pass through unchanged. CSS strings are parsed.\n * Unsupported values return undefined.\n */\nexport function normalizeColor(value: unknown): UiColor | undefined {\n if (value === undefined || value === null) {\n return undefined;\n }\n if (typeof value === 'string') {\n return parseColor(value);\n }\n if (\n typeof value === 'object' &&\n typeof (value as Partial<UiColor>).r === 'number' &&\n typeof (value as Partial<UiColor>).g === 'number' &&\n typeof (value as Partial<UiColor>).b === 'number' &&\n typeof (value as Partial<UiColor>).a === 'number'\n ) {\n return value as UiColor;\n }\n return undefined;\n}\n\n/**\n * Equality for color property values, used by the registry to decide\n * whether a change repaints. Two literal colors compare by channel; a\n * theme palette name compares by name, because what it paints depends\n * on a theme this comparison cannot see. Lives here rather than with\n * the theme lookup so the registry can import it without a cycle.\n */\nexport function colorValuesEqual(a: unknown, b: unknown): boolean {\n if (a === b) {\n return true;\n }\n const normalizedA = normalizeColor(a);\n const normalizedB = normalizeColor(b);\n if (normalizedA === undefined || normalizedB === undefined) {\n return false;\n }\n return colorsEqual(normalizedA, normalizedB);\n}\n","import type { UiColor } from '../properties/UiColor';\nimport { colorsEqual, UiBasicColors } from '../properties/UiColor';\n\n/**\n * A renderer-independent color palette.\n *\n * This is a starter set of semantic colors. Names are not hard\n * requirements; consumers can define additional palettes or extend\n * this shape as the framework grows.\n */\nexport interface UiColors {\n readonly background: UiColor;\n readonly surface: UiColor;\n readonly primary: UiColor;\n readonly secondary: UiColor;\n readonly text: UiColor;\n readonly textMuted: UiColor;\n readonly border: UiColor;\n readonly shadow: UiColor;\n /**\n * The ground of something standing in for content that has not\n * arrived: a skeleton's bars, an avatar with no picture yet.\n *\n * Its own token rather than a borrowed one because it is a role no\n * other token plays. Borrowing `border` would tie a filled block to\n * the colour of a rule, and borrowing `controlBackgroundPressed`\n * would move every skeleton on the screen when a theme adjusted how\n * a button looks while held.\n */\n readonly placeholder: UiColor;\n\n // Control tokens. Named for the role a control plays, not for the\n // widget: one set serves the checkbox, the switch, the radio, the\n // slider, the number field and the text field, so a theme restyles\n // all of them at once. Components read these instead of taking\n // colour props, which would fork the theme at every call site.\n readonly controlBackground: UiColor;\n readonly controlBackgroundHovered: UiColor;\n readonly controlBackgroundPressed: UiColor;\n readonly controlBorder: UiColor;\n readonly controlForeground: UiColor;\n readonly controlForegroundDisabled: UiColor;\n /** The fill of a control that is on: a ticked box, a thrown switch. */\n readonly controlAccent: UiColor;\n /** An invalid control's border, and the text explaining why. */\n readonly danger: UiColor;\n /**\n * The ring drawn outside whatever holds keyboard focus. It sits on\n * the background rather than on the control, so it is its own token\n * and not `controlAccent`: a ring has to stay legible against the\n * surface behind every control, including a chosen row.\n *\n * Both palettes make it the ink they already write text in, rather\n * than an accent. A ring is the one piece of colour a control grows\n * without the app asking for it, so the stock one should be a colour\n * the app is using anyway; a themed accent that nobody chose reads\n * as the framework's colour showing through the app's.\n */\n readonly focusRing: UiColor;\n\n // Selection tokens. A row of a list, a tree or a table is chosen\n // rather than operated, so it is neither a control's accent nor its\n // hover: one pair, so the three data components agree on what\n // \"chosen\" looks like without any of them naming a colour.\n readonly selectionBackground: UiColor;\n readonly selectionForeground: UiColor;\n}\n\nexport const lightColors: UiColors = {\n background: UiBasicColors.white,\n surface: { r: 0.98, g: 0.98, b: 0.98, a: 1 },\n primary: { r: 0.13, g: 0.59, b: 0.95, a: 1 },\n secondary: { r: 0.61, g: 0.15, b: 0.69, a: 1 },\n text: UiBasicColors.black,\n textMuted: { r: 0.4, g: 0.4, b: 0.4, a: 1 },\n border: { r: 0.85, g: 0.85, b: 0.85, a: 1 },\n shadow: { r: 0, g: 0, b: 0, a: 0.2 },\n placeholder: { r: 0.91, g: 0.91, b: 0.92, a: 1 },\n controlBackground: UiBasicColors.white,\n controlBackgroundHovered: { r: 0.95, g: 0.95, b: 0.96, a: 1 },\n controlBackgroundPressed: { r: 0.9, g: 0.9, b: 0.92, a: 1 },\n controlBorder: { r: 0.76, g: 0.77, b: 0.79, a: 1 },\n controlForeground: { r: 0.07, g: 0.09, b: 0.13, a: 1 },\n controlForegroundDisabled: { r: 0.6, g: 0.62, b: 0.65, a: 1 },\n controlAccent: { r: 0.13, g: 0.59, b: 0.95, a: 1 },\n danger: { r: 0.86, g: 0.15, b: 0.15, a: 1 },\n focusRing: { r: 0.07, g: 0.09, b: 0.13, a: 1 },\n selectionBackground: { r: 0.85, g: 0.92, b: 0.99, a: 1 },\n selectionForeground: { r: 0.05, g: 0.24, b: 0.44, a: 1 }\n} as const;\n\nexport const darkColors: UiColors = {\n background: { r: 0.12, g: 0.12, b: 0.12, a: 1 },\n surface: { r: 0.18, g: 0.18, b: 0.18, a: 1 },\n primary: { r: 0.4, g: 0.76, b: 1, a: 1 },\n secondary: { r: 0.88, g: 0.6, b: 0.94, a: 1 },\n text: UiBasicColors.white,\n textMuted: { r: 0.6, g: 0.6, b: 0.6, a: 1 },\n border: { r: 0.3, g: 0.3, b: 0.3, a: 1 },\n shadow: { r: 0, g: 0, b: 0, a: 0.5 },\n placeholder: { r: 0.26, g: 0.26, b: 0.27, a: 1 },\n controlBackground: { r: 0.16, g: 0.17, b: 0.2, a: 1 },\n controlBackgroundHovered: { r: 0.21, g: 0.23, b: 0.27, a: 1 },\n controlBackgroundPressed: { r: 0.26, g: 0.28, b: 0.33, a: 1 },\n controlBorder: { r: 0.34, g: 0.36, b: 0.41, a: 1 },\n controlForeground: { r: 0.9, g: 0.91, b: 0.94, a: 1 },\n controlForegroundDisabled: { r: 0.48, g: 0.5, b: 0.55, a: 1 },\n controlAccent: { r: 0.4, g: 0.76, b: 1, a: 1 },\n danger: { r: 0.94, g: 0.42, b: 0.42, a: 1 },\n focusRing: { r: 0.9, g: 0.91, b: 0.94, a: 1 },\n selectionBackground: { r: 0.16, g: 0.29, b: 0.42, a: 1 },\n selectionForeground: { r: 0.85, g: 0.93, b: 1, a: 1 }\n} as const;\n\n/**\n * Compares two color palettes for equality.\n *\n * Over the keys rather than a written-out list: a palette that gains a\n * token must invalidate on a change to it, and a list is a thing to\n * forget to extend. Extra names a custom palette adds are compared too.\n */\nexport function colorsEqualPalette(a: UiColors, b: UiColors): boolean {\n const left = a as unknown as Record<string, UiColor | undefined>;\n const right = b as unknown as Record<string, UiColor | undefined>;\n const keys = Object.keys(left);\n if (keys.length !== Object.keys(right).length) {\n return false;\n }\n for (const key of keys) {\n const one = left[key];\n const other = right[key];\n if (one === undefined || other === undefined) {\n if (one !== other) {\n return false;\n }\n continue;\n }\n if (!colorsEqual(one, other)) {\n return false;\n }\n }\n return true;\n}\n","import type { UiColor } from './UiColor';\nimport type { UiColorValue, UiFontWeight, UiTextAlign, UiTextDirection } from './UiPropertyValues';\nimport type { UiNode } from '../graph/UiNode';\n\n/**\n * A coherent typography value.\n *\n * TextStyle is the unit of inheritance: a parent can provide a\n * TextStyle and descendants can override individual fields while\n * keeping the rest.\n *\n * The four fields below `textDirection` are optional because the\n * environment's typography roles were written before they existed and\n * a role that says nothing about them means \"normal\", which is what\n * their property defaults already say.\n */\nexport interface UiTextStyle {\n readonly fontFamily: string;\n readonly fontSize: number;\n readonly fontWeight: UiFontWeight;\n readonly lineHeight: number;\n readonly letterSpacing: number;\n readonly color: UiColor;\n readonly textAlign: UiTextAlign;\n readonly textDirection: UiTextDirection;\n readonly fontStyle?: UiFontStyle;\n readonly fontStretch?: UiFontStretch;\n readonly fontVariant?: UiFontVariant;\n readonly fontKerning?: UiFontKerning;\n readonly textDecoration?: UiTextDecoration;\n}\n\n/** Upright or sloped. `oblique` is a synthesised slant where no italic face exists. */\nexport type UiFontStyle = 'normal' | 'italic' | 'oblique';\n\n/**\n * The width axis, as CSS names it.\n *\n * A variable font's `wdth` is reached through these keywords and\n * nowhere else: the Canvas2D context takes `fontStretch` as a\n * property, and a font string cannot carry an axis tuple.\n */\nexport type UiFontStretch =\n | 'ultra-condensed'\n | 'extra-condensed'\n | 'condensed'\n | 'semi-condensed'\n | 'normal'\n | 'semi-expanded'\n | 'expanded'\n | 'extra-expanded'\n | 'ultra-expanded';\n\n/**\n * The one font-variant value the CSS font shorthand carries, and so\n * the one a canvas font string carries. `font-feature-settings` is not\n * part of the shorthand and the context has no property for it, which\n * is why `tnum` and `liga` are not here.\n */\nexport type UiFontVariant = 'normal' | 'small-caps';\n\n/** Whether the shaper applies the font's kerning pairs. */\nexport type UiFontKerning = 'auto' | 'normal' | 'none';\n\n/** Lines drawn with the text. Both may be asked for at once. */\nexport type UiTextDecoration = 'none' | 'underline' | 'line-through' | 'underline line-through';\n\n/**\n * The fields of a style that change how wide its text measures.\n *\n * The split matters: only these reach the measure request, so a run\n * that changes colour, background or underline is repainted from the\n * paragraph the cache already holds, and only a run that changes font\n * makes the paragraph new. See `TextMeasurer.ts`.\n */\nexport interface UiTextMetrics {\n readonly fontFamily?: string;\n readonly fontSize?: number;\n readonly fontWeight?: UiFontWeight;\n readonly fontStyle?: UiFontStyle;\n readonly fontStretch?: UiFontStretch;\n readonly fontVariant?: UiFontVariant;\n readonly fontKerning?: UiFontKerning;\n readonly letterSpacing?: number;\n}\n\n/**\n * A run that is activated rather than only read.\n *\n * `onClick` runs on a press that neither moved nor selected, and on\n * Enter or Space while the run is focused. `label` names the run in\n * the semantics mirror when the text itself would not (\"here\" is a\n * link a screen reader cannot use); `href` is carried for the\n * application's own use and the runtime never navigates to it.\n */\nexport interface UiTextLink {\n readonly onClick?: () => void;\n readonly label?: string;\n readonly href?: string;\n}\n\n/**\n * One run of a paragraph, with the style fields it overrides.\n *\n * A `Text` node takes either a `text` string or a `spans` array, and\n * the array is the whole of the paragraph: its texts concatenated in\n * order are the text, so every offset the rest of the runtime\n * works in — a line's `start`, a selection range, a find match, a\n * caret — means the same thing whether the paragraph has runs or not.\n * That is the property the whole feature rests on, and it is why runs\n * are a shape of one paragraph rather than a tree of nodes.\n *\n * Anything a span does not set it inherits from the node, and the\n * node from its environment, exactly as a node inherits today.\n */\nexport interface UiTextSpan extends UiTextMetrics {\n readonly text: string;\n readonly color?: UiColorValue;\n readonly backgroundColor?: UiColorValue;\n readonly textDecoration?: UiTextDecoration;\n readonly link?: UiTextLink;\n}\n\n/** A span placed in the flattened text: the same fields, plus where it is. */\nexport interface UiResolvedTextSpan extends UiTextMetrics {\n readonly start: number;\n readonly end: number;\n readonly color?: UiColorValue;\n readonly backgroundColor?: UiColorValue;\n readonly textDecoration?: UiTextDecoration;\n readonly link?: UiTextLink;\n}\n\n/** A paragraph's text and the runs inside it. */\nexport interface UiSpannedText {\n readonly text: string;\n readonly spans: readonly UiResolvedTextSpan[];\n}\n\nexport const defaultTextStyle: UiTextStyle = {\n fontFamily: 'sans-serif',\n fontSize: 14,\n fontWeight: 'normal',\n lineHeight: 16.8,\n letterSpacing: 0,\n color: { r: 0, g: 0, b: 0, a: 1 },\n textAlign: 'start',\n textDirection: 'ltr'\n} as const;\n\nconst EMPTY_SPANS: readonly UiResolvedTextSpan[] = [];\n\n/**\n * Flattened spans, remembered by the identity of the array they came\n * from.\n *\n * The flattening is a concatenation and an offset per run, which is\n * cheap; doing it on every layout, paint, hit test and semantics pass\n * of every paragraph on screen is not. An application that rebuilds\n * its span array every frame gets the work every frame and is no\n * worse off than it would be without the memo, and one that holds the\n * array still — which is what a bound cell does — pays once.\n */\nconst flattened = new WeakMap<readonly UiTextSpan[], UiSpannedText>();\n\n/** The text of a span array, with each run's offsets into it. */\nexport function flattenTextSpans(spans: readonly UiTextSpan[]): UiSpannedText {\n const cached = flattened.get(spans);\n if (cached !== undefined) {\n return cached;\n }\n let text = '';\n const resolved: UiResolvedTextSpan[] = [];\n for (const span of spans) {\n const start = text.length;\n text += span.text;\n if (text.length === start) {\n // An empty run has no offsets to cover and nothing to draw.\n continue;\n }\n resolved.push({\n start,\n end: text.length,\n fontFamily: span.fontFamily,\n fontSize: span.fontSize,\n fontWeight: span.fontWeight,\n fontStyle: span.fontStyle,\n fontStretch: span.fontStretch,\n fontVariant: span.fontVariant,\n fontKerning: span.fontKerning,\n letterSpacing: span.letterSpacing,\n color: span.color,\n backgroundColor: span.backgroundColor,\n textDecoration: span.textDecoration,\n link: span.link\n });\n }\n const result: UiSpannedText = { text, spans: resolved };\n flattened.set(spans, result);\n return result;\n}\n\n/**\n * A node's paragraph as text and runs, or undefined when it has no\n * runs.\n *\n * `spans` wins over `text` when both are set, because a node that was\n * given runs meant them; the `text` prop is then ignored rather than\n * appended, so there is exactly one source of offsets.\n */\nexport function spannedTextOf(node: UiNode): UiSpannedText | undefined {\n const spans = node.properties.get('spans') as readonly UiTextSpan[] | undefined;\n if (spans === undefined || spans.length === 0) {\n return undefined;\n }\n const flat = flattenTextSpans(spans);\n return flat.text.length === 0 ? undefined : flat;\n}\n\n/**\n * The text a node draws: its runs' text if it has runs, its `text`\n * property otherwise.\n *\n * Every reader of a node's paragraph goes through this — layout,\n * paint, selection, find and the semantics mirror — so a spanned\n * paragraph is selectable, findable and readable without any of them\n * knowing what a span is.\n */\nexport function textContentOf(node: UiNode): string {\n const spanned = spannedTextOf(node);\n if (spanned !== undefined) {\n return spanned.text;\n }\n const text = node.properties.get('text');\n return typeof text === 'string' ? text : '';\n}\n\n/** The runs of a node's paragraph; empty when it has none. */\nexport function resolvedSpansOf(node: UiNode): readonly UiResolvedTextSpan[] {\n return spannedTextOf(node)?.spans ?? EMPTY_SPANS;\n}\n\n/**\n * The runs an *editable* node styles its own text with.\n *\n * An editable's paragraph is the user's, held by its model rather\n * than by a property — so unlike a `Text`, its runs do not supply the\n * text, they only describe it. `spans` on an editable is presentation\n * over a string somebody is typing.\n *\n * Which is why this checks. Every offset the editor works in — the\n * caret, the selection, the hit test that turns a click into a text\n * position — is an offset into the model's string. Runs describing a\n * *different* string would put the glyphs somewhere the caret does\n * not agree with, and the field would look subtly, unfixably wrong.\n * When they disagree the text is drawn unstyled, which is a frame of\n * plain colour rather than a frame of nonsense, and corrects itself\n * as soon as the application catches up.\n */\nexport function editableSpansOf(node: UiNode, text: string): readonly UiResolvedTextSpan[] {\n const spanned = spannedTextOf(node);\n return spanned !== undefined && spanned.text === text ? spanned.spans : EMPTY_SPANS;\n}\n\n/** The span covering an offset, or undefined where no run does. */\nexport function spanAtOffset(spans: readonly UiResolvedTextSpan[], offset: number): UiResolvedTextSpan | undefined {\n for (const span of spans) {\n if (offset >= span.start && offset < span.end) {\n return span;\n }\n }\n return undefined;\n}\n\n/**\n * Compares two span arrays for equality.\n *\n * A link is compared by identity, as every function-valued prop in\n * the registry is: an application that rebuilds its handler each\n * render says the run changed, which costs a paint and no layout,\n * since a handler is not a metric field.\n */\nexport function textSpansEqual(a: readonly UiTextSpan[] | undefined, b: readonly UiTextSpan[] | undefined): boolean {\n if (a === b) {\n return true;\n }\n if (a === undefined || b === undefined || a.length !== b.length) {\n return false;\n }\n for (let i = 0; i < a.length; i++) {\n if (!spansEqual(a[i], b[i])) {\n return false;\n }\n }\n return true;\n}\n\nfunction spansEqual(a: UiTextSpan, b: UiTextSpan): boolean {\n return (\n a.text === b.text &&\n a.fontFamily === b.fontFamily &&\n a.fontSize === b.fontSize &&\n a.fontWeight === b.fontWeight &&\n a.fontStyle === b.fontStyle &&\n a.fontStretch === b.fontStretch &&\n a.fontVariant === b.fontVariant &&\n a.fontKerning === b.fontKerning &&\n a.letterSpacing === b.letterSpacing &&\n colorValueEqual(a.color, b.color) &&\n colorValueEqual(a.backgroundColor, b.backgroundColor) &&\n a.textDecoration === b.textDecoration &&\n a.link === b.link\n );\n}\n\nfunction colorValueEqual(a: UiColorValue | undefined, b: UiColorValue | undefined): boolean {\n if (a === b) {\n return true;\n }\n if (typeof a !== 'object' || typeof b !== 'object' || a === null || b === null) {\n return false;\n }\n return a.r === b.r && a.g === b.g && a.b === b.b && a.a === b.a;\n}\n\n/**\n * Compares two text styles for equality.\n */\nexport function textStylesEqual(a: UiTextStyle, b: UiTextStyle): boolean {\n const epsilon = 0.0001;\n return (\n a.fontFamily === b.fontFamily &&\n Math.abs(a.fontSize - b.fontSize) < epsilon &&\n a.fontWeight === b.fontWeight &&\n Math.abs(a.lineHeight - b.lineHeight) < epsilon &&\n Math.abs(a.letterSpacing - b.letterSpacing) < epsilon &&\n Math.abs(a.color.r - b.color.r) < epsilon &&\n Math.abs(a.color.g - b.color.g) < epsilon &&\n Math.abs(a.color.b - b.color.b) < epsilon &&\n Math.abs(a.color.a - b.color.a) < epsilon &&\n a.textAlign === b.textAlign &&\n a.textDirection === b.textDirection &&\n a.fontStyle === b.fontStyle &&\n a.fontStretch === b.fontStretch &&\n a.fontVariant === b.fontVariant &&\n a.fontKerning === b.fontKerning &&\n a.textDecoration === b.textDecoration\n );\n}\n","import type { UiTextStyle } from '../properties/UiTextStyle';\nimport { textStylesEqual } from '../properties/UiTextStyle';\n\n/**\n * A typography scale.\n *\n * Each named style is a complete TextStyle so that it can be\n * inherited as a unit. Components can override individual fields\n * while falling back to the scale for the rest.\n */\nexport interface UiTypography {\n readonly body: UiTextStyle;\n readonly bodyLarge: UiTextStyle;\n readonly bodySmall: UiTextStyle;\n readonly headline: UiTextStyle;\n readonly title: UiTextStyle;\n readonly label: UiTextStyle;\n}\n\n/**\n * Roles an application adds to the scale, declared by merging.\n *\n * A scale of six covers a document and not an application: the two\n * applications here use fourteen and eleven distinct sizes. Rather\n * than grow `UiTypography` for everyone, or send an application back\n * to writing numbers on elements, a theme's typography may carry names\n * of its own, and an application declares them so they type:\n *\n * declare module 'gesso-core' {\n * interface UiTypographyExtensions {\n * readonly cardTitle: unknown;\n * readonly display: unknown;\n * }\n * }\n *\n * The value type is not used, only the key, because what the theme\n * carries is always a `UiTextStyle`. Declaring one makes\n * `textStyle=\"cardTitle\"` legal and `textStyle=\"cardTtile\"` a compile\n * error, which is the whole point.\n */\nexport interface UiTypographyExtensions {}\n\n/**\n * A role in the scale, as an element names it: `textStyle=\"title\"`.\n *\n * The idiom the documentation teaches. A size, a weight and a line\n * height written out on an element are three numbers to keep in step\n * across a screen and six to keep in step across an application, and\n * none of them follows a theme; a role is one word that does.\n */\nexport type UiTypographyRole = keyof UiTypography | (keyof UiTypographyExtensions & string);\n\n/**\n * Whether a value names a role of the supplied scale.\n *\n * Asked of the scale rather than of a written-out list, so a role an\n * application added is a role. A name the scale does not carry is not\n * one, and the element keeps whatever type it inherited rather than\n * drawing at a default size, which is the quieter of the two failures.\n */\nexport function isTypographyRole(value: unknown, scale: UiTypography): value is UiTypographyRole {\n return typeof value === 'string' && Object.prototype.hasOwnProperty.call(scale, value);\n}\n\nconst defaultBody: UiTextStyle = {\n fontFamily: 'sans-serif',\n fontSize: 14,\n fontWeight: 'normal',\n lineHeight: 16.8,\n letterSpacing: 0,\n color: { r: 0, g: 0, b: 0, a: 1 },\n textAlign: 'start',\n textDirection: 'ltr'\n} as const;\n\nexport const defaultTypography: UiTypography = {\n body: defaultBody,\n bodyLarge: { ...defaultBody, fontSize: 16, lineHeight: 19.2 },\n bodySmall: { ...defaultBody, fontSize: 12, lineHeight: 14.4 },\n headline: { ...defaultBody, fontSize: 24, fontWeight: 'bold', lineHeight: 28.8 },\n title: { ...defaultBody, fontSize: 20, fontWeight: '500', lineHeight: 24 },\n label: { ...defaultBody, fontSize: 11, fontWeight: '500', lineHeight: 13.2, letterSpacing: 0.5 }\n} as const;\n\n/**\n * Compares two typography scales for equality.\n *\n * Over the keys rather than a written-out list, as `colorsEqualPalette`\n * is and for the same reason: a scale that carries roles of its own\n * has to invalidate on a change to one of them. Written out, the six\n * shipped roles were compared and an application's own were not, so a\n * scale differing only in a role it had added compared equal and the\n * change never reached the nodes that would have read it.\n */\nexport function typographyEqual(a: UiTypography, b: UiTypography): boolean {\n const left = a as unknown as Record<string, UiTextStyle | undefined>;\n const right = b as unknown as Record<string, UiTextStyle | undefined>;\n const keys = Object.keys(left);\n if (keys.length !== Object.keys(right).length) {\n return false;\n }\n for (const key of keys) {\n const one = left[key];\n const other = right[key];\n if (one === undefined || other === undefined) {\n if (one !== other) {\n return false;\n }\n continue;\n }\n if (!textStylesEqual(one, other)) {\n return false;\n }\n }\n return true;\n}\n","/**\n * A renderer-independent shape scale.\n *\n * Each value is a logical pixel radius. These are semantic names;\n * renderers translate them into border radii or other shape\n * representations.\n */\nexport interface UiShapes {\n readonly none: number;\n readonly extraSmall: number;\n readonly small: number;\n readonly medium: number;\n readonly large: number;\n readonly extraLarge: number;\n readonly full: number;\n}\n\nexport const defaultShapes: UiShapes = {\n none: 0,\n extraSmall: 2,\n small: 4,\n medium: 8,\n large: 16,\n extraLarge: 24,\n full: 9999\n} as const;\n\n/**\n * Compares two shape scales for equality.\n *\n * Over the scale's own keys rather than the seven written out, for the\n * reason `typographyEqual` was rewritten the same way: a theme may\n * carry steps of its own (see\n * `UiShapeExtensions`), and a written-out list would let a change to\n * one of those pass as no change at all, so nothing would repaint.\n */\nexport function shapesEqual(a: UiShapes, b: UiShapes): boolean {\n const left = a as unknown as Readonly<Record<string, number | undefined>>;\n const right = b as unknown as Readonly<Record<string, number | undefined>>;\n const keys = Object.keys(left);\n if (keys.length !== Object.keys(right).length) {\n return false;\n }\n for (const key of keys) {\n if (left[key] !== right[key]) {\n return false;\n }\n }\n return true;\n}\n\n/**\n * Radii an application adds to the scale, declared by merging.\n *\n * The same mechanism as `UiTypographyExtensions`, for the same reason:\n * seven steps cover a document and not an application, and a control\n * library wants radii the shared scale has no name for. Rather than\n * grow `UiShapes` for everyone, a theme's shape scale may carry names\n * of its own, and an application declares them so they type:\n *\n * declare module 'gesso-core' {\n * interface UiShapeExtensions {\n * readonly control: unknown;\n * readonly sheet: unknown;\n * }\n * }\n *\n * The value type is not used, only the key, because what the theme\n * carries is always a number. Declaring one makes\n * `borderRadius=\"control\"` legal and `borderRadius=\"contorl\"` a\n * compile error, which is the whole point.\n */\nexport interface UiShapeExtensions {}\n\n/**\n * A step of the scale, as an element names it: `borderRadius=\"medium\"`.\n *\n * Resolved at paint against the theme the element is under, exactly as\n * a palette name in `backgroundColor` is, so a radius follows a theme\n * change without anything on the element knowing.\n */\nexport type UiShapeName = keyof UiShapes | (keyof UiShapeExtensions & string);\n\n/**\n * Whether a value names a step of the supplied scale.\n *\n * Asked of the scale rather than of a written-out list, so a step an\n * application added is a step. Mirrors `isTypographyRole`.\n */\nexport function isShapeName(value: unknown, scale: UiShapes): value is UiShapeName {\n return typeof value === 'string' && Object.prototype.hasOwnProperty.call(scale, value);\n}\n","import type { UiColor } from './UiColor';\n\n/**\n * Renderer-independent box shadow description.\n *\n * A shadow is defined by its offset, blur, spread, color, and\n * whether it is inset. The renderer is responsible for translating\n * these semantics into drawing operations.\n */\nexport interface UiBoxShadow {\n readonly offsetX: number;\n readonly offsetY: number;\n readonly blurRadius: number;\n readonly spreadRadius: number;\n readonly color: UiColor;\n readonly inset?: boolean;\n}\n\n/**\n * Creates a box shadow with the supplied parameters.\n */\nexport function boxShadow(\n offsetX: number,\n offsetY: number,\n blurRadius: number,\n spreadRadius: number,\n color: UiColor,\n inset = false\n): UiBoxShadow {\n return { offsetX, offsetY, blurRadius, spreadRadius, color, inset };\n}\n\n/**\n * Compares two box shadows for equality.\n */\nexport function boxShadowsEqual(a: UiBoxShadow, b: UiBoxShadow): boolean {\n const epsilon = 0.0001;\n return (\n a.offsetX === b.offsetX &&\n a.offsetY === b.offsetY &&\n a.blurRadius === b.blurRadius &&\n a.spreadRadius === b.spreadRadius &&\n a.inset === b.inset &&\n Math.abs(a.color.r - b.color.r) < epsilon &&\n Math.abs(a.color.g - b.color.g) < epsilon &&\n Math.abs(a.color.b - b.color.b) < epsilon &&\n Math.abs(a.color.a - b.color.a) < epsilon\n );\n}\n\n/**\n * Compares two shadow arrays for equality.\n */\nexport function boxShadowArraysEqual(a: readonly UiBoxShadow[], b: readonly UiBoxShadow[]): boolean {\n if (a.length !== b.length) {\n return false;\n }\n for (let i = 0; i < a.length; i++) {\n if (!boxShadowsEqual(a[i]!, b[i]!)) {\n return false;\n }\n }\n return true;\n}\n","import type { UiBoxShadow } from '../properties/UiBoxShadow';\nimport { boxShadowArraysEqual } from '../properties/UiBoxShadow';\n\n/**\n * A renderer-independent shadow scale.\n *\n * Each value is an array of shadows so layered shadows can be\n * expressed. Renderers translate these into native shadow drawing\n * operations.\n */\nexport interface UiShadows {\n readonly none: readonly UiBoxShadow[];\n readonly extraSmall: readonly UiBoxShadow[];\n readonly small: readonly UiBoxShadow[];\n readonly medium: readonly UiBoxShadow[];\n readonly large: readonly UiBoxShadow[];\n readonly extraLarge: readonly UiBoxShadow[];\n}\n\nexport const defaultShadows: UiShadows = {\n none: [],\n extraSmall: [],\n small: [],\n medium: [],\n large: [],\n extraLarge: []\n} as const;\n\n/**\n * Compares two shadow scales for equality.\n */\nexport function shadowsEqual(a: UiShadows, b: UiShadows): boolean {\n return (\n boxShadowArraysEqual(a.none, b.none) &&\n boxShadowArraysEqual(a.extraSmall, b.extraSmall) &&\n boxShadowArraysEqual(a.small, b.small) &&\n boxShadowArraysEqual(a.medium, b.medium) &&\n boxShadowArraysEqual(a.large, b.large) &&\n boxShadowArraysEqual(a.extraLarge, b.extraLarge)\n );\n}\n","/**\n * A renderer-independent spacing scale.\n *\n * Each value is a logical pixel gap. The names are the shape scale's\n * names on purpose: an application that has learned `borderRadius`\n * from `theme.shapes` already knows what `small` and `extraLarge`\n * mean, and one vocabulary across the theme is one thing to learn.\n *\n * Eight steps rather than the shape scale's seven, because spacing is\n * the token an application reaches for most often and a scale that\n * cannot say \"two\" sends the author back to a literal. The values are\n * a four pixel grid with a two pixel step at the bottom, which is what\n * the two applications' own numbers already cluster on.\n */\nexport interface UiSpacing {\n readonly none: number;\n readonly hairline: number;\n readonly extraSmall: number;\n readonly small: number;\n readonly medium: number;\n readonly large: number;\n readonly extraLarge: number;\n readonly huge: number;\n}\n\nexport const defaultSpacing: UiSpacing = {\n none: 0,\n hairline: 2,\n extraSmall: 4,\n small: 8,\n medium: 12,\n large: 16,\n extraLarge: 24,\n huge: 32\n} as const;\n\n/** The steps, in order, for a scale that is derived rather than written out. */\nexport const spacingSteps: readonly (keyof UiSpacing)[] = [\n 'none',\n 'hairline',\n 'extraSmall',\n 'small',\n 'medium',\n 'large',\n 'extraLarge',\n 'huge'\n] as const;\n\n/**\n * The same scale at a different density.\n *\n * Rounded to whole pixels, because a padding that lands on a half\n * pixel puts every box inside it on one too, and the renderers snap\n * differently at that point. `none` stays zero at every density: a gap\n * an application asked not to have is not a gap to shrink.\n */\nexport function scaleSpacing(spacing: UiSpacing, factor: number): UiSpacing {\n const scaled: Record<string, number> = {};\n for (const step of spacingSteps) {\n const value = spacing[step];\n scaled[step] = value === 0 ? 0 : Math.max(1, Math.round(value * factor));\n }\n return scaled as unknown as UiSpacing;\n}\n\n/**\n * Compares two spacing scales for equality.\n */\nexport function spacingEqual(a: UiSpacing, b: UiSpacing): boolean {\n for (const step of spacingSteps) {\n if (a[step] !== b[step]) {\n return false;\n }\n }\n return true;\n}\n","/**\n * How tightly a theme packs.\n *\n * An axis rather than a second theme: an application that wants a\n * compact table and a comfortable settings sheet provides the same\n * theme twice with one field changed, and nothing else about its\n * colours or type is duplicated.\n *\n * `comfortable` is the scale as written. `compact` is three quarters\n * of it, `spacious` a quarter more. Only the spacing scale moves; type\n * and shape do not, because a smaller gap between two rows is a\n * density choice and a smaller word is a typography one.\n */\nexport type UiDensity = 'compact' | 'comfortable' | 'spacious';\n\n/** The multiplier each density applies to the spacing scale. */\nexport const densityFactors: Readonly<Record<UiDensity, number>> = {\n compact: 0.75,\n comfortable: 1,\n spacious: 1.25\n} as const;\n","import type { UiColor } from '../properties/UiColor';\nimport type { UiColors } from './UiColors';\n\n/**\n * How much separation a theme keeps between what is drawn and what it\n * is drawn on.\n *\n * `standard` is the palette as the designer wrote it. `high` is the\n * same palette with every foreground pushed away from the surface\n * behind it until it clears a contrast ratio, which is what a person\n * who has turned the operating system's high-contrast setting on is\n * asking for. It is an axis of the theme rather than a second palette\n * so that an application which has already chosen its colours does not\n * have to choose them twice, and so that the accessibility audit has\n * one place to look.\n */\nexport type UiContrast = 'standard' | 'high';\n\n/**\n * The ratio a foreground is raised to at `high`.\n *\n * WCAG's AAA threshold for body text. The stock palettes already clear\n * AA, so raising to AA would leave most tokens untouched and the axis\n * would look as though it did nothing.\n */\nconst HIGH_CONTRAST_RATIO = 7;\n\n/**\n * Relative luminance, as WCAG defines it.\n *\n * Alpha is ignored: a token is compared against the surface it sits\n * on, and what a translucent foreground actually looks like depends on\n * a composite this cannot see. Raising a translucent token toward the\n * extreme is still the right direction.\n */\nexport function relativeLuminance(color: UiColor): number {\n return 0.2126 * channel(color.r) + 0.7152 * channel(color.g) + 0.0722 * channel(color.b);\n}\n\nfunction channel(value: number): number {\n const clamped = Math.min(1, Math.max(0, value));\n return clamped <= 0.03928 ? clamped / 12.92 : Math.pow((clamped + 0.055) / 1.055, 2.4);\n}\n\n/**\n * The WCAG contrast ratio between two colours, from 1 to 21.\n */\nexport function contrastRatio(a: UiColor, b: UiColor): number {\n const light = Math.max(relativeLuminance(a), relativeLuminance(b));\n const dark = Math.min(relativeLuminance(a), relativeLuminance(b));\n return (light + 0.05) / (dark + 0.05);\n}\n\n/**\n * The same colour, moved toward black or white until it clears\n * `ratio` against `against`.\n *\n * Toward whichever extreme is already the further from the surface, so\n * text on a dark ground gets lighter and text on a light ground gets\n * darker: pushing the other way would cross the surface's own\n * luminance and come out worse before it came out better. A colour\n * that cannot reach the ratio even at the extreme is returned at the\n * extreme, which is the best the palette can do and is still an\n * improvement.\n *\n * Mixed in linear steps of the stored channels rather than by solving\n * for the luminance, because the search is sixteen steps and this runs\n * when a theme is built, not when a frame is drawn.\n */\nexport function raiseContrast(color: UiColor, against: UiColor, ratio: number): UiColor {\n if (contrastRatio(color, against) >= ratio) {\n return color;\n }\n const target: UiColor = relativeLuminance(against) > 0.5 ? { r: 0, g: 0, b: 0, a: 1 } : { r: 1, g: 1, b: 1, a: 1 };\n let low = 0;\n let high = 1;\n for (let step = 0; step < 16; step++) {\n const mid = (low + high) / 2;\n if (contrastRatio(mix(color, target, mid), against) >= ratio) {\n high = mid;\n } else {\n low = mid;\n }\n }\n return mix(color, target, high);\n}\n\nfunction mix(from: UiColor, to: UiColor, amount: number): UiColor {\n return {\n r: from.r + (to.r - from.r) * amount,\n g: from.g + (to.g - from.g) * amount,\n b: from.b + (to.b - from.b) * amount,\n a: from.a\n };\n}\n\n/**\n * Which surface each token is read against.\n *\n * A token that is itself a surface is not listed: raising a background\n * against a background is meaningless, and a palette whose grounds all\n * moved would not be the application's palette any more. The rest are\n * foregrounds, and each names the surface it is actually drawn on, so\n * a control's own text is measured against the control and not against\n * the page.\n */\nconst FOREGROUNDS: Readonly<Record<string, keyof UiColors>> = {\n text: 'background',\n textMuted: 'background',\n primary: 'background',\n secondary: 'background',\n border: 'background',\n danger: 'background',\n focusRing: 'background',\n controlForeground: 'controlBackground',\n controlForegroundDisabled: 'controlBackground',\n controlBorder: 'controlBackground',\n controlAccent: 'controlBackground',\n selectionForeground: 'selectionBackground'\n} as const;\n\n/**\n * A palette at high contrast.\n *\n * Every extra name a custom palette added is raised too, against the\n * page background, because a palette that grew a token for its own\n * accent should not be the one thing that stays quiet when the setting\n * is turned on. The named foregrounds above override that default with\n * the surface they are really drawn on.\n */\nexport function highContrastColors(colors: UiColors): UiColors {\n const source = colors as unknown as Readonly<Record<string, UiColor | undefined>>;\n const raised: Record<string, UiColor> = { ...(source as Record<string, UiColor>) };\n for (const name of Object.keys(source)) {\n const value = source[name];\n if (value === undefined || SURFACES.has(name)) {\n continue;\n }\n const againstName = FOREGROUNDS[name] ?? 'background';\n const against = source[againstName];\n if (against === undefined) {\n continue;\n }\n raised[name] = raiseContrast(value, against, HIGH_CONTRAST_RATIO);\n }\n return raised as unknown as UiColors;\n}\n\n/** The tokens that are grounds rather than marks, and are left alone. */\nconst SURFACES: ReadonlySet<string> = new Set([\n 'background',\n 'surface',\n 'shadow',\n 'controlBackground',\n 'controlBackgroundHovered',\n 'controlBackgroundPressed',\n 'selectionBackground'\n]);\n","/**\n * Tokens an application adds to a theme, under its own name.\n *\n * `UiTheme` carries the vocabulary every application shares: colours,\n * type, shapes, shadows, spacing. An application always has more than\n * that, and the two in this repository each grew a module of module\n * level constants to hold it, which is a theme that no provider can\n * change and no appearance toggle can reach.\n *\n * An extension is that module turned into part of the theme:\n *\n * const brand = defineThemeExtension({\n * name: 'brand',\n * defaults: { linen: '#be9a6e', chalk: '#f7f3ea' }\n * });\n *\n * const theme = withThemeExtension(lightTheme, brand, { linen: …, chalk: … });\n * themeExtension(theme, brand).linen\n *\n * The read is a property access on the object the extension was\n * declared with, so an editor completes the token names and a\n * misspelling is a compile error. Nothing about `UiTheme` or\n * `themesEqual` changes to add one: the extensions ride in a map keyed\n * by the symbol `defineThemeExtension` minted, and `themesEqual`\n * compares them with each extension's own comparison.\n *\n * A component in a library may declare an extension too, which is how\n * a component that needs a token the shared vocabulary does not have\n * gets one without adding a prop for it.\n */\nexport interface UiThemeExtension<T extends object> {\n /** Identity, so two extensions cannot collide on a name. */\n readonly key: symbol;\n readonly name: string;\n /** What `themeExtension` returns for a theme that does not carry it. */\n readonly defaults: T;\n readonly equals: (a: T, b: T) => boolean;\n}\n\nexport interface UiThemeExtensionOptions<T extends object> {\n readonly name: string;\n readonly defaults: T;\n /**\n * How two values of this extension are compared, for the environment\n * to decide whether a theme change has to invalidate the subtree.\n *\n * The default compares the group's own keys, and compares each one\n * structurally when it is a plain object, so a group of `UiColor`\n * tokens built freshly on each appearance change is equal to the one\n * before it. It goes no deeper than that: an extension whose tokens\n * are themselves nested groups should pass its own comparison rather\n * than find out later that its theme never invalidates.\n */\n readonly equals?: (a: T, b: T) => boolean;\n}\n\n/** The map a theme carries. Empty for every stock theme. */\nexport type UiThemeExtensions = ReadonlyMap<symbol, object>;\n\nexport const noThemeExtensions: UiThemeExtensions = new Map<symbol, object>();\n\n/**\n * Declares a group of tokens an application or a library adds to a\n * theme. Call it once, at module level, and export the result.\n */\nexport function defineThemeExtension<T extends object>(options: UiThemeExtensionOptions<T>): UiThemeExtension<T> {\n const extension: UiThemeExtension<T> = {\n key: Symbol(options.name),\n name: options.name,\n defaults: options.defaults,\n equals: options.equals ?? shallowEqual\n };\n // A theme carries values, not the extension objects that describe\n // them, so `themeExtensionsEqual` has to find the comparison from\n // the key alone. Registered here, at module load, which is before\n // any theme carrying this extension can exist.\n comparisons.set(extension.key, extension.equals as (a: object, b: object) => boolean);\n return extension;\n}\n\n/** Each extension's comparison, by key. See `defineThemeExtension`. */\nconst comparisons = new Map<symbol, (a: object, b: object) => boolean>();\n\n/** A comparison over the group's own keys, one token deep. */\nfunction shallowEqual<T extends object>(a: T, b: T): boolean {\n if (a === b) {\n return true;\n }\n const left = a as Record<string, unknown>;\n const right = b as Record<string, unknown>;\n const keys = Object.keys(left);\n if (keys.length !== Object.keys(right).length) {\n return false;\n }\n for (const key of keys) {\n if (!tokensEqual(left[key], right[key])) {\n return false;\n }\n }\n return true;\n}\n\n/**\n * One token. A plain object is compared field by field, because the\n * commonest token an extension holds is a `UiColor`, and a palette\n * rebuilt when the appearance changed holds new objects with the same\n * numbers in them.\n */\nfunction tokensEqual(a: unknown, b: unknown): boolean {\n if (Object.is(a, b)) {\n return true;\n }\n if (!isPlainObject(a) || !isPlainObject(b)) {\n return false;\n }\n const keys = Object.keys(a);\n if (keys.length !== Object.keys(b).length) {\n return false;\n }\n for (const key of keys) {\n if (!Object.is(a[key], b[key])) {\n return false;\n }\n }\n return true;\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\n/** What the theme carries for this extension, or its declared defaults. */\nexport function themeExtension<T extends object>(\n theme: { readonly extensions?: UiThemeExtensions },\n extension: UiThemeExtension<T>\n): T {\n const carried = theme.extensions?.get(extension.key);\n return carried === undefined ? extension.defaults : (carried as T);\n}\n\n/** Whether the theme carries this extension at all, rather than falling back. */\nexport function hasThemeExtension<T extends object>(\n theme: { readonly extensions?: UiThemeExtensions },\n extension: UiThemeExtension<T>\n): boolean {\n return theme.extensions?.has(extension.key) === true;\n}\n\n/**\n * The same theme with one extension's tokens set.\n *\n * Returns a new theme; a theme is a value and is compared as one. The\n * extensions map is copied rather than mutated for the same reason,\n * since two themes derived from one base must not share it.\n */\nexport function withThemeExtension<Theme extends { readonly extensions?: UiThemeExtensions }, T extends object>(\n theme: Theme,\n extension: UiThemeExtension<T>,\n value: T\n): Theme {\n const next = new Map(theme.extensions ?? noThemeExtensions);\n next.set(extension.key, value);\n return { ...theme, extensions: next as UiThemeExtensions };\n}\n\n/**\n * Compares the extension maps of two themes.\n *\n * A key one carries and the other does not is a difference, and each\n * key is compared with the comparison its own extension declared. The\n * comparison lives on the value rather than in a registry so that an\n * extension declared in an application is compared as well as one\n * declared here, which is the whole point of the mechanism.\n */\nexport function themeExtensionsEqual(a: UiThemeExtensions | undefined, b: UiThemeExtensions | undefined): boolean {\n const left = a ?? noThemeExtensions;\n const right = b ?? noThemeExtensions;\n if (left === right) {\n return true;\n }\n if (left.size !== right.size) {\n return false;\n }\n for (const [key, value] of left) {\n if (!right.has(key)) {\n return false;\n }\n const other = right.get(key) as object;\n const compare = comparisons.get(key);\n if (compare === undefined) {\n if (!shallowEqual(value, other)) {\n return false;\n }\n continue;\n }\n if (!compare(value, other)) {\n return false;\n }\n }\n return true;\n}\n","import type { UiColors } from './UiColors';\nimport type { UiTypography } from './UiTypography';\nimport type { UiShapes } from './UiShapes';\nimport type { UiShadows } from './UiShadows';\nimport type { UiSpacing } from './UiSpacing';\nimport type { UiDensity } from './UiDensity';\nimport type { UiContrast } from './UiContrast';\nimport type { UiThemeExtensions } from './UiThemeExtension';\nimport { colorsEqualPalette, darkColors, lightColors } from './UiColors';\nimport { typographyEqual } from './UiTypography';\nimport { shapesEqual } from './UiShapes';\nimport { shadowsEqual } from './UiShadows';\nimport { defaultSpacing, scaleSpacing, spacingEqual } from './UiSpacing';\nimport { densityFactors } from './UiDensity';\nimport { highContrastColors } from './UiContrast';\nimport { themeExtensionsEqual } from './UiThemeExtension';\nimport { boxShadow } from '../properties/UiBoxShadow';\n\n/**\n * A renderer-independent theme.\n *\n * A theme bundles colors, typography, shapes, shadows and spacing into\n * a single environment value. It can be provided at any node and is\n * inherited by descendants until another provider overrides it.\n *\n * `density` and `contrast` are axes rather than scales: they record\n * which way this theme was already turned, so a component can branch\n * on the answer and `withDensity` and `withContrast` can turn it\n * again from the base. `extensions` is where an application's own\n * token groups live; see `UiThemeExtension.ts`.\n */\nexport interface UiTheme {\n readonly colors: UiColors;\n readonly typography: UiTypography;\n readonly shapes: UiShapes;\n readonly shadows: UiShadows;\n readonly spacing: UiSpacing;\n readonly density: UiDensity;\n readonly contrast: UiContrast;\n readonly extensions?: UiThemeExtensions;\n}\n\nexport const lightTheme: UiTheme = {\n colors: lightColors,\n typography: {\n body: {\n fontFamily: 'sans-serif',\n fontSize: 14,\n fontWeight: 'normal',\n lineHeight: 16.8,\n letterSpacing: 0,\n color: { r: 0, g: 0, b: 0, a: 1 },\n textAlign: 'start',\n textDirection: 'ltr'\n },\n bodyLarge: {\n fontFamily: 'sans-serif',\n fontSize: 16,\n fontWeight: 'normal',\n lineHeight: 19.2,\n letterSpacing: 0,\n color: { r: 0, g: 0, b: 0, a: 1 },\n textAlign: 'start',\n textDirection: 'ltr'\n },\n bodySmall: {\n fontFamily: 'sans-serif',\n fontSize: 12,\n fontWeight: 'normal',\n lineHeight: 14.4,\n letterSpacing: 0,\n color: { r: 0, g: 0, b: 0, a: 1 },\n textAlign: 'start',\n textDirection: 'ltr'\n },\n headline: {\n fontFamily: 'sans-serif',\n fontSize: 24,\n fontWeight: 'bold',\n lineHeight: 28.8,\n letterSpacing: 0,\n color: { r: 0, g: 0, b: 0, a: 1 },\n textAlign: 'start',\n textDirection: 'ltr'\n },\n title: {\n fontFamily: 'sans-serif',\n fontSize: 20,\n fontWeight: '500',\n lineHeight: 24,\n letterSpacing: 0,\n color: { r: 0, g: 0, b: 0, a: 1 },\n textAlign: 'start',\n textDirection: 'ltr'\n },\n label: {\n fontFamily: 'sans-serif',\n fontSize: 11,\n fontWeight: '500',\n lineHeight: 13.2,\n letterSpacing: 0.5,\n color: { r: 0, g: 0, b: 0, a: 1 },\n textAlign: 'start',\n textDirection: 'ltr'\n }\n },\n spacing: defaultSpacing,\n density: 'comfortable',\n contrast: 'standard',\n shapes: {\n none: 0,\n extraSmall: 2,\n small: 4,\n medium: 8,\n large: 16,\n extraLarge: 24,\n full: 9999\n },\n shadows: {\n none: [],\n extraSmall: [boxShadow(0, 1, 2, 0, { r: 0, g: 0, b: 0, a: 0.05 })],\n small: [boxShadow(0, 1, 3, 0, { r: 0, g: 0, b: 0, a: 0.1 })],\n medium: [\n boxShadow(0, 4, 6, -1, { r: 0, g: 0, b: 0, a: 0.1 }),\n boxShadow(0, 2, 4, -1, { r: 0, g: 0, b: 0, a: 0.06 })\n ],\n large: [\n boxShadow(0, 10, 15, -3, { r: 0, g: 0, b: 0, a: 0.1 }),\n boxShadow(0, 4, 6, -2, { r: 0, g: 0, b: 0, a: 0.05 })\n ],\n extraLarge: [\n boxShadow(0, 20, 25, -5, { r: 0, g: 0, b: 0, a: 0.1 }),\n boxShadow(0, 8, 10, -6, { r: 0, g: 0, b: 0, a: 0.04 })\n ]\n }\n} as const;\n\nexport const darkTheme: UiTheme = {\n ...lightTheme,\n colors: darkColors,\n typography: {\n body: { ...lightTheme.typography.body, color: { r: 1, g: 1, b: 1, a: 1 } },\n bodyLarge: { ...lightTheme.typography.bodyLarge, color: { r: 1, g: 1, b: 1, a: 1 } },\n bodySmall: { ...lightTheme.typography.bodySmall, color: { r: 1, g: 1, b: 1, a: 1 } },\n headline: { ...lightTheme.typography.headline, color: { r: 1, g: 1, b: 1, a: 1 } },\n title: { ...lightTheme.typography.title, color: { r: 1, g: 1, b: 1, a: 1 } },\n label: { ...lightTheme.typography.label, color: { r: 1, g: 1, b: 1, a: 1 } }\n },\n shadows: {\n none: [],\n extraSmall: [boxShadow(0, 1, 2, 0, { r: 0, g: 0, b: 0, a: 0.2 })],\n small: [boxShadow(0, 1, 3, 0, { r: 0, g: 0, b: 0, a: 0.3 })],\n medium: [\n boxShadow(0, 4, 6, -1, { r: 0, g: 0, b: 0, a: 0.35 }),\n boxShadow(0, 2, 4, -1, { r: 0, g: 0, b: 0, a: 0.25 })\n ],\n large: [\n boxShadow(0, 10, 15, -3, { r: 0, g: 0, b: 0, a: 0.4 }),\n boxShadow(0, 4, 6, -2, { r: 0, g: 0, b: 0, a: 0.25 })\n ],\n extraLarge: [\n boxShadow(0, 20, 25, -5, { r: 0, g: 0, b: 0, a: 0.45 }),\n boxShadow(0, 8, 10, -6, { r: 0, g: 0, b: 0, a: 0.3 })\n ]\n }\n} as const;\n\n/**\n * Compares two themes for equality.\n *\n * The extensions are compared with each extension's own comparison, so\n * an application that adds a token group gets invalidation on a change\n * to it without editing this function. That was the point of the\n * mechanism: a theme layer\n * added without extending `themesEqual` is a theme change that does\n * not repaint, and it is easy to forget.\n */\nexport function themesEqual(a: UiTheme, b: UiTheme): boolean {\n return (\n a.density === b.density &&\n a.contrast === b.contrast &&\n colorsEqualPalette(a.colors, b.colors) &&\n typographyEqual(a.typography, b.typography) &&\n shapesEqual(a.shapes, b.shapes) &&\n shadowsEqual(a.shadows, b.shadows) &&\n spacingEqual(a.spacing, b.spacing) &&\n themeExtensionsEqual(a.extensions, b.extensions)\n );\n}\n\n/**\n * The same theme at another density.\n *\n * Derived from the theme it is given rather than from a base, so\n * asking twice for `compact` does not shrink the scale twice: a theme\n * already at that density is returned unchanged.\n */\nexport function withDensity(theme: UiTheme, density: UiDensity): UiTheme {\n if (theme.density === density) {\n return theme;\n }\n const base = scaleSpacing(theme.spacing, 1 / densityFactors[theme.density]);\n return { ...theme, density, spacing: scaleSpacing(base, densityFactors[density]) };\n}\n\n/**\n * The same theme at another contrast.\n *\n * There is no way back from `high`: raising a palette loses what it\n * was, and a theme that has to be able to return keeps its standard\n * self and derives the high-contrast one from it. That is what an\n * application does anyway, since the setting it follows is a cell and\n * both themes exist for the life of the application.\n */\nexport function withContrast(theme: UiTheme, contrast: UiContrast): UiTheme {\n if (theme.contrast === contrast) {\n return theme;\n }\n if (contrast === 'standard') {\n throw new Error('withContrast cannot lower a raised palette; keep the standard theme and derive the high one.');\n }\n return { ...theme, contrast, colors: highContrastColors(theme.colors) };\n}\n","import { BehaviorSubject, distinctUntilChanged, map, type Observable } from 'rxjs';\n\nimport type { Size } from '../layout/LayoutTypes';\n\n/**\n * A box's content size as it changes, for the things that branch on\n * it.\n *\n * The value behind `UiEnvironmentKeys.containerSize`, and deliberately\n * a *source* rather than a size. An environment value is a snapshot\n * that a subtree caches, so putting a number in one would mean\n * rebuilding the environment of everything under a container on every\n * pixel of a drag. The source object never changes identity, so the\n * environment is built once; what changes is what the source reports,\n * and only the code that asked to hear about it does any work.\n *\n * A media query is the wrong tool for this and is why the environment\n * carries the container and not the window. `observeMediaQuery` needs\n * a window, the runtime that would branch on it is usually in a\n * worker, and the question a component actually has is \"how much room\n * do I have\", which is not the window's width in any layout with a\n * sidebar in it.\n */\nexport interface UiContainerSize {\n /** The last size reported, or zeroes before the first layout. */\n readonly current: Size;\n /** Every distinct size, starting with `current`. */\n readonly changes: Observable<Size>;\n}\n\n/**\n * A container size nothing has measured yet.\n *\n * The default for the environment key, so a component that reads the\n * key outside any container gets zeroes and one emission rather than\n * an error. A layout branching on zero picks its narrowest arm, which\n * is the right guess for something whose room is unknown.\n */\nexport const unknownContainerSize: UiContainerSize = {\n current: { width: 0, height: 0 },\n changes: new BehaviorSubject<Size>({ width: 0, height: 0 }).asObservable()\n};\n\n/**\n * A container size a modifier feeds from the layout pass.\n *\n * `report` is called by `sizeContainer` after any frame that changed\n * the node's box; the value is deduplicated here rather than at every\n * consumer, because a scroll moves a box without resizing it and\n * reports the same numbers again.\n */\nexport class UiContainerSizeSource implements UiContainerSize {\n private readonly subject = new BehaviorSubject<Size>({ width: 0, height: 0 });\n\n get current(): Size {\n return this.subject.value;\n }\n\n get changes(): Observable<Size> {\n return this.subject.asObservable();\n }\n\n report(width: number, height: number): void {\n const previous = this.subject.value;\n if (previous.width === width && previous.height === height) {\n return;\n }\n this.subject.next({ width, height });\n }\n}\n\n/**\n * The band a width falls into, given the widths a layout switches at.\n *\n * The number the layout should be *built* from, rather than the width\n * itself: children rebuilt on every pixel of a resize would allocate a\n * subtree per frame of a drag, which is the\n * \"sugar that hides cost\" in the one place it would be most expensive.\n * A width of 900 against `[600, 1200]` gives 600, and every width from\n * 600 to 1199 gives the same 600, so the children are built once for\n * the whole band.\n *\n * Widths below the first breakpoint give 0, which is the band a layout\n * writes its narrowest arm for.\n */\nexport function bandOf(width: number, breakpoints: readonly number[]): number {\n let band = 0;\n for (const breakpoint of breakpoints) {\n if (width >= breakpoint) {\n band = breakpoint;\n }\n }\n return band;\n}\n\n/**\n * The width bands of a container, one value per band entered.\n *\n * What `Responsive` builds its children from, and what an author who\n * wants only a number rather than a subtree can subscribe to directly.\n */\nexport function containerBands(size: UiContainerSize, breakpoints: readonly number[]): Observable<number> {\n return size.changes.pipe(\n map(measured => bandOf(measured.width, breakpoints)),\n distinctUntilChanged()\n );\n}\n","import { BehaviorSubject, type Observable } from 'rxjs';\n\n/** Space along each edge that something else has taken. */\nexport interface UiInsets {\n readonly top: number;\n readonly right: number;\n readonly bottom: number;\n readonly left: number;\n}\n\n/** One edge of a box, named physically. */\nexport type UiInsetEdge = 'top' | 'right' | 'bottom' | 'left';\n\nexport const noInsets: UiInsets = { top: 0, right: 0, bottom: 0, left: 0 };\n\nexport function insetsEqual(a: UiInsets, b: UiInsets): boolean {\n return a.top === b.top && a.right === b.right && a.bottom === b.bottom && a.left === b.left;\n}\n\n/**\n * What is in the way of the content, and how much of it there is.\n *\n * The value behind `UiEnvironmentKeys.insets`, and a source for the\n * same reason `UiContainerSize` is: the numbers change while a\n * keyboard slides up, and an environment value that changed with them\n * would rebuild the environment of the whole screen forty times.\n *\n * Three quite different things end up on the same four numbers, which\n * is the point of having them: the platform's safe area (a notch, a\n * home indicator, a window's rounded corner), the soft keyboard, and\n * whatever the application itself has floating over its own content.\n * A screen that keeps its last row clear of all three should not have\n * to know which of the three it is clearing, and before this every\n * Segue screen knew about exactly one of them by name and about the\n * height of the bar that caused it.\n */\nexport interface UiInsetSource {\n /** The largest contribution on each edge, as it stands. */\n readonly current: UiInsets;\n /** Every distinct set of insets, starting with `current`. */\n readonly changes: Observable<UiInsets>;\n}\n\n/**\n * The insets in force, gathered from everything that publishes one.\n *\n * Contributions compose by **maximum per edge, not by sum**. Two\n * things over the same edge overlap far more often than they stack: a\n * bar drawn across the home indicator already covers the safe area\n * under it, and a soft keyboard that pushes a bar up covers it too.\n * Adding them would push the content clear of a strip nothing is\n * occupying, and nobody would notice until the keyboard was open on a\n * phone. A publisher whose bar genuinely sits on top of another one\n * publishes the total it occupies, because it is the only thing that\n * knows.\n *\n * Publishing is by handle, and the handle retracts. That is what makes\n * this usable from a modifier: the bar's contribution goes away when\n * the bar unmounts, without the registry knowing what a bar is.\n */\nexport class UiInsetRegistry implements UiInsetSource {\n private readonly contributions = new Map<symbol, UiInsets>();\n private readonly subject = new BehaviorSubject<UiInsets>(noInsets);\n\n get current(): UiInsets {\n return this.subject.value;\n }\n\n get changes(): Observable<UiInsets> {\n return this.subject.asObservable();\n }\n\n /**\n * Publishes one contributor's insets, replacing whatever it\n * published before. The returned function retracts them.\n */\n publish(insets: Partial<UiInsets>): (next?: Partial<UiInsets>) => void {\n const token = Symbol('inset');\n const write = (next?: Partial<UiInsets>): void => {\n if (next === undefined) {\n this.contributions.delete(token);\n } else {\n this.contributions.set(token, { ...noInsets, ...next });\n }\n this.recompute();\n };\n write(insets);\n return write;\n }\n\n private recompute(): void {\n let top = 0;\n let right = 0;\n let bottom = 0;\n let left = 0;\n for (const contribution of this.contributions.values()) {\n top = Math.max(top, contribution.top);\n right = Math.max(right, contribution.right);\n bottom = Math.max(bottom, contribution.bottom);\n left = Math.max(left, contribution.left);\n }\n const next: UiInsets = { top, right, bottom, left };\n if (!insetsEqual(this.subject.value, next)) {\n this.subject.next(next);\n }\n }\n}\n\n/**\n * The insets a thread that has a window can see, as plain numbers.\n *\n * Both halves come from the same place. `visualViewport` reports the\n * part of the page the person can actually see, so the strip a soft\n * keyboard covers is `layoutViewport.height - visualViewport.height`\n * once the offset is taken off; the safe area comes from the four\n * `env(safe-area-inset-*)` values, read off a probe element because\n * `env()` is only legal in CSS.\n *\n * **Shell side, and only shell side.** `visualViewport` needs a\n * window, and the runtime that decides what to do about a keyboard is\n * usually in a worker. What crosses the boundary is these four\n * numbers, which is the thread model's rule:\n * the shell holds what only it can hold and posts plain data, and\n * every decision about the data is taken on the far side. Nothing\n * here reads a Gesso object, and the caller passes what it hears to\n * `UiInsetRegistry.publish`.\n *\n * Reports once immediately as well as on change, for the same reason\n * `observeMediaQuery` does: a keyboard that is already open, or a\n * phone whose notch has been there all along, sends no event.\n *\n * Returns a function that stops watching. Where there is no\n * `visualViewport` it reports zeroes once and stops, which is the\n * honest answer on a desktop window with no notch.\n */\nexport function observeViewportInsets(onChange: (insets: UiInsets) => void): () => void {\n const view = globalThis as {\n visualViewport?: VisualViewportLike;\n innerHeight?: number;\n getComputedStyle?: (element: object) => { getPropertyValue(name: string): string };\n document?: DocumentLike;\n };\n const viewport = view.visualViewport;\n if (viewport === undefined) {\n onChange(noInsets);\n return () => {};\n }\n let last: UiInsets | null = null;\n const report = (): void => {\n const safeArea = readSafeArea(view);\n // What the keyboard covers: the room the layout thinks it has,\n // less the room that is actually visible, less how far the page\n // has been scrolled up out of the way to make room.\n const covered = Math.max(0, (view.innerHeight ?? viewport.height) - viewport.height - viewport.offsetTop);\n const next: UiInsets = {\n top: safeArea.top,\n right: safeArea.right,\n bottom: Math.max(safeArea.bottom, covered),\n left: safeArea.left\n };\n if (last === null || !insetsEqual(last, next)) {\n last = next;\n onChange(next);\n }\n };\n report();\n viewport.addEventListener('resize', report);\n viewport.addEventListener('scroll', report);\n return () => {\n viewport.removeEventListener('resize', report);\n viewport.removeEventListener('scroll', report);\n };\n}\n\n/** Only the parts of `VisualViewport` this reads, so core needs no DOM lib. */\ninterface VisualViewportLike {\n readonly height: number;\n readonly offsetTop: number;\n addEventListener(type: string, listener: () => void): void;\n removeEventListener(type: string, listener: () => void): void;\n}\n\ninterface DocumentLike {\n readonly documentElement?: object;\n}\n\n/**\n * The four `env(safe-area-inset-*)` values, in pixels.\n *\n * Read off the document element's computed style through four custom\n * properties, which is the only way to get at `env()` from script: the\n * page's stylesheet has to declare `--gesso-safe-area-top: env(...)`\n * for these to be anything but empty, and an application that has not\n * declared them gets zeroes rather than a failure. That is the same\n * bargain the template's stylesheet strikes for the colour scheme.\n */\nfunction readSafeArea(view: {\n getComputedStyle?: (element: object) => { getPropertyValue(name: string): string };\n document?: DocumentLike;\n}): UiInsets {\n const element = view.document?.documentElement;\n if (element === undefined || typeof view.getComputedStyle !== 'function') {\n return noInsets;\n }\n const style = view.getComputedStyle(element);\n return {\n top: pixels(style.getPropertyValue('--gesso-safe-area-top')),\n right: pixels(style.getPropertyValue('--gesso-safe-area-right')),\n bottom: pixels(style.getPropertyValue('--gesso-safe-area-bottom')),\n left: pixels(style.getPropertyValue('--gesso-safe-area-left'))\n };\n}\n\nfunction pixels(value: string): number {\n const parsed = Number.parseFloat(value);\n return Number.isFinite(parsed) && parsed > 0 ? parsed : 0;\n}\n","import { createEnvironmentKey } from './UiEnvironmentKey';\nimport type { UiTheme } from './UiTheme';\nimport type { UiTextStyle } from '../properties/UiTextStyle';\nimport type { UiColor } from '../properties/UiColor';\nimport { lightTheme, themesEqual } from './UiTheme';\nimport { defaultTextStyle, textStylesEqual } from '../properties/UiTextStyle';\nimport { UiBasicColors, colorsEqual } from '../properties/UiColor';\nimport type { UiContainerSize } from './UiContainerSize';\nimport { unknownContainerSize } from './UiContainerSize';\nimport type { UiInsetSource } from './UiInsets';\nimport { UiInsetRegistry } from './UiInsets';\n\n/**\n * Built-in environment keys.\n *\n * These are the scoped values that nodes can provide and\n * descendants can resolve. Additional keys can be defined anywhere\n * by calling createEnvironmentKey().\n */\nexport const UiEnvironmentKeys = {\n theme: createEnvironmentKey<UiTheme>({\n name: 'theme',\n defaultValue: lightTheme,\n compare: themesEqual\n }),\n\n textStyle: createEnvironmentKey<UiTextStyle>({\n name: 'textStyle',\n defaultValue: defaultTextStyle,\n compare: textStylesEqual\n }),\n\n contentColor: createEnvironmentKey<UiColor>({\n name: 'contentColor',\n defaultValue: UiBasicColors.black,\n compare: colorsEqual\n }),\n\n /**\n * How much room the nearest container that declared itself one has,\n * as it changes. Provided by `Responsive` and by the\n * `containerSize` property; see `UiContainerSize`.\n */\n containerSize: createEnvironmentKey<UiContainerSize>({\n name: 'containerSize',\n defaultValue: unknownContainerSize\n }),\n\n /**\n * What is in the way of the content on each edge: the platform's\n * safe area, the soft keyboard, and whatever the application floats\n * over itself. See `UiInsets`.\n *\n * The default is an empty registry rather than a constant, so a\n * screen mounted outside any provider can still publish into one and\n * read the result back. It is a shared object, which is fine because\n * a runtime with no provider has one screen in it; an application\n * with two windows provides one per window.\n */\n insets: createEnvironmentKey<UiInsetSource>({\n name: 'insets',\n defaultValue: new UiInsetRegistry()\n })\n} as const;\n","import type { DirtyFlags } from '../graph/DirtyFlags';\nimport type { UiEnvironmentKey } from '../environment/UiEnvironmentKey';\n\n/**\n * Metadata describing a single UI property.\n *\n * The runtime uses this definition to know:\n *\n * - what the property is called\n * - what value to use when none is specified\n * - whether the value inherits from the scoped environment\n * - what changing the value invalidates\n * - how to compare two values for equality\n *\n * A property may optionally declare an environment key and a\n * resolver that extracts the property value from that environment\n * value. When `environmentKey` is absent, inherited properties look\n * for an environment key whose name matches the property name.\n */\nexport interface UiPropertyDefinition<T> {\n readonly name: string;\n readonly defaultValue: T;\n readonly inherited: boolean;\n readonly affects: DirtyFlags;\n readonly compare?: (a: T, b: T) => boolean;\n readonly environmentKey?: UiEnvironmentKey<unknown>;\n readonly resolveFromEnvironment?: (value: unknown) => T;\n /**\n * Rejects a value the property cannot hold, returning the message\n * for the error the builder throws. Declared only by properties with\n * a closed set of values, such as `role`; the builder checks it when\n * a plain value is written, so it costs nothing on the graph's own\n * write path. A value arriving through an Observable is checked by\n * whatever reads it, as a bound length is checked at layout.\n */\n readonly validate?: (value: T) => string | undefined;\n}\n\n/**\n * Creates a property definition with the supplied metadata.\n *\n * The default compare function is reference equality (`Object.is`).\n */\nexport function defineProperty<T>(\n options: Omit<UiPropertyDefinition<T>, 'name'> & { name: string }\n): UiPropertyDefinition<T> {\n return {\n name: options.name,\n defaultValue: options.defaultValue,\n inherited: options.inherited,\n affects: options.affects,\n compare: options.compare,\n environmentKey: options.environmentKey,\n resolveFromEnvironment: options.resolveFromEnvironment,\n validate: options.validate\n };\n}\n\n/**\n * Compares two property values using the definition's comparison\n * function, falling back to `Object.is` when none is provided.\n */\nexport function propertyValuesEqual<T>(definition: UiPropertyDefinition<T>, a: T, b: T): boolean {\n if (definition.compare !== undefined) {\n return definition.compare(a, b);\n }\n return Object.is(a, b);\n}\n","/**\n * Renderer-independent border radius description.\n *\n * Each corner is measured in logical pixels. A single scalar radius\n * can be expressed by setting all four corners to the same value.\n */\nexport interface UiBorderRadius {\n readonly topLeft: number;\n readonly topRight: number;\n readonly bottomRight: number;\n readonly bottomLeft: number;\n}\n\nexport const UiBorderRadiuses = {\n none: { topLeft: 0, topRight: 0, bottomRight: 0, bottomLeft: 0 }\n} as const;\n\n/**\n * Creates a uniform border radius.\n */\nexport function borderRadius(radius: number): UiBorderRadius {\n return {\n topLeft: radius,\n topRight: radius,\n bottomRight: radius,\n bottomLeft: radius\n };\n}\n\n/**\n * Creates a border radius with per-corner values.\n */\nexport function borderRadiusCorners(\n topLeft: number,\n topRight: number,\n bottomRight: number,\n bottomLeft: number\n): UiBorderRadius {\n return { topLeft, topRight, bottomRight, bottomLeft };\n}\n\n/**\n * Compares two border radii for equality.\n */\nexport function borderRadiusEqual(a: UiBorderRadius, b: UiBorderRadius): boolean {\n return (\n a.topLeft === b.topLeft &&\n a.topRight === b.topRight &&\n a.bottomRight === b.bottomRight &&\n a.bottomLeft === b.bottomLeft\n );\n}\n\n/**\n * Returns true when every corner radius is zero.\n */\nexport function borderRadiusIsZero(radius: UiBorderRadius): boolean {\n return radius.topLeft === 0 && radius.topRight === 0 && radius.bottomRight === 0 && radius.bottomLeft === 0;\n}\n\n/**\n * Returns a single scalar radius for renderers that do not yet\n * support per-corner radii. This is a temporary bridge; per-corner\n * support belongs in each renderer.\n */\nexport function uniformBorderRadius(radius: UiBorderRadius): number {\n return Math.max(radius.topLeft, radius.topRight, radius.bottomRight, radius.bottomLeft);\n}\n\n/**\n * Normalizes a border radius value to a UiBorderRadius.\n *\n * Numbers are expanded to a uniform radius; UiBorderRadius objects\n * pass through unchanged.\n */\nfunction clampRadius(value: number): number {\n return Math.max(0, value);\n}\n\nexport function normalizeBorderRadius(value: unknown): UiBorderRadius {\n if (typeof value === 'number') {\n return borderRadius(clampRadius(value));\n }\n if (typeof value === 'object' && value !== null) {\n const candidate = value as Partial<UiBorderRadius>;\n return {\n topLeft: clampRadius(candidate.topLeft ?? 0),\n topRight: clampRadius(candidate.topRight ?? 0),\n bottomRight: clampRadius(candidate.bottomRight ?? 0),\n bottomLeft: clampRadius(candidate.bottomLeft ?? 0)\n };\n }\n return UiBorderRadiuses.none;\n}\n\n/**\n * Equality for border radius property values, used by the registry to\n * decide whether a change repaints.\n *\n * Two literal radii compare corner by corner; a scale name compares by\n * name, because what it draws depends on a theme this comparison\n * cannot see. That is the same rule and the same reason as\n * `colorValuesEqual`, and without it every name would normalize to\n * `none` and `'small'` changing to `'large'` would look like no change\n * at all.\n */\nexport function borderRadiusValuesEqual(a: unknown, b: unknown): boolean {\n if (Object.is(a, b)) {\n return true;\n }\n // One name and one literal are never the same value, and two\n // different names are two different lookups. Either way the answer\n // is no, and normalizing first would wrongly say yes.\n if (typeof a === 'string' || typeof b === 'string') {\n return false;\n }\n return borderRadiusEqual(normalizeBorderRadius(a), normalizeBorderRadius(b));\n}\n","/**\n * Length values accepted by size and offset properties.\n *\n * A plain number is logical pixels. Anything else is a small tagged\n * object built by the helpers below — never a string to parse — so a\n * typo is a type error, and a malformed value reaching the engine at\n * runtime throws at layout rather than silently becoming zero.\n *\n * width: 200 // pixels\n * width: percent(50) // half of the containing size, when it is\n * // definite; behaves as `auto` otherwise\n * margin: auto // main-axis auto margins absorb free space;\n * // cross-axis ones centre the item\n * minWidth: auto // the default: a flex item's automatic\n * // minimum, its min-content size\n */\n\nexport interface PercentLength {\n readonly unit: 'percent';\n readonly value: number;\n}\n\nexport interface AutoLength {\n readonly unit: 'auto';\n}\n\nexport type UiLength = number | PercentLength | AutoLength;\n\n/** A grid track that takes a share of free space, `fr(1)`. */\nexport interface FrLength {\n readonly unit: 'fr';\n readonly value: number;\n}\n\n/** A grid track bounded below and above, `minmax(100, fr(1))`. */\nexport interface MinMaxTrack {\n readonly unit: 'minmax';\n readonly min: number | PercentLength | AutoLength;\n readonly max: number | PercentLength | AutoLength | FrLength;\n}\n\n/** What a grid's `columns` / `rows` arrays hold. */\nexport type UiTrackSize = number | PercentLength | AutoLength | FrLength | MinMaxTrack;\n\nexport function fr(value: number): FrLength {\n if (!(value >= 0) || !Number.isFinite(value)) {\n throw new Error(`fr(): expected a non-negative finite number, got ${String(value)}.`);\n }\n return { unit: 'fr', value };\n}\n\nexport function minmax(min: MinMaxTrack['min'], max: MinMaxTrack['max']): MinMaxTrack {\n return { unit: 'minmax', min, max };\n}\n\n/** `repeat(3, fr(1))` → three `fr(1)` tracks; several sizes repeat as a pattern. */\nexport function repeat(count: number, ...sizes: UiTrackSize[]): UiTrackSize[] {\n if (!Number.isInteger(count) || count < 0) {\n throw new Error(`repeat(): expected a non-negative integer count, got ${String(count)}.`);\n }\n if (sizes.length === 0) {\n throw new Error('repeat(): expected at least one track size.');\n }\n const tracks: UiTrackSize[] = [];\n for (let i = 0; i < count; i++) {\n tracks.push(...sizes);\n }\n return tracks;\n}\n\nexport function isFrLength(value: unknown): value is FrLength {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as FrLength).unit === 'fr' &&\n typeof (value as FrLength).value === 'number'\n );\n}\n\nexport function isMinMaxTrack(value: unknown): value is MinMaxTrack {\n return typeof value === 'object' && value !== null && (value as MinMaxTrack).unit === 'minmax';\n}\n\nexport function percent(value: number): PercentLength {\n if (!Number.isFinite(value)) {\n throw new Error(`percent(): expected a finite number, got ${String(value)}.`);\n }\n return { unit: 'percent', value };\n}\n\nexport const auto: AutoLength = Object.freeze({ unit: 'auto' });\n\nexport function isAutoLength(value: unknown): value is AutoLength | 'auto' {\n return value === 'auto' || (typeof value === 'object' && value !== null && (value as AutoLength).unit === 'auto');\n}\n\nexport function isPercentLength(value: unknown): value is PercentLength {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as PercentLength).unit === 'percent' &&\n typeof (value as PercentLength).value === 'number'\n );\n}\n\n/**\n * Resolves a property value to pixels.\n *\n * Returns `undefined` when the property is unset, `null`, `auto`, or a\n * percentage of an indefinite size — every case the caller treats as\n * \"no value\". Returns `'auto'` only when `keepAuto` is set, for the\n * properties where auto means something (margins, minimum sizes).\n *\n * Anything else that is not a finite number or a tagged length throws,\n * naming the property: `width: '100%'` must fail loudly, not lay out\n * as if the property were absent.\n */\nexport function resolveLength(\n value: unknown,\n base: number | undefined,\n property: string,\n keepAuto = false\n): number | undefined | 'auto' {\n if (value === undefined || value === null) {\n return undefined;\n }\n if (typeof value === 'number') {\n if (!Number.isFinite(value)) {\n throw new Error(`Property '${property}' must be a finite number, got ${String(value)}.`);\n }\n return value;\n }\n if (isAutoLength(value)) {\n return keepAuto ? 'auto' : undefined;\n }\n if (isPercentLength(value)) {\n if (base === undefined || !Number.isFinite(base)) {\n return undefined;\n }\n return (base * value.value) / 100;\n }\n throw new Error(\n `Property '${property}' has an invalid length ${describe(value)}. Use a number of pixels, percent(n), or auto.`\n );\n}\n\nfunction describe(value: unknown): string {\n if (typeof value === 'string') {\n return `'${value}'`;\n }\n try {\n return JSON.stringify(value) ?? String(value);\n } catch {\n return String(value);\n }\n}\n","import type { PercentLength } from '../layout/UiLength';\nimport { isPercentLength } from '../layout/UiLength';\nimport type { UiColor } from './UiColor';\nimport type { UiColorValue } from './UiPropertyValues';\nimport { colorValuesEqual } from './UiColor';\n\n/**\n * Renderer-independent gradient descriptions.\n *\n * A gradient is a paint, not a colour: it is what a box's background\n * is filled with instead of one flat value, and both backends have to\n * arrive at the same pixels from it. So the description here is\n * geometry plus stops, with nothing renderer-shaped in it, and the two\n * renderers share the arithmetic in `gradientPaint` below rather than\n * each deriving a gradient line of its own.\n *\n * Lengths follow the rest of the framework: a plain number is logical\n * pixels and `percent(n)` is a fraction of whatever the value is a\n * fraction of, never a string to parse. For a stop that is the length\n * of the gradient itself, so `percent(50)` is halfway along it whatever\n * the box measures, and `24` is 24 pixels from its start.\n */\n\n/** How far along a gradient a stop sits. */\nexport type UiGradientOffset = number | PercentLength;\n\nexport interface UiGradientStop {\n /**\n * Omitted on every stop of a gradient means \"spread them evenly\",\n * which is what almost every gradient wants. Omitted on only some of\n * them is an error rather than a guess: CSS's rule for filling the\n * gaps is subtle enough that a reader could not predict the result.\n */\n readonly offset?: UiGradientOffset;\n /**\n * A palette name resolves against the theme the node inherits, so a\n * themed gradient follows a theme change exactly as `backgroundColor`\n * does.\n */\n readonly color: UiColorValue;\n}\n\nexport interface UiLinearGradient {\n readonly kind: 'linear';\n /**\n * Direction in radians, on CSS's compass: 0 points at the top of the\n * box and the angle turns clockwise, so `Math.PI / 2` runs left to\n * right and `Math.PI` runs top to bottom.\n */\n readonly angle: number;\n readonly stops: readonly UiGradientStop[];\n}\n\nexport interface UiRadialGradient {\n readonly kind: 'radial';\n /** The centre, from the box's top-left. Defaults to `percent(50)` on both axes. */\n readonly centerX?: UiGradientOffset;\n readonly centerY?: UiGradientOffset;\n /**\n * The radius of the outermost stop. `percent(100)`, the default, is\n * the distance from the centre to the box's farthest corner, which is\n * CSS's `farthest-corner`.\n */\n readonly radius?: UiGradientOffset;\n readonly stops: readonly UiGradientStop[];\n}\n\nexport type UiGradient = UiLinearGradient | UiRadialGradient;\n\n/**\n * The most stops one gradient may carry.\n *\n * The WebGPU side stores a gradient as a fixed-size slab in a storage\n * buffer, because a variable-length record would need a second buffer\n * of stops and an index into it for what is, in every real interface, a\n * handful of colours. Eight keeps a record at twelve `vec4`s, and a\n * ninth stop is a loud error rather than a stop that quietly vanishes:\n * see `validateGradient`.\n */\nexport const MAX_GRADIENT_STOPS = 8;\n\n/**\n * A linear gradient at `angle` radians, clockwise from the top.\n *\n * linearGradient(Math.PI, [{ color: '#0ea5e9' }, { color: '#1e293b' }])\n */\nexport function linearGradient(angle: number, stops: readonly UiGradientStop[]): UiLinearGradient {\n return checked({ kind: 'linear', angle, stops });\n}\n\n/** A radial gradient, centred and sized as `UiRadialGradient` describes. */\nexport function radialGradient(\n stops: readonly UiGradientStop[],\n options: Omit<UiRadialGradient, 'kind' | 'stops'> = {}\n): UiRadialGradient {\n return checked({ kind: 'radial', ...options, stops });\n}\n\nfunction checked<T extends UiGradient>(gradient: T): T {\n const message = validateGradient(gradient);\n if (message !== undefined) {\n throw new Error(message);\n }\n return gradient;\n}\n\n/**\n * Rejects a gradient the renderers cannot draw, returning the message\n * for the error the caller raises.\n *\n * The property registry calls this when a plain value is written, so a\n * bad gradient fails where it was authored. A gradient arriving through\n * an Observable is checked by `resolveGradient` instead, at paint,\n * which is where a bound length is checked too.\n */\nexport function validateGradient(value: unknown): string | undefined {\n if (value === undefined) {\n return undefined;\n }\n const gradient = value as Partial<UiGradient>;\n if (typeof value !== 'object' || value === null) {\n return `backgroundGradient: expected a gradient, got ${String(value)}. Use linearGradient() or radialGradient().`;\n }\n if (gradient.kind !== 'linear' && gradient.kind !== 'radial') {\n return `backgroundGradient: unknown gradient kind '${String(gradient.kind)}'. Use 'linear' or 'radial'.`;\n }\n if (gradient.kind === 'linear' && !Number.isFinite((gradient as UiLinearGradient).angle)) {\n return `backgroundGradient: a linear gradient needs a finite angle in radians, got ${String(\n (gradient as UiLinearGradient).angle\n )}.`;\n }\n const stops = gradient.stops;\n if (!Array.isArray(stops)) {\n return 'backgroundGradient: a gradient needs a `stops` array.';\n }\n if (stops.length < 2) {\n return `backgroundGradient: a gradient needs at least two stops, got ${stops.length}.`;\n }\n if (stops.length > MAX_GRADIENT_STOPS) {\n return (\n `backgroundGradient: ${stops.length} stops exceeds the ${MAX_GRADIENT_STOPS} a gradient may carry. ` +\n `The WebGPU backend stores a gradient as a fixed-size record, so the limit is a hard one; ` +\n `approximate the ramp with ${MAX_GRADIENT_STOPS} stops, or stack two gradients.`\n );\n }\n let placed = 0;\n for (const stop of stops as readonly UiGradientStop[]) {\n if (stop === null || typeof stop !== 'object') {\n return `backgroundGradient: expected a stop object, got ${String(stop)}.`;\n }\n if (stop.offset !== undefined) {\n placed++;\n if (!isGradientOffset(stop.offset)) {\n return `backgroundGradient: a stop offset must be a number of pixels or percent(n), got ${String(stop.offset)}.`;\n }\n }\n }\n if (placed !== 0 && placed !== stops.length) {\n return (\n `backgroundGradient: ${placed} of ${stops.length} stops carry an offset. ` +\n 'Give every stop an offset, or none of them, in which case they spread evenly.'\n );\n }\n if (gradient.kind === 'radial') {\n const radial = gradient as UiRadialGradient;\n for (const [name, offset] of [\n ['centerX', radial.centerX],\n ['centerY', radial.centerY],\n ['radius', radial.radius]\n ] as const) {\n if (offset !== undefined && !isGradientOffset(offset)) {\n return `backgroundGradient: ${name} must be a number of pixels or percent(n), got ${String(offset)}.`;\n }\n }\n }\n return undefined;\n}\n\nfunction isGradientOffset(value: unknown): value is UiGradientOffset {\n return (typeof value === 'number' && Number.isFinite(value)) || isPercentLength(value);\n}\n\n/** Whether two gradient property values would paint the same, for the registry. */\nexport function gradientsEqual(a: UiGradient | undefined, b: UiGradient | undefined): boolean {\n if (a === b) {\n return true;\n }\n if (a === undefined || b === undefined || a.kind !== b.kind) {\n return false;\n }\n if (a.kind === 'linear' && b.kind === 'linear') {\n if (a.angle !== b.angle) {\n return false;\n }\n } else if (a.kind === 'radial' && b.kind === 'radial') {\n if (\n !offsetsEqual(a.centerX, b.centerX) ||\n !offsetsEqual(a.centerY, b.centerY) ||\n !offsetsEqual(a.radius, b.radius)\n ) {\n return false;\n }\n }\n if (a.stops.length !== b.stops.length) {\n return false;\n }\n for (let i = 0; i < a.stops.length; i++) {\n if (!offsetsEqual(a.stops[i].offset, b.stops[i].offset) || !colorValuesEqual(a.stops[i].color, b.stops[i].color)) {\n return false;\n }\n }\n return true;\n}\n\nfunction offsetsEqual(a: UiGradientOffset | undefined, b: UiGradientOffset | undefined): boolean {\n if (a === b) {\n return true;\n }\n if (isPercentLength(a) && isPercentLength(b)) {\n return a.value === b.value;\n }\n return false;\n}\n\n// ---------------------------------------------------------------------------\n// Paint-time resolution\n// ---------------------------------------------------------------------------\n\nexport interface ResolvedGradientStop {\n readonly offset: UiGradientOffset | undefined;\n readonly color: UiColor;\n}\n\n/**\n * A gradient with its palette names resolved against the node's theme,\n * and nothing else changed.\n *\n * Geometry stays as it was authored because it needs the node's box,\n * which `resolvePaintState` does not have: the renderer turns this into\n * a `GradientPaint` once it knows the record. Splitting it that way\n * also means the theme is read once per node per frame rather than once\n * per stop per pixel.\n */\nexport type ResolvedGradient =\n | { readonly kind: 'linear'; readonly angle: number; readonly stops: readonly ResolvedGradientStop[] }\n | {\n readonly kind: 'radial';\n readonly centerX: UiGradientOffset | undefined;\n readonly centerY: UiGradientOffset | undefined;\n readonly radius: UiGradientOffset | undefined;\n readonly stops: readonly ResolvedGradientStop[];\n };\n\n/**\n * Note that the resolution itself, `resolveGradient`, lives in\n * `UiThemeColor.ts` rather than here. The registry imports this file\n * for `gradientsEqual` and `validateGradient`, and the theme lookup\n * reads properties, so a gradient that resolved its own stops would\n * close a cycle through the registry. It is the same split that keeps\n * `colorValuesEqual` in `UiColor.ts`.\n */\n\n/**\n * A gradient placed in a box: geometry in the box's own coordinates,\n * with the origin at its top-left, and stop offsets as fractions of the\n * gradient's length.\n *\n * This is the shared form both renderers draw from. Canvas2D adds the\n * box's origin and hands the numbers to `createLinearGradient`; the\n * WebGPU builder writes them into the frame's gradient buffer and the\n * fragment shader evaluates the same ramp per pixel.\n */\nexport interface GradientPaint {\n readonly kind: 'linear' | 'radial';\n /** Linear: the start of the gradient line. Radial: the centre. */\n readonly x0: number;\n readonly y0: number;\n /** Linear: the end of the gradient line. Radial: the centre again. */\n readonly x1: number;\n readonly y1: number;\n /** Radial only; zero for a linear gradient. */\n readonly radius: number;\n readonly stops: readonly { readonly offset: number; readonly color: UiColor }[];\n}\n\n/**\n * Places a resolved gradient in a box of the given size.\n *\n * The linear case is CSS's: the gradient line runs through the centre\n * of the box in the direction of the angle, and it is long enough that\n * the two corners nearest its ends sit exactly on its endpoints, which\n * is `|w·sin| + |h·cos|`. The radial case is a circle, centred where\n * the gradient says and reaching the farthest corner at `percent(100)`.\n *\n * Offsets are clamped into `[0, 1]` and forced to not go backwards, as\n * CSS forces them, so the two backends receive one already-sorted list\n * and neither has to decide what a stop behind its predecessor means.\n */\nexport function gradientPaint(gradient: ResolvedGradient, width: number, height: number): GradientPaint {\n if (gradient.kind === 'linear') {\n const dx = Math.sin(gradient.angle);\n // Screen y grows downwards, so the vector for \"towards the top\" is\n // negative in y; this is the whole of the difference between CSS's\n // compass and the coordinates the renderers work in.\n const dy = -Math.cos(gradient.angle);\n const length = Math.abs(width * dx) + Math.abs(height * dy);\n const cx = width / 2;\n const cy = height / 2;\n return {\n kind: 'linear',\n x0: cx - (dx * length) / 2,\n y0: cy - (dy * length) / 2,\n x1: cx + (dx * length) / 2,\n y1: cy + (dy * length) / 2,\n radius: 0,\n stops: placeStops(gradient.stops, length)\n };\n }\n const cx = resolveOffset(gradient.centerX, width, width / 2);\n const cy = resolveOffset(gradient.centerY, height, height / 2);\n const farthest = Math.hypot(Math.max(cx, width - cx), Math.max(cy, height - cy));\n const radius = resolveOffset(gradient.radius, farthest, farthest);\n return {\n kind: 'radial',\n x0: cx,\n y0: cy,\n x1: cx,\n y1: cy,\n radius,\n stops: placeStops(gradient.stops, radius)\n };\n}\n\n/** A pixel length, or a percentage of `base`; `fallback` when unset. */\nfunction resolveOffset(offset: UiGradientOffset | undefined, base: number, fallback: number): number {\n if (offset === undefined) {\n return fallback;\n }\n return isPercentLength(offset) ? (offset.value / 100) * base : offset;\n}\n\nfunction placeStops(\n stops: readonly ResolvedGradientStop[],\n length: number\n): readonly { offset: number; color: UiColor }[] {\n const placed: { offset: number; color: UiColor }[] = [];\n const spread = stops.every(stop => stop.offset === undefined);\n let previous = 0;\n for (let i = 0; i < stops.length; i++) {\n const raw = spread ? i / (stops.length - 1) : resolveFraction(stops[i].offset, length);\n const offset = Math.max(previous, Math.min(1, Math.max(0, raw)));\n previous = offset;\n placed.push({ offset, color: stops[i].color });\n }\n return placed;\n}\n\n/** A stop's position as a fraction of the gradient's length. */\nfunction resolveFraction(offset: UiGradientOffset | undefined, length: number): number {\n if (offset === undefined) {\n return 0;\n }\n if (isPercentLength(offset)) {\n return offset.value / 100;\n }\n return length > 0 ? offset / length : 0;\n}\n","/**\n * Renderer-independent 2D transform.\n *\n * The transform is applied around a pivot, and `x` / `y` are where\n * that pivot sits inside the node — not a translation. Both renderers\n * compose `T(translate) · T(pivot) · R · S · T(-pivot)`\n * (`Canvas2DRenderer.applyTransform`, `buildOwnTransform` in\n * `WebGPURenderData`), so `{ x: 50, y: 50 }` alone moves nothing,\n * which is what `UiHitTester.spec`'s \"unaffected by an identity\n * transform\" asserts. A node that wants to rotate about its middle\n * passes half its width and height.\n *\n * Those two fields were documented as \"additional translation\" until\n * the Media tier's `Spinner` was written against that description and\n * swung around its own top-left corner in the browser. Moving a node\n * is `translateX` / `translateY`, which is a different pair and is\n * outside the pivot, exactly as CSS's `translate` is outside\n * `transform-origin`.\n */\nexport interface UiTransform {\n /** The pivot's offset from the node's left edge, in logical pixels. */\n readonly x: number;\n /** The pivot's offset from the node's top edge, in logical pixels. */\n readonly y: number;\n /**\n * Moves the node right by this many logical pixels, after the pivot,\n * rotation and scale have been applied.\n *\n * The field a motion system moves things with. It is paint-only —\n * the layout record does not change, so a node sliding across the\n * screen marks Paint and never Layout — which is the whole reason it\n * exists: `animateLayout` accepted a relative `left`/`top` offset\n * precisely because this was missing, and paid\n * for it with a relayout per tick.\n */\n readonly translateX: number;\n /** The same, downwards. */\n readonly translateY: number;\n /** Scale along the x-axis. */\n readonly scaleX: number;\n /** Scale along the y-axis. */\n readonly scaleY: number;\n /** Rotation in radians. */\n readonly rotation: number;\n}\n\nexport const UiTransforms = {\n identity: { x: 0, y: 0, translateX: 0, translateY: 0, scaleX: 1, scaleY: 1, rotation: 0 }\n} as const;\n\n/**\n * Creates a transform from partial values, filling in identity\n * defaults for any omitted field.\n */\nexport function transform(partial: Partial<UiTransform> = {}): UiTransform {\n return {\n x: partial.x ?? 0,\n y: partial.y ?? 0,\n translateX: partial.translateX ?? 0,\n translateY: partial.translateY ?? 0,\n scaleX: partial.scaleX ?? 1,\n scaleY: partial.scaleY ?? 1,\n rotation: partial.rotation ?? 0\n };\n}\n\nfunction isValidNumber(v: unknown): v is number {\n return typeof v === 'number' && Number.isFinite(v);\n}\n\n/**\n * Parses a loose transform object into a canonical transform.\n */\nexport function parseTransform(value: unknown): UiTransform | undefined {\n if (typeof value !== 'object' || value === null) {\n return undefined;\n }\n const candidate = value as Partial<UiTransform>;\n if (\n (candidate.x !== undefined && !isValidNumber(candidate.x)) ||\n (candidate.y !== undefined && !isValidNumber(candidate.y)) ||\n (candidate.translateX !== undefined && !isValidNumber(candidate.translateX)) ||\n (candidate.translateY !== undefined && !isValidNumber(candidate.translateY)) ||\n (candidate.scaleX !== undefined && !isValidNumber(candidate.scaleX)) ||\n (candidate.scaleY !== undefined && !isValidNumber(candidate.scaleY)) ||\n (candidate.rotation !== undefined && !isValidNumber(candidate.rotation))\n ) {\n return undefined;\n }\n const parsed = transform(candidate);\n if (transformIsIdentity(parsed)) {\n return undefined;\n }\n return parsed;\n}\n\n/**\n * Compares two transforms for equality.\n */\nexport function transformsEqual(a: UiTransform, b: UiTransform): boolean {\n const epsilon = 0.0001;\n return (\n Math.abs(a.x - b.x) < epsilon &&\n Math.abs(a.y - b.y) < epsilon &&\n Math.abs(a.translateX - b.translateX) < epsilon &&\n Math.abs(a.translateY - b.translateY) < epsilon &&\n Math.abs(a.scaleX - b.scaleX) < epsilon &&\n Math.abs(a.scaleY - b.scaleY) < epsilon &&\n Math.abs(a.rotation - b.rotation) < epsilon\n );\n}\n\n/**\n * Returns true when the transform is the identity transform.\n */\nexport function transformIsIdentity(transform: UiTransform): boolean {\n return transformsEqual(transform, UiTransforms.identity);\n}\n","import type { UiColorValue } from '../properties/UiPropertyValues';\nimport type { UiGradient } from '../properties/UiGradient';\nimport type { UiImage } from '../properties/UiImage';\n\n/**\n * The drawing vocabulary an application gets when it wants to draw\n * something the property set has no name for: a sparkline, a gauge, a\n * waveform, a chart axis.\n *\n * It sits beside `UiRenderer` on purpose argues\n * the placement at length. The short version is the risk it exists to\n * avoid: a paint hook handed a `CanvasRenderingContext2D` would be a\n * Canvas2D-only capability with a WebGPU backend that could never\n * catch up, which is how a second-class renderer is made. Nothing here\n * names a canvas, a device or a texture, so neither backend can be the\n * one the vocabulary was written for.\n *\n * **Coordinates are the node's own.** `(0, 0)` is the top-left of the\n * resolved box and the box's width and height are the extent, so a\n * painter never reads a layout record and never learns where on the\n * screen it ended up. The device scale arrives separately, for the one\n * thing that genuinely needs it: choosing a hairline that is one\n * physical pixel rather than one logical one.\n *\n * **Every call is recorded, not executed.** The object a painter is\n * handed is a `PaintRecorder`, and what it produces is a\n * `PaintRecording`: plain data, comparable, replayable, and cheap\n * enough to keep. See `PaintRecording.ts` for why that indirection is\n * what makes the two backends agree.\n */\nexport interface PaintSurface {\n // -------------------------------------------------------------------------\n // State\n // -------------------------------------------------------------------------\n\n /** Pushes the transform, the clip and every style value. */\n save(): void;\n restore(): void;\n\n translate(x: number, y: number): void;\n scale(x: number, y: number): void;\n /** Radians, clockwise, about the current origin. */\n rotate(angle: number): void;\n /** Multiplies the current transform by the 3x2 affine `a b c d e f`. */\n transform(a: number, b: number, c: number, d: number, e: number, f: number): void;\n\n // -------------------------------------------------------------------------\n // Path building\n // -------------------------------------------------------------------------\n\n beginPath(): void;\n moveTo(x: number, y: number): void;\n lineTo(x: number, y: number): void;\n quadraticCurveTo(cx: number, cy: number, x: number, y: number): void;\n bezierCurveTo(c1x: number, c1y: number, c2x: number, c2y: number, x: number, y: number): void;\n /** Radians; `counterclockwise` defaults to false. */\n arc(x: number, y: number, radius: number, startAngle: number, endAngle: number, counterclockwise?: boolean): void;\n rect(x: number, y: number, width: number, height: number): void;\n /** One radius for all four corners, clamped to half the smaller side. */\n roundRect(x: number, y: number, width: number, height: number, radius: number): void;\n closePath(): void;\n /**\n * Appends SVG path data to the current path, in the surface's own\n * coordinates.\n *\n * The whole grammar an icon set uses is understood, `A` included:\n * `PaintPathData.ts` turns it into the calls above, so a `d` string\n * costs exactly what writing those calls by hand would and works\n * wherever the rest of this does. That last part is the reason it is\n * parsed here rather than handed to `Path2D`, which exists in a\n * browser and not in the suite.\n */\n path(d: string): void;\n\n // -------------------------------------------------------------------------\n // Style\n // -------------------------------------------------------------------------\n\n /**\n * A `UiColor`, a hex or named CSS colour, or a palette name.\n *\n * A palette name is the reason a painted node follows the light and\n * dark toggle without the painter knowing there was a toggle: the\n * name is resolved against whatever theme the node inherits, at the\n * moment the picture is made, exactly as a `backgroundColor` prop is.\n */\n fillColor(color: UiColorValue): void;\n /**\n * A gradient for the fills that follow, placed in the rectangle\n * given here rather than in the node's box, so a painter can ramp\n * one bar of a chart without arithmetic of its own.\n */\n fillGradient(gradient: UiGradient, x: number, y: number, width: number, height: number): void;\n strokeColor(color: UiColorValue): void;\n lineWidth(width: number): void;\n lineCap(cap: PaintLineCap): void;\n lineJoin(join: PaintLineJoin): void;\n miterLimit(limit: number): void;\n /**\n * A dash pattern in logical pixels, and how far into it the first\n * dash starts. An empty pattern draws solid.\n */\n lineDash(segments: readonly number[], offset?: number): void;\n /** Multiplies into the opacity already in force, as a node's does. */\n alpha(value: number): void;\n /**\n * Blurs everything drawn after it, by a radius in logical pixels.\n *\n * Scoped by `save` and `restore` like every other style value, so a\n * frosted panel is `save`, `blur`, draw, `restore`. Zero clears it.\n */\n blur(radius: number): void;\n\n // -------------------------------------------------------------------------\n // Drawing\n // -------------------------------------------------------------------------\n\n /** Fills the current path. The default rule is `nonzero`. */\n fill(rule?: PaintFillRule): void;\n stroke(): void;\n /** Intersects the clip with the current path, until the next `restore`. */\n clip(rule?: PaintFillRule): void;\n /**\n * One line of text at a baseline, in the current fill colour.\n *\n * Deliberately one line and not a paragraph: wrapping, bidi and\n * selection belong to the text node, which does them properly, and a\n * painter that needs them should draw a text node instead. This is\n * for the labels a chart puts on its own axes.\n */\n text(value: string, x: number, y: number, style?: PaintTextStyle): void;\n /** Draws an image into a rectangle, stretched to fill it. */\n image(image: UiImage, x: number, y: number, width: number, height: number): void;\n}\n\nexport type PaintFillRule = 'nonzero' | 'evenodd';\nexport type PaintLineCap = 'butt' | 'round' | 'square';\nexport type PaintLineJoin = 'miter' | 'round' | 'bevel';\nexport type PaintTextAlign = 'left' | 'center' | 'right';\n\n/** The little of a text style a single painted line can carry. */\nexport interface PaintTextStyle {\n readonly fontSize?: number;\n readonly fontFamily?: string;\n readonly fontWeight?: number | string;\n /** Which end of the run `x` names. Defaults to `left`. */\n readonly align?: PaintTextAlign;\n}\n\n/**\n * The box a painter is asked to fill, in its own coordinates.\n *\n * The node's border box, not its content box: a painter that wants to\n * respect padding is told what it is and decides, because a gauge\n * drawn to the edge and a chart inset by its padding are both\n * legitimate and the property set cannot tell which was meant.\n */\nexport interface PaintBox {\n readonly width: number;\n readonly height: number;\n readonly paddingTop: number;\n readonly paddingRight: number;\n readonly paddingBottom: number;\n readonly paddingLeft: number;\n /**\n * Physical pixels per logical pixel the picture is being made at.\n *\n * The one thing a painter needs the device for: `1 / scale` is a\n * hairline, and a grid line drawn at `1` on a retina display is two\n * physical pixels wide and looks it.\n */\n readonly scale: number;\n}\n\n/**\n * What a node's `paint` prop holds: the drawing, and what it depends\n * on.\n *\n * `inputs` is the whole of the cost story. The picture is made when\n * the inputs change and at no other time, so a painted node on a\n * still frame costs one image draw and nothing else, and\n * `PaintPicture.budget.spec.ts` asserts exactly that. Without it the\n * only safe assumption would be that the closure captured something\n * new, and every frame would repaint.\n *\n * Values are compared with `Object.is`, one by one, so a list of\n * numbers or of stable references works and an array literal rebuilt\n * per render does not defeat it. Omitting `inputs` means the drawing\n * never changes on its own, which is the right default for a static\n * shape and the wrong one for a chart.\n */\nexport interface UiPaint {\n readonly draw: (surface: PaintSurface, box: PaintBox) => void;\n readonly inputs?: readonly unknown[];\n /**\n * The size the node takes when the layout has none to give it: no\n * width or height, no flex, nothing stretching it. Zero, like any\n * other empty leaf, when it is absent.\n */\n readonly intrinsicWidth?: number;\n readonly intrinsicHeight?: number;\n}\n\n/**\n * A static vector shape, as a property rather than a function.\n *\n * The declarative half of this workstream: an icon, a logo, a\n * decorative rule, anything whose geometry is fixed and whose colours\n * follow the theme. It is drawn through the same surface a painter\n * writes to, so there is no second path to keep in step, and a node\n * may carry both a `path` and a `paint` (the path is drawn first, and\n * the painter draws over it).\n */\nexport interface UiPath {\n /** SVG path data, in `viewBox` units. */\n readonly d: string;\n /**\n * The square the path is authored in, scaled to fit the node's box\n * as `object-fit: contain` would, and centred in it. Omitted means\n * the path is already in the node's own logical pixels.\n */\n readonly viewBox?: number;\n readonly fill?: UiColorValue;\n readonly fillRule?: PaintFillRule;\n readonly stroke?: UiColorValue;\n readonly strokeWidth?: number;\n readonly lineCap?: PaintLineCap;\n readonly lineJoin?: PaintLineJoin;\n readonly miterLimit?: number;\n readonly dash?: readonly number[];\n readonly dashOffset?: number;\n}\n\n/**\n * Whether two `paint` values would draw the same picture.\n *\n * Identity on `draw` plus item-by-item identity on `inputs`, which is\n * the comparison the property registry runs on every write. A painter\n * rebuilt by a render body has a new `draw`, so a component that wants\n * the caching has to hoist the function and vary the inputs, which is\n * the same rule a modifier's arguments follow.\n */\nexport function paintValuesEqual(a: UiPaint | undefined, b: UiPaint | undefined): boolean {\n if (a === b) {\n return true;\n }\n if (a === undefined || b === undefined) {\n return false;\n }\n if (a.draw !== b.draw || a.intrinsicWidth !== b.intrinsicWidth || a.intrinsicHeight !== b.intrinsicHeight) {\n return false;\n }\n return inputsEqual(a.inputs, b.inputs);\n}\n\n/** Item-by-item identity, with absent and empty treated alike. */\nexport function inputsEqual(a: readonly unknown[] | undefined, b: readonly unknown[] | undefined): boolean {\n const left = a ?? EMPTY_INPUTS;\n const right = b ?? EMPTY_INPUTS;\n if (left === right) {\n return true;\n }\n if (left.length !== right.length) {\n return false;\n }\n for (let i = 0; i < left.length; i++) {\n if (!Object.is(left[i], right[i])) {\n return false;\n }\n }\n return true;\n}\n\nconst EMPTY_INPUTS: readonly unknown[] = Object.freeze([]);\n\n/** Whether two `path` values describe the same shape in the same style. */\nexport function pathValuesEqual(a: UiPath | undefined, b: UiPath | undefined): boolean {\n if (a === b) {\n return true;\n }\n if (a === undefined || b === undefined) {\n return false;\n }\n return (\n a.d === b.d &&\n a.viewBox === b.viewBox &&\n a.fill === b.fill &&\n a.fillRule === b.fillRule &&\n a.stroke === b.stroke &&\n a.strokeWidth === b.strokeWidth &&\n a.lineCap === b.lineCap &&\n a.lineJoin === b.lineJoin &&\n a.miterLimit === b.miterLimit &&\n a.dashOffset === b.dashOffset &&\n inputsEqual(a.dash, b.dash)\n );\n}\n","import type { UiColors } from '../environment/UiColors';\nimport type { UiShapeName } from '../environment/UiShapes';\nimport type { UiColor } from './UiColor';\nimport type { UiBorderRadius } from './UiBorderRadius';\n\n/**\n * Value vocabularies for the string-valued properties.\n *\n * These are the words the layout engine, the renderers and the input\n * layer actually compare against. They live here, next to the\n * registry, so that a property's type in `UiProperties` is the single\n * source of truth for both the runtime and the authoring types derived\n * from it (see `UiElementProps`).\n */\n\n/**\n * Alignment of children along an axis. Which words apply depends on\n * whether the axis is a flex container's main axis (`start`, `center`,\n * `end`, `space-*`), its cross axis (`start`, `center`, `end`,\n * `stretch`, `baseline`), a stack or a grid cell (`start`, `center`,\n * `end`, `stretch`). The engine ignores a word that does not apply.\n */\nexport type UiAlignment =\n | 'start'\n | 'center'\n | 'end'\n | 'stretch'\n | 'baseline'\n | 'space-between'\n | 'space-around'\n | 'space-evenly';\n\n/** Per-child override of the parent's alignment on one axis. */\nexport type UiSelfAlignment = 'start' | 'center' | 'end' | 'stretch' | 'baseline';\n\n/** Distribution of a wrapping container's lines or a grid's tracks. */\nexport type UiContentDistribution =\n | 'stretch'\n | 'start'\n | 'center'\n | 'end'\n | 'space-between'\n | 'space-around'\n | 'space-evenly';\n\nexport type UiFlexWrap = 'nowrap' | 'wrap' | 'wrap-reverse';\n\n/**\n * Main-axis direction of a flex or scroll container. `horizontal` and\n * `vertical` are accepted as synonyms of `row` and `column`.\n */\nexport type UiDirection = 'row' | 'column' | 'row-reverse' | 'column-reverse' | 'horizontal' | 'vertical';\n\nexport type UiGridAutoFlow = 'row' | 'column';\n\n/**\n * Which axis a nested grid takes from its parent's tracks. Only the\n * column axis exists: see the `subgrid` property.\n */\nexport type UiSubgridAxis = 'columns';\n\nexport const UI_SUBGRID_AXES: readonly UiSubgridAxis[] = ['columns'];\n\n/** Validates the `subgrid` prop the way `role` and `states` are validated. */\nexport function validateSubgrid(value: unknown): string | undefined {\n if (value === undefined || value === 'columns') {\n return undefined;\n }\n return (\n `Unknown subgrid axis '${String(value)}'. ` +\n `Only 'columns' is supported: a virtualized table's parent cannot see the rows that are not mounted, ` +\n `so its row tracks are not something a row could share.`\n );\n}\n\nexport type UiPosition = 'static' | 'relative' | 'absolute' | 'sticky';\n\nexport type UiOverflow = 'visible' | 'hidden' | 'scroll' | 'auto';\n\n/** Side and alignment of an anchored node against its anchor. */\nexport type UiPlacement =\n | 'top'\n | 'top-start'\n | 'top-end'\n | 'bottom'\n | 'bottom-start'\n | 'bottom-end'\n | 'left'\n | 'left-start'\n | 'left-end'\n | 'right'\n | 'right-start'\n | 'right-end';\n\nexport type UiTextWrapValue = 'word' | 'char' | 'none';\n\nexport type UiTextOverflowValue = 'clip' | 'ellipsis';\n\n/**\n * Where a line sits in its box. `start` and `end` follow the paragraph's\n * `textDirection`, as CSS's do, and `start` is the default: a right-to-left\n * paragraph aligns right without being told to.\n */\nexport type UiTextAlign = 'start' | 'end' | 'left' | 'center' | 'right';\n\nexport type UiTextDirection = 'ltr' | 'rtl';\n\nexport type UiVerticalAlign = 'top' | 'middle' | 'bottom';\n\nexport type UiObjectFit = 'fill' | 'cover' | 'contain' | 'none';\n\nexport type UiPointerEvents = 'auto' | 'none';\n\n/** A CSS font weight: a number, a numeric string, or a keyword. */\nexport type UiFontWeight = number | `${number}` | 'normal' | 'bold' | 'lighter' | 'bolder';\n\n/**\n * The CSS cursor names a shell may show over the hovered node. Set on\n * an element or any ancestor; the runtime reports the nearest one to\n * the shell, which puts it on the canvas.\n */\nexport type UiCursor =\n | 'default'\n | 'pointer'\n | 'text'\n | 'move'\n | 'grab'\n | 'grabbing'\n | 'crosshair'\n | 'not-allowed'\n | 'wait'\n | 'progress'\n | 'help'\n | 'none'\n | 'col-resize'\n | 'row-resize'\n | 'ew-resize'\n | 'ns-resize'\n | 'nesw-resize'\n | 'nwse-resize'\n | 'zoom-in'\n | 'zoom-out';\n\n/** A name in the theme's color palette, resolved at paint time. */\nexport type UiThemeColorName = keyof UiColors;\n\n/**\n * What a color property accepts: a `UiColor`, a theme palette name\n * (`'primary'`), or a CSS color string (`'#1f6feb'`, `'red'`). The\n * palette names are listed so they complete; the open string keeps hex\n * and named CSS colors legal.\n */\nexport type UiColorValue = UiColor | UiThemeColorName | (string & {});\n\n/**\n * What a border radius property accepts: a number, a per-corner\n * `UiBorderRadius`, or a name in the theme's shape scale\n * (`'medium'`), resolved at paint.\n *\n * Unlike `UiColorValue` this is *not* widened with `(string & {})`. A\n * colour has to stay open because hex and CSS names are legal values;\n * a radius has no such literal spelling, so every string here is meant\n * to be a scale name and one that is not should not compile. An\n * application with its own steps declares them through\n * `UiShapeExtensions`.\n */\nexport type UiBorderRadiusValue = UiBorderRadius | number | UiShapeName;\n","/**\n * What a node means, as opposed to what it looks like.\n *\n * A canvas has no DOM, so nothing about a Gesso tree is visible to a\n * screen reader unless the tree says what it is. These properties are\n * that statement: they are read by the semantics phase, diffed per\n * frame, and mirrored into an off-screen DOM the\n * platform's assistive technology can see.\n *\n * The vocabulary is ARIA's, because ARIA is what the mirror will emit\n * and what every accessibility API on the three target webviews\n * understands. Borrowing the names means the translation is a rename,\n * not a mapping table.\n */\n\n/**\n * What a node is. Closed, so a typo is a build error the way an\n * unknown prop already is: the mirror can only emit roles it knows.\n */\nexport type UiRole =\n // Controls\n | 'button'\n | 'checkbox'\n | 'switch'\n | 'radio'\n | 'radiogroup'\n | 'slider'\n | 'spinbutton'\n | 'textbox'\n | 'searchbox'\n | 'combobox'\n | 'listbox'\n | 'option'\n | 'menu'\n | 'menubar'\n | 'menuitem'\n | 'menuitemcheckbox'\n | 'menuitemradio'\n | 'tab'\n | 'tablist'\n | 'tabpanel'\n | 'link'\n | 'progressbar'\n // Structure\n | 'list'\n | 'listitem'\n | 'tree'\n | 'treeitem'\n | 'grid'\n | 'row'\n | 'columnheader'\n | 'rowheader'\n | 'cell'\n | 'group'\n | 'separator'\n | 'toolbar'\n | 'heading'\n | 'image'\n | 'paragraph'\n // Windows and live regions\n | 'dialog'\n | 'alertdialog'\n | 'tooltip'\n | 'alert'\n | 'status'\n // Landmarks\n | 'banner'\n | 'navigation'\n | 'main'\n | 'region'\n | 'form'\n | 'search'\n | 'contentinfo';\n\n/** How urgently a live region's changes are announced. */\nexport type UiLiveRegion = 'polite' | 'assertive';\n\nexport const UI_ROLES: readonly UiRole[] = [\n 'button',\n 'checkbox',\n 'switch',\n 'radio',\n 'radiogroup',\n 'slider',\n 'spinbutton',\n 'textbox',\n 'searchbox',\n 'combobox',\n 'listbox',\n 'option',\n 'menu',\n 'menubar',\n 'menuitem',\n 'menuitemcheckbox',\n 'menuitemradio',\n 'tab',\n 'tablist',\n 'tabpanel',\n 'link',\n 'progressbar',\n 'list',\n 'listitem',\n 'tree',\n 'treeitem',\n 'grid',\n 'row',\n 'columnheader',\n 'rowheader',\n 'cell',\n 'group',\n 'separator',\n 'toolbar',\n 'heading',\n 'image',\n 'paragraph',\n 'dialog',\n 'alertdialog',\n 'tooltip',\n 'alert',\n 'status',\n 'banner',\n 'navigation',\n 'main',\n 'region',\n 'form',\n 'search',\n 'contentinfo'\n];\n\nconst roleSet: ReadonlySet<string> = new Set<string>(UI_ROLES);\n\nexport function isUiRole(value: unknown): value is UiRole {\n return typeof value === 'string' && roleSet.has(value);\n}\n\n/**\n * A control's condition, beyond its role and value.\n *\n * `disabled` is deliberately absent: `disabled` is already a property,\n * it is inherited by a whole subtree through `isNodeInert`, and having\n * two ways to say it would let them disagree. The semantics record\n * derives it.\n */\nexport type UiSemanticState =\n | 'checked'\n | 'mixed'\n | 'expanded'\n | 'collapsed'\n | 'selected'\n | 'pressed'\n | 'busy'\n | 'invalid'\n | 'required'\n | 'readonly'\n | 'modal';\n\nexport const UI_SEMANTIC_STATES: readonly UiSemanticState[] = [\n 'checked',\n 'mixed',\n 'expanded',\n 'collapsed',\n 'selected',\n 'pressed',\n 'busy',\n 'invalid',\n 'required',\n 'readonly',\n 'modal'\n];\n\nconst stateSet: ReadonlySet<string> = new Set<string>(UI_SEMANTIC_STATES);\n\nexport function isUiSemanticState(value: unknown): value is UiSemanticState {\n return typeof value === 'string' && stateSet.has(value);\n}\n\n/**\n * The states a node declares, as an array so authoring is\n * `states: ['checked']` rather than a Set literal. Order does not\n * matter; the semantics record normalises it.\n */\nexport type UiSemanticStates = readonly UiSemanticState[];\n\n/** Sorted and de-duplicated, so two orders of the same states diff equal. */\nexport function normalizeStates(states: UiSemanticStates): UiSemanticState[] {\n return [...new Set(states)].sort();\n}\n\nexport function statesEqual(a: UiSemanticStates | undefined, b: UiSemanticStates | undefined): boolean {\n if (a === undefined || b === undefined) {\n return a === b;\n }\n if (a.length !== b.length) {\n return false;\n }\n const left = normalizeStates(a);\n const right = normalizeStates(b);\n return left.every((state, index) => state === right[index]);\n}\n\n/**\n * Validates a `role` prop, returning the message for the error the\n * builder throws, or undefined when the value is fine.\n */\nexport function validateRole(value: unknown): string | undefined {\n if (value === undefined || isUiRole(value)) {\n return undefined;\n }\n const suggestion = closest(String(value), UI_ROLES);\n return (\n `Unknown role '${String(value)}'.` +\n (suggestion !== undefined ? ` Did you mean '${suggestion}'?` : '') +\n ` Roles are the ARIA names listed in UI_ROLES.`\n );\n}\n\n/** Validates a `states` prop the same way. */\nexport function validateStates(value: unknown): string | undefined {\n if (value === undefined) {\n return undefined;\n }\n if (!Array.isArray(value)) {\n return `States must be an array of state names, got ${typeof value}.`;\n }\n for (const state of value) {\n if (!isUiSemanticState(state)) {\n const suggestion = closest(String(state), UI_SEMANTIC_STATES);\n return (\n `Unknown state '${String(state)}'.` +\n (suggestion !== undefined ? ` Did you mean '${suggestion}'?` : '') +\n ` States are the names listed in UI_SEMANTIC_STATES.`\n );\n }\n }\n return undefined;\n}\n\n/**\n * The nearest candidate within a third of the name's length, the same\n * rule `closestPropertyName` uses for a misspelled prop.\n */\nfunction closest(value: string, candidates: readonly string[]): string | undefined {\n let best: string | undefined;\n let bestDistance = Infinity;\n const target = value.toLowerCase();\n for (const candidate of candidates) {\n const distance = editDistance(target, candidate);\n if (distance < bestDistance) {\n bestDistance = distance;\n best = candidate;\n }\n }\n return best !== undefined && bestDistance <= Math.max(1, Math.floor(value.length / 3)) ? best : undefined;\n}\n\nfunction editDistance(a: string, b: string): number {\n const previous = Array.from({ length: b.length + 1 }, (_, index) => index);\n for (let i = 1; i <= a.length; i++) {\n let diagonal = previous[0];\n previous[0] = i;\n for (let j = 1; j <= b.length; j++) {\n const next = Math.min(previous[j] + 1, previous[j - 1] + 1, diagonal + (a[i - 1] === b[j - 1] ? 0 : 1));\n diagonal = previous[j];\n previous[j] = next;\n }\n }\n return previous[b.length];\n}\n","import { DirtyFlags } from '../graph/DirtyFlags';\nimport { UiEnvironmentKeys } from '../environment/UiEnvironmentKeys';\nimport type { UiContainerSize } from '../environment/UiContainerSize';\nimport type { UiInsetSource } from '../environment/UiInsets';\nimport { defineProperty, type UiPropertyDefinition } from './UiPropertyDefinition';\nimport type { UiEnvironmentKey } from '../environment/UiEnvironmentKey';\nimport { UiBasicColors, colorValuesEqual } from './UiColor';\nimport { UiBorderRadiuses, borderRadiusValuesEqual } from './UiBorderRadius';\nimport type { UiBoxShadow } from './UiBoxShadow';\nimport { boxShadowArraysEqual } from './UiBoxShadow';\nimport type { UiGradient } from './UiGradient';\nimport { gradientsEqual, validateGradient } from './UiGradient';\nimport type { UiTransform } from './UiTransform';\nimport { transform, transformsEqual } from './UiTransform';\nimport type { UiPaint, UiPath } from '../rendering/PaintSurface';\nimport { paintValuesEqual, pathValuesEqual } from '../rendering/PaintSurface';\nimport type {\n UiFontKerning,\n UiFontStretch,\n UiFontStyle,\n UiFontVariant,\n UiTextDecoration,\n UiTextSpan,\n UiTextStyle\n} from './UiTextStyle';\nimport { defaultTextStyle, textSpansEqual } from './UiTextStyle';\nimport type { UiVisualStateSet } from './UiVisualState';\nimport type { UiLayoutProtocol } from '../layout/CustomLayout';\nimport type { UiLength, UiTrackSize } from '../layout/UiLength';\nimport type { UiNode } from '../graph/UiNode';\nimport type { UiTheme } from '../environment/UiTheme';\nimport type { UiTypographyRole } from '../environment/UiTypography';\nimport type { UiImage } from './UiImage';\nimport type { UiVideoSurface } from './UiVideo';\nimport type { UiVirtualWindow } from '../composition/UiVirtualWindow';\nimport type { UiVirtualSheet } from '../composition/UiVirtualSheet';\nimport type { EditableTextModel } from '../editing/EditableTextModel';\nimport type {\n UiAlignment,\n UiBorderRadiusValue,\n UiColorValue,\n UiContentDistribution,\n UiCursor,\n UiDirection,\n UiFlexWrap,\n UiFontWeight,\n UiGridAutoFlow,\n UiObjectFit,\n UiOverflow,\n UiPlacement,\n UiPointerEvents,\n UiPosition,\n UiSelfAlignment,\n UiSubgridAxis,\n UiTextAlign,\n UiTextDirection,\n UiTextOverflowValue,\n UiTextWrapValue,\n UiVerticalAlign\n} from './UiPropertyValues';\nimport { validateSubgrid } from './UiPropertyValues';\nimport { defaultVisualState, visualStatesEqual } from './UiVisualState';\nimport type { UiRole, UiSemanticStates } from './UiSemantics';\nimport { statesEqual, validateRole, validateStates } from './UiSemantics';\nimport type { UiLiveRegion } from './UiSemantics';\n\nconst L = DirtyFlags.Layout;\nconst P = DirtyFlags.Paint;\nconst C = DirtyFlags.Content;\nconst T = DirtyFlags.Transform;\nconst E = DirtyFlags.Environment;\nconst S = DirtyFlags.Semantics;\n\n// ---------------------------------------------------------------------------\n// Layout\n// ---------------------------------------------------------------------------\n\nexport const UiProperties = {\n width: defineProperty<UiLength | undefined>({\n name: 'width',\n defaultValue: undefined,\n inherited: false,\n affects: L\n }),\n\n height: defineProperty<UiLength | undefined>({\n name: 'height',\n defaultValue: undefined,\n inherited: false,\n affects: L\n }),\n\n minWidth: defineProperty<UiLength | undefined>({\n name: 'minWidth',\n defaultValue: undefined,\n inherited: false,\n affects: L\n }),\n\n maxWidth: defineProperty<UiLength | undefined>({\n name: 'maxWidth',\n defaultValue: undefined,\n inherited: false,\n affects: L\n }),\n\n minHeight: defineProperty<UiLength | undefined>({\n name: 'minHeight',\n defaultValue: undefined,\n inherited: false,\n affects: L\n }),\n\n maxHeight: defineProperty<UiLength | undefined>({\n name: 'maxHeight',\n defaultValue: undefined,\n inherited: false,\n affects: L\n }),\n\n /**\n * Space inside the box, on all four sides.\n *\n * A single number, and deliberately not a tuple or an object: see\n * `paddingX` below.\n */\n padding: defineProperty<number | undefined>({\n name: 'padding',\n defaultValue: undefined,\n inherited: false,\n affects: L\n }),\n\n /**\n * Space inside the box, left and right.\n *\n * The idiom the documentation teaches for a box that is padded more\n * on one axis than the other, which is nearly every box: a card, a\n * row, a button, a header. It resolves between `padding` and the\n * four sides, so `paddingX={16} paddingTop={10}` says what it looks\n * like it says.\n *\n * The four sides stay, because an inset on one edge alone is a thing\n * boxes really need and no axis can express it. What the docs stop\n * teaching is the *pair*: `paddingLeft` and `paddingRight` set to the\n * same number is `paddingX`, and Segue wrote that pair fifty-six\n * times.\n */\n paddingX: defineProperty<number | undefined>({\n name: 'paddingX',\n defaultValue: undefined,\n inherited: false,\n affects: L\n }),\n\n /** Space inside the box, top and bottom. See `paddingX`. */\n paddingY: defineProperty<number | undefined>({\n name: 'paddingY',\n defaultValue: undefined,\n inherited: false,\n affects: L\n }),\n\n paddingTop: defineProperty<number | undefined>({\n name: 'paddingTop',\n defaultValue: undefined,\n inherited: false,\n affects: L\n }),\n\n paddingRight: defineProperty<number | undefined>({\n name: 'paddingRight',\n defaultValue: undefined,\n inherited: false,\n affects: L\n }),\n\n paddingBottom: defineProperty<number | undefined>({\n name: 'paddingBottom',\n defaultValue: undefined,\n inherited: false,\n affects: L\n }),\n\n paddingLeft: defineProperty<number | undefined>({\n name: 'paddingLeft',\n defaultValue: undefined,\n inherited: false,\n affects: L\n }),\n\n /**\n * Space inside the box on the edge the reading starts at: the left\n * under `textDirection=\"ltr\"`, the right under `\"rtl\"`.\n *\n * The idiom the documentation teaches for a single horizontal edge,\n * in place of `paddingLeft` and `paddingRight`. Nearly every inset a\n * screen names on one edge is logical rather than physical: the space\n * before a leading icon, the indent of a nested row, the gutter a\n * list keeps against the side it starts at. Written physically, all\n * three are wrong the moment the application runs in Arabic, and\n * the mirroring cannot fix them because\n * nothing marks them as the edge that should move.\n *\n * `paddingLeft` and `paddingRight` stay, and are still the answer for\n * an edge that is genuinely physical: a gutter kept clear of an\n * overlay scrollbar sits on the same side in both directions. They\n * also win over the logical pair when both are given, because a\n * physical name is the more specific statement of the two. The\n * resolution order in full is side, then logical side, then axis,\n * then the shorthand. Same rule as the token layer\n * sets: most specific wins, and the docs teach one of them.\n */\n paddingStart: defineProperty<number | undefined>({\n name: 'paddingStart',\n defaultValue: undefined,\n inherited: false,\n affects: L\n }),\n\n /** Space inside the box on the edge the reading ends at. See `paddingStart`. */\n paddingEnd: defineProperty<number | undefined>({\n name: 'paddingEnd',\n defaultValue: undefined,\n inherited: false,\n affects: L\n }),\n\n margin: defineProperty<UiLength | undefined>({\n name: 'margin',\n defaultValue: undefined,\n inherited: false,\n affects: L\n }),\n\n /** Space outside the box, left and right. See `paddingX`. */\n marginX: defineProperty<UiLength | undefined>({\n name: 'marginX',\n defaultValue: undefined,\n inherited: false,\n affects: L\n }),\n\n /** Space outside the box, top and bottom. See `paddingX`. */\n marginY: defineProperty<UiLength | undefined>({\n name: 'marginY',\n defaultValue: undefined,\n inherited: false,\n affects: L\n }),\n\n marginTop: defineProperty<UiLength | undefined>({\n name: 'marginTop',\n defaultValue: undefined,\n inherited: false,\n affects: L\n }),\n\n marginRight: defineProperty<UiLength | undefined>({\n name: 'marginRight',\n defaultValue: undefined,\n inherited: false,\n affects: L\n }),\n\n marginBottom: defineProperty<UiLength | undefined>({\n name: 'marginBottom',\n defaultValue: undefined,\n inherited: false,\n affects: L\n }),\n\n marginLeft: defineProperty<UiLength | undefined>({\n name: 'marginLeft',\n defaultValue: undefined,\n inherited: false,\n affects: L\n }),\n\n /** Space outside the box on the edge the reading starts at. See `paddingStart`. */\n marginStart: defineProperty<UiLength | undefined>({\n name: 'marginStart',\n defaultValue: undefined,\n inherited: false,\n affects: L\n }),\n\n /** Space outside the box on the edge the reading ends at. See `paddingStart`. */\n marginEnd: defineProperty<UiLength | undefined>({\n name: 'marginEnd',\n defaultValue: undefined,\n inherited: false,\n affects: L\n }),\n\n gap: defineProperty<number | undefined>({\n name: 'gap',\n defaultValue: undefined,\n inherited: false,\n affects: L\n }),\n\n /** Gap between rows (lines of a wrapping row, items of a column). */\n rowGap: defineProperty<number | undefined>({\n name: 'rowGap',\n defaultValue: undefined,\n inherited: false,\n affects: L\n }),\n\n /** Gap between columns (items of a row, lines of a wrapping column). */\n columnGap: defineProperty<number | undefined>({\n name: 'columnGap',\n defaultValue: undefined,\n inherited: false,\n affects: L\n }),\n\n /** `flex: n` — grow n, shrink 1, basis 0, as in CSS. */\n flex: defineProperty<number | undefined>({\n name: 'flex',\n defaultValue: undefined,\n inherited: false,\n affects: L\n }),\n\n /** 'nowrap' (default), 'wrap' or 'wrap-reverse'. */\n flexWrap: defineProperty<UiFlexWrap | undefined>({\n name: 'flexWrap',\n defaultValue: undefined,\n inherited: false,\n affects: L\n }),\n\n /**\n * How a wrapping container distributes its lines along the cross\n * axis: 'stretch' (default), 'start', 'center', 'end',\n * 'space-between', 'space-around', 'space-evenly'.\n */\n alignContent: defineProperty<UiContentDistribution | undefined>({\n name: 'alignContent',\n defaultValue: undefined,\n inherited: false,\n affects: L\n }),\n\n // -------------------------------------------------------------------------\n // Grid\n // -------------------------------------------------------------------------\n\n /** Explicit column tracks: numbers, percent(), auto, fr(), minmax(). */\n columns: defineProperty<readonly UiTrackSize[] | undefined>({\n name: 'columns',\n defaultValue: undefined,\n inherited: false,\n affects: L\n }),\n\n /** Explicit row tracks. Rows beyond them are implicit, sized by autoRows. */\n rows: defineProperty<readonly UiTrackSize[] | undefined>({\n name: 'rows',\n defaultValue: undefined,\n inherited: false,\n affects: L\n }),\n\n /** Size of implicit columns (default auto). */\n autoColumns: defineProperty<UiTrackSize | undefined>({\n name: 'autoColumns',\n defaultValue: undefined,\n inherited: false,\n affects: L\n }),\n\n /** Size of implicit rows (default auto). */\n autoRows: defineProperty<UiTrackSize | undefined>({\n name: 'autoRows',\n defaultValue: undefined,\n inherited: false,\n affects: L\n }),\n\n /**\n * A grid item that is itself a Grid takes its column tracks from the\n * span it occupies in its parent, instead of declaring its own — so a\n * table's rows line up with its header without either knowing the\n * widths. Only the column axis: a virtualized table's parent cannot\n * see the rows that are not mounted, so its row tracks are not\n * something a row could share.\n */\n subgrid: defineProperty<UiSubgridAxis | undefined>({\n name: 'subgrid',\n defaultValue: undefined,\n inherited: false,\n affects: L,\n validate: validateSubgrid\n }),\n\n /** 'row' (default) fills rows left to right; 'column' fills columns top to bottom. */\n autoFlow: defineProperty<UiGridAutoFlow | undefined>({\n name: 'autoFlow',\n defaultValue: undefined,\n inherited: false,\n affects: L\n }),\n\n /** Distribution of a grid's columns across spare width: 'stretch' (default), 'start', 'center', 'end', 'space-*'. */\n justifyContent: defineProperty<UiContentDistribution | undefined>({\n name: 'justifyContent',\n defaultValue: undefined,\n inherited: false,\n affects: L\n }),\n\n /** 1-based column line a grid item starts at. */\n column: defineProperty<number | undefined>({\n name: 'column',\n defaultValue: undefined,\n inherited: false,\n affects: L\n }),\n\n /** Columns a grid item spans (default 1). */\n columnSpan: defineProperty<number | undefined>({\n name: 'columnSpan',\n defaultValue: undefined,\n inherited: false,\n affects: L\n }),\n\n /** 1-based row line a grid item starts at. */\n row: defineProperty<number | undefined>({\n name: 'row',\n defaultValue: undefined,\n inherited: false,\n affects: L\n }),\n\n /** Rows a grid item spans (default 1). */\n rowSpan: defineProperty<number | undefined>({\n name: 'rowSpan',\n defaultValue: undefined,\n inherited: false,\n affects: L\n }),\n\n /**\n * A layout the application wrote itself, which measures and places\n * this node's children. See `layout/CustomLayout.ts`.\n *\n * Compared with `Object.is` like every other property value, so the\n * protocol object has to be held still across renders: a fresh one\n * per frame marks the node dirty per frame.\n */\n layout: defineProperty<UiLayoutProtocol | undefined>({\n name: 'layout',\n defaultValue: undefined,\n inherited: false,\n affects: L\n }),\n\n /**\n * A value carried to the custom layout that arranges this node: a\n * weight, a lane, a timestamp. Meaningless to everything else.\n */\n layoutData: defineProperty<unknown>({\n name: 'layoutData',\n defaultValue: undefined,\n inherited: false,\n affects: L\n }),\n\n /** Width divided by height; the decided axis drives the other. */\n aspectRatio: defineProperty<number | undefined>({\n name: 'aspectRatio',\n defaultValue: undefined,\n inherited: false,\n affects: L\n }),\n\n flexGrow: defineProperty<number | undefined>({\n name: 'flexGrow',\n defaultValue: undefined,\n inherited: false,\n affects: L\n }),\n\n flexShrink: defineProperty<number | undefined>({\n name: 'flexShrink',\n defaultValue: undefined,\n inherited: false,\n affects: L\n }),\n\n flexBasis: defineProperty<UiLength | undefined>({\n name: 'flexBasis',\n defaultValue: undefined,\n inherited: false,\n affects: L\n }),\n\n /**\n * Alignment of children along the x-axis.\n *\n * For a row this is the main axis; for a column this is the cross\n * axis. The value is axis-relative and does not flip meaning when\n * the flex direction changes.\n */\n x: defineProperty<UiAlignment | undefined>({\n name: 'x',\n defaultValue: undefined,\n inherited: false,\n affects: L\n }),\n\n /**\n * Alignment of children along the y-axis.\n *\n * For a column this is the main axis; for a row this is the cross\n * axis. The value is axis-relative and does not flip meaning when\n * the flex direction changes.\n */\n y: defineProperty<UiAlignment | undefined>({\n name: 'y',\n defaultValue: undefined,\n inherited: false,\n affects: L\n }),\n\n /**\n * Per-child override for x-axis alignment.\n */\n selfX: defineProperty<UiSelfAlignment | undefined>({\n name: 'selfX',\n defaultValue: undefined,\n inherited: false,\n affects: L\n }),\n\n /**\n * Per-child override for y-axis alignment.\n */\n selfY: defineProperty<UiSelfAlignment | undefined>({\n name: 'selfY',\n defaultValue: undefined,\n inherited: false,\n affects: L\n }),\n\n /**\n * 'static' (default), 'relative' (in flow, then offset by\n * top/right/bottom/left, and a containing block for absolute\n * descendants), 'absolute' (out of flow, positioned against the\n * nearest positioned ancestor or the layout root) or 'sticky' (in\n * flow, but held at the edge of its scroll container by\n * top/right/bottom/left while the container scrolls, until its\n * parent's box ends).\n */\n position: defineProperty<UiPosition | undefined>({\n name: 'position',\n defaultValue: undefined,\n inherited: false,\n affects: L\n }),\n\n top: defineProperty<UiLength | undefined>({\n name: 'top',\n defaultValue: undefined,\n inherited: false,\n affects: L\n }),\n\n right: defineProperty<UiLength | undefined>({\n name: 'right',\n defaultValue: undefined,\n inherited: false,\n affects: L\n }),\n\n bottom: defineProperty<UiLength | undefined>({\n name: 'bottom',\n defaultValue: undefined,\n inherited: false,\n affects: L\n }),\n\n left: defineProperty<UiLength | undefined>({\n name: 'left',\n defaultValue: undefined,\n inherited: false,\n affects: L\n }),\n\n /**\n * Paint and hit-test order among siblings; higher paints later and\n * is hit first. Ties keep tree order.\n *\n * Layout rather than Paint, which it was until a bound zIndex was\n * found to change nothing. The order is not decided at paint time:\n * `LayoutEngine.updatePaintOrder` sorts a parent's children into\n * `LayoutRecord.paintOrder` during layout, from the same record\n * field `position` writes — so a zIndex that only marked Paint was\n * read back from a record nothing had recomputed, and took effect\n * only if something else happened to relayout. Its partner in that\n * sort key, `position`, has always been Layout.\n */\n zIndex: defineProperty<number | undefined>({\n name: 'zIndex',\n defaultValue: undefined,\n inherited: false,\n affects: L\n }),\n\n /**\n * Paints this node, and everything under it, in a top layer: above\n * the whole tree and outside every clip an ancestor imposes.\n *\n * `zIndex` orders a node among its siblings and nowhere else, and it\n * cannot do anything at all about `overflow`. That is enough for an\n * element that has to cover the row beside it, and no use to one\n * that has to leave the row: a picture morphing back into a card in\n * a `LazyRow` starts its journey at the middle of the page, which is\n * outside the row's scroll clip, so most of the morph is simply cut\n * away. Lifting is the answer to that, and only to that.\n *\n * What is kept and what is dropped is the whole of the definition.\n * Kept: the node's place in the layout, and every ancestor's\n * transform, scroll offset and opacity, so a lifted node is drawn\n * exactly where it would have been drawn and moves with what it\n * belongs to. Dropped: every ancestor's clip, and the node's place\n * in paint order, which becomes \"after everything else\".\n *\n * Layout rather than Paint, for the reason `zIndex` is: the flag is\n * read while the tree is laid out, and a property that only marked\n * Paint would be read back from a record nothing had recomputed.\n *\n * It is a transient. `sharedElement({ lift: true })` sets it for the\n * length of a morph and clears it after; an element that is lifted\n * for good is over everything for good, hit testing included, which\n * is almost never what anyone wants.\n */\n lift: defineProperty<boolean | undefined>({\n name: 'lift',\n defaultValue: undefined,\n inherited: false,\n affects: L\n }),\n\n /**\n * How far up \"above everything\" reaches: a lifted descendant of this\n * node is painted at the end of *this* node rather than at the end\n * of the frame.\n *\n * Without one, `lift` means above the whole tree, and across a\n * screen transition that is too far. Two screens are on screen at\n * once while one replaces the other, and the one being left may hold\n * an element still morphing: lifted to the very top, it paints over\n * the screen that is arriving, so the picture from the last\n * navigation flies across the new page. Held to its own screen it\n * escapes the row it lives in, which is what it was lifted for, and\n * is covered by the arriving screen, which is what a departing\n * screen should be.\n *\n * `Presence` marks each of its layers with this, so every screen,\n * dialog and toast is one, and an application rarely sets it itself.\n */\n liftBoundary: defineProperty<boolean | undefined>({\n name: 'liftBoundary',\n defaultValue: undefined,\n inherited: false,\n affects: L\n }),\n\n /**\n * The UiNode an absolutely positioned node is placed next to. With\n * an anchor, top/right/bottom/left are ignored and `placement`\n * decides the side; the node flips to the opposite side when it\n * would overflow its containing block and shifts along the anchor\n * to stay inside it.\n */\n anchor: defineProperty<UiNode | null | undefined>({\n name: 'anchor',\n defaultValue: undefined,\n inherited: false,\n affects: L\n }),\n\n /**\n * Side and alignment against the anchor: 'bottom' (default),\n * 'bottom-start', 'bottom-end', 'top', 'top-start', 'top-end',\n * 'left', 'left-start', 'left-end', 'right', 'right-start',\n * 'right-end'.\n */\n placement: defineProperty<UiPlacement | undefined>({\n name: 'placement',\n defaultValue: undefined,\n inherited: false,\n affects: L\n }),\n\n /** Gap between an anchored node and its anchor. */\n anchorOffset: defineProperty<number | undefined>({\n name: 'anchorOffset',\n defaultValue: undefined,\n inherited: false,\n affects: L\n }),\n\n /**\n * Layout direction for flex and scroll containers.\n */\n direction: defineProperty<UiDirection | undefined>({\n name: 'direction',\n defaultValue: undefined,\n inherited: false,\n affects: L\n }),\n\n /**\n * 'visible' (default): children may paint outside the box. 'hidden'\n * clips them to it (following borderRadius in Canvas2D). 'scroll' and\n * 'auto' clip and make the box a scroll container: scrollX/scrollY\n * apply, overlay scrollbars show while scrolling, and sticky\n * descendants stick to its edges.\n */\n overflow: defineProperty<UiOverflow | undefined>({\n name: 'overflow',\n defaultValue: undefined,\n inherited: false,\n affects: L | P\n }),\n\n inset: defineProperty<UiLength | undefined>({\n name: 'inset',\n defaultValue: undefined,\n inherited: false,\n affects: L\n }),\n\n // -------------------------------------------------------------------------\n // Paint\n // -------------------------------------------------------------------------\n\n backgroundColor: defineProperty<UiColorValue | undefined>({\n name: 'backgroundColor',\n defaultValue: undefined,\n inherited: false,\n affects: P,\n compare: colorValuesEqual\n }),\n\n /**\n * A gradient filling the box, painted over `backgroundColor` and\n * under `image`, which is where CSS paints a `background-image`.\n * Build it with `linearGradient()` or `radialGradient()`.\n */\n backgroundGradient: defineProperty<UiGradient | undefined>({\n name: 'backgroundGradient',\n defaultValue: undefined,\n inherited: false,\n affects: P,\n compare: gradientsEqual,\n validate: validateGradient\n }),\n\n color: defineProperty<UiColorValue>({\n name: 'color',\n defaultValue: UiBasicColors.black,\n inherited: true,\n affects: P,\n environmentKey: UiEnvironmentKeys.textStyle as UiEnvironmentKey<unknown>,\n resolveFromEnvironment: (value: unknown) => {\n const textStyle = value as UiTextStyle;\n return textStyle.color;\n },\n compare: colorValuesEqual\n }),\n\n borderColor: defineProperty<UiColorValue | undefined>({\n name: 'borderColor',\n defaultValue: undefined,\n inherited: false,\n affects: P,\n compare: colorValuesEqual\n }),\n\n borderWidth: defineProperty<number | undefined>({\n name: 'borderWidth',\n defaultValue: undefined,\n inherited: false,\n affects: P\n }),\n\n /**\n * The corner radius: a number, a per-corner object, or a name in the\n * theme's shape scale (`borderRadius=\"medium\"`).\n *\n * A name is resolved at paint against the theme the element is\n * under, exactly as a palette name in `backgroundColor` is, so a\n * radius follows an appearance toggle or a nested theme provider\n * with nothing on the element knowing. This is the one metric\n * property that can take a name: a radius is read at paint, where\n * the theme is already being consulted for every colour, and not in\n * the layout pass that the token layer was protecting.\n */\n borderRadius: defineProperty<UiBorderRadiusValue>({\n name: 'borderRadius',\n defaultValue: UiBorderRadiuses.none,\n inherited: false,\n affects: P,\n compare: borderRadiusValuesEqual\n }),\n\n opacity: defineProperty<number>({\n name: 'opacity',\n defaultValue: 1,\n inherited: false,\n affects: P\n }),\n\n boxShadows: defineProperty<readonly UiBoxShadow[]>({\n name: 'boxShadows',\n defaultValue: [],\n inherited: false,\n affects: P,\n compare: boxShadowArraysEqual\n }),\n\n visible: defineProperty<boolean>({\n name: 'visible',\n defaultValue: true,\n inherited: false,\n // An invisible subtree is not in the semantics tree at all, so\n // hiding a node removes its record and showing it adds one back.\n affects: P | S\n }),\n\n // -------------------------------------------------------------------------\n // Typography\n // -------------------------------------------------------------------------\n\n fontFamily: defineProperty<string>({\n name: 'fontFamily',\n defaultValue: defaultTextStyle.fontFamily,\n inherited: true,\n affects: L | P,\n environmentKey: UiEnvironmentKeys.textStyle as UiEnvironmentKey<unknown>,\n resolveFromEnvironment: (value: unknown) => (value as UiTextStyle).fontFamily\n }),\n\n fontSize: defineProperty<number>({\n name: 'fontSize',\n defaultValue: defaultTextStyle.fontSize,\n inherited: true,\n affects: L | P,\n environmentKey: UiEnvironmentKeys.textStyle as UiEnvironmentKey<unknown>,\n resolveFromEnvironment: (value: unknown) => (value as UiTextStyle).fontSize\n }),\n\n fontWeight: defineProperty<UiFontWeight>({\n name: 'fontWeight',\n defaultValue: defaultTextStyle.fontWeight,\n inherited: true,\n affects: L | P,\n environmentKey: UiEnvironmentKeys.textStyle as UiEnvironmentKey<unknown>,\n resolveFromEnvironment: (value: unknown) => (value as UiTextStyle).fontWeight\n }),\n\n lineHeight: defineProperty<number>({\n name: 'lineHeight',\n defaultValue: defaultTextStyle.lineHeight,\n inherited: true,\n affects: L | P,\n environmentKey: UiEnvironmentKeys.textStyle as UiEnvironmentKey<unknown>,\n resolveFromEnvironment: (value: unknown) => (value as UiTextStyle).lineHeight\n }),\n\n letterSpacing: defineProperty<number>({\n name: 'letterSpacing',\n defaultValue: defaultTextStyle.letterSpacing,\n inherited: true,\n affects: L | P,\n environmentKey: UiEnvironmentKeys.textStyle as UiEnvironmentKey<unknown>,\n resolveFromEnvironment: (value: unknown) => (value as UiTextStyle).letterSpacing\n }),\n\n textAlign: defineProperty<UiTextAlign>({\n name: 'textAlign',\n defaultValue: defaultTextStyle.textAlign,\n inherited: true,\n affects: P,\n environmentKey: UiEnvironmentKeys.textStyle as UiEnvironmentKey<unknown>,\n resolveFromEnvironment: (value: unknown) => (value as UiTextStyle).textAlign\n }),\n\n textDirection: defineProperty<UiTextDirection>({\n name: 'textDirection',\n defaultValue: defaultTextStyle.textDirection,\n inherited: true,\n affects: P,\n environmentKey: UiEnvironmentKeys.textStyle as UiEnvironmentKey<unknown>,\n resolveFromEnvironment: (value: unknown) => (value as UiTextStyle).textDirection\n }),\n\n fontStyle: defineProperty<UiFontStyle>({\n name: 'fontStyle',\n defaultValue: 'normal',\n inherited: true,\n affects: L | P,\n environmentKey: UiEnvironmentKeys.textStyle as UiEnvironmentKey<unknown>,\n resolveFromEnvironment: (value: unknown) => (value as UiTextStyle).fontStyle ?? 'normal'\n }),\n\n /**\n * The width axis, as CSS names it. A context property rather than\n * part of the canvas font string, which is why it is set on every\n * measure and every draw: see `applyCanvasTextStyle`.\n */\n fontStretch: defineProperty<UiFontStretch>({\n name: 'fontStretch',\n defaultValue: 'normal',\n inherited: true,\n affects: L | P,\n environmentKey: UiEnvironmentKeys.textStyle as UiEnvironmentKey<unknown>,\n resolveFromEnvironment: (value: unknown) => (value as UiTextStyle).fontStretch ?? 'normal'\n }),\n\n fontVariant: defineProperty<UiFontVariant>({\n name: 'fontVariant',\n defaultValue: 'normal',\n inherited: true,\n affects: L | P,\n environmentKey: UiEnvironmentKeys.textStyle as UiEnvironmentKey<unknown>,\n resolveFromEnvironment: (value: unknown) => (value as UiTextStyle).fontVariant ?? 'normal'\n }),\n\n fontKerning: defineProperty<UiFontKerning>({\n name: 'fontKerning',\n defaultValue: 'auto',\n inherited: true,\n affects: L | P,\n environmentKey: UiEnvironmentKeys.textStyle as UiEnvironmentKey<unknown>,\n resolveFromEnvironment: (value: unknown) => (value as UiTextStyle).fontKerning ?? 'auto'\n }),\n\n /**\n * Lines drawn with the text. Paint only: an underline is a\n * rectangle beside the glyphs and moves nothing.\n */\n textDecoration: defineProperty<UiTextDecoration>({\n name: 'textDecoration',\n defaultValue: 'none',\n inherited: true,\n affects: P,\n environmentKey: UiEnvironmentKeys.textStyle as UiEnvironmentKey<unknown>,\n resolveFromEnvironment: (value: unknown) => (value as UiTextStyle).textDecoration ?? 'none'\n }),\n\n /**\n * The paragraph as runs of `{ text, style }` rather than one string.\n *\n * Set instead of `text`, never beside it: the runs' texts\n * concatenated are the paragraph, so a line's offsets, a selection,\n * a find match and the semantics mirror all mean the same thing\n * whichever of the two a node was given. Affects content, layout and\n * semantics for exactly the reasons `text` does.\n */\n spans: defineProperty<readonly UiTextSpan[] | undefined>({\n name: 'spans',\n defaultValue: undefined,\n inherited: false,\n affects: C | L | S,\n compare: textSpansEqual\n }),\n\n verticalAlign: defineProperty<UiVerticalAlign | undefined>({\n name: 'verticalAlign',\n defaultValue: undefined,\n inherited: false,\n affects: P\n }),\n\n /**\n * How text breaks into lines: 'word' (default), 'char', or 'none'.\n */\n textWrap: defineProperty<UiTextWrapValue | undefined>({\n name: 'textWrap',\n defaultValue: undefined,\n inherited: false,\n affects: L | P\n }),\n\n /**\n * Maximum number of lines a text node keeps.\n */\n maxLines: defineProperty<number | undefined>({\n name: 'maxLines',\n defaultValue: undefined,\n inherited: false,\n affects: L | P\n }),\n\n /**\n * What happens to a line that does not fit: 'clip' (default) or\n * 'ellipsis'.\n */\n textOverflow: defineProperty<UiTextOverflowValue | undefined>({\n name: 'textOverflow',\n defaultValue: undefined,\n inherited: false,\n affects: L | P\n }),\n\n // -------------------------------------------------------------------------\n // Editing (EditableText)\n // -------------------------------------------------------------------------\n\n /**\n * The text of an editable node. Writing it replaces what the user\n * typed; the runtime reports edits through `onInput`, and an app that\n * writes the reported value back gets a controlled field.\n */\n value: defineProperty<string | undefined>({\n name: 'value',\n defaultValue: undefined,\n inherited: false,\n // Semantics too: an editable's value is what a screen reader reads\n // it as, so the semantics tree has to follow the text.\n affects: C | L | S\n }),\n\n /** Shown, muted, while an editable is empty. */\n placeholder: defineProperty<string | undefined>({\n name: 'placeholder',\n defaultValue: undefined,\n inherited: false,\n affects: L | P\n }),\n\n /** Enter inserts a newline (default false: Enter is left to the app). */\n multiline: defineProperty<boolean | undefined>({\n name: 'multiline',\n defaultValue: undefined,\n inherited: false,\n affects: DirtyFlags.Properties\n }),\n\n /** The text can be selected and copied but not changed. */\n readOnly: defineProperty<boolean | undefined>({\n name: 'readOnly',\n defaultValue: undefined,\n inherited: false,\n affects: DirtyFlags.Properties\n }),\n\n /** Colour of the caret; defaults to the text colour. */\n caretColor: defineProperty<UiColorValue | undefined>({\n name: 'caretColor',\n defaultValue: undefined,\n inherited: false,\n affects: P,\n compare: colorValuesEqual\n }),\n\n /** Colour behind selected text; defaults to a translucent theme primary. */\n selectionColor: defineProperty<UiColorValue | undefined>({\n name: 'selectionColor',\n defaultValue: undefined,\n inherited: false,\n affects: P,\n compare: colorValuesEqual\n }),\n\n /** Colour behind text a find query matched; defaults to a translucent theme secondary. */\n matchColor: defineProperty<UiColorValue | undefined>({\n name: 'matchColor',\n defaultValue: undefined,\n inherited: false,\n affects: P,\n compare: colorValuesEqual\n }),\n\n /** Colour of the placeholder; defaults to the theme's muted text. */\n placeholderColor: defineProperty<UiColorValue | undefined>({\n name: 'placeholderColor',\n defaultValue: undefined,\n inherited: false,\n affects: P,\n compare: colorValuesEqual\n }),\n\n /** Set by the runtime on each editable node: its EditableTextModel. */\n editor: defineProperty<EditableTextModel | undefined>({\n name: 'editor',\n defaultValue: undefined,\n inherited: false,\n affects: DirtyFlags.Properties\n }),\n\n // -------------------------------------------------------------------------\n // Interaction\n // -------------------------------------------------------------------------\n\n /**\n * CSS cursor shown while the pointer is over this node or a\n * descendant that sets none. Resolved by the runtime on hover and\n * applied to the canvas by the shell.\n */\n cursor: defineProperty<UiCursor | undefined>({\n name: 'cursor',\n defaultValue: undefined,\n inherited: false,\n affects: DirtyFlags.Properties\n }),\n\n /**\n * Whether the user may select this subtree's text with the pointer.\n * Read up the ancestor chain like CSS `user-select`, so setting it\n * once on a container covers everything inside; a Button opts its\n * label out by default.\n */\n selectable: defineProperty<boolean | undefined>({\n name: 'selectable',\n defaultValue: undefined,\n inherited: false,\n affects: DirtyFlags.Properties\n }),\n\n pointerEvents: defineProperty<UiPointerEvents | undefined>({\n name: 'pointerEvents',\n defaultValue: undefined,\n inherited: false,\n affects: DirtyFlags.Properties\n }),\n\n focusable: defineProperty<boolean | undefined>({\n name: 'focusable',\n defaultValue: undefined,\n inherited: false,\n affects: DirtyFlags.Properties\n }),\n\n tabStop: defineProperty<boolean | undefined>({\n name: 'tabStop',\n defaultValue: undefined,\n inherited: false,\n affects: DirtyFlags.Properties\n }),\n\n disabled: defineProperty<boolean | undefined>({\n name: 'disabled',\n defaultValue: undefined,\n inherited: false,\n // Inert-ness is a semantic fact as well as an input one: a\n // disabled control is announced as unavailable, not hidden.\n affects: DirtyFlags.Properties | S\n }),\n\n // -------------------------------------------------------------------------\n // Semantics\n //\n // What the node means. Read by the semantics phase, diffed per frame\n // and (F6b) mirrored into an off-screen DOM. See UiSemantics.ts.\n // -------------------------------------------------------------------------\n\n /** What this node is, in ARIA's vocabulary. Closed: a typo throws. */\n role: defineProperty<UiRole | undefined>({\n name: 'role',\n defaultValue: undefined,\n inherited: false,\n affects: S,\n validate: validateRole\n }),\n\n /** The node's accessible name. Without one it is named by its text. */\n label: defineProperty<string | undefined>({\n name: 'label',\n defaultValue: undefined,\n inherited: false,\n affects: S\n }),\n\n /** Supplementary text read after the name: a hint, an error. */\n description: defineProperty<string | undefined>({\n name: 'description',\n defaultValue: undefined,\n inherited: false,\n affects: S\n }),\n\n /**\n * A live region: a screen reader announces this node's text when it\n * changes, without focus moving there. `polite` waits for a pause,\n * `assertive` interrupts. The roles `status` and `alert` imply one.\n */\n live: defineProperty<UiLiveRegion | undefined>({\n name: 'live',\n defaultValue: undefined,\n inherited: false,\n affects: S\n }),\n\n /** Conditions beyond role and value: checked, expanded, invalid, … */\n states: defineProperty<UiSemanticStates | undefined>({\n name: 'states',\n defaultValue: undefined,\n inherited: false,\n affects: S,\n compare: statesEqual,\n validate: validateStates\n }),\n\n /** A range control's current position; with valueMin and valueMax. */\n valueNow: defineProperty<number | undefined>({\n name: 'valueNow',\n defaultValue: undefined,\n inherited: false,\n affects: S\n }),\n\n valueMin: defineProperty<number | undefined>({\n name: 'valueMin',\n defaultValue: undefined,\n inherited: false,\n affects: S\n }),\n\n valueMax: defineProperty<number | undefined>({\n name: 'valueMax',\n defaultValue: undefined,\n inherited: false,\n affects: S\n }),\n\n /** How the value should be spoken, when the number is not it (\"40%\"). */\n valueText: defineProperty<string | undefined>({\n name: 'valueText',\n defaultValue: undefined,\n inherited: false,\n affects: S\n }),\n\n /** 1-based position in a set, for a virtualized list's rows. */\n posInSet: defineProperty<number | undefined>({\n name: 'posInSet',\n defaultValue: undefined,\n inherited: false,\n affects: S\n }),\n\n /** How many items the set holds, including the ones not mounted. */\n setSize: defineProperty<number | undefined>({\n name: 'setSize',\n defaultValue: undefined,\n inherited: false,\n affects: S\n }),\n\n /**\n * How deep a treeitem sits, 1 for a root. A tree is rendered as a\n * flat list of rows — it must be, to be virtualized — so the nesting\n * exists nowhere else for a reader to find.\n */\n level: defineProperty<number | undefined>({\n name: 'level',\n defaultValue: undefined,\n inherited: false,\n affects: S\n }),\n\n // -------------------------------------------------------------------------\n // Transform\n // -------------------------------------------------------------------------\n\n /** Any subset of x, y, scaleX, scaleY, rotation; the rest is identity. */\n transform: defineProperty<Partial<UiTransform> | undefined>({\n name: 'transform',\n defaultValue: undefined,\n inherited: false,\n affects: P | T,\n compare: (a, b) => {\n if (a === undefined && b === undefined) return true;\n if (a === undefined || b === undefined) return false;\n return transformsEqual(transform(a), transform(b));\n }\n }),\n\n // -------------------------------------------------------------------------\n // Content\n // -------------------------------------------------------------------------\n\n text: defineProperty<string | undefined>({\n name: 'text',\n defaultValue: undefined,\n inherited: false,\n // Semantics too, for the reason `value` carries it: a node's\n // accessible name is its `label` if it has one and its text\n // otherwise, and a name that never changes is worse than no name.\n // Without this a bound counter repainted and a screen reader went\n // on reading the number it first saw, forever.\n affects: C | L | S\n }),\n\n image: defineProperty<UiImage | undefined>({\n name: 'image',\n defaultValue: undefined,\n inherited: false,\n affects: P\n }),\n\n /**\n * A moving picture, drawn where `image` is and under the same\n * `objectFit` and rounded clip.\n *\n * Paint only, like `image`: a video's box comes from the element, so\n * a new frame arriving never moves anything. See `UiVideo.ts` for\n * why the value is a surface with a version rather than a frame.\n */\n video: defineProperty<UiVideoSurface | undefined>({\n name: 'video',\n defaultValue: undefined,\n inherited: false,\n affects: P\n }),\n\n objectFit: defineProperty<UiObjectFit | undefined>({\n name: 'objectFit',\n defaultValue: undefined,\n inherited: false,\n affects: P\n }),\n\n scrollX: defineProperty<number | undefined>({\n name: 'scrollX',\n defaultValue: undefined,\n inherited: false,\n affects: T\n }),\n\n /**\n * Whether a wheel moves this container at once or animates it.\n *\n * `'instant'` opts out of the smoothing a notched wheel gets by\n * default. Only the wheel consults it — a scrollbar thumb drag, a\n * focus reveal and a caret reveal are always instant, because each\n * of them is already tracking something the person is doing.\n *\n * It affects nothing that is laid out or painted; it is a policy the\n * input layer reads, and it is registered rather than read loosely\n * so that a misspelling is an error instead of silence.\n */\n scrollBehavior: defineProperty<'instant' | 'smooth' | undefined>({\n name: 'scrollBehavior',\n defaultValue: undefined,\n inherited: false,\n affects: DirtyFlags.None\n }),\n\n scrollY: defineProperty<number | undefined>({\n name: 'scrollY',\n defaultValue: undefined,\n inherited: false,\n affects: T\n }),\n\n /**\n * What happens to a wheel delta this node cannot use.\n *\n * Named after the CSS property it means the same thing as.\n * `'auto'`, the default, chains the leftover to the nearest\n * ancestor that can scroll — and when nothing in the runtime can,\n * lets it out to whatever the canvas is embedded in, so a page\n * around the canvas keeps scrolling. `'contain'` keeps it: the\n * chain stops at this node and the shell prevents the browser's\n * default.\n *\n * The distinction only matters at the point where scrolling runs\n * out, which is exactly where getting it wrong is most visible. An\n * app that fills the viewport wants `'contain'` on its root and\n * nothing outside it moves; a live example embedded in an article\n * wants the default, or the article stops scrolling whenever the\n * cursor crosses the canvas.\n *\n * Like `scrollBehavior`, this is read by the input layer and\n * affects nothing laid out or painted.\n */\n overscrollBehavior: defineProperty<'auto' | 'contain' | undefined>({\n name: 'overscrollBehavior',\n defaultValue: undefined,\n inherited: false,\n affects: DirtyFlags.None\n }),\n\n // -------------------------------------------------------------------------\n // Interaction and internal markers\n // -------------------------------------------------------------------------\n\n /** False skips the node itself in hit testing; its children still hit. */\n hitTestable: defineProperty<boolean | undefined>({\n name: 'hitTestable',\n defaultValue: undefined,\n inherited: false,\n affects: DirtyFlags.Properties\n }),\n\n /** Set by LazyColumn/LazyRow on each mounted item wrapper: its index. */\n virtualIndex: defineProperty<number | undefined>({\n name: 'virtualIndex',\n defaultValue: undefined,\n inherited: false,\n affects: DirtyFlags.Properties\n }),\n\n /** Set by LazyGrid on its header: the content above the first row. */\n virtualLead: defineProperty<boolean | undefined>({\n name: 'virtualLead',\n defaultValue: undefined,\n inherited: false,\n affects: DirtyFlags.Properties\n }),\n\n /** Set by LazyColumn/LazyRow on the scroll container: its UiVirtualWindow. */\n virtualWindow: defineProperty<UiVirtualWindow | undefined>({\n name: 'virtualWindow',\n defaultValue: undefined,\n inherited: false,\n affects: DirtyFlags.Properties\n }),\n\n /** Set by LazySheet on the scroll container: its UiVirtualSheet. */\n virtualSheet: defineProperty<UiVirtualSheet | undefined>({\n name: 'virtualSheet',\n defaultValue: undefined,\n inherited: false,\n affects: DirtyFlags.Properties\n }),\n\n // -------------------------------------------------------------------------\n // Environment provider properties\n // -------------------------------------------------------------------------\n\n theme: defineProperty<UiTheme | undefined>({\n name: 'theme',\n defaultValue: undefined,\n inherited: false,\n affects: E\n }),\n\n /**\n * The type this element and its subtree are written in: a role in\n * the theme's scale (`textStyle=\"title\"`), or a style of its own.\n *\n * A role is looked up in the theme the element is under, so the same\n * `title` is one size on a phone theme and another on a dense one,\n * and neither is written on the element. `UiGraph` resolves it while\n * it builds the environment, which is the same place the theme it\n * resolves against arrives.\n */\n textStyle: defineProperty<UiTextStyle | UiTypographyRole | undefined>({\n name: 'textStyle',\n defaultValue: undefined,\n inherited: false,\n affects: E\n }),\n\n contentColor: defineProperty<UiColorValue | undefined>({\n name: 'contentColor',\n defaultValue: undefined,\n inherited: false,\n affects: E\n }),\n\n /**\n * Declares this node a size query container: its content size is\n * published to the subtree through `UiEnvironmentKeys.containerSize`,\n * so a descendant can lay itself out from the room it has rather\n * than from the window's width.\n *\n * The value is the source object, not the size. `Responsive` builds\n * one and feeds it; an author who wants the size somewhere the\n * helper's children cannot reach builds a `UiContainerSizeSource`,\n * puts it here, and attaches `sizeContainer` with the same object.\n */\n containerSize: defineProperty<UiContainerSize | undefined>({\n name: 'containerSize',\n defaultValue: undefined,\n inherited: false,\n affects: E\n }),\n\n /**\n * What is in the way of the content in this subtree, on each edge.\n *\n * A `UiInsetRegistry` an application provides once at its root; a\n * floating bar publishes into it with `publishInset`, and a scrolling\n * screen keeps clear of whatever is in it with `insetPadding`. See\n * `environment/UiInsets.ts`.\n */\n insets: defineProperty<UiInsetSource | undefined>({\n name: 'insets',\n defaultValue: undefined,\n inherited: false,\n affects: E\n }),\n\n // -------------------------------------------------------------------------\n // Visual state\n // -------------------------------------------------------------------------\n\n visualState: defineProperty<UiVisualStateSet>({\n name: 'visualState',\n defaultValue: defaultVisualState,\n inherited: false,\n affects: P,\n compare: visualStatesEqual\n }),\n\n // -------------------------------------------------------------------------\n // Painting\n // -------------------------------------------------------------------------\n\n /**\n * What an application draws into a node itself.\n *\n * Layout as well as paint, for the reason `text` carries layout: a\n * painter may declare an intrinsic size, and a node sized by its\n * content has to be measured again when that content changes. A\n * painted node with an explicit width and height is a relayout\n * boundary, so a chart repainting on a stream re-measures one leaf.\n *\n * See `rendering/PaintSurface.ts` for the vocabulary.\n */\n paint: defineProperty<UiPaint | undefined>({\n name: 'paint',\n defaultValue: undefined,\n inherited: false,\n affects: L | P,\n compare: paintValuesEqual\n }),\n\n /** A static vector shape: `rendering/PaintSurface.ts`'s `UiPath`. */\n path: defineProperty<UiPath | undefined>({\n name: 'path',\n defaultValue: undefined,\n inherited: false,\n affects: P,\n compare: pathValuesEqual\n }),\n\n /**\n * SVG path data the node's painted content is clipped to, in its own\n * logical pixels. A rounded mask, without the painter restating it.\n */\n clipPath: defineProperty<string | undefined>({\n name: 'clipPath',\n defaultValue: undefined,\n inherited: false,\n affects: P\n }),\n\n /**\n * Blurs the node's painted content, by a radius in logical pixels.\n *\n * The painted content only: blurring a subtree, and blurring what\n * lies behind one, both need an offscreen pass the WebGPU backend\n * does not have says so rather than shipping\n * the Canvas2D half of it.\n */\n blur: defineProperty<number | undefined>({\n name: 'blur',\n defaultValue: undefined,\n inherited: false,\n affects: P\n })\n} as const;\n\nexport type UiPropertyName = keyof typeof UiProperties;\n\n/** The value type a property definition was declared with. */\nexport type UiPropertyValueOf<D> = D extends UiPropertyDefinition<infer T> ? T : never;\n\n/**\n * Property name → value type, derived from the registry so that the\n * authoring types (`TextProps`, `RowProps`, …) can never disagree with\n * what the runtime reads.\n */\nexport type UiPropertyValues = {\n readonly [K in UiPropertyName]: UiPropertyValueOf<(typeof UiProperties)[K]>;\n};\n","import { DirtyFlags } from '../graph/DirtyFlags';\nimport { UiProperties } from './UiProperty';\nimport type { UiPropertyDefinition } from './UiPropertyDefinition';\n\n/**\n * Lookup table from property name to its definition.\n */\nconst registry = new Map<string, UiPropertyDefinition<unknown>>();\n\nfor (const definition of Object.values(UiProperties)) {\n registry.set(definition.name, definition as UiPropertyDefinition<unknown>);\n}\n\n/**\n * Returns the property definition for the supplied name, or\n * undefined when no definition exists.\n */\nexport function findPropertyDefinition<T>(name: string): UiPropertyDefinition<T> | undefined {\n return registry.get(name) as UiPropertyDefinition<T> | undefined;\n}\n\n/**\n * Returns all registered property names.\n */\nexport function getPropertyNames(): string[] {\n return Array.from(registry.keys());\n}\n\n/**\n * Returns the dirty flags caused by changing the named property.\n *\n * Unknown properties are treated as generic property changes so\n * they are never silently ignored.\n */\nexport function propertyEffects(name: string): DirtyFlags {\n const definition = findPropertyDefinition<unknown>(name);\n if (definition !== undefined) {\n return definition.affects;\n }\n return DirtyFlags.Properties;\n}\n\n/**\n * The registered property name closest to `name`, for the error a\n * misspelled prop raises; undefined when nothing is reasonably close.\n * Case differences count as one edit so `Width` suggests `width`.\n */\nexport function closestPropertyName(name: string, candidates: Iterable<string> = registry.keys()): string | undefined {\n let best: string | undefined;\n let bestDistance = Infinity;\n const target = name.toLowerCase();\n for (const candidate of candidates) {\n const distance = editDistance(target, candidate.toLowerCase());\n if (distance < bestDistance) {\n bestDistance = distance;\n best = candidate;\n }\n }\n // Allow more edits for longer names; a two-letter prop must be exact.\n return best !== undefined && bestDistance <= Math.max(1, Math.floor(name.length / 3)) ? best : undefined;\n}\n\n/** Edits between two strings, an adjacent transposition (`widht`) counting as one. */\nfunction editDistance(a: string, b: string): number {\n const rows: number[][] = [];\n for (let i = 0; i <= a.length; i++) {\n rows.push(Array.from({ length: b.length + 1 }, () => 0));\n rows[i][0] = i;\n }\n for (let j = 0; j <= b.length; j++) {\n rows[0][j] = j;\n }\n for (let i = 1; i <= a.length; i++) {\n for (let j = 1; j <= b.length; j++) {\n const cost = a[i - 1] === b[j - 1] ? 0 : 1;\n let best = Math.min(rows[i - 1][j] + 1, rows[i][j - 1] + 1, rows[i - 1][j - 1] + cost);\n if (i > 1 && j > 1 && a[i - 1] === b[j - 2] && a[i - 2] === b[j - 1]) {\n best = Math.min(best, rows[i - 2][j - 2] + 1);\n }\n rows[i][j] = best;\n }\n }\n return rows[a.length][b.length];\n}\n\n/**\n * Returns true when the named property is declared as inherited.\n */\nexport function propertyIsInherited(name: string): boolean {\n const definition = findPropertyDefinition<unknown>(name);\n return definition?.inherited ?? false;\n}\n\n/**\n * The names of all declared inherited properties.\n */\nexport function inheritedPropertyNames(): string[] {\n const names: string[] = [];\n for (const definition of registry.values()) {\n if (definition.inherited) {\n names.push(definition.name);\n }\n }\n return names;\n}\n\n/**\n * The union of the dirty flags every inherited property affects.\n *\n * This is what an environment change has to mark on the nodes it\n * reaches, and the registry is fixed at module load, so it is computed\n * once rather than on every propagation.\n */\nexport const inheritedPropertyFlags: DirtyFlags = (() => {\n let flags = DirtyFlags.None;\n for (const definition of registry.values()) {\n if (definition.inherited) {\n flags |= definition.affects;\n }\n }\n // Nothing inherited still has to repaint: a node that resolved a\n // default is drawn with it.\n return flags === DirtyFlags.None ? DirtyFlags.Paint : flags;\n})();\n\n/**\n * Compares two values for the named property using the definition's\n * comparison function, falling back to Object.is.\n */\nexport function propertyValuesEqualByName<T>(name: string, a: T, b: T): boolean {\n const definition = findPropertyDefinition<T>(name);\n if (definition !== undefined && definition.compare !== undefined) {\n return definition.compare(a, b);\n }\n return Object.is(a, b);\n}\n","import { DirtyFlags } from './DirtyFlags';\nimport { writeDeclaredProperty } from './UiPropertyOverrides';\nimport { DirtyNodeSet } from './DirtyNodeSet';\nimport { type NodeId, type NodeProperty, UiNode } from './UiNode';\nimport { UiNodeType } from './UiNodeType';\nimport { type BindingId, UiBinding } from '../bindings/UiBinding';\nimport type { UiChildrenBinding } from '../bindings/UiChildrenBinding';\nimport type { UiEventBinding } from '../bindings/UiEventBinding';\nimport { UiEnvironment } from '../environment/UiEnvironment';\nimport { findEnvironmentKey, type UiEnvironmentKey } from '../environment/UiEnvironmentKey';\nimport { UiEnvironmentKeys } from '../environment/UiEnvironmentKeys';\nimport { isTypographyRole } from '../environment/UiTypography';\nimport { inheritedPropertyFlags } from '../properties/UiPropertyRegistry';\nimport type { Observable } from 'rxjs';\n\nexport class UiGraph {\n constructor() {\n this.root = new UiNode('root', UiNodeType.Root);\n this.root.environment = new UiEnvironment(null);\n this.nodes.set(this.root.id, this.root);\n }\n\n private readonly nodes = new Map<NodeId, UiNode>();\n\n /**\n * Nodes that are roots of invalidated regions.\n *\n * We don't necessarily put every dirty descendant here.\n * A single subtree-invalidated node can represent thousands\n * of affected descendants.\n */\n private readonly dirtyNodes = new DirtyNodeSet();\n\n /**\n * Notified whenever a node newly becomes dirty.\n *\n * A scheduler subscribes here so that marking dirty can arm\n * a frame without the graph knowing about timing.\n */\n private dirtyListener: (() => void) | null = null;\n\n /**\n * Notified whenever a node is removed from the graph.\n *\n * Consumers that keep per-node projections (such as the\n * layout engine) subscribe here so their state stays in sync\n * with tree lifetime.\n */\n private nodeRemovedListener: ((node: UiNode) => void) | null = null;\n private environmentChangedListener: ((node: UiNode) => void) | null = null;\n\n public readonly root: UiNode;\n\n private readonly bindings = new Map<BindingId, UiBinding<unknown>>();\n\n /**\n * Property bindings, keyed by node then by the property they drive.\n *\n * Keyed by node object rather than by id: the id is a concatenated\n * path whose length grows with depth, so hashing it costs more the\n * deeper the tree, and every teardown and rebind would pay it. The\n * inner map means finding the binding for one property is a lookup\n * rather than a scan of everything bound on the node.\n */\n private readonly nodeBindings = new Map<UiNode, Map<NodeProperty, UiBinding<unknown>>>();\n\n private readonly childrenBindings = new Map<UiNode, UiChildrenBinding>();\n\n /**\n * Declarative `on*` handlers, keyed by node then event type.\n *\n * Stored here rather than only in the dispatcher so that removing a\n * node tears its handlers down through the same path as its property\n * and children bindings.\n */\n private readonly eventBindings = new Map<UiNode, Map<string, UiEventBinding>>();\n\n private nextBindingId = 0;\n\n /** Set when any node is marked DirtyFlags.Environment. */\n private environmentDirty = false;\n\n /**\n * Set while the environment phase is rebuilding.\n *\n * That phase runs from the scheduler's pre-collect hook, so the\n * nodes it dirties are collected by the frame already in flight.\n * Letting those marks reach the dirty listener would arm a second,\n * redundant frame behind it.\n */\n private suppressDirtyListener = false;\n\n // ---------------------------------------------------------------------------\n // Node lookup\n // ---------------------------------------------------------------------------\n\n public getNode(id: NodeId): UiNode | undefined {\n return this.nodes.get(id);\n }\n\n public requireNode(id: NodeId): UiNode {\n const node = this.nodes.get(id);\n if (!node) {\n throw new Error(`UI node '${id}' does not exist.`);\n }\n return node;\n }\n\n public hasNode(id: NodeId): boolean {\n return this.nodes.has(id);\n }\n\n public get size(): number {\n return this.nodes.size;\n }\n\n // ---------------------------------------------------------------------------\n // Node creation\n // ---------------------------------------------------------------------------\n\n public createNode(id: NodeId, type: UiNodeType): UiNode {\n if (this.nodes.has(id)) {\n throw new Error(`UI node '${id}' already exists.`);\n }\n const node = new UiNode(id, type);\n this.nodes.set(id, node);\n return node;\n }\n\n // ---------------------------------------------------------------------------\n // Tree manipulation\n // ---------------------------------------------------------------------------\n\n public appendChild(parent: UiNode, child: UiNode): void {\n if (child.parent !== null) {\n throw new Error(`Node '${child.id}' already has a parent.`);\n }\n child.parent = parent;\n parent.childOrderVersion++;\n if (parent.lastChild === null) {\n // First child.\n parent.firstChild = child;\n parent.lastChild = child;\n this.inheritEnvironment(child);\n return;\n }\n const previous = parent.lastChild;\n previous.nextSibling = child;\n child.previousSibling = previous;\n parent.lastChild = child;\n this.inheritEnvironment(child);\n }\n\n /**\n * Inserts a child before the reference child.\n *\n * When reference is null the child is appended to the end.\n */\n public insertBefore(parent: UiNode, child: UiNode, reference: UiNode | null): void {\n if (child.parent !== null) {\n throw new Error(`Node '${child.id}' already has a parent.`);\n }\n if (reference !== null && reference.parent !== parent) {\n throw new Error(`Reference node '${reference.id}' is not a child of '${parent.id}'.`);\n }\n if (reference === null) {\n this.appendChild(parent, child);\n return;\n }\n parent.childOrderVersion++;\n const previous = reference.previousSibling;\n if (previous !== null) {\n previous.nextSibling = child;\n } else {\n parent.firstChild = child;\n }\n child.parent = parent;\n child.previousSibling = previous;\n child.nextSibling = reference;\n reference.previousSibling = child;\n // The reference keeps its place after the child, so the last child\n // does not change. Setting it to the child here, as this once did,\n // made every later append hang off the middle of the chain and left\n // the true tail registered but unreachable.\n this.inheritEnvironment(child);\n }\n\n public removeNode(node: UiNode): void {\n const parent = node.parent;\n // Remove the whole subtree, not just the node itself: a\n // detached child would otherwise stay indexed with stale\n // dirty state and live bindings.\n const stack: UiNode[] = [node];\n while (stack.length > 0) {\n const current = stack.pop()!;\n // First stop all reactive subscriptions.\n this.unbindNode(current);\n this.unbindChildren(current);\n this.unbindEvents(current);\n // Then remove it from the tree.\n this.detachNode(current);\n // Remove it from the node index.\n this.nodes.delete(current.id);\n // Remove any dirty state.\n this.dirtyNodes.delete(current);\n for (let child = current.firstChild; child !== null; child = child.nextSibling) {\n stack.push(child);\n }\n }\n // Structure change: the parent must be re-laid out.\n if (parent !== null) {\n this.markDirty(parent, DirtyFlags.Children);\n }\n // Notify projection consumers (layout engine) last. The\n // engine's detachNode walks the subtree itself, so a single\n // notification covers every removed record.\n this.nodeRemovedListener?.(node);\n }\n\n public detachNode(node: UiNode): void {\n const parent = node.parent;\n if (!parent) {\n return;\n }\n parent.childOrderVersion++;\n const previous = node.previousSibling;\n const next = node.nextSibling;\n if (previous) {\n previous.nextSibling = next;\n } else {\n parent.firstChild = next;\n }\n if (next) {\n next.previousSibling = previous;\n } else {\n parent.lastChild = previous;\n }\n node.parent = null;\n node.previousSibling = null;\n node.nextSibling = null;\n }\n\n // ---------------------------------------------------------------------------\n // Bindings\n // ---------------------------------------------------------------------------\n\n /**\n * The binding driving one property of one node, if any.\n */\n public getBindingForProperty(node: UiNode, property: NodeProperty): UiBinding<unknown> | undefined {\n return this.nodeBindings.get(node)?.get(property);\n }\n\n public bind(\n node: UiNode,\n property: NodeProperty,\n observable: Observable<unknown>,\n dirtyFlags: DirtyFlags\n ): UiBinding<unknown> {\n // Make sure the node actually belongs to this graph.\n const registeredNode = this.nodes.get(node.id);\n if (registeredNode !== node) {\n throw new Error(`Cannot bind to node '${node.id}' because it does not belong to this graph.`);\n }\n let byProperty = this.nodeBindings.get(node);\n if (byProperty !== undefined && byProperty.has(property)) {\n throw new Error(`Property '${property}' on node '${node.id}' is already bound.`);\n }\n const bindingId = this.nextBindingId++;\n const binding = new UiBinding(bindingId, node, property, observable, this, dirtyFlags);\n // Global binding lookup.\n this.bindings.set(bindingId, binding);\n // Node → property → binding lookup.\n if (byProperty === undefined) {\n byProperty = new Map<NodeProperty, UiBinding<unknown>>();\n this.nodeBindings.set(node, byProperty);\n }\n byProperty.set(property, binding);\n // Start receiving values.\n binding.connect();\n return binding;\n }\n\n public unbind(binding: UiBinding<unknown>): void {\n const registeredBinding = this.bindings.get(binding.id);\n // Already removed.\n if (registeredBinding !== binding) {\n return;\n }\n // Stop the RxJS subscription.\n binding.disconnect();\n // Remove global lookup.\n this.bindings.delete(binding.id);\n // Remove node → binding relationship.\n const byProperty = this.nodeBindings.get(binding.node);\n if (byProperty !== undefined && byProperty.get(binding.property) === binding) {\n byProperty.delete(binding.property);\n if (byProperty.size === 0) {\n this.nodeBindings.delete(binding.node);\n }\n }\n }\n\n public unbindNode(node: UiNode): void {\n const byProperty = this.nodeBindings.get(node);\n if (byProperty === undefined) {\n return;\n }\n // Drop the index first so each unbind() below finds nothing left\n // to remove and cannot mutate the map being iterated.\n this.nodeBindings.delete(node);\n for (const binding of byProperty.values()) {\n binding.disconnect();\n this.bindings.delete(binding.id);\n }\n }\n\n public handleBindingError(binding: UiBinding<unknown>, error: unknown): void {\n console.error(`UI binding ${binding.id} failed ` + `(${binding.nodeId}.${binding.property})`, error);\n this.unbind(binding);\n }\n\n /**\n * A modifier threw in `attach`, `update` or `detach`.\n *\n * Reported here rather than allowed to propagate for the reason a\n * binding error is: the throw happens inside the builder, halfway\n * through reconciling a subtree, and letting it out leaves the tree\n * partly built with no way back. The caller detaches the modifier,\n * so the node keeps whatever the element declared and the rest of\n * the frame goes on.\n *\n * Like `handleBindingError`, this reaches the console and not the\n * error overlay. Both should, and neither does; that is one channel\n * to add, not two.\n */\n public handleModifierError(name: string, node: UiNode, phase: 'attach' | 'update' | 'detach', error: unknown): void {\n console.error(`UI modifier '${name}' threw in ${phase} on node '${node.id}'`, error);\n }\n\n public getBindingsForNode(node: UiNode): UiBinding<unknown>[] {\n const byProperty = this.nodeBindings.get(node);\n return byProperty === undefined ? [] : [...byProperty.values()];\n }\n\n /**\n * How many live subscriptions one node holds: the properties an\n * Observable drives, its children binding when its children are\n * reactive, and its declarative event handlers.\n *\n * The three are counted together because the question a devtools\n * subscription view asks is \"what is this component still holding\n * on to\", and a leak looks the same whichever of the three it is.\n */\n public subscriptionsForNode(node: UiNode): number {\n return (\n (this.nodeBindings.get(node)?.size ?? 0) +\n (this.childrenBindings.has(node) ? 1 : 0) +\n (this.eventBindings.get(node)?.size ?? 0)\n );\n }\n\n /**\n * Every live subscription in the graph.\n *\n * Counted on demand rather than kept as a running total: a counter\n * maintained across `unbind`, `unbindNode`, `unbindChildren` and\n * `unbindEvents` is a counter that drifts, and drift is precisely\n * the thing a leak hunt cannot tolerate. Nothing calls this unless a\n * panel is attached.\n */\n public get subscriptionCount(): number {\n let count = this.bindings.size + this.childrenBindings.size;\n for (const byType of this.eventBindings.values()) {\n count += byType.size;\n }\n return count;\n }\n\n // ---------------------------------------------------------------------------\n // Children bindings\n // ---------------------------------------------------------------------------\n\n public getChildrenBindingForNode(node: UiNode): UiChildrenBinding | undefined {\n return this.childrenBindings.get(node);\n }\n\n public bindChildren(fragmentNode: UiNode, binding: UiChildrenBinding): void {\n const registeredNode = this.nodes.get(fragmentNode.id);\n if (registeredNode !== fragmentNode) {\n throw new Error(`Cannot bind children to node '${fragmentNode.id}' because it does not belong to this graph.`);\n }\n this.childrenBindings.set(fragmentNode, binding);\n binding.connect();\n }\n\n public unbindChildren(node: UiNode): void {\n const binding = this.childrenBindings.get(node);\n if (binding === undefined) {\n return;\n }\n binding.disconnect();\n this.childrenBindings.delete(node);\n }\n\n // ---------------------------------------------------------------------------\n // Event bindings\n // ---------------------------------------------------------------------------\n\n public getEventBindingsForNode(node: UiNode): UiEventBinding[] {\n const byType = this.eventBindings.get(node);\n return byType === undefined ? [] : [...byType.values()];\n }\n\n /**\n * The handler bound to one event type on one node, if any.\n */\n public getEventBindingForType(node: UiNode, type: string): UiEventBinding | undefined {\n return this.eventBindings.get(node)?.get(type);\n }\n\n public bindEvent(node: UiNode, binding: UiEventBinding): void {\n const registeredNode = this.nodes.get(node.id);\n if (registeredNode !== node) {\n throw new Error(`Cannot bind events to node '${node.id}' because it does not belong to this graph.`);\n }\n let byType = this.eventBindings.get(node);\n if (byType === undefined) {\n byType = new Map();\n this.eventBindings.set(node, byType);\n }\n const existing = byType.get(binding.type);\n if (existing !== undefined) {\n existing.disconnect();\n }\n byType.set(binding.type, binding);\n binding.connect();\n }\n\n public unbindEvent(node: UiNode, binding: UiEventBinding): void {\n const byType = this.eventBindings.get(node);\n if (byType === undefined || byType.get(binding.type) !== binding) {\n return;\n }\n binding.disconnect();\n byType.delete(binding.type);\n if (byType.size === 0) {\n this.eventBindings.delete(node);\n }\n }\n\n public unbindEvents(node: UiNode): void {\n const byType = this.eventBindings.get(node);\n if (byType === undefined) {\n return;\n }\n this.eventBindings.delete(node);\n for (const binding of byType.values()) {\n binding.disconnect();\n }\n }\n\n // ---------------------------------------------------------------------------\n // Dirty state\n // ---------------------------------------------------------------------------\n\n public markDirty(node: UiNode, flags: DirtyFlags): void {\n const newlyDirty = this.dirtyNodes.mark(node);\n node.dirtyFlags |= flags;\n if ((flags & DirtyFlags.Environment) !== 0) {\n this.environmentDirty = true;\n }\n if (newlyDirty && !this.suppressDirtyListener) {\n this.dirtyListener?.();\n }\n }\n\n /**\n * Whether any node is waiting for its environment to be rebuilt.\n *\n * Lets a frame skip the environment phase outright, which is the\n * common case: themes change far less often than anything else.\n */\n public hasEnvironmentDirty(): boolean {\n return this.environmentDirty;\n }\n\n public markDirtyById(id: NodeId, flags: DirtyFlags): void {\n const node = this.requireNode(id);\n this.markDirty(node, flags);\n }\n\n public clearDirty(node: UiNode): void {\n node.dirtyFlags = DirtyFlags.None;\n this.dirtyNodes.delete(node);\n }\n\n /**\n * Subscribes to new dirty marks.\n *\n * The listener is invoked once per node that newly enters the\n * dirty set. Pass null to clear the subscription.\n */\n public setDirtyListener(listener: (() => void) | null): void {\n this.dirtyListener = listener;\n }\n\n /**\n * Subscribes to node removals.\n *\n * The listener is invoked once per removed node. Pass null to\n * clear the subscription.\n */\n public setNodeRemovedListener(listener: ((node: UiNode) => void) | null): void {\n this.nodeRemovedListener = listener;\n }\n\n /**\n * Subscribes to environment reassignment.\n *\n * Invoked once per node whose inherited environment resolved to\n * something different — at attach, and after a provider above it\n * changed. An inherited *property* needs no such thing, because the\n * node is marked dirty and re-resolves on the next frame; a modifier\n * that read a value out of the environment holds it where no dirty\n * flag reaches, which is what this exists for.\n */\n public setEnvironmentChangedListener(listener: ((node: UiNode) => void) | null): void {\n this.environmentChangedListener = listener;\n }\n\n /**\n * The shared dirty set, for a scheduler to drain.\n */\n public getDirtyNodes(): DirtyNodeSet {\n return this.dirtyNodes;\n }\n\n public updateProperty<T>(\n nodeId: string,\n property: string,\n value: T,\n dirtyFlags: DirtyFlags = DirtyFlags.Properties\n ): boolean {\n return this.updateNodeProperty(this.requireNode(nodeId), property, value, dirtyFlags);\n }\n\n /**\n * Writes a property, marking the node dirty only when the value\n * actually changed.\n *\n * The node-taking form of updateProperty, for callers that already\n * hold the node and would otherwise pay for an id lookup.\n */\n public updateNodeProperty<T>(\n node: UiNode,\n property: string,\n value: T,\n dirtyFlags: DirtyFlags = DirtyFlags.Properties\n ): boolean {\n // A declared transition turns this write into a target rather than\n // a value. It sits here, above the cascade, for the reason the\n // cascade sits here at all: the builder's static\n // writes and a binding's emissions both funnel through this one\n // method, so it is the only place that catches both. One field\n // read for every node that declares no transition.\n if (node.transitions !== null && node.transitions.write(property, value, dirtyFlags)) {\n return true;\n }\n return this.updateNodePropertyNow(node, property, value, dirtyFlags);\n }\n\n /**\n * Writes a property without consulting the node's transitions.\n *\n * What a transition's own per-frame writes go through: they are\n * already the animation towards the target, so re-entering the\n * transition check would have each frame start an animation towards\n * the value it had just produced. Everything below this — the\n * override cascade, the equality check, the dirty marking — is\n * unchanged, so an animated value is overridable by a modifier\n * exactly as a bound one is.\n */\n public updateNodePropertyNow<T>(\n node: UiNode,\n property: string,\n value: T,\n dirtyFlags: DirtyFlags = DirtyFlags.Properties\n ): boolean {\n if (node.overrides !== null) {\n // A modifier is writing over something on this node, so the\n // element's value goes into the cascade rather than onto the\n // node. One field read for every node that has no modifiers.\n return writeDeclaredProperty(this, node, property, value, dirtyFlags);\n }\n return this.applyResolvedProperty(node, property, true, value, dirtyFlags);\n }\n\n /**\n * Writes the value a cascade resolved to, or removes the property\n * when it resolved to nothing.\n *\n * Removing rather than writing a default is what lets a detaching\n * modifier restore inheritance: a node that never declared `color`\n * reads it from the environment again, as it did before.\n */\n public applyResolvedProperty(\n node: UiNode,\n property: NodeProperty,\n present: boolean,\n value: unknown,\n dirtyFlags: DirtyFlags\n ): boolean {\n if (!present) {\n if (!node.properties.has(property)) {\n return false;\n }\n node.properties.delete(property);\n this.markDirty(node, dirtyFlags);\n return true;\n }\n const previousValue = node.getProperty(property);\n if (Object.is(previousValue, value)) {\n return false;\n }\n node.setProperty(property, value);\n this.markDirty(node, dirtyFlags);\n return true;\n }\n\n // ---------------------------------------------------------------------------\n // Dirty traversal\n // ---------------------------------------------------------------------------\n\n /**\n * Drains the dirty set and visits every node of every dirty subtree.\n *\n * Dirty roots can nest, so a node reached from an outer root is not\n * visited again when its own root comes up.\n */\n public processDirty(callback: (node: UiNode) => void): void {\n const roots = this.dirtyNodes.take();\n if (roots.length <= 1) {\n if (roots.length === 1) {\n this.traverse(roots[0], callback);\n }\n return;\n }\n const visited = new Set<UiNode>();\n for (const root of roots) {\n this.traverseOnce(root, visited, callback);\n }\n }\n\n /**\n * Pre-order traversal that stops at anything an earlier root already\n * covered.\n *\n * A visited node implies a visited subtree, because every traversal\n * runs to the leaves, so the whole branch can be skipped rather than\n * re-walked and filtered.\n */\n private traverseOnce(node: UiNode, visited: Set<UiNode>, callback: (node: UiNode) => void): void {\n if (visited.has(node)) {\n return;\n }\n visited.add(node);\n callback(node);\n let child = node.firstChild;\n while (child !== null) {\n this.traverseOnce(child, visited, callback);\n child = child.nextSibling;\n }\n }\n\n public traverse(node: UiNode, callback: (node: UiNode) => void): void {\n callback(node);\n let child = node.firstChild;\n while (child !== null) {\n this.traverse(child, callback);\n child = child.nextSibling;\n }\n }\n\n public traverseChildren(node: UiNode, callback: (child: UiNode) => void): void {\n let child = node.firstChild;\n while (child !== null) {\n callback(child);\n child = child.nextSibling;\n }\n }\n\n // ---------------------------------------------------------------------------\n // Environment propagation\n // ---------------------------------------------------------------------------\n\n /**\n * Builds the environment a node should use given its parent and its\n * own provider properties.\n *\n * `parent` defaults to the node's own, and is passed explicitly for\n * a node the builder has constructed but not yet put in the tree —\n * which is every node at the moment its modifiers attach.\n */\n public buildNodeEnvironment(node: UiNode, parent: UiNode | null = node.parent): UiEnvironment {\n const base = parent !== null ? parent.environment : null;\n let env = base ?? new UiEnvironment(null);\n\n const theme = node.getProperty<unknown>('theme');\n if (theme !== undefined) {\n env = env.set(UiEnvironmentKeys.theme as UiEnvironmentKey<unknown>, theme);\n }\n\n const textStyle = node.getProperty<unknown>('textStyle');\n if (textStyle !== undefined) {\n // A role name is looked up in the theme this node is under,\n // which is the environment built so far and so includes a theme\n // the same node provides. Resolved here rather than at paint\n // because the text properties already inherit through this key,\n // and a role that turned into a style anywhere later would be a\n // second resolution path for the same six numbers.\n const scale = env.get(UiEnvironmentKeys.theme).typography;\n if (isTypographyRole(textStyle, scale)) {\n const style = (scale as unknown as Record<string, unknown>)[textStyle];\n env = env.set(UiEnvironmentKeys.textStyle as UiEnvironmentKey<unknown>, style);\n } else if (typeof textStyle !== 'string') {\n env = env.set(UiEnvironmentKeys.textStyle as UiEnvironmentKey<unknown>, textStyle);\n }\n // A string the scale does not carry provides nothing: the\n // subtree keeps the type it inherited, which is quieter than\n // every word under it falling back to a default size.\n }\n\n const contentColor = node.getProperty<unknown>('contentColor');\n if (contentColor !== undefined) {\n env = env.set(UiEnvironmentKeys.contentColor as UiEnvironmentKey<unknown>, contentColor);\n }\n\n // The last two provide a *source* rather than a value: a size that\n // changes with a drag and a set of insets that changes with a\n // keyboard would otherwise rebuild the environment of everything\n // beneath them per frame. The source's identity is what is\n // provided, so it is set once and never compares unequal again.\n const containerSize = node.getProperty<unknown>('containerSize');\n if (containerSize !== undefined) {\n env = env.set(UiEnvironmentKeys.containerSize as UiEnvironmentKey<unknown>, containerSize);\n }\n\n const insets = node.getProperty<unknown>('insets');\n if (insets !== undefined) {\n env = env.set(UiEnvironmentKeys.insets as UiEnvironmentKey<unknown>, insets);\n }\n\n return env;\n }\n\n /**\n * Assigns an environment to a node and returns whether it changed.\n */\n public setNodeEnvironment(node: UiNode, environment: UiEnvironment): boolean {\n const previous = node.environment;\n if (previous === environment) {\n return false;\n }\n node.environment = environment;\n return true;\n }\n\n /**\n * Gives a freshly attached subtree the environment of the tree it\n * joined.\n *\n * Environments used to be built once, when the root was built, and\n * afterwards only for a node whose own provider property changed. So\n * every node mounted later — a keyed list's new row, and every row a\n * lazy list mounts as it scrolls — kept `environment === null` and\n * resolved its palette names against the *default* theme: a row\n * chosen in a dark table came out in the light theme's blue, in a\n * card that had provided a dark theme since the first frame.\n *\n * This runs at attach because the builder writes a node's props and\n * builds its children before putting it in the tree, so by the time\n * an edge is made both the subtree and its new parent's environment\n * are final. The walk is bounded by the subtree being attached, which\n * is what a mount costs anyway.\n */\n private inheritEnvironment(child: UiNode): void {\n if (child.parent?.environment == null) {\n return;\n }\n const visit = (node: UiNode): void => {\n const previous = node.environment;\n const next = this.buildNodeEnvironment(node);\n if (previous === null || !this.environmentsEqual(previous, next)) {\n node.environment = next;\n // A node that already had an environment and now resolves a\n // different one has to repaint. A node that had none is new,\n // and its creation dirtied it already — marking it again would\n // only widen the flags a freshly built node reports.\n if (previous !== null) {\n this.markDirty(node, inheritedPropertyFlags);\n }\n this.environmentChangedListener?.(node);\n }\n for (let current = node.firstChild; current !== null; current = current.nextSibling) {\n visit(current);\n }\n };\n visit(child);\n }\n\n /**\n * Recomputes environments for a node and its descendants after a\n * provider change. Nodes whose environment changes are marked dirty\n * with the flags of the inherited properties they may resolve.\n */\n public propagateEnvironment(node: UiNode): void {\n this.rebuildEnvironment(node, inheritedPropertyFlags);\n }\n\n /**\n * Processes all nodes carrying the Environment dirty flag, propagating\n * the change to descendants and clearing the flag.\n */\n public processEnvironmentDirty(): void {\n this.environmentDirty = false;\n const nodes = this.dirtyNodes.take();\n // This runs inside the frame that is about to collect the dirty\n // set, so the marks below belong to that frame; letting them reach\n // the listener would arm a redundant one behind it.\n this.suppressDirtyListener = true;\n try {\n for (const node of nodes) {\n if ((node.dirtyFlags & DirtyFlags.Environment) !== 0) {\n node.dirtyFlags &= ~DirtyFlags.Environment;\n this.rebuildEnvironment(node, inheritedPropertyFlags);\n }\n if (node.dirtyFlags !== DirtyFlags.None) {\n this.dirtyNodes.mark(node);\n }\n }\n } finally {\n this.suppressDirtyListener = false;\n }\n }\n\n private rebuildEnvironment(node: UiNode, inheritedFlags: DirtyFlags): void {\n const previous = node.environment;\n const next = this.buildNodeEnvironment(node);\n const changed = previous === null || !this.environmentsEqual(previous, next);\n\n // Keep the existing instance when the values match. Environments\n // are immutable snapshots, so holding identity steady is what lets\n // an unchanged subtree be recognised by a pointer compare instead\n // of a key-by-key walk on every propagation.\n if (changed) {\n node.environment = next;\n this.markDirty(node, inheritedFlags);\n this.environmentChangedListener?.(node);\n }\n\n let child = node.firstChild;\n while (child !== null) {\n this.rebuildEnvironment(child, inheritedFlags);\n child = child.nextSibling;\n }\n }\n\n private environmentsEqual(a: UiEnvironment, b: UiEnvironment): boolean {\n // The common case by far: a node that provides nothing gets its\n // parent's environment handed straight back.\n if (a === b) {\n return true;\n }\n if (a.providedSize !== b.providedSize) {\n return false;\n }\n for (const keyName of a.providedKeys()) {\n if (!b.providesOwn(keyName)) {\n return false;\n }\n const previousValue = a.getOwn(keyName);\n const nextValue = b.getOwn(keyName);\n if (Object.is(previousValue, nextValue)) {\n continue;\n }\n // A key without a comparison function falls back to identity\n // rather than counting as a change, which would have re-dirtied\n // the whole subtree on every propagation.\n const key = findEnvironmentKey(keyName);\n const compare = key?.compare;\n if (compare === undefined || !compare(previousValue, nextValue)) {\n return false;\n }\n }\n return true;\n }\n}\n","import type { UiNode } from '../graph/UiNode';\nimport type { UiEnvironmentKey } from '../environment/UiEnvironmentKey';\nimport { findPropertyDefinition } from './UiPropertyRegistry';\nimport type { UiPropertyDefinition } from './UiPropertyDefinition';\n\n/**\n * Resolves a property value for a node.\n *\n * Resolution order:\n *\n * 1. The value explicitly specified on the node.\n * 2. The value inherited from the node's scoped environment.\n * 3. The property definition's default value.\n *\n * The resolver does not allocate and is safe to call from hot paths\n * such as layout and paint.\n */\nexport function resolveProperty<T>(node: UiNode, definition: UiPropertyDefinition<T>): T {\n const specified = node.properties.get(definition.name);\n if (specified !== undefined) {\n return specified as T;\n }\n\n if (definition.inherited && node.environment !== null) {\n const environmentKey = definition.environmentKey;\n if (environmentKey !== undefined) {\n const envValue = node.environment.get(environmentKey);\n if (definition.resolveFromEnvironment !== undefined) {\n return definition.resolveFromEnvironment(envValue);\n }\n return envValue as T;\n }\n\n const fallback = node.environment.get(createFallbackKey(definition));\n if (fallback !== undefined) {\n return fallback as T;\n }\n }\n\n return definition.defaultValue;\n}\n\n/**\n * Resolves a property by name.\n *\n * Returns undefined when no definition exists; callers that know\n * the property exists should use resolveProperty() with the\n * definition for stronger typing.\n */\nexport function resolvePropertyByName<T>(node: UiNode, name: string): T | undefined {\n const definition = findPropertyDefinition<T>(name);\n if (definition === undefined) {\n return undefined;\n }\n return resolveProperty(node, definition);\n}\n\n/**\n * Resolves a numeric property, returning undefined when the value\n * is missing or not a finite number.\n */\nexport function resolveNumber(node: UiNode, name: string): number | undefined {\n const value = resolvePropertyByName<unknown>(node, name);\n if (typeof value === 'number' && Number.isFinite(value)) {\n return value;\n }\n return undefined;\n}\n\n/**\n * Resolves a string property, returning undefined when the value is\n * missing or not a non-empty string.\n */\nexport function resolveString(node: UiNode, name: string): string | undefined {\n const value = resolvePropertyByName<unknown>(node, name);\n if (typeof value === 'string' && value.length > 0) {\n return value;\n }\n return undefined;\n}\n\n/**\n * Resolves a boolean property, returning undefined when the value\n * is missing or not a boolean.\n */\nexport function resolveBoolean(node: UiNode, name: string): boolean | undefined {\n const value = resolvePropertyByName<unknown>(node, name);\n if (typeof value === 'boolean') {\n return value;\n }\n return undefined;\n}\n\n/**\n * Lazily creates a fallback environment key that matches the\n * property name. The key is cached so repeated resolutions of the\n * same property do not allocate.\n */\nconst fallbackKeys = new Map<string, UiEnvironmentKey<unknown>>();\n\nfunction createFallbackKey<T>(definition: UiPropertyDefinition<T>): UiEnvironmentKey<unknown> {\n let key = fallbackKeys.get(definition.name);\n if (key === undefined) {\n key = {\n name: definition.name,\n defaultValue: definition.defaultValue as unknown,\n compare: definition.compare as ((a: unknown, b: unknown) => boolean) | undefined\n };\n fallbackKeys.set(definition.name, key);\n }\n return key;\n}\n","/**\n * Boundaries in a text: graphemes, words and lines.\n *\n * Offsets are UTF-16 code unit indices, as everywhere else in the\n * runtime, but a caret never lands inside a grapheme: an emoji, a\n * flag or a letter with combining marks moves and deletes as one.\n * `Intl.Segmenter` does the segmentation where it exists (every\n * current engine); the fallback keeps surrogate pairs together and\n * treats letters, digits and underscore as word characters.\n */\n\ninterface Segment {\n index: number;\n segment: string;\n isWordLike?: boolean;\n}\n\ninterface Segmenter {\n segment(text: string): {\n containing(index: number): Segment | undefined;\n } & Iterable<Segment>;\n}\n\nconst graphemes: Segmenter | null = createSegmenter('grapheme');\nconst words: Segmenter | null = createSegmenter('word');\n\nfunction createSegmenter(granularity: 'grapheme' | 'word'): Segmenter | null {\n const intl = Intl as unknown as {\n Segmenter?: new (locale: undefined, options: { granularity: string }) => Segmenter;\n };\n if (typeof intl.Segmenter !== 'function') {\n return null;\n }\n try {\n return new intl.Segmenter(undefined, { granularity });\n } catch {\n return null;\n }\n}\n\n/** The end of the grapheme that starts at `index`; `text.length` at the end. */\nexport function nextGraphemeEnd(text: string, index: number): number {\n if (index >= text.length) {\n return text.length;\n }\n if (graphemes !== null) {\n const segment = graphemes.segment(text).containing(index);\n if (segment !== undefined) {\n return segment.index + segment.segment.length;\n }\n }\n const code = text.charCodeAt(index);\n if (code >= 0xd800 && code <= 0xdbff && index + 1 < text.length) {\n return index + 2;\n }\n return index + 1;\n}\n\n/** The start of the grapheme that ends at `index`; 0 at the start. */\nexport function previousGraphemeStart(text: string, index: number): number {\n if (index <= 0) {\n return 0;\n }\n if (graphemes !== null) {\n const segment = graphemes.segment(text).containing(index - 1);\n if (segment !== undefined) {\n return segment.index;\n }\n }\n const code = text.charCodeAt(index - 1);\n if (code >= 0xdc00 && code <= 0xdfff && index - 2 >= 0) {\n return index - 2;\n }\n return index - 1;\n}\n\n/**\n * Every caret position in `text`: 0, each grapheme boundary,\n * `text.length`.\n *\n * One pass over the segmenter rather than a `nextGraphemeEnd` per\n * grapheme: each of those re-segments the whole string and then scans\n * it for the offset, which makes the walk quadratic. That did not\n * matter while only a caret move used it; the WebGPU text path asks\n * for the boundaries of every line it draws.\n */\nexport function graphemeBoundaries(text: string): number[] {\n const boundaries = [0];\n if (graphemes !== null) {\n for (const segment of graphemes.segment(text)) {\n boundaries.push(segment.index + segment.segment.length);\n }\n return boundaries;\n }\n let index = 0;\n while (index < text.length) {\n index = nextGraphemeEnd(text, index);\n boundaries.push(index);\n }\n return boundaries;\n}\n\n/**\n * Every word boundary in `text`, as `Intl.Segmenter` sees them: 0, the\n * end of each segment, `text.length`. Segments include the spaces and\n * punctuation between words, so a boundary falls on both sides of each.\n * The line breaker asks for these where a script writes without spaces\n * (Thai, Lao, Khmer, Myanmar), because there a break is a dictionary\n * decision and the segmenter's dictionary is the browser's own. Empty\n * where no segmenter exists.\n */\nexport function wordBoundaries(text: string): number[] {\n if (words === null) {\n return [];\n }\n const boundaries = [0];\n for (const segment of words.segment(text)) {\n boundaries.push(segment.index + segment.segment.length);\n }\n return boundaries;\n}\n\n/**\n * Where a word-wise move to the right stops: past any spaces and\n * punctuation, at the end of the next word. A newline is a boundary\n * of its own so word moves never skip a line.\n */\nexport function nextWordEnd(text: string, index: number): number {\n const length = text.length;\n if (index >= length) {\n return length;\n }\n if (text[index] === '\\n') {\n return index + 1;\n }\n let position = index;\n while (position < length && !isWordCharAt(text, position)) {\n if (text[position] === '\\n') {\n return position;\n }\n position = nextGraphemeEnd(text, position);\n }\n if (position >= length) {\n return length;\n }\n return wordEndAt(text, position);\n}\n\n/**\n * Where a word-wise move to the left stops: back over spaces and\n * punctuation, to the start of the previous word.\n */\nexport function previousWordStart(text: string, index: number): number {\n if (index <= 0) {\n return 0;\n }\n if (text[index - 1] === '\\n') {\n return index - 1;\n }\n let position = index;\n while (position > 0 && !isWordCharAt(text, position - 1)) {\n if (text[position - 1] === '\\n') {\n return position;\n }\n position = previousGraphemeStart(text, position);\n }\n if (position <= 0) {\n return 0;\n }\n return wordStartAt(text, position - 1);\n}\n\n/**\n * The word under `index`, for a double-click: a run of word\n * characters, else the run of whatever else is there (spaces,\n * punctuation), never crossing a newline.\n */\nexport function wordRangeAt(text: string, index: number): { start: number; end: number } {\n if (text.length === 0) {\n return { start: 0, end: 0 };\n }\n const at = Math.min(index, text.length - 1);\n if (text[at] === '\\n') {\n return { start: at, end: at };\n }\n if (words !== null) {\n const segment = words.segment(text).containing(at);\n if (segment !== undefined) {\n return { start: segment.index, end: segment.index + segment.segment.length };\n }\n }\n const wordLike = isWordCharAt(text, at);\n let start = at;\n while (start > 0 && text[start - 1] !== '\\n' && isWordCharAt(text, start - 1) === wordLike) {\n start = previousGraphemeStart(text, start);\n }\n let end = at;\n while (end < text.length && text[end] !== '\\n' && isWordCharAt(text, end) === wordLike) {\n end = nextGraphemeEnd(text, end);\n }\n return { start, end };\n}\n\n/** The offset just after the previous newline, or 0. */\nexport function lineStartAt(text: string, index: number): number {\n const newline = text.lastIndexOf('\\n', Math.max(0, index - 1));\n return newline < 0 ? 0 : newline + 1;\n}\n\n/** The offset of the next newline, or `text.length`. */\nexport function lineEndAt(text: string, index: number): number {\n const newline = text.indexOf('\\n', index);\n return newline < 0 ? text.length : newline;\n}\n\nfunction wordEndAt(text: string, index: number): number {\n if (words !== null) {\n const segment = words.segment(text).containing(index);\n if (segment !== undefined && segment.isWordLike) {\n return segment.index + segment.segment.length;\n }\n }\n let end = index;\n while (end < text.length && isWordCharAt(text, end)) {\n end = nextGraphemeEnd(text, end);\n }\n return end;\n}\n\nfunction wordStartAt(text: string, index: number): number {\n if (words !== null) {\n const segment = words.segment(text).containing(index);\n if (segment !== undefined && segment.isWordLike) {\n return segment.index;\n }\n }\n let start = index;\n while (start > 0 && isWordCharAt(text, start - 1)) {\n start = previousGraphemeStart(text, start);\n }\n return start;\n}\n\nconst WORD_CHAR = /[\\p{L}\\p{N}_]/u;\n\nfunction isWordCharAt(text: string, index: number): boolean {\n if (words !== null) {\n const segment = words.segment(text).containing(index);\n return segment?.isWordLike === true;\n }\n const code = text.charCodeAt(index);\n const character =\n code >= 0xd800 && code <= 0xdbff && index + 1 < text.length ? text.slice(index, index + 2) : text[index];\n return WORD_CHAR.test(character);\n}\n","import {\n lineEndAt,\n lineStartAt,\n nextGraphemeEnd,\n nextWordEnd,\n previousGraphemeStart,\n previousWordStart\n} from './TextBoundaries';\n\n/** How far a caret move or a delete reaches. */\nexport type EditUnit = 'grapheme' | 'word' | 'line' | 'document';\n\n/** A composition in progress: the IME owns `[start, end)` until it commits. */\nexport interface CompositionRange {\n readonly start: number;\n readonly end: number;\n}\n\ninterface Snapshot {\n text: string;\n anchor: number;\n focus: number;\n}\n\ntype EditKind = 'insert' | 'delete' | 'other';\n\nconst MAX_UNDO = 500;\n\n/**\n * The text behind an editable node: the buffer, the selection, the\n * composition the IME is building, and an undo stack.\n *\n * Deliberately free of layout: everything that needs a line or an x\n * position (up/down, click to place, drag to select) is computed by\n * `TextGeometry` from the paragraph layout and fed in as an offset.\n * That keeps this class a plain value that specs can drive without a\n * measurer.\n *\n * Selection is `anchor` → `focus` (the caret). `start`/`end` are the\n * same two in order. Offsets are UTF-16 code units; every move and\n * delete steps by grapheme so a caret never splits an emoji.\n *\n * Undo coalesces a run of typing into one entry and a run of\n * backspaces into another, as editors do, and breaks the group on\n * anything else. A composition is one entry however many updates it\n * took. `replaceText` — the host resetting the value from outside —\n * drops the history: the text it replaces never existed as far as the\n * next undo is concerned.\n */\nexport class EditableTextModel {\n private textValue = '';\n private anchorValue = 0;\n private focusValue = 0;\n private compositionValue: CompositionRange | null = null;\n private compositionBase: Snapshot | null = null;\n private undoStack: Snapshot[] = [];\n private redoStack: Snapshot[] = [];\n private lastEdit: EditKind = 'other';\n private lastEditEnd = -1;\n\n /** Whether the node holds focus; the caret only shows (and blinks) then. */\n focused = false;\n /**\n * Bumped by every change to the text or the selection, so anything\n * derived from them can tell cheaply whether it is stale.\n */\n version = 0;\n /**\n * The time the caret last moved or the text changed. The caret is\n * visible from here and blinks from here, so typing keeps it lit.\n */\n blinkOrigin = 0;\n /** The last `value` the host synchronised in; see `UiEditable`. */\n syncedValue: string | undefined = undefined;\n\n /**\n * The selection the last `selectionchange` reported.\n *\n * Kept on the model rather than worked out at each call site,\n * because the caret is moved from a dozen places — arrows, clicks,\n * select-all, an edit that replaces a range — and every one of them\n * would otherwise have to remember to compare. Storing what was\n * last said makes the comparison the notifier's job and the answer\n * the same wherever the move came from.\n *\n * `NaN` to begin with, so the first report always fires: a fresh\n * model at offset zero has genuinely not told anyone yet.\n */\n notifiedAnchor = Number.NaN;\n notifiedFocus = Number.NaN;\n\n constructor(text = '') {\n this.textValue = text;\n }\n\n get text(): string {\n return this.textValue;\n }\n\n get anchor(): number {\n return this.anchorValue;\n }\n\n /** The caret: the moving end of the selection. */\n get focus(): number {\n return this.focusValue;\n }\n\n get start(): number {\n return Math.min(this.anchorValue, this.focusValue);\n }\n\n get end(): number {\n return Math.max(this.anchorValue, this.focusValue);\n }\n\n get collapsed(): boolean {\n return this.anchorValue === this.focusValue;\n }\n\n get selectedText(): string {\n return this.textValue.slice(this.start, this.end);\n }\n\n get composition(): CompositionRange | null {\n return this.compositionValue;\n }\n\n get composing(): boolean {\n return this.compositionValue !== null;\n }\n\n get canUndo(): boolean {\n return this.undoStack.length > 0;\n }\n\n get canRedo(): boolean {\n return this.redoStack.length > 0;\n }\n\n // ---------------------------------------------------------------------------\n // Selection\n // ---------------------------------------------------------------------------\n\n /** Sets the selection; `focus` defaults to `anchor` (a caret). */\n select(anchor: number, focus: number = anchor): void {\n const nextAnchor = this.clampOffset(anchor);\n const nextFocus = this.clampOffset(focus);\n if (nextAnchor === this.anchorValue && nextFocus === this.focusValue) {\n return;\n }\n this.anchorValue = nextAnchor;\n this.focusValue = nextFocus;\n this.lastEdit = 'other';\n this.touch();\n }\n\n /** Moves the caret to `offset`, extending the selection from the anchor when asked. */\n moveTo(offset: number, extend: boolean): void {\n this.select(extend ? this.anchorValue : offset, offset);\n }\n\n selectAll(): void {\n this.select(0, this.textValue.length);\n }\n\n /**\n * Moves the caret by one unit. A collapsed selection moves from the\n * caret; a range collapses to the side it moves toward first, as\n * every editor does. 'line' is the hard line (up to a newline);\n * vertical movement is the caller's, since it needs geometry.\n */\n move(unit: EditUnit, direction: -1 | 1, extend: boolean): void {\n if (!extend && !this.collapsed && unit === 'grapheme') {\n this.select(direction < 0 ? this.start : this.end);\n return;\n }\n this.moveTo(this.offsetBy(this.focusValue, unit, direction), extend);\n }\n\n /** The offset one `unit` away from `from` in `direction`. */\n offsetBy(from: number, unit: EditUnit, direction: -1 | 1): number {\n const text = this.textValue;\n switch (unit) {\n case 'grapheme':\n return direction < 0 ? previousGraphemeStart(text, from) : nextGraphemeEnd(text, from);\n case 'word':\n return direction < 0 ? previousWordStart(text, from) : nextWordEnd(text, from);\n case 'line':\n return direction < 0 ? lineStartAt(text, from) : lineEndAt(text, from);\n case 'document':\n return direction < 0 ? 0 : text.length;\n }\n }\n\n // ---------------------------------------------------------------------------\n // Editing\n // ---------------------------------------------------------------------------\n\n /**\n * Replaces the selection with `text` and puts the caret after it.\n * Single-grapheme insertions at the caret coalesce into one undo\n * entry with the previous one.\n */\n insertText(text: string): void {\n const start = this.start;\n const end = this.end;\n const typing = this.collapsed && text.length > 0 && text === text.slice(0, nextGraphemeEnd(text, 0));\n const coalesce = typing && this.lastEdit === 'insert' && this.lastEditEnd === start;\n this.edit(start, end, text, coalesce, 'insert');\n }\n\n /**\n * Deletes the selection, or one unit before the caret when nothing\n * is selected. Repeated single-grapheme deletes coalesce.\n */\n deleteBackward(unit: EditUnit = 'grapheme'): void {\n if (!this.collapsed) {\n this.edit(this.start, this.end, '', false, 'other');\n return;\n }\n const caret = this.focusValue;\n if (caret === 0) {\n return;\n }\n let start = this.offsetBy(caret, unit, -1);\n if (start === caret) {\n // Already at the line start: Cmd+Backspace on an empty line joins it.\n start = previousGraphemeStart(this.textValue, caret);\n }\n const coalesce = unit === 'grapheme' && this.lastEdit === 'delete' && this.lastEditEnd === caret;\n this.edit(start, caret, '', coalesce, 'delete');\n }\n\n /** Deletes the selection, or one unit after the caret. */\n deleteForward(unit: EditUnit = 'grapheme'): void {\n if (!this.collapsed) {\n this.edit(this.start, this.end, '', false, 'other');\n return;\n }\n const caret = this.focusValue;\n if (caret >= this.textValue.length) {\n return;\n }\n let end = this.offsetBy(caret, unit, 1);\n if (end === caret) {\n end = nextGraphemeEnd(this.textValue, caret);\n }\n this.edit(caret, end, '', false, 'other');\n }\n\n /** Replaces `[start, end)` with `text`; one undo entry. */\n replaceRange(start: number, end: number, text: string): void {\n const from = this.clampOffset(Math.min(start, end));\n const to = this.clampOffset(Math.max(start, end));\n this.edit(from, to, text, false, 'other');\n }\n\n /**\n * Resets the text from outside (the host's `value`). The selection\n * is kept where it still fits; the history is dropped. Equal text is\n * a no-op, which is what makes a controlled value echo harmless.\n */\n replaceText(text: string): void {\n if (text === this.textValue) {\n return;\n }\n this.textValue = text;\n this.anchorValue = this.clampOffset(this.anchorValue);\n this.focusValue = this.clampOffset(this.focusValue);\n this.compositionValue = null;\n this.compositionBase = null;\n this.undoStack = [];\n this.redoStack = [];\n this.lastEdit = 'other';\n this.touch();\n }\n\n // ---------------------------------------------------------------------------\n // Composition\n // ---------------------------------------------------------------------------\n\n /**\n * An IME started composing: the selection is what it replaces. Until\n * the commit, `updateComposition` rewrites the composing range in\n * place and the undo stack sees nothing.\n */\n beginComposition(): void {\n if (this.compositionValue !== null) {\n return;\n }\n this.compositionBase = this.snapshot();\n const start = this.start;\n const end = this.end;\n if (start !== end) {\n this.textValue = this.textValue.slice(0, start) + this.textValue.slice(end);\n }\n this.anchorValue = start;\n this.focusValue = start;\n this.compositionValue = { start, end: start };\n this.touch();\n }\n\n /**\n * The composition text changed; `caret` is the caret within it.\n * Without a preceding `beginComposition` one is started here.\n */\n updateComposition(text: string, caret: number = text.length): void {\n if (this.compositionValue === null) {\n this.beginComposition();\n }\n const range = this.compositionValue!;\n this.textValue = this.textValue.slice(0, range.start) + text + this.textValue.slice(range.end);\n const end = range.start + text.length;\n this.compositionValue = { start: range.start, end };\n const position = range.start + Math.max(0, Math.min(caret, text.length));\n this.anchorValue = position;\n this.focusValue = position;\n this.touch();\n }\n\n /**\n * The IME finished: `text` (the committed string) replaces the\n * composing range, the caret follows it and the whole composition\n * becomes one undo entry. With no composition open this is a plain\n * insertion, which is how an engine that reports the end before the\n * updates still lands the text once.\n */\n commitComposition(text: string): void {\n if (this.compositionValue === null) {\n this.insertText(text);\n this.lastEdit = 'other';\n return;\n }\n const range = this.compositionValue;\n const base = this.compositionBase;\n this.textValue = this.textValue.slice(0, range.start) + text + this.textValue.slice(range.end);\n const caret = range.start + text.length;\n this.anchorValue = caret;\n this.focusValue = caret;\n this.compositionValue = null;\n this.compositionBase = null;\n if (base !== null && base.text !== this.textValue) {\n this.pushUndo(base);\n }\n this.lastEdit = 'other';\n this.touch();\n }\n\n /** The IME abandoned the composition: the text is as it was before it. */\n cancelComposition(): void {\n if (this.compositionValue === null) {\n return;\n }\n const base = this.compositionBase!;\n this.textValue = base.text;\n this.anchorValue = base.anchor;\n this.focusValue = base.focus;\n this.compositionValue = null;\n this.compositionBase = null;\n this.touch();\n }\n\n // ---------------------------------------------------------------------------\n // History\n // ---------------------------------------------------------------------------\n\n undo(): boolean {\n const entry = this.undoStack.pop();\n if (entry === undefined) {\n return false;\n }\n this.redoStack.push(this.snapshot());\n this.restore(entry);\n return true;\n }\n\n redo(): boolean {\n const entry = this.redoStack.pop();\n if (entry === undefined) {\n return false;\n }\n this.undoStack.push(this.snapshot());\n this.restore(entry);\n return true;\n }\n\n /** Ends the current typing run: the next insertion starts a new undo entry. */\n breakUndoGroup(): void {\n this.lastEdit = 'other';\n }\n\n // ---------------------------------------------------------------------------\n // Internals\n // ---------------------------------------------------------------------------\n\n private edit(start: number, end: number, text: string, coalesce: boolean, kind: EditKind): void {\n if (this.compositionValue !== null) {\n // An edit under an open composition ends it as committed.\n this.commitComposition(this.textValue.slice(this.compositionValue.start, this.compositionValue.end));\n }\n if (start === end && text.length === 0) {\n return;\n }\n if (!coalesce) {\n this.pushUndo(this.snapshot());\n }\n this.redoStack = [];\n this.textValue = this.textValue.slice(0, start) + text + this.textValue.slice(end);\n const caret = start + text.length;\n this.anchorValue = caret;\n this.focusValue = caret;\n this.lastEdit = kind;\n this.lastEditEnd = caret;\n this.touch();\n }\n\n private pushUndo(entry: Snapshot): void {\n this.undoStack.push(entry);\n if (this.undoStack.length > MAX_UNDO) {\n this.undoStack.shift();\n }\n }\n\n private restore(entry: Snapshot): void {\n this.textValue = entry.text;\n this.anchorValue = this.clampOffset(entry.anchor);\n this.focusValue = this.clampOffset(entry.focus);\n this.compositionValue = null;\n this.compositionBase = null;\n this.lastEdit = 'other';\n this.touch();\n }\n\n private snapshot(): Snapshot {\n return { text: this.textValue, anchor: this.anchorValue, focus: this.focusValue };\n }\n\n private clampOffset(offset: number): number {\n return Math.max(0, Math.min(this.textValue.length, Math.floor(offset)));\n }\n\n private touch(): void {\n this.version++;\n }\n}\n","import type { LayoutBox } from '../layout/LayoutTypes';\nimport { graphemeBoundaries } from './TextBoundaries';\n\n/**\n * A placed line, as `placeLines` in the text renderer produces: the\n * source offsets it covers, its box after alignment, and its text.\n */\nexport interface PlacedLine {\n readonly text: string;\n readonly start: number;\n readonly end: number;\n readonly x: number;\n readonly y: number;\n readonly width: number;\n readonly height: number;\n}\n\n/**\n * The advance width of a run in the paragraph's font.\n *\n * `start` is the run's first character's offset in the source text,\n * and is what a paragraph with runs of its own needs to know which\n * font to measure in; a paragraph in one font ignores it. Omitted for\n * a string that is not in the text at all, such as the space a\n * selection past the end of a line is widened by.\n */\nexport type RunMeasure = (text: string, start?: number) => number;\n\nexport interface CaretRect {\n x: number;\n y: number;\n height: number;\n /** Index of the line the caret is on. */\n line: number;\n}\n\n/**\n * Caret and selection geometry over laid-out lines.\n *\n * The lines are the paragraph the layout engine sized the node with\n * and the renderer draws, so a caret computed here sits exactly where\n * the glyphs are. Widths come from the same measurer: the x of offset\n * `n` on a line is the width of that line's first `n` characters.\n *\n * Direction: `rtl` mirrors every x against the line's right edge, so a\n * right-to-left paragraph places its caret and selection from the\n * right. Runs of mixed direction within one line are not reordered —\n * the renderers do not shape them either — so this is direction-aware\n * rather than fully bidirectional, and says so.\n */\n\n/**\n * The line an offset belongs to. Hanging spaces at a wrap belong to\n * the line before the break; the first character after the break\n * starts the next line.\n */\nexport function lineIndexForOffset(lines: readonly PlacedLine[], offset: number): number {\n let index = 0;\n for (let i = 1; i < lines.length; i++) {\n if (lines[i].start <= offset) {\n index = i;\n } else {\n break;\n }\n }\n return index;\n}\n\n/**\n * The offset a line's caret positions run to, hanging spaces included:\n * the text's end on the last line, else up to the break — the newline\n * character itself, or the first character of the next line.\n *\n * `line.end` stops at the last glyph, since spaces at a wrap hang and\n * have no width in layout. The caret still has to move through them,\n * as it does in a textarea, so geometry measures them from `text`.\n */\nexport function lineLimit(lines: readonly PlacedLine[], index: number, text: string): number {\n if (index >= lines.length - 1) {\n return text.length;\n }\n const nextStart = lines[index + 1].start;\n return nextStart > 0 && text[nextStart - 1] === '\\n' ? nextStart - 1 : nextStart;\n}\n\n/** The advance from a line's start to `offset`, through hanging spaces if need be. */\nfunction advanceTo(line: PlacedLine, offset: number, text: string, measure: RunMeasure): number {\n const inLine = Math.max(0, offset - line.start);\n if (inLine === 0) {\n return 0;\n }\n if (inLine === line.text.length) {\n return line.width;\n }\n return measure(inLine < line.text.length ? line.text.slice(0, inLine) : text.slice(line.start, offset), line.start);\n}\n\n/** Where the caret for `offset` is drawn. */\nexport function caretRectFor(\n lines: readonly PlacedLine[],\n text: string,\n offset: number,\n measure: RunMeasure,\n rtl: boolean\n): CaretRect {\n const index = lineIndexForOffset(lines, offset);\n const line = lines[index];\n const advance = advanceTo(line, Math.min(offset, lineLimit(lines, index, text)), text, measure);\n return { x: rtl ? line.x + line.width - advance : line.x + advance, y: line.y, height: line.height, line: index };\n}\n\n/** The line whose box contains `y`, clamped to the first and last. */\nexport function lineIndexAtY(lines: readonly PlacedLine[], y: number): number {\n if (y < lines[0].y) {\n return 0;\n }\n for (let i = 0; i < lines.length; i++) {\n if (y < lines[i].y + lines[i].height) {\n return i;\n }\n }\n return lines.length - 1;\n}\n\n/** The caret position nearest to a point: the boundary closest to `x` on the line under `y`. */\nexport function offsetAtPoint(\n lines: readonly PlacedLine[],\n text: string,\n x: number,\n y: number,\n measure: RunMeasure,\n rtl: boolean\n): number {\n const index = lineIndexAtY(lines, y);\n return offsetAtX(lines, index, text, x, measure, rtl);\n}\n\n/**\n * The caret position on one line nearest to `x`. Widths grow with the\n * prefix, so the boundary is found by bisection: O(log n) measures per\n * click on a line of n graphemes.\n *\n * On the last line the trailing spaces are positions too, so a click\n * past the text lands after them. On a wrapped line the hanging spaces\n * are not: a click past the glyphs stops before the break, as it does\n * in a textarea.\n */\nexport function offsetAtX(\n lines: readonly PlacedLine[],\n index: number,\n text: string,\n x: number,\n measure: RunMeasure,\n rtl: boolean\n): number {\n const line = lines[index];\n const segment = index === lines.length - 1 ? text.slice(line.start, lineLimit(lines, index, text)) : line.text;\n const segmentWidth = segment.length === line.text.length ? line.width : measure(segment, line.start);\n const distance = rtl ? line.x + line.width - x : x - line.x;\n if (distance <= 0) {\n return line.start;\n }\n if (distance >= segmentWidth) {\n return line.start + segment.length;\n }\n const boundaries = graphemeBoundaries(segment);\n const widthAt = (k: number): number => (k === 0 ? 0 : measure(segment.slice(0, boundaries[k]), line.start));\n let low = 0;\n let high = boundaries.length - 1;\n // Smallest k whose prefix width reaches the point.\n while (low < high) {\n const mid = (low + high) >> 1;\n if (widthAt(mid) < distance) {\n low = mid + 1;\n } else {\n high = mid;\n }\n }\n if (low > 0) {\n const before = widthAt(low - 1);\n const after = widthAt(low);\n if (distance - before < after - distance) {\n low--;\n }\n }\n return line.start + boundaries[low];\n}\n\n/**\n * The offset a vertical move lands on: the position nearest the\n * caret's x (or `goalX`, the x of the line the run of moves started\n * on) on the adjacent line. Null when there is no line that way, which\n * callers turn into \"go to the start / end of the text\".\n */\nexport function offsetForVerticalMove(\n lines: readonly PlacedLine[],\n text: string,\n offset: number,\n direction: -1 | 1,\n measure: RunMeasure,\n rtl: boolean,\n goalX?: number\n): { offset: number; x: number } | null {\n const caret = caretRectFor(lines, text, offset, measure, rtl);\n const target = caret.line + direction;\n if (target < 0 || target >= lines.length) {\n return null;\n }\n const x = goalX ?? caret.x;\n return { offset: offsetAtX(lines, target, text, x, measure, rtl), x };\n}\n\n/**\n * The boxes covering `[start, end)`, one per line touched. Hanging\n * spaces inside the range are highlighted at their width; a line the\n * range runs past with nothing hanging gets a space's width more, so a\n * selected line break is visible.\n */\nexport function selectionRects(\n lines: readonly PlacedLine[],\n text: string,\n start: number,\n end: number,\n measure: RunMeasure,\n rtl: boolean\n): LayoutBox[] {\n if (end <= start) {\n return [];\n }\n const rects: LayoutBox[] = [];\n const first = lineIndexForOffset(lines, start);\n const last = lineIndexForOffset(lines, Math.max(start, end - 1));\n for (let i = first; i <= last; i++) {\n const line = lines[i];\n const limit = lineLimit(lines, i, text);\n const fromX = advanceTo(line, Math.max(line.start, Math.min(start, limit)), text, measure);\n let toX = advanceTo(line, Math.min(end, limit), text, measure);\n if (end > limit && i < lines.length - 1 && limit === line.end) {\n toX += measure(' ');\n }\n if (toX <= fromX) {\n continue;\n }\n rects.push({\n x: rtl ? line.x + line.width - toX : line.x + fromX,\n y: line.y,\n width: toX - fromX,\n height: line.height\n });\n }\n return rects;\n}\n","import { UiEnvironmentKeys } from '../environment/UiEnvironmentKeys';\nimport type { UiShapes } from '../environment/UiShapes';\nimport type { UiNode } from '../graph/UiNode';\nimport { type UiBorderRadius, borderRadius, normalizeBorderRadius } from './UiBorderRadius';\nimport type { UiBorderRadiusValue } from './UiPropertyValues';\n\n/**\n * The radius a name stands for in the scale the node inherits.\n *\n * Decided against the scale the node actually has, not a written-out\n * list, so a step a custom theme added resolves too — the same rule\n * `themeColorFor` follows for a palette name, and the reason\n * `UiShapeExtensions` is worth declaring.\n */\nfunction themeRadiusFor(node: UiNode, value: string): number | undefined {\n const theme =\n node.environment !== null ? node.environment.get(UiEnvironmentKeys.theme) : UiEnvironmentKeys.theme.defaultValue;\n const shapes = theme.shapes as unknown as Readonly<Record<string, number | undefined>>;\n return Object.prototype.hasOwnProperty.call(shapes, value) ? shapes[value as keyof UiShapes] : undefined;\n}\n\n/**\n * Resolves a border radius value to a `UiBorderRadius`.\n *\n * A scale name (`'medium'`) is looked up in the theme the node\n * inherits, so the same tree repaints at the right radii when the\n * theme provider above it changes; anything else goes through\n * `normalizeBorderRadius`, which is where numbers and per-corner\n * objects already went.\n *\n * This is the colour rule applied to the one other property that can\n * afford it. `borderRadius` affects paint and nothing else, so the\n * lookup happens exactly where `backgroundColor`'s does and costs what\n * that costs: a node that names a number never reaches the string\n * branch at all. By-name lengths are ruled out because a\n * length is read in the layout pass — a radius is not, which is why\n * this one is free and `padding` is a separate question.\n *\n * A name the scale does not carry resolves to no radius, and the\n * element draws square. That is the quiet failure `resolveColorValue`\n * already chose for a colour name nothing matches: a misspelling is a\n * compile error when the name was declared, and a theme that simply\n * lacks the step should not take the frame down.\n */\nexport function resolveBorderRadiusValue(node: UiNode, value: UiBorderRadiusValue | undefined): UiBorderRadius {\n if (typeof value === 'string') {\n const named = themeRadiusFor(node, value);\n return named === undefined ? normalizeBorderRadius(undefined) : borderRadius(Math.max(0, named));\n }\n return normalizeBorderRadius(value);\n}\n\n/** A step of the shape scale the node inherits, for defaults that follow the theme. */\nexport function themeRadius(node: UiNode, name: string): number | undefined {\n return themeRadiusFor(node, name);\n}\n","/**\n * A moving picture, as the renderers see it.\n *\n * The interesting field is `version`, and the reason it exists is a\n * cache. `UiImage` is an `ImageBitmap`, and `WebGPUTextureCache` keys\n * its textures on that object with a `WeakMap` — which is exactly\n * right for a picture, whose identity and whose pixels are the same\n * thing. A video's pixels change sixty times a second while the thing\n * on screen stays the same thing, so a surface that handed the\n * renderer a fresh frame object would allocate and never reuse a GPU\n * texture per frame.\n *\n * So the surface's **identity is stable for the life of the playback**\n * and `version` counts frames. The texture cache keys on the surface,\n * compares versions, and re-uploads into the texture it already has,\n * recreating it only when the size changes. Canvas2D does not care and\n * simply draws `frame`.\n *\n * `frame` is a `VideoFrame` where WebCodecs decoded it, and may be an\n * `ImageBitmap` where something else produced it — both are\n * `CanvasImageSource` and both are accepted by\n * `copyExternalImageToTexture`, so neither backend has to know which\n * it got.\n */\nexport interface UiVideoSurface {\n /** The frame to draw now, or null before the first one has arrived. */\n readonly frame: VideoFrame | ImageBitmap | null;\n /** Bumped on every new frame. A cache re-uploads when it changes. */\n readonly version: number;\n /** The picture's size, known from the container before any frame is. */\n readonly width: number;\n readonly height: number;\n}\n\n/**\n * Whether a value is a video surface.\n *\n * Structural, like `parseTransform` and the rest of this directory: a\n * property's value arrives from an element and has to be recognised\n * rather than trusted.\n */\nexport function isVideoSurface(value: unknown): value is UiVideoSurface {\n if (typeof value !== 'object' || value === null) {\n return false;\n }\n const candidate = value as Partial<UiVideoSurface>;\n return (\n typeof candidate.version === 'number' &&\n typeof candidate.width === 'number' &&\n typeof candidate.height === 'number' &&\n 'frame' in candidate\n );\n}\n\n/** The drawable size of a frame, which the two frame types spell differently. */\nexport function videoFrameSize(surface: UiVideoSurface): { width: number; height: number } {\n const frame = surface.frame;\n if (frame === null) {\n return { width: surface.width, height: surface.height };\n }\n if (typeof (frame as VideoFrame).displayWidth === 'number') {\n const video = frame as VideoFrame;\n return { width: video.displayWidth, height: video.displayHeight };\n }\n const bitmap = frame as ImageBitmap;\n return { width: bitmap.width, height: bitmap.height };\n}\n","import { UiEnvironmentKeys } from '../environment/UiEnvironmentKeys';\nimport type { UiNode } from '../graph/UiNode';\nimport { type UiColor, normalizeColor } from './UiColor';\nimport type { ResolvedGradient, ResolvedGradientStop, UiGradient } from './UiGradient';\nimport { validateGradient } from './UiGradient';\nimport type { UiPropertyDefinition } from './UiPropertyDefinition';\nimport { resolveProperty } from './UiPropertyResolver';\nimport type { UiColorValue, UiThemeColorName } from './UiPropertyValues';\n\n/**\n * Whether a color value names an entry of the theme palette rather\n * than a literal color. Decided against the palette the node actually\n * inherits, so a custom theme with extra names works too.\n */\nfunction themeColorFor(node: UiNode, value: string): UiColor | undefined {\n const theme =\n node.environment !== null ? node.environment.get(UiEnvironmentKeys.theme) : UiEnvironmentKeys.theme.defaultValue;\n const colors = theme.colors as unknown as Readonly<Record<string, UiColor | undefined>>;\n return Object.prototype.hasOwnProperty.call(colors, value) ? colors[value as UiThemeColorName] : undefined;\n}\n\n/**\n * Resolves a color property to a `UiColor`.\n *\n * A palette name (`'primary'`) is looked up in the theme the node\n * inherits, so the same tree repaints in the right colors when the\n * theme provider above it changes. Anything else goes through\n * `normalizeColor`: `UiColor` objects, hex and named CSS colors.\n */\nexport function resolveColor<T extends UiColorValue | undefined>(\n node: UiNode,\n definition: UiPropertyDefinition<T>\n): UiColor | undefined {\n return resolveColorValue(node, resolveProperty(node, definition));\n}\n\n/**\n * The same resolution for a colour that did not come from a property.\n *\n * A decoration shape carries its colour inline rather than through the\n * registry, and must still honour a palette name — otherwise a focus\n * ring would be the one thing in the library that names a literal\n * colour.\n */\nexport function resolveColorValue(node: UiNode, value: UiColorValue | undefined): UiColor | undefined {\n if (typeof value === 'string') {\n const themed = themeColorFor(node, value);\n if (themed !== undefined) {\n return themed;\n }\n }\n return normalizeColor(value);\n}\n\n/**\n * Resolves a gradient property value against the node's theme.\n *\n * Every stop goes through `resolveColorValue`, so `{ color: 'primary' }`\n * in a gradient means what `backgroundColor: 'primary'` means and a\n * themed gradient repaints with the theme above it. Lives here rather\n * than in `UiGradient.ts` because the registry imports that file, and\n * the theme lookup reads properties: see the note there.\n *\n * Throws on a malformed gradient, naming what is wrong. A value that\n * arrived through a binding skipped the builder's check, and a\n * background that silently does not paint is worse than a frame that\n * says why. Returns undefined when there is no gradient, or when a stop\n * names a colour nothing can resolve.\n */\nexport function resolveGradient(node: UiNode, value: UiGradient | undefined): ResolvedGradient | undefined {\n if (value === undefined) {\n return undefined;\n }\n const message = validateGradient(value);\n if (message !== undefined) {\n throw new Error(message);\n }\n const stops: ResolvedGradientStop[] = [];\n for (const stop of value.stops) {\n const color = resolveColorValue(node, stop.color);\n if (color === undefined) {\n return undefined;\n }\n stops.push({ offset: stop.offset, color });\n }\n if (value.kind === 'linear') {\n return { kind: 'linear', angle: value.angle, stops };\n }\n return { kind: 'radial', centerX: value.centerX, centerY: value.centerY, radius: value.radius, stops };\n}\n\n/** A palette entry of the theme the node inherits, for defaults that follow the theme. */\nexport function themeColor(node: UiNode, name: UiThemeColorName): UiColor | undefined {\n return themeColorFor(node, name);\n}\n\nexport { colorValuesEqual } from './UiColor';\n","import type { UiNode } from '../graph/UiNode';\nimport { UiNodeType } from '../graph/UiNodeType';\nimport { EditableTextModel } from './EditableTextModel';\n\n/** The node property holding an editable's model; see UiProperties.editor. */\nexport const EDITOR_PROP = 'editor';\n\n/** The caret shows for this long, then hides for as long, from the last activity. */\nexport const CARET_BLINK_MS = 530;\n\n/**\n * How wide the caret is drawn. Both renderers paint it, and layout\n * keeps this much room past the end of a field's text so that a caret\n * at the end of a scrolled line is still inside the box.\n */\nexport const CARET_WIDTH = 1;\n\n/**\n * The model behind an EditableText node.\n *\n * The node is the identity — it survives reconciliation exactly as\n * the layout record does — so the model lives on it, created on first\n * use by whichever of layout, paint or input gets there first. All\n * three read the text from here rather than from a property, because\n * the user's keystrokes must not wait for an app to echo `value` back.\n *\n * `value` is still honoured: whenever the property differs from the\n * last value synchronised in, the model takes it. An app that writes\n * every reported value back therefore controls the field, and one\n * that never writes it leaves the user's text alone.\n */\nexport function editorFor(node: UiNode): EditableTextModel {\n let model = node.properties.get(EDITOR_PROP) as EditableTextModel | undefined;\n if (!(model instanceof EditableTextModel)) {\n model = new EditableTextModel();\n node.properties.set(EDITOR_PROP, model);\n }\n syncEditorValue(node, model);\n return model;\n}\n\n/** The model, if the node has one already; never creates it. */\nexport function editorOf(node: UiNode): EditableTextModel | undefined {\n const model = node.properties.get(EDITOR_PROP);\n return model instanceof EditableTextModel ? model : undefined;\n}\n\n/** Applies a changed `value` property to the model; see editorFor. */\nexport function syncEditorValue(node: UiNode, model: EditableTextModel): void {\n const value = node.properties.get('value');\n const text = typeof value === 'string' ? value : value === undefined || value === null ? undefined : String(value);\n if (text === model.syncedValue) {\n return;\n }\n model.syncedValue = text;\n model.replaceText(text ?? '');\n}\n\nexport function isEditableNode(node: UiNode): boolean {\n return node.type === UiNodeType.EditableText;\n}\n\nexport function isMultiline(node: UiNode): boolean {\n return node.properties.get('multiline') === true;\n}\n\nexport function isReadOnly(node: UiNode): boolean {\n return node.properties.get('readOnly') === true;\n}\n\n/**\n * Whether the caret is in the visible half of its blink at `now`. It\n * is always visible while a composition is open — the IME caret must\n * not wink — and for the first half-period after any activity.\n */\nexport function caretVisibleAt(model: EditableTextModel, now: number): boolean {\n if (model.composing) {\n return true;\n }\n const elapsed = Math.max(0, now - model.blinkOrigin);\n return Math.floor(elapsed / CARET_BLINK_MS) % 2 === 0;\n}\n\n/** When the caret next toggles, given it is blinking. */\nexport function nextCaretToggle(model: EditableTextModel, now: number): number {\n const elapsed = Math.max(0, now - model.blinkOrigin);\n return model.blinkOrigin + (Math.floor(elapsed / CARET_BLINK_MS) + 1) * CARET_BLINK_MS;\n}\n","import type { UiNode } from '../graph/UiNode';\nimport type { UiTextLink } from '../properties/UiTextStyle';\nimport { resolvedSpansOf } from '../properties/UiTextStyle';\nimport type { ParagraphGeometry } from './TextSelectionGeometry';\n\n/**\n * Which run of a paragraph the pointer is on, kept on the node.\n *\n * The same shape as `textSelection` and `textMatches`, and for the\n * same reason: paint has a node and a `PaintState` and nothing else,\n * so anything paint must know about a paragraph beyond its properties\n * has to be written onto the node. Here it decides three things — the\n * wash behind the run, the underline that appears under it, and the\n * cursor the shell shows — which is exactly the hover affordance a\n * link owes the person using it.\n */\nconst TEXT_LINK_HOVER_PROP = 'textLinkHover';\n\n/** Index into the node's runs of the link the pointer is on, or -1. */\nexport function linkHoverOf(node: UiNode): number {\n const value = node.properties.get(TEXT_LINK_HOVER_PROP);\n return typeof value === 'number' ? value : -1;\n}\n\n/** Records the hovered run. Returns whether it changed. */\nexport function setLinkHover(node: UiNode, index: number): boolean {\n if (linkHoverOf(node) === index) {\n return false;\n }\n if (index < 0) {\n node.properties.delete(TEXT_LINK_HOVER_PROP);\n } else {\n node.properties.set(TEXT_LINK_HOVER_PROP, index);\n }\n return true;\n}\n\n/** Forgets the hovered run. Returns whether there was one. */\nexport function clearLinkHover(node: UiNode): boolean {\n return setLinkHover(node, -1);\n}\n\n/** Whether any run of this node's paragraph is a link. */\nexport function hasTextLinks(node: UiNode): boolean {\n for (const span of resolvedSpansOf(node)) {\n if (span.link !== undefined) {\n return true;\n }\n }\n return false;\n}\n\n/** The link of one of a node's runs, or undefined when that run is not one. */\nexport function linkOf(node: UiNode, index: number): UiTextLink | undefined {\n const spans = resolvedSpansOf(node);\n return index >= 0 && index < spans.length ? spans[index].link : undefined;\n}\n\n/**\n * The run under a point, as an index into the node's runs, or -1.\n *\n * Hit-tested against the runs the paragraph was laid out into rather\n * than against character offsets, so a click lands on the run it looks\n * like it landed on: a run's box is its own advance, and the gap\n * between two runs belongs to neither.\n *\n * `y` picks the line by its box, so a point in the leading above the\n * glyphs still hits the line, as it does when selecting.\n */\nexport function linkRunAtPointIn(geometry: ParagraphGeometry, x: number, y: number): number {\n for (const line of geometry.lines) {\n if (line.runs === undefined || y < line.y || y >= line.y + line.height) {\n continue;\n }\n for (const run of line.runs) {\n if (run.span >= 0 && x >= run.x && x < run.x + run.width) {\n return run.span;\n }\n }\n return -1;\n }\n return -1;\n}\n","import { UiNodeType } from '../graph/UiNodeType';\nimport { linkHoverOf } from '../selection/UiTextLinks';\nimport type { UiNode } from '../graph/UiNode';\n\n/**\n * Central definition of a node's participation in input.\n *\n * The hit tester, pointer controller, focus manager and keyboard\n * routing all read the same predicates, so \"what is interactive\"\n * has exactly one meaning across the system.\n *\n * Model:\n * disabled — the node AND its subtree are inert: no pointer\n * events, no focus, no keyboard, skipped by hit\n * testing. This is the same shape as the CSS\n * `inert` attribute: a disabled Button stays\n * inert even when it wraps Text children.\n * pointerEvents — 'none' makes the node AND its subtree skipped\n * by hit testing (CSS-like). Use it to block a\n * whole region.\n * hitTestable — false skips only the node itself; children are\n * still tested. Use it for decorative containers\n * that must not swallow clicks.\n * visible/opacity — false/0 hides the subtree (matching the\n * renderer, which returns before painting\n * children), so the subtree is skipped too.\n * focusable — true opts any node into focus; false opts out.\n * Buttons are focusable by default.\n */\n\n/** The node and its whole subtree are excluded from pointer input. */\nexport function isNodeInert(node: UiNode): boolean {\n if (node.properties.get('disabled') === true) {\n return true;\n }\n if (node.properties.get('pointerEvents') === 'none') {\n return true;\n }\n if (node.properties.get('visible') === false) {\n return true;\n }\n const opacity = node.properties.get('opacity');\n if (typeof opacity === 'number' && Number.isFinite(opacity) && opacity <= 0) {\n return true;\n }\n return false;\n}\n\n/** The node itself cannot be the target of a hit, but children can. */\nexport function isNodeHitTestable(node: UiNode): boolean {\n return node.properties.get('hitTestable') !== false;\n}\n\n/**\n * Whether the node may hold logical focus.\n *\n * Disabled/inert nodes can never be focused. `focusable` explicitly\n * opts in (true) or opts out (false); without an explicit value,\n * interactive controls (Button) are focusable and everything else is\n * not. The graph Root never participates in tab order.\n */\nexport function isNodeFocusable(node: UiNode): boolean {\n if (isNodeInert(node) || node.type === UiNodeType.Root) {\n return false;\n }\n const focusable = node.properties.get('focusable');\n if (focusable === true) {\n return true;\n }\n if (focusable === false) {\n return false;\n }\n return node.type === UiNodeType.Button || node.type === UiNodeType.EditableText;\n}\n\n/**\n * Whether Tab should stop here.\n *\n * Every tab stop is focusable and not every focusable node is a tab\n * stop, which is the distinction `tabindex=\"-1\"` draws in the DOM and\n * the one this engine was missing. `focusable` answers \"may this node\n * hold focus at all\", and that is the wrong question for a container:\n * a dialog's body must be able to *take* the keyboard, so that opening\n * a dialog whose content is a sentence does not hand it to nothing, and\n * must not be a place Tab *lands*, or every dialog gains a stop that\n * announces nothing and does nothing.\n *\n * So `tabStop: false` means focusable, reachable by a press and by\n * `focus()`, and skipped by the cycle. It says nothing on a node that\n * is not focusable in the first place, because there is no order to be\n * out of.\n */\nexport function isNodeTabStop(node: UiNode): boolean {\n return isNodeFocusable(node) && node.properties.get('tabStop') !== false;\n}\n\n/**\n * Whether the user may select this node's text with the pointer.\n *\n * `selectable` inherits down the tree the way CSS `user-select` does:\n * the nearest ancestor that sets it decides, and text is selectable\n * when nothing along the path says otherwise. A `Button` opts its\n * subtree out, as browsers' default stylesheets do — dragging across a\n * control should press it, not highlight its label.\n */\nexport function isNodeSelectable(node: UiNode): boolean {\n for (let current: UiNode | null = node; current !== null; current = current.parent) {\n const value = current.properties.get('selectable');\n if (value === true) {\n return true;\n }\n if (value === false) {\n return false;\n }\n if (current.type === UiNodeType.Button) {\n return false;\n }\n }\n return true;\n}\n\n/**\n * The cursor to show over a node: its own `cursor`, else the nearest\n * ancestor's, as CSS inherits it — so a button sets `cursor: 'pointer'`\n * once and its label inherits it. Null when nothing along the path\n * sets one, which the shell shows as the default arrow.\n */\nexport function resolveCursor(node: UiNode | null): string | null {\n if (node !== null && linkHoverOf(node) >= 0) {\n // An inline link is a run rather than a node, so it cannot set a\n // `cursor` property of its own; the run the pointer is on is\n // written onto the paragraph and read back here.\n return 'pointer';\n }\n for (let current = node; current !== null; current = current.parent) {\n const cursor = current.properties.get('cursor');\n if (typeof cursor === 'string' && cursor.length > 0) {\n return cursor;\n }\n if (current.type === UiNodeType.EditableText) {\n // An editable shows the I-beam unless told otherwise, as a\n // textarea does.\n return 'text';\n }\n }\n return null;\n}\n","import type { UiNode } from '../graph/UiNode';\nimport { UiNodeType } from '../graph/UiNodeType';\nimport { isNodeInert, isNodeSelectable } from '../input/UiInteraction';\nimport { textContentOf } from '../properties/UiTextStyle';\n\n/**\n * The node property holding the range of a `Text` node's text that is\n * selected, as `{ start, end }` in source offsets, or absent when none\n * of it is.\n *\n * It lives on the node for the same reason the editable's model does\n * (see `UiEditable`): the node is the identity that survives\n * reconciliation, and paint has to see the selection without the\n * selection having to be threaded through the render context — which\n * matters most in the render worker, where the graph is all the\n * renderer has.\n */\nexport const TEXT_SELECTION_PROP = 'textSelection';\n\nexport interface TextRange {\n readonly start: number;\n readonly end: number;\n}\n\n/** The selected range of a node's text, or undefined when none is. */\nexport function selectionRangeOf(node: UiNode): TextRange | undefined {\n const range = node.properties.get(TEXT_SELECTION_PROP);\n if (typeof range !== 'object' || range === null) {\n return undefined;\n }\n const candidate = range as Partial<TextRange>;\n return typeof candidate.start === 'number' && typeof candidate.end === 'number' ? (range as TextRange) : undefined;\n}\n\n/**\n * Writes a node's selected range. Returns whether it changed, so the\n * caller only marks the node dirty when there is something new to\n * paint.\n */\nexport function setSelectionRange(node: UiNode, start: number, end: number): boolean {\n const current = selectionRangeOf(node);\n if (current !== undefined && current.start === start && current.end === end) {\n return false;\n }\n node.properties.set(TEXT_SELECTION_PROP, { start, end });\n return true;\n}\n\n/** Clears a node's selected range. Returns whether it had one. */\nexport function clearSelectionRange(node: UiNode): boolean {\n return node.properties.delete(TEXT_SELECTION_PROP);\n}\n\n/**\n * The text a `Text` node draws, when the user may select it.\n *\n * Undefined for anything that is not selectable text: another node\n * type, an empty or absent string, an inert subtree, or a subtree that\n * opted out through `selectable: false` — which, as in a browser's\n * default stylesheet, a `Button` does for its label.\n */\nexport function selectableTextOf(node: UiNode): string | undefined {\n if (node.type !== UiNodeType.Text || !isNodeSelectable(node) || isUnderInert(node)) {\n return undefined;\n }\n // A paragraph given runs has its text in them; `textContentOf` is\n // the one place that difference is known, so selecting, finding and\n // the semantics mirror all see one string either way.\n const text = textContentOf(node);\n return text.length > 0 ? text : undefined;\n}\n\n/**\n * Whether anything from the node up hides it. Inertness is a subtree\n * property, so the answer is not on the node alone — and a caller may\n * hold a node reference from before an ancestor was hidden.\n */\nfunction isUnderInert(node: UiNode): boolean {\n for (let current: UiNode | null = node; current !== null; current = current.parent) {\n if (isNodeInert(current)) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * Every selectable text node under `root`, in document order.\n *\n * Document order is what makes a selection across nodes meaningful:\n * the two ends are ordered by their position in this list, and every\n * node between them is fully covered. Fragments are expanded in place,\n * as they are everywhere else; `zIndex` is deliberately not honoured,\n * because painting order is not reading order.\n */\nexport function selectableTextNodes(root: UiNode): UiNode[] {\n const found: UiNode[] = [];\n collectSelectable(root, found);\n return found;\n}\n\nfunction collectSelectable(node: UiNode, out: UiNode[]): void {\n if (isNodeInert(node)) {\n return;\n }\n if (selectableTextOf(node) !== undefined) {\n out.push(node);\n return;\n }\n for (let child = node.firstChild; child !== null; child = child.nextSibling) {\n collectSelectable(child, out);\n }\n}\n","import type { UiNode } from '../graph/UiNode';\nimport type { TextRange } from '../selection/UiSelectable';\n\n/**\n * The node property holding the ranges of a `Text` node's text that the\n * current find query matched, or absent when none of it did.\n *\n * A list rather than the single range a selection has, because a\n * paragraph can hold several matches; and a separate property from\n * `textSelection`, because the two are lit at once — the active match\n * is the selection, drawn over its own softer match highlight. Both\n * live on the node for the same reason (see `UiSelectable`): in the\n * render worker the graph is all the renderer has.\n */\nexport const TEXT_MATCHES_PROP = 'textMatches';\n\n/** The matched ranges of a node's text, or undefined when it has none. */\nexport function matchRangesOf(node: UiNode): readonly TextRange[] | undefined {\n const ranges = node.properties.get(TEXT_MATCHES_PROP);\n return Array.isArray(ranges) && ranges.length > 0 ? (ranges as readonly TextRange[]) : undefined;\n}\n\n/** Writes a node's matched ranges. Returns whether they changed. */\nexport function setMatchRanges(node: UiNode, ranges: readonly TextRange[]): boolean {\n const current = matchRangesOf(node);\n if (current !== undefined && rangesEqual(current, ranges)) {\n return false;\n }\n if (ranges.length === 0) {\n return clearMatchRanges(node);\n }\n node.properties.set(TEXT_MATCHES_PROP, ranges);\n return true;\n}\n\n/** Clears a node's matched ranges. Returns whether it had any. */\nexport function clearMatchRanges(node: UiNode): boolean {\n return node.properties.delete(TEXT_MATCHES_PROP);\n}\n\nfunction rangesEqual(a: readonly TextRange[], b: readonly TextRange[]): boolean {\n if (a.length !== b.length) {\n return false;\n }\n for (let i = 0; i < a.length; i++) {\n if (a[i].start !== b[i].start || a[i].end !== b[i].end) {\n return false;\n }\n }\n return true;\n}\n","import type { UiNode } from '../graph/UiNode';\nimport { UiProperties } from './UiProperty';\nimport { resolveProperty } from './UiPropertyResolver';\nimport type { UiFontWeight } from './UiPropertyValues';\nimport type { UiFontKerning, UiFontStretch, UiFontStyle, UiFontVariant } from './UiTextStyle';\n\n/**\n * `line-height: normal`: the factor of the font size a line takes when\n * no line height is set. Shared by ParagraphLayout and PaintState.\n */\nexport const DEFAULT_LINE_HEIGHT_FACTOR = 1.2;\n\n/** The font a text node is measured and painted with. */\nexport interface UiResolvedFont {\n readonly fontSize: number;\n readonly fontFamily: string;\n readonly fontWeight: UiFontWeight;\n readonly lineHeight: number;\n readonly letterSpacing: number;\n readonly fontStyle: UiFontStyle;\n readonly fontStretch: UiFontStretch;\n readonly fontVariant: UiFontVariant;\n readonly fontKerning: UiFontKerning;\n}\n\n/**\n * Resolves a node's font the one way layout and paint both use.\n *\n * Font size, family, weight and letter spacing inherit through the\n * environment's text style. Line height is the subtle one: a text\n * style carries a line height that belongs with its font size, so a\n * node that inherits the style takes it whole. A node that sets its\n * own `fontSize` without a `lineHeight` gets a normal line height for\n * that size, `fontSize × 1.2`, rather than the inherited pixel value\n * sized for a different font — the inherited 16.8px of the default\n * style is right for 14px text and wrong for 22px. An explicit\n * `lineHeight` always wins.\n *\n * Before this, layout read the raw props (unset line height → ×1.2)\n * and paint read the inherited ones (→ 16.8px), so any text whose size\n * differed from the style's was measured in one line box and drawn in\n * another, and sat high or low inside it.\n */\nexport function resolveFont(node: UiNode): UiResolvedFont {\n const out: UiFontFields = {\n fontSize: 0,\n fontFamily: '',\n fontWeight: 'normal',\n lineHeight: 0,\n letterSpacing: 0,\n fontStyle: 'normal',\n fontStretch: 'normal',\n fontVariant: 'normal',\n fontKerning: 'auto'\n };\n resolveFontInto(node, out);\n return out as UiResolvedFont;\n}\n\n/**\n * The fields a resolved font is, seen as somewhere to put them.\n *\n * `PaintState` has all of them under the same names, which is what\n * lets paint resolve a node's font straight into the scratch it\n * already owns rather than into a record it allocates and copies out\n * of. The weight is widened to `string | number`, and the four\n * keyword fields to `string`, because the paint state carries them\n * that way.\n */\nexport interface UiFontFields {\n fontSize: number;\n fontFamily: string;\n fontWeight: string | number;\n lineHeight: number;\n letterSpacing: number;\n fontStyle: string;\n fontStretch: string;\n fontVariant: string;\n fontKerning: string;\n}\n\n/** `resolveFont`, writing into a target the caller owns. */\nexport function resolveFontInto(node: UiNode, out: UiFontFields): void {\n const fontSize = positive(resolveProperty(node, UiProperties.fontSize)) ?? UiProperties.fontSize.defaultValue;\n const ownFontSize = node.properties.get('fontSize');\n const ownLineHeight = positive(node.properties.get('lineHeight'));\n if (ownLineHeight !== undefined) {\n out.lineHeight = ownLineHeight;\n } else if (ownFontSize !== undefined) {\n out.lineHeight = fontSize * DEFAULT_LINE_HEIGHT_FACTOR;\n } else {\n out.lineHeight = positive(resolveProperty(node, UiProperties.lineHeight)) ?? fontSize * DEFAULT_LINE_HEIGHT_FACTOR;\n }\n out.fontSize = fontSize;\n out.fontFamily = nonEmpty(resolveProperty(node, UiProperties.fontFamily)) ?? UiProperties.fontFamily.defaultValue;\n out.fontWeight = weight(resolveProperty(node, UiProperties.fontWeight)) ?? UiProperties.fontWeight.defaultValue;\n out.letterSpacing = finite(resolveProperty(node, UiProperties.letterSpacing)) ?? 0;\n out.fontStyle = nonEmpty(resolveProperty(node, UiProperties.fontStyle)) ?? 'normal';\n out.fontStretch = nonEmpty(resolveProperty(node, UiProperties.fontStretch)) ?? 'normal';\n out.fontVariant = nonEmpty(resolveProperty(node, UiProperties.fontVariant)) ?? 'normal';\n out.fontKerning = nonEmpty(node.properties.get('fontKerning')) ?? 'auto';\n}\n\nfunction positive(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isFinite(value) && value > 0 ? value : undefined;\n}\n\nfunction finite(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined;\n}\n\nfunction weight(value: unknown): UiFontWeight | undefined {\n return typeof value === 'number' ? finite(value) : (nonEmpty(value) as UiFontWeight | undefined);\n}\n\nfunction nonEmpty(value: unknown): string | undefined {\n return typeof value === 'string' && value.length > 0 ? value : undefined;\n}\n","import type { UiNode } from '../graph/UiNode';\nimport type { LayoutBox } from '../layout/LayoutTypes';\nimport type { TextOverflow, TextWrap } from '../layout/TextMeasurer';\nimport { resolveProperty, resolveNumber, resolveString, resolveBoolean } from '../properties/UiPropertyResolver';\nimport { UiProperties } from '../properties/UiProperty';\nimport type { UiColor } from '../properties/UiColor';\nimport { UiBasicColors, colorToHex, colorToRgba } from '../properties/UiColor';\nimport type { UiBorderRadius } from '../properties/UiBorderRadius';\nimport { resolveBorderRadiusValue } from '../properties/UiThemeShape';\nimport type { UiBoxShadow } from '../properties/UiBoxShadow';\nimport type { UiTransform } from '../properties/UiTransform';\nimport type { UiImage } from '../properties/UiImage';\nimport { isVideoSurface, type UiVideoSurface } from '../properties/UiVideo';\nimport { resolveColor, resolveColorValue, resolveGradient, themeColor } from '../properties/UiThemeColor';\nimport { UiEnvironmentKeys } from '../environment/UiEnvironmentKeys';\nimport type { ResolvedGradient } from '../properties/UiGradient';\nimport type { EditableTextModel } from '../editing/EditableTextModel';\nimport { editorFor, isEditableNode } from '../editing/UiEditable';\nimport { selectionRangeOf, type TextRange } from '../selection/UiSelectable';\nimport { matchRangesOf } from '../find/UiTextMatches';\nimport { resolveFontInto } from '../properties/UiTextFont';\nimport type {\n UiFontKerning,\n UiFontStretch,\n UiFontStyle,\n UiFontVariant,\n UiTextDecoration,\n UiTextLink,\n UiTextMetrics,\n UiResolvedTextSpan\n} from '../properties/UiTextStyle';\nimport { editableSpansOf, resolvedSpansOf, textContentOf } from '../properties/UiTextStyle';\nimport { linkHoverOf } from '../selection/UiTextLinks';\nimport { parseTransform } from '../properties/UiTransform';\n\nexport type { UiImage } from '../properties/UiImage';\nexport type { UiVideoSurface } from '../properties/UiVideo';\n\nexport type TextAlign = 'start' | 'end' | 'left' | 'center' | 'right';\nexport type VerticalAlign = 'top' | 'middle' | 'bottom';\nexport type ObjectFit = 'fill' | 'cover' | 'contain' | 'none';\n\n/**\n * Everything a node needs to paint, folded out of node properties.\n *\n * Resolved per frame into a reusable scratch (see resolvePaintState);\n * never stored on the node. `transform` is always allocated so the\n * resolution pass does not allocate; read it only when hasTransform\n * is true.\n */\nexport interface PaintState {\n visible: boolean;\n opacity: number;\n backgroundColor: UiColor | undefined;\n /**\n * A gradient filling the box, painted over `backgroundColor` and\n * under `image`, with its stops' palette names already resolved\n * against the node's theme. Its geometry is still relative: the\n * renderer places it once it has the node's box.\n */\n backgroundGradient: ResolvedGradient | undefined;\n image: UiImage | undefined;\n /**\n * A moving picture, drawn where `image` would be and under the same\n * `objectFit` and rounded clip.\n *\n * A slot of its own rather than a widened `image`, because the two\n * are cached differently: an image is its pixels and a video is a\n * surface whose pixels change. See `UiVideo.ts`.\n */\n video: UiVideoSurface | undefined;\n objectFit: ObjectFit;\n borderColor: UiColor | undefined;\n borderWidth: number;\n borderRadius: UiBorderRadius;\n boxShadows: readonly UiBoxShadow[];\n hasTransform: boolean;\n transform: UiTransform;\n text: string | undefined;\n /**\n * The paragraph's runs, with their colours resolved against the\n * node's theme; undefined for a paragraph in one style.\n *\n * `text` is the runs' text concatenated, so every other field of\n * this state, and every offset any other layer holds, means what it\n * always meant.\n */\n spans: readonly PaintTextSpan[] | undefined;\n /** Index into `spans` of the link the pointer is on, or -1. */\n linkHover: number;\n fontSize: number;\n fontFamily: string;\n fontWeight: string | number;\n lineHeight: number;\n /** Extra space after each character, as CSS `letter-spacing`. */\n letterSpacing: number;\n fontStyle: UiFontStyle;\n fontStretch: UiFontStretch;\n fontVariant: UiFontVariant;\n fontKerning: UiFontKerning;\n /** Lines drawn with the whole paragraph; a run may override it. */\n textDecoration: UiTextDecoration;\n textColor: UiColor;\n textAlign: TextAlign;\n verticalAlign: VerticalAlign;\n textWrap: TextWrap;\n maxLines: number | undefined;\n textOverflow: TextOverflow;\n /** Right-to-left paragraph direction. */\n rtl: boolean;\n /**\n * Set for an EditableText node: the model whose text `text` is, with\n * its selection and composition, and the colours the editing chrome\n * is drawn in. Undefined for every other node.\n */\n editor: EditableTextModel | undefined;\n /**\n * Set for a `Text` node the user has selected part of: the range of\n * `text`, in source offsets, drawn behind the glyphs in\n * `selectionColor`. Undefined for everything else, including\n * editables, whose selection lives in `editor`.\n */\n textSelection: TextRange | undefined;\n /**\n * Set for a `Text` node the current find query matched: the ranges of\n * `text` drawn in `matchColor`, under the selection, so the active\n * match reads as the strongest of them.\n */\n textMatches: readonly TextRange[] | undefined;\n placeholder: string | undefined;\n placeholderColor: UiColor;\n selectionColor: UiColor;\n matchColor: UiColor;\n caretColor: UiColor;\n}\n\n/** A run of a paragraph, ready to paint: metrics, resolved colours, and its link. */\nexport interface PaintTextSpan extends UiTextMetrics {\n readonly start: number;\n readonly end: number;\n readonly color?: UiColor;\n readonly backgroundColor?: UiColor;\n readonly textDecoration?: UiTextDecoration;\n readonly link?: UiTextLink;\n}\n\nexport const DEFAULT_FONT_SIZE = 14;\nexport const DEFAULT_FONT_FAMILY = 'sans-serif';\nexport const DEFAULT_FONT_WEIGHT = 'normal';\nexport const DEFAULT_TEXT_COLOR = UiBasicColors.black;\nexport { DEFAULT_LINE_HEIGHT_FACTOR } from '../properties/UiTextFont';\n\nexport function normalizeTextAlign(value: unknown): TextAlign {\n switch (value) {\n case 'center':\n case 'right':\n case 'left':\n case 'end':\n return value;\n default:\n return 'start';\n }\n}\n\nexport function normalizeTextWrap(value: unknown): TextWrap {\n if (value === 'none' || value === 'nowrap') {\n return 'none';\n }\n if (value === 'char') {\n return 'char';\n }\n return 'word';\n}\n\nexport function normalizeTextOverflow(value: unknown): TextOverflow {\n return value === 'ellipsis' ? 'ellipsis' : 'clip';\n}\n\nexport function normalizeVerticalAlign(value: unknown): VerticalAlign {\n if (value === 'middle' || value === 'center') {\n return 'middle';\n }\n if (value === 'bottom' || value === 'end') {\n return 'bottom';\n }\n return 'top';\n}\n\n/**\n * Folds a node's properties into the supplied paint state.\n *\n * Mutates `out` and returns it. The renderer owns one scratch and\n * calls this per node, so the tree stays structural and no paint\n * objects are allocated per frame.\n *\n * The text half is resolved only for a node that has text, because\n * most nodes in a real tree are boxes and the half is about ten\n * property resolutions they would never read. The condition is\n * `out.text`, which is set a few lines above by the branch that knows:\n * an editable takes it from its model, so it is a string (possibly\n * empty) for every editable and drives the caret and placeholder that\n * an empty field still paints; everything else takes it from\n * `resolveString`, which reports an empty string as absent, so a\n * `<text text=\"\" />` and a `<box />` are the same node to paint and\n * were before this split too.\n *\n * What makes that safe is that nothing reads a text field without\n * first asking whether the node has text. Both renderer walks capture\n * a `hasText` from the resolved state and enter their foreground block\n * only if it is set; Canvas2D's `paintContent` tests `text` again\n * before it draws. Decorations, backgrounds, borders, images,\n * scrollbars and the lifted-node replay read only the geometry half.\n * The three controllers that resolve a state of their own reach a text\n * field only through `paragraphGeometry` or `EditableLayout`, and each\n * of them is already behind a guard that requires text: the selection\n * and find controllers only ever ask about a node `selectableTextOf`\n * returned a non-empty string for, and the editing controller only\n * about a node with an editor. `rtl` lives here rather than with the\n * geometry because paint's copy is the paragraph's base direction and\n * nothing else; the row reversal that reads the same declared property\n * asks the node directly, in `LayoutEngine`.\n *\n * The skipped fields are reset rather than left holding the previous\n * node's, so the scratch a box comes out of is exactly the one\n * `createPaintState` builds. That costs about a twentieth of what\n * resolving them costs and it is what makes the split safe by\n * construction: a reader added later that forgets the guard gets a\n * default font and a black, top-left, wrapping paragraph, not the\n * neighbouring label's.\n *\n * A new reader of any of these fields must therefore be reachable only\n * when `text` is set, or it must resolve what it needs from the node\n * itself. Widening the condition is the wrong repair: the fields exist\n * to describe a paragraph, and a node with no paragraph has no honest\n * answer for them.\n */\nexport function resolvePaintState(node: UiNode, out: PaintState): PaintState {\n out.visible = resolveBoolean(node, 'visible') ?? true;\n\n const opacity = resolveNumber(node, 'opacity');\n out.opacity = opacity === undefined ? 1 : Math.min(Math.max(opacity, 0), 1);\n\n out.backgroundColor = resolveColor(node, UiProperties.backgroundColor);\n out.backgroundGradient = resolveGradient(node, resolveProperty(node, UiProperties.backgroundGradient));\n out.borderColor = resolveColor(node, UiProperties.borderColor);\n out.borderWidth = resolveNumber(node, 'borderWidth') ?? 0;\n out.borderRadius = resolveBorderRadiusValue(node, resolveProperty(node, UiProperties.borderRadius));\n out.boxShadows = resolveProperty(node, UiProperties.boxShadows);\n out.image = parseImage(node.properties.get('image'));\n out.video = parseVideo(node.properties.get('video'));\n out.objectFit = parseObjectFit(node.properties.get('objectFit'));\n\n const rawTransform = node.properties.get('transform');\n const parsedTransform = rawTransform !== undefined ? parseTransform(rawTransform) : undefined;\n if (parsedTransform !== undefined) {\n out.hasTransform = true;\n out.transform = parsedTransform;\n } else {\n out.hasTransform = false;\n }\n\n if (isEditableNode(node)) {\n // The user's text lives in the model, not in a property; see\n // UiEditable. It is always a string here, so an empty field still\n // paints its caret and placeholder.\n const model = editorFor(node);\n out.editor = model;\n out.text = model.text;\n out.placeholder = resolveString(node, 'placeholder');\n out.placeholderColor =\n resolveColor(node, UiProperties.placeholderColor) ?? themeColor(node, 'textMuted') ?? DEFAULT_PLACEHOLDER_COLOR;\n out.selectionColor = resolveColor(node, UiProperties.selectionColor) ?? defaultSelectionColor(node);\n out.caretColor =\n resolveColor(node, UiProperties.caretColor) ?? resolveColor(node, UiProperties.color) ?? UiBasicColors.black;\n out.textSelection = undefined;\n out.textMatches = undefined;\n } else {\n out.editor = undefined;\n const spanned = resolvedSpansOf(node);\n if (spanned.length > 0) {\n out.text = textContentOf(node);\n } else {\n out.text = resolveString(node, 'text');\n if (out.text === undefined) {\n warnIfTextIsNotText(node);\n }\n }\n out.placeholder = undefined;\n // Only a selected paragraph pays for the colour: the scratch is\n // reused across nodes, so an unselected one must not resolve it and\n // must not read the last node's either.\n out.textSelection = out.text === undefined ? undefined : selectionRangeOf(node);\n if (out.textSelection !== undefined) {\n out.selectionColor = resolveColor(node, UiProperties.selectionColor) ?? defaultSelectionColor(node);\n }\n out.textMatches = out.text === undefined ? undefined : matchRangesOf(node);\n if (out.textMatches !== undefined) {\n out.matchColor = resolveColor(node, UiProperties.matchColor) ?? defaultMatchColor(node);\n }\n }\n\n if (out.text === undefined) {\n resetTextStyle(out);\n return out;\n }\n\n out.rtl = resolveProperty(node, UiProperties.textDirection) === 'rtl';\n\n // Resolved the same way layout measured it (see resolveFont), and\n // straight into the scratch: the state already has the fields under\n // those names, so paint has no record to allocate and copy.\n resolveFontInto(node, out);\n // An editable may carry runs too, but only ones that describe the\n // text its model holds — see `editableSpansOf`.\n out.spans = resolvePaintSpans(\n node,\n out.editor === undefined ? resolvedSpansOf(node) : editableSpansOf(node, out.text ?? '')\n );\n out.linkHover = out.spans === undefined ? -1 : linkHoverOf(node);\n out.textDecoration = resolveProperty(node, UiProperties.textDecoration);\n out.textColor = resolveColor(node, UiProperties.color) ?? UiBasicColors.black;\n out.textAlign = normalizeTextAlign(resolveProperty(node, UiProperties.textAlign));\n out.verticalAlign = normalizeVerticalAlign(resolveString(node, 'verticalAlign'));\n out.textWrap = normalizeTextWrap(resolveString(node, 'textWrap'));\n const maxLines = resolveNumber(node, 'maxLines');\n out.maxLines = maxLines !== undefined && maxLines >= 1 ? Math.floor(maxLines) : undefined;\n out.textOverflow = normalizeTextOverflow(resolveString(node, 'textOverflow'));\n\n return out;\n}\n\n/**\n * Returns the text half of a reused scratch to the values\n * `createPaintState` gives it, for a node that has no text.\n *\n * Twelve assignments of constants, against the ten property\n * resolutions they stand in for: on the frame benchmark's tree the\n * reset is 0.09ms of a 3.2ms pass over 5,001 nodes, where skipping the\n * resolutions saves 1.7ms of it. Keeping the previous node's values\n * instead would save that twentieth and cost the one guarantee worth\n * having here, which is that a box never comes out of this function\n * wearing a label's font.\n *\n * `lineHeight` resets to zero rather than to a normal line height for\n * the default size, because zero is what the field means when nothing\n * has resolved it: `textMeasureRequest` reads any value at or below\n * zero as \"no declared line height\" and lets the paragraph choose.\n */\nfunction resetTextStyle(out: PaintState): void {\n out.fontSize = DEFAULT_FONT_SIZE;\n out.fontFamily = DEFAULT_FONT_FAMILY;\n out.fontWeight = DEFAULT_FONT_WEIGHT;\n out.lineHeight = 0;\n out.letterSpacing = 0;\n out.textColor = DEFAULT_TEXT_COLOR;\n out.textAlign = 'start';\n out.verticalAlign = 'top';\n out.textWrap = 'word';\n out.maxLines = undefined;\n out.textOverflow = 'clip';\n out.rtl = false;\n out.fontStyle = 'normal';\n out.fontStretch = 'normal';\n out.fontVariant = 'normal';\n out.fontKerning = 'auto';\n out.textDecoration = 'none';\n out.spans = undefined;\n out.linkHover = -1;\n}\n\n/**\n * A node's runs with their colours resolved against its theme,\n * remembered by the identity of the array they came from and the\n * theme they were resolved against.\n *\n * The memo is what keeps the paint state's promise not to allocate per\n * frame: a run's colour may be a palette name, so resolving it needs\n * the theme, and doing that for every run of every paragraph on screen\n * on every frame would allocate a run record per run per frame. A\n * theme change is an object change, so it invalidates the memo without\n * anything having to notice.\n */\nconst paintSpans = new WeakMap<readonly UiResolvedTextSpan[], { theme: unknown; spans: readonly PaintTextSpan[] }>();\n\nfunction resolvePaintSpans(node: UiNode, spans: readonly UiResolvedTextSpan[]): readonly PaintTextSpan[] | undefined {\n if (spans.length === 0) {\n return undefined;\n }\n const theme = node.environment !== null ? node.environment.get(UiEnvironmentKeys.theme) : undefined;\n const cached = paintSpans.get(spans);\n if (cached !== undefined && cached.theme === theme) {\n return cached.spans;\n }\n const resolved: PaintTextSpan[] = spans.map(span => ({\n start: span.start,\n end: span.end,\n fontFamily: span.fontFamily,\n fontSize: span.fontSize,\n fontWeight: span.fontWeight,\n fontStyle: span.fontStyle,\n fontStretch: span.fontStretch,\n fontVariant: span.fontVariant,\n fontKerning: span.fontKerning,\n letterSpacing: span.letterSpacing,\n color: resolveColorValue(node, span.color),\n backgroundColor: resolveColorValue(node, span.backgroundColor),\n textDecoration: span.textDecoration,\n link: span.link\n }));\n paintSpans.set(spans, { theme, spans: resolved });\n return resolved;\n}\n\n/**\n * Whether a node paints at all, answered from its two cheapest\n * properties.\n *\n * Both renderer walks need to know this before they know anything else:\n * an invisible node is skipped whether or not it is on screen, and a\n * lifted one must not join the top layer if it is invisible. Resolving\n * the whole paint state to learn it costs about twenty-five property\n * resolutions, which a long list pays for every row it then culls, so\n * the walks ask this first and resolve the rest only for the nodes that\n * survive the cull.\n *\n * It reads `visible` and `opacity` through the same resolvers\n * `resolvePaintState` uses, so the two cannot come to different\n * answers. `resolvePaintState` clamps opacity into [0, 1] and the\n * renderers then test it against zero, which is the same question as\n * \"is it zero or less\" asked of the unclamped value; a non-numeric\n * opacity fails both comparisons and stays visible either way.\n */\nexport function isPaintVisible(node: UiNode): boolean {\n if (resolveBoolean(node, 'visible') === false) {\n return false;\n }\n const opacity = resolveNumber(node, 'opacity');\n return !(opacity !== undefined && opacity <= 0);\n}\n\n/**\n * Resolves the destination rectangle for an object-fit image.\n *\n * Pure geometry so the same semantics can be reused by a future\n * WebGPU backend.\n */\nexport function computeObjectFitRect(\n fit: ObjectFit,\n imageWidth: number,\n imageHeight: number,\n box: LayoutBox\n): LayoutBox {\n if (imageWidth <= 0 || imageHeight <= 0) {\n return { x: box.x, y: box.y, width: 0, height: 0 };\n }\n switch (fit) {\n case 'cover': {\n const scale = Math.max(box.width / imageWidth, box.height / imageHeight);\n const width = imageWidth * scale;\n const height = imageHeight * scale;\n return { x: box.x + (box.width - width) / 2, y: box.y + (box.height - height) / 2, width, height };\n }\n case 'contain': {\n const scale = Math.min(box.width / imageWidth, box.height / imageHeight);\n const width = imageWidth * scale;\n const height = imageHeight * scale;\n return { x: box.x + (box.width - width) / 2, y: box.y + (box.height - height) / 2, width, height };\n }\n case 'none':\n return { x: box.x, y: box.y, width: imageWidth, height: imageHeight };\n default:\n return { x: box.x, y: box.y, width: box.width, height: box.height };\n }\n}\n\nfunction parseVideo(value: unknown): UiVideoSurface | undefined {\n return isVideoSurface(value) ? value : undefined;\n}\n\nfunction parseImage(value: unknown): UiImage | undefined {\n if (typeof value !== 'object' || value === null) {\n return undefined;\n }\n const candidate = value as { width?: unknown; height?: unknown };\n if (typeof candidate.width !== 'number' || typeof candidate.height !== 'number') {\n return undefined;\n }\n return value as UiImage;\n}\n\nfunction parseObjectFit(value: unknown): ObjectFit {\n if (value === 'cover' || value === 'contain' || value === 'none') {\n return value;\n }\n return 'fill';\n}\n\n/**\n * Creates a fresh default PaintState with its transform scratch\n * pre-allocated. The result is meant to be reused across nodes.\n */\nexport function createPaintState(): PaintState {\n return {\n visible: true,\n opacity: 1,\n backgroundColor: undefined,\n backgroundGradient: undefined,\n image: undefined,\n video: undefined,\n objectFit: 'fill',\n borderColor: undefined,\n borderWidth: 0,\n borderRadius: { topLeft: 0, topRight: 0, bottomRight: 0, bottomLeft: 0 },\n boxShadows: [],\n hasTransform: false,\n transform: { x: 0, y: 0, translateX: 0, translateY: 0, scaleX: 1, scaleY: 1, rotation: 0 },\n text: undefined,\n spans: undefined,\n linkHover: -1,\n fontSize: DEFAULT_FONT_SIZE,\n fontFamily: DEFAULT_FONT_FAMILY,\n fontWeight: DEFAULT_FONT_WEIGHT,\n lineHeight: 0,\n letterSpacing: 0,\n fontStyle: 'normal',\n fontStretch: 'normal',\n fontVariant: 'normal',\n fontKerning: 'auto',\n textDecoration: 'none',\n textColor: DEFAULT_TEXT_COLOR,\n textAlign: 'start',\n verticalAlign: 'top',\n textWrap: 'word',\n maxLines: undefined,\n textOverflow: 'clip',\n rtl: false,\n editor: undefined,\n textSelection: undefined,\n textMatches: undefined,\n placeholder: undefined,\n placeholderColor: DEFAULT_PLACEHOLDER_COLOR,\n selectionColor: DEFAULT_SELECTION_COLOR,\n matchColor: DEFAULT_MATCH_COLOR,\n caretColor: DEFAULT_TEXT_COLOR\n };\n}\n\nconst DEFAULT_PLACEHOLDER_COLOR: UiColor = { r: 0.4, g: 0.4, b: 0.4, a: 1 };\nconst DEFAULT_SELECTION_COLOR: UiColor = { r: 0.13, g: 0.59, b: 0.95, a: 0.35 };\nconst DEFAULT_MATCH_COLOR: UiColor = { r: 0.61, g: 0.15, b: 0.69, a: 0.3 };\n\n/** The theme's primary at a third of its strength, behind selected text. */\nfunction defaultSelectionColor(node: UiNode): UiColor {\n const primary = themeColor(node, 'primary');\n return primary === undefined ? DEFAULT_SELECTION_COLOR : { r: primary.r, g: primary.g, b: primary.b, a: 0.35 };\n}\n\n/**\n * The theme's secondary, weaker than the selection. Find matches are\n * drawn under the active one, which is a real selection in the theme's\n * primary, so the two have to be told apart at a glance.\n */\nfunction defaultMatchColor(node: UiNode): UiColor {\n const secondary = themeColor(node, 'secondary');\n return secondary === undefined ? DEFAULT_MATCH_COLOR : { r: secondary.r, g: secondary.g, b: secondary.b, a: 0.3 };\n}\n\n/**\n * Converts a UiColor to a CSS color string for renderer consumption.\n *\n * Uses hex for fully opaque colors and rgba() when transparency is\n * involved, matching common Canvas2D conventions.\n */\nexport function colorToCss(color: UiColor): string {\n if (color.a === 1) {\n return colorToHex(color);\n }\n return colorToRgba(color);\n}\n\nconst warnedNonText = new WeakSet<UiNode>();\n\n/**\n * A `text` that is not a string paints nothing and, until now, said\n * nothing. The one honest way to write one is the JSX rule that a lone\n * Observable child of <text> or <button> is its label: an icon written\n * as `<button>{icon$}</button>` binds an element to `text`. Once per\n * node, so a bound value that flickers through a wrong type is one line\n * and not a stream.\n */\nfunction warnIfTextIsNotText(node: UiNode): void {\n const raw = resolveProperty(node, UiProperties.text) as unknown;\n if (raw === undefined || raw === null || typeof raw === 'string' || warnedNonText.has(node)) {\n return;\n }\n warnedNonText.add(node);\n const kind = Array.isArray(raw) ? 'an array' : typeof raw === 'object' ? 'an element or object' : typeof raw;\n console.warn(\n `Node '${node.id}' has a text that is ${kind}, and nothing is drawn for it. A lone Observable child of ` +\n `<text> or <button> is read as its text; if it was meant as children, put it in an array (\\`{[child$]}\\`) ` +\n `or wrap it in a <box>.`\n );\n}\n","/**\n * The fallback stack behind a declared font family.\n *\n * An application declares a family once, with the families to try for\n * glyphs it lacks and to draw with until its file arrives\n * (`renderRoot(App).useFonts(...)` in the framework). Text then names\n * the family alone, `fontFamily: 'Inter'`, and every font string the\n * runtime builds, for measuring and for drawing, on either renderer,\n * carries the whole stack: `Inter, system-ui, sans-serif`. That is the\n * one place a family name becomes a CSS font-family list, so a\n * measurement and the glyphs drawn from it can never disagree about\n * which fonts they meant.\n *\n * A module-level registry, like the platform's own `FontFaceSet`: fonts\n * are a fact about the thread, not about one runtime, and two runtimes\n * in one worker (the playground has several) see the same faces.\n * A family nobody declared passes through unchanged, so a string that\n * is already a list, `'Georgia, serif'`, keeps working as it always\n * has.\n */\ninterface FontStack {\n readonly families: readonly string[];\n /** How many times a face of this family has arrived; see `bumpFontStack`. */\n generation: number;\n /** The list as last built, so a measure does not rebuild it. */\n list: string;\n}\n\nconst stacks = new Map<string, FontStack>();\n\n/** Declares the families tried after `family`, in order. */\nexport function registerFontStack(family: string, fallback: readonly string[]): void {\n const families = [family, ...fallback].map(cssFamilyName);\n stacks.set(family, { families, generation: 0, list: families.join(', ') });\n}\n\n/** The CSS font-family list for a family: its declared stack, or the name as given. */\nexport function fontStackFor(family: string): string {\n return stacks.get(family)?.list ?? family;\n}\n\n/**\n * Records that a face of `family` has arrived, and changes the family's\n * list so that every font string built from now on differs from every\n * one built before.\n *\n * That difference is the whole point. Chrome resolves a canvas font\n * string once per worker and keeps the answer: a string first used\n * while the face was still loading stays resolved to the fallback for\n * the worker's lifetime, however many faces load afterwards, and a\n * fresh context or a wait for `fonts.ready` does not help. A string it\n * has not seen resolves against the faces present now. (Measured in\n * Chrome 152, in a worker: `10px Ahem, monospace` kept measuring the\n * monospace fallback after Ahem loaded; `10px Ahem, serif`, never used\n * before, measured Ahem.) So the list gains a trailing family name\n * that exists nowhere, `gesso-reload-N`, which no glyph ever reaches\n * because the generic before it matches everything, and which makes\n * the string new.\n */\nexport function bumpFontStack(family: string): void {\n const stack = stacks.get(family);\n if (stack === undefined) {\n return;\n }\n stack.generation++;\n stack.list = [...stack.families, `gesso-reload-${stack.generation}`].join(', ');\n}\n\n/** Forgets every declared stack; for tests. */\nexport function clearFontStacks(): void {\n stacks.clear();\n}\n\n/**\n * Quotes a family name that needs it. Generic families (`sans-serif`,\n * `system-ui`) must stay bare, because a quoted one is a family called\n * that; a name with a space must be quoted or the shorthand parser reads\n * it as several.\n */\nfunction cssFamilyName(name: string): string {\n const trimmed = name.trim();\n if (/^[\"']/.test(trimmed) || /^[a-zA-Z_-][\\w-]*$/.test(trimmed)) {\n return trimmed;\n }\n return `\"${trimmed.replace(/\"/g, '\\\\\"')}\"`;\n}\n","import type { ParagraphLayout, TextMeasureRequest, TextMeasurer, TextRunStyle } from '../layout/TextMeasurer';\nimport type { LayoutBox } from '../layout/LayoutTypes';\nimport type { UiColor } from '../properties/UiColor';\nimport type { Canvas2DContext } from './canvas2d/Canvas2DContext';\nimport type { PaintState, PaintTextSpan } from './PaintState';\nimport { colorToCss } from './PaintState';\nimport { fontStackFor } from './FontStacks';\n\n/**\n * A positioned line ready to draw.\n */\nexport interface TextLinePlacement {\n text: string;\n /** Offsets into the source text the line covers; see TextLine. */\n start: number;\n end: number;\n /** Left edge of the line box after horizontal alignment. */\n x: number;\n /** Top edge of the line box. */\n y: number;\n /** Alphabetic baseline: where the glyphs are actually drawn. */\n baselineY: number;\n /** Measured width of the line. */\n width: number;\n /** Height of one line box. */\n height: number;\n /**\n * The line cut at its runs, present only for a paragraph with\n * spans. `x` is already in the line's space, so a renderer draws a\n * run without knowing where the line starts.\n */\n runs?: readonly PlacedTextRun[];\n}\n\n/** One run of a placed line. */\nexport interface PlacedTextRun {\n /** Index into the paint state's spans, or -1 for text outside every run. */\n span: number;\n start: number;\n end: number;\n text: string;\n x: number;\n width: number;\n}\n\n/**\n * A rectangle drawn with the text: a run's background, an underline, a\n * strikethrough.\n *\n * Both renderers fill these and neither computes them, which is what\n * keeps the two in step: a decoration that moved would move in both\n * pictures or in neither, and the parity gate would see nothing.\n */\nexport interface TextRunRect {\n x: number;\n y: number;\n width: number;\n height: number;\n color: UiColor;\n}\n\n/** How much of the hovered link's own colour washes behind it. */\nconst LINK_HOVER_ALPHA = 0.12;\n\n/** One style object for every draw; see `runCanvasStyleInto`. */\nconst drawStyle: CanvasTextStyle = { font: '', letterSpacing: 0, fontStretch: 'normal', fontKerning: 'auto' };\n\n/**\n * Pure text layout, separated from Canvas2D drawing.\n *\n * Asks the shared TextMeasurer for the paragraph — the same lines the\n * layout engine sized the node with — and resolves x/y per line for\n * the requested alignment. Nothing here touches a canvas, so the same\n * geometry drives Canvas2D, WebGPU and the tests.\n *\n * Glyphs sit on the alphabetic baseline, `firstBaseline` below each\n * line top (half-leading plus ascent), which is how CSS positions a\n * line box and what the layout engine uses for baseline alignment.\n */\nexport function layoutTextLines(box: LayoutBox, state: PaintState, measurer: TextMeasurer): TextLinePlacement[] {\n const text = state.text;\n if (text === undefined || text.length === 0 || state.fontSize <= 0) {\n return [];\n }\n return placeLines(box, state, measurer.layout(textMeasureRequest(text, state, box)));\n}\n\n/** The measure request paint makes for a node's text: the one layout made too. */\nexport function textMeasureRequest(\n text: string,\n state: Pick<\n PaintState,\n | 'fontSize'\n | 'fontFamily'\n | 'fontWeight'\n | 'lineHeight'\n | 'letterSpacing'\n | 'fontStyle'\n | 'fontStretch'\n | 'fontVariant'\n | 'fontKerning'\n | 'textWrap'\n | 'maxLines'\n | 'textOverflow'\n | 'spans'\n >,\n box: LayoutBox\n): TextMeasureRequest {\n return {\n text,\n fontSize: state.fontSize,\n fontFamily: state.fontFamily,\n fontWeight: state.fontWeight,\n lineHeight: state.lineHeight > 0 ? state.lineHeight : undefined,\n // Tracking belongs in the request because it changes every width\n // in the paragraph. Paint left it out until spans arrived, so a\n // tracked label wrapped one way in layout and was re-laid-out\n // another way to be drawn, and cost two cache entries doing it.\n letterSpacing: state.letterSpacing,\n fontStyle: state.fontStyle,\n fontStretch: state.fontStretch,\n fontVariant: state.fontVariant,\n fontKerning: state.fontKerning,\n maxWidth: box.width > 0 ? box.width : undefined,\n wrap: state.textWrap,\n maxLines: state.maxLines,\n overflow: state.textOverflow,\n spans: state.spans\n };\n}\n\n/**\n * Positions a measured paragraph's lines in a box: x per line from the\n * horizontal alignment, y from the vertical alignment and line index.\n *\n * A line's runs are placed with it. In a right-to-left paragraph they\n * are placed from the right edge in reverse, because the canvas\n * reorders within one `fillText` and can no longer do it across two;\n * runs of mixed direction inside one line are still not reordered,\n * which is the limit `TextGeometry.ts` already states.\n */\nexport function placeLines(\n box: LayoutBox,\n state: Pick<PaintState, 'textAlign' | 'verticalAlign' | 'rtl'>,\n paragraph: ParagraphLayout\n): TextLinePlacement[] {\n const offsetY = verticalOffset(state.verticalAlign, box.height, paragraph.height);\n const placements: TextLinePlacement[] = [];\n for (let i = 0; i < paragraph.lines.length; i++) {\n const line = paragraph.lines[i];\n const x = horizontalOffset(state.textAlign, state.rtl, box.x, box.width, line.width);\n const y = box.y + offsetY + i * paragraph.lineHeight;\n let runs: PlacedTextRun[] | undefined;\n if (line.runs !== undefined) {\n runs = [];\n for (const run of line.runs) {\n runs.push({\n span: run.span,\n start: run.start,\n end: run.end,\n text: run.text,\n x: state.rtl ? x + line.width - run.x - run.width : x + run.x,\n width: run.width\n });\n }\n }\n placements.push({\n text: line.text,\n start: line.start,\n end: line.end,\n x,\n y,\n baselineY: y + paragraph.firstBaseline,\n width: line.width,\n height: paragraph.lineHeight,\n runs\n });\n }\n return placements;\n}\n\n/**\n * Builds a Canvas2D font shorthand from a resolved text style.\n *\n * The family goes through `fontStackFor`, so a declared family carries\n * its fallback stack here and nowhere else: the measurer and both\n * renderers build their font strings with this function.\n *\n * The order is the CSS `font` shorthand's, style then variant then\n * weight then size then family, and it is the whole of what a canvas\n * font string can say. A variable font's `wght` is reached through a\n * numeric weight, `wdth` through `fontStretch` — a context property,\n * not part of this string — and `tnum` and `liga` are not reachable at\n * all.\n */\nexport function buildFontString(\n state: Pick<PaintState, 'fontWeight' | 'fontSize' | 'fontFamily'> & { fontStyle?: string; fontVariant?: string }\n): string {\n const style = state.fontStyle !== undefined && state.fontStyle !== 'normal' ? `${state.fontStyle} ` : '';\n const variant = state.fontVariant !== undefined && state.fontVariant !== 'normal' ? `${state.fontVariant} ` : '';\n return `${style}${variant}${String(state.fontWeight)} ${state.fontSize}px ${fontStackFor(state.fontFamily)}`;\n}\n\n/**\n * The font shorthand for one run of a measure request: the run's own\n * fields where it sets them, the paragraph's where it does not.\n */\nexport function runFontString(request: TextRunStyle, style: TextRunStyle | undefined): string {\n return buildFontString({\n fontWeight: style?.fontWeight ?? request.fontWeight ?? 'normal',\n fontSize: style?.fontSize ?? request.fontSize ?? 0,\n fontFamily: style?.fontFamily ?? request.fontFamily ?? 'sans-serif',\n fontStyle: style?.fontStyle ?? request.fontStyle,\n fontVariant: style?.fontVariant ?? request.fontVariant\n });\n}\n\n/**\n * Everything about how a run is drawn that a canvas can be told.\n *\n * The font shorthand carries style, variant, weight, size and family.\n * The other three are context properties, and all three are *sticky*:\n * set once and every run drawn after inherits them, so each is written\n * on every apply, including back to its default.\n */\nexport interface CanvasTextStyle {\n font: string;\n letterSpacing: number;\n fontStretch: string;\n fontKerning: string;\n}\n\n/** A style object to fill, so the hot path allocates none. */\nexport function createCanvasTextStyle(): CanvasTextStyle {\n return { font: '', letterSpacing: 0, fontStretch: 'normal', fontKerning: 'auto' };\n}\n\n/**\n * Fills a caller-owned style with one run's font, and returns the key\n * that identifies it.\n *\n * The key is what the width cache is keyed by, and it has to carry the\n * three sticky properties as well as the font string, since two runs\n * of the same text in the same font are different widths at different\n * tracking, in a different width axis, or with kerning off. Measuring\n * and drawing both come through here, which is the only reason a width\n * can be trusted to describe the glyphs that get drawn.\n */\nexport function runCanvasStyleInto(\n request: TextRunStyle,\n style: TextRunStyle | undefined,\n out: CanvasTextStyle\n): string {\n out.font = runFontString(request, style);\n out.letterSpacing = style?.letterSpacing ?? request.letterSpacing ?? 0;\n out.fontStretch = style?.fontStretch ?? request.fontStretch ?? 'normal';\n out.fontKerning = style?.fontKerning ?? request.fontKerning ?? 'auto';\n return `${out.font}\\0${out.letterSpacing}\\0${out.fontStretch}\\0${out.fontKerning}`;\n}\n\n/**\n * Sets a run's font on a context.\n *\n * An engine too old for one of the three context properties ignores\n * the assignment, measuring and drawing both quietly do without, and\n * the two still agree, which is the only property that matters here.\n */\nexport function applyCanvasTextStyle(context: Canvas2DContext, style: CanvasTextStyle): void {\n context.font = style.font;\n const mutable = context as { letterSpacing?: string; fontStretch?: string; fontKerning?: string };\n mutable.letterSpacing = `${style.letterSpacing}px`;\n mutable.fontStretch = style.fontStretch;\n mutable.fontKerning = style.fontKerning;\n}\n\n/**\n * Draws a node's text into a 2D context.\n *\n * All style fields used are assigned before the first fillText, so\n * no state leaks between nodes and no save/restore is needed. Lines\n * are drawn at their measured width — never squeezed with fillText's\n * maxWidth — because the paragraph layout already decided how the\n * text fits: it wrapped, was ellipsised, or overflows exactly as CSS\n * would.\n */\nexport function drawText(ctx: Canvas2DContext, box: LayoutBox, state: PaintState, measurer: TextMeasurer): void {\n const placements = layoutTextLines(box, state, measurer);\n fillTextRects(ctx, textRunBackgrounds(placements, state));\n drawTextLines(\n ctx,\n placements,\n buildFontString(state),\n colorToCss(state.textColor),\n state.letterSpacing,\n state.rtl,\n state\n );\n fillTextRects(ctx, textRunDecorations(placements, state));\n}\n\n/**\n * Draws already-placed lines in one font and colour.\n *\n * `letterSpacing` is passed separately because it is not part of the\n * font shorthand, and it is set on every call rather than only when\n * non-zero because the context keeps it: a label with tracking would\n * otherwise leave every run drawn after it spaced out too. `rtl` is\n * the paragraph's base direction, set the same way and for the same\n * reason: the canvas keeps it, and it decides which side a neutral\n * character at the end of a line lands on. Lines are placed by\n * `placeLines` already, so the canvas's own alignment stays `left`.\n *\n * A line with runs is drawn run by run instead, each in its own font\n * and colour, at the x the paragraph measured for it. Everything about\n * where a run sits was decided in layout, so this is the same walk in\n * a different order and asks the platform to measure nothing.\n */\nexport function drawTextLines(\n ctx: Canvas2DContext,\n placements: readonly TextLinePlacement[],\n font: string,\n color: string,\n letterSpacing = 0,\n rtl = false,\n state?: SpanPaint\n): void {\n if (placements.length === 0) {\n return;\n }\n ctx.direction = rtl ? 'rtl' : 'ltr';\n ctx.textAlign = 'left';\n ctx.textBaseline = 'alphabetic';\n drawStyle.font = font;\n drawStyle.letterSpacing = letterSpacing;\n drawStyle.fontStretch = state?.fontStretch ?? 'normal';\n drawStyle.fontKerning = state?.fontKerning ?? 'auto';\n applyCanvasTextStyle(ctx, drawStyle);\n ctx.fillStyle = color;\n for (const placement of placements) {\n if (placement.runs !== undefined && state !== undefined) {\n for (const run of placement.runs) {\n if (run.text.length === 0) {\n continue;\n }\n const span = spanOf(state, run.span);\n runCanvasStyleInto(state, span, drawStyle);\n applyCanvasTextStyle(ctx, drawStyle);\n ctx.fillStyle = colorToCss(span?.color ?? state.textColor);\n ctx.fillText(run.text, run.x, placement.baselineY);\n }\n continue;\n }\n if (placement.text.length > 0) {\n ctx.fillText(placement.text, placement.x, placement.baselineY);\n }\n }\n}\n\n/** Fills rectangles that came from `textRunBackgrounds` or `textRunDecorations`. */\nexport function fillTextRects(ctx: Canvas2DContext, rects: readonly TextRunRect[]): void {\n for (const rect of rects) {\n ctx.fillStyle = colorToCss(rect.color);\n ctx.fillRect(rect.x, rect.y, rect.width, rect.height);\n }\n}\n\n/**\n * The paint half of a paragraph's runs: what a renderer needs that the\n * measure request does not carry.\n */\nexport type SpanPaint = Pick<\n PaintState,\n | 'spans'\n | 'textColor'\n | 'fontSize'\n | 'fontFamily'\n | 'fontWeight'\n | 'letterSpacing'\n | 'fontStyle'\n | 'fontStretch'\n | 'fontVariant'\n | 'fontKerning'\n | 'textDecoration'\n | 'linkHover'\n>;\n\n/**\n * The rectangles painted behind a paragraph's glyphs: a run's own\n * background, and the wash under the link the pointer is on.\n *\n * A background fills the line box rather than the glyph box, as a CSS\n * inline background does, so two adjacent runs of the same colour read\n * as one band.\n */\nexport function textRunBackgrounds(placements: readonly TextLinePlacement[], state: SpanPaint): readonly TextRunRect[] {\n if (state.spans === undefined) {\n return EMPTY_RECTS;\n }\n const rects: TextRunRect[] = [];\n for (const placement of placements) {\n if (placement.runs === undefined) {\n continue;\n }\n for (const run of placement.runs) {\n const span = spanOf(state, run.span);\n if (span === undefined) {\n continue;\n }\n if (span.backgroundColor !== undefined) {\n rects.push({\n x: run.x,\n y: placement.y,\n width: run.width,\n height: placement.height,\n color: span.backgroundColor\n });\n }\n if (run.span === state.linkHover && span.link !== undefined) {\n const color = span.color ?? state.textColor;\n rects.push({\n x: run.x,\n y: placement.y,\n width: run.width,\n height: placement.height,\n color: { r: color.r, g: color.g, b: color.b, a: color.a * LINK_HOVER_ALPHA }\n });\n }\n }\n }\n return rects;\n}\n\n/**\n * The lines drawn with a paragraph: underline and strikethrough, per\n * run where a run asks for them and across the whole paragraph where\n * the node does.\n *\n * The offsets are a fraction of the font size rather than the font's\n * own underline position, because a canvas font string cannot be asked\n * for that metric and `TextMetrics` does not carry it. They are\n * rounded to whole pixels so a hairline stays a hairline, and computed\n * here rather than in either renderer so the two cannot drift.\n *\n * A link the pointer is on is underlined whether or not it asked to\n * be, which is the hover state a link owes the person using it.\n */\nexport function textRunDecorations(placements: readonly TextLinePlacement[], state: SpanPaint): readonly TextRunRect[] {\n const paragraphDecoration = state.textDecoration ?? 'none';\n if (paragraphDecoration === 'none' && state.spans === undefined) {\n return EMPTY_RECTS;\n }\n const rects: TextRunRect[] = [];\n for (const placement of placements) {\n if (placement.runs === undefined) {\n if (paragraphDecoration !== 'none' && placement.text.length > 0) {\n push(\n rects,\n paragraphDecoration,\n placement.x,\n placement.width,\n placement.baselineY,\n state.fontSize,\n state.textColor\n );\n }\n continue;\n }\n for (const run of placement.runs) {\n if (run.text.length === 0) {\n continue;\n }\n const span = spanOf(state, run.span);\n const hovered = run.span === state.linkHover && span?.link !== undefined;\n let decoration = span?.textDecoration ?? paragraphDecoration;\n if (hovered && decoration !== 'underline line-through') {\n decoration = decoration === 'line-through' ? 'underline line-through' : 'underline';\n }\n if (decoration === 'none') {\n continue;\n }\n push(\n rects,\n decoration,\n run.x,\n run.width,\n placement.baselineY,\n span?.fontSize ?? state.fontSize,\n span?.color ?? state.textColor\n );\n }\n }\n return rects;\n}\n\nconst EMPTY_RECTS: readonly TextRunRect[] = [];\n\nfunction push(\n rects: TextRunRect[],\n decoration: string,\n x: number,\n width: number,\n baselineY: number,\n fontSize: number,\n color: UiColor\n): void {\n const thickness = Math.max(1, Math.round(fontSize / 14));\n if (decoration.includes('underline')) {\n rects.push({ x, y: Math.round(baselineY + Math.max(1, fontSize * 0.08)), width, height: thickness, color });\n }\n if (decoration.includes('line-through')) {\n rects.push({ x, y: Math.round(baselineY - fontSize * 0.28), width, height: thickness, color });\n }\n}\n\n/** The span a run came from, or undefined for text outside every run. */\nexport function spanOf(state: Pick<PaintState, 'spans'>, index: number): PaintTextSpan | undefined {\n return index < 0 || state.spans === undefined ? undefined : state.spans[index];\n}\n\n/** `start` and `end` follow the paragraph's direction; `left` and `right` do not. */\nfunction horizontalOffset(align: string, rtl: boolean, x: number, width: number, lineWidth: number): number {\n switch (align) {\n case 'center':\n return x + (width - lineWidth) / 2;\n case 'right':\n return x + width - lineWidth;\n case 'left':\n return x;\n case 'end':\n return rtl ? x : x + width - lineWidth;\n default:\n return rtl ? x + width - lineWidth : x;\n }\n}\n\nfunction verticalOffset(align: string, boxHeight: number, contentHeight: number): number {\n switch (align) {\n case 'middle':\n return (boxHeight - contentHeight) / 2;\n case 'bottom':\n return boxHeight - contentHeight;\n default:\n return 0;\n }\n}\n","import type { LayoutBox } from '../layout/LayoutTypes';\nimport type { TextMeasurer } from '../layout/TextMeasurer';\nimport type { PaintState } from '../rendering/PaintState';\nimport { placeLines, textMeasureRequest, type TextLinePlacement } from '../rendering/TextRenderer';\nimport type { EditableTextModel } from './EditableTextModel';\nimport {\n caretRectFor,\n offsetAtPoint,\n offsetForVerticalMove,\n selectionRects,\n type CaretRect,\n type RunMeasure\n} from './TextGeometry';\n\n/**\n * An editable's text laid out in its content box, with the geometry\n * questions input and painting ask of it.\n *\n * Built by the controller (to place the caret from a click, move it\n * vertically, and report its rectangle to the shell) and by both\n * renderers (to draw the selection, the composition underline and the\n * caret), from the same paint state and measurer the layout engine\n * sized the node with — so all of them see the same lines.\n *\n * Coordinates are those of `box`: callers pass the content box in\n * whatever space they work in (node-local for input, the parent's\n * content space for paint).\n */\nexport class EditableLayout {\n /** The text's lines; always at least one, so an empty field has a caret line. */\n readonly lines: readonly TextLinePlacement[];\n /** The placeholder's lines while the text is empty and one is set. */\n readonly placeholderLines: readonly TextLinePlacement[];\n readonly measure: RunMeasure;\n readonly rtl: boolean;\n\n constructor(\n readonly model: EditableTextModel,\n readonly box: LayoutBox,\n state: PaintState,\n measurer: TextMeasurer\n ) {\n const request = textMeasureRequest(model.text, state, box);\n // An editable never ellipsises or clamps: every character the user\n // typed has a caret position.\n request.maxLines = undefined;\n request.overflow = 'clip';\n this.lines = placeLines(box, state, measurer.layout(request));\n this.measure = text => (text.length === 0 ? 0 : measurer.measureRunWidth(text, request));\n this.rtl = state.rtl;\n this.placeholderLines =\n model.text.length === 0 && state.placeholder !== undefined && state.placeholder.length > 0\n ? placeLines(box, state, measurer.layout({ ...request, text: state.placeholder }))\n : [];\n }\n\n caretRect(offset: number = this.model.focus): CaretRect {\n return caretRectFor(this.lines, this.model.text, offset, this.measure, this.rtl);\n }\n\n offsetAt(x: number, y: number): number {\n return offsetAtPoint(this.lines, this.model.text, x, y, this.measure, this.rtl);\n }\n\n verticalMove(offset: number, direction: -1 | 1, goalX?: number): { offset: number; x: number } | null {\n return offsetForVerticalMove(this.lines, this.model.text, offset, direction, this.measure, this.rtl, goalX);\n }\n\n /** Boxes behind the selected text. */\n selectionBoxes(): LayoutBox[] {\n return selectionRects(this.lines, this.model.text, this.model.start, this.model.end, this.measure, this.rtl);\n }\n\n /** Boxes under the text the IME is composing, for its underline. */\n compositionBoxes(): LayoutBox[] {\n const range = this.model.composition;\n if (range === null) {\n return [];\n }\n return selectionRects(this.lines, this.model.text, range.start, range.end, this.measure, this.rtl);\n }\n}\n","import type { UiKeyModifiers } from '../input/UiInputEvent';\nimport type { EditUnit } from './EditableTextModel';\n\n/** Which keyboard conventions apply: Command on a Mac, Control elsewhere. */\nexport type EditingPlatform = 'mac' | 'other';\n\n/**\n * What a key press asks an editable to do.\n *\n * `move` with unit 'vertical' is up/down a visual line and needs the\n * paragraph layout, so the model cannot do it alone; the controller\n * resolves it through `TextGeometry`.\n */\nexport type EditCommand =\n | { kind: 'move'; unit: EditUnit | 'vertical'; direction: -1 | 1; extend: boolean }\n | { kind: 'delete'; unit: EditUnit; direction: -1 | 1 }\n | { kind: 'newline' }\n | { kind: 'selectAll' }\n | { kind: 'undo' }\n | { kind: 'redo' }\n | { kind: 'insert'; text: string };\n\n/**\n * The platform the runtime is on, decided once. Available in a worker\n * too, since `navigator.userAgent` is; tests set it explicitly.\n */\nexport function detectEditingPlatform(): EditingPlatform {\n const agent = typeof navigator !== 'undefined' ? navigator.userAgent : '';\n return /Mac|iPhone|iPad|iPod/.test(agent) ? 'mac' : 'other';\n}\n\n/**\n * Maps a key press to an editing command, following the host's\n * conventions:\n *\n * Mac — Option steps by word, Command jumps to line and document\n * ends, Command+Backspace deletes to the line start.\n * Others — Control steps by word, Home/End and Control+Home/End are\n * the line and document ends.\n *\n * Shift extends every move. Enter is a newline (the controller drops\n * it in a single-line field). A printable key becomes `insert` only\n * when `textFromKeys` is set: a host with an editing proxy delivers\n * text through `beforeinput` instead, where the IME and dead keys\n * have already been resolved.\n */\nexport function commandForKey(\n key: string,\n modifiers: UiKeyModifiers,\n platform: EditingPlatform,\n textFromKeys: boolean\n): EditCommand | null {\n const mac = platform === 'mac';\n const primary = mac ? modifiers.meta : modifiers.ctrl;\n const word = mac ? modifiers.alt : modifiers.ctrl;\n const extend = modifiers.shift;\n\n switch (key) {\n case 'ArrowLeft':\n case 'ArrowRight': {\n const direction = key === 'ArrowLeft' ? -1 : 1;\n if (mac && modifiers.meta) {\n return { kind: 'move', unit: 'line', direction, extend };\n }\n return { kind: 'move', unit: word ? 'word' : 'grapheme', direction, extend };\n }\n case 'ArrowUp':\n case 'ArrowDown': {\n const direction = key === 'ArrowUp' ? -1 : 1;\n if (mac && modifiers.meta) {\n return { kind: 'move', unit: 'document', direction, extend };\n }\n return { kind: 'move', unit: 'vertical', direction, extend };\n }\n case 'Home':\n return { kind: 'move', unit: modifiers.ctrl ? 'document' : 'line', direction: -1, extend };\n case 'End':\n return { kind: 'move', unit: modifiers.ctrl ? 'document' : 'line', direction: 1, extend };\n case 'Backspace':\n if (mac && modifiers.meta) {\n return { kind: 'delete', unit: 'line', direction: -1 };\n }\n return { kind: 'delete', unit: word ? 'word' : 'grapheme', direction: -1 };\n case 'Delete':\n return { kind: 'delete', unit: word ? 'word' : 'grapheme', direction: 1 };\n case 'Enter':\n return primary ? null : { kind: 'newline' };\n }\n\n if (primary && !modifiers.alt) {\n switch (key.toLowerCase()) {\n case 'a':\n return { kind: 'selectAll' };\n case 'z':\n return modifiers.shift ? { kind: 'redo' } : { kind: 'undo' };\n case 'y':\n return mac ? null : { kind: 'redo' };\n }\n return null;\n }\n\n if (textFromKeys && isPrintable(key) && !modifiers.ctrl && !modifiers.meta) {\n return { kind: 'insert', text: key };\n }\n return null;\n}\n\n/** A key value that is the character it types: one grapheme, not a name like 'Shift'. */\nexport function isPrintable(key: string): boolean {\n if (key.length === 1) {\n return true;\n }\n if (key.length === 2) {\n const code = key.charCodeAt(0);\n return code >= 0xd800 && code <= 0xdbff;\n }\n return false;\n}\n","import { graphemeBoundaries, wordBoundaries } from '../editing/TextBoundaries';\nimport type { TextWrap } from './TextMeasurer';\n\n/**\n * Where a paragraph may break, as segments that must stay whole.\n *\n * A segment is a run of text with no break opportunity inside it and\n * none of the blanks (spaces, tabs) that separate segments: the\n * paragraph is its segments with blanks between them, and a line ends\n * at a segment's end. Blanks at a break hang, so they belong to no\n * segment; a hyphen at a break does not hang, so it ends its segment\n * and counts toward the line.\n *\n * The rules are the part of UAX #14 that Latin text meets, checked\n * against Chrome by the text conformance fixtures\n * (`textConformance/cases.ts`, the `wrap/` group):\n *\n * - a break is allowed after a blank (LB18);\n * - after a hyphen-minus, a hyphen, a figure dash or an en dash\n * (classes HY and BA), except before closing punctuation (LB13),\n * before another dash (LB21, though Chrome breaks between two\n * hyphen-minus and so does this), or between a hyphen that begins its\n * word and the digit after it, where it is a sign (LB25 as Chrome\n * applies it: \"2024-\" | \"07\" breaks, \"-5\" does not);\n * - before and after an em dash (class B2), except between two of\n * them (LB17) or after an opening bracket (LB14);\n * - after a zero-width space (LB8);\n * - after closing punctuation (LB31), except after a comma, full\n * stop, colon, semicolon or closing parenthesis when a letter or\n * digit follows (LB25, LB29, LB30); after a prefix sign only before\n * an opening bracket (\"5327+\" | \"(numero)\", as Chrome does); after a slash only before a\n * character outside ASCII, which is what Chrome does: its fast\n * path for pairs of ASCII characters keeps \"path/to\" whole, and\n * ICU, which decides every other pair, has no rule against a break\n * after a slash, so \"fantastique/\" | \"Évaluation\" breaks;\n * - never next to a quotation mark (LB19) or a no-break space,\n * non-breaking hyphen or word joiner (LB12);\n * - before or after an ideograph, kana or Hangul syllable (class ID,\n * and CJ treated as ID, which is what Chrome does outside\n * `line-break: strict`), except before closing punctuation, a\n * middle dot or leaders (LB13, LB16, LB22), after an opening bracket\n * (LB14), between a currency prefix and the ideograph after it\n * (LB23a) or between an ideograph and a percent sign (LB24);\n * - between two words of a script that writes without spaces (Thai,\n * Lao, Khmer, Myanmar; class SA), where the words are the ones\n * `Intl.Segmenter` finds, which is the browser's own dictionary and\n * therefore Chrome's (LB1 resolves SA by dictionary);\n * - before or after an emoji (classes EB and ID), whose sequences\n * (skin tones, flags, keycaps, families joined with U+200D) are one\n * grapheme cluster and so one unit;\n * - and never inside a grapheme cluster (LB9), so a base and its\n * combining marks, or a surrogate pair, are one unit.\n *\n * An ideographic space (U+3000) is a blank here: it separates segments\n * and hangs at a break, as Chrome hangs it, but it is a one-em glyph\n * between two segments on a line, which `ParagraphLayout` measures.\n *\n * A soft hyphen is not a\n * break opportunity yet: taking it means drawing a hyphen that is not in\n * the text, which is hyphenation, and the fixture that pins it says so.\n *\n * `wrap: 'char'` allows a break between any two clusters; `wrap: 'none'`\n * makes the whole paragraph one segment.\n */\nexport interface TextSegment {\n start: number;\n end: number;\n}\n\nexport function segmentParagraph(paragraph: string, wrap: TextWrap): TextSegment[] {\n const length = paragraph.length;\n if (length === 0) {\n return [];\n }\n if (wrap === 'none') {\n return [{ start: 0, end: length }];\n }\n const boundaries = clusterBoundaries(paragraph);\n const dictionary = hasComplexContext(paragraph) ? new Set(wordBoundaries(paragraph)) : null;\n const segments: TextSegment[] = [];\n let i = 0;\n while (i < boundaries.length - 1) {\n // Skip the blanks before a segment.\n while (i < boundaries.length - 1 && isBlank(paragraph.charCodeAt(boundaries[i]))) {\n i++;\n }\n if (i >= boundaries.length - 1) {\n break;\n }\n const start = boundaries[i];\n let end = boundaries[i + 1];\n i++;\n while (i < boundaries.length - 1) {\n const next = paragraph.codePointAt(boundaries[i])!;\n const previous = paragraph.codePointAt(boundaries[i - 1])!;\n const beforePrevious = i >= 2 ? paragraph.codePointAt(boundaries[i - 2]) : undefined;\n if (\n isBlank(next) ||\n wrap === 'char' ||\n breaksBetween(previous, next, beforePrevious) ||\n (dictionary !== null && dictionary.has(boundaries[i]) && isComplexContext(previous) && isComplexContext(next))\n ) {\n break;\n }\n end = boundaries[i + 1];\n i++;\n }\n segments.push({ start, end });\n }\n return segments;\n}\n\n/** Spaces, tabs and ideographic spaces separate segments and hang at a break; nothing else does. */\nexport function isBlank(code: number): boolean {\n return code === 0x20 || code === 0x09 || code === IDEOGRAPHIC_SPACE;\n}\n\nexport const IDEOGRAPHIC_SPACE = 0x3000;\n\n/**\n * Whether a line may break between two adjacent clusters that are not\n * blanks, given the code point each starts with. UAX #14's shape: a\n * break is allowed everywhere (LB31) except where a rule forbids it,\n * and the rules that keep letters, digits and their prefixes together\n * are what make a Latin word one segment. `beforePreviousCode` is the\n * cluster before `beforeCode`, or undefined at the start of a word,\n * for the one rule that looks that far back.\n */\nfunction breaksBetween(beforeCode: number, afterCode: number, beforePreviousCode?: number): boolean {\n const before = classOf(beforeCode);\n const after = classOf(afterCode);\n if (before === 'ZW') {\n return true; // LB8\n }\n if (after === 'ZW' || before === 'GL' || after === 'GL') {\n return false; // LB7, LB12\n }\n if (after === 'CL' || after === 'CP' || after === 'EX' || after === 'IS' || after === 'SY' || after === 'NS') {\n return false; // LB13, LB16\n }\n if (before === 'OP' || before === 'QU' || after === 'QU') {\n return false; // LB14, LB19\n }\n if (before === 'PR' && after === 'OP') {\n // Chrome breaks after a prefix sign before an opening bracket,\n // \"5327+\" | \"(numero)\", the one pair of ASCII symbols it breaks at\n // besides the hyphen. Found by a Commons file name; probed against\n // every other ASCII symbol, which all stay glued.\n return true;\n }\n if (beforeCode === 0x2d && afterCode === 0x2d) {\n // Two hyphen-minus in a row: Chrome breaks between them (\"0075-\" |\n // \"-010001\"), against LB21, which never breaks before a dash. Found\n // by a Wikipedia title made of double-hyphen separators.\n return true;\n }\n if (after === 'HY' || after === 'BA') {\n return false; // LB21\n }\n if (before === 'HY' || before === 'BA') {\n if (after === 'B2') {\n return false;\n }\n if (before === 'HY' && after === 'NU') {\n // LB25's HY × NU, as Chrome applies it: only a hyphen that begins\n // its word is a number's sign and sticks to it (\"-5\", and the\n // second of \"--0075\", which follows a break opportunity); one\n // inside a word is a break opportunity before digits too (\"2024-\"\n // | \"07\", \"Ägypten-\" | \"2015\"). Found by the Wikipedia titles; see\n // the wrap/hyphen fixtures.\n return beforePreviousCode !== undefined && !isBlank(beforePreviousCode) && beforePreviousCode !== 0x2d;\n }\n return true;\n }\n if (before === 'B2') {\n return after !== 'B2'; // LB17\n }\n if (after === 'B2') {\n return true;\n }\n if (before === 'SY') {\n // Chrome breaks after a slash only before a character outside\n // ASCII: its fast path for pairs of ASCII characters keeps \"path/to\"\n // whole, and ICU, which decides every other pair, has no rule\n // against a break after SY. Both fixtures say so.\n return afterCode > 0x7f;\n }\n if (before === 'IS' || before === 'CP') {\n return after !== 'AL' && after !== 'NU'; // LB29, LB25, LB30\n }\n if (before === 'CL' || before === 'EX' || before === 'NS') {\n return true; // LB31\n }\n if (before === 'ID') {\n return after !== 'PO'; // LB23a\n }\n if (after === 'ID') {\n return before !== 'PR'; // LB23a\n }\n return false; // LB23, LB24, LB25, LB28: letters, digits, prefixes and postfixes stick\n}\n\ntype BreakClass =\n | 'AL'\n | 'NU'\n | 'ID'\n | 'OP'\n | 'CL'\n | 'CP'\n | 'IS'\n | 'EX'\n | 'NS'\n | 'SY'\n | 'QU'\n | 'GL'\n | 'PR'\n | 'PO'\n | 'HY'\n | 'BA'\n | 'B2'\n | 'ZW';\n\n/** The UAX #14 class of a code point, as far as these rules tell them apart; AL for everything else. */\nfunction classOf(code: number): BreakClass {\n if (code >= 0x30 && code <= 0x39) {\n return 'NU';\n }\n switch (code) {\n case 0x2d:\n return 'HY';\n case 0x2010: // ‐\n case 0x2012: // ‒\n case 0x2013: // –\n case 0x0964: // । danda\n case 0x0965: // ॥ double danda\n return 'BA';\n case 0x2014: // —\n return 'B2';\n case 0x200b:\n return 'ZW';\n case 0xa0: // no-break space\n case 0x2011: // non-breaking hyphen\n case 0x202f: // narrow no-break space\n case 0x2060: // word joiner\n return 'GL';\n case 0x2f: // /\n return 'SY';\n case 0x2c: // ,\n case 0x2e: // .\n case 0x3a: // :\n case 0x3b: // ;\n return 'IS';\n case 0x21: // !\n case 0x3f: // ?\n case 0xff01: // !\n case 0xff1f: // ?\n return 'EX';\n case 0x29: // )\n case 0x5d: // ]\n return 'CP';\n case 0x22: // \"\n case 0x27: // '\n case 0xab: // «\n case 0xbb: // »\n case 0x2018: // ‘\n case 0x2019: // ’\n case 0x201c: // “\n case 0x201d: // ”\n return 'QU';\n case 0x2b: // +\n case 0xb1: // ±\n case 0x2212: // − minus sign\n case 0x24: // $\n case 0xa3: // £\n case 0xa5: // ¥\n case 0x20ac: // €\n case 0xff04: // $\n case 0xffe1: // £\n case 0xffe5: // ¥\n return 'PR';\n case 0x25: // %\n case 0xb0: // °\n case 0x2030: // ‰\n case 0x2103: // ℃\n case 0xff05: // %\n return 'PO';\n case 0x28: // (\n case 0x5b: // [\n case 0x7b: // {\n case 0x3008: // 〈\n case 0x300a: // 《\n case 0x300c: // 「\n case 0x300e: // 『\n case 0x3010: // 【\n case 0x3014: // 〔\n case 0x3016: // 〖\n case 0x3018: // 〘\n case 0x301a: // 〚\n case 0x301d: // 〝\n case 0xff08: // (\n case 0xff3b: // [\n case 0xff5b: // {\n case 0xff5f: // ⦅\n case 0xff62: // 「\n return 'OP';\n case 0x7d: // }\n case 0x3001: // 、\n case 0x3002: // 。\n case 0x3009: // 〉\n case 0x300b: // 》\n case 0x300d: // 」\n case 0x300f: // 』\n case 0x3011: // 】\n case 0x3015: // 〕\n case 0x3017: // 〗\n case 0x3019: // 〙\n case 0x301b: // 〛\n case 0x301e: // 〞\n case 0x301f: // 〟\n case 0xff09: // )\n case 0xff0c: // ,\n case 0xff0e: // .\n case 0xff3d: // ]\n case 0xff5d: // }\n case 0xff60: // ⦆\n case 0xff61: // 。\n case 0xff63: // 」\n case 0xff64: // 、\n return 'CL';\n case 0x2025: // ‥\n case 0x2026: // …\n case 0x301c: // 〜\n case 0x303b: // 〻\n case 0x309b: // ゛\n case 0x309c: // ゜\n case 0x309d: // ゝ\n case 0x309e: // ゞ\n case 0x30fb: // ・\n case 0x30fd: // ヽ\n case 0x30fe: // ヾ\n case 0xff1a: // :\n case 0xff1b: // ;\n case 0xff65: // ・\n return 'NS';\n default:\n return isIdeographic(code) || isEmoji(code) ? 'ID' : 'AL';\n }\n}\n\n/**\n * Emoji and the pictographic symbols that render as emoji, from the\n * miscellaneous symbols block upward. The `Extended_Pictographic`\n * property alone would also claim © ® and ™, which UAX #14 keeps as\n * letters, so the block floor excludes them.\n */\nfunction isEmoji(code: number): boolean {\n if (code >= 0x1f1e6 && code <= 0x1f1ff) {\n return true; // regional indicators: a flag is a pair, and the cluster keeps the pair\n }\n return code >= 0x2600 && EXTENDED_PICTOGRAPHIC.test(String.fromCodePoint(code));\n}\n\nconst EXTENDED_PICTOGRAPHIC = /^\\p{Extended_Pictographic}$/u;\n\n/**\n * Class ID, as a line breaker sees it: Han, kana (with CJ folded in),\n * Hangul syllables and jamo, Bopomofo, Yi, the enclosed and\n * compatibility CJK blocks, fullwidth letters and digits, and halfwidth\n * katakana. Punctuation in the same blocks is handled above.\n */\nexport function isIdeographic(code: number): boolean {\n return (\n (code >= 0x1100 && code <= 0x11ff) || // Hangul Jamo\n (code >= 0x2e80 && code <= 0x2fff) || // CJK and Kangxi radicals\n (code >= 0x3003 && code <= 0x3007) || // 〃々〆〇 and the dictionary mark\n (code >= 0x3012 && code <= 0x3013) || // 〒〓\n (code >= 0x3020 && code <= 0x303a) || // ideographic telegraph symbols, iteration marks\n (code >= 0x3041 && code <= 0x309a) || // Hiragana\n (code >= 0x309f && code <= 0x30fa) || // ゟ and Katakana\n code === 0x30fc || // ー\n code === 0x30ff || // ヿ\n (code >= 0x3100 && code <= 0x31ff) || // Bopomofo, Hangul compatibility jamo, Kanbun, Katakana phonetic extensions\n (code >= 0x3200 && code <= 0x4dbf) || // enclosed CJK, CJK compatibility, Extension A\n (code >= 0x4e00 && code <= 0x9fff) || // CJK Unified Ideographs\n (code >= 0xa000 && code <= 0xa4cf) || // Yi\n (code >= 0xa960 && code <= 0xa97f) || // Hangul Jamo Extended-A\n (code >= 0xac00 && code <= 0xd7ff) || // Hangul syllables and Jamo Extended-B\n (code >= 0xf900 && code <= 0xfaff) || // CJK Compatibility Ideographs\n (code >= 0xfe30 && code <= 0xfe4f) || // CJK Compatibility Forms\n (code >= 0xff10 && code <= 0xff19) || // fullwidth digits\n (code >= 0xff21 && code <= 0xff3a) || // fullwidth Latin capitals\n (code >= 0xff41 && code <= 0xff5a) || // fullwidth Latin small letters\n (code >= 0xff66 && code <= 0xff9f) || // halfwidth Katakana\n (code >= 0xffe0 && code <= 0xffe6) || // fullwidth signs\n (code >= 0x20000 && code <= 0x3134f) // Extensions B to G\n );\n}\n\n/** Class SA: scripts whose words are found by dictionary, not by spaces. */\nfunction isComplexContext(code: number): boolean {\n return (\n (code >= 0x0e00 && code <= 0x0e7f) || // Thai\n (code >= 0x0e80 && code <= 0x0eff) || // Lao\n (code >= 0x1000 && code <= 0x109f) || // Myanmar\n (code >= 0x1780 && code <= 0x17ff) // Khmer\n );\n}\n\nfunction hasComplexContext(paragraph: string): boolean {\n for (let i = 0; i < paragraph.length; i++) {\n if (isComplexContext(paragraph.charCodeAt(i))) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * Grapheme cluster boundaries, with a fast path for ASCII, where every\n * code unit is a cluster and the segmenter would only cost time.\n */\nfunction clusterBoundaries(paragraph: string): number[] {\n if (isAscii(paragraph)) {\n // A counted loop rather than `Array.from` with a mapper: the\n // mapper form goes through the generic iteration protocol and was\n // a tenth of a resize sweep's whole profile,\n // because every paragraph is segmented again at every width.\n const boundaries: number[] = [];\n for (let i = 0; i <= paragraph.length; i++) {\n boundaries.push(i);\n }\n return boundaries;\n }\n return graphemeBoundaries(paragraph);\n}\n\nfunction isAscii(text: string): boolean {\n for (let i = 0; i < text.length; i++) {\n if (text.charCodeAt(i) > 0x7f) {\n return false;\n }\n }\n return true;\n}\n","import type {\n FontMetrics,\n ParagraphLayout,\n SpannedRuns,\n TextLine,\n TextLineRun,\n TextMeasureRequest,\n TextRunMeasurer,\n TextWrap\n} from './TextMeasurer';\nimport { spannedRunsFor } from './TextMeasurer';\nimport { IDEOGRAPHIC_SPACE, segmentParagraph } from './LineBreaks';\nimport type { TextSegment } from './LineBreaks';\n\nexport { DEFAULT_LINE_HEIGHT_FACTOR } from '../properties/UiTextFont';\nimport { DEFAULT_LINE_HEIGHT_FACTOR } from '../properties/UiTextFont';\nexport const ELLIPSIS = '…';\n\n/**\n * The width of a stretch of the paragraph.\n *\n * `segment` is always `text.slice(start, end)`. The offsets are what a\n * paragraph with runs measures by, and a paragraph without them\n * ignores; the string is passed as well because the platform measures\n * a string and slicing it twice would be waste.\n */\ntype Measure = (segment: string, start: number, end: number) => number;\n\n/**\n * How far past the available width a line may reach and still fit.\n *\n * Chrome lays text out in 1/64 px units and snaps each advance to one,\n * so five 16 px ideographs fit an 80 px line exactly. `measureText`\n * answers in floats with the shaper's fixed-point noise in them\n * (16.00003 px per ideograph in one font), and five of those would not\n * fit without this. One layout unit of slack is what Chrome itself has.\n */\nconst FIT_EPSILON = 1 / 64;\n\n/**\n * Breaks a text into lines and sizes the paragraph.\n *\n * This is the one line-breaking algorithm in the runtime. Measurers\n * supply run widths and font metrics; layout, both renderers and the\n * tests all get their lines from here, so a line can never wrap in\n * one place and not another.\n *\n * Semantics follow CSS where Gesso borrows its names, with\n * `white-space: pre-wrap` as the model for wrapping text: runs of\n * spaces are preserved, `\\n` always breaks, and spaces at a break hang.\n *\n * wrap 'word' — break after blanks and at the opportunities\n * `LineBreaks.ts` knows (hyphens, dashes, zero-width\n * spaces); a segment wider than the available width\n * overflows on its own line.\n * wrap 'char' — `word-break: break-all`: break between any two\n * grapheme clusters.\n * wrap 'none' — `white-space: nowrap`: only '\\n' breaks.\n *\n * Blanks at a break hang: they neither count toward the line width nor\n * start the next line. Blanks at the start of a paragraph are kept, as\n * pre-wrap keeps them, so an indented line stays indented. Widths are\n * accumulated per segment so a paragraph re-laid out at a new width\n * asks the platform only for segments it has not seen; the final width\n * of each line is measured once as a whole.\n *\n * The paragraph width is CSS fit-content: the available width when\n * wrapping occurred, the natural width when it did not, and never\n * narrower than the widest segment. When a segment is wider than the\n * available width the paragraph grows to it, and every line wraps\n * against that grown width rather than the one asked for, because that\n * is the box the lines will be painted in.\n *\n * The first baseline sits half the leading below the line top, plus the\n * ascent, with the half-leading floored to a whole pixel. That floor is\n * what Chrome does (its line layout floors the half-leading before\n * adding it to the ascent), and the text conformance fixtures showed\n * every baseline a fraction of a pixel below Chrome's without it. It is\n * also why DOM text is crisp: with whole-pixel font metrics and a\n * whole-pixel line height, the baseline lands on a pixel boundary.\n *\n * **Runs.** `request.spans` names stretches of the same text with\n * fonts of their own, and everything above changes in one way: a width\n * is asked for by offsets and answered run by run. The text is one\n * string either way, so a line's `start`, a selection, a find match\n * and a caret mean what they always meant, and the algorithm here is\n * the algorithm it was. Each line additionally carries `runs`, the\n * line cut at the run boundaries with each piece's x, measured while\n * the line's own width is measured, so that painting a paragraph with\n * runs asks the platform for nothing.\n */\nexport function layoutParagraph(request: TextMeasureRequest, runs: TextRunMeasurer): ParagraphLayout {\n const fontSize = request.fontSize;\n const requestedLineHeight =\n request.lineHeight !== undefined && request.lineHeight > 0\n ? request.lineHeight\n : fontSize * DEFAULT_LINE_HEIGHT_FACTOR;\n const spanned = fontSize > 0 ? spannedRunsFor(request, runs) : undefined;\n const box = lineBox(request, runs, spanned, requestedLineHeight, fontSize > 0);\n const lineHeight = box.height;\n const wrap: TextWrap = request.wrap ?? 'word';\n const maxWidth = request.maxWidth !== undefined && request.maxWidth >= 0 ? request.maxWidth : Infinity;\n const text = request.text;\n const measure: Measure =\n spanned === undefined\n ? segment => (segment.length === 0 ? 0 : runs.measureRunWidth(segment, request))\n : (_segment, start, end) => spanned.width(text, start, end);\n\n // Split into paragraphs and segment each, so the widest segment is\n // known before any line is broken: it is the floor of the box, and\n // the width the lines wrap against.\n const paragraphs: { start: number; text: string; segments: TextSegment[] }[] = [];\n let maxContentWidth = 0;\n let minContentWidth = 0;\n let paragraphStart = 0;\n for (;;) {\n let paragraphEnd = text.indexOf('\\n', paragraphStart);\n if (paragraphEnd < 0) {\n paragraphEnd = text.length;\n }\n const paragraph = text.slice(paragraphStart, paragraphEnd);\n const segments = segmentParagraph(paragraph, wrap);\n paragraphs.push({ start: paragraphStart, text: paragraph, segments });\n maxContentWidth = Math.max(maxContentWidth, measure(paragraph, paragraphStart, paragraphEnd));\n for (const segment of segments) {\n minContentWidth = Math.max(\n minContentWidth,\n measure(\n paragraph.slice(segment.start, segment.end),\n paragraphStart + segment.start,\n paragraphStart + segment.end\n )\n );\n }\n if (paragraphEnd >= text.length) {\n break;\n }\n paragraphStart = paragraphEnd + 1;\n }\n const available = Math.max(maxWidth, minContentWidth);\n\n const lines: TextLine[] = [];\n for (const paragraph of paragraphs) {\n const before = lines.length;\n if (wrap === 'none' || !isFinite(available)) {\n pushLine(text, paragraph.text, paragraph.start, 0, paragraph.text.length, measure, spanned, lines);\n } else {\n breakGreedy(text, paragraph.text, paragraph.start, paragraph.segments, available, measure, spanned, lines);\n }\n if (lines.length === before) {\n // A blank or all-space paragraph still occupies a line.\n lines.push({ start: paragraph.start, end: paragraph.start, text: '', width: 0 });\n }\n }\n\n if (request.maxLines !== undefined && request.maxLines >= 1 && lines.length > request.maxLines) {\n lines.length = request.maxLines;\n if (request.overflow === 'ellipsis') {\n lines[lines.length - 1] = ellipsize(text, lines[lines.length - 1], maxWidth, measure, spanned);\n }\n } else if (request.overflow === 'ellipsis' && isFinite(maxWidth)) {\n // A line that does not fit — no wrapping, or a segment wider than\n // the box — is ellipsised in place.\n for (let i = 0; i < lines.length; i++) {\n if (lines[i].width > maxWidth) {\n lines[i] = ellipsize(text, lines[i], maxWidth, measure, spanned);\n }\n }\n }\n\n return {\n lines,\n width: Math.max(minContentWidth, Math.min(maxContentWidth, maxWidth)),\n height: lines.length * lineHeight,\n lineHeight,\n ascent: box.ascent,\n descent: box.descent,\n firstBaseline: box.baseline,\n minContentWidth,\n maxContentWidth\n };\n}\n\n/** Metrics for measurers that cannot ask the platform for them. */\nexport function proportionalFontMetrics(fontSize: number, ascentFactor = 0.8, descentFactor = 0.2): FontMetrics {\n return { ascent: fontSize * ascentFactor, descent: fontSize * descentFactor };\n}\n\n// ---------------------------------------------------------------------------\n// The line box\n// ---------------------------------------------------------------------------\n\ninterface LineBox {\n ascent: number;\n descent: number;\n baseline: number;\n height: number;\n}\n\n/**\n * Where the baseline sits in a line and how tall the line is.\n *\n * One font is the case CSS makes simple and the one this has always\n * answered: the baseline is the ascent plus the floored half-leading,\n * and the line is exactly the requested line height.\n *\n * Several fonts is the case CSS answers by stacking inline boxes. A\n * run inherits the paragraph's line height as a length, so its own box\n * is that tall whatever its font size, and it is placed with its\n * baseline `ascent + halfLeading` below its top. The line's baseline is\n * therefore the largest of those distances, and the line's height is\n * that plus the largest distance below. With one font the two rules\n * are the same arithmetic, which is why this is not two code paths;\n * with one font it is also not run at all past the first entry.\n *\n * What it does not do is size each line separately. Every line of a\n * paragraph gets the tallest line's box, because `height` is\n * `lines × lineHeight` here and both renderers step by that. A run\n * much larger than the paragraph therefore makes every line as tall as\n * the one it is on, which Chrome does not; the fixture that pins it\n * says so.\n */\nfunction lineBox(\n request: TextMeasureRequest,\n runs: TextRunMeasurer,\n spanned: SpannedRuns | undefined,\n lineHeight: number,\n hasFont: boolean\n): LineBox {\n const metrics = hasFont ? runs.fontMetrics(request) : { ascent: 0, descent: 0 };\n if (spanned === undefined) {\n return {\n ascent: metrics.ascent,\n descent: metrics.descent,\n baseline: metrics.ascent + halfLeading(lineHeight, metrics),\n height: lineHeight\n };\n }\n let ascent = metrics.ascent;\n let descent = metrics.descent;\n let above = metrics.ascent + halfLeading(lineHeight, metrics);\n let below = lineHeight - above;\n for (const span of spanned.spans) {\n const runMetrics = runs.fontMetrics(spanned.requestAt(span.start));\n const top = halfLeading(lineHeight, runMetrics);\n ascent = Math.max(ascent, runMetrics.ascent);\n descent = Math.max(descent, runMetrics.descent);\n above = Math.max(above, runMetrics.ascent + top);\n below = Math.max(below, lineHeight - runMetrics.ascent - top);\n }\n return { ascent, descent, baseline: above, height: above + below };\n}\n\n/** The space above the ascent, floored as Chrome's line layout floors it. */\nfunction halfLeading(lineHeight: number, metrics: FontMetrics): number {\n return Math.floor((lineHeight - (metrics.ascent + metrics.descent)) / 2);\n}\n\n// ---------------------------------------------------------------------------\n// Breaking\n// ---------------------------------------------------------------------------\n\n/**\n * Greedy first-fit: append segments while they fit, otherwise start a\n * new line with the segment. The first segment on a line always goes\n * on it, so an oversized segment overflows rather than vanishing.\n *\n * Blanks between two segments on one line are counted at their own\n * widths: a space or a tab as one space (a tab stop is a position the\n * renderer does not know; the fixture that pins it says so), an\n * ideographic space as itself. Blanks before the first segment of the\n * paragraph are part of its first line; blanks before the first segment\n * of any later line hang off the line before, as pre-wrap hangs them.\n */\nfunction breakGreedy(\n source: string,\n paragraph: string,\n offset: number,\n segments: readonly TextSegment[],\n available: number,\n measure: Measure,\n spanned: SpannedRuns | undefined,\n out: TextLine[]\n): void {\n // One space is one measurement for a paragraph in one font, and one\n // per blank for a paragraph whose runs may space differently.\n const spaceWidth = spanned === undefined ? measure(' ', offset, offset) : 0;\n const blanks = (from: number, to: number): number => {\n let width = 0;\n for (let i = from; i < to; i++) {\n const blank = paragraph.charCodeAt(i) === IDEOGRAPHIC_SPACE ? ' ' : ' ';\n if (spanned !== undefined) {\n width += spanned.widthOf(blank, offset + i);\n } else if (blank === ' ') {\n width += spaceWidth;\n } else {\n width += measure(blank, offset + i, offset + i);\n }\n }\n return width;\n };\n let lineStart = -1;\n let lineEnd = -1;\n let lineWidth = 0;\n let firstLine = true;\n\n for (const segment of segments) {\n const segmentWidth = measure(\n paragraph.slice(segment.start, segment.end),\n offset + segment.start,\n offset + segment.end\n );\n if (lineStart < 0) {\n lineStart = firstLine ? 0 : segment.start;\n lineEnd = segment.end;\n lineWidth = blanks(lineStart, segment.start) + segmentWidth;\n } else {\n const candidate = lineWidth + blanks(lineEnd, segment.start) + segmentWidth;\n if (candidate <= available + FIT_EPSILON) {\n lineEnd = segment.end;\n lineWidth = candidate;\n } else {\n pushLine(source, paragraph, offset, lineStart, lineEnd, measure, spanned, out);\n firstLine = false;\n lineStart = segment.start;\n lineEnd = segment.end;\n lineWidth = segmentWidth;\n }\n }\n }\n\n if (lineStart >= 0) {\n pushLine(source, paragraph, offset, lineStart, lineEnd, measure, spanned, out);\n }\n}\n\nfunction pushLine(\n source: string,\n paragraph: string,\n offset: number,\n start: number,\n end: number,\n measure: Measure,\n spanned: SpannedRuns | undefined,\n out: TextLine[]\n): void {\n const text = paragraph.slice(start, end);\n const from = offset + start;\n const to = offset + end;\n if (spanned === undefined) {\n out.push({ start: from, end: to, text, width: measure(text, from, to) });\n return;\n }\n // Cutting the line measures each piece, and their widths sum to the\n // line's, so the line is not measured a second time as a whole.\n const runs = spanned.cut(source, from, to, 0);\n let width = 0;\n for (const run of runs) {\n width += run.width;\n }\n out.push({ start: from, end: to, text, width, runs });\n}\n\n/**\n * Shortens a line until it and an ellipsis fit the available width.\n * Trailing spaces are dropped before the ellipsis is appended.\n *\n * The ellipsis belongs to the run the text it follows ends in, so a\n * clamped line of bold text ends in a bold ellipsis.\n */\nfunction ellipsize(\n source: string,\n line: TextLine,\n maxWidth: number,\n measure: Measure,\n spanned: SpannedRuns | undefined\n): TextLine {\n if (!isFinite(maxWidth)) {\n return line;\n }\n let text = line.text;\n for (;;) {\n const trimmed = text.replace(/\\s+$/, '');\n const candidate = trimmed + ELLIPSIS;\n const end = line.start + trimmed.length;\n const width =\n spanned === undefined\n ? measure(candidate, line.start, end)\n : measure(trimmed, line.start, end) + spanned.widthOf(ELLIPSIS, Math.max(line.start, end - 1));\n if (width <= maxWidth || trimmed.length === 0) {\n return {\n start: line.start,\n end,\n text: candidate,\n width,\n runs: spanned === undefined ? undefined : ellipsisRuns(source, spanned, line.start, end, width)\n };\n }\n text = trimmed.slice(0, previousCharacterStart(trimmed, trimmed.length));\n }\n}\n\n/** The clamped line's runs, with the ellipsis on the end of the last. */\nfunction ellipsisRuns(\n source: string,\n spanned: SpannedRuns,\n start: number,\n end: number,\n width: number\n): readonly TextLineRun[] {\n const runs = spanned.cut(source, start, end, 0);\n if (runs.length === 0) {\n return [{ span: -1, start, end, text: ELLIPSIS, x: 0, width }];\n }\n const last = runs[runs.length - 1];\n runs[runs.length - 1] = {\n span: last.span,\n start: last.start,\n end: last.end,\n text: last.text + ELLIPSIS,\n x: last.x,\n width: width - last.x\n };\n return runs;\n}\n\nfunction previousCharacterStart(text: string, index: number): number {\n const code = text.charCodeAt(index - 1);\n if (code >= 0xdc00 && code <= 0xdfff && index - 2 >= 0) {\n return index - 2;\n }\n return index - 1;\n}\n","import type { Size } from './LayoutTypes';\nimport { layoutParagraph, proportionalFontMetrics } from './ParagraphLayout';\n\nexport type TextWrap = 'word' | 'char' | 'none';\nexport type TextOverflow = 'clip' | 'ellipsis';\n\n/**\n * The font a piece of text is measured in.\n *\n * Structural rather than imported so that layout keeps depending on\n * nothing above it; a `UiResolvedTextSpan` is one of these plus the\n * fields that only paint reads.\n */\nexport interface TextRunStyle {\n fontFamily?: string;\n fontWeight?: string | number;\n fontSize?: number;\n fontStyle?: string;\n fontStretch?: string;\n fontVariant?: string;\n fontKerning?: string;\n letterSpacing?: number;\n}\n\n/** A run of the paragraph with a font of its own, as offsets into the text. */\nexport interface TextRunSpan extends TextRunStyle {\n readonly start: number;\n readonly end: number;\n}\n\nexport interface TextMeasureRequest {\n text: string;\n fontSize: number;\n /** Available width. Wrapping and fit-content sizing happen against it. */\n maxWidth?: number;\n /**\n * Font family for platforms that can shape text.\n *\n * Deterministic measurers may ignore every style field; they\n * are hints for platform-backed implementations only.\n */\n fontFamily?: string;\n fontWeight?: string | number;\n lineHeight?: number;\n letterSpacing?: number;\n fontStyle?: string;\n fontStretch?: string;\n fontVariant?: string;\n fontKerning?: string;\n /** Default 'word'. */\n wrap?: TextWrap;\n /** Keep at most this many lines. */\n maxLines?: number;\n /** What happens to a line that does not fit. Default 'clip'. */\n overflow?: TextOverflow;\n /**\n * Runs of `text` with a font of their own, in order and not\n * overlapping. Text outside every run is measured in the request's\n * own font.\n *\n * Only the fields that change a width are here. A run that differs\n * from its neighbours only in colour, background or underline is not\n * in this list at all, so it costs a paint and never a re-layout.\n */\n spans?: readonly TextRunSpan[];\n}\n\n/** One run of a line: where it sits in the line and which span it came from. */\nexport interface TextLineRun {\n /** Index into the request's `spans`, or -1 for text outside every run. */\n span: number;\n /** Offsets into the source text. */\n start: number;\n end: number;\n text: string;\n /** Distance from the line's left edge to this run's left edge. */\n x: number;\n width: number;\n}\n\n/** One laid-out line. `text` is what gets drawn and may end in an ellipsis. */\nexport interface TextLine {\n /** Offsets into the source text; hanging spaces and the ellipsis are outside them. */\n start: number;\n end: number;\n text: string;\n width: number;\n /**\n * The line cut at its runs, present only for a paragraph that has\n * spans.\n *\n * Measured once, here, where the line's own width is measured. That\n * is what keeps a spanned paragraph as cheap to paint as a plain\n * one: a renderer walks these and asks the platform for nothing.\n */\n runs?: readonly TextLineRun[];\n}\n\nexport interface FontMetrics {\n /** Distance from the alphabetic baseline to the top of the glyph box. */\n ascent: number;\n /** Distance from the alphabetic baseline to the bottom of the glyph box. */\n descent: number;\n}\n\n/**\n * A measured paragraph: everything layout, alignment and painting need.\n *\n * `width` is fit-content, `height` is lines × lineHeight, and\n * `firstBaseline` is the distance from the paragraph top to the first\n * line's alphabetic baseline (half-leading plus ascent).\n */\nexport interface ParagraphLayout {\n lines: TextLine[];\n width: number;\n height: number;\n lineHeight: number;\n ascent: number;\n descent: number;\n firstBaseline: number;\n /** Widest unbreakable segment under the requested wrap mode. */\n minContentWidth: number;\n /** Width with no wrapping at all. */\n maxContentWidth: number;\n}\n\n/**\n * Abstraction between layout and text platforms.\n *\n * Layout never measures text itself; a platform layer\n * (Canvas2D, WebGPU, tests) supplies an implementation.\n */\nexport interface TextMeasurer {\n measure(request: TextMeasureRequest): Size;\n layout(request: TextMeasureRequest): ParagraphLayout;\n /**\n * The advance width of one run in the request's font. Caret and\n * selection geometry is built from prefix widths, so it has to come\n * from the same source as the line widths.\n */\n measureRunWidth(text: string, request: TextMeasureRequest): number;\n /**\n * Forgets every cached answer. Called when what a font string means\n * has changed under the measurer: a declared face finished loading,\n * so widths measured with its fallback are wrong now. Measurers with\n * nothing cached need not implement it.\n */\n invalidate?(): void;\n}\n\n/**\n * The primitive a platform has to provide: the advance width of one\n * run of text, and the font's vertical metrics. Everything above it\n * is shared (see ParagraphLayout.ts).\n */\nexport interface TextRunMeasurer {\n measureRunWidth(text: string, request: TextMeasureRequest): number;\n fontMetrics(request: TextMeasureRequest): FontMetrics;\n}\n\n/**\n * The widths of a paragraph whose runs have fonts of their own.\n *\n * Everything above it — line breaking, hanging blanks, the ellipsis,\n * caret and selection geometry — asks for the width of a stretch of\n * the text by its offsets rather than by its characters, and this\n * splits that stretch at the run boundaries and measures each piece in\n * its own font. That is the whole of what a span costs: the paragraph\n * algorithm is unchanged, and a paragraph with no spans never builds\n * one of these at all.\n */\nexport interface SpannedRuns {\n /** The runs, as the request gave them. */\n readonly spans: readonly TextRunSpan[];\n /** Index of the run covering `offset`, or -1 where no run does. */\n indexAt(offset: number): number;\n /** The request an offset is measured with: its run's, or the paragraph's. */\n requestAt(offset: number): TextMeasureRequest;\n /** Width of `text.slice(start, end)`, measured run by run. */\n width(text: string, start: number, end: number): number;\n /**\n * Width of a string that is not in the text, in the font of the run\n * covering `offset`: the ellipsis, and the space a tab is counted\n * as.\n */\n widthOf(run: string, offset: number): number;\n /** `text.slice(start, end)` cut at the run boundaries, each piece placed from `x`. */\n cut(text: string, start: number, end: number, x: number): TextLineRun[];\n}\n\n/**\n * Builds the run widths for a request, or undefined when it has no\n * runs.\n *\n * One request object per run, built once: the paragraph cache means a\n * paragraph is laid out once per distinct request, so this runs once\n * per paragraph rather than once per frame.\n */\nexport function spannedRunsFor(\n request: TextMeasureRequest,\n runs: Pick<TextRunMeasurer, 'measureRunWidth'>\n): SpannedRuns | undefined {\n const spans = request.spans;\n if (spans === undefined || spans.length === 0) {\n return undefined;\n }\n const requests: TextMeasureRequest[] = spans.map(span => ({\n ...request,\n spans: undefined,\n fontFamily: span.fontFamily ?? request.fontFamily,\n fontWeight: span.fontWeight ?? request.fontWeight,\n fontSize: span.fontSize ?? request.fontSize,\n fontStyle: span.fontStyle ?? request.fontStyle,\n fontStretch: span.fontStretch ?? request.fontStretch,\n fontVariant: span.fontVariant ?? request.fontVariant,\n fontKerning: span.fontKerning ?? request.fontKerning,\n letterSpacing: span.letterSpacing ?? request.letterSpacing\n }));\n const base: TextMeasureRequest = { ...request, spans: undefined };\n\n const indexAt = (offset: number): number => {\n // Runs are in order and do not overlap, so a scan stops at the\n // first one that has not started yet. Paragraphs have runs in the\n // tens; a binary search would cost more than it saved.\n for (let i = 0; i < spans.length; i++) {\n if (offset < spans[i].start) {\n return -1;\n }\n if (offset < spans[i].end) {\n return i;\n }\n }\n return -1;\n };\n const requestAt = (offset: number): TextMeasureRequest => {\n const index = indexAt(offset);\n return index < 0 ? base : requests[index];\n };\n const measure = (text: string, from: number, to: number, index: number): number => {\n if (to <= from) {\n return 0;\n }\n return runs.measureRunWidth(text.slice(from, to), index < 0 ? base : requests[index]);\n };\n const each = (start: number, end: number, piece: (from: number, to: number, index: number) => void): void => {\n let from = start;\n while (from < end) {\n const index = indexAt(from);\n // The stretch runs to the end of this run, or up to where the\n // next one starts when this offset is in no run at all.\n let to = end;\n if (index >= 0) {\n to = Math.min(end, spans[index].end);\n } else {\n for (const span of spans) {\n if (span.start > from) {\n to = Math.min(end, span.start);\n break;\n }\n }\n }\n piece(from, to, index);\n from = to;\n }\n };\n\n return {\n spans,\n indexAt,\n requestAt,\n width(text, start, end) {\n let width = 0;\n each(start, end, (from, to, index) => {\n width += measure(text, from, to, index);\n });\n return width;\n },\n widthOf(run, offset) {\n return run.length === 0 ? 0 : runs.measureRunWidth(run, requestAt(offset));\n },\n cut(text, start, end, x) {\n const out: TextLineRun[] = [];\n let pen = x;\n each(start, end, (from, to, index) => {\n const width = measure(text, from, to, index);\n out.push({ span: index, start: from, end: to, text: text.slice(from, to), x: pen, width });\n pen += width;\n });\n return out;\n }\n };\n}\n\n/** Paragraphs remembered before the least recently asked for is forgotten. */\nconst PARAGRAPH_CACHE_ENTRIES = 4096;\n\n/**\n * Base class for measurers: implement the two primitives and the\n * paragraph algorithm does the rest.\n *\n * **Every paragraph is laid out once per distinct request.** The same\n * request arrives several times a frame and on every frame after: the\n * layout engine asks when it measures the node, and both renderers ask\n * again when they paint it, because a `PaintState` and a box are all a\n * renderer holds. Without a cache a repaint is a line break, and a\n * transition that repaints the whole screen for half a second breaks\n * every paragraph on it sixty times a second. Measured on Sluice's\n * Bluesky feed opening a post: 30 to 50 ms a frame in `segmentParagraph`,\n * `measureRunWidth` and `applySpacing`, against under 13 ms on the same\n * click over short Wikipedia titles. The cache is keyed by every field\n * of the request, so a paragraph that changed in any way is laid out\n * again, and it is least-recently-used with a cap, so a feed that\n * mounts forty new rows a second does not grow it without bound.\n *\n * The result is shared between callers and must not be mutated.\n */\nexport abstract class ParagraphTextMeasurer implements TextMeasurer, TextRunMeasurer {\n private readonly paragraphs = new Map<string, ParagraphLayout>();\n\n abstract measureRunWidth(text: string, request: TextMeasureRequest): number;\n abstract fontMetrics(request: TextMeasureRequest): FontMetrics;\n\n layout(request: TextMeasureRequest): ParagraphLayout {\n const key = paragraphKey(request);\n const cached = this.paragraphs.get(key);\n if (cached !== undefined) {\n // Re-inserted so the map's order is recency, which is what the\n // eviction below reads.\n this.paragraphs.delete(key);\n this.paragraphs.set(key, cached);\n return cached;\n }\n const paragraph = layoutParagraph(request, this);\n if (this.paragraphs.size >= PARAGRAPH_CACHE_ENTRIES) {\n const oldest = this.paragraphs.keys().next().value;\n if (oldest !== undefined) {\n this.paragraphs.delete(oldest);\n }\n }\n this.paragraphs.set(key, paragraph);\n return paragraph;\n }\n\n measure(request: TextMeasureRequest): Size {\n const paragraph = this.layout(request);\n return { width: paragraph.width, height: paragraph.height };\n }\n\n /** How many paragraphs are remembered right now; for specs. */\n get cachedParagraphs(): number {\n return this.paragraphs.size;\n }\n\n /**\n * Forgets every laid-out paragraph. A subclass that caches its own\n * primitives overrides this and calls it, so a font that finished\n * loading invalidates the lines as well as the widths they were\n * built from.\n */\n invalidate(): void {\n this.paragraphs.clear();\n }\n}\n\n/** Every field of a request, in a fixed order; two requests that lay out alike share a key. */\nfunction paragraphKey(request: TextMeasureRequest): string {\n return `${request.fontSize}\\0${request.maxWidth ?? ''}\\0${request.fontFamily ?? ''}\\0${request.fontWeight ?? ''}\\0${\n request.lineHeight ?? ''\n }\\0${request.letterSpacing ?? ''}\\0${request.wrap ?? ''}\\0${request.maxLines ?? ''}\\0${request.overflow ?? ''}\\0${\n request.fontStyle ?? ''\n }\\0${request.fontStretch ?? ''}\\0${request.fontVariant ?? ''}\\0${request.fontKerning ?? ''}\\0${spansKey(\n request.spans\n )}\\0${request.text}`;\n}\n\n/**\n * The runs' part of a paragraph key, remembered by the identity of the\n * array.\n *\n * Every field of every run would otherwise be spelt out on every\n * paint of every spanned paragraph on screen, which is the one way\n * spans could quietly undo the paragraph cache. A span array held still\n * by a bound cell is spelt out once and looked up thereafter.\n */\nconst spanKeys = new WeakMap<readonly TextRunSpan[], string>();\n\nfunction spansKey(spans: readonly TextRunSpan[] | undefined): string {\n if (spans === undefined || spans.length === 0) {\n return '';\n }\n const cached = spanKeys.get(spans);\n if (cached !== undefined) {\n return cached;\n }\n let key = '';\n for (const span of spans) {\n key += `${span.start}:${span.end}:${span.fontFamily ?? ''}:${span.fontWeight ?? ''}:${span.fontSize ?? ''}:${\n span.fontStyle ?? ''\n }:${span.fontStretch ?? ''}:${span.fontVariant ?? ''}:${span.fontKerning ?? ''}:${span.letterSpacing ?? ''};`;\n }\n spanKeys.set(spans, key);\n return key;\n}\n\nexport interface FixedMetricsOptions {\n /** Advance of every glyph as a fraction of the font size. Default 0.6. */\n glyphWidth?: number;\n /** Ascent as a fraction of the font size. Default 0.8. */\n ascent?: number;\n /** Descent as a fraction of the font size. Default 0.2. */\n descent?: number;\n}\n\n/**\n * Deterministic measurer: every glyph is `glyphWidth` em wide, the\n * font is `ascent + descent` em tall, and the default line is 1.2em.\n *\n * Intended for tests and headless environments. With `glyphWidth: 1`\n * it reproduces the Ahem test font exactly, which is how the layout\n * conformance fixtures compare real wrapping text against Chrome.\n */\nexport class CharacterCountTextMeasurer extends ParagraphTextMeasurer {\n private readonly glyphWidth: number;\n private readonly ascentFactor: number;\n private readonly descentFactor: number;\n\n constructor(options: FixedMetricsOptions = {}) {\n super();\n this.glyphWidth = options.glyphWidth ?? 0.6;\n this.ascentFactor = options.ascent ?? 0.8;\n this.descentFactor = options.descent ?? 0.2;\n }\n\n measureRunWidth(text: string, request: TextMeasureRequest): number {\n let glyphs = 0;\n for (const _character of text) {\n glyphs++;\n }\n return glyphs * request.fontSize * this.glyphWidth;\n }\n\n fontMetrics(request: TextMeasureRequest): FontMetrics {\n return proportionalFontMetrics(request.fontSize, this.ascentFactor, this.descentFactor);\n }\n}\n","import type { LayoutBox } from '../layout/LayoutTypes';\nimport type { TextMeasurer } from '../layout/TextMeasurer';\nimport { spannedRunsFor } from '../layout/TextMeasurer';\nimport type { PaintState } from '../rendering/PaintState';\nimport { placeLines, textMeasureRequest, type TextLinePlacement } from '../rendering/TextRenderer';\nimport { offsetAtPoint, selectionRects, type RunMeasure } from '../editing/TextGeometry';\nimport { wordRangeAt } from '../editing/TextBoundaries';\n\n/**\n * A laid-out paragraph, ready to answer the two questions a selection\n * asks of it: which offset is under a point, and which boxes cover a\n * range.\n *\n * This is `EditableLayout` for text nobody types into, and the\n * difference is the reason it is its own thing: an editable never\n * clamps, so every character it holds has a caret position, while a\n * `Text` node may be capped by `maxLines` and ellipsised. Only what is\n * drawn can be selected, so `text` here is the source truncated to the\n * last drawn line — which keeps the geometry helpers, written for the\n * un-clamped case, correct without a clamp-aware branch in each of\n * them.\n */\nexport interface ParagraphGeometry {\n readonly lines: readonly TextLinePlacement[];\n /** The source text, truncated to what the lines actually draw. */\n readonly text: string;\n /** Offset the drawn text starts at; always 0 today, kept for symmetry with `end`. */\n readonly start: number;\n /** Offset the drawn text ends at: past it there is nothing to select. */\n readonly end: number;\n readonly measure: RunMeasure;\n readonly rtl: boolean;\n}\n\n/**\n * Lays a node's text out in its content box, exactly as the renderers\n * draw it: the same measure request, so the lines are the ones on\n * screen.\n *\n * `box` is in whatever space the caller works in — node-local for\n * input, the parent's content space for paint — and the offsets and\n * boxes come back in that space.\n */\nexport function paragraphGeometry(\n text: string,\n box: LayoutBox,\n state: PaintState,\n measurer: TextMeasurer\n): ParagraphGeometry {\n const request = textMeasureRequest(text, state, box);\n const lines = placeLines(box, state, measurer.layout(request));\n return geometryFor(lines, text, request, state, measurer);\n}\n\n/**\n * The same geometry over lines a caller has already placed. Both\n * renderers lay a paragraph out to draw it, so a selected one is not\n * laid out twice.\n */\nexport function paragraphGeometryFrom(\n lines: readonly TextLinePlacement[],\n text: string,\n box: LayoutBox,\n state: PaintState,\n measurer: TextMeasurer\n): ParagraphGeometry {\n return geometryFor(lines, text, textMeasureRequest(text, state, box), state, measurer);\n}\n\nfunction geometryFor(\n lines: readonly TextLinePlacement[],\n text: string,\n request: ReturnType<typeof textMeasureRequest>,\n state: PaintState,\n measurer: TextMeasurer\n): ParagraphGeometry {\n const end = lines.length === 0 ? 0 : lines[lines.length - 1].end;\n // Runs are measured by offset, in the font of the run each piece\n // falls in, exactly as the paragraph algorithm measured the lines\n // these came from. Without the offset there is no run to look up,\n // which is the case for a string that is not in the text.\n const spanned = spannedRunsFor(request, measurer);\n return {\n lines,\n text: end === text.length ? text : text.slice(0, end),\n start: lines.length === 0 ? 0 : lines[0].start,\n end,\n measure: (run, from) =>\n run.length === 0\n ? 0\n : spanned === undefined || from === undefined\n ? measurer.measureRunWidth(run, request)\n : spanned.width(text, from, from + run.length),\n rtl: state.rtl\n };\n}\n\n/** Whether anything in this paragraph can be selected at all. */\nexport function hasDrawnText(geometry: ParagraphGeometry): boolean {\n return geometry.lines.length > 0 && geometry.end > geometry.start;\n}\n\n/** The offset nearest a point, clamped to the drawn text. */\nexport function offsetAtPointIn(geometry: ParagraphGeometry, x: number, y: number): number {\n if (geometry.lines.length === 0) {\n return 0;\n }\n return offsetAtPoint(geometry.lines, geometry.text, x, y, geometry.measure, geometry.rtl);\n}\n\n/** The boxes covering `[start, end)`, one per line the range touches. */\nexport function selectionRectsIn(geometry: ParagraphGeometry, start: number, end: number): LayoutBox[] {\n const from = clamp(start, geometry.start, geometry.end);\n const to = clamp(end, geometry.start, geometry.end);\n if (geometry.lines.length === 0 || to <= from) {\n return [];\n }\n return selectionRects(geometry.lines, geometry.text, from, to, geometry.measure, geometry.rtl);\n}\n\n/** The word around an offset, for a double click. */\nexport function wordRangeIn(geometry: ParagraphGeometry, offset: number): { start: number; end: number } {\n return wordRangeAt(geometry.text, clamp(offset, geometry.start, geometry.end));\n}\n\nfunction clamp(value: number, low: number, high: number): number {\n return value < low ? low : value > high ? high : value;\n}\n","import type { UiNode } from '../graph/UiNode';\nimport { UiEventType, type UiInputEvent } from './UiInputEvent';\n\n/**\n * Listener for framework input events.\n *\n * `event.currentTarget` is the node the listener is attached to;\n * `event.target` is the node the event was routed to.\n */\nexport type UiEventListener = (event: UiInputEvent) => void;\n\nexport interface UiEventListenerOptions {\n /**\n * Invoke the listener during the capture phase (root → target)\n * instead of the bubble phase (target → root).\n */\n capture?: boolean;\n}\n\ninterface ListenerEntry {\n listener: UiEventListener;\n capture: boolean;\n}\n\n/**\n * Per-node listener storage keyed by event type.\n *\n * Entries are appended in registration order and invoked in that\n * order within a phase.\n */\ntype ListenerStore = Map<string, ListenerEntry[]>;\n\n/**\n * Routes framework input events through the retained UI tree.\n *\n * This is the single dispatch point for raw platform input and for\n * synthesized gesture events, so there is exactly one event model.\n *\n * Phase order mirrors the DOM:\n *\n * capture — root → target (excluding the target)\n * target — the target's capture then bubble listeners\n * bubble — target's parent → root\n *\n * stopPropagation() ends the current phase and skips\n * every remaining phase.\n * stopImmediatePropagation() ends the current listener list and\n * every remaining phase.\n * preventDefault() is advisory: it only sets the flag\n * so consumers can cancel framework\n * default behaviour (click synthesis,\n * drag interpretation, scroll, tab).\n *\n * Focus, Blur, PointerEnter and PointerLeave are target-only: only\n * the target's listeners run, never its ancestors (they do not\n * bubble, mirroring DOM focus/blur and mouseenter/mouseleave).\n *\n * A throwing listener is reported and does not stop the rest of the\n * dispatch, matching how bindings isolate errors in UiGraph.\n */\n/**\n * What to do with an exception a listener threw.\n *\n * `node` and `type` are what a report needs to be actionable, and the\n * error keeps its stack.\n */\nexport type UiListenerErrorReporter = (error: unknown, node: UiNode, type: string) => void;\n\nexport class UiInputDispatcher {\n private readonly stores = new WeakMap<UiNode, ListenerStore>();\n\n /**\n * Where a throwing listener is reported.\n *\n * The dispatch has to continue — one broken `onClick` must not stop\n * the event reaching the rest of the tree, or stop the other\n * listeners on the same node — so the exception is caught here and\n * nowhere else can see it. Left unset it goes to the console, which\n * inside a render worker is a console almost nobody opens; a runtime\n * sets this so the failure can reach the shell instead.\n */\n private errorReporter: UiListenerErrorReporter | null = null;\n\n onListenerError(reporter: UiListenerErrorReporter | null): void {\n this.errorReporter = reporter;\n }\n\n /**\n * Number of registered listeners per event type.\n *\n * A zero entry lets dispatch return before walking the tree when\n * nothing is listening for the event type at all.\n */\n private readonly typeCount = new Map<string, number>();\n\n addEventListener(\n node: UiNode,\n type: UiEventType,\n listener: UiEventListener,\n options: UiEventListenerOptions = {}\n ): void {\n const capture = options.capture ?? false;\n let store = this.stores.get(node);\n if (store === undefined) {\n store = new Map();\n this.stores.set(node, store);\n }\n let entries = store.get(type);\n if (entries === undefined) {\n entries = [];\n store.set(type, entries);\n }\n if (entries.some(entry => entry.listener === listener && entry.capture === capture)) {\n return;\n }\n entries.push({ listener, capture });\n this.typeCount.set(type, (this.typeCount.get(type) ?? 0) + 1);\n }\n\n removeEventListener(\n node: UiNode,\n type: UiEventType,\n listener: UiEventListener,\n options: UiEventListenerOptions = {}\n ): void {\n const store = this.stores.get(node);\n if (store === undefined) {\n return;\n }\n const entries = store.get(type);\n if (entries === undefined) {\n return;\n }\n const capture = options.capture ?? false;\n const index = entries.findIndex(entry => entry.listener === listener && entry.capture === capture);\n if (index === -1) {\n return;\n }\n entries.splice(index, 1);\n if (entries.length === 0) {\n store.delete(type);\n if (store.size === 0) {\n this.stores.delete(node);\n }\n const remaining = (this.typeCount.get(type) ?? 0) - 1;\n if (remaining <= 0) {\n this.typeCount.delete(type);\n } else {\n this.typeCount.set(type, remaining);\n }\n }\n }\n\n /**\n * Whether any node has a listener for the event type.\n *\n * Used as a cheap guard before dispatch so event streams with no\n * subscribers (e.g. pointer moves over a static tree) cost almost\n * nothing.\n */\n hasListeners(type: UiEventType): boolean {\n return (this.typeCount.get(type) ?? 0) > 0;\n }\n\n /** The event types this node has listeners for, for the inspector. */\n listenerTypes(node: UiNode): UiEventType[] {\n const store = this.stores.get(node);\n return store === undefined ? [] : ([...store.keys()] as UiEventType[]);\n }\n\n /**\n * Dispatches the event, routed to the supplied target.\n *\n * Sets `event.target` and walks `event.currentTarget` over the\n * dispatch path. Returns the event for chaining; the event is left\n * with `currentTarget === null` so a reused instance never leaks\n * its last dispatch position.\n */\n dispatch(event: UiInputEvent, target: UiNode): UiInputEvent {\n if (!this.hasListeners(event.type)) {\n return event;\n }\n event.target = target;\n event.currentTarget = null;\n\n const targetOnly =\n event.type === UiEventType.Focus ||\n event.type === UiEventType.Blur ||\n event.type === UiEventType.PointerEnter ||\n event.type === UiEventType.PointerLeave;\n\n const chain: UiNode[] = [];\n for (let node: UiNode | null = target; node !== null; node = node.parent) {\n chain.push(node);\n }\n\n if (targetOnly) {\n this.invokeListeners(target, event, true);\n this.invokeListeners(target, event, false);\n } else {\n // Capture: root down to the target's parent.\n for (let i = chain.length - 1; i >= 1 && !event.immediateStopped; i -= 1) {\n if (event.propagationStopped) {\n break;\n }\n this.invokeListeners(chain[i], event, true);\n }\n // Target: capture then bubble listeners on the target itself.\n if (!event.propagationStopped && !event.immediateStopped) {\n this.invokeListeners(target, event, true);\n this.invokeListeners(target, event, false);\n }\n // Bubble: the target's parent up to and including the root.\n for (let i = 1; i <= chain.length - 1 && !event.immediateStopped; i += 1) {\n if (event.propagationStopped) {\n break;\n }\n this.invokeListeners(chain[i], event, false);\n }\n }\n\n event.currentTarget = null;\n return event;\n }\n\n private invokeListeners(node: UiNode, event: UiInputEvent, capture: boolean): void {\n const entries = this.stores.get(node)?.get(event.type);\n if (entries === undefined) {\n return;\n }\n event.currentTarget = node;\n // Snapshot so listeners added or removed mid-dispatch do not\n // disturb the current phase.\n for (const entry of entries.slice()) {\n if (entry.capture !== capture || event.immediateStopped) {\n continue;\n }\n try {\n entry.listener(event);\n } catch (error) {\n if (this.errorReporter !== null) {\n this.errorReporter(error, node, event.type);\n } else {\n console.error(`UI event listener failed (${node.id}.${event.type})`, error);\n }\n }\n }\n }\n}\n","import type { LayoutRecord } from './LayoutRecord';\nimport type { LayoutBox } from './LayoutTypes';\n\n/** Thickness of an overlay scrollbar thumb. */\nexport const SCROLLBAR_THICKNESS = 6;\n/** Gap between the thumb and the container's edges. */\nexport const SCROLLBAR_INSET = 2;\n/** Shortest thumb, so a long list still shows something to grab. */\nexport const SCROLLBAR_MIN_THUMB = 24;\n/** Distance from the end edge within which the pointer reveals the bar. */\nexport const SCROLLBAR_HOVER_ZONE = 16;\n\nexport type ScrollbarAxis = 'x' | 'y';\n\n/**\n * One scrollbar's geometry, in the container's record coordinates\n * (pre-scroll, like the record box): the thumb rectangle and the\n * numbers that map pointer travel back to scroll offset.\n */\nexport interface ScrollbarThumb {\n axis: ScrollbarAxis;\n thumb: LayoutBox;\n /** Length of the track the thumb moves in. */\n track: number;\n /** How far the thumb can travel: track minus thumb length. */\n travel: number;\n /** contentExtent minus viewport: the scroll offset at full travel. */\n maxScroll: number;\n /** The container's extent along the axis: one page. */\n viewport: number;\n}\n\n/**\n * The scrollbars a scroll container shows: one per axis whose content\n * overflows. Renderers draw exactly these rectangles and the hit\n * tester grabs them, so what is seen is what is dragged.\n */\nexport function scrollbarThumbs(rec: LayoutRecord): {\n vertical: ScrollbarThumb | null;\n horizontal: ScrollbarThumb | null;\n} {\n return { vertical: thumbFor(rec, 'y'), horizontal: thumbFor(rec, 'x') };\n}\n\nexport function scrollbarThumb(rec: LayoutRecord, axis: ScrollbarAxis): ScrollbarThumb | null {\n return thumbFor(rec, axis);\n}\n\nfunction thumbFor(rec: LayoutRecord, axis: ScrollbarAxis): ScrollbarThumb | null {\n const viewport = axis === 'y' ? rec.height : rec.width;\n const content = axis === 'y' ? rec.contentHeight : rec.contentWidth;\n if (!(content > viewport) || viewport <= 0) {\n return null;\n }\n const track = viewport - SCROLLBAR_INSET * 2;\n const length = Math.min(track, Math.max(SCROLLBAR_MIN_THUMB, (track * viewport) / content));\n const travel = Math.max(0, track - length);\n const maxScroll = content - viewport;\n const offset = axis === 'y' ? rec.scrollY : rec.scrollX;\n const along = SCROLLBAR_INSET + (maxScroll > 0 ? (travel * offset) / maxScroll : 0);\n const thumb: LayoutBox =\n axis === 'y'\n ? {\n // The vertical bar hangs on the edge a line of text ends at,\n // which is the left one when the container reads right to\n // left. The horizontal bar stays at the bottom either way.\n x: rec.mirrored ? rec.x + SCROLLBAR_INSET : rec.x + rec.width - SCROLLBAR_INSET - SCROLLBAR_THICKNESS,\n y: rec.y + along,\n width: SCROLLBAR_THICKNESS,\n height: length\n }\n : {\n x: rec.x + along,\n y: rec.y + rec.height - SCROLLBAR_INSET - SCROLLBAR_THICKNESS,\n width: length,\n height: SCROLLBAR_THICKNESS\n };\n return { axis, thumb, track, travel, maxScroll, viewport };\n}\n\n/**\n * Whether a point in the container's record space lies in the band\n * along the end edge where the bar lives (and where hovering reveals\n * it). Returns the axis, or null.\n */\nexport function scrollbarZoneAt(rec: LayoutRecord, x: number, y: number): ScrollbarAxis | null {\n const inside = x >= rec.x && x < rec.x + rec.width && y >= rec.y && y < rec.y + rec.height;\n if (!inside) {\n return null;\n }\n const inVerticalZone = rec.mirrored\n ? x < rec.x + SCROLLBAR_HOVER_ZONE\n : x >= rec.x + rec.width - SCROLLBAR_HOVER_ZONE;\n if (rec.contentHeight > rec.height && inVerticalZone) {\n return 'y';\n }\n if (rec.contentWidth > rec.width && y >= rec.y + rec.height - SCROLLBAR_HOVER_ZONE) {\n return 'x';\n }\n return null;\n}\n\n/**\n * The rectangle a press grabs a thumb by.\n *\n * The painted thumb is six pixels thick. Six pixels at the very edge\n * of a window is a hard thing to hit, and missing it is not a near\n * miss — the press lands on the track instead and pages a whole\n * screenful, which reads as the bar refusing to be dragged. So the\n * grab target is the thumb's length by the whole band that reveals it:\n * as easy to catch as it is to summon, which is what an overlay\n * scrollbar is expected to be. What is drawn is unchanged.\n */\nexport function scrollbarGrabBox(rec: LayoutRecord, bar: ScrollbarThumb): LayoutBox {\n if (bar.axis === 'y') {\n return {\n x: rec.mirrored ? rec.x : rec.x + rec.width - SCROLLBAR_HOVER_ZONE,\n y: bar.thumb.y,\n width: SCROLLBAR_HOVER_ZONE,\n height: bar.thumb.height\n };\n }\n return {\n x: bar.thumb.x,\n y: rec.y + rec.height - SCROLLBAR_HOVER_ZONE,\n width: bar.thumb.width,\n height: SCROLLBAR_HOVER_ZONE\n };\n}\n\nexport function pointInBox(box: LayoutBox, x: number, y: number): boolean {\n return x >= box.x && x < box.x + box.width && y >= box.y && y < box.y + box.height;\n}\n","import { UiNodeType } from '../graph/UiNodeType';\nimport type { UiNode } from '../graph/UiNode';\nimport type { LayoutRecord } from '../layout/LayoutRecord';\nimport type { SubtreeBounds } from '../layout/SubtreeBounds';\nimport { isNodeHitTestable, isNodeInert } from './UiInteraction';\nimport {\n pointInBox,\n scrollbarGrabBox,\n scrollbarThumb,\n scrollbarZoneAt,\n type ScrollbarAxis\n} from '../layout/Scrollbars';\n\n/**\n * Read access to layout records for hit testing.\n *\n * LayoutEngine satisfies this structurally. The interface exists so\n * the hit tester is coupled to a geometry projection, not to the\n * concrete engine, and so a future implementation could be fed\n * transferable geometry in a Worker.\n */\nexport interface HitTestLayoutReader {\n recordFor(node: UiNode): LayoutRecord | undefined;\n /**\n * The nodes asking for `lift`, which are painted in a top layer and\n * so are pressed before anything in the tree.\n *\n * Optional because it is an index rather than a geometry: a reader\n * that does not keep one simply has no top layer, and every node is\n * tested where the tree puts it. `LayoutEngine` keeps one.\n */\n readonly lifted?: ReadonlySet<UiNode>;\n /**\n * A box around everything in a node's subtree that could take a\n * point, in the space the node's own record lives in, so that a\n * subtree the point falls outside of is passed over rather than\n * descended into.\n *\n * Optional for the same reason `lifted` is: a reader that cannot\n * summarise its geometry offers none, and the walk descends into\n * everything, which is what it did before bounds existed. The\n * summary is only ever allowed to be too large, so a reader that\n * offers one changes how long a hit test takes and never what it\n * answers.\n */\n subtreeBoundsFor?(node: UiNode): SubtreeBounds | undefined;\n}\n\nexport interface UiPoint {\n x: number;\n y: number;\n}\n\n/**\n * The result of a successful hit: the topmost node under the point\n * plus the point expressed in that node's local (untransformed,\n * pre-scroll) coordinates.\n */\nexport interface HitTestResult {\n node: UiNode;\n localX: number;\n localY: number;\n /**\n * Set when the point is on a scroll container's scrollbar: which axis,\n * and whether it is on the thumb (drag) or the track beside it (page).\n * `node` is the container. Only a visible bar, or its thumb, takes the\n * hit; otherwise content underneath wins.\n */\n scrollbar?: { axis: ScrollbarAxis; onThumb: boolean };\n}\n\n/**\n * Abstraction over hit testing.\n *\n * The initial implementation is a reverse-paint-order tree walk. It\n * is O(n) in the worst case, and close to the depth of the pointer\n * path in the ordinary one: a subtree whose bounds the point falls\n * outside of is passed over, when the reader offers bounds at all.\n * Later implementations could back this interface with a spatial\n * hash, an R-tree, a grid, or GPU picking without the pointer\n * pipeline changing.\n */\nexport interface HitTester {\n hitTest(x: number, y: number): HitTestResult | null;\n /** Converts a canvas-space point into a node's local coordinates. */\n toLocal(node: UiNode, x: number, y: number): UiPoint;\n /**\n * The scroll container whose scrollbar band the point is in, visible\n * or not — the pointer controller reveals bars as the pointer nears\n * them. Null away from any bar.\n */\n scrollbarZoneAt(x: number, y: number): { node: UiNode; axis: ScrollbarAxis } | null;\n}\n\n/**\n * Affine inverse-transform scratch. Non-allocating hit traversal.\n *\n * Node transforms mirror the renderer's CTM exactly:\n * world = T(origin) · R(θ) · S(sx, sy) · T(-origin) · local\n * with origin = (record.x + transform.x, record.y + transform.y).\n * The inverse maps a world point back into the node's record space,\n * where its layout box is tested directly. Identity transforms\n * round-trip exactly, so no \"is it transformed?\" branch is needed.\n */\ninterface TransformScratch {\n x: number;\n y: number;\n}\n\n/**\n * Tree-walking hit tester.\n *\n * Traverses the retained UiNode tree in the inverse of paint order\n * (last child first, because it paints on top), carrying clipping\n * and scroll state implicitly:\n *\n * - Scroll containers clip to their viewport record rect, then\n * shift the point by (scrollX, scrollY) before testing\n * descendants, whose records are pre-scroll content coords.\n * - Every node applies its affine inverse transform so rotated /\n * scaled boxes are tested in their own record space.\n * - Inert subtrees (disabled, pointerEvents:none, invisible,\n * opacity 0) are skipped entirely; nodes with\n * hitTestable:false are skipped as candidates but still expose\n * their children.\n *\n * Descendant tests run before the node itself because children\n * paint on top of the parent's background. No per-node allocations\n * happen on the traversal path; a result object is produced only\n * when a hit is found.\n *\n * The walk descends into a child only when the point is inside the\n * bounds of that child's subtree, which is what stops a list of a\n * thousand rows costing a thousand descents for a point in one of\n * them. Those bounds come from the layout reader and are conservative\n * by construction, so they change how much of the tree is visited and\n * never which node comes back.\n */\nexport class UiHitTester implements HitTester {\n private readonly point: TransformScratch = { x: 0, y: 0 };\n private readonly result = new HitScratch();\n /** True while answering scrollbarZoneAt: bands count, content does not. */\n private zoneOnly = false;\n /** Root-to-node scratch for toLocal, reused so a pointer drag allocates nothing. */\n private readonly path: UiNode[] = [];\n /** The lifted nodes of the moment, ordered so the last is tried first. */\n private readonly liftedScratch: UiNode[] = [];\n /** True while testing inside a lifted subtree, so it is not skipped again. */\n private inLifted = false;\n\n constructor(\n private layout: HitTestLayoutReader,\n private root: UiNode\n ) {}\n\n /** The node traversal starts from (normally the layout root). */\n setRoot(root: UiNode): void {\n this.root = root;\n }\n\n hitTest(x: number, y: number): HitTestResult | null {\n this.result.scrollbar = undefined;\n this.zoneOnly = false;\n // The top layer first: `lift` paints those nodes over the whole\n // tree, and what is drawn last is pressed first.\n if (this.hitTestLifted(x, y) || this.hitTestNode(this.root, x, y)) {\n const result: HitTestResult = { node: this.result.node!, localX: this.result.localX, localY: this.result.localY };\n const scrollbar = this.result.takeScrollbar();\n if (scrollbar !== undefined) {\n result.scrollbar = scrollbar;\n }\n return result;\n }\n return null;\n }\n\n /**\n * Every hit-testable node under the point, topmost first: the one a\n * press would reach, then each node it is painted over. For the\n * inspector, which answers \"why did my click land on this\" by naming\n * what lies beneath. Scrollbars are not counted; a press on one is\n * not a press on a node.\n */\n hitStack(x: number, y: number): UiNode[] {\n const out: UiNode[] = [];\n this.forEachLifted(x, y, (node, px, py) => {\n this.inLifted = true;\n this.collectNode(node, px, py, out);\n this.inLifted = false;\n return false;\n });\n this.collectNode(this.root, x, y, out);\n return out;\n }\n\n private collectNode(node: UiNode, x: number, y: number, out: UiNode[]): void {\n if (isNodeInert(node)) {\n return;\n }\n const rec = this.layout.recordFor(node);\n if (rec === undefined || !this.invertPoint(node, rec, x, y)) {\n return;\n }\n if (rec.lifted && !this.inLifted) {\n // Already collected from the top layer, where it is drawn.\n return;\n }\n const px = this.point.x - rec.stickyOffsetX;\n const py = this.point.y - rec.stickyOffsetY;\n const inside = px >= rec.x && px < rec.x + rec.width && py >= rec.y && py < rec.y + rec.height;\n if (rec.clips && !inside) {\n return;\n }\n const shiftX = rec.clips && rec.scrollable ? rec.scrollX : 0;\n const shiftY = rec.clips && rec.scrollable ? rec.scrollY : 0;\n this.collectChildren(node, px + shiftX, py + shiftY, out);\n if (inside && isNodeHitTestable(node)) {\n out.push(node);\n }\n }\n\n private collectChildren(parent: UiNode, x: number, y: number, out: UiNode[]): void {\n const order = this.layout.recordFor(parent)?.paintOrder;\n if (order !== null && order !== undefined) {\n for (let i = order.length - 1; i >= 0; i--) {\n this.collectNode(order[i], x, y, out);\n }\n return;\n }\n for (let child = parent.lastChild; child !== null; child = child.previousSibling) {\n if (child.type === UiNodeType.Fragment) {\n this.collectChildren(child, x, y, out);\n } else {\n this.collectNode(child, x, y, out);\n }\n }\n }\n\n scrollbarZoneAt(x: number, y: number): { node: UiNode; axis: ScrollbarAxis } | null {\n this.result.scrollbar = undefined;\n this.zoneOnly = true;\n const hit = this.hitTestNode(this.root, x, y);\n this.zoneOnly = false;\n const scrollbar = this.result.takeScrollbar();\n if (hit && scrollbar !== undefined) {\n return { node: this.result.node!, axis: scrollbar.axis };\n }\n return null;\n }\n\n /**\n * A canvas point in a node's local coordinates.\n *\n * This has to replay the descent `hitTest` makes rather than undo\n * the node's own transform alone: records stay in pre-scroll\n * coordinates, so a node inside a scrolled container sits at a\n * record y the pointer's canvas y knows nothing about. The walk\n * applies each ancestor's inverse transform, sticky shift and\n * scroll offset in the same order the traversal does, so the answer\n * agrees with `hitTest`'s `localX`/`localY` for the node it hit —\n * which is what places the caret from a click inside a scrolled\n * editable.\n */\n toLocal(node: UiNode, x: number, y: number): UiPoint {\n const rec = this.layout.recordFor(node);\n if (rec === undefined) {\n return { x, y };\n }\n const path = this.path;\n path.length = 0;\n // Fragments carry no record and are traversed transparently.\n for (let current: UiNode | null = node; current !== null; current = current.parent) {\n if (current.type !== UiNodeType.Fragment) {\n path.push(current);\n }\n if (current === this.root) {\n break;\n }\n }\n let px = x;\n let py = y;\n for (let i = path.length - 1; i >= 0; i--) {\n const ancestor = path[i];\n const record = this.layout.recordFor(ancestor);\n if (record === undefined) {\n continue;\n }\n // A degenerate transform draws nothing, so there is no sensible\n // point to map through it: leave it as the identity.\n if (this.invertPoint(ancestor, record, px, py)) {\n px = this.point.x;\n py = this.point.y;\n }\n px -= record.stickyOffsetX;\n py -= record.stickyOffsetY;\n if (i > 0 && record.clips && record.scrollable) {\n px += record.scrollX;\n py += record.scrollY;\n }\n }\n path.length = 0;\n return { x: px - rec.x, y: py - rec.y };\n }\n\n // -------------------------------------------------------------------------\n // The top layer\n // -------------------------------------------------------------------------\n\n /**\n * Tries the lifted nodes, last one first, and reports whether one\n * took the point.\n *\n * Last first because `lift` puts them over the tree in the order\n * they were lifted, and the reason the ordinary walk reads\n * `paintOrder` backwards holds here too: whatever is drawn on top is\n * pressed first.\n */\n private hitTestLifted(x: number, y: number): boolean {\n return this.forEachLifted(x, y, (node, px, py) => {\n this.inLifted = true;\n const hit = this.hitTestNode(node, px, py);\n this.inLifted = false;\n return hit;\n });\n }\n\n /**\n * Runs `visit` for each lifted node with the point in the space its\n * record box lives in, stopping at the first that answers true.\n *\n * The point is replayed down the ancestor chain rather than taken\n * from the walk, because there is no walk to take it from: the whole\n * point of the top layer is that the descent to it went through\n * clips that would have rejected the point long before it arrived.\n * `toLocal` replays the same chain for the same reason.\n */\n private forEachLifted(x: number, y: number, visit: (node: UiNode, px: number, py: number) => boolean): boolean {\n const lifted = this.layout.lifted;\n if (lifted === undefined || lifted.size === 0) {\n return false;\n }\n const nodes = this.liftedScratch;\n nodes.length = 0;\n for (const node of lifted) {\n nodes.push(node);\n }\n let hit = false;\n for (let i = nodes.length - 1; i >= 0 && !hit; i--) {\n const node = nodes[i]!;\n if (this.layout.recordFor(node) === undefined) {\n continue;\n }\n this.pointInParentSpace(node, x, y);\n hit = visit(node, this.point.x, this.point.y);\n }\n nodes.length = 0;\n return hit;\n }\n\n /**\n * Puts `this.point` in the coordinate space a node's record box\n * lives in: every ancestor's transform, sticky shift and scroll\n * offset applied, and the node's own left alone, which is exactly\n * what `hitTestNode` expects to be handed.\n */\n private pointInParentSpace(node: UiNode, x: number, y: number): void {\n const path = this.path;\n path.length = 0;\n for (let current: UiNode | null = node.parent; current !== null; current = current.parent) {\n if (current.type !== UiNodeType.Fragment) {\n path.push(current);\n }\n if (current === this.root) {\n break;\n }\n }\n let px = x;\n let py = y;\n for (let i = path.length - 1; i >= 0; i--) {\n const ancestor = path[i]!;\n const record = this.layout.recordFor(ancestor);\n if (record === undefined) {\n continue;\n }\n if (this.invertPoint(ancestor, record, px, py)) {\n px = this.point.x;\n py = this.point.y;\n }\n px -= record.stickyOffsetX;\n py -= record.stickyOffsetY;\n if (record.clips && record.scrollable) {\n px += record.scrollX;\n py += record.scrollY;\n }\n }\n path.length = 0;\n this.point.x = px;\n this.point.y = py;\n }\n\n // -------------------------------------------------------------------------\n // Traversal\n // -------------------------------------------------------------------------\n\n private hitTestNode(node: UiNode, x: number, y: number): boolean {\n if (isNodeInert(node)) {\n return false;\n }\n const rec = this.layout.recordFor(node);\n if (rec === undefined) {\n return false;\n }\n if (rec.lifted && !this.inLifted) {\n // Tested in the top layer, where it is drawn. Testing it here as\n // well would let a press land on a picture that is halfway across\n // the screen, which is the clipped position `lift` exists to stop\n // it being drawn at.\n return false;\n }\n if (!this.invertPoint(node, rec, x, y)) {\n // Degenerate (zero-scale) transform: nothing is drawn, nothing hits.\n return false;\n }\n // A sticky node is drawn shifted from its record; undo the shift\n // so the record box (and the children, drawn with it) can be tested.\n const px = this.point.x - rec.stickyOffsetX;\n const py = this.point.y - rec.stickyOffsetY;\n\n if (rec.clips) {\n // The clip is the node's own box: outside it nothing of this\n // subtree can be hit. Descendants of a scroll container live in\n // pre-scroll content coordinates, so the point is shifted by the\n // scroll offset after the clip passes.\n if (px < rec.x || px >= rec.x + rec.width || py < rec.y || py >= rec.y + rec.height) {\n return false;\n }\n if (rec.scrollable && this.hitScrollbar(node, rec, px, py)) {\n return true;\n }\n if (this.zoneOnly) {\n // Looking for a bar band only: descend, but never land on content.\n const shiftX = rec.scrollX;\n const shiftY = rec.scrollY;\n return this.hitTestChildren(node, px + shiftX, py + shiftY);\n }\n const shiftX = rec.scrollable ? rec.scrollX : 0;\n const shiftY = rec.scrollable ? rec.scrollY : 0;\n if (this.hitTestChildren(node, px + shiftX, py + shiftY)) {\n return true;\n }\n return isNodeHitTestable(node) && this.recordHit(node, rec, px, py);\n }\n\n // Non-clipping nodes let children paint outside them, so children\n // are tested regardless of whether the point falls inside the box.\n // What keeps that from meaning \"every node in the tree, on every\n // pointer move\" is the bounds check in `hitTestChildren`, which\n // knows how far outside the box the children actually reach.\n if (this.hitTestChildren(node, px, py)) {\n return true;\n }\n if (this.zoneOnly || !isNodeHitTestable(node)) {\n return false;\n }\n if (px < rec.x || px >= rec.x + rec.width || py < rec.y || py >= rec.y + rec.height) {\n return false;\n }\n return this.recordHit(node, rec, px, py);\n }\n\n private hitTestChildren(parent: UiNode, x: number, y: number): boolean {\n // zIndex reordered these children: the topmost paints last, so it\n // is tested first. Fragments are already expanded in the order.\n const order = this.layout.recordFor(parent)?.paintOrder;\n if (order !== null && order !== undefined) {\n for (let i = order.length - 1; i >= 0; i--) {\n if (!this.outsideSubtree(order[i], x, y) && this.hitTestNode(order[i], x, y)) {\n return true;\n }\n }\n return false;\n }\n for (let child = parent.lastChild; child !== null; child = child.previousSibling) {\n if (child.type === UiNodeType.Fragment) {\n // A fragment has no record and so no bounds of its own; its\n // children carry theirs, and are checked one by one below.\n if (this.hitTestChildren(child, x, y)) {\n return true;\n }\n continue;\n }\n if (!this.outsideSubtree(child, x, y) && this.hitTestNode(child, x, y)) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * Whether a subtree can be passed over without being descended into.\n *\n * This is the only thing standing between a pointer move and a walk\n * of the whole tree, and it is allowed to be wrong in exactly one\n * direction: a box that is too large costs a descent that finds\n * nothing, and a box that is too small loses a click at a position\n * where something is visibly drawn. The reader is what promises that\n * (see `SubtreeBounds`); here the edges are compared inclusively, so\n * a point exactly on one is descended into and left for the node's\n * own half-open box test to reject.\n */\n private outsideSubtree(node: UiNode, x: number, y: number): boolean {\n const bounds = this.layout.subtreeBoundsFor?.(node);\n if (bounds === undefined || bounds.boundsUnbounded) {\n return false;\n }\n return x < bounds.boundsMinX || x > bounds.boundsMaxX || y < bounds.boundsMinY || y > bounds.boundsMaxY;\n }\n\n private recordHit(node: UiNode, rec: LayoutRecord, px: number, py: number): boolean {\n this.result.node = node;\n this.result.localX = px - rec.x;\n this.result.localY = py - rec.y;\n return true;\n }\n\n /**\n * Scrollbars paint above a container's children, so they are tested\n * before them. The thumb always takes the hit; the rest of the band\n * only while the bar is showing (or when asked for the band alone).\n */\n private hitScrollbar(node: UiNode, rec: LayoutRecord, px: number, py: number): boolean {\n const zone = scrollbarZoneAt(rec, px, py);\n if (zone === null) {\n return false;\n }\n let axis = zone;\n let bar = scrollbarThumb(rec, axis);\n let onThumb = bar !== null && pointInBox(scrollbarGrabBox(rec, bar), px, py);\n if (!onThumb) {\n // The corner where the two bars meet is in both bands, and\n // `scrollbarZoneAt` has to answer with one of them. A press that\n // is on the *other* axis's thumb belongs to that axis whatever\n // the precedence says — otherwise a grab aimed at the horizontal\n // thumb, down in the corner, pages the vertical bar instead.\n const other: ScrollbarAxis = axis === 'y' ? 'x' : 'y';\n const otherBar = scrollbarThumb(rec, other);\n if (otherBar !== null && pointInBox(scrollbarGrabBox(rec, otherBar), px, py)) {\n axis = other;\n bar = otherBar;\n onThumb = true;\n }\n }\n if (bar === null) {\n return false;\n }\n const visible = rec.scrollbarVisibleUntil > (typeof performance !== 'undefined' ? performance.now() : Date.now());\n if (!onThumb && !visible && !this.zoneOnly) {\n return false;\n }\n this.recordHit(node, rec, px, py);\n this.result.scrollbar = { axis, onThumb };\n return true;\n }\n\n // -------------------------------------------------------------------------\n // Inverse affine transform\n // -------------------------------------------------------------------------\n\n /**\n * Maps (x, y) into the node's record space. Writes into the shared\n * scratch and returns false when the transform is degenerate.\n */\n private invertPoint(node: UiNode, rec: LayoutRecord, x: number, y: number): boolean {\n let scaleX = 1;\n let scaleY = 1;\n let rotation = 0;\n let offsetX = 0;\n let offsetY = 0;\n let translateX = 0;\n let translateY = 0;\n const raw = node.properties.get('transform');\n if (typeof raw === 'object' && raw !== null) {\n const transform = raw as Partial<\n Record<'x' | 'y' | 'translateX' | 'translateY' | 'scaleX' | 'scaleY' | 'rotation', unknown>\n >;\n scaleX = toFinite(transform.scaleX) ?? 1;\n scaleY = toFinite(transform.scaleY) ?? 1;\n rotation = toFinite(transform.rotation) ?? 0;\n offsetX = toFinite(transform.x) ?? 0;\n offsetY = toFinite(transform.y) ?? 0;\n translateX = toFinite(transform.translateX) ?? 0;\n translateY = toFinite(transform.translateY) ?? 0;\n }\n if (scaleX <= 0 || scaleY <= 0) {\n return false;\n }\n const originX = rec.x + offsetX;\n const originY = rec.y + offsetY;\n // The translation is the outermost factor of the forward transform,\n // so undoing it is the first thing the inverse does.\n const dx = x - translateX - originX;\n const dy = y - translateY - originY;\n if (rotation === 0) {\n this.point.x = dx / scaleX + originX;\n this.point.y = dy / scaleY + originY;\n return true;\n }\n const cos = Math.cos(rotation);\n const sin = Math.sin(rotation);\n const rotatedX = dx * cos + dy * sin;\n const rotatedY = -dx * sin + dy * cos;\n this.point.x = rotatedX / scaleX + originX;\n this.point.y = rotatedY / scaleY + originY;\n return true;\n }\n}\n\n/** Mutable hit output so the traversal path allocates nothing. */\nclass HitScratch {\n node: UiNode | null = null;\n localX = 0;\n localY = 0;\n scrollbar: { axis: ScrollbarAxis; onThumb: boolean } | undefined = undefined;\n\n /** Read through a method so a prior reset does not narrow the field to undefined. */\n takeScrollbar(): { axis: ScrollbarAxis; onThumb: boolean } | undefined {\n return this.scrollbar;\n }\n}\n\nfunction toFinite(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined;\n}\n","import type { UiNode } from '../graph/UiNode';\nimport { UiEventType, UiFocusEvent } from './UiInputEvent';\nimport { isNodeFocusable, isNodeTabStop } from './UiInteraction';\nimport type { UiInputDispatcher } from './UiInputDispatcher';\n\n/**\n * One entry on the focus scope stack.\n *\n * `restore` is what held focus when the scope was pushed, so popping\n * can hand focus back to the control that opened the dialog. Scopes\n * nest: a confirmation dialog over a dialog pushes a second one, and\n * each pop restores its own opener.\n */\n/**\n * What moved focus, which decides whether the focused node is scrolled\n * into view.\n *\n * A browser draws the same distinction and it is the reason it exists:\n * keyboard focus must reveal its target, because a control the person\n * cannot see is a control they cannot use, while a *click* has already\n * shown them where they are — the thing they pressed is under their\n * cursor. Scrolling after a click moves the page out from under a\n * pointer that is still there, and on a tall element that is a jump of\n * most of the screen.\n */\nexport type FocusSource = 'pointer' | 'keyboard' | 'program';\n\n/**\n * How the person last drove the app, as far as focus can tell: the\n * pointer or the keyboard. This is what decides whether focus is\n * *visible*, the way `:focus-visible` does in a browser: a ring that\n * appeared on every mouse click would mark a control nobody is about to\n * drive with the keyboard, so the ring waits until the keyboard is used.\n */\nexport type FocusModality = 'pointer' | 'keyboard';\n\ninterface FocusScope {\n readonly root: UiNode;\n readonly restore: UiNode | null;\n}\n\n/**\n * Logical focus within the UI tree.\n *\n * At most one node holds focus at a time. Focus transitions are\n * target-only: the node losing focus receives Blur (with the new\n * node as `relatedNode`), then the node gaining focus receives Focus\n * (with the old node as `relatedNode`).\n *\n * Tab / Shift+Tab navigation walks the focusable nodes in document\n * (depth-first) order and wraps around. A node participates when\n * `isNodeFocusable` says so: focusable by type (Button), explicitly\n * opted in via `focusable: true`, and never when inert.\n *\n * Focus-on-press is applied through `focusOnPress`, which the pointer\n * pipeline calls after a successful pointerdown (skipped when the\n * down was defaultPrevented).\n *\n * **Scopes.** `pushScope(node)` confines focus to a subtree: traversal\n * collects only that subtree's focusables, so Tab wraps inside it, and\n * `focus()` refuses a node outside it — which is what makes a modal\n * dialog modal for the keyboard. `popScope()` restores focus to\n * whatever held it when the scope was pushed. Components reach both\n * through `FocusService`, never directly.\n */\nexport class UiFocusManager {\n private root: UiNode;\n private focused: UiNode | null = null;\n /**\n * Keyboard until told otherwise, so focus placed before any input\n * (an `autoFocus`, a dialog's first field) is visible, as a browser\n * would show it.\n */\n private modality: FocusModality = 'keyboard';\n private readonly listeners = new Set<(node: UiNode | null, source: FocusSource) => void>();\n private readonly scopeListeners = new Set<() => void>();\n private readonly scopes: FocusScope[] = [];\n\n constructor(\n root: UiNode,\n private readonly dispatcher: UiInputDispatcher\n ) {\n this.root = root;\n }\n\n /** The root used for focus-order traversal. Clears any active scope. */\n setRoot(root: UiNode): void {\n this.root = root;\n this.scopes.length = 0;\n }\n\n /** The node that currently holds logical focus, or null. */\n get focusedNode(): UiNode | null {\n return this.focused;\n }\n\n hasFocus(): boolean {\n return this.focused !== null;\n }\n\n /** How the person last drove the app. */\n get focusModality(): FocusModality {\n return this.modality;\n }\n\n /**\n * Whether the focus held should be shown. True while focus was\n * reached by the keyboard, or by code with no pointer since; false\n * after a pointer press, until the next key.\n */\n get focusVisible(): boolean {\n return this.focused !== null && this.modality === 'keyboard';\n }\n\n /**\n * Records an input the person made. A change of modality while a node\n * holds focus is reported to the focus listeners as a change on that\n * node, so a ring can appear on a mouse-focused control the moment an\n * arrow key is pressed, and disappear again on the next press.\n */\n noteInput(modality: FocusModality): void {\n if (this.modality === modality) {\n return;\n }\n this.modality = modality;\n if (this.focused !== null) {\n this.notify(this.focused, modality);\n }\n }\n\n /**\n * The subtree focus is currently confined to: the innermost scope,\n * or the whole tree when none is active.\n */\n get scopeRoot(): UiNode {\n return this.scopes.length === 0 ? this.root : this.scopes[this.scopes.length - 1].root;\n }\n\n /** Whether focus is confined to a subtree. */\n get trapped(): boolean {\n return this.scopes.length > 0;\n }\n\n /**\n * Moves focus to the node. Returns false when the node cannot be\n * focused (inert, non-focusable, outside the active scope); true\n * otherwise, including when the node already held focus (a no-op\n * that emits nothing).\n */\n focus(node: UiNode, source: FocusSource = 'program'): boolean {\n if (!isNodeFocusable(node) || !this.withinScope(node)) {\n return false;\n }\n if (node === this.focused) {\n return true;\n }\n if (source !== 'program') {\n this.modality = source;\n }\n const previous = this.focused;\n this.focused = node;\n if (previous !== null) {\n this.dispatcher.dispatch(new UiFocusEvent(UiEventType.Blur, node), previous);\n }\n this.dispatcher.dispatch(new UiFocusEvent(UiEventType.Focus, previous), node);\n this.notify(node, source);\n return true;\n }\n\n /**\n * Called after focus moves or clears, with the new focused node. The\n * runtime uses it to scroll the focused node into view.\n */\n onFocusChange(listener: (node: UiNode | null, source: FocusSource) => void): () => void {\n this.listeners.add(listener);\n return () => {\n this.listeners.delete(listener);\n };\n }\n\n /** Called after a scope is pushed or popped. */\n onScopeChange(listener: () => void): () => void {\n this.scopeListeners.add(listener);\n return () => {\n this.scopeListeners.delete(listener);\n };\n }\n\n private notify(node: UiNode | null, source: FocusSource): void {\n for (const listener of this.listeners) {\n listener(node, source);\n }\n }\n\n private notifyScope(): void {\n for (const listener of this.scopeListeners) {\n listener();\n }\n }\n\n /** Drops focus without moving it anywhere. */\n blur(): void {\n if (this.focused === null) {\n return;\n }\n const previous = this.focused;\n this.focused = null;\n this.dispatcher.dispatch(new UiFocusEvent(UiEventType.Blur, null), previous);\n this.notify(null, 'program');\n }\n\n /**\n * Focus-on-press hook: focuses the nearest focusable node at or above\n * the one that was pressed.\n *\n * The walk upward is what the DOM does, and what a container that is\n * one tab stop needs: pressing a tab hits the Text inside it, a table\n * cell hits a Box three levels below the table, and a component whose\n * arrows move a selection is keyboard-dead after a mouse press if the\n * press left focus where it was. Found in a browser, on `Tabs` —\n * clicking a tab selected it and the arrows then did nothing.\n *\n * Nothing focusable above the press leaves focus untouched, as before:\n * pressing the page background is not a request to blur.\n */\n focusOnPress(node: UiNode): void {\n // A press is a press whether or not it lands on something focusable:\n // the person is on the mouse now, and a ring on whatever holds\n // focus should go.\n this.noteInput('pointer');\n for (let current: UiNode | null = node; current !== null; current = current.parent) {\n if (isNodeFocusable(current)) {\n this.focus(current, 'pointer');\n return;\n }\n }\n }\n\n /** Moves focus to the next focusable node, wrapping to the first. */\n focusNext(): boolean {\n return this.moveFocus(1);\n }\n\n /** Moves focus to the previous focusable node, wrapping to the last. */\n focusPrevious(): boolean {\n return this.moveFocus(-1);\n }\n\n /**\n * Confines focus to `root` until the matching `popScope`.\n *\n * Focus that is outside the new scope moves to its first focusable,\n * so the very next Tab stays inside; a scope with nothing focusable\n * in it drops focus rather than leaving it behind the dialog.\n */\n pushScope(root: UiNode): void {\n this.scopes.push({ root, restore: this.focused });\n this.settleScope();\n this.notifyScope();\n }\n\n /**\n * Moves focus into the innermost scope when it is outside it, and\n * drops it when the scope has nothing to focus.\n *\n * A scope is usually taken from a `ref`, which fires before the\n * node's children are reconciled — so at that moment a dialog is an\n * empty box and there is nothing in it to focus. The runtime calls\n * this again once the frame's tree is built, which is when a dialog\n * gets its caret. Idempotent: with focus already inside the scope,\n * or no scope at all, it does nothing.\n *\n * **The scope root is the fallback, and it is the whole reason\n * `tabStop` exists.** A scope with no tab stop inside it used to\n * blur, which hands the keyboard to nothing: a `Dialog` whose body\n * is a sentence and a button could not be dismissed with Escape,\n * because Escape had nowhere to be delivered. Falling back to the\n * root fixes that only if the root can hold focus without becoming a\n * stop of its own, or every dialog grows a tab stop that announces\n * nothing. `focusable: true, tabStop: false` on the body is exactly\n * that pair, and the fallback is what makes it worth setting.\n *\n * Blurring is still what happens when the root cannot hold focus\n * either, because a scope that has genuinely nothing to focus is\n * better admitted than faked.\n */\n settleScope(): void {\n if (this.scopes.length === 0 || (this.focused !== null && this.withinScope(this.focused))) {\n return;\n }\n if (!this.focusNext() && !this.focus(this.scopeRoot)) {\n this.blur();\n }\n }\n\n /**\n * Ends the innermost scope and hands focus back to whatever held it\n * when that scope was pushed, when that node is still in the tree\n * and still focusable. Otherwise focus is dropped rather than left\n * on a node the scope was hiding.\n */\n popScope(): void {\n const scope = this.scopes.pop();\n if (scope === undefined) {\n return;\n }\n const restore = scope.restore;\n if (restore !== null && this.isAttached(restore) && this.focus(restore)) {\n this.notifyScope();\n return;\n }\n if (this.focused !== null && this.isWithin(this.focused, scope.root)) {\n this.blur();\n }\n this.notifyScope();\n }\n\n /**\n * Reacts to a subtree leaving the graph.\n *\n * The graph reports the root of a removed subtree after detaching\n * every node in it, so the descendants' parent links are already\n * gone: the test is \"is this node still attached\", not \"was it in\n * that subtree\".\n *\n * A scope whose subtree has gone is a trap that ended, so it is\n * popped as though the component had released it and focus returns\n * to the opener — a dialog that unmounts hands the keyboard back\n * without having to sequence its own teardown. Focus lost with the\n * subtree is dropped without a Blur, since the node's listeners were\n * released with it.\n */\n handleNodeRemoved(_node: UiNode): void {\n const hadFocus = this.focused !== null;\n if (this.focused !== null && !this.isAttached(this.focused)) {\n this.focused = null;\n }\n while (this.scopes.length > 0 && !this.isAttached(this.scopeRoot)) {\n this.popScope();\n }\n if (hadFocus && this.focused === null) {\n this.notify(null, 'program');\n }\n }\n\n private moveFocus(delta: number): boolean {\n const focusables = this.collectFocusable();\n if (focusables.length === 0) {\n return false;\n }\n let index = this.focused === null ? -1 : focusables.indexOf(this.focused);\n if (index === -1) {\n // Nothing focused, or focus sits outside the active scope: move\n // to the first (next) or last (previous).\n index = delta > 0 ? focusables.length - 1 : 0;\n }\n const next = focusables[(index + delta + focusables.length) % focusables.length];\n return this.focus(next, 'keyboard');\n }\n\n /**\n * The tab stops in document order (parent before children).\n *\n * Tab stops and not every focusable node: a container with\n * `tabStop: false` can hold focus and is not a place the cycle\n * stops, which is what lets a dialog body be the keyboard's home of\n * last resort without becoming a stop of its own.\n */\n private collectFocusable(): UiNode[] {\n const result: UiNode[] = [];\n const visit = (node: UiNode): void => {\n if (isNodeTabStop(node)) {\n result.push(node);\n }\n for (let child = node.firstChild; child !== null; child = child.nextSibling) {\n visit(child);\n }\n };\n visit(this.scopeRoot);\n return result;\n }\n\n /** Whether the node may hold focus given the active scope, if any. */\n private withinScope(node: UiNode): boolean {\n return this.scopes.length === 0 || this.isWithin(node, this.scopeRoot);\n }\n\n /** Whether the node is still connected to the traversal root. */\n private isAttached(node: UiNode): boolean {\n return this.isWithin(node, this.root);\n }\n\n private isWithin(node: UiNode, ancestor: UiNode): boolean {\n for (let current: UiNode | null = node; current !== null; current = current.parent) {\n if (current === ancestor) {\n return true;\n }\n }\n return false;\n }\n}\n","import type { UiNode } from '../graph/UiNode';\nimport {\n MOUSE_POINTER,\n noKeyModifiers,\n UiEventType,\n UiPointerEvent,\n type UiKeyModifiers,\n type UiPointerDevice\n} from './UiInputEvent';\nimport type { HitTester } from './UiHitTester';\nimport { UiInputDispatcher } from './UiInputDispatcher';\nimport type { GestureInput } from './UiGestureRecognizer';\nimport type { ScrollSink } from './UiWheelController';\nimport type { ScrollbarAxis } from '../layout/Scrollbars';\n\nexport interface PointerControllerOptions {\n /**\n * Maximum distance (px) a press may travel between pointerdown and\n * pointerup and still count as a Click.\n */\n slop?: number;\n /**\n * The same allowance for a finger.\n *\n * A tap is not a click held still. The contact point moves as the\n * finger flattens and lifts, and four pixels of travel — the mouse\n * allowance — is routinely exceeded by a tap the person considers\n * perfectly stationary. At that threshold a touchscreen loses\n * roughly every other tap, silently: the PointerUp fires and no\n * Click follows it.\n */\n touchSlop?: number;\n /**\n * Optional gesture recognizer fed the press sequence. When a\n * gesture is claimed, Click synthesis is suppressed.\n */\n gestures?: GestureInput;\n /**\n * Invoked after a successful (not defaultPrevented) pointerdown on\n * a node. Applications wire focus-on-press here, e.g. forwarding to\n * a focus manager's `focusOnPress`.\n */\n onPress?: (node: UiNode) => void;\n /**\n * Scrolling backend for scrollbar interaction: dragging a thumb,\n * paging on a track press, and revealing bars as the pointer nears\n * them. Without it scrollbars are display only.\n */\n scrollSink?: ScrollSink;\n /**\n * Invoked when the hovered node changes, after the PointerLeave and\n * PointerEnter events have been dispatched. The layout inspector\n * follows the pointer through this.\n */\n onHoverChange?: (node: UiNode | null) => void;\n /**\n * Default pointer behaviour for editable text: a press places the\n * caret (or selects a word, a line), a drag extends the selection.\n * Applied after the app's listeners, and skipped when the pointerdown\n * was defaultPrevented.\n */\n editing?: {\n isEditable(node: UiNode): boolean;\n pointerDown(node: UiNode, x: number, y: number, modifiers: UiKeyModifiers): void;\n pointerMove(node: UiNode, x: number, y: number): void;\n pointerUp(): void;\n };\n /**\n * Default pointer behaviour for text nobody types into: a press on\n * it starts a selection, a drag extends it, a press anywhere else\n * clears it. Applied after the app's listeners, on the same terms as\n * `editing`, and never for a press that landed on an editable —\n * that one has its own selection.\n *\n * The drag is fed raw canvas coordinates rather than the pressed\n * node, because a selection is the one gesture that has to cross\n * node boundaries while the press is captured.\n */\n selection?: {\n pointerDown(node: UiNode | null, x: number, y: number, modifiers: UiKeyModifiers): void;\n pointerMove(x: number, y: number): void;\n pointerUp(): void;\n clear(): void;\n /**\n * The pointer moved with nothing pressed. An inline link is a run\n * of a paragraph rather than a node, so its hover cannot come from\n * `onHoverChange`, which fires only when the node changes; the\n * point inside the node is the whole question.\n */\n pointerHover?(node: UiNode | null, x: number, y: number): void;\n };\n}\n\n/** A thumb drag in progress. */\ninterface ScrollbarDrag {\n node: UiNode;\n axis: ScrollbarAxis;\n /** Pointer position along the axis when the drag started. */\n startPointer: number;\n /** Scroll offset when the drag started. */\n startScroll: number;\n /** Scroll offset per pixel of thumb travel. */\n scale: number;\n}\n\n/**\n * Routes raw pointer input through the dispatcher.\n *\n * The platform adapter feeds it canvas-space positions; application\n * code never sees browser events.\n *\n * Model:\n * - Hover: while nothing is pressed, the pointer is hit-tested on\n * every move. PointerMove bubbles from the hovered node, and\n * PointerEnter / PointerLeave fire on the subtree boundary when\n * the hovered node changes (target-only, like mouseenter/leave).\n * - Press capture: from pointerdown until pointerup/cancel, every\n * pointer event is routed to the node the press started on, even\n * when the pointer leaves its box. This keeps drags and releases\n * owned by the pressed widget.\n * - Click: synthesized on pointerup when the press stayed within\n * `slop` px (`touchSlop` for a finger, which never holds as still\n * as a mouse), pointerdown did not call preventDefault(), and no\n * gesture recognizer claimed the press.\n * - pointercancel aborts the press and never produces a Click.\n * - Contacts: a press is owned by the contact that started it, and\n * the moves and releases of any other contact are ignored until it\n * ends. A second finger therefore cannot drag a widget the first\n * one is holding. Every contact is still *reported* to the gesture\n * recognizer, which is what a pinch is made of; being refused the\n * press and being unheard are two different things.\n * - Context menu: a press of the secondary button alone dispatches\n * PointerDown and then ContextMenu at the same point, and\n * establishes no press at all, so nothing is dragged, nothing is\n * focused and no Click follows the release. A finger asks for the\n * same thing by holding, which the gesture recognizer answers.\n * - Touch hover: a finger's hover is dropped when it lifts, because\n * the finger is no longer anywhere. A mouse keeps its hover.\n * - Scrollbars: a press on a scroll container's thumb starts a drag\n * that moves the content with the pointer; a press on the track\n * beside a visible thumb pages one viewport toward the pointer.\n * Neither reaches the content under the bar. Nearing a bar while\n * idle reveals it.\n *\n * When a gesture recognizer is supplied it is fed the press sequence\n * and synthesizes LongPress/Pan/Drag through the same dispatcher.\n *\n * The controller is single-press: a pointerdown while already\n * pressing is ignored.\n */\nexport class UiPointerController {\n private readonly slop: number;\n private readonly touchSlop: number;\n private readonly gestures: GestureInput | null;\n private readonly onPress: ((node: UiNode) => void) | null;\n private readonly scrollSink: ScrollSink | null;\n private readonly onHoverChange: ((node: UiNode | null) => void) | null;\n private readonly editing: PointerControllerOptions['editing'];\n private readonly selection: PointerControllerOptions['selection'];\n\n private hoverNode: UiNode | null = null;\n\n private downTarget: UiNode | null = null;\n private downX = 0;\n private downY = 0;\n private downDefaultPrevented = false;\n /**\n * The contact that owns the press in progress, or null when idle.\n *\n * Everything from the pointerdown to the release is routed by this\n * id. Without it a second finger landing on the canvas mid-drag\n * feeds its own moves to the node the *first* finger pressed, and\n * the drag jumps between the two contacts.\n */\n private activePointer: UiPointerDevice | null = null;\n\n private scrollbarDrag: ScrollbarDrag | null = null;\n\n constructor(\n private readonly hitTester: HitTester,\n private readonly dispatcher: UiInputDispatcher,\n options: PointerControllerOptions = {}\n ) {\n this.slop = options.slop ?? 4;\n this.touchSlop = options.touchSlop ?? 10;\n this.gestures = options.gestures ?? null;\n this.onPress = options.onPress ?? null;\n this.scrollSink = options.scrollSink ?? null;\n this.onHoverChange = options.onHoverChange ?? null;\n this.editing = options.editing;\n this.selection = options.selection;\n }\n\n /** The node currently under the pointer, or null over empty space. */\n /** Where the pointer was last seen, in canvas space; null before it has been. */\n get position(): { readonly x: number; readonly y: number } | null {\n return this.lastPosition;\n }\n\n private lastPosition: { x: number; y: number } | null = null;\n\n get hoveredNode(): UiNode | null {\n return this.hoverNode;\n }\n\n /** The node the current press started on, or null when idle. */\n get pressedNode(): UiNode | null {\n return this.downTarget;\n }\n\n /** The scroll container whose thumb is being dragged, or null. */\n get draggingScrollbarOf(): UiNode | null {\n return this.scrollbarDrag?.node ?? null;\n }\n\n /**\n * Pointer press. Hit-tests at the point, establishes hover, and\n * dispatches PointerDown to the pressed node. Subsequent moves and\n * the up are routed to that node until release.\n */\n pointerDown(\n x: number,\n y: number,\n buttons = 1,\n modifiers: UiKeyModifiers = noKeyModifiers(),\n pointer: UiPointerDevice = MOUSE_POINTER\n ): UiPointerEvent {\n this.lastPosition = { x, y };\n const event = new UiPointerEvent(UiEventType.PointerDown, x, y, buttons, modifiers, pointer);\n if (this.downTarget !== null || this.scrollbarDrag !== null) {\n // The press stays with the contact that started it. The contact\n // is still reported, because \"a second finger landed\" is exactly\n // what a pinch is made of, and dropping it here is what\n // left touch input unfinished.\n this.gestures?.contactDown?.(pointer, x, y, this.downTarget, modifiers);\n return event;\n }\n const hit = this.hitTester.hitTest(x, y);\n if (hit?.scrollbar !== undefined && this.scrollSink !== null) {\n this.activePointer = pointer;\n this.pressScrollbar(hit.node, hit.scrollbar.axis, hit.scrollbar.onThumb, x, y);\n return event;\n }\n const target = hit?.node ?? null;\n this.updateHover(target, x, y, buttons, modifiers, pointer);\n if (target !== null && isSecondaryButton(buttons)) {\n // A right press is a question, not a gesture: it asks what can be\n // done with the node under it. No press is established, so no\n // drag begins, no Click is synthesized on the release and the\n // focus a left press would have taken is left where it was.\n this.dispatcher.dispatch(event, target);\n if (!event.defaultPrevented) {\n this.dispatcher.dispatch(\n new UiPointerEvent(UiEventType.ContextMenu, x, y, buttons, modifiers, pointer),\n target\n );\n }\n return event;\n }\n this.gestures?.contactDown?.(pointer, x, y, target, modifiers);\n if (target !== null) {\n this.dispatcher.dispatch(event, target);\n this.gestures?.pointerDown(event, target);\n if (!event.defaultPrevented) {\n this.onPress?.(target);\n if (this.editing !== undefined && this.editing.isEditable(target)) {\n this.editing.pointerDown(target, x, y, modifiers);\n this.selection?.clear();\n } else {\n this.selection?.pointerDown(target, x, y, modifiers);\n }\n }\n } else {\n // A press on empty space drops the selection, as it does on a page.\n this.selection?.pointerDown(null, x, y, modifiers);\n }\n this.downTarget = target;\n this.downX = x;\n this.downY = y;\n this.downDefaultPrevented = event.defaultPrevented;\n this.activePointer = pointer;\n return event;\n }\n\n /**\n * Pointer movement. While a press is active the move is routed to\n * the pressed node (capture); otherwise it hit-tests, updates\n * hover enter/leave, and dispatches PointerMove to the hovered\n * node. Returns null when the move lands on empty space.\n */\n pointerMove(\n x: number,\n y: number,\n buttons = 0,\n modifiers: UiKeyModifiers = noKeyModifiers(),\n pointer: UiPointerDevice = MOUSE_POINTER\n ): UiPointerEvent | null {\n this.lastPosition = { x, y };\n this.gestures?.contactMove?.(pointer, x, y);\n if (!this.ownsPress(pointer)) {\n return null;\n }\n if (this.scrollbarDrag !== null) {\n this.dragScrollbar(x, y);\n return null;\n }\n if (this.downTarget !== null) {\n const event = new UiPointerEvent(UiEventType.PointerMove, x, y, buttons, modifiers, pointer);\n this.dispatcher.dispatch(event, this.downTarget);\n this.gestures?.pointerMove(event, this.downTarget);\n if (!event.defaultPrevented) {\n if (this.editing !== undefined && this.editing.isEditable(this.downTarget)) {\n this.editing.pointerMove(this.downTarget, x, y);\n } else if (!this.downDefaultPrevented) {\n // A press the app cancelled started no selection, so the\n // moves after it are not extending one either.\n this.selection?.pointerMove(x, y);\n }\n }\n return event;\n }\n if (this.scrollSink?.revealScrollbars !== undefined) {\n // Nearing a bar shows it, so there is something to grab.\n const zone = this.hitTester.scrollbarZoneAt(x, y);\n if (zone !== null) {\n this.scrollSink.revealScrollbars(zone.node);\n }\n }\n const target = this.hitTester.hitTest(x, y)?.node ?? null;\n this.updateHover(target, x, y, buttons, modifiers, pointer);\n this.selection?.pointerHover?.(target, x, y);\n if (target === null) {\n return null;\n }\n const event = new UiPointerEvent(UiEventType.PointerMove, x, y, buttons, modifiers, pointer);\n this.dispatcher.dispatch(event, target);\n return event;\n }\n\n /**\n * Pointer release. Dispatches PointerUp to the pressed node and,\n * when the press did not travel beyond the slop and was not\n * cancelled via preventDefault on the down, synthesizes a Click on\n * the same node. Returns null when nothing was pressed.\n */\n pointerUp(\n x: number,\n y: number,\n buttons = 0,\n modifiers: UiKeyModifiers = noKeyModifiers(),\n pointer: UiPointerDevice = MOUSE_POINTER\n ): UiPointerEvent | null {\n this.gestures?.contactUp?.(pointer);\n if (!this.ownsPress(pointer)) {\n return null;\n }\n if (this.scrollbarDrag !== null) {\n this.dragScrollbar(x, y);\n this.scrollbarDrag = null;\n this.activePointer = null;\n return null;\n }\n const target = this.downTarget;\n if (target === null) {\n return null;\n }\n this.downTarget = null;\n this.activePointer = null;\n this.editing?.pointerUp();\n this.selection?.pointerUp();\n\n const event = new UiPointerEvent(UiEventType.PointerUp, x, y, buttons, modifiers, pointer);\n this.dispatcher.dispatch(event, target);\n this.gestures?.pointerUp(event, target);\n\n const gestureClaimed = this.gestures?.claimed() ?? false;\n if (!this.downDefaultPrevented && !gestureClaimed) {\n const dx = Math.abs(x - this.downX);\n const dy = Math.abs(y - this.downY);\n const slop = pointer.kind === 'touch' ? this.touchSlop : this.slop;\n if (dx <= slop && dy <= slop) {\n const click = new UiPointerEvent(UiEventType.Click, x, y, buttons, modifiers, pointer);\n this.dispatcher.dispatch(click, target);\n }\n }\n this.releaseHover(x, y, modifiers, pointer);\n return event;\n }\n\n /**\n * Aborts the active press: dispatches PointerCancel to the pressed\n * node and clears press state so no Click is synthesized.\n */\n pointerCancel(pointer: UiPointerDevice = MOUSE_POINTER): void {\n this.gestures?.contactUp?.(pointer);\n if (!this.ownsPress(pointer)) {\n return;\n }\n this.scrollbarDrag = null;\n this.editing?.pointerUp();\n this.selection?.pointerUp();\n const target = this.downTarget;\n this.downTarget = null;\n this.activePointer = null;\n if (target === null) {\n return;\n }\n const event = new UiPointerEvent(UiEventType.PointerCancel, this.downX, this.downY, 0, noKeyModifiers(), pointer);\n this.dispatcher.dispatch(event, target);\n this.gestures?.pointerCancel();\n this.releaseHover(this.downX, this.downY, noKeyModifiers(), pointer);\n }\n\n /**\n * Whether an event from this contact should be acted on.\n *\n * While a press is in flight only the contact that started it is\n * heard; a second finger's moves and releases are dropped. When\n * nothing is pressed every contact is heard, so hover still follows\n * a mouse that never pressed anything.\n */\n private ownsPress(pointer: UiPointerDevice): boolean {\n return this.activePointer === null || this.activePointer.id === pointer.id;\n }\n\n // -------------------------------------------------------------------------\n // Scrollbars\n // -------------------------------------------------------------------------\n\n /**\n * A press on the thumb starts a drag that maps pointer travel to\n * scroll offset through the thumb's travel range. A press on the\n * track pages one viewport toward the pointer, as classic scrollbars\n * do.\n */\n private pressScrollbar(node: UiNode, axis: ScrollbarAxis, onThumb: boolean, x: number, y: number): void {\n const sink = this.scrollSink!;\n const state = sink.containerState(node);\n const bar = sink.scrollbar?.(node, axis) ?? null;\n if (state === undefined || bar === null) {\n return;\n }\n sink.revealScrollbars?.(node);\n const scroll = axis === 'y' ? state.scrollY : state.scrollX;\n if (onThumb) {\n this.scrollbarDrag = {\n node,\n axis,\n startPointer: axis === 'y' ? y : x,\n startScroll: scroll,\n scale: bar.travel > 0 ? bar.maxScroll / bar.travel : 0\n };\n return;\n }\n // The thumb is in the container's record space; so is the pointer\n // once mapped with toLocal (which is relative to the record origin).\n const local = this.hitTester.toLocal(node, x, y);\n const pointer = axis === 'y' ? local.y : local.x;\n const thumbStartLocal =\n axis === 'y' ? bar.thumb.y - this.recordOrigin(node, 'y') : bar.thumb.x - this.recordOrigin(node, 'x');\n const delta = (pointer < thumbStartLocal ? -1 : 1) * bar.viewport;\n // Animated, for the reason a wheel notch is: pressing the track\n // moves a whole screenful at once, and a screenful arriving\n // instantly gives no sense of which way the content went. A thumb\n // *drag* stays instant and must — it recomputes an absolute target\n // from pointer travel on every move and reads the current offset\n // back, so an animation in flight would have it chasing a position\n // the container is only passing through.\n if (axis === 'y') {\n sink.scrollBy(node, 0, delta, 'smooth');\n } else {\n sink.scrollBy(node, delta, 0, 'smooth');\n }\n }\n\n /**\n * The record origin along an axis, recovered from toLocal: local\n * coordinates are record coordinates minus the record origin, so\n * mapping the origin itself yields the offset.\n */\n private recordOrigin(node: UiNode, axis: ScrollbarAxis): number {\n const zero = this.hitTester.toLocal(node, 0, 0);\n return axis === 'y' ? -zero.y : -zero.x;\n }\n\n private dragScrollbar(x: number, y: number): void {\n const drag = this.scrollbarDrag!;\n const sink = this.scrollSink!;\n const state = sink.containerState(drag.node);\n if (state === undefined) {\n return;\n }\n const pointer = drag.axis === 'y' ? y : x;\n const target = drag.startScroll + (pointer - drag.startPointer) * drag.scale;\n const current = drag.axis === 'y' ? state.scrollY : state.scrollX;\n const max = drag.axis === 'y' ? state.maxScrollY : state.maxScrollX;\n const clamped = Math.min(Math.max(target, 0), max);\n if (clamped !== current) {\n if (drag.axis === 'y') {\n sink.scrollBy(drag.node, 0, clamped - current);\n } else {\n sink.scrollBy(drag.node, clamped - current, 0);\n }\n }\n sink.revealScrollbars?.(drag.node);\n }\n\n // -------------------------------------------------------------------------\n // Hover enter/leave\n // -------------------------------------------------------------------------\n\n /**\n * Reconciles the hovered node after a hit-test change.\n *\n * Ancestor chains are compared as sets: the nodes present in the\n * previous chain but not the next get PointerLeave, and vice versa\n * for PointerEnter. This yields exactly the subtree boundary\n * between the two hovered nodes (the lowest common ancestor is\n * shared and never fires), matching mouseenter/mouseleave.\n */\n private updateHover(\n next: UiNode | null,\n x: number,\n y: number,\n buttons: number,\n modifiers: UiKeyModifiers,\n pointer: UiPointerDevice\n ): void {\n if (next === this.hoverNode) {\n return;\n }\n const previous = this.hoverNode;\n this.hoverNode = next;\n\n if (previous !== null) {\n const nextChain = next === null ? new Set<UiNode>() : new Set(this.chain(next));\n for (const node of this.chain(previous)) {\n if (nextChain.has(node)) {\n break;\n }\n this.dispatchBoundary(UiEventType.PointerLeave, node, x, y, buttons, modifiers, pointer);\n }\n }\n if (next !== null) {\n const previousChain = previous === null ? new Set<UiNode>() : new Set(this.chain(previous));\n for (const node of this.chain(next)) {\n if (previousChain.has(node)) {\n break;\n }\n this.dispatchBoundary(UiEventType.PointerEnter, node, x, y, buttons, modifiers, pointer);\n }\n }\n this.onHoverChange?.(next);\n }\n\n /** The node itself followed by its ancestors, innermost first. */\n private chain(node: UiNode): UiNode[] {\n const chain: UiNode[] = [];\n for (let current: UiNode | null = node; current !== null; current = current.parent) {\n chain.push(current);\n }\n return chain;\n }\n\n private dispatchBoundary(\n type: UiEventType,\n node: UiNode,\n x: number,\n y: number,\n buttons: number,\n modifiers: UiKeyModifiers,\n pointer: UiPointerDevice\n ): void {\n const event = new UiPointerEvent(type, x, y, buttons, modifiers, pointer);\n this.dispatcher.dispatch(event, node);\n }\n\n /**\n * Drops hover when the contact that had it has left the surface.\n *\n * A finger stops existing when it lifts. A mouse does not, so its\n * hover survives the release and the node it was released over stays\n * hovered — which is what a mouse user sees and expects.\n *\n * Without this a tap leaves the tapped node hovered for good: every\n * hover affordance in the app stays lit under the last thing touched,\n * and the next tap somewhere else moves the stuck highlight rather\n * than clearing it. It is the most visible thing that goes wrong when\n * a canvas UI meets a touchscreen.\n */\n private releaseHover(x: number, y: number, modifiers: UiKeyModifiers, pointer: UiPointerDevice): void {\n if (pointer.kind !== 'touch') {\n return;\n }\n this.updateHover(null, x, y, 0, modifiers, pointer);\n }\n}\n\n/**\n * Whether the pressed buttons are the secondary one and nothing else.\n *\n * The DOM's `buttons` bitmask, where 2 is the right button. Read as an\n * exact value rather than a bit test on purpose: a press with the left\n * and right buttons together is a press, and treating it as a menu\n * request would take the drag away from anyone whose hand rests on\n * both.\n */\nfunction isSecondaryButton(buttons: number): boolean {\n return buttons === 2;\n}\n","import type { UiNode } from '../graph/UiNode';\nimport { UiNodeType } from '../graph/UiNodeType';\nimport { noKeyModifiers, UiEventType, UiKeyboardEvent, UiPointerEvent, type UiKeyModifiers } from './UiInputEvent';\nimport { isNodeInert } from './UiInteraction';\nimport type { UiInputDispatcher } from './UiInputDispatcher';\nimport type { UiFocusManager } from './UiFocusManager';\n\nexport interface KeyboardControllerOptions {\n /**\n * Whether Tab / Shift+Tab drive focus navigation (default true).\n * Set false to leave Tab to application listeners.\n */\n tabNavigation?: boolean;\n /**\n * Default keyboard behaviour for a focused editable: caret movement,\n * deletion, undo, and typing when no shell proxy supplies text. Runs\n * after the app's KeyDown listeners and only if none called\n * preventDefault(); a key it handles is marked default-prevented.\n */\n editing?: { handleKey(node: UiNode, key: string, modifiers: UiKeyModifiers): boolean };\n /**\n * Default keyboard behaviour for a canvas text selection: copy it,\n * select everything, or clear it. Runs only when no focused editable\n * claimed the key first, so Cmd/Ctrl+A and Cmd/Ctrl+C inside a field\n * still belong to the field.\n */\n selection?: { handleKey(key: string, modifiers: UiKeyModifiers): boolean };\n /**\n * Default keyboard behaviour for find: Cmd/Ctrl+F opens a session,\n * Escape closes one. Runs before the selection's, so Escape ends the\n * find rather than clearing the match it has selected.\n */\n find?: { handleKey(key: string, modifiers: UiKeyModifiers): boolean };\n /**\n * Where a keyboard press lands on a node, for the click Enter or Space\n * synthesises on a focused button: its centre, when the host can lay\n * hands on a layout box. Without it the click is at the node's origin,\n * which every `onClick` that ignores its coordinates is fine with.\n */\n activation?: { clickAt(node: UiNode): { x: number; y: number } };\n}\n\n/**\n * Routes keyboard input through the dispatcher.\n *\n * KeyDown/KeyUp are dispatched to the focused node and bubble up the\n * tree, so a container can handle keys for its focused child. When\n * nothing is focused, events are routed to the root node so\n * application-level key handling still works. The root may be given as\n * a getter, for a host whose root is rebuilt while the controller\n * lives (a reload) or that wants keys to land on the application's own\n * root rather than the layout root it is wrapped in: an event\n * dispatched to a node bubbles to its ancestors, so nothing above the\n * chosen root is left out.\n *\n * Default behaviour (cancelled by preventDefault on the KeyDown), in\n * order: the focused editable's editing keys, then find's open/close,\n * then the canvas text selection's copy / select-all / clear, then\n * Enter or Space pressing a focused button (a `Button`, or a node whose\n * role is `button` or `link`) as a click, then Tab moving focus to the\n * next focusable node and Shift+Tab to the previous, wrapping around.\n *\n * The button press is the one a keyboard-only or screen-reader user\n * relies on: every control in the component library binds its own keys,\n * but a plain `Button` element did not press on Enter until the\n * keyboard gallery (`Keyboard.spec.ts` in the components package) tabbed\n * to one and found it inert.\n */\nconst MODIFIER_KEYS: ReadonlySet<string> = new Set(['Shift', 'Control', 'Alt', 'Meta', 'CapsLock']);\n\nexport class UiKeyboardController {\n private readonly tabNavigation: boolean;\n private readonly editing: KeyboardControllerOptions['editing'];\n private readonly selection: KeyboardControllerOptions['selection'];\n private readonly find: KeyboardControllerOptions['find'];\n private readonly activation: KeyboardControllerOptions['activation'];\n\n private readonly root: () => UiNode;\n\n constructor(\n private readonly dispatcher: UiInputDispatcher,\n private readonly focusManager: UiFocusManager,\n root: UiNode | (() => UiNode),\n options: KeyboardControllerOptions = {}\n ) {\n this.root = typeof root === 'function' ? root : () => root;\n this.tabNavigation = options.tabNavigation ?? true;\n this.editing = options.editing;\n this.selection = options.selection;\n this.find = options.find;\n this.activation = options.activation;\n }\n\n keyDown(key: string, modifiers: UiKeyModifiers = noKeyModifiers()): UiKeyboardEvent {\n // A key makes focus visible again after a mouse press, as\n // `:focus-visible` does. A modifier on its own does not count: it is\n // held for a click as often as for a shortcut.\n if (!MODIFIER_KEYS.has(key)) {\n this.focusManager.noteInput('keyboard');\n }\n const event = new UiKeyboardEvent(UiEventType.KeyDown, key, modifiers);\n const focused = this.focusManager.focusedNode;\n const target = focused ?? this.root();\n this.dispatcher.dispatch(event, target);\n if (\n !event.defaultPrevented &&\n focused !== null &&\n this.editing !== undefined &&\n this.editing.handleKey(focused, key, modifiers)\n ) {\n event.preventDefault();\n return event;\n }\n if (!event.defaultPrevented && this.find !== undefined && this.find.handleKey(key, modifiers)) {\n event.preventDefault();\n return event;\n }\n if (!event.defaultPrevented && this.selection !== undefined && this.selection.handleKey(key, modifiers)) {\n event.preventDefault();\n return event;\n }\n if (!event.defaultPrevented && focused !== null && (key === 'Enter' || key === ' ') && isPressable(focused)) {\n // What Enter and Space do to a focused button everywhere else:\n // press it. A synthesised click, so the button's `onClick` is the\n // one handler an author writes, for the pointer and the keyboard\n // and an assistive technology alike (`GessoRuntime.applySemanticsAction`\n // sends the same event).\n const at = this.activation?.clickAt(focused) ?? { x: 0, y: 0 };\n this.dispatcher.dispatch(new UiPointerEvent(UiEventType.Click, at.x, at.y, 1), focused);\n event.preventDefault();\n return event;\n }\n if (!event.defaultPrevented && this.tabNavigation && key === 'Tab') {\n if (modifiers.shift) {\n this.focusManager.focusPrevious();\n } else {\n this.focusManager.focusNext();\n }\n }\n return event;\n }\n\n keyUp(key: string, modifiers: UiKeyModifiers = noKeyModifiers()): UiKeyboardEvent {\n const event = new UiKeyboardEvent(UiEventType.KeyUp, key, modifiers);\n const target = this.focusManager.focusedNode ?? this.root();\n this.dispatcher.dispatch(event, target);\n return event;\n }\n}\n\n/** A focused node Enter and Space press: a Button, or anything playing one that is not inert. */\nfunction isPressable(node: UiNode): boolean {\n if (isNodeInert(node)) {\n return false;\n }\n const role = node.properties.get('role');\n return node.type === UiNodeType.Button || role === 'button' || role === 'link';\n}\n","import { UiNodeType } from '../graph/UiNodeType';\nimport type { UiNode } from '../graph/UiNode';\nimport { noKeyModifiers, UiEventType, UiWheelDeltaMode, UiWheelEvent, type UiKeyModifiers } from './UiInputEvent';\nimport type { HitTester } from './UiHitTester';\nimport type { ScrollbarThumb } from '../layout/Scrollbars';\nimport type { UiInputDispatcher } from './UiInputDispatcher';\n\n/**\n * Scroll projection of a scroll container queried by the wheel\n * controller so it can decide how a wheel delta maps onto the\n * container's scroll axis.\n */\nexport interface ScrollContainerState {\n scrollX: number;\n scrollY: number;\n maxScrollX: number;\n maxScrollY: number;\n /**\n * True when the container lays its children out in a row.\n *\n * The wheel no longer reads this: it asks each axis whether it has\n * room, so a container that overflows both ways takes both deltas.\n * `UiTouchScroller` still reads it to pick the axis a drag and its\n * inertia run along, which is a single-axis model — a two-axis\n * container is panned on whichever axis this names.\n */\n horizontal: boolean;\n /**\n * The visible extent, which is what a page-mode wheel delta means.\n *\n * Optional because a wheel that reports its deltas in pixels — every\n * wheel on Chrome, and every trackpad everywhere — never needs it,\n * and a sink written before page mode existed should not have to\n * grow a field to keep compiling. A page delta with no extent falls\n * back to a screenful of lines.\n */\n viewportWidth?: number;\n viewportHeight?: number;\n}\n\n/**\n * A line, in pixels, for a wheel that measures its deltas in lines.\n *\n * There is no API that says what a line is, so this is a choice: one\n * line of default body text, near enough. Firefox reports three of\n * them per notch, which lands close to the distance a notch moves a\n * document there.\n */\nconst LINE_HEIGHT_PX = 16;\n\n/**\n * Bridges wheel scroll consumption to the layout system. The app\n * layer provides an implementation backed by LayoutEngine (or the\n * scheduler's incremental scroll-only pass); tests use a harness\n * sink. The sink owns clamping and re-layout after a scroll.\n */\nexport interface ScrollSink {\n containerState(node: UiNode): ScrollContainerState | undefined;\n /**\n * Moves the container, either at once or over time.\n *\n * `behavior` is a hint and defaults to `'instant'`, which is what\n * every caller but the wheel wants and what a sink that does not\n * animate should do with `'smooth'` as well. Animating belongs to\n * the sink rather than to a caller stepping this in a loop: a\n * playground harness sink echoes every write to another thread, and\n * a scrollbar thumb drag reads the offset back on each pointer move,\n * so a caller-driven animation would drive both of those too.\n */\n scrollBy(node: UiNode, dx: number, dy: number, behavior?: UiScrollBehavior): void;\n /**\n * Every scroll container currently laid out, in no order.\n *\n * Only the tree-level question needs this — \"does this runtime\n * scroll at all\", which is what a touchscreen's `touch-action` has\n * to be set from, since that is latched before the finger lands and\n * there is no position to ask about yet. Optional, so a sink\n * written before this existed still compiles; a sink that omits it\n * is read as scrolling nothing.\n */\n scrollContainers?(): Iterable<UiNode>;\n /** Show the container's scrollbars, as hovering near them or dragging one does. */\n revealScrollbars?(node: UiNode): void;\n /** Geometry of one scrollbar, for dragging its thumb. */\n scrollbar?(node: UiNode, axis: 'x' | 'y'): ScrollbarThumb | null;\n}\n\n/** Whether a scroll lands at once or is animated to its destination. */\nexport type UiScrollBehavior = 'instant' | 'smooth';\n\n/**\n * Which way a wheel at some point would move something in the\n * runtime.\n *\n * Four directions rather than one flag because the interesting case\n * is a container at an edge: a list scrolled to its top has to keep\n * upward wheels away from itself and hand them to the page, and\n * answering \"is anything scrollable here\" with a single boolean gets\n * that exactly backwards.\n */\nexport interface UiScrollability {\n up: boolean;\n down: boolean;\n left: boolean;\n right: boolean;\n}\n\n/** Nothing under the pointer takes a wheel in any direction. */\nconst NOTHING_SCROLLABLE: UiScrollability = Object.freeze({\n up: false,\n down: false,\n left: false,\n right: false\n});\n\n/** Every direction is kept, which is what containing overscroll means. */\nconst EVERYTHING_SCROLLABLE: UiScrollability = Object.freeze({\n up: true,\n down: true,\n left: true,\n right: true\n});\n\n/**\n * How much remaining range still counts as room to scroll.\n *\n * Offsets are floats — a fractional device pixel ratio and a clamped\n * scroll both produce them — so an exact comparison against the\n * maximum leaves a container permanently a hair off its own edge,\n * claiming room it cannot use. Half a pixel is below anything a\n * person can see move and well above that noise.\n */\nconst SCROLL_EPSILON = 0.5;\n\n/** Whether an offset can still move in the direction `delta` points. */\nexport function hasScrollRoom(offset: number, max: number, delta: number): boolean {\n return delta > 0 ? offset < max - SCROLL_EPSILON : offset > SCROLL_EPSILON;\n}\n\n/** Whether this node keeps overscroll rather than chaining it outwards. */\nfunction containsOverscroll(node: UiNode | null): boolean {\n return node !== null && node.getProperty('overscrollBehavior') === 'contain';\n}\n\n/** The topmost ancestor of a node — the app root, in a mounted tree. */\nfunction rootOf(node: UiNode): UiNode {\n let current = node;\n while (current.parent !== null) {\n current = current.parent;\n }\n return current;\n}\n\n/**\n * Whether this wheel event came from something with detents.\n *\n * Only a notched wheel is worth animating. It delivers one large jump\n * per detent and nothing in between, which is the whole of the problem\n * smooth scrolling solves. A trackpad already delivers a fine-grained\n * inertial stream from the operating system, and animating that would\n * integrate an inertia curve on top of one — a rubbery lag laid over\n * scrolling that was already smooth, which is worse than the jumps.\n *\n * There is no honest way to *ask* what a device is, so this reads the\n * evidence a `WheelEvent` carries and **only smooths on a positive\n * answer**:\n *\n * - A delta measured in lines or pages is never a precision device.\n * - `wheelDeltaY` is the legacy field, and a detented wheel reports\n * it in multiples of 120. A precision device does not.\n *\n * Anything else is treated as precise, so the failure direction is the\n * behaviour that shipped before this existed.\n */\nexport function isNotchedWheel(deltaMode: UiWheelDeltaMode, wheelDeltaY: number | undefined): boolean {\n if (deltaMode !== UiWheelDeltaMode.Pixel) {\n return true;\n }\n if (wheelDeltaY === undefined) {\n return false;\n }\n const magnitude = Math.abs(wheelDeltaY);\n // Half a detent is not one. This is what keeps a trackpad's small\n // deltas out, since the test below would otherwise read anything\n // near zero as a whole number of detents.\n if (magnitude < NOTCH_WHEEL_DELTA / 2) {\n return false;\n }\n const remainder = magnitude % NOTCH_WHEEL_DELTA;\n return remainder <= NOTCH_TOLERANCE || NOTCH_WHEEL_DELTA - remainder <= NOTCH_TOLERANCE;\n}\n\n/** What a detent is worth in the legacy `wheelDelta` field. */\nconst NOTCH_WHEEL_DELTA = 120;\n/**\n * How far off a whole detent still counts as one.\n *\n * An exact multiple is too much to ask, and real hardware said so: the\n * same mouse reports `wheelDeltaY` of exactly -120 on one monitor and\n * **-119** on another, with a `deltaY` of 119.99999642372141 rather\n * than a round number. Chrome scales a wheel delta per display, and\n * the scaled value is truncated on its way into the legacy field. An\n * equality test therefore classified every notch on that display as a\n * precision device and scrolling never smoothed at all.\n *\n * Five percent of a detent, which is far tighter than the gap to\n * anything a trackpad sends and loose enough for that scaling.\n */\nconst NOTCH_TOLERANCE = 6;\n\n/**\n * Routes wheel input. Dispatches a bubbling Wheel event to the node\n * under the pointer, then, unless the event was defaultPrevented,\n * walks the scroll chain from that node outwards and gives the delta\n * to the first container with room for it. preventDefault() on Wheel\n * therefore opts out of automatic scroll consumption.\n *\n * The returned event says whether anything took the delta, via\n * `consumed`. A shell needs that answer to decide whether to prevent\n * the browser's default: a canvas that prevents unconditionally is a\n * scroll trap on the page around it, and one that never prevents lets\n * a scroll happen twice.\n */\nexport class UiWheelController {\n constructor(\n private readonly hitTester: HitTester,\n private readonly dispatcher: UiInputDispatcher,\n private readonly scrollSink: ScrollSink,\n /**\n * The tree's root, when the host knows it.\n *\n * Only `scrollsAnything()` needs it, and only to honour an\n * `overscrollBehavior=\"contain\"` root in a tree that has no scroll\n * container to walk up from. Optional so every existing caller\n * still constructs; without it such a root is read as the default.\n */\n private readonly rootNode: (() => UiNode | null) | null = null\n ) {}\n\n /**\n * The node the last wheel landed on, or null before any.\n *\n * A wheel is evidence of where the pointer is, and sometimes the\n * only evidence there is: scrolling a page slides a canvas under a\n * cursor that never moved, so no pointer event ever told the\n * runtime it was hovered. A host reporting scrollability falls back\n * to this when nothing is hovered, which is what makes the second\n * wheel of a burst land correctly even though the first could not.\n */\n lastWheelTarget: UiNode | null = null;\n\n wheel(\n x: number,\n y: number,\n deltaX: number,\n deltaY: number,\n modifiers: UiKeyModifiers = noKeyModifiers(),\n deltaMode: UiWheelDeltaMode = UiWheelDeltaMode.Pixel,\n wheelDeltaY?: number\n ): UiWheelEvent {\n const target = this.hitTester.hitTest(x, y)?.node ?? null;\n this.lastWheelTarget = target;\n const event = new UiWheelEvent(UiEventType.Wheel, x, y, deltaX, deltaY, modifiers, deltaMode, wheelDeltaY);\n if (target !== null) {\n this.dispatcher.dispatch(event, target);\n }\n if (!event.defaultPrevented && target !== null) {\n this.scrollChain(target, event, deltaX, deltaY, deltaMode, wheelDeltaY);\n }\n return event;\n }\n\n /**\n * Whether a wheel at this point would move anything, without moving\n * it.\n *\n * The same walk `wheel()` does, stopping short of scrolling. It\n * exists for a shell that has to answer *before* the delta arrives:\n * one driving the runtime across a worker boundary cannot ask\n * synchronously inside a DOM wheel handler, and a touchscreen's\n * `touch-action` has to be set in CSS before the finger lands. Both\n * read this after a pointer move and cache the answer.\n *\n * Application listeners are not consulted — they are not run for a\n * question — so a handler that would call `preventDefault()` on the\n * real event is invisible here. That is a deliberate limit and the\n * safe direction: it can only under-report a trap, never invent one.\n */\n scrollabilityAt(x: number, y: number): UiScrollability {\n return this.scrollabilityOf(this.hitTester.hitTest(x, y)?.node ?? null);\n }\n\n /**\n * `scrollabilityAt` for a node already in hand.\n *\n * The runtime answers from the hovered node rather than a point,\n * since it has one and re-running a hit test to rediscover it would\n * be the same walk twice. A null node — the pointer over empty\n * space, or never yet moved — scrolls nothing.\n */\n scrollabilityOf(target: UiNode | null): UiScrollability {\n if (target === null) {\n // A root that contains its overscroll says nothing leaves the\n // canvas, and that has to hold before anything has been\n // hovered — otherwise a full-viewport app leaks its first wheel\n // to the page it is mounted in.\n return containsOverscroll(this.rootNode?.() ?? null) ? EVERYTHING_SCROLLABLE : NOTHING_SCROLLABLE;\n }\n let up = false;\n let down = false;\n let left = false;\n let right = false;\n for (let node: UiNode | null = target; node !== null; node = node.parent) {\n if (!isScrollContainer(node)) {\n continue;\n }\n const state = this.scrollSink.containerState(node);\n if (state === undefined) {\n continue;\n }\n left ||= hasScrollRoom(state.scrollX, state.maxScrollX, -1);\n right ||= hasScrollRoom(state.scrollX, state.maxScrollX, 1);\n up ||= hasScrollRoom(state.scrollY, state.maxScrollY, -1);\n down ||= hasScrollRoom(state.scrollY, state.maxScrollY, 1);\n if (containsOverscroll(node)) {\n // Nothing past here can be reached by chaining, so nothing\n // past here is worth reporting — and the contained node keeps\n // every direction whether or not it has room left.\n return EVERYTHING_SCROLLABLE;\n }\n }\n if (containsOverscroll(rootOf(target))) {\n return EVERYTHING_SCROLLABLE;\n }\n return { up, down, left, right };\n }\n\n /**\n * Whether anything in the tree scrolls at all.\n *\n * The coarse, position-free form of `scrollabilityAt`, and the only\n * one a touchscreen can use: `touch-action` is latched when the\n * finger lands, so there is no hover position to have asked about\n * and no later moment at which changing it would still count. A\n * runtime with nothing scrollable can hand every gesture to the\n * page; one with a scrollable container anywhere has to keep them,\n * because it cannot know yet where the finger will land.\n */\n scrollsAnything(): boolean {\n if (containsOverscroll(this.rootNode?.() ?? null)) {\n return true;\n }\n for (const node of this.scrollSink.scrollContainers?.() ?? []) {\n const state = this.scrollSink.containerState(node);\n if (state === undefined) {\n continue;\n }\n if (state.maxScrollX > SCROLL_EPSILON || state.maxScrollY > SCROLL_EPSILON) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * Gives the delta to the first container along the chain with room\n * for it, marking the event consumed when one takes it.\n *\n * \"Room\" means room in the direction of travel, not room for the\n * whole delta: a container part-way down its range takes a wheel\n * that would overshoot and clamps, which is what a browser does and\n * what keeps a fast flick from jumping out to the page.\n */\n private scrollChain(\n target: UiNode,\n event: UiWheelEvent,\n deltaX: number,\n deltaY: number,\n deltaMode: UiWheelDeltaMode,\n wheelDeltaY: number | undefined\n ): void {\n for (let node: UiNode | null = target; node !== null; node = node.parent) {\n if (!isScrollContainer(node)) {\n continue;\n }\n const state = this.scrollSink.containerState(node);\n if (state === undefined) {\n continue;\n }\n // Each axis is asked for separately, because a container may\n // scroll on both. A spreadsheet is the case that found this: its\n // viewport is one ScrollView whose content overflows in both\n // directions, and a container classified as one or the other\n // dropped every horizontal delta on the floor and then found no\n // horizontal container to chain to either. A container that\n // overflows on one axis only is unaffected — the axis it does\n // not scroll has no room, so it is not taken.\n const takesX = deltaX !== 0 && hasScrollRoom(state.scrollX, state.maxScrollX, deltaX);\n const takesY = deltaY !== 0 && hasScrollRoom(state.scrollY, state.maxScrollY, deltaY);\n if (takesX || takesY) {\n this.applyDelta(\n node,\n state,\n takesX ? deltaX : 0,\n takesY ? deltaY : 0,\n deltaMode,\n behaviorFor(node, deltaMode, wheelDeltaY)\n );\n event.markConsumed();\n return;\n }\n if (containsOverscroll(node)) {\n event.markConsumed();\n return;\n }\n }\n // Nothing had room. The root has the last word on whether the\n // leftover leaves the canvas: by default it does, so a page\n // around an embedded runtime goes on scrolling.\n if (containsOverscroll(rootOf(target))) {\n event.markConsumed();\n }\n }\n\n private applyDelta(\n container: UiNode,\n state: ScrollContainerState,\n deltaX: number,\n deltaY: number,\n deltaMode: UiWheelDeltaMode,\n behavior: UiScrollBehavior\n ): void {\n // A page-mode delta means a screenful, and a screenful is a\n // different number on each axis, so each is converted in its own\n // viewport extent rather than one of them borrowing the other's.\n this.scrollSink.scrollBy(\n container,\n deltaX === 0 ? 0 : this.toPixels(deltaX, deltaMode, state.viewportWidth),\n deltaY === 0 ? 0 : this.toPixels(deltaY, deltaMode, state.viewportHeight),\n behavior\n );\n }\n\n /**\n * A wheel delta in whatever unit it arrived in, as pixels.\n *\n * A `WheelEvent`'s delta is only a distance when `deltaMode` is\n * `Pixel`. Chrome reports pixels; Firefox reports **lines**, three\n * per notch, so a delta taken at face value there moves the view\n * three pixels — a scroll that looks broken rather than fast or\n * slow. Page mode exists too, and means a screenful.\n */\n private toPixels(delta: number, mode: UiWheelDeltaMode, extent: number | undefined): number {\n if (mode === UiWheelDeltaMode.Line) {\n return delta * LINE_HEIGHT_PX;\n }\n if (mode === UiWheelDeltaMode.Page) {\n // A screenful, less nothing: this matches paging the scrollbar\n // track, which already moves by exactly one viewport.\n return delta * (extent ?? LINE_HEIGHT_PX * 25);\n }\n return delta;\n }\n}\n\n/**\n * Whether this wheel should animate the container it is over.\n *\n * Both halves have to agree: the device has to be one that jumps, and\n * the container has not to have opted out with\n * `scrollBehavior=\"instant\"`.\n */\nfunction behaviorFor(\n container: UiNode,\n deltaMode: UiWheelDeltaMode,\n wheelDeltaY: number | undefined\n): UiScrollBehavior {\n if (container.getProperty('scrollBehavior') === 'instant') {\n return 'instant';\n }\n return isNotchedWheel(deltaMode, wheelDeltaY) ? 'smooth' : 'instant';\n}\n\n/** A ScrollView, or any node with overflow 'scroll' or 'auto'. */\nexport function isScrollContainer(node: UiNode): boolean {\n if (node.type === UiNodeType.ScrollView) {\n return true;\n }\n const overflow = node.properties.get('overflow');\n return overflow === 'scroll' || overflow === 'auto';\n}\n","import type { UiNode } from '../graph/UiNode';\nimport { noKeyModifiers, UiEventType, UiPinchEvent, type UiKeyModifiers, type UiPointerDevice } from './UiInputEvent';\nimport type { UiInputDispatcher } from './UiInputDispatcher';\n\nexport interface PinchRecognizerOptions {\n /**\n * How far apart the contacts' separation must change, as a fraction\n * of where it started, before the gesture is claimed as a pinch.\n *\n * Two fingers land a few milliseconds apart and never perfectly\n * still, so a gesture claimed on the first move would report a scale\n * of 1.02 for a two-finger press that was going to be a pan.\n */\n scaleThreshold?: number;\n /** The same in degrees, for the rotation half. */\n rotationThreshold?: number;\n}\n\n/**\n * One contact, kept in a fixed slot rather than a map.\n *\n * The recognizer holds exactly two of these for the life of the\n * runtime and writes into them, because a pointer move that allocates\n * is a per-frame allocation on the hottest path the framework has.\n */\ninterface Contact {\n id: number;\n x: number;\n y: number;\n down: boolean;\n}\n\n/**\n * Turns two contacts into a scale, a rotation and a translation.\n *\n * Touch input left this out for two reasons. Both are answered here\n * rather than waved past.\n *\n * The first was that a pinch \"would have to undo the rule that a press\n * ignores every other contact\". It does not. That rule is about who\n * owns the *press*, and it stays exactly as it was: the first contact\n * keeps the press, and the second contact's events are still refused\n * by everything downstream of it. What changed is that the pointer\n * controller now tells its gesture recognizer about every contact it\n * sees before deciding whose press it is, through `contactDown`,\n * `contactMove` and `contactUp`. A second finger is no longer\n * silently dropped on the floor; it is dropped from the press and\n * handed here.\n *\n * The second was that \"what a framework should do with a pinch when it\n * owns no zoom is a design question\". The answer this takes is that it\n * should do nothing at all: there is no framework-owned zoom, no\n * `UiTouchScroller` equivalent listening at the root, and a pinch that\n * nothing listens for costs one dispatch that returns immediately.\n * The zoom lives in `pinchable`, a modifier an element opts into, on\n * the same terms as every other behaviour a modifier carries.\n *\n * What a pinch does take is the press. When the second contact lands,\n * whatever single-contact gesture was in flight is ended where it\n * stands and the press stops producing a Click, because a person who\n * has put a second finger down is no longer doing the thing the first\n * finger started. The pan gets a real `PanEnd` rather than being\n * abandoned, so a `draggable` in the middle of a drag puts the card\n * down instead of leaving it stuck to a finger that has moved on.\n */\nexport class UiPinchRecognizer {\n private readonly scaleThreshold: number;\n private readonly rotationThreshold: number;\n\n private readonly first: Contact = { id: -1, x: 0, y: 0, down: false };\n private readonly second: Contact = { id: -1, x: 0, y: 0, down: false };\n\n private target: UiNode | null = null;\n private modifiers: UiKeyModifiers = noKeyModifiers();\n\n /** Separation and angle when the second contact landed. */\n private startDistance = 0;\n private startAngle = 0;\n /** What was last reported, so each event carries a delta as well. */\n private lastScale = 1;\n private lastRotation = 0;\n private lastCenterX = 0;\n private lastCenterY = 0;\n private recognized = false;\n\n constructor(\n private readonly dispatcher: UiInputDispatcher,\n options: PinchRecognizerOptions = {}\n ) {\n this.scaleThreshold = options.scaleThreshold ?? 0.05;\n this.rotationThreshold = options.rotationThreshold ?? 4;\n }\n\n /** Whether two contacts are down and the gesture has been claimed. */\n get pinching(): boolean {\n return this.recognized;\n }\n\n /** Whether a second contact is down at all, claimed or not. */\n get holding(): boolean {\n return this.first.down && this.second.down;\n }\n\n /**\n * A contact landed. Returns true when this is the second one, which\n * is the moment the caller has to end whatever the first was doing.\n */\n contactDown(\n pointer: UiPointerDevice,\n x: number,\n y: number,\n target: UiNode | null,\n modifiers: UiKeyModifiers\n ): boolean {\n if (!this.first.down) {\n write(this.first, pointer.id, x, y);\n this.target = target;\n return false;\n }\n if (this.second.down || pointer.id === this.first.id) {\n // A third finger is not a second pinch. It is ignored until the\n // hand comes off, which is what every platform does.\n return false;\n }\n write(this.second, pointer.id, x, y);\n this.modifiers = modifiers;\n if (target !== null) {\n this.target = target;\n }\n this.startDistance = this.distance();\n this.startAngle = this.angle();\n this.lastScale = 1;\n this.lastRotation = 0;\n this.lastCenterX = (this.first.x + this.second.x) / 2;\n this.lastCenterY = (this.first.y + this.second.y) / 2;\n this.recognized = false;\n return true;\n }\n\n /** A contact moved. Emits PinchStart the first time past the threshold. */\n contactMove(pointer: UiPointerDevice, x: number, y: number): void {\n const contact = this.contactFor(pointer.id);\n if (contact === null) {\n return;\n }\n contact.x = x;\n contact.y = y;\n if (!this.holding || this.target === null || this.startDistance <= 0) {\n return;\n }\n const scale = this.distance() / this.startDistance;\n const rotation = normalizeDegrees(this.angle() - this.startAngle);\n if (!this.recognized) {\n if (Math.abs(scale - 1) < this.scaleThreshold && Math.abs(rotation) < this.rotationThreshold) {\n return;\n }\n this.recognized = true;\n this.emit(UiEventType.PinchStart, scale, rotation);\n return;\n }\n this.emit(UiEventType.PinchMove, scale, rotation);\n }\n\n /**\n * A contact left. A pinch needs both, so the gesture ends with the\n * first one to go and the other is left in place doing nothing until\n * it too comes off.\n */\n contactUp(pointer: UiPointerDevice): void {\n const contact = this.contactFor(pointer.id);\n if (contact === null) {\n return;\n }\n if (this.recognized) {\n this.emit(UiEventType.PinchEnd, this.lastScale, this.lastRotation);\n this.recognized = false;\n }\n contact.down = false;\n contact.id = -1;\n if (!this.first.down && !this.second.down) {\n this.target = null;\n }\n }\n\n /** Drops everything, for a cancelled press or a disposed runtime. */\n cancel(): void {\n this.recognized = false;\n this.first.down = false;\n this.first.id = -1;\n this.second.down = false;\n this.second.id = -1;\n this.target = null;\n }\n\n private contactFor(id: number): Contact | null {\n if (this.first.down && this.first.id === id) {\n return this.first;\n }\n if (this.second.down && this.second.id === id) {\n return this.second;\n }\n return null;\n }\n\n private distance(): number {\n return Math.hypot(this.second.x - this.first.x, this.second.y - this.first.y);\n }\n\n private angle(): number {\n return (Math.atan2(this.second.y - this.first.y, this.second.x - this.first.x) * 180) / Math.PI;\n }\n\n private emit(\n type: UiEventType.PinchStart | UiEventType.PinchMove | UiEventType.PinchEnd,\n scale: number,\n rotation: number\n ): void {\n const centerX = (this.first.x + this.second.x) / 2;\n const centerY = (this.first.y + this.second.y) / 2;\n const event = new UiPinchEvent(\n type,\n centerX,\n centerY,\n scale,\n rotation,\n scale - this.lastScale,\n rotation - this.lastRotation,\n centerX - this.lastCenterX,\n centerY - this.lastCenterY,\n this.modifiers\n );\n this.lastScale = scale;\n this.lastRotation = rotation;\n this.lastCenterX = centerX;\n this.lastCenterY = centerY;\n this.dispatcher.dispatch(event, this.target!);\n }\n}\n\nfunction write(contact: Contact, id: number, x: number, y: number): void {\n contact.id = id;\n contact.x = x;\n contact.y = y;\n contact.down = true;\n}\n\n/**\n * An angle difference brought back into (-180, 180].\n *\n * Two contacts crossing the -180/180 seam would otherwise report a\n * rotation of nearly a full turn for a movement of one degree, and a\n * transform written from it would spin the element.\n */\nfunction normalizeDegrees(degrees: number): number {\n let value = degrees % 360;\n if (value > 180) {\n value -= 360;\n }\n if (value <= -180) {\n value += 360;\n }\n return value;\n}\n","import type { UiNode } from '../graph/UiNode';\nimport {\n noKeyModifiers,\n UiEventType,\n UiGestureEvent,\n UiPointerEvent,\n type UiKeyModifiers,\n type UiPointerDevice,\n type UiPointerKind\n} from './UiInputEvent';\nimport type { UiInputDispatcher } from './UiInputDispatcher';\nimport { UiPinchRecognizer, type PinchRecognizerOptions } from './UiPinchRecognizer';\n\nexport interface GestureRecognizerOptions {\n /**\n * Movement (px) beyond which a press cancels a pending LongPress and\n * is claimed as a Pan.\n */\n slop?: number;\n /**\n * The same threshold for a finger.\n *\n * Larger, because a finger is not a cursor: it rolls as it presses\n * and the reported point wanders several pixels without the person\n * intending to move at all. At the mouse threshold a deliberate\n * long press on a touchscreen is claimed as a pan before the hold\n * time is up, so the gesture becomes unreachable.\n */\n touchSlop?: number;\n /** Hold time (ms) before a still press becomes a LongPress. */\n longPressDelay?: number;\n /**\n * How much of the recent movement the release speed is measured over\n * (ms).\n *\n * The whole gesture is the wrong window, for the reason\n * `UiTouchScroller` gives: a long slow drag that ends in a flick\n * averages out to nothing across the whole of it, and the flick is\n * the part the person meant.\n */\n velocityWindow?: number;\n /**\n * The clock the velocity is measured against, for specs that drive a\n * gesture without waiting. Any monotonic millisecond source will do,\n * since the samples are only ever subtracted from each other.\n */\n now?: () => number;\n /**\n * Whether a long press from a finger also asks for a context menu.\n * Default true; see `UiGestureRecognizer` for what suppresses it.\n */\n contextMenuOnLongPress?: boolean;\n /** Thresholds for the two-contact half. */\n pinch?: PinchRecognizerOptions;\n}\n\n/**\n * Pointer-feed interface consumed by the pointer controller.\n *\n * The controller is the single owner of the press sequence and feeds\n * each raw pointer event plus the captured target here; the\n * recognizer turns them into gesture events on the same dispatcher.\n *\n * The `contact*` half is separate and deliberately not an event: it is\n * fed for **every** contact the controller sees, including the ones it\n * refuses to give the press to, and building a `UiPointerEvent` for a\n * contact that is about to be ignored would allocate on a path that\n * runs at the pointer's sample rate.\n */\nexport interface GestureInput {\n pointerDown(event: UiPointerEvent, target: UiNode): void;\n pointerMove(event: UiPointerEvent, target: UiNode): void;\n pointerUp(event: UiPointerEvent, target: UiNode): void;\n pointerCancel(): void;\n /** Whether the current press produced a gesture that should suppress Click. */\n claimed(): boolean;\n /** A contact landed, whether or not it was given the press. */\n contactDown?(pointer: UiPointerDevice, x: number, y: number, target: UiNode | null, modifiers: UiKeyModifiers): void;\n /** A contact moved, whether or not it holds the press. */\n contactMove?(pointer: UiPointerDevice, x: number, y: number): void;\n /** A contact left. */\n contactUp?(pointer: UiPointerDevice): void;\n}\n\ntype GestureState = 'idle' | 'pressing' | 'longPressed' | 'panning' | 'dragging';\n\n/** How many positions the velocity window is measured over. */\nconst VELOCITY_SAMPLES = 8;\n\n/** One position of the contact, written into a fixed slot. */\ninterface Sample {\n t: number;\n x: number;\n y: number;\n}\n\n/**\n * Synthesizes discrete gestures from a press sequence.\n *\n * Each press resolves to exactly one of:\n *\n * Pan — the pointer moves beyond `slop` before the hold time\n * elapses: PanStart/PanMove/PanEnd. For scrolling and\n * panning containers.\n * LongPress — the pointer holds still within `slop` for\n * `longPressDelay`: fires once. A subsequent move\n * claims the press as a Drag.\n * Drag — LongPress, then movement: DragStart/DragMove/DragEnd.\n * The classic long-press-to-pick-up drag.\n *\n * A press that is released before any of these (a tap) produces no\n * gesture events; Click synthesis lives in the pointer controller.\n *\n * A pointermove whose default was prevented (a consumer is handling\n * the move itself) never claims or advances a Pan/Drag. A cancelled\n * press aborts everything without gesture end events.\n *\n * ## The end of a gesture carries its speed\n *\n * `PanEnd` and `DragEnd` are `UiGestureEvent`s whose `velocityX` and\n * `velocityY` are the speed the contact left at, in pixels per second,\n * which is the unit `UiSpringOptions.velocity` takes. Without it every\n * spring handed a dropped card starts from rest, and a card thrown\n * across the screen stops dead the instant the finger leaves it.\n * Measured over the last `velocityWindow` milliseconds rather than the\n * whole gesture, and from a fixed ring of samples so a move allocates\n * nothing.\n *\n * ## A long press asks for a menu\n *\n * A finger has no second button, so a held finger is how a touchscreen\n * asks for the commands that apply to something. After the LongPress\n * has been dispatched, a `ContextMenu` event follows at the same point\n * unless the LongPress was `preventDefault()`ed, which is how a node\n * that means to be picked up rather than interrogated says so. A mouse\n * long press raises nothing: it has a secondary button, and the\n * pointer controller dispatches the event from that instead.\n *\n * ## Two contacts\n *\n * Every contact the controller sees is fed to a `UiPinchRecognizer`,\n * including the ones that are refused the press. When a second one\n * lands, whatever gesture the first was performing is **ended where it\n * stands** and the press stops synthesizing a Click, because the\n * person is no longer doing the thing they started. See\n * `UiPinchRecognizer` for how that is answered.\n */\nexport class UiGestureRecognizer implements GestureInput {\n private readonly slop: number;\n private readonly touchSlop: number;\n private readonly longPressDelay: number;\n private readonly velocityWindow: number;\n private readonly now: () => number;\n private readonly contextMenuOnLongPress: boolean;\n private readonly pinch: UiPinchRecognizer;\n\n private state: GestureState = 'idle';\n private startX = 0;\n private startY = 0;\n private startKind: UiPointerKind = 'mouse';\n private claimedPress = false;\n private timer: ReturnType<typeof setTimeout> | null = null;\n\n /** The press's recent positions, as a ring so a move allocates nothing. */\n private readonly samples: Sample[] = Array.from({ length: VELOCITY_SAMPLES }, () => ({ t: 0, x: 0, y: 0 }));\n private sampleCount = 0;\n private sampleNext = 0;\n\n /** What the in-flight press is against, kept so a pinch can end it. */\n private pressTarget: UiNode | null = null;\n private lastX = 0;\n private lastY = 0;\n private lastButtons = 0;\n private lastModifiers: UiKeyModifiers = noKeyModifiers();\n private lastPointer: UiPointerDevice | null = null;\n\n constructor(\n private readonly dispatcher: UiInputDispatcher,\n options: GestureRecognizerOptions = {}\n ) {\n this.slop = options.slop ?? 8;\n this.touchSlop = options.touchSlop ?? 12;\n this.longPressDelay = options.longPressDelay ?? 500;\n this.velocityWindow = options.velocityWindow ?? 100;\n this.now = options.now ?? defaultClock;\n this.contextMenuOnLongPress = options.contextMenuOnLongPress ?? true;\n this.pinch = new UiPinchRecognizer(dispatcher, options.pinch);\n }\n\n pointerDown(event: UiPointerEvent, target: UiNode): void {\n if (this.state !== 'idle') {\n return;\n }\n this.state = 'pressing';\n this.claimedPress = false;\n this.startX = event.x;\n this.startY = event.y;\n // Read once at the press: the threshold must not change under a\n // gesture already being measured against it.\n this.startKind = event.pointer.kind;\n this.pressTarget = target;\n this.remember(event);\n this.resetSamples();\n this.armLongPress(target, event);\n }\n\n pointerMove(event: UiPointerEvent, target: UiNode): void {\n if (event.defaultPrevented) {\n return;\n }\n this.remember(event);\n if (this.state === 'pressing') {\n if (Math.hypot(event.x - this.startX, event.y - this.startY) > this.pressSlop()) {\n this.clearTimer();\n this.state = 'panning';\n this.claimedPress = true;\n this.dispatch(UiEventType.PanStart, target, this.startX, this.startY, event);\n this.dispatch(UiEventType.PanMove, target, event.x, event.y, event);\n }\n return;\n }\n if (this.state === 'panning') {\n this.dispatch(UiEventType.PanMove, target, event.x, event.y, event);\n return;\n }\n if (this.state === 'longPressed') {\n this.state = 'dragging';\n this.claimedPress = true;\n this.dispatch(UiEventType.DragStart, target, this.startX, this.startY, event);\n this.dispatch(UiEventType.DragMove, target, event.x, event.y, event);\n return;\n }\n if (this.state === 'dragging') {\n this.dispatch(UiEventType.DragMove, target, event.x, event.y, event);\n }\n }\n\n pointerUp(event: UiPointerEvent, target: UiNode): void {\n this.remember(event);\n if (this.state === 'panning') {\n this.dispatchEnd(UiEventType.PanEnd, target, event.x, event.y, event);\n }\n if (this.state === 'dragging') {\n this.dispatchEnd(UiEventType.DragEnd, target, event.x, event.y, event);\n }\n this.clearTimer();\n this.state = 'idle';\n this.pressTarget = null;\n }\n\n pointerCancel(): void {\n this.clearTimer();\n this.state = 'idle';\n this.pressTarget = null;\n this.pinch.cancel();\n }\n\n claimed(): boolean {\n return this.claimedPress;\n }\n\n // -------------------------------------------------------------------------\n // Contacts\n // -------------------------------------------------------------------------\n\n contactDown(pointer: UiPointerDevice, x: number, y: number, target: UiNode | null, modifiers: UiKeyModifiers): void {\n const second = this.pinch.contactDown(pointer, x, y, target ?? this.pressTarget, modifiers);\n if (second) {\n this.endForPinch();\n }\n }\n\n contactMove(pointer: UiPointerDevice, x: number, y: number): void {\n this.pinch.contactMove(pointer, x, y);\n }\n\n contactUp(pointer: UiPointerDevice): void {\n this.pinch.contactUp(pointer);\n }\n\n /**\n * Puts down whatever the first contact was carrying.\n *\n * The pan or drag gets a real end event at the point it reached, so\n * a `draggable` releases the card rather than holding it against a\n * finger whose gesture has become something else, and the press is\n * marked claimed so no Click follows the release of either contact.\n */\n private endForPinch(): void {\n if (this.state === 'panning' && this.pressTarget !== null) {\n this.dispatchEnd(UiEventType.PanEnd, this.pressTarget, this.lastX, this.lastY, null);\n }\n if (this.state === 'dragging' && this.pressTarget !== null) {\n this.dispatchEnd(UiEventType.DragEnd, this.pressTarget, this.lastX, this.lastY, null);\n }\n this.clearTimer();\n this.state = 'idle';\n this.claimedPress = true;\n }\n\n // -------------------------------------------------------------------------\n // LongPress timer\n // -------------------------------------------------------------------------\n\n private armLongPress(target: UiNode, down: UiPointerEvent): void {\n this.timer = setTimeout(() => {\n this.timer = null;\n if (this.state !== 'pressing') {\n return;\n }\n this.state = 'longPressed';\n this.claimedPress = true;\n const held = this.dispatch(UiEventType.LongPress, target, this.startX, this.startY, down);\n // A finger has no second button. A held finger is how a\n // touchscreen asks for the commands that apply to something, so\n // the menu request follows the press it was made with — unless a\n // listener said the press was for picking the node up.\n if (this.contextMenuOnLongPress && down.pointer.kind !== 'mouse' && !held.defaultPrevented) {\n this.dispatcher.dispatch(\n new UiPointerEvent(\n UiEventType.ContextMenu,\n this.startX,\n this.startY,\n down.buttons,\n down.modifiers,\n down.pointer\n ),\n target\n );\n }\n }, this.longPressDelay);\n }\n\n private clearTimer(): void {\n if (this.timer !== null) {\n clearTimeout(this.timer);\n this.timer = null;\n }\n }\n\n /** The movement threshold for the device that started the press. */\n private pressSlop(): number {\n return this.startKind === 'touch' ? this.touchSlop : this.slop;\n }\n\n private dispatch(type: UiEventType, target: UiNode, x: number, y: number, source: UiPointerEvent): UiGestureEvent {\n // The device is carried onto the synthesized event: a listener\n // that has to size a drag handle for a finger learns it from the\n // DragStart, not from the raw press it never saw.\n const event = new UiGestureEvent(type, x, y, source.buttons, source.modifiers, source.pointer);\n this.dispatcher.dispatch(event, target);\n return event;\n }\n\n /**\n * The last event of a gesture, carrying the speed it ended at.\n *\n * `source` is null when the gesture is being ended by something other\n * than a release — a second contact landing — and the buttons,\n * modifiers and device of the last event seen are used instead.\n */\n private dispatchEnd(type: UiEventType, target: UiNode, x: number, y: number, source: UiPointerEvent | null): void {\n const buttons = source?.buttons ?? this.lastButtons;\n const modifiers = source?.modifiers ?? this.lastModifiers;\n const pointer = source?.pointer ?? this.lastPointer ?? undefined;\n const event = new UiGestureEvent(\n type,\n x,\n y,\n buttons,\n modifiers,\n pointer,\n this.velocityAlong('x'),\n this.velocityAlong('y')\n );\n this.dispatcher.dispatch(event, target);\n }\n\n // -------------------------------------------------------------------------\n // Velocity\n // -------------------------------------------------------------------------\n\n private resetSamples(): void {\n this.sampleCount = 0;\n this.sampleNext = 0;\n }\n\n /** Records where the contact is, into the ring, without allocating. */\n private remember(event: UiPointerEvent): void {\n const slot = this.samples[this.sampleNext];\n slot.t = this.now();\n slot.x = event.x;\n slot.y = event.y;\n this.sampleNext = (this.sampleNext + 1) % VELOCITY_SAMPLES;\n if (this.sampleCount < VELOCITY_SAMPLES) {\n this.sampleCount += 1;\n }\n this.lastX = event.x;\n this.lastY = event.y;\n this.lastButtons = event.buttons;\n this.lastModifiers = event.modifiers;\n this.lastPointer = event.pointer;\n }\n\n /**\n * Pixels per second along one axis, over the recent window.\n *\n * The oldest sample still inside the window is the baseline, so a\n * gesture that dawdled and then flicked reports the flick. Fewer than\n * two samples, or two at the same instant, is no evidence of speed\n * and reports none rather than dividing by zero.\n */\n private velocityAlong(axis: 'x' | 'y'): number {\n if (this.sampleCount < 2) {\n return 0;\n }\n const newestIndex = (this.sampleNext - 1 + VELOCITY_SAMPLES) % VELOCITY_SAMPLES;\n const newest = this.samples[newestIndex];\n let oldest = newest;\n for (let back = 1; back < this.sampleCount; back += 1) {\n const candidate = this.samples[(newestIndex - back + VELOCITY_SAMPLES) % VELOCITY_SAMPLES];\n if (newest.t - candidate.t > this.velocityWindow) {\n break;\n }\n oldest = candidate;\n }\n const elapsed = newest.t - oldest.t;\n if (elapsed <= 0) {\n return 0;\n }\n const travelled = axis === 'x' ? newest.x - oldest.x : newest.y - oldest.y;\n return (travelled / elapsed) * 1000;\n }\n}\n\nfunction defaultClock(): number {\n return typeof performance !== 'undefined' ? performance.now() : Date.now();\n}\n","import type { UiNode } from '../graph/UiNode';\nimport { UiEventType, type UiInputEvent, type UiPointerEvent } from './UiInputEvent';\nimport type { UiInputDispatcher } from './UiInputDispatcher';\nimport { hasScrollRoom, isScrollContainer, type ScrollContainerState, type ScrollSink } from './UiWheelController';\n\nexport interface TouchScrollerOptions {\n /**\n * How far a flick coasts, in milliseconds of its release speed.\n *\n * The projected distance is `velocity * momentum`, which is the\n * closed form of an exponential deceleration: a fling that leaves the\n * finger at 2px/ms travels 600px and settles. Raising it makes the\n * content run further from the same flick.\n */\n momentum?: number;\n /**\n * Speed (px/ms) a release must exceed to coast at all.\n *\n * Below it the finger was placing the content, not throwing it, and\n * carrying on moving would be the content sliding out from under\n * someone who had stopped.\n */\n flingVelocity?: number;\n /**\n * How much of the recent movement the release speed is measured over\n * (ms).\n *\n * A whole gesture is the wrong window — a long slow drag that ends in\n * a flick would average out to nothing. Only the last moments count.\n */\n velocityWindow?: number;\n /**\n * The clock, for specs that need to drive velocity without waiting.\n *\n * `performance.now()` where there is one; the samples are only ever\n * subtracted from each other, so any monotonic millisecond source\n * will do.\n */\n now?: () => number;\n}\n\n/** A container that will take a gesture, and the axes it will take it on. */\ninterface ResolvedScroll {\n node: UiNode;\n state: ScrollContainerState;\n takesX: boolean;\n takesY: boolean;\n}\n\n/** One position of the finger, kept only long enough to measure speed. */\ninterface Sample {\n t: number;\n x: number;\n y: number;\n}\n\n/**\n * Scrolls a container by dragging its contents, the way a touchscreen\n * does.\n *\n * A wheel is the only thing that scrolled anything, and a finger\n * produces no wheel events, so a scroll container on a touchscreen was\n * simply stuck. The gesture already existed — the recognizer\n * synthesizes Pan from any press that moves — and nothing consumed it.\n *\n * ## Why a listener rather than a hook in the controller\n *\n * This registers Pan listeners on the **root**, in the bubble phase, so\n * a pan reaches it only if nothing on the way up claimed it. That is\n * not an implementation convenience: it is the whole opt-out mechanism,\n * and it was already the documented contract before anything\n * implemented it. `Slider` and `SplitPane` both call\n * `stopPropagation()` on their pans and both say why — \"keeps a scroll\n * container above from panning at the same time\". A widget that owns\n * the drag therefore keeps it, with no new API and no list of\n * exceptions in here.\n *\n * ## What it does\n *\n * Each move scrolls by how far the finger travelled, inverted: the\n * content follows the finger rather than the viewport following it.\n * When the innermost scroll container has reached its end the next one\n * out takes over, so a list inside a page hands the page its scroll\n * instead of stopping dead. On release a flick coasts, as a projected\n * distance handed to the sink's smooth path rather than a loop of our\n * own — the sink already owns animating a scroll, and a second animator\n * driving the same offset would fight it.\n *\n * Touch only, deliberately. A mouse drag inside a scroll container is\n * how text is selected, and a pen is used for exactly that precision,\n * so neither can be read as a scroll without taking something away.\n */\nexport class UiTouchScroller {\n private readonly momentum: number;\n private readonly flingVelocity: number;\n private readonly velocityWindow: number;\n private readonly now: () => number;\n\n private container: UiNode | null = null;\n private lastX = 0;\n private lastY = 0;\n private samples: Sample[] = [];\n private readonly detach: () => void;\n\n constructor(\n dispatcher: UiInputDispatcher,\n root: UiNode,\n private readonly scrollSink: ScrollSink,\n options: TouchScrollerOptions = {}\n ) {\n this.momentum = options.momentum ?? 300;\n this.flingVelocity = options.flingVelocity ?? 0.1;\n this.velocityWindow = options.velocityWindow ?? 100;\n this.now = options.now ?? defaultClock;\n\n const start = (event: UiInputEvent): void => this.panStart(event as UiPointerEvent);\n const move = (event: UiInputEvent): void => this.panMove(event as UiPointerEvent);\n const end = (event: UiInputEvent): void => this.panEnd(event as UiPointerEvent);\n dispatcher.addEventListener(root, UiEventType.PanStart, start);\n dispatcher.addEventListener(root, UiEventType.PanMove, move);\n dispatcher.addEventListener(root, UiEventType.PanEnd, end);\n this.detach = () => {\n dispatcher.removeEventListener(root, UiEventType.PanStart, start);\n dispatcher.removeEventListener(root, UiEventType.PanMove, move);\n dispatcher.removeEventListener(root, UiEventType.PanEnd, end);\n };\n }\n\n /** The container this pan is scrolling, or null when it is not scrolling one. */\n get scrollingNode(): UiNode | null {\n return this.container;\n }\n\n /** Stops listening. */\n dispose(): void {\n this.detach();\n this.container = null;\n this.samples = [];\n }\n\n private panStart(event: UiPointerEvent): void {\n this.container = null;\n this.samples = [];\n if (event.pointer.kind !== 'touch') {\n return;\n }\n this.lastX = event.x;\n this.lastY = event.y;\n // No velocity sample here. A PanStart carries the point the press\n // began at, timestamped now — so the slop the finger crossed before\n // the gesture was recognized would be counted as distance covered\n // in no time at all, and the first flick of every gesture would\n // coast several times too far.\n //\n // The node is resolved per move rather than here, so a pan that\n // exhausts one container can hand over to the next without the\n // finger being lifted.\n this.container = event.target;\n }\n\n private panMove(event: UiPointerEvent): void {\n if (this.container === null) {\n return;\n }\n // Inverted: dragging the finger up moves the content up, which\n // means scrolling further down.\n const dx = this.lastX - event.x;\n const dy = this.lastY - event.y;\n this.lastX = event.x;\n this.lastY = event.y;\n this.sample(event.x, event.y);\n\n const resolved = this.resolve(event.target, dx, dy);\n if (resolved === null) {\n return;\n }\n const { node, takesX, takesY } = resolved;\n this.scrollSink.scrollBy(node, takesX ? dx : 0, takesY ? dy : 0);\n // A touchscreen has no hover, so this is the only chance the person\n // gets to see where they are in the content.\n this.scrollSink.revealScrollbars?.(node);\n }\n\n private panEnd(event: UiPointerEvent): void {\n const target = this.container;\n this.container = null;\n if (target === null) {\n return;\n }\n this.sample(event.x, event.y);\n const velocity = this.releaseVelocity();\n this.samples = [];\n if (velocity === null) {\n return;\n }\n const resolved = this.resolve(event.target, velocity.x, velocity.y);\n if (resolved === null) {\n return;\n }\n const { node, takesX, takesY } = resolved;\n // Each axis passes the threshold on its own, so a diagonal throw\n // coasts on both and a vertical one with a pixel of drift coasts on\n // neither sideways. One threshold on the combined speed would let a\n // fast vertical fling drag the content sideways by whatever the\n // thumb happened to do.\n const flingX = takesX && Math.abs(velocity.x) >= this.flingVelocity ? velocity.x * this.momentum : 0;\n const flingY = takesY && Math.abs(velocity.y) >= this.flingVelocity ? velocity.y * this.momentum : 0;\n if (flingX === 0 && flingY === 0) {\n return;\n }\n this.scrollSink.scrollBy(node, flingX, flingY, 'smooth');\n }\n\n private sample(x: number, y: number): void {\n const t = this.now();\n this.samples.push({ t, x, y });\n while (this.samples.length > 2 && t - (this.samples[0] as Sample).t > this.velocityWindow) {\n this.samples.shift();\n }\n }\n\n /**\n * The speed of the content at the moment of release, px/ms, in the\n * same inverted sense as a move: positive means the offset is growing.\n */\n private releaseVelocity(): { x: number; y: number } | null {\n const first = this.samples[0];\n const last = this.samples[this.samples.length - 1];\n if (first === undefined || last === undefined) {\n return null;\n }\n const elapsed = last.t - first.t;\n if (elapsed <= 0) {\n return null;\n }\n return { x: (first.x - last.x) / elapsed, y: (first.y - last.y) / elapsed };\n }\n\n /**\n * The container that should take this movement, and which of its axes.\n *\n * The nearest scroll container that can still move in the direction\n * asked for, walking outward. A container already at its end is\n * skipped rather than ending the gesture, which is what lets a list\n * that has hit its bottom keep scrolling the page it sits in. When\n * nothing can move, the innermost container is returned so the\n * gesture still belongs somewhere.\n *\n * **Each axis is asked for separately**, because a container may\n * scroll on both, and this used to pick one from the container's\n * flex direction and drop the other on the floor. A spreadsheet is\n * the case that found it on the wheel in 38e70a3: one `ScrollView`\n * whose content overflows in both directions, classified as vertical,\n * so a sideways drag moved nothing at all. This is the same fix on\n * the same shared state, so the two input paths cannot disagree about\n * which container takes a gesture.\n *\n * A container that overflows on one axis only is unaffected: the axis\n * it does not scroll has no room, so it is not taken.\n */\n private resolve(target: UiNode | null, dx: number, dy: number): ResolvedScroll | null {\n let innermost: ResolvedScroll | null = null;\n for (let node: UiNode | null = target; node !== null; node = node.parent) {\n if (!isScrollContainer(node)) {\n continue;\n }\n const state = this.scrollSink.containerState(node);\n if (state === undefined) {\n continue;\n }\n const takesX = dx !== 0 && hasScrollRoom(state.scrollX, state.maxScrollX, dx);\n const takesY = dy !== 0 && hasScrollRoom(state.scrollY, state.maxScrollY, dy);\n // The innermost is the fallback, and it takes nothing: a gesture\n // that nothing can move should belong somewhere without moving\n // anything.\n innermost ??= { node, state, takesX: false, takesY: false };\n if (takesX || takesY) {\n return { node, state, takesX, takesY };\n }\n }\n return innermost;\n }\n}\n\nfunction defaultClock(): number {\n return typeof performance !== 'undefined' ? performance.now() : Date.now();\n}\n","import { DirtyFlags } from '../graph/DirtyFlags';\nimport type { UiNode } from '../graph/UiNode';\nimport type { LayoutBox } from '../layout/LayoutTypes';\nimport type { LayoutRecord } from '../layout/LayoutRecord';\nimport type { TextMeasurer } from '../layout/TextMeasurer';\nimport { createPaintState, resolvePaintState } from '../rendering/PaintState';\nimport { EditableLayout } from '../editing/EditableLayout';\nimport type { EditableTextModel, EditUnit } from '../editing/EditableTextModel';\nimport { commandForKey, detectEditingPlatform, type EditCommand, type EditingPlatform } from '../editing/EditingKeymap';\nimport { wordRangeAt, lineStartAt, lineEndAt } from '../editing/TextBoundaries';\nimport { editorFor, isEditableNode, isMultiline, isReadOnly, nextCaretToggle } from '../editing/UiEditable';\nimport type { CaretRect } from '../editing/TextGeometry';\nimport type { UiInputDispatcher } from './UiInputDispatcher';\nimport type { UiFocusManager } from './UiFocusManager';\nimport {\n UiBeforeInputEvent,\n UiPasteEvent,\n UiSelectionChangeEvent,\n UiTextChangeEvent,\n type UiKeyModifiers\n} from './UiInputEvent';\n\n/**\n * What the controller needs from the runtime around it: geometry,\n * measurement, and the two things it cannot do itself — mark a node\n * dirty and scroll a rectangle into view.\n */\nexport interface EditingHost {\n recordFor(node: UiNode): LayoutRecord | undefined;\n /** Where the node is seen, scroll offsets applied; for the shell's caret rectangle. */\n visibleBox(node: UiNode): LayoutBox;\n /** A layout-root point in the node's own coordinates. */\n toLocal(node: UiNode, x: number, y: number): { x: number; y: number };\n readonly measurer: TextMeasurer;\n markDirty(node: UiNode, flags: DirtyFlags): void;\n /** Scrolls ancestors so a node-local box is visible. */\n reveal(node: UiNode, box: LayoutBox): void;\n now(): number;\n}\n\n/**\n * What a shell mirrors while an editable has focus: its text and\n * selection (so native copy, cut and IME context are right) and where\n * the caret is on the canvas (so the IME candidate window opens there).\n */\nexport interface EditingState {\n readonly text: string;\n readonly selectionStart: number;\n readonly selectionEnd: number;\n /** Caret box in canvas (layout root) pixels. */\n readonly caret: LayoutBox;\n readonly multiline: boolean;\n readonly composing: boolean;\n}\n\nexport interface EditingControllerOptions {\n /** Keyboard conventions; detected from the user agent by default. */\n platform?: EditingPlatform;\n}\n\n/** How long two presses may be apart and still count as a double click. */\nconst MULTI_CLICK_MS = 500;\nconst MULTI_CLICK_SLOP = 4;\n/** Room kept around the caret when scrolling it into view. */\nconst CARET_REVEAL_PADDING = 4;\n\n/**\n * Editing behaviour for EditableText nodes.\n *\n * The keyboard and pointer controllers call in here as their default\n * behaviour for an editable target — after the app's listeners have\n * run and only when none of them called preventDefault() — and the\n * host feeds it the shell's text input: `beforeinput` edits,\n * composition, paste. The model on the node is the single source of\n * truth; this class turns intents into model changes, marks the node\n * dirty so layout and paint follow, reports the change through an\n * `input` event, and keeps the caret in view.\n *\n * Text arrives one of two ways. A shell with an editing proxy sends\n * `beforeinput`, where the browser has already resolved the IME, dead\n * keys and the keyboard layout; then printable key presses are not\n * text and `textFromKeys` is off. Without a proxy — tests, a bare\n * runtime — printable keys become insertions.\n */\nexport class UiEditingController {\n /** Insert printable key presses as text; off when a shell delivers text through beforeinput. */\n textFromKeys = true;\n\n private readonly platform: EditingPlatform;\n private readonly paint = createPaintState();\n private focusedEditable: UiNode | null = null;\n private visible = true;\n /** x the current run of vertical moves keeps returning to. */\n private verticalGoalX: number | undefined = undefined;\n private dragging: UiNode | null = null;\n private lastPress: { node: UiNode; x: number; y: number; at: number; count: number } | null = null;\n private compositionOpen = false;\n\n constructor(\n private readonly host: EditingHost,\n private readonly dispatcher: UiInputDispatcher,\n private readonly focus: UiFocusManager,\n options: EditingControllerOptions = {}\n ) {\n this.platform = options.platform ?? detectEditingPlatform();\n this.focus.onFocusChange(node => this.handleFocusChange(node));\n }\n\n /** The editable that holds focus, or null. */\n get focused(): UiNode | null {\n return this.focusedEditable;\n }\n\n /** Whether the pointer controller should hand presses on the node to this controller. */\n isEditable(node: UiNode): boolean {\n return isEditableNode(node);\n }\n\n // ---------------------------------------------------------------------------\n // Keyboard\n // ---------------------------------------------------------------------------\n\n /**\n * Default keyboard behaviour for the focused editable. Returns true\n * when the key was an editing command, so the caller can mark the\n * event handled.\n */\n handleKey(node: UiNode, key: string, modifiers: UiKeyModifiers): boolean {\n if (!isEditableNode(node)) {\n return false;\n }\n const command = commandForKey(key, modifiers, this.platform, this.textFromKeys);\n if (command === null) {\n return false;\n }\n return this.execute(node, command);\n }\n\n private execute(node: UiNode, command: EditCommand): boolean {\n const model = editorFor(node);\n const readOnly = isReadOnly(node);\n switch (command.kind) {\n case 'move':\n this.move(node, model, command.unit, command.direction, command.extend);\n return true;\n case 'delete':\n if (readOnly) {\n return true;\n }\n return this.applyEdit(node, model, deleteInputType(command.unit, command.direction), null, () => {\n if (command.direction < 0) {\n model.deleteBackward(command.unit);\n } else {\n model.deleteForward(command.unit);\n }\n });\n case 'newline':\n if (!isMultiline(node)) {\n // Enter in a single-line field is the app's (submit), not ours.\n return false;\n }\n if (readOnly) {\n return true;\n }\n return this.applyEdit(node, model, 'insertLineBreak', '\\n', () => model.insertText('\\n'));\n case 'insert':\n if (readOnly) {\n return true;\n }\n return this.applyEdit(node, model, 'insertText', command.text, () => model.insertText(command.text));\n case 'selectAll':\n model.selectAll();\n this.afterSelectionChange(node, model);\n return true;\n case 'undo':\n if (readOnly) {\n return true;\n }\n this.history(node, model, 'historyUndo', () => model.undo());\n return true;\n case 'redo':\n if (readOnly) {\n return true;\n }\n this.history(node, model, 'historyRedo', () => model.redo());\n return true;\n }\n }\n\n private move(\n node: UiNode,\n model: EditableTextModel,\n unit: EditUnit | 'vertical',\n direction: -1 | 1,\n extend: boolean\n ): void {\n if (unit === 'vertical') {\n const layout = this.layoutOf(node);\n const target = layout.verticalMove(model.focus, direction, this.verticalGoalX);\n if (target === null) {\n // Off the first or last line: the caret goes to the text's edge.\n model.moveTo(direction < 0 ? 0 : model.text.length, extend);\n this.verticalGoalX = undefined;\n } else {\n model.moveTo(target.offset, extend);\n this.verticalGoalX = target.x;\n }\n this.afterSelectionChange(node, model, true);\n return;\n }\n if (unit === 'line') {\n // Home/End are the visual line, which needs the layout; the\n // model's 'line' is the hard line.\n const layout = this.layoutOf(node);\n const caret = layout.caretRect(model.focus);\n const line = layout.lines[caret.line];\n const hard = direction < 0 ? lineStartAt(model.text, model.focus) : lineEndAt(model.text, model.focus);\n const visual = direction < 0 ? line.start : line.end;\n model.moveTo(direction < 0 ? Math.max(hard, visual) : Math.min(hard, visual), extend);\n this.afterSelectionChange(node, model);\n return;\n }\n model.move(unit, direction, extend);\n this.afterSelectionChange(node, model);\n }\n\n // ---------------------------------------------------------------------------\n // Text input from the shell\n // ---------------------------------------------------------------------------\n\n /**\n * A `beforeinput` from the shell's editing proxy, in the DOM's\n * vocabulary. Returns true when it was applied to the focused\n * editable. Composition types are not handled here: the composition\n * methods carry them, and an engine that fires both must not insert\n * twice.\n */\n beforeInput(inputType: string, data: string | null): boolean {\n const node = this.focusedEditable;\n if (node === null) {\n return false;\n }\n const model = editorFor(node);\n const readOnly = isReadOnly(node);\n switch (inputType) {\n case 'insertText':\n case 'insertReplacementText':\n case 'insertFromDrop':\n case 'insertFromYank':\n if (data === null || data.length === 0) {\n return false;\n }\n return readOnly || this.insert(node, model, inputType, data);\n case 'insertFromPaste':\n return readOnly || (data !== null && this.insert(node, model, inputType, data));\n case 'insertLineBreak':\n case 'insertParagraph':\n if (!isMultiline(node)) {\n return false;\n }\n return readOnly || this.applyEdit(node, model, inputType, '\\n', () => model.insertText('\\n'));\n case 'deleteContentBackward':\n case 'deleteWordBackward':\n case 'deleteSoftLineBackward':\n case 'deleteHardLineBackward':\n case 'deleteContentForward':\n case 'deleteWordForward':\n case 'deleteSoftLineForward':\n case 'deleteHardLineForward':\n case 'deleteContent':\n case 'deleteByCut':\n case 'deleteByDrag': {\n if (readOnly) {\n return true;\n }\n const unit: EditUnit = /Word/.test(inputType) ? 'word' : /Line/.test(inputType) ? 'line' : 'grapheme';\n const forward = /Forward/.test(inputType);\n return this.applyEdit(node, model, inputType, null, () => {\n if (inputType === 'deleteContent' || inputType === 'deleteByCut' || inputType === 'deleteByDrag') {\n model.replaceRange(model.start, model.end, '');\n } else if (forward) {\n model.deleteForward(unit);\n } else {\n model.deleteBackward(unit);\n }\n });\n }\n case 'historyUndo':\n return readOnly || this.history(node, model, inputType, () => model.undo());\n case 'historyRedo':\n return readOnly || this.history(node, model, inputType, () => model.redo());\n default:\n return false;\n }\n }\n\n /** Inserts text at the selection of the focused editable, as typing would. */\n insertText(text: string): boolean {\n const node = this.focusedEditable;\n if (node === null || isReadOnly(node)) {\n return false;\n }\n return this.insert(node, editorFor(node), 'insertText', text);\n }\n\n /**\n * Replaces the focused editable's whole text, as an assistive\n * technology's \"set value\" does.\n *\n * `insertReplacementText` is the DOM's own input type for this, so an\n * `onBeforeInput` that vets edits sees the same vocabulary it sees\n * for typing, and an app that rejects the edit rejects this one too.\n * Selecting everything first is what makes it one undo step and one\n * `onInput` rather than a delete and an insert.\n */\n replaceText(text: string): boolean {\n const node = this.focusedEditable;\n if (node === null || isReadOnly(node)) {\n return false;\n }\n const model = editorFor(node);\n model.selectAll();\n return this.insert(node, model, 'insertReplacementText', text);\n }\n\n /**\n * Pastes text: newlines are kept in a multiline field and become\n * spaces in a single-line one.\n *\n * With nothing editable focused the text is offered to whatever is,\n * as a `Paste` event, instead of being dropped. That is the case a\n * grid needs: it owns a rectangle of cells, a block of tab-separated\n * text means something to it that it means to nothing else, and\n * before this there was no way for it to hear about one at all.\n */\n paste(text: string): boolean {\n const node = this.focusedEditable;\n if (node === null || isReadOnly(node)) {\n return this.offerPaste(text);\n }\n return this.insert(node, editorFor(node), 'insertFromPaste', text);\n }\n\n private offerPaste(text: string): boolean {\n const target = this.focus.focusedNode;\n if (target === null) {\n return false;\n }\n const event = new UiPasteEvent(text);\n this.dispatcher.dispatch(event, target);\n return event.defaultPrevented;\n }\n\n private insert(node: UiNode, model: EditableTextModel, inputType: string, text: string): boolean {\n const data = isMultiline(node) ? text : text.replace(/\\r\\n|\\r|\\n/g, ' ');\n return this.applyEdit(node, model, inputType, data, () => model.insertText(data));\n }\n\n // ---------------------------------------------------------------------------\n // Composition\n // ---------------------------------------------------------------------------\n\n compositionStart(): void {\n const node = this.focusedEditable;\n if (node === null || isReadOnly(node)) {\n return;\n }\n const model = editorFor(node);\n model.beginComposition();\n this.compositionOpen = true;\n this.afterTextChange(node, model, false);\n }\n\n /** The composition text so far and the caret within it. */\n compositionUpdate(text: string, caret: number = text.length): void {\n const node = this.focusedEditable;\n if (node === null || isReadOnly(node)) {\n return;\n }\n const model = editorFor(node);\n model.updateComposition(text, caret);\n this.compositionOpen = true;\n this.afterTextChange(node, model, false);\n }\n\n /** The IME committed `text` (possibly empty: the composition was cancelled). */\n compositionEnd(text: string): void {\n const node = this.focusedEditable;\n this.compositionOpen = false;\n if (node === null || isReadOnly(node)) {\n return;\n }\n const model = editorFor(node);\n const data = isMultiline(node) ? text : text.replace(/\\r\\n|\\r|\\n/g, ' ');\n const before = model.text;\n model.commitComposition(data);\n this.afterTextChange(node, model, before !== model.text);\n }\n\n // ---------------------------------------------------------------------------\n // Pointer\n // ---------------------------------------------------------------------------\n\n /**\n * A press on an editable places the caret (Shift extends the\n * selection to it); a second press within the double-click window\n * selects the word, a third the line. Dragging afterwards extends the\n * selection from the anchor.\n */\n pointerDown(node: UiNode, x: number, y: number, modifiers: UiKeyModifiers): void {\n if (!isEditableNode(node)) {\n return;\n }\n const model = editorFor(node);\n const layout = this.layoutOf(node);\n const local = this.host.toLocal(node, x, y);\n const offset = layout.offsetAt(local.x, local.y);\n const now = this.host.now();\n const last = this.lastPress;\n // Shift+press extends the selection whatever came before it, and\n // does not count toward a double click.\n const count =\n !modifiers.shift &&\n last !== null &&\n last.node === node &&\n now - last.at <= MULTI_CLICK_MS &&\n Math.abs(last.x - x) <= MULTI_CLICK_SLOP &&\n Math.abs(last.y - y) <= MULTI_CLICK_SLOP\n ? last.count + 1\n : 1;\n this.lastPress = { node, x, y, at: now, count };\n this.dragging = node;\n\n if (modifiers.shift) {\n model.moveTo(offset, true);\n } else if (count === 2) {\n const word = wordRangeAt(model.text, offset);\n model.select(word.start, word.end);\n } else if (count >= 3) {\n model.select(lineStartAt(model.text, offset), lineEndAt(model.text, offset));\n } else {\n model.select(offset);\n }\n model.breakUndoGroup();\n this.afterSelectionChange(node, model);\n }\n\n pointerMove(node: UiNode, x: number, y: number): void {\n if (this.dragging !== node) {\n return;\n }\n const model = editorFor(node);\n const layout = this.layoutOf(node);\n const local = this.host.toLocal(node, x, y);\n const offset = layout.offsetAt(local.x, local.y);\n if (offset !== model.focus) {\n model.moveTo(offset, true);\n this.afterSelectionChange(node, model);\n }\n }\n\n pointerUp(): void {\n this.dragging = null;\n }\n\n // ---------------------------------------------------------------------------\n // State for the shell, caret blink\n // ---------------------------------------------------------------------------\n\n /** The focused editable's state for the shell to mirror, or null. */\n state(): EditingState | null {\n const node = this.focusedEditable;\n if (node === null || this.host.recordFor(node) === undefined) {\n return null;\n }\n const model = editorFor(node);\n const caret = this.layoutOf(node).caretRect();\n const visible = this.host.visibleBox(node);\n return {\n text: model.text,\n selectionStart: model.start,\n selectionEnd: model.end,\n caret: { x: visible.x + caret.x, y: visible.y + caret.y, width: 1, height: caret.height },\n multiline: isMultiline(node),\n composing: model.composing\n };\n }\n\n /**\n * When the focused caret next toggles, or undefined when nothing\n * blinks: no focused editable, a composition in progress (the caret\n * holds), or a hidden page.\n */\n nextCaretChange(now: number): number | undefined {\n const node = this.focusedEditable;\n if (node === null || !this.visible) {\n return undefined;\n }\n const model = editorFor(node);\n if (model.composing || !model.collapsed) {\n return undefined;\n }\n return nextCaretToggle(model, now);\n }\n\n /**\n * The page was hidden or shown. A hidden page stops the blink so a\n * background tab schedules no frames; showing it restarts the caret.\n */\n setVisible(visible: boolean): void {\n if (this.visible === visible) {\n return;\n }\n this.visible = visible;\n const node = this.focusedEditable;\n if (node !== null) {\n editorFor(node).blinkOrigin = this.host.now();\n this.host.markDirty(node, DirtyFlags.Paint);\n }\n }\n\n /** Whether the caret may be drawn at all (the page is visible). */\n get caretEnabled(): boolean {\n return this.visible;\n }\n\n // ---------------------------------------------------------------------------\n // Internals\n // ---------------------------------------------------------------------------\n\n private handleFocusChange(node: UiNode | null): void {\n const previous = this.focusedEditable;\n const next = node !== null && isEditableNode(node) ? node : null;\n if (previous === next) {\n return;\n }\n if (previous !== null) {\n const model = editorFor(previous);\n if (model.composing) {\n model.commitComposition(model.text.slice(model.composition!.start, model.composition!.end));\n }\n model.focused = false;\n this.host.markDirty(previous, DirtyFlags.Paint);\n }\n this.focusedEditable = next;\n this.compositionOpen = false;\n this.verticalGoalX = undefined;\n if (next !== null) {\n const model = editorFor(next);\n model.focused = true;\n model.blinkOrigin = this.host.now();\n this.host.markDirty(next, DirtyFlags.Paint);\n }\n }\n\n /**\n * Runs an edit unless a `beforeinput` listener cancels it, then\n * reports it. Returns true when the input was consumed either way.\n */\n private applyEdit(\n node: UiNode,\n model: EditableTextModel,\n inputType: string,\n data: string | null,\n run: () => void\n ): boolean {\n const before = new UiBeforeInputEvent(inputType, data);\n this.dispatcher.dispatch(before, node);\n if (before.defaultPrevented) {\n return true;\n }\n const text = model.text;\n run();\n this.afterTextChange(node, model, text !== model.text);\n return true;\n }\n\n private history(node: UiNode, model: EditableTextModel, inputType: string, run: () => boolean): boolean {\n const before = new UiBeforeInputEvent(inputType, null);\n this.dispatcher.dispatch(before, node);\n if (before.defaultPrevented) {\n return true;\n }\n const text = model.text;\n run();\n this.afterTextChange(node, model, text !== model.text);\n return true;\n }\n\n private afterTextChange(node: UiNode, model: EditableTextModel, changed: boolean): void {\n this.verticalGoalX = undefined;\n model.blinkOrigin = this.host.now();\n // The text is what layout measures, so a change is content and\n // layout; an unchanged text with a moved caret is paint only.\n this.host.markDirty(\n node,\n changed || this.compositionOpen ? DirtyFlags.Content | DirtyFlags.Layout : DirtyFlags.Paint\n );\n if (changed) {\n this.dispatcher.dispatch(new UiTextChangeEvent(model.text, model.start, model.end), node);\n }\n // After the text change, so a listener reading the value sees the\n // new one rather than the value it is about to be told about.\n this.notifySelection(node, model);\n this.revealCaret(node);\n }\n\n /**\n * Reports the selection, if it has actually moved since last time.\n *\n * The guard is what keeps this quiet: holding a right arrow against\n * the end of the text moves nothing and must say nothing, and a\n * listener that recomputed decoration on every key would otherwise\n * do it forever for no reason.\n *\n * `hasListeners` already makes an unheard dispatch free, so the\n * cost when nobody is listening is the two comparisons here.\n */\n private notifySelection(node: UiNode, model: EditableTextModel): void {\n if (model.anchor === model.notifiedAnchor && model.focus === model.notifiedFocus) {\n return;\n }\n model.notifiedAnchor = model.anchor;\n model.notifiedFocus = model.focus;\n this.dispatcher.dispatch(\n new UiSelectionChangeEvent(model.text, model.start, model.end, model.anchor, model.focus),\n node\n );\n }\n\n private afterSelectionChange(node: UiNode, model: EditableTextModel, keepGoal = false): void {\n if (!keepGoal) {\n this.verticalGoalX = undefined;\n }\n model.blinkOrigin = this.host.now();\n this.host.markDirty(node, DirtyFlags.Paint);\n this.notifySelection(node, model);\n this.revealCaret(node);\n }\n\n /**\n * Asks the host to scroll the caret into view, when the node has been\n * laid out: the field's own text first, then any scroll container\n * around it.\n *\n * `layoutOf` places the text where it is seen, so the caret comes\n * back with the field's own scroll already taken off; the reveal is\n * asked for in the node's unscrolled coordinates, which is where the\n * offset it wants is measured from.\n */\n private revealCaret(node: UiNode): void {\n const rec = this.host.recordFor(node);\n if (rec === undefined) {\n return;\n }\n const caret = this.layoutOf(node).caretRect();\n this.host.reveal(node, {\n x: caret.x + rec.scrollX - CARET_REVEAL_PADDING,\n y: caret.y + rec.scrollY - CARET_REVEAL_PADDING,\n width: 1 + 2 * CARET_REVEAL_PADDING,\n height: caret.height + 2 * CARET_REVEAL_PADDING\n });\n }\n\n /**\n * The node's text laid out in node-local coordinates: the content box\n * starts at the padding and is shifted by the field's own scroll, as\n * it is for the renderers in the parent's space. Points from the\n * pointer and the caret box the shell is given are both in that same\n * seen space, so neither has to know the offset. Before the first\n * layout the record is empty and the lines fall at the origin, which\n * is still a valid place for a caret.\n */\n /**\n * Where the caret is inside a field, in the field's own coordinates.\n *\n * Relative to the node's border-box origin, with the field's own\n * scroll already applied — so a popup placed under the caret adds\n * the node's position on screen and nothing else.\n *\n * Public because an application cannot work this out. The geometry\n * needs the paragraph as it was *laid out*, which means the\n * measurer, the resolved paint and the layout record, and an\n * application that re-measured the text to find the caret would be\n * a second measurer that must never disagree with this one. Asking\n * is the only version that stays right.\n *\n * Null when the node is not an editable, or has not been laid out.\n */\n caretRectOf(node: UiNode): CaretRect | null {\n if (!isEditableNode(node) || this.host.recordFor(node) === undefined) {\n return null;\n }\n return this.layoutOf(node).caretRect();\n }\n\n private layoutOf(node: UiNode): EditableLayout {\n const rec = this.host.recordFor(node);\n const state = resolvePaintState(node, this.paint);\n const box: LayoutBox =\n rec === undefined\n ? { x: 0, y: 0, width: 0, height: 0 }\n : {\n x: rec.paddingLeft - rec.scrollX,\n y: rec.paddingTop - rec.scrollY,\n width: Math.max(0, rec.width - rec.paddingLeft - rec.paddingRight),\n height: Math.max(0, rec.height - rec.paddingTop - rec.paddingBottom)\n };\n return new EditableLayout(state.editor!, box, state, this.host.measurer);\n }\n}\n\nfunction deleteInputType(unit: EditUnit, direction: -1 | 1): string {\n const side = direction < 0 ? 'Backward' : 'Forward';\n switch (unit) {\n case 'word':\n return `deleteWord${side}`;\n case 'line':\n case 'document':\n return `deleteSoftLine${side}`;\n default:\n return `deleteContent${side}`;\n }\n}\n","import {\n MOUSE_POINTER,\n wheelDeltaYOf,\n type UiKeyModifiers,\n type UiPointerDevice,\n type UiPointerKind\n} from './UiInputEvent';\nimport type { UiKeyboardController } from './UiKeyboardController';\nimport type { UiPointerController } from './UiPointerController';\nimport type { UiWheelController } from './UiWheelController';\n\n/**\n * Minimal event target surface the adapter can attach to. Real DOM\n * EventTargets satisfy this structurally; tests use a fake.\n */\nexport interface PlatformEventTarget {\n addEventListener(\n type: string,\n listener: ((event: Event) => void) | null,\n options?: AddEventListenerOptions | boolean\n ): void;\n removeEventListener(\n type: string,\n listener: ((event: Event) => void) | null,\n options?: EventListenerOptions | boolean\n ): void;\n}\n\n/**\n * Surface abstraction that supplies pointer and keyboard targets and\n * converts DOM viewport coordinates into the layout coordinate space.\n */\nexport interface PlatformSurface {\n readonly pointerTarget: PlatformEventTarget;\n readonly keyboardTarget: PlatformEventTarget;\n clientToLocal(clientX: number, clientY: number): { x: number; y: number };\n /**\n * Sets the surface's `touch-action`, when the surface is something\n * that has one.\n *\n * The adapter drives this rather than leaving it fixed at the value\n * `prepareInputSurface` set, because the right value is not a\n * property of the canvas — it is a property of what is currently\n * inside it. Optional: a test fake, or a surface that is not a DOM\n * element, has nothing to set.\n */\n setTouchAction?(value: string): void;\n /**\n * Releases whatever the surface holds outside the adapter's own\n * listeners — a cached measurement's invalidation listeners, an\n * observer.\n *\n * Called from `detach`, so a surface with a lifetime of its own does\n * not need its host to know that: both hosts construct the surface\n * inline in the `attach` call and keep no reference to it, and\n * asking them to start keeping one would have been a change to\n * every host rather than to the one class that grew the listeners.\n * Optional, since a fake or a surface that holds nothing has nothing\n * to release.\n */\n dispose?(): void;\n}\n\nexport interface PlatformAdapterOptions {\n pointerController: UiPointerController;\n wheelController: UiWheelController;\n keyboardController: UiKeyboardController;\n}\n\n/**\n * Bridges platform/browser input events to the framework input\n * controllers. The adapter can be used directly (for tests, Worker\n * runtimes, or custom event sources) or attached to a PlatformSurface\n * that supplies real DOM events.\n */\nexport class UiPlatformAdapter {\n private readonly pointer: UiPointerController;\n private readonly wheel: UiWheelController;\n private readonly keyboard: UiKeyboardController;\n private surface: PlatformSurface | null = null;\n private pointerDownHandler: ((e: Event) => void) | null = null;\n private pointerMoveHandler: ((e: Event) => void) | null = null;\n private pointerUpHandler: ((e: Event) => void) | null = null;\n private pointerCancelHandler: ((e: Event) => void) | null = null;\n private wheelHandler: ((e: Event) => void) | null = null;\n private keyDownHandler: ((e: Event) => void) | null = null;\n private keyUpHandler: ((e: Event) => void) | null = null;\n\n constructor(options: PlatformAdapterOptions) {\n this.pointer = options.pointerController;\n this.wheel = options.wheelController;\n this.keyboard = options.keyboardController;\n }\n\n /** True when the adapter is currently attached to a surface. */\n get attached(): boolean {\n return this.surface !== null;\n }\n\n /**\n * Attach to a surface and start forwarding DOM events to the\n * controllers. Detaches any previous surface first.\n */\n attach(surface: PlatformSurface): void {\n this.detach();\n this.surface = surface;\n\n this.pointerDownHandler = e => {\n const p = e as PointerEvent;\n const local = surface.clientToLocal(p.clientX, p.clientY);\n // The element keeps every later event of this contact even once\n // the finger leaves its box. Touch captures implicitly and a\n // mouse does not, so without this a drag that runs off the\n // canvas stops being delivered on one device and not the other.\n capturePointer(e.target, p.pointerId);\n const event = this.pointer.pointerDown(local.x, local.y, p.buttons, modifiersFromEvent(p), pointerDeviceOf(p));\n if (event.defaultPrevented) {\n p.preventDefault();\n }\n };\n this.pointerMoveHandler = e => {\n const p = e as PointerEvent;\n const local = surface.clientToLocal(p.clientX, p.clientY);\n this.pointer.pointerMove(local.x, local.y, p.buttons, modifiersFromEvent(p), pointerDeviceOf(p));\n this.syncTouchAction();\n };\n this.pointerUpHandler = e => {\n const p = e as PointerEvent;\n const local = surface.clientToLocal(p.clientX, p.clientY);\n this.pointer.pointerUp(local.x, local.y, p.buttons, modifiersFromEvent(p), pointerDeviceOf(p));\n };\n this.pointerCancelHandler = e => {\n this.pointer.pointerCancel(pointerDeviceOf(e as PointerEvent));\n };\n this.wheelHandler = e => {\n const w = e as WheelEvent;\n const local = surface.clientToLocal(w.clientX, w.clientY);\n const event = this.wheel.wheel(\n local.x,\n local.y,\n w.deltaX,\n w.deltaY,\n modifiersFromEvent(w),\n w.deltaMode,\n wheelDeltaYOf(w)\n );\n // Both halves matter, and each was a bug on its own. `consumed`\n // says a container took the delta, and without it the page\n // behind the canvas scrolled too — one wheel, two scrolls.\n // `defaultPrevented` says an application handler took it\n // instead. Anything else is a wheel the runtime had no use for,\n // and it has to reach the page, or a canvas embedded in a\n // document becomes a scroll trap.\n if (event.consumed || event.defaultPrevented) {\n w.preventDefault();\n }\n this.syncTouchAction();\n };\n this.keyDownHandler = e => {\n const k = e as KeyboardEvent;\n const event = this.keyboard.keyDown(k.key, modifiersFromEvent(k));\n if (event.defaultPrevented) {\n k.preventDefault();\n }\n };\n this.keyUpHandler = e => {\n const k = e as KeyboardEvent;\n this.keyboard.keyUp(k.key, modifiersFromEvent(k));\n };\n\n surface.pointerTarget.addEventListener('pointerdown', this.pointerDownHandler);\n surface.pointerTarget.addEventListener('pointermove', this.pointerMoveHandler);\n surface.pointerTarget.addEventListener('pointerup', this.pointerUpHandler);\n surface.pointerTarget.addEventListener('pointercancel', this.pointerCancelHandler);\n surface.pointerTarget.addEventListener('wheel', this.wheelHandler, { passive: false });\n surface.keyboardTarget.addEventListener('keydown', this.keyDownHandler);\n surface.keyboardTarget.addEventListener('keyup', this.keyUpHandler);\n this.syncTouchAction();\n }\n\n /**\n * Puts the surface's `touch-action` in step with what the runtime\n * currently has to scroll.\n *\n * Called after input that could have changed the answer, and public\n * so a host that changes the tree without any input — a list that\n * grew, a route that swapped — can say so. Cheap and idempotent:\n * it walks the scroll containers, which are few, and writes to the\n * DOM only on a change.\n */\n syncTouchAction(): void {\n this.surface?.setTouchAction?.(touchActionFor(this.wheel.scrollsAnything()));\n }\n\n /** Remove all listeners from the attached surface. */\n detach(): void {\n if (this.surface === null) {\n return;\n }\n const surface = this.surface;\n if (this.pointerDownHandler !== null) {\n surface.pointerTarget.removeEventListener('pointerdown', this.pointerDownHandler);\n }\n if (this.pointerMoveHandler !== null) {\n surface.pointerTarget.removeEventListener('pointermove', this.pointerMoveHandler);\n }\n if (this.pointerUpHandler !== null) {\n surface.pointerTarget.removeEventListener('pointerup', this.pointerUpHandler);\n }\n if (this.pointerCancelHandler !== null) {\n surface.pointerTarget.removeEventListener('pointercancel', this.pointerCancelHandler);\n }\n if (this.wheelHandler !== null) {\n surface.pointerTarget.removeEventListener('wheel', this.wheelHandler);\n }\n if (this.keyDownHandler !== null) {\n surface.keyboardTarget.removeEventListener('keydown', this.keyDownHandler);\n }\n if (this.keyUpHandler !== null) {\n surface.keyboardTarget.removeEventListener('keyup', this.keyUpHandler);\n }\n // After the adapter's own listeners, and before the field is\n // cleared: a surface that caches anything about the element keeps\n // the listeners that invalidate it, and this is the only moment\n // either host tells anybody that the surface is finished with.\n surface.dispose?.();\n this.surface = null;\n this.pointerDownHandler = null;\n this.pointerMoveHandler = null;\n this.pointerUpHandler = null;\n this.pointerCancelHandler = null;\n this.wheelHandler = null;\n this.keyDownHandler = null;\n this.keyUpHandler = null;\n }\n}\n\n/**\n * The device behind a DOM pointer event.\n *\n * Anything the browser reports that is not one of the three known\n * kinds is read as a mouse: `pointerType` is an open string, and an\n * unrecognised device behaving like the default is better than one\n * whose events are dropped.\n *\n * Exported because the worker shell does the same conversion on its\n * way to the protocol, and the two must not answer differently.\n */\nexport function pointerDeviceOf(event: PointerEvent): UiPointerDevice {\n const kind = event.pointerType;\n if (kind !== 'touch' && kind !== 'pen' && kind !== 'mouse') {\n return MOUSE_POINTER;\n }\n return { id: event.pointerId, kind: kind as UiPointerKind };\n}\n\n/**\n * Asks the element to keep this contact, ignoring the failure.\n *\n * `setPointerCapture` throws for a pointer that is no longer active —\n * a contact already released between the event and this call — and\n * that is not a reason to lose the press. A target that has no such\n * method (a test double, a non-element event target) is left alone.\n */\nexport function capturePointer(target: EventTarget | null, pointerId: number): void {\n const element = target as { setPointerCapture?: (id: number) => void } | null;\n if (typeof element?.setPointerCapture !== 'function') {\n return;\n }\n try {\n element.setPointerCapture(pointerId);\n } catch {\n // The contact ended first; the press will end with it.\n }\n}\n\nfunction modifiersFromEvent(event: {\n shiftKey: boolean;\n ctrlKey: boolean;\n altKey: boolean;\n metaKey: boolean;\n}): UiKeyModifiers {\n return {\n shift: event.shiftKey,\n ctrl: event.ctrlKey,\n alt: event.altKey,\n meta: event.metaKey\n };\n}\n\n/**\n * Makes an element usable as an input surface.\n *\n * Five settings, all of them the same instruction in different words:\n * this element is an application, not a document. Every one of them is\n * invisible until a finger arrives, and getting one wrong produces a\n * subtly dead or subtly wrong surface rather than an error.\n *\n * touch-action the browser does not take gestures for\n * page scrolling and double-tap zoom. The\n * framework scrolls its own containers.\n * This is the starting value only: once\n * an adapter is attached it owns this\n * property and relaxes it to `auto`\n * whenever the runtime has nothing of its\n * own to scroll, so a finger over an\n * embedded canvas still scrolls the page\n * around it. See `syncTouchAction`.\n * user-select a press-and-drag does not start selecting\n * the page around the canvas. The framework\n * has its own text selection, over text the\n * DOM cannot see.\n * -webkit-touch-callout a long press does not raise the iOS\n * callout menu over the app, which would\n * land on the LongPress gesture the app is\n * about to receive.\n * -webkit-tap-highlight a tap does not flash a grey box over\n * whatever the browser guessed was hit.\n *\n * Vendor-prefixed properties are set through the style map rather than\n * as fields, since TypeScript's CSSStyleDeclaration has only some of\n * them and the missing ones are exactly the ones iOS needs.\n */\nexport function prepareInputSurface(element: HTMLElement): void {\n const style = element.style;\n style.touchAction = 'none';\n style.userSelect = 'none';\n style.setProperty('-webkit-user-select', 'none');\n style.setProperty('-webkit-touch-callout', 'none');\n style.setProperty('-webkit-tap-highlight-color', 'transparent');\n // The surface carries `tabIndex = 0` so that Tab reaches the\n // application at all, which also gives it the browser's own focus\n // outline: click a button drawn on the canvas and the ring lands\n // around the whole canvas rather than around the button. Gesso draws\n // its own indicator for whichever node holds focus (`focusRing` in\n // `modifiers`, coloured by the `focusRing` token), so the platform\n // ring is not the only one and suppressing it costs nothing a\n // keyboard user can see.\n style.outline = 'none';\n // The browser's own menu would land directly on top of the\n // `ContextMenu` event the runtime dispatches for the same press,\n // which is the mistake `-webkit-touch-callout` above was added to\n // stop iOS making. Registered on the element rather than removed on\n // detach for the same reason the styles are written and never\n // unwritten: the surface is the application's, and the listener\n // stops existing when the element does.\n element.addEventListener('contextmenu', suppressContextMenu);\n}\n\n/** Keeps the platform menu out of the way of the framework's own. */\nfunction suppressContextMenu(event: Event): void {\n event.preventDefault();\n}\n\n/**\n * Surface implementation backed by a real HTML element. Pointer and\n * wheel events come from the element; keyboard events come from\n * `window` by default so Tab/keys work even when the canvas is not\n * focused. `clientToLocal` subtracts the element's bounding client\n * rect, producing layout-logical coordinates.\n *\n * That rect is cached, because reading it is not free. A\n * `getBoundingClientRect` against a dirty document forces the browser\n * to flush style and layout synchronously, and `clientToLocal` ran\n * once per pointer event on the main thread — so a pointermove burst\n * through a drag was a burst of forced layouts, which is the single\n * largest piece of frame time this shell was giving away. The\n * worker-backed shell caches the same two numbers for the same\n * reason; neither path is worth fixing alone.\n *\n * What drops the cache is everything that can move or resize the\n * element and says so: a scroll anywhere in the ancestor chain, a\n * window resize, and a ResizeObserver on the element where the\n * environment has one. Scroll is listened for on `window` in the\n * capture phase because a scroll event on some inner container does\n * not bubble, and the element's offset moves whichever ancestor\n * scrolled. A pointerdown drops it too, so every gesture starts from\n * a rect read after the press.\n *\n * What that gives up is exactness while a press is already down and\n * something moves the element with no event at all — a CSS\n * transition on the canvas's own position, a frame callback writing\n * `style.left`. A drag in flight then tracks against where the\n * element was when the finger landed. The pointerdown read is what\n * bounds the error: it cannot outlive one press. The alternative was\n * to re-read once per animation frame instead, which costs a forced\n * layout per frame in exchange for being wrong for less of a frame —\n * the same defect, priced higher.\n *\n * Every global here is reached for through a guard, because this is\n * `gesso-core` and core does not get to assume a browser. With no\n * `window` and no `ResizeObserver` nothing is observed, and then\n * nothing is cached either: `clientToLocal` reads the rect on every\n * call, exactly as it did before. A cache that no event can\n * invalidate is a wrong answer waiting to be handed out, and a\n * headless or test host pays nothing for the listeners it cannot\n * have. For the same reason the element is only measured when a\n * coordinate is actually asked for, never in the constructor: the\n * element handed to a test is not always one with a box.\n */\nexport class CanvasPlatformSurface implements PlatformSurface {\n /** The element's viewport offset, or null when it must be re-read. */\n private rect: { left: number; top: number } | null = null;\n /** Null where the environment has no window to listen on. */\n private viewportRoot: PlatformEventTarget | null = null;\n private resizeObserver: ResizeObserver | null = null;\n private readonly invalidateRect = (): void => {\n this.rect = null;\n };\n\n constructor(\n private readonly element: HTMLElement,\n // Guarded rather than `= window`, which is a ReferenceError and\n // not merely undefined on a thread that has no window — and a\n // surface that throws on construction is no use to the headless\n // host this package is also built for. With no window there is\n // nothing to hear keys on, so the target is inert and says so by\n // accepting listeners it will never call.\n private readonly keyboardRoot: PlatformEventTarget = browserWindow() ?? inertEventTarget\n ) {\n const root = browserWindow();\n if (root !== null) {\n // `passive`, because none of the three is ever preventDefaulted\n // here, and a non-passive scroll listener on window is its own\n // scrolling jank.\n root.addEventListener('scroll', this.invalidateRect, { capture: true, passive: true });\n root.addEventListener('resize', this.invalidateRect, { passive: true });\n root.addEventListener('pointerdown', this.invalidateRect, { capture: true, passive: true });\n this.viewportRoot = root;\n }\n this.resizeObserver = observeElementBox(element, this.invalidateRect);\n }\n\n get pointerTarget(): PlatformEventTarget {\n return this.element;\n }\n\n get keyboardTarget(): PlatformEventTarget {\n return this.keyboardRoot;\n }\n\n clientToLocal(clientX: number, clientY: number): { x: number; y: number } {\n const rect = this.rect ?? this.readRect();\n return { x: clientX - rect.left, y: clientY - rect.top };\n }\n\n setTouchAction(value: string): void {\n if (this.element.style.touchAction !== value) {\n this.element.style.touchAction = value;\n }\n }\n\n /**\n * Removes the listeners and the observer the constructor added.\n *\n * `UiPlatformAdapter.detach` calls this for whatever surface it\n * holds, which is how the two existing hosts — `GessoApp.dispose`\n * and the playground — get the teardown without either of them\n * learning that the surface now has one. Safe to call twice, and\n * safe to keep using afterwards: a disposed surface has nothing\n * left that could tell it the element moved, so it stops caching\n * and goes back to measuring on every call rather than answering\n * from a rect nothing can correct.\n */\n dispose(): void {\n const root = this.viewportRoot;\n if (root !== null) {\n root.removeEventListener('scroll', this.invalidateRect, { capture: true });\n root.removeEventListener('resize', this.invalidateRect);\n root.removeEventListener('pointerdown', this.invalidateRect, { capture: true });\n this.viewportRoot = null;\n }\n this.resizeObserver?.disconnect();\n this.resizeObserver = null;\n this.rect = null;\n }\n\n /**\n * Measures the element, and keeps the answer only if something is\n * watching for it to go stale.\n *\n * An element with no `getBoundingClientRect` reads as sitting at the\n * viewport origin, for the reason `capturePointer` ignores a target\n * with no `setPointerCapture`: a test double or a non-element event\n * target is not a reason to fail a press.\n */\n private readRect(): { left: number; top: number } {\n const box =\n typeof this.element.getBoundingClientRect === 'function'\n ? this.element.getBoundingClientRect()\n : { left: 0, top: 0 };\n const rect = { left: box.left, top: box.top };\n if (this.viewportRoot !== null || this.resizeObserver !== null) {\n this.rect = rect;\n }\n return rect;\n }\n}\n\n/** The window, on a thread that has one. */\nfunction browserWindow(): PlatformEventTarget | null {\n return typeof window === 'undefined' ? null : window;\n}\n\n/** Stands in for a window that isn't there, so nothing has to branch. */\nconst inertEventTarget: PlatformEventTarget = {\n addEventListener(): void {},\n removeEventListener(): void {}\n};\n\n/**\n * Watches an element's box, where the environment can.\n *\n * Two things can go wrong and neither is fatal: there may be no\n * `ResizeObserver` at all (a worker, Node, an older engine), and the\n * \"element\" may be a double that `observe` refuses. Both mean the\n * caller simply learns nothing about resizes, which it is written to\n * survive.\n */\nfunction observeElementBox(element: HTMLElement, onResize: () => void): ResizeObserver | null {\n if (typeof ResizeObserver === 'undefined') {\n return null;\n }\n try {\n const observer = new ResizeObserver(onResize);\n observer.observe(element);\n return observer;\n } catch {\n return null;\n }\n}\n\n/**\n * The `touch-action` a runtime in this state should have.\n *\n * `'none'` means the framework takes every gesture, which is right\n * whenever it has something of its own to scroll — its touch scroller\n * handles the finger and the page must not fight it. `'auto'` hands\n * gestures back, which is what an embedded canvas with nothing to\n * scroll has to do, or a finger over it cannot scroll the article it\n * sits in.\n *\n * There is no middle value worth using. `pan-y` would let the page\n * scroll vertically while the runtime kept horizontal drags, but\n * touch-action is latched when the finger lands and cannot be\n * narrowed afterwards, so a runtime that guessed wrong has lost the\n * gesture either way. The coarse answer is the one it can defend.\n */\nexport function touchActionFor(scrollsAnything: boolean): string {\n return scrollsAnything ? 'none' : 'auto';\n}\n","export enum MainAxisAlignment {\n Start = 0,\n Center = 1,\n End = 2,\n SpaceBetween = 3,\n SpaceEvenly = 4,\n SpaceAround = 5\n}\n\nexport enum CrossAxisAlignment {\n Start = 0,\n Center = 1,\n End = 2,\n Stretch = 3,\n /** Rows only: align first baselines. A column treats it as Start. */\n Baseline = 4\n}\n\nexport function parseMainAxisAlignment(value: unknown): MainAxisAlignment {\n if (typeof value === 'string') {\n switch (value) {\n case 'center':\n return MainAxisAlignment.Center;\n case 'end':\n return MainAxisAlignment.End;\n case 'space-between':\n return MainAxisAlignment.SpaceBetween;\n case 'space-evenly':\n return MainAxisAlignment.SpaceEvenly;\n case 'space-around':\n return MainAxisAlignment.SpaceAround;\n }\n }\n if (typeof value === 'number') {\n return value as MainAxisAlignment;\n }\n return MainAxisAlignment.Start;\n}\n\nexport function parseCrossAxisAlignment(value: unknown): CrossAxisAlignment | undefined {\n if (typeof value === 'string') {\n switch (value) {\n case 'start':\n return CrossAxisAlignment.Start;\n case 'center':\n return CrossAxisAlignment.Center;\n case 'end':\n return CrossAxisAlignment.End;\n case 'stretch':\n return CrossAxisAlignment.Stretch;\n case 'baseline':\n return CrossAxisAlignment.Baseline;\n }\n }\n if (typeof value === 'number') {\n return value as CrossAxisAlignment;\n }\n return undefined;\n}\n\n/** Distribution of a multi-line flex container's lines along the cross axis. */\nexport enum AlignContent {\n Start = 0,\n Center = 1,\n End = 2,\n SpaceBetween = 3,\n SpaceEvenly = 4,\n SpaceAround = 5,\n Stretch = 6\n}\n\nexport function parseAlignContent(value: unknown): AlignContent {\n switch (value) {\n case 'start':\n return AlignContent.Start;\n case 'center':\n return AlignContent.Center;\n case 'end':\n return AlignContent.End;\n case 'space-between':\n return AlignContent.SpaceBetween;\n case 'space-evenly':\n return AlignContent.SpaceEvenly;\n case 'space-around':\n return AlignContent.SpaceAround;\n default:\n return AlignContent.Stretch;\n }\n}\n","import { AlignContent } from './Alignment';\nimport type { UiTrackSize } from './UiLength';\nimport { isAutoLength, isFrLength, isMinMaxTrack, isPercentLength } from './UiLength';\n\n/**\n * The grid algorithm, without nodes: placement into cells and track\n * sizing (a subset of CSS Grid §11). The layout engine feeds it items\n * and measurements and reads back track sizes and cell rectangles.\n *\n * Supported: explicit tracks of `px`, `percent`, `auto`, `fr` and\n * `minmax(min, max)`, implicit tracks sized by an auto track size,\n * sparse auto-placement in row or column flow, explicit placement by\n * 1-based line with spans, gaps, and track distribution (`start`,\n * `center`, `end`, `space-*`, `stretch`). Not supported: dense packing,\n * negative lines, named lines and areas, subgrid.\n */\n\nexport interface GridItemRequest<T> {\n item: T;\n /** 1-based start line, or undefined for auto-placement. */\n column: number | undefined;\n row: number | undefined;\n columnSpan: number;\n rowSpan: number;\n}\n\nexport interface GridPlacement<T> {\n item: T;\n /** 0-based track indices; end is exclusive. */\n columnStart: number;\n columnEnd: number;\n rowStart: number;\n rowEnd: number;\n}\n\nexport interface GridPlacementResult<T> {\n placements: GridPlacement<T>[];\n columnCount: number;\n rowCount: number;\n}\n\n/**\n * Places items into cells (CSS Grid §8.5, without dense packing).\n *\n * Items with both lines given go first, where they say. Items with only\n * the line on the flow's cross axis given are locked to that track and\n * take the first free run along the flow axis. Everything else follows\n * a cursor that only moves forward, wrapping when it reaches the end of\n * the explicit tracks on the cross axis and growing the grid along the\n * flow axis as needed.\n */\nexport function placeGridItems<T>(\n items: readonly GridItemRequest<T>[],\n explicitColumns: number,\n explicitRows: number,\n flow: 'row' | 'column'\n): GridPlacementResult<T> {\n const occupied = new Set<string>();\n const placements: (GridPlacement<T> | null)[] = items.map(() => null);\n let columnCount = Math.max(explicitColumns, 1);\n let rowCount = Math.max(explicitRows, 1);\n\n const occupy = (p: GridPlacement<T>): void => {\n for (let c = p.columnStart; c < p.columnEnd; c++) {\n for (let r = p.rowStart; r < p.rowEnd; r++) {\n occupied.add(`${c},${r}`);\n }\n }\n columnCount = Math.max(columnCount, p.columnEnd);\n rowCount = Math.max(rowCount, p.rowEnd);\n };\n const fits = (c: number, r: number, cs: number, rs: number): boolean => {\n for (let x = c; x < c + cs; x++) {\n for (let y = r; y < r + rs; y++) {\n if (occupied.has(`${x},${y}`)) {\n return false;\n }\n }\n }\n return true;\n };\n\n // 1. Fully specified items.\n items.forEach((request, index) => {\n if (request.column !== undefined && request.row !== undefined) {\n const p: GridPlacement<T> = {\n item: request.item,\n columnStart: request.column - 1,\n columnEnd: request.column - 1 + request.columnSpan,\n rowStart: request.row - 1,\n rowEnd: request.row - 1 + request.rowSpan\n };\n placements[index] = p;\n occupy(p);\n }\n });\n\n // 2. Items locked on the cross axis of the flow.\n const rowFlow = flow === 'row';\n items.forEach((request, index) => {\n if (placements[index] !== null) {\n return;\n }\n const locked = rowFlow ? request.row : request.column;\n if (locked === undefined) {\n return;\n }\n const crossStart = locked - 1;\n const crossSpan = rowFlow ? request.rowSpan : request.columnSpan;\n const mainSpan = rowFlow ? request.columnSpan : request.rowSpan;\n let main = 0;\n for (;;) {\n const c = rowFlow ? main : crossStart;\n const r = rowFlow ? crossStart : main;\n if (fits(c, r, rowFlow ? mainSpan : crossSpan, rowFlow ? crossSpan : mainSpan)) {\n break;\n }\n main++;\n }\n const p: GridPlacement<T> = rowFlow\n ? {\n item: request.item,\n columnStart: main,\n columnEnd: main + mainSpan,\n rowStart: crossStart,\n rowEnd: crossStart + crossSpan\n }\n : {\n item: request.item,\n columnStart: crossStart,\n columnEnd: crossStart + crossSpan,\n rowStart: main,\n rowEnd: main + mainSpan\n };\n placements[index] = p;\n occupy(p);\n });\n\n // 3. Auto-placed items, with a forward-only cursor.\n const crossLimit = rowFlow ? columnCount : rowCount;\n let cursorMain = 0;\n let cursorCross = 0;\n items.forEach((request, index) => {\n if (placements[index] !== null) {\n return;\n }\n const crossSpan = rowFlow ? request.columnSpan : request.rowSpan;\n const mainSpan = rowFlow ? request.rowSpan : request.columnSpan;\n const lockedMain = rowFlow ? request.row : request.column;\n if (lockedMain !== undefined) {\n // Given on the flow axis only: start at that line, search across.\n const main = lockedMain - 1;\n if (main !== cursorMain) {\n cursorMain = main;\n cursorCross = 0;\n }\n }\n for (;;) {\n if (cursorCross + crossSpan > Math.max(crossLimit, crossSpan)) {\n cursorCross = 0;\n cursorMain++;\n continue;\n }\n const c = rowFlow ? cursorCross : cursorMain;\n const r = rowFlow ? cursorMain : cursorCross;\n if (fits(c, r, rowFlow ? crossSpan : mainSpan, rowFlow ? mainSpan : crossSpan)) {\n const p: GridPlacement<T> = rowFlow\n ? { item: request.item, columnStart: c, columnEnd: c + crossSpan, rowStart: r, rowEnd: r + mainSpan }\n : { item: request.item, columnStart: c, columnEnd: c + mainSpan, rowStart: r, rowEnd: r + crossSpan };\n placements[index] = p;\n occupy(p);\n cursorCross += crossSpan;\n break;\n }\n cursorCross++;\n }\n });\n\n return { placements: placements as GridPlacement<T>[], columnCount, rowCount };\n}\n\n// ---------------------------------------------------------------------------\n// Track sizing\n// ---------------------------------------------------------------------------\n\nexport interface GridTrack {\n /** Where the track starts along the axis, from the content-box start. */\n offset: number;\n size: number;\n /** Intrinsic minimum the track settled on before free space was added. */\n base: number;\n}\n\n/** An item's min-content and max-content size along the axis being sized. */\nexport interface GridContribution {\n min: number;\n max: number;\n}\n\ninterface WorkTrack {\n base: number;\n limit: number;\n flex: number;\n intrinsicMin: boolean;\n intrinsicMax: boolean;\n /** Stretches when the container has spare space and distribution is stretch. */\n auto: boolean;\n}\n\nexport interface GridTrackSizingInput {\n /** Track size per track, explicit ones followed by implicit ones. */\n sizes: readonly UiTrackSize[];\n /** Definite content-box extent on this axis, or undefined. */\n available: number | undefined;\n gap: number;\n distribution: AlignContent;\n /** Each item's span on this axis (0-based start, exclusive end) and its contribution. */\n items: readonly { start: number; end: number; contribution: GridContribution }[];\n}\n\nexport interface GridTrackSizingResult {\n tracks: GridTrack[];\n /** Σ sizes + gaps: the content extent along the axis. */\n total: number;\n /** Σ intrinsic minimums + gaps: the axis's min-content size. */\n minTotal: number;\n}\n\n/**\n * Sizes the tracks of one axis (CSS Grid §11.5–11.8, simplified).\n *\n * 1. Initialise each track's base size and growth limit from its size.\n * 2. Resolve intrinsic sizes: items spanning only non-flexible tracks,\n * smallest spans first, raise the bases of intrinsic-min tracks by\n * their min-content and the limits of intrinsic-max tracks by their\n * max-content, spread equally over the spanned tracks.\n * 3. Maximise: spare definite space grows bases toward their limits.\n * 4. Flexible tracks share what remains by their fr factors; without a\n * definite size the fr is the largest an item or base demands.\n * 5. Stretch: with a definite size and `stretch` distribution, auto\n * tracks share the leftover equally.\n * Offsets then follow the distribution (start, center, end, space-*).\n */\nexport function sizeGridTracks(input: GridTrackSizingInput): GridTrackSizingResult {\n const { sizes, available, gap, distribution, items } = input;\n const count = sizes.length;\n const tracks: WorkTrack[] = sizes.map(size => initialTrack(size, available));\n const gaps = gap * Math.max(0, count - 1);\n\n // 2. Intrinsic contributions, by span. Items spanning several tracks\n // one of which is flexible contribute nothing here (their automatic\n // minimum is zero, CSS Grid §6.6); the flexible step sizes them.\n const spanned = items\n .map(item => ({ ...item, span: item.end - item.start }))\n .filter(item => item.span === 1 || (item.span > 1 && !rangeHasFlex(tracks, item.start, item.end)))\n .sort((a, b) => a.span - b.span);\n for (const item of spanned) {\n distributeToTracks(tracks, item.start, item.end, item.contribution.min, gap, 'base');\n distributeToTracks(tracks, item.start, item.end, item.contribution.max, gap, 'limit');\n }\n for (const track of tracks) {\n if (!isFinite(track.limit)) {\n track.limit = track.base;\n }\n track.limit = Math.max(track.limit, track.base);\n }\n const minTotal = tracks.reduce((sum, track) => sum + track.base, 0) + gaps;\n\n // 3. Maximise: definite spare space grows bases toward limits; an\n // indefinite size is a max-content constraint, so every track grows\n // all the way (CSS Grid §11.6).\n if (available !== undefined) {\n const free = available - gaps - tracks.reduce((sum, track) => sum + track.base, 0);\n if (free > 0) {\n growTowardLimits(tracks, free);\n }\n } else {\n for (const track of tracks) {\n if (track.flex === 0) {\n track.base = track.limit;\n }\n }\n }\n\n // 4. Flexible tracks.\n const flexTracks = tracks.filter(track => track.flex > 0);\n if (flexTracks.length > 0) {\n let fr: number;\n if (available !== undefined) {\n fr = findFrSize(tracks, available - gaps);\n } else {\n fr = 0;\n for (const track of flexTracks) {\n fr = Math.max(fr, track.base / track.flex);\n }\n for (const item of items) {\n if (item.end > item.start && rangeAllFlex(tracks, item.start, item.end)) {\n let factors = 0;\n for (let i = item.start; i < item.end; i++) {\n factors += tracks[i].flex;\n }\n if (factors > 0) {\n fr = Math.max(fr, (item.contribution.max - gap * (item.end - item.start - 1)) / factors);\n }\n }\n }\n }\n for (const track of flexTracks) {\n track.base = Math.max(track.base, fr * track.flex);\n track.limit = track.base;\n }\n }\n\n // 5. Stretch auto tracks into leftover definite space.\n let total = tracks.reduce((sum, track) => sum + track.base, 0) + gaps;\n if (available !== undefined && distribution === AlignContent.Stretch) {\n const stretchable = tracks.filter(track => track.auto && track.flex === 0);\n const free = available - total;\n if (free > 0 && stretchable.length > 0) {\n for (const track of stretchable) {\n track.base += free / stretchable.length;\n }\n total = available;\n }\n }\n\n // Offsets by distribution.\n let leading = 0;\n let between = gap;\n if (available !== undefined && available > total && count > 0) {\n const free = available - total;\n switch (distribution) {\n case AlignContent.Center:\n leading = free / 2;\n break;\n case AlignContent.End:\n leading = free;\n break;\n case AlignContent.SpaceBetween:\n if (count > 1) {\n between = gap + free / (count - 1);\n }\n break;\n case AlignContent.SpaceAround: {\n const slot = free / count;\n leading = slot / 2;\n between = gap + slot;\n break;\n }\n case AlignContent.SpaceEvenly: {\n const slot = free / (count + 1);\n leading = slot;\n between = gap + slot;\n break;\n }\n default:\n break;\n }\n }\n const result: GridTrack[] = [];\n let cursor = leading;\n for (let i = 0; i < count; i++) {\n result.push({ offset: cursor, size: tracks[i].base, base: tracks[i].base });\n cursor += tracks[i].base + (i < count - 1 ? between : 0);\n }\n return { tracks: result, total, minTotal };\n}\n\nfunction initialTrack(size: UiTrackSize, available: number | undefined): WorkTrack {\n const track: WorkTrack = { base: 0, limit: Infinity, flex: 0, intrinsicMin: false, intrinsicMax: false, auto: false };\n if (typeof size === 'number') {\n track.base = size;\n track.limit = size;\n return track;\n }\n if (isPercentLength(size)) {\n if (available !== undefined) {\n track.base = (available * size.value) / 100;\n track.limit = track.base;\n } else {\n track.intrinsicMin = true;\n track.intrinsicMax = true;\n track.auto = true;\n }\n return track;\n }\n if (isAutoLength(size)) {\n track.intrinsicMin = true;\n track.intrinsicMax = true;\n track.auto = true;\n return track;\n }\n if (isFrLength(size)) {\n // `fr` is minmax(auto, fr): a single-span item's min-content still\n // raises its base, so an fr column never gets narrower than a word.\n track.flex = size.value;\n track.intrinsicMin = true;\n return track;\n }\n if (isMinMaxTrack(size)) {\n const { min, max } = size;\n if (typeof min === 'number') {\n track.base = min;\n } else if (isPercentLength(min) && available !== undefined) {\n track.base = (available * min.value) / 100;\n } else {\n track.intrinsicMin = true;\n }\n if (typeof max === 'number') {\n track.limit = max;\n } else if (isPercentLength(max) && available !== undefined) {\n track.limit = (available * max.value) / 100;\n } else if (isFrLength(max)) {\n track.flex = max.value;\n } else {\n track.intrinsicMax = true;\n track.auto = true;\n }\n return track;\n }\n throw new Error(`Invalid grid track size ${JSON.stringify(size)}. Use a number, percent(), auto, fr() or minmax().`);\n}\n\nfunction rangeHasFlex(tracks: WorkTrack[], start: number, end: number): boolean {\n for (let i = start; i < end; i++) {\n if (tracks[i].flex > 0) {\n return true;\n }\n }\n return false;\n}\n\nfunction rangeAllFlex(tracks: WorkTrack[], start: number, end: number): boolean {\n for (let i = start; i < end; i++) {\n if (tracks[i].flex === 0) {\n return false;\n }\n }\n return true;\n}\n\n/**\n * Raises the bases (or limits) of the intrinsic tracks an item spans\n * until the span holds the item's contribution, sharing the shortfall\n * equally. A limit still infinite counts as its base.\n */\nfunction distributeToTracks(\n tracks: WorkTrack[],\n start: number,\n end: number,\n contribution: number,\n gap: number,\n field: 'base' | 'limit'\n): void {\n const receivers: WorkTrack[] = [];\n let current = gap * (end - start - 1);\n for (let i = start; i < end; i++) {\n const track = tracks[i];\n const value = field === 'base' ? track.base : isFinite(track.limit) ? track.limit : track.base;\n current += value;\n if (field === 'base' ? track.intrinsicMin : track.intrinsicMax) {\n receivers.push(track);\n }\n }\n const shortfall = contribution - current;\n if (shortfall <= 0 || receivers.length === 0) {\n return;\n }\n const share = shortfall / receivers.length;\n for (const track of receivers) {\n if (field === 'base') {\n track.base += share;\n } else {\n track.limit = (isFinite(track.limit) ? track.limit : track.base) + share;\n }\n }\n}\n\n/** Grows bases toward limits, equally, until the space or the limits run out. */\nfunction growTowardLimits(tracks: WorkTrack[], free: number): void {\n let remaining = free;\n for (let guard = 0; guard < tracks.length + 1 && remaining > 1e-9; guard++) {\n const growable = tracks.filter(track => track.flex === 0 && track.limit > track.base + 1e-9);\n if (growable.length === 0) {\n return;\n }\n const share = remaining / growable.length;\n let used = 0;\n for (const track of growable) {\n const grow = Math.min(share, track.limit - track.base);\n track.base += grow;\n used += grow;\n }\n remaining -= used;\n if (used <= 1e-9) {\n return;\n }\n }\n}\n\n/**\n * The fr size for a definite space (CSS Grid §11.7.1): the leftover after\n * inflexible tracks, divided by the flex factors — treating any flexible\n * track whose base already exceeds its share as inflexible and repeating.\n */\nfunction findFrSize(tracks: WorkTrack[], space: number): number {\n const inflexible = new Set<WorkTrack>();\n for (;;) {\n let leftover = space;\n let factors = 0;\n for (const track of tracks) {\n if (track.flex > 0 && !inflexible.has(track)) {\n factors += track.flex;\n } else {\n leftover -= track.base;\n }\n }\n if (factors <= 0) {\n return 0;\n }\n const hypothetical = Math.max(0, leftover) / Math.max(factors, 1);\n let changed = false;\n for (const track of tracks) {\n if (track.flex > 0 && !inflexible.has(track) && track.base > hypothetical * track.flex) {\n inflexible.add(track);\n changed = true;\n }\n }\n if (!changed) {\n return hypothetical;\n }\n }\n}\n","export enum FlexDirection {\n Row = 0,\n Column = 1\n}\n\nexport function parseFlexDirection(value: unknown): FlexDirection | undefined {\n if (value === 'row' || value === 'horizontal') {\n return FlexDirection.Row;\n }\n if (value === 'column' || value === 'vertical') {\n return FlexDirection.Column;\n }\n return undefined;\n}\n","import type { Constraints, Size } from './LayoutTypes';\n\n/**\n * How many times one child may be measured in a single call to a\n * protocol's `layout`.\n *\n * Two, because two is what the engine's own flex algorithm needs: a\n * base measurement at the item's content size, and a second one once\n * the main axis is resolved so a cross size that depends on it comes\n * out right. A protocol that needs a third measurement of the same\n * child is almost always measuring inside a loop over its siblings,\n * which is the shape that turns a linear pass into a quadratic one, so\n * the third throws rather than running.\n *\n * The cap is per child, so the total across a call can never exceed\n * twice the number of children however the protocol distributes them.\n */\nexport const MAX_MEASURES_PER_CHILD = 2;\n\n/**\n * One child of a custom layout, as its protocol sees it.\n *\n * Deliberately not a `UiNode`. A protocol is application code running\n * inside the layout pass, and the four things here are the whole\n * budget: it can ask a child how big it is at a given size, read what\n * it last answered, read the value the element declared as\n * `layoutData`, and say where it goes. It cannot reach the node, its\n * record, its siblings' records or the engine, so there is no way for\n * it to move a box the pass is not expecting to move, and no way for\n * it to read geometry that this pass has not computed yet.\n *\n * A handle lives for exactly one call. Holding one and using it later\n * throws, because a `place` that landed after the pass had ended would\n * write a box nothing invalidated.\n */\nexport interface UiLayoutChild {\n /** Its position among the container's in-flow children, from zero. */\n readonly index: number;\n /**\n * Whatever the element declared as `layoutData`: a weight, a lane, a\n * timestamp. The protocol decides what the value means; the engine\n * only carries it.\n */\n readonly data: unknown;\n /**\n * Measures the child under `constraints` and returns the size it\n * takes, margins excluded.\n *\n * At most `MAX_MEASURES_PER_CHILD` times per call. A child that is\n * never measured is measured once by the engine, under the same\n * constraints the container was given, so a protocol that only\n * arranges fixed-size children need not measure at all.\n */\n measure(constraints: Constraints): Size;\n /** What the last `measure` returned, or a zero size before the first. */\n readonly size: Size;\n /**\n * Puts the child's border box at a point in the container's content\n * box, `start` running from the edge the reading starts at.\n *\n * Under `textDirection=\"rtl\"` that edge is the right one and the\n * engine mirrors the coordinate, so a layout written once is laid out\n * both ways round. A protocol that needs to know which way it is\n * being mirrored reads `UiLayoutContext.direction`.\n *\n * `margin` on a child is not applied: only the protocol knows what\n * the space between two of its own children means, and a margin the\n * engine added behind its back would move boxes it had placed.\n */\n place(start: number, top: number): void;\n /**\n * Where `place` last put the child, in the same coordinates, or null\n * when this pass has not placed it. Read by `explain`.\n */\n readonly position: { readonly start: number; readonly top: number } | null;\n}\n\n/** What a protocol is told about the container it is laying out. */\nexport interface UiLayoutContext {\n /** Which way the container reads, so a protocol can be asymmetric on purpose. */\n readonly direction: 'ltr' | 'rtl';\n /** The container's content box, padding excluded, when the axis is definite. */\n readonly definiteWidth: number | undefined;\n readonly definiteHeight: number | undefined;\n}\n\n/**\n * A layout an application writes itself: the analogue of SwiftUI's\n * `Layout` and Compose's `Layout {}`.\n *\n * A masonry, a radial arrangement, a timeline and a tag cloud are all\n * one function over the children's sizes, and none of them is\n * expressible in flex or in grid. Before this they were written with\n * `position: 'absolute'` and a `ctx.bounds()` subscription, which put\n * the arrangement one frame behind the sizes it was arranged from and\n * made every such component measure its own children twice.\n *\n * The protocol speaks the engine's own vocabulary. `Constraints` is\n * the same class the engine hands down, `Size` is what a measurement\n * returns, and the size the protocol returns is clamped by the node's\n * own `width`, `minWidth` and the rest exactly as a Row's content size\n * is. That is the point of the shape: a custom layout is another\n * container, not a hole in the pass.\n *\n * Hold the protocol object still. It is a property value, compared with\n * `Object.is` like every other, so a fresh object per render marks the\n * node dirty on every frame. Build it once at module scope, or\n * memoise it on the parameters it closes over.\n *\n * See `layout/conformance` for what the engine is graded against, and\n * `apps/playground/src/examples/MasonryApp.tsx` for a masonry written\n * against these exports alone.\n */\nexport interface UiLayoutProtocol {\n /** Names the arrangement in `explain` and in an error. */\n readonly name: string;\n /**\n * Measures the children, places them, and returns the size the\n * content needs.\n *\n * Called twice per pass over a node whose layout is not memoised:\n * once while measuring, when the returned size is what the container\n * reports to its parent and `place` does nothing, and once while\n * placing, when the constraints are the resolved content box and the\n * `place` calls are what assign the boxes. Both calls see the same\n * children in the same order, so a protocol that is a function of its\n * arguments needs no state between them, and one that keeps state\n * anyway will be wrong the first time a memo hit skips a measurement.\n */\n layout(children: readonly UiLayoutChild[], constraints: Constraints, context: UiLayoutContext): Size;\n /**\n * Sentences describing the arrangement, for `LayoutEngine.explain`.\n *\n * Called after a pass, never during one, and given handles that can\n * be read but neither measured nor placed. Say the things the boxes\n * do not: how many columns there are, which one a child landed in,\n * what was left over. `formatExplanation` prints them under the\n * node's own reasons.\n */\n explain?(children: readonly UiLayoutChild[], size: Size, context: UiLayoutContext): readonly string[];\n}\n\n/** Whether a property value is a usable layout protocol. */\nexport function isLayoutProtocol(value: unknown): value is UiLayoutProtocol {\n return (\n typeof value === 'object' &&\n value !== null &&\n typeof (value as UiLayoutProtocol).name === 'string' &&\n typeof (value as UiLayoutProtocol).layout === 'function'\n );\n}\n","import type { UiNode } from '../graph/UiNode';\n\nexport interface Size {\n width: number;\n height: number;\n}\n\nexport interface LayoutBox {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\n/**\n * Options applied to a Constraints instance.\n *\n * An explicit width/height makes that axis tight\n * (min === max), mirroring CSS replaced sizing.\n */\nexport interface TightenOptions {\n width?: number;\n height?: number;\n minWidth?: number;\n maxWidth?: number;\n minHeight?: number;\n maxHeight?: number;\n}\n\n/**\n * Immutable bounds handed down the layout tree.\n *\n * Unbounded axes use Infinity for max.\n */\nexport class Constraints {\n constructor(\n readonly minWidth: number = 0,\n readonly maxWidth: number = Infinity,\n readonly minHeight: number = 0,\n readonly maxHeight: number = Infinity\n ) {}\n\n static unbounded(): Constraints {\n return new Constraints();\n }\n\n static tight(width: number, height: number): Constraints {\n return new Constraints(width, width, height, height);\n }\n\n static loose(width: number, height: number): Constraints {\n return new Constraints(0, width, 0, height);\n }\n\n hasBoundedWidth(): boolean {\n return isFinite(this.maxWidth);\n }\n\n hasBoundedHeight(): boolean {\n return isFinite(this.maxHeight);\n }\n}\n\n/** What one layout call did; see LayoutEngine.stats. */\nexport interface LayoutStats {\n /** Nodes whose measure ran (memo hits excluded). */\n measured: number;\n /** Nodes whose place ran. */\n placed: number;\n /** Subtrees laid out from a relayout boundary instead of the root. */\n relayoutRoots: number;\n /** Whether the pass started from the root. */\n fullLayout: boolean;\n /** Every node whose measure ran, in order, when `LayoutEngine.trace` is on. */\n measuredNodes: UiNode[];\n}\n\n/**\n * The result of a full layout pass for the layout root.\n *\n * Descendant geometry is read from LayoutRecords.\n */\nexport interface LayoutResult {\n root: UiNode;\n box: LayoutBox;\n contentWidth: number;\n contentHeight: number;\n scrollX: number;\n scrollY: number;\n clip: LayoutBox;\n}\n\nexport function clampSize(constraints: Constraints, width: number, height: number): Size {\n return {\n width: Math.min(Math.max(width, constraints.minWidth), constraints.maxWidth),\n height: Math.min(Math.max(height, constraints.minHeight), constraints.maxHeight)\n };\n}\n\nexport function constraintsEqual(a: Constraints, b: Constraints): boolean {\n return (\n a.minWidth === b.minWidth && a.maxWidth === b.maxWidth && a.minHeight === b.minHeight && a.maxHeight === b.maxHeight\n );\n}\n\n/**\n * Returns new constraints with the options applied on top of\n * the supplied constraints. Explicit sizes make an axis tight,\n * min/max values tighten the existing bounds.\n */\nexport function tightenConstraints(constraints: Constraints, options: TightenOptions): Constraints {\n let minWidth = Math.max(constraints.minWidth, options.minWidth ?? 0);\n let maxWidth = Math.min(constraints.maxWidth, options.maxWidth ?? Infinity);\n let minHeight = Math.max(constraints.minHeight, options.minHeight ?? 0);\n let maxHeight = Math.min(constraints.maxHeight, options.maxHeight ?? Infinity);\n minWidth = Math.max(0, minWidth);\n minHeight = Math.max(0, minHeight);\n // Like CSS, a min bound wins over a conflicting max bound.\n if (minWidth > maxWidth) {\n maxWidth = minWidth;\n }\n if (minHeight > maxHeight) {\n maxHeight = minHeight;\n }\n // An explicit size tightens the axis, clamped into the\n // resolved min/max bounds.\n if (options.width !== undefined) {\n const width = Math.min(Math.max(options.width, minWidth), maxWidth);\n minWidth = width;\n maxWidth = width;\n }\n if (options.height !== undefined) {\n const height = Math.min(Math.max(options.height, minHeight), maxHeight);\n minHeight = height;\n maxHeight = height;\n }\n return new Constraints(minWidth, maxWidth, minHeight, maxHeight);\n}\n","import { Constraints } from './LayoutTypes';\nimport type { UiNode } from '../graph/UiNode';\n\n/**\n * The constraints a record has before anything has measured it.\n *\n * One instance rather than one per record: Constraints is immutable,\n * and a record that has never been measured is only ever compared\n * against, never written through.\n */\nconst NEVER_MEASURED = Constraints.unbounded();\n\n/**\n * Mutable per-node layout projection owned by LayoutEngine.\n *\n * Records are keyed by UiNode identity and survive graph\n * reconciliation when the node survives. All geometry is\n * scalar so the projection can later migrate to typed-array\n * slabs for Worker/shared-memory transfer.\n */\nexport class LayoutRecord {\n constructor(public readonly node: UiNode) {}\n\n /** Final border box, parent-content coordinates, pre-scroll. */\n x = 0;\n y = 0;\n width = 0;\n height = 0;\n\n /** Desired size under the last constraints. */\n measuredWidth = 0;\n measuredHeight = 0;\n\n /** Measured size plus margins: contribution to the parent. */\n outerWidth = 0;\n outerHeight = 0;\n\n paddingLeft = 0;\n paddingRight = 0;\n paddingTop = 0;\n paddingBottom = 0;\n\n marginLeft = 0;\n marginRight = 0;\n marginTop = 0;\n marginBottom = 0;\n\n /** Own min/max resolved from properties (grow/shrink clamps). */\n minWidth = 0;\n maxWidth = Infinity;\n minHeight = 0;\n maxHeight = Infinity;\n\n flexGrow = 0;\n flexShrink = 1;\n /** `flex: n` shorthand without an explicit flexBasis: basis is 0. */\n flexBasisZero = false;\n\n /**\n * True when the minimum on that axis is `auto` (unset): as a flex item\n * the node then has CSS's automatic minimum, its min-content size.\n */\n minWidthAuto = true;\n minHeightAuto = true;\n\n marginLeftAuto = false;\n marginRightAuto = false;\n marginTopAuto = false;\n marginBottomAuto = false;\n\n aspectRatio: number | undefined = undefined;\n\n /**\n * Distance from the box top to the first alphabetic baseline, when\n * the node has one: its own text, or a descendant's along the start\n * edge. Boxes without one synthesise a baseline from their bottom\n * edge at alignment time (as CSS does), which is why this is a flag\n * and not a sentinel value.\n */\n hasBaseline = false;\n baseline = 0;\n\n /**\n * Intrinsic sizes. `minContentWidth` is the narrowest the content can\n * be (a text's longest word, a row's summed items) and\n * `minContentHeight` the shortest, on the same terms; `intrinsicHeight`\n * is the content's height before explicit or parent sizes. Flex uses\n * the min-content sizes for the automatic minimum size of items.\n *\n * The two min-content sizes leave a scroll container out: scrollable\n * content pushes on nothing outside the scroller, so a box holding a\n * list is as small as the box, not as tall as the list. The intrinsic\n * sizes count it, which is why they are not the minimums.\n */\n minContentWidth = 0;\n minContentHeight = 0;\n maxContentWidth = 0;\n intrinsicWidth = 0;\n intrinsicHeight = 0;\n\n /**\n * What the last flex container this node was an item of decided\n * about it, kept for `LayoutEngine.explain`: which axis was the main\n * axis (0 when the node is not a flex item), the flex base size, and\n * the minimum and maximum the resolution clamped it between —\n * `flexMinAuto` when that minimum was CSS's automatic minimum (the\n * content's min-content size) rather than an explicit one.\n */\n flexMain: 0 | 1 | 2 = 0;\n flexBase = 0;\n flexMin = 0;\n flexMax = Infinity;\n flexMinAuto = false;\n\n /**\n * Positioning. An absolute node is out of flow: it neither takes\n * space in its parent nor is measured with it; the parent positions\n * it against its containing block after the flow is placed. A\n * relative node is in flow and shifted by its offsets afterwards.\n * Both are containing blocks for absolute descendants.\n */\n positioned = false;\n absolute = false;\n top: number | undefined = undefined;\n right: number | undefined = undefined;\n bottom: number | undefined = undefined;\n left: number | undefined = undefined;\n\n zIndex = 0;\n\n /**\n * `lift`: this node and its subtree are painted in a top layer,\n * above the whole tree and outside every ancestor's clip. Hit\n * testing tries the lifted nodes before the tree, for the same\n * reason it walks `paintOrder` in reverse: what is drawn last is\n * pressed first.\n */\n lifted = false;\n\n /**\n * `liftBoundary`: lifted descendants of this node are painted at the\n * end of this node's subtree rather than at the end of the frame.\n */\n liftBoundary = false;\n\n /**\n * Overflow. A clipping node paints and hit-tests its children inside\n * its own box; a scrollable one (a ScrollView, or overflow 'scroll'\n * / 'auto') also translates them by its scroll offset and clamps\n * that offset to its content extent.\n */\n clips = false;\n scrollable = false;\n\n /**\n * A scroll container that reads right to left, so its overlay\n * scrollbar hangs on the left edge and the band that reveals it is\n * on the left too.\n *\n * Kept on the record because `Scrollbars.ts` is handed a record and\n * nothing else: the thumb rectangle a renderer draws and the one the\n * hit tester grabs come from the same function, which is what makes\n * what is seen the thing that is dragged.\n */\n mirrored = false;\n\n /**\n * position: 'sticky'. The offsets are how far the node is shifted from\n * its flow position to stay at its scroll container's edge; they are\n * recomputed whenever anything scrolls and are part of the node's\n * visible position, not its record box.\n */\n sticky = false;\n stickyOffsetX = 0;\n stickyOffsetY = 0;\n\n /** Time (ms) until which this scroll container's scrollbars are shown. */\n scrollbarVisibleUntil = 0;\n\n /**\n * `subgrid: 'columns'`: the parent grid's resolved track widths for\n * the span this node occupies, and the parent's column gap, written\n * by the parent before it measures the node. A subgrid lays itself\n * out against these instead of its own `columns` prop, which is what\n * makes a table row line up with its header.\n */\n subgridColumns: number[] | undefined = undefined;\n subgridColumnGap = 0;\n\n /**\n * Children (fragments expanded) in paint order when any of them has\n * a non-zero zIndex; null means tree order. Hit testing walks it in\n * reverse. Rebuilt whenever the node is placed.\n */\n paintOrder: UiNode[] | null = null;\n\n /**\n * A box around everything in this node's subtree that could take a\n * point, filled in by `LayoutEngine.subtreeBoundsFor` and read by\n * hit testing to pass whole subtrees over. Never smaller than the\n * true hit area, and unbounded where it cannot promise that; see\n * `SubtreeBounds`, which is the read view of these five.\n */\n boundsMinX = 0;\n boundsMinY = 0;\n boundsMaxX = 0;\n boundsMaxY = 0;\n boundsUnbounded = true;\n\n /** Effective scroll offset of a scroll container. */\n scrollX = 0;\n scrollY = 0;\n\n /** Content extent of a scroll container, pre-scroll. */\n contentWidth = 0;\n contentHeight = 0;\n\n /** Constraints this record was last measured under. */\n lastConstraints: Constraints = NEVER_MEASURED;\n\n /**\n * A second memoised measurement. Flex measures every item twice —\n * loose for its max-content size, then tight at its final size — and\n * a one-entry memo would miss on every pass of every later frame. The\n * outputs of the previous constraints are kept here and swapped back\n * in when those constraints come round again, so an unchanged item\n * costs nothing in either pass.\n */\n altValid = false;\n altConstraints: Constraints = NEVER_MEASURED;\n\n /**\n * The alternate measurement's twelve outputs, one field each.\n *\n * These were a `number[]` built by an `outputs()` helper, which reads\n * better and cost two array allocations on every flex item of every\n * pass: a full pass of the benchmark list spent 2.2% of its time in\n * the pair of helpers that packed and unpacked them, before the\n * collector's share of having made the arrays at all. A field per\n * output is the same twelve numbers with nothing built to hold them.\n */\n private altMeasuredWidth = 0;\n private altMeasuredHeight = 0;\n private altOuterWidth = 0;\n private altOuterHeight = 0;\n private altMinContentWidth = 0;\n private altMinContentHeight = 0;\n private altMaxContentWidth = 0;\n private altIntrinsicWidth = 0;\n private altIntrinsicHeight = 0;\n private altHasBaseline = false;\n private altBaseline = 0;\n private altContentWidth = 0;\n private altContentHeight = 0;\n\n /** Keeps the current measurement as the alternate before a fresh one overwrites it. */\n saveAlt(): void {\n this.altValid = true;\n this.altConstraints = this.lastConstraints;\n this.altMeasuredWidth = this.measuredWidth;\n this.altMeasuredHeight = this.measuredHeight;\n this.altOuterWidth = this.outerWidth;\n this.altOuterHeight = this.outerHeight;\n this.altMinContentWidth = this.minContentWidth;\n this.altMinContentHeight = this.minContentHeight;\n this.altMaxContentWidth = this.maxContentWidth;\n this.altIntrinsicWidth = this.intrinsicWidth;\n this.altIntrinsicHeight = this.intrinsicHeight;\n this.altHasBaseline = this.hasBaseline;\n this.altBaseline = this.baseline;\n this.altContentWidth = this.contentWidth;\n this.altContentHeight = this.contentHeight;\n }\n\n /** Makes the alternate measurement current, and the current one alternate. */\n swapAlt(): void {\n const constraints = this.lastConstraints;\n this.lastConstraints = this.altConstraints;\n this.altConstraints = constraints;\n let swap: number = this.measuredWidth;\n this.measuredWidth = this.altMeasuredWidth;\n this.altMeasuredWidth = swap;\n swap = this.measuredHeight;\n this.measuredHeight = this.altMeasuredHeight;\n this.altMeasuredHeight = swap;\n swap = this.outerWidth;\n this.outerWidth = this.altOuterWidth;\n this.altOuterWidth = swap;\n swap = this.outerHeight;\n this.outerHeight = this.altOuterHeight;\n this.altOuterHeight = swap;\n swap = this.minContentWidth;\n this.minContentWidth = this.altMinContentWidth;\n this.altMinContentWidth = swap;\n swap = this.minContentHeight;\n this.minContentHeight = this.altMinContentHeight;\n this.altMinContentHeight = swap;\n swap = this.maxContentWidth;\n this.maxContentWidth = this.altMaxContentWidth;\n this.altMaxContentWidth = swap;\n swap = this.intrinsicWidth;\n this.intrinsicWidth = this.altIntrinsicWidth;\n this.altIntrinsicWidth = swap;\n swap = this.intrinsicHeight;\n this.intrinsicHeight = this.altIntrinsicHeight;\n this.altIntrinsicHeight = swap;\n const hadBaseline = this.hasBaseline;\n this.hasBaseline = this.altHasBaseline;\n this.altHasBaseline = hadBaseline;\n swap = this.baseline;\n this.baseline = this.altBaseline;\n this.altBaseline = swap;\n swap = this.contentWidth;\n this.contentWidth = this.altContentWidth;\n this.altContentWidth = swap;\n swap = this.contentHeight;\n this.contentHeight = this.altContentHeight;\n this.altContentHeight = swap;\n }\n\n /**\n * Set by the parent before measuring this node: something outside it\n * reads a content-derived output beyond its constrained size — its\n * min-content width, intrinsic height or baseline. True until a\n * parent says otherwise, so an unflagged node is never a boundary.\n */\n contentMatters = true;\n\n /**\n * Set by the parent after measuring this node: the parent's layout\n * cannot change when this node's content does, because the sizes the\n * parent read were fixed by constraints or explicit lengths and\n * nothing content-derived was consulted. A change inside such a node\n * is laid out from the node itself (a relayout boundary, as Flutter\n * calls it) instead of from the root.\n */\n relayoutBoundary = false;\n\n measureDirty = true;\n placeDirty = true;\n transformDirty = false;\n\n /**\n * Which layout pass last folded the node's properties onto this\n * record, and the percentage base they were folded against.\n *\n * A pass asks for the same node's properties several times over (the\n * measure walk, then again from whichever container places it), and\n * each ask re-reads about thirty properties and re-resolves every\n * length. `LayoutEngine.resolveLayoutProps` compares these three\n * against the pass it is in and returns early when they agree, which\n * is why the base is recorded and not just the pass number: the\n * engine reassigns the base as it descends, and a node measured\n * before its container's content box was known is genuinely resolved\n * twice against two different bases.\n *\n * Zero is \"never resolved\", and pass numbers start at one, so a fresh\n * record cannot match the pass it is first seen in.\n */\n propsPass = 0;\n propsBaseWidth: number | undefined = undefined;\n propsBaseHeight: number | undefined = undefined;\n\n /**\n * Returns the record to the state a freshly constructed one is in,\n * so a full layout can reuse the object instead of replacing it.\n *\n * `layout()` used to drop every record and let the pass build new\n * ones, which is 5,001 objects of seventy fields for the benchmark\n * list, once per mount and once per resize notification: 71% of\n * everything a full pass allocated, and the largest part of the 10%\n * of it the collector was taking. The engine now keeps the object\n * and calls this instead, which is the same thing without the\n * garbage. Only the node stays, and it is the one field a record is\n * never reused across.\n *\n * **Every field above has to appear here, with the value it is\n * declared with.** A field that is added and not reset would carry\n * one pass's answer into the next, which is the kind of fault that\n * shows as a stale box on a screen and as nothing at all in a test\n * that lays out once. `LayoutRecord.spec.ts` compares a reset record\n * against a new one field by field so the omission fails loudly.\n */\n reset(): void {\n this.x = 0;\n this.y = 0;\n this.width = 0;\n this.height = 0;\n this.measuredWidth = 0;\n this.measuredHeight = 0;\n this.outerWidth = 0;\n this.outerHeight = 0;\n this.paddingLeft = 0;\n this.paddingRight = 0;\n this.paddingTop = 0;\n this.paddingBottom = 0;\n this.marginLeft = 0;\n this.marginRight = 0;\n this.marginTop = 0;\n this.marginBottom = 0;\n this.minWidth = 0;\n this.maxWidth = Infinity;\n this.minHeight = 0;\n this.maxHeight = Infinity;\n this.flexGrow = 0;\n this.flexShrink = 1;\n this.flexBasisZero = false;\n this.minWidthAuto = true;\n this.minHeightAuto = true;\n this.marginLeftAuto = false;\n this.marginRightAuto = false;\n this.marginTopAuto = false;\n this.marginBottomAuto = false;\n this.aspectRatio = undefined;\n this.hasBaseline = false;\n this.baseline = 0;\n this.minContentWidth = 0;\n this.minContentHeight = 0;\n this.maxContentWidth = 0;\n this.intrinsicWidth = 0;\n this.intrinsicHeight = 0;\n this.flexMain = 0;\n this.flexBase = 0;\n this.flexMin = 0;\n this.flexMax = Infinity;\n this.flexMinAuto = false;\n this.positioned = false;\n this.absolute = false;\n this.top = undefined;\n this.right = undefined;\n this.bottom = undefined;\n this.left = undefined;\n this.zIndex = 0;\n this.lifted = false;\n this.liftBoundary = false;\n this.clips = false;\n this.scrollable = false;\n this.mirrored = false;\n this.sticky = false;\n this.stickyOffsetX = 0;\n this.stickyOffsetY = 0;\n this.scrollbarVisibleUntil = 0;\n this.subgridColumns = undefined;\n this.subgridColumnGap = 0;\n this.paintOrder = null;\n this.boundsMinX = 0;\n this.boundsMinY = 0;\n this.boundsMaxX = 0;\n this.boundsMaxY = 0;\n this.boundsUnbounded = true;\n this.scrollX = 0;\n this.scrollY = 0;\n this.contentWidth = 0;\n this.contentHeight = 0;\n this.lastConstraints = NEVER_MEASURED;\n this.altValid = false;\n this.altConstraints = NEVER_MEASURED;\n this.altMeasuredWidth = 0;\n this.altMeasuredHeight = 0;\n this.altOuterWidth = 0;\n this.altOuterHeight = 0;\n this.altMinContentWidth = 0;\n this.altMinContentHeight = 0;\n this.altMaxContentWidth = 0;\n this.altIntrinsicWidth = 0;\n this.altIntrinsicHeight = 0;\n this.altHasBaseline = false;\n this.altBaseline = 0;\n this.altContentWidth = 0;\n this.altContentHeight = 0;\n this.contentMatters = true;\n this.relayoutBoundary = false;\n this.measureDirty = true;\n this.placeDirty = true;\n this.transformDirty = false;\n this.propsPass = 0;\n this.propsBaseWidth = undefined;\n this.propsBaseHeight = undefined;\n }\n}\n","import { UiNodeType } from '../graph/UiNodeType';\nimport type { UiNode } from '../graph/UiNode';\nimport type { LayoutRecord } from './LayoutRecord';\n\n/**\n * A conservative box around everything in a subtree that could take a\n * point, in the coordinate space that subtree's own record lives in.\n *\n * Hit testing descends into every child of a non-clipping node,\n * because a child is free to paint outside its parent; a list of a\n * thousand rows is therefore descended into a thousand times for a\n * point inside exactly one of them. These bounds are what lets the\n * walk pass a subtree over: the point is outside the box, so nothing\n * inside the subtree can hold it.\n *\n * The one rule that matters is that the box is never smaller than the\n * true hit area. Too large costs a descent that finds nothing, which\n * is the behaviour hit testing had before these existed. Too small\n * loses a click, silently, at a position where something is plainly\n * drawn. So anything a bottom-up union cannot honestly summarise is\n * left `boundsUnbounded` instead of approximated, and that flag is\n * carried up to every ancestor whose union included it.\n *\n * This is the read view of five fields that live on `LayoutRecord`\n * itself. They are flat scalars, and not a box object hanging off the\n * record, for the reason every other number on a record is one: they\n * are filled by a walk of the whole tree, and an extra object a node\n * is an extra pointer to chase on a walk that is memory bound before\n * it is anything else.\n */\nexport interface SubtreeBounds {\n readonly boundsMinX: number;\n readonly boundsMinY: number;\n readonly boundsMaxX: number;\n readonly boundsMaxY: number;\n /**\n * True when the box says nothing and the subtree has to be descended\n * into. It starts true so a record nobody has filled in yet, one\n * outside the walked tree above all, is never trusted.\n */\n readonly boundsUnbounded: boolean;\n}\n\n/**\n * Fills in the subtree bounds of every record under `root`, bottom up.\n *\n * The traversal mirrors the hit tester's exactly, `paintOrder` and\n * transparent fragments included, so the set of nodes a box covers is\n * the set of nodes the descent it replaces would have reached.\n */\nexport function fillSubtreeBounds(root: UiNode, records: ReadonlyMap<UiNode, LayoutRecord>): void {\n fillNode(root, records);\n}\n\n/**\n * A node's bounds, and its whole subtree's on the way there. Returns\n * null for a node with no record, a fragment above all, which has\n * nothing of its own to contribute to its parent's box.\n */\nfunction fillNode(node: UiNode, records: ReadonlyMap<UiNode, LayoutRecord>): LayoutRecord | null {\n const rec = records.get(node);\n if (rec === undefined) {\n return null;\n }\n rec.boundsMinX = rec.x;\n rec.boundsMinY = rec.y;\n rec.boundsMaxX = rec.x + rec.width;\n rec.boundsMaxY = rec.y + rec.height;\n rec.boundsUnbounded = isUnbounded(node, rec);\n // A clipping node rejects a point outside its own box before it\n // looks at a single child, so its box is the whole answer and a\n // descendant that reaches past it changes nothing. That is also\n // where an unbounded descendant stops propagating: whatever a\n // transform inside the clip does, the clip still holds.\n //\n // The children are filled in either way, because the descent that\n // does happen inside the clip consults them.\n fillChildren(node, rec.paintOrder, records, rec.clips ? null : rec);\n return rec;\n}\n\nfunction fillChildren(\n parent: UiNode,\n order: UiNode[] | null,\n records: ReadonlyMap<UiNode, LayoutRecord>,\n into: LayoutRecord | null\n): void {\n if (order !== null) {\n for (let i = 0; i < order.length; i++) {\n union(into, fillNode(order[i], records));\n }\n return;\n }\n for (let child = parent.firstChild; child !== null; child = child.nextSibling) {\n if (child.type === UiNodeType.Fragment) {\n // Fragments carry no record of their own, so they have no paint\n // order to read and their children belong to whatever box this\n // walk is filling.\n fillChildren(child, null, records, into);\n } else {\n union(into, fillNode(child, records));\n }\n }\n}\n\nfunction union(into: LayoutRecord | null, child: LayoutRecord | null): void {\n if (into === null || child === null) {\n return;\n }\n if (child.boundsUnbounded) {\n into.boundsUnbounded = true;\n return;\n }\n if (child.boundsMinX < into.boundsMinX) {\n into.boundsMinX = child.boundsMinX;\n }\n if (child.boundsMinY < into.boundsMinY) {\n into.boundsMinY = child.boundsMinY;\n }\n if (child.boundsMaxX > into.boundsMaxX) {\n into.boundsMaxX = child.boundsMaxX;\n }\n if (child.boundsMaxY > into.boundsMaxY) {\n into.boundsMaxY = child.boundsMaxY;\n }\n}\n\n/**\n * Whether a node's own hit area is something its parent's box cannot\n * describe.\n *\n * A transform is the first case. The hit tester inverts the point into\n * a node's local space before it compares anything, so the box a\n * parent would test the point against is in the space the transform\n * moved the node out of: a node translated three hundred pixels up is\n * hit three hundred pixels up and bounded where it is not. Mapping the\n * box forward through the transform is possible, and rotation makes it\n * fiddly enough to be worth doing on its own evidence rather than\n * here; until then a transformed node is simply always descended into.\n *\n * Sticky is the second. A sticky node is drawn, and hit, shifted from\n * its record by an offset `applySticky` writes after placement, and\n * the shift moves the node's whole subtree without moving a single\n * box. The shifted box is knowable here, but it is knowable only\n * because the walk runs after layout has settled, and that is a\n * thinner reason than the rule these bounds are held to. Sticky nodes\n * are few, and every one of them sits inside a scroll container, whose\n * clip stops the flag going any further.\n *\n * Anchored nodes are deliberately not on this list. An anchored\n * overlay is re-placed after the pass that moved its anchor, but every\n * such move writes a box, and a written box invalidates these bounds,\n * so the walk that fills them always runs against the boxes an anchor\n * settled on.\n */\nfunction isUnbounded(node: UiNode, rec: LayoutRecord): boolean {\n if (rec.sticky) {\n return true;\n }\n const transform = node.properties.get('transform');\n return typeof transform === 'object' && transform !== null;\n}\n","import type { LayoutRecord } from './LayoutRecord';\nimport type { UiNode } from '../graph/UiNode';\n\nexport interface Transform {\n x: number;\n y: number;\n}\n\n/**\n * Maps a container's content space into its own outer\n * coordinate space.\n *\n * Content starts at the box origin plus padding, then scroll\n * shifts it, so the mapping is a pure translation. Descendant\n * layout boxes never change when scroll does.\n */\nexport function contentOffset(record: LayoutRecord): Transform {\n return {\n x: record.paddingLeft - record.scrollX,\n y: record.paddingTop - record.scrollY\n };\n}\n\n/**\n * Reads the world position of a node in layout coordinates.\n *\n * LayoutRecords store x/y already in absolute layout-root\n * space: placers compute child positions as\n * `parent.x + parent.padding + offset`, so every box is\n * expressed relative to the layout root with no chain walk\n * required. Scroll translation is intentionally excluded —\n * it is applied separately per scroll container via\n * contentOffset.\n *\n * Writes into out (a mutable x/y holder) to avoid allocation in\n * hot paths.\n */\nexport function accumulatedOffsetTo(\n node: UiNode,\n records: ReadonlyMap<UiNode, LayoutRecord>,\n out: { x: number; y: number }\n): void {\n const record = records.get(node);\n if (record === undefined) {\n out.x = 0;\n out.y = 0;\n return;\n }\n out.x = record.x;\n out.y = record.y;\n}\n","import type { UiNode } from '../graph/UiNode';\nimport type { Constraints, LayoutBox, Size } from './LayoutTypes';\nimport { isAutoLength, isPercentLength } from './UiLength';\n\n/**\n * Why a node has the size it has. Produced by `LayoutEngine.explain`.\n *\n * Everything here is read from the layout record and the node's\n * properties after the fact; nothing is computed that layout did not\n * already compute. The per-axis `reasons` are sentences a developer\n * can read in order, and `decidedBy` is the one rule that fixed the\n * measured size, so a tool can colour or group by it.\n */\nexport interface LayoutExplanation {\n readonly node: UiNode;\n /** False when the node has never been laid out; the axes are then empty. */\n readonly laidOut: boolean;\n /** Why there is no record, when `laidOut` is false. */\n readonly notLaidOutReason?: string;\n /** The node whose measure handed this node its constraints; null for the layout root. */\n readonly parent: UiNode | null;\n /** Border box in layout-root coordinates, before scrolling. */\n readonly box: LayoutBox;\n /** What the content asked for on each axis, before any clamp. */\n readonly content: Size;\n /** The size the node reported to its parent. */\n readonly measured: Size;\n /** Constraints the parent handed down on the last measurement. */\n readonly constraints: Constraints;\n /** Those constraints after the node's own width/height/min/max. */\n readonly effective: Constraints;\n readonly padding: Edges;\n readonly margin: Edges;\n readonly width: AxisExplanation;\n readonly height: AxisExplanation;\n readonly relayout: RelayoutExplanation;\n readonly state: LayoutStateExplanation;\n /** Scroll facts, for a scroll container or a field that scrolls its text. */\n readonly scroll?: { scrollX: number; scrollY: number; contentWidth: number; contentHeight: number };\n /**\n * For each property a modifier is writing, who is writing it and what\n * the element declared. Undefined when no modifier writes anything.\n *\n * L8 made layout explain itself and B1 then let a modifier change the\n * numbers it explains, which without this makes the explanation lie\n * by omission: `width 240 (explicit)` is true of the node and says\n * nothing about the element saying 200. Every property is listed,\n * not only the two the axes are about, because \"why is it that\n * colour\" has the same answer and no other tool gives it.\n */\n readonly sources?: OverrideSources;\n /**\n * The application's own layout, when this node carries one: what it\n * is called and what it says about the arrangement.\n *\n * A custom layout is the one container whose reasoning the engine\n * cannot describe, because the engine did not do it. `explain` would\n * otherwise say \"content 640 × 420\" and stop, which is true and\n * useless. The protocol's `explain` fills the gap, and this is\n * where what it said is carried; `formatExplanation` prints the\n * sentences under the two axes.\n */\n readonly custom?: CustomLayoutExplanation;\n}\n\nexport interface CustomLayoutExplanation {\n /** `UiLayoutProtocol.name`. */\n readonly name: string;\n /** How many in-flow children it arranged. */\n readonly children: number;\n /**\n * The sentences the protocol's own `explain` returned, or a single\n * line saying it has none.\n */\n readonly notes: readonly string[];\n}\n\n/** Property name to a sentence naming the modifiers that write it. */\nexport type OverrideSources = Readonly<Record<string, string>>;\n\nexport interface Edges {\n readonly top: number;\n readonly right: number;\n readonly bottom: number;\n readonly left: number;\n}\n\n/**\n * The single rule that fixed a node's measured size on one axis.\n *\n * - `viewport`: the layout root filling bounded constraints\n * - `explicit`: the node's own `width`/`height`\n * - `flex`: flexed by a Row or Column (grew, shrank, or held at a clamp)\n * - `stretch`: stretched across a container's cross axis or a grid area\n * - `inset`: an absolute node with both edges set\n * - `parent`: a tight size from the parent for another reason\n * - `content`: what the content needed\n * - `min` / `max`: content, then raised or capped by a minimum or maximum\n * - `aspect-ratio`: derived from the other axis\n */\nexport type SizeDecision =\n | 'viewport'\n | 'explicit'\n | 'flex'\n | 'stretch'\n | 'inset'\n | 'parent'\n | 'content'\n | 'min'\n | 'max'\n | 'aspect-ratio'\n /** Sized and placed by a layout the application wrote; see `custom`. */\n | 'custom';\n\nexport interface AxisExplanation {\n readonly axis: 'width' | 'height';\n readonly content: number;\n readonly measured: number;\n /** The final box size; differs from `measured` only when placement overrode it. */\n readonly final: number;\n readonly decidedBy: SizeDecision;\n /** Sentences, in the order the rules applied. */\n readonly reasons: readonly string[];\n}\n\nexport interface RelayoutExplanation {\n /** A change inside this node cannot change its parent's layout. */\n readonly boundary: boolean;\n /** Something outside reads a content-derived size of this node. */\n readonly contentMatters: boolean;\n /**\n * Where a change to this node's layout properties is laid out from:\n * the nearest ancestor that is a relayout boundary, else the layout\n * root. The node itself only when it is the layout root.\n */\n readonly root: UiNode;\n readonly rootIsLayoutRoot: boolean;\n /** How many ancestors the dirty walk climbs to reach `root`. */\n readonly depth: number;\n}\n\nexport interface LayoutStateExplanation {\n readonly measureDirty: boolean;\n readonly placeDirty: boolean;\n /** Whether the last layout pass measured this node; undefined when the engine is not tracing. */\n readonly measuredLastPass: boolean | undefined;\n readonly position: 'static' | 'relative' | 'absolute' | 'sticky';\n readonly clips: boolean;\n}\n\n/**\n * How one axis was sized, gathered by the engine from the record, the\n * node's properties and the parent's type. `buildAxisExplanation`\n * turns these into sentences.\n */\nexport interface AxisFacts {\n readonly axis: 'width' | 'height';\n readonly isRoot: boolean;\n readonly parentLabel: string;\n /** Constraints the parent handed down. */\n readonly parentMin: number;\n readonly parentMax: number;\n /** Constraints after the node's own size properties. */\n readonly effectiveMin: number;\n readonly effectiveMax: number;\n /** The node's own `width`/`height`, resolved, and as written. */\n readonly explicit: number | undefined;\n readonly explicitRaw: unknown;\n /** The node's own minimum/maximum, resolved; undefined when unset. */\n readonly ownMin: number | undefined;\n readonly ownMax: number | undefined;\n readonly content: number;\n readonly measured: number;\n readonly final: number;\n /** The content's minimum on this axis (min-content width, intrinsic height). */\n readonly contentMin: number;\n readonly padding: number;\n readonly aspectRatio: number | undefined;\n /** Set when a Row/Column flexed the node along this axis. */\n readonly flex?: FlexFacts;\n /** The parent made the axis tight to stretch the node across it. */\n readonly stretched: boolean;\n /** An absolute node with both edges set along this axis. */\n readonly inset: boolean;\n /** A grid item filling its area along this axis. */\n readonly gridArea: boolean;\n /** The parent carries a custom layout, which sized and placed this node. */\n readonly customParent: string | undefined;\n /** Content that clips (a scroll container, ellipsised or clamped text) has no automatic minimum. */\n readonly clipsContent: boolean;\n readonly isText: boolean;\n readonly childCount: number;\n}\n\nexport interface FlexFacts {\n readonly base: number;\n readonly min: number;\n readonly max: number;\n readonly minAuto: boolean;\n readonly grow: number;\n readonly shrink: number;\n readonly basis: number | undefined;\n readonly containerLabel: string;\n /** A ScrollView lays its children out as a column/row but never flexes them. */\n readonly scroller: boolean;\n}\n\nconst EPSILON = 1e-6;\n\n/**\n * Turns the facts about one axis into the rule that decided it and the\n * sentences that say so.\n */\nexport function buildAxisExplanation(f: AxisFacts): AxisExplanation {\n const reasons: string[] = [];\n let decidedBy: SizeDecision = 'content';\n const px = (value: number): string => formatNumber(value);\n const minProp = f.axis === 'width' ? 'minWidth' : 'minHeight';\n const maxProp = f.axis === 'width' ? 'maxWidth' : 'maxHeight';\n const parentTight = f.parentMin === f.parentMax && isFinite(f.parentMax);\n\n if (f.customParent !== undefined && !f.isRoot) {\n // A custom layout measured this node itself, so none of the rules\n // below apply: whatever constraints it was measured under were the\n // protocol's choice, and its box is where the protocol put it.\n decidedBy = 'custom';\n reasons.push(`the '${f.customParent}' layout on ${f.parentLabel} measured it at ${px(f.measured)}`);\n if (Math.abs(f.final - f.measured) > EPSILON) {\n reasons.push(`and placed it at ${px(f.final)}`);\n }\n return { axis: f.axis, content: f.content, measured: f.measured, final: f.final, decidedBy, reasons };\n }\n\n if (f.isRoot) {\n if (f.explicit !== undefined) {\n decidedBy = 'explicit';\n reasons.push(`${f.axis}: ${describeLength(f.explicitRaw)} (explicit) → ${px(f.explicit)}`);\n } else if (isFinite(f.parentMax)) {\n decidedBy = 'viewport';\n reasons.push(`the layout root fills its viewport: ${px(f.parentMax)}`);\n } else {\n reasons.push(`the layout root is unbounded here and takes its content ${f.axis}: ${px(f.content)}`);\n }\n } else if (parentTight) {\n if (f.flex !== undefined && !f.flex.scroller) {\n decidedBy = flexReasons(f, f.flex, reasons);\n } else if (f.inset) {\n decidedBy = 'inset';\n const edges = f.axis === 'width' ? 'left and right' : 'top and bottom';\n reasons.push(`both ${edges} are set, so the containing block decides the ${f.axis}: ${px(f.parentMin)}`);\n } else if (f.gridArea) {\n decidedBy = 'stretch';\n reasons.push(`stretched across its grid area: ${px(f.parentMin)}`);\n } else if (f.stretched) {\n decidedBy = 'stretch';\n reasons.push(`stretched across ${f.parentLabel}: ${px(f.parentMin)}`);\n } else {\n decidedBy = 'parent';\n reasons.push(`${f.parentLabel} fixed the ${f.axis} at ${px(f.parentMin)}`);\n }\n if (f.effectiveMin !== f.parentMin) {\n const clamp = f.effectiveMin > f.parentMin ? minProp : maxProp;\n const to = f.effectiveMin > f.parentMin ? f.ownMin : f.ownMax;\n reasons.push(`clamped by its own ${clamp} ${px(to ?? f.effectiveMin)} → ${px(f.effectiveMin)}`);\n }\n if (f.content > f.effectiveMin + EPSILON) {\n reasons.push(\n `its content would need ${px(f.content)}; the extra ${px(f.content - f.effectiveMin)} ${\n f.clipsContent ? 'is clipped' : 'overflows'\n }`\n );\n }\n } else if (f.explicit !== undefined) {\n decidedBy = 'explicit';\n reasons.push(`${f.axis}: ${describeLength(f.explicitRaw)} (explicit) → ${px(f.explicit)}`);\n if (f.flex !== undefined && !f.flex.scroller) {\n reasons.push(unflexedReason(f.flex));\n }\n if (f.effectiveMin !== f.explicit) {\n const clamp = f.effectiveMin > f.explicit ? minProp : maxProp;\n const to = f.effectiveMin > f.explicit ? f.ownMin : f.ownMax;\n reasons.push(`clamped by ${clamp} ${px(to ?? f.effectiveMin)} → ${px(f.effectiveMin)}`);\n }\n if (isFinite(f.parentMax) && f.effectiveMin > f.parentMax + EPSILON) {\n reasons.push(`wider than the ${px(f.parentMax)} available: it overflows ${f.parentLabel}`);\n }\n } else {\n reasons.push(contentReason(f));\n if (f.flex !== undefined && !f.flex.scroller) {\n reasons.push(unflexedReason(f.flex));\n }\n if (f.aspectRatio !== undefined && Math.abs(f.content - f.measured) > EPSILON) {\n decidedBy = 'aspect-ratio';\n reasons.push(`aspectRatio ${formatNumber(f.aspectRatio)} derives it from the other axis → ${px(f.measured)}`);\n }\n if (f.content < f.effectiveMin - EPSILON) {\n if (f.ownMin !== undefined && f.ownMin >= f.effectiveMin - EPSILON) {\n decidedBy = 'min';\n reasons.push(`raised to ${minProp} ${px(f.ownMin)}`);\n } else {\n decidedBy = 'min';\n reasons.push(`raised to the minimum ${f.parentLabel} asked for: ${px(f.parentMin)}`);\n }\n } else if (f.ownMax !== undefined && f.content > f.ownMax + EPSILON && f.measured <= f.ownMax + EPSILON) {\n decidedBy = 'max';\n reasons.push(`capped by ${maxProp} ${px(f.ownMax)}`);\n }\n if (isFinite(f.parentMax) && f.measured > f.parentMax + EPSILON) {\n reasons.push(\n `the ${px(f.parentMax)} available was only a bound, not a size: the extra ${px(f.measured - f.parentMax)} ${\n f.clipsContent ? 'is clipped' : 'overflows'\n } ${f.parentLabel}`\n );\n }\n }\n\n if (Math.abs(f.final - f.measured) > EPSILON) {\n reasons.push(`placed at ${px(f.final)} by ${f.parentLabel} (measured ${px(f.measured)})`);\n }\n\n return {\n axis: f.axis,\n content: f.content,\n measured: f.measured,\n final: f.final,\n decidedBy,\n reasons\n };\n}\n\n/**\n * A flex item whose main axis the container made tight. Appends the\n * sentences and returns the rule: `flex` when the item grew or shrank,\n * otherwise whatever gave it the base size it kept.\n */\nfunction flexReasons(f: AxisFacts, flex: FlexFacts, reasons: string[]): SizeDecision {\n const px = formatNumber;\n const final = f.parentMin;\n const grew = final > flex.base + EPSILON;\n const shrank = final < flex.base - EPSILON;\n if (!grew && !shrank) {\n if (f.explicit !== undefined) {\n reasons.push(`${f.axis}: ${describeLength(f.explicitRaw)} (explicit) → ${px(f.explicit)}`);\n reasons.push(unflexedReason(flex));\n return 'explicit';\n }\n if (flex.basis !== undefined) {\n reasons.push(`flexBasis ${px(flex.basis)} → ${px(flex.base)}`);\n reasons.push(unflexedReason(flex));\n return 'flex';\n }\n reasons.push(`its max-content ${f.axis} is ${px(flex.base)}`);\n reasons.push(unflexedReason(flex));\n return 'content';\n }\n const baseSource =\n f.explicit !== undefined\n ? `${f.axis}: ${describeLength(f.explicitRaw)}`\n : flex.basis !== undefined\n ? `flexBasis ${px(flex.basis)}`\n : `its max-content ${f.axis}`;\n reasons.push(`flex item of ${flex.containerLabel}: base ${px(flex.base)} from ${baseSource}`);\n if (grew) {\n reasons.push(`grew to ${px(final)} (flexGrow ${px(flex.grow)} takes a share of the free space)`);\n if (Math.abs(final - flex.max) < EPSILON && isFinite(flex.max)) {\n reasons.push(`stopped at ${f.axis === 'width' ? 'maxWidth' : 'maxHeight'} ${px(flex.max)}`);\n }\n } else {\n reasons.push(\n `shrank to ${px(final)} (flexShrink ${px(flex.shrink)}: the items' base sizes exceed the content box of ${\n flex.containerLabel\n }, so they give up space)`\n );\n if (Math.abs(final - flex.min) < EPSILON) {\n reasons.push(minimumReason(f, flex));\n }\n }\n return 'flex';\n}\n\n/** A flex item whose main axis stayed loose: the container never resized it. */\nfunction unflexedReason(flex: FlexFacts): string {\n const note = flex.grow === 0 ? ' (flexGrow 0, so free space goes to others)' : ' (no free space to take)';\n return `flex item of ${flex.containerLabel}: kept its base ${formatNumber(flex.base)}${note}`;\n}\n\n/**\n * Why a shrinking item stopped where it did (CSS `min-width: auto`).\n */\nfunction minimumReason(f: AxisFacts, flex: FlexFacts): string {\n const px = formatNumber;\n const minProp = f.axis === 'width' ? 'minWidth' : 'minHeight';\n if (!flex.minAuto) {\n return `stopped at ${minProp} ${px(flex.min)}`;\n }\n if (flex.min === 0 && f.clipsContent) {\n return `its automatic minimum is 0: a scroll container or clipped text has none, so it may shrink to nothing`;\n }\n if (flex.min === 0 && f.contentMin === 0) {\n return `its automatic minimum is 0: the content has no minimum ${f.axis}`;\n }\n if (f.explicit !== undefined && Math.abs(flex.min - f.explicit) < EPSILON) {\n return `stopped at its automatic minimum ${px(flex.min)}, its explicit ${f.axis} (set ${minProp}: 0 to allow smaller)`;\n }\n return `stopped at its automatic minimum ${px(flex.min)} (the content's min-content ${f.axis}; set ${minProp}: 0 to allow smaller)`;\n}\n\nfunction contentReason(f: AxisFacts): string {\n const px = formatNumber;\n const inner = Math.max(0, f.content - f.padding);\n const paddingNote = f.padding > 0 ? ` + padding ${px(f.padding)}` : '';\n if (f.isText) {\n return `text needs ${px(inner)}${paddingNote} → ${px(f.content)}`;\n }\n if (f.childCount === 0) {\n return f.content === 0 ? `no content and no ${f.axis}: 0` : `no children${paddingNote} → ${px(f.content)}`;\n }\n return `${f.childCount} child${f.childCount === 1 ? '' : 'ren'} need ${px(inner)}${paddingNote} → ${px(f.content)}`;\n}\n\n/** A length as written: a number, `50%`, `auto`, or its JSON. */\nexport function describeLength(raw: unknown): string {\n if (typeof raw === 'number') {\n return formatNumber(raw);\n }\n if (isPercentLength(raw)) {\n return `${formatNumber(raw.value)}%`;\n }\n if (isAutoLength(raw)) {\n return 'auto';\n }\n if (raw === undefined) {\n return 'unset';\n }\n return JSON.stringify(raw);\n}\n\nexport function formatNumber(value: number): string {\n if (!isFinite(value)) {\n return value > 0 ? '∞' : '-∞';\n }\n const rounded = Math.round(value * 100) / 100;\n return String(rounded);\n}\n\nexport function formatConstraints(constraints: Constraints): string {\n return `width ${formatRange(constraints.minWidth, constraints.maxWidth)} · height ${formatRange(\n constraints.minHeight,\n constraints.maxHeight\n )}`;\n}\n\nfunction formatRange(min: number, max: number): string {\n if (min === max) {\n return `${formatNumber(min)} (tight)`;\n }\n return `[${formatNumber(min)}, ${formatNumber(max)}${isFinite(max) ? ']' : ')'}`;\n}\n\nfunction formatEdges(edges: Edges): string {\n if (edges.top === edges.right && edges.right === edges.bottom && edges.bottom === edges.left) {\n return formatNumber(edges.top);\n }\n return [edges.top, edges.right, edges.bottom, edges.left].map(formatNumber).join(' ');\n}\n\n/** A node named the way the explanation names every node: type and id. */\n/**\n * Who is writing over what the element declared, per property.\n *\n * Reads `node.overrides`, which the cascade already keeps: every entry\n * carries the name of the modifier kind that wrote it, in the order\n * the element listed them, and the last one is the value in force.\n * Nothing is computed that the write did not already record.\n */\nexport function describeOverrides(node: UiNode): OverrideSources | undefined {\n if (node.overrides === null || node.overrides.size === 0) {\n return undefined;\n }\n const out: Record<string, string> = {};\n for (const [property, overrides] of node.overrides) {\n if (overrides.entries.length === 0) {\n continue;\n }\n const names = overrides.entries.map(entry => entry.name);\n // The last one wins, so it is named last, and the rest are named as\n // what it won against: \"set by hoverable, then draggable\" reads in\n // the order the element listed them.\n const who = names.length === 1 ? `set by ${names[0]}` : `set by ${names.join(', then ')}`;\n // `describeLength` prints a length in every form the engine has and\n // JSON-quotes anything that is not one, so it serves a colour or a\n // set of visual states as well as it serves a width.\n const declared = overrides.declared.present\n ? `declared ${describeLength(overrides.declared.value)}`\n : 'the element declared none';\n out[property] = `${who} (${declared})`;\n }\n return Object.keys(out).length === 0 ? undefined : out;\n}\n\n/** The axis explanation with its override source as a last reason. */\nexport function withOverrideSource(axis: AxisExplanation, source: string | undefined): AxisExplanation {\n return source === undefined ? axis : { ...axis, reasons: [...axis.reasons, source] };\n}\n\nexport function labelNode(node: UiNode): string {\n return `${node.type} '${node.id}'`;\n}\n\n/**\n * The explanation as text, one fact per line, for a console, a test\n * failure message or the playground's inspector panel.\n */\nexport function formatExplanation(explanation: LayoutExplanation): string {\n const { node } = explanation;\n if (!explanation.laidOut) {\n return `${labelNode(node)} has no layout: ${explanation.notLaidOutReason ?? 'it has not been measured'}.`;\n }\n const { box, width, height, relayout, state } = explanation;\n const lines: string[] = [];\n lines.push(\n `${labelNode(node)} · ${formatNumber(box.width)} × ${formatNumber(box.height)} at (${formatNumber(\n box.x\n )}, ${formatNumber(box.y)})`\n );\n lines.push(`width ${formatNumber(width.final).padEnd(7)} ${width.reasons.join('; ')}`);\n lines.push(`height ${formatNumber(height.final).padEnd(7)} ${height.reasons.join('; ')}`);\n if (explanation.custom !== undefined) {\n const custom = explanation.custom;\n lines.push(\n `layout '${custom.name}' over ${custom.children} ${custom.children === 1 ? 'child' : 'children'}` +\n custom.notes.map(note => `\\n ${note}`).join('')\n );\n }\n const from = explanation.parent === null ? 'the viewport' : labelNode(explanation.parent);\n lines.push(`constraints from ${from}: ${formatConstraints(explanation.constraints)}`);\n if (\n explanation.effective.minWidth !== explanation.constraints.minWidth ||\n explanation.effective.maxWidth !== explanation.constraints.maxWidth ||\n explanation.effective.minHeight !== explanation.constraints.minHeight ||\n explanation.effective.maxHeight !== explanation.constraints.maxHeight\n ) {\n lines.push(`after own size props: ${formatConstraints(explanation.effective)}`);\n }\n const contentWidth = Math.max(0, box.width - explanation.padding.left - explanation.padding.right);\n const contentHeight = Math.max(0, box.height - explanation.padding.top - explanation.padding.bottom);\n lines.push(\n `padding ${formatEdges(explanation.padding)} · margin ${formatEdges(explanation.margin)} · content box ${formatNumber(\n contentWidth\n )} × ${formatNumber(contentHeight)}`\n );\n if (explanation.scroll !== undefined) {\n const s = explanation.scroll;\n lines.push(\n `scroll (${formatNumber(s.scrollX)}, ${formatNumber(s.scrollY)}) of content ${formatNumber(\n s.contentWidth\n )} × ${formatNumber(s.contentHeight)}`\n );\n }\n const rootLabel =\n relayout.root === node\n ? 'itself (it is the layout root)'\n : `${relayout.rootIsLayoutRoot ? 'the layout root ' : ''}${labelNode(relayout.root)} (${\n relayout.depth\n } level${relayout.depth === 1 ? '' : 's'} up)`;\n lines.push(\n `relayout: ${relayout.boundary ? 'boundary' : 'not a boundary'} · content ${\n relayout.contentMatters ? 'matters to the parent' : 'stays inside'\n } · a change here is laid out from ${rootLabel}`\n );\n // The two axes already carry theirs, on the line that explains the\n // number they changed.\n const others = Object.entries(explanation.sources ?? {}).filter(\n ([property]) => property !== 'width' && property !== 'height'\n );\n if (others.length > 0) {\n lines.push(`overrides: ${others.map(([property, source]) => `${property} ${source}`).join(' · ')}`);\n }\n const measuredNote =\n state.measuredLastPass === undefined\n ? ''\n : state.measuredLastPass\n ? ' · measured in the last pass'\n : ' · not measured in the last pass';\n lines.push(\n `state: ${state.measureDirty ? 'measure dirty' : 'measured'} · ${\n state.placeDirty ? 'place dirty' : 'placed'\n } · position ${state.position}${state.clips ? ' · clips' : ''}${measuredNote}`\n );\n return lines.join('\\n');\n}\n","import { DirtyFlags } from '../graph/DirtyFlags';\nimport type { UiNode } from '../graph/UiNode';\nimport { UiNodeType } from '../graph/UiNodeType';\nimport { resolveFont } from '../properties/UiTextFont';\nimport { editableSpansOf, resolvedSpansOf, textContentOf } from '../properties/UiTextStyle';\nimport { CARET_WIDTH, editorFor } from '../editing/UiEditable';\nimport type { UiFrame } from '../scheduler/UiFrame';\nimport {\n AlignContent,\n CrossAxisAlignment,\n MainAxisAlignment,\n parseAlignContent,\n parseCrossAxisAlignment,\n parseMainAxisAlignment\n} from './Alignment';\nimport { resolveString } from '../properties/UiPropertyResolver';\nimport { resolveLength } from './UiLength';\nimport type { UiTrackSize } from './UiLength';\nimport { placeGridItems, sizeGridTracks } from './GridLayout';\nimport type { GridContribution, GridItemRequest, GridPlacement, GridTrackSizingResult } from './GridLayout';\nimport { FlexDirection, parseFlexDirection } from './FlexDirection';\nimport { MAX_MEASURES_PER_CHILD, isLayoutProtocol } from './CustomLayout';\nimport type { UiLayoutChild, UiLayoutContext, UiLayoutProtocol } from './CustomLayout';\nimport { LayoutRecord } from './LayoutRecord';\nimport { fillSubtreeBounds } from './SubtreeBounds';\nimport type { SubtreeBounds } from './SubtreeBounds';\nimport { CharacterCountTextMeasurer } from './TextMeasurer';\nimport type { TextMeasurer, TextOverflow, TextWrap } from './TextMeasurer';\nimport { accumulatedOffsetTo } from './LayoutTransform';\nimport { Constraints, constraintsEqual } from './LayoutTypes';\nimport type { LayoutBox, LayoutResult, LayoutStats, Size } from './LayoutTypes';\nimport { buildAxisExplanation, describeOverrides, labelNode, withOverrideSource } from './LayoutExplanation';\nimport type { AxisFacts, CustomLayoutExplanation, FlexFacts, LayoutExplanation } from './LayoutExplanation';\n\n/** How long overlay scrollbars stay after the last scroll change. */\nexport const SCROLLBAR_LINGER_MS = 1200;\n/** Portion of the linger during which the scrollbar fades out. */\nexport const SCROLLBAR_FADE_MS = 350;\n/**\n * How many times a pass re-places anchored nodes that moved because\n * something they are anchored to moved. One pass settles an overlay on\n * a box; a further pass settles an overlay anchored to that overlay.\n * The limit is what stops a cycle of anchors from spinning.\n */\nconst ANCHOR_CHAIN_LIMIT = 4;\n\n/** An editable's text is the user's; runs are a property of a `Text` node. */\n\nexport interface ScrollAdjustment {\n container: UiNode;\n scrollX: number;\n scrollY: number;\n}\n\n/**\n * Whether a node names any of the four logical horizontal insets, and\n * so needs its writing direction resolved before its box is worked\n * out.\n *\n * Four misses on a Map, on every measured node. The alternative is\n * resolving `textDirection` for every node whether or not anything\n * asked, which walks the environment chain and is what this exists to\n * avoid; the check is the same shape and price as the one `paddingX`\n * added to each side.\n */\nfunction hasLogicalSpacing(props: ReadonlyMap<string, unknown>): boolean {\n return props.has('paddingStart') || props.has('paddingEnd') || props.has('marginStart') || props.has('marginEnd');\n}\n\n/** Where a run puts a child, when the run is the placing one. */\ninterface CustomPlacement {\n /** The content box's origin, in layout-root coordinates. */\n readonly x: number;\n readonly y: number;\n /** Its width, for mirroring a start coordinate. */\n readonly width: number;\n readonly mirrored: boolean;\n}\n\n/**\n * One call into a protocol's `layout`, and the fence around it.\n *\n * See `measureCustom` for what the fence is for. The two callbacks are\n * the only way out of it: one measures a child through the engine's\n * own `measure`, so a memo hit still counts as a memo hit, and one\n * assigns a box through `assignBox`, so a moved child invalidates\n * everything a moved child normally invalidates.\n */\nclass CustomLayoutRun {\n private readonly handles: CustomChildHandle[] = [];\n private readonly nodes: UiNode[] = [];\n private live = false;\n /** The widest any child measured, for the container's min-content width. */\n widestChild = 0;\n\n constructor(\n private readonly protocol: UiLayoutProtocol,\n private readonly constraints: Constraints,\n private readonly placement: CustomPlacement | null,\n private readonly context: UiLayoutContext,\n private readonly measureChild: (child: UiNode, constraints: Constraints) => Size,\n private readonly assign: (child: UiNode, x: number, y: number, size: Size) => void\n ) {}\n\n add(child: UiNode, data: unknown): void {\n this.nodes.push(child);\n this.handles.push(new CustomChildHandle(this.handles.length, data, this));\n }\n\n execute(): Size {\n this.live = true;\n let size: Size;\n try {\n size = this.protocol.layout(this.handles, this.constraints, this.context);\n } finally {\n this.live = false;\n }\n // Whatever the protocol left alone still has to be measured and\n // still has to have a box, or it would paint at wherever it was\n // last frame with whatever size it had then.\n for (let index = 0; index < this.handles.length; index++) {\n const handle = this.handles[index];\n if (handle.measures === 0) {\n this.live = true;\n try {\n // Loosened: a tight content box is the container's size, and\n // forcing a child the protocol never looked at to fill it\n // would be an arrangement rather than a fallback.\n handle.measure(new Constraints(0, this.constraints.maxWidth, 0, this.constraints.maxHeight));\n } finally {\n this.live = false;\n }\n }\n if (this.placement !== null && handle.position === null) {\n this.put(handle, 0, 0);\n }\n }\n if (!Number.isFinite(size.width) || !Number.isFinite(size.height)) {\n throw new Error(`The '${this.protocol.name}' layout returned ${size.width} × ${size.height}.`);\n }\n return { width: Math.max(0, size.width), height: Math.max(0, size.height) };\n }\n\n /** Called by a handle; see `UiLayoutChild.measure`. */\n runMeasure(handle: CustomChildHandle, constraints: Constraints): Size {\n this.assertLive('measure');\n if (handle.measures >= MAX_MEASURES_PER_CHILD) {\n throw new Error(\n `The '${this.protocol.name}' layout measured child ${handle.index} more than ${MAX_MEASURES_PER_CHILD} times ` +\n 'in one pass. Measuring a child inside a loop over the others is what makes a layout quadratic; ' +\n 'measure each child once, then arrange them from the sizes you have.'\n );\n }\n handle.measures++;\n const size = this.measureChild(this.nodes[handle.index], constraints);\n this.widestChild = Math.max(this.widestChild, size.width);\n return size;\n }\n\n /** Called by a handle; see `UiLayoutChild.place`. */\n runPlace(handle: CustomChildHandle, start: number, top: number): void {\n this.assertLive('place');\n if (!Number.isFinite(start) || !Number.isFinite(top)) {\n throw new Error(`The '${this.protocol.name}' layout placed child ${handle.index} at (${start}, ${top}).`);\n }\n if (this.placement !== null) {\n this.put(handle, start, top);\n } else {\n // The measuring run: remember it for `explain`, but assign\n // nothing. Every box is written by the placing run, which is the\n // one that knows where the container ended up.\n handle.position = { start, top };\n }\n }\n\n private put(handle: CustomChildHandle, start: number, top: number): void {\n const at = this.placement!;\n handle.position = { start, top };\n const x = at.mirrored ? at.x + at.width - start - handle.size.width : at.x + start;\n this.assign(this.nodes[handle.index], x, at.y + top, handle.size);\n }\n\n private assertLive(what: string): void {\n if (!this.live) {\n throw new Error(\n `The '${this.protocol.name}' layout tried to ${what} a child outside its own layout call. ` +\n 'A child handle is valid only for the call it was given to.'\n );\n }\n }\n}\n\n/** A `UiLayoutChild`, and the only object a protocol is handed. */\nclass CustomChildHandle implements UiLayoutChild {\n size: Size = { width: 0, height: 0 };\n position: { start: number; top: number } | null = null;\n measures = 0;\n\n constructor(\n readonly index: number,\n readonly data: unknown,\n private readonly run: CustomLayoutRun\n ) {}\n\n measure(constraints: Constraints): Size {\n this.size = this.run.runMeasure(this, constraints);\n return this.size;\n }\n\n place(start: number, top: number): void {\n this.run.runPlace(this, start, top);\n }\n}\n\n/**\n * Swaps start for end, for an axis that runs the other way.\n *\n * `center` and `stretch` are symmetric and stay put; `baseline` is\n * only ever a vertical alignment and never reaches a mirrored axis.\n */\nfunction mirrorAlignment(align: CrossAxisAlignment): CrossAxisAlignment {\n if (align === CrossAxisAlignment.Start) {\n return CrossAxisAlignment.End;\n }\n if (align === CrossAxisAlignment.End) {\n return CrossAxisAlignment.Start;\n }\n return align;\n}\n\ninterface FlexItem {\n child: UiNode;\n rec: LayoutRecord;\n /** Flex base size: max-content along the main axis, or flexBasis. */\n baseMain: number;\n /**\n * What the item's own content asks for along the main axis, which is\n * the base size again unless `flexBasis` replaced it. Kept apart from\n * `baseMain` because a container shrink-wrapping around an item that\n * starts flexing from zero has to wrap around the content, not\n * around the zero.\n */\n maxContentMain: number;\n /** Base size clamped to the item's min/max. */\n hypotheticalMain: number;\n finalMain: number;\n /** Cross size after the second measurement pass, margins excluded. */\n cross: number;\n /** Margins; auto ones start at 0 and grow when free space is shared out. */\n marginMainStart: number;\n marginMainEnd: number;\n marginCrossStart: number;\n marginCrossEnd: number;\n marginMainStartAuto: boolean;\n marginMainEndAuto: boolean;\n marginCrossStartAuto: boolean;\n marginCrossEndAuto: boolean;\n minMain: number;\n maxMain: number;\n grow: number;\n shrink: number;\n /**\n * Both of the item's first-pass sizes came from lengths or tight\n * constraints, not from content — a candidate relayout boundary.\n */\n sizeFree: boolean;\n align: CrossAxisAlignment;\n /** Resolution state (CSS Flexbox §9.7). */\n frozen: boolean;\n violation: number;\n}\n\ninterface FlexLine {\n items: FlexItem[];\n cross: number;\n crossStart: number;\n /** Main-axis space left after flexing and auto margins. */\n free?: number;\n /** Cross-axis spacing from alignContent. */\n leading?: number;\n between?: number;\n}\n\ninterface FlexConfig {\n row: boolean;\n isScroll: boolean;\n gapMain: number;\n gapLine: number;\n wrap: boolean;\n wrapReverse: boolean;\n mainReversed: boolean;\n /** A Column's cross axis is horizontal, so rtl swaps its start and end. */\n crossReversed: boolean;\n mainAlign: MainAxisAlignment;\n crossAlign: CrossAxisAlignment;\n alignContent: AlignContent;\n paddingMainStart: number;\n paddingCrossStart: number;\n}\n\n/**\n * Calculates geometry for a retained UiNode tree.\n *\n * Layout owns a separate projection of the graph (LayoutRecords\n * keyed by UiNode identity) so the graph stays structural and\n * the renderer/hit-testing read geometry from one place. The\n * engine knows nothing about Canvas, WebGPU, or the DOM: it\n * produces numbers only.\n *\n * measure: bottom-up, dirty subtrees only, early-stop via\n * idempotent measured-size comparison\n * place: top-down, dirty paths only, re-places a child's\n * descendants only when its box actually changed\n *\n * Flex is two-pass, as in CSS: items are first measured at their\n * max-content size to obtain a flex base, the main axis is resolved,\n * and any item whose main size changed is measured again at that size\n * so a cross size that depends on it — wrapped text above all — comes\n * out right. The second pass only touches items that actually flexed.\n *\n * Scroll offset is a coordinate-space translation stored on the\n * container record; descendants keep content coordinates, so\n * scrolling never re-measures or re-places them.\n */\nexport class LayoutEngine {\n private records = new Map<UiNode, LayoutRecord>();\n /**\n * The records the previous full layout ended with, held for the\n * length of the next one so their objects can be reused.\n *\n * `layout()` starts every full pass with an empty map, because the\n * contract is that a node outside the subtree it lays out ends\n * without a record, and the only honest way to say that is to make\n * the pass re-add whatever it touches. Building the records again as\n * well is the part that was not necessary: on the benchmark list\n * that is 5,001 objects of eighty fields per pass, which was 71% of\n * everything a full pass allocated and most of the tenth of its time\n * the collector was taking. The record for a node the pass asks for\n * is lifted out of here, reset, and reused; a node the pass never\n * asks for is dropped with the map when the pass ends, exactly as\n * before.\n *\n * A record is only ever reused for the node it already belongs to,\n * so anything still holding one sees its own node's record cleared\n * rather than somebody else's values.\n *\n * Empty except while a full pass is running, so `record()`'s second\n * lookup costs nothing on an incremental frame.\n */\n private retiredRecords = new Map<UiNode, LayoutRecord>();\n private readonly scrollNodes = new Set<UiNode>();\n /**\n * Editables, which scroll their own text inside their box the way a\n * scroll container scrolls its children — the offset lives on the\n * record and is clamped every pass, but there are no scrollbars and\n * no children to translate, so they are kept apart from `scrollNodes`.\n */\n private readonly textScrollNodes = new Set<UiNode>();\n /** Absolutely positioned nodes placed against an anchor node. */\n private readonly anchoredNodes = new Set<UiNode>();\n /** The anchor each of those nodes was last placed against. */\n private readonly anchorOf = new Map<UiNode, UiNode>();\n /**\n * The reverse index: which anchored nodes each anchor carries. A box\n * that moves consults it, so an anchor that moved for any reason\n * takes its overlays with it without every frame paying for the\n * question.\n */\n private readonly anchorDependents = new Map<UiNode, Set<UiNode>>();\n /** Anchored nodes whose anchor moved this frame, re-placed once it settles. */\n private readonly movedAnchored = new Set<UiNode>();\n /**\n * The nodes asking for `lift`, in the order they asked.\n *\n * Kept as a set rather than rebuilt per pass because layout is\n * incremental: a node whose subtree was not re-placed this frame is\n * still lifted, and a list gathered during placement would have lost\n * it. Hit testing reads this, and it is empty in every frame nothing\n * is morphing, which is nearly all of them.\n */\n private readonly liftedNodes = new Set<UiNode>();\n /** position: 'sticky' nodes, re-offset whenever anything scrolls. */\n private readonly stickyNodes = new Set<UiNode>();\n /**\n * The sticky nodes whose shift came out different this pass. A shift\n * moves a node without moving its box, so it is the one thing the\n * anchor index cannot hear about from `assignBox`; this is what the\n * overlays anchored inside a sticky header are asked about, and only\n * on a pass where something actually stuck or let go.\n */\n private readonly stickyShifted = new Set<UiNode>();\n private readonly textMeasurer: TextMeasurer;\n /**\n * The definite size percentages resolve against while a container's\n * children are measured: its content box. Undefined on an axis whose\n * size is not yet known, which makes a percentage there behave as\n * `auto`, as CSS does with cyclic percentages.\n */\n private percentBase: { width: number | undefined; height: number | undefined } = {\n width: undefined,\n height: undefined\n };\n /**\n * Which layout pass this is, counted from one and bumped by every\n * `layout` and `layoutForFrame`. Records stamp it when their\n * properties are folded onto them, which is what lets\n * `resolveLayoutProps` tell \"already done, this pass\" from \"done\n * under some earlier state of the tree\".\n */\n private layoutPass = 0;\n private layoutRoot: UiNode | null = null;\n private rootConstraints: Constraints = Constraints.unbounded();\n /**\n * Bumped by anything that can move where a node is hit: every box\n * written, every pass that did any work at all, and every sticky\n * shift that came out different. Subtree bounds are a summary of the\n * records, and this is what keeps them from outliving the records\n * they summarise.\n *\n * A pass that changes nothing leaves it alone, which is the whole\n * point: a pointer crossing a still tree re-uses the same bounds\n * from the first move to the last.\n */\n private layoutVersion = 0;\n /** The version `subtreeBounds` on the records was filled from. */\n private boundsVersion = -1;\n\n constructor(textMeasurer: TextMeasurer = new CharacterCountTextMeasurer()) {\n this.textMeasurer = textMeasurer;\n }\n\n // ---------------------------------------------------------------------------\n // Public API\n // ---------------------------------------------------------------------------\n\n recordFor(node: UiNode): LayoutRecord | undefined {\n return this.records.get(node);\n }\n\n /**\n * A box around everything in a node's subtree that could take a\n * point, so a hit test can pass the subtree over instead of\n * descending into it. Undefined for a node with no record, and\n * `boundsUnbounded` where no honest box exists (see `SubtreeBounds`).\n *\n * The bounds are computed for the whole tree at once, on the first\n * ask after anything moved, rather than kept up to date as layout\n * runs. That is not laziness for its own sake: an incremental pass\n * re-places only from a relayout boundary downwards, and a boundary\n * is any node whose container fixed its size, not just a clipping\n * one, so a descendant can move and grow past the cached bounds of\n * ancestors that were never re-placed. Filling every record from one\n * walk over boxes that have all settled cannot get that wrong, and\n * it costs four number reads a node on the frames where layout\n * changed rather than a walk of the tree on every pointer move.\n */\n subtreeBoundsFor(node: UiNode): SubtreeBounds | undefined {\n if (this.boundsVersion !== this.layoutVersion) {\n this.boundsVersion = this.layoutVersion;\n if (this.layoutRoot !== null) {\n fillSubtreeBounds(this.layoutRoot, this.records);\n }\n }\n return this.records.get(node);\n }\n\n /** The node the last `layout` / `layoutForFrame` started from, if any. */\n get root(): UiNode | null {\n return this.layoutRoot;\n }\n\n /**\n * Why a node has the box it has: the constraints it was handed, what\n * its content asked for, which rule fixed each axis (a flex\n * resolution, a stretch, an explicit size, a clamp) and where a\n * change to it is laid out from. Reads the record and the node's\n * properties; computes nothing layout did not.\n *\n * `formatExplanation` prints the result; the playground's inspector\n * shows it for the hovered node.\n */\n explain(node: UiNode): LayoutExplanation {\n const rec = this.records.get(node);\n const flowParent = this.flowParentOf(node);\n const parent = node === this.layoutRoot ? null : flowParent;\n if (rec === undefined) {\n return this.unexplained(node, parent);\n }\n const isRoot = node === this.layoutRoot;\n const absolute = rec.absolute && !isRoot;\n const pRec = parent === null ? undefined : this.records.get(parent);\n const block = absolute ? this.containingBlockOf(node) : undefined;\n // Percentages resolve against what they resolved against in layout:\n // the containing block, the parent's content box, or the viewport.\n const savedBase = this.percentBase;\n this.percentBase =\n block !== undefined\n ? { width: block.width, height: block.height }\n : pRec === undefined\n ? this.rootPercentBase(this.rootConstraints)\n : {\n width: Math.max(0, pRec.width - pRec.paddingLeft - pRec.paddingRight),\n height: Math.max(0, pRec.height - pRec.paddingTop - pRec.paddingBottom)\n };\n const constraints = rec.lastConstraints;\n const effective = this.effectiveConstraints(node, constraints, undefined);\n const parentLabel = parent === null ? 'the viewport' : labelNode(parent);\n const clipsContent =\n rec.clips ||\n node.properties.get('textOverflow') === 'ellipsis' ||\n this.numberProp(node, 'maxLines') !== undefined;\n const isText =\n node.type === UiNodeType.Text || node.type === UiNodeType.Button || node.type === UiNodeType.EditableText;\n let childCount = 0;\n this.forEachLayoutChild(node, () => childCount++);\n const parentProtocol = parent === null || absolute ? undefined : parent.properties.get('layout');\n const customParent = isLayoutProtocol(parentProtocol) ? parentProtocol.name : undefined;\n const flexContainer =\n parent !== null &&\n !absolute &&\n (parent.type === UiNodeType.Row || parent.type === UiNodeType.Column || parent.type === UiNodeType.ScrollView);\n const flexFacts = (axis: 'width' | 'height'): FlexFacts | undefined => {\n if (!flexContainer || rec.flexMain !== (axis === 'width' ? 1 : 2)) {\n return undefined;\n }\n return {\n base: rec.flexBase,\n min: rec.flexMin,\n max: rec.flexMax,\n minAuto: rec.flexMinAuto,\n grow: rec.flexGrow,\n shrink: rec.flexShrink,\n basis: this.flexBasis(node, rec, axis === 'width' ? this.percentBase.width : this.percentBase.height),\n containerLabel: parentLabel,\n scroller: parent.type === UiNodeType.ScrollView\n };\n };\n const facts = (axis: 'width' | 'height'): AxisFacts => {\n const horizontal = axis === 'width';\n const base = horizontal ? this.percentBase.width : this.percentBase.height;\n const explicit = this.lengthProp(node, axis, base);\n const flex = flexFacts(axis);\n const parentMin = horizontal ? constraints.minWidth : constraints.minHeight;\n const parentMax = horizontal ? constraints.maxWidth : constraints.maxHeight;\n const tight = parentMin === parentMax && isFinite(parentMax);\n const inset =\n absolute &&\n (horizontal\n ? rec.left !== undefined && rec.right !== undefined\n : rec.top !== undefined && rec.bottom !== undefined) &&\n explicit === undefined;\n return {\n axis,\n isRoot,\n parentLabel,\n parentMin,\n parentMax,\n effectiveMin: horizontal ? effective.minWidth : effective.minHeight,\n effectiveMax: horizontal ? effective.maxWidth : effective.maxHeight,\n explicit,\n explicitRaw: node.properties.get(axis),\n ownMin: this.lengthProp(node, horizontal ? 'minWidth' : 'minHeight', base),\n ownMax: this.lengthProp(node, horizontal ? 'maxWidth' : 'maxHeight', base),\n content: horizontal ? rec.intrinsicWidth : rec.intrinsicHeight,\n measured: horizontal ? rec.measuredWidth : rec.measuredHeight,\n final: horizontal ? rec.width : rec.height,\n contentMin: horizontal ? rec.minContentWidth : rec.minContentHeight,\n padding: horizontal ? rec.paddingLeft + rec.paddingRight : rec.paddingTop + rec.paddingBottom,\n aspectRatio: rec.aspectRatio,\n flex,\n stretched: tight && !isRoot && explicit === undefined && flex === undefined && !inset,\n inset,\n gridArea: tight && parent !== null && parent.type === UiNodeType.Grid && explicit === undefined,\n customParent,\n clipsContent,\n isText,\n childCount\n };\n };\n const sources = describeOverrides(node);\n const width = withOverrideSource(buildAxisExplanation(facts('width')), sources?.width);\n const height = withOverrideSource(buildAxisExplanation(facts('height')), sources?.height);\n this.percentBase = savedBase;\n\n const position = rec.absolute ? 'absolute' : rec.sticky ? 'sticky' : rec.positioned ? 'relative' : 'static';\n return {\n node,\n laidOut: true,\n parent,\n box: { x: rec.x, y: rec.y, width: rec.width, height: rec.height },\n content: { width: rec.intrinsicWidth, height: rec.intrinsicHeight },\n measured: { width: rec.measuredWidth, height: rec.measuredHeight },\n constraints,\n effective,\n padding: { top: rec.paddingTop, right: rec.paddingRight, bottom: rec.paddingBottom, left: rec.paddingLeft },\n margin: { top: rec.marginTop, right: rec.marginRight, bottom: rec.marginBottom, left: rec.marginLeft },\n width,\n height,\n relayout: this.explainRelayout(node, rec),\n state: {\n measureDirty: rec.measureDirty,\n placeDirty: rec.placeDirty,\n measuredLastPass: this.trace ? this.stats.measuredNodes.includes(node) : undefined,\n position,\n clips: rec.clips\n },\n // A field scrolls its own text, so \"why is the line cut off here\"\n // has the same answer for it as for a scroll container.\n scroll:\n rec.scrollable || this.textScrollNodes.has(node)\n ? {\n scrollX: rec.scrollX,\n scrollY: rec.scrollY,\n contentWidth: rec.contentWidth,\n contentHeight: rec.contentHeight\n }\n : undefined,\n sources,\n custom: this.explainCustom(node, rec, childCount)\n };\n }\n\n /**\n * What a node's own layout protocol says about the arrangement.\n *\n * The protocol is asked after the pass, over handles that can be\n * read but neither measured nor placed: `explain` is a question, and\n * a question that moved boxes would be a second layout nothing\n * invalidated.\n */\n private explainCustom(node: UiNode, rec: LayoutRecord, childCount: number): CustomLayoutExplanation | undefined {\n const protocol = node.properties.get('layout');\n if (!isLayoutProtocol(protocol)) {\n return undefined;\n }\n const size = {\n width: Math.max(0, rec.width - rec.paddingLeft - rec.paddingRight),\n height: Math.max(0, rec.height - rec.paddingTop - rec.paddingBottom)\n };\n if (protocol.explain === undefined) {\n return { name: protocol.name, children: childCount, notes: [`'${protocol.name}' does not explain itself.`] };\n }\n const handles: UiLayoutChild[] = [];\n let index = 0;\n this.forEachLayoutChild(node, child => {\n const cRec = this.records.get(child);\n handles.push({\n index: index++,\n data: child.properties.get('layoutData'),\n size: { width: cRec?.width ?? 0, height: cRec?.height ?? 0 },\n position:\n cRec === undefined\n ? null\n : {\n start:\n this.startEdge(node) === 'right'\n ? rec.x + rec.paddingLeft + size.width - cRec.x - cRec.width\n : cRec.x - rec.x - rec.paddingLeft,\n top: cRec.y - rec.y - rec.paddingTop\n },\n measure() {\n throw new Error(`'${protocol.name}' cannot measure a child from explain().`);\n },\n place() {\n throw new Error(`'${protocol.name}' cannot place a child from explain().`);\n }\n });\n });\n return {\n name: protocol.name,\n children: childCount,\n notes: protocol.explain(handles, size, {\n direction: this.startEdge(node) === 'right' ? 'rtl' : 'ltr',\n definiteWidth: size.width,\n definiteHeight: size.height\n })\n };\n }\n\n private unexplained(node: UiNode, parent: UiNode | null): LayoutExplanation {\n let reason: string;\n if (this.layoutRoot === null) {\n reason = 'nothing has been laid out yet';\n } else if (this.isFragment(node)) {\n reason = 'fragments are transparent anchors with no box of their own; explain one of its children';\n } else if (!this.isUnderRoot(node)) {\n reason = `it is not under the layout root ${labelNode(this.layoutRoot)}`;\n } else if (this.hiddenAncestor(node) !== null) {\n reason = `an ancestor (${labelNode(this.hiddenAncestor(node)!)}) has not been laid out`;\n } else {\n reason = 'it was added after the last layout pass and no frame has run since';\n }\n const empty = Constraints.unbounded();\n const zero = { width: 0, height: 0 };\n const axis = (name: 'width' | 'height') => ({\n axis: name,\n content: 0,\n measured: 0,\n final: 0,\n decidedBy: 'content' as const,\n reasons: [] as string[]\n });\n return {\n node,\n laidOut: false,\n notLaidOutReason: reason,\n parent,\n box: { x: 0, y: 0, width: 0, height: 0 },\n content: zero,\n measured: zero,\n constraints: empty,\n effective: empty,\n padding: { top: 0, right: 0, bottom: 0, left: 0 },\n margin: { top: 0, right: 0, bottom: 0, left: 0 },\n width: axis('width'),\n height: axis('height'),\n relayout: {\n boundary: false,\n contentMatters: true,\n root: this.layoutRoot ?? node,\n rootIsLayoutRoot: true,\n depth: this.depthOf(node)\n },\n state: { measureDirty: true, placeDirty: true, measuredLastPass: undefined, position: 'static', clips: false }\n };\n }\n\n /**\n * Where a change to the node's own layout properties is laid out\n * from — the same walk `markLayoutDirty` takes, without marking.\n */\n private explainRelayout(node: UiNode, rec: LayoutRecord): LayoutExplanation['relayout'] {\n let current: UiNode = node;\n let depth = 0;\n for (;;) {\n if (current === this.layoutRoot || current.parent === null) {\n break;\n }\n const cRec = this.records.get(current);\n if (current !== node && cRec?.relayoutBoundary && !cRec.positioned) {\n break;\n }\n current = current.parent;\n depth++;\n }\n return {\n boundary: rec.relayoutBoundary,\n contentMatters: rec.contentMatters,\n root: current,\n rootIsLayoutRoot: current === this.layoutRoot,\n depth\n };\n }\n\n private isUnderRoot(node: UiNode): boolean {\n for (let current: UiNode | null = node; current !== null; current = current.parent) {\n if (current === this.layoutRoot) {\n return true;\n }\n }\n return false;\n }\n\n /** The nearest non-fragment ancestor without a record, if any. */\n private hiddenAncestor(node: UiNode): UiNode | null {\n for (let current = node.parent; current !== null; current = current.parent) {\n if (!this.isFragment(current) && !this.records.has(current)) {\n return current;\n }\n }\n return null;\n }\n\n /**\n * Counters for the most recent `layout` / `layoutForFrame` call.\n * `measured` and `placed` count nodes whose measure or place actually\n * ran (memo hits are free and not counted); `relayoutRoots` counts\n * subtrees laid out from a relayout boundary instead of the root.\n */\n readonly stats: LayoutStats = { measured: 0, placed: 0, relayoutRoots: 0, fullLayout: false, measuredNodes: [] };\n\n /** Records the measured nodes in `stats.measuredNodes` (for inspectors and tests). */\n trace = false;\n\n /** Where the dirty walks of the current frame stopped. */\n private readonly relayoutRoots = new Set<UiNode>();\n\n /**\n * Full layout pass for a subtree. Every record in the subtree\n * is measured and placed; other records are dropped.\n */\n /**\n * Forgets every measurement, for when what text measures has changed\n * under an unchanged tree: a declared font face arrived, so every\n * width measured with its fallback is wrong. The caller marks the\n * root's subtree dirty; the next layout then re-measures every node\n * instead of trusting the sizes it had for the same constraints.\n */\n invalidateMeasurements(): void {\n for (const rec of this.records.values()) {\n rec.measureDirty = true;\n rec.placeDirty = true;\n rec.altValid = false;\n }\n }\n\n layout(node: UiNode, constraints: Constraints): LayoutResult {\n this.layoutPass++;\n this.layoutVersion++;\n this.layoutRoot = node;\n this.rootConstraints = constraints;\n // The pass starts with no records and re-adds what it touches, so\n // that a node outside this subtree ends without one. The map that\n // held them is kept aside rather than cleared, so `record()` can\n // hand each node back the object it had; see `retiredRecords`.\n const retired = this.records;\n this.records = this.retiredRecords;\n if (this.records.size > 0) {\n // Only reachable if a previous pass threw part way through and\n // left its records behind; the contract is an empty map either way.\n this.records.clear();\n }\n this.retiredRecords = retired;\n this.liftedNodes.clear();\n this.scrollNodes.clear();\n this.textScrollNodes.clear();\n this.anchorOf.clear();\n this.anchorDependents.clear();\n this.movedAnchored.clear();\n this.resetStats();\n this.fullLayout(constraints);\n const rec = this.record(node);\n this.applyScroll();\n // Placement is one top-down walk, so an overlay placed before its\n // anchor saw a box the anchor has since been given, and an anchor\n // placed before the overlay reached the index moved without anything\n // to name. Scroll offsets are clamped only once the pass is over, so\n // every anchored node was placed against a list that had not\n // scrolled yet. Every box is final here, and a full layout has just\n // placed all of them, so each anchored node is settled once.\n for (const anchored of this.anchoredNodes) {\n this.movedAnchored.add(anchored);\n }\n this.replaceMovedAnchored();\n // Whatever is still in here belongs to a node this pass never\n // reached, which is exactly what a full layout drops.\n this.retiredRecords.clear();\n const isScroll = node.type === UiNodeType.ScrollView;\n return {\n root: node,\n box: { x: rec.x, y: rec.y, width: rec.width, height: rec.height },\n contentWidth: rec.contentWidth,\n contentHeight: rec.contentHeight,\n scrollX: rec.scrollX,\n scrollY: rec.scrollY,\n clip: isScroll\n ? { x: rec.scrollX, y: rec.scrollY, width: rec.width, height: rec.height }\n : { x: 0, y: 0, width: rec.width, height: rec.height }\n };\n }\n\n /**\n * Incremental layout driven by a scheduler frame. Only dirty\n * subtrees are re-measured and re-placed; transform-only\n * changes skip layout entirely.\n */\n layoutForFrame(frame: UiFrame, constraints: Constraints, root?: UiNode): void {\n this.layoutPass++;\n if (root !== undefined) {\n this.layoutRoot = root;\n this.rootConstraints = constraints;\n } else if (this.layoutRoot === null) {\n throw new Error('LayoutEngine has no layout root. Call layout() first.');\n } else {\n this.rootConstraints = constraints;\n }\n\n this.resetStats();\n this.relayoutRoots.clear();\n let anyLayout = false;\n for (const [node, flags] of frame.entries()) {\n if ((flags & (DirtyFlags.Layout | DirtyFlags.Children | DirtyFlags.SubtreeLayout)) !== 0) {\n anyLayout = true;\n // A node whose own layout properties changed may have a new\n // size, so it cannot bound its own relayout; one whose children\n // changed keeps its size and can.\n this.markLayoutDirty(node, (flags & DirtyFlags.Layout) === 0);\n }\n if ((flags & DirtyFlags.Transform) !== 0) {\n // A transform is the one thing a hit test reads straight off\n // the node rather than off the record, so a node that has just\n // been given one is drawn and hit somewhere its cached subtree\n // bounds never described. Asking whether it has one now is\n // what keeps the far more common member of this flag, a scroll\n // offset changing, from throwing the bounds away every frame a\n // list is scrolled: a scroll container clips, so its bounds are\n // its own box whatever its offset, and its descendants keep\n // their pre-scroll coordinates. A node that has just *lost* its\n // transform is left alone for the same reason it is safe to:\n // its bounds say unbounded, which only costs a descent.\n const transform = node.properties.get('transform');\n if (typeof transform === 'object' && transform !== null) {\n this.layoutVersion++;\n }\n this.record(node).transformDirty = true;\n (node.type === UiNodeType.EditableText ? this.textScrollNodes : this.scrollNodes).add(node);\n // An anchored node sits next to something that may just have\n // scrolled; it is re-placed, cheaply, once the frame settles.\n for (const anchored of this.anchoredNodes) {\n this.movedAnchored.add(anchored);\n }\n }\n }\n\n if (!anyLayout) {\n this.applyScroll();\n this.replaceMovedAnchored();\n return;\n }\n\n // Every box a pass writes bumps the version on its own, but a pass\n // can also change what a box means without moving it: a node that\n // stops clipping starts letting its children be hit outside it,\n // and its cached bounds are its own box. Work was done, so the\n // summary of it is thrown away.\n this.layoutVersion++;\n this.relayout(constraints);\n this.applyScroll();\n this.replaceMovedAnchored();\n }\n\n /**\n * Lays out what the frame dirtied: from the root when a dirty walk\n * reached it, otherwise from each relayout boundary the walks stopped\n * at. A boundary that turns out to have changed size after all\n * (its flag was computed under an earlier layout) hands the work to\n * its parent's walk, so the result is always the one a full layout\n * would give.\n */\n private relayout(constraints: Constraints): void {\n const root = this.layoutRoot!;\n for (;;) {\n if (this.relayoutRoots.has(root)) {\n this.relayoutRoots.clear();\n this.fullLayout(constraints);\n return;\n }\n const next = this.outermostRelayoutRoot();\n if (next === null) {\n return;\n }\n this.relayoutRoots.delete(next);\n // A root inside another root's subtree is kept: the walk that\n // stopped at it did not dirty the nodes between the two, so the\n // outer root's measure may memo-hit that path and never reach it.\n // If the outer pass did reach it, its own pass is two memo hits.\n if (!this.relayoutAt(next)) {\n this.record(next).relayoutBoundary = false;\n this.markLayoutDirty(next.parent ?? root, true);\n }\n }\n }\n\n private fullLayout(constraints: Constraints): void {\n const root = this.layoutRoot!;\n this.stats.fullLayout = true;\n this.percentBase = this.rootPercentBase(constraints);\n const rootRec = this.record(root);\n rootRec.contentMatters = false;\n this.measure(root, this.rootMeasureConstraints(root, constraints));\n const rootBox = this.computeRootBox();\n this.assignBox(root, 0, 0, rootBox.width, rootBox.height);\n if (rootRec.placeDirty) {\n this.place(root);\n }\n }\n\n /**\n * Re-measures a boundary under the constraints its parent last gave\n * it and re-places its subtree in the box it already has. Returns\n * false when its size came out different, which means the parent\n * has to be involved after all.\n */\n private relayoutAt(node: UiNode): boolean {\n const rec = this.record(node);\n const flowParent = this.flowParentOf(node);\n const pRec = flowParent === null ? undefined : this.records.get(flowParent);\n // The node's own percentages resolve against the parent's content\n // box, which is final.\n this.percentBase =\n pRec === undefined\n ? this.rootPercentBase(this.rootConstraints)\n : {\n width: Math.max(0, pRec.width - pRec.paddingLeft - pRec.paddingRight),\n height: Math.max(0, pRec.height - pRec.paddingTop - pRec.paddingBottom)\n };\n const width = rec.width;\n const height = rec.height;\n this.stats.relayoutRoots++;\n this.measure(node, rec.lastConstraints);\n if (rec.measuredWidth !== width || rec.measuredHeight !== height) {\n return false;\n }\n rec.placeDirty = true;\n this.place(node);\n return true;\n }\n\n private outermostRelayoutRoot(): UiNode | null {\n let best: UiNode | null = null;\n let bestDepth = Infinity;\n for (const node of this.relayoutRoots) {\n const depth = this.depthOf(node);\n if (depth < bestDepth) {\n best = node;\n bestDepth = depth;\n }\n }\n return best;\n }\n\n private depthOf(node: UiNode): number {\n let depth = 0;\n for (let current = node.parent; current !== null; current = current.parent) {\n depth++;\n }\n return depth;\n }\n\n /**\n * A root without an explicit size fills bounded constraints\n * (computeRootBox), so it is measured tight there: its children then\n * see the definite size they will be placed in, and a stretched\n * child is measured once at that size instead of loose and again at\n * placement.\n */\n private rootMeasureConstraints(root: UiNode, constraints: Constraints): Constraints {\n const base = this.rootPercentBase(constraints);\n const fillsWidth = constraints.hasBoundedWidth() && this.lengthProp(root, 'width', base.width) === undefined;\n const fillsHeight = constraints.hasBoundedHeight() && this.lengthProp(root, 'height', base.height) === undefined;\n if (!fillsWidth && !fillsHeight) {\n return constraints;\n }\n return new Constraints(\n fillsWidth ? constraints.maxWidth : constraints.minWidth,\n constraints.maxWidth,\n fillsHeight ? constraints.maxHeight : constraints.minHeight,\n constraints.maxHeight\n );\n }\n\n private resetStats(): void {\n this.stats.measured = 0;\n this.stats.placed = 0;\n this.stats.relayoutRoots = 0;\n this.stats.fullLayout = false;\n this.stats.measuredNodes.length = 0;\n }\n\n /** Marks every record in a subtree as no boundary, without measuring. */\n private clearBoundaries(node: UiNode): void {\n const stack: UiNode[] = [node];\n while (stack.length > 0) {\n const current = stack.pop()!;\n const rec = this.records.get(current);\n if (rec !== undefined) {\n rec.relayoutBoundary = false;\n rec.contentMatters = true;\n }\n for (let child = current.firstChild; child !== null; child = child.nextSibling) {\n stack.push(child);\n }\n }\n }\n\n /**\n * Border box of a node in layout coordinates (relative to the\n * layout root). For scroll containers this is also the clip.\n */\n worldBoxTo(node: UiNode, out: LayoutBox): LayoutBox {\n const rec = this.records.get(node);\n if (rec === undefined) {\n out.x = 0;\n out.y = 0;\n out.width = 0;\n out.height = 0;\n return out;\n }\n accumulatedOffsetTo(node, this.records, out);\n out.width = rec.width;\n out.height = rec.height;\n return out;\n }\n\n worldBox(node: UiNode): LayoutBox {\n return this.worldBoxTo(node, { x: 0, y: 0, width: 0, height: 0 });\n }\n\n /**\n * Where a node is actually seen: its record box shifted by every\n * scroll ancestor's offset and by the sticky offsets of the node and\n * its ancestors. Records stay in pre-scroll coordinates; this is the\n * projection renderers and hit testing agree on.\n */\n visibleBox(node: UiNode): LayoutBox {\n const rec = this.records.get(node);\n if (rec === undefined) {\n return { x: 0, y: 0, width: 0, height: 0 };\n }\n let x = rec.x + rec.stickyOffsetX;\n let y = rec.y + rec.stickyOffsetY;\n for (let current = node.parent; current !== null; current = current.parent) {\n const ancestor = this.records.get(current);\n if (ancestor === undefined) {\n continue;\n }\n x += ancestor.stickyOffsetX;\n y += ancestor.stickyOffsetY;\n if (ancestor.scrollable) {\n x -= ancestor.scrollX;\n y -= ancestor.scrollY;\n }\n }\n return { x, y, width: rec.width, height: rec.height };\n }\n\n /**\n * The scroll offsets each scroll ancestor would need so that `node`\n * is inside its viewport, `padding` pixels from the nearest edge,\n * innermost first. Nothing is changed: the caller writes the offsets\n * (scrollX/scrollY properties) and marks the containers dirty, which\n * is how GessoRuntime.scrollIntoView keeps a focused row on screen.\n *\n * `inner`, a box in the node's own coordinates, reveals that part of\n * the node instead of the whole — the caret of a tall editable.\n */\n revealAdjustments(node: UiNode, padding = 0, inner?: LayoutBox): ScrollAdjustment[] {\n const rec = this.records.get(node);\n if (rec === undefined) {\n return [];\n }\n const targetX = rec.x + (inner?.x ?? 0);\n const targetY = rec.y + (inner?.y ?? 0);\n const targetWidth = inner?.width ?? rec.width;\n const targetHeight = inner?.height ?? rec.height;\n const adjustments: ScrollAdjustment[] = [];\n // The target's edges in the layout root's pre-scroll frame, brought\n // into each successive scroller's content space by removing the\n // offsets of the scrollers passed on the way up.\n let innerScrollX = 0;\n let innerScrollY = 0;\n // A field scrolls its own text first: the caret comes into the\n // field's content box, and the ancestors then only have to bring\n // the field itself into view.\n if (inner !== undefined && this.textScrollNodes.has(node)) {\n const self = this.textScrollAdjustment(rec, targetX, targetY, targetWidth, targetHeight, padding);\n if (self.scrollX !== rec.scrollX || self.scrollY !== rec.scrollY) {\n adjustments.push({ container: node, scrollX: self.scrollX, scrollY: self.scrollY });\n }\n innerScrollX = self.scrollX;\n innerScrollY = self.scrollY;\n }\n for (let current = node.parent; current !== null; current = current.parent) {\n const container = this.records.get(current);\n if (container === undefined || !container.scrollable) {\n continue;\n }\n const left = targetX - innerScrollX - padding;\n const right = targetX + targetWidth - innerScrollX + padding;\n const top = targetY - innerScrollY - padding;\n const bottom = targetY + targetHeight - innerScrollY + padding;\n const viewLeft = container.x + container.scrollX;\n const viewTop = container.y + container.scrollY;\n let scrollX = container.scrollX;\n let scrollY = container.scrollY;\n if (left < viewLeft) {\n scrollX -= viewLeft - left;\n } else if (right > viewLeft + container.width) {\n scrollX += right - (viewLeft + container.width);\n }\n if (top < viewTop) {\n scrollY -= viewTop - top;\n } else if (bottom > viewTop + container.height) {\n scrollY += bottom - (viewTop + container.height);\n }\n scrollX = this.clamp(scrollX, 0, Math.max(0, container.contentWidth - container.width));\n scrollY = this.clamp(scrollY, 0, Math.max(0, container.contentHeight - container.height));\n if (scrollX !== container.scrollX || scrollY !== container.scrollY) {\n adjustments.push({ container: current, scrollX, scrollY });\n }\n innerScrollX += scrollX;\n innerScrollY += scrollY;\n }\n return adjustments;\n }\n\n /**\n * Where a field must scroll its own text so that `target` — the caret,\n * padded — is inside its content box.\n *\n * The offset is not clamped to the record's content size, only to\n * zero: the caret is placed from the text as it is now, while the\n * record's extent is from the last pass and so is a keystroke behind\n * while typing at the end of a line. `applyScroll` clamps against the\n * fresh extent on the pass that follows, which is what pulls the\n * offset back when text is deleted.\n */\n private textScrollAdjustment(\n rec: LayoutRecord,\n targetX: number,\n targetY: number,\n targetWidth: number,\n targetHeight: number,\n padding: number\n ): { scrollX: number; scrollY: number } {\n const viewLeft = rec.x + rec.paddingLeft + rec.scrollX;\n const viewTop = rec.y + rec.paddingTop + rec.scrollY;\n const viewWidth = Math.max(0, rec.width - rec.paddingLeft - rec.paddingRight);\n const viewHeight = Math.max(0, rec.height - rec.paddingTop - rec.paddingBottom);\n const left = targetX - padding;\n const right = targetX + targetWidth + padding;\n const top = targetY - padding;\n const bottom = targetY + targetHeight + padding;\n let scrollX = rec.scrollX;\n let scrollY = rec.scrollY;\n if (left < viewLeft) {\n scrollX -= viewLeft - left;\n } else if (right > viewLeft + viewWidth) {\n scrollX += right - (viewLeft + viewWidth);\n }\n if (top < viewTop) {\n scrollY -= viewTop - top;\n } else if (bottom > viewTop + viewHeight) {\n scrollY += bottom - (viewTop + viewHeight);\n }\n return { scrollX: Math.max(0, scrollX), scrollY: Math.max(0, scrollY) };\n }\n\n /**\n * Shows a scroll container's scrollbars as if it had just scrolled:\n * the pointer is near them, or dragging one.\n */\n revealScrollbars(node: UiNode): void {\n const rec = this.records.get(node);\n if (rec !== undefined) {\n rec.scrollbarVisibleUntil = this.now() + SCROLLBAR_LINGER_MS;\n }\n }\n\n /** Every scroll container that has been laid out. */\n scrollContainers(): Iterable<UiNode> {\n return this.scrollNodes;\n }\n\n /**\n * When the next scrollbar changes appearance (starts fading or\n * disappears), or undefined when none is showing. Lets a host schedule\n * the repaint that a fade needs without polling.\n */\n nextScrollbarChange(now: number): number | undefined {\n let next: number | undefined;\n for (const node of this.scrollNodes) {\n const rec = this.records.get(node);\n if (rec === undefined || !rec.scrollable || rec.scrollbarVisibleUntil <= now) {\n continue;\n }\n if (rec.contentWidth <= rec.width && rec.contentHeight <= rec.height) {\n continue;\n }\n const fadeStart = rec.scrollbarVisibleUntil - SCROLLBAR_FADE_MS;\n const candidate = now < fadeStart ? fadeStart : now + 16;\n next = next === undefined ? candidate : Math.min(next, candidate);\n }\n return next;\n }\n\n /**\n * The visible window of a scroll container over its content,\n * in content coordinates.\n */\n contentWindow(node: UiNode): LayoutBox {\n const rec = this.records.get(node);\n if (rec === undefined) {\n return { x: 0, y: 0, width: 0, height: 0 };\n }\n return { x: rec.scrollX, y: rec.scrollY, width: rec.width, height: rec.height };\n }\n\n /**\n * Drops layout records for a removed subtree. Wired to\n * UiGraph's node-removal listener.\n */\n detachNode(node: UiNode): void {\n const stack: UiNode[] = [node];\n while (stack.length > 0) {\n const current = stack.pop()!;\n this.records.delete(current);\n // A node removed part way through a full pass must not be handed\n // back the record it had when the pass reaches it.\n this.retiredRecords.delete(current);\n this.liftedNodes.delete(current);\n this.scrollNodes.delete(current);\n this.textScrollNodes.delete(current);\n this.anchoredNodes.delete(current);\n this.movedAnchored.delete(current);\n this.forgetAnchoring(current);\n this.stickyNodes.delete(current);\n this.stickyShifted.delete(current);\n for (let child = current.firstChild; child !== null; child = child.nextSibling) {\n stack.push(child);\n }\n }\n }\n\n // ---------------------------------------------------------------------------\n // Measurement\n // ---------------------------------------------------------------------------\n\n private measure(node: UiNode, constraints: Constraints): void {\n const rec = this.record(node);\n if (this.isFragment(node)) {\n // Fragments are transparent graph anchors. Their children are\n // measured, but the fragment itself contributes zero size.\n this.forEachLayoutChild(node, child => this.measure(child, constraints));\n rec.measuredWidth = 0;\n rec.measuredHeight = 0;\n rec.outerWidth = 0;\n rec.outerHeight = 0;\n rec.measureDirty = false;\n return;\n }\n if (!rec.measureDirty) {\n if (constraintsEqual(rec.lastConstraints, constraints)) {\n return;\n }\n if (rec.altValid && constraintsEqual(rec.altConstraints, constraints)) {\n rec.swapAlt();\n return;\n }\n rec.saveAlt();\n } else {\n rec.altValid = false;\n }\n this.stats.measured++;\n if (this.trace) {\n this.stats.measuredNodes.push(node);\n }\n rec.lastConstraints = constraints;\n this.resolveLayoutProps(node, rec);\n rec.hasBaseline = false;\n // Containers that know their min-content height set it as they\n // measure; everything else gets the content height below. A\n // negative value is \"not set\", so a measurer cannot leave a stale\n // one behind from the last constraints.\n rec.minContentHeight = -1;\n const effective = this.effectiveConstraints(node, constraints, rec);\n let size: Size;\n if (\n node.type === UiNodeType.Row ||\n node.type === UiNodeType.Column ||\n node.type === UiNodeType.ScrollView ||\n node.hasChildren()\n ) {\n size = this.measureContainer(node, rec, effective);\n } else {\n size = this.measureLeaf(node, rec, effective);\n }\n if (rec.aspectRatio !== undefined) {\n size = this.applyAspectRatio(size, rec.aspectRatio, effective);\n }\n // The content's own size, before any explicit or parent size: the\n // \"content size suggestion\" a column uses for automatic minimums,\n // and what explain() reports the content asked for.\n rec.intrinsicWidth = size.width;\n rec.intrinsicHeight = size.height;\n if (rec.minContentHeight < 0) {\n rec.minContentHeight = size.height;\n }\n // A tight axis is the parent's decision (a flexed main size, a\n // stretched cross size, the viewport) and wins outright. A loose\n // axis only set the available space: content that cannot fit it\n // overflows, as in CSS, clamped by the node's own min/max alone.\n rec.measuredWidth =\n effective.minWidth === effective.maxWidth\n ? effective.minWidth\n : this.clamp(Math.max(size.width, effective.minWidth), rec.minWidth, rec.maxWidth);\n rec.measuredHeight =\n effective.minHeight === effective.maxHeight\n ? effective.minHeight\n : this.clamp(Math.max(size.height, effective.minHeight), rec.minHeight, rec.maxHeight);\n rec.outerWidth = rec.measuredWidth + rec.marginLeft + rec.marginRight;\n rec.outerHeight = rec.measuredHeight + rec.marginTop + rec.marginBottom;\n rec.measureDirty = false;\n }\n\n private measureContainer(node: UiNode, rec: LayoutRecord, effective: Constraints): Size {\n const content = this.contentConstraints(rec, effective);\n // Checked before the node's type is looked at, so a Row or a Grid\n // carrying a protocol is arranged by it rather than by two\n // algorithms disagreeing about the same children.\n const protocol = node.properties.get('layout');\n if (isLayoutProtocol(protocol)) {\n return this.measureCustom(node, rec, protocol, content);\n }\n if (node.type === UiNodeType.ScrollView) {\n return this.measureScroll(node, rec, content);\n }\n if (node.type === UiNodeType.Row || node.type === UiNodeType.Column) {\n return this.measureFlex(\n node,\n rec,\n content,\n node.type === UiNodeType.Row ? FlexDirection.Row : FlexDirection.Column\n );\n }\n if (node.type === UiNodeType.Grid) {\n return this.measureGrid(node, rec, content);\n }\n return this.measureStack(node, rec, content);\n }\n\n // ---------------------------------------------------------------------------\n // Grid\n // ---------------------------------------------------------------------------\n\n private measureGrid(node: UiNode, rec: LayoutRecord, content: Constraints): Size {\n const paddingH = rec.paddingLeft + rec.paddingRight;\n const paddingV = rec.paddingTop + rec.paddingBottom;\n const grid = this.layoutGrid(\n node,\n content,\n this.definiteAxis(content, 'width'),\n this.definiteAxis(content, 'height')\n );\n rec.minContentWidth = paddingH + grid.columns.minTotal;\n const first = grid.placements[0];\n if (first !== undefined) {\n const cRec = this.record(first.item);\n rec.hasBaseline = true;\n rec.baseline =\n rec.paddingTop +\n grid.rows.tracks[first.rowStart].offset +\n cRec.marginTop +\n (cRec.hasBaseline ? cRec.baseline : cRec.measuredHeight);\n }\n return { width: paddingH + grid.columns.total, height: paddingV + grid.rows.total };\n }\n\n private placeGrid(node: UiNode, rec: LayoutRecord): void {\n const contentX = rec.x + rec.paddingLeft;\n const contentY = rec.y + rec.paddingTop;\n const contentWidth = Math.max(0, rec.width - rec.paddingLeft - rec.paddingRight);\n const contentHeight = Math.max(0, rec.height - rec.paddingTop - rec.paddingBottom);\n // The box is final: tracks are sized against it, percentages resolve.\n const content = new Constraints(contentWidth, contentWidth, contentHeight, contentHeight);\n const grid = this.layoutGrid(node, content, contentWidth, contentHeight);\n const gridX = parseCrossAxisAlignment(node.properties.get('x')) ?? CrossAxisAlignment.Stretch;\n const gridY = parseCrossAxisAlignment(node.properties.get('y')) ?? CrossAxisAlignment.Stretch;\n // Under rtl the first column line is the right edge. The tracks are\n // sized identically either way, so the whole column axis is\n // mirrored in one place here rather than in the sizing: an area is\n // reflected across the content box, and the alignment inside it\n // with it. `justifyContent`'s distribution is already in the track\n // offsets and reflects with them.\n const mirrored = this.startEdge(node) === 'right';\n const savedBase = this.percentBase;\n for (const placement of grid.placements) {\n const child = placement.item;\n const cRec = this.record(child);\n const area = this.gridArea(grid, placement);\n if (mirrored) {\n area.x = contentWidth - area.x - area.width;\n }\n this.percentBase = { width: area.width, height: area.height };\n this.resolveLayoutProps(child, cRec);\n const alignX = this.stackAlignment(child, 'selfX', 'width', gridX, mirrored);\n const alignY = this.stackAlignment(child, 'selfY', 'height', gridY);\n const availableWidth = Math.max(0, area.width - cRec.marginLeft - cRec.marginRight);\n const availableHeight = Math.max(0, area.height - cRec.marginTop - cRec.marginBottom);\n this.measure(\n child,\n new Constraints(\n alignX === CrossAxisAlignment.Stretch ? availableWidth : 0,\n availableWidth,\n alignY === CrossAxisAlignment.Stretch ? availableHeight : 0,\n availableHeight\n )\n );\n const x =\n contentX + area.x + cRec.marginLeft + this.stackOffset(alignX, availableWidth, cRec.measuredWidth, mirrored);\n const y = contentY + area.y + cRec.marginTop + this.stackOffset(alignY, availableHeight, cRec.measuredHeight);\n this.assignBox(child, x, y, cRec.measuredWidth, cRec.measuredHeight);\n }\n this.percentBase = savedBase;\n }\n\n /**\n * Places the grid's items and sizes both axes' tracks (GridLayout.ts\n * does the arithmetic). Columns are sized from the items' intrinsic\n * widths, then rows from the items' heights at their column widths —\n * the same two-step CSS Grid takes, which is what lets text in a cell\n * wrap at its column and decide its row's height.\n */\n private layoutGrid(\n node: UiNode,\n content: Constraints,\n availableWidth: number | undefined,\n availableHeight: number | undefined\n ): { columns: GridTrackSizingResult; rows: GridTrackSizingResult; placements: GridPlacement<UiNode>[] } {\n const columnsProp = this.trackList(node, 'columns');\n const rowsProp = this.trackList(node, 'rows');\n const autoColumns = this.trackSize(node, 'autoColumns');\n const autoRows = this.trackSize(node, 'autoRows');\n const flow = node.properties.get('autoFlow') === 'column' ? 'column' : 'row';\n const gap = this.numberProp(node, 'gap') ?? 0;\n const columnGap = this.numberProp(node, 'columnGap') ?? gap;\n const rowGap = this.numberProp(node, 'rowGap') ?? gap;\n const gridX = parseCrossAxisAlignment(node.properties.get('x')) ?? CrossAxisAlignment.Stretch;\n\n // A subgrid's own tracks come from its parent, so its own `columns`\n // prop is not read here: the tracks it has are the span it was\n // given, and its cells are placed into those.\n const subgridded = this.subgridColumns(node);\n const explicitColumns = subgridded?.tracks.length ?? columnsProp.length;\n const requests = this.gridRequests(node, explicitColumns);\n const placed = placeGridItems(requests, explicitColumns, rowsProp.length, flow);\n const columnSizes = subgridded?.tracks ?? this.fillTracks(columnsProp, placed.columnCount, autoColumns);\n const rowSizes = this.fillTracks(rowsProp, placed.rowCount, autoRows);\n const effectiveColumnGap = subgridded?.gap ?? columnGap;\n\n const savedBase = this.percentBase;\n this.percentBase = { width: availableWidth, height: availableHeight };\n\n // Columns: from each item's min- and max-content width — except a\n // subgrid item, whose own children contribute to the tracks it\n // spans, one per column, so the parent sizes a column from the\n // cells in it rather than from a row treated as one lump.\n const gridRec = this.record(node);\n const columnItems: Array<{ start: number; end: number; contribution: GridContribution }> = [];\n for (const placement of placed.placements) {\n const cRec = this.record(placement.item);\n this.resolveLayoutProps(placement.item, cRec);\n if (this.isSubgrid(placement.item)) {\n cRec.contentMatters = true;\n cRec.relayoutBoundary = false;\n this.collectSubgridColumns(placement, columnItems);\n continue;\n }\n // Tracks are sized from the items' content unless both of an\n // item's sizes are lengths.\n const explicitBoth =\n this.lengthProp(placement.item, 'width', undefined) !== undefined &&\n this.lengthProp(placement.item, 'height', undefined) !== undefined;\n cRec.contentMatters = gridRec.contentMatters || !explicitBoth;\n this.measure(placement.item, new Constraints(0, Infinity, 0, Infinity));\n cRec.relayoutBoundary =\n explicitBoth && !cRec.contentMatters && cRec.aspectRatio === undefined && !cRec.positioned;\n const marginH = cRec.marginLeft + cRec.marginRight;\n const contribution: GridContribution = {\n min: this.minContentContribution(placement.item, cRec) + marginH,\n max: cRec.measuredWidth + marginH\n };\n columnItems.push({ start: placement.columnStart, end: placement.columnEnd, contribution });\n }\n const columns = sizeGridTracks({\n sizes: columnSizes,\n available: availableWidth,\n gap: effectiveColumnGap,\n distribution: parseAlignContent(node.properties.get('justifyContent')),\n items: columnItems\n });\n\n // Every subgrid row now knows the widths it must lay its cells out\n // in, before it is measured for its own row's height below.\n for (const placement of placed.placements) {\n if (this.isSubgrid(placement.item)) {\n this.publishSubgridTracks(placement, columns, effectiveColumnGap);\n }\n }\n\n // Rows: from each item's height at the width its column area gives it.\n const rowItems = placed.placements.map(placement => {\n const cRec = this.record(placement.item);\n const areaWidth = this.spanExtent(columns, placement.columnStart, placement.columnEnd, effectiveColumnGap);\n const alignX = this.stackAlignment(placement.item, 'selfX', 'width', gridX);\n const marginH = cRec.marginLeft + cRec.marginRight;\n const width = Math.max(0, areaWidth - marginH);\n this.percentBase = { width: areaWidth, height: availableHeight };\n this.measure(\n placement.item,\n new Constraints(alignX === CrossAxisAlignment.Stretch ? width : 0, width, 0, Infinity)\n );\n const height = cRec.measuredHeight + cRec.marginTop + cRec.marginBottom;\n return { start: placement.rowStart, end: placement.rowEnd, contribution: { min: height, max: height } };\n });\n const rows = sizeGridTracks({\n sizes: rowSizes,\n available: availableHeight,\n gap: rowGap,\n distribution: parseAlignContent(node.properties.get('alignContent')),\n items: rowItems\n });\n this.percentBase = savedBase;\n void content;\n return { columns, rows, placements: placed.placements };\n }\n\n /**\n * A grid's items, fragments expanded, with their placement requests.\n *\n * A subgrid child that does not say how many columns it spans spans\n * all of them: a table row shares the whole header, and requiring\n * every row to repeat the column count would be a number to keep in\n * step with the columns array.\n */\n private gridRequests(node: UiNode, explicitColumns: number): GridItemRequest<UiNode>[] {\n const requests: GridItemRequest<UiNode>[] = [];\n this.forEachLayoutChild(node, child => {\n const declaredSpan = this.numberProp(child, 'columnSpan');\n const span =\n declaredSpan === undefined && this.isSubgrid(child)\n ? Math.max(1, explicitColumns)\n : Math.max(1, Math.floor(declaredSpan ?? 1));\n requests.push({\n item: child,\n column: this.lineProp(child, 'column'),\n row: this.lineProp(child, 'row'),\n columnSpan: span,\n rowSpan: Math.max(1, Math.floor(this.numberProp(child, 'rowSpan') ?? 1))\n });\n });\n return requests;\n }\n\n /** A Grid that takes its column tracks from the grid it sits in. */\n private isSubgrid(node: UiNode): boolean {\n return node.type === UiNodeType.Grid && node.properties.get('subgrid') === 'columns';\n }\n\n /**\n * The tracks a subgrid was handed by its parent, as fixed lengths, or\n * undefined for an ordinary grid.\n *\n * A subgrid that is laid out with no parent tracks yet — measured on\n * its own, or sitting in something that is not a Grid — falls back to\n * its own `columns`, so it degrades to an ordinary grid rather than\n * collapsing to nothing.\n */\n private subgridColumns(node: UiNode): { tracks: UiTrackSize[]; gap: number } | undefined {\n if (!this.isSubgrid(node)) {\n return undefined;\n }\n const rec = this.record(node);\n if (rec.subgridColumns === undefined) {\n return undefined;\n }\n return { tracks: [...rec.subgridColumns], gap: rec.subgridColumnGap };\n }\n\n /**\n * Contributes a subgrid's cells to the parent's tracks, one entry per\n * cell in the parent's column space.\n *\n * The cells are measured here rather than through the subgrid,\n * because the subgrid cannot be measured until the tracks these\n * contributions decide exist. A subgrid's own horizontal padding and\n * margins are not distributed into the tracks (CSS subgrid does):\n * a row that wants inset content puts the padding on its cells.\n */\n private collectSubgridColumns(\n placement: GridPlacement<UiNode>,\n out: Array<{ start: number; end: number; contribution: GridContribution }>\n ): void {\n const span = placement.columnEnd - placement.columnStart;\n const inner = placeGridItems(this.gridRequests(placement.item, span), span, 0, 'row');\n for (const cell of inner.placements) {\n const cellRec = this.record(cell.item);\n this.resolveLayoutProps(cell.item, cellRec);\n cellRec.contentMatters = true;\n this.measure(cell.item, new Constraints(0, Infinity, 0, Infinity));\n cellRec.relayoutBoundary = false;\n const marginH = cellRec.marginLeft + cellRec.marginRight;\n out.push({\n // A cell beyond the row's span is clamped into it: the parent\n // has no track there, and a row is not allowed to add one.\n start: placement.columnStart + Math.min(cell.columnStart, span - 1),\n end: placement.columnStart + Math.min(cell.columnEnd, span),\n contribution: {\n min: this.minContentContribution(cell.item, cellRec) + marginH,\n max: cellRec.measuredWidth + marginH\n }\n });\n }\n }\n\n /**\n * Writes the parent's resolved tracks onto a subgrid, and marks it\n * for re-measurement when they moved — its constraints can be\n * unchanged while the tracks inside them are not, and the measurement\n * cache compares only constraints.\n */\n private publishSubgridTracks(placement: GridPlacement<UiNode>, columns: GridTrackSizingResult, gap: number): void {\n const rec = this.record(placement.item);\n const tracks: number[] = [];\n for (let index = placement.columnStart; index < placement.columnEnd; index++) {\n tracks.push(columns.tracks[Math.min(index, columns.tracks.length - 1)]?.size ?? 0);\n }\n const previous = rec.subgridColumns;\n if (\n previous === undefined ||\n rec.subgridColumnGap !== gap ||\n previous.length !== tracks.length ||\n previous.some((size, index) => size !== tracks[index])\n ) {\n rec.subgridColumns = tracks;\n rec.subgridColumnGap = gap;\n rec.measureDirty = true;\n rec.placeDirty = true;\n }\n }\n\n private gridArea(\n grid: { columns: GridTrackSizingResult; rows: GridTrackSizingResult },\n placement: GridPlacement<UiNode>\n ): LayoutBox {\n const x = grid.columns.tracks[placement.columnStart].offset;\n const y = grid.rows.tracks[placement.rowStart].offset;\n const lastColumn = grid.columns.tracks[placement.columnEnd - 1];\n const lastRow = grid.rows.tracks[placement.rowEnd - 1];\n return { x, y, width: lastColumn.offset + lastColumn.size - x, height: lastRow.offset + lastRow.size - y };\n }\n\n private spanExtent(result: GridTrackSizingResult, start: number, end: number, gap: number): number {\n if (end <= start || result.tracks.length === 0) {\n return 0;\n }\n const first = result.tracks[Math.min(start, result.tracks.length - 1)];\n const last = result.tracks[Math.min(end - 1, result.tracks.length - 1)];\n void gap;\n return last.offset + last.size - first.offset;\n }\n\n private fillTracks(explicit: readonly UiTrackSize[], count: number, implicit: UiTrackSize): UiTrackSize[] {\n const sizes = [...explicit];\n while (sizes.length < count) {\n sizes.push(implicit);\n }\n return sizes;\n }\n\n private trackList(node: UiNode, property: string): readonly UiTrackSize[] {\n const value = node.properties.get(property);\n if (value === undefined || value === null) {\n return [];\n }\n if (!Array.isArray(value)) {\n throw new Error(\n `Property '${property}' must be an array of track sizes (numbers, percent(), auto, fr(), minmax()).`\n );\n }\n return value as UiTrackSize[];\n }\n\n private trackSize(node: UiNode, property: string): UiTrackSize {\n const value = node.properties.get(property);\n return value === undefined || value === null ? { unit: 'auto' } : (value as UiTrackSize);\n }\n\n /** A 1-based grid line, or undefined for auto placement. */\n private lineProp(node: UiNode, property: string): number | undefined {\n const value = this.numberProp(node, property);\n if (value === undefined) {\n return undefined;\n }\n if (!Number.isInteger(value) || value < 1) {\n throw new Error(`Property '${property}' must be a positive integer grid line, got ${String(value)}.`);\n }\n return value;\n }\n\n /** Constraints for a container's content box: the border box less padding. */\n private contentConstraints(rec: LayoutRecord, effective: Constraints): Constraints {\n const paddingH = rec.paddingLeft + rec.paddingRight;\n const paddingV = rec.paddingTop + rec.paddingBottom;\n return new Constraints(\n Math.max(0, effective.minWidth - paddingH),\n Math.max(0, effective.maxWidth - paddingH),\n Math.max(0, effective.minHeight - paddingV),\n Math.max(0, effective.maxHeight - paddingV)\n );\n }\n\n private measureFlex(node: UiNode, rec: LayoutRecord, content: Constraints, direction: FlexDirection): Size {\n const row = direction === FlexDirection.Row;\n const paddingMain = row ? rec.paddingLeft + rec.paddingRight : rec.paddingTop + rec.paddingBottom;\n const paddingCross = row ? rec.paddingTop + rec.paddingBottom : rec.paddingLeft + rec.paddingRight;\n const config = this.flexConfig(node, rec, direction);\n const mainMin = row ? content.minWidth : content.minHeight;\n const mainMax = row ? content.maxWidth : content.maxHeight;\n const mainBounded = isFinite(mainMax);\n const mainDefinite = mainBounded && mainMin === mainMax;\n const crossDefinite = row\n ? isFinite(content.maxHeight) && content.minHeight === content.maxHeight\n : isFinite(content.maxWidth) && content.minWidth === content.maxWidth;\n\n const items = this.collectFlexItems(node, content, direction, config, crossDefinite && !config.wrap);\n if (items.length === 0) {\n rec.minContentWidth = rec.paddingLeft + rec.paddingRight;\n rec.minContentHeight = rec.paddingTop + rec.paddingBottom;\n return { width: paddingMain, height: paddingCross };\n }\n const lines = this.breakLines(items, config, mainBounded ? mainMax : Infinity);\n\n // Resolve the main axis now when the outcome is already known: the\n // container's main size is definite (explicit or tight), or a line\n // overflows and must shrink to the available space. Otherwise the\n // container shrink-wraps its items and nothing flexes here; a parent\n // that then assigns a larger box (the layout root filling its\n // viewport, a stretched cross axis) gets the same resolution and\n // second pass from placeFlex.\n let contentMain = 0;\n for (const line of lines) {\n const lineTotal = this.lineOuterMain(line, config.gapMain, 'hypothetical');\n if (mainBounded && (mainDefinite || lineTotal > mainMax)) {\n this.resolveLine(line, mainMax - config.gapMain * (line.items.length - 1), config);\n this.measureFlexedItems(\n line.items,\n content,\n direction,\n crossDefinite && !config.wrap ? (row ? content.maxHeight : content.maxWidth) : undefined\n );\n contentMain = Math.max(contentMain, this.lineOuterMain(line, config.gapMain, 'final'));\n } else {\n for (const item of line.items) {\n item.finalMain = item.hypotheticalMain;\n }\n contentMain = Math.max(contentMain, this.lineMaxContentMain(line, config.gapMain));\n }\n }\n if (mainDefinite) {\n contentMain = Math.max(mainMax, contentMain);\n }\n this.markFlexBoundaries(lines);\n\n let contentCross = 0;\n for (const line of lines) {\n line.cross = this.flexLineCross(line.items, row);\n contentCross += line.cross;\n }\n contentCross += config.gapLine * (lines.length - 1);\n\n this.setFlexBaseline(rec, lines[0].items, row);\n rec.minContentWidth = this.flexMinContentWidth(rec, items, row, config);\n rec.minContentHeight = this.flexMinContentHeight(rec, items, row, config);\n return {\n width: row ? paddingMain + contentMain : paddingCross + contentCross,\n height: row ? paddingCross + contentCross : paddingMain + contentMain\n };\n }\n\n /**\n * The properties that shape a flex container, read once per pass.\n */\n private flexConfig(node: UiNode, rec: LayoutRecord, direction: FlexDirection): FlexConfig {\n const row = direction === FlexDirection.Row;\n const gap = this.numberProp(node, 'gap') ?? 0;\n const rowGap = this.numberProp(node, 'rowGap') ?? gap;\n const columnGap = this.numberProp(node, 'columnGap') ?? gap;\n const wrapValue = node.properties.get('flexWrap');\n const wrap = wrapValue === 'wrap' || wrapValue === 'wrap-reverse';\n const rawDirection = node.properties.get('direction');\n const reversedDirection = typeof rawDirection === 'string' && rawDirection.endsWith('-reverse');\n // Under rtl the horizontal axis runs the other way, whichever axis\n // of the container that is. For a Row it is the main axis, so\n // alignment, ordering and auto margins all mirror with it; for a\n // Column it is the cross axis, so `x` and `selfX` swap start for\n // end and nothing about the order changes.\n const rtl = resolveString(node, 'textDirection') === 'rtl';\n return {\n row,\n isScroll: node.type === UiNodeType.ScrollView,\n gapMain: row ? columnGap : rowGap,\n gapLine: row ? rowGap : columnGap,\n wrap,\n // A wrapping Column stacks its lines along the horizontal axis,\n // so rtl mirrors them for the same reason `wrap-reverse` does,\n // and the two cancel when both apply.\n wrapReverse: (wrapValue === 'wrap-reverse') !== (!row && rtl),\n mainReversed: reversedDirection !== (row && rtl),\n crossReversed: !row && rtl,\n mainAlign: parseMainAxisAlignment(node.properties.get(row ? 'x' : 'y')),\n crossAlign: parseCrossAxisAlignment(node.properties.get(row ? 'y' : 'x')) ?? CrossAxisAlignment.Stretch,\n alignContent: parseAlignContent(node.properties.get('alignContent')),\n paddingMainStart: row ? rec.paddingLeft : rec.paddingTop,\n paddingCrossStart: row ? rec.paddingTop : rec.paddingLeft\n };\n }\n\n /**\n * Measures each child at its flex base size and builds the items\n * the resolution steps work on.\n *\n * `crossTightForStretch` is true for a single-line container whose\n * cross size is definite: CSS gives stretched items that size before\n * measuring (9.2.3), so text wraps at the width it will really have.\n */\n private collectFlexItems(\n node: UiNode,\n content: Constraints,\n direction: FlexDirection,\n config: FlexConfig,\n crossTightForStretch: boolean\n ): FlexItem[] {\n const row = direction === FlexDirection.Row;\n const rec = this.record(node);\n const items: FlexItem[] = [];\n const mainBase = this.definiteAxis(content, row ? 'width' : 'height');\n const crossBase = this.definiteAxis(content, row ? 'height' : 'width');\n const savedBase = this.percentBase;\n this.percentBase = row ? { width: mainBase, height: crossBase } : { width: crossBase, height: mainBase };\n this.forEachLayoutChild(node, child => {\n const cRec = this.record(child);\n // Margins and min/max are needed before the child is measured,\n // to size its constraints; measure() resolves them again, cheaply.\n this.resolveLayoutProps(child, cRec);\n let align = parseCrossAxisAlignment(child.properties.get(row ? 'selfY' : 'selfX')) ?? config.crossAlign;\n if (!row && align === CrossAxisAlignment.Baseline) {\n align = CrossAxisAlignment.Start;\n }\n // Stretch only sizes an item whose cross size is auto; an explicit\n // one is left alone and start-aligned, as in CSS.\n const explicitCross = this.lengthProp(child, row ? 'height' : 'width', crossBase) !== undefined;\n if (align === CrossAxisAlignment.Stretch && explicitCross) {\n align = CrossAxisAlignment.Start;\n }\n // Last, so the two fallbacks above land on the logical start and\n // are mirrored with it. Margins are not touched: they resolved to\n // physical sides already, and `crossPlacement` reads them as such.\n if (config.crossReversed) {\n align = mirrorAlignment(align);\n }\n // What this container reads from the item beyond its size: its\n // baseline when aligning by baseline, and whatever this container\n // passes on to its own parent.\n cRec.contentMatters = rec.contentMatters || align === CrossAxisAlignment.Baseline;\n this.measure(child, this.flexChildConstraints(cRec, content, direction, align, undefined, crossTightForStretch));\n const measuredMain = row ? cRec.measuredWidth : cRec.measuredHeight;\n const explicitMain = this.lengthProp(child, row ? 'width' : 'height', mainBase);\n const maxMain = row ? cRec.maxWidth : cRec.maxHeight;\n // Automatic minimum size (CSS `min-width: auto`): the smaller of\n // the specified main size and the content's min-content size, so\n // a text item never shrinks below its longest word and a column\n // never crushes an item below its content. Explicit minimums win;\n // scroll containers have none.\n let minMain: number;\n let minFromContent = false;\n if (row ? cRec.minWidthAuto : cRec.minHeightAuto) {\n // Scroll containers and text that clips (ellipsis, maxLines) do\n // not have visible overflow, so CSS gives them no automatic\n // minimum; everything else keeps its min-content size.\n // An editable is a field, not a label: it shrinks to what the\n // row gives it and its text scrolls or wraps inside.\n const clips =\n child.type === UiNodeType.ScrollView ||\n child.type === UiNodeType.EditableText ||\n child.properties.get('textOverflow') === 'ellipsis' ||\n this.numberProp(child, 'maxLines') !== undefined;\n const contentSuggestion = clips ? 0 : row ? cRec.minContentWidth : cRec.minContentHeight;\n minMain = Math.min(contentSuggestion, explicitMain ?? Infinity, maxMain);\n minFromContent = !clips && explicitMain === undefined;\n } else {\n minMain = row ? cRec.minWidth : cRec.minHeight;\n }\n const basis = this.flexBasis(child, cRec, mainBase);\n const baseMain = basis ?? measuredMain;\n // The main size is content-free when it comes from a length or an\n // explicit basis whose automatic minimum is not the content; the\n // cross size when it is a length or tight for stretching.\n const sizeFree =\n (explicitMain !== undefined || (basis !== undefined && !minFromContent)) &&\n (explicitCross || (align === CrossAxisAlignment.Stretch && crossTightForStretch)) &&\n cRec.aspectRatio === undefined &&\n !cRec.positioned;\n // Along a mirrored main axis (rtl, *-reverse) the physical start\n // margin is the logical end margin; positions are mirrored back\n // at placement, so the swap lands each margin on its own side.\n const physicalStart = row ? cRec.marginLeft : cRec.marginTop;\n const physicalEnd = row ? cRec.marginRight : cRec.marginBottom;\n const physicalStartAuto = row ? cRec.marginLeftAuto : cRec.marginTopAuto;\n const physicalEndAuto = row ? cRec.marginRightAuto : cRec.marginBottomAuto;\n // Kept on the record so explain() can say how the item flexed.\n cRec.flexMain = row ? 1 : 2;\n cRec.flexBase = baseMain;\n cRec.flexMin = minMain;\n cRec.flexMax = maxMain;\n cRec.flexMinAuto = row ? cRec.minWidthAuto : cRec.minHeightAuto;\n items.push({\n child,\n rec: cRec,\n baseMain,\n maxContentMain: measuredMain,\n hypotheticalMain: this.clamp(baseMain, minMain, maxMain),\n finalMain: baseMain,\n cross: row ? cRec.measuredHeight : cRec.measuredWidth,\n marginMainStart: config.mainReversed ? physicalEnd : physicalStart,\n marginMainEnd: config.mainReversed ? physicalStart : physicalEnd,\n marginCrossStart: row ? cRec.marginTop : cRec.marginLeft,\n marginCrossEnd: row ? cRec.marginBottom : cRec.marginRight,\n marginMainStartAuto: config.mainReversed ? physicalEndAuto : physicalStartAuto,\n marginMainEndAuto: config.mainReversed ? physicalStartAuto : physicalEndAuto,\n marginCrossStartAuto: row ? cRec.marginTopAuto : cRec.marginLeftAuto,\n marginCrossEndAuto: row ? cRec.marginBottomAuto : cRec.marginRightAuto,\n minMain,\n maxMain,\n grow: cRec.flexGrow,\n shrink: cRec.flexShrink,\n sizeFree,\n align,\n frozen: false,\n violation: 0\n });\n });\n this.percentBase = savedBase;\n return items;\n }\n\n /**\n * Decides, once a line's main sizes are final, which items are\n * relayout boundaries. An item that was shrunk below its hypothetical\n * size had its automatic minimum — its content — consulted, so its\n * content matters from now on; every boundary below it is cleared,\n * because those were decided while it did not.\n */\n private markFlexBoundaries(lines: FlexLine[]): void {\n for (const line of lines) {\n for (const item of line.items) {\n const shrunk = item.finalMain < item.hypotheticalMain - 1e-6;\n if (shrunk && !item.rec.contentMatters) {\n item.rec.contentMatters = true;\n this.clearBoundaries(item.child);\n }\n item.rec.relayoutBoundary = item.sizeFree && !shrunk && !item.rec.contentMatters;\n }\n }\n }\n\n /** `flexBasis`, resolved: a number, a percent of the main size, or undefined for content. */\n private flexBasis(child: UiNode, cRec: LayoutRecord, mainBase: number | undefined): number | undefined {\n const basis = this.lengthProp(child, 'flexBasis', mainBase);\n if (basis !== undefined) {\n return basis;\n }\n return cRec.flexBasisZero ? 0 : undefined;\n }\n\n /**\n * Constraints for measuring a flex child.\n *\n * The main axis is unbounded so the child reports its max-content\n * size — the CSS flex base for `flex-basis: auto` — unless a final\n * main size is supplied, which makes the axis tight. The cross axis\n * is bounded by the container's content box and, for a stretched\n * child of a single-line container whose cross size is definite,\n * tight.\n *\n * A zero minimum on both axes keeps a tight parent from forcing a\n * child to fill it; explicit sizes and flexing decide the box.\n */\n private flexChildConstraints(\n cRec: LayoutRecord,\n content: Constraints,\n direction: FlexDirection,\n align: CrossAxisAlignment,\n mainTight: number | undefined,\n crossTightForStretch: boolean\n ): Constraints {\n const row = direction === FlexDirection.Row;\n const marginCross = row ? cRec.marginTop + cRec.marginBottom : cRec.marginLeft + cRec.marginRight;\n const crossMaxRaw = row ? content.maxHeight : content.maxWidth;\n const crossMax = Math.max(0, crossMaxRaw - marginCross);\n const crossTight = align === CrossAxisAlignment.Stretch && crossTightForStretch;\n const mainMin = mainTight ?? 0;\n const mainMax = mainTight ?? Infinity;\n return row\n ? new Constraints(mainMin, mainMax, crossTight ? crossMax : 0, crossMax)\n : new Constraints(crossTight ? crossMax : 0, crossMax, mainMin, mainMax);\n }\n\n /**\n * Splits items into lines. Without wrapping, or with unbounded main\n * space, everything is one line; otherwise items go on a line while\n * their hypothetical outer sizes and the gaps between them fit, and\n * an item that fits nowhere starts a line of its own.\n */\n private breakLines(items: FlexItem[], config: FlexConfig, availableMain: number): FlexLine[] {\n if (!config.wrap || !isFinite(availableMain)) {\n return [{ items, cross: 0, crossStart: 0 }];\n }\n const lines: FlexLine[] = [];\n let current: FlexItem[] = [];\n let used = 0;\n for (const item of items) {\n const outer = item.hypotheticalMain + item.marginMainStart + item.marginMainEnd;\n const candidate = current.length === 0 ? outer : used + config.gapMain + outer;\n if (current.length > 0 && candidate > availableMain) {\n lines.push({ items: current, cross: 0, crossStart: 0 });\n current = [item];\n used = outer;\n } else {\n current.push(item);\n used = candidate;\n }\n }\n if (current.length > 0) {\n lines.push({ items: current, cross: 0, crossStart: 0 });\n }\n return lines;\n }\n\n /**\n * A line's main size when the container shrink-wraps it.\n *\n * The sum of the hypothetical sizes would be the answer if an item\n * never grew — but `flex: 1` is `flex-basis: 0`, and an item that\n * starts flexing from zero asks for nothing while its content still\n * wants the width of its text. A container wrapped around that sum\n * comes out too narrow; the item's text then wraps inside a box that\n * was measured as though it had not, and the container is left\n * shorter than the children it draws — a menu whose last rows fall\n * out of its own panel.\n *\n * So an item that can grow contributes whichever is larger, the size\n * its basis gives it or the size its content asks for. Chrome ignores\n * the basis entirely here and browsers disagree with each other about\n * it; the larger of the two is the reading that keeps `flex-basis`\n * counting for something, which is what `basis/sizes-container`\n * already records this engine as doing.\n */\n private lineMaxContentMain(line: FlexLine, gap: number): number {\n let total = gap * (line.items.length - 1);\n for (const item of line.items) {\n const wanted = item.grow > 0 ? this.clamp(item.maxContentMain, item.minMain, item.maxMain) : 0;\n total += Math.max(item.hypotheticalMain, wanted) + item.marginMainStart + item.marginMainEnd;\n }\n return total;\n }\n\n private lineOuterMain(line: FlexLine, gap: number, size: 'hypothetical' | 'final'): number {\n let total = gap * (line.items.length - 1);\n for (const item of line.items) {\n total += (size === 'final' ? item.finalMain : item.hypotheticalMain) + item.marginMainStart + item.marginMainEnd;\n }\n return total;\n }\n\n /**\n * Resolves the flexible lengths of one line (CSS Flexbox §9.7).\n *\n * Items with a zero factor, or already clamped against the direction\n * of flexing, are frozen at their hypothetical size. The remaining\n * free space is then distributed by factor over the unfrozen items,\n * each is clamped to its min/max, and any item whose clamp fought the\n * distribution is frozen at the clamp — repeatedly, so space an item\n * could not take is redistributed to the ones that can, instead of\n * being left over.\n *\n * Returns the free space left for alignment. Scroll containers never\n * flex: content overflows a viewport rather than compressing into it.\n */\n private resolveLine(line: FlexLine, availableMain: number, config: FlexConfig): number {\n const items = line.items;\n if (config.isScroll) {\n for (const item of items) {\n item.finalMain = item.hypotheticalMain;\n item.frozen = true;\n }\n return 0;\n }\n let margins = 0;\n let hypothetical = 0;\n for (const item of items) {\n margins += item.marginMainStart + item.marginMainEnd;\n hypothetical += item.hypotheticalMain;\n }\n const growing = availableMain - margins - hypothetical > 0;\n\n for (const item of items) {\n const factor = growing ? item.grow : item.shrink;\n item.frozen =\n factor === 0 ||\n (growing && item.baseMain > item.hypotheticalMain) ||\n (!growing && item.baseMain < item.hypotheticalMain);\n item.finalMain = item.frozen ? item.hypotheticalMain : item.baseMain;\n }\n\n for (let guard = 0; guard <= items.length; guard++) {\n let frozenTotal = 0;\n let unfrozenBase = 0;\n let factorSum = 0;\n let scaledSum = 0;\n let unfrozen = 0;\n for (const item of items) {\n if (item.frozen) {\n frozenTotal += item.finalMain;\n } else {\n unfrozen++;\n unfrozenBase += item.baseMain;\n factorSum += growing ? item.grow : item.shrink;\n scaledSum += item.shrink * item.baseMain;\n }\n }\n if (unfrozen === 0) {\n break;\n }\n let free = availableMain - margins - frozenTotal - unfrozenBase;\n // A line whose factors sum below one only takes that fraction of\n // the free space, as the spec asks.\n if (factorSum < 1) {\n free *= factorSum;\n }\n\n let totalViolation = 0;\n for (const item of items) {\n if (item.frozen) {\n continue;\n }\n let target = item.baseMain;\n if (growing && factorSum > 0) {\n target = item.baseMain + (free * item.grow) / factorSum;\n } else if (!growing && scaledSum > 0) {\n target = item.baseMain - (Math.abs(free) * item.shrink * item.baseMain) / scaledSum;\n }\n const clamped = this.clamp(Math.max(0, target), item.minMain, item.maxMain);\n item.finalMain = clamped;\n item.violation = clamped - target;\n totalViolation += item.violation;\n }\n\n for (const item of items) {\n if (item.frozen) {\n continue;\n }\n if (\n totalViolation === 0 ||\n (totalViolation > 0 && item.violation > 0) ||\n (totalViolation < 0 && item.violation < 0)\n ) {\n item.frozen = true;\n }\n }\n }\n\n let used = margins;\n for (const item of items) {\n used += item.finalMain;\n }\n return Math.max(0, availableMain - used);\n }\n\n /**\n * Second measurement pass: any item whose main size changed is\n * measured again at that size so its cross size reflects it, and a\n * stretched item learns its definite cross size. Items that did not\n * flex early-stop inside measure().\n */\n private measureFlexedItems(\n items: FlexItem[],\n content: Constraints,\n direction: FlexDirection,\n crossAvailable: number | undefined\n ): void {\n const row = direction === FlexDirection.Row;\n // The items' own percentages resolve against this container's\n // content box, as they did when the items were collected. Without\n // this the second measure of a grown item saw the base left over\n // from measuring the container itself, its parent's box, and a\n // `width: percent(100)` item in a column came out the width of the\n // grandparent.\n const mainBase = this.definiteAxis(content, row ? 'width' : 'height');\n const crossBase = this.definiteAxis(content, row ? 'height' : 'width');\n const savedBase = this.percentBase;\n this.percentBase = row ? { width: mainBase, height: crossBase } : { width: crossBase, height: mainBase };\n for (const item of items) {\n const measuredMain = row ? item.rec.measuredWidth : item.rec.measuredHeight;\n // A stretched item of a single-line container whose cross size is\n // known is measured at that size here, so the stretch pass finds\n // it measured already: two constraint sets per item, not three.\n const stretched =\n item.align === CrossAxisAlignment.Stretch &&\n crossAvailable !== undefined &&\n !item.marginCrossStartAuto &&\n !item.marginCrossEndAuto;\n if (item.finalMain === measuredMain && !stretched) {\n continue;\n }\n let constraints = this.flexChildConstraints(item.rec, content, direction, item.align, item.finalMain, false);\n if (stretched) {\n const cross = Math.max(0, crossAvailable - item.marginCrossStart - item.marginCrossEnd);\n constraints = row\n ? new Constraints(constraints.minWidth, constraints.maxWidth, cross, cross)\n : new Constraints(cross, cross, constraints.minHeight, constraints.maxHeight);\n }\n this.measure(item.child, constraints);\n item.cross = row ? item.rec.measuredHeight : item.rec.measuredWidth;\n }\n this.percentBase = savedBase;\n }\n\n /**\n * Cross size of one flex line: the tallest margin box, or for a\n * baseline-aligned row the span from the highest item top to the\n * lowest item bottom once baselines coincide.\n */\n private flexLineCross(items: FlexItem[], row: boolean): number {\n let crossMax = 0;\n let above = 0;\n let below = 0;\n for (const item of items) {\n const outer = item.cross + item.marginCrossStart + item.marginCrossEnd;\n if (row && item.align === CrossAxisAlignment.Baseline) {\n const baseline = item.marginCrossStart + this.itemBaseline(item);\n above = Math.max(above, baseline);\n below = Math.max(below, outer - baseline);\n } else {\n crossMax = Math.max(crossMax, outer);\n }\n }\n return Math.max(crossMax, above + below);\n }\n\n /**\n * An item's first baseline measured from its border-box top. A node\n * without one synthesises it from its bottom edge, as CSS does.\n */\n private itemBaseline(item: FlexItem): number {\n return item.rec.hasBaseline ? item.rec.baseline : item.cross;\n }\n\n /**\n * The container's own first baseline, from its first line: the shared\n * baseline of a baseline-aligned row, otherwise the first item's,\n * positioned as if aligned to the start edge.\n *\n * The start-edge assumption is what CSS does for the first item of a\n * column; for a row whose cross alignment is center or end it is an\n * approximation, accepted until nested baseline alignment needs it.\n */\n private setFlexBaseline(rec: LayoutRecord, items: FlexItem[], row: boolean): void {\n if (items.length === 0) {\n return;\n }\n if (row) {\n let above = 0;\n let any = false;\n for (const item of items) {\n if (item.align === CrossAxisAlignment.Baseline) {\n above = Math.max(above, item.marginCrossStart + this.itemBaseline(item));\n any = true;\n }\n }\n if (any) {\n rec.hasBaseline = true;\n rec.baseline = rec.paddingTop + above;\n return;\n }\n }\n const first = items[0];\n const marginTop = row ? first.marginCrossStart : first.marginMainStart;\n rec.hasBaseline = true;\n rec.baseline = rec.paddingTop + marginTop + this.itemBaseline(first);\n }\n\n /**\n * A flex container's min-content width: the widest item contribution\n * when items can wrap or run vertically, their sum when they must sit\n * in one row.\n */\n private flexMinContentWidth(rec: LayoutRecord, items: FlexItem[], row: boolean, config: FlexConfig): number {\n let total = 0;\n for (const item of items) {\n const contribution =\n this.minContentContribution(item.child, item.rec) + item.rec.marginLeft + item.rec.marginRight;\n total = row && !config.wrap ? total + contribution : Math.max(total, contribution);\n }\n if (row && !config.wrap) {\n total += config.gapMain * (items.length - 1);\n }\n return total + rec.paddingLeft + rec.paddingRight;\n }\n\n /** `flexMinContentWidth` for the other axis: a column sums its items, a row takes the tallest. */\n private flexMinContentHeight(rec: LayoutRecord, items: FlexItem[], row: boolean, config: FlexConfig): number {\n let total = 0;\n for (const item of items) {\n const contribution =\n this.minContentHeightContribution(item.child, item.rec) + item.rec.marginTop + item.rec.marginBottom;\n total = !row && !config.wrap ? total + contribution : Math.max(total, contribution);\n }\n if (!row && !config.wrap) {\n total += config.gapMain * (items.length - 1);\n }\n return total + rec.paddingTop + rec.paddingBottom;\n }\n\n /**\n * What a child contributes to its parent's min-content width: its\n * explicit width when it has one, else its own min-content width,\n * clamped to its min/max.\n *\n * A scroll container contributes nothing it does not ask for: its\n * content scrolls rather than widening it. An editable is the same\n * kind of box — a field whose text scrolls or wraps inside it, not a\n * label that must be shown whole — so it passes nothing up either.\n * Without that, an unwrapped field's whole line would become its\n * parent's minimum, and a row would push its siblings narrower with\n * every character typed.\n *\n * A minimum the box declares is different: the box will be at least\n * that size whatever it is given, so a parent that did not count it\n * would allocate less and lay the next sibling over the difference.\n */\n private minContentContribution(child: UiNode, cRec: LayoutRecord): number {\n if (child.type === UiNodeType.ScrollView || child.type === UiNodeType.EditableText) {\n return this.lengthProp(child, 'width', undefined) ?? cRec.minWidth;\n }\n const explicit = this.lengthProp(child, 'width', undefined);\n return this.clamp(explicit ?? cRec.minContentWidth, cRec.minWidth, cRec.maxWidth);\n }\n\n /**\n * A child's min-content height, as its parent's automatic minimum\n * counts it: the counterpart of `minContentContribution`, with the\n * same exception for a scroll container, whose content is its own\n * business and pushes on nothing outside it, and the same rule for\n * a declared minimum, which the parent must make room for.\n */\n private minContentHeightContribution(child: UiNode, cRec: LayoutRecord): number {\n if (child.type === UiNodeType.ScrollView || child.type === UiNodeType.EditableText) {\n return this.lengthProp(child, 'height', undefined) ?? cRec.minHeight;\n }\n const explicit = this.lengthProp(child, 'height', undefined);\n return this.clamp(explicit ?? cRec.minContentHeight, cRec.minHeight, cRec.maxHeight);\n }\n\n private measureStack(node: UiNode, rec: LayoutRecord, content: Constraints): Size {\n let maxWidth = 0;\n let maxHeight = 0;\n let minContent = 0;\n let minContentHeight = 0;\n let first = true;\n const savedBase = this.percentBase;\n const definiteWidth = this.definiteAxis(content, 'width');\n const definiteHeight = this.definiteAxis(content, 'height');\n this.percentBase = { width: definiteWidth, height: definiteHeight };\n const stackX = parseCrossAxisAlignment(node.properties.get('x')) ?? CrossAxisAlignment.Start;\n const stackY = parseCrossAxisAlignment(node.properties.get('y')) ?? CrossAxisAlignment.Start;\n this.forEachLayoutChild(node, child => {\n const cRec = this.record(child);\n this.resolveLayoutProps(child, cRec);\n // A stretched child of a definite stack is measured at the size\n // it will be placed in, as a stretched flex item is; the loose\n // measurement would only be repeated tight at placement.\n const explicitWidth = this.lengthProp(child, 'width', definiteWidth) !== undefined;\n const explicitHeight = this.lengthProp(child, 'height', definiteHeight) !== undefined;\n const stretchX =\n definiteWidth !== undefined &&\n this.stackAlignment(child, 'selfX', 'width', stackX) === CrossAxisAlignment.Stretch;\n const stretchY =\n definiteHeight !== undefined &&\n this.stackAlignment(child, 'selfY', 'height', stackY) === CrossAxisAlignment.Stretch;\n const availableWidth = Math.max(0, content.maxWidth - cRec.marginLeft - cRec.marginRight);\n const availableHeight = Math.max(0, content.maxHeight - cRec.marginTop - cRec.marginBottom);\n // The stack passes its first child's baseline and every child's\n // min-content on to its own parent.\n cRec.contentMatters = rec.contentMatters;\n this.measure(\n child,\n new Constraints(\n stretchX ? availableWidth : 0,\n stretchX ? availableWidth : content.maxWidth,\n stretchY ? availableHeight : 0,\n stretchY ? availableHeight : content.maxHeight\n )\n );\n cRec.relayoutBoundary =\n (explicitWidth || stretchX) &&\n (explicitHeight || stretchY) &&\n cRec.aspectRatio === undefined &&\n !cRec.positioned &&\n !cRec.contentMatters;\n maxWidth = Math.max(maxWidth, cRec.outerWidth);\n maxHeight = Math.max(maxHeight, cRec.outerHeight);\n minContent = Math.max(minContent, this.minContentContribution(child, cRec) + cRec.marginLeft + cRec.marginRight);\n minContentHeight = Math.max(\n minContentHeight,\n this.minContentHeightContribution(child, cRec) + cRec.marginTop + cRec.marginBottom\n );\n if (first) {\n first = false;\n rec.hasBaseline = true;\n rec.baseline = rec.paddingTop + cRec.marginTop + (cRec.hasBaseline ? cRec.baseline : cRec.measuredHeight);\n }\n });\n this.percentBase = savedBase;\n rec.minContentWidth = rec.paddingLeft + rec.paddingRight + minContent;\n rec.minContentHeight = rec.paddingTop + rec.paddingBottom + minContentHeight;\n return {\n width: rec.paddingLeft + rec.paddingRight + maxWidth,\n height: rec.paddingTop + rec.paddingBottom + maxHeight\n };\n }\n\n private measureScroll(node: UiNode, rec: LayoutRecord, content: Constraints): Size {\n const direction = this.scrollDirection(node);\n const vertical = direction === FlexDirection.Column;\n const gap = this.numberProp(node, 'gap') ?? 0;\n const paddingMain = vertical ? rec.paddingTop + rec.paddingBottom : rec.paddingLeft + rec.paddingRight;\n const paddingCross = vertical ? rec.paddingLeft + rec.paddingRight : rec.paddingTop + rec.paddingBottom;\n let mainTotal = 0;\n let crossMax = 0;\n let childCount = 0;\n const savedBase = this.percentBase;\n const definiteWidth = this.definiteAxis(content, 'width');\n const definiteHeight = this.definiteAxis(content, 'height');\n this.percentBase = { width: definiteWidth, height: definiteHeight };\n const crossDefinite = vertical ? definiteWidth : definiteHeight;\n const crossAlign = parseCrossAxisAlignment(node.properties.get(vertical ? 'x' : 'y')) ?? CrossAxisAlignment.Stretch;\n this.forEachLayoutChild(node, child => {\n const cRec = this.record(child);\n this.resolveLayoutProps(child, cRec);\n const explicitMain = this.lengthProp(\n child,\n vertical ? 'height' : 'width',\n vertical ? definiteHeight : definiteWidth\n );\n const explicitCross = this.lengthProp(child, vertical ? 'width' : 'height', crossDefinite) !== undefined;\n const align = parseCrossAxisAlignment(child.properties.get(vertical ? 'selfX' : 'selfY')) ?? crossAlign;\n // A stretched child of a definite scroller is measured at the\n // cross size placement gives it; placeFlex then finds it measured.\n const crossTight = crossDefinite !== undefined && align === CrossAxisAlignment.Stretch && !explicitCross;\n const childMarginCross = vertical ? cRec.marginLeft + cRec.marginRight : cRec.marginTop + cRec.marginBottom;\n const crossLimit = Math.max(0, (vertical ? content.maxWidth : content.maxHeight) - childMarginCross);\n const childBase = vertical\n ? new Constraints(crossTight ? crossLimit : 0, crossLimit, 0, Infinity)\n : new Constraints(0, Infinity, crossTight ? crossLimit : 0, crossLimit);\n // Scrollable content pushes on nothing outside the scroller.\n cRec.contentMatters = false;\n this.measure(child, childBase);\n cRec.relayoutBoundary =\n explicitMain !== undefined &&\n (explicitCross || crossTight) &&\n cRec.aspectRatio === undefined &&\n !cRec.positioned;\n const measuredMain = vertical ? cRec.measuredHeight : cRec.measuredWidth;\n const measuredCross = vertical ? cRec.measuredWidth : cRec.measuredHeight;\n const marginMain = vertical ? cRec.marginTop + cRec.marginBottom : cRec.marginLeft + cRec.marginRight;\n const marginCross = vertical ? cRec.marginLeft + cRec.marginRight : cRec.marginTop + cRec.marginBottom;\n mainTotal += measuredMain + marginMain;\n crossMax = Math.max(crossMax, measuredCross + marginCross);\n childCount++;\n });\n this.percentBase = savedBase;\n // Scrollable content does not push on the outside world.\n rec.minContentWidth = rec.paddingLeft + rec.paddingRight;\n rec.minContentHeight = rec.paddingTop + rec.paddingBottom;\n mainTotal += gap * Math.max(0, childCount - 1);\n const contentMain = mainTotal + paddingMain;\n const contentCross = crossMax + paddingCross;\n rec.contentWidth = vertical ? contentCross : contentMain;\n rec.contentHeight = vertical ? contentMain : contentCross;\n this.scrollNodes.add(node);\n\n const explicitWidth = this.lengthProp(node, 'width', savedBase.width);\n const explicitHeight = this.lengthProp(node, 'height', savedBase.height);\n const width = explicitWidth ?? (content.hasBoundedWidth() ? content.maxWidth : rec.contentWidth);\n const height = explicitHeight ?? (content.hasBoundedHeight() ? content.maxHeight : rec.contentHeight);\n return { width, height };\n }\n\n /**\n * A leaf is its content plus padding. Text content comes from the\n * paragraph layout, whose lines the renderer will draw unchanged.\n */\n private measureLeaf(node: UiNode, rec: LayoutRecord, effective: Constraints): Size {\n const paddingH = rec.paddingLeft + rec.paddingRight;\n const paddingV = rec.paddingTop + rec.paddingBottom;\n const editable = node.type === UiNodeType.EditableText;\n if (node.type === UiNodeType.Text || node.type === UiNodeType.Button || editable) {\n // An editable's text is the user's, held by its model rather than\n // a property; its placeholder sizes it while it is empty, so an\n // empty field is as wide as the hint it shows.\n // A paragraph given runs has its text in them, and the runs go\n // into the request so each is measured in its own font. The\n // request is otherwise the one it always was: the text is one\n // string either way and the algorithm above it is unchanged.\n // An editable's runs describe its model's text rather than\n // supplying it, so the text is read first and the runs are\n // accepted only if they describe that string; see\n // `editableSpansOf`.\n const typed = editable ? editorFor(node).text : '';\n const spans = editable ? editableSpansOf(node, typed) : resolvedSpansOf(node);\n const text = editable\n ? typed\n : spans.length > 0\n ? textContentOf(node)\n : String(node.properties.get('text') ?? '');\n const placeholderProp = node.properties.get('placeholder');\n const placeholder =\n editable && text.length === 0 && typeof placeholderProp === 'string' ? placeholderProp : undefined;\n // The same resolution paint uses, so the line box measured here is\n // the one the glyphs are drawn in.\n const font = resolveFont(node);\n const maxLines = editable ? undefined : this.numberProp(node, 'maxLines');\n const request = {\n text,\n fontSize: font.fontSize,\n fontFamily: font.fontFamily,\n fontWeight: font.fontWeight,\n lineHeight: font.lineHeight,\n letterSpacing: font.letterSpacing,\n fontStyle: font.fontStyle,\n fontStretch: font.fontStretch,\n fontVariant: font.fontVariant,\n fontKerning: font.fontKerning,\n maxWidth: isFinite(effective.maxWidth) ? Math.max(0, effective.maxWidth - paddingH) : undefined,\n wrap: this.textWrapProp(node),\n maxLines: maxLines !== undefined && maxLines >= 1 ? Math.floor(maxLines) : undefined,\n overflow: editable ? ('clip' as const) : this.textOverflowProp(node),\n spans: spans.length > 0 ? spans : undefined\n };\n const paragraph = this.textMeasurer.layout(request);\n let width = paragraph.width;\n let minContentWidth = paragraph.minContentWidth;\n let maxContentWidth = paragraph.maxContentWidth;\n if (placeholder !== undefined && placeholder.length > 0) {\n const hint = this.textMeasurer.layout({ ...request, text: placeholder });\n width = Math.max(width, hint.width);\n minContentWidth = Math.max(minContentWidth, hint.minContentWidth);\n maxContentWidth = Math.max(maxContentWidth, hint.maxContentWidth);\n }\n rec.hasBaseline = true;\n rec.baseline = rec.paddingTop + paragraph.firstBaseline;\n rec.minContentWidth = minContentWidth + paddingH;\n rec.maxContentWidth = maxContentWidth + paddingH;\n if (editable) {\n // The field's scrollable extent. A wrapped field's paragraph is\n // no wider than the box and only its height can overflow; an\n // unwrapped one keeps its whole line here, which is what the\n // caret scrolls along. `applyScroll` clamps the offset to it,\n // so a field that grows short again scrolls back on its own.\n rec.contentWidth = width + paddingH;\n rec.contentHeight = paragraph.height + paddingV;\n this.textScrollNodes.add(node);\n }\n return { width: width + paddingH, height: paragraph.height + paddingV };\n }\n if (node.type === UiNodeType.Paint) {\n // A painter may declare the size it wants when nothing else\n // gives the node one, which is how a sparkline in a row of text\n // gets a box without the caller restating its dimensions. It is\n // the leaf equivalent of a paragraph's measured width, and like\n // one it is only a preference: an explicit width, a flex or a\n // stretch still wins.\n const paint = node.properties.get('paint') as { intrinsicWidth?: number; intrinsicHeight?: number } | undefined;\n const intrinsicWidth = paint?.intrinsicWidth ?? 0;\n rec.minContentWidth = intrinsicWidth + paddingH;\n rec.maxContentWidth = intrinsicWidth + paddingH;\n return { width: intrinsicWidth + paddingH, height: (paint?.intrinsicHeight ?? 0) + paddingV };\n }\n rec.minContentWidth = paddingH;\n rec.maxContentWidth = paddingH;\n return { width: paddingH, height: paddingV };\n }\n\n // ---------------------------------------------------------------------------\n // Custom layout\n // ---------------------------------------------------------------------------\n\n /**\n * Runs an application's own layout over a node's children.\n *\n * The whole of the protocol's reach is `CustomLayoutRun`: it hands\n * out handles that can measure a child, place a child and read what\n * either of those returned, and it invalidates them the moment the\n * call is over. That is what stops a custom layout from breaking the\n * pass rather than a rule the protocol is asked to observe. Three\n * things in particular cannot happen:\n *\n * - **A quadratic pass.** A handle refuses a third measurement of\n * the same child in one call, so the work is at worst twice the\n * number of children however the protocol loops.\n * - **A box written outside the pass.** A handle held past the call\n * throws, so a protocol cannot stash one and place a node from a\n * timer, where nothing would have invalidated the record.\n * - **Reaching the graph.** A handle carries an index and the value\n * the element declared as `layoutData`, and nothing else. There\n * is no node on it, so a protocol cannot read another subtree's\n * geometry mid-pass or write a property that would dirty one.\n *\n * The children the protocol never measured are measured once here\n * afterwards, under the constraints the container had, so a layout\n * that only arranges fixed-size boxes need not measure at all and\n * their records are still valid.\n */\n private measureCustom(node: UiNode, rec: LayoutRecord, protocol: UiLayoutProtocol, content: Constraints): Size {\n const savedBase = this.percentBase;\n this.percentBase = { width: this.definiteAxis(content, 'width'), height: this.definiteAxis(content, 'height') };\n const run = this.customRun(node, rec, protocol, content, null);\n let size: Size;\n try {\n size = run.execute();\n } finally {\n this.percentBase = savedBase;\n }\n const paddingH = rec.paddingLeft + rec.paddingRight;\n const paddingV = rec.paddingTop + rec.paddingBottom;\n // A custom layout is free to put its children anywhere, so the\n // narrowest it can honestly claim to be is the widest child: no\n // arrangement makes a box that cannot hold its largest item.\n rec.minContentWidth = paddingH + run.widestChild;\n rec.maxContentWidth = paddingH + size.width;\n return { width: paddingH + size.width, height: paddingV + size.height };\n }\n\n /**\n * The same protocol, over a content box that is now decided, with\n * the `place` calls assigning boxes.\n *\n * Called rather than replayed because a memo hit can skip the\n * measurement entirely, so nothing may be held over from it. The\n * engine's own flex does the same: `placeFlex` collects its items\n * again rather than trusting what `measureFlex` left behind.\n */\n private placeCustom(node: UiNode, rec: LayoutRecord, protocol: UiLayoutProtocol): void {\n const contentWidth = Math.max(0, rec.width - rec.paddingLeft - rec.paddingRight);\n const contentHeight = Math.max(0, rec.height - rec.paddingTop - rec.paddingBottom);\n const content = new Constraints(contentWidth, contentWidth, contentHeight, contentHeight);\n const savedBase = this.percentBase;\n this.percentBase = { width: contentWidth, height: contentHeight };\n try {\n this.customRun(node, rec, protocol, content, {\n x: rec.x + rec.paddingLeft,\n y: rec.y + rec.paddingTop,\n width: contentWidth,\n mirrored: this.startEdge(node) === 'right'\n }).execute();\n } finally {\n this.percentBase = savedBase;\n }\n }\n\n /** Builds one run, with a handle per in-flow child in tree order. */\n private customRun(\n node: UiNode,\n rec: LayoutRecord,\n protocol: UiLayoutProtocol,\n content: Constraints,\n placement: CustomPlacement | null\n ): CustomLayoutRun {\n const run = new CustomLayoutRun(\n protocol,\n content,\n placement,\n {\n direction: this.startEdge(node) === 'right' ? 'rtl' : 'ltr',\n definiteWidth: this.definiteAxis(content, 'width'),\n definiteHeight: this.definiteAxis(content, 'height')\n },\n (child, constraints) => {\n const cRec = this.record(child);\n this.measure(child, constraints);\n return { width: cRec.measuredWidth, height: cRec.measuredHeight };\n },\n (child, x, y, size) => this.assignBox(child, x, y, size.width, size.height)\n );\n this.forEachLayoutChild(node, child => {\n const cRec = this.record(child);\n this.resolveLayoutProps(child, cRec);\n // A child of a custom layout is never a relayout boundary: the\n // protocol reads every child's size to decide the container's, so\n // a change inside one can move all the others.\n cRec.relayoutBoundary = false;\n cRec.contentMatters = rec.contentMatters;\n run.add(child, child.properties.get('layoutData'));\n });\n return run;\n }\n\n // ---------------------------------------------------------------------------\n // Placement\n // ---------------------------------------------------------------------------\n\n private place(node: UiNode): void {\n const rec = this.record(node);\n if (this.isFragment(node)) {\n // Fragments are transparent: pass placement through to children.\n rec.placeDirty = false;\n this.forEachLayoutChild(node, child => {\n if (this.record(child).placeDirty) {\n this.place(child);\n }\n });\n return;\n }\n if (!rec.placeDirty) {\n return;\n }\n this.stats.placed++;\n rec.placeDirty = false;\n if (!node.hasChildren()) {\n return;\n }\n const protocol = node.properties.get('layout');\n if (isLayoutProtocol(protocol)) {\n this.placeCustom(node, rec, protocol);\n } else if (node.type === UiNodeType.Row || node.type === UiNodeType.Column) {\n this.placeFlex(node, rec, node.type === UiNodeType.Row ? FlexDirection.Row : FlexDirection.Column);\n } else if (node.type === UiNodeType.ScrollView) {\n this.placeFlex(node, rec, this.scrollDirection(node));\n } else if (node.type === UiNodeType.Grid) {\n this.placeGrid(node, rec);\n } else {\n this.placeStack(node, rec);\n }\n // Out-of-flow children are positioned once the flow has settled,\n // against containing blocks that are already placed.\n this.placeAbsoluteChildren(node);\n this.updatePaintOrder(node, rec);\n if (rec.clips) {\n this.updateContentExtent(node, rec);\n }\n if (rec.scrollable) {\n this.scrollNodes.add(node);\n }\n this.forEachChild(node, child => {\n const cRec = this.record(child);\n if (cRec.sticky) {\n this.stickyNodes.add(child);\n } else {\n this.stickyNodes.delete(child);\n }\n if (cRec.placeDirty) {\n this.place(child);\n }\n });\n }\n\n /**\n * How far a clipping node's children reach, from its placed boxes:\n * the scrollable extent of a scroll container. A ScrollView measured\n * this already, but placement is the truth for any container.\n */\n private updateContentExtent(node: UiNode, rec: LayoutRecord): void {\n let right = rec.x + rec.paddingLeft;\n let bottom = rec.y + rec.paddingTop;\n this.forEachChild(node, child => {\n const cRec = this.record(child);\n right = Math.max(right, cRec.x + cRec.width + cRec.marginRight);\n bottom = Math.max(bottom, cRec.y + cRec.height + cRec.marginBottom);\n });\n rec.contentWidth = right - rec.x + rec.paddingRight;\n rec.contentHeight = bottom - rec.y + rec.paddingBottom;\n }\n\n /**\n * Positions the absolutely positioned children of `parent`.\n *\n * Each is measured now, against its containing block — the nearest\n * positioned ancestor, or the layout root — since it took no part in\n * the flow. With both edges of an axis set and no explicit size the\n * axis is tight; otherwise the child is its own size and one edge\n * decides where it goes, `left`/`top` winning over `right`/`bottom`.\n * A child with an `anchor` ignores its edges and is placed next to\n * the anchor instead.\n */\n private placeAbsoluteChildren(parent: UiNode): void {\n const savedBase = this.percentBase;\n this.forEachAbsoluteChild(parent, child => {\n const cRec = this.record(child);\n const block = this.containingBlockOf(child);\n this.percentBase = { width: block.width, height: block.height };\n this.resolveLayoutProps(child, cRec);\n const anchor = child.properties.get('anchor');\n if (anchor !== undefined && anchor !== null) {\n this.anchoredNodes.add(child);\n this.trackAnchor(child, anchor as UiNode);\n const anchorRec = this.records.get(anchor as UiNode);\n if (anchorRec !== undefined) {\n this.placeAnchored(child, cRec, anchorRec, anchor as UiNode, block);\n return;\n }\n } else {\n this.anchoredNodes.delete(child);\n this.trackAnchor(child, null);\n }\n\n const marginH = cRec.marginLeft + cRec.marginRight;\n const marginV = cRec.marginTop + cRec.marginBottom;\n const availableWidth = Math.max(0, block.width - (cRec.left ?? 0) - (cRec.right ?? 0) - marginH);\n const availableHeight = Math.max(0, block.height - (cRec.top ?? 0) - (cRec.bottom ?? 0) - marginV);\n const tightWidth =\n cRec.left !== undefined &&\n cRec.right !== undefined &&\n this.lengthProp(child, 'width', block.width) === undefined;\n const tightHeight =\n cRec.top !== undefined &&\n cRec.bottom !== undefined &&\n this.lengthProp(child, 'height', block.height) === undefined;\n this.measure(\n child,\n new Constraints(\n tightWidth ? availableWidth : 0,\n availableWidth,\n tightHeight ? availableHeight : 0,\n availableHeight\n )\n );\n const width = cRec.measuredWidth;\n const height = cRec.measuredHeight;\n let x: number;\n if (cRec.left !== undefined) {\n x = block.x + cRec.left + cRec.marginLeft;\n } else if (cRec.right !== undefined) {\n x = block.x + block.width - cRec.right - cRec.marginRight - width;\n } else {\n x = block.x + cRec.marginLeft;\n }\n let y: number;\n if (cRec.top !== undefined) {\n y = block.y + cRec.top + cRec.marginTop;\n } else if (cRec.bottom !== undefined) {\n y = block.y + block.height - cRec.bottom - cRec.marginBottom - height;\n } else {\n y = block.y + cRec.marginTop;\n }\n this.assignBox(child, x, y, width, height);\n });\n this.percentBase = savedBase;\n }\n\n /**\n * Places an anchored node beside its anchor.\n *\n * `placement` names a side and, after a dash, an alignment along it\n * ('bottom-start', 'right-end'; the bare side centres). The node\n * flips to the opposite side when it would overflow the containing\n * block there and the opposite side has more room, and shifts along\n * the anchor so it stays inside the block. Anchor and node may live\n * under different scroll containers, so both positions are brought\n * into the same visible space before comparing them.\n */\n private placeAnchored(\n child: UiNode,\n cRec: LayoutRecord,\n anchorRec: LayoutRecord,\n anchor: UiNode,\n block: LayoutBox\n ): void {\n this.measure(child, new Constraints(0, Math.max(0, block.width), 0, Math.max(0, block.height)));\n const width = cRec.measuredWidth;\n const height = cRec.measuredHeight;\n const gap = this.numberProp(child, 'anchorOffset') ?? 0;\n const { side, align } = this.parsePlacement(child.properties.get('placement'));\n\n // Anchor box in the child's coordinate space: where each of the two\n // is seen, which is its box less the scrolling above it and plus the\n // sticky shifts holding it, brought back into the child's own frame.\n const scrollAnchor = this.scrollOffsetOf(anchor);\n const scrollChild = this.scrollOffsetOf(child);\n const stickyAnchor = this.stickyOffsetOf(anchor);\n const stickyChild = this.stickyOffsetOf(child);\n const ax = anchorRec.x + stickyAnchor.x - scrollAnchor.x + scrollChild.x - stickyChild.x;\n const ay = anchorRec.y + stickyAnchor.y - scrollAnchor.y + scrollChild.y - stickyChild.y;\n const aw = anchorRec.width;\n const ah = anchorRec.height;\n\n const vertical = side === 'top' || side === 'bottom';\n let resolvedSide = side;\n if (vertical) {\n const roomBelow = block.y + block.height - (ay + ah + gap);\n const roomAbove = ay - gap - block.y;\n if (side === 'bottom' && height > roomBelow && roomAbove > roomBelow) {\n resolvedSide = 'top';\n } else if (side === 'top' && height > roomAbove && roomBelow > roomAbove) {\n resolvedSide = 'bottom';\n }\n } else {\n const roomRight = block.x + block.width - (ax + aw + gap);\n const roomLeft = ax - gap - block.x;\n if (side === 'right' && width > roomRight && roomLeft > roomRight) {\n resolvedSide = 'left';\n } else if (side === 'left' && width > roomLeft && roomRight > roomLeft) {\n resolvedSide = 'right';\n }\n }\n\n let x: number;\n let y: number;\n if (vertical) {\n y = resolvedSide === 'bottom' ? ay + ah + gap : ay - gap - height;\n x = align === 'start' ? ax : align === 'end' ? ax + aw - width : ax + (aw - width) / 2;\n x = this.clamp(x, block.x, Math.max(block.x, block.x + block.width - width));\n } else {\n x = resolvedSide === 'right' ? ax + aw + gap : ax - gap - width;\n y = align === 'start' ? ay : align === 'end' ? ay + ah - height : ay + (ah - height) / 2;\n y = this.clamp(y, block.y, Math.max(block.y, block.y + block.height - height));\n }\n this.assignBox(child, x, y, width, height);\n }\n\n /**\n * Records which anchor an anchored node is placed against, in both\n * directions, so a moved anchor can name its dependents. Passing\n * `null` forgets the node, which is what a child that lost its\n * `anchor` property does.\n */\n private trackAnchor(child: UiNode, anchor: UiNode | null): void {\n const previous = this.anchorOf.get(child);\n if (previous === (anchor ?? undefined)) {\n return;\n }\n if (previous !== undefined) {\n const siblings = this.anchorDependents.get(previous);\n siblings?.delete(child);\n if (siblings !== undefined && siblings.size === 0) {\n this.anchorDependents.delete(previous);\n }\n }\n if (anchor === null) {\n this.anchorOf.delete(child);\n return;\n }\n this.anchorOf.set(child, anchor);\n let dependents = this.anchorDependents.get(anchor);\n if (dependents === undefined) {\n dependents = new Set<UiNode>();\n this.anchorDependents.set(anchor, dependents);\n }\n dependents.add(child);\n }\n\n /** Drops a removed node from the anchor index, on both sides of it. */\n private forgetAnchoring(node: UiNode): void {\n this.trackAnchor(node, null);\n const dependents = this.anchorDependents.get(node);\n if (dependents === undefined) {\n return;\n }\n for (const dependent of dependents) {\n this.anchorOf.delete(dependent);\n }\n this.anchorDependents.delete(node);\n }\n\n /**\n * Re-places the anchored nodes whose anchor moved during this pass.\n * Placement is a single top-down walk, so an overlay may be reached\n * before the anchor it follows; this runs once every box is final,\n * and only over the overlays an actually moved box named. Placing one\n * can move another that is anchored to it, so the queue is drained\n * until it stays empty, up to a depth that stops a cycle.\n */\n private replaceMovedAnchored(): void {\n for (let pass = 0; this.movedAnchored.size > 0 && pass < ANCHOR_CHAIN_LIMIT; pass++) {\n const pending = [...this.movedAnchored];\n this.movedAnchored.clear();\n for (const child of pending) {\n this.replaceAnchored(child);\n }\n }\n this.movedAnchored.clear();\n }\n\n /** Places one anchored node against the box its anchor now has. */\n private replaceAnchored(child: UiNode): void {\n const cRec = this.records.get(child);\n const anchor = this.anchorOf.get(child);\n const anchorRec = anchor === undefined ? undefined : this.records.get(anchor);\n if (cRec === undefined || anchor === undefined || anchorRec === undefined) {\n return;\n }\n const savedBase = this.percentBase;\n const block = this.containingBlockOf(child);\n this.percentBase = { width: block.width, height: block.height };\n this.resolveLayoutProps(child, cRec);\n this.placeAnchored(child, cRec, anchorRec, anchor, block);\n this.percentBase = savedBase;\n // Only a node that came out somewhere new has anything to re-place\n // inside it; assignBox left the flag set if it did.\n if (cRec.placeDirty) {\n this.place(child);\n }\n }\n\n private parsePlacement(value: unknown): {\n side: 'top' | 'bottom' | 'left' | 'right';\n align: 'start' | 'center' | 'end';\n } {\n const text = typeof value === 'string' ? value : 'bottom';\n const [rawSide, rawAlign] = text.split('-');\n const side = rawSide === 'top' || rawSide === 'left' || rawSide === 'right' ? rawSide : ('bottom' as const);\n const align = rawAlign === 'start' || rawAlign === 'end' ? rawAlign : ('center' as const);\n return { side, align };\n }\n\n /**\n * Sum of the sticky shifts holding a node where it is seen: its own,\n * and every ancestor's, since a sticky node carries its whole subtree\n * with it. A tree with nothing sticky in it answers without walking.\n */\n private stickyOffsetOf(node: UiNode): { x: number; y: number } {\n let x = 0;\n let y = 0;\n if (this.stickyNodes.size === 0) {\n return { x, y };\n }\n for (let current: UiNode | null = node; current !== null; current = current.parent) {\n const rec = this.records.get(current);\n if (rec !== undefined) {\n x += rec.stickyOffsetX;\n y += rec.stickyOffsetY;\n }\n }\n return { x, y };\n }\n\n /** Sum of the scroll offsets of a node's scroll-container ancestors. */\n private scrollOffsetOf(node: UiNode): { x: number; y: number } {\n let x = 0;\n let y = 0;\n for (let current = node.parent; current !== null; current = current.parent) {\n const rec = this.records.get(current);\n if (rec !== undefined && rec.scrollable) {\n x += rec.scrollX;\n y += rec.scrollY;\n }\n }\n return { x, y };\n }\n\n /**\n * The box an absolute child is positioned against: the nearest\n * positioned ancestor's, else the layout root's.\n */\n private containingBlockOf(child: UiNode): LayoutBox {\n for (let current = child.parent; current !== null; current = current.parent) {\n if (this.isFragment(current)) {\n continue;\n }\n const rec = this.records.get(current);\n if (rec !== undefined && (rec.positioned || current === this.layoutRoot)) {\n return { x: rec.x, y: rec.y, width: rec.width, height: rec.height };\n }\n }\n const root = this.record(this.layoutRoot!);\n return { x: root.x, y: root.y, width: root.width, height: root.height };\n }\n\n /**\n * Records the children's paint order when it differs from tree order,\n * so renderers and hit testing agree on who is on top: by zIndex, and\n * within a zIndex positioned children (relative, sticky, absolute)\n * after in-flow ones — CSS's stacking rule, and what lets a sticky\n * header paint over the rows that scroll under it.\n */\n private updatePaintOrder(node: UiNode, rec: LayoutRecord): void {\n let reorder = false;\n const children: UiNode[] = [];\n this.forEachChild(node, child => {\n const cRec = this.record(child);\n children.push(child);\n if (cRec.zIndex !== 0 || cRec.positioned) {\n reorder = true;\n }\n });\n if (!reorder) {\n rec.paintOrder = null;\n return;\n }\n // Array.prototype.sort is stable: equal keys keep tree order.\n const key = (child: UiNode): number => {\n const cRec = this.record(child);\n return cRec.zIndex * 2 + (cRec.positioned ? 1 : 0);\n };\n children.sort((a, b) => key(a) - key(b));\n rec.paintOrder = children;\n }\n\n private placeFlex(node: UiNode, rec: LayoutRecord, direction: FlexDirection): void {\n const row = direction === FlexDirection.Row;\n const config = this.flexConfig(node, rec, direction);\n const paddingH = rec.paddingLeft + rec.paddingRight;\n const paddingV = rec.paddingTop + rec.paddingBottom;\n const contentX = rec.x + rec.paddingLeft;\n const contentY = rec.y + rec.paddingTop;\n const contentMain = Math.max(0, (row ? rec.width : rec.height) - (row ? paddingH : paddingV));\n const contentCross = Math.max(0, (row ? rec.height : rec.width) - (row ? paddingV : paddingH));\n // The box is final now, so children measure against it: percentages\n // resolve, and a stretched item of a single-line container is tight.\n const content = row\n ? new Constraints(contentMain, contentMain, contentCross, contentCross)\n : new Constraints(contentCross, contentCross, contentMain, contentMain);\n const items = this.collectFlexItems(node, content, direction, config, !config.wrap);\n if (items.length === 0) {\n return;\n }\n const lines = this.breakLines(items, config, contentMain);\n\n // Main axis, per line: flex, let auto margins take what is left,\n // then measure items at their final main size so cross sizes that\n // depend on it — wrapped text — are right before boxes are assigned.\n for (const line of lines) {\n line.free = this.resolveLine(line, contentMain - config.gapMain * (line.items.length - 1), config);\n this.distributeAutoMargins(line);\n this.measureFlexedItems(line.items, content, direction, config.wrap ? undefined : contentCross);\n line.cross = this.flexLineCross(line.items, row);\n }\n this.markFlexBoundaries(lines);\n\n // Cross axis. A single-line container's line is the container's\n // inner cross size; multiple lines share it by alignContent.\n if (lines.length === 1 && !config.wrap) {\n lines[0].cross = contentCross;\n } else {\n this.alignLines(lines, contentCross, config);\n }\n const crossOrigin = row ? contentY : contentX;\n let crossCursor = crossOrigin;\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n line.crossStart = crossCursor + (line.leading ?? 0);\n crossCursor = line.crossStart + line.cross + (i < lines.length - 1 ? (line.between ?? config.gapLine) : 0);\n if (config.wrapReverse) {\n // Cross-start is the far edge: mirror the line across the axis.\n line.crossStart = crossOrigin + contentCross - (line.crossStart - crossOrigin) - line.cross;\n }\n // Stretched items learn their line's cross size before placement.\n this.stretchItems(line.items, content, direction, line.cross);\n }\n\n const contentStart = row ? contentX : contentY;\n for (const line of lines) {\n let leading = 0;\n let between = config.gapMain;\n const free = line.free ?? 0;\n if (free > 0) {\n switch (config.mainAlign) {\n case MainAxisAlignment.Center:\n leading = free / 2;\n break;\n case MainAxisAlignment.End:\n leading = free;\n break;\n case MainAxisAlignment.SpaceBetween:\n if (line.items.length > 1) {\n between = config.gapMain + free / (line.items.length - 1);\n }\n break;\n case MainAxisAlignment.SpaceEvenly: {\n const slot = free / (line.items.length + 1);\n leading = slot;\n between = config.gapMain + slot;\n break;\n }\n case MainAxisAlignment.SpaceAround: {\n const slot = free / line.items.length;\n leading = slot / 2;\n between = config.gapMain + slot;\n break;\n }\n default:\n break;\n }\n }\n\n // Baseline alignment: the shared baseline sits `above` below the\n // line's cross start, where `above` is the largest distance from\n // any participating item's margin-box top to its baseline.\n let above = 0;\n if (row) {\n for (const item of line.items) {\n if (item.align === CrossAxisAlignment.Baseline) {\n above = Math.max(above, item.marginCrossStart + this.itemBaseline(item));\n }\n }\n }\n\n let mainCursor = contentStart + leading;\n for (let i = 0; i < line.items.length; i++) {\n const item = line.items[i];\n let mainPos = mainCursor + item.marginMainStart;\n if (config.mainReversed) {\n // Mirror across the main axis: flex-start becomes the far\n // edge, item order reverses, auto margins push the other way.\n mainPos = contentStart + contentMain - (mainPos - contentStart) - item.finalMain;\n }\n const { crossPos, crossDim } = this.crossPlacement(item, line, above, config.crossReversed);\n const x = row ? mainPos : crossPos;\n const y = row ? crossPos : mainPos;\n const width = row ? item.finalMain : crossDim;\n const height = row ? crossDim : item.finalMain;\n this.assignBox(item.child, x, y, width, height);\n mainCursor += item.marginMainStart + item.finalMain + item.marginMainEnd;\n if (i < line.items.length - 1) {\n mainCursor += between;\n }\n }\n }\n }\n\n /**\n * Main-axis `margin: auto` absorbs the line's free space, shared\n * equally between every auto margin, before alignment sees any.\n */\n private distributeAutoMargins(line: FlexLine): void {\n const free = line.free ?? 0;\n if (free <= 0) {\n return;\n }\n let count = 0;\n for (const item of line.items) {\n count += (item.marginMainStartAuto ? 1 : 0) + (item.marginMainEndAuto ? 1 : 0);\n }\n if (count === 0) {\n return;\n }\n const share = free / count;\n for (const item of line.items) {\n if (item.marginMainStartAuto) {\n item.marginMainStart += share;\n }\n if (item.marginMainEndAuto) {\n item.marginMainEnd += share;\n }\n }\n line.free = 0;\n }\n\n /**\n * Distributes a multi-line container's spare cross space over its\n * lines (CSS `align-content`): as leading space, between lines, or\n * by growing every line for `stretch`, the default.\n */\n private alignLines(lines: FlexLine[], contentCross: number, config: FlexConfig): void {\n let total = config.gapLine * (lines.length - 1);\n for (const line of lines) {\n total += line.cross;\n }\n const free = Math.max(0, contentCross - total);\n for (const line of lines) {\n line.leading = 0;\n line.between = undefined;\n }\n if (free === 0) {\n return;\n }\n switch (config.alignContent) {\n case AlignContent.Stretch:\n for (const line of lines) {\n line.cross += free / lines.length;\n }\n break;\n case AlignContent.Center:\n lines[0].leading = free / 2;\n break;\n case AlignContent.End:\n lines[0].leading = free;\n break;\n case AlignContent.SpaceBetween:\n if (lines.length > 1) {\n for (const line of lines) {\n line.between = config.gapLine + free / (lines.length - 1);\n }\n }\n break;\n case AlignContent.SpaceAround: {\n const slot = free / lines.length;\n lines[0].leading = slot / 2;\n for (const line of lines) {\n line.between = config.gapLine + slot;\n }\n break;\n }\n case AlignContent.SpaceEvenly: {\n const slot = free / (lines.length + 1);\n lines[0].leading = slot;\n for (const line of lines) {\n line.between = config.gapLine + slot;\n }\n break;\n }\n default:\n break;\n }\n }\n\n /** Re-measures a line's stretched items at the line's cross size. */\n private stretchItems(items: FlexItem[], content: Constraints, direction: FlexDirection, lineCross: number): void {\n const row = direction === FlexDirection.Row;\n // As in `measureFlexedItems`: the items' percentages are this\n // container's, not the base left over from measuring the container.\n const mainBase = this.definiteAxis(content, row ? 'width' : 'height');\n const crossBase = this.definiteAxis(content, row ? 'height' : 'width');\n const savedBase = this.percentBase;\n this.percentBase = row ? { width: mainBase, height: crossBase } : { width: crossBase, height: mainBase };\n for (const item of items) {\n if (item.align !== CrossAxisAlignment.Stretch || item.marginCrossStartAuto || item.marginCrossEndAuto) {\n continue;\n }\n const cross = Math.max(0, lineCross - item.marginCrossStart - item.marginCrossEnd);\n const base = this.flexChildConstraints(item.rec, content, direction, item.align, item.finalMain, false);\n const constraints = row\n ? new Constraints(base.minWidth, base.maxWidth, cross, cross)\n : new Constraints(cross, cross, base.minHeight, base.maxHeight);\n this.measure(item.child, constraints);\n // The child clamps a stretched size by its own min/max.\n item.cross = row ? item.rec.measuredHeight : item.rec.measuredWidth;\n }\n this.percentBase = savedBase;\n }\n\n /**\n * Where an item sits across its line. Cross-axis auto margins take\n * precedence: both centre the item, one pushes it to the other edge.\n */\n private crossPlacement(\n item: FlexItem,\n line: FlexLine,\n above: number,\n mirrored: boolean\n ): { crossPos: number; crossDim: number } {\n const crossStart = line.crossStart;\n const marginCross = item.marginCrossStart + item.marginCrossEnd;\n const outerCross = item.cross + marginCross;\n if (item.marginCrossStartAuto || item.marginCrossEndAuto) {\n const free = Math.max(0, line.cross - outerCross);\n const startShare = item.marginCrossStartAuto ? (item.marginCrossEndAuto ? free / 2 : free) : 0;\n return { crossPos: crossStart + item.marginCrossStart + startShare, crossDim: item.cross };\n }\n switch (item.align) {\n case CrossAxisAlignment.Stretch:\n // A stretched item usually fills the line, and then both edges\n // are the same edge. It does not when its own maximum cut it\n // short, and the leftover then sits at the cross-start, which\n // for a Column that reads right to left is the right-hand side.\n return {\n crossPos: mirrored\n ? crossStart + (line.cross - outerCross) + item.marginCrossStart\n : crossStart + item.marginCrossStart,\n crossDim: item.cross\n };\n case CrossAxisAlignment.Center:\n return { crossPos: crossStart + item.marginCrossStart + (line.cross - outerCross) / 2, crossDim: item.cross };\n case CrossAxisAlignment.End:\n return { crossPos: crossStart + (line.cross - outerCross) + item.marginCrossStart, crossDim: item.cross };\n case CrossAxisAlignment.Baseline:\n return { crossPos: crossStart + above - this.itemBaseline(item), crossDim: item.cross };\n default:\n return { crossPos: crossStart + item.marginCrossStart, crossDim: item.cross };\n }\n }\n\n /**\n * A stack lays every child over the same content box. `x` and `y`\n * on the stack align them all (start, center, end, stretch), and\n * `selfX` / `selfY` on a child override. Margins are honoured.\n */\n private placeStack(node: UiNode, rec: LayoutRecord): void {\n const contentX = rec.x + rec.paddingLeft;\n const contentY = rec.y + rec.paddingTop;\n const contentWidth = Math.max(0, rec.width - rec.paddingLeft - rec.paddingRight);\n const contentHeight = Math.max(0, rec.height - rec.paddingTop - rec.paddingBottom);\n const stackX = parseCrossAxisAlignment(node.properties.get('x')) ?? CrossAxisAlignment.Start;\n const stackY = parseCrossAxisAlignment(node.properties.get('y')) ?? CrossAxisAlignment.Start;\n const mirrored = this.startEdge(node) === 'right';\n const savedBase = this.percentBase;\n this.percentBase = { width: contentWidth, height: contentHeight };\n this.forEachLayoutChild(node, child => {\n const cRec = this.record(child);\n this.resolveLayoutProps(child, cRec);\n const alignX = this.stackAlignment(child, 'selfX', 'width', stackX, mirrored);\n const alignY = this.stackAlignment(child, 'selfY', 'height', stackY);\n const availableWidth = Math.max(0, contentWidth - cRec.marginLeft - cRec.marginRight);\n const availableHeight = Math.max(0, contentHeight - cRec.marginTop - cRec.marginBottom);\n const stretchX = alignX === CrossAxisAlignment.Stretch;\n const stretchY = alignY === CrossAxisAlignment.Stretch;\n if (stretchX || stretchY) {\n // A stretched axis is tight, so the child lays out at that size.\n const last = cRec.lastConstraints;\n this.measure(\n child,\n new Constraints(\n stretchX ? availableWidth : last.minWidth,\n stretchX ? availableWidth : last.maxWidth,\n stretchY ? availableHeight : last.minHeight,\n stretchY ? availableHeight : last.maxHeight\n )\n );\n }\n const width = cRec.measuredWidth;\n const height = cRec.measuredHeight;\n const x = contentX + cRec.marginLeft + this.stackOffset(alignX, availableWidth, width, mirrored);\n const y = contentY + cRec.marginTop + this.stackOffset(alignY, availableHeight, height);\n this.assignBox(child, x, y, width, height);\n });\n this.percentBase = savedBase;\n }\n\n private stackAlignment(\n child: UiNode,\n selfProp: string,\n sizeProp: string,\n fallback: CrossAxisAlignment,\n mirrored = false\n ): CrossAxisAlignment {\n let align = parseCrossAxisAlignment(child.properties.get(selfProp)) ?? fallback;\n if (align === CrossAxisAlignment.Baseline) {\n align = CrossAxisAlignment.Start;\n }\n // Stretch never overrides an explicit size, as in CSS.\n if (\n align === CrossAxisAlignment.Stretch &&\n this.lengthProp(child, sizeProp, sizeProp === 'width' ? this.percentBase.width : this.percentBase.height) !==\n undefined\n ) {\n align = CrossAxisAlignment.Start;\n }\n // `mirrored` is passed only for the horizontal axis of a container\n // that reads right to left, and after the two fallbacks so that a\n // value that fell back to start is mirrored with the rest.\n return mirrored ? mirrorAlignment(align) : align;\n }\n\n private stackOffset(\n align: CrossAxisAlignment,\n available: number,\n size: number,\n /** Set for the horizontal axis of a container that reads right to left. */\n mirrored = false\n ): number {\n switch (align) {\n case CrossAxisAlignment.Center:\n return (available - size) / 2;\n case CrossAxisAlignment.End:\n return available - size;\n case CrossAxisAlignment.Stretch:\n // See `crossPlacement`: stretch is only distinguishable from\n // start when the child's own maximum stopped it short of the\n // box, and what is left over is at the start edge.\n return mirrored ? available - size : 0;\n default:\n // Start, which `stackAlignment` has already swapped for End\n // when the axis is mirrored, so this is always the near edge.\n return 0;\n }\n }\n\n // ---------------------------------------------------------------------------\n // Invalidation\n // ---------------------------------------------------------------------------\n\n /**\n * Marks a node and its ancestors for re-measure and re-place, up to\n * the first relayout boundary — a node whose parent cannot be\n * affected by anything inside it — or the root. The node itself may\n * be that boundary only when `selfCanBound` says its own size is\n * not in question.\n */\n private markLayoutDirty(node: UiNode, selfCanBound = false): void {\n let current: UiNode = node;\n let bounded = false;\n for (;;) {\n // Only nodes that have been laid out have records. Fragments never\n // do — measure and place look through them to their children —\n // and must not get one here: renderers treat a record as a box\n // to cull against, and a fragment's would be empty.\n const rec = this.records.get(current);\n if (rec !== undefined) {\n rec.measureDirty = true;\n rec.placeDirty = true;\n }\n if (current === this.layoutRoot || current.parent === null) {\n if (!bounded) {\n this.relayoutRoots.add(this.layoutRoot ?? current);\n }\n return;\n }\n if (!bounded && rec?.relayoutBoundary && !rec.positioned && (current !== node || selfCanBound)) {\n this.relayoutRoots.add(current);\n /**\n * The boundary is where the *relayout* starts, and the walk\n * carries on past it marking ancestors.\n *\n * Stopping here as well is sound only while the pass really\n * does start at this boundary. It does not always: another\n * node dirtied in the same frame can drag the layout root\n * into `relayoutRoots`, and then the pass is a `fullLayout`\n * that measures from the root — down through ancestors this\n * walk left clean, every one of which short-circuits on its\n * own measure memo and never reaches the node that changed.\n *\n * Found with a bar switched into the chrome by choosing a\n * menu item: the menu's own teardown put the root in the set,\n * the frame did a full layout, and `measure` was never called\n * on the column that had gained a child. It drew at zero\n * height, with every spec passing — a spec asks what a node's\n * properties are, and they were all correct.\n *\n * Marking to the root costs a walk of the depth and two\n * booleans a node, against a memo that is otherwise believed\n * when it should not be.\n */\n bounded = true;\n }\n current = current.parent;\n }\n }\n\n private applyScroll(): void {\n for (const node of this.scrollNodes) {\n this.applyScrollOffset(node, false);\n }\n // A field has no scrollbars, so nothing lingers after it scrolls;\n // it does keep room for the caret past the end of its text.\n for (const node of this.textScrollNodes) {\n this.applyScrollOffset(node, true);\n }\n this.applySticky();\n }\n\n /**\n * Brings a record's scroll offset up to date with its `scrollX` and\n * `scrollY` properties, clamped to what there is to scroll. This runs\n * every pass, so an offset written against a larger content — a field\n * whose text has since been deleted, a list that lost rows — comes\n * back into range on its own.\n *\n * A field that scrolls may go one caret width further than its text,\n * so that a caret at the very end is inside the box and not on its\n * edge, where the clip would take it. A field wide enough for its\n * text does not: the allowance would shift the line by a pixel the\n * moment the caret reached the end.\n */\n private applyScrollOffset(node: UiNode, field: boolean): void {\n const rec = this.record(node);\n const rawX = this.numberProp(node, 'scrollX') ?? 0;\n const rawY = this.numberProp(node, 'scrollY') ?? 0;\n const caret = field ? CARET_WIDTH : 0;\n const overflowX = rec.contentWidth - rec.width;\n const overflowY = rec.contentHeight - rec.height;\n const maxX = overflowX > 0 ? overflowX + caret : 0;\n const maxY = overflowY > 0 ? overflowY + caret : 0;\n const scrollX = this.clamp(rawX, 0, maxX);\n const scrollY = this.clamp(rawY, 0, maxY);\n if (scrollX !== rec.scrollX || scrollY !== rec.scrollY) {\n rec.scrollX = scrollX;\n rec.scrollY = scrollY;\n if (!field) {\n // Overlay scrollbars show while the user scrolls and linger a\n // moment after; the host repaints when they fade.\n rec.scrollbarVisibleUntil = this.now() + SCROLLBAR_LINGER_MS;\n }\n }\n rec.transformDirty = false;\n }\n\n /**\n * Holds each sticky node at its scroll container's edge.\n *\n * A sticky node keeps its flow position until scrolling would carry\n * it past the edge named by top/right/bottom/left (CSS: the inset is\n * measured from the scrollport); it is then shifted just enough to\n * stay there, but never beyond its parent's box — when the parent\n * scrolls away, the node goes with it. For a node whose parent is the\n * scroll container itself, the parent's box is the scrollable extent.\n */\n private applySticky(): void {\n this.stickyShifted.clear();\n for (const node of this.stickyNodes) {\n const rec = this.records.get(node);\n if (rec === undefined) {\n continue;\n }\n const wasX = rec.stickyOffsetX;\n const wasY = rec.stickyOffsetY;\n this.resolveStickyOffset(node, rec);\n if (rec.stickyOffsetX !== wasX || rec.stickyOffsetY !== wasY) {\n this.stickyShifted.add(node);\n }\n }\n if (this.stickyShifted.size > 0) {\n // A shift moves a node, and everything under it, without moving\n // a box, so nothing else here would tell the subtree bounds that\n // the tree they summarise has changed shape.\n this.layoutVersion++;\n if (this.anchorOf.size > 0) {\n this.followStickyShifts();\n }\n }\n }\n\n /**\n * The shift for one sticky node, written onto its record. Zero is the\n * answer for a node with nothing to stick inside, or with no inset to\n * hold it at an edge.\n */\n private resolveStickyOffset(node: UiNode, rec: LayoutRecord): void {\n rec.stickyOffsetX = 0;\n rec.stickyOffsetY = 0;\n const scroller = this.scrollAncestorOf(node);\n const parent = this.flowParentOf(node);\n if (scroller === null || parent === null) {\n return;\n }\n const sRec = this.record(scroller);\n const pRec = this.record(parent);\n const parentIsScroller = parent === scroller;\n // Bounds the node may move within: its parent's content box, in\n // the same pre-scroll frame as the node's record.\n const boundTop = pRec.y + pRec.paddingTop;\n const boundLeft = pRec.x + pRec.paddingLeft;\n const boundBottom = parentIsScroller\n ? pRec.y + pRec.contentHeight - pRec.paddingBottom\n : pRec.y + pRec.height - pRec.paddingBottom;\n const boundRight = parentIsScroller\n ? pRec.x + pRec.contentWidth - pRec.paddingRight\n : pRec.x + pRec.width - pRec.paddingRight;\n // The scrollport's edges in that frame.\n const viewTop = sRec.y + sRec.scrollY + (parentIsScroller ? 0 : 0);\n const viewLeft = sRec.x + sRec.scrollX;\n const viewBottom = viewTop + sRec.height;\n const viewRight = viewLeft + sRec.width;\n\n if (rec.top !== undefined) {\n const wanted = viewTop + rec.top - rec.y;\n const limit = boundBottom - rec.height - rec.y;\n rec.stickyOffsetY = this.clamp(wanted, 0, Math.max(0, limit));\n } else if (rec.bottom !== undefined) {\n const wanted = viewBottom - rec.bottom - rec.height - rec.y;\n const limit = boundTop - rec.y;\n rec.stickyOffsetY = this.clamp(wanted, Math.min(0, limit), 0);\n }\n if (rec.left !== undefined) {\n const wanted = viewLeft + rec.left - rec.x;\n const limit = boundRight - rec.width - rec.x;\n rec.stickyOffsetX = this.clamp(wanted, 0, Math.max(0, limit));\n } else if (rec.right !== undefined) {\n const wanted = viewRight - rec.right - rec.width - rec.x;\n const limit = boundLeft - rec.x;\n rec.stickyOffsetX = this.clamp(wanted, Math.min(0, limit), 0);\n }\n }\n\n /**\n * Queues the overlays a sticky shift moved. A sticky node carries its\n * whole subtree, so an overlay anchored to the node, or to anything\n * inside it, is now beside where its anchor used to be, and one that\n * lives inside a shifted node has been carried away from an anchor\n * that has not moved. Both are placed again once the pass settles.\n *\n * The question is asked of the anchored nodes, of which a screen has\n * a handful, rather than of the shifted subtrees, which are as large\n * as a header's contents; and only on a pass where a shift changed.\n */\n private followStickyShifts(): void {\n for (const [child, anchor] of this.anchorOf) {\n if (this.carriedBySticky(anchor) || this.carriedBySticky(child)) {\n this.movedAnchored.add(child);\n }\n }\n }\n\n /** Whether a sticky node that shifted this pass is carrying `node`. */\n private carriedBySticky(node: UiNode): boolean {\n for (let current: UiNode | null = node; current !== null; current = current.parent) {\n if (this.stickyShifted.has(current)) {\n return true;\n }\n }\n return false;\n }\n\n private scrollAncestorOf(node: UiNode): UiNode | null {\n for (let current = node.parent; current !== null; current = current.parent) {\n const rec = this.records.get(current);\n if (rec !== undefined && rec.scrollable) {\n return current;\n }\n }\n return null;\n }\n\n /** The nearest non-fragment ancestor. */\n private flowParentOf(node: UiNode): UiNode | null {\n for (let current = node.parent; current !== null; current = current.parent) {\n if (!this.isFragment(current)) {\n return current;\n }\n }\n return null;\n }\n\n private now(): number {\n return typeof performance !== 'undefined' ? performance.now() : Date.now();\n }\n\n // ---------------------------------------------------------------------------\n // Helpers\n // ---------------------------------------------------------------------------\n\n private record(node: UiNode): LayoutRecord {\n let rec = this.records.get(node);\n if (rec === undefined) {\n // A full pass in progress has the previous pass's records here;\n // outside one the map is empty and this is a miss on nothing.\n rec = this.retiredRecords.get(node);\n if (rec === undefined) {\n rec = new LayoutRecord(node);\n } else {\n // Left where it is rather than deleted: the record is in the\n // live map from here on, so nothing looks for it here again,\n // and the whole map is dropped when the pass ends. Five\n // thousand deletes a pass is not a cost worth paying for\n // tidiness the caller cannot see.\n rec.reset();\n }\n this.records.set(node, rec);\n }\n return rec;\n }\n\n private computeRootBox(): Size {\n const rec = this.record(this.layoutRoot!);\n const constraints = this.rootConstraints;\n let width = rec.measuredWidth;\n let height = rec.measuredHeight;\n // A root without an explicit size fills the bounded constraints\n // (app-viewport behavior); an explicit size wins instead.\n const explicitWidth = this.lengthProp(this.layoutRoot!, 'width', this.rootPercentBase(constraints).width);\n const explicitHeight = this.lengthProp(this.layoutRoot!, 'height', this.rootPercentBase(constraints).height);\n if (explicitWidth === undefined && constraints.hasBoundedWidth()) {\n width = constraints.maxWidth;\n }\n if (explicitHeight === undefined && constraints.hasBoundedHeight()) {\n height = constraints.maxHeight;\n }\n width = Math.max(width, constraints.minWidth);\n height = Math.max(height, constraints.minHeight);\n return { width, height };\n }\n\n /**\n * Folds the node's layout properties onto its record: sizes, minima\n * and maxima, padding, margins, positioning, the insets, and the\n * flags the walks read off the record rather than off the property\n * map.\n *\n * Ten places call this, because a node is measured by one container\n * and then placed by another and each wants the record current\n * before it reads it. On a list of five thousand nodes that came to\n * five full re-resolutions per node per pass, each one about thirty\n * property lookups with a length resolution on most of them, which\n * was a tenth of the time a full pass took and a good deal of the\n * garbage it made. So the result is memoized, but only for the\n * duration of one pass.\n *\n * Only for one pass, deliberately. A cache that outlived a pass\n * would have to be invalidated whenever any layout property changed,\n * and would be silently wrong the first time some path wrote a\n * property without marking the node layout-dirty. Within a pass the\n * question does not arise: nothing writes node properties while a\n * pass is running, so the second through fifth resolutions provably\n * produce exactly what the first one did, and the memo cannot be\n * stale because there is nothing to go stale against. The stamp is\n * thrown away between frames on purpose; it is not a bug that the\n * work is done again next frame.\n *\n * The percentage base is part of the key rather than assumed\n * constant, because it is not. The engine reassigns `percentBase` as\n * it descends, and on the benchmark list two fifths of the nodes\n * (the text inside each row's column) are first resolved while their\n * container's content width is still unknown and again once it is\n * known, against a base of `undefined` and then of a number. Those\n * must resolve twice or a percentage would keep the answer it got\n * when there was nothing to be a percentage of.\n *\n * `setLifted` is the one thing here that writes engine state rather\n * than record state, and skipping it on a repeat call is safe for\n * the same reason the rest is: `lift` cannot change mid-pass, so the\n * first call already put the node in or out of `liftedNodes` and a\n * later call would find `rec.lifted` equal and return.\n */\n private resolveLayoutProps(node: UiNode, rec: LayoutRecord): void {\n const props = node.properties;\n const base = this.percentBase;\n if (rec.propsPass === this.layoutPass && rec.propsBaseWidth === base.width && rec.propsBaseHeight === base.height) {\n return;\n }\n rec.propsPass = this.layoutPass;\n rec.propsBaseWidth = base.width;\n rec.propsBaseHeight = base.height;\n // `flex: n` is CSS's shorthand for grow n, shrink 1, basis 0.\n const flex = this.numberProp(node, 'flex');\n rec.flexGrow = this.numberProp(node, 'flexGrow') ?? flex ?? 0;\n rec.flexShrink = this.numberProp(node, 'flexShrink') ?? 1;\n rec.flexBasisZero = flex !== undefined && props.get('flexBasis') === undefined;\n const minWidth = this.lengthPropOrAuto(node, 'minWidth', base.width);\n const minHeight = this.lengthPropOrAuto(node, 'minHeight', base.height);\n rec.minWidthAuto = typeof minWidth !== 'number';\n rec.minHeightAuto = typeof minHeight !== 'number';\n rec.minWidth = typeof minWidth === 'number' ? minWidth : 0;\n rec.minHeight = typeof minHeight === 'number' ? minHeight : 0;\n rec.maxWidth = this.lengthProp(node, 'maxWidth', base.width) ?? Infinity;\n rec.maxHeight = this.lengthProp(node, 'maxHeight', base.height) ?? Infinity;\n // Which physical edge the logical pair names. Resolved only when\n // one of the four is present, because it means reading an\n // inherited property and the overwhelming majority of nodes name\n // none of them; four misses on a Map is what the check costs, the\n // same price `paddingX` added to each side.\n const leftIsStart = !hasLogicalSpacing(props) || this.startEdge(node) === 'left';\n rec.paddingLeft = this.spacingProp(props, 'paddingLeft', leftIsStart ? 'paddingStart' : 'paddingEnd', 'paddingX');\n rec.paddingRight = this.spacingProp(props, 'paddingRight', leftIsStart ? 'paddingEnd' : 'paddingStart', 'paddingX');\n rec.paddingTop = this.spacingProp(props, 'paddingTop', undefined, 'paddingY');\n rec.paddingBottom = this.spacingProp(props, 'paddingBottom', undefined, 'paddingY');\n const marginLeft = this.marginProp(props, 'marginLeft', leftIsStart ? 'marginStart' : 'marginEnd', 'marginX');\n const marginRight = this.marginProp(props, 'marginRight', leftIsStart ? 'marginEnd' : 'marginStart', 'marginX');\n const marginTop = this.marginProp(props, 'marginTop', undefined, 'marginY');\n const marginBottom = this.marginProp(props, 'marginBottom', undefined, 'marginY');\n rec.marginLeftAuto = marginLeft === 'auto';\n rec.marginRightAuto = marginRight === 'auto';\n rec.marginTopAuto = marginTop === 'auto';\n rec.marginBottomAuto = marginBottom === 'auto';\n rec.marginLeft = typeof marginLeft === 'number' ? marginLeft : 0;\n rec.marginRight = typeof marginRight === 'number' ? marginRight : 0;\n rec.marginTop = typeof marginTop === 'number' ? marginTop : 0;\n rec.marginBottom = typeof marginBottom === 'number' ? marginBottom : 0;\n const position = props.get('position');\n rec.absolute = position === 'absolute';\n rec.sticky = position === 'sticky';\n rec.positioned = rec.absolute || rec.sticky || position === 'relative';\n const overflow = props.get('overflow');\n rec.scrollable = node.type === UiNodeType.ScrollView || overflow === 'scroll' || overflow === 'auto';\n // Only a scroll container asks, and there are few of them, so this\n // resolution is not on the path every box takes.\n rec.mirrored = rec.scrollable && this.startEdge(node) === 'right';\n // An editable clips like a form control: its box is a window on the\n // text, which scrolls behind it (see `measureLeaf`). Without this a\n // field narrower than its line would paint the overflow across\n // whatever sits beside it.\n rec.clips = rec.scrollable || overflow === 'hidden' || node.type === UiNodeType.EditableText;\n const insetH = this.lengthProp(node, 'inset', base.width);\n const insetV = this.lengthProp(node, 'inset', base.height);\n rec.top = this.lengthProp(node, 'top', base.height) ?? insetV;\n rec.right = this.lengthProp(node, 'right', base.width) ?? insetH;\n rec.bottom = this.lengthProp(node, 'bottom', base.height) ?? insetV;\n rec.left = this.lengthProp(node, 'left', base.width) ?? insetH;\n rec.zIndex = this.numberProp(node, 'zIndex') ?? 0;\n this.setLifted(node, rec, node.properties.get('lift') === true);\n rec.liftBoundary = node.properties.get('liftBoundary') === true;\n const ratio = this.numberProp(node, 'aspectRatio');\n rec.aspectRatio = ratio !== undefined && ratio > 0 ? ratio : undefined;\n }\n\n /**\n * Sizes with a fixed width:height ratio (CSS `aspect-ratio`). The\n * axis the parent or an explicit size decided drives the other; when\n * neither is decided the content's width does.\n */\n private applyAspectRatio(size: Size, ratio: number, effective: Constraints): Size {\n const tightWidth = effective.minWidth === effective.maxWidth;\n const tightHeight = effective.minHeight === effective.maxHeight;\n if (tightWidth && !tightHeight) {\n return { width: size.width, height: effective.minWidth / ratio };\n }\n if (tightHeight && !tightWidth) {\n return { width: effective.minHeight * ratio, height: size.height };\n }\n if (!tightWidth && !tightHeight) {\n if (size.width > 0) {\n return { width: size.width, height: size.width / ratio };\n }\n if (size.height > 0) {\n return { width: size.height * ratio, height: size.height };\n }\n }\n return size;\n }\n\n /** The percentage base for a root: the viewport where it is bounded. */\n private rootPercentBase(constraints: Constraints): { width: number | undefined; height: number | undefined } {\n return {\n width: constraints.hasBoundedWidth() ? constraints.maxWidth : undefined,\n height: constraints.hasBoundedHeight() ? constraints.maxHeight : undefined\n };\n }\n\n /** A content-box axis that is definite (tight), else undefined. */\n private definiteAxis(content: Constraints, axis: 'width' | 'height'): number | undefined {\n if (axis === 'width') {\n return isFinite(content.maxWidth) && content.minWidth === content.maxWidth ? content.maxWidth : undefined;\n }\n return isFinite(content.maxHeight) && content.minHeight === content.maxHeight ? content.maxHeight : undefined;\n }\n\n /**\n * The constraints a node sizes itself under: the parent's, combined\n * with its own size properties.\n *\n * Per axis: a tight parent constraint is authoritative and the node's\n * own properties are ignored (the parent has flexed or stretched it).\n * Otherwise an explicit size, clamped by the node's own min/max,\n * makes the axis tight even when it exceeds the parent's bound — the\n * node overflows rather than being squeezed. Without an explicit\n * size the bounds intersect, and the parent's max is the available\n * space content lays out against.\n *\n * `rec` is the node's record when its properties have just been\n * folded onto it against the same percentage base, and undefined\n * when they have not. It is only an optimisation: the four minimums\n * and maximums this needs are the four `resolveLayoutProps` has\n * already resolved from the same properties against the same base\n * (`minWidth` resolves through `lengthPropOrAuto`, whose `'auto'`\n * lands on the record as zero exactly as `?? 0` does here), so\n * passing the record turns six length resolutions per measured node\n * into two. A pass over the benchmark list did 173,018 of them and\n * 66,006 were these four.\n *\n * The one caller that passes undefined is `explain`, which reads a\n * record it did not resolve, under a percentage base it worked out\n * for itself; it asks the properties instead rather than trusting\n * that the two bases agree.\n */\n private effectiveConstraints(node: UiNode, constraints: Constraints, rec: LayoutRecord | undefined): Constraints {\n const base = this.percentBase;\n this.axisConstraints(\n constraints.minWidth,\n constraints.maxWidth,\n this.lengthProp(node, 'width', base.width),\n rec !== undefined ? rec.minWidth : (this.lengthProp(node, 'minWidth', base.width) ?? 0),\n rec !== undefined ? rec.maxWidth : (this.lengthProp(node, 'maxWidth', base.width) ?? Infinity)\n );\n const minWidth = this.axisMin;\n const maxWidth = this.axisMax;\n this.axisConstraints(\n constraints.minHeight,\n constraints.maxHeight,\n this.lengthProp(node, 'height', base.height),\n rec !== undefined ? rec.minHeight : (this.lengthProp(node, 'minHeight', base.height) ?? 0),\n rec !== undefined ? rec.maxHeight : (this.lengthProp(node, 'maxHeight', base.height) ?? Infinity)\n );\n return new Constraints(minWidth, maxWidth, this.axisMin, this.axisMax);\n }\n\n /**\n * The lower and upper bound `axisConstraints` last worked out.\n *\n * It returned them as a two-element tuple, which allocated an array\n * per axis per measured node, 22,002 of them in a pass over the\n * benchmark list. Two fields cannot be misread across a nested call\n * because there is no nested call: `axisConstraints` is arithmetic\n * over its arguments and reaches nothing that could measure anything,\n * so the only code that runs between writing these and reading them\n * is the read itself.\n */\n private axisMin = 0;\n private axisMax = 0;\n\n private axisConstraints(\n parentMin: number,\n parentMax: number,\n own: number | undefined,\n ownMin: number,\n ownMax: number\n ): void {\n const min = Math.max(0, ownMin);\n // Like CSS, a min bound wins over a conflicting max bound.\n const max = Math.max(min, ownMax);\n if (parentMin === parentMax) {\n // A stretched or flexed size is still clamped by the node's own\n // min/max, as CSS clamps a stretched cross size.\n const size = this.clamp(parentMin, min, max);\n this.axisMin = size;\n this.axisMax = size;\n return;\n }\n if (own !== undefined) {\n const size = this.clamp(own, min, max);\n this.axisMin = size;\n this.axisMax = size;\n return;\n }\n const lower = Math.max(parentMin, min);\n this.axisMin = lower;\n this.axisMax = Math.max(lower, Math.min(parentMax, max));\n }\n\n /**\n * Constraints for measuring a child of a stack or scroll container:\n * the container's available space with a zero minimum, so a tight\n * parent never forces a child to fill it. The child applies its own\n * size properties itself, in measure().\n */\n private assignBox(node: UiNode, x: number, y: number, width: number, height: number): void {\n const rec = this.record(node);\n if (rec.positioned && !rec.absolute && !rec.sticky && node !== this.layoutRoot) {\n // A relative node keeps its place in the flow and is drawn offset.\n x += rec.left ?? (rec.right !== undefined ? -rec.right : 0);\n y += rec.top ?? (rec.bottom !== undefined ? -rec.bottom : 0);\n }\n /**\n * A **sticky** node is not offset by its insets, and that is the\n * difference between the two.\n *\n * `top: 0` on a sticky header is a threshold — \"do not let me go\n * above the top of the scrollport\" — and not a displacement, which\n * is what CSS means by it and what `resolveStickyOffset` below\n * assumes when it computes `viewLeft + rec.left - rec.x`. Offset\n * here *and* used as a threshold there, an inset is applied twice\n * and the two errors cancel only when it is zero.\n *\n * Which is why nothing noticed: every sticky node in the framework\n * and its examples sticks at zero. The first one that did not — a\n * spreadsheet's second frozen column, which sticks at the width of\n * the gutter — was drawn one gutter too far to the right.\n */\n if (rec.x !== x || rec.y !== y || rec.width !== width || rec.height !== height) {\n rec.x = x;\n rec.y = y;\n rec.width = width;\n rec.height = height;\n rec.placeDirty = true;\n // Subtree bounds are a summary of these four numbers, so this is\n // the one place that can promise they are never stale: a box\n // written after a pass has ended, by an overlay following the\n // anchor it hangs off, invalidates them just as one written\n // inside the pass does.\n this.layoutVersion++;\n // Anything anchored to this node was placed against the box it\n // had a moment ago and has to be placed again. A box that did not\n // move asks nothing, and a tree with no anchored node at all does\n // not even look.\n if (this.anchorDependents.size > 0) {\n const dependents = this.anchorDependents.get(node);\n if (dependents !== undefined) {\n for (const dependent of dependents) {\n this.movedAnchored.add(dependent);\n }\n }\n }\n }\n }\n\n private scrollDirection(node: UiNode): FlexDirection {\n return parseFlexDirection(node.properties.get('direction')) ?? FlexDirection.Column;\n }\n\n /**\n * Iterates over a node's in-flow children, transparently expanding\n * Fragment anchors so their children participate in layout as if\n * they were direct children of the parent. Absolutely positioned\n * children are skipped: they take no space and are placed separately.\n *\n * The two questions are asked inline here and in the two iterators\n * below rather than through named predicates, which read better. A\n * pass over the benchmark list asked the pair 80,002 times, 48,000\n * of them from these three loops, and the profile put the two at\n * 5.4% of the pass between them. The callback differs at every call\n * site, so nothing about this loop is inlined into anything, and a\n * predicate call per child per iterator is a real fraction of a walk\n * that does very little else. The absolute test had no caller\n * outside these loops and is gone; `isFragment` stayed, because\n * everywhere else it is asked once for a node rather than once per\n * sibling.\n */\n private forEachLayoutChild(node: UiNode, callback: (child: UiNode) => void): void {\n for (let child = node.firstChild; child !== null; child = child.nextSibling) {\n if (child.type === UiNodeType.Fragment) {\n this.forEachLayoutChild(child, callback);\n } else if (child.properties.get('position') !== 'absolute') {\n callback(child);\n }\n }\n }\n\n /** The absolutely positioned children, fragments expanded. */\n private forEachAbsoluteChild(node: UiNode, callback: (child: UiNode) => void): void {\n for (let child = node.firstChild; child !== null; child = child.nextSibling) {\n if (child.type === UiNodeType.Fragment) {\n this.forEachAbsoluteChild(child, callback);\n } else if (child.properties.get('position') === 'absolute') {\n callback(child);\n }\n }\n }\n\n /** Every child, in flow or not, fragments expanded, in tree order. */\n private forEachChild(node: UiNode, callback: (child: UiNode) => void): void {\n for (let child = node.firstChild; child !== null; child = child.nextSibling) {\n if (child.type === UiNodeType.Fragment) {\n this.forEachChild(child, callback);\n } else {\n callback(child);\n }\n }\n }\n\n private isFragment(node: UiNode): boolean {\n return node.type === UiNodeType.Fragment;\n }\n\n /**\n * Records whether a node is lifted, keeping the index in step.\n *\n * The set is the index and the record field is the answer to \"is\n * this one lifted\", because the renderers ask that of every node\n * they walk and a set lookup per node per frame is a cost the walk\n * does not need to pay.\n */\n private setLifted(node: UiNode, rec: LayoutRecord, lifted: boolean): void {\n if (rec.lifted === lifted) {\n return;\n }\n rec.lifted = lifted;\n if (lifted) {\n this.liftedNodes.add(node);\n } else {\n this.liftedNodes.delete(node);\n }\n }\n\n /**\n * The nodes painted in the top layer, in the order they were lifted.\n *\n * Hit testing tries them last-first, so the most recently lifted\n * wins a point two of them cover. Two lifted elements overlapping at\n * all is already unusual: this exists so a morph can escape a clip,\n * and one thing morphs at a time.\n */\n get lifted(): ReadonlySet<UiNode> {\n return this.liftedNodes;\n }\n\n private numberProp(node: UiNode, property: string): number | undefined {\n const value = node.properties.get(property);\n if (typeof value === 'number' && Number.isFinite(value)) {\n return value;\n }\n return undefined;\n }\n\n /**\n * A length property in pixels; percentages resolve against `base`.\n *\n * The two cases answered here rather than in `resolveLength` are the\n * two a tree is almost entirely made of: a property nobody set, and\n * a plain number of pixels. A pass over the benchmark list asks this\n * 129,014 times and never once reaches a percentage or an `auto`,\n * because an application writes its sizes as numbers and only\n * reaches for a tagged length where it means one. So the call, its\n * default argument and its chain of type tests were most of what\n * every resolution cost. Anything that is not a finite number still\n * goes to `resolveLength`, which is where the rules and the errors\n * live.\n */\n private lengthProp(node: UiNode, property: string, base: number | undefined): number | undefined {\n const raw = node.properties.get(property);\n if (raw === undefined) {\n return undefined;\n }\n if (typeof raw === 'number' && Number.isFinite(raw)) {\n return raw;\n }\n const value = resolveLength(raw, base, property);\n return value === 'auto' ? undefined : value;\n }\n\n private lengthPropOrAuto(node: UiNode, property: string, base: number | undefined): number | undefined | 'auto' {\n const raw = node.properties.get(property);\n if (raw === undefined) {\n return undefined;\n }\n if (typeof raw === 'number' && Number.isFinite(raw)) {\n return raw;\n }\n return resolveLength(raw, base, property, true);\n }\n\n /**\n * A margin side: the side's own value, else the logical side that\n * resolved to it, else its axis, else the shorthand; may be auto.\n */\n private marginProp(\n props: ReadonlyMap<string, unknown>,\n side: string,\n logical: string | undefined,\n axis: string\n ): number | 'auto' {\n const value =\n props.get(side) ??\n (logical !== undefined ? props.get(logical) : undefined) ??\n props.get(axis) ??\n props.get('margin');\n if (value === undefined) {\n return 0;\n }\n if (typeof value === 'number' && Number.isFinite(value)) {\n return value;\n }\n return resolveLength(value, undefined, side, true) ?? 0;\n }\n\n private textWrapProp(node: UiNode): TextWrap | undefined {\n const value = node.properties.get('textWrap');\n if (value === 'none' || value === 'nowrap') {\n return 'none';\n }\n if (value === 'char' || value === 'word') {\n return value;\n }\n return undefined;\n }\n\n private textOverflowProp(node: UiNode): TextOverflow | undefined {\n const value = node.properties.get('textOverflow');\n return value === 'ellipsis' ? 'ellipsis' : undefined;\n }\n\n /**\n * A padding side: the side's own value, else the logical side that\n * resolved to it, else its axis, else the shorthand.\n *\n * Four steps rather than the two it began with: `paddingX` added\n * one and `paddingStart` added another. Most specific wins, as in\n * CSS, so `padding={8} paddingX={16} paddingLeft={0}` is 0 left, 16\n * right, 8 top and bottom, and a physical side beats the logical one\n * that landed on the same edge. `props.get` on a name nothing wrote\n * costs a miss on a Map, and the horizontal sides are the only ones\n * that pay for the logical step at all.\n */\n private spacingProp(\n props: ReadonlyMap<string, unknown>,\n side: string,\n logical: string | undefined,\n axis: string\n ): number {\n const explicit = props.get(side);\n if (explicit !== undefined) {\n return this.toNumber(explicit) ?? 0;\n }\n if (logical !== undefined) {\n const onEdge = props.get(logical);\n if (onEdge !== undefined) {\n return this.toNumber(onEdge) ?? 0;\n }\n }\n const onAxis = props.get(axis);\n if (onAxis !== undefined) {\n return this.toNumber(onAxis) ?? 0;\n }\n const shorthand = props.get('padding');\n if (shorthand !== undefined) {\n return this.toNumber(shorthand) ?? 0;\n }\n return 0;\n }\n\n /**\n * Which physical edge `start` means for a node: the left, unless it\n * reads right to left.\n *\n * `textDirection` is inherited, so a subtree under one `rtl` mirrors\n * without every box in it repeating the fact. That is the same\n * property a Row's main axis already reverses on, which is what\n * makes the mirroring one decision rather than two that can\n * disagree.\n */\n private startEdge(node: UiNode): 'left' | 'right' {\n return resolveString(node, 'textDirection') === 'rtl' ? 'right' : 'left';\n }\n\n private toNumber(value: unknown): number | undefined {\n if (typeof value === 'number' && Number.isFinite(value)) {\n return value;\n }\n return undefined;\n }\n\n private clamp(value: number, min: number, max: number): number {\n return Math.min(Math.max(value, min), max);\n }\n}\n","import type { Canvas2DContext } from './canvas2d/Canvas2DContext';\nimport type { LayoutBox } from '../layout/LayoutTypes';\n\n/**\n * What a debugging overlay is made of: filled boxes, outlines drawn as\n * a band inside their box, and labels. Everything is in logical\n * layout-root pixels, unclipped and untransformed — the overlay sits\n * over the finished scene — so either renderer can draw it: Canvas2D\n * with rects and text, WebGPU as fill and border instances and a text\n * run appended after the scene's commands.\n */\nexport type OverlayShape =\n | { kind: 'fill'; x: number; y: number; width: number; height: number; color: string }\n | { kind: 'stroke'; x: number; y: number; width: number; height: number; color: string; lineWidth: number }\n | {\n kind: 'label';\n /** The box the label annotates; the label sits above it when there is room. */\n box: LayoutBox;\n text: string;\n /** Canvas font shorthand. */\n font: string;\n fontSize: number;\n fontFamily: string;\n textColor: string;\n background: string;\n height: number;\n };\n\n/** Where a label's background box goes: above its box when there is room, else inside its top edge. */\nexport function labelOrigin(shape: Extract<OverlayShape, { kind: 'label' }>): { x: number; y: number } {\n return {\n x: Math.max(0, shape.box.x),\n y: shape.box.y >= shape.height ? shape.box.y - shape.height : shape.box.y\n };\n}\n\n/** Horizontal padding inside a label box, each side. */\nexport const LABEL_PADDING_X = 4;\n\n/**\n * Draws overlay shapes onto a 2D context left in logical pixels, as the\n * Canvas2D renderer leaves it after a frame. Styles are assigned only\n * when they change, so a run of strips in one colour is one style set.\n */\nexport function drawOverlayShapes(ctx: Canvas2DContext, shapes: readonly OverlayShape[]): void {\n let fillStyle: string | undefined;\n let strokeStyle: string | undefined;\n let lineWidth: number | undefined;\n const fill = (color: string): void => {\n if (fillStyle !== color) {\n ctx.fillStyle = color;\n fillStyle = color;\n }\n };\n for (const shape of shapes) {\n switch (shape.kind) {\n case 'fill':\n fill(shape.color);\n ctx.fillRect(shape.x, shape.y, shape.width, shape.height);\n break;\n case 'stroke': {\n if (strokeStyle !== shape.color) {\n ctx.strokeStyle = shape.color;\n strokeStyle = shape.color;\n }\n if (lineWidth !== shape.lineWidth) {\n ctx.lineWidth = shape.lineWidth;\n lineWidth = shape.lineWidth;\n }\n // Centred on a path inset by half the width: the band lies inside the box.\n const inset = shape.lineWidth / 2;\n ctx.strokeRect(\n shape.x + inset,\n shape.y + inset,\n Math.max(0, shape.width - shape.lineWidth),\n Math.max(0, shape.height - shape.lineWidth)\n );\n break;\n }\n case 'label': {\n ctx.font = shape.font;\n ctx.textAlign = 'left';\n ctx.textBaseline = 'alphabetic';\n const width = ctx.measureText(shape.text).width + 2 * LABEL_PADDING_X;\n const { x, y } = labelOrigin(shape);\n fill(shape.background);\n ctx.fillRect(x, y, width, shape.height);\n fill(shape.textColor);\n ctx.fillText(shape.text, x + LABEL_PADDING_X, y + shape.height - 4);\n break;\n }\n }\n }\n}\n","import type { LayoutRecord } from '../layout/LayoutRecord';\nimport type { UiNode } from '../graph/UiNode';\nimport type { UiColor } from '../properties/UiColor';\nimport type { UiColorValue } from '../properties/UiPropertyValues';\nimport { resolveColorValue } from '../properties/UiThemeColor';\n\n/**\n * What a modifier may put on screen, and the only thing it may.\n *\n * A decoration is the sibling of `OverlayShape` for the inside of a\n * frame rather than the top of it. The differences are the whole\n * point of having two vocabularies:\n *\n * | | `OverlayShape` | `DecorationShape` |\n * | --- | --- | --- |\n * | Coordinates | layout-root pixels | node-local, from the node's border box |\n * | Painted | over the finished scene | in the node's own paint pass |\n * | Clip / transform / opacity | none | the node's ancestors' |\n * | Colour | a CSS string | a `UiColorValue`, so a palette name works |\n *\n * That third row is why a focus ring is a decoration and not an\n * overlay: a ring on a row scrolled half out of a `ScrollView` has to\n * be cut off with the row, and a ring on a transformed card has to\n * turn with it. An overlay drawn over the finished scene can do\n * neither.\n *\n * **A decoration is clipped by the node's ancestors and not by the\n * node itself.** It is painted where the node's own background and\n * border are painted, outside the node's own clip — which is the only\n * rule under which a ring with an `outset` is visible at all, since\n * every pixel of it lies outside the box that would clip it.\n */\nexport type DecorationShape = DecorationFill | DecorationStroke;\n\ninterface DecorationBox {\n /**\n * The rectangle, in the node's own coordinates: `(0, 0)` is the\n * top-left of its border box — the box its background fills — and\n * the defaults are the whole of it.\n */\n readonly x?: number;\n readonly y?: number;\n readonly width?: number;\n readonly height?: number;\n /**\n * The far edges, as distances inward from the node's right and\n * bottom. Any two of `x`, `width`, `right` fix the horizontal axis,\n * exactly as CSS's `left`, `width` and `right` do, and likewise\n * `y`, `height`, `bottom`.\n *\n * { y: 0, height: 2 } the top edge, two pixels\n * { bottom: 0, height: 2 } the bottom edge\n * { x: 0, width: 2, y: 2, bottom: 2 } the left edge, between them\n *\n * Without them a shape could only be placed from the top left, and\n * `width` and `height` only defaulted to the node's own — so\n * anything pinned to a far edge, or spanning between two, had to be\n * built by a caller that had already measured the node. An\n * application that declares its own geometry, as a spreadsheet\n * declares its row height, does not need this; a general modifier\n * such as `borders()` cannot exist without it.\n *\n * Given all three on one axis, the size wins and the far inset is\n * ignored, which is the rule CSS settles the same conflict with.\n */\n readonly right?: number;\n readonly bottom?: number;\n /**\n * Grows the rectangle on all four sides. This is what puts a focus\n * ring outside the control instead of on top of it.\n */\n readonly outset?: number;\n /**\n * Corner radius. Omitted means the node's own radius grown by the\n * outset, so a ring around a rounded button is concentric with it\n * without the modifier having to read the node's radius.\n */\n readonly radius?: number;\n /**\n * Paints after the node's children and its own text instead of\n * before them. Both phases are outside the node's own clip; this\n * chooses which side of the content the decoration lands on.\n */\n readonly after?: 'children';\n}\n\nexport interface DecorationFill extends DecorationBox {\n readonly kind: 'fill';\n /** A `UiColor`, a hex or named CSS colour, or a palette name. */\n readonly color: UiColorValue;\n}\n\nexport interface DecorationStroke extends DecorationBox {\n readonly kind: 'stroke';\n readonly color: UiColorValue;\n /**\n * The band lies *inside* the rectangle, as a border does and as an\n * overlay stroke does, so `outset: 3, lineWidth: 2` puts the ring\n * between one and three pixels outside the node's box.\n */\n readonly lineWidth: number;\n}\n\n/** A decoration's rectangle in the absolute coordinates a record uses. */\nexport interface DecorationRect {\n x: number;\n y: number;\n width: number;\n height: number;\n radius: number;\n}\n\n/**\n * Places a decoration against the node's record.\n *\n * Shared by both backends rather than derived twice: the offsets, the\n * outset and the inherited radius are exactly the arithmetic the two\n * renderers would otherwise drift on.\n */\nexport function decorationRect(shape: DecorationShape, rec: LayoutRecord, nodeRadius: number): DecorationRect {\n const outset = shape.outset ?? 0;\n const horizontal = axis(rec.x, rec.width, shape.x, shape.width, shape.right, outset);\n const vertical = axis(rec.y, rec.height, shape.y, shape.height, shape.bottom, outset);\n const radius = Math.max(0, shape.radius ?? nodeRadius + outset);\n return {\n x: horizontal.start,\n y: vertical.start,\n width: horizontal.size,\n height: vertical.size,\n radius\n };\n}\n\n/**\n * One axis of the placement, from any two of near, size and far.\n *\n * The outset applies after the three are reconciled, growing the\n * rectangle by it on both sides, so it means the same thing however\n * the rectangle was described.\n */\nfunction axis(\n origin: number,\n extent: number,\n near: number | undefined,\n size: number | undefined,\n far: number | undefined,\n outset: number\n): { start: number; size: number } {\n let start: number;\n let length: number;\n if (near === undefined && size !== undefined && far !== undefined) {\n // Pinned to the far edge at a fixed size: the only case where the\n // near edge is the one that has to be worked out.\n length = size;\n start = extent - far - size;\n } else {\n start = near ?? 0;\n length = size ?? extent - start - (far ?? 0);\n }\n return { start: origin + start - outset, size: Math.max(0, length + 2 * outset) };\n}\n\n/**\n * A decoration's colour, resolved against the node it decorates.\n *\n * The same rule every colour prop follows: a palette name resolves\n * against whatever theme the node inherits, at paint. That is why\n * `focusRing()` never reads the theme — it names `focusRing` and the\n * node's environment decides what that is, so a ring inside a dark\n * card is the dark palette's without the modifier knowing there was a\n * card.\n */\nexport function decorationColor(node: UiNode, shape: DecorationShape): UiColor | undefined {\n return resolveColorValue(node, shape.color);\n}\n\n/** Whether a shape paints before the node's children or after them. */\nexport function paintsAfterChildren(shape: DecorationShape): boolean {\n return shape.after === 'children';\n}\n\n/** Whether any shape in the list paints in the given phase; lets a renderer skip a pass. */\nexport function hasDecorationPhase(shapes: readonly DecorationShape[], after: boolean): boolean {\n for (const shape of shapes) {\n if (paintsAfterChildren(shape) === after) {\n return true;\n }\n }\n return false;\n}\n","/**\n * Pre-scaled copies of images, kept at the size they are drawn.\n *\n * `drawImage` with a destination size that differs from the source\n * resamples, and whether that is free depends entirely on the engine.\n * Chromium records the call and lets the GPU sample it, so a\n * 1280x992 bitmap drawn at 1000x800 costs nothing measurable.\n * Gecko resamples on the CPU, on whichever thread issued the call,\n * and the same draw costs about 1.8ms. Measured in a worker\n * `OffscreenCanvas` on Firefox 154:\n *\n * | draw | Firefox | Chrome |\n * | --------------------------------- | ------- | ------ |\n * | 1280x992 bitmap at 1000x800 | 1.80ms | 0.00ms |\n * | 1000x800 bitmap at 1000x800 | 0.10ms | 0.00ms |\n *\n * The cost tracks destination pixels, at roughly 2.2ns each, so it\n * is not the size of the source that hurts but the resample itself:\n * the same bitmap drawn small is cheap, and a bitmap that needs no\n * resample is cheap at any size. A screen that is mostly artwork\n * therefore spends its whole frame budget in `drawImage`, which on\n * the transitions example was 11.5ms of an 11.6ms frame.\n *\n * So this keeps, per source image, one copy at the device size that\n * image was last drawn at, and hands that copy back instead. The\n * draw becomes 1:1 and the resample happens once rather than sixty\n * times a second. Chromium pays a single blit per size and is\n * otherwise unaffected, which is the reason this is not conditioned\n * on the engine: an engine check would be a second thing to be\n * wrong about, and there is nothing to gain by skipping it.\n *\n * **Sizes are device pixels, not layout pixels.** A copy is only\n * worth having if the draw it serves needs no resample, and that is\n * a fact about the backing store: the same box is a different number\n * of pixels at a different device pixel ratio, and again under a\n * node transform that scales.\n */\n\n/** What a cached copy is worth having for. */\ninterface ScaledImageEntry {\n /** The source these pixels came from, for eviction to identify. */\n source: ImageBitmap;\n /** The copy, at exactly `width` x `height` device pixels. */\n bitmap: ImageBitmap | null;\n width: number;\n height: number;\n /** Consecutive resolves that asked for this size. */\n stable: number;\n}\n\n/**\n * How many consecutive frames a size must hold before a copy is made.\n *\n * A morph transition scales its image every frame, so every frame\n * asks for a size no copy will ever be asked for again. Building one\n * anyway would add a blit to a frame that already had to resample,\n * making the one case that is most sensitive to frame time worse.\n * Two frames is enough to tell a settled layout from an animating\n * one, and costs an animation nothing it was not already paying.\n */\nconst FRAMES_BEFORE_COPY = 2;\n\n/**\n * The largest copy worth keeping, in device pixels.\n *\n * A full-bleed image on a 3440x1440 display is about 5 megapixels\n * and 20MB as a copy, which is worth it: that image is the single\n * most expensive draw in the frame. Twice that is not, so the\n * ceiling sits above the largest real screen and below anything a\n * mistake would ask for.\n */\nconst MAX_COPY_PIXELS = 12_000_000;\n\n/**\n * How many copies to keep.\n *\n * One per image visible at once, near enough. A shelf of artwork\n * scrolls new images in and old ones out, and the cost of losing a\n * copy is one resampled draw plus one blit, so this only has to be\n * large enough that a screenful does not evict itself.\n */\nconst MAX_ENTRIES = 48;\n\n/** Somewhere to draw a copy: `OffscreenCanvas`, or a test double. */\nexport interface ScaledImageSurface {\n width: number;\n height: number;\n getContext(\n contextId: '2d'\n ): { drawImage(image: ImageBitmap, dx: number, dy: number, dw: number, dh: number): void } | null;\n transferToImageBitmap(): ImageBitmap;\n}\n\nexport type ScaledImageSurfaceFactory = (width: number, height: number) => ScaledImageSurface;\n\nfunction defaultSurfaceFactory(width: number, height: number): ScaledImageSurface {\n return new OffscreenCanvas(width, height) as unknown as ScaledImageSurface;\n}\n\n/**\n * Whether this environment can make a copy at all.\n *\n * `OffscreenCanvas` is the only synchronous way to resample: the\n * asynchronous `createImageBitmap(source, { resizeWidth })` cannot\n * be awaited inside a frame, and a copy that arrives a frame later\n * is a copy that arrives after the size it was made for has changed.\n */\nexport function canScaleImages(): boolean {\n return typeof OffscreenCanvas === 'function';\n}\n\nexport class ScaledImageCache {\n /**\n * Insertion-ordered, which is what makes eviction least-recently-used:\n * a hit deletes and re-sets its key, so the oldest entry is first.\n *\n * A `Map` rather than a `WeakMap` because eviction has to be able to\n * find the entry it is dropping in order to close the copy it holds,\n * and a weak collection cannot be walked. The strong reference to the\n * source is bounded by `MAX_ENTRIES` and released on eviction.\n */\n private readonly entries = new Map<string, ScaledImageEntry>();\n /**\n * A number per source, so an entry can be keyed by picture *and*\n * size.\n *\n * One slot per source was a bug rather than a simplification. A\n * picture on screen at two sizes at once — Segue's now-playing bar\n * shows the same cover at 52px that its page shows at 340 — had the\n * two draws fight over the single slot: each in turn held the size\n * long enough to earn a copy, made it, and closed the other's. The\n * smaller one then alternated between a crisp copy and a raw\n * downsample of the source every few frames, which reads on screen as\n * the picture shimmering. `ScaledImageCache.spec.ts` pins it.\n *\n * `WeakMap`, so a source that goes away takes its id with it; the\n * entries themselves are still strongly held and evicted by count.\n */\n private readonly sourceIds = new WeakMap<ImageBitmap, number>();\n private nextSourceId = 1;\n private readonly createSurface: ScaledImageSurfaceFactory;\n private readonly enabled: boolean;\n\n constructor(createSurface?: ScaledImageSurfaceFactory) {\n this.enabled = createSurface !== undefined || canScaleImages();\n this.createSurface = createSurface ?? defaultSurfaceFactory;\n }\n\n /**\n * The image to draw for a destination of `width` x `height` device\n * pixels: a copy at that exact size when one is worth having and\n * ready, and otherwise `source` unchanged.\n *\n * Always safe to draw the result at the destination rectangle the\n * sizes came from. A copy is a resample of the same pixels, so the\n * picture is the same either way; only which of the two resamples\n * runs this frame differs.\n */\n resolve(source: ImageBitmap, width: number, height: number): ImageBitmap {\n if (!this.enabled) {\n return source;\n }\n const w = Math.round(width);\n const h = Math.round(height);\n if (w <= 0 || h <= 0 || w * h > MAX_COPY_PIXELS) {\n return source;\n }\n // Already 1:1. Copying would spend memory to save nothing, and\n // this is the common case for an icon drawn at its natural size.\n if (source.width === w && source.height === h) {\n return source;\n }\n const key = this.keyFor(source, w, h);\n const entry = this.entries.get(key);\n if (entry === undefined) {\n this.insert(key, { source, bitmap: null, width: w, height: h, stable: 1 });\n return source;\n }\n // Refresh recency whether or not a copy comes of it: an image\n // drawn every frame at a size that keeps changing is still an\n // image this cache should not evict ahead of an idle one.\n this.entries.delete(key);\n this.entries.set(key, entry);\n if (entry.bitmap !== null) {\n return entry.bitmap;\n }\n entry.stable++;\n if (entry.stable < FRAMES_BEFORE_COPY) {\n return source;\n }\n const copy = this.copy(source, w, h);\n if (copy === null) {\n return source;\n }\n entry.bitmap = copy;\n return copy;\n }\n\n /** Drops every copy. Called when the renderer goes away. */\n dispose(): void {\n for (const entry of this.entries.values()) {\n entry.bitmap?.close();\n }\n this.entries.clear();\n }\n\n /** How many picture-and-size pairs are tracked. For specs and the inspector. */\n get size(): number {\n return this.entries.size;\n }\n\n /**\n * The cache key: this picture, at this size.\n *\n * A size that is asked for once and never again makes an entry that\n * holds no copy and is evicted by count like any other, which is why\n * a morph scaling every frame costs entries rather than copies.\n */\n private keyFor(source: ImageBitmap, width: number, height: number): string {\n let id = this.sourceIds.get(source);\n if (id === undefined) {\n id = this.nextSourceId++;\n this.sourceIds.set(source, id);\n }\n return `${id}:${width}x${height}`;\n }\n\n private insert(key: string, entry: ScaledImageEntry): void {\n if (this.entries.size >= MAX_ENTRIES) {\n const oldest = this.entries.keys().next();\n if (!oldest.done) {\n this.entries.get(oldest.value)?.bitmap?.close();\n this.entries.delete(oldest.value);\n }\n }\n this.entries.set(key, entry);\n }\n\n /**\n * Resamples once, into a bitmap.\n *\n * Failure is not exceptional: a source that has been closed under\n * us throws here, and the honest answer is to draw the original and\n * let the next frame notice. So this reports null rather than\n * letting a frame die over an image.\n */\n private copy(source: ImageBitmap, width: number, height: number): ImageBitmap | null {\n try {\n const surface = this.createSurface(width, height);\n const context = surface.getContext('2d');\n if (context === null) {\n return null;\n }\n context.drawImage(source, 0, 0, width, height);\n return surface.transferToImageBitmap();\n } catch {\n return null;\n }\n }\n}\n","import type { PaintSurface } from './PaintSurface';\n\n/**\n * SVG path data, as calls on a `PaintSurface`.\n *\n * `IconRasterizer` hands its `d` string to `Path2D` and lets the\n * browser do this. That is the right call there, because an icon is\n * only ever rasterised in a browser, and it is the wrong call here for\n * two reasons: `Path2D` does not exist in the suite, so nothing about\n * a path could be asserted without a browser, and a recording that\n * held an opaque `Path2D` could not be compared, replayed or handed to\n * a second backend, which is the whole design.\n *\n * The grammar is the full one: `M L H V C S Q T A Z`, upper case\n * absolute and lower case relative, repeated coordinate sets after one\n * command letter, and the shorthand curves' reflected control points.\n * An unknown letter ends the parse rather than throwing, because a\n * half-drawn logo is a better failure in front of a person than a\n * blank frame.\n */\nexport function tracePathData(surface: PaintSurface, d: string): void {\n const scanner = new Scanner(d);\n // Where the pen is, and where the subpath started, so `Z` and a\n // relative command after it both have an origin.\n let x = 0;\n let y = 0;\n let startX = 0;\n let startY = 0;\n // The previous curve's second control point, reflected by `S` and\n // `T`. Null after anything that is not a curve of the matching kind,\n // which is what the specification says the reflection falls back on.\n let lastCubic: [number, number] | null = null;\n let lastQuadratic: [number, number] | null = null;\n let command = '';\n\n for (;;) {\n scanner.skipSeparators();\n if (scanner.done) {\n return;\n }\n const next = scanner.peekCommand();\n if (next !== undefined) {\n command = next;\n } else if (command === '') {\n return;\n } else if (command === 'M') {\n // A repeated coordinate set after `M` is a line, which is the\n // one place the implicit command is not the one just written.\n command = 'L';\n } else if (command === 'm') {\n command = 'l';\n }\n const relative = command >= 'a';\n const upper = relative ? command.toUpperCase() : command;\n const originX = relative ? x : 0;\n const originY = relative ? y : 0;\n\n switch (upper) {\n case 'M': {\n x = scanner.number() + originX;\n y = scanner.number() + originY;\n startX = x;\n startY = y;\n surface.moveTo(x, y);\n lastCubic = null;\n lastQuadratic = null;\n break;\n }\n case 'L': {\n x = scanner.number() + originX;\n y = scanner.number() + originY;\n surface.lineTo(x, y);\n lastCubic = null;\n lastQuadratic = null;\n break;\n }\n case 'H': {\n x = scanner.number() + originX;\n surface.lineTo(x, y);\n lastCubic = null;\n lastQuadratic = null;\n break;\n }\n case 'V': {\n y = scanner.number() + originY;\n surface.lineTo(x, y);\n lastCubic = null;\n lastQuadratic = null;\n break;\n }\n case 'C': {\n const c1x = scanner.number() + originX;\n const c1y = scanner.number() + originY;\n const c2x = scanner.number() + originX;\n const c2y = scanner.number() + originY;\n x = scanner.number() + originX;\n y = scanner.number() + originY;\n surface.bezierCurveTo(c1x, c1y, c2x, c2y, x, y);\n lastCubic = [c2x, c2y];\n lastQuadratic = null;\n break;\n }\n case 'S': {\n const [c1x, c1y] = reflect(lastCubic, x, y);\n const c2x = scanner.number() + originX;\n const c2y = scanner.number() + originY;\n x = scanner.number() + originX;\n y = scanner.number() + originY;\n surface.bezierCurveTo(c1x, c1y, c2x, c2y, x, y);\n lastCubic = [c2x, c2y];\n lastQuadratic = null;\n break;\n }\n case 'Q': {\n const cx = scanner.number() + originX;\n const cy = scanner.number() + originY;\n x = scanner.number() + originX;\n y = scanner.number() + originY;\n surface.quadraticCurveTo(cx, cy, x, y);\n lastQuadratic = [cx, cy];\n lastCubic = null;\n break;\n }\n case 'T': {\n const [cx, cy] = reflect(lastQuadratic, x, y);\n x = scanner.number() + originX;\n y = scanner.number() + originY;\n surface.quadraticCurveTo(cx, cy, x, y);\n lastQuadratic = [cx, cy];\n lastCubic = null;\n break;\n }\n case 'A': {\n const rx = scanner.number();\n const ry = scanner.number();\n const rotation = (scanner.number() * Math.PI) / 180;\n const largeArc = scanner.flag();\n const sweep = scanner.flag();\n const endX = scanner.number() + originX;\n const endY = scanner.number() + originY;\n arcToCurves(surface, x, y, rx, ry, rotation, largeArc, sweep, endX, endY);\n x = endX;\n y = endY;\n lastCubic = null;\n lastQuadratic = null;\n break;\n }\n case 'Z': {\n surface.closePath();\n x = startX;\n y = startY;\n lastCubic = null;\n lastQuadratic = null;\n break;\n }\n default:\n return;\n }\n }\n}\n\n/** The previous control point mirrored through the current point. */\nfunction reflect(control: [number, number] | null, x: number, y: number): [number, number] {\n return control === null ? [x, y] : [2 * x - control[0], 2 * y - control[1]];\n}\n\n/**\n * An elliptical arc as cubic segments, by the endpoint-to-centre\n * conversion in the SVG specification's implementation notes.\n *\n * Nothing in the surface draws an ellipse, and nothing should: an arc\n * with a rotation and two radii is the only shape in the grammar that\n * a rectangle-and-curve vocabulary cannot state, and one conversion\n * here is cheaper than a primitive every consumer of the recording\n * would have to implement. Ninety degrees per segment keeps the error\n * far under a tenth of a pixel at icon sizes.\n */\nfunction arcToCurves(\n surface: PaintSurface,\n x0: number,\n y0: number,\n rx: number,\n ry: number,\n rotation: number,\n largeArc: boolean,\n sweep: boolean,\n x1: number,\n y1: number\n): void {\n if (x0 === x1 && y0 === y1) {\n return;\n }\n let radiusX = Math.abs(rx);\n let radiusY = Math.abs(ry);\n if (radiusX === 0 || radiusY === 0) {\n // A degenerate radius is a straight line, which is what the\n // specification says and what an exported path occasionally holds.\n surface.lineTo(x1, y1);\n return;\n }\n const cos = Math.cos(rotation);\n const sin = Math.sin(rotation);\n const dx = (x0 - x1) / 2;\n const dy = (y0 - y1) / 2;\n const px = cos * dx + sin * dy;\n const py = -sin * dx + cos * dy;\n // Radii too small to join the endpoints are grown until they just\n // do, rather than the arc being dropped.\n const lambda = (px * px) / (radiusX * radiusX) + (py * py) / (radiusY * radiusY);\n if (lambda > 1) {\n const grow = Math.sqrt(lambda);\n radiusX *= grow;\n radiusY *= grow;\n }\n const numerator = radiusX * radiusX * radiusY * radiusY - radiusX * radiusX * py * py - radiusY * radiusY * px * px;\n const denominator = radiusX * radiusX * py * py + radiusY * radiusY * px * px;\n const factor = (largeArc === sweep ? -1 : 1) * Math.sqrt(Math.max(0, numerator / denominator));\n const cxPrime = (factor * radiusX * py) / radiusY;\n const cyPrime = (-factor * radiusY * px) / radiusX;\n const cx = cos * cxPrime - sin * cyPrime + (x0 + x1) / 2;\n const cy = sin * cxPrime + cos * cyPrime + (y0 + y1) / 2;\n\n const start = Math.atan2((py - cyPrime) / radiusY, (px - cxPrime) / radiusX);\n const end = Math.atan2((-py - cyPrime) / radiusY, (-px - cxPrime) / radiusX);\n let sweepAngle = end - start;\n if (!sweep && sweepAngle > 0) {\n sweepAngle -= 2 * Math.PI;\n } else if (sweep && sweepAngle < 0) {\n sweepAngle += 2 * Math.PI;\n }\n\n const segments = Math.max(1, Math.ceil(Math.abs(sweepAngle) / (Math.PI / 2)));\n const step = sweepAngle / segments;\n // The control-point distance that makes a cubic match a circular arc\n // of `step` radians; 4/3 tan(step/4) is the standard value.\n const handle = (4 / 3) * Math.tan(step / 4);\n let angle = start;\n for (let i = 0; i < segments; i++) {\n const next = angle + step;\n const cosA = Math.cos(angle);\n const sinA = Math.sin(angle);\n const cosB = Math.cos(next);\n const sinB = Math.sin(next);\n const p1 = onEllipse(cx, cy, radiusX, radiusY, cos, sin, cosA - handle * sinA, sinA + handle * cosA);\n const p2 = onEllipse(cx, cy, radiusX, radiusY, cos, sin, cosB + handle * sinB, sinB - handle * cosB);\n const p3 = onEllipse(cx, cy, radiusX, radiusY, cos, sin, cosB, sinB);\n surface.bezierCurveTo(p1[0], p1[1], p2[0], p2[1], p3[0], p3[1]);\n angle = next;\n }\n}\n\n/** A point on the rotated ellipse, from its unit-circle coordinates. */\nfunction onEllipse(\n cx: number,\n cy: number,\n rx: number,\n ry: number,\n cos: number,\n sin: number,\n ux: number,\n uy: number\n): [number, number] {\n const x = rx * ux;\n const y = ry * uy;\n return [cx + cos * x - sin * y, cy + sin * x + cos * y];\n}\n\n/**\n * A cursor over path data.\n *\n * Path data is written without separators wherever it can be\n * (`M0 0l5-3.5`), so nothing here can split on whitespace: numbers are\n * read character by character, and the two arc flags are read as a\n * single digit each, which is the one place the grammar is not a plain\n * number list.\n */\nclass Scanner {\n private index = 0;\n\n constructor(private readonly source: string) {}\n\n get done(): boolean {\n return this.index >= this.source.length;\n }\n\n skipSeparators(): void {\n while (this.index < this.source.length) {\n const code = this.source.charCodeAt(this.index);\n // space, tab, newline, carriage return, form feed, comma\n if (code === 32 || code === 9 || code === 10 || code === 13 || code === 12 || code === 44) {\n this.index++;\n continue;\n }\n return;\n }\n }\n\n /** The command letter here, consumed; undefined when a number is next. */\n peekCommand(): string | undefined {\n const char = this.source[this.index];\n if (char === undefined || !/[a-zA-Z]/.test(char)) {\n return undefined;\n }\n this.index++;\n return char;\n }\n\n number(): number {\n this.skipSeparators();\n const start = this.index;\n if (this.source[this.index] === '+' || this.source[this.index] === '-') {\n this.index++;\n }\n while (this.isDigit()) {\n this.index++;\n }\n if (this.source[this.index] === '.') {\n this.index++;\n while (this.isDigit()) {\n this.index++;\n }\n }\n const exponent = this.source[this.index];\n if (exponent === 'e' || exponent === 'E') {\n this.index++;\n if (this.source[this.index] === '+' || this.source[this.index] === '-') {\n this.index++;\n }\n while (this.isDigit()) {\n this.index++;\n }\n }\n const value = Number.parseFloat(this.source.slice(start, this.index));\n return Number.isNaN(value) ? 0 : value;\n }\n\n /** One character, `0` or `1`: the arc flags carry no separator. */\n flag(): boolean {\n this.skipSeparators();\n const char = this.source[this.index];\n this.index++;\n return char === '1';\n }\n\n private isDigit(): boolean {\n const code = this.source.charCodeAt(this.index);\n return code >= 48 && code <= 57;\n }\n}\n","import type { UiColorValue } from '../properties/UiPropertyValues';\nimport type { UiGradient } from '../properties/UiGradient';\nimport type { UiImage } from '../properties/UiImage';\nimport { tracePathData } from './PaintPathData';\nimport type { PaintFillRule, PaintLineCap, PaintLineJoin, PaintSurface, PaintTextStyle } from './PaintSurface';\n\n/**\n * One call a painter made, as data.\n *\n * The union mirrors `PaintSurface` one method to one variant, and\n * deliberately keeps `translate`, `scale` and `rotate` apart from the\n * general `transform` they could all collapse into: a replay onto a\n * real context should make the call the painter made, both because it\n * is cheaper and because the renderer parity decoder reads those three\n * by name.\n */\nexport type PaintOp =\n | { readonly op: 'save' }\n | { readonly op: 'restore' }\n | { readonly op: 'translate'; readonly x: number; readonly y: number }\n | { readonly op: 'scale'; readonly x: number; readonly y: number }\n | { readonly op: 'rotate'; readonly angle: number }\n | {\n readonly op: 'transform';\n readonly a: number;\n readonly b: number;\n readonly c: number;\n readonly d: number;\n readonly e: number;\n readonly f: number;\n }\n | { readonly op: 'beginPath' }\n | { readonly op: 'moveTo'; readonly x: number; readonly y: number }\n | { readonly op: 'lineTo'; readonly x: number; readonly y: number }\n | {\n readonly op: 'quadraticCurveTo';\n readonly cx: number;\n readonly cy: number;\n readonly x: number;\n readonly y: number;\n }\n | {\n readonly op: 'bezierCurveTo';\n readonly c1x: number;\n readonly c1y: number;\n readonly c2x: number;\n readonly c2y: number;\n readonly x: number;\n readonly y: number;\n }\n | {\n readonly op: 'arc';\n readonly x: number;\n readonly y: number;\n readonly radius: number;\n readonly startAngle: number;\n readonly endAngle: number;\n readonly counterclockwise: boolean;\n }\n | { readonly op: 'rect'; readonly x: number; readonly y: number; readonly width: number; readonly height: number }\n | {\n readonly op: 'roundRect';\n readonly x: number;\n readonly y: number;\n readonly width: number;\n readonly height: number;\n readonly radius: number;\n }\n | { readonly op: 'closePath' }\n | { readonly op: 'fillColor'; readonly color: UiColorValue }\n | {\n readonly op: 'fillGradient';\n readonly gradient: UiGradient;\n readonly x: number;\n readonly y: number;\n readonly width: number;\n readonly height: number;\n }\n | { readonly op: 'strokeColor'; readonly color: UiColorValue }\n | { readonly op: 'lineWidth'; readonly width: number }\n | { readonly op: 'lineCap'; readonly cap: PaintLineCap }\n | { readonly op: 'lineJoin'; readonly join: PaintLineJoin }\n | { readonly op: 'miterLimit'; readonly limit: number }\n | { readonly op: 'lineDash'; readonly segments: readonly number[]; readonly offset: number }\n | { readonly op: 'alpha'; readonly value: number }\n | { readonly op: 'blur'; readonly radius: number }\n | { readonly op: 'fill'; readonly rule: PaintFillRule }\n | { readonly op: 'stroke' }\n | { readonly op: 'clip'; readonly rule: PaintFillRule }\n | {\n readonly op: 'text';\n readonly value: string;\n readonly x: number;\n readonly y: number;\n readonly style: PaintTextStyle | undefined;\n }\n | {\n readonly op: 'image';\n readonly image: UiImage;\n readonly x: number;\n readonly y: number;\n readonly width: number;\n readonly height: number;\n };\n\n/**\n * What a painter drew, as an ordered list of calls.\n *\n * This is the object that makes the two backends agree, and it is\n * worth being precise about how. A painter does not draw; it describes\n * a drawing, once, when its inputs change. The description is then\n * turned into pixels in exactly one place, so there is no second\n * implementation of `arc`, of the even-odd rule or of a dash pattern\n * for a backend to get subtly wrong. The obvious alternative, for each\n * renderer to replay the recording in its own vocabulary, would mean a\n * second rasteriser to keep in agreement.\n */\nexport interface PaintRecording {\n readonly ops: readonly PaintOp[];\n}\n\n/** A recording with nothing in it, for a painter that drew nothing. */\nexport const EMPTY_RECORDING: PaintRecording = Object.freeze({ ops: Object.freeze([]) as readonly PaintOp[] });\n\n/**\n * The `PaintSurface` a painter is actually handed.\n *\n * Every call is one push. Nothing is validated, coalesced or\n * normalised on the way in: a recorder that dropped a redundant\n * `lineWidth` would be deciding what the picture is, and the whole\n * value of the recording is that it is what the painter said.\n */\nexport class PaintRecorder implements PaintSurface {\n private readonly recorded: PaintOp[] = [];\n\n /** The recording so far. Safe to keep; the recorder is done with it. */\n finish(): PaintRecording {\n return { ops: this.recorded };\n }\n\n save(): void {\n this.recorded.push(SAVE);\n }\n\n restore(): void {\n this.recorded.push(RESTORE);\n }\n\n translate(x: number, y: number): void {\n this.recorded.push({ op: 'translate', x, y });\n }\n\n scale(x: number, y: number): void {\n this.recorded.push({ op: 'scale', x, y });\n }\n\n rotate(angle: number): void {\n this.recorded.push({ op: 'rotate', angle });\n }\n\n transform(a: number, b: number, c: number, d: number, e: number, f: number): void {\n this.recorded.push({ op: 'transform', a, b, c, d, e, f });\n }\n\n beginPath(): void {\n this.recorded.push(BEGIN_PATH);\n }\n\n moveTo(x: number, y: number): void {\n this.recorded.push({ op: 'moveTo', x, y });\n }\n\n lineTo(x: number, y: number): void {\n this.recorded.push({ op: 'lineTo', x, y });\n }\n\n quadraticCurveTo(cx: number, cy: number, x: number, y: number): void {\n this.recorded.push({ op: 'quadraticCurveTo', cx, cy, x, y });\n }\n\n bezierCurveTo(c1x: number, c1y: number, c2x: number, c2y: number, x: number, y: number): void {\n this.recorded.push({ op: 'bezierCurveTo', c1x, c1y, c2x, c2y, x, y });\n }\n\n arc(x: number, y: number, radius: number, startAngle: number, endAngle: number, counterclockwise = false): void {\n this.recorded.push({ op: 'arc', x, y, radius, startAngle, endAngle, counterclockwise });\n }\n\n rect(x: number, y: number, width: number, height: number): void {\n this.recorded.push({ op: 'rect', x, y, width, height });\n }\n\n roundRect(x: number, y: number, width: number, height: number, radius: number): void {\n this.recorded.push({ op: 'roundRect', x, y, width, height, radius });\n }\n\n closePath(): void {\n this.recorded.push(CLOSE_PATH);\n }\n\n /**\n * The one call that is not one op: path data expands into the moves\n * and curves it names, so a recording never holds a string that has\n * to be parsed again at replay, and a `d` string and the equivalent\n * hand-written calls produce byte-identical recordings.\n */\n path(d: string): void {\n tracePathData(this, d);\n }\n\n fillColor(color: UiColorValue): void {\n this.recorded.push({ op: 'fillColor', color });\n }\n\n fillGradient(gradient: UiGradient, x: number, y: number, width: number, height: number): void {\n this.recorded.push({ op: 'fillGradient', gradient, x, y, width, height });\n }\n\n strokeColor(color: UiColorValue): void {\n this.recorded.push({ op: 'strokeColor', color });\n }\n\n lineWidth(width: number): void {\n this.recorded.push({ op: 'lineWidth', width });\n }\n\n lineCap(cap: PaintLineCap): void {\n this.recorded.push({ op: 'lineCap', cap });\n }\n\n lineJoin(join: PaintLineJoin): void {\n this.recorded.push({ op: 'lineJoin', join });\n }\n\n miterLimit(limit: number): void {\n this.recorded.push({ op: 'miterLimit', limit });\n }\n\n lineDash(segments: readonly number[], offset = 0): void {\n this.recorded.push({ op: 'lineDash', segments, offset });\n }\n\n alpha(value: number): void {\n this.recorded.push({ op: 'alpha', value });\n }\n\n blur(radius: number): void {\n this.recorded.push({ op: 'blur', radius });\n }\n\n fill(rule: PaintFillRule = 'nonzero'): void {\n this.recorded.push({ op: 'fill', rule });\n }\n\n stroke(): void {\n this.recorded.push(STROKE);\n }\n\n clip(rule: PaintFillRule = 'nonzero'): void {\n this.recorded.push({ op: 'clip', rule });\n }\n\n text(value: string, x: number, y: number, style?: PaintTextStyle): void {\n this.recorded.push({ op: 'text', value, x, y, style });\n }\n\n image(image: UiImage, x: number, y: number, width: number, height: number): void {\n this.recorded.push({ op: 'image', image, x, y, width, height });\n }\n}\n\n// The argument-free ops are shared values rather than fresh objects: a\n// path of a hundred segments emits a `beginPath` and a `closePath` per\n// subpath, and they carry nothing to tell apart.\nconst SAVE: PaintOp = Object.freeze({ op: 'save' as const });\nconst RESTORE: PaintOp = Object.freeze({ op: 'restore' as const });\nconst BEGIN_PATH: PaintOp = Object.freeze({ op: 'beginPath' as const });\nconst CLOSE_PATH: PaintOp = Object.freeze({ op: 'closePath' as const });\nconst STROKE: PaintOp = Object.freeze({ op: 'stroke' as const });\n\n/**\n * Replays a recording onto any surface.\n *\n * The surface is a `PaintSurface` and not a canvas, so a recording can\n * be replayed into a rasteriser, into another recorder, or into a spec\n * double that counts what it was asked to do. That is the property the\n * parity gate leans on: neither backend is the one this understands.\n */\nexport function replayPaint(recording: PaintRecording, surface: PaintSurface): void {\n for (const op of recording.ops) {\n switch (op.op) {\n case 'save':\n surface.save();\n break;\n case 'restore':\n surface.restore();\n break;\n case 'translate':\n surface.translate(op.x, op.y);\n break;\n case 'scale':\n surface.scale(op.x, op.y);\n break;\n case 'rotate':\n surface.rotate(op.angle);\n break;\n case 'transform':\n surface.transform(op.a, op.b, op.c, op.d, op.e, op.f);\n break;\n case 'beginPath':\n surface.beginPath();\n break;\n case 'moveTo':\n surface.moveTo(op.x, op.y);\n break;\n case 'lineTo':\n surface.lineTo(op.x, op.y);\n break;\n case 'quadraticCurveTo':\n surface.quadraticCurveTo(op.cx, op.cy, op.x, op.y);\n break;\n case 'bezierCurveTo':\n surface.bezierCurveTo(op.c1x, op.c1y, op.c2x, op.c2y, op.x, op.y);\n break;\n case 'arc':\n surface.arc(op.x, op.y, op.radius, op.startAngle, op.endAngle, op.counterclockwise);\n break;\n case 'rect':\n surface.rect(op.x, op.y, op.width, op.height);\n break;\n case 'roundRect':\n surface.roundRect(op.x, op.y, op.width, op.height, op.radius);\n break;\n case 'closePath':\n surface.closePath();\n break;\n case 'fillColor':\n surface.fillColor(op.color);\n break;\n case 'fillGradient':\n surface.fillGradient(op.gradient, op.x, op.y, op.width, op.height);\n break;\n case 'strokeColor':\n surface.strokeColor(op.color);\n break;\n case 'lineWidth':\n surface.lineWidth(op.width);\n break;\n case 'lineCap':\n surface.lineCap(op.cap);\n break;\n case 'lineJoin':\n surface.lineJoin(op.join);\n break;\n case 'miterLimit':\n surface.miterLimit(op.limit);\n break;\n case 'lineDash':\n surface.lineDash(op.segments, op.offset);\n break;\n case 'alpha':\n surface.alpha(op.value);\n break;\n case 'blur':\n surface.blur(op.radius);\n break;\n case 'fill':\n surface.fill(op.rule);\n break;\n case 'stroke':\n surface.stroke();\n break;\n case 'clip':\n surface.clip(op.rule);\n break;\n case 'text':\n surface.text(op.value, op.x, op.y, op.style);\n break;\n case 'image':\n surface.image(op.image, op.x, op.y, op.width, op.height);\n break;\n }\n }\n}\n","import type { UiColor } from '../properties/UiColor';\nimport type { UiColorValue } from '../properties/UiPropertyValues';\nimport type { ResolvedGradient, UiGradient } from '../properties/UiGradient';\nimport { gradientPaint } from '../properties/UiGradient';\nimport type { UiImage } from '../properties/UiImage';\nimport { colorToCss, DEFAULT_FONT_FAMILY, DEFAULT_FONT_SIZE, DEFAULT_FONT_WEIGHT } from './PaintState';\nimport { fontStackFor } from './FontStacks';\nimport { tracePathData } from './PaintPathData';\nimport type { PaintFillRule, PaintLineCap, PaintLineJoin, PaintSurface, PaintTextStyle } from './PaintSurface';\n\n/**\n * The 2D context a picture is drawn into.\n *\n * Named separately from `Canvas2DContext` for the reason `IconContext`\n * is: this is the rasteriser's list, not the renderer's, and the two\n * want different things. A picture never draws a paragraph, so nothing\n * here measures text; a picture does draw dashes, curves and blurs,\n * none of which the node renderer has ever needed. Both a real\n * `OffscreenCanvasRenderingContext2D` and a spec double satisfy it\n * structurally.\n */\nexport interface PaintContext2D {\n save(): void;\n restore(): void;\n translate(x: number, y: number): void;\n scale(x: number, y: number): void;\n rotate(angle: number): void;\n transform(a: number, b: number, c: number, d: number, e: number, f: number): void;\n beginPath(): void;\n moveTo(x: number, y: number): void;\n lineTo(x: number, y: number): void;\n quadraticCurveTo(cx: number, cy: number, x: number, y: number): void;\n bezierCurveTo(c1x: number, c1y: number, c2x: number, c2y: number, x: number, y: number): void;\n arc(x: number, y: number, radius: number, startAngle: number, endAngle: number, counterclockwise?: boolean): void;\n arcTo(x1: number, y1: number, x2: number, y2: number, radius: number): void;\n rect(x: number, y: number, width: number, height: number): void;\n closePath(): void;\n fill(fillRule?: PaintFillRule): void;\n stroke(): void;\n clip(fillRule?: PaintFillRule): void;\n fillText(text: string, x: number, y: number): void;\n drawImage(image: UiImage, dx: number, dy: number, dw: number, dh: number): void;\n setLineDash(segments: readonly number[]): void;\n createLinearGradient(x0: number, y0: number, x1: number, y1: number): PaintGradient;\n createRadialGradient(x0: number, y0: number, r0: number, x1: number, y1: number, r1: number): PaintGradient;\n lineDashOffset: number;\n lineWidth: number;\n lineCap: PaintLineCap;\n lineJoin: PaintLineJoin;\n miterLimit: number;\n globalAlpha: number;\n /**\n * A CSS filter list. Blur is the only one used, and it is a context\n * property rather than a draw argument, so `save` and `restore`\n * scope it exactly as `PaintSurface.blur` promises.\n *\n * Optional because a double has no reason to carry it, and because\n * a host without filter support should draw an unblurred picture\n * rather than none.\n */\n filter?: string;\n fillStyle: string | PaintGradient;\n strokeStyle: string | PaintGradient;\n font: string;\n textAlign: 'left' | 'center' | 'right';\n textBaseline: 'alphabetic';\n}\n\n/** The part of a canvas gradient a picture uses. */\nexport interface PaintGradient {\n addColorStop(offset: number, color: string): void;\n}\n\n/** How a painted node's colour values become colours. */\nexport interface PaintResolver {\n /** A `UiColor`, a CSS string, or a palette name against the node's theme. */\n color(value: UiColorValue): UiColor | undefined;\n gradient(value: UiGradient): ResolvedGradient | undefined;\n}\n\n/**\n * A `PaintSurface` that draws, rather than records.\n *\n * The second implementation of the vocabulary and the only one that\n * makes pixels. It is not a backend: it is handed an offscreen 2D\n * context by `PaintPicture.ts`, and the bitmap that comes out is what\n * both renderers draw. So there is one implementation of an even-odd\n * fill and one of a dash pattern in the tree, which is the property\n * the paint hook asks for, and the reason it\n * cannot fork the renderers.\n *\n * Colour values are resolved here rather than at record time, so a\n * painter may name a palette entry and the picture follows the light\n * and dark toggle: the resolver is bound to the node, and a theme\n * change replaces the node's environment, which is part of the\n * picture's cache key.\n */\nexport class PaintTarget implements PaintSurface {\n /**\n * The pending blur radius per save level.\n *\n * Tracked rather than read back off the context because `filter` is\n * optional here: a context that does not carry one still has to see\n * the rest of the drawing.\n */\n private readonly blurStack: number[] = [];\n private blurRadius = 0;\n\n constructor(\n private readonly ctx: PaintContext2D,\n private readonly resolver: PaintResolver\n ) {}\n\n save(): void {\n this.blurStack.push(this.blurRadius);\n this.ctx.save();\n }\n\n restore(): void {\n this.blurRadius = this.blurStack.pop() ?? 0;\n this.ctx.restore();\n }\n\n translate(x: number, y: number): void {\n this.ctx.translate(x, y);\n }\n\n scale(x: number, y: number): void {\n this.ctx.scale(x, y);\n }\n\n rotate(angle: number): void {\n this.ctx.rotate(angle);\n }\n\n transform(a: number, b: number, c: number, d: number, e: number, f: number): void {\n this.ctx.transform(a, b, c, d, e, f);\n }\n\n beginPath(): void {\n this.ctx.beginPath();\n }\n\n moveTo(x: number, y: number): void {\n this.ctx.moveTo(x, y);\n }\n\n lineTo(x: number, y: number): void {\n this.ctx.lineTo(x, y);\n }\n\n quadraticCurveTo(cx: number, cy: number, x: number, y: number): void {\n this.ctx.quadraticCurveTo(cx, cy, x, y);\n }\n\n bezierCurveTo(c1x: number, c1y: number, c2x: number, c2y: number, x: number, y: number): void {\n this.ctx.bezierCurveTo(c1x, c1y, c2x, c2y, x, y);\n }\n\n arc(x: number, y: number, radius: number, startAngle: number, endAngle: number, counterclockwise = false): void {\n this.ctx.arc(x, y, radius, startAngle, endAngle, counterclockwise);\n }\n\n rect(x: number, y: number, width: number, height: number): void {\n this.ctx.rect(x, y, width, height);\n }\n\n /**\n * Traced with `arcTo` rather than the context's own `roundRect`, for\n * the reason `traceRoundedRect` gives: the newer call is not\n * depended on anywhere else in the renderer and there is nothing to\n * gain by depending on it here.\n */\n roundRect(x: number, y: number, width: number, height: number, radius: number): void {\n const r = Math.min(radius, width / 2, height / 2);\n if (!(r > 0)) {\n this.ctx.rect(x, y, width, height);\n return;\n }\n this.ctx.moveTo(x + r, y);\n this.ctx.arcTo(x + width, y, x + width, y + height, r);\n this.ctx.arcTo(x + width, y + height, x, y + height, r);\n this.ctx.arcTo(x, y + height, x, y, r);\n this.ctx.arcTo(x, y, x + width, y, r);\n this.ctx.closePath();\n }\n\n closePath(): void {\n this.ctx.closePath();\n }\n\n path(d: string): void {\n // Path data is expanded by the recorder, so a target only ever\n // sees the calls it names. Kept for the interface, and correct if\n // a caller ever drives a target directly.\n tracePathData(this, d);\n }\n\n fillColor(color: UiColorValue): void {\n const resolved = this.resolver.color(color);\n this.ctx.fillStyle = resolved === undefined ? 'transparent' : colorToCss(resolved);\n }\n\n fillGradient(gradient: UiGradient, x: number, y: number, width: number, height: number): void {\n const resolved = this.resolver.gradient(gradient);\n if (resolved === undefined) {\n return;\n }\n // `gradientPaint` places the ramp in the rectangle's own\n // coordinates and the origin is added here, which is exactly what\n // `canvasGradient` in the Canvas2D renderer does. One arithmetic,\n // three callers.\n const placed = gradientPaint(resolved, width, height);\n if (placed.kind === 'radial' && !(placed.radius > 0)) {\n return;\n }\n const style =\n placed.kind === 'linear'\n ? this.ctx.createLinearGradient(x + placed.x0, y + placed.y0, x + placed.x1, y + placed.y1)\n : this.ctx.createRadialGradient(x + placed.x0, y + placed.y0, 0, x + placed.x0, y + placed.y0, placed.radius);\n for (const stop of placed.stops) {\n style.addColorStop(stop.offset, colorToCss(stop.color));\n }\n this.ctx.fillStyle = style;\n }\n\n strokeColor(color: UiColorValue): void {\n const resolved = this.resolver.color(color);\n this.ctx.strokeStyle = resolved === undefined ? 'transparent' : colorToCss(resolved);\n }\n\n lineWidth(width: number): void {\n this.ctx.lineWidth = width;\n }\n\n lineCap(cap: PaintLineCap): void {\n this.ctx.lineCap = cap;\n }\n\n lineJoin(join: PaintLineJoin): void {\n this.ctx.lineJoin = join;\n }\n\n miterLimit(limit: number): void {\n this.ctx.miterLimit = limit;\n }\n\n lineDash(segments: readonly number[], offset = 0): void {\n this.ctx.setLineDash(segments);\n this.ctx.lineDashOffset = offset;\n }\n\n alpha(value: number): void {\n this.ctx.globalAlpha *= value;\n }\n\n blur(radius: number): void {\n this.blurRadius = Math.max(0, radius);\n if (this.ctx.filter !== undefined || this.blurRadius > 0) {\n this.ctx.filter = this.blurRadius > 0 ? `blur(${this.blurRadius}px)` : 'none';\n }\n }\n\n fill(rule: PaintFillRule = 'nonzero'): void {\n this.ctx.fill(rule);\n }\n\n stroke(): void {\n this.ctx.stroke();\n }\n\n clip(rule: PaintFillRule = 'nonzero'): void {\n this.ctx.clip(rule);\n }\n\n text(value: string, x: number, y: number, style?: PaintTextStyle): void {\n const size = style?.fontSize ?? DEFAULT_FONT_SIZE;\n const weight = style?.fontWeight ?? DEFAULT_FONT_WEIGHT;\n const family = fontStackFor(style?.fontFamily ?? DEFAULT_FONT_FAMILY);\n this.ctx.font = `${String(weight)} ${size}px ${family}`;\n this.ctx.textAlign = style?.align ?? 'left';\n this.ctx.textBaseline = 'alphabetic';\n this.ctx.fillText(value, x, y);\n }\n\n image(image: UiImage, x: number, y: number, width: number, height: number): void {\n this.ctx.drawImage(image, x, y, width, height);\n }\n}\n","import type { UiNode } from '../graph/UiNode';\nimport type { UiEnvironment } from '../environment/UiEnvironment';\nimport type { LayoutRecord } from '../layout/LayoutRecord';\nimport type { UiImage } from '../properties/UiImage';\nimport { resolveColorValue, resolveGradient } from '../properties/UiThemeColor';\nimport { EMPTY_RECORDING, PaintRecorder, replayPaint, type PaintRecording } from './PaintRecording';\nimport { PaintTarget, type PaintContext2D, type PaintResolver } from './PaintTarget';\nimport { paintValuesEqual, pathValuesEqual, type PaintBox, type UiPaint, type UiPath } from './PaintSurface';\n\n/**\n * The canvas a picture is drawn into, and the bitmap it becomes.\n *\n * `IconCanvas`'s sibling, and injectable for the same two reasons: the\n * suite has no `OffscreenCanvas`, and a host that lacks one should\n * fail by drawing nothing rather than by throwing in a frame.\n *\n * `take()` is synchronous, which is the whole reason the default is\n * `transferToImageBitmap` and not `createImageBitmap`. An asynchronous\n * raster would put the picture a frame behind its inputs and would\n * need a way to ask for another frame from inside a renderer, which no\n * renderer has and none should.\n */\nexport interface PaintCanvas {\n context(): PaintContext2D | null;\n take(): UiImage;\n}\n\nexport type PaintCanvasFactory = (width: number, height: number) => PaintCanvas | null;\n\n/**\n * The largest picture that will be rasterised, per side, in physical\n * pixels.\n *\n * A painted node is sized by the layout, so a full-width waveform on a\n * wide display at two device pixels is already four thousand across,\n * and a node that a bug sized at a hundred thousand would ask for a\n * forty gigabyte bitmap. The cap turns that into a picture that is\n * merely wrong instead of a tab that dies.\n */\nconst MAX_PICTURE_SIDE = 8192;\n\ninterface PaintedSlot {\n picture: UiImage | null;\n recording: PaintRecording;\n paint: UiPaint | undefined;\n path: UiPath | undefined;\n clipPath: string | undefined;\n blur: number | undefined;\n environment: UiEnvironment | null;\n width: number;\n height: number;\n scale: number;\n}\n\n/** What a painted frame did, for `PaintPicture.budget.spec.ts`. */\nexport interface PaintStats {\n /** How many times a painter's `draw` ran. */\n recorded: number;\n /** How many times a recording was turned into a bitmap. */\n rasterized: number;\n /** How many times a renderer asked for a node's picture. */\n resolved: number;\n}\n\n/**\n * The pictures painted nodes have produced, keyed by node.\n *\n * **One cache, shared by both backends, and that is the design.** The\n * obvious alternative is for each renderer to replay the recording in\n * its own vocabulary, which this declines: WebGPU has no path\n * pipeline, so a native replay there would mean tessellation, a second\n * rasteriser and two implementations of every fill rule to keep in\n * step. Rasterising once and handing the same bitmap to both means the\n * two backends cannot disagree about a painted node, because there is\n * nothing for them to disagree about. What the parity gate then checks\n * is what remains: that both place the same picture in the same box,\n * at the same point in paint order, under the same clip and opacity.\n *\n * **The cost follows the change.** A frame that draws a painted node\n * whose inputs, box, scale and theme are unchanged makes no recording\n * and no bitmap; it draws the one already here. The key holds the\n * `paint` and `path` values (compared as the property registry\n * compares them), the box, the device scale, and the node's\n * environment, which a theme swap replaces, so the light and dark\n * toggle repaints a picture without a painter knowing there was a\n * theme.\n *\n * A `WeakMap` rather than a `Map`: a node removed from the tree takes\n * its slot and its bitmap with it, without the graph having to know\n * that pictures exist.\n */\nexport class PaintPictureCache {\n private readonly slots = new WeakMap<UiNode, PaintedSlot>();\n private createCanvas: PaintCanvasFactory;\n readonly stats: PaintStats = { recorded: 0, rasterized: 0, resolved: 0 };\n\n constructor(createCanvas: PaintCanvasFactory = offscreenPaintCanvas) {\n this.createCanvas = createCanvas;\n }\n\n /** Swaps the canvas the rasteriser draws into. For specs and for a host without one. */\n setCanvasFactory(factory: PaintCanvasFactory): void {\n this.createCanvas = factory;\n }\n\n resetStats(): void {\n this.stats.recorded = 0;\n this.stats.rasterized = 0;\n this.stats.resolved = 0;\n }\n\n /**\n * The node's picture at this box and device scale, made if the\n * inputs have moved and reused if they have not.\n *\n * Undefined when the node paints nothing, when the box has no area,\n * or when the host could not give the rasteriser a context, which is\n * how a picture degrades: the rest of the node still draws.\n */\n pictureFor(node: UiNode, rec: LayoutRecord, scale: number): UiImage | undefined {\n this.stats.resolved++;\n const paint = node.properties.get('paint') as UiPaint | undefined;\n const path = node.properties.get('path') as UiPath | undefined;\n if (paint === undefined && path === undefined) {\n return undefined;\n }\n if (!(rec.width > 0) || !(rec.height > 0)) {\n return undefined;\n }\n const clipPath = node.properties.get('clipPath') as string | undefined;\n const blur = node.properties.get('blur') as number | undefined;\n const slot = this.slots.get(node);\n if (\n slot !== undefined &&\n slot.picture !== null &&\n slot.width === rec.width &&\n slot.height === rec.height &&\n slot.scale === scale &&\n slot.environment === node.environment &&\n slot.clipPath === clipPath &&\n slot.blur === blur &&\n paintValuesEqual(slot.paint, paint) &&\n pathValuesEqual(slot.path, path)\n ) {\n return slot.picture;\n }\n\n const box: PaintBox = {\n width: rec.width,\n height: rec.height,\n paddingTop: rec.paddingTop,\n paddingRight: rec.paddingRight,\n paddingBottom: rec.paddingBottom,\n paddingLeft: rec.paddingLeft,\n scale\n };\n const recording = this.record(paint, path, clipPath, blur, box);\n const picture = this.rasterize(node, recording, box);\n // The old bitmap is released now rather than when the collector\n // gets to it: a chart repainting on a stream would otherwise hold\n // every frame it has ever drawn until it did.\n slot?.picture?.close?.();\n this.slots.set(node, {\n picture,\n recording,\n paint,\n path,\n clipPath,\n blur,\n environment: node.environment,\n width: rec.width,\n height: rec.height,\n scale\n });\n return picture ?? undefined;\n }\n\n /**\n * The recording a node's picture was made from.\n *\n * The parity gate and the inspector both want to ask what a painted\n * node actually drew, and a bitmap cannot answer. Empty for a node\n * that has not been painted yet.\n */\n recordingFor(node: UiNode): PaintRecording {\n return this.slots.get(node)?.recording ?? EMPTY_RECORDING;\n }\n\n private record(\n paint: UiPaint | undefined,\n path: UiPath | undefined,\n clipPath: string | undefined,\n blur: number | undefined,\n box: PaintBox\n ): PaintRecording {\n this.stats.recorded++;\n const recorder = new PaintRecorder();\n // `clipPath` and `blur` are properties of the node rather than\n // calls a painter makes, so they wrap everything the node draws:\n // the rounded mask and the frosted panel a design asks for first,\n // without the painter restating them.\n if (clipPath !== undefined) {\n recorder.beginPath();\n recorder.path(clipPath);\n recorder.clip();\n }\n if (blur !== undefined && blur > 0) {\n recorder.blur(blur);\n }\n if (path !== undefined) {\n drawPath(recorder, path, box);\n }\n paint?.draw(recorder, box);\n return recorder.finish();\n }\n\n private rasterize(node: UiNode, recording: PaintRecording, box: PaintBox): UiImage | null {\n if (recording.ops.length === 0) {\n return null;\n }\n const width = Math.min(MAX_PICTURE_SIDE, Math.max(1, Math.round(box.width * box.scale)));\n const height = Math.min(MAX_PICTURE_SIDE, Math.max(1, Math.round(box.height * box.scale)));\n const canvas = this.createCanvas(width, height);\n const ctx = canvas?.context() ?? null;\n if (canvas === null || ctx === null) {\n return null;\n }\n this.stats.rasterized++;\n // The picture is drawn in logical pixels and the one transform\n // here puts it in the bitmap's physical ones, which is the same\n // trick `IconRasterizer` plays with the viewBox: nothing below\n // this line has to know what a device pixel ratio is.\n ctx.scale(box.scale, box.scale);\n replayPaint(recording, new PaintTarget(ctx, resolverFor(node)));\n return canvas.take();\n }\n}\n\n/**\n * The cache the renderers use.\n *\n * Module level, like `FontStacks`, and for the same reason: two\n * backends drawing the same tree have to reach the same one, and\n * threading a cache through `render()` and `buildRenderList()` would\n * make it possible for them not to.\n */\nexport const paintPictures = new PaintPictureCache();\n\n/** A painter's colour values, against the node's own theme. */\nfunction resolverFor(node: UiNode): PaintResolver {\n return {\n color: value => resolveColorValue(node, value),\n gradient: value => resolveGradient(node, value)\n };\n}\n\n/**\n * A `path` property, as calls on a surface.\n *\n * The viewBox is fitted as `object-fit: contain` fits an image, which\n * is what an icon grid expects and what makes a 24-unit path land\n * correctly in a box of any size. Stroke width is in viewBox units\n * too, so a path scaled up keeps its proportions rather than growing a\n * hairline.\n */\nfunction drawPath(surface: PaintRecorder, path: UiPath, box: PaintBox): void {\n const inner = {\n width: Math.max(0, box.width - box.paddingLeft - box.paddingRight),\n height: Math.max(0, box.height - box.paddingTop - box.paddingBottom)\n };\n if (!(inner.width > 0) || !(inner.height > 0)) {\n return;\n }\n surface.save();\n surface.translate(box.paddingLeft, box.paddingTop);\n if (path.viewBox !== undefined && path.viewBox > 0) {\n const unit = Math.min(inner.width / path.viewBox, inner.height / path.viewBox);\n surface.translate((inner.width - path.viewBox * unit) / 2, (inner.height - path.viewBox * unit) / 2);\n surface.scale(unit, unit);\n }\n surface.beginPath();\n surface.path(path.d);\n if (path.fill !== undefined) {\n surface.fillColor(path.fill);\n surface.fill(path.fillRule ?? 'nonzero');\n }\n const strokeWidth = path.strokeWidth ?? 0;\n if (path.stroke !== undefined && strokeWidth > 0) {\n surface.strokeColor(path.stroke);\n surface.lineWidth(strokeWidth);\n surface.lineCap(path.lineCap ?? 'butt');\n surface.lineJoin(path.lineJoin ?? 'miter');\n if (path.miterLimit !== undefined) {\n surface.miterLimit(path.miterLimit);\n }\n if (path.dash !== undefined && path.dash.length > 0) {\n surface.lineDash(path.dash, path.dashOffset ?? 0);\n }\n surface.stroke();\n }\n surface.restore();\n}\n\n/**\n * `OffscreenCanvas` on the main thread and in a worker, which is what\n * lets a picture be made wherever the runtime lives. The same property\n * `IconRasterizer` relies on, and the reason `UiImage` is an\n * `ImageBitmap`: both backends already know how to draw one.\n */\nfunction offscreenPaintCanvas(width: number, height: number): PaintCanvas | null {\n if (typeof OffscreenCanvas !== 'function') {\n return null;\n }\n const canvas = new OffscreenCanvas(width, height);\n return {\n context: () => canvas.getContext('2d') as unknown as PaintContext2D | null,\n // Transferring rather than copying: it hands back the bitmap the\n // canvas already holds and leaves the canvas blank, so a picture\n // costs one allocation instead of two, and costs nothing at all\n // asynchronously.\n take: () => canvas.transferToImageBitmap()\n };\n}\n","import { UiNodeType } from '../../graph/UiNodeType';\nimport type { UiNode } from '../../graph/UiNode';\nimport type { LayoutRecord } from '../../layout/LayoutRecord';\nimport type { Canvas2DContext, Canvas2DGradient } from './Canvas2DContext';\nimport type { CanvasSurface } from './CanvasSurface';\nimport type { ResolvedGradient } from '../../properties/UiGradient';\nimport { gradientPaint } from '../../properties/UiGradient';\nimport { colorToCss, computeObjectFitRect, createPaintState, isPaintVisible, resolvePaintState } from '../PaintState';\nimport type { PaintState } from '../PaintState';\nimport { borderRadiusIsZero, uniformBorderRadius } from '../../properties/UiBorderRadius';\nimport { videoFrameSize } from '../../properties/UiVideo';\nimport type { RenderContext } from '../RenderContext';\nimport {\n buildFontString,\n drawText,\n drawTextLines,\n fillTextRects,\n layoutTextLines,\n textRunBackgrounds,\n textRunDecorations\n} from '../TextRenderer';\nimport { EditableLayout } from '../../editing/EditableLayout';\nimport { lineIndexForOffset } from '../../editing/TextGeometry';\nimport { CARET_WIDTH, caretVisibleAt } from '../../editing/UiEditable';\nimport { paragraphGeometryFrom, selectionRectsIn } from '../../selection/TextSelectionGeometry';\nimport { SCROLLBAR_FADE_MS } from '../../layout/LayoutEngine';\nimport { SCROLLBAR_THICKNESS, scrollbarThumbs } from '../../layout/Scrollbars';\nimport type { LayoutBox } from '../../layout/LayoutTypes';\nimport type { RendererBackend, UiRenderer } from '../UiRenderer';\nimport { drawOverlayShapes } from '../OverlayShapes';\nimport { decorationColor, decorationRect, hasDecorationPhase, type DecorationShape } from '../Decorations';\nimport { ScaledImageCache } from '../ScaledImageCache';\nimport { paintPictures } from '../PaintPicture';\n\nexport interface Canvas2DRendererOptions {\n /**\n * The canvas surface this renderer draws into.\n *\n * Owns the backing store, device pixel ratio and resize; the\n * renderer only reads it per frame. Passed at construction so the\n * renderer can be swapped (e.g. for a WebGPU surface) without the\n * runtime knowing.\n */\n surface: CanvasSurface;\n}\n\n/**\n * Canvas2D rendering backend.\n *\n * Consumes the retained UiNode tree plus LayoutRecords produced by\n * the layout engine and turns them into canvas operations. It owns\n * none of: composition, bindings, layout, scheduling, or dirty\n * state - those live upstream and are the only reason a frame runs.\n *\n * Painting per node (in order):\n *\n * 1. background fill (backgroundColor, rounded rect when radius > 0)\n * 2. background image (image + objectFit)\n * 2b. picture (what a Paint node's `paint`/`path` drew)\n * 3. border (borderWidth/borderColor)\n * 4. decorations (what the node's modifiers drew)\n * 5. children (tree order)\n * 6. foreground text (text + text style)\n * 7. decorations (those marked `after: 'children'`)\n *\n * All geometry is absolute layout-root coordinates. Scroll\n * containers clip to their viewport and translate by\n * (-scrollX, -scrollY); node transforms compose on the current CTM.\n *\n * State isolation: save()/restore() are used exactly when a node\n * introduces opacity, a transform, or a scroll viewport. Flat style\n * fields (fillStyle, font, lineWidth, ...) are assigned before each\n * draw and cannot leak between nodes.\n *\n * The frame strategy is a full clear + full traversal. Off-screen\n * subtrees are culled (while no ancestor transform is active) so\n * scrolling large lists only issues draws for the visible window.\n */\nexport class Canvas2DRenderer implements UiRenderer {\n readonly backend: RendererBackend = 'canvas2d';\n private disposed = false;\n\n /** Scratch for the padded box text is drawn in; reused across nodes. */\n private readonly contentBox: LayoutBox = { x: 0, y: 0, width: 0, height: 0 };\n private readonly paint = createPaintState();\n /**\n * Whose style the shared paint scratch currently holds.\n *\n * `resolvePaintState` folds about thirty properties — several of\n * them inherited, so each is an ancestor walk — into one reused\n * object. A node that paints text resolved twice: once for its own\n * box, and again after the walk into its children, because a child\n * overwrites the scratch before the text is drawn.\n *\n * Only the second one is conditional. A leaf never had a child to\n * clobber it, and neither did a node whose children turned out to be\n * every one of them invisible, culled or lifted — and leaves are\n * most of the text in an application. Recording the owner answers\n * \"is the scratch still mine\" exactly, for one reference compare,\n * where asking `node.firstChild === null` would only approximate it\n * and would go quietly wrong as the early-outs in `renderNode`\n * change. Every write goes through `resolvePaint`, so the answer\n * cannot drift from the truth.\n */\n private paintOwner: UiNode | null = null;\n private cullX = 0;\n private cullY = 0;\n private cullWidth = 0;\n private cullHeight = 0;\n private readonly cullStack: number[] = [];\n /**\n * Copies of images at the size they are drawn.\n *\n * A `drawImage` that resamples is the most expensive call this\n * renderer makes on an engine that resamples on the CPU, and it\n * makes one per picture per frame. See `ScaledImageCache`.\n */\n private readonly scaledImages = new ScaledImageCache();\n /**\n * The lifted nodes met on this frame's walk, with the state they\n * were met in: the matrix and the alpha their ancestors had built\n * up, which is everything about the ancestors a lifted node keeps.\n * Drained after the walk; see `render`.\n */\n private readonly liftedPass: UiNode[] = [];\n\n constructor(private readonly options: Canvas2DRendererOptions) {}\n\n private get surface(): CanvasSurface {\n return this.options.surface;\n }\n\n /** A 2D context needs no asynchronous setup. */\n initialize(): Promise<void> {\n return Promise.resolve();\n }\n\n get isReady(): boolean {\n return !this.disposed;\n }\n\n resize(width: number, height: number, dpr: number): void {\n this.surface.setLogicalSize(width, height, dpr);\n }\n\n dispose(): void {\n this.disposed = true;\n this.scaledImages.dispose();\n }\n\n render(root: UiNode, context: RenderContext): void {\n const ctx = this.surface.getContext2D();\n this.beginFrame(ctx);\n this.cullStack.length = 0;\n this.cullX = 0;\n this.cullY = 0;\n this.cullWidth = this.surface.logicalWidth;\n this.cullHeight = this.surface.logicalHeight;\n this.liftedPass.length = 0;\n // A property the scratch folded last frame may have changed since,\n // so ownership does not carry across frames. Nothing observes it\n // today — every check follows an unconditional resolve of the same\n // node within one `renderNode` — but the field would otherwise be\n // a true statement about the wrong frame.\n this.paintOwner = null;\n this.renderNode(root, context, ctx, true, false);\n this.renderLifted(context, ctx);\n if (context.overlay !== undefined && context.overlay.length > 0) {\n drawOverlayShapes(ctx, context.overlay);\n }\n }\n\n /**\n * Folds a node's style into the shared scratch and records that it\n * is now that node's. The one writer; see `paintOwner`.\n */\n private resolvePaint(node: UiNode): PaintState {\n this.paintOwner = node;\n return resolvePaintState(node, this.paint);\n }\n\n // -------------------------------------------------------------------------\n // Frame setup\n // -------------------------------------------------------------------------\n\n private beginFrame(ctx: Canvas2DContext): void {\n ctx.setTransform(1, 0, 0, 1, 0, 0);\n ctx.clearRect(0, 0, this.surface.physicalWidth, this.surface.physicalHeight);\n if (this.surface.dpr !== 1) {\n // All drawing stays in logical pixels; the backing store is\n // physical = logical × dpr.\n ctx.setTransform(this.surface.dpr, 0, 0, this.surface.dpr, 0, 0);\n }\n }\n\n // -------------------------------------------------------------------------\n // Traversal\n // -------------------------------------------------------------------------\n\n private renderNode(node: UiNode, context: RenderContext, ctx: Canvas2DContext, cull: boolean, lifted: boolean): void {\n const rec = context.layout.recordFor(node);\n if (rec === undefined) {\n return;\n }\n // Visibility from its own two properties rather than from the paint\n // state, and the cull test from the record alone, so that a node\n // this walk is about to discard never pays for the twenty-five or so\n // property resolutions the full state costs. A long list culls most\n // of what it walks, which is where that adds up.\n if (!isPaintVisible(node)) {\n return;\n }\n if (rec.lifted && !lifted) {\n // Held back for the top layer, and held back *before* the cull\n // test: a lifted node is nearly always somewhere its record box\n // is not — that is what it is for — so the box it would be culled\n // by says nothing about where it will be drawn.\n this.liftedPass.push(node);\n return;\n }\n const sticky = rec.stickyOffsetX !== 0 || rec.stickyOffsetY !== 0;\n if (cull && !this.intersectsCull(rec.x + rec.stickyOffsetX, rec.y + rec.stickyOffsetY, rec.width, rec.height)) {\n return;\n }\n\n const paint = this.resolvePaint(node);\n\n // Captured before children reuse the shared scratch below.\n const hasText = paint.text !== undefined;\n\n let saves = 0;\n if (paint.opacity < 1 || paint.hasTransform || sticky) {\n ctx.save();\n saves++;\n if (sticky) {\n // A sticky node is drawn shifted to its scroll container's edge,\n // children included; its record keeps the flow position.\n ctx.translate(rec.stickyOffsetX, rec.stickyOffsetY);\n }\n if (paint.opacity < 1) {\n ctx.globalAlpha *= paint.opacity;\n }\n if (paint.hasTransform) {\n this.applyTransform(ctx, rec, paint);\n }\n }\n\n this.paintBackground(ctx, rec, paint);\n this.paintImage(ctx, rec, paint);\n if (node.type === UiNodeType.Paint) {\n this.paintPicture(ctx, node, rec);\n }\n this.paintBorder(ctx, rec, paint);\n // Decorations sit beside the border, outside the node's own clip:\n // a focus ring's every pixel lies outside the box that would clip\n // it. Ancestors' clips and the node's transform do apply, which is\n // what makes a ring disappear with a scrolled-away row.\n const decorations = node.decorations;\n if (decorations !== null && hasDecorationPhase(decorations, false)) {\n this.paintDecorations(ctx, node, rec, paint, decorations, false);\n }\n\n if (rec.clips) {\n // overflow hidden/scroll/auto and ScrollView: children and the\n // node's own text are clipped to the box (following its corner\n // radius); for a scroll container the children are also\n // translated by the scroll offset.\n ctx.save();\n if (!borderRadiusIsZero(paint.borderRadius)) {\n traceRoundedRect(ctx, rec.x, rec.y, rec.width, rec.height, uniformBorderRadius(paint.borderRadius));\n } else {\n ctx.beginPath();\n ctx.rect(rec.x, rec.y, rec.width, rec.height);\n }\n ctx.clip();\n this.pushCull(rec);\n }\n if (rec.scrollable) {\n ctx.save();\n ctx.translate(-rec.scrollX, -rec.scrollY);\n }\n\n // Culling works in record coordinates; a transform or a sticky shift\n // moves what is drawn away from them, so descendants are not culled.\n const liftedBefore = this.liftedPass.length;\n this.renderChildren(node, context, ctx, cull && !paint.hasTransform && !sticky);\n\n if (rec.scrollable) {\n ctx.restore();\n }\n if (rec.clips) {\n this.popCull();\n }\n\n if (hasText) {\n // Foreground text is painted after children, inside the node's\n // own clip and in its own (unscrolled) space. If the walk below\n // wrote the shared scratch, it now holds some descendant's style\n // and this node's has to be folded again before the text is\n // drawn with it; if nothing wrote, the scratch is still this\n // node's and re-resolving would only spend the thirty property\n // lookups over.\n if (this.paintOwner !== node) {\n this.resolvePaint(node);\n }\n this.paintContent(ctx, rec, this.paint, context);\n }\n if (rec.liftBoundary && this.liftedPass.length > liftedBefore) {\n // A boundary: everything the subtree lifted is drawn here, over\n // the rest of this subtree and inside whatever holds it. The\n // context is back at this node's own state, because every clip\n // and transform the walk opened below it has been restored, so\n // the descendants' clips are gone and this node's is not.\n this.renderLifted(context, ctx, liftedBefore, node);\n }\n\n if (rec.clips) {\n ctx.restore();\n }\n if (decorations !== null && hasDecorationPhase(decorations, true)) {\n // Same argument as the text pass above: the lifted pass and the\n // child walk may both have left, or may both have left alone.\n this.paintDecorations(\n ctx,\n node,\n rec,\n this.paintOwner === node ? this.paint : this.resolvePaint(node),\n decorations,\n true\n );\n }\n if (rec.scrollable) {\n this.paintScrollbars(ctx, rec, context.now ?? performance.now());\n }\n\n while (saves > 0) {\n ctx.restore();\n saves--;\n }\n }\n\n private renderChildren(node: UiNode, context: RenderContext, ctx: Canvas2DContext, cull: boolean): void {\n // zIndex reordered these children: layout recorded the order (with\n // fragments already expanded) so paint and hit testing agree.\n const order = context.layout.recordFor(node)?.paintOrder;\n if (order !== null && order !== undefined) {\n for (const child of order) {\n this.renderNode(child, context, ctx, cull, false);\n }\n return;\n }\n let child = node.firstChild;\n while (child !== null) {\n if (child.type === UiNodeType.Fragment) {\n this.renderChildren(child, context, ctx, cull);\n } else {\n this.renderNode(child, context, ctx, cull, false);\n }\n child = child.nextSibling;\n }\n }\n\n /**\n * The top layer: the nodes that asked for `lift`, drawn after the\n * tree and outside every clip in it.\n *\n * The clips are gone because the walk has unwound: every `save` it\n * made is restored by the time this runs, so the context is back at\n * the frame's base transform with no clipping region at all. What is\n * *not* free is everything else a lifted node keeps, so the ancestor\n * chain is replayed here: their sticky shifts, opacities, transforms\n * and scroll offsets, in the same order `renderNode` applies them.\n * Replaying beats recording the matrix on the way past, because it\n * costs nothing at all on the frames where nothing is lifted, which\n * is nearly every frame.\n */\n private renderLifted(context: RenderContext, ctx: Canvas2DContext, from = 0, boundary: UiNode | null = null): void {\n if (this.liftedPass.length <= from) {\n return;\n }\n // Walked by index rather than iterated: a lifted node inside a\n // lifted subtree is appended while this runs, and it belongs after\n // the one that carried it, as paint order says.\n const dpr = this.surface.dpr;\n for (let i = from; i < this.liftedPass.length; i++) {\n const node = this.liftedPass[i]!;\n ctx.save();\n if (boundary === null) {\n // The frame's own base: every clip is unwound and the walk is\n // over, so this is the top of everything.\n ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n }\n // From the boundary, or from the root when there is none. The\n // boundary's own transform and clip are already in force, so\n // only what lies below it is replayed.\n this.applyAncestors(node, context, ctx, boundary);\n // No culling: the ancestors' cull rectangles have been unwound\n // with their clips, and the node is drawn wherever its transform\n // puts it.\n this.renderNode(node, context, ctx, false, true);\n ctx.restore();\n }\n this.liftedPass.length = from;\n }\n\n /** Everything between the boundary (or the root) and a lifted node. */\n private applyAncestors(\n node: UiNode,\n context: RenderContext,\n ctx: Canvas2DContext,\n boundary: UiNode | null = null\n ): void {\n const chain: UiNode[] = [];\n for (let parent = node.parent; parent !== null && parent !== boundary; parent = parent.parent) {\n chain.push(parent);\n }\n for (let i = chain.length - 1; i >= 0; i--) {\n const ancestor = chain[i]!;\n const rec = context.layout.recordFor(ancestor);\n if (rec === undefined) {\n // A fragment: no box, no transform, nothing to apply.\n continue;\n }\n // Through the helper, like every other write: this leaves an\n // *ancestor's* style in the scratch, and a check further up the\n // walk that believed otherwise would paint text in it.\n const paint = this.resolvePaint(ancestor);\n if (rec.stickyOffsetX !== 0 || rec.stickyOffsetY !== 0) {\n ctx.translate(rec.stickyOffsetX, rec.stickyOffsetY);\n }\n if (paint.opacity < 1) {\n ctx.globalAlpha *= paint.opacity;\n }\n if (paint.hasTransform) {\n this.applyTransform(ctx, rec, paint);\n }\n if (rec.scrollable) {\n ctx.translate(-rec.scrollX, -rec.scrollY);\n }\n }\n }\n\n // -------------------------------------------------------------------------\n // Painting\n // -------------------------------------------------------------------------\n\n private paintBackground(ctx: Canvas2DContext, rec: LayoutRecord, paint: PaintState): void {\n if (paint.backgroundColor !== undefined) {\n ctx.fillStyle = colorToCss(paint.backgroundColor);\n this.fillBox(ctx, rec, paint);\n }\n // The gradient goes over the colour and under the image, which is\n // where CSS puts a `background-image`. Both are the node's own box,\n // so a node with both pays for two fills, as it would in a browser.\n if (paint.backgroundGradient !== undefined) {\n const style = canvasGradient(ctx, paint.backgroundGradient, rec);\n if (style !== undefined) {\n ctx.fillStyle = style;\n this.fillBox(ctx, rec, paint);\n }\n }\n }\n\n /** The node's box, following its corner radius. */\n private fillBox(ctx: Canvas2DContext, rec: LayoutRecord, paint: PaintState): void {\n if (!borderRadiusIsZero(paint.borderRadius)) {\n traceRoundedRect(ctx, rec.x, rec.y, rec.width, rec.height, uniformBorderRadius(paint.borderRadius));\n ctx.fill();\n } else {\n ctx.fillRect(rec.x, rec.y, rec.width, rec.height);\n }\n }\n\n /**\n * The image is clipped to the node's (rounded) box, as CSS clips\n * `object-fit`: `cover` and `none` produce a rectangle larger than\n * the box, and only the box shows.\n */\n private paintImage(ctx: Canvas2DContext, rec: LayoutRecord, paint: PaintState): void {\n // A video draws exactly where an image would, under the same\n // object-fit and the same rounded clip — the only difference is\n // where the pixels came from, which `drawImage` does not care\n // about. It wins over a still on the same node: an element with\n // both has a poster it has finished with.\n const video = paint.video;\n const source = video?.frame ?? paint.image;\n if (source === undefined || source === null) {\n return;\n }\n const size =\n video === undefined ? { width: paint.image!.width, height: paint.image!.height } : videoFrameSize(video);\n const rect = computeObjectFitRect(paint.objectFit, size.width, size.height, rec);\n if (rect.width <= 0 || rect.height <= 0) {\n return;\n }\n const overflows =\n rect.x < rec.x ||\n rect.y < rec.y ||\n rect.x + rect.width > rec.x + rec.width ||\n rect.y + rect.height > rec.y + rec.height;\n const rounded = !borderRadiusIsZero(paint.borderRadius);\n // Only a still is worth a pre-scaled copy. A video's frame is a\n // different object every time, so a copy of one could never be\n // reused; the saving there is made in `VideoResolver` instead, by\n // converting each decoded frame once rather than on every draw.\n const still = video === undefined ? paint.image : undefined;\n const drawn = still === undefined || still === null ? source : this.scaledFor(ctx, still, rect.width, rect.height);\n if (!overflows && !rounded) {\n ctx.drawImage(drawn, rect.x, rect.y, rect.width, rect.height);\n return;\n }\n ctx.save();\n traceRoundedRect(ctx, rec.x, rec.y, rec.width, rec.height, rounded ? uniformBorderRadius(paint.borderRadius) : 0);\n ctx.clip();\n ctx.drawImage(drawn, rect.x, rect.y, rect.width, rect.height);\n ctx.restore();\n }\n\n /**\n * What the node's `paint` or `path` drew, as one image the size of\n * the box.\n *\n * The picture is made by `PaintPicture.ts` when the painter's inputs\n * move and reused otherwise, so a still frame costs this one\n * `drawImage` and nothing else. It is drawn at the device scale\n * rather than at the node's full transform scale, which is what\n * `PaintSurface` promises a painter: a node a morph is scaling is\n * resampled for the length of the morph, exactly as a picture on it\n * would be, instead of being redrawn sixty times.\n *\n * The WebGPU backend draws the same bitmap in the same box, because\n * it asks the same cache for it. That is the whole of the parity\n * story for a painted node.\n */\n private paintPicture(ctx: Canvas2DContext, node: UiNode, rec: LayoutRecord): void {\n const picture = paintPictures.pictureFor(node, rec, this.surface.dpr);\n if (picture === undefined) {\n return;\n }\n ctx.drawImage(picture, rec.x, rec.y, rec.width, rec.height);\n }\n\n /**\n * The image to draw for a destination `width` x `height` in the\n * units the current transform is in.\n *\n * The cache works in device pixels, because a copy only saves the\n * resample when it is the size the backing store actually receives.\n * That is the box under the whole current transform, not under the\n * device pixel ratio alone: a node a morph is scaling covers a\n * different number of pixels every frame, and a copy made for the\n * untransformed size would be resampled again on the way down.\n */\n private scaledFor(ctx: Canvas2DContext, source: ImageBitmap, width: number, height: number): ImageBitmap {\n const transform = ctx.getTransform?.();\n const scaleX = transform === undefined ? this.surface.dpr : Math.hypot(transform.a, transform.b);\n const scaleY = transform === undefined ? this.surface.dpr : Math.hypot(transform.c, transform.d);\n return this.scaledImages.resolve(source, width * scaleX, height * scaleY);\n }\n\n /**\n * Borders lie inside the box, as CSS draws them and as the WebGPU\n * backend's border band does: the stroke is centred on a path inset\n * by half its width, so its outer edge is the box edge.\n */\n private paintBorder(ctx: Canvas2DContext, rec: LayoutRecord, paint: PaintState): void {\n if (paint.borderWidth <= 0) {\n return;\n }\n const inset = paint.borderWidth / 2;\n const x = rec.x + inset;\n const y = rec.y + inset;\n const width = Math.max(0, rec.width - paint.borderWidth);\n const height = Math.max(0, rec.height - paint.borderWidth);\n ctx.strokeStyle = paint.borderColor !== undefined ? colorToCss(paint.borderColor) : '#000';\n ctx.lineWidth = paint.borderWidth;\n ctx.lineJoin = 'round';\n if (!borderRadiusIsZero(paint.borderRadius)) {\n traceRoundedRect(ctx, x, y, width, height, Math.max(0, uniformBorderRadius(paint.borderRadius) - inset));\n ctx.stroke();\n } else {\n ctx.strokeRect(x, y, width, height);\n }\n }\n\n /**\n * The shapes the node's modifiers put on it, in modifier order.\n *\n * The geometry and the colour come from `Decorations.ts` rather than\n * from here, because the WebGPU backend asks the same two questions\n * and a second copy of either is a way for the two to drift.\n */\n private paintDecorations(\n ctx: Canvas2DContext,\n node: UiNode,\n rec: LayoutRecord,\n paint: PaintState,\n shapes: readonly DecorationShape[],\n after: boolean\n ): void {\n const nodeRadius = uniformBorderRadius(paint.borderRadius);\n for (const shape of shapes) {\n if ((shape.after === 'children') !== after) {\n continue;\n }\n const color = decorationColor(node, shape);\n if (color === undefined) {\n continue;\n }\n const box = decorationRect(shape, rec, nodeRadius);\n if (box.width <= 0 || box.height <= 0) {\n continue;\n }\n if (shape.kind === 'fill') {\n ctx.fillStyle = colorToCss(color);\n if (box.radius > 0) {\n traceRoundedRect(ctx, box.x, box.y, box.width, box.height, box.radius);\n ctx.fill();\n } else {\n ctx.fillRect(box.x, box.y, box.width, box.height);\n }\n continue;\n }\n if (shape.lineWidth <= 0) {\n continue;\n }\n // The band lies inside the shape's box, as a border does: the\n // stroke is centred on a path inset by half its width.\n const inset = shape.lineWidth / 2;\n ctx.strokeStyle = colorToCss(color);\n ctx.lineWidth = shape.lineWidth;\n ctx.lineJoin = 'round';\n const x = box.x + inset;\n const y = box.y + inset;\n const width = Math.max(0, box.width - shape.lineWidth);\n const height = Math.max(0, box.height - shape.lineWidth);\n if (box.radius > 0) {\n traceRoundedRect(ctx, x, y, width, height, Math.max(0, box.radius - inset));\n ctx.stroke();\n } else {\n ctx.strokeRect(x, y, width, height);\n }\n }\n }\n\n private paintContent(ctx: Canvas2DContext, rec: LayoutRecord, paint: PaintState, context: RenderContext): void {\n if (paint.text !== undefined) {\n // Text lives in the content box: layout sized the paragraph inside\n // the padding, so paint must place it there too. A field also\n // scrolls its own text — the offset is zero for everything else —\n // and the node's clip is already open, so the line is cut at the\n // box rather than painted over what is beside it.\n this.contentBox.x = rec.x + rec.paddingLeft - rec.scrollX;\n this.contentBox.y = rec.y + rec.paddingTop - rec.scrollY;\n this.contentBox.width = Math.max(0, rec.width - rec.paddingLeft - rec.paddingRight);\n this.contentBox.height = Math.max(0, rec.height - rec.paddingTop - rec.paddingBottom);\n if (paint.editor !== undefined) {\n this.paintEditable(ctx, paint, context);\n return;\n }\n if (paint.textSelection !== undefined || paint.textMatches !== undefined) {\n this.paintHighlightedText(ctx, paint, context);\n return;\n }\n drawText(ctx, this.contentBox, paint, context.text);\n }\n }\n\n /**\n * Static text with part of it highlighted: find matches, then the\n * selection over them, then the glyphs — so the active match, which\n * is both, reads as the strongest. The lines are laid out once and\n * shared, so a highlighted paragraph is measured no more often than a\n * plain one.\n */\n private paintHighlightedText(ctx: Canvas2DContext, paint: PaintState, context: RenderContext): void {\n const lines = layoutTextLines(this.contentBox, paint, context.text);\n const geometry = paragraphGeometryFrom(lines, paint.text!, this.contentBox, paint, context.text);\n // A run's own background is under the highlights, as a CSS inline\n // background is under a selection.\n fillTextRects(ctx, textRunBackgrounds(lines, paint));\n if (paint.textMatches !== undefined) {\n ctx.fillStyle = colorToCss(paint.matchColor);\n for (const range of paint.textMatches) {\n for (const box of selectionRectsIn(geometry, range.start, range.end)) {\n ctx.fillRect(box.x, box.y, box.width, box.height);\n }\n }\n }\n if (paint.textSelection !== undefined) {\n ctx.fillStyle = colorToCss(paint.selectionColor);\n for (const box of selectionRectsIn(geometry, paint.textSelection.start, paint.textSelection.end)) {\n ctx.fillRect(box.x, box.y, box.width, box.height);\n }\n }\n drawTextLines(\n ctx,\n lines,\n buildFontString(paint),\n colorToCss(paint.textColor),\n paint.letterSpacing,\n paint.rtl,\n paint\n );\n fillTextRects(ctx, textRunDecorations(lines, paint));\n }\n\n /**\n * An editable: the selection behind the text, the text (or the\n * placeholder while it is empty), the underline of an IME composition,\n * and the caret — only while focused, and in the lit half of its\n * blink. The geometry is `EditableLayout`'s, the same the input\n * layer places the caret with.\n */\n private paintEditable(ctx: Canvas2DContext, paint: PaintState, context: RenderContext): void {\n const model = paint.editor!;\n const layout = new EditableLayout(model, this.contentBox, paint, context.text);\n // A run's own background goes under the selection, as a CSS inline\n // background goes under one. Nothing is drawn here unless the\n // field was given runs, which almost none are.\n fillTextRects(ctx, textRunBackgrounds(layout.lines, paint));\n if (model.focused && !model.collapsed) {\n ctx.fillStyle = colorToCss(paint.selectionColor);\n for (const box of layout.selectionBoxes()) {\n ctx.fillRect(box.x, box.y, box.width, box.height);\n }\n }\n if (layout.placeholderLines.length > 0) {\n drawTextLines(\n ctx,\n layout.placeholderLines,\n buildFontString(paint),\n colorToCss(paint.placeholderColor),\n paint.letterSpacing,\n paint.rtl\n );\n } else {\n // `paint` last: that is what turns this into a run-by-run draw\n // for a field that was given runs, and changes nothing for one\n // that was not.\n drawTextLines(\n ctx,\n layout.lines,\n buildFontString(paint),\n colorToCss(paint.textColor),\n paint.letterSpacing,\n paint.rtl,\n paint\n );\n fillTextRects(ctx, textRunDecorations(layout.lines, paint));\n }\n if (model.composing) {\n ctx.fillStyle = colorToCss(paint.textColor);\n for (const box of layout.compositionBoxes()) {\n const line = layout.lines[lineIndexForOffset(layout.lines, model.composition!.start)];\n const underlineY = Math.round(line.baselineY + 1);\n ctx.fillRect(box.x, underlineY, box.width, 1);\n }\n }\n if (model.focused && model.collapsed && caretVisibleAt(model, context.now ?? performance.now())) {\n const caret = layout.caretRect();\n ctx.fillStyle = colorToCss(paint.caretColor);\n ctx.fillRect(Math.round(caret.x), caret.y, CARET_WIDTH, caret.height);\n }\n }\n\n private applyTransform(ctx: Canvas2DContext, rec: LayoutRecord, paint: PaintState): void {\n const transform = paint.transform;\n const originX = rec.x + transform.x;\n const originY = rec.y + transform.y;\n // Outside the pivot dance, so it moves the node rather than moving\n // where it turns. See `UiTransform` for the difference.\n if (transform.translateX !== 0 || transform.translateY !== 0) {\n ctx.translate(transform.translateX, transform.translateY);\n }\n ctx.translate(originX, originY);\n if (transform.rotation !== 0) {\n ctx.rotate(transform.rotation);\n }\n if (transform.scaleX !== 1 || transform.scaleY !== 1) {\n ctx.scale(transform.scaleX, transform.scaleY);\n }\n ctx.translate(-originX, -originY);\n }\n\n // -------------------------------------------------------------------------\n // Bounds culling\n // -------------------------------------------------------------------------\n\n private intersectsCull(x: number, y: number, width: number, height: number): boolean {\n if (this.cullWidth <= 0 || this.cullHeight <= 0) {\n return false;\n }\n return (\n x < this.cullX + this.cullWidth &&\n this.cullX < x + width &&\n y < this.cullY + this.cullHeight &&\n this.cullY < y + height\n );\n }\n\n /**\n * Intersects the visible region with a scroll viewport and shifts\n * by its scroll offset, so child boxes (absolute, pre-scroll) can\n * be tested against the region their screen pixels occupy.\n */\n /**\n * Overlay scrollbars: a thin rounded thumb along the end edge of each\n * overflowing axis, sized by viewport/content and placed by the\n * scroll offset. Shown while scrolling and for a moment after, fading\n * out over the last part of that time.\n */\n private paintScrollbars(ctx: Canvas2DContext, rec: LayoutRecord, now: number): void {\n const remaining = rec.scrollbarVisibleUntil - now;\n if (remaining <= 0) {\n return;\n }\n const alpha = Math.min(1, remaining / SCROLLBAR_FADE_MS) * 0.55;\n ctx.fillStyle = `rgba(128,128,128,${alpha.toFixed(3)})`;\n const { vertical, horizontal } = scrollbarThumbs(rec);\n for (const bar of [vertical, horizontal]) {\n if (bar === null) {\n continue;\n }\n const { x, y, width, height } = bar.thumb;\n traceRoundedRect(ctx, x, y, width, height, SCROLLBAR_THICKNESS / 2);\n ctx.fill();\n }\n }\n\n private pushCull(rec: LayoutRecord): void {\n const right = Math.min(this.cullX + this.cullWidth, rec.x + rec.width);\n const bottom = Math.min(this.cullY + this.cullHeight, rec.y + rec.height);\n const left = Math.max(this.cullX, rec.x);\n const top = Math.max(this.cullY, rec.y);\n const width = Math.max(0, right - left);\n const height = Math.max(0, bottom - top);\n this.cullStack.push(this.cullX, this.cullY, this.cullWidth, this.cullHeight);\n this.cullX = left + rec.scrollX;\n this.cullY = top + rec.scrollY;\n this.cullWidth = width;\n this.cullHeight = height;\n }\n\n private popCull(): void {\n this.cullHeight = this.cullStack.pop() ?? 0;\n this.cullWidth = this.cullStack.pop() ?? 0;\n this.cullY = this.cullStack.pop() ?? 0;\n this.cullX = this.cullStack.pop() ?? 0;\n }\n}\n\n/**\n * A `CanvasGradient` for the node's box, or undefined when the gradient\n * covers nothing (a zero radius, or a box with no area).\n *\n * `gradientPaint` places the gradient in the box's own coordinates and\n * the box's origin is added here, so the arithmetic that decides where\n * a gradient line runs is the one the WebGPU builder uses too.\n */\nfunction canvasGradient(\n ctx: Canvas2DContext,\n gradient: ResolvedGradient,\n rec: LayoutRecord\n): Canvas2DGradient | undefined {\n const placed = gradientPaint(gradient, rec.width, rec.height);\n if (placed.kind === 'radial' && !(placed.radius > 0)) {\n return undefined;\n }\n const style =\n placed.kind === 'linear'\n ? ctx.createLinearGradient(rec.x + placed.x0, rec.y + placed.y0, rec.x + placed.x1, rec.y + placed.y1)\n : ctx.createRadialGradient(\n rec.x + placed.x0,\n rec.y + placed.y0,\n 0,\n rec.x + placed.x0,\n rec.y + placed.y0,\n placed.radius\n );\n for (const stop of placed.stops) {\n style.addColorStop(stop.offset, colorToCss(stop.color));\n }\n return style;\n}\n\n/**\n * Emits a rounded-rectangle path (clamped radius) onto a context.\n *\n * Uses arcTo instead of roundRect so the renderer does not depend\n * on the newer roundRect API. The radius is clamped to half the\n * smaller box dimension; radius <= 0 falls back to a plain rect.\n */\nexport function traceRoundedRect(\n ctx: Canvas2DContext,\n x: number,\n y: number,\n width: number,\n height: number,\n radius: number\n): void {\n const r = Math.min(radius, width / 2, height / 2);\n if (r <= 0) {\n ctx.beginPath();\n ctx.rect(x, y, width, height);\n return;\n }\n ctx.beginPath();\n ctx.moveTo(x + r, y);\n ctx.arcTo(x + width, y, x + width, y + height, r);\n ctx.arcTo(x + width, y + height, x, y + height, r);\n ctx.arcTo(x, y + height, x, y, r);\n ctx.arcTo(x, y, x + width, y, r);\n ctx.closePath();\n}\n","import type { Canvas2DContext } from './Canvas2DContext';\n\n/**\n * Something that can host a 2D drawing surface.\n *\n * Covers both HTMLCanvasElement (main thread) and OffscreenCanvas\n * (Worker) without naming either type, so the rendering core stays\n * DOM-free. Both canvas types satisfy this structurally.\n */\nexport interface CanvasHost {\n width: number;\n height: number;\n getContext(contextId: '2d'): CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D | null;\n}\n\n/**\n * Logical/physical viewport bookkeeping for a canvas surface.\n *\n * Layout and drawing operate in logical (CSS-like) pixels; the\n * backing store holds physical = logical × dpr. Resizing the\n * surface never touches UiNodes, layout records, or bindings - the\n * runtime is told about the new viewport through its existing\n * constraint mechanism and simply renders the next frame.\n */\nexport class CanvasSurface {\n private logicalW = 0;\n private logicalH = 0;\n private pixelRatio = 1;\n private context: Canvas2DContext | null = null;\n\n constructor(private readonly canvas: CanvasHost) {}\n\n get logicalWidth(): number {\n return this.logicalW;\n }\n\n get logicalHeight(): number {\n return this.logicalH;\n }\n\n get dpr(): number {\n return this.pixelRatio;\n }\n\n get physicalWidth(): number {\n return this.canvas.width;\n }\n\n get physicalHeight(): number {\n return this.canvas.height;\n }\n\n /**\n * The 2D context for the backing store, acquired lazily.\n */\n getContext2D(): Canvas2DContext {\n if (this.context === null) {\n this.context = this.acquireContext();\n }\n return this.context;\n }\n\n private acquireContext(): Canvas2DContext {\n // The two real context types are structurally compatible with\n // Canvas2DContext; the widening lives at this boundary only.\n const context = this.canvas.getContext('2d') as unknown as Canvas2DContext;\n if (context === null) {\n throw new Error('CanvasSurface: canvas 2D context is unavailable.');\n }\n return context;\n }\n\n /**\n * Resizes the backing store to logical × dpr.\n *\n * The canvas backing store is only reassigned when the physical\n * size actually changes; reassigning resets context state, so\n * unchanged frames are not disturbed.\n */\n setLogicalSize(width: number, height: number, dpr: number = 1): void {\n this.logicalW = width;\n this.logicalH = height;\n this.pixelRatio = dpr;\n const physicalWidth = Math.max(1, Math.round(width * dpr));\n const physicalHeight = Math.max(1, Math.round(height * dpr));\n if (this.canvas.width !== physicalWidth || this.canvas.height !== physicalHeight) {\n this.canvas.width = physicalWidth;\n this.canvas.height = physicalHeight;\n // A backing-store resize resets the context state, so an\n // already-cached context is stale. Reacquire immediately so\n // the next frame starts from a clean context; when no context\n // was ever acquired, stay lazy.\n if (this.context !== null) {\n this.context = this.acquireContext();\n }\n }\n }\n}\n\n/**\n * Wraps any canvas host (HTMLCanvasElement, OffscreenCanvas, or a\n * test double) in the logical/physical viewport bookkeeping.\n */\nexport function createCanvasSurface(host: CanvasHost): CanvasSurface {\n return new CanvasSurface(host);\n}\n"],"mappings":"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"}