Skip to content

refactor(native): combine two values of a style prop in one place - #487

Open
YevheniiKotyrlo wants to merge 5 commits into
nativewind:mainfrom
YevheniiKotyrlo:refactor/one-style-combine
Open

YevheniiKotyrlo wants to merge 5 commits into
nativewind:mainfrom
YevheniiKotyrlo:refactor/one-style-combine

Conversation

@YevheniiKotyrlo

Copy link
Copy Markdown
Contributor

Problem

deepMergeConfig combines a computed style value with another one in three places, three ways:

  • important styles over the computed ones: flattened into one object;
  • an inline value over a one-segment array target ("style", "contentContainerStyle"): the inline value alone when it overrides every computed key, otherwise both in an array;
  • an inline value over a one-segment string target ({ target: "style" }): always both in an array.

So { className: "style" } and { className: { target: "style" } }, two spellings of one mapping, combine style={{ backgroundColor: "blue" }} over bg-red differently: the first gives { backgroundColor: "blue" }, the second [{ backgroundColor: "#f00" }, { backgroundColor: "blue" }]. And a new kind of style value has to be handled in all three places, as #416 does for a Pressable's callback style.

Solution

combineStyleValues(left, right, layering) is the one combination: a callback composes with the other value, a value that overrides every key of the other replaces it, and otherwise the two are flattened when this library computed both (important styles) or layered when one came from the element, since an inline style object can carry an identity a copy would lose. The three sites call it, so the string target collapses as its array spelling does; the important and array-target paths combine as before.

Tests

src/__tests__/native/className-with-style.test.tsx: both spellings of a style target, with an inline style that sets every property the class sets (it replaces the class's value) and one that sets other properties (the two are layered). On main the object form returns both values in an array where the shorthand returns the inline value alone. The existing suites hold the other two paths and #416's callback styles.

Verification

On Ubuntu with the workflow's steps - build, lint, typecheck, yarn test, node --test node/__tests__/*.mjs, both library builds, the web export, the unstaged-changes checks and commitlint - everything passes.

Not run: the iOS and Android example builds.

Merge order

…tton family

Gesture Handler's Pressable, its button family and PureNativeButton render
GestureHandlerButton, a codegen'd native view the react-native rewrite never
reaches, so className fell onto a view that declares no such prop.
DrawerLayoutAndroid wraps react-native's component, which has no styled
twin, and the Android GestureHandlerRootView renders a native view too.
react-native-css/components/react-native-gesture-handler re-declares these
with className mapped to the style each forwards, and the Metro resolver
routes react-native-gesture-handler to it. GestureHandlerRootView keeps its
flex: 1 default, which a resolved class would otherwise displace.

The resolver anchors its own-package check on the layout segment, since it
runs from src/metro under the source condition and from dist/<format>/metro
once built; a fixed level count sent this package's own components back
through the wrapper.

Pressable calls a function style with its pressed state, so the className
merge keeps a callback a callback on every merge path rather than merging it
into an array, where it never runs. The inline branch of the style-target
merge is removed: the length-one target merge after it always decides the
inline style.
…er suite

Jest's teardown reads every global, and expo's lazy fetch then loads the
renderer through the suite's react-native mock. With nativeFabricUIManager
still cleared, that throws, and on Linux Jest reports the suite as failed
to run.
…s flex:1 default

Gesture Handler's root falls back to `flex: 1` while no style is given,
and the re-declaration kept that default under every class. Yoga reads
a positive flex over an explicit or absent basis, so a root a class
sizes to its content — `grow-0`, `shrink-0`, `basis-*`, `flex-none` —
collapsed or stretched instead.

The default now yields to a class that states its own flex sizing, and
an inline style still displaces it, as Gesture Handler's own does.
… modules

The resolver computed the package root and the own-module test the babel
import plugin already computes, and its copy dropped the trailing path
separator, so a directory beside the package whose name merely begins
with dist or src counted as the package's own and its imports were left
unrewritten. Both now import one isFromThisModule.
deepMergeConfig combined a computed style value with another one three ways: flattened for
important styles, an array collapsed to the inline value when it overrides every computed key
for a one-segment array target, and a plain array for a one-segment string target. A new kind
of style value had to be taught to all three, as the callback styles were.

combineStyleValues is the one combination: a callback composes, a value that overrides every key
of the other replaces it, and otherwise the two are flattened when this library computed both or
layered when one came from the element. A one-segment string target now collapses as its array
spelling does, so `{ target: "style" }` and `"style"` combine an inline style the same way.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant