/** * Copyright (c) 2015-present, Facebook, Inc. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ #pragma once #include #include #include #include #include #include #include #include namespace facebook { namespace react { /* * Template for all -like classes (classes which have all same props * as and similar basic behaviour). * For example: , , but not , . */ template class ConcreteViewShadowNode: public ConcreteShadowNode, public AccessibleShadowNode, public YogaLayoutableShadowNode { static_assert(std::is_base_of::value, "ViewPropsT must be a descendant of ViewProps"); static_assert(std::is_base_of::value, "ViewPropsT must be a descendant of YogaStylableProps"); static_assert(std::is_base_of::value, "ViewPropsT must be a descendant of AccessibilityProps"); public: using ConcreteViewProps = ViewPropsT; using SharedConcreteViewProps = std::shared_ptr; using ConcreteViewEventEmitter = ViewEventEmitterT; using SharedConcreteViewEventEmitter = std::shared_ptr; using SharedConcreteViewShadowNode = std::shared_ptr; ConcreteViewShadowNode( const Tag &tag, const Tag &rootTag, const SharedConcreteViewProps &props, const SharedConcreteViewEventEmitter &eventEmitter, const SharedShadowNodeSharedList &children, const ShadowNodeCloneFunction &cloneFunction ): ConcreteShadowNode( tag, rootTag, props, eventEmitter, children, cloneFunction ), AccessibleShadowNode( props ), YogaLayoutableShadowNode( props, children ) {}; ConcreteViewShadowNode( const SharedConcreteViewShadowNode &shadowNode, const SharedConcreteViewProps &props, const SharedConcreteViewEventEmitter &eventEmitter, const SharedShadowNodeSharedList &children ): ConcreteShadowNode( shadowNode, props, eventEmitter, children ), AccessibleShadowNode( shadowNode, props ), YogaLayoutableShadowNode( shadowNode, props, children ) {}; void appendChild(const SharedShadowNode &child) { ensureUnsealed(); ShadowNode::appendChild(child); auto yogaLayoutableChild = std::dynamic_pointer_cast(child); if (yogaLayoutableChild) { YogaLayoutableShadowNode::appendChild(yogaLayoutableChild); } } SharedLayoutableShadowNode cloneAndReplaceChild(const SharedLayoutableShadowNode &child) override { ensureUnsealed(); auto childShadowNode = std::dynamic_pointer_cast(child); assert(childShadowNode); auto childShadowNodeClone = childShadowNode->clone(); // This is overloading of `SharedLayoutableShadowNode::cloneAndReplaceChild`, // the method is used to clone some node as a preparation for future mutation // caused by relayout. // Because those changes are not requested by UIManager, they add a layer // of node generation (between the committed stage and new proposed stage). // That additional layer confuses the Diffing algorithm which uses // `sourceNode` for referencing the previous (aka committed) stage // of the tree to produce mutation instructions. // In other words, if we don't compensate this change here, // the Diffing algorithm will compare wrong trees // ("new-but-not-laid-out-yet vs. new" instead of "committed vs. new"). auto nonConstChildShadowNodeClone = std::const_pointer_cast(childShadowNodeClone); nonConstChildShadowNodeClone->shallowSourceNode(); ShadowNode::replaceChild(childShadowNode, childShadowNodeClone); return std::dynamic_pointer_cast(childShadowNodeClone); } #pragma mark - Equality bool operator==(const ShadowNode& rhs) const override { if (!ShadowNode::operator==(rhs)) { return false; } auto &&other = static_cast(rhs); return getLayoutMetrics() == other.getLayoutMetrics(); } #pragma mark - DebugStringConvertible SharedDebugStringConvertibleList getDebugProps() const override { SharedDebugStringConvertibleList list = {}; auto basePropsList = ShadowNode::getDebugProps(); std::move(basePropsList.begin(), basePropsList.end(), std::back_inserter(list)); list.push_back(std::make_shared("layout", "", LayoutableShadowNode::getDebugProps())); return list; } protected: #pragma mark - LayoutableShadowNode SharedLayoutableShadowNodeList getLayoutableChildNodes() const override { SharedLayoutableShadowNodeList sharedLayoutableShadowNodeList = {}; for (auto child : *ShadowNode::children_) { const SharedLayoutableShadowNode layoutableShadowNode = std::dynamic_pointer_cast(child); if (!layoutableShadowNode) { continue; } sharedLayoutableShadowNodeList.push_back(layoutableShadowNode); } return sharedLayoutableShadowNodeList; } }; } // namespace react } // namespace facebook