@preact/signals-devtools-ui 0.4.0 → 0.4.1
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/CHANGELOG.md +6 -0
- package/dist/devtools-ui.js +1 -1
- package/dist/devtools-ui.js.map +1 -1
- package/dist/devtools-ui.min.js +1 -1
- package/dist/devtools-ui.min.js.map +1 -1
- package/dist/devtools-ui.mjs +1 -1
- package/dist/devtools-ui.mjs.map +1 -1
- package/dist/devtools-ui.module.js +1 -1
- package/dist/devtools-ui.module.js.map +1 -1
- package/dist/styles.css +400 -101
- package/package.json +2 -2
- package/src/components/Graph.tsx +5 -17
- package/src/components/Header.tsx +21 -1
- package/src/context.ts +73 -1
- package/src/styles.css +400 -101
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@preact/signals-devtools-ui",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "DevTools UI components for @preact/signals",
|
|
6
6
|
"keywords": [
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"typescript": "~5.8.3",
|
|
55
55
|
"vite": "^7.0.0",
|
|
56
56
|
"vitest": "^4.0.17",
|
|
57
|
-
"@preact/signals": "2.
|
|
57
|
+
"@preact/signals": "2.8.0"
|
|
58
58
|
},
|
|
59
59
|
"publishConfig": {
|
|
60
60
|
"access": "public",
|
package/src/components/Graph.tsx
CHANGED
|
@@ -493,7 +493,7 @@ export function GraphVisualization() {
|
|
|
493
493
|
refY="3"
|
|
494
494
|
orient="auto"
|
|
495
495
|
>
|
|
496
|
-
<polygon points="0 0, 8 3, 0 6"
|
|
496
|
+
<polygon points="0 0, 8 3, 0 6" className="graph-arrowhead" />
|
|
497
497
|
</marker>
|
|
498
498
|
</defs>
|
|
499
499
|
|
|
@@ -639,31 +639,19 @@ export function GraphVisualization() {
|
|
|
639
639
|
|
|
640
640
|
<div className="graph-legend">
|
|
641
641
|
<div className="legend-item">
|
|
642
|
-
<div
|
|
643
|
-
className="legend-color"
|
|
644
|
-
style={{ backgroundColor: "#2196f3" }}
|
|
645
|
-
></div>
|
|
642
|
+
<div className="legend-color signal"></div>
|
|
646
643
|
<span>Signal</span>
|
|
647
644
|
</div>
|
|
648
645
|
<div className="legend-item">
|
|
649
|
-
<div
|
|
650
|
-
className="legend-color"
|
|
651
|
-
style={{ backgroundColor: "#ff9800" }}
|
|
652
|
-
></div>
|
|
646
|
+
<div className="legend-color computed"></div>
|
|
653
647
|
<span>Computed</span>
|
|
654
648
|
</div>
|
|
655
649
|
<div className="legend-item">
|
|
656
|
-
<div
|
|
657
|
-
className="legend-color"
|
|
658
|
-
style={{ backgroundColor: "#4caf50" }}
|
|
659
|
-
></div>
|
|
650
|
+
<div className="legend-color effect"></div>
|
|
660
651
|
<span>Effect</span>
|
|
661
652
|
</div>
|
|
662
653
|
<div className="legend-item">
|
|
663
|
-
<div
|
|
664
|
-
className="legend-color"
|
|
665
|
-
style={{ backgroundColor: "#9c27b0" }}
|
|
666
|
-
></div>
|
|
654
|
+
<div className="legend-color component"></div>
|
|
667
655
|
<span>Component</span>
|
|
668
656
|
</div>
|
|
669
657
|
</div>
|
|
@@ -1,9 +1,22 @@
|
|
|
1
1
|
import { StatusIndicator } from "./StatusIndicator";
|
|
2
2
|
import { Button } from "./Button";
|
|
3
3
|
import { getContext } from "../context";
|
|
4
|
+
import type { ThemeMode } from "../context";
|
|
5
|
+
|
|
6
|
+
const themeLabels: Record<ThemeMode, string> = {
|
|
7
|
+
auto: "Auto",
|
|
8
|
+
light: "Light",
|
|
9
|
+
dark: "Dark",
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const themeIcons: Record<ThemeMode, string> = {
|
|
13
|
+
auto: "\u25D1",
|
|
14
|
+
light: "\u2600",
|
|
15
|
+
dark: "\u263E",
|
|
16
|
+
};
|
|
4
17
|
|
|
5
18
|
export function Header() {
|
|
6
|
-
const { connectionStore, updatesStore } = getContext();
|
|
19
|
+
const { connectionStore, updatesStore, themeStore } = getContext();
|
|
7
20
|
|
|
8
21
|
const onTogglePause = () => {
|
|
9
22
|
updatesStore.isPaused.value = !updatesStore.isPaused.value;
|
|
@@ -23,6 +36,13 @@ export function Header() {
|
|
|
23
36
|
/>
|
|
24
37
|
</div>
|
|
25
38
|
<div className="header-controls">
|
|
39
|
+
<button
|
|
40
|
+
className="theme-toggle"
|
|
41
|
+
onClick={themeStore.toggleTheme}
|
|
42
|
+
title={`Theme: ${themeLabels[themeStore.theme]}`}
|
|
43
|
+
>
|
|
44
|
+
{themeIcons[themeStore.theme]} {themeLabels[themeStore.theme]}
|
|
45
|
+
</button>
|
|
26
46
|
{onClear && <Button onClick={onClear}>Clear</Button>}
|
|
27
47
|
{onTogglePause && (
|
|
28
48
|
<Button onClick={onTogglePause} active={updatesStore.isPaused.value}>
|
package/src/context.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { signal, computed } from "@preact/signals";
|
|
1
|
+
import { signal, computed, effect } from "@preact/signals";
|
|
2
2
|
import type {
|
|
3
3
|
DevToolsAdapter,
|
|
4
4
|
ConnectionStatus,
|
|
@@ -8,11 +8,14 @@ import type {
|
|
|
8
8
|
DependencyInfo,
|
|
9
9
|
} from "@preact/signals-devtools-adapter";
|
|
10
10
|
|
|
11
|
+
export type ThemeMode = "auto" | "light" | "dark";
|
|
12
|
+
|
|
11
13
|
export interface DevToolsContext {
|
|
12
14
|
adapter: DevToolsAdapter;
|
|
13
15
|
connectionStore: ReturnType<typeof createConnectionStore>;
|
|
14
16
|
updatesStore: ReturnType<typeof createUpdatesStore>;
|
|
15
17
|
settingsStore: ReturnType<typeof createSettingsStore>;
|
|
18
|
+
themeStore: ReturnType<typeof createThemeStore>;
|
|
16
19
|
}
|
|
17
20
|
|
|
18
21
|
let currentContext: DevToolsContext | null = null;
|
|
@@ -325,16 +328,85 @@ export function createSettingsStore(adapter: DevToolsAdapter) {
|
|
|
325
328
|
};
|
|
326
329
|
}
|
|
327
330
|
|
|
331
|
+
const THEME_STORAGE_KEY = "signals-devtools-theme";
|
|
332
|
+
|
|
333
|
+
export function createThemeStore() {
|
|
334
|
+
const stored = (() => {
|
|
335
|
+
try {
|
|
336
|
+
const val = localStorage.getItem(THEME_STORAGE_KEY);
|
|
337
|
+
if (val === "light" || val === "dark" || val === "auto") return val;
|
|
338
|
+
} catch {
|
|
339
|
+
// localStorage unavailable
|
|
340
|
+
}
|
|
341
|
+
return "auto" as ThemeMode;
|
|
342
|
+
})();
|
|
343
|
+
|
|
344
|
+
const theme = signal<ThemeMode>(stored);
|
|
345
|
+
|
|
346
|
+
const mediaQuery =
|
|
347
|
+
typeof window !== "undefined"
|
|
348
|
+
? window.matchMedia("(prefers-color-scheme: dark)")
|
|
349
|
+
: null;
|
|
350
|
+
const systemIsDark = signal(mediaQuery?.matches ?? false);
|
|
351
|
+
|
|
352
|
+
if (mediaQuery) {
|
|
353
|
+
const handler = (e: MediaQueryListEvent) => {
|
|
354
|
+
systemIsDark.value = e.matches;
|
|
355
|
+
};
|
|
356
|
+
mediaQuery.addEventListener("change", handler);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
const resolvedTheme = computed<"light" | "dark">(() =>
|
|
360
|
+
theme.value === "auto"
|
|
361
|
+
? systemIsDark.value
|
|
362
|
+
? "dark"
|
|
363
|
+
: "light"
|
|
364
|
+
: theme.value
|
|
365
|
+
);
|
|
366
|
+
|
|
367
|
+
// Apply data-theme attribute to the devtools container
|
|
368
|
+
effect(() => {
|
|
369
|
+
const resolved = resolvedTheme.value;
|
|
370
|
+
const el = document.querySelector(".signals-devtools");
|
|
371
|
+
if (el instanceof HTMLElement) {
|
|
372
|
+
el.dataset.theme = resolved;
|
|
373
|
+
}
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
const toggleTheme = () => {
|
|
377
|
+
const order: ThemeMode[] = ["auto", "light", "dark"];
|
|
378
|
+
const idx = order.indexOf(theme.value);
|
|
379
|
+
theme.value = order[(idx + 1) % order.length];
|
|
380
|
+
try {
|
|
381
|
+
localStorage.setItem(THEME_STORAGE_KEY, theme.value);
|
|
382
|
+
} catch {
|
|
383
|
+
// localStorage unavailable
|
|
384
|
+
}
|
|
385
|
+
};
|
|
386
|
+
|
|
387
|
+
return {
|
|
388
|
+
get theme() {
|
|
389
|
+
return theme.value;
|
|
390
|
+
},
|
|
391
|
+
get resolvedTheme() {
|
|
392
|
+
return resolvedTheme.value;
|
|
393
|
+
},
|
|
394
|
+
toggleTheme,
|
|
395
|
+
};
|
|
396
|
+
}
|
|
397
|
+
|
|
328
398
|
export function initDevTools(adapter: DevToolsAdapter): DevToolsContext {
|
|
329
399
|
const settingsStore = createSettingsStore(adapter);
|
|
330
400
|
const updatesStore = createUpdatesStore(adapter, settingsStore);
|
|
331
401
|
const connectionStore = createConnectionStore(adapter);
|
|
402
|
+
const themeStore = createThemeStore();
|
|
332
403
|
|
|
333
404
|
currentContext = {
|
|
334
405
|
adapter,
|
|
335
406
|
connectionStore,
|
|
336
407
|
updatesStore,
|
|
337
408
|
settingsStore,
|
|
409
|
+
themeStore,
|
|
338
410
|
};
|
|
339
411
|
|
|
340
412
|
return currentContext;
|