Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/**
* 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.
*
* @format
*/

import type * as React from 'react';

type LayoutConformanceProps = {
/**
* strict: Layout in accordance with W3C spec, even when breaking
* compatibility: Layout with the same behavior as previous versions of React Native
*/
mode: 'strict' | 'compatibility';
children: React.ReactNode;
};

export const experimental_LayoutConformance: React.ComponentType<LayoutConformanceProps>;
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/**
* 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.
*
* @flow strict-local
* @format
* @oncall react_native
*/

import StyleSheet from '../../StyleSheet/StyleSheet';
import LayoutConformanceNativeComponent from './LayoutConformanceNativeComponent';
import * as React from 'react';

type Props = $ReadOnly<{
/**
* strict: Layout in accordance with W3C spec, even when breaking
* compatibility: Layout with the same behavior as previous versions of React Native
*/
mode: 'strict' | 'compatibility',

children: React.Node,
}>;

// We want a graceful fallback for apps using legacy arch, but need to know
// ahead of time whether the component is available, so we test for global.
// This does not correctly handle mixed arch apps (which is okay, since we just
// degrade the error experience).
const isFabricUIManagerInstalled = global?.nativeFabricUIManager != null;

function LayoutConformance(props: Props): React.Node {
return (
<LayoutConformanceNativeComponent {...props} style={styles.container} />
);
}

function UnimplementedLayoutConformance(props: Props): React.Node {
if (__DEV__) {
const warnOnce = require('../../Utilities/warnOnce');

warnOnce(
'layoutconformance-unsupported',
'"LayoutConformance" is only supported in the New Architecture',
);
}

return props.children;
}

export default (isFabricUIManagerInstalled
? LayoutConformance
: UnimplementedLayoutConformance) as component(...Props);

