react-x11 2.49.0 → 2.50.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/package.json +3 -3
- package/src/ClickToComponent.js +11 -132
- package/src/cli/dev.js +94 -19
- package/src/cli/errorwindow.js +368 -0
- package/src/cocoa/presenter.js +3 -1
- package/src/cocoa/promotion.js +10 -11
- package/src/cocoa/relaunch.js +110 -13
- package/src/currentcolor.js +28 -0
- package/src/decorations.js +21 -9
- package/src/editor.js +151 -0
- package/src/foreignnodes.js +8 -1
- package/src/gloverlay.js +2 -1
- package/src/node.d.ts +5 -0
- package/src/nodes/animation.js +31 -3
- package/src/nodes/boxpaint.js +34 -8
- package/src/nodes/cascade.js +50 -3
- package/src/nodes/damage.js +2 -0
- package/src/nodes/layout.js +9 -17
- package/src/nodes/moveblit.js +5 -5
- package/src/nodes/node.js +8 -0
- package/src/nodes/paint.js +4 -2
- package/src/nodes/queries.js +46 -34
- package/src/nodes/scrollblit.js +10 -7
- package/src/nodes/styling.js +176 -21
- package/src/nodes/window/capabilities.js +1 -1
- package/src/nodes/window/floors.js +63 -18
- package/src/nodes/window/size.js +94 -19
- package/src/refresh/loader.d.ts +16 -0
- package/src/refresh/loader.js +58 -8
- package/src/shorthands.js +1266 -0
- package/src/styles.js +370 -131
- package/src/types/style.d.ts +163 -39
package/src/nodes/window/size.js
CHANGED
|
@@ -2,7 +2,11 @@
|
|
|
2
2
|
// floors, laying the root out, deferring floors during a live resize and
|
|
3
3
|
// catching up after, and refitting the window to what it holds.
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
exactLayoutConfig,
|
|
7
|
+
measuringExactly,
|
|
8
|
+
setLayoutValue,
|
|
9
|
+
} from '../../styles.js';
|
|
6
10
|
import { availableArea } from '../../screens.js';
|
|
7
11
|
import { Yoga } from '../../yoga.js';
|
|
8
12
|
import {
|
|
@@ -185,7 +189,14 @@ export class WindowSize {
|
|
|
185
189
|
this._floorsStale.add(boundary.parent);
|
|
186
190
|
}
|
|
187
191
|
// its children's floors are written from here; a sized box's own
|
|
188
|
-
// extent is its style's, and stands
|
|
192
|
+
// extent is its style's, and stands, and one its content sizes is
|
|
193
|
+
// measured with them (`_ownExtent`), or left unmeasured with them
|
|
194
|
+
if (typeof boundary.style.width !== 'number') {
|
|
195
|
+
boundary._floorW = undefined;
|
|
196
|
+
}
|
|
197
|
+
if (typeof boundary.style.height !== 'number') {
|
|
198
|
+
boundary._floorH = undefined;
|
|
199
|
+
}
|
|
189
200
|
this._floorsStale.add(boundary);
|
|
190
201
|
collectFloorStale(boundary, this._floorsStale, found, false);
|
|
191
202
|
}
|
|
@@ -453,9 +464,10 @@ export class WindowSize {
|
|
|
453
464
|
/**
|
|
454
465
|
* One boundary's floors, measured with it laid out alone — the passes
|
|
455
466
|
* `_measureContentSpans` runs over the whole tree, run over the box: its
|
|
456
|
-
* size is
|
|
457
|
-
*
|
|
458
|
-
*
|
|
467
|
+
* size is the same in either (`isFloorBoundary`), its style's or its
|
|
468
|
+
* content's, so the space everything inside it is laid out in is the
|
|
469
|
+
* same. `probe` is the height measurement's check for leaves whose width
|
|
470
|
+
* moved, stopped at the box, whose own extent stands.
|
|
459
471
|
*/
|
|
460
472
|
_measureBoundary(boundary, axis, probe = false) {
|
|
461
473
|
// on copies of its boxes (exactcopy.js): the tree's own are left as the
|
|
@@ -473,45 +485,108 @@ export class WindowSize {
|
|
|
473
485
|
if (axis === 'width') {
|
|
474
486
|
const shrunk = [];
|
|
475
487
|
setMeasuringShrink(boundary, axis, shrunk);
|
|
476
|
-
// its own extent
|
|
477
|
-
//
|
|
478
|
-
|
|
488
|
+
// nothing reads its own extent, so what it holds is read only where a
|
|
489
|
+
// floor is written from it, as down the window's columns — where its
|
|
490
|
+
// width is its style's: one that is its content's is as wide as the
|
|
491
|
+
// leaves in it, stretched or not, and a leaf left unshaped answers 0
|
|
492
|
+
const read =
|
|
493
|
+
NO_UNREAD_WIDTHS ||
|
|
494
|
+
this._readEveryWidth ||
|
|
495
|
+
typeof boundary.style.width !== 'number';
|
|
479
496
|
const unread = [];
|
|
480
497
|
if (!read) markUnreadLeaves(boundary, unread);
|
|
481
|
-
this._scopedFloorPasses += 1;
|
|
482
498
|
try {
|
|
483
|
-
|
|
499
|
+
this._layOutBoundary(boundary, undefined, dir);
|
|
484
500
|
} finally {
|
|
485
501
|
for (const leaf of unread) leaf._widthUnread = false;
|
|
486
502
|
}
|
|
487
|
-
contentSpan(boundary, axis, null, this, read);
|
|
503
|
+
const span = contentSpan(boundary, axis, null, this, read);
|
|
504
|
+
if (typeof boundary.style.width !== 'number') {
|
|
505
|
+
this._ownExtent(boundary, axis, span);
|
|
506
|
+
}
|
|
488
507
|
restoreShrink(shrunk);
|
|
489
508
|
return;
|
|
490
509
|
}
|
|
491
|
-
this.
|
|
492
|
-
yoga.calculateLayout(undefined, undefined, dir);
|
|
510
|
+
this._layOutBoundary(boundary, undefined, dir);
|
|
493
511
|
if (probe) {
|
|
494
512
|
const hit = { marked: false, owed: false };
|
|
495
513
|
probeHeightFloors(boundary, this, hit, boundary);
|
|
496
514
|
if (hit.marked) {
|
|
497
515
|
this._writeFloors('height');
|
|
498
|
-
this.
|
|
499
|
-
yoga.calculateLayout(undefined, undefined, dir);
|
|
516
|
+
this._layOutBoundary(boundary, undefined, dir);
|
|
500
517
|
}
|
|
501
518
|
}
|
|
502
519
|
const intrinsic = new Map();
|
|
503
520
|
captureLeafHeights(boundary, intrinsic);
|
|
504
|
-
|
|
521
|
+
// …and the box's own, as the pass over the window pins it with
|
|
522
|
+
// everything else under a node being measured: one its content sizes
|
|
523
|
+
// would be measured again in the collapse, and a row that wraps take
|
|
524
|
+
// every item onto one line
|
|
525
|
+
const frozen = [boundary];
|
|
526
|
+
yoga.setWidth(yoga.getComputedWidth());
|
|
505
527
|
freezeWidths(boundary, frozen);
|
|
506
528
|
const shrunk = [];
|
|
507
529
|
setMeasuringShrink(boundary, axis, shrunk);
|
|
508
|
-
this.
|
|
509
|
-
|
|
510
|
-
|
|
530
|
+
this._layOutBoundary(boundary, 0, dir, true);
|
|
531
|
+
const span = contentSpan(boundary, axis, intrinsic, this);
|
|
532
|
+
if (typeof boundary.style.height !== 'number') {
|
|
533
|
+
this._ownExtent(boundary, axis, span);
|
|
534
|
+
}
|
|
511
535
|
restoreWidths(frozen);
|
|
512
536
|
restoreShrink(shrunk);
|
|
513
537
|
}
|
|
514
538
|
|
|
539
|
+
/** A boundary its content sizes has an extent its content gives, as any
|
|
540
|
+
* box does (`contentSpan`): nothing reads it, absolute as the box is, and
|
|
541
|
+
* it is written here as the pass over the window would have written it,
|
|
542
|
+
* rather than left at what the content measured before it changed. */
|
|
543
|
+
_ownExtent(boundary, axis, span) {
|
|
544
|
+
const yoga = boundary.yoga;
|
|
545
|
+
if (axis === 'width') {
|
|
546
|
+
boundary._floorW = declaresOwnMinimum(boundary, axis)
|
|
547
|
+
? yoga.getComputedWidth()
|
|
548
|
+
: span;
|
|
549
|
+
} else {
|
|
550
|
+
boundary._floorH = declaresOwnMinimum(boundary, axis)
|
|
551
|
+
? yoga.getComputedHeight()
|
|
552
|
+
: span;
|
|
553
|
+
boundary._floorAtW = yoga.getComputedWidth();
|
|
554
|
+
}
|
|
555
|
+
this._floorsMeasured += 1;
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
/**
|
|
559
|
+
* One pass over a boundary alone, laid out as yoga lays an absolute box
|
|
560
|
+
* out where it sits. A size its style names is the size it is laid out
|
|
561
|
+
* at. Along an axis it names none, it is measured at what its content
|
|
562
|
+
* asks for and laid out again at exactly that: the second pass is where a
|
|
563
|
+
* percentage inside it resolves, against the size the first one found,
|
|
564
|
+
* and squeezes what stands beside it — which a box laid out once, at no
|
|
565
|
+
* size, never does. `height` is what the pass offers down a box with a
|
|
566
|
+
* height of its own: 0 in the collapse. One as tall as its content is
|
|
567
|
+
* offered nothing in the collapse over the window either, since yoga
|
|
568
|
+
* bounds an absolute box by nothing down, and offered 0 here it would be
|
|
569
|
+
* squashed to its padding, and what gives way in it with it. `pinned`
|
|
570
|
+
* says its width is held where the last pass left it, as the collapse
|
|
571
|
+
* holds every width (`freezeWidths`).
|
|
572
|
+
*/
|
|
573
|
+
_layOutBoundary(boundary, height, dir, pinned = false) {
|
|
574
|
+
const yoga = boundary.yoga;
|
|
575
|
+
const style = boundary.style;
|
|
576
|
+
const across = !pinned && typeof style.width !== 'number';
|
|
577
|
+
const down = typeof style.height !== 'number';
|
|
578
|
+
this._scopedFloorPasses += 1;
|
|
579
|
+
yoga.calculateLayout(undefined, down ? undefined : height, dir);
|
|
580
|
+
if (!across && !down) return;
|
|
581
|
+
// on the copy (`onExactCopy`), and taken off again for the next pass
|
|
582
|
+
if (across) yoga.setWidth(yoga.getComputedWidth());
|
|
583
|
+
if (down) yoga.setHeight(yoga.getComputedHeight());
|
|
584
|
+
this._scopedFloorPasses += 1;
|
|
585
|
+
yoga.calculateLayout(undefined, undefined, dir);
|
|
586
|
+
if (across) setLayoutValue(yoga, 'width', style.width);
|
|
587
|
+
if (down) setLayoutValue(yoga, 'height', style.height);
|
|
588
|
+
}
|
|
589
|
+
|
|
515
590
|
/** The floors on the children of every node found stale, from the extents
|
|
516
591
|
* they carry — `writeFloors` for each. */
|
|
517
592
|
_writeFloors(axis) {
|
package/src/refresh/loader.d.ts
CHANGED
|
@@ -35,3 +35,19 @@ export function createTransformer(options?: RefreshOptions): Promise<{
|
|
|
35
35
|
matches(pathname: string): boolean;
|
|
36
36
|
transform(source: string, filename: string): { code: string };
|
|
37
37
|
}>;
|
|
38
|
+
|
|
39
|
+
/** One hot module compiled: `error` is null when it compiled, and what the
|
|
40
|
+
* compiler threw when it did not. */
|
|
41
|
+
export interface TransformEvent {
|
|
42
|
+
filename: string;
|
|
43
|
+
error: Error | null;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Called for every hot module the loader compiles. A save that does not
|
|
48
|
+
* compile is otherwise only printed — the app keeps running the module's last
|
|
49
|
+
* version — so this is how a host shows it. Returns an unsubscribe.
|
|
50
|
+
*/
|
|
51
|
+
export function onTransform(
|
|
52
|
+
listener: (event: TransformEvent) => void,
|
|
53
|
+
): () => void;
|
package/src/refresh/loader.js
CHANGED
|
@@ -305,7 +305,8 @@ function buildTransformer({ babel, jsxTransform, refreshTransform }, options) {
|
|
|
305
305
|
`const $RefreshSig$ = __ReactX11Refresh.createSignatureFunctionForTransform`,
|
|
306
306
|
...prelude,
|
|
307
307
|
];
|
|
308
|
-
//
|
|
308
|
+
// One statement a line, above the module's own first line: the source map
|
|
309
|
+
// below starts that many lines down to match.
|
|
309
310
|
const preludeSource = preludeLines.join(';\n') + ';';
|
|
310
311
|
|
|
311
312
|
let lastModuleInfo = null;
|
|
@@ -320,7 +321,7 @@ function buildTransformer({ babel, jsxTransform, refreshTransform }, options) {
|
|
|
320
321
|
},
|
|
321
322
|
transform(source, filename) {
|
|
322
323
|
lastModuleInfo = null;
|
|
323
|
-
const { code } = babel.transformSync(source, {
|
|
324
|
+
const { code, map } = babel.transformSync(source, {
|
|
324
325
|
filename,
|
|
325
326
|
babelrc: false,
|
|
326
327
|
configFile: false,
|
|
@@ -331,7 +332,7 @@ function buildTransformer({ babel, jsxTransform, refreshTransform }, options) {
|
|
|
331
332
|
guardPlugin,
|
|
332
333
|
],
|
|
333
334
|
retainLines: true,
|
|
334
|
-
sourceMaps:
|
|
335
|
+
sourceMaps: true,
|
|
335
336
|
});
|
|
336
337
|
const { opaque, names } = lastModuleInfo;
|
|
337
338
|
const exportsArg =
|
|
@@ -339,13 +340,55 @@ function buildTransformer({ babel, jsxTransform, refreshTransform }, options) {
|
|
|
339
340
|
? 'null'
|
|
340
341
|
: `{ ${names.map((n) => `${JSON.stringify(n)}: ${n}`).join(', ')} }`;
|
|
341
342
|
const footer = `\n;import.meta.hot && __ReactX11Refresh.moduleReady(import.meta.hot, import.meta.url, ${exportsArg});`;
|
|
342
|
-
return {
|
|
343
|
+
return {
|
|
344
|
+
code:
|
|
345
|
+
`${preludeSource}\n${code}${footer}\n` +
|
|
346
|
+
inlineSourceMap(map, preludeLines.length),
|
|
347
|
+
};
|
|
343
348
|
},
|
|
344
349
|
};
|
|
345
350
|
}
|
|
346
351
|
|
|
352
|
+
const transformListeners = new Set();
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* Called for every hot module this loader compiles, with `{ filename, error }`
|
|
356
|
+
* — `error` null when it compiled. The seam a host needs for a save that does
|
|
357
|
+
* not compile: hot-module-replacement catches the error of a reload and only
|
|
358
|
+
* prints it, and the app keeps running the module's last version, so nothing
|
|
359
|
+
* else tells the host. `react-x11 dev` shows it in a window. Returns an
|
|
360
|
+
* unsubscribe.
|
|
361
|
+
*/
|
|
362
|
+
export function onTransform(listener) {
|
|
363
|
+
transformListeners.add(listener);
|
|
364
|
+
return () => transformListeners.delete(listener);
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
function reportTransform(event) {
|
|
368
|
+
for (const listener of [...transformListeners]) {
|
|
369
|
+
try {
|
|
370
|
+
listener(event);
|
|
371
|
+
} catch (err) {
|
|
372
|
+
console.error('react-x11/refresh: an onTransform listener threw', err);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
347
377
|
let registered = false;
|
|
348
378
|
|
|
379
|
+
/**
|
|
380
|
+
* Babel's map for a module, as the comment that carries it, moved `lines`
|
|
381
|
+
* down: babel describes its own output, and the prelude goes in above that.
|
|
382
|
+
* An empty line in a map's mappings is a `;`, so the shift is that many of
|
|
383
|
+
* them. hot-module-replacement, the layer above, composes this map into its
|
|
384
|
+
* own — which is what a stack trace through a hot module is read through.
|
|
385
|
+
*/
|
|
386
|
+
export function inlineSourceMap(map, lines) {
|
|
387
|
+
const shifted = { ...map, mappings: ';'.repeat(lines) + map.mappings };
|
|
388
|
+
const payload = Buffer.from(JSON.stringify(shifted)).toString('base64');
|
|
389
|
+
return `//# sourceMappingURL=data:application/json;charset=utf-8;base64,${payload}\n`;
|
|
390
|
+
}
|
|
391
|
+
|
|
349
392
|
/**
|
|
350
393
|
* Which files stay out of the hot graph: every package in node_modules,
|
|
351
394
|
* react-x11's own src/, and whatever the app's `ignore` names.
|
|
@@ -426,10 +469,17 @@ export async function registerRefresh(options = {}) {
|
|
|
426
469
|
if (hotIgnore(filename)) {
|
|
427
470
|
return nextLoad(url, context);
|
|
428
471
|
}
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
472
|
+
let code;
|
|
473
|
+
try {
|
|
474
|
+
({ code } = transformer.transform(
|
|
475
|
+
readFileSync(filename, 'utf8'),
|
|
476
|
+
filename,
|
|
477
|
+
));
|
|
478
|
+
} catch (error) {
|
|
479
|
+
reportTransform({ filename, error });
|
|
480
|
+
throw error;
|
|
481
|
+
}
|
|
482
|
+
reportTransform({ filename, error: null });
|
|
433
483
|
return { format: 'module', source: code, shortCircuit: true };
|
|
434
484
|
},
|
|
435
485
|
});
|