Git Product home page Git Product logo

rpearce / react-medium-image-zoom Goto Github PK

View Code? Open in Web Editor NEW
1.8K 12.0 100.0 90.86 MB

πŸ”Ž 🏞 The original medium.com-inspired image zooming library for React (since 2016)

Home Page: https://rpearce.github.io/react-medium-image-zoom/

License: BSD 3-Clause "New" or "Revised" License

JavaScript 3.79% CSS 4.34% TypeScript 90.49% Dockerfile 0.17% Nix 0.69% MDX 0.51%
image-zoom medium react props zoom react-images zoom-images zoomable typescript reactjs hacktoberfest

react-medium-image-zoom's Introduction

react-medium-image-zoom

npm version react-medium-image-zoom bundlejs badge npm downloads All Contributors

The original medium.com-inspired image zooming library for React.

View the storybook examples to see various usages.

Features:

Requirements to know about:

  • <dialog> element (caniuse dialog)
  • ResizeObserver (caniuse ResizeObserver)
  • Package build target is ES2021. If you need to support older environments, run this package through your build system.

Quickstart

npm install --save react-medium-image-zoom
import React from 'react'
import Zoom from 'react-medium-image-zoom'
import 'react-medium-image-zoom/dist/styles.css'

export const MyImg = () => (
  <Zoom>
    <img
      alt="That Wanaka Tree, New Zealand by Laura Smetsers"
      src="/path/to/thatwanakatree.jpg"
      width="500"
    />
  </Zoom>
)

API

You can pass these options to either the Uncontrolled (default) or Controlled components.

export interface UncontrolledProps {
  // Accessible label text for when you want to unzoom.
  // Default: 'Minimize image'
  a11yNameButtonUnzoom?: string

  // Accessible label text for when you want to zoom.
  // Default: 'Expand image'
  a11yNameButtonZoom?: string

  // Allow swipe gesture to unzoom.
  // Default: true
  canSwipeToUnzoom?: boolean

  // Your image (required).
  children: ReactNode

  // Custom CSS className to add to the zoomed <dialog>.
  classDialog?: string

  // Provide your own unzoom button icon.
  // Default: ICompress
  IconUnzoom?: ElementType

  // Provide your own zoom button icon.
  // Default: IEnlarge
  IconZoom?: ElementType

  // Swipe gesture threshold after which to unzoom.
  // Default: 10
  swipeToUnzoomThreshold?: number

  // Specify what type of element should be used for
  // internal component usage. This is useful if the
  // image is inside a <p> or <button>, for example.
  // Default: 'div'
  wrapElement?: 'div' | 'span'

  // Provide your own custom modal content component.
  ZoomContent?: (props: {
    img: ReactElement | null;
    buttonUnzoom: ReactElement<HTMLButtonElement>;
    onUnzoom: () => void;
  }) => ReactElement;

  // Higher quality image attributes to use on zoom.
  zoomImg?: ImgHTMLAttributes<HTMLImageElement>

  // Offset in pixels the zoomed image should
  // be from the window's boundaries.
  // Default: 0
  zoomMargin?: number
}

You can pass these options to only the Controlled component.

export interface ControlledProps {
  // ...same as UncontrolledProps

  // Tell the component whether or not it should be zoomed
  // Default: false
  isZoomed: boolean

  // Listen for hints from the component about when you
  // should zoom (`true` value) or unzoom (`false` value)
  onZoomChange?: (value: boolean) => void
}

Basic Usage

Uncontrolled component (default)

Import the component and the CSS, wrap your image with the component, and the component will handle it's own state.

import React from 'react'
import Zoom from 'react-medium-image-zoom'
import 'react-medium-image-zoom/dist/styles.css'

// <img />
export const MyImg = () => (
  <Zoom>
    <img
      alt="That Wanaka Tree, New Zealand by Laura Smetsers"
      src="/path/to/thatwanakatree.jpg"
      width="500"
    />
  </Zoom>
)

// <div>
export const MyDiv = () => (
  <Zoom>
    <div
      aria-label="That Wanaka Tree, New Zealand by Laura Smetsers"
      role="img"
      style={{
        backgroundColor: '#fff',
        backgroundImage: `url("/path/to/thatwanakatree.jpg")`,
        backgroundPosition: '50%',
        backgroundRepeat: 'no-repeat',
        backgroundSize: 'cover',
        height: '0',
        paddingBottom: '56%',
        width: '100%',
      }}
    />
  </Zoom>
)

// <picture>
export const MyPicture = () => (
  <Zoom>
    <picture>
      <source media="(max-width: 800px)" srcSet="/path/to/teAraiPoint.jpg" />
      <img
        alt="A beautiful, serene setting in nature"
        src="/path/to/thatwanakatree.jpg"
        width="500"
      />
    </picture>
  </Zoom>
)

