diff --git a/app/javascript/mastodon/containers/media_container.jsx b/app/javascript/mastodon/containers/media_container.jsx
index a4f79fcf94c..08e106e5d89 100644
--- a/app/javascript/mastodon/containers/media_container.jsx
+++ b/app/javascript/mastodon/containers/media_container.jsx
@@ -10,7 +10,7 @@ import ModalRoot from 'mastodon/components/modal_root';
import { Poll } from 'mastodon/components/poll';
import { Audio } from 'mastodon/features/audio';
import Card from 'mastodon/features/status/components/card';
-import MediaModal from 'mastodon/features/ui/components/media_modal';
+import { MediaModal } from 'mastodon/features/ui/components/media_modal';
import { Video } from 'mastodon/features/video';
import { IntlProvider } from 'mastodon/locales';
import { createPollFromServerJSON } from 'mastodon/models/poll';
diff --git a/app/javascript/mastodon/features/ui/components/media_modal.jsx b/app/javascript/mastodon/features/ui/components/media_modal.jsx
deleted file mode 100644
index 2ce13bf1d39..00000000000
--- a/app/javascript/mastodon/features/ui/components/media_modal.jsx
+++ /dev/null
@@ -1,296 +0,0 @@
-import PropTypes from 'prop-types';
-
-import { defineMessages, injectIntl } from 'react-intl';
-
-import classNames from 'classnames';
-
-import ImmutablePropTypes from 'react-immutable-proptypes';
-import ImmutablePureComponent from 'react-immutable-pure-component';
-
-import ReactSwipeableViews from 'react-swipeable-views';
-
-import ChevronLeftIcon from '@/material-icons/400-24px/chevron_left.svg?react';
-import ChevronRightIcon from '@/material-icons/400-24px/chevron_right.svg?react';
-import CloseIcon from '@/material-icons/400-24px/close.svg?react';
-import FitScreenIcon from '@/material-icons/400-24px/fit_screen.svg?react';
-import ActualSizeIcon from '@/svg-icons/actual_size.svg?react';
-import { getAverageFromBlurhash } from 'mastodon/blurhash';
-import { GIFV } from 'mastodon/components/gifv';
-import { Icon } from 'mastodon/components/icon';
-import { IconButton } from 'mastodon/components/icon_button';
-import { Footer } from 'mastodon/features/picture_in_picture/components/footer';
-import { Video } from 'mastodon/features/video';
-import { disableSwiping } from 'mastodon/initial_state';
-
-import { ZoomableImage } from './zoomable_image';
-
-const messages = defineMessages({
- close: { id: 'lightbox.close', defaultMessage: 'Close' },
- previous: { id: 'lightbox.previous', defaultMessage: 'Previous' },
- next: { id: 'lightbox.next', defaultMessage: 'Next' },
- zoomIn: { id: 'lightbox.zoom_in', defaultMessage: 'Zoom to actual size' },
- zoomOut: { id: 'lightbox.zoom_out', defaultMessage: 'Zoom to fit' },
-});
-
-class MediaModal extends ImmutablePureComponent {
-
- static propTypes = {
- media: ImmutablePropTypes.list.isRequired,
- statusId: PropTypes.string,
- lang: PropTypes.string,
- index: PropTypes.number.isRequired,
- onClose: PropTypes.func.isRequired,
- intl: PropTypes.object.isRequired,
- onChangeBackgroundColor: PropTypes.func.isRequired,
- currentTime: PropTypes.number,
- autoPlay: PropTypes.bool,
- volume: PropTypes.number,
- };
-
- state = {
- index: null,
- navigationHidden: false,
- zoomedIn: false,
- };
-
- handleZoomClick = () => {
- this.setState(prevState => ({
- zoomedIn: !prevState.zoomedIn,
- }));
- };
-
- handleZoomChange = (zoomedIn) => {
- this.setState({
- zoomedIn,
- });
- };
-
- handleSwipe = (index) => {
- this.setState({
- index: index % this.props.media.size,
- zoomedIn: false,
- });
- };
-
- handleTransitionEnd = () => {
- this.setState({
- zoomedIn: false,
- });
- };
-
- handleNextClick = () => {
- this.setState({
- index: (this.getIndex() + 1) % this.props.media.size,
- zoomedIn: false,
- });
- };
-
- handlePrevClick = () => {
- this.setState({
- index: (this.props.media.size + this.getIndex() - 1) % this.props.media.size,
- zoomedIn: false,
- });
- };
-
- handleChangeIndex = (e) => {
- const index = Number(e.currentTarget.getAttribute('data-index'));
-
- this.setState({
- index: index % this.props.media.size,
- zoomedIn: false,
- });
- };
-
- handleKeyDown = (e) => {
- switch(e.key) {
- case 'ArrowLeft':
- this.handlePrevClick();
- e.preventDefault();
- e.stopPropagation();
- break;
- case 'ArrowRight':
- this.handleNextClick();
- e.preventDefault();
- e.stopPropagation();
- break;
- }
- };
-
- componentDidMount () {
- window.addEventListener('keydown', this.handleKeyDown, false);
-
- this._sendBackgroundColor();
- }
-
- componentDidUpdate (prevProps, prevState) {
- if (prevState.index !== this.state.index) {
- this._sendBackgroundColor();
- }
- }
-
- _sendBackgroundColor () {
- const { media, onChangeBackgroundColor } = this.props;
- const index = this.getIndex();
- const blurhash = media.getIn([index, 'blurhash']);
-
- if (blurhash) {
- const backgroundColor = getAverageFromBlurhash(blurhash);
- onChangeBackgroundColor(backgroundColor);
- }
- }
-
- componentWillUnmount () {
- window.removeEventListener('keydown', this.handleKeyDown);
-
- this.props.onChangeBackgroundColor(null);
- }
-
- getIndex () {
- return this.state.index !== null ? this.state.index : this.props.index;
- }
-
- handleToggleNavigation = () => {
- this.setState(prevState => ({
- navigationHidden: !prevState.navigationHidden,
- }));
- };
-
- setRef = c => {
- this.setState({
- viewportWidth: c?.clientWidth,
- viewportHeight: c?.clientHeight,
- });
- };
-
- render () {
- const { media, statusId, lang, intl, onClose } = this.props;
- const { navigationHidden, zoomedIn, viewportWidth, viewportHeight } = this.state;
-
- const index = this.getIndex();
-
- const leftNav = media.size > 1 && ;
- const rightNav = media.size > 1 && ;
-
- const content = media.map((image, idx) => {
- const width = image.getIn(['meta', 'original', 'width']) || null;
- const height = image.getIn(['meta', 'original', 'height']) || null;
- const description = image.getIn(['translation', 'description']) || image.get('description');
-
- if (image.get('type') === 'image') {
- return (
-
- );
- } else if (image.get('type') === 'video') {
- const { currentTime, autoPlay, volume } = this.props;
-
- return (
-
- );
- } else if (image.get('type') === 'gifv') {
- return (
-
- );
- }
-
- return null;
- }).toArray();
-
- // you can't use 100vh, because the viewport height is taller
- // than the visible part of the document in some mobile
- // browsers when it's address bar is visible.
- // https://developers.google.com/web/updates/2016/12/url-bar-resizing
- const swipeableViewsStyle = {
- width: '100%',
- height: '100%',
- };
-
- const containerStyle = {
- alignItems: 'center', // center vertically
- };
-
- const navigationClassName = classNames('media-modal__navigation', {
- 'media-modal__navigation--hidden': navigationHidden,
- });
-
- let pagination;
-
- if (media.size > 1) {
- pagination = media.map((item, i) => (
-
- ));
- }
-
- const currentMedia = media.get(index);
- const zoomable = currentMedia.get('type') === 'image' && (currentMedia.getIn(['meta', 'original', 'width']) > viewportWidth || currentMedia.getIn(['meta', 'original', 'height']) > viewportHeight);
-
- return (
-
-
-
- {content}
-
-
-
-
-
- {zoomable && }
-
-
-
- {leftNav}
- {rightNav}
-
-
- {pagination &&
}
- {statusId &&
}
-
-
-
- );
- }
-
-}
-
-export default injectIntl(MediaModal);
diff --git a/app/javascript/mastodon/features/ui/components/media_modal.tsx b/app/javascript/mastodon/features/ui/components/media_modal.tsx
new file mode 100644
index 00000000000..d1203552ea7
--- /dev/null
+++ b/app/javascript/mastodon/features/ui/components/media_modal.tsx
@@ -0,0 +1,363 @@
+import { forwardRef, useCallback, useEffect, useMemo, useState } from 'react';
+import type { RefCallback, FC } from 'react';
+
+import { defineMessages, useIntl } from 'react-intl';
+
+import classNames from 'classnames';
+
+import type { List as ImmutableList } from 'immutable';
+
+import { animated, useSpring } from '@react-spring/web';
+import { useDrag } from '@use-gesture/react';
+
+import type { MediaAttachment } from '@/mastodon/models/status';
+import ChevronLeftIcon from '@/material-icons/400-24px/chevron_left.svg?react';
+import ChevronRightIcon from '@/material-icons/400-24px/chevron_right.svg?react';
+import CloseIcon from '@/material-icons/400-24px/close.svg?react';
+import FitScreenIcon from '@/material-icons/400-24px/fit_screen.svg?react';
+import ActualSizeIcon from '@/svg-icons/actual_size.svg?react';
+import type { RGB } from 'mastodon/blurhash';
+import { getAverageFromBlurhash } from 'mastodon/blurhash';
+import { GIFV } from 'mastodon/components/gifv';
+import { Icon } from 'mastodon/components/icon';
+import { IconButton } from 'mastodon/components/icon_button';
+import { Footer } from 'mastodon/features/picture_in_picture/components/footer';
+import { Video } from 'mastodon/features/video';
+
+import { ZoomableImage } from './zoomable_image';
+
+const messages = defineMessages({
+ close: { id: 'lightbox.close', defaultMessage: 'Close' },
+ previous: { id: 'lightbox.previous', defaultMessage: 'Previous' },
+ next: { id: 'lightbox.next', defaultMessage: 'Next' },
+ zoomIn: { id: 'lightbox.zoom_in', defaultMessage: 'Zoom to actual size' },
+ zoomOut: { id: 'lightbox.zoom_out', defaultMessage: 'Zoom to fit' },
+});
+
+interface MediaModalProps {
+ media: ImmutableList;
+ statusId?: string;
+ lang?: string;
+ index: number;
+ onClose: () => void;
+ onChangeBackgroundColor: (color: RGB | null) => void;
+ currentTime?: number;
+ autoPlay?: boolean;
+ volume?: number;
+}
+
+export const MediaModal: FC = forwardRef<
+ HTMLDivElement,
+ MediaModalProps
+>(
+ (
+ {
+ media,
+ onClose,
+ index: startIndex,
+ lang,
+ currentTime,
+ autoPlay,
+ volume,
+ statusId,
+ onChangeBackgroundColor,
+ },
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars -- _ref is required to keep the ref forwarding working
+ _ref,
+ ) => {
+ const [index, setIndex] = useState(startIndex);
+ const currentMedia = media.get(index);
+
+ const handleChangeIndex = useCallback(
+ (newIndex: number) => {
+ if (newIndex < 0) {
+ newIndex = media.size + newIndex;
+ }
+ setIndex(newIndex % media.size);
+ setZoomedIn(false);
+ },
+ [media.size],
+ );
+ const handlePrevClick = useCallback(() => {
+ handleChangeIndex(index - 1);
+ }, [handleChangeIndex, index]);
+ const handleNextClick = useCallback(() => {
+ handleChangeIndex(index + 1);
+ }, [handleChangeIndex, index]);
+
+ const handleKeyDown = useCallback(
+ (event: KeyboardEvent) => {
+ if (event.key === 'ArrowLeft') {
+ handlePrevClick();
+ event.preventDefault();
+ event.stopPropagation();
+ } else if (event.key === 'ArrowRight') {
+ handleNextClick();
+ event.preventDefault();
+ event.stopPropagation();
+ }
+ },
+ [handleNextClick, handlePrevClick],
+ );
+
+ useEffect(() => {
+ window.addEventListener('keydown', handleKeyDown, false);
+
+ return () => {
+ window.removeEventListener('keydown', handleKeyDown);
+ };
+ }, [handleKeyDown]);
+
+ useEffect(() => {
+ const blurhash = currentMedia?.get('blurhash') as string | undefined;
+ if (blurhash) {
+ const backgroundColor = getAverageFromBlurhash(blurhash);
+ if (backgroundColor) {
+ onChangeBackgroundColor(backgroundColor);
+ }
+ }
+ }, [currentMedia, onChangeBackgroundColor]);
+
+ const [viewportDimensions, setViewportDimensions] = useState<{
+ width: number;
+ height: number;
+ }>({ width: 0, height: 0 });
+ const handleRef: RefCallback = useCallback((ele) => {
+ if (ele?.clientWidth && ele.clientHeight) {
+ setViewportDimensions({
+ width: ele.clientWidth,
+ height: ele.clientHeight,
+ });
+ }
+ }, []);
+
+ const [zoomedIn, setZoomedIn] = useState(false);
+ const zoomable =
+ currentMedia?.get('type') === 'image' &&
+ ((currentMedia.getIn(['meta', 'original', 'width']) as number) >
+ viewportDimensions.width ||
+ (currentMedia.getIn(['meta', 'original', 'height']) as number) >
+ viewportDimensions.height);
+ const handleZoomClick = useCallback(() => {
+ setZoomedIn((prev) => !prev);
+ }, []);
+
+ const wrapperStyles = useSpring({
+ x: `-${index * 100}%`,
+ });
+ const bind = useDrag(
+ ({ swipe: [swipeX] }) => {
+ if (swipeX === 0) return;
+ handleChangeIndex(index + swipeX * -1); // Invert swipe as swiping left loads the next slide.
+ },
+ { pointer: { capture: false } },
+ );
+
+ const [navigationHidden, setNavigationHidden] = useState(false);
+ const handleToggleNavigation = useCallback(() => {
+ setNavigationHidden((prev) => !prev);
+ }, []);
+
+ const content = useMemo(
+ () =>
+ media.map((item, idx) => {
+ const url = item.get('url') as string;
+ const blurhash = item.get('blurhash') as string;
+ const width = item.getIn(['meta', 'original', 'width'], 0) as number;
+ const height = item.getIn(
+ ['meta', 'original', 'height'],
+ 0,
+ ) as number;
+ const description = item.getIn(
+ ['translation', 'description'],
+ item.get('description'),
+ ) as string;
+ if (item.get('type') === 'image') {
+ return (
+
+ );
+ } else if (item.get('type') === 'video') {
+ return (
+
+ );
+ } else if (item.get('type') === 'gifv') {
+ return (
+
+ );
+ }
+
+ return null;
+ }),
+ [
+ autoPlay,
+ currentTime,
+ handleToggleNavigation,
+ handleZoomClick,
+ index,
+ lang,
+ media,
+ onClose,
+ volume,
+ zoomedIn,
+ ],
+ );
+
+ const intl = useIntl();
+
+ const leftNav = media.size > 1 && (
+
+ );
+ const rightNav = media.size > 1 && (
+
+ );
+
+ return (
+
+
+ {content}
+
+
+
+
+ {zoomable && (
+
+ )}
+
+
+
+ {leftNav}
+ {rightNav}
+
+
+
+ {statusId && (
+
+ )}
+
+
+
+ );
+ },
+);
+MediaModal.displayName = 'MediaModal';
+
+interface MediaPaginationProps {
+ itemsCount: number;
+ index: number;
+ onChangeIndex: (newIndex: number) => void;
+}
+
+const MediaPagination: FC = ({
+ itemsCount,
+ index,
+ onChangeIndex,
+}) => {
+ const handleChangeIndex = useCallback(
+ (curIndex: number) => {
+ return () => {
+ onChangeIndex(curIndex);
+ };
+ },
+ [onChangeIndex],
+ );
+
+ if (itemsCount <= 1) {
+ return null;
+ }
+
+ return (
+
+ {Array.from({ length: itemsCount }).map((_, i) => (
+
+ ))}
+
+ );
+};
diff --git a/app/javascript/mastodon/features/ui/components/modal_root.jsx b/app/javascript/mastodon/features/ui/components/modal_root.jsx
index 944feb325e9..8d9ac55a57c 100644
--- a/app/javascript/mastodon/features/ui/components/modal_root.jsx
+++ b/app/javascript/mastodon/features/ui/components/modal_root.jsx
@@ -43,7 +43,7 @@ import {
QuietPostQuoteInfoModal,
} from './confirmation_modals';
import { ImageModal } from './image_modal';
-import MediaModal from './media_modal';
+import { MediaModal } from './media_modal';
import { ModalPlaceholder } from './modal_placeholder';
import VideoModal from './video_modal';
import { VisibilityModal } from './visibility_modal';
diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss
index 5f71676ee4d..f1ea5e98ed7 100644
--- a/app/javascript/styles/mastodon/components.scss
+++ b/app/javascript/styles/mastodon/components.scss
@@ -2685,6 +2685,7 @@ a.account__display-name {
outline-offset: -1px;
border-radius: 8px;
touch-action: none;
+ user-select: none;
}
&--zoomed-in {
@@ -6096,6 +6097,7 @@ a.status-card {
width: 100%;
height: 100%;
position: relative;
+ touch-action: pan-y;
&__buttons {
position: absolute;
@@ -6131,11 +6133,17 @@ a.status-card {
}
.media-modal__closer {
+ display: flex;
position: absolute;
top: 0;
inset-inline-start: 0;
inset-inline-end: 0;
bottom: 0;
+
+ > div {
+ flex-shrink: 0;
+ overflow: auto;
+ }
}
.media-modal__navigation {
diff --git a/package.json b/package.json
index 0bd06c90215..4a5b28710ea 100644
--- a/package.json
+++ b/package.json
@@ -101,7 +101,6 @@
"react-router-dom": "^5.3.4",
"react-select": "^5.7.3",
"react-sparklines": "^1.7.0",
- "react-swipeable-views": "^0.14.0",
"react-textarea-autosize": "^8.4.1",
"react-toggle": "^4.1.3",
"redux-immutable": "^4.0.0",
@@ -158,7 +157,6 @@
"@types/react-router": "^5.1.20",
"@types/react-router-dom": "^5.3.3",
"@types/react-sparklines": "^1.7.2",
- "@types/react-swipeable-views": "^0.13.1",
"@types/react-test-renderer": "^18.0.0",
"@types/react-toggle": "^4.0.3",
"@types/redux-immutable": "^4.0.3",
diff --git a/yarn.lock b/yarn.lock
index d0964d13085..3279a22a0a0 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1174,16 +1174,7 @@ __metadata:
languageName: node
linkType: hard
-"@babel/runtime@npm:7.0.0":
- version: 7.0.0
- resolution: "@babel/runtime@npm:7.0.0"
- dependencies:
- regenerator-runtime: "npm:^0.12.0"
- checksum: 10c0/fbbdf86380a1cfa6ce32a743549f4e4c8b8eb06a18be5054441cc0f66e75a747ae43b042d8989f4657027e1be3b9a82069865ccc5080838f004abd1161093742
- languageName: node
- linkType: hard
-
-"@babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.0, @babel/runtime@npm:^7.12.13, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.13.8, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.2.0, @babel/runtime@npm:^7.20.13, @babel/runtime@npm:^7.3.1, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.6.3, @babel/runtime@npm:^7.8.7, @babel/runtime@npm:^7.9.2":
+"@babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.0, @babel/runtime@npm:^7.12.13, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.13.8, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.20.13, @babel/runtime@npm:^7.3.1, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.6.3, @babel/runtime@npm:^7.8.7, @babel/runtime@npm:^7.9.2":
version: 7.27.0
resolution: "@babel/runtime@npm:7.27.0"
dependencies:
@@ -2827,7 +2818,6 @@ __metadata:
"@types/react-router": "npm:^5.1.20"
"@types/react-router-dom": "npm:^5.3.3"
"@types/react-sparklines": "npm:^1.7.2"
- "@types/react-swipeable-views": "npm:^0.13.1"
"@types/react-test-renderer": "npm:^18.0.0"
"@types/react-toggle": "npm:^4.0.3"
"@types/redux-immutable": "npm:^4.0.3"
@@ -2905,7 +2895,6 @@ __metadata:
react-router-dom: "npm:^5.3.4"
react-select: "npm:^5.7.3"
react-sparklines: "npm:^1.7.0"
- react-swipeable-views: "npm:^0.14.0"
react-test-renderer: "npm:^18.2.0"
react-textarea-autosize: "npm:^8.4.1"
react-toggle: "npm:^4.1.3"
@@ -4484,15 +4473,6 @@ __metadata:
languageName: node
linkType: hard
-"@types/react-swipeable-views@npm:^0.13.1":
- version: 0.13.6
- resolution: "@types/react-swipeable-views@npm:0.13.6"
- dependencies:
- "@types/react": "npm:*"
- checksum: 10c0/a26879146748417234bb7f44c5a71e6bab2b76c0b34c72f0493c18403487a5d77021510e8665bd8bd22786904fbbd90d6db55c8dd2bf983c32421139de851c94
- languageName: node
- linkType: hard
-
"@types/react-test-renderer@npm:^18.0.0":
version: 18.3.1
resolution: "@types/react-test-renderer@npm:18.3.1"
@@ -9221,13 +9201,6 @@ __metadata:
languageName: node
linkType: hard
-"keycode@npm:^2.1.7":
- version: 2.2.1
- resolution: "keycode@npm:2.2.1"
- checksum: 10c0/e38ecbdc62f57e18ef9f7ad88aefded84e05b89115a40eea3081a7002d7c055765ddb5f5c3e2dd36ac2b2ab3901053c8286c9db082fd807b3abeb7e44034d96a
- languageName: node
- linkType: hard
-
"keyv@npm:^4.5.4":
version: 4.5.4
resolution: "keyv@npm:4.5.4"
@@ -11267,7 +11240,7 @@ __metadata:
languageName: node
linkType: hard
-"prop-types@npm:^15.5.10, prop-types@npm:^15.5.4, prop-types@npm:^15.6.0, prop-types@npm:^15.6.2, prop-types@npm:^15.7.2, prop-types@npm:^15.8.1":
+"prop-types@npm:^15.5.10, prop-types@npm:^15.6.0, prop-types@npm:^15.6.2, prop-types@npm:^15.7.2, prop-types@npm:^15.8.1":
version: 15.8.1
resolution: "prop-types@npm:15.8.1"
dependencies:
@@ -11427,19 +11400,6 @@ __metadata:
languageName: node
linkType: hard
-"react-event-listener@npm:^0.6.0":
- version: 0.6.6
- resolution: "react-event-listener@npm:0.6.6"
- dependencies:
- "@babel/runtime": "npm:^7.2.0"
- prop-types: "npm:^15.6.0"
- warning: "npm:^4.0.1"
- peerDependencies:
- react: ^16.3.0
- checksum: 10c0/07ca093d74b7963cb6048953517f881a0fdee9b485d31dabd49814cda51543eee20e714dd423e25946984b0ac26dbcb80aaf1211b0170e9b0cfa92fa85b0984e
- languageName: node
- linkType: hard
-
"react-fast-compare@npm:^3.1.1":
version: 3.2.2
resolution: "react-fast-compare@npm:3.2.2"
@@ -11682,49 +11642,6 @@ __metadata:
languageName: node
linkType: hard
-"react-swipeable-views-core@npm:^0.14.1":
- version: 0.14.1
- resolution: "react-swipeable-views-core@npm:0.14.1"
- dependencies:
- "@babel/runtime": "npm:7.0.0"
- warning: "npm:^4.0.1"
- peerDependencies:
- react: ^15.3.0 || ^16.0.0 || ^17.0.0
- checksum: 10c0/4da08493dad34f8498b66c596c1f40cd9a62e4968e71d00c79a26bf45e25ba3a3323e690641121cc8e7fd9c695e7da37fe781fa3f69e7d2b60fff3bfe4621426
- languageName: node
- linkType: hard
-
-"react-swipeable-views-utils@npm:^0.14.1":
- version: 0.14.1
- resolution: "react-swipeable-views-utils@npm:0.14.1"
- dependencies:
- "@babel/runtime": "npm:7.0.0"
- keycode: "npm:^2.1.7"
- prop-types: "npm:^15.6.0"
- react-event-listener: "npm:^0.6.0"
- react-swipeable-views-core: "npm:^0.14.1"
- shallow-equal: "npm:^1.2.1"
- peerDependencies:
- react: ^15.3.0 || ^16.0.0 || ^17.0.0
- checksum: 10c0/f9a9930e7df9dab9cd0f5344c7cf0423cc8aff4728436eb7dc13588186fbd1a557c8250b6329ec09242f3f6d2700d33e1155ab191ce8de48aa860fad6fb1814b
- languageName: node
- linkType: hard
-
-"react-swipeable-views@npm:^0.14.0":
- version: 0.14.1
- resolution: "react-swipeable-views@npm:0.14.1"
- dependencies:
- "@babel/runtime": "npm:7.0.0"
- prop-types: "npm:^15.5.4"
- react-swipeable-views-core: "npm:^0.14.1"
- react-swipeable-views-utils: "npm:^0.14.1"
- warning: "npm:^4.0.1"
- peerDependencies:
- react: ^15.3.0 || ^16.0.0 || ^17.0.0
- checksum: 10c0/7ee6d19cc33172e0846835eafd4b24ece0f26aed5cc9bbe80d3ec7c8d22f327443df8b2d50ddb4b837e1d6fbb40744abc41f62cdcab8e941e0663a952d627a15
- languageName: node
- linkType: hard
-
"react-test-renderer@npm:^18.2.0":
version: 18.3.1
resolution: "react-test-renderer@npm:18.3.1"
@@ -11923,13 +11840,6 @@ __metadata:
languageName: node
linkType: hard
-"regenerator-runtime@npm:^0.12.0":
- version: 0.12.1
- resolution: "regenerator-runtime@npm:0.12.1"
- checksum: 10c0/dbefbb38f5d6d55261aec1182d7c97ac93f2eec6ef9c756d9656eb5152f5cb3f8d873df020ddb4a3a8126c2ac1a3c2e534413cffe18d8f89b1c2a480a0a38601
- languageName: node
- linkType: hard
-
"regenerator-runtime@npm:^0.13.3":
version: 0.13.11
resolution: "regenerator-runtime@npm:0.13.11"
@@ -12521,13 +12431,6 @@ __metadata:
languageName: node
linkType: hard
-"shallow-equal@npm:^1.2.1":
- version: 1.2.1
- resolution: "shallow-equal@npm:1.2.1"
- checksum: 10c0/51e03abadd97c9ebe590547d92db9148446962a3f23a3a0fb1ba2fccab80af881eef0ff1f8ccefd3f066c0bc5a4c8ca53706194813b95c8835fa66448a843a26
- languageName: node
- linkType: hard
-
"shebang-command@npm:^2.0.0":
version: 2.0.0
resolution: "shebang-command@npm:2.0.0"
@@ -14377,7 +14280,7 @@ __metadata:
languageName: node
linkType: hard
-"warning@npm:^4.0.1, warning@npm:^4.0.3":
+"warning@npm:^4.0.3":
version: 4.0.3
resolution: "warning@npm:4.0.3"
dependencies: