@react-x11/components 0.10.0 → 0.11.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.
Files changed (90) hide show
  1. package/dist/code/index.d.ts.map +1 -1
  2. package/dist/code/index.js +25 -24
  3. package/dist/code/index.js.map +1 -1
  4. package/dist/code-language/index.d.ts +1 -1
  5. package/dist/code-language/index.d.ts.map +1 -1
  6. package/dist/code-language/index.js +1 -1
  7. package/dist/code-language/index.js.map +1 -1
  8. package/dist/code-language/runs.d.ts +31 -0
  9. package/dist/code-language/runs.d.ts.map +1 -1
  10. package/dist/code-language/runs.js +105 -0
  11. package/dist/code-language/runs.js.map +1 -1
  12. package/dist/codeblock/index.d.ts +13 -0
  13. package/dist/codeblock/index.d.ts.map +1 -1
  14. package/dist/codeblock/index.js +37 -1
  15. package/dist/codeblock/index.js.map +1 -1
  16. package/dist/html/css/cascade.d.ts +32 -10
  17. package/dist/html/css/cascade.d.ts.map +1 -1
  18. package/dist/html/css/cascade.js +72 -27
  19. package/dist/html/css/cascade.js.map +1 -1
  20. package/dist/html/css/style.d.ts +7 -4
  21. package/dist/html/css/style.d.ts.map +1 -1
  22. package/dist/html/css/style.js +37 -6
  23. package/dist/html/css/style.js.map +1 -1
  24. package/dist/html/css/ua.js +8 -5
  25. package/dist/html/css/ua.js.map +1 -1
  26. package/dist/html/layout/block.d.ts.map +1 -1
  27. package/dist/html/layout/block.js +127 -9
  28. package/dist/html/layout/block.js.map +1 -1
  29. package/dist/html/layout/boxes.d.ts +27 -0
  30. package/dist/html/layout/boxes.d.ts.map +1 -1
  31. package/dist/html/layout/boxes.js +30 -2
  32. package/dist/html/layout/boxes.js.map +1 -1
  33. package/dist/html/layout/inline.d.ts +3 -0
  34. package/dist/html/layout/inline.d.ts.map +1 -1
  35. package/dist/html/layout/inline.js +236 -14
  36. package/dist/html/layout/inline.js.map +1 -1
  37. package/dist/html/node.d.ts.map +1 -1
  38. package/dist/html/node.js +118 -57
  39. package/dist/html/node.js.map +1 -1
  40. package/dist/html/paint.d.ts.map +1 -1
  41. package/dist/html/paint.js +203 -37
  42. package/dist/html/paint.js.map +1 -1
  43. package/dist/html/svg.d.ts.map +1 -1
  44. package/dist/html/svg.js +27 -20
  45. package/dist/html/svg.js.map +1 -1
  46. package/dist/internal/codelines.d.ts +42 -0
  47. package/dist/internal/codelines.d.ts.map +1 -0
  48. package/dist/internal/codelines.js +170 -0
  49. package/dist/internal/codelines.js.map +1 -0
  50. package/dist/markdown/index.d.ts.map +1 -1
  51. package/dist/markdown/index.js +98 -26
  52. package/dist/markdown/index.js.map +1 -1
  53. package/dist/rich-text-editor/index.d.ts.map +1 -1
  54. package/dist/rich-text-editor/index.js +3 -8
  55. package/dist/rich-text-editor/index.js.map +1 -1
  56. package/dist/rich-text-editor/markdown.d.ts.map +1 -1
  57. package/dist/rich-text-editor/markdown.js +30 -1
  58. package/dist/rich-text-editor/markdown.js.map +1 -1
  59. package/dist/rich-text-editor/replace.d.ts +13 -0
  60. package/dist/rich-text-editor/replace.d.ts.map +1 -0
  61. package/dist/rich-text-editor/replace.js +64 -0
  62. package/dist/rich-text-editor/replace.js.map +1 -0
  63. package/dist/terminal-output/index.d.ts.map +1 -1
  64. package/dist/terminal-output/index.js +100 -25
  65. package/dist/terminal-output/index.js.map +1 -1
  66. package/dist/terminal-output/runs.d.ts +4 -1
  67. package/dist/terminal-output/runs.d.ts.map +1 -1
  68. package/dist/terminal-output/runs.js +5 -1
  69. package/dist/terminal-output/runs.js.map +1 -1
  70. package/package.json +1 -1
  71. package/src/code/index.ts +34 -32
  72. package/src/code-language/index.ts +1 -1
  73. package/src/code-language/runs.ts +111 -1
  74. package/src/codeblock/index.ts +48 -1
  75. package/src/html/css/cascade.ts +117 -39
  76. package/src/html/css/style.ts +43 -15
  77. package/src/html/css/ua.ts +8 -5
  78. package/src/html/layout/block.ts +134 -8
  79. package/src/html/layout/boxes.ts +43 -2
  80. package/src/html/layout/inline.ts +257 -13
  81. package/src/html/node.ts +145 -79
  82. package/src/html/paint.ts +236 -45
  83. package/src/html/svg.ts +30 -19
  84. package/src/internal/codelines.ts +200 -0
  85. package/src/markdown/index.ts +145 -26
  86. package/src/rich-text-editor/index.ts +3 -11
  87. package/src/rich-text-editor/markdown.ts +36 -1
  88. package/src/rich-text-editor/replace.ts +85 -0
  89. package/src/terminal-output/index.ts +127 -34
  90. package/src/terminal-output/runs.ts +16 -2
