1.0.11 • Published 10 months ago

nuxt-dropzone-filelist v1.0.11

Weekly downloads
-
License
ISC
Repository
github
Last release
10 months ago

Dropzone Filelist

npm version npm downloads License Nuxt

A Nuxt module with opinionated settings to show a file list, directly based on dropzone.js, NOT based on any other dropzone plugin or module.

Features

  • no secondary vue dependencies
  • opinionated to enable a specific style
  • inbuild file icon
  • places text input fields for filenames, while uploads files directly to custom url
  • filling files on load
  • even files added by code, have an input
  • it is always relyably multifile internally, dropzone options can limit the file amount

Quick Setup

  1. Add nuxt-dropzone-filelist dependency to your project

    # Using pnpm
    pnpm add -D nuxt-dropzone-filelist
    
    # Using yarn
    yarn add --dev nuxt-dropzone-filelist
    
    # Using npm
    npm install --save-dev nuxt-dropzone-filelist
  2. Add nuxt-dropzone-filelist to the modules section of nuxt.config.ts

    export default defineNuxtConfig({
      modules: [
        'nuxt-dropzone-filelist'
      ]
    })
  3. Use it

    <template>
      <DropzoneFilelist uploadUrl="/api/upload" />
    </template>

Properties:

Note: When using as attributes, the properies will need to be kebab-case.

id: String = null

  • used for the fileid file-input name, falls back to options.paramName -> element id -> random number

nameTemplate: String = 'file[${id}][]'

  • template for name to use, supports: ${id}, ${name}, ${num} (current file index, no logic)
  • Note: no template-string content support

uploadUrl: String (required)

  • upload target url to post the files to

uploadText: String = 'Drag files here or click to upload'

  • upload area text

removeText: String = 'remove?'

  • string to use on the remove file item button

imgMaxSize: String = '2.5em'

  • cube side size for the image preview and file icon

hasClick: Boolean = false

  • false will not show the click highlight and message, but still trigger the click-handler

clickText: String = 'Clicked!'

  • text on the click highlight

clickFn: ( fileName: string, fileElement: HTMLDivElement, dropzone: Dropzone ):void => ...

  • default: console.log("clicked", fileName, { fileElement, dropzone })
  • handler on clicking on an item

clickDurrationMs: Number = 1000

  • how long the click highlight should be shown, 0 will not show the click highlight and message

initialFiles: Array = []

  • list of files to fill in on initialization

filesIconColor: Object = ...

  • default: { txt: "#E9EAEB", rtf: "#7C54AB", pdf: "#f40f02", doc: "#1B5EBE", docx: "#1B5EBE", xls: "#1d6f42", xlsx: "#1d6f42" }
  • file color map for file icon template

fileIconTemplate: String | null = null

  • supply an alternative data string to use as file icon, placeholders: 🔆 = color, ❓ = font-family, 👑 = title
  • be aware: it has to be a image url (base64 or passed through encodeURIComponent()), resulting in something for SVGs like: "data:image/svg+xml,%3Csvg ..."

usePreviewIcon: Boolean = true

  • use to show file icon while loading preview or if preview is not available

useFontAwesomeIcons: Boolean = false

  • uses the fontawesome 5 icons, fontawesome css needs to be available allready

addFileInputs: Boolean = true

  • enable adding text input fields with filenames for each added file

columnMode: String = 'container'

  • adds .***-width classes to adjust to available space, select the method to use:
    • 'media' == media-query, 'container' == container-query, 'column' / nothing == 1fr

useFormelement: Boolean = false

  • usually uses a div as wrapper, this changes it to <form>

disabled: Boolean = false

  • disables using of the element like a form element (also sets a real disabled property)

options: Object = {}

Events:

@init: (options: {dropzone: Dropzone, element: HTMLElement}): void

  • event handler that gt4s called after initialization

@addedFile: (options: {file: DropzoneFile, dropzone: Dropzone, element: HTMLElement}): void

  • event handler that gets called when a file got added (as well as for initialFiles)
  • use to add event handlers to slotted elements

@removedFile: (options: { file: DropzoneFile, dropzone: Dropzone, element: HTMLElement}): void

  • event handler that gets called when a file got removed

Methods:

To use Methods, you need a ref on the component, then access it as usual.

.addFile()

