@instantdb/react
Advanced tools
Comparing version 0.6.3 to 0.6.4
@@ -0,1 +1,2 @@ | ||
/// <reference types="react" /> | ||
import { tx, id, getLocalId, Config, transact, auth, Query, QueryResponse, InstantObject, Exactly, QueryState, AuthState, User } from "@instantdb/core"; | ||
@@ -26,4 +27,9 @@ /** | ||
* useQuery({ goals: { todos: {} } }) | ||
* | ||
* Curious about the state of your query? | ||
* Just add a `debugRef` to any element and inspect it with debug mode! `(cmd|ctrl) + shift + O` | ||
*/ | ||
declare function useQuery<Q extends Query>(_query: Exactly<Query, Q>): QueryState<Q>; | ||
declare function useQuery<Q extends Query>(_query: Exactly<Query, Q>): { | ||
debugRef: React.LegacyRef<any>; | ||
} & QueryState<Q>; | ||
/** | ||
@@ -30,0 +36,0 @@ * Listen for the logged in state. This is useful |
"use strict"; | ||
var _a; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
@@ -11,2 +12,12 @@ exports.init = exports.useQuery = exports.useAuth = exports.getLocalId = exports.transact = exports.tx = exports.id = exports.auth = void 0; | ||
const react_1 = require("react"); | ||
const isBrowser = typeof window !== "undefined"; | ||
const isDev = typeof process !== "undefined" && ((_a = process.env) === null || _a === void 0 ? void 0 : _a.NODE_ENV) === "development"; | ||
const debugEvents = new EventTarget(); | ||
let isDebugMode = false; | ||
let activeDebugId = null; | ||
let debugPopupEl = null; | ||
const colors = { | ||
debugOutlineSoft: "#eec4e4", | ||
debugOutlineFocused: "#f660d2", | ||
}; | ||
/** | ||
@@ -39,2 +50,5 @@ * | ||
* useQuery({ goals: { todos: {} } }) | ||
* | ||
* Curious about the state of your query? | ||
* Just add a `debugRef` to any element and inspect it with debug mode! `(cmd|ctrl) + shift + O` | ||
*/ | ||
@@ -58,3 +72,4 @@ function useQuery(_query) { | ||
}, [(0, core_1.weakHash)(query), db]); | ||
return state; | ||
const { debugRef } = useDebugRef({ query, state }); | ||
return Object.assign(Object.assign({}, state), { debugRef }); | ||
} | ||
@@ -103,2 +118,145 @@ exports.useQuery = useQuery; | ||
exports.useAuth = useAuth; | ||
function useDebugRef({ query, state, }) { | ||
const debugRef = (0, react_1.useRef)(); | ||
const debugIdRef = (0, react_1.useRef)((0, core_1.id)()); | ||
const [debugMode, setDebugMode] = (0, react_1.useState)(false); | ||
const [focused, setFocused] = (0, react_1.useState)(false); | ||
function onDebugChange(e) { | ||
setDebugMode(e.detail.active); | ||
} | ||
(0, react_1.useEffect)(() => { | ||
if (activeDebugId !== debugIdRef.current) | ||
return; | ||
updateDebugPopup({ id: debugIdRef.current, query, state }); | ||
}, [state, query, focused]); | ||
(0, react_1.useEffect)(() => { | ||
debugEvents.addEventListener("change", onDebugChange); | ||
return () => debugEvents.removeEventListener("change", onDebugChange); | ||
}, []); | ||
(0, react_1.useLayoutEffect)(() => { | ||
if (!debugMode) | ||
return; | ||
const el = debugRef.current; | ||
if (!el) | ||
return; | ||
const origOutline = el.style.outline; | ||
function onMouseEnter() { | ||
activeDebugId = debugIdRef.current; | ||
el.style.outline = `1px ${colors.debugOutlineFocused} solid`; | ||
setFocused(true); | ||
} | ||
function onMouseLeave() { | ||
el.style.outline = `1px ${colors.debugOutlineSoft} solid`; | ||
setFocused(false); | ||
} | ||
el.style.outline = `1px ${colors.debugOutlineSoft} solid`; | ||
el.addEventListener("mouseenter", onMouseEnter); | ||
el.addEventListener("mouseleave", onMouseLeave); | ||
return () => { | ||
el.style.outline = origOutline; | ||
el.removeEventListener("mouseenter", onMouseEnter); | ||
el.removeEventListener("mouseleave", onMouseLeave); | ||
}; | ||
}, [debugMode, debugRef.current]); | ||
return { debugRef }; | ||
} | ||
function isDebugKeyCombo(e) { | ||
return e.metaKey && e.shiftKey && e.key === "o"; | ||
} | ||
function initializeDebugPopup() { | ||
var _a; | ||
const rootId = "_idb-root"; | ||
(_a = document.getElementById(rootId)) === null || _a === void 0 ? void 0 : _a.remove(); | ||
debugPopupEl = document.createElement("div"); | ||
debugPopupEl.id = rootId; | ||
document.body.appendChild(debugPopupEl); | ||
} | ||
function updateDebugPopup(data) { | ||
const html = /*html*/ ` | ||
<div class="_idb-container"'> | ||
<strong>🔍 Instant Query Inspector</strong> | ||
${data | ||
? ` | ||
<div> | ||
<strong>State:</strong> ${data.state.isLoading ? "Loading" : data.state.error ? "Error" : "OK"} | ||
</div> | ||
<div> | ||
${data.state.data | ||
? ` | ||
<strong>Data</strong> | ||
<pre class="_idb-code">${JSON.stringify(data.state.data, null, 2)}</pre> | ||
` | ||
: data.state.error | ||
? ` | ||
<strong>Error</strong> | ||
<pre class="_idb-code">${JSON.stringify(data.state.error, null, 2)}</pre> | ||
` | ||
: ""} | ||
</div> | ||
<div> | ||
<strong>Query</strong> | ||
<pre class="_idb-code">${JSON.stringify(data.query, null, 2)}</pre> | ||
</div> | ||
` | ||
: `<em>Hover your cursor over an element to inspect it's data.</em>`} | ||
<style> | ||
._idb-container { | ||
animation: pop 0.2s forwards 1; | ||
position: fixed; | ||
bottom: 12px; | ||
right: 12px; | ||
height: 45vh; | ||
width: 50vw; | ||
max-width: 400px; | ||
max-height: 600px; | ||
overflow-x: hidden; | ||
overflow-y: scroll; | ||
display: flex; | ||
flex-direction: column; | ||
gap: 12px; | ||
box-sizing: border-box; | ||
border: 1px #ddd solid; | ||
padding: 16px; | ||
color: black; | ||
background-color: white; | ||
font-family: monospace; | ||
font-size: 11px; | ||
border-radius: 8px; | ||
box-shadow: 0px 0px 12px #00000022; | ||
} | ||
._idb-code { | ||
overflow: auto; | ||
border: 1px #ddd solid; | ||
background-color: #f6f6f6; | ||
padding: 12px; | ||
font-size: 10px; | ||
} | ||
</style> | ||
</div> | ||
`; | ||
debugPopupEl.innerHTML = html; | ||
} | ||
if (isBrowser && isDev) { | ||
addEventListener("keydown", (e) => { | ||
if (!isDebugKeyCombo(e)) { | ||
return; | ||
} | ||
if (!debugPopupEl) { | ||
initializeDebugPopup(); | ||
} | ||
isDebugMode = !isDebugMode; | ||
activeDebugId = null; | ||
debugEvents.dispatchEvent(new CustomEvent("change", { | ||
detail: { active: isDebugMode }, | ||
})); | ||
debugPopupEl.style.display = isDebugMode ? "block" : "none"; | ||
updateDebugPopup(); | ||
}); | ||
} | ||
//# sourceMappingURL=index.js.map |
@@ -0,1 +1,2 @@ | ||
/// <reference types="react" /> | ||
import { tx, id, getLocalId, Config, transact, auth, Query, QueryResponse, InstantObject, Exactly, QueryState, AuthState, User } from "@instantdb/core"; | ||
@@ -26,4 +27,9 @@ /** | ||
* useQuery({ goals: { todos: {} } }) | ||
* | ||
* Curious about the state of your query? | ||
* Just add a `debugRef` to any element and inspect it with debug mode! `(cmd|ctrl) + shift + O` | ||
*/ | ||
declare function useQuery<Q extends Query>(_query: Exactly<Query, Q>): QueryState<Q>; | ||
declare function useQuery<Q extends Query>(_query: Exactly<Query, Q>): { | ||
debugRef: React.LegacyRef<any>; | ||
} & QueryState<Q>; | ||
/** | ||
@@ -30,0 +36,0 @@ * Listen for the logged in state. This is useful |
@@ -0,3 +1,14 @@ | ||
var _a; | ||
import { getDB, weakHash, tx, id, init as initCore, getLocalId, transact, coerceQuery, auth, } from "@instantdb/core"; | ||
import { useEffect, useState } from "react"; | ||
import { useEffect, useLayoutEffect, useRef, useState } from "react"; | ||
const isBrowser = typeof window !== "undefined"; | ||
const isDev = typeof process !== "undefined" && ((_a = process.env) === null || _a === void 0 ? void 0 : _a.NODE_ENV) === "development"; | ||
const debugEvents = new EventTarget(); | ||
let isDebugMode = false; | ||
let activeDebugId = null; | ||
let debugPopupEl = null; | ||
const colors = { | ||
debugOutlineSoft: "#eec4e4", | ||
debugOutlineFocused: "#f660d2", | ||
}; | ||
/** | ||
@@ -29,2 +40,5 @@ * | ||
* useQuery({ goals: { todos: {} } }) | ||
* | ||
* Curious about the state of your query? | ||
* Just add a `debugRef` to any element and inspect it with debug mode! `(cmd|ctrl) + shift + O` | ||
*/ | ||
@@ -48,3 +62,4 @@ function useQuery(_query) { | ||
}, [weakHash(query), db]); | ||
return state; | ||
const { debugRef } = useDebugRef({ query, state }); | ||
return Object.assign(Object.assign({}, state), { debugRef }); | ||
} | ||
@@ -91,3 +106,146 @@ /** | ||
} | ||
function useDebugRef({ query, state, }) { | ||
const debugRef = useRef(); | ||
const debugIdRef = useRef(id()); | ||
const [debugMode, setDebugMode] = useState(false); | ||
const [focused, setFocused] = useState(false); | ||
function onDebugChange(e) { | ||
setDebugMode(e.detail.active); | ||
} | ||
useEffect(() => { | ||
if (activeDebugId !== debugIdRef.current) | ||
return; | ||
updateDebugPopup({ id: debugIdRef.current, query, state }); | ||
}, [state, query, focused]); | ||
useEffect(() => { | ||
debugEvents.addEventListener("change", onDebugChange); | ||
return () => debugEvents.removeEventListener("change", onDebugChange); | ||
}, []); | ||
useLayoutEffect(() => { | ||
if (!debugMode) | ||
return; | ||
const el = debugRef.current; | ||
if (!el) | ||
return; | ||
const origOutline = el.style.outline; | ||
function onMouseEnter() { | ||
activeDebugId = debugIdRef.current; | ||
el.style.outline = `1px ${colors.debugOutlineFocused} solid`; | ||
setFocused(true); | ||
} | ||
function onMouseLeave() { | ||
el.style.outline = `1px ${colors.debugOutlineSoft} solid`; | ||
setFocused(false); | ||
} | ||
el.style.outline = `1px ${colors.debugOutlineSoft} solid`; | ||
el.addEventListener("mouseenter", onMouseEnter); | ||
el.addEventListener("mouseleave", onMouseLeave); | ||
return () => { | ||
el.style.outline = origOutline; | ||
el.removeEventListener("mouseenter", onMouseEnter); | ||
el.removeEventListener("mouseleave", onMouseLeave); | ||
}; | ||
}, [debugMode, debugRef.current]); | ||
return { debugRef }; | ||
} | ||
function isDebugKeyCombo(e) { | ||
return e.metaKey && e.shiftKey && e.key === "o"; | ||
} | ||
function initializeDebugPopup() { | ||
var _a; | ||
const rootId = "_idb-root"; | ||
(_a = document.getElementById(rootId)) === null || _a === void 0 ? void 0 : _a.remove(); | ||
debugPopupEl = document.createElement("div"); | ||
debugPopupEl.id = rootId; | ||
document.body.appendChild(debugPopupEl); | ||
} | ||
function updateDebugPopup(data) { | ||
const html = /*html*/ ` | ||
<div class="_idb-container"'> | ||
<strong>🔍 Instant Query Inspector</strong> | ||
${data | ||
? ` | ||
<div> | ||
<strong>State:</strong> ${data.state.isLoading ? "Loading" : data.state.error ? "Error" : "OK"} | ||
</div> | ||
<div> | ||
${data.state.data | ||
? ` | ||
<strong>Data</strong> | ||
<pre class="_idb-code">${JSON.stringify(data.state.data, null, 2)}</pre> | ||
` | ||
: data.state.error | ||
? ` | ||
<strong>Error</strong> | ||
<pre class="_idb-code">${JSON.stringify(data.state.error, null, 2)}</pre> | ||
` | ||
: ""} | ||
</div> | ||
<div> | ||
<strong>Query</strong> | ||
<pre class="_idb-code">${JSON.stringify(data.query, null, 2)}</pre> | ||
</div> | ||
` | ||
: `<em>Hover your cursor over an element to inspect it's data.</em>`} | ||
<style> | ||
._idb-container { | ||
animation: pop 0.2s forwards 1; | ||
position: fixed; | ||
bottom: 12px; | ||
right: 12px; | ||
height: 45vh; | ||
width: 50vw; | ||
max-width: 400px; | ||
max-height: 600px; | ||
overflow-x: hidden; | ||
overflow-y: scroll; | ||
display: flex; | ||
flex-direction: column; | ||
gap: 12px; | ||
box-sizing: border-box; | ||
border: 1px #ddd solid; | ||
padding: 16px; | ||
color: black; | ||
background-color: white; | ||
font-family: monospace; | ||
font-size: 11px; | ||
border-radius: 8px; | ||
box-shadow: 0px 0px 12px #00000022; | ||
} | ||
._idb-code { | ||
overflow: auto; | ||
border: 1px #ddd solid; | ||
background-color: #f6f6f6; | ||
padding: 12px; | ||
font-size: 10px; | ||
} | ||
</style> | ||
</div> | ||
`; | ||
debugPopupEl.innerHTML = html; | ||
} | ||
if (isBrowser && isDev) { | ||
addEventListener("keydown", (e) => { | ||
if (!isDebugKeyCombo(e)) { | ||
return; | ||
} | ||
if (!debugPopupEl) { | ||
initializeDebugPopup(); | ||
} | ||
isDebugMode = !isDebugMode; | ||
activeDebugId = null; | ||
debugEvents.dispatchEvent(new CustomEvent("change", { | ||
detail: { active: isDebugMode }, | ||
})); | ||
debugPopupEl.style.display = isDebugMode ? "block" : "none"; | ||
updateDebugPopup(); | ||
}); | ||
} | ||
export { auth, id, tx, transact, getLocalId, useAuth, useQuery, init, }; | ||
//# sourceMappingURL=index.js.map |
{ | ||
"name": "@instantdb/react", | ||
"version": "0.6.3", | ||
"version": "0.6.4", | ||
"description": "Instant DB for React", | ||
@@ -32,4 +32,4 @@ "main": "dist/index.js", | ||
"dependencies": { | ||
"@instantdb/core": "0.6.3" | ||
"@instantdb/core": "0.6.4" | ||
} | ||
} |
203
src/index.ts
@@ -21,4 +21,19 @@ import { | ||
import { useEffect, useState } from "react"; | ||
import { useEffect, useLayoutEffect, useRef, useState } from "react"; | ||
const isBrowser = typeof window !== "undefined"; | ||
const isDev = | ||
typeof process !== "undefined" && process.env?.NODE_ENV === "development"; | ||
const debugEvents = new EventTarget(); | ||
let isDebugMode = false; | ||
let activeDebugId: string | null = null; | ||
let debugPopupEl: HTMLDivElement | null = null; | ||
const colors = { | ||
debugOutlineSoft: "#eec4e4", | ||
debugOutlineFocused: "#f660d2", | ||
}; | ||
/** | ||
@@ -51,4 +66,9 @@ * | ||
* useQuery({ goals: { todos: {} } }) | ||
* | ||
* Curious about the state of your query? | ||
* Just add a `debugRef` to any element and inspect it with debug mode! `(cmd|ctrl) + shift + O` | ||
*/ | ||
function useQuery<Q extends Query>(_query: Exactly<Query, Q>): QueryState<Q> { | ||
function useQuery<Q extends Query>( | ||
_query: Exactly<Query, Q>, | ||
): { debugRef: React.LegacyRef<any> } & QueryState<Q> { | ||
const query = coerceQuery(_query); | ||
@@ -70,4 +90,5 @@ const db = getDB(); | ||
}, [weakHash(query), db]); | ||
const { debugRef } = useDebugRef({ query, state }); | ||
return state; | ||
return { ...state, debugRef }; | ||
} | ||
@@ -117,2 +138,178 @@ | ||
function useDebugRef({ | ||
query, | ||
state, | ||
}: { | ||
query: object; | ||
state: QueryState<any>; | ||
}) { | ||
const debugRef = useRef<HTMLElement>(); | ||
const debugIdRef = useRef<string>(id()); | ||
const [debugMode, setDebugMode] = useState(false); | ||
const [focused, setFocused] = useState(false); | ||
function onDebugChange(e: CustomEvent<{ active: boolean }>) { | ||
setDebugMode(e.detail.active); | ||
} | ||
useEffect(() => { | ||
if (activeDebugId !== debugIdRef.current) return; | ||
updateDebugPopup({ id: debugIdRef.current, query, state }); | ||
}, [state, query, focused]); | ||
useEffect(() => { | ||
debugEvents.addEventListener("change", onDebugChange); | ||
return () => debugEvents.removeEventListener("change", onDebugChange); | ||
}, []); | ||
useLayoutEffect(() => { | ||
if (!debugMode) return; | ||
const el = debugRef.current; | ||
if (!el) return; | ||
const origOutline = el.style.outline; | ||
function onMouseEnter() { | ||
activeDebugId = debugIdRef.current; | ||
el.style.outline = `1px ${colors.debugOutlineFocused} solid`; | ||
setFocused(true); | ||
} | ||
function onMouseLeave() { | ||
el.style.outline = `1px ${colors.debugOutlineSoft} solid`; | ||
setFocused(false); | ||
} | ||
el.style.outline = `1px ${colors.debugOutlineSoft} solid`; | ||
el.addEventListener("mouseenter", onMouseEnter); | ||
el.addEventListener("mouseleave", onMouseLeave); | ||
return () => { | ||
el.style.outline = origOutline; | ||
el.removeEventListener("mouseenter", onMouseEnter); | ||
el.removeEventListener("mouseleave", onMouseLeave); | ||
}; | ||
}, [debugMode, debugRef.current]); | ||
return { debugRef }; | ||
} | ||
function isDebugKeyCombo(e: KeyboardEvent) { | ||
return e.metaKey && e.shiftKey && e.key === "o"; | ||
} | ||
function initializeDebugPopup() { | ||
const rootId = "_idb-root"; | ||
document.getElementById(rootId)?.remove(); | ||
debugPopupEl = document.createElement("div"); | ||
debugPopupEl.id = rootId; | ||
document.body.appendChild(debugPopupEl); | ||
} | ||
function updateDebugPopup(data?: { | ||
id: string; | ||
query: object; | ||
state: QueryState<any>; | ||
}) { | ||
const html = /*html*/ ` | ||
<div class="_idb-container"'> | ||
<strong>🔍 Instant Query Inspector</strong> | ||
${ | ||
data | ||
? ` | ||
<div> | ||
<strong>State:</strong> ${ | ||
data.state.isLoading ? "Loading" : data.state.error ? "Error" : "OK" | ||
} | ||
</div> | ||
<div> | ||
${ | ||
data.state.data | ||
? ` | ||
<strong>Data</strong> | ||
<pre class="_idb-code">${JSON.stringify(data.state.data, null, 2)}</pre> | ||
` | ||
: data.state.error | ||
? ` | ||
<strong>Error</strong> | ||
<pre class="_idb-code">${JSON.stringify(data.state.error, null, 2)}</pre> | ||
` | ||
: "" | ||
} | ||
</div> | ||
<div> | ||
<strong>Query</strong> | ||
<pre class="_idb-code">${JSON.stringify(data.query, null, 2)}</pre> | ||
</div> | ||
` | ||
: `<em>Hover your cursor over an element to inspect it's data.</em>` | ||
} | ||
<style> | ||
._idb-container { | ||
animation: pop 0.2s forwards 1; | ||
position: fixed; | ||
bottom: 12px; | ||
right: 12px; | ||
height: 45vh; | ||
width: 50vw; | ||
max-width: 400px; | ||
max-height: 600px; | ||
overflow-x: hidden; | ||
overflow-y: scroll; | ||
display: flex; | ||
flex-direction: column; | ||
gap: 12px; | ||
box-sizing: border-box; | ||
border: 1px #ddd solid; | ||
padding: 16px; | ||
color: black; | ||
background-color: white; | ||
font-family: monospace; | ||
font-size: 11px; | ||
border-radius: 8px; | ||
box-shadow: 0px 0px 12px #00000022; | ||
} | ||
._idb-code { | ||
overflow: auto; | ||
border: 1px #ddd solid; | ||
background-color: #f6f6f6; | ||
padding: 12px; | ||
font-size: 10px; | ||
} | ||
</style> | ||
</div> | ||
`; | ||
debugPopupEl.innerHTML = html; | ||
} | ||
if (isBrowser && isDev) { | ||
addEventListener("keydown", (e) => { | ||
if (!isDebugKeyCombo(e)) { | ||
return; | ||
} | ||
if (!debugPopupEl) { | ||
initializeDebugPopup(); | ||
} | ||
isDebugMode = !isDebugMode; | ||
activeDebugId = null; | ||
debugEvents.dispatchEvent( | ||
new CustomEvent("change", { | ||
detail: { active: isDebugMode }, | ||
}), | ||
); | ||
debugPopupEl.style.display = isDebugMode ? "block" : "none"; | ||
updateDebugPopup(); | ||
}); | ||
} | ||
export { | ||
@@ -119,0 +316,0 @@ Config, |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
41032
924
3
+ Added@instantdb/core@0.6.4(transitive)
- Removed@instantdb/core@0.6.3(transitive)
Updated@instantdb/core@0.6.4