mirror of
https://github.com/facebook/react.git
synced 2026-02-27 03:07:57 +00:00
The event priority constants exports by the reconciler package are meant to be used by the reconciler (host config) itself. So it doesn't make sense to export them from a module that requires them. To break the cycle, we can move them to a separate module and import that. This looks like a "deep import" of an internal module, which we try to avoid, but conceptually these are part of the public interface of the reconciler module. So, no different than importing from the main `react-reconciler`. We do need to be careful about not mixing these types of imports with implementation details. Those are the ones to really avoid. An unintended benefit of the reconciler fork infra is that it makes deep imports harder. Any module that we treat as "public", like this one, needs to account for the `enableNewReconciler` flag and forward to the correct implementation.
472 lines
11 KiB
JavaScript
472 lines
11 KiB
JavaScript
/**
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*/
|
|
|
|
import Transform from 'art/core/transform';
|
|
import Mode from 'art/modes/current';
|
|
import invariant from 'shared/invariant';
|
|
|
|
import {TYPES, EVENT_TYPES, childrenAsString} from './ReactARTInternals';
|
|
|
|
import {DefaultEventPriority} from 'react-reconciler/src/ReactEventPriorities';
|
|
|
|
const pooledTransform = new Transform();
|
|
|
|
const NO_CONTEXT = {};
|
|
const UPDATE_SIGNAL = {};
|
|
if (__DEV__) {
|
|
Object.freeze(NO_CONTEXT);
|
|
Object.freeze(UPDATE_SIGNAL);
|
|
}
|
|
|
|
/** Helper Methods */
|
|
|
|
function addEventListeners(instance, type, listener) {
|
|
// We need to explicitly unregister before unmount.
|
|
// For this reason we need to track subscriptions.
|
|
if (!instance._listeners) {
|
|
instance._listeners = {};
|
|
instance._subscriptions = {};
|
|
}
|
|
|
|
instance._listeners[type] = listener;
|
|
|
|
if (listener) {
|
|
if (!instance._subscriptions[type]) {
|
|
instance._subscriptions[type] = instance.subscribe(
|
|
type,
|
|
createEventHandler(instance),
|
|
instance,
|
|
);
|
|
}
|
|
} else {
|
|
if (instance._subscriptions[type]) {
|
|
instance._subscriptions[type]();
|
|
delete instance._subscriptions[type];
|
|
}
|
|
}
|
|
}
|
|
|
|
function createEventHandler(instance) {
|
|
return function handleEvent(event) {
|
|
const listener = instance._listeners[event.type];
|
|
|
|
if (!listener) {
|
|
// Noop
|
|
} else if (typeof listener === 'function') {
|
|
listener.call(instance, event);
|
|
} else if (listener.handleEvent) {
|
|
listener.handleEvent(event);
|
|
}
|
|
};
|
|
}
|
|
|
|
function destroyEventListeners(instance) {
|
|
if (instance._subscriptions) {
|
|
for (const type in instance._subscriptions) {
|
|
instance._subscriptions[type]();
|
|
}
|
|
}
|
|
|
|
instance._subscriptions = null;
|
|
instance._listeners = null;
|
|
}
|
|
|
|
function getScaleX(props) {
|
|
if (props.scaleX != null) {
|
|
return props.scaleX;
|
|
} else if (props.scale != null) {
|
|
return props.scale;
|
|
} else {
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
function getScaleY(props) {
|
|
if (props.scaleY != null) {
|
|
return props.scaleY;
|
|
} else if (props.scale != null) {
|
|
return props.scale;
|
|
} else {
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
function isSameFont(oldFont, newFont) {
|
|
if (oldFont === newFont) {
|
|
return true;
|
|
} else if (typeof newFont === 'string' || typeof oldFont === 'string') {
|
|
return false;
|
|
} else {
|
|
return (
|
|
newFont.fontSize === oldFont.fontSize &&
|
|
newFont.fontStyle === oldFont.fontStyle &&
|
|
newFont.fontVariant === oldFont.fontVariant &&
|
|
newFont.fontWeight === oldFont.fontWeight &&
|
|
newFont.fontFamily === oldFont.fontFamily
|
|
);
|
|
}
|
|
}
|
|
|
|
/** Render Methods */
|
|
|
|
function applyClippingRectangleProps(instance, props, prevProps = {}) {
|
|
applyNodeProps(instance, props, prevProps);
|
|
|
|
instance.width = props.width;
|
|
instance.height = props.height;
|
|
}
|
|
|
|
function applyGroupProps(instance, props, prevProps = {}) {
|
|
applyNodeProps(instance, props, prevProps);
|
|
|
|
instance.width = props.width;
|
|
instance.height = props.height;
|
|
}
|
|
|
|
function applyNodeProps(instance, props, prevProps = {}) {
|
|
const scaleX = getScaleX(props);
|
|
const scaleY = getScaleY(props);
|
|
|
|
pooledTransform
|
|
.transformTo(1, 0, 0, 1, 0, 0)
|
|
.move(props.x || 0, props.y || 0)
|
|
.rotate(props.rotation || 0, props.originX, props.originY)
|
|
.scale(scaleX, scaleY, props.originX, props.originY);
|
|
|
|
if (props.transform != null) {
|
|
pooledTransform.transform(props.transform);
|
|
}
|
|
|
|
if (
|
|
instance.xx !== pooledTransform.xx ||
|
|
instance.yx !== pooledTransform.yx ||
|
|
instance.xy !== pooledTransform.xy ||
|
|
instance.yy !== pooledTransform.yy ||
|
|
instance.x !== pooledTransform.x ||
|
|
instance.y !== pooledTransform.y
|
|
) {
|
|
instance.transformTo(pooledTransform);
|
|
}
|
|
|
|
if (props.cursor !== prevProps.cursor || props.title !== prevProps.title) {
|
|
instance.indicate(props.cursor, props.title);
|
|
}
|
|
|
|
if (instance.blend && props.opacity !== prevProps.opacity) {
|
|
instance.blend(props.opacity == null ? 1 : props.opacity);
|
|
}
|
|
|
|
if (props.visible !== prevProps.visible) {
|
|
if (props.visible == null || props.visible) {
|
|
instance.show();
|
|
} else {
|
|
instance.hide();
|
|
}
|
|
}
|
|
|
|
for (const type in EVENT_TYPES) {
|
|
addEventListeners(instance, EVENT_TYPES[type], props[type]);
|
|
}
|
|
}
|
|
|
|
function applyRenderableNodeProps(instance, props, prevProps = {}) {
|
|
applyNodeProps(instance, props, prevProps);
|
|
|
|
if (prevProps.fill !== props.fill) {
|
|
if (props.fill && props.fill.applyFill) {
|
|
props.fill.applyFill(instance);
|
|
} else {
|
|
instance.fill(props.fill);
|
|
}
|
|
}
|
|
if (
|
|
prevProps.stroke !== props.stroke ||
|
|
prevProps.strokeWidth !== props.strokeWidth ||
|
|
prevProps.strokeCap !== props.strokeCap ||
|
|
prevProps.strokeJoin !== props.strokeJoin ||
|
|
// TODO: Consider deep check of stokeDash; may benefit VML in IE.
|
|
prevProps.strokeDash !== props.strokeDash
|
|
) {
|
|
instance.stroke(
|
|
props.stroke,
|
|
props.strokeWidth,
|
|
props.strokeCap,
|
|
props.strokeJoin,
|
|
props.strokeDash,
|
|
);
|
|
}
|
|
}
|
|
|
|
function applyShapeProps(instance, props, prevProps = {}) {
|
|
applyRenderableNodeProps(instance, props, prevProps);
|
|
|
|
const path = props.d || childrenAsString(props.children);
|
|
|
|
const prevDelta = instance._prevDelta;
|
|
const prevPath = instance._prevPath;
|
|
|
|
if (
|
|
path !== prevPath ||
|
|
path.delta !== prevDelta ||
|
|
prevProps.height !== props.height ||
|
|
prevProps.width !== props.width
|
|
) {
|
|
instance.draw(path, props.width, props.height);
|
|
|
|
instance._prevDelta = path.delta;
|
|
instance._prevPath = path;
|
|
}
|
|
}
|
|
|
|
function applyTextProps(instance, props, prevProps = {}) {
|
|
applyRenderableNodeProps(instance, props, prevProps);
|
|
|
|
const string = props.children;
|
|
|
|
if (
|
|
instance._currentString !== string ||
|
|
!isSameFont(props.font, prevProps.font) ||
|
|
props.alignment !== prevProps.alignment ||
|
|
props.path !== prevProps.path
|
|
) {
|
|
instance.draw(string, props.font, props.alignment, props.path);
|
|
|
|
instance._currentString = string;
|
|
}
|
|
}
|
|
|
|
export * from 'react-reconciler/src/ReactFiberHostConfigWithNoPersistence';
|
|
export * from 'react-reconciler/src/ReactFiberHostConfigWithNoHydration';
|
|
export * from 'react-reconciler/src/ReactFiberHostConfigWithNoScopes';
|
|
export * from 'react-reconciler/src/ReactFiberHostConfigWithNoTestSelectors';
|
|
export * from 'react-reconciler/src/ReactFiberHostConfigWithNoMicrotasks';
|
|
|
|
export function appendInitialChild(parentInstance, child) {
|
|
if (typeof child === 'string') {
|
|
// Noop for string children of Text (eg <Text>{'foo'}{'bar'}</Text>)
|
|
invariant(false, 'Text children should already be flattened.');
|
|
return;
|
|
}
|
|
|
|
child.inject(parentInstance);
|
|
}
|
|
|
|
export function createInstance(type, props, internalInstanceHandle) {
|
|
let instance;
|
|
|
|
switch (type) {
|
|
case TYPES.CLIPPING_RECTANGLE:
|
|
instance = Mode.ClippingRectangle();
|
|
instance._applyProps = applyClippingRectangleProps;
|
|
break;
|
|
case TYPES.GROUP:
|
|
instance = Mode.Group();
|
|
instance._applyProps = applyGroupProps;
|
|
break;
|
|
case TYPES.SHAPE:
|
|
instance = Mode.Shape();
|
|
instance._applyProps = applyShapeProps;
|
|
break;
|
|
case TYPES.TEXT:
|
|
instance = Mode.Text(
|
|
props.children,
|
|
props.font,
|
|
props.alignment,
|
|
props.path,
|
|
);
|
|
instance._applyProps = applyTextProps;
|
|
break;
|
|
}
|
|
|
|
invariant(instance, 'ReactART does not support the type "%s"', type);
|
|
|
|
instance._applyProps(instance, props);
|
|
|
|
return instance;
|
|
}
|
|
|
|
export function createTextInstance(
|
|
text,
|
|
rootContainerInstance,
|
|
internalInstanceHandle,
|
|
) {
|
|
return text;
|
|
}
|
|
|
|
export function finalizeInitialChildren(domElement, type, props) {
|
|
return false;
|
|
}
|
|
|
|
export function getPublicInstance(instance) {
|
|
return instance;
|
|
}
|
|
|
|
export function prepareForCommit() {
|
|
// Noop
|
|
return null;
|
|
}
|
|
|
|
export function prepareUpdate(domElement, type, oldProps, newProps) {
|
|
return UPDATE_SIGNAL;
|
|
}
|
|
|
|
export function resetAfterCommit() {
|
|
// Noop
|
|
}
|
|
|
|
export function resetTextContent(domElement) {
|
|
// Noop
|
|
}
|
|
|
|
export function getRootHostContext() {
|
|
return NO_CONTEXT;
|
|
}
|
|
|
|
export function getChildHostContext() {
|
|
return NO_CONTEXT;
|
|
}
|
|
|
|
export const scheduleTimeout = setTimeout;
|
|
export const cancelTimeout = clearTimeout;
|
|
export const noTimeout = -1;
|
|
|
|
export function shouldSetTextContent(type, props) {
|
|
return (
|
|
typeof props.children === 'string' || typeof props.children === 'number'
|
|
);
|
|
}
|
|
|
|
export function getCurrentEventPriority() {
|
|
return DefaultEventPriority;
|
|
}
|
|
|
|
// The ART renderer is secondary to the React DOM renderer.
|
|
export const isPrimaryRenderer = false;
|
|
|
|
// The ART renderer shouldn't trigger missing act() warnings
|
|
export const warnsIfNotActing = false;
|
|
|
|
export const supportsMutation = true;
|
|
|
|
export function appendChild(parentInstance, child) {
|
|
if (child.parentNode === parentInstance) {
|
|
child.eject();
|
|
}
|
|
child.inject(parentInstance);
|
|
}
|
|
|
|
export function appendChildToContainer(parentInstance, child) {
|
|
if (child.parentNode === parentInstance) {
|
|
child.eject();
|
|
}
|
|
child.inject(parentInstance);
|
|
}
|
|
|
|
export function insertBefore(parentInstance, child, beforeChild) {
|
|
invariant(
|
|
child !== beforeChild,
|
|
'ReactART: Can not insert node before itself',
|
|
);
|
|
child.injectBefore(beforeChild);
|
|
}
|
|
|
|
export function insertInContainerBefore(parentInstance, child, beforeChild) {
|
|
invariant(
|
|
child !== beforeChild,
|
|
'ReactART: Can not insert node before itself',
|
|
);
|
|
child.injectBefore(beforeChild);
|
|
}
|
|
|
|
export function removeChild(parentInstance, child) {
|
|
destroyEventListeners(child);
|
|
child.eject();
|
|
}
|
|
|
|
export function removeChildFromContainer(parentInstance, child) {
|
|
destroyEventListeners(child);
|
|
child.eject();
|
|
}
|
|
|
|
export function commitTextUpdate(textInstance, oldText, newText) {
|
|
// Noop
|
|
}
|
|
|
|
export function commitMount(instance, type, newProps) {
|
|
// Noop
|
|
}
|
|
|
|
export function commitUpdate(
|
|
instance,
|
|
updatePayload,
|
|
type,
|
|
oldProps,
|
|
newProps,
|
|
) {
|
|
instance._applyProps(instance, newProps, oldProps);
|
|
}
|
|
|
|
export function hideInstance(instance) {
|
|
instance.hide();
|
|
}
|
|
|
|
export function hideTextInstance(textInstance) {
|
|
// Noop
|
|
}
|
|
|
|
export function unhideInstance(instance, props) {
|
|
if (props.visible == null || props.visible) {
|
|
instance.show();
|
|
}
|
|
}
|
|
|
|
export function unhideTextInstance(textInstance, text): void {
|
|
// Noop
|
|
}
|
|
|
|
export function clearContainer(container) {
|
|
// TODO Implement this
|
|
}
|
|
|
|
export function getInstanceFromNode(node) {
|
|
throw new Error('Not yet implemented.');
|
|
}
|
|
|
|
export function isOpaqueHydratingObject(value: mixed): boolean {
|
|
throw new Error('Not yet implemented');
|
|
}
|
|
|
|
export function makeOpaqueHydratingObject(
|
|
attemptToReadValue: () => void,
|
|
): OpaqueIDType {
|
|
throw new Error('Not yet implemented.');
|
|
}
|
|
|
|
export function makeClientId(): OpaqueIDType {
|
|
throw new Error('Not yet implemented');
|
|
}
|
|
|
|
export function makeClientIdInDEV(warnOnAccessInDEV: () => void): OpaqueIDType {
|
|
throw new Error('Not yet implemented');
|
|
}
|
|
|
|
export function beforeActiveInstanceBlur(internalInstanceHandle: Object) {
|
|
// noop
|
|
}
|
|
|
|
export function afterActiveInstanceBlur() {
|
|
// noop
|
|
}
|
|
|
|
export function preparePortalMount(portalInstance: any): void {
|
|
// noop
|
|
}
|
|
|
|
export function detachDeletedInstance(node: Instance): void {
|
|
// noop
|
|
}
|