import { getNextElement, insert, spread, SVGElements, hydrate as hydrateCore } from "./client.js";
import {
createSignal,
createMemo,
onCleanup,
untrack,
splitProps,
JSX,
createRoot,
sharedConfig,
Accessor,
enableHydration,
$DEVCOMP,
ComponentProps,
ValidComponent,
} from "solid-js";
export * from "./client.js";
export {
For,
Show,
Suspense,
SuspenseList,
Switch,
Match,
Index,
ErrorBoundary,
mergeProps
} from "solid-js";
export * from "./server-mock.js";
export const isServer = false;
const SVG_NAMESPACE = "http://www.w3.org/2000/svg";
function createElement(tagName: string, isSVG = false): HTMLElement | SVGElement {
return isSVG ? document.createElementNS(SVG_NAMESPACE, tagName) : document.createElement(tagName);
}
export const hydrate: typeof hydrateCore = (...args) => {
enableHydration();
return hydrateCore(...args);
};
/**
* renders components somewhere else in the DOM
*
* Useful for inserting modals and tooltips outside of an cropping layout. If no mount point is given, the portal is inserted in document.body; it is wrapped in a `
` unless the target is document.head or `isSVG` is true. setting `useShadow` to true places the element in a shadow root to isolate styles.
*
* @description https://www.solidjs.com/docs/latest/api#%3Cportal%3E
*/
export function Portal(props: {
mount?: Node;
useShadow?: T;
isSVG?: S;
ref?:
| (S extends true ? SVGGElement : HTMLDivElement)
| ((
el: (T extends true ? { readonly shadowRoot: ShadowRoot } : {}) &
(S extends true ? SVGGElement : HTMLDivElement)
) => void);
children: JSX.Element;
}) {
const { useShadow } = props,
marker = document.createTextNode(""),
mount = props.mount || document.body;
// don't render when hydrating
function renderPortal() {
if (sharedConfig.context) {
const [s, set] = createSignal(false);
queueMicrotask(() => set(true));
return () => s() && props.children;
} else return () => props.children;
}
if (mount instanceof HTMLHeadElement) {
const [clean, setClean] = createSignal(false);
const cleanup = () => setClean(true);
createRoot(dispose => insert(mount, () => (!clean() ? renderPortal()() : dispose()), null));
onCleanup(() => {
if (sharedConfig.context) queueMicrotask(cleanup);
else cleanup();
});
} else {
const container = createElement(props.isSVG ? "g" : "div", props.isSVG),
renderRoot =
useShadow && container.attachShadow ? container.attachShadow({ mode: "open" }) : container;
Object.defineProperty(container, "host", {
get() {
return marker.parentNode;
}
});
insert(renderRoot, renderPortal());
mount.appendChild(container);
(props as any).ref && (props as any).ref(container);
onCleanup(() => mount.removeChild(container));
}
return marker;
}
type DynamicProps = ComponentProps & {
component: T | undefined;
};
/**
* renders an arbitrary custom or native component and passes the other props
* ```typescript
*
* ```
* @description https://www.solidjs.com/docs/latest/api#%3Cdynamic%3E
*/
export function Dynamic(props: DynamicProps): Accessor {
const [p, others] = splitProps(props, ["component"]);
const cached = createMemo(() => p.component)
return createMemo(() => {
const component = cached();
switch (typeof component) {
case "function":
if ("_DX_DEV_") Object.assign(component, { [$DEVCOMP]: true });
return untrack(() => component(others));
case "string":
const isSvg = SVGElements.has(component);
const el = sharedConfig.context ? getNextElement() : createElement(component, isSvg);
spread(el, others, isSvg);
return el;
default:
break;
}
});
}