@tschk/moonshine 0.3.2 → 0.3.4
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 +5 -5
- package/src/signal.ts +7 -1
- package/src/create-app.ts +0 -79
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tschk/moonshine",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.4",
|
|
4
4
|
"description": "Hyperminimal signal runtime — Bun-first; import /react for TSX apps",
|
|
5
5
|
"license": "ISC",
|
|
6
6
|
"type": "module",
|
|
@@ -18,10 +18,10 @@
|
|
|
18
18
|
"./shaders": "./src/shaders.ts"
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@tschk/moonshine-react": "^0.3.
|
|
22
|
-
"@tschk/moonshine-router": "^0.3.
|
|
23
|
-
"@tschk/moonshine-server": "^0.3.
|
|
24
|
-
"@tschk/moonshine-shaders": "^0.3.
|
|
21
|
+
"@tschk/moonshine-react": "^0.3.4",
|
|
22
|
+
"@tschk/moonshine-router": "^0.3.4",
|
|
23
|
+
"@tschk/moonshine-server": "^0.3.4",
|
|
24
|
+
"@tschk/moonshine-shaders": "^0.3.4"
|
|
25
25
|
},
|
|
26
26
|
"scripts": {
|
|
27
27
|
"test": "bun test",
|
package/src/signal.ts
CHANGED
|
@@ -205,9 +205,15 @@ export function createMemo<T>(compute: () => T): Memo<T> {
|
|
|
205
205
|
currentTracker = previous;
|
|
206
206
|
}
|
|
207
207
|
|
|
208
|
+
// Re-subscribing tears down and rebuilds the whole upstream chain, so only
|
|
209
|
+
// do it when the dependency set actually moved.
|
|
210
|
+
const sameDeps =
|
|
211
|
+
collected.length === deps.length &&
|
|
212
|
+
collected.every((entry, index) => entry.node === deps[index]!.node);
|
|
213
|
+
|
|
208
214
|
deps = collected;
|
|
209
215
|
stale = false;
|
|
210
|
-
if (listeners.size > 0) observe();
|
|
216
|
+
if (listeners.size > 0 && (!sameDeps || unsubs.length === 0)) observe();
|
|
211
217
|
|
|
212
218
|
if (!hasValue || !Object.is(next, value)) {
|
|
213
219
|
value = next;
|
package/src/create-app.ts
DELETED
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
import { createElement, type ComponentType, type ReactNode } from "react";
|
|
2
|
-
import { createRoot, type Root } from "react-dom/client";
|
|
3
|
-
|
|
4
|
-
export type MoonshineAppOptions = {
|
|
5
|
-
/** React root component. */
|
|
6
|
-
root: ComponentType;
|
|
7
|
-
/** Optional CSS class applied to the mount host. */
|
|
8
|
-
className?: string;
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
export type MoonshineApp = {
|
|
12
|
-
/** Mount into a DOM container (selector or element). */
|
|
13
|
-
mount: (container: string | Element) => void;
|
|
14
|
-
/** Unmount and dispose the React root. */
|
|
15
|
-
unmount: () => void;
|
|
16
|
-
/** True after a successful mount and before unmount. */
|
|
17
|
-
readonly mounted: boolean;
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Create a lightweight Moonshine app shell.
|
|
22
|
-
*
|
|
23
|
-
* ```ts
|
|
24
|
-
* const app = createMoonshineApp({ root: App });
|
|
25
|
-
* app.mount("#app");
|
|
26
|
-
* ```
|
|
27
|
-
*/
|
|
28
|
-
export function createMoonshineApp(options: MoonshineAppOptions): MoonshineApp {
|
|
29
|
-
let reactRoot: Root | null = null;
|
|
30
|
-
let host: Element | null = null;
|
|
31
|
-
let mounted = false;
|
|
32
|
-
|
|
33
|
-
return {
|
|
34
|
-
get mounted() {
|
|
35
|
-
return mounted;
|
|
36
|
-
},
|
|
37
|
-
mount(container) {
|
|
38
|
-
if (mounted) {
|
|
39
|
-
throw new Error("createMoonshineApp: already mounted");
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
const el =
|
|
43
|
-
typeof container === "string"
|
|
44
|
-
? document.querySelector(container)
|
|
45
|
-
: container;
|
|
46
|
-
if (!el) {
|
|
47
|
-
throw new Error(
|
|
48
|
-
`createMoonshineApp: mount target not found: ${String(container)}`,
|
|
49
|
-
);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
host = el;
|
|
53
|
-
if (options.className) {
|
|
54
|
-
el.classList.add(...options.className.split(/\s+/).filter(Boolean));
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
reactRoot = createRoot(el);
|
|
58
|
-
reactRoot.render(createElement(options.root));
|
|
59
|
-
mounted = true;
|
|
60
|
-
},
|
|
61
|
-
unmount() {
|
|
62
|
-
if (!mounted || !reactRoot) return;
|
|
63
|
-
reactRoot.unmount();
|
|
64
|
-
reactRoot = null;
|
|
65
|
-
if (host && options.className) {
|
|
66
|
-
for (const cls of options.className.split(/\s+/).filter(Boolean)) {
|
|
67
|
-
host.classList.remove(cls);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
host = null;
|
|
71
|
-
mounted = false;
|
|
72
|
-
},
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/** @internal helper for tests / SSR stubs that only need an element tree. */
|
|
77
|
-
export function renderToNode(root: ComponentType): ReactNode {
|
|
78
|
-
return createElement(root);
|
|
79
|
-
}
|