mirror of
https://github.com/transloadit/uppy.git
synced 2026-01-23 02:25:07 +00:00
Make Generics Optional in uppy.getPlugin (#6057)
fixes #6024. ### Problem - `getPlugin()` defaults to `UnknownPlugin`, so methods like `openModal` are not visible , since core is not aware of that plugin type ### Proposed change - Introduce a types-only registry in core: - `export interface PluginTypeRegistry<M extends Meta, B extends Body> {}` - Overload `getPlugin` to return a precise type when the id is a known key of the registry. - add `Dashboard` to PluginTypeRegistry through module augmentation: - `'Dashboard': Dashboard<M, B>`. - When a project imports from `@uppy/dashboard`, its module augmentation extends PluginTypeRegistry, adding the correct type into it - I've added Tests , kept them in a separate file so it's easier to review , once this approach gets approved I'll add them to `Uppy.test.ts` Once this PR gets a positive review I'll add this for other plugins , currently only added for `@uppy/dashboard` **Build with Local tarball can be checked here** https://stackblitz.com/~/github.com/qxprakash/uppy-type-test?file=type_test.ts
This commit is contained in:
parent
c788818410
commit
79e6460a6c
44 changed files with 320 additions and 45 deletions
36
.changeset/nasty-friends-win.md
Normal file
36
.changeset/nasty-friends-win.md
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
---
|
||||
"@uppy/google-photos-picker": minor
|
||||
"@uppy/google-drive-picker": minor
|
||||
"@uppy/thumbnail-generator": minor
|
||||
"@uppy/golden-retriever": minor
|
||||
"@uppy/provider-views": minor
|
||||
"@uppy/remote-sources": minor
|
||||
"@uppy/screen-capture": minor
|
||||
"@uppy/google-drive": minor
|
||||
"@uppy/image-editor": minor
|
||||
"@uppy/drop-target": minor
|
||||
"@uppy/transloadit": minor
|
||||
"@uppy/compressor": minor
|
||||
"@uppy/status-bar": minor
|
||||
"@uppy/xhr-upload": minor
|
||||
"@uppy/dashboard": minor
|
||||
"@uppy/drag-drop": minor
|
||||
"@uppy/instagram": minor
|
||||
"@uppy/facebook": minor
|
||||
"@uppy/onedrive": minor
|
||||
"@uppy/unsplash": minor
|
||||
"@uppy/dropbox": minor
|
||||
"@uppy/aws-s3": minor
|
||||
"@uppy/webcam": minor
|
||||
"@uppy/webdav": minor
|
||||
"@uppy/audio": minor
|
||||
"@uppy/core": minor
|
||||
"@uppy/form": minor
|
||||
"@uppy/zoom": minor
|
||||
"@uppy/box": minor
|
||||
"@uppy/tus": minor
|
||||
"@uppy/url": minor
|
||||
---
|
||||
|
||||
- Add PluginTypeRegistry and typed getPlugin overload in @uppy/core
|
||||
- Register plugin ids across packages so uppy.getPlugin('Dashboard' | 'Webcam') returns the concrete plugin type and removes the need to pass generics in getPlugin()
|
||||
|
|
@ -15,6 +15,12 @@ import PermissionsScreen from './PermissionsScreen.js'
|
|||
import RecordingScreen from './RecordingScreen.js'
|
||||
import supportsMediaRecorder from './supportsMediaRecorder.js'
|
||||
|
||||
declare module '@uppy/core' {
|
||||
export interface PluginTypeRegistry<M extends Meta, B extends Body> {
|
||||
Audio: Audio<M, B>
|
||||
}
|
||||
}
|
||||
|
||||
export interface AudioOptions extends UIPluginOptions {
|
||||
showAudioSourceDropdown?: boolean
|
||||
locale?: LocaleStrings<typeof locale>
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import {
|
|||
} from 'vitest'
|
||||
|
||||
import 'whatwg-fetch'
|
||||
import Core, { type UppyFile } from '@uppy/core'
|
||||
import Core, { type Meta, type UppyFile } from '@uppy/core'
|
||||
import nock from 'nock'
|
||||
import AwsS3Multipart, {
|
||||
type AwsBody,
|
||||
|
|
@ -36,8 +36,8 @@ describe('AwsS3Multipart', () => {
|
|||
let opts: Partial<AwsS3MultipartOptions<any, any>>
|
||||
|
||||
beforeEach(() => {
|
||||
const core = new Core<any, AwsBody>().use(AwsS3Multipart)
|
||||
const awsS3Multipart = core.getPlugin('AwsS3Multipart') as any
|
||||
const core = new Core<Meta, AwsBody>().use(AwsS3Multipart)
|
||||
const awsS3Multipart = core.getPlugin('AwsS3Multipart')!
|
||||
opts = awsS3Multipart.opts
|
||||
})
|
||||
|
||||
|
|
@ -125,8 +125,8 @@ describe('AwsS3Multipart', () => {
|
|||
const awsS3Multipart = core.getPlugin('AwsS3Multipart')!
|
||||
|
||||
const err = 'Expected a `endpoint` option'
|
||||
const file = {}
|
||||
const opts = {}
|
||||
const file = {} as unknown as UppyFile<Meta, Record<string, never>>
|
||||
const opts = {} as any
|
||||
|
||||
expect(() => awsS3Multipart.opts.createMultipartUpload(file)).toThrow(err)
|
||||
expect(() => awsS3Multipart.opts.listParts(file, opts)).toThrow(err)
|
||||
|
|
@ -202,11 +202,11 @@ describe('AwsS3Multipart', () => {
|
|||
})
|
||||
|
||||
describe('without companionUrl (custom main functions)', () => {
|
||||
let core: Core<any, AwsBody>
|
||||
let awsS3Multipart: AwsS3Multipart<any, AwsBody>
|
||||
let core: Core<Meta, AwsBody>
|
||||
let awsS3Multipart: AwsS3Multipart<Meta, AwsBody>
|
||||
|
||||
beforeEach(() => {
|
||||
core = new Core<any, AwsBody>()
|
||||
core = new Core<Meta, AwsBody>()
|
||||
core.use(AwsS3Multipart, {
|
||||
shouldUseMultipart: true,
|
||||
limit: 0,
|
||||
|
|
@ -226,7 +226,7 @@ describe('AwsS3Multipart', () => {
|
|||
}),
|
||||
listParts: undefined as any,
|
||||
})
|
||||
awsS3Multipart = core.getPlugin('AwsS3Multipart') as any
|
||||
awsS3Multipart = core.getPlugin('AwsS3Multipart')!
|
||||
})
|
||||
|
||||
it('Keeps chunks marked as busy through retries until they complete', async () => {
|
||||
|
|
@ -366,7 +366,6 @@ describe('AwsS3Multipart', () => {
|
|||
),
|
||||
listParts: undefined as any,
|
||||
})
|
||||
const awsS3Multipart = core.getPlugin('AwsS3Multipart')!
|
||||
const fileSize = 5 * MB + 1 * MB
|
||||
|
||||
core.addFile({
|
||||
|
|
@ -380,7 +379,7 @@ describe('AwsS3Multipart', () => {
|
|||
|
||||
await core.upload()
|
||||
|
||||
expect(awsS3Multipart.opts.uploadPartBytes.mock.calls.length).toEqual(3)
|
||||
expect(uploadPartBytes.mock.calls.length).toEqual(3)
|
||||
})
|
||||
|
||||
it('calls `upload-error` when uploadPartBytes fails after all retries', async () => {
|
||||
|
|
@ -406,7 +405,6 @@ describe('AwsS3Multipart', () => {
|
|||
listParts: undefined as any,
|
||||
})
|
||||
const fileSize = 5 * MB + 1 * MB
|
||||
const awsS3Multipart = core.getPlugin('AwsS3Multipart')!
|
||||
const uploadErrorMock = vi.fn()
|
||||
const uploadSuccessMock = vi.fn()
|
||||
core.on('upload-error', uploadErrorMock)
|
||||
|
|
@ -438,7 +436,7 @@ describe('AwsS3Multipart', () => {
|
|||
// Catch Promise.all reject
|
||||
}
|
||||
|
||||
expect(awsS3Multipart.opts.uploadPartBytes.mock.calls.length).toEqual(5)
|
||||
expect(uploadPartBytes.mock.calls.length).toEqual(5)
|
||||
expect(uploadErrorMock.mock.calls.length).toEqual(1)
|
||||
expect(uploadSuccessMock.mock.calls.length).toEqual(1) // This fails for me becuase upload returned early.
|
||||
})
|
||||
|
|
@ -526,8 +524,8 @@ describe('AwsS3Multipart', () => {
|
|||
})
|
||||
|
||||
describe('dynamic companionHeader using setOption', () => {
|
||||
let core: Core<any, AwsBody>
|
||||
let awsS3Multipart: AwsS3Multipart<any, AwsBody>
|
||||
let core: Core<Meta, AwsBody>
|
||||
let awsS3Multipart: AwsS3Multipart<Meta, AwsBody>
|
||||
const newToken = 'new token'
|
||||
|
||||
it('companionHeader is updated before uploading file', async () => {
|
||||
|
|
@ -536,7 +534,7 @@ describe('AwsS3Multipart', () => {
|
|||
/* Set up preprocessor */
|
||||
core.addPreProcessor(() => {
|
||||
awsS3Multipart =
|
||||
core.getPlugin<AwsS3Multipart<any, AwsBody>>('AwsS3Multipart')!
|
||||
core.getPlugin<AwsS3Multipart<Meta, AwsBody>>('AwsS3Multipart')!
|
||||
awsS3Multipart.setOptions({
|
||||
endpoint: 'http://localhost',
|
||||
headers: {
|
||||
|
|
|
|||
|
|
@ -45,6 +45,9 @@ declare module '@uppy/core' {
|
|||
export interface UppyEventMap<M extends Meta, B extends Body> {
|
||||
's3-multipart:part-uploaded': PartUploadedCallback<M, B>
|
||||
}
|
||||
export interface PluginTypeRegistry<M extends Meta, B extends Body> {
|
||||
AwsS3Multipart: AwsS3Multipart<M, B>
|
||||
}
|
||||
}
|
||||
|
||||
function assertServerError<T>(res: T): T {
|
||||
|
|
|
|||
|
|
@ -109,3 +109,9 @@ export default class Box<M extends Meta, B extends Body>
|
|||
return this.view.render(state)
|
||||
}
|
||||
}
|
||||
|
||||
declare module '@uppy/core' {
|
||||
export interface PluginTypeRegistry<M extends Meta, B extends Body> {
|
||||
Box: Box<M, B>
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,9 @@ declare module '@uppy/core' {
|
|||
export interface UppyEventMap<M extends Meta, B extends Body> {
|
||||
'compressor:complete': (file: UppyFile<M, B>[]) => void
|
||||
}
|
||||
export interface PluginTypeRegistry<M extends Meta, B extends Body> {
|
||||
Compressor: Compressor<M, B>
|
||||
}
|
||||
}
|
||||
|
||||
export interface CompressorOpts extends PluginOpts, CompressorJS.Options {
|
||||
|
|
|
|||
|
|
@ -142,6 +142,10 @@ export type UnknownProviderPluginState = {
|
|||
searchResults?: string[] | undefined
|
||||
}
|
||||
|
||||
// biome-ignore lint/suspicious/noEmptyInterface: PluginTypeRegistry is extended via module augmentation
|
||||
// biome-ignore lint/correctness/noUnusedVariables: Type parameters are used in module augmentation
|
||||
export interface PluginTypeRegistry<M extends Meta, B extends Body> {}
|
||||
|
||||
export interface AsyncStore {
|
||||
getItem: (key: string) => Promise<string | null>
|
||||
setItem: (key: string, value: string) => Promise<void>
|
||||
|
|
@ -1941,12 +1945,21 @@ export class Uppy<
|
|||
/**
|
||||
* Find one Plugin by name.
|
||||
*/
|
||||
|
||||
getPlugin<K extends keyof PluginTypeRegistry<M, B>>(
|
||||
id: K,
|
||||
): PluginTypeRegistry<M, B>[K] | undefined
|
||||
|
||||
getPlugin<T extends UnknownPlugin<M, B> = UnknownPlugin<M, B>>(
|
||||
id: string,
|
||||
): T | undefined {
|
||||
): T | undefined
|
||||
|
||||
getPlugin(id: string): UnknownPlugin<M, B> | undefined {
|
||||
for (const plugins of Object.values(this.#plugins)) {
|
||||
const foundPlugin = plugins.find((plugin) => plugin.id === id)
|
||||
if (foundPlugin != null) return foundPlugin as T
|
||||
if (foundPlugin != null) {
|
||||
return foundPlugin as UnknownPlugin<M, B>
|
||||
}
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ export type {
|
|||
PartialTreeFolderNode,
|
||||
PartialTreeFolderRoot,
|
||||
PartialTreeId,
|
||||
PluginTypeRegistry,
|
||||
State,
|
||||
UnknownPlugin,
|
||||
UnknownProviderPlugin,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import type { Body, InternalMetadata, LocaleStrings, Meta } from '@uppy/utils'
|
||||
import { expectTypeOf, test } from 'vitest'
|
||||
import BasePlugin from './BasePlugin.js'
|
||||
import UIPlugin, { type UIPluginOptions } from './UIPlugin.js'
|
||||
import Uppy, { type UnknownPlugin } from './Uppy.js'
|
||||
|
||||
|
|
@ -68,3 +69,72 @@ test('Meta and Body generic move through the Uppy class', async () => {
|
|||
|
||||
await core.upload()
|
||||
})
|
||||
|
||||
class TestRegistryPlugin<M extends Meta, B extends Body> extends BasePlugin<
|
||||
Record<string, never>,
|
||||
M,
|
||||
B
|
||||
> {
|
||||
constructor(uppy: Uppy<M, B>) {
|
||||
super(uppy, {})
|
||||
this.id = 'TestRegistryPlugin'
|
||||
this.type = 'acquirer'
|
||||
}
|
||||
}
|
||||
|
||||
// Augment the Type Registry with our test plugin
|
||||
declare module './Uppy.js' {
|
||||
interface PluginTypeRegistry<M extends Meta, B extends Body> {
|
||||
TestRegistryPlugin: TestRegistryPlugin<M, B>
|
||||
}
|
||||
}
|
||||
|
||||
test('Type Registry: getPlugin with registered plugin name returns correct type', () => {
|
||||
const uppy = new Uppy()
|
||||
uppy.use(TestRegistryPlugin)
|
||||
|
||||
// When using a registered plugin name, TypeScript should infer the correct type from PluginTypeRegistry
|
||||
const plugin = uppy.getPlugin('TestRegistryPlugin')
|
||||
|
||||
expectTypeOf(plugin).toEqualTypeOf<
|
||||
TestRegistryPlugin<Meta, Record<string, never>> | undefined
|
||||
>()
|
||||
})
|
||||
|
||||
test('Type Registry: getPlugin with unregistered name returns UnknownPlugin', () => {
|
||||
const uppy = new Uppy()
|
||||
|
||||
// When using a non-registered string, should return UnknownPlugin
|
||||
const plugin = uppy.getPlugin('SomeRandomPlugin')
|
||||
|
||||
expectTypeOf(plugin).toEqualTypeOf<
|
||||
UnknownPlugin<Meta, Record<string, never>> | undefined
|
||||
>()
|
||||
})
|
||||
|
||||
test('Type Registry: getPlugin with dynamic string returns UnknownPlugin', () => {
|
||||
const uppy = new Uppy()
|
||||
const pluginName: string = 'DynamicName'
|
||||
|
||||
// Dynamic string should use the fallback overload unlike literal string
|
||||
const plugin = uppy.getPlugin(pluginName)
|
||||
|
||||
expectTypeOf(plugin).toEqualTypeOf<
|
||||
UnknownPlugin<Meta, Record<string, never>> | undefined
|
||||
>()
|
||||
})
|
||||
|
||||
test('Type Registry: works with custom Meta and Body types', () => {
|
||||
type CustomMeta = { userId: string; timestamp: number }
|
||||
type CustomBody = { encrypted: boolean }
|
||||
|
||||
// With custom Meta and Body types
|
||||
const uppy = new Uppy<CustomMeta, CustomBody>()
|
||||
uppy.use(TestRegistryPlugin)
|
||||
|
||||
const plugin = uppy.getPlugin('TestRegistryPlugin')
|
||||
|
||||
expectTypeOf(plugin).toEqualTypeOf<
|
||||
TestRegistryPlugin<CustomMeta, CustomBody> | undefined
|
||||
>()
|
||||
})
|
||||
|
|
|
|||
|
|
@ -40,6 +40,10 @@ declare module '@uppy/core' {
|
|||
'dashboard:file-edit-complete': DashboardFileEditCompleteCallback<M, B>
|
||||
'dashboard:close-panel': (id: string | undefined) => void
|
||||
}
|
||||
|
||||
export interface PluginTypeRegistry<M extends Meta, B extends Body> {
|
||||
Dashboard: Dashboard<M, B>
|
||||
}
|
||||
}
|
||||
|
||||
interface PromiseWithResolvers<T> {
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ afterEach(async () => {
|
|||
|
||||
// this is done to prevent the edgecase when all plugins are removed before dashboard is unmounted from UI
|
||||
// causing PickerPanelContent to crash
|
||||
const dashboard = uppy.getPlugin('Dashboard') as Dashboard<any, any>
|
||||
const dashboard = uppy.getPlugin('Dashboard')
|
||||
dashboard?.hideAllPanels()
|
||||
const panelSelector = '[data-uppy-panelType="PickerPanel"]'
|
||||
if (document.querySelector(panelSelector)) {
|
||||
|
|
|
|||
|
|
@ -12,6 +12,12 @@ import type { ComponentChild, h } from 'preact'
|
|||
import packageJson from '../package.json' with { type: 'json' }
|
||||
import locale from './locale.js'
|
||||
|
||||
declare module '@uppy/core' {
|
||||
export interface PluginTypeRegistry<M extends Meta, B extends Body> {
|
||||
DragDrop: DragDrop<M, B>
|
||||
}
|
||||
}
|
||||
|
||||
export interface DragDropOptions extends UIPluginOptions {
|
||||
inputName?: string
|
||||
allowMultipleFiles?: boolean
|
||||
|
|
|
|||
|
|
@ -3,6 +3,12 @@ import { BasePlugin } from '@uppy/core'
|
|||
import { getDroppedFiles, toArray } from '@uppy/utils'
|
||||
import packageJson from '../package.json' with { type: 'json' }
|
||||
|
||||
declare module '@uppy/core' {
|
||||
export interface PluginTypeRegistry<M extends Meta, B extends Body> {
|
||||
DropTarget: DropTarget<M, B>
|
||||
}
|
||||
}
|
||||
|
||||
export interface DropTargetOptions extends PluginOpts {
|
||||
target?: HTMLElement | string | null
|
||||
onDrop?: (event: DragEvent) => void
|
||||
|
|
|
|||
|
|
@ -21,6 +21,12 @@ import { type ComponentChild, h } from 'preact'
|
|||
import packageJson from '../package.json' with { type: 'json' }
|
||||
import locale from './locale.js'
|
||||
|
||||
declare module '@uppy/core' {
|
||||
export interface PluginTypeRegistry<M extends Meta, B extends Body> {
|
||||
Dropbox: Dropbox<M, B>
|
||||
}
|
||||
}
|
||||
|
||||
export type DropboxOptions = CompanionPluginOptions & {
|
||||
locale?: LocaleStrings<typeof locale>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,12 @@ import { type ComponentChild, h } from 'preact'
|
|||
import packageJson from '../package.json' with { type: 'json' }
|
||||
import locale from './locale.js'
|
||||
|
||||
declare module '@uppy/core' {
|
||||
export interface PluginTypeRegistry<M extends Meta, B extends Body> {
|
||||
Facebook: Facebook<M, B>
|
||||
}
|
||||
}
|
||||
|
||||
export type FacebookOptions = CompanionPluginOptions & {
|
||||
locale?: LocaleStrings<typeof locale>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,12 @@ import getFormData from 'get-form-data'
|
|||
|
||||
import packageJson from '../package.json' with { type: 'json' }
|
||||
|
||||
declare module '@uppy/core' {
|
||||
export interface PluginTypeRegistry<M extends Meta, B extends Body> {
|
||||
Form: Form<M, B>
|
||||
}
|
||||
}
|
||||
|
||||
type Result<M extends Meta, B extends Body> = Parameters<
|
||||
UppyEventMap<M, B>['complete']
|
||||
>[0]
|
||||
|
|
|
|||
|
|
@ -207,9 +207,9 @@ describe('Golden retriever', () => {
|
|||
|
||||
// Simulate ghosting of the files by deleting it from store(s)
|
||||
// @ts-expect-error
|
||||
;(uppy.getPlugin('GoldenRetriever') as GoldenRetriever<any, any>)[
|
||||
Symbol.for('uppy test: deleteBlobs')
|
||||
](fileIds)
|
||||
uppy
|
||||
.getPlugin('GoldenRetriever')
|
||||
[Symbol.for('uppy test: deleteBlobs')](fileIds)
|
||||
|
||||
// reload page and recreate Uppy instance
|
||||
uppy = createUppy({ withPageReload: true }).use(GoldenRetriever)
|
||||
|
|
|
|||
|
|
@ -19,6 +19,9 @@ declare module '@uppy/core' {
|
|||
export interface UppyEventMap<M extends Meta, B extends Body> {
|
||||
'restore:plugin-data-changed': (data: Record<string, unknown>) => void
|
||||
}
|
||||
export interface PluginTypeRegistry<M extends Meta, B extends Body> {
|
||||
GoldenRetriever: GoldenRetriever<M, B>
|
||||
}
|
||||
}
|
||||
|
||||
export interface GoldenRetrieverOptions extends PluginOpts {
|
||||
|
|
|
|||
|
|
@ -15,6 +15,12 @@ import type { LocaleStrings } from '@uppy/utils'
|
|||
import packageJson from '../package.json' with { type: 'json' }
|
||||
import locale from './locale.js'
|
||||
|
||||
declare module '@uppy/core' {
|
||||
export interface PluginTypeRegistry<M extends Meta, B extends Body> {
|
||||
GoogleDrivePicker: GoogleDrivePicker<M, B>
|
||||
}
|
||||
}
|
||||
|
||||
export type GoogleDrivePickerOptions = CompanionPluginOptions & {
|
||||
clientId: string
|
||||
apiKey: string
|
||||
|
|
|
|||
|
|
@ -22,6 +22,12 @@ import packageJson from '../package.json' with { type: 'json' }
|
|||
import DriveProviderViews from './DriveProviderViews.js'
|
||||
import locale from './locale.js'
|
||||
|
||||
declare module '@uppy/core' {
|
||||
export interface PluginTypeRegistry<M extends Meta, B extends Body> {
|
||||
GoogleDrive: GoogleDrive<M, B>
|
||||
}
|
||||
}
|
||||
|
||||
export type GoogleDriveOptions = CompanionPluginOptions & {
|
||||
locale?: LocaleStrings<typeof locale>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,12 @@ import type { LocaleStrings } from '@uppy/utils'
|
|||
import packageJson from '../package.json' with { type: 'json' }
|
||||
import locale from './locale.js'
|
||||
|
||||
declare module '@uppy/core' {
|
||||
export interface PluginTypeRegistry<M extends Meta, B extends Body> {
|
||||
GooglePhotosPicker: GooglePhotosPicker<M, B>
|
||||
}
|
||||
}
|
||||
|
||||
export type GooglePhotosPickerOptions = CompanionPluginOptions & {
|
||||
clientId: string
|
||||
locale?: LocaleStrings<typeof locale>
|
||||
|
|
|
|||
|
|
@ -13,6 +13,12 @@ import packageJson from '../package.json' with { type: 'json' }
|
|||
import Editor from './Editor.js'
|
||||
import locale from './locale.js'
|
||||
|
||||
declare module '@uppy/core' {
|
||||
export interface PluginTypeRegistry<M extends Meta, B extends Body> {
|
||||
ImageEditor: ImageEditor<M, B>
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
namespace preact {
|
||||
interface Component {
|
||||
|
|
|
|||
|
|
@ -21,6 +21,12 @@ import { type ComponentChild, h } from 'preact'
|
|||
import packageJson from '../package.json' with { type: 'json' }
|
||||
import locale from './locale.js'
|
||||
|
||||
declare module '@uppy/core' {
|
||||
export interface PluginTypeRegistry<M extends Meta, B extends Body> {
|
||||
Instagram: Instagram<M, B>
|
||||
}
|
||||
}
|
||||
|
||||
export type InstagramOptions = CompanionPluginOptions & {
|
||||
locale?: LocaleStrings<typeof locale>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -122,3 +122,9 @@ export default class OneDrive<M extends Meta, B extends Body>
|
|||
return this.view.render(state)
|
||||
}
|
||||
}
|
||||
|
||||
declare module '@uppy/core' {
|
||||
export interface PluginTypeRegistry<M extends Meta, B extends Body> {
|
||||
OneDrive: OneDrive<M, B>
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ class DashboardModal<M extends Meta, B extends Body> extends Component<
|
|||
|
||||
uppy.use(DashboardPlugin<M, B>, options)
|
||||
|
||||
this.plugin = uppy.getPlugin(options.id) as DashboardPlugin<M, B>
|
||||
this.plugin = uppy.getPlugin(options.id)!
|
||||
if (open) {
|
||||
this.plugin.openModal()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -122,3 +122,9 @@ export default class RemoteSources<
|
|||
this.#installedPlugins.clear()
|
||||
}
|
||||
}
|
||||
|
||||
declare module '@uppy/core' {
|
||||
export interface PluginTypeRegistry<M extends Meta, B extends Body> {
|
||||
RemoteSources: RemoteSources<M, B>
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,12 @@ import locale from './locale.js'
|
|||
import RecorderScreen from './RecorderScreen.js'
|
||||
import ScreenRecIcon from './ScreenRecIcon.js'
|
||||
|
||||
declare module '@uppy/core' {
|
||||
export interface PluginTypeRegistry<M extends Meta, B extends Body> {
|
||||
ScreenCapture: ScreenCapture<M, B>
|
||||
}
|
||||
}
|
||||
|
||||
// Check if screen capturing is supported.
|
||||
// mediaDevices is supprted on mobile Safari, getDisplayMedia is not
|
||||
function isScreenRecordingSupported() {
|
||||
|
|
|
|||
|
|
@ -15,6 +15,12 @@ import type { StatusBarOptions } from './StatusBarOptions.js'
|
|||
import statusBarStates from './StatusBarStates.js'
|
||||
import StatusBarUI, { type StatusBarUIProps } from './StatusBarUI.js'
|
||||
|
||||
declare module '@uppy/core' {
|
||||
export interface PluginTypeRegistry<M extends Meta, B extends Body> {
|
||||
StatusBar: StatusBar<M, B>
|
||||
}
|
||||
}
|
||||
|
||||
const speedFilterHalfLife = 2000
|
||||
const ETAFilterHalfLife = 2000
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ const installPlugin = () => {
|
|||
} satisfies DashboardOptions<M, B>;
|
||||
|
||||
uppy.use(DashboardPlugin<M, B>, options);
|
||||
plugin = uppy.getPlugin(options.id) as DashboardPlugin<M, B>;
|
||||
plugin = uppy.getPlugin(options.id)!;
|
||||
};
|
||||
const uninstallPlugin = (uppyInstance: Uppy<M, B> = uppy) => {
|
||||
if (plugin != null) uppyInstance.removePlugin(plugin);
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ const installPlugin = () => {
|
|||
} satisfies DashboardOptions<M, B>;
|
||||
|
||||
uppy.use(DashboardPlugin<M, B>, options);
|
||||
plugin = uppy.getPlugin(options.id) as DashboardPlugin<M, B>;
|
||||
plugin = uppy.getPlugin(options.id)!;
|
||||
if (open) plugin.openModal();
|
||||
};
|
||||
const uninstallPlugin = (uppyInstance: Uppy<M, B> = uppy) => {
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ const installPlugin = () => {
|
|||
} satisfies StatusBarOptions;
|
||||
|
||||
uppy.use(StatusBarPlugin<M, B>, options);
|
||||
plugin = uppy.getPlugin(options.id) as StatusBarPlugin<M, B>;
|
||||
plugin = uppy.getPlugin(options.id)!;
|
||||
};
|
||||
const uninstallPlugin = (uppyInstance: Uppy<M, B> = uppy) => {
|
||||
if (plugin != null) uppyInstance.removePlugin(plugin);
|
||||
|
|
|
|||
|
|
@ -15,6 +15,9 @@ declare module '@uppy/core' {
|
|||
'thumbnail:request': (file: UppyFile<M, B>) => void
|
||||
'thumbnail:cancel': (file: UppyFile<M, B>) => void
|
||||
}
|
||||
export interface PluginTypeRegistry<M extends Meta, B extends Body> {
|
||||
ThumbnailGenerator: ThumbnailGenerator<M, B>
|
||||
}
|
||||
}
|
||||
|
||||
interface Rotation {
|
||||
|
|
@ -500,3 +503,9 @@ export default class ThumbnailGenerator<
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
declare module '@uppy/core' {
|
||||
export interface PluginTypeRegistry<M extends Meta, B extends Body> {
|
||||
ThumbnailGenerator: ThumbnailGenerator<M, B>
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -132,6 +132,10 @@ declare module '@uppy/core' {
|
|||
progress_combined?: number
|
||||
}) => void
|
||||
}
|
||||
|
||||
export interface PluginTypeRegistry<M extends Meta, B extends Body> {
|
||||
Transloadit: Transloadit<M, B>
|
||||
}
|
||||
}
|
||||
|
||||
declare module '@uppy/utils' {
|
||||
|
|
|
|||
|
|
@ -106,6 +106,12 @@ declare module '@uppy/utils' {
|
|||
}
|
||||
}
|
||||
|
||||
declare module '@uppy/core' {
|
||||
export interface PluginTypeRegistry<M extends Meta, B extends Body> {
|
||||
Tus: Tus<M, B>
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tus resumable file uploader
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -112,3 +112,9 @@ export default class Unsplash<M extends Meta, B extends Body>
|
|||
this.unmount()
|
||||
}
|
||||
}
|
||||
|
||||
declare module '@uppy/core' {
|
||||
export interface PluginTypeRegistry<M extends Meta, B extends Body> {
|
||||
Unsplash: Unsplash<M, B>
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,12 @@ import locale from './locale.js'
|
|||
import UrlUI from './UrlUI.js'
|
||||
import forEachDroppedOrPastedUrl from './utils/forEachDroppedOrPastedUrl.js'
|
||||
|
||||
declare module '@uppy/core' {
|
||||
export interface PluginTypeRegistry<M extends Meta, B extends Body> {
|
||||
Url: Url<M, B>
|
||||
}
|
||||
}
|
||||
|
||||
function UrlIcon() {
|
||||
return (
|
||||
<svg
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ export default defineComponent({
|
|||
target: containerRef.value,
|
||||
}
|
||||
uppy.use(DashboardPlugin, options)
|
||||
pluginRef.value = uppy.getPlugin(options.id) as DashboardPlugin<any, any>
|
||||
pluginRef.value = uppy.getPlugin(options.id)!
|
||||
}
|
||||
|
||||
useUppy(onMount, pluginRef, props.uppy, propsRef)
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ export default defineComponent({
|
|||
target: containerRef.value,
|
||||
}
|
||||
uppy.use(DashboardPlugin, options)
|
||||
pluginRef.value = uppy.getPlugin(options.id) as DashboardPlugin<any, any>
|
||||
pluginRef.value = uppy.getPlugin(options.id)!
|
||||
}
|
||||
|
||||
useUppy(onMount, pluginRef, props.uppy, propsRef)
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ export default defineComponent({
|
|||
target: containerRef.value,
|
||||
}
|
||||
uppy.use(StatusBarPlugin, options)
|
||||
pluginRef.value = uppy.getPlugin(options.id) as StatusBarPlugin<any, any>
|
||||
pluginRef.value = uppy.getPlugin(options.id)!
|
||||
}
|
||||
|
||||
useUppy(onMount, pluginRef, props.uppy, propsRef)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import Uppy from '@uppy/core'
|
||||
import { Uppy } from '@uppy/core'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import Webcam from './index.js'
|
||||
|
||||
|
|
@ -10,10 +10,9 @@ describe('Webcam', () => {
|
|||
isTypeSupported: () => true,
|
||||
}
|
||||
|
||||
const uppy = new Uppy<any, any>().use(Webcam)
|
||||
const uppy = new Uppy().use(Webcam)
|
||||
expect(
|
||||
(uppy.getPlugin('Webcam') as Webcam<any, any>).getMediaRecorderOptions()
|
||||
.mimeType,
|
||||
uppy.getPlugin('Webcam')?.getMediaRecorderOptions().mimeType,
|
||||
).not.toBeDefined()
|
||||
})
|
||||
|
||||
|
|
@ -27,8 +26,7 @@ describe('Webcam', () => {
|
|||
preferredVideoMimeType: 'video/webm',
|
||||
})
|
||||
expect(
|
||||
(uppy.getPlugin('Webcam') as Webcam<any, any>).getMediaRecorderOptions()
|
||||
.mimeType,
|
||||
uppy.getPlugin('Webcam')?.getMediaRecorderOptions().mimeType,
|
||||
).toEqual('video/webm')
|
||||
})
|
||||
|
||||
|
|
@ -42,8 +40,7 @@ describe('Webcam', () => {
|
|||
preferredVideoMimeType: 'video/mp4',
|
||||
})
|
||||
expect(
|
||||
(uppy.getPlugin('Webcam') as Webcam<any, any>).getMediaRecorderOptions()
|
||||
.mimeType,
|
||||
uppy.getPlugin('Webcam')?.getMediaRecorderOptions().mimeType,
|
||||
).not.toBeDefined()
|
||||
})
|
||||
|
||||
|
|
@ -57,8 +54,7 @@ describe('Webcam', () => {
|
|||
restrictions: { allowedFileTypes: ['video/mp4', 'video/webm'] },
|
||||
}).use(Webcam)
|
||||
expect(
|
||||
(uppy.getPlugin('Webcam') as Webcam<any, any>).getMediaRecorderOptions()
|
||||
.mimeType,
|
||||
uppy.getPlugin('Webcam')?.getMediaRecorderOptions().mimeType,
|
||||
).toEqual('video/mp4')
|
||||
})
|
||||
|
||||
|
|
@ -72,8 +68,7 @@ describe('Webcam', () => {
|
|||
restrictions: { allowedFileTypes: ['video/mp4', 'video/webm'] },
|
||||
}).use(Webcam)
|
||||
expect(
|
||||
(uppy.getPlugin('Webcam') as Webcam<any, any>).getMediaRecorderOptions()
|
||||
.mimeType,
|
||||
uppy.getPlugin('Webcam')?.getMediaRecorderOptions().mimeType,
|
||||
).toEqual('video/webm')
|
||||
})
|
||||
|
||||
|
|
@ -89,8 +84,7 @@ describe('Webcam', () => {
|
|||
preferredVideoMimeType: 'video/webm',
|
||||
})
|
||||
expect(
|
||||
(uppy.getPlugin('Webcam') as Webcam<any, any>).getMediaRecorderOptions()
|
||||
.mimeType,
|
||||
uppy.getPlugin('Webcam')?.getMediaRecorderOptions().mimeType,
|
||||
).toEqual('video/webm')
|
||||
})
|
||||
|
||||
|
|
@ -104,8 +98,7 @@ describe('Webcam', () => {
|
|||
restrictions: { allowedFileTypes: ['video/mp4', 'video/webm'] },
|
||||
}).use(Webcam)
|
||||
expect(
|
||||
(uppy.getPlugin('Webcam') as Webcam<any, any>).getMediaRecorderOptions()
|
||||
.mimeType,
|
||||
uppy.getPlugin('Webcam')?.getMediaRecorderOptions().mimeType,
|
||||
).toEqual(undefined)
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -20,6 +20,12 @@ import locale from './locale.js'
|
|||
import PermissionsScreen from './PermissionsScreen.js'
|
||||
import supportsMediaRecorder from './supportsMediaRecorder.js'
|
||||
|
||||
declare module '@uppy/core' {
|
||||
export interface PluginTypeRegistry<M extends Meta, B extends Body> {
|
||||
Webcam: Webcam<M, B>
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize a MIME type or file extension into a MIME type.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -163,3 +163,9 @@ export default class Webdav<M extends Meta, B extends Body>
|
|||
return this.view.render(state)
|
||||
}
|
||||
}
|
||||
|
||||
declare module '@uppy/core' {
|
||||
export interface PluginTypeRegistry<M extends Meta, B extends Body> {
|
||||
WebDav: Webdav<M, B>
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -86,6 +86,12 @@ declare module '@uppy/core' {
|
|||
}
|
||||
}
|
||||
|
||||
declare module '@uppy/core' {
|
||||
export interface PluginTypeRegistry<M extends Meta, B extends Body> {
|
||||
XHRUpload: XHRUpload<M, B>
|
||||
}
|
||||
}
|
||||
|
||||
function buildResponseError(
|
||||
xhr?: XMLHttpRequest,
|
||||
err?: string | Error | NetworkError,
|
||||
|
|
|
|||
|
|
@ -107,3 +107,9 @@ export default class Zoom<M extends Meta, B extends Body>
|
|||
return this.view.render(state)
|
||||
}
|
||||
}
|
||||
|
||||
declare module '@uppy/core' {
|
||||
export interface PluginTypeRegistry<M extends Meta, B extends Body> {
|
||||
Zoom: Zoom<M, B>
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue