-
Notifications
You must be signed in to change notification settings - Fork 50k
Description
This issue tracks tasks related to the React DOM implementation of the experimental React Events API (react-events) aka React Flare (our internal code-name for the project). The idea is to extend React's event system to include high-level events that allow for consistent cross-device and cross-platform behavior.
Note: For now this is completely experimental and won't affect the open source builds of React.
Core
- Document specific UX patterns that this enables and fixes. (inc. from my workplace post on styles, Dan & Brian dev tools, apps, etc.)
- Every user-facing event should have a
timeStamp. Should we provide a standard way to derive data that might be common across events and require different logic for different positional information, e.g., point, delta, offset, etc? - How to test discrete vs continuous events?
- Should we polyfill pointer events or not dispatch emulated touch/mouse events in the core, to avoid multiple event components needing to implement the same logic to ignore emulated events?
- Investigate native pointer capture for retargeting events - https://www.w3.org/TR/pointerevents/#pointer-capture. This could be particularly useful for drag/swipe UX.
- Limit all event components to have a single host node as child? If not enforced for all components, we might need this for Hover/Focus/Press at least.
- FYI Always use event capturing. Remove media events. #12919
- Optimize bundle output.
- Replace magic object export with
React.unstable_createEventComponent(type: Symbol | number, responder: ReactEventResponder, displayName: ?string) - Document core API for building responders
- Stop propagation by default but scope to event module types.
- Investigate ways to listen to root events without first needing to wait for a target event to be dispatched to the event component.
- Remove
listenerfrom event object passed to callbacks likeonPress - Ensure discrete events do not unnecessarily force flush previous non-discrete events.
- Ensure event responder get unmounted correctly and pending events (e.g. long press) properly get removed when doing so. Maybe an unmount lifecycle method needs adding to event responders?
- Create a new synthetic event and dispatch mechanism that relies on the event being generated in the event responder module, rather than from React. This allows for the event to be better typed and have a much simpler implementation for how React fires the event when dispatched + it means we can avoid pulling in the current SyntheticEvent system and all its dependencies.
Ownership
- Decide on prop name equivalents to RN
onStartShouldSetResponderandonMoveShouldSetResponder.
Focus module
- Determine the potential use cases for DOM
focusinandfocusoutevents. - Cross browser and device/modality testing.
- add
focusVisiblefunctionality - Add README
- Write unit tests
- disabled
- onBlur
- onFocus
- onFocusChange
- onFocusVisibleChange
- Determine event object data (might require a global "modality" tracker to help attach this info to focus/blur events)
{
pointerType: 'mouse' | 'pen' | 'touch' | 'keyboard'
}
Hover module
- Cross browser and device/modality testing.
- Determine event object data.
{
pointerType: 'mouse' | 'pen',
point: { x: number, y: number }
}
- Write unit tests (Rename hover props in experimental event API and write unit tests #15283)
- disabled
- onHoverMove
- onHoverChange
- onHoverStart
- onHoverEnd
- delayHoverStart
- delayHoverEnd
- ensure doesn't respond to emulated mouse events
- Add README
- Add
delayHoverStartanddelayHoverEndprops. - Rename events to
onHoverStart,onHoverEnd.
Press module
- Cross browser and device/modality testing.
- Behaviour for selecting text within pressable. End press on selection event? Add a new props to configure the behaviour, like
onMoveShouldEndPress? - Allow contextMenu to display when element is a link and ctrl is held down during press
- Cancel long press if active press moves (exceeding threshold, IIRC RN uses 10px delta)
- Reactivate when moving out-of-bounds press back into the responder region.
- BUG: press start -> move out of target -> release -> tap press. The second press doesn't cause
onPressStart/Changeto be called, even thought those events are dispatched to the core responder system. (Event API: Fix bug where Press root events were not being cleared #15507) - FYI:
touchAction:'none'is needed oncurrentTargetto prevent browser cancelling afterpointermove. - Prevent contextMenu appearing during a long press on touch screens.
- Account for UX involving interactions on links with modifier keys held.
- Add
pressRetentionOffsetto control when press is released after moving the pointer away from the press target. - Add README
- Always prevent default on clicks. Maybe have an override to turn off behaviour?
- Rename events to
onPressStart,onPressEnd(Rename press props in experimental event API #15263). - Change
longPressCancelsPresstoonLongPressShouldCancelPress(Rename press props in experimental event API #15263). - Change default
delayLongPressto 500ms (see note in Add tests for Press responder event module #15290) - Add keyboard support for all events.
- Prevent scroll-down page when pressing Spacebar on keyboard to interact
- Add
delayPressStartanddelayPressEndprops. - Write unit tests (Add tests for Press responder event module #15290)
- disabled
- onLongPress
- onLongPressChange
- onLongPressShouldCancelPress
- onPress
- onPressChange
- onPressStart
- onPressEnd
- delayLongPress
- delayPressStart
- delayPressEnd
- pressRententionOffset / pressRect
- emulated mouse events
-
fix keyboard press events when metaKey is involved(this currently works the same way as native, so will leave it for now) - any special case anchor tag-related tests
- hitslop interactions
- Determine event object data.
{
pointerType: 'mouse' | 'pen' | 'touch' | 'keyboard',
initial: { x: number, y: number },
point: { x: number, y: number },
delta: { x: number, y: number }
}
FocusScope module
Consider adding onFocusIn and onFocusOut (names tbd) to support userland customisation of focus repair. We could return the native elements.
A use case to consider: being able to programmatically move focus to an element without
allowing keyboards to focus the element (e.g., the document body, the root of a modal). In this
case the element (other than a few special cases) must have tabIndex={-1}.
InputScope module
-
onChangefires when an input element has been changed. This applies to<input>,<textarea>,<select>and elements withcontenteditableor whendesignModeis enabled.onChangeprovides a callback with the event for the element that changed and akeyof the elment that changed (if akeywas supplied). -
onValueChangeis similar toonChange, but only provides the value changed. This applies to<input>,<textarea>,<select>and elements withcontenteditableor whendesignModeis enabled.onValueChangeprovides avalueandkeyof the element that changed (if akeywas supplied). -
onSubmitfor when any<form>elements trigger form submit. -
onKeyPressfor when any keyboard keys are pressed. -
preventKeysaccepts an array of key strings that will get prevented from entering input. -
onSelectionChangefor when any any text selection occurs in any child elements. -
onBeforeChangefires before a change is about to occur. This applies to<input>,<textarea>,<select>and elements withcontenteditableor whendesignModeis enabled.onBeforeChangeprovides a callback with the event for the element that changed and akeyof the elment that changed (if akeywas supplied).
Drag module
- Determine event object data (same as Pan)
- Cancelling drag.
- FYI:
touchAction:'none'is needed oncurrentTargetto prevent browser cancelling afterpointermove. - FYI: Firefox might have problems when combining
mousemovewithdisplay:flex. - Add README
- Cross browser and device/modality testing.
- Write unit tests.
Pan module
- Write unit tests.
- Cross browser and device/modality testing.
- Cancelling pan.
- Add README
- FYI:
touchAction:'none'is needed oncurrentTargetto prevent browser cancelling afterpointermove. - Determine event object data.
{
pointerType: 'mouse' | 'pen' | 'touch',
initial: { x: number, y: number },
point: { x: number, y: number },
velocity: { x: number, y: number },
delta: { x: number, y: number }
}
Scroll module
-
disabled -
onScroll -
onScrollDragStart -
onScrollDragEnd -
onMomentumScrollStart -
onMomentumScrollEnd - scroll directions
- Determine event object data
- FYI Fix wheel/touch browser locking in IE and Safari #9333
Swipe module
- Combine
onSwipe{Left,Right,Up,Down}intoonSwipew/ event data. - Cancelling swipe.
- Write comprehensive unit tests.
- Cross browser and device/modality testing.
- Add README
- Determine event object data (same as Pan)
- FYI:
touchAction:'none'is needed oncurrentTargetto prevent browser cancelling afterpointermove.
Touch HitSlop
Consider whether we need this at all. Some browsers have a native hitslop and we could work with vendors on any potential improvements to the native system
- Figure out how to
positionparent of hitslop. - Measurement without reflows (ResizeObserver?)
- Add README
- Figure out solution for SSR w/ non-touch interactions if no client-side JS
- Add
touchHitSlop(Add event touch hit target hit slop logic to experimental event API #15261). - Add
touchHitSlopSSR support
Dev Tools (#15267)
- Add
displayNamefields to event components and event targets. - Possibly add a
descriptionordisplayNamefield to event responders? For example thePressresponder module for ReactDOM could have the nameReactDOMPressResponder. - Expose some DEV only event triggering exports from event responder modules. i.e.
HoverEventResponder.DevToolEvents = [{ name: 'hover', trigger: [{ name: 'pointerup', passive: false }]]; - Add basic support for rendering event responders and event targets in the tree. @bvaughn
Ancillary work
- Investigate removing object assign polyfill from individual event modules
- Add internal interactive documentation / fiddle
- Investigate press event patterns on
input,textarea,select, etc. - Implement high-level components like Pressable (inc delays).
- Nested Pressables should not bubble events.
- Investigate accounting for element resizes when determining hit bounds, e.g., using resize observer for notifications