jsx-dom
Version:
JSX to document.createElement.
697 lines (680 loc) • 17.2 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;
}
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found on
* https://github.com/facebook/react/blob/b87aabdfe1b7461e7331abb3601d9e6bb27544bc/LICENSE
*/
/**
* CSS properties which accept numbers but are not in units of "px".
*/
const isUnitlessNumber = {
animationIterationCount: 0,
borderImageOutset: 0,
borderImageSlice: 0,
borderImageWidth: 0,
boxFlex: 0,
boxFlexGroup: 0,
boxOrdinalGroup: 0,
columnCount: 0,
columns: 0,
flex: 0,
flexGrow: 0,
flexPositive: 0,
flexShrink: 0,
flexNegative: 0,
flexOrder: 0,
gridArea: 0,
gridRow: 0,
gridRowEnd: 0,
gridRowSpan: 0,
gridRowStart: 0,
gridColumn: 0,
gridColumnEnd: 0,
gridColumnSpan: 0,
gridColumnStart: 0,
fontWeight: 0,
lineClamp: 0,
lineHeight: 0,
opacity: 0,
order: 0,
orphans: 0,
tabSize: 0,
widows: 0,
zIndex: 0,
zoom: 0,
// SVG-related properties
fillOpacity: 0,
floodOpacity: 0,
stopOpacity: 0,
strokeDasharray: 0,
strokeDashoffset: 0,
strokeMiterlimit: 0,
strokeOpacity: 0,
strokeWidth: 0,
};
/**
* @param prefix vendor-specific prefix, eg: Webkit
* @param key style name, eg: transitionDuration
* @return style name prefixed with `prefix`, properly camelCased, eg:
* WebkitTransitionDuration
*/
function prefixKey(prefix, key) {
return prefix + key.charAt(0).toUpperCase() + key.substring(1);
}
/**
* Support style names that may come passed in prefixed by adding permutations
* of vendor prefixes.
*/
const prefixes = ["Webkit", "ms", "Moz", "O"];
// Using Object.keys here, or else the vanilla for-in loop makes IE8 go into an
// infinite loop, because it iterates over the newly added props too.
keys(isUnitlessNumber).forEach((prop) => {
prefixes.forEach((prefix) => {
isUnitlessNumber[prefixKey(prefix, prop)] = 0; // isUnitlessNumber[prop]
});
});
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";
const XLinkNamespace = "http://www.w3.org/1999/xlink";
const XMLNamespace = "http://www.w3.org/XML/1998/namespace";
// 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 "";
}
}
const svg = {
animate: 0,
circle: 0,
clipPath: 0,
defs: 0,
desc: 0,
ellipse: 0,
feBlend: 0,
feColorMatrix: 0,
feComponentTransfer: 0,
feComposite: 0,
feConvolveMatrix: 0,
feDiffuseLighting: 0,
feDisplacementMap: 0,
feDistantLight: 0,
feFlood: 0,
feFuncA: 0,
feFuncB: 0,
feFuncG: 0,
feFuncR: 0,
feGaussianBlur: 0,
feImage: 0,
feMerge: 0,
feMergeNode: 0,
feMorphology: 0,
feOffset: 0,
fePointLight: 0,
feSpecularLighting: 0,
feSpotLight: 0,
feTile: 0,
feTurbulence: 0,
filter: 0,
foreignObject: 0,
g: 0,
image: 0,
line: 0,
linearGradient: 0,
marker: 0,
mask: 0,
metadata: 0,
path: 0,
pattern: 0,
polygon: 0,
polyline: 0,
radialGradient: 0,
rect: 0,
stop: 0,
svg: 0,
switch: 0,
symbol: 0,
text: 0,
textPath: 0,
tspan: 0,
use: 0,
view: 0,
};
const nonPresentationSVGAttributes =
/^(a(ll|t|u)|base[FP]|c(al|lipPathU|on)|di|ed|ex|filter[RU]|g(lyphR|r)|ke|l(en|im)|ma(rker[HUW]|s)|n|pat|pr|point[^e]|re[^n]|s[puy]|st[^or]|ta|textL|vi|xC|y|z)/;
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;
if (!attr.namespaceURI && svg[tag] === 0) {
attr = {
...attr,
namespaceURI: SVGNamespace,
};
}
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 normalizeAttribute(s, separator) {
return s.replace(/[A-Z]/g, (match) => separator + match.toLowerCase());
}
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 if (isNumber(val) && isUnitlessNumber[key] !== 0) {
node.style[key] = val + "px";
} else {
node.style[key] = val;
}
});
}
}
function attribute(key, value, node) {
switch (key) {
case "xlinkActuate":
case "xlinkArcrole":
case "xlinkHref":
case "xlinkRole":
case "xlinkShow":
case "xlinkTitle":
case "xlinkType":
attrNS(node, XLinkNamespace, normalizeAttribute(key, ":"), value);
return;
case "xmlnsXlink":
attr(node, normalizeAttribute(key, ":"), value);
return;
case "xmlBase":
case "xmlLang":
case "xmlSpace":
attrNS(node, XMLNamespace, normalizeAttribute(key, ":"), value);
return;
}
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) {
if (node instanceof SVGElement && !nonPresentationSVGAttributes.test(key)) {
attr(node, normalizeAttribute(key, "-"), value);
} else {
attr(node, key, value);
}
}
}
function attr(node, key, value) {
node.setAttribute(key, value);
}
function attrNS(node, namespace, key, value) {
node.setAttributeNS(namespace, 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,
};