From 24c95d19139d3ab3744df25594e7d69a3e5faf81 Mon Sep 17 00:00:00 2001 From: Nick Gerleman Date: Fri, 28 Oct 2022 21:24:25 -0700 Subject: [PATCH 01/11] RFC: Vision for Layout Conformance/Parity This adds a document outlining our long-term vision for adding new layout features to React Native, while moving the ecosystem towards web compliant behavior. It is a long-term, relatively ambitious plan, that we intend to make concrete progress on over the next several months. Feedback on what parts folks agree with, want, or don't want, are welcome. --- ...-layout-conformance-capabilities-vision.md | 241 ++++++++++++++++++ 1 file changed, 241 insertions(+) create mode 100644 proposals/0537-layout-conformance-capabilities-vision.md diff --git a/proposals/0537-layout-conformance-capabilities-vision.md b/proposals/0537-layout-conformance-capabilities-vision.md new file mode 100644 index 00000000..4b8ca089 --- /dev/null +++ b/proposals/0537-layout-conformance-capabilities-vision.md @@ -0,0 +1,241 @@ + +# Vision for Layout Conformance/Parity + +React Native models its layout and styling support after web browsers, offering a subset of CSS features. Some CSS properties like color are mapped to functionality in the backing UI framework. Sizing, positioning, and general layout is handled by the Yoga layout engine. This intersection gives web developers a familiar experience when working in React Native, but also behaves similarly enough to enable code-sharing, as supported by projects like react-native-web. + +There are gaps in what React Native supports, with “CSS Features” being the [#1 request](https://github.com/react-native-community/discussions-and-proposals/discussions/528?sort=top#discussioncomment-3886000) for in a recent survey to the community over the state of React Native. This intertwines with asks for us to invest in Yoga, which has been [inactive](https://github.com/facebook/yoga/issues/1151) in OSS. Flexbox support has had limitations akin to targeting [Internet Explorer 9](http://caniuse.com/?search=column-gap). We also hear a desire for more consistent behavior of existing behaviors with web. This document outlines a set of problems, strategies, and solutions, for building out the intertwined problems of layout conformance, and layout parity. + +## Where are the differences? + +Differences between layout in RN vs web can roughly be categorized into: + +1. **Algorithm Differences:** Given the same styles, normalized for defaults, React Native may still produce a different layout from web browsers. An example of this is a Yoga flag `UseLegacyStretchBehaviour`, where for backwards compatibility, React Native today intentionally diverges from web spec. +2. **Different default behavior:** A new box in react-native is given different [default style properties](https://reactnative.dev/docs/flexbox#flex) than a box on web. E.g. items flow in a column by default instead of a row. Standalone Yoga allows controlling some of these via a `UseWebDefaults` configuration flag, and existing frameworks like `react-native-web` bridge the gap by setting React Native’s default [styles](https://github.com/necolas/react-native-web/blob/dee258ae02188befca4192ea502d4fbebc478341/packages/react-native-web/src/exports/View/index.js#L157) on each View. +3. **Capabilities:** Browser-makers continually add support for new layout capabilities to CSS. This includes new layout systems like CSS grid, but also continual [revisions](https://www.w3.org/TR/css-align-3/) standards which form the basis of Flexbox (e.g. for row-gap and column-gap). + +Where new capabilities are additive, changing default behavior, or existing layout algorithms would affect the way existing components renders. Even if the new behavior is correct, we must be conscious to preserve compatibility with the vast ecosystem of existing React Native components. + +## Strict layout + +Fixing algorithm behaviors has often caused unintended changes when performed at the scale of large applications. This requires the ability to control layout behavior in a more confined context. A flexible solution for this problem is the introduction of a `` component which allows opting its children into more-correct layout behaviors. + +```jsx +import {StrictLayout} from 'react-native'; + + + {...} + +``` + +This style of component has downsides. React encourages encapsulation, where individual components don’t have to reason about the tree above or around them. If `StrictLayout` were to radically shift behavior, it would require component authors to reason about more state outside of their component and negatively impact developer experience. For this reason `StrictLayout` **does not** change the default styles of a component tree. It instead is focused on algorithm correctness, and will only cause changes where components were previously relying on out-of-spec behavior. We will also try to alert users where their component rendering is reliant on out-of-spec behavior, and attempt to offer actionable guidance (see “Migration Hints” below). + +### Usage + +Existing apps or shared components targeting both web and mobile can safely opt-into stricter conformance layout algorithms, since any existing layout must render correctly on web. A `strict` property is present, which allows opting a component subtree into a set of [multiple behavior changes](https://fb.quip.com/l9ibAMvt6Bgu#temp:C:fMOd3c9cc6ceae04319be44e809c) to align closer to web algorithms: + +```jsx +// Shared surfaces/components can be authored with consistent rendering + + + {...} + + +``` + +There are several cases where an app otherwise using strict layout may want to opt certain trees into classic layout behavior. This can be useful both as a tool for incremental migration (starting by disabling strict layout where it causes differences), cases where code may be unable to be changed (e.g. third-party components), or as a tool to unblock fixing new algorithm issues (see “Staging” below). `LayoutMode` should offer an API which allows opting out of either all strict layout changes, or individual changes (especially useful for large migrations). + +```jsx +import CruftView from '@react-native-community/cruft-view' + +// Force fully classic rendering and disable migration hints + + + + +// Disable a single behavior change and its migration hints + + + +``` + +### Staging + +There is more than a single conformance change that we would like to make, and we are likely to continually discover new places where we diverge from browsers. This means strict layout may continually evolve, and continue to make new breaking changes. This poses a risk to the community if we were to release `StrictLayout` before we have integrated a full set of changes, since someone who adopts strict layout may need to battle repeated breaking changes. + +We should instead treat `StrictLayout` as an unstable API, then coalesce the changes to an eventual point where it becomes official. + +```jsx +// Treat StrictLayout as unstable until we have a fuller set of breaks +import {unstable_StrictLayout as StrictLayout} from 'react-native' +``` + +### Implementation + +`StrictLayout` and `ClassicLayout` would internally change the `YGConfig` used to layout individual Yoga nodes. The most valuable implementation is in Fabric, where this code is shared between all platforms. A custom shadow node would have access to all child Yoga nodes, so a `LayoutMode` ShadowNode may traverse its full set of children to change Yoga node configuration before the root is laid out. + +For platforms where Fabric is further out (e.g. desktop), this could still be implemented, but the implementation would need to be per-platform. + +## Handling different default styles + +Changing existing default styles would be an incredibly disruptive change, breaking compatibility with all existing RN components, and making developers need to reason about two sets of rules within the same set of primitives. A separate approach is to define defaults in a higher level component, which allows local reasoning. + +```jsx +// Defaults to flexDirection: 'column' + + +// Defaults to flexDirection: 'row' +
+``` + +This direct approach of defining this translation in JS has potential to tangibly increased memory usage. ShadowNodes are pay-for-play in terms of number of properties, and while Yoga node stylesheets may be in the future (see below). This could be mitigated by new internal APIs to allow switching to web defaults on the level of a Yoga node explicitly specifying style properties at the component level. + +## Fixing the ecosystem + +Some projects, like those already being shared with web, can migrate to strict layout safely and quickly. Others will require some amount of work, which may not be immediately valuable to their usages. This creates a situation where without incentives, strict layout would be likely to fragment the ecosystem in a way that causes pain for developers. + +Aspirationally, we should aim to eventually make strict layout mode the default of react-native. Apart from being a more expected behavior it unlocks new opportunities for layout engine usage (see “Betting on Yoga” below). We must take steps to create a critical mass of usage in currently active projects. We can do this by making it easy to fix code which depends on non-conforming layout, and to provide tangible benefits for doing so. + +### Traceable styles + +It is not possible to statically reason about whether a given style will render differently under strict layout. We can instead rely on runtime feedback from the underlying JS engine. We can add an API to Yoga like `YGNodeAffectedByQuirk()` to query if the engine made choices based on legacy behavior. E.g. on branching to `UseLegacyStretchBehaviour` we can calculate whether the different behavior will lead to a visible difference, and cache that on the yoga node within an existing flags buffer. + +The Yoga Node attached to a Shadow Node is far enough away from the JS source defining a style that we need a method to correlate the two. This can be solved by a Babel transform, which inserts a correlation ID into each style, forwarded to the underlying Yoga Node. This ID can be mapped in the bundle to source location. This has a negative effect on bundle size, but should be possible to add to development mode bundles, as a debugging feature. + +The below shows a structure the babel transform could replicate: + +```jsx +// Original stylesheet +const styles = StyleSheet.create({ + widget: { + flex: 1, + } +}); + +// After babel transform +let styles = StyleSheet.create({ + widget: { + flex: 1, + } +}); +styles = StyleSheet.compose(styles, {_creationOrigin: 123}) + + +// Style calculated by function + + +// After babel transform + + +// Compound style + + +// After babel transform + +``` + +### Migration hints + +Traceable styles let us point to what style acts differently under strict layout. React Native uses LogBox warnings for providing this sort of information to developers, but we must take care not to make them spammy or inactionable. This can be mitigated by: + +1. Measuring the occurrence of these warnings internally, before rolling out (they should be relatively rare) +2. Disable the warnings if a user explicitly opts into classic layout (such as for abandoned third-party components) + +>**Warning** +> +>A component was laid out with behavior incompatible with W3C Flexbox. See >more at https://reactnative.dev/docs/strict-layout. +> +>Issue: React Native stretched your component along the main axis. +>Fix: Add `flexGrow: 1` to your style if this was intentional or enable `` to opt into W3C behavior (no stretching). +> +>View: Widget.js:123 +>Style: Widget.js:60 + +### Capability Lockout + +Future layout capabilities may depend on using an engine without the quirks of Yoga. We can enable this future flexibility, and encourage migration (avoid splitting the ecosystem) by requiring StrictLayout to use the new capabilities we add. + +>**Error** +> +>`display: 'grid'` is only supported when using strict layout mode. See more at https://reactnative.dev/docs/strict-layout. +> +>View: Widget.js:123 +>Style: Widget.js:60 + +## Betting on Yoga (Alternative Choices) + +React Native, and much of the rest of the OSS ecosystem rely on Yoga. Yoga has been in maintenance for the past few years, with the originally owning team not engaging with the community over the last few years. Yoga has had contributors who file issues, and have submit PRs fixing conformance issues (e.g. fixing stale measurements), and adding whole new features (e.g. `gap`/`rowGap`/`columnGap`). + +Beyond adding new capabilities directly, we have a long road to enable a technical and social environment which allows contributions to Yoga. We need to fixup the tools used by OSS to build changes against Yoga, and be meaningfully responsive to incoming changes and issues. This is a huge undertaking, that we think is worth it not just for React Native, but the broader community using Yoga. This was compared against several alternatives: + +### Yoga 2 (flexlayout) + +Yoga 2/flexlayout (not to be confused with a popular set of Yoga bindings also named FlexLayout) is a currently closed source spiritual successor to Yoga, developed by Yoga’s owning team. It is undergoing active rollout within Meta, being used internally for [ComponentKit](https://componentkit.org/), and soon [Litho](https://fblitho.com/). It is derived from Yoga, but offers a simplified Modern C++ codebase, and a programming model which lets the consuming application define its own node structure (Data can be embedded into the ShadowNode instead of a separate Yoga Node tree). Aligning to it would allow unifying resources between teams, which is usually a positive. + +Despite these advantages, we’ve chosen not to prioritize migration to Yoga 2. Its future roadmap and maintenance is uncertain as is its role in OSS. It has not shown performance benefits over Yoga, and does not currently implement new features. It is still being stabilized, and is not yet at full parity which Yoga (e.g. as of writing, the `flex` shorthand is unsupported). Some of the goals behind Yoga 2 conflict with the goals of React Native. Yoga 2 was built for environments with a high sensitivity to binary size, where we are more interested in adding new complexity, negatively impacting that goal. Yoga 2 does not support code which assumes the bugs and legacy flags of Yoga 1, and we would need to implement changes in the engine to support the current RN ecosystem. Migration in RN would itself be a very large effort blocking enablement of the innovations we would like. We will continue to reevaluate usage of Yoga 2 as it matures, and our ecosystem becomes more compliant, but should not block improving React Native and our ecosystem in the meantime. + +### Browser engines + +It is tempting to try to reuse an already developed styling engine from a browser. Major advantages are conformance and capabilities, but these are tied to internals of each browser, and add a large footprint and complexity that is undesirable. We would also need to build in Yoga bug compatibility. It would effectively entail rebuilding a new layout engine, heavily forked from a one-time snapshot of a browser engine. + +### Taffy + +[Taffy](https://github.com/DioxusLabs/taffy) is a Flexbox layout engine written in Rust, authored by Emil Sjölander, a main contributor of Yoga. It is seeing active development under new hands, and has some capabilities that Yoga doesn’t (e.g. it recently added `align-items: 'space-evenly'`). It does not have bug compatibility with the existing RN ecosystem, its rollout/production usage is unknown, and being owned outside of Meta limits our ability to direct the engine in ways which are targeted towards RN’s use-cases. + +### Platform-specific controls + +Platform-holders like Microsoft and Google have looked at (or have) implemented their own FlexBox controls, such as `google/FlexboxLayout`. For cases where these controls may be made in-box, we get to punt on a lot of complexity, and make React Native apps smaller. Not all platforms have native flexbox controls though, they do not match the set of capabilities we want, and they do not have bug compatibility or Meta ownership. + +## Validating conformance + +We know about some subset of conformance issues, but there are likely to be more, and as we add new capabilities, we must be systematic in ensuring a correct implementation. Browsermakers share a set of tests for validating conformance called [WPT (Web Platform Tests)](https://github.com/web-platform-tests/wpt/tree/master/css). These have already been leveraged by React Native for pointer events, by porting the HTML to React Native. An alternative to porting the code may be to rely on Yoga’s existing capabilities of generating unit test derived from how Chrome lays out HTML fixtures. + +## Specific W3C conformance issues + +While we are likely to discover more conformance issues (and there are pending issues and PRs on GitHub that should be examined), the below list targets some of the issues that have been observed by framework authors, and individual developers: + +1. **`UseLegacyStretchBehaviour`:** A Yoga configuration flag set by react-native for bug compatibility, which may incorrectly stretch an items flex-basis, even when told not to grow. It has been a source of multiple reports of different behavior between browsers and RN, and does not require additional implementation within the layout engine. +2. **Stale flex basis:** Yoga does not correctly invalidate flex basis after it changes. A fix for this was added, gated behind `YGExperimentalWebFlexBasis`, but there are concerns over its correctness. A long running issue with text truncation in a large Meta application was root-caused to this issue. An existing [pull request](https://github.com/facebook/yoga/pull/1017)may offer a fix. +3. **Box-sizing:** While not strictly related to Yoga, react-native offers a box-sizing similar, but reportedly not quite in line with `box-sizing: 'border-box'`. More investigation is needed into the exact behavior. +4. **Two-pass flexible item resolution:** Yoga [deviates](https://github.com/facebook/yoga/blob/5dd33acc912711c599250e3533b07c732de503ee/yoga/Yoga.cpp#L2365) from the W3C spec on how the lengths of flexible items are resolved, implementing a simpler/more performant algorithm. +5. **Content-based minimum size:** Yoga intentionally [does not](https://github.com/facebook/yoga/blob/5dd33acc912711c599250e3533b07c732de503ee/yoga/Yoga.cpp#L2662-L2665)assign a minimum size to flexible items in deviation from the flexbox spec, for performance reasons. +6. **Min/Max in flexible items:** At least according to [in-code documentation](https://github.com/facebook/yoga/blob/5dd33acc912711c599250e3533b07c732de503ee/yoga/Yoga.cpp#L2666-L2667), Yoga does not respect min/max size constraints on the main axis for flexible items. Because of a lack of support this is unlikely to affect existing RN code, but affects code ported from web. +7. **Differences in circular dependencies:** Yoga handles styles differently from browsers when a parent is sized based on content, and a child is sized based on its parent. This was guessed to be the cause of layout differences when porting code using Yoga previously to web (Meta employees see [this link](https://fb.workplace.com/groups/yogalayout/posts/7192992174106050/?comment_id=7197040323701235)). + +## Synchronous Layout + +While not a W3C conformance issue, React Native doesn’t expose the DOMs methods of synchronous layout, which bleeds into differences in the React programming model. React has both “effects“ and ”layout effects”. On the web, effects (e.g. code in `useEffect`) are executed after the component has been laid out and painted. Layout effects are executed directly after DOM mutation, and block painting. In React Native, both effects and layout effects are executed in parallel with layout and painting. This limits the ability for components to synchronously measure components, or programmatically respond to layout changes, without relying on first committing them to screen. Layout computation is not thread affined today (it can happen off the UI thread). A solution for this is to allow synchronously running layout on the JS thread. This was previously attempted, but had (possibly mitigable) performance concerns when measured. + +## Choosing the capabilities to build + +React Native does not implement the full set of browser CSS features. Apart from higher level concepts like stylesheets, selectors, and cascading (which can largely be supplanted by CSS-in-JS solutions shared between RN and browser), React Native doesn’t implement all style properties. + +It’s clear there is a desire for more capabilities, but there is a question of which should be added. React Native should enable skills to be transferable, offer a stellar developer experience, and enable substantial code-sharing (while being leaner than a browser). A natural conflict is whether to prioritize building for compatibility (existing usages), or for developer experience. Given the capability lockout strategy, ecosystem traction is dependent on building out features developers would like to use, in their existing React Native projects. + +With the initial focus of building for developer experience, instead of compatibility, we need input on what the community cares about. We can derive a lot of this from asking directly, but should be opportunistic in our choices, accounting for implementation complexity. + +## Mitigating Bloat + +Yoga internally represents a stylesheet as a packed structure of all possible properties. This structure is already 192 bytes, scaling with each additional Yoga Node. As we add more styles, this could expand. Doubling the number of styles on a tree of 20,000 nodes would increase memory consumption by almost 4MB, a huge amount for some of the devices React Native targets. We should measure, and potentially switch YGStyle to a data structure which is pay-for-play in number of properties. This shift would be performance sensitive, but theoretically quick data structures exist (e.g. a bitfield header with a small-vector for larger values). + +## Example capabilities + +The following is a non-exhaustive list of capabilities where Yoga lags browsers. We should consult specs used by yoga (CSS Box Alignment, CSS Box Sizing, CSS Flexbox, etc) for a more exhaustive list. + +1. **`display: grid`:** CSS Grid is highly used in responsive designs on the modern web, allowing some layouts which are hard or not possible to express with Flexbox. It is one of the most requested additions, but has one of the highest implementation cost of the listed examples. +2. **`display: inline/block/table/ruby`:** Yoga treats text as inline, but other nodes act as `display: flex`. The listed display modes could help compatibility, but Flexbox has superseded much of their usage. +3. **`display: contents`:** Useful for composing boxes which should not alter child layout (e.g. embedding event handlers)`.` +4. **`position: fixed/sticky`:** React native does not support `position: fixed` or `position: sticky`. React Native’s closest API is `stickyHeaderIndices`, which allows top-level ScrollView items to be sticky. +5. **`box-sizing`:** React Native does not support specifying box-sizing, and anecdotally is closest to but does not fully conform to `border-box`. implementing box-sizing allows new modes which may be conformant. +6. **`align-content: space-evenly`:** Yoga does not supported `space-evenly` as a value for flexbox alignment. +7. **`place-content`:** Shorthand for `align-content` and `justify-content`. Trivial to add but lower value. It raises a question on memory tradeoffs, and if we should aim to avoid properties, or make the per-node style dictionary sparser). +8. **`inset:`** Shortland for top/left/bottom/right (similar considerations to `place-contents` as a shorthand property +9. **Viewport based units `(vmin, vh, vw, etc)`:** React Native + Yoga does not support units derived from viewport/root node size. +10. **Font based units `(em, rem, etc)`:** React Native + Yoga does not support units derived from the size of the current font. Configurable `fontSize` in React Native is currently confined to text components, and will not cascade. Its pixel value would then be scaled by `fontSize` if set on a Text component or by system default font if unset on Text, or on a View. +11. **Percentages in more places:** Some existing functionality like gap is implemented with support for pixels, but are missing support for percentage. +12. **`min-content`:** As part of not supporting content-based minimum sizing, the `min-content` keyword is not supported. + +## Other styling gaps + +This document focuses specifically on layout, but there are other gaps in styling between React Native and browsers. Common examples are in `box-shadow` , `filter`, `transform`, `mask`, and `clip-path`. We should evaluate the complexity of implementing each, for the underlying native platforms which they would interact with. + + From f5d557ae35b354e19a031c8dd4c9b280d095f4ff Mon Sep 17 00:00:00 2001 From: Nick Gerleman Date: Fri, 28 Oct 2022 21:25:24 -0700 Subject: [PATCH 02/11] Rename 0537-layout-conformance-capabilities-vision.md to 0540-layout-conformance-capabilities-vision.md --- ...s-vision.md => 0540-layout-conformance-capabilities-vision.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename proposals/{0537-layout-conformance-capabilities-vision.md => 0540-layout-conformance-capabilities-vision.md} (100%) diff --git a/proposals/0537-layout-conformance-capabilities-vision.md b/proposals/0540-layout-conformance-capabilities-vision.md similarity index 100% rename from proposals/0537-layout-conformance-capabilities-vision.md rename to proposals/0540-layout-conformance-capabilities-vision.md From e710343e901a85d70b4f072d7ae626431550edb3 Mon Sep 17 00:00:00 2001 From: Nick Gerleman Date: Sun, 30 Oct 2022 21:41:57 -0700 Subject: [PATCH 03/11] Update 0540-layout-conformance-capabilities-vision.md --- ...-layout-conformance-capabilities-vision.md | 78 +++++++++---------- 1 file changed, 37 insertions(+), 41 deletions(-) diff --git a/proposals/0540-layout-conformance-capabilities-vision.md b/proposals/0540-layout-conformance-capabilities-vision.md index 4b8ca089..e42e3304 100644 --- a/proposals/0540-layout-conformance-capabilities-vision.md +++ b/proposals/0540-layout-conformance-capabilities-vision.md @@ -1,9 +1,9 @@ # Vision for Layout Conformance/Parity -React Native models its layout and styling support after web browsers, offering a subset of CSS features. Some CSS properties like color are mapped to functionality in the backing UI framework. Sizing, positioning, and general layout is handled by the Yoga layout engine. This intersection gives web developers a familiar experience when working in React Native, but also behaves similarly enough to enable code-sharing, as supported by projects like react-native-web. +React Native models its layout and styling support after web browsers, offering a subset of CSS features. Some CSS properties like color are mapped to functionality in the backing UI framework. Sizing, positioning, and general layout is handled by the Yoga layout engine. This intersection gives web developers a familiar experience when working in React Native, but also behaves similarly enough to web to enable code-sharing, as supported by projects like react-native-web. -There are gaps in what React Native supports, with “CSS Features” being the [#1 request](https://github.com/react-native-community/discussions-and-proposals/discussions/528?sort=top#discussioncomment-3886000) for in a recent survey to the community over the state of React Native. This intertwines with asks for us to invest in Yoga, which has been [inactive](https://github.com/facebook/yoga/issues/1151) in OSS. Flexbox support has had limitations akin to targeting [Internet Explorer 9](http://caniuse.com/?search=column-gap). We also hear a desire for more consistent behavior of existing behaviors with web. This document outlines a set of problems, strategies, and solutions, for building out the intertwined problems of layout conformance, and layout parity. +There are gaps in what React Native supports, with “CSS Features” being the [#1 request](https://github.com/react-native-community/discussions-and-proposals/discussions/528?sort=top#discussioncomment-3886000) in a recent survey to the community over the state of React Native. This intertwines with asks for us to invest in Yoga, which has been [inactive](https://github.com/facebook/yoga/issues/1151). Flexbox support in React Native has had limitations akin to targeting [Internet Explorer 9](http://caniuse.com/?search=column-gap). We also hear a desire for more consistent behavior of existing behaviors with web. This document outlines a set of problems, strategies, and solutions, for building out the intertwined problems of layout conformance, and layout parity. ## Where are the differences? @@ -27,11 +27,11 @@ import {StrictLayout} from 'react-native'; ``` -This style of component has downsides. React encourages encapsulation, where individual components don’t have to reason about the tree above or around them. If `StrictLayout` were to radically shift behavior, it would require component authors to reason about more state outside of their component and negatively impact developer experience. For this reason `StrictLayout` **does not** change the default styles of a component tree. It instead is focused on algorithm correctness, and will only cause changes where components were previously relying on out-of-spec behavior. We will also try to alert users where their component rendering is reliant on out-of-spec behavior, and attempt to offer actionable guidance (see “Migration Hints” below). +This style of component has downsides. React encourages encapsulation, where individual components don’t have to reason about the tree above or around them. If `StrictLayout` were to radically shift behavior, it would require component authors to reason about more state outside of their component and negatively impact developer experience. For this reason `StrictLayout` **does not** change the default styles of a component tree. It instead is focused on algorithm correctness, and will only cause changes where components were previously relying on behavior divergent from browsers. After StrictMode is [stable](#staging), we will start flagging to developers where their component rendering is reliant on out-of-spec behavior, and attempt to offer actionable guidance (see “Migration Hints” below). ### Usage -Existing apps or shared components targeting both web and mobile can safely opt-into stricter conformance layout algorithms, since any existing layout must render correctly on web. A `strict` property is present, which allows opting a component subtree into a set of [multiple behavior changes](https://fb.quip.com/l9ibAMvt6Bgu#temp:C:fMOd3c9cc6ceae04319be44e809c) to align closer to web algorithms: +Existing apps or shared components targeting both web and mobile can safely get wins from glovally opting into stricter layout algorithms, since any existing layout must render correctly on web. A `` component allows opting a component subtree into a continually growing [set of changes](#specific-w3c-conformance-issues) to align closer to web algorithms: ```jsx // Shared surfaces/components can be authored with consistent rendering @@ -42,22 +42,6 @@ Existing apps or shared components targeting both web and mobile can safely opt- ``` -There are several cases where an app otherwise using strict layout may want to opt certain trees into classic layout behavior. This can be useful both as a tool for incremental migration (starting by disabling strict layout where it causes differences), cases where code may be unable to be changed (e.g. third-party components), or as a tool to unblock fixing new algorithm issues (see “Staging” below). `LayoutMode` should offer an API which allows opting out of either all strict layout changes, or individual changes (especially useful for large migrations). - -```jsx -import CruftView from '@react-native-community/cruft-view' - -// Force fully classic rendering and disable migration hints - - - - -// Disable a single behavior change and its migration hints - - - -``` - ### Staging There is more than a single conformance change that we would like to make, and we are likely to continually discover new places where we diverge from browsers. This means strict layout may continually evolve, and continue to make new breaking changes. This poses a risk to the community if we were to release `StrictLayout` before we have integrated a full set of changes, since someone who adopts strict layout may need to battle repeated breaking changes. @@ -71,9 +55,9 @@ import {unstable_StrictLayout as StrictLayout} from 'react-native' ### Implementation -`StrictLayout` and `ClassicLayout` would internally change the `YGConfig` used to layout individual Yoga nodes. The most valuable implementation is in Fabric, where this code is shared between all platforms. A custom shadow node would have access to all child Yoga nodes, so a `LayoutMode` ShadowNode may traverse its full set of children to change Yoga node configuration before the root is laid out. +`StrictLayout` and `ClassicLayout` would internally change the `YGConfig` used to layout individual Yoga nodes. The most valuable implementation is in Fabric, where this code is shared between all platforms. A custom shadow node would have access to all child Yoga nodes, so a single `RCTLayoutConfig` ShadowNode may traverse its full set of children to change Yoga node configuration before the root is laid out. -For platforms where Fabric is further out (e.g. desktop), this could still be implemented, but the implementation would need to be per-platform. +Where Fabric is potentially further out (e.g. out-of-tree platforms), this set of changes could still be implemented, but the implementation would need to be per-platform. ## Handling different default styles @@ -82,22 +66,40 @@ Changing existing default styles would be an incredibly disruptive change, break ```jsx // Defaults to flexDirection: 'column' - +``` +```jsx // Defaults to flexDirection: 'row'
``` -This direct approach of defining this translation in JS has potential to tangibly increased memory usage. ShadowNodes are pay-for-play in terms of number of properties, and while Yoga node stylesheets may be in the future (see below). This could be mitigated by new internal APIs to allow switching to web defaults on the level of a Yoga node explicitly specifying style properties at the component level. +This direct approach of defining this translation in JS has potential to tangibly increased memory usage. ShadowNodes are pay-for-play in terms of number of properties, and Yoga stylesheets [may be in the future](#mitigating-bloat-to-heap-usage). This could possibly be mitigated as part of the `RCTLayoutConfig` internal interface. ## Fixing the ecosystem -Some projects, like those already being shared with web, can migrate to strict layout safely and quickly. Others will require some amount of work, which may not be immediately valuable to their usages. This creates a situation where without incentives, strict layout would be likely to fragment the ecosystem in a way that causes pain for developers. +Projects already sharing code with web can safely enable `StrictLayout` at their top-level to opt into a continuing set of fixes. Projects not previously targeting the web need some amount of intervention to safely adopt W3C compliant behaviors behaviors. Strict layout would then fragment the ecosystem if it didn't also offer benefits for existing projects only targeting Android and iOS. + +We should instead lean towards a future where components are shareable with web by default, while quarantining components which asume previous behaviors. Apart from better code-sharing, moving the bulk of the ecosystem towards tolerating W3C behavior unlocks new opportunities for [layout engine usage](#betting-on-yoga-alternative-choices). We must take steps to create a critical mass of usage in currently active projects. We can do this by making it easy to fix code which depends on non-conforming layout, and to provide tangible benefits for doing so. -Aspirationally, we should aim to eventually make strict layout mode the default of react-native. Apart from being a more expected behavior it unlocks new opportunities for layout engine usage (see “Betting on Yoga” below). We must take steps to create a critical mass of usage in currently active projects. We can do this by making it easy to fix code which depends on non-conforming layout, and to provide tangible benefits for doing so. +### Classic layout + +An app otherwise using strict layout may want to opt specific component trees into classic layout behavior. This can be useful both as a tool for incremental migration (starting by disabling strict layout where it causes differences), cases where code may be unable to be changed (e.g. third-party components), or as a tool to unblock fixing [new algorithm issues](#staging). `` then needs a negatinig counterpart `` to allows opting out of a configurable subset of changes (especially useful for large migrations). + +```jsx +// Force fully classic rendering and disable migration hints + + + +``` +```jsx +// Disable a single behavior change and its migration hints + + + +``` ### Traceable styles -It is not possible to statically reason about whether a given style will render differently under strict layout. We can instead rely on runtime feedback from the underlying JS engine. We can add an API to Yoga like `YGNodeAffectedByQuirk()` to query if the engine made choices based on legacy behavior. E.g. on branching to `UseLegacyStretchBehaviour` we can calculate whether the different behavior will lead to a visible difference, and cache that on the yoga node within an existing flags buffer. +It is not possible to statically reason about whether a given style will render differently under strict layout. We can instead rely on runtime feedback from the underlying layout engine. We can add an API to Yoga like `YGNodeAffectedByQuirk()` to query if the engine made choices based on legacy behavior. E.g. on branching to `UseLegacyStretchBehaviour` we can calculate whether the different behavior will lead to a visible difference, and cache that on the yoga node. The Yoga Node attached to a Shadow Node is far enough away from the JS source defining a style that we need a method to correlate the two. This can be solved by a Babel transform, which inserts a correlation ID into each style, forwarded to the underlying Yoga Node. This ID can be mapped in the bundle to source location. This has a negative effect on bundle size, but should be possible to add to development mode bundles, as a debugging feature. @@ -125,24 +127,18 @@ styles = StyleSheet.compose(styles, {_creationOrigin: 123}) // After babel transform - -// Compound style - - -// After babel transform - ``` ### Migration hints -Traceable styles let us point to what style acts differently under strict layout. React Native uses LogBox warnings for providing this sort of information to developers, but we must take care not to make them spammy or inactionable. This can be mitigated by: +Traceable styles let us point to what makes styles acts differently under strict layout. React Native uses LogBox warnings for providing guising information to developers, but we must take care not to make them spammy or inactionable. This can be mitigated by: -1. Measuring the occurrence of these warnings internally, before rolling out (they should be relatively rare) +1. Measuring the occurrence of these warnings silently internally, before rolling out (they should be relatively rare) 2. Disable the warnings if a user explicitly opts into classic layout (such as for abandoned third-party components) ->**Warning** +>**⚠️ Warning** > ->A component was laid out with behavior incompatible with W3C Flexbox. See >more at https://reactnative.dev/docs/strict-layout. +>A component was laid out with behavior incompatible with W3C Flexbox. See more at https://reactnative.dev/docs/strict-layout. > >Issue: React Native stretched your component along the main axis. >Fix: Add `flexGrow: 1` to your style if this was intentional or enable `` to opt into W3C behavior (no stretching). @@ -154,7 +150,7 @@ Traceable styles let us point to what style acts differently under strict layout Future layout capabilities may depend on using an engine without the quirks of Yoga. We can enable this future flexibility, and encourage migration (avoid splitting the ecosystem) by requiring StrictLayout to use the new capabilities we add. ->**Error** +>**❌ Error** > >`display: 'grid'` is only supported when using strict layout mode. See more at https://reactnative.dev/docs/strict-layout. > @@ -213,7 +209,7 @@ It’s clear there is a desire for more capabilities, but there is a question of With the initial focus of building for developer experience, instead of compatibility, we need input on what the community cares about. We can derive a lot of this from asking directly, but should be opportunistic in our choices, accounting for implementation complexity. -## Mitigating Bloat +## Mitigating bloat to heap usage Yoga internally represents a stylesheet as a packed structure of all possible properties. This structure is already 192 bytes, scaling with each additional Yoga Node. As we add more styles, this could expand. Doubling the number of styles on a tree of 20,000 nodes would increase memory consumption by almost 4MB, a huge amount for some of the devices React Native targets. We should measure, and potentially switch YGStyle to a data structure which is pay-for-play in number of properties. This shift would be performance sensitive, but theoretically quick data structures exist (e.g. a bitfield header with a small-vector for larger values). @@ -227,8 +223,8 @@ The following is a non-exhaustive list of capabilities where Yoga lags browsers. 4. **`position: fixed/sticky`:** React native does not support `position: fixed` or `position: sticky`. React Native’s closest API is `stickyHeaderIndices`, which allows top-level ScrollView items to be sticky. 5. **`box-sizing`:** React Native does not support specifying box-sizing, and anecdotally is closest to but does not fully conform to `border-box`. implementing box-sizing allows new modes which may be conformant. 6. **`align-content: space-evenly`:** Yoga does not supported `space-evenly` as a value for flexbox alignment. -7. **`place-content`:** Shorthand for `align-content` and `justify-content`. Trivial to add but lower value. It raises a question on memory tradeoffs, and if we should aim to avoid properties, or make the per-node style dictionary sparser). -8. **`inset:`** Shortland for top/left/bottom/right (similar considerations to `place-contents` as a shorthand property +7. **`place-content`:** Shorthand for `align-content` and `justify-content`. Trivial to add but has a memory const without [sparse stylesheets](](#mitigating-bloat-to-heap-usage)). +8. **`inset:`** Shortland for top/left/bottom/right (similar considerations to `place-contents` as a shorthand property) 9. **Viewport based units `(vmin, vh, vw, etc)`:** React Native + Yoga does not support units derived from viewport/root node size. 10. **Font based units `(em, rem, etc)`:** React Native + Yoga does not support units derived from the size of the current font. Configurable `fontSize` in React Native is currently confined to text components, and will not cascade. Its pixel value would then be scaled by `fontSize` if set on a Text component or by system default font if unset on Text, or on a View. 11. **Percentages in more places:** Some existing functionality like gap is implemented with support for pixels, but are missing support for percentage. From 322b1d006fddd8016ec55b9a130a829e127075d9 Mon Sep 17 00:00:00 2001 From: Nick Gerleman Date: Mon, 31 Oct 2022 00:16:13 -0700 Subject: [PATCH 04/11] Update 0540-layout-conformance-capabilities-vision.md --- ...-layout-conformance-capabilities-vision.md | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/proposals/0540-layout-conformance-capabilities-vision.md b/proposals/0540-layout-conformance-capabilities-vision.md index e42e3304..7e9c7fc1 100644 --- a/proposals/0540-layout-conformance-capabilities-vision.md +++ b/proposals/0540-layout-conformance-capabilities-vision.md @@ -27,11 +27,11 @@ import {StrictLayout} from 'react-native'; ``` -This style of component has downsides. React encourages encapsulation, where individual components don’t have to reason about the tree above or around them. If `StrictLayout` were to radically shift behavior, it would require component authors to reason about more state outside of their component and negatively impact developer experience. For this reason `StrictLayout` **does not** change the default styles of a component tree. It instead is focused on algorithm correctness, and will only cause changes where components were previously relying on behavior divergent from browsers. After StrictMode is [stable](#staging), we will start flagging to developers where their component rendering is reliant on out-of-spec behavior, and attempt to offer actionable guidance (see “Migration Hints” below). +This style of component has downsides. React encourages encapsulation, where individual components don’t have to reason about the tree above or around them. If `StrictLayout` were to radically shift behavior, it would require component authors to reason about more state outside of their component and negatively impact developer experience. For this reason `StrictLayout` **does not** change the default styles of a component tree. It instead is focused on algorithm correctness, and will only cause changes where components were previously relying on behavior divergent from browsers. After StrictMode is [stable](#staging), we will start flagging to developers where their component rendering is reliant on out-of-spec behavior, and attempt to offer [actionable guidance](#migration-hints). ### Usage -Existing apps or shared components targeting both web and mobile can safely get wins from glovally opting into stricter layout algorithms, since any existing layout must render correctly on web. A `` component allows opting a component subtree into a continually growing [set of changes](#specific-w3c-conformance-issues) to align closer to web algorithms: +Existing apps or shared components targeting both web and mobile can safely get wins from globally opting into stricter layout algorithms, since any existing layout must render correctly on web. A `` component allows opting a component subtree into a continually growing [set of changes](#specific-w3c-conformance-issues) to align closer to web algorithms: ```jsx // Shared surfaces/components can be authored with consistent rendering @@ -136,26 +136,26 @@ Traceable styles let us point to what makes styles acts differently under strict 1. Measuring the occurrence of these warnings silently internally, before rolling out (they should be relatively rare) 2. Disable the warnings if a user explicitly opts into classic layout (such as for abandoned third-party components) ->**⚠️ Warning** +> **⚠️ Warning** > ->A component was laid out with behavior incompatible with W3C Flexbox. See more at https://reactnative.dev/docs/strict-layout. +> A component was laid out with behavior incompatible with W3C Flexbox. See more at https://reactnative.dev/docs/strict-layout. > ->Issue: React Native stretched your component along the main axis. ->Fix: Add `flexGrow: 1` to your style if this was intentional or enable `` to opt into W3C behavior (no stretching). +> Issue: React Native stretched your component along the main axis. +> Fix: Add `flexGrow: 1` to your style if this was intentional or enable `` to opt into W3C behavior (no stretching). > ->View: Widget.js:123 ->Style: Widget.js:60 +> View: Widget.js:123
+> Style: Widget.js:60 -### Capability Lockout +### Restriction to conformant trees Future layout capabilities may depend on using an engine without the quirks of Yoga. We can enable this future flexibility, and encourage migration (avoid splitting the ecosystem) by requiring StrictLayout to use the new capabilities we add. ->**❌ Error** +> **❌ Error** > ->`display: 'grid'` is only supported when using strict layout mode. See more at https://reactnative.dev/docs/strict-layout. +> `display: 'grid'` is only supported when using strict layout mode. See more at https://reactnative.dev/docs/strict-layout. > ->View: Widget.js:123 ->Style: Widget.js:60 +> View: Widget.js:123
+> Style: Widget.js:60 ## Betting on Yoga (Alternative Choices) @@ -205,7 +205,7 @@ While not a W3C conformance issue, React Native doesn’t expose the DOMs method React Native does not implement the full set of browser CSS features. Apart from higher level concepts like stylesheets, selectors, and cascading (which can largely be supplanted by CSS-in-JS solutions shared between RN and browser), React Native doesn’t implement all style properties. -It’s clear there is a desire for more capabilities, but there is a question of which should be added. React Native should enable skills to be transferable, offer a stellar developer experience, and enable substantial code-sharing (while being leaner than a browser). A natural conflict is whether to prioritize building for compatibility (existing usages), or for developer experience. Given the capability lockout strategy, ecosystem traction is dependent on building out features developers would like to use, in their existing React Native projects. +It’s clear there is a desire for more capabilities, but there is a question of which should be added. React Native should enable skills to be transferable, offer a stellar developer experience, and enable substantial code-sharing (while being leaner than a browser). A natural conflict is whether to prioritize building for compatibility (existing usages), or for developer experience. [Adoption of conformant layout](#restriction-to-conformant-trees) is dependent on building out features developers would like to use, in their existing React Native projects. With the initial focus of building for developer experience, instead of compatibility, we need input on what the community cares about. We can derive a lot of this from asking directly, but should be opportunistic in our choices, accounting for implementation complexity. From 384692f5f805f65dc9eb0bcbdaad0be889f19cbc Mon Sep 17 00:00:00 2001 From: Nick Gerleman Date: Mon, 31 Oct 2022 00:25:09 -0700 Subject: [PATCH 05/11] Update 0540-layout-conformance-capabilities-vision.md --- ...-layout-conformance-capabilities-vision.md | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/proposals/0540-layout-conformance-capabilities-vision.md b/proposals/0540-layout-conformance-capabilities-vision.md index 7e9c7fc1..b0ae82b0 100644 --- a/proposals/0540-layout-conformance-capabilities-vision.md +++ b/proposals/0540-layout-conformance-capabilities-vision.md @@ -110,23 +110,24 @@ The below shows a structure the babel transform could replicate: const styles = StyleSheet.create({ widget: { flex: 1, - } + }, }); // After babel transform -let styles = StyleSheet.create({ - widget: { - flex: 1, - } +const styles = StyleSheet.create({ + widget: StyleSheet.compose( + { + flex: 1, + }, + {_creationOrigin: 123}, + ), }); -styles = StyleSheet.compose(styles, {_creationOrigin: 123}) - // Style calculated by function - +; // After babel transform - +; ``` ### Migration hints From 932c502a18aaca9507c4658e95c1f3a0f0346afc Mon Sep 17 00:00:00 2001 From: Nick Gerleman Date: Mon, 31 Oct 2022 00:32:26 -0700 Subject: [PATCH 06/11] Update 0540-layout-conformance-capabilities-vision.md --- proposals/0540-layout-conformance-capabilities-vision.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/proposals/0540-layout-conformance-capabilities-vision.md b/proposals/0540-layout-conformance-capabilities-vision.md index b0ae82b0..0bb91ffe 100644 --- a/proposals/0540-layout-conformance-capabilities-vision.md +++ b/proposals/0540-layout-conformance-capabilities-vision.md @@ -50,7 +50,7 @@ We should instead treat `StrictLayout` as an unstable API, then coalesce the cha ```jsx // Treat StrictLayout as unstable until we have a fuller set of breaks -import {unstable_StrictLayout as StrictLayout} from 'react-native' +import {unstable_StrictLayout as StrictLayout} from 'react-native'; ``` ### Implementation @@ -93,7 +93,7 @@ An app otherwise using strict layout may want to opt specific component trees in ```jsx // Disable a single behavior change and its migration hints - + ``` From e5437f2fcb0340a317a884da38e119f37cb9bcca Mon Sep 17 00:00:00 2001 From: Nick Gerleman Date: Mon, 31 Oct 2022 00:33:21 -0700 Subject: [PATCH 07/11] Rename 0540-layout-conformance-capabilities-vision.md to 0540-vision-for-layout-conformance-parity.md --- ...ies-vision.md => 0540-vision-for-layout-conformance-parity.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename proposals/{0540-layout-conformance-capabilities-vision.md => 0540-vision-for-layout-conformance-parity.md} (100%) diff --git a/proposals/0540-layout-conformance-capabilities-vision.md b/proposals/0540-vision-for-layout-conformance-parity.md similarity index 100% rename from proposals/0540-layout-conformance-capabilities-vision.md rename to proposals/0540-vision-for-layout-conformance-parity.md From 95662b015f10293851c69ec061bf1b2277ca24d1 Mon Sep 17 00:00:00 2001 From: Nick Gerleman Date: Mon, 31 Oct 2022 00:41:19 -0700 Subject: [PATCH 08/11] Update 0540-vision-for-layout-conformance-parity.md --- proposals/0540-vision-for-layout-conformance-parity.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/proposals/0540-vision-for-layout-conformance-parity.md b/proposals/0540-vision-for-layout-conformance-parity.md index 0bb91ffe..ae0e0a1d 100644 --- a/proposals/0540-vision-for-layout-conformance-parity.md +++ b/proposals/0540-vision-for-layout-conformance-parity.md @@ -191,10 +191,10 @@ We know about some subset of conformance issues, but there are likely to be more While we are likely to discover more conformance issues (and there are pending issues and PRs on GitHub that should be examined), the below list targets some of the issues that have been observed by framework authors, and individual developers: 1. **`UseLegacyStretchBehaviour`:** A Yoga configuration flag set by react-native for bug compatibility, which may incorrectly stretch an items flex-basis, even when told not to grow. It has been a source of multiple reports of different behavior between browsers and RN, and does not require additional implementation within the layout engine. -2. **Stale flex basis:** Yoga does not correctly invalidate flex basis after it changes. A fix for this was added, gated behind `YGExperimentalWebFlexBasis`, but there are concerns over its correctness. A long running issue with text truncation in a large Meta application was root-caused to this issue. An existing [pull request](https://github.com/facebook/yoga/pull/1017)may offer a fix. +2. **Stale flex basis:** Yoga does not correctly invalidate flex basis after it changes. A fix for this was added, gated behind `YGExperimentalWebFlexBasis`, but there are concerns over its correctness. A long running issue with text truncation in a large Meta application was root-caused to this issue. An existing [pull request](https://github.com/facebook/yoga/pull/1017) may offer a fix. 3. **Box-sizing:** While not strictly related to Yoga, react-native offers a box-sizing similar, but reportedly not quite in line with `box-sizing: 'border-box'`. More investigation is needed into the exact behavior. 4. **Two-pass flexible item resolution:** Yoga [deviates](https://github.com/facebook/yoga/blob/5dd33acc912711c599250e3533b07c732de503ee/yoga/Yoga.cpp#L2365) from the W3C spec on how the lengths of flexible items are resolved, implementing a simpler/more performant algorithm. -5. **Content-based minimum size:** Yoga intentionally [does not](https://github.com/facebook/yoga/blob/5dd33acc912711c599250e3533b07c732de503ee/yoga/Yoga.cpp#L2662-L2665)assign a minimum size to flexible items in deviation from the flexbox spec, for performance reasons. +5. **Content-based minimum size:** Yoga intentionally [does not](https://github.com/facebook/yoga/blob/5dd33acc912711c599250e3533b07c732de503ee/yoga/Yoga.cpp#L2662-L2665) assign a minimum size to flexible items in deviation from the flexbox spec, for performance reasons. 6. **Min/Max in flexible items:** At least according to [in-code documentation](https://github.com/facebook/yoga/blob/5dd33acc912711c599250e3533b07c732de503ee/yoga/Yoga.cpp#L2666-L2667), Yoga does not respect min/max size constraints on the main axis for flexible items. Because of a lack of support this is unlikely to affect existing RN code, but affects code ported from web. 7. **Differences in circular dependencies:** Yoga handles styles differently from browsers when a parent is sized based on content, and a child is sized based on its parent. This was guessed to be the cause of layout differences when porting code using Yoga previously to web (Meta employees see [this link](https://fb.workplace.com/groups/yogalayout/posts/7192992174106050/?comment_id=7197040323701235)). From 89b72670b3e05af0dd3a79aac5a8f68454f0e855 Mon Sep 17 00:00:00 2001 From: Nick Gerleman Date: Mon, 31 Oct 2022 00:42:58 -0700 Subject: [PATCH 09/11] Update 0540-vision-for-layout-conformance-parity.md --- proposals/0540-vision-for-layout-conformance-parity.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/0540-vision-for-layout-conformance-parity.md b/proposals/0540-vision-for-layout-conformance-parity.md index ae0e0a1d..557e5ea7 100644 --- a/proposals/0540-vision-for-layout-conformance-parity.md +++ b/proposals/0540-vision-for-layout-conformance-parity.md @@ -224,7 +224,7 @@ The following is a non-exhaustive list of capabilities where Yoga lags browsers. 4. **`position: fixed/sticky`:** React native does not support `position: fixed` or `position: sticky`. React Native’s closest API is `stickyHeaderIndices`, which allows top-level ScrollView items to be sticky. 5. **`box-sizing`:** React Native does not support specifying box-sizing, and anecdotally is closest to but does not fully conform to `border-box`. implementing box-sizing allows new modes which may be conformant. 6. **`align-content: space-evenly`:** Yoga does not supported `space-evenly` as a value for flexbox alignment. -7. **`place-content`:** Shorthand for `align-content` and `justify-content`. Trivial to add but has a memory const without [sparse stylesheets](](#mitigating-bloat-to-heap-usage)). +7. **`place-content`:** Shorthand for `align-content` and `justify-content`. Trivial to add but has a memory const without [sparse stylesheets](#mitigating-bloat-to-heap-usage). 8. **`inset:`** Shortland for top/left/bottom/right (similar considerations to `place-contents` as a shorthand property) 9. **Viewport based units `(vmin, vh, vw, etc)`:** React Native + Yoga does not support units derived from viewport/root node size. 10. **Font based units `(em, rem, etc)`:** React Native + Yoga does not support units derived from the size of the current font. Configurable `fontSize` in React Native is currently confined to text components, and will not cascade. Its pixel value would then be scaled by `fontSize` if set on a Text component or by system default font if unset on Text, or on a View. From c673d4d6d369644c9735793d40819b6c3d827915 Mon Sep 17 00:00:00 2001 From: Nick Gerleman Date: Mon, 31 Oct 2022 00:48:16 -0700 Subject: [PATCH 10/11] Update 0540-vision-for-layout-conformance-parity.md --- proposals/0540-vision-for-layout-conformance-parity.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/proposals/0540-vision-for-layout-conformance-parity.md b/proposals/0540-vision-for-layout-conformance-parity.md index 557e5ea7..7ce92275 100644 --- a/proposals/0540-vision-for-layout-conformance-parity.md +++ b/proposals/0540-vision-for-layout-conformance-parity.md @@ -144,8 +144,8 @@ Traceable styles let us point to what makes styles acts differently under strict > Issue: React Native stretched your component along the main axis. > Fix: Add `flexGrow: 1` to your style if this was intentional or enable `` to opt into W3C behavior (no stretching). > -> View: Widget.js:123
-> Style: Widget.js:60 +> View: Widget.jsx:60
+> Style: Widget.jsx:123 ### Restriction to conformant trees @@ -155,8 +155,8 @@ Future layout capabilities may depend on using an engine without the quirks of Y > > `display: 'grid'` is only supported when using strict layout mode. See more at https://reactnative.dev/docs/strict-layout. > -> View: Widget.js:123
-> Style: Widget.js:60 +> View: Widget.jsx:80
+> Style: Widget.jsx:146 ## Betting on Yoga (Alternative Choices) From 2ba2018027f3b9934fefda053ee135209ac3a640 Mon Sep 17 00:00:00 2001 From: Nick Gerleman Date: Sat, 5 Nov 2022 02:32:25 -0700 Subject: [PATCH 11/11] Apply suggestions from code review Co-authored-by: Fabio M. Costa --- proposals/0540-vision-for-layout-conformance-parity.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/proposals/0540-vision-for-layout-conformance-parity.md b/proposals/0540-vision-for-layout-conformance-parity.md index 7ce92275..7b463a63 100644 --- a/proposals/0540-vision-for-layout-conformance-parity.md +++ b/proposals/0540-vision-for-layout-conformance-parity.md @@ -76,7 +76,7 @@ This direct approach of defining this translation in JS has potential to tangibl ## Fixing the ecosystem -Projects already sharing code with web can safely enable `StrictLayout` at their top-level to opt into a continuing set of fixes. Projects not previously targeting the web need some amount of intervention to safely adopt W3C compliant behaviors behaviors. Strict layout would then fragment the ecosystem if it didn't also offer benefits for existing projects only targeting Android and iOS. +Projects already sharing code with web can safely enable `StrictLayout` at their top-level to opt into a continuing set of fixes. Projects not previously targeting the web need some amount of intervention to safely adopt W3C compliant behaviors. Strict layout would then fragment the ecosystem if it didn't also offer benefits for existing projects only targeting Android and iOS. We should instead lean towards a future where components are shareable with web by default, while quarantining components which asume previous behaviors. Apart from better code-sharing, moving the bulk of the ecosystem towards tolerating W3C behavior unlocks new opportunities for [layout engine usage](#betting-on-yoga-alternative-choices). We must take steps to create a critical mass of usage in currently active projects. We can do this by making it easy to fix code which depends on non-conforming layout, and to provide tangible benefits for doing so. @@ -132,7 +132,7 @@ const styles = StyleSheet.create({ ### Migration hints -Traceable styles let us point to what makes styles acts differently under strict layout. React Native uses LogBox warnings for providing guising information to developers, but we must take care not to make them spammy or inactionable. This can be mitigated by: +Traceable styles let us point to what makes styles acts differently under strict layout. React Native uses LogBox warnings for providing guiding information to developers, but we must take care not to make them spammy or inactionable. This can be mitigated by: 1. Measuring the occurrence of these warnings silently internally, before rolling out (they should be relatively rare) 2. Disable the warnings if a user explicitly opts into classic layout (such as for abandoned third-party components)