vue-jsx-vapor
Version:
Convert Vue JSX to Vapor
113 lines (111 loc) • 3.47 kB
JavaScript
import * as Vue from "vue";
import { EffectScope, VaporFragment, insert, isFragment, isVaporComponent, proxyRefs, remove, renderEffect, shallowRef as useRef, toRefs, useAttrs } from "vue";
//#region src/core/runtime.ts
function getCurrentInstance() {
return Vue.currentInstance || Vue.getCurrentInstance();
}
/**
* Returns the props of the current component instance.
*
* @example
* ```tsx
* import { useProps } from 'vue-jsx-vapor'
*
* defineComponent(({ foo = '' })=>{
* const props = useProps() // { foo: '' }
* })
* ```
*/
function useProps() {
const i = getCurrentInstance();
return i.props;
}
/**
* Returns the merged props and attrs of the current component.\
* Equivalent to `useProps()` + `useAttrs()`.
*
* @example
* ```tsx
* import { useFullProps } from 'vue-jsx-vapor'
*
* defineComponent((props) => {
* const fullProps = useFullProps() // = useAttrs() + useProps()
* })
*/
function useFullProps() {
return proxyRefs({
...toRefs(useProps()),
...toRefs(useAttrs())
});
}
function createFragment(nodes, anchor = document.createTextNode("")) {
const frag = new VaporFragment(nodes);
frag.anchor = anchor;
return frag;
}
function normalizeNode(node, anchor) {
if (node instanceof Node || isFragment(node)) {
anchor && (anchor.textContent = "");
return node;
} else if (isVaporComponent(node)) {
anchor && (anchor.textContent = "");
return createFragment(node, anchor);
} else if (Array.isArray(node)) {
anchor && (anchor.textContent = "");
return createFragment(node.map((i) => normalizeNode(i)), anchor);
} else {
const result = node == null || typeof node === "boolean" ? "" : String(node);
if (anchor) {
anchor.textContent = result;
return anchor;
} else return document.createTextNode(result);
}
}
function resolveValue(current, value, _anchor) {
const node = normalizeNode(value, _anchor);
if (current) {
if (isFragment(current)) {
const { anchor } = current;
if (anchor && anchor.parentNode) {
remove(current.nodes, anchor.parentNode);
insert(node, anchor.parentNode, anchor);
!_anchor && anchor.parentNode.removeChild(anchor);
}
} else if (current instanceof Node) {
if (isFragment(node) && current.parentNode) {
insert(node, current.parentNode, current);
current.parentNode.removeChild(current);
} else if (node instanceof Node) {
if (current.nodeType === 3 && node.nodeType === 3) {
current.textContent = node.textContent;
return current;
} else if (current.parentNode) current.parentNode.replaceChild(node, current);
}
}
}
return node;
}
function resolveValues(values = [], _anchor) {
const nodes = [];
const frag = createFragment(nodes, _anchor);
const scopes = [];
for (const [index, value] of values.entries()) {
const anchor = index === values.length - 1 ? _anchor : void 0;
if (typeof value === "function") renderEffect(() => {
if (scopes[index]) scopes[index].stop();
scopes[index] = new EffectScope();
nodes[index] = scopes[index].run(() => resolveValue(nodes[index], value(), anchor));
});
else nodes[index] = resolveValue(nodes[index], value, anchor);
}
return frag;
}
function setNodes(anchor, ...values) {
const resolvedValues = resolveValues(values, anchor);
anchor.parentNode && insert(resolvedValues, anchor.parentNode, anchor);
}
function createNodes(...values) {
return resolveValues(values);
}
//#endregion
export { createNodes, getCurrentInstance, setNodes, useFullProps, useProps, useRef };