package/src/html/node.ts CHANGED
@@ -51,14 +51,22 @@ import { codePointAtOffset, codeUnitOffsets } from '../internal/text.js';
51
51
  import { attr, HtmlSource, imageUrlOf, isElement, tagOf } from './dom.js';
52
52
  import type { Document } from './dom.js';
53
53
  import { Cascade } from './css/cascade.js';
54
+ import type { MetricFace } from './css/cascade.js';
54
55
  import { mediaMatches, parseStylesheet } from './css/parse.js';
55
56
  import type { Stylesheet } from './css/parse.js';
56
57
  import { uaStylesheet } from './css/ua.js';
57
58
  import type { ComputedStyle, RootLook } from './css/style.js';
58
- import { buildBoxes, CONTENT_IMAGES } from './layout/boxes.js';
59
+ import {
60
+ BOX_RAISES,
61
+ buildBoxes,
62
+ CONTENT_IMAGES,
63
+ LINE_BOX_RAISES,
64
+ SHIFTED_LINES,
65
+ } from './layout/boxes.js';
59
66
  import type {
60
67
  Box,
61
68
  BoxTree,
69
+ LineBox,
62
70
  LineText,
63
71
  ReplacedKind,
64
72
  TextLayoutLike,
@@ -67,7 +75,7 @@ import { layoutDocument } from './layout/block.js';
67
75
  import { TextLayoutCache } from './layout/cache.js';
68
76
  import { shapingSafe } from './layout/shaping.js';
69
77
  import { SurfaceCache } from './surfaces.js';
70
- import { inlineDecoration, runFor } from './layout/inline.js';
78
+ import { faceExtentOf, inlineDecoration, runFor } from './layout/inline.js';
71
79
  import type { FontsLike } from './layout/inline.js';
72
80
  import type { TextRun } from '../richtext/index.js';
73
81
  // Through the inline module rather than a second cache: the offsets table for
@@ -583,9 +591,9 @@ export class HtmlViewNode extends Node {
583
591
  width,
584
592
  this._viewportHeight(),
585
593
  this._scale,
586
- fonts ? (family, size) => xHeightOf(fonts, family, size) : null,
587
- fonts ? (family, size) => zeroWidthOf(fonts, family, size) : null,
588
- fonts ? (family, size) => normalLineOf(fonts, family, size) : null,
594
+ fonts ? (face) => xHeightOf(fonts, face) : null,
595
+ fonts ? (face) => zeroWidthOf(fonts, face) : null,
596
+ fonts ? (face) => normalLineOf(fonts, face) : null,
589
597
  faces.length ? this._webFonts : null,
590
598
  );
591
599
  this._sheetsRead = {
@@ -1188,17 +1196,38 @@ export class HtmlViewNode extends Node {
1188
1196
  rect = { x: box.x, y: box.y, width: box.width, height: box.height };
1189
1197
  } else {
1190
1198
  const bands: Rect[] = [];
1199
+ // an inline box's fragments are on the lines of the block it is laid
1200
+ // out in, and no text of a float or a positioned box inside it — on
1201
+ // lines of their own — is one of them (CSSOM View 6.1): a list item
1202
+ // made inline around an absolute link measured as the link
1203
+ let block: Box | null = box.parent;
1204
+ while (block && !block.lines) block = block.parent;
1191
1205
  if (box.subtreeTextEnd > box.subtreeTextStart) {
1192
- collectBands(
1193
- tree.root,
1194
- box.subtreeTextStart,
1195
- box.subtreeTextEnd,
1196
- 0,
1197
- 0,
1198
- bands,
1199
- );
1206
+ if (box.kind === 'inline' && block?.lines) {
1207
+ lineBands(
1208
+ block.lines,
1209
+ box.subtreeTextStart,
1210
+ box.subtreeTextEnd,
1211
+ 0,
1212
+ 0,
1213
+ bands,
1214
+ );
1215
+ } else {
1216
+ collectBands(
1217
+ tree.root,
1218
+ box.subtreeTextStart,
1219
+ box.subtreeTextEnd,
1220
+ 0,
1221
+ 0,
1222
+ bands,
1223
+ );
1224
+ }
1225
+ }
1226
+ if (box.kind === 'inline') {
1227
+ fragmentReach(box, bands);
1228
+ const fonts = this._layouts?.fonts;
1229
+ if (fonts) fragmentHeights(box, bands, fonts);
1200
1230
  }
1201
- if (box.kind === 'inline') fragmentReach(box, bands);
1202
1231
  for (const band of bands) rect = rect ? unionRect(rect, band) : band;
1203
1232
  if (!rect) {
1204
1233
  // an empty subtree's range is `[0, 0)`, wherever it stands: where
@@ -1936,56 +1965,96 @@ function fragmentReach(box: Box, out: Rect[]): void {
1936
1965
  }
1937
1966
  }
1938
1967
 
1939
- function collectBands(
1940
- box: Box,
1968
+ /**
1969
+ * An inline element's bands made as tall as its fragments' border boxes,
1970
+ * as CSSOM View takes an inline box's client rects (6.1): its font's
1971
+ * content area about its own baseline, with the padding and the border
1972
+ * above and below it, which take no room on the line (CSS 2.1 10.6.1) and
1973
+ * which paint draws the background over (`paintInlineBoxes`). A band is a
1974
+ * line's height across until then: a link padded 10px below measured as
1975
+ * tall as its line and no taller.
1976
+ */
1977
+ function fragmentHeights(box: Box, bands: Rect[], fonts: FontsLike): void {
1978
+ let block = box.parent;
1979
+ while (block && !block.lines) block = block.parent;
1980
+ if (!block?.lines?.length) return;
1981
+ const face = faceExtentOf(fonts, box.style);
1982
+ const byTop = new Map<number, LineBox>();
1983
+ for (const line of block.lines) byTop.set(line.y, line);
1984
+ for (let i = 0; i < bands.length; i += 1) {
1985
+ const band = bands[i];
1986
+ const line = byTop.get(band.y);
1987
+ if (!line) continue;
1988
+ // on its own baseline, which `vertical-align` may raise off the line's
1989
+ const raise = SHIFTED_LINES.has(line)
1990
+ ? (LINE_BOX_RAISES.get(line)?.get(box) ?? BOX_RAISES.get(box) ?? 0)
1991
+ : 0;
1992
+ const baseline = line.y + line.baseline - raise;
1993
+ const top = baseline - face.ascent - box.padTop - box.borderTop;
1994
+ const bottom = baseline + face.descent + box.padBottom + box.borderBottom;
1995
+ bands[i] = { x: band.x, y: top, width: band.width, height: bottom - top };
1996
+ }
1997
+ }
1998
+
1999
+ /** The bands of a text range on one block's own lines. */
2000
+ function lineBands(
2001
+ lines: readonly LineBox[],
1941
2002
  from: number,
1942
2003
  to: number,
1943
2004
  dx: number,
1944
2005
  dy: number,
1945
2006
  out: Rect[],
1946
2007
  ): void {
1947
- if (box.subtreeTextEnd <= box.subtreeTextStart) return;
1948
- if (box.subtreeTextEnd <= from || box.subtreeTextStart >= to) return;
1949
- if (box.lines) {
1950
- const lines = box.lines;
1951
- // First line whose text can reach `from`, by binary search over the
1952
- // sorted text starts; stop at the first line past `to`.
1953
- let lo = 0;
1954
- let hi = lines.length;
1955
- while (lo < hi) {
1956
- const mid = (lo + hi) >> 1;
1957
- if (lines[mid].textEnd > from) hi = mid;
1958
- else lo = mid + 1;
1959
- }
1960
- for (let i = lo; i < lines.length; i += 1) {
1961
- const line = lines[i];
1962
- if (line.textStart >= to) break;
1963
- if (line.textEnd > from && line.textStart < to) {
1964
- for (const text of line.texts) {
1965
- const natural = text.layout.lines[text.layoutLine];
1966
- if (!natural) continue;
1967
- const a = Math.max(from, text.textStart);
1968
- const b = Math.min(to, text.textEnd);
1969
- if (b <= a) continue;
1970
- const offsets = layoutOffsetsOf(text.layout);
1971
- for (const band of bandsFor(
1972
- text.layout,
1973
- natural,
1974
- offsets,
1975
- layoutOffsetOf(text, a),
1976
- layoutOffsetOf(text, b, true),
1977
- )) {
1978
- out.push({
1979
- x: dx + band.x + text.drawX,
1980
- y: dy + line.y,
1981
- width: band.width,
1982
- height: line.height,
1983
- });
1984
- }
2008
+ // First line whose text can reach `from`, by binary search over the
2009
+ // sorted text starts; stop at the first line past `to`.
2010
+ let lo = 0;
2011
+ let hi = lines.length;
2012
+ while (lo < hi) {
2013
+ const mid = (lo + hi) >> 1;
2014
+ if (lines[mid].textEnd > from) hi = mid;
2015
+ else lo = mid + 1;
2016
+ }
2017
+ for (let i = lo; i < lines.length; i += 1) {
2018
+ const line = lines[i];
2019
+ if (line.textStart >= to) break;
2020
+ if (line.textEnd > from && line.textStart < to) {
2021
+ for (const text of line.texts) {
2022
+ const natural = text.layout.lines[text.layoutLine];
2023
+ if (!natural) continue;
2024
+ const a = Math.max(from, text.textStart);
2025
+ const b = Math.min(to, text.textEnd);
2026
+ if (b <= a) continue;
2027
+ const offsets = layoutOffsetsOf(text.layout);
2028
+ for (const band of bandsFor(
2029
+ text.layout,
2030
+ natural,
2031
+ offsets,
2032
+ layoutOffsetOf(text, a),
2033
+ layoutOffsetOf(text, b, true),
2034
+ )) {
2035
+ out.push({
2036
+ x: dx + band.x + text.drawX,
2037
+ y: dy + line.y,
2038
+ width: band.width,
2039
+ height: line.height,
2040
+ });
1985
2041
  }
1986
2042
  }
1987
2043
  }
1988
2044
  }
2045
+ }
2046
+
2047
+ function collectBands(
2048
+ box: Box,
2049
+ from: number,
2050
+ to: number,
2051
+ dx: number,
2052
+ dy: number,
2053
+ out: Rect[],
2054
+ ): void {
2055
+ if (box.subtreeTextEnd <= box.subtreeTextStart) return;
2056
+ if (box.subtreeTextEnd <= from || box.subtreeTextStart >= to) return;
2057
+ if (box.lines) lineBands(box.lines, from, to, dx, dy, out);
1989
2058
  // Atomics are ordinary children, reached below.
1990
2059
  for (const child of box.children) {
1991
2060
  if (child.kind === 'text' || child.kind === 'break') continue;
@@ -2375,45 +2444,42 @@ function ownerOf(boxes: readonly Box[], index: number): Element | null {
2375
2444
 
2376
2445
  export type { ControlRect, ReplacedKind, ResourceRequest, ResourceResult };
2377
2446
 
2378
- /** The advance of a font's "0" at a size, laid out: null where the engine
2379
- * cannot lay it out. */
2380
- function zeroWidthOf(
2381
- fonts: FontsLike,
2382
- family: string,
2383
- size: number,
2384
- ): number | null {
2447
+ /** The advance of a face's "0", laid out: null where the engine cannot
2448
+ * lay it out. */
2449
+ function zeroWidthOf(fonts: FontsLike, face: MetricFace): number | null {
2450
+ const { family, size, weight } = face;
2451
+ // a run is upright or slanted, as `inline.ts` sets one
2452
+ const style = face.style === 'normal' ? 'normal' : 'italic';
2385
2453
  try {
2386
- return fonts.layout([{ text: '0', family, size }], { family, size }, {})
2387
- .width;
2454
+ const run = { family, size, weight, style } as const;
2455
+ return fonts.layout([{ text: '0', ...run }], run, {}).width;
2388
2456
  } catch {
2389
2457
  return null;
2390
2458
  }
2391
2459
  }
2392
2460
 
2393
- /** A font's own line height at a size, as the engine reports it: null
2394
- * where it cannot say. */
2395
- function normalLineOf(
2396
- fonts: FontsLike,
2397
- family: string,
2398
- size: number,
2399
- ): number | null {
2461
+ /** A face's own line height, as the engine reports it: null where it
2462
+ * cannot say. */
2463
+ function normalLineOf(fonts: FontsLike, face: MetricFace): number | null {
2464
+ const { family, size, weight, style } = face;
2400
2465
  try {
2401
- const line = fonts.match(family, { size }).metrics(size).lineHeight;
2466
+ const line = fonts
2467
+ .match(family, { size, weight, style })
2468
+ .metrics(size).lineHeight;
2402
2469
  return line > 0 ? line : null;
2403
2470
  } catch {
2404
2471
  return null;
2405
2472
  }
2406
2473
  }
2407
2474
 
2408
- /** A font's x-height at a size, as the engine reports it: null where the
2409
- * face states none, or the engine does not say. */
2410
- function xHeightOf(
2411
- fonts: FontsLike,
2412
- family: string,
2413
- size: number,
2414
- ): number | null {
2475
+ /** A face's x-height, as the engine reports it: null where the face
2476
+ * states none, or the engine does not say. */
2477
+ function xHeightOf(fonts: FontsLike, face: MetricFace): number | null {
2478
+ const { family, size, weight, style } = face;
2415
2479
  try {
2416
- const metrics = fonts.match(family, { size }).metrics(size) as {
2480
+ const metrics = fonts
2481
+ .match(family, { size, weight, style })
2482
+ .metrics(size) as {
2417
2483
  xHeight?: number | null;
2418
2484
  };
2419
2485
  const x = metrics.xHeight;