Spaces:
Running
Running
| import { | |
| render as preactRender, | |
| hydrate as preactHydrate, | |
| options, | |
| toChildArray, | |
| Component | |
| } from 'preact'; | |
| import { | |
| useCallback, | |
| useContext, | |
| useDebugValue, | |
| useEffect, | |
| useId, | |
| useImperativeHandle, | |
| useLayoutEffect, | |
| useMemo, | |
| useReducer, | |
| useRef, | |
| useState | |
| } from 'preact/hooks'; | |
| import { | |
| useDeferredValue, | |
| useInsertionEffect, | |
| useSyncExternalStore, | |
| useTransition | |
| } from './index'; | |
| export const REACT_ELEMENT_TYPE = | |
| (typeof Symbol != 'undefined' && Symbol.for && Symbol.for('react.element')) || | |
| 0xeac7; | |
| const CAMEL_PROPS = | |
| /^(?:accent|alignment|arabic|baseline|cap|clip(?!PathU)|color|dominant|fill|flood|font|glyph(?!R)|horiz|image(!S)|letter|lighting|marker(?!H|W|U)|overline|paint|pointer|shape|stop|strikethrough|stroke|text(?!L)|transform|underline|unicode|units|v|vector|vert|word|writing|x(?!C))[A-Z]/; | |
| const ON_ANI = /^on(Ani|Tra|Tou|BeforeInp|Compo)/; | |
| const CAMEL_REPLACE = /[A-Z0-9]/g; | |
| const IS_DOM = typeof document !== 'undefined'; | |
| // Input types for which onchange should not be converted to oninput. | |
| // type="file|checkbox|radio", plus "range" in IE11. | |
| // (IE11 doesn't support Symbol, which we use here to turn `rad` into `ra` which matches "range") | |
| const onChangeInputType = type => | |
| (typeof Symbol != 'undefined' && typeof Symbol() == 'symbol' | |
| ? /fil|che|rad/ | |
| : /fil|che|ra/ | |
| ).test(type); | |
| // Some libraries like `react-virtualized` explicitly check for this. | |
| Component.prototype.isReactComponent = true; | |
| // `UNSAFE_*` lifecycle hooks | |
| // Preact only ever invokes the unprefixed methods. | |
| // Here we provide a base "fallback" implementation that calls any defined UNSAFE_ prefixed method. | |
| // - If a component defines its own `componentDidMount()` (including via defineProperty), use that. | |
| // - If a component defines `UNSAFE_componentDidMount()`, `componentDidMount` is the alias getter/setter. | |
| // - If anything assigns to an `UNSAFE_*` property, the assignment is forwarded to the unprefixed property. | |
| // See https://github.com/preactjs/preact/issues/1941 | |
| [ | |
| 'componentWillMount', | |
| 'componentWillReceiveProps', | |
| 'componentWillUpdate' | |
| ].forEach(key => { | |
| Object.defineProperty(Component.prototype, key, { | |
| configurable: true, | |
| get() { | |
| return this['UNSAFE_' + key]; | |
| }, | |
| set(v) { | |
| Object.defineProperty(this, key, { | |
| configurable: true, | |
| writable: true, | |
| value: v | |
| }); | |
| } | |
| }); | |
| }); | |
| /** | |
| * Proxy render() since React returns a Component reference. | |
| * @param {import('./internal').VNode} vnode VNode tree to render | |
| * @param {import('./internal').PreactElement} parent DOM node to render vnode tree into | |
| * @param {() => void} [callback] Optional callback that will be called after rendering | |
| * @returns {import('./internal').Component | null} The root component reference or null | |
| */ | |
| export function render(vnode, parent, callback) { | |
| // React destroys any existing DOM nodes, see #1727 | |
| // ...but only on the first render, see #1828 | |
| if (parent._children == null) { | |
| parent.textContent = ''; | |
| } | |
| preactRender(vnode, parent); | |
| if (typeof callback == 'function') callback(); | |
| return vnode ? vnode._component : null; | |
| } | |
| export function hydrate(vnode, parent, callback) { | |
| preactHydrate(vnode, parent); | |
| if (typeof callback == 'function') callback(); | |
| return vnode ? vnode._component : null; | |
| } | |
| let oldEventHook = options.event; | |
| options.event = e => { | |
| if (oldEventHook) e = oldEventHook(e); | |
| e.persist = () => {}; | |
| e.isPropagationStopped = function isPropagationStopped() { | |
| return this.cancelBubble; | |
| }; | |
| e.isDefaultPrevented = function isDefaultPrevented() { | |
| return this.defaultPrevented; | |
| }; | |
| return (e.nativeEvent = e); | |
| }; | |
| const classNameDescriptorNonEnumberable = { | |
| configurable: true, | |
| get() { | |
| return this.class; | |
| } | |
| }; | |
| function handleDomVNode(vnode) { | |
| let props = vnode.props, | |
| type = vnode.type, | |
| normalizedProps = {}, | |
| isNonDashedType = type.indexOf('-') == -1; | |
| for (let i in props) { | |
| let value = props[i]; | |
| if ( | |
| (i === 'value' && 'defaultValue' in props && value == null) || | |
| // Emulate React's behavior of not rendering the contents of noscript tags on the client. | |
| (IS_DOM && i === 'children' && type === 'noscript') || | |
| i === 'class' || | |
| i === 'className' | |
| ) { | |
| // Skip applying value if it is null/undefined and we already set | |
| // a default value | |
| continue; | |
| } | |
| let lowerCased = i.toLowerCase(); | |
| if (i === 'defaultValue' && 'value' in props && props.value == null) { | |
| // `defaultValue` is treated as a fallback `value` when a value prop is present but null/undefined. | |
| // `defaultValue` for Elements with no value prop is the same as the DOM defaultValue property. | |
| i = 'value'; | |
| } else if (i === 'download' && value === true) { | |
| // Calling `setAttribute` with a truthy value will lead to it being | |
| // passed as a stringified value, e.g. `download="true"`. React | |
| // converts it to an empty string instead, otherwise the attribute | |
| // value will be used as the file name and the file will be called | |
| // "true" upon downloading it. | |
| value = ''; | |
| } else if (lowerCased === 'translate' && value === 'no') { | |
| value = false; | |
| } else if (lowerCased[0] === 'o' && lowerCased[1] === 'n') { | |
| if (lowerCased === 'ondoubleclick') { | |
| i = 'ondblclick'; | |
| } else if ( | |
| lowerCased === 'onchange' && | |
| (type === 'input' || type === 'textarea') && | |
| !onChangeInputType(props.type) | |
| ) { | |
| lowerCased = i = 'oninput'; | |
| } else if (lowerCased === 'onfocus') { | |
| i = 'onfocusin'; | |
| } else if (lowerCased === 'onblur') { | |
| i = 'onfocusout'; | |
| } else if (ON_ANI.test(i)) { | |
| i = lowerCased; | |
| } | |
| } else if (isNonDashedType && CAMEL_PROPS.test(i)) { | |
| i = i.replace(CAMEL_REPLACE, '-$&').toLowerCase(); | |
| } else if (value === null) { | |
| value = undefined; | |
| } | |
| // Add support for onInput and onChange, see #3561 | |
| // if we have an oninput prop already change it to oninputCapture | |
| if (lowerCased === 'oninput') { | |
| i = lowerCased; | |
| if (normalizedProps[i]) { | |
| i = 'oninputCapture'; | |
| } | |
| } | |
| normalizedProps[i] = value; | |
| } | |
| if (type == 'select') { | |
| // Add support for array select values: <select multiple value={[]} /> | |
| if (normalizedProps.multiple && Array.isArray(normalizedProps.value)) { | |
| // forEach() always returns undefined, which we abuse here to unset the value prop. | |
| normalizedProps.value = toChildArray(props.children).forEach(child => { | |
| child.props.selected = | |
| normalizedProps.value.indexOf(child.props.value) != -1; | |
| }); | |
| } | |
| // Adding support for defaultValue in select tag | |
| if (normalizedProps.defaultValue != null) { | |
| normalizedProps.value = toChildArray(props.children).forEach(child => { | |
| if (normalizedProps.multiple) { | |
| child.props.selected = | |
| normalizedProps.defaultValue.indexOf(child.props.value) != -1; | |
| } else { | |
| child.props.selected = | |
| normalizedProps.defaultValue == child.props.value; | |
| } | |
| }); | |
| } | |
| } | |
| if (props.class && !props.className) { | |
| normalizedProps.class = props.class; | |
| Object.defineProperty( | |
| normalizedProps, | |
| 'className', | |
| classNameDescriptorNonEnumberable | |
| ); | |
| } else if (props.className) { | |
| normalizedProps.class = normalizedProps.className = props.className; | |
| } | |
| vnode.props = normalizedProps; | |
| } | |
| let oldVNodeHook = options.vnode; | |
| options.vnode = vnode => { | |
| // only normalize props on Element nodes | |
| if (typeof vnode.type === 'string') { | |
| handleDomVNode(vnode); | |
| } | |
| vnode.$$typeof = REACT_ELEMENT_TYPE; | |
| if (oldVNodeHook) oldVNodeHook(vnode); | |
| }; | |
| // Only needed for react-relay | |
| let currentComponent; | |
| const oldBeforeRender = options._render; | |
| options._render = function (vnode) { | |
| if (oldBeforeRender) { | |
| oldBeforeRender(vnode); | |
| } | |
| currentComponent = vnode._component; | |
| }; | |
| const oldDiffed = options.diffed; | |
| /** @type {(vnode: import('./internal').VNode) => void} */ | |
| options.diffed = function (vnode) { | |
| if (oldDiffed) { | |
| oldDiffed(vnode); | |
| } | |
| const props = vnode.props; | |
| const dom = vnode._dom; | |
| if ( | |
| dom != null && | |
| vnode.type === 'textarea' && | |
| 'value' in props && | |
| props.value !== dom.value | |
| ) { | |
| dom.value = props.value == null ? '' : props.value; | |
| } | |
| currentComponent = null; | |
| }; | |
| // This is a very very private internal function for React it | |
| // is used to sort-of do runtime dependency injection. | |
| export const __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED = { | |
| ReactCurrentDispatcher: { | |
| current: { | |
| readContext(context) { | |
| return currentComponent._globalContext[context._id].props.value; | |
| }, | |
| useCallback, | |
| useContext, | |
| useDebugValue, | |
| useDeferredValue, | |
| useEffect, | |
| useId, | |
| useImperativeHandle, | |
| useInsertionEffect, | |
| useLayoutEffect, | |
| useMemo, | |
| // useMutableSource, // experimental-only and replaced by uSES, likely not worth supporting | |
| useReducer, | |
| useRef, | |
| useState, | |
| useSyncExternalStore, | |
| useTransition | |
| } | |
| } | |
| }; | |