Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

@uppy/core: migrate to TS #4811

Merged
merged 1 commit into from
Dec 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -469,7 +469,7 @@ module.exports = {
},
{
files: ['packages/@uppy/*/src/**/*.ts', 'packages/@uppy/*/src/**/*.tsx'],
excludedFiles: ['packages/@uppy/**/*.test.ts'],
excludedFiles: ['packages/@uppy/**/*.test.ts', 'packages/@uppy/core/src/mocks/*.ts'],
rules: {
'@typescript-eslint/explicit-function-return-type': 'error',
},
Expand Down
85 changes: 0 additions & 85 deletions packages/@uppy/core/src/BasePlugin.js

This file was deleted.

106 changes: 106 additions & 0 deletions packages/@uppy/core/src/BasePlugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
/* eslint-disable class-methods-use-this */
/* eslint-disable @typescript-eslint/no-empty-function */

/**
* Core plugin logic that all plugins share.
*
* BasePlugin does not contain DOM rendering so it can be used for plugins
* without a user interface.
*
* See `Plugin` for the extended version with Preact rendering for interfaces.
*/

import Translator from '@uppy/utils/lib/Translator'
import type { I18n, Locale } from '@uppy/utils/lib/Translator'
import type { Body, Meta } from '@uppy/utils/lib/UppyFile'
import type { Uppy } from '.'

export type PluginOpts = { locale?: Locale; [key: string]: unknown }

export default class BasePlugin<
Opts extends PluginOpts,
M extends Meta,
B extends Body,
> {
uppy: Uppy<M, B>

opts: Opts

id: string

defaultLocale: Locale

i18n: I18n

i18nArray: Translator['translateArray']

type: string

VERSION: string

constructor(uppy: Uppy<M, B>, opts: Opts) {
this.uppy = uppy
this.opts = opts ?? {}
}

getPluginState(): Record<string, unknown> {
const { plugins } = this.uppy.getState()
return plugins?.[this.id] || {}
}

setPluginState(update: unknown): void {
if (!update) return
const { plugins } = this.uppy.getState()

this.uppy.setState({
plugins: {
...plugins,
[this.id]: {
...plugins[this.id],
...update,
},
},
})
}

setOptions(newOpts: Partial<Opts>): void {
this.opts = { ...this.opts, ...newOpts }
this.setPluginState(undefined) // so that UI re-renders with new options
this.i18nInit()
}

i18nInit(): void {
const translator = new Translator([
this.defaultLocale,
this.uppy.locale,
this.opts.locale,
])
this.i18n = translator.translate.bind(translator)
this.i18nArray = translator.translateArray.bind(translator)
this.setPluginState(undefined) // so that UI re-renders and we see the updated locale
}

/**
* Extendable methods
* ==================
* These methods are here to serve as an overview of the extendable methods as well as
* making them not conditional in use, such as `if (this.afterUpdate)`.
*/

// eslint-disable-next-line @typescript-eslint/no-unused-vars
addTarget(plugin: unknown): HTMLElement {
throw new Error(
"Extend the addTarget method to add your plugin to another plugin's target",
)
}

install(): void {}

uninstall(): void {}

// eslint-disable-next-line @typescript-eslint/no-unused-vars
update(state: any): void {}

// Called after every state update, after everything's mounted. Debounced.
afterUpdate(): void {}
}
114 changes: 114 additions & 0 deletions packages/@uppy/core/src/EventManager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import type { Meta, Body, UppyFile } from '@uppy/utils/lib/UppyFile'
import type {
DeprecatedUppyEventMap,
Uppy,
UppyEventMap,
_UppyEventMap,
} from './Uppy'

/**
* Create a wrapper around an event emitter with a `remove` method to remove
* all events that were added using the wrapped emitter.
*/
export default class EventManager<M extends Meta, B extends Body> {
#uppy: Uppy<M, B>

#events: Array<[keyof UppyEventMap<M, B>, (...args: any[]) => void]> = []

constructor(uppy: Uppy<M, B>) {
this.#uppy = uppy
}

on<K extends keyof _UppyEventMap<M, B>>(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why three ons?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One is deprecated

event: K,
fn: _UppyEventMap<M, B>[K],
): Uppy<M, B>

/** @deprecated */
on<K extends keyof DeprecatedUppyEventMap<M, B>>(
event: K,
fn: DeprecatedUppyEventMap<M, B>[K],
): Uppy<M, B>

on<K extends keyof UppyEventMap<M, B>>(
event: K,
fn: UppyEventMap<M, B>[K],
): Uppy<M, B> {
this.#events.push([event, fn])
return this.#uppy.on(event as keyof _UppyEventMap<M, B>, fn)
}

remove(): void {
for (const [event, fn] of this.#events.splice(0)) {
this.#uppy.off(event, fn)
}
}

onFilePause(
fileID: UppyFile<M, B>['id'],
cb: (isPaused: boolean) => void,
): void {
this.on('upload-pause', (targetFileID, isPaused) => {
if (fileID === targetFileID) {
cb(isPaused)
}
})
}

onFileRemove(
fileID: UppyFile<M, B>['id'],
cb: (isPaused: UppyFile<M, B>['id']) => void,
): void {
this.on('file-removed', (file) => {
if (fileID === file.id) cb(file.id)
})
}

onPause(fileID: UppyFile<M, B>['id'], cb: (isPaused: boolean) => void): void {
this.on('upload-pause', (targetFileID, isPaused) => {
if (fileID === targetFileID) {
// const isPaused = this.#uppy.pauseResume(fileID)
cb(isPaused)
}
})
}

onRetry(fileID: UppyFile<M, B>['id'], cb: () => void): void {
this.on('upload-retry', (targetFileID) => {
if (fileID === targetFileID) {
cb()
}
})
}

onRetryAll(fileID: UppyFile<M, B>['id'], cb: () => void): void {
this.on('retry-all', () => {
if (!this.#uppy.getFile(fileID)) return
cb()
})
}

onPauseAll(fileID: UppyFile<M, B>['id'], cb: () => void): void {
this.on('pause-all', () => {
if (!this.#uppy.getFile(fileID)) return
cb()
})
}

onCancelAll(
fileID: UppyFile<M, B>['id'],
eventHandler: UppyEventMap<M, B>['cancel-all'],
): void {
this.on('cancel-all', (...args) => {
if (!this.#uppy.getFile(fileID)) return
eventHandler(...args)
})
}

onResumeAll(fileID: UppyFile<M, B>['id'], cb: () => void): void {
this.on('resume-all', () => {
if (!this.#uppy.getFile(fileID)) return
cb()
})
}
}
Loading