diff --git a/app/soapbox/actions/profile_hover_card.js b/app/soapbox/actions/profile_hover_card.js new file mode 100644 index 000000000..90543148d --- /dev/null +++ b/app/soapbox/actions/profile_hover_card.js @@ -0,0 +1,24 @@ +export const PROFILE_HOVER_CARD_OPEN = 'PROFILE_HOVER_CARD_OPEN'; +export const PROFILE_HOVER_CARD_UPDATE = 'PROFILE_HOVER_CARD_UPDATE'; +export const PROFILE_HOVER_CARD_CLOSE = 'PROFILE_HOVER_CARD_CLOSE'; + +export function openProfileHoverCard(ref, accountId) { + return { + type: PROFILE_HOVER_CARD_OPEN, + ref, + accountId, + }; +} + +export function updateProfileHoverCard() { + return { + type: PROFILE_HOVER_CARD_UPDATE, + }; +} + +export function closeProfileHoverCard(force = false) { + return { + type: PROFILE_HOVER_CARD_CLOSE, + force, + }; +} diff --git a/app/soapbox/components/__tests__/__snapshots__/display_name-test.js.snap b/app/soapbox/components/__tests__/__snapshots__/display_name-test.js.snap index 59789099f..d26a406a2 100644 --- a/app/soapbox/components/__tests__/__snapshots__/display_name-test.js.snap +++ b/app/soapbox/components/__tests__/__snapshots__/display_name-test.js.snap @@ -4,16 +4,22 @@ exports[` renders display name + account name 1`] = ` - - Foo

", + + + Foo

", + } } - } - /> -
+ /> +
+
diff --git a/app/soapbox/components/__tests__/display_name-test.js b/app/soapbox/components/__tests__/display_name-test.js index 0d040c4cd..f626f94ca 100644 --- a/app/soapbox/components/__tests__/display_name-test.js +++ b/app/soapbox/components/__tests__/display_name-test.js @@ -1,7 +1,7 @@ import React from 'react'; -import renderer from 'react-test-renderer'; import { fromJS } from 'immutable'; import DisplayName from '../display_name'; +import { createComponent } from 'soapbox/test_helpers'; describe('', () => { it('renders display name + account name', () => { @@ -10,7 +10,7 @@ describe('', () => { acct: 'bar@baz', display_name_html: '

Foo

', }); - const component = renderer.create(); + const component = createComponent(); const tree = component.toJSON(); expect(tree).toMatchSnapshot(); diff --git a/app/soapbox/components/display_name.js b/app/soapbox/components/display_name.js index 7ab8b9e60..7d848a902 100644 --- a/app/soapbox/components/display_name.js +++ b/app/soapbox/components/display_name.js @@ -4,6 +4,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes'; import VerificationBadge from './verification_badge'; import { acctFull } from '../utils/accounts'; import { List as ImmutableList } from 'immutable'; +import HoverRefWrapper from 'soapbox/components/hover_ref_wrapper'; export default class DisplayName extends React.PureComponent { @@ -42,7 +43,9 @@ export default class DisplayName extends React.PureComponent { return ( - {displayName} + + {displayName} + {suffix} {children} diff --git a/app/soapbox/components/hover_ref_wrapper.js b/app/soapbox/components/hover_ref_wrapper.js new file mode 100644 index 000000000..fe6ac2bed --- /dev/null +++ b/app/soapbox/components/hover_ref_wrapper.js @@ -0,0 +1,56 @@ +import React, { useRef } from 'react'; +import PropTypes from 'prop-types'; +import { + openProfileHoverCard, + closeProfileHoverCard, +} from 'soapbox/actions/profile_hover_card'; +import { useDispatch } from 'react-redux'; +import { debounce } from 'lodash'; +import { isMobile } from 'soapbox/is_mobile'; + +const showProfileHoverCard = debounce((dispatch, ref, accountId) => { + dispatch(openProfileHoverCard(ref, accountId)); +}, 1200); + +const handleMouseEnter = (dispatch, ref, accountId) => { + return e => { + if (!isMobile(window.innerWidth)) + showProfileHoverCard(dispatch, ref, accountId); + }; +}; + +const handleMouseLeave = (dispatch) => { + return e => { + showProfileHoverCard.cancel(); + setTimeout(() => dispatch(closeProfileHoverCard()), 300); + }; +}; + +export const HoverRefWrapper = ({ accountId, children, inline }) => { + const dispatch = useDispatch(); + const ref = useRef(); + const Elem = inline ? 'span' : 'div'; + + return ( + + {children} + + ); +}; + +HoverRefWrapper.propTypes = { + accountId: PropTypes.string, + children: PropTypes.node, + inline: PropTypes.bool, +}; + +HoverRefWrapper.defaultProps = { + inline: false, +}; + +export default HoverRefWrapper; diff --git a/app/soapbox/components/profile_hover_card.js b/app/soapbox/components/profile_hover_card.js new file mode 100644 index 000000000..8d234aa4b --- /dev/null +++ b/app/soapbox/components/profile_hover_card.js @@ -0,0 +1,92 @@ +import React, { useEffect, useState } from 'react'; +import PropTypes from 'prop-types'; +import { useSelector, useDispatch } from 'react-redux'; +import { makeGetAccount } from 'soapbox/selectors'; +import { injectIntl, FormattedMessage } from 'react-intl'; +import ImmutablePropTypes from 'react-immutable-proptypes'; +import UserPanel from 'soapbox/features/ui/components/user_panel'; +import ActionButton from 'soapbox/features/ui/components/action_button'; +import { isAdmin, isModerator } from 'soapbox/utils/accounts'; +import Badge from 'soapbox/components/badge'; +import classNames from 'classnames'; +import { fetchRelationships } from 'soapbox/actions/accounts'; +import { usePopper } from 'react-popper'; +import { + closeProfileHoverCard, + updateProfileHoverCard, +} from 'soapbox/actions/profile_hover_card'; + +const getAccount = makeGetAccount(); + +const getBadges = (account) => { + let badges = []; + if (isAdmin(account)) badges.push(); + if (isModerator(account)) badges.push(); + if (account.getIn(['patron', 'is_patron'])) badges.push(); + return badges; +}; + +const handleMouseEnter = (dispatch) => { + return e => { + dispatch(updateProfileHoverCard()); + }; +}; + +const handleMouseLeave = (dispatch) => { + return e => { + dispatch(closeProfileHoverCard(true)); + }; +}; + +export const ProfileHoverCard = ({ visible }) => { + const dispatch = useDispatch(); + + const [popperElement, setPopperElement] = useState(null); + + const accountId = useSelector(state => state.getIn(['profile_hover_card', 'accountId'])); + const account = useSelector(state => accountId && getAccount(state, accountId)); + const targetRef = useSelector(state => state.getIn(['profile_hover_card', 'ref', 'current'])); + const badges = account ? getBadges(account) : []; + + useEffect(() => { + if (accountId) dispatch(fetchRelationships([accountId])); + }, [dispatch, accountId]); + + const { styles, attributes } = usePopper(targetRef, popperElement); + + if (!account) return null; + const accountBio = { __html: account.get('note_emojified') }; + const followedBy = account.getIn(['relationship', 'followed_by']); + + return ( +
+
+ {followedBy && + + + } +
+ + {badges.length > 0 && +
+ {badges} +
} + {account.getIn(['source', 'note'], '').length > 0 && +
} +
+
+ ); +}; + +ProfileHoverCard.propTypes = { + visible: PropTypes.bool, + accountId: PropTypes.string, + account: ImmutablePropTypes.map, + intl: PropTypes.object.isRequired, +}; + +ProfileHoverCard.defaultProps = { + visible: true, +}; + +export default injectIntl(ProfileHoverCard); diff --git a/app/soapbox/components/status.js b/app/soapbox/components/status.js index 8acb4e7f5..9e8a2d684 100644 --- a/app/soapbox/components/status.js +++ b/app/soapbox/components/status.js @@ -18,10 +18,8 @@ import classNames from 'classnames'; import Icon from 'soapbox/components/icon'; import PollContainer from 'soapbox/containers/poll_container'; import { NavLink } from 'react-router-dom'; -import ProfileHoverCardContainer from '../features/profile_hover_card/profile_hover_card_container'; -import { isMobile } from '../../../app/soapbox/is_mobile'; -import { debounce } from 'lodash'; import { getDomain } from 'soapbox/utils/accounts'; +import HoverRefWrapper from 'soapbox/components/hover_ref_wrapper'; // We use the component (and not the container) since we do not want // to use the progress bar to show download progress @@ -82,6 +80,7 @@ class Status extends ImmutablePureComponent { onEmbed: PropTypes.func, onHeightChange: PropTypes.func, onToggleHidden: PropTypes.func, + onShowHoverProfileCard: PropTypes.func, muted: PropTypes.bool, hidden: PropTypes.bool, unread: PropTypes.bool, @@ -108,7 +107,6 @@ class Status extends ImmutablePureComponent { state = { showMedia: defaultMediaVisibility(this.props.status, this.props.displayMedia), statusId: undefined, - profileCardVisible: false, }; // Track height changes we know about to compensate scrolling @@ -256,19 +254,6 @@ class Status extends ImmutablePureComponent { this.handleToggleMediaVisibility(); } - showProfileCard = debounce(() => { - this.setState({ profileCardVisible: true }); - }, 1200); - - handleProfileHover = e => { - if (!isMobile(window.innerWidth)) this.showProfileCard(); - } - - handleProfileLeave = e => { - this.showProfileCard.cancel(); - this.setState({ profileCardVisible: false }); - } - _properStatus() { const { status } = this.props; @@ -457,7 +442,6 @@ class Status extends ImmutablePureComponent { }; const statusUrl = `/@${status.getIn(['account', 'acct'])}/posts/${status.get('id')}`; - const { profileCardVisible } = this.state; const favicon = status.getIn(['account', 'pleroma', 'favicon']); const domain = getDomain(status.get('account')); @@ -478,17 +462,17 @@ class Status extends ImmutablePureComponent {
} -
+
- - {statusAvatar} + + + {statusAvatar} + +
- { profileCardVisible && - - }
diff --git a/app/soapbox/features/chats/chat_room.js b/app/soapbox/features/chats/chat_room.js index f3e81cc12..a9f0ccd5d 100644 --- a/app/soapbox/features/chats/chat_room.js +++ b/app/soapbox/features/chats/chat_room.js @@ -3,6 +3,7 @@ import { connect } from 'react-redux'; import PropTypes from 'prop-types'; import ImmutablePropTypes from 'react-immutable-proptypes'; import { injectIntl } from 'react-intl'; +import { Link } from 'react-router-dom'; import ImmutablePureComponent from 'react-immutable-pure-component'; import Avatar from 'soapbox/components/avatar'; import { acctFull } from 'soapbox/utils/accounts'; @@ -75,12 +76,12 @@ class ChatRoom extends ImmutablePureComponent {
-
+
@{acctFull(account)}
-
+
({ me: state.get('me'), @@ -79,13 +80,24 @@ class ChatWindow extends ImmutablePureComponent { const right = (285 * (idx + 1)) + 20; const unreadCount = chat.get('unread'); + const unreadIcon = ( + + {shortNumberFormat(unreadCount)} + + ); + + const avatar = ( + + + + + + ); + return (
- {unreadCount > 0 - ? {shortNumberFormat(unreadCount)} - : - } + {unreadCount > 0 ? unreadIcon : avatar } diff --git a/app/soapbox/features/profile_hover_card/profile_hover_card_container.js b/app/soapbox/features/profile_hover_card/profile_hover_card_container.js deleted file mode 100644 index d4f706212..000000000 --- a/app/soapbox/features/profile_hover_card/profile_hover_card_container.js +++ /dev/null @@ -1,79 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import { connect } from 'react-redux'; -import { makeGetAccount } from '../../selectors'; -import { injectIntl, FormattedMessage } from 'react-intl'; -import ImmutablePropTypes from 'react-immutable-proptypes'; -import ImmutablePureComponent from 'react-immutable-pure-component'; -import UserPanel from '../ui/components/user_panel'; -import ActionButton from '../ui/components/action_button'; -import { isAdmin, isModerator } from 'soapbox/utils/accounts'; -import Badge from 'soapbox/components/badge'; -import classNames from 'classnames'; -import { fetchRelationships } from 'soapbox/actions/accounts'; - -const getAccount = makeGetAccount(); - -const mapStateToProps = (state, { accountId }) => { - return { - account: getAccount(state, accountId), - }; -}; - -export default @connect(mapStateToProps) -@injectIntl -class ProfileHoverCardContainer extends ImmutablePureComponent { - - static propTypes = { - visible: PropTypes.bool, - accountId: PropTypes.string, - account: ImmutablePropTypes.map, - intl: PropTypes.object.isRequired, - dispatch: PropTypes.func.isRequired, - } - - static defaultProps = { - visible: true, - } - - getBadges = () => { - const { account } = this.props; - let badges = []; - if (isAdmin(account)) badges.push(); - if (isModerator(account)) badges.push(); - if (account.getIn(['patron', 'is_patron'])) badges.push(); - return badges; - } - - componentDidMount() { - this.props.dispatch(fetchRelationships([this.props.accountId])); - } - - render() { - const { visible, accountId, account } = this.props; - if (!accountId) return null; - const accountBio = { __html: account.get('note_emojified') }; - const followedBy = account.getIn(['relationship', 'followed_by']); - const badges = this.getBadges(); - - return ( -
-
- {followedBy && - - - } -
- - {badges.length > 0 && -
- {badges} -
} - {account.getIn(['source', 'note'], '').length > 0 && -
} -
-
- ); - } - -}; diff --git a/app/soapbox/features/status/components/detailed_status.js b/app/soapbox/features/status/components/detailed_status.js index d58bd7e72..131de49ec 100644 --- a/app/soapbox/features/status/components/detailed_status.js +++ b/app/soapbox/features/status/components/detailed_status.js @@ -16,10 +16,8 @@ import classNames from 'classnames'; import Icon from 'soapbox/components/icon'; import PollContainer from 'soapbox/containers/poll_container'; import { StatusInteractionBar } from './status_interaction_bar'; -import ProfileHoverCardContainer from 'soapbox/features/profile_hover_card/profile_hover_card_container'; -import { isMobile } from 'soapbox/is_mobile'; -import { debounce } from 'lodash'; import { getDomain } from 'soapbox/utils/accounts'; +import HoverRefWrapper from 'soapbox/components/hover_ref_wrapper'; export default class DetailedStatus extends ImmutablePureComponent { @@ -42,7 +40,6 @@ export default class DetailedStatus extends ImmutablePureComponent { state = { height: null, - profileCardVisible: false, }; handleOpenVideo = (media, startTime) => { @@ -86,24 +83,10 @@ export default class DetailedStatus extends ImmutablePureComponent { window.open(href, 'soapbox-intent', 'width=445,height=600,resizable=no,menubar=no,status=no,scrollbars=yes'); } - showProfileCard = debounce(() => { - this.setState({ profileCardVisible: true }); - }, 1200); - - handleProfileHover = e => { - if (!isMobile(window.innerWidth)) this.showProfileCard(); - } - - handleProfileLeave = e => { - this.showProfileCard.cancel(); - this.setState({ profileCardVisible: false }); - } - render() { const status = (this.props.status && this.props.status.get('reblog')) ? this.props.status.get('reblog') : this.props.status; const outerStyle = { boxSizing: 'border-box' }; const { compact } = this.props; - const { profileCardVisible } = this.state; const favicon = status.getIn(['account', 'pleroma', 'favicon']); const domain = getDomain(status.get('account')); @@ -181,20 +164,21 @@ export default class DetailedStatus extends ImmutablePureComponent { return (
-
+
- + + +
- + + +
- { profileCardVisible && - - }
{status.get('group') && ( diff --git a/app/soapbox/features/ui/components/user_panel.js b/app/soapbox/features/ui/components/user_panel.js index 1ba4e3efc..411b9b70b 100644 --- a/app/soapbox/features/ui/components/user_panel.js +++ b/app/soapbox/features/ui/components/user_panel.js @@ -56,26 +56,26 @@ class UserPanel extends ImmutablePureComponent {
-
+ {account.get('statuses_count') &&
{shortNumberFormat(account.get('statuses_count'))} -
+
} -
+ {account.get('followers_count') &&
{shortNumberFormat(account.get('followers_count'))} -
+
} -
+ {account.get('following_count') &&
{shortNumberFormat(account.get('following_count'))} -
+
}
diff --git a/app/soapbox/features/ui/index.js b/app/soapbox/features/ui/index.js index ff80086ee..3f37ffe40 100644 --- a/app/soapbox/features/ui/index.js +++ b/app/soapbox/features/ui/index.js @@ -38,6 +38,7 @@ import { Redirect } from 'react-router-dom'; import Icon from 'soapbox/components/icon'; import { isStaff } from 'soapbox/utils/accounts'; import ChatPanes from 'soapbox/features/chats/components/chat_panes'; +import ProfileHoverCard from 'soapbox/components/profile_hover_card'; import { Status, @@ -650,6 +651,7 @@ class UI extends React.PureComponent { {me && } {me && !mobile && } +
); diff --git a/app/soapbox/reducers/index.js b/app/soapbox/reducers/index.js index 2caec469a..6f4abdafe 100644 --- a/app/soapbox/reducers/index.js +++ b/app/soapbox/reducers/index.js @@ -46,6 +46,7 @@ import admin from './admin'; import chats from './chats'; import chat_messages from './chat_messages'; import chat_message_lists from './chat_message_lists'; +import profile_hover_card from './profile_hover_card'; const reducers = { dropdown_menu, @@ -95,6 +96,7 @@ const reducers = { chats, chat_messages, chat_message_lists, + profile_hover_card, }; export default combineReducers(reducers); diff --git a/app/soapbox/reducers/profile_hover_card.js b/app/soapbox/reducers/profile_hover_card.js new file mode 100644 index 000000000..5776a3e87 --- /dev/null +++ b/app/soapbox/reducers/profile_hover_card.js @@ -0,0 +1,27 @@ +import { + PROFILE_HOVER_CARD_OPEN, + PROFILE_HOVER_CARD_CLOSE, + PROFILE_HOVER_CARD_UPDATE, +} from 'soapbox/actions/profile_hover_card'; +import { Map as ImmutableMap } from 'immutable'; + +const initialState = ImmutableMap(); + +export default function profileHoverCard(state = initialState, action) { + switch(action.type) { + case PROFILE_HOVER_CARD_OPEN: + return ImmutableMap({ + ref: action.ref, + accountId: action.accountId, + }); + case PROFILE_HOVER_CARD_UPDATE: + return state.set('hovered', true); + case PROFILE_HOVER_CARD_CLOSE: + if (state.get('hovered') === true && !action.force) + return state; + else + return ImmutableMap(); + default: + return state; + } +} diff --git a/app/styles/application.scss b/app/styles/application.scss index 96eb4dcf4..fdce329ad 100644 --- a/app/styles/application.scss +++ b/app/styles/application.scss @@ -27,7 +27,6 @@ @import 'dyslexic'; @import 'demetricator'; @import 'pro'; -@import 'overflow_hacks'; @import 'chats'; // COMPONENTS diff --git a/app/styles/chats.scss b/app/styles/chats.scss index 29c2f0c4f..3e2fc2e24 100644 --- a/app/styles/chats.scss +++ b/app/styles/chats.scss @@ -322,7 +322,6 @@ display: flex; align-items: center; background: var(--accent-color--faint); - border-radius: 10px 10px 0 0; .column-back-button { background: transparent; diff --git a/app/styles/components/columns.scss b/app/styles/components/columns.scss index d8034e497..10e46e441 100644 --- a/app/styles/components/columns.scss +++ b/app/styles/components/columns.scss @@ -212,7 +212,6 @@ font-size: 16px; line-height: inherit; border: 0; - border-radius: 10px 10px 0 0; text-align: unset; padding: 15px; margin: 0; diff --git a/app/styles/components/detailed-status.scss b/app/styles/components/detailed-status.scss index d53b426ee..ceab5899c 100644 --- a/app/styles/components/detailed-status.scss +++ b/app/styles/components/detailed-status.scss @@ -62,7 +62,6 @@ border-bottom: 1px solid var(--brand-color--faint); display: flex; flex-direction: row; - border-radius: 0 0 10px 10px; } .detailed-status__link { diff --git a/app/styles/components/drawer.scss b/app/styles/components/drawer.scss index 39e936158..7dc5a1a10 100644 --- a/app/styles/components/drawer.scss +++ b/app/styles/components/drawer.scss @@ -20,7 +20,7 @@ .column, .drawer { flex: 1 1 100%; - overflow: visible; + overflow: hidden; } .drawer__pager { diff --git a/app/styles/components/profile_hover_card.scss b/app/styles/components/profile_hover_card.scss index decb68711..b3fb4fc31 100644 --- a/app/styles/components/profile_hover_card.scss +++ b/app/styles/components/profile_hover_card.scss @@ -15,19 +15,14 @@ transition-duration: 0.2s; width: 320px; z-index: 200; - left: -10px; - padding: 20px; - margin-bottom: 10px; + top: 0; + left: 0; &--visible { opacity: 1; pointer-events: all; } - @media(min-width: 750px) { - left: -100px; - } - .profile-hover-card__container { @include standard-panel; position: relative; @@ -114,18 +109,12 @@ .detailed-status { .profile-hover-card { top: 0; - left: 60px; + left: 0; } } -/* Prevent floating avatars from intercepting with current card */ -.status, -.detailed-status { - .floating-link { - display: none; - } - - &:hover .floating-link { - display: block; - } +/* Hide the popper when the reference is hidden */ +#popper[data-popper-reference-hidden] { + visibility: hidden; + pointer-events: none; } diff --git a/app/styles/loading.scss b/app/styles/loading.scss index 88705782e..42a3a0c1f 100644 --- a/app/styles/loading.scss +++ b/app/styles/loading.scss @@ -188,7 +188,6 @@ align-items: center; justify-content: center; padding: 20px; - border-radius: 0 0 10px 10px; & > div { width: 100%; diff --git a/app/styles/overflow_hacks.scss b/app/styles/overflow_hacks.scss deleted file mode 100644 index ef72b6863..000000000 --- a/app/styles/overflow_hacks.scss +++ /dev/null @@ -1,37 +0,0 @@ -// This is a file dedicated to fixing the css we broke by introducing the hover -// card and `overflow:visible` on drawer.scss line 23. If we ever figure out how -// to pop the hover card out while keeping `overflow:hidden`, feel free to delete -// this entire file. - -button.column-header__button.active { - border-radius: 0 10px 0 0; -} - -.column-back-button.column-back-button--slim-button { - border-radius: 0 10px 0 0; -} - -.detailed-status__wrapper .detailed-status__action-bar { - border-radius: 0 0 10px 10px; -} - -.slist .item-list .column-link { - background-color: transparent; - border-top: 1px solid var(--brand-color--med); -} - -.focusable { - &:focus { - border-radius: 0 0 10px 10px; - } -} - -.load-more:hover { - border-radius: 0 0 10px 10px; -} - -// this still looks like shit but at least it's better than it overflowing - -.empty-column-indicator { - border-radius: 0 0 10px 10px; -} diff --git a/package.json b/package.json index f2fbc4e17..d42e7b002 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,7 @@ "@babel/runtime": "^7.3.4", "@clusterws/cws": "^0.16.0", "@fonticonpicker/react-fonticonpicker": "^1.2.0", + "@popperjs/core": "^2.4.4", "array-includes": "^3.0.3", "autoprefixer": "^9.5.1", "axios": "^0.19.0", @@ -115,6 +116,7 @@ "react-motion": "^0.5.2", "react-notification": "^6.8.4", "react-overlays": "^0.8.3", + "react-popper": "^2.2.3", "react-redux": "^7.2.1", "react-redux-loading-bar": "^4.5.0", "react-router-dom": "^4.1.1", diff --git a/yarn.lock b/yarn.lock index 2ed08b81f..e1be9d3a8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1494,6 +1494,11 @@ "@types/yargs" "^15.0.0" chalk "^4.0.0" +"@popperjs/core@^2.4.4": + version "2.4.4" + resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.4.4.tgz#11d5db19bd178936ec89cd84519c4de439574398" + integrity sha512-1oO6+dN5kdIA3sKPZhRGJTfGVP4SWV6KqlMOwry4J3HfyD68sl/3KmG7DeYUzvN+RbhXDnv/D8vNNB8168tAMg== + "@sinonjs/commons@^1.7.0": version "1.8.0" resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.0.tgz#c8d68821a854c555bba172f3b06959a0039b236d" @@ -9495,6 +9500,11 @@ react-fast-compare@^2.0.4: resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-2.0.4.tgz#e84b4d455b0fec113e0402c329352715196f81f9" integrity sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw== +react-fast-compare@^3.0.1: + version "3.2.0" + resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.0.tgz#641a9da81b6a6320f270e89724fb45a0b39e43bb" + integrity sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA== + react-helmet@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/react-helmet/-/react-helmet-6.0.0.tgz#fcb93ebaca3ba562a686eb2f1f9d46093d83b5f8" @@ -9622,6 +9632,14 @@ react-overlays@^0.8.3: react-transition-group "^2.2.0" warning "^3.0.0" +react-popper@^2.2.3: + version "2.2.3" + resolved "https://registry.yarnpkg.com/react-popper/-/react-popper-2.2.3.tgz#33d425fa6975d4bd54d9acd64897a89d904b9d97" + integrity sha512-mOEiMNT1249js0jJvkrOjyHsGvqcJd3aGW/agkiMoZk3bZ1fXN1wQszIQSjHIai48fE67+zwF8Cs+C4fWqlfjw== + dependencies: + react-fast-compare "^3.0.1" + warning "^4.0.2" + react-redux-loading-bar@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/react-redux-loading-bar/-/react-redux-loading-bar-4.5.0.tgz#96538d0ba041463d810e213fb54eadbce9628266" @@ -11883,6 +11901,13 @@ warning@^4.0.1: dependencies: loose-envify "^1.0.0" +warning@^4.0.2: + version "4.0.3" + resolved "https://registry.yarnpkg.com/warning/-/warning-4.0.3.tgz#16e9e077eb8a86d6af7d64aa1e05fd85b4678ca3" + integrity sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w== + dependencies: + loose-envify "^1.0.0" + watchpack@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.6.0.tgz#4bc12c2ebe8aa277a71f1d3f14d685c7b446cd00"