@nice-code/state 0.4.6 → 0.4.8
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.
|
@@ -161,7 +161,7 @@ class StateDevtoolsCore {
|
|
|
161
161
|
}
|
|
162
162
|
}
|
|
163
163
|
// src/devtools/browser/NiceStateDevtools.tsx
|
|
164
|
-
import { useEffect as useEffect2, useId, useMemo
|
|
164
|
+
import { useEffect as useEffect2, useId, useMemo, useReducer, useState as useState3 } from "react";
|
|
165
165
|
|
|
166
166
|
// src/devtools/core/devtools_colors.ts
|
|
167
167
|
var DEVTOOL_COLOR_SEMANTIC_ERROR = "#FF5C5C";
|
|
@@ -253,6 +253,25 @@ function summarizeChange(change) {
|
|
|
253
253
|
function topLevel(path) {
|
|
254
254
|
return path.length > 0 ? String(path[0]) : "(root)";
|
|
255
255
|
}
|
|
256
|
+
function changeGroupKey(change) {
|
|
257
|
+
return `${change.storeId}|${safeStringify(change.snapshot, 0)}`;
|
|
258
|
+
}
|
|
259
|
+
function groupChanges(changes) {
|
|
260
|
+
const groups = [];
|
|
261
|
+
let lastKey = null;
|
|
262
|
+
for (const change of changes) {
|
|
263
|
+
const key = changeGroupKey(change);
|
|
264
|
+
const last = groups[groups.length - 1];
|
|
265
|
+
if (last != null && key === lastKey) {
|
|
266
|
+
last.count++;
|
|
267
|
+
last.oldest = change;
|
|
268
|
+
} else {
|
|
269
|
+
groups.push({ representative: change, oldest: change, count: 1 });
|
|
270
|
+
}
|
|
271
|
+
lastKey = key;
|
|
272
|
+
}
|
|
273
|
+
return groups;
|
|
274
|
+
}
|
|
256
275
|
function computeDiff(before, after) {
|
|
257
276
|
const out = [];
|
|
258
277
|
walkDiff([], before, after, out);
|
|
@@ -1466,37 +1485,15 @@ function ToggleCheckbox({
|
|
|
1466
1485
|
}
|
|
1467
1486
|
|
|
1468
1487
|
// src/devtools/browser/components/ChangeList.tsx
|
|
1469
|
-
import { useMemo } from "react";
|
|
1470
1488
|
import { jsxDEV as jsxDEV6 } from "react/jsx-dev-runtime";
|
|
1471
|
-
function changeGroupKey(change) {
|
|
1472
|
-
const shape = change.patches.length > 0 ? safeStringify(change.patches, 0) : safeStringify(change.snapshot, 0);
|
|
1473
|
-
return `${change.storeId}|${change.source}|${shape}`;
|
|
1474
|
-
}
|
|
1475
|
-
function groupChanges(changes) {
|
|
1476
|
-
const groups = [];
|
|
1477
|
-
let lastKey = null;
|
|
1478
|
-
for (const change of changes) {
|
|
1479
|
-
const key = changeGroupKey(change);
|
|
1480
|
-
const last = groups[groups.length - 1];
|
|
1481
|
-
if (last != null && key === lastKey) {
|
|
1482
|
-
last.count++;
|
|
1483
|
-
last.oldestCuid = change.cuid;
|
|
1484
|
-
} else {
|
|
1485
|
-
groups.push({ representative: change, oldestCuid: change.cuid, count: 1 });
|
|
1486
|
-
}
|
|
1487
|
-
lastKey = key;
|
|
1488
|
-
}
|
|
1489
|
-
return groups;
|
|
1490
|
-
}
|
|
1491
1489
|
function ChangeList({
|
|
1492
|
-
|
|
1490
|
+
groups,
|
|
1493
1491
|
selectedCuid,
|
|
1494
1492
|
onSelect,
|
|
1495
1493
|
showStore,
|
|
1496
1494
|
style
|
|
1497
1495
|
}) {
|
|
1498
|
-
|
|
1499
|
-
if (changes.length === 0) {
|
|
1496
|
+
if (groups.length === 0) {
|
|
1500
1497
|
return /* @__PURE__ */ jsxDEV6("div", {
|
|
1501
1498
|
style: {
|
|
1502
1499
|
padding: "24px",
|
|
@@ -1516,7 +1513,7 @@ function ChangeList({
|
|
|
1516
1513
|
selected: group.representative.cuid === selectedCuid,
|
|
1517
1514
|
onClick: () => onSelect(group.representative.cuid),
|
|
1518
1515
|
showStore
|
|
1519
|
-
}, group.
|
|
1516
|
+
}, group.oldest.cuid, false, undefined, this))
|
|
1520
1517
|
}, undefined, false, undefined, this);
|
|
1521
1518
|
}
|
|
1522
1519
|
function ChangeRow({
|
|
@@ -2098,15 +2095,30 @@ function NiceStateDevtools_Panel({
|
|
|
2098
2095
|
const dockSide = getDockSide(position);
|
|
2099
2096
|
const isHorizDock = dockSide === "top" || dockSide === "bottom";
|
|
2100
2097
|
const dockedSize = isHorizDock ? dockedHeight : dockedWidth;
|
|
2101
|
-
const filteredChanges =
|
|
2102
|
-
const
|
|
2098
|
+
const filteredChanges = useMemo(() => storeFilter == null ? changes : changes.filter((c) => c.storeId === storeFilter), [changes, storeFilter]);
|
|
2099
|
+
const groups = useMemo(() => groupChanges(filteredChanges), [filteredChanges]);
|
|
2100
|
+
const selectedChange = useMemo(() => {
|
|
2101
|
+
if (selectedChangeCuid == null)
|
|
2102
|
+
return null;
|
|
2103
|
+
const group = groups.find((g) => g.representative.cuid === selectedChangeCuid);
|
|
2104
|
+
if (group == null)
|
|
2105
|
+
return changes.find((c) => c.cuid === selectedChangeCuid) ?? null;
|
|
2106
|
+
if (group.count > 1) {
|
|
2107
|
+
return {
|
|
2108
|
+
...group.representative,
|
|
2109
|
+
prevSnapshot: group.oldest.prevSnapshot,
|
|
2110
|
+
inversePatches: group.oldest.inversePatches
|
|
2111
|
+
};
|
|
2112
|
+
}
|
|
2113
|
+
return group.representative;
|
|
2114
|
+
}, [selectedChangeCuid, groups, changes]);
|
|
2103
2115
|
const latestCuid = filteredChanges.length > 0 ? filteredChanges[0].cuid : null;
|
|
2104
2116
|
useEffect2(() => {
|
|
2105
2117
|
if (stayOnLatest && latestCuid != null)
|
|
2106
2118
|
setSelectedChangeCuid(latestCuid);
|
|
2107
2119
|
}, [stayOnLatest, latestCuid]);
|
|
2108
2120
|
const activeStore = stores.find((s) => s.id === storeFilter) ?? (stores.length > 0 ? stores[0] : null);
|
|
2109
|
-
const dock =
|
|
2121
|
+
const dock = useMemo(() => getDevtoolsDockCoordinator(), []);
|
|
2110
2122
|
const panelId = useId();
|
|
2111
2123
|
const [, bumpView] = useReducer((n) => n + 1, 0);
|
|
2112
2124
|
const badge = changes.length > 0 ? String(changes.length) : undefined;
|
|
@@ -2248,7 +2260,7 @@ function NiceStateDevtools_Panel({
|
|
|
2248
2260
|
/* @__PURE__ */ jsxDEV10("div", {
|
|
2249
2261
|
style: { flex: 1, minHeight: 0, overflowY: "auto" },
|
|
2250
2262
|
children: /* @__PURE__ */ jsxDEV10(ChangeList, {
|
|
2251
|
-
|
|
2263
|
+
groups,
|
|
2252
2264
|
selectedCuid: selectedChangeCuid,
|
|
2253
2265
|
onSelect: (cuid) => {
|
|
2254
2266
|
if (stayOnLatest)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type
|
|
3
|
-
export declare function ChangeList({
|
|
4
|
-
|
|
1
|
+
import type { CSSProperties } from "react";
|
|
2
|
+
import { type IChangeGroup } from "./utils";
|
|
3
|
+
export declare function ChangeList({ groups, selectedCuid, onSelect, showStore, style, }: {
|
|
4
|
+
groups: IChangeGroup[];
|
|
5
5
|
selectedCuid: string | null;
|
|
6
6
|
onSelect: (cuid: string) => void;
|
|
7
7
|
showStore: boolean;
|
|
@@ -13,6 +13,33 @@ export declare function patchPathToString(path: Patch["path"]): string;
|
|
|
13
13
|
* the distinct top-level paths affected.
|
|
14
14
|
*/
|
|
15
15
|
export declare function summarizeChange(change: IDevtoolsStateChange): string;
|
|
16
|
+
/** A run of consecutive, structurally-equal changes collapsed into one row. */
|
|
17
|
+
export interface IChangeGroup {
|
|
18
|
+
/** Newest change in the run — the one the row renders and selects. */
|
|
19
|
+
representative: IDevtoolsStateChange;
|
|
20
|
+
/**
|
|
21
|
+
* Oldest change in the run — the one that actually moved the state (every later
|
|
22
|
+
* member re-applied the same mutation as a no-op). Its `prevSnapshot` is the
|
|
23
|
+
* real "before" of the whole run, so the detail panel uses it to show what the
|
|
24
|
+
* initial update changed instead of the representative's empty self-diff.
|
|
25
|
+
*/
|
|
26
|
+
oldest: IDevtoolsStateChange;
|
|
27
|
+
/** How many changes the run collapses (1 = ungrouped). */
|
|
28
|
+
count: number;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Structural identity of a change by its *resulting* state: same store, same
|
|
32
|
+
* snapshot. The feature collapses updates that "didn't change the state from the
|
|
33
|
+
* previous update", so we compare the committed state itself rather than the
|
|
34
|
+
* mutation that produced it. Keying on patches would miss the no-op cases this is
|
|
35
|
+
* meant to catch — a fresh object reference with identical content, or a
|
|
36
|
+
* same-value write from a different source (e.g. a devtools edit followed by an
|
|
37
|
+
* app update). Those carry patches yet leave the state untouched, so they belong
|
|
38
|
+
* in the run that already reached this state regardless of source.
|
|
39
|
+
*/
|
|
40
|
+
export declare function changeGroupKey(change: IDevtoolsStateChange): string;
|
|
41
|
+
/** Collapse consecutive structurally-equal changes (list is newest-first). */
|
|
42
|
+
export declare function groupChanges(changes: IDevtoolsStateChange[]): IChangeGroup[];
|
|
16
43
|
export type TDiffKind = "added" | "removed" | "changed";
|
|
17
44
|
export interface IDiffEntry {
|
|
18
45
|
path: string;
|