jsx-dom
Version:
JSX to document.createElement.
521 lines (508 loc) • 13 kB
JavaScript
/* eslint-disable */
const keys = Object.keys;
function identity(value) {
return value;
}
function isBoolean(val) {
return typeof val === "boolean";
}
function isElement(val) {
return val && typeof val.nodeType === "number";
}
function isString(val) {
return typeof val === "string";
}
function isNumber(val) {
return typeof val === "number";
}
function isObject(val) {
return typeof val === "object" ? val !== null : isFunction(val);
}
function isFunction(val) {
return typeof val === "function";
}
function isComponentClass(Component) {
return !!(Component && Component.isComponent);
}
function isArrayLike(obj) {
return (
isObject(obj) &&
typeof obj.length === "number" &&
typeof obj.nodeType !== "number"
);
}
function forEach(value, fn) {
if (!value) return;
for (const key of keys(value)) {
fn(value[key], key);
}
}
function createRef() {
return Object.seal({
current: null,
});
}
function isRef(maybeRef) {
return isObject(maybeRef) && "current" in maybeRef;
}
const jsxDomType = Symbol.for("jsx-dom:type");
var JsxDomType = /*#__PURE__*/ (function (JsxDomType) {
JsxDomType["ShadowRoot"] = "ShadowRoot";
return JsxDomType;
})(JsxDomType || {});
function ShadowRoot(_ref) {
let { children, ref, ...attr } = _ref;
return {
[jsxDomType]: JsxDomType.ShadowRoot,
ref,
attr,
children,
};
}
function isShadowRoot(el) {
return el != null && el[jsxDomType] === JsxDomType.ShadowRoot;
}
const SVGNamespace = "http://www.w3.org/2000/svg";
// https://facebook.github.io/react/docs/jsx-in-depth.html#booleans-null-and-undefined-are-ignored
// Emulate JSX Expression logic to ignore certain type of children or className.
function isVisibleChild(value) {
return !isBoolean(value) && value != null;
}
/**
* Convert a `value` to a className string.
* `value` can be a string, an array or a `Dictionary<boolean>`.
*/
function className(value) {
if (Array.isArray(value)) {
return value.map(className).filter(Boolean).join(" ");
} else if (isObject(value)) {
if (Symbol.iterator in value) {
return className(Array.from(value));
}
return keys(value)
.filter((k) => value[k])
.join(" ");
} else if (isVisibleChild(value)) {
return "" + value;
} else {
return "";
}
}
function createFactory(tag) {
return createElement.bind(null, tag);
}
function Fragment(attr) {
const fragment = document.createDocumentFragment();
appendChild(attr.children, fragment);
return fragment;
}
class Component {
static isComponent = true;
constructor(props) {
this.props = props;
}
render() {
return null;
}
}
function initComponentClass(Class, attr, children) {
attr = {
...attr,
children,
};
const instance = new Class(attr);
const node = instance.render();
if ("ref" in attr) {
attachRef(attr.ref, instance);
}
return node;
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
function jsx(tag, _ref) {
let { children, ...attr } = _ref;
let node;
if (isString(tag)) {
node = attr.namespaceURI
? document.createElementNS(attr.namespaceURI, tag)
: document.createElement(tag);
attributes(attr, node);
appendChild(children, node);
// Select `option` elements in `select`
if (node instanceof window.HTMLSelectElement && attr.value != null) {
if (attr.multiple === true && Array.isArray(attr.value)) {
const values = attr.value.map((value) => String(value));
node
.querySelectorAll("option")
.forEach(
(option) => (option.selected = values.includes(option.value)),
);
} else {
node.value = attr.value;
}
}
attachRef(attr.ref, node);
} else if (isFunction(tag)) {
// Custom elements.
if (isObject(tag.defaultProps)) {
attr = {
...tag.defaultProps,
...attr,
};
}
node = isComponentClass(tag)
? initComponentClass(tag, attr, children)
: tag({
...attr,
children,
});
} else {
throw new TypeError(`Invalid JSX element type: ${tag}`);
}
return node;
}
function createElement(tag, attr) {
for (
var _len = arguments.length,
children = new Array(_len > 2 ? _len - 2 : 0),
_key2 = 2;
_key2 < _len;
_key2++
) {
children[_key2 - 2] = arguments[_key2];
}
if (isString(attr) || Array.isArray(attr)) {
children.unshift(attr);
attr = {};
}
attr = attr || {};
if (attr.children != null && !children.length) {
({ children, ...attr } = attr);
}
return jsx(
tag,
{
...attr,
children,
},
attr.key,
);
}
function attachRef(ref, node) {
if (isRef(ref)) {
ref.current = node;
} else if (isFunction(ref)) {
ref(node);
}
}
function appendChild(child, node) {
if (isArrayLike(child)) {
appendChildren(child, node);
} else if (isString(child) || isNumber(child)) {
appendChildToNode(document.createTextNode(child), node);
} else if (child === null) {
appendChildToNode(document.createComment(""), node);
} else if (isElement(child)) {
appendChildToNode(child, node);
} else if (isShadowRoot(child)) {
const shadowRoot = node.attachShadow(child.attr);
appendChild(child.children, shadowRoot);
attachRef(child.ref, shadowRoot);
}
}
function appendChildren(children, node) {
for (const child of [...children]) {
appendChild(child, node);
}
return node;
}
function appendChildToNode(child, node) {
if (node instanceof window.HTMLTemplateElement) {
node.content.appendChild(child);
} else {
node.appendChild(child);
}
}
function style(node, value) {
if (value == null || value === false);
else if (Array.isArray(value)) {
value.forEach((v) => style(node, v));
} else if (isString(value)) {
node.setAttribute("style", value);
} else if (isObject(value)) {
forEach(value, (val, key) => {
if (key.indexOf("-") === 0) {
// CSS custom properties (variables) start with `-` (e.g. `--my-variable`)
// and must be assigned via `setProperty`.
node.style.setProperty(key, val);
} else {
node.style[key] = val;
}
});
}
}
function attribute(key, value, node) {
switch (key) {
case "htmlFor":
attr(node, "for", value);
return;
case "dataset":
forEach(value, (dataValue, dataKey) => {
if (dataValue != null) {
node.dataset[dataKey] = dataValue;
}
});
return;
case "innerHTML":
case "innerText":
case "textContent":
if (isVisibleChild(value)) {
node[key] = value;
}
return;
case "dangerouslySetInnerHTML":
if (isObject(value)) {
node.innerHTML = value["__html"];
}
return;
case "value":
if (value == null || node instanceof window.HTMLSelectElement) {
// skip nullish values
// for `<select>` apply value after appending `<option>` elements
return;
} else if (node instanceof window.HTMLTextAreaElement) {
node.value = value;
return;
}
// use attribute for other elements
break;
case "spellCheck":
node.spellcheck = value;
return;
case "class":
case "className":
if (isFunction(value)) {
value(node);
} else {
attr(node, "class", className(value));
}
return;
case "ref":
case "namespaceURI":
return;
case "style":
style(node, value);
return;
case "on":
case "onCapture":
forEach(value, (eventHandler, eventName) => {
node.addEventListener(eventName, eventHandler, key === "onCapture");
});
return;
// fallthrough
}
if (isFunction(value)) {
if (key[0] === "o" && key[1] === "n") {
let attribute = key.toLowerCase();
const useCapture = attribute.endsWith("capture");
if (attribute === "ondoubleclick") {
attribute = "ondblclick";
} else if (useCapture && attribute === "ondoubleclickcapture") {
attribute = "ondblclickcapture";
}
if (!useCapture && node[attribute] === null) {
// use property when possible PR #17
node[attribute] = value;
} else if (useCapture) {
node.addEventListener(
attribute.substring(2, attribute.length - 7),
value,
true,
);
} else {
let eventName;
if (attribute in window) {
// standard event
// the JSX attribute could have been "onMouseOver" and the
// member name "onmouseover" is on the window's prototype
// so let's add the listener "mouseover", which is all lowercased
const standardEventName = attribute.substring(2);
eventName = standardEventName;
} else {
// custom event
// the JSX attribute could have been "onMyCustomEvent"
// so let's trim off the "on" prefix and lowercase the first character
// and add the listener "myCustomEvent"
// except for the first character, we keep the event name case
const customEventName = attribute[2] + key.slice(3);
eventName = customEventName;
}
node.addEventListener(eventName, value);
}
}
} else if (isObject(value)) {
node[key] = value;
} else if (value === true) {
attr(node, key, "");
} else if (value !== false && value != null) {
attr(node, key, value);
}
}
function attr(node, key, value) {
node.setAttribute(key, value);
}
function attributes(attr, node) {
for (const key of keys(attr)) {
attribute(key, attr[key], node);
}
return node;
}
function useText(initialValue) {
const text = new Text();
Object.defineProperty(text, "toString", {
value() {
return this.textContent;
},
});
function setText(value) {
text.textContent = value;
}
if (initialValue != null) {
setText(initialValue);
}
return [text, setText];
}
function useClassList(initialValue) {
const div = document.createElement("div");
if (initialValue != null) {
div.className = className(initialValue);
}
let list = div.classList;
function ClassList(value) {
value.setAttribute("class", list.value);
list = value.classList;
}
Object.defineProperties(
ClassList,
Object.getOwnPropertyDescriptors({
get size() {
return list.length;
},
get value() {
return list.value;
},
add() {
list.add(...arguments);
},
remove() {
list.remove(...arguments);
},
toggle(token, force) {
list.toggle(token, force);
},
contains(token) {
return list.contains(token);
},
}),
);
return ClassList;
}
function useMemo(factory) {
return factory();
}
function forwardRef(render) {
return (_ref) => {
let { ref, ...props } = _ref;
return render(props, ref ?? createRef());
};
}
function useImperativeHandle(ref, init) {
attachRef(ref, init());
}
const cache = /* @__PURE__ */ new Map();
const createStyledComponent = (name) =>
function (list) {
for (
var _len = arguments.length,
interpolations = new Array(_len > 1 ? _len - 1 : 0),
_key = 1;
_key < _len;
_key++
) {
interpolations[_key - 1] = arguments[_key];
}
return (_ref) => {
let { style, ...props } = _ref;
const lastIndex = list.length - 1;
const css =
list.slice(0, lastIndex).reduce((p, s, i) => {
const interpolation = interpolations[i];
const current =
typeof interpolation === "function"
? interpolation(props)
: interpolation;
return p + s + current;
}, "") + list[lastIndex];
return createElement(name, {
style: [css, style],
...props,
});
};
};
const baseStyled = (customComponent) => createStyledComponent(customComponent);
const styled = /* @__PURE__ */ new Proxy(baseStyled, {
get(_, name) {
return setIfAbsent(cache, name, () => createStyledComponent(name));
},
});
function setIfAbsent(map, key, getValue) {
if (map.has(key)) {
return map.get(key);
} else {
const value = getValue(key);
map.set(key, value);
return value;
}
}
var index = {
Component,
PureComponent: Component,
createElement,
Fragment,
ShadowRoot,
};
function preventDefault(event) {
event.preventDefault();
return event;
}
function stopPropagation(event) {
event.stopPropagation();
return event;
}
export {
Component,
Fragment,
Component as PureComponent,
SVGNamespace,
ShadowRoot,
Fragment as StrictMode,
className,
createElement,
createFactory,
createRef,
index as default,
forwardRef,
createElement as h,
isRef,
jsx,
jsx as jsxs,
identity as memo,
preventDefault,
stopPropagation,
styled,
identity as useCallback,
useClassList,
useImperativeHandle,
useMemo,
createRef as useRef,
useText,
};