/
index.ts
144 lines (131 loc) · 4.3 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
import { getNextElement, insert, spread, SVGElements, hydrate as hydrateCore } from "./client.js";
import {
createSignal,
createMemo,
onCleanup,
untrack,
splitProps,
JSX,
createRoot,
sharedConfig,
enableHydration,
$DEVCOMP,
ComponentProps,
ValidComponent,
createEffect,
getOwner,
runWithOwner
} 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: boolean = false;
export const isDev: boolean = "_SOLID_DEV_" as unknown as boolean;
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 `<div>` 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://docs.solidjs.com/reference/components/portal
*/
export function Portal<T extends boolean = false, S extends boolean = false>(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,
owner = getOwner();
let content: undefined | (() => JSX.Element);
let hydrating = !!sharedConfig.context;
createEffect(
() => {
// basically we backdoor into a sort of renderEffect here
if (hydrating) (getOwner() as any).user = hydrating = false;
content || (content = runWithOwner(owner, () => createMemo(() => props.children)));
const el = mount();
if (el instanceof HTMLHeadElement) {
const [clean, setClean] = createSignal(false);
const cleanup = () => setClean(true);
createRoot(dispose => insert(el, () => (!clean() ? content!() : dispose()), null));
onCleanup(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;
},
configurable: true
});
insert(renderRoot, content);
el.appendChild(container);
props.ref && (props as any).ref(container);
onCleanup(() => el.removeChild(container));
}
},
undefined,
{ render: !hydrating }
);
return marker;
}
export type DynamicProps<T extends ValidComponent, P = ComponentProps<T>> = {
[K in keyof P]: P[K];
} & {
component: T | undefined;
};
/**
* Renders an arbitrary custom or native component and passes the other props
* ```typescript
* <Dynamic component={multiline() ? 'textarea' : 'input'} value={value()} />
* ```
* @description https://docs.solidjs.com/reference/components/dynamic
*/
export function Dynamic<T extends ValidComponent>(props: DynamicProps<T>): JSX.Element {
const [p, others] = splitProps(props, ["component"]);
const cached = createMemo<Function | string>(() => 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;
}
}) as unknown as JSX.Element;
}