// <figure>
export const MyFigure = () => (
  <figure>
    <Zoom>
      <img
        alt="That Wanaka Tree, New Zealand by Laura Smetsers"
        src="/path/to/thatwanakatree.jpg"
        width="500"
      />
    </Zoom>
    <figcaption>Photo by Laura Smetsers</figcaption>
  </figure>
)

Controlled component

Import the Controlled component and the CSS, wrap your image with the component, and then dictate the isZoomed state to the component.

import React, { useCallback, useState } from 'react'
import { Controlled as ControlledZoom } from 'react-medium-image-zoom'
import 'react-medium-image-zoom/dist/styles.css'

const MyComponent = () => {
  const [isZoomed, setIsZoomed] = useState(false)

  const handleZoomChange = useCallback(shouldZoom => {
    setIsZoomed(shouldZoom)
  }, [])

  return (
    <ControlledZoom isZoomed={isZoomed} onZoomChange={handleZoomChange}>
      <img
        alt="That wanaka tree, alone in the water near mountains"
        src="/path/to/thatwanakatree.jpg"
        width="500"
      />
    </ControlledZoom>
  )
)

export default MyComponent

The onZoomChange prop accepts a callback that will receive true or false based on events that occur (like click or scroll events) to assist you in determining when to zoom and unzoom the component.

Styles

You can import the default styles from react-medium-image-zoom/dist/styles.css and override the values from your code, or you can copy the styles.css file and alter it to your liking. The latter is the best option, given rems should be used instead of px to account for different default browser font sizes, and it's hard for a library to guess at what these values should be.

An example of customizing the transition duration, timing function, overlay background color, and unzoom button styles with :focus-visible can be found in this story: https://rpearce.github.io/react-medium-image-zoom/?path=/story/img--custom-modal-styles

Custom zoom modal content

If you want to customize the zoomed modal experience with a caption, form, or other set of components, you can do so by providing a custom component to the ZoomContent prop.

View the live example of custom zoom modal content.

Below is some example code that demonstrates how to use this feature.

export const MyImg = () => (
  <Zoom ZoomContent={CustomZoomContent}>
    <img
      alt="That Wanaka Tree, New Zealand by Laura Smetsers"
      src="/path/to/thatwanakatree.jpg"
      width="500"
    />
  </Zoom>
)

const CustomZoomContent = ({
  buttonUnzoom, // default unzoom button
  modalState,   // current state of the zoom modal: UNLOADED, LOADING, LOADED, UNLOADING
  img,          // your image, prepped for zooming
  //onUnzoom,   // unused here, but a callback to manually unzoom the image and
                //   close the modal if you want to use your own buttons or
                //   listeners in your custom experience
}) => {
  const [isLoaded, setIsLoaded] = useState(false)

  useLayoutEffect(() => {
    if (modalState === 'LOADED') {
      setIsLoaded(true)
    } else if (modalState === 'UNLOADING') {
      setIsLoaded(false)
    }
  }, [modalState])

  const classCaption = isLoaded
    ? 'zoom-caption zoom-caption--loaded'
    : 'zoom-caption'

  return <>
    {buttonUnzoom}

    <figure>
      {img}
      <figcaption className={classCaption}>
        That Wanaka Tree, also known as the Wanaka Willow, is a willow tree
        located at the southern end of Lake Wānaka in the Otago region of New
        Zealand.
        <cite className="zoom-caption-cite">
          Wikipedia, <a className="zoom-caption-link" href="https://en.wikipedia.org/wiki/That_Wanaka_Tree">
            That Wanaka Tree
          </a>
        </cite>
      </figcaption>
    </figure>
  </>
}

Migrating From v4 to v5

Here are the prop changes from v4 to be aware of:

  • closeText was renamed to a11yNameButtonUnzoom
  • openText was renamed to a11yNameButtonZoom
  • overlayBgColorStart was removed and is now controlled via the CSS selector [data-rmiz-modal-overlay="hidden"]
  • overlayBgColorEnd was removed and is now controlled via the CSS selector [data-rmiz-modal-overlay="visible"]
  • portalEl was removed, for we are using the <dialog> element now
  • transitionDuration was removed and is now controlled via the CSS selectors [data-rmiz-modal-overlay] and [data-rmiz-modal-img]
  • wrapElement was removed then added back in v5.1.0
  • wrapStyle was removed
  • zoomZindex was removed, for we are using the <dialog> element now

And you can now provide zoomImg props to specify a different image to load when zooming.

Contributors ✨

Thanks goes to these wonderful people (emoji key):

Robert Pearce
Robert Pearce

