diff --git a/packages/react-native/src/private/webapis/dom/events/CustomEvent.js b/packages/react-native/src/private/webapis/dom/events/CustomEvent.js new file mode 100644 index 00000000000000..25d046b2709dd8 --- /dev/null +++ b/packages/react-native/src/private/webapis/dom/events/CustomEvent.js @@ -0,0 +1,40 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow strict + * @format + */ + +/** + * This module implements the `CustomEvent` interface from the DOM. + * See https://dom.spec.whatwg.org/#interface-customevent. + */ + +// flowlint unsafe-getters-setters:off + +import type {EventInit} from './Event'; + +import Event from './Event'; + +export type CustomEventInit = { + ...EventInit, + detail?: mixed, +}; + +export default class CustomEvent extends Event { + _detail: mixed; + + constructor(type: string, options?: ?CustomEventInit) { + const {detail, ...eventOptions} = options ?? {}; + super(type, eventOptions); + + this._detail = detail; + } + + get detail(): mixed { + return this._detail; + } +} diff --git a/packages/react-native/src/private/webapis/dom/events/Event.js b/packages/react-native/src/private/webapis/dom/events/Event.js index 55a927d26fb528..10ccd67061e441 100644 --- a/packages/react-native/src/private/webapis/dom/events/Event.js +++ b/packages/react-native/src/private/webapis/dom/events/Event.js @@ -36,7 +36,7 @@ import { setStopPropagationFlag, } from './internals/EventInternals'; -type EventInit = { +export type EventInit = { bubbles?: boolean, cancelable?: boolean, composed?: boolean, diff --git a/packages/react-native/src/private/webapis/dom/events/__tests__/CustomEvent-itest.js b/packages/react-native/src/private/webapis/dom/events/__tests__/CustomEvent-itest.js new file mode 100644 index 00000000000000..ac0eecf5e8e12d --- /dev/null +++ b/packages/react-native/src/private/webapis/dom/events/__tests__/CustomEvent-itest.js @@ -0,0 +1,53 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow strict-local + * @format + * @oncall react_native + * @fantom_flags enableAccessToHostTreeInFabric:true + */ + +import '../../../../../../Libraries/Core/InitializeCore.js'; + +import CustomEvent from '../CustomEvent'; +import Event from '../Event'; + +describe('CustomEvent', () => { + it('extends Event', () => { + const event = new CustomEvent('foo', { + bubbles: true, + cancelable: true, + composed: true, + }); + + expect(event.type).toBe('foo'); + expect(event.bubbles).toBe(true); + expect(event.cancelable).toBe(true); + expect(event.composed).toBe(true); + expect(event).toBeInstanceOf(Event); + }); + + it('allows passing a detail value', () => { + const detail = Symbol('detail'); + + const event = new CustomEvent('foo', {detail}); + + expect(event.detail).toBe(detail); + }); + + it('does NOT allow changing the detail value after construction', () => { + const detail = Symbol('detail'); + + const event = new CustomEvent('foo', {detail}); + + expect(() => { + 'use strict'; + // Use strict mode to throw an error instead of silently failing + // $FlowExpectedError[cannot-write] + event.detail = 'bar'; + }).toThrow(); + }); +});