@multiplatform.one/core 7.28.1 → 7.29.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/package.json +14 -18
- package/src/app/CreateApp.tsx +3 -2
- package/src/app/CreateRootLayout.hydration.spec.tsx +4 -2
- package/src/app/CreateRootLayout.native.tsx +2 -3
- package/src/app/CreateRootLayout.schemeClass.spec.tsx +6 -1
- package/src/app/CreateRootLayout.schemeInstance.spec.tsx +135 -0
- package/src/app/CreateRootLayout.web.spec.tsx +4 -2
- package/src/app/CreateRootLayout.web.tsx +11 -2
- package/src/app/TanstackDevtools.tsx +8 -2
- package/src/app/devtoolsTrigger.spec.ts +144 -44
- package/src/app/devtoolsTrigger.ts +71 -27
- package/types/app/CreateApp.d.ts +3 -2
- package/types/app/CreateApp.d.ts.map +1 -1
- package/types/app/CreateRootLayout.native.d.ts +1 -1
- package/types/app/CreateRootLayout.native.d.ts.map +1 -1
- package/types/app/CreateRootLayout.web.d.ts.map +1 -1
- package/types/app/TanstackDevtools.d.ts.map +1 -1
- package/types/app/devtoolsTrigger.d.ts +34 -20
- package/types/app/devtoolsTrigger.d.ts.map +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@multiplatform.one/core",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.29.1",
|
|
4
4
|
"description": "Core framework shell, provider composition, and layout factories for multiplatform.one",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"app",
|
|
@@ -41,24 +41,24 @@
|
|
|
41
41
|
"access": "public"
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"@multiplatform.one/i18n": "7.
|
|
45
|
-
"@multiplatform.one/logger": "7.
|
|
46
|
-
"@multiplatform.one/platform": "7.
|
|
47
|
-
"@multiplatform.one/store": "7.
|
|
48
|
-
"@multiplatform.one/theme": "7.
|
|
49
|
-
"@tanstack/devtools-event-client": "^0.4.3",
|
|
44
|
+
"@multiplatform.one/i18n": "7.29.1",
|
|
45
|
+
"@multiplatform.one/logger": "7.29.1",
|
|
46
|
+
"@multiplatform.one/platform": "7.29.1",
|
|
47
|
+
"@multiplatform.one/store": "7.29.1",
|
|
48
|
+
"@multiplatform.one/theme": "7.29.1",
|
|
50
49
|
"@tanstack/devtools-utils": "^0.4.0",
|
|
51
50
|
"@tanstack/pacer-devtools": "1.3.0",
|
|
52
|
-
"@tanstack/react-devtools": "
|
|
51
|
+
"@tanstack/react-devtools": "0.10.13",
|
|
53
52
|
"@tanstack/react-form-devtools": "0.2.22",
|
|
54
53
|
"react-cookie": "^8.1.2"
|
|
55
54
|
},
|
|
56
55
|
"devDependencies": {
|
|
57
|
-
"@multiplatform.one/frappe": "7.
|
|
58
|
-
"@multiplatform.one/web3": "7.
|
|
56
|
+
"@multiplatform.one/frappe": "7.29.1",
|
|
57
|
+
"@multiplatform.one/web3": "7.29.1",
|
|
59
58
|
"@sentry/react": "^10.51.0",
|
|
60
59
|
"@tanstack/react-query": "^5.100.7",
|
|
61
60
|
"@tanstack/react-query-devtools": "^5.100.7",
|
|
61
|
+
"@vxrn/color-scheme": "~1.16.5",
|
|
62
62
|
"i18next": "^25.10.10",
|
|
63
63
|
"one": "^1.16.5",
|
|
64
64
|
"react": "19.2.5",
|
|
@@ -72,14 +72,13 @@
|
|
|
72
72
|
"vitest": "^4.1.5"
|
|
73
73
|
},
|
|
74
74
|
"peerDependencies": {
|
|
75
|
-
"@multiplatform.one/frappe": "^7.
|
|
76
|
-
"@multiplatform.one/frappe-ui": "^7.
|
|
77
|
-
"@multiplatform.one/keycloak": "^7.
|
|
78
|
-
"@multiplatform.one/web3": "^7.
|
|
75
|
+
"@multiplatform.one/frappe": "^7.29.1",
|
|
76
|
+
"@multiplatform.one/frappe-ui": "^7.29.1",
|
|
77
|
+
"@multiplatform.one/keycloak": "^7.29.1",
|
|
78
|
+
"@multiplatform.one/web3": "^7.29.1",
|
|
79
79
|
"@sentry/react": "^9.0.0",
|
|
80
80
|
"@tanstack/react-query": "^5.0.0",
|
|
81
81
|
"@tanstack/react-query-devtools": "^5.0.0",
|
|
82
|
-
"@vxrn/color-scheme": "^1.0.0",
|
|
83
82
|
"expo-font": ">=11.0.0",
|
|
84
83
|
"i18next": "^25.0.0",
|
|
85
84
|
"one": "^1.0.0",
|
|
@@ -97,9 +96,6 @@
|
|
|
97
96
|
"@sentry/react": {
|
|
98
97
|
"optional": true
|
|
99
98
|
},
|
|
100
|
-
"@vxrn/color-scheme": {
|
|
101
|
-
"optional": true
|
|
102
|
-
},
|
|
103
99
|
"i18next": {
|
|
104
100
|
"optional": true
|
|
105
101
|
},
|
package/src/app/CreateApp.tsx
CHANGED
|
@@ -103,8 +103,9 @@ export interface TanstackConfig {
|
|
|
103
103
|
/** Options forwarded to the QueryClient constructor. */
|
|
104
104
|
queryClientOptions?: Record<string, unknown>;
|
|
105
105
|
/**
|
|
106
|
-
* Pass `useUserScheme` from `one`
|
|
107
|
-
*
|
|
106
|
+
* Pass `useUserScheme` from `one` so the theme devtools panel can control
|
|
107
|
+
* the color scheme (light / dark / system). It must be `one`'s: the root
|
|
108
|
+
* layout paints from that store.
|
|
108
109
|
*/
|
|
109
110
|
useUserScheme?: () => {
|
|
110
111
|
setting: "system" | "light" | "dark";
|
|
@@ -6,12 +6,14 @@ import { describe, expect, it, vi } from "vitest";
|
|
|
6
6
|
import type { ReactNode } from "react";
|
|
7
7
|
import { createRootLayout } from "./CreateRootLayout.web";
|
|
8
8
|
|
|
9
|
-
vi.mock("one", () => ({ LoadProgressBar: () => null, Slot: () => null, useMatches: () => [] }));
|
|
10
9
|
vi.mock("tamagui", async () => ({
|
|
11
10
|
useDidFinishSSR: (await import("@tamagui/use-did-finish-ssr")).useDidFinishSSR,
|
|
12
11
|
}));
|
|
13
12
|
const scheme = vi.hoisted(() => ({ value: "light", stored: "dark", system: "dark" }));
|
|
14
|
-
vi.mock("
|
|
13
|
+
vi.mock("one", () => ({
|
|
14
|
+
LoadProgressBar: () => null,
|
|
15
|
+
Slot: () => null,
|
|
16
|
+
useMatches: () => [],
|
|
15
17
|
SchemeProvider: ({ children }: { children: ReactNode }) => children,
|
|
16
18
|
setUserScheme: (value: string) => {
|
|
17
19
|
scheme.value = value === "system" ? scheme.system : value;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { SchemeProvider, useUserScheme } from "@vxrn/color-scheme";
|
|
2
1
|
import { useFonts } from "expo-font";
|
|
3
2
|
import i18n from "i18next";
|
|
4
|
-
import { Slot, routerStore } from "one";
|
|
3
|
+
import { SchemeProvider, Slot, routerStore, useUserScheme } from "one";
|
|
5
4
|
import type { ComponentType, ReactNode } from "react";
|
|
6
5
|
import { StyleSheet } from "react-native";
|
|
7
6
|
import { GestureHandlerRootView } from "react-native-gesture-handler";
|
|
@@ -28,7 +27,7 @@ const styles = StyleSheet.create({
|
|
|
28
27
|
/**
|
|
29
28
|
* Creates a root layout component for **React Native** (iOS + Android).
|
|
30
29
|
*
|
|
31
|
-
* Handles i18n initialization, color-scheme detection via
|
|
30
|
+
* Handles i18n initialization, color-scheme detection via `one`'s scheme store,
|
|
32
31
|
* and wraps content in `GestureHandlerRootView` → `SafeAreaProvider` →
|
|
33
32
|
* `SchemeProvider` → `AppProvider` → `RootLayout` → `<Slot />`.
|
|
34
33
|
*
|
|
@@ -31,7 +31,12 @@ const env = vi.hoisted(() => {
|
|
|
31
31
|
return state;
|
|
32
32
|
});
|
|
33
33
|
|
|
34
|
-
vi.mock("one", () => ({
|
|
34
|
+
vi.mock("one", async () => ({
|
|
35
|
+
...(await vi.importActual<typeof import("@vxrn/color-scheme")>("@vxrn/color-scheme")),
|
|
36
|
+
LoadProgressBar: () => null,
|
|
37
|
+
Slot: () => null,
|
|
38
|
+
useMatches: () => [],
|
|
39
|
+
}));
|
|
35
40
|
vi.mock("i18next", () => ({
|
|
36
41
|
default: {
|
|
37
42
|
use: () => ({ init: () => Promise.resolve() }),
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
// @vitest-environment jsdom
|
|
2
|
+
/**
|
|
3
|
+
* MPO-447: an app hands the devtools panel `useUserScheme` from `one`, and the
|
|
4
|
+
* panel's Scheme knob calls its `set()`. The root layout has to paint from that
|
|
5
|
+
* same store. When core reached `@vxrn/color-scheme` on its own, shc's lock gave
|
|
6
|
+
* core 1.16.12 while `one` pins 1.16.5: two stores, one localStorage key. The
|
|
7
|
+
* click wrote `vxrn-scheme` and `<html>` kept `t_light` until a reload (portal,
|
|
8
|
+
* console on 7.23.2).
|
|
9
|
+
*
|
|
10
|
+
* `one` below re-exports the real store, as the published `one` does. The bare
|
|
11
|
+
* `@vxrn/color-scheme` specifier is a second copy with its own state, standing
|
|
12
|
+
* in for the separately resolved one.
|
|
13
|
+
*/
|
|
14
|
+
import type { ReactNode } from "react";
|
|
15
|
+
import { act } from "react";
|
|
16
|
+
import { createRoot } from "react-dom/client";
|
|
17
|
+
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
18
|
+
|
|
19
|
+
vi.mock("one", async () => ({
|
|
20
|
+
...(await vi.importActual<typeof import("@vxrn/color-scheme")>("@vxrn/color-scheme")),
|
|
21
|
+
LoadProgressBar: () => null,
|
|
22
|
+
Slot: () => null,
|
|
23
|
+
useMatches: () => [],
|
|
24
|
+
}));
|
|
25
|
+
vi.mock("@vxrn/color-scheme", async () => {
|
|
26
|
+
const { useEffect, useLayoutEffect, useReducer } = await import("react");
|
|
27
|
+
type Setting = "system" | "light" | "dark";
|
|
28
|
+
let setting: Setting = "light";
|
|
29
|
+
const listeners = new Set<() => void>();
|
|
30
|
+
const resolve = () => (setting === "dark" ? "dark" : "light");
|
|
31
|
+
const setUserScheme = (next: Setting) => {
|
|
32
|
+
setting = next;
|
|
33
|
+
for (const listener of listeners) listener();
|
|
34
|
+
};
|
|
35
|
+
function useUserScheme() {
|
|
36
|
+
const [, rerender] = useReducer((n: number) => n + 1, 0);
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
listeners.add(rerender);
|
|
39
|
+
return () => {
|
|
40
|
+
listeners.delete(rerender);
|
|
41
|
+
};
|
|
42
|
+
}, []);
|
|
43
|
+
return { setting, value: resolve(), set: setUserScheme };
|
|
44
|
+
}
|
|
45
|
+
function SchemeProvider({ children }: { children: ReactNode }) {
|
|
46
|
+
const { value } = useUserScheme();
|
|
47
|
+
useLayoutEffect(() => {
|
|
48
|
+
document.documentElement.classList.remove("t_light", "t_dark");
|
|
49
|
+
document.documentElement.classList.add(`t_${value}`);
|
|
50
|
+
}, [value]);
|
|
51
|
+
return children;
|
|
52
|
+
}
|
|
53
|
+
return { SchemeProvider, setUserScheme, useUserScheme };
|
|
54
|
+
});
|
|
55
|
+
vi.mock("tamagui", () => ({ useDidFinishSSR: () => true }));
|
|
56
|
+
vi.mock("i18next", () => ({
|
|
57
|
+
default: {
|
|
58
|
+
use: () => ({ init: () => Promise.resolve() }),
|
|
59
|
+
changeLanguage: vi.fn(),
|
|
60
|
+
language: "en",
|
|
61
|
+
},
|
|
62
|
+
}));
|
|
63
|
+
vi.mock("react-i18next", () => ({ initReactI18next: {} }));
|
|
64
|
+
vi.mock("@multiplatform.one/platform", () => ({
|
|
65
|
+
config: { get: (_key: string, fallback?: string) => fallback },
|
|
66
|
+
isDev: false,
|
|
67
|
+
platform: { isServer: false },
|
|
68
|
+
}));
|
|
69
|
+
vi.mock("@multiplatform.one/i18n", () => ({ createI18nConfig: () => ({}) }));
|
|
70
|
+
vi.mock("@multiplatform.one/logger", () => ({ logger: { error: vi.fn() } }));
|
|
71
|
+
vi.mock("@multiplatform.one/store", () => ({
|
|
72
|
+
storage: { getItem: (key: string) => localStorage.getItem(key) },
|
|
73
|
+
}));
|
|
74
|
+
vi.mock("./RuntimePublicConfigScript", () => ({ RuntimePublicConfigScript: () => null }));
|
|
75
|
+
|
|
76
|
+
vi.stubGlobal("matchMedia", (query: string) => ({
|
|
77
|
+
matches: false,
|
|
78
|
+
media: query,
|
|
79
|
+
addEventListener() {},
|
|
80
|
+
removeEventListener() {},
|
|
81
|
+
addListener() {},
|
|
82
|
+
removeListener() {},
|
|
83
|
+
}));
|
|
84
|
+
|
|
85
|
+
afterEach(() => {
|
|
86
|
+
localStorage.clear();
|
|
87
|
+
document.documentElement.className = "";
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
describe("the devtools Scheme knob repaints the root live (MPO-447)", () => {
|
|
91
|
+
it("a set() through one's store flips <html> and the app's scheme without a reload", async () => {
|
|
92
|
+
localStorage.setItem("vxrn-scheme", "light");
|
|
93
|
+
const { createRootLayout } = await import("./CreateRootLayout.web");
|
|
94
|
+
const { useUserScheme } = await import("one");
|
|
95
|
+
const seen: string[] = [];
|
|
96
|
+
let setScheme: ((next: "system" | "light" | "dark") => void) | undefined;
|
|
97
|
+
function Panel() {
|
|
98
|
+
setScheme = useUserScheme().set;
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
const Layout = createRootLayout({
|
|
102
|
+
AppProvider: ({ systemTheme, children }: { systemTheme?: string; children?: ReactNode }) => {
|
|
103
|
+
seen.push(String(systemTheme));
|
|
104
|
+
return (
|
|
105
|
+
<>
|
|
106
|
+
<Panel />
|
|
107
|
+
{children}
|
|
108
|
+
</>
|
|
109
|
+
);
|
|
110
|
+
},
|
|
111
|
+
RootLayout: ({ children }: { children?: ReactNode }) => <>{children}</>,
|
|
112
|
+
i18n: { languages: ["en"], namespaces: ["common"], defaultLanguage: "en" },
|
|
113
|
+
} as unknown as Parameters<typeof createRootLayout>[0]);
|
|
114
|
+
|
|
115
|
+
const container = document.createElement("div");
|
|
116
|
+
const root = createRoot(container);
|
|
117
|
+
await act(async () => {
|
|
118
|
+
root.render(<Layout />);
|
|
119
|
+
});
|
|
120
|
+
expect(document.documentElement.classList.contains("t_light")).toBe(true);
|
|
121
|
+
expect(seen.at(-1)).toBe("light");
|
|
122
|
+
|
|
123
|
+
await act(async () => {
|
|
124
|
+
setScheme?.("dark");
|
|
125
|
+
});
|
|
126
|
+
expect(localStorage.getItem("vxrn-scheme")).toBe("dark");
|
|
127
|
+
expect(document.documentElement.classList.contains("t_dark")).toBe(true);
|
|
128
|
+
expect(document.documentElement.classList.contains("t_light")).toBe(false);
|
|
129
|
+
expect(seen.at(-1)).toBe("dark");
|
|
130
|
+
|
|
131
|
+
await act(async () => {
|
|
132
|
+
root.unmount();
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
});
|
|
@@ -3,8 +3,10 @@ import { describe, expect, it, vi } from "vitest";
|
|
|
3
3
|
import type { ReactNode } from "react";
|
|
4
4
|
import { createRootLayout } from "./CreateRootLayout.web";
|
|
5
5
|
|
|
6
|
-
vi.mock("one", () => ({
|
|
7
|
-
|
|
6
|
+
vi.mock("one", () => ({
|
|
7
|
+
LoadProgressBar: () => null,
|
|
8
|
+
Slot: () => null,
|
|
9
|
+
useMatches: () => [],
|
|
8
10
|
SchemeProvider: ({ children }: { children: ReactNode }) => children,
|
|
9
11
|
setUserScheme: vi.fn(),
|
|
10
12
|
useUserScheme: () => ({ value: "light" }),
|
|
@@ -1,7 +1,16 @@
|
|
|
1
1
|
import i18n from "i18next";
|
|
2
2
|
import { useDidFinishSSR } from "tamagui";
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
// The scheme store comes through `one`, never a bare `@vxrn/color-scheme`: apps
|
|
4
|
+
// hand the devtools panel `one`'s `useUserScheme`, and a second resolved copy
|
|
5
|
+
// of the store would paint <html> from state the panel never writes (MPO-447).
|
|
6
|
+
import {
|
|
7
|
+
LoadProgressBar,
|
|
8
|
+
SchemeProvider,
|
|
9
|
+
Slot,
|
|
10
|
+
setUserScheme,
|
|
11
|
+
useMatches,
|
|
12
|
+
useUserScheme,
|
|
13
|
+
} from "one";
|
|
5
14
|
import type { ComponentType, ReactNode } from "react";
|
|
6
15
|
import { CookiesProvider, Cookies } from "react-cookie";
|
|
7
16
|
import { initReactI18next } from "react-i18next";
|
|
@@ -14,7 +14,12 @@ import { ThemeDevtoolsPanel } from "@multiplatform.one/theme";
|
|
|
14
14
|
import { storage } from "@multiplatform.one/store";
|
|
15
15
|
import { useEffect, useState } from "react";
|
|
16
16
|
import type { TanstackConfig } from "./CreateApp";
|
|
17
|
-
import {
|
|
17
|
+
import {
|
|
18
|
+
devtoolsOpenHotkey,
|
|
19
|
+
useDevtoolsKeyboardTrigger,
|
|
20
|
+
useDevtoolsOpenRequests,
|
|
21
|
+
useShakeToOpen,
|
|
22
|
+
} from "./devtoolsTrigger";
|
|
18
23
|
|
|
19
24
|
const devtoolsSettingsKey = "tanstack_devtools_settings";
|
|
20
25
|
|
|
@@ -136,6 +141,7 @@ export default function TanstackDevtoolsWrapper({
|
|
|
136
141
|
// Cmd/Ctrl+Shift+` — capture-phase so apps cannot swallow it. TanStack
|
|
137
142
|
// still receives openHotkey (US-layout e.key sequence) as a fallback.
|
|
138
143
|
useDevtoolsKeyboardTrigger(true);
|
|
144
|
+
const openRequests = useDevtoolsOpenRequests();
|
|
139
145
|
|
|
140
146
|
const plugins = [
|
|
141
147
|
{
|
|
@@ -179,7 +185,7 @@ export default function TanstackDevtoolsWrapper({
|
|
|
179
185
|
|
|
180
186
|
return (
|
|
181
187
|
<TanStackDevtools
|
|
182
|
-
key={resolvedScheme}
|
|
188
|
+
key={`${resolvedScheme}:${openRequests}`}
|
|
183
189
|
config={{
|
|
184
190
|
defaultOpen: false,
|
|
185
191
|
triggerHidden: true,
|
|
@@ -14,9 +14,10 @@ import {
|
|
|
14
14
|
devtoolsArmMotionEvent,
|
|
15
15
|
devtoolsMotionArmedEvent,
|
|
16
16
|
devtoolsOpenHotkey,
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
devtoolsOpenRequestEvent,
|
|
18
|
+
devtoolsShellStateKey,
|
|
19
19
|
isDevtoolsOpenHotkeyEvent,
|
|
20
|
+
isDevtoolsShellOpen,
|
|
20
21
|
isMotionPermissionRequired,
|
|
21
22
|
motionMagnitude,
|
|
22
23
|
openDevtoolsShell,
|
|
@@ -284,42 +285,75 @@ describe("createMotionPermissionFlow", () => {
|
|
|
284
285
|
});
|
|
285
286
|
});
|
|
286
287
|
|
|
287
|
-
|
|
288
|
+
/** A localStorage stand-in holding the shell's persisted state. */
|
|
289
|
+
function memoryStorage(initial?: Record<string, unknown>) {
|
|
290
|
+
const values = new Map<string, string>();
|
|
291
|
+
if (initial) values.set(devtoolsShellStateKey, JSON.stringify(initial));
|
|
292
|
+
return {
|
|
293
|
+
getItem: (key: string) => values.get(key) ?? null,
|
|
294
|
+
setItem: (key: string, value: string) => {
|
|
295
|
+
values.set(key, value);
|
|
296
|
+
},
|
|
297
|
+
state: () => JSON.parse(values.get(devtoolsShellStateKey) ?? "null"),
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
describe("openDevtoolsShell (MPO-447)", () => {
|
|
302
|
+
const realWindow = (globalThis as { window?: unknown }).window;
|
|
303
|
+
|
|
288
304
|
afterEach(() => {
|
|
289
|
-
(globalThis as {
|
|
290
|
-
null;
|
|
305
|
+
(globalThis as { window?: unknown }).window = realWindow;
|
|
291
306
|
});
|
|
292
307
|
|
|
293
|
-
|
|
294
|
-
const
|
|
295
|
-
(globalThis as {
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
expect(
|
|
307
|
-
expect(
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
expect(
|
|
308
|
+
function stubWindow() {
|
|
309
|
+
const win = new EventTarget();
|
|
310
|
+
(globalThis as { window?: unknown }).window = win;
|
|
311
|
+
const requests = vi.fn();
|
|
312
|
+
win.addEventListener(devtoolsOpenRequestEvent, requests);
|
|
313
|
+
return requests;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
it("marks a closed shell open for its next mount and asks for that mount", () => {
|
|
317
|
+
const requests = stubWindow();
|
|
318
|
+
const storage = memoryStorage({ persistOpen: false, layout: { tab: "theme" } });
|
|
319
|
+
openDevtoolsShell(storage);
|
|
320
|
+
expect(storage.state()).toEqual({ persistOpen: true, layout: { tab: "theme" } });
|
|
321
|
+
expect(isDevtoolsShellOpen(storage)).toBe(true);
|
|
322
|
+
expect(requests).toHaveBeenCalledTimes(1);
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
it("opens a shell that never persisted any state", () => {
|
|
326
|
+
const requests = stubWindow();
|
|
327
|
+
const storage = memoryStorage();
|
|
328
|
+
openDevtoolsShell(storage);
|
|
329
|
+
expect(storage.state()).toEqual({ persistOpen: true });
|
|
330
|
+
expect(requests).toHaveBeenCalledTimes(1);
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
it("leaves an open shell alone, so a continued shake never remounts or closes it", () => {
|
|
334
|
+
const requests = stubWindow();
|
|
335
|
+
const storage = memoryStorage({ persistOpen: true });
|
|
336
|
+
openDevtoolsShell(storage);
|
|
337
|
+
openDevtoolsShell(storage);
|
|
338
|
+
expect(storage.state()).toEqual({ persistOpen: true });
|
|
339
|
+
expect(requests).not.toHaveBeenCalled();
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
it("recovers from unreadable state instead of throwing", () => {
|
|
343
|
+
const requests = stubWindow();
|
|
344
|
+
const storage = memoryStorage();
|
|
345
|
+
storage.setItem(devtoolsShellStateKey, "{not json");
|
|
346
|
+
openDevtoolsShell(storage);
|
|
347
|
+
expect(storage.state()).toEqual({ persistOpen: true });
|
|
348
|
+
expect(requests).toHaveBeenCalledTimes(1);
|
|
315
349
|
});
|
|
316
350
|
});
|
|
317
351
|
|
|
318
352
|
describe("upstream contract (installed packages)", () => {
|
|
319
|
-
// The
|
|
320
|
-
//
|
|
321
|
-
// installed packages
|
|
322
|
-
// silently breaking shake-to-open.
|
|
353
|
+
// The shell has no public open call. What this code relies on is how the
|
|
354
|
+
// installed shell decides it is open when it mounts, so pin that against
|
|
355
|
+
// the installed packages: an upstream change fails tests instead of
|
|
356
|
+
// silently breaking the shortcut and shake-to-open again.
|
|
323
357
|
/**
|
|
324
358
|
* Locate an installed package dir regardless of linker layout: walk
|
|
325
359
|
* ancestor node_modules (hoisted puts everything at the repo root),
|
|
@@ -342,26 +376,82 @@ describe("upstream contract (installed packages)", () => {
|
|
|
342
376
|
return null;
|
|
343
377
|
}
|
|
344
378
|
|
|
345
|
-
|
|
379
|
+
function shellDir(): string {
|
|
346
380
|
const reactDevtoolsDir = findInstalled("@tanstack/react-devtools");
|
|
347
381
|
expect(reactDevtoolsDir).toBeTruthy();
|
|
348
382
|
const devtoolsDir = findInstalled("@tanstack/devtools", reactDevtoolsDir as string);
|
|
349
383
|
expect(devtoolsDir).toBeTruthy();
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
384
|
+
return devtoolsDir as string;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
function distSources(dir: string): string[] {
|
|
388
|
+
const out: string[] = [];
|
|
389
|
+
for (const sub of ["devtools", "chunk"]) {
|
|
390
|
+
const subDir = join(dir, "dist", sub);
|
|
391
|
+
if (!existsSync(subDir)) continue;
|
|
392
|
+
for (const file of readdirSync(subDir).filter((f) => f.endsWith(".js"))) {
|
|
393
|
+
out.push(readFileSync(join(subDir, file), "utf8"));
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
return out;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
it("core pins the shell exactly, and the installed shell is that pin", () => {
|
|
400
|
+
// A range let shc resolve 0.10.10 while this spec ran against 0.10.2, and
|
|
401
|
+
// the difference was the whole bug. An exact pin makes an app resolve
|
|
402
|
+
// the version these contracts were checked on.
|
|
403
|
+
const pkg = JSON.parse(readFileSync(join(here, "..", "..", "package.json"), "utf8")) as {
|
|
404
|
+
dependencies: Record<string, string>;
|
|
405
|
+
};
|
|
406
|
+
const pinned = pkg.dependencies["@tanstack/react-devtools"];
|
|
407
|
+
expect(pinned).toMatch(/^\d+\.\d+\.\d+$/);
|
|
408
|
+
const installed = JSON.parse(
|
|
409
|
+
readFileSync(
|
|
410
|
+
join(findInstalled("@tanstack/react-devtools") as string, "package.json"),
|
|
411
|
+
"utf8",
|
|
412
|
+
),
|
|
413
|
+
) as { version: string };
|
|
414
|
+
expect(installed.version).toBe(pinned);
|
|
356
415
|
});
|
|
357
416
|
|
|
358
|
-
it("
|
|
359
|
-
const
|
|
360
|
-
|
|
361
|
-
|
|
417
|
+
it("the shell stores its state under tanstack_devtools_state", () => {
|
|
418
|
+
const sources = distSources(shellDir());
|
|
419
|
+
expect(sources.some((src) => src.includes(`"${devtoolsShellStateKey}"`))).toBe(true);
|
|
420
|
+
});
|
|
421
|
+
|
|
422
|
+
it("a mounting shell opens from persistOpen in that state", () => {
|
|
423
|
+
const sources = distSources(shellDir());
|
|
424
|
+
expect(
|
|
425
|
+
sources.some((src) =>
|
|
426
|
+
/createSignal\(\s*settings\(\)\.defaultOpen\s*\|\|\s*persistOpen\(\)\s*\)/.test(src),
|
|
427
|
+
),
|
|
428
|
+
).toBe(true);
|
|
429
|
+
});
|
|
430
|
+
|
|
431
|
+
it("the shell's own event client is inert outside development, so an open cannot ride the bus", async () => {
|
|
432
|
+
// vitest runs with NODE_ENV !== "development", as a deployed bundle does.
|
|
433
|
+
// From @tanstack/devtools-event-client 0.5 the shell's client is the NoOp
|
|
434
|
+
// there: its trigger-toggled subscription registers nothing. If this
|
|
435
|
+
// fails, upstream dropped the gate and the bus would work again.
|
|
436
|
+
const clientDir = findInstalled("@tanstack/devtools-client", shellDir());
|
|
362
437
|
expect(clientDir).toBeTruthy();
|
|
363
|
-
const
|
|
364
|
-
|
|
438
|
+
const target = new EventTarget();
|
|
439
|
+
const added = vi.spyOn(target, "addEventListener");
|
|
440
|
+
const previous = (globalThis as { __TANSTACK_EVENT_TARGET__?: EventTarget | null })
|
|
441
|
+
.__TANSTACK_EVENT_TARGET__;
|
|
442
|
+
(globalThis as { __TANSTACK_EVENT_TARGET__?: EventTarget | null }).__TANSTACK_EVENT_TARGET__ =
|
|
443
|
+
target;
|
|
444
|
+
try {
|
|
445
|
+
const client = await import(
|
|
446
|
+
pathToFileURL(join(clientDir as string, "dist", "esm", "index.js")).href
|
|
447
|
+
);
|
|
448
|
+
const unsubscribe = client.devtoolsEventClient.on("trigger-toggled", () => {});
|
|
449
|
+
expect(added).not.toHaveBeenCalled();
|
|
450
|
+
unsubscribe();
|
|
451
|
+
} finally {
|
|
452
|
+
(globalThis as { __TANSTACK_EVENT_TARGET__?: EventTarget | null }).__TANSTACK_EVENT_TARGET__ =
|
|
453
|
+
previous;
|
|
454
|
+
}
|
|
365
455
|
});
|
|
366
456
|
|
|
367
457
|
it("@tanstack/pacer-devtools/production resolves the REAL core, not the NoOp", async () => {
|
|
@@ -502,6 +592,16 @@ describe("devtools shell wiring", () => {
|
|
|
502
592
|
expect(shellSource).toContain("useDevtoolsKeyboardTrigger(");
|
|
503
593
|
});
|
|
504
594
|
|
|
595
|
+
it("the shortcut and a shake open through openDevtoolsShell, and a request remounts the shell", () => {
|
|
596
|
+
expect(triggerSource).toMatch(
|
|
597
|
+
/if \(!isDevtoolsOpenHotkeyEvent\(event\)\) return;[\s\S]*?openDevtoolsShell\(\);/,
|
|
598
|
+
);
|
|
599
|
+
expect(triggerSource).toContain("onShake: () => void = openDevtoolsShell");
|
|
600
|
+
expect(shellSource).toContain("const openRequests = useDevtoolsOpenRequests();");
|
|
601
|
+
expect(shellSource).toContain("key={`${resolvedScheme}:${openRequests}`}");
|
|
602
|
+
expect(triggerSource).not.toContain('from "@tanstack/devtools-event-client"');
|
|
603
|
+
});
|
|
604
|
+
|
|
505
605
|
it("mounts shake-to-open with the config opt-out", () => {
|
|
506
606
|
expect(shellSource).toContain("useShakeToOpen(tanstackConfig.shakeToOpen !== false)");
|
|
507
607
|
});
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { useEffect } from "react";
|
|
1
|
+
import { useEffect, useState } from "react";
|
|
3
2
|
|
|
4
3
|
// ---------------------------------------------------------------------------
|
|
5
4
|
// Keyboard trigger
|
|
@@ -41,7 +40,7 @@ export function isDevtoolsOpenHotkeyEvent(event: KeyboardEvent): boolean {
|
|
|
41
40
|
* shortcut. Capture runs before app-level keydown handlers, so a page
|
|
42
41
|
* that stopPropagation's cannot swallow it. preventDefault +
|
|
43
42
|
* stopImmediatePropagation keep TanStack's own createShortcut from
|
|
44
|
-
* also firing
|
|
43
|
+
* also firing, which would toggle the shell it is about to replace.
|
|
45
44
|
*/
|
|
46
45
|
export function useDevtoolsKeyboardTrigger(enabled: boolean) {
|
|
47
46
|
useEffect(() => {
|
|
@@ -58,41 +57,86 @@ export function useDevtoolsKeyboardTrigger(enabled: boolean) {
|
|
|
58
57
|
}
|
|
59
58
|
|
|
60
59
|
// ---------------------------------------------------------------------------
|
|
61
|
-
// Programmatic open
|
|
60
|
+
// Programmatic open: persist the shell's open state, then remount it
|
|
62
61
|
// ---------------------------------------------------------------------------
|
|
63
62
|
|
|
64
63
|
/**
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
* subscribes to `<pluginId>:trigger-toggled` and opens/closes on the
|
|
68
|
-
* payload's `isOpen`. The spec asserts both strings
|
|
69
|
-
* against the installed packages so an upstream rename fails the build
|
|
70
|
-
* instead of silently breaking shake-to-open.
|
|
64
|
+
* localStorage key the TanStack Devtools shell keeps its own state under. A
|
|
65
|
+
* mounting shell opens when this state's `persistOpen` is true.
|
|
71
66
|
*/
|
|
72
|
-
export const
|
|
67
|
+
export const devtoolsShellStateKey = "tanstack_devtools_state";
|
|
73
68
|
|
|
74
|
-
/**
|
|
75
|
-
|
|
69
|
+
/**
|
|
70
|
+
* Window event `openDevtoolsShell` dispatches once it has marked the shell
|
|
71
|
+
* open. The shell wrapper remounts on it (`useDevtoolsOpenRequests`).
|
|
72
|
+
*/
|
|
73
|
+
export const devtoolsOpenRequestEvent = "mpo:devtools-open";
|
|
74
|
+
|
|
75
|
+
interface ShellStorage {
|
|
76
|
+
getItem(key: string): string | null;
|
|
77
|
+
setItem(key: string, value: string): void;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function shellStorage(): ShellStorage | undefined {
|
|
81
|
+
try {
|
|
82
|
+
return typeof localStorage === "undefined" ? undefined : localStorage;
|
|
83
|
+
} catch {
|
|
84
|
+
return undefined;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function readShellState(storage: ShellStorage): Record<string, unknown> {
|
|
89
|
+
try {
|
|
90
|
+
const parsed: unknown = JSON.parse(storage.getItem(devtoolsShellStateKey) ?? "null");
|
|
91
|
+
return parsed && typeof parsed === "object" ? (parsed as Record<string, unknown>) : {};
|
|
92
|
+
} catch {
|
|
93
|
+
return {};
|
|
94
|
+
}
|
|
95
|
+
}
|
|
76
96
|
|
|
77
|
-
|
|
78
|
-
|
|
97
|
+
/** True when the shell's persisted state says it is open. */
|
|
98
|
+
export function isDevtoolsShellOpen(storage: ShellStorage | undefined = shellStorage()): boolean {
|
|
99
|
+
return storage ? readShellState(storage).persistOpen === true : false;
|
|
79
100
|
}
|
|
80
101
|
|
|
81
|
-
|
|
102
|
+
/**
|
|
103
|
+
* Open the TanStack Devtools shell. Open-only by design: a continued shake
|
|
104
|
+
* must not re-close the panel, so an open shell is left alone and closing
|
|
105
|
+
* stays on the close button and Escape.
|
|
106
|
+
*
|
|
107
|
+
* The shell exposes no open call, and from `@tanstack/devtools-event-client`
|
|
108
|
+
* 0.5 its `trigger-toggled` listener is a no-op in every build but
|
|
109
|
+
* development, so an emitted open never reached a deployed app (MPO-447). What
|
|
110
|
+
* every shell version does read is `persistOpen` in its stored state, on
|
|
111
|
+
* mount. This writes it and asks the wrapper to remount the shell.
|
|
112
|
+
*/
|
|
113
|
+
export function openDevtoolsShell(storage: ShellStorage | undefined = shellStorage()): void {
|
|
114
|
+
if (!storage || isDevtoolsShellOpen(storage)) return;
|
|
115
|
+
try {
|
|
116
|
+
storage.setItem(
|
|
117
|
+
devtoolsShellStateKey,
|
|
118
|
+
JSON.stringify({ ...readShellState(storage), persistOpen: true }),
|
|
119
|
+
);
|
|
120
|
+
} catch {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
if (typeof window !== "undefined") window.dispatchEvent(new Event(devtoolsOpenRequestEvent));
|
|
124
|
+
}
|
|
82
125
|
|
|
83
126
|
/**
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
* closing stays on the close button / Escape / the keyboard shortcut.
|
|
88
|
-
* The event client queues emits until the bus connects, so an early shake
|
|
89
|
-
* racing the shell mount is still delivered.
|
|
127
|
+
* Counts open requests since mount. The shell wrapper folds it into the
|
|
128
|
+
* shell's React key, so each request mounts a fresh shell that reads the
|
|
129
|
+
* `persistOpen` `openDevtoolsShell` just wrote.
|
|
90
130
|
*/
|
|
91
|
-
export function
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
131
|
+
export function useDevtoolsOpenRequests(): number {
|
|
132
|
+
const [requests, setRequests] = useState(0);
|
|
133
|
+
useEffect(() => {
|
|
134
|
+
if (typeof window === "undefined") return;
|
|
135
|
+
const onRequest = () => setRequests((n) => n + 1);
|
|
136
|
+
window.addEventListener(devtoolsOpenRequestEvent, onRequest);
|
|
137
|
+
return () => window.removeEventListener(devtoolsOpenRequestEvent, onRequest);
|
|
138
|
+
}, []);
|
|
139
|
+
return requests;
|
|
96
140
|
}
|
|
97
141
|
|
|
98
142
|
// ---------------------------------------------------------------------------
|
package/types/app/CreateApp.d.ts
CHANGED
|
@@ -49,8 +49,9 @@ export interface TanstackConfig {
|
|
|
49
49
|
/** Options forwarded to the QueryClient constructor. */
|
|
50
50
|
queryClientOptions?: Record<string, unknown>;
|
|
51
51
|
/**
|
|
52
|
-
* Pass `useUserScheme` from `one`
|
|
53
|
-
*
|
|
52
|
+
* Pass `useUserScheme` from `one` so the theme devtools panel can control
|
|
53
|
+
* the color scheme (light / dark / system). It must be `one`'s: the root
|
|
54
|
+
* layout paints from that store.
|
|
54
55
|
*/
|
|
55
56
|
useUserScheme?: () => {
|
|
56
57
|
setting: "system" | "light" | "dark";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CreateApp.d.ts","sourceRoot":"","sources":["../../src/app/CreateApp.tsx"],"names":[],"mappings":"AAAA,OAAc,EAMZ,KAAK,aAAa,EAClB,KAAK,iBAAiB,EAEvB,MAAM,OAAO,CAAC;AAEf,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAG5D,OAAO,KAAK,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAW9E,MAAM,MAAM,iBAAiB,GAAG,aAAa,CAAC,iBAAiB,CAAC,CAAC;AAIjE,iEAAiE;AACjE,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd;AAOD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,2BAA2B,CACzC,UAAU,EAAE,MAAM,EAClB,IAAI,GAAE,YAAY,GAAG,SAAiC,EACtD,GAAG,GAAE,OAAe,GACnB,MAAM,CAcR;AAMD,MAAM,WAAW,cAAc;IAC7B;;;;OAIG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB;;;;;;;OAOG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,wDAAwD;IACxD,kBAAkB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC7C
|
|
1
|
+
{"version":3,"file":"CreateApp.d.ts","sourceRoot":"","sources":["../../src/app/CreateApp.tsx"],"names":[],"mappings":"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"}
|
|
@@ -4,7 +4,7 @@ export type { CreateRootLayoutConfig, HeadConfig, RootLayoutProps, RootLoaderDat
|
|
|
4
4
|
/**
|
|
5
5
|
* Creates a root layout component for **React Native** (iOS + Android).
|
|
6
6
|
*
|
|
7
|
-
* Handles i18n initialization, color-scheme detection via
|
|
7
|
+
* Handles i18n initialization, color-scheme detection via `one`'s scheme store,
|
|
8
8
|
* and wraps content in `GestureHandlerRootView` → `SafeAreaProvider` →
|
|
9
9
|
* `SchemeProvider` → `AppProvider` → `RootLayout` → `<Slot />`.
|
|
10
10
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CreateRootLayout.native.d.ts","sourceRoot":"","sources":["../../src/app/CreateRootLayout.native.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"CreateRootLayout.native.d.ts","sourceRoot":"","sources":["../../src/app/CreateRootLayout.native.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAa,MAAM,OAAO,CAAC;AAQtD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAGjE,YAAY,EACV,sBAAsB,EACtB,UAAU,EACV,eAAe,EACf,cAAc,EACd,YAAY,GACb,MAAM,oBAAoB,CAAC;AAM5B;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,sBAAsB,GAAG,aAAa,CA+D3E"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CreateRootLayout.web.d.ts","sourceRoot":"","sources":["../../src/app/CreateRootLayout.web.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"CreateRootLayout.web.d.ts","sourceRoot":"","sources":["../../src/app/CreateRootLayout.web.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,aAAa,EAAa,MAAM,OAAO,CAAC;AAQtD,OAAO,KAAK,EAAE,sBAAsB,EAAkB,MAAM,oBAAoB,CAAC;AAEjF,YAAY,EACV,sBAAsB,EACtB,UAAU,EACV,eAAe,EACf,cAAc,EACd,YAAY,GACb,MAAM,oBAAoB,CAAC;AAE5B;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,sBAAsB,GAAG,aAAa,CAqL3E"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TanstackDevtools.d.ts","sourceRoot":"","sources":["../../src/app/TanstackDevtools.tsx"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"TanstackDevtools.d.ts","sourceRoot":"","sources":["../../src/app/TanstackDevtools.tsx"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAyClD,MAAM,WAAW,qBAAqB;IACpC,cAAc,EAAE,OAAO,GAAG,MAAM,CAAC;IACjC,cAAc,EAAE,cAAc,CAAC;CAChC;AAkED,MAAM,CAAC,OAAO,UAAU,uBAAuB,CAAC,EAC9C,cAAc,EACd,cAAc,GACf,EAAE,qBAAqB,2CAqEvB"}
|
|
@@ -26,29 +26,43 @@ export declare function isDevtoolsOpenHotkeyEvent(event: KeyboardEvent): boolean
|
|
|
26
26
|
* shortcut. Capture runs before app-level keydown handlers, so a page
|
|
27
27
|
* that stopPropagation's cannot swallow it. preventDefault +
|
|
28
28
|
* stopImmediatePropagation keep TanStack's own createShortcut from
|
|
29
|
-
* also firing
|
|
29
|
+
* also firing, which would toggle the shell it is about to replace.
|
|
30
30
|
*/
|
|
31
31
|
export declare function useDevtoolsKeyboardTrigger(enabled: boolean): void;
|
|
32
32
|
/**
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
*
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
*
|
|
50
|
-
|
|
51
|
-
|
|
33
|
+
* localStorage key the TanStack Devtools shell keeps its own state under. A
|
|
34
|
+
* mounting shell opens when this state's `persistOpen` is true.
|
|
35
|
+
*/
|
|
36
|
+
export declare const devtoolsShellStateKey = "tanstack_devtools_state";
|
|
37
|
+
/**
|
|
38
|
+
* Window event `openDevtoolsShell` dispatches once it has marked the shell
|
|
39
|
+
* open. The shell wrapper remounts on it (`useDevtoolsOpenRequests`).
|
|
40
|
+
*/
|
|
41
|
+
export declare const devtoolsOpenRequestEvent = "mpo:devtools-open";
|
|
42
|
+
interface ShellStorage {
|
|
43
|
+
getItem(key: string): string | null;
|
|
44
|
+
setItem(key: string, value: string): void;
|
|
45
|
+
}
|
|
46
|
+
/** True when the shell's persisted state says it is open. */
|
|
47
|
+
export declare function isDevtoolsShellOpen(storage?: ShellStorage | undefined): boolean;
|
|
48
|
+
/**
|
|
49
|
+
* Open the TanStack Devtools shell. Open-only by design: a continued shake
|
|
50
|
+
* must not re-close the panel, so an open shell is left alone and closing
|
|
51
|
+
* stays on the close button and Escape.
|
|
52
|
+
*
|
|
53
|
+
* The shell exposes no open call, and from `@tanstack/devtools-event-client`
|
|
54
|
+
* 0.5 its `trigger-toggled` listener is a no-op in every build but
|
|
55
|
+
* development, so an emitted open never reached a deployed app (MPO-447). What
|
|
56
|
+
* every shell version does read is `persistOpen` in its stored state, on
|
|
57
|
+
* mount. This writes it and asks the wrapper to remount the shell.
|
|
58
|
+
*/
|
|
59
|
+
export declare function openDevtoolsShell(storage?: ShellStorage | undefined): void;
|
|
60
|
+
/**
|
|
61
|
+
* Counts open requests since mount. The shell wrapper folds it into the
|
|
62
|
+
* shell's React key, so each request mounts a fresh shell that reads the
|
|
63
|
+
* `persistOpen` `openDevtoolsShell` just wrote.
|
|
64
|
+
*/
|
|
65
|
+
export declare function useDevtoolsOpenRequests(): number;
|
|
52
66
|
/** Defaults: deliberate shakes peak 15–25 m/s²; walking/bumps stay under ~8. */
|
|
53
67
|
export declare const shakeDefaults: {
|
|
54
68
|
/** m/s² a sample must exceed to count as a shake peak. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"devtoolsTrigger.d.ts","sourceRoot":"","sources":["../../src/app/devtoolsTrigger.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"devtoolsTrigger.d.ts","sourceRoot":"","sources":["../../src/app/devtoolsTrigger.ts"],"names":[],"mappings":"AAMA;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,kBAAkB,uCAAwC,CAAC;AAExE;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAMvE;AAED;;;;;;GAMG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,OAAO,QAY1D;AAMD;;;GAGG;AACH,eAAO,MAAM,qBAAqB,4BAA4B,CAAC;AAE/D;;;GAGG;AACH,eAAO,MAAM,wBAAwB,sBAAsB,CAAC;AAE5D,UAAU,YAAY;IACpB,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IACpC,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3C;AAmBD,6DAA6D;AAC7D,wBAAgB,mBAAmB,CAAC,OAAO,GAAE,YAAY,GAAG,SAA0B,GAAG,OAAO,CAE/F;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,GAAE,YAAY,GAAG,SAA0B,GAAG,IAAI,CAW1F;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,IAAI,MAAM,CAShD;AAQD,gFAAgF;AAChF,eAAO,MAAM,aAAa;IACxB,0DAA0D;;IAE1D,iFAAiF;;IAEjF,wDAAwD;;IAExD,kDAAkD;;IAElD,+DAA+D;;CAEvD,CAAC;AAEX,UAAU,UAAU;IAClB,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAClB,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAClB,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACnB;AAED,oFAAoF;AACpF,MAAM,WAAW,eAAe;IAC9B,YAAY,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC;IACjC,4BAA4B,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC;CAClD;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM,GAAG,IAAI,CAUrE;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,aAAa;IAC5B,iEAAiE;IACjE,YAAY,EAAE,CAAC,KAAK,EAAE,eAAe,EAAE,GAAG,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7D,yCAAyC;IACzC,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,EAClC,OAAO,EACP,SAAmC,EACnC,YAAyC,EACzC,SAAmC,EACnC,QAAiC,EACjC,UAAqC,GACtC,EAAE,oBAAoB,GAAG,aAAa,CA2BtC;AAMD,MAAM,MAAM,qBAAqB,GAAG,SAAS,GAAG,kBAAkB,GAAG,YAAY,GAAG,QAAQ,CAAC;AAE7F,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,KAAK,EAAE,qBAAqB,CAAC;IACtC;;;OAGG;IACH,aAAa,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CACpC;AAED;;;;;;GAMG;AACH,wBAAgB,0BAA0B,CAAC,EACzC,iBAAiB,EACjB,SAAS,EACT,QAAQ,GACT,EAAE;IACD,iBAAiB,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IAC1C,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;CACvB,GAAG,oBAAoB,CA8BvB;AAcD;;;;;GAKG;AACH,wBAAgB,0BAA0B,IAAI,OAAO,CAEpD;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,sBAAsB,4BAA4B,CAAC;AAEhE;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,8BAA8B,CAAC;AA4BpE,oEAAoE;AACpE,wBAAgB,mBAAmB,SAGlC;AAED;;;;;;GAMG;AACH,wBAAsB,kCAAkC,IAAI,OAAO,CAAC,qBAAqB,CAAC,CAqBzF;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,IAAI,IAAI,CAGxC;AAMD;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,GAAE,MAAM,IAAwB,QA+BvF"}
|