react-state-inspector-devtools 0.1.2 → 1.0.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/dist/index.js +720 -244
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +723 -247
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -3
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/provider.tsx
|
|
2
|
-
import { createContext, useContext, useEffect, useId, useMemo
|
|
2
|
+
import { createContext, useContext, useEffect, useId, useMemo } from "react";
|
|
3
3
|
|
|
4
4
|
// src/store.ts
|
|
5
5
|
function createInspectorStore() {
|
|
@@ -84,16 +84,22 @@ function createInspectorStore() {
|
|
|
84
84
|
// src/provider.tsx
|
|
85
85
|
import { jsx } from "react/jsx-runtime";
|
|
86
86
|
var InspectorContext = createContext(null);
|
|
87
|
+
var storeRef = { current: null };
|
|
88
|
+
function getStore() {
|
|
89
|
+
if (!storeRef.current) {
|
|
90
|
+
storeRef.current = createInspectorStore();
|
|
91
|
+
}
|
|
92
|
+
return storeRef.current;
|
|
93
|
+
}
|
|
87
94
|
function StateInspectorProvider({
|
|
88
95
|
enabled = true,
|
|
89
96
|
children
|
|
90
97
|
}) {
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
storeRef.current =
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
return /* @__PURE__ */ jsx(InspectorContext.Provider, { value: storeRef.current, children });
|
|
98
|
+
const store = useMemo(() => getStore(), []);
|
|
99
|
+
useEffect(() => {
|
|
100
|
+
storeRef.current.enabled = enabled;
|
|
101
|
+
}, [enabled]);
|
|
102
|
+
return /* @__PURE__ */ jsx(InspectorContext.Provider, { value: store, children });
|
|
97
103
|
}
|
|
98
104
|
function useInspectorStore() {
|
|
99
105
|
const ctx = useContext(InspectorContext);
|
|
@@ -122,7 +128,7 @@ function useInspectorComponent(label) {
|
|
|
122
128
|
}
|
|
123
129
|
|
|
124
130
|
// src/hooks.ts
|
|
125
|
-
import { useEffect as useEffect2, useId as useId2, useMemo as useMemo2, useRef
|
|
131
|
+
import { useEffect as useEffect2, useId as useId2, useMemo as useMemo2, useRef, useState } from "react";
|
|
126
132
|
function stableKey(input) {
|
|
127
133
|
return input.trim();
|
|
128
134
|
}
|
|
@@ -139,7 +145,7 @@ function useInspectableState(component, key, initial, meta) {
|
|
|
139
145
|
const componentId = component.id;
|
|
140
146
|
const stateKey = useMemo2(() => stableKey(key), [key]);
|
|
141
147
|
const [value, setValue] = useState(initial);
|
|
142
|
-
const setValueRef =
|
|
148
|
+
const setValueRef = useRef(() => {
|
|
143
149
|
});
|
|
144
150
|
setValueRef.current = (next) => {
|
|
145
151
|
setValue(next);
|
|
@@ -182,189 +188,397 @@ function useComponentLabel(label) {
|
|
|
182
188
|
}
|
|
183
189
|
|
|
184
190
|
// src/StateInspectorUI.tsx
|
|
185
|
-
import { useEffect as
|
|
191
|
+
import { useEffect as useEffect4, useMemo as useMemo3, useRef as useRef2, useState as useState3 } from "react";
|
|
186
192
|
import { createPortal } from "react-dom";
|
|
187
|
-
|
|
193
|
+
|
|
194
|
+
// src/ui/constants.ts
|
|
195
|
+
var LS_LAYOUT = "rsi:panel-layout";
|
|
196
|
+
var LS_KEY = "rsi:panel-pos";
|
|
197
|
+
var LS_SIZE = "rsi:panel-size";
|
|
198
|
+
var LS_LEFT_W = "rsi:left-width";
|
|
199
|
+
var SNAP = 100;
|
|
200
|
+
var DOCK_W = 420;
|
|
201
|
+
var DOCK_H = 320;
|
|
202
|
+
var MARGIN = 12;
|
|
203
|
+
var LEFT_MIN = 180;
|
|
204
|
+
var LEFT_MAX = 420;
|
|
205
|
+
var isMac = typeof navigator !== "undefined" ? navigator.platform.toUpperCase().includes("MAC") : false;
|
|
206
|
+
|
|
207
|
+
// src/ui/utils.ts
|
|
188
208
|
function isOptionObject(opt) {
|
|
189
209
|
return typeof opt === "object" && opt !== null && "value" in opt;
|
|
190
210
|
}
|
|
191
|
-
function
|
|
192
|
-
const
|
|
193
|
-
const
|
|
194
|
-
const
|
|
195
|
-
const
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
211
|
+
function computePreview(x, y) {
|
|
212
|
+
const w = window.innerWidth;
|
|
213
|
+
const h = window.innerHeight;
|
|
214
|
+
const nearLeft = x <= SNAP;
|
|
215
|
+
const nearRight = x >= w - SNAP;
|
|
216
|
+
const nearTop = y <= SNAP;
|
|
217
|
+
const nearBottom = y >= h - SNAP;
|
|
218
|
+
if (nearLeft) return "dock-left";
|
|
219
|
+
if (nearRight) return "dock-right";
|
|
220
|
+
if (nearTop) return "dock-top";
|
|
221
|
+
if (nearBottom) return "dock-bottom";
|
|
222
|
+
return null;
|
|
223
|
+
}
|
|
224
|
+
function previewRectStyle(p) {
|
|
225
|
+
const base = {
|
|
226
|
+
position: "fixed",
|
|
227
|
+
border: "1px dashed #555",
|
|
228
|
+
background: "rgba(255,255,255,0.06)",
|
|
229
|
+
borderRadius: 12
|
|
230
|
+
};
|
|
231
|
+
if (p === "dock-left") {
|
|
232
|
+
return { ...base, left: MARGIN, top: MARGIN, bottom: MARGIN, width: DOCK_W };
|
|
233
|
+
}
|
|
234
|
+
if (p === "dock-right") {
|
|
235
|
+
return { ...base, right: MARGIN, top: MARGIN, bottom: MARGIN, width: DOCK_W };
|
|
236
|
+
}
|
|
237
|
+
if (p === "dock-top") {
|
|
238
|
+
return { ...base, left: MARGIN, right: MARGIN, top: MARGIN, height: DOCK_H };
|
|
239
|
+
}
|
|
240
|
+
return { ...base, left: MARGIN, right: MARGIN, bottom: MARGIN, height: DOCK_H };
|
|
241
|
+
}
|
|
242
|
+
function safeStringify(v) {
|
|
243
|
+
try {
|
|
244
|
+
return JSON.stringify(v, null, 2);
|
|
245
|
+
} catch {
|
|
246
|
+
return String(v);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// src/ui/components/FloatingButton.tsx
|
|
251
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
252
|
+
function FloatingButton({ onClick }) {
|
|
253
|
+
return /* @__PURE__ */ jsx2(
|
|
254
|
+
"button",
|
|
255
|
+
{
|
|
256
|
+
title: "State Inspector (\u2318\u21E7I / Ctrl\u21E7I)",
|
|
257
|
+
onClick,
|
|
258
|
+
style: {
|
|
259
|
+
position: "fixed",
|
|
260
|
+
right: 16,
|
|
261
|
+
bottom: 16,
|
|
262
|
+
width: 44,
|
|
263
|
+
height: 44,
|
|
264
|
+
borderRadius: 22,
|
|
265
|
+
border: "none",
|
|
266
|
+
background: "#111",
|
|
267
|
+
color: "#fff",
|
|
268
|
+
cursor: "pointer",
|
|
269
|
+
zIndex: 999999
|
|
270
|
+
},
|
|
271
|
+
"aria-label": "Toggle State Inspector",
|
|
272
|
+
children: "\u25CE"
|
|
205
273
|
}
|
|
206
|
-
|
|
207
|
-
|
|
274
|
+
);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// src/ui/components/DockPreviewOverlay.tsx
|
|
278
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
279
|
+
function DockPreviewOverlay({ preview }) {
|
|
280
|
+
if (!preview) return null;
|
|
281
|
+
return /* @__PURE__ */ jsx3(
|
|
282
|
+
"div",
|
|
283
|
+
{
|
|
284
|
+
style: {
|
|
285
|
+
position: "fixed",
|
|
286
|
+
inset: 0,
|
|
287
|
+
pointerEvents: "none",
|
|
288
|
+
zIndex: 999998
|
|
289
|
+
},
|
|
290
|
+
children: /* @__PURE__ */ jsx3("div", { style: previewRectStyle(preview) })
|
|
208
291
|
}
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
292
|
+
);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// src/ui/components/ResizeHandle.tsx
|
|
296
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
297
|
+
function ResizeHandle({ onResize }) {
|
|
298
|
+
return /* @__PURE__ */ jsx4(
|
|
299
|
+
"div",
|
|
300
|
+
{
|
|
301
|
+
onPointerDown: (e) => {
|
|
302
|
+
const startX = e.clientX;
|
|
303
|
+
const startY = e.clientY;
|
|
304
|
+
e.currentTarget.setPointerCapture(e.pointerId);
|
|
305
|
+
const onMove = (ev) => {
|
|
306
|
+
onResize({
|
|
307
|
+
dx: ev.clientX - startX,
|
|
308
|
+
dy: ev.clientY - startY
|
|
309
|
+
});
|
|
310
|
+
};
|
|
311
|
+
const onUp = () => {
|
|
312
|
+
window.removeEventListener("pointermove", onMove);
|
|
313
|
+
window.removeEventListener("pointerup", onUp);
|
|
314
|
+
};
|
|
315
|
+
window.addEventListener("pointermove", onMove);
|
|
316
|
+
window.addEventListener("pointerup", onUp);
|
|
317
|
+
},
|
|
318
|
+
style: {
|
|
319
|
+
position: "absolute",
|
|
320
|
+
right: 6,
|
|
321
|
+
bottom: 6,
|
|
322
|
+
width: 14,
|
|
323
|
+
height: 14,
|
|
324
|
+
borderRadius: 6,
|
|
325
|
+
border: "1px solid #333",
|
|
326
|
+
background: "#838383",
|
|
327
|
+
cursor: "nwse-resize"
|
|
328
|
+
}
|
|
214
329
|
}
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
return
|
|
223
|
-
|
|
224
|
-
|
|
330
|
+
);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// src/ui/components/SidebarResizer.tsx
|
|
334
|
+
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
335
|
+
function SidebarResizer({ leftWidth, onWidthChange, hidden }) {
|
|
336
|
+
if (hidden) return null;
|
|
337
|
+
return /* @__PURE__ */ jsx5(
|
|
338
|
+
"div",
|
|
339
|
+
{
|
|
340
|
+
onPointerDown: (e) => {
|
|
341
|
+
e.preventDefault();
|
|
342
|
+
const startX = e.clientX;
|
|
343
|
+
const startW = leftWidth;
|
|
344
|
+
e.currentTarget.setPointerCapture(e.pointerId);
|
|
345
|
+
const onMove = (ev) => {
|
|
346
|
+
const dx = ev.clientX - startX;
|
|
347
|
+
const next = Math.max(LEFT_MIN, Math.min(LEFT_MAX, startW + dx));
|
|
348
|
+
onWidthChange(next);
|
|
349
|
+
};
|
|
350
|
+
const onUp = () => {
|
|
351
|
+
window.removeEventListener("pointermove", onMove);
|
|
352
|
+
window.removeEventListener("pointerup", onUp);
|
|
353
|
+
};
|
|
354
|
+
window.addEventListener("pointermove", onMove);
|
|
355
|
+
window.addEventListener("pointerup", onUp);
|
|
356
|
+
},
|
|
357
|
+
style: {
|
|
358
|
+
width: 8,
|
|
359
|
+
cursor: "col-resize",
|
|
360
|
+
background: "transparent",
|
|
361
|
+
borderLeft: "1px solid #2a2a2a",
|
|
362
|
+
borderRight: "1px solid #2a2a2a"
|
|
363
|
+
},
|
|
364
|
+
title: "Resize sidebar"
|
|
365
|
+
}
|
|
366
|
+
);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// src/ui/components/DragHandle.tsx
|
|
370
|
+
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
371
|
+
function DragHandle({ children, onDragStart, onDragEnd, style }) {
|
|
372
|
+
return /* @__PURE__ */ jsx6(
|
|
373
|
+
"div",
|
|
374
|
+
{
|
|
375
|
+
style: { cursor: "grab", userSelect: "none", ...style },
|
|
376
|
+
onPointerDown: onDragStart,
|
|
377
|
+
onPointerUp: onDragEnd,
|
|
378
|
+
children
|
|
379
|
+
}
|
|
380
|
+
);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// src/ui/components/ComponentList.tsx
|
|
384
|
+
import { jsx as jsx7, jsxs } from "react/jsx-runtime";
|
|
385
|
+
function ComponentList({
|
|
386
|
+
components,
|
|
387
|
+
selectedId,
|
|
388
|
+
onSelect,
|
|
389
|
+
onDragStart,
|
|
390
|
+
onDragEnd,
|
|
391
|
+
height,
|
|
392
|
+
hidden
|
|
393
|
+
}) {
|
|
394
|
+
if (hidden) return null;
|
|
395
|
+
return /* @__PURE__ */ jsxs("div", { style: { padding: 12, height, flexDirection: "column", boxSizing: "border-box", display: "flex" }, children: [
|
|
396
|
+
/* @__PURE__ */ jsxs(
|
|
397
|
+
DragHandle,
|
|
398
|
+
{
|
|
399
|
+
onDragStart,
|
|
400
|
+
onDragEnd,
|
|
401
|
+
style: { display: "flex", alignItems: "center", justifyContent: "space-between" },
|
|
402
|
+
children: [
|
|
403
|
+
/* @__PURE__ */ jsx7("h4", { style: { margin: 0 }, children: "Components" }),
|
|
404
|
+
/* @__PURE__ */ jsx7("span", { style: { fontSize: 12, opacity: 0.7 }, children: components.length })
|
|
405
|
+
]
|
|
406
|
+
}
|
|
407
|
+
),
|
|
408
|
+
/* @__PURE__ */ jsx7("div", { style: { marginTop: 10, display: "flex", flexDirection: "column", gap: 8, overflow: "auto", flex: 1 }, children: components.map((c) => {
|
|
409
|
+
const active = c.id === selectedId;
|
|
410
|
+
return /* @__PURE__ */ jsxs(
|
|
225
411
|
"button",
|
|
226
412
|
{
|
|
227
|
-
|
|
413
|
+
id: `rsi-comp-${c.id}`,
|
|
414
|
+
onClick: () => onSelect(c.id),
|
|
228
415
|
style: {
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
borderRadius: 22,
|
|
235
|
-
border: "none",
|
|
236
|
-
background: "#111",
|
|
416
|
+
textAlign: "left",
|
|
417
|
+
background: active ? "#2a2a2a" : "transparent",
|
|
418
|
+
border: "1px solid #333",
|
|
419
|
+
borderRadius: 10,
|
|
420
|
+
padding: 10,
|
|
237
421
|
color: "#fff",
|
|
238
422
|
cursor: "pointer",
|
|
239
|
-
|
|
240
|
-
},
|
|
241
|
-
"aria-label": "Toggle State Inspector",
|
|
242
|
-
title: "State Inspector",
|
|
243
|
-
children: "\u25CE"
|
|
244
|
-
}
|
|
245
|
-
),
|
|
246
|
-
open && /* @__PURE__ */ jsxs(
|
|
247
|
-
"div",
|
|
248
|
-
{
|
|
249
|
-
style: {
|
|
250
|
-
position: "fixed",
|
|
251
|
-
right: 16,
|
|
252
|
-
bottom: 72,
|
|
253
|
-
width: 720,
|
|
254
|
-
maxWidth: "calc(100vw - 32px)",
|
|
255
|
-
height: 420,
|
|
256
|
-
maxHeight: "calc(100vh - 120px)",
|
|
257
|
-
background: "#1c1c1c",
|
|
258
|
-
color: "#fff",
|
|
259
|
-
borderRadius: 12,
|
|
260
|
-
border: "1px solid #333",
|
|
261
|
-
zIndex: 999999,
|
|
262
|
-
display: "grid",
|
|
263
|
-
gridTemplateColumns: "280px 1fr",
|
|
264
|
-
overflow: "hidden"
|
|
423
|
+
flex: "none"
|
|
265
424
|
},
|
|
266
425
|
children: [
|
|
267
|
-
/* @__PURE__ */
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
] }),
|
|
272
|
-
/* @__PURE__ */ jsx2("div", { style: { marginTop: 10, display: "grid", gap: 8, overflow: "auto", flex: 1 }, children: components.map((c) => {
|
|
273
|
-
const active = c.id === selectedId;
|
|
274
|
-
return /* @__PURE__ */ jsxs(
|
|
275
|
-
"button",
|
|
276
|
-
{
|
|
277
|
-
onClick: () => setSelectedId(c.id),
|
|
278
|
-
style: {
|
|
279
|
-
textAlign: "left",
|
|
280
|
-
background: active ? "#2a2a2a" : "transparent",
|
|
281
|
-
border: "1px solid #333",
|
|
282
|
-
borderRadius: 10,
|
|
283
|
-
padding: 10,
|
|
284
|
-
color: "#fff",
|
|
285
|
-
cursor: "pointer"
|
|
286
|
-
},
|
|
287
|
-
children: [
|
|
288
|
-
/* @__PURE__ */ jsx2("div", { style: { fontWeight: 700 }, children: c.label }),
|
|
289
|
-
/* @__PURE__ */ jsxs("div", { style: { fontSize: 12, opacity: 0.7 }, children: [
|
|
290
|
-
"states: ",
|
|
291
|
-
c.stateKeys.length ? c.stateKeys.length : 0
|
|
292
|
-
] })
|
|
293
|
-
]
|
|
294
|
-
},
|
|
295
|
-
c.id
|
|
296
|
-
);
|
|
297
|
-
}) })
|
|
298
|
-
] }),
|
|
299
|
-
/* @__PURE__ */ jsxs("div", { style: { padding: 12, overflow: "auto" }, children: [
|
|
300
|
-
/* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between" }, children: [
|
|
301
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
302
|
-
/* @__PURE__ */ jsx2("h4", { style: { margin: 0 }, children: "State" }),
|
|
303
|
-
/* @__PURE__ */ jsx2("div", { style: { fontSize: 12, opacity: 0.7 }, children: selected ? selected.label : "No selection" })
|
|
304
|
-
] }),
|
|
305
|
-
/* @__PURE__ */ jsx2(
|
|
306
|
-
"button",
|
|
307
|
-
{
|
|
308
|
-
onClick: () => setOpen(false),
|
|
309
|
-
style: {
|
|
310
|
-
background: "transparent",
|
|
311
|
-
color: "#fff",
|
|
312
|
-
border: "1px solid #333",
|
|
313
|
-
borderRadius: 10,
|
|
314
|
-
padding: "6px 10px",
|
|
315
|
-
cursor: "pointer"
|
|
316
|
-
},
|
|
317
|
-
children: "Close"
|
|
318
|
-
}
|
|
319
|
-
)
|
|
320
|
-
] }),
|
|
321
|
-
/* @__PURE__ */ jsxs("div", { style: { marginTop: 12, display: "grid", gap: 10 }, children: [
|
|
322
|
-
selected && selected.states.size === 0 && /* @__PURE__ */ jsx2("div", { style: { fontSize: 13, opacity: 0.7 }, children: "This component has no inspectable state." }),
|
|
323
|
-
!selected && /* @__PURE__ */ jsx2("div", { style: { opacity: 0.7, fontSize: 13 }, children: "No component selected." }),
|
|
324
|
-
selected && Array.from(selected.states.values()).map((s) => /* @__PURE__ */ jsxs(
|
|
325
|
-
"div",
|
|
326
|
-
{
|
|
327
|
-
style: {
|
|
328
|
-
border: "1px solid #333",
|
|
329
|
-
borderRadius: 12,
|
|
330
|
-
padding: 10,
|
|
331
|
-
display: "grid",
|
|
332
|
-
gap: 8
|
|
333
|
-
},
|
|
334
|
-
children: [
|
|
335
|
-
/* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between", gap: 12 }, children: [
|
|
336
|
-
/* @__PURE__ */ jsx2("div", { style: { fontWeight: 700 }, children: s.key }),
|
|
337
|
-
/* @__PURE__ */ jsx2("div", { style: { fontSize: 12, opacity: 0.6 }, children: s.meta?.type ?? "auto" })
|
|
338
|
-
] }),
|
|
339
|
-
/* @__PURE__ */ jsx2(
|
|
340
|
-
StateEditor,
|
|
341
|
-
{
|
|
342
|
-
value: s.value,
|
|
343
|
-
meta: s.meta,
|
|
344
|
-
onChange: (next) => s.setValue(next)
|
|
345
|
-
}
|
|
346
|
-
)
|
|
347
|
-
]
|
|
348
|
-
},
|
|
349
|
-
s.key
|
|
350
|
-
))
|
|
351
|
-
] })
|
|
426
|
+
/* @__PURE__ */ jsx7("div", { style: { fontWeight: 700 }, children: c.label }),
|
|
427
|
+
/* @__PURE__ */ jsxs("div", { style: { fontSize: 12, opacity: 0.7 }, children: [
|
|
428
|
+
"states: ",
|
|
429
|
+
c.stateKeys.length || 0
|
|
352
430
|
] })
|
|
353
431
|
]
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
);
|
|
432
|
+
},
|
|
433
|
+
c.id
|
|
434
|
+
);
|
|
435
|
+
}) })
|
|
436
|
+
] });
|
|
359
437
|
}
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
438
|
+
|
|
439
|
+
// src/ui/components/StatePanelHeader.tsx
|
|
440
|
+
import { jsx as jsx8, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
441
|
+
function StatePanelHeader({
|
|
442
|
+
selectedLabel,
|
|
443
|
+
leftCollapsed,
|
|
444
|
+
onToggleCollapse,
|
|
445
|
+
onClose,
|
|
446
|
+
onDragStart,
|
|
447
|
+
onDragEnd
|
|
364
448
|
}) {
|
|
449
|
+
return /* @__PURE__ */ jsxs2("div", { style: { display: "flex", alignItems: "center" }, children: [
|
|
450
|
+
/* @__PURE__ */ jsx8(
|
|
451
|
+
"button",
|
|
452
|
+
{
|
|
453
|
+
onClick: (e) => {
|
|
454
|
+
e.preventDefault();
|
|
455
|
+
onToggleCollapse();
|
|
456
|
+
},
|
|
457
|
+
style: {
|
|
458
|
+
padding: 4,
|
|
459
|
+
marginRight: 12,
|
|
460
|
+
borderRadius: 6,
|
|
461
|
+
border: "1px solid #333",
|
|
462
|
+
background: "transparent",
|
|
463
|
+
color: "#fff",
|
|
464
|
+
cursor: "pointer",
|
|
465
|
+
fontSize: 12,
|
|
466
|
+
width: 24,
|
|
467
|
+
height: 24
|
|
468
|
+
},
|
|
469
|
+
children: leftCollapsed ? "\xBB" : "\xAB"
|
|
470
|
+
}
|
|
471
|
+
),
|
|
472
|
+
/* @__PURE__ */ jsxs2(
|
|
473
|
+
DragHandle,
|
|
474
|
+
{
|
|
475
|
+
onDragStart,
|
|
476
|
+
onDragEnd,
|
|
477
|
+
style: { display: "flex", flexDirection: "column", flex: 1 },
|
|
478
|
+
children: [
|
|
479
|
+
/* @__PURE__ */ jsx8("h4", { style: { margin: 0 }, children: "State" }),
|
|
480
|
+
/* @__PURE__ */ jsx8("div", { style: { fontSize: 12, opacity: 0.7 }, children: selectedLabel ?? "No selection" })
|
|
481
|
+
]
|
|
482
|
+
}
|
|
483
|
+
),
|
|
484
|
+
/* @__PURE__ */ jsx8(
|
|
485
|
+
"button",
|
|
486
|
+
{
|
|
487
|
+
onClick: onClose,
|
|
488
|
+
style: {
|
|
489
|
+
background: "transparent",
|
|
490
|
+
color: "#fff",
|
|
491
|
+
border: "1px solid #333",
|
|
492
|
+
borderRadius: 10,
|
|
493
|
+
padding: "6px 10px",
|
|
494
|
+
cursor: "pointer",
|
|
495
|
+
fontSize: 12,
|
|
496
|
+
marginLeft: "auto"
|
|
497
|
+
},
|
|
498
|
+
children: "Close"
|
|
499
|
+
}
|
|
500
|
+
)
|
|
501
|
+
] });
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
// src/ui/styles.ts
|
|
505
|
+
var inputStyle = {
|
|
506
|
+
padding: "8px 10px",
|
|
507
|
+
borderRadius: 10,
|
|
508
|
+
border: "1px solid #333",
|
|
509
|
+
background: "#111",
|
|
510
|
+
color: "#fff"
|
|
511
|
+
};
|
|
512
|
+
var cardStyle = {
|
|
513
|
+
border: "1px solid #333",
|
|
514
|
+
borderRadius: 12,
|
|
515
|
+
padding: 10
|
|
516
|
+
};
|
|
517
|
+
|
|
518
|
+
// src/ui/components/SearchInput.tsx
|
|
519
|
+
import { jsx as jsx9 } from "react/jsx-runtime";
|
|
520
|
+
function SearchInput({ value, onChange, inputRef }) {
|
|
521
|
+
return /* @__PURE__ */ jsx9(
|
|
522
|
+
"input",
|
|
523
|
+
{
|
|
524
|
+
value,
|
|
525
|
+
onChange: (e) => onChange(e.target.value),
|
|
526
|
+
placeholder: "Search components / state keys\u2026",
|
|
527
|
+
ref: inputRef,
|
|
528
|
+
style: {
|
|
529
|
+
...inputStyle,
|
|
530
|
+
marginTop: 10,
|
|
531
|
+
outline: "none"
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
);
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
// src/ui/components/JsonEditor.tsx
|
|
538
|
+
import { useEffect as useEffect3, useState as useState2 } from "react";
|
|
539
|
+
import { jsx as jsx10, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
540
|
+
function JsonEditor({ initial, onValidJson }) {
|
|
541
|
+
const [raw, setRaw] = useState2(initial);
|
|
542
|
+
const [error, setError] = useState2(null);
|
|
543
|
+
useEffect3(() => {
|
|
544
|
+
setRaw(initial);
|
|
545
|
+
}, [initial]);
|
|
546
|
+
const handleChange = (e) => {
|
|
547
|
+
const next = e.target.value;
|
|
548
|
+
setRaw(next);
|
|
549
|
+
try {
|
|
550
|
+
const parsed = JSON.parse(next);
|
|
551
|
+
setError(null);
|
|
552
|
+
onValidJson(parsed);
|
|
553
|
+
} catch {
|
|
554
|
+
setError("Invalid JSON");
|
|
555
|
+
}
|
|
556
|
+
};
|
|
557
|
+
return /* @__PURE__ */ jsxs3("div", { style: { display: "grid", gap: 6 }, children: [
|
|
558
|
+
/* @__PURE__ */ jsx10(
|
|
559
|
+
"textarea",
|
|
560
|
+
{
|
|
561
|
+
value: raw,
|
|
562
|
+
onChange: handleChange,
|
|
563
|
+
rows: 6,
|
|
564
|
+
style: {
|
|
565
|
+
...inputStyle,
|
|
566
|
+
fontFamily: "ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace",
|
|
567
|
+
fontSize: 12,
|
|
568
|
+
resize: "vertical"
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
),
|
|
572
|
+
error && /* @__PURE__ */ jsx10("div", { style: { fontSize: 12, color: "#ff6b6b" }, children: error })
|
|
573
|
+
] });
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
// src/ui/components/StateEditor.tsx
|
|
577
|
+
import { jsx as jsx11, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
578
|
+
function StateEditor({ value, meta, onChange }) {
|
|
365
579
|
if (meta?.type === "boolean" || typeof value === "boolean") {
|
|
366
|
-
return /* @__PURE__ */
|
|
367
|
-
/* @__PURE__ */
|
|
580
|
+
return /* @__PURE__ */ jsxs4("label", { style: { display: "flex", gap: 10, alignItems: "center" }, children: [
|
|
581
|
+
/* @__PURE__ */ jsx11(
|
|
368
582
|
"input",
|
|
369
583
|
{
|
|
370
584
|
type: "checkbox",
|
|
@@ -372,33 +586,26 @@ function StateEditor({
|
|
|
372
586
|
onChange: (e) => onChange(e.target.checked)
|
|
373
587
|
}
|
|
374
588
|
),
|
|
375
|
-
/* @__PURE__ */
|
|
589
|
+
/* @__PURE__ */ jsx11("span", { style: { fontSize: 13, opacity: 0.8 }, children: String(Boolean(value)) })
|
|
376
590
|
] });
|
|
377
591
|
}
|
|
378
592
|
if (meta?.type === "select" && Array.isArray(meta.options)) {
|
|
379
593
|
const current = typeof value === "string" ? value : String(value ?? "");
|
|
380
|
-
return /* @__PURE__ */
|
|
594
|
+
return /* @__PURE__ */ jsx11(
|
|
381
595
|
"select",
|
|
382
596
|
{
|
|
383
597
|
value: current,
|
|
384
598
|
onChange: (e) => onChange(e.target.value),
|
|
385
|
-
style:
|
|
386
|
-
width: "100%",
|
|
387
|
-
padding: "8px 10px",
|
|
388
|
-
borderRadius: 10,
|
|
389
|
-
border: "1px solid #333",
|
|
390
|
-
background: "#111",
|
|
391
|
-
color: "#fff"
|
|
392
|
-
},
|
|
599
|
+
style: inputStyle,
|
|
393
600
|
children: meta.options.map((opt) => {
|
|
394
601
|
const o = isOptionObject(opt) ? opt : { label: String(opt), value: String(opt) };
|
|
395
|
-
return /* @__PURE__ */
|
|
602
|
+
return /* @__PURE__ */ jsx11("option", { value: o.value, children: o.label }, o.value);
|
|
396
603
|
})
|
|
397
604
|
}
|
|
398
605
|
);
|
|
399
606
|
}
|
|
400
|
-
if (meta?.type === "number"
|
|
401
|
-
return /* @__PURE__ */
|
|
607
|
+
if (meta?.type === "number") {
|
|
608
|
+
return /* @__PURE__ */ jsx11(
|
|
402
609
|
"input",
|
|
403
610
|
{
|
|
404
611
|
type: "number",
|
|
@@ -407,87 +614,356 @@ function StateEditor({
|
|
|
407
614
|
max: meta?.max,
|
|
408
615
|
step: meta?.step,
|
|
409
616
|
onChange: (e) => onChange(e.target.value === "" ? 0 : Number(e.target.value)),
|
|
410
|
-
style:
|
|
411
|
-
width: "100%",
|
|
412
|
-
padding: "8px 10px",
|
|
413
|
-
borderRadius: 10,
|
|
414
|
-
border: "1px solid #333",
|
|
415
|
-
background: "#111",
|
|
416
|
-
color: "#fff"
|
|
417
|
-
}
|
|
617
|
+
style: inputStyle
|
|
418
618
|
}
|
|
419
619
|
);
|
|
420
620
|
}
|
|
421
621
|
if (meta?.type === "json" || value && typeof value === "object") {
|
|
422
|
-
|
|
423
|
-
return /* @__PURE__ */ jsx2(JsonEditor, { initial: text, onValidJson: (obj) => onChange(obj) });
|
|
622
|
+
return /* @__PURE__ */ jsx11(JsonEditor, { initial: safeStringify(value), onValidJson: onChange });
|
|
424
623
|
}
|
|
425
|
-
return /* @__PURE__ */
|
|
624
|
+
return /* @__PURE__ */ jsx11(
|
|
426
625
|
"input",
|
|
427
626
|
{
|
|
428
627
|
type: "text",
|
|
429
628
|
value: typeof value === "string" ? value : String(value ?? ""),
|
|
430
|
-
placeholder: meta?.placeholder,
|
|
629
|
+
placeholder: meta?.type === "text" ? meta.placeholder : void 0,
|
|
431
630
|
onChange: (e) => onChange(e.target.value),
|
|
432
|
-
style:
|
|
433
|
-
width: "100%",
|
|
434
|
-
padding: "8px 10px",
|
|
435
|
-
borderRadius: 10,
|
|
436
|
-
border: "1px solid #333",
|
|
437
|
-
background: "#111",
|
|
438
|
-
color: "#fff"
|
|
439
|
-
}
|
|
631
|
+
style: inputStyle
|
|
440
632
|
}
|
|
441
633
|
);
|
|
442
634
|
}
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
635
|
+
|
|
636
|
+
// src/ui/components/StateCard.tsx
|
|
637
|
+
import { jsx as jsx12, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
638
|
+
function StateCard({ state }) {
|
|
639
|
+
return /* @__PURE__ */ jsxs5(
|
|
640
|
+
"div",
|
|
641
|
+
{
|
|
642
|
+
style: {
|
|
643
|
+
...cardStyle,
|
|
644
|
+
display: "flex",
|
|
645
|
+
flexDirection: "column",
|
|
646
|
+
gap: 8
|
|
647
|
+
},
|
|
648
|
+
children: [
|
|
649
|
+
/* @__PURE__ */ jsxs5("div", { style: { display: "flex", justifyContent: "space-between", gap: 12 }, children: [
|
|
650
|
+
/* @__PURE__ */ jsx12("div", { style: { fontWeight: 700 }, children: state.key }),
|
|
651
|
+
/* @__PURE__ */ jsx12("div", { style: { fontSize: 12, opacity: 0.6 }, children: state.meta?.type ?? "auto" })
|
|
652
|
+
] }),
|
|
653
|
+
/* @__PURE__ */ jsx12(
|
|
654
|
+
StateEditor,
|
|
655
|
+
{
|
|
656
|
+
value: state.value,
|
|
657
|
+
meta: state.meta,
|
|
658
|
+
onChange: (next) => state.setValue(next)
|
|
659
|
+
}
|
|
660
|
+
)
|
|
661
|
+
]
|
|
662
|
+
}
|
|
663
|
+
);
|
|
449
664
|
}
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
665
|
+
|
|
666
|
+
// src/ui/components/StateEditorPanel.tsx
|
|
667
|
+
import { jsx as jsx13, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
668
|
+
function StateEditorPanel({
|
|
669
|
+
selected,
|
|
670
|
+
query,
|
|
671
|
+
onQueryChange,
|
|
672
|
+
searchRef,
|
|
673
|
+
leftCollapsed,
|
|
674
|
+
onToggleCollapse,
|
|
675
|
+
onClose,
|
|
676
|
+
onDragStart,
|
|
677
|
+
onDragEnd
|
|
453
678
|
}) {
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
setRaw(initial);
|
|
458
|
-
}, [initial]);
|
|
459
|
-
return /* @__PURE__ */ jsxs("div", { style: { display: "grid", gap: 6 }, children: [
|
|
460
|
-
/* @__PURE__ */ jsx2(
|
|
461
|
-
"textarea",
|
|
679
|
+
return /* @__PURE__ */ jsxs6("div", { style: { padding: 12, overflow: "auto", display: "flex", flexDirection: "column", boxSizing: "border-box" }, children: [
|
|
680
|
+
/* @__PURE__ */ jsx13(
|
|
681
|
+
StatePanelHeader,
|
|
462
682
|
{
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
setError(null);
|
|
470
|
-
onValidJson(parsed);
|
|
471
|
-
} catch (err) {
|
|
472
|
-
setError("Invalid JSON");
|
|
473
|
-
}
|
|
474
|
-
},
|
|
475
|
-
rows: 6,
|
|
476
|
-
style: {
|
|
477
|
-
width: "100%",
|
|
478
|
-
padding: "8px 10px",
|
|
479
|
-
borderRadius: 10,
|
|
480
|
-
border: "1px solid #333",
|
|
481
|
-
background: "#111",
|
|
482
|
-
color: "#fff",
|
|
483
|
-
fontFamily: "ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace",
|
|
484
|
-
fontSize: 12
|
|
485
|
-
}
|
|
683
|
+
selectedLabel: selected?.label ?? null,
|
|
684
|
+
leftCollapsed,
|
|
685
|
+
onToggleCollapse,
|
|
686
|
+
onClose,
|
|
687
|
+
onDragStart,
|
|
688
|
+
onDragEnd
|
|
486
689
|
}
|
|
487
690
|
),
|
|
488
|
-
|
|
691
|
+
/* @__PURE__ */ jsx13(
|
|
692
|
+
SearchInput,
|
|
693
|
+
{
|
|
694
|
+
value: query,
|
|
695
|
+
onChange: onQueryChange,
|
|
696
|
+
inputRef: searchRef
|
|
697
|
+
}
|
|
698
|
+
),
|
|
699
|
+
/* @__PURE__ */ jsxs6("div", { style: { marginTop: 12, display: "grid", gap: 10 }, children: [
|
|
700
|
+
selected && selected.states.size === 0 && /* @__PURE__ */ jsx13("div", { style: { fontSize: 13, opacity: 0.7 }, children: "This component has no inspectable state." }),
|
|
701
|
+
!selected && /* @__PURE__ */ jsx13("div", { style: { opacity: 0.7, fontSize: 13 }, children: "No component selected." }),
|
|
702
|
+
selected && Array.from(selected.states.values()).map((s) => /* @__PURE__ */ jsx13(StateCard, { state: s }, s.key))
|
|
703
|
+
] })
|
|
489
704
|
] });
|
|
490
705
|
}
|
|
706
|
+
|
|
707
|
+
// src/StateInspectorUI.tsx
|
|
708
|
+
import { Fragment, jsx as jsx14, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
709
|
+
function StateInspectorUI() {
|
|
710
|
+
const store = useInspectorStore();
|
|
711
|
+
const [query, setQuery] = useState3("");
|
|
712
|
+
const [leftCollapsed, setLeftCollapsed] = useState3(false);
|
|
713
|
+
const [layout, setLayout] = useState3("floating");
|
|
714
|
+
const [preview, setPreview] = useState3(null);
|
|
715
|
+
const [isTransitioning, setIsTransitioning] = useState3(false);
|
|
716
|
+
const [open, setOpen] = useState3(false);
|
|
717
|
+
const [selectedId, setSelectedId] = useState3(null);
|
|
718
|
+
const [, force] = useState3(0);
|
|
719
|
+
const searchRef = useRef2(null);
|
|
720
|
+
const [pos, setPos] = useState3(() => {
|
|
721
|
+
try {
|
|
722
|
+
const raw = localStorage.getItem(LS_KEY);
|
|
723
|
+
return raw ? JSON.parse(raw) : { right: 16, bottom: 72 };
|
|
724
|
+
} catch {
|
|
725
|
+
return { right: 16, bottom: 72 };
|
|
726
|
+
}
|
|
727
|
+
});
|
|
728
|
+
const [leftWidth, setLeftWidth] = useState3(() => {
|
|
729
|
+
try {
|
|
730
|
+
const raw = localStorage.getItem(LS_LEFT_W);
|
|
731
|
+
return raw ? Number(raw) : 280;
|
|
732
|
+
} catch {
|
|
733
|
+
return 280;
|
|
734
|
+
}
|
|
735
|
+
});
|
|
736
|
+
const [size, setSize] = useState3(() => {
|
|
737
|
+
try {
|
|
738
|
+
const raw = localStorage.getItem(LS_SIZE);
|
|
739
|
+
return raw ? JSON.parse(raw) : { width: 720, height: 420 };
|
|
740
|
+
} catch {
|
|
741
|
+
return { width: 720, height: 420 };
|
|
742
|
+
}
|
|
743
|
+
});
|
|
744
|
+
useEffect4(() => {
|
|
745
|
+
try {
|
|
746
|
+
localStorage.setItem(LS_LAYOUT, layout);
|
|
747
|
+
} catch (e) {
|
|
748
|
+
console.error(e);
|
|
749
|
+
}
|
|
750
|
+
}, [layout]);
|
|
751
|
+
useEffect4(() => {
|
|
752
|
+
try {
|
|
753
|
+
localStorage.setItem(LS_KEY, JSON.stringify(pos));
|
|
754
|
+
} catch (e) {
|
|
755
|
+
console.error(e);
|
|
756
|
+
}
|
|
757
|
+
}, [pos]);
|
|
758
|
+
useEffect4(() => {
|
|
759
|
+
try {
|
|
760
|
+
localStorage.setItem(LS_LEFT_W, String(leftWidth));
|
|
761
|
+
} catch (e) {
|
|
762
|
+
console.error(e);
|
|
763
|
+
}
|
|
764
|
+
}, [leftWidth]);
|
|
765
|
+
useEffect4(() => {
|
|
766
|
+
try {
|
|
767
|
+
localStorage.setItem(LS_SIZE, JSON.stringify(size));
|
|
768
|
+
} catch (e) {
|
|
769
|
+
console.error(e);
|
|
770
|
+
}
|
|
771
|
+
}, [size]);
|
|
772
|
+
useEffect4(() => {
|
|
773
|
+
const shouldCollapse = leftWidth <= 200 || (size.width ?? 720) - leftWidth < 320;
|
|
774
|
+
setLeftCollapsed(shouldCollapse);
|
|
775
|
+
}, [leftWidth, size.width]);
|
|
776
|
+
useEffect4(() => store.subscribe(() => force((x) => x + 1)), [store]);
|
|
777
|
+
const snapshot = useMemo3(() => store.getSnapshot(), [store]);
|
|
778
|
+
const components = useMemo3(
|
|
779
|
+
() => snapshot.components.filter((c) => c.mounted),
|
|
780
|
+
[snapshot.components]
|
|
781
|
+
);
|
|
782
|
+
const q = query.trim().toLowerCase();
|
|
783
|
+
const filtered = useMemo3(
|
|
784
|
+
() => q ? components.filter((c) => {
|
|
785
|
+
const labelHit = c.label.toLowerCase().includes(q);
|
|
786
|
+
const keyHit = c.stateKeys.some((k) => k.toLowerCase().includes(q));
|
|
787
|
+
return labelHit || keyHit;
|
|
788
|
+
}) : components,
|
|
789
|
+
[q, components]
|
|
790
|
+
);
|
|
791
|
+
useEffect4(() => {
|
|
792
|
+
if (!open) return;
|
|
793
|
+
if (components.length === 0) {
|
|
794
|
+
setSelectedId(null);
|
|
795
|
+
return;
|
|
796
|
+
}
|
|
797
|
+
if (!selectedId || !components.some((c) => c.id === selectedId)) {
|
|
798
|
+
setSelectedId(components[0].id);
|
|
799
|
+
}
|
|
800
|
+
}, [open, components.length]);
|
|
801
|
+
useEffect4(() => {
|
|
802
|
+
function onKey(e) {
|
|
803
|
+
const mod = isMac ? e.metaKey : e.ctrlKey;
|
|
804
|
+
if (mod && e.shiftKey && e.key.toLowerCase() === "i") {
|
|
805
|
+
e.preventDefault();
|
|
806
|
+
setOpen((o) => !o);
|
|
807
|
+
return;
|
|
808
|
+
}
|
|
809
|
+
if (!open) return;
|
|
810
|
+
if (e.key === "Escape") {
|
|
811
|
+
setOpen(false);
|
|
812
|
+
return;
|
|
813
|
+
}
|
|
814
|
+
if (e.key === "/") {
|
|
815
|
+
e.preventDefault();
|
|
816
|
+
searchRef.current?.focus();
|
|
817
|
+
return;
|
|
818
|
+
}
|
|
819
|
+
if (e.key === "ArrowDown" || e.key === "ArrowUp") {
|
|
820
|
+
e.preventDefault();
|
|
821
|
+
const list = filtered;
|
|
822
|
+
if (!list.length) return;
|
|
823
|
+
const idx = list.findIndex((c) => c.id === selectedId);
|
|
824
|
+
const next = e.key === "ArrowDown" ? list[(Math.max(-1, idx) + 1) % list.length].id : list[idx <= 0 ? list.length - 1 : idx - 1].id;
|
|
825
|
+
setSelectedId(next);
|
|
826
|
+
setTimeout(() => {
|
|
827
|
+
document.getElementById(`rsi-comp-${next}`)?.scrollIntoView({ block: "nearest" });
|
|
828
|
+
}, 0);
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
window.addEventListener("keydown", onKey);
|
|
832
|
+
return () => window.removeEventListener("keydown", onKey);
|
|
833
|
+
}, [open, filtered, selectedId]);
|
|
834
|
+
const selected = useMemo3(() => {
|
|
835
|
+
if (!selectedId) return null;
|
|
836
|
+
return store.components.get(selectedId) ?? null;
|
|
837
|
+
}, [store, selectedId]);
|
|
838
|
+
const handleDragEnd = () => {
|
|
839
|
+
if (preview) {
|
|
840
|
+
setLayout(preview);
|
|
841
|
+
setIsTransitioning(true);
|
|
842
|
+
const rects = previewRectStyle(preview);
|
|
843
|
+
setSize({ width: rects.width, height: rects.height });
|
|
844
|
+
setPos({
|
|
845
|
+
left: rects.left,
|
|
846
|
+
right: rects.right,
|
|
847
|
+
top: rects.top,
|
|
848
|
+
bottom: rects.bottom
|
|
849
|
+
});
|
|
850
|
+
setPreview(null);
|
|
851
|
+
setTimeout(() => setIsTransitioning(false), 300);
|
|
852
|
+
return;
|
|
853
|
+
}
|
|
854
|
+
setPreview(null);
|
|
855
|
+
};
|
|
856
|
+
const handleDragStart = (e) => {
|
|
857
|
+
const startX = e.clientX;
|
|
858
|
+
const startY = e.clientY;
|
|
859
|
+
const start = pos;
|
|
860
|
+
setLayout("floating");
|
|
861
|
+
setIsTransitioning(true);
|
|
862
|
+
setSize({ width: 720, height: 420 });
|
|
863
|
+
setTimeout(() => setIsTransitioning(false), 300);
|
|
864
|
+
e.currentTarget.setPointerCapture(e.pointerId);
|
|
865
|
+
const onMove = (ev) => {
|
|
866
|
+
const dx = ev.clientX - startX;
|
|
867
|
+
const dy = ev.clientY - startY;
|
|
868
|
+
const nextPreview = computePreview(ev.clientX, ev.clientY);
|
|
869
|
+
setPreview((p) => p === nextPreview ? p : nextPreview);
|
|
870
|
+
const newPos = {};
|
|
871
|
+
if (start.left !== void 0) {
|
|
872
|
+
newPos.left = Math.max(8, start.left + dx);
|
|
873
|
+
} else {
|
|
874
|
+
newPos.right = Math.max(8, (start.right ?? 16) - dx);
|
|
875
|
+
}
|
|
876
|
+
if (start.top !== void 0) {
|
|
877
|
+
newPos.top = Math.max(8, start.top + dy);
|
|
878
|
+
} else {
|
|
879
|
+
newPos.bottom = Math.max(8, (start.bottom ?? 72) - dy);
|
|
880
|
+
}
|
|
881
|
+
setPos(newPos);
|
|
882
|
+
};
|
|
883
|
+
const onUp = () => {
|
|
884
|
+
window.removeEventListener("pointermove", onMove);
|
|
885
|
+
window.removeEventListener("pointerup", onUp);
|
|
886
|
+
};
|
|
887
|
+
window.addEventListener("pointermove", onMove);
|
|
888
|
+
window.addEventListener("pointerup", onUp);
|
|
889
|
+
};
|
|
890
|
+
const handlePanelResize = (startSize) => (delta) => {
|
|
891
|
+
setSize({
|
|
892
|
+
width: Math.min(window.innerWidth - 16, Math.max(480, (startSize.width ?? 0) + delta.dx)),
|
|
893
|
+
height: Math.min(window.innerHeight - 120, Math.max(280, (startSize.height ?? 0) + delta.dy))
|
|
894
|
+
});
|
|
895
|
+
};
|
|
896
|
+
if (!store.enabled) return null;
|
|
897
|
+
return createPortal(
|
|
898
|
+
/* @__PURE__ */ jsxs7(Fragment, { children: [
|
|
899
|
+
/* @__PURE__ */ jsx14(FloatingButton, { onClick: () => setOpen((o) => !o) }),
|
|
900
|
+
/* @__PURE__ */ jsx14(DockPreviewOverlay, { preview }),
|
|
901
|
+
open && /* @__PURE__ */ jsxs7(
|
|
902
|
+
"div",
|
|
903
|
+
{
|
|
904
|
+
style: {
|
|
905
|
+
position: "fixed",
|
|
906
|
+
left: pos.left,
|
|
907
|
+
right: pos.right,
|
|
908
|
+
top: pos.top,
|
|
909
|
+
bottom: pos.bottom,
|
|
910
|
+
width: size.width || "calc(100dvw - 24px)",
|
|
911
|
+
maxWidth: "calc(100vw - 24px)",
|
|
912
|
+
height: size.height || "calc(100dvh - 24px)",
|
|
913
|
+
maxHeight: "calc(100vh - 24px)",
|
|
914
|
+
background: "#1c1c1c",
|
|
915
|
+
color: "#fff",
|
|
916
|
+
borderRadius: 12,
|
|
917
|
+
border: "1px solid #333",
|
|
918
|
+
zIndex: 999999,
|
|
919
|
+
display: "grid",
|
|
920
|
+
gridTemplateColumns: leftCollapsed ? "auto" : `${leftWidth}px 14px auto`,
|
|
921
|
+
overflow: "hidden",
|
|
922
|
+
transition: isTransitioning ? "all 0.3s ease" : "none"
|
|
923
|
+
},
|
|
924
|
+
children: [
|
|
925
|
+
/* @__PURE__ */ jsx14(ResizeHandle, { onResize: handlePanelResize(size) }),
|
|
926
|
+
/* @__PURE__ */ jsx14(
|
|
927
|
+
ComponentList,
|
|
928
|
+
{
|
|
929
|
+
components: filtered,
|
|
930
|
+
selectedId,
|
|
931
|
+
onSelect: setSelectedId,
|
|
932
|
+
onDragStart: handleDragStart,
|
|
933
|
+
onDragEnd: handleDragEnd,
|
|
934
|
+
height: size.height,
|
|
935
|
+
hidden: leftCollapsed
|
|
936
|
+
}
|
|
937
|
+
),
|
|
938
|
+
/* @__PURE__ */ jsx14(
|
|
939
|
+
SidebarResizer,
|
|
940
|
+
{
|
|
941
|
+
leftWidth,
|
|
942
|
+
onWidthChange: setLeftWidth,
|
|
943
|
+
hidden: leftCollapsed
|
|
944
|
+
}
|
|
945
|
+
),
|
|
946
|
+
/* @__PURE__ */ jsx14(
|
|
947
|
+
StateEditorPanel,
|
|
948
|
+
{
|
|
949
|
+
selected,
|
|
950
|
+
query,
|
|
951
|
+
onQueryChange: setQuery,
|
|
952
|
+
searchRef,
|
|
953
|
+
leftCollapsed,
|
|
954
|
+
onToggleCollapse: () => setLeftCollapsed((v) => !v),
|
|
955
|
+
onClose: () => setOpen(false),
|
|
956
|
+
onDragStart: handleDragStart,
|
|
957
|
+
onDragEnd: handleDragEnd
|
|
958
|
+
}
|
|
959
|
+
)
|
|
960
|
+
]
|
|
961
|
+
}
|
|
962
|
+
)
|
|
963
|
+
] }),
|
|
964
|
+
document.body
|
|
965
|
+
);
|
|
966
|
+
}
|
|
491
967
|
export {
|
|
492
968
|
StateInspectorProvider,
|
|
493
969
|
StateInspectorUI,
|