@hakit/core
Version:
A collection of React hooks and helpers for Home Assistant to easily communicate with the Home Assistant WebSocket API.
382 lines (381 loc) • 11.6 kB
JavaScript
import * as F from "react/jsx-runtime";
import * as w from "react";
import it, { forwardRef as ut, useContext as lt, useRef as q, useCallback as d, useEffect as x, useMemo as ft } from "react";
import gt from "@emotion/cache";
import { getRegisteredStyles as ht, registerStyles as dt, insertStyles as mt } from "@emotion/utils";
import { serializeStyles as yt } from "@emotion/serialize";
import St from "react-is";
import { getStates as pt, getServices as vt, getConfig as Et, getUser as X, subscribeEntities as bt, subscribeConfig as wt, callService as Ct } from "home-assistant-js-websocket";
import { isArray as Pt, snakeCase as G } from "lodash";
import { clearTokens as Ot, loadTokens as jt } from "./es/HassConnect/token-storage.js";
import { useInternalStore as u, HassContext as xt } from "./es/HassConnect/HassContext.js";
import { useStore as Tt } from "./es/hooks/useStore/index.js";
import { handleSuspendResume as Rt } from "./es/HassConnect/handleSuspendResume.js";
import { callApi as Nt } from "./es/HassConnect/callApi.js";
import { tryConnection as It, handleError as $t } from "./es/HassConnect/tryConnection.js";
var Y, Q;
function Ht() {
if (Q) return Y;
Q = 1;
var r = St, t = {
childContextTypes: !0,
contextType: !0,
contextTypes: !0,
defaultProps: !0,
displayName: !0,
getDefaultProps: !0,
getDerivedStateFromError: !0,
getDerivedStateFromProps: !0,
mixins: !0,
propTypes: !0,
type: !0
}, s = {
name: !0,
length: !0,
prototype: !0,
caller: !0,
callee: !0,
arguments: !0,
arity: !0
}, n = {
$$typeof: !0,
render: !0,
defaultProps: !0,
displayName: !0,
propTypes: !0
}, o = {
$$typeof: !0,
compare: !0,
defaultProps: !0,
displayName: !0,
propTypes: !0,
type: !0
}, c = {};
c[r.ForwardRef] = n, c[r.Memo] = o;
function g(S) {
return r.isMemo(S) ? o : c[S.$$typeof] || t;
}
var m = Object.defineProperty, h = Object.getOwnPropertyNames, l = Object.getOwnPropertySymbols, M = Object.getOwnPropertyDescriptor, L = Object.getPrototypeOf, $ = Object.prototype;
function _(S, v, T) {
if (typeof v != "string") {
if ($) {
var R = L(v);
R && R !== $ && _(S, R, T);
}
var O = h(v);
l && (O = O.concat(l(v)));
for (var E = g(S), N = g(v), I = 0; I < O.length; ++I) {
var b = O[I];
if (!s[b] && !(T && T[b]) && !(N && N[b]) && !(E && E[b])) {
var A = M(v, b);
try {
m(S, b, A);
} catch {
}
}
}
}
return S;
}
return Y = _, Y;
}
Ht();
var Ut = function(t) {
return t();
}, Ft = w.useInsertionEffect ? w.useInsertionEffect : !1, Mt = Ft || Ut, et = /* @__PURE__ */ w.createContext(
// we're doing this to avoid preconstruct's dead code elimination in this one case
// because this module is primarily intended for the browser and node
// but it's also required in react native and similar environments sometimes
// and we could have a special build just for that
// but this is much easier and the native packages
// might use a different theme context in the future anyway
typeof HTMLElement < "u" ? /* @__PURE__ */ gt({
key: "css"
}) : null
);
et.Provider;
var _t = function(t) {
return /* @__PURE__ */ ut(function(s, n) {
var o = lt(et);
return t(s, o, n);
});
}, At = /* @__PURE__ */ w.createContext({}), z = {}.hasOwnProperty, J = "__EMOTION_TYPE_PLEASE_DO_NOT_USE__", rt = function(t, s) {
var n = {};
for (var o in s)
z.call(s, o) && (n[o] = s[o]);
return n[J] = t, n;
}, Dt = function(t) {
var s = t.cache, n = t.serialized, o = t.isStringTag;
return dt(s, n, o), Mt(function() {
return mt(s, n, o);
}), null;
}, zt = /* @__PURE__ */ _t(function(r, t, s) {
var n = r.css;
typeof n == "string" && t.registered[n] !== void 0 && (n = t.registered[n]);
var o = r[J], c = [n], g = "";
typeof r.className == "string" ? g = ht(t.registered, c, r.className) : r.className != null && (g = r.className + " ");
var m = yt(c, void 0, w.useContext(At));
g += t.key + "-" + m.name;
var h = {};
for (var l in r)
z.call(r, l) && l !== "css" && l !== J && (h[l] = r[l]);
return h.className = g, s && (h.ref = s), /* @__PURE__ */ w.createElement(w.Fragment, null, /* @__PURE__ */ w.createElement(Dt, {
cache: t,
serialized: m,
isStringTag: typeof o == "string"
}), /* @__PURE__ */ w.createElement(o, h));
}), nt = zt, oe = F.Fragment, Z = function(t, s, n) {
return z.call(s, "css") ? F.jsx(nt, rt(t, s), n) : F.jsx(t, s, n);
}, Lt = function(t, s, n) {
return z.call(s, "css") ? F.jsxs(nt, rt(t, s), n) : F.jsxs(t, s, n);
};
const k = (r) => Symbol.iterator in r, B = (r) => (
// HACK: avoid checking entries type
"entries" in r
), tt = (r, t) => {
const s = r instanceof Map ? r : new Map(r.entries()), n = t instanceof Map ? t : new Map(t.entries());
if (s.size !== n.size)
return !1;
for (const [o, c] of s)
if (!Object.is(c, n.get(o)))
return !1;
return !0;
}, Wt = (r, t) => {
const s = r[Symbol.iterator](), n = t[Symbol.iterator]();
let o = s.next(), c = n.next();
for (; !o.done && !c.done; ) {
if (!Object.is(o.value, c.value))
return !1;
o = s.next(), c = n.next();
}
return !!o.done && !!c.done;
};
function qt(r, t) {
return Object.is(r, t) ? !0 : typeof r != "object" || r === null || typeof t != "object" || t === null || Object.getPrototypeOf(r) !== Object.getPrototypeOf(t) ? !1 : k(r) && k(t) ? B(r) && B(t) ? tt(r, t) : Wt(r, t) : tt(
{ entries: () => Object.entries(r) },
{ entries: () => Object.entries(t) }
);
}
function Yt(r) {
const t = it.useRef(void 0);
return (s) => {
const n = r(s);
return qt(t.current, n) ? t.current : t.current = n;
};
}
const Jt = () => u.getState().entities, D = () => u.getState().connection;
function ae({
children: r,
hassUrl: t,
hassToken: s,
portalRoot: n,
windowContext: o,
renderError: c = (m) => m,
handleResumeOptions: g
}) {
const m = q(null), h = q(!1), l = q(null), {
hash: M,
ready: L,
error: $,
cannotConnect: _,
setError: S
} = u(
Yt((e) => ({
hash: e.hash,
routes: e.routes,
ready: e.ready,
// ready is set internally in the store when we have entities (setEntities does this)
error: e.error,
cannotConnect: e.cannotConnect,
auth: e.auth,
setError: e.setError
}))
), v = d(async () => {
const e = D();
return e === null ? null : await pt(e);
}, []), T = d(async () => {
const e = D();
return e === null ? null : await vt(e);
}, []), R = d(async () => {
const e = D();
return e === null ? null : await Et(e);
}, []), O = d(async () => {
const e = D();
return e === null ? null : await X(e);
}, []);
x(() => {
const { setPortalRoot: e } = u.getState();
n && e(n);
}, [n]), x(() => {
const { setWindowContext: e } = u.getState();
o && e(o);
}, [o]);
const E = d(() => {
const {
setAuth: e,
setUser: a,
setCannotConnect: p,
setConfig: f,
setConnection: i,
setEntities: C,
setError: H,
setReady: U,
setRoutes: y,
setConnectionStatus: j
} = u.getState();
e(null), y([]), U(!1), i(null), C({}), f(null), H(null), p(!1), a(null), j("pending"), h.current = !1, l.current && (l.current(), l.current = null), m.current && (m.current(), m.current = null);
}, []), N = d(async () => {
const { setError: e } = u.getState();
try {
E(), Ot(), location && location.reload();
} catch (a) {
console.error("Error:", a), e("Unable to log out!");
}
}, [E]), I = d(async () => {
const { setError: e, setUser: a, setCannotConnect: p, setAuth: f, setConnection: i, setEntities: C, setConfig: H, setConnectionStatus: U } = u.getState(), y = await It(t, s);
if (y.type === "error")
h.current = !1, e(y.error);
else if (y.type === "failed")
h.current = !1, p(!0);
else if (y.type === "success") {
const { connection: j, auth: ot } = y;
f(ot), i(j), m.current = bt(j, (P) => {
C(P);
}), l.current = wt(j, (P) => {
H(P);
}), X(j).then((P) => {
a(P);
});
const { onStatusChange: at, ...ct } = g || {};
return Rt(j, {
suspendWhenHidden: !0,
hiddenDelayMs: 3e5,
// 5 minutes
debug: !1,
onStatusChange: (P) => {
U(P), at?.(P);
},
...ct
});
}
}, [t, s, g]);
x(() => {
const { setHassUrl: e } = u.getState();
e(t);
}, [t]);
const b = d((e) => {
const { connection: a } = u.getState();
return a ? new URL(e, a?.options.auth?.data.hassUrl).toString() : "";
}, []);
x(() => {
const { setHash: e } = u.getState();
location.hash !== "" && location.hash.replace("#", "") !== M && e(location.hash);
}, [M]), x(() => {
function e() {
const { routes: a, setRoutes: p, setHash: f } = u.getState();
p(
a.map((i) => i.hash === location.hash.replace("#", "") ? {
...i,
active: !0
} : {
...i,
active: !1
})
), f(location.hash);
}
return window.addEventListener("hashchange", e), () => {
window.removeEventListener("hashchange", e);
};
}, []);
const A = d((e) => {
const { routes: a, setRoutes: p } = u.getState();
if (!(a.find((i) => i.hash === e.hash) !== void 0) && typeof window < "u") {
const i = window.location.hash.replace("#", ""), C = i !== "" && i === e.hash;
p([
...a,
{
...e,
active: C
}
]);
}
}, []), W = d((e) => u.getState().routes.find((f) => f.hash === e) || null, []), K = d(
async ({
domain: e,
service: a,
serviceData: p,
target: f,
returnResponse: i
}) => {
const { connection: C, ready: H } = u.getState(), U = typeof f == "string" || Pt(f) ? {
entity_id: f
} : f;
if (typeof a != "string")
throw new Error("service must be a string");
if (C && H)
try {
const y = await Ct(
C,
G(e),
G(a),
// purposely cast here as we know it's correct
p,
U,
i
);
return i ? y : void 0;
} catch (y) {
console.log("Error:", y);
}
},
[]
);
x(() => () => {
E();
}, [E]);
const V = d(async () => {
try {
h.current && E(), h.current = !0, g?.onStatusChange?.("pending"), await I();
} catch (e) {
const a = $t(e);
S(`Unable to connect to Home Assistant, please check the URL: "${a}"`);
}
}, [E, I, S, g]);
x(() => {
V();
}, [V]);
const st = ft(
() => ({
useStore: Tt,
logout: N,
addRoute: A,
getRoute: W,
getStates: v,
getServices: T,
getConfig: R,
getUser: O,
callApi: Nt,
getAllEntities: Jt,
callService: K,
joinHassUrl: b
}),
[N, A, W, v, T, R, O, K, b]
);
return _ ? c(
/* @__PURE__ */ Lt("p", { children: [
"Unable to connect to $",
jt(t).hassUrl,
", refresh the page and try again, or ",
/* @__PURE__ */ Z("a", { onClick: N, children: "Logout" }),
"."
] })
) : /* @__PURE__ */ Z(xt.Provider, { value: st, children: $ === null ? r(L) : c($) });
}
export {
oe as F,
ae as H,
Lt as a,
Z as j,
Yt as u
};
//# sourceMappingURL=Provider-fbkyrDDA.js.map