Replace Photoswipe react library (#10144)
This commit is contained in:
Родитель
c66b9138af
Коммит
0d752cc844
|
@ -8,8 +8,6 @@ module.exports = {
|
|||
moduleDirectories: ['src', 'node_modules'],
|
||||
moduleFileExtensions: ['js', 'json', 'jsx'],
|
||||
moduleNameMapper: {
|
||||
// Prevent un-transpiled react-photoswipe code being required.
|
||||
'^photoswipe$': '<rootDir>/node_modules/photoswipe',
|
||||
// Alias tests for tests to be able to import helpers.
|
||||
'^tests/(.*)$': '<rootDir>/tests/$1',
|
||||
// Replaces the following formats with an empty module.
|
||||
|
|
|
@ -186,6 +186,7 @@
|
|||
"nano-time": "1.0.0",
|
||||
"normalize.css": "8.0.1",
|
||||
"photon-colors": "3.3.2",
|
||||
"photoswipe": "4.1.3",
|
||||
"pino": "6.11.1",
|
||||
"pino-mozlog": "2.2.0",
|
||||
"prop-types": "15.7.2",
|
||||
|
@ -203,7 +204,7 @@
|
|||
"react-keydown": "1.9.12",
|
||||
"react-nested-status": "0.2.1",
|
||||
"react-onclickoutside": "6.10.0",
|
||||
"react-photoswipe": "1.3.0",
|
||||
"react-photoswipe-gallery": "1.3.4",
|
||||
"react-redux": "5.1.2",
|
||||
"react-router": "4.3.1",
|
||||
"react-router-dom": "4.3.1",
|
||||
|
|
|
@ -1,26 +1,13 @@
|
|||
/* @flow */
|
||||
/* global window */
|
||||
import invariant from 'invariant';
|
||||
import * as React from 'react';
|
||||
import { PhotoSwipeGallery } from 'react-photoswipe';
|
||||
import 'react-photoswipe/lib/photoswipe.css';
|
||||
import { Gallery, Item } from 'react-photoswipe-gallery';
|
||||
import 'photoswipe/dist/photoswipe.css';
|
||||
import 'photoswipe/dist/default-skin/default-skin.css';
|
||||
|
||||
import type { PreviewType } from 'amo/types/addons';
|
||||
import './styles.scss';
|
||||
|
||||
type ThumbBounds =
|
||||
| false
|
||||
| {|
|
||||
w: number,
|
||||
x: number,
|
||||
y: number,
|
||||
|};
|
||||
|
||||
type GetThumbBoundsExtraParams = {|
|
||||
_document: typeof document | null,
|
||||
_window: typeof window | null,
|
||||
|};
|
||||
|
||||
export const PHOTO_SWIPE_OPTIONS = {
|
||||
closeEl: true,
|
||||
captionEl: true,
|
||||
|
@ -30,67 +17,32 @@ export const PHOTO_SWIPE_OPTIONS = {
|
|||
counterEl: true,
|
||||
arrowEl: true,
|
||||
preloaderEl: true,
|
||||
// Overload getThumbBoundsFn as workaround to
|
||||
// https://github.com/minhtranite/react-photoswipe/issues/23
|
||||
getThumbBoundsFn: (
|
||||
index: number,
|
||||
{
|
||||
// $FlowFixMe: see https://github.com/facebook/flow/issues/183
|
||||
_document = typeof document !== 'undefined' ? document : null,
|
||||
_window = typeof window !== 'undefined' ? window : null,
|
||||
}: GetThumbBoundsExtraParams = {},
|
||||
): ThumbBounds => {
|
||||
if (!_document || !_window) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const thumbnail = _document.querySelectorAll('.pswp-thumbnails')[index];
|
||||
|
||||
if (thumbnail && thumbnail.getElementsByTagName) {
|
||||
const img = thumbnail.getElementsByTagName('img')[0];
|
||||
const pageYScroll =
|
||||
_window.pageYOffset ||
|
||||
(_document.documentElement ? _document.documentElement.scrollTop : 0);
|
||||
const rect = img.getBoundingClientRect();
|
||||
|
||||
return { x: rect.left, y: rect.top + pageYScroll, w: rect.width };
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
};
|
||||
|
||||
export const thumbnailContent = (item: PreviewType): React.Node => (
|
||||
<img
|
||||
alt={item.title}
|
||||
className="ScreenShots-image"
|
||||
height={item.thumbnail_h}
|
||||
src={item.thumbnail_src}
|
||||
title={item.title}
|
||||
width={item.thumbnail_w}
|
||||
/>
|
||||
);
|
||||
|
||||
type Props = {|
|
||||
previews: Array<PreviewType>,
|
||||
|};
|
||||
|
||||
export default class ScreenShots extends React.Component<Props> {
|
||||
onClose = (photoswipe: Object) => {
|
||||
const index = photoswipe.getCurrentIndex();
|
||||
viewport: HTMLElement | null;
|
||||
|
||||
onOpenPhotoswipe = (photoswipe: Object) => {
|
||||
invariant(this.viewport, 'viewport ref is required');
|
||||
|
||||
const list = this.viewport.querySelector('.pswp-thumbnails');
|
||||
|
||||
const list = this.viewport.querySelector('.ScreenShots-list');
|
||||
invariant(list, 'list is required');
|
||||
|
||||
const currentItem = list.children[index];
|
||||
const offset = currentItem.getBoundingClientRect().left;
|
||||
list.scrollLeft += offset - list.getBoundingClientRect().left;
|
||||
};
|
||||
// This is used to update the horizontal list of thumbnails in order to
|
||||
// show the last image displayed in fullscreen mode when we close the
|
||||
// carousel.
|
||||
photoswipe.listen('close', () => {
|
||||
const index = photoswipe.getCurrentIndex();
|
||||
const currentItem = list.children[index];
|
||||
const offset = currentItem.getBoundingClientRect().left;
|
||||
|
||||
viewport: HTMLElement | null;
|
||||
list.scrollLeft += offset - list.getBoundingClientRect().left;
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const { previews } = this.props;
|
||||
|
@ -103,13 +55,36 @@ export default class ScreenShots extends React.Component<Props> {
|
|||
this.viewport = el;
|
||||
}}
|
||||
>
|
||||
<PhotoSwipeGallery
|
||||
className="ScreenShots-list"
|
||||
close={this.onClose}
|
||||
items={previews}
|
||||
options={PHOTO_SWIPE_OPTIONS}
|
||||
thumbnailContent={thumbnailContent}
|
||||
/>
|
||||
<div className="ScreenShots-list">
|
||||
<Gallery
|
||||
options={PHOTO_SWIPE_OPTIONS}
|
||||
onOpen={this.onOpenPhotoswipe}
|
||||
>
|
||||
{previews.map((preview) => (
|
||||
<Item
|
||||
key={preview.src}
|
||||
original={preview.src}
|
||||
thumbnail={preview.thumbnail_src}
|
||||
width={preview.w}
|
||||
height={preview.h}
|
||||
title={preview.title}
|
||||
>
|
||||
{({ ref, open }) => (
|
||||
// eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-noninteractive-element-interactions
|
||||
<img
|
||||
alt={preview.title}
|
||||
className="ScreenShots-image"
|
||||
ref={ref}
|
||||
onClick={open}
|
||||
src={preview.thumbnail_src}
|
||||
width={preview.thumbnail_w}
|
||||
height={preview.thumbnail_h}
|
||||
/>
|
||||
)}
|
||||
</Item>
|
||||
))}
|
||||
</Gallery>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -7,10 +7,6 @@ $image-height: $screenshot-height - 20px;
|
|||
$screenshot-width: 320px;
|
||||
|
||||
.ScreenShots {
|
||||
.pswp-thumbnails {
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
.pswp__caption__center {
|
||||
text-align: center;
|
||||
}
|
||||
|
@ -20,9 +16,10 @@ $screenshot-width: 320px;
|
|||
height: $screenshot-height;
|
||||
}
|
||||
|
||||
.ScreenShots-list .pswp-thumbnails {
|
||||
.ScreenShots-list {
|
||||
display: flex;
|
||||
height: $screenshot-height;
|
||||
line-height: 0;
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
overflow-x: scroll;
|
||||
|
@ -31,20 +28,16 @@ $screenshot-width: 320px;
|
|||
width: auto;
|
||||
}
|
||||
|
||||
.ScreenShots-list .pswp-thumbnail {
|
||||
display: inline-block;
|
||||
margin: 0 10px;
|
||||
|
||||
&:first-of-type {
|
||||
@include margin-start(0);
|
||||
}
|
||||
}
|
||||
|
||||
.ScreenShots-image {
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
height: $image-height;
|
||||
margin: 0 10px;
|
||||
width: $screenshot-width;
|
||||
|
||||
&:first-of-type {
|
||||
@include margin-start(0);
|
||||
}
|
||||
}
|
||||
|
||||
// Don't stretch the images.
|
||||
|
|
|
@ -1,11 +1,8 @@
|
|||
import { shallow, mount } from 'enzyme';
|
||||
import * as React from 'react';
|
||||
import { PhotoSwipeGallery } from 'react-photoswipe';
|
||||
import { Gallery, Item } from 'react-photoswipe-gallery';
|
||||
|
||||
import ScreenShots, {
|
||||
PHOTO_SWIPE_OPTIONS,
|
||||
thumbnailContent,
|
||||
} from 'amo/components/ScreenShots';
|
||||
import ScreenShots, { PHOTO_SWIPE_OPTIONS } from 'amo/components/ScreenShots';
|
||||
|
||||
const HEIGHT = 400;
|
||||
const WIDTH = 200;
|
||||
|
@ -34,36 +31,26 @@ describe(__filename, () => {
|
|||
|
||||
it('renders the previews', () => {
|
||||
const root = shallow(<ScreenShots previews={previews} />);
|
||||
const gallery = root.children().children();
|
||||
|
||||
expect(gallery.type()).toEqual(PhotoSwipeGallery);
|
||||
expect(gallery.prop('items')).toEqual(previews);
|
||||
expect(gallery.prop('thumbnailContent')).toEqual(thumbnailContent);
|
||||
});
|
||||
expect(root.find(Gallery)).toHaveLength(1);
|
||||
expect(root.find(Gallery)).toHaveProp('options', PHOTO_SWIPE_OPTIONS);
|
||||
expect(root.find(Item)).toHaveLength(previews.length);
|
||||
|
||||
it('renders custom thumbnail', () => {
|
||||
const thumbnailSrc = 'http://example.com/thumbnail.png';
|
||||
const thumbnailHeight = 123;
|
||||
const thumbnailWidth = 200;
|
||||
previews.forEach((preview, index) => {
|
||||
const item = root.find(Item).at(index);
|
||||
expect(item).toHaveProp('original', preview.src);
|
||||
expect(item).toHaveProp('thumbnail', preview.thumbnail_src);
|
||||
expect(item).toHaveProp('width', preview.w);
|
||||
expect(item).toHaveProp('height', preview.h);
|
||||
expect(item).toHaveProp('title', preview.title);
|
||||
|
||||
const item = {
|
||||
src: 'https://foo.com/img.png',
|
||||
title: 'test title',
|
||||
h: HEIGHT,
|
||||
w: WIDTH,
|
||||
thumbnail_src: thumbnailSrc,
|
||||
thumbnail_h: thumbnailHeight,
|
||||
thumbnail_w: thumbnailWidth,
|
||||
};
|
||||
|
||||
const thumbnail = shallow(thumbnailContent(item));
|
||||
|
||||
expect(thumbnail.type()).toEqual('img');
|
||||
expect(thumbnail.prop('src')).toEqual(thumbnailSrc);
|
||||
expect(thumbnail.prop('height')).toEqual(thumbnailHeight);
|
||||
expect(thumbnail.prop('width')).toEqual(thumbnailWidth);
|
||||
expect(thumbnail.prop('alt')).toEqual('test title');
|
||||
expect(thumbnail.prop('title')).toEqual('test title');
|
||||
const image = item.shallow();
|
||||
expect(image.type()).toEqual('img');
|
||||
expect(image).toHaveProp('src', preview.thumbnail_src);
|
||||
expect(image).toHaveProp('width', preview.thumbnail_w);
|
||||
expect(image).toHaveProp('height', preview.thumbnail_h);
|
||||
expect(image).toHaveProp('alt', preview.title);
|
||||
});
|
||||
});
|
||||
|
||||
it('scrolls to the active item on close', () => {
|
||||
|
@ -83,114 +70,12 @@ describe(__filename, () => {
|
|||
};
|
||||
sinon.stub(root.instance().viewport, 'querySelector').returns(list);
|
||||
|
||||
const photoswipe = { getCurrentIndex: () => 1 };
|
||||
root.instance().onClose(photoswipe);
|
||||
const fakePhotoswipe = {
|
||||
getCurrentIndex: () => 1,
|
||||
listen: (event, callback) => callback(),
|
||||
};
|
||||
root.instance().onOpenPhotoswipe(fakePhotoswipe);
|
||||
// 0 += 500 - 55
|
||||
expect(list.scrollLeft).toEqual(445);
|
||||
});
|
||||
|
||||
describe('PHOTO_SWIPE_OPTIONS.getThumbBoundsFn', () => {
|
||||
const { getThumbBoundsFn } = PHOTO_SWIPE_OPTIONS;
|
||||
|
||||
const getFakeDocument = ({ left, top, width }) => {
|
||||
const fakeImg = {
|
||||
getBoundingClientRect: () => ({
|
||||
height: 123,
|
||||
left,
|
||||
top,
|
||||
width,
|
||||
}),
|
||||
};
|
||||
|
||||
const fakeThumbnail = {
|
||||
getElementsByTagName: () => [fakeImg],
|
||||
};
|
||||
|
||||
const fakeDocument = {
|
||||
querySelectorAll: () => [fakeThumbnail],
|
||||
};
|
||||
|
||||
return fakeDocument;
|
||||
};
|
||||
|
||||
it('returns false if thumbnail does not exist', () => {
|
||||
const bounds = getThumbBoundsFn(0);
|
||||
|
||||
expect(bounds).toEqual(false);
|
||||
});
|
||||
|
||||
it('returns false if _document is null', () => {
|
||||
const bounds = getThumbBoundsFn(0, { _document: null });
|
||||
|
||||
expect(bounds).toEqual(false);
|
||||
});
|
||||
|
||||
it('returns false if _window is null', () => {
|
||||
const bounds = getThumbBoundsFn(0, {
|
||||
_document: getFakeDocument({ left: 1, top: 2, width: 3 }),
|
||||
_window: null,
|
||||
});
|
||||
|
||||
expect(bounds).toEqual(false);
|
||||
});
|
||||
|
||||
it('returns an object with x, y and w values', () => {
|
||||
const left = 123;
|
||||
const top = 124;
|
||||
const width = 100;
|
||||
|
||||
const fakeDocument = getFakeDocument({ left, top, width });
|
||||
|
||||
const bounds = getThumbBoundsFn(0, { _document: fakeDocument });
|
||||
|
||||
expect(bounds).toEqual({
|
||||
w: width,
|
||||
x: left,
|
||||
y: top,
|
||||
});
|
||||
});
|
||||
|
||||
it('uses window.pageYOffset to compute `y` if available', () => {
|
||||
const left = 123;
|
||||
const top = 124;
|
||||
const width = 100;
|
||||
|
||||
const fakeDocument = getFakeDocument({ left, top, width });
|
||||
|
||||
const fakeWindow = {
|
||||
pageYOffset: 20,
|
||||
};
|
||||
|
||||
const bounds = getThumbBoundsFn(0, {
|
||||
_document: fakeDocument,
|
||||
_window: fakeWindow,
|
||||
});
|
||||
|
||||
expect(bounds).toEqual({
|
||||
w: width,
|
||||
x: left,
|
||||
y: top + fakeWindow.pageYOffset,
|
||||
});
|
||||
});
|
||||
|
||||
it('uses document.documentElement.scrollTop to compute `y` if available', () => {
|
||||
const left = 123;
|
||||
const top = 124;
|
||||
const width = 100;
|
||||
const scrollTop = 30;
|
||||
|
||||
const fakeDocument = getFakeDocument({ left, top, width });
|
||||
fakeDocument.documentElement = {
|
||||
scrollTop,
|
||||
};
|
||||
|
||||
const bounds = getThumbBoundsFn(0, { _document: fakeDocument });
|
||||
|
||||
expect(bounds).toEqual({
|
||||
w: width,
|
||||
x: left,
|
||||
y: top + scrollTop,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
24
yarn.lock
24
yarn.lock
|
@ -3355,7 +3355,7 @@ class-utils@^0.3.5:
|
|||
isobject "^3.0.0"
|
||||
static-extend "^0.1.1"
|
||||
|
||||
classnames@2.2.6, classnames@2.x, classnames@^2.2.1, classnames@^2.2.3, classnames@^2.2.6:
|
||||
classnames@2.2.6, classnames@2.x, classnames@^2.2.1, classnames@^2.2.6:
|
||||
version "2.2.6"
|
||||
resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.6.tgz#43935bffdd291f326dad0a205309b38d00f650ce"
|
||||
integrity sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q==
|
||||
|
@ -8192,11 +8192,6 @@ lodash.memoize@^4.1.2:
|
|||
resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
|
||||
integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=
|
||||
|
||||
lodash.pick@^4.2.1:
|
||||
version "4.4.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3"
|
||||
integrity sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM=
|
||||
|
||||
lodash.sortby@^4.7.0:
|
||||
version "4.7.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438"
|
||||
|
@ -9771,7 +9766,7 @@ photon-colors@3.3.2:
|
|||
resolved "https://registry.yarnpkg.com/photon-colors/-/photon-colors-3.3.2.tgz#eaf2e5a8ba9368fcdee0607cc86a9f613e6d3417"
|
||||
integrity sha512-xCeL7J2F8cjM00zQZEZawHAGnrSOM509RbanL4c8hvrV8n19V/wwdzydX6rSUEtLYj4nx4OvhmKC4/vujo9f/Q==
|
||||
|
||||
photoswipe@^4.1.0:
|
||||
photoswipe@4.1.3:
|
||||
version "4.1.3"
|
||||
resolved "https://registry.yarnpkg.com/photoswipe/-/photoswipe-4.1.3.tgz#59f49494eeb9ddab5888d03392926a19bc197550"
|
||||
integrity sha512-89Z43IRUyw7ycTolo+AaiDn3W1EEIfox54hERmm9bI12IB9cvRfHSHez3XhAyU8XW2EAFrC+2sKMhh7SJwn0bA==
|
||||
|
@ -10521,7 +10516,7 @@ prop-types-exact@^1.2.0:
|
|||
object.assign "^4.1.0"
|
||||
reflect.ownkeys "^0.2.0"
|
||||
|
||||
prop-types@15.7.2, prop-types@^15.5.10, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2:
|
||||
prop-types@15.7.2, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2:
|
||||
version "15.7.2"
|
||||
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
|
||||
integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
|
||||
|
@ -10888,15 +10883,10 @@ react-onclickoutside@6.10.0:
|
|||
resolved "https://registry.yarnpkg.com/react-onclickoutside/-/react-onclickoutside-6.10.0.tgz#05abb592575b08b4d129003494056b9dff46eeeb"
|
||||
integrity sha512-7i2L3ef+0ILXpL6P+Hg304eCQswh4jl3ynwR71BSlMU49PE2uk31k8B2GkP6yE9s2D4jTGKnzuSpzWxu4YxfQQ==
|
||||
|
||||
react-photoswipe@1.3.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/react-photoswipe/-/react-photoswipe-1.3.0.tgz#016dd978450a8406776db97511eaf96f2ffb9cfb"
|
||||
integrity sha512-1ok6vXFAj/rd60KIzF0YwCdq1Tcl+8yKqWJHbPo43lJBuwUi+LBosmBdJmswpiOzMn2496ekU0k/r6aHWQk7PQ==
|
||||
dependencies:
|
||||
classnames "^2.2.3"
|
||||
lodash.pick "^4.2.1"
|
||||
photoswipe "^4.1.0"
|
||||
prop-types "^15.5.10"
|
||||
react-photoswipe-gallery@1.3.4:
|
||||
version "1.3.4"
|
||||
resolved "https://registry.yarnpkg.com/react-photoswipe-gallery/-/react-photoswipe-gallery-1.3.4.tgz#770f82ae7afb3acf4cdc27d08db7a978555b4b3e"
|
||||
integrity sha512-PiKGQTWHMORlMgEI32e8nMpVBKZeTJv378x4Jom9Dl68HPZdKadEQPcgVkiVPoRqvv0ynHNvFdUehzpQqe8SXw==
|
||||
|
||||
react-redux@5.1.2:
|
||||
version "5.1.2"
|
||||
|
|
Загрузка…
Ссылка в новой задаче