use state in paragraph component (#24873)
Summary: Updates the paragraph component to use State instead of Local Data, part of the path to a Fabric TextInput 💯 ## Changelog [General] [Changed] - Fabric: Use State instead of Local Data for Paragraph Pull Request resolved: https://github.com/facebook/react-native/pull/24873 Differential Revision: D15410979 Pulled By: shergin fbshipit-source-id: 3c9517d2495a64c4dbd213b6efb5ff55287900e3
This commit is contained in:
Родитель
c59da6eae8
Коммит
6ec19aba4e
|
@ -8,8 +8,8 @@
|
|||
#import "RCTParagraphComponentView.h"
|
||||
|
||||
#import <react/components/text/ParagraphComponentDescriptor.h>
|
||||
#import <react/components/text/ParagraphLocalData.h>
|
||||
#import <react/components/text/ParagraphProps.h>
|
||||
#import <react/components/text/ParagraphState.h>
|
||||
#import <react/components/text/RawTextComponentDescriptor.h>
|
||||
#import <react/components/text/TextComponentDescriptor.h>
|
||||
#import <react/core/LocalData.h>
|
||||
|
@ -21,7 +21,7 @@
|
|||
using namespace facebook::react;
|
||||
|
||||
@implementation RCTParagraphComponentView {
|
||||
SharedParagraphLocalData _paragraphLocalData;
|
||||
ParagraphShadowNode::ConcreteState::Shared _state;
|
||||
ParagraphAttributes _paragraphAttributes;
|
||||
}
|
||||
|
||||
|
@ -63,32 +63,32 @@ using namespace facebook::react;
|
|||
_paragraphAttributes = paragraphProps->paragraphAttributes;
|
||||
}
|
||||
|
||||
- (void)updateLocalData:(SharedLocalData)localData oldLocalData:(SharedLocalData)oldLocalData
|
||||
- (void)updateState:(State::Shared)state oldState:(State::Shared)oldState
|
||||
{
|
||||
_paragraphLocalData = std::static_pointer_cast<const ParagraphLocalData>(localData);
|
||||
assert(_paragraphLocalData);
|
||||
_state = std::static_pointer_cast<ParagraphShadowNode::ConcreteState const>(state);
|
||||
assert(_state);
|
||||
[self setNeedsDisplay];
|
||||
}
|
||||
|
||||
- (void)prepareForRecycle
|
||||
{
|
||||
[super prepareForRecycle];
|
||||
_paragraphLocalData.reset();
|
||||
_state.reset();
|
||||
}
|
||||
|
||||
- (void)drawRect:(CGRect)rect
|
||||
{
|
||||
if (!_paragraphLocalData) {
|
||||
if (!_state) {
|
||||
return;
|
||||
}
|
||||
|
||||
SharedTextLayoutManager textLayoutManager = _paragraphLocalData->getTextLayoutManager();
|
||||
SharedTextLayoutManager textLayoutManager = _state->getData().layoutManager;
|
||||
RCTTextLayoutManager *nativeTextLayoutManager =
|
||||
(__bridge RCTTextLayoutManager *)textLayoutManager->getNativeTextLayoutManager();
|
||||
|
||||
CGRect frame = RCTCGRectFromRect(_layoutMetrics.getContentFrame());
|
||||
|
||||
[nativeTextLayoutManager drawAttributedString:_paragraphLocalData->getAttributedString()
|
||||
[nativeTextLayoutManager drawAttributedString:_state->getData().attributedString
|
||||
paragraphAttributes:_paragraphAttributes
|
||||
frame:frame];
|
||||
}
|
||||
|
@ -102,26 +102,26 @@ using namespace facebook::react;
|
|||
return superAccessibilityLabel;
|
||||
}
|
||||
|
||||
if (!_paragraphLocalData) {
|
||||
if (!_state) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
return RCTNSStringFromString(_paragraphLocalData->getAttributedString().getString());
|
||||
return RCTNSStringFromString(_state->getData().attributedString.getString());
|
||||
}
|
||||
|
||||
- (SharedTouchEventEmitter)touchEventEmitterAtPoint:(CGPoint)point
|
||||
{
|
||||
if (!_paragraphLocalData) {
|
||||
if (!_state) {
|
||||
return _eventEmitter;
|
||||
}
|
||||
|
||||
SharedTextLayoutManager textLayoutManager = _paragraphLocalData->getTextLayoutManager();
|
||||
SharedTextLayoutManager textLayoutManager = _state->getData().layoutManager;
|
||||
RCTTextLayoutManager *nativeTextLayoutManager =
|
||||
(__bridge RCTTextLayoutManager *)textLayoutManager->getNativeTextLayoutManager();
|
||||
CGRect frame = RCTCGRectFromRect(_layoutMetrics.getContentFrame());
|
||||
|
||||
SharedEventEmitter eventEmitter =
|
||||
[nativeTextLayoutManager getEventEmitterWithAttributeString:_paragraphLocalData->getAttributedString()
|
||||
[nativeTextLayoutManager getEventEmitterWithAttributeString:_state->getData().attributedString
|
||||
paragraphAttributes:_paragraphAttributes
|
||||
frame:frame
|
||||
atPoint:point];
|
||||
|
|
|
@ -64,7 +64,7 @@ class ParagraphComponentDescriptor final
|
|||
|
||||
private:
|
||||
SharedTextLayoutManager textLayoutManager_;
|
||||
std::unique_ptr<const ParagraphMeasurementCache> measureCache_;
|
||||
std::unique_ptr<ParagraphMeasurementCache const> measureCache_;
|
||||
};
|
||||
|
||||
} // namespace react
|
||||
|
|
|
@ -1,58 +0,0 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#include "ParagraphLocalData.h"
|
||||
|
||||
#include <react/components/text/conversions.h>
|
||||
#include <react/debug/debugStringConvertibleUtils.h>
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
AttributedString ParagraphLocalData::getAttributedString() const {
|
||||
return attributedString_;
|
||||
}
|
||||
|
||||
void ParagraphLocalData::setAttributedString(
|
||||
AttributedString attributedString) {
|
||||
ensureUnsealed();
|
||||
attributedString_ = attributedString;
|
||||
}
|
||||
|
||||
SharedTextLayoutManager ParagraphLocalData::getTextLayoutManager() const {
|
||||
return textLayoutManager_;
|
||||
}
|
||||
|
||||
void ParagraphLocalData::setTextLayoutManager(
|
||||
SharedTextLayoutManager textLayoutManager) {
|
||||
ensureUnsealed();
|
||||
textLayoutManager_ = textLayoutManager;
|
||||
}
|
||||
|
||||
#ifdef ANDROID
|
||||
|
||||
folly::dynamic ParagraphLocalData::getDynamic() const {
|
||||
return toDynamic(*this);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#pragma mark - DebugStringConvertible
|
||||
|
||||
#if RN_DEBUG_STRING_CONVERTIBLE
|
||||
std::string ParagraphLocalData::getDebugName() const {
|
||||
return "ParagraphLocalData";
|
||||
}
|
||||
|
||||
SharedDebugStringConvertibleList ParagraphLocalData::getDebugProps() const {
|
||||
return {
|
||||
debugStringConvertibleItem("attributedString", attributedString_, "")};
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
|
@ -1,58 +0,0 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and its 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 <react/attributedstring/AttributedString.h>
|
||||
#include <react/core/LocalData.h>
|
||||
#include <react/textlayoutmanager/TextLayoutManager.h>
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
class ParagraphLocalData;
|
||||
|
||||
using SharedParagraphLocalData = std::shared_ptr<const ParagraphLocalData>;
|
||||
|
||||
/*
|
||||
* LocalData for <Paragraph> component.
|
||||
* Represents what to render and how to render.
|
||||
*/
|
||||
class ParagraphLocalData : public LocalData {
|
||||
public:
|
||||
/*
|
||||
* All content of <Paragraph> component represented as an `AttributedString`.
|
||||
*/
|
||||
AttributedString getAttributedString() const;
|
||||
void setAttributedString(AttributedString attributedString);
|
||||
|
||||
/*
|
||||
* `TextLayoutManager` provides a connection to platform-specific
|
||||
* text rendering infrastructure which is capable to render the
|
||||
* `AttributedString`.
|
||||
*/
|
||||
SharedTextLayoutManager getTextLayoutManager() const;
|
||||
void setTextLayoutManager(SharedTextLayoutManager textLayoutManager);
|
||||
|
||||
#ifdef ANDROID
|
||||
folly::dynamic getDynamic() const override;
|
||||
#endif
|
||||
|
||||
#pragma mark - DebugStringConvertible
|
||||
|
||||
#if RN_DEBUG_STRING_CONVERTIBLE
|
||||
std::string getDebugName() const override;
|
||||
SharedDebugStringConvertibleList getDebugProps() const override;
|
||||
#endif
|
||||
|
||||
private:
|
||||
AttributedString attributedString_;
|
||||
SharedTextLayoutManager textLayoutManager_;
|
||||
};
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
|
@ -15,8 +15,8 @@ namespace facebook {
|
|||
namespace react {
|
||||
|
||||
static ParagraphAttributes convertRawProp(
|
||||
const RawProps &rawProps,
|
||||
const ParagraphAttributes &defaultParagraphAttributes) {
|
||||
RawProps const &rawProps,
|
||||
ParagraphAttributes const &defaultParagraphAttributes) {
|
||||
auto paragraphAttributes = ParagraphAttributes{};
|
||||
|
||||
paragraphAttributes.maximumNumberOfLines = convertRawProp(
|
||||
|
@ -44,8 +44,8 @@ static ParagraphAttributes convertRawProp(
|
|||
}
|
||||
|
||||
ParagraphProps::ParagraphProps(
|
||||
const ParagraphProps &sourceProps,
|
||||
const RawProps &rawProps)
|
||||
ParagraphProps const &sourceProps,
|
||||
RawProps const &rawProps)
|
||||
: ViewProps(sourceProps, rawProps),
|
||||
BaseTextProps(sourceProps, rawProps),
|
||||
paragraphAttributes(
|
||||
|
|
|
@ -26,7 +26,7 @@ namespace react {
|
|||
class ParagraphProps : public ViewProps, public BaseTextProps {
|
||||
public:
|
||||
ParagraphProps() = default;
|
||||
ParagraphProps(const ParagraphProps &sourceProps, const RawProps &rawProps);
|
||||
ParagraphProps(ParagraphProps const &sourceProps, RawProps const &rawProps);
|
||||
|
||||
#pragma mark - Props
|
||||
|
||||
|
@ -34,12 +34,12 @@ class ParagraphProps : public ViewProps, public BaseTextProps {
|
|||
* Contains all prop values that affect visual representation of the
|
||||
* paragraph.
|
||||
*/
|
||||
const ParagraphAttributes paragraphAttributes{};
|
||||
ParagraphAttributes const paragraphAttributes{};
|
||||
|
||||
/*
|
||||
* Defines can the text be selected (and copied) or not.
|
||||
*/
|
||||
const bool isSelectable{};
|
||||
bool const isSelectable{};
|
||||
|
||||
#pragma mark - DebugStringConvertible
|
||||
|
||||
|
|
|
@ -6,13 +6,13 @@
|
|||
*/
|
||||
|
||||
#include "ParagraphShadowNode.h"
|
||||
#include "ParagraphLocalData.h"
|
||||
#include "ParagraphMeasurementCache.h"
|
||||
#include "ParagraphState.h"
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
const char ParagraphComponentName[] = "Paragraph";
|
||||
char const ParagraphComponentName[] = "Paragraph";
|
||||
|
||||
AttributedString ParagraphShadowNode::getAttributedString() const {
|
||||
if (!cachedAttributedString_.has_value()) {
|
||||
|
@ -33,26 +33,21 @@ void ParagraphShadowNode::setTextLayoutManager(
|
|||
}
|
||||
|
||||
void ParagraphShadowNode::setMeasureCache(
|
||||
const ParagraphMeasurementCache *cache) {
|
||||
ParagraphMeasurementCache const *cache) {
|
||||
ensureUnsealed();
|
||||
measureCache_ = cache;
|
||||
}
|
||||
|
||||
void ParagraphShadowNode::updateLocalDataIfNeeded() {
|
||||
void ParagraphShadowNode::updateStateIfNeeded() {
|
||||
ensureUnsealed();
|
||||
|
||||
auto attributedString = getAttributedString();
|
||||
auto currentLocalData =
|
||||
std::static_pointer_cast<const ParagraphLocalData>(getLocalData());
|
||||
if (currentLocalData &&
|
||||
currentLocalData->getAttributedString() == attributedString) {
|
||||
auto const &state = getStateData();
|
||||
if (state.attributedString == attributedString) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto localData = std::make_shared<ParagraphLocalData>();
|
||||
localData->setAttributedString(std::move(attributedString));
|
||||
localData->setTextLayoutManager(textLayoutManager_);
|
||||
setLocalData(localData);
|
||||
setStateData(ParagraphState{attributedString, textLayoutManager_});
|
||||
}
|
||||
|
||||
#pragma mark - LayoutableShadowNode
|
||||
|
@ -64,15 +59,16 @@ Size ParagraphShadowNode::measure(LayoutConstraints layoutConstraints) const {
|
|||
return {0, 0};
|
||||
}
|
||||
|
||||
const ParagraphAttributes paragraphAttributes =
|
||||
ParagraphAttributes const paragraphAttributes =
|
||||
getProps()->paragraphAttributes;
|
||||
|
||||
// Cache results of this function so we don't need to call measure()
|
||||
// repeatedly.
|
||||
if (measureCache_) {
|
||||
return measureCache_->get(
|
||||
ParagraphMeasurementCacheKey{attributedString, paragraphAttributes, layoutConstraints},
|
||||
[&](const ParagraphMeasurementCacheKey &key) {
|
||||
ParagraphMeasurementCacheKey{
|
||||
attributedString, paragraphAttributes, layoutConstraints},
|
||||
[&](ParagraphMeasurementCacheKey const &key) {
|
||||
return textLayoutManager_->measure(
|
||||
attributedString, paragraphAttributes, layoutConstraints);
|
||||
});
|
||||
|
@ -83,7 +79,7 @@ Size ParagraphShadowNode::measure(LayoutConstraints layoutConstraints) const {
|
|||
}
|
||||
|
||||
void ParagraphShadowNode::layout(LayoutContext layoutContext) {
|
||||
updateLocalDataIfNeeded();
|
||||
updateStateIfNeeded();
|
||||
ConcreteViewShadowNode::layout(layoutContext);
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <folly/Optional.h>
|
||||
#include <react/components/text/ParagraphMeasurementCache.h>
|
||||
#include <react/components/text/ParagraphProps.h>
|
||||
#include <react/components/text/ParagraphState.h>
|
||||
#include <react/components/text/TextShadowNode.h>
|
||||
#include <react/components/view/ConcreteViewShadowNode.h>
|
||||
#include <react/core/ConcreteShadowNode.h>
|
||||
|
@ -20,7 +21,7 @@
|
|||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
extern const char ParagraphComponentName[];
|
||||
extern char const ParagraphComponentName[];
|
||||
|
||||
using ParagraphEventEmitter = ViewEventEmitter;
|
||||
|
||||
|
@ -32,7 +33,8 @@ using ParagraphEventEmitter = ViewEventEmitter;
|
|||
class ParagraphShadowNode : public ConcreteViewShadowNode<
|
||||
ParagraphComponentName,
|
||||
ParagraphProps,
|
||||
ParagraphEventEmitter>,
|
||||
ParagraphEventEmitter,
|
||||
ParagraphState>,
|
||||
public BaseTextShadowNode {
|
||||
public:
|
||||
using ConcreteViewShadowNode::ConcreteViewShadowNode;
|
||||
|
@ -45,7 +47,7 @@ class ParagraphShadowNode : public ConcreteViewShadowNode<
|
|||
/*
|
||||
* Associates a shared TextLayoutManager with the node.
|
||||
* `ParagraphShadowNode` uses the manager to measure text content
|
||||
* and construct `ParagraphLocalData` objects.
|
||||
* and construct `ParagraphState` objects.
|
||||
*/
|
||||
void setTextLayoutManager(SharedTextLayoutManager textLayoutManager);
|
||||
|
||||
|
@ -56,7 +58,7 @@ class ParagraphShadowNode : public ConcreteViewShadowNode<
|
|||
* By design, the ParagraphComponentDescriptor outlives all
|
||||
* shadow nodes, so it's safe for this to be a raw pointer.
|
||||
*/
|
||||
void setMeasureCache(const ParagraphMeasurementCache *cache);
|
||||
void setMeasureCache(ParagraphMeasurementCache const *cache);
|
||||
|
||||
#pragma mark - LayoutableShadowNode
|
||||
|
||||
|
@ -65,13 +67,13 @@ class ParagraphShadowNode : public ConcreteViewShadowNode<
|
|||
|
||||
private:
|
||||
/*
|
||||
* Creates a `LocalData` object (with `AttributedText` and
|
||||
* Creates a `State` object (with `AttributedText` and
|
||||
* `TextLayoutManager`) if needed.
|
||||
*/
|
||||
void updateLocalDataIfNeeded();
|
||||
void updateStateIfNeeded();
|
||||
|
||||
SharedTextLayoutManager textLayoutManager_;
|
||||
const ParagraphMeasurementCache *measureCache_;
|
||||
ParagraphMeasurementCache const *measureCache_;
|
||||
|
||||
/*
|
||||
* Cached attributed string that represents the content of the subtree started
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#include "ParagraphState.h"
|
||||
|
||||
#include <react/components/text/conversions.h>
|
||||
#include <react/debug/debugStringConvertibleUtils.h>
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
#ifdef ANDROID
|
||||
folly::dynamic ParagraphState::getDynamic() const {
|
||||
return toDynamic(*this);
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
|
@ -0,0 +1,52 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and its 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 <react/attributedstring/AttributedString.h>
|
||||
#include <react/textlayoutmanager/TextLayoutManager.h>
|
||||
|
||||
#ifdef ANDROID
|
||||
#include <folly/dynamic.h>
|
||||
#endif
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
/*
|
||||
* State for <Paragraph> component.
|
||||
* Represents what to render and how to render.
|
||||
*/
|
||||
class ParagraphState final {
|
||||
public:
|
||||
/*
|
||||
* All content of <Paragraph> component represented as an `AttributedString`.
|
||||
*/
|
||||
AttributedString attributedString;
|
||||
|
||||
/*
|
||||
* `TextLayoutManager` provides a connection to platform-specific
|
||||
* text rendering infrastructure which is capable to render the
|
||||
* `AttributedString`.
|
||||
*/
|
||||
SharedTextLayoutManager layoutManager;
|
||||
|
||||
#ifdef ANDROID
|
||||
ParagraphState(
|
||||
AttributedString const &attributedString,
|
||||
SharedTextLayoutManager const &layoutManager)
|
||||
: attributedString(attributedString), layoutManager(layoutManager) {}
|
||||
ParagraphState() = default;
|
||||
ParagraphState(folly::dynamic const &data) {
|
||||
assert(false && "Not supported");
|
||||
};
|
||||
folly::dynamic getDynamic() const;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
|
@ -5,21 +5,18 @@
|
|||
|
||||
#include <folly/dynamic.h>
|
||||
#include <react/attributedstring/conversions.h>
|
||||
#include <react/components/text/ParagraphLocalData.h>
|
||||
#include <react/components/text/ParagraphState.h>
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
#ifdef ANDROID
|
||||
|
||||
inline folly::dynamic toDynamic(const ParagraphLocalData ¶graphLocalData) {
|
||||
folly::dynamic newLocalData = folly::dynamic::object();
|
||||
newLocalData["attributedString"] =
|
||||
toDynamic(paragraphLocalData.getAttributedString());
|
||||
newLocalData["hash"] = newLocalData["attributedString"]["hash"];
|
||||
return newLocalData;
|
||||
inline folly::dynamic toDynamic(ParagraphState const ¶graphState) {
|
||||
folly::dynamic newState = folly::dynamic::object();
|
||||
newState["attributedString"] = toDynamic(paragraphState.attributedString);
|
||||
newState["hash"] = newState["attributedString"]["hash"];
|
||||
return newState;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace react
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
#include <react/attributedstring/AttributedString.h>
|
||||
#include <react/attributedstring/TextAttributes.h>
|
||||
#include <react/attributedstring/primitives.h>
|
||||
#include <react/components/text/ParagraphLocalData.h>
|
||||
#include <react/components/text/ParagraphState.h>
|
||||
#include <react/components/text/conversions.h>
|
||||
|
||||
namespace facebook {
|
||||
|
@ -21,7 +21,7 @@ namespace react {
|
|||
#ifdef ANDROID
|
||||
|
||||
TEST(ParagraphLocalDataTest, testSomething) {
|
||||
auto attString = AttributedString();
|
||||
auto attributedString = AttributedString();
|
||||
auto fragment = AttributedString::Fragment();
|
||||
fragment.string = "test";
|
||||
|
||||
|
@ -35,10 +35,10 @@ TEST(ParagraphLocalDataTest, testSomething) {
|
|||
fragment.textAttributes = text;
|
||||
attString.prependFragment(fragment);
|
||||
|
||||
auto paragraphLocalData = ParagraphLocalData();
|
||||
paragraphLocalData.setAttributedString(attString);
|
||||
auto paragraphState = ParagraphState{};
|
||||
paragraphLocalData.attributedString = attributedString;
|
||||
|
||||
auto result = toDynamic(paragraphLocalData)["attributedString"];
|
||||
auto result = toDynamic(paragraphState)["attributedString"];
|
||||
|
||||
assert(result["string"] == fragment.string);
|
||||
auto textAttribute = result["fragments"][0]["textAttributes"];
|
||||
|
|
Загрузка…
Ссылка в новой задаче