@tanstack/devtools 0.6.10 → 0.6.12

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.
@@ -62,12 +62,12 @@ var initialState = {
62
62
  openHotkey: ["Shift", "A"],
63
63
  requireUrlFlag: false,
64
64
  urlFlag: "tanstack-devtools",
65
- theme: typeof window !== "undefined" && window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light"
65
+ theme: typeof window !== "undefined" && typeof window.matchMedia !== "undefined" && window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light"
66
66
  },
67
67
  state: {
68
68
  activeTab: "plugins",
69
69
  height: 400,
70
- activePlugin: void 0,
70
+ activePlugins: [],
71
71
  persistOpen: false
72
72
  }
73
73
  };
@@ -198,8 +198,21 @@ var generatePluginId = (plugin, index) => {
198
198
  }
199
199
  return index.toString();
200
200
  };
201
+ function getStateFromLocalStorage(plugins) {
202
+ const existingStateString = getStorageItem(TANSTACK_DEVTOOLS_STATE);
203
+ const existingState = tryParseJson(existingStateString);
204
+ const pluginIds = [];
205
+ if (existingState?.activePlugins) {
206
+ const originalLength = existingState.activePlugins.length;
207
+ existingState.activePlugins = existingState.activePlugins.filter((id) => pluginIds.includes(id));
208
+ if (existingState.activePlugins.length !== originalLength) {
209
+ setStorageItem(TANSTACK_DEVTOOLS_STATE, JSON.stringify(existingState));
210
+ }
211
+ }
212
+ return existingState;
213
+ }
201
214
  var getExistingStateFromStorage = (config, plugins) => {
202
- const existingState = getStorageItem(TANSTACK_DEVTOOLS_STATE);
215
+ const existingState = getStateFromLocalStorage();
203
216
  const settings = getSettings();
204
217
  const state = {
205
218
  ...initialState,
@@ -212,7 +225,7 @@ var getExistingStateFromStorage = (config, plugins) => {
212
225
  }) || [],
213
226
  state: {
214
227
  ...initialState.state,
215
- ...existingState ? JSON.parse(existingState) : {}
228
+ ...existingState
216
229
  },
217
230
  settings: {
218
231
  ...initialState.settings,
package/dist/dev.js CHANGED
@@ -1,5 +1,5 @@
1
- import { initialState, DevtoolsProvider, PiPProvider } from './chunk/CEHNENNI.js';
2
- export { PLUGIN_CONTAINER_ID, PLUGIN_TITLE_CONTAINER_ID } from './chunk/CEHNENNI.js';
1
+ import { initialState, DevtoolsProvider, PiPProvider } from './chunk/EYSAUXP6.js';
2
+ export { PLUGIN_CONTAINER_ID, PLUGIN_TITLE_CONTAINER_ID } from './chunk/EYSAUXP6.js';
3
3
  import { render, createComponent, Portal } from 'solid-js/web';
4
4
  import { lazy } from 'solid-js';
5
5
  import { ClientEventBus } from '@tanstack/devtools-event-bus/client';
@@ -29,7 +29,7 @@ var TanStackDevtoolsCore = class {
29
29
  const mountTo = el;
30
30
  const dispose = render(() => {
31
31
  const _self$ = this;
32
- this.#Component = lazy(() => import('./devtools/67YFWU65.js'));
32
+ this.#Component = lazy(() => import('./devtools/73UYH4PF.js'));
33
33
  const Devtools = this.#Component;
34
34
  this.#eventBus = new ClientEventBus(this.#eventBusConfig);
35
35
  this.#eventBus.start();
@@ -1,4 +1,4 @@
1
- import { usePiPWindow, keyboardModifiers, getAllPermutations, TANSTACK_DEVTOOLS, DevtoolsContext, PLUGIN_TITLE_CONTAINER_ID, PLUGIN_CONTAINER_ID, uppercaseFirstLetter } from '../chunk/CEHNENNI.js';
1
+ import { usePiPWindow, keyboardModifiers, getAllPermutations, TANSTACK_DEVTOOLS, DevtoolsContext, PLUGIN_TITLE_CONTAINER_ID, PLUGIN_CONTAINER_ID, uppercaseFirstLetter } from '../chunk/EYSAUXP6.js';
2
2
  import { createComponent, Portal, ssr, ssrAttribute, escape } from 'solid-js/web';
3
3
  import { createContext, createSignal, createEffect, onCleanup, Show, createMemo, For, useContext, onMount } from 'solid-js';
4
4
  import { createShortcut } from '@solid-primitives/keyboard';
@@ -78,24 +78,29 @@ var usePlugins = () => {
78
78
  const { store, setStore } = useDevtoolsContext();
79
79
  const { setForceExpand } = useDrawContext();
80
80
  const plugins = createMemo(() => store.plugins);
81
- const activePlugin = createMemo(() => store.state.activePlugin);
81
+ const activePlugins = createMemo(() => store.state.activePlugins);
82
82
  createEffect(() => {
83
- if (activePlugin() == null) {
84
- setForceExpand(false);
85
- } else {
83
+ if (activePlugins().length === 0) {
86
84
  setForceExpand(true);
85
+ } else {
86
+ setForceExpand(false);
87
87
  }
88
88
  });
89
- const setActivePlugin = (pluginId) => {
90
- setStore((prev) => ({
91
- ...prev,
92
- state: {
93
- ...prev.state,
94
- activePlugin: pluginId
95
- }
96
- }));
89
+ const toggleActivePlugins = (pluginId) => {
90
+ setStore((prev) => {
91
+ const isActive = prev.state.activePlugins.includes(pluginId);
92
+ const updatedPlugins = isActive ? prev.state.activePlugins.filter((id) => id !== pluginId) : [...prev.state.activePlugins, pluginId];
93
+ if (updatedPlugins.length > 3) return prev;
94
+ return {
95
+ ...prev,
96
+ state: {
97
+ ...prev.state,
98
+ activePlugins: updatedPlugins
99
+ }
100
+ };
101
+ });
97
102
  };
98
- return { plugins, setActivePlugin, activePlugin };
103
+ return { plugins, toggleActivePlugins, activePlugins };
99
104
  };
100
105
  var useDevtoolsState = () => {
101
106
  const { store, setStore } = useDevtoolsContext();
@@ -1182,24 +1187,34 @@ var SettingsTab = () => {
1182
1187
  }
1183
1188
  });
1184
1189
  };
1185
- var _tmpl$6 = ["<div", "><div", "><div", ">", "</div></div><div", "></div></div>"];
1186
- var _tmpl$24 = ["<div", "><h3", "></h3></div>"];
1190
+ var _tmpl$6 = ["<div", "><div", "><div", ">", "</div></div>", "</div>"];
1191
+ var _tmpl$24 = ["<div", '><h3 id="', '"></h3></div>'];
1192
+ var _tmpl$33 = ['<div id="', '"', "></div>"];
1187
1193
  var PluginsTab = () => {
1188
1194
  const {
1189
1195
  plugins,
1190
- activePlugin,
1191
- setActivePlugin
1196
+ activePlugins,
1197
+ toggleActivePlugins
1192
1198
  } = usePlugins();
1193
1199
  const {
1194
1200
  expanded,
1195
1201
  hoverUtils,
1196
1202
  animationMs
1197
1203
  } = useDrawContext();
1198
- useTheme();
1204
+ const [pluginRefs, setPluginRefs] = createSignal(/* @__PURE__ */ new Map());
1205
+ const styles = useStyles();
1206
+ const {
1207
+ theme
1208
+ } = useTheme();
1199
1209
  createEffect(() => {
1200
- plugins()?.find((plugin) => plugin.id === activePlugin());
1210
+ const currentActivePlugins = plugins()?.filter((plugin) => activePlugins().includes(plugin.id));
1211
+ currentActivePlugins?.forEach((plugin) => {
1212
+ const ref = pluginRefs().get(plugin.id);
1213
+ if (ref) {
1214
+ plugin.render(ref, theme());
1215
+ }
1216
+ });
1201
1217
  });
1202
- const styles = useStyles();
1203
1218
  return ssr(_tmpl$6, ssrAttribute("class", escape(styles().pluginsTabPanel, true), false), ssrAttribute("class", escape(clsx3(styles().pluginsTabDraw(expanded()), {
1204
1219
  [styles().pluginsTabDraw(expanded())]: expanded()
1205
1220
  }, styles().pluginsTabDrawTransition(animationMs)), true), false), ssrAttribute("class", escape(clsx3(styles().pluginsTabSidebar(expanded()), styles().pluginsTabSidebarTransition(animationMs)), true), false), escape(createComponent(For, {
@@ -1209,11 +1224,17 @@ var PluginsTab = () => {
1209
1224
  children: (plugin) => {
1210
1225
  createEffect(() => {
1211
1226
  });
1227
+ const isActive = createMemo(() => activePlugins().includes(plugin.id));
1212
1228
  return ssr(_tmpl$24, ssrAttribute("class", escape(clsx3(styles().pluginName, {
1213
- active: activePlugin() === plugin.id
1214
- }), true), false), ssrAttribute("id", escape(PLUGIN_TITLE_CONTAINER_ID, true), false));
1229
+ active: isActive()
1230
+ }), true), false), `${escape(PLUGIN_TITLE_CONTAINER_ID, true)}-${escape(plugin.id, true)}`);
1215
1231
  }
1216
- })), ssrAttribute("id", escape(PLUGIN_CONTAINER_ID, true), false) + ssrAttribute("class", escape(styles().pluginsTabContent, true), false));
1232
+ })), escape(createComponent(For, {
1233
+ get each() {
1234
+ return activePlugins();
1235
+ },
1236
+ children: (pluginId) => ssr(_tmpl$33, `${escape(PLUGIN_CONTAINER_ID, true)}-${escape(pluginId, true)}`, ssrAttribute("class", escape(styles().pluginsTabContent, true), false))
1237
+ })));
1217
1238
  };
