@react-x11/components 0.13.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/controls.d.ts +29 -2
- package/dist/html/controls.d.ts.map +1 -1
- package/dist/html/controls.js +70 -2
- package/dist/html/controls.js.map +1 -1
- 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 +336 -16
- 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 +18 -4
- package/dist/html/css/parse.d.ts.map +1 -1
- package/dist/html/css/parse.js +66 -28
- package/dist/html/css/parse.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 +128 -15
- package/dist/html/css/style.d.ts.map +1 -1
- package/dist/html/css/style.js +547 -144
- 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.map +1 -1
- package/dist/html/css/ua.js +14 -2
- 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/fonts.d.ts +55 -5
- package/dist/html/fonts.d.ts.map +1 -1
- package/dist/html/fonts.js +284 -23
- package/dist/html/fonts.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 +104 -12
- package/dist/html/layout/block.d.ts.map +1 -1
- package/dist/html/layout/block.js +410 -39
- package/dist/html/layout/block.js.map +1 -1
- package/dist/html/layout/boxes.d.ts +72 -1
- package/dist/html/layout/boxes.d.ts.map +1 -1
- package/dist/html/layout/boxes.js +40 -2
- 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 +144 -24
- 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 +585 -85
- 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 +144 -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 +97 -31
- package/dist/html/layout/table.js.map +1 -1
- package/dist/html/node.d.ts +4 -0
- package/dist/html/node.d.ts.map +1 -1
- package/dist/html/node.js +319 -47
- package/dist/html/node.js.map +1 -1
- package/dist/html/paint.d.ts +83 -5
- package/dist/html/paint.d.ts.map +1 -1
- package/dist/html/paint.js +1474 -217
- package/dist/html/paint.js.map +1 -1
- package/dist/html/svg.d.ts +39 -9
- package/dist/html/svg.d.ts.map +1 -1
- package/dist/html/svg.js +482 -37
- package/dist/html/svg.js.map +1 -1
- package/dist/html/widgets.js +87 -7
- package/dist/html/widgets.js.map +1 -1
- 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/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 +1 -1
- package/src/html/controls.ts +85 -2
- package/src/html/css/cascade.ts +366 -8
- package/src/html/css/color.ts +29 -0
- package/src/html/css/parse.ts +71 -31
- package/src/html/css/shapes.ts +239 -0
- package/src/html/css/style.ts +652 -147
- package/src/html/css/transform.ts +459 -0
- package/src/html/css/ua.ts +15 -2
- package/src/html/css/values.ts +4 -0
- package/src/html/fonts.ts +312 -29
- package/src/html/layout/axes.ts +62 -0
- package/src/html/layout/block.ts +466 -37
- package/src/html/layout/boxes.ts +95 -3
- package/src/html/layout/cache.ts +6 -0
- package/src/html/layout/css-grid.ts +169 -32
- package/src/html/layout/flex.ts +686 -79
- package/src/html/layout/inline.ts +149 -55
- package/src/html/layout/multicol.ts +977 -0
- package/src/html/layout/shaping.ts +27 -18
- package/src/html/layout/table.ts +105 -35
- package/src/html/node.ts +354 -48
- package/src/html/paint.ts +1804 -315
- package/src/html/svg.ts +573 -36
- package/src/html/widgets.ts +95 -9
- package/src/html/woff2.ts +612 -0
- package/src/maps/controller.ts +28 -7
- package/src/richtext/node.ts +13 -2
- package/src/richtext/runs.ts +313 -35
|
@@ -47,29 +47,38 @@ export function shapingSafe(engine: FontsLike): FontsLike {
|
|
|
47
47
|
return engine.layout(stood.content, style, options);
|
|
48
48
|
}
|
|
49
49
|
};
|
|
50
|
-
|
|
51
|
-
// and what a caller feature-detects — ntk's `prewarm`, which
|
|
52
|
-
// `_warmFaces` asks for — where a wrapper that forwarded only the two
|
|
53
|
-
// it knew of hid the rest, and warming stopped without a word.
|
|
54
|
-
const bound = new Map<PropertyKey, { from: unknown; to: unknown }>();
|
|
55
|
-
safe = new Proxy(engine, {
|
|
56
|
-
get(target, key) {
|
|
57
|
-
if (key === 'layout') return layout;
|
|
58
|
-
const value: unknown = Reflect.get(target, key, target);
|
|
59
|
-
if (typeof value !== 'function') return value;
|
|
60
|
-
let hit = bound.get(key);
|
|
61
|
-
if (hit?.from !== value) {
|
|
62
|
-
hit = { from: value, to: value.bind(target) };
|
|
63
|
-
bound.set(key, hit);
|
|
64
|
-
}
|
|
65
|
-
return hit.to;
|
|
66
|
-
},
|
|
67
|
-
});
|
|
50
|
+
safe = withLayout(engine, layout);
|
|
68
51
|
SAFE.set(engine, safe);
|
|
69
52
|
}
|
|
70
53
|
return safe;
|
|
71
54
|
}
|
|
72
55
|
|
|
56
|
+
/**
|
|
57
|
+
* `engine` with another `layout`. Everything else the engine answers is its
|
|
58
|
+
* own, called on it: `match`, and what a caller feature-detects — ntk's
|
|
59
|
+
* `prewarm`, which `_warmFaces` asks for — where a wrapper that forwarded
|
|
60
|
+
* only the two it knew of hid the rest, and warming stopped without a word.
|
|
61
|
+
*/
|
|
62
|
+
export function withLayout(
|
|
63
|
+
engine: FontsLike,
|
|
64
|
+
layout: FontsLike['layout'],
|
|
65
|
+
): FontsLike {
|
|
66
|
+
const bound = new Map<PropertyKey, { from: unknown; to: unknown }>();
|
|
67
|
+
return new Proxy(engine, {
|
|
68
|
+
get(target, key) {
|
|
69
|
+
if (key === 'layout') return layout;
|
|
70
|
+
const value: unknown = Reflect.get(target, key, target);
|
|
71
|
+
if (typeof value !== 'function') return value;
|
|
72
|
+
let hit = bound.get(key);
|
|
73
|
+
if (hit?.from !== value) {
|
|
74
|
+
hit = { from: value, to: value.bind(target) };
|
|
75
|
+
bound.set(key, hit);
|
|
76
|
+
}
|
|
77
|
+
return hit.to;
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
73
82
|
/** `content` with each character its face cannot shape replaced, or null
|
|
74
83
|
* when there is none to replace. */
|
|
75
84
|
function standIns(
|
package/src/html/layout/table.ts
CHANGED
|
@@ -13,11 +13,16 @@
|
|
|
13
13
|
// algorithm is too slow — which, on a table with a thousand rows, it is.
|
|
14
14
|
import { AUTO, isPct, resolveOrNull } from '../css/values.js';
|
|
15
15
|
import type { Len } from '../css/values.js';
|
|
16
|
+
import type { ComputedStyle } from '../css/style.js';
|
|
16
17
|
import { Box, CLIPPED_CELLS, COLLAPSED_CELLS, isBlank } from './boxes.js';
|
|
17
18
|
import {
|
|
18
19
|
CELL_CONTENT,
|
|
20
|
+
FLEXED_HEIGHT,
|
|
19
21
|
MIN_CONTENT_PROBE,
|
|
22
|
+
STRETCHED_ACROSS,
|
|
23
|
+
USED_HEIGHT,
|
|
20
24
|
clampHeight,
|
|
25
|
+
cyclicWidth,
|
|
21
26
|
exactMinContent,
|
|
22
27
|
layoutBlockIn,
|
|
23
28
|
measureIntrinsicWidth,
|
|
@@ -40,12 +45,19 @@ export function layoutTable(
|
|
|
40
45
|
tableGrid(table);
|
|
41
46
|
table.captionTop = 0;
|
|
42
47
|
table.captionBottom = 0;
|
|
48
|
+
// a percentage of a width that is not known is `auto`: the table is as
|
|
49
|
+
// wide as its columns where its content is measured (`cyclicWidth`)
|
|
50
|
+
const own =
|
|
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);
|
|
43
55
|
if (!columnCount) {
|
|
44
56
|
// With no columns, an auto table is as wide as its widest caption can
|
|
45
57
|
// be and its `min-width` asks, as one with columns is at the least
|
|
46
58
|
// (17.5.2), rather than as the room on offer: a caption over no cells
|
|
47
59
|
// was centred in the width of the page.
|
|
48
|
-
if (
|
|
60
|
+
if (auto) {
|
|
49
61
|
let inner = captions.length
|
|
50
62
|
? captionMinimum(captions, ctx) - table.horizontalExtra
|
|
51
63
|
: 0;
|
|
@@ -72,11 +84,18 @@ export function layoutTable(
|
|
|
72
84
|
const gaps = spacing * (columnCount + 1);
|
|
73
85
|
const available = Math.max(0, contentWidth - gaps);
|
|
74
86
|
|
|
75
|
-
|
|
87
|
+
// While the columns are sized, a percentage in a cell's padding is of
|
|
88
|
+
// nothing: the width it is of is the one the columns are being sized to
|
|
89
|
+
// come to (CSS Sizing 3, 5.2.1), and a cell asks of its column what its
|
|
90
|
+
// content does. It is a share of the row once the columns have their
|
|
91
|
+
// widths, below. Taken of the table's width here, and of the cell's own
|
|
92
|
+
// where the cell was laid out, a padded cell's column was wider than
|
|
93
|
+
// its share and its padding narrower.
|
|
94
|
+
for (const cell of cells) resolveEdges(cell.box, 0);
|
|
76
95
|
|
|
77
96
|
// a fixed layout needs a width to be fixed to; with `auto` a table is laid
|
|
78
|
-
// out by its contents after all (CSS 2.1 17.5.2.1)
|
|
79
|
-
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;
|
|
80
99
|
// a percentage of the table's width less its spacing (CSS 2.1 17.5.2.1)
|
|
81
100
|
const set = columnWidths(columnBoxes, columnGroups, available);
|
|
82
101
|
const widths = fixed
|
|
@@ -88,14 +107,14 @@ export function layoutTable(
|
|
|
88
107
|
available,
|
|
89
108
|
ctx,
|
|
90
109
|
contentWidth,
|
|
91
|
-
|
|
110
|
+
!auto,
|
|
92
111
|
spacing,
|
|
93
112
|
);
|
|
94
113
|
|
|
95
114
|
// --- place ---------------------------------------------------------------
|
|
96
115
|
// An auto table is at least as wide as its widest caption can be (CSS 2.1
|
|
97
116
|
// 17.5.2), and as its `min-width` asks; the columns share what that adds.
|
|
98
|
-
if (
|
|
117
|
+
if (auto) {
|
|
99
118
|
let room = 0;
|
|
100
119
|
if (captions.length) {
|
|
101
120
|
room = captionMinimum(captions, ctx) - table.horizontalExtra - gaps;
|
|
@@ -145,7 +164,7 @@ export function layoutTable(
|
|
|
145
164
|
// gives its room back either way, set width or not.
|
|
146
165
|
const used = x - table.contentX;
|
|
147
166
|
let tableContentWidth = contentWidth;
|
|
148
|
-
if (
|
|
167
|
+
if (auto) {
|
|
149
168
|
tableContentWidth = used;
|
|
150
169
|
table.width = tableContentWidth + table.horizontalExtra;
|
|
151
170
|
} else if (used > contentWidth || anyGone) {
|
|
@@ -164,11 +183,21 @@ export function layoutTable(
|
|
|
164
183
|
// tallest cell in it rather than the first one that was measured. What
|
|
165
184
|
// its content came to is kept apart from a height the cell sets: it is
|
|
166
185
|
// that content `vertical-align` moves in the cell.
|
|
186
|
+
//
|
|
187
|
+
// A percentage in a cell's padding is of the width of its row: the
|
|
188
|
+
// columns and the spacing between them, without the spacing either side
|
|
189
|
+
// and the table's own padding. CSS 2.1 8.4 has it of the containing
|
|
190
|
+
// block's width and names none for a cell; the row's is what browsers
|
|
191
|
+
// take, and what the table's content box is wherever there is no
|
|
192
|
+
// spacing. Every column counts, one `visibility: collapse` takes out
|
|
193
|
+
// too, so that taking it out changes no row's height.
|
|
194
|
+
let rowWidth = spacing * Math.max(0, columnCount - 1);
|
|
195
|
+
for (const columnWidth of widths) rowWidth += columnWidth;
|
|
167
196
|
const natural: number[] = new Array<number>(cells.length);
|
|
168
197
|
for (let i = 0; i < cells.length; i += 1) {
|
|
169
198
|
const cell = cells[i];
|
|
170
199
|
const width = spannedWidth(widths, cell, spacing);
|
|
171
|
-
ctx.layoutSubtree(cell.box, width);
|
|
200
|
+
ctx.layoutSubtree(cell.box, width, rowWidth);
|
|
172
201
|
natural[i] = CELL_CONTENT.get(cell.box) ?? cell.box.height;
|
|
173
202
|
// A height a cell sets is a least one: its content is laid out as a
|
|
174
203
|
// block's, which keeps a height it sets and lets the content run out of
|
|
@@ -187,15 +216,21 @@ export function layoutTable(
|
|
|
187
216
|
// A cell aligned on the baseline — every value but `top`, `middle` and
|
|
188
217
|
// `bottom` — hangs its first line on its first row's baseline, the lowest
|
|
189
218
|
// of theirs from the row's top (CSS 2.1 17.5.3), and the row is as tall as
|
|
190
|
-
// the cells hung from it need.
|
|
191
|
-
|
|
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]);
|
|
192
230
|
for (let i = 0; i < cells.length; i += 1) {
|
|
193
231
|
const cell = cells[i];
|
|
194
232
|
if (cell.rowSpan > 1) continue;
|
|
195
|
-
rowHeight[cell.row] = Math.max(
|
|
196
|
-
rowHeight[cell.row],
|
|
197
|
-
lift[i] + cell.box.height,
|
|
198
|
-
);
|
|
233
|
+
rowHeight[cell.row] = Math.max(rowHeight[cell.row], needs(i));
|
|
199
234
|
}
|
|
200
235
|
for (let r = 0; r < rows.length; r += 1) {
|
|
201
236
|
const specified = resolveOrNull(rows[r].style.height, NaN);
|
|
@@ -211,14 +246,20 @@ export function layoutTable(
|
|
|
211
246
|
let covered = 0;
|
|
212
247
|
for (let r = cell.row; r <= last; r += 1) covered += rowHeight[r];
|
|
213
248
|
covered += rowSpacing * (last - cell.row);
|
|
214
|
-
const missing =
|
|
249
|
+
const missing = needs(i) - covered;
|
|
215
250
|
if (missing > 0) rowHeight[last] += missing;
|
|
216
251
|
}
|
|
217
252
|
|
|
218
253
|
// A table's own height, within its least and greatest, is a least
|
|
219
254
|
// height: what its rows come short of it goes to them (CSS 2.1 17.5.3,
|
|
220
|
-
// 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.
|
|
221
261
|
const wanted = resolveOrNull(style.height, table.percentHeightBase);
|
|
262
|
+
const given = FLEXED_HEIGHT.get(table) ?? USED_HEIGHT.get(table) ?? NaN;
|
|
222
263
|
if (rows.length) {
|
|
223
264
|
const extraBox = table.verticalExtra;
|
|
224
265
|
const set =
|
|
@@ -227,7 +268,10 @@ export function layoutTable(
|
|
|
227
268
|
: style.boxSizing === 'border-box'
|
|
228
269
|
? wanted
|
|
229
270
|
: wanted + extraBox;
|
|
230
|
-
|
|
271
|
+
let inner = clampHeight(table, set) - extraBox;
|
|
272
|
+
if (Number.isFinite(given)) {
|
|
273
|
+
inner = Math.max(inner, given - table.captionTop - table.captionBottom);
|
|
274
|
+
}
|
|
231
275
|
let total = 0;
|
|
232
276
|
for (const h of rowHeight) total += h;
|
|
233
277
|
const extra = inner - total - rowSpacing * (rows.length + 1);
|
|
@@ -303,7 +347,9 @@ export function layoutTable(
|
|
|
303
347
|
// `vertical-align` inside a cell moves the *content*, not the box: the
|
|
304
348
|
// box fills the row, background and all, and the content sits top,
|
|
305
349
|
// middle, bottom or on the row's baseline in it — in the box a height
|
|
306
|
-
// of its own makes too, which is no content to be moved
|
|
350
|
+
// of its own makes too, which is no content to be moved. The cell was
|
|
351
|
+
// laid out above, in this pass over the cells, so this is the one move
|
|
352
|
+
// its content and its static positions get (`moveContent`)
|
|
307
353
|
let offset = lift[i];
|
|
308
354
|
const va = cell.box.style.verticalAlign;
|
|
309
355
|
const content = natural[i];
|
|
@@ -462,7 +508,7 @@ function fixedColumns(
|
|
|
462
508
|
}
|
|
463
509
|
for (const cell of cells) {
|
|
464
510
|
if (cell.row > 0) break;
|
|
465
|
-
const px =
|
|
511
|
+
const px = ownWidth(cell.box.style, available);
|
|
466
512
|
if (px === null) continue;
|
|
467
513
|
const box = cell.box;
|
|
468
514
|
const outer =
|
|
@@ -706,14 +752,14 @@ function columnWidths(
|
|
|
706
752
|
}
|
|
707
753
|
|
|
708
754
|
/** A column's or a column group's width, within its limits, or null where
|
|
709
|
-
* it sets none.
|
|
755
|
+
* it sets none. The limits are lengths: a percentage in them does what it
|
|
756
|
+
* does in a cell's (`cellWidth`). */
|
|
710
757
|
function partWidth(box: Box, base: number): number | null {
|
|
711
758
|
const style = box.style;
|
|
712
|
-
const width =
|
|
713
|
-
const min =
|
|
759
|
+
const width = ownWidth(style, base);
|
|
760
|
+
const min = typeof style.minWidth === 'number' ? style.minWidth : 0;
|
|
714
761
|
if (width === null && !(min > 0)) return null;
|
|
715
|
-
const max =
|
|
716
|
-
style.maxWidth === 'none' ? null : lengthAgainst(style.maxWidth, base);
|
|
762
|
+
const max = typeof style.maxWidth === 'number' ? style.maxWidth : null;
|
|
717
763
|
let out = width ?? 0;
|
|
718
764
|
if (max !== null) out = Math.min(out, max);
|
|
719
765
|
return Math.max(0, out, min);
|
|
@@ -726,15 +772,20 @@ function partWidth(box: Box, base: number): number | null {
|
|
|
726
772
|
* `min-width` and `max-width` as a column's is (`partWidth`), which CSS
|
|
727
773
|
* 2.1 leaves undefined and every browser does: a cell set `width: 3in;
|
|
728
774
|
* max-width: 1in` is an inch wide, and one with `min-width` alone is as
|
|
729
|
-
* wide as that.
|
|
775
|
+
* wide as that.
|
|
776
|
+
*
|
|
777
|
+
* Where they are lengths. A percentage `min-width` is ignored, and a
|
|
778
|
+
* percentage `max-width` holds a percentage `width` and nothing else
|
|
779
|
+
* (CSS Tables 3, 3.8.2, and `ownWidth`): a cell `width: 100px;
|
|
780
|
+
* max-width: 10%` in a table of 600 is 100 wide, where it was 60, and
|
|
781
|
+
* one set `min-width: 150%` takes no more than its content asks. */
|
|
730
782
|
function cellWidth(cell: Cell, base: number): number | null {
|
|
731
783
|
const style = cell.box.style;
|
|
732
784
|
const len = style.width;
|
|
733
|
-
const width =
|
|
734
|
-
const min =
|
|
785
|
+
const width = ownWidth(style, base);
|
|
786
|
+
const min = typeof style.minWidth === 'number' ? style.minWidth : 0;
|
|
735
787
|
if (width === null && !(min > 0)) return null;
|
|
736
|
-
const max =
|
|
737
|
-
style.maxWidth === 'none' ? null : lengthAgainst(style.maxWidth, base);
|
|
788
|
+
const max = typeof style.maxWidth === 'number' ? style.maxWidth : null;
|
|
738
789
|
let own = width ?? 0;
|
|
739
790
|
if (max !== null) own = Math.min(own, max);
|
|
740
791
|
own = Math.max(0, own, min);
|
|
@@ -744,6 +795,19 @@ function cellWidth(cell: Cell, base: number): number | null {
|
|
|
744
795
|
return own + cell.box.horizontalExtra;
|
|
745
796
|
}
|
|
746
797
|
|
|
798
|
+
/** A cell's, a column's or a column group's `width` as the columns read
|
|
799
|
+
* it, or null: a percentage no more than a percentage its `max-width` is
|
|
800
|
+
* — the percentage each contributes is `min(percentage width, percentage
|
|
801
|
+
* max-width)`, a `max-width` that is no percentage counting as an
|
|
802
|
+
* infinite one (CSS Tables 3, 3.8.2). */
|
|
803
|
+
function ownWidth(style: ComputedStyle, base: number): number | null {
|
|
804
|
+
const width = tableWidth(style.width, base);
|
|
805
|
+
const limit = style.maxWidth;
|
|
806
|
+
if (width === null || !isPct(style.width)) return width;
|
|
807
|
+
if (limit === 'none' || !isPct(limit) || limit.px || limit.of) return width;
|
|
808
|
+
return Math.min(width, lengthAgainst(limit, base) ?? width);
|
|
809
|
+
}
|
|
810
|
+
|
|
747
811
|
/** A cell's or a column's width. One that adds a percentage to a length,
|
|
748
812
|
* a `calc()`, is `auto` in a table, as browsers read it: a column cannot be
|
|
749
813
|
* both a share of the table and a size of its own. */
|
|
@@ -762,12 +826,18 @@ function lengthAgainst(len: Len, base: number): number | null {
|
|
|
762
826
|
* row's: 0 for a cell aligned `top`, `middle` or `bottom`, which is placed
|
|
763
827
|
* once the row's height is known. A cell's baseline is its first line box's,
|
|
764
828
|
* at any depth, or the bottom of its content where it has none (CSS 2.1
|
|
765
|
-
* 17.5.3); it is taken as laid out, from the cell's top.
|
|
766
|
-
*
|
|
767
|
-
*
|
|
768
|
-
*
|
|
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.
|
|
769
835
|
*/
|
|
770
|
-
function baselineLifts(
|
|
836
|
+
function baselineLifts(
|
|
837
|
+
cells: Cell[],
|
|
838
|
+
rowCount: number,
|
|
839
|
+
natural: number[],
|
|
840
|
+
): number[] {
|
|
771
841
|
const lift = new Array<number>(cells.length).fill(0);
|
|
772
842
|
let any = false;
|
|
773
843
|
for (const cell of cells) {
|
|
@@ -786,7 +856,7 @@ function baselineLifts(cells: Cell[], rowCount: number): number[] {
|
|
|
786
856
|
own[i] =
|
|
787
857
|
first !== null
|
|
788
858
|
? first - box.y
|
|
789
|
-
:
|
|
859
|
+
: natural[i] - box.padBottom - box.borderBottom;
|
|
790
860
|
row[cells[i].row] = Math.max(row[cells[i].row], own[i]);
|
|
791
861
|
}
|
|
792
862
|
for (let i = 0; i < cells.length; i += 1) {
|