pqina / filepond-plugin-image-preview

🖼 Show a preview for images dropped on FilePond

Home Page:https://pqina.nl/filepond

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Status overlay (SVG mask) does not show

rovansteen opened this issue · comments

When I upload an image via filepond the status overlay becomes a solid color, on further inspection it seems that the SVG mask is not displayed, causing the status color to fill the complete shape with a solid color.

screenshot 2018-12-18 at 08 44 41

Here is the code I use to set up Filepond.

import React from 'react';
import 'doka/doka.min.css';
import * as Doka from 'doka';
import cookie from 'js-cookie';
import Box from 'components/box';
import styled from 'library/styled';
import * as config from 'library/config';
import { File, FilePond, registerPlugin } from 'react-filepond';

import 'filepond/dist/filepond.min.css';
import FilePondPluginImageEdit from 'filepond-plugin-image-edit';
import FilePondPluginImageCrop from 'filepond-plugin-image-crop';
import FilePondPluginImageResize from 'filepond-plugin-image-resize';
import FilePondPluginImagePreview from 'filepond-plugin-image-preview';
import 'filepond-plugin-image-edit/dist/filepond-plugin-image-edit.css';
import FilePondPluginImageTransform from 'filepond-plugin-image-transform';
import 'filepond-plugin-image-preview/dist/filepond-plugin-image-preview.css';
import FilePondPluginImageExifOrientation from 'filepond-plugin-image-exif-orientation';

registerPlugin(
  FilePondPluginImageExifOrientation,
  FilePondPluginImagePreview,
  FilePondPluginImageCrop,
  FilePondPluginImageResize,
  FilePondPluginImageTransform,
  FilePondPluginImageEdit,
);

interface Props {
  required?: boolean;
  cropAspectRatio?: string | number | null;
  onChange: (value: any) => void;
  value?: any;
}

interface State {
  image: any;
}

export default class ImageUpload extends React.Component<Props> {
  /**
   * Define the default props.
   */
  static defaultProps = {
    cropAspectRatio: null,
  };

  /**
   * Get the derived state from the props.
   *
   * @static
   * @param {Props} props
   * @param {State} state
   */
  static getDerivedStateFromProps(props: Props, state: State) {
    return {
      image: state.image || props.value,
    };
  }

  /**
   * Define the initial state.
   */
  state = {
    image: null,
  };

  /**
   * Ref to the pond instance.
   */
  pond = React.createRef();

  /**
   * Server config.
   */
  getConfig() {
    const token = cookie.get('XSRF-TOKEN');

    if (!token) {
      throw new Error('Could not set up a secure connection with the server.');
    }

    return {
      url: config.api.uploadImage,
      process: {
        withCredentials: true,
        headers: {
          Accept: 'application/json',
          'X-XSRF-TOKEN': token,
        },
      },
    };
  }

  /**
   * Handle when the image is uploaded.
   */
  handleUpload = (error: any, file: any) => {
    if (error) throw error;
    this.props.onChange(file.serverId);
  };

  /**
   * Handle when the image is added.
   */
  handleUpdate = (files: Array<any>) => {
    this.setState({ image: files.length ? files[0].file : null });
  };

  /**
   * Handle when the image is removed.
   */
  handleRemoval = (file: any) => {
    this.props.onChange(null);
  };

  /**
   * Render the component.
   */
  render() {
    const { image } = this.state;
    const { cropAspectRatio, required } = this.props;

    return (
      <Box maxWidth="170px">
        <FilePond
          name="payload"
          ref={(ref: any) => (this.pond = ref)}
          required={required}
          allowRevert={false}
          allowMultiple={false}
          imageCropAspectRatio={cropAspectRatio}
          imageEditInstantEdit={false}
          imageEditEditor={Doka.create()}
          server={this.getConfig()}
          onprocessfile={this.handleUpload}
          onupdatefiles={this.handleUpdate}
          onremovefile={this.handleRemoval}
          labelIdle={`Drag & Drop your picture or <span class="filepond--label-action">Browse</span>`}
          imagePreviewHeight={170}
          imageResizeTargetWidth={100}
          imageResizeTargetHeight={100}
          stylePanelLayout="compact circle"
          styleButtonRemoveItemPosition="center bottom"
          styleProgressIndicatorPosition="center bottom"
          styleImageEditButtonEditItemPosition="right bottom"
        >
          {image && <File key={image} src={image} origin="local" />}
        </FilePond>
      </Box>
    );
  }
}