1218
1239
  function useHeadChanges(onChange, opts = {}) {
1219
1240
  const {
@@ -1279,7 +1300,7 @@ function useHeadChanges(onChange, opts = {}) {
1279
1300
  // src/tabs/seo-tab.tsx
1280
1301
  var _tmpl$7 = ["<div", ' style="', '"><div', ' style="', '">', " Preview</div>", "<div", ">", "</div><div", ">", "</div><div", ">", "</div></div>"];
1281
1302
  var _tmpl$25 = ["<img", ' alt="Preview"', ">"];
1282
- var _tmpl$33 = ["<div", ' style="', '">No Image</div>'];
1303
+ var _tmpl$34 = ["<div", ' style="', '">No Image</div>'];
1283
1304
  var _tmpl$43 = ["<div", ">", "</div>"];
1284
1305
  var _tmpl$52 = ["<div>", "", "</div>"];
1285
1306
  var _tmpl$62 = ["<div", "><strong>Missing tags for ", ":</strong><ul", ">", "</ul></div>"];
@@ -1408,7 +1429,7 @@ var SOCIALS = [
1408
1429
  ];
1409
1430
  function SocialPreview(props) {
1410
1431
  const styles = useStyles();
1411
- return ssr(_tmpl$7, ssrAttribute("class", escape(styles().seoPreviewCard, true), false), "border-color:" + escape(props.color, true), ssrAttribute("class", escape(styles().seoPreviewHeader, true), false), "color:" + escape(props.color, true), escape(props.network), props.meta.image ? ssr(_tmpl$25, ssrAttribute("src", escape(props.meta.image, true), false), ssrAttribute("class", escape(styles().seoPreviewImage, true), false)) : ssr(_tmpl$33, ssrAttribute("class", escape(styles().seoPreviewImage, true), false), "background:#222;color:#888;display:flex;align-items:center;justify-content:center;min-height:80px;width:100%"), ssrAttribute("class", escape(styles().seoPreviewTitle, true), false), escape(props.meta.title) || "No Title", ssrAttribute("class", escape(styles().seoPreviewDesc, true), false), escape(props.meta.description) || "No Description", ssrAttribute("class", escape(styles().seoPreviewUrl, true), false), escape(props.meta.url) || escape(window.location.href));
1432
+ return ssr(_tmpl$7, ssrAttribute("class", escape(styles().seoPreviewCard, true), false), "border-color:" + escape(props.color, true), ssrAttribute("class", escape(styles().seoPreviewHeader, true), false), "color:" + escape(props.color, true), escape(props.network), props.meta.image ? ssr(_tmpl$25, ssrAttribute("src", escape(props.meta.image, true), false), ssrAttribute("class", escape(styles().seoPreviewImage, true), false)) : ssr(_tmpl$34, ssrAttribute("class", escape(styles().seoPreviewImage, true), false), "background:#222;color:#888;display:flex;align-items:center;justify-content:center;min-height:80px;width:100%"), ssrAttribute("class", escape(styles().seoPreviewTitle, true), false), escape(props.meta.title) || "No Title", ssrAttribute("class", escape(styles().seoPreviewDesc, true), false), escape(props.meta.description) || "No Description", ssrAttribute("class", escape(styles().seoPreviewUrl, true), false), escape(props.meta.url) || escape(window.location.href));
1412
1433
  }
1413
1434
  var SeoTab = () => {
1414
1435
  const [reports, setReports] = createSignal(analyzeHead());
@@ -1504,7 +1525,7 @@ var tabs = [{
1504
1525
  // src/components/tabs.tsx
1505
1526
  var _tmpl$8 = ["<div", ">", "", "</div>"];
1506
1527
  var _tmpl$26 = ['<button type="button"', ">", "</button>"];
1507
- var _tmpl$34 = ['<div style="', '"><button type="button"', ">", '</button><button type="button"', ">", "</button></div>"];
1528
+ var _tmpl$35 = ['<div style="', '"><button type="button"', ">", '</button><button type="button"', ">", "</button></div>"];
1508
1529
  var Tabs = (props) => {
1509
1530
  const styles = useStyles();
1510
1531
  const {
@@ -1520,7 +1541,7 @@ var Tabs = (props) => {
1520
1541
  children: (tab) => ssr(_tmpl$26, ssrAttribute("class", escape(clsx3(styles().tab, {
1521
1542
  active: state().activeTab === tab.id
1522
1543
  }), true), false), escape(tab.icon()))
1523
- })), pipWindow().pipWindow !== null ? escape(null) : ssr(_tmpl$34, "margin-top:auto", ssrAttribute("class", escape(clsx3(styles().tab, "detach"), true), false), escape(createComponent(PiP, {})), ssrAttribute("class", escape(clsx3(styles().tab, "close"), true), false), escape(createComponent(X, {}))));
1544
+ })), pipWindow().pipWindow !== null ? escape(null) : ssr(_tmpl$35, "margin-top:auto", ssrAttribute("class", escape(clsx3(styles().tab, "detach"), true), false), escape(createComponent(PiP, {})), ssrAttribute("class", escape(clsx3(styles().tab, "close"), true), false), escape(createComponent(X, {}))));
1524
1545
  };
