Skip to content

Commit

Permalink
chore: feed list data from external json
Browse files Browse the repository at this point in the history
  • Loading branch information
azimgd committed Dec 8, 2024
1 parent b1e84c3 commit 5129f78
Show file tree
Hide file tree
Showing 9 changed files with 25,076 additions and 12 deletions.
24,962 changes: 24,962 additions & 0 deletions cpp/json/json.hpp

Large diffs are not rendered by default.

95 changes: 88 additions & 7 deletions cpp/module/SLModuleSpec/SLCommitHook.cpp
Original file line number Diff line number Diff line change
@@ -1,20 +1,72 @@
#include <react/renderer/components/text/RawTextShadowNode.h>
#include "json.hpp"
#include "SLCommitHook.h"
#include "SLContainerShadowNode.h"
#include "SLElementShadowNode.h"


using namespace facebook::react;

namespace facebook::react {

int nextFamilyTag = -2;

class KeyExtractor {
public:
static std::optional<std::string> extractKey(const std::string& input) {
if (input.length() < 4) {
return std::nullopt;
}

if (input.substr(0, 2) != "{{" || input.substr(input.length() - 2) != "}}") {
return std::nullopt;
}

std::string key = input.substr(2, input.length() - 4);

if (key.find('{') != std::string::npos || key.find('}') != std::string::npos) {
return std::nullopt;
}

if (key.empty()) {
return std::nullopt;
}

return key;
}

static std::vector<std::string> extractAllKeys(const std::string& input) {
std::vector<std::string> keys;
size_t pos = 0;

while (pos < input.length()) {
size_t start = input.find("{{", pos);
if (start == std::string::npos) break;

size_t end = input.find("}}", start);
if (end == std::string::npos) break;

std::string potential_key = input.substr(start, end - start + 2);
auto key = extractKey(potential_key);

if (key) {
keys.push_back(*key);
}

pos = end + 2;
}

return keys;
}
};

auto adjustFamilyTag = [](int tag) {
const int MIN_TAG_VALUE = -2e9;
const int CLAMPED_TAG = -2;
return tag < MIN_TAG_VALUE ? CLAMPED_TAG : tag - 2;
};

ShadowNode::Shared cloneShadowNodeTree(jsi::Runtime *runtime, const ShadowNode::Shared& shadowNode)
ShadowNode::Shared cloneShadowNodeTree(jsi::Runtime *runtime, nlohmann::json* elementData, const ShadowNode::Shared& shadowNode)
{
auto const &componentDescriptor = shadowNode->getComponentDescriptor();
PropsParserContext propsParserContext{shadowNode->getSurfaceId(), *componentDescriptor.getContextContainer().get()};
Expand All @@ -25,16 +77,37 @@ ShadowNode::Shared cloneShadowNodeTree(jsi::Runtime *runtime, const ShadowNode::
*runtime,
shadowNode->getInstanceHandle(*runtime),
shadowNode->getTag());

auto const fragment = ShadowNodeFamilyFragment{nextFamilyTag, shadowNode->getSurfaceId(), instanceHandle};
auto const family = componentDescriptor.createFamily(fragment);
auto const props = componentDescriptor.cloneProps(propsParserContext, shadowNode->getProps(), {});
auto const state = componentDescriptor.createInitialState(props, family);
auto const nextShadowNode = componentDescriptor.createShadowNode(
ShadowNodeFragment{props, ShadowNodeFragment::childrenPlaceholder(), state}, family);

RawTextShadowNode::ConcreteProps* interpolatedProps;
if (shadowNode->getComponentName() == std::string("RawText")) {
const Props::Shared& nextprops = nextShadowNode->getProps();
interpolatedProps = const_cast<RawTextShadowNode::ConcreteProps*>(
static_cast<const RawTextShadowNode::ConcreteProps*>(nextprops.get())
);

try {
if (!KeyExtractor::extractKey(interpolatedProps->text).has_value()) {
throw false;
}

auto elementDataPointer = nlohmann::json::json_pointer(
"/" + KeyExtractor::extractKey(interpolatedProps->text).value()
);

if ((*elementData).contains(elementDataPointer) && (*elementData)[elementDataPointer].is_string()) {
interpolatedProps->text = (*elementData)[elementDataPointer].get<std::string>();
}
} catch (...) {}
}

for (const auto &childShadowNode : shadowNode->getChildren()) {
auto const clonedChildShadowNode = cloneShadowNodeTree(runtime, childShadowNode);
auto const clonedChildShadowNode = cloneShadowNodeTree(runtime, elementData, childShadowNode);
componentDescriptor.appendChild(nextShadowNode, clonedChildShadowNode);
}

Expand Down Expand Up @@ -83,17 +156,25 @@ RootShadowNode::Unshared SLCommitHook::shadowTreeWillCommit(
containerNodes_.begin()->second->getFamily(),
[this, rootShadowNodeChildren](const ShadowNode& oldShadowNode) {

auto containerShadowNodeProps = const_cast<SLContainerShadowNode::ConcreteProps*>(
static_cast<const SLContainerShadowNode::ConcreteProps*>(oldShadowNode.getProps().get())
);

auto containerData = std::make_shared<nlohmann::json>(nlohmann::json::parse(containerShadowNodeProps->data));

for (const auto& elementNode : elementNodes_) {
auto elementShadowNodeProps = const_cast<SLElementShadowNode::ConcreteProps*>(
static_cast<const SLElementShadowNode::ConcreteProps*>(elementNode.second->getProps().get())
);

if (elementShadowNodeProps->uniqueId == std::string("ListChildrenComponentUniqueId")) {
for (int i = 0; i < 100; ++i) {
rootShadowNodeChildren->push_back(cloneShadowNodeTree(runtime_, elementNode.second));
if ((*containerData).is_array() && elementShadowNodeProps->uniqueId == std::string("ListChildrenComponentUniqueId")) {
for (int i = 0; i < (*containerData).size(); ++i) {
auto elementDataPointer = nlohmann::json::json_pointer("/" + std::to_string(i));
auto* elementData = &(*containerData)[elementDataPointer];
rootShadowNodeChildren->push_back(cloneShadowNodeTree(runtime_, elementData, elementNode.second));
}
} else {
rootShadowNodeChildren->push_back(cloneShadowNodeTree(runtime_, elementNode.second));
// rootShadowNodeChildren->push_back(cloneShadowNodeTree(runtime_, elementData, elementNode.second));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ SLContainerProps::SLContainerProps(
const SLContainerProps &sourceProps,
const RawProps &rawProps): ViewProps(context, sourceProps, rawProps),

data(convertRawProp(context, rawProps, "data", sourceProps.data, {})),
inverted(convertRawProp(context, rawProps, "inverted", sourceProps.inverted, {})),
horizontal(convertRawProp(context, rawProps, "horizontal", sourceProps.horizontal, {})),
initialNumToRender(convertRawProp(context, rawProps, "initialNumToRender", sourceProps.initialNumToRender, {})),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class SLContainerProps final : public ViewProps {

#pragma mark - Props

std::string data;
bool inverted = false;
bool horizontal = false;
int initialNumToRender = 10;
Expand Down
2 changes: 1 addition & 1 deletion example/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
import useData from './useData';
import Element from './Element';

const ITEMS_COUNT = 10;
const ITEMS_COUNT = 5;
const IS_INVERTED = false;
const IS_HORIZONTAL = false;
const INITIAL_SCROLL_INDEX = 0;
Expand Down
15 changes: 15 additions & 0 deletions ios/SLModule.mm
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,21 @@ - (void)installJSIBindingsWithRuntime:(facebook::jsi::Runtime &)runtime
return facebook::jsi::Value::undefined();
});
runtime.global().setProperty(runtime, "__NATIVE_registerElementNode", std::move(registerElementFamily));
auto unregisterElementFamily = facebook::jsi::Function::createFromHostFunction(
runtime,
facebook::jsi::PropNameID::forAscii(runtime, "__NATIVE_unregisterElementNode"),
1,
[=](facebook::jsi::Runtime &runtime,
const facebook::jsi::Value &thisValue,
const facebook::jsi::Value *arguments,
size_t count) -> facebook::jsi::Value
{
auto shadowNode = shadowNodeFromValue(runtime, arguments[0]);
self->commitHook_->unregisterElementNode(shadowNode);

return facebook::jsi::Value::undefined();
});
runtime.global().setProperty(runtime, "__NATIVE_unregisterElementNode", std::move(unregisterContainerFamily));
}

- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const facebook::react::ObjCTurboModule::InitParams &)params
Expand Down
7 changes: 5 additions & 2 deletions src/SLContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ import SLContainerNativeComponent, {
// @ts-ignore
import ReactNativeInterface from 'react-native/Libraries/ReactPrivate/ReactNativePrivateInterface';

export type SLContainerWrapperProps = {};
export type SLContainerWrapperProps = {
data: Array<any>;
};

export type SLContainerInstance = InstanceType<
typeof SLContainerNativeComponent
Expand All @@ -23,7 +25,7 @@ export type SLContainerRef = {
};

const SLContainerWrapper = (
props: SLContainerNativeProps & SLContainerWrapperProps,
props: Omit<SLContainerNativeProps, 'data'> & SLContainerWrapperProps,
forwardedRef: React.Ref<Partial<SLContainerNativeCommands>>
) => {
const instanceRef = React.useRef<SLContainerInstance>(null);
Expand Down Expand Up @@ -62,6 +64,7 @@ const SLContainerWrapper = (
return (
<SLContainerNativeComponent
{...props}
data={JSON.stringify(props.data)}
ref={instanceRef}
style={[containerStyle, props.style]}
>
Expand Down
1 change: 1 addition & 0 deletions src/SLContainerNativeComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export type OnEndReached = {
};

export interface SLContainerNativeProps extends ViewProps {
data: string;
inverted?: boolean;
horizontal?: boolean;
initialNumToRender?: Int32;
Expand Down
4 changes: 2 additions & 2 deletions src/Shadowlist.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const invoker = (Component: Component) => {
};

export type ShadowlistProps = {
data: any[];
data: Array<any>;
renderItem: () => React.ReactElement;
keyExtractor: (item: any, index: number) => string;
contentContainerStyle?: ViewStyle;
Expand All @@ -33,7 +33,7 @@ export type ShadowlistProps = {

export const Shadowlist = React.forwardRef(
(
props: SLContainerNativeProps & ShadowlistProps,
props: Omit<SLContainerNativeProps, 'data'> & ShadowlistProps,
ref: Ref<Partial<SLContainerNativeCommands>>
) => {
/**
Expand Down

0 comments on commit 5129f78

Please sign in to comment.