Params:
  1. nameOrFileObj: | string | { name: string; size?: number; imageUrl?: string }
  2. size?: number
  3. imageUrl?: string
  4. color?: string | false
  5. crossOrigin: "anonymous" | "use-credentials" | undefined = 'anonymous'
Examples:
// add image
this.$refs.dropzoneFilelist.addFile('name.jpg', 123123/*bytes*/, '/assets/preview.jpg');
// add non-image
this.$refs.dropzoneFilelist.addFile('name.ext', 123123/*bytes*/, undefined, '#FF0000');
// as object
this.$refs.dropzoneFilelist.addFile({
  name: 'name.ext',
  size: 123123,
  color: '#ff0000',
  // imageUrl: '/assets/preview.jpg'
});

Slots

default

  • use to add html to use as actions that will be visible on hover
  • use event @addedFile to add click handlers

Solutions & Examples

Tests are available here in the ./pages/ *.vue files

  • item click handler
    • to have a click action on a file item, add a handler with :click-fn
    • appearance can be changed by :has-click,:click-text,:click-durration-ms
  • action buttons

    • use default slot for additional buttons/links
    • handler: use @addedFile to add click handler by finding it with .querySelector()
    • <template>
        <DropzoneFilelist upload-url="/api/upload" @addedFile="addedFile">
          <button data-action-open-external>open</button>
        </DropzoneFilelist>
      </template>
      
      <script>
        export default defineComponent({
          methods: {
            addedFile({file, dropzone, element}) {
              element
                .querySelector('[data-action-open-external]')
                .addEventListener('click', (ev) => {
                  ev.preventDefault();
                  ev.stopPropagation();
      
                  // custom action
                  alert(file.name);
                });
            },
          },
        });
      </script>
  • loading initial files

    • :initial-files needs an array of: {name, filesize , imgUrl?, color?} (imgUrl or color, color for file icon)
  • getting a count of added files
    • this.$refs.dzf.dropzone.files.length
  • getting list of added files
    • this.$refs.dzf.dropzone.files => File[]
  • item select toggle
    • use an item click handler
    • toggle a class on element to change the background color
    • use an array to add or remove the file names to keep track
  • limit files
    • use dropzone's options, namely maxFiles:number
      <DropzoneFilelist upload-url="/api/upload" :options="{maxFiles: 2}" />
  • allow specific files only
    • use dropzone's options, namely acceptedFiles:string
      <DropzoneFilelist upload-url="/api/upload" :options="{acceptedFiles: 'image/jpeg,image/png,application/pdf'}" />
  • upload to nuxt /api

    • use npm/h3-formidable
    • ... to let formidable save the file first, then copy it to where it should go (moving is usually a problem due to file permissions on temp files)

      // ./server/api/upload.post.ts
      import fs from "node:fs/promises";
      import path from "node:path";
      
      import { readFiles } from "h3-formidable";
      
      export default defineEventHandler(async (event) => {
      
        // ... do some validation here: session / bearer-token / jwt / ...
      
        const { fields, files } = await readFiles(event, {
          includeFields: true,
          maxFileSize: 20 * 1024 * 1024,
          filter: () => true,
          // filter: ({ name, originalFilename, mimetype }) => mimetype && mimetype.includes("image"),
      
          // uploadDir: './upload', // direct uploading
          // keepExtensions: true,
      
          // other formidable options here
          // https://github.com/node-formidable/formidable#options
        });
  // if not `uploadDir` ... we move the file:
  let f: any = files.file[0];

  const targetPath = path.join(
    await fs.realpath("./upload"),
    f.originalFilename
  );

  await fs.copyFile(f.filepath, targetPath);
  await fs.unlink(f.filepath);

  // if a string is returned, it will be shown as error by DropZone
  return "";
```
  • Nuxt (h3) has native Session support: useSession() (my documentation and example)
  • the server could also be a PHP/ASPx/... server (when using the dropzone component from this package without the nuxt module part)

Development

# Install dependencies
npm install

# Generate type stubs
npm run dev:prepare

# Develop with the playground
npm run dev

# Build the playground
npm run dev:build

# Run ESLint
npm run lint

# Run Vitest
npm run test
npm run test:watch

# Release new version
npm run release
1.0.11

10 months ago

1.0.10

11 months ago

1.0.9

11 months ago

1.0.8

12 months ago

1.0.6

12 months ago

1.0.5

12 months ago

1.0.4

12 months ago

1.0.3

12 months ago

1.0.2

12 months ago

1.0.1

12 months ago