@assistant-ui/react-devtools 0.1.1 → 0.1.2

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.
@@ -1 +1 @@
1
- {"version":3,"file":"DevToolsModal.d.ts","sourceRoot":"","sources":["../src/DevToolsModal.tsx"],"names":[],"mappings":"AAsKA,eAAO,MAAM,aAAa,sDAWzB,CAAC"}
1
+ {"version":3,"file":"DevToolsModal.d.ts","sourceRoot":"","sources":["../src/DevToolsModal.tsx"],"names":[],"mappings":"AA6KA,eAAO,MAAM,aAAa,sDAWzB,CAAC"}
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
 
3
3
  // src/DevToolsModal.tsx
4
- import { useEffect, useMemo, useState } from "react";
4
+ import { useEffect, useMemo, useState, useSyncExternalStore } from "react";
5
5
  import { DevToolsFrame } from "./DevToolsFrame.js";
6
6
  import { getStyles, ANIMATION_STYLES } from "./styles/DevToolsModal.styles.js";
7
7
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
@@ -9,11 +9,34 @@ var isDarkMode = () => {
9
9
  if (typeof document === "undefined") return false;
10
10
  return document.documentElement.classList.contains("dark") || document.body.classList.contains("dark");
11
11
  };
12
+ var subscribeToThemeChanges = (callback) => {
13
+ if (typeof MutationObserver === "undefined") {
14
+ return () => {
15
+ };
16
+ }
17
+ const observer = new MutationObserver(callback);
18
+ observer.observe(document.documentElement, {
19
+ attributes: true,
20
+ attributeFilter: ["class"]
21
+ });
22
+ if (document.body !== document.documentElement) {
23
+ observer.observe(document.body, {
24
+ attributes: true,
25
+ attributeFilter: ["class"]
26
+ });
27
+ }
28
+ return () => observer.disconnect();
29
+ };
12
30
  var DevToolsModalImpl = () => {
13
31
  const [isOpen, setIsOpen] = useState(false);
14
- const [darkMode, setDarkMode] = useState(false);
15
32
  const [buttonHover, setButtonHover] = useState(false);
16
33
  const [closeHover, setCloseHover] = useState(false);
34
+ const darkMode = useSyncExternalStore(
35
+ subscribeToThemeChanges,
36
+ isDarkMode,
37
+ () => false
38
+ // Server-side always returns false
39
+ );
17
40
  const styles = useMemo(() => getStyles(darkMode), [darkMode]);
18
41
  useEffect(() => {
19
42
  if (typeof document === "undefined") return;
@@ -31,22 +54,6 @@ var DevToolsModalImpl = () => {
31
54
  }
32
55
  };
33
56
  }, []);
