UNPKG

1.76 kBJavaScriptView Raw
1import { h, createContext } from "preact";
2import { useContext } from "preact/hooks";
3const isServer = typeof window === "undefined";
4export const HydrateContext = createContext(false);
5export function withHydrate(Component, hydrationProps = {}) {
6 const name = hydrationProps.displayName || Component.displayName || Component.name;
7 const { method, fallback: Fallback } = hydrationProps;
8 const Wrapped = (props, ref) => {
9 const hydrateParent = useContext(HydrateContext);
10 if (hydrateParent)
11 throw new Error(`withHydrate() should only be called at the top-level of a Component tree. <${name} /> should not be nested within <${hydrateParent} />`);
12 if (props.children && !["string", "number"].includes(typeof props.children))
13 throw new Error(`withHydrate() is unable to serialize complex \`children\`. Please inline these children into <${name} />.`);
14 const p = isServer ? `p=${JSON.stringify(props)}` : '';
15 const m = isServer && method ? `m=${method}` : '';
16 const f = isServer && typeof Fallback !== 'undefined' ? 'f=1' : '';
17 const Marker = 'hydrate-marker';
18 const Placeholder = 'hydrate-placeholder';
19 return (h(HydrateContext.Provider, { value: name },
20 isServer && (h(Marker, { dangerouslySetInnerHTML: { __html: `?h c=${name} ?` } })),
21 typeof Fallback !== 'undefined' ? (Fallback || h(Placeholder, null)) : h(Component, Object.assign({}, Object.assign(Object.assign({}, props), { ref }))),
22 isServer && (h(Marker, { dangerouslySetInnerHTML: { __html: `?h ${[p, m, f].filter(v => v).join(' ')} ?` } }))));
23 };
24 Object.defineProperty(Wrapped, "name", { value: name, configurable: true });
25 return Wrapped;
26}