@uppy/core
Version:
Core module for the extensible JavaScript file upload widget with support for drag&drop, resumable uploads, previews, restrictions, file processing/encoding, remote providers like Instagram, Dropbox, Google Drive, S3 and more :dog:
120 lines (95 loc) • 2.96 kB
text/typescript
/**
* 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 type { Body, I18n, Meta, OptionalPluralizeLocale } from '@uppy/utils'
import { Translator } from '@uppy/utils'
import type { State, UnknownPlugin, Uppy } from './Uppy.js'
export type PluginOpts = {
locale?: OptionalPluralizeLocale
id?: string
}
export type OnlyOptionals<T> = Pick<
T,
{
// biome-ignore lint/complexity/noBannedTypes: ...
[K in keyof T]-?: {} extends Pick<T, K> ? K : never
}[keyof T]
>
/**
* DefinePluginOpts marks all of the passed AlwaysDefinedKeys as “required” or “always defined”.
*/
export type DefinePluginOpts<
Opts,
AlwaysDefinedKeys extends keyof OnlyOptionals<Opts>,
> = Opts & Required<Pick<Opts, AlwaysDefinedKeys>>
export default class BasePlugin<
Opts extends PluginOpts,
M extends Meta,
B extends Body,
PluginState extends Record<string, unknown> = Record<string, unknown>,
> {
uppy: Uppy<M, B>
opts: Opts
id!: string
defaultLocale: OptionalPluralizeLocale
i18n!: I18n
i18nArray!: Translator['translateArray']
type!: string
VERSION!: string
constructor(uppy: Uppy<M, B>, opts?: Opts) {
this.uppy = uppy
this.opts = opts ?? ({} as Opts)
}
getPluginState(): PluginState {
const { plugins } = this.uppy.getState()
return (plugins?.[this.id] || {}) as PluginState
}
setPluginState(update?: Partial<PluginState>): void {
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)`.
*/
addTarget(plugin: UnknownPlugin<M, B>): HTMLElement | null {
throw new Error(
"Extend the addTarget method to add your plugin to another plugin's target",
)
}
install(): void {}
uninstall(): void {}
update(state: Partial<State<M, B>>): void {}
// Called after every state update, after everything's mounted. Debounced.
afterUpdate(): void {}
}