34
- useEffect(() => {
35
- if (typeof MutationObserver === "undefined") return;
36
- const checkDarkMode = () => setDarkMode(isDarkMode());
37
- const observer = new MutationObserver(checkDarkMode);
38
- observer.observe(document.documentElement, {
39
- attributes: true,
40
- attributeFilter: ["class"]
41
- });
42
- if (document.body !== document.documentElement) {
43
- observer.observe(document.body, {
44
- attributes: true,
45
- attributeFilter: ["class"]
46
- });
47
- }
48
- return () => observer.disconnect();
49
- }, []);
50
57
  useEffect(() => {
51
58
  if (!isOpen) return;
52
59
  const handleEscape = (event) => {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/DevToolsModal.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useMemo, useState } from \"react\";\nimport { DevToolsFrame } from \"./DevToolsFrame\";\nimport { getStyles, ANIMATION_STYLES } from \"./styles/DevToolsModal.styles\";\n\nconst isDarkMode = (): boolean => {\n if (typeof document === \"undefined\") return false;\n return (\n document.documentElement.classList.contains(\"dark\") ||\n document.body.classList.contains(\"dark\")\n );\n};\n\nconst DevToolsModalImpl = () => {\n const [isOpen, setIsOpen] = useState(false);\n const [darkMode, setDarkMode] = useState(false);\n const [buttonHover, setButtonHover] = useState(false);\n const [closeHover, setCloseHover] = useState(false);\n\n const styles = useMemo(() => getStyles(darkMode), [darkMode]);\n\n useEffect(() => {\n if (typeof document === \"undefined\") return;\n\n const styleId = \"devtools-modal-animations\";\n if (!document.getElementById(styleId)) {\n const style = document.createElement(\"style\");\n style.id = styleId;\n style.textContent = ANIMATION_STYLES;\n document.head.appendChild(style);\n }\n\n return () => {\n const style = document.getElementById(styleId);\n if (style && !document.querySelector(\"[data-devtools-modal]\")) {\n style.remove();\n }\n };\n }, []);\n\n useEffect(() => {\n if (typeof MutationObserver === \"undefined\") return;\n\n const checkDarkMode = () => setDarkMode(isDarkMode());\n const observer = new MutationObserver(checkDarkMode);\n\n observer.observe(document.documentElement, {\n attributes: true,\n attributeFilter: [\"class\"],\n });\n if (document.body !== document.documentElement) {\n observer.observe(document.body, {\n attributes: true,\n attributeFilter: [\"class\"],\n });\n }\n\n return () => observer.disconnect();\n }, []);\n\n useEffect(() => {\n if (!isOpen) return;\n\n const handleEscape = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") {\n setIsOpen(false);\n }\n };\n\n document.addEventListener(\"keydown\", handleEscape);\n return () => document.removeEventListener(\"keydown\", handleEscape);\n }, [isOpen]);\n\n return (\n <>\n <div style={styles.floatingContainer}>\n <button\n onClick={() => setIsOpen(true)}\n onMouseEnter={() => setButtonHover(true)}\n onMouseLeave={() => setButtonHover(false)}\n style={{\n ...styles.floatingButton,\n ...(buttonHover ? styles.floatingButtonHover : {}),\n }}\n aria-label=\"Open assistant-ui DevTools\"\n title=\"Open assistant-ui DevTools\"\n >\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n style={{ width: \"20px\", height: \"20px\" }}\n >\n <path\n d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\"\n stroke=\"currentColor\"\n strokeWidth=\"1.8\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n fill=\"none\"\n />\n </svg>\n </button>\n </div>\n\n {isOpen && (\n <>\n <div style={styles.backdrop} onClick={() => setIsOpen(false)} />\n\n <div style={styles.modal} data-devtools-modal>\n <button\n onClick={() => setIsOpen(false)}\n onMouseEnter={() => setCloseHover(true)}\n onMouseLeave={() => setCloseHover(false)}\n style={{\n ...styles.dismissButton,\n ...(closeHover ? styles.dismissButtonHover : {}),\n }}\n aria-label=\"Close DevTools\"\n >\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M18 6L6 18\"\n stroke=\"currentColor\"\n strokeWidth=\"1.6\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M6 6L18 18\"\n stroke=\"currentColor\"\n strokeWidth=\"1.6\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n </button>\n\n <div style={styles.modalContent}>\n <DevToolsFrame\n style={{\n width: \"100%\",\n height: \"100%\",\n border: \"none\",\n borderRadius: \"12px\",\n backgroundColor: \"transparent\",\n }}\n />\n </div>\n </div>\n </>\n )}\n </>\n );\n};\n\n// Export a component that only renders in development\nexport const DevToolsModal = () => {\n // Check if we're in production - most bundlers will replace process.env.NODE_ENV\n // This allows the entire component to be eliminated via dead code elimination\n if (\n typeof process !== \"undefined\" &&\n process.env?.[\"NODE_ENV\"] === \"production\"\n ) {\n return null;\n }\n\n return <DevToolsModalImpl />;\n};\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/DevToolsModal.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useMemo, useState, useSyncExternalStore } from \"react\";\nimport { DevToolsFrame } from \"./DevToolsFrame\";\nimport { getStyles, ANIMATION_STYLES } from \"./styles/DevToolsModal.styles\";\n\nconst isDarkMode = (): boolean => {\n if (typeof document === \"undefined\") return false;\n return (\n document.documentElement.classList.contains(\"dark\") ||\n document.body.classList.contains(\"dark\")\n );\n};\n\nconst subscribeToThemeChanges = (callback: () => void) => {\n if (typeof MutationObserver === \"undefined\") {\n return () => {};\n }\n\n const observer = new MutationObserver(callback);\n\n observer.observe(document.documentElement, {\n attributes: true,\n attributeFilter: [\"class\"],\n });\n\n if (document.body !== document.documentElement) {\n observer.observe(document.body, {\n attributes: true,\n attributeFilter: [\"class\"],\n });\n }\n\n return () => observer.disconnect();\n};\n\nconst DevToolsModalImpl = () => {\n const [isOpen, setIsOpen] = useState(false);\n const [buttonHover, setButtonHover] = useState(false);\n const [closeHover, setCloseHover] = useState(false);\n\n const darkMode = useSyncExternalStore(\n subscribeToThemeChanges,\n isDarkMode,\n () => false, // Server-side always returns false\n );\n\n const styles = useMemo(() => getStyles(darkMode), [darkMode]);\n\n useEffect(() => {\n if (typeof document === \"undefined\") return;\n\n const styleId = \"devtools-modal-animations\";\n if (!document.getElementById(styleId)) {\n const style = document.createElement(\"style\");\n style.id = styleId;\n style.textContent = ANIMATION_STYLES;\n document.head.appendChild(style);\n }\n\n return () => {\n const style = document.getElementById(styleId);\n if (style && !document.querySelector(\"[data-devtools-modal]\")) {\n style.remove();\n }\n };\n }, []);\n\n useEffect(() => {\n if (!isOpen) return;\n\n const handleEscape = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") {\n setIsOpen(false);\n }\n };\n\n document.addEventListener(\"keydown\", handleEscape);\n return () => document.removeEventListener(\"keydown\", handleEscape);\n }, [isOpen]);\n\n return (\n <>\n <div style={styles.floatingContainer}>\n <button\n onClick={() => setIsOpen(true)}\n onMouseEnter={() => setButtonHover(true)}\n onMouseLeave={() => setButtonHover(false)}\n style={{\n ...styles.floatingButton,\n ...(buttonHover ? styles.floatingButtonHover : {}),\n }}\n aria-label=\"Open assistant-ui DevTools\"\n title=\"Open assistant-ui DevTools\"\n >\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n style={{ width: \"20px\", height: \"20px\" }}\n >\n <path\n d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\"\n stroke=\"currentColor\"\n strokeWidth=\"1.8\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n fill=\"none\"\n />\n </svg>\n </button>\n </div>\n\n {isOpen && (\n <>\n <div style={styles.backdrop} onClick={() => setIsOpen(false)} />\n\n <div style={styles.modal} data-devtools-modal>\n <button\n onClick={() => setIsOpen(false)}\n onMouseEnter={() => setCloseHover(true)}\n onMouseLeave={() => setCloseHover(false)}\n style={{\n ...styles.dismissButton,\n ...(closeHover ? styles.dismissButtonHover : {}),\n }}\n aria-label=\"Close DevTools\"\n >\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M18 6L6 18\"\n stroke=\"currentColor\"\n strokeWidth=\"1.6\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M6 6L18 18\"\n stroke=\"currentColor\"\n strokeWidth=\"1.6\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n </button>\n\n <div style={styles.modalContent}>\n <DevToolsFrame\n style={{\n width: \"100%\",\n height: \"100%\",\n border: \"none\",\n borderRadius: \"12px\",\n backgroundColor: \"transparent\",\n }}\n />\n </div>\n </div>\n </>\n )}\n </>\n );\n};\n\n// Export a component that only renders in development\nexport const DevToolsModal = () => {\n // Check if we're in production - most bundlers will replace process.env.NODE_ENV\n // This allows the entire component to be eliminated via dead code elimination\n if (\n typeof process !== \"undefined\" &&\n process.env?.[\"NODE_ENV\"] === \"production\"\n ) {\n return null;\n }\n\n return <DevToolsModalImpl />;\n};\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -8,7 +8,7 @@
8
8
  "development",
9
9
  "debugging"
10
10
  ],
