@hippy/react
Version:
Hippy react framework
1,503 lines (1,486 loc) • 221 kB
JavaScript
/*!
* @hippy/react v3.3.4-rc.1
* Build at: Wed Mar 05 2025 15:28:06 GMT+0800 (中国标准时间)
*
* Tencent is pleased to support the open source community by making
* Hippy available.
*
* Copyright (C) 2017-2025 THL A29 Limited, a Tencent company.
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React from 'react';
import reactReconciler from '@hippy/react-reconciler';
/*
* Tencent is pleased to support the open source community by making
* Hippy available.
*
* Copyright (C) 2017-2019 THL A29 Limited, a Tencent company.
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
if (!global.__GLOBAL__) {
global.__GLOBAL__ = {};
}
global.__GLOBAL__.nodeId = 0;
global.__GLOBAL__.animationId = 0;
const { asyncStorage: AsyncStorage$2, bridge: Bridge$2, device: Device$2, document: UIManager, register: HippyRegister$2, on: addEventListener$2, off: removeEventListener$2, emit: dispatchEvent$1, } = global.Hippy;
var HippyGlobal = /*#__PURE__*/Object.freeze({
__proto__: null,
addEventListener: addEventListener$2,
removeEventListener: removeEventListener$2,
dispatchEvent: dispatchEvent$1,
AsyncStorage: AsyncStorage$2,
Bridge: Bridge$2,
Device: Device$2,
HippyRegister: HippyRegister$2,
UIManager: UIManager
});
/*
* Tencent is pleased to support the open source community by making
* Hippy available.
*
* Copyright (C) 2017-2019 THL A29 Limited, a Tencent company.
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Single root instance
let rootContainer;
let rootViewId;
const fiberNodeCache = new Map();
function setRootContainer(rootId, root) {
rootViewId = rootId;
rootContainer = root;
}
function getRootContainer() {
return rootContainer;
}
function getRootViewId() {
if (!rootViewId) {
throw new Error('getRootViewId must execute after setRootContainer');
}
return rootViewId;
}
function findNodeByCondition(condition) {
if (!rootContainer) {
return null;
}
const { current: root } = rootContainer;
const queue = [root];
while (queue.length) {
const targetNode = queue.shift();
if (!targetNode) {
break;
}
if (condition(targetNode)) {
return targetNode;
}
if (targetNode.child) {
queue.push(targetNode.child);
}
if (targetNode.sibling) {
queue.push(targetNode.sibling);
}
}
return null;
}
function findNodeById(nodeId) {
return findNodeByCondition(node => node.stateNode && node.stateNode.nodeId === nodeId);
}
/**
* preCacheFiberNode - cache FiberNode
* @param {Fiber} targetNode
* @param {number} nodeId
*/
function preCacheFiberNode(targetNode, nodeId) {
fiberNodeCache.set(nodeId, targetNode);
}
/**
* unCacheFiberNode - delete Fiber Node from cache
* @param {number} nodeId
*/
function unCacheFiberNode(nodeId) {
fiberNodeCache.delete(nodeId);
}
/**
* getElementFromFiber - get ElementNode by Fiber
* @param {number} fiberNode
*/
function getElementFromFiber(fiberNode) {
return (fiberNode === null || fiberNode === void 0 ? void 0 : fiberNode.stateNode) || null;
}
/**
* getFiberNodeFromId - get FiberNode by nodeId
* @param {number} nodeId
*/
function getFiberNodeFromId(nodeId) {
return fiberNodeCache.get(nodeId) || null;
}
/**
* unCacheFiberNodeOnIdle - recursively delete FiberNode cache on idle
* @param {ElementNode|number} node
*/
function unCacheFiberNodeOnIdle(node) {
requestIdleCallback((deadline) => {
// if idle time exists or callback invoked when timeout
if (deadline.timeRemaining() > 0 || deadline.didTimeout) {
recursivelyUnCacheFiberNode(node);
}
}, { timeout: 50 }); // 50ms to avoid blocking user operation
}
/**
* recursivelyUnCacheFiberNode - delete ViewNode cache recursively
* @param {ElementNode|number} node
*/
function recursivelyUnCacheFiberNode(node) {
if (typeof node === 'number') {
// if leaf node (e.g. text node)
unCacheFiberNode(node);
}
else if (node) {
unCacheFiberNode(node.nodeId);
if (Array.isArray(node.childNodes)) {
node.childNodes.forEach(node => recursivelyUnCacheFiberNode(node));
}
}
}
/**
* requestIdleCallback polyfill
* @param {Function} cb
* @param {{timeout: number}} [options]
*/
function requestIdleCallback(cb, options) {
if (!global.requestIdleCallback) {
return setTimeout(() => {
cb({
didTimeout: false,
timeRemaining() {
return Infinity;
},
});
}, 1);
}
return global.requestIdleCallback(cb, options);
}
// Event Name Index
const NATIVE_EVENT_INDEX = 1;
const eventHandlerType = {
ADD: 0,
REMOVE: 1,
};
const relativeToRefType = {
BEFORE: -1,
AFTER: 1,
};
const eventNamesMap = {
// onPressIn: ['onPressIn', 'onTouchDown'],
// onPressOut: ['onPressOut', 'onTouchEnd'],
onTouchStart: ['onTouchStart', 'onTouchDown'],
onPress: ['onPress', 'onClick'],
};
const DOMEventPhase = {
NONE: 0,
CAPTURING_PHASE: 1,
AT_TARGET: 2,
BUBBLING_PHASE: 3,
};
const nativeEventMap = {
onClick: 'click',
onLongClick: 'longclick',
// onPressIn: 'touchstart', // normalization
// onPressOut: 'touchend', // normalization
onPressIn: 'pressin',
onPressOut: 'pressout',
onTouchDown: 'touchstart',
onTouchStart: 'touchstart',
onTouchEnd: 'touchend',
onTouchMove: 'touchmove',
onTouchCancel: 'touchcancel',
};
function isNativeGesture$1(name) {
return !!nativeEventMap[name];
}
function translateToNativeEventName(name) {
return name.replace(/^(on)?/g, '').toLocaleLowerCase();
}
function isTextNode(targetNode) {
return (targetNode && targetNode.nativeName === 'Text') || ['p', 'span'].indexOf(targetNode.tagName) !== -1;
}
/*
* Tencent is pleased to support the open source community by making
* Hippy available.
*
* Copyright (C) 2017-2019 THL A29 Limited, a Tencent company.
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const IS_NUMBER_REG = new RegExp(/^\d+$/);
let silent = false;
let defaultBubbles = false;
/**
* Trace running information
*/
function trace(...context) {
// In production build or silent
if (isTraceEnabled()) {
console.log(...context);
}
}
/**
* Warning information output
*/
function warn(...context) {
// In production build
if (!isDev()) {
return;
}
console.warn(...context);
}
/**
* Convert unicode string to normal string
* @param {string} text - The unicode string input
*/
function unicodeToChar(text) {
return text.replace(/\\u[\dA-F]{4}|\\x[\dA-F]{2}/gi, match => String.fromCharCode(parseInt(match.replace(/\\u|\\x/g, ''), 16)));
}
const captureEventReg = new RegExp('^on.+Capture$');
/**
* ensure capture event name
* @param {any} eventName
*/
function isCaptureEvent(eventName) {
return captureEventReg.test(eventName);
}
function hasTargetEvent(key, events) {
return (typeof events !== 'undefined' && typeof events[key] === 'object' && !!events[key]);
}
/**
* Convert to string as possible
*/
const numberRegEx = new RegExp('^(?=.+)[+-]?\\d*\\.?\\d*([Ee][+-]?\\d+)?$');
/**
* Try to convert something to number
*
* @param {any} input - The input try to convert number
*/
function tryConvertNumber(input) {
if (typeof input === 'number') {
return input;
}
if (typeof input === 'string' && numberRegEx.test(input)) {
try {
return parseFloat(input);
}
catch (err) {
return input;
}
}
return input;
}
/**
* Determine input is function.
*
* @param {any} input - The input will determine is function.
* @returns {boolean}
*/
function isFunction(input) {
return Object.prototype.toString.call(input) === '[object Function]';
}
/**
* Determine a string is number.
* @param {string} input - the input will determine is number.
* @returns {boolean}
*/
function isNumber(input) {
return IS_NUMBER_REG.test(input);
}
/**
* Make trace be silent.
* @param {boolean} silentArg - The silent flag for log
*/
function setSilent(silentArg) {
silent = silentArg;
}
/**
* is development environment
*/
function isDev() {
return process.env.NODE_ENV !== 'production';
}
/**
* is Trace silent
* @returns {boolean}
*/
function isTraceEnabled() {
return isDev() && !silent;
}
/**
* set bubbles config, default is false
* @param bubbles
*/
function setBubbles(bubbles = false) {
defaultBubbles = bubbles;
}
/**
* get bubbles config
* @returns boolean
*/
function isGlobalBubble() {
return defaultBubbles;
}
/**
* Convert Image url to specific type
* @param url - image path
*/
function convertImgUrl(url) {
if (url && !/^(http|https):\/\//.test(url) && url.indexOf('assets') > -1) {
if (isDev()) {
const addStr1 = 'http://';
return `${addStr1}127.0.0.1:${process.env.PORT}/${url}`;
}
const addStr2 = 'hpfile://';
return `${addStr2}./${url}`;
}
return url;
}
function deepCopy(data, hash = new WeakMap()) {
if (typeof data !== 'object' || data === null) {
throw new TypeError('deepCopy data is object');
}
// is it data existed in WeakMap
if (hash.has(data)) {
return hash.get(data);
}
const newData = {};
const dataKeys = Object.keys(data);
dataKeys.forEach((value) => {
const currentDataValue = data[value];
if (typeof currentDataValue !== 'object' || currentDataValue === null) {
newData[value] = currentDataValue;
}
else if (Array.isArray(currentDataValue)) {
newData[value] = [...currentDataValue];
}
else if (currentDataValue instanceof Set) {
newData[value] = new Set([...currentDataValue]);
}
else if (currentDataValue instanceof Map) {
newData[value] = new Map([...currentDataValue]);
}
else {
hash.set(data, data);
newData[value] = deepCopy(currentDataValue, hash);
}
});
return newData;
}
function isStyleNotEmpty(style) {
if (typeof style === 'string') {
return style.trim() !== '';
}
return style !== null && style !== undefined;
}
/*
* Tencent is pleased to support the open source community by making
* Hippy available.
*
* Copyright (C) 2017-2019 THL A29 Limited, a Tencent company.
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class HippyEventHub {
constructor(eventName) {
this.handlerContainer = {};
this.nextIdForHandler = 0;
this.eventName = eventName;
}
getEventListeners() {
return Object.keys(this.handlerContainer)
.filter(key => this.handlerContainer[key])
.map(key => this.handlerContainer[key]);
}
getHandlerSize() {
return Object.keys(this.handlerContainer).length;
}
addEventHandler(handler, callContext) {
if (!handler) {
throw new TypeError('Invalid arguments for addEventHandler');
}
const currId = this.nextIdForHandler;
this.nextIdForHandler += 1;
const eventHandlerWrapper = {
id: currId,
eventHandler: handler,
context: callContext,
};
const idAttrName = `eventHandler_${currId}`;
this.handlerContainer[idAttrName] = eventHandlerWrapper;
return currId;
}
notifyEvent(...eventParams) {
Object.keys(this.handlerContainer).forEach((key) => {
const instance = this.handlerContainer[key];
if (!instance || !instance.eventHandler) {
return;
}
if (instance.context) {
instance.eventHandler.call(instance.context, ...eventParams);
}
else {
instance.eventHandler(...eventParams);
}
});
}
removeEventHandler(handlerId) {
if (typeof handlerId !== 'number') {
throw new TypeError('Invalid arguments for removeEventHandler');
}
const idAttrName = `eventHandler_${handlerId}`;
if (this.handlerContainer[idAttrName]) {
delete this.handlerContainer[idAttrName];
}
}
}
/*
* Tencent is pleased to support the open source community by making
* Hippy available.
*
* Copyright (C) 2017-2019 THL A29 Limited, a Tencent company.
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class Event {
/**
* constructor
* @param eventName - handler name, e.g. onClick
* @param currentTarget - currentTarget is the node which the handler bind to
* @param target - target is the node which triggered the real event
*/
constructor(eventName, currentTarget, target) {
this.type = eventName;
this.bubbles = true;
// currentTarget is the node which the handler bind to
this.currentTarget = currentTarget;
// target is the node which triggered the real event
this.target = target;
}
stopPropagation() {
this.bubbles = false;
}
preventDefault() {
// noop
}
}
/*
* Tencent is pleased to support the open source community by making
* Hippy available.
*
* Copyright (C) 2017-2019 THL A29 Limited, a Tencent company.
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const eventHubs = new Map();
const componentName$2 = ['%c[event]%c', 'color: green', 'color: auto'];
function isNodePropFunction(prop, nextNodeItem) {
return !!(nextNodeItem.memoizedProps && typeof nextNodeItem.memoizedProps[prop] === 'function');
}
/**
* dispatchGestureEvent - dispatch event
* @param {string} eventName
* @param {NativeEvent} nativeEvent
* @param {Fiber} currentItem
* @param {Fiber} targetItem
* @param {any} params
* @param {HippyTypes.DOMEvent} domEvent
*/
function dispatchGestureEvent(eventName, nativeEvent, currentItem, targetItem, params, domEvent) {
try {
let isStopBubble = false;
const targetNode = getElementFromFiber(targetItem);
const currentTargetNode = getElementFromFiber(currentItem);
const { eventPhase } = domEvent;
// handle target & capture phase event
if (isNodePropFunction(eventName, currentItem)
&& isCaptureEvent(eventName)
&& [DOMEventPhase.AT_TARGET, DOMEventPhase.CAPTURING_PHASE].indexOf(eventPhase) > -1) {
const syntheticEvent = new Event(eventName, currentTargetNode, targetNode);
Object.assign(syntheticEvent, { eventPhase }, params);
currentItem.memoizedProps[eventName](syntheticEvent);
if (!syntheticEvent.bubbles && domEvent) {
domEvent.stopPropagation();
}
}
if (isNodePropFunction(eventName, currentItem)
&& !isCaptureEvent(eventName)
&& [DOMEventPhase.AT_TARGET, DOMEventPhase.BUBBLING_PHASE].indexOf(eventPhase) > -1) {
// handle target & bubbling phase event
const syntheticEvent = new Event(eventName, currentTargetNode, targetNode);
Object.assign(syntheticEvent, { eventPhase }, params);
isStopBubble = currentItem.memoizedProps[eventName](syntheticEvent);
// If callback have no return, use global bubble config to set isStopBubble.
if (typeof isStopBubble !== 'boolean') {
isStopBubble = !isGlobalBubble();
}
// event bubbles flag has higher priority
if (!syntheticEvent.bubbles) {
isStopBubble = true;
}
if (isStopBubble && domEvent) {
domEvent.stopPropagation();
}
}
}
catch (err) {
console.error(err);
}
}
/**
* dispatchUIEvent - dispatch ui event
* @param {string} eventName
* @param {NativeEvent} nativeEvent
* @param {Fiber} currentItem
* @param {Fiber} targetItem
* @param {any} params
* @param {HippyTypes.DOMEvent} domEvent
*/
function dispatchUIEvent(eventName, nativeEvent, currentItem, targetItem, params, domEvent) {
let isStopBubble = false;
const targetNode = getElementFromFiber(targetItem);
const currentTargetNode = getElementFromFiber(currentItem);
try {
const { eventPhase } = domEvent;
// handle target & bubbling phase event
if (isNodePropFunction(eventName, currentItem)
&& !isCaptureEvent(eventName)
&& [DOMEventPhase.AT_TARGET, DOMEventPhase.BUBBLING_PHASE].indexOf(eventPhase) > -1) {
const syntheticEvent = new Event(eventName, currentTargetNode, targetNode);
Object.assign(syntheticEvent, { eventPhase }, params);
currentItem.memoizedProps[eventName](syntheticEvent);
isStopBubble = !isGlobalBubble();
// event bubbles flag has higher priority
if (!syntheticEvent.bubbles) {
isStopBubble = true;
}
if (isStopBubble && domEvent) {
domEvent.stopPropagation();
}
}
}
catch (err) {
console.error(err);
}
}
function receiveComponentEvent(nativeEvent, domEvent) {
trace(...componentName$2, 'receiveComponentEvent', nativeEvent);
if (!nativeEvent || !domEvent) {
warn(...componentName$2, 'receiveComponentEvent', 'nativeEvent or domEvent not exist');
return;
}
const { id, currentId, nativeName, originalName, params = {} } = nativeEvent;
const currentTargetNode = getFiberNodeFromId(currentId);
const targetNode = getFiberNodeFromId(id);
if (!currentTargetNode || !targetNode) {
warn(...componentName$2, 'receiveComponentEvent', 'currentTargetNode or targetNode not exist');
return;
}
if (isNativeGesture$1(nativeName)) {
dispatchGestureEvent(originalName, nativeEvent, currentTargetNode, targetNode, params, domEvent);
}
else {
dispatchUIEvent(originalName, nativeEvent, currentTargetNode, targetNode, params, domEvent);
}
}
function getHippyEventHub(eventName) {
if (typeof eventName !== 'string') {
throw new TypeError(`Invalid eventName for getHippyEventHub: ${eventName}`);
}
return eventHubs.get(eventName) || null;
}
function registerNativeEventHub(eventName) {
trace(...componentName$2, 'registerNativeEventHub', eventName);
if (typeof eventName !== 'string') {
throw new TypeError(`Invalid eventName for registerNativeEventHub: ${eventName}`);
}
let targetEventHub = eventHubs.get(eventName);
if (!targetEventHub) {
targetEventHub = new HippyEventHub(eventName);
eventHubs.set(eventName, targetEventHub);
}
return targetEventHub;
}
function unregisterNativeEventHub(eventName) {
if (typeof eventName !== 'string') {
throw new TypeError(`Invalid eventName for unregisterNativeEventHub: ${eventName}`);
}
if (eventHubs.has(eventName)) {
eventHubs.delete(eventName);
}
}
function receiveNativeEvent(nativeEvent) {
trace(...componentName$2, 'receiveNativeEvent', nativeEvent);
if (!nativeEvent || !Array.isArray(nativeEvent) || nativeEvent.length < 2) {
throw new TypeError(`Invalid params for receiveNativeEvent: ${JSON.stringify(nativeEvent)}`);
}
const [eventName, eventParams] = nativeEvent;
if (typeof eventName !== 'string') {
throw new TypeError('Invalid arguments for nativeEvent eventName');
}
const currEventHub = getHippyEventHub(eventName);
if (!currEventHub) {
return;
}
currEventHub.notifyEvent(eventParams);
}
const EventDispatcher = {
registerNativeEventHub,
getHippyEventHub,
unregisterNativeEventHub,
receiveNativeEvent,
receiveComponentEvent,
};
if (global.__GLOBAL__) {
global.__GLOBAL__.jsModuleList.EventDispatcher = EventDispatcher;
}
/*
* Tencent is pleased to support the open source community by making
* Hippy available.
*
* Copyright (C) 2017-2019 THL A29 Limited, a Tencent company.
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class EventEmitterRevoker {
constructor(id, listener) {
this.callback = id;
this.bindListener = listener;
}
remove() {
if (typeof this.callback !== 'number' || !this.bindListener) {
return;
}
this.bindListener.removeCallback(this.callback);
this.bindListener = undefined;
}
}
/*
* Tencent is pleased to support the open source community by making
* Hippy available.
*
* Copyright (C) 2017-2019 THL A29 Limited, a Tencent company.
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class HippyEventListener {
constructor(event) {
this.eventName = event;
this.listenerIdList = [];
}
unregister() {
const eventHub = EventDispatcher.getHippyEventHub(this.eventName);
if (!eventHub) {
throw new ReferenceError(`No listeners for ${this.eventName}`);
}
const listenerIdSize = this.listenerIdList.length;
for (let i = 0; i < listenerIdSize; i += 1) {
eventHub.removeEventHandler(this.listenerIdList[i]);
}
this.listenerIdList = [];
if (eventHub.getHandlerSize() === 0) {
EventDispatcher.unregisterNativeEventHub(this.eventName);
}
}
getSize() {
return this.listenerIdList.length;
}
addCallback(handleFunc, callContext) {
if (typeof handleFunc !== 'function') {
throw new TypeError('Invalid addCallback function arguments');
}
const targetEventHub = EventDispatcher.registerNativeEventHub(this.eventName);
if (!targetEventHub) {
throw new ReferenceError(`No listeners for ${this.eventName}`);
}
const listenerId = targetEventHub.addEventHandler(handleFunc, callContext);
if (typeof listenerId !== 'number') {
throw new Error('Fail to addEventHandler in addCallback function');
}
this.listenerIdList.push(listenerId);
return listenerId;
}
removeCallback(callbackId) {
if (typeof callbackId !== 'number') {
throw new TypeError('Invalid arguments for removeCallback');
}
const targetEventHub = EventDispatcher.getHippyEventHub(this.eventName);
if (!targetEventHub) {
throw new ReferenceError(`No listeners for ${this.eventName}`);
}
targetEventHub.removeEventHandler(callbackId);
const listenerIdSize = this.listenerIdList.length;
for (let i = 0; i < listenerIdSize; i += 1) {
if (callbackId === this.listenerIdList[i]) {
this.listenerIdList.splice(i, 1);
break;
}
}
}
}
/*
* Tencent is pleased to support the open source community by making
* Hippy available.
*
* Copyright (C) 2017-2019 THL A29 Limited, a Tencent company.
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
function getNameForEvent(event) {
if (typeof event !== 'string') {
throw new TypeError('Invalid arguments for getNameForEvent');
}
return `eventEmitter_${event}`;
}
class HippyEventEmitter {
constructor(sharedListeners) {
if (sharedListeners && typeof sharedListeners === 'object') {
this.hippyEventListeners = sharedListeners;
}
else {
this.hippyEventListeners = {};
}
}
sharedListeners() {
return this.hippyEventListeners;
}
addListener(event, callback, context) {
if (typeof event !== 'string' || typeof callback !== 'function') {
throw new TypeError('Invalid arguments for addListener');
}
let registeredListener = this.hippyEventListeners[getNameForEvent(event)];
if (!registeredListener) {
registeredListener = new HippyEventListener(event);
this.hippyEventListeners[getNameForEvent(event)] = registeredListener;
}
const listenerId = registeredListener.addCallback(callback, context);
if (typeof listenerId !== 'number') {
throw new Error('Fail to addCallback in addListener');
}
return new EventEmitterRevoker(listenerId, registeredListener);
}
removeAllListeners(event) {
if (typeof event !== 'string') {
throw new TypeError('Invalid arguments for removeAllListeners');
}
const registeredListener = this.hippyEventListeners[getNameForEvent(event)];
if (registeredListener) {
registeredListener.unregister();
delete this.hippyEventListeners[getNameForEvent(event)];
}
}
emit(event, param) {
if (typeof event !== 'string') {
return false;
}
const eventHub = EventDispatcher.getHippyEventHub(event);
if (!eventHub) {
return false;
}
eventHub.notifyEvent(param);
return true;
}
listenerSize(event) {
if (typeof event !== 'string') {
throw new TypeError('Invalid arguments for listenerSize');
}
const registeredListener = this.hippyEventListeners[getNameForEvent(event)];
if (registeredListener) {
return registeredListener.getSize();
}
return 0;
}
}
HippyEventEmitter.emit = HippyEventEmitter.prototype.emit;
/*
* Tencent is pleased to support the open source community by making
* Hippy available.
*
* Copyright (C) 2022 THL A29 Limited, a Tencent company.
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const globalEventListeners = {};
function addListener(event, callback, context) {
if (!globalEventListeners[event]) {
globalEventListeners[event] = {
eventListener: new HippyEventListener(event),
eventMap: new Map(),
};
}
const { eventListener, eventMap } = globalEventListeners[event];
const listenerId = eventListener.addCallback(callback, context);
if (typeof listenerId !== 'number') {
throw new Error('Fail to addCallback in addListener');
}
eventMap.set(callback, listenerId);
}
function removeListener(event, callback) {
// remove specific listener for this event
const eventInfo = globalEventListeners[event];
if (!eventInfo) {
return warn(`Event [${event}] has not been registered yet in EventBus`);
}
const { eventListener, eventMap } = eventInfo;
// remove all listeners for this event
if (!callback) {
eventListener.unregister();
eventMap.clear();
delete globalEventListeners[event];
}
else {
// remove specific listener for this event
const listenerId = eventMap.get(callback);
if (typeof listenerId !== 'number') {
return warn(`The listener for event [${event}] cannot be found to remove`);
}
eventListener.removeCallback(listenerId);
eventMap.delete(callback);
// if listeners size is 0, means this event info needs to be deleted
if (eventMap.size === 0) {
delete globalEventListeners[event];
}
}
}
const EventBus = {
on: (events, callback, context) => {
if ((typeof events !== 'string' && !Array.isArray(events)) || typeof callback !== 'function') {
throw new TypeError('Invalid arguments for EventBus.on()');
}
if (Array.isArray(events)) {
events.forEach((event) => {
addListener(event, callback, context);
});
}
else {
addListener(events, callback, context);
}
return EventBus;
},
off: (events, callback) => {
if (typeof events !== 'string' && !Array.isArray(events)) {
throw new TypeError('The event argument is not string or array for EventBus.off()');
}
if (Array.isArray(events)) {
events.forEach((event) => {
removeListener(event, callback);
});
}
else {
removeListener(events, callback);
}
return EventBus;
},
sizeOf(event) {
if (typeof event !== 'string') {
throw new TypeError('The event argument is not string for EventBus.sizeOf()');
}
const eventInfo = globalEventListeners[event];
if (eventInfo === null || eventInfo === void 0 ? void 0 : eventInfo.eventMap) {
return eventInfo.eventMap.size;
}
return 0;
},
emit(event, ...param) {
if (typeof event !== 'string') {
throw new TypeError('The event argument is not string for EventBus.emit()');
}
const eventHub = EventDispatcher.getHippyEventHub(event);
if (!eventHub) {
warn(`Event [${event}] has not been registered yet in EventBus`);
return EventBus;
}
eventHub.notifyEvent(...param);
return EventBus;
},
};
/*
* Tencent is pleased to support the open source community by making
* Hippy available.
*
* Copyright (C) 2017-2019 THL A29 Limited, a Tencent company.
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
function call(...args) {
return `\\(\\s*(${args.join(')\\s*,\\s*(')})\\s*\\)`;
}
const colors = {
transparent: 0x00000000,
aliceblue: 0xf0f8ffff,
antiquewhite: 0xfaebd7ff,
aqua: 0x00ffffff,
aquamarine: 0x7fffd4ff,
azure: 0xf0ffffff,
beige: 0xf5f5dcff,
bisque: 0xffe4c4ff,
black: 0x000000ff,
blanchedalmond: 0xffebcdff,
blue: 0x0000ffff,
blueviolet: 0x8a2be2ff,
brown: 0xa52a2aff,
burlywood: 0xdeb887ff,
burntsienna: 0xea7e5dff,
cadetblue: 0x5f9ea0ff,
chartreuse: 0x7fff00ff,
chocolate: 0xd2691eff,
coral: 0xff7f50ff,
cornflowerblue: 0x6495edff,
cornsilk: 0xfff8dcff,
crimson: 0xdc143cff,
cyan: 0x00ffffff,
darkblue: 0x00008bff,
darkcyan: 0x008b8bff,
darkgoldenrod: 0xb8860bff,
darkgray: 0xa9a9a9ff,
darkgreen: 0x006400ff,
darkgrey: 0xa9a9a9ff,
darkkhaki: 0xbdb76bff,
darkmagenta: 0x8b008bff,
darkolivegreen: 0x556b2fff,
darkorange: 0xff8c00ff,
darkorchid: 0x9932ccff,
darkred: 0x8b0000ff,
darksalmon: 0xe9967aff,
darkseagreen: 0x8fbc8fff,
darkslateblue: 0x483d8bff,
darkslategray: 0x2f4f4fff,
darkslategrey: 0x2f4f4fff,
darkturquoise: 0x00ced1ff,
darkviolet: 0x9400d3ff,
deeppink: 0xff1493ff,
deepskyblue: 0x00bfffff,
dimgray: 0x696969ff,
dimgrey: 0x696969ff,
dodgerblue: 0x1e90ffff,
firebrick: 0xb22222ff,
floralwhite: 0xfffaf0ff,
forestgreen: 0x228b22ff,
fuchsia: 0xff00ffff,
gainsboro: 0xdcdcdcff,
ghostwhite: 0xf8f8ffff,
gold: 0xffd700ff,
goldenrod: 0xdaa520ff,
gray: 0x808080ff,
green: 0x008000ff,
greenyellow: 0xadff2fff,
grey: 0x808080ff,
honeydew: 0xf0fff0ff,
hotpink: 0xff69b4ff,
indianred: 0xcd5c5cff,
indigo: 0x4b0082ff,
ivory: 0xfffff0ff,
khaki: 0xf0e68cff,
lavender: 0xe6e6faff,
lavenderblush: 0xfff0f5ff,
lawngreen: 0x7cfc00ff,
lemonchiffon: 0xfffacdff,
lightblue: 0xadd8e6ff,
lightcoral: 0xf08080ff,
lightcyan: 0xe0ffffff,
lightgoldenrodyellow: 0xfafad2ff,
lightgray: 0xd3d3d3ff,
lightgreen: 0x90ee90ff,
lightgrey: 0xd3d3d3ff,
lightpink: 0xffb6c1ff,
lightsalmon: 0xffa07aff,
lightseagreen: 0x20b2aaff,
lightskyblue: 0x87cefaff,
lightslategray: 0x778899ff,
lightslategrey: 0x778899ff,
lightsteelblue: 0xb0c4deff,
lightyellow: 0xffffe0ff,
lime: 0x00ff00ff,
limegreen: 0x32cd32ff,
linen: 0xfaf0e6ff,
magenta: 0xff00ffff,
maroon: 0x800000ff,
mediumaquamarine: 0x66cdaaff,
mediumblue: 0x0000cdff,
mediumorchid: 0xba55d3ff,
mediumpurple: 0x9370dbff,
mediumseagreen: 0x3cb371ff,
mediumslateblue: 0x7b68eeff,
mediumspringgreen: 0x00fa9aff,
mediumturquoise: 0x48d1ccff,
mediumvioletred: 0xc71585ff,
midnightblue: 0x191970ff,
mintcream: 0xf5fffaff,
mistyrose: 0xffe4e1ff,
moccasin: 0xffe4b5ff,
navajowhite: 0xffdeadff,
navy: 0x000080ff,
oldlace: 0xfdf5e6ff,
olive: 0x808000ff,
olivedrab: 0x6b8e23ff,
orange: 0xffa500ff,
orangered: 0xff4500ff,
orchid: 0xda70d6ff,
palegoldenrod: 0xeee8aaff,
palegreen: 0x98fb98ff,
paleturquoise: 0xafeeeeff,
palevioletred: 0xdb7093ff,
papayawhip: 0xffefd5ff,
peachpuff: 0xffdab9ff,
peru: 0xcd853fff,
pink: 0xffc0cbff,
plum: 0xdda0ddff,
powderblue: 0xb0e0e6ff,
purple: 0x800080ff,
rebeccapurple: 0x663399ff,
red: 0xff0000ff,
rosybrown: 0xbc8f8fff,
royalblue: 0x4169e1ff,
saddlebrown: 0x8b4513ff,
salmon: 0xfa8072ff,
sandybrown: 0xf4a460ff,
seagreen: 0x2e8b57ff,
seashell: 0xfff5eeff,
sienna: 0xa0522dff,
silver: 0xc0c0c0ff,
skyblue: 0x87ceebff,
slateblue: 0x6a5acdff,
slategray: 0x708090ff,
slategrey: 0x708090ff,
snow: 0xfffafaff,
springgreen: 0x00ff7fff,
steelblue: 0x4682b4ff,
tan: 0xd2b48cff,
teal: 0x008080ff,
thistle: 0xd8bfd8ff,
tomato: 0xff6347ff,
turquoise: 0x40e0d0ff,
violet: 0xee82eeff,
wheat: 0xf5deb3ff,
white: 0xffffffff,
whitesmoke: 0xf5f5f5ff,
yellow: 0xffff00ff,
yellowgreen: 0x9acd32ff,
};
const NUMBER = '[-+]?\\d*\\.?\\d+';
const PERCENTAGE = `${NUMBER}%`;
const matchers = {
rgb: new RegExp(`rgb${call(NUMBER, NUMBER, NUMBER)}`),
rgba: new RegExp(`rgba${call(NUMBER, NUMBER, NUMBER, NUMBER)}`),
hsl: new RegExp(`hsl${call(NUMBER, PERCENTAGE, PERCENTAGE)}`),
hsla: new RegExp(`hsla${call(NUMBER, PERCENTAGE, PERCENTAGE, NUMBER)}`),
hex3: /^#([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/,
hex4: /^#([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/,
hex6: /^#([0-9a-fA-F]{6})$/,
hex8: /^#([0-9a-fA-F]{8})$/,
};
/*
* Tencent is pleased to support the open source community by making
* Hippy available.
*
* Copyright (C) 2017-2019 THL A29 Limited, a Tencent company.
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
function parse255(str) {
const int = parseInt(str, 10);
if (int < 0) {
return 0;
}
if (int > 255) {
return 255;
}
return int;
}
function parse1(str) {
const num = parseFloat(str);
if (num < 0) {
return 0;
}
if (num > 1) {
return 255;
}
return Math.round(num * 255);
}
function hue2rgb(p, q, tx) {
let t = tx;
if (t < 0) {
t += 1;
}
if (t > 1) {
t -= 1;
}
if (t < 1 / 6) {
return p + (q - p) * 6 * t;
}
if (t < 1 / 2) {
return q;
}
if (t < 2 / 3) {
return p + (q - p) * (2 / 3 - t) * 6;
}
return p;
}
function hslToRgb(h, s, l) {
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
const p = 2 * l - q;
const r = hue2rgb(p, q, h + 1 / 3);
const g = hue2rgb(p, q, h);
const b = hue2rgb(p, q, h - 1 / 3);
return ((Math.round(r * 255) << 24)
| (Math.round(g * 255) << 16)
| (Math.round(b * 255) << 8));
}
function parse360(str) {
const int = parseFloat(str);
return (((int % 360) + 360) % 360) / 360;
}
function parsePercentage(str) {
const int = parseFloat(str);
if (int < 0) {
return 0;
}
if (int > 100) {
return 1;
}
return int / 100;
}
function baseColor(color) {
let match;
if (typeof color === 'number') {
if (color >>> 0 === color && color >= 0 && color <= 0xffffffff) {
return color;
}
return null;
}
match = matchers.hex6.exec(color);
if (Array.isArray(match)) {
return parseInt(`${match[1]}ff`, 16) >>> 0;
}
if (Object.hasOwnProperty.call(colors, color)) {
return colors[color];
}
match = matchers.rgb.exec(color);
if (Array.isArray(match)) {
return ((parse255(match[1]) << 24) // r
| (parse255(match[2]) << 16) // g
| (parse255(match[3]) << 8) // b
| 0x000000ff // a
) >>> 0;
}
match = matchers.rgba.exec(color);
if (match) {
return ((parse255(match[1]) << 24) // r
| (parse255(match[2]) << 16) // g
| (parse255(match[3]) << 8) // b
| parse1(match[4]) // a
) >>> 0;
}
match = matchers.hex3.exec(color);
if (match) {
return parseInt(`${match[1] + match[1] // r
+ match[2] + match[2] // g
+ match[3] + match[3] // b
}ff`, // a
16) >>> 0;
}
match = matchers.hex8.exec(color);
if (match) {
return parseInt(match[1], 16) >>> 0;
}
match = matchers.hex4.exec(color);
if (match) {
return parseInt(match[1] + match[1] // r
+ match[2] + match[2] // g
+ match[3] + match[3] // b
+ match[4] + match[4], // a
16) >>> 0;
}
match = matchers.hsl.exec(color);
if (match) {
return (hslToRgb(parse360(match[1]), // h
parsePercentage(match[2]), // s
parsePercentage(match[3]))
| 0x000000ff // a
) >>> 0;
}
match = matchers.hsla.exec(color);
if (match) {
return (hslToRgb(parse360(match[1]), // h
parsePercentage(match[2]), // s
parsePercentage(match[3]))
| parse1(match[4]) // a
) >>> 0;
}
return null;
}
/*
* Tencent is pleased to support the open source community by making
* Hippy available.
*
* Copyright (C) 2017-2019 THL A29 Limited, a Tencent company.
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Parse the color value to integer that native understand.
*
* @param {string} color - The color value.
*/
function colorParse(color) {
if (Number.isInteger(color)) {
return color;
}
let int32Color = baseColor(color);
if (int32Color === null) {
return 0;
}
int32Color = (int32Color << 24 | int32Color >>> 8) >>> 0;
return int32Color;
}
/**
* Parse the color values array to integer array that native understand.
*
* @param {string[]} colorArray The color values array.
*/
function colorArrayParse(colorArray) {
if (!Array.isArray(colorArray)) {
warn('Input color value is not a array', colorArray);
return [0];
}
return colorArray.map(color => colorParse(color));
}
/*
* Tencent is pleased to support the open source community by making
* Hippy available.
*
* Copyright (C) 2017-2019 THL A29 Limited, a Tencent company.
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
function repeatCountDict(repeatCount) {
if (repeatCount === 'loop') {
return -1;
}
return repeatCount;
}
/*
* Tencent is pleased to support the open source community by making
* Hippy available.
*
* Copyright (C) 2017-2022 THL A29 Limited, a Tencent company.
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* parse value of special value type
* @param valueType
* @param originalValue
*/
function parseValue(valueType, originalValue) {
if (valueType === 'color' && ['number', 'string'].indexOf(typeof originalValue) >= 0) {
return colorParse(originalValue);
}
return originalValue;
}
const animationEvent$1 = {
START: 'animationstart',
END: 'animationend',
CANCEL: 'animationcancel',
REPEAT: 'animationrepeat',
};
/**
* Better performance of Animation solution.
*
* It pushes the animation scheme to native at once.
*/
class Animation {
constructor(config) {
var _a;
let startValue;
if (((_a = config.startValue) === null || _a === void 0 ? void 0 : _a.constructor) && config.startValue.constructor.name === 'Animation') {
startValue = { animationId: config.startValue.animationId };
}
else {
const { startValue: tempStartValue } = config;
startValue = parseValue(config.valueType, tempStartValue);
}
const toValue = parseVal