From 7938f17bf9b71276cf0561487609e041d69c1a8e Mon Sep 17 00:00:00 2001 From: Matteo Vesprini-Heidrich Date: Thu, 26 Oct 2017 15:43:34 -0400 Subject: [PATCH] add Portal support to React.Children calls --- packages/react/src/ReactChildren.js | 7 ++++-- .../react/src/__tests__/ReactChildren-test.js | 25 +++++++++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/packages/react/src/ReactChildren.js b/packages/react/src/ReactChildren.js index 987d3e79c4595..346668b59bc6c 100644 --- a/packages/react/src/ReactChildren.js +++ b/packages/react/src/ReactChildren.js @@ -25,7 +25,9 @@ var FAUX_ITERATOR_SYMBOL = '@@iterator'; // Before Symbol spec. var REACT_ELEMENT_TYPE = (typeof Symbol === 'function' && Symbol.for && Symbol.for('react.element')) || 0xeac7; - +const REACT_PORTAL_TYPE = + (typeof Symbol === 'function' && Symbol.for && Symbol.for('react.portal')) || + 0xeaca; var SEPARATOR = '.'; var SUBSEPARATOR = ':'; @@ -125,7 +127,8 @@ function traverseAllChildrenImpl( type === 'number' || // The following is inlined from ReactElement. This means we can optimize // some checks. React Fiber also inlines this logic for similar purposes. - (type === 'object' && children.$$typeof === REACT_ELEMENT_TYPE) + (type === 'object' && children.$$typeof === REACT_ELEMENT_TYPE) || + (type === 'object' && children.$$typeof === REACT_PORTAL_TYPE) ) { callback( traverseContext, diff --git a/packages/react/src/__tests__/ReactChildren-test.js b/packages/react/src/__tests__/ReactChildren-test.js index 88c68fe0aac89..d06e965ea7b9c 100644 --- a/packages/react/src/__tests__/ReactChildren-test.js +++ b/packages/react/src/__tests__/ReactChildren-test.js @@ -48,6 +48,31 @@ describe('ReactChildren', () => { expect(mappedChildren[0]).toEqual(); }); + it('should support Portal components', () => { + const context = {}; + const callback = jasmine.createSpy().and.callFake(function(kid, index) { + expect(this).toBe(context); + return kid; + }); + const ReactDOM = require('react-dom'); + const portalContainer = document.createElement('div'); + + const simpleChild = ; + const portal = ReactDOM.createPortal(simpleChild, portalContainer); + const instance =
{portal}
; + + React.Children.forEach(instance.props.children, callback, context); + expect(callback).toHaveBeenCalledWith(portal, 0); + callback.calls.reset(); + const mappedChildren = React.Children.map( + instance.props.children, + callback, + context, + ); + expect(callback).toHaveBeenCalledWith(portal, 0); + expect(mappedChildren[0]).toEqual(portal); + }); + it('should treat single arrayless child as being in array', () => { var context = {}; var callback = jasmine.createSpy().and.callFake(function(kid, index) {