Skip to content

Commit 5445e3b

Browse files
Merge pull request #431 from preactjs/signals-2
2 parents 7c90833 + a86f6d7 commit 5445e3b

File tree

16 files changed

+159
-26
lines changed

16 files changed

+159
-26
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@
5050
"@parcel/css": "^1.12.2",
5151
"@playwright/test": "^1.25.1",
5252
"@preact/preset-vite": "^2.3.0",
53-
"@preact/signals": "^1.0.1",
53+
"@preact/signals": "^1.1.1",
5454
"@testing-library/preact": "^2.0.0",
5555
"@types/archiver": "^5.3.1",
5656
"@types/babel__core": "^7.1.19",

src/adapter/adapter/adapter.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ export interface InspectData {
3535
hooks: PropData[] | null;
3636
props: Record<string, any> | null;
3737
state: Record<string, any> | null;
38+
signals: Record<string, any> | null;
3839
canSuspend: boolean;
3940
/** Only Suspense components have this */
4041
suspended: boolean;
@@ -148,6 +149,13 @@ export function createAdapter(
148149
listen("update-prop", data => update({ ...data, type: "props" }));
149150
listen("update-state", data => update({ ...data, type: "state" }));
150151
listen("update-context", data => update({ ...data, type: "context" }));
152+
listen("update-signal", data => {
153+
getRendererByVNodeId(renderers, data.id)?.updateSignal?.(
154+
data.id,
155+
+data.path.replace("root.", "").replace(".value", ""),
156+
data.value,
157+
);
158+
});
151159
listen("update-hook", data => {
152160
if (!data.meta) return;
153161

src/adapter/hook.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ export interface DevtoolEvents {
2424
"update-prop": { id: ID; path: string; value: any };
2525
"update-state": { id: ID; path: string; value: any };
2626
"update-context": { id: ID; path: string; value: any };
27+
"update-signal": { id: ID; path: string; value: any };
2728
"update-hook": { id: ID; value: any; meta: any };
2829
/**
2930
* @deprecated

src/adapter/protocol/events.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,7 @@ describe("applyEvent", () => {
229229
name: "Foo",
230230
props: null,
231231
state: null,
232+
signals: null,
232233
type: "asd",
233234
canSuspend: false,
234235
suspended: false,
@@ -257,6 +258,7 @@ describe("applyEvent", () => {
257258
name: "Foo",
258259
props: null,
259260
state: null,
261+
signals: null,
260262
type: "asd",
261263
canSuspend: false,
262264
suspended: false,

src/adapter/renderer.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ export interface Renderer<T extends SharedVNode = SharedVNode> {
2929

3030
// Hooks
3131
updateHook?(id: ID, index: number, value: any): void; // V3
32+
// signals
33+
updateSignal?(id: ID, index: number, value: any): void; // V5
3234

3335
// Component actions
3436
suspend?(id: ID, active: boolean): void; // V4

src/adapter/shared/inspectVNode.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ export function inspectVNode<T extends SharedVNode>(
5050
? serialize(config, bindings, cleanProps(vnode.props))
5151
: null;
5252
const state = hasState ? serialize(config, bindings, c!.state) : null;
53+
const signals =
54+
c != null && "__$u" in c
55+
? inspectSignalSubscriptions(config, bindings, c.__$u.s)
56+
: null;
5357

5458
let suspended = false;
5559
let canSuspend = false;
@@ -77,9 +81,29 @@ export function inspectVNode<T extends SharedVNode>(
7781
name: getSignalTextName(bindings.getDisplayName(vnode, config)),
7882
props,
7983
state,
84+
signals,
8085
// TODO: We're not using this information anywhere yet
8186
type: getDevtoolsType(vnode, bindings),
8287
suspended,
8388
version,
8489
};
8590
}
91+
92+
function inspectSignalSubscriptions<T extends SharedVNode>(
93+
config: RendererConfig,
94+
bindings: PreactBindings<T>,
95+
node: any,
96+
) {
97+
const out: Record<string, any> = {};
98+
let i = 0;
99+
100+
const seen = new Set();
101+
while (node !== null && node !== undefined && !seen.has(node)) {
102+
seen.add(node);
103+
out[i] = serialize(config, bindings, node.S);
104+
node = node.n;
105+
i++;
106+
}
107+
108+
return i > 0 ? out : null;
109+
}

src/adapter/shared/renderer.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,28 @@ export function createRenderer<T extends SharedVNode>(
356356
}
357357
},
358358

359+
updateSignal(id, index, value) {
360+
const vnode = getVNodeById(ids, id);
361+
if (vnode !== null && bindings.isComponent(vnode)) {
362+
const c = bindings.getComponent(vnode);
363+
364+
if (c !== null && "__$u" in c) {
365+
let node = c.__$u.s;
366+
let i = 0;
367+
const seen = new Set();
368+
while (node !== null && node !== undefined && !seen.has(node)) {
369+
if (i === index) {
370+
node.S.value = value;
371+
return;
372+
}
373+
seen.add(node);
374+
node = node.n;
375+
i++;
376+
}
377+
}
378+
}
379+
},
380+
359381
suspend(id, active) {
360382
let vnode = getVNodeById(ids, id);
361383
while (vnode !== null) {

src/adapter/shared/serialize.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,12 @@ export function isSignal(x: any): x is Signal {
3333
}
3434

3535
export function isReadOnlySignal(signal: Signal): boolean {
36-
return (signal as any)._r === true;
36+
return (
37+
// Signals <1.2.0
38+
(signal as any)._r === true ||
39+
// Signals >=1.2.0
40+
("g" in signal && typeof (signal as any).x === "function")
41+
);
3742
}
3843

3944
export function jsonify(

src/adapter/store.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ describe("Store", () => {
8383
name: "Foo",
8484
props: null,
8585
state: null,
86+
signals: null,
8687
suspended: false,
8788
type: 1,
8889
version: "",

src/view/components/sidebar/Sidebar.tsx

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export function Sidebar() {
2020
}
2121
return null;
2222
}).value;
23-
const { props: propData, state, context, hooks } = store.sidebar;
23+
const { props: propData, state, context, hooks, signals } = store.sidebar;
2424
const { emit } = store;
2525

2626
return (
@@ -42,6 +42,20 @@ export function Sidebar() {
4242
onCopy={() => inspect && emit("copy", serializeProps(inspect.props))}
4343
canAddNew
4444
/>
45+
{inspect && inspect.signals !== null && (
46+
<PropsPanel
47+
label="Signals"
48+
items={signals.items}
49+
uncollapsed={signals.uncollapsed}
50+
onChange={(value, path) => {
51+
emit("update-signal", {
52+
id: inspect!.id,
53+
path,
54+
value,
55+
});
56+
}}
57+
/>
58+
)}
4559
{inspect && inspect.hooks !== null && (
4660
<PropsPanel
4761
label="Hooks"

0 commit comments

Comments
 (0)