@react-x11/components 0.11.0 → 0.13.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/flow/node.d.ts +14 -6
- package/dist/flow/node.d.ts.map +1 -1
- package/dist/flow/node.js +82 -64
- package/dist/flow/node.js.map +1 -1
- package/dist/html/controls.d.ts +38 -10
- package/dist/html/controls.d.ts.map +1 -1
- package/dist/html/controls.js +43 -58
- 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 +538 -128
- package/dist/html/css/cascade.js.map +1 -1
- package/dist/html/css/color.d.ts +19 -0
- package/dist/html/css/color.d.ts.map +1 -1
- package/dist/html/css/color.js +86 -0
- package/dist/html/css/color.js.map +1 -1
- package/dist/html/css/parse.d.ts +40 -2
- package/dist/html/css/parse.d.ts.map +1 -1
- package/dist/html/css/parse.js +391 -13
- package/dist/html/css/parse.js.map +1 -1
- package/dist/html/css/style.d.ts +52 -1
- package/dist/html/css/style.d.ts.map +1 -1
- package/dist/html/css/style.js +328 -11
- package/dist/html/css/style.js.map +1 -1
- 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 -7
- package/dist/html/css/ua.js.map +1 -1
- package/dist/html/css/values.d.ts +10 -1
- package/dist/html/css/values.d.ts.map +1 -1
- package/dist/html/css/values.js +27 -2
- package/dist/html/css/values.js.map +1 -1
- package/dist/html/css/vars.d.ts +5 -0
- package/dist/html/css/vars.d.ts.map +1 -1
- package/dist/html/css/vars.js +2 -2
- package/dist/html/css/vars.js.map +1 -1
- package/dist/html/dom.d.ts.map +1 -1
- package/dist/html/dom.js +38 -3
- package/dist/html/dom.js.map +1 -1
- package/dist/html/fonts.d.ts +25 -1
- package/dist/html/fonts.d.ts.map +1 -1
- package/dist/html/fonts.js +99 -6
- 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 -264
- package/dist/html/index.js.map +1 -1
- package/dist/html/layout/block.d.ts +11 -2
- package/dist/html/layout/block.d.ts.map +1 -1
- package/dist/html/layout/block.js +186 -19
- package/dist/html/layout/block.js.map +1 -1
- package/dist/html/layout/boxes.d.ts +65 -7
- package/dist/html/layout/boxes.d.ts.map +1 -1
- package/dist/html/layout/boxes.js +87 -22
- package/dist/html/layout/boxes.js.map +1 -1
- package/dist/html/layout/cache.d.ts +2 -2
- package/dist/html/layout/cache.d.ts.map +1 -1
- package/dist/html/layout/cache.js +8 -3
- package/dist/html/layout/cache.js.map +1 -1
- package/dist/html/layout/flex.js +4 -1
- package/dist/html/layout/flex.js.map +1 -1
- package/dist/html/layout/floats.d.ts +4 -0
- package/dist/html/layout/floats.d.ts.map +1 -1
- package/dist/html/layout/floats.js +26 -0
- package/dist/html/layout/floats.js.map +1 -1
- package/dist/html/layout/inline.d.ts +26 -2
- package/dist/html/layout/inline.d.ts.map +1 -1
- package/dist/html/layout/inline.js +1232 -115
- package/dist/html/layout/inline.js.map +1 -1
- package/dist/html/node.d.ts +120 -15
- package/dist/html/node.d.ts.map +1 -1
- package/dist/html/node.js +993 -174
- package/dist/html/node.js.map +1 -1
- package/dist/html/paint.d.ts +75 -2
- package/dist/html/paint.d.ts.map +1 -1
- package/dist/html/paint.js +836 -200
- package/dist/html/paint.js.map +1 -1
- package/dist/html/surfaces.d.ts +7 -2
- package/dist/html/surfaces.d.ts.map +1 -1
- package/dist/html/surfaces.js +16 -0
- package/dist/html/surfaces.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 +620 -0
- package/dist/html/widgets.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/internal/window.d.ts +22 -0
- package/dist/internal/window.d.ts.map +1 -1
- package/dist/internal/window.js +35 -8
- package/dist/internal/window.js.map +1 -1
- package/dist/richtext/node.d.ts +7 -0
- package/dist/richtext/node.d.ts.map +1 -1
- package/dist/richtext/node.js.map +1 -1
- package/package.json +6 -4
- package/src/flow/node.ts +80 -64
- package/src/html/controls.ts +79 -58
- package/src/html/css/cascade.ts +610 -146
- package/src/html/css/color.ts +87 -0
- package/src/html/css/parse.ts +431 -13
- package/src/html/css/style.ts +367 -11
- package/src/html/css/ua.ts +76 -8
- package/src/html/css/values.ts +31 -3
- package/src/html/css/vars.ts +2 -2
- package/src/html/dom.ts +41 -3
- package/src/html/fonts.ts +116 -6
- package/src/html/form.ts +962 -0
- package/src/html/index.ts +49 -300
- package/src/html/layout/block.ts +231 -16
- package/src/html/layout/boxes.ts +133 -32
- package/src/html/layout/cache.ts +8 -3
- package/src/html/layout/flex.ts +4 -1
- package/src/html/layout/floats.ts +24 -0
- package/src/html/layout/inline.ts +1445 -108
- package/src/html/node.ts +1010 -166
- package/src/html/paint.ts +980 -270
- package/src/html/surfaces.ts +21 -1
- package/src/html/widgets.ts +735 -0
- package/src/index.ts +1 -0
- package/src/internal/window.ts +36 -8
- package/src/richtext/node.ts +7 -0
package/src/html/controls.ts
CHANGED
|
@@ -22,9 +22,15 @@
|
|
|
22
22
|
import type { Element } from 'domhandler';
|
|
23
23
|
|
|
24
24
|
import { attr, tagOf } from './dom.js';
|
|
25
|
+
import {
|
|
26
|
+
optionElements,
|
|
27
|
+
optionLabel,
|
|
28
|
+
optionValue,
|
|
29
|
+
selectedOptions,
|
|
30
|
+
} from './form.js';
|
|
25
31
|
import type { ComputedStyle } from './css/style.js';
|
|
26
32
|
import { isTransparent } from './css/values.js';
|
|
27
|
-
import type { BoxTree, ReplacedKind } from './layout/boxes.js';
|
|
33
|
+
import type { Box, BoxTree, ReplacedKind } from './layout/boxes.js';
|
|
28
34
|
import type { FontsLike } from './layout/inline.js';
|
|
29
35
|
|
|
30
36
|
/** The palette numbers a control's box has to reserve room for. */
|
|
@@ -48,23 +54,48 @@ export interface ControlRect {
|
|
|
48
54
|
width: number;
|
|
49
55
|
height: number;
|
|
50
56
|
/**
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
57
|
+
* The element's computed face and size: what `measureControl` measured
|
|
58
|
+
* its box in, and so what the widget sets its text in. The palette's,
|
|
59
|
+
* from the UA sheet, unless the page set its own — `font: inherit`, which
|
|
60
|
+
* a CSS reset gives every control, for one.
|
|
61
|
+
*/
|
|
62
|
+
fontFamily: string;
|
|
63
|
+
fontSize: number;
|
|
64
|
+
/**
|
|
65
|
+
* Set on a text field or a `<select>` whose own box the author styled —
|
|
66
|
+
* gave it a border or a background (`styledField`). The document draws
|
|
67
|
+
* that box, and the widget goes bare inside its content box, here, with
|
|
68
|
+
* no frame or fill of its own and its text in the element's colour and
|
|
69
|
+
* font.
|
|
55
70
|
*/
|
|
56
71
|
bare?: BareField;
|
|
72
|
+
/**
|
|
73
|
+
* How opaque the widget is drawn, where it is less than 1: the element's
|
|
74
|
+
* own `opacity` times every ancestor's, since each fades what is in it as
|
|
75
|
+
* a group. At 0 the widget is not seen and still takes a press, as the
|
|
76
|
+
* element does in a browser — the checkbox a CSS-only dropdown lays,
|
|
77
|
+
* invisible, over its label.
|
|
78
|
+
*/
|
|
79
|
+
opacity?: number;
|
|
57
80
|
}
|
|
58
81
|
|
|
59
|
-
/** Where a styled
|
|
82
|
+
/** Where a styled field's widget goes, and how its text looks. */
|
|
60
83
|
export interface BareField {
|
|
61
84
|
x: number;
|
|
62
85
|
y: number;
|
|
63
86
|
width: number;
|
|
64
87
|
height: number;
|
|
65
88
|
color: string;
|
|
89
|
+
/** @deprecated The rect's own `fontFamily`, which every rect carries. */
|
|
66
90
|
fontFamily: string;
|
|
91
|
+
/** @deprecated The rect's own `fontSize`, which every rect carries. */
|
|
67
92
|
fontSize: number;
|
|
93
|
+
/**
|
|
94
|
+
* A `<select>`'s: whether it draws its arrow. It does unless the page set
|
|
95
|
+
* `appearance: none`, which is how a page that draws its own arrow — as a
|
|
96
|
+
* background image, most often — says so.
|
|
97
|
+
*/
|
|
98
|
+
chevron?: boolean;
|
|
68
99
|
}
|
|
69
100
|
|
|
70
101
|
/** The rectangles every control in a laid-out document landed on. */
|
|
@@ -73,6 +104,8 @@ export function controlRectsOf(tree: BoxTree): ControlRect[] {
|
|
|
73
104
|
for (const box of tree.controls) {
|
|
74
105
|
if (!box.el) continue;
|
|
75
106
|
if (box.width <= 0 || box.height <= 0) continue;
|
|
107
|
+
// a hidden element draws nothing and takes no press (CSS 2.1 11.2)
|
|
108
|
+
if (box.style.visibility !== 'visible') continue;
|
|
76
109
|
const rect: ControlRect = {
|
|
77
110
|
element: box.el,
|
|
78
111
|
kind: box.replaced,
|
|
@@ -80,7 +113,14 @@ export function controlRectsOf(tree: BoxTree): ControlRect[] {
|
|
|
80
113
|
y: box.y,
|
|
81
114
|
width: box.width,
|
|
82
115
|
height: box.height,
|
|
116
|
+
fontFamily: box.style.fontFamily,
|
|
117
|
+
fontSize: box.style.fontSize,
|
|
83
118
|
};
|
|
119
|
+
let opacity = 1;
|
|
120
|
+
for (let at: Box | null = box; at; at = at.parent) {
|
|
121
|
+
opacity *= at.style.opacity;
|
|
122
|
+
}
|
|
123
|
+
if (opacity < 1) rect.opacity = Math.max(0, opacity);
|
|
84
124
|
if (styledField(box.replaced, box.style)) {
|
|
85
125
|
rect.bare = {
|
|
86
126
|
x: box.contentX,
|
|
@@ -90,6 +130,9 @@ export function controlRectsOf(tree: BoxTree): ControlRect[] {
|
|
|
90
130
|
color: box.style.color,
|
|
91
131
|
fontFamily: box.style.fontFamily,
|
|
92
132
|
fontSize: box.style.fontSize,
|
|
133
|
+
...(box.replaced === 'select' && {
|
|
134
|
+
chevron: box.style.appearance !== 'none',
|
|
135
|
+
}),
|
|
93
136
|
};
|
|
94
137
|
}
|
|
95
138
|
out.push(rect);
|
|
@@ -98,17 +141,23 @@ export function controlRectsOf(tree: BoxTree): ControlRect[] {
|
|
|
98
141
|
}
|
|
99
142
|
|
|
100
143
|
/**
|
|
101
|
-
* Whether a
|
|
102
|
-
*
|
|
144
|
+
* Whether a field's box is the author's to draw: one given a border or a
|
|
145
|
+
* background of its own, which the UA sheet gives no control, or set to
|
|
103
146
|
* `appearance: none`, which says so outright. A browser drops a field's
|
|
104
147
|
* native look for the author's then (CSS UI 4 7.1, `appearance`), and so
|
|
105
148
|
* does this: the widget's frame and fill would hide the author's, and what
|
|
106
149
|
* they would draw is the theme's rather than the page's. `appearance: none`
|
|
107
150
|
* is how a design system writes every field it has — meetup.com's search
|
|
108
151
|
* pill holds two with no background, only one of them with a border.
|
|
152
|
+
*
|
|
153
|
+
* A `<select>` is one too. A browser keeps its arrow when the page gave it a
|
|
154
|
+
* border or a background (Blink's `menulist-button`), and leaves that out
|
|
155
|
+
* as well at `appearance: none` — `BareField.chevron`.
|
|
109
156
|
*/
|
|
110
157
|
export function styledField(kind: ReplacedKind, style: ComputedStyle): boolean {
|
|
111
|
-
if (kind !== 'input' && kind !== 'textarea')
|
|
158
|
+
if (kind !== 'input' && kind !== 'textarea' && kind !== 'select') {
|
|
159
|
+
return false;
|
|
160
|
+
}
|
|
112
161
|
return (
|
|
113
162
|
style.appearance === 'none' ||
|
|
114
163
|
!isTransparent(style.backgroundColor) ||
|
|
@@ -168,6 +217,16 @@ export function measureControl(
|
|
|
168
217
|
}
|
|
169
218
|
case 'select': {
|
|
170
219
|
const widest = optionWidths(el);
|
|
220
|
+
// a select the page styled is its widest option and its arrow, and
|
|
221
|
+
// the room around them is the page's
|
|
222
|
+
if (styledField(kind, style)) {
|
|
223
|
+
return {
|
|
224
|
+
width: Math.round(
|
|
225
|
+
ch * widest + (style.appearance === 'none' ? 0 : em),
|
|
226
|
+
),
|
|
227
|
+
height: lineHeight,
|
|
228
|
+
};
|
|
229
|
+
}
|
|
171
230
|
// The room for the chevron is the widget's, not the document's, but
|
|
172
231
|
// the document has to reserve it or the last letter of the widest
|
|
173
232
|
// option sits under it.
|
|
@@ -220,9 +279,11 @@ export function buttonLabel(el: Element): string {
|
|
|
220
279
|
const trimmed = text.trim();
|
|
221
280
|
if (trimmed) return trimmed;
|
|
222
281
|
}
|
|
282
|
+
const type = (attr(el, 'type') ?? '').trim().toLowerCase();
|
|
283
|
+
// an image button with no image yet says what the image would have
|
|
284
|
+
if (type === 'image') return attr(el, 'alt') || attr(el, 'value') || 'Submit';
|
|
223
285
|
const value = attr(el, 'value');
|
|
224
286
|
if (value) return value;
|
|
225
|
-
const type = (attr(el, 'type') ?? '').toLowerCase();
|
|
226
287
|
if (type === 'submit') return 'Submit';
|
|
227
288
|
if (type === 'reset') return 'Reset';
|
|
228
289
|
return attr(el, 'alt') ?? 'Button';
|
|
@@ -230,57 +291,17 @@ export function buttonLabel(el: Element): string {
|
|
|
230
291
|
|
|
231
292
|
/** A `<select>`'s options, as the widget's item list. */
|
|
232
293
|
export function optionsOf(el: Element): { value: string; label: string }[] {
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
const tag = tagOf(child);
|
|
238
|
-
if (tag === 'option') {
|
|
239
|
-
let label = '';
|
|
240
|
-
for (const kid of child.children) {
|
|
241
|
-
if (kid.type === 'text') label += kid.data;
|
|
242
|
-
}
|
|
243
|
-
const trimmed = label.trim();
|
|
244
|
-
out.push({ value: attr(child, 'value') ?? trimmed, label: trimmed });
|
|
245
|
-
} else if (tag === 'optgroup') {
|
|
246
|
-
walk(child);
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
};
|
|
250
|
-
walk(el);
|
|
251
|
-
return out;
|
|
294
|
+
return optionElements(el).map((option) => ({
|
|
295
|
+
value: optionValue(option),
|
|
296
|
+
label: optionLabel(option),
|
|
297
|
+
}));
|
|
252
298
|
}
|
|
253
299
|
|
|
254
|
-
/** Which option a `<select>`
|
|
300
|
+
/** Which option a `<select>` shows: the one it has selected, which is the
|
|
301
|
+
* first where none is marked (`selectedOptions`). */
|
|
255
302
|
export function selectedOption(el: Element): string | null {
|
|
256
|
-
const
|
|
257
|
-
|
|
258
|
-
for (const child of node.children) {
|
|
259
|
-
if (child.type !== 'tag') continue;
|
|
260
|
-
if (tagOf(child) === 'option' && attr(child, 'selected') !== undefined) {
|
|
261
|
-
let label = '';
|
|
262
|
-
for (const kid of child.children) {
|
|
263
|
-
if (kid.type === 'text') label += kid.data;
|
|
264
|
-
}
|
|
265
|
-
return attr(child, 'value') ?? label.trim();
|
|
266
|
-
}
|
|
267
|
-
const nested = walk(child);
|
|
268
|
-
if (nested !== null) return nested;
|
|
269
|
-
}
|
|
270
|
-
return null;
|
|
271
|
-
};
|
|
272
|
-
return walk(el) ?? options[0]?.value ?? null;
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
/** A `<textarea>`'s initial text — its content, not an attribute. */
|
|
276
|
-
export function textareaValue(el: Element): string {
|
|
277
|
-
let text = '';
|
|
278
|
-
for (const child of el.children) {
|
|
279
|
-
if (child.type === 'text') text += child.data;
|
|
280
|
-
}
|
|
281
|
-
// HTML drops one leading newline after the open tag, which is why a
|
|
282
|
-
// pretty-printed `<textarea>` does not start with a blank line.
|
|
283
|
-
return text.replace(/^\r?\n/, '');
|
|
303
|
+
const [option] = selectedOptions(el);
|
|
304
|
+
return option ? optionValue(option) : null;
|
|
284
305
|
}
|
|
285
306
|
|
|
286
307
|
function numberAttr(el: Element, name: string): number | null {
|