11
- "version": "0.1.1",
11
+ "version": "0.1.2",
12
12
  "license": "MIT",
13
13
  "type": "module",
14
14
  "exports": {
@@ -51,9 +51,9 @@
51
51
  "eslint-config-next": "15.4.6",
52
52
  "tsx": "^4.20.4",
53
53
  "vitest": "^3.2.4",
54
- "@assistant-ui/tap": "0.1.1",
55
- "@assistant-ui/react": "0.11.19",
56
- "@assistant-ui/x-buildutils": "0.0.1"
54
+ "@assistant-ui/react": "0.11.20",
55
+ "@assistant-ui/x-buildutils": "0.0.1",
56
+ "@assistant-ui/tap": "0.1.1"
57
57
  },
58
58
  "publishConfig": {
59
59
  "access": "public",
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
 
3
- import { useEffect, useMemo, useState } from "react";
3
+ import { useEffect, useMemo, useState, useSyncExternalStore } from "react";
4
4
  import { DevToolsFrame } from "./DevToolsFrame";
5
5
  import { getStyles, ANIMATION_STYLES } from "./styles/DevToolsModal.styles";
6
6
 
@@ -12,12 +12,39 @@ const isDarkMode = (): boolean => {
12
12
  );
13
13
  };
14
14
 