Versions:

    "filepond": "^3.5.1",
    "filepond-plugin-image-crop": "^2.0.0",
    "filepond-plugin-image-edit": "^1.0.1",
    "filepond-plugin-image-exif-orientation": "^1.0.3",
    "filepond-plugin-image-preview": "^3.1.4",
    "filepond-plugin-image-resize": "^2.0.1",
    "filepond-plugin-image-transform": "^3.1.0",

Weirdly enough, sometimes it does work (like once every 10 attempts). Could it be some kind of race condition?

commented

Hi Robert, that's weird indeed. The Image Preview plugin generates a sprite map at the root of the page (as a child of the body element). Maybe it's somehow removed? Does the React app live in a <div> as a child of <body>?

@rikschennink Yes I'm using the default create-react-app template which renders React in a <div id="root" /> that is a direct descendant of <body>.

See: https://github.com/facebook/create-react-app/blob/master/packages/react-scripts/template/public/index.html

In the cases it does work (seemingly random) I indeed see a <svg> node as child of <body> and in the cases it does not work it's missing.

commented

Okay, thanks for clarifying, my test environment is based on create-react-app as well so that should make it easier to test. Will get back to you later this week (again, probably Thursday).

commented

I've just published a new version 3.1.5 of the image preview plugin that tries to add the SVG a bit earlier and is a bit more persistent in trying to add it. Can you give it a try and let me know if it fixes the issue.

@rikschennink tested for a bit and the SVG mask displayed correctly every time I tried so seem to be resolved, thanks!

commented

Fantastic! Thanks for confirming!

I have the exact same problem with a similar setup in Angular 7. Works on desktop and most other devices but iOS (latest version) with Safari is a source of trouble which gives the same green large box.

Updated all your packages to the latest version but problem remains. The solution mentioned here does solve the problem but is not quite as appealing.

@supports (-webkit-marquee-repetition: infinite) and (object-fit: fill) {
	.filepond--image-preview-overlay svg rect { display: none; }
	.filepond--image-preview-overlay svg { background: linear-gradient(currentColor 0%, transparent 66%); }
}

Any idea's?

commented

@Zwimber Do you see the <svg> element that is generated by the image preview plugin, it should be appended to the element, somewhere near the end of the DOM.

screenshot 2019-02-04 at 09 54 31

Sorry for my late response, yes I do see the SVG element:

screenshot 2019-02-11 at 01 48 28

commented

@Zwimber reproduced the issue, it's related to the <base> tag.

See this issue: airbnb/lottie-web#360

Fixing it now.

commented

Should be fixed in Image Preview plugin version 4.0.2

I think this update actually broke it for me again, I'm getting the solid color like @Zwimber but it was working fine in 4.0.1

commented

Haha oh no 🤦🏼‍♂️

Any <base> tag present in your code?

This is the injected SVG code:

<svg class="filepond--image-preview-sprite" style="position: absolute; width: 0px; height: 0px;"><radialGradient id="filepond--image-preview-radial-gradient" cx=".5" cy="1.25" r="1.15">
<stop offset="50%" stop-color="#000000"></stop>
<stop offset="56%" stop-color="#0a0a0a"></stop>
<stop offset="63%" stop-color="#262626"></stop>
<stop offset="69%" stop-color="#4f4f4f"></stop>
<stop offset="75%" stop-color="#808080"></stop>
<stop offset="81%" stop-color="#b1b1b1"></stop>
<stop offset="88%" stop-color="#dadada"></stop>
<stop offset="94%" stop-color="#f6f6f6"></stop>
<stop offset="100%" stop-color="#ffffff"></stop>
</radialGradient>

<mask id="filepond--image-preview-masking">
<rect x="0" y="0" width="500" height="200" fill="url(http://localhost:3000#filepond--image-preview-radial-gradient)"></rect>
</mask></svg>

There's no <base> tag in my code.

commented

If it is there it’s probably in the <head> of the page.

commented

Tried to reproduce with create-react-app but it seems to work correctly

@rikschennink how exactly should it look? The <svg> should be wrapped in a <base> tag?

commented

@rovansteen It's unrelated to the <svg>, it's literally an element called <base> that sits in the <head> of the website.

https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base

Ah, I didn't even know that existed. So I'm not using that. I'm guessing it has something to do with using push state routing, but it's weird that it was working fine before.

commented

I've updated the plugin to change the contents of the url() value inside the SVG, maybe it conflicts with push state, will check later today.

commented

Just published version 4.0.3, it should fix the issue @rovansteen

@rikschennink thanks! Works perfectly again.

2019-04-19_01 10 44
It still occurs in React in Chrome @
"filepond": "^4.3.9",
"filepond-plugin-file-metadata": "^1.0.6",
"filepond-plugin-image-preview": "^4.0.8",

commented

@dnknitro Please provide a publicly accessible test case