dev.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511
  1. import { createMemo, createRoot, createRenderEffect, sharedConfig, createSignal, onCleanup, splitProps, untrack } from 'solid-js';
  2. export { ErrorBoundary, For, Index, Match, Show, Suspense, SuspenseList, Switch, createComponent, createRenderEffect as effect, getOwner, mergeProps } from 'solid-js';
  3. const booleans = ["allowfullscreen", "allowpaymentrequest", "async", "autofocus", "autoplay", "checked", "controls", "default", "disabled", "formnovalidate", "hidden", "ismap", "itemscope", "loop", "multiple", "muted", "nomodule", "novalidate", "open", "playsinline", "readonly", "required", "reversed", "seamless", "selected", "truespeed"];
  4. const Properties = new Set(["className", "indeterminate", "value", ...booleans]);
  5. const ChildProperties = new Set(["innerHTML", "textContent", "innerText", "children"]);
  6. const Aliases = {
  7. className: "class",
  8. htmlFor: "for"
  9. };
  10. const DelegatedEvents = new Set(["beforeinput", "click", "dblclick", "focusin", "focusout", "input", "keydown", "keyup", "mousedown", "mousemove", "mouseout", "mouseover", "mouseup", "pointerdown", "pointermove", "pointerout", "pointerover", "pointerup", "touchend", "touchmove", "touchstart"]);
  11. const SVGElements = new Set([
  12. "altGlyph", "altGlyphDef", "altGlyphItem", "animate", "animateColor", "animateMotion", "animateTransform", "circle", "clipPath", "color-profile", "cursor", "defs", "desc", "ellipse", "feBlend", "feColorMatrix", "feComponentTransfer", "feComposite", "feConvolveMatrix", "feDiffuseLighting", "feDisplacementMap", "feDistantLight", "feFlood", "feFuncA", "feFuncB", "feFuncG", "feFuncR", "feGaussianBlur", "feImage", "feMerge", "feMergeNode", "feMorphology", "feOffset", "fePointLight", "feSpecularLighting", "feSpotLight", "feTile", "feTurbulence", "filter", "font", "font-face", "font-face-format", "font-face-name", "font-face-src", "font-face-uri", "foreignObject", "g", "glyph", "glyphRef", "hkern", "image", "line", "linearGradient", "marker", "mask", "metadata", "missing-glyph", "mpath", "path", "pattern", "polygon", "polyline", "radialGradient", "rect",
  13. "set", "stop",
  14. "svg", "switch", "symbol", "text", "textPath",
  15. "tref", "tspan", "use", "view", "vkern"]);
  16. const SVGNamespace = {
  17. xlink: "http://www.w3.org/1999/xlink",
  18. xml: "http://www.w3.org/XML/1998/namespace"
  19. };
  20. function memo(fn, equals) {
  21. return createMemo(fn, undefined, !equals ? {
  22. equals
  23. } : undefined);
  24. }
  25. function reconcileArrays(parentNode, a, b) {
  26. let bLength = b.length,
  27. aEnd = a.length,
  28. bEnd = bLength,
  29. aStart = 0,
  30. bStart = 0,
  31. after = a[aEnd - 1].nextSibling,
  32. map = null;
  33. while (aStart < aEnd || bStart < bEnd) {
  34. if (aEnd === aStart) {
  35. const node = bEnd < bLength ? bStart ? b[bStart - 1].nextSibling : b[bEnd - bStart] : after;
  36. while (bStart < bEnd) parentNode.insertBefore(b[bStart++], node);
  37. } else if (bEnd === bStart) {
  38. while (aStart < aEnd) {
  39. if (!map || !map.has(a[aStart])) parentNode.removeChild(a[aStart]);
  40. aStart++;
  41. }
  42. } else if (a[aStart] === b[bStart]) {
  43. aStart++;
  44. bStart++;
  45. } else if (a[aEnd - 1] === b[bEnd - 1]) {
  46. aEnd--;
  47. bEnd--;
  48. } else if (a[aStart] === b[bEnd - 1] && b[bStart] === a[aEnd - 1]) {
  49. const node = a[--aEnd].nextSibling;
  50. parentNode.insertBefore(b[bStart++], a[aStart++].nextSibling);
  51. parentNode.insertBefore(b[--bEnd], node);
  52. a[aEnd] = b[bEnd];
  53. } else {
  54. if (!map) {
  55. map = new Map();
  56. let i = bStart;
  57. while (i < bEnd) map.set(b[i], i++);
  58. }
  59. const index = map.get(a[aStart]);
  60. if (index != null) {
  61. if (bStart < index && index < bEnd) {
  62. let i = aStart,
  63. sequence = 1,
  64. t;
  65. while (++i < aEnd && i < bEnd) {
  66. if ((t = map.get(a[i])) == null || t !== index + sequence) break;
  67. sequence++;
  68. }
  69. if (sequence > index - bStart) {
  70. const node = a[aStart];
  71. while (bStart < index) parentNode.insertBefore(b[bStart++], node);
  72. } else parentNode.replaceChild(b[bStart++], a[aStart++]);
  73. } else aStart++;
  74. } else parentNode.removeChild(a[aStart++]);
  75. }
  76. }
  77. }
  78. const $$EVENTS = Symbol("delegated-events");
  79. function render(code, element, init) {
  80. let disposer;
  81. createRoot(dispose => {
  82. disposer = dispose;
  83. insert(element, code(), element.firstChild ? null : undefined, init);
  84. });
  85. return () => {
  86. disposer();
  87. element.textContent = "";
  88. };
  89. }
  90. function template(html, check, isSVG) {
  91. const t = document.createElement("template");
  92. t.innerHTML = html;
  93. if (check && t.innerHTML.split("<").length - 1 !== check) throw `The browser resolved template HTML does not match JSX input:\n${t.innerHTML}\n\n${html}. Is your HTML properly formed?`;
  94. let node = t.content.firstChild;
  95. if (isSVG) node = node.firstChild;
  96. return node;
  97. }
  98. function delegateEvents(eventNames) {
  99. const e = document[$$EVENTS] || (document[$$EVENTS] = new Set());
  100. for (let i = 0, l = eventNames.length; i < l; i++) {
  101. const name = eventNames[i];
  102. if (!e.has(name)) {
  103. e.add(name);
  104. document.addEventListener(name, eventHandler);
  105. }
  106. }
  107. }
  108. function clearDelegatedEvents() {
  109. if (document[$$EVENTS]) {
  110. for (let name of document[$$EVENTS].keys()) document.removeEventListener(name, eventHandler);
  111. delete document[$$EVENTS];
  112. }
  113. }
  114. function setAttribute(node, name, value) {
  115. if (value == null) node.removeAttribute(name);else node.setAttribute(name, value);
  116. }
  117. function setAttributeNS(node, namespace, name, value) {
  118. if (value == null) node.removeAttributeNS(namespace, name);else node.setAttributeNS(namespace, name, value);
  119. }
  120. function addEventListener(node, name, handler, delegate) {
  121. if (delegate) {
  122. if (Array.isArray(handler)) {
  123. node[`$$${name}`] = handler[0];
  124. node[`$$${name}Data`] = handler[1];
  125. } else node[`$$${name}`] = handler;
  126. } else if (Array.isArray(handler)) {
  127. node.addEventListener(name, e => handler[0](handler[1], e));
  128. } else node.addEventListener(name, handler);
  129. }
  130. function classList(node, value, prev = {}) {
  131. const classKeys = Object.keys(value),
  132. prevKeys = Object.keys(prev);
  133. let i, len;
  134. for (i = 0, len = prevKeys.length; i < len; i++) {
  135. const key = prevKeys[i];
  136. if (!key || key === "undefined" || key in value) continue;
  137. toggleClassKey(node, key, false);
  138. delete prev[key];
  139. }
  140. for (i = 0, len = classKeys.length; i < len; i++) {
  141. const key = classKeys[i],
  142. classValue = !!value[key];
  143. if (!key || key === "undefined" || prev[key] === classValue) continue;
  144. toggleClassKey(node, key, classValue);
  145. prev[key] = classValue;
  146. }
  147. return prev;
  148. }
  149. function style(node, value, prev = {}) {
  150. const nodeStyle = node.style;
  151. if (typeof value === "string") return nodeStyle.cssText = value;
  152. typeof prev === "string" && (prev = {});
  153. let v, s;
  154. for (s in prev) {
  155. value[s] == null && nodeStyle.removeProperty(s);
  156. delete prev[s];
  157. }
  158. for (s in value) {
  159. v = value[s];
  160. if (v !== prev[s]) {
  161. nodeStyle.setProperty(s, v);
  162. prev[s] = v;
  163. }
  164. }
  165. return prev;
  166. }
  167. function spread(node, accessor, isSVG, skipChildren) {
  168. if (typeof accessor === "function") {
  169. createRenderEffect(current => spreadExpression(node, accessor(), current, isSVG, skipChildren));
  170. } else spreadExpression(node, accessor, undefined, isSVG, skipChildren);
  171. }
  172. function dynamicProperty(props, key) {
  173. const src = props[key];
  174. Object.defineProperty(props, key, {
  175. get() {
  176. return src();
  177. },
  178. enumerable: true
  179. });
  180. return props;
  181. }
  182. function insert(parent, accessor, marker, initial) {
  183. if (marker !== undefined && !initial) initial = [];
  184. if (typeof accessor !== "function") return insertExpression(parent, accessor, initial, marker);
  185. createRenderEffect(current => insertExpression(parent, accessor(), current, marker), initial);
  186. }
  187. function assign(node, props, isSVG, skipChildren, prevProps = {}) {
  188. let isCE, isProp, isChildProp;
  189. for (const prop in props) {
  190. if (prop === "children") {
  191. if (!skipChildren) insertExpression(node, props.children);
  192. continue;
  193. }
  194. const value = props[prop];
  195. if (value === prevProps[prop]) continue;
  196. if (prop === "style") {
  197. style(node, value, prevProps[prop]);
  198. } else if (prop === "class" && !isSVG) {
  199. node.className = value;
  200. } else if (prop === "classList") {
  201. classList(node, value, prevProps[prop]);
  202. } else if (prop === "ref") {
  203. value(node);
  204. } else if (prop.slice(0, 3) === "on:") {
  205. node.addEventListener(prop.slice(3), value);
  206. } else if (prop.slice(0, 10) === "oncapture:") {
  207. node.addEventListener(prop.slice(10), value, true);
  208. } else if (prop.slice(0, 2) === "on") {
  209. const name = prop.slice(2).toLowerCase();
  210. const delegate = DelegatedEvents.has(name);
  211. addEventListener(node, name, value, delegate);
  212. delegate && delegateEvents([name]);
  213. } else if ((isChildProp = ChildProperties.has(prop)) || !isSVG && (isProp = Properties.has(prop)) || (isCE = node.nodeName.includes("-"))) {
  214. if (isCE && !isProp && !isChildProp) node[toPropertyName(prop)] = value;else node[prop] = value;
  215. } else {
  216. const ns = isSVG && prop.indexOf(":") > -1 && SVGNamespace[prop.split(":")[0]];
  217. if (ns) setAttributeNS(node, ns, prop, value);else setAttribute(node, Aliases[prop] || prop, value);
  218. }
  219. prevProps[prop] = value;
  220. }
  221. }
  222. function hydrate(code, element) {
  223. sharedConfig.resources = globalThis._$HYDRATION.resources;
  224. sharedConfig.completed = globalThis._$HYDRATION.completed;
  225. sharedConfig.events = globalThis._$HYDRATION.events;
  226. sharedConfig.context = {
  227. id: "",
  228. count: 0,
  229. loadResource: globalThis._$HYDRATION.loadResource
  230. };
  231. sharedConfig.registry = new Map();
  232. gatherHydratable(element);
  233. const dispose = render(code, element, [...element.childNodes]);
  234. sharedConfig.context = null;
  235. return dispose;
  236. }
  237. function gatherHydratable(element) {
  238. const templates = element.querySelectorAll(`*[data-hk]`);
  239. for (let i = 0; i < templates.length; i++) {
  240. const node = templates[i];
  241. sharedConfig.registry.set(node.getAttribute("data-hk"), node);
  242. }
  243. }
  244. function getNextElement(template) {
  245. let node, key;
  246. if (!sharedConfig.context || !(node = sharedConfig.registry.get(key = getHydrationKey()))) {
  247. return template.cloneNode(true);
  248. }
  249. if (sharedConfig.completed) sharedConfig.completed.add(node);
  250. sharedConfig.registry.delete(key);
  251. return node;
  252. }
  253. function getNextMarker(start) {
  254. let end = start,
  255. count = 0,
  256. current = [];
  257. if (sharedConfig.context) {
  258. while (end) {
  259. if (end.nodeType === 8) {
  260. const v = end.nodeValue;
  261. if (v === "#") count++;else if (v === "/") {
  262. if (count === 0) return [end, current];
  263. count--;
  264. }
  265. }
  266. current.push(end);
  267. end = end.nextSibling;
  268. }
  269. }
  270. return [end, current];
  271. }
  272. function runHydrationEvents() {
  273. if (sharedConfig.events && !sharedConfig.events.queued) {
  274. queueMicrotask(() => {
  275. const {
  276. completed,
  277. events
  278. } = sharedConfig;
  279. events.queued = false;
  280. while (events.length) {
  281. const [el, e] = events[0];
  282. if (!completed.has(el)) return;
  283. eventHandler(e);
  284. events.shift();
  285. }
  286. });
  287. sharedConfig.events.queued = true;
  288. }
  289. }
  290. function toPropertyName(name) {
  291. return name.toLowerCase().replace(/-([a-z])/g, (_, w) => w.toUpperCase());
  292. }
  293. function toggleClassKey(node, key, value) {
  294. const classNames = key.split(/\s+/);
  295. for (let i = 0, nameLen = classNames.length; i < nameLen; i++) node.classList.toggle(classNames[i], value);
  296. }
  297. function eventHandler(e) {
  298. const key = `$$${e.type}`;
  299. let node = e.composedPath && e.composedPath()[0] || e.target;
  300. if (e.target !== node) {
  301. Object.defineProperty(e, "target", {
  302. configurable: true,
  303. value: node
  304. });
  305. }
  306. Object.defineProperty(e, "currentTarget", {
  307. configurable: true,
  308. get() {
  309. return node;
  310. }
  311. });
  312. while (node !== null) {
  313. const handler = node[key];
  314. if (handler) {
  315. const data = node[`${key}Data`];
  316. data !== undefined ? handler(data, e) : handler(e);
  317. if (e.cancelBubble) return;
  318. }
  319. node = node.host && node.host !== node && node.host instanceof Node ? node.host : node.parentNode;
  320. }
  321. }
  322. function spreadExpression(node, props, prevProps = {}, isSVG, skipChildren) {
  323. if (!skipChildren && "children" in props) {
  324. createRenderEffect(() => prevProps.children = insertExpression(node, props.children, prevProps.children));
  325. }
  326. createRenderEffect(() => assign(node, props, isSVG, true, prevProps));
  327. return prevProps;
  328. }
  329. function insertExpression(parent, value, current, marker, unwrapArray) {
  330. while (typeof current === "function") current = current();
  331. if (value === current) return current;
  332. const t = typeof value,
  333. multi = marker !== undefined;
  334. parent = multi && current[0] && current[0].parentNode || parent;
  335. if (t === "string" || t === "number") {
  336. if (t === "number") value = value.toString();
  337. if (multi) {
  338. let node = current[0];
  339. if (node && node.nodeType === 3) {
  340. node.data = value;
  341. } else node = document.createTextNode(value);
  342. current = cleanChildren(parent, current, marker, node);
  343. } else {
  344. if (current !== "" && typeof current === "string") {
  345. current = parent.firstChild.data = value;
  346. } else current = parent.textContent = value;
  347. }
  348. } else if (value == null || t === "boolean") {
  349. if (sharedConfig.context) return current;
  350. current = cleanChildren(parent, current, marker);
  351. } else if (t === "function") {
  352. createRenderEffect(() => {
  353. let v = value();
  354. while (typeof v === "function") v = v();
  355. current = insertExpression(parent, v, current, marker);
  356. });
  357. return () => current;
  358. } else if (Array.isArray(value)) {
  359. const array = [];
  360. if (normalizeIncomingArray(array, value, unwrapArray)) {
  361. createRenderEffect(() => current = insertExpression(parent, array, current, marker, true));
  362. return () => current;
  363. }
  364. if (sharedConfig.context && current.length) return current;
  365. if (array.length === 0) {
  366. current = cleanChildren(parent, current, marker);
  367. if (multi) return current;
  368. } else {
  369. if (Array.isArray(current)) {
  370. if (current.length === 0) {
  371. appendNodes(parent, array, marker);
  372. } else reconcileArrays(parent, current, array);
  373. } else if (current == null || current === "") {
  374. appendNodes(parent, array);
  375. } else {
  376. reconcileArrays(parent, multi && current || [parent.firstChild], array);
  377. }
  378. }
  379. current = array;
  380. } else if (value instanceof Node) {
  381. if (Array.isArray(current)) {
  382. if (multi) return current = cleanChildren(parent, current, marker, value);
  383. cleanChildren(parent, current, null, value);
  384. } else if (current == null || current === "" || !parent.firstChild) {
  385. parent.appendChild(value);
  386. } else parent.replaceChild(value, parent.firstChild);
  387. current = value;
  388. } else console.warn(`Unrecognized value. Skipped inserting`, value);
  389. return current;
  390. }
  391. function normalizeIncomingArray(normalized, array, unwrap) {
  392. let dynamic = false;
  393. for (let i = 0, len = array.length; i < len; i++) {
  394. let item = array[i],
  395. t;
  396. if (item instanceof Node) {
  397. normalized.push(item);
  398. } else if (item == null || item === true || item === false) ; else if (Array.isArray(item)) {
  399. dynamic = normalizeIncomingArray(normalized, item) || dynamic;
  400. } else if ((t = typeof item) === "string") {
  401. normalized.push(document.createTextNode(item));
  402. } else if (t === "function") {
  403. if (unwrap) {
  404. while (typeof item === "function") item = item();
  405. dynamic = normalizeIncomingArray(normalized, Array.isArray(item) ? item : [item]) || dynamic;
  406. } else {
  407. normalized.push(item);
  408. dynamic = true;
  409. }
  410. } else normalized.push(document.createTextNode(item.toString()));
  411. }
  412. return dynamic;
  413. }
  414. function appendNodes(parent, array, marker) {
  415. for (let i = 0, len = array.length; i < len; i++) parent.insertBefore(array[i], marker);
  416. }
  417. function cleanChildren(parent, current, marker, replacement) {
  418. if (marker === undefined) return parent.textContent = "";
  419. const node = replacement || document.createTextNode("");
  420. if (current.length) {
  421. let inserted = false;
  422. for (let i = current.length - 1; i >= 0; i--) {
  423. const el = current[i];
  424. if (node !== el) {
  425. const isParent = el.parentNode === parent;
  426. if (!inserted && !i) isParent ? parent.replaceChild(node, el) : parent.insertBefore(node, marker);else isParent && parent.removeChild(el);
  427. } else inserted = true;
  428. }
  429. } else parent.insertBefore(node, marker);
  430. return [node];
  431. }
  432. function getHydrationKey() {
  433. const hydrate = sharedConfig.context;
  434. return `${hydrate.id}${hydrate.count++}`;
  435. }
  436. function renderToString(fn, options) {}
  437. function renderToStringAsync(fn, options) {}
  438. function renderToNodeStream(fn, options) {}
  439. function renderToWebStream(fn, options) {}
  440. function ssr(template, ...nodes) {}
  441. function resolveSSRNode(node) {}
  442. function ssrClassList(value) {}
  443. function ssrStyle(value) {}
  444. function ssrSpread(accessor) {}
  445. function ssrBoolean(key, value) {}
  446. function escape(html) {}
  447. const isServer = false;
  448. const SVG_NAMESPACE = "http://www.w3.org/2000/svg";
  449. function createElement(tagName, isSVG = false) {
  450. return isSVG ? document.createElementNS(SVG_NAMESPACE, tagName) : document.createElement(tagName);
  451. }
  452. function Portal(props) {
  453. const {
  454. useShadow
  455. } = props,
  456. marker = document.createTextNode(""),
  457. mount = props.mount || document.body;
  458. function renderPortal() {
  459. if (sharedConfig.context) {
  460. const [s, set] = createSignal(false);
  461. queueMicrotask(() => set(true));
  462. return () => s() && props.children;
  463. } else return () => props.children;
  464. }
  465. if (mount instanceof HTMLHeadElement) {
  466. const [clean, setClean] = createSignal(false);
  467. const cleanup = () => setClean(true);
  468. createRoot(dispose => insert(mount, () => !clean() ? renderPortal()() : dispose(), null));
  469. onCleanup(() => {
  470. if (sharedConfig.context) queueMicrotask(cleanup);else cleanup();
  471. });
  472. } else {
  473. const container = createElement(props.isSVG ? "g" : "div", props.isSVG),
  474. renderRoot = useShadow && container.attachShadow ? container.attachShadow({
  475. mode: "open"
  476. }) : container;
  477. Object.defineProperty(container, "host", {
  478. get() {
  479. return marker.parentNode;
  480. }
  481. });
  482. insert(renderRoot, renderPortal());
  483. mount.appendChild(container);
  484. props.ref && props.ref(container);
  485. onCleanup(() => mount.removeChild(container));
  486. }
  487. return marker;
  488. }
  489. function Dynamic(props) {
  490. const [p, others] = splitProps(props, ["component"]);
  491. return createMemo(() => {
  492. const component = p.component;
  493. switch (typeof component) {
  494. case "function":
  495. return untrack(() => component(others));
  496. case "string":
  497. const isSvg = SVGElements.has(component);
  498. const el = createElement(component, isSvg);
  499. spread(el, others, isSvg);
  500. return el;
  501. }
  502. });
  503. }
  504. export { Aliases, ChildProperties, DelegatedEvents, Dynamic, Portal, Properties, SVGElements, SVGNamespace, addEventListener, assign, classList, clearDelegatedEvents, delegateEvents, dynamicProperty, escape, gatherHydratable, getHydrationKey, getNextElement, getNextMarker, hydrate, insert, isServer, memo, render, renderToNodeStream, renderToString, renderToStringAsync, renderToWebStream, resolveSSRNode, runHydrationEvents, setAttribute, setAttributeNS, spread, ssr, ssrBoolean, ssrClassList, ssrSpread, ssrStyle, style, template };