Introduces a counterpart to mapChildren. It excludes empty children just as
mapChildren for compatibility. With might introduce something like
sliceChildrenIncludingEmptyValues at some point.
I still think the semantics of flattening children is valid but we'll
want to revert the flattening implementation while we solidify the
semantics and try another approach.
This reverts flattening so that this.props.children can once again be
either a single child, flat array or nested array.
mapChildren calls flattenChildren before doing anything else. This is
not the most efficient approach but I wanted to keep this inital diff
simple. It also ignores empty values for backwards compatibility.
We may want to try another approach where empty values are included
in the map.
Validation of keys is still done inside ReactComponent. Ideally I'd
like to extract that into a separate module but to avoid cyclic
dependencies, I'm keeping it in ReactComponent for now.
A dynamic value can be provided as a key to a child. Either as part of an object
or key property. This becomes part of the component's ID.
We have to be careful to escape this key before inserting it into the DOM since
it could become a vulnerability. We fixed this by escaping just the keys.
However, the current implementation breaks when you used escaped keys. The
internal value is escaped and the value used by getAttributeNode and
getElementById are both unescaped.
This fixes that by keeping the unescaped value internally but escaping it right
before the HTML is generated (like any other attribute).
This is important since business logic IDs (that should be used as keys)
contains characters that need to be escaped.
This fixes the last known parts of the flattening experiment. This has grown to
be somewhat complex and potentially fragile because of it. We may end up
reverting flattening in the future or address it slightly differently.
The purpose of this diff is to test if we've finally understood the real world
edge cases that flattening can lead to and how we have to key components to
cover those cases.
With this commit we never rekey the internal _key property. The semantics is
that once a component passes through a composite component, it's identity is
frozen.
props.key should accept numeric values and booleans which includes 0 and false.
This fixes the truthiness check.
We should never warn about missing key properties if a component is passed as a
static child. The _key acts as a flag to determine whether this component
was checked already.
Small utility that extracts and validates that there is only a single
child passed to a React composite component. The benefit here is that we
abstract away *how* the children are actually stored while we iterate on
different approaches. This way we won't break callsites as we try different
ideas. When we settle on a final approach, all of these callsites will still
work.
React's top-level event delegation dispatches `AbstractEvent` objects that contain:
- `nativeEvent`, the original browser event.
- `data`, an object with custom normalized properties.
This diff creates a set of `DelegateEvent` classes that will replace `AbstractEvent`. The goal is two-fold:
# Provide a cross-browser implementation that conforms to the DOM Level 3 Events API so people don't have to use `nativeEvent`.
# Generalize the event object API so that it can be shared by `DOMEventManager`, a top-level event delegation WIP.
This simply implements the classes. I will follow-up by replacing `AbstractEvent` with them.
Type coersion bug and ID breaking assumption.
Names need to be wrapped in something unique since otherwise two unique siblings
can end up having IDs that are subsets of eachother.
Currently we're mutating _key. Mutation here is fine, but it needs to
be idempotent - which it's not. This is causing some issues.
Instead I reassign the _key every time it passes through a flattening.
This means that it's unique and stable for a single pass through a composite
component. When it's repassed another level, it loses it previous
identity and is rekeyed by it's new location.
For auto-generated keys by index, this actually means it has the same
semantics as before flattening.
For explicit keys, it has the effect that keys need to be unique at
every level. Regardless of how the key got there. Every component needs to ensure
that it doesn't combine keys from two different sources that may collide. This
is also inline with the old semantics but less intuitive in the new model.
flattenChildren was only using key when child.mountInContainerNode
exists, which is defined on ReactCompositeComponent, and not
ReactNativeComponent.
This uses the isValidComponent() fn to see if we should use this key.
This expects static children as additional arguments to the constructor
and flattens any array arguments one level deep.
Component(props, child1, child2, arrayOfChildren, child3) ->
.props.children = [child1, child2, ...arrayOfChildren, child3]
This can avoid an additional heap allocation for the unflat array.
It allows you to pass nested arrays and objects like you used to. Those
aren't immediately flattened. That makes this a fairly safe change.
Passing a dynamic array without key properties will yield a warning
(once). Might consider throwing later.
Once we change the transpiler to use the new syntax, you'll end up with
a single flat array in normal usage.
This doesn't actually update the JSX transform.