Skip to content

Commit

Permalink
feat: Remove mitt dependency
Browse files Browse the repository at this point in the history
  • Loading branch information
manzt committed Jul 15, 2024
1 parent 693b7bb commit 0e0a0ca
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 23 deletions.
6 changes: 0 additions & 6 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 @@ -9,7 +9,6 @@
"imjoy-rpc": "^0.2.23",
"jotai": "^1.0.0",
"just-debounce-it": "^3.1.1",
"mitt": "^3.0.0",
"p-map": "^5.5.0",
"quick-lru": "^6.0.0",
"react": "^18.2.0",
Expand Down
20 changes: 4 additions & 16 deletions src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ import ReactDOM from 'react-dom/client';
import { Provider, atom } from 'jotai';
import { useSetAtom } from 'jotai';
import { ThemeProvider } from '@material-ui/styles';
import mitt from 'mitt';

import Menu from './components/Menu';
import Viewer from './components/Viewer';
import './codecs/register';
import { addImageAtom, ImageLayerConfig, ViewState, atomWithEffect } from './state';
import { defer, typedEmitter } from './utils';
import theme from './theme';

export { version } from '../package.json';
Expand All @@ -26,24 +26,12 @@ export interface VizarrViewer {
destroy(): void;
}

/** switch to Promise.withResolvers when it's available */
function defer<T>() {
let resolve: (value: T | PromiseLike<T>) => void;
let reject: (reason?: any) => void;
const promise = new Promise<T>((res, rej) => {
resolve = res;
reject = rej;
});
// @ts-expect-error - resolve and reject are OK
return { promise, resolve, reject };
}

export function createViewer(element: HTMLElement): Promise<VizarrViewer> {
const ref = React.createRef<VizarrViewer>();
const emitter = mitt<Events>();
const emitter = typedEmitter<Events>();
const viewStateAtom = atomWithEffect<ViewState | undefined, ViewState>(
atom<ViewState | undefined>(undefined),
({ zoom, target }) => emitter.emit('viewStateChange', { zoom, target })
({ zoom, target }) => emitter.emit('viewStateChange', { zoom, target }),
);
const { promise, resolve } = defer<VizarrViewer>();

Expand All @@ -55,7 +43,7 @@ export function createViewer(element: HTMLElement): Promise<VizarrViewer> {
() => ({
addImage,
setViewState,
on: emitter.on,
on: emitter.on.bind(emitter),
destroy: () => root.unmount(),
}),
[]
Expand Down
41 changes: 41 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -278,3 +278,44 @@ export async function calcConstrastLimits<S extends string[]>(
})
);
}

/**
* Create a promise that can be resolved or rejected externally.
*
* TODO: Switch to Promise.withResolvers when it's available
*/
export function defer<T>() {
let resolve: (value: T | PromiseLike<T>) => void;
let reject: (reason?: any) => void;
const promise = new Promise<T>((res, rej) => {
resolve = res;
reject = rej;
});
// @ts-expect-error - resolve and reject are OK
return { promise, resolve, reject };
}

/**
* A simple event emitter that allows for typed events.
*
* @example
* ```ts
* const emitter = typedEmitter<{ foo: string, bar: number }>();
* emitter.on('foo', (data) => console.log(data));
* emitter.emit('foo', 'hello');
* ```
*
* TODO: Add support for removing listeners.
*/
export function typedEmitter<T>() {
let target = new EventTarget();
return {
on: <E extends keyof T & string>(event: E, cb: (data: T[E]) => void) => {
target.addEventListener(event, (e) => cb((e as CustomEvent).detail));
},
emit: <E extends keyof T & string>(event: E, data: T[E]) => {
target.dispatchEvent(new CustomEvent(event, { detail: data }));
},
}
}

0 comments on commit 0e0a0ca

Please sign in to comment.