πŸ’» πŸ’¬ ⚠️ πŸ› πŸ’‘ 🎨 πŸ‘€ πŸ€” πŸ“–
Cameron Bothner
Cameron Bothner

πŸ’» πŸ“– πŸ› πŸ’‘ πŸ€” πŸ‘€ ⚠️
Jeremy Bini
Jeremy Bini

πŸ’» πŸ›
ismay
ismay

πŸ› πŸ€”
Rajit Singh
Rajit Singh

πŸ›
Roberto Saccon
Roberto Saccon

πŸ›
wtfdaemon
wtfdaemon

πŸ›
Josh Sloat
Josh Sloat

πŸ› πŸ’» πŸ’‘ πŸ‘€ πŸ€” πŸ“– 🎨 πŸ’¬
Aswin
Aswin

πŸ’¬
Alex Shelkovskiy
Alex Shelkovskiy

πŸ›
Adrian Bindiu
Adrian Bindiu

πŸ›
Kendall Buchanan
Kendall Buchanan

πŸ›
Kaycee
Kaycee

πŸ’»
Anuj
Anuj

πŸ› πŸ’¬
Ludwig Frank
Ludwig Frank

πŸ› πŸ’»
LX
LX

πŸ› πŸ€”
Rosen Tomov
Rosen Tomov

πŸ›
Tom Moor
Tom Moor

πŸ’» πŸ›
Johan Preynat
Johan Preynat

πŸ’» πŸ›
Rahul Gaba
Rahul Gaba

πŸ’» πŸ›
Spencer Davis
Spencer Davis

πŸ’» πŸ€” πŸ‘€ 🎨
dnlnvl
dnlnvl

πŸ’»
Madi
Madi

πŸ€”
Ben Hood
Ben Hood

πŸ€” πŸ› πŸ’‘ πŸ‘€
Navilan
Navilan

πŸ€”
13806
13806

πŸ›
Akshay Kadam (A2K)
Akshay Kadam (A2K)

πŸ› πŸ€”
Jake Stewart
Jake Stewart

πŸ› πŸ€”
hhh
hhh

πŸ›
@davalapar
@davalapar

πŸ›
Sun Knudsen
Sun Knudsen

πŸ’» πŸ› πŸ€” πŸ’‘ πŸ’¬ πŸ‘€ ⚠️ πŸ“–
Douglas Galdino
Douglas Galdino

πŸ’» πŸ“– πŸ› πŸ€” πŸ’‘ πŸ‘€ ⚠️
Mohammed Faragallah
Mohammed Faragallah

πŸ› πŸ€” πŸ’‘
Youngrok Kim
Youngrok Kim

πŸ’» πŸ›
Nandhagopal Ezhilmaran
Nandhagopal Ezhilmaran

πŸ›
Mattia Astorino
Mattia Astorino

πŸ›
Dan Wood
Dan Wood

πŸ“–
Zachery C Gentry
Zachery C Gentry

πŸ›
xmflsct
xmflsct

πŸ›
Will.iam
Will.iam

πŸ’» ⚠️
Gourav Goyal
Gourav Goyal

πŸ“–
Joshua Chen
Joshua Chen

πŸ› πŸ’»
David Edler
David Edler

πŸ›
rikusen0335
rikusen0335

πŸ€”
Surjith S M
Surjith S M

πŸ€”
developergunny
developergunny

πŸ›
Khan Mohsin
Khan Mohsin

πŸ’¬
Robin Goudeketting
Robin Goudeketting

πŸ›
Botros Toro
Botros Toro

πŸ€”
Christian Guevara
Christian Guevara

πŸ’¬
Johan Book
Johan Book

πŸ›
Paolo Di Bello
Paolo Di Bello

πŸ€”
Tommaso De Rossi
Tommaso De Rossi

πŸ“– πŸ›
Lezan
Lezan

πŸ› πŸ€”
Ibrahim H. Sluma
Ibrahim H. Sluma

πŸ›
Ben Gotow
Ben Gotow

πŸ›
Rubon72
Rubon72

πŸ›
wanderingme
wanderingme

πŸ›
Thomas Strobl
Thomas Strobl

πŸ› πŸ€” πŸ’‘ πŸ’¬ πŸ‘€
Songkeys
Songkeys

πŸ› πŸ€” πŸ’‘ πŸ’¬ πŸ‘€
AntoineS92
AntoineS92

πŸ›
Sindre Aubert
Sindre Aubert

πŸ›
mx
mx

πŸ›
Sander Heling
Sander Heling

πŸ›
Yida Zhang
Yida Zhang

πŸ› πŸ’»
Nir
Nir

πŸ›
hhatakeyama
hhatakeyama

πŸ›
Paco
Paco

πŸ› πŸ€”
LichLord91
LichLord91

πŸ›
just-small-potato
just-small-potato

