UNPKG

@bytescale/upload-widget-vue

Version:

Vue File Upload UI Widget โ€” Lightweight & supports: drag and drop, multiple uploads, image cropping, customization & more ๐Ÿš€ Comes with Cloud Storage ๐ŸŒ

556 lines (446 loc) โ€ข 21.6 kB
<h1 align="center"> <a href="https://www.bytescale.com/docs/upload-widget/vue"> <img alt="Bytescale Upload Widget for Vue" width="524" height="80" src="https://raw.githubusercontent.com/bytescale/bytescale-upload-widget-vue/main/.github/assets/bytescale-upload-widget-vue.svg"> </a> </h1> <p align="center"><b>Beautiful File Upload Widget for Vue</b><br/> (With Built-in Cloud Storage)</p> <br/> <p align="center"> <a href="https://www.npmjs.com/package/@bytescale/upload-widget-vue"> <img src="https://img.shields.io/badge/%40bytescale%2Fupload--widget--vue-npm-4ba0f6" /> </a> <a href="https://github.com/bytescale/bytescale-upload-widget-vue/actions/workflows/ci.yml"> <img src="https://img.shields.io/badge/build-passing-4ba0f6" /> </a> <a href="https://github.com/bytescale/bytescale-upload-widget-vue/"> <img src="https://img.shields.io/badge/gzipped-33%20kb-4ba0f6" /> </a> <a href="https://www.npmjs.com/package/@bytescale/upload-widget-vue"> <img src="https://img.shields.io/npm/dt/uploader?color=%234ba0f6" /> </a> <br/> <a href="https://www.npmjs.com/package/@bytescale/upload-widget-vue"> <img src="https://img.shields.io/badge/TypeScript-included-4ba0f6" /> </a> <a href="https://github.com/bytescale/bytescale-upload-widget-vue/actions/workflows/ci.yml"> <img src="https://img.shields.io/npms-io/maintenance-score/uploader?color=4ba0f6" /> </a> <a target="_blank" href="https://twitter.com/intent/tweet?text=This%20was%20a%20great%20find...%0A%0Ahttps%3A%2F%2Fgithub.com%2Fbytescale%2Fbytescale-upload-widget-vue"> <img alt="Twitter URL" src="https://img.shields.io/twitter/url?style=social&url=https%3A%2F%2Fgithub.com%2Fbytescale%2Fbytescale-upload-widget-vue" /> </a> </p> <h1 align="center"> Get Started โ€” <a href="https://codepen.io/bytescale/pen/yLpvYew?editors=0010"> Try on CodePen </a> </h1> <p align="center"><a href="https://www.bytescale.com/docs/upload-widget"><img alt="Upload Widget Demo" width="100%" src="https://raw.githubusercontent.com/bytescale/bytescale-upload-widget/main/.github/assets/demo.gif"></a></p> <p align="center">100% Serverless File Upload Widget <br /> Powered by <a href="https://www.bytescale.com/">Bytescale</a><br/><br/></p> <hr/> <p align="center"> <b>Supports:</b> Image Cropping, Video Previews, Document Previews, Drag & Drop, and more... <br /> <br /> <a href="https://www.bytescale.com/docs/upload-widget/vue" rel="nofollow"><b>Full Documentation</b></a> โ€ข <a href="https://www.bytescale.com/docs/sdks/javascript" rel="nofollow">Headless SDK</a> โ€ข <a href="https://www.bytescale.com/docs/media-processing-apis" rel="nofollow">Media Processing APIs</a> โ€ข <a href="https://www.bytescale.com/docs/storage/sources" rel="nofollow">Storage</a> โ€ข <a href="https://www.bytescale.com/docs/cdn" rel="nofollow">CDN</a> </p> <hr/> <br /> ## Installation Install via NPM: ```shell npm install @bytescale/upload-widget-vue ``` Or via YARN: ```shell yarn add @bytescale/upload-widget-vue ``` Or via a `<script>` tag: ```html <script src="https://js.bytescale.com/upload-widget-vue/v4"></script> ``` ## Usage ### Option 1) File Upload Button โ€” [Try on CodePen](https://codepen.io/bytescale/pen/yLpvYew?editors=1000) Create a file upload button using the `openUploadModal` helper: ```html <template> <button @click="uploadFile">Upload a file...</button> </template> <script lang="ts"> import { openUploadModal } from "@bytescale/upload-widget-vue"; import type { UploadWidgetConfig, UploadWidgetResult } from "@bytescale/upload-widget"; import type { PreventableEvent } from "@bytescale/upload-widget-vue"; // Full Configuration: // https://www.bytescale.com/docs/upload-widget#configuration const options: UploadWidgetConfig = { apiKey: "free", // Get API keys from: www.bytescale.com maxFileCount: 10 }; export default { name: "App", methods: { uploadFile(event: PreventableEvent) { openUploadModal({ event, options, onComplete: (files: UploadWidgetResult[]) => { if (files.length === 0) { alert("No files selected."); } else { alert(files.map(f => f.fileUrl).join("\n")); } } }) } } }; </script> ``` ### Option 2) Dropzone โ€” [Try on CodePen](https://codepen.io/bytescale/pen/RwJvpKG?editors=1000) Create a file upload dropzone using the `UploadDropzone` component: ```html <template> <UploadDropzone :options="options" :on-complete="onFilesUploaded" :on-update="onFileListChanged" width="600px" height="375px" /> </template> <script lang="ts"> import { UploadDropzone } from "@bytescale/upload-widget-vue"; import type { UploadWidgetConfig, UploadWidgetResult, UploadWidgetOnUpdateEvent } from "@bytescale/upload-widget"; // Full Configuration: // https://www.bytescale.com/docs/upload-widget#configuration const options: UploadWidgetConfig = { apiKey: "free", // Get API keys from: www.bytescale.com maxFileCount: 10, showFinishButton: true }; export default { name: "App", components: { UploadDropzone }, data() { return { options }; }, methods: { onFileListChanged({ uploadedFiles, pendingFiles, failedFiles }: UploadWidgetOnUpdateEvent) { const uploadedFileUrls = uploadedFiles.map(x => x.fileUrl).join("\n"); console.log(uploadedFileUrls); }, onFilesUploaded(files: UploadWidgetResult[]) { if (files.length === 0) { alert("No files selected."); } else { alert(files.map(f => f.fileUrl).join("\n")); } } } }; </script> ``` > **Special behaviour for dropzones:** > > `on-complete` only fires if `showFinishButton = true` (when the user clicks "Finish"). > > `on-update` must be used when `showFinishButton = false`. > > Default value: `showFinishButton = false` ## Result The callbacks receive a `Array<UploadWidgetResult>`: ```javascript { fileUrl: "https://upcdn.io/FW25...", // URL to use when serving this file. filePath: "/uploads/example.jpg", // File path (we recommend saving this to your database). accountId: "FW251aX", // Bytescale account the file was uploaded to. editedFile: undefined, // Edited file (for image crops). Same structure as below. originalFile: { fileUrl: "https://upcdn.io/FW25...", // Uploaded file URL. filePath: "/uploads/example.jpg", // Uploaded file path (relative to your raw file directory). accountId: "FW251aX", // Bytescale account the file was uploaded to. originalFileName: "example.jpg", // Original file name from the user's machine. file: { ... }, // Original DOM file object from the <input> element. size: 12345, // File size in bytes. lastModified: 1663410542397, // Epoch timestamp of when the file was uploaded or updated. mime: "image/jpeg", // File MIME type. metadata: { ... // User-provided JSON object. }, tags: [ "tag1", // User-provided & auto-generated tags. "tag2", ... ] } } ``` ## โš™๏ธ Configuration All configuration is optional (except for the `apiKey` field, which is required). ```javascript const options = { apiKey: "free", // Get API keys from: www.bytescale.com locale: myCustomLocale, // EN_US by default. (See "Localization" section below.) maxFileCount: 5, // Unlimited by default (or 1 if multi: false). maxFileSizeBytes: 1024 ** 2, // Unlimited by default. mimeTypes: ["image/*"], // Unrestricted by default. Supports * wildcard suffix. multi: false, // False by default. onInit: ({ // Exposes lifecycle methods for the component. close, // Closes the widget when called. reset, // Resets the widget when called. updateConfig // Updates the widget's config by passing a new config }) => {}, // object to the method's first parameter. onUpdate: (event) => { // Called each time the Upload Widget's list of files change. // event.pendingFiles // Array of files that are either uploading or queued. // event.failedFiles // Array of files that failed to upload (due to network or validation reasons). // event.uploadedFiles // Array of files that have been uploaded and not removed. }, onPreUpload: async file => ({ errorMessage: "Uh oh!", // Displays this validation error to the user (if set). transformedFile: file // Uploads 'transformedFile' instead of 'file' (if set). }), showFinishButton: true, // Show/hide the "finish" button in the widget. showRemoveButton: true, // Show/hide the "remove" button next to each file. styles: { breakpoints: { fullScreenWidth: 750, // Full-screen mode activates when the screen is at or below this width. fullScreenHeight: 420 // Full-screen mode activates when the screen is at or below this height. }, colors: { primary: "#377dff", // Primary buttons & links active: "#528fff", // Primary buttons & links (hover). Inferred if undefined. error: "#d23f4d", // Error messages shade100: "#333", // Standard text shade200: "#7a7a7a", // Secondary button text shade300: "#999", // Secondary button text (hover) shade400: "#a5a6a8", // Welcome text shade500: "#d3d3d3", // Modal close button shade600: "#dddddd", // Border shade700: "#f0f0f0", // Progress indicator background shade800: "#f8f8f8", // File item background shade900: "#fff" // Various (draggable crop buttons, etc.) }, fontFamilies: { base: "arial, sans-serif" // Base font family (comma-delimited). }, fontSizes: { base: 16 // Base font size (px). } }, path: { // Optional: a string (full file path) or object like so: fileName: "Example.jpg", // Supports path variables (e.g. {ORIGINAL_FILE_EXT}). folderPath: "/uploads" // Please refer to docs for all path variables. }, metadata: { hello: "world" // Arbitrary JSON metadata (saved against the file). }, tags: ["profile_picture"], // Requires a Bytescale account. editor: { images: { allowResizeOnMove: true, // True by default. If false, prevents cropper from resizing when moved. preview: true, // True by default if cropping is enabled. Previews PDFs and videos too. crop: true, // True by default. cropFilePath: image => { // Choose the file path used for JSON image crop files. const {filePath} = image // In: https://www.bytescale.com/docs/types/UploadedFile return `${filePath}.crop` // Out: https://www.bytescale.com/docs/types/FilePathDefinition }, cropRatio: 4 / 3, // Width / Height. Undefined enables freeform (default). cropShape: "rect" // "rect" (default) or "circ". } }, } ``` ### ๐Ÿณ๏ธ Localization Default is [EN_US](https://github.com/bytescale/bytescale-upload-widget/blob/main/lib/src/modules/locales/EN_US.ts): ```javascript const myCustomLocale = { addAnotherFileBtn: "Add another file...", addAnotherImageBtn: "Add another image...", cancelBtn: "cancel", cancelBtnClicked: "cancelled", cancelPreviewBtn: "Cancel", continueBtn: "Continue", cropBtn: "Crop", customValidationFailed: "Failed to validate file.", doneBtn: "Done", fileSizeLimitPrefix: "File size limit:", finishBtn: "Finished", finishBtnIcon: true, imageCropNumberPrefix: "Image", maxFilesReachedPrefix: "Maximum number of files:", maxImagesReachedPrefix: "Maximum number of images:", orDragDropFile: "...or drag and drop a file.", orDragDropFileMulti: "...or drag and drop files.", orDragDropImage: "...or drag and drop an image.", orDragDropImageMulti: "...or drag and drop images.", processingFile: "Processing file...", removeBtn: "remove", removeBtnClicked: "removed", submitBtnError: "Error!", submitBtnLoading: "Please wait...", unsupportedFileType: "File type not supported.", uploadFileBtn: "Upload a File", uploadFileMultiBtn: "Upload Files", uploadImageBtn: "Upload an Image", uploadImageMultiBtn: "Upload Images", xOfY: "of" } ``` # ๐ŸŒ API Support ## ๐ŸŒ File Management APIs Bytescale provides a wide range of [File Management APIs](https://www.bytescale.com/docs/apis): - **[File Listing](https://www.bytescale.com/docs/folder-api/ListFolder)** - **[File Deleting](https://www.bytescale.com/docs/file-api/DeleteFile)** - **[File Copying](https://www.bytescale.com/docs/file-api/CopyFile)** - [And more...](https://www.bytescale.com/docs/apis) ## ๐ŸŒ Media Processing APIs (Image/Video/Audio) Bytescale also provides real-time [Media Processing APIs](https://www.bytescale.com/docs/media-processing-apis): - **[Image Processing APIs](https://www.bytescale.com/docs/image-processing-api)** ([resize](https://www.bytescale.com/docs/image-processing-api#image-resizing-api), [crop](https://www.bytescale.com/docs/image-processing-api#image-cropping-api), [convert](https://www.bytescale.com/docs/image-processing-api#f), [compress](https://www.bytescale.com/docs/image-processing-api#image-compression-api) & [watermark](https://www.bytescale.com/docs/image-processing-api#Text-layering-api)) - **[Video Processing APIs](https://www.bytescale.com/docs/video-processing-api)** ([transcode](https://www.bytescale.com/docs/video-processing-api#video-transcoding-api), [optimize](https://www.bytescale.com/docs/video-processing-api#video-compression-api), [resize](https://www.bytescale.com/docs/video-processing-api#video-resizing-api) & [extract metadata](https://www.bytescale.com/docs/video-processing-api#video-metadata-api)) - **[Audio Processing APIs](https://www.bytescale.com/docs/audio-processing-api)** ([transcode](https://www.bytescale.com/docs/audio-processing-api#audio-transcoding-api), [optimize](https://www.bytescale.com/docs/audio-processing-api#audio-compression-api), [trim](https://www.bytescale.com/docs/audio-processing-api#audio-trimming-api) & [extract metadata](https://www.bytescale.com/docs/audio-processing-api#audio-metadata-api)) ### Image Processing API (Original Image) Here's an example using [a photo of Chicago](https://upcdn.io/W142hJk/raw/example/city-landscape.jpg): <img src="https://upcdn.io/W142hJk/raw/example/city-landscape.jpg" /> ``` https://upcdn.io/W142hJk/raw/example/city-landscape.jpg ``` ### Image Processing API (Transformed Image) Using the [Image Processing API](https://www.bytescale.com/docs/image-processing-api), you can produce [this image](https://upcdn.io/W142hJk/image/example/city-landscape.jpg?w=900&h=600&fit=crop&f=webp&q=80&blur=4&text=WATERMARK&layer-opacity=80&blend=overlay&layer-rotate=315&font-size=100&padding=10&font-weight=900&color=ffffff&repeat=true&text=Chicago&gravity=bottom&padding-x=50&padding-bottom=20&font=/example/fonts/Lobster.ttf&color=ffe400): <img src="https://upcdn.io/W142hJk/image/example/city-landscape.jpg?w=900&h=600&fit=crop&f=webp&q=80&blur=4&text=WATERMARK&layer-opacity=80&blend=overlay&layer-rotate=315&font-size=100&padding=10&font-weight=900&color=ffffff&repeat=true&text=Chicago&gravity=bottom&padding-x=50&padding-bottom=20&font=/example/fonts/Lobster.ttf&color=ffe400" /> ``` https://upcdn.io/W142hJk/image/example/city-landscape.jpg ?w=900 &h=600 &fit=crop &f=webp &q=80 &blur=4 &text=WATERMARK &layer-opacity=80 &blend=overlay &layer-rotate=315 &font-size=100 &padding=10 &font-weight=900 &color=ffffff &repeat=true &text=Chicago &gravity=bottom &padding-x=50 &padding-bottom=20 &font=/example/fonts/Lobster.ttf &color=ffe400 ``` ## Authentication Bytescale supports two types of authentication: ### API Keys The Bytescale Upload Widget uses the `apiKey` parameter to authenticate with [Bytescale](https://www.bytescale.com/). With API key auth, the requester has access to the resources available to the API key: - Secret API keys (`secret_***`) can perform all API operations (see: [Bytescale JavaScript SDK](https://www.bytescale.com/docs/sdks/javascript)). - Public API keys (`public_***`) can perform file uploads and file downloads only. File overwrites, file deletes, and all other destructive operations cannot be performed using public API keys. You must always use **public API keys** (e.g. `public_***`) in your client-side code. Each API key can have its read/write access limited to a subset of files/folders. ### JWTs JWTs are optional. With JWTs, users can download private files directly via the URL, as authentication is performed implicitly via a session cookie _or_ via an `authorization` header if service workers are enabled (see the `serviceWorkerScript` param on the `AuthManager.beginAuthSession` method). This allows the browser to display private files in `<img>`, `<video>`, and other elements. With JWTs, users can upload files to per-user folders. This is because the permissions in the [JWT's payload](https://www.bytescale.com/docs/types/BytescaleJwt) can be generated at runtime. The [Bytescale Upload Widget](https://www.bytescale.com/docs/upload-widget) internally uses the [Bytescale JavaScript SDK](https://www.bytescale.com/docs/sdks/javascript) to perform file uploads: the Bytescale JavaScript SDK handles the JWT refresh process with your API, requesting new JWTs when required, and includes your JWTs in all subsequent requests to the Bytescale API. [Learn more about the `AuthManager` and JWTs ยป](https://www.bytescale.com/docs/auth) ## UrlBuilder The [Bytescale JavaScript SDK](https://github.com/bytescale/bytescale-javascript-sdk) exports a `UrlBuilder` to construct URLs from `filePaths`: ```javascript import { UrlBuilder } from "@bytescale/sdk"; ``` **Recommended:** you should always save `filePaths` to your DB instead of `fileUrls`. #### Raw Files To get the URL for the uploaded image `/example.jpg` in its original form, use the following: ```javascript // Returns: "https://upcdn.io/1234abc/raw/example.jpg" UrlBuilder.url({ accountId: "1234abc", filePath: "/example.jpg" }); ``` #### Images To resize the uploaded image `/example.jpg` to 800x600, use the following: ```javascript // Returns: "https://upcdn.io/1234abc/image/example.jpg?w=800&h=600" UrlBuilder.url({ accountId: "1234abc", filePath: "/example.jpg", options: { transformation: "image", transformationParams: { w: 800, h: 600 } } }); ``` [Image Processing API Docs ยป](https://www.bytescale.com/docs/image-processing-api) #### Videos To transcode the uploaded video `/example.mov` to MP4/H.264 in HD, use the following: ```javascript // Returns: "https://upcdn.io/1234abc/video/example.mov?f=mp4-h264&h=1080" UrlBuilder.url({ accountId: "1234abc", filePath: "/example.mov", options: { transformation: "video", transformationParams: { f: "mp4-h264", h: 1080 } } }); ``` [Video Processing API Docs ยป](https://www.bytescale.com/docs/video-processing-api) #### Audio To transcode the uploaded audio `/example.wav` to AAC in 192kbps, use the following: ```javascript // Returns: "https://upcdn.io/1234abc/audio/example.wav?f=aac&br=192" UrlBuilder.url({ accountId: "1234abc", filePath: "/example.wav", options: { transformation: "audio", transformationParams: { f: "aac", br: 192 } } }); ``` [Audio Processing API Docs ยป](https://www.bytescale.com/docs/audio-processing-api) #### Archives To extract the file `document.docx` from the uploaded ZIP file `/example.zip`: ```javascript // Returns: "https://upcdn.io/1234abc/archive/example.zip?m=extract&artifact=/document.docx" UrlBuilder.url({ accountId: "1234abc", filePath: "/example.zip", options: { transformation: "archive", transformationParams: { m: "extract" }, artifact: "/document.docx" } }); ``` [Archive Processing API Docs ยป](https://www.bytescale.com/docs/archive-processing-api) ## ๐Ÿ™‹ Can I use my own storage? Bytescale supports AWS S3, Cloudflare R2, Google Storage, DigitalOcean, and Bytescale Storage. **[Bytescale Storage Docs ยป](https://www.bytescale.com/docs/storage/sources)** ## ๐Ÿ‘‹ Create your Bytescale Account Bytescale is the best way to upload, transform, and serve images, videos, and audio at scale. **[Create a Bytescale account ยป](https://www.bytescale.com/get-started)** #### Full Documentation - **[Bytescale Upload Widget Docs ยป](https://www.bytescale.com/docs/upload-widget)** - **[Bytescale Upload Widget (React) Docs ยป](https://www.bytescale.com/docs/upload-widget/frameworks/react)** - **[Bytescale Upload Widget (Angular) Docs ยป](https://www.bytescale.com/docs/upload-widget/frameworks/angular)** - **[Bytescale Upload Widget (Vue.js) Docs ยป](https://www.bytescale.com/docs/upload-widget/frameworks/vue)** - **[Bytescale Upload Widget (jQuery) Docs ยป](https://www.bytescale.com/docs/upload-widget/frameworks/jquery)** ## License [MIT](LICENSE)