react-x11 2.48.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/README.md +9 -8
- package/package.json +7 -4
- package/src/ClickToComponent.js +11 -132
- package/src/Reconciler.js +4 -1
- package/src/cli/dev.js +578 -0
- package/src/cli/errorwindow.js +368 -0
- package/src/cli/index.js +81 -0
- package/src/cocoa/app.js +12 -3
- 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/errors.js +8 -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 +84 -14
- package/src/refresh/register.js +8 -5
- package/src/shorthands.js +1266 -0
- package/src/styles.js +370 -131
- package/src/types/style.d.ts +163 -39
package/src/refresh/loader.js
CHANGED
|
@@ -31,11 +31,22 @@ import { markHotReloadSession } from '../registry.js';
|
|
|
31
31
|
const RUNTIME_URL = new URL('./index.js', import.meta.url).href;
|
|
32
32
|
const SRC_DIR = fileURLToPath(new URL('../', import.meta.url));
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
34
|
+
/**
|
|
35
|
+
* The hot-reload toolchain: each specifier this loader imports, and the
|
|
36
|
+
* package it comes from. Optional peer dependencies, so `react-x11 dev`
|
|
37
|
+
* checks the same list before it starts (src/cli/dev.js).
|
|
38
|
+
*/
|
|
39
|
+
export const TOOLCHAIN = [
|
|
40
|
+
{ specifier: '@babel/core', name: '@babel/core' },
|
|
41
|
+
{
|
|
42
|
+
specifier: '@babel/plugin-transform-react-jsx',
|
|
43
|
+
name: '@babel/plugin-transform-react-jsx',
|
|
44
|
+
},
|
|
45
|
+
{ specifier: 'react-refresh/babel', name: 'react-refresh' },
|
|
46
|
+
{
|
|
47
|
+
specifier: 'hot-module-replacement/register',
|
|
48
|
+
name: 'hot-module-replacement',
|
|
49
|
+
},
|
|
39
50
|
];
|
|
40
51
|
|
|
41
52
|
async function loadToolchain() {
|
|
@@ -54,13 +65,22 @@ async function loadToolchain() {
|
|
|
54
65
|
'@babel/plugin-transform-react-jsx',
|
|
55
66
|
);
|
|
56
67
|
const refreshTransform = await load('react-refresh/babel', 'react-refresh');
|
|
68
|
+
// Resolved rather than imported: importing it registers its hooks, which
|
|
69
|
+
// has to wait until ours are in. Checked here all the same, so a missing
|
|
70
|
+
// one is this message and not a bare ERR_MODULE_NOT_FOUND after the
|
|
71
|
+
// babel hooks already went in.
|
|
72
|
+
try {
|
|
73
|
+
import.meta.resolve('hot-module-replacement/register');
|
|
74
|
+
} catch {
|
|
75
|
+
missing.push('hot-module-replacement');
|
|
76
|
+
}
|
|
57
77
|
if (missing.length > 0) {
|
|
58
78
|
throw new Error(
|
|
59
79
|
`react-x11/refresh: the hot-reload toolchain is not installed ` +
|
|
60
80
|
`(missing: ${missing.join(', ')}). It is a set of optional peer ` +
|
|
61
81
|
`dependencies — an app that never hot-reloads does not carry them. ` +
|
|
62
82
|
`Install them where the dev loop runs:\n\n` +
|
|
63
|
-
` npm install --save-dev ${TOOLCHAIN.join(' ')}\n`,
|
|
83
|
+
` npm install --save-dev ${TOOLCHAIN.map((t) => t.name).join(' ')}\n`,
|
|
64
84
|
);
|
|
65
85
|
}
|
|
66
86
|
return {
|
|
@@ -285,7 +305,8 @@ function buildTransformer({ babel, jsxTransform, refreshTransform }, options) {
|
|
|
285
305
|
`const $RefreshSig$ = __ReactX11Refresh.createSignatureFunctionForTransform`,
|
|
286
306
|
...prelude,
|
|
287
307
|
];
|
|
288
|
-
//
|
|
308
|
+
// One statement a line, above the module's own first line: the source map
|
|
309
|
+
// below starts that many lines down to match.
|
|
289
310
|
const preludeSource = preludeLines.join(';\n') + ';';
|
|
290
311
|
|
|
291
312
|
let lastModuleInfo = null;
|
|
@@ -300,7 +321,7 @@ function buildTransformer({ babel, jsxTransform, refreshTransform }, options) {
|
|
|
300
321
|
},
|
|
301
322
|
transform(source, filename) {
|
|
302
323
|
lastModuleInfo = null;
|
|
303
|
-
const { code } = babel.transformSync(source, {
|
|
324
|
+
const { code, map } = babel.transformSync(source, {
|
|
304
325
|
filename,
|
|
305
326
|
babelrc: false,
|
|
306
327
|
configFile: false,
|
|
@@ -311,7 +332,7 @@ function buildTransformer({ babel, jsxTransform, refreshTransform }, options) {
|
|
|
311
332
|
guardPlugin,
|
|
312
333
|
],
|
|
313
334
|
retainLines: true,
|
|
314
|
-
sourceMaps:
|
|
335
|
+
sourceMaps: true,
|
|
315
336
|
});
|
|
316
337
|
const { opaque, names } = lastModuleInfo;
|
|
317
338
|
const exportsArg =
|
|
@@ -319,13 +340,55 @@ function buildTransformer({ babel, jsxTransform, refreshTransform }, options) {
|
|
|
319
340
|
? 'null'
|
|
320
341
|
: `{ ${names.map((n) => `${JSON.stringify(n)}: ${n}`).join(', ')} }`;
|
|
321
342
|
const footer = `\n;import.meta.hot && __ReactX11Refresh.moduleReady(import.meta.hot, import.meta.url, ${exportsArg});`;
|
|
322
|
-
return {
|
|
343
|
+
return {
|
|
344
|
+
code:
|
|
345
|
+
`${preludeSource}\n${code}${footer}\n` +
|
|
346
|
+
inlineSourceMap(map, preludeLines.length),
|
|
347
|
+
};
|
|
323
348
|
},
|
|
324
349
|
};
|
|
325
350
|
}
|
|
326
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
|
+
|
|
327
377
|
let registered = false;
|
|
328
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
|
+
|
|
329
392
|
/**
|
|
330
393
|
* Which files stay out of the hot graph: every package in node_modules,
|
|
331
394
|
* react-x11's own src/, and whatever the app's `ignore` names.
|
|
@@ -406,10 +469,17 @@ export async function registerRefresh(options = {}) {
|
|
|
406
469
|
if (hotIgnore(filename)) {
|
|
407
470
|
return nextLoad(url, context);
|
|
408
471
|
}
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
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 });
|
|
413
483
|
return { format: 'module', source: code, shortCircuit: true };
|
|
414
484
|
},
|
|
415
485
|
});
|
package/src/refresh/register.js
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
// react-x11/refresh/register — hot reload with the defaults, for --import:
|
|
2
2
|
//
|
|
3
|
-
// node --enable-source-maps --import react-x11/refresh/register
|
|
3
|
+
// node --enable-source-maps --import react-x11/refresh/register main.jsx
|
|
4
4
|
//
|
|
5
|
-
// The app
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
5
|
+
// The app writes no wiring of its own: the loader injects the runtime into
|
|
6
|
+
// every hot module, edits to components apply in place with hook state
|
|
7
|
+
// intact, and `onReload` (from react-x11/refresh) is there when a tool wants
|
|
8
|
+
// to observe the reloads. What the app does owe is a split: main.jsx is
|
|
9
|
+
// never watched — hot-module-replacement watches a module when another
|
|
10
|
+
// imports it — so the components it mounts live in modules it imports, and
|
|
11
|
+
// an app in one file never reloads. A tool that needs the seams —
|
|
9
12
|
// extensions, ignore, an injected prelude — writes its own two-line
|
|
10
13
|
// --import module calling registerRefresh(options) instead.
|
|
11
14
|
import { registerRefresh } from './loader.js';
|