From fd33bcb3b25d3eaf593ade0aa8709a1184fc254e Mon Sep 17 00:00:00 2001 From: Peter Simonsson Date: Wed, 11 Jan 2023 21:58:46 +0100 Subject: Fix dropdown menu positions when scrolling (#22916) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update react-overlays to latest version * Fix breaking changes in dropdown menus * Use react-overlays built-in arrow positioning feature * Re-implemented `.dropdown-menu__arrow` to have a defined width and height to improve positioning * Moved wrapping div (`.dropdown-menu` from `DropdownMenu` to `Dropdown`) * Wrap button in a span to solve issue with ref * Temporarily remove animations * Fix breaking changes in emoji picker * Wrap EmojiPickerMenu in a div where react-overlays’ ref is added * Fix breaking changes in language dropdown * Fix breaking changes in privacy dropdown * Fix breaking changes in search form * Add animations back using `@keyframes` * Fix arrow color in light theme * Fix linting issue * Remove unused `mounted` state * Remove `placement` state from components and redux And remove the placement state from props of the menu components. * Remove abolution position to fix flip issue * Remove z-index to fix modals and overlay positions * Fix lint issues * Set placement in privacy and language components Copy the placement state into the `PrivacyDropdown` and `LanguageDropdown` components, to apply correct styling to the buttons depending on which placement the Overlay has. * Move `placement` state to correct component --- app/javascript/mastodon/actions/dropdown_menu.js | 4 +- .../mastodon/components/dropdown_menu.js | 102 ++++++++------------- .../containers/dropdown_menu_container.js | 5 +- .../mastodon/containers/dropdown_menu_container.js | 5 +- .../compose/components/emoji_picker_dropdown.js | 39 ++++---- .../compose/components/language_dropdown.js | 81 ++++++++-------- .../compose/components/privacy_dropdown.js | 85 +++++++++-------- .../mastodon/features/compose/components/search.js | 51 +++++------ app/javascript/mastodon/reducers/dropdown_menu.js | 4 +- app/javascript/styles/mastodon-light/diff.scss | 18 +--- app/javascript/styles/mastodon/components.scss | 87 +++++++++++++----- 11 files changed, 239 insertions(+), 242 deletions(-) (limited to 'app/javascript') diff --git a/app/javascript/mastodon/actions/dropdown_menu.js b/app/javascript/mastodon/actions/dropdown_menu.js index fb6e55612..023151d4b 100644 --- a/app/javascript/mastodon/actions/dropdown_menu.js +++ b/app/javascript/mastodon/actions/dropdown_menu.js @@ -1,8 +1,8 @@ export const DROPDOWN_MENU_OPEN = 'DROPDOWN_MENU_OPEN'; export const DROPDOWN_MENU_CLOSE = 'DROPDOWN_MENU_CLOSE'; -export function openDropdownMenu(id, placement, keyboard, scroll_key) { - return { type: DROPDOWN_MENU_OPEN, id, placement, keyboard, scroll_key }; +export function openDropdownMenu(id, keyboard, scroll_key) { + return { type: DROPDOWN_MENU_OPEN, id, keyboard, scroll_key }; } export function closeDropdownMenu(id) { diff --git a/app/javascript/mastodon/components/dropdown_menu.js b/app/javascript/mastodon/components/dropdown_menu.js index 4b4ad8355..5897aada8 100644 --- a/app/javascript/mastodon/components/dropdown_menu.js +++ b/app/javascript/mastodon/components/dropdown_menu.js @@ -2,9 +2,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import ImmutablePropTypes from 'react-immutable-proptypes'; import IconButton from './icon_button'; -import Overlay from 'react-overlays/lib/Overlay'; -import Motion from '../features/ui/util/optional_motion'; -import spring from 'react-motion/lib/spring'; +import Overlay from 'react-overlays/Overlay'; import { supportsPassiveEvents } from 'detect-passive-events'; import classNames from 'classnames'; import { CircularProgress } from 'mastodon/components/loading_indicator'; @@ -24,9 +22,6 @@ class DropdownMenu extends React.PureComponent { scrollable: PropTypes.bool, onClose: PropTypes.func.isRequired, style: PropTypes.object, - placement: PropTypes.string, - arrowOffsetLeft: PropTypes.string, - arrowOffsetTop: PropTypes.string, openedViaKeyboard: PropTypes.bool, renderItem: PropTypes.func, renderHeader: PropTypes.func, @@ -35,11 +30,6 @@ class DropdownMenu extends React.PureComponent { static defaultProps = { style: {}, - placement: 'bottom', - }; - - state = { - mounted: false, }; handleDocumentClick = e => { @@ -56,8 +46,6 @@ class DropdownMenu extends React.PureComponent { if (this.focusedItem && this.props.openedViaKeyboard) { this.focusedItem.focus({ preventScroll: true }); } - - this.setState({ mounted: true }); } componentWillUnmount () { @@ -139,40 +127,28 @@ class DropdownMenu extends React.PureComponent { } render () { - const { items, style, placement, arrowOffsetLeft, arrowOffsetTop, scrollable, renderHeader, loading } = this.props; - const { mounted } = this.state; + const { items, scrollable, renderHeader, loading } = this.props; let renderItem = this.props.renderItem || this.renderItem; return ( - - {({ opacity, scaleX, scaleY }) => ( - // It should not be transformed when mounting because the resulting - // size will be used to determine the coordinate of the menu by - // react-overlays -
-
- -
- {loading && ( - - )} - - {!loading && renderHeader && ( -
- {renderHeader(items)} -
- )} - - {!loading && ( -
    - {items.map((option, i) => renderItem(option, i, { onClick: this.handleClick, onKeyPress: this.handleItemKeyPress }))} -
- )} -
+
+ {loading && ( + + )} + + {!loading && renderHeader && ( +
+ {renderHeader(items)}
)} - + + {!loading && ( +
    + {items.map((option, i) => renderItem(option, i, { onClick: this.handleClick, onKeyPress: this.handleItemKeyPress }))} +
+ )} +
); } @@ -197,7 +173,6 @@ export default class Dropdown extends React.PureComponent { isUserTouching: PropTypes.func, onOpen: PropTypes.func.isRequired, onClose: PropTypes.func.isRequired, - dropdownPlacement: PropTypes.string, openDropdownId: PropTypes.number, openedViaKeyboard: PropTypes.bool, renderItem: PropTypes.func, @@ -213,13 +188,11 @@ export default class Dropdown extends React.PureComponent { id: id++, }; - handleClick = ({ target, type }) => { + handleClick = ({ type }) => { if (this.state.id === this.props.openDropdownId) { this.handleClose(); } else { - const { top } = target.getBoundingClientRect(); - const placement = top * 2 < innerHeight ? 'bottom' : 'top'; - this.props.onOpen(this.state.id, this.handleItemClick, placement, type !== 'click'); + this.props.onOpen(this.state.id, this.handleItemClick, type !== 'click'); } } @@ -303,7 +276,6 @@ export default class Dropdown extends React.PureComponent { disabled, loading, scrollable, - dropdownPlacement, openDropdownId, openedViaKeyboard, children, @@ -314,7 +286,6 @@ export default class Dropdown extends React.PureComponent { const open = this.state.id === openDropdownId; const button = children ? React.cloneElement(React.Children.only(children), { - ref: this.setTargetRef, onClick: this.handleClick, onMouseDown: this.handleMouseDown, onKeyDown: this.handleButtonKeyDown, @@ -326,7 +297,6 @@ export default class Dropdown extends React.PureComponent { active={open} disabled={disabled} size={size} - ref={this.setTargetRef} onClick={this.handleClick} onMouseDown={this.handleMouseDown} onKeyDown={this.handleButtonKeyDown} @@ -336,19 +306,27 @@ export default class Dropdown extends React.PureComponent { return ( - {button} - - - + + {button} + + + {({ props, arrowProps, placement }) => ( +
+
+
+ +
+
+ )} ); diff --git a/app/javascript/mastodon/components/edited_timestamp/containers/dropdown_menu_container.js b/app/javascript/mastodon/components/edited_timestamp/containers/dropdown_menu_container.js index e30c18372..16fe77a73 100644 --- a/app/javascript/mastodon/components/edited_timestamp/containers/dropdown_menu_container.js +++ b/app/javascript/mastodon/components/edited_timestamp/containers/dropdown_menu_container.js @@ -4,7 +4,6 @@ import { fetchHistory } from 'mastodon/actions/history'; import DropdownMenu from 'mastodon/components/dropdown_menu'; const mapStateToProps = (state, { statusId }) => ({ - dropdownPlacement: state.getIn(['dropdown_menu', 'placement']), openDropdownId: state.getIn(['dropdown_menu', 'openId']), openedViaKeyboard: state.getIn(['dropdown_menu', 'keyboard']), items: state.getIn(['history', statusId, 'items']), @@ -13,9 +12,9 @@ const mapStateToProps = (state, { statusId }) => ({ const mapDispatchToProps = (dispatch, { statusId }) => ({ - onOpen (id, onItemClick, dropdownPlacement, keyboard) { + onOpen (id, onItemClick, keyboard) { dispatch(fetchHistory(statusId)); - dispatch(openDropdownMenu(id, dropdownPlacement, keyboard)); + dispatch(openDropdownMenu(id, keyboard)); }, onClose (id) { diff --git a/app/javascript/mastodon/containers/dropdown_menu_container.js b/app/javascript/mastodon/containers/dropdown_menu_container.js index c45bab40b..bedd1c63f 100644 --- a/app/javascript/mastodon/containers/dropdown_menu_container.js +++ b/app/javascript/mastodon/containers/dropdown_menu_container.js @@ -6,13 +6,12 @@ import DropdownMenu from '../components/dropdown_menu'; import { isUserTouching } from '../is_mobile'; const mapStateToProps = state => ({ - dropdownPlacement: state.getIn(['dropdown_menu', 'placement']), openDropdownId: state.getIn(['dropdown_menu', 'openId']), openedViaKeyboard: state.getIn(['dropdown_menu', 'keyboard']), }); const mapDispatchToProps = (dispatch, { status, items, scrollKey }) => ({ - onOpen(id, onItemClick, dropdownPlacement, keyboard) { + onOpen(id, onItemClick, keyboard) { if (status) { dispatch(fetchRelationships([status.getIn(['account', 'id'])])); } @@ -21,7 +20,7 @@ const mapDispatchToProps = (dispatch, { status, items, scrollKey }) => ({ status, actions: items, onClick: onItemClick, - }) : openDropdownMenu(id, dropdownPlacement, keyboard, scrollKey)); + }) : openDropdownMenu(id, keyboard, scrollKey)); }, onClose(id) { diff --git a/app/javascript/mastodon/features/compose/components/emoji_picker_dropdown.js b/app/javascript/mastodon/features/compose/components/emoji_picker_dropdown.js index 8cca8af2a..76c9cda81 100644 --- a/app/javascript/mastodon/features/compose/components/emoji_picker_dropdown.js +++ b/app/javascript/mastodon/features/compose/components/emoji_picker_dropdown.js @@ -2,7 +2,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; import { EmojiPicker as EmojiPickerAsync } from '../../ui/util/async-components'; -import Overlay from 'react-overlays/lib/Overlay'; +import Overlay from 'react-overlays/Overlay'; import classNames from 'classnames'; import ImmutablePropTypes from 'react-immutable-proptypes'; import { supportsPassiveEvents } from 'detect-passive-events'; @@ -154,9 +154,6 @@ class EmojiPickerMenu extends React.PureComponent { onClose: PropTypes.func.isRequired, onPick: PropTypes.func.isRequired, style: PropTypes.object, - placement: PropTypes.string, - arrowOffsetLeft: PropTypes.string, - arrowOffsetTop: PropTypes.string, intl: PropTypes.object.isRequired, skinTone: PropTypes.number.isRequired, onSkinTone: PropTypes.func.isRequired, @@ -324,14 +321,13 @@ class EmojiPickerDropdown extends React.PureComponent { state = { active: false, loading: false, - placement: null, }; setRef = (c) => { this.dropdown = c; } - onShowDropdown = ({ target }) => { + onShowDropdown = () => { this.setState({ active: true }); if (!EmojiPicker) { @@ -346,9 +342,6 @@ class EmojiPickerDropdown extends React.PureComponent { this.setState({ loading: false, active: false }); }); } - - const { top } = target.getBoundingClientRect(); - this.setState({ placement: top * 2 < innerHeight ? 'bottom' : 'top' }); } onHideDropdown = () => { @@ -382,7 +375,7 @@ class EmojiPickerDropdown extends React.PureComponent { render () { const { intl, onPickEmoji, onSkinTone, skinTone, frequentlyUsedEmojis, button } = this.props; const title = intl.formatMessage(messages.emoji); - const { active, loading, placement } = this.state; + const { active, loading } = this.state; return (
@@ -394,16 +387,22 @@ class EmojiPickerDropdown extends React.PureComponent { />}
- - + + {({ props, placement })=> ( +
+
+ +
+
+ )}
); diff --git a/app/javascript/mastodon/features/compose/components/language_dropdown.js b/app/javascript/mastodon/features/compose/components/language_dropdown.js index bf56fd0fa..4254a4926 100644 --- a/app/javascript/mastodon/features/compose/components/language_dropdown.js +++ b/app/javascript/mastodon/features/compose/components/language_dropdown.js @@ -2,9 +2,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import { injectIntl, defineMessages } from 'react-intl'; import TextIconButton from './text_icon_button'; -import Overlay from 'react-overlays/lib/Overlay'; -import Motion from 'mastodon/features/ui/util/optional_motion'; -import spring from 'react-motion/lib/spring'; +import Overlay from 'react-overlays/Overlay'; import { supportsPassiveEvents } from 'detect-passive-events'; import classNames from 'classnames'; import { languages as preloadedLanguages } from 'mastodon/initial_state'; @@ -22,10 +20,8 @@ const listenerOptions = supportsPassiveEvents ? { passive: true } : false; class LanguageDropdownMenu extends React.PureComponent { static propTypes = { - style: PropTypes.object, value: PropTypes.string.isRequired, frequentlyUsedLanguages: PropTypes.arrayOf(PropTypes.string).isRequired, - placement: PropTypes.string.isRequired, onClose: PropTypes.func.isRequired, onChange: PropTypes.func.isRequired, languages: PropTypes.arrayOf(PropTypes.arrayOf(PropTypes.string)), @@ -37,7 +33,6 @@ class LanguageDropdownMenu extends React.PureComponent { }; state = { - mounted: false, searchValue: '', }; @@ -50,7 +45,6 @@ class LanguageDropdownMenu extends React.PureComponent { componentDidMount () { document.addEventListener('click', this.handleDocumentClick, false); document.addEventListener('touchend', this.handleDocumentClick, listenerOptions); - this.setState({ mounted: true }); // Because of https://github.com/react-bootstrap/react-bootstrap/issues/2614 we need // to wait for a frame before focusing @@ -222,29 +216,22 @@ class LanguageDropdownMenu extends React.PureComponent { } render () { - const { style, placement, intl } = this.props; - const { mounted, searchValue } = this.state; + const { intl } = this.props; + const { searchValue } = this.state; const isSearching = searchValue !== ''; const results = this.search(); return ( - - {({ opacity, scaleX, scaleY }) => ( - // It should not be transformed when mounting because the resulting - // size will be used to determine the coordinate of the menu by - // react-overlays -
-
- - -
+
+
+ + +
-
- {results.map(this.renderItem)} -
-
- )} - +
+ {results.map(this.renderItem)} +
+
); } @@ -266,14 +253,11 @@ class LanguageDropdown extends React.PureComponent { placement: 'bottom', }; - handleToggle = ({ target }) => { - const { top } = target.getBoundingClientRect(); - + handleToggle = () => { if (this.state.open && this.activeElement) { this.activeElement.focus({ preventScroll: true }); } - this.setState({ placement: top * 2 < innerHeight ? 'bottom' : 'top' }); this.setState({ open: !this.state.open }); } @@ -293,13 +277,25 @@ class LanguageDropdown extends React.PureComponent { onChange(value); } + setTargetRef = c => { + this.target = c; + } + + findTarget = () => { + return this.target; + } + + handleOverlayEnter = (state) => { + this.setState({ placement: state.placement }); + } + render () { const { value, intl, frequentlyUsedLanguages } = this.props; const { open, placement } = this.state; return ( -
-
+
+
- - + + {({ props, placement }) => ( +
+
+ +
+
+ )}
); diff --git a/app/javascript/mastodon/features/compose/components/privacy_dropdown.js b/app/javascript/mastodon/features/compose/components/privacy_dropdown.js index 1f0e998d3..09bbc8e99 100644 --- a/app/javascript/mastodon/features/compose/components/privacy_dropdown.js +++ b/app/javascript/mastodon/features/compose/components/privacy_dropdown.js @@ -2,9 +2,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import { injectIntl, defineMessages } from 'react-intl'; import IconButton from '../../../components/icon_button'; -import Overlay from 'react-overlays/lib/Overlay'; -import Motion from '../../ui/util/optional_motion'; -import spring from 'react-motion/lib/spring'; +import Overlay from 'react-overlays/Overlay'; import { supportsPassiveEvents } from 'detect-passive-events'; import classNames from 'classnames'; import Icon from 'mastodon/components/icon'; @@ -29,15 +27,10 @@ class PrivacyDropdownMenu extends React.PureComponent { style: PropTypes.object, items: PropTypes.array.isRequired, value: PropTypes.string.isRequired, - placement: PropTypes.string.isRequired, onClose: PropTypes.func.isRequired, onChange: PropTypes.func.isRequired, }; - state = { - mounted: false, - }; - handleDocumentClick = e => { if (this.node && !this.node.contains(e.target)) { this.props.onClose(); @@ -101,7 +94,6 @@ class PrivacyDropdownMenu extends React.PureComponent { document.addEventListener('click', this.handleDocumentClick, false); document.addEventListener('touchend', this.handleDocumentClick, listenerOptions); if (this.focusedItem) this.focusedItem.focus({ preventScroll: true }); - this.setState({ mounted: true }); } componentWillUnmount () { @@ -118,31 +110,23 @@ class PrivacyDropdownMenu extends React.PureComponent { } render () { - const { mounted } = this.state; - const { style, items, placement, value } = this.props; + const { style, items, value } = this.props; return ( - - {({ opacity, scaleX, scaleY }) => ( - // It should not be transformed when mounting because the resulting - // size will be used to determine the coordinate of the menu by - // react-overlays -
- {items.map(item => ( -
-
- -
- -
- {item.text} - {item.meta} -
-
- ))} +
+ {items.map(item => ( +
+
+ +
+ +
+ {item.text} + {item.meta} +
- )} - + ))} +
); } @@ -168,7 +152,7 @@ class PrivacyDropdown extends React.PureComponent { placement: 'bottom', }; - handleToggle = ({ target }) => { + handleToggle = () => { if (this.props.isUserTouching && this.props.isUserTouching()) { if (this.state.open) { this.props.onModalClose(); @@ -179,11 +163,9 @@ class PrivacyDropdown extends React.PureComponent { }); } } else { - const { top } = target.getBoundingClientRect(); if (this.state.open && this.activeElement) { this.activeElement.focus({ preventScroll: true }); } - this.setState({ placement: top * 2 < innerHeight ? 'bottom' : 'top' }); this.setState({ open: !this.state.open }); } } @@ -247,6 +229,18 @@ class PrivacyDropdown extends React.PureComponent { } } + setTargetRef = c => { + this.target = c; + } + + findTarget = () => { + return this.target; + } + + handleOverlayEnter = (state) => { + this.setState({ placement: state.placement }); + } + render () { const { value, container, disabled, intl } = this.props; const { open, placement } = this.state; @@ -255,7 +249,7 @@ class PrivacyDropdown extends React.PureComponent { return (
-
+
- - + + {({ props, placement }) => ( +
+
+ +
+
+ )}
); diff --git a/app/javascript/mastodon/features/compose/components/search.js b/app/javascript/mastodon/features/compose/components/search.js index 8254fb607..5820f8ca2 100644 --- a/app/javascript/mastodon/features/compose/components/search.js +++ b/app/javascript/mastodon/features/compose/components/search.js @@ -1,9 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; -import Overlay from 'react-overlays/lib/Overlay'; -import Motion from '../../ui/util/optional_motion'; -import spring from 'react-motion/lib/spring'; +import Overlay from 'react-overlays/Overlay'; import { searchEnabled } from '../../../initial_state'; import Icon from 'mastodon/components/icon'; @@ -14,31 +12,20 @@ const messages = defineMessages({ class SearchPopout extends React.PureComponent { - static propTypes = { - style: PropTypes.object, - }; - render () { - const { style } = this.props; const extraInformation = searchEnabled ? : ; return ( -
- - {({ opacity, scaleX, scaleY }) => ( -
-

- -
    -
  • #example
  • -
  • @username@domain
  • -
  • URL
  • -
  • URL
  • -
- - {extraInformation} -
- )} -
+
+

+ +
    +
  • #example
  • +
  • @username@domain
  • +
  • URL
  • +
  • URL
  • +
+ + {extraInformation}
); } @@ -115,6 +102,10 @@ class Search extends React.PureComponent { this.setState({ expanded: false }); } + findTarget = () => { + return this.searchForm; + } + render () { const { intl, value, submitted } = this.props; const { expanded } = this.state; @@ -140,8 +131,14 @@ class Search extends React.PureComponent {
- - + + {({ props, placement }) => ( +
+
+ +
+
+ )}
); diff --git a/app/javascript/mastodon/reducers/dropdown_menu.js b/app/javascript/mastodon/reducers/dropdown_menu.js index a78a11acc..51bf9375b 100644 --- a/app/javascript/mastodon/reducers/dropdown_menu.js +++ b/app/javascript/mastodon/reducers/dropdown_menu.js @@ -4,12 +4,12 @@ import { DROPDOWN_MENU_CLOSE, } from '../actions/dropdown_menu'; -const initialState = Immutable.Map({ openId: null, placement: null, keyboard: false, scroll_key: null }); +const initialState = Immutable.Map({ openId: null, keyboard: false, scroll_key: null }); export default function dropdownMenu(state = initialState, action) { switch (action.type) { case DROPDOWN_MENU_OPEN: - return state.merge({ openId: action.id, placement: action.placement, keyboard: action.keyboard, scroll_key: action.scroll_key }); + return state.merge({ openId: action.id, keyboard: action.keyboard, scroll_key: action.scroll_key }); case DROPDOWN_MENU_CLOSE: return state.get('openId') === action.id ? state.set('openId', null).set('scroll_key', null) : state; default: diff --git a/app/javascript/styles/mastodon-light/diff.scss b/app/javascript/styles/mastodon-light/diff.scss index 928af8453..123fe0c67 100644 --- a/app/javascript/styles/mastodon-light/diff.scss +++ b/app/javascript/styles/mastodon-light/diff.scss @@ -285,22 +285,8 @@ html { .dropdown-menu { background: $white; - &__arrow { - &.left { - border-left-color: $white; - } - - &.top { - border-top-color: $white; - } - - &.bottom { - border-bottom-color: $white; - } - - &.right { - border-right-color: $white; - } + &__arrow::before { + background-color: $white; } &__item { diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index 0439156f1..ad59303f4 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -363,8 +363,8 @@ } } -.dropdown-menu { - position: absolute; +body > [data-popper-placement] { + z-index: 3; } .invisible { @@ -1932,6 +1932,42 @@ a.account__display-name { text-decoration: none; } +.dropdown-animation { + animation: dropdown 300ms cubic-bezier(0.1, 0.7, 0.1, 1); + + @keyframes dropdown { + from { + opacity: 0; + transform: scaleX(0.85) scaleY(0.75); + } + + to { + opacity: 1; + transform: scaleX(1) scaleY(1); + } + } + + &.top { + transform-origin: bottom; + } + + &.right { + transform-origin: left; + } + + &.bottom { + transform-origin: top; + } + + &.left { + transform-origin: right; + } + + .reduce-motion & { + animation: none; + } +} + .dropdown { display: inline-block; } @@ -2016,36 +2052,42 @@ a.account__display-name { .dropdown-menu__arrow { position: absolute; - width: 0; - height: 0; - border: 0 solid transparent; - &.left { - right: -5px; - margin-top: -5px; - border-width: 5px 0 5px 5px; - border-left-color: $ui-secondary-color; + &::before { + content: ''; + display: block; + width: 14px; + height: 5px; + background-color: $ui-secondary-color; + mask-image: url("data:image/svg+xml;utf8,"); } &.top { bottom: -5px; - margin-left: -7px; - border-width: 5px 7px 0; - border-top-color: $ui-secondary-color; + + &::before { + transform: rotate(180deg); + } + } + + &.right { + left: -9px; + + &::before { + transform: rotate(-90deg); + } } &.bottom { top: -5px; - margin-left: -7px; - border-width: 0 7px 5px; - border-bottom-color: $ui-secondary-color; } - &.right { - left: -5px; - margin-top: -5px; - border-width: 5px 5px 5px 0; - border-right-color: $ui-secondary-color; + &.left { + right: -9px; + + &::before { + transform: rotate(90deg); + } } } @@ -4524,7 +4566,6 @@ a.status-card.compact:hover { } .privacy-dropdown__dropdown { - position: absolute; background: $simple-background-color; box-shadow: 2px 4px 15px rgba($base-shadow-color, 0.4); border-radius: 4px; @@ -4630,7 +4671,6 @@ a.status-card.compact:hover { .language-dropdown { &__dropdown { - position: absolute; background: $simple-background-color; box-shadow: 2px 4px 15px rgba($base-shadow-color, 0.4); border-radius: 4px; @@ -4877,7 +4917,6 @@ a.status-card.compact:hover { .modal-root__modal { pointer-events: auto; display: flex; - z-index: 9999; } .video-modal__container { -- cgit