Buckets:
| // src/jsx/dom/render.ts | |
| import { toArray } from "../children.js"; | |
| import { | |
| DOM_ERROR_HANDLER, | |
| DOM_INTERNAL_TAG, | |
| DOM_MEMO, | |
| DOM_RENDERER, | |
| DOM_STASH | |
| } from "../constants.js"; | |
| import { globalContexts as globalJSXContexts, useContext } from "../context.js"; | |
| import { STASH_EFFECT } from "../hooks/index.js"; | |
| import { normalizeIntrinsicElementKey, styleObjectForEach } from "../utils.js"; | |
| import { createContext } from "./context.js"; | |
| var HONO_PORTAL_ELEMENT = "_hp"; | |
| var eventAliasMap = { | |
| Change: "Input", | |
| DoubleClick: "DblClick" | |
| }; | |
| var nameSpaceMap = { | |
| svg: "2000/svg", | |
| math: "1998/Math/MathML" | |
| }; | |
| var buildDataStack = []; | |
| var refCleanupMap = /* @__PURE__ */ new WeakMap(); | |
| var nameSpaceContext = void 0; | |
| var getNameSpaceContext = () => nameSpaceContext; | |
| var isNodeString = (node) => "t" in node; | |
| var eventCache = { | |
| // pre-define events that are used very frequently | |
| onClick: ["click", false] | |
| }; | |
| var getEventSpec = (key) => { | |
| if (!key.startsWith("on")) { | |
| return void 0; | |
| } | |
| if (eventCache[key]) { | |
| return eventCache[key]; | |
| } | |
| const match = key.match(/^on([A-Z][a-zA-Z]+?(?:PointerCapture)?)(Capture)?$/); | |
| if (match) { | |
| const [, eventName, capture] = match; | |
| return eventCache[key] = [(eventAliasMap[eventName] || eventName).toLowerCase(), !!capture]; | |
| } | |
| return void 0; | |
| }; | |
| var toAttributeName = (element, key) => nameSpaceContext && element instanceof SVGElement && /[A-Z]/.test(key) && (key in element.style || // Presentation attributes are findable in style object. "clip-path", "font-size", "stroke-width", etc. | |
| key.match(/^(?:o|pai|str|u|ve)/)) ? key.replace(/([A-Z])/g, "-$1").toLowerCase() : key; | |
| var applyProps = (container, attributes, oldAttributes) => { | |
| attributes ||= {}; | |
| for (let key in attributes) { | |
| const value = attributes[key]; | |
| if (key !== "children" && (!oldAttributes || oldAttributes[key] !== value)) { | |
| key = normalizeIntrinsicElementKey(key); | |
| const eventSpec = getEventSpec(key); | |
| if (eventSpec) { | |
| if (oldAttributes?.[key] !== value) { | |
| if (oldAttributes) { | |
| container.removeEventListener(eventSpec[0], oldAttributes[key], eventSpec[1]); | |
| } | |
| if (value != null) { | |
| if (typeof value !== "function") { | |
| throw new Error(`Event handler for "${key}" is not a function`); | |
| } | |
| container.addEventListener(eventSpec[0], value, eventSpec[1]); | |
| } | |
| } | |
| } else if (key === "dangerouslySetInnerHTML" && value) { | |
| container.innerHTML = value.__html; | |
| } else if (key === "ref") { | |
| let cleanup; | |
| if (typeof value === "function") { | |
| cleanup = value(container) || (() => value(null)); | |
| } else if (value && "current" in value) { | |
| value.current = container; | |
| cleanup = () => value.current = null; | |
| } | |
| refCleanupMap.set(container, cleanup); | |
| } else if (key === "style") { | |
| const style = container.style; | |
| if (typeof value === "string") { | |
| style.cssText = value; | |
| } else { | |
| style.cssText = ""; | |
| if (value != null) { | |
| styleObjectForEach(value, style.setProperty.bind(style)); | |
| } | |
| } | |
| } else { | |
| if (key === "value") { | |
| const nodeName = container.nodeName; | |
| if (nodeName === "INPUT" || nodeName === "TEXTAREA" || nodeName === "SELECT") { | |
| ; | |
| container.value = value === null || value === void 0 || value === false ? null : value; | |
| if (nodeName === "TEXTAREA") { | |
| container.textContent = value; | |
| continue; | |
| } else if (nodeName === "SELECT") { | |
| if (container.selectedIndex === -1) { | |
| ; | |
| container.selectedIndex = 0; | |
| } | |
| continue; | |
| } | |
| } | |
| } else if (key === "checked" && container.nodeName === "INPUT" || key === "selected" && container.nodeName === "OPTION") { | |
| ; | |
| container[key] = value; | |
| } | |
| const k = toAttributeName(container, key); | |
| if (value === null || value === void 0 || value === false) { | |
| container.removeAttribute(k); | |
| } else if (value === true) { | |
| container.setAttribute(k, ""); | |
| } else if (typeof value === "string" || typeof value === "number") { | |
| container.setAttribute(k, value); | |
| } else { | |
| container.setAttribute(k, value.toString()); | |
| } | |
| } | |
| } | |
| } | |
| if (oldAttributes) { | |
| for (let key in oldAttributes) { | |
| const value = oldAttributes[key]; | |
| if (key !== "children" && !(key in attributes)) { | |
| key = normalizeIntrinsicElementKey(key); | |
| const eventSpec = getEventSpec(key); | |
| if (eventSpec) { | |
| container.removeEventListener(eventSpec[0], value, eventSpec[1]); | |
| } else if (key === "ref") { | |
| refCleanupMap.get(container)?.(); | |
| } else { | |
| container.removeAttribute(toAttributeName(container, key)); | |
| } | |
| } | |
| } | |
| } | |
| }; | |
| var invokeTag = (context, node) => { | |
| node[DOM_STASH][0] = 0; | |
| buildDataStack.push([context, node]); | |
| const func = node.tag[DOM_RENDERER] || node.tag; | |
| const props = func.defaultProps ? { | |
| // eslint-disable-next-line @typescript-eslint/no-explicit-any | |
| ...func.defaultProps, | |
| ...node.props | |
| } : node.props; | |
| try { | |
| return [func.call(null, props)]; | |
| } finally { | |
| buildDataStack.pop(); | |
| } | |
| }; | |
| var getNextChildren = (node, container, nextChildren, childrenToRemove, callbacks) => { | |
| if (node.vR?.length) { | |
| childrenToRemove.push(...node.vR); | |
| delete node.vR; | |
| } | |
| if (typeof node.tag === "function") { | |
| node[DOM_STASH][1][STASH_EFFECT]?.forEach((data) => callbacks.push(data)); | |
| } | |
| node.vC.forEach((child) => { | |
| if (isNodeString(child)) { | |
| nextChildren.push(child); | |
| } else { | |
| if (typeof child.tag === "function" || child.tag === "") { | |
| child.c = container; | |
| const currentNextChildrenIndex = nextChildren.length; | |
| getNextChildren(child, container, nextChildren, childrenToRemove, callbacks); | |
| if (child.s) { | |
| for (let i = currentNextChildrenIndex; i < nextChildren.length; i++) { | |
| nextChildren[i].s = true; | |
| } | |
| child.s = false; | |
| } | |
| } else { | |
| nextChildren.push(child); | |
| if (child.vR?.length) { | |
| childrenToRemove.push(...child.vR); | |
| delete child.vR; | |
| } | |
| } | |
| } | |
| }); | |
| }; | |
| var findInsertBefore = (node) => { | |
| for (; ; node = node.tag === HONO_PORTAL_ELEMENT || !node.vC || !node.pP ? node.nN : node.vC[0]) { | |
| if (!node) { | |
| return null; | |
| } | |
| if (node.tag !== HONO_PORTAL_ELEMENT && node.e) { | |
| return node.e; | |
| } | |
| } | |
| }; | |
| var removeNode = (node) => { | |
| if (!isNodeString(node)) { | |
| node[DOM_STASH]?.[1][STASH_EFFECT]?.forEach((data) => data[2]?.()); | |
| refCleanupMap.get(node.e)?.(); | |
| if (node.p === 2) { | |
| node.vC?.forEach((n) => n.p = 2); | |
| } | |
| node.vC?.forEach(removeNode); | |
| } | |
| if (!node.p) { | |
| node.e?.remove(); | |
| delete node.e; | |
| } | |
| if (typeof node.tag === "function") { | |
| updateMap.delete(node); | |
| fallbackUpdateFnArrayMap.delete(node); | |
| delete node[DOM_STASH][3]; | |
| node.a = true; | |
| } | |
| }; | |
| var apply = (node, container, isNew) => { | |
| node.c = container; | |
| applyNodeObject(node, container, isNew); | |
| }; | |
| var findChildNodeIndex = (childNodes, child) => { | |
| if (!child) { | |
| return; | |
| } | |
| for (let i = 0, len = childNodes.length; i < len; i++) { | |
| if (childNodes[i] === child) { | |
| return i; | |
| } | |
| } | |
| return; | |
| }; | |
| var cancelBuild = /* @__PURE__ */ Symbol(); | |
| var applyNodeObject = (node, container, isNew) => { | |
| const next = []; | |
| const remove = []; | |
| const callbacks = []; | |
| getNextChildren(node, container, next, remove, callbacks); | |
| remove.forEach(removeNode); | |
| const childNodes = isNew ? void 0 : container.childNodes; | |
| let offset; | |
| let insertBeforeNode = null; | |
| if (isNew) { | |
| offset = -1; | |
| } else if (!childNodes.length) { | |
| offset = 0; | |
| } else { | |
| const offsetByNextNode = findChildNodeIndex(childNodes, findInsertBefore(node.nN)); | |
| if (offsetByNextNode !== void 0) { | |
| insertBeforeNode = childNodes[offsetByNextNode]; | |
| offset = offsetByNextNode; | |
| } else { | |
| offset = findChildNodeIndex(childNodes, next.find((n) => n.tag !== HONO_PORTAL_ELEMENT && n.e)?.e) ?? -1; | |
| } | |
| if (offset === -1) { | |
| isNew = true; | |
| } | |
| } | |
| for (let i = 0, len = next.length; i < len; i++, offset++) { | |
| const child = next[i]; | |
| let el; | |
| if (child.s && child.e) { | |
| el = child.e; | |
| child.s = false; | |
| } else { | |
| const isNewLocal = isNew || !child.e; | |
| if (isNodeString(child)) { | |
| if (child.e && child.d) { | |
| child.e.textContent = child.t; | |
| } | |
| child.d = false; | |
| el = child.e ||= document.createTextNode(child.t); | |
| } else { | |
| el = child.e ||= child.n ? document.createElementNS(child.n, child.tag) : document.createElement(child.tag); | |
| applyProps(el, child.props, child.pP); | |
| applyNodeObject(child, el, isNewLocal); | |
| } | |
| } | |
| if (child.tag === HONO_PORTAL_ELEMENT) { | |
| offset--; | |
| } else if (isNew) { | |
| if (!el.parentNode) { | |
| container.appendChild(el); | |
| } | |
| } else if (childNodes[offset] !== el && childNodes[offset - 1] !== el) { | |
| if (childNodes[offset + 1] === el) { | |
| container.appendChild(childNodes[offset]); | |
| } else { | |
| container.insertBefore(el, insertBeforeNode || childNodes[offset] || null); | |
| } | |
| } | |
| } | |
| if (node.pP) { | |
| delete node.pP; | |
| } | |
| if (callbacks.length) { | |
| const useLayoutEffectCbs = []; | |
| const useEffectCbs = []; | |
| callbacks.forEach(([, useLayoutEffectCb, , useEffectCb, useInsertionEffectCb]) => { | |
| if (useLayoutEffectCb) { | |
| useLayoutEffectCbs.push(useLayoutEffectCb); | |
| } | |
| if (useEffectCb) { | |
| useEffectCbs.push(useEffectCb); | |
| } | |
| useInsertionEffectCb?.(); | |
| }); | |
| useLayoutEffectCbs.forEach((cb) => cb()); | |
| if (useEffectCbs.length) { | |
| requestAnimationFrame(() => { | |
| useEffectCbs.forEach((cb) => cb()); | |
| }); | |
| } | |
| } | |
| }; | |
| var isSameContext = (oldContexts, newContexts) => !!(oldContexts && oldContexts.length === newContexts.length && oldContexts.every((ctx, i) => ctx[1] === newContexts[i][1])); | |
| var fallbackUpdateFnArrayMap = /* @__PURE__ */ new WeakMap(); | |
| var build = (context, node, children) => { | |
| const buildWithPreviousChildren = !children && node.pC; | |
| if (children) { | |
| node.pC ||= node.vC; | |
| } | |
| let foundErrorHandler; | |
| try { | |
| children ||= typeof node.tag == "function" ? invokeTag(context, node) : toArray(node.props.children); | |
| if (children[0]?.tag === "" && children[0][DOM_ERROR_HANDLER]) { | |
| foundErrorHandler = children[0][DOM_ERROR_HANDLER]; | |
| context[5].push([context, foundErrorHandler, node]); | |
| } | |
| const oldVChildren = buildWithPreviousChildren ? [...node.pC] : node.vC ? [...node.vC] : void 0; | |
| const vChildren = []; | |
| let prevNode; | |
| for (let i = 0; i < children.length; i++) { | |
| if (Array.isArray(children[i])) { | |
| children.splice(i, 1, ...children[i].flat()); | |
| } | |
| let child = buildNode(children[i]); | |
| if (child) { | |
| if (typeof child.tag === "function" && // eslint-disable-next-line @typescript-eslint/no-explicit-any | |
| !child.tag[DOM_INTERNAL_TAG]) { | |
| if (globalJSXContexts.length > 0) { | |
| child[DOM_STASH][2] = globalJSXContexts.map((c) => [c, c.values.at(-1)]); | |
| } | |
| if (context[5]?.length) { | |
| child[DOM_STASH][3] = context[5].at(-1); | |
| } | |
| } | |
| let oldChild; | |
| if (oldVChildren && oldVChildren.length) { | |
| const i2 = oldVChildren.findIndex( | |
| isNodeString(child) ? (c) => isNodeString(c) : child.key !== void 0 ? (c) => c.key === child.key && c.tag === child.tag : (c) => c.tag === child.tag | |
| ); | |
| if (i2 !== -1) { | |
| oldChild = oldVChildren[i2]; | |
| oldVChildren.splice(i2, 1); | |
| } | |
| } | |
| if (oldChild) { | |
| if (isNodeString(child)) { | |
| if (oldChild.t !== child.t) { | |
| ; | |
| oldChild.t = child.t; | |
| oldChild.d = true; | |
| } | |
| child = oldChild; | |
| } else { | |
| const pP = oldChild.pP = oldChild.props; | |
| oldChild.props = child.props; | |
| oldChild.f ||= child.f || node.f; | |
| if (typeof child.tag === "function") { | |
| const oldContexts = oldChild[DOM_STASH][2]; | |
| oldChild[DOM_STASH][2] = child[DOM_STASH][2] || []; | |
| oldChild[DOM_STASH][3] = child[DOM_STASH][3]; | |
| if (!oldChild.f && ((oldChild.o || oldChild) === child.o || // The code generated by the react compiler is memoized under this condition. | |
| oldChild.tag[DOM_MEMO]?.(pP, oldChild.props)) && // The `memo` function is memoized under this condition. | |
| isSameContext(oldContexts, oldChild[DOM_STASH][2])) { | |
| oldChild.s = true; | |
| } | |
| } | |
| child = oldChild; | |
| } | |
| } else if (!isNodeString(child) && nameSpaceContext) { | |
| const ns = useContext(nameSpaceContext); | |
| if (ns) { | |
| child.n = ns; | |
| } | |
| } | |
| if (!isNodeString(child) && !child.s) { | |
| build(context, child); | |
| delete child.f; | |
| } | |
| vChildren.push(child); | |
| if (prevNode && !prevNode.s && !child.s) { | |
| for (let p = prevNode; p && !isNodeString(p); p = p.vC?.at(-1)) { | |
| p.nN = child; | |
| } | |
| } | |
| prevNode = child; | |
| } | |
| } | |
| node.vR = buildWithPreviousChildren ? [...node.vC, ...oldVChildren || []] : oldVChildren || []; | |
| node.vC = vChildren; | |
| if (buildWithPreviousChildren) { | |
| delete node.pC; | |
| } | |
| } catch (e) { | |
| node.f = true; | |
| if (e === cancelBuild) { | |
| if (foundErrorHandler) { | |
| return; | |
| } else { | |
| throw e; | |
| } | |
| } | |
| const [errorHandlerContext, errorHandler, errorHandlerNode] = node[DOM_STASH]?.[3] || []; | |
| if (errorHandler) { | |
| const fallbackUpdateFn = () => update([0, false, context[2]], errorHandlerNode); | |
| const fallbackUpdateFnArray = fallbackUpdateFnArrayMap.get(errorHandlerNode) || []; | |
| fallbackUpdateFnArray.push(fallbackUpdateFn); | |
| fallbackUpdateFnArrayMap.set(errorHandlerNode, fallbackUpdateFnArray); | |
| const fallback = errorHandler(e, () => { | |
| const fnArray = fallbackUpdateFnArrayMap.get(errorHandlerNode); | |
| if (fnArray) { | |
| const i = fnArray.indexOf(fallbackUpdateFn); | |
| if (i !== -1) { | |
| fnArray.splice(i, 1); | |
| return fallbackUpdateFn(); | |
| } | |
| } | |
| }); | |
| if (fallback) { | |
| if (context[0] === 1) { | |
| context[1] = true; | |
| } else { | |
| build(context, errorHandlerNode, [fallback]); | |
| if ((errorHandler.length === 1 || context !== errorHandlerContext) && errorHandlerNode.c) { | |
| apply(errorHandlerNode, errorHandlerNode.c, false); | |
| return; | |
| } | |
| } | |
| throw cancelBuild; | |
| } | |
| } | |
| throw e; | |
| } finally { | |
| if (foundErrorHandler) { | |
| context[5].pop(); | |
| } | |
| } | |
| }; | |
| var buildNode = (node) => { | |
| if (node === void 0 || node === null || typeof node === "boolean") { | |
| return void 0; | |
| } else if (typeof node === "string" || typeof node === "number") { | |
| return { t: node.toString(), d: true }; | |
| } else { | |
| if ("vR" in node) { | |
| node = { | |
| tag: node.tag, | |
| props: node.props, | |
| key: node.key, | |
| f: node.f, | |
| type: node.tag, | |
| ref: node.props.ref, | |
| o: node.o || node | |
| // eslint-disable-next-line @typescript-eslint/no-explicit-any | |
| }; | |
| } | |
| if (typeof node.tag === "function") { | |
| ; | |
| node[DOM_STASH] = [0, []]; | |
| } else { | |
| const ns = nameSpaceMap[node.tag]; | |
| if (ns) { | |
| nameSpaceContext ||= createContext(""); | |
| node.props.children = [ | |
| { | |
| tag: nameSpaceContext, | |
| props: { | |
| value: node.n = `http://www.w3.org/${ns}`, | |
| children: node.props.children | |
| } | |
| } | |
| ]; | |
| } | |
| } | |
| return node; | |
| } | |
| }; | |
| var replaceContainer = (node, from, to) => { | |
| if (node.c === from) { | |
| node.c = to; | |
| node.vC.forEach((child) => replaceContainer(child, from, to)); | |
| } | |
| }; | |
| var updateSync = (context, node) => { | |
| node[DOM_STASH][2]?.forEach(([c, v]) => { | |
| c.values.push(v); | |
| }); | |
| try { | |
| build(context, node, void 0); | |
| } catch { | |
| return; | |
| } | |
| if (node.a) { | |
| delete node.a; | |
| return; | |
| } | |
| node[DOM_STASH][2]?.forEach(([c]) => { | |
| c.values.pop(); | |
| }); | |
| if (context[0] !== 1 || !context[1]) { | |
| apply(node, node.c, false); | |
| } | |
| }; | |
| var updateMap = /* @__PURE__ */ new WeakMap(); | |
| var currentUpdateSets = []; | |
| var update = async (context, node) => { | |
| context[5] ||= []; | |
| const existing = updateMap.get(node); | |
| if (existing) { | |
| existing[0](void 0); | |
| } | |
| let resolve; | |
| const promise = new Promise((r) => resolve = r); | |
| updateMap.set(node, [ | |
| resolve, | |
| () => { | |
| if (context[2]) { | |
| context[2](context, node, (context2) => { | |
| updateSync(context2, node); | |
| }).then(() => resolve(node)); | |
| } else { | |
| updateSync(context, node); | |
| resolve(node); | |
| } | |
| } | |
| ]); | |
| if (currentUpdateSets.length) { | |
| ; | |
| currentUpdateSets.at(-1).add(node); | |
| } else { | |
| await Promise.resolve(); | |
| const latest = updateMap.get(node); | |
| if (latest) { | |
| updateMap.delete(node); | |
| latest[1](); | |
| } | |
| } | |
| return promise; | |
| }; | |
| var renderNode = (node, container) => { | |
| const context = []; | |
| context[5] = []; | |
| context[4] = true; | |
| build(context, node, void 0); | |
| context[4] = false; | |
| const fragment = document.createDocumentFragment(); | |
| apply(node, fragment, true); | |
| replaceContainer(node, fragment, container); | |
| container.replaceChildren(fragment); | |
| }; | |
| var render = (jsxNode, container) => { | |
| renderNode(buildNode({ tag: "", props: { children: jsxNode } }), container); | |
| }; | |
| var flushSync = (callback) => { | |
| const set = /* @__PURE__ */ new Set(); | |
| currentUpdateSets.push(set); | |
| callback(); | |
| set.forEach((node) => { | |
| const latest = updateMap.get(node); | |
| if (latest) { | |
| updateMap.delete(node); | |
| latest[1](); | |
| } | |
| }); | |
| currentUpdateSets.pop(); | |
| }; | |
| var createPortal = (children, container, key) => ({ | |
| tag: HONO_PORTAL_ELEMENT, | |
| props: { | |
| children | |
| }, | |
| key, | |
| e: container, | |
| p: 1 | |
| // eslint-disable-next-line @typescript-eslint/no-explicit-any | |
| }); | |
| export { | |
| build, | |
| buildDataStack, | |
| buildNode, | |
| createPortal, | |
| flushSync, | |
| getNameSpaceContext, | |
| render, | |
| renderNode, | |
| update | |
| }; | |
Xet Storage Details
- Size:
- 18.8 kB
- Xet hash:
- cf7e19ce1a76919246747b6dc437ff4f15b29a8cd9e424572958856f15bfc57c
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.