@tanstack/pacer-devtools 1.1.5 → 1.2.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/dist/{components-DDmnxkL2.js → components-CGEHIK6F.js} +344 -231
- package/dist/{components-ByKT1JiI.js → components-vap4_VJT.js} +267 -166
- package/dist/index.d.ts +4 -8
- package/dist/index.js +3 -1
- package/dist/production/index.d.ts +3 -15
- package/dist/production/index.js +3 -1
- package/dist/production/server.js +3 -1
- package/dist/server.js +3 -1
- package/package.json +6 -6
- package/src/PacerContextProvider.tsx +96 -127
- package/src/components/ActionButtons.tsx +57 -33
- package/src/components/DetailsPanel.tsx +2 -1
- package/src/components/Shell.tsx +103 -34
- package/src/components/StateHeader.tsx +96 -66
- package/src/components/UtilStateJsonTree.tsx +25 -0
- package/src/core.tsx +4 -4
- package/src/index.ts +1 -1
- package/src/styles/use-styles.ts +22 -1
- package/src/utils/read-pacer-store-state.ts +33 -0
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { createComponent, escape, ssr, ssrAttribute, ssrStyleProperty } from "solid-js/web";
|
|
1
|
+
import { createComponent, escape, ssr, ssrAttribute, ssrStyle, ssrStyleProperty } from "solid-js/web";
|
|
2
2
|
import { Header, HeaderLogo, JsonTree, MainPanel, ThemeContextProvider, useTheme } from "@tanstack/devtools-ui";
|
|
3
|
-
import { createStore } from "solid-js/store";
|
|
4
|
-
import { For, createContext, createEffect, createMemo, createSignal, onCleanup, onMount, useContext } from "solid-js";
|
|
5
|
-
import { pacerEventClient } from "@tanstack/pacer/event-client";
|
|
3
|
+
import { createStore, produce } from "solid-js/store";
|
|
4
|
+
import { For, Show, createContext, createEffect, createMemo, createSignal, onCleanup, onMount, useContext } from "solid-js";
|
|
5
|
+
import { getPacerDevtoolsInstance, pacerEventClient } from "@tanstack/pacer/event-client";
|
|
6
6
|
import * as goober from "goober";
|
|
7
7
|
import { useStore } from "@tanstack/solid-store";
|
|
8
8
|
import clsx from "clsx";
|
|
@@ -23,109 +23,78 @@ const initialPacerDevtoolsStore = {
|
|
|
23
23
|
lastUpdatedByKey: {}
|
|
24
24
|
};
|
|
25
25
|
const PacerDevtoolsContext = createContext([initialPacerDevtoolsStore, () => {}]);
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
26
|
+
/**
|
|
27
|
+
* Match TanStack Form devtools: subscribe with {@link pacerEventClient.on} per
|
|
28
|
+
* event suffix so the same `pacer:${suffix}` channel the library emits on is
|
|
29
|
+
* observed. `onAllPluginEvents` only sees `tanstack-devtools-global`, which is
|
|
30
|
+
* not always relayed the same way by the shell.
|
|
31
|
+
*
|
|
32
|
+
* `d-*` suffixes are used when the devtools panel pushes state back (see
|
|
33
|
+
* ActionButtons); those must update the panel store too.
|
|
34
|
+
*/
|
|
35
|
+
const PACER_DEVTOOLS_UTIL_EVENTS = [
|
|
36
|
+
{
|
|
37
|
+
listKey: "asyncBatchers",
|
|
38
|
+
suffixes: ["AsyncBatcher", "d-AsyncBatcher"]
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
listKey: "asyncDebouncers",
|
|
42
|
+
suffixes: ["AsyncDebouncer", "d-AsyncDebouncer"]
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
listKey: "asyncQueuers",
|
|
46
|
+
suffixes: ["AsyncQueuer", "d-AsyncQueuer"]
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
listKey: "asyncRateLimiters",
|
|
50
|
+
suffixes: ["AsyncRateLimiter", "d-AsyncRateLimiter"]
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
listKey: "asyncThrottlers",
|
|
54
|
+
suffixes: ["AsyncThrottler", "d-AsyncThrottler"]
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
listKey: "batchers",
|
|
58
|
+
suffixes: ["Batcher", "d-Batcher"]
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
listKey: "debouncers",
|
|
62
|
+
suffixes: ["Debouncer", "d-Debouncer"]
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
listKey: "queuers",
|
|
66
|
+
suffixes: ["Queuer", "d-Queuer"]
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
listKey: "rateLimiters",
|
|
70
|
+
suffixes: ["RateLimiter", "d-RateLimiter"]
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
listKey: "throttlers",
|
|
74
|
+
suffixes: ["Throttler", "d-Throttler"]
|
|
75
|
+
}
|
|
76
|
+
];
|
|
31
77
|
function PacerContextProvider(props) {
|
|
32
78
|
const [store, setStore] = createStore(initialPacerDevtoolsStore);
|
|
33
79
|
createEffect(() => {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
asyncDebouncers: updateOrAddToArray(store.asyncDebouncers, e.payload),
|
|
49
|
-
lastUpdatedByKey: {
|
|
50
|
-
...store.lastUpdatedByKey,
|
|
51
|
-
[e.payload.key]: Date.now()
|
|
52
|
-
}
|
|
53
|
-
});
|
|
54
|
-
break;
|
|
55
|
-
case "pacer:AsyncQueuer":
|
|
56
|
-
setStore({
|
|
57
|
-
asyncQueuers: updateOrAddToArray(store.asyncQueuers, e.payload),
|
|
58
|
-
lastUpdatedByKey: {
|
|
59
|
-
...store.lastUpdatedByKey,
|
|
60
|
-
[e.payload.key]: Date.now()
|
|
61
|
-
}
|
|
62
|
-
});
|
|
63
|
-
break;
|
|
64
|
-
case "pacer:AsyncRateLimiter":
|
|
65
|
-
setStore({
|
|
66
|
-
asyncRateLimiters: updateOrAddToArray(store.asyncRateLimiters, e.payload),
|
|
67
|
-
lastUpdatedByKey: {
|
|
68
|
-
...store.lastUpdatedByKey,
|
|
69
|
-
[e.payload.key]: Date.now()
|
|
70
|
-
}
|
|
71
|
-
});
|
|
72
|
-
break;
|
|
73
|
-
case "pacer:AsyncThrottler":
|
|
74
|
-
setStore({
|
|
75
|
-
asyncThrottlers: updateOrAddToArray(store.asyncThrottlers, e.payload),
|
|
76
|
-
lastUpdatedByKey: {
|
|
77
|
-
...store.lastUpdatedByKey,
|
|
78
|
-
[e.payload.key]: Date.now()
|
|
79
|
-
}
|
|
80
|
-
});
|
|
81
|
-
break;
|
|
82
|
-
case "pacer:Batcher":
|
|
83
|
-
setStore({
|
|
84
|
-
batchers: updateOrAddToArray(store.batchers, e.payload),
|
|
85
|
-
lastUpdatedByKey: {
|
|
86
|
-
...store.lastUpdatedByKey,
|
|
87
|
-
[e.payload.key]: Date.now()
|
|
88
|
-
}
|
|
89
|
-
});
|
|
90
|
-
break;
|
|
91
|
-
case "pacer:Debouncer":
|
|
92
|
-
setStore({
|
|
93
|
-
debouncers: updateOrAddToArray(store.debouncers, e.payload),
|
|
94
|
-
lastUpdatedByKey: {
|
|
95
|
-
...store.lastUpdatedByKey,
|
|
96
|
-
[e.payload.key]: Date.now()
|
|
97
|
-
}
|
|
98
|
-
});
|
|
99
|
-
break;
|
|
100
|
-
case "pacer:Queuer":
|
|
101
|
-
setStore({
|
|
102
|
-
queuers: updateOrAddToArray(store.queuers, e.payload),
|
|
103
|
-
lastUpdatedByKey: {
|
|
104
|
-
...store.lastUpdatedByKey,
|
|
105
|
-
[e.payload.key]: Date.now()
|
|
106
|
-
}
|
|
107
|
-
});
|
|
108
|
-
break;
|
|
109
|
-
case "pacer:RateLimiter":
|
|
110
|
-
setStore({
|
|
111
|
-
rateLimiters: updateOrAddToArray(store.rateLimiters, e.payload),
|
|
112
|
-
lastUpdatedByKey: {
|
|
113
|
-
...store.lastUpdatedByKey,
|
|
114
|
-
[e.payload.key]: Date.now()
|
|
115
|
-
}
|
|
116
|
-
});
|
|
117
|
-
break;
|
|
118
|
-
case "pacer:Throttler":
|
|
119
|
-
setStore({
|
|
120
|
-
throttlers: updateOrAddToArray(store.throttlers, e.payload),
|
|
121
|
-
lastUpdatedByKey: {
|
|
122
|
-
...store.lastUpdatedByKey,
|
|
123
|
-
[e.payload.key]: Date.now()
|
|
124
|
-
}
|
|
125
|
-
});
|
|
126
|
-
break;
|
|
127
|
-
}
|
|
80
|
+
const cleanups = [];
|
|
81
|
+
for (const { listKey, suffixes } of PACER_DEVTOOLS_UTIL_EVENTS) for (const suffix of suffixes) cleanups.push(pacerEventClient.on(suffix, (e) => {
|
|
82
|
+
const key = e.payload.key;
|
|
83
|
+
if (!key) return;
|
|
84
|
+
const instance = getPacerDevtoolsInstance(key);
|
|
85
|
+
if (!instance || typeof instance !== "object") return;
|
|
86
|
+
setStore(produce((draft) => {
|
|
87
|
+
const list = draft[listKey];
|
|
88
|
+
const index = list.findIndex((item) => item.key === key);
|
|
89
|
+
const inst = instance;
|
|
90
|
+
if (index !== -1) list[index] = inst;
|
|
91
|
+
else list.push(inst);
|
|
92
|
+
draft.lastUpdatedByKey[key] = Date.now();
|
|
93
|
+
}));
|
|
128
94
|
}));
|
|
95
|
+
onCleanup(() => {
|
|
96
|
+
for (const cleanup of cleanups) cleanup();
|
|
97
|
+
});
|
|
129
98
|
});
|
|
130
99
|
return createComponent(PacerDevtoolsContext.Provider, {
|
|
131
100
|
value: [store, setStore],
|
|
@@ -447,9 +416,25 @@ const stylesFactory = (theme) => {
|
|
|
447
416
|
const css = goober.css;
|
|
448
417
|
const t = (light, dark) => theme === "light" ? light : dark;
|
|
449
418
|
return {
|
|
419
|
+
shellRoot: css`
|
|
420
|
+
display: flex;
|
|
421
|
+
flex-direction: column;
|
|
422
|
+
box-sizing: border-box;
|
|
423
|
+
width: 100%;
|
|
424
|
+
height: 100%;
|
|
425
|
+
min-height: 0;
|
|
426
|
+
overflow: hidden;
|
|
427
|
+
`,
|
|
428
|
+
mainPanelShell: css`
|
|
429
|
+
display: flex;
|
|
430
|
+
flex-direction: column;
|
|
431
|
+
flex: 1 1 0%;
|
|
432
|
+
min-height: 0;
|
|
433
|
+
overflow: hidden !important;
|
|
434
|
+
`,
|
|
450
435
|
mainContainer: css`
|
|
451
436
|
display: flex;
|
|
452
|
-
flex: 1
|
|
437
|
+
flex: 1 1 0%;
|
|
453
438
|
min-height: 0;
|
|
454
439
|
overflow: hidden;
|
|
455
440
|
padding: ${size[2]};
|
|
@@ -855,7 +840,7 @@ var _tmpl$$4 = [
|
|
|
855
840
|
"<div",
|
|
856
841
|
">",
|
|
857
842
|
"</div>"
|
|
858
|
-
], _tmpl$2$
|
|
843
|
+
], _tmpl$2$3 = [
|
|
859
844
|
"<div",
|
|
860
845
|
"><div",
|
|
861
846
|
">",
|
|
@@ -873,7 +858,7 @@ function UtilList(props) {
|
|
|
873
858
|
const styles = useStyles();
|
|
874
859
|
return ssr(_tmpl$$4, ssrAttribute("class", escape(styles().utilList, true), false), escape(createComponent(For, {
|
|
875
860
|
each: UTIL_GROUPS,
|
|
876
|
-
children: (group) => props.utilState()[group.key].length > 0 && ssr(_tmpl$2$
|
|
861
|
+
children: (group) => props.utilState()[group.key].length > 0 && ssr(_tmpl$2$3, ssrAttribute("class", escape(styles().utilGroup, true), false), ssrAttribute("class", escape(styles().utilGroupHeader, true), false), escape(group.label), escape(createComponent(For, {
|
|
877
862
|
get each() {
|
|
878
863
|
return props.utilState()[group.key];
|
|
879
864
|
},
|
|
@@ -892,8 +877,25 @@ function UtilList(props) {
|
|
|
892
877
|
})));
|
|
893
878
|
}
|
|
894
879
|
//#endregion
|
|
880
|
+
//#region src/utils/read-pacer-store-state.ts
|
|
881
|
+
/** TanStack Store (`@tanstack/store`) used by pacer utils. */
|
|
882
|
+
function isPacerUtilTanStackStore(x) {
|
|
883
|
+
return typeof x === "object" && x !== null && "subscribe" in x && typeof x.subscribe === "function" && "get" in x && typeof x.get === "function";
|
|
884
|
+
}
|
|
885
|
+
/**
|
|
886
|
+
* Core pacer utils expose TanStack `Store` (`get()` / `state`). React hooks may
|
|
887
|
+
* also expose a reactive `state` field. Use this for devtools UI that needs a
|
|
888
|
+
* plain snapshot (e.g. JsonTree).
|
|
889
|
+
*/
|
|
890
|
+
function getPacerUtilStoreState(instance) {
|
|
891
|
+
const store = instance.store;
|
|
892
|
+
if (store && typeof store.get === "function") return store.get();
|
|
893
|
+
if (store && store.state !== void 0) return store.state;
|
|
894
|
+
return instance.state;
|
|
895
|
+
}
|
|
896
|
+
//#endregion
|
|
895
897
|
//#region src/components/ActionButtons.tsx
|
|
896
|
-
var _tmpl$$3 = ["<div", ">No actions available for this util</div>"], _tmpl$2$
|
|
898
|
+
var _tmpl$$3 = ["<div", ">No actions available for this util</div>"], _tmpl$2$2 = [
|
|
897
899
|
"<div",
|
|
898
900
|
">",
|
|
899
901
|
"",
|
|
@@ -930,11 +932,20 @@ var _tmpl$$3 = ["<div", ">No actions available for this util</div>"], _tmpl$2$1
|
|
|
930
932
|
function ActionButtons(props) {
|
|
931
933
|
const styles = useStyles();
|
|
932
934
|
const utilInstance = props.instance;
|
|
933
|
-
const
|
|
934
|
-
const
|
|
935
|
-
const
|
|
936
|
-
const
|
|
937
|
-
|
|
935
|
+
const store = utilInstance?.store;
|
|
936
|
+
const stateAccessor = isPacerUtilTanStackStore(store) ? useStore(store, (s) => s !== null && s !== void 0 && typeof s === "object" ? s : {}) : () => getPacerUtilStoreState(utilInstance);
|
|
937
|
+
const getState = () => stateAccessor();
|
|
938
|
+
const hasPending = () => {
|
|
939
|
+
return "isPending" in getState();
|
|
940
|
+
};
|
|
941
|
+
const isPending = () => {
|
|
942
|
+
const u = getState();
|
|
943
|
+
return "isPending" in u ? !!u.isPending : false;
|
|
944
|
+
};
|
|
945
|
+
const isEmptyFlag = () => {
|
|
946
|
+
const u = getState();
|
|
947
|
+
return "isEmpty" in u ? !!u.isEmpty : false;
|
|
948
|
+
};
|
|
938
949
|
const hasFlush = typeof utilInstance.flush === "function";
|
|
939
950
|
const hasCancel = typeof utilInstance.cancel === "function";
|
|
940
951
|
const hasReset = typeof utilInstance.reset === "function";
|
|
@@ -942,10 +953,14 @@ function ActionButtons(props) {
|
|
|
942
953
|
const hasStart = typeof utilInstance.start === "function";
|
|
943
954
|
const hasStop = typeof utilInstance.stop === "function";
|
|
944
955
|
const hasStartStop = hasStart && hasStop;
|
|
945
|
-
const isRunning =
|
|
946
|
-
|
|
956
|
+
const isRunning = () => {
|
|
957
|
+
const u = getState();
|
|
958
|
+
return "isRunning" in u ? !!u.isRunning : true;
|
|
959
|
+
};
|
|
960
|
+
if (!hasPending() && !hasFlush && !hasCancel && !hasReset && !hasClear) return ssr(_tmpl$$3, ssrAttribute("class", escape(styles().sectionEmpty, true), false));
|
|
947
961
|
`${props.utilName}`;
|
|
948
|
-
|
|
962
|
+
const utilNameLower = props.utilName.toLowerCase();
|
|
963
|
+
return ssr(_tmpl$2$2, ssrAttribute("class", escape(styles().actionsRow, true), false), hasPending() && ssr(_tmpl$3$1, ssrAttribute("class", escape(styles().actionButton, true), false), ssrAttribute("class", escape(styles().actionDotBlue, true), false), isPending() ? "Restore Pending" : "Trigger Pending"), hasFlush && ssr(_tmpl$4, ssrAttribute("class", escape(styles().actionButton, true), false), ssrAttribute("disabled", utilNameLower.includes("debouncer") && !isPending() || utilNameLower.includes("throttler") && !isPending() || utilNameLower.includes("batcher") && isEmptyFlag() || utilNameLower.includes("queuer") && isEmptyFlag(), true), ssrAttribute("class", escape(styles().actionDotGreen, true), false)), hasCancel && ssr(_tmpl$5, ssrAttribute("class", escape(styles().actionButton, true), false), ssrAttribute("disabled", utilNameLower.includes("debouncer") && !isPending() || utilNameLower.includes("throttler") && !isPending() || utilNameLower.includes("batcher") && isEmptyFlag() || utilNameLower.includes("queuer") && isEmptyFlag(), true), ssrAttribute("class", escape(styles().actionDotRed, true), false)), hasReset && ssr(_tmpl$6, ssrAttribute("class", escape(styles().actionButton, true), false), ssrAttribute("class", escape(styles().actionDotYellow, true), false)), hasClear && ssr(_tmpl$7, ssrAttribute("class", escape(styles().actionButton, true), false), ssrAttribute("disabled", utilNameLower.includes("batcher") && isEmptyFlag() || utilNameLower.includes("queuer") && isEmptyFlag(), true), ssrAttribute("class", escape(styles().actionDotOrange, true), false)), hasStartStop && ssr(_tmpl$3$1, ssrAttribute("class", escape(styles().actionButton, true), false), ssrAttribute("class", escape(styles().actionDotPurple, true), false), isRunning() ? "Stop" : "Start"));
|
|
949
964
|
}
|
|
950
965
|
//#endregion
|
|
951
966
|
//#region src/components/StateHeader.tsx
|
|
@@ -968,6 +983,37 @@ var _tmpl$$2 = [
|
|
|
968
983
|
"% reduction</div></div></div>"
|
|
969
984
|
];
|
|
970
985
|
dayjs.extend(relativeTime);
|
|
986
|
+
function reductionFromState(entry, state) {
|
|
987
|
+
if (!state) return 0;
|
|
988
|
+
const completedExecutions = entry.type.toLowerCase().includes("async") ? Number(state.settleCount) || 0 : Number(state.executionCount) || 0;
|
|
989
|
+
if (entry.type.toLowerCase().includes("batcher")) {
|
|
990
|
+
const totalItemsProcessed = Number(state.totalItemsProcessed) || 0;
|
|
991
|
+
if (totalItemsProcessed === 0) return 0;
|
|
992
|
+
return Math.round((totalItemsProcessed - completedExecutions) / totalItemsProcessed * 100);
|
|
993
|
+
}
|
|
994
|
+
let requestCount = 0;
|
|
995
|
+
if (state.maybeExecuteCount !== void 0) requestCount = Number(state.maybeExecuteCount) || 0;
|
|
996
|
+
else if (state.addItemCount !== void 0) requestCount = Number(state.addItemCount) || 0;
|
|
997
|
+
else return 0;
|
|
998
|
+
if (requestCount === 0) return 0;
|
|
999
|
+
const reduction = requestCount - completedExecutions;
|
|
1000
|
+
return Math.round(reduction / requestCount * 100);
|
|
1001
|
+
}
|
|
1002
|
+
function StateHeaderInner(props) {
|
|
1003
|
+
const key = props.entry.instance.key;
|
|
1004
|
+
const updatedAt = () => props.utilState().lastUpdatedByKey[key] ?? Date.now();
|
|
1005
|
+
const getRelativeTime = () => {
|
|
1006
|
+
const at = updatedAt();
|
|
1007
|
+
const diffMs = props.now() - at;
|
|
1008
|
+
const diffSeconds = Math.floor(diffMs / 1e3);
|
|
1009
|
+
if (diffSeconds < 60) return `${diffSeconds} second${diffSeconds !== 1 ? "s" : ""} ago`;
|
|
1010
|
+
return dayjs(at).fromNow();
|
|
1011
|
+
};
|
|
1012
|
+
const store = props.entry.instance?.store;
|
|
1013
|
+
const stateAccessor = isPacerUtilTanStackStore(store) ? useStore(store, (s) => s !== null && s !== void 0 && typeof s === "object" ? s : {}) : () => getPacerUtilStoreState(props.entry.instance);
|
|
1014
|
+
const reductionPercentage = () => reductionFromState(props.entry, stateAccessor());
|
|
1015
|
+
return ssr(_tmpl$$2, ssrAttribute("class", escape(props.styles.stateHeader, true), false), ssrAttribute("class", escape(props.styles.stateTitle, true), false), escape(props.entry.type), ssrStyleProperty("display:", "flex") + ssrStyleProperty(";align-items:", "center") + ssrStyleProperty(";gap:", "16px"), ssrAttribute("class", escape(props.styles.infoGrid, true), false), ssrAttribute("class", escape(props.styles.infoLabel, true), false), ssrAttribute("class", escape(props.styles.infoValueMono, true), false), escape(key), ssrAttribute("class", escape(props.styles.infoLabel, true), false), ssrAttribute("class", escape(props.styles.infoValueMono, true), false), escape(new Date(updatedAt()).toLocaleTimeString()), escape(getRelativeTime()), ssrAttribute("class", escape(props.styles.infoValueMono, true), false), ssrStyleProperty("margin-left:", "auto") + ssrStyleProperty(";font-weight:", "bold"), escape(reductionPercentage()));
|
|
1016
|
+
}
|
|
971
1017
|
function StateHeader(props) {
|
|
972
1018
|
const styles = useStyles();
|
|
973
1019
|
const [now, setNow] = createSignal(Date.now());
|
|
@@ -979,35 +1025,42 @@ function StateHeader(props) {
|
|
|
979
1025
|
clearInterval(interval);
|
|
980
1026
|
});
|
|
981
1027
|
});
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1028
|
+
return createComponent(Show, {
|
|
1029
|
+
get when() {
|
|
1030
|
+
return props.selectedInstance();
|
|
1031
|
+
},
|
|
1032
|
+
children: (entry) => createComponent(StateHeaderInner, {
|
|
1033
|
+
get entry() {
|
|
1034
|
+
return entry();
|
|
1035
|
+
},
|
|
1036
|
+
get styles() {
|
|
1037
|
+
return styles();
|
|
1038
|
+
},
|
|
1039
|
+
now,
|
|
1040
|
+
get utilState() {
|
|
1041
|
+
return props.utilState;
|
|
1042
|
+
}
|
|
1043
|
+
})
|
|
1044
|
+
});
|
|
1045
|
+
}
|
|
1046
|
+
//#endregion
|
|
1047
|
+
//#region src/components/UtilStateJsonTree.tsx
|
|
1048
|
+
/**
|
|
1049
|
+
* Subscribes to the util's TanStack Store so the tree updates live (same
|
|
1050
|
+
* idea as {@link UtilList} status). A plain snapshot would only refresh when the
|
|
1051
|
+
* devtools shell re-renders, which does not happen on nested store updates.
|
|
1052
|
+
*/
|
|
1053
|
+
function UtilStateJsonTree(props) {
|
|
1054
|
+
const store = props.instance?.store;
|
|
1055
|
+
if (isPacerUtilTanStackStore(store)) {
|
|
1056
|
+
const snapshot = useStore(store, (s) => s);
|
|
1057
|
+
return createComponent(JsonTree, { get value() {
|
|
1058
|
+
return snapshot();
|
|
1059
|
+
} });
|
|
1060
|
+
}
|
|
1061
|
+
return createComponent(JsonTree, { get value() {
|
|
1062
|
+
return getPacerUtilStoreState(props.instance);
|
|
1063
|
+
} });
|
|
1011
1064
|
}
|
|
1012
1065
|
//#endregion
|
|
1013
1066
|
//#region src/components/DetailsPanel.tsx
|
|
@@ -1015,7 +1068,7 @@ var _tmpl$$1 = [
|
|
|
1015
1068
|
"<div",
|
|
1016
1069
|
">",
|
|
1017
1070
|
"</div>"
|
|
1018
|
-
], _tmpl$2 = ["<div", ">Select a util from the left panel to view its state</div>"], _tmpl$3 = [
|
|
1071
|
+
], _tmpl$2$1 = ["<div", ">Select a util from the left panel to view its state</div>"], _tmpl$3 = [
|
|
1019
1072
|
"<div",
|
|
1020
1073
|
"><div",
|
|
1021
1074
|
"><div",
|
|
@@ -1034,7 +1087,7 @@ function DetailsPanel(props) {
|
|
|
1034
1087
|
const styles = useStyles();
|
|
1035
1088
|
return ssr(_tmpl$$1, ssrAttribute("class", escape(styles().stateDetails, true), false), (() => {
|
|
1036
1089
|
const entry = props.selectedInstance();
|
|
1037
|
-
if (!entry) return ssr(_tmpl$2, ssrAttribute("class", escape(styles().noSelection, true), false));
|
|
1090
|
+
if (!entry) return ssr(_tmpl$2$1, ssrAttribute("class", escape(styles().noSelection, true), false));
|
|
1038
1091
|
return escape([createComponent(StateHeader, {
|
|
1039
1092
|
get selectedInstance() {
|
|
1040
1093
|
return props.selectedInstance;
|
|
@@ -1049,8 +1102,8 @@ function DetailsPanel(props) {
|
|
|
1049
1102
|
get utilName() {
|
|
1050
1103
|
return entry.type;
|
|
1051
1104
|
}
|
|
1052
|
-
})), ssrAttribute("class", escape(styles().detailSection, true), false), ssrAttribute("class", escape(styles().detailSectionHeader, true), false), ssrAttribute("class", escape(styles().stateContent, true), false), escape(createComponent(
|
|
1053
|
-
return entry.instance
|
|
1105
|
+
})), ssrAttribute("class", escape(styles().detailSection, true), false), ssrAttribute("class", escape(styles().detailSectionHeader, true), false), ssrAttribute("class", escape(styles().stateContent, true), false), escape(createComponent(UtilStateJsonTree, { get instance() {
|
|
1106
|
+
return entry.instance;
|
|
1054
1107
|
} })), ssrAttribute("class", escape(styles().detailSection, true), false), ssrAttribute("class", escape(styles().detailSectionHeader, true), false), ssrAttribute("class", escape(styles().stateContent, true), false), escape(createComponent(JsonTree, { get value() {
|
|
1055
1108
|
return entry.instance.options;
|
|
1056
1109
|
} })))]);
|
|
@@ -1069,7 +1122,23 @@ var _tmpl$ = [
|
|
|
1069
1122
|
"\"><div",
|
|
1070
1123
|
">Details</div>",
|
|
1071
1124
|
"</div></div>"
|
|
1125
|
+
], _tmpl$2 = [
|
|
1126
|
+
"<div",
|
|
1127
|
+
" style=\"",
|
|
1128
|
+
"\">",
|
|
1129
|
+
"</div>"
|
|
1072
1130
|
];
|
|
1131
|
+
function readResizeObserverBlockSize(entry) {
|
|
1132
|
+
const [box] = entry.borderBoxSize;
|
|
1133
|
+
if (box !== void 0) return box.blockSize;
|
|
1134
|
+
return entry.contentRect.height;
|
|
1135
|
+
}
|
|
1136
|
+
/** Outer plugin slot from TanStack Devtools (not the inner React mount div, which can report a tiny height). */
|
|
1137
|
+
function resolvePluginHost(el) {
|
|
1138
|
+
const byId = el.closest("[id^=\"plugin-container-\"]");
|
|
1139
|
+
if (byId) return byId;
|
|
1140
|
+
return el.parentElement?.parentElement?.parentElement ?? el.parentElement?.parentElement ?? el.parentElement;
|
|
1141
|
+
}
|
|
1073
1142
|
function Shell() {
|
|
1074
1143
|
const styles = useStyles();
|
|
1075
1144
|
const state = usePacerDevtoolsState();
|
|
@@ -1077,6 +1146,8 @@ function Shell() {
|
|
|
1077
1146
|
const [selectedKey, setSelectedKey] = createSignal(null);
|
|
1078
1147
|
const [leftPanelWidth, setLeftPanelWidth] = createSignal(300);
|
|
1079
1148
|
const [isDragging, setIsDragging] = createSignal(false);
|
|
1149
|
+
const [shellRootEl, setShellRootEl] = createSignal(null);
|
|
1150
|
+
const [slotHeightPx, setSlotHeightPx] = createSignal(void 0);
|
|
1080
1151
|
const selectedInstance = createMemo(() => {
|
|
1081
1152
|
const key = selectedKey();
|
|
1082
1153
|
if (!key) return null;
|
|
@@ -1110,24 +1181,54 @@ function Shell() {
|
|
|
1110
1181
|
document.removeEventListener("mousemove", handleMouseMove);
|
|
1111
1182
|
document.removeEventListener("mouseup", handleMouseUp);
|
|
1112
1183
|
});
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1184
|
+
/**
|
|
1185
|
+
* TanStack Devtools plugin slots use height: 100% without min-height: 0 on flex
|
|
1186
|
+
* ancestors, so percentage height often never constrains our tree. Observing the
|
|
1187
|
+
* outer `plugin-container-*` host (not the immediate React mount wrapper) and
|
|
1188
|
+
* setting an explicit pixel height makes inner overflow-y regions scroll without
|
|
1189
|
+
* capping to the mount div’s collapsed height.
|
|
1190
|
+
*/
|
|
1191
|
+
createEffect(() => {
|
|
1192
|
+
const el = shellRootEl();
|
|
1193
|
+
if (!el || typeof ResizeObserver === "undefined") return;
|
|
1194
|
+
const pluginSlot = resolvePluginHost(el);
|
|
1195
|
+
if (!pluginSlot) return;
|
|
1196
|
+
const ro = new ResizeObserver((entries) => {
|
|
1197
|
+
const entry = entries[0];
|
|
1198
|
+
if (!entry) return;
|
|
1199
|
+
const target = entry.target;
|
|
1200
|
+
const h = target.clientHeight > 0 ? target.clientHeight : readResizeObserverBlockSize(entry);
|
|
1201
|
+
if (h > 0) setSlotHeightPx(Math.round(h));
|
|
1202
|
+
});
|
|
1203
|
+
ro.observe(pluginSlot);
|
|
1204
|
+
onCleanup(() => ro.disconnect());
|
|
1205
|
+
});
|
|
1206
|
+
return ssr(_tmpl$2, ssrAttribute("class", escape(styles().shellRoot, true), false), ssrStyle({ ...slotHeightPx() !== void 0 ? {
|
|
1207
|
+
height: `${slotHeightPx()}px`,
|
|
1208
|
+
"max-height": `${slotHeightPx()}px`
|
|
1209
|
+
} : {} }), escape(createComponent(MainPanel, {
|
|
1210
|
+
get ["class"]() {
|
|
1211
|
+
return styles().mainPanelShell;
|
|
1212
|
+
},
|
|
1213
|
+
get children() {
|
|
1214
|
+
return [createComponent(Header, { get children() {
|
|
1215
|
+
return createComponent(HeaderLogo, {
|
|
1216
|
+
flavor: {
|
|
1217
|
+
light: "#84cc16",
|
|
1218
|
+
dark: "#84cc16"
|
|
1219
|
+
},
|
|
1220
|
+
children: "TanStack Pacer"
|
|
1221
|
+
});
|
|
1222
|
+
} }), ssr(_tmpl$, ssrAttribute("class", escape(styles().mainContainer, true), false), ssrAttribute("class", escape(styles().leftPanel, true), false), ssrStyleProperty("width:", `${escape(leftPanelWidth(), true)}px`) + ssrStyleProperty(";min-width:", "150px") + ssrStyleProperty(";max-width:", "800px"), escape(createComponent(UtilList, {
|
|
1223
|
+
selectedKey,
|
|
1224
|
+
setSelectedKey,
|
|
1225
|
+
utilState
|
|
1226
|
+
})), `${escape(styles().dragHandle, true)} ${isDragging() ? "dragging" : ""}`, ssrAttribute("class", escape(styles().rightPanel, true), false), ssrStyleProperty("flex:", 1), ssrAttribute("class", escape(styles().panelHeader, true), false), escape(createComponent(DetailsPanel, {
|
|
1227
|
+
selectedInstance,
|
|
1228
|
+
utilState
|
|
1229
|
+
})))];
|
|
1230
|
+
}
|
|
1231
|
+
})));
|
|
1131
1232
|
}
|
|
1132
1233
|
//#endregion
|
|
1133
1234
|
//#region src/components/index.tsx
|
package/dist/index.d.ts
CHANGED
|
@@ -1,14 +1,10 @@
|
|
|
1
|
+
import { ClassType } from "@tanstack/devtools-utils/solid";
|
|
2
|
+
|
|
1
3
|
//#region src/core.d.ts
|
|
2
4
|
interface PacerDevtoolsInit {}
|
|
5
|
+
declare const PacerDevtoolsCore$1: ClassType;
|
|
3
6
|
//#endregion
|
|
4
7
|
//#region src/index.d.ts
|
|
5
|
-
declare const PacerDevtoolsCore:
|
|
6
|
-
"__#private@#isMounted": boolean;
|
|
7
|
-
"__#private@#isMounting": boolean;
|
|
8
|
-
"__#private@#abortMount": boolean;
|
|
9
|
-
"__#private@#dispose"?: () => void;
|
|
10
|
-
mount<T extends HTMLElement>(el: T, props: TanStackDevtoolsPluginProps): Promise<void>;
|
|
11
|
-
unmount(): void;
|
|
12
|
-
};
|
|
8
|
+
declare const PacerDevtoolsCore: typeof PacerDevtoolsCore$1;
|
|
13
9
|
//#endregion
|
|
14
10
|
export { PacerDevtoolsCore, type PacerDevtoolsInit };
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { constructCoreClass } from "@tanstack/devtools-utils/solid";
|
|
3
3
|
//#region src/core.tsx
|
|
4
|
-
const
|
|
4
|
+
const coreClasses = constructCoreClass(() => import("./components-CGEHIK6F.js"));
|
|
5
|
+
const PacerDevtoolsCore$1 = coreClasses[0];
|
|
6
|
+
const PacerDevtoolsCoreNoOp = coreClasses[1];
|
|
5
7
|
//#endregion
|
|
6
8
|
//#region src/index.ts
|
|
7
9
|
const PacerDevtoolsCore = process.env.NODE_ENV !== "development" ? PacerDevtoolsCoreNoOp : PacerDevtoolsCore$1;
|
|
@@ -1,19 +1,7 @@
|
|
|
1
|
+
import { ClassType } from "@tanstack/devtools-utils/solid";
|
|
2
|
+
|
|
1
3
|
//#region src/core.d.ts
|
|
2
4
|
interface PacerDevtoolsInit {}
|
|
3
|
-
declare const PacerDevtoolsCore:
|
|
4
|
-
"__#private@#isMounted": boolean;
|
|
5
|
-
"__#private@#isMounting": boolean;
|
|
6
|
-
"__#private@#abortMount": boolean;
|
|
7
|
-
"__#private@#dispose"?: () => void;
|
|
8
|
-
mount<T extends HTMLElement>(el: T, props: TanStackDevtoolsPluginProps): Promise<void>;
|
|
9
|
-
unmount(): void;
|
|
10
|
-
}, PacerDevtoolsCoreNoOp: new () => {
|
|
11
|
-
mount<T extends HTMLElement>(_el: T, _props: TanStackDevtoolsPluginProps): Promise<void>;
|
|
12
|
-
unmount(): void;
|
|
13
|
-
"__#private@#isMounted": boolean;
|
|
14
|
-
"__#private@#isMounting": boolean;
|
|
15
|
-
"__#private@#abortMount": boolean;
|
|
16
|
-
"__#private@#dispose"?: () => void;
|
|
17
|
-
};
|
|
5
|
+
declare const PacerDevtoolsCore: ClassType;
|
|
18
6
|
//#endregion
|
|
19
7
|
export { PacerDevtoolsCore, type PacerDevtoolsInit };
|
package/dist/production/index.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { constructCoreClass } from "@tanstack/devtools-utils/solid";
|
|
3
3
|
//#region src/core.tsx
|
|
4
|
-
const
|
|
4
|
+
const coreClasses = constructCoreClass(() => import("../components-CGEHIK6F.js"));
|
|
5
|
+
const PacerDevtoolsCore = coreClasses[0];
|
|
6
|
+
coreClasses[1];
|
|
5
7
|
//#endregion
|
|
6
8
|
export { PacerDevtoolsCore };
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { constructCoreClass } from "@tanstack/devtools-utils/solid";
|
|
3
3
|
//#region src/core.tsx
|
|
4
|
-
const
|
|
4
|
+
const coreClasses = constructCoreClass(() => import("../components-vap4_VJT.js"));
|
|
5
|
+
const PacerDevtoolsCore = coreClasses[0];
|
|
6
|
+
coreClasses[1];
|
|
5
7
|
//#endregion
|
|
6
8
|
export { PacerDevtoolsCore };
|
package/dist/server.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { constructCoreClass } from "@tanstack/devtools-utils/solid";
|
|
3
3
|
//#region src/core.tsx
|
|
4
|
-
const
|
|
4
|
+
const coreClasses = constructCoreClass(() => import("./components-vap4_VJT.js"));
|
|
5
|
+
const PacerDevtoolsCore$1 = coreClasses[0];
|
|
6
|
+
const PacerDevtoolsCoreNoOp = coreClasses[1];
|
|
5
7
|
//#endregion
|
|
6
8
|
//#region src/index.ts
|
|
7
9
|
const PacerDevtoolsCore = process.env.NODE_ENV !== "development" ? PacerDevtoolsCoreNoOp : PacerDevtoolsCore$1;
|