1525
1546
  var _tmpl$9 = ["<div", ">", "</div>"];
1526
1547
  var TabContent = () => {
@@ -1628,7 +1649,7 @@ function DevTools() {
1628
1649
  if (dataSource) {
1629
1650
  e.preventDefault();
1630
1651
  e.stopPropagation();
1631
- fetch(`__TSD_HOST__://localhost:__TSD_PORT__/__tsd/open-source?source=${encodeURIComponent(dataSource)}`).catch(() => {
1652
+ fetch(`${location.origin}/__tsd/open-source?source=${encodeURIComponent(dataSource)}`).catch(() => {
1632
1653
  });
1633
1654
  }
1634
1655
  }
@@ -1,4 +1,4 @@
1
- import { usePiPWindow, keyboardModifiers, getAllPermutations, TANSTACK_DEVTOOLS, DevtoolsContext, PLUGIN_TITLE_CONTAINER_ID, PLUGIN_CONTAINER_ID, uppercaseFirstLetter } from '../chunk/CEHNENNI.js';
1
+ import { usePiPWindow, keyboardModifiers, getAllPermutations, TANSTACK_DEVTOOLS, DevtoolsContext, PLUGIN_TITLE_CONTAINER_ID, PLUGIN_CONTAINER_ID, uppercaseFirstLetter } from '../chunk/EYSAUXP6.js';
2
2
  import { delegateEvents, createComponent, Portal, template, use, setAttribute, insert, memo, effect, className, addEventListener } from 'solid-js/web';
3
3
  import { createContext, createSignal, createEffect, onCleanup, Show, createMemo, For, useContext, onMount } from 'solid-js';
4
4
  import { createShortcut } from '@solid-primitives/keyboard';
@@ -78,24 +78,29 @@ var usePlugins = () => {
78
78
  const { store, setStore } = useDevtoolsContext();
79
79
  const { setForceExpand } = useDrawContext();
80
80
  const plugins = createMemo(() => store.plugins);
81
- const activePlugin = createMemo(() => store.state.activePlugin);
81
+ const activePlugins = createMemo(() => store.state.activePlugins);
82
82
  createEffect(() => {
83
- if (activePlugin() == null) {
84
- setForceExpand(false);
85
- } else {
83
+ if (activePlugins().length === 0) {
86
84
  setForceExpand(true);
85
+ } else {
86
+ setForceExpand(false);
87
87
  }
88
88
  });
89
- const setActivePlugin = (pluginId) => {
90
- setStore((prev) => ({
91
- ...prev,
92
- state: {
93
- ...prev.state,
94
- activePlugin: pluginId
95
- }
96
- }));
89
+ const toggleActivePlugins = (pluginId) => {
90
+ setStore((prev) => {
91
+ const isActive = prev.state.activePlugins.includes(pluginId);
92
+ const updatedPlugins = isActive ? prev.state.activePlugins.filter((id) => id !== pluginId) : [...prev.state.activePlugins, pluginId];
93
+ if (updatedPlugins.length > 3) return prev;
94
+ return {
95
+ ...prev,
96
+ state: {
97
+ ...prev.state,
98
+ activePlugins: updatedPlugins
99
+ }
100
+ };
101
+ });
97
102
  };
98
- return { plugins, setActivePlugin, activePlugin };
103
+ return { plugins, toggleActivePlugins, activePlugins };
99
104
  };
100
105
  var useDevtoolsState = () => {
101
106
  const { store, setStore } = useDevtoolsContext();
@@ -1262,38 +1267,38 @@ var SettingsTab = () => {
1262
1267
  }
1263
1268
  });
1264
1269
  };
1265
- var _tmpl$5 = /* @__PURE__ */ template(`<div><div><div></div></div><div>`);
1270
+ var _tmpl$5 = /* @__PURE__ */ template(`<div><div><div>`);
1266
1271
  var _tmpl$23 = /* @__PURE__ */ template(`<div><h3>`);
1272
+ var _tmpl$33 = /* @__PURE__ */ template(`<div>`);
1267
1273
  var PluginsTab = () => {
1268
1274
  const {
1269
1275
  plugins,
1270
- activePlugin,
1271
- setActivePlugin
1276
+ activePlugins,
1277
+ toggleActivePlugins
1272
1278
  } = usePlugins();
1273
1279
  const {
1274
1280
  expanded,
1275
1281
  hoverUtils,
1276
1282
  animationMs
1277
1283
  } = useDrawContext();
1278
- let activePluginRef;
1284
+ const [pluginRefs, setPluginRefs] = createSignal(/* @__PURE__ */ new Map());
1285
+ const styles = useStyles();
1279
1286
  const {
1280
1287
  theme
1281
1288
  } = useTheme();
1282
1289
  createEffect(() => {
1283
- const currentActivePlugin = plugins()?.find((plugin) => plugin.id === activePlugin());
1284
- if (activePluginRef && currentActivePlugin) {
1285
- currentActivePlugin.render(activePluginRef, theme());
1286
- }
1290
+ const currentActivePlugins = plugins()?.filter((plugin) => activePlugins().includes(plugin.id));
1291
+ currentActivePlugins?.forEach((plugin) => {
1292
+ const ref = pluginRefs().get(plugin.id);
1293
+ if (ref) {
1294
+ plugin.render(ref, theme());
1295
+ }
1296
+ });
1287
1297
  });
1288
- const styles = useStyles();
1289
1298
  return (() => {
1290
- var _el$ = _tmpl$5(), _el$2 = _el$.firstChild, _el$3 = _el$2.firstChild, _el$4 = _el$2.nextSibling;
1291
- _el$2.addEventListener("mouseleave", () => {
1292
- hoverUtils.leave();
1293
- });
1294
- _el$2.addEventListener("mouseenter", () => {
1295
- hoverUtils.enter();
1296
- });
1299
+ var _el$ = _tmpl$5(), _el$2 = _el$.firstChild, _el$3 = _el$2.firstChild;
1300
+ _el$2.addEventListener("mouseleave", () => hoverUtils.leave());
1301
+ _el$2.addEventListener("mouseenter", () => hoverUtils.enter());
1297
1302
  insert(_el$3, createComponent(For, {
1298
1303
  get each() {
1299
1304
  return plugins();
@@ -1305,36 +1310,59 @@ var PluginsTab = () => {
1305
1310
  typeof plugin.name === "string" ? pluginHeading.textContent = plugin.name : plugin.name(pluginHeading, theme());
1306
1311
  }
1307
1312
  });
1313
+ const isActive = createMemo(() => activePlugins().includes(plugin.id));
1308
1314
  return (() => {
1309
- var _el$5 = _tmpl$23(), _el$6 = _el$5.firstChild;
1310
- _el$5.$$click = () => setActivePlugin(plugin.id);
1311
- var _ref$2 = pluginHeading;
1312
- typeof _ref$2 === "function" ? use(_ref$2, _el$6) : pluginHeading = _el$6;
1313
- setAttribute(_el$6, "id", PLUGIN_TITLE_CONTAINER_ID);
1314
- effect(() => className(_el$5, clsx3(styles().pluginName, {
1315
- active: activePlugin() === plugin.id
1316
- })));
1317
- return _el$5;
1315
+ var _el$4 = _tmpl$23(), _el$5 = _el$4.firstChild;
1316
+ _el$4.$$click = () => {
1317
+ toggleActivePlugins(plugin.id);
1318
+ };
1319
+ var _ref$ = pluginHeading;
1320
+ typeof _ref$ === "function" ? use(_ref$, _el$5) : pluginHeading = _el$5;
1321
+ effect((_p$) => {
1322
+ var _v$4 = clsx3(styles().pluginName, {
1323
+ active: isActive()
1324
+ }), _v$5 = `${PLUGIN_TITLE_CONTAINER_ID}-${plugin.id}`;
1325
+ _v$4 !== _p$.e && className(_el$4, _p$.e = _v$4);
1326
+ _v$5 !== _p$.t && setAttribute(_el$5, "id", _p$.t = _v$5);
1327
+ return _p$;
1328
+ }, {
1329
+ e: void 0,
1330
+ t: void 0
1331
+ });
1332
+ return _el$4;
1318
1333
  })();
1319
1334
  }
1320
1335
  }));
1321
- var _ref$ = activePluginRef;
1322
- typeof _ref$ === "function" ? use(_ref$, _el$4) : activePluginRef = _el$4;
1323
- setAttribute(_el$4, "id", PLUGIN_CONTAINER_ID);
1336
+ insert(_el$, createComponent(For, {
1337
+ get each() {
1338
+ return activePlugins();
1339
+ },
1340
+ children: (pluginId) => (() => {
1341
+ var _el$6 = _tmpl$33();
1342
+ use((el) => {
1343
+ setPluginRefs((prev) => {
1344
+ const updated = new Map(prev);
1345
+ updated.set(pluginId, el);
1346
+ return updated;
1347
+ });
1348
+ }, _el$6);
1349
+ setAttribute(_el$6, "id", `${PLUGIN_CONTAINER_ID}-${pluginId}`);
1350
+ effect(() => className(_el$6, styles().pluginsTabContent));
1351
+ return _el$6;
1352
+ })()
1353
+ }), null);
1324
1354
  effect((_p$) => {
1325
1355
  var _v$ = styles().pluginsTabPanel, _v$2 = clsx3(styles().pluginsTabDraw(expanded()), {
1326
1356
  [styles().pluginsTabDraw(expanded())]: expanded()
1327
- }, styles().pluginsTabDrawTransition(animationMs)), _v$3 = clsx3(styles().pluginsTabSidebar(expanded()), styles().pluginsTabSidebarTransition(animationMs)), _v$4 = styles().pluginsTabContent;
1357
+ }, styles().pluginsTabDrawTransition(animationMs)), _v$3 = clsx3(styles().pluginsTabSidebar(expanded()), styles().pluginsTabSidebarTransition(animationMs));
1328
1358
  _v$ !== _p$.e && className(_el$, _p$.e = _v$);
1329
1359
  _v$2 !== _p$.t && className(_el$2, _p$.t = _v$2);
1330
1360
  _v$3 !== _p$.a && className(_el$3, _p$.a = _v$3);
1331
- _v$4 !== _p$.o && className(_el$4, _p$.o = _v$4);
1332
1361
  return _p$;
1333
1362
  }, {
1334
1363
  e: void 0,
1335
1364
  t: void 0,
1336
- a: void 0,
1337
- o: void 0
1365
+ a: void 0
1338
1366
  });
1339
1367
  return _el$;
1340
1368
  })();