15
+ const subscribeToThemeChanges = (callback: () => void) => {
16
+ if (typeof MutationObserver === "undefined") {
17
+ return () => {};
18
+ }
19
+
20
+ const observer = new MutationObserver(callback);
21
+
22
+ observer.observe(document.documentElement, {
23
+ attributes: true,
24
+ attributeFilter: ["class"],
25
+ });
26
+
27
+ if (document.body !== document.documentElement) {
28
+ observer.observe(document.body, {
29
+ attributes: true,
30
+ attributeFilter: ["class"],
31
+ });
32
+ }
33
+
34
+ return () => observer.disconnect();
35
+ };
36
+
15
37
  const DevToolsModalImpl = () => {
16
38
  const [isOpen, setIsOpen] = useState(false);
17
- const [darkMode, setDarkMode] = useState(false);
18
39
  const [buttonHover, setButtonHover] = useState(false);
19
40
  const [closeHover, setCloseHover] = useState(false);
20
41
 
42
+ const darkMode = useSyncExternalStore(
43
+ subscribeToThemeChanges,
44
+ isDarkMode,
45
+ () => false, // Server-side always returns false
46
+ );
47
+
21
48
  const styles = useMemo(() => getStyles(darkMode), [darkMode]);
22
49
 
23
50
  useEffect(() => {
@@ -39,26 +66,6 @@ const DevToolsModalImpl = () => {
39
66
  };
40
67
  }, []);
41
68
 
42
- useEffect(() => {
43
- if (typeof MutationObserver === "undefined") return;
44
-
45
- const checkDarkMode = () => setDarkMode(isDarkMode());
46
- const observer = new MutationObserver(checkDarkMode);
47
-
48
- observer.observe(document.documentElement, {
49
- attributes: true,
50
- attributeFilter: ["class"],
51
- });
52
- if (document.body !== document.documentElement) {
53
- observer.observe(document.body, {
54
- attributes: true,
55
- attributeFilter: ["class"],
56
- });
57
- }
58
-
59
- return () => observer.disconnect();
60
- }, []);
61
-
62
69
  useEffect(() => {
63
70
  if (!isOpen) return;
64
71