@react-x11/components 0.14.0 → 0.16.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/code-editor/node.d.ts +13 -0
- package/dist/code-editor/node.d.ts.map +1 -1
- package/dist/code-editor/node.js +23 -5
- package/dist/code-editor/node.js.map +1 -1
- package/dist/html/css/cascade.d.ts +209 -23
- package/dist/html/css/cascade.d.ts.map +1 -1
- package/dist/html/css/cascade.js +873 -175
- package/dist/html/css/cascade.js.map +1 -1
- package/dist/html/css/color.d.ts +25 -0
- package/dist/html/css/color.d.ts.map +1 -1
- package/dist/html/css/color.js +307 -19
- package/dist/html/css/color.js.map +1 -1
- package/dist/html/css/content.d.ts +11 -6
- package/dist/html/css/content.d.ts.map +1 -1
- package/dist/html/css/content.js +171 -12
- package/dist/html/css/content.js.map +1 -1
- package/dist/html/css/parse.d.ts.map +1 -1
- package/dist/html/css/parse.js +62 -9
- package/dist/html/css/parse.js.map +1 -1
- package/dist/html/css/shapes.d.ts +62 -0
- package/dist/html/css/shapes.d.ts.map +1 -0
- package/dist/html/css/shapes.js +214 -0
- package/dist/html/css/shapes.js.map +1 -0
- package/dist/html/css/style.d.ts +42 -5
- package/dist/html/css/style.d.ts.map +1 -1
- package/dist/html/css/style.js +75 -27
- package/dist/html/css/style.js.map +1 -1
- package/dist/html/css/ua.js +15 -0
- package/dist/html/css/ua.js.map +1 -1
- package/dist/html/css/values.d.ts +5 -0
- package/dist/html/css/values.d.ts.map +1 -1
- package/dist/html/css/values.js +18 -9
- package/dist/html/css/values.js.map +1 -1
- package/dist/html/index.d.ts.map +1 -1
- package/dist/html/index.js +7 -0
- package/dist/html/index.js.map +1 -1
- package/dist/html/layout/block.d.ts +38 -7
- package/dist/html/layout/block.d.ts.map +1 -1
- package/dist/html/layout/block.js +160 -50
- package/dist/html/layout/block.js.map +1 -1
- package/dist/html/layout/boxes.d.ts +29 -2
- package/dist/html/layout/boxes.d.ts.map +1 -1
- package/dist/html/layout/boxes.js +159 -20
- 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 +69 -19
- 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 +1648 -225
- package/dist/html/layout/flex.js.map +1 -1
- package/dist/html/layout/inline.d.ts +15 -3
- package/dist/html/layout/inline.d.ts.map +1 -1
- package/dist/html/layout/inline.js +23 -8
- package/dist/html/layout/inline.js.map +1 -1
- package/dist/html/layout/table.d.ts +27 -1
- package/dist/html/layout/table.d.ts.map +1 -1
- package/dist/html/layout/table.js +907 -323
- package/dist/html/layout/table.js.map +1 -1
- package/dist/html/node.d.ts +36 -4
- package/dist/html/node.d.ts.map +1 -1
- package/dist/html/node.js +174 -37
- 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 +769 -204
- package/dist/html/paint.js.map +1 -1
- package/dist/html/resources.js +14 -1
- package/dist/html/resources.js.map +1 -1
- package/dist/html/svg.d.ts +50 -17
- package/dist/html/svg.d.ts.map +1 -1
- package/dist/html/svg.js +501 -83
- package/dist/html/svg.js.map +1 -1
- package/dist/html/widgets.d.ts.map +1 -1
- package/dist/html/widgets.js +57 -4
- package/dist/html/widgets.js.map +1 -1
- package/package.json +3 -3
- package/src/code-editor/node.ts +24 -5
- package/src/html/css/cascade.ts +987 -176
- package/src/html/css/color.ts +345 -18
- package/src/html/css/content.ts +173 -15
- package/src/html/css/parse.ts +60 -8
- package/src/html/css/shapes.ts +273 -0
- package/src/html/css/style.ts +123 -30
- package/src/html/css/ua.ts +15 -0
- package/src/html/css/values.ts +23 -9
- package/src/html/index.ts +7 -0
- package/src/html/layout/block.ts +169 -56
- package/src/html/layout/boxes.ts +198 -24
- package/src/html/layout/css-grid.ts +89 -22
- package/src/html/layout/flex.ts +1863 -219
- package/src/html/layout/inline.ts +27 -7
- package/src/html/layout/table.ts +989 -333
- package/src/html/node.ts +204 -37
- package/src/html/paint.ts +999 -252
- package/src/html/resources.ts +13 -1
- package/src/html/svg.ts +600 -78
- package/src/html/widgets.ts +61 -4
package/src/html/css/values.ts
CHANGED
|
@@ -127,6 +127,11 @@ export interface UnitContext {
|
|
|
127
127
|
rlh?: () => number;
|
|
128
128
|
/** Every property at its initial value, which `initial` sets one to. */
|
|
129
129
|
initial?: ComputedStyle;
|
|
130
|
+
/** The palette's focus ring, which `-webkit-focus-ring-color` is. */
|
|
131
|
+
focusRing?: string;
|
|
132
|
+
/** Each system colour as the `light-dark()` it is, the palette's in the
|
|
133
|
+
* palette's scheme (`systemColorTable`); Chrome's where it is missing. */
|
|
134
|
+
systemColors?: Map<string, string>;
|
|
130
135
|
}
|
|
131
136
|
|
|
132
137
|
/** A CSS number (CSS Syntax 3 4.3.12): a sign, digits with at most one
|
|
@@ -348,9 +353,10 @@ export function fourSides<T>(parts: T[]): [T, T, T, T] {
|
|
|
348
353
|
* element's own ink, everything else passed through. */
|
|
349
354
|
export function inkColor(color: string, current: string): string {
|
|
350
355
|
if (color === 'currentColor') return current;
|
|
351
|
-
// a `color-mix()` with `currentColor` in it waits
|
|
352
|
-
// every other functional colour was read when it was
|
|
353
|
-
|
|
356
|
+
// a `color-mix()` or a relative colour with `currentColor` in it waits
|
|
357
|
+
// for the colour too; every other functional colour was read when it was
|
|
358
|
+
// parsed, to `#rrggbb` or `rgba()` with no letters in it
|
|
359
|
+
if (color.charCodeAt(color.length - 1) === 41 && HAS_CURRENT.test(color)) {
|
|
354
360
|
return functionalColor(color.replace(CURRENT, current)) ?? current;
|
|
355
361
|
}
|
|
356
362
|
return color;
|
|
@@ -358,6 +364,7 @@ export function inkColor(color: string, current: string): string {
|
|
|
358
364
|
|
|
359
365
|
const CURRENT = /currentcolor/gi;
|
|
360
366
|
const HAS_CURRENT = /currentcolor/i;
|
|
367
|
+
const RELATIVE_COLOR = /^[a-z]+\(\s*from\s/i;
|
|
361
368
|
|
|
362
369
|
/** Whether a colour paints anything at all. Two string tests rather than a
|
|
363
370
|
* parse, for the reason at the top of the file. */
|
|
@@ -410,12 +417,19 @@ export function parseColor(value: string): string | null {
|
|
|
410
417
|
// five or seven, and a typo'd `#ff000` took the application down
|
|
411
418
|
if (v.startsWith('#')) return HEX_COLOR.test(v) ? v : null;
|
|
412
419
|
if (/^(?:rgba?|hsla?|hwb|lab|lch|oklab|oklch|color|color-mix)\(/i.test(v)) {
|
|
413
|
-
// a mix with `currentColor` in it is kept to be
|
|
414
|
-
// (`inkColor`), once it is known to be one
|
|
415
|
-
if (HAS_CURRENT.test(v)
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
420
|
+
// a mix or a relative colour with `currentColor` in it is kept to be
|
|
421
|
+
// worked out where it is used (`inkColor`), once it is known to be one
|
|
422
|
+
if (HAS_CURRENT.test(v)) {
|
|
423
|
+
if (/^color-mix\(/i.test(v)) {
|
|
424
|
+
return functionalColor(v.replace(CURRENT, '#000')) === null
|
|
425
|
+
? null
|
|
426
|
+
: `color-mix(${v.slice(v.indexOf('(') + 1)}`;
|
|
427
|
+
}
|
|
428
|
+
if (RELATIVE_COLOR.test(v)) {
|
|
429
|
+
return functionalColor(v.replace(CURRENT, '#000')) === null
|
|
430
|
+
? null
|
|
431
|
+
: `${v.slice(0, v.indexOf('(')).toLowerCase()}${v.slice(v.indexOf('('))}`;
|
|
432
|
+
}
|
|
419
433
|
}
|
|
420
434
|
return functionalColor(v);
|
|
421
435
|
}
|
package/src/html/index.ts
CHANGED
|
@@ -238,6 +238,13 @@ function deriveLook(
|
|
|
238
238
|
// `medium` and the face it reads pages in
|
|
239
239
|
controlFontSize: Number(theme.fontSize ?? 14),
|
|
240
240
|
controlFontFamily: String(theme.fontFamily ?? 'sans-serif'),
|
|
241
|
+
...(typeof theme.focusRing === 'string' && { focusRing: theme.focusRing }),
|
|
242
|
+
...(typeof theme.focusRingWidth === 'number' && {
|
|
243
|
+
focusRingWidth: theme.focusRingWidth,
|
|
244
|
+
}),
|
|
245
|
+
...(typeof theme.focusRingOffset === 'number' && {
|
|
246
|
+
focusRingOffset: theme.focusRingOffset,
|
|
247
|
+
}),
|
|
241
248
|
};
|
|
242
249
|
}
|
|
243
250
|
|
package/src/html/layout/block.ts
CHANGED
|
@@ -30,6 +30,7 @@ import {
|
|
|
30
30
|
CONTAIN_LAYOUT,
|
|
31
31
|
CONTAIN_PAINT,
|
|
32
32
|
CONTAIN_SIZE,
|
|
33
|
+
INLINE_BEFORE_ABSOLUTE,
|
|
33
34
|
scrolls,
|
|
34
35
|
} from '../css/style.js';
|
|
35
36
|
import { about, linearOf, matrixOf, transformed } from '../css/transform.js';
|
|
@@ -71,6 +72,7 @@ import type {
|
|
|
71
72
|
} from './boxes.js';
|
|
72
73
|
import { FloatContext } from './floats.js';
|
|
73
74
|
import {
|
|
75
|
+
emptyLinePoint,
|
|
74
76
|
faceExtentOf,
|
|
75
77
|
isButton,
|
|
76
78
|
joinsBefore,
|
|
@@ -83,7 +85,7 @@ import {
|
|
|
83
85
|
import type { FontsLike, InlineOptions, InlineResult } from './inline.js';
|
|
84
86
|
import type { TextRun } from '../../richtext/index.js';
|
|
85
87
|
import { layoutFlex } from './flex.js';
|
|
86
|
-
import { finishCaptions, layoutTable } from './table.js';
|
|
88
|
+
import { finishCaptions, givenHeight, layoutTable } from './table.js';
|
|
87
89
|
import { collapseEdges } from './collapse.js';
|
|
88
90
|
import {
|
|
89
91
|
clipsFor,
|
|
@@ -132,7 +134,8 @@ export interface LayoutContext {
|
|
|
132
134
|
* its padding, its margins and its width limits are of (CSS 2.1 8.3,
|
|
133
135
|
* 8.4, 10.4). Left out, `width` is both — a box probed at the room there
|
|
134
136
|
* is for it. For a table cell it is the width of its row, which its
|
|
135
|
-
* padding's percentages are of
|
|
137
|
+
* padding's percentages are of, and it says the cell is laid out in its
|
|
138
|
+
* columns: at `width`, whatever its limits say.
|
|
136
139
|
*/
|
|
137
140
|
layoutSubtree(box: Box, width: number, containing?: number): void;
|
|
138
141
|
/** How many flex boxes' Yoga passes are running, one inside the last's
|
|
@@ -843,13 +846,19 @@ function layoutChildren(
|
|
|
843
846
|
marked = null;
|
|
844
847
|
}
|
|
845
848
|
if (child.outOfFlow) {
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
849
|
+
const top = y + marginOf(pendingMargin);
|
|
850
|
+
if (INLINE_BEFORE_ABSOLUTE.has(child.style)) {
|
|
851
|
+
// one that was inline-level is on a line of its own, beside the
|
|
852
|
+
// floats there, where the line's alignment puts what it holds
|
|
853
|
+
const band = floats.bandAt(
|
|
854
|
+
top,
|
|
855
|
+
1,
|
|
856
|
+
contentLeft,
|
|
857
|
+
contentLeft + contentWidth,
|
|
858
|
+
);
|
|
859
|
+
const at = emptyLinePoint(box.style, band.left, band.right);
|
|
860
|
+
placeStatic(child, box, at, 0, top);
|
|
861
|
+
} else placeStatic(child, box, contentLeft, contentWidth, top);
|
|
853
862
|
ctx.positioned.push({
|
|
854
863
|
box: child,
|
|
855
864
|
containing: containingBlockFor(child) ?? box,
|
|
@@ -1670,43 +1679,65 @@ export function measureIntrinsicWidth(
|
|
|
1670
1679
|
available: number,
|
|
1671
1680
|
content = false,
|
|
1672
1681
|
): number {
|
|
1673
|
-
ctx.layoutSubtree
|
|
1682
|
+
// not through `ctx.layoutSubtree`, which is this and one frame more on
|
|
1683
|
+
// the stack for every level of a document that measures what it holds
|
|
1684
|
+
// (`layoutTable`)
|
|
1685
|
+
layoutSubtree(box, ctx, available, undefined, true);
|
|
1674
1686
|
const specified = box.style.width;
|
|
1675
1687
|
if (!content && specified !== AUTO && Number.isFinite(box.width)) {
|
|
1676
1688
|
return box.width;
|
|
1677
1689
|
}
|
|
1678
|
-
return
|
|
1690
|
+
return (
|
|
1691
|
+
intrinsicWidth(box, undefined, available === MIN_CONTENT_PROBE) +
|
|
1692
|
+
box.horizontalExtra
|
|
1693
|
+
);
|
|
1679
1694
|
}
|
|
1680
1695
|
|
|
1681
1696
|
/**
|
|
1682
1697
|
* Lay a box and everything under it out at a width, at the origin — what
|
|
1683
|
-
* `LayoutContext.layoutSubtree` hands to `flex.ts` and `
|
|
1684
|
-
* the shrink-to-fit probe
|
|
1685
|
-
* because there is nothing inside it to lay out.
|
|
1698
|
+
* `LayoutContext.layoutSubtree` hands to `flex.ts` and `css-grid.ts`, and
|
|
1699
|
+
* what the shrink-to-fit probe and a table's cells use. A replaced box is
|
|
1700
|
+
* sized rather than laid out, because there is nothing inside it to lay out.
|
|
1686
1701
|
*/
|
|
1687
|
-
function layoutSubtree(
|
|
1702
|
+
export function layoutSubtree(
|
|
1688
1703
|
box: Box,
|
|
1689
1704
|
ctx: LayoutContext,
|
|
1690
1705
|
width: number,
|
|
1691
1706
|
/** Its containing block's width, where `width` is the box's own. */
|
|
1692
|
-
containing
|
|
1707
|
+
containing?: number,
|
|
1708
|
+
/** Whether this lays it out to measure it (`measureIntrinsicWidth`). */
|
|
1709
|
+
measuring = false,
|
|
1693
1710
|
): void {
|
|
1694
|
-
|
|
1711
|
+
const base = containing ?? width;
|
|
1712
|
+
resolveEdges(box, Number.isFinite(base) ? base : 0);
|
|
1695
1713
|
if (box.kind === 'replaced') {
|
|
1696
1714
|
sizeReplaced(box, width);
|
|
1697
1715
|
box.x = 0;
|
|
1698
1716
|
box.y = 0;
|
|
1699
1717
|
return;
|
|
1700
1718
|
}
|
|
1701
|
-
//
|
|
1719
|
+
// Within its limits, a percentage among them of its containing block's
|
|
1702
1720
|
// width and not of its own: a flex item `max-width: 50%` that the flex
|
|
1703
|
-
// layout made half its row was laid out at a quarter of it.
|
|
1704
|
-
//
|
|
1705
|
-
//
|
|
1706
|
-
//
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1721
|
+
// layout made half its row was laid out at a quarter of it. An
|
|
1722
|
+
// intrinsic limit is among them, as it is in a block's flow: without it,
|
|
1723
|
+
// a flex or grid item `min-width: max-content` that its layout made as
|
|
1724
|
+
// wide as its content was laid out at a smaller `max-width`, where the
|
|
1725
|
+
// minimum wins (CSS Sizing 3, 3.1). Not where the box is laid out to be
|
|
1726
|
+
// measured, since that is what an intrinsic limit is measured from.
|
|
1727
|
+
//
|
|
1728
|
+
// A table cell laid out in its columns, which hand it its row's width,
|
|
1729
|
+
// is as wide as they are (CSS Tables 3, 3.10.2): its limits are theirs
|
|
1730
|
+
// to weigh (3.8.2), and have been. Clamped again, `td { max-width:
|
|
1731
|
+
// 50px }` in a column 200 wide set its text in 50 of it. Probed for
|
|
1732
|
+
// what it asks of them, at none, it keeps within its length limits as
|
|
1733
|
+
// any box does; a percentage one is of nothing and does not hold it.
|
|
1734
|
+
let borderBox = Infinity;
|
|
1735
|
+
if (Number.isFinite(width)) {
|
|
1736
|
+
if (box.kind !== 'table-cell') {
|
|
1737
|
+
borderBox = clampWidth(box, width, base, measuring ? undefined : ctx);
|
|
1738
|
+
} else if (containing !== undefined) borderBox = width;
|
|
1739
|
+
else borderBox = clampWidth(box, width, NaN);
|
|
1740
|
+
}
|
|
1710
1741
|
layoutInternals(box, ctx, borderBox, 0, 0);
|
|
1711
1742
|
}
|
|
1712
1743
|
|
|
@@ -2110,12 +2141,12 @@ function layoutMarker(box: Box, marker: Marker, ctx: LayoutContext): void {
|
|
|
2110
2141
|
const style = box.style;
|
|
2111
2142
|
if (marker.image) {
|
|
2112
2143
|
// an image: its bottom on the first line's baseline, as an inline
|
|
2113
|
-
// image's is, and
|
|
2144
|
+
// image's is, and its own gap before the content (`MARKER_IMAGE_GAP`)
|
|
2114
2145
|
const first = firstLineIn(box);
|
|
2115
2146
|
marker.y = first
|
|
2116
2147
|
? first.y + first.baseline - marker.image.height
|
|
2117
2148
|
: box.contentY;
|
|
2118
|
-
const gap =
|
|
2149
|
+
const { gap } = marker.image;
|
|
2119
2150
|
// at the start of the line, which is its right in a right-to-left item
|
|
2120
2151
|
marker.x =
|
|
2121
2152
|
style.direction === 'rtl'
|
|
@@ -2150,9 +2181,13 @@ function layoutMarker(box: Box, marker: Marker, ctx: LayoutContext): void {
|
|
|
2150
2181
|
});
|
|
2151
2182
|
marker.layout = layout;
|
|
2152
2183
|
// a space between it and the content — the one its style's suffix ends
|
|
2153
|
-
// in, or its own text's — in its own face: a line measures without
|
|
2154
|
-
|
|
2155
|
-
|
|
2184
|
+
// in, or its own text's — in its own face: a line measures without the
|
|
2185
|
+
// spaces it ends in, and with a no-break space, which `content: "1.\a0"`
|
|
2186
|
+
// writes and which was a second gap on top of its own
|
|
2187
|
+
const trailing = marker.flush
|
|
2188
|
+
? (/[ \t\n\r\f]*$/.exec(marker.text)?.[0].length ?? 0)
|
|
2189
|
+
: 1;
|
|
2190
|
+
const gap = trailing ? trailing * markerGap(fonts, face) : 0;
|
|
2156
2191
|
// The marker sits on the first line of the item's *content*, which is not
|
|
2157
2192
|
// always the item's own: an `<li>` holding a paragraph, or one holding text
|
|
2158
2193
|
// and a nested list, has its inline content in an anonymous block. Looking
|
|
@@ -2324,8 +2359,9 @@ function stretchHeight(box: Box): number | null {
|
|
|
2324
2359
|
* stretched item's, a flexed one's in a container of a definite height (CSS
|
|
2325
2360
|
* Flexbox 9.8), a grid item's stretched down its area (CSS Grid 1, 11.1) —
|
|
2326
2361
|
* which what is in it takes its percentages of, and which an item that is
|
|
2327
|
-
* a flex or grid container itself lays its own items out in
|
|
2328
|
-
* `flex.ts` and `css-grid.ts` for the
|
|
2362
|
+
* a flex or grid container itself lays its own items out in, and a table
|
|
2363
|
+
* shares out among its rows. Set by `flex.ts` and `css-grid.ts` for the
|
|
2364
|
+
* item's own layout alone.
|
|
2329
2365
|
*/
|
|
2330
2366
|
export const FLEXED_HEIGHT = new WeakMap<Box, number>();
|
|
2331
2367
|
|
|
@@ -2333,12 +2369,26 @@ export const FLEXED_HEIGHT = new WeakMap<Box, number>();
|
|
|
2333
2369
|
* The content height a flex layout gave an item without making it definite:
|
|
2334
2370
|
* flexed along a column that has no height of its own, which 9.8 leaves
|
|
2335
2371
|
* indefinite. An item that is a flex or grid container lays its own items
|
|
2336
|
-
* out in it all the same — it is its used size (9.7) —
|
|
2337
|
-
* takes a percentage of it. Set by
|
|
2338
|
-
* alone.
|
|
2372
|
+
* out in it all the same — it is its used size (9.7) — as a table shares
|
|
2373
|
+
* it among its rows, and nothing in it takes a percentage of it. Set by
|
|
2374
|
+
* `flex.ts` for the item's own layout alone.
|
|
2339
2375
|
*/
|
|
2340
2376
|
export const USED_HEIGHT = new WeakMap<Box, number>();
|
|
2341
2377
|
|
|
2378
|
+
/**
|
|
2379
|
+
* A table a grid or a flex layout gives its width, whose `auto` width is
|
|
2380
|
+
* then the one it is laid out at. `normal` stretches any grid item but a
|
|
2381
|
+
* replaced one across its area (CSS Grid 1, 6.2), and a flex item across a
|
|
2382
|
+
* column's line (CSS Flexbox 9.4, step 11), a table among them; and a flex
|
|
2383
|
+
* item along a row is the size the line flexed it to (9.7) — where in a
|
|
2384
|
+
* block's flow a table's `auto` width is its columns' (CSS 2.1 17.5.2;
|
|
2385
|
+
* Blink leaves tables out of the boxes a block stretches, `space_utils.cc`,
|
|
2386
|
+
* and stretches them in a grid, `grid_item.cc`, and a flex box). Set by
|
|
2387
|
+
* `css-grid.ts` and `flex.ts` for the item's own layout alone, and never
|
|
2388
|
+
* while its widths are measured.
|
|
2389
|
+
*/
|
|
2390
|
+
export const STRETCHED_ACROSS = new WeakSet<Box>();
|
|
2391
|
+
|
|
2342
2392
|
/**
|
|
2343
2393
|
* Hand a box's children the height their percentages resolve against —
|
|
2344
2394
|
* through inline boxes, which are no containing block, to the inline-block
|
|
@@ -2527,6 +2577,14 @@ function finishHeight(box: Box, contentHeight: number): void {
|
|
|
2527
2577
|
if (box.kind === 'table-cell') {
|
|
2528
2578
|
CELL_CONTENT.set(box, contentHeight + box.verticalExtra);
|
|
2529
2579
|
}
|
|
2580
|
+
// A table a flex or grid layout gave a height is as tall as that, or as
|
|
2581
|
+
// its rows where they need more, which `layoutTable` has shared it out
|
|
2582
|
+
// among — whatever height it has of its own, which the flex layout
|
|
2583
|
+
// started from (`layoutTable`)
|
|
2584
|
+
if (box.kind === 'table' && Number.isFinite(givenHeight(box))) {
|
|
2585
|
+
box.height = contentHeight + box.verticalExtra;
|
|
2586
|
+
return;
|
|
2587
|
+
}
|
|
2530
2588
|
const set = specifiedHeight(box);
|
|
2531
2589
|
// at least zero: a `calc()` may come to less
|
|
2532
2590
|
const specified = set === null ? null : Math.max(0, set);
|
|
@@ -2596,7 +2654,9 @@ export function clampHeight(box: Box, height: number): number {
|
|
|
2596
2654
|
out,
|
|
2597
2655
|
min + (box.style.boxSizing === 'border-box' ? 0 : box.verticalExtra),
|
|
2598
2656
|
);
|
|
2599
|
-
|
|
2657
|
+
// no shorter than its padding and borders, as `clampWidth` is no
|
|
2658
|
+
// narrower
|
|
2659
|
+
return Math.max(box.verticalExtra, out);
|
|
2600
2660
|
}
|
|
2601
2661
|
|
|
2602
2662
|
/** Place a block-level box horizontally, honouring `margin: auto`. */
|
|
@@ -2816,7 +2876,10 @@ export function clampWidth(
|
|
|
2816
2876
|
keywordWidth(box, ctx, style.minWidthKeyword, containingWidth, room),
|
|
2817
2877
|
);
|
|
2818
2878
|
}
|
|
2819
|
-
|
|
2879
|
+
// and no narrower than its padding and borders: a `border-box` length
|
|
2880
|
+
// less than them leaves its content box none wide, and not less (CSS
|
|
2881
|
+
// Sizing 3, 3.3)
|
|
2882
|
+
return Math.max(box.horizontalExtra, out);
|
|
2820
2883
|
}
|
|
2821
2884
|
|
|
2822
2885
|
/** An intrinsic `min-width` or `max-width` in the room a box's margins
|
|
@@ -2858,10 +2921,8 @@ export function contentSizedWidth(
|
|
|
2858
2921
|
// the content's sizes, whatever width the box has of its own: a
|
|
2859
2922
|
// `min-width: max-content` beside a `width` is its content's widest,
|
|
2860
2923
|
// and a probe of the box at no width answered the probe's width
|
|
2861
|
-
let probed = false;
|
|
2862
2924
|
if (box.intrinsicMaxContent < 0) {
|
|
2863
2925
|
box.intrinsicMaxContent = measureIntrinsicWidth(box, ctx, Infinity, true);
|
|
2864
|
-
probed = true;
|
|
2865
2926
|
}
|
|
2866
2927
|
if (size !== 'max-content' && box.intrinsicMinContent < 0) {
|
|
2867
2928
|
box.intrinsicMinContent = measureIntrinsicWidth(
|
|
@@ -2870,12 +2931,19 @@ export function contentSizedWidth(
|
|
|
2870
2931
|
MIN_CONTENT_PROBE,
|
|
2871
2932
|
true,
|
|
2872
2933
|
);
|
|
2873
|
-
probed = true;
|
|
2874
2934
|
}
|
|
2875
|
-
|
|
2876
|
-
|
|
2935
|
+
// The probes resolved a percentage of the box's padding or border
|
|
2936
|
+
// against nothing, which is how the sizes are kept, whatever the width
|
|
2937
|
+
// around the box: what one comes to against `percentBase` goes on top.
|
|
2938
|
+
// Left out, `width: max-content; padding-left: 10%` was as wide as its
|
|
2939
|
+
// content, the padding inside it.
|
|
2940
|
+
resolveEdges(box, 0);
|
|
2941
|
+
const bare = box.horizontalExtra;
|
|
2942
|
+
resolveEdges(box, Number.isFinite(percentBase) ? percentBase : 0);
|
|
2943
|
+
const extra = box.horizontalExtra - bare;
|
|
2944
|
+
const max = box.intrinsicMaxContent + extra;
|
|
2877
2945
|
if (size === 'max-content') return max;
|
|
2878
|
-
const min = box.intrinsicMinContent;
|
|
2946
|
+
const min = box.intrinsicMinContent + extra;
|
|
2879
2947
|
if (size === 'min-content') return min;
|
|
2880
2948
|
return Math.min(
|
|
2881
2949
|
max,
|
|
@@ -3027,6 +3095,10 @@ const PREFERRED = new WeakMap<Box, number>();
|
|
|
3027
3095
|
* or is indented, a block with widths of its own.
|
|
3028
3096
|
*/
|
|
3029
3097
|
export function exactMinContent(box: Box, fonts: FontsLike): number | null {
|
|
3098
|
+
// a flex row's is its items' side by side, a grid's its columns', and a
|
|
3099
|
+
// replaced element has no words: read as its widest word, a row of two
|
|
3100
|
+
// in a flex column's item was as narrow as the wider of them
|
|
3101
|
+
if (box.kind !== 'block' && box.kind !== 'table-cell') return null;
|
|
3030
3102
|
if (hasWidths(box.style) || contained(box, CONTAIN_WIDTH)) return null;
|
|
3031
3103
|
const inner = exactWords(box, fonts);
|
|
3032
3104
|
return inner === null ? null : inner + box.horizontalExtra;
|
|
@@ -3160,13 +3232,32 @@ function wordBound(box: Box, fonts: FontsLike, measured: boolean): number {
|
|
|
3160
3232
|
* `seen.cut` is set where a line it measured was cut short by
|
|
3161
3233
|
* `text-overflow`, in a box with a width to cut it at: the line is wider
|
|
3162
3234
|
* than it was drawn, and the answer is of what was drawn.
|
|
3235
|
+
*
|
|
3236
|
+
* `narrowest` says the box was laid out by the min-content probe
|
|
3237
|
+
* (`MIN_CONTENT_PROBE`), and the answer is its min-content width: the
|
|
3238
|
+
* probe lays a box out at no width, but one with a least width of its own
|
|
3239
|
+
* at that, and nothing in the layout tells the two apart.
|
|
3163
3240
|
*/
|
|
3164
|
-
export function intrinsicWidth(
|
|
3241
|
+
export function intrinsicWidth(
|
|
3242
|
+
box: Box,
|
|
3243
|
+
seen?: { cut: boolean },
|
|
3244
|
+
narrowest = false,
|
|
3245
|
+
): number {
|
|
3165
3246
|
// under size containment, as though it held nothing: the size
|
|
3166
3247
|
// `contain-intrinsic-size` gives it, or none (CSS Containment 2, 3.2)
|
|
3167
3248
|
if (contained(box, CONTAIN_WIDTH)) {
|
|
3168
3249
|
return box.style.containIntrinsicWidth ?? 0;
|
|
3169
3250
|
}
|
|
3251
|
+
// a table is as wide as its layout made it: its columns, the spacing
|
|
3252
|
+
// either side of them and between, and its captions' least (`layoutTable`)
|
|
3253
|
+
// — at no width limit its widest, and at none its narrowest. What it
|
|
3254
|
+
// holds says less: its rows run from the first column to the last, the
|
|
3255
|
+
// spacing either side outside them, and measured by them a table in a
|
|
3256
|
+
// flex row, a grid, a float or an `inline-table` came to that much too
|
|
3257
|
+
// narrow, and its columns gave it up
|
|
3258
|
+
if (box.kind === 'table' && Number.isFinite(box.width)) {
|
|
3259
|
+
return Math.max(0, box.width - box.horizontalExtra);
|
|
3260
|
+
}
|
|
3170
3261
|
// a grid laid out at no width limit has its columns at their widest, and
|
|
3171
3262
|
// is as wide as they are — an item that runs past its column makes it no
|
|
3172
3263
|
// wider — or, where it has none, as where its items end
|
|
@@ -3185,11 +3276,17 @@ export function intrinsicWidth(box: Box, seen?: { cut: boolean }): number {
|
|
|
3185
3276
|
}
|
|
3186
3277
|
let widest = 0;
|
|
3187
3278
|
// A row of flex items is as wide as all of them side by side, and gaps
|
|
3188
|
-
// between them; any other box is as wide as the widest thing in it
|
|
3279
|
+
// between them; any other box is as wide as the widest thing in it. So
|
|
3280
|
+
// is a row that wraps, at its narrowest: each of its items may be a line
|
|
3281
|
+
// of its own, and it is as wide as the widest of them (CSS Flexbox
|
|
3282
|
+
// 9.9.1). Summed, a wrapping row of three 30px items made a
|
|
3283
|
+
// `width: min-content` box around it 90 wide, the items side by side,
|
|
3284
|
+
// where Chrome has 30, one under another
|
|
3189
3285
|
const display = box.style.display;
|
|
3190
3286
|
const row =
|
|
3191
3287
|
(display === 'flex' || display === 'inline-flex') &&
|
|
3192
3288
|
box.style.flexDirection.startsWith('row');
|
|
3289
|
+
const wraps = row && narrowest && box.style.flexWrap !== 'nowrap';
|
|
3193
3290
|
let total = 0;
|
|
3194
3291
|
let items = 0;
|
|
3195
3292
|
const lines = box.lines;
|
|
@@ -3257,7 +3354,8 @@ export function intrinsicWidth(box: Box, seen?: { cut: boolean }): number {
|
|
|
3257
3354
|
contribution = Math.max(contribution, stated + margins);
|
|
3258
3355
|
}
|
|
3259
3356
|
} else {
|
|
3260
|
-
let inner =
|
|
3357
|
+
let inner =
|
|
3358
|
+
intrinsicWidth(child, seen, narrowest) + child.horizontalExtra;
|
|
3261
3359
|
if (typeof style.maxWidth === 'number') {
|
|
3262
3360
|
inner = Math.min(inner, style.maxWidth + contentExtra(child));
|
|
3263
3361
|
}
|
|
@@ -3269,10 +3367,10 @@ export function intrinsicWidth(box: Box, seen?: { cut: boolean }): number {
|
|
|
3269
3367
|
across = Math.max(across, contribution);
|
|
3270
3368
|
continue;
|
|
3271
3369
|
}
|
|
3272
|
-
if (row) {
|
|
3370
|
+
if (row && !wraps) {
|
|
3273
3371
|
total += contribution;
|
|
3274
3372
|
items += 1;
|
|
3275
|
-
} else if (!sideBySide) widest = Math.max(widest, contribution);
|
|
3373
|
+
} else if (wraps || !sideBySide) widest = Math.max(widest, contribution);
|
|
3276
3374
|
else if (child.isFloat) {
|
|
3277
3375
|
const clear = style.clear;
|
|
3278
3376
|
if (clear !== 'none') {
|
|
@@ -3404,8 +3502,17 @@ function sizeReplaced(
|
|
|
3404
3502
|
const ih = own.missing & 2 ? null : own.height;
|
|
3405
3503
|
// `aspect-ratio` over its own, unless written `auto` and it has one
|
|
3406
3504
|
const aspect = style.aspectRatio;
|
|
3407
|
-
const ratio
|
|
3408
|
-
|
|
3505
|
+
const pages = aspect !== null && !(aspect.auto && own.ratio > 0);
|
|
3506
|
+
const ratio = pages ? aspect.ratio : own.ratio;
|
|
3507
|
+
// A ratio of the page's is of the box `box-sizing` names (CSS Sizing 4,
|
|
3508
|
+
// 5.1): one axis's content size to the other's goes through the border
|
|
3509
|
+
// box there. Written with `auto`, it is of the content box, as the
|
|
3510
|
+
// replaced element's own is, whichever it is.
|
|
3511
|
+
const outer = pages && !aspect.auto && style.boxSizing === 'border-box';
|
|
3512
|
+
const ox = outer ? box.horizontalExtra : 0;
|
|
3513
|
+
const oy = outer ? box.verticalExtra : 0;
|
|
3514
|
+
const widthOf = (h: number): number => Math.max(0, (h + oy) * ratio - ox);
|
|
3515
|
+
const heightOf = (w: number): number => Math.max(0, (w + ox) / ratio - oy);
|
|
3409
3516
|
// the width a block would have here: what a ratio with no size fills, and
|
|
3410
3517
|
// an `hr`, whose whole appearance is its border across the line
|
|
3411
3518
|
const room = (): number => {
|
|
@@ -3421,16 +3528,16 @@ function sizeReplaced(
|
|
|
3421
3528
|
// which moves both axes together
|
|
3422
3529
|
if (iw !== null) {
|
|
3423
3530
|
w = iw;
|
|
3424
|
-
h = ih ?? iw
|
|
3531
|
+
h = ih ?? heightOf(iw);
|
|
3425
3532
|
} else if (ih !== null) {
|
|
3426
3533
|
h = ih;
|
|
3427
|
-
w = ih
|
|
3534
|
+
w = widthOf(ih);
|
|
3428
3535
|
} else {
|
|
3429
3536
|
// a ratio and no size: CSS 2.1 leaves it undefined and suggests the
|
|
3430
3537
|
// width a block would have, which is what browsers do — or, where the
|
|
3431
3538
|
// containing block waits on this box, the default object size
|
|
3432
3539
|
w = Number.isFinite(containingWidth) ? room() : own.width;
|
|
3433
|
-
h = w
|
|
3540
|
+
h = heightOf(w);
|
|
3434
3541
|
}
|
|
3435
3542
|
[w, h] = constrained(w, h, minW, maxW, minH, maxH);
|
|
3436
3543
|
} else {
|
|
@@ -3439,12 +3546,12 @@ function sizeReplaced(
|
|
|
3439
3546
|
// again" for a limit)
|
|
3440
3547
|
const usedHeight = height === null ? null : clamp(height, minH, maxH);
|
|
3441
3548
|
if (width !== null) w = width;
|
|
3442
|
-
else if (usedHeight !== null && ratio > 0) w = usedHeight
|
|
3549
|
+
else if (usedHeight !== null && ratio > 0) w = widthOf(usedHeight);
|
|
3443
3550
|
else if (box.replaced === 'hr') w = room();
|
|
3444
3551
|
else w = own.width;
|
|
3445
3552
|
w = clamp(w, minW, maxW);
|
|
3446
3553
|
if (usedHeight !== null) h = usedHeight;
|
|
3447
|
-
else if (ratio > 0) h = clamp(w
|
|
3554
|
+
else if (ratio > 0) h = clamp(heightOf(w), minH, maxH);
|
|
3448
3555
|
else h = clamp(own.height, minH, maxH);
|
|
3449
3556
|
}
|
|
3450
3557
|
box.width = w + box.horizontalExtra;
|
|
@@ -3793,10 +3900,16 @@ function layoutPositioned(box: Box, containing: Box, ctx: LayoutContext): void {
|
|
|
3793
3900
|
0,
|
|
3794
3901
|
cbHeight - top - bottom - box.marginTop - box.marginBottom,
|
|
3795
3902
|
);
|
|
3796
|
-
// — a box with a ratio has its height from its width
|
|
3903
|
+
// — a box with a ratio has its height from its width, and a table is
|
|
3904
|
+
// as tall as its rows, as it is as wide as its columns between two
|
|
3905
|
+
// offsets: `normal` stretches neither (Blink: "Replaced/tables don't
|
|
3906
|
+
// stretch in abspos", `out_of_flow_layout_part.cc`), and a table taken
|
|
3907
|
+
// to the height its offsets leave was that tall around rows that were
|
|
3908
|
+
// not
|
|
3797
3909
|
const stretches =
|
|
3798
3910
|
style.height === AUTO &&
|
|
3799
3911
|
(box.kind !== 'replaced' || control) &&
|
|
3912
|
+
box.kind !== 'table' &&
|
|
3800
3913
|
!boxRatio(box);
|
|
3801
3914
|
// both offsets and no height: the box fills what they leave, its
|
|
3802
3915
|
// `auto` margins nothing (10.6.4, rule 5) — unless `min-height` or
|