gesso-core 0.5.0 → 0.6.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.
@@ -1400,6 +1400,7 @@ const lightColors = {
1400
1400
  border: rgb8(229, 231, 235),
1401
1401
  shadow: rgb8(17, 24, 39, 41),
1402
1402
  placeholder: rgb8(240, 241, 244),
1403
+ scrim: rgb8(17, 24, 39, 102),
1403
1404
  controlBackground: UiBasicColors.white,
1404
1405
  controlBackgroundHovered: rgb8(243, 244, 246),
1405
1406
  controlBackgroundPressed: rgb8(229, 231, 235),
@@ -1422,6 +1423,7 @@ const darkColors = {
1422
1423
  border: rgb8(42, 46, 54),
1423
1424
  shadow: rgb8(0, 0, 0, 128),
1424
1425
  placeholder: rgb8(37, 41, 48),
1426
+ scrim: rgb8(0, 0, 0, 153),
1425
1427
  controlBackground: rgb8(26, 29, 35),
1426
1428
  controlBackgroundHovered: rgb8(35, 39, 46),
1427
1429
  controlBackgroundPressed: rgb8(44, 49, 57),
@@ -2068,6 +2070,7 @@ const SURFACES = /* @__PURE__ */ new Set([
2068
2070
  "background",
2069
2071
  "surface",
2070
2072
  "shadow",
2073
+ "scrim",
2071
2074
  "controlBackground",
2072
2075
  "controlBackgroundHovered",
2073
2076
  "controlBackgroundPressed",
@@ -2612,6 +2615,25 @@ const UiEnvironmentKeys = {
2612
2615
  defaultValue: defaultTextStyle,
2613
2616
  compare: textStylesEqual
2614
2617
  }),
2618
+ /**
2619
+ * The text colour a subtree inherits: the `color` of the nearest
2620
+ * ancestor that set one, or the colour of the nearest `textStyle`,
2621
+ * whichever is closer.
2622
+ *
2623
+ * Its own key rather than a field of `textStyle`, because what an
2624
+ * ancestor sets is often a palette name, and a name has to travel
2625
+ * down unresolved: it is looked up against the theme where it is
2626
+ * painted, so `color="text"` beside a `theme` means that theme's
2627
+ * text, and a card under it that provides another theme gets that
2628
+ * theme's. A `UiTextStyle` holds a resolved `UiColor`, which would
2629
+ * have fixed the name to whichever theme was in scope where it was
2630
+ * written.
2631
+ */
2632
+ color: createEnvironmentKey({
2633
+ name: "color",
2634
+ defaultValue: defaultTextStyle.color,
2635
+ compare: colorValuesEqual
2636
+ }),
2615
2637
  contentColor: createEnvironmentKey({
2616
2638
  name: "contentColor",
2617
2639
  defaultValue: UiBasicColors.black,
@@ -3809,6 +3831,19 @@ const UiProperties = {
3809
3831
  inherited: false,
3810
3832
  affects: L
3811
3833
  }),
3834
+ /**
3835
+ * The part of the anchor to be placed beside, in the anchor's own
3836
+ * coordinates (from its border box's top left): a character in a
3837
+ * field, the word being typed. The node is placed against that
3838
+ * rectangle as it would be against the whole anchor, and follows the
3839
+ * anchor through scrolling in the same way. Ignored without `anchor`.
3840
+ */
3841
+ anchorRect: defineProperty({
3842
+ name: "anchorRect",
3843
+ defaultValue: void 0,
3844
+ inherited: false,
3845
+ affects: L
3846
+ }),
3812
3847
  /** Gap between an anchored node and its anchor. */
3813
3848
  anchorOffset: defineProperty({
3814
3849
  name: "anchorOffset",
@@ -3864,15 +3899,22 @@ const UiProperties = {
3864
3899
  compare: gradientsEqual,
3865
3900
  validate: validateGradient
3866
3901
  }),
3902
+ /**
3903
+ * The text colour, inherited by everything below that sets none.
3904
+ *
3905
+ * It is a provider as well: `UiGraph` puts the value down
3906
+ * `UiEnvironmentKeys.color`, which a text style also writes, so the
3907
+ * nearer of the two wins. A palette name travels unresolved and is
3908
+ * looked up where it is painted. `affects` stays `Paint`, because
3909
+ * the graph re-provides it itself, and re-providing a colour costs
3910
+ * the subtree a repaint and nothing more.
3911
+ */
3867
3912
  color: defineProperty({
3868
3913
  name: "color",
3869
3914
  defaultValue: UiBasicColors.black,
3870
3915
  inherited: true,
3871
3916
  affects: P,
3872
- environmentKey: UiEnvironmentKeys.textStyle,
3873
- resolveFromEnvironment: (value) => {
3874
- return value.color;
3875
- },
3917
+ environmentKey: UiEnvironmentKeys.color,
3876
3918
  compare: colorValuesEqual
3877
3919
  }),
3878
3920
  borderColor: defineProperty({
@@ -4306,6 +4348,28 @@ const UiProperties = {
4306
4348
  affects: S
4307
4349
  }),
4308
4350
  /**
4351
+ * The node this one shows or changes: the list a combobox's field
4352
+ * opens, the panel a tab switches to. The node should be a record of
4353
+ * its own (a `listbox`, a `tabpanel`); see `aria-controls`.
4354
+ */
4355
+ controls: defineProperty({
4356
+ name: "controls",
4357
+ defaultValue: void 0,
4358
+ inherited: false,
4359
+ affects: S
4360
+ }),
4361
+ /**
4362
+ * What a field offers as it's typed into: `list` for a combobox whose
4363
+ * list suggests, `inline` for a field that fills in the rest of the
4364
+ * word, `both`. See `aria-autocomplete`.
4365
+ */
4366
+ autocomplete: defineProperty({
4367
+ name: "autocomplete",
4368
+ defaultValue: void 0,
4369
+ inherited: false,
4370
+ affects: S
4371
+ }),
4372
+ /**
4309
4373
  * How deep a treeitem sits, 1 for a root. A tree is rendered as a
4310
4374
  * flat list of rows — it must be, to be virtualized — so the nesting
4311
4375
  * exists nowhere else for a reader to find.
@@ -4711,7 +4775,166 @@ function propertyValuesEqualByName(name, a, b) {
4711
4775
  return Object.is(a, b);
4712
4776
  }
4713
4777
  //#endregion
4778
+ //#region src/properties/UiPropertyResolver.ts
4779
+ /**
4780
+ * Resolves a property value for a node.
4781
+ *
4782
+ * Resolution order:
4783
+ *
4784
+ * 1. The value explicitly specified on the node.
4785
+ * 2. The value inherited from the node's scoped environment.
4786
+ * 3. The property definition's default value.
4787
+ *
4788
+ * The resolver does not allocate and is safe to call from hot paths
4789
+ * such as layout and paint.
4790
+ */
4791
+ function resolveProperty(node, definition) {
4792
+ const specified = node.properties.get(definition.name);
4793
+ if (specified !== void 0) return specified;
4794
+ if (definition.inherited && node.environment !== null) {
4795
+ const environmentKey = definition.environmentKey;
4796
+ if (environmentKey !== void 0) {
4797
+ const envValue = node.environment.get(environmentKey);
4798
+ if (definition.resolveFromEnvironment !== void 0) return definition.resolveFromEnvironment(envValue);
4799
+ return envValue;
4800
+ }
4801
+ const fallback = node.environment.get(createFallbackKey(definition));
4802
+ if (fallback !== void 0) return fallback;
4803
+ }
4804
+ return definition.defaultValue;
4805
+ }
4806
+ /**
4807
+ * Resolves a property by name.
4808
+ *
4809
+ * Returns undefined when no definition exists; callers that know
4810
+ * the property exists should use resolveProperty() with the
4811
+ * definition for stronger typing.
4812
+ */
4813
+ function resolvePropertyByName(node, name) {
4814
+ const definition = findPropertyDefinition(name);
4815
+ if (definition === void 0) return;
4816
+ return resolveProperty(node, definition);
4817
+ }
4818
+ /**
4819
+ * Resolves a numeric property, returning undefined when the value
4820
+ * is missing or not a finite number.
4821
+ */
4822
+ function resolveNumber(node, name) {
4823
+ const value = resolvePropertyByName(node, name);
4824
+ if (typeof value === "number" && Number.isFinite(value)) return value;
4825
+ }
4826
+ /**
4827
+ * Resolves a string property, returning undefined when the value is
4828
+ * missing or not a non-empty string.
4829
+ */
4830
+ function resolveString(node, name) {
4831
+ const value = resolvePropertyByName(node, name);
4832
+ if (typeof value === "string" && value.length > 0) return value;
4833
+ }
4834
+ /**
4835
+ * Resolves a boolean property, returning undefined when the value
4836
+ * is missing or not a boolean.
4837
+ */
4838
+ function resolveBoolean(node, name) {
4839
+ const value = resolvePropertyByName(node, name);
4840
+ if (typeof value === "boolean") return value;
4841
+ }
4842
+ /**
4843
+ * Lazily creates a fallback environment key that matches the
4844
+ * property name. The key is cached so repeated resolutions of the
4845
+ * same property do not allocate.
4846
+ */
4847
+ const fallbackKeys = /* @__PURE__ */ new Map();
4848
+ function createFallbackKey(definition) {
4849
+ let key = fallbackKeys.get(definition.name);
4850
+ if (key === void 0) {
4851
+ key = {
4852
+ name: definition.name,
4853
+ defaultValue: definition.defaultValue,
4854
+ compare: definition.compare
4855
+ };
4856
+ fallbackKeys.set(definition.name, key);
4857
+ }
4858
+ return key;
4859
+ }
4860
+ //#endregion
4861
+ //#region src/properties/UiTextFont.ts
4862
+ /**
4863
+ * `line-height: normal`: the factor of the font size a line takes when
4864
+ * no line height is set. Shared by ParagraphLayout and PaintState.
4865
+ */
4866
+ const DEFAULT_LINE_HEIGHT_FACTOR = 1.2;
4867
+ /**
4868
+ * Resolves a node's font the one way layout and paint both use.
4869
+ *
4870
+ * Font size, family, weight and letter spacing inherit through the
4871
+ * environment's text style. Line height is the subtle one: a text
4872
+ * style carries a line height that belongs with its font size, so a
4873
+ * node that inherits the style takes it whole. A node that sets its
4874
+ * own `fontSize` without a `lineHeight` gets a normal line height for
4875
+ * that size, `fontSize × 1.2`, rather than the inherited pixel value
4876
+ * sized for a different font — the inherited 16.8px of the default
4877
+ * style is right for 14px text and wrong for 22px. An explicit
4878
+ * `lineHeight` always wins.
4879
+ *
4880
+ * Before this, layout read the raw props (unset line height → ×1.2)
4881
+ * and paint read the inherited ones (→ 16.8px), so any text whose size
4882
+ * differed from the style's was measured in one line box and drawn in
4883
+ * another, and sat high or low inside it.
4884
+ */
4885
+ function resolveFont(node) {
4886
+ const out = {
4887
+ fontSize: 0,
4888
+ fontFamily: "",
4889
+ fontWeight: "normal",
4890
+ lineHeight: 0,
4891
+ letterSpacing: 0,
4892
+ fontStyle: "normal",
4893
+ fontStretch: "normal",
4894
+ fontVariant: "normal",
4895
+ fontKerning: "auto"
4896
+ };
4897
+ resolveFontInto(node, out);
4898
+ return out;
4899
+ }
4900
+ /** `resolveFont`, writing into a target the caller owns. */
4901
+ function resolveFontInto(node, out) {
4902
+ const fontSize = positive$1(resolveProperty(node, UiProperties.fontSize)) ?? UiProperties.fontSize.defaultValue;
4903
+ const ownFontSize = node.properties.get("fontSize");
4904
+ const ownLineHeight = positive$1(node.properties.get("lineHeight"));
4905
+ if (ownLineHeight !== void 0) out.lineHeight = ownLineHeight;
4906
+ else if (ownFontSize !== void 0) out.lineHeight = fontSize * DEFAULT_LINE_HEIGHT_FACTOR;
4907
+ else out.lineHeight = positive$1(resolveProperty(node, UiProperties.lineHeight)) ?? fontSize * 1.2;
4908
+ out.fontSize = fontSize;
4909
+ out.fontFamily = nonEmpty(resolveProperty(node, UiProperties.fontFamily)) ?? UiProperties.fontFamily.defaultValue;
4910
+ out.fontWeight = weight(resolveProperty(node, UiProperties.fontWeight)) ?? UiProperties.fontWeight.defaultValue;
4911
+ out.letterSpacing = finite(resolveProperty(node, UiProperties.letterSpacing)) ?? 0;
4912
+ out.fontStyle = nonEmpty(resolveProperty(node, UiProperties.fontStyle)) ?? "normal";
4913
+ out.fontStretch = nonEmpty(resolveProperty(node, UiProperties.fontStretch)) ?? "normal";
4914
+ out.fontVariant = nonEmpty(resolveProperty(node, UiProperties.fontVariant)) ?? "normal";
4915
+ out.fontKerning = nonEmpty(node.properties.get("fontKerning")) ?? "auto";
4916
+ }
4917
+ function positive$1(value) {
4918
+ return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : void 0;
4919
+ }
4920
+ function finite(value) {
4921
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
4922
+ }
4923
+ function weight(value) {
4924
+ return typeof value === "number" ? finite(value) : nonEmpty(value);
4925
+ }
4926
+ function nonEmpty(value) {
4927
+ return typeof value === "string" && value.length > 0 ? value : void 0;
4928
+ }
4929
+ //#endregion
4714
4930
  //#region src/graph/UiGraph.ts
4931
+ /**
4932
+ * How many times one frame rebuilds environments that rebuilding others
4933
+ * dirtied. One is the ordinary case and two is an overlay following its
4934
+ * declaration; more means listeners answering each other, which a frame
4935
+ * stops rather than hangs on.
4936
+ */
4937
+ const MAX_ENVIRONMENT_PASSES = 8;
4715
4938
  var UiGraph = class {
4716
4939
  constructor() {
4717
4940
  this.root = new UiNode("root", "root");
@@ -5113,16 +5336,33 @@ var UiGraph = class {
5113
5336
  if (!present) {
5114
5337
  if (!node.properties.has(property)) return false;
5115
5338
  node.properties.delete(property);
5116
- this.markDirty(node, dirtyFlags);
5339
+ this.markDirty(node, this.withProvidedFlags(property, dirtyFlags));
5117
5340
  return true;
5118
5341
  }
5119
5342
  const previousValue = node.getProperty(property);
5120
5343
  if (Object.is(previousValue, value)) return false;
5121
5344
  node.setProperty(property, value);
5122
- this.markDirty(node, dirtyFlags);
5345
+ this.markDirty(node, this.withProvidedFlags(property, dirtyFlags));
5123
5346
  return true;
5124
5347
  }
5125
5348
  /**
5349
+ * Adds the environment flag to a write of `color` or of a text
5350
+ * style field, which a node provides to its subtree as well as
5351
+ * paints with.
5352
+ *
5353
+ * Here rather than in the properties' `affects`, because `affects`
5354
+ * is also what the layout layer reads to classify a property, and
5355
+ * these have to stay what they are there: `color` and
5356
+ * `textDecoration` paint-only, `fontSize` layout and paint. The
5357
+ * rebuild this schedules dirties the subtree for paint alone when
5358
+ * only paint changed (see `environmentChangeFlags`). Marked for a
5359
+ * childless node too, since a child appended later inherits from
5360
+ * the environment this rebuilds.
5361
+ */
5362
+ withProvidedFlags(property, dirtyFlags) {
5363
+ return property === "color" || textStyleFields.has(property) ? dirtyFlags | 128 : dirtyFlags;
5364
+ }
5365
+ /**
5126
5366
  * Drains the dirty set and visits every node of every dirty subtree.
5127
5367
  *
5128
5368
  * Dirty roots can nest, so a node reached from an outer root is not
@@ -5185,10 +5425,27 @@ var UiGraph = class {
5185
5425
  const textStyle = node.getProperty("textStyle");
5186
5426
  if (textStyle !== void 0) {
5187
5427
  const scale = env.get(UiEnvironmentKeys.theme).typography;
5188
- if (isTypographyRole(textStyle, scale)) {
5189
- const style = scale[textStyle];
5428
+ let style;
5429
+ if (isTypographyRole(textStyle, scale)) style = scale[textStyle];
5430
+ else if (typeof textStyle !== "string") style = textStyle;
5431
+ if (style !== void 0) {
5190
5432
  env = env.set(UiEnvironmentKeys.textStyle, style);
5191
- } else if (typeof textStyle !== "string") env = env.set(UiEnvironmentKeys.textStyle, textStyle);
5433
+ env = env.set(UiEnvironmentKeys.color, style.color);
5434
+ }
5435
+ }
5436
+ const color = node.getProperty("color");
5437
+ if (color !== void 0) env = env.set(UiEnvironmentKeys.color, color);
5438
+ let own = null;
5439
+ for (const field of textStyleFieldNames) {
5440
+ const value = node.getProperty(field);
5441
+ if (value !== void 0) {
5442
+ own ??= { ...env.get(UiEnvironmentKeys.textStyle) };
5443
+ own[field] = value;
5444
+ }
5445
+ }
5446
+ if (own !== null) {
5447
+ if (positive(node.getProperty("lineHeight")) === void 0 && node.getProperty("fontSize") !== void 0) own.lineHeight = (positive(own.fontSize) ?? UiEnvironmentKeys.textStyle.defaultValue.fontSize) * DEFAULT_LINE_HEIGHT_FACTOR;
5448
+ env = env.set(UiEnvironmentKeys.textStyle, own);
5192
5449
  }
5193
5450
  const contentColor = node.getProperty("contentColor");
5194
5451
  if (contentColor !== void 0) env = env.set(UiEnvironmentKeys.contentColor, contentColor);
@@ -5229,9 +5486,10 @@ var UiGraph = class {
5229
5486
  const visit = (node) => {
5230
5487
  const previous = node.environment;
5231
5488
  const next = this.buildNodeEnvironment(node);
5232
- if (previous === null || !this.environmentsEqual(previous, next)) {
5489
+ const flags = previous === null ? 0 : this.environmentChangeFlags(previous, next, inheritedPropertyFlags);
5490
+ if (previous === null || flags !== 0) {
5233
5491
  node.environment = next;
5234
- if (previous !== null) this.markDirty(node, inheritedPropertyFlags);
5492
+ if (previous !== null) this.markDirty(node, flags);
5235
5493
  this.environmentChangedListener?.(node);
5236
5494
  }
5237
5495
  for (let current = node.firstChild; current !== null; current = current.nextSibling) visit(current);
@@ -5251,16 +5509,17 @@ var UiGraph = class {
5251
5509
  * the change to descendants and clearing the flag.
5252
5510
  */
5253
5511
  processEnvironmentDirty() {
5254
- this.environmentDirty = false;
5255
- const nodes = this.dirtyNodes.take();
5256
5512
  this.suppressDirtyListener = true;
5257
5513
  try {
5258
- for (const node of nodes) {
5259
- if ((node.dirtyFlags & 128) !== 0) {
5260
- node.dirtyFlags &= -129;
5261
- this.rebuildEnvironment(node, inheritedPropertyFlags);
5514
+ for (let pass = 0; pass === 0 || this.environmentDirty && pass < MAX_ENVIRONMENT_PASSES; pass++) {
5515
+ this.environmentDirty = false;
5516
+ for (const node of this.dirtyNodes.take()) {
5517
+ if ((node.dirtyFlags & 128) !== 0) {
5518
+ node.dirtyFlags &= -129;
5519
+ this.rebuildEnvironment(node, inheritedPropertyFlags);
5520
+ }
5521
+ if (node.dirtyFlags !== 0) this.dirtyNodes.mark(node);
5262
5522
  }
5263
- if (node.dirtyFlags !== 0) this.dirtyNodes.mark(node);
5264
5523
  }
5265
5524
  } finally {
5266
5525
  this.suppressDirtyListener = false;
@@ -5269,9 +5528,10 @@ var UiGraph = class {
5269
5528
  rebuildEnvironment(node, inheritedFlags) {
5270
5529
  const previous = node.environment;
5271
5530
  const next = this.buildNodeEnvironment(node);
5272
- if (previous === null || !this.environmentsEqual(previous, next)) {
5531
+ const flags = previous === null ? inheritedFlags : this.environmentChangeFlags(previous, next, inheritedFlags);
5532
+ if (flags !== 0) {
5273
5533
  node.environment = next;
5274
- this.markDirty(node, inheritedFlags);
5534
+ this.markDirty(node, flags);
5275
5535
  this.environmentChangedListener?.(node);
5276
5536
  }
5277
5537
  let child = node.firstChild;
@@ -5280,102 +5540,75 @@ var UiGraph = class {
5280
5540
  child = child.nextSibling;
5281
5541
  }
5282
5542
  }
5283
- environmentsEqual(a, b) {
5284
- if (a === b) return true;
5285
- if (a.providedSize !== b.providedSize) return false;
5543
+ /**
5544
+ * What a node whose environment went from `a` to `b` has to redo:
5545
+ * nothing when they hold the same values, a repaint when what
5546
+ * differs can only change how text is painted, and otherwise
5547
+ * everything an inherited property can affect.
5548
+ *
5549
+ * Paint is singled out because the provided values that change with
5550
+ * a hover or a selection are a colour or an underline, and
5551
+ * everything else provided — a theme, a font size — can move a line
5552
+ * break, so a colour change counted as one of them re-laid out the
5553
+ * subtree of every box whose colour was animated.
5554
+ */
5555
+ environmentChangeFlags(a, b, inheritedFlags) {
5556
+ if (a === b) return 0;
5557
+ let flags = 0;
5286
5558
  for (const keyName of a.providedKeys()) {
5287
- if (!b.providesOwn(keyName)) return false;
5288
- const previousValue = a.getOwn(keyName);
5289
- const nextValue = b.getOwn(keyName);
5290
- if (Object.is(previousValue, nextValue)) continue;
5291
- const compare = findEnvironmentKey(keyName)?.compare;
5292
- if (compare === void 0 || !compare(previousValue, nextValue)) return false;
5293
- }
5294
- return true;
5559
+ flags |= this.providedChangeFlags(keyName, a, b, inheritedFlags);
5560
+ if (flags === inheritedFlags) return flags;
5561
+ }
5562
+ for (const keyName of b.providedKeys()) if (!a.providesOwn(keyName)) flags |= this.providedChangeFlags(keyName, a, b, inheritedFlags);
5563
+ return flags;
5564
+ }
5565
+ /** `environmentChangeFlags` for one key either side provides. */
5566
+ providedChangeFlags(keyName, a, b, inheritedFlags) {
5567
+ const key = findEnvironmentKey(keyName);
5568
+ const previouslyProvided = a.providesOwn(keyName);
5569
+ const nextProvided = b.providesOwn(keyName);
5570
+ const previousValue = previouslyProvided ? a.getOwn(keyName) : key?.defaultValue;
5571
+ const nextValue = nextProvided ? b.getOwn(keyName) : key?.defaultValue;
5572
+ if (previouslyProvided === nextProvided) {
5573
+ if (Object.is(previousValue, nextValue)) return 0;
5574
+ const compare = key?.compare;
5575
+ if (compare !== void 0 && compare(previousValue, nextValue)) return 0;
5576
+ }
5577
+ if (keyName === UiEnvironmentKeys.color.name) return 2;
5578
+ if (keyName === UiEnvironmentKeys.textStyle.name && textStyleFontsEqual(previousValue, nextValue)) return 2;
5579
+ return inheritedFlags;
5295
5580
  }
5296
5581
  };
5297
- //#endregion
5298
- //#region src/properties/UiPropertyResolver.ts
5299
5582
  /**
5300
- * Resolves a property value for a node.
5301
- *
5302
- * Resolution order:
5303
- *
5304
- * 1. The value explicitly specified on the node.
5305
- * 2. The value inherited from the node's scoped environment.
5306
- * 3. The property definition's default value.
5307
- *
5308
- * The resolver does not allocate and is safe to call from hot paths
5309
- * such as layout and paint.
5310
- */
5311
- function resolveProperty(node, definition) {
5312
- const specified = node.properties.get(definition.name);
5313
- if (specified !== void 0) return specified;
5314
- if (definition.inherited && node.environment !== null) {
5315
- const environmentKey = definition.environmentKey;
5316
- if (environmentKey !== void 0) {
5317
- const envValue = node.environment.get(environmentKey);
5318
- if (definition.resolveFromEnvironment !== void 0) return definition.resolveFromEnvironment(envValue);
5319
- return envValue;
5320
- }
5321
- const fallback = node.environment.get(createFallbackKey(definition));
5322
- if (fallback !== void 0) return fallback;
5323
- }
5324
- return definition.defaultValue;
5325
- }
5326
- /**
5327
- * Resolves a property by name.
5328
- *
5329
- * Returns undefined when no definition exists; callers that know
5330
- * the property exists should use resolveProperty() with the
5331
- * definition for stronger typing.
5332
- */
5333
- function resolvePropertyByName(node, name) {
5334
- const definition = findPropertyDefinition(name);
5335
- if (definition === void 0) return;
5336
- return resolveProperty(node, definition);
5337
- }
5338
- /**
5339
- * Resolves a numeric property, returning undefined when the value
5340
- * is missing or not a finite number.
5341
- */
5342
- function resolveNumber(node, name) {
5343
- const value = resolvePropertyByName(node, name);
5344
- if (typeof value === "number" && Number.isFinite(value)) return value;
5345
- }
5346
- /**
5347
- * Resolves a string property, returning undefined when the value is
5348
- * missing or not a non-empty string.
5349
- */
5350
- function resolveString(node, name) {
5351
- const value = resolvePropertyByName(node, name);
5352
- if (typeof value === "string" && value.length > 0) return value;
5353
- }
5583
+ * The properties a node provides to its subtree as fields of the text
5584
+ * style, which are the ones that resolve through it.
5585
+ */
5586
+ const textStyleFieldNames = [
5587
+ "fontFamily",
5588
+ "fontSize",
5589
+ "fontWeight",
5590
+ "lineHeight",
5591
+ "letterSpacing",
5592
+ "textAlign",
5593
+ "textDirection",
5594
+ "fontStyle",
5595
+ "fontStretch",
5596
+ "fontVariant",
5597
+ "fontKerning",
5598
+ "textDecoration"
5599
+ ];
5600
+ const textStyleFields = new Set(textStyleFieldNames);
5354
5601
  /**
5355
- * Resolves a boolean property, returning undefined when the value
5356
- * is missing or not a boolean.
5602
+ * Whether two text styles measure the same, so that a change between
5603
+ * them repaints and lays out nothing: they differ at most in colour,
5604
+ * alignment, direction or decoration, the fields whose properties are
5605
+ * paint-only.
5357
5606
  */
5358
- function resolveBoolean(node, name) {
5359
- const value = resolvePropertyByName(node, name);
5360
- if (typeof value === "boolean") return value;
5607
+ function textStyleFontsEqual(a, b) {
5608
+ return a.fontFamily === b.fontFamily && a.fontSize === b.fontSize && a.fontWeight === b.fontWeight && a.lineHeight === b.lineHeight && a.letterSpacing === b.letterSpacing && a.fontStyle === b.fontStyle && a.fontStretch === b.fontStretch && a.fontVariant === b.fontVariant && a.fontKerning === b.fontKerning;
5361
5609
  }
5362
- /**
5363
- * Lazily creates a fallback environment key that matches the
5364
- * property name. The key is cached so repeated resolutions of the
5365
- * same property do not allocate.
5366
- */
5367
- const fallbackKeys = /* @__PURE__ */ new Map();
5368
- function createFallbackKey(definition) {
5369
- let key = fallbackKeys.get(definition.name);
5370
- if (key === void 0) {
5371
- key = {
5372
- name: definition.name,
5373
- defaultValue: definition.defaultValue,
5374
- compare: definition.compare
5375
- };
5376
- fallbackKeys.set(definition.name, key);
5377
- }
5378
- return key;
5610
+ function positive(value) {
5611
+ return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : void 0;
5379
5612
  }
5380
5613
  //#endregion
5381
5614
  //#region src/editing/TextBoundaries.ts
@@ -6431,75 +6664,6 @@ function isAscii(text) {
6431
6664
  return true;
6432
6665
  }
6433
6666
  //#endregion
6434
- //#region src/properties/UiTextFont.ts
6435
- /**
6436
- * `line-height: normal`: the factor of the font size a line takes when
6437
- * no line height is set. Shared by ParagraphLayout and PaintState.
6438
- */
6439
- const DEFAULT_LINE_HEIGHT_FACTOR = 1.2;
6440
- /**
6441
- * Resolves a node's font the one way layout and paint both use.
6442
- *
6443
- * Font size, family, weight and letter spacing inherit through the
6444
- * environment's text style. Line height is the subtle one: a text
6445
- * style carries a line height that belongs with its font size, so a
6446
- * node that inherits the style takes it whole. A node that sets its
6447
- * own `fontSize` without a `lineHeight` gets a normal line height for
6448
- * that size, `fontSize × 1.2`, rather than the inherited pixel value
6449
- * sized for a different font — the inherited 16.8px of the default
6450
- * style is right for 14px text and wrong for 22px. An explicit
6451
- * `lineHeight` always wins.
6452
- *
6453
- * Before this, layout read the raw props (unset line height → ×1.2)
6454
- * and paint read the inherited ones (→ 16.8px), so any text whose size
6455
- * differed from the style's was measured in one line box and drawn in
6456
- * another, and sat high or low inside it.
6457
- */
6458
- function resolveFont(node) {
6459
- const out = {
6460
- fontSize: 0,
6461
- fontFamily: "",
6462
- fontWeight: "normal",
6463
- lineHeight: 0,
6464
- letterSpacing: 0,
6465
- fontStyle: "normal",
6466
- fontStretch: "normal",
6467
- fontVariant: "normal",
6468
- fontKerning: "auto"
6469
- };
6470
- resolveFontInto(node, out);
6471
- return out;
6472
- }
6473
- /** `resolveFont`, writing into a target the caller owns. */
6474
- function resolveFontInto(node, out) {
6475
- const fontSize = positive(resolveProperty(node, UiProperties.fontSize)) ?? UiProperties.fontSize.defaultValue;
6476
- const ownFontSize = node.properties.get("fontSize");
6477
- const ownLineHeight = positive(node.properties.get("lineHeight"));
6478
- if (ownLineHeight !== void 0) out.lineHeight = ownLineHeight;
6479
- else if (ownFontSize !== void 0) out.lineHeight = fontSize * DEFAULT_LINE_HEIGHT_FACTOR;
6480
- else out.lineHeight = positive(resolveProperty(node, UiProperties.lineHeight)) ?? fontSize * 1.2;
6481
- out.fontSize = fontSize;
6482
- out.fontFamily = nonEmpty(resolveProperty(node, UiProperties.fontFamily)) ?? UiProperties.fontFamily.defaultValue;
6483
- out.fontWeight = weight(resolveProperty(node, UiProperties.fontWeight)) ?? UiProperties.fontWeight.defaultValue;
6484
- out.letterSpacing = finite(resolveProperty(node, UiProperties.letterSpacing)) ?? 0;
6485
- out.fontStyle = nonEmpty(resolveProperty(node, UiProperties.fontStyle)) ?? "normal";
6486
- out.fontStretch = nonEmpty(resolveProperty(node, UiProperties.fontStretch)) ?? "normal";
6487
- out.fontVariant = nonEmpty(resolveProperty(node, UiProperties.fontVariant)) ?? "normal";
6488
- out.fontKerning = nonEmpty(node.properties.get("fontKerning")) ?? "auto";
6489
- }
6490
- function positive(value) {
6491
- return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : void 0;
6492
- }
6493
- function finite(value) {
6494
- return typeof value === "number" && Number.isFinite(value) ? value : void 0;
6495
- }
6496
- function weight(value) {
6497
- return typeof value === "number" ? finite(value) : nonEmpty(value);
6498
- }
6499
- function nonEmpty(value) {
6500
- return typeof value === "string" && value.length > 0 ? value : void 0;
6501
- }
6502
- //#endregion
6503
6667
  //#region src/layout/ParagraphLayout.ts
6504
6668
  const ELLIPSIS = "…";
6505
6669
  /**
@@ -11854,13 +12018,13 @@ var UiEditingController = class {
11854
12018
  let current = focused !== null && editingGroupOf(focused)?.root === root ? focused : adjacentField(root, target, 1) ?? edgeField(root, -1);
11855
12019
  if (current === null) return null;
11856
12020
  const distance = (node) => {
11857
- const box = this.host.visibleBox(node);
12021
+ const box = this.drawnBox(node);
11858
12022
  return y < box.y ? box.y - y : y > box.y + box.height ? y - box.y - box.height : 0;
11859
12023
  };
11860
12024
  for (;;) {
11861
12025
  const here = distance(current);
11862
12026
  if (here === 0) return current;
11863
- const box = this.host.visibleBox(current);
12027
+ const box = this.drawnBox(current);
11864
12028
  const next = adjacentField(root, current, y < box.y ? -1 : 1);
11865
12029
  if (next === null || distance(next) >= here) return current;
11866
12030
  current = next;
@@ -11957,20 +12121,20 @@ var UiEditingController = class {
11957
12121
  const node = this.focusedEditable;
11958
12122
  if (node === null || this.host.recordFor(node) === void 0) return null;
11959
12123
  const model = editorFor(node);
11960
- const caret = this.layoutOf(node).caretRect();
11961
- const visible = this.host.visibleBox(node);
12124
+ const local = this.layoutOf(node).caretRect();
12125
+ const caret = this.drawnBox(node, {
12126
+ x: local.x,
12127
+ y: local.y,
12128
+ width: 1,
12129
+ height: local.height
12130
+ });
11962
12131
  if (this.span !== null) {
11963
12132
  const { text, html } = this.spanCopy();
11964
12133
  return {
11965
12134
  text,
11966
12135
  selectionStart: 0,
11967
12136
  selectionEnd: text.length,
11968
- caret: {
11969
- x: visible.x + caret.x,
11970
- y: visible.y + caret.y,
11971
- width: 1,
11972
- height: caret.height
11973
- },
12137
+ caret,
11974
12138
  multiline: true,
11975
12139
  composing: false,
11976
12140
  ...html === void 0 ? {} : { html }
@@ -11981,12 +12145,7 @@ var UiEditingController = class {
11981
12145
  text: model.text,
11982
12146
  selectionStart: model.start,
11983
12147
  selectionEnd: model.end,
11984
- caret: {
11985
- x: visible.x + caret.x,
11986
- y: visible.y + caret.y,
11987
- width: 1,
11988
- height: caret.height
11989
- },
12148
+ caret,
11990
12149
  multiline: isMultiline(node),
11991
12150
  composing: model.composing,
11992
12151
  ...html === void 0 ? {} : { html }
@@ -12280,12 +12439,12 @@ var UiEditingController = class {
12280
12439
  fieldAt(root, from, y) {
12281
12440
  let current = from;
12282
12441
  for (;;) {
12283
- const box = this.host.visibleBox(current);
12442
+ const box = this.drawnBox(current);
12284
12443
  const step = y < box.y ? -1 : y > box.y + box.height ? 1 : 0;
12285
12444
  if (step === 0) return current;
12286
12445
  const next = adjacentField(root, current, step);
12287
12446
  if (next === null) return current;
12288
- const nextBox = this.host.visibleBox(next);
12447
+ const nextBox = this.drawnBox(next);
12289
12448
  if (step > 0 ? y < nextBox.y : y > nextBox.y + nextBox.height) return next;
12290
12449
  current = next;
12291
12450
  }
@@ -12344,11 +12503,27 @@ var UiEditingController = class {
12344
12503
  * a second measurer that must never disagree with this one. Asking
12345
12504
  * is the only version that stays right.
12346
12505
  *
12506
+ * `offset` asks where a caret at another character would be: where
12507
+ * the word being typed began, for a list that stays under its start.
12508
+ * It is clamped to the text.
12509
+ *
12347
12510
  * Null when the node is not an editable, or has not been laid out.
12348
12511
  */
12349
- caretRectOf(node) {
12512
+ caretRectOf(node, offset) {
12350
12513
  if (!isEditableNode(node) || this.host.recordFor(node) === void 0) return null;
12351
- return this.layoutOf(node).caretRect();
12514
+ const layout = this.layoutOf(node);
12515
+ return offset === void 0 ? layout.caretRect() : layout.caretRect(Math.max(0, Math.min(offset, layout.model.text.length)));
12516
+ }
12517
+ /** Where a field, or a part of it in its own coordinates, is drawn; see `EditingHost.screenBox`. */
12518
+ drawnBox(node, part) {
12519
+ if (this.host.screenBox !== void 0) return this.host.screenBox(node, part);
12520
+ const box = this.host.visibleBox(node);
12521
+ return part === void 0 ? box : {
12522
+ x: box.x + part.x,
12523
+ y: box.y + part.y,
12524
+ width: part.width,
12525
+ height: part.height
12526
+ };
12352
12527
  }
12353
12528
  layoutOf(node) {
12354
12529
  const rec = this.host.recordFor(node);
@@ -13962,6 +14137,76 @@ function accumulatedOffsetTo(node, records, out) {
13962
14137
  out.x = record.x;
13963
14138
  out.y = record.y;
13964
14139
  }
14140
+ /**
14141
+ * Whether a node or any ancestor carries a `transform`.
14142
+ *
14143
+ * The same test `layoutForFrame` makes, an object rather than a
14144
+ * parsed non-identity transform: it is the question a caller asks to
14145
+ * take the plain additive path, so an identity object costs it only
14146
+ * the general one, which gives the same answer.
14147
+ */
14148
+ function hasTransformedChain(node) {
14149
+ for (let current = node; current !== null; current = current.parent) {
14150
+ const transform = current.properties.get("transform");
14151
+ if (typeof transform === "object" && transform !== null) return true;
14152
+ }
14153
+ return false;
14154
+ }
14155
+ /**
14156
+ * Carries points in a node's record space out to its parent's: through
14157
+ * its transform (unless `withTransform` is false), then its sticky
14158
+ * shift. The order is the renderer's
14159
+ * (`Canvas2DRenderer` translates by the sticky shift and then applies
14160
+ * `T(translate) · T(pivot) · R · S · T(-pivot)` about the record box),
14161
+ * because the point of this is to agree with where the node is drawn.
14162
+ *
14163
+ * `points` is x, y pairs, written in place.
14164
+ */
14165
+ function transformPointsOut(node, record, points, withTransform = true) {
14166
+ const transform = withTransform ? parseTransform(node.properties.get("transform")) : void 0;
14167
+ for (let i = 0; i < points.length; i += 2) {
14168
+ let x = points[i];
14169
+ let y = points[i + 1];
14170
+ if (transform !== void 0) {
14171
+ const originX = record.x + transform.x;
14172
+ const originY = record.y + transform.y;
14173
+ const dx = (x - originX) * transform.scaleX;
14174
+ const dy = (y - originY) * transform.scaleY;
14175
+ const cos = Math.cos(transform.rotation);
14176
+ const sin = Math.sin(transform.rotation);
14177
+ x = originX + dx * cos - dy * sin + transform.translateX;
14178
+ y = originY + dx * sin + dy * cos + transform.translateY;
14179
+ }
14180
+ points[i] = x + record.stickyOffsetX;
14181
+ points[i + 1] = y + record.stickyOffsetY;
14182
+ }
14183
+ }
14184
+ /**
14185
+ * The inverse of `transformPointsOut`: points in a node's parent's space
14186
+ * brought into the node's record space. A degenerate (zero-scale)
14187
+ * transform draws nothing and has no inverse, so it is left out, as
14188
+ * `UiHitTester.toLocal` leaves it out.
14189
+ */
14190
+ function transformPointsIn(node, record, points) {
14191
+ const transform = parseTransform(node.properties.get("transform"));
14192
+ const invertible = transform !== void 0 && transform.scaleX !== 0 && transform.scaleY !== 0;
14193
+ for (let i = 0; i < points.length; i += 2) {
14194
+ let x = points[i] - record.stickyOffsetX;
14195
+ let y = points[i + 1] - record.stickyOffsetY;
14196
+ if (invertible) {
14197
+ const originX = record.x + transform.x;
14198
+ const originY = record.y + transform.y;
14199
+ const dx = x - transform.translateX - originX;
14200
+ const dy = y - transform.translateY - originY;
14201
+ const cos = Math.cos(transform.rotation);
14202
+ const sin = Math.sin(transform.rotation);
14203
+ x = (dx * cos + dy * sin) / transform.scaleX + originX;
14204
+ y = (-dx * sin + dy * cos) / transform.scaleY + originY;
14205
+ }
14206
+ points[i] = x;
14207
+ points[i + 1] = y;
14208
+ }
14209
+ }
13965
14210
  //#endregion
13966
14211
  //#region src/layout/LayoutExplanation.ts
13967
14212
  const EPSILON$1 = 1e-6;
@@ -14474,6 +14719,8 @@ function stackDefault(node) {
14474
14719
  }
14475
14720
  var LayoutEngine = class {
14476
14721
  records = /* @__PURE__ */ new Map();
14722
+ /** A box's corners on their way through `projectBox` and `unprojectBox`. */
14723
+ cornerScratch = /* @__PURE__ */ new Float64Array(8);
14477
14724
  /**
14478
14725
  * The records the previous full layout ended with, held for the
14479
14726
  * length of the next one so their objects can be reused.
@@ -14528,6 +14775,22 @@ var LayoutEngine = class {
14528
14775
  /** Anchored nodes whose anchor moved this frame, re-placed once it settles. */
14529
14776
  movedAnchored = /* @__PURE__ */ new Set();
14530
14777
  /**
14778
+ * Every absolutely positioned node placed by its edges or at a point,
14779
+ * with the containing block it was placed against.
14780
+ *
14781
+ * Such a node is placed when its parent is, but its containing block
14782
+ * can be an ancestor further up: a panel pinned to the window's
14783
+ * corner from inside a column that keeps its size. When the window
14784
+ * grew, the column didn't move, so nothing placed the panel again,
14785
+ * and it stayed where the old corner was. A block that changes size
14786
+ * says so (`blockResized`), and the nodes whose block is no longer
14787
+ * the one they were placed against are placed again once the pass
14788
+ * settles.
14789
+ */
14790
+ absoluteBlocks = /* @__PURE__ */ new Map();
14791
+ /** A positioned node, or the root, took a new box this pass; see `absoluteBlocks`. */
14792
+ blockResized = false;
14793
+ /**
14531
14794
  * The nodes asking for `lift`, in the order they asked.
14532
14795
  *
14533
14796
  * Kept as a set rather than rebuilt per pass because layout is
@@ -14978,9 +15241,11 @@ var LayoutEngine = class {
14978
15241
  this.anchorOf.clear();
14979
15242
  this.anchorDependents.clear();
14980
15243
  this.movedAnchored.clear();
15244
+ this.blockResized = false;
14981
15245
  this.resetStats();
14982
15246
  this.fullLayout(constraints);
14983
15247
  const rec = this.record(node);
15248
+ this.replaceStaleAbsolute();
14984
15249
  this.applyScroll();
14985
15250
  for (const anchored of this.anchoredNodes) this.movedAnchored.add(anchored);
14986
15251
  this.replaceMovedAnchored();
@@ -15049,7 +15314,9 @@ var LayoutEngine = class {
15049
15314
  return;
15050
15315
  }
15051
15316
  this.layoutVersion++;
15317
+ this.blockResized = false;
15052
15318
  this.relayout(constraints);
15319
+ this.replaceStaleAbsolute();
15053
15320
  this.applyScroll();
15054
15321
  this.replaceMovedAnchored();
15055
15322
  }
@@ -15195,6 +15462,8 @@ var LayoutEngine = class {
15195
15462
  * scroll ancestor's offset and by the sticky offsets of the node and
15196
15463
  * its ancestors. Records stay in pre-scroll coordinates; this is the
15197
15464
  * projection renderers and hit testing agree on.
15465
+ *
15466
+ * Transforms are not applied; `screenBox` applies its ancestors'.
15198
15467
  */
15199
15468
  visibleBox(node) {
15200
15469
  const rec = this.records.get(node);
@@ -15224,6 +15493,48 @@ var LayoutEngine = class {
15224
15493
  };
15225
15494
  }
15226
15495
  /**
15496
+ * Where a node's box is drawn on the canvas: `visibleBox`, carried
15497
+ * through the `transform` of every ancestor as well. A card under a
15498
+ * panned and zoomed camera box is drawn far from its record, which a
15499
+ * transform never moves, and this is the box beside which its tooltip
15500
+ * belongs and over which its accessibility element goes. Under a
15501
+ * rotation it is the box the turned corners span.
15502
+ *
15503
+ * The node's own transform is left out. It is what a node animates
15504
+ * itself with — a spinner turning, a dialog scaling in — and a box
15505
+ * that included it would wobble with the animation: the mirror's
15506
+ * rectangle for a spinner grew and shrank on every step, and a
15507
+ * tooltip on it shook. The ancestors' are where it is; its own is how
15508
+ * it is drawn there. A tree with no transform above the node gets
15509
+ * `visibleBox`'s answer exactly.
15510
+ *
15511
+ * `part`, when given, is a rectangle in the node's own coordinates
15512
+ * (its box's top-left corner is 0, 0) and is answered instead of the
15513
+ * whole box: a caret inside a text field, the padding strip around a
15514
+ * node in the inspector. Adding its offset to the whole box's corner
15515
+ * is right only at scale 1; under a zoomed parent the part is scaled
15516
+ * with the node and sits twice as far into it.
15517
+ */
15518
+ screenBox(node, part) {
15519
+ const rec = this.records.get(node);
15520
+ if (rec === void 0) return {
15521
+ x: 0,
15522
+ y: 0,
15523
+ width: 0,
15524
+ height: 0
15525
+ };
15526
+ if (!hasTransformedChain(node.parent)) {
15527
+ const seen = this.visibleBox(node);
15528
+ return part === void 0 ? seen : {
15529
+ x: seen.x + part.x,
15530
+ y: seen.y + part.y,
15531
+ width: part.width,
15532
+ height: part.height
15533
+ };
15534
+ }
15535
+ return part === void 0 ? this.projectBox(node, rec.x, rec.y, rec.width, rec.height) : this.projectBox(node, rec.x + part.x, rec.y + part.y, part.width, part.height);
15536
+ }
15537
+ /**
15227
15538
  * The scroll offsets each scroll ancestor would need so that `node`
15228
15539
  * is inside its viewport, `padding` pixels from the nearest edge,
15229
15540
  * innermost first. Nothing is changed: the caller writes the offsets
@@ -15376,6 +15687,7 @@ var LayoutEngine = class {
15376
15687
  this.textScrollPending.delete(current);
15377
15688
  this.anchoredNodes.delete(current);
15378
15689
  this.movedAnchored.delete(current);
15690
+ this.absoluteBlocks.delete(current);
15379
15691
  this.forgetAnchoring(current);
15380
15692
  this.stickyNodes.delete(current);
15381
15693
  this.stickyShifted.delete(current);
@@ -15737,13 +16049,14 @@ var LayoutEngine = class {
15737
16049
  let contentMain = 0;
15738
16050
  for (const line of lines) {
15739
16051
  const lineTotal = this.lineOuterMain(line, config.gapMain, "hypothetical");
15740
- if (mainBounded && (mainDefinite || lineTotal > mainMax)) {
16052
+ const lineWanted = this.lineMaxContentMain(line, config.gapMain);
16053
+ if (mainBounded && (mainDefinite || lineTotal > mainMax || lineWanted > mainMax)) {
15741
16054
  this.resolveLine(line, mainMax - config.gapMain * (line.items.length - 1), config);
15742
16055
  this.measureFlexedItems(line.items, content, direction, crossDefinite && !config.wrap ? row ? content.maxHeight : content.maxWidth : void 0);
15743
16056
  contentMain = Math.max(contentMain, this.lineOuterMain(line, config.gapMain, "final"));
15744
16057
  } else {
15745
16058
  for (const item of line.items) item.finalMain = item.hypotheticalMain;
15746
- contentMain = Math.max(contentMain, this.lineMaxContentMain(line, config.gapMain));
16059
+ contentMain = Math.max(contentMain, lineWanted);
15747
16060
  }
15748
16061
  }
15749
16062
  if (mainDefinite) contentMain = Math.max(mainMax, contentMain);
@@ -16565,8 +16878,12 @@ var LayoutEngine = class {
16565
16878
  * the anchor instead.
16566
16879
  */
16567
16880
  placeAbsoluteChildren(parent) {
16881
+ this.forEachAbsoluteChild(parent, (child) => this.placeAbsolute(child));
16882
+ }
16883
+ /** Places one absolutely positioned node against its containing block; see `placeAbsoluteChildren`. */
16884
+ placeAbsolute(child) {
16568
16885
  const savedBase = this.percentBase;
16569
- this.forEachAbsoluteChild(parent, (child) => {
16886
+ try {
16570
16887
  const cRec = this.record(child);
16571
16888
  const block = this.containingBlockOf(child);
16572
16889
  this.percentBase = {
@@ -16581,12 +16898,14 @@ var LayoutEngine = class {
16581
16898
  this.trackAnchor(child, anchor);
16582
16899
  const anchorRec = this.records.get(anchor);
16583
16900
  if (anchorRec !== void 0) {
16901
+ this.absoluteBlocks.delete(child);
16584
16902
  this.placeAnchored(child, cRec, anchorRec, anchor, block);
16585
16903
  return;
16586
16904
  }
16587
16905
  } else if (point !== void 0 && point !== null) {
16588
16906
  this.anchoredNodes.delete(child);
16589
16907
  this.trackAnchor(child, null);
16908
+ this.absoluteBlocks.set(child, block);
16590
16909
  this.measure(child, new Constraints(0, Math.max(0, block.width), 0, Math.max(0, block.height)));
16591
16910
  this.placeBeside(child, cRec, block.x + point.x, block.y + point.y, 0, 0, block);
16592
16911
  return;
@@ -16594,6 +16913,7 @@ var LayoutEngine = class {
16594
16913
  this.anchoredNodes.delete(child);
16595
16914
  this.trackAnchor(child, null);
16596
16915
  }
16916
+ this.absoluteBlocks.set(child, block);
16597
16917
  const marginH = cRec.marginLeft + cRec.marginRight;
16598
16918
  const marginV = cRec.marginTop + cRec.marginBottom;
16599
16919
  const availableWidth = Math.max(0, block.width - (cRec.left ?? 0) - (cRec.right ?? 0) - marginH);
@@ -16614,8 +16934,33 @@ var LayoutEngine = class {
16614
16934
  else if (cRec.bottom !== void 0) y = block.y + block.height - cRec.bottom - cRec.marginBottom - height;
16615
16935
  else y = block.y + cRec.marginTop;
16616
16936
  this.assignBox(child, x, y, width, height);
16617
- });
16618
- this.percentBase = savedBase;
16937
+ } finally {
16938
+ this.percentBase = savedBase;
16939
+ }
16940
+ }
16941
+ /**
16942
+ * Places again the absolutely positioned nodes whose containing block
16943
+ * is not the box they were placed against, once a pass has settled
16944
+ * every box. Only after a pass in which a positioned node or the root
16945
+ * took a new box, which is rare outside a resize; placing one can
16946
+ * resize a block another is placed against, so it repeats, up to the
16947
+ * limit that stops anchors spinning.
16948
+ */
16949
+ replaceStaleAbsolute() {
16950
+ for (let pass = 0; this.blockResized && pass < ANCHOR_CHAIN_LIMIT; pass++) {
16951
+ this.blockResized = false;
16952
+ for (const [child, was] of this.absoluteBlocks) {
16953
+ if (!this.records.has(child)) {
16954
+ this.absoluteBlocks.delete(child);
16955
+ continue;
16956
+ }
16957
+ const block = this.containingBlockOf(child);
16958
+ if (block.x === was.x && block.y === was.y && block.width === was.width && block.height === was.height) continue;
16959
+ this.placeAbsolute(child);
16960
+ if (this.record(child).placeDirty) this.place(child);
16961
+ }
16962
+ }
16963
+ this.blockResized = false;
16619
16964
  }
16620
16965
  /**
16621
16966
  * Places an anchored node beside its anchor.
@@ -16630,12 +16975,23 @@ var LayoutEngine = class {
16630
16975
  */
16631
16976
  placeAnchored(child, cRec, anchorRec, anchor, block) {
16632
16977
  this.measure(child, new Constraints(0, Math.max(0, block.width), 0, Math.max(0, block.height)));
16978
+ const part = child.properties.get("anchorRect");
16979
+ if (hasTransformedChain(anchor.parent) || hasTransformedChain(child.parent)) {
16980
+ const seen = part !== void 0 && part !== null ? this.projectBox(anchor, anchorRec.x + part.x, anchorRec.y + part.y, part.width, part.height) : this.projectBox(anchor, anchorRec.x, anchorRec.y, anchorRec.width, anchorRec.height);
16981
+ const local = this.unprojectBox(child, seen);
16982
+ this.placeBeside(child, cRec, local.x, local.y, local.width, local.height, block);
16983
+ return;
16984
+ }
16633
16985
  const scrollAnchor = this.scrollOffsetOf(anchor);
16634
16986
  const scrollChild = this.scrollOffsetOf(child);
16635
16987
  const stickyAnchor = this.stickyOffsetOf(anchor);
16636
16988
  const stickyChild = this.stickyOffsetOf(child);
16637
16989
  const ax = anchorRec.x + stickyAnchor.x - scrollAnchor.x + scrollChild.x - stickyChild.x;
16638
16990
  const ay = anchorRec.y + stickyAnchor.y - scrollAnchor.y + scrollChild.y - stickyChild.y;
16991
+ if (part !== void 0 && part !== null) {
16992
+ this.placeBeside(child, cRec, ax + part.x, ay + part.y, part.width, part.height, block);
16993
+ return;
16994
+ }
16639
16995
  this.placeBeside(child, cRec, ax, ay, anchorRec.width, anchorRec.height, block);
16640
16996
  }
16641
16997
  /**
@@ -16790,6 +17146,85 @@ var LayoutEngine = class {
16790
17146
  };
16791
17147
  }
16792
17148
  /**
17149
+ * Where a box in a node's record space is seen on the canvas: through
17150
+ * the node's own sticky shift (not its transform; see `screenBox`),
17151
+ * then, for each ancestor in turn, its scroll offset (which moves only
17152
+ * what is inside it) and its transform and sticky shift. The same
17153
+ * chain the renderer composes on the way down, walked up; a turned box
17154
+ * is the box its corners span.
17155
+ */
17156
+ projectBox(node, x, y, width, height) {
17157
+ const corners = this.cornersOf(x, y, width, height);
17158
+ for (let current = node; current !== null; current = current.parent) {
17159
+ const rec = this.records.get(current);
17160
+ if (rec === void 0) continue;
17161
+ if (current !== node && rec.scrollable) for (let i = 0; i < corners.length; i += 2) {
17162
+ corners[i] -= rec.scrollX;
17163
+ corners[i + 1] -= rec.scrollY;
17164
+ }
17165
+ transformPointsOut(current, rec, corners, current !== node);
17166
+ }
17167
+ return this.boundsOfCorners(corners);
17168
+ }
17169
+ /**
17170
+ * A canvas box brought into the space an absolute child's record is
17171
+ * placed in: `projectBox` undone for each of its ancestors, outermost
17172
+ * first, and the child's own sticky shift taken off. The child's own
17173
+ * transform stays, because it applies on top of the box being placed.
17174
+ */
17175
+ unprojectBox(child, box) {
17176
+ const corners = this.cornersOf(box.x, box.y, box.width, box.height);
17177
+ const chain = [];
17178
+ for (let current = child.parent; current !== null; current = current.parent) chain.push(current);
17179
+ for (let i = chain.length - 1; i >= 0; i--) {
17180
+ const ancestor = chain[i];
17181
+ const rec = this.records.get(ancestor);
17182
+ if (rec === void 0) continue;
17183
+ transformPointsIn(ancestor, rec, corners);
17184
+ if (rec.scrollable) for (let j = 0; j < corners.length; j += 2) {
17185
+ corners[j] += rec.scrollX;
17186
+ corners[j + 1] += rec.scrollY;
17187
+ }
17188
+ }
17189
+ const own = this.records.get(child);
17190
+ if (own !== void 0) for (let j = 0; j < corners.length; j += 2) {
17191
+ corners[j] -= own.stickyOffsetX;
17192
+ corners[j + 1] -= own.stickyOffsetY;
17193
+ }
17194
+ return this.boundsOfCorners(corners);
17195
+ }
17196
+ /** The four corners of a box as x, y pairs, in a scratch array the projections reuse. */
17197
+ cornersOf(x, y, width, height) {
17198
+ const corners = this.cornerScratch;
17199
+ corners[0] = x;
17200
+ corners[1] = y;
17201
+ corners[2] = x + width;
17202
+ corners[3] = y;
17203
+ corners[4] = x;
17204
+ corners[5] = y + height;
17205
+ corners[6] = x + width;
17206
+ corners[7] = y + height;
17207
+ return corners;
17208
+ }
17209
+ boundsOfCorners(corners) {
17210
+ let minX = Infinity;
17211
+ let minY = Infinity;
17212
+ let maxX = -Infinity;
17213
+ let maxY = -Infinity;
17214
+ for (let i = 0; i < corners.length; i += 2) {
17215
+ minX = Math.min(minX, corners[i]);
17216
+ maxX = Math.max(maxX, corners[i]);
17217
+ minY = Math.min(minY, corners[i + 1]);
17218
+ maxY = Math.max(maxY, corners[i + 1]);
17219
+ }
17220
+ return {
17221
+ x: minX,
17222
+ y: minY,
17223
+ width: maxX - minX,
17224
+ height: maxY - minY
17225
+ };
17226
+ }
17227
+ /**
16793
17228
  * The box an absolute child is positioned against: the nearest
16794
17229
  * positioned ancestor's, else the layout root's.
16795
17230
  */
@@ -17587,6 +18022,7 @@ var LayoutEngine = class {
17587
18022
  rec.extentMaxY = y + height + rec.paintReachBottom;
17588
18023
  this.growExtentUp(node);
17589
18024
  rec.placeDirty = true;
18025
+ if (rec.positioned || node === this.layoutRoot) this.blockResized = true;
17590
18026
  this.layoutVersion++;
17591
18027
  if (this.anchorDependents.size > 0) {
17592
18028
  const dependents = this.anchorDependents.get(node);
@@ -20719,6 +21155,6 @@ function createCanvasSurface(host) {
20719
21155
  return new CanvasSurface(host);
20720
21156
  }
20721
21157
  //#endregion
20722
- export { pointerDeviceOf as $, UiKeyboardEvent as $a, boxShadow as $i, caretRectFor as $n, radialGradient as $r, DEFAULT_FONT_SIZE as $t, withOverrideSource as A, rgb8 as Aa, darkTheme as Ai, linkRunAtPointIn as An, UiProperties as Ar, edgeField as At, FlexDirection as B, writeDeclaredProperty as Ba, withThemeExtension as Bi, isReadOnly as Bn, validateSubgrid as Br, fillTextRects as Bt, SCROLLBAR_LINGER_MS as C, UiBasicColors as Ca, insetsEqual as Ci, isNodeTabStop as Cn, findPropertyDefinition as Cr, offsetAtPointIn as Ct, formatExplanation as D, colorsEqual as Da, bandOf as Di, hasTextLinks as Dn, propertyEffects as Dr, wordRangeIn as Dt, formatConstraints as E, colorValuesEqual as Ea, UiContainerSizeSource as Ei, clearLinkHover as En, inheritedPropertyNames as Er, selectionRectsIn as Et, clampSize as F, UiNode as Fa, defineThemeExtension as Fi, caretVisibleAt as Fn, normalizeStates as Fr, EditableLayout as Ft, CrossAxisAlignment as G, visualState as Ga, densityFactors as Gi, videoFrameSize as Gn, parseTransform as Gr, textMeasureRequest as Gt, placeGridItems as H, UiVisualState as Ha, highContrastColors as Hi, syncEditorValue as Hn, paintValuesEqual as Hr, runCanvasStyleInto as Ht, constraintsEqual as I, DirtyNodeSet as Ia, hasThemeExtension as Ii, editorFor as In, statesEqual as Ir, applyCanvasTextStyle as It, parseCrossAxisAlignment as J, UiBeforeInputEvent as Ja, spacingEqual as Ji, spannedRunsFor as Jn, transformsEqual as Jr, bumpFontStack as Jt, MainAxisAlignment as K, visualStatesEqual as Ka, defaultSpacing as Ki, CharacterCountTextMeasurer as Kn, transform as Kr, textRunBackgrounds as Kt, tightenConstraints as L, clearOverrideProperty as La, noThemeExtensions as Li, editorOf as Ln, validateRole as Lr, buildFontString as Lt, contentOffset as M, createEnvironmentKey as Ma, themesEqual as Mi, CARET_BLINK_MS as Mn, UI_SEMANTIC_STATES as Mr, commandForKey as Mt, LayoutRecord as N, findEnvironmentKey as Na, withContrast as Ni, CARET_WIDTH as Nn, isUiRole as Nr, detectEditingPlatform as Nt, formatNumber as O, normalizeColor as Oa, containerBands as Oi, linkHoverOf as On, propertyIsInherited as Or, adjacentField as Ot, Constraints as P, UiEnvironment as Pa, withDensity as Pi, EDITOR_PROP as Pn, isUiSemanticState as Pr, isPrintable as Pt, capturePointer as Q, UiInputEvent as Qa, BOX_SHADOW_BLUR_REACH as Qi, DEFAULT_LINE_HEIGHT_FACTOR as Qn, linearGradient as Qr, DEFAULT_FONT_FAMILY as Qt, MAX_MEASURES_PER_CHILD as R, overrideSources as Ra, themeExtension as Ri, isEditableNode as Rn, validateStates as Rr, createCanvasTextStyle as Rt, SCROLLBAR_FADE_MS as S, lightColors as Sa, UiInsetRegistry as Si, isNodeSelectable as Sn, closestPropertyName as Sr, hasDrawnText as St, describeOverrides as T, colorToRgba as Ta, observeViewportInsets as Ti, resolveCursor as Tn, inheritedPropertyFlags as Tr, paragraphGeometryFrom as Tt, sizeGridTracks as U, defaultVisualState as Ua, raiseContrast as Ui, resolveColorValue as Un, pathValuesEqual as Ur, runFontString as Ut, parseFlexDirection as V, writeOverrideProperty as Va, contrastRatio as Vi, nextCaretToggle as Vn, inputsEqual as Vr, layoutTextLines as Vt, AlignContent as W, hasVisualState as Wa, relativeLuminance as Wi, isVideoSurface as Wn, UiTransforms as Wr, spanOf as Wt, CanvasPlatformSurface as X, UiFocusEvent as Xa, defaultShadows as Xi, layoutParagraph as Xn, gradientPaint as Xr, fontStackFor as Xt, parseMainAxisAlignment as Y, UiEventType as Ya, spacingSteps as Yi, ELLIPSIS as Yn, MAX_GRADIENT_STOPS as Yr, clearFontStacks as Yt, UiPlatformAdapter as Z, UiGestureEvent as Za, shadowsEqual as Zi, proportionalFontMetrics as Zn, gradientsEqual as Zr, registerFontStack as Zt, LABEL_PADDING_X as _, textContentOf as _a, normalizeBorderRadius as _i, selectionRangeOf as _n, resolveNumber as _r, scrollRange as _t, PaintPictureCache as a, isShapeName as aa, isMinMaxTrack as ai, isPaintVisible as an, UiWheelDeltaMode as ao, offsetForVerticalMove as ar, UiPinchRecognizer as at, snapScroll as b, colorsEqualPalette as ba, propertyValuesEqual as bi, isNodeHitTestable as bn, resolveString as br, scrollbarZoneAt as bt, EMPTY_RECORDING as c, isTypographyRole as ca, percent as ci, resolvePaintState as cn, wheelDeltaYOf as co, graphemeBoundaries as cr, UiKeyboardController as ct, tracePathData as d, editableSpansOf as da, UiBorderRadiuses as di, matchRangesOf as dn, UiBinding as do, nextGraphemeEnd as dr, UiHitTester as dt, boxShadowArraysEqual as ea, validateGradient as ei, DEFAULT_FONT_WEIGHT as en, UiPasteEvent as eo, lineIndexAtY as er, prepareInputSurface as et, ScaledImageCache as f, flattenTextSpans as fa, borderRadius as fi, setMatchRanges as fn, nextWordEnd as fr, SCROLLBAR_HOVER_ZONE as ft, paintsAfterChildren as g, spannedTextOf as ga, borderRadiusValuesEqual as gi, selectableTextOf as gn, resolveBoolean as gr, scrollLeaderOf as gt, hasDecorationPhase as h, spanAtOffset as ha, borderRadiusIsZero as hi, selectableTextNodes as hn, wordRangeAt as hr, SCROLLBAR_THICKNESS as ht, traceRoundedRect as i, defaultShapes as ia, isFrLength as ii, createPaintState as in, UiTextChangeEvent as io, offsetAtX as ir, UiGestureRecognizer as it, accumulatedOffsetTo as j, rgba as ja, lightTheme as ji, setLinkHover as jn, UI_ROLES as jr, editingGroupOf as jt, labelNode as k, parseColor as ka, unknownContainerSize as ki, linkOf as kn, propertyValuesEqualByName as kr, comparePositions as kt, PaintRecorder as l, typographyEqual as la, repeat as li, TEXT_MATCHES_PROP as ln, UiNodeType as lo, lineEndAt as lr, UiPointerController as lt, decorationRect as m, resolvedSpansOf as ma, borderRadiusEqual as mi, clearSelectionRange as mn, previousWordStart as mr, SCROLLBAR_MIN_THUMB as mt, createCanvasSurface as n, boxShadowReach as na, fr as ni, colorToCss as nn, UiPointerEvent as no, lineLimit as nr, UiEditingController as nt, paintPictures as o, shapesEqual as oa, isPercentLength as oi, normalizeTextAlign as on, UiWheelEvent as oo, selectionRects as or, UiWheelController as ot, decorationColor as p, hiddenRangesOf as pa, borderRadiusCorners as pi, TEXT_SELECTION_PROP as pn, previousGraphemeStart as pr, SCROLLBAR_INSET as pt, parseAlignContent as q, MOUSE_POINTER as qa, scaleSpacing as qi, ParagraphTextMeasurer as qn, transformIsIdentity as qr, textRunDecorations as qt, Canvas2DRenderer as r, boxShadowsEqual as ra, isAutoLength as ri, computeObjectFitRect as rn, UiSelectionChangeEvent as ro, offsetAtPoint as rr, UiTouchScroller as rt, PaintTarget as s, defaultTypography as sa, minmax as si, normalizeVerticalAlign as sn, noKeyModifiers as so, EditableTextModel as sr, isScrollContainer as st, CanvasSurface as t, boxShadowRadius as ta, auto as ti, DEFAULT_TEXT_COLOR as tn, UiPinchEvent as to, lineIndexForOffset as tr, touchActionFor as tt, replayPaint as u, defaultTextStyle as ua, resolveLength as ui, clearMatchRanges as un, DirtyFlags as uo, lineStartAt as ur, UiFocusManager as ut, drawOverlayShapes as v, textSpansEqual as va, uniformBorderRadius as vi, setSelectionRange as vn, resolveProperty as vr, scrollbarThumb as vt, describeLength as w, colorToHex as wa, noInsets as wi, isPressable as wn, getPropertyNames as wr, paragraphGeometry as wt, LayoutEngine as x, darkColors as xa, UiEnvironmentKeys as xi, isNodeInert as xn, UiGraph as xr, UiInputDispatcher as xt, labelOrigin as y, textStylesEqual as ya, defineProperty as yi, isNodeFocusable as yn, resolvePropertyByName as yr, scrollbarThumbs as yt, isLayoutProtocol as z, resetOverrideWarnings as za, themeExtensionsEqual as zi, isMultiline as zn, UI_SUBGRID_AXES as zr, drawText as zt };
21158
+ export { pointerDeviceOf as $, UiKeyboardEvent as $a, boxShadow as $i, lineIndexAtY as $n, radialGradient as $r, DEFAULT_FONT_SIZE as $t, withOverrideSource as A, rgb8 as Aa, darkTheme as Ai, linkRunAtPointIn as An, UiProperties as Ar, edgeField as At, FlexDirection as B, writeDeclaredProperty as Ba, withThemeExtension as Bi, isReadOnly as Bn, validateSubgrid as Br, fillTextRects as Bt, SCROLLBAR_LINGER_MS as C, UiBasicColors as Ca, insetsEqual as Ci, isNodeTabStop as Cn, findPropertyDefinition as Cr, offsetAtPointIn as Ct, formatExplanation as D, colorsEqual as Da, bandOf as Di, hasTextLinks as Dn, propertyEffects as Dr, wordRangeIn as Dt, formatConstraints as E, colorValuesEqual as Ea, UiContainerSizeSource as Ei, clearLinkHover as En, inheritedPropertyNames as Er, selectionRectsIn as Et, clampSize as F, UiNode as Fa, defineThemeExtension as Fi, caretVisibleAt as Fn, normalizeStates as Fr, EditableLayout as Ft, CrossAxisAlignment as G, visualState as Ga, densityFactors as Gi, videoFrameSize as Gn, parseTransform as Gr, textMeasureRequest as Gt, placeGridItems as H, UiVisualState as Ha, highContrastColors as Hi, syncEditorValue as Hn, paintValuesEqual as Hr, runCanvasStyleInto as Ht, constraintsEqual as I, DirtyNodeSet as Ia, hasThemeExtension as Ii, editorFor as In, statesEqual as Ir, applyCanvasTextStyle as It, parseCrossAxisAlignment as J, UiBeforeInputEvent as Ja, spacingEqual as Ji, spannedRunsFor as Jn, transformsEqual as Jr, bumpFontStack as Jt, MainAxisAlignment as K, visualStatesEqual as Ka, defaultSpacing as Ki, CharacterCountTextMeasurer as Kn, transform as Kr, textRunBackgrounds as Kt, tightenConstraints as L, clearOverrideProperty as La, noThemeExtensions as Li, editorOf as Ln, validateRole as Lr, buildFontString as Lt, contentOffset as M, createEnvironmentKey as Ma, themesEqual as Mi, CARET_BLINK_MS as Mn, UI_SEMANTIC_STATES as Mr, commandForKey as Mt, LayoutRecord as N, findEnvironmentKey as Na, withContrast as Ni, CARET_WIDTH as Nn, isUiRole as Nr, detectEditingPlatform as Nt, formatNumber as O, normalizeColor as Oa, containerBands as Oi, linkHoverOf as On, propertyIsInherited as Or, adjacentField as Ot, Constraints as P, UiEnvironment as Pa, withDensity as Pi, EDITOR_PROP as Pn, isUiSemanticState as Pr, isPrintable as Pt, capturePointer as Q, UiInputEvent as Qa, BOX_SHADOW_BLUR_REACH as Qi, caretRectFor as Qn, linearGradient as Qr, DEFAULT_FONT_FAMILY as Qt, MAX_MEASURES_PER_CHILD as R, overrideSources as Ra, themeExtension as Ri, isEditableNode as Rn, validateStates as Rr, createCanvasTextStyle as Rt, SCROLLBAR_FADE_MS as S, lightColors as Sa, UiInsetRegistry as Si, isNodeSelectable as Sn, closestPropertyName as Sr, hasDrawnText as St, describeOverrides as T, colorToRgba as Ta, observeViewportInsets as Ti, resolveCursor as Tn, inheritedPropertyFlags as Tr, paragraphGeometryFrom as Tt, sizeGridTracks as U, defaultVisualState as Ua, raiseContrast as Ui, resolveColorValue as Un, pathValuesEqual as Ur, runFontString as Ut, parseFlexDirection as V, writeOverrideProperty as Va, contrastRatio as Vi, nextCaretToggle as Vn, inputsEqual as Vr, layoutTextLines as Vt, AlignContent as W, hasVisualState as Wa, relativeLuminance as Wi, isVideoSurface as Wn, UiTransforms as Wr, spanOf as Wt, CanvasPlatformSurface as X, UiFocusEvent as Xa, defaultShadows as Xi, layoutParagraph as Xn, gradientPaint as Xr, fontStackFor as Xt, parseMainAxisAlignment as Y, UiEventType as Ya, spacingSteps as Yi, ELLIPSIS as Yn, MAX_GRADIENT_STOPS as Yr, clearFontStacks as Yt, UiPlatformAdapter as Z, UiGestureEvent as Za, shadowsEqual as Zi, proportionalFontMetrics as Zn, gradientsEqual as Zr, registerFontStack as Zt, LABEL_PADDING_X as _, textContentOf as _a, normalizeBorderRadius as _i, selectionRangeOf as _n, resolveBoolean as _r, scrollRange as _t, PaintPictureCache as a, isShapeName as aa, isMinMaxTrack as ai, isPaintVisible as an, UiWheelDeltaMode as ao, selectionRects as ar, UiPinchRecognizer as at, snapScroll as b, colorsEqualPalette as ba, propertyValuesEqual as bi, isNodeHitTestable as bn, resolvePropertyByName as br, scrollbarZoneAt as bt, EMPTY_RECORDING as c, isTypographyRole as ca, percent as ci, resolvePaintState as cn, wheelDeltaYOf as co, lineEndAt as cr, UiKeyboardController as ct, tracePathData as d, editableSpansOf as da, UiBorderRadiuses as di, matchRangesOf as dn, UiBinding as do, nextWordEnd as dr, UiHitTester as dt, boxShadowArraysEqual as ea, validateGradient as ei, DEFAULT_FONT_WEIGHT as en, UiPasteEvent as eo, lineIndexForOffset as er, prepareInputSurface as et, ScaledImageCache as f, flattenTextSpans as fa, borderRadius as fi, setMatchRanges as fn, previousGraphemeStart as fr, SCROLLBAR_HOVER_ZONE as ft, paintsAfterChildren as g, spannedTextOf as ga, borderRadiusValuesEqual as gi, selectableTextOf as gn, DEFAULT_LINE_HEIGHT_FACTOR as gr, scrollLeaderOf as gt, hasDecorationPhase as h, spanAtOffset as ha, borderRadiusIsZero as hi, selectableTextNodes as hn, UiGraph as hr, SCROLLBAR_THICKNESS as ht, traceRoundedRect as i, defaultShapes as ia, isFrLength as ii, createPaintState as in, UiTextChangeEvent as io, offsetForVerticalMove as ir, UiGestureRecognizer as it, accumulatedOffsetTo as j, rgba as ja, lightTheme as ji, setLinkHover as jn, UI_ROLES as jr, editingGroupOf as jt, labelNode as k, parseColor as ka, unknownContainerSize as ki, linkOf as kn, propertyValuesEqualByName as kr, comparePositions as kt, PaintRecorder as l, typographyEqual as la, repeat as li, TEXT_MATCHES_PROP as ln, UiNodeType as lo, lineStartAt as lr, UiPointerController as lt, decorationRect as m, resolvedSpansOf as ma, borderRadiusEqual as mi, clearSelectionRange as mn, wordRangeAt as mr, SCROLLBAR_MIN_THUMB as mt, createCanvasSurface as n, boxShadowReach as na, fr as ni, colorToCss as nn, UiPointerEvent as no, offsetAtPoint as nr, UiEditingController as nt, paintPictures as o, shapesEqual as oa, isPercentLength as oi, normalizeTextAlign as on, UiWheelEvent as oo, EditableTextModel as or, UiWheelController as ot, decorationColor as p, hiddenRangesOf as pa, borderRadiusCorners as pi, TEXT_SELECTION_PROP as pn, previousWordStart as pr, SCROLLBAR_INSET as pt, parseAlignContent as q, MOUSE_POINTER as qa, scaleSpacing as qi, ParagraphTextMeasurer as qn, transformIsIdentity as qr, textRunDecorations as qt, Canvas2DRenderer as r, boxShadowsEqual as ra, isAutoLength as ri, computeObjectFitRect as rn, UiSelectionChangeEvent as ro, offsetAtX as rr, UiTouchScroller as rt, PaintTarget as s, defaultTypography as sa, minmax as si, normalizeVerticalAlign as sn, noKeyModifiers as so, graphemeBoundaries as sr, isScrollContainer as st, CanvasSurface as t, boxShadowRadius as ta, auto as ti, DEFAULT_TEXT_COLOR as tn, UiPinchEvent as to, lineLimit as tr, touchActionFor as tt, replayPaint as u, defaultTextStyle as ua, resolveLength as ui, clearMatchRanges as un, DirtyFlags as uo, nextGraphemeEnd as ur, UiFocusManager as ut, drawOverlayShapes as v, textSpansEqual as va, uniformBorderRadius as vi, setSelectionRange as vn, resolveNumber as vr, scrollbarThumb as vt, describeLength as w, colorToHex as wa, noInsets as wi, isPressable as wn, getPropertyNames as wr, paragraphGeometry as wt, LayoutEngine as x, darkColors as xa, UiEnvironmentKeys as xi, isNodeInert as xn, resolveString as xr, UiInputDispatcher as xt, labelOrigin as y, textStylesEqual as ya, defineProperty as yi, isNodeFocusable as yn, resolveProperty as yr, scrollbarThumbs as yt, isLayoutProtocol as z, resetOverrideWarnings as za, themeExtensionsEqual as zi, isMultiline as zn, UI_SUBGRID_AXES as zr, drawText as zt };
20723
21159
 
20724
- //# sourceMappingURL=CanvasSurface-CDjWI3EH.js.map
21160
+ //# sourceMappingURL=CanvasSurface-CKvX3pXn.js.map