Skip to content

Commit

Permalink
Merge pull request #233 from FrameMuse/228-replace-eventemitter-with-…
Browse files Browse the repository at this point in the history
…custom-implementation

Replace `eventemitter` with custom implementation
  • Loading branch information
FrameMuse committed Dec 9, 2023
2 parents f6d32a6 + ca56d91 commit 53b2796
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 154 deletions.
126 changes: 0 additions & 126 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
}
},
"dependencies": {
"eventemitter3": "^5.0.0",
"type-fest": "^4.0.0"
},
"devDependencies": {
Expand Down
39 changes: 39 additions & 0 deletions src/EventEmitter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
MIT License
Copyright (c) 2023 Valery Zinchenko
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
*/

type EventEmitterListener = (...args: never[]) => void

class EventEmitter<Events extends Record<EventName, EventEmitterListener>, EventName extends keyof Events = keyof Events> {
private callbacks: Partial<Record<keyof never, Set<EventEmitterListener>>> = {}

public on<Event extends keyof Events>(event: Event, callback: Events[Event]) {
this.callbacks[event] ??= new Set
this.callbacks[event]?.add(callback as EventEmitterListener)
}
public off<Event extends keyof Events>(event: Event, callback: Events[Event]) {
this.callbacks[event]?.delete(callback as EventEmitterListener)
}
public emit<Event extends keyof Events>(event: Event, ...args: Parameters<Events[Event]>) {
const callbacks = this.callbacks[event]
if (callbacks == null) return

for (const callback of callbacks) callback(...args)
}
}

export default EventEmitter
23 changes: 11 additions & 12 deletions src/ModalController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,15 @@ copies or substantial portions of the Software.
*/

import EventEmitter from "eventemitter3"

import EventEmitter from "./EventEmitter"
import { ModalWindow, ModalWindowAny } from "./ModalWindow"
import { ExternalStore, MODAL_WINDOW_PARAMS_EXPLANATION, ModalComponent, ModalComponentProps, ModalNamedComponents, ModalParams, ModalSnapshot, ModalWindowParams } from "./types"


interface ModalControllerEvents {
add: [ModalWindowAny]
remove: [ModalWindowAny]
update: []
add(modalWindow: ModalWindowAny): void
remove(modalWindow: ModalWindowAny): void
update(): void
}

interface ModalControllerConfig<Components extends ModalNamedComponents = ModalNamedComponents> {
Expand Down Expand Up @@ -86,11 +85,11 @@ class ModalController<Config extends Partial<ModalControllerConfig> = ModalContr
* @example
* await Modal.open(MyModal, { id: 1 })
* console.log("Modal was closed")
*
*
* @example
* const modal = Modal.open(MyModal, { id: 1 })
* modal.then(() => console.log("Modal was closed"))
*
*
* @example
* const modal = Modal.open(MyModal, { id: 1 })
* modal.on("close", () => console.log("Modal was closed"))
Expand Down Expand Up @@ -229,13 +228,13 @@ class ModalController<Config extends Partial<ModalControllerConfig> = ModalContr

/**
* Subscribes to `event` with `listener`.
*
*
* @example
* Modal.on("close", () => { })
*
*
* @returns `unsubscribe` method
*/
public on<T extends keyof ModalControllerEvents>(event: T, listener: (...args: ModalControllerEvents[T]) => void) {
public on<T extends keyof ModalControllerEvents>(event: T, listener: ModalControllerEvents[T]) {
this.events.on(event, listener)

return () => {
Expand All @@ -245,9 +244,9 @@ class ModalController<Config extends Partial<ModalControllerConfig> = ModalContr

/**
* Used for container component to get the current state.
*
*
* Observes the state and calls the callback on any changes.
*
*
* @returns `unsubscribe` method to stop observing.
*/
public subscribe(callback: () => void) {
Expand Down
29 changes: 14 additions & 15 deletions src/ModalWindow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,16 @@ copies or substantial portions of the Software.
*/

import EventEmitter from "eventemitter3"

import Deffered from "./Deffered"
import EventEmitter from "./EventEmitter"
import { ModalComponent, ModalParams } from "./types"
import { cyrb53, serialize } from "./utils"

const MODAL_SEED = Date.now()

interface ModalWindowEvents {
open: []
close: []
open(): void
close(): void
}

const DEFAULT_PARAMS: ModalParams = {
Expand All @@ -43,12 +42,12 @@ const DEFAULT_PARAMS: ModalParams = {
class ModalWindow<CustomParams = unknown> {
/**
* Hash of `serialized` property.
*
*
* Unique id of the modal window.
* If two modals have the same id, they will be treated as the same modal.
*
*
* This is usually used in `key` prop for React components.
*
*
* @note
* This is not the same as `params.id` because `id` is unique for each modal window.
*/
Expand All @@ -62,7 +61,7 @@ class ModalWindow<CustomParams = unknown> {
public params: ModalParams & CustomParams
/**
* Indicates that the `close` method has been called and the modal window is going to be removed.
*
*
* @default
* false
*/
Expand All @@ -88,10 +87,10 @@ class ModalWindow<CustomParams = unknown> {

/**
* Closes the modal window.
*
*
* @note
* This is an arrow function, which prevents `this` from being lost - You can use it without `bind`.
*
*
* @example
* const modal = Modal.open(PopupHello, { title: "Hello" })
* modal.close()
Expand All @@ -108,7 +107,7 @@ class ModalWindow<CustomParams = unknown> {

/**
* Can be used to wait for the modal to be closed before performing an action.
*
*
* @example
* await Modal.open(PopupHello, { title: "Hello" })
* doAnyAction()
Expand All @@ -121,12 +120,12 @@ class ModalWindow<CustomParams = unknown> {
* @example
* const modal = Modal.open(PopupHello, { title: "Hello" })
* modal.on("close", () => { })
*
*
* @note If you want to do something on close, you can use await directly on this instance. For details see `then` method in `ModalWindow`.
*
*
* @returns `unsubscribe` method
*/
on<K extends keyof ModalWindowEvents>(event: K, listener: (...args: ModalWindowEvents[K]) => void) {
on<K extends keyof ModalWindowEvents>(event: K, listener: ModalWindowEvents[K]) {
this.events.on(event, listener)

return () => {
Expand All @@ -137,7 +136,7 @@ class ModalWindow<CustomParams = unknown> {

/**
* This is a workaround for TypeScript.
*
*
* Used if it doesn't matter what type of `CustomParams` is used.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
Expand Down

0 comments on commit 53b2796

Please sign in to comment.