Skip to content

Commit

Permalink
Add support of onBeforeToggle and onToggle
Browse files Browse the repository at this point in the history
  • Loading branch information
Sebastian Silbermann committed Feb 18, 2024
1 parent 9336bf3 commit 4def45c
Show file tree
Hide file tree
Showing 8 changed files with 59 additions and 5 deletions.
12 changes: 12 additions & 0 deletions packages/react-dom-bindings/src/client/ReactDOMComponent.js
Original file line number Diff line number Diff line change
Expand Up @@ -796,6 +796,11 @@ function setProp(
}
break;
}
case 'popover':
listenToNonDelegatedEvent('beforetoggle', domElement);
listenToNonDelegatedEvent('toggle', domElement);
setValueForAttribute(domElement, 'popover', value);
break;
case 'xlinkActuate':
setValueForNamespacedAttribute(
domElement,
Expand Down Expand Up @@ -2835,6 +2840,13 @@ export function diffHydratedProperties(
}
}

if (props.popover != null) {
// We listen to this event in case to ensure emulated bubble
// listeners still fire for the toggle event.
listenToNonDelegatedEvent('beforetoggle', domElement);
listenToNonDelegatedEvent('toggle', domElement);
}

if (props.onScroll != null) {
listenToNonDelegatedEvent('scroll', domElement);
}
Expand Down
1 change: 1 addition & 0 deletions packages/react-dom-bindings/src/events/DOMEventNames.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export type DOMEventName =
// 'animationstart' |
| 'beforeblur' // Not a real event. This is used by event experiments.
| 'beforeinput'
| 'beforetoggle'
| 'blur'
| 'canplay'
| 'canplaythrough'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export const topLevelEventsToReactNames: Map<DOMEventName, string | null> =
const simpleEventPluginEvents = [
'abort',
'auxClick',
'beforeToggle',
'cancel',
'canPlay',
'canPlayThrough',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@ export const mediaEventTypes: Array<DOMEventName> = [
// set them on the actual target element itself. This is primarily
// because these events do not consistently bubble in the DOM.
export const nonDelegatedEvents: Set<DOMEventName> = new Set([
'beforetoggle',
'cancel',
'close',
'invalid',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,7 @@ export function getEventPriority(domEventName: DOMEventName): EventPriority {
case 'select':
case 'selectstart':
return DiscreteEventPriority;
case 'beforetoggle':
case 'drag':
case 'dragenter':
case 'dragexit':
Expand Down
46 changes: 41 additions & 5 deletions packages/react-dom/src/__tests__/ReactDOMEventPropagation-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1217,6 +1217,40 @@ describe('ReactDOMEventListener', () => {
});
});

it('onBeforeToggle Popover API', async () => {
await testEmulatedBubblingEvent({
type: 'div',
targetProps: {popover: 'any'},
reactEvent: 'onBeforeToggle',
reactEventType: 'beforetoggle',
nativeEvent: 'beforetoggle',
dispatch(node) {
const e = new Event('beforetoggle', {
bubbles: false,
cancelable: true,
});
node.dispatchEvent(e);
},
});
});

it('onToggle Popover API', async () => {
await testEmulatedBubblingEvent({
type: 'div',
targetProps: {popover: 'any'},
reactEvent: 'onToggle',
reactEventType: 'toggle',
nativeEvent: 'toggle',
dispatch(node) {
const e = new Event('toggle', {
bubbles: false,
cancelable: true,
});
node.dispatchEvent(e);
},
});
});

it('onVolumeChange', async () => {
await testEmulatedBubblingEvent({
type: 'video',
Expand Down Expand Up @@ -1918,6 +1952,7 @@ describe('ReactDOMEventListener', () => {
type={eventConfig.type}
targetRef={targetRef}
targetProps={{
...eventConfig.targetProps,
[eventConfig.reactEvent]: e => {
log.push('---- inner');
},
Expand Down Expand Up @@ -2084,11 +2119,10 @@ describe('ReactDOMEventListener', () => {
<Fixture
type={eventConfig.type}
targetRef={targetRef}
targetProps={
{
// No listener on the target itself.
}
}
targetProps={{
...eventConfig.targetProps,
// No listener on the target itself.
}}
parentProps={{
[eventConfig.reactEvent]: e => {
log.push('--- inner parent');
Expand Down Expand Up @@ -2317,6 +2351,7 @@ describe('ReactDOMEventListener', () => {
type={eventConfig.type}
targetRef={targetRef}
targetProps={{
...eventConfig.targetProps,
[eventConfig.reactEvent]: e => {
e.stopPropagation(); // <---------
log.push('---- inner');
Expand Down Expand Up @@ -2654,6 +2689,7 @@ describe('ReactDOMEventListener', () => {
}
}}
targetProps={{
...eventConfig.targetProps,
[eventConfig.reactEvent]: e => {
log.push('---- inner');
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ exports[`ReactTestUtils Simulate should have locally attached media events 1`] =
"animationStart",
"auxClick",
"beforeInput",
"beforeToggle",
"blur",
"canPlay",
"canPlayThrough",
Expand Down
1 change: 1 addition & 0 deletions packages/react-dom/src/test-utils/ReactTestUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -627,6 +627,7 @@ function makeSimulator(eventType) {

// A one-time snapshot with no plans to update. We'll probably want to deprecate Simulate API.
const simulatedEventTypes = [
'beforeToggle',
'blur',
'cancel',
'click',
Expand Down

0 comments on commit 4def45c

Please sign in to comment.