@@ -1404,7 +1432,7 @@ function useHeadChanges(onChange, opts = {}) {
1404
1432
  // src/tabs/seo-tab.tsx
1405
1433
  var _tmpl$6 = /* @__PURE__ */ template(`<div><div> Preview</div><div></div><div></div><div>`);
1406
1434
  var _tmpl$24 = /* @__PURE__ */ template(`<img alt=Preview>`);
1407
- var _tmpl$33 = /* @__PURE__ */ template(`<div>No Image`);
1435
+ var _tmpl$34 = /* @__PURE__ */ template(`<div>No Image`);
1408
1436
  var _tmpl$42 = /* @__PURE__ */ template(`<div>`);
1409
1437
  var _tmpl$52 = /* @__PURE__ */ template(`<div><strong>Missing tags for <!>:</strong><ul>`);
1410
1438
  var _tmpl$62 = /* @__PURE__ */ template(`<li>`);
@@ -1550,7 +1578,7 @@ function SocialPreview(props) {
1550
1578
  });
1551
1579
  return _el$7;
1552
1580
  })() : (() => {
1553
- var _el$8 = _tmpl$33();
1581
+ var _el$8 = _tmpl$34();
1554
1582
  _el$8.style.setProperty("background", "#222");
1555
1583
  _el$8.style.setProperty("color", "#888");
1556
1584
  _el$8.style.setProperty("display", "flex");
@@ -1713,7 +1741,7 @@ var tabs = [{
1713
1741
  // src/components/tabs.tsx
1714
1742
  var _tmpl$7 = /* @__PURE__ */ template(`<div>`);
1715
1743
  var _tmpl$25 = /* @__PURE__ */ template(`<button type=button>`);
1716
- var _tmpl$34 = /* @__PURE__ */ template(`<div><button type=button></button><button type=button>`);
1744
+ var _tmpl$35 = /* @__PURE__ */ template(`<div><button type=button></button><button type=button>`);
1717
1745
  var Tabs = (props) => {
1718
1746
  const styles = useStyles();
1719
1747
  const {
@@ -1752,7 +1780,7 @@ var Tabs = (props) => {
1752
1780
  insert(_el$, (() => {
1753
1781
  var _c$ = memo(() => pipWindow().pipWindow !== null);
1754
1782
  return () => _c$() ? null : (() => {
1755
- var _el$3 = _tmpl$34(), _el$4 = _el$3.firstChild, _el$5 = _el$4.nextSibling;
1783
+ var _el$3 = _tmpl$35(), _el$4 = _el$3.firstChild, _el$5 = _el$4.nextSibling;
1756
1784
  _el$3.style.setProperty("margin-top", "auto");
1757
1785
  _el$4.$$click = handleDetachment;
1758
1786
  insert(_el$4, createComponent(PiP, {}));
@@ -1915,7 +1943,7 @@ function DevTools() {
1915
1943
  if (dataSource) {
1916
1944
  e.preventDefault();
1917
1945
  e.stopPropagation();
1918
- fetch(`__TSD_HOST__://localhost:__TSD_PORT__/__tsd/open-source?source=${encodeURIComponent(dataSource)}`).catch(() => {
1946
+ fetch(`${location.origin}/__tsd/open-source?source=${encodeURIComponent(dataSource)}`).catch(() => {
1919
1947
  });
1920
1948
  }
1921
1949
  }
package/dist/index.d.ts CHANGED
@@ -72,7 +72,7 @@ type DevtoolsStore = {
72
72
  state: {
73
73
  activeTab: TabName;
74
74
  height: number;
75
- activePlugin?: string | undefined;
75
+ activePlugins: Array<string>;
76
76
  persistOpen: boolean;
77
77
  };
78
78
  plugins?: Array<TanStackDevtoolsPlugin>;
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { initialState, DevtoolsProvider, PiPProvider } from './chunk/CEHNENNI.js';
2
- export { PLUGIN_CONTAINER_ID, PLUGIN_TITLE_CONTAINER_ID } from './chunk/CEHNENNI.js';
1
+ import { initialState, DevtoolsProvider, PiPProvider } from './chunk/EYSAUXP6.js';
2
+ export { PLUGIN_CONTAINER_ID, PLUGIN_TITLE_CONTAINER_ID } from './chunk/EYSAUXP6.js';
3
3
  import { render, createComponent, Portal } from 'solid-js/web';
4
4
  import { lazy } from 'solid-js';
5
5
  import { ClientEventBus } from '@tanstack/devtools-event-bus/client';
@@ -29,7 +29,7 @@ var TanStackDevtoolsCore = class {
29
29
  const mountTo = el;
30
30
  const dispose = render(() => {
31
31
  const _self$ = this;
32
- this.#Component = lazy(() => import('./devtools/67YFWU65.js'));
32
+ this.#Component = lazy(() => import('./devtools/73UYH4PF.js'));
33
33
  const Devtools = this.#Component;
34
34
  this.#eventBus = new ClientEventBus(this.#eventBusConfig);
35
35
  this.#eventBus.start();
package/dist/server.js CHANGED
@@ -1,5 +1,5 @@
1
- import { initialState } from './chunk/CEHNENNI.js';
2
- export { PLUGIN_CONTAINER_ID, PLUGIN_TITLE_CONTAINER_ID } from './chunk/CEHNENNI.js';
1
+ import { initialState } from './chunk/EYSAUXP6.js';
2
+ export { PLUGIN_CONTAINER_ID, PLUGIN_TITLE_CONTAINER_ID } from './chunk/EYSAUXP6.js';
3
3
  import 'solid-js/web';
4
4
  import 'solid-js';
5
5
  import '@tanstack/devtools-event-bus/client';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/devtools",
3
- "version": "0.6.10",
3
+ "version": "0.6.12",
4
4
  "description": "TanStack Devtools is a set of tools for building advanced devtools for your application.",
5
5
  "author": "Tanner Linsley",
6
6
  "license": "MIT",
@@ -50,7 +50,7 @@
50
50
  "goober": "^2.1.16",
51
51
  "solid-js": "^1.9.7",
52
52
  "@tanstack/devtools-event-bus": "0.3.2",
53
- "@tanstack/devtools-ui": "0.3.4"
53
+ "@tanstack/devtools-ui": "0.3.5"
54
54
  },
55
55
  "peerDependencies": {
56
56
  "solid-js": ">=1.9.7"
@@ -0,0 +1,59 @@
1
+ import { beforeEach, describe, expect, it } from 'vitest'
2
+ import { TANSTACK_DEVTOOLS_STATE } from '../utils/storage'
3
+ import { getStateFromLocalStorage } from './devtools-context'
4
+
5
+ describe('getStateFromLocalStorage', () => {
6
+ beforeEach(() => {
7
+ localStorage.clear()
8
+ })
9
+ it('should return undefined when no data in localStorage', () => {
10
+ const state = getStateFromLocalStorage()
11
+ expect(state).toEqual(undefined)
12
+ })
13
+ it('should return parsed state from localStorage and not remove valid plugins', () => {
14
+ const mockState = {
15
+ activePlugins: ['plugin1'],
16
+ settings: {
17
+ theme: 'dark',
18
+ },
19
+ }
20
+ localStorage.setItem(TANSTACK_DEVTOOLS_STATE, JSON.stringify(mockState))
21
+ const state = getStateFromLocalStorage([
22
+ {
23
+ id: 'plugin1',
24
+ render: () => {},
25
+ name: 'Plugin 1',
26
+ },
27
+ ])
28
+ expect(state).toEqual(mockState)
29
+ })
30
+ it('should filter out inactive plugins', () => {
31
+ const mockState = {
32
+ activePlugins: ['plugin1', 'plugin2'],
33
+ settings: {
34
+ theme: 'dark',
35
+ },
36
+ }
37
+ localStorage.setItem(TANSTACK_DEVTOOLS_STATE, JSON.stringify(mockState))
38
+ const plugins = [{ id: 'plugin1', render: () => {}, name: 'Plugin 1' }]
39
+ const state = getStateFromLocalStorage(plugins)
40
+ expect(state?.activePlugins).toEqual(['plugin1'])
41
+ })
42
+ it('should return empty plugin state if all active plugins are invalid', () => {
43
+ const mockState = {
44
+ activePlugins: ['plugin1', 'plugin2'],
45
+ settings: {
46
+ theme: 'dark',
47
+ },
48
+ }
49
+ localStorage.setItem(TANSTACK_DEVTOOLS_STATE, JSON.stringify(mockState))
50
+ const plugins = [{ id: 'plugin3', render: () => {}, name: 'Plugin 3' }]
51
+ const state = getStateFromLocalStorage(plugins)
52
+ expect(state?.activePlugins).toEqual([])
53
+ })
54
+ it('should handle invalid JSON in localStorage gracefully', () => {
55
+ localStorage.setItem(TANSTACK_DEVTOOLS_STATE, 'invalid json')
56
+ const state = getStateFromLocalStorage()
57
+ expect(state).toEqual(undefined)
58
+ })
59
+ })
@@ -99,11 +99,35 @@ const generatePluginId = (plugin: TanStackDevtoolsPlugin, index: number) => {
99
99
  return index.toString()
100
100
  }
101
101
 
102
+ export function getStateFromLocalStorage(
103
+ plugins?: Array<TanStackDevtoolsPlugin>,
104
+ ) {
105
+ const existingStateString = getStorageItem(TANSTACK_DEVTOOLS_STATE)
106
+ const existingState =
107
+ tryParseJson<DevtoolsStore['state']>(existingStateString)
108
+ const pluginIds =
109
+ plugins?.map((plugin, i) => generatePluginId(plugin, i)) || []
110
+ if (existingState?.activePlugins) {
111
+ const originalLength = existingState.activePlugins.length
112
+ // Filter out any active plugins that are no longer available
113
+ existingState.activePlugins = existingState.activePlugins.filter((id) =>
114
+ pluginIds.includes(id),
115
+ )
116
+
117
+ if (existingState.activePlugins.length !== originalLength) {
118
+ // If any active plugins were removed, update local storage
119
+ setStorageItem(TANSTACK_DEVTOOLS_STATE, JSON.stringify(existingState))
120
+ }
121
+ }
122
+
123
+ return existingState
124
+ }
125
+
102
126
  const getExistingStateFromStorage = (
103
127
  config?: TanStackDevtoolsConfig,
104
128
  plugins?: Array<TanStackDevtoolsPlugin>,
105
129
  ) => {
106
- const existingState = getStorageItem(TANSTACK_DEVTOOLS_STATE)
130
+ const existingState = getStateFromLocalStorage()
107
131
  const settings = getSettings()
108
132
 
109
133
  const state: DevtoolsStore = {
@@ -118,7 +142,7 @@ const getExistingStateFromStorage = (
118
142
  }) || [],
119
143
  state: {
120
144
  ...initialState.state,
121
- ...(existingState ? JSON.parse(existingState) : {}),
145
+ ...existingState,
122
146
  },
123
147
  settings: {
124
148
  ...initialState.settings,
@@ -65,7 +65,7 @@ export type DevtoolsStore = {
65
65
  state: {
66
66
  activeTab: TabName
67
67
  height: number
68
- activePlugin?: string | undefined
68
+ activePlugins: Array<string>
69
69
  persistOpen: boolean
70
70
  }
71
71
  plugins?: Array<TanStackDevtoolsPlugin>
@@ -82,6 +82,7 @@ export const initialState: DevtoolsStore = {
82
82
  urlFlag: 'tanstack-devtools',
83
83
  theme:
84
84
  typeof window !== 'undefined' &&
85
+ typeof window.matchMedia !== 'undefined' &&
85
86
  window.matchMedia('(prefers-color-scheme: dark)').matches
86
87
  ? 'dark'
87
88
  : 'light',
@@ -89,7 +90,7 @@ export const initialState: DevtoolsStore = {
89
90
  state: {
90
91
  activeTab: 'plugins',
91
92
  height: 400,
92
- activePlugin: undefined,
93
+ activePlugins: [],
93
94
  persistOpen: false,
94
95
  },
95
96
  }
@@ -33,27 +33,35 @@ export const usePlugins = () => {
33
33
  const { setForceExpand } = useDrawContext()
34
34
 
35
35
  const plugins = createMemo(() => store.plugins)
36
- const activePlugin = createMemo(() => store.state.activePlugin)
36
+ const activePlugins = createMemo(() => store.state.activePlugins)
37
37
 
38
38
  createEffect(() => {
39
- if (activePlugin() == null) {
40
- setForceExpand(false)
41
- } else {
39
+ if (activePlugins().length === 0) {
42
40
  setForceExpand(true)
41
+ } else {
42
+ setForceExpand(false)
43
43
  }
44
44
  })
45
45
 
46
- const setActivePlugin = (pluginId: string) => {
47
- setStore((prev) => ({
48
- ...prev,
49
- state: {
50
- ...prev.state,
51
- activePlugin: pluginId,
52
- },
53
- }))
46
+ const toggleActivePlugins = (pluginId: string) => {
47
+ setStore((prev) => {
48
+ const isActive = prev.state.activePlugins.includes(pluginId)
49
+
50
+ const updatedPlugins = isActive
51
+ ? prev.state.activePlugins.filter((id) => id !== pluginId)
52
+ : [...prev.state.activePlugins, pluginId]
53
+ if (updatedPlugins.length > 3) return prev
54
+ return {
55
+ ...prev,
56
+ state: {
57
+ ...prev.state,
58
+ activePlugins: updatedPlugins,
59
+ },
60
+ }
61
+ })
54
62
  }
55
63
 
56
- return { plugins, setActivePlugin, activePlugin }
64
+ return { plugins, toggleActivePlugins, activePlugins }
57
65
  }
58
66
 
59
67
  export const useDevtoolsState = () => {
package/src/devtools.tsx CHANGED
@@ -174,7 +174,9 @@ export default function DevTools() {
174
174
  e.preventDefault()
175
175
  e.stopPropagation()
176
176
  fetch(
177
- `__TSD_HOST__://localhost:__TSD_PORT__/__tsd/open-source?source=${encodeURIComponent(dataSource)}`,
177
+ `${location.origin}/__tsd/open-source?source=${encodeURIComponent(
178
+ dataSource,
179
+ )}`,
178
180
  ).catch(() => {})
179
181
  }
180
182
  }
@@ -1,4 +1,4 @@
1
- import { For, createEffect } from 'solid-js'
1
+ import { For, createEffect, createMemo, createSignal } from 'solid-js'
2
2
  import clsx from 'clsx'
3
3
  import { useDrawContext } from '../context/draw-context'
4
4
  import { usePlugins, useTheme } from '../context/use-devtools-context'
@@ -6,20 +6,30 @@ import { useStyles } from '../styles/use-styles'
6
6
  import { PLUGIN_CONTAINER_ID, PLUGIN_TITLE_CONTAINER_ID } from '../constants'
7
7
 
8
8
  export const PluginsTab = () => {
9
- const { plugins, activePlugin, setActivePlugin } = usePlugins()
9
+ const { plugins, activePlugins, toggleActivePlugins } = usePlugins()
10
10
  const { expanded, hoverUtils, animationMs } = useDrawContext()
11
- let activePluginRef: HTMLDivElement | undefined
11
+
12
+ const [pluginRefs, setPluginRefs] = createSignal(
13
+ new Map<string, HTMLDivElement>(),
14
+ )
15
+
16
+ const styles = useStyles()
12
17
 
13
18
  const { theme } = useTheme()
14
19
  createEffect(() => {
15
- const currentActivePlugin = plugins()?.find(
16
- (plugin) => plugin.id === activePlugin(),
20
+ const currentActivePlugins = plugins()?.filter((plugin) =>
21
+ activePlugins().includes(plugin.id!),
17
22
  )
18
- if (activePluginRef && currentActivePlugin) {
19
- currentActivePlugin.render(activePluginRef, theme())
20
- }
23
+
24
+ currentActivePlugins?.forEach((plugin) => {
25
+ const ref = pluginRefs().get(plugin.id!)
26
+
27
+ if (ref) {
28
+ plugin.render(ref, theme())
29
+ }
30
+ })
21
31
  })
22
- const styles = useStyles()
32
+
23
33
  return (
24
34
  <div class={styles().pluginsTabPanel}>
25
35
  <div
@@ -30,12 +40,8 @@ export const PluginsTab = () => {
30
40
  },
31
41
  styles().pluginsTabDrawTransition(animationMs),
32
42
  )}
33
- onMouseEnter={() => {
34
- hoverUtils.enter()
35
- }}
36
- onMouseLeave={() => {
37
- hoverUtils.leave()
38
- }}
43
+ onMouseEnter={() => hoverUtils.enter()}
44
+ onMouseLeave={() => hoverUtils.leave()}
39
45
  >
40
46
  <div
41
47
  class={clsx(
@@ -46,6 +52,7 @@ export const PluginsTab = () => {
46
52
  <For each={plugins()}>
47
53
  {(plugin) => {
48
54
  let pluginHeading: HTMLHeadingElement | undefined
55
+
49
56
  createEffect(() => {
50
57
  if (pluginHeading) {
51
58
  typeof plugin.name === 'string'
@@ -53,14 +60,24 @@ export const PluginsTab = () => {
53
60
  : plugin.name(pluginHeading, theme())
54
61
  }
55
62
  })
63
+
64
+ const isActive = createMemo(() =>
65
+ activePlugins().includes(plugin.id!),
66
+ )
67
+
56
68
  return (
57
69
  <div
58
- onClick={() => setActivePlugin(plugin.id!)}
70
+ onClick={() => {
71
+ toggleActivePlugins(plugin.id!)
72
+ }}
59
73
  class={clsx(styles().pluginName, {
60
- active: activePlugin() === plugin.id,
74
+ active: isActive(),
61
75
  })}
62
76
  >
63
- <h3 id={PLUGIN_TITLE_CONTAINER_ID} ref={pluginHeading} />
77
+ <h3
78
+ id={`${PLUGIN_TITLE_CONTAINER_ID}-${plugin.id}`}
79
+ ref={pluginHeading}
80
+ />
64
81
  </div>
65
82
  )
66
83
  }}
@@ -68,11 +85,21 @@ export const PluginsTab = () => {
68
85
  </div>
69
86
  </div>
70
87
 
71
- <div
72
- id={PLUGIN_CONTAINER_ID}
73
- ref={activePluginRef}
74
- class={styles().pluginsTabContent}
75
- ></div>
88
+ <For each={activePlugins()}>
89
+ {(pluginId) => (
90
+ <div
91
+ id={`${PLUGIN_CONTAINER_ID}-${pluginId}`}
92
+ ref={(el) => {
93
+ setPluginRefs((prev) => {
94
+ const updated = new Map(prev)
95
+ updated.set(pluginId, el)
96
+ return updated
97
+ })
98
+ }}
99
+ class={styles().pluginsTabContent}
100
+ />
101
+ )}
102
+ </For>
76
103
  </div>
77
104
  )
78
105
  }