gesso-core 0.5.1 → 0.6.1

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,
@@ -3877,15 +3899,22 @@ const UiProperties = {
3877
3899
  compare: gradientsEqual,
3878
3900
  validate: validateGradient
3879
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
+ */
3880
3912
  color: defineProperty({
3881
3913
  name: "color",
3882
3914
  defaultValue: UiBasicColors.black,
3883
3915
  inherited: true,
3884
3916
  affects: P,
3885
- environmentKey: UiEnvironmentKeys.textStyle,
3886
- resolveFromEnvironment: (value) => {
3887
- return value.color;
3888
- },
3917
+ environmentKey: UiEnvironmentKeys.color,
3889
3918
  compare: colorValuesEqual
3890
3919
  }),
3891
3920
  borderColor: defineProperty({
@@ -4746,6 +4775,158 @@ function propertyValuesEqualByName(name, a, b) {
4746
4775
  return Object.is(a, b);
4747
4776
  }
4748
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
4749
4930
  //#region src/graph/UiGraph.ts
4750
4931
  /**
4751
4932
  * How many times one frame rebuilds environments that rebuilding others
@@ -5155,16 +5336,33 @@ var UiGraph = class {
5155
5336
  if (!present) {
5156
5337
  if (!node.properties.has(property)) return false;
5157
5338
  node.properties.delete(property);
5158
- this.markDirty(node, dirtyFlags);
5339
+ this.markDirty(node, this.withProvidedFlags(property, dirtyFlags));
5159
5340
  return true;
5160
5341
  }
5161
5342
  const previousValue = node.getProperty(property);
5162
5343
  if (Object.is(previousValue, value)) return false;
5163
5344
  node.setProperty(property, value);
5164
- this.markDirty(node, dirtyFlags);
5345
+ this.markDirty(node, this.withProvidedFlags(property, dirtyFlags));
5165
5346
  return true;
5166
5347
  }
5167
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
+ /**
5168
5366
  * Drains the dirty set and visits every node of every dirty subtree.
5169
5367
  *
5170
5368
  * Dirty roots can nest, so a node reached from an outer root is not
@@ -5227,10 +5425,27 @@ var UiGraph = class {
5227
5425
  const textStyle = node.getProperty("textStyle");
5228
5426
  if (textStyle !== void 0) {
5229
5427
  const scale = env.get(UiEnvironmentKeys.theme).typography;
5230
- if (isTypographyRole(textStyle, scale)) {
5231
- 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) {
5232
5432
  env = env.set(UiEnvironmentKeys.textStyle, style);
5233
- } 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);
5234
5449
  }
5235
5450
  const contentColor = node.getProperty("contentColor");
5236
5451
  if (contentColor !== void 0) env = env.set(UiEnvironmentKeys.contentColor, contentColor);
@@ -5271,9 +5486,10 @@ var UiGraph = class {
5271
5486
  const visit = (node) => {
5272
5487
  const previous = node.environment;
5273
5488
  const next = this.buildNodeEnvironment(node);
5274
- if (previous === null || !this.environmentsEqual(previous, next)) {
5489
+ const flags = previous === null ? 0 : this.environmentChangeFlags(previous, next, inheritedPropertyFlags);
5490
+ if (previous === null || flags !== 0) {
5275
5491
  node.environment = next;
5276
- if (previous !== null) this.markDirty(node, inheritedPropertyFlags);
5492
+ if (previous !== null) this.markDirty(node, flags);
5277
5493
  this.environmentChangedListener?.(node);
5278
5494
  }
5279
5495
  for (let current = node.firstChild; current !== null; current = current.nextSibling) visit(current);
@@ -5312,9 +5528,10 @@ var UiGraph = class {
5312
5528
  rebuildEnvironment(node, inheritedFlags) {
5313
5529
  const previous = node.environment;
5314
5530
  const next = this.buildNodeEnvironment(node);
5315
- if (previous === null || !this.environmentsEqual(previous, next)) {
5531
+ const flags = previous === null ? inheritedFlags : this.environmentChangeFlags(previous, next, inheritedFlags);
5532
+ if (flags !== 0) {
5316
5533
  node.environment = next;
5317
- this.markDirty(node, inheritedFlags);
5534
+ this.markDirty(node, flags);
5318
5535
  this.environmentChangedListener?.(node);
5319
5536
  }
5320
5537
  let child = node.firstChild;
@@ -5323,102 +5540,75 @@ var UiGraph = class {
5323
5540
  child = child.nextSibling;
5324
5541
  }
5325
5542
  }
5326
- environmentsEqual(a, b) {
5327
- if (a === b) return true;
5328
- 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;
5329
5558
  for (const keyName of a.providedKeys()) {
5330
- if (!b.providesOwn(keyName)) return false;
5331
- const previousValue = a.getOwn(keyName);
5332
- const nextValue = b.getOwn(keyName);
5333
- if (Object.is(previousValue, nextValue)) continue;
5334
- const compare = findEnvironmentKey(keyName)?.compare;
5335
- if (compare === void 0 || !compare(previousValue, nextValue)) return false;
5336
- }
5337
- 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;
5338
5580
  }
5339
5581
  };
5340
- //#endregion
5341
- //#region src/properties/UiPropertyResolver.ts
5342
- /**
5343
- * Resolves a property value for a node.
5344
- *
5345
- * Resolution order:
5346
- *
5347
- * 1. The value explicitly specified on the node.
5348
- * 2. The value inherited from the node's scoped environment.
5349
- * 3. The property definition's default value.
5350
- *
5351
- * The resolver does not allocate and is safe to call from hot paths
5352
- * such as layout and paint.
5353
- */
5354
- function resolveProperty(node, definition) {
5355
- const specified = node.properties.get(definition.name);
5356
- if (specified !== void 0) return specified;
5357
- if (definition.inherited && node.environment !== null) {
5358
- const environmentKey = definition.environmentKey;
5359
- if (environmentKey !== void 0) {
5360
- const envValue = node.environment.get(environmentKey);
5361
- if (definition.resolveFromEnvironment !== void 0) return definition.resolveFromEnvironment(envValue);
5362
- return envValue;
5363
- }
5364
- const fallback = node.environment.get(createFallbackKey(definition));
5365
- if (fallback !== void 0) return fallback;
5366
- }
5367
- return definition.defaultValue;
5368
- }
5369
- /**
5370
- * Resolves a property by name.
5371
- *
5372
- * Returns undefined when no definition exists; callers that know
5373
- * the property exists should use resolveProperty() with the
5374
- * definition for stronger typing.
5375
- */
5376
- function resolvePropertyByName(node, name) {
5377
- const definition = findPropertyDefinition(name);
5378
- if (definition === void 0) return;
5379
- return resolveProperty(node, definition);
5380
- }
5381
5582
  /**
5382
- * Resolves a numeric property, returning undefined when the value
5383
- * is missing or not a finite number.
5384
- */
5385
- function resolveNumber(node, name) {
5386
- const value = resolvePropertyByName(node, name);
5387
- if (typeof value === "number" && Number.isFinite(value)) return value;
5388
- }
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);
5389
5601
  /**
5390
- * Resolves a string property, returning undefined when the value is
5391
- * missing or not a non-empty string.
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.
5392
5606
  */
5393
- function resolveString(node, name) {
5394
- const value = resolvePropertyByName(node, name);
5395
- if (typeof value === "string" && value.length > 0) 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;
5396
5609
  }
5397
- /**
5398
- * Resolves a boolean property, returning undefined when the value
5399
- * is missing or not a boolean.
5400
- */
5401
- function resolveBoolean(node, name) {
5402
- const value = resolvePropertyByName(node, name);
5403
- if (typeof value === "boolean") return value;
5404
- }
5405
- /**
5406
- * Lazily creates a fallback environment key that matches the
5407
- * property name. The key is cached so repeated resolutions of the
5408
- * same property do not allocate.
5409
- */
5410
- const fallbackKeys = /* @__PURE__ */ new Map();
5411
- function createFallbackKey(definition) {
5412
- let key = fallbackKeys.get(definition.name);
5413
- if (key === void 0) {
5414
- key = {
5415
- name: definition.name,
5416
- defaultValue: definition.defaultValue,
5417
- compare: definition.compare
5418
- };
5419
- fallbackKeys.set(definition.name, key);
5420
- }
5421
- return key;
5610
+ function positive(value) {
5611
+ return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : void 0;
5422
5612
  }
5423
5613
  //#endregion
5424
5614
  //#region src/editing/TextBoundaries.ts
@@ -6474,75 +6664,6 @@ function isAscii(text) {
6474
6664
  return true;
6475
6665
  }
6476
6666
  //#endregion
6477
- //#region src/properties/UiTextFont.ts
6478
- /**
6479
- * `line-height: normal`: the factor of the font size a line takes when
6480
- * no line height is set. Shared by ParagraphLayout and PaintState.
6481
- */
6482
- const DEFAULT_LINE_HEIGHT_FACTOR = 1.2;
6483
- /**
6484
- * Resolves a node's font the one way layout and paint both use.
6485
- *
6486
- * Font size, family, weight and letter spacing inherit through the
6487
- * environment's text style. Line height is the subtle one: a text
6488
- * style carries a line height that belongs with its font size, so a
6489
- * node that inherits the style takes it whole. A node that sets its
6490
- * own `fontSize` without a `lineHeight` gets a normal line height for
6491
- * that size, `fontSize × 1.2`, rather than the inherited pixel value
6492
- * sized for a different font — the inherited 16.8px of the default
6493
- * style is right for 14px text and wrong for 22px. An explicit
6494
- * `lineHeight` always wins.
6495
- *
6496
- * Before this, layout read the raw props (unset line height → ×1.2)
6497
- * and paint read the inherited ones (→ 16.8px), so any text whose size
6498
- * differed from the style's was measured in one line box and drawn in
6499
- * another, and sat high or low inside it.
6500
- */
6501
- function resolveFont(node) {
6502
- const out = {
6503
- fontSize: 0,
6504
- fontFamily: "",
6505
- fontWeight: "normal",
6506
- lineHeight: 0,
6507
- letterSpacing: 0,
6508
- fontStyle: "normal",
6509
- fontStretch: "normal",
6510
- fontVariant: "normal",
6511
- fontKerning: "auto"
6512
- };
6513
- resolveFontInto(node, out);
6514
- return out;
6515
- }
6516
- /** `resolveFont`, writing into a target the caller owns. */
6517
- function resolveFontInto(node, out) {
6518
- const fontSize = positive(resolveProperty(node, UiProperties.fontSize)) ?? UiProperties.fontSize.defaultValue;
6519
- const ownFontSize = node.properties.get("fontSize");
6520
- const ownLineHeight = positive(node.properties.get("lineHeight"));
6521
- if (ownLineHeight !== void 0) out.lineHeight = ownLineHeight;
6522
- else if (ownFontSize !== void 0) out.lineHeight = fontSize * DEFAULT_LINE_HEIGHT_FACTOR;
6523
- else out.lineHeight = positive(resolveProperty(node, UiProperties.lineHeight)) ?? fontSize * 1.2;
6524
- out.fontSize = fontSize;
6525
- out.fontFamily = nonEmpty(resolveProperty(node, UiProperties.fontFamily)) ?? UiProperties.fontFamily.defaultValue;
6526
- out.fontWeight = weight(resolveProperty(node, UiProperties.fontWeight)) ?? UiProperties.fontWeight.defaultValue;
6527
- out.letterSpacing = finite(resolveProperty(node, UiProperties.letterSpacing)) ?? 0;
6528
- out.fontStyle = nonEmpty(resolveProperty(node, UiProperties.fontStyle)) ?? "normal";
6529
- out.fontStretch = nonEmpty(resolveProperty(node, UiProperties.fontStretch)) ?? "normal";
6530
- out.fontVariant = nonEmpty(resolveProperty(node, UiProperties.fontVariant)) ?? "normal";
6531
- out.fontKerning = nonEmpty(node.properties.get("fontKerning")) ?? "auto";
6532
- }
6533
- function positive(value) {
6534
- return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : void 0;
6535
- }
6536
- function finite(value) {
6537
- return typeof value === "number" && Number.isFinite(value) ? value : void 0;
6538
- }
6539
- function weight(value) {
6540
- return typeof value === "number" ? finite(value) : nonEmpty(value);
6541
- }
6542
- function nonEmpty(value) {
6543
- return typeof value === "string" && value.length > 0 ? value : void 0;
6544
- }
6545
- //#endregion
6546
6667
  //#region src/layout/ParagraphLayout.ts
6547
6668
  const ELLIPSIS = "…";
6548
6669
  /**
@@ -8866,11 +8987,14 @@ function paragraphGeometryFrom(lines, text, box, state, measurer) {
8866
8987
  function geometryFor(lines, text, request, state, measurer) {
8867
8988
  const end = lines.length === 0 ? 0 : lines[lines.length - 1].end;
8868
8989
  const spanned = spannedRunsFor(request, measurer);
8990
+ const truncated = end < text.length && /\S/.test(text.slice(end));
8869
8991
  return {
8870
8992
  lines,
8871
8993
  text: end === text.length ? text : text.slice(0, end),
8872
8994
  start: lines.length === 0 ? 0 : lines[0].start,
8873
8995
  end,
8996
+ source: text,
8997
+ sourceEnd: truncated ? text.length : end,
8874
8998
  measure: (run, from) => run.length === 0 ? 0 : spanned === void 0 || from === void 0 ? measurer.measureRunWidth(run, request) : spanned.width(text, from, from + run.length),
8875
8999
  rtl: state.rtl,
8876
9000
  hidden: state.spans === void 0 ? NO_RANGES : hiddenRangesOf(state.spans)
@@ -8880,21 +9004,73 @@ function geometryFor(lines, text, request, state, measurer) {
8880
9004
  function hasDrawnText(geometry) {
8881
9005
  return geometry.lines.length > 0 && geometry.end > geometry.start;
8882
9006
  }
8883
- /** The offset nearest a point, clamped to the drawn text. */
9007
+ /**
9008
+ * The offset nearest a point: within the drawn text, or `sourceEnd`
9009
+ * when the point is past the last drawn glyph of a truncated paragraph.
9010
+ */
8884
9011
  function offsetAtPointIn(geometry, x, y) {
8885
- if (geometry.lines.length === 0) return 0;
8886
- return offsetAtPoint(geometry.lines, geometry.text, x, y, geometry.measure, geometry.rtl);
9012
+ const lines = geometry.lines;
9013
+ if (lines.length === 0) return 0;
9014
+ const offset = offsetAtPoint(lines, geometry.text, x, y, geometry.measure, geometry.rtl);
9015
+ if (offset !== geometry.end || geometry.sourceEnd === geometry.end || lineIndexAtY(lines, y) !== lines.length - 1) return offset;
9016
+ const line = lines[lines.length - 1];
9017
+ const drawn = drawnWidth(geometry);
9018
+ return (geometry.rtl ? line.x + line.width - x : x - line.x) > drawn + (line.width - drawn) / 2 ? geometry.sourceEnd : offset;
8887
9019
  }
8888
- /** The boxes covering `[start, end)`, one per line the range touches. */
9020
+ /**
9021
+ * The boxes covering `[start, end)`, one per line the range touches.
9022
+ * A range reaching into the hidden tail lights the ellipsis, which is
9023
+ * where that text is on screen.
9024
+ */
8889
9025
  function selectionRectsIn(geometry, start, end) {
9026
+ if (geometry.lines.length === 0) return [];
8890
9027
  const from = clamp(start, geometry.start, geometry.end);
8891
9028
  const to = clamp(end, geometry.start, geometry.end);
8892
- if (geometry.lines.length === 0 || to <= from) return [];
8893
- return selectionRects(geometry.lines, geometry.text, from, to, geometry.measure, geometry.rtl);
9029
+ const rects = to <= from ? [] : selectionRects(geometry.lines, geometry.text, from, to, geometry.measure, geometry.rtl);
9030
+ const ellipsis = end > geometry.end && start < geometry.sourceEnd && geometry.sourceEnd > geometry.end ? ellipsisBox(geometry) : void 0;
9031
+ if (ellipsis === void 0) return rects;
9032
+ const last = rects.length === 0 ? void 0 : rects[rects.length - 1];
9033
+ if (last !== void 0 && last.y === ellipsis.y) {
9034
+ const left = Math.min(last.x, ellipsis.x);
9035
+ const right = Math.max(last.x + last.width, ellipsis.x + ellipsis.width);
9036
+ rects[rects.length - 1] = {
9037
+ x: left,
9038
+ y: last.y,
9039
+ width: right - left,
9040
+ height: last.height
9041
+ };
9042
+ } else rects.push(ellipsis);
9043
+ return rects;
8894
9044
  }
8895
- /** The word around an offset, for a double click. */
9045
+ /**
9046
+ * The word around an offset, for a double click. Read from the source,
9047
+ * so a word the ellipsis cuts is taken whole, as a browser takes it.
9048
+ */
8896
9049
  function wordRangeIn(geometry, offset) {
8897
- return visibleWordRange(geometry.text, geometry.hidden, clamp(offset, geometry.start, geometry.end));
9050
+ const word = visibleWordRange(geometry.source, geometry.hidden, clamp(offset, geometry.start, geometry.sourceEnd));
9051
+ return {
9052
+ start: word.start,
9053
+ end: Math.min(word.end, geometry.sourceEnd)
9054
+ };
9055
+ }
9056
+ /** The advance of the last line's drawn glyphs, its ellipsis excluded. */
9057
+ function drawnWidth(geometry) {
9058
+ const line = geometry.lines[geometry.lines.length - 1];
9059
+ const drawn = geometry.text.slice(line.start, geometry.end);
9060
+ return drawn.length === line.text.length ? line.width : geometry.measure(drawn, line.start);
9061
+ }
9062
+ /** The ellipsis on the last line, or undefined for a clamp that draws none. */
9063
+ function ellipsisBox(geometry) {
9064
+ const line = geometry.lines[geometry.lines.length - 1];
9065
+ const drawn = drawnWidth(geometry);
9066
+ const width = line.width - drawn;
9067
+ if (width <= 0) return;
9068
+ return {
9069
+ x: geometry.rtl ? line.x : line.x + drawn,
9070
+ y: line.y,
9071
+ width,
9072
+ height: line.height
9073
+ };
8898
9074
  }
8899
9075
  function clamp(value, low, high) {
8900
9076
  return value < low ? low : value > high ? high : value;
@@ -11897,13 +12073,13 @@ var UiEditingController = class {
11897
12073
  let current = focused !== null && editingGroupOf(focused)?.root === root ? focused : adjacentField(root, target, 1) ?? edgeField(root, -1);
11898
12074
  if (current === null) return null;
11899
12075
  const distance = (node) => {
11900
- const box = this.host.visibleBox(node);
12076
+ const box = this.drawnBox(node);
11901
12077
  return y < box.y ? box.y - y : y > box.y + box.height ? y - box.y - box.height : 0;
11902
12078
  };
11903
12079
  for (;;) {
11904
12080
  const here = distance(current);
11905
12081
  if (here === 0) return current;
11906
- const box = this.host.visibleBox(current);
12082
+ const box = this.drawnBox(current);
11907
12083
  const next = adjacentField(root, current, y < box.y ? -1 : 1);
11908
12084
  if (next === null || distance(next) >= here) return current;
11909
12085
  current = next;
@@ -12000,20 +12176,20 @@ var UiEditingController = class {
12000
12176
  const node = this.focusedEditable;
12001
12177
  if (node === null || this.host.recordFor(node) === void 0) return null;
12002
12178
  const model = editorFor(node);
12003
- const caret = this.layoutOf(node).caretRect();
12004
- const visible = this.host.visibleBox(node);
12179
+ const local = this.layoutOf(node).caretRect();
12180
+ const caret = this.drawnBox(node, {
12181
+ x: local.x,
12182
+ y: local.y,
12183
+ width: 1,
12184
+ height: local.height
12185
+ });
12005
12186
  if (this.span !== null) {
12006
12187
  const { text, html } = this.spanCopy();
12007
12188
  return {
12008
12189
  text,
12009
12190
  selectionStart: 0,
12010
12191
  selectionEnd: text.length,
12011
- caret: {
12012
- x: visible.x + caret.x,
12013
- y: visible.y + caret.y,
12014
- width: 1,
12015
- height: caret.height
12016
- },
12192
+ caret,
12017
12193
  multiline: true,
12018
12194
  composing: false,
12019
12195
  ...html === void 0 ? {} : { html }
@@ -12024,12 +12200,7 @@ var UiEditingController = class {
12024
12200
  text: model.text,
12025
12201
  selectionStart: model.start,
12026
12202
  selectionEnd: model.end,
12027
- caret: {
12028
- x: visible.x + caret.x,
12029
- y: visible.y + caret.y,
12030
- width: 1,
12031
- height: caret.height
12032
- },
12203
+ caret,
12033
12204
  multiline: isMultiline(node),
12034
12205
  composing: model.composing,
12035
12206
  ...html === void 0 ? {} : { html }
@@ -12323,12 +12494,12 @@ var UiEditingController = class {
12323
12494
  fieldAt(root, from, y) {
12324
12495
  let current = from;
12325
12496
  for (;;) {
12326
- const box = this.host.visibleBox(current);
12497
+ const box = this.drawnBox(current);
12327
12498
  const step = y < box.y ? -1 : y > box.y + box.height ? 1 : 0;
12328
12499
  if (step === 0) return current;
12329
12500
  const next = adjacentField(root, current, step);
12330
12501
  if (next === null) return current;
12331
- const nextBox = this.host.visibleBox(next);
12502
+ const nextBox = this.drawnBox(next);
12332
12503
  if (step > 0 ? y < nextBox.y : y > nextBox.y + nextBox.height) return next;
12333
12504
  current = next;
12334
12505
  }
@@ -12398,6 +12569,17 @@ var UiEditingController = class {
12398
12569
  const layout = this.layoutOf(node);
12399
12570
  return offset === void 0 ? layout.caretRect() : layout.caretRect(Math.max(0, Math.min(offset, layout.model.text.length)));
12400
12571
  }
12572
+ /** Where a field, or a part of it in its own coordinates, is drawn; see `EditingHost.screenBox`. */
12573
+ drawnBox(node, part) {
12574
+ if (this.host.screenBox !== void 0) return this.host.screenBox(node, part);
12575
+ const box = this.host.visibleBox(node);
12576
+ return part === void 0 ? box : {
12577
+ x: box.x + part.x,
12578
+ y: box.y + part.y,
12579
+ width: part.width,
12580
+ height: part.height
12581
+ };
12582
+ }
12401
12583
  layoutOf(node) {
12402
12584
  const rec = this.host.recordFor(node);
12403
12585
  const state = resolvePaintState(node, this.paint);
@@ -14010,6 +14192,76 @@ function accumulatedOffsetTo(node, records, out) {
14010
14192
  out.x = record.x;
14011
14193
  out.y = record.y;
14012
14194
  }
14195
+ /**
14196
+ * Whether a node or any ancestor carries a `transform`.
14197
+ *
14198
+ * The same test `layoutForFrame` makes, an object rather than a
14199
+ * parsed non-identity transform: it is the question a caller asks to
14200
+ * take the plain additive path, so an identity object costs it only
14201
+ * the general one, which gives the same answer.
14202
+ */
14203
+ function hasTransformedChain(node) {
14204
+ for (let current = node; current !== null; current = current.parent) {
14205
+ const transform = current.properties.get("transform");
14206
+ if (typeof transform === "object" && transform !== null) return true;
14207
+ }
14208
+ return false;
14209
+ }
14210
+ /**
14211
+ * Carries points in a node's record space out to its parent's: through
14212
+ * its transform (unless `withTransform` is false), then its sticky
14213
+ * shift. The order is the renderer's
14214
+ * (`Canvas2DRenderer` translates by the sticky shift and then applies
14215
+ * `T(translate) · T(pivot) · R · S · T(-pivot)` about the record box),
14216
+ * because the point of this is to agree with where the node is drawn.
14217
+ *
14218
+ * `points` is x, y pairs, written in place.
14219
+ */
14220
+ function transformPointsOut(node, record, points, withTransform = true) {
14221
+ const transform = withTransform ? parseTransform(node.properties.get("transform")) : void 0;
14222
+ for (let i = 0; i < points.length; i += 2) {
14223
+ let x = points[i];
14224
+ let y = points[i + 1];
14225
+ if (transform !== void 0) {
14226
+ const originX = record.x + transform.x;
14227
+ const originY = record.y + transform.y;
14228
+ const dx = (x - originX) * transform.scaleX;
14229
+ const dy = (y - originY) * transform.scaleY;
14230
+ const cos = Math.cos(transform.rotation);
14231
+ const sin = Math.sin(transform.rotation);
14232
+ x = originX + dx * cos - dy * sin + transform.translateX;
14233
+ y = originY + dx * sin + dy * cos + transform.translateY;
14234
+ }
14235
+ points[i] = x + record.stickyOffsetX;
14236
+ points[i + 1] = y + record.stickyOffsetY;
14237
+ }
14238
+ }
14239
+ /**
14240
+ * The inverse of `transformPointsOut`: points in a node's parent's space
14241
+ * brought into the node's record space. A degenerate (zero-scale)
14242
+ * transform draws nothing and has no inverse, so it is left out, as
14243
+ * `UiHitTester.toLocal` leaves it out.
14244
+ */
14245
+ function transformPointsIn(node, record, points) {
14246
+ const transform = parseTransform(node.properties.get("transform"));
14247
+ const invertible = transform !== void 0 && transform.scaleX !== 0 && transform.scaleY !== 0;
14248
+ for (let i = 0; i < points.length; i += 2) {
14249
+ let x = points[i] - record.stickyOffsetX;
14250
+ let y = points[i + 1] - record.stickyOffsetY;
14251
+ if (invertible) {
14252
+ const originX = record.x + transform.x;
14253
+ const originY = record.y + transform.y;
14254
+ const dx = x - transform.translateX - originX;
14255
+ const dy = y - transform.translateY - originY;
14256
+ const cos = Math.cos(transform.rotation);
14257
+ const sin = Math.sin(transform.rotation);
14258
+ x = (dx * cos + dy * sin) / transform.scaleX + originX;
14259
+ y = (-dx * sin + dy * cos) / transform.scaleY + originY;
14260
+ }
14261
+ points[i] = x;
14262
+ points[i + 1] = y;
14263
+ }
14264
+ }
14013
14265
  //#endregion
14014
14266
  //#region src/layout/LayoutExplanation.ts
14015
14267
  const EPSILON$1 = 1e-6;
@@ -14522,6 +14774,8 @@ function stackDefault(node) {
14522
14774
  }
14523
14775
  var LayoutEngine = class {
14524
14776
  records = /* @__PURE__ */ new Map();
14777
+ /** A box's corners on their way through `projectBox` and `unprojectBox`. */
14778
+ cornerScratch = /* @__PURE__ */ new Float64Array(8);
14525
14779
  /**
14526
14780
  * The records the previous full layout ended with, held for the
14527
14781
  * length of the next one so their objects can be reused.
@@ -14576,6 +14830,22 @@ var LayoutEngine = class {
14576
14830
  /** Anchored nodes whose anchor moved this frame, re-placed once it settles. */
14577
14831
  movedAnchored = /* @__PURE__ */ new Set();
14578
14832
  /**
14833
+ * Every absolutely positioned node placed by its edges or at a point,
14834
+ * with the containing block it was placed against.
14835
+ *
14836
+ * Such a node is placed when its parent is, but its containing block
14837
+ * can be an ancestor further up: a panel pinned to the window's
14838
+ * corner from inside a column that keeps its size. When the window
14839
+ * grew, the column didn't move, so nothing placed the panel again,
14840
+ * and it stayed where the old corner was. A block that changes size
14841
+ * says so (`blockResized`), and the nodes whose block is no longer
14842
+ * the one they were placed against are placed again once the pass
14843
+ * settles.
14844
+ */
14845
+ absoluteBlocks = /* @__PURE__ */ new Map();
14846
+ /** A positioned node, or the root, took a new box this pass; see `absoluteBlocks`. */
14847
+ blockResized = false;
14848
+ /**
14579
14849
  * The nodes asking for `lift`, in the order they asked.
14580
14850
  *
14581
14851
  * Kept as a set rather than rebuilt per pass because layout is
@@ -15026,9 +15296,11 @@ var LayoutEngine = class {
15026
15296
  this.anchorOf.clear();
15027
15297
  this.anchorDependents.clear();
15028
15298
  this.movedAnchored.clear();
15299
+ this.blockResized = false;
15029
15300
  this.resetStats();
15030
15301
  this.fullLayout(constraints);
15031
15302
  const rec = this.record(node);
15303
+ this.replaceStaleAbsolute();
15032
15304
  this.applyScroll();
15033
15305
  for (const anchored of this.anchoredNodes) this.movedAnchored.add(anchored);
15034
15306
  this.replaceMovedAnchored();
@@ -15097,7 +15369,9 @@ var LayoutEngine = class {
15097
15369
  return;
15098
15370
  }
15099
15371
  this.layoutVersion++;
15372
+ this.blockResized = false;
15100
15373
  this.relayout(constraints);
15374
+ this.replaceStaleAbsolute();
15101
15375
  this.applyScroll();
15102
15376
  this.replaceMovedAnchored();
15103
15377
  }
@@ -15243,6 +15517,8 @@ var LayoutEngine = class {
15243
15517
  * scroll ancestor's offset and by the sticky offsets of the node and
15244
15518
  * its ancestors. Records stay in pre-scroll coordinates; this is the
15245
15519
  * projection renderers and hit testing agree on.
15520
+ *
15521
+ * Transforms are not applied; `screenBox` applies its ancestors'.
15246
15522
  */
15247
15523
  visibleBox(node) {
15248
15524
  const rec = this.records.get(node);
@@ -15272,6 +15548,48 @@ var LayoutEngine = class {
15272
15548
  };
15273
15549
  }
15274
15550
  /**
15551
+ * Where a node's box is drawn on the canvas: `visibleBox`, carried
15552
+ * through the `transform` of every ancestor as well. A card under a
15553
+ * panned and zoomed camera box is drawn far from its record, which a
15554
+ * transform never moves, and this is the box beside which its tooltip
15555
+ * belongs and over which its accessibility element goes. Under a
15556
+ * rotation it is the box the turned corners span.
15557
+ *
15558
+ * The node's own transform is left out. It is what a node animates
15559
+ * itself with — a spinner turning, a dialog scaling in — and a box
15560
+ * that included it would wobble with the animation: the mirror's
15561
+ * rectangle for a spinner grew and shrank on every step, and a
15562
+ * tooltip on it shook. The ancestors' are where it is; its own is how
15563
+ * it is drawn there. A tree with no transform above the node gets
15564
+ * `visibleBox`'s answer exactly.
15565
+ *
15566
+ * `part`, when given, is a rectangle in the node's own coordinates
15567
+ * (its box's top-left corner is 0, 0) and is answered instead of the
15568
+ * whole box: a caret inside a text field, the padding strip around a
15569
+ * node in the inspector. Adding its offset to the whole box's corner
15570
+ * is right only at scale 1; under a zoomed parent the part is scaled
15571
+ * with the node and sits twice as far into it.
15572
+ */
15573
+ screenBox(node, part) {
15574
+ const rec = this.records.get(node);
15575
+ if (rec === void 0) return {
15576
+ x: 0,
15577
+ y: 0,
15578
+ width: 0,
15579
+ height: 0
15580
+ };
15581
+ if (!hasTransformedChain(node.parent)) {
15582
+ const seen = this.visibleBox(node);
15583
+ return part === void 0 ? seen : {
15584
+ x: seen.x + part.x,
15585
+ y: seen.y + part.y,
15586
+ width: part.width,
15587
+ height: part.height
15588
+ };
15589
+ }
15590
+ 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);
15591
+ }
15592
+ /**
15275
15593
  * The scroll offsets each scroll ancestor would need so that `node`
15276
15594
  * is inside its viewport, `padding` pixels from the nearest edge,
15277
15595
  * innermost first. Nothing is changed: the caller writes the offsets
@@ -15424,6 +15742,7 @@ var LayoutEngine = class {
15424
15742
  this.textScrollPending.delete(current);
15425
15743
  this.anchoredNodes.delete(current);
15426
15744
  this.movedAnchored.delete(current);
15745
+ this.absoluteBlocks.delete(current);
15427
15746
  this.forgetAnchoring(current);
15428
15747
  this.stickyNodes.delete(current);
15429
15748
  this.stickyShifted.delete(current);
@@ -15785,13 +16104,14 @@ var LayoutEngine = class {
15785
16104
  let contentMain = 0;
15786
16105
  for (const line of lines) {
15787
16106
  const lineTotal = this.lineOuterMain(line, config.gapMain, "hypothetical");
15788
- if (mainBounded && (mainDefinite || lineTotal > mainMax)) {
16107
+ const lineWanted = this.lineMaxContentMain(line, config.gapMain);
16108
+ if (mainBounded && (mainDefinite || lineTotal > mainMax || lineWanted > mainMax)) {
15789
16109
  this.resolveLine(line, mainMax - config.gapMain * (line.items.length - 1), config);
15790
16110
  this.measureFlexedItems(line.items, content, direction, crossDefinite && !config.wrap ? row ? content.maxHeight : content.maxWidth : void 0);
15791
16111
  contentMain = Math.max(contentMain, this.lineOuterMain(line, config.gapMain, "final"));
15792
16112
  } else {
15793
16113
  for (const item of line.items) item.finalMain = item.hypotheticalMain;
15794
- contentMain = Math.max(contentMain, this.lineMaxContentMain(line, config.gapMain));
16114
+ contentMain = Math.max(contentMain, lineWanted);
15795
16115
  }
15796
16116
  }
15797
16117
  if (mainDefinite) contentMain = Math.max(mainMax, contentMain);
@@ -16613,8 +16933,12 @@ var LayoutEngine = class {
16613
16933
  * the anchor instead.
16614
16934
  */
16615
16935
  placeAbsoluteChildren(parent) {
16936
+ this.forEachAbsoluteChild(parent, (child) => this.placeAbsolute(child));
16937
+ }
16938
+ /** Places one absolutely positioned node against its containing block; see `placeAbsoluteChildren`. */
16939
+ placeAbsolute(child) {
16616
16940
  const savedBase = this.percentBase;
16617
- this.forEachAbsoluteChild(parent, (child) => {
16941
+ try {
16618
16942
  const cRec = this.record(child);
16619
16943
  const block = this.containingBlockOf(child);
16620
16944
  this.percentBase = {
@@ -16629,12 +16953,14 @@ var LayoutEngine = class {
16629
16953
  this.trackAnchor(child, anchor);
16630
16954
  const anchorRec = this.records.get(anchor);
16631
16955
  if (anchorRec !== void 0) {
16956
+ this.absoluteBlocks.delete(child);
16632
16957
  this.placeAnchored(child, cRec, anchorRec, anchor, block);
16633
16958
  return;
16634
16959
  }
16635
16960
  } else if (point !== void 0 && point !== null) {
16636
16961
  this.anchoredNodes.delete(child);
16637
16962
  this.trackAnchor(child, null);
16963
+ this.absoluteBlocks.set(child, block);
16638
16964
  this.measure(child, new Constraints(0, Math.max(0, block.width), 0, Math.max(0, block.height)));
16639
16965
  this.placeBeside(child, cRec, block.x + point.x, block.y + point.y, 0, 0, block);
16640
16966
  return;
@@ -16642,6 +16968,7 @@ var LayoutEngine = class {
16642
16968
  this.anchoredNodes.delete(child);
16643
16969
  this.trackAnchor(child, null);
16644
16970
  }
16971
+ this.absoluteBlocks.set(child, block);
16645
16972
  const marginH = cRec.marginLeft + cRec.marginRight;
16646
16973
  const marginV = cRec.marginTop + cRec.marginBottom;
16647
16974
  const availableWidth = Math.max(0, block.width - (cRec.left ?? 0) - (cRec.right ?? 0) - marginH);
@@ -16662,8 +16989,33 @@ var LayoutEngine = class {
16662
16989
  else if (cRec.bottom !== void 0) y = block.y + block.height - cRec.bottom - cRec.marginBottom - height;
16663
16990
  else y = block.y + cRec.marginTop;
16664
16991
  this.assignBox(child, x, y, width, height);
16665
- });
16666
- this.percentBase = savedBase;
16992
+ } finally {
16993
+ this.percentBase = savedBase;
16994
+ }
16995
+ }
16996
+ /**
16997
+ * Places again the absolutely positioned nodes whose containing block
16998
+ * is not the box they were placed against, once a pass has settled
16999
+ * every box. Only after a pass in which a positioned node or the root
17000
+ * took a new box, which is rare outside a resize; placing one can
17001
+ * resize a block another is placed against, so it repeats, up to the
17002
+ * limit that stops anchors spinning.
17003
+ */
17004
+ replaceStaleAbsolute() {
17005
+ for (let pass = 0; this.blockResized && pass < ANCHOR_CHAIN_LIMIT; pass++) {
17006
+ this.blockResized = false;
17007
+ for (const [child, was] of this.absoluteBlocks) {
17008
+ if (!this.records.has(child)) {
17009
+ this.absoluteBlocks.delete(child);
17010
+ continue;
17011
+ }
17012
+ const block = this.containingBlockOf(child);
17013
+ if (block.x === was.x && block.y === was.y && block.width === was.width && block.height === was.height) continue;
17014
+ this.placeAbsolute(child);
17015
+ if (this.record(child).placeDirty) this.place(child);
17016
+ }
17017
+ }
17018
+ this.blockResized = false;
16667
17019
  }
16668
17020
  /**
16669
17021
  * Places an anchored node beside its anchor.
@@ -16678,13 +17030,19 @@ var LayoutEngine = class {
16678
17030
  */
16679
17031
  placeAnchored(child, cRec, anchorRec, anchor, block) {
16680
17032
  this.measure(child, new Constraints(0, Math.max(0, block.width), 0, Math.max(0, block.height)));
17033
+ const part = child.properties.get("anchorRect");
17034
+ if (hasTransformedChain(anchor.parent) || hasTransformedChain(child.parent)) {
17035
+ 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);
17036
+ const local = this.unprojectBox(child, seen);
17037
+ this.placeBeside(child, cRec, local.x, local.y, local.width, local.height, block);
17038
+ return;
17039
+ }
16681
17040
  const scrollAnchor = this.scrollOffsetOf(anchor);
16682
17041
  const scrollChild = this.scrollOffsetOf(child);
16683
17042
  const stickyAnchor = this.stickyOffsetOf(anchor);
16684
17043
  const stickyChild = this.stickyOffsetOf(child);
16685
17044
  const ax = anchorRec.x + stickyAnchor.x - scrollAnchor.x + scrollChild.x - stickyChild.x;
16686
17045
  const ay = anchorRec.y + stickyAnchor.y - scrollAnchor.y + scrollChild.y - stickyChild.y;
16687
- const part = child.properties.get("anchorRect");
16688
17046
  if (part !== void 0 && part !== null) {
16689
17047
  this.placeBeside(child, cRec, ax + part.x, ay + part.y, part.width, part.height, block);
16690
17048
  return;
@@ -16843,6 +17201,85 @@ var LayoutEngine = class {
16843
17201
  };
16844
17202
  }
16845
17203
  /**
17204
+ * Where a box in a node's record space is seen on the canvas: through
17205
+ * the node's own sticky shift (not its transform; see `screenBox`),
17206
+ * then, for each ancestor in turn, its scroll offset (which moves only
17207
+ * what is inside it) and its transform and sticky shift. The same
17208
+ * chain the renderer composes on the way down, walked up; a turned box
17209
+ * is the box its corners span.
17210
+ */
17211
+ projectBox(node, x, y, width, height) {
17212
+ const corners = this.cornersOf(x, y, width, height);
17213
+ for (let current = node; current !== null; current = current.parent) {
17214
+ const rec = this.records.get(current);
17215
+ if (rec === void 0) continue;
17216
+ if (current !== node && rec.scrollable) for (let i = 0; i < corners.length; i += 2) {
17217
+ corners[i] -= rec.scrollX;
17218
+ corners[i + 1] -= rec.scrollY;
17219
+ }
17220
+ transformPointsOut(current, rec, corners, current !== node);
17221
+ }
17222
+ return this.boundsOfCorners(corners);
17223
+ }
17224
+ /**
17225
+ * A canvas box brought into the space an absolute child's record is
17226
+ * placed in: `projectBox` undone for each of its ancestors, outermost
17227
+ * first, and the child's own sticky shift taken off. The child's own
17228
+ * transform stays, because it applies on top of the box being placed.
17229
+ */
17230
+ unprojectBox(child, box) {
17231
+ const corners = this.cornersOf(box.x, box.y, box.width, box.height);
17232
+ const chain = [];
17233
+ for (let current = child.parent; current !== null; current = current.parent) chain.push(current);
17234
+ for (let i = chain.length - 1; i >= 0; i--) {
17235
+ const ancestor = chain[i];
17236
+ const rec = this.records.get(ancestor);
17237
+ if (rec === void 0) continue;
17238
+ transformPointsIn(ancestor, rec, corners);
17239
+ if (rec.scrollable) for (let j = 0; j < corners.length; j += 2) {
17240
+ corners[j] += rec.scrollX;
17241
+ corners[j + 1] += rec.scrollY;
17242
+ }
17243
+ }
17244
+ const own = this.records.get(child);
17245
+ if (own !== void 0) for (let j = 0; j < corners.length; j += 2) {
17246
+ corners[j] -= own.stickyOffsetX;
17247
+ corners[j + 1] -= own.stickyOffsetY;
17248
+ }
17249
+ return this.boundsOfCorners(corners);
17250
+ }
17251
+ /** The four corners of a box as x, y pairs, in a scratch array the projections reuse. */
17252
+ cornersOf(x, y, width, height) {
17253
+ const corners = this.cornerScratch;
17254
+ corners[0] = x;
17255
+ corners[1] = y;
17256
+ corners[2] = x + width;
17257
+ corners[3] = y;
17258
+ corners[4] = x;
17259
+ corners[5] = y + height;
17260
+ corners[6] = x + width;
17261
+ corners[7] = y + height;
17262
+ return corners;
17263
+ }
17264
+ boundsOfCorners(corners) {
17265
+ let minX = Infinity;
17266
+ let minY = Infinity;
17267
+ let maxX = -Infinity;
17268
+ let maxY = -Infinity;
17269
+ for (let i = 0; i < corners.length; i += 2) {
17270
+ minX = Math.min(minX, corners[i]);
17271
+ maxX = Math.max(maxX, corners[i]);
17272
+ minY = Math.min(minY, corners[i + 1]);
17273
+ maxY = Math.max(maxY, corners[i + 1]);
17274
+ }
17275
+ return {
17276
+ x: minX,
17277
+ y: minY,
17278
+ width: maxX - minX,
17279
+ height: maxY - minY
17280
+ };
17281
+ }
17282
+ /**
16846
17283
  * The box an absolute child is positioned against: the nearest
16847
17284
  * positioned ancestor's, else the layout root's.
16848
17285
  */
@@ -17640,6 +18077,7 @@ var LayoutEngine = class {
17640
18077
  rec.extentMaxY = y + height + rec.paintReachBottom;
17641
18078
  this.growExtentUp(node);
17642
18079
  rec.placeDirty = true;
18080
+ if (rec.positioned || node === this.layoutRoot) this.blockResized = true;
17643
18081
  this.layoutVersion++;
17644
18082
  if (this.anchorDependents.size > 0) {
17645
18083
  const dependents = this.anchorDependents.get(node);
@@ -20772,6 +21210,6 @@ function createCanvasSurface(host) {
20772
21210
  return new CanvasSurface(host);
20773
21211
  }
20774
21212
  //#endregion
20775
- 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 };
21213
+ 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 };
20776
21214
 
20777
- //# sourceMappingURL=CanvasSurface-Dok8FuyX.js.map
21215
+ //# sourceMappingURL=CanvasSurface-Bxu_gNmc.js.map