[Glitch] Add expand/compress image button on image view box
Port 6a2db10f76 to glitch-soc
Signed-off-by: Thibaut Girka <thib@sitedethib.com>
			
			
This commit is contained in:
		@@ -13,6 +13,7 @@ export default class ImageLoader extends React.PureComponent {
 | 
			
		||||
    width: PropTypes.number,
 | 
			
		||||
    height: PropTypes.number,
 | 
			
		||||
    onClick: PropTypes.func,
 | 
			
		||||
    zoomButtonHidden: PropTypes.bool,
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static defaultProps = {
 | 
			
		||||
@@ -151,6 +152,9 @@ export default class ImageLoader extends React.PureComponent {
 | 
			
		||||
            alt={alt}
 | 
			
		||||
            src={src}
 | 
			
		||||
            onClick={onClick}
 | 
			
		||||
            width={width}
 | 
			
		||||
            height={height}
 | 
			
		||||
            zoomButtonHidden={this.props.zoomButtonHidden}
 | 
			
		||||
          />
 | 
			
		||||
        )}
 | 
			
		||||
      </div>
 | 
			
		||||
 
 | 
			
		||||
@@ -35,23 +35,39 @@ class MediaModal extends ImmutablePureComponent {
 | 
			
		||||
  state = {
 | 
			
		||||
    index: null,
 | 
			
		||||
    navigationHidden: false,
 | 
			
		||||
    zoomButtonHidden: false,
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  handleSwipe = (index) => {
 | 
			
		||||
    this.setState({ index: index % this.props.media.size });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  handleTransitionEnd = () => {
 | 
			
		||||
    this.setState({
 | 
			
		||||
      zoomButtonHidden: false,
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  handleNextClick = () => {
 | 
			
		||||
    this.setState({ index: (this.getIndex() + 1) % this.props.media.size });
 | 
			
		||||
    this.setState({
 | 
			
		||||
      index: (this.getIndex() + 1) % this.props.media.size,
 | 
			
		||||
      zoomButtonHidden: true,
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  handlePrevClick = () => {
 | 
			
		||||
    this.setState({ index: (this.props.media.size + this.getIndex() - 1) % this.props.media.size });
 | 
			
		||||
    this.setState({
 | 
			
		||||
      index: (this.props.media.size + this.getIndex() - 1) % this.props.media.size,
 | 
			
		||||
      zoomButtonHidden: true,
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  handleChangeIndex = (e) => {
 | 
			
		||||
    const index = Number(e.currentTarget.getAttribute('data-index'));
 | 
			
		||||
    this.setState({ index: index % this.props.media.size });
 | 
			
		||||
    this.setState({
 | 
			
		||||
      index: index % this.props.media.size,
 | 
			
		||||
      zoomButtonHidden: true,
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  handleKeyDown = (e) => {
 | 
			
		||||
@@ -128,6 +144,7 @@ class MediaModal extends ImmutablePureComponent {
 | 
			
		||||
            alt={image.get('description')}
 | 
			
		||||
            key={image.get('url')}
 | 
			
		||||
            onClick={this.toggleNavigation}
 | 
			
		||||
            zoomButtonHidden={this.state.zoomButtonHidden}
 | 
			
		||||
          />
 | 
			
		||||
        );
 | 
			
		||||
      } else if (image.get('type') === 'video') {
 | 
			
		||||
@@ -191,6 +208,7 @@ class MediaModal extends ImmutablePureComponent {
 | 
			
		||||
            style={swipeableViewsStyle}
 | 
			
		||||
            containerStyle={containerStyle}
 | 
			
		||||
            onChangeIndex={this.handleSwipe}
 | 
			
		||||
            onTransitionEnd={this.handleTransitionEnd}
 | 
			
		||||
            index={index}
 | 
			
		||||
          >
 | 
			
		||||
            {content}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,16 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import PropTypes from 'prop-types';
 | 
			
		||||
import IconButton from 'flavours/glitch/components/icon_button';
 | 
			
		||||
import { defineMessages, injectIntl } from 'react-intl';
 | 
			
		||||
 | 
			
		||||
const messages = defineMessages({
 | 
			
		||||
  compress: { id: 'lightbox.compress', defaultMessage: 'Compress image view box' },
 | 
			
		||||
  expand: { id: 'lightbox.expand', defaultMessage: 'Expand image view box' },
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const MIN_SCALE = 1;
 | 
			
		||||
const MAX_SCALE = 4;
 | 
			
		||||
const NAV_BAR_HEIGHT = 66;
 | 
			
		||||
 | 
			
		||||
const getMidpoint = (p1, p2) => ({
 | 
			
		||||
  x: (p1.clientX + p2.clientX) / 2,
 | 
			
		||||
@@ -14,7 +22,77 @@ const getDistance = (p1, p2) =>
 | 
			
		||||
 | 
			
		||||
const clamp = (min, max, value) => Math.min(max, Math.max(min, value));
 | 
			
		||||
 | 
			
		||||
export default class ZoomableImage extends React.PureComponent {
 | 
			
		||||
// Normalizing mousewheel speed across browsers
 | 
			
		||||
// copy from: https://github.com/facebookarchive/fixed-data-table/blob/master/src/vendor_upstream/dom/normalizeWheel.js
 | 
			
		||||
const normalizeWheel = event => {
 | 
			
		||||
  // Reasonable defaults
 | 
			
		||||
  const PIXEL_STEP = 10;
 | 
			
		||||
  const LINE_HEIGHT = 40;
 | 
			
		||||
  const PAGE_HEIGHT = 800;
 | 
			
		||||
 | 
			
		||||
  let sX = 0,
 | 
			
		||||
    sY = 0, // spinX, spinY
 | 
			
		||||
    pX = 0,
 | 
			
		||||
    pY = 0; // pixelX, pixelY
 | 
			
		||||
 | 
			
		||||
  // Legacy
 | 
			
		||||
  if ('detail' in event) {
 | 
			
		||||
    sY = event.detail;
 | 
			
		||||
  }
 | 
			
		||||
  if ('wheelDelta' in event) {
 | 
			
		||||
    sY = -event.wheelDelta / 120;
 | 
			
		||||
  }
 | 
			
		||||
  if ('wheelDeltaY' in event) {
 | 
			
		||||
    sY = -event.wheelDeltaY / 120;
 | 
			
		||||
  }
 | 
			
		||||
  if ('wheelDeltaX' in event) {
 | 
			
		||||
    sX = -event.wheelDeltaX / 120;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // side scrolling on FF with DOMMouseScroll
 | 
			
		||||
  if ('axis' in event && event.axis === event.HORIZONTAL_AXIS) {
 | 
			
		||||
    sX = sY;
 | 
			
		||||
    sY = 0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  pX = sX * PIXEL_STEP;
 | 
			
		||||
  pY = sY * PIXEL_STEP;
 | 
			
		||||
 | 
			
		||||
  if ('deltaY' in event) {
 | 
			
		||||
    pY = event.deltaY;
 | 
			
		||||
  }
 | 
			
		||||
  if ('deltaX' in event) {
 | 
			
		||||
    pX = event.deltaX;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if ((pX || pY) && event.deltaMode) {
 | 
			
		||||
    if (event.deltaMode === 1) { // delta in LINE units
 | 
			
		||||
      pX *= LINE_HEIGHT;
 | 
			
		||||
      pY *= LINE_HEIGHT;
 | 
			
		||||
    } else { // delta in PAGE units
 | 
			
		||||
      pX *= PAGE_HEIGHT;
 | 
			
		||||
      pY *= PAGE_HEIGHT;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Fall-back if spin cannot be determined
 | 
			
		||||
  if (pX && !sX) {
 | 
			
		||||
    sX = (pX < 1) ? -1 : 1;
 | 
			
		||||
  }
 | 
			
		||||
  if (pY && !sY) {
 | 
			
		||||
    sY = (pY < 1) ? -1 : 1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return {
 | 
			
		||||
    spinX: sX,
 | 
			
		||||
    spinY: sY,
 | 
			
		||||
    pixelX: pX,
 | 
			
		||||
    pixelY: pY,
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default @injectIntl
 | 
			
		||||
class ZoomableImage extends React.PureComponent {
 | 
			
		||||
 | 
			
		||||
  static propTypes = {
 | 
			
		||||
    alt: PropTypes.string,
 | 
			
		||||
@@ -22,6 +100,8 @@ export default class ZoomableImage extends React.PureComponent {
 | 
			
		||||
    width: PropTypes.number,
 | 
			
		||||
    height: PropTypes.number,
 | 
			
		||||
    onClick: PropTypes.func,
 | 
			
		||||
    zoomButtonHidden: PropTypes.bool,
 | 
			
		||||
    intl: PropTypes.object.isRequired,
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static defaultProps = {
 | 
			
		||||
@@ -32,6 +112,22 @@ export default class ZoomableImage extends React.PureComponent {
 | 
			
		||||
 | 
			
		||||
  state = {
 | 
			
		||||
    scale: MIN_SCALE,
 | 
			
		||||
    zoomMatrix: {
 | 
			
		||||
      type: null, // 'full-width' 'full-height'
 | 
			
		||||
      rate: null, // full screen scale rate
 | 
			
		||||
      clientWidth: null,
 | 
			
		||||
      clientHeight: null,
 | 
			
		||||
      offsetWidth: null,
 | 
			
		||||
      offsetHeight: null,
 | 
			
		||||
      clientHeightFixed: null,
 | 
			
		||||
      scrollTop: null,
 | 
			
		||||
      scrollLeft: null,
 | 
			
		||||
    },
 | 
			
		||||
    zoomState: 'expand', // 'expand' 'compress'
 | 
			
		||||
    navigationHidden: false,
 | 
			
		||||
    dragPosition: { top: 0, left: 0, x: 0, y: 0 },
 | 
			
		||||
    dragged: false,
 | 
			
		||||
    lockScroll: { x: 0, y: 0 },
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  removers = [];
 | 
			
		||||
@@ -49,17 +145,101 @@ export default class ZoomableImage extends React.PureComponent {
 | 
			
		||||
    // https://www.chromestatus.com/features/5093566007214080
 | 
			
		||||
    this.container.addEventListener('touchmove', handler, { passive: false });
 | 
			
		||||
    this.removers.push(() => this.container.removeEventListener('touchend', handler));
 | 
			
		||||
 | 
			
		||||
    handler = this.mouseDownHandler;
 | 
			
		||||
    this.container.addEventListener('mousedown', handler);
 | 
			
		||||
    this.removers.push(() => this.container.removeEventListener('mousedown', handler));
 | 
			
		||||
 | 
			
		||||
    handler = this.mouseWheelHandler;
 | 
			
		||||
    this.container.addEventListener('wheel', handler);
 | 
			
		||||
    this.removers.push(() => this.container.removeEventListener('wheel', handler));
 | 
			
		||||
    // Old Chrome
 | 
			
		||||
    this.container.addEventListener('mousewheel', handler);
 | 
			
		||||
    this.removers.push(() => this.container.removeEventListener('mousewheel', handler));
 | 
			
		||||
    // Old Firefox
 | 
			
		||||
    this.container.addEventListener('DOMMouseScroll', handler);
 | 
			
		||||
    this.removers.push(() => this.container.removeEventListener('DOMMouseScroll', handler));
 | 
			
		||||
 | 
			
		||||
    this.initZoomMatrix();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  componentWillUnmount () {
 | 
			
		||||
    this.removeEventListeners();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  componentDidUpdate () {
 | 
			
		||||
    if (this.props.zoomButtonHidden) {
 | 
			
		||||
      this.setState({ scale: MIN_SCALE }, () => {
 | 
			
		||||
        this.container.scrollLeft = 0;
 | 
			
		||||
        this.container.scrollTop = 0;
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    this.setState({ zoomState: this.state.scale >= this.state.zoomMatrix.rate ? 'compress' : 'expand' });
 | 
			
		||||
 | 
			
		||||
    if (this.state.scale === 1) {
 | 
			
		||||
      this.container.style.removeProperty('cursor');
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  removeEventListeners () {
 | 
			
		||||
    this.removers.forEach(listeners => listeners());
 | 
			
		||||
    this.removers = [];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  mouseWheelHandler = e => {
 | 
			
		||||
    e.preventDefault();
 | 
			
		||||
 | 
			
		||||
    const event = normalizeWheel(e);
 | 
			
		||||
 | 
			
		||||
    if (this.state.zoomMatrix.type === 'full-width') {
 | 
			
		||||
      // full width, scroll vertical
 | 
			
		||||
      this.container.scrollTop = this.container.scrollTop + event.pixelY;
 | 
			
		||||
    } else {
 | 
			
		||||
      // full height, scroll horizontal
 | 
			
		||||
      this.container.scrollLeft = this.container.scrollLeft + event.pixelY;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  mouseDownHandler = e => {
 | 
			
		||||
    this.container.style.cursor = 'grabbing';
 | 
			
		||||
    this.container.style.userSelect = 'none';
 | 
			
		||||
 | 
			
		||||
    this.setState({ dragPosition: {
 | 
			
		||||
      left: this.container.scrollLeft,
 | 
			
		||||
      top: this.container.scrollTop,
 | 
			
		||||
      // Get the current mouse position
 | 
			
		||||
      x: e.clientX,
 | 
			
		||||
      y: e.clientY,
 | 
			
		||||
    } });
 | 
			
		||||
 | 
			
		||||
    this.image.addEventListener('mousemove', this.mouseMoveHandler);
 | 
			
		||||
    this.image.addEventListener('mouseup', this.mouseUpHandler);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  mouseMoveHandler = e => {
 | 
			
		||||
    const dx = e.clientX - this.state.dragPosition.x;
 | 
			
		||||
    const dy = e.clientY - this.state.dragPosition.y;
 | 
			
		||||
 | 
			
		||||
    if ((this.state.dragPosition.left - dx) >= this.state.lockScroll.x) {
 | 
			
		||||
      this.container.scrollLeft = this.state.dragPosition.left - dx;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if ((this.state.dragPosition.top - dy) >= this.state.lockScroll.y) {
 | 
			
		||||
      this.container.scrollTop = this.state.dragPosition.top - dy;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    this.setState({ dragged: true });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  mouseUpHandler = () => {
 | 
			
		||||
    this.container.style.cursor = 'grab';
 | 
			
		||||
    this.container.style.removeProperty('user-select');
 | 
			
		||||
 | 
			
		||||
    this.image.removeEventListener('mousemove', this.mouseMoveHandler);
 | 
			
		||||
    this.image.removeEventListener('mouseup', this.mouseUpHandler);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  handleTouchStart = e => {
 | 
			
		||||
    if (e.touches.length !== 2) return;
 | 
			
		||||
 | 
			
		||||
@@ -80,7 +260,8 @@ export default class ZoomableImage extends React.PureComponent {
 | 
			
		||||
 | 
			
		||||
    const distance = getDistance(...e.touches);
 | 
			
		||||
    const midpoint = getMidpoint(...e.touches);
 | 
			
		||||
    const scale = clamp(MIN_SCALE, MAX_SCALE, this.state.scale * distance / this.lastDistance);
 | 
			
		||||
    const _MAX_SCALE = Math.max(MAX_SCALE, this.state.zoomMatrix.rate);
 | 
			
		||||
    const scale = clamp(MIN_SCALE, _MAX_SCALE, this.state.scale * distance / this.lastDistance);
 | 
			
		||||
 | 
			
		||||
    this.zoom(scale, midpoint);
 | 
			
		||||
 | 
			
		||||
@@ -110,8 +291,72 @@ export default class ZoomableImage extends React.PureComponent {
 | 
			
		||||
  handleClick = e => {
 | 
			
		||||
    // don't propagate event to MediaModal
 | 
			
		||||
    e.stopPropagation();
 | 
			
		||||
    const dragged = this.state.dragged;
 | 
			
		||||
    this.setState({ dragged: false });
 | 
			
		||||
    if (dragged) return;
 | 
			
		||||
    const handler = this.props.onClick;
 | 
			
		||||
    if (handler) handler();
 | 
			
		||||
    this.setState({ navigationHidden: !this.state.navigationHidden });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  handleMouseDown = e => {
 | 
			
		||||
    e.preventDefault();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  initZoomMatrix = () => {
 | 
			
		||||
    const { width, height } = this.props;
 | 
			
		||||
    const { clientWidth, clientHeight } = this.container;
 | 
			
		||||
    const { offsetWidth, offsetHeight } = this.image;
 | 
			
		||||
    const clientHeightFixed = clientHeight - NAV_BAR_HEIGHT;
 | 
			
		||||
 | 
			
		||||
    const type = width/height < clientWidth / clientHeightFixed ? 'full-width' : 'full-height';
 | 
			
		||||
    const rate = type === 'full-width' ? clientWidth / offsetWidth : clientHeightFixed / offsetHeight;
 | 
			
		||||
    const scrollTop = type === 'full-width' ?  (clientHeight - offsetHeight) / 2 - NAV_BAR_HEIGHT : (clientHeightFixed - offsetHeight) / 2;
 | 
			
		||||
    const scrollLeft = (clientWidth - offsetWidth) / 2;
 | 
			
		||||
 | 
			
		||||
    this.setState({
 | 
			
		||||
      zoomMatrix: {
 | 
			
		||||
        type: type,
 | 
			
		||||
        rate: rate,
 | 
			
		||||
        clientWidth: clientWidth,
 | 
			
		||||
        clientHeight: clientHeight,
 | 
			
		||||
        offsetWidth: offsetWidth,
 | 
			
		||||
        offsetHeight: offsetHeight,
 | 
			
		||||
        clientHeightFixed: clientHeightFixed,
 | 
			
		||||
        scrollTop: scrollTop,
 | 
			
		||||
        scrollLeft: scrollLeft,
 | 
			
		||||
      },
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  handleZoomClick = e => {
 | 
			
		||||
    e.preventDefault();
 | 
			
		||||
    e.stopPropagation();
 | 
			
		||||
 | 
			
		||||
    const { scale, zoomMatrix } = this.state;
 | 
			
		||||
 | 
			
		||||
    if ( scale >= zoomMatrix.rate ) {
 | 
			
		||||
      this.setState({ scale: MIN_SCALE }, () => {
 | 
			
		||||
        this.container.scrollLeft = 0;
 | 
			
		||||
        this.container.scrollTop = 0;
 | 
			
		||||
        this.setState({ lockScroll: {
 | 
			
		||||
          x: 0,
 | 
			
		||||
          y: 0,
 | 
			
		||||
        } });
 | 
			
		||||
      });
 | 
			
		||||
    } else {
 | 
			
		||||
      this.setState({ scale: zoomMatrix.rate }, () => {
 | 
			
		||||
        this.container.scrollLeft = zoomMatrix.scrollLeft;
 | 
			
		||||
        this.container.scrollTop = zoomMatrix.scrollTop;
 | 
			
		||||
        this.setState({ lockScroll: {
 | 
			
		||||
          x: zoomMatrix.scrollLeft,
 | 
			
		||||
          y: zoomMatrix.scrollTop,
 | 
			
		||||
        } });
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    this.container.style.cursor = 'grab';
 | 
			
		||||
    this.container.style.removeProperty('user-select');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  setContainerRef = c => {
 | 
			
		||||
@@ -123,29 +368,47 @@ export default class ZoomableImage extends React.PureComponent {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  render () {
 | 
			
		||||
    const { alt, src } = this.props;
 | 
			
		||||
    const { alt, src, width, height, intl } = this.props;
 | 
			
		||||
    const { scale } = this.state;
 | 
			
		||||
    const overflow = scale === 1 ? 'hidden' : 'scroll';
 | 
			
		||||
    const zoomButtonSshouldHide = !this.state.navigationHidden && !this.props.zoomButtonHidden ? '' : 'media-modal__zoom-button--hidden';
 | 
			
		||||
    const zoomButtonTitle = this.state.zoomState === 'compress' ? intl.formatMessage(messages.compress) : intl.formatMessage(messages.expand);
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
      <div
 | 
			
		||||
        className='zoomable-image'
 | 
			
		||||
        ref={this.setContainerRef}
 | 
			
		||||
        style={{ overflow }}
 | 
			
		||||
      >
 | 
			
		||||
        <img
 | 
			
		||||
          role='presentation'
 | 
			
		||||
          ref={this.setImageRef}
 | 
			
		||||
          alt={alt}
 | 
			
		||||
          title={alt}
 | 
			
		||||
          src={src}
 | 
			
		||||
      <React.Fragment>
 | 
			
		||||
        <IconButton
 | 
			
		||||
          className={`media-modal__zoom-button ${zoomButtonSshouldHide}`}
 | 
			
		||||
          title={zoomButtonTitle}
 | 
			
		||||
          icon={this.state.zoomState}
 | 
			
		||||
          onClick={this.handleZoomClick}
 | 
			
		||||
          size={40}
 | 
			
		||||
          style={{
 | 
			
		||||
            transform: `scale(${scale})`,
 | 
			
		||||
            transformOrigin: '0 0',
 | 
			
		||||
            fontSize: '30px', /* Fontawesome's fa-compress fa-expand is larger than fa-close */
 | 
			
		||||
          }}
 | 
			
		||||
          onClick={this.handleClick}
 | 
			
		||||
        />
 | 
			
		||||
      </div>
 | 
			
		||||
        <div
 | 
			
		||||
          className='zoomable-image'
 | 
			
		||||
          ref={this.setContainerRef}
 | 
			
		||||
          style={{ overflow }}
 | 
			
		||||
        >
 | 
			
		||||
          <img
 | 
			
		||||
            role='presentation'
 | 
			
		||||
            ref={this.setImageRef}
 | 
			
		||||
            alt={alt}
 | 
			
		||||
            title={alt}
 | 
			
		||||
            src={src}
 | 
			
		||||
            width={width}
 | 
			
		||||
            height={height}
 | 
			
		||||
            style={{
 | 
			
		||||
              transform: `scale(${scale})`,
 | 
			
		||||
              transformOrigin: '0 0',
 | 
			
		||||
            }}
 | 
			
		||||
            draggable={false}
 | 
			
		||||
            onClick={this.handleClick}
 | 
			
		||||
            onMouseDown={this.handleMouseDown}
 | 
			
		||||
          />
 | 
			
		||||
        </div>
 | 
			
		||||
      </React.Fragment>
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -425,6 +425,20 @@
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
  scrollbar-width: none; /* Firefox */
 | 
			
		||||
  -ms-overflow-style: none;  /* IE 10+ */
 | 
			
		||||
 | 
			
		||||
  * {
 | 
			
		||||
    scrollbar-width: none; /* Firefox */
 | 
			
		||||
    -ms-overflow-style: none;  /* IE 10+ */
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  &::-webkit-scrollbar,
 | 
			
		||||
  *::-webkit-scrollbar {
 | 
			
		||||
    width: 0;
 | 
			
		||||
    height: 0;
 | 
			
		||||
    background: transparent; /* Chrome/Safari/Webkit */
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .image-loader__preview-canvas {
 | 
			
		||||
    max-width: $media-modal-media-max-width;
 | 
			
		||||
 
 | 
			
		||||
@@ -40,6 +40,21 @@
 | 
			
		||||
  z-index: 9999;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.media-modal__zoom-button {
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  right: 64px;
 | 
			
		||||
  top: 8px;
 | 
			
		||||
  z-index: 100;
 | 
			
		||||
  pointer-events: auto;
 | 
			
		||||
  transition: opacity 0.3s linear;
 | 
			
		||||
  will-change: opacity;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.media-modal__zoom-button--hidden {
 | 
			
		||||
  pointer-events: none;
 | 
			
		||||
  opacity: 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.onboarding-modal,
 | 
			
		||||
.error-modal,
 | 
			
		||||
.embed-modal {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user