πŸ€”
walmsles
walmsles

πŸ›
tenshin
tenshin

πŸ’¬
Steven Tey
Steven Tey

πŸ›
Sergey
Sergey

πŸ› πŸ’» πŸ“–
Diego Azevedo
Diego Azevedo

πŸ“–
Faizan Ahmad
Faizan Ahmad

πŸ›
Kunal L.
Kunal L.

πŸ›
Kevin Wang
Kevin Wang

πŸ€”
u3u
u3u

πŸ€” πŸ‘€
Hong
Hong

πŸ’»
Wojciech Rok
Wojciech Rok

πŸ’» πŸ€”
Matija
Matija

πŸ›
Jiayi Hu
Jiayi Hu

πŸ›
Zeit der Forschung
Zeit der Forschung

πŸ›
Andrei Barabas
Andrei Barabas

πŸ› πŸ€”
NΓ©meth Benedek
NΓ©meth Benedek

πŸ›
iMalFect
iMalFect

πŸ›

This project follows the all-contributors specification. Contributions of any kind welcome!

react-medium-image-zoom's People

Contributors

cbothner avatar dependabot[bot] avatar diegoatwa avatar dnlnvl avatar dougg0k avatar eych avatar gorvgoyl avatar jeremybini avatar josh-cena avatar jpreynat avatar rgabs avatar rokoroku avatar romanown avatar rpearce avatar spencerfdavis avatar sunknudsen avatar tommoor avatar tshmieldev avatar tszhong0411 avatar valtism avatar zjhch123 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

react-medium-image-zoom's Issues

Component should have two "modes", controlled and uncontrolled, just like text inputs

Issue stems from the discussion and initial issue on #48.

Initial Issue:

Should be checking this.props against nextProps to see if props have
updated. Was instead checking against .state which could be different
even if isZoomed prop never changed.

To reproduce the issue I'm seeing, setting a prop to change after 10 seconds and then zoom into an image. Even though the prop you change isn't isZoomed the image will unzoom.
– @rajit

Diagnosis & Solution Plan

I think that this might be related to this comment of mine from February. I would think that, to follow the React way, props.isZoomed should not be able to be overridden by internal state except by a call to an event handler.

I would say the component should have two β€œmodes”: uncontrolled, in which it handles its own state in state, and controlled, in which a click fires the onUnzoom callback and does nothing else. A controlled component should expect its props to be adjusted for it, in response to an event, just as a controlled <input> doesn’t display a letter until its value prop is changed in response to onChange. This mode change could be based on whether or not a value is provided for isZoomed, controlled if the prop is provided and uncontrolled if it’s undefined.
– @cbothner

Further thoughts

TBD

Using srcset on zoomImage does not work

I would like to be able to define srcset and sizes on the zoomImage prop, but adding either of these fields has no effect.

I think that any extra fields defined on zoomImage should be passed down to the img tag, and additionally fetchZoomImage would pass these fields into the Image element so that the onload function can respond to the proper image source. If this sounds reasonable I'm happy to put up a PR

Blurry Image Zoom in iOS

This issue is a:

  • Bug report

Expected behavior

I expected to see the zoomed in image to be sharp on a mobile device (iOS).

Actual behavior

What actually happened was that the zoomed in image was really blurry.

Image1
Image2

Steps to reproduce behavior

  1. Go to https://rpearce.github.io/react-medium-image-zoom/ on a mobile device Safari or Chrome (iOS)
  2. Tap an image and look at the sharpness of the image

I tried this on 3.0.5 locally and I get the same effect.

Remove Firefox check and make all browsers behave the same

This issue is a:

  • Other

Description

We should consider taking out the InstallTrigger Firefox check and make the same functionality happen across all the browsers. It's probably the safest thing to do.

Conversation Reference:
#117 (comment)

