/* * 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 { namespace 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 const &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)]() -> StateData::Shared { auto stateData = ConcreteStateData(); 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 (auto const &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; return *this; } /* * During component construction, assigns a given pointer to a component * that is being constructed. */ Element &reference(ConcreteUnsharedShadowNode &outShadowNode) { fragment_.referenceCallback = [&](ShadowNode::Shared const &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 react } // namespace facebook