@react-x11/components 0.12.0 → 0.14.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.
- package/dist/html/controls.d.ts +41 -5
- package/dist/html/controls.d.ts.map +1 -1
- package/dist/html/controls.js +85 -57
- package/dist/html/controls.js.map +1 -1
- package/dist/html/css/cascade.d.ts +134 -20
- package/dist/html/css/cascade.d.ts.map +1 -1
- package/dist/html/css/cascade.js +545 -126
- package/dist/html/css/cascade.js.map +1 -1
- package/dist/html/css/color.d.ts +18 -0
- package/dist/html/css/color.d.ts.map +1 -1
- package/dist/html/css/color.js +27 -0
- package/dist/html/css/color.js.map +1 -1
- package/dist/html/css/parse.d.ts +47 -6
- package/dist/html/css/parse.d.ts.map +1 -1
- package/dist/html/css/parse.js +336 -30
- package/dist/html/css/parse.js.map +1 -1
- package/dist/html/css/style.d.ts +142 -15
- package/dist/html/css/style.d.ts.map +1 -1
- package/dist/html/css/style.js +563 -147
- package/dist/html/css/style.js.map +1 -1
- package/dist/html/css/transform.d.ts +85 -0
- package/dist/html/css/transform.d.ts.map +1 -0
- package/dist/html/css/transform.js +425 -0
- package/dist/html/css/transform.js.map +1 -0
- package/dist/html/css/ua.d.ts +11 -1
- package/dist/html/css/ua.d.ts.map +1 -1
- package/dist/html/css/ua.js +73 -9
- package/dist/html/css/ua.js.map +1 -1
- package/dist/html/css/values.d.ts +4 -0
- package/dist/html/css/values.d.ts.map +1 -1
- package/dist/html/css/values.js.map +1 -1
- package/dist/html/dom.d.ts.map +1 -1
- package/dist/html/dom.js +3 -1
- package/dist/html/dom.js.map +1 -1
- package/dist/html/fonts.d.ts +78 -4
- package/dist/html/fonts.d.ts.map +1 -1
- package/dist/html/fonts.js +373 -19
- package/dist/html/fonts.js.map +1 -1
- package/dist/html/form.d.ts +200 -0
- package/dist/html/form.d.ts.map +1 -0
- package/dist/html/form.js +801 -0
- package/dist/html/form.js.map +1 -0
- package/dist/html/index.d.ts +12 -0
- package/dist/html/index.d.ts.map +1 -1
- package/dist/html/index.js +30 -301
- package/dist/html/index.js.map +1 -1
- package/dist/html/layout/axes.d.ts +14 -0
- package/dist/html/layout/axes.d.ts.map +1 -0
- package/dist/html/layout/axes.js +28 -0
- package/dist/html/layout/axes.js.map +1 -0
- package/dist/html/layout/block.d.ts +93 -12
- package/dist/html/layout/block.d.ts.map +1 -1
- package/dist/html/layout/block.js +393 -39
- package/dist/html/layout/block.js.map +1 -1
- package/dist/html/layout/boxes.d.ts +90 -2
- package/dist/html/layout/boxes.d.ts.map +1 -1
- package/dist/html/layout/boxes.js +74 -10
- package/dist/html/layout/boxes.js.map +1 -1
- package/dist/html/layout/cache.d.ts +1 -1
- package/dist/html/layout/cache.d.ts.map +1 -1
- package/dist/html/layout/cache.js +6 -0
- package/dist/html/layout/cache.js.map +1 -1
- package/dist/html/layout/css-grid.d.ts.map +1 -1
- package/dist/html/layout/css-grid.js +90 -18
- package/dist/html/layout/css-grid.js.map +1 -1
- package/dist/html/layout/flex.d.ts.map +1 -1
- package/dist/html/layout/flex.js +574 -84
- package/dist/html/layout/flex.js.map +1 -1
- package/dist/html/layout/inline.d.ts +3 -0
- package/dist/html/layout/inline.d.ts.map +1 -1
- package/dist/html/layout/inline.js +154 -54
- package/dist/html/layout/inline.js.map +1 -1
- package/dist/html/layout/multicol.d.ts +42 -0
- package/dist/html/layout/multicol.d.ts.map +1 -0
- package/dist/html/layout/multicol.js +897 -0
- package/dist/html/layout/multicol.js.map +1 -0
- package/dist/html/layout/shaping.d.ts +7 -0
- package/dist/html/layout/shaping.d.ts.map +1 -1
- package/dist/html/layout/shaping.js +25 -20
- package/dist/html/layout/shaping.js.map +1 -1
- package/dist/html/layout/table.d.ts.map +1 -1
- package/dist/html/layout/table.js +62 -18
- package/dist/html/layout/table.js.map +1 -1
- package/dist/html/node.d.ts +90 -15
- package/dist/html/node.d.ts.map +1 -1
- package/dist/html/node.js +771 -186
- package/dist/html/node.js.map +1 -1
- package/dist/html/paint.d.ts +101 -5
- package/dist/html/paint.d.ts.map +1 -1
- package/dist/html/paint.js +1502 -160
- package/dist/html/paint.js.map +1 -1
- package/dist/html/svg.d.ts +15 -2
- package/dist/html/svg.d.ts.map +1 -1
- package/dist/html/svg.js +249 -17
- package/dist/html/svg.js.map +1 -1
- package/dist/html/widgets.d.ts +29 -0
- package/dist/html/widgets.d.ts.map +1 -0
- package/dist/html/widgets.js +700 -0
- package/dist/html/widgets.js.map +1 -0
- package/dist/html/woff2.d.ts +14 -0
- package/dist/html/woff2.d.ts.map +1 -0
- package/dist/html/woff2.js +608 -0
- package/dist/html/woff2.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/maps/controller.d.ts +17 -1
- package/dist/maps/controller.d.ts.map +1 -1
- package/dist/maps/controller.js +27 -7
- package/dist/maps/controller.js.map +1 -1
- package/dist/richtext/node.d.ts +8 -1
- package/dist/richtext/node.d.ts.map +1 -1
- package/dist/richtext/node.js +5 -1
- package/dist/richtext/node.js.map +1 -1
- package/dist/richtext/runs.d.ts +25 -6
- package/dist/richtext/runs.d.ts.map +1 -1
- package/dist/richtext/runs.js +240 -24
- package/dist/richtext/runs.js.map +1 -1
- package/package.json +2 -2
- package/src/html/controls.ts +114 -51
- package/src/html/css/cascade.ts +614 -140
- package/src/html/css/color.ts +29 -0
- package/src/html/css/parse.ts +388 -33
- package/src/html/css/style.ts +688 -150
- package/src/html/css/transform.ts +459 -0
- package/src/html/css/ua.ts +77 -10
- package/src/html/css/values.ts +4 -0
- package/src/html/dom.ts +3 -1
- package/src/html/fonts.ts +417 -24
- package/src/html/form.ts +962 -0
- package/src/html/index.ts +49 -338
- package/src/html/layout/axes.ts +62 -0
- package/src/html/layout/block.ts +447 -37
- package/src/html/layout/boxes.ts +143 -14
- package/src/html/layout/cache.ts +6 -0
- package/src/html/layout/css-grid.ts +95 -22
- package/src/html/layout/flex.ts +675 -78
- package/src/html/layout/inline.ts +159 -55
- package/src/html/layout/multicol.ts +977 -0
- package/src/html/layout/shaping.ts +27 -18
- package/src/html/layout/table.ts +62 -19
- package/src/html/node.ts +798 -172
- package/src/html/paint.ts +1742 -241
- package/src/html/svg.ts +277 -19
- package/src/html/widgets.ts +821 -0
- package/src/html/woff2.ts +612 -0
- package/src/index.ts +1 -0
- package/src/maps/controller.ts +28 -7
- package/src/richtext/node.ts +13 -2
- package/src/richtext/runs.ts +313 -35
package/src/html/layout/boxes.ts
CHANGED
|
@@ -28,7 +28,12 @@ import {
|
|
|
28
28
|
NON_RENDERED,
|
|
29
29
|
tagOf,
|
|
30
30
|
} from '../dom.js';
|
|
31
|
-
import type {
|
|
31
|
+
import type {
|
|
32
|
+
Cascade,
|
|
33
|
+
FirstLetterRules,
|
|
34
|
+
KeptStyles,
|
|
35
|
+
SelectionStyle,
|
|
36
|
+
} from '../css/cascade.js';
|
|
32
37
|
import type { CollapsedTable } from './collapse.js';
|
|
33
38
|
import { quoteAt } from '../css/content.js';
|
|
34
39
|
import type { CounterStyles } from '../css/counter-styles.js';
|
|
@@ -197,6 +202,17 @@ export interface LineText {
|
|
|
197
202
|
* the ones before a forced break that fit take room on the line.
|
|
198
203
|
*/
|
|
199
204
|
hung?: { at: number; x: number; width: number }[];
|
|
205
|
+
/**
|
|
206
|
+
* How far the line goes on past this text for the collapsible spaces it
|
|
207
|
+
* ends on, which its engine, laying out a piece of a line as a line,
|
|
208
|
+
* stripped: the room they take where more follows them on the line, and
|
|
209
|
+
* none where the line ends on them, since CSS removes them there (CSS
|
|
210
|
+
* Text 3, 4.1.2). They are the text's, in the elements they are in, and
|
|
211
|
+
* `trailRun` is the run they are the end of: whose underline, line
|
|
212
|
+
* through and highlight go on under them.
|
|
213
|
+
*/
|
|
214
|
+
trail?: number;
|
|
215
|
+
trailRun?: TextRun;
|
|
200
216
|
/** Any offset in the layout's own text as a document index — how a run
|
|
201
217
|
* under the pointer finds the element whose text it is. Per pass: the
|
|
202
218
|
* layout may be one an earlier pass made (`TextLayoutCache`), and the
|
|
@@ -556,6 +572,10 @@ export type FirstLineStyler = (
|
|
|
556
572
|
parent: ComputedStyle,
|
|
557
573
|
) => ComputedStyle;
|
|
558
574
|
|
|
575
|
+
/** The `::selection` of the element a box's text is in, or null for the
|
|
576
|
+
* palette's highlight (`Cascade.selectionStyle`). */
|
|
577
|
+
export type SelectionStyler = (box: Box | null) => SelectionStyle | null;
|
|
578
|
+
|
|
559
579
|
/** The url of an image generated content put in a pseudo-element: it has
|
|
560
580
|
* no element of its own to name it (`imageUrlOf`). */
|
|
561
581
|
export const CONTENT_IMAGES = new WeakMap<Box, string>();
|
|
@@ -621,12 +641,16 @@ export const CLAMPED = new WeakSet<Box>();
|
|
|
621
641
|
/** A grid's tracks as its layout left them, each column's and each row's
|
|
622
642
|
* start and end from the content box's corner, with the lines of each
|
|
623
643
|
* axis by number and by name: what an absolutely positioned box's grid
|
|
624
|
-
* area is found in (CSS Grid 1, 9.1).
|
|
644
|
+
* area is found in (CSS Grid 1, 9.1). And the first of its items in
|
|
645
|
+
* row-major order, where they were placed and not where they were
|
|
646
|
+
* written, which the grid's own baseline is taken from (10.6): null for a
|
|
647
|
+
* grid with no item. */
|
|
625
648
|
export interface GridTracks {
|
|
626
649
|
cols: [number, number][];
|
|
627
650
|
rows: [number, number][];
|
|
628
651
|
colLines: GridLines;
|
|
629
652
|
rowLines: GridLines;
|
|
653
|
+
first: Box | null;
|
|
630
654
|
}
|
|
631
655
|
export const GRID_TRACKS = new WeakMap<Box, GridTracks>();
|
|
632
656
|
|
|
@@ -641,6 +665,54 @@ export const PAINT_ORDER = new WeakMap<Box, Box[]>();
|
|
|
641
665
|
* a browser's does (`elementRect`). */
|
|
642
666
|
export const CUT_BLOCKS = new WeakMap<Box, Box[]>();
|
|
643
667
|
|
|
668
|
+
/** Where a block that clearance moved below the floats would have stood
|
|
669
|
+
* without it, its border edge's top (CSS 2.1 9.5.2): a browser's
|
|
670
|
+
* fragment of an inline box around such a block starts there, and takes
|
|
671
|
+
* the clearance in (`elementRect`). Only the blocks that had clearance. */
|
|
672
|
+
export const CLEARED_FROM = new WeakMap<Box, number>();
|
|
673
|
+
|
|
674
|
+
/**
|
|
675
|
+
* One piece of a block that a column break falls inside (CSS Multi-column
|
|
676
|
+
* 1): its border box in one column, as far as the box goes in it, and where
|
|
677
|
+
* the whole box would stand there — the box its background and its borders
|
|
678
|
+
* are drawn as, cut to the piece (`box-decoration-break: slice`).
|
|
679
|
+
*/
|
|
680
|
+
export interface ColumnPiece {
|
|
681
|
+
x: number;
|
|
682
|
+
y: number;
|
|
683
|
+
width: number;
|
|
684
|
+
height: number;
|
|
685
|
+
/** The top of the whole box, in this column, and its height. */
|
|
686
|
+
wholeY: number;
|
|
687
|
+
wholeHeight: number;
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
/** The pieces of each block a column break falls inside, in the order of
|
|
691
|
+
* the columns. The block's own rect is what takes them all in, as a
|
|
692
|
+
* browser's bounding rect of it is. */
|
|
693
|
+
export const COLUMN_PIECES = new WeakMap<Box, ColumnPiece[]>();
|
|
694
|
+
|
|
695
|
+
/** The lines of a box that columns took apart: they are not one under
|
|
696
|
+
* another, and a search that counts on their tops rising reads them all
|
|
697
|
+
* instead. */
|
|
698
|
+
export const COLUMN_LINES = new WeakSet<LineBox[]>();
|
|
699
|
+
|
|
700
|
+
/**
|
|
701
|
+
* The rows of a text's layout that are in the text's own column, from the
|
|
702
|
+
* layout's origin, where the layout's lines went to more than one: a layout
|
|
703
|
+
* is drawn whole, so it is drawn once for each column, there, and clipped
|
|
704
|
+
* to the rows that are that column's. One object for all the texts of a
|
|
705
|
+
* layout in a column, which is what tells a draw of it from another.
|
|
706
|
+
*/
|
|
707
|
+
export const COLUMN_ROWS = new WeakMap<
|
|
708
|
+
LineText,
|
|
709
|
+
{ top: number; bottom: number }
|
|
710
|
+
>();
|
|
711
|
+
|
|
712
|
+
/** Whether any layout has broken a box between columns: what the walks
|
|
713
|
+
* that would ask the three maps above of every box ask first. */
|
|
714
|
+
export const columned = { any: false };
|
|
715
|
+
|
|
644
716
|
/** The element a pseudo-element's box is generated from, which has no
|
|
645
717
|
* element of its own (`Box.pseudo`): whose the images its styles name are,
|
|
646
718
|
* when the host is asked for them. */
|
|
@@ -673,6 +745,10 @@ export interface BoxTree {
|
|
|
673
745
|
controls: Box[];
|
|
674
746
|
/** Every box carrying an `href`, for click and hover. */
|
|
675
747
|
links: Box[];
|
|
748
|
+
/** The style of an anonymous box under a parent's (`anonymousStyles`):
|
|
749
|
+
* the one the fix-up gave each it made, and what such a box takes when
|
|
750
|
+
* its parent's style changes where it is (`HtmlViewNode._hoverInPlace`). */
|
|
751
|
+
anonymous: AnonymousStyle;
|
|
676
752
|
/** Every box with a `background-image`, a border image or a mask image,
|
|
677
753
|
* an element's or a pseudo-element's, for the host to be asked for: a
|
|
678
754
|
* document has a handful, and finding them was a walk over every box
|
|
@@ -694,6 +770,10 @@ export interface BoxTree {
|
|
|
694
770
|
/** Each box's style on a first line (`FirstLineStyler`), where any
|
|
695
771
|
* block has a `::first-line`. */
|
|
696
772
|
firstLineStyler: FirstLineStyler | null;
|
|
773
|
+
/** Each box's `::selection` (`SelectionStyler`), where any rule styles
|
|
774
|
+
* one: worked out as a selection is first painted over it, not as the
|
|
775
|
+
* tree is built, since most builds are never selected in. */
|
|
776
|
+
selectionStyler: SelectionStyler | null;
|
|
697
777
|
/** Whether a float or an out-of-flow box sits in an inline box: where
|
|
698
778
|
* none does, layout looks for them among a block's own children and
|
|
699
779
|
* goes through no inline box to find them. */
|
|
@@ -710,10 +790,17 @@ export interface BoxTree {
|
|
|
710
790
|
* (`Cascade.rootStyle`), whose background is the canvas's; null where
|
|
711
791
|
* the document has either. */
|
|
712
792
|
impliedHtml: ComputedStyle | null;
|
|
793
|
+
/** The scheme the palette is, which the element the document is drawn
|
|
794
|
+
* in is of: where the root element's is the other, the canvas is that
|
|
795
|
+
* scheme's and opaque (`paintDocument`). */
|
|
796
|
+
paletteScheme: 'light' | 'dark';
|
|
713
797
|
}
|
|
714
798
|
|
|
715
799
|
export interface BuildOptions {
|
|
716
800
|
cascade: Cascade;
|
|
801
|
+
/** The styles of the tree this one replaces, where only some elements'
|
|
802
|
+
* can have changed since (`Cascade.beginSharing`). */
|
|
803
|
+
kept?: KeptStyles | null;
|
|
717
804
|
/** Device pixels per CSS pixel. An image's pixels and a `width="600"`
|
|
718
805
|
* attribute are CSS pixels; every box is device, so both are multiplied
|
|
719
806
|
* on the way in. Default 1. */
|
|
@@ -813,7 +900,7 @@ class Builder {
|
|
|
813
900
|
|
|
814
901
|
run(root: Element): BoxTree {
|
|
815
902
|
const cascade = this._options.cascade;
|
|
816
|
-
cascade.beginSharing();
|
|
903
|
+
cascade.beginSharing(this._options.kept ?? null);
|
|
817
904
|
const { style: rootStyle, html: impliedHtml } = cascade.rootStyle(
|
|
818
905
|
hasBody(root),
|
|
819
906
|
hasHtml(root),
|
|
@@ -832,10 +919,13 @@ class Builder {
|
|
|
832
919
|
// it carries no margins of its own and cannot collapse with anything.
|
|
833
920
|
this._children(root, rootBox, rootStyle, false, null, ROOT_SHARE_KEY);
|
|
834
921
|
this._endLine();
|
|
835
|
-
|
|
922
|
+
cascade.endSharing();
|
|
923
|
+
const anonymous = anonymousStyles(cascade.initial);
|
|
924
|
+
fixUp(rootBox, anonymous);
|
|
836
925
|
assignSubtreeRanges(rootBox);
|
|
837
926
|
return {
|
|
838
927
|
root: rootBox,
|
|
928
|
+
anonymous,
|
|
839
929
|
text: this._chunks.join(''),
|
|
840
930
|
textBoxes: this._textBoxes,
|
|
841
931
|
textStyles: this._textStyles,
|
|
@@ -848,10 +938,36 @@ class Builder {
|
|
|
848
938
|
negative: this._negative,
|
|
849
939
|
firstLine: this._firstLine,
|
|
850
940
|
firstLineStyler: this._firstLine ? this._firstLineStyler() : null,
|
|
941
|
+
selectionStyler: cascade.hasSelection ? this._selectionStyler() : null,
|
|
851
942
|
nestedOutOfLine: this._nestedOutOfLine,
|
|
852
943
|
movedInline: this._movedInline,
|
|
853
944
|
clipText: this._clipText,
|
|
854
945
|
impliedHtml,
|
|
946
|
+
paletteScheme: cascade.initial.colorScheme,
|
|
947
|
+
};
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
/** `BoxTree.selectionStyler`, over this build's cascade: an element's
|
|
951
|
+
* over its parent's, each once. A box with no element of its own — text,
|
|
952
|
+
* an anonymous box — is its nearest element's. */
|
|
953
|
+
private _selectionStyler(): SelectionStyler {
|
|
954
|
+
const cascade = this._options.cascade;
|
|
955
|
+
const styles = this._styles;
|
|
956
|
+
const known = new Map<Element, SelectionStyle | null>();
|
|
957
|
+
const of = (el: Element): SelectionStyle | null => {
|
|
958
|
+
let found = known.get(el);
|
|
959
|
+
if (found !== undefined) return found;
|
|
960
|
+
// the parser keeps a document to 256 elements deep (`dom.ts`)
|
|
961
|
+
const parent = isElement(el.parent) ? of(el.parent) : null;
|
|
962
|
+
const own = styles.get(el)?.style;
|
|
963
|
+
found = own ? cascade.selectionStyle(el, own, parent) : parent;
|
|
964
|
+
known.set(el, found);
|
|
965
|
+
return found;
|
|
966
|
+
};
|
|
967
|
+
return (box) => {
|
|
968
|
+
let at = box;
|
|
969
|
+
while (at && !at.el) at = at.parent;
|
|
970
|
+
return at?.el ? of(at.el) : null;
|
|
855
971
|
};
|
|
856
972
|
}
|
|
857
973
|
|
|
@@ -989,7 +1105,7 @@ class Builder {
|
|
|
989
1105
|
}
|
|
990
1106
|
}
|
|
991
1107
|
// a translation is moved by the same pass
|
|
992
|
-
if (style.translate || style.
|
|
1108
|
+
if (style.translate || style.transform) this._relative = true;
|
|
993
1109
|
if (style.backgroundClipText) this._clipText = true;
|
|
994
1110
|
if (style.verticalAlign !== 'baseline' && style.display === 'inline') {
|
|
995
1111
|
this._movedInline = true;
|
|
@@ -1024,7 +1140,9 @@ class Builder {
|
|
|
1024
1140
|
}
|
|
1025
1141
|
|
|
1026
1142
|
// an `<object>` is its image once it has one, and its content until;
|
|
1027
|
-
// an `<embed>` its image, and a `<video>` its poster, or a frame
|
|
1143
|
+
// an `<embed>` its image, and a `<video>` its poster, or a frame; an
|
|
1144
|
+
// image button its image, and a button saying what it is for until it
|
|
1145
|
+
// has one, so it can be pressed either way
|
|
1028
1146
|
const replaced =
|
|
1029
1147
|
tag === 'object'
|
|
1030
1148
|
? this._options.imageSize(el)
|
|
@@ -1032,7 +1150,11 @@ class Builder {
|
|
|
1032
1150
|
: 'none'
|
|
1033
1151
|
: (tag === 'embed' || tag === 'video') && this._options.imageSize(el)
|
|
1034
1152
|
? 'image'
|
|
1035
|
-
:
|
|
1153
|
+
: isImageButton(el, tag)
|
|
1154
|
+
? this._options.imageSize(el)
|
|
1155
|
+
? 'image'
|
|
1156
|
+
: 'button'
|
|
1157
|
+
: replacedKind(el, tag);
|
|
1036
1158
|
if (replaced !== 'none') {
|
|
1037
1159
|
this._replaced(el, tag, replaced, style, into);
|
|
1038
1160
|
return;
|
|
@@ -1288,7 +1410,7 @@ class Builder {
|
|
|
1288
1410
|
}
|
|
1289
1411
|
}
|
|
1290
1412
|
// a translation is moved by the same pass
|
|
1291
|
-
if (style.translate || style.
|
|
1413
|
+
if (style.translate || style.transform) this._relative = true;
|
|
1292
1414
|
if (style.backgroundClipText) this._clipText = true;
|
|
1293
1415
|
if (style.verticalAlign !== 'baseline' && style.display === 'inline') {
|
|
1294
1416
|
this._movedInline = true;
|
|
@@ -2359,6 +2481,13 @@ function setIntrinsics(box: Box, size: IntrinsicSize, scale: number): void {
|
|
|
2359
2481
|
};
|
|
2360
2482
|
}
|
|
2361
2483
|
|
|
2484
|
+
/** An `<input type=image>`: a picture that submits its form. */
|
|
2485
|
+
function isImageButton(el: Element, tag: string): boolean {
|
|
2486
|
+
return (
|
|
2487
|
+
tag === 'input' && (attr(el, 'type') ?? '').trim().toLowerCase() === 'image'
|
|
2488
|
+
);
|
|
2489
|
+
}
|
|
2490
|
+
|
|
2362
2491
|
function replacedKind(el: Element, tag: string): ReplacedKind {
|
|
2363
2492
|
switch (tag) {
|
|
2364
2493
|
case 'img':
|
|
@@ -2662,24 +2791,24 @@ function namesImages(style: ComputedStyle): boolean {
|
|
|
2662
2791
|
* paragraph after it the height of the div further down. One per parent
|
|
2663
2792
|
* style, which the cascade already shares between elements.
|
|
2664
2793
|
*/
|
|
2665
|
-
type AnonymousStyle = (
|
|
2666
|
-
parent:
|
|
2794
|
+
export type AnonymousStyle = (
|
|
2795
|
+
parent: ComputedStyle,
|
|
2667
2796
|
display: ComputedStyle['display'],
|
|
2668
2797
|
) => ComputedStyle;
|
|
2669
2798
|
|
|
2670
2799
|
function anonymousStyles(initial: ComputedStyle): AnonymousStyle {
|
|
2671
2800
|
const made = new WeakMap<ComputedStyle, Map<string, ComputedStyle>>();
|
|
2672
2801
|
return (parent, display) => {
|
|
2673
|
-
let byDisplay = made.get(parent
|
|
2802
|
+
let byDisplay = made.get(parent);
|
|
2674
2803
|
if (!byDisplay) {
|
|
2675
2804
|
byDisplay = new Map();
|
|
2676
|
-
made.set(parent
|
|
2805
|
+
made.set(parent, byDisplay);
|
|
2677
2806
|
}
|
|
2678
2807
|
let style = byDisplay.get(display);
|
|
2679
2808
|
if (!style) {
|
|
2680
2809
|
// `display` is the one property it does not start from: it is the
|
|
2681
2810
|
// box the fix-up made, and layout asks the style what a box is
|
|
2682
|
-
style = inherit(parent
|
|
2811
|
+
style = inherit(parent, initial);
|
|
2683
2812
|
style.display = display;
|
|
2684
2813
|
byDisplay.set(display, style);
|
|
2685
2814
|
}
|
|
@@ -2787,7 +2916,7 @@ function anonymousOf(
|
|
|
2787
2916
|
anonymous: AnonymousStyle,
|
|
2788
2917
|
display: ComputedStyle['display'] = kind as ComputedStyle['display'],
|
|
2789
2918
|
): Box {
|
|
2790
|
-
const box = new Box(kind, null, anonymous(parent, display));
|
|
2919
|
+
const box = new Box(kind, null, anonymous(parent.style, display));
|
|
2791
2920
|
box.parent = parent;
|
|
2792
2921
|
for (const child of run) {
|
|
2793
2922
|
child.parent = box;
|
package/src/html/layout/cache.ts
CHANGED
|
@@ -186,6 +186,8 @@ export const RUN_FIELDS = [
|
|
|
186
186
|
'underlineOffset',
|
|
187
187
|
'underlineThickness',
|
|
188
188
|
'strike',
|
|
189
|
+
'strikeStyle',
|
|
190
|
+
'strikeThickness',
|
|
189
191
|
'href',
|
|
190
192
|
'features',
|
|
191
193
|
'nowrap',
|
|
@@ -221,6 +223,8 @@ function sameRun(a: TextRun, b: TextRun): boolean {
|
|
|
221
223
|
a.underlineOffset === b.underlineOffset &&
|
|
222
224
|
a.underlineThickness === b.underlineThickness &&
|
|
223
225
|
a.strike === b.strike &&
|
|
226
|
+
a.strikeStyle === b.strikeStyle &&
|
|
227
|
+
a.strikeThickness === b.strikeThickness &&
|
|
224
228
|
a.href === b.href &&
|
|
225
229
|
a.features === b.features &&
|
|
226
230
|
a.nowrap === b.nowrap &&
|
|
@@ -249,6 +253,8 @@ function sameStyle(
|
|
|
249
253
|
a.underlineOffset === b.underlineOffset &&
|
|
250
254
|
a.underlineThickness === b.underlineThickness &&
|
|
251
255
|
a.strike === b.strike &&
|
|
256
|
+
a.strikeStyle === b.strikeStyle &&
|
|
257
|
+
a.strikeThickness === b.strikeThickness &&
|
|
252
258
|
a.href === b.href &&
|
|
253
259
|
a.features === b.features &&
|
|
254
260
|
a.nowrap === b.nowrap &&
|
|
@@ -31,6 +31,8 @@ import { Box, GRID_TRACKS, isBlank } from './boxes.js';
|
|
|
31
31
|
import {
|
|
32
32
|
FLEXED_HEIGHT,
|
|
33
33
|
MIN_CONTENT_PROBE,
|
|
34
|
+
USED_HEIGHT,
|
|
35
|
+
centreButton,
|
|
34
36
|
clampHeight,
|
|
35
37
|
clampWidth,
|
|
36
38
|
exactMinContent,
|
|
@@ -60,6 +62,25 @@ interface Item {
|
|
|
60
62
|
max: number;
|
|
61
63
|
}
|
|
62
64
|
|
|
65
|
+
/**
|
|
66
|
+
* The first of a grid's items in row-major order: the one furthest to the
|
|
67
|
+
* start of the first row that holds an item, which the grid's baseline is
|
|
68
|
+
* taken from (CSS Grid 1, 10.6).
|
|
69
|
+
*/
|
|
70
|
+
function firstItem(items: Item[]): Box | null {
|
|
71
|
+
let first: Item | null = null;
|
|
72
|
+
for (const item of items) {
|
|
73
|
+
if (
|
|
74
|
+
first === null ||
|
|
75
|
+
item.row < first.row ||
|
|
76
|
+
(item.row === first.row && item.col < first.col)
|
|
77
|
+
) {
|
|
78
|
+
first = item;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return first?.box ?? null;
|
|
82
|
+
}
|
|
83
|
+
|
|
63
84
|
/**
|
|
64
85
|
* Lay out a grid container's children. Returns the content height.
|
|
65
86
|
*/
|
|
@@ -78,7 +99,13 @@ export function layoutGrid(
|
|
|
78
99
|
positionOutOfFlow(child, box, ctx, false);
|
|
79
100
|
continue;
|
|
80
101
|
}
|
|
81
|
-
|
|
102
|
+
// While the columns are sized, the area an item is in has no width for
|
|
103
|
+
// the percentages in its margins and its padding to be of, and they
|
|
104
|
+
// are of nothing (CSS Sizing 3, 5.2.1): a column is as wide as what
|
|
105
|
+
// is in the item. They are of the area once it has a width
|
|
106
|
+
// (`layoutItem`). Taken of the grid's width, an item `margin: 0 25%`
|
|
107
|
+
// made its `min-content` column half the grid wide.
|
|
108
|
+
resolveEdges(child, 0);
|
|
82
109
|
boxes.push(child);
|
|
83
110
|
}
|
|
84
111
|
// the gaps: a percentage of the grid's content size along them, and of
|
|
@@ -240,14 +267,15 @@ export function layoutGrid(
|
|
|
240
267
|
item,
|
|
241
268
|
extent(widths, lefts, item.col, item.cols),
|
|
242
269
|
ctx,
|
|
243
|
-
|
|
270
|
+
spanBefore(item),
|
|
244
271
|
);
|
|
245
272
|
}
|
|
246
273
|
|
|
247
274
|
// a height of the grid's own, or else the least it may be, which the
|
|
248
|
-
// `fr` rows and the `auto` ones fill
|
|
275
|
+
// `fr` rows and the `auto` ones fill: its `min-height`, or the height a
|
|
276
|
+
// column it is an item of flexed it to (`USED_HEIGHT`)
|
|
249
277
|
const own = Number.isFinite(definite);
|
|
250
|
-
const least = own ? 0 : leastHeight(box);
|
|
278
|
+
const least = own ? 0 : Math.max(leastHeight(box), USED_HEIGHT.get(box) ?? 0);
|
|
251
279
|
// the rows against a height: percentages of it, or `auto` without one
|
|
252
280
|
const sizeRows = (base: number, available: number, atLeast: number) => {
|
|
253
281
|
const rowTracks: SizingTrack[] = [];
|
|
@@ -301,18 +329,14 @@ export function layoutGrid(
|
|
|
301
329
|
if (Object.is(child.percentHeightBase, tall) || !percentOwn(child))
|
|
302
330
|
continue;
|
|
303
331
|
child.percentHeightBase = tall;
|
|
304
|
-
layoutItem(
|
|
305
|
-
item,
|
|
306
|
-
extent(widths, lefts, item.col, item.cols),
|
|
307
|
-
ctx,
|
|
308
|
-
heightBeforeRows(child, tall),
|
|
309
|
-
);
|
|
332
|
+
layoutItem(item, extent(widths, lefts, item.col, item.cols), ctx, tall);
|
|
310
333
|
}
|
|
311
334
|
GRID_TRACKS.set(box, {
|
|
312
335
|
cols: tracksOf(widths, lefts, keepCols),
|
|
313
336
|
rows: tracksOf(heights, tops, keepRows),
|
|
314
337
|
colLines,
|
|
315
338
|
rowLines,
|
|
339
|
+
first: firstItem(items),
|
|
316
340
|
});
|
|
317
341
|
|
|
318
342
|
for (const item of items) {
|
|
@@ -371,20 +395,28 @@ export function layoutGrid(
|
|
|
371
395
|
const width =
|
|
372
396
|
wide === null ? child.width : clampWidth(child, wide, area, ctx);
|
|
373
397
|
// what is in it takes its percentages of that height, which a
|
|
374
|
-
// stretch makes definite, as it does a flex item's
|
|
398
|
+
// stretch makes definite, as it does a flex item's — and an item that
|
|
399
|
+
// is a flex or grid container lays its own items out in it (11.1:
|
|
400
|
+
// "the grid area's width and height are considered definite for this
|
|
401
|
+
// purpose"): a card's `margin-top: auto` takes what its row is taller
|
|
402
|
+
// than the card by, its `flex: 1` grows into it (CSS Flexbox 8.1,
|
|
403
|
+
// 9.7). Its content's own height is the same layout, and kept.
|
|
375
404
|
if (
|
|
376
405
|
child.kind !== 'replaced' &&
|
|
377
|
-
(wide !== null ||
|
|
406
|
+
(wide !== null ||
|
|
407
|
+
percentHeightsIn(child) ||
|
|
408
|
+
(child.kind === 'flex' && height !== child.height))
|
|
378
409
|
) {
|
|
379
410
|
FLEXED_HEIGHT.set(child, Math.max(0, height - child.verticalExtra));
|
|
380
411
|
try {
|
|
381
|
-
ctx.layoutSubtree(child, width);
|
|
412
|
+
ctx.layoutSubtree(child, width, area);
|
|
382
413
|
} finally {
|
|
383
414
|
FLEXED_HEIGHT.delete(child);
|
|
384
415
|
}
|
|
385
416
|
}
|
|
386
417
|
child.width = width;
|
|
387
418
|
child.height = height;
|
|
419
|
+
centreButton(child);
|
|
388
420
|
}
|
|
389
421
|
moveTo(
|
|
390
422
|
child,
|
|
@@ -617,15 +649,25 @@ function maxContentOf(box: Box, ctx: LayoutContext): number {
|
|
|
617
649
|
return box.intrinsicMaxContent;
|
|
618
650
|
}
|
|
619
651
|
|
|
620
|
-
/**
|
|
621
|
-
*
|
|
622
|
-
*
|
|
652
|
+
/**
|
|
653
|
+
* Lay an item out in its area: stretched across it where its width is
|
|
654
|
+
* `auto` and it is stretched, or at its content's width, no wider than
|
|
655
|
+
* the area, where it is aligned instead.
|
|
656
|
+
*
|
|
657
|
+
* The area is the item's containing block (CSS Grid 1, 3.3), so it is its
|
|
658
|
+
* width that a percentage in the item's margins, its padding, its
|
|
659
|
+
* `min-width` and its `max-width` is of (6.4, and CSS 2.1 8.3, 8.4 and
|
|
660
|
+
* 10.4), whatever width the item comes to in it. With its own width
|
|
661
|
+
* standing for its area's, an item `width: 50%; max-width: 80%` was four
|
|
662
|
+
* tenths of its column, and one `min-width: 50%` aligned to the start was
|
|
663
|
+
* as wide as its text.
|
|
664
|
+
*/
|
|
623
665
|
function layoutItem(
|
|
624
666
|
item: Item,
|
|
625
667
|
area: number,
|
|
626
668
|
ctx: LayoutContext,
|
|
627
|
-
/**
|
|
628
|
-
|
|
669
|
+
/** The height of the rows it spans, where they have one yet. */
|
|
670
|
+
rows: number,
|
|
629
671
|
): void {
|
|
630
672
|
const child = item.box;
|
|
631
673
|
const style = child.style;
|
|
@@ -634,19 +676,35 @@ function layoutItem(
|
|
|
634
676
|
style.justifySelf === 'auto'
|
|
635
677
|
? (parent?.justifyItems ?? 'normal')
|
|
636
678
|
: style.justifySelf;
|
|
679
|
+
resolveEdges(child, area);
|
|
680
|
+
// its border box's height before the rows are sized, where it has one
|
|
681
|
+
const tall = heightBeforeRows(child, rows);
|
|
637
682
|
const margins = child.marginLeft + child.marginRight;
|
|
638
683
|
const room = Math.max(0, area - margins);
|
|
639
|
-
//
|
|
684
|
+
// Its content's widths, border box: measured once in its life, with the
|
|
685
|
+
// percentages in its padding of nothing, as they are while the columns
|
|
686
|
+
// are sized, and here with what those come to of its area. Measuring
|
|
687
|
+
// resolves its edges against nothing, and they are put back.
|
|
688
|
+
const padded = percentPadding(child);
|
|
640
689
|
const content = (): [number, number] => {
|
|
641
|
-
|
|
690
|
+
let probed = false;
|
|
691
|
+
if (child.intrinsicMaxContent < 0) {
|
|
692
|
+
maxContentOf(child, ctx);
|
|
693
|
+
probed = true;
|
|
694
|
+
}
|
|
642
695
|
if (child.intrinsicMinContent < 0) {
|
|
643
696
|
child.intrinsicMinContent = measureIntrinsicWidth(
|
|
644
697
|
child,
|
|
645
698
|
ctx,
|
|
646
699
|
MIN_CONTENT_PROBE,
|
|
647
700
|
);
|
|
701
|
+
probed = true;
|
|
648
702
|
}
|
|
649
|
-
|
|
703
|
+
if (probed) resolveEdges(child, area);
|
|
704
|
+
return [
|
|
705
|
+
child.intrinsicMinContent + padded,
|
|
706
|
+
child.intrinsicMaxContent + padded,
|
|
707
|
+
];
|
|
650
708
|
};
|
|
651
709
|
const keyword = style.widthKeyword;
|
|
652
710
|
// `stretch` fills its area, and so does `normal` but for a replaced
|
|
@@ -699,7 +757,7 @@ function layoutItem(
|
|
|
699
757
|
width = Math.min(widest, Math.max(narrowest, room));
|
|
700
758
|
}
|
|
701
759
|
if (child.kind !== 'replaced') {
|
|
702
|
-
ctx.layoutSubtree(child, width);
|
|
760
|
+
ctx.layoutSubtree(child, width, area);
|
|
703
761
|
return;
|
|
704
762
|
}
|
|
705
763
|
// a replaced element sizes itself from its style: then it is given the
|
|
@@ -718,6 +776,21 @@ function layoutItem(
|
|
|
718
776
|
}
|
|
719
777
|
}
|
|
720
778
|
|
|
779
|
+
/** What the percentages in a box's padding come to across it, its edges
|
|
780
|
+
* resolved: what a width of its content's, measured with them of nothing,
|
|
781
|
+
* is short of its border box by. */
|
|
782
|
+
function percentPadding(box: Box): number {
|
|
783
|
+
const { paddingLeft, paddingRight } = box.style;
|
|
784
|
+
let out = 0;
|
|
785
|
+
if (isPct(paddingLeft)) {
|
|
786
|
+
out += box.padLeft - Math.max(0, resolve(paddingLeft, 0));
|
|
787
|
+
}
|
|
788
|
+
if (isPct(paddingRight)) {
|
|
789
|
+
out += box.padRight - Math.max(0, resolve(paddingRight, 0));
|
|
790
|
+
}
|
|
791
|
+
return out;
|
|
792
|
+
}
|
|
793
|
+
|
|
721
794
|
/** Whether a box's content is its least size through a ratio, which it is
|
|
722
795
|
* where the box shows what overflows it and its least width is `auto`
|
|
723
796
|
* (CSS Sizing 4, 5.2). */
|