@react-x11/components 0.14.0 → 0.14.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.
- package/dist/html/css/cascade.d.ts +42 -1
- package/dist/html/css/cascade.d.ts.map +1 -1
- package/dist/html/css/cascade.js +310 -12
- package/dist/html/css/cascade.js.map +1 -1
- package/dist/html/css/shapes.d.ts +44 -0
- package/dist/html/css/shapes.d.ts.map +1 -0
- package/dist/html/css/shapes.js +194 -0
- package/dist/html/css/shapes.js.map +1 -0
- package/dist/html/css/style.d.ts.map +1 -1
- package/dist/html/css/style.js +1 -15
- package/dist/html/css/style.js.map +1 -1
- package/dist/html/layout/block.d.ts +16 -5
- package/dist/html/layout/block.d.ts.map +1 -1
- package/dist/html/layout/block.js +26 -5
- package/dist/html/layout/block.js.map +1 -1
- package/dist/html/layout/boxes.d.ts +13 -0
- package/dist/html/layout/boxes.d.ts.map +1 -1
- package/dist/html/layout/boxes.js +18 -0
- package/dist/html/layout/boxes.js.map +1 -1
- package/dist/html/layout/css-grid.d.ts.map +1 -1
- package/dist/html/layout/css-grid.js +58 -10
- package/dist/html/layout/css-grid.js.map +1 -1
- package/dist/html/layout/flex.js +19 -6
- package/dist/html/layout/flex.js.map +1 -1
- package/dist/html/layout/table.d.ts.map +1 -1
- package/dist/html/layout/table.js +38 -16
- package/dist/html/layout/table.js.map +1 -1
- package/dist/html/node.d.ts +1 -0
- package/dist/html/node.d.ts.map +1 -1
- package/dist/html/node.js +57 -12
- package/dist/html/node.js.map +1 -1
- package/dist/html/paint.d.ts +4 -1
- package/dist/html/paint.d.ts.map +1 -1
- package/dist/html/paint.js +269 -84
- package/dist/html/paint.js.map +1 -1
- package/dist/html/svg.d.ts +27 -10
- package/dist/html/svg.d.ts.map +1 -1
- package/dist/html/svg.js +259 -46
- package/dist/html/svg.js.map +1 -1
- package/package.json +1 -1
- package/src/html/css/cascade.ts +343 -8
- package/src/html/css/shapes.ts +239 -0
- package/src/html/css/style.ts +1 -13
- package/src/html/layout/block.ts +27 -5
- package/src/html/layout/boxes.ts +30 -0
- package/src/html/layout/css-grid.ts +77 -13
- package/src/html/layout/flex.ts +22 -9
- package/src/html/layout/table.ts +45 -18
- package/src/html/node.ts +54 -11
- package/src/html/paint.ts +379 -90
- package/src/html/svg.ts +318 -39
package/src/html/layout/table.ts
CHANGED
|
@@ -17,7 +17,10 @@ import type { ComputedStyle } from '../css/style.js';
|
|
|
17
17
|
import { Box, CLIPPED_CELLS, COLLAPSED_CELLS, isBlank } from './boxes.js';
|
|
18
18
|
import {
|
|
19
19
|
CELL_CONTENT,
|
|
20
|
+
FLEXED_HEIGHT,
|
|
20
21
|
MIN_CONTENT_PROBE,
|
|
22
|
+
STRETCHED_ACROSS,
|
|
23
|
+
USED_HEIGHT,
|
|
21
24
|
clampHeight,
|
|
22
25
|
cyclicWidth,
|
|
23
26
|
exactMinContent,
|
|
@@ -44,8 +47,11 @@ export function layoutTable(
|
|
|
44
47
|
table.captionBottom = 0;
|
|
45
48
|
// a percentage of a width that is not known is `auto`: the table is as
|
|
46
49
|
// wide as its columns where its content is measured (`cyclicWidth`)
|
|
47
|
-
const
|
|
50
|
+
const own =
|
|
48
51
|
table.style.width === AUTO || cyclicWidth(table.style, contentWidth);
|
|
52
|
+
// — and one a grid stretches across its area is as wide as that, as a
|
|
53
|
+
// table with a width of its own is (`STRETCHED_ACROSS`)
|
|
54
|
+
const auto = own && !STRETCHED_ACROSS.has(table);
|
|
49
55
|
if (!columnCount) {
|
|
50
56
|
// With no columns, an auto table is as wide as its widest caption can
|
|
51
57
|
// be and its `min-width` asks, as one with columns is at the least
|
|
@@ -88,8 +94,8 @@ export function layoutTable(
|
|
|
88
94
|
for (const cell of cells) resolveEdges(cell.box, 0);
|
|
89
95
|
|
|
90
96
|
// a fixed layout needs a width to be fixed to; with `auto` a table is laid
|
|
91
|
-
// out by its contents after all (CSS 2.1 17.5.2.1)
|
|
92
|
-
const fixed = style.tableLayout === 'fixed' && !
|
|
97
|
+
// out by its contents after all (CSS 2.1 17.5.2.1), stretched or not
|
|
98
|
+
const fixed = style.tableLayout === 'fixed' && !own;
|
|
93
99
|
// a percentage of the table's width less its spacing (CSS 2.1 17.5.2.1)
|
|
94
100
|
const set = columnWidths(columnBoxes, columnGroups, available);
|
|
95
101
|
const widths = fixed
|
|
@@ -210,15 +216,21 @@ export function layoutTable(
|
|
|
210
216
|
// A cell aligned on the baseline — every value but `top`, `middle` and
|
|
211
217
|
// `bottom` — hangs its first line on its first row's baseline, the lowest
|
|
212
218
|
// of theirs from the row's top (CSS 2.1 17.5.3), and the row is as tall as
|
|
213
|
-
// the cells hung from it need.
|
|
214
|
-
|
|
219
|
+
// the cells hung from it need. What moves down is the content, so a cell
|
|
220
|
+
// needs the lift and its content, and a height it sets is a least one
|
|
221
|
+
// beside that rather than more room under the lift: two cells set
|
|
222
|
+
// `height: 80px` with text of two sizes in them are a row 80px tall, where
|
|
223
|
+
// the lift on top of the height made it 104px. A cell spanning rows needs
|
|
224
|
+
// the same of them, which is where Chrome differs: it sizes a spanning
|
|
225
|
+
// cell by its content and height alone and lets the lifted content hang
|
|
226
|
+
// out of it, and the rows here "encompass the cell" (17.5.3).
|
|
227
|
+
const lift = baselineLifts(cells, rows.length, natural);
|
|
228
|
+
const needs = (i: number): number =>
|
|
229
|
+
Math.max(cells[i].box.height, lift[i] + natural[i]);
|
|
215
230
|
for (let i = 0; i < cells.length; i += 1) {
|
|
216
231
|
const cell = cells[i];
|
|
217
232
|
if (cell.rowSpan > 1) continue;
|
|
218
|
-
rowHeight[cell.row] = Math.max(
|
|
219
|
-
rowHeight[cell.row],
|
|
220
|
-
lift[i] + cell.box.height,
|
|
221
|
-
);
|
|
233
|
+
rowHeight[cell.row] = Math.max(rowHeight[cell.row], needs(i));
|
|
222
234
|
}
|
|
223
235
|
for (let r = 0; r < rows.length; r += 1) {
|
|
224
236
|
const specified = resolveOrNull(rows[r].style.height, NaN);
|
|
@@ -234,14 +246,20 @@ export function layoutTable(
|
|
|
234
246
|
let covered = 0;
|
|
235
247
|
for (let r = cell.row; r <= last; r += 1) covered += rowHeight[r];
|
|
236
248
|
covered += rowSpacing * (last - cell.row);
|
|
237
|
-
const missing =
|
|
249
|
+
const missing = needs(i) - covered;
|
|
238
250
|
if (missing > 0) rowHeight[last] += missing;
|
|
239
251
|
}
|
|
240
252
|
|
|
241
253
|
// A table's own height, within its least and greatest, is a least
|
|
242
254
|
// height: what its rows come short of it goes to them (CSS 2.1 17.5.3,
|
|
243
|
-
// which leaves how to its user agents: `growRows`)
|
|
255
|
+
// which leaves how to its user agents: `growRows`). So is the height a
|
|
256
|
+
// flex or grid layout gave it, stretched or flexed (`FLEXED_HEIGHT`,
|
|
257
|
+
// `USED_HEIGHT`), which is its wrapper box's, captions and all (CSS
|
|
258
|
+
// Flexbox 1, 4): taken as the table's box alone, a table stretched down
|
|
259
|
+
// its line kept its rows at their content's height, and a cell had
|
|
260
|
+
// nothing for `vertical-align` to centre its content in.
|
|
244
261
|
const wanted = resolveOrNull(style.height, table.percentHeightBase);
|
|
262
|
+
const given = FLEXED_HEIGHT.get(table) ?? USED_HEIGHT.get(table) ?? NaN;
|
|
245
263
|
if (rows.length) {
|
|
246
264
|
const extraBox = table.verticalExtra;
|
|
247
265
|
const set =
|
|
@@ -250,7 +268,10 @@ export function layoutTable(
|
|
|
250
268
|
: style.boxSizing === 'border-box'
|
|
251
269
|
? wanted
|
|
252
270
|
: wanted + extraBox;
|
|
253
|
-
|
|
271
|
+
let inner = clampHeight(table, set) - extraBox;
|
|
272
|
+
if (Number.isFinite(given)) {
|
|
273
|
+
inner = Math.max(inner, given - table.captionTop - table.captionBottom);
|
|
274
|
+
}
|
|
254
275
|
let total = 0;
|
|
255
276
|
for (const h of rowHeight) total += h;
|
|
256
277
|
const extra = inner - total - rowSpacing * (rows.length + 1);
|
|
@@ -805,12 +826,18 @@ function lengthAgainst(len: Len, base: number): number | null {
|
|
|
805
826
|
* row's: 0 for a cell aligned `top`, `middle` or `bottom`, which is placed
|
|
806
827
|
* once the row's height is known. A cell's baseline is its first line box's,
|
|
807
828
|
* at any depth, or the bottom of its content where it has none (CSS 2.1
|
|
808
|
-
* 17.5.3); it is taken as laid out, from the cell's top.
|
|
809
|
-
*
|
|
810
|
-
*
|
|
811
|
-
*
|
|
829
|
+
* 17.5.3); it is taken as laid out, from the cell's top. That bottom is of
|
|
830
|
+
* the content (`natural`) and not of a height the cell sets, which "does not
|
|
831
|
+
* increase the height of the cell box": taken from the set height, a cell
|
|
832
|
+
* holding one block of 30px in 80px hung the text beside it from 80px. An
|
|
833
|
+
* empty cell has nothing to align and says nothing about the row's, as in a
|
|
834
|
+
* browser.
|
|
812
835
|
*/
|
|
813
|
-
function baselineLifts(
|
|
836
|
+
function baselineLifts(
|
|
837
|
+
cells: Cell[],
|
|
838
|
+
rowCount: number,
|
|
839
|
+
natural: number[],
|
|
840
|
+
): number[] {
|
|
814
841
|
const lift = new Array<number>(cells.length).fill(0);
|
|
815
842
|
let any = false;
|
|
816
843
|
for (const cell of cells) {
|
|
@@ -829,7 +856,7 @@ function baselineLifts(cells: Cell[], rowCount: number): number[] {
|
|
|
829
856
|
own[i] =
|
|
830
857
|
first !== null
|
|
831
858
|
? first - box.y
|
|
832
|
-
:
|
|
859
|
+
: natural[i] - box.padBottom - box.borderBottom;
|
|
833
860
|
row[cells[i].row] = Math.max(row[cells[i].row], own[i]);
|
|
834
861
|
}
|
|
835
862
|
for (let i = 0; i < cells.length; i += 1) {
|
package/src/html/node.ts
CHANGED
|
@@ -60,6 +60,7 @@ import {
|
|
|
60
60
|
import type { HoverTouch, KeptStyles, MetricFace } from './css/cascade.js';
|
|
61
61
|
import { mediaMatches, parseStylesheet } from './css/parse.js';
|
|
62
62
|
import type { MediaCondition, Stylesheet } from './css/parse.js';
|
|
63
|
+
import type { ShapeStyles } from './css/shapes.js';
|
|
63
64
|
import { uaStylesheet } from './css/ua.js';
|
|
64
65
|
import type { ComputedStyle, RootLook } from './css/style.js';
|
|
65
66
|
import {
|
|
@@ -74,6 +75,7 @@ import {
|
|
|
74
75
|
GENERATED_FROM,
|
|
75
76
|
INLINE_OFFSETS,
|
|
76
77
|
LINE_BOX_RAISES,
|
|
78
|
+
SHAPE_STYLES,
|
|
77
79
|
SHIFTED_LINES,
|
|
78
80
|
TEXT_SHIFTS,
|
|
79
81
|
columned,
|
|
@@ -1711,7 +1713,39 @@ export class HtmlViewNode extends Node {
|
|
|
1711
1713
|
styleOf(el);
|
|
1712
1714
|
if (refused) return false;
|
|
1713
1715
|
}
|
|
1714
|
-
|
|
1716
|
+
// The drawings the move reached. What the rules give the shapes in one
|
|
1717
|
+
// is no box's style (`BoxTree.shapeStyler`), so it is asked for again:
|
|
1718
|
+
// of a drawing whose own style changed — its colour, a custom property
|
|
1719
|
+
// — and of each where a rule that reaches into a drawing tests the
|
|
1720
|
+
// pointer, `a:hover svg path`. One with another answer is painted
|
|
1721
|
+
// again; one never painted has none yet, and asks when it is.
|
|
1722
|
+
const redrawn: [Box, ShapeStyles | null][] = [];
|
|
1723
|
+
if (tree.shapeStyler) {
|
|
1724
|
+
for (const el of reach) {
|
|
1725
|
+
if (tagOf(el) !== 'svg') continue;
|
|
1726
|
+
const style = fresh.get(el);
|
|
1727
|
+
if (!style) continue;
|
|
1728
|
+
if (!changed.has(el) && !cascade.shapesFollowPointer) continue;
|
|
1729
|
+
const box = this._firstBoxesOf(tree).get(el);
|
|
1730
|
+
const was = box && SHAPE_STYLES.get(box);
|
|
1731
|
+
if (!box || was === undefined) continue;
|
|
1732
|
+
const shapes = cascade.shapeStyles(el, style);
|
|
1733
|
+
if (shapes?.key !== was?.key) redrawn.push([box, shapes]);
|
|
1734
|
+
}
|
|
1735
|
+
}
|
|
1736
|
+
const redraw = (): Rect[] => {
|
|
1737
|
+
const inks: Rect[] = [];
|
|
1738
|
+
for (const [box, shapes] of redrawn) {
|
|
1739
|
+
SHAPE_STYLES.set(box, shapes);
|
|
1740
|
+
const ink = inkOf(box);
|
|
1741
|
+
if (ink) inks.push(ink);
|
|
1742
|
+
}
|
|
1743
|
+
return inks;
|
|
1744
|
+
};
|
|
1745
|
+
if (!changed.size && pseudoRules === HOVER_PSEUDO_NONE) {
|
|
1746
|
+
this._repaintInk(redraw());
|
|
1747
|
+
return true;
|
|
1748
|
+
}
|
|
1715
1749
|
for (const el of changed.keys()) {
|
|
1716
1750
|
const tag = tagOf(el);
|
|
1717
1751
|
// their backgrounds are the canvas's
|
|
@@ -1830,7 +1864,10 @@ export class HtmlViewNode extends Node {
|
|
|
1830
1864
|
}
|
|
1831
1865
|
}
|
|
1832
1866
|
}
|
|
1833
|
-
if (!restyled.length)
|
|
1867
|
+
if (!restyled.length) {
|
|
1868
|
+
this._repaintInk(redraw());
|
|
1869
|
+
return true;
|
|
1870
|
+
}
|
|
1834
1871
|
|
|
1835
1872
|
// the text: each layout holding a run of a restyled box's, made again
|
|
1836
1873
|
// with its new ink, where it comes out the same shape
|
|
@@ -1883,6 +1920,7 @@ export class HtmlViewNode extends Node {
|
|
|
1883
1920
|
for (const [el, style] of changed) {
|
|
1884
1921
|
tree.styles.set(el, { style, inFlex: tree.styles.get(el)!.inFlex });
|
|
1885
1922
|
}
|
|
1923
|
+
for (const ink of redraw()) inks.push(ink);
|
|
1886
1924
|
// A box that moved moves what is in it, as layout moved it the first
|
|
1887
1925
|
// time (`applyRelativeOffsets`), and a later layout moves it the same
|
|
1888
1926
|
// way; where it reached the document's end, before or after, the
|
|
@@ -1923,14 +1961,7 @@ export class HtmlViewNode extends Node {
|
|
|
1923
1961
|
* of: made on the first move over a tree, which is one walk of it. */
|
|
1924
1962
|
private _firstBoxes: { tree: BoxTree; of: Map<Element, Box> } | null = null;
|
|
1925
1963
|
|
|
1926
|
-
|
|
1927
|
-
* The blocks a restyle of `changed` has to look in: for each element, the
|
|
1928
|
-
* box its text is set in the lines of — the nearest box around its first
|
|
1929
|
-
* that is not an inline one — which holds every box that takes its style
|
|
1930
|
-
* from it, the pieces a block in it broke it into among them
|
|
1931
|
-
* (`breakAround`). One that is inside another is left to it.
|
|
1932
|
-
*/
|
|
1933
|
-
private _blocksOf(tree: BoxTree, changed: Iterable<Element>): Box[] {
|
|
1964
|
+
private _firstBoxesOf(tree: BoxTree): Map<Element, Box> {
|
|
1934
1965
|
let index = this._firstBoxes;
|
|
1935
1966
|
if (index?.tree !== tree) {
|
|
1936
1967
|
const of = new Map<Element, Box>();
|
|
@@ -1944,9 +1975,21 @@ export class HtmlViewNode extends Node {
|
|
|
1944
1975
|
}
|
|
1945
1976
|
index = this._firstBoxes = { tree, of };
|
|
1946
1977
|
}
|
|
1978
|
+
return index.of;
|
|
1979
|
+
}
|
|
1980
|
+
|
|
1981
|
+
/**
|
|
1982
|
+
* The blocks a restyle of `changed` has to look in: for each element, the
|
|
1983
|
+
* box its text is set in the lines of — the nearest box around its first
|
|
1984
|
+
* that is not an inline one — which holds every box that takes its style
|
|
1985
|
+
* from it, the pieces a block in it broke it into among them
|
|
1986
|
+
* (`breakAround`). One that is inside another is left to it.
|
|
1987
|
+
*/
|
|
1988
|
+
private _blocksOf(tree: BoxTree, changed: Iterable<Element>): Box[] {
|
|
1989
|
+
const first = this._firstBoxesOf(tree);
|
|
1947
1990
|
const blocks = new Set<Box>();
|
|
1948
1991
|
for (const el of changed) {
|
|
1949
|
-
let box: Box | null =
|
|
1992
|
+
let box: Box | null = first.get(el) ?? null;
|
|
1950
1993
|
while (
|
|
1951
1994
|
box?.parent &&
|
|
1952
1995
|
(box.kind === 'inline' || box.kind === 'text' || box.kind === 'break')
|