const styles = StyleSheet.create({
container: {
display: 'contents',
},
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/**
* 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.
*
* @flow strict-local
* @format
*/

import type {HostComponent} from '../../Renderer/shims/ReactNativeTypes';
import type {ViewProps} from '../View/ViewPropTypes';

import * as NativeComponentRegistry from '../../NativeComponent/NativeComponentRegistry';

type Props = $ReadOnly<{
mode: 'strict' | 'compatibility',
...ViewProps,
}>;

const LayoutConformanceNativeComponent: HostComponent<Props> =
NativeComponentRegistry.get<Props>('LayoutConformance', () => ({
uiViewClassName: 'LayoutConformance',
validAttributes: {
mode: true,
},
}));

export default LayoutConformanceNativeComponent;
Original file line number Diff line number Diff line change
Expand Up @@ -211,11 +211,4 @@ export interface ViewProps
* Used to reference react managed views from native code.
*/
nativeID?: string | undefined;

/**
* Contols whether this view, and its transitive children, are laid in a way
* consistent with web browsers ('strict'), or consistent with existing
* React Native code which may rely on incorrect behavior ('classic').
*/
experimental_layoutConformance?: 'strict' | 'classic' | undefined;
}
Original file line number Diff line number Diff line change
Expand Up @@ -578,15 +578,6 @@ export type ViewProps = $ReadOnly<{|
*/
collapsableChildren?: ?boolean,

/**
* Contols whether this view, and its transitive children, are laid in a way
* consistent with web browsers ('strict'), or consistent with existing
* React Native code which may rely on incorrect behavior ('classic').
*
* This prop only works when using Fabric.
*/
experimental_layoutConformance?: ?('strict' | 'classic'),

/**
* Used to locate this view from native classes. Has precedence over `nativeID` prop.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -293,8 +293,6 @@ const validAttributesForNonEventProps = {

style: ReactNativeStyleAttributes,

experimental_layoutConformance: true,

// ReactClippingViewManager @ReactProps
removeClippedSubviews: true,

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -357,8 +357,6 @@ const validAttributesForNonEventProps = {
direction: true,

style: ReactNativeStyleAttributes,

experimental_layoutConformance: true,
};

// Props for bubbling and direct events
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1887,6 +1887,25 @@ declare export default typeof NativeKeyboardObserver;
"
`;

exports[`public API should not change unintentionally Libraries/Components/LayoutConformance/LayoutConformance.js 1`] = `
"type Props = $ReadOnly<{
mode: \\"strict\\" | \\"compatibility\\",
children: React.Node,
}>;
declare export default component(...Props);
"
`;

exports[`public API should not change unintentionally Libraries/Components/LayoutConformance/LayoutConformanceNativeComponent.js 1`] = `
"type Props = $ReadOnly<{
mode: \\"strict\\" | \\"compatibility\\",
...ViewProps,
}>;
declare const LayoutConformanceNativeComponent: HostComponent<Props>;
declare export default typeof LayoutConformanceNativeComponent;
"
`;

exports[`public API should not change unintentionally Libraries/Components/Pressable/Pressable.js 1`] = `
"type ViewStyleProp = $ElementType<React.ElementConfig<typeof View>, \\"style\\">;
export type StateCallbackType = $ReadOnly<{|
Expand Down Expand Up @@ -4268,7 +4287,6 @@ export type ViewProps = $ReadOnly<{|
\\"aria-hidden\\"?: ?boolean,
collapsable?: ?boolean,
collapsableChildren?: ?boolean,
experimental_layoutConformance?: ?(\\"strict\\" | \\"classic\\"),
id?: string,
testID?: ?string,
nativeID?: ?string,
Expand Down Expand Up @@ -9627,6 +9645,7 @@ declare module.exports: {
get Image(): Image,
get ImageBackground(): ImageBackground,
get InputAccessoryView(): InputAccessoryView,
get experimental_LayoutConformance(): LayoutConformance,
get KeyboardAvoidingView(): KeyboardAvoidingView,
get Modal(): Modal,
get Pressable(): Pressable,
Expand Down
7 changes: 0 additions & 7 deletions packages/react-native/React/Views/RCTViewManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -424,13 +424,6 @@ - (void)updateAccessibilityTraitsForRole:(RCTView *)view withDefaultView:(RCTVie
// filtered by view configs.
}

RCT_CUSTOM_VIEW_PROPERTY(experimental_layoutConformance, NSString *, RCTView)
{
// Property is only to be used in the new renderer.
// It is necessary to add it here, otherwise it gets
// filtered by view configs.
}

typedef NSArray *FilterArray; // Custom type to make the StaticViewConfigValidator Happy
RCT_CUSTOM_VIEW_PROPERTY(filter, FilterArray, RCTView)
{
Expand Down
1 change: 0 additions & 1 deletion packages/react-native/ReactAndroid/api/ReactAndroid.api
Original file line number Diff line number Diff line change
Expand Up @@ -4155,7 +4155,6 @@ public class com/facebook/react/uimanager/LayoutShadowNode : com/facebook/react/
public fun setInsetBlock (ILcom/facebook/react/bridge/Dynamic;)V
public fun setInsetInline (ILcom/facebook/react/bridge/Dynamic;)V
public fun setJustifyContent (Ljava/lang/String;)V
public fun setLayoutConformance (Ljava/lang/String;)V
public fun setMarginBlock (ILcom/facebook/react/bridge/Dynamic;)V
public fun setMarginInline (ILcom/facebook/react/bridge/Dynamic;)V
public fun setMargins (ILcom/facebook/react/bridge/Dynamic;)V
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -972,9 +972,4 @@ public void setShouldNotifyPointerLeave(boolean value) {
public void setShouldNotifyPointerMove(boolean value) {
// Do Nothing: Align with static ViewConfigs
}

@ReactProp(name = "experimental_layoutConformance")
public void setLayoutConformance(String value) {
// Do Nothing: Align with static ViewConfigs
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <react/renderer/components/text/ParagraphComponentDescriptor.h>
#include <react/renderer/components/text/RawTextComponentDescriptor.h>
#include <react/renderer/components/text/TextComponentDescriptor.h>
#include <react/renderer/components/view/LayoutConformanceComponentDescriptor.h>
#include <react/renderer/components/view/ViewComponentDescriptor.h>

namespace facebook::react::CoreComponentsRegistry {
Expand Down Expand Up @@ -66,6 +67,8 @@ sharedProviderRegistry() {
AndroidDrawerLayoutComponentDescriptor>());
providerRegistry->add(concreteComponentDescriptorProvider<
DebuggingOverlayComponentDescriptor>());
providerRegistry->add(concreteComponentDescriptorProvider<
LayoutConformanceComponentDescriptor>());

return providerRegistry;
}();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -342,16 +342,7 @@ BaseViewProps::BaseViewProps(
rawProps,
"removeClippedSubviews",
sourceProps.removeClippedSubviews,
false)),
experimental_layoutConformance(
ReactNativeFeatureFlags::enableCppPropsIteratorSetter()
? sourceProps.experimental_layoutConformance
: convertRawProp(
context,
rawProps,
"experimental_layoutConformance",
sourceProps.experimental_layoutConformance,
{})) {}
false)) {}

#define VIEW_EVENT_CASE(eventType) \
case CONSTEXPR_RAW_PROPS_KEY_HASH("on" #eventType): { \
Expand Down Expand Up @@ -397,7 +388,6 @@ void BaseViewProps::setProp(
RAW_SET_PROP_SWITCH_CASE_BASIC(collapsable);
RAW_SET_PROP_SWITCH_CASE_BASIC(collapsableChildren);
RAW_SET_PROP_SWITCH_CASE_BASIC(removeClippedSubviews);
RAW_SET_PROP_SWITCH_CASE_BASIC(experimental_layoutConformance);
RAW_SET_PROP_SWITCH_CASE_BASIC(cursor);
RAW_SET_PROP_SWITCH_CASE_BASIC(outlineColor);
RAW_SET_PROP_SWITCH_CASE_BASIC(outlineOffset);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,6 @@ class BaseViewProps : public YogaStylableProps, public AccessibilityProps {

bool removeClippedSubviews{false};

LayoutConformance experimental_layoutConformance{};

#pragma mark - Convenience Methods

CascadedBorderWidths getBorderWidths() const;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
* 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 <react/renderer/components/view/LayoutConformanceShadowNode.h>
#include <react/renderer/core/ConcreteComponentDescriptor.h>

namespace facebook::react {

using LayoutConformanceComponentDescriptor =
ConcreteComponentDescriptor<LayoutConformanceShadowNode>;

} // namespace facebook::react
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* 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 <react/renderer/components/view/YogaStylableProps.h>
#include <react/renderer/components/view/propsConversions.h>

namespace facebook::react {

struct LayoutConformanceProps final : public YogaStylableProps {
/**
* Whether to layout the subtree with strict conformance to W3C standard
* (YGErrataNone) or for compatibility with legacy RN bugs (YGErrataAll)
*/
LayoutConformance mode{LayoutConformance::Strict};

LayoutConformanceProps() = default;
LayoutConformanceProps(
const PropsParserContext& context,
const LayoutConformanceProps& sourceProps,
const RawProps& rawProps)
: YogaStylableProps(context, sourceProps, rawProps),
mode{convertRawProp(
context,
rawProps,
"mode",
mode,
LayoutConformance::Strict)} {}
};

} // namespace facebook::react
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* 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 <react/renderer/components/view/ConcreteViewShadowNode.h>
#include <react/renderer/components/view/LayoutConformanceProps.h>
#include <react/renderer/components/view/YogaLayoutableShadowNode.h>