Basically, these lines (https://github.com/rpearce/react-medium-image-zoom/blob/master/src/Zoom.js#L87-L92)

const src = img.currentSrc || img.src

// See comment at top of file for Firefox check information
const newState = isFirefox ? { tmpSrc: src } : { src }

this.setState(newState)

should be changed to

this.setState({ tmpSrc: img.currentSrc || img.src })

and the isFirefox check should be removed.

cc @kingdido999 for talking sense into me.

Wrap image in link for graceful degradation

I'm using this library for my portfolio, which is a universal app. Everything works fine, but I recently encountered a bug unrelated to this library which caused my clientside code to fail to boot. Because of the serverside rendering everything still worked, even without clientside js. Except for the zoom that this library provides (which makes sense of course).

Now I definitely don't expect a react app to work without js. But in the spirit of graceful degradation it might be sensible to wrap the image react-medium-image-zoom renders in a link, which points to the zoomImage src. The onClick handler could be attached to the link instead of the image, which would mean that in case of a failure to boot the link would work as a regular link and still lead the user to the zoomed image (albeit without the nice effect etc.).

Just a thought. I'm not sure whether such an implementation would have negative consequences on other parts of this lib. But it seemed like a nice semantic way of adding a bit of graceful degradation. Interested to hear what everyone thinks!

Zoom status doesn't always update when props.isZoomed changes.

I would like to use this as a controlled component, where I can toggle its zoomed state in a central state store. It seems like that's what the isZoomed prop is for, however if the image has never been zoomed before, then changing the isZoomed prop does nothing. If it has been zoomed before, setting isZoomed to true does open the zoomed view and setting isZoomed to false does close it, but the portal, then, is not deleted and all mouse input to the rest of the page is intercepted. Additionally, being able to set onZoom() and onUnzoom() callbacks would be useful.

styles for zoomImage prop don't work

Expected behavior

I expected style key to work with the zoomImage prop.

e.g.

zoomImage={{
    src: `${item.imageS}`,
    style: {width: `20rem`, height: `5rem`}
}}

...makes the zoomed image 20rem wide, 5rem tall.
Changing styles works perfectly for the image prop.

Actual behavior

Adding style key the zoomImage prop object has no effect.

e.g.

zoomImage={{
    src: `${item.imageS}`,
    style: {width: `20rem`, height: `5rem`}
}}

Don't provide zoom option if it can't actually be zoomed

Currently, if you click to zoom on an image that can't get any bigger, it just moves to the center of the screen. Let's disable it if it's already at its max size.

Also make sure to not scale it BIGGER than its max size (hook into shouldRespectMaxDimension?)

Wrong images is used after second zoom

Using v2.0.7 (because our project is still on React v15) our initialization of the component looks like this:

<ImageZoom
    shouldReplaceImage={false}
    image={{
        src: 'file1.jpg',
    }}
    zoomImage={{
        src: 'file2.jpg',
    }}
/>

When we click on the image for the first time, file2.jpg is in the zoomed dialog (expected!), then we close it and click it again for zooming and file1.jpg is in the zoomed dialog. Why? Expected behavior: file2.jpg has to be always rendered in the zoomed dialog.

Improve keyboard interaction for accessibility

Per accessibility standards (WAI-ARIA, MDN, WebAIM), it's important to ensure that all content can be accessed with the keyboard alone - and that the keyboard and mouse produce the same experience.

Since this component supports click to zoom, it should also support keyboard interaction to initiate and exit zoom.

  • By default, users can only navigate to links, buttons, and form controls with a keyboard. These natively-accessible elements should be used whenever possible. If this is not possible (like this case), you may need to use tabindex="0" to ensure an element can receive keyboard focus.
  • Following ARIA Practices, the interaction most closely models a button, so it should honor both Enter and Space. Use onkeydown to trap rather than onkeypress since IE will not fire keypress events for non-alphanumeric keys.
  • Since the zoomed appearance functions like a modal dialog, focus should return to the image element that opened the dialog.
  • Since the zoomed appearance functions like a modal dialog, it should support Esc to close as it already does.

Zooming and Unzooming with `Enter` Produces Errors

This issue is a:

  • Bug report

Expected behavior

That the 'Enter' key works without throwing errors.

Actual behavior

This might sound nit-picky, but it's happening with our users in production. If you open an image, and then sit and press Enter over and over (maybe 5 to 10 times?), invoking zoom and unzoom, eventually you can start throwing errors.

Steps to reproduce behavior

  1. Visit https://rpearce.github.io/react-medium-image-zoom/
  2. Scroll to the first image.
  3. Open Dev Tools.
  4. Zoom the image.
  5. Begin pressing Enter over and over.
  6. Watch for errors.

image

After unzoom the image src is replaced by zoomimage src

This issue is a:

  • Bug report

Expected behavior

While using this, I noticed that after I click on an image and then unzoom it, the src of the img tag is replaceted by the zoomImage src instead of having the original image src set.

Steps to reproduce behavior

  1. Open https://rpearce.github.io/react-medium-image-zoom/
  2. Open the dev console and inspect the bridge picture's img element
  3. Click on the picture of the bridge, then unzoom it, and inspect the src value changing

Link to repository/example of behavior

example

Render issue even while trying the example

Hi,

Even when i use the example to render an image i get this issue -

Uncaught Error: ImageZoom.render(): A valid React element (or null) must be returned. You may have returned undefined, an array or some other invalid object.

Pasting code here -

import React, {Component} from 'react';
import ReactMarkdown from 'react-markdown'
import markdown from '../../../data/Work/sourceapp/sourceapp.md'
import styles from './ProjectPage.scss'
import MediumImage from '../../utils/MediumImage'
import ImageZoom from 'react-medium-image-zoom'

class ProjectPage extends Component {
  render() {
    return (
      <div className="container">
        <h1>Image Zoom</h1>
        <p>
          Trust fund seitan chia, wolf lomo letterpress Bushwick before they
          sold out. Carles kogi fixie, squid twee Tonx readymade cred typewriter
          scenester locavore kale chips vegan organic. Meggings pug wolf
          Shoreditch typewriter skateboard. McSweeney&apos;s iPhone chillwave,
          food truck direct trade disrupt flannel irony tousled Cosby sweater
          single-origin coffee. Organic disrupt bicycle rights, tattooed
          messenger bag flannel craft beer fashion axe bitters. Readymade
          sartorial craft beer, quinoa sustainable butcher Marfa Echo Park Terry
          Richardson gluten-free flannel retro cred mlkshk banjo. Salvia
          90&apos;s art party Blue Bottle, PBR&amp;B cardigan 8-bit.
        </p>
        <p>
          Meggings irony fashion axe, tattooed master cleanse Blue Bottle
          stumptown bitters authentic flannel freegan paleo letterpress ugh
          sriracha. Wolf PBR&amp;B art party aesthetic meh cliche. Sartorial
          before they sold out deep v, aesthetic PBR&amp;B craft beer
          post-ironic synth keytar pork belly skateboard pour-over. Tonx cray
          pug Etsy, gastropub ennui wolf ethnic Odd Future viral master cleanse
          skateboard banjo. Pitchfork scenester cornhole, whatever try-hard
          ethnic banjo +1 gastropub American Apparel vinyl skateboard Shoreditch
          seitan. Blue Bottle keffiyeh Austin Helvetica art party. Portland
          ethnic fixie, beard retro direct trade ugh scenester Tumblr readymade
          authentic plaid pickled hashtag biodiesel.
        </p>
        <div>
          <ImageZoom
            image={{
              src: 'http://res.cloudinary.com/aswin/image/upload/v1511706514/Cover_g8mjcw.png',
              alt: 'Golden Gate Bridge',
              className: 'img'
            }}
            zoomImage={{
              src: 'http://res.cloudinary.com/aswin/image/upload/v1511706514/Cover_g8mjcw.png',
              alt: 'Golden Gate Bridge',
              className: 'img--zoomed'
            }}
          />
        </div>
        <p>
          Thundercats freegan Truffaut, four loko twee Austin scenester lo-fi
          seitan High Life paleo quinoa cray. Schlitz butcher ethical Tumblr,
          pop-up DIY keytar ethnic iPhone PBR sriracha. Tonx direct trade
          bicycle rights gluten-free flexitarian asymmetrical. Whatever drinking
          vinegar PBR XOXO Bushwick gentrify. Cliche semiotics banjo retro squid
          Wes Anderson. Fashion axe dreamcatcher you probably haven&apos;t heard
          of them bicycle rights. Tote bag organic four loko ethical selfies
          gastropub, PBR fingerstache tattooed bicycle rights.
        </p>
        <div style={{ float: 'left', margin: '0 1.5em 0 0' }}>
          <ImageZoom
            image={{
              src: 'http://res.cloudinary.com/aswin/image/upload/v1511706514/Cover_g8mjcw.png',
              alt: 'Picture of Mt. Cook in New Zealand',
              className: 'img',
              style: {
                width: '20em'
              }
            }}
            zoomImage={{
              src: 'http://res.cloudinary.com/aswin/image/upload/v1511706514/Cover_g8mjcw.png',
              alt: 'Picture of Mt. Cook in New Zealand',
              className: 'img--zoomed'
            }}
          />
        </div>
        <p>
          Ugh Portland Austin, distillery tattooed typewriter polaroid pug
          Banksy Neutra keffiyeh. Shoreditch mixtape wolf PBR&amp;B, tote bag
          dreamcatcher literally bespoke Odd Future selfies 90&apos;s master
          cleanse vegan. Flannel tofu deep v next level pickled, authentic Etsy
          Shoreditch literally swag photo booth iPhone pug semiotics banjo.
          Bicycle rights butcher Blue Bottle, actually DIY semiotics Banksy
          banjo mixtape Austin pork belly post-ironic. American Apparel
          gastropub hashtag, McSweeney&apos;s master cleanse occupy High Life
          bitters wayfarers next level bicycle rights. Wolf chia Terry
          Richardson, pop-up plaid kitsch ugh. Butcher +1 Carles, swag selfies
          Blue Bottle viral.
        </p>
        <p>
          Keffiyeh food truck organic letterpress leggings iPhone four loko
          hella pour-over occupy, Wes Anderson cray post-ironic. Neutra retro
          fixie gastropub +1, High Life semiotics. Vinyl distillery Etsy freegan
          flexitarian cliche jean shorts, Schlitz wayfarers skateboard tousled
          irony locavore XOXO meh. Ethnic Wes Anderson McSweeney&apos;s
          messenger bag, mixtape XOXO slow-carb cornhole aesthetic Marfa banjo
          Thundercats bitters. Raw denim banjo typewriter cray Tumblr, High Life
          single-origin coffee. 90&apos;s Tumblr cred, Terry Richardson occupy
          raw denim tofu fashion axe photo booth banh mi. Trust fund locavore
          Helvetica, fashion axe selvage authentic Shoreditch swag selfies
          stumptown +1.
        </p>
        <div>
          <ImageZoom
            image={{
              src: 'http://res.cloudinary.com/aswin/image/upload/v1511706514/Cover_g8mjcw.png',
              alt: 'Gazelle Stomping',
              title: "Don't exceed original image dimensions...",
              className: 'img',
              style: {
                width: '250px'
              }
            }}
            shouldRespectMaxDimension={true}
          />
        </div>
        <p>
          Scenester chambray slow-carb, trust fund biodiesel ugh bicycle rights
          cornhole. Gentrify messenger bag Truffaut tousled roof party pork
          belly leggings, photo booth jean shorts. Austin readymade PBR plaid
          chambray. Squid Echo Park pour-over, wayfarers forage whatever
          locavore typewriter artisan deep v four loko. Locavore occupy Neutra
          Pitchfork McSweeney&apos;s, wayfarers fingerstache. Actually
          asymmetrical drinking vinegar yr brunch biodiesel. Before they sold
          out sustainable readymade craft beer Portland gastropub squid Austin,
          roof party Thundercats chambray narwhal Bushwick pug.
        </p>
        <p>
          Literally typewriter chillwave, bicycle rights Carles flannel
          wayfarers. Biodiesel farm-to-table actually, locavore keffiyeh hella
          shabby chic pour-over try-hard Bushwick. Sriracha American Apparel
          Brooklyn, synth cray stumptown blog Bushwick +1 VHS hashtag. Wolf
          umami Carles Marfa, 90&apos;s food truck Cosby sweater. Fanny pack
          try-hard keytar pop-up readymade, master cleanse four loko trust fund
          polaroid salvia. Photo booth kitsch forage chambray, Carles scenester
          slow-carb lomo cardigan dreamcatcher. Swag asymmetrical leggings,
          biodiesel Tonx shabby chic ethnic master cleanse freegan.
        </p>
        <p>
          Raw denim Banksy shabby chic, 8-bit salvia narwhal fashion axe.
          Ethical Williamsburg four loko, chia kale chips distillery Shoreditch
          messenger bag swag iPhone Pitchfork. Viral PBR&amp;B single-origin
          coffee quinoa readymade, ethical chillwave drinking vinegar
          gluten-free Wes Anderson kitsch Tumblr synth actually bitters. Butcher
          McSweeney&apos;s forage mlkshk kogi fingerstache. Selvage scenester
          butcher Shoreditch, Carles beard plaid disrupt DIY. Pug readymade
          selvage retro, Austin salvia vinyl master cleanse flexitarian deep v
          bicycle rights plaid Terry Richardson mlkshk pour-over. Trust fund
          try-hard banh mi Brooklyn, 90&apos;s Etsy kogi YOLO salvia.
        </p>
      </div>
    )
  }
}

export default ProjectPage

Problem shouldReplaceImage

I am using 3.0.2, and when I try use shouldReplaceImage=false and zoomImage together image don't get zoomed second time.

Expected:

Click to zoom: zoomImage showed.
Click to unzoom: original image showed.

Click to zoom again: zoomImage showed (bit this not works, instead original image showed).

z-index of zoomContainer should be customizable

when using UI frameworks I prefer to set the z-index in react-medium-image-zoom to a value higher than the highest z-index used in the UI framework. Messing around with z-indexes in the UI framework itself, can quickly turn into a disaster.

So if the z-index would be exposed as a prop, it would be even easier !!! I have currently to use the source version of react-medium-image-zoom, just for being able to customize the z-index.

Video support / Extensibility

This issue is a: Feature request

Video support

Hello.
Love the component, especially the elegant UX of it. Would like to know if there are plans or a possibility for video integration? As a better alternative to gif. https://help.imgur.com/hc/en-us/articles/208606616-What-is-GIFV-

I hacked together a simple version that replaces the image with a video tag as a proof of concept:
https://www.youtube.com/watch?v=sgAzI9YyxUI

If there are no plans for integrating this sort of functionality, can anyone point me in the right direction of extending this component?

Thanks in advance!

Preload zoomImage url

Do you think preloading the zoomImages is a useful addition to this component? It seems quite useful to have the component automatically add

<link rel="preload" href="a_zoomImage.jpg" as="image">

for each zoomImage. Interested in what you think and whether or not that would be a useful optimisation. As I see it it should allow the browser to decide for itself whether or not to download the images ahead of time, and should mean that the zoomImages are available earlier.

Allow image attributes to change after init

Currently, there's no way to change image attributes after initial definition unless the image source also changes. This means that attributes like alt, className, tabIndex, etc cannot be dynamic.

Internally, the component stores the image prop as state and references the image through state (rather than props) during render. The state can only update on a source change. This was done to support regular and high res versions of the image.

The ideal solution is to treat the image's source as the only cached state, allowing all image attributes to serve as uncached, mutable props.

Some useful breadcrumbs:

if (this.props.image.src !== nextProps.image.src) {

const { image, isMaxDimension } = this.state

Opacity not respected by defaultStyles > overlay value

Can see where (line 610) you are using a bitwise and; to convert the opacity value to 0 or 1 based on visibility. Unfortunately, this has the side effect of overriding the opacity value I'm trying to pass in this.props.defaultStyles.overlay. It's important to me, from a design perspective to be able to have a partially opaque background while image is zoomed.

PropTypes warning remains

I realize this was probably fixed in #38, but the problem persisted for me:

Warning: Failed propType: Invariant Violation: Calling PropTypes validators directly is not supported by the `prop-types` package. Use `PropTypes.checkPropTypes()` to call them. Read more at http://fb.me/use-check-prop-types Check the render method of `ZoomPortrait`.

That's even after updating to React 15.6.1. The only way I could remove it was by removing all references to PropTypes altogether from the library: https://github.com/banzai-inc/react-medium-image-zoom/tree/without-prop-types

Any suggestions?

Import PropTypes from separate package

React 15.5 has deprecated importing PropTypes from the react package. Instead they're now recommending to use the new prop-types package. Any packages that use the old import strategy will produce a console error.

Feature request: allow handleZoom to filter out ctrl-Click or cmd-Click

When clicking on an image with cmd key pressed (or ctrl on windows), I am performing a different action than zooming. So I had to customize the handleZoom (I filtered out for all possible keyEvents):

  handleZoom(event) {
    if (!event.ctrlKey && !event.metaKey && !event.shiftKey && !event.altKey) {
      this.setState({ isZoomed: true })
    }
  }

Can we integrate this (or maybe an improved approach where one can provide an optional list which keys need to be filtered) ?

Cursor: zoom-in when image is not zoomable

This issue is a:

  • Bug report

Expected behavior

I expected cursor is default pointer when image isn't zoomable e.g. when shouldHandleZoom returns false.

Actual behavior

Cursor is always zoom-in by inline style.

Steps to reproduce behavior

  1. shouldHandleZoom returns false
  2. Try to zoom an image

Enlarge animations on mobile devices

Looks like the enlarge animations does not work on mobile devices when loading image remotely.
Contract animations works as expected.
On web browsers this works fine.

I'm using this inside a SPA based on react.
This sits inside a component from the 'react-bootstrap' library.
Also tried putting the component alone inside the return of the render function,
Still had that issue.

CODE SAMPLE:

      <div dir="auto">
        <Panel header={<h2>{this.props.dish.name}</h2>}>
        <Grid fluid>
          <Row>
            <Col lg={6} md={6} sm={6} xs={6}>
              <div>
                <ImageZoom
                  image={{
                    src: this.props.dish.image_url,
                    alt: this.props.dish.name,
                    className: 'img-responsive img-rounded',
                    style: { width: '100em' }
                  }}
                  defaultStyles={{
                    overlay: {
                      'backgroundColor': 'rgba(255, 255, 255, 0.8)'
                    },
                    zoomContainer: {
                      zIndex: 9999
                    }
                  }}
                  zoomMargin={10}
                />
              </div>
            </Col>
            <Col lg={6} md={6} sm={6} xs={6}>
              {this.props.dish.description}
            </Col>
          </Row>
          <Row className="price-label">
            <Col>
              <span>{this.props.dish.price_prefix}{this.props.dish.price}</span>
            </Col>
          </Row>
        </Grid>
      </Panel>
    </div>

shouldRespectMaxDimension doesn't really respect max dimension

Hi!

First of all, thanks for this great component and all your effort!

But the behavior of shouldRespectMaxDimension seems to be confusing and strange. When we specify zoomImage, this original image can be still smaller than the actual window size, so, we don't want it to be scaled with transform and want that its original size is being respected.

The current use case of shouldRespectMaxDimension is valid, but we would expect it to respect original image dimention if there is one.

Are there any technical difficulties for this limitation?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.