/** * 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. * * @format * @flow strict-local */ // https://dom.spec.whatwg.org/#dictdef-eventinit type Event$Init = { bubbles?: boolean, cancelable?: boolean, composed?: boolean, /** Non-standard. See `composed` instead. */ scoped?: boolean, ... }; /** * This is a copy of the Event interface defined in Flow: * https://github.com/facebook/flow/blob/741104e69c43057ebd32804dd6bcc1b5e97548ea/lib/dom.js * which is itself a faithful interface of the W3 spec: * https://dom.spec.whatwg.org/#interface-event * * Since Flow assumes that Event is provided and is on the global object, * we must provide an implementation of Event for CustomEvent (and future * alignment of React Native's event system with the W3 spec). */ interface IEvent { constructor(type: string, eventInitDict?: Event$Init): void; /** * Returns the type of event, e.g. "click", "hashchange", or "submit". */ +type: string; /** * Returns the object to which event is dispatched (its target). */ +target: EventTarget; // TODO: nullable /** @deprecated */ +srcElement: Element; // TODO: nullable /** * Returns the object whose event listener's callback is currently being invoked. */ +currentTarget: EventTarget; // TODO: nullable /** * Returns the invocation target objects of event's path (objects on which * listeners will be invoked), except for any nodes in shadow trees of which * the shadow root's mode is "closed" that are not reachable from event's * currentTarget. */ composedPath(): Array; +NONE: number; +AT_TARGET: number; +BUBBLING_PHASE: number; +CAPTURING_PHASE: number; /** * Returns the event's phase, which is one of NONE, CAPTURING_PHASE, AT_TARGET, * and BUBBLING_PHASE. */ +eventPhase: number; /** * When dispatched in a tree, invoking this method prevents event from reaching * any objects other than the current object. */ stopPropagation(): void; /** * Invoking this method prevents event from reaching any registered event * listeners after the current one finishes running and, when dispatched in a * tree, also prevents event from reaching any other objects. */ stopImmediatePropagation(): void; /** * Returns true or false depending on how event was initialized. True if * event goes through its target's ancestors in reverse tree order, and * false otherwise. */ +bubbles: boolean; /** * Returns true or false depending on how event was initialized. Its * return value does not always carry meaning, but true can indicate * that part of the operation during which event was dispatched, can * be canceled by invoking the preventDefault() method. */ +cancelable: boolean; // returnValue: boolean; // legacy, and some subclasses still define it as a string! /** * If invoked when the cancelable attribute value is true, and while * executing a listener for the event with passive set to false, signals to * the operation that caused event to be dispatched that it needs to be * canceled. */ preventDefault(): void; /** * Returns true if preventDefault() was invoked successfully to indicate * cancelation, and false otherwise. */ +defaultPrevented: boolean; /** * Returns true or false depending on how event was initialized. True if * event invokes listeners past a ShadowRoot node that is the root of its * target, and false otherwise. */ +composed: boolean; /** * Returns true if event was dispatched by the user agent, and false otherwise. */ +isTrusted: boolean; /** * Returns the event's timestamp as the number of milliseconds measured relative * to the time origin. */ +timeStamp: number; /** Non-standard. See Event.prototype.composedPath */ +deepPath?: () => EventTarget[]; /** Non-standard. See Event.prototype.composed */ +scoped: boolean; /** * @deprecated */ initEvent(type: string, bubbles: boolean, cancelable: boolean): void; } class EventPolyfill implements IEvent { type: string; bubbles: boolean; cancelable: boolean; composed: boolean; // Non-standard. See `composed` instead. scoped: boolean; isTrusted: boolean; defaultPrevented: boolean; timeStamp: number; // https://developer.mozilla.org/en-US/docs/Web/API/Event/eventPhase NONE: number; AT_TARGET: number; BUBBLING_PHASE: number; CAPTURING_PHASE: number; eventPhase: number; currentTarget: EventTarget; // TODO: nullable target: EventTarget; // TODO: nullable /** @deprecated */ srcElement: Element; // TODO: nullable // React Native-specific: proxy data to a SyntheticEvent when // certain methods are called. // SyntheticEvent will also have a reference to this instance - // it is circular - and both classes use this reference to keep // data with the other in sync. _syntheticEvent: mixed; constructor(type: string, eventInitDict?: Event$Init) { this.type = type; this.bubbles = !!(eventInitDict?.bubbles || false); this.cancelable = !!(eventInitDict?.cancelable || false); this.composed = !!(eventInitDict?.composed || false); this.scoped = !!(eventInitDict?.scoped || false); // TODO: somehow guarantee that only "private" instantiations of Event // can set this to true this.isTrusted = false; // TODO: in the future we'll want to make sure this has the same // time-basis as events originating from native this.timeStamp = Date.now(); this.defaultPrevented = false; // https://developer.mozilla.org/en-US/docs/Web/API/Event/eventPhase this.NONE = 0; this.AT_TARGET = 1; this.BUBBLING_PHASE = 2; this.CAPTURING_PHASE = 3; this.eventPhase = this.NONE; // $FlowFixMe this.currentTarget = null; // $FlowFixMe this.target = null; // $FlowFixMe this.srcElement = null; } composedPath(): Array { throw new Error('TODO: not yet implemented'); } preventDefault(): void { this.defaultPrevented = true; if (this._syntheticEvent != null) { // $FlowFixMe this._syntheticEvent.preventDefault(); } } initEvent(type: string, bubbles: boolean, cancelable: boolean): void { throw new Error( 'TODO: not yet implemented. This method is also deprecated.', ); } stopImmediatePropagation(): void { throw new Error('TODO: not yet implemented'); } stopPropagation(): void { if (this._syntheticEvent != null) { // $FlowFixMe this._syntheticEvent.stopPropagation(); } } setSyntheticEvent(value: mixed): void { this._syntheticEvent = value; } } // Assertion magic for polyfill follows. declare var checkEvent: Event; // eslint-disable-line no-unused-vars /*:: // This can be a strict mode error at runtime so put it in a Flow comment. (checkEvent: IEvent); */ global.Event = EventPolyfill; export default EventPolyfill;