Spaces:
Running
Running
File size: 4,880 Bytes
e8a57cb | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 | import { options, Fragment } from 'preact';
import { encodeEntities } from './utils';
import { IS_NON_DIMENSIONAL } from '../../src/constants';
let vnodeId = 0;
const isArray = Array.isArray;
/**
* @fileoverview
* This file exports various methods that implement Babel's "automatic" JSX runtime API:
* - jsx(type, props, key)
* - jsxs(type, props, key)
* - jsxDEV(type, props, key, __source, __self)
*
* The implementation of createVNode here is optimized for performance.
* Benchmarks: https://esbench.com/bench/5f6b54a0b4632100a7dcd2b3
*/
/**
* JSX.Element factory used by Babel's {runtime:"automatic"} JSX transform
* @param {VNode['type']} type
* @param {VNode['props']} props
* @param {VNode['key']} [key]
* @param {unknown} [isStaticChildren]
* @param {unknown} [__source]
* @param {unknown} [__self]
*/
function createVNode(type, props, key, isStaticChildren, __source, __self) {
if (!props) props = {};
// We'll want to preserve `ref` in props to get rid of the need for
// forwardRef components in the future, but that should happen via
// a separate PR.
let normalizedProps = props,
ref,
i;
if ('ref' in normalizedProps) {
normalizedProps = {};
for (i in props) {
if (i == 'ref') {
ref = props[i];
} else {
normalizedProps[i] = props[i];
}
}
}
/** @type {VNode & { __source: any; __self: any }} */
const vnode = {
type,
props: normalizedProps,
key,
ref,
_children: null,
_parent: null,
_depth: 0,
_dom: null,
_component: null,
constructor: undefined,
_original: --vnodeId,
_index: -1,
_flags: 0,
__source,
__self
};
// If a Component VNode, check for and apply defaultProps.
// Note: `type` is often a String, and can be `undefined` in development.
if (typeof type === 'function' && (ref = type.defaultProps)) {
for (i in ref)
if (normalizedProps[i] === undefined) {
normalizedProps[i] = ref[i];
}
}
if (options.vnode) options.vnode(vnode);
return vnode;
}
/**
* Create a template vnode. This function is not expected to be
* used directly, but rather through a precompile JSX transform
* @param {string[]} templates
* @param {Array<string | null | VNode>} exprs
* @returns {VNode}
*/
function jsxTemplate(templates, ...exprs) {
const vnode = createVNode(Fragment, { tpl: templates, exprs });
// Bypass render to string top level Fragment optimization
vnode.key = vnode._vnode;
return vnode;
}
const JS_TO_CSS = {};
const CSS_REGEX = /[A-Z]/g;
/**
* Unwrap potential signals.
* @param {*} value
* @returns {*}
*/
function normalizeAttrValue(value) {
return value !== null &&
typeof value === 'object' &&
typeof value.valueOf === 'function'
? value.valueOf()
: value;
}
/**
* Serialize an HTML attribute to a string. This function is not
* expected to be used directly, but rather through a precompile
* JSX transform
* @param {string} name The attribute name
* @param {*} value The attribute value
* @returns {string}
*/
function jsxAttr(name, value) {
if (options.attr) {
const result = options.attr(name, value);
if (typeof result === 'string') return result;
}
value = normalizeAttrValue(value);
if (name === 'ref' || name === 'key') return '';
if (name === 'style' && typeof value === 'object') {
let str = '';
for (let prop in value) {
let val = value[prop];
if (val != null && val !== '') {
const name =
prop[0] == '-'
? prop
: JS_TO_CSS[prop] ||
(JS_TO_CSS[prop] = prop.replace(CSS_REGEX, '-$&').toLowerCase());
let suffix = ';';
if (
typeof val === 'number' &&
// Exclude custom-attributes
!name.startsWith('--') &&
!IS_NON_DIMENSIONAL.test(name)
) {
suffix = 'px;';
}
str = str + name + ':' + val + suffix;
}
}
return name + '="' + encodeEntities(str) + '"';
}
if (
value == null ||
value === false ||
typeof value === 'function' ||
typeof value === 'object'
) {
return '';
} else if (value === true) return name;
return name + '="' + encodeEntities('' + value) + '"';
}
/**
* Escape a dynamic child passed to `jsxTemplate`. This function
* is not expected to be used directly, but rather through a
* precompile JSX transform
* @param {*} value
* @returns {string | null | VNode | Array<string | null | VNode>}
*/
function jsxEscape(value) {
if (
value == null ||
typeof value === 'boolean' ||
typeof value === 'function'
) {
return null;
}
if (typeof value === 'object') {
// Check for VNode
if (value.constructor === undefined) return value;
if (isArray(value)) {
for (let i = 0; i < value.length; i++) {
value[i] = jsxEscape(value[i]);
}
return value;
}
}
return encodeEntities('' + value);
}
export {
createVNode as jsx,
createVNode as jsxs,
createVNode as jsxDEV,
Fragment,
// precompiled JSX transform
jsxTemplate,
jsxAttr,
jsxEscape
};
|