Skip to content

Commit

Permalink
[react-core] Add experimental React Scope component API (#16587)
Browse files Browse the repository at this point in the history
  • Loading branch information
trueadm authored Aug 29, 2019
1 parent 996acf9 commit bd79be9
Show file tree
Hide file tree
Showing 22 changed files with 459 additions and 94 deletions.
86 changes: 1 addition & 85 deletions packages/react-dom/src/events/DOMEventResponderSystem.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
PASSIVE_NOT_SUPPORTED,
} from 'legacy-events/EventSystemFlags';
import type {AnyNativeEvent} from 'legacy-events/PluginModuleType';
import {HostComponent, SuspenseComponent} from 'shared/ReactWorkTags';
import {HostComponent} from 'shared/ReactWorkTags';
import type {EventPriority} from 'shared/ReactTypes';
import type {
ReactDOMEventResponder,
Expand Down Expand Up @@ -238,28 +238,6 @@ const eventResponderContext: ReactDOMResponderContext = {
}
}
},
getFocusableElementsInScope(deep: boolean): Array<HTMLElement> {
validateResponderContext();
const focusableElements = [];
const eventResponderInstance = ((currentInstance: any): ReactDOMEventResponderInstance);
const currentResponder = eventResponderInstance.responder;
let focusScopeFiber = eventResponderInstance.fiber;
if (deep) {
let deepNode = focusScopeFiber.return;
while (deepNode !== null) {
if (doesFiberHaveResponder(deepNode, currentResponder)) {
focusScopeFiber = deepNode;
}
deepNode = deepNode.return;
}
}
const child = focusScopeFiber.child;

if (child !== null) {
collectFocusableElements(child, focusableElements);
}
return focusableElements;
},
getActiveDocument,
objectAssign: Object.assign,
getTimeStamp(): number {
Expand Down Expand Up @@ -335,33 +313,6 @@ function validateEventValue(eventValue: any): void {
}
}

function collectFocusableElements(
node: Fiber,
focusableElements: Array<HTMLElement>,
): void {
if (isFiberSuspenseAndTimedOut(node)) {
const fallbackChild = getSuspenseFallbackChild(node);
if (fallbackChild !== null) {
collectFocusableElements(fallbackChild, focusableElements);
}
} else {
if (isFiberHostComponentFocusable(node)) {
focusableElements.push(node.stateNode);
} else {
const child = node.child;

if (child !== null) {
collectFocusableElements(child, focusableElements);
}
}
}
const sibling = node.sibling;

if (sibling !== null) {
collectFocusableElements(sibling, focusableElements);
}
}

function doesFiberHaveResponder(
fiber: Fiber,
responder: ReactDOMEventResponder,
Expand All @@ -382,33 +333,6 @@ function getActiveDocument(): Document {
return ((currentDocument: any): Document);
}

function isFiberHostComponentFocusable(fiber: Fiber): boolean {
if (fiber.tag !== HostComponent) {
return false;
}
const {type, memoizedProps} = fiber;
if (memoizedProps.tabIndex === -1 || memoizedProps.disabled) {
return false;
}
if (memoizedProps.tabIndex === 0 || memoizedProps.contentEditable === true) {
return true;
}
if (type === 'a' || type === 'area') {
return !!memoizedProps.href && memoizedProps.rel !== 'ignore';
}
if (type === 'input') {
return memoizedProps.type !== 'hidden' && memoizedProps.type !== 'file';
}
return (
type === 'button' ||
type === 'textarea' ||
type === 'object' ||
type === 'select' ||
type === 'iframe' ||
type === 'embed'
);
}

function processTimers(
timers: Map<number, ResponderTimer>,
delay: number,
Expand Down Expand Up @@ -626,14 +550,6 @@ function validateResponderContext(): void {
);
}

function isFiberSuspenseAndTimedOut(fiber: Fiber): boolean {
return fiber.tag === SuspenseComponent && fiber.memoizedState !== null;
}

function getSuspenseFallbackChild(fiber: Fiber): Fiber | null {
return ((((fiber.child: any): Fiber).sibling: any): Fiber).child;
}

export function dispatchEventForResponderEventSystem(
topLevelType: string,
targetFiber: null | Fiber,
Expand Down
5 changes: 0 additions & 5 deletions packages/react-events/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,6 @@ const event = { type: 'press', target, pointerType, x, y };
context.dispatchEvent('onPress', event, DiscreteEvent);
```

### getFocusableElementsInScope(): Array<Element>

Returns every DOM element that can be focused within the scope of the Event
Responder instance.

### isTargetWithinNode(target: Element, element: Element): boolean

Returns `true` if `target` is a child of `element`.
Expand Down
27 changes: 27 additions & 0 deletions packages/react-reconciler/src/ReactFiber.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import type {
ReactEventResponder,
ReactEventResponderInstance,
ReactFundamentalComponent,
ReactScope,
} from 'shared/ReactTypes';
import type {RootTag} from 'shared/ReactRootTags';
import type {WorkTag} from 'shared/ReactWorkTags';
Expand All @@ -32,6 +33,7 @@ import {
enableProfilerTimer,
enableFundamentalAPI,
enableUserTimingAPI,
enableScopeAPI,
} from 'shared/ReactFeatureFlags';
import {NoEffect, Placement} from 'shared/ReactSideEffectTags';
import {ConcurrentRoot, BatchedRoot} from 'shared/ReactRootTags';
Expand All @@ -56,6 +58,7 @@ import {
SimpleMemoComponent,
LazyComponent,
FundamentalComponent,
ScopeComponent,
} from 'shared/ReactWorkTags';
import getComponentName from 'shared/getComponentName';

Expand Down Expand Up @@ -86,6 +89,7 @@ import {
REACT_MEMO_TYPE,
REACT_LAZY_TYPE,
REACT_FUNDAMENTAL_TYPE,
REACT_SCOPE_TYPE,
} from 'shared/ReactSymbols';

let hasBadMapPolyfill;
Expand Down Expand Up @@ -674,6 +678,16 @@ export function createFiberFromTypeAndProps(
);
}
break;
case REACT_SCOPE_TYPE:
if (enableScopeAPI) {
return createFiberFromScope(
type,
pendingProps,
mode,
expirationTime,
key,
);
}
}
}
let info = '';
Expand Down Expand Up @@ -766,6 +780,19 @@ export function createFiberFromFundamental(
return fiber;
}

function createFiberFromScope(
scope: ReactScope,
pendingProps: any,
mode: TypeOfMode,
expirationTime: ExpirationTime,
key: null | string,
) {
const fiber = createFiber(ScopeComponent, pendingProps, key, mode);
fiber.type = scope;
fiber.expirationTime = expirationTime;
return fiber;
}

function createFiberFromProfiler(
pendingProps: any,
mode: TypeOfMode,
Expand Down
25 changes: 25 additions & 0 deletions packages/react-reconciler/src/ReactFiberBeginWork.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import {
LazyComponent,
IncompleteClassComponent,
FundamentalComponent,
ScopeComponent,
} from 'shared/ReactWorkTags';
import {
NoEffect,
Expand All @@ -63,6 +64,7 @@ import {
enableSuspenseServerRenderer,
enableFundamentalAPI,
warnAboutDefaultPropsOnFunctionComponents,
enableScopeAPI,
} from 'shared/ReactFeatureFlags';
import invariant from 'shared/invariant';
import shallowEqual from 'shared/shallowEqual';
Expand Down Expand Up @@ -2672,6 +2674,19 @@ function updateFundamentalComponent(
return workInProgress.child;
}

function updateScopeComponent(current, workInProgress, renderExpirationTime) {
const nextProps = workInProgress.pendingProps;
const nextChildren = nextProps.children;

reconcileChildren(
current,
workInProgress,
nextChildren,
renderExpirationTime,
);
return workInProgress.child;
}

export function markWorkInProgressReceivedUpdate() {
didReceiveUpdate = true;
}
Expand Down Expand Up @@ -3158,6 +3173,16 @@ function beginWork(
}
break;
}
case ScopeComponent: {
if (enableScopeAPI) {
return updateScopeComponent(
current,
workInProgress,
renderExpirationTime,
);
}
break;
}
}
invariant(
false,
Expand Down
14 changes: 14 additions & 0 deletions packages/react-reconciler/src/ReactFiberCommitWork.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import {
enableFlareAPI,
enableFundamentalAPI,
enableSuspenseCallback,
enableScopeAPI,
} from 'shared/ReactFeatureFlags';
import {
FunctionComponent,
Expand All @@ -49,6 +50,7 @@ import {
SimpleMemoComponent,
SuspenseListComponent,
FundamentalComponent,
ScopeComponent,
} from 'shared/ReactWorkTags';
import {
invokeGuardedCallback,
Expand Down Expand Up @@ -617,6 +619,7 @@ function commitLifeCycles(
case SuspenseListComponent:
case IncompleteClassComponent:
case FundamentalComponent:
case ScopeComponent:
return;
default: {
invariant(
Expand Down Expand Up @@ -691,6 +694,10 @@ function commitAttachRef(finishedWork: Fiber) {
default:
instanceToUse = instance;
}
// Moved outside to ensure DCE works with this flag
if (enableScopeAPI && finishedWork.tag === ScopeComponent) {
instanceToUse = instance.methods;
}
if (typeof ref === 'function') {
ref(instanceToUse);
} else {
Expand Down Expand Up @@ -1383,6 +1390,13 @@ function commitWork(current: Fiber | null, finishedWork: Fiber): void {
}
return;
}
case ScopeComponent: {
if (enableScopeAPI) {
const scopeInstance = finishedWork.stateNode;
scopeInstance.fiber = finishedWork;
}
return;
}
default: {
invariant(
false,
Expand Down
33 changes: 32 additions & 1 deletion packages/react-reconciler/src/ReactFiberCompleteWork.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@

import type {Fiber} from './ReactFiber';
import type {ExpirationTime} from './ReactFiberExpirationTime';
import type {ReactFundamentalComponentInstance} from 'shared/ReactTypes';
import type {
ReactFundamentalComponentInstance,
ReactScopeInstance,
} from 'shared/ReactTypes';
import type {FiberRoot} from './ReactFiberRoot';
import type {
Instance,
Expand Down Expand Up @@ -47,6 +50,7 @@ import {
LazyComponent,
IncompleteClassComponent,
FundamentalComponent,
ScopeComponent,
} from 'shared/ReactWorkTags';
import {NoMode, BatchedMode} from './ReactTypeOfMode';
import {
Expand Down Expand Up @@ -112,6 +116,7 @@ import {
enableSuspenseServerRenderer,
enableFlareAPI,
enableFundamentalAPI,
enableScopeAPI,
} from 'shared/ReactFeatureFlags';
import {
markSpawnedWork,
Expand All @@ -123,6 +128,7 @@ import {createFundamentalStateInstance} from './ReactFiberFundamental';
import {Never} from './ReactFiberExpirationTime';
import {resetChildFibers} from './ReactChildFiber';
import {updateEventListeners} from './ReactFiberEvents';
import {createScopeMethods} from './ReactFiberScope';

function markUpdate(workInProgress: Fiber) {
// Tag the fiber with an update effect. This turns a Placement into
Expand Down Expand Up @@ -1213,6 +1219,31 @@ function completeWork(
}
break;
}
case ScopeComponent: {
if (enableScopeAPI) {
if (current === null) {
const type = workInProgress.type;
const scopeInstance: ReactScopeInstance = {
fiber: workInProgress,
methods: null,
};
workInProgress.stateNode = scopeInstance;
scopeInstance.methods = createScopeMethods(type, scopeInstance);
if (workInProgress.ref !== null) {
markRef(workInProgress);
markUpdate(workInProgress);
}
} else {
if (current.ref !== workInProgress.ref) {
markRef(workInProgress);
}
if (workInProgress.ref !== null) {
markUpdate(workInProgress);
}
}
}
break;
}
default:
invariant(
false,
Expand Down
Loading

0 comments on commit bd79be9

Please sign in to comment.