UNPKG

@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
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