@react-x11/components 0.12.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/html/controls.d.ts +12 -3
- package/dist/html/controls.d.ts.map +1 -1
- package/dist/html/controls.js +15 -55
- 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 +519 -122
- package/dist/html/css/cascade.js.map +1 -1
- package/dist/html/css/parse.d.ts +29 -2
- package/dist/html/css/parse.d.ts.map +1 -1
- package/dist/html/css/parse.js +277 -9
- package/dist/html/css/parse.js.map +1 -1
- package/dist/html/css/style.d.ts +14 -0
- package/dist/html/css/style.d.ts.map +1 -1
- package/dist/html/css/style.js +2 -3
- 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 +59 -7
- package/dist/html/css/ua.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 +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 -301
- package/dist/html/index.js.map +1 -1
- package/dist/html/layout/block.d.ts.map +1 -1
- package/dist/html/layout/block.js +5 -1
- package/dist/html/layout/block.js.map +1 -1
- package/dist/html/layout/boxes.d.ts +31 -1
- package/dist/html/layout/boxes.d.ts.map +1 -1
- package/dist/html/layout/boxes.js +52 -8
- package/dist/html/layout/boxes.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/inline.d.ts.map +1 -1
- package/dist/html/layout/inline.js +10 -0
- package/dist/html/layout/inline.js.map +1 -1
- package/dist/html/node.d.ts +87 -15
- package/dist/html/node.d.ts.map +1 -1
- package/dist/html/node.js +510 -152
- package/dist/html/node.js.map +1 -1
- package/dist/html/paint.d.ts +22 -1
- package/dist/html/paint.d.ts.map +1 -1
- package/dist/html/paint.js +290 -20
- package/dist/html/paint.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/package.json +2 -2
- package/src/html/controls.ts +29 -49
- package/src/html/css/cascade.ts +591 -140
- package/src/html/css/parse.ts +324 -9
- package/src/html/css/style.ts +24 -3
- package/src/html/css/ua.ts +62 -8
- package/src/html/dom.ts +3 -1
- package/src/html/fonts.ts +116 -6
- package/src/html/form.ts +962 -0
- package/src/html/index.ts +49 -338
- package/src/html/layout/block.ts +3 -0
- package/src/html/layout/boxes.ts +78 -11
- package/src/html/layout/flex.ts +4 -1
- package/src/html/layout/inline.ts +10 -0
- package/src/html/node.ts +498 -135
- package/src/html/paint.ts +330 -29
- package/src/html/widgets.ts +735 -0
- package/src/index.ts +1 -0
package/src/html/fonts.ts
CHANGED
|
@@ -35,6 +35,18 @@
|
|
|
35
35
|
// keyed by a family list, the text layouts', the metrics', ntk's, that the
|
|
36
36
|
// text has to be set again.
|
|
37
37
|
//
|
|
38
|
+
// **A face the text engine cannot set is not registered.** A face is drawn by
|
|
39
|
+
// the engine, and an engine can read a file it cannot draw every weight of:
|
|
40
|
+
// ntk cuts an instance out of a variable face for the weight and the size a
|
|
41
|
+
// style asks for, and fontkit, which does the cutting, could not cut one out
|
|
42
|
+
// of a WOFF2 — the container nearly every variable web font is served in.
|
|
43
|
+
// The throw came out of the first text layout in the family, and the
|
|
44
|
+
// document it took down was nextjs.org's blog, for Geist. So a face is asked
|
|
45
|
+
// for an instance once, before it is registered (`refusal`), and one the
|
|
46
|
+
// engine refuses is a source that did not load: the next is tried, and with
|
|
47
|
+
// none left the family stays out of the list and the text is set in the
|
|
48
|
+
// next one, as a browser sets it when it cannot use a font.
|
|
49
|
+
//
|
|
38
50
|
// A family split by `unicode-range` is registered a name per range, since the
|
|
39
51
|
// font manager picks among one name's faces by weight and slant alone, and
|
|
40
52
|
// the range that holds the most of the document's characters goes first: the
|
|
@@ -46,7 +58,7 @@
|
|
|
46
58
|
// anywhere in the app (react-x11's `loadFont` says so), and nothing is ever
|
|
47
59
|
// unregistered — the font manager has no way to. A session that visits many
|
|
48
60
|
// sites keeps their faces, one registration per distinct declaration.
|
|
49
|
-
import { loadFont } from 'react-x11';
|
|
61
|
+
import { loadFont, openFont } from 'react-x11';
|
|
50
62
|
import type { Element } from 'domhandler';
|
|
51
63
|
|
|
52
64
|
import type { FontFaceRule } from './css/parse.js';
|
|
@@ -126,6 +138,8 @@ interface Registry {
|
|
|
126
138
|
/** Faces being loaded, by `faceKey`, so a second document waits for the
|
|
127
139
|
* first document's request rather than making its own. */
|
|
128
140
|
pending: Map<string, Promise<boolean>>;
|
|
141
|
+
/** Whether a face the engine refused has been said (`warnRefused`). */
|
|
142
|
+
warned: boolean;
|
|
129
143
|
}
|
|
130
144
|
|
|
131
145
|
const REGISTRIES = new WeakMap<object, Registry>();
|
|
@@ -138,6 +152,7 @@ function registryOf(app: object): Registry {
|
|
|
138
152
|
names: new Map(),
|
|
139
153
|
ready: new Set(),
|
|
140
154
|
pending: new Map(),
|
|
155
|
+
warned: false,
|
|
141
156
|
};
|
|
142
157
|
REGISTRIES.set(app, registry);
|
|
143
158
|
}
|
|
@@ -493,12 +508,12 @@ export class WebFonts implements FontFamilies {
|
|
|
493
508
|
}
|
|
494
509
|
if (isPromise(answer)) {
|
|
495
510
|
answer.then(
|
|
496
|
-
(result) => after(this._register(face, result)),
|
|
511
|
+
(result) => after(this._register(face, result, source.url)),
|
|
497
512
|
() => after(false),
|
|
498
513
|
);
|
|
499
514
|
return 'waiting';
|
|
500
515
|
}
|
|
501
|
-
if (this._register(face, answer)) {
|
|
516
|
+
if (this._register(face, answer, source.url)) {
|
|
502
517
|
finish(true);
|
|
503
518
|
if (sync) face.state = 'ready';
|
|
504
519
|
else this._settled(face, true);
|
|
@@ -529,12 +544,24 @@ export class WebFonts implements FontFamilies {
|
|
|
529
544
|
/** Register a face's bytes under its group's name. False when the host
|
|
530
545
|
* declined, or the font manager could not read them — a `.woff2` on
|
|
531
546
|
* macOS, whose CoreText reads no such container, or a file that is not a
|
|
532
|
-
* font — and
|
|
533
|
-
|
|
547
|
+
* font — or read them and cannot set text in them (`refusal`), and the
|
|
548
|
+
* next source is tried. */
|
|
549
|
+
private _register(
|
|
550
|
+
face: Face,
|
|
551
|
+
result: ResourceResult | null,
|
|
552
|
+
url: string,
|
|
553
|
+
): boolean {
|
|
534
554
|
if (this._destroyed || !this._app || result?.kind !== 'font') return false;
|
|
535
555
|
const { weight, style } = face.rule;
|
|
556
|
+
const app = this._app as Parameters<typeof loadFont>[0];
|
|
536
557
|
try {
|
|
537
|
-
loadFont
|
|
558
|
+
// `loadFont` opens the file first too, and finds this one opened
|
|
559
|
+
const refused = refusal(app, openFont(app, result.bytes), this._fallback);
|
|
560
|
+
if (refused !== null) {
|
|
561
|
+
warnRefused(registryOf(this._app), url, refused);
|
|
562
|
+
return false;
|
|
563
|
+
}
|
|
564
|
+
loadFont(app, result.bytes, {
|
|
538
565
|
family: face.group.name,
|
|
539
566
|
// a range is registered at the weight nearest regular in it: the
|
|
540
567
|
// font manager picks among a group's faces by distance from one
|
|
@@ -560,6 +587,89 @@ export class WebFonts implements FontFamilies {
|
|
|
560
587
|
}
|
|
561
588
|
}
|
|
562
589
|
|
|
590
|
+
/** The slice of an opened face `refusal` reads: react-x11's `Font`. */
|
|
591
|
+
interface OpenedFace {
|
|
592
|
+
variationAxes?: Record<string, { min: number; default: number; max: number }>;
|
|
593
|
+
variation?(settings: Record<string, number>): unknown;
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
/** The axes a style moves without naming one: ntk sets `wght` from the
|
|
597
|
+
* weight and `opsz` from the size (its `docs/fonts.md`), and nothing here
|
|
598
|
+
* hands it a `font-variation-settings`. A face with neither is set as its
|
|
599
|
+
* file has it, whatever else varies in it. */
|
|
600
|
+
const DRIVEN_AXES = ['wght', 'opsz'];
|
|
601
|
+
|
|
602
|
+
/**
|
|
603
|
+
* Why the text engine cannot set text in an opened face, or null when it
|
|
604
|
+
* can: the face is asked for the instance a layout will ask it for, at the
|
|
605
|
+
* far end of each axis a style moves, and the answer is the engine's own.
|
|
606
|
+
* What it cost unasked was the document: ntk instantiates inside `match`,
|
|
607
|
+
* so the throw came out of the first layout in the family, at whatever
|
|
608
|
+
* weight was not the file's default.
|
|
609
|
+
*
|
|
610
|
+
* Only an engine that draws through the face is asked. CoreText and
|
|
611
|
+
* DirectWrite move an axis themselves, and the face react-x11 opens there
|
|
612
|
+
* is fontkit's, for an application to read: what it cannot do says nothing
|
|
613
|
+
* about what they draw.
|
|
614
|
+
*/
|
|
615
|
+
export function refusal(
|
|
616
|
+
app: object,
|
|
617
|
+
font: OpenedFace,
|
|
618
|
+
family: string,
|
|
619
|
+
): string | null {
|
|
620
|
+
const axes = font.variationAxes;
|
|
621
|
+
if (!axes || typeof font.variation !== 'function') return null;
|
|
622
|
+
const settings: Record<string, number> = {};
|
|
623
|
+
for (const tag of DRIVEN_AXES) {
|
|
624
|
+
const axis = axes[tag];
|
|
625
|
+
if (!axis) continue;
|
|
626
|
+
const far = axis.max !== axis.default ? axis.max : axis.min;
|
|
627
|
+
if (far !== axis.default) settings[tag] = far;
|
|
628
|
+
}
|
|
629
|
+
if (!Object.keys(settings).length) return null;
|
|
630
|
+
try {
|
|
631
|
+
font.variation(settings);
|
|
632
|
+
return null;
|
|
633
|
+
} catch (error) {
|
|
634
|
+
return instantiates(app, family)
|
|
635
|
+
? String((error as Error)?.message ?? error)
|
|
636
|
+
: null;
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
/** Whether the engine's faces are cut into instances as an opened one is:
|
|
641
|
+
* the face it matches a family with has `variation`, as ntk's has and a
|
|
642
|
+
* CoreText or DirectWrite one has not. An engine that cannot say — no
|
|
643
|
+
* family to match — is taken to, since what is at stake is the document. */
|
|
644
|
+
function instantiates(app: object, family: string): boolean {
|
|
645
|
+
try {
|
|
646
|
+
const fonts = (app as { fonts?: { match?(family: string): unknown } })
|
|
647
|
+
.fonts;
|
|
648
|
+
const face = fonts?.match?.(family) as OpenedFace | null | undefined;
|
|
649
|
+
return !face || typeof face.variation === 'function';
|
|
650
|
+
} catch {
|
|
651
|
+
return true;
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
/** Said once a connection, in development: a page set in its fallback
|
|
656
|
+
* family looks like a font that never loaded, and this says it did. */
|
|
657
|
+
function warnRefused(registry: Registry, url: string, why: string): void {
|
|
658
|
+
if (registry.warned) return;
|
|
659
|
+
registry.warned = true;
|
|
660
|
+
const g = globalThis as {
|
|
661
|
+
process?: { env?: Record<string, string | undefined> };
|
|
662
|
+
console?: { warn(message: string): void };
|
|
663
|
+
};
|
|
664
|
+
if (g.process?.env?.NODE_ENV === 'production') return;
|
|
665
|
+
g.console?.warn(
|
|
666
|
+
`@react-x11/components: <Html> loaded the font at ${url} and the text ` +
|
|
667
|
+
'engine cannot set text in it, so its family is left out and the text ' +
|
|
668
|
+
'is set in the next one — as it is for every face the engine refuses. ' +
|
|
669
|
+
`A variable font served as WOFF2 is the usual cause.\n${why}`,
|
|
670
|
+
);
|
|
671
|
+
}
|
|
672
|
+
|
|
563
673
|
/** A face's identity within a registered name. */
|
|
564
674
|
function faceKey(name: string, rule: FontFaceRule): string {
|
|
565
675
|
return `${name}\u0000${faceSignature(rule)}`;
|