namespace facebook::react {

constexpr const char LayoutConformanceShadowNodeComponentName[] =
"LayoutConformance";

using LayoutConformanceShadowNode = ConcreteShadowNode<
LayoutConformanceShadowNodeComponentName,
YogaLayoutableShadowNode,
LayoutConformanceProps>;

} // namespace facebook::react
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <react/debug/flags.h>
#include <react/debug/react_native_assert.h>
#include <react/featureflags/ReactNativeFeatureFlags.h>
#include <react/renderer/components/view/LayoutConformanceShadowNode.h>
#include <react/renderer/components/view/ViewProps.h>
#include <react/renderer/components/view/ViewShadowNode.h>
#include <react/renderer/components/view/conversions.h>
Expand Down Expand Up @@ -501,15 +502,13 @@ void YogaLayoutableShadowNode::configureYogaTree(
}

YGErrata YogaLayoutableShadowNode::resolveErrata(YGErrata defaultErrata) const {
if (auto viewShadowNode = dynamic_cast<const ViewShadowNode*>(this)) {
const auto& props = viewShadowNode->getConcreteProps();
switch (props.experimental_layoutConformance) {
case LayoutConformance::Classic:
return YGErrataAll;
if (auto layoutConformanceNode =
dynamic_cast<const LayoutConformanceShadowNode*>(this)) {
switch (layoutConformanceNode->getConcreteProps().mode) {
case LayoutConformance::Strict:
return YGErrataNone;
case LayoutConformance::Undefined:
return defaultErrata;
case LayoutConformance::Compatibility:
return YGErrataAll;
}
}

Expand Down
Loading
Loading