mirror of
https://github.com/transloadit/uppy.git
synced 2026-01-23 02:25:07 +00:00
Bring back StatusBar and DragDrop (#5931)
While the frameworks have good alternatives now with new components and hooks, Uppy is also popular in 'vanilla' JS setups without frameworks using the CDN bundle. Consumers of this were left with no viable alternative so it's sensible to bring back status bar and drag drop for the CDN publish (at least until we also publish/document using hooks via CDN). The framework packages don't really need this, as the alternatives are viable there. - Bring back `@uppy/status-bar` and `@uppy/drag-drop` from git tag `4.18.1` (latest release before 5.0) - Put exports maps on both packages - Put both packages in the CDN bundle - Version appropriately with changesets - Override existing locale keys. Unfortunately now that status-bar was merged into dashboard, the keys need to exist in both places but our tooling was setup to error when the same keys are found. Now it just overrides the existing key (to the same value in this case)
This commit is contained in:
parent
057c1aeefa
commit
3290864cf3
37 changed files with 2777 additions and 6 deletions
9
.changeset/all-ties-march.md
Normal file
9
.changeset/all-ties-march.md
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
---
|
||||
"@uppy/status-bar": major
|
||||
"@uppy/drag-drop": major
|
||||
---
|
||||
|
||||
All packages now have export maps. This is a breaking change in two cases:
|
||||
|
||||
1. The css imports have changed from `@uppy[package]/dist/styles.min.css` to `@uppy[package]/css/styles.min.css`
|
||||
2. You were importing something that wasn't exported from the root, for instance `@uppy/core/lib/foo.js`. You can now only import things we explicitly exported.
|
||||
5
.changeset/whole-brooms-sneeze.md
Normal file
5
.changeset/whole-brooms-sneeze.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
"uppy": minor
|
||||
---
|
||||
|
||||
Bring back StatusBar and DragDrop into the CDN bundle
|
||||
1
packages/@uppy/drag-drop/.npmignore
Normal file
1
packages/@uppy/drag-drop/.npmignore
Normal file
|
|
@ -0,0 +1 @@
|
|||
tsconfig.*
|
||||
139
packages/@uppy/drag-drop/CHANGELOG.md
Normal file
139
packages/@uppy/drag-drop/CHANGELOG.md
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
# @uppy/drag-drop
|
||||
|
||||
## 4.2.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 1b1a9e3: Define "files" in package.json
|
||||
- Updated dependencies [1b1a9e3]
|
||||
- @uppy/utils@6.2.2
|
||||
- @uppy/core@4.5.2
|
||||
|
||||
## 4.2.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 0c24c5a: Use TypeScript compiler instead of Babel
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [0c24c5a]
|
||||
- Updated dependencies [0c24c5a]
|
||||
- @uppy/core@4.5.0
|
||||
- @uppy/utils@6.2.0
|
||||
|
||||
## 4.1.3
|
||||
|
||||
Released: 2025-05-18
|
||||
Included in: Uppy v4.16.0
|
||||
|
||||
- @uppy/audio,@uppy/box,@uppy/core,@uppy/dashboard,@uppy/drag-drop,@uppy/dropbox,@uppy/facebook,@uppy/file-input,@uppy/google-drive-picker,@uppy/google-drive,@uppy/google-photos-picker,@uppy/image-editor,@uppy/instagram,@uppy/onedrive,@uppy/remote-sources,@uppy/screen-capture,@uppy/unsplash,@uppy/url,@uppy/utils,@uppy/webcam,@uppy/webdav,@uppy/zoom: ts: make locale strings optional (Merlijn Vos / #5728)
|
||||
|
||||
## 4.1.0
|
||||
|
||||
Released: 2025-01-06
|
||||
Included in: Uppy v4.11.0
|
||||
|
||||
- @uppy/angular,@uppy/audio,@uppy/aws-s3,@uppy/box,@uppy/companion-client,@uppy/compressor,@uppy/core,@uppy/dashboard,@uppy/drag-drop,@uppy/drop-target,@uppy/dropbox,@uppy/facebook,@uppy/file-input,@uppy/form,@uppy/golden-retriever,@uppy/google-drive-picker,@uppy/google-drive,@uppy/google-photos-picker,@uppy/google-photos,@uppy/image-editor,@uppy/informer,@uppy/instagram,@uppy/locales,@uppy/onedrive,@uppy/progress-bar,@uppy/provider-views,@uppy/react,@uppy/remote-sources,@uppy/screen-capture,@uppy/status-bar,@uppy/thumbnail-generator,@uppy/transloadit,@uppy/tus,@uppy/unsplash,@uppy/url,@uppy/vue,@uppy/webcam,@uppy/webdav,@uppy/xhr-upload,@uppy/zoom: Remove "paths" from all tsconfig's (Merlijn Vos / #5572)
|
||||
|
||||
## 4.0.5
|
||||
|
||||
Released: 2024-12-05
|
||||
Included in: Uppy v4.8.0
|
||||
|
||||
- @uppy/audio,@uppy/aws-s3,@uppy/box,@uppy/companion-client,@uppy/compressor,@uppy/core,@uppy/dashboard,@uppy/drag-drop,@uppy/drop-target,@uppy/dropbox,@uppy/facebook,@uppy/file-input,@uppy/form,@uppy/golden-retriever,@uppy/google-drive,@uppy/google-photos,@uppy/image-editor,@uppy/informer,@uppy/instagram,@uppy/locales,@uppy/onedrive,@uppy/progress-bar,@uppy/provider-views,@uppy/react,@uppy/remote-sources,@uppy/screen-capture,@uppy/status-bar,@uppy/store-default,@uppy/thumbnail-generator,@uppy/transloadit,@uppy/tus,@uppy/unsplash,@uppy/url,@uppy/utils,@uppy/vue,@uppy/webcam,@uppy/xhr-upload,@uppy/zoom: cleanup tsconfig (Mikael Finstad / #5520)
|
||||
|
||||
## 4.0.4
|
||||
|
||||
Released: 2024-10-31
|
||||
Included in: Uppy v4.6.0
|
||||
|
||||
- @uppy/aws-s3,@uppy/box,@uppy/companion-client,@uppy/core,@uppy/dashboard,@uppy/drag-drop,@uppy/dropbox,@uppy/facebook,@uppy/file-input,@uppy/form,@uppy/golden-retriever,@uppy/google-drive,@uppy/google-photos,@uppy/image-editor,@uppy/informer,@uppy/instagram,@uppy/locales,@uppy/onedrive,@uppy/progress-bar,@uppy/provider-views,@uppy/react-native,@uppy/react,@uppy/redux-dev-tools,@uppy/screen-capture,@uppy/status-bar,@uppy/store-default,@uppy/store-redux,@uppy/svelte,@uppy/thumbnail-generator,@uppy/transloadit,@uppy/tus,@uppy/unsplash,@uppy/url,@uppy/utils,@uppy/vue,@uppy/webcam,@uppy/xhr-upload,@uppy/zoom: Fix links (Anthony Veaudry / #5492)
|
||||
|
||||
## 4.0.3
|
||||
|
||||
Released: 2024-10-15
|
||||
Included in: Uppy v4.5.0
|
||||
|
||||
- @uppy/dashboard,@uppy/drag-drop,@uppy/file-input: `.handleInputChange()` - use `.currentTarget`; clear the input using `''` (Evgenia Karunus / #5381)
|
||||
|
||||
## 4.0.2
|
||||
|
||||
Released: 2024-08-15
|
||||
Included in: Uppy v4.1.1
|
||||
|
||||
- @uppy/dashboard,@uppy/drag-drop,@uppy/file-input: Transform the `accept` prop into a string everywhere (Evgenia Karunus / #5380)
|
||||
|
||||
## 4.0.1
|
||||
|
||||
Released: 2024-07-15
|
||||
Included in: Uppy v4.0.1
|
||||
|
||||
- @uppy/dashboard,@uppy/drag-drop,@uppy/drop-target: `<Dashboard/>`, `<DragDrop/>`, `drop-target` - new anti-flickering solution (Evgenia Karunus / #5326)
|
||||
|
||||
## 4.0.0-beta.1
|
||||
|
||||
Released: 2024-03-28
|
||||
Included in: Uppy v4.0.0-beta.1
|
||||
|
||||
- @uppy/drag-drop: refine type of private variables (Antoine du Hamel / #5026)
|
||||
- @uppy/drag-drop,@uppy/progress-bar: add missing exports (Antoine du Hamel / #5009)
|
||||
- @uppy/drag-drop: refactor to TypeScript (Antoine du Hamel / #4983)
|
||||
|
||||
## 3.1.1
|
||||
|
||||
Released: 2024-07-02
|
||||
Included in: Uppy v3.27.2
|
||||
|
||||
- docs,@uppy/drag-drop: `uppy.io/docs` - fix typos/broken links (Evgenia Karunus / #5296)
|
||||
|
||||
## 3.1.0
|
||||
|
||||
Released: 2024-03-27
|
||||
Included in: Uppy v3.24.0
|
||||
|
||||
- @uppy/drag-drop: refine type of private variables (Antoine du Hamel / #5026)
|
||||
- @uppy/drag-drop,@uppy/progress-bar: add missing exports (Antoine du Hamel / #5009)
|
||||
- @uppy/drag-drop: refactor to TypeScript (Antoine du Hamel / #4983)
|
||||
|
||||
## 3.0.1
|
||||
|
||||
Released: 2022-09-25
|
||||
Included in: Uppy v3.1.0
|
||||
|
||||
- @uppy/audio,@uppy/aws-s3-multipart,@uppy/aws-s3,@uppy/box,@uppy/companion-client,@uppy/companion,@uppy/compressor,@uppy/core,@uppy/dashboard,@uppy/drag-drop,@uppy/drop-target,@uppy/dropbox,@uppy/facebook,@uppy/file-input,@uppy/form,@uppy/golden-retriever,@uppy/google-drive,@uppy/image-editor,@uppy/informer,@uppy/instagram,@uppy/locales,@uppy/onedrive,@uppy/progress-bar,@uppy/provider-views,@uppy/react,@uppy/redux-dev-tools,@uppy/remote-sources,@uppy/screen-capture,@uppy/status-bar,@uppy/store-default,@uppy/store-redux,@uppy/svelte,@uppy/thumbnail-generator,@uppy/transloadit,@uppy/tus,@uppy/unsplash,@uppy/url,@uppy/utils,@uppy/vue,@uppy/webcam,@uppy/xhr-upload,@uppy/zoom: add missing entries to changelog for individual packages (Antoine du Hamel / #4092)
|
||||
|
||||
## 3.0.0
|
||||
|
||||
Released: 2022-08-22
|
||||
Included in: Uppy v3.0.0
|
||||
|
||||
- Switch to ESM
|
||||
|
||||
## 2.1.1
|
||||
|
||||
Released: 2022-05-30
|
||||
Included in: Uppy v2.11.0
|
||||
|
||||
- @uppy/angular,@uppy/audio,@uppy/aws-s3-multipart,@uppy/aws-s3,@uppy/box,@uppy/core,@uppy/dashboard,@uppy/drag-drop,@uppy/dropbox,@uppy/facebook,@uppy/file-input,@uppy/form,@uppy/golden-retriever,@uppy/google-drive,@uppy/image-editor,@uppy/informer,@uppy/instagram,@uppy/onedrive,@uppy/progress-bar,@uppy/react,@uppy/redux-dev-tools,@uppy/robodog,@uppy/screen-capture,@uppy/status-bar,@uppy/store-default,@uppy/store-redux,@uppy/thumbnail-generator,@uppy/transloadit,@uppy/tus,@uppy/unsplash,@uppy/url,@uppy/vue,@uppy/webcam,@uppy/xhr-upload,@uppy/zoom: doc: update bundler recommendation (Antoine du Hamel / #3763)
|
||||
|
||||
## 2.0.7
|
||||
|
||||
Released: 2022-04-27
|
||||
Included in: Uppy v2.9.4
|
||||
|
||||
- @uppy/drag-drop: refactor to ESM (Antoine du Hamel / #3647)
|
||||
|
||||
## 2.0.6
|
||||
|
||||
Released: 2022-01-10
|
||||
Included in: Uppy v2.4.0
|
||||
|
||||
- @uppy/drag-drop: fix `undefined is not a function` TypeError (Antoine du Hamel / #3397)
|
||||
|
||||
## 2.0.5
|
||||
|
||||
Released: 2021-12-07
|
||||
Included in: Uppy v2.3.0
|
||||
|
||||
- @uppy/aws-s3,@uppy/box,@uppy/core,@uppy/dashboard,@uppy/drag-drop,@uppy/dropbox,@uppy/facebook,@uppy/file-input,@uppy/google-drive,@uppy/image-editor,@uppy/instagram,@uppy/locales,@uppy/onedrive,@uppy/screen-capture,@uppy/status-bar,@uppy/thumbnail-generator,@uppy/transloadit,@uppy/url,@uppy/webcam,@uppy/xhr-upload,@uppy/zoom: Refactor locale scripts & generate types and docs (Merlijn Vos / #3276)
|
||||
21
packages/@uppy/drag-drop/LICENSE
Normal file
21
packages/@uppy/drag-drop/LICENSE
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2018 Transloadit
|
||||
|
||||
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.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
47
packages/@uppy/drag-drop/README.md
Normal file
47
packages/@uppy/drag-drop/README.md
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
# @uppy/drag-drop
|
||||
|
||||
<img src="https://uppy.io/img/logo.svg" width="120" alt="Uppy logo: a smiling puppy above a pink upwards arrow" align="right">
|
||||
|
||||
[](https://www.npmjs.com/package/@uppy/drag-drop)
|
||||

|
||||

|
||||

|
||||
|
||||
Droppable zone UI for Uppy. Drag and drop files into it to upload.
|
||||
|
||||
**[Read the docs](https://uppy.io/docs/drag-drop/)**
|
||||
|
||||
Uppy is being developed by the folks at [Transloadit](https://transloadit.com),
|
||||
a versatile file encoding service.
|
||||
|
||||
## Example
|
||||
|
||||
```js
|
||||
import Uppy from '@uppy/core'
|
||||
import DragDrop from '@uppy/drag-drop'
|
||||
|
||||
const uppy = new Uppy()
|
||||
uppy.use(DragDrop, {
|
||||
target: '#upload',
|
||||
})
|
||||
```
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
$ npm install @uppy/drag-drop
|
||||
```
|
||||
|
||||
Alternatively, you can also use this plugin in a pre-built bundle from
|
||||
Transloadit’s CDN: Smart CDN. In that case `Uppy` will attach itself to the
|
||||
global `window.Uppy` object. See the
|
||||
[main Uppy documentation](https://uppy.io/docs/#Installation) for instructions.
|
||||
|
||||
## Documentation
|
||||
|
||||
Documentation for this plugin can be found on the
|
||||
[Uppy website](https://uppy.io/docs/drag-drop/).
|
||||
|
||||
## License
|
||||
|
||||
[The MIT License](./LICENSE).
|
||||
61
packages/@uppy/drag-drop/package.json
Normal file
61
packages/@uppy/drag-drop/package.json
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
{
|
||||
"name": "@uppy/drag-drop",
|
||||
"description": "Droppable zone UI for Uppy. Drag and drop files into it to upload.",
|
||||
"version": "4.2.2",
|
||||
"license": "MIT",
|
||||
"main": "lib/index.js",
|
||||
"style": "dist/style.min.css",
|
||||
"type": "module",
|
||||
"sideEffects": [
|
||||
"*.css"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "tsc --build tsconfig.build.json",
|
||||
"build:css": "sass --load-path=../../ src/style.scss dist/style.css && postcss dist/style.css -u cssnano -o dist/style.min.css",
|
||||
"typecheck": "tsc --build"
|
||||
},
|
||||
"keywords": [
|
||||
"file uploader",
|
||||
"uppy",
|
||||
"uppy-plugin",
|
||||
"drag-drop",
|
||||
"drag",
|
||||
"drop",
|
||||
"dropzone",
|
||||
"upload"
|
||||
],
|
||||
"homepage": "https://uppy.io",
|
||||
"bugs": {
|
||||
"url": "https://github.com/transloadit/uppy/issues"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/transloadit/uppy.git"
|
||||
},
|
||||
"files": [
|
||||
"src",
|
||||
"lib",
|
||||
"dist",
|
||||
"CHANGELOG.md"
|
||||
],
|
||||
"exports": {
|
||||
".": "./lib/index.js",
|
||||
"./css/style.css": "./dist/style.css",
|
||||
"./css/style.min.css": "./dist/style.min.css",
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
"dependencies": {
|
||||
"@uppy/utils": "workspace:^",
|
||||
"preact": "^10.5.13"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@uppy/core": "workspace:^"
|
||||
},
|
||||
"devDependencies": {
|
||||
"cssnano": "^7.0.7",
|
||||
"postcss": "^8.5.6",
|
||||
"postcss-cli": "^11.0.1",
|
||||
"sass": "^1.89.2",
|
||||
"typescript": "^5.8.3"
|
||||
}
|
||||
}
|
||||
245
packages/@uppy/drag-drop/src/DragDrop.tsx
Normal file
245
packages/@uppy/drag-drop/src/DragDrop.tsx
Normal file
|
|
@ -0,0 +1,245 @@
|
|||
import type {
|
||||
Body,
|
||||
DefinePluginOpts,
|
||||
Meta,
|
||||
UIPluginOptions,
|
||||
Uppy,
|
||||
} from '@uppy/core'
|
||||
import { UIPlugin } from '@uppy/core'
|
||||
import type { LocaleStrings } from '@uppy/utils'
|
||||
import { getDroppedFiles, isDragDropSupported, toArray } from '@uppy/utils'
|
||||
import type { ComponentChild } from 'preact'
|
||||
import type { TargetedEvent } from 'preact/compat'
|
||||
import packageJson from '../package.json' with { type: 'json' }
|
||||
import locale from './locale.js'
|
||||
|
||||
export interface DragDropOptions extends UIPluginOptions {
|
||||
inputName?: string
|
||||
allowMultipleFiles?: boolean
|
||||
width?: string | number
|
||||
height?: string | number
|
||||
note?: string
|
||||
onDragOver?: (event: DragEvent) => void
|
||||
onDragLeave?: (event: DragEvent) => void
|
||||
onDrop?: (event: DragEvent) => void
|
||||
locale?: LocaleStrings<typeof locale>
|
||||
}
|
||||
|
||||
const defaultOptions = {
|
||||
inputName: 'files[]',
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
} satisfies Partial<DragDropOptions>
|
||||
|
||||
/**
|
||||
* Drag & Drop plugin
|
||||
*
|
||||
*/
|
||||
export default class DragDrop<M extends Meta, B extends Body> extends UIPlugin<
|
||||
DefinePluginOpts<DragDropOptions, keyof typeof defaultOptions>,
|
||||
M,
|
||||
B
|
||||
> {
|
||||
static VERSION = packageJson.version
|
||||
|
||||
// Check for browser dragDrop support
|
||||
private isDragDropSupported = isDragDropSupported()
|
||||
|
||||
private fileInputRef!: HTMLInputElement
|
||||
|
||||
constructor(uppy: Uppy<M, B>, opts?: DragDropOptions) {
|
||||
super(uppy, {
|
||||
...defaultOptions,
|
||||
...opts,
|
||||
})
|
||||
this.type = 'acquirer'
|
||||
this.id = this.opts.id || 'DragDrop'
|
||||
this.title = 'Drag & Drop'
|
||||
|
||||
this.defaultLocale = locale
|
||||
|
||||
this.i18nInit()
|
||||
}
|
||||
|
||||
private addFiles = (files: File[]) => {
|
||||
const descriptors = files.map((file) => ({
|
||||
source: this.id,
|
||||
name: file.name,
|
||||
type: file.type,
|
||||
data: file,
|
||||
meta: {
|
||||
// path of the file relative to the ancestor directory the user selected.
|
||||
// e.g. 'docs/Old Prague/airbnb.pdf'
|
||||
relativePath: (file as any).relativePath || null,
|
||||
} as any as M,
|
||||
}))
|
||||
|
||||
try {
|
||||
this.uppy.addFiles(descriptors)
|
||||
} catch (err) {
|
||||
this.uppy.log(err as any)
|
||||
}
|
||||
}
|
||||
|
||||
private onInputChange = (event: TargetedEvent<HTMLInputElement, Event>) => {
|
||||
const files = toArray(event.currentTarget.files || [])
|
||||
if (files.length > 0) {
|
||||
this.uppy.log('[DragDrop] Files selected through input')
|
||||
this.addFiles(files)
|
||||
}
|
||||
|
||||
// Clear the input so that Chrome can detect file section when the same file is repeatedly selected
|
||||
// (see https://github.com/transloadit/uppy/issues/768#issuecomment-2264902758)
|
||||
event.currentTarget.value = ''
|
||||
}
|
||||
|
||||
private handleDragOver = (event: DragEvent) => {
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
|
||||
// Check if the "type" of the datatransfer object includes files. If not, deny drop.
|
||||
const { types } = event.dataTransfer!
|
||||
const hasFiles = types.some((type) => type === 'Files')
|
||||
const { allowNewUpload } = this.uppy.getState()
|
||||
if (!hasFiles || !allowNewUpload) {
|
||||
event.dataTransfer!.dropEffect = 'none'
|
||||
return
|
||||
}
|
||||
|
||||
// Add a small (+) icon on drop
|
||||
// (and prevent browsers from interpreting this as files being _moved_ into the browser
|
||||
// https://github.com/transloadit/uppy/issues/1978)
|
||||
//
|
||||
event.dataTransfer!.dropEffect = 'copy'
|
||||
|
||||
this.setPluginState({ isDraggingOver: true })
|
||||
|
||||
this.opts.onDragOver?.(event)
|
||||
}
|
||||
|
||||
private handleDragLeave = (event: DragEvent) => {
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
|
||||
this.setPluginState({ isDraggingOver: false })
|
||||
|
||||
this.opts.onDragLeave?.(event)
|
||||
}
|
||||
|
||||
private handleDrop = async (event: DragEvent) => {
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
|
||||
this.setPluginState({ isDraggingOver: false })
|
||||
|
||||
const logDropError = (error: any) => {
|
||||
this.uppy.log(error, 'error')
|
||||
}
|
||||
|
||||
// Add all dropped files
|
||||
const files = await getDroppedFiles(event.dataTransfer!, { logDropError })
|
||||
if (files.length > 0) {
|
||||
this.uppy.log('[DragDrop] Files dropped')
|
||||
this.addFiles(files)
|
||||
}
|
||||
|
||||
this.opts.onDrop?.(event)
|
||||
}
|
||||
|
||||
private renderHiddenFileInput() {
|
||||
const { restrictions } = this.uppy.opts
|
||||
return (
|
||||
<input
|
||||
className="uppy-DragDrop-input"
|
||||
type="file"
|
||||
hidden
|
||||
ref={(ref) => {
|
||||
this.fileInputRef = ref!
|
||||
}}
|
||||
name={this.opts.inputName}
|
||||
multiple={restrictions.maxNumberOfFiles !== 1}
|
||||
accept={restrictions.allowedFileTypes?.join(', ')}
|
||||
onChange={this.onInputChange}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
private static renderArrowSvg() {
|
||||
return (
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
focusable="false"
|
||||
className="uppy-c-icon uppy-DragDrop-arrow"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 16 16"
|
||||
>
|
||||
<path d="M11 10V0H5v10H2l6 6 6-6h-3zm0 0" fillRule="evenodd" />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
private renderLabel() {
|
||||
return (
|
||||
<div className="uppy-DragDrop-label">
|
||||
{this.i18nArray('dropHereOr', {
|
||||
browse: (
|
||||
<span className="uppy-DragDrop-browse">{this.i18n('browse')}</span>
|
||||
) as any,
|
||||
})}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
private renderNote() {
|
||||
return <span className="uppy-DragDrop-note">{this.opts.note}</span>
|
||||
}
|
||||
|
||||
render(): ComponentChild {
|
||||
const dragDropClass = `uppy-u-reset
|
||||
uppy-DragDrop-container
|
||||
${this.isDragDropSupported ? 'uppy-DragDrop--isDragDropSupported' : ''}
|
||||
${this.getPluginState().isDraggingOver ? 'uppy-DragDrop--isDraggingOver' : ''}
|
||||
`
|
||||
|
||||
const dragDropStyle = {
|
||||
width: this.opts.width,
|
||||
height: this.opts.height,
|
||||
}
|
||||
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
className={dragDropClass}
|
||||
style={dragDropStyle}
|
||||
onClick={() => this.fileInputRef.click()}
|
||||
onDragOver={this.handleDragOver}
|
||||
onDragLeave={this.handleDragLeave}
|
||||
onDrop={this.handleDrop}
|
||||
>
|
||||
{this.renderHiddenFileInput()}
|
||||
<div className="uppy-DragDrop-inner">
|
||||
{DragDrop.renderArrowSvg()}
|
||||
{this.renderLabel()}
|
||||
{this.renderNote()}
|
||||
</div>
|
||||
</button>
|
||||
)
|
||||
}
|
||||
|
||||
install(): void {
|
||||
const { target } = this.opts
|
||||
|
||||
this.setPluginState({
|
||||
isDraggingOver: false,
|
||||
})
|
||||
|
||||
if (target) {
|
||||
this.mount(target, this)
|
||||
}
|
||||
}
|
||||
|
||||
uninstall(): void {
|
||||
this.unmount()
|
||||
}
|
||||
}
|
||||
2
packages/@uppy/drag-drop/src/index.ts
Normal file
2
packages/@uppy/drag-drop/src/index.ts
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
export type { DragDropOptions } from './DragDrop.js'
|
||||
export { default } from './DragDrop.js'
|
||||
9
packages/@uppy/drag-drop/src/locale.ts
Normal file
9
packages/@uppy/drag-drop/src/locale.ts
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
export default {
|
||||
strings: {
|
||||
// Text to show on the droppable area.
|
||||
// `%{browse}` is replaced with a link that opens the system file selection dialog.
|
||||
dropHereOr: 'Drop here or %{browse}',
|
||||
// Used as the label for the link that opens the system file selection dialog.
|
||||
browse: 'browse',
|
||||
},
|
||||
}
|
||||
67
packages/@uppy/drag-drop/src/style.scss
Normal file
67
packages/@uppy/drag-drop/src/style.scss
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
@use "sass:color";
|
||||
@use '@uppy/core/src/_utils.scss';
|
||||
@use '@uppy/core/src/_variables.scss';
|
||||
|
||||
.uppy-DragDrop-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
max-width: 100%;
|
||||
font-family: variables.$font-family-base;
|
||||
background-color: variables.$white;
|
||||
border-radius: 7px;
|
||||
cursor: pointer;
|
||||
|
||||
// firefox fix: removes thin dotted outline
|
||||
&::-moz-focus-inner {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
box-shadow: 0 0 0 3px rgba(variables.$blue, 0.4);
|
||||
}
|
||||
}
|
||||
|
||||
.uppy-DragDrop-inner {
|
||||
margin: 0;
|
||||
padding: 80px 20px;
|
||||
line-height: 1.4;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.uppy-DragDrop-arrow {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
margin-bottom: 17px;
|
||||
fill: color.adjust(variables.$gray-500, $lightness: 30%);
|
||||
}
|
||||
|
||||
.uppy-DragDrop--isDragDropSupported {
|
||||
border: 2px dashed color.adjust(variables.$gray-500, $lightness: 10%);
|
||||
}
|
||||
|
||||
.uppy-DragDrop--isDraggingOver {
|
||||
background: variables.$gray-200;
|
||||
border: 2px dashed variables.$blue;
|
||||
|
||||
.uppy-DragDrop-arrow {
|
||||
fill: variables.$gray-500;
|
||||
}
|
||||
}
|
||||
|
||||
.uppy-DragDrop-label {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
font-size: 1.15em;
|
||||
}
|
||||
|
||||
.uppy-DragDrop-browse {
|
||||
color: variables.$blue;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.uppy-DragDrop-note {
|
||||
color: color.adjust(variables.$gray-500, $lightness: 10%);
|
||||
font-size: 1em;
|
||||
}
|
||||
17
packages/@uppy/drag-drop/tsconfig.build.json
Normal file
17
packages/@uppy/drag-drop/tsconfig.build.json
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"extends": "../../../tsconfig.shared",
|
||||
"compilerOptions": {
|
||||
"outDir": "./lib",
|
||||
"rootDir": "./src"
|
||||
},
|
||||
"include": ["./src/**/*.*"],
|
||||
"exclude": ["./src/**/*.test.ts"],
|
||||
"references": [
|
||||
{
|
||||
"path": "../utils/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../core/tsconfig.build.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
16
packages/@uppy/drag-drop/tsconfig.json
Normal file
16
packages/@uppy/drag-drop/tsconfig.json
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"extends": "../../../tsconfig.shared",
|
||||
"compilerOptions": {
|
||||
"emitDeclarationOnly": false,
|
||||
"noEmit": true
|
||||
},
|
||||
"include": ["./package.json", "./src/**/*.*"],
|
||||
"references": [
|
||||
{
|
||||
"path": "../utils/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../core/tsconfig.build.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
8
packages/@uppy/drag-drop/turbo.json
Normal file
8
packages/@uppy/drag-drop/turbo.json
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"extends": ["//"],
|
||||
"tasks": {
|
||||
"build": {
|
||||
"dependsOn": ["^build", "@uppy/core#build"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -17,13 +17,8 @@ async function getLocalesAndCombinedLocale() {
|
|||
const locales = await getLocales(`${root}/packages/@uppy/**/lib/locale.js`)
|
||||
|
||||
const combinedLocale = {}
|
||||
for (const [pluginName, locale] of Object.entries(locales)) {
|
||||
for (const [, locale] of Object.entries(locales)) {
|
||||
for (const [key, value] of Object.entries(locale.strings)) {
|
||||
if (key in combinedLocale && value !== combinedLocale[key]) {
|
||||
throw new Error(
|
||||
`'${key}' from ${pluginName} already exists in locale pack.`,
|
||||
)
|
||||
}
|
||||
combinedLocale[key] = value
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ en_US.strings = {
|
|||
authenticateWithTitle:
|
||||
'Please authenticate with %{pluginName} to select files',
|
||||
back: 'Back',
|
||||
browse: 'browse',
|
||||
browseFiles: 'browse files',
|
||||
browseFolders: 'browse folders',
|
||||
cancel: 'Cancel',
|
||||
|
|
@ -63,6 +64,7 @@ en_US.strings = {
|
|||
discardMediaFile: 'Discard Media',
|
||||
discardRecordedFile: 'Discard recorded file',
|
||||
done: 'Done',
|
||||
dropHereOr: 'Drop here or %{browse}',
|
||||
dropHint: 'Drop your files here',
|
||||
dropPasteBoth: 'Drop files here, %{browseFiles} or %{browseFolders}',
|
||||
dropPasteFiles: 'Drop files here or %{browseFiles}',
|
||||
|
|
|
|||
1
packages/@uppy/status-bar/.npmignore
Normal file
1
packages/@uppy/status-bar/.npmignore
Normal file
|
|
@ -0,0 +1 @@
|
|||
tsconfig.*
|
||||
215
packages/@uppy/status-bar/CHANGELOG.md
Normal file
215
packages/@uppy/status-bar/CHANGELOG.md
Normal file
|
|
@ -0,0 +1,215 @@
|
|||
# @uppy/status-bar
|
||||
|
||||
## 4.2.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- c15c6fd: Make each entry in `strings` in locale type optional
|
||||
|
||||
## 4.2.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 1b1a9e3: Define "files" in package.json
|
||||
- Updated dependencies [1b1a9e3]
|
||||
- @uppy/utils@6.2.2
|
||||
- @uppy/core@4.5.2
|
||||
|
||||
## 4.2.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 0c24c5a: Use TypeScript compiler instead of Babel
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [0c24c5a]
|
||||
- Updated dependencies [0c24c5a]
|
||||
- @uppy/core@4.5.0
|
||||
- @uppy/utils@6.2.0
|
||||
|
||||
## 4.1.2
|
||||
|
||||
Released: 2025-02-25
|
||||
Included in: Uppy v4.13.3
|
||||
|
||||
- @uppy/status-bar: fix aria-hidden warning (Merlijn Vos / #5663)
|
||||
|
||||
## 4.1.1
|
||||
|
||||
Released: 2025-01-09
|
||||
Included in: Uppy v4.12.2
|
||||
|
||||
- @uppy/status-bar: fix double upload progress (Mikael Finstad / #5587)
|
||||
|
||||
## 4.1.0
|
||||
|
||||
Released: 2025-01-06
|
||||
Included in: Uppy v4.11.0
|
||||
|
||||
- @uppy/angular,@uppy/audio,@uppy/aws-s3,@uppy/box,@uppy/companion-client,@uppy/compressor,@uppy/core,@uppy/dashboard,@uppy/drag-drop,@uppy/drop-target,@uppy/dropbox,@uppy/facebook,@uppy/file-input,@uppy/form,@uppy/golden-retriever,@uppy/google-drive-picker,@uppy/google-drive,@uppy/google-photos-picker,@uppy/google-photos,@uppy/image-editor,@uppy/informer,@uppy/instagram,@uppy/locales,@uppy/onedrive,@uppy/progress-bar,@uppy/provider-views,@uppy/react,@uppy/remote-sources,@uppy/screen-capture,@uppy/status-bar,@uppy/thumbnail-generator,@uppy/transloadit,@uppy/tus,@uppy/unsplash,@uppy/url,@uppy/vue,@uppy/webcam,@uppy/webdav,@uppy/xhr-upload,@uppy/zoom: Remove "paths" from all tsconfig's (Merlijn Vos / #5572)
|
||||
|
||||
## 4.0.6
|
||||
|
||||
Released: 2024-12-17
|
||||
Included in: Uppy v4.9.0
|
||||
|
||||
- e2e,@uppy/status-bar,@uppy/utils: Companion stream upload unknown size files (Mikael Finstad / #5489)
|
||||
|
||||
## 4.0.5
|
||||
|
||||
Released: 2024-12-05
|
||||
Included in: Uppy v4.8.0
|
||||
|
||||
- @uppy/audio,@uppy/aws-s3,@uppy/box,@uppy/companion-client,@uppy/compressor,@uppy/core,@uppy/dashboard,@uppy/drag-drop,@uppy/drop-target,@uppy/dropbox,@uppy/facebook,@uppy/file-input,@uppy/form,@uppy/golden-retriever,@uppy/google-drive,@uppy/google-photos,@uppy/image-editor,@uppy/informer,@uppy/instagram,@uppy/locales,@uppy/onedrive,@uppy/progress-bar,@uppy/provider-views,@uppy/react,@uppy/remote-sources,@uppy/screen-capture,@uppy/status-bar,@uppy/store-default,@uppy/thumbnail-generator,@uppy/transloadit,@uppy/tus,@uppy/unsplash,@uppy/url,@uppy/utils,@uppy/vue,@uppy/webcam,@uppy/xhr-upload,@uppy/zoom: cleanup tsconfig (Mikael Finstad / #5520)
|
||||
|
||||
## 4.0.4
|
||||
|
||||
Released: 2024-10-31
|
||||
Included in: Uppy v4.6.0
|
||||
|
||||
- @uppy/aws-s3,@uppy/box,@uppy/companion-client,@uppy/core,@uppy/dashboard,@uppy/drag-drop,@uppy/dropbox,@uppy/facebook,@uppy/file-input,@uppy/form,@uppy/golden-retriever,@uppy/google-drive,@uppy/google-photos,@uppy/image-editor,@uppy/informer,@uppy/instagram,@uppy/locales,@uppy/onedrive,@uppy/progress-bar,@uppy/provider-views,@uppy/react-native,@uppy/react,@uppy/redux-dev-tools,@uppy/screen-capture,@uppy/status-bar,@uppy/store-default,@uppy/store-redux,@uppy/svelte,@uppy/thumbnail-generator,@uppy/transloadit,@uppy/tus,@uppy/unsplash,@uppy/url,@uppy/utils,@uppy/vue,@uppy/webcam,@uppy/xhr-upload,@uppy/zoom: Fix links (Anthony Veaudry / #5492)
|
||||
|
||||
## 4.0.3
|
||||
|
||||
Released: 2024-08-20
|
||||
Included in: Uppy v4.2.0
|
||||
|
||||
- @uppy/status-bar: show upload button when files are recovered (Merlijn Vos / #5418)
|
||||
|
||||
## 4.0.1
|
||||
|
||||
Released: 2024-07-30
|
||||
Included in: Uppy v4.1.0
|
||||
|
||||
- @uppy/status-bar: GoldenRetriever + `hideUploadButton=true` (Evgenia Karunus / #5350)
|
||||
|
||||
## 4.0.0-beta.9
|
||||
|
||||
Released: 2024-06-04
|
||||
Included in: Uppy v4.0.0-beta.10
|
||||
|
||||
- @uppy/status-bar: remove unused component props (Antoine du Hamel / #5211)
|
||||
- @uppy/status-bar: rename `StatusBar` to `StatusBarUI` (Mikael Finstad / #5200)
|
||||
|
||||
## 4.0.0-beta.1
|
||||
|
||||
Released: 2024-03-28
|
||||
Included in: Uppy v4.0.0-beta.1
|
||||
|
||||
- @uppy/companion-client,@uppy/provider-views,@uppy/status-bar: fix type imports (Antoine du Hamel / #5038)
|
||||
- @uppy/status-bar: remove default target (Antoine du Hamel / #4970)
|
||||
- @uppy/status-bar: refine type of private variables (Antoine du Hamel / #5025)
|
||||
- @uppy/status-bar: fix `recoveredState` type (Antoine du Hamel / #4996)
|
||||
|
||||
## 3.3.3
|
||||
|
||||
Released: 2024-05-07
|
||||
Included in: Uppy v3.25.2
|
||||
|
||||
- @uppy/compressor,@uppy/core,@uppy/dashboard,@uppy/status-bar: Upgrade @transloadit/prettier-bytes (Merlijn Vos / #5150)
|
||||
|
||||
## 3.3.1
|
||||
|
||||
Released: 2024-03-27
|
||||
Included in: Uppy v3.24.0
|
||||
|
||||
- @uppy/box,@uppy/companion-client,@uppy/provider-views,@uppy/status-bar: fix type imports (Antoine du Hamel / #5038)
|
||||
- @uppy/status-bar: refine type of private variables (Antoine du Hamel / #5025)
|
||||
- @uppy/status-bar: fix `recoveredState` type (Antoine du Hamel / #4996)
|
||||
|
||||
## 3.2.7
|
||||
|
||||
Released: 2024-02-20
|
||||
Included in: Uppy v3.22.1
|
||||
|
||||
- @uppy/compressor,@uppy/core,@uppy/dashboard,@uppy/status-bar: bump `@transloadit/prettier-bytes` (Antoine du Hamel / #4933)
|
||||
|
||||
## 3.2.6
|
||||
|
||||
Released: 2024-02-19
|
||||
Included in: Uppy v3.22.0
|
||||
|
||||
- @uppy/status-bar: fix `statusbaroptions` type (antoine du hamel / #4883)
|
||||
- @uppy/status-bar: refactor to typescript (antoine du hamel / #4839)
|
||||
|
||||
## 3.2.4
|
||||
|
||||
Released: 2023-08-15
|
||||
Included in: Uppy v3.14.0
|
||||
|
||||
- @uppy/status-bar: e2e: add test for retrying and pausing uploads (Antoine du Hamel / #3599)
|
||||
|
||||
## 3.2.3
|
||||
|
||||
Released: 2023-07-20
|
||||
Included in: Uppy v3.13.0
|
||||
|
||||
- @uppy/status-bar: fix ETA when status bar is installed during upload (Antoine du Hamel / #4588)
|
||||
|
||||
## 3.2.2
|
||||
|
||||
Released: 2023-07-13
|
||||
Included in: Uppy v3.12.0
|
||||
|
||||
- @uppy/status-bar: listen to `upload` event instead of button click (Antoine du Hamel / #4563)
|
||||
|
||||
## 3.2.1
|
||||
|
||||
Released: 2023-07-06
|
||||
Included in: Uppy v3.11.0
|
||||
|
||||
- @uppy/status-bar: remove throttled component (Artur Paikin / #4396)
|
||||
- @uppy/status-bar: fix ETA when Uppy recovers its state (Antoine du Hamel / #4525)
|
||||
|
||||
## 3.2.0
|
||||
|
||||
Released: 2023-06-19
|
||||
Included in: Uppy v3.10.0
|
||||
|
||||
- @uppy/companion,@uppy/core,@uppy/dashboard,@uppy/golden-retriever,@uppy/status-bar,@uppy/utils: Migrate all lodash' per-method-packages usage to lodash. (LinusMain / #4274)
|
||||
- @uppy/status-bar: Filtered ETA (stduhpf / #4458)
|
||||
|
||||
## 3.0.1
|
||||
|
||||
Released: 2022-09-25
|
||||
Included in: Uppy v3.1.0
|
||||
|
||||
- @uppy/audio,@uppy/aws-s3-multipart,@uppy/aws-s3,@uppy/box,@uppy/companion-client,@uppy/companion,@uppy/compressor,@uppy/core,@uppy/dashboard,@uppy/drag-drop,@uppy/drop-target,@uppy/dropbox,@uppy/facebook,@uppy/file-input,@uppy/form,@uppy/golden-retriever,@uppy/google-drive,@uppy/image-editor,@uppy/informer,@uppy/instagram,@uppy/locales,@uppy/onedrive,@uppy/progress-bar,@uppy/provider-views,@uppy/react,@uppy/redux-dev-tools,@uppy/remote-sources,@uppy/screen-capture,@uppy/status-bar,@uppy/store-default,@uppy/store-redux,@uppy/svelte,@uppy/thumbnail-generator,@uppy/transloadit,@uppy/tus,@uppy/unsplash,@uppy/url,@uppy/utils,@uppy/vue,@uppy/webcam,@uppy/xhr-upload,@uppy/zoom: add missing entries to changelog for individual packages (Antoine du Hamel / #4092)
|
||||
|
||||
## 3.0.0
|
||||
|
||||
Released: 2022-08-22
|
||||
Included in: Uppy v3.0.0
|
||||
|
||||
- @uppy/core,@uppy/dashboard,@uppy/status-bar: Style tweaks: use all: initial + other resets (Artur Paikin / #3983)
|
||||
- Switch to ESM
|
||||
|
||||
## 3.0.0-beta.2
|
||||
|
||||
Released: 2022-08-03
|
||||
Included in: Uppy v3.0.0-beta.4
|
||||
|
||||
- @uppy/status-bar: rename internal modules (Antoine du Hamel / #3929)
|
||||
|
||||
## 2.2.1
|
||||
|
||||
Released: 2022-05-30
|
||||
Included in: Uppy v2.11.0
|
||||
|
||||
- @uppy/angular,@uppy/audio,@uppy/aws-s3-multipart,@uppy/aws-s3,@uppy/box,@uppy/core,@uppy/dashboard,@uppy/drag-drop,@uppy/dropbox,@uppy/facebook,@uppy/file-input,@uppy/form,@uppy/golden-retriever,@uppy/google-drive,@uppy/image-editor,@uppy/informer,@uppy/instagram,@uppy/onedrive,@uppy/progress-bar,@uppy/react,@uppy/redux-dev-tools,@uppy/robodog,@uppy/screen-capture,@uppy/status-bar,@uppy/store-default,@uppy/store-redux,@uppy/thumbnail-generator,@uppy/transloadit,@uppy/tus,@uppy/unsplash,@uppy/url,@uppy/vue,@uppy/webcam,@uppy/xhr-upload,@uppy/zoom: doc: update bundler recommendation (Antoine du Hamel / #3763)
|
||||
|
||||
## 2.2.0
|
||||
|
||||
Released: 2022-05-14
|
||||
Included in: Uppy v2.10.0
|
||||
|
||||
- @uppy/status-bar: refactor to ESM (Antoine du Hamel / #3697)
|
||||
|
||||
## 2.1.2
|
||||
|
||||
Released: 2021-12-07
|
||||
Included in: Uppy v2.3.0
|
||||
|
||||
- @uppy/status-bar: Status bar error state improvements (Merlijn Vos / #3299)
|
||||
- @uppy/aws-s3,@uppy/box,@uppy/core,@uppy/dashboard,@uppy/drag-drop,@uppy/dropbox,@uppy/facebook,@uppy/file-input,@uppy/google-drive,@uppy/image-editor,@uppy/instagram,@uppy/locales,@uppy/onedrive,@uppy/screen-capture,@uppy/status-bar,@uppy/thumbnail-generator,@uppy/transloadit,@uppy/url,@uppy/webcam,@uppy/xhr-upload,@uppy/zoom: Refactor locale scripts & generate types and docs (Merlijn Vos / #3276)
|
||||
21
packages/@uppy/status-bar/LICENSE
Normal file
21
packages/@uppy/status-bar/LICENSE
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2018 Transloadit
|
||||
|
||||
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.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
54
packages/@uppy/status-bar/README.md
Normal file
54
packages/@uppy/status-bar/README.md
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
# @uppy/status-bar
|
||||
|
||||
<img src="https://uppy.io/img/logo.svg" width="120" alt="Uppy logo: a smiling puppy above a pink upwards arrow" align="right">
|
||||
|
||||
[](https://www.npmjs.com/package/@uppy/status-bar)
|
||||

|
||||

|
||||

|
||||
|
||||
The status-bar shows upload progress and speed, ETAs, pre- and post-processing
|
||||
information, and allows users to control (pause/resume/cancel) the upload. Best
|
||||
used together with a basic file source plugin, such as
|
||||
[@uppy/file-input](https://uppy.io/docs/file-input) or
|
||||
[@uppy/drag-drop](https://uppy.io/docs/drag-drop), or a custom implementation.
|
||||
It’s also included in the [@uppy/dashboard](https://uppy.io/docs/dashboard)
|
||||
plugin.
|
||||
|
||||
Uppy is being developed by the folks at [Transloadit](https://transloadit.com),
|
||||
a versatile file encoding service.
|
||||
|
||||
## Example
|
||||
|
||||
```js
|
||||
import Uppy from '@uppy/core'
|
||||
import StatusBar from '@uppy/status-bar'
|
||||
|
||||
const uppy = new Uppy()
|
||||
uppy.use(StatusBar, {
|
||||
target: 'body',
|
||||
hideUploadButton: false,
|
||||
showProgressDetails: false,
|
||||
hideAfterFinish: true,
|
||||
})
|
||||
```
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
$ npm install @uppy/status-bar
|
||||
```
|
||||
|
||||
Alternatively, you can also use this plugin in a pre-built bundle from
|
||||
Transloadit’s CDN: Smart CDN. In that case `Uppy` will attach itself to the
|
||||
global `window.Uppy` object. See the
|
||||
[main Uppy documentation](https://uppy.io/docs/#Installation) for instructions.
|
||||
|
||||
## Documentation
|
||||
|
||||
Documentation for this plugin can be found on the
|
||||
[Uppy website](https://uppy.io/docs/status-bar).
|
||||
|
||||
## License
|
||||
|
||||
[The MIT License](./LICENSE).
|
||||
64
packages/@uppy/status-bar/package.json
Normal file
64
packages/@uppy/status-bar/package.json
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
{
|
||||
"name": "@uppy/status-bar",
|
||||
"description": "A progress bar for Uppy, with many bells and whistles.",
|
||||
"version": "4.2.3",
|
||||
"license": "MIT",
|
||||
"main": "lib/index.js",
|
||||
"style": "dist/style.min.css",
|
||||
"type": "module",
|
||||
"sideEffects": [
|
||||
"*.css"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "tsc --build tsconfig.build.json",
|
||||
"build:css": "sass --load-path=../../ src/style.scss dist/style.css && postcss dist/style.css -u cssnano -o dist/style.min.css",
|
||||
"typecheck": "tsc --build"
|
||||
},
|
||||
"keywords": [
|
||||
"file uploader",
|
||||
"uppy",
|
||||
"uppy-plugin",
|
||||
"progress bar",
|
||||
"status bar",
|
||||
"progress",
|
||||
"upload",
|
||||
"eta",
|
||||
"speed"
|
||||
],
|
||||
"homepage": "https://uppy.io",
|
||||
"bugs": {
|
||||
"url": "https://github.com/transloadit/uppy/issues"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/transloadit/uppy.git"
|
||||
},
|
||||
"files": [
|
||||
"src",
|
||||
"lib",
|
||||
"dist",
|
||||
"CHANGELOG.md"
|
||||
],
|
||||
"exports": {
|
||||
".": "./lib/index.js",
|
||||
"./css/style.css": "./dist/style.css",
|
||||
"./css/style.min.css": "./dist/style.min.css",
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
"dependencies": {
|
||||
"@transloadit/prettier-bytes": "^0.3.4",
|
||||
"@uppy/utils": "workspace:^",
|
||||
"classnames": "^2.2.6",
|
||||
"preact": "^10.5.13"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@uppy/core": "workspace:^"
|
||||
},
|
||||
"devDependencies": {
|
||||
"cssnano": "^7.0.7",
|
||||
"postcss": "^8.5.6",
|
||||
"postcss-cli": "^11.0.1",
|
||||
"sass": "^1.89.2",
|
||||
"typescript": "^5.8.3"
|
||||
}
|
||||
}
|
||||
546
packages/@uppy/status-bar/src/Components.tsx
Normal file
546
packages/@uppy/status-bar/src/Components.tsx
Normal file
|
|
@ -0,0 +1,546 @@
|
|||
import prettierBytes from '@transloadit/prettier-bytes'
|
||||
import type { Body, Meta, State, Uppy } from '@uppy/core'
|
||||
import type { FileProcessingInfo, I18n } from '@uppy/utils'
|
||||
import { prettyETA } from '@uppy/utils'
|
||||
import classNames from 'classnames'
|
||||
|
||||
import statusBarStates from './StatusBarStates.js'
|
||||
|
||||
const DOT = `\u00B7`
|
||||
const renderDot = (): string => ` ${DOT} `
|
||||
|
||||
interface UploadBtnProps<M extends Meta, B extends Body> {
|
||||
newFiles: number
|
||||
isUploadStarted: boolean
|
||||
recoveredState: State<M, B>['recoveredState']
|
||||
i18n: I18n
|
||||
uploadState: string
|
||||
isSomeGhost: boolean
|
||||
startUpload: () => void
|
||||
}
|
||||
|
||||
function UploadBtn<M extends Meta, B extends Body>(
|
||||
props: UploadBtnProps<M, B>,
|
||||
) {
|
||||
const {
|
||||
newFiles,
|
||||
isUploadStarted,
|
||||
recoveredState,
|
||||
i18n,
|
||||
uploadState,
|
||||
isSomeGhost,
|
||||
startUpload,
|
||||
} = props
|
||||
|
||||
const uploadBtnClassNames = classNames(
|
||||
'uppy-u-reset',
|
||||
'uppy-c-btn',
|
||||
'uppy-StatusBar-actionBtn',
|
||||
'uppy-StatusBar-actionBtn--upload',
|
||||
{
|
||||
'uppy-c-btn-primary': uploadState === statusBarStates.STATE_WAITING,
|
||||
},
|
||||
{ 'uppy-StatusBar-actionBtn--disabled': isSomeGhost },
|
||||
)
|
||||
|
||||
const uploadBtnText =
|
||||
newFiles && isUploadStarted && !recoveredState
|
||||
? i18n('uploadXNewFiles', { smart_count: newFiles })
|
||||
: i18n('uploadXFiles', { smart_count: newFiles })
|
||||
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
className={uploadBtnClassNames}
|
||||
aria-label={i18n('uploadXFiles', { smart_count: newFiles })}
|
||||
onClick={startUpload}
|
||||
disabled={isSomeGhost}
|
||||
data-uppy-super-focusable
|
||||
>
|
||||
{uploadBtnText}
|
||||
</button>
|
||||
)
|
||||
}
|
||||
|
||||
interface RetryBtnProps<M extends Meta, B extends Body> {
|
||||
i18n: I18n
|
||||
uppy: Uppy<M, B>
|
||||
}
|
||||
|
||||
function RetryBtn<M extends Meta, B extends Body>(props: RetryBtnProps<M, B>) {
|
||||
const { i18n, uppy } = props
|
||||
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
className="uppy-u-reset uppy-c-btn uppy-StatusBar-actionBtn uppy-StatusBar-actionBtn--retry"
|
||||
aria-label={i18n('retryUpload')}
|
||||
onClick={() =>
|
||||
uppy.retryAll().catch(() => {
|
||||
/* Error reported and handled via an event */
|
||||
})
|
||||
}
|
||||
data-uppy-super-focusable
|
||||
data-cy="retry"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
focusable="false"
|
||||
className="uppy-c-icon"
|
||||
width="8"
|
||||
height="10"
|
||||
viewBox="0 0 8 10"
|
||||
>
|
||||
<path d="M4 2.408a2.75 2.75 0 1 0 2.75 2.75.626.626 0 0 1 1.25.018v.023a4 4 0 1 1-4-4.041V.25a.25.25 0 0 1 .389-.208l2.299 1.533a.25.25 0 0 1 0 .416l-2.3 1.533A.25.25 0 0 1 4 3.316v-.908z" />
|
||||
</svg>
|
||||
{i18n('retry')}
|
||||
</button>
|
||||
)
|
||||
}
|
||||
|
||||
interface CancelBtnProps<M extends Meta, B extends Body> {
|
||||
i18n: I18n
|
||||
uppy: Uppy<M, B>
|
||||
}
|
||||
|
||||
function CancelBtn<M extends Meta, B extends Body>(
|
||||
props: CancelBtnProps<M, B>,
|
||||
) {
|
||||
const { i18n, uppy } = props
|
||||
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
className="uppy-u-reset uppy-StatusBar-actionCircleBtn"
|
||||
title={i18n('cancel')}
|
||||
aria-label={i18n('cancel')}
|
||||
onClick={(): void => uppy.cancelAll()}
|
||||
data-cy="cancel"
|
||||
data-uppy-super-focusable
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
focusable="false"
|
||||
className="uppy-c-icon"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 16 16"
|
||||
>
|
||||
<g fill="none" fillRule="evenodd">
|
||||
<circle fill="#888" cx="8" cy="8" r="8" />
|
||||
<path
|
||||
fill="#FFF"
|
||||
d="M9.283 8l2.567 2.567-1.283 1.283L8 9.283 5.433 11.85 4.15 10.567 6.717 8 4.15 5.433 5.433 4.15 8 6.717l2.567-2.567 1.283 1.283z"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
</button>
|
||||
)
|
||||
}
|
||||
|
||||
interface PauseResumeButtonProps<M extends Meta, B extends Body> {
|
||||
i18n: I18n
|
||||
uppy: Uppy<M, B>
|
||||
isAllPaused: boolean
|
||||
isAllComplete: boolean
|
||||
resumableUploads: boolean
|
||||
}
|
||||
|
||||
function PauseResumeButton<M extends Meta, B extends Body>(
|
||||
props: PauseResumeButtonProps<M, B>,
|
||||
) {
|
||||
const { isAllPaused, i18n, isAllComplete, resumableUploads, uppy } = props
|
||||
const title = isAllPaused ? i18n('resume') : i18n('pause')
|
||||
|
||||
function togglePauseResume(): void {
|
||||
if (isAllComplete) return
|
||||
|
||||
if (!resumableUploads) {
|
||||
uppy.cancelAll()
|
||||
return
|
||||
}
|
||||
|
||||
if (isAllPaused) {
|
||||
uppy.resumeAll()
|
||||
return
|
||||
}
|
||||
|
||||
uppy.pauseAll()
|
||||
}
|
||||
|
||||
return (
|
||||
<button
|
||||
title={title}
|
||||
aria-label={title}
|
||||
className="uppy-u-reset uppy-StatusBar-actionCircleBtn"
|
||||
type="button"
|
||||
onClick={togglePauseResume}
|
||||
data-cy="togglePauseResume"
|
||||
data-uppy-super-focusable
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
focusable="false"
|
||||
className="uppy-c-icon"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 16 16"
|
||||
>
|
||||
<g fill="none" fillRule="evenodd">
|
||||
<circle fill="#888" cx="8" cy="8" r="8" />
|
||||
<path
|
||||
fill="#FFF"
|
||||
d={
|
||||
isAllPaused
|
||||
? 'M6 4.25L11.5 8 6 11.75z'
|
||||
: 'M5 4.5h2v7H5v-7zm4 0h2v7H9v-7z'
|
||||
}
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
</button>
|
||||
)
|
||||
}
|
||||
|
||||
interface DoneBtnProps {
|
||||
i18n: I18n
|
||||
doneButtonHandler: (() => void) | undefined
|
||||
}
|
||||
|
||||
function DoneBtn(props: DoneBtnProps) {
|
||||
const { i18n, doneButtonHandler } = props
|
||||
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
className="uppy-u-reset uppy-c-btn uppy-StatusBar-actionBtn uppy-StatusBar-actionBtn--done"
|
||||
onClick={doneButtonHandler}
|
||||
data-uppy-super-focusable
|
||||
>
|
||||
{i18n('done')}
|
||||
</button>
|
||||
)
|
||||
}
|
||||
|
||||
function LoadingSpinner() {
|
||||
return (
|
||||
<svg
|
||||
className="uppy-StatusBar-spinner"
|
||||
aria-hidden="true"
|
||||
focusable="false"
|
||||
width="14"
|
||||
height="14"
|
||||
>
|
||||
<path
|
||||
d="M13.983 6.547c-.12-2.509-1.64-4.893-3.939-5.936-2.48-1.127-5.488-.656-7.556 1.094C.524 3.367-.398 6.048.162 8.562c.556 2.495 2.46 4.52 4.94 5.183 2.932.784 5.61-.602 7.256-3.015-1.493 1.993-3.745 3.309-6.298 2.868-2.514-.434-4.578-2.349-5.153-4.84a6.226 6.226 0 0 1 2.98-6.778C6.34.586 9.74 1.1 11.373 3.493c.407.596.693 1.282.842 1.988.127.598.073 1.197.161 1.794.078.525.543 1.257 1.15.864.525-.341.49-1.05.456-1.592-.007-.15.02.3 0 0"
|
||||
fillRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
interface ProgressBarProcessingProps {
|
||||
progress: FileProcessingInfo
|
||||
}
|
||||
|
||||
function ProgressBarProcessing(props: ProgressBarProcessingProps) {
|
||||
const { progress } = props
|
||||
const { value, mode, message } = progress
|
||||
const dot = `\u00B7`
|
||||
|
||||
return (
|
||||
<div className="uppy-StatusBar-content">
|
||||
<LoadingSpinner />
|
||||
{mode === 'determinate' ? `${Math.round(value * 100)}% ${dot} ` : ''}
|
||||
{message}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
interface ProgressDetailsProps {
|
||||
i18n: I18n
|
||||
numUploads: number
|
||||
complete: number
|
||||
totalUploadedSize: number
|
||||
totalSize: number | null
|
||||
totalETA: number | null
|
||||
}
|
||||
|
||||
function ProgressDetails(props: ProgressDetailsProps) {
|
||||
const { numUploads, complete, totalUploadedSize, totalSize, totalETA, i18n } =
|
||||
props
|
||||
|
||||
const ifShowFilesUploadedOfTotal = numUploads > 1
|
||||
|
||||
const totalUploadedSizeStr = prettierBytes(totalUploadedSize)
|
||||
|
||||
return (
|
||||
<div className="uppy-StatusBar-statusSecondary">
|
||||
{ifShowFilesUploadedOfTotal &&
|
||||
i18n('filesUploadedOfTotal', {
|
||||
complete,
|
||||
smart_count: numUploads,
|
||||
})}
|
||||
<span className="uppy-StatusBar-additionalInfo">
|
||||
{/* When should we render this dot?
|
||||
1. .-additionalInfo is shown (happens only on desktops)
|
||||
2. AND 'filesUploadedOfTotal' was shown
|
||||
*/}
|
||||
{ifShowFilesUploadedOfTotal && renderDot()}
|
||||
|
||||
{totalSize != null
|
||||
? i18n('dataUploadedOfTotal', {
|
||||
complete: totalUploadedSizeStr,
|
||||
total: prettierBytes(totalSize),
|
||||
})
|
||||
: i18n('dataUploadedOfUnknown', { complete: totalUploadedSizeStr })}
|
||||
|
||||
{renderDot()}
|
||||
|
||||
{totalETA != null &&
|
||||
i18n('xTimeLeft', {
|
||||
time: prettyETA(totalETA),
|
||||
})}
|
||||
</span>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
interface FileUploadCountProps {
|
||||
i18n: I18n
|
||||
complete: number
|
||||
numUploads: number
|
||||
}
|
||||
|
||||
function FileUploadCount(props: FileUploadCountProps) {
|
||||
const { i18n, complete, numUploads } = props
|
||||
|
||||
return (
|
||||
<div className="uppy-StatusBar-statusSecondary">
|
||||
{i18n('filesUploadedOfTotal', { complete, smart_count: numUploads })}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
interface UploadNewlyAddedFilesProps {
|
||||
i18n: I18n
|
||||
newFiles: number
|
||||
startUpload: () => void
|
||||
}
|
||||
|
||||
function UploadNewlyAddedFiles(props: UploadNewlyAddedFilesProps) {
|
||||
const { i18n, newFiles, startUpload } = props
|
||||
const uploadBtnClassNames = classNames(
|
||||
'uppy-u-reset',
|
||||
'uppy-c-btn',
|
||||
'uppy-StatusBar-actionBtn',
|
||||
'uppy-StatusBar-actionBtn--uploadNewlyAdded',
|
||||
)
|
||||
|
||||
return (
|
||||
<div className="uppy-StatusBar-statusSecondary">
|
||||
<div className="uppy-StatusBar-statusSecondaryHint">
|
||||
{i18n('xMoreFilesAdded', { smart_count: newFiles })}
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
className={uploadBtnClassNames}
|
||||
aria-label={i18n('uploadXFiles', { smart_count: newFiles })}
|
||||
onClick={startUpload}
|
||||
>
|
||||
{i18n('upload')}
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
interface ProgressBarUploadingProps {
|
||||
i18n: I18n
|
||||
supportsUploadProgress: boolean
|
||||
totalProgress: number
|
||||
showProgressDetails: boolean | undefined
|
||||
isUploadStarted: boolean
|
||||
isAllComplete: boolean
|
||||
isAllPaused: boolean
|
||||
newFiles: number
|
||||
numUploads: number
|
||||
complete: number
|
||||
totalUploadedSize: number
|
||||
totalSize: number | null
|
||||
totalETA: number | null
|
||||
startUpload: () => void
|
||||
}
|
||||
|
||||
function ProgressBarUploading(props: ProgressBarUploadingProps) {
|
||||
const {
|
||||
i18n,
|
||||
supportsUploadProgress,
|
||||
totalProgress,
|
||||
showProgressDetails,
|
||||
isUploadStarted,
|
||||
isAllComplete,
|
||||
isAllPaused,
|
||||
newFiles,
|
||||
numUploads,
|
||||
complete,
|
||||
totalUploadedSize,
|
||||
totalSize,
|
||||
totalETA,
|
||||
startUpload,
|
||||
} = props
|
||||
|
||||
const showUploadNewlyAddedFiles = newFiles && isUploadStarted
|
||||
|
||||
if (!isUploadStarted || isAllComplete) {
|
||||
return null
|
||||
}
|
||||
|
||||
const title = isAllPaused ? i18n('paused') : i18n('uploading')
|
||||
|
||||
function renderProgressDetails() {
|
||||
if (!isAllPaused && !showUploadNewlyAddedFiles && showProgressDetails) {
|
||||
if (supportsUploadProgress) {
|
||||
return (
|
||||
<ProgressDetails
|
||||
numUploads={numUploads}
|
||||
complete={complete}
|
||||
totalUploadedSize={totalUploadedSize}
|
||||
totalSize={totalSize}
|
||||
totalETA={totalETA}
|
||||
i18n={i18n}
|
||||
/>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<FileUploadCount
|
||||
i18n={i18n}
|
||||
complete={complete}
|
||||
numUploads={numUploads}
|
||||
/>
|
||||
)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="uppy-StatusBar-content" title={title}>
|
||||
{!isAllPaused ? <LoadingSpinner /> : null}
|
||||
<div className="uppy-StatusBar-status">
|
||||
<div className="uppy-StatusBar-statusPrimary">
|
||||
{supportsUploadProgress && totalProgress !== 0
|
||||
? `${title}: ${totalProgress}%`
|
||||
: title}
|
||||
</div>
|
||||
|
||||
{renderProgressDetails()}
|
||||
|
||||
{showUploadNewlyAddedFiles ? (
|
||||
<UploadNewlyAddedFiles
|
||||
i18n={i18n}
|
||||
newFiles={newFiles}
|
||||
startUpload={startUpload}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
interface ProgressBarCompleteProps {
|
||||
i18n: I18n
|
||||
}
|
||||
|
||||
function ProgressBarComplete(props: ProgressBarCompleteProps) {
|
||||
const { i18n } = props
|
||||
|
||||
return (
|
||||
<div
|
||||
className="uppy-StatusBar-content"
|
||||
// biome-ignore lint/a11y/useSemanticElements: ...
|
||||
role="status"
|
||||
title={i18n('complete')}
|
||||
>
|
||||
<div className="uppy-StatusBar-status">
|
||||
<div className="uppy-StatusBar-statusPrimary">
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
focusable="false"
|
||||
className="uppy-StatusBar-statusIndicator uppy-c-icon"
|
||||
width="15"
|
||||
height="11"
|
||||
viewBox="0 0 15 11"
|
||||
>
|
||||
<path d="M.414 5.843L1.627 4.63l3.472 3.472L13.202 0l1.212 1.213L5.1 10.528z" />
|
||||
</svg>
|
||||
{i18n('complete')}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
interface ProgressBarErrorProps {
|
||||
i18n: I18n
|
||||
error: any
|
||||
complete: number
|
||||
numUploads: number
|
||||
}
|
||||
|
||||
function ProgressBarError(props: ProgressBarErrorProps) {
|
||||
const { error, i18n, complete, numUploads } = props
|
||||
|
||||
function displayErrorAlert(): void {
|
||||
const errorMessage = `${i18n('uploadFailed')} \n\n ${error}`
|
||||
alert(errorMessage) // TODO: move to custom alert implementation
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="uppy-StatusBar-content" title={i18n('uploadFailed')}>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
focusable="false"
|
||||
className="uppy-StatusBar-statusIndicator uppy-c-icon"
|
||||
width="11"
|
||||
height="11"
|
||||
viewBox="0 0 11 11"
|
||||
>
|
||||
<path d="M4.278 5.5L0 1.222 1.222 0 5.5 4.278 9.778 0 11 1.222 6.722 5.5 11 9.778 9.778 11 5.5 6.722 1.222 11 0 9.778z" />
|
||||
</svg>
|
||||
<div className="uppy-StatusBar-status">
|
||||
<div className="uppy-StatusBar-statusPrimary">
|
||||
{i18n('uploadFailed')}
|
||||
|
||||
<button
|
||||
className="uppy-u-reset uppy-StatusBar-details"
|
||||
aria-label={i18n('showErrorDetails')}
|
||||
data-microtip-position="top-right"
|
||||
data-microtip-size="medium"
|
||||
onClick={displayErrorAlert}
|
||||
type="button"
|
||||
>
|
||||
?
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<FileUploadCount
|
||||
i18n={i18n}
|
||||
complete={complete}
|
||||
numUploads={numUploads}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export {
|
||||
UploadBtn,
|
||||
RetryBtn,
|
||||
CancelBtn,
|
||||
PauseResumeButton,
|
||||
DoneBtn,
|
||||
LoadingSpinner,
|
||||
ProgressDetails,
|
||||
ProgressBarProcessing,
|
||||
ProgressBarError,
|
||||
ProgressBarUploading,
|
||||
ProgressBarComplete,
|
||||
}
|
||||
301
packages/@uppy/status-bar/src/StatusBar.tsx
Normal file
301
packages/@uppy/status-bar/src/StatusBar.tsx
Normal file
|
|
@ -0,0 +1,301 @@
|
|||
import type {
|
||||
Body,
|
||||
DefinePluginOpts,
|
||||
Meta,
|
||||
State,
|
||||
Uppy,
|
||||
UppyFile,
|
||||
} from '@uppy/core'
|
||||
import { UIPlugin } from '@uppy/core'
|
||||
import { emaFilter, getTextDirection } from '@uppy/utils'
|
||||
import type { ComponentChild } from 'preact'
|
||||
import packageJson from '../package.json' with { type: 'json' }
|
||||
import locale from './locale.js'
|
||||
import type { StatusBarOptions } from './StatusBarOptions.js'
|
||||
import statusBarStates from './StatusBarStates.js'
|
||||
import StatusBarUI, { type StatusBarUIProps } from './StatusBarUI.js'
|
||||
|
||||
const speedFilterHalfLife = 2000
|
||||
const ETAFilterHalfLife = 2000
|
||||
|
||||
function getUploadingState(
|
||||
error: unknown,
|
||||
isAllComplete: boolean,
|
||||
recoveredState: any,
|
||||
files: Record<string, UppyFile<any, any>>,
|
||||
): StatusBarUIProps<any, any>['uploadState'] {
|
||||
if (error) {
|
||||
return statusBarStates.STATE_ERROR
|
||||
}
|
||||
|
||||
if (isAllComplete) {
|
||||
return statusBarStates.STATE_COMPLETE
|
||||
}
|
||||
|
||||
if (recoveredState) {
|
||||
return statusBarStates.STATE_WAITING
|
||||
}
|
||||
|
||||
let state: StatusBarUIProps<any, any>['uploadState'] =
|
||||
statusBarStates.STATE_WAITING
|
||||
const fileIDs = Object.keys(files)
|
||||
for (let i = 0; i < fileIDs.length; i++) {
|
||||
const { progress } = files[fileIDs[i]]
|
||||
// If ANY files are being uploaded right now, show the uploading state.
|
||||
if (progress.uploadStarted && !progress.uploadComplete) {
|
||||
return statusBarStates.STATE_UPLOADING
|
||||
}
|
||||
// If files are being preprocessed AND postprocessed at this time, we show the
|
||||
// preprocess state. If any files are being uploaded we show uploading.
|
||||
if (progress.preprocess) {
|
||||
state = statusBarStates.STATE_PREPROCESSING
|
||||
}
|
||||
// If NO files are being preprocessed or uploaded right now, but some files are
|
||||
// being postprocessed, show the postprocess state.
|
||||
if (progress.postprocess && state !== statusBarStates.STATE_PREPROCESSING) {
|
||||
state = statusBarStates.STATE_POSTPROCESSING
|
||||
}
|
||||
}
|
||||
return state
|
||||
}
|
||||
|
||||
const defaultOptions = {
|
||||
hideUploadButton: false,
|
||||
hideRetryButton: false,
|
||||
hidePauseResumeButton: false,
|
||||
hideCancelButton: false,
|
||||
showProgressDetails: false,
|
||||
hideAfterFinish: true,
|
||||
doneButtonHandler: null,
|
||||
} satisfies StatusBarOptions
|
||||
|
||||
/**
|
||||
* StatusBar: renders a status bar with upload/pause/resume/cancel/retry buttons,
|
||||
* progress percentage and time remaining.
|
||||
*/
|
||||
export default class StatusBar<M extends Meta, B extends Body> extends UIPlugin<
|
||||
DefinePluginOpts<StatusBarOptions, keyof typeof defaultOptions>,
|
||||
M,
|
||||
B
|
||||
> {
|
||||
static VERSION = packageJson.version
|
||||
|
||||
#lastUpdateTime!: ReturnType<typeof performance.now>
|
||||
|
||||
#previousUploadedBytes!: number | null
|
||||
|
||||
#previousSpeed!: number | null
|
||||
|
||||
#previousETA!: number | null
|
||||
|
||||
constructor(uppy: Uppy<M, B>, opts?: StatusBarOptions) {
|
||||
super(uppy, { ...defaultOptions, ...opts })
|
||||
this.id = this.opts.id || 'StatusBar'
|
||||
this.title = 'StatusBar'
|
||||
this.type = 'progressindicator'
|
||||
|
||||
this.defaultLocale = locale
|
||||
|
||||
this.i18nInit()
|
||||
|
||||
this.render = this.render.bind(this)
|
||||
this.install = this.install.bind(this)
|
||||
}
|
||||
|
||||
#computeSmoothETA(totalBytes: {
|
||||
uploaded: number
|
||||
total: number | null // null means indeterminate
|
||||
}) {
|
||||
if (totalBytes.total == null || totalBytes.total === 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
const remaining = totalBytes.total - totalBytes.uploaded
|
||||
if (remaining <= 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
// When state is restored, lastUpdateTime is still nullish at this point.
|
||||
this.#lastUpdateTime ??= performance.now()
|
||||
const dt = performance.now() - this.#lastUpdateTime
|
||||
if (dt === 0) {
|
||||
return Math.round((this.#previousETA ?? 0) / 100) / 10
|
||||
}
|
||||
|
||||
const uploadedBytesSinceLastTick =
|
||||
totalBytes.uploaded - this.#previousUploadedBytes!
|
||||
this.#previousUploadedBytes = totalBytes.uploaded
|
||||
|
||||
// uploadedBytesSinceLastTick can be negative in some cases (packet loss?)
|
||||
// in which case, we wait for next tick to update ETA.
|
||||
if (uploadedBytesSinceLastTick <= 0) {
|
||||
return Math.round((this.#previousETA ?? 0) / 100) / 10
|
||||
}
|
||||
const currentSpeed = uploadedBytesSinceLastTick / dt
|
||||
const filteredSpeed =
|
||||
this.#previousSpeed == null
|
||||
? currentSpeed
|
||||
: emaFilter(currentSpeed, this.#previousSpeed, speedFilterHalfLife, dt)
|
||||
this.#previousSpeed = filteredSpeed
|
||||
const instantETA = remaining / filteredSpeed
|
||||
|
||||
const updatedPreviousETA = Math.max(this.#previousETA! - dt, 0)
|
||||
const filteredETA =
|
||||
this.#previousETA == null
|
||||
? instantETA
|
||||
: emaFilter(instantETA, updatedPreviousETA, ETAFilterHalfLife, dt)
|
||||
this.#previousETA = filteredETA
|
||||
this.#lastUpdateTime = performance.now()
|
||||
|
||||
return Math.round(filteredETA / 100) / 10
|
||||
}
|
||||
|
||||
startUpload = (): ReturnType<Uppy<M, B>['upload']> => {
|
||||
return this.uppy.upload().catch((() => {
|
||||
// Error logged in Core
|
||||
}) as () => undefined)
|
||||
}
|
||||
|
||||
render(state: State<M, B>): ComponentChild {
|
||||
const {
|
||||
capabilities,
|
||||
files,
|
||||
allowNewUpload,
|
||||
totalProgress,
|
||||
error,
|
||||
recoveredState,
|
||||
} = state
|
||||
|
||||
const {
|
||||
newFiles,
|
||||
startedFiles,
|
||||
completeFiles,
|
||||
|
||||
isUploadStarted,
|
||||
isAllComplete,
|
||||
isAllPaused,
|
||||
isUploadInProgress,
|
||||
isSomeGhost,
|
||||
} = this.uppy.getObjectOfFilesPerState()
|
||||
|
||||
// If some state was recovered, we want to show Upload button/counter
|
||||
// for all the files, because in this case it’s not an Upload button,
|
||||
// but “Confirm Restore Button”
|
||||
const newFilesOrRecovered = recoveredState ? Object.values(files) : newFiles
|
||||
const resumableUploads = !!capabilities.resumableUploads
|
||||
const supportsUploadProgress = capabilities.uploadProgress !== false
|
||||
|
||||
let totalSize: number | null = null
|
||||
let totalUploadedSize = 0
|
||||
|
||||
// Only if all files have a known size, does it make sense to display a total size
|
||||
if (
|
||||
startedFiles.every(
|
||||
(f) => f.progress.bytesTotal != null && f.progress.bytesTotal !== 0,
|
||||
)
|
||||
) {
|
||||
totalSize = 0
|
||||
startedFiles.forEach((file) => {
|
||||
totalSize! += file.progress.bytesTotal || 0
|
||||
totalUploadedSize += file.progress.bytesUploaded || 0
|
||||
})
|
||||
} else {
|
||||
// however uploaded size we will always have
|
||||
startedFiles.forEach((file) => {
|
||||
totalUploadedSize += file.progress.bytesUploaded || 0
|
||||
})
|
||||
}
|
||||
|
||||
const totalETA = this.#computeSmoothETA({
|
||||
uploaded: totalUploadedSize,
|
||||
total: totalSize,
|
||||
})
|
||||
|
||||
return StatusBarUI({
|
||||
error,
|
||||
uploadState: getUploadingState(
|
||||
error,
|
||||
isAllComplete,
|
||||
recoveredState,
|
||||
state.files || {},
|
||||
),
|
||||
allowNewUpload,
|
||||
totalProgress,
|
||||
totalSize,
|
||||
totalUploadedSize,
|
||||
isAllComplete: false,
|
||||
isAllPaused,
|
||||
isUploadStarted,
|
||||
isUploadInProgress,
|
||||
isSomeGhost,
|
||||
recoveredState,
|
||||
complete: completeFiles.length,
|
||||
newFiles: newFilesOrRecovered.length,
|
||||
numUploads: startedFiles.length,
|
||||
totalETA,
|
||||
files,
|
||||
i18n: this.i18n,
|
||||
uppy: this.uppy,
|
||||
startUpload: this.startUpload,
|
||||
doneButtonHandler: this.opts.doneButtonHandler,
|
||||
resumableUploads,
|
||||
supportsUploadProgress,
|
||||
showProgressDetails: this.opts.showProgressDetails,
|
||||
hideUploadButton: this.opts.hideUploadButton,
|
||||
hideRetryButton: this.opts.hideRetryButton,
|
||||
hidePauseResumeButton: this.opts.hidePauseResumeButton,
|
||||
hideCancelButton: this.opts.hideCancelButton,
|
||||
hideAfterFinish: this.opts.hideAfterFinish,
|
||||
})
|
||||
}
|
||||
|
||||
onMount(): void {
|
||||
// Set the text direction if the page has not defined one.
|
||||
const element = this.el!
|
||||
const direction = getTextDirection(element)
|
||||
if (!direction) {
|
||||
element.dir = 'ltr'
|
||||
}
|
||||
}
|
||||
|
||||
#onUploadStart = (): void => {
|
||||
const { recoveredState } = this.uppy.getState()
|
||||
|
||||
this.#previousSpeed = null
|
||||
this.#previousETA = null
|
||||
if (recoveredState) {
|
||||
this.#previousUploadedBytes = Object.values(recoveredState.files).reduce(
|
||||
(pv, { progress }) => pv + (progress.bytesUploaded as number),
|
||||
0,
|
||||
)
|
||||
|
||||
// We don't set `#lastUpdateTime` at this point because the upload won't
|
||||
// actually resume until the user asks for it.
|
||||
|
||||
this.uppy.emit('restore-confirmed')
|
||||
return
|
||||
}
|
||||
this.#lastUpdateTime = performance.now()
|
||||
this.#previousUploadedBytes = 0
|
||||
}
|
||||
|
||||
install(): void {
|
||||
const { target } = this.opts
|
||||
if (target) {
|
||||
this.mount(target, this)
|
||||
}
|
||||
this.uppy.on('upload', this.#onUploadStart)
|
||||
|
||||
// To cover the use case where the status bar is installed while the upload
|
||||
// has started, we set `lastUpdateTime` right away.
|
||||
this.#lastUpdateTime = performance.now()
|
||||
this.#previousUploadedBytes = this.uppy
|
||||
.getFiles()
|
||||
.reduce((pv, file) => pv + (file.progress.bytesUploaded as number), 0)
|
||||
}
|
||||
|
||||
uninstall(): void {
|
||||
this.unmount()
|
||||
this.uppy.off('upload', this.#onUploadStart)
|
||||
}
|
||||
}
|
||||
14
packages/@uppy/status-bar/src/StatusBarOptions.ts
Normal file
14
packages/@uppy/status-bar/src/StatusBarOptions.ts
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
import type { UIPluginOptions } from '@uppy/core'
|
||||
import type { LocaleStrings } from '@uppy/utils'
|
||||
import type StatusBarLocale from './locale.js'
|
||||
|
||||
export interface StatusBarOptions extends UIPluginOptions {
|
||||
showProgressDetails?: boolean
|
||||
hideUploadButton?: boolean
|
||||
hideAfterFinish?: boolean
|
||||
hideRetryButton?: boolean
|
||||
hidePauseResumeButton?: boolean
|
||||
hideCancelButton?: boolean
|
||||
doneButtonHandler?: (() => void) | null
|
||||
locale?: LocaleStrings<typeof StatusBarLocale>
|
||||
}
|
||||
8
packages/@uppy/status-bar/src/StatusBarStates.ts
Normal file
8
packages/@uppy/status-bar/src/StatusBarStates.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
export default {
|
||||
STATE_ERROR: 'error' as const,
|
||||
STATE_WAITING: 'waiting' as const,
|
||||
STATE_PREPROCESSING: 'preprocessing' as const,
|
||||
STATE_UPLOADING: 'uploading' as const,
|
||||
STATE_POSTPROCESSING: 'postprocessing' as const,
|
||||
STATE_COMPLETE: 'complete' as const,
|
||||
}
|
||||
275
packages/@uppy/status-bar/src/StatusBarUI.tsx
Normal file
275
packages/@uppy/status-bar/src/StatusBarUI.tsx
Normal file
|
|
@ -0,0 +1,275 @@
|
|||
import type { Body, Meta, State, Uppy, UppyFile } from '@uppy/core'
|
||||
import type { I18n } from '@uppy/utils'
|
||||
import classNames from 'classnames'
|
||||
import {
|
||||
CancelBtn,
|
||||
DoneBtn,
|
||||
PauseResumeButton,
|
||||
ProgressBarComplete,
|
||||
ProgressBarError,
|
||||
ProgressBarProcessing,
|
||||
ProgressBarUploading,
|
||||
RetryBtn,
|
||||
UploadBtn,
|
||||
} from './Components.js'
|
||||
import calculateProcessingProgress from './calculateProcessingProgress.js'
|
||||
import statusBarStates from './StatusBarStates.js'
|
||||
|
||||
const {
|
||||
STATE_ERROR,
|
||||
STATE_WAITING,
|
||||
STATE_PREPROCESSING,
|
||||
STATE_UPLOADING,
|
||||
STATE_POSTPROCESSING,
|
||||
STATE_COMPLETE,
|
||||
} = statusBarStates
|
||||
|
||||
export interface StatusBarUIProps<M extends Meta, B extends Body> {
|
||||
newFiles: number
|
||||
allowNewUpload: boolean
|
||||
isUploadInProgress: boolean
|
||||
isAllPaused: boolean
|
||||
resumableUploads: boolean
|
||||
error: any
|
||||
hideUploadButton?: boolean
|
||||
hidePauseResumeButton?: boolean
|
||||
hideCancelButton?: boolean
|
||||
hideRetryButton?: boolean
|
||||
recoveredState: State<M, B>['recoveredState']
|
||||
uploadState: (typeof statusBarStates)[keyof typeof statusBarStates]
|
||||
totalProgress: number
|
||||
files: Record<string, UppyFile<M, B>>
|
||||
supportsUploadProgress: boolean
|
||||
hideAfterFinish?: boolean
|
||||
isSomeGhost: boolean
|
||||
doneButtonHandler?: (() => void) | null
|
||||
isUploadStarted: boolean
|
||||
i18n: I18n
|
||||
startUpload: () => void
|
||||
uppy: Uppy<M, B>
|
||||
isAllComplete: boolean
|
||||
showProgressDetails?: boolean
|
||||
numUploads: number
|
||||
complete: number
|
||||
totalSize: number | null
|
||||
totalETA: number | null
|
||||
totalUploadedSize: number
|
||||
}
|
||||
|
||||
export default function StatusBarUI<M extends Meta, B extends Body>({
|
||||
newFiles,
|
||||
allowNewUpload,
|
||||
isUploadInProgress,
|
||||
isAllPaused,
|
||||
resumableUploads,
|
||||
error,
|
||||
hideUploadButton = undefined,
|
||||
hidePauseResumeButton = false,
|
||||
hideCancelButton = false,
|
||||
hideRetryButton = false,
|
||||
recoveredState,
|
||||
uploadState,
|
||||
totalProgress,
|
||||
files,
|
||||
supportsUploadProgress,
|
||||
hideAfterFinish = false,
|
||||
isSomeGhost,
|
||||
doneButtonHandler = undefined,
|
||||
isUploadStarted,
|
||||
i18n,
|
||||
startUpload,
|
||||
uppy,
|
||||
isAllComplete,
|
||||
showProgressDetails = undefined,
|
||||
numUploads,
|
||||
complete,
|
||||
totalSize,
|
||||
totalETA,
|
||||
totalUploadedSize,
|
||||
}: StatusBarUIProps<M, B>) {
|
||||
function getProgressValue(): number | null {
|
||||
switch (uploadState) {
|
||||
case STATE_POSTPROCESSING:
|
||||
case STATE_PREPROCESSING: {
|
||||
const progress = calculateProcessingProgress(files)
|
||||
|
||||
if (progress.mode === 'determinate') {
|
||||
return progress.value * 100
|
||||
}
|
||||
return totalProgress
|
||||
}
|
||||
case STATE_ERROR: {
|
||||
return null
|
||||
}
|
||||
case STATE_UPLOADING: {
|
||||
if (!supportsUploadProgress) {
|
||||
return null
|
||||
}
|
||||
return totalProgress
|
||||
}
|
||||
default:
|
||||
return totalProgress
|
||||
}
|
||||
}
|
||||
|
||||
function getIsIndeterminate(): boolean {
|
||||
switch (uploadState) {
|
||||
case STATE_POSTPROCESSING:
|
||||
case STATE_PREPROCESSING: {
|
||||
const { mode } = calculateProcessingProgress(files)
|
||||
return mode === 'indeterminate'
|
||||
}
|
||||
case STATE_UPLOADING: {
|
||||
if (!supportsUploadProgress) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
const progressValue = getProgressValue()
|
||||
|
||||
const width = progressValue ?? 100
|
||||
|
||||
const showUploadBtn =
|
||||
!error &&
|
||||
newFiles &&
|
||||
((!isUploadInProgress && !isAllPaused) || recoveredState) &&
|
||||
allowNewUpload &&
|
||||
!hideUploadButton
|
||||
|
||||
const showCancelBtn =
|
||||
!hideCancelButton &&
|
||||
uploadState !== STATE_WAITING &&
|
||||
uploadState !== STATE_COMPLETE
|
||||
|
||||
const showPauseResumeBtn =
|
||||
resumableUploads &&
|
||||
!hidePauseResumeButton &&
|
||||
uploadState === STATE_UPLOADING
|
||||
|
||||
const showRetryBtn = error && !isAllComplete && !hideRetryButton
|
||||
|
||||
const showDoneBtn = doneButtonHandler && uploadState === STATE_COMPLETE
|
||||
|
||||
const progressClassNames = classNames('uppy-StatusBar-progress', {
|
||||
'is-indeterminate': getIsIndeterminate(),
|
||||
})
|
||||
|
||||
const statusBarClassNames = classNames(
|
||||
'uppy-StatusBar',
|
||||
`is-${uploadState}`,
|
||||
{ 'has-ghosts': isSomeGhost },
|
||||
)
|
||||
|
||||
const progressBarStateEl = (() => {
|
||||
switch (uploadState) {
|
||||
case STATE_PREPROCESSING:
|
||||
case STATE_POSTPROCESSING:
|
||||
return (
|
||||
<ProgressBarProcessing
|
||||
progress={calculateProcessingProgress(files)}
|
||||
/>
|
||||
)
|
||||
case STATE_COMPLETE:
|
||||
return <ProgressBarComplete i18n={i18n} />
|
||||
case STATE_ERROR:
|
||||
return (
|
||||
<ProgressBarError
|
||||
error={error}
|
||||
i18n={i18n}
|
||||
numUploads={numUploads}
|
||||
complete={complete}
|
||||
/>
|
||||
)
|
||||
case STATE_UPLOADING:
|
||||
return (
|
||||
<ProgressBarUploading
|
||||
i18n={i18n}
|
||||
supportsUploadProgress={supportsUploadProgress}
|
||||
totalProgress={totalProgress}
|
||||
showProgressDetails={showProgressDetails}
|
||||
isUploadStarted={isUploadStarted}
|
||||
isAllComplete={isAllComplete}
|
||||
isAllPaused={isAllPaused}
|
||||
newFiles={newFiles}
|
||||
numUploads={numUploads}
|
||||
complete={complete}
|
||||
totalUploadedSize={totalUploadedSize}
|
||||
totalSize={totalSize}
|
||||
totalETA={totalETA}
|
||||
startUpload={startUpload}
|
||||
/>
|
||||
)
|
||||
default:
|
||||
return null
|
||||
}
|
||||
})()
|
||||
|
||||
const atLeastOneAction =
|
||||
showUploadBtn ||
|
||||
showRetryBtn ||
|
||||
showPauseResumeBtn ||
|
||||
showCancelBtn ||
|
||||
showDoneBtn
|
||||
const thereIsNothingInside = !atLeastOneAction && !progressBarStateEl
|
||||
|
||||
const isHidden =
|
||||
thereIsNothingInside || (uploadState === STATE_COMPLETE && hideAfterFinish)
|
||||
|
||||
if (isHidden) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={statusBarClassNames}>
|
||||
<div
|
||||
className={progressClassNames}
|
||||
style={{ width: `${width}%` }}
|
||||
role="progressbar"
|
||||
aria-label={`${width}%`}
|
||||
aria-valuetext={`${width}%`}
|
||||
aria-valuemin={0}
|
||||
aria-valuemax={100}
|
||||
aria-valuenow={progressValue!}
|
||||
/>
|
||||
|
||||
{progressBarStateEl}
|
||||
|
||||
<div className="uppy-StatusBar-actions">
|
||||
{showUploadBtn ? (
|
||||
<UploadBtn
|
||||
newFiles={newFiles}
|
||||
isUploadStarted={isUploadStarted}
|
||||
recoveredState={recoveredState}
|
||||
i18n={i18n}
|
||||
isSomeGhost={isSomeGhost}
|
||||
startUpload={startUpload}
|
||||
uploadState={uploadState}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
{showRetryBtn ? <RetryBtn i18n={i18n} uppy={uppy} /> : null}
|
||||
|
||||
{showPauseResumeBtn ? (
|
||||
<PauseResumeButton
|
||||
isAllPaused={isAllPaused}
|
||||
i18n={i18n}
|
||||
isAllComplete={isAllComplete}
|
||||
resumableUploads={resumableUploads}
|
||||
uppy={uppy}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
{showCancelBtn ? <CancelBtn i18n={i18n} uppy={uppy} /> : null}
|
||||
|
||||
{showDoneBtn ? (
|
||||
<DoneBtn i18n={i18n} doneButtonHandler={doneButtonHandler} />
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
30
packages/@uppy/status-bar/src/calculateProcessingProgress.ts
Normal file
30
packages/@uppy/status-bar/src/calculateProcessingProgress.ts
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
import type { FileProcessingInfo, UppyFile } from '@uppy/utils'
|
||||
|
||||
export default function calculateProcessingProgress(
|
||||
files: Record<string, UppyFile<any, any>>,
|
||||
): FileProcessingInfo {
|
||||
const values: number[] = []
|
||||
let mode: FileProcessingInfo['mode'] = 'indeterminate'
|
||||
let message: FileProcessingInfo['message']
|
||||
|
||||
for (const { progress } of Object.values(files)) {
|
||||
const { preprocess, postprocess } = progress
|
||||
// In the future we should probably do this differently. For now we'll take the
|
||||
// mode and message from the first file…
|
||||
if (message == null && (preprocess || postprocess)) {
|
||||
;({ mode, message } = preprocess || postprocess!)
|
||||
}
|
||||
if (preprocess?.mode === 'determinate') values.push(preprocess.value)
|
||||
if (postprocess?.mode === 'determinate') values.push(postprocess.value)
|
||||
}
|
||||
|
||||
const value = values.reduce((total, progressValue) => {
|
||||
return total + progressValue / values.length
|
||||
}, 0)
|
||||
|
||||
return {
|
||||
mode,
|
||||
message,
|
||||
value,
|
||||
} as FileProcessingInfo
|
||||
}
|
||||
2
packages/@uppy/status-bar/src/index.ts
Normal file
2
packages/@uppy/status-bar/src/index.ts
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
export { default } from './StatusBar.js'
|
||||
export type { StatusBarOptions } from './StatusBarOptions.js'
|
||||
50
packages/@uppy/status-bar/src/locale.ts
Normal file
50
packages/@uppy/status-bar/src/locale.ts
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
export default {
|
||||
strings: {
|
||||
// Shown in the status bar while files are being uploaded.
|
||||
uploading: 'Uploading',
|
||||
// Shown in the status bar once all files have been uploaded.
|
||||
complete: 'Complete',
|
||||
// Shown in the status bar if an upload failed.
|
||||
uploadFailed: 'Upload failed',
|
||||
// Shown in the status bar while the upload is paused.
|
||||
paused: 'Paused',
|
||||
// Used as the label for the button that retries an upload.
|
||||
retry: 'Retry',
|
||||
// Used as the label for the button that cancels an upload.
|
||||
cancel: 'Cancel',
|
||||
// Used as the label for the button that pauses an upload.
|
||||
pause: 'Pause',
|
||||
// Used as the label for the button that resumes an upload.
|
||||
resume: 'Resume',
|
||||
// Used as the label for the button that resets the upload state after an upload
|
||||
done: 'Done',
|
||||
// When `showProgressDetails` is set, shows the number of files that have been fully uploaded so far.
|
||||
filesUploadedOfTotal: {
|
||||
0: '%{complete} of %{smart_count} file uploaded',
|
||||
1: '%{complete} of %{smart_count} files uploaded',
|
||||
},
|
||||
// When `showProgressDetails` is set, shows the amount of bytes that have been uploaded so far.
|
||||
dataUploadedOfTotal: '%{complete} of %{total}',
|
||||
dataUploadedOfUnknown: '%{complete} of unknown',
|
||||
// When `showProgressDetails` is set, shows an estimation of how long the upload will take to complete.
|
||||
xTimeLeft: '%{time} left',
|
||||
// Used as the label for the button that starts an upload.
|
||||
uploadXFiles: {
|
||||
0: 'Upload %{smart_count} file',
|
||||
1: 'Upload %{smart_count} files',
|
||||
},
|
||||
// Used as the label for the button that starts an upload, if another upload has been started in the past
|
||||
// and new files were added later.
|
||||
uploadXNewFiles: {
|
||||
0: 'Upload +%{smart_count} file',
|
||||
1: 'Upload +%{smart_count} files',
|
||||
},
|
||||
upload: 'Upload',
|
||||
retryUpload: 'Retry upload',
|
||||
xMoreFilesAdded: {
|
||||
0: '%{smart_count} more file added',
|
||||
1: '%{smart_count} more files added',
|
||||
},
|
||||
showErrorDetails: 'Show error details',
|
||||
},
|
||||
}
|
||||
463
packages/@uppy/status-bar/src/style.scss
Normal file
463
packages/@uppy/status-bar/src/style.scss
Normal file
|
|
@ -0,0 +1,463 @@
|
|||
@use "sass:color";
|
||||
@use '@uppy/core/src/_utils.scss';
|
||||
@use '@uppy/core/src/_variables.scss';
|
||||
@use '@uppy/utils/src/microtip.scss';
|
||||
|
||||
.uppy-StatusBar {
|
||||
position: relative;
|
||||
z-index: variables.$zIndex-2;
|
||||
display: flex;
|
||||
height: 46px;
|
||||
color: variables.$white;
|
||||
font-weight: 400;
|
||||
font-size: 12px;
|
||||
line-height: 40px;
|
||||
background-color: variables.$white;
|
||||
transition: height 0.2s;
|
||||
|
||||
[data-uppy-theme='dark'] & {
|
||||
background-color: variables.$gray-900;
|
||||
}
|
||||
}
|
||||
|
||||
.uppy-StatusBar::before {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 2px;
|
||||
background-color: variables.$gray-200;
|
||||
content: '';
|
||||
|
||||
[data-uppy-theme='dark'] & {
|
||||
background-color: variables.$gray-600;
|
||||
}
|
||||
}
|
||||
|
||||
.uppy-StatusBar[aria-hidden='true'] {
|
||||
height: 0;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
.uppy-StatusBar.is-complete .uppy-StatusBar-progress {
|
||||
background-color: variables.$green;
|
||||
}
|
||||
|
||||
.uppy-StatusBar.is-error .uppy-StatusBar-progress {
|
||||
background-color: variables.$red;
|
||||
}
|
||||
|
||||
.uppy-StatusBar.is-complete .uppy-StatusBar-statusIndicator {
|
||||
color: variables.$green;
|
||||
}
|
||||
|
||||
.uppy-StatusBar.is-error .uppy-StatusBar-statusIndicator {
|
||||
color: variables.$red;
|
||||
}
|
||||
|
||||
.uppy-StatusBar:not([aria-hidden='true']).is-waiting {
|
||||
height: 65px;
|
||||
background-color: variables.$white;
|
||||
border-top: 1px solid variables.$gray-200;
|
||||
|
||||
[data-uppy-theme='dark'] & {
|
||||
background-color: variables.$gray-900;
|
||||
border-top: 1px solid variables.$gray-800;
|
||||
}
|
||||
}
|
||||
|
||||
.uppy-StatusBar-progress {
|
||||
position: absolute;
|
||||
z-index: variables.$zIndex-2;
|
||||
height: 2px;
|
||||
background-color: variables.$blue;
|
||||
transition:
|
||||
background-color,
|
||||
width 0.3s ease-out;
|
||||
|
||||
&.is-indeterminate {
|
||||
$stripe-color: rgba(0, 0, 0, 0.3);
|
||||
|
||||
background-image: linear-gradient(
|
||||
45deg,
|
||||
$stripe-color 25%,
|
||||
transparent 25%,
|
||||
transparent 50%,
|
||||
$stripe-color 50%,
|
||||
$stripe-color 75%,
|
||||
transparent 75%,
|
||||
transparent
|
||||
);
|
||||
background-size: 64px 64px;
|
||||
animation: uppy-StatusBar-ProgressStripes 1s linear infinite;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes uppy-StatusBar-ProgressStripes {
|
||||
from {
|
||||
background-position: 0 0;
|
||||
}
|
||||
to {
|
||||
background-position: 64px 0;
|
||||
}
|
||||
}
|
||||
|
||||
.uppy-StatusBar.is-preprocessing .uppy-StatusBar-progress,
|
||||
.uppy-StatusBar.is-postprocessing .uppy-StatusBar-progress {
|
||||
background-color: variables.$orange;
|
||||
}
|
||||
|
||||
.uppy-StatusBar.is-waiting .uppy-StatusBar-progress {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.uppy-StatusBar-content {
|
||||
position: relative;
|
||||
z-index: variables.$zIndex-3;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
color: variables.$gray-800;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
padding-inline-start: 10px;
|
||||
|
||||
.uppy-size--md & {
|
||||
padding-inline-start: 15px;
|
||||
}
|
||||
|
||||
[data-uppy-theme='dark'] & {
|
||||
color: variables.$gray-200;
|
||||
}
|
||||
}
|
||||
|
||||
.uppy-StatusBar-status {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
font-weight: normal;
|
||||
line-height: 1.4;
|
||||
padding-inline-end: 0.3em;
|
||||
}
|
||||
|
||||
.uppy-StatusBar-statusPrimary {
|
||||
font-weight: 500;
|
||||
line-height: 1;
|
||||
display: flex;
|
||||
|
||||
button.uppy-StatusBar-details {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
[data-uppy-theme='dark'] & {
|
||||
color: variables.$gray-200;
|
||||
}
|
||||
}
|
||||
|
||||
.uppy-StatusBar-statusSecondary {
|
||||
display: inline-block;
|
||||
margin-top: 1px;
|
||||
color: variables.$gray-600;
|
||||
font-size: 11px;
|
||||
line-height: 1.2;
|
||||
white-space: nowrap;
|
||||
|
||||
[data-uppy-theme='dark'] & {
|
||||
color: variables.$gray-400;
|
||||
}
|
||||
}
|
||||
|
||||
.uppy-StatusBar-statusSecondaryHint {
|
||||
display: inline-block;
|
||||
line-height: 1;
|
||||
vertical-align: middle;
|
||||
margin-inline-end: 5px;
|
||||
|
||||
.uppy-size--md & {
|
||||
margin-inline-end: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.uppy-StatusBar-statusIndicator {
|
||||
position: relative;
|
||||
top: 1px;
|
||||
color: variables.$gray-700;
|
||||
margin-inline-end: 7px;
|
||||
|
||||
svg {
|
||||
vertical-align: text-bottom;
|
||||
}
|
||||
}
|
||||
|
||||
.uppy-StatusBar-actions {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
z-index: variables.$zIndex-4;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
inset-inline-end: 10px;
|
||||
}
|
||||
|
||||
.uppy-StatusBar.is-waiting .uppy-StatusBar-actions {
|
||||
position: static;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 0 15px;
|
||||
background-color: variables.$gray-50;
|
||||
|
||||
[data-uppy-theme='dark'] & {
|
||||
background-color: variables.$gray-900;
|
||||
}
|
||||
}
|
||||
|
||||
.uppy-StatusBar:not([aria-hidden='true']).is-waiting.has-ghosts {
|
||||
flex-direction: column;
|
||||
height: 90px;
|
||||
|
||||
.uppy-size--md & {
|
||||
flex-direction: row;
|
||||
height: 65px;
|
||||
}
|
||||
|
||||
.uppy-StatusBar-actions {
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
|
||||
.uppy-size--md & {
|
||||
flex-direction: row;
|
||||
justify-content: initial;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.uppy-StatusBar-actionCircleBtn {
|
||||
@include utils.blue-border-focus;
|
||||
|
||||
margin: 3px;
|
||||
line-height: 1;
|
||||
cursor: pointer;
|
||||
opacity: 0.9;
|
||||
|
||||
[data-uppy-theme='dark'] & {
|
||||
@include utils.blue-border-focus--dark;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
&:focus {
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
.uppy-StatusBar-actionCircleBtn svg {
|
||||
vertical-align: bottom;
|
||||
}
|
||||
|
||||
.uppy-StatusBar-actionBtn {
|
||||
display: inline-block;
|
||||
color: variables.$blue;
|
||||
font-size: 10px;
|
||||
line-height: inherit;
|
||||
vertical-align: middle;
|
||||
|
||||
.uppy-size--md & {
|
||||
font-size: 11px;
|
||||
}
|
||||
}
|
||||
|
||||
.uppy-StatusBar-actionBtn--disabled {
|
||||
opacity: 0.4;
|
||||
|
||||
[data-uppy-theme='dark'] & {
|
||||
opacity: 0.7;
|
||||
}
|
||||
}
|
||||
|
||||
.uppy-StatusBar-actionBtn--retry {
|
||||
@include utils.blue-border-focus();
|
||||
|
||||
position: relative;
|
||||
height: 16px;
|
||||
padding: 1px 6px 3px 18px;
|
||||
color: #fff;
|
||||
line-height: 1;
|
||||
background-color: variables.$pomegranate;
|
||||
border-radius: 8px;
|
||||
margin-inline-end: 6px;
|
||||
|
||||
[data-uppy-theme='dark'] & {
|
||||
@include utils.blue-border-focus--dark;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: color.adjust(variables.$pomegranate, $lightness: -8%);
|
||||
}
|
||||
|
||||
svg {
|
||||
position: absolute;
|
||||
top: 3px;
|
||||
inset-inline-start: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
.uppy-StatusBar.is-waiting .uppy-StatusBar-actionBtn--upload {
|
||||
width: 100%;
|
||||
padding: 15px 10px;
|
||||
color: variables.$white;
|
||||
font-size: 14px;
|
||||
line-height: 1;
|
||||
background-color: variables.$green;
|
||||
|
||||
&:hover {
|
||||
background-color: color.adjust(variables.$green, $lightness: -5%);
|
||||
}
|
||||
|
||||
[data-uppy-theme='dark'] & {
|
||||
background-color: variables.$darkgreen;
|
||||
}
|
||||
|
||||
[data-uppy-theme='dark'] &:hover {
|
||||
background-color: color.adjust(variables.$darkgreen, $lightness: -5%);
|
||||
}
|
||||
}
|
||||
|
||||
.uppy-size--md .uppy-StatusBar.is-waiting .uppy-StatusBar-actionBtn--upload {
|
||||
width: auto;
|
||||
padding: 13px 22px;
|
||||
}
|
||||
|
||||
.uppy-StatusBar.is-waiting
|
||||
.uppy-StatusBar-actionBtn--upload.uppy-StatusBar-actionBtn--disabled:hover {
|
||||
background-color: variables.$green;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
[data-uppy-theme='dark']
|
||||
.uppy-StatusBar.is-waiting
|
||||
.uppy-StatusBar-actionBtn--upload.uppy-StatusBar-actionBtn--disabled:hover {
|
||||
background-color: variables.$darkgreen;
|
||||
}
|
||||
|
||||
.uppy-StatusBar:not(.is-waiting) .uppy-StatusBar-actionBtn--upload {
|
||||
color: variables.$blue;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.uppy-StatusBar-actionBtn--uploadNewlyAdded {
|
||||
// for focus
|
||||
@include utils.blue-border-focus;
|
||||
|
||||
padding-inline-end: 3px;
|
||||
padding-inline-start: 3px;
|
||||
padding-bottom: 1px;
|
||||
border-radius: 3px;
|
||||
|
||||
[data-uppy-theme='dark'] & {
|
||||
@include utils.blue-border-focus--dark;
|
||||
}
|
||||
|
||||
.uppy-StatusBar.is-preprocessing &,
|
||||
.uppy-StatusBar.is-postprocessing & {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.uppy-StatusBar-actionBtn--done {
|
||||
@include utils.highlight-focus;
|
||||
|
||||
padding: 7px 8px;
|
||||
line-height: 1;
|
||||
border-radius: 3px;
|
||||
|
||||
[data-uppy-theme='dark'] & {
|
||||
color: variables.$highlight--dark;
|
||||
}
|
||||
}
|
||||
|
||||
.uppy-size--md .uppy-StatusBar-actionBtn--done {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.uppy-StatusBar-serviceMsg {
|
||||
padding-left: 10px;
|
||||
color: variables.$black;
|
||||
font-size: 11px;
|
||||
line-height: 1.1;
|
||||
|
||||
.uppy-size--md & {
|
||||
padding-left: 15px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
[data-uppy-theme='dark'] & {
|
||||
color: variables.$gray-200;
|
||||
}
|
||||
}
|
||||
|
||||
.uppy-StatusBar-serviceMsg-ghostsIcon {
|
||||
position: relative;
|
||||
top: 2px;
|
||||
left: 6px;
|
||||
width: 10px;
|
||||
vertical-align: text-bottom;
|
||||
opacity: 0.5;
|
||||
|
||||
.uppy-size--md & {
|
||||
top: 1px;
|
||||
left: 10px;
|
||||
width: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
.uppy-StatusBar-details {
|
||||
position: relative;
|
||||
top: 0;
|
||||
display: inline-block;
|
||||
width: 13px;
|
||||
height: 13px;
|
||||
color: variables.$white;
|
||||
font-weight: 600;
|
||||
font-size: 10px;
|
||||
line-height: 12px;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
background-color: variables.$gray-500;
|
||||
border-radius: 50%;
|
||||
cursor: help;
|
||||
appearance: none;
|
||||
inset-inline-start: 2px;
|
||||
}
|
||||
|
||||
.uppy-StatusBar-details::after {
|
||||
line-height: 1.3;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.uppy-StatusBar-spinner {
|
||||
animation-name: uppy-StatusBar-spinnerAnimation;
|
||||
animation-duration: 1s;
|
||||
animation-timing-function: linear;
|
||||
animation-iteration-count: infinite;
|
||||
fill: variables.$blue;
|
||||
margin-inline-end: 10px;
|
||||
}
|
||||
|
||||
.uppy-StatusBar.is-preprocessing .uppy-StatusBar-spinner,
|
||||
.uppy-StatusBar.is-postprocessing .uppy-StatusBar-spinner {
|
||||
fill: variables.$orange;
|
||||
}
|
||||
|
||||
@keyframes uppy-StatusBar-spinnerAnimation {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
17
packages/@uppy/status-bar/tsconfig.build.json
Normal file
17
packages/@uppy/status-bar/tsconfig.build.json
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"extends": "../../../tsconfig.shared",
|
||||
"compilerOptions": {
|
||||
"outDir": "./lib",
|
||||
"rootDir": "./src"
|
||||
},
|
||||
"include": ["./src/**/*.*"],
|
||||
"exclude": ["./src/**/*.test.ts"],
|
||||
"references": [
|
||||
{
|
||||
"path": "../utils/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../core/tsconfig.build.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
16
packages/@uppy/status-bar/tsconfig.json
Normal file
16
packages/@uppy/status-bar/tsconfig.json
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"extends": "../../../tsconfig.shared",
|
||||
"compilerOptions": {
|
||||
"emitDeclarationOnly": false,
|
||||
"noEmit": true
|
||||
},
|
||||
"include": ["./package.json", "./src/**/*.*"],
|
||||
"references": [
|
||||
{
|
||||
"path": "../utils/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../core/tsconfig.build.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
8
packages/@uppy/status-bar/turbo.json
Normal file
8
packages/@uppy/status-bar/turbo.json
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"extends": ["//"],
|
||||
"tasks": {
|
||||
"build": {
|
||||
"dependsOn": ["^build", "@uppy/core#build"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -44,6 +44,7 @@
|
|||
"@uppy/compressor": "workspace:^",
|
||||
"@uppy/core": "workspace:^",
|
||||
"@uppy/dashboard": "workspace:^",
|
||||
"@uppy/drag-drop": "workspace:^",
|
||||
"@uppy/drop-target": "workspace:^",
|
||||
"@uppy/dropbox": "workspace:^",
|
||||
"@uppy/facebook": "workspace:^",
|
||||
|
|
@ -59,6 +60,7 @@
|
|||
"@uppy/provider-views": "workspace:^",
|
||||
"@uppy/remote-sources": "workspace:^",
|
||||
"@uppy/screen-capture": "workspace:^",
|
||||
"@uppy/status-bar": "workspace:^",
|
||||
"@uppy/store-default": "workspace:^",
|
||||
"@uppy/thumbnail-generator": "workspace:^",
|
||||
"@uppy/transloadit": "workspace:^",
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ export { default as Box } from '@uppy/box'
|
|||
export { default as Compressor } from '@uppy/compressor'
|
||||
// UI plugins
|
||||
export { default as Dashboard } from '@uppy/dashboard'
|
||||
export { default as DragDrop } from '@uppy/drag-drop'
|
||||
export { default as DropTarget } from '@uppy/drop-target'
|
||||
export { default as Dropbox } from '@uppy/dropbox'
|
||||
export { default as Facebook } from '@uppy/facebook'
|
||||
|
|
@ -38,6 +39,7 @@ export { default as Instagram } from '@uppy/instagram'
|
|||
export { default as OneDrive } from '@uppy/onedrive'
|
||||
export { default as RemoteSources } from '@uppy/remote-sources'
|
||||
export { default as ScreenCapture } from '@uppy/screen-capture'
|
||||
export { default as StatusBar } from '@uppy/status-bar'
|
||||
// Stores
|
||||
export { default as DefaultStore } from '@uppy/store-default'
|
||||
export { default as ThumbnailGenerator } from '@uppy/thumbnail-generator'
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ export type { CompressorOptions } from '@uppy/compressor'
|
|||
export type { UIPluginOptions, UppyOptions } from '@uppy/core'
|
||||
// UI plugins
|
||||
export type { DashboardOptions } from '@uppy/dashboard'
|
||||
export type { DragDropOptions } from '@uppy/drag-drop'
|
||||
export type { DropTargetOptions } from '@uppy/drop-target'
|
||||
export type { DropboxOptions } from '@uppy/dropbox'
|
||||
export type { FacebookOptions } from '@uppy/facebook'
|
||||
|
|
@ -20,6 +21,7 @@ export type { InstagramOptions } from '@uppy/instagram'
|
|||
export type { OneDriveOptions } from '@uppy/onedrive'
|
||||
export type { RemoteSourcesOptions } from '@uppy/remote-sources'
|
||||
export type { ScreenCaptureOptions } from '@uppy/screen-capture'
|
||||
export type { StatusBarOptions } from '@uppy/status-bar'
|
||||
export type { ThumbnailGeneratorOptions } from '@uppy/thumbnail-generator'
|
||||
export type { TransloaditOptions } from '@uppy/transloadit'
|
||||
export type { TusOptions } from '@uppy/tus'
|
||||
|
|
|
|||
36
yarn.lock
36
yarn.lock
|
|
@ -9296,6 +9296,22 @@ __metadata:
|
|||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@uppy/drag-drop@workspace:^, @uppy/drag-drop@workspace:packages/@uppy/drag-drop":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@uppy/drag-drop@workspace:packages/@uppy/drag-drop"
|
||||
dependencies:
|
||||
"@uppy/utils": "workspace:^"
|
||||
cssnano: "npm:^7.0.7"
|
||||
postcss: "npm:^8.5.6"
|
||||
postcss-cli: "npm:^11.0.1"
|
||||
preact: "npm:^10.5.13"
|
||||
sass: "npm:^1.89.2"
|
||||
typescript: "npm:^5.8.3"
|
||||
peerDependencies:
|
||||
"@uppy/core": "workspace:^"
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@uppy/drop-target@workspace:*, @uppy/drop-target@workspace:^, @uppy/drop-target@workspace:packages/@uppy/drop-target":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@uppy/drop-target@workspace:packages/@uppy/drop-target"
|
||||
|
|
@ -9569,6 +9585,24 @@ __metadata:
|
|||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@uppy/status-bar@workspace:^, @uppy/status-bar@workspace:packages/@uppy/status-bar":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@uppy/status-bar@workspace:packages/@uppy/status-bar"
|
||||
dependencies:
|
||||
"@transloadit/prettier-bytes": "npm:^0.3.4"
|
||||
"@uppy/utils": "workspace:^"
|
||||
classnames: "npm:^2.2.6"
|
||||
cssnano: "npm:^7.0.7"
|
||||
postcss: "npm:^8.5.6"
|
||||
postcss-cli: "npm:^11.0.1"
|
||||
preact: "npm:^10.5.13"
|
||||
sass: "npm:^1.89.2"
|
||||
typescript: "npm:^5.8.3"
|
||||
peerDependencies:
|
||||
"@uppy/core": "workspace:^"
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@uppy/store-default@workspace:^, @uppy/store-default@workspace:packages/@uppy/store-default":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@uppy/store-default@workspace:packages/@uppy/store-default"
|
||||
|
|
@ -23851,6 +23885,7 @@ __metadata:
|
|||
"@uppy/compressor": "workspace:^"
|
||||
"@uppy/core": "workspace:^"
|
||||
"@uppy/dashboard": "workspace:^"
|
||||
"@uppy/drag-drop": "workspace:^"
|
||||
"@uppy/drop-target": "workspace:^"
|
||||
"@uppy/dropbox": "workspace:^"
|
||||
"@uppy/facebook": "workspace:^"
|
||||
|
|
@ -23866,6 +23901,7 @@ __metadata:
|
|||
"@uppy/provider-views": "workspace:^"
|
||||
"@uppy/remote-sources": "workspace:^"
|
||||
"@uppy/screen-capture": "workspace:^"
|
||||
"@uppy/status-bar": "workspace:^"
|
||||
"@uppy/store-default": "workspace:^"
|
||||
"@uppy/thumbnail-generator": "workspace:^"
|
||||
"@uppy/transloadit": "workspace:^"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue