/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * 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 namespace facebook::react { /* * `Element<>` is an abstraction layer that allows describing component * hierarchy in a declarative way. Creating `Element`s themself does not create * a component tree (aka `ShadowNode` tree) but describes some hierarchical * structure that might be used to build an actual component tree (similar to * XML Elements). * `Element` provides some basic type-safety guarantees: all modifications * of element objects require using objects (such as Props or State) of * compatible type. */ template class Element final { public: using ConcreteProps = typename ShadowNodeT::ConcreteProps; using SharedConcreteProps = std::shared_ptr; using ConcreteState = typename ShadowNodeT::ConcreteState; using ConcreteStateData = typename ShadowNodeT::ConcreteStateData; using SharedConcreteState = std::shared_ptr; using ConcreteShadowNode = ShadowNodeT; using ConcreteUnsharedShadowNode = std::shared_ptr; using ConcreteReferenceCallback = std::function& shadowNode)>; /* * Constructs an `Element`. */ Element() { fragment_.componentHandle = ShadowNodeT::Handle(); fragment_.componentName = ShadowNodeT::Name(); fragment_.props = ShadowNodeT::defaultSharedProps(); } /* * Converts to `ElementFragment` object. */ operator ElementFragment() { return fragment_; } /* * Sets `tag`. */ Element& tag(Tag tag) { fragment_.tag = tag; return *this; } /* * Sets `surfaceId`. */ Element& surfaceId(SurfaceId surfaceId) { fragment_.surfaceId = surfaceId; return *this; } /* * Sets `props`. */ Element& props(SharedConcreteProps props) { fragment_.props = props; return *this; } /* * Sets `props` using callback. */ Element& props(std::function callback) { fragment_.props = callback(); return *this; } /* * Sets `state` using callback. */ Element& stateData(std::function callback) { fragment_.stateCallback = [callback = std::move(callback)]( const State::Shared& state) -> StateData::Shared { auto stateData = static_cast(state.get())->getData(); callback(stateData); return std::make_shared(stateData); }; return *this; } /* * Sets children. */ Element& children(std::vector children) { auto fragments = ElementFragment::List{}; fragments.reserve(children.size()); for (const auto& child : children) { fragments.push_back(child); } fragment_.children = fragments; return *this; } /* * Calls the callback during component construction with a pointer to the * component which is being constructed. */ Element& reference( std::function callback) { fragment_.referenceCallback = [callback = std::move(callback)](const ShadowNode::Shared& shadowNode) { callback(std::const_pointer_cast( std::static_pointer_cast(shadowNode))); }; return *this; } /* * During component construction, assigns a given pointer to a component * that is being constructed. */ Element& reference(ConcreteUnsharedShadowNode& outShadowNode) { fragment_.referenceCallback = [&](const ShadowNode::Shared& shadowNode) { outShadowNode = std::const_pointer_cast( std::static_pointer_cast(shadowNode)); }; return *this; } /* * Calls the callback with a reference to a just constructed component. */ Element& finalize( std::function finalizeCallback) { fragment_.finalizeCallback = [=](ShadowNode& shadowNode) { return finalizeCallback(static_cast(shadowNode)); }; return *this; } private: friend class ComponentBuilder; ElementFragment fragment_; }